diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md index 274866b8dd..8882b18875 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: @@ -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 ##### RU configuration diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index 617243b0fd..283116d3da 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -178,25 +178,25 @@ 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; 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; @@ -208,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; @@ -235,21 +235,20 @@ 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 } // 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]); 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; + }; + }); +};