diff --git a/CMakeLists.txt b/CMakeLists.txt index 14d90a4c3b..989503a36d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1789,6 +1789,24 @@ 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(nr-oru + ${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/SCHED_NR/nr_prach_procedures.c + ${OPENAIR_DIR}/openair1/SCHED/phy_procedures_lte_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(nr-oru PRIVATE + UTIL SCHED_RU_LIB PHY_COMMON PHY_RU PHY_NR shlib_loader z dl) +target_link_libraries(nr-oru PRIVATE pthread m CONFIG_LIB rt ${T_LIB} utils + barrier actor) +target_link_libraries(nr-oru PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs nr_phy_common time_management) + # nr-softmodem ################################################### diff --git a/executables/main_nr_ru.c b/executables/main_nr_ru.c new file mode 100644 index 0000000000..d8f2a02235 --- /dev/null +++ b/executables/main_nr_ru.c @@ -0,0 +1,220 @@ +/* + * 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 + */ + +#include +#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 +#include + +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(); +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(bool das, + int fapi_beam_index, + NR_gNB_COMMON *common_vars, + int slot, + int symbols_per_slot, + int bitmap_symbols) +{ + return 0; +} +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; + +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(); + LOG_W(PHY, "%s is experimental software and at this point is not an implementation of a 7.2 O-RAN RU\n", argv[0]); + 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); + + RU_t *ru = RC.ru[0]; + + 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; +} diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 279b6f5142..2a21945f85 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1555,8 +1555,13 @@ void init_NR_RU(configmodule_interface_t *cfg, char *rf_config_file) } } - PHY_VARS_gNB *gNB_RC = RC.gNB[0]; - PHY_VARS_gNB *gNB0 = ru->gNB_list[0]; + + PHY_VARS_gNB *gNB_RC = NULL; + PHY_VARS_gNB *gNB0 = NULL; + if (RC.nb_nr_L1_inst > 0) { + gNB_RC = RC.gNB[0]; + gNB0 = ru->gNB_list[0]; + } LOG_D(PHY, "RU FUnction:%d ru->if_south:%d\n", ru->function, ru->if_south); if (gNB0) { diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index 71418bb1e3..d82ff3c919 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -33,20 +33,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); diff --git a/radio/fhi_72/oran-config.c b/radio/fhi_72/oran-config.c index 00c13bc64d..e15d0a68e5 100644 --- a/radio/fhi_72/oran-config.c +++ b/radio/fhi_72/oran-config.c @@ -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); @@ -460,14 +461,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_rus, 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) { @@ -540,7 +541,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] @@ -678,6 +679,19 @@ static bool set_fh_init(void *mplane_api, struct xran_fh_init *fh_init, enum xra const int nfh = sizeofArray(FHconfigs); config_getlist(config_get_if(), &FH_ConfigList, FHconfigs, nfh, aprefix); + int num_rus = FH_ConfigList.numelt; // based on the number of fh_config sections -> number of RUs + 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(false, "Illegal node configuration, num_du_addr %d, num_ru_addr %d\n", num_du_addr, num_ru_addr); + fh_init->xran_ports = is_du == 1 ? num_rus : num_du_addr; + #ifdef OAI_MPLANE ru_session_list_t *ru_session_list = (ru_session_list_t *)mplane_api; int num_rus = ru_session_list->num_rus; @@ -704,9 +718,8 @@ 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)) + + if (!set_fh_io_cfg(&fh_init->io_cfg, fhip, nump, num_rus, is_du)) return false; if (!set_fh_eaxcid_conf(&fh_init->eAxCId_conf, xran_cat)) return false; @@ -714,16 +727,35 @@ 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 @@ -732,7 +764,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