Compare commits

...

1 Commits

Author SHA1 Message Date
alexjiao
3876725ead UE sends the periodical measurement report
UE sends the periodical measurement report of serving and neighboring cells
2026-02-13 16:45:33 +08:00
6 changed files with 288 additions and 147 deletions

View File

@@ -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)

View File

@@ -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,

View File

@@ -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(&params->TA2);
nr_timer_stop(&params->TA3);
nr_timer_stop(&params->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(&params->periodic_report_timer)) {
nr_timer_setup(&params->periodic_report_timer, params->report_interval_ms, 10);
nr_timer_start(&params->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(&params->TA2) && (params->reports_sent == 0)) {
start_meas_event(l3_measurements,
rrcNB,
&l3_measurements->TA2,
&params->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(&params->TA2) && (serving_cell_rsrp - rsrp_hysteresis > rsrp_threshold)) {
stop_meas_event(params, &params->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(&params->TA3) && (params->reports_sent == 0)) {
start_meas_event(l3_measurements,
rrcNB,
&l3_measurements->TA3,
&params->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(&params->TA3) && !above_leaving_threshold) {
stop_meas_event(params, &params->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));

View File

@@ -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 {

View File

@@ -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);

View File

@@ -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(&params->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(&params->periodic_report_timer)) {
nr_timer_setup(&params->periodic_report_timer, params->report_interval_ms, 10);
nr_timer_start(&params->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(&params->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(&params->periodic_report_timer)) {
nr_timer_setup(&params->periodic_report_timer, params->report_interval_ms, 10);
nr_timer_start(&params->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(&params->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(&params->periodic_report_timer, params->report_interval_ms, 10);
nr_timer_start(&params->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(&params->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(&params->periodic_report_timer, params->report_interval_ms, 10);
nr_timer_start(&params->periodic_report_timer);
}
}
}
}