Merge remote-tracking branch 'origin/fix-a3-event' into integration_2026_w04 (!3789)

fix A3 event configuration

See commit message for more information.
As a reference, for comparison purpose, PCAPs and TXT files for various tests
done in develop and in this MR are available in the MR description.
This commit is contained in:
Jaroslava Fiedlerova
2026-01-19 13:55:40 +01:00
3 changed files with 40 additions and 14 deletions
+6 -2
View File
@@ -1121,7 +1121,8 @@ NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt,
NR_ReportConfigToAddMod_t *rc_PER, NR_ReportConfigToAddMod_t *rc_PER,
NR_ReportConfigToAddMod_t *rc_A2, NR_ReportConfigToAddMod_t *rc_A2,
seq_arr_t *rc_A3_seq, seq_arr_t *rc_A3_seq,
seq_arr_t *neigh_seq) seq_arr_t *neigh_seq,
int *neigh_a3_id)
{ {
DevAssert(mt != NULL && mt->frequencyAndTiming != NULL); DevAssert(mt != NULL && mt->frequencyAndTiming != NULL);
const struct NR_MeasTiming__frequencyAndTiming *ft = mt->frequencyAndTiming; const struct NR_MeasTiming__frequencyAndTiming *ft = mt->frequencyAndTiming;
@@ -1207,7 +1208,10 @@ NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt,
if (neigh_seq) { if (neigh_seq) {
int i = 0; int i = 0;
FOR_EACH_SEQ_ARR(nr_neighbour_cell_t *, neigh_cell, neigh_seq) { FOR_EACH_SEQ_ARR(nr_neighbour_cell_t *, neigh_cell, neigh_seq) {
NR_ReportConfigId_t reportConfigId = neigh_cell->physicalCellId == -1 ? 3 : i + 4; NR_ReportConfigId_t reportConfigId = neigh_a3_id[i];
/* check that there is a A3 configured for this neighbour */
if (reportConfigId == -1)
continue;
NR_MeasIdToAddMod_t *measid_A3 = get_MeasId(meas_idx + 1, reportConfigId, i + 2); NR_MeasIdToAddMod_t *measid_A3 = get_MeasId(meas_idx + 1, reportConfigId, i + 2);
meas_idx++; meas_idx++;
asn1cSeqAdd(&mc->measIdToAddModList->list, measid_A3); asn1cSeqAdd(&mc->measIdToAddModList->list, measid_A3);
+2 -1
View File
@@ -164,7 +164,8 @@ NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt,
NR_ReportConfigToAddMod_t *rc_PER, NR_ReportConfigToAddMod_t *rc_PER,
NR_ReportConfigToAddMod_t *rc_A2, NR_ReportConfigToAddMod_t *rc_A2,
seq_arr_t *rc_A3_seq, seq_arr_t *rc_A3_seq,
seq_arr_t *neigh_seq); seq_arr_t *neigh_seq,
int *neigh_a3_id);
void free_MeasConfig(NR_MeasConfig_t *mc); void free_MeasConfig(NR_MeasConfig_t *mc);
int do_NR_Paging(uint8_t Mod_id, uint8_t *buffer, uint32_t tmsi); int do_NR_Paging(uint8_t Mod_id, uint8_t *buffer, uint32_t tmsi);
+32 -11
View File
@@ -622,9 +622,6 @@ static nr_a3_event_t *get_a3_configuration(gNB_RRC_INST *rrc, int pci)
return a3_event; return a3_event;
} }
if (measurementConfiguration->is_default_a3_configuration_exists)
return get_a3_configuration(rrc, -1);
return NULL; return NULL;
} }
@@ -750,6 +747,10 @@ NR_MeasConfig_t *nr_rrc_get_measconfig(const gNB_RRC_INST *rrc, uint64_t nr_cell
if (neighbour_config) if (neighbour_config)
neighbour_cells = neighbour_config->neighbour_cells; neighbour_cells = neighbour_config->neighbour_cells;
int *neigh_a3_id = NULL;
if (neighbour_cells && neighbour_cells->size)
neigh_a3_id = calloc_or_fail(neighbour_cells->size, sizeof(int));
if (neighbour_cells && rrc->measurementConfiguration.a3_event_list && rrc->measurementConfiguration.a3_event_list->size > 0) { if (neighbour_cells && rrc->measurementConfiguration.a3_event_list && rrc->measurementConfiguration.a3_event_list->size > 0) {
/* Loop through neighbours and find related A3 configuration /* Loop through neighbours and find related A3 configuration
If no related A3 but there is default add the default one. If no related A3 but there is default add the default one.
@@ -759,16 +760,31 @@ NR_MeasConfig_t *nr_rrc_get_measconfig(const gNB_RRC_INST *rrc, uint64_t nr_cell
bool default_a3_added = false; // To ensure that the default configuration is only added once bool default_a3_added = false; // To ensure that the default configuration is only added once
for (int i = 0; i < neighbour_cells->size; i++) { for (int i = 0; i < neighbour_cells->size; i++) {
nr_neighbour_cell_t *neighbourCell = (nr_neighbour_cell_t *)seq_arr_at(neighbour_cells, i); nr_neighbour_cell_t *neighbourCell = (nr_neighbour_cell_t *)seq_arr_at(neighbour_cells, i);
if (default_a3_added && neighbourCell->physicalCellId == -1)
continue;
seq_arr_push_back(&neigh_seq, neighbourCell, sizeof(nr_neighbour_cell_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); const nr_a3_event_t *a3Event = get_a3_configuration((gNB_RRC_INST *)rrc, neighbourCell->physicalCellId);
if (a3Event) { if (!a3Event) {
NR_ReportConfigId_t reportConfigId = neighbourCell->physicalCellId == -1 ? 3 : i + 4; /* no A3 event configured for this neighbour, let's try the default one, if it exists */
seq_arr_push_back(&rc_A3_seq, prepare_a3_event_report(a3Event, reportConfigId), sizeof(NR_ReportConfigToAddMod_t)); if (default_a3_added) {
if (neighbourCell->physicalCellId == -1) /* default A3 exists and is already added, use it for this neighbour */
default_a3_added = true; neigh_a3_id[i] = 3;
continue;
}
/* try to get the default A3 config */
a3Event = get_a3_configuration((gNB_RRC_INST *)rrc, -1);
if (!a3Event) {
/* no default A3 config found, so no A3 config for this neighbour */
neigh_a3_id[i] = -1;
continue;
}
default_a3_added = true;
/* default A3 report config ID is 3 */
neigh_a3_id[i] = 3;
} else {
/* specific A3 report config ID are 4, 5, ... */
neigh_a3_id[i] = i + 4;
} }
NR_ReportConfigId_t reportConfigId = neigh_a3_id[i];
seq_arr_push_back(&rc_A3_seq, prepare_a3_event_report(a3Event, reportConfigId), sizeof(NR_ReportConfigToAddMod_t));
} }
} }
if (rrc->measurementConfiguration.per_event) if (rrc->measurementConfiguration.per_event)
@@ -776,12 +792,14 @@ NR_MeasConfig_t *nr_rrc_get_measconfig(const gNB_RRC_INST *rrc, uint64_t nr_cell
if (rrc->measurementConfiguration.a2_event) if (rrc->measurementConfiguration.a2_event)
rc_A2 = prepare_a2_event_report(rrc->measurementConfiguration.a2_event); rc_A2 = prepare_a2_event_report(rrc->measurementConfiguration.a2_event);
NR_MeasConfig_t *result = get_MeasConfig(mt, band, scs, cell_info->nr_pci, rc_PER, rc_A2, &rc_A3_seq, &neigh_seq); NR_MeasConfig_t *result = get_MeasConfig(mt, band, scs, cell_info->nr_pci, rc_PER, rc_A2, &rc_A3_seq, &neigh_seq, neigh_a3_id);
// Clean up sequence arrays // Clean up sequence arrays
seq_arr_free(&rc_A3_seq, NULL); seq_arr_free(&rc_A3_seq, NULL);
seq_arr_free(&neigh_seq, NULL); seq_arr_free(&neigh_seq, NULL);
free(neigh_a3_id);
return result; return result;
} }
return NULL; return NULL;
@@ -1620,6 +1638,9 @@ static void process_Event_Based_Measurement_Report(gNB_RRC_INST *rrc,
if (!neigh_cell && neighbour) { if (!neigh_cell && neighbour) {
// No F1 connection but static neighbour configuration is available // No F1 connection but static neighbour configuration is available
const nr_a3_event_t *a3_event_configuration = get_a3_configuration(rrc, neighbour->physicalCellId); const nr_a3_event_t *a3_event_configuration = get_a3_configuration(rrc, neighbour->physicalCellId);
/* if no A3 event configured for this physical cell ID, try to get the default one */
if (!a3_event_configuration)
a3_event_configuration = get_a3_configuration(rrc, -1);
// Additional check - This part can be modified according to additional cell specific Handover Margin // Additional check - This part can be modified according to additional cell specific Handover Margin
// a3-Offset: The actual value is field value * 0.5 dB. // a3-Offset: The actual value is field value * 0.5 dB.
if (a3_event_configuration if (a3_event_configuration