diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index dda303c952..dcd17efe22 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -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; diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index 08ba09e980..373958b1e8 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -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 diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index c242ed4377..552b1fa041 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -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; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index c2b3e9f89d..ae5305d77c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -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) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index c73ea4c9db..cf58252ed9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -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; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 9e0cba1cdd..682ea765ac 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -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; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 4422a05f7b..ac4b1717a8 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -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); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index eaee764b54..be5d9d37b9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -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); diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index c016e4c899..3ff6aecea9 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -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)); diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index 432db0e5cd..dde62d142f 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -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, diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 68a83c9545..f1d9acba7b 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -314,6 +314,7 @@ typedef struct { int physicalCellId; int absoluteFrequencySSB; int subcarrierSpacing; + int band; plmn_identity_t plmn; uint32_t tac; bool isIntraFrequencyNeighbour; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 000c4f46cb..0e5912aafe 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -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; }