Add neighboring cell measurements

Implement intra-frequency neighboring cell measurements including:
- Measurement configuration structures
- Blind search and known PCI validation
- RSRP measurements for neighbor cells

Co-authored-by: Roberto Louro Magueta <rmagueta@allbesmart.pt>
This commit is contained in:
alexjiao
2026-01-09 20:05:11 +08:00
co-authored by Roberto Louro Magueta
parent dfd3ad267e
commit 3fdbe01157
9 changed files with 523 additions and 26 deletions
@@ -29,6 +29,11 @@
#define NFAPI_UE_MAX_NUM_CB 8
#define NFAPI_MAX_NUM_UL_PDU 255
#define NFAPI_MAX_NUM_CSI_RATEMATCH 4
// Maximum number of neighboring cells that can be tracked simultaneously
// Set to 1 due to PSS search limitation: pss_search_time_nr() returns only
// the single strongest PSS correlation peak, making it impossible to reliably
// detect multiple neighbor cells in the same measurement cycle
#define NUMBER_OF_NEIGHBORING_CELLS_MAX 1
/*
typedef unsigned int uint32_t;
@@ -718,6 +723,16 @@ typedef struct
} fapi_nr_prach_config_t;
typedef struct {
uint16_t Nid_cell;
uint8_t active;
uint32_t ssb_freq;
} fapi_nr_neighboring_cell_t;
typedef struct {
fapi_nr_neighboring_cell_t nr_neighboring_cell[NUMBER_OF_NEIGHBORING_CELLS_MAX];
} fapi_nr_meas_config_t;
typedef struct {
int16_t target_Nid_cell;
bool ssb_bw_scan;
@@ -733,7 +748,7 @@ typedef struct {
fapi_nr_tdd_table_t tdd_table;
fapi_nr_prach_config_t prach_config;
fapi_nr_ntn_config_t ntn_config;
fapi_nr_meas_config_t meas_config;
} fapi_nr_config_request_t;
#endif
+14 -1
View File
@@ -114,10 +114,23 @@ uint32_t nr_ue_calculate_ssb_rsrp(const NR_DL_FRAME_PARMS *fp,
int ssb_start_subcarrier);
void nr_ue_ssb_rsrp_measurements(PHY_VARS_NR_UE *ue,
uint8_t gNB_index,
int ssb_index,
const UE_nr_rxtx_proc_t *proc,
c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]);
// Structure to pass data to neighboring cell measurement task
typedef struct {
UE_nr_rxtx_proc_t proc;
PHY_VARS_NR_UE *ue;
c16_t *rxdata[NB_RX_ANTENNAS_MAX];
uint32_t rxdata_size;
c16_t rxdata_ant[];
} nr_meas_task_args_t;
void nr_ue_meas_neighboring_cell(void *arg);
void do_neighboring_cell_measurements(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, c16_t **rxdata, uint32_t rxdata_size);
void nr_ue_rrc_measurements(PHY_VARS_NR_UE *ue,
const UE_nr_rxtx_proc_t *proc,
c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]);
@@ -37,6 +37,12 @@
#include "common/utils/LOG/log.h"
#include "PHY/sse_intrin.h"
#include "SCHED_NR_UE/defs.h"
#include "PHY/NR_REFSIG/sss_nr.h"
#include "PHY/NR_REFSIG/pss_nr.h"
#include "PHY/NR_REFSIG/ss_pbch_nr.h"
#include "PHY/MODULATION/modulation_UE.h"
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
#include "PHY/NR_UE_ESTIMATION/nr_estimation.h"
#define K1 ((long long int) 512)
#define K2 ((long long int) (1024-K1))
@@ -246,6 +252,271 @@ void nr_ue_ssb_rsrp_measurements(PHY_VARS_NR_UE *ue,
ue->if_inst->dl_indication(&dl_indication);
}
static bool search_neighboring_cell(NR_DL_FRAME_PARMS *frame_parms,
fapi_nr_neighboring_cell_t *nr_neighboring_cell,
neighboring_cell_info_t *neighboring_cell_info,
c16_t **rxdata,
uint32_t rxdata_size,
uint32_t rxdataF_sz,
c16_t rxdataF[][rxdataF_sz],
c16_t pssTime[][frame_parms->ofdm_symbol_size])
{
int detected_nid_cell = -1;
int ssb_offset = 0;
int freq_offset_pss = 0;
int pss_peak = 0;
int pss_avg = 0;
int32_t sss_metric = 0;
uint8_t sss_phase = 0;
int freq_offset_sss = 0;
nr_ssb_search_params_t search_params = {
.frame_parms = frame_parms,
.rxdata = rxdata,
.rxdata_size = rxdata_size,
.ssb_start_subcarrier = frame_parms->ssb_start_subcarrier,
.target_nid_cell = -1, // Blind search
.exclude_nid_cell = frame_parms->Nid_cell, // Exclude serving cell
.apply_freq_offset = false,
.search_frame_id = 0, // Search in first frame of buffer
.fo_flag = false,
.rxdataF = rxdataF,
.pssTime = pssTime,
.detected_nid_cell = &detected_nid_cell,
.ssb_offset = &ssb_offset,
.sss_metric = &sss_metric,
.freq_offset_pss = &freq_offset_pss,
.freq_offset_sss = &freq_offset_sss,
.sss_phase = &sss_phase,
.pss_peak = &pss_peak,
.pss_avg = &pss_avg,
};
bool found = nr_search_ssb_common(&search_params);
if (found) {
nr_neighboring_cell->Nid_cell = detected_nid_cell;
LOG_I(NR_PHY,
"Found neighbor cell PCI=%d (sss_metric=%d, ssb_offset=%d, pss_peak=%d dB, pss_avg=%d dB)\n",
detected_nid_cell,
sss_metric,
ssb_offset,
pss_peak,
pss_avg);
// Update search window
neighboring_cell_info->pss_search_start = ssb_offset + frame_parms->nb_prefix_samples - 16;
neighboring_cell_info->pss_search_length = 32;
}
return found;
}
static bool validate_known_pci(NR_DL_FRAME_PARMS *frame_parms,
fapi_nr_neighboring_cell_t *nr_neighboring_cell,
neighboring_cell_info_t *neighboring_cell_info,
c16_t **rxdata,
uint32_t rxdataF_sz,
c16_t rxdataF[][rxdataF_sz],
c16_t pssTime[][frame_parms->ofdm_symbol_size])
{
int known_pci = nr_neighboring_cell->Nid_cell;
int pss_index = GET_NID2(known_pci);
int f_off = 0;
int pss_peak = 0;
int pss_avg = 0;
int start = neighboring_cell_info->pss_search_start;
int length = neighboring_cell_info->pss_search_length;
int peak_position = pss_search_time_nr((const c16_t **)rxdata,
frame_parms,
pssTime,
false, // no frequency offset estimation for tracking
0, // first frame
known_pci,
&pss_index,
&f_off,
&pss_peak,
&pss_avg,
start,
length);
if (peak_position < frame_parms->nb_prefix_samples) {
if (neighboring_cell_info->valid_meas)
neighboring_cell_info->consec_fail++;
LOG_D(NR_PHY,
"PSS validation failed for PCI=%d (search window: start=%d, length=%d, peak=%d dB, avg=%d dB), consec_fail=%d\n",
known_pci,
start,
length,
pss_peak,
pss_avg,
neighboring_cell_info->consec_fail);
return false;
}
int ssb_offset = peak_position - frame_parms->nb_prefix_samples;
uint8_t sss_symbol = SSS_SYMBOL_NB - PSS_SYMBOL_NB;
nr_slot_fep(NULL, frame_parms, 0, 0, rxdataF, link_type_dl, ssb_offset, (c16_t **)rxdata);
nr_slot_fep(NULL, frame_parms, 0, sss_symbol, rxdataF, link_type_dl, ssb_offset, (c16_t **)rxdata);
int detected_nid_cell = -1;
int32_t sss_metric = 0;
uint8_t sss_phase = 0;
int freq_offset_sss = 0;
bool sss_detected = rx_sss_nr(frame_parms,
pss_index,
known_pci,
0,
frame_parms->ssb_start_subcarrier,
&detected_nid_cell,
&sss_metric,
&sss_phase,
&freq_offset_sss,
rxdataF);
if (!sss_detected) {
if (neighboring_cell_info->valid_meas)
neighboring_cell_info->consec_fail++;
LOG_D(NR_PHY,
"Known PCI validation failed for PCI=%d (metric=%d), consec_fail=%d\n",
known_pci,
sss_metric,
neighboring_cell_info->consec_fail);
return false;
}
LOG_D(NR_PHY, "Known PCI validation completed for PCI=%d, metric=%d\n", known_pci, sss_metric);
neighboring_cell_info->consec_fail = 0;
neighboring_cell_info->valid_meas = true;
neighboring_cell_info->pss_search_start = peak_position - 16;
neighboring_cell_info->pss_search_length = 32;
return true;
}
void do_neighboring_cell_measurements(UE_nr_rxtx_proc_t *proc, PHY_VARS_NR_UE *ue, c16_t **rxdata, uint32_t rxdata_size)
{
NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
const uint32_t rxdataF_sz = ue->frame_parms.samples_per_slot_wCP;
// Generate PSS time-domain sequences once for all neighbor cells
__attribute__((aligned(32))) c16_t pssTime[NUMBER_PSS_SEQUENCE][frame_parms->ofdm_symbol_size];
for (int nid2_idx = 0; nid2_idx < NUMBER_PSS_SEQUENCE; nid2_idx++) {
generate_pss_nr_time(frame_parms, nid2_idx, frame_parms->ssb_start_subcarrier, pssTime[nid2_idx]);
}
__attribute__((aligned(32))) c16_t rxdataF[ue->frame_parms.nb_antennas_rx][rxdataF_sz];
for (int cell_idx = 0; cell_idx < NUMBER_OF_NEIGHBORING_CELLS_MAX; cell_idx++) {
fapi_nr_neighboring_cell_t *neighbor_cell = &ue->nrUE_config.meas_config.nr_neighboring_cell[cell_idx];
if (neighbor_cell->active == 0) {
continue;
}
memset(rxdataF, 0, sizeof(rxdataF));
neighboring_cell_info_t *neighboring_cell_info = &ue->measurements.neighboring_cell_info[cell_idx];
// performing the correlation on a frame length plus two symbols
// to take into account the possibility of PSS between the two frames
if (neighboring_cell_info->pss_search_length == 0) {
neighboring_cell_info->pss_search_length = frame_parms->samples_per_frame + (2 * frame_parms->ofdm_symbol_size);
}
bool is_blind_search = (neighbor_cell->Nid_cell == (uint16_t)-1) || (neighbor_cell->Nid_cell == frame_parms->Nid_cell);
if (neighbor_cell->Nid_cell == frame_parms->Nid_cell) {
LOG_D(NR_PHY, "Neighbor cell PCI %d matches serving cell, using blind search\n", neighbor_cell->Nid_cell);
neighboring_cell_info->pss_search_start = 0;
neighboring_cell_info->pss_search_length = frame_parms->samples_per_frame + (2 * frame_parms->ofdm_symbol_size);
}
LOG_D(NR_PHY,
"Neighbor cell measurement: Nid_cell=%u, is_blind_search=%s, active=%u\n",
neighbor_cell->Nid_cell,
is_blind_search ? "true" : "false",
neighbor_cell->active);
if (is_blind_search) {
if (!search_neighboring_cell(frame_parms,
neighbor_cell,
neighboring_cell_info,
rxdata,
rxdata_size,
rxdataF_sz,
rxdataF,
pssTime)) {
continue;
}
} else {
if (!validate_known_pci(frame_parms, neighbor_cell, neighboring_cell_info, rxdata, rxdataF_sz, rxdataF, pssTime)) {
if (neighboring_cell_info->consec_fail >= NEIGHBOR_CELL_MAX_CONSECUTIVE_FAILURES) {
LOG_D(NR_PHY, "Max consecutive failures reached for PCI=%d, resetting to full search\n", neighbor_cell->Nid_cell);
neighboring_cell_info->pss_search_start = 0;
neighboring_cell_info->pss_search_length = frame_parms->samples_per_frame + (2 * frame_parms->ofdm_symbol_size);
neighboring_cell_info->valid_meas = false;
neighboring_cell_info->consec_fail = 0;
// Send invalid RSRP to MAC to trigger reset
if (ue->if_inst && ue->if_inst->dl_indication) {
fapi_nr_l1_measurements_t l1_measurements = {
.gNB_index = proc->gNB_id,
.meas_type = NFAPI_NR_SS_MEAS,
.Nid_cell = neighbor_cell->Nid_cell,
.is_neighboring_cell = true,
.rsrp_dBm = INT_MAX,
.ssb_index = -1,
.sinr_dB = 0.0,
};
nr_downlink_indication_t dl_indication = {0};
fapi_nr_rx_indication_t rx_ind = {0};
nr_fill_dl_indication(&dl_indication, NULL, &rx_ind, proc, ue, NULL);
nr_fill_rx_indication(&rx_ind, FAPI_NR_MEAS_IND, ue, NULL, NULL, 1, proc, &l1_measurements, NULL);
ue->if_inst->dl_indication(&dl_indication);
}
}
continue;
}
}
// RSRP measurements
neighboring_cell_info->ssb_rsrp = nr_ue_calculate_ssb_rsrp(frame_parms, proc, rxdataF, 0, frame_parms->ssb_start_subcarrier);
neighboring_cell_info->ssb_rsrp_dBm = 10 * log10(neighboring_cell_info->ssb_rsrp) + 30 - SQ15_SQUARED_NORM_FACTOR_DB
- ((int)ue->openair0_cfg[0].rx_gain[0] - (int)ue->openair0_cfg[0].rx_gain_offset[0])
- dB_fixed(ue->frame_parms.ofdm_symbol_size);
// Send SS measurements to MAC
if (!ue->if_inst || !ue->if_inst->dl_indication)
continue;
fapi_nr_l1_measurements_t l1_measurements = {
.gNB_index = proc->gNB_id,
.meas_type = NFAPI_NR_SS_MEAS,
.Nid_cell = nr_neighboring_cell->Nid_cell,
.is_neighboring_cell = true,
.rsrp_dBm = neighboring_cell_info->ssb_rsrp_dBm,
};
nr_downlink_indication_t dl_indication = {0};
fapi_nr_rx_indication_t rx_ind = {0};
nr_fill_dl_indication(&dl_indication, NULL, &rx_ind, proc, ue, NULL);
nr_fill_rx_indication(&rx_ind, FAPI_NR_MEAS_IND, ue, NULL, NULL, 1, proc, &l1_measurements, NULL);
ue->if_inst->dl_indication(&dl_indication);
}
}
void nr_ue_meas_neighboring_cell(void *arg)
{
nr_meas_task_args_t *args = (nr_meas_task_args_t *)arg;
do_neighboring_cell_measurements(&args->proc, args->ue, args->rxdata, args->rxdata_size);
args->ue->measurements.meas_request_pending = false;
free(args);
}
// This function computes the received noise power
// Measurement units:
// - psd_awgn (AWGN power spectral density): dBm/Hz
+14 -1
View File
@@ -125,6 +125,17 @@ typedef enum {
#define debug_msg if (((mac_xface->frame%100) == 0) || (mac_xface->frame < 50)) msg
#define NEIGHBOR_CELL_MAX_CONSECUTIVE_FAILURES 10
typedef struct {
int pss_search_start;
int pss_search_length;
uint32_t ssb_rsrp;
int ssb_rsrp_dBm;
int consec_fail; // Counter for consecutive detection failures
bool valid_meas;
} neighboring_cell_info_t;
typedef struct {
uint8_t decoded_output[3]; // PBCH paylod not larger than 3B
uint8_t xtra_byte;
@@ -214,7 +225,9 @@ typedef struct {
unsigned char nb_antennas_rx;
/// DLSCH error counter
// short dlsch_errors;
/// Info about neighboring cells to perform the measurements
neighboring_cell_info_t neighboring_cell_info[NUMBER_OF_NEIGHBORING_CELLS_MAX];
bool meas_request_pending;
} PHY_NR_MEASUREMENTS;
typedef struct {
@@ -973,6 +973,32 @@ static void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
}
static bool check_meas_to_perform(PHY_VARS_NR_UE *ue, int nr_slot_rx)
{
if (nr_slot_rx != 0) {
return false;
}
if (ue->measurements.meas_request_pending == true) {
return false;
}
// Check if any intra-frequency neighbor cells are configured
uint32_t serving_ssb_freq = get_ssb_arfcn(&ue->frame_parms);
bool has_intra_freq_neighbors = false;
for (int cell_idx = 0; cell_idx < NUMBER_OF_NEIGHBORING_CELLS_MAX; cell_idx++) {
fapi_nr_neighboring_cell_t *nr_neighboring_cell = &ue->nrUE_config.meas_config.nr_neighboring_cell[cell_idx];
if (nr_neighboring_cell->active == 1) {
if (nr_neighboring_cell->ssb_freq == 0 || nr_neighboring_cell->ssb_freq == serving_ssb_freq) {
has_intra_freq_neighbors = true;
}
}
}
return has_intra_freq_neighbors;
}
static bool is_ssb_index_transmitted(const PHY_VARS_NR_UE *ue, const int index)
{
if (ue->received_config_request) {
@@ -1188,6 +1214,28 @@ int pbch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_da
} // for i
} // for rsc_id
} // for gNB_id
PHY_NR_MEASUREMENTS *measurements = &ue->measurements;
if (check_meas_to_perform(ue, nr_slot_rx)) {
measurements->meas_request_pending = true;
// Copy rxdata
uint32_t rxdata_size = (2 * (fp->samples_per_frame) + fp->ofdm_symbol_size);
size_t total_size = sizeof(nr_meas_task_args_t) + fp->nb_antennas_rx * rxdata_size * sizeof(c16_t);
nr_meas_task_args_t *args = malloc(total_size);
args->proc = *proc;
args->ue = ue;
args->rxdata_size = rxdata_size;
for (int i = 0; i < fp->nb_antennas_rx; i++) {
args->rxdata[i] = &args->rxdata_ant[i * rxdata_size];
memcpy(args->rxdata[i], ue->common_vars.rxdata[i], rxdata_size * sizeof(c16_t));
}
task_t t = {.func = nr_ue_meas_neighboring_cell, .args = args};
pushTpool(&get_nrUE_params()->Tpool, t);
}
TracyCZoneEnd(ctx);
return sampleShift;
}
+14
View File
@@ -2858,3 +2858,17 @@ void nr_rrc_mac_config_req_cg(module_id_t module_id,
ret = pthread_mutex_unlock(&mac->if_mutex);
AssertFatal(!ret, "mutex failed %d\n", ret);
}
void nr_rrc_mac_config_req_meas(module_id_t module_id, const nr_neighbor_cell_info_t *neighbor_cells, int num_neighbors)
{
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
for (int i = 0; i < num_neighbors && i < NUMBER_OF_NEIGHBORING_CELLS_MAX; i++) {
fapi_nr_neighboring_cell_t *phy_cell = &mac->phy_config.config_req.meas_config.nr_neighboring_cell[i];
phy_cell->Nid_cell = neighbor_cells[i].Nid_cell;
phy_cell->ssb_freq = neighbor_cells[i].ssb_freq;
phy_cell->active = neighbor_cells[i].active;
}
mac->if_module->phy_config_request(&mac->phy_config);
}
+8
View File
@@ -97,6 +97,14 @@ void nr_rrc_mac_config_other_sib(module_id_t module_id, NR_SIB19_r17_t *sib19_r1
void nr_rrc_mac_resume_rb(module_id_t module_id, bool is_srb, int rb_id);
void nr_rrc_mac_config_req_reset(module_id_t module_id, NR_UE_MAC_reset_cause_t cause);
typedef struct nr_neighbor_cell_info {
int16_t Nid_cell; // Physical Cell ID
uint32_t ssb_freq; // SSB frequency (ARFCN)
uint8_t active; // 1 = active, 0 = inactive
} nr_neighbor_cell_info_t;
void nr_rrc_mac_config_req_meas(module_id_t module_id, const nr_neighbor_cell_info_t *neighbor_cells, int num_neighbors);
/**\brief initialization NR UE MAC instance(s)*/
NR_UE_MAC_INST_t * nr_l2_init_ue(int nb_inst);
+136 -23
View File
@@ -921,6 +921,14 @@ static void nr_rrc_manage_rlc_bearers(NR_UE_RRC_INST_t *rrc, const NR_CellGroupC
}
}
static void nr_ue_meas_reset(meas_t *meas_cell, bool csi_meas)
{
if (csi_meas)
meas_cell->csi_rsrp_dBm.init = false;
else
meas_cell->ss_rsrp_dBm.init = false;
}
static void nr_rrc_process_reconfigurationWithSync(NR_UE_RRC_INST_t *rrc,
NR_ReconfigurationWithSync_t *reconfigurationWithSync,
int gNB_index)
@@ -934,6 +942,24 @@ static void nr_rrc_process_reconfigurationWithSync(NR_UE_RRC_INST_t *rrc,
return;
}
// Clear neighbor cell lists from measurement objects during handover
rrcPerNB_t *rrcNB = &rrc->perNB[gNB_index];
for (int i = 0; i < MAX_MEAS_OBJ; i++) {
if (rrcNB->MeasObj[i] && rrcNB->MeasObj[i]->measObject.present == NR_MeasObjectToAddMod__measObject_PR_measObjectNR) {
NR_MeasObjectNR_t *measObjNR = rrcNB->MeasObj[i]->measObject.choice.measObjectNR;
if (measObjNR->cellsToAddModList) {
ASN_STRUCT_FREE(asn_DEF_NR_CellsToAddModList, measObjNR->cellsToAddModList);
measObjNR->cellsToAddModList = NULL;
}
}
}
l3_measurements_t *l3m = &rrcNB->l3_measurements;
for (int i = 0; i < NUMBER_OF_NEIGHBORING_CELLS_MAX; i++) {
nr_ue_meas_reset(&l3m->neighboring_cell[i], false);
nr_ue_meas_reset(&l3m->neighboring_cell[i], true);
}
if (reconfigurationWithSync->spCellConfigCommon) {
/* if the frequencyInfoDL is included, consider the target SpCell
to be one on the SSB frequency indicated by the frequencyInfoDL */
@@ -1353,7 +1379,11 @@ static void handle_measid_remove(rrcPerNB_t *rrc, struct NR_MeasIdToRemoveList *
}
}
static void handle_measid_addmod(rrcPerNB_t *rrc, struct NR_MeasIdToAddModList *addmod_list, NR_UE_Timers_Constants_t *timers)
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)
{
for (int i = 0; i < addmod_list->list.count; i++) {
NR_MeasId_t id = addmod_list->list.array[i]->measId;
@@ -1387,11 +1417,56 @@ static void handle_measid_addmod(rrcPerNB_t *rrc, struct NR_MeasIdToAddModList *
nr_timer_start(&timers->T321);
}
}
// Check for A3 event and extract neighbor cell info for MAC/PHY
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)++;
}
}
}
}
}
}
}
}
static void nr_rrc_ue_process_measConfig(rrcPerNB_t *rrc, NR_MeasConfig_t *const measConfig, NR_UE_Timers_Constants_t *timers)
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)
{
if (measConfig->measObjectToRemoveList)
handle_measobj_remove(rrc, measConfig->measObjectToRemoveList, timers);
@@ -1412,7 +1487,7 @@ static void nr_rrc_ue_process_measConfig(rrcPerNB_t *rrc, NR_MeasConfig_t *const
handle_measid_remove(rrc, measConfig->measIdToRemoveList, timers);
if (measConfig->measIdToAddModList)
handle_measid_addmod(rrc, measConfig->measIdToAddModList, timers);
handle_measid_addmod(rrc, measConfig->measIdToAddModList, timers, neighbor_cells, num_neighbors);
LOG_W(NR_RRC, "Measurement gaps not yet supported!\n");
@@ -1485,7 +1560,12 @@ static void nr_rrc_ue_process_rrcReconfiguration(NR_UE_RRC_INST_t *rrc, int gNB_
}
if (ie->measConfig) {
LOG_I(NR_RRC, "RRCReconfiguration includes Measurement Configuration\n");
nr_rrc_ue_process_measConfig(rrcNB, ie->measConfig, &rrc->timers_and_constants);
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);
if (num_neighbors > 0) {
nr_rrc_mac_config_req_meas(rrc->ue_id, neighbor_cells, num_neighbors);
}
}
if (ie->lateNonCriticalExtension) {
LOG_E(NR_RRC, "RRCReconfiguration includes lateNonCriticalExtension. Not handled.\n");
@@ -2613,13 +2693,10 @@ static void apply_ema(val_init_t *vi_rsrp_dBm, float filter_coeff_rsrp, int rsrp
*meas_init = true;
}
void nr_ue_meas_filtering(rrcPerNB_t *rrc, bool is_neighboring_cell, uint16_t Nid_cell, bool csi_meas, int rsrp_dBm)
void nr_ue_meas_filtering(rrcPerNB_t *rrc, meas_t *meas_cell, uint16_t Nid_cell, bool csi_meas, int rsrp_dBm)
{
if (is_neighboring_cell)
return;
l3_measurements_t *l3_measurements = &rrc->l3_measurements;
meas_t *meas_cell = &l3_measurements->serving_cell;
if (meas_cell->Nid_cell != Nid_cell) {
meas_cell->ss_rsrp_dBm.init = false;
meas_cell->csi_rsrp_dBm.init = false;
@@ -2788,6 +2865,54 @@ static void nr_rrc_handle_ra_indication(NR_UE_RRC_INST_t *rrc, bool ra_succeeded
}
}
static void nr_rrc_handle_meas_indication(NR_UE_RRC_INST_t *rrc, NRRrcMacMeasDataInd *meas_ind)
{
rrcPerNB_t *rrcNB = rrc->perNB + meas_ind->gnb_index;
l3_measurements_t *l3_measurements = &rrcNB->l3_measurements;
meas_t *meas_cell = NULL;
if (meas_ind->is_neighboring_cell) {
uint16_t target_nid_cell = meas_ind->Nid_cell;
for (int i = 0; i < NUMBER_OF_NEIGHBORING_CELLS_MAX; i++) {
if (l3_measurements->neighboring_cell[i].Nid_cell == target_nid_cell) {
meas_cell = &l3_measurements->neighboring_cell[i];
break;
}
}
if (!meas_cell) {
for (int i = 0; i < NUMBER_OF_NEIGHBORING_CELLS_MAX; i++) {
if (!l3_measurements->neighboring_cell[i].ss_rsrp_dBm.init && !l3_measurements->neighboring_cell[i].csi_rsrp_dBm.init) {
meas_cell = &l3_measurements->neighboring_cell[i];
break;
}
}
}
} else {
meas_cell = &l3_measurements->serving_cell;
}
if (!meas_cell) {
LOG_E(NR_RRC, "meas_cell not found!\n");
return;
}
if (meas_ind->is_neighboring_cell && meas_ind->rsrp_dBm == INT_MAX) {
LOG_W(NR_RRC, "[Nid_cell %i] Neighboring cell not detected. L3 measurements will be reset.\n", meas_ind->Nid_cell);
meas_cell->Nid_cell = meas_ind->Nid_cell;
nr_ue_meas_reset(meas_cell, meas_ind->is_csi_meas);
} else {
LOG_D(NR_RRC,
"[%s][Nid_cell %i] Received %s measurements: RSRP = %i (dBm)\n",
meas_ind->is_neighboring_cell ? "Neighboring cell" : "Active cell",
meas_ind->Nid_cell,
meas_ind->is_csi_meas ? "CSI meas" : "SSB meas",
meas_ind->rsrp_dBm);
nr_ue_meas_filtering(rrcNB, meas_cell, meas_ind->Nid_cell, meas_ind->is_csi_meas, meas_ind->rsrp_dBm);
nr_ue_check_meas_report(rrc, meas_ind->gnb_index);
}
}
void *rrc_nrue_task(void *args_p)
{
itti_mark_task_ready(TASK_RRC_NRUE);
@@ -2892,21 +3017,9 @@ void *rrc_nrue(void *notUsed)
nr_rrc_ue_decode_NR_SBCCH_SL_BCH_Message(rrc, sbcch->gnb_index,sbcch->frame, sbcch->slot, sbcch->sdu,
sbcch->sdu_size, sbcch->rx_slss_id);
break;
case NR_RRC_MAC_MEAS_DATA_IND:
LOG_D(NR_RRC, "[%s][Nid_cell %i] Received %s measurements: RSRP = %i (dBm)\n",
NR_RRC_MAC_MEAS_DATA_IND(msg_p).is_neighboring_cell? "Neighboring cell" : "Active cell",
NR_RRC_MAC_MEAS_DATA_IND(msg_p).Nid_cell,
NR_RRC_MAC_MEAS_DATA_IND(msg_p).is_csi_meas ? "CSI meas" : "SSB meas",
NR_RRC_MAC_MEAS_DATA_IND(msg_p).rsrp_dBm);
rrcPerNB_t *rrcNB = rrc->perNB + NR_RRC_MAC_MEAS_DATA_IND(msg_p).gnb_index;
nr_ue_meas_filtering(rrcNB,
NR_RRC_MAC_MEAS_DATA_IND(msg_p).is_neighboring_cell,
NR_RRC_MAC_MEAS_DATA_IND(msg_p).Nid_cell,
NR_RRC_MAC_MEAS_DATA_IND(msg_p).is_csi_meas,
NR_RRC_MAC_MEAS_DATA_IND(msg_p).rsrp_dBm);
nr_ue_check_meas_report(rrc, NR_RRC_MAC_MEAS_DATA_IND(msg_p).gnb_index);
nr_rrc_handle_meas_indication(rrc, &NR_RRC_MAC_MEAS_DATA_IND(msg_p));
break;
case NR_RRC_MAC_CCCH_DATA_IND: {
+2
View File
@@ -70,6 +70,7 @@
#define MAX_MEAS_CONFIG 64
#define MAX_MEAS_ID 64
#define MAX_QUANTITY_CONFIG 2
#define NUMBER_OF_NEIGHBORING_CELLS_MAX 1
typedef enum {
nr_SecondaryCellGroupConfig_r15=0,
@@ -196,6 +197,7 @@ 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;
long trigger_quantity;
long rs_type;