From e0f95f2344cb72f04b51edfb1a8f88ec62839148 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teodora=20Vladi=C4=87?= Date: Thu, 5 Mar 2026 10:54:54 +0100 Subject: [PATCH 1/3] [FHI72] Add verified Benetel FW versions Note: RAN550-1v1.4.1-M-25fa970 verified with both CUS and CUSM. At this stage, RAN550-1v2.0.5-M-92a9d2c verified with CUS only. --- doc/ORAN_FHI7.2_Tutorial.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md index c90f9c72a5..95dc3b96d4 100644 --- a/doc/ORAN_FHI7.2_Tutorial.md +++ b/doc/ORAN_FHI7.2_Tutorial.md @@ -61,8 +61,8 @@ We tested the category A radio units listed below. |-----------------|---------------------------------------------| |VVDN LPRU |03-v3.0.5 | |LiteON RU |01.00.08/02.00.03/02.00.10 | -|Benetel 650 |RAN650-1v1.0.4-dda1bf5|RAN650-1v1.2.2-2fa04bc| -|Benetel 550 |RAN550-1v1.0.4-605a25a|RAN550-1v1.2.2-2fa04bc| +|Benetel 650 |RAN650-1v1.0.4-dda1bf5/RAN650-1v1.2.2-2fa04bc/RAN650-1v1.4.2-NM-c48047d| +|Benetel 550 |RAN550-1v1.0.4-605a25a/RAN550-1v1.2.2-2fa04bc/RAN550-1v1.4.1-M-25fa970/RAN550-1v2.0.5-M-92a9d2c| |Foxconn RPQN |v3.1.15q.551_rc10 | Tested libxran releases: From 63b048b2ff647d63df52a8bd92dee0502fc770b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teodora=20Vladi=C4=87?= Date: Wed, 4 Mar 2026 17:08:51 +0100 Subject: [PATCH 2/3] [FHI72] Refactor PRACH code Move PRACH slot checking from oaioran.c to oran_isolate.c because xran_is_prach_slot() compared the current slot instead of the scheduled. The current and the scheduled slot are the same in case of short format, but different in case of format 0. Therefore, with this commit, in xran_is_prach_slot() we check the `prach_id->slot` and not `slot`. --- radio/fhi_72/oaioran.c | 14 ++------------ radio/fhi_72/oran_isolate.c | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index 617243b0fd..24adfe50b2 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -182,21 +182,11 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot) int prach_end_sym = prach_info.N_dur + prach_start_sym; struct xran_ru_config *ru_conf = &fh_cfg->ru_conf; int slots_per_frame = 10 << fh_cfg->frame_conf.nNumerology; - int slots_per_subframe = 1 << fh_cfg->frame_conf.nNumerology; - int tti = slots_per_frame * (frame) + (slot); - uint32_t subframe = slot / slots_per_subframe; - // PRACH occasion in a frame if and only if SFN % x == y, TS 38.211 Table 6.3.3.2-2/3/4 - uint32_t is_prach_frame = (frame % prach_info.x == prach_info.y); - uint32_t is_prach_slot = is_prach_frame && xran_is_prach_slot(0, subframe, (slot % slots_per_subframe)); int nb_rx_per_ru = ru->nb_rx / fh_init->xran_ports; /* If it is PRACH slot, copy prach IQ from XRAN PRACH buffer to OAI PRACH buffer */ - if (is_prach_slot) { - if (!ru->prach_buf) { - LOG_W(HW, "we get rach data from ru, but it is not scheduled %d.%d\n", frame, slot); - return -1; - } + if (ru->prach_buf) { for (sym_idx = prach_start_sym; sym_idx < prach_end_sym; sym_idx++) { for (int aa = 0; aa < ru->nb_rx; aa++) { int16_t *dst, *src; @@ -249,7 +239,7 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot) } // COMPMETHOD_BLKFLOAT } // aa } // symb_indx - } // is_prach_slot + } // ru->prach_buf return (0); } diff --git a/radio/fhi_72/oran_isolate.c b/radio/fhi_72/oran_isolate.c index d19d2c1f00..1881eae163 100644 --- a/radio/fhi_72/oran_isolate.c +++ b/radio/fhi_72/oran_isolate.c @@ -213,16 +213,31 @@ int trx_oran_ctlrecv(openair0_device_t *device, void *msg, ssize_t msg_len) void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot) { - prach_item_t *prach_id = find_nr_prach(&ru->gNB_list[0]->prach_list, *frame, *slot, SEARCH_EXIST); ru_info_t ru_info = { .nb_rx = ru->nb_rx * ru->num_beams_period, .nb_tx = ru->nb_tx * ru->num_beams_period, .rxdataF = ru->common.rxdataF, .beam_id = ru->common.beam_id, .num_beams_period = ru->num_beams_period, - .prach_buf = prach_id ? prach_id->rxsigF : NULL, + .prach_buf = NULL, }; + prach_item_t *prach_id = find_nr_prach(&ru->gNB_list[0]->prach_list, *frame, *slot, SEARCH_EXIST); + if (prach_id) { + struct xran_fh_config *fh_cfg = get_xran_fh_config(0); + int slots_per_subframe = 1 << fh_cfg->frame_conf.nNumerology; + uint32_t subframe = *slot / slots_per_subframe; // `slot` = slot in which PRACH is received + // PRACH occasion in a frame if and only if SFN % x == y, TS 38.211 Table 6.3.3.2-2/3/4 + nr_prach_info_t prach_info = get_prach_info(0); + bool is_prach_frame = (*frame % prach_info.x == prach_info.y); + bool is_prach_slot = is_prach_frame && xran_is_prach_slot(0, subframe, (prach_id->slot % slots_per_subframe)); // `prach_id->slot` = slot in which PRACH is scheduled + if (is_prach_slot) { + ru_info.prach_buf = prach_id->rxsigF; + } else { + LOG_W(HW, "[%d.%d] Expected PRACH reception of scheduled slot %d\n", *frame, *slot, prach_id->slot); + } + } + RU_proc_t *proc = &ru->proc; int f, sl; LOG_D(HW, "Read rxdataF %p,%p\n", ru_info.rxdataF[0], ru_info.rxdataF[1]); From 141690c780794819d5577c56cde5aa899dd1a17f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teodora=20Vladi=C4=87?= Date: Wed, 4 Mar 2026 18:08:20 +0100 Subject: [PATCH 3/3] [FHI72] Handle long PRACH format Only static long PRACH configuration verified, i.e. PRACH C-plane is ignored by the RU. Note: Introducing `N_ZC` and `num_prbu` parameters is needed for testing with xran F release. However, in the K release, this information is stored in xran_rx_packet_ctl struct. --- doc/ORAN_FHI7.2_Tutorial.md | 9 + radio/fhi_72/oaioran.c | 27 +- ...73prb.fhi72.2x2-benetel550-long-prach.conf | 273 ++++++++++++++++++ 3 files changed, 300 insertions(+), 9 deletions(-) create mode 100644 targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.2x2-benetel550-long-prach.conf diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md index 95dc3b96d4..80f3fa7d3c 100644 --- a/doc/ORAN_FHI7.2_Tutorial.md +++ b/doc/ORAN_FHI7.2_Tutorial.md @@ -563,6 +563,15 @@ flexran_prach_workaround=disabled dl_tuning_special_slot=0x13b6 ``` +In addition, PRACH format 0 is also verified with FW v2.0.5. An example gNB config file can be found at [`gnb.sa.band77.273prb.fhi72.2x2-benetel550-long-prach.conf`](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.2x2-benetel550-long-prach.conf). On the RU side, the following parameters shall be modified: +```bash +mimo_mode=1_3 +prach_format=long +prach_freq_offset_dynamic=false +lf_prach_compression_enable=true +lf_prach_slot_id=0 +``` + #### LITEON The OAI configuration file [`gnb.sa.band78.273prb.fhi72.4x4-liteon.conf`](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-liteon.conf) corresponds to: diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index 24adfe50b2..283116d3da 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -178,6 +178,16 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot) struct xran_fh_config *fh_cfg = get_xran_fh_config(0); nr_prach_info_t prach_info = get_prach_info(0); + uint16_t N_ZC, num_prbu; + if ((prach_info.format & 0xff) < 4) { + N_ZC = 839; + num_prbu = 70; + prach_info.N_dur = 1; + } else { + N_ZC = 139; + num_prbu = 12; + } + int prach_start_sym = prach_info.start_symbol; int prach_end_sym = prach_info.N_dur + prach_start_sym; struct xran_ru_config *ru_conf = &fh_cfg->ru_conf; @@ -198,25 +208,25 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot) /* convert Network order to host order */ if (ru_conf->compMeth_PRACH == XRAN_COMPMETHOD_NONE) { if (sym_idx == prach_start_sym) { - for (idx = 0; idx < 139 * 2; idx++) { + for (idx = 0; idx < N_ZC * 2; idx++) { dst[idx] = ((int16_t)ntohs(src[idx + g_kbar])); } } else { - for (idx = 0; idx < 139 * 2; idx++) { + for (idx = 0; idx < N_ZC * 2; idx++) { dst[idx] += ((int16_t)ntohs(src[idx + g_kbar])); } } } else if (ru_conf->compMeth_PRACH == XRAN_COMPMETHOD_BLKFLOAT) { - int16_t local_dst[12 * 2 * N_SC_PER_PRB] __attribute__((aligned(64))); + int16_t local_dst[num_prbu * 2 * N_SC_PER_PRB] __attribute__((aligned(64))); #if defined(__i386__) || defined(__x86_64__) struct xranlib_decompress_request bfp_decom_req = {}; struct xranlib_decompress_response bfp_decom_rsp = {}; - int payload_len = (3 * ru_conf->iqWidth_PRACH + 1) * 12; // 12 = closest number of PRBs to 139 REs + int payload_len = (3 * ru_conf->iqWidth_PRACH + 1) * num_prbu; bfp_decom_req.data_in = (int8_t *)src; - bfp_decom_req.numRBs = 12; // closest number of PRBs to 139 REs + bfp_decom_req.numRBs = num_prbu; bfp_decom_req.len = payload_len; bfp_decom_req.compMethod = XRAN_COMPMETHOD_BLKFLOAT; bfp_decom_req.iqWidth = ru_conf->iqWidth_PRACH; @@ -225,16 +235,15 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot) bfp_decom_rsp.len = 0; xranlib_decompress_avx512(&bfp_decom_req, &bfp_decom_rsp); #elif defined(__arm__) || defined(__aarch64__) - armral_bfp_decompression(ru_conf->iqWidth_PRACH, 12, (int8_t *)src, (int16_t *)local_dst); + armral_bfp_decompression(ru_conf->iqWidth_PRACH, num_prbu, (int8_t *)src, (int16_t *)local_dst); #else AssertFatal(1 == 0, "BFP decompression not supported on this architecture"); #endif - // note: this is hardwired for 139 point PRACH sequence, kbar=2 if (sym_idx == prach_start_sym) - for (idx = 0; idx < (139 * 2); idx++) + for (idx = 0; idx < (N_ZC * 2); idx++) dst[idx] = local_dst[idx + g_kbar]; else - for (idx = 0; idx < (139 * 2); idx++) + for (idx = 0; idx < (N_ZC * 2); idx++) dst[idx] += (local_dst[idx + g_kbar]); } // COMPMETHOD_BLKFLOAT } // aa diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.2x2-benetel550-long-prach.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.2x2-benetel550-long-prach.conf new file mode 100644 index 0000000000..ae356fb689 --- /dev/null +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.2x2-benetel550-long-prach.conf @@ -0,0 +1,273 @@ +Active_gNBs = ( "gNB-OAI"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + gNB_name = "gNB-OAI"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ( { sst = 1; }); }); + + nr_cellid = 1; + + ////////// Physical parameters: + + pdsch_AntennaPorts_XP = 2; + pdsch_AntennaPorts_N1 = 1; + maxMIMO_layers = 2; + pusch_AntennaPorts = 2; + do_CSIRS = 1; + do_SRS = 0; + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + # n_TimingAdvanceOffset = 0; +# downlinkConfigCommon + #frequencyInfoDL + # center frequency = 3950.4 MHz + # selected SSB frequency = 3950.4 MHz + absoluteFrequencySSB = 663360; + dl_frequencyBand = 77; + # frequency point A = 3901.26 MHz + dl_absoluteFrequencyPointA = 660084; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 273; + #initialDownlinkBWP + #genericParameters + initialDLBWPlocationAndBandwidth = 1099; #38.101-1 Table 5.3.2-1 + # +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 11; + initialDLBWPsearchSpaceZero = 0; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 77; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 273; + pMax = 23; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 1099; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 7; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 0; + preambleReceivedTargetPower = -100; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 8; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 3; +#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 = 3; +#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 = 1; + 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, + +# this is the offset between the last PRACH preamble power and the Msg3 PUSCH, 2 times the field value in dB + msg3_DeltaPreamble = 2; + p0_NominalWithGrant = -96; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 0; + p0_nominal = -96; + + ssb_PositionsInBurst_Bitmap = 0x1; + +# 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 = -15; + } + ); + + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// AMF parameters: + amf_ip_address = ({ ipv4 = "172.21.6.5";}); + + NETWORK_INTERFACES : + { + GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.130"; + GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.130"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + } +); + +MACRLCs = ( +{ + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + pusch_TargetSNRx10 = 180; + pucch_TargetSNRx10 = 180; +# dl_bler_target_upper = .35; +# dl_bler_target_lower = .15; +# ul_bler_target_upper = .35; +# ul_bler_target_lower = .15; + pusch_FailureThres = 100; + ul_max_mcs = 28; +} +); + +L1s = ( +{ + num_cc = 1; + tr_n_preference = "local_mac"; + prach_dtx_threshold = 100; + pucch0_dtx_threshold = 10; + pusch_dtx_threshold = 10; + max_ldpc_iterations = 15; + tx_amp_backoff_dB = 12; # needs to match O-RU configuration + L1_rx_thread_core = 6; + L1_tx_thread_core = 7; + phase_compensation = 0; # needs to match O-RU configuration +} +); + +RUs = ( +{ + local_rf = "no"; + nb_tx = 2; + nb_rx = 2; + att_tx = 0; + att_rx = 0; + bands = [77]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 75; + sf_extension = 0; + eNB_instances = [0]; + ru_thread_core = 8; + sl_ahead = 5; + tr_preference = "raw_if4p5"; # important: activate FHI7.2 + do_precoding = 0; # needs to match O-RU configuration +} +); + +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 = "info"; + f1ap_log_level = "info"; +}; + +fhi_72 = { + dpdk_devices = ("0000:6f:01.0"); + system_core = 9; + io_core = 10; + worker_cores = (11); + ru_addr = ("8c:1f:64:d1:11:1e"); + mtu = 9216; + fh_config = ({ + T1a_cp_dl = (419, 470); + T1a_cp_ul = (285, 336); + T1a_up = (294, 345); + Ta4 = (0, 831); + ru_config = { + iq_width = 9; + iq_width_prach = 9; + }; + prach_config = { + eAxC_offset = 8; + }; + }); +};