Commit b60572d1 authored by Robert Schmidt's avatar Robert Schmidt

Merge remote-tracking branch 'origin/refactor-measConfig' into integration_2025_w37 (!3531)

Refactor measConfig

- Refactor and minor improvements in get_MeasConfig function;
- Add support for band in neighbourConfiguration (It is currently
  possible to handover cells with different frequencies, as long as they
  are in the same band, but this MR allows the handover to also be done
  between cells in different bands).
parents 99962b55 89ebbb41
......@@ -1870,6 +1870,7 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc
neighbourCell.nrcell_id = (uint64_t) * (NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_NR_CELLID_IDX].u64ptr);
neighbourCell.physicalCellId = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_PHYSICAL_ID_IDX].uptr;
neighbourCell.subcarrierSpacing = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_SCS_IDX].uptr;
neighbourCell.band = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_BAND_IDX].uptr;
neighbourCell.absoluteFrequencySSB = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_ABS_FREQ_SSB_IDX].i64ptr;
neighbourCell.tac = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_TAC_IDX].uptr;
......
......@@ -336,6 +336,7 @@ typedef enum {
#define GNB_CONFIG_STRING_NEIGHBOUR_CELL_PHYSICAL_ID "physical_cellId"
#define GNB_CONFIG_STRING_NEIGHBOUR_CELL_ABS_FREQ_SSB "absoluteFrequencySSB"
#define GNB_CONFIG_STRING_NEIGHBOUR_CELL_SCS "subcarrierSpacing"
#define GNB_CONFIG_STRING_NEIGHBOUR_CELL_BAND "band"
#define GNB_CONFIG_STRING_NEIGHBOUR_TRACKING_ARE_CODE "tracking_area_code"
#define GNB_CONFIG_STRING_NEIGHBOUR_PLMN "plmn"
......@@ -344,7 +345,8 @@ typedef enum {
#define GNB_CONFIG_N_CELL_PHYSICAL_ID_IDX 2
#define GNB_CONFIG_N_CELL_ABS_FREQ_SSB_IDX 3
#define GNB_CONFIG_N_CELL_SCS_IDX 4
#define GNB_CONFIG_N_CELL_TAC_IDX 5
#define GNB_CONFIG_N_CELL_BAND_IDX 5
#define GNB_CONFIG_N_CELL_TAC_IDX 6
// clang-format off
#define GNBNEIGHBOURCELLPARAMS_DESC { \
/* optname helpstr paramflags XXXptr def val type numelt */ \
......@@ -353,6 +355,7 @@ typedef enum {
{GNB_CONFIG_STRING_NEIGHBOUR_CELL_PHYSICAL_ID, "neighbour cell physical id", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \
{GNB_CONFIG_STRING_NEIGHBOUR_CELL_ABS_FREQ_SSB, "neighbour cell abs freq ssb", PARAMFLAG_MANDATORY, .i64ptr=NULL, .defint64val=0, TYPE_INT64, 0}, \
{GNB_CONFIG_STRING_NEIGHBOUR_CELL_SCS, "neighbour cell scs", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \
{GNB_CONFIG_STRING_NEIGHBOUR_CELL_BAND, "neighbour cell band", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=78, TYPE_UINT, 0}, \
{GNB_CONFIG_STRING_NEIGHBOUR_TRACKING_ARE_CODE, "neighbour cell tracking area", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \
}
// clang-format on
......
......@@ -628,7 +628,7 @@ static void pf_dl(module_id_t module_id,
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
NR_UE_DL_BWP_t *current_BWP = &UE->current_DL_BWP;
if (sched_ctrl->ul_failure)
if (!nr_mac_ue_is_active(UE))
continue;
const NR_mac_dir_stats_t *stats = &UE->mac_stats.dl;
......@@ -1038,7 +1038,7 @@ void nr_schedule_ue_spec(module_id_t module_id,
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
NR_UE_DL_BWP_t *current_BWP = &UE->current_DL_BWP;
if (sched_ctrl->ul_failure && !get_softmodem_params()->phy_test)
if (!nr_mac_ue_is_active(UE) && !get_softmodem_params()->phy_test)
continue;
NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch;
......
......@@ -3464,10 +3464,7 @@ void nr_measgap_scheduling(gNB_MAC_INST *nr_mac, frame_t frame, sub_frame_t slot
interrupt_followup_action_t a = nr_timer_is_active(t) ? UE->interrupt_action : FOLLOW_INSYNC;
// start a timer to stop scheduling UE during MeasGap, or extend timer for
// duration of measGap with existing follow-up action
// TODO: if the timer is running, it might be to stop scheduling of the UE afterwards, but then it does not make sense to stop
// scheduling the UE now, we should maybe just skip it?
if (!nr_timer_is_active(t) || nr_timer_remaining_time(t) < mgc->mgl_slots) {
nr_mac_trigger_ul_failure(&UE->UE_sched_ctrl, UE->current_DL_BWP.scs); /* set the UE to "not active" */
nr_mac_interrupt_ue_transmission(nr_mac, UE, a, mgc->mgl_slots);
}
}
......@@ -3644,12 +3641,9 @@ void nr_mac_update_timers(module_id_t module_id, frame_t frame, slot_t slot)
if (nr_timer_tick(&sched_ctrl->transm_interrupt)) {
/* expired */
nr_timer_stop(&sched_ctrl->transm_interrupt);
if (UE->interrupt_action == FOLLOW_OUTOFSYNC) {
if (UE->interrupt_action == FOLLOW_OUTOFSYNC)
nr_mac_trigger_ul_failure(sched_ctrl, UE->current_DL_BWP.scs);
} else {
DevAssert(UE->interrupt_action == FOLLOW_INSYNC);
nr_mac_reset_ul_failure(sched_ctrl);
}
/* else: default FOLLOW_INSYNC: nothing to do (UE is now active again) */
}
}
}
......@@ -3856,6 +3850,17 @@ bool nr_mac_check_release(NR_UE_sched_ctrl_t *sched_ctrl, int rnti)
return sched_ctrl->release_timer == 0;
}
bool nr_mac_ue_is_active(const NR_UE_info_t *ue)
{
/* pass NR_UE_info_t, so that later we could adapt, e.g., for DRX */
const NR_UE_sched_ctrl_t *sched_ctrl = &ue->UE_sched_ctrl;
if (sched_ctrl->ul_failure)
return false;
if (nr_timer_is_active(&sched_ctrl->transm_interrupt))
return false;
return true;
}
#define UL_FAILURE_REQ_GRACE 10000
#define UL_FAILURE_TIMEOUT 30000
void nr_mac_trigger_ul_failure(NR_UE_sched_ctrl_t *sched_ctrl, NR_SubcarrierSpacing_t subcarrier_spacing)
......
......@@ -533,10 +533,9 @@ void nr_schedule_srs(int module_id, frame_t frame, int slot)
UE_iterator(UE_info->connected_ue_list, UE) {
const int CC_id = 0;
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP;
if ((sched_ctrl->ul_failure && !get_softmodem_params()->phy_test) || nr_timer_is_active(&sched_ctrl->transm_interrupt)) {
if (!nr_mac_ue_is_active(UE) && !get_softmodem_params()->phy_test) {
continue;
}
......
......@@ -236,7 +236,7 @@ void nr_csi_meas_reporting(int Mod_idP,frame_t frame, slot_t slot)
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP;
const int n_slots_frame = nrmac->frame_structure.numb_slots_frame;
if (nr_timer_is_active(&sched_ctrl->transm_interrupt) || (sched_ctrl->ul_failure && !get_softmodem_params()->phy_test)) {
if (!nr_mac_ue_is_active(UE) && !get_softmodem_params()->phy_test) {
continue;
}
const NR_CSI_MeasConfig_t *csi_measconfig = UE->sc_info.csi_MeasConfig;
......@@ -1280,7 +1280,7 @@ void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t SFN, slot_t slot)
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP;
const int n_slots_frame = nrmac->frame_structure.numb_slots_frame;
if (sched_ctrl->ul_failure || nr_timer_is_active(&sched_ctrl->transm_interrupt))
if (!nr_mac_ue_is_active(UE))
continue;
NR_PUCCH_Config_t *pucch_Config = ul_bwp->pucch_Config;
......
......@@ -1966,7 +1966,7 @@ static int pf_ul(gNB_MAC_INST *nrmac,
UE_iterator(UE_list, UE) {
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
if (sched_ctrl->ul_failure)
if (!nr_mac_ue_is_active(UE))
continue;
LOG_D(NR_MAC,"pf_ul: preparing UL scheduling for UE %04x\n",UE->rnti);
......
......@@ -478,6 +478,9 @@ void nr_mac_trigger_release_complete(gNB_MAC_INST *mac, int rnti);
void nr_mac_release_ue(gNB_MAC_INST *mac, int rnti);
bool nr_mac_request_release_ue(const gNB_MAC_INST *nrmac, int rnti);
void clean_bwp_structures(NR_SpCellConfig_t *spCellConfig);
bool nr_mac_ue_is_active(const NR_UE_info_t *ue);
void nr_mac_trigger_ul_failure(NR_UE_sched_ctrl_t *sched_ctrl, NR_SubcarrierSpacing_t subcarrier_spacing);
void nr_mac_reset_ul_failure(NR_UE_sched_ctrl_t *sched_ctrl);
bool nr_mac_check_ul_failure(gNB_MAC_INST *nrmac, int rnti, NR_UE_sched_ctrl_t *sched_ctrl);
......
......@@ -995,22 +995,32 @@ static NR_MeasIdToAddMod_t *get_MeasId(NR_MeasId_t measId, NR_ReportConfigId_t r
NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt,
int band,
int scs,
int nr_pci,
NR_ReportConfigToAddMod_t *rc_PER,
NR_ReportConfigToAddMod_t *rc_A2,
seq_arr_t *rc_A3_seq,
seq_arr_t *neigh_seq)
{
DevAssert(mt != NULL && mt->frequencyAndTiming != NULL);
const struct NR_MeasTiming__frequencyAndTiming *ft = mt->frequencyAndTiming;
NR_MeasConfig_t *mc = calloc_or_fail(1, sizeof(*mc));
mc->measObjectToAddModList = calloc_or_fail(1, sizeof(*mc->measObjectToAddModList));
mc->reportConfigToAddModList = calloc_or_fail(1, sizeof(*mc->reportConfigToAddModList));
mc->measIdToAddModList = calloc_or_fail(1, sizeof(*mc->measIdToAddModList));
// Report Configuration: A reporting configuration defines the reporting criteria. The reporting criteria are classified as event
// triggered reporting, periodic reporting, CGI reporting or SFTD reporting.
// Periodic report
if (rc_PER)
asn1cSeqAdd(&mc->reportConfigToAddModList->list, rc_PER);
// Event A2
if (rc_A2)
asn1cSeqAdd(&mc->reportConfigToAddModList->list, rc_A2);
// Event A3
if (rc_A3_seq) {
for (int i = 0; i < rc_A3_seq->size; i++) {
NR_ReportConfigToAddMod_t *rc_A3 = (NR_ReportConfigToAddMod_t *)seq_arr_at(rc_A3_seq, i);
......@@ -1018,50 +1028,69 @@ NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt,
}
}
DevAssert(mt != NULL && mt->frequencyAndTiming != NULL);
const struct NR_MeasTiming__frequencyAndTiming *ft = mt->frequencyAndTiming;
// Measurement Objects: Specifies what is to be measured. For NR and inter-RAT E-UTRA measurements, this may include
// cell-specific offsets, blacklisted cells to be ignored and whitelisted cells to consider for measurements.
// Serving cell
NR_MeasObjectToAddMod_t *mo1 = get_MeasObject(ft, band, ft->carrierFreq, 1);
if (neigh_seq) {
NR_MeasObjectNR_t *monr1 = mo1->measObject.choice.measObjectNR;
if (monr1->cellsToAddModList == NULL)
monr1->cellsToAddModList = calloc_or_fail(1, sizeof(*monr1->cellsToAddModList));
FOR_EACH_SEQ_ARR(nr_neighbour_cell_t *, n, neigh_seq) {
NR_CellsToAddMod_t *cell = calloc_or_fail(1, sizeof(*cell));
cell->physCellId = n->physicalCellId;
ASN_SEQUENCE_ADD(&monr1->cellsToAddModList->list, cell);
}
}
NR_MeasObjectNR_t *monr1 = mo1->measObject.choice.measObjectNR;
monr1->cellsToAddModList = calloc_or_fail(1, sizeof(*monr1->cellsToAddModList));
NR_CellsToAddMod_t *cell = calloc_or_fail(1, sizeof(*cell));
cell->physCellId = nr_pci;
ASN_SEQUENCE_ADD(&monr1->cellsToAddModList->list, cell);
asn1cSeqAdd(&mc->measObjectToAddModList->list, mo1);
// Preparation of measId
uint8_t reportIdx = 0;
for (; reportIdx < mc->reportConfigToAddModList->list.count; reportIdx++) {
const NR_ReportConfigId_t reportId = mc->reportConfigToAddModList->list.array[reportIdx]->reportConfigId;
NR_MeasIdToAddMod_t *measid = get_MeasId(reportIdx + 1, reportId, 1);
asn1cSeqAdd(&mc->measIdToAddModList->list, measid);
}
// Preparation of measId for neighbour cells for periodic report
// Neighbour cells
if (neigh_seq) {
int mo_id = 2;
FOR_EACH_SEQ_ARR(nr_neighbour_cell_t *, neigh_cell, neigh_seq) {
NR_MeasObjectToAddMod_t *mo_neighbour = get_MeasObject(ft, band, neigh_cell->absoluteFrequencySSB, mo_id);
NR_MeasObjectToAddMod_t *mo_neighbour = get_MeasObject(ft, neigh_cell->band, neigh_cell->absoluteFrequencySSB, mo_id);
NR_MeasObjectNR_t *monr = mo_neighbour->measObject.choice.measObjectNR;
monr->cellsToAddModList = calloc_or_fail(1, sizeof(*monr->cellsToAddModList));
NR_CellsToAddMod_t *cell = calloc_or_fail(1, sizeof(*cell));
cell->physCellId = neigh_cell->physicalCellId;
ASN_SEQUENCE_ADD(&monr->cellsToAddModList->list, cell);
asn1cSeqAdd(&mc->measObjectToAddModList->list, mo_neighbour);
NR_MeasIdToAddMod_t *measid = get_MeasId(reportIdx + 1, rc_PER->reportConfigId, mo_id);
asn1cSeqAdd(&mc->measIdToAddModList->list, measid);
reportIdx++;
mo_id++;
}
}
// Measurement identities: A list of measurement identities where each measurement identity links one measurement object with one
// reporting configuration. By configuring multiple measurement identities, it is possible to link more than one measurement
// object to the same reporting configuration, as well as to link more than one reporting configuration to the same measurement
// object.
// MeasId for Periodic report
int meas_idx = 0;
if (rc_PER) {
for (; meas_idx < mc->measObjectToAddModList->list.count; meas_idx++) {
const NR_MeasObjectId_t measObjectId = mc->measObjectToAddModList->list.array[meas_idx]->measObjectId;
NR_MeasIdToAddMod_t *measid = get_MeasId(meas_idx + 1, rc_PER->reportConfigId, measObjectId);
asn1cSeqAdd(&mc->measIdToAddModList->list, measid);
}
}
// MeasId for Event A2
if (rc_A2) {
NR_MeasIdToAddMod_t *measid_A2 = get_MeasId(meas_idx + 1, rc_A2->reportConfigId, 1);
meas_idx++;
asn1cSeqAdd(&mc->measIdToAddModList->list, measid_A2);
}
// MeasId for Event A3
if (neigh_seq) {
int i = 0;
FOR_EACH_SEQ_ARR(nr_neighbour_cell_t *, neigh_cell, neigh_seq) {
NR_ReportConfigId_t reportConfigId = neigh_cell->physicalCellId == -1 ? 3 : i + 4;
NR_MeasIdToAddMod_t *measid_A3 = get_MeasId(meas_idx + 1, reportConfigId, i + 2);
meas_idx++;
asn1cSeqAdd(&mc->measIdToAddModList->list, measid_A3);
i++;
}
}
// Quantity configurations: The quantity configuration defines the measurement filtering configuration used for measurement event
// evaluation and related reporting, and for periodical reporting of that measurement.
mc->quantityConfig = calloc_or_fail(1, sizeof(*mc->quantityConfig));
mc->quantityConfig->quantityConfigNR_List = calloc_or_fail(1, sizeof(*mc->quantityConfig->quantityConfigNR_List));
NR_QuantityConfigNR_t *qcnr = calloc_or_fail(1, sizeof(*qcnr));
......
......@@ -153,6 +153,7 @@ int do_RRCReestablishmentComplete(uint8_t *buffer, size_t buffer_size, int64_t r
NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt,
int band,
int scs,
int nr_pci,
NR_ReportConfigToAddMod_t *rc_PER,
NR_ReportConfigToAddMod_t *rc_A2,
seq_arr_t *rc_A3_seq,
......
......@@ -314,6 +314,7 @@ typedef struct {
int physicalCellId;
int absoluteFrequencySSB;
int subcarrierSpacing;
int band;
plmn_identity_t plmn;
uint32_t tac;
bool isIntraFrequencyNeighbour;
......
......@@ -544,12 +544,12 @@ static NR_ReportConfigToAddMod_t *prepare_a2_event_report(const nr_a2_event_t *a
return rc_A2;
}
static NR_ReportConfigToAddMod_t *prepare_a3_event_report(const nr_a3_event_t *a3_event)
static NR_ReportConfigToAddMod_t *prepare_a3_event_report(const nr_a3_event_t *a3_event, NR_ReportConfigId_t reportConfigId)
{
NR_ReportConfigToAddMod_t *rc_A3 = calloc(1, sizeof(*rc_A3));
// 3 is default A3 Report Config ID. So cellId(0) specific Report Config ID
// starts from 4
rc_A3->reportConfigId = a3_event->pci == -1 ? 3 : a3_event->pci + 4;
rc_A3->reportConfigId = reportConfigId;
rc_A3->reportConfig.present = NR_ReportConfigToAddMod__reportConfig_PR_reportConfigNR;
NR_EventTriggerConfig_t *etrc_A3 = calloc(1, sizeof(*etrc_A3));
etrc_A3->eventId.present = NR_EventTriggerConfig__eventId_PR_eventA3;
......@@ -593,6 +593,7 @@ NR_MeasConfig_t *nr_rrc_get_measconfig(const gNB_RRC_INST *rrc, uint64_t nr_cell
NR_ReportConfigToAddMod_t *rc_PER = NULL;
NR_ReportConfigToAddMod_t *rc_A2 = NULL;
seq_arr_t *rc_A3_seq = NULL;
seq_arr_t *neigh_seq = NULL;
if (du->mtc != NULL) {
int scs = get_ssb_scs(cell_info);
int band = get_dl_band(cell_info);
......@@ -609,24 +610,30 @@ NR_MeasConfig_t *nr_rrc_get_measconfig(const gNB_RRC_INST *rrc, uint64_t nr_cell
If default one added once as a report, no need to add it again && duplication.
*/
rc_A3_seq = malloc(sizeof(seq_arr_t));
neigh_seq = malloc(sizeof(seq_arr_t));
seq_arr_init(rc_A3_seq, sizeof(NR_ReportConfigToAddMod_t));
LOG_D(NR_RRC, "HO LOG: Preparing A3 Event Measurement Configuration!\n");
bool is_default_a3_added = false;
seq_arr_init(neigh_seq, sizeof(nr_neighbour_cell_t));
LOG_D(NR_RRC, "Preparing A3 Event Measurement Configuration!\n");
bool default_a3_added = false; // To ensure that the default configuration is only added once
for (int i = 0; i < neighbour_cells->size; i++) {
nr_neighbour_cell_t *neighbourCell = (nr_neighbour_cell_t *)seq_arr_at(neighbour_cells, i);
const nr_a3_event_t *a3Event = get_a3_configuration((gNB_RRC_INST *)rrc, neighbourCell->physicalCellId);
if (!a3Event || is_default_a3_added)
if (default_a3_added && neighbourCell->physicalCellId == -1)
continue;
if (a3Event->pci == -1)
is_default_a3_added = true;
seq_arr_push_back(rc_A3_seq, prepare_a3_event_report(a3Event), sizeof(NR_ReportConfigToAddMod_t));
seq_arr_push_back(neigh_seq, neighbourCell, sizeof(nr_neighbour_cell_t));
const nr_a3_event_t *a3Event = get_a3_configuration((gNB_RRC_INST *)rrc, neighbourCell->physicalCellId);
if (a3Event) {
NR_ReportConfigId_t reportConfigId = neighbourCell->physicalCellId == -1 ? 3 : i + 4;
seq_arr_push_back(rc_A3_seq, prepare_a3_event_report(a3Event, reportConfigId), sizeof(NR_ReportConfigToAddMod_t));
if (neighbourCell->physicalCellId == -1)
default_a3_added = true;
}
}
}
if (rrc->measurementConfiguration.per_event)
rc_PER = prepare_periodic_event_report(rrc->measurementConfiguration.per_event);
if (rrc->measurementConfiguration.a2_event)
rc_A2 = prepare_a2_event_report(rrc->measurementConfiguration.a2_event);
return get_MeasConfig(mt, band, scs, rc_PER, rc_A2, rc_A3_seq, neighbour_cells);
return get_MeasConfig(mt, band, scs, cell_info->nr_pci, rc_PER, rc_A2, rc_A3_seq, neigh_seq);
}
return NULL;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment