mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-15 21:50:27 +00:00
Compare commits
1 Commits
pre-commit
...
meas_repor
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3876725ead |
@@ -875,9 +875,10 @@ int do_RRCSetupComplete(uint8_t *buffer,
|
||||
return((enc_rval.encoded+7)/8);
|
||||
}
|
||||
|
||||
// TODO: This function is only implemented for event A2/A3
|
||||
// This function is implemented for event A2/A3 and periodical report
|
||||
int do_nrMeasurementReport_SA(long trigger_to_measid,
|
||||
long trigger_quantity,
|
||||
bool report_rsrp,
|
||||
long rs_type,
|
||||
uint16_t Nid_cell,
|
||||
int rsrp_index,
|
||||
@@ -908,7 +909,7 @@ int do_nrMeasurementReport_SA(long trigger_to_measid,
|
||||
*pci = Nid_cell;
|
||||
|
||||
struct NR_MeasQuantityResults *active_mq_res = calloc_or_fail(1, sizeof(*active_mq_res));
|
||||
if (trigger_quantity == NR_MeasTriggerQuantityOffset_PR_rsrp) {
|
||||
if (trigger_quantity == NR_MeasTriggerQuantityOffset_PR_rsrp || report_rsrp) {
|
||||
asn1cCalloc(active_mq_res->rsrp, rsrp);
|
||||
// Assign precomputed RSRP index
|
||||
*rsrp = rsrp_index;
|
||||
@@ -932,7 +933,7 @@ int do_nrMeasurementReport_SA(long trigger_to_measid,
|
||||
*neighbor_pci = neighbor_Nid_cell;
|
||||
struct NR_MeasResultNR__measResult__cellResults *cellResults = &meas_result_neigh_cell->measResult.cellResults;
|
||||
struct NR_MeasQuantityResults *neigh_mq_res = calloc_or_fail(1, sizeof(*neigh_mq_res));
|
||||
if (trigger_quantity == NR_MeasTriggerQuantityOffset_PR_rsrp) {
|
||||
if (trigger_quantity == NR_MeasTriggerQuantityOffset_PR_rsrp || report_rsrp) {
|
||||
asn1cCalloc(neigh_mq_res->rsrp, rsrp);
|
||||
*rsrp = neighbor_rsrp_index;
|
||||
if (rs_type == NR_NR_RS_Type_ssb)
|
||||
|
||||
@@ -128,6 +128,7 @@ int do_RRCSetupRequest(uint8_t *buffer, size_t buffer_size, uint8_t *rv, uint64_
|
||||
|
||||
int do_nrMeasurementReport_SA(long trigger_to_measid,
|
||||
long trigger_quantity,
|
||||
bool report_rsrp,
|
||||
long rs_type,
|
||||
uint16_t Nid_cell,
|
||||
int rsrp_index,
|
||||
|
||||
@@ -1194,12 +1194,13 @@ static void handle_meas_reporting_remove(rrcPerNB_t *rrc, int id, NR_UE_Timers_C
|
||||
nr_timer_stop(&timers->T321);
|
||||
|
||||
l3_measurements_t *l3_measurements = &rrc->l3_measurements;
|
||||
nr_timer_stop(&l3_measurements->TA2);
|
||||
nr_timer_stop(&l3_measurements->periodic_report_timer);
|
||||
meas_report_params_t *params = &l3_measurements->meas_report[id];
|
||||
|
||||
l3_measurements->reports_sent = 0;
|
||||
l3_measurements->max_reports = 0;
|
||||
l3_measurements->report_interval_ms = 0;
|
||||
nr_timer_stop(¶ms->TA2);
|
||||
nr_timer_stop(¶ms->TA3);
|
||||
nr_timer_stop(¶ms->periodic_report_timer);
|
||||
|
||||
memset(params, 0, sizeof(*params));
|
||||
}
|
||||
|
||||
static void handle_measobj_remove(rrcPerNB_t *rrc, struct NR_MeasObjectToRemoveList *remove_list, NR_UE_Timers_Constants_t *timers)
|
||||
@@ -1381,11 +1382,153 @@ static void handle_measid_remove(rrcPerNB_t *rrc, struct NR_MeasIdToRemoveList *
|
||||
}
|
||||
}
|
||||
|
||||
static long get_measurement_report_interval_ms(NR_ReportInterval_t interval)
|
||||
{
|
||||
switch (interval) {
|
||||
case NR_ReportInterval_ms120:
|
||||
return 120;
|
||||
case NR_ReportInterval_ms240:
|
||||
return 240;
|
||||
case NR_ReportInterval_ms480:
|
||||
return 480;
|
||||
case NR_ReportInterval_ms640:
|
||||
return 640;
|
||||
case NR_ReportInterval_ms1024:
|
||||
return 1024;
|
||||
case NR_ReportInterval_ms2048:
|
||||
return 2048;
|
||||
case NR_ReportInterval_ms5120:
|
||||
return 5120;
|
||||
case NR_ReportInterval_ms10240:
|
||||
return 10240;
|
||||
case NR_ReportInterval_min1:
|
||||
return 60000;
|
||||
case NR_ReportInterval_min6:
|
||||
return 360000;
|
||||
case NR_ReportInterval_min12:
|
||||
return 720000;
|
||||
case NR_ReportInterval_min30:
|
||||
return 1800000;
|
||||
default:
|
||||
return 1024;
|
||||
}
|
||||
}
|
||||
|
||||
static int get_meas_id(rrcPerNB_t *rrcNB, int report_config_id)
|
||||
{
|
||||
for (int j = 0; j < MAX_MEAS_ID; j++) {
|
||||
NR_MeasIdToAddMod_t *meas_id_toAddMod = rrcNB->MeasId[j];
|
||||
if (meas_id_toAddMod && meas_id_toAddMod->reportConfigId == report_config_id)
|
||||
return meas_id_toAddMod->measId;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void setup_meas_params(meas_report_params_t *params,
|
||||
long trigger_quantity,
|
||||
long rs_type,
|
||||
long report_amount,
|
||||
bool is_infinity,
|
||||
NR_ReportInterval_t report_interval,
|
||||
bool neighbor_cell_valid)
|
||||
{
|
||||
params->trigger_quantity = trigger_quantity;
|
||||
params->rs_type = rs_type;
|
||||
params->reports_sent = 0;
|
||||
params->max_reports = is_infinity ? INT_MAX : (1 << report_amount);
|
||||
params->report_interval_ms = get_measurement_report_interval_ms(report_interval);
|
||||
params->neighbor_cell_valid = neighbor_cell_valid;
|
||||
params->report_rsrp = false;
|
||||
}
|
||||
|
||||
static void start_periodical_report(rrcPerNB_t *rrc, NR_PeriodicalReportConfig_t *periodical_config, int meas_id)
|
||||
{
|
||||
l3_measurements_t *l3_measurements = &rrc->l3_measurements;
|
||||
meas_report_params_t *params = &l3_measurements->meas_report[meas_id];
|
||||
|
||||
setup_meas_params(params,
|
||||
0,
|
||||
periodical_config->rsType,
|
||||
periodical_config->reportAmount,
|
||||
periodical_config->reportAmount == NR_PeriodicalReportConfig__reportAmount_infinity,
|
||||
periodical_config->reportInterval,
|
||||
true);
|
||||
|
||||
params->reports_sent = 0;
|
||||
params->report_rsrp = periodical_config->reportQuantityCell.rsrp;
|
||||
|
||||
// Start the periodic report timer
|
||||
if (!nr_timer_is_active(¶ms->periodic_report_timer)) {
|
||||
nr_timer_setup(¶ms->periodic_report_timer, params->report_interval_ms, 10);
|
||||
nr_timer_start(¶ms->periodic_report_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void extract_neighbor_cells_from_measObject(NR_MeasObjectNR_t *obj_nr,
|
||||
nr_neighbor_cell_info_t *neighbor_cells,
|
||||
int *num_neighbors,
|
||||
int max_neighbors,
|
||||
uint32_t serving_cell_pci)
|
||||
{
|
||||
uint32_t ssb_freq = 0;
|
||||
if (obj_nr->ssbFrequency) {
|
||||
ssb_freq = *obj_nr->ssbFrequency;
|
||||
}
|
||||
|
||||
if (obj_nr->cellsToAddModList) {
|
||||
NR_CellsToAddModList_t *cellsToAddModList = obj_nr->cellsToAddModList;
|
||||
for (int j = 0; j < cellsToAddModList->list.count; j++) {
|
||||
NR_CellsToAddMod_t *cell = cellsToAddModList->list.array[j];
|
||||
// Skip serving cell
|
||||
if (cell->physCellId == serving_cell_pci) {
|
||||
LOG_D(NR_RRC, "Skipping serving cell PCI %d from neighbor list\n", serving_cell_pci);
|
||||
continue;
|
||||
}
|
||||
// Check if this cell is already in the list
|
||||
bool is_duplicate = false;
|
||||
for (int k = 0; k < *num_neighbors; k++) {
|
||||
if (neighbor_cells[k].Nid_cell == cell->physCellId && neighbor_cells[k].ssb_freq == ssb_freq) {
|
||||
is_duplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!is_duplicate) {
|
||||
if (*num_neighbors < max_neighbors) {
|
||||
neighbor_cells[*num_neighbors].Nid_cell = cell->physCellId;
|
||||
neighbor_cells[*num_neighbors].ssb_freq = ssb_freq;
|
||||
neighbor_cells[*num_neighbors].active = 1;
|
||||
(*num_neighbors)++;
|
||||
} else {
|
||||
LOG_W(NR_RRC, "More than %d neighboring cells configured, ignoring excess cells!\n", max_neighbors);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We do not know PCI of neighboring cells, so we do blind search
|
||||
bool is_duplicate = false;
|
||||
for (int k = 0; k < *num_neighbors; k++) {
|
||||
if (neighbor_cells[k].Nid_cell == -1 && neighbor_cells[k].ssb_freq == ssb_freq) {
|
||||
is_duplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!is_duplicate && *num_neighbors < max_neighbors) {
|
||||
neighbor_cells[*num_neighbors].Nid_cell = -1;
|
||||
neighbor_cells[*num_neighbors].ssb_freq = ssb_freq;
|
||||
neighbor_cells[*num_neighbors].active = 1;
|
||||
(*num_neighbors)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_measid_addmod(rrcPerNB_t *rrc,
|
||||
struct NR_MeasIdToAddModList *addmod_list,
|
||||
NR_UE_Timers_Constants_t *timers,
|
||||
nr_neighbor_cell_info_t *neighbor_cells,
|
||||
int *num_neighbors)
|
||||
int *num_neighbors,
|
||||
int max_neighbors,
|
||||
uint32_t serving_cell_pci)
|
||||
{
|
||||
for (int i = 0; i < addmod_list->list.count; i++) {
|
||||
NR_MeasId_t id = addmod_list->list.array[i]->measId;
|
||||
@@ -1419,47 +1562,28 @@ static void handle_measid_addmod(rrcPerNB_t *rrc,
|
||||
nr_timer_start(&timers->T321);
|
||||
}
|
||||
}
|
||||
// Check for A3 event and extract neighbor cell info for MAC/PHY
|
||||
// Check for A3 event and extract neighbor cell info for MAC
|
||||
else if (reportNR->reportType.present == NR_ReportConfigNR__reportType_PR_eventTriggered) {
|
||||
NR_EventTriggerConfig_t *eventTriggerConfig = reportNR->reportType.choice.eventTriggered;
|
||||
if (eventTriggerConfig->eventId.present == NR_EventTriggerConfig__eventId_PR_eventA3) {
|
||||
if (rrc->MeasObj[measObjectId]
|
||||
&& rrc->MeasObj[measObjectId]->measObject.present == NR_MeasObjectToAddMod__measObject_PR_measObjectNR) {
|
||||
NR_MeasObjectNR_t *obj_nr = rrc->MeasObj[measObjectId]->measObject.choice.measObjectNR;
|
||||
|
||||
uint32_t ssb_freq = 0;
|
||||
if (obj_nr->ssbFrequency) {
|
||||
ssb_freq = *obj_nr->ssbFrequency;
|
||||
}
|
||||
|
||||
if (obj_nr->cellsToAddModList) {
|
||||
NR_CellsToAddModList_t *cellsToAddModList = obj_nr->cellsToAddModList;
|
||||
for (int j = 0; j < cellsToAddModList->list.count; j++) {
|
||||
if (*num_neighbors < NUMBER_OF_NEIGHBORING_CELLS_MAX) {
|
||||
NR_CellsToAddMod_t *cell = cellsToAddModList->list.array[j];
|
||||
neighbor_cells[*num_neighbors].Nid_cell = cell->physCellId;
|
||||
neighbor_cells[*num_neighbors].ssb_freq = ssb_freq;
|
||||
neighbor_cells[*num_neighbors].active = 1;
|
||||
(*num_neighbors)++;
|
||||
} else {
|
||||
LOG_W(NR_RRC,
|
||||
"More than %d neighboring cells configured, ignoring excess cells!\n",
|
||||
NUMBER_OF_NEIGHBORING_CELLS_MAX);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We do not know PCI of neighboring cells, so we do blind search
|
||||
if (*num_neighbors < NUMBER_OF_NEIGHBORING_CELLS_MAX) {
|
||||
neighbor_cells[*num_neighbors].Nid_cell = -1;
|
||||
neighbor_cells[*num_neighbors].ssb_freq = ssb_freq;
|
||||
neighbor_cells[*num_neighbors].active = 1;
|
||||
(*num_neighbors)++;
|
||||
}
|
||||
}
|
||||
extract_neighbor_cells_from_measObject(obj_nr, neighbor_cells, num_neighbors, max_neighbors, serving_cell_pci);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check for periodical report and extract neighbor cell info for MAC
|
||||
else if (reportNR->reportType.present == NR_ReportConfigNR__reportType_PR_periodical) {
|
||||
NR_PeriodicalReportConfig_t *periodical_config = reportNR->reportType.choice.periodical;
|
||||
if (rrc->MeasObj[measObjectId]
|
||||
&& rrc->MeasObj[measObjectId]->measObject.present == NR_MeasObjectToAddMod__measObject_PR_measObjectNR) {
|
||||
NR_MeasObjectNR_t *obj_nr = rrc->MeasObj[measObjectId]->measObject.choice.measObjectNR;
|
||||
extract_neighbor_cells_from_measObject(obj_nr, neighbor_cells, num_neighbors, max_neighbors, serving_cell_pci);
|
||||
// Initialize periodical report (first report sent when measurements available)
|
||||
start_periodical_report(rrc, periodical_config, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1468,7 +1592,9 @@ static void nr_rrc_ue_process_measConfig(rrcPerNB_t *rrc,
|
||||
NR_MeasConfig_t *const measConfig,
|
||||
NR_UE_Timers_Constants_t *timers,
|
||||
nr_neighbor_cell_info_t *neighbor_cells,
|
||||
int *num_neighbors)
|
||||
int *num_neighbors,
|
||||
int max_neighbors,
|
||||
uint32_t serving_cell_pci)
|
||||
{
|
||||
if (measConfig->measObjectToRemoveList)
|
||||
handle_measobj_remove(rrc, measConfig->measObjectToRemoveList, timers);
|
||||
@@ -1489,7 +1615,7 @@ static void nr_rrc_ue_process_measConfig(rrcPerNB_t *rrc,
|
||||
handle_measid_remove(rrc, measConfig->measIdToRemoveList, timers);
|
||||
|
||||
if (measConfig->measIdToAddModList)
|
||||
handle_measid_addmod(rrc, measConfig->measIdToAddModList, timers, neighbor_cells, num_neighbors);
|
||||
handle_measid_addmod(rrc, measConfig->measIdToAddModList, timers, neighbor_cells, num_neighbors, max_neighbors, serving_cell_pci);
|
||||
|
||||
LOG_W(NR_RRC, "Measurement gaps not yet supported!\n");
|
||||
|
||||
@@ -1564,7 +1690,7 @@ static void nr_rrc_ue_process_rrcReconfiguration(NR_UE_RRC_INST_t *rrc, int gNB_
|
||||
LOG_I(NR_RRC, "RRCReconfiguration includes Measurement Configuration\n");
|
||||
nr_neighbor_cell_info_t neighbor_cells[NUMBER_OF_NEIGHBORING_CELLS_MAX];
|
||||
int num_neighbors = 0;
|
||||
nr_rrc_ue_process_measConfig(rrcNB, ie->measConfig, &rrc->timers_and_constants, neighbor_cells, &num_neighbors);
|
||||
nr_rrc_ue_process_measConfig(rrcNB, ie->measConfig, &rrc->timers_and_constants, neighbor_cells, &num_neighbors, NUMBER_OF_NEIGHBORING_CELLS_MAX, rrc->phyCellID);
|
||||
if (num_neighbors > 0) {
|
||||
nr_rrc_mac_config_req_meas(rrc->ue_id, neighbor_cells, num_neighbors);
|
||||
}
|
||||
@@ -2721,38 +2847,6 @@ void nr_ue_meas_filtering(rrcPerNB_t *rrc, meas_t *meas_cell, uint16_t Nid_cell,
|
||||
apply_ema(&meas_cell->ss_rsrp_dBm, l3_measurements->ssb_filter_coeff_rsrp, rsrp_dBm);
|
||||
}
|
||||
|
||||
static long get_measurement_report_interval_ms(NR_ReportInterval_t interval)
|
||||
{
|
||||
switch (interval) {
|
||||
case NR_ReportInterval_ms120:
|
||||
return 120;
|
||||
case NR_ReportInterval_ms240:
|
||||
return 240;
|
||||
case NR_ReportInterval_ms480:
|
||||
return 480;
|
||||
case NR_ReportInterval_ms640:
|
||||
return 640;
|
||||
case NR_ReportInterval_ms1024:
|
||||
return 1024;
|
||||
case NR_ReportInterval_ms2048:
|
||||
return 2048;
|
||||
case NR_ReportInterval_ms5120:
|
||||
return 5120;
|
||||
case NR_ReportInterval_ms10240:
|
||||
return 10240;
|
||||
case NR_ReportInterval_min1:
|
||||
return 60000;
|
||||
case NR_ReportInterval_min6:
|
||||
return 360000;
|
||||
case NR_ReportInterval_min12:
|
||||
return 720000;
|
||||
case NR_ReportInterval_min30:
|
||||
return 1800000;
|
||||
default:
|
||||
return 1024;
|
||||
}
|
||||
}
|
||||
|
||||
static int get_rsrp_value(const meas_t *cell)
|
||||
{
|
||||
if (cell->ss_rsrp_dBm.init)
|
||||
@@ -2762,30 +2856,23 @@ static int get_rsrp_value(const meas_t *cell)
|
||||
return INT_MAX;
|
||||
}
|
||||
|
||||
static int get_meas_id(rrcPerNB_t *rrcNB, int report_config_id)
|
||||
{
|
||||
for (int j = 0; j < MAX_MEAS_ID; j++) {
|
||||
NR_MeasIdToAddMod_t *meas_id_toAddMod = rrcNB->MeasId[j];
|
||||
if (meas_id_toAddMod && meas_id_toAddMod->reportConfigId == report_config_id)
|
||||
return meas_id_toAddMod->measId;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void setup_meas_trigger(l3_measurements_t *l3_measurements,
|
||||
NR_EventTriggerConfig_t *event_config,
|
||||
int meas_id,
|
||||
long trigger_quantity,
|
||||
bool neighbor_cell_valid)
|
||||
{
|
||||
l3_measurements->trigger_to_measid = meas_id;
|
||||
l3_measurements->trigger_quantity = trigger_quantity;
|
||||
l3_measurements->rs_type = event_config->rsType;
|
||||
l3_measurements->reports_sent = 0;
|
||||
l3_measurements->max_reports =
|
||||
(event_config->reportAmount == NR_EventTriggerConfig__reportAmount_infinity) ? INT_MAX : (1 << event_config->reportAmount);
|
||||
l3_measurements->report_interval_ms = get_measurement_report_interval_ms(event_config->reportInterval);
|
||||
l3_measurements->neighbor_cell_valid = neighbor_cell_valid;
|
||||
meas_report_params_t *params = &l3_measurements->meas_report[meas_id];
|
||||
|
||||
setup_meas_params(params,
|
||||
trigger_quantity,
|
||||
event_config->rsType,
|
||||
event_config->reportAmount,
|
||||
event_config->reportAmount == NR_EventTriggerConfig__reportAmount_infinity,
|
||||
event_config->reportInterval,
|
||||
neighbor_cell_valid);
|
||||
|
||||
params->report_rsrp = event_config->reportQuantityCell.rsrp;
|
||||
}
|
||||
|
||||
static void start_meas_event(l3_measurements_t *l3_measurements,
|
||||
@@ -2806,11 +2893,10 @@ static void start_meas_event(l3_measurements_t *l3_measurements,
|
||||
setup_meas_trigger(l3_measurements, event_config, meas_id, trigger_quantity, neighbor_cell_valid);
|
||||
}
|
||||
|
||||
static void stop_meas_event(l3_measurements_t *l3_measurements, NR_timer_t *event_timer)
|
||||
static void stop_meas_event(meas_report_params_t *params, NR_timer_t *event_timer)
|
||||
{
|
||||
nr_timer_stop(event_timer);
|
||||
nr_timer_stop(&l3_measurements->periodic_report_timer);
|
||||
l3_measurements->reports_sent = 0;
|
||||
params->reports_sent = 0;
|
||||
}
|
||||
|
||||
// TS 38.331 - 5.5.4.3 Event A2 (Serving becomes worse than threshold)
|
||||
@@ -2823,6 +2909,10 @@ static void handle_event_a2(l3_measurements_t *l3_measurements,
|
||||
if (event_A2->a2_Threshold.present != NR_MeasTriggerQuantity_PR_rsrp)
|
||||
return;
|
||||
|
||||
int meas_id = get_meas_id(rrcNB, report_config_id);
|
||||
if (meas_id < 0)
|
||||
return;
|
||||
meas_report_params_t *params = &l3_measurements->meas_report[meas_id];
|
||||
meas_t *serving_cell = &l3_measurements->serving_cell;
|
||||
int serving_cell_rsrp = get_rsrp_value(serving_cell);
|
||||
if (serving_cell_rsrp == INT_MAX) {
|
||||
@@ -2834,10 +2924,10 @@ static void handle_event_a2(l3_measurements_t *l3_measurements,
|
||||
int rsrp_hysteresis = event_A2->hysteresis >> 1;
|
||||
|
||||
if (serving_cell_rsrp + rsrp_hysteresis < rsrp_threshold) {
|
||||
if (!nr_timer_is_active(&l3_measurements->TA2) && (l3_measurements->reports_sent == 0)) {
|
||||
if (!nr_timer_is_active(¶ms->TA2) && (params->reports_sent == 0)) {
|
||||
start_meas_event(l3_measurements,
|
||||
rrcNB,
|
||||
&l3_measurements->TA2,
|
||||
¶ms->TA2,
|
||||
event_trigger_config,
|
||||
report_config_id,
|
||||
event_A2->a2_Threshold.present,
|
||||
@@ -2850,8 +2940,8 @@ static void handle_event_a2(l3_measurements_t *l3_measurements,
|
||||
rsrp_hysteresis,
|
||||
rsrp_threshold);
|
||||
}
|
||||
} else if (nr_timer_is_active(&l3_measurements->TA2) && (serving_cell_rsrp - rsrp_hysteresis > rsrp_threshold)) {
|
||||
stop_meas_event(l3_measurements, &l3_measurements->TA2);
|
||||
} else if (nr_timer_is_active(¶ms->TA2) && (serving_cell_rsrp - rsrp_hysteresis > rsrp_threshold)) {
|
||||
stop_meas_event(params, ¶ms->TA2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2865,6 +2955,10 @@ static void handle_event_a3(l3_measurements_t *l3_measurements,
|
||||
if (event_A3->a3_Offset.present != NR_MeasTriggerQuantityOffset_PR_rsrp)
|
||||
return;
|
||||
|
||||
int meas_id = get_meas_id(rrcNB, report_config_id);
|
||||
if (meas_id < 0)
|
||||
return;
|
||||
meas_report_params_t *params = &l3_measurements->meas_report[meas_id];
|
||||
meas_t *serving_cell = &l3_measurements->serving_cell;
|
||||
|
||||
int serving_cell_rsrp = get_rsrp_value(serving_cell);
|
||||
@@ -2903,10 +2997,10 @@ static void handle_event_a3(l3_measurements_t *l3_measurements,
|
||||
}
|
||||
|
||||
// Trigger event if any neighbor meets entry condition
|
||||
if (entry_cond_met && !nr_timer_is_active(&l3_measurements->TA3) && (l3_measurements->reports_sent == 0)) {
|
||||
if (entry_cond_met && !nr_timer_is_active(¶ms->TA3) && (params->reports_sent == 0)) {
|
||||
start_meas_event(l3_measurements,
|
||||
rrcNB,
|
||||
&l3_measurements->TA3,
|
||||
¶ms->TA3,
|
||||
event_trigger_config,
|
||||
report_config_id,
|
||||
NR_MeasTriggerQuantityOffset_PR_rsrp,
|
||||
@@ -2921,8 +3015,8 @@ static void handle_event_a3(l3_measurements_t *l3_measurements,
|
||||
rsrp_hysteresis);
|
||||
}
|
||||
// Stop event if all neighbors are below leaving threshold
|
||||
else if (nr_timer_is_active(&l3_measurements->TA3) && !above_leaving_threshold) {
|
||||
stop_meas_event(l3_measurements, &l3_measurements->TA3);
|
||||
else if (nr_timer_is_active(¶ms->TA3) && !above_leaving_threshold) {
|
||||
stop_meas_event(params, ¶ms->TA3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3560,22 +3654,38 @@ void nr_rrc_set_mac_queue(instance_t instance, notifiedFIFO_t *mac_input_nf)
|
||||
rrc->mac_input_nf = mac_input_nf;
|
||||
}
|
||||
|
||||
void rrc_ue_generate_measurementReport(rrcPerNB_t *rrc, instance_t ue_id)
|
||||
void rrc_ue_generate_measurementReport(rrcPerNB_t *rrc, instance_t ue_id, int meas_id)
|
||||
{
|
||||
uint8_t buffer[NR_RRC_BUF_SIZE];
|
||||
l3_measurements_t *l3m = &rrc->l3_measurements;
|
||||
int rsrp_dBm = l3m->rs_type == NR_NR_RS_Type_ssb ? l3m->serving_cell.ss_rsrp_dBm.val : l3m->serving_cell.csi_rsrp_dBm.val;
|
||||
meas_report_params_t *params = &l3m->meas_report[meas_id];
|
||||
int rsrp_dBm = params->rs_type == NR_NR_RS_Type_ssb ? l3m->serving_cell.ss_rsrp_dBm.val : l3m->serving_cell.csi_rsrp_dBm.val;
|
||||
int rsrp_index = get_rsrp_index(rsrp_dBm);
|
||||
int neighbor_rsrp_dBm =
|
||||
l3m->rs_type == NR_NR_RS_Type_ssb ? l3m->neighboring_cell[0].ss_rsrp_dBm.val : l3m->neighboring_cell[0].csi_rsrp_dBm.val;
|
||||
int neighbor_rsrp_index = get_rsrp_index(neighbor_rsrp_dBm);
|
||||
uint8_t size = do_nrMeasurementReport_SA(l3m->trigger_to_measid,
|
||||
l3m->trigger_quantity,
|
||||
l3m->rs_type,
|
||||
uint16_t neighbor_pci = 0;
|
||||
int neighbor_rsrp_index = 0;
|
||||
bool neighbor_valid = false;
|
||||
|
||||
// Check if neighbor cell measurement is actually available
|
||||
if (params->neighbor_cell_valid) {
|
||||
bool is_valid = (params->rs_type == NR_NR_RS_Type_ssb) ? l3m->neighboring_cell[0].ss_rsrp_dBm.init
|
||||
: l3m->neighboring_cell[0].csi_rsrp_dBm.init;
|
||||
|
||||
if (is_valid) {
|
||||
neighbor_pci = l3m->neighboring_cell[0].Nid_cell;
|
||||
int neighbor_rsrp_dBm = (params->rs_type == NR_NR_RS_Type_ssb) ? l3m->neighboring_cell[0].ss_rsrp_dBm.val
|
||||
: l3m->neighboring_cell[0].csi_rsrp_dBm.val;
|
||||
neighbor_rsrp_index = get_rsrp_index(neighbor_rsrp_dBm);
|
||||
neighbor_valid = true;
|
||||
}
|
||||
}
|
||||
uint8_t size = do_nrMeasurementReport_SA(meas_id,
|
||||
params->trigger_quantity,
|
||||
params->report_rsrp,
|
||||
params->rs_type,
|
||||
l3m->serving_cell.Nid_cell,
|
||||
rsrp_index,
|
||||
l3m->neighbor_cell_valid,
|
||||
l3m->neighboring_cell[0].Nid_cell,
|
||||
neighbor_valid,
|
||||
neighbor_pci,
|
||||
neighbor_rsrp_index,
|
||||
buffer,
|
||||
sizeof(buffer));
|
||||
|
||||
@@ -193,21 +193,25 @@ typedef enum {
|
||||
|
||||
typedef enum { RB_NOT_PRESENT, RB_ESTABLISHED, RB_SUSPENDED } NR_RB_status_t;
|
||||
|
||||
typedef struct l3_measurements_s {
|
||||
float ssb_filter_coeff_rsrp;
|
||||
float csi_RS_filter_coeff_rsrp;
|
||||
meas_t serving_cell;
|
||||
meas_t neighboring_cell[NUMBER_OF_NEIGHBORING_CELLS_MAX];
|
||||
long trigger_to_measid;
|
||||
typedef struct meas_report_params_s {
|
||||
long trigger_quantity;
|
||||
long rs_type;
|
||||
int reports_sent;
|
||||
int max_reports;
|
||||
long report_interval_ms;
|
||||
bool neighbor_cell_valid;
|
||||
bool report_rsrp;
|
||||
NR_timer_t TA2;
|
||||
NR_timer_t TA3;
|
||||
NR_timer_t periodic_report_timer;
|
||||
} meas_report_params_t;
|
||||
|
||||
typedef struct l3_measurements_s {
|
||||
float ssb_filter_coeff_rsrp;
|
||||
float csi_RS_filter_coeff_rsrp;
|
||||
meas_t serving_cell;
|
||||
meas_t neighboring_cell[NUMBER_OF_NEIGHBORING_CELLS_MAX];
|
||||
meas_report_params_t meas_report[MAX_MEAS_ID];
|
||||
} l3_measurements_t;
|
||||
|
||||
typedef struct rrcPerNB {
|
||||
|
||||
@@ -52,7 +52,7 @@ void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc,
|
||||
|
||||
void handle_RRCRelease(NR_UE_RRC_INST_t *rrc);
|
||||
|
||||
void rrc_ue_generate_measurementReport(rrcPerNB_t *rrc, instance_t ue_id);
|
||||
void rrc_ue_generate_measurementReport(rrcPerNB_t *rrc, instance_t ue_id, int meas_id);
|
||||
|
||||
void set_rlf_sib1_timers_and_constants(NR_UE_Timers_Constants_t *tac, NR_UE_TimersAndConstants_t *ue_TimersAndConstants);
|
||||
|
||||
|
||||
@@ -128,38 +128,63 @@ void handle_meas_timers(NR_UE_RRC_INST_t *rrc)
|
||||
rrcPerNB_t *nb = &rrc->perNB[i];
|
||||
l3_measurements_t *l3_measurements = &nb->l3_measurements;
|
||||
|
||||
bool ta2_expired = nr_timer_tick(&l3_measurements->TA2);
|
||||
bool ta3_expired = nr_timer_tick(&l3_measurements->TA3);
|
||||
if (ta2_expired && l3_measurements->trigger_quantity > 0) {
|
||||
rrc_ue_generate_measurementReport(nb, rrc->ue_id);
|
||||
l3_measurements->reports_sent = 1;
|
||||
for (int meas_id = 0; meas_id < MAX_MEAS_ID; meas_id++) {
|
||||
meas_report_params_t *params = &l3_measurements->meas_report[meas_id];
|
||||
|
||||
if (l3_measurements->reports_sent < l3_measurements->max_reports
|
||||
&& !nr_timer_is_active(&l3_measurements->periodic_report_timer)) {
|
||||
nr_timer_setup(&l3_measurements->periodic_report_timer, l3_measurements->report_interval_ms, 10);
|
||||
nr_timer_start(&l3_measurements->periodic_report_timer);
|
||||
// Check if this measId is configured
|
||||
if (nb->MeasId[meas_id] == NULL)
|
||||
continue;
|
||||
|
||||
// Handle Event A2 timer expiry
|
||||
bool ta2_expired = nr_timer_tick(¶ms->TA2);
|
||||
if (ta2_expired && params->trigger_quantity > 0) {
|
||||
rrc_ue_generate_measurementReport(nb, rrc->ue_id, meas_id);
|
||||
params->reports_sent = 1;
|
||||
|
||||
if (params->reports_sent < params->max_reports && !nr_timer_is_active(¶ms->periodic_report_timer)) {
|
||||
nr_timer_setup(¶ms->periodic_report_timer, params->report_interval_ms, 10);
|
||||
nr_timer_start(¶ms->periodic_report_timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ta3_expired && l3_measurements->trigger_quantity > 0) {
|
||||
rrc_ue_generate_measurementReport(nb, rrc->ue_id);
|
||||
l3_measurements->reports_sent = 1;
|
||||
// Handle Event A3 timer expiry
|
||||
bool ta3_expired = nr_timer_tick(¶ms->TA3);
|
||||
if (ta3_expired && params->trigger_quantity > 0) {
|
||||
rrc_ue_generate_measurementReport(nb, rrc->ue_id, meas_id);
|
||||
params->reports_sent = 1;
|
||||
|
||||
if (l3_measurements->reports_sent < l3_measurements->max_reports
|
||||
&& !nr_timer_is_active(&l3_measurements->periodic_report_timer)) {
|
||||
nr_timer_setup(&l3_measurements->periodic_report_timer, l3_measurements->report_interval_ms, 10);
|
||||
nr_timer_start(&l3_measurements->periodic_report_timer);
|
||||
if (params->reports_sent < params->max_reports && !nr_timer_is_active(¶ms->periodic_report_timer)) {
|
||||
nr_timer_setup(¶ms->periodic_report_timer, params->report_interval_ms, 10);
|
||||
nr_timer_start(¶ms->periodic_report_timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool periodic_expired = nr_timer_tick(&l3_measurements->periodic_report_timer);
|
||||
if (periodic_expired && l3_measurements->reports_sent < l3_measurements->max_reports) {
|
||||
rrc_ue_generate_measurementReport(nb, rrc->ue_id);
|
||||
l3_measurements->reports_sent++;
|
||||
// Handle periodical report
|
||||
// Per TS 38.331 Section 5.5.4.1, initiate measurement reporting immediately
|
||||
// after the quantity to be reported becomes available for the NR SpCell
|
||||
if (params->trigger_quantity == 0 && params->reports_sent == 0 && nr_timer_is_active(¶ms->periodic_report_timer)) {
|
||||
bool meas_available = (params->rs_type == NR_NR_RS_Type_ssb) ? l3_measurements->serving_cell.ss_rsrp_dBm.init
|
||||
: l3_measurements->serving_cell.csi_rsrp_dBm.init;
|
||||
if (meas_available) {
|
||||
rrc_ue_generate_measurementReport(nb, rrc->ue_id, meas_id);
|
||||
params->reports_sent = 1;
|
||||
if (params->reports_sent < params->max_reports) {
|
||||
nr_timer_setup(¶ms->periodic_report_timer, params->report_interval_ms, 10);
|
||||
nr_timer_start(¶ms->periodic_report_timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (l3_measurements->reports_sent < l3_measurements->max_reports) {
|
||||
nr_timer_setup(&l3_measurements->periodic_report_timer, l3_measurements->report_interval_ms, 10);
|
||||
nr_timer_start(&l3_measurements->periodic_report_timer);
|
||||
// Handle periodic report timer expiry for subsequent reports
|
||||
bool periodic_expired = nr_timer_tick(¶ms->periodic_report_timer);
|
||||
if (periodic_expired && params->reports_sent > 0 && params->reports_sent < params->max_reports) {
|
||||
rrc_ue_generate_measurementReport(nb, rrc->ue_id, meas_id);
|
||||
params->reports_sent++;
|
||||
|
||||
if (params->reports_sent < params->max_reports) {
|
||||
nr_timer_setup(¶ms->periodic_report_timer, params->report_interval_ms, 10);
|
||||
nr_timer_start(¶ms->periodic_report_timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user