From 71e23b12c2eb0ea4209394db81b7783cf59665f9 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Thu, 11 Dec 2025 14:43:21 +0000 Subject: [PATCH 01/22] Reset outdated PUCCHs to avoid Assertion caused by non-processed and active PUCCHs When there is real-time issues in L1 it may happen that the scheduler misses/skips some slots, thus, L2 not processing and not freeing some structures like PUCCH. This commit avoids the Assertion by resetting any Active outdated PUCCH --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 5 ++++- 1 file changed, 4 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 eb32fde2e6..a072fdc544 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -280,7 +280,10 @@ void nr_csi_meas_reporting(int Mod_idP,frame_t frame, slot_t slot) const int pucch_index = get_pucch_index(sched_frame, sched_slot, &nrmac->frame_structure, sched_ctrl->sched_pucch_size); NR_sched_pucch_t *curr_pucch = &sched_ctrl->sched_pucch[pucch_index]; - AssertFatal(curr_pucch->active == false, "CSI structure is scheduled in advance. It should be free!\n"); + if (curr_pucch->active) { + LOG_E(NR_MAC, "CSI structure is scheduled in advance. It should be free!\n"); + memset(curr_pucch, 0, sizeof(*curr_pucch)); + } curr_pucch->r_pucch = -1; curr_pucch->frame = sched_frame; curr_pucch->ul_slot = sched_slot; From 9470c51b004f10e4fe194a6dc89a543e1b5d71c3 Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 15 Dec 2025 12:13:34 +0100 Subject: [PATCH 02/22] remove phy_extern_nr_ue file --- .../telnetsrv/telnetsrv_5Gue_measurements.c | 4 ++- common/utils/telnetsrv/telnetsrv_ciUE.c | 4 ++- doc/Doxyfile | 1 - executables/nr-ue.c | 1 - openair1/PHY/INIT/nr_init_ue.c | 1 - .../PHY/NR_UE_ESTIMATION/nr_adjust_gain.c | 1 - .../PHY/NR_UE_ESTIMATION/nr_ue_measurements.c | 1 - openair1/PHY/NR_UE_TRANSPORT/csi_rx.c | 1 - .../PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c | 1 - openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c | 1 - .../PHY/NR_UE_TRANSPORT/nr_ue_rf_helpers.c | 3 +- openair1/PHY/phy_extern_nr_ue.h | 33 ------------------- openair1/SCHED_NR_UE/fapi_nr_ue_l1.c | 3 +- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 1 - 14 files changed, 10 insertions(+), 46 deletions(-) delete mode 100644 openair1/PHY/phy_extern_nr_ue.h diff --git a/common/utils/telnetsrv/telnetsrv_5Gue_measurements.c b/common/utils/telnetsrv/telnetsrv_5Gue_measurements.c index 6f2d1c7516..323a4175bc 100644 --- a/common/utils/telnetsrv/telnetsrv_5Gue_measurements.c +++ b/common/utils/telnetsrv/telnetsrv_5Gue_measurements.c @@ -50,7 +50,9 @@ #include "telnetsrv_ltemeasur_def.h" #include "telnetsrv_cpumeasur_def.h" #include "openair2/LAYER2/NR_MAC_UE/mac_defs.h" -#include "openair1/PHY/phy_extern_nr_ue.h" +#include "openair1/PHY/defs_nr_UE.h" + +extern PHY_VARS_NR_UE ***PHY_vars_UE_g; void measurcmd_display_macstats(telnet_printfunc_t prnt); void measurcmd_display_macstats_ue(telnet_printfunc_t prnt); diff --git a/common/utils/telnetsrv/telnetsrv_ciUE.c b/common/utils/telnetsrv/telnetsrv_ciUE.c index 6f86f1678f..cc580b1a83 100644 --- a/common/utils/telnetsrv/telnetsrv_ciUE.c +++ b/common/utils/telnetsrv/telnetsrv_ciUE.c @@ -37,8 +37,8 @@ #include "openair2/LAYER2/NR_MAC_UE/mac_defs.h" #include "openair2/LAYER2/NR_MAC_UE/mac_proto.h" #include "openair2/RRC/NR_UE/rrc_proto.h" -#include "openair1/PHY/phy_extern_nr_ue.h" #include "openair1/PHY/defs_nr_common.h" +#include "openair1/PHY/defs_nr_UE.h" #include "openair3/NAS/NR_UE/nr_nas_msg.h" #define TELNETSERVERCODE @@ -46,6 +46,8 @@ #define ERROR_MSG_RET(mSG, aRGS...) do { prnt(mSG, ##aRGS); return 1; } while (0) +extern PHY_VARS_NR_UE ***PHY_vars_UE_g; + /* UE L2 state string */ const char* NR_UE_L2_STATE_STR[] = { #define UE_STATE(state) #state, diff --git a/doc/Doxyfile b/doc/Doxyfile index 85cb5776c0..39c7983e72 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -1924,7 +1924,6 @@ INPUT = \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/SDAP/nr_sdap/nr_sdap_entity.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/defs_gNB.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/impl_defs_top.h \ -@CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/phy_extern_nr_ue.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/INIT/lte_parms.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/INIT/nr_init_ru.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/INIT/nr_parms.c \ diff --git a/executables/nr-ue.c b/executables/nr-ue.c index f57b663f1e..bb88768029 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -24,7 +24,6 @@ #include #include #include "executables/nr-uesoftmodem.h" -#include "PHY/phy_extern_nr_ue.h" #include "PHY/INIT/nr_phy_init.h" #include "NR_MAC_UE/mac_proto.h" #include "RRC/NR_UE/rrc_proto.h" diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index 7ab8a8863d..ded11bc4af 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -20,7 +20,6 @@ */ #include "nr_phy_init.h" -#include "PHY/phy_extern_nr_ue.h" #include "openair1/PHY/defs_RU.h" #include "openair1/PHY/impl_defs_nr.h" #include "common/utils/LOG/vcd_signal_dumper.h" diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_adjust_gain.c b/openair1/PHY/NR_UE_ESTIMATION/nr_adjust_gain.c index 4a884b964b..6f3466e436 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_adjust_gain.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_adjust_gain.c @@ -21,7 +21,6 @@ #include "PHY/types.h" #include "PHY/defs_nr_UE.h" -#include "PHY/phy_extern_nr_ue.h" void phy_adjust_gain_nr (PHY_VARS_NR_UE *ue, uint32_t rx_power_fil_dB, uint8_t eNB_id) diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c index 4c8c57d9fd..b04f595481 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c @@ -34,7 +34,6 @@ #include "executables/nr-softmodem-common.h" #include "PHY/defs_nr_UE.h" #include "PHY/INIT/nr_phy_init.h" -#include "PHY/phy_extern_nr_ue.h" #include "common/utils/LOG/log.h" #include "PHY/sse_intrin.h" #include "SCHED_NR_UE/defs.h" diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 26cad50f12..b2e43b3c16 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -35,7 +35,6 @@ #include "executables/nr-softmodem-common.h" #include "nr_transport_proto_ue.h" -#include "PHY/phy_extern_nr_ue.h" #include "PHY/NR_REFSIG/nr_refsig.h" #include "common/utils/nr/nr_common.h" #include "PHY/NR_UE_ESTIMATION/filt16a_32.h" diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c index e6b4503e1b..be71e435a0 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c @@ -25,7 +25,6 @@ #include "common/utils/LOG/vcd_signal_dumper.h" #include "PHY/defs_nr_UE.h" #include "SCHED_NR_UE/harq_nr.h" -#include "PHY/phy_extern_nr_ue.h" #include "PHY/CODING/coding_extern.h" #include "PHY/CODING/coding_defs.h" #include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c index 00130b3642..8d3ac6db21 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c @@ -31,7 +31,6 @@ */ #include "PHY/defs_nr_UE.h" #include "PHY/CODING/coding_extern.h" -#include "PHY/phy_extern_nr_ue.h" #include "PHY/sse_intrin.h" #include "PHY/INIT/nr_phy_init.h" #include "openair1/SCHED_NR_UE/defs.h" diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ue_rf_helpers.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ue_rf_helpers.c index 8199b45fc6..436ebfe5e0 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ue_rf_helpers.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ue_rf_helpers.c @@ -29,10 +29,11 @@ */ #include "PHY/defs_nr_UE.h" -#include "PHY/phy_extern_nr_ue.h" #include "nr_transport_proto_ue.h" #include "executables/softmodem-common.h" +extern PHY_VARS_NR_UE ***PHY_vars_UE_g; + void nr_get_carrier_frequencies(PHY_VARS_NR_UE *ue, uint64_t *dl_carrier, uint64_t *ul_carrier){ NR_DL_FRAME_PARMS *fp = &ue->frame_parms; diff --git a/openair1/PHY/phy_extern_nr_ue.h b/openair1/PHY/phy_extern_nr_ue.h deleted file mode 100644 index 2c4679dddd..0000000000 --- a/openair1/PHY/phy_extern_nr_ue.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -#ifndef __PHY_EXTERN_NR_UE__H__ -#define __PHY_EXTERN_NR_UE__H__ - -#include "PHY/defs_nr_UE.h" -extern PHY_VARS_NR_UE ***PHY_vars_UE_g; - -extern uint64_t downlink_frequency[MAX_NUM_CCs][4]; -extern int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; -extern uint64_t sidelink_frequency[MAX_NUM_CCs][4]; - -#endif /*__PHY_EXTERN_H__ */ - diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c index 5c679630f4..6810f2c08d 100644 --- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c +++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c @@ -39,7 +39,8 @@ #include "PHY/impl_defs_nr.h" #include "utils.h" #include "SCHED_NR_UE/phy_sch_processing_time.h" -#include "openair1/PHY/phy_extern_nr_ue.h" + +extern PHY_VARS_NR_UE ***PHY_vars_UE_g; const char *const dl_pdu_type[] = {"DCI", "DLSCH", "RA_DLSCH", "SI_DLSCH", "P_DLSCH", "CSI_RS", "CSI_IM", "TA"}; const char *const ul_pdu_type[] = {"PRACH", "PUCCH", "PUSCH", "SRS"}; diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index d018630357..68c0541e3a 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -37,7 +37,6 @@ #include "defs.h" #include "PHY/defs_nr_UE.h" #include "PHY/NR_REFSIG/dmrs_nr.h" -#include "PHY/phy_extern_nr_ue.h" #include "PHY/MODULATION/modulation_UE.h" #include "PHY/INIT/nr_phy_init.h" #include "PHY/nr_phy_common/inc/nr_phy_common.h" From 26879d5616bcf4d5615e16d5c2f6296495a8921a Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 15 Dec 2025 15:22:57 +0100 Subject: [PATCH 03/22] Add two missing include guards --- openair1/SCHED_NR_UE/phy_sch_processing_time.h | 5 +++++ openair2/LAYER2/NR_MAC_COMMON/nr_prach_config.h | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/openair1/SCHED_NR_UE/phy_sch_processing_time.h b/openair1/SCHED_NR_UE/phy_sch_processing_time.h index 896c93b9ee..1861fea9a4 100644 --- a/openair1/SCHED_NR_UE/phy_sch_processing_time.h +++ b/openair1/SCHED_NR_UE/phy_sch_processing_time.h @@ -31,6 +31,9 @@ \warning */ +#ifndef __PHY_SCH_PROCESSING_TIME_H__ +#define __PHY_SCH_PROCESSING_TIME_H__ + /* TS 38.214 Table 5.3-1: PDSCH processing time for PDSCH processing capability 1 // corresponding to the PDSCH decoding time N_1 [symbols] // where mu corresponds to the one of {mu_PDCCH, mu_PDSCH, mu_UL} @@ -139,3 +142,5 @@ static const float pusch_d_2_2_timing_capability_2[4][2] = { { 2, 9 }, { 3, 18 }, }; + +#endif diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_prach_config.h b/openair2/LAYER2/NR_MAC_COMMON/nr_prach_config.h index 1b6aa0bfb7..5898e2b80c 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_prach_config.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_prach_config.h @@ -30,6 +30,9 @@ * For example the PRACH duration is requested in the O-RAN 7.2 FrontHaul Interface */ +#ifndef __NR_PRACH_CONFIG_H__ +#define __NR_PRACH_CONFIG_H__ + /** * @brief Fetch PRACH format (format only) from PRACH configuration tables * @@ -73,3 +76,5 @@ nr_prach_info_t get_nr_prach_occasion_info_from_index(uint8_t index, frequency_r * @return PRACH format (format concatenated with format2) */ uint16_t get_nr_prach_format_from_index(uint8_t index, uint32_t pointa, uint8_t unpaired); + +#endif From 35e5cb69d1e17d899483221b9aa097de7a6b3083 Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Thu, 23 Oct 2025 02:38:20 +0000 Subject: [PATCH 04/22] clean-up: fix code repetition --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c | 135 ++++++++---------- 1 file changed, 57 insertions(+), 78 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index eb063b48ef..7bc5d6ed91 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -114,6 +114,56 @@ static int encode_mib(NR_BCCH_BCH_Message_t *mib, frame_t frame, uint8_t *buffer return encode_size; } +static void schedule_one_ssb(gNB_MAC_INST *gNB, + nfapi_nr_dl_tti_request_body_t *dl_req, + const long band, + const NR_SubcarrierSpacing_t scs, + const int i_ssb, + const int rel_slot, + const frame_t frameP, + const slot_t slotP, + const int CC_id, + const uint8_t ssb_frame_periodicity, + const frequency_range_t FR) +{ + // if start symbol is in current slot, schedule current SSB, fill VRB map and call get_type0_PDCCH_CSS_config_parameters + const int slots_per_frame = gNB->frame_structure.numb_slots_frame; + const uint16_t offset_pointa = gNB->ssb_OffsetPointA; + NR_COMMON_channels_t *cc = &gNB->common_channels[CC_id]; + NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; + const NR_MIB_t *mib = cc->mib->message.choice.mib; + uint32_t mib_pdu = (*(uint32_t *)cc->MIB_pdu) & ((1 << 24) - 1); + uint8_t ssbSubcarrierOffset = gNB->ssb_SubcarrierOffset; + + uint16_t ssb_start_symbol = get_ssb_start_symbol(band, scs, i_ssb); + int beam_index = get_fapi_beamforming_index(gNB, i_ssb); + NR_beam_alloc_t beam = beam_allocation_procedure(&gNB->beam_info, frameP, slotP, beam_index, slots_per_frame); + AssertFatal(beam.idx >= 0, "Cannot allocate SSB %d in any available beam\n", i_ssb); + const int prb_offset = (FR == FR2) ? offset_pointa >> (scs - 2) : offset_pointa >> scs; + schedule_ssb(frameP, slotP, scc, dl_req, i_ssb, beam_index, ssbSubcarrierOffset, offset_pointa, mib_pdu); + fill_ssb_vrb_map(cc, + prb_offset, + (FR == FR2) ? ssbSubcarrierOffset >> (scs - 2) : ssbSubcarrierOffset, + ssb_start_symbol, + CC_id, + beam.idx); + if (IS_SA_MODE(get_softmodem_params())) { + get_type0_PDCCH_CSS_config_parameters(&gNB->type0_PDCCH_CSS_config[i_ssb], + frameP, + mib, + slots_per_frame, + ssbSubcarrierOffset, + ssb_start_symbol, + scs, + FR, + band, + i_ssb, + ssb_frame_periodicity, + prb_offset); + gNB->type0_PDCCH_CSS_config[i_ssb].active = true; + } +} + void schedule_nr_mib(module_id_t module_idP, frame_t frameP, slot_t slotP, nfapi_nr_dl_tti_request_t *DL_req) { gNB_MAC_INST *gNB = RC.nrmac[module_idP]; @@ -121,8 +171,7 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, slot_t slotP, nfapi nfapi_nr_dl_tti_request_body_t *dl_req; for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - NR_COMMON_channels_t *cc= &gNB->common_channels[CC_id]; - const NR_MIB_t *mib = cc->mib->message.choice.mib; + NR_COMMON_channels_t *cc = &gNB->common_channels[CC_id]; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; const int slots_per_frame = gNB->frame_structure.numb_slots_frame; dl_req = &DL_req->dl_tti_request_body; @@ -143,8 +192,6 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, slot_t slotP, nfapi mib_sdu_length); } - uint32_t mib_pdu = (*(uint32_t *)cc->MIB_pdu) & ((1 << 24) - 1); - int8_t ssb_period = *scc->ssb_periodicityServingCell; uint8_t ssb_frame_periodicity = 1; // every how many frames SSB are generated @@ -162,8 +209,6 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, slot_t slotP, nfapi NR_SubcarrierSpacing_t scs = *scc->ssbSubcarrierSpacing; const long band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]; - const uint16_t offset_pointa = gNB->ssb_OffsetPointA; - uint8_t ssbSubcarrierOffset = gNB->ssb_SubcarrierOffset; const BIT_STRING_t *shortBitmap = &scc->ssb_PositionsInBurst->choice.shortBitmap; const BIT_STRING_t *mediumBitmap = &scc->ssb_PositionsInBurst->choice.mediumBitmap; @@ -175,30 +220,8 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, slot_t slotP, nfapi for (int i_ssb = 0; i_ssb < 4; i_ssb++) { if ((shortBitmap->buf[0] >> (7 - i_ssb)) & 0x01) { uint16_t ssb_start_symbol = get_ssb_start_symbol(band, scs, i_ssb); - // if start symbol is in current slot, schedule current SSB, fill VRB map and call get_type0_PDCCH_CSS_config_parameters - if ((ssb_start_symbol / 14) == rel_slot) { - int beam_index = get_fapi_beamforming_index(gNB, i_ssb); - NR_beam_alloc_t beam = beam_allocation_procedure(&gNB->beam_info, frameP, slotP, beam_index, slots_per_frame); - AssertFatal(beam.idx >= 0, "Cannot allocate SSB %d in any available beam\n", i_ssb); - const int prb_offset = offset_pointa >> scs; - schedule_ssb(frameP, slotP, scc, dl_req, i_ssb, beam_index, ssbSubcarrierOffset, offset_pointa, mib_pdu); - fill_ssb_vrb_map(cc, prb_offset, ssbSubcarrierOffset, ssb_start_symbol, CC_id, beam.idx); - if (IS_SA_MODE(get_softmodem_params())) { - get_type0_PDCCH_CSS_config_parameters(&gNB->type0_PDCCH_CSS_config[i_ssb], - frameP, - mib, - slots_per_frame, - ssbSubcarrierOffset, - ssb_start_symbol, - scs, - FR1, - band, - i_ssb, - ssb_frame_periodicity, - prb_offset); - gNB->type0_PDCCH_CSS_config[i_ssb].active = true; - } - } + if ((ssb_start_symbol / 14) == rel_slot) + schedule_one_ssb(gNB, dl_req, band, scs, i_ssb, rel_slot, frameP, slotP, CC_id, ssb_frame_periodicity, FR1); } } break; @@ -207,30 +230,8 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, slot_t slotP, nfapi for (int i_ssb = 0; i_ssb < 8; i_ssb++) { if ((mediumBitmap->buf[0] >> (7 - i_ssb)) & 0x01) { uint16_t ssb_start_symbol = get_ssb_start_symbol(band, scs, i_ssb); - // if start symbol is in current slot, schedule current SSB, fill VRB map and call get_type0_PDCCH_CSS_config_parameters - if ((ssb_start_symbol / 14) == rel_slot) { - int beam_index = get_fapi_beamforming_index(gNB, i_ssb); - NR_beam_alloc_t beam = beam_allocation_procedure(&gNB->beam_info, frameP, slotP, beam_index, slots_per_frame); - AssertFatal(beam.idx >= 0, "Cannot allocate SSB %d in any available beam\n", i_ssb); - const int prb_offset = offset_pointa >> scs; - schedule_ssb(frameP, slotP, scc, dl_req, i_ssb, beam_index, ssbSubcarrierOffset, offset_pointa, mib_pdu); - fill_ssb_vrb_map(cc, prb_offset, ssbSubcarrierOffset, ssb_start_symbol, CC_id, beam.idx); - if (IS_SA_MODE(get_softmodem_params())) { - get_type0_PDCCH_CSS_config_parameters(&gNB->type0_PDCCH_CSS_config[i_ssb], - frameP, - mib, - slots_per_frame, - ssbSubcarrierOffset, - ssb_start_symbol, - scs, - FR1, - band, - i_ssb, - ssb_frame_periodicity, - prb_offset); - gNB->type0_PDCCH_CSS_config[i_ssb].active = true; - } - } + if ((ssb_start_symbol / 14) == rel_slot) + schedule_one_ssb(gNB, dl_req, band, scs, i_ssb, rel_slot, frameP, slotP, CC_id, ssb_frame_periodicity, FR1); } } break; @@ -239,30 +240,8 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, slot_t slotP, nfapi for (int i_ssb = 0; i_ssb < 64; i_ssb++) { if ((longBitmap->buf[i_ssb / 8] >> (7 - (i_ssb % 8))) & 0x01) { uint16_t ssb_start_symbol = get_ssb_start_symbol(band, scs, i_ssb); - // if start symbol is in current slot, schedule current SSB, fill VRB map and call get_type0_PDCCH_CSS_config_parameters - if ((ssb_start_symbol / 14) == rel_slot) { - int beam_index = get_fapi_beamforming_index(gNB, i_ssb); - NR_beam_alloc_t beam = beam_allocation_procedure(&gNB->beam_info, frameP, slotP, beam_index, slots_per_frame); - AssertFatal(beam.idx >= 0, "Cannot allocate SSB %d in any available beam\n", i_ssb); - const int prb_offset = offset_pointa >> (scs-2); // reference 60kHz - schedule_ssb(frameP, slotP, scc, dl_req, i_ssb, beam_index, ssbSubcarrierOffset, offset_pointa, mib_pdu); - fill_ssb_vrb_map(cc, prb_offset, ssbSubcarrierOffset >> (scs - 2), ssb_start_symbol, CC_id, beam.idx); - if (IS_SA_MODE(get_softmodem_params())) { - get_type0_PDCCH_CSS_config_parameters(&gNB->type0_PDCCH_CSS_config[i_ssb], - frameP, - mib, - slots_per_frame, - ssbSubcarrierOffset, - ssb_start_symbol, - scs, - FR2, - band, - i_ssb, - ssb_frame_periodicity, - prb_offset); - gNB->type0_PDCCH_CSS_config[i_ssb].active = true; - } - } + if ((ssb_start_symbol / 14) == rel_slot) + schedule_one_ssb(gNB, dl_req, band, scs, i_ssb, rel_slot, frameP, slotP, CC_id, ssb_frame_periodicity, FR2); } } break; From 15e59665e6a51d6fdce76fe5cd306c2197baaa66 Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Sat, 29 Nov 2025 03:58:13 +0000 Subject: [PATCH 05/22] mac: change array beam_allocation to int16_t int16_t is sufficient to hold beam_id and -1 if not allocated. Following commits will bring changes to only pass LSB 15 bits as beam_id to PHY. --- openair2/GNB_APP/gnb_config.c | 2 +- openair2/LAYER2/NR_MAC_gNB/config.c | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 6 +++--- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 4 ++-- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 1f641fc6d9..cbf73a861b 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1630,7 +1630,7 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) AssertFatal(NFAPI_MODE == NFAPI_MONOLITHIC, "Analog beamforming only supported for monolithic scenario\n"); NR_beam_info_t *beam_info = &RC.nrmac[j]->beam_info; int beams_per_period = *MacRLC_ParamList.paramarray[j][MACRLC_ANALOG_BEAMS_PERIOD_IDX].u8ptr; - beam_info->beam_allocation = malloc16(beams_per_period * sizeof(int *)); + beam_info->beam_allocation = malloc16(beams_per_period * sizeof(beam_info->beam_allocation)); beam_info->beam_duration = *MacRLC_ParamList.paramarray[j][MACRLC_ANALOG_BEAM_DURATION_IDX].u8ptr; beam_info->beams_per_period = beams_per_period; beam_info->beam_allocation_size = -1; // to be initialized once we have information on frame configuration diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 35b6fa509a..93146b7b6f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -780,7 +780,7 @@ static void initialize_beam_information(NR_beam_info_t *beam_info, int mu, int s slots_per_frame); beam_info->beam_allocation_size = size / beam_info->beam_duration; for (int i = 0; i < beam_info->beams_per_period; i++) { - beam_info->beam_allocation[i] = malloc16(beam_info->beam_allocation_size * sizeof(int)); + beam_info->beam_allocation[i] = malloc16(beam_info->beam_allocation_size * sizeof(*beam_info->beam_allocation)); for (int j = 0; j < beam_info->beam_allocation_size; j++) beam_info->beam_allocation[i][j] = -1; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 14dedb1de9..01a3f8d31a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -3666,7 +3666,7 @@ static inline int get_beam_index(const NR_beam_info_t *beam_info, int frame, int return ((frame * slots_per_frame + slot) / beam_info->beam_duration) % beam_info->beam_allocation_size; } -NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame) +NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame, int slot, int16_t beam_index, int slots_per_frame) { // if no beam allocation for analog beamforming we always return beam index 0 (no multiple beams) if (beam_info->beam_mode == NO_BEAM_MODE) @@ -3675,7 +3675,7 @@ NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame, const int index = get_beam_index(beam_info, frame, slot, slots_per_frame); for (int i = 0; i < beam_info->beams_per_period; i++) { NR_beam_alloc_t beam_struct = {.new_beam = false, .idx = i}; - int *beam = &beam_info->beam_allocation[i][index]; + int16_t *beam = &beam_info->beam_allocation[i][index]; if (*beam == -1) { beam_struct.new_beam = true; *beam = beam_index; @@ -3689,7 +3689,7 @@ NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame, return (NR_beam_alloc_t) {.new_beam = false, .idx = -1}; } -void reset_beam_status(NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame, bool new_beam) +void reset_beam_status(NR_beam_info_t *beam_info, int frame, int slot, int16_t beam_index, int slots_per_frame, bool new_beam) { if(!new_beam) // need to reset only if the beam was allocated specifically for this instance return; diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index af0d102212..fb771c4759 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -447,8 +447,8 @@ int ul_buffer_index(int frame, int slot, int slots_per_frame, int size); void UL_tti_req_ahead_initialization(gNB_MAC_INST *gNB, int n, int CCid, frame_t frameP, int slotP); void fapi_beam_index_allocation(NR_ServingCellConfigCommon_t *scc, const nr_mac_config_t *config, gNB_MAC_INST *mac); int get_fapi_beamforming_index(gNB_MAC_INST *mac, int ssb_idx); -NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame); -void reset_beam_status(NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame, bool new_beam); +NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame, int slot, int16_t beam_index, int slots_per_frame); +void reset_beam_status(NR_beam_info_t *beam_info, int frame, int slot, int16_t beam_index, int slots_per_frame, bool new_beam); void beam_selection_procedures(gNB_MAC_INST *mac, NR_UE_info_t *UE); void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t frameP, slot_t slotP); bwp_info_t get_pdsch_bwp_start_size(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 9035901456..de7962fb7b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -826,7 +826,7 @@ typedef enum { typedef struct { /// list of allocated beams per period - int **beam_allocation; + int16_t **beam_allocation; int beam_duration; // in slots int beams_per_period; int beam_allocation_size; From c288f8465133d65b0a4799e83edb7504f2140b9b Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Mon, 29 Sep 2025 17:26:42 +0000 Subject: [PATCH 06/22] mac: fix fapi beam id Set MSB of fapi beam ID based on flag for beamforming done in hiPHY or loPHY. --- common/utils/utils.h | 4 +-- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 2 +- openair2/GNB_APP/gnb_config.c | 1 + openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 33 ++++++++----------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c | 26 ++++----------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 5 +-- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 15 +++++++-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c | 3 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 3 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 11 ++++--- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 11 ++++--- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 2 +- 12 files changed, 58 insertions(+), 58 deletions(-) diff --git a/common/utils/utils.h b/common/utils/utils.h index df188b812f..ede5cf7a84 100644 --- a/common/utils/utils.h +++ b/common/utils/utils.h @@ -33,8 +33,8 @@ extern "C" { __typeof__ (b) _b = (b); \ _a < _b ? _a : _b; }) - - +#define IS_BIT_SET(a, b) ((a >> b) & 1) +#define SET_BIT(a, b) (a | (1 << b)) #ifdef __cplusplus #ifdef min diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index b1971d133f..f7d2496faf 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -77,7 +77,7 @@ int beam_index_allocation(bool das, if (das) return fapi_beam_index; - int ru_beam_idx = analog_bf->analog_beam_list[fapi_beam_index].value; + int ru_beam_idx = analog_bf->analog_beam_list[fapi_beam_index].value & 0x7fff; int idx = -1; for (int j = 0; j < common_vars->num_beams_period; j++) { // L2 analog beam implementation is slot based, so we need to verify occupancy for the whole slot diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index cbf73a861b..d70bf712b8 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1634,6 +1634,7 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) beam_info->beam_duration = *MacRLC_ParamList.paramarray[j][MACRLC_ANALOG_BEAM_DURATION_IDX].u8ptr; beam_info->beams_per_period = beams_per_period; beam_info->beam_allocation_size = -1; // to be initialized once we have information on frame configuration + // TODO: Indicate this to MAC via FAPI TLV 0x0164. beam_info->beam_mode = ab == 1 ? PRECONFIGURED_BEAM_IDX : LOPHY_BEAM_IDX; } else { RC.nrmac[j]->beam_info.beam_mode = NO_BEAM_MODE; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index a1e63d6e74..5720f28279 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -516,7 +516,8 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) prach_pdu->beamforming.num_prgs = 1; prach_pdu->beamforming.prg_size = n_ra_rb; prach_pdu->beamforming.dig_bf_interface = num_td_occ; - prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[num_td_occ - 1].beam_idx = beam_index; + const uint16_t fapi_beam = convert_to_fapi_beam(beam_index, gNB->beam_info.beam_mode); + prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[num_td_occ - 1].beam_idx = fapi_beam; LOG_D(NR_MAC, "Frame %d, Slot %d: Prach Occasion id = %u fdm index = %u start symbol = %u slot index = %u subframe index = %u \n", @@ -900,7 +901,8 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, 0, ra->msg3_round, ul_bwp->pusch_Config && ul_bwp->pusch_Config->frequencyHopping, - UE->rnti); + UE->rnti, + nr_mac->beam_info.beam_mode); future_ul_tti_req->n_pdus += 1; // generation of DCI 0_0 to schedule msg3 retransmission @@ -933,14 +935,9 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, } // Fill PDCCH DL DCI PDU - nfapi_nr_dl_dci_pdu_t *dci_pdu = prepare_dci_pdu(pdcch_pdu_rel15, - scc, - ss, - coreset, - aggregation_level, - CCEIndex, - UE->UE_beam_index, - UE->rnti); + const uint16_t fapi_beam = convert_to_fapi_beam(UE->UE_beam_index, nr_mac->beam_info.beam_mode); + nfapi_nr_dl_dci_pdu_t *dci_pdu = + prepare_dci_pdu(pdcch_pdu_rel15, scc, ss, coreset, aggregation_level, CCEIndex, fapi_beam, UE->rnti); pdcch_pdu_rel15->numDlDci++; dci_pdu_rel15_t uldci_payload = {0}; @@ -1204,7 +1201,8 @@ static void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, slot_ 0, 0, ul_bwp->pusch_Config && ul_bwp->pusch_Config->frequencyHopping, - UE->rnti); + UE->rnti, + mac->beam_info.beam_mode); future_ul_tti_req->n_pdus += 1; // calling function to fill rar message @@ -1326,6 +1324,7 @@ static void prepare_dl_pdus(gNB_MAC_INST *nr_mac, NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; + const uint16_t fapi_beam = convert_to_fapi_beam(UE->UE_beam_index, nr_mac->beam_info.beam_mode); nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 = prepare_pdsch_pdu(dl_tti_pdsch_pdu, nr_mac, UE, @@ -1334,19 +1333,13 @@ static void prepare_dl_pdus(gNB_MAC_INST *nr_mac, false, round, rnti, - UE->UE_beam_index, + fapi_beam, 1, pduindex); /* Fill PDCCH DL DCI PDU */ - nfapi_nr_dl_dci_pdu_t *dci_pdu = prepare_dci_pdu(pdcch_pdu_rel15, - scc, - sched_ctrl->search_space, - coreset, - aggregation_level, - CCEIndex, - UE->UE_beam_index, - rnti); + nfapi_nr_dl_dci_pdu_t *dci_pdu = + prepare_dci_pdu(pdcch_pdu_rel15, scc, sched_ctrl->search_space, coreset, aggregation_level, CCEIndex, fapi_beam, rnti); pdcch_pdu_rel15->numDlDci++; dci_pdu_rel15_t dci_payload = prepare_dci_dl_payload(nr_mac, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index 7bc5d6ed91..937032693b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -139,6 +139,7 @@ static void schedule_one_ssb(gNB_MAC_INST *gNB, int beam_index = get_fapi_beamforming_index(gNB, i_ssb); NR_beam_alloc_t beam = beam_allocation_procedure(&gNB->beam_info, frameP, slotP, beam_index, slots_per_frame); AssertFatal(beam.idx >= 0, "Cannot allocate SSB %d in any available beam\n", i_ssb); + beam_index = convert_to_fapi_beam(beam_index, gNB->beam_info.beam_mode); const int prb_offset = (FR == FR2) ? offset_pointa >> (scs - 2) : offset_pointa >> scs; schedule_ssb(frameP, slotP, scc, dl_req, i_ssb, beam_index, ssbSubcarrierOffset, offset_pointa, mib_pdu); fill_ssb_vrb_map(cc, @@ -401,17 +402,9 @@ static void nr_fill_nfapi_dl_SIB_pdu(gNB_MAC_INST *gNB_mac, dl_tti_pdsch_pdu->PDUSize = (uint16_t)(4+sizeof(nfapi_nr_dl_tti_pdsch_pdu)); dl_req->nPDUs += 1; - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 = prepare_pdsch_pdu(dl_tti_pdsch_pdu, - gNB_mac, - NULL, - pdsch, - NULL, - is_sib1, - 0, - SI_RNTI, - beam_index, - 1, - pdu_index); + const uint16_t fapi_beam = convert_to_fapi_beam(beam_index, gNB_mac->beam_info.beam_mode); + nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 = + prepare_pdsch_pdu(dl_tti_pdsch_pdu, gNB_mac, NULL, pdsch, NULL, is_sib1, 0, SI_RNTI, fapi_beam, 1, pdu_index); LOG_D(NR_MAC, "OtherSI:bwpStart %d, bwpSize %d, rbStart %d, rbSize %d, dlDmrsSymbPos = 0x%x\n", pdsch_pdu_rel15->BWPStart, @@ -421,14 +414,8 @@ static void nr_fill_nfapi_dl_SIB_pdu(gNB_MAC_INST *gNB_mac, pdsch_pdu_rel15->dlDmrsSymbPos); /* Fill PDCCH DL DCI PDU */ - nfapi_nr_dl_dci_pdu_t *dci_pdu = prepare_dci_pdu(pdcch_pdu_rel15, - scc, - search_space, - coreset, - aggregation_level, - cce_index, - beam_index, - SI_RNTI); + nfapi_nr_dl_dci_pdu_t *dci_pdu = + prepare_dci_pdu(pdcch_pdu_rel15, scc, search_space, coreset, aggregation_level, cce_index, fapi_beam, SI_RNTI); pdcch_pdu_rel15->numDlDci++; /* DCI payload */ @@ -629,6 +616,7 @@ static void other_sib_sched_control(module_id_t module_idP, slot); NR_ServingCellConfigCommon_t *scc = gNB_mac->common_channels[0].ServingCellConfigCommon; int n_slots_frame = gNB_mac->frame_structure.numb_slots_frame; + beam_index = get_fapi_beamforming_index(gNB_mac, beam_index); NR_beam_alloc_t beam = beam_allocation_procedure(&gNB_mac->beam_info, frame, slot, beam_index, n_slots_frame); AssertFatal(beam.idx >= 0, "Cannot allocate otherSIB corresponding for SSB number %d in any available beam\n", beam_index); LOG_D(NR_MAC, "(%d.%d) otherSIB payload %d transmission for ssb number %d\n", frame, slot, payload_idx, beam_index); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index d5c1048ad6..00c41953a1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1142,6 +1142,7 @@ void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE maxMIMO_Layers = 1; } const int nl_tbslbrm = min(maxMIMO_Layers, 4); + const uint16_t fapi_beam = convert_to_fapi_beam(UE->UE_beam_index, nr_mac->beam_info.beam_mode); nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu = prepare_pdsch_pdu(dl_tti_pdsch_pdu, nr_mac, UE, @@ -1150,7 +1151,7 @@ void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE false, harq->round, rnti, - UE->UE_beam_index, + fapi_beam, nl_tbslbrm, pduindex); @@ -1163,7 +1164,7 @@ void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE sched_ctrl->coreset, sched_ctrl->aggregation_level, sched_ctrl->cce_index, - UE->UE_beam_index, + fapi_beam, rnti); pdcch_pdu->numDlDci++; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 01a3f8d31a..403a4187c9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -1326,7 +1326,8 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t *pucch_pdu, uint16_t O_csi, uint16_t O_ack, uint8_t O_sr, - int r_pucch) + int r_pucch, + nr_beam_mode_t beam_mode) { NR_PUCCH_Resource_t *pucchres; NR_PUCCH_FormatConfig_t *pucchfmt; @@ -1534,7 +1535,8 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t *pucch_pdu, pucch_pdu->beamforming.num_prgs = 1; pucch_pdu->beamforming.prg_size = pucch_pdu->prb_size; pucch_pdu->beamforming.dig_bf_interface = 1; - pucch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = UE->UE_beam_index; + const uint16_t fapi_beam = convert_to_fapi_beam(UE->UE_beam_index, beam_mode); + pucch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = fapi_beam; } void set_r_pucch_parms(int rsetindex, @@ -3246,7 +3248,8 @@ void nr_csirs_scheduling(int Mod_idP, frame_t frame, slot_t slot, nfapi_nr_dl_tt csirs_pdu_rel15->precodingAndBeamforming.prg_size = resourceMapping.freqBand.nrofRBs; //1 PRG of max size csirs_pdu_rel15->precodingAndBeamforming.dig_bf_interfaces = 1; csirs_pdu_rel15->precodingAndBeamforming.prgs_list[0].pm_idx = 0; - csirs_pdu_rel15->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = UE->UE_beam_index; + const uint16_t fapi_beam = convert_to_fapi_beam(UE->UE_beam_index, gNB_mac->beam_info.beam_mode); + csirs_pdu_rel15->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = fapi_beam; csirs_pdu_rel15->bwp_size = dl_bwp->BWPSize; csirs_pdu_rel15->bwp_start = dl_bwp->BWPStart; csirs_pdu_rel15->subcarrier_spacing = dl_bwp->scs; @@ -3689,6 +3692,12 @@ NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame, return (NR_beam_alloc_t) {.new_beam = false, .idx = -1}; } +uint16_t convert_to_fapi_beam(const uint16_t beam_idx, const nr_beam_mode_t mode) +{ + AssertFatal(beam_idx >= 0 && beam_idx < 32768, "Beam index out of range. Valid range is [0, 32767]\n"); + return (mode == LOPHY_BEAM_IDX) ? SET_BIT(beam_idx, 15) : beam_idx; +} + void reset_beam_status(NR_beam_info_t *beam_info, int frame, int slot, int16_t beam_index, int slots_per_frame, bool new_beam) { if(!new_beam) // need to reset only if the beam was allocated specifically for this instance diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index cf58252ed9..8c8a25e446 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -473,7 +473,8 @@ static void nr_configure_srs(gNB_MAC_INST *nrmac, srs_pdu->beamforming.num_prgs = m_SRS[srs_pdu->config_index]; srs_pdu->beamforming.prg_size = srs_pdu->srs_parameters_v4.srs_bandwidth_size; } - srs_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = UE->UE_beam_index; + const uint16_t fapi_beam = convert_to_fapi_beam(UE->UE_beam_index, nrmac->beam_info.beam_mode); + srs_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = fapi_beam; NR_beam_alloc_t beam = beam_allocation_procedure(&nrmac->beam_info, frame, slot, UE->UE_beam_index, slots_per_frame); AssertFatal(beam.idx >= 0, "Cannot allocate SRS in any available beam\n"); uint16_t *vrb_map_UL = &nrmac->common_channels[CC_id].vrb_map_UL[beam.idx][buffer_index * MAX_BWP_SIZE]; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index eb32fde2e6..1bd7f3eb72 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -94,7 +94,8 @@ static void nr_fill_nfapi_pucch(gNB_MAC_INST *nrmac, frame_t frame, slot_t slot, pucch->csi_bits, pucch->dai_c, pucch->sr_flag, - pucch->r_pucch); + pucch->r_pucch, + nrmac->beam_info.beam_mode); } #define MIN_RSRP_VALUE -141 diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index abe5cd8361..f815caf9fd 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -2314,7 +2314,8 @@ nfapi_nr_pusch_pdu_t *prepare_pusch_pdu(nfapi_nr_ul_tti_request_t *future_ul_tti int harq_id, int harq_round, int fh, - int rnti) + int rnti, + nr_beam_mode_t beam_mode) { nfapi_nr_pusch_pdu_t *pusch_pdu = &future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pusch_pdu; memset(pusch_pdu, 0, sizeof(nfapi_nr_pusch_pdu_t)); @@ -2364,7 +2365,8 @@ nfapi_nr_pusch_pdu_t *prepare_pusch_pdu(nfapi_nr_ul_tti_request_t *future_ul_tti pusch_pdu->beamforming.num_prgs = 1; pusch_pdu->beamforming.prg_size = pusch_pdu->bwp_size; pusch_pdu->beamforming.dig_bf_interface = 1; - pusch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = UE->UE_beam_index; + pusch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = + convert_to_fapi_beam(UE->UE_beam_index, beam_mode); /* TRANSFORM PRECODING --------------------------------------------------------*/ if (pusch_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled) { // U as specified in section 6.4.1.1.1.2 in 38.211, if sequence hopping and group hopping are disabled @@ -2522,7 +2524,8 @@ void post_process_ulsch(gNB_MAC_INST *nr_mac, post_process_pusch_t *pusch, NR_UE harq_id, cur_harq->round, current_BWP->pusch_Config && current_BWP->pusch_Config->frequencyHopping, - UE->rnti); + UE->rnti, + nr_mac->beam_info.beam_mode); req->n_pdus += 1; // Calculate the normalized tx_power for PHR @@ -2564,7 +2567,7 @@ void post_process_ulsch(gNB_MAC_INST *nr_mac, post_process_pusch_t *pusch, NR_UE coreset, sched_ctrl->aggregation_level, sched_ctrl->cce_index, - UE->UE_beam_index, + convert_to_fapi_beam(UE->UE_beam_index, nr_mac->beam_info.beam_mode), UE->rnti); pdcch_pdu->numDlDci++; diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index fb771c4759..b3890d4019 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -213,14 +213,15 @@ int nr_get_pucch_resource(NR_ControlResourceSet_t *coreset, NR_PUCCH_Config_t *pucch_Config, int CCEIndex); -void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu, +void nr_configure_pucch(nfapi_nr_pucch_pdu_t *pucch_pdu, NR_ServingCellConfigCommon_t *scc, - NR_UE_info_t* UE, + NR_UE_info_t *UE, uint8_t pucch_resource, uint16_t O_csi, uint16_t O_ack, uint8_t O_sr, - int r_pucch); + int r_pucch, + nr_beam_mode_t mode); void find_search_space(int ss_type, NR_BWP_Downlink_t *bwp, @@ -330,7 +331,8 @@ nfapi_nr_pusch_pdu_t *prepare_pusch_pdu(nfapi_nr_ul_tti_request_t *future_ul_tti int harq_id, int harq_round, int fh, - int rnti); + int rnti, + nr_beam_mode_t beam_mode); nfapi_nr_dl_tti_pdsch_pdu_rel15_t *prepare_pdsch_pdu(nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu, const gNB_MAC_INST *mac, const NR_UE_info_t *UE, @@ -447,6 +449,7 @@ int ul_buffer_index(int frame, int slot, int slots_per_frame, int size); void UL_tti_req_ahead_initialization(gNB_MAC_INST *gNB, int n, int CCid, frame_t frameP, int slotP); void fapi_beam_index_allocation(NR_ServingCellConfigCommon_t *scc, const nr_mac_config_t *config, gNB_MAC_INST *mac); int get_fapi_beamforming_index(gNB_MAC_INST *mac, int ssb_idx); +uint16_t convert_to_fapi_beam(const uint16_t beam_idx, const nr_beam_mode_t mode); NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame, int slot, int16_t beam_index, int slots_per_frame); void reset_beam_status(NR_beam_info_t *beam_info, int frame, int slot, int16_t beam_index, int slots_per_frame, bool new_beam); void beam_selection_procedures(gNB_MAC_INST *mac, NR_UE_info_t *UE); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index de7962fb7b..608723f510 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -794,7 +794,7 @@ typedef struct NR_UE_info { NR_UE_NR_Capability_t *capability; measgap_config_t measgap_config; // UE selected beam index - uint8_t UE_beam_index; + uint16_t UE_beam_index; float ul_thr_ue; float dl_thr_ue; long pdsch_HARQ_ACK_Codebook; From 830d619d3eb61914cb60380c2bd0e1055e2ec276 Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Tue, 21 Oct 2025 20:44:10 +0000 Subject: [PATCH 07/22] mac: allocate PDSCH on beams in phytest --- doc/analog_beamforming.md | 9 ++++ .../LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c | 7 +-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c | 53 +++++++++++++++---- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 10 ++++ openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 1 + 5 files changed, 66 insertions(+), 14 deletions(-) diff --git a/doc/analog_beamforming.md b/doc/analog_beamforming.md index 45f93bf44c..28de7edfeb 100644 --- a/doc/analog_beamforming.md +++ b/doc/analog_beamforming.md @@ -34,6 +34,15 @@ To this goal, we extended the virtual resource block (VRB) map by one dimension It is important to note that in current implementation, there are several periodical channels, e.g. PRACH or PUCCH for CSI et cetera, that have the precendence in being assigned a beam, that is because the scheduling is automatic, set in RRC configuration, and not up to the scheduler. For these instances, we assume the beam is available (if not there are assertions to stop the process). For data channels, the currently implemented PF scheduler is used. The only modification is that a UE can be served only if there is a free beam available or the one of the beams already in use correspond to that UE beam. +## Beams in phy-test scheduler + +In phy-test mode, beams are assigned to PDSCH slots in the same manner as SSB slots with the only addition that it repeats for every TDD period in a frame. For example if PDSCH is scheduled on all DL slot for TDD format DDDDDDDSUU, and with SSB bit map = `0b1010101` and the following beam parameters in config file, +- `beam_weights` = [10,11,12,13] +- `beam_duration` = 1 +- `beams_per_period` = 1 + +The DL slots in every TDD period will have beams 10,11,12,13,0,0,0 + # FAPI implementation To be noted that in our implementation analog beamforming is only supported in non-split/monolithic mode because we don't support yet SCF P19 interface that would be needed to manage these procedure in a split scenario with SCF FAPI. diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index 937032693b..35a0cb60b5 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -136,10 +136,11 @@ static void schedule_one_ssb(gNB_MAC_INST *gNB, uint8_t ssbSubcarrierOffset = gNB->ssb_SubcarrierOffset; uint16_t ssb_start_symbol = get_ssb_start_symbol(band, scs, i_ssb); - int beam_index = get_fapi_beamforming_index(gNB, i_ssb); - NR_beam_alloc_t beam = beam_allocation_procedure(&gNB->beam_info, frameP, slotP, beam_index, slots_per_frame); + NR_beam_alloc_t beam = + beam_allocation_procedure(&gNB->beam_info, frameP, slotP, get_fapi_beamforming_index(gNB, i_ssb), slots_per_frame); AssertFatal(beam.idx >= 0, "Cannot allocate SSB %d in any available beam\n", i_ssb); - beam_index = convert_to_fapi_beam(beam_index, gNB->beam_info.beam_mode); + const uint16_t beam_index = + convert_to_fapi_beam(get_allocated_beam(&gNB->beam_info, frameP, slotP, slots_per_frame, beam.idx), gNB->beam_info.beam_mode); const int prb_offset = (FR == FR2) ? offset_pointa >> (scs - 2) : offset_pointa >> scs; schedule_ssb(frameP, slotP, scc, dl_req, i_ssb, beam_index, ssbSubcarrierOffset, offset_pointa, mib_pdu); fill_ssb_vrb_map(cc, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index f9121b3125..84da5a4f78 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -92,14 +92,48 @@ void nr_preprocessor_phytest(gNB_MAC_INST *mac, post_process_pdsch_t *pp_pdsch) const int bwpSize = dl_bwp->BWPSize; const int BWPStart = dl_bwp->BWPStart; - // TODO implement beam procedures for phy-test mode - int beam = 0; + /* This is a primitive beam allocation procedure for PDSCH in phytest mode which is + intended to be used to verify the beamformed signal in VSA. The beam allocation of PDSCH + slots follows the SSB slots even in slots that don't have SSB. */ + int num_ssb = 0; + BIT_STRING_t *ssbBitmap = NULL; + switch (scc->ssb_PositionsInBurst->present) { + case 1: + num_ssb = 4; + ssbBitmap = &scc->ssb_PositionsInBurst->choice.shortBitmap; + break; + + case 2: + num_ssb = 8; + ssbBitmap = &scc->ssb_PositionsInBurst->choice.mediumBitmap; + break; + + default: + AssertFatal(0, "SSB burst len in burst not supported\n"); + } + int ssb_idx_beam = 0; + for (int i_ssb = 0; i_ssb < num_ssb; i_ssb++) { + if (IS_BIT_SET(ssbBitmap->buf[0], (7 - i_ssb))) { + NR_SubcarrierSpacing_t scs = *scc->ssbSubcarrierSpacing; + const long band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]; + uint16_t ssb_start_symbol = get_ssb_start_symbol(band, scs, i_ssb); + // select beam for PDSCH in current slot based on SSB beam + if ((ssb_start_symbol / NR_NUMBER_OF_SYMBOLS_PER_SLOT) == (slot % mac->frame_structure.numb_slots_period)) { + ssb_idx_beam = i_ssb; + break; + } + } + } + int beam_idx = get_fapi_beamforming_index(mac, ssb_idx_beam); + NR_beam_alloc_t beam = beam_allocation_procedure(&mac->beam_info, frame, slot, beam_idx, mac->frame_structure.numb_slots_frame); + AssertFatal(beam.idx > -1, "Can't allocate beam %d in phytest scheduler\n", beam_idx); + UE->UE_beam_index = get_allocated_beam(&mac->beam_info, frame, slot, mac->frame_structure.numb_slots_frame, beam.idx); int rbStart = 0; int rbSize = 0; if (target_dl_bw>bwpSize) target_dl_bw = bwpSize; - uint16_t *vrb_map = mac->common_channels[CC_id].vrb_map[beam]; + uint16_t *vrb_map = mac->common_channels[CC_id].vrb_map[beam.idx]; /* loop ensures that we allocate exactly target_dl_bw, or return */ while (true) { /* advance to first free RB */ @@ -132,9 +166,11 @@ void nr_preprocessor_phytest(gNB_MAC_INST *mac, post_process_pdsch_t *pp_pdsch) sched_ctrl->num_total_bytes += sched_ctrl->rlc_status[lcid].bytes_in_buffer; int CCEIndex = get_cce_index(mac, - CC_id, slot, UE->rnti, + CC_id, + slot, + UE->rnti, &sched_ctrl->aggregation_level, - beam, + beam.idx, sched_ctrl->search_space, sched_ctrl->coreset, &sched_ctrl->sched_pdcch, @@ -156,12 +192,7 @@ void nr_preprocessor_phytest(gNB_MAC_INST *mac, post_process_pdsch_t *pp_pdsch) sched_ctrl->cce_index = CCEIndex; - fill_pdcch_vrb_map(mac, - CC_id, - &sched_ctrl->sched_pdcch, - CCEIndex, - sched_ctrl->aggregation_level, - beam); + fill_pdcch_vrb_map(mac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, beam.idx); NR_sched_pdsch_t sched_pdsch = { .rbSize = rbSize, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 403a4187c9..cba1b32a54 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -3698,6 +3698,16 @@ uint16_t convert_to_fapi_beam(const uint16_t beam_idx, const nr_beam_mode_t mode return (mode == LOPHY_BEAM_IDX) ? SET_BIT(beam_idx, 15) : beam_idx; } +int16_t get_allocated_beam(const NR_beam_info_t *beam_info, int frame, int slot, int slots_per_frame, int beam_number_in_period) +{ + int16_t beam_idx = 0; + if (beam_info->beam_mode != NO_BEAM_MODE) { + const int index = get_beam_index(beam_info, frame, slot, slots_per_frame); + beam_idx = beam_info->beam_allocation[beam_number_in_period][index]; + } + return beam_idx; +} + void reset_beam_status(NR_beam_info_t *beam_info, int frame, int slot, int16_t beam_index, int slots_per_frame, bool new_beam) { if(!new_beam) // need to reset only if the beam was allocated specifically for this instance diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index b3890d4019..3aded2d318 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -449,6 +449,7 @@ int ul_buffer_index(int frame, int slot, int slots_per_frame, int size); void UL_tti_req_ahead_initialization(gNB_MAC_INST *gNB, int n, int CCid, frame_t frameP, int slotP); void fapi_beam_index_allocation(NR_ServingCellConfigCommon_t *scc, const nr_mac_config_t *config, gNB_MAC_INST *mac); int get_fapi_beamforming_index(gNB_MAC_INST *mac, int ssb_idx); +int16_t get_allocated_beam(const NR_beam_info_t *beam_info, int frame, int slot, int slots_per_frame, int beam_number_in_period); uint16_t convert_to_fapi_beam(const uint16_t beam_idx, const nr_beam_mode_t mode); NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame, int slot, int16_t beam_index, int slots_per_frame); void reset_beam_status(NR_beam_info_t *beam_info, int frame, int slot, int16_t beam_index, int slots_per_frame, bool new_beam); From 644579a4cf8f57f81cc4dba90d67e440f143fdda Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Fri, 31 Oct 2025 17:58:48 +0000 Subject: [PATCH 08/22] clean-up: rename functions Rename few functions and array related to beam index storing and allocation. Reduce code duplication in function to get ssb index bitmap. --- openair2/LAYER2/NR_MAC_gNB/config.c | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 6 +-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c | 6 +-- .../LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c | 22 ++-------- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 41 ++++++++++--------- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 6 ++- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 2 +- openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c | 2 +- 8 files changed, 39 insertions(+), 48 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 93146b7b6f..2637f72221 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -885,7 +885,7 @@ void nr_mac_config_scc(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, c LOG_D(NR_MAC, "Configuring common parameters from NR ServingCellConfig\n"); config_common(nrmac, config, scc); - fapi_beam_index_allocation(scc, config, nrmac); + fill_beam_index_list(scc, config, nrmac); if (NFAPI_MODE == NFAPI_MONOLITHIC) { // nothing to be sent in the other cases diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 5720f28279..c3cc4088ed 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -421,7 +421,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) // ordered ssb number int n_ssb = (int) (prach_occasion_id / (int)(1 / num_ssb_per_RO)) % cc->num_active_ssb; // fapi beam index - beam_index = get_fapi_beamforming_index(gNB, cc->ssb_index[n_ssb]); + beam_index = get_beam_from_ssbidx(gNB, cc->ssb_index[n_ssb]); // multi-beam allocation structure beam = beam_allocation_procedure(&gNB->beam_info, frameP, slotP, beam_index, slots_frame); AssertFatal(beam.idx >= 0, "Cannot allocate PRACH corresponding to %d SSB transmitted in any available beam\n", n_ssb + 1); @@ -429,7 +429,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) int first_ssb_index = (prach_occasion_id * (int)num_ssb_per_RO) % cc->num_active_ssb; for(int j = first_ssb_index; j < first_ssb_index + num_ssb_per_RO; j++) { // fapi beam index - beam_index = get_fapi_beamforming_index(gNB, cc->ssb_index[j]); + beam_index = get_beam_from_ssbidx(gNB, cc->ssb_index[j]); // multi-beam allocation structure beam = beam_allocation_procedure(&gNB->beam_info, frameP, slotP, beam_index, slots_frame); AssertFatal(beam.idx >= 0, "Cannot allocate PRACH corresponding to SSB %d in any available beam\n", j); @@ -763,7 +763,7 @@ void nr_initiate_ra_proc(module_id_t module_idP, configure_UE_BWP(nr_mac, scc, UE, true, NR_SearchSpace__searchSpaceType_PR_common, -1, -1); // return current SSB order in the list of tranmitted SSBs int n_ssb = ssb_index_from_prach(module_idP, frame, slot, preamble_index, freq_index, symbol); - UE->UE_beam_index = get_fapi_beamforming_index(nr_mac, cc->ssb_index[n_ssb]); + UE->UE_beam_index = get_beam_from_ssbidx(nr_mac, cc->ssb_index[n_ssb]); LOG_I(NR_MAC, "UE %04x: Sync beam index %d\n", UE->rnti, UE->UE_beam_index); NR_SCHED_UNLOCK(&nr_mac->sched_lock); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC, 0); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index 35a0cb60b5..d8c4ee04ba 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -137,7 +137,7 @@ static void schedule_one_ssb(gNB_MAC_INST *gNB, uint16_t ssb_start_symbol = get_ssb_start_symbol(band, scs, i_ssb); NR_beam_alloc_t beam = - beam_allocation_procedure(&gNB->beam_info, frameP, slotP, get_fapi_beamforming_index(gNB, i_ssb), slots_per_frame); + beam_allocation_procedure(&gNB->beam_info, frameP, slotP, get_beam_from_ssbidx(gNB, i_ssb), slots_per_frame); AssertFatal(beam.idx >= 0, "Cannot allocate SSB %d in any available beam\n", i_ssb); const uint16_t beam_index = convert_to_fapi_beam(get_allocated_beam(&gNB->beam_info, frameP, slotP, slots_per_frame, beam.idx), gNB->beam_info.beam_mode); @@ -509,7 +509,7 @@ void schedule_nr_sib1(module_id_t module_idP, "Trying to schedule SIB1 in slot %d which is not DL. Check searchSpaceZero configuration.\n", slotP); const int n_slots_frame = gNB_mac->frame_structure.numb_slots_frame; - int beam_index = get_fapi_beamforming_index(gNB_mac, i); + int beam_index = get_beam_from_ssbidx(gNB_mac, i); NR_beam_alloc_t beam = beam_allocation_procedure(&gNB_mac->beam_info, frameP, slotP, beam_index, n_slots_frame); AssertFatal(beam.idx >= 0, "Cannot allocate SIB1 corresponding to SSB %d in any available beam\n", i); LOG_D(NR_MAC,"(%d.%d) SIB1 transmission: ssb_index %d\n", frameP, slotP, type0_PDCCH_CSS_config->ssb_index); @@ -617,7 +617,7 @@ static void other_sib_sched_control(module_id_t module_idP, slot); NR_ServingCellConfigCommon_t *scc = gNB_mac->common_channels[0].ServingCellConfigCommon; int n_slots_frame = gNB_mac->frame_structure.numb_slots_frame; - beam_index = get_fapi_beamforming_index(gNB_mac, beam_index); + beam_index = get_beam_from_ssbidx(gNB_mac, beam_index); NR_beam_alloc_t beam = beam_allocation_procedure(&gNB_mac->beam_info, frame, slot, beam_index, n_slots_frame); AssertFatal(beam.idx >= 0, "Cannot allocate otherSIB corresponding for SSB number %d in any available beam\n", beam_index); LOG_D(NR_MAC, "(%d.%d) otherSIB payload %d transmission for ssb number %d\n", frame, slot, payload_idx, beam_index); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index 84da5a4f78..f23dfe8b30 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -95,25 +95,11 @@ void nr_preprocessor_phytest(gNB_MAC_INST *mac, post_process_pdsch_t *pp_pdsch) /* This is a primitive beam allocation procedure for PDSCH in phytest mode which is intended to be used to verify the beamformed signal in VSA. The beam allocation of PDSCH slots follows the SSB slots even in slots that don't have SSB. */ - int num_ssb = 0; - BIT_STRING_t *ssbBitmap = NULL; - switch (scc->ssb_PositionsInBurst->present) { - case 1: - num_ssb = 4; - ssbBitmap = &scc->ssb_PositionsInBurst->choice.shortBitmap; - break; - - case 2: - num_ssb = 8; - ssbBitmap = &scc->ssb_PositionsInBurst->choice.mediumBitmap; - break; - - default: - AssertFatal(0, "SSB burst len in burst not supported\n"); - } + uint8_t num_ssb = 0; + const uint64_t ssbBitmap = get_ssb_bitmap_and_len(scc, &num_ssb); int ssb_idx_beam = 0; for (int i_ssb = 0; i_ssb < num_ssb; i_ssb++) { - if (IS_BIT_SET(ssbBitmap->buf[0], (7 - i_ssb))) { + if (IS_BIT_SET(ssbBitmap, (63 - i_ssb))) { NR_SubcarrierSpacing_t scs = *scc->ssbSubcarrierSpacing; const long band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]; uint16_t ssb_start_symbol = get_ssb_start_symbol(band, scs, i_ssb); @@ -124,7 +110,7 @@ void nr_preprocessor_phytest(gNB_MAC_INST *mac, post_process_pdsch_t *pp_pdsch) } } } - int beam_idx = get_fapi_beamforming_index(mac, ssb_idx_beam); + int beam_idx = get_beam_from_ssbidx(mac, ssb_idx_beam); NR_beam_alloc_t beam = beam_allocation_procedure(&mac->beam_info, frame, slot, beam_idx, mac->frame_structure.numb_slots_frame); AssertFatal(beam.idx > -1, "Can't allocate beam %d in phytest scheduler\n", beam_idx); UE->UE_beam_index = get_allocated_beam(&mac->beam_info, frame, slot, mac->frame_structure.numb_slots_frame, beam.idx); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index cba1b32a54..f9a099d79b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -3622,45 +3622,48 @@ void UL_tti_req_ahead_initialization(gNB_MAC_INST *gNB, int n, int CCid, frame_t } } -int get_fapi_beamforming_index(gNB_MAC_INST *mac, int ssb_idx) +int get_beam_from_ssbidx(gNB_MAC_INST *mac, int ssb_idx) { - int beam_idx = mac->fapi_beam_index[ssb_idx]; + int beam_idx = mac->beam_index_list[ssb_idx]; AssertFatal(beam_idx >= 0, "Invalid beamforming index %d\n", beam_idx); return beam_idx; } -// TODO this is a placeholder for a possibly more complex function -// for now the fapi beam index is the number of SSBs transmitted before ssb_index i -void fapi_beam_index_allocation(NR_ServingCellConfigCommon_t *scc, const nr_mac_config_t *config, gNB_MAC_INST *mac) +uint64_t get_ssb_bitmap_and_len(const NR_ServingCellConfigCommon_t *scc, uint8_t *len) { - if (mac->beam_info.beam_mode == NO_BEAM_MODE) - return; - int len = 0; - uint8_t* buf = NULL; switch (scc->ssb_PositionsInBurst->present) { case NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_shortBitmap: - len = 4; - buf = scc->ssb_PositionsInBurst->choice.shortBitmap.buf; + *len = 4; break; case NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_mediumBitmap: - len = 8; - buf = scc->ssb_PositionsInBurst->choice.mediumBitmap.buf; + *len = 8; break; case NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_longBitmap: - len = 64; - buf = scc->ssb_PositionsInBurst->choice.longBitmap.buf; + *len = 64; break; default : AssertFatal(false, "Invalid configuration\n"); } + return get_ssb_bitmap(scc); +} + +// TODO this is a placeholder for a possibly more complex function +// for now the fapi beam index is the number of SSBs transmitted before ssb_index i +void fill_beam_index_list(NR_ServingCellConfigCommon_t *scc, const nr_mac_config_t *config, gNB_MAC_INST *mac) +{ + if (mac->beam_info.beam_mode == NO_BEAM_MODE) + return; + + uint8_t len = 0; + const uint64_t ssbBitmap = get_ssb_bitmap_and_len(scc, &len); int index = 0; for (int i = 0; i < len; ++i) { - if ((buf[i / 8] >> (7 - i % 8)) & 0x1) { + if (IS_BIT_SET(ssbBitmap, (63 - i))) { int fapi_index = mac->beam_info.beam_mode == LOPHY_BEAM_IDX ? config->bw_list[index] : index; - mac->fapi_beam_index[i] = fapi_index; + mac->beam_index_list[i] = fapi_index; index++; } else - mac->fapi_beam_index[i] = -1; + mac->beam_index_list[i] = -1; } } @@ -3726,7 +3729,7 @@ void beam_selection_procedures(gNB_MAC_INST *mac, NR_UE_info_t *UE) return; RSRP_report_t *rsrp_report = &UE->UE_sched_ctrl.CSI_report.ssb_rsrp_report; // simple beam switching algorithm -> we select beam with highest RSRP from CSI report - int new_bf_index = get_fapi_beamforming_index(mac, rsrp_report->resource_id[0]); + int new_bf_index = get_beam_from_ssbidx(mac, rsrp_report->resource_id[0]); if (UE->UE_beam_index == new_bf_index) return; // no beam change needed diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 3aded2d318..a8d4c76b31 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -447,8 +447,10 @@ int get_mcs_from_bler(const NR_bler_options_t *bler_options, int ul_buffer_index(int frame, int slot, int slots_per_frame, int size); void UL_tti_req_ahead_initialization(gNB_MAC_INST *gNB, int n, int CCid, frame_t frameP, int slotP); -void fapi_beam_index_allocation(NR_ServingCellConfigCommon_t *scc, const nr_mac_config_t *config, gNB_MAC_INST *mac); -int get_fapi_beamforming_index(gNB_MAC_INST *mac, int ssb_idx); +uint64_t get_ssb_bitmap(const NR_ServingCellConfigCommon_t *scc); +uint64_t get_ssb_bitmap_and_len(const NR_ServingCellConfigCommon_t *scc, uint8_t *len); +void fill_beam_index_list(NR_ServingCellConfigCommon_t *scc, const nr_mac_config_t *config, gNB_MAC_INST *mac); +int get_beam_from_ssbidx(gNB_MAC_INST *mac, int ssb_idx); int16_t get_allocated_beam(const NR_beam_info_t *beam_info, int frame, int slot, int slots_per_frame, int beam_number_in_period); uint16_t convert_to_fapi_beam(const uint16_t beam_idx, const nr_beam_mode_t mode); NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame, int slot, int16_t beam_index, int slots_per_frame); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 608723f510..ca1e217099 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -993,7 +993,7 @@ typedef struct gNB_MAC_INST_s { uint16_t min_grant_prb; bool identity_pm; int precoding_matrix_size[NR_MAX_NB_LAYERS]; - int fapi_beam_index[MAX_NUM_OF_SSB]; + int beam_index_list[MAX_NUM_OF_SSB]; /// dedicate UL TDA, common for all UEs seq_arr_t ul_tda; diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c index 3cd448b216..72bc611e2c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c @@ -309,7 +309,7 @@ static NR_ControlResourceSet_t *get_coreset_config(int bwp_id, int curr_bwp, uin return coreset; } -static uint64_t get_ssb_bitmap(const NR_ServingCellConfigCommon_t *scc) +uint64_t get_ssb_bitmap(const NR_ServingCellConfigCommon_t *scc) { uint64_t bitmap=0; switch (scc->ssb_PositionsInBurst->present) { From c1747a81091693d14050a69cc05c490ca81a2af0 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 14 Nov 2025 11:36:54 +0100 Subject: [PATCH 09/22] phy: remove unnecessary vendor extension fields When doing analogue beamforming, the beam ID for a pre-defined beam table is passed directly to RU and there is no need to store the beam table in PHY. --- doc/analog_beamforming.md | 10 ++-- executables/nr-gnb.c | 7 ++- nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c | 53 +++---------------- nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c | 21 -------- .../nfapi/public_inc/nfapi_nr_interface.h | 3 -- .../nfapi/public_inc/nfapi_nr_interface_scf.h | 2 - nfapi/tests/p5/nr_fapi_config_request_test.c | 25 ++------- openair1/PHY/NR_TRANSPORT/nr_dci.c | 1 - openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 1 - openair1/PHY/NR_TRANSPORT/nr_prach.c | 1 - openair1/PHY/NR_TRANSPORT/nr_ulsch.c | 1 - openair1/PHY/NR_TRANSPORT/pucch_rx.c | 1 - openair1/PHY/NR_TRANSPORT/srs_rx.c | 1 - openair1/SCHED_NR/phy_procedures_nr_gNB.c | 6 +-- openair1/SCHED_NR/sched_nr.h | 1 - openair2/LAYER2/NR_MAC_gNB/config.c | 9 ---- 16 files changed, 21 insertions(+), 122 deletions(-) diff --git a/doc/analog_beamforming.md b/doc/analog_beamforming.md index 28de7edfeb..cc0099c283 100644 --- a/doc/analog_beamforming.md +++ b/doc/analog_beamforming.md @@ -45,15 +45,15 @@ The DL slots in every TDD period will have beams 10,11,12,13,0,0,0 # FAPI implementation -To be noted that in our implementation analog beamforming is only supported in non-split/monolithic mode because we don't support yet SCF P19 interface that would be needed to manage these procedure in a split scenario with SCF FAPI. +To be noted that in our implementation analog beamforming is only partially supported in split mode. +The index based beamforming relies on the Tx precoding and beamforming PDU definition of beam-ID, where MSB is used to signal if the ID can be directly used or is it a pointer to a pre-stored vector of weights. +This definition of beam-ID is present only in the most recent versions of SCF PHY API specifications (at least from v8 and later, possibly from v6). -In `config_request` structure, a vendor extension (`nfapi_nr_analog_beamforming_ve_t`) configures the lower layers at initialization with the following information: +In addition to that, a `config_request` structure defined as vendor extension (`nfapi_nr_analog_beamforming_ve_t`) configures the lower layers at initialization with the following information: - `analog_bf_vendor_ext` which can assume values 1 or 0 for enabling or disabling analog beamforming - `num_beams_period_vendor_ext` which corresponds to the configuration parameter `beams_per_period` -- `total_num_beams_vendor_ext` which corresponds to the number of beams configured in `beam_weights` -- `analog_beam_list` which contains the RU beamforming indices configured in `beam_weights` -Additionally, L2 provides in each channel FAPI message information about the beam index. Small Cell Forum (SCF) FAPI provides in its PHY API specifications for the channels only a field for digital beamforming as part of the `precoding_and_beamforming` stucture. Therefore without a better option, we are currently using that one to store the internal analog beamforming index. This is the index used internally by the code to progressively identify the beam with a value from 0 to `total_num_beams_vendor_ext`. +Therefore, in case of analog beamforming, L2 provides in each channel FAPI message information about the beam index via the beam-ID parameter with MSB set to 1. # L1 implementation diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 94fc22cf46..226bf2775b 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -117,10 +117,9 @@ static void tx_func(processingData_L1tx_t *info) pushNotifiedFIFO(&gNB->resp_L1, res); int tx_slot_type = nr_slot_select(cfg, frame_tx, slot_tx); - // TODO check for analog_beam_list is a workaround while no beam API for beam - // selection is implemented - if (tx_slot_type == NR_DOWNLINK_SLOT || tx_slot_type == NR_MIXED_SLOT || get_softmodem_params()->continuous_tx || IS_SOFTMODEM_RFSIM - || cfg->analog_beamforming_ve.analog_beam_list) { + // TODO check for analog_bf_vendor_ext set to 1 is a workaround while no beam API for beam selection is implemented + if (tx_slot_type == NR_DOWNLINK_SLOT || tx_slot_type == NR_MIXED_SLOT || get_softmodem_params()->continuous_tx + || IS_SOFTMODEM_RFSIM || cfg->analog_beamforming_ve.analog_bf_vendor_ext.value) { start_meas(&info->gNB->phy_proc_tx); phy_procedures_gNB_TX(info->gNB, &sched_response.DL_req, diff --git a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c index c3e36d9999..9bbda9d519 100644 --- a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c +++ b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c @@ -1229,33 +1229,6 @@ uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e // only increase if it was set numTLVs += pNfapiMsg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag == NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG; - AssertFatal(pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.tl.tag == 0, - "Total num beams Vendor extension shouldn't be set!"); - // The call to pack the TLV would be the same as any other TLV, it is only packed if the tag is set, - // so, it's safe to add the call to pack_nr_tlv even if it is not always set - retval &= pack_nr_tlv(NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG, - &(pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext), - ppWritePackedMsg, - end, - &pack_uint8_tlv_value); - // only increase if it was set - numTLVs += - pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.tl.tag == NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG; - - for (int beam = 0; beam < pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.value; beam++) { - AssertFatal(pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam].tl.tag == 0, - "Analog beams list Vendor extension shouldn't be set!"); - // The call to pack the TLV would be the same as any other TLV, it is only packed if the tag is set, - // so, it's safe to add the call to pack_nr_tlv even if it is not always set - retval &= pack_nr_tlv(NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG, - &(pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam]), - ppWritePackedMsg, - end, - &pack_uint8_tlv_value); - // only increase if it was set - numTLVs += pNfapiMsg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag == NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG; - } - pNfapiMsg->num_tlv = numTLVs; retval &= push8(pNfapiMsg->num_tlv, &pNumTLVFields, end); return retval; @@ -1357,7 +1330,6 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void * int tdd_periodicity_idx = 0; int symbol_per_slot_idx = 0; #endif - int beam_ve_idx = 0; nfapi_nr_config_request_scf_t *pNfapiMsg = (nfapi_nr_config_request_scf_t *)msg; // unpack TLVs @@ -1417,10 +1389,12 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void * {NFAPI_NR_CONFIG_TDD_TABLE, NULL, &unpack_nr_tdd_table_10_04}, #endif #endif - {NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG, &(pNfapiMsg->analog_beamforming_ve.num_beams_period_vendor_ext), &unpack_uint8_tlv_value}, - {NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG, &(pNfapiMsg->analog_beamforming_ve.analog_bf_vendor_ext), &unpack_uint8_tlv_value}, - {NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG, &(pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext), &unpack_uint8_tlv_value}, - {NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG, NULL, &unpack_uint8_tlv_value}, + {NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG, + &(pNfapiMsg->analog_beamforming_ve.num_beams_period_vendor_ext), + &unpack_uint8_tlv_value}, + {NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG, + &(pNfapiMsg->analog_beamforming_ve.analog_bf_vendor_ext), + &unpack_uint8_tlv_value}, {NFAPI_NR_CONFIG_RSSI_MEASUREMENT_TAG, &(pNfapiMsg->measurement_config.rssi_measurement), &unpack_uint8_tlv_value}, {NFAPI_NR_CONFIG_BEAMFORMING_TABLE_TAG, NULL, &unpack_dbt_table_tlv_value}, {NFAPI_NR_CONFIG_PRECODING_TABLE_V6_TAG, NULL, &unpack_pm_table_tlv_value}, @@ -1463,21 +1437,6 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void * } int result = 0; switch (generic_tl.tag) { - case NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG: - pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.tl.tag = generic_tl.tag; - pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.tl.length = generic_tl.length; - result = (*unpack_fns[idx].unpack_func)(&pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext, ppReadPackedMsg, end); - pNfapiMsg->analog_beamforming_ve.analog_beam_list = (nfapi_uint8_tlv_t *)malloc( - pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.value * sizeof(nfapi_uint8_tlv_t)); - beam_ve_idx = 0; - break; - case NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG: - unpack_fns[idx].tlv = &pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam_ve_idx]; - pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam_ve_idx].tl.tag = generic_tl.tag; - pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam_ve_idx].tl.length = generic_tl.length; - result = (*unpack_fns[idx].unpack_func)(&pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam_ve_idx], ppReadPackedMsg, end); - beam_ve_idx ++; - break; case NFAPI_NR_CONFIG_BEAMFORMING_TABLE_TAG: unpack_fns[idx].tlv = &generic_tl; result = (*unpack_fns[idx].unpack_func)(&pNfapiMsg->dbt_config, ppReadPackedMsg, end); diff --git a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c index 5d1d0ba4e8..1ef65b664c 100644 --- a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c +++ b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c @@ -315,12 +315,6 @@ bool eq_config_request(const nfapi_nr_config_request_scf_t *unpacked_req, const EQ_TLV(unpacked_req->analog_beamforming_ve.analog_bf_vendor_ext, req->analog_beamforming_ve.analog_bf_vendor_ext); - EQ_TLV(unpacked_req->analog_beamforming_ve.total_num_beams_vendor_ext, req->analog_beamforming_ve.total_num_beams_vendor_ext); - - for (int i = 0; i < unpacked_req->analog_beamforming_ve.total_num_beams_vendor_ext.value; ++i) { - EQ_TLV(unpacked_req->analog_beamforming_ve.analog_beam_list[i], req->analog_beamforming_ve.analog_beam_list[i]); - } - return true; } @@ -464,10 +458,6 @@ void free_config_request(nfapi_nr_config_request_scf_t *msg) free(msg->dbt_config.dig_beam_list); free(msg->pmi_list.pmi_pdu); - - if (msg->analog_beamforming_ve.analog_beam_list) { - free(msg->analog_beamforming_ve.analog_beam_list); - } } void free_config_response(nfapi_nr_config_response_scf_t *msg) @@ -895,17 +885,6 @@ void copy_config_request(const nfapi_nr_config_request_scf_t *src, nfapi_nr_conf COPY_TLV(dst->analog_beamforming_ve.num_beams_period_vendor_ext, src->analog_beamforming_ve.num_beams_period_vendor_ext); COPY_TLV(dst->analog_beamforming_ve.analog_bf_vendor_ext, src->analog_beamforming_ve.analog_bf_vendor_ext); - - COPY_TLV(dst->analog_beamforming_ve.total_num_beams_vendor_ext, src->analog_beamforming_ve.total_num_beams_vendor_ext); - - if (dst->analog_beamforming_ve.total_num_beams_vendor_ext.value > 0) { - dst->analog_beamforming_ve.analog_beam_list = (nfapi_uint8_tlv_t *)malloc( - dst->analog_beamforming_ve.total_num_beams_vendor_ext.value * sizeof(nfapi_uint8_tlv_t)); - for (int i = 0; i < src->analog_beamforming_ve.total_num_beams_vendor_ext.value; ++i) { - COPY_TLV(dst->analog_beamforming_ve.analog_beam_list[i], src->analog_beamforming_ve.analog_beam_list[i]); - } - } - } void copy_config_response(const nfapi_nr_config_response_scf_t *src, nfapi_nr_config_response_scf_t *dst) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h index 683de59c59..2e74fdc800 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h @@ -31,9 +31,6 @@ #define NFAPI_NR_NFAPI_TIMING_INFO_PERIOD_TAG 0x0120 #define NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG 0xA000 #define NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG 0xA001 -#define NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG 0xA002 -#define NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG 0xA003 - typedef struct { uint16_t phy_id; diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index 12cf081fdc..10e6b7c14a 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -512,8 +512,6 @@ typedef struct { typedef struct { nfapi_uint8_tlv_t num_beams_period_vendor_ext; nfapi_uint8_tlv_t analog_bf_vendor_ext; - nfapi_uint8_tlv_t total_num_beams_vendor_ext; - nfapi_uint8_tlv_t *analog_beam_list; } nfapi_nr_analog_beamforming_ve_t; // ERROR enums diff --git a/nfapi/tests/p5/nr_fapi_config_request_test.c b/nfapi/tests/p5/nr_fapi_config_request_test.c index 5a80a89f3d..ed57a64d62 100644 --- a/nfapi/tests/p5/nr_fapi_config_request_test.c +++ b/nfapi/tests/p5/nr_fapi_config_request_test.c @@ -285,12 +285,10 @@ static void fill_config_request_tlv_tdd_rand(nfapi_nr_config_request_scf_t *nfap FILL_TLV(nfapi_resp->nfapi_config.timing_info_period, NFAPI_NR_NFAPI_TIMING_INFO_PERIOD_TAG, rand8()); nfapi_resp->num_tlv++; -/* - // TODO: Uncomment this block when ready to enable the pack of the following VE TLVs in nr_fapi_p5.c - // NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG - // NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG - // NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG - // NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG + /* + // TODO: Uncomment this block when ready to enable the pack of the following VE TLVs in nr_fapi_p5.c + // NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG + // NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG FILL_TLV(nfapi_resp->analog_beamforming_ve.num_beams_period_vendor_ext, NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG, rand8()); @@ -298,20 +296,7 @@ static void fill_config_request_tlv_tdd_rand(nfapi_nr_config_request_scf_t *nfap FILL_TLV(nfapi_resp->analog_beamforming_ve.analog_bf_vendor_ext, NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG, rand8()); nfapi_resp->num_tlv++; - - FILL_TLV(nfapi_resp->analog_beamforming_ve.total_num_beams_vendor_ext, - NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG, - rand8()); - nfapi_resp->num_tlv++; - - if (nfapi_resp->analog_beamforming_ve.total_num_beams_vendor_ext.value > 0) { - nfapi_resp->analog_beamforming_ve.analog_beam_list = - (nfapi_uint8_tlv_t *)malloc(nfapi_resp->analog_beamforming_ve.total_num_beams_vendor_ext.value * sizeof(nfapi_uint8_tlv_t)); - for (int i = 0; i < nfapi_resp->analog_beamforming_ve.total_num_beams_vendor_ext.value; ++i) { - FILL_TLV(nfapi_resp->analog_beamforming_ve.analog_beam_list[i], NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG, rand8()); - nfapi_resp->num_tlv++; - } - }*/ + */ } static void test_pack_unpack(nfapi_nr_config_request_scf_t *req) diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c index 2df2df8eb0..28d22b31bb 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c @@ -83,7 +83,6 @@ void nr_generate_dci(PHY_VARS_gNB *gNB, int bitmap = SL_to_bitmap(cset_start_symb, pdcch_pdu_rel15->DurationSymbols); int beam_nb = beam_index_allocation(gNB->enable_analog_das, dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx, - &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, frame_parms->symbols_per_slot, diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index 8df7b4814c..b8663aa435 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -681,7 +681,6 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC int bitmap = SL_to_bitmap(rel15->StartSymbolIndex, rel15->NrOfSymbols); int beam_nb = beam_index_allocation(gNB->enable_analog_das, pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, - &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, frame_parms->symbols_per_slot, diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 6ad39489d5..e42c02953c 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -103,7 +103,6 @@ prach_item_t *nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_n int bitmap = SL_to_bitmap(start_symb, n_symb); prach->beams[i] = beam_index_allocation(gNB->enable_analog_das, fapi_beam_idx, - &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, Slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c index 06aef61935..b963b7d970 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c @@ -158,7 +158,6 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pusch_pdu_t int bitmap = SL_to_bitmap(ulsch_pdu->start_symbol_index, ulsch_pdu->nr_of_symbols); ulsch->beam_nb = beam_index_allocation(gNB->enable_analog_das, fapi_beam_idx, - &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index 2a3987e755..8e2076df2f 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -71,7 +71,6 @@ void nr_fill_pucch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pucch_pdu_t int bitmap = SL_to_bitmap(pucch_pdu->start_symbol_index, pucch_pdu->nr_of_symbols); pucch->beam_nb = beam_index_allocation(gNB->enable_analog_das, fapi_beam_idx, - &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, diff --git a/openair1/PHY/NR_TRANSPORT/srs_rx.c b/openair1/PHY/NR_TRANSPORT/srs_rx.c index 3da018bf84..d5731557a0 100644 --- a/openair1/PHY/NR_TRANSPORT/srs_rx.c +++ b/openair1/PHY/NR_TRANSPORT/srs_rx.c @@ -60,7 +60,6 @@ void nr_fill_srs(PHY_VARS_gNB *gNB, frame_t frame, slot_t slot, nfapi_nr_srs_pdu int fapi_beam_idx = srs_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; srs->beam_nb = beam_index_allocation(gNB->enable_analog_das, fapi_beam_idx, - &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index f7d2496faf..1271734866 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -66,7 +66,6 @@ static void nr_fill_indication(PHY_VARS_gNB *gNB, int beam_index_allocation(bool das, int fapi_beam_index, - const nfapi_nr_analog_beamforming_ve_t *analog_bf, NR_gNB_COMMON *common_vars, int slot, int symbols_per_slot, @@ -77,7 +76,8 @@ int beam_index_allocation(bool das, if (das) return fapi_beam_index; - int ru_beam_idx = analog_bf->analog_beam_list[fapi_beam_index].value & 0x7fff; + AssertFatal(IS_BIT_SET(fapi_beam_index, 15), "Can't handle preconfigured DBM yet\n"); + int ru_beam_idx = fapi_beam_index & 0x7fff; int idx = -1; for (int j = 0; j < common_vars->num_beams_period; j++) { // L2 analog beam implementation is slot based, so we need to verify occupancy for the whole slot @@ -160,7 +160,6 @@ void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, const n int bitmap = SL_to_bitmap(ssb_start_symbol, 4); // 4 ssb symbols int beam_nb = beam_index_allocation(gNB->enable_analog_das, pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, - &cfg->analog_beamforming_ve, &gNB->common_vars, slot, fp->symbols_per_slot, @@ -229,7 +228,6 @@ static void nr_generate_csi_rs_gNB(PHY_VARS_gNB *gNB, csi_bitmap |= ((1 << lprime_num) - 1) << mapping_parms.loverline[j]; int beam_nb = beam_index_allocation(gNB->enable_analog_das, pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, - &cfg->analog_beamforming_ve, &gNB->common_vars, slot, gNB->frame_parms.symbols_per_slot, diff --git a/openair1/SCHED_NR/sched_nr.h b/openair1/SCHED_NR/sched_nr.h index da71809589..84691e9584 100644 --- a/openair1/SCHED_NR/sched_nr.h +++ b/openair1/SCHED_NR/sched_nr.h @@ -56,7 +56,6 @@ void nr_phy_free_RU(RU_t *ru); void clear_slot_beamid(PHY_VARS_gNB *gNB, int slot); int beam_index_allocation(bool das, int fapi_beam_index, - const nfapi_nr_analog_beamforming_ve_t *analog_bf, NR_gNB_COMMON *common_vars, int slot, int symbols_per_slot, diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 2637f72221..ed4d902345 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -708,7 +708,6 @@ static void config_common(gNB_MAC_INST *nrmac, const nr_mac_config_t *config, NR // precoding matrix configuration (to be improved) cfg->pmi_list = init_DL_MIMO_codebook(nrmac, pdsch_AntennaPorts); - int nb_beams = config->nb_bfw[1]; // number of beams if (nrmac->beam_info.beam_mode == PRECONFIGURED_BEAM_IDX) { LOG_I(NR_MAC, "Configuring analog beamforming in config_request message\n"); cfg->analog_beamforming_ve.num_beams_period_vendor_ext.tl.tag = NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG; @@ -717,14 +716,6 @@ static void config_common(gNB_MAC_INST *nrmac, const nr_mac_config_t *config, NR cfg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag = NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG; cfg->analog_beamforming_ve.analog_bf_vendor_ext.value = 1; // analog BF enabled cfg->num_tlv++; - cfg->analog_beamforming_ve.total_num_beams_vendor_ext.tl.tag = NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG; - cfg->analog_beamforming_ve.total_num_beams_vendor_ext.value = nb_beams; - cfg->num_tlv++; - cfg->analog_beamforming_ve.analog_beam_list = malloc16(nb_beams * sizeof(*cfg->analog_beamforming_ve.analog_beam_list)); - for (int i = 0; i < nb_beams; i++) { - cfg->analog_beamforming_ve.analog_beam_list[i].tl.tag = NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG; - cfg->analog_beamforming_ve.analog_beam_list[i].value = config->bw_list[i]; - } } else { cfg->analog_beamforming_ve.analog_bf_vendor_ext.value = 0; // analog BF disabled if (NFAPI_MODE == NFAPI_MONOLITHIC) { From ad366c3b17920e3ca6edc22f1a616f0f08a50c1a Mon Sep 17 00:00:00 2001 From: Sakthivel Velumani Date: Mon, 17 Nov 2025 17:07:20 +0000 Subject: [PATCH 10/22] fapi: ignore MSB of beam-ID for aerial Aerial L1 don't support handling of MSB bit in beam-ID. So it is not set in the fapi functions before sending down. --- nfapi/open-nFAPI/fapi/src/nr_fapi_p7.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/nfapi/open-nFAPI/fapi/src/nr_fapi_p7.c b/nfapi/open-nFAPI/fapi/src/nr_fapi_p7.c index aa90d3b4b9..3315ee2a4c 100644 --- a/nfapi/open-nFAPI/fapi/src/nr_fapi_p7.c +++ b/nfapi/open-nFAPI/fapi/src/nr_fapi_p7.c @@ -236,6 +236,12 @@ bool fapi_nr_p7_message_unpack(void *pMessageBuf, return true; } +#ifndef ENABLE_AERIAL +#define PARSE_BEAMID(a) (a) +#else +#define PARSE_BEAMID(a) ((a) & 0x7fff) +#endif + static uint8_t pack_nr_tx_beamforming_pdu(const nfapi_nr_tx_precoding_and_beamforming_t *beamforming_pdu, uint8_t **ppWritePackedMsg, uint8_t *end) @@ -249,7 +255,9 @@ static uint8_t pack_nr_tx_beamforming_pdu(const nfapi_nr_tx_precoding_and_beamfo return 0; } for (int digBFInterface = 0; digBFInterface < beamforming_pdu->dig_bf_interfaces; digBFInterface++) { - if (!push16(beamforming_pdu->prgs_list[prg].dig_bf_interface_list[digBFInterface].beam_idx, ppWritePackedMsg, end)) { + if (!push16(PARSE_BEAMID(beamforming_pdu->prgs_list[prg].dig_bf_interface_list[digBFInterface].beam_idx), + ppWritePackedMsg, + end)) { return 0; } } @@ -715,7 +723,9 @@ static uint8_t pack_nr_rx_beamforming_pdu(const nfapi_nr_ul_beamforming_t *beamf } for (int prg = 0; prg < beamforming_pdu->num_prgs; prg++) { for (int digBFInterface = 0; digBFInterface < beamforming_pdu->dig_bf_interface; digBFInterface++) { - if (!push16(beamforming_pdu->prgs_list[prg].dig_bf_interface_list[digBFInterface].beam_idx, ppWritePackedMsg, end)) { + if (!push16(PARSE_BEAMID(beamforming_pdu->prgs_list[prg].dig_bf_interface_list[digBFInterface].beam_idx), + ppWritePackedMsg, + end)) { return 0; } } @@ -1400,7 +1410,7 @@ static uint8_t pack_ul_dci_pdu_list_value(void *tlv, uint8_t **ppWritePackedMsg, return 0; } for (int digInt = 0; digInt < beamforming->dig_bf_interfaces; digInt++) { - if (!push16(beamforming->prgs_list[prg].dig_bf_interface_list[digInt].beam_idx, ppWritePackedMsg, end)) { + if (!push16(PARSE_BEAMID(beamforming->prgs_list[prg].dig_bf_interface_list[digInt].beam_idx), ppWritePackedMsg, end)) { return 0; } } From 6900edbf920eee04215950b57927d99a75ca738e Mon Sep 17 00:00:00 2001 From: Raghavendra Dinavahi Date: Mon, 24 Nov 2025 17:44:41 +0100 Subject: [PATCH 11/22] UE NTN: Fix in case SIB19 periodicity is greater than 2 secs --- openair2/RRC/NR_UE/rrc_UE.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 8487619092..cc07b374d6 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -259,6 +259,9 @@ static int get_ntn_timervalues(NR_UE_RRC_SI_INFO *SI_info, NR_NTN_Config_r17_t * // TODO remove the hardoded values and define a better strategy to determine the time of expiry // with real GEO/LEO/MEO SATs. int expire_before_ms = ((val430 >= 120) ? 10000 : 2000); + // SIB19 periodicity even for LEO could be configured to be more than epoch time interval (2 secs) + if (expire_before_ms < 2 * sib19_periodicity_ms) + expire_before_ms = 2 * sib19_periodicity_ms; int diff = *val430_ms - expire_before_ms; int sib19_timer_ms = (diff > 0) ? diff : ((*val430_ms - sib19_periodicity_ms) > 0) ? (*val430_ms - sib19_periodicity_ms) : 0; LOG_I(NR_RRC, "val430:%d s, T430:%d ms, sib19_timer:%d ms\n", val430, *val430_ms, sib19_timer_ms); From 912eca1af29474589dba5eebb9008d4b04c51ebe Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 16 Dec 2025 14:48:35 +0100 Subject: [PATCH 12/22] set correct beamforming type in CI FR2 test --- ci-scripts/conf_files/gnb.sa.band261.u3.32prb.rfsim.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-scripts/conf_files/gnb.sa.band261.u3.32prb.rfsim.conf b/ci-scripts/conf_files/gnb.sa.band261.u3.32prb.rfsim.conf index 6471c7bd02..f2455bc2c6 100644 --- a/ci-scripts/conf_files/gnb.sa.band261.u3.32prb.rfsim.conf +++ b/ci-scripts/conf_files/gnb.sa.band261.u3.32prb.rfsim.conf @@ -172,7 +172,7 @@ MACRLCs = ({ tr_n_preference = "local_RRC"; pusch_TargetSNRx10 = 200; pucch_TargetSNRx10 = 200; - set_analog_beamforming = 1; + set_analog_beamforming = 2; beam_duration = 1; beams_per_period = 1; beam_weights = [0]; // single SSB -> one analog beam From 1cca7f090ee5fae9e65ff21ec4868b9c1021df38 Mon Sep 17 00:00:00 2001 From: Raghavendra Dinavahi Date: Tue, 16 Dec 2025 15:24:28 +0100 Subject: [PATCH 13/22] UE NTN: changed handling of SIB19 periodic reception --- openair2/RRC/NR_UE/rrc_UE.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index cc07b374d6..384be2a7b1 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -248,22 +248,19 @@ static int eval_epoch_time(NR_UE_RRC_SI_INFO *SI_info, NR_NTN_Config_r17_t *ntnc static int get_ntn_timervalues(NR_UE_RRC_SI_INFO *SI_info, NR_NTN_Config_r17_t *ntncfg, int diff_frames, int *val430_ms) { int val430 = get_ulsyncvalidityduration_timer_value(ntncfg); - int sib19_periodicity_ms = (SI_info->sib19_periodicity + 1) * 10; + int sib19_periodicity_ms = SI_info->sib19_periodicity * 10; *val430_ms = val430 * 1000 + diff_frames * 10; // in ms if (*val430_ms <= sib19_periodicity_ms) LOG_E(NR_RRC, "Too small T430 value. Might result in frequent ULSYNC failure\n"); - // Depending on ulsyncvalidity duration, SIB19 timer expires 15secs/2secs before T430 - // LArger values might be used for GEO and epoch time interval can be around 10 secs - // Lower values will be used for NGSO (LEO/MEO), epoch time interval can be between 2-3 secs. - // TODO remove the hardoded values and define a better strategy to determine the time of expiry - // with real GEO/LEO/MEO SATs. - int expire_before_ms = ((val430 >= 120) ? 10000 : 2000); - // SIB19 periodicity even for LEO could be configured to be more than epoch time interval (2 secs) - if (expire_before_ms < 2 * sib19_periodicity_ms) - expire_before_ms = 2 * sib19_periodicity_ms; - int diff = *val430_ms - expire_before_ms; - int sib19_timer_ms = (diff > 0) ? diff : ((*val430_ms - sib19_periodicity_ms) > 0) ? (*val430_ms - sib19_periodicity_ms) : 0; + // by default SIB19 reception is started from the middle of the ulsyncvalidity duration.(i.e val430 in ms / 2) + int sib19_timer_ms = val430 * 500 + diff_frames * 10; + + // if this is less than the SIB19 periodicity, use that instead. + // set the timer to expire 1 frame (10 ms) before periodicity, to not miss the SIB19 + if (sib19_timer_ms <= sib19_periodicity_ms) + sib19_timer_ms = sib19_periodicity_ms - 10; + LOG_I(NR_RRC, "val430:%d s, T430:%d ms, sib19_timer:%d ms\n", val430, *val430_ms, sib19_timer_ms); return sib19_timer_ms; } From b5aad5956cee78bfd5d2bb7ead5e38ff1874217b Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Wed, 3 Dec 2025 15:06:31 +0100 Subject: [PATCH 14/22] vrtsim: rewrite sample history Limit sample history to 256 samples and copy it into each channel modelling task instead of relying on globally available buffer. This simplifies the code and addressing into the saved samples buffer as well as enabling further optimizations without sacrificing thread safety. --- radio/vrtsim/vrtsim.c | 55 ++++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/radio/vrtsim/vrtsim.c b/radio/vrtsim/vrtsim.c index 9e678a5305..01589797d0 100644 --- a/radio/vrtsim/vrtsim.c +++ b/radio/vrtsim/vrtsim.c @@ -54,7 +54,7 @@ typedef enum { ROLE_SERVER = 1, ROLE_CLIENT } role; #define MAX_NUM_ANTENNAS_TX 4 -#define MAX_CHANNEL_LENGTH (1 << 20) +#define SAVED_SAMPLES_LEN 256 #define ROLE_CLIENT_STRING "client" #define ROLE_SERVER_STRING "server" @@ -125,9 +125,6 @@ typedef struct { int client_num_rx_antennas; } vrtsim_state_t; -// Sample history for channel impulse response -static c16_t saved_samples[MAX_NUM_ANTENNAS_TX][MAX_CHANNEL_LENGTH] __attribute__((aligned(32))) = {0}; - static void histogram_add(histogram_t *histogram, double diff) { histogram->num_samples++; @@ -375,6 +372,7 @@ typedef struct { int nbAnt; int flags; int aarx; + c16_t saved_samples[MAX_NUM_ANTENNAS_TX][SAVED_SAMPLES_LEN]; } channel_modelling_args_t; static void perform_channel_modelling(void *arg) @@ -418,14 +416,13 @@ static void perform_channel_modelling(void *arg) } for (int aatx = 0; aatx < nb_tx_ant; aatx++) { - c16_t *previous_samples = saved_samples[aatx]; for (int i = 0; i < nsamps; i++) { cf_t *impulse_response = channel_impulse_response_p[aatx]; for (int l = 0; l < channel_desc->channel_length; l++) { int idx = i - l; // TODO: Use AVX2 for this c16_t tx_input = idx >= 0 ? input_samples[aatx][idx] - : previous_samples[(channel_modelling_args->timestamp + i + idx) % MAX_CHANNEL_LENGTH]; + : channel_modelling_args->saved_samples[aatx][SAVED_SAMPLES_LEN + idx]; samples[i].r += tx_input.r * impulse_response[l].r - tx_input.i * impulse_response[l].i; samples[i].i += tx_input.i * impulse_response[l].r + tx_input.r * impulse_response[l].i; } @@ -469,6 +466,11 @@ static int vrtsim_write_with_chanmod(vrtsim_state_t *vrtsim_state, int nbAnt, int flags) { + // Sample history for channel impulse response + static c16_t saved_samples[MAX_NUM_ANTENNAS_TX][SAVED_SAMPLES_LEN] __attribute__((aligned(32))) = {0}; + // Indicates what samples are saves in saved_samples + static openair0_timestamp last_timestamp = 0; + AssertFatal(nbAnt < MAX_NUM_ANTENNAS_TX, "Number of antennas %d exceeds maximum %d\n", nbAnt, MAX_NUM_ANTENNAS_TX); for (int aarx = 0; aarx < vrtsim_state->peer_info.num_rx_antennas; aarx++) { notifiedFIFO_elt_t *task = newNotifiedFIFO_elt(sizeof(channel_modelling_args_t), 0, NULL, perform_channel_modelling); @@ -482,25 +484,40 @@ static int vrtsim_write_with_chanmod(vrtsim_state_t *vrtsim_state, for (int i = 0; i < nbAnt; i++) { args->samples[i] = samplesVoid[i]; } + + // Fill in saved_samples + size_t gap_samples = timestamp - last_timestamp; + if (gap_samples > 0) { + size_t gap_samples_needed = min(SAVED_SAMPLES_LEN, gap_samples); + for (int aatx = 0; aatx < nbAnt; aatx++) { + memset(&args->saved_samples[aatx][SAVED_SAMPLES_LEN - gap_samples_needed], 0, sizeof(c16_t) * gap_samples_needed); + if (gap_samples < SAVED_SAMPLES_LEN) { + size_t samples_from_saved = SAVED_SAMPLES_LEN - gap_samples_needed; + memcpy(&args->saved_samples[aatx][0], &saved_samples[aatx][SAVED_SAMPLES_LEN - samples_from_saved], sizeof(c16_t) * samples_from_saved); + } + } + } else { + for (int aatx = 0; aatx < nbAnt; aatx++) + memcpy(&args->saved_samples[aatx][0], saved_samples[aatx], sizeof(c16_t) * SAVED_SAMPLES_LEN); + } + memcpy(args->saved_samples, saved_samples, sizeof(saved_samples)); pushNotifiedFIFO(&vrtsim_state->channel_modelling_actors[aarx].fifo, task); } - int start_index = timestamp % MAX_CHANNEL_LENGTH; - int end_index = min(start_index + nsamps, MAX_CHANNEL_LENGTH); - int cp_nsamps = end_index - start_index; - for (int aatx = 0; aatx < nbAnt; aatx++) { - c16_t *samples = (c16_t *)samplesVoid[aatx]; - memcpy(&saved_samples[aatx][start_index], &samples[0], sizeof(c16_t) * cp_nsamps); - } - if (end_index < start_index + nsamps) { - // wrap around condition, write at beginning of buffer - cp_nsamps = nsamps - cp_nsamps; // remaining samples - start_index = 0; + // Save samples for next round + if (nsamps < SAVED_SAMPLES_LEN) { for (int aatx = 0; aatx < nbAnt; aatx++) { - c16_t *samples = (c16_t *)samplesVoid[aatx]; - memcpy(&saved_samples[aatx][start_index], &samples[0], sizeof(c16_t) * cp_nsamps); + memmove(&saved_samples[aatx][0], &saved_samples[aatx][nsamps], sizeof(c16_t) * (SAVED_SAMPLES_LEN - nsamps)); + memcpy(&saved_samples[aatx][SAVED_SAMPLES_LEN - nsamps], samplesVoid[aatx], sizeof(c16_t) * nsamps); + } + } else { + for (int aatx = 0; aatx < nbAnt; aatx++) { + c16_t* samples = (c16_t*)samplesVoid[aatx]; + memcpy(saved_samples[aatx], &samples[nsamps - SAVED_SAMPLES_LEN], sizeof(c16_t) * (SAVED_SAMPLES_LEN)); } } + + last_timestamp = timestamp + nsamps; return nsamps; } From 8f116f68d2aaa062a8ac9467701f4d7d9465e20f Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Wed, 3 Dec 2025 15:09:19 +0100 Subject: [PATCH 15/22] vrtsim: fix assert for number of TX antennas --- radio/vrtsim/vrtsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/vrtsim/vrtsim.c b/radio/vrtsim/vrtsim.c index 01589797d0..ae47a4d370 100644 --- a/radio/vrtsim/vrtsim.c +++ b/radio/vrtsim/vrtsim.c @@ -471,7 +471,7 @@ static int vrtsim_write_with_chanmod(vrtsim_state_t *vrtsim_state, // Indicates what samples are saves in saved_samples static openair0_timestamp last_timestamp = 0; - AssertFatal(nbAnt < MAX_NUM_ANTENNAS_TX, "Number of antennas %d exceeds maximum %d\n", nbAnt, MAX_NUM_ANTENNAS_TX); + AssertFatal(nbAnt <= MAX_NUM_ANTENNAS_TX, "Number of antennas %d exceeds maximum %d\n", nbAnt, MAX_NUM_ANTENNAS_TX); for (int aarx = 0; aarx < vrtsim_state->peer_info.num_rx_antennas; aarx++) { notifiedFIFO_elt_t *task = newNotifiedFIFO_elt(sizeof(channel_modelling_args_t), 0, NULL, perform_channel_modelling); channel_modelling_args_t *args = (channel_modelling_args_t *)NotifiedFifoData(task); From 9d3670eefd553c5205562d54a26cb8cd45e4ca81 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Wed, 3 Dec 2025 15:25:44 +0100 Subject: [PATCH 16/22] vrtsim: Enable batch processing in perform_channel_modelling In perfrom_channel_modelling, do convolution in batches which allows vrtsim to write the channel samples as they are being produced instead of waiting for the last sample in the slot to be ready. --- radio/vrtsim/vrtsim.c | 88 ++++++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 38 deletions(-) diff --git a/radio/vrtsim/vrtsim.c b/radio/vrtsim/vrtsim.c index ae47a4d370..f47c865fcc 100644 --- a/radio/vrtsim/vrtsim.c +++ b/radio/vrtsim/vrtsim.c @@ -372,6 +372,8 @@ typedef struct { int nbAnt; int flags; int aarx; + int batch_size; + int num_batches; c16_t saved_samples[MAX_NUM_ANTENNAS_TX][SAVED_SAMPLES_LEN]; } channel_modelling_args_t; @@ -415,48 +417,55 @@ static void perform_channel_modelling(void *arg) } } - for (int aatx = 0; aatx < nb_tx_ant; aatx++) { - for (int i = 0; i < nsamps; i++) { - cf_t *impulse_response = channel_impulse_response_p[aatx]; - for (int l = 0; l < channel_desc->channel_length; l++) { - int idx = i - l; - // TODO: Use AVX2 for this - c16_t tx_input = idx >= 0 ? input_samples[aatx][idx] - : channel_modelling_args->saved_samples[aatx][SAVED_SAMPLES_LEN + idx]; - samples[i].r += tx_input.r * impulse_response[l].r - tx_input.i * impulse_response[l].i; - samples[i].i += tx_input.i * impulse_response[l].r + tx_input.r * impulse_response[l].i; + for (int batch_index = 0; batch_index < channel_modelling_args->num_batches; batch_index++) { + int start_sample = batch_index * channel_modelling_args->batch_size; + int num_samples = min(channel_modelling_args->batch_size, nsamps - start_sample); + if (start_sample >= nsamps) { + break; + } + for (int aatx = 0; aatx < nb_tx_ant; aatx++) { + for (int i = start_sample; i < start_sample + num_samples; i++) { + cf_t *impulse_response = channel_impulse_response_p[aatx]; + for (int l = 0; l < channel_desc->channel_length; l++) { + int idx = i - l; + // TODO: Use AVX2 for this + c16_t tx_input = idx >= 0 ? input_samples[aatx][idx] + : channel_modelling_args->saved_samples[aatx][SAVED_SAMPLES_LEN + idx]; + samples[i].r += tx_input.r * impulse_response[l].r - tx_input.i * impulse_response[l].i; + samples[i].i += tx_input.i * impulse_response[l].r + tx_input.r * impulse_response[l].i; + } } } - } - // Convert to c16_t - c16_t samples_out[aligned_nsamps] __attribute__((aligned(64))); -#if defined(__AVX512F__) - for (int i = 0; i < aligned_nsamps / 8; i++) { - simde__m512 *in = (simde__m512 *)&samples[i * 8]; - simde__m256i *out = (simde__m256i *)&samples_out[i * 8]; - *out = simde_mm512_cvtsepi32_epi16(simde_mm512_cvtps_epi32(*in)); - } -#elif defined(__AVX2__) - for (int i = 0; i < aligned_nsamps / 4; i++) { - simde__m256 *in = (simde__m256 *)&samples[i * 4]; - simde__m128i *out = (simde__m128i *)&samples_out[i * 4]; - *out = simde_mm256_cvtsepi32_epi16(simde_mm256_cvtps_epi32(*in)); - } -#else - for (int i = 0; i < nsamps; i++) { - samples_out[i].r = lroundf(samples[i].r); - samples_out[i].i = lroundf(samples[i].i); - } -#endif + // Convert to c16_t + c16_t samples_out[aligned_nsamps] __attribute__((aligned(64))); + #if defined(__AVX512F__) + for (int i = 0; i < aligned_nsamps / 8; i++) { + simde__m512 *in = (simde__m512 *)&samples[i * 8]; + simde__m256i *out = (simde__m256i *)&samples_out[i * 8]; + *out = simde_mm512_cvtsepi32_epi16(simde_mm512_cvtps_epi32(*in)); + } + #elif defined(__AVX2__) + for (int i = 0; i < aligned_nsamps / 4; i++) { + simde__m256 *in = (simde__m256 *)&samples[i * 4]; + simde__m128i *out = (simde__m128i *)&samples_out[i * 4]; + *out = simde_mm256_cvtsepi32_epi16(simde_mm256_cvtps_epi32(*in)); + } + #else + for (int i = 0; i < nsamps; i++) { + samples_out[i].r = lroundf(samples[i].r); + samples_out[i].i = lroundf(samples[i].i); + } + #endif - vrtsim_write_internal(channel_modelling_args->vrtsim_state, - channel_modelling_args->timestamp, - samples_out, - channel_modelling_args->nsamps, - aarx, - channel_modelling_args->flags, - aarx); + vrtsim_write_internal(channel_modelling_args->vrtsim_state, + channel_modelling_args->timestamp, + samples_out, + channel_modelling_args->nsamps, + aarx, + channel_modelling_args->flags, + aarx); + } } static int vrtsim_write_with_chanmod(vrtsim_state_t *vrtsim_state, @@ -470,6 +479,7 @@ static int vrtsim_write_with_chanmod(vrtsim_state_t *vrtsim_state, static c16_t saved_samples[MAX_NUM_ANTENNAS_TX][SAVED_SAMPLES_LEN] __attribute__((aligned(32))) = {0}; // Indicates what samples are saves in saved_samples static openair0_timestamp last_timestamp = 0; + const int batch_size = 4096; AssertFatal(nbAnt <= MAX_NUM_ANTENNAS_TX, "Number of antennas %d exceeds maximum %d\n", nbAnt, MAX_NUM_ANTENNAS_TX); for (int aarx = 0; aarx < vrtsim_state->peer_info.num_rx_antennas; aarx++) { @@ -481,6 +491,8 @@ static int vrtsim_write_with_chanmod(vrtsim_state_t *vrtsim_state, args->nbAnt = nbAnt; args->flags = flags; args->aarx = aarx; + args->batch_size = batch_size; + args->num_batches = (nsamps + batch_size - 1) / batch_size; for (int i = 0; i < nbAnt; i++) { args->samples[i] = samplesVoid[i]; } From b9665aac5f0a739f0bd17ca6c52813e158fd8d8f Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 3 Nov 2025 19:05:39 +0100 Subject: [PATCH 17/22] vrtsim CI testcase with channel modelling Add vrtsim CI testcase with channel modelling. --- .../gnb.sa.band78.106prb.vrtsim.2x2.yaml | 209 ++++++++++++++++++ .../conf_files/nrue.vrtsim.chanmod.yaml | 20 ++ .../xml_files/container_5g_vrtsim_chanmod.xml | 140 ++++++++++++ .../5g_vrtsim_chanmod/docker-compose.yaml | 163 ++++++++++++++ 4 files changed, 532 insertions(+) create mode 100644 ci-scripts/conf_files/gnb.sa.band78.106prb.vrtsim.2x2.yaml create mode 100644 ci-scripts/conf_files/nrue.vrtsim.chanmod.yaml create mode 100644 ci-scripts/xml_files/container_5g_vrtsim_chanmod.xml create mode 100644 ci-scripts/yaml_files/5g_vrtsim_chanmod/docker-compose.yaml diff --git a/ci-scripts/conf_files/gnb.sa.band78.106prb.vrtsim.2x2.yaml b/ci-scripts/conf_files/gnb.sa.band78.106prb.vrtsim.2x2.yaml new file mode 100644 index 0000000000..5cca2b0718 --- /dev/null +++ b/ci-scripts/conf_files/gnb.sa.band78.106prb.vrtsim.2x2.yaml @@ -0,0 +1,209 @@ +Active_gNBs: + - gnb-rfsim +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity: none +gNBs: + ##### Identification parameters: + - gNB_ID: 0xe00 + gNB_name: gnb-rfsim + tracking_area_code: 1 + plmn_list: + - mcc: 208 + mnc: 99 + mnc_length: 2 + snssaiList: + - sst: 1 + sd: 0xffffff + nr_cellid: 12345678 + ##### Physical parameters: + min_rxtxtime: 6 + pusch_AntennaPorts: 2 + pdsch_AntennaPorts_XP: 2 + + servingCellConfigCommon: + #spCellConfigCommon + - physCellId: 0 + # downlinkConfigCommon + #frequencyInfoDL + # this is 3300.60 MHz + 53*12*30e-3 MHz = 3319.68 + absoluteFrequencySSB: 621312 + # this is 3300.60 MHz + dl_absoluteFrequencyPointA: 620040 + #scs-SpecificCarrierList + dl_offstToCarrier: 0 + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing: 1 + dl_carrierBandwidth: 106 + #initialDownlinkBWP + #genericParameters + # this is RBstart=0,L=106 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth: 28875 + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing: 1 + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero: 11 + initialDLBWPsearchSpaceZero: 0 + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand: 78 + #scs-SpecificCarrierList + ul_offstToCarrier: 0 + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing: 1 + ul_carrierBandwidth: 106 + pMax: 20 + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth: 28875 + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing: 1 + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex: 98 + #prach_msg1_FDM + #0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM: 0 + prach_msg1_FrequencyStart: 0 + zeroCorrelationZoneConfig: 12 + preambleReceivedTargetPower: -104 + #preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax: 6 + #powerRampingStep + # 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep: 1 + #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR + #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR: 4 + #one (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB: 15 + #ra_ContentionResolutionTimer + #(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer: 7 + rsrp_ThresholdSSB: 19 + #prach-RootSequenceIndex_PR + #1 = 839, 2 = 139 + prach_RootSequenceIndex_PR: 2 + prach_RootSequenceIndex: 1 + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + msg1_SubcarrierSpacing: 1 + # restrictedSetConfig + # 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig: 0 + msg3_DeltaPreamble: 1 + p0_NominalWithGrant: -90 + + # pucch-ConfigCommon setup : + # pucchGroupHopping + # 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping: 0 + hoppingId: 40 + p0_nominal: -90 + ssb_PositionsInBurst_Bitmap: 1 + # ssb_periodicityServingCell + # 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell: 2 + + # dmrs_TypeA_position + # 0 = pos2, 1 = pos3 + dmrs_TypeA_Position: 0 + + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing: 1 + + #tdd-UL-DL-ConfigurationCommon + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing: 1 + + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity: 6 + nrofDownlinkSlots: 7 + nrofDownlinkSymbols: 6 + nrofUplinkSlots: 2 + nrofUplinkSymbols: 4 + ssPBCH_BlockPower: -25 + SCTP: + SCTP_INSTREAMS: 2 + SCTP_OUTSTREAMS: 2 + + ##### AMF parameters: + amf_ip_address: + - ipv4: 192.168.71.132 + + NETWORK_INTERFACES: + GNB_IPV4_ADDRESS_FOR_NG_AMF: 192.168.71.140 + GNB_IPV4_ADDRESS_FOR_NGU: 192.168.71.140 + GNB_PORT_FOR_S1U: 2152 # Spec 2152 + + +MACRLCs: + - num_cc: 1 + tr_s_preference: local_L1 + tr_n_preference: local_RRC + pusch_TargetSNRx10: 200 + pucch_TargetSNRx10: 200 + +L1s: + - num_cc: 1 + tr_n_preference: local_mac + prach_dtx_threshold: 200 + # pucch0_dtx_threshold = 150; + +RUs: + - local_rf: yes + nb_tx: 2 + nb_rx: 2 + att_tx: 0 + att_rx: 0 + bands: [78] + max_pdschReferenceSignalPower: -27 + max_rxgain: 75 + eNB_instances: [0] + sf_extension: 0 + +security: + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms: [nea0] + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms: [nia2, nia0] + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering: yes + drb_integrity: no + +log_config: + global_log_level: info + hw_log_level: info + phy_log_level: info + mac_log_level: info + rlc_log_level: info + pdcp_log_level: info + rrc_log_level: info + ngap_log_level: debug + f1ap_log_level: debug + + +channelmod: + max_chan: 10 + modellist: DefaultChannelList + DefaultChannelList: + - model_name: server_tx_channel_model + type: AWGN + ploss_dB: 0 + noise_power_dB: -100 + forgetfact: 0 + offset: 0 + ds_tdl: 0 diff --git a/ci-scripts/conf_files/nrue.vrtsim.chanmod.yaml b/ci-scripts/conf_files/nrue.vrtsim.chanmod.yaml new file mode 100644 index 0000000000..a9488007d7 --- /dev/null +++ b/ci-scripts/conf_files/nrue.vrtsim.chanmod.yaml @@ -0,0 +1,20 @@ +uicc0: + imsi: 208990100001100 + key: fec86ba6eb707ed08905757b1bb44b8f + opc: C42449363BBAD02B66D16BC975D77CC1 + dnn: oai + nssai_sst: 1 + +thread-pool: "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1" + +channelmod: + max_chan: 10; + modellist: DefaultChannelList + DefaultChannelList: + - model_name: client_tx_channel_model + type: AWGN + ploss_dB: 0 + noise_power_dB: -100 + forgetfact: 0 + offset: 0 + ds_tdl: 0 diff --git a/ci-scripts/xml_files/container_5g_vrtsim_chanmod.xml b/ci-scripts/xml_files/container_5g_vrtsim_chanmod.xml new file mode 100644 index 0000000000..6bd16eff1f --- /dev/null +++ b/ci-scripts/xml_files/container_5g_vrtsim_chanmod.xml @@ -0,0 +1,140 @@ + + + vrtsim-5gnr-chanmod + Monolithic gNB vrtsim + chanmod + wrench + + 111111 + 800813 + 000011 + 000012 + 000013 + 020011 + 020012 + 030011 + 030012 + 100011 + 222222 + + + + + Pull_Local_Registry + Pull Images from Local Registry + localhost + oai-gnb oai-nr-ue + + + Create_Workspace + Create new Workspace + localhost + + + Deploy_Object + Deploy OAI 5G CoreNetwork + localhost + ci-scripts/yaml_files/5g_vrtsim_chanmod + mysql oai-amf oai-smf oai-upf oai-ext-dn + + + + Deploy_Object + Deploy OAI 5G gNB+UE RF sim SA + localhost + ci-scripts/yaml_files/5g_vrtsim_chanmod + oai-gnb oai-nr-ue + + + + Attach_UE + Attach OAI UE (Wait for IP) + rfsim5g_ue + localhost + + + + Ping + Ping ext-dn from NR-UE + rfsim5g_ue + localhost + rfsim5g_ext_dn + localhost + -c 20 -i 0.25 + 5 + + + + Ping + Ping NR-UE from ext-dn + rfsim5g_ext_dn + localhost + rfsim5g_ue + localhost + -c 20 -i 0.25 + 5 + + + + Iperf + Iperf (DL/3Mbps/UDP)(20 sec) + -u -b 3M -t 20 -R + rfsim5g_ue + localhost + rfsim5g_ext_dn + localhost + 5 + 90 + + + + Iperf + Iperf (UL/1Mbps/UDP)(20 sec) + -u -b 1M -t 20 + rfsim5g_ue + localhost + rfsim5g_ext_dn + localhost + 5 + 90 + + + + Undeploy_Object + true + Undeploy all OAI 5G stack + localhost + ci-scripts/yaml_files/5g_vrtsim_chanmod + 1,0,0,0 + 1,0,0,0 + + + + Clean_Test_Server_Images + true + Clean Test Images on Test Server + localhost + oai-gnb oai-nr-ue + + + diff --git a/ci-scripts/yaml_files/5g_vrtsim_chanmod/docker-compose.yaml b/ci-scripts/yaml_files/5g_vrtsim_chanmod/docker-compose.yaml new file mode 100644 index 0000000000..bff7807f22 --- /dev/null +++ b/ci-scripts/yaml_files/5g_vrtsim_chanmod/docker-compose.yaml @@ -0,0 +1,163 @@ +services: + mysql: + container_name: "rfsim5g-mysql" + image: mysql:8.0 + init: true + volumes: + - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql + - ../5g_rfsimulator/mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh + environment: + - TZ=Europe/Paris + - MYSQL_DATABASE=oai_db + - MYSQL_USER=test + - MYSQL_PASSWORD=test + - MYSQL_ROOT_PASSWORD=linux + healthcheck: + test: /bin/bash -c "/tmp/mysql-healthcheck.sh" + interval: 10s + timeout: 5s + start_period: 10s + start_interval: 500ms + retries: 30 + networks: + public_net: + ipv4_address: 192.168.71.131 + oai-amf: + container_name: "rfsim5g-oai-amf" + image: oaisoftwarealliance/oai-amf:v2.1.10 + environment: + - TZ=Europe/paris + volumes: + - ../5g_rfsimulator/mini_nonrf_config.yaml:/openair-amf/etc/config.yaml + depends_on: + - mysql + networks: + public_net: + ipv4_address: 192.168.71.132 + oai-smf: + container_name: "rfsim5g-oai-smf" + image: oaisoftwarealliance/oai-smf:v2.1.10 + environment: + - TZ=Europe/Paris + volumes: + - ../5g_rfsimulator/mini_nonrf_config.yaml:/openair-smf/etc/config.yaml + depends_on: + - oai-amf + networks: + public_net: + ipv4_address: 192.168.71.133 + oai-upf: + container_name: "rfsim5g-oai-upf" + image: oaisoftwarealliance/oai-upf:v2.1.10 + init: true + environment: + - TZ=Europe/Paris + volumes: + - ../5g_rfsimulator/mini_nonrf_config.yaml:/openair-upf/etc/config.yaml + depends_on: + - oai-smf + cap_add: + - NET_ADMIN + - SYS_ADMIN + cap_drop: + - ALL + privileged: true + networks: + public_net: + ipv4_address: 192.168.71.134 + interface_name: eth0 + traffic_net: + ipv4_address: 192.168.72.134 + interface_name: eth1 + oai-ext-dn: + privileged: true + container_name: rfsim5g-oai-ext-dn + image: oaisoftwarealliance/trf-gen-cn5g:focal + init: true + entrypoint: /bin/bash -c \ + "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ + "ip route add 12.1.1.0/24 via 192.168.72.134 dev eth0; sleep infinity" + depends_on: + - oai-upf + networks: + traffic_net: + ipv4_address: 192.168.72.135 + healthcheck: + test: /bin/bash -c "ping -c 2 192.168.72.134" + interval: 10s + timeout: 5s + retries: 5 + start_period: 10s + start_interval: 500ms + oai-gnb: + image: ${REGISTRY-oaisoftwarealliance/}${GNB_IMG:-oai-gnb}:${TAG:-develop} + container_name: rfsim5g-oai-gnb + cap_drop: + - ALL + environment: + USE_ADDITIONAL_OPTIONS: -E --log_config.global_log_options level,nocolor,time --device.name vrtsim --vrtsim.role server --vrtsim.chanmod 1 + depends_on: + - oai-ext-dn + networks: + public_net: + ipv4_address: 192.168.71.140 + volumes: + - ../../conf_files/gnb.sa.band78.106prb.vrtsim.2x2.yaml:/opt/oai-gnb/etc/gnb.yaml + - tmp_data:/tmp/ + healthcheck: + test: /bin/bash -c "pgrep nr-softmodem" + interval: 10s + timeout: 5s + start_period: 10s + start_interval: 500ms + retries: 5 + ipc: host + oai-nr-ue: + image: ${REGISTRY-oaisoftwarealliance/}${NRUE_IMG:-oai-nr-ue}:${TAG:-develop} + container_name: rfsim5g-oai-nr-ue + cap_drop: + - ALL + cap_add: + - NET_ADMIN # for interface bringup + - NET_RAW # for ping + environment: + USE_ADDITIONAL_OPTIONS: -E -r 106 --numerology 1 --band 78 -C 3619200000 --ssb 516 --uicc0.imsi 208990100001100 --log_config.global_log_options level,nocolor,time --device.name vrtsim + depends_on: + - oai-gnb + networks: + public_net: + ipv4_address: 192.168.71.150 + devices: + - /dev/net/tun:/dev/net/tun + volumes: + - ../../conf_files/nrue.vrtsim.chanmod.yaml:/opt/oai-nr-ue/etc/nr-ue.yaml + - tmp_data:/tmp/ + healthcheck: + test: /bin/bash -c "pgrep nr-uesoftmodem" + interval: 10s + timeout: 5s + retries: 5 + start_period: 10s + start_interval: 500ms + ipc: host + +networks: + public_net: + driver: bridge + name: rfsim5g-oai-public-net + ipam: + config: + - subnet: 192.168.71.128/26 + driver_opts: + com.docker.network.bridge.name: "rfsim5g-public" + traffic_net: + driver: bridge + name: rfsim5g-oai-traffic-net + ipam: + config: + - subnet: 192.168.72.128/26 + driver_opts: + com.docker.network.bridge.name: "rfsim5g-traffic" + +volumes: + tmp_data: From 4ac445ac30fad7f80a2f4c1b046cda31d70c20c0 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Wed, 17 Dec 2025 08:47:52 +0100 Subject: [PATCH 18/22] vrtsim: add randominit() call This is required with the updated gaussZiggurat call. --- radio/vrtsim/vrtsim.c | 1 + 1 file changed, 1 insertion(+) diff --git a/radio/vrtsim/vrtsim.c b/radio/vrtsim/vrtsim.c index f47c865fcc..2b40f2f05d 100644 --- a/radio/vrtsim/vrtsim.c +++ b/radio/vrtsim/vrtsim.c @@ -659,6 +659,7 @@ static int vrtsim_set_freq(openair0_device *device, openair0_config_t *openair0_ __attribute__((__visibility__("default"))) int device_init(openair0_device *device, openair0_config_t *openair0_cfg) { + randominit(); vrtsim_state_t *vrtsim_state = calloc_or_fail(1, sizeof(vrtsim_state_t)); vrtsim_readconfig(vrtsim_state); LOG_I(HW, From a44fb9bcf8a0f814e76f38ee44661b050100becd Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Tue, 9 Dec 2025 18:49:10 +0000 Subject: [PATCH 19/22] Change trf-gen-cn5g version for tests on GH trf-gen-cn5g:latest is available on OAI DockerHub for linux/arm64, trf-gen-cn5g:focal is only for linux/amd64 --- ci-scripts/yaml_files/5g_vrtsim_chanmod/docker-compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-scripts/yaml_files/5g_vrtsim_chanmod/docker-compose.yaml b/ci-scripts/yaml_files/5g_vrtsim_chanmod/docker-compose.yaml index bff7807f22..503161fc62 100644 --- a/ci-scripts/yaml_files/5g_vrtsim_chanmod/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_vrtsim_chanmod/docker-compose.yaml @@ -72,7 +72,7 @@ services: oai-ext-dn: privileged: true container_name: rfsim5g-oai-ext-dn - image: oaisoftwarealliance/trf-gen-cn5g:focal + image: oaisoftwarealliance/trf-gen-cn5g:latest init: true entrypoint: /bin/bash -c \ "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ From 60f6137d6cff4c1ced8bdb05ad9e8def5c4507be Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Mon, 1 Dec 2025 13:40:53 +0000 Subject: [PATCH 20/22] Add XML file for running vrtsim on ARM --- .../container_5g_vrtsim_chanmod_gh.xml | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 ci-scripts/xml_files/container_5g_vrtsim_chanmod_gh.xml diff --git a/ci-scripts/xml_files/container_5g_vrtsim_chanmod_gh.xml b/ci-scripts/xml_files/container_5g_vrtsim_chanmod_gh.xml new file mode 100644 index 0000000000..3d3fd6ee59 --- /dev/null +++ b/ci-scripts/xml_files/container_5g_vrtsim_chanmod_gh.xml @@ -0,0 +1,141 @@ + + + vrtsim-5gnr-chanmod-gh + Monolithic gNB vrtsim + chanmod + wrench + + 111111 + 800813 + 000011 + 000012 + 000013 + 020011 + 020012 + 030011 + 030012 + 100011 + 222222 + + + + + Pull_Local_Registry + Pull Images from Local Registry + localhost + oai-gnb oai-nr-ue + arm_ + + + Create_Workspace + Create new Workspace + localhost + + + Deploy_Object + Deploy OAI 5G CoreNetwork + localhost + ci-scripts/yaml_files/5g_vrtsim_chanmod + mysql oai-amf oai-smf oai-upf oai-ext-dn + + + + Deploy_Object + Deploy OAI 5G gNB+UE RF sim SA + localhost + ci-scripts/yaml_files/5g_vrtsim_chanmod + oai-gnb oai-nr-ue + + + + Attach_UE + Attach OAI UE (Wait for IP) + rfsim5g_ue + localhost + + + + Ping + Ping ext-dn from NR-UE + rfsim5g_ue + localhost + rfsim5g_ext_dn + localhost + -c 20 -i 0.25 + 5 + + + + Ping + Ping NR-UE from ext-dn + rfsim5g_ext_dn + localhost + rfsim5g_ue + localhost + -c 20 -i 0.25 + 5 + + + + Iperf + Iperf (DL/3Mbps/UDP)(30 sec) + -u -b 3M -t 30 -R + rfsim5g_ue + localhost + rfsim5g_ext_dn + localhost + 5 + 90 + + + + Iperf + Iperf (UL/1Mbps/UDP)(30 sec) + -u -b 1M -t 30 + rfsim5g_ue + localhost + rfsim5g_ext_dn + localhost + 5 + 90 + + + + Undeploy_Object + true + Undeploy all OAI 5G stack + localhost + ci-scripts/yaml_files/5g_vrtsim_chanmod + 1,0,0,0 + 1,0,0,0 + + + + Clean_Test_Server_Images + true + Clean Test Images on Test Server + localhost + oai-gnb oai-nr-ue + + + From ee4dc21f25279b9db4d7905d1e8a5e23dd442209 Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Wed, 17 Dec 2025 13:50:06 +0100 Subject: [PATCH 21/22] CI: Add VRT-Sim test pipeline to parent pipeline --- ci-scripts/Jenkinsfile-GitLab-Container | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/ci-scripts/Jenkinsfile-GitLab-Container b/ci-scripts/Jenkinsfile-GitLab-Container index a2bb8112fc..e395973b25 100644 --- a/ci-scripts/Jenkinsfile-GitLab-Container +++ b/ci-scripts/Jenkinsfile-GitLab-Container @@ -380,6 +380,29 @@ pipeline { } } } + stage ("VRT-Sim-Test-5G") { + when { expression {do5Gtest || do5GUeTest} } + steps { + script { + triggerSlaveJob ('RAN-VRT-Sim-Test-5G', 'VRT-Sim-Test-5G') + } + } + post { + always { + script { + // Using a unique variable name for each test stage to avoid overwriting on a global variable + // due to parallel-time concurrency + vrtSim5GStatus = finalizeSlaveJob('RAN-VRT-Sim-Test-5G') + } + } + failure { + script { + currentBuild.result = 'FAILURE' + failingStages += vrtSim5GStatus + } + } + } + } stage ("RF-Sim-Test-5G") { when { expression {do5Gtest || do5GUeTest} } steps { From bf347a62d4d0209734acb5d0e7e1d8f4ba993793 Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Thu, 18 Dec 2025 16:07:12 +0100 Subject: [PATCH 22/22] CI: adjust UE attach timeout handling - Set default attach_timeout to 40s - Increase timeout only after failed attach attempts This modification addresses an issue in the RFSim-5G 2x2 test where the UE often fails to attach within the initial 20s window. The timeout may cause the UE to restart, which leads to two UEs appearing in the gNB log. By increasing the initial timeout to 40s, we avoid unnecessary restarts. --- ci-scripts/cls_module.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci-scripts/cls_module.py b/ci-scripts/cls_module.py index 17d45828c8..a82e2050b9 100644 --- a/ci-scripts/cls_module.py +++ b/ci-scripts/cls_module.py @@ -111,11 +111,10 @@ class Module_UE: return self._collectTrace(ctx) return None - def attach(self, attach_tries = 3, attach_timeout = 0): + def attach(self, attach_tries = 3, attach_timeout = 40): ip = None while attach_tries > 0: self._command(self.cmd_dict["attach"]) - attach_timeout += 20 timeout = attach_timeout logging.debug("Waiting for IP address to be assigned") ip = self.getIP(silent=False, reportNonZero=True) @@ -126,6 +125,7 @@ class Module_UE: if ip: break logging.warning(f"UE did not receive IP address after {attach_timeout} s, detaching") + attach_timeout += 20 attach_tries -= 1 self._command(self.cmd_dict["detach"]) time.sleep(5)