Compare commits

...

8 Commits

Author SHA1 Message Date
Bartosz Podrygajlo
3691075e05 Add a function which loads the specified radio library 2025-07-24 16:11:37 +02:00
Bartosz Podrygajlo
53ade4237f A sync method for TX 2025-07-24 16:06:17 +02:00
Bartosz Podrygajlo
594117e451 Add memif conf files 2025-07-23 14:32:18 +02:00
Bartosz Podrygajlo
2d1d3b88a4 O-RU thread function
Added a new O-RU thread for reading DL IQ from xran lib.
Added a new OAI ORAN lib function for reading DL IQ data.
2025-07-23 12:02:20 +02:00
Mario Joa-Ng
da5789a613 Use no of fh_config in configuration file to determine the number of peers
Determine number of DU for RU config file or no of RU for DU config file
based on number of fh_config elements.
2025-07-23 12:01:29 +02:00
Mario Joa-Ng
8adf30b17d remove duplicate fields in oran-params.h due to rebase 2025-07-23 12:01:29 +02:00
Mario Joa-Ng
b4f9d80f16 Fix a segfault in RU.
RU invokes nr_ru_init_frame_parms() that configures
tdd_table.max_tdd_periodicity_list for one TDD period only.
It does not account for the number of periods per frame.
Change nr_ru_init_frame_parms() as in set_tdd_config_nr()
that account for the number of periods per frame.
2025-07-23 12:01:29 +02:00
Raymond Knopp
b556eb848b initial implementation of O-RU for 7.2 emulator 2025-07-23 12:01:29 +02:00
24 changed files with 1294 additions and 70 deletions

View File

@@ -607,6 +607,11 @@ include_directories("${OPENAIR_DIR}")
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/common/utils/T
${CMAKE_CURRENT_BINARY_DIR}/common/utils/T)
include_directories(${OPENAIR_DIR}/common/utils/barrier)
include_directories(${OPENAIR_DIR}/common/utils/actor)
include_directories(${OPENAIR_DIR}/common/utils/threadPool)
# set the T_LIB name to T if the target exists, otherwise leave empty
set(T_LIB $<TARGET_NAME_IF_EXISTS:T>)
@@ -1781,9 +1786,6 @@ target_link_libraries(oairu PRIVATE
SCHED_RU_LIB PHY_COMMON PHY_RU UTIL shlib_loader
-Wl,--end-group z dl)
target_link_libraries(oairu PRIVATE pthread m CONFIG_LIB rt ${T_LIB})
target_link_libraries(oairu PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
# force the generation of ASN.1 so that we don't need to wait during the build
target_link_libraries(lte-softmodem PRIVATE
asn1_lte_rrc asn1_s1ap asn1_m2ap asn1_m3ap asn1_x2ap)
@@ -1822,6 +1824,30 @@ target_link_libraries(lte-uesoftmodem PRIVATE ${blas_LIBRARIES} ${cblas_LIBRARIE
target_link_libraries(lte-uesoftmodem PRIVATE
asn1_lte_rrc asn1_s1ap asn1_m2ap asn1_m3ap asn1_x2ap)
# nr RRU
add_executable(oainr_ru
${OPENAIR_DIR}/executables/nr-ru.c
${OPENAIR_DIR}/openair1/PHY/INIT/nr_parms.c
${OPENAIR_DIR}/openair1/SCHED_NR/phy_frame_config_nr.c
${OPENAIR_DIR}/openair1/PHY/INIT/nr_parms.c
${OPENAIR_DIR}/openair1/SCHED_NR/nr_prach_procedures.c
${OPENAIR_DIR}/openair1/SCHED/phy_procedures_lte_common.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_prach.c
${OPENAIR_DIR}/common/utils/nr/nr_common.c
${OPENAIR_DIR}/radio/COMMON/common_lib.c
${OPENAIR_DIR}/radio/COMMON/record_player.c
${OPENAIR_DIR}/executables/softmodem-common.c
${OPENAIR_DIR}/executables/main_nr_ru.c
)
target_link_libraries(oainr_ru PRIVATE
-Wl,--start-group
UTIL SCHED_RU_LIB PHY_COMMON PHY_RU shlib_loader
-Wl,--end-group z dl)
target_link_libraries(oainr_ru PRIVATE pthread m CONFIG_LIB rt ${T_LIB} utils
barrier actor)
target_link_libraries(oainr_ru PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs nr_phy_common time_management)
target_link_libraries(oainr_ru PUBLIC MAC_NR_COMMON)
# nr-softmodem
###################################################

View File

@@ -87,6 +87,8 @@ Options:
Makes the NR softmodem
--RU
Makes the OAI RRU
--nrRU
Makes the OAI nrRRU
--UE
Makes the UE specific parts (usim, nvram) from the given configuration file
--nrUE
@@ -242,6 +244,11 @@ function main() {
TARGET_LIST="$TARGET_LIST oairu"
echo_info "Will compile RRU"
shift;;
--nrRU)
nrRU=1
TARGET_LIST="$TARGET_LIST oainr_ru"
echo_info "Will compile nrRRU"
shift;;
--UE)
UE=1
TARGET_LIST="$TARGET_LIST lte-uesoftmodem"
@@ -492,7 +499,7 @@ function main() {
if [[ $TARGET_LIST != "" ]] && [[ -f $OPENAIR_DIR/CMakeLists.txt ]]; then
# add some default libraries that should always be built
# for eNB, gNB, UEs, simulators
if [[ $gNB == 1 || $eNB == 1 || $UE == 1 || $nrUE == 1 || $SIMUS_PHY == 1 || $RU == 1 ]]; then
if [[ $gNB == 1 || $eNB == 1 || $UE == 1 || $nrUE == 1 || $SIMUS_PHY == 1 || $RU == 1 || $nrRU == 1 ]]; then
TARGET_LIST="$TARGET_LIST params_libconfig coding rfsimulator dfts params_yaml vrtsim"
fi

221
executables/main_nr_ru.c Normal file
View File

@@ -0,0 +1,221 @@
/*
* 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
*/
/*! \file oairu.c
* \brief Top-level threads for radio-unit
* \author R. Knopp
* \date 2020
* \version 0.1
* \company Eurecom
* \email: knopp@eurecom.fr
* \note
* \warning
*/
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <sched.h>
#include "assertions.h"
#include "PHY/types.h"
#include "PHY/defs_RU.h"
#include "common/oai_version.h"
#include "common/config/config_userapi.h"
#include "common/utils/load_module_shlib.h"
#include "common/ran_context.h"
#include "radio/COMMON/common_lib.h"
#include "radio/ETHERNET/if_defs.h"
#include "PHY/phy_vars.h"
#include "PHY/phy_extern.h"
#include "PHY/TOOLS/phy_scope_interface.h"
#include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
//#include "PHY/INIT/phy_init.h"
#include "openair2/ENB_APP/enb_paramdef.h"
#include "system.h"
#include "nfapi/oai_integration/vendor_ext.h"
#include <executables/softmodem-common.h>
#include <executables/thread-common.h>
pthread_cond_t sync_cond;
pthread_mutex_t sync_mutex;
int sync_var=-1; //!< protected by mutex \ref sync_mutex.
int config_sync_var=-1;
int oai_exit = 0;
int sf_ahead = 4;
int emulate_rf = 0;
RAN_CONTEXT_t RC;
extern void kill_NR_RU_proc(int inst);
extern void set_function_spec_param(RU_t *ru);
extern void start_NR_RU(RU_t *ru);
extern void init_NR_RU(configmodule_interface_t *cfg, char *);
int32_t uplink_frequency_offset[MAX_NUM_CCs][4];
void nfapi_setmode(nfapi_mode_t nfapi_mode) { return; }
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert) {
if (s != NULL) {
printf("%s:%d %s() Exiting OAI softmodem: %s\n",file,line, function, s);
}
close_log_mem();
oai_exit = 1;
RU_t *ru = RC.ru[0];
if (ru->rfdevice.trx_end_func) {
ru->rfdevice.trx_end_func(&ru->rfdevice);
ru->rfdevice.trx_end_func = NULL;
}
if (ru->ifdevice.trx_end_func) {
ru->ifdevice.trx_end_func(&ru->ifdevice);
ru->ifdevice.trx_end_func = NULL;
}
pthread_mutex_destroy(ru->ru_mutex);
pthread_cond_destroy(ru->ru_cond);
if (assert) {
abort();
} else {
sleep(1); // allow lte-softmodem threads to exit first
exit(EXIT_SUCCESS);
}
}
static void get_options(configmodule_interface_t *cfg)
{
CONFIG_SETRTFLAG(CONFIG_NOEXITONHELP);
get_common_options(cfg);
CONFIG_CLEARRTFLAG(CONFIG_NOEXITONHELP);
// NRCConfig();
}
nfapi_mode_t nfapi_getmode(void) {
return(NFAPI_MODE_PNF);
}
void oai_nfapi_rach_ind(nfapi_rach_indication_t *rach_ind) {
AssertFatal(1==0,"This is bad ... please check why we get here\n");
}
void wait_eNBs(void){ return; }
void wait_gNBs(void){ return; }
struct timespec timespec_add(struct timespec,struct timespec) {struct timespec t={0}; return t;};
struct timespec timespec_sub(struct timespec,struct timespec) {struct timespec t={0}; return t;};
void perform_symbol_rotation(NR_DL_FRAME_PARMS *fp, double f0, c16_t *symbol_rotation) {return;}
void init_timeshift_rotation(NR_DL_FRAME_PARMS *fp) {return;};
int beam_index_allocation(int fapi_beam_index, NR_gNB_COMMON *common_vars, int slot, int symbols_per_slot, int bitmap_symbols) {int i=0; return i;};
void nr_fill_du(uint16_t N_ZC, const uint16_t *prach_root_sequence_map, uint16_t nr_du[NR_PRACH_SEQ_LEN_L - 1]) {return;};
uint16_t nr_du[838];
uint64_t downlink_frequency[MAX_NUM_CCs][4];
configmodule_interface_t *uniqCfg = NULL;
THREAD_STRUCT thread_struct;
void oru_init(ORU_t *oru);
void *oru_north_read_thread(void *arg);
void *oru_south_read_thread(void *arg);
int main ( int argc, char **argv )
{
memset(&RC,0,sizeof(RC));
if ((uniqCfg = load_configmodule(argc, argv, 0)) == NULL) {
exit_fun("[SOFTMODEM] Error, configuration module init failed\n");
}
logInit();
printf("Reading in command-line options\n");
get_options(uniqCfg);
if (CONFIG_ISFLAGSET(CONFIG_ABORT) ) {
fprintf(stderr,"Getting configuration failed\n");
exit(-1);
}
#if T_TRACER
T_Config_Init();
#endif
printf("configuring for RRU\n");
// strdup to put the sring in the core file for post mortem identification
LOG_I(HW, "Version: %s\n", strdup(OAI_PACKAGE_VERSION));
/* Read configuration */
printf("About to Init RU threads\n");
lock_memory_to_ram();
RC.nb_RU=1;
RC.ru = malloc(sizeof(RC.ru));
init_NR_RU(config_get_if(),NULL);
load_dftslib();
RU_t *ru = RC.ru[0];
ORU_t oru;
oru.ru = ru;
oru_init(&oru);
pthread_create(&oru.north_read_thread, NULL, oru_north_read_thread, (void *)&oru);
pthread_create(&oru.south_read_thread, NULL, oru_south_read_thread, (void *)&oru);
while (oai_exit==0) sleep(1);
// stop threads
kill_NR_RU_proc(0);
end_configmodule(uniqCfg);
if (ru->rfdevice.trx_end_func) {
ru->rfdevice.trx_end_func(&ru->rfdevice);
ru->rfdevice.trx_end_func = NULL;
}
if (ru->ifdevice.trx_end_func) {
ru->ifdevice.trx_end_func(&ru->ifdevice);
ru->ifdevice.trx_end_func = NULL;
}
logClean();
printf("Bye.\n");
return 0;
}

View File

@@ -56,6 +56,8 @@ static int DEFBANDS[] = {7};
static int DEFENBS[] = {0};
static int DEFBFW[] = {0x00007fff};
static int DEFRUTPCORES[] = {-1,-1,-1,-1};
static int DEFBW[] = {273};
static int DEFCARRIER[] = {3430560};
#include "ENB_APP/enb_paramdef.h"
#include "GNB_APP/gnb_paramdef.h"
@@ -68,6 +70,7 @@ static int DEFRUTPCORES[] = {-1,-1,-1,-1};
#include "nfapi_interface.h"
#include <nfapi/oai_integration/vendor_ext.h>
#include "executables/nr-softmodem-common.h"
#include "common/utils/load_module_shlib.h"
static void NRRCconfig_RU(configmodule_interface_t *cfg);
@@ -187,7 +190,7 @@ int connect_rau(RU_t *ru) {
break;
default:
AssertFatal(1==0,"RU_function is unknown %d\n",RC.ru[0]->function);
AssertFatal(1==0,"RU_function is unknown %d\n",ru->function);
break;
}
@@ -238,7 +241,7 @@ int connect_rau(RU_t *ru) {
// southbound IF5 fronthaul for 16-bit OAI format
void fh_if5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) {
if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
int offset = ru->nr_frame_parms->get_samples_slot_timestamp(slot,ru->nr_frame_parms,0);
void *buffs[ru->nb_tx];
for (int aid = 0; aid < ru->nb_tx; aid++)
@@ -260,7 +263,7 @@ void fh_if5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) {
void fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) {
nfapi_nr_config_request_scf_t *cfg = &ru->config;
if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
LOG_D(PHY,"Sending IF4p5 for frame %d subframe %d\n",ru->proc.frame_tx,ru->proc.tti_tx);
@@ -377,7 +380,7 @@ void fh_if4p5_south_in(RU_t *ru,
*slot = proc->tti_rx;
}
if (ru == RC.ru[0]) {
if (ru->idx == 0) {
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_RU, f );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_RX0_RU, sl);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, proc->frame_tx );
@@ -453,7 +456,7 @@ void fh_if4p5_north_in(RU_t *ru,int *frame,int *slot) {
} while (symbol_mask != symbol_mask_full);
// dump VCD output for first RU in list
if (ru == RC.ru[0]) {
if (ru->idx == 0) {
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, *frame );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, *slot );
}
@@ -529,7 +532,7 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *slot) {
LOG_D(PHY,"RU %d/%d TST %llu, frame %d, subframe %d\n",ru->idx,0,(long long unsigned int)proc->timestamp_tx,frame_tx,slot_tx);
// dump VCD output for first RU in list
if (ru == RC.ru[0]) {
if (ru->idx == 0) {
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, frame_tx );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, slot_tx );
}
@@ -572,7 +575,7 @@ void *emulatedRF_thread(void *param) {
int microsec = 500; // length of time to sleep, in miliseconds
struct timespec req = {0};
req.tv_sec = 0;
req.tv_nsec = (numerology>0)? ((microsec * 1000L)/numerology):(microsec * 1000L)*2;
req.tv_nsec = (proc->ru->numerology>0)? ((microsec * 1000L)/proc->ru->numerology):(microsec * 1000L)*2;
wait_sync("emulatedRF_thread");
while(!oai_exit) {
@@ -655,7 +658,7 @@ static void rx_rf(RU_t *ru, int *frame, int *slot)
proc->frame_rx,proc->tti_rx,proc->tti_tx,fp->slots_per_frame);
// dump VCD output for first RU in list
if (ru == RC.ru[0]) {
if (ru->idx == 0) {
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_RU, proc->frame_rx );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_RX0_RU, proc->tti_rx );
}
@@ -683,7 +686,7 @@ static void rx_rf(RU_t *ru, int *frame, int *slot)
*slot = proc->tti_rx;
}
if (!emulate_rf) {
if (!ru->emulate_rf) {
metadata mt = {.slot = *slot, .frame = *frame};
gNBscopeCopyWithMetadata(ru, gNbTimeDomainSamples, rxp[0], sizeof(c16_t), 1, samples_per_slot, 0, &mt);
}
@@ -1010,7 +1013,7 @@ void ru_tx_func(void *param)
if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm))
ru->feptx_ofdm(ru, frame_tx, slot_tx);
if(!emulate_rf) {
if(!ru->emulate_rf) {
// do outgoing fronthaul (south) if needed
if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out))
ru->fh_south_out(ru, frame_tx, slot_tx, info->timestamp_tx);
@@ -1080,7 +1083,7 @@ static bool wait_free_rx_tti(notifiedFIFO_t *L1_rx_out, bool rx_tti_busy[RU_RX_S
if (!res)
return false;
processingData_L1_t *info = NotifiedFifoData(res);
LOG_D(NR_PHY, "%d.%d Got access to RX slot %d.%d (%d)\n", frame_rx, slot_rx, info->frame_rx, info->slot_rx, idx);
LOG_I(NR_PHY, "%d.%d Got access to RX slot %d.%d (%d)\n", frame_rx, slot_rx, info->frame_rx, info->slot_rx, idx);
rx_tti_busy[info->slot_rx % RU_RX_SLOT_DEPTH] = false;
if ((info->slot_rx % RU_RX_SLOT_DEPTH) == idx)
not_done = false;
@@ -1119,7 +1122,7 @@ void *ru_thread(void *param)
fill_rf_config(ru, ru->rf_config_file);
fill_split7_2_config(&ru->openair0_cfg.split7, &ru->config, fp->slots_per_frame, fp->ofdm_symbol_size);
if(!emulate_rf) {
if(!ru->emulate_rf) {
// Start IF device if any
if (ru->nr_start_if) {
LOG_I(PHY, "starting transport\n");
@@ -1181,7 +1184,7 @@ void *ru_thread(void *param)
pthread_mutex_unlock(&RC.ru_mutex);
wait_sync("ru_thread");
if(!emulate_rf) {
if(!ru->emulate_rf) {
// Start RF device if any
if (ru->start_rf) {
if (ru->start_rf(ru) != 0)
@@ -1370,7 +1373,7 @@ void init_RU_proc(RU_t *ru) {
pthread_mutex_init( &proc->mutex_emulateRF,NULL);
pthread_cond_init( &proc->cond_emulateRF, NULL);
if(emulate_rf)
if(ru->emulate_rf)
threadCreate( &proc->pthread_emulateRF, emulatedRF_thread, (void *)proc, "emulateRF", -1, OAI_PRIORITY_RT );
LOG_I(PHY, "Initialized RU proc %d (%s,%s),\n", ru->idx, NB_functions[ru->function], NB_timing[ru->if_timing]);
}
@@ -1585,6 +1588,7 @@ void set_function_spec_param(RU_t *ru)
reset_meas(&ru->tx_fhaul);
reset_meas(&ru->compression);
reset_meas(&ru->transport);
LOG_I(NR_PHY,"Setting IF4p5 (7.2 split)\n");
} else if (ru->function == gNodeB_3GPP) {
ru->do_prach = 0; // no prach processing in RU
ru->feprx = nr_fep_tp; // this is frequency-shift + DFTs
@@ -1692,9 +1696,10 @@ void init_NR_RU(configmodule_interface_t *cfg, char *rf_config_file)
ru->num_gNB=1;
}
}
gNB_RC = RC.gNB[0];
gNB0 = ru->gNB_list[0];
if (RC.nb_nr_L1_inst > 0) {
gNB_RC = RC.gNB[0];
gNB0 = ru->gNB_list[0];
}
fp = ru->nr_frame_parms;
LOG_D(PHY, "RU FUnction:%d ru->if_south:%d\n", ru->function, ru->if_south);
@@ -1715,6 +1720,9 @@ void init_NR_RU(configmodule_interface_t *cfg, char *rf_config_file)
}
}
}
else {
nr_ru_init_frame_parms(ru);
}
set_function_spec_param(ru);
init_RU_proc(ru);
if (ru->if_south != REMOTE_IF4p5) {
@@ -1742,9 +1750,8 @@ void init_NR_RU(configmodule_interface_t *cfg, char *rf_config_file)
LOG_D(HW,"[nr-softmodem.c] RU threads created\n");
}
void start_NR_RU()
void start_NR_RU(RU_t *ru)
{
RU_t *ru = RC.ru[0];
start_RU_proc(ru);
}
@@ -1854,7 +1861,7 @@ static void NRRCconfig_RU(configmodule_interface_t *cfg)
if (!(config_isparamset(RUParamList.paramarray[j],RU_LOCAL_IF_NAME_IDX))) {
RC.ru[j]->if_south = LOCAL_RF;
RC.ru[j]->function = gNodeB_3GPP;
LOG_D(PHY, "Setting function for RU %d to gNodeB_3GPP\n", j);
LOG_I(NR_PHY, "Setting function for RU %d to gNodeB_3GPP\n", j);
} else {
RC.ru[j]->eth_params.local_if_name = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr));
RC.ru[j]->eth_params.my_addr = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr));
@@ -1868,22 +1875,22 @@ static void NRRCconfig_RU(configmodule_interface_t *cfg)
RC.ru[j]->if_south = LOCAL_RF;
RC.ru[j]->function = NGFI_RRU_IF5;
RC.ru[j]->eth_params.transp_preference = ETH_UDP_MODE;
LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF5 (udp)\n", j);
LOG_I(NR_PHY, "Setting function for RU %d to NGFI_RRU_IF5 (udp)\n", j);
} else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw") == 0) {
RC.ru[j]->if_south = LOCAL_RF;
RC.ru[j]->function = NGFI_RRU_IF5;
RC.ru[j]->eth_params.transp_preference = ETH_RAW_MODE;
LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF5 (raw)\n", j);
LOG_I(NR_PHY, "Setting function for RU %d to NGFI_RRU_IF5 (raw)\n", j);
} else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_if4p5") == 0) {
RC.ru[j]->if_south = LOCAL_RF;
RC.ru[j]->function = NGFI_RRU_IF4p5;
RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF4p5_MODE;
LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF4p5 (udp)\n", j);
LOG_I(NR_PHY, "Setting function for RU %d to NGFI_RRU_IF4p5 (udp)\n", j);
} else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if4p5") == 0) {
RC.ru[j]->if_south = LOCAL_RF;
RC.ru[j]->function = NGFI_RRU_IF4p5;
RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF4p5_MODE;
LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF4p5 (raw)\n", j);
LOG_I(NR_PHY, "Setting function for RU %d to NGFI_RRU_IF4p5 (raw)\n", j);
}
}
@@ -1932,8 +1939,23 @@ static void NRRCconfig_RU(configmodule_interface_t *cfg)
RC.ru[j]->if_freq_offset = *(RUParamList.paramarray[j][RU_IF_FREQ_OFFSET].iptr);
RC.ru[j]->sl_ahead = *(RUParamList.paramarray[j][RU_SL_AHEAD].iptr);
RC.ru[j]->num_bands = RUParamList.paramarray[j][RU_BAND_LIST_IDX].numelt;
for (int i = 0; i < RC.ru[j]->num_bands; i++)
for (int i = 0; i < RC.ru[j]->num_bands; i++) {
RC.ru[j]->band[i] = RUParamList.paramarray[j][RU_BAND_LIST_IDX].iptr[i];
RC.ru[j]->bw_tx[i] = RUParamList.paramarray[j][RU_TX_BW_LIST_IDX].iptr[i];
RC.ru[j]->bw_rx[i] = RUParamList.paramarray[j][RU_RX_BW_LIST_IDX].iptr[i];
RC.ru[j]->carrier_freq_tx[i] = RUParamList.paramarray[j][RU_TX_CARRIER_LIST_IDX].iptr[i];
RC.ru[j]->carrier_freq_rx[i] = RUParamList.paramarray[j][RU_RX_CARRIER_LIST_IDX].iptr[i];
}
RC.ru[j]->frame_type = *(RUParamList.paramarray[j][RU_FRAME_TYPE_IDX].iptr);
RC.ru[j]->prach_config_index = *(RUParamList.paramarray[j][RU_PRACH_CONFIGID_IDX].iptr);
RC.ru[j]->prach_msg1_freq = *(RUParamList.paramarray[j][RU_PRACH_MSG1FREQ_IDX].iptr);
RC.ru[j]->numerology = *(RUParamList.paramarray[j][RU_NUMEROLOGY_IDX].iptr);
RC.ru[j]->tdd_period = *(RUParamList.paramarray[j][RU_TDD_PERIOD_IDX].iptr);
RC.ru[j]->num_DL_slots = *(RUParamList.paramarray[j][RU_NUM_DL_SLOTS_IDX].iptr);
RC.ru[j]->num_UL_slots = *(RUParamList.paramarray[j][RU_NUM_UL_SLOTS_IDX].iptr);
RC.ru[j]->num_DL_symbols = *(RUParamList.paramarray[j][RU_NUM_DL_SYMBOLS_IDX].iptr);
RC.ru[j]->num_UL_symbols = *(RUParamList.paramarray[j][RU_NUM_UL_SYMBOLS_IDX].iptr);
RC.ru[j]->openair0_cfg.nr_flag = *(RUParamList.paramarray[j][RU_NR_FLAG].iptr);
RC.ru[j]->openair0_cfg.nr_band = RC.ru[j]->band[0];
RC.ru[j]->openair0_cfg.nr_scs_for_raster = *(RUParamList.paramarray[j][RU_NR_SCS_FOR_RASTER].iptr);
@@ -1960,3 +1982,180 @@ static void NRRCconfig_RU(configmodule_interface_t *cfg)
return;
}
void oru_init(ORU_t *oru) {
RU_t *ru = oru->ru;
struct NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
nr_init_frame_parms(&ru->config, fp);
nr_dump_frame_parms(fp);
nr_phy_init_RU(ru);
fill_rf_config(ru, ru->rf_config_file);
fill_split7_2_config(&ru->openair0_cfg.split7, &ru->config, fp->slots_per_frame, fp->ofdm_symbol_size);
if (setup_RU_buffers(ru) != 0) {
LOG_E(PHY, "Exiting, cannot initialize RU Buffers\n");
exit(-1);
}
openair0_load(&ru->rfdevice, "vrtsim", &ru->openair0_cfg, NULL);
ru->rfdevice.trx_start_func(&ru->rfdevice);
}
static void oru_tx_slot_processing(RU_t *ru, int frame, int slot, openair0_timestamp tx_timestamp)
{
LOG_I(PHY, "RU %d: Processing frame %d, slot %d\n", ru->idx, frame, slot);
const NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
int slot_type = nr_slot_select(&ru->config, frame, slot % fp->slots_per_frame);
if (slot_type != NR_UPLINK_SLOT) {
for (int i = 0; i < ru->nb_tx; i++) {
apply_nr_rotation_TX(fp,
(c16_t *)ru->common.txdataF_BF[i],
fp->symbol_rotation[0],
slot,
fp->N_RB_DL,
0,
fp->Ncp == EXTENDED ? 12 : 14);
nr_feptx0(ru, slot, 0, 14, i);
}
}
tx_rf(ru, frame, slot, tx_timestamp);
}
void oru_keep_timing(ORU_t *oru, int frame, int slot)
{
if (oru->timing_initialized) {
if (frame < oru->last_frame) {
oru->hfn++;
}
} else {
oru->first_frame = frame;
oru->first_call_timestamp = oru->current_timestamp;
oru->first_slot = slot;
oru->timing_initialized = true;
oru->hfn = 0;
}
oru->last_frame = frame;
}
uint64_t oru_get_timestamp(ORU_t *oru, int frame, int slot)
{
AssertFatal(oru->timing_initialized, "oru_get_timestamp called before timing initialized\n");
const NR_DL_FRAME_PARMS *fp = oru->ru->nr_frame_parms;
int frames_since_first_call = frame - oru->first_frame + oru->hfn * 1024;
openair0_timestamp timestamp = oru->first_call_timestamp + frames_since_first_call * fp->samples_per_frame;
timestamp += fp->get_samples_slot_timestamp(slot, fp, 0) - fp->get_samples_slot_timestamp(oru->first_slot, fp, 0);
return timestamp;
}
void *oru_north_read_thread(void *arg)
{
ORU_t *oru = (ORU_t *)arg;
RU_t *ru = (RU_t *)oru->ru;
char threadname[40];
sprintf(threadname, "oru_thread %u", ru->idx);
int cpu = sched_getcpu();
if (ru->ru_thread_core > -1 && cpu != ru->ru_thread_core) {
/* we start the ru_thread using threadCreate(), which already sets CPU
* affinity; let's force it here again as per feature request #732 */
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(ru->ru_thread_core, &cpuset);
int ret = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
AssertFatal(ret == 0, "Error in pthread_getaffinity_np(): ret: %d, errno: %d", ret, errno);
LOG_I(PHY, "RU %d: manually set CPU affinity to CPU %d\n", ru->idx, ru->ru_thread_core);
}
// Start IF device if any
if (ru->nr_start_if) {
LOG_I(PHY, "starting transport\n");
int ret = openair0_transport_load(&ru->ifdevice, &ru->openair0_cfg, &ru->eth_params);
AssertFatal(ret == 0, "RU %u: openair0_transport_init() ret %d: cannot initialize transport protocol\n", ru->idx, ret);
if (ru->ifdevice.get_internal_parameter != NULL) {
void *t = ru->ifdevice.get_internal_parameter("fh_if4p5_north_in");
if (t != NULL)
ru->fh_north_in = t;
t = ru->ifdevice.get_internal_parameter("fh_if4p5_north_out");
if (t != NULL)
ru->fh_north_out = t;
}
LOG_I(PHY, "Starting IF interface for RU %d, nb_rx %d\n", ru->idx, ru->nb_rx);
AssertFatal(ru->nr_start_if(ru, NULL) == 0, "Could not start the IF device\n");
if (ru->has_ctrl_prt > 0) {
ret = attach_rru(ru);
AssertFatal(ret == 0, "Cannot connect to remote radio\n");
}
} else {
AssertFatal(false, "RU %d: no IF device and no local RF\n", ru->idx);
}
// Start RF device if any
if (ru->start_rf) {
if (ru->start_rf(ru) != 0)
LOG_E(HW, "Could not start the RF device\n");
else
LOG_I(PHY, "RU %d rf device ready\n", ru->idx);
} else
LOG_I(PHY, "RU %d no rf device\n", ru->idx);
LOG_I(PHY, "RU %d RF started cpu_meas_enabled %d\n", ru->idx, cpu_meas_enabled);
// start trx write thread
if (usrp_tx_thread == 1) {
if (ru->start_write_thread) {
if (ru->start_write_thread(ru) != 0) {
LOG_E(HW, "Could not start tx write thread\n");
} else {
LOG_I(PHY, "tx write thread ready\n");
}
}
}
int frame = 0, slot = 0;
while (!oai_exit) {
if (ru->fh_north_in) {
ru->fh_north_in(ru, &frame, &slot);
oru_keep_timing(oru, frame, slot);
oru_tx_slot_processing(ru, frame, slot, oru_get_timestamp(oru, frame, slot));
}
else
AssertFatal(1 == 0, "No fronthaul interface at north port");
}
return NULL;
}
// Just used to obtain timing information for now. Should be used to read samples for RX chain
void *oru_south_read_thread(void *arg)
{
ORU_t *oru = (ORU_t *)arg;
RU_t *ru = (RU_t *)oru->ru;
const int num_samples = 3000;
c16_t void_samples[ru->nb_rx][num_samples];
c16_t *void_samples_ptr[ru->nb_rx];
for (int i = 0; i < ru->nb_rx; i++) {
void_samples_ptr[i] = void_samples[i];
}
while (true) {
if (oru->timing_initialized == false) {
// Keep updating the timestamp until first xran call
openair0_timestamp timestamp;
ru->rfdevice.trx_read_func(
&ru->rfdevice,
&timestamp,
(void **)&void_samples_ptr,
num_samples,
ru->nb_rx);
oru->current_timestamp = timestamp + num_samples;
} else {
openair0_timestamp dummy;
ru->rfdevice.trx_read_func(
&ru->rfdevice,
&dummy,
(void **)&void_samples_ptr,
num_samples,
ru->nb_rx);
}
}
}

View File

@@ -492,7 +492,7 @@ int start_L1L2(module_id_t gnb_id)
init_NR_RU(config_get_if(), NULL);
start_NR_RU();
start_NR_RU(RC.ru[0]);
wait_RUs();
init_eNB_afterRU();
LOG_I(GNB_APP, "Sending sync to all threads\n");
@@ -716,7 +716,7 @@ int main( int argc, char **argv ) {
wait_f1_setup_response();
if (RC.nb_RU > 0)
start_NR_RU();
start_NR_RU(RC.ru[0]);
#ifdef ENABLE_AERIAL
gNB_MAC_INST *nrmac = RC.nrmac[0];

View File

@@ -47,7 +47,7 @@ extern void stop_gNB(int);
// In nr-ru.c
extern void init_NR_RU(configmodule_interface_t *cfg, char *);
extern void init_RU_proc(RU_t *ru);
extern void start_NR_RU(void);
extern void start_NR_RU(RU_t *ru);
extern void stop_RU(int nb_ru);
extern void kill_NR_RU_proc(int inst);
extern void set_function_spec_param(RU_t *ru);

View File

@@ -35,20 +35,23 @@ void nr_phy_init_RU(RU_t *ru)
LOG_D(PHY, "Initializing RU signal buffers (if_south %s) nb_tx %d, nb_rx %d\n", ru_if_types[ru->if_south], ru->nb_tx, ru->nb_rx);
nfapi_nr_config_request_scf_t *cfg = &ru->config;
ru->nb_log_antennas = 0;
for (int n = 0; n < ru->num_gNB; n++) {
if (cfg->carrier_config.num_tx_ant.value > ru->nb_log_antennas)
ru->nb_log_antennas = cfg->carrier_config.num_tx_ant.value;
ru->num_beams_period = 1;
if (ru->num_gNB > 0) {
nfapi_nr_config_request_scf_t *cfg = &ru->config;
ru->nb_log_antennas = 0;
for (int n = 0; n < ru->num_gNB; n++) {
if (cfg->carrier_config.num_tx_ant.value > ru->nb_log_antennas)
ru->nb_log_antennas = cfg->carrier_config.num_tx_ant.value;
}
nfapi_nr_analog_beamforming_ve_t *analog_config = &cfg->analog_beamforming_ve;
ru->num_beams_period = analog_config->analog_bf_vendor_ext.value ? analog_config->num_beams_period_vendor_ext.value : 1;
}
else ru->nb_log_antennas = ru->nb_tx;
// copy configuration from gNB[0] in to RU, assume that all gNB instances sharing RU use the same configuration
// (at least the parts that are needed by the RU, numerology and PRACH)
AssertFatal(ru->nb_log_antennas > 0 && ru->nb_log_antennas < 13, "ru->nb_log_antennas %d ! \n",ru->nb_log_antennas);
nfapi_nr_analog_beamforming_ve_t *analog_config = &cfg->analog_beamforming_ve;
ru->num_beams_period = analog_config->analog_bf_vendor_ext.value ? analog_config->num_beams_period_vendor_ext.value : 1;
int nb_tx_streams = ru->nb_tx * ru->num_beams_period;
int nb_rx_streams = ru->nb_rx * ru->num_beams_period;
LOG_I(NR_PHY, "nb_tx_streams %d, nb_rx_streams %d, num_Beams_period %d\n", nb_tx_streams, nb_rx_streams, ru->num_beams_period);

View File

@@ -286,6 +286,93 @@ uint32_t get_samples_slot_timestamp(int slot, const NR_DL_FRAME_PARMS *fp, unsig
return samp_count;
}
void nr_ru_init_frame_parms(RU_t *ru) {
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
fp->frame_type = ru->frame_type;
ru->config.cell_config.frame_duplex_type.value = ru->frame_type;
ru->config.cell_config.frame_duplex_type.tl.tag = 0x100D;
fp->N_RB_DL = ru->bw_tx[0];
ru->config.ssb_config.scs_common.value=ru->numerology;
ru->config.carrier_config.dl_grid_size[ru->config.ssb_config.scs_common.value].value = ru->bw_tx[0];
fp->N_RB_UL = ru->bw_rx[0];
ru->config.carrier_config.ul_grid_size[ru->config.ssb_config.scs_common.value].value = ru->bw_rx[0];
fp->numerology_index=ru->numerology;
fp->nr_band = ru->band[0];
LOG_I(NR_PHY,"Set RU frame type to %s, N_RB_DL %d, N_RB_UL %d, mu %d\n",ru->frame_type == TDD ? "TDD" : "FDD", ru->bw_tx[0],ru->bw_rx[0],ru->numerology);
set_scs_parameters(fp,fp->numerology_index,ru->bw_tx[0]);
fp->slots_per_frame = 10 * fp->slots_per_subframe;
fp->nb_antennas_rx = ru->nb_rx;
fp->nb_antennas_tx = ru->nb_tx;
fp->symbols_per_slot=14;
fp->samples_per_subframe_wCP = fp->ofdm_symbol_size * fp->symbols_per_slot * fp->slots_per_subframe;
fp->samples_per_frame_wCP = 10 * fp->samples_per_subframe_wCP;
fp->samples_per_slot_wCP = fp->symbols_per_slot*fp->ofdm_symbol_size;
fp->samples_per_slotN0 = (fp->nb_prefix_samples + fp->ofdm_symbol_size) * fp->symbols_per_slot;
fp->samples_per_slot0 = fp->nb_prefix_samples0 + ((fp->symbols_per_slot-1)*fp->nb_prefix_samples) + (fp->symbols_per_slot*fp->ofdm_symbol_size);
fp->samples_per_subframe = (fp->nb_prefix_samples0 + fp->ofdm_symbol_size) * 2 +
(fp->nb_prefix_samples + fp->ofdm_symbol_size) * (fp->symbols_per_slot * fp->slots_per_subframe - 2);
fp->get_samples_per_slot = &get_samples_per_slot;
fp->get_samples_slot_timestamp = &get_samples_slot_timestamp;
fp->get_slot_from_timestamp = &get_slot_from_timestamp;
fp->samples_per_frame = 10 * fp->samples_per_subframe;
fp->freq_range = (ru->carrier_freq_tx[0] < 6e6)? FR1 : FR2;
fp->dl_CarrierFreq = (double)ru->carrier_freq_tx[0] * 1000;
fp->ul_CarrierFreq = (double)ru->carrier_freq_rx[0] * 1000;
fp->Ncp = NORMAL;
// Split 7.2 parameters
ru->config.prach_config.num_prach_fd_occasions.value = 1;
ru->config.prach_config.prach_ConfigurationIndex.value = ru->prach_config_index;
ru->config.prach_config.prach_ConfigurationIndex.tl.tag = 0x1029;
ru->config.prach_config.num_prach_fd_occasions_list = malloc(sizeof(*ru->config.prach_config.num_prach_fd_occasions_list));
ru->config.prach_config.num_prach_fd_occasions_list[0].k1.value = ru->prach_msg1_freq;
if (ru->config.cell_config.frame_duplex_type.value == 1 /* TDD */) {
ru->config.tdd_table.tdd_period.value = ru->tdd_period;
ru->config.tdd_table.tdd_period.tl.tag = 0x1026;
int numb_slots_frame = (1 << ru->numerology) * NR_NUMBER_OF_SUBFRAMES_PER_FRAME;
int numb_period_frame = get_nb_periods_per_frame(ru->tdd_period);
int numb_slots_period = numb_slots_frame / numb_period_frame;
LOG_I(NR_PHY,
"Set TDD Period Configuration: %d periods per frame, %d slots to be configured (%d DL, %d UL)\n",
numb_period_frame,
numb_slots_frame,
ru->num_DL_slots + 1,
ru->num_UL_slots + 1);
ru->config.tdd_table.max_tdd_periodicity_list =
malloc(sizeof(*ru->config.tdd_table.max_tdd_periodicity_list) * (numb_slots_frame));
for (int n = 0; n < numb_slots_frame; n++) {
int s = 0;
int p = n % numb_slots_period;
if (p < ru->num_DL_slots) {
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list =
malloc(sizeof(*ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list)
* NR_NUMBER_OF_SYMBOLS_PER_SLOT);
for (s = 0; s < 14; s++)
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list[s].slot_config.value = 0;
} else if (p == ru->num_DL_slots) {
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list =
malloc(sizeof(*ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list)
* NR_NUMBER_OF_SYMBOLS_PER_SLOT);
for (s = 0; s < ru->num_DL_symbols; s++)
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list[s].slot_config.value = 0;
for (; s < NR_NUMBER_OF_SYMBOLS_PER_SLOT - ru->num_UL_symbols; s++)
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list[s].slot_config.value = 2;
for (; s < NR_NUMBER_OF_SYMBOLS_PER_SLOT; s++)
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list[s].slot_config.value = 1;
} else {
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list =
malloc(sizeof(*ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list)
* NR_NUMBER_OF_SYMBOLS_PER_SLOT);
for (s = 0; s < NR_NUMBER_OF_SYMBOLS_PER_SLOT; s++)
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list[s].slot_config.value = 1;
}
}
}
}
void nr_init_frame_parms(nfapi_nr_config_request_scf_t* cfg, NR_DL_FRAME_PARMS *fp)
{
@@ -339,6 +426,7 @@ void nr_init_frame_parms(nfapi_nr_config_request_scf_t* cfg, NR_DL_FRAME_PARMS *
fp->N_ssb += ((fp->L_ssb >> (63-p)) & 0x01);
fp->print_ue_help_cmdline_log = true;
fp->ofdm_offset_divisor = 8;
}
int nr_init_frame_parms_ue(NR_DL_FRAME_PARMS *fp,

View File

@@ -27,6 +27,7 @@
int nr_get_ssb_start_symbol(const NR_DL_FRAME_PARMS *fp, uint8_t i_ssb);
void nr_init_frame_parms(nfapi_nr_config_request_scf_t *config, NR_DL_FRAME_PARMS *frame_parms);
void nr_ru_init_frame_parms(RU_t *ru);
int nr_init_frame_parms_ue(NR_DL_FRAME_PARMS *frame_parms, fapi_nr_config_request_t *config, uint16_t nr_band);
void nr_init_frame_parms_ue_sa(NR_DL_FRAME_PARMS *frame_parms, uint64_t downlink_frequency, int32_t uplink_frequency_offset, uint8_t mu, uint16_t nr_band);
int nr_init_frame_parms_ue_sl(NR_DL_FRAME_PARMS *fp,

View File

@@ -487,6 +487,30 @@ typedef struct RU_t_s {
int num_bands;
/// band list
int band[MAX_BANDS_PER_RRU];
/// tx carrier
uint64_t carrier_freq_tx[MAX_BANDS_PER_RRU];
/// rx carrier
uint64_t carrier_freq_rx[MAX_BANDS_PER_RRU];
/// tx BW in PRBs
int bw_tx[MAX_BANDS_PER_RRU];
/// rx BW in PRBs
int bw_rx[MAX_BANDS_PER_RRU];
/// 3GPP FRAME Type FDD/TDD
int frame_type;
/// 3GPP PRACH configuration index
int prach_config_index;
/// 3GPP MSG1 Start frequency
int prach_msg1_freq;
/// 3GPP TDD periodicity (0.5 ms, 1 0.625ms, 2 1ms, 3 1.25ms, 4 2ms,5 2.5ms, 6 5ms, 7 10ms, 8 3ms, 9 4ms
int tdd_period;
/// number of DL slots
int num_DL_slots;
/// number of UL slots
int num_UL_slots;
/// number of DL symbols
int num_DL_symbols;
/// number of UL symbols
int num_UL_symbols;
/// number of RX paths on device
int nb_rx;
/// number of TX paths on device
@@ -670,6 +694,18 @@ typedef struct RU_t_s {
void* scopeData;
} RU_t;
typedef struct {
pthread_t north_read_thread;
pthread_t south_read_thread;
RU_t *ru;
openair0_timestamp current_timestamp;
openair0_timestamp first_call_timestamp;
int first_frame;
int first_slot;
int last_frame;
int hfn;
bool timing_initialized;
} ORU_t;
typedef enum {
RAU_tick=0,

View File

@@ -113,6 +113,21 @@ typedef enum {
#define CONFIG_STRING_RU_HALF_SLOT_PARALLELIZATION "half_slot_parallelization"
#define CONFIG_STRING_RU_RU_THREAD_CORE "ru_thread_core"
#define CONFIG_STRING_RU_GPIO_CONTROL "gpio_controller"
#define CONFIG_STRING_RU_TX_BW_LIST "tx_bw"
#define CONFIG_STRING_RU_RX_BW_LIST "rx_bw"
#define CONFIG_STRING_RU_CARRIER_TX_LIST "carrier_tx"
#define CONFIG_STRING_RU_CARRIER_RX_LIST "carrier_rx"
#define CONFIG_STRING_RU_FRAME_TYPE "frame_type"
#define CONFIG_STRING_RU_PRACH_CONFIGID "prach_config_index"
#define CONFIG_STRING_RU_PRACH_MSG1FREQ "prach_msg1_start"
#define CONFIG_STRING_RU_NUMEROLOGY "mu"
#define CONFIG_STRING_RU_TDD_PERIOD "tdd_period"
#define CONFIG_STRING_RU_NUM_DL_SLOTS "num_dl_slots"
#define CONFIG_STRING_RU_NUM_UL_SLOTS "num_ul_slots"
#define CONFIG_STRING_RU_NUM_DL_SYMBOLS "num_dl_symbols"
#define CONFIG_STRING_RU_NUM_UL_SYMBOLS "num_ul_symbols"
#define HLP_RU_SF_AHEAD "LTE TX processing advance"
#define HLP_RU_SL_AHEAD "NR TX processing advance"
@@ -126,6 +141,20 @@ typedef enum {
#define HLP_RU_HALF_SLOT_PARALLELIZATION "run half slots in parallel in RU FEP"
#define HLP_RU_RU_THREAD_CORE "id of core to pin ru_thread, -1 is default"
#define HLP_RU_GPIO_CONTROL "set the GPIO control type for the RU"
#define HLP_RU_TX_BW "set the TX bandwidth list per component carrier"
#define HLP_RU_RX_BW "set the RX bandwidth list per component carrier"
#define HLP_RU_CARRIER_TX "set the TX carrier frequencies per component carrier"
#define HLP_RU_CARRIER_RX "set the RX carrier frequencies per component carrier"
#define HLP_RU_FRAMETYPE "set the Frame type TDD/FDD of all component carriers"
#define HLP_RU_PRACH_CONFIGID "set the PRACH configuration id of all component carriers"
#define HLP_RU_PRACH_MSG1FREQ "set the PRACH MSG1 frequency of all component carriers"
#define HLP_RU_NUMEROLOGY "set the numerology of the RU"
#define HLP_RU_TDD_PERIOD "set the 3GPP TDD periodificty 0-9"
#define HLP_RU_NUM_DL_SLOTS "set the number of DL Slots in TDD"
#define HLP_RU_NUM_UL_SLOTS "set the number of UL Slots in TDD"
#define HLP_RU_NUM_DL_SYMBOLS "set the number of DL symbols in the mixed slot"
#define HLP_RU_NUM_UL_SYMBOLS "set the number of UL symbols in the mixed slot"
#define RU_LOCAL_IF_NAME_IDX 0
#define RU_LOCAL_ADDRESS_IDX 1
@@ -170,6 +199,19 @@ typedef enum {
#define RU_HALF_SLOT_PARALLELIZATION 40
#define RU_RU_THREAD_CORE 41
#define RU_GPIO_CONTROL 42
#define RU_TX_BW_LIST_IDX 43
#define RU_RX_BW_LIST_IDX 44
#define RU_TX_CARRIER_LIST_IDX 45
#define RU_RX_CARRIER_LIST_IDX 46
#define RU_FRAME_TYPE_IDX 47
#define RU_PRACH_CONFIGID_IDX 48
#define RU_PRACH_MSG1FREQ_IDX 49
#define RU_NUMEROLOGY_IDX 50
#define RU_TDD_PERIOD_IDX 51
#define RU_NUM_DL_SLOTS_IDX 52
#define RU_NUM_UL_SLOTS_IDX 53
#define RU_NUM_DL_SYMBOLS_IDX 54
#define RU_NUM_UL_SYMBOLS_IDX 55
/*-----------------------------------------------------------------------------------------------------------------------------------------*/
/* RU configuration parameters */
/* optname helpstr paramflags XXXptr defXXXval type numelt */
@@ -219,6 +261,19 @@ typedef enum {
{CONFIG_STRING_RU_HALF_SLOT_PARALLELIZATION, HLP_RU_HALF_SLOT_PARALLELIZATION, 0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_RU_THREAD_CORE, HLP_RU_RU_THREAD_CORE, 0, .uptr=NULL, .defintval=-1, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_GPIO_CONTROL, HLP_RU_GPIO_CONTROL, 0, .strptr=NULL, .defstrval="generic", TYPE_STRING, 0}, \
{CONFIG_STRING_RU_TX_BW_LIST, HLP_RU_TX_BW, 0, .iptr=NULL, .defintarrayval=DEFBW, TYPE_INTARRAY, 0}, \
{CONFIG_STRING_RU_RX_BW_LIST, HLP_RU_RX_BW, 0, .iptr=NULL, .defintarrayval=DEFBW, TYPE_INTARRAY, 0}, \
{CONFIG_STRING_RU_CARRIER_TX_LIST, HLP_RU_CARRIER_TX, 0, .iptr=NULL, .defintarrayval=DEFCARRIER, TYPE_INTARRAY, 0}, \
{CONFIG_STRING_RU_CARRIER_RX_LIST, HLP_RU_CARRIER_RX, 0, .iptr=NULL, .defintarrayval=DEFCARRIER, TYPE_INTARRAY, 0}, \
{CONFIG_STRING_RU_FRAME_TYPE, HLP_RU_FRAMETYPE, 0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_PRACH_CONFIGID, HLP_RU_PRACH_CONFIGID, 0, .uptr=NULL, .defintval=152, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_PRACH_MSG1FREQ, HLP_RU_PRACH_MSG1FREQ, 0, .uptr=NULL, .defintval=0, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_NUMEROLOGY, HLP_RU_NUMEROLOGY, 0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_TDD_PERIOD, HLP_RU_TDD_PERIOD, 0, .uptr=NULL, .defintval=5, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_NUM_DL_SLOTS, HLP_RU_NUM_DL_SLOTS, 0, .uptr=NULL, .defintval=3, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_NUM_UL_SLOTS, HLP_RU_NUM_UL_SLOTS, 0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_NUM_DL_SYMBOLS, HLP_RU_NUM_DL_SYMBOLS, 0, .uptr=NULL, .defintval=7, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_NUM_UL_SYMBOLS, HLP_RU_NUM_UL_SYMBOLS, 0, .uptr=NULL, .defintval=3, TYPE_UINT, 0}, \
}
// clang-format on

View File

@@ -84,7 +84,8 @@ static int DEFBANDS[] = {7};
static int DEFENBS[] = {0};
static int DEFBFW[] = {0x00007fff};
static int DEFRUTPCORES[] = {-1,-1,-1,-1};
static int DEFBW[] = {273};
static int DEFCARRIER[] = {3430560};
/**
* @brief Helper define to allocate and initialize SetupRelease structures
*/

View File

@@ -175,6 +175,19 @@ int openair0_transport_load(openair0_device *device,
return rc;
}
int openair0_load(openair0_device *device, char *name, openair0_config_t *openair0_cfg, eth_params_t *eth_params)
{
loader_shlibfunc_t shlib_fdesc[1];
int ret = 0;
shlib_fdesc[0].fname = eth_params == NULL ? "device_init" : "transport_init";
ret = load_module_shlib(name, shlib_fdesc, 1, NULL);
AssertFatal((ret >= 0), "Library %s couldn't be loaded\n", name);
return ((devfunc_t)shlib_fdesc[0].fptr)(device, openair0_cfg, eth_params);
}
static void writerEnqueue(re_order_t *ctx, openair0_timestamp timestamp, void **txp, int nsamps, int nbAnt, int flags)
{
pthread_mutex_lock(&ctx->mutex_store);

View File

@@ -656,7 +656,7 @@ const char *get_devname(int devtype);
int openair0_device_load(openair0_device *device, openair0_config_t *openair0_cfg);
/*! \brief Initialize transport protocol . It returns 0 if OK */
int openair0_transport_load(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t *eth_params);
int openair0_load(openair0_device *device, char *name, openair0_config_t *openair0_cfg, eth_params_t *eth_params);
/*! \brief Get current timestamp of USRP
* \param device the hardware to use

View File

@@ -33,7 +33,7 @@ endif()
add_compile_options(-Wno-packed-not-aligned)
set_target_properties(oran_fhlib_5g PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -march=native")
target_link_libraries(oran_fhlib_5g PRIVATE xran::xran ${dpdk_LINK_LIBRARIES} ${T_LIB} pthread dl rt m numa)
target_link_libraries(oran_fhlib_5g PRIVATE MAC_NR_COMMON xran::xran ${dpdk_LINK_LIBRARIES} ${T_LIB} pthread dl rt m numa)
target_include_directories(oran_fhlib_5g PRIVATE ${dpdk_INCLUDE_DIRS})
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
find_package(armral REQUIRED)

View File

@@ -56,10 +56,33 @@ int xran_is_prach_slot(uint8_t PortId, uint32_t subframe_id, uint32_t slot_id);
#ifndef USE_POLLING
extern notifiedFIFO_t oran_sync_fifo;
extern notifiedFIFO_t dl_sync_fifo;
#else
volatile oran_sync_info_t oran_sync_info = {0};
#endif
int32_t symbol_callback(void *args, struct xran_sense_of_time* p_sense_of_time)
{
uint32_t frame = p_sense_of_time->nFrameIdx;
uint32_t slot = p_sense_of_time->nSlotIdx;
uint32_t subframe = p_sense_of_time->nSubframeIdx;
const struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
const int slots_in_sf = 1 << fh_cfg->frame_conf.nNumerology;
uint32_t slot_in_frame = slot + subframe * slots_in_sf;
if (!first_call_set)
return 0;
LOG_D(HW, "Push %d.%d (slot %d, subframe %d)\n", frame, slot_in_frame, slot, subframe);
notifiedFIFO_elt_t *req = newNotifiedFIFO_elt(sizeof(oran_sync_info_t), 0, NULL, NULL);
oran_sync_info_t *info = NotifiedFifoData(req);
info->sl = slot_in_frame;
info->f = frame;
pushNotifiedFIFO(&dl_sync_fifo, req);
return 0;
}
/** @details xran-specific callback, called when all packets for given CC and
* 1/4, 1/2, 3/4, all symbols of a slot arrived. Currently, only used to get
* timing information and unblock another thread in xran_fh_rx_read_slot()
@@ -467,6 +490,154 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
return (0);
}
/** @details Read PDSCH data from xran buffers on the O-RU. If I/Q compression
* (bitwidth < 16 bits) is configured, deccompresses the data before writing.
* Prints ON TIME counters every 128 frames.
*
* Function is blocking and waits for next frame/slot combination. It is unblocked
* by oai_xran_fh_rx_callback(). It writes the current slot into parameters
* frame/slot. */
int xran_fh_tx_read_slot(ru_info_t *ru, int *frame, int *slot)
{
void *ptr = NULL;
int32_t *pos = NULL;
int idx = 0;
// pull next even from oran_sync_fifo
notifiedFIFO_elt_t *res = pullNotifiedFIFO(&dl_sync_fifo);
notifiedFIFO_elt_t *f;
while ((f = pollNotifiedFIFO(&dl_sync_fifo)) != NULL) {
oran_sync_info_t *old_info = NotifiedFifoData(res);
oran_sync_info_t *new_info = NotifiedFifoData(f);
LOG_E(HW, "Detected double sync message %d.%d => %d.%d\n", old_info->f, old_info->sl, new_info->f, new_info->sl);
delNotifiedFIFO_elt(res);
res = f;
}
oran_sync_info_t *info = NotifiedFifoData(res);
*slot = info->sl;
*frame = info->f;
delNotifiedFIFO_elt(res);
struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
int slots_per_frame = 10 << fh_cfg->frame_conf.nNumerology;
int tti = slots_per_frame * (*frame) + (*slot);
const struct xran_fh_init *fh_init = get_xran_fh_init();
int nPRBs = fh_cfg->nULRBs;
int fftsize = 1 << fh_cfg->ru_conf.fftSize;
int slot_offset_rxdata = 3 & (*slot);
uint32_t slot_size = 4 * 14 * fftsize;
uint8_t *tx_data;
uint8_t *start_ptr = NULL;
int nb_rx_per_ru = ru->nb_rx / fh_init->xran_ports;
for (uint16_t cc_id = 0; cc_id < 1 /*nSectorNum*/; cc_id++) { // OAI does not support multiple CC yet.
for (uint8_t ant_id = 0; ant_id < ru->nb_rx; ant_id++) {
tx_data = (uint8_t *)ru->txdataF_BF[ant_id];
start_ptr = tx_data + (slot_size * slot_offset_rxdata);
const struct xran_frame_config *frame_conf = &get_xran_fh_config(ant_id / nb_rx_per_ru)->frame_conf;
// This loop would better be more inner to avoid confusion and maybe also errors.
for (int32_t sym_idx = 0; sym_idx < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_idx++) {
/* the callback is for mixed and UL slots. In mixed, we have to
* skip DL and guard symbols. */
if (is_tdd_ul_symbol(frame_conf, *slot, sym_idx))
continue;
uint8_t *pData;
oran_buf_list_t *bufs = get_xran_buffers(ant_id / nb_rx_per_ru);
uint8_t *pPrbMapData = bufs->dstcp[ant_id % nb_rx_per_ru][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData;
struct xran_prb_map *pPrbMap = (struct xran_prb_map *)pPrbMapData;
struct xran_prb_elm *pRbElm = &pPrbMap->prbMap[0];
#ifdef E_RELEASE
struct xran_section_desc *p_sec_desc = pRbElm->p_sec_desc[sym_idx][0];
#elif defined F_RELEASE
struct xran_section_desc *p_sec_desc = &pRbElm->sec_desc[sym_idx][0];
#endif
uint32_t one_rb_size =
(((pRbElm->iqWidth == 0) || (pRbElm->iqWidth == 16)) ? (N_SC_PER_PRB * 2 * 2) : (3 * pRbElm->iqWidth + 1));
if (fh_init->mtu < pRbElm->nRBSize * one_rb_size)
pData = bufs->dst[ant_id % nb_rx_per_ru][tti % XRAN_N_FE_BUF_LEN]
.pBuffers[sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT]
.pData;
else
pData = p_sec_desc->pData;
ptr = pData;
pos = (int32_t *)(start_ptr + (4 * sym_idx * fftsize));
if (ptr == NULL || pos == NULL)
continue;
struct xran_prb_map *pRbMap = pPrbMap;
uint32_t idxElm = 0;
uint8_t *src = (uint8_t *)ptr;
LOG_D(HW, "pRbMap->nPrbElm %d\n", pRbMap->nPrbElm);
for (idxElm = 0; idxElm < pRbMap->nPrbElm; idxElm++) {
LOG_D(HW,
"prbMap[%d] : PRBstart %d nPRBs %d\n",
idxElm,
pRbMap->prbMap[idxElm].nRBStart,
pRbMap->prbMap[idxElm].nRBSize);
pRbElm = &pRbMap->prbMap[idxElm];
int pos_len = 0;
int neg_len = 0;
if (pRbElm->nRBStart < (nPRBs >> 1)) // there are PRBs left of DC
neg_len = min((nPRBs * 6) - (pRbElm->nRBStart * 12), pRbElm->nRBSize * N_SC_PER_PRB);
pos_len = (pRbElm->nRBSize * N_SC_PER_PRB) - neg_len;
src = pData;
// Calculation of the pointer for the section in the buffer.
// positive half
uint8_t *dst1 = (uint8_t *)(pos + (neg_len == 0 ? ((pRbElm->nRBStart * N_SC_PER_PRB) - (nPRBs * 6)) : 0));
// negative half
uint8_t *dst2 = (uint8_t *)(pos + (pRbElm->nRBStart * N_SC_PER_PRB) + fftsize - (nPRBs * 6));
int32_t local_dst[pRbElm->nRBSize * N_SC_PER_PRB] __attribute__((aligned(64)));
if (pRbElm->compMethod == XRAN_COMPMETHOD_NONE) {
// NOTE: gcc 11 knows how to generate AVX2 for this!
for (idx = 0; idx < pRbElm->nRBSize * N_SC_PER_PRB * 2; idx++)
((int16_t *)local_dst)[idx] = ((int16_t)ntohs(((uint16_t *)src)[idx])) >> 2;
memcpy((void *)dst2, (void *)local_dst, neg_len * 4);
memcpy((void *)dst1, (void *)&local_dst[neg_len], pos_len * 4);
} else if (pRbElm->compMethod == XRAN_COMPMETHOD_BLKFLOAT) {
#if defined(__i386__) || defined(__x86_64__)
struct xranlib_decompress_request bfp_decom_req = {};
struct xranlib_decompress_response bfp_decom_rsp = {};
int16_t payload_len = (3 * pRbElm->iqWidth + 1) * pRbElm->nRBSize;
bfp_decom_req.data_in = (int8_t *)src;
bfp_decom_req.numRBs = pRbElm->nRBSize;
bfp_decom_req.len = payload_len;
bfp_decom_req.compMethod = pRbElm->compMethod;
bfp_decom_req.iqWidth = pRbElm->iqWidth;
bfp_decom_rsp.data_out = (int16_t *)local_dst;
bfp_decom_rsp.len = 0;
xranlib_decompress_avx512(&bfp_decom_req, &bfp_decom_rsp);
#elif defined(__arm__) || defined(__aarch64__)
armral_bfp_decompression(pRbElm->iqWidth, pRbElm->nRBSize, (int8_t *)src, (int16_t *)local_dst);
#else
AssertFatal(1 == 0, "BFP compression not supported on this architecture");
#endif
memcpy((void *)dst2, (void *)local_dst, neg_len * 4);
memcpy((void *)dst1, (void *)&local_dst[neg_len], pos_len * 4);
} else {
printf("pRbElm->compMethod == %d is not supported\n", pRbElm->compMethod);
exit(-1);
}
}
} // sym_ind
} // ant_ind
} // vv_inf
return (0);
}
/** @details Write PDSCH IQ-data from OAI txdataF_BF buffer to xran buffers. If
* I/Q compression (bitwidth < 16 bits) is configured, compresses the data
* before writing. */

View File

@@ -35,5 +35,6 @@ typedef struct {
void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status);
/** @brief xran callback for time alignment, see xran_reg_physide_cb(). */
int oai_physide_dl_tti_call_back(void *param);
int32_t symbol_callback(void *args, struct xran_sense_of_time* p_sense_of_time);
#endif /* OAIORAN_H */

View File

@@ -184,7 +184,8 @@ void print_fh_init(const struct xran_fh_init *fh_init)
fh_init->filePrefix,
fh_init->mtu,
fh_init->p_o_du_addr);
print_ether_addr(" p_o_ru_addr", fh_init->xran_ports * fh_init->io_cfg.num_vfs, (struct rte_ether_addr *)fh_init->p_o_ru_addr);
if (fh_init->p_o_ru_addr) print_ether_addr(" p_o_ru_addr", fh_init->xran_ports * fh_init->io_cfg.num_vfs, (struct rte_ether_addr *)fh_init->p_o_ru_addr);
else if (fh_init->p_o_du_addr) print_ether_addr(" p_o_du_addr", fh_init->xran_ports * fh_init->io_cfg.num_vfs, (struct rte_ether_addr *)fh_init->p_o_du_addr);
printf("\
totalBfWeights %d\n",
fh_init->totalBfWeights);
@@ -466,14 +467,14 @@ char bbdev_dev[32] = "";
char bbdev_vfio_vf_token[64] = "";
#endif
static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, int nump, const int num_rus)
static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, int nump, const int num_peer, const int is_du)
{
DevAssert(fhip != NULL);
int num_dev = gpd(fhip, nump, ORAN_CONFIG_DPDK_DEVICES)->numelt;
AssertFatal(num_dev > 0, "need to provide DPDK devices for O-RAN 7.2 Fronthaul\n");
AssertFatal(num_dev < 17, "too many DPDK devices for O-RAN 7.2 Fronthaul\n");
io_cfg->id = 0; // 0 -> xran as O-DU; 1 -> xran as O-RU
io_cfg->id = 1-is_du; // 0 -> xran as O-DU; 1 -> xran as O-RU
io_cfg->num_vfs = num_dev; // number of VFs for C-plane and U-plane (should be even); max = XRAN_VF_MAX
io_cfg->num_rxq = 1; // number of RX queues per VF
for (int i = 0; i < num_dev; ++i) {
@@ -535,7 +536,7 @@ static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, in
io_cfg->io_sleep = 0; // enable sleep on PMD cores; 0 -> no sleep
io_cfg->nEthLinePerPort = *gpd(fhip, nump, ORAN_CONFIG_NETHPERPORT)->uptr; // 1, 2, 3 total number of links per O-RU (Fronthaul Ethernet link)
io_cfg->nEthLineSpeed = *gpd(fhip, nump, ORAN_CONFIG_NETHSPEED)->uptr; // 10G,25G,40G,100G speed of Physical connection on O-RU
io_cfg->one_vf_cu_plane = (io_cfg->num_vfs == num_rus); // C-plane and U-plane use one VF
io_cfg->one_vf_cu_plane = (io_cfg->num_vfs == num_peer); // C-plane and U-plane use one VF
/* eCPRI One-Way Delay Measurements common settings for O-DU and O-RU;
use owdm to calculate T12 and T34 -> CUS specification, section 2.3.3.3;
@@ -546,7 +547,7 @@ static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, in
/* if RU does support, io_cfg->eowd_cmn[0] should only be filled as id = O_DU; io_cfg->eowd_cmn[1] only used if id = O_RU */
const uint16_t owdm_enable = *gpd(fhip, nump, ORAN_CONFIG_ECPRI_OWDM)->uptr;
if (owdm_enable) {
io_cfg->eowd_cmn[0].initiator_en = 1; // 1 -> initiator (always O-DU), 0 -> recipient (always O-RU)
io_cfg->eowd_cmn[0].initiator_en = is_du ? 1 : 0; // 1 -> initiator (always O-DU), 0 -> recipient (always O-RU)
io_cfg->eowd_cmn[0].numberOfSamples = 8; // total number of samples to be collected and averaged per port
io_cfg->eowd_cmn[0].filterType = 0; // 0 -> simple average based on number of measurements; not used in xran in both E and F releases
io_cfg->eowd_cmn[0].responseTo = 10000000; // response timeout in [ns]
@@ -710,9 +711,17 @@ static bool set_fh_init(void *mplane_api, struct xran_fh_init *fh_init, enum xra
}
}
#else
int num_rus = FH_ConfigList.numelt; // based on the number of fh_config sections -> number of RUs
fh_init->xran_ports = num_rus; // since we use xran as O-DU, xran_ports is set to the number of RUs
if (!set_fh_io_cfg(&fh_init->io_cfg, fhip, nump, num_rus))
int num_peer = FH_ConfigList.numelt; // based on the number of fh_config sections
int is_du=0;
int num_ru_addr = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->numelt;
int num_du_addr = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->numelt;
if (num_ru_addr > 0 && num_du_addr == 0) is_du = 1;
else if (num_du_addr > 0 && num_ru_addr == 0) is_du = 0;
else AssertFatal(1==0,"Illegal node configuration, num_du_addr %d, num_ru_addr %d\n",num_du_addr,num_ru_addr);
fh_init->xran_ports = num_peer;
if (!set_fh_io_cfg(&fh_init->io_cfg, fhip, nump, num_peer, is_du))
return false;
if (!set_fh_eaxcid_conf(&fh_init->eAxCId_conf, xran_cat))
return false;
@@ -720,16 +729,36 @@ static bool set_fh_init(void *mplane_api, struct xran_fh_init *fh_init, enum xra
communicated in a single xRAN network layer transaction. Supported 1500 bytes and 9600 bytes (Jumbo Frame);
xran only checks if (MTU <= 1500), therefore setting any value > 1500, xran assumes 9600 value is used */
fh_init->mtu = *gpd(fhip, nump, ORAN_CONFIG_MTU)->uptr;
int num_ru_addr = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->numelt;
fh_init->p_o_ru_addr = calloc(num_ru_addr, sizeof(struct rte_ether_addr));
AssertFatal(fh_init->p_o_ru_addr != NULL, "out of memory\n");
char **ru_addrs = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->strlistptr;
for (int i = 0; i < num_ru_addr; ++i) {
struct rte_ether_addr *ea = (struct rte_ether_addr *)fh_init->p_o_ru_addr;
if (get_ether_addr(ru_addrs[i], &ea[i]) == NULL) {
printf("could not read ethernet address '%s' for RU!\n", ru_addrs[i]);
return false;
}
fh_init->p_o_du_addr = NULL; // DPDK retreives DU MAC address within the xran library with rte_eth_macaddr_get() function
char **ru_addrs,**du_addrs;
if (is_du > 0) {
fh_init->p_o_ru_addr = calloc(num_ru_addr, sizeof(struct rte_ether_addr));
ru_addrs = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->strlistptr;
AssertFatal(fh_init->p_o_ru_addr != NULL, "out of memory\n");
for (int i = 0; i < num_ru_addr; ++i) {
struct rte_ether_addr *ea = (struct rte_ether_addr *)fh_init->p_o_ru_addr;
if (get_ether_addr(ru_addrs[i], &ea[i]) == NULL) {
printf("could not read ethernet address '%s' for RU!\n", ru_addrs[i]);
return false;
}
}
fh_init->p_o_du_addr = NULL;
}
else {
fh_init->p_o_du_addr = calloc(num_du_addr, sizeof(struct rte_ether_addr));
du_addrs = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->strlistptr;
AssertFatal(fh_init->p_o_du_addr != NULL, "out of memory\n");
for (int i = 0; i < num_du_addr; ++i) {
struct rte_ether_addr *ea = (struct rte_ether_addr *)fh_init->p_o_du_addr;
if (get_ether_addr(du_addrs[i], &ea[i]) == NULL) {
printf("could not read ethernet address '%s' for DU!\n", du_addrs[i]);
return false;
}
}
fh_init->p_o_ru_addr = NULL;
}
#endif
@@ -738,7 +767,6 @@ static bool set_fh_init(void *mplane_api, struct xran_fh_init *fh_init, enum xra
/* used to specify a unique prefix for shared memory, and files created by multiple DPDK processes;
it is necessary */
fh_init->filePrefix = strdup(*gpd(fhip, nump, ORAN_CONFIG_FILE_PREFIX)->strptr);
fh_init->p_o_du_addr = NULL; // DPDK retreives DU MAC address within the xran library with rte_eth_macaddr_get() function
fh_init->totalBfWeights = 0; // only used if id = O_RU (for emulation); C-plane extension types; section 5.4.6 of CUS spec
#ifdef F_RELEASE

View File

@@ -298,6 +298,7 @@ static void oai_xran_fh_rx_prach_callback(void *pCallbackTag, xran_status_t stat
}
static void oran_allocate_buffers(void *handle,
bool is_du,
int xran_inst,
int num_sectors,
oran_port_instance_t *portInstances,
@@ -425,8 +426,20 @@ static void oran_allocate_buffers(void *handle,
}
}
xran_5g_fronthault_config(pi->instanceHandle, src, srccp, dst, dstcp, oai_xran_fh_rx_callback, &portInstances->pusch_tag);
xran_5g_prach_req(pi->instanceHandle, prach, prachdecomp, oai_xran_fh_rx_prach_callback, &portInstances->prach_tag);
if (is_du) {
xran_5g_fronthault_config(pi->instanceHandle, src, srccp, dst, dstcp, oai_xran_fh_rx_callback, &portInstances->pusch_tag);
xran_5g_prach_req(pi->instanceHandle, prach, prachdecomp, oai_xran_fh_rx_prach_callback, &portInstances->prach_tag);
}
else {
static struct xran_sense_of_time symCbTime;
// TODO: Check if symbol callback should also run in half slot
xran_reg_sym_cb(handle, symbol_callback, NULL, &symCbTime, 13, XRAN_CB_SYM_TX_WIN_END);
// Only setup UPlane/CPlane buffers for O-RU. O-RU does not need callback for PUSCH and PRACH as the timing will be reliant on
// the underlying RF device
xran_5g_fronthault_config(pi->instanceHandle, src, srccp, dst, dstcp, NULL, NULL);
// TODO: PRACH
// TODO: Beamforming weights
}
}
int *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_config *xran_fh_config)
@@ -440,6 +453,7 @@ int *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_confi
exit(-1);
}
bool is_du = xran_fh_init->io_cfg.id == 0;
/** process all the O-RU|O-DU for use case */
for (int32_t o_xu_id = 0; o_xu_id < xran_fh_init->xran_ports; o_xu_id++) {
print_fh_config(&xran_fh_config[o_xu_id]);
@@ -457,9 +471,9 @@ int *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_confi
pi->pusch_tag = tag;
#ifdef E_RELEASE
LOG_W(HW, "Please be aware that E release support will be removed in the future. Consider switching to F release.\n");
oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, &xran_fh_config[o_xu_id]);
oran_allocate_buffers(gxran_handle, is_du, o_xu_id, 1, pi, &xran_fh_config[o_xu_id]);
#elif defined F_RELEASE
oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, xran_fh_init->mtu, &xran_fh_config[o_xu_id]);
oran_allocate_buffers(gxran_handle, is_du, o_xu_id, 1, pi, xran_fh_init->mtu, &xran_fh_config[o_xu_id]);
#endif
if ((xret = xran_reg_physide_cb(gxran_handle, oai_physide_dl_tti_call_back, NULL, 10, XRAN_CB_TTI)) != XRAN_STATUS_SUCCESS) {

View File

@@ -32,11 +32,12 @@
#define ORAN_CONFIG_IO_CORE "io_core"
#define ORAN_CONFIG_WORKER_CORES "worker_cores"
#define ORAN_CONFIG_DU_KEYPAIR "du_key_pair" // only needed for M-plane
#define ORAN_CONFIG_DU_ADDR "du_addr" // only needed for M-plane
#define ORAN_CONFIG_VLAN_TAG "vlan_tag" // only needed for M-plane
#define ORAN_CONFIG_RU_ADDR "ru_addr" // not needed if M-plane used
#define ORAN_CONFIG_RU_IP_ADDR "ru_ip_addr" // only needed for M-plane
#define ORAN_CONFIG_MTU "mtu" // not needed if M-plane used
#define ORAN_CONFIG_DU_ADDR "du_addr"
#define ORAN_CONFIG_RU_ADDR "ru_addr"
#define ORAN_CONFIG_MTU "mtu"
#define ORAN_CONFIG_FILE_PREFIX "file_prefix"
#define ORAN_CONFIG_NETHPERPORT "eth_lines"
#define ORAN_CONFIG_NETHSPEED "eth_speed"
@@ -53,10 +54,10 @@
{ORAN_CONFIG_IO_CORE, "DPDK Core used for IO\n", PARAMFLAG_MANDATORY, .iptr=NULL, .defintval=4, TYPE_INT, 0}, \
{ORAN_CONFIG_WORKER_CORES, "CPU Cores to use for workers\n", PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=NULL,TYPE_UINTARRAY, 0}, \
{ORAN_CONFIG_DU_KEYPAIR, "DU keypair for RU authentication\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
{ORAN_CONFIG_DU_ADDR, "Ether addr of DU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
{ORAN_CONFIG_VLAN_TAG, "VLAN tag\n", PARAMFLAG_MANDATORY, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \
{ORAN_CONFIG_RU_ADDR, "Ether addr of RU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
{ORAN_CONFIG_RU_IP_ADDR, "IP addr of RU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
{ORAN_CONFIG_DU_ADDR, "Ether addr of DU\n", 0, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
{ORAN_CONFIG_RU_ADDR, "Ether addr of RU\n", 0, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
{ORAN_CONFIG_MTU, "MTU of Eth interface\n", 0, .uptr=NULL, .defuintval=1500, TYPE_UINT, 0}, \
{ORAN_CONFIG_FILE_PREFIX, "DPDK file-prefix\n", 0, .strptr=NULL, .defstrval="wls_0", TYPE_STRING, 0}, \
{ORAN_CONFIG_NETHPERPORT, "number of links per port\n", 0, .uptr=NULL, .defuintval=1, TYPE_UINT, 0}, \

View File

@@ -53,6 +53,7 @@ typedef struct {
} oran_eth_state_t;
notifiedFIFO_t oran_sync_fifo;
notifiedFIFO_t dl_sync_fifo;
int trx_oran_start(openair0_device *device)
{
@@ -210,6 +211,16 @@ int trx_oran_ctlrecv(openair0_device *device, void *msg, ssize_t msg_len)
return 0;
}
void oran_fh_if4p5_north_in(RU_t *ru, int *frame, int *slot) {
ru_info_t ru_info;
ru_info.nb_rx = ru->nb_rx * ru->num_beams_period;
ru_info.txdataF_BF = ru->common.txdataF_BF;
start_meas(&ru->rx_fhaul);
int ret = xran_fh_tx_read_slot(&ru_info, frame, slot);
AssertFatal(ret == 0, "ORAN: %d.%d ORAN_fh_if4p5_north_in ERROR in RX function \n", *frame, *slot);
stop_meas(&ru->rx_fhaul);
}
void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot)
{
ru_info_t ru_info;
@@ -286,6 +297,8 @@ void *get_internal_parameter(char *name)
return (void *)oran_fh_if4p5_south_in;
if (!strcmp(name, "fh_if4p5_south_out"))
return (void *)oran_fh_if4p5_south_out;
if (!strcmp(name, "fh_if4p5_north_in"))
return (void *)oran_fh_if4p5_north_in;
return NULL;
}
@@ -363,6 +376,7 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device *d
// create message queues for ORAN sync
initNotifiedFIFO(&oran_sync_fifo);
initNotifiedFIFO(&dl_sync_fifo);
eth->e.flags = ETH_RAW_IF4p5_MODE;
eth->e.compression = NO_COMPRESS;

View File

@@ -51,6 +51,7 @@ typedef struct ru_info_s {
* @param frame output of the frame which has been read.
* @param slot output of the slot which has been read. */
int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot);
int xran_fh_tx_read_slot(ru_info_t *ru, int *frame, int *slot);
/** @brief Writes TX data (PDSCH) of given slot. */
int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp);

View File

@@ -0,0 +1,284 @@
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 = 2;
maxMIMO_layers = 2;
pusch_AntennaPorts = 4;
do_CSIRS = 1;
do_SRS = 0;
sib1_tda = 15;
pdcch_ConfigSIB1 = (
{
controlResourceSetZero = 11;
searchSpaceZero = 0;
}
);
servingCellConfigCommon = (
{
#spCellConfigCommon
physCellId = 0;
# n_TimingAdvanceOffset = 0;
# downlinkConfigCommon
#frequencyInfoDL
# center frequency = 3450.72 MHz
# selected SSB frequency = 3450.72 MHz
absoluteFrequencySSB = 630048;
dl_frequencyBand = 78;
# frequency point A = 3401.58 MHz
dl_absoluteFrequencyPointA = 626772;
#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 = 78;
#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 = 159;
#prach_msg1_FDM
#0 = one, 1=two, 2=four, 3=eight
prach_msg1_FDM = 0;
prach_msg1_FrequencyStart = 22;
zeroCorrelationZoneConfig = 15;
preambleReceivedTargetPower = -104;
#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
preambleTransMax = 7;
#powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 2;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 5;
#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;
#oneHalf (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,
# 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 = 5;
nrofDownlinkSlots = 3;
nrofDownlinkSymbols = 6;
nrofUplinkSlots = 1;
nrofUplinkSymbols = 4;
ssPBCH_BlockPower = 0;
}
);
# ------- 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.51";
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.51";
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;
# dl_bler_target_upper = .35;
# dl_bler_target_lower = .15;
ul_bler_target_upper = .35;
ul_bler_target_lower = .15;
pusch_FailureThres = 100;
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
prach_dtx_threshold = 130
pucch0_dtx_threshold = 80;
pusch_dtx_threshold = 10;
tx_amp_backoff_dB = 20; # needs to match O-RU configuration
L1_rx_thread_core = -1;
L1_tx_thread_core = -1;
phase_compensation = 1; # needs to match O-RU configuration
}
);
RUs = (
{
local_rf = "no";
nb_tx = 4;
nb_rx = 4;
att_tx = 0;
att_rx = 0;
bands = [78];
max_pdschReferenceSignalPower = -27;
max_rxgain = 75;
sf_extension = 0;
eNB_instances = [0];
ru_thread_core = -1;
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 = ("vdev=net_memif1,bsize=1514,role=client,socket=/tmp/memif.sock");
system_core = 0;
io_core = 1;
worker_cores = (2);
ru_addr = ("00:00:00:00:00:01");
file_prefix = "gnb";
dpdk_mem_size = 0;
mtu = 1514;
fh_config = ({
T1a_cp_dl = (285, 429);
T1a_cp_ul = (285, 429);
T1a_up = (96, 196);
Ta4 = (110, 180);
ru_config = {
iq_width = 16;
iq_width_prach = 16;
};
prach_config = {
kbar = 0;
};
});
};

View File

@@ -0,0 +1,60 @@
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
RUs = (
{
local_rf = "no";
nb_tx = 4;
nb_rx = 4;
att_tx = 0;
att_rx = 0;
bands = [78];
max_pdschReferenceSignalPower = -27;
max_rxgain = 75;
sf_extension = 0;
eNB_instances = [0];
ru_thread_core = -1;
sl_ahead = 5;
tr_preference = "raw_if4p5"; # important: activate FHI7.2
do_precoding = 0; # needs to match O-RU configuration
}
);
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 = ("vdev=net_memif0,bsize=1514,role=server,socket=/tmp/memif.sock"); # one VF can be used as well
dpdk_iova_mode = "VA";
system_core = 10;
io_core = 12;
worker_cores = (14);
du_addr = ("46:bd:39:e7:c3:23");
file_prefix = "ru";
dpdk_mem_size = 0;
mtu = 1514;
fh_config = ({
T1a_cp_dl = (285, 429);
T1a_cp_ul = (285, 429);
T1a_up = (96, 196);
Ta4 = (110, 180);
ru_config = {
iq_width = 16;
iq_width_prach = 16;
};
prach_config = {
kbar = 0;
};
});
};