From fc4bd2e20ced1e5db83c9df9fa0cfa8473b328ec Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 28 May 2025 16:25:30 +0200 Subject: [PATCH 1/6] RRC configuration for more than 1 reported RS option via configuration file to limit the number of reports to be configured --- openair2/GNB_APP/gnb_config.c | 1 + openair2/GNB_APP/gnb_paramdef.h | 4 ++ openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 1 + openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c | 55 +++++++++++++++++--- 4 files changed, 53 insertions(+), 8 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 55110fc449..6f33946d93 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1431,6 +1431,7 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) LOG_I(GNB_APP, "SIB1 TDA %d\n", config.sib1_tda); config.do_CSIRS = *GNBParamList.paramarray[0][GNB_DO_CSIRS_IDX].iptr; config.do_SRS = *GNBParamList.paramarray[0][GNB_DO_SRS_IDX].iptr; + config.max_num_rsrp = *GNBParamList.paramarray[0][GNB_LIMIT_RSRP_REPORT_IDX].iptr; config.do_SINR = *GNBParamList.paramarray[0][GNB_DO_SINR_IDX].iptr; config.force_256qam_off = *GNBParamList.paramarray[0][GNB_FORCE256QAMOFF_IDX].iptr; config.force_UL256qam_off = *GNBParamList.paramarray[0][GNB_FORCEUL256QAMOFF_IDX].iptr; diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index 373958b1e8..e4e4bc3d2a 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -139,6 +139,7 @@ typedef enum { #define GNB_CONFIG_STRING_DU_SIB_LIST "du_sibs" #define GNB_CONFIG_STRING_DOSINR "do_SINR" #define GNB_CONFIG_STRING_1ST_ACTIVE_BWP "first_active_bwp" +#define GNB_CONFIG_STRING_LIMIT_RSRP_REPORT "max_num_RSRP_reported" #define GNB_CONFIG_HLP_STRING_ENABLE_SDAP "enable the SDAP layer\n" #define GNB_CONFIG_HLP_FORCE256QAMOFF "suppress activation of 256 QAM despite UE support" @@ -202,6 +203,7 @@ typedef enum { {GNB_CONFIG_STRING_DU_SIB_LIST, GNB_CONFIG_HLP_DU_SIBS, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \ {GNB_CONFIG_STRING_DOSINR, GNB_CONFIG_HLP_DOSINR, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ {GNB_CONFIG_STRING_1ST_ACTIVE_BWP, NULL, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ +{GNB_CONFIG_STRING_LIMIT_RSRP_REPORT, NULL, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ } // clang-format on @@ -246,6 +248,7 @@ typedef enum { #define GNB_DU_SIBS_IDX 37 #define GNB_DO_SINR_IDX 38 #define GNB_1ST_ACTIVE_BWP_IDX 39 +#define GNB_LIMIT_RSRP_REPORT_IDX 40 #define TRACKING_AREA_CODE_OKRANGE {0x0001,0xFFFD} #define NUM_DL_HARQ_OKVALUES {2,4,6,8,10,12,16,32} @@ -292,6 +295,7 @@ typedef enum { { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ } /*-------------------------------------------------------------------------------------------------------------------------------------------------*/ diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 50f77b681c..026d8d563e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -186,6 +186,7 @@ typedef struct nr_mac_config_t { int minRXTXTIME; int do_CSIRS; int do_SRS; + int max_num_rsrp; bool force_256qam_off; bool force_UL256qam_off; bool use_deltaMCS; diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c index bb108d4004..f8919a3fa8 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c @@ -2094,21 +2094,52 @@ static void config_csi_meas_report(NR_CSI_MeasConfig_t *csi_MeasConfig, asn1cSeqAdd(&csi_MeasConfig->csi_ReportConfigToAddModList->list, csirep); } +static long config_nrofReportedRS(const NR_UE_NR_Capability_t *uecap, + uint64_t ssb_bitmap, + const NR_ServingCellConfigCommon_t *scc, + int max_num_reported_rs) +{ + long nb_band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]; + int num_supported_rs = 0; + if (uecap) { + for (int i = 0; i < uecap->rf_Parameters.supportedBandListNR.list.count; i++) { + NR_BandNR_t *band = uecap->rf_Parameters.supportedBandListNR.list.array[i]; + if (band->bandNR == nb_band) { + if (band->mimo_ParametersPerBand && band->mimo_ParametersPerBand->maxNumberNonGroupBeamReporting) { + int maxNumberNonGroupBeamReporting = 1 << *band->mimo_ParametersPerBand->maxNumberNonGroupBeamReporting; + if (num_supported_rs == 0 || num_supported_rs > maxNumberNonGroupBeamReporting) + num_supported_rs = maxNumberNonGroupBeamReporting; + } + } + } + } + int configured_rs = max_num_reported_rs > 0 ? min(num_supported_rs, max_num_reported_rs) : num_supported_rs; + uint32_t num_ssb = count_bits64(ssb_bitmap); + if (num_ssb == 1 || configured_rs < 2) + return NR_CSI_ReportConfig__groupBasedBeamReporting__disabled__nrofReportedRS_n1; + if (num_ssb == 2 || configured_rs == 2) + return NR_CSI_ReportConfig__groupBasedBeamReporting__disabled__nrofReportedRS_n2; + if (num_ssb == 3 || configured_rs == 3) + return NR_CSI_ReportConfig__groupBasedBeamReporting__disabled__nrofReportedRS_n3; + return NR_CSI_ReportConfig__groupBasedBeamReporting__disabled__nrofReportedRS_n4; +} + static void config_rsrp_meas_report(NR_CSI_MeasConfig_t *csi_MeasConfig, + const NR_UE_NR_Capability_t *uecap, const NR_ServingCellConfigCommon_t *servingcellconfigcommon, NR_PUCCH_CSI_Resource_t *pucchcsires, - int do_csi, // if rsrp is based on CSI or SSB + const nr_mac_config_t *configuration, int rep_id, int uid, int curr_bwp, int num_antenna_ports, - bool do_sinr) + uint64_t ssb_bitmap) { int resource_id = -1; for (int csi_list = 0; csi_list < csi_MeasConfig->csi_ResourceConfigToAddModList->list.count; csi_list++) { NR_CSI_ResourceConfig_t *csires = csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_list]; if (csires->csi_RS_ResourceSetList.present == NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB) { - if (do_csi && num_antenna_ports < 4) { + if (configuration->do_CSIRS && num_antenna_ports < 4) { if (csires->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList) resource_id = csires->csi_ResourceConfigId; } else { @@ -2130,13 +2161,13 @@ static void config_rsrp_meas_report(NR_CSI_MeasConfig_t *csi_MeasConfig, csirep->reportConfigType.choice.periodic = calloc(1, sizeof(*csirep->reportConfigType.choice.periodic)); set_csi_meas_periodicity(servingcellconfigcommon, csirep, uid, curr_bwp, true); asn1cSeqAdd(&csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list, pucchcsires); - if (do_csi && num_antenna_ports < 4) { + if (configuration->do_CSIRS && num_antenna_ports < 4) { csirep->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP; csirep->reportQuantity.choice.cri_RSRP = (NULL_t)0; } else { csirep->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP; csirep->reportQuantity.choice.ssb_Index_RSRP = (NULL_t)0; - if (do_sinr) { + if (configuration->do_SINR) { csirep->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_none; csirep->reportQuantity.choice.none = (NULL_t)0; csirep->ext2 = calloc(1, sizeof(*csirep->ext2)); @@ -2148,7 +2179,10 @@ static void config_rsrp_meas_report(NR_CSI_MeasConfig_t *csi_MeasConfig, csirep->groupBasedBeamReporting.present = NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled; csirep->groupBasedBeamReporting.choice.disabled = calloc(1, sizeof(*csirep->groupBasedBeamReporting.choice.disabled)); csirep->groupBasedBeamReporting.choice.disabled->nrofReportedRS = calloc(1, sizeof(*csirep->groupBasedBeamReporting.choice.disabled->nrofReportedRS)); - *csirep->groupBasedBeamReporting.choice.disabled->nrofReportedRS = NR_CSI_ReportConfig__groupBasedBeamReporting__disabled__nrofReportedRS_n1; + *csirep->groupBasedBeamReporting.choice.disabled->nrofReportedRS = config_nrofReportedRS(uecap, + ssb_bitmap, + servingcellconfigcommon, + configuration->max_num_rsrp); asn1cSeqAdd(&csi_MeasConfig->csi_ReportConfigToAddModList->list, csirep); } @@ -3292,6 +3326,7 @@ static NR_BWP_DownlinkDedicated_t *configure_initial_dl_bwp(const NR_ServingCell } static NR_CSI_MeasConfig_t *get_csiMeasConfig(const NR_ServingCellConfig_t *configDedicated, + const NR_UE_NR_Capability_t *uecap, const NR_ServingCellConfigCommon_t *scc, const nr_mac_config_t *configuration, int uid, @@ -3396,14 +3431,15 @@ static NR_CSI_MeasConfig_t *get_csiMeasConfig(const NR_ServingCellConfig_t *conf pucchrsrp->uplinkBandwidthPartId = bwp_id; pucchrsrp->pucch_Resource = pucch_Resource; config_rsrp_meas_report(csi_MeasConfig, + uecap, scc, pucchrsrp, - configuration->do_CSIRS, + configuration, bwp_id + 10, uid, curr_bwp, pdsch_AntennaPorts, - configuration->do_SINR); + bitmap); return csi_MeasConfig; } @@ -3482,6 +3518,7 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, configDedicated->csi_MeasConfig = calloc(1, sizeof(*configDedicated->csi_MeasConfig)); configDedicated->csi_MeasConfig->present = NR_SetupRelease_CSI_MeasConfig_PR_setup; configDedicated->csi_MeasConfig->choice.setup = get_csiMeasConfig(configDedicated, + NULL, scc, configuration, uid, @@ -3786,6 +3823,7 @@ NR_CellGroupConfig_t * update_cellGroupConfig_for_BWP_switch(NR_CellGroupConfig_ ASN_STRUCT_FREE(asn_DEF_NR_CSI_MeasConfig, configDedicated->csi_MeasConfig->choice.setup); configDedicated->csi_MeasConfig->choice.setup = get_csiMeasConfig(configDedicated, + uecap, scc, configuration, uid, @@ -4101,6 +4139,7 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC configDedicated->csi_MeasConfig = calloc(1, sizeof(*configDedicated->csi_MeasConfig)); configDedicated->csi_MeasConfig->present = NR_SetupRelease_CSI_MeasConfig_PR_setup; configDedicated->csi_MeasConfig->choice.setup = get_csiMeasConfig(configDedicated, + uecap, servingcellconfigcommon, configuration, uid, From e5ea77f629f7cc8be8756ae837de30b455a6d386 Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 18 Aug 2025 14:41:04 +0200 Subject: [PATCH 2/6] separate UE fapi message for SSB measurements --- .../nfapi/public_inc/fapi_nr_ue_interface.h | 7 +++---- openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c | 1 + openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 2 -- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 5 +++++ openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c | 14 +------------- 5 files changed, 10 insertions(+), 19 deletions(-) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index a9e83758f6..6bea8f55cc 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -59,7 +59,9 @@ typedef struct { uint16_t Nid_cell; nfapi_nr_meas_type_e meas_type; bool is_neighboring_cell; - uint8_t rsrp_dBm; + int ssb_index; + int rsrp_dBm; + float sinr_dB; uint8_t rank_indicator; uint16_t i1; uint8_t i2; @@ -133,11 +135,8 @@ typedef struct { uint8_t ssb_length; uint16_t cell_id; uint16_t ssb_start_subcarrier; - short rsrp_dBm; long arfcn; rlm_t radiolink_monitoring; // -1 no monitoring, 0 out_of_sync, 1 in_sync - // SINR value times 10 as reporting granularity is 0.5 - float sinr_dB; } fapi_nr_ssb_pdu_t; typedef struct { diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c index 825e025308..747a000c4d 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c @@ -264,6 +264,7 @@ void nr_ue_ssb_rsrp_measurements(PHY_VARS_NR_UE *ue, .gNB_index = proc->gNB_id, .meas_type = NFAPI_NR_SS_MEAS, .Nid_cell = ue->frame_parms.Nid_cell, + .ssb_index = ssb_index, .is_neighboring_cell = false, }; int ssb_rsrp_dBm = ue->measurements.ssb_rsrp_dBm[ssb_index]; diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 25447e4bb4..065cea8f72 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -176,8 +176,6 @@ void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind, rx->ssb_pdu.ssb_length = frame_parms->Lmax; rx->ssb_pdu.cell_id = frame_parms->Nid_cell; rx->ssb_pdu.ssb_start_subcarrier = frame_parms->ssb_start_subcarrier; - rx->ssb_pdu.rsrp_dBm = ue->measurements.ssb_rsrp_dBm[frame_parms->ssb_index]; - rx->ssb_pdu.sinr_dB = ue->measurements.ssb_sinr_dB[frame_parms->ssb_index]; rx->ssb_pdu.arfcn = get_ssb_arfcn(frame_parms); rx->ssb_pdu.radiolink_monitoring = RLM_in_sync; // TODO to be removed from here rx->ssb_pdu.decoded_pdu = true; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index ab13c9dd07..683834d736 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -1509,6 +1509,11 @@ void nr_ue_process_l1_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slo LOG_D(NR_MAC, "(%d.%d) Received CSI-RS measurements\n", frame, slot); memcpy(&mac->l1_measurements, l1_measurements, sizeof(*l1_measurements)); bool csi_meas = l1_measurements->meas_type == NFAPI_NR_CSI_MEAS; + if (!csi_meas && !l1_measurements->is_neighboring_cell) { + mac->ssb_measurements.ssb_index = l1_measurements->ssb_index; + mac->ssb_measurements.ssb_rsrp_dBm = l1_measurements->rsrp_dBm; + mac->ssb_measurements.ssb_sinr_dB = l1_measurements->sinr_dB; + } nr_mac_rrc_meas_ind_ue(mac->ue_id, l1_measurements->gNB_index, l1_measurements->Nid_cell, diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c index 3f765bf6c9..1f86c61be5 100644 --- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c @@ -374,7 +374,6 @@ static void fill_mib_in_rx_ind(nfapi_nr_dl_tti_request_pdu_t *pdu_list, fapi_nr_ rx_ind->rx_indication_body[pdu_idx].ssb_pdu.pdu[0] = (ssb_pdu->bchPayload) & 0xff; rx_ind->rx_indication_body[pdu_idx].ssb_pdu.pdu[1] = (ssb_pdu->bchPayload >> 8) & 0xff; rx_ind->rx_indication_body[pdu_idx].ssb_pdu.pdu[2] = (ssb_pdu->bchPayload >> 16) & 0xff; - rx_ind->rx_indication_body[pdu_idx].ssb_pdu.rsrp_dBm = ssb_pdu->ssbRsrp; rx_ind->rx_indication_body[pdu_idx].ssb_pdu.ssb_index = ssb_pdu->SsbBlockIndex; rx_ind->rx_indication_body[pdu_idx].ssb_pdu.ssb_length = pdu_list->PDUSize; rx_ind->rx_indication_body[pdu_idx].ssb_pdu.ssb_start_subcarrier = ssb_pdu->SsbSubcarrierOffset; @@ -1138,13 +1137,6 @@ static nr_dci_format_t handle_dci(NR_UE_MAC_INST_t *mac, return nr_ue_process_dci_indication_pdu(mac, frame, slot, dci); } -static void handle_ssb_meas(NR_UE_MAC_INST_t *mac, uint8_t ssb_index, int16_t rsrp_dbm, float_t sinr_dB) -{ - mac->ssb_measurements.ssb_index = ssb_index; - mac->ssb_measurements.ssb_rsrp_dBm = rsrp_dbm; - mac->ssb_measurements.ssb_sinr_dB = sinr_dB; -} - // L2 Abstraction Layer // Note: sdu should always be processed because data and timing advance updates are transmitted by the UE static int8_t handle_dlsch(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, int pdu_id) @@ -1268,16 +1260,12 @@ static uint32_t nr_ue_dl_processing(NR_UE_MAC_INST_t *mac, nr_downlink_indicatio rx_indication_body.pdu_type, dl_info->rx_ind->number_pdus); - switch(rx_indication_body.pdu_type){ + switch(rx_indication_body.pdu_type) { case FAPI_NR_RX_PDU_TYPE_SSB: handle_rlm(rx_indication_body.ssb_pdu.radiolink_monitoring, dl_info->frame, mac); if(rx_indication_body.ssb_pdu.decoded_pdu) { - handle_ssb_meas(mac, - rx_indication_body.ssb_pdu.ssb_index, - rx_indication_body.ssb_pdu.rsrp_dBm, - rx_indication_body.ssb_pdu.sinr_dB); ret_mask |= (handle_bcch_bch(mac, dl_info->cc_id, dl_info->gNB_index, From b462fa45e81dcc17c3de966c3e3558108126fc68 Mon Sep 17 00:00:00 2001 From: Jan Fromme Date: Thu, 14 Aug 2025 12:29:12 +0200 Subject: [PATCH 3/6] Fix RSRP report unpacking logic in gNB scheduler UCI Correctly handle unpacking of the first RSRP report and its resource ID before processing additional reports. Use the initial RSRP value as the reference for differential RSRP calculations in subsequent reports. --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 682ea765ac..7edbf95600 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -588,28 +588,29 @@ static void evaluate_rsrp_report(gNB_MAC_INST *nrmac, } rsrp_report->nr_reports = csi_report->CSI_report_bitlen.nb_ssbri_cri; - uint16_t curr_payload; - for (int i = 0; i < rsrp_report->nr_reports; i++) { - int bitlen = csi_report->CSI_report_bitlen.cri_ssbri_bitlen; - curr_payload = pickandreverse_bits(payload, bitlen, *cumul_bits); - rsrp_report->resource_id[i] = *(index_list[bitlen > 0 ? ((curr_payload) & ~(~1U << (bitlen - 1))) : bitlen]); - LOG_D(MAC,"SSB/CSI-RS index = %d\n", rsrp_report->resource_id[i]); - *cumul_bits += bitlen; - } + int bitlen = csi_report->CSI_report_bitlen.cri_ssbri_bitlen; + uint8_t curr_payload = pickandreverse_bits(payload, bitlen, *cumul_bits); + rsrp_report->resource_id[0] = *(index_list[bitlen > 0 ? ((curr_payload) & ~(~1U << (bitlen - 1))) : bitlen]); + LOG_D(NR_MAC, "SSB/CSI-RS index = %d\n", rsrp_report->resource_id[0]); + *cumul_bits += bitlen; curr_payload = pickandreverse_bits(payload, 7, *cumul_bits); - int rsrp_index = curr_payload & 0x7f; + int rsrp = curr_payload & 0x7f; *cumul_bits += 7; - csi_report->nb_of_csi_ssb_report++; - bool valid = get_measured_rsrp(rsrp_index, &rsrp_report->RSRP[0]); + bool valid = get_measured_rsrp(rsrp, &rsrp_report->RSRP[0]); if (!valid) { - LOG_E(NR_MAC, "UE %04x: reported RSRP index %d invalid\n", UE->rnti, rsrp_index); + LOG_E(NR_MAC, "UE %04x: reported RSRP index %d invalid\n", UE->rnti, rsrp); return; } for (int i = 1; i < rsrp_report->nr_reports; i++) { + curr_payload = pickandreverse_bits(payload, bitlen, *cumul_bits); + rsrp_report->resource_id[i] = *(index_list[bitlen > 0 ? ((curr_payload) & ~(~1U << (bitlen - 1))) : bitlen]); + *cumul_bits += bitlen; + curr_payload = pickandreverse_bits(payload, 4, *cumul_bits); + csi_report->nb_of_csi_ssb_report++; rsrp_report->RSRP[i] = get_diff_rsrp(curr_payload & 0x0f, rsrp_report->RSRP[0]); *cumul_bits += 4; } From 5903806d2e2fe82d5cf2f780d18893c562162be1 Mon Sep 17 00:00:00 2001 From: Jan Fromme Date: Thu, 14 Aug 2025 16:44:25 +0200 Subject: [PATCH 4/6] enabled transmission of up to 4 RSRP measurement reports from UE to gNB --- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 53 ++++---- openair2/LAYER2/NR_MAC_UE/mac_defs.h | 13 +- openair2/LAYER2/NR_MAC_UE/mac_proto.h | 2 +- openair2/LAYER2/NR_MAC_UE/main_ue_nr.c | 5 + openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c | 6 +- .../LAYER2/NR_MAC_UE/nr_ue_power_procedures.c | 19 +-- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 126 +++++++++++------- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 4 +- 8 files changed, 137 insertions(+), 91 deletions(-) diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 065cea8f72..afb71ed164 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -965,31 +965,38 @@ int pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_ nr_ue_ssb_rsrp_measurements(ue, ssb_index, proc, rxdataF); // resetting ssb index for PBCH detection if there is a stronger SSB index - if(ue->measurements.ssb_rsrp_dBm[ssb_index] > ue->measurements.ssb_rsrp_dBm[fp->ssb_index]) + if(ue->measurements.ssb_rsrp_dBm[ssb_index] > ue->measurements.ssb_rsrp_dBm[fp->ssb_index]) { fp->ssb_index = ssb_index; - - if(ssb_index == fp->ssb_index) { - - LOG_D(PHY," ------ Decode MIB: frame.slot %d.%d ------ \n", frame_rx%1024, nr_slot_rx); - const int pbchSuccess = nr_ue_pbch_procedures(ue, proc, estimateSz, dl_ch_estimates, rxdataF); - - if (ue->no_timing_correction==0 && pbchSuccess == 0) { - LOG_D(PHY,"start adjust sync slot = %d no timing %d\n", nr_slot_rx, ue->no_timing_correction); - sampleShift = - nr_adjust_synch_ue(fp, ue, gNB_id, fp->ofdm_symbol_size, dl_ch_estimates_time, frame_rx, nr_slot_rx, 16384); - } - - if (get_nrUE_params()->cont_fo_comp && pbchSuccess == 0) { - double freq_offset = nr_ue_pbch_freq_offset(fp, estimateSz, dl_ch_estimates); - LOG_D(PHY,"compensated frequency offset = %.3f Hz, detected residual frequency offset = %.3f Hz, accumulated frequency offset = %.3f Hz\n", ue->freq_offset, freq_offset, ue->freq_off_acc); - - // PI controller - const double PID_P = get_nrUE_params()->freq_sync_P; - const double PID_I = get_nrUE_params()->freq_sync_I; - ue->freq_offset += freq_offset * PID_P + ue->freq_off_acc * PID_I; - ue->freq_off_acc += freq_offset; - } + LOG_D(PHY, "New best SSB: index %d RSRP %d\n", ssb_index, ue->measurements.ssb_rsrp_dBm[ssb_index]); } + + if(ssb_index != fp->ssb_index) + continue; + + LOG_D(PHY, " ------ Decode MIB: frame.slot %d.%d ------ \n", frame_rx % 1024, nr_slot_rx); + const int pbchSuccess = nr_ue_pbch_procedures(ue, proc, estimateSz, dl_ch_estimates, rxdataF); + + if (ue->no_timing_correction == 0 && pbchSuccess == 0) { + LOG_D(PHY,"start adjust sync slot = %d no timing %d\n", nr_slot_rx, ue->no_timing_correction); + sampleShift = + nr_adjust_synch_ue(fp, ue, gNB_id, fp->ofdm_symbol_size, dl_ch_estimates_time, frame_rx, nr_slot_rx, 16384); + } + + if (get_nrUE_params()->cont_fo_comp && pbchSuccess == 0) { + double freq_offset = nr_ue_pbch_freq_offset(fp, estimateSz, dl_ch_estimates); + LOG_D(PHY, + "compensated freq offset = %.3f Hz, detected residual freq offset = %.3f Hz, accumulated freq offset = %.3f Hz\n", + ue->freq_offset, + freq_offset, + ue->freq_off_acc); + + // PI controller + const double PID_P = get_nrUE_params()->freq_sync_P; + const double PID_I = get_nrUE_params()->freq_sync_I; + ue->freq_offset += freq_offset * PID_P + ue->freq_off_acc * PID_I; + ue->freq_off_acc += freq_offset; + } + LOG_D(PHY, "Doing N0 measurements in %s\n", __FUNCTION__); nr_ue_rrc_measurements(ue, proc, rxdataF); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP_PBCH, VCD_FUNCTION_OUT); diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 680b5138df..1db7d33afc 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -407,8 +407,8 @@ typedef struct { NR_PUCCH_Resource_t *pucch_resource; uint32_t ack_payload; uint8_t sr_payload; - uint32_t csi_part1_payload; - uint32_t csi_part2_payload; + uint64_t csi_part1_payload; + uint64_t csi_part2_payload; int n_sr; int n_csi; int n_harq; @@ -418,9 +418,8 @@ typedef struct { } PUCCH_sched_t; typedef struct { - uint32_t ssb_index; /// SSB RSRP in dBm - short ssb_rsrp_dBm; + int ssb_rsrp_dBm; float_t ssb_sinr_dB; } NR_SSB_meas_t; @@ -473,8 +472,8 @@ typedef struct { } NR_BWP_PDCCH_t; typedef struct csi_payload { - uint32_t part1_payload; - uint32_t part2_payload; + uint64_t part1_payload; + uint64_t part2_payload; int p1_bits; int p2_bits; } csi_payload_t; @@ -625,7 +624,7 @@ typedef struct NR_UE_MAC_INST_s { uint8_t ssb_subcarrier_offset; int ssb_start_subcarrier; - NR_SSB_meas_t ssb_measurements; + NR_SSB_meas_t ssb_measurements[MAX_NB_SSB]; dci_pdu_rel15_t def_dci_pdu_rel15[NR_MAX_SLOTS_PER_FRAME][8]; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index 035e59c09c..4897a8fab8 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -289,7 +289,7 @@ void remove_ul_config_last_item(fapi_nr_ul_config_request_pdu_t *pdu); fapi_nr_ul_config_request_pdu_t *fapiLockIterator(fapi_nr_ul_config_request_t *ul_config, frame_t frame_tx, int slot_tx); void release_ul_config(fapi_nr_ul_config_request_pdu_t *pdu, bool clearIt); -int16_t compute_nr_SSB_PL(NR_UE_MAC_INST_t *mac, short ssb_rsrp_dBm); +int16_t compute_nr_SSB_PL(NR_UE_MAC_INST_t *mac); // PUSCH scheduler: // - Calculate the slot in which ULSCH should be scheduled. This is current slot + K2, diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index 78bfb1021c..1f35df5c4b 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -77,6 +77,11 @@ void nr_ue_init_mac(NR_UE_MAC_INST_t *mac) nr_timer_stop(&mac->scheduling_info.sr_DelayTimer); memset(&mac->ssb_measurements, 0, sizeof(mac->ssb_measurements)); + for (int i = 0; i < MAX_NB_SSB; i++) { + mac->ssb_measurements[i].ssb_rsrp_dBm = INT_MIN; + mac->ssb_measurements[i].ssb_sinr_dB = INT_MIN; + } + memset(&mac->ul_time_alignment, 0, sizeof(mac->ul_time_alignment)); memset(&mac->ssb_list, 0, sizeof(mac->ssb_list)); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c index bc29f7a9b9..9f962efc6e 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c @@ -42,7 +42,7 @@ int16_t get_prach_tx_power(NR_UE_MAC_INST_t *mac) { RA_config_t *ra = &mac->ra; - int16_t pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); + int16_t pathloss = compute_nr_SSB_PL(mac); int16_t ra_preamble_rx_power = (int16_t)(ra->prach_resources.ra_preamble_rx_target_power + pathloss); return min(ra->prach_resources.Pc_max, ra_preamble_rx_power); } @@ -177,7 +177,7 @@ static void select_preamble_group(NR_UE_MAC_INST_t *mac) // – preambleReceivedTargetPower – msg3-DeltaPreamble – messagePowerOffsetGroupB int groupB_pow_offset = get_messagePowerOffsetGroupB(groupB->messagePowerOffsetGroupB); int PLThreshold = ra->prach_resources.Pc_max - ra->preambleRxTargetPower - ra->msg3_deltaPreamble - groupB_pow_offset; - int pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); + int pathloss = compute_nr_SSB_PL(mac); // TODO if the Random Access procedure was initiated for the CCCH logical channel and the CCCH SDU size // plus MAC subheader is greater than ra-Msg3SizeGroupA if (ra->Msg3_size > get_Msg3SizeGroupA(groupB->ra_Msg3SizeGroupA) && pathloss < PLThreshold) @@ -971,7 +971,7 @@ bool init_RA(NR_UE_MAC_INST_t *mac, int frame) "msgA_RSRP_Threshold_r16 is mandatory present if both 2-step and 4-step random access types are configured\n"); // For thresholds the RSRP value is (IE value – 156) dBm except for the IE 127 in which case the actual value is infinity int rsrp_msga_thr = *twostep_conf->msgA_RSRP_Threshold_r16 - 156; - if (*twostep_conf->msgA_RSRP_Threshold_r16 != 127 && mac->ssb_measurements.ssb_rsrp_dBm > rsrp_msga_thr) + if (*twostep_conf->msgA_RSRP_Threshold_r16 != 127 && mac->ssb_measurements[mac->mib_ssb].ssb_rsrp_dBm > rsrp_msga_thr) twostep = true; } else { // if the BWP selected for Random Access procedure is only configured with 2-step RA type Random Access diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c index 1efa0f1f12..860089165f 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c @@ -358,7 +358,7 @@ int16_t get_pucch_tx_power_ue(NR_UE_MAC_INST_t *mac, 1, start_prb); float P_CMIN = current_UL_BWP->P_CMIN; - int16_t pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); + int16_t pathloss = compute_nr_SSB_PL(mac); if (power_config->twoPUCCH_PC_AdjustmentStates && *power_config->twoPUCCH_PC_AdjustmentStates > 1) { LOG_E(MAC,"PUCCH power control adjustment states with 2 states not yet implemented\n"); @@ -427,20 +427,23 @@ static int get_deltatf(uint16_t nb_of_prbs, // - PRACH transmission from a UE is not in response to a detection of a PDCCH order by the UE // Measurement units: // - referenceSignalPower: dBm/RE (average EPRE of the resources elements that carry secondary synchronization signals in dBm) -int16_t compute_nr_SSB_PL(NR_UE_MAC_INST_t *mac, short ssb_rsrp_dBm) +int16_t compute_nr_SSB_PL(NR_UE_MAC_INST_t *mac) { + // getting the maximum SSB RSRP from the SSB measurements + int max_ssb_rsrp_dBm = mac->ssb_measurements[mac->mib_ssb].ssb_rsrp_dBm; fapi_nr_config_request_t *cfg = &mac->phy_config.config_req; int referenceSignalPower = cfg->ssb_config.ss_pbch_power; + //TODO improve PL measurements. Probably not correct as it is. - int16_t pathloss = (int16_t)(referenceSignalPower - ssb_rsrp_dBm); + int16_t pathloss = (int16_t)(referenceSignalPower - max_ssb_rsrp_dBm); LOG_D(NR_MAC, "pathloss %d dB, referenceSignalPower %d dBm/RE (%f mW), RSRP %d dBm (%f mW)\n", pathloss, referenceSignalPower, pow(10, referenceSignalPower/10), - ssb_rsrp_dBm, - pow(10, ssb_rsrp_dBm/10)); + max_ssb_rsrp_dBm, + pow(10, max_ssb_rsrp_dBm/10)); return pathloss; } @@ -557,8 +560,8 @@ int get_pusch_tx_power_ue(NR_UE_MAC_INST_t *mac, DELTA_TF = 10 * log10(pow(2, BPRE * 1.25f) * beta_offset); } - // TODO: compute pathoss using correct reference - int16_t pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); + // TODO: compute pathloss using correct reference + int16_t pathloss = compute_nr_SSB_PL(mac); int P_CMIN = mac->current_UL_BWP->P_CMIN; float pusch_power_without_f_b_f_c = P_O_PUSCH + M_pusch_component + alpha * pathloss + DELTA_TF; @@ -626,7 +629,7 @@ int get_srs_tx_power_ue(NR_UE_MAC_INST_t *mac, get_m_srs(srs_resource->freqHopping.c_SRS, srs_resource->freqHopping.b_SRS), 0); // TODO: Determine SRS start RB - int16_t pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); + int16_t pathloss = compute_nr_SSB_PL(mac); int srs_power_without_h_b_f_c = P_0_SRS + alpha * pathloss + m_srs_component; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 683834d736..9c9d01fa1f 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -78,6 +78,12 @@ const uint16_t table_7_2_1[16] = { 1920, // row index 13 }; +typedef struct { + uint32_t ssb_index; + short ssb_rsrp_dBm; + float_t ssb_sinr_dB; +} NR_RSRP_meas_t; + /* TS 36.213 Table 9.2.3-3: Mapping of values for one HARQ-ACK bit to sequences */ static const int sequence_cyclic_shift_1_harq_ack_bit[2] /* HARQ-ACK Value 0 1 */ @@ -1510,9 +1516,9 @@ void nr_ue_process_l1_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slo memcpy(&mac->l1_measurements, l1_measurements, sizeof(*l1_measurements)); bool csi_meas = l1_measurements->meas_type == NFAPI_NR_CSI_MEAS; if (!csi_meas && !l1_measurements->is_neighboring_cell) { - mac->ssb_measurements.ssb_index = l1_measurements->ssb_index; - mac->ssb_measurements.ssb_rsrp_dBm = l1_measurements->rsrp_dBm; - mac->ssb_measurements.ssb_sinr_dB = l1_measurements->sinr_dB; + int ssb_index = l1_measurements->ssb_index; + mac->ssb_measurements[ssb_index].ssb_rsrp_dBm = l1_measurements->rsrp_dBm; + mac->ssb_measurements[ssb_index].ssb_sinr_dB = l1_measurements->sinr_dB; } nr_mac_rrc_meas_ind_ue(mac->ue_id, l1_measurements->gNB_index, @@ -2764,6 +2770,14 @@ static uint8_t get_sinr_diff_index(float best_sinr, float current_sinr) return diff; } +// Comparison function for sorting SSB SINR measurements in descending order +static int compare_ssb_sinr(const void *a, const void *b) +{ + const NR_RSRP_meas_t *ma = (const NR_RSRP_meas_t *)a; + const NR_RSRP_meas_t *mb = (const NR_RSRP_meas_t *)b; + return mb->ssb_sinr_dB - ma->ssb_sinr_dB; +} + static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac, struct NR_CSI_ReportConfig *csi_reportconfig, NR_CSI_ResourceConfigId_t csi_ResourceConfigId, @@ -2772,7 +2786,7 @@ static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac, int nb_ssb = 0; // nb of ssb in the resource int nb_meas = 0; // nb of ssb to report measurements on int bits = 0; - uint32_t temp_payload = 0; + uint64_t temp_payload = 0; for (int csi_resourceidx = 0; csi_resourceidx < csi_MeasConfig->csi_ResourceConfigToAddModList->list.count; csi_resourceidx++) { struct NR_CSI_ResourceConfig *csi_resourceconfig = csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_resourceidx]; @@ -2797,51 +2811,55 @@ static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac, } AssertFatal(nb_ssb > 0, "No SSB found in the resource set\n"); - AssertFatal(nb_meas == 1, "PHY currently reports only the strongest SSB to MAC. Can't report more than 1 RSRP\n"); + AssertFatal(nb_meas <= 4,"Can't report more than 4 RSRPs\n"); int ssbri_bits = ceil(log2(nb_ssb)); - int ssb_index[nb_meas]; // the array contains index and RSRP of each SSB to be reported (nb_meas highest RSRPs) - float ssb_sinr[nb_meas]; - - // TODO replace the following 2 lines with a function to order the nb_meas highest SSB RSRPs - for (int i = 0; i < nb_ssb; i++) { - ssb_index[i] = -1;//Invalid index - if (*SSB_resource.list.array[i] == mac->mib_ssb) { - ssb_index[0] = i; - break; + // map SSB index to SSB resource table index, copy measurements, sort in descending order + NR_RSRP_meas_t sorted_sinr_measurements[nb_ssb]; + int sorted_idx = 0; + for (int measured_ssb_idx = 0; measured_ssb_idx < MAX_NB_SSB; measured_ssb_idx++) { + // searching for the SSB index in the SSB resource table + for (int ssb_resource = 0; ssb_resource < nb_ssb; ssb_resource++) { + if (*SSB_resource.list.array[ssb_resource] == measured_ssb_idx) { + sorted_sinr_measurements[sorted_idx].ssb_index = ssb_resource; + sorted_sinr_measurements[sorted_idx].ssb_rsrp_dBm = mac->ssb_measurements[measured_ssb_idx].ssb_rsrp_dBm; + sorted_sinr_measurements[sorted_idx].ssb_sinr_dB = mac->ssb_measurements[measured_ssb_idx].ssb_sinr_dB; + sorted_idx++; + break; + } } } - AssertFatal(ssb_index[0] >= 0, "Couldn't find corresponding SSB in csi_SSB_ResourceList\n"); - ssb_sinr[0] = mac->ssb_measurements.ssb_sinr_dB; + qsort(sorted_sinr_measurements, nb_ssb, sizeof(NR_RSRP_meas_t), compare_ssb_sinr); uint8_t ssbi; // TS38.212 v16.5.0: Table 6.3.1.1.2-8A if (ssbri_bits > 0) { - ssbi = ssb_index[0]; + ssbi = sorted_sinr_measurements[0].ssb_index; temp_payload = reverse_bits(ssbi, ssbri_bits); bits += ssbri_bits; } - uint8_t sinr_idx = get_sinr_index(ssb_sinr[0]); + uint8_t sinr_idx = get_sinr_index(sorted_sinr_measurements[0].ssb_sinr_dB); temp_payload |= (reverse_bits(sinr_idx, 7) << bits); bits += 7; // 7 bits for highest SINR // from the second SSB, differential report for (int i = 1; i < nb_meas; i++) { - ssbi = ssb_index[i]; + ssbi = sorted_sinr_measurements[i].ssb_index; temp_payload = reverse_bits(ssbi, ssbri_bits); bits += ssbri_bits; - sinr_idx = get_sinr_diff_index(ssb_sinr[0], ssb_sinr[i]); + sinr_idx = get_sinr_diff_index(sorted_sinr_measurements[0].ssb_sinr_dB, sorted_sinr_measurements[i].ssb_sinr_dB); temp_payload |= (reverse_bits(sinr_idx, 4) << bits); - bits += 4; // 7 bits for highest SINR + bits += 4; // 4 bits for differential SINR } break; // resource found } } - AssertFatal(bits <= 32, "Not supporting CSI report with more than 32 bits\n"); - csi_payload_t csi = {.part1_payload = temp_payload, .p1_bits = bits, csi.p2_bits = 0}; + int max_bits = sizeof(((csi_payload_t *)0)->part1_payload) * 8; + AssertFatal(bits <= max_bits, "Not supporting CSI report with more than %d bits (payload: %d bits)\n", max_bits, bits); + csi_payload_t csi = {.part1_payload = temp_payload, .part2_payload = 0, .p1_bits = bits, csi.p2_bits = 0}; return csi; } @@ -2891,6 +2909,14 @@ csi_payload_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac, return csi; } +// Comparison function for sorting SSB RSRP measurements in descending order +static int compare_ssb_rsrp(const void *a, const void *b) +{ + const NR_RSRP_meas_t *ma = (const NR_RSRP_meas_t *)a; + const NR_RSRP_meas_t *mb = (const NR_RSRP_meas_t *)b; + return mb->ssb_rsrp_dBm - ma->ssb_rsrp_dBm; +} + static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac, struct NR_CSI_ReportConfig *csi_reportconfig, NR_CSI_ResourceConfigId_t csi_ResourceConfigId, @@ -2899,7 +2925,7 @@ static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac, int nb_ssb = 0; // nb of ssb in the resource int nb_meas = 0; // nb of ssb to report measurements on int bits = 0; - uint32_t temp_payload = 0; + uint64_t temp_payload = 0; for (int csi_resourceidx = 0; csi_resourceidx < csi_MeasConfig->csi_ResourceConfigToAddModList->list.count; csi_resourceidx++) { struct NR_CSI_ResourceConfig *csi_resourceconfig = csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_resourceidx]; @@ -2907,7 +2933,7 @@ static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac, if (csi_reportconfig->groupBasedBeamReporting.present == NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled) { if (csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS != NULL) - nb_meas = *(csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS)+1; + nb_meas = *(csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS) + 1; else nb_meas = 1; } else @@ -2924,50 +2950,56 @@ static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac, } } - AssertFatal(nb_ssb>0,"No SSB found in the resource set\n"); - AssertFatal(nb_meas==1,"PHY currently reports only the strongest SSB to MAC. Can't report more than 1 RSRP\n"); + AssertFatal(nb_ssb > 0,"No SSB found in the resource set\n"); + AssertFatal(nb_meas <= 4,"Can't report more than 4 RSRPs\n"); int ssbri_bits = ceil(log2(nb_ssb)); - int ssb_rsrp[2][nb_meas]; // the array contains index and RSRP of each SSB to be reported (nb_meas highest RSRPs) - memset(ssb_rsrp, 0, sizeof(ssb_rsrp)); - - //TODO replace the following 2 lines with a function to order the nb_meas highest SSB RSRPs - for (int i=0; imib_ssb) { - ssb_rsrp[0][0] = i; - break; + // map SSB index to SSB resource table index, copy measurements, sort in descending order + NR_RSRP_meas_t sorted_rsrp_measurements[nb_ssb]; + int sorted_idx = 0; + for (int measured_ssb_idx = 0; measured_ssb_idx < MAX_NB_SSB; measured_ssb_idx++) { + // searching for the SSB index in the SSB resource table + for (int ssb_resource = 0; ssb_resource < nb_ssb; ssb_resource++) { + if (*SSB_resource.list.array[ssb_resource] == measured_ssb_idx) { + sorted_rsrp_measurements[sorted_idx].ssb_index = ssb_resource; + sorted_rsrp_measurements[sorted_idx].ssb_rsrp_dBm = mac->ssb_measurements[measured_ssb_idx].ssb_rsrp_dBm; + sorted_rsrp_measurements[sorted_idx].ssb_sinr_dB = mac->ssb_measurements[measured_ssb_idx].ssb_sinr_dB; + sorted_idx++; + break; + } } } - AssertFatal(*SSB_resource.list.array[ssb_rsrp[0][0]] == mac->mib_ssb, "Couldn't find corresponding SSB in csi_SSB_ResourceList\n"); - ssb_rsrp[1][0] = mac->ssb_measurements.ssb_rsrp_dBm; + qsort(sorted_rsrp_measurements, nb_ssb, sizeof(NR_RSRP_meas_t), compare_ssb_rsrp); - uint8_t ssbi; + uint32_t ssbi; if (ssbri_bits > 0) { - ssbi = ssb_rsrp[0][0]; + ssbi = sorted_rsrp_measurements[0].ssb_index; temp_payload = reverse_bits(ssbi, ssbri_bits); bits += ssbri_bits; } - uint8_t rsrp_idx = get_rsrp_index(ssb_rsrp[1][0]); + uint8_t rsrp_idx = get_rsrp_index(sorted_rsrp_measurements[0].ssb_rsrp_dBm); temp_payload |= (reverse_bits(rsrp_idx, 7) << bits); bits += 7; // 7 bits for highest RSRP // from the second SSB, differential report - for (int i=1; ipart1_payload) * 8; + AssertFatal(bits <= max_bits, "Not supporting CSI report with more than %d bits (payload: %d bits)\n", max_bits, bits); + + csi_payload_t csi = {.part1_payload = temp_payload, .part2_payload = 0, .p1_bits = bits, .p2_bits = 0}; return csi; } diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index cf7fda5ccf..fed19223f3 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -260,7 +260,7 @@ void update_mac_ul_timers(NR_UE_MAC_INST_t *mac) if (phr_info->is_configured) { bool prohibit_expired = nr_timer_tick(&phr_info->prohibitPHR_Timer); if (prohibit_expired) { - int16_t pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); + int16_t pathloss = compute_nr_SSB_PL(mac); if (abs(pathloss - phr_info->PathlossLastValue) > phr_info->PathlossChange_db) { phr_info->phr_reporting |= (1 << phr_cause_prohibit_timer); } @@ -2905,7 +2905,7 @@ static void nr_ue_fill_phr(NR_UE_MAC_INST_t *mac, headroom, tx_power); - phr_info->PathlossLastValue = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); + phr_info->PathlossLastValue = compute_nr_SSB_PL(mac); // Restart both timers according to 38.321 nr_timer_start(&phr_info->periodicPHR_Timer); nr_timer_start(&phr_info->prohibitPHR_Timer); From df9c41f36428679117a6342cfef40f56f19618ec Mon Sep 17 00:00:00 2001 From: Jan Fromme Date: Thu, 21 Aug 2025 09:16:07 +0000 Subject: [PATCH 5/6] Accumulate SSB indices in the SINR payload instead of overwriting the payload --- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 9c9d01fa1f..f2f783869c 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2847,7 +2847,7 @@ static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac, // from the second SSB, differential report for (int i = 1; i < nb_meas; i++) { ssbi = sorted_sinr_measurements[i].ssb_index; - temp_payload = reverse_bits(ssbi, ssbri_bits); + temp_payload |= (reverse_bits(ssbi, ssbri_bits) << bits); bits += ssbri_bits; sinr_idx = get_sinr_diff_index(sorted_sinr_measurements[0].ssb_sinr_dB, sorted_sinr_measurements[i].ssb_sinr_dB); From ca7fadfe075ccdc241d879f70c5409413831eef2 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 19 Sep 2025 11:07:28 +0200 Subject: [PATCH 6/6] improved logs to evaluate RSRP report --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 7edbf95600..f3de970683 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -591,7 +591,6 @@ static void evaluate_rsrp_report(gNB_MAC_INST *nrmac, int bitlen = csi_report->CSI_report_bitlen.cri_ssbri_bitlen; uint8_t curr_payload = pickandreverse_bits(payload, bitlen, *cumul_bits); rsrp_report->resource_id[0] = *(index_list[bitlen > 0 ? ((curr_payload) & ~(~1U << (bitlen - 1))) : bitlen]); - LOG_D(NR_MAC, "SSB/CSI-RS index = %d\n", rsrp_report->resource_id[0]); *cumul_bits += bitlen; curr_payload = pickandreverse_bits(payload, 7, *cumul_bits); @@ -599,6 +598,7 @@ static void evaluate_rsrp_report(gNB_MAC_INST *nrmac, *cumul_bits += 7; csi_report->nb_of_csi_ssb_report++; bool valid = get_measured_rsrp(rsrp, &rsrp_report->RSRP[0]); + LOG_D(NR_MAC, "SSB/CSI-RS index %d RSRP %d\n", rsrp_report->resource_id[0], rsrp_report->RSRP[0]); if (!valid) { LOG_E(NR_MAC, "UE %04x: reported RSRP index %d invalid\n", UE->rnti, rsrp); return; @@ -612,6 +612,7 @@ static void evaluate_rsrp_report(gNB_MAC_INST *nrmac, curr_payload = pickandreverse_bits(payload, 4, *cumul_bits); csi_report->nb_of_csi_ssb_report++; rsrp_report->RSRP[i] = get_diff_rsrp(curr_payload & 0x0f, rsrp_report->RSRP[0]); + LOG_D(NR_MAC, "SSB/CSI-RS index %d RSRP %d\n", rsrp_report->resource_id[i], rsrp_report->RSRP[i]); *cumul_bits += 4; }