/* * SPDX-License-Identifier: LicenseRef-CSSL-1.0 */ /*! * \brief Top-level threads for radio-unit */ #define _GNU_SOURCE /* See feature_test_macros(7) */ #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 "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 static int DEFBANDS[] = {7}; static int DEFENBS[] = {0}; static int DEFBFW[] = {0x00007fff}; static int DEFRUTPCORES[] = {2,4,6,8}; THREAD_STRUCT thread_struct; 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; RU_t ru_m; extern void init_RU0(RU_t *ru,int ru_id,char *rf_config_file, int send_dmrssync); extern void init_RU_proc(RU_t *ru); extern void kill_RU_proc(RU_t *ru); extern void set_function_spec_param(RU_t *ru); int64_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; if (ru_m.rfdevice.trx_end_func) { if (ru_m.rfdevice.trx_get_stats_func) { ru_m.rfdevice.trx_get_stats_func(&ru_m.rfdevice); ru_m.rfdevice.trx_get_stats_func = NULL; } ru_m.rfdevice.trx_end_func(&ru_m.rfdevice); ru_m.rfdevice.trx_end_func = NULL; } if (ru_m.ifdevice.trx_end_func) { if (ru_m.ifdevice.trx_get_stats_func) { ru_m.ifdevice.trx_get_stats_func(&ru_m.ifdevice); ru_m.ifdevice.trx_get_stats_func = NULL; } ru_m.ifdevice.trx_end_func(&ru_m.ifdevice); ru_m.ifdevice.trx_end_func = NULL; } pthread_mutex_destroy(ru_m.ru_mutex); pthread_cond_destroy(ru_m.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); IS_SOFTMODEM_ENB = true; get_common_options(cfg); CONFIG_CLEARRTFLAG(CONFIG_NOEXITONHELP); // RCConfig(); } extern void phy_free_RU(RU_t *); 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; } uint64_t downlink_frequency[MAX_NUM_CCs][4]; configmodule_interface_t *uniqCfg = NULL; int main ( int argc, char **argv ) { 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(); RU_t *ru=&ru_m; paramdef_t RUParams[] = RUPARAMS_DESC; paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST,NULL,0}; config_getlist(config_get_if(), &RUParamList, RUParams, sizeofArray(RUParams), NULL); int j=0; uint64_t ru_mask=1; pthread_mutex_t ru_mutex; pthread_mutex_init(&ru_mutex,NULL); pthread_cond_t ru_cond; pthread_cond_init(&ru_cond,NULL); ru->ru_mask= &ru_mask; ru->ru_mutex = &ru_mutex; ru->ru_cond = &ru_cond; ru->if_timing = synch_to_ext_device; ru->num_eNB = 0; ru->has_ctrl_prt = 1; if (config_isparamset(RUParamList.paramarray[j], RU_SDR_ADDRS)) { ru->openair0_cfg.sdr_addrs = strdup(*(RUParamList.paramarray[j][RU_SDR_ADDRS].strptr)); } if (config_isparamset(RUParamList.paramarray[j], RU_SDR_CLK_SRC)) { if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "internal") == 0) { ru->openair0_cfg.clock_source = internal; LOG_D(PHY, "RU clock source set as internal\n"); } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "external") == 0) { ru->openair0_cfg.clock_source = external; LOG_D(PHY, "RU clock source set as external\n"); } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "gpsdo") == 0) { ru->openair0_cfg.clock_source = gpsdo; LOG_D(PHY, "RU clock source set as gpsdo\n"); } else { LOG_E(PHY, "Erroneous RU clock source in the provided configuration file: '%s'\n", *(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr)); } } else { ru->openair0_cfg.clock_source = unset; } if (config_isparamset(RUParamList.paramarray[j], RU_SDR_TME_SRC)) { if (strcmp(*(RUParamList.paramarray[j][RU_SDR_TME_SRC].strptr), "internal") == 0) { ru->openair0_cfg.time_source = internal; LOG_D(PHY, "RU time source set as internal\n"); } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_TME_SRC].strptr), "external") == 0) { ru->openair0_cfg.time_source = external; LOG_D(PHY, "RU time source set as external\n"); } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_TME_SRC].strptr), "gpsdo") == 0) { ru->openair0_cfg.time_source = gpsdo; LOG_D(PHY, "RU time source set as gpsdo\n"); } else { LOG_E(PHY, "Erroneous RU time source in the provided configuration file: '%s'\n", *(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr)); } } else { ru->openair0_cfg.time_source = unset; } if (strcmp(*(RUParamList.paramarray[j][RU_LOCAL_RF_IDX].strptr), "yes") == 0) { if ( !(config_isparamset(RUParamList.paramarray[j],RU_LOCAL_IF_NAME_IDX)) ) { AssertFatal(1==0,"IF_NAME is required\n"); } else { ru->eth_params.local_if_name = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr)); ru->eth_params.my_addr = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr)); ru->eth_params.remote_addr = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr)); ru->eth_params.my_portd = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr); ru->eth_params.remote_portd = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr); // Check if control port set if (!(config_isparamset(RUParamList.paramarray[j],RU_REMOTE_PORTC_IDX)) ) { printf("Removing control port for RU %d\n",j); ru->has_ctrl_prt = 0; } else { ru->eth_params.my_portc = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr); ru->eth_params.remote_portc = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr); printf(" Control port %u \n",ru->eth_params.my_portc); } if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp") == 0) { ru->if_south = LOCAL_RF; ru->function = NGFI_RRU_IF5; ru->eth_params.transp_preference = ETH_UDP_MODE; printf("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) { ru->if_south = LOCAL_RF; ru->function = NGFI_RRU_IF5; ru->eth_params.transp_preference = ETH_RAW_MODE; printf("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) { ru->if_south = LOCAL_RF; ru->function = NGFI_RRU_IF4p5; ru->eth_params.transp_preference = ETH_UDP_IF4p5_MODE; printf("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) { ru->if_south = LOCAL_RF; ru->function = NGFI_RRU_IF4p5; ru->eth_params.transp_preference = ETH_RAW_IF4p5_MODE; printf("Setting function for RU %d to NGFI_RRU_IF4p5 (raw)\n",j); } printf("RU %d is_slave=%s\n",j,*(RUParamList.paramarray[j][RU_IS_SLAVE_IDX].strptr)); if (strcmp(*(RUParamList.paramarray[j][RU_IS_SLAVE_IDX].strptr), "yes") == 0) ru->is_slave=1; else ru->is_slave=0; printf("RU %d ota_sync_enabled=%s\n",j,*(RUParamList.paramarray[j][RU_OTA_SYNC_ENABLE_IDX].strptr)); if (strcmp(*(RUParamList.paramarray[j][RU_OTA_SYNC_ENABLE_IDX].strptr), "yes") == 0) ru->ota_sync_enable=1; else ru->ota_sync_enable=0; } ru->max_pdschReferenceSignalPower = *(RUParamList.paramarray[j][RU_MAX_RS_EPRE_IDX].uptr);; ru->max_rxgain = *(RUParamList.paramarray[j][RU_MAX_RXGAIN_IDX].uptr); ru->num_bands = RUParamList.paramarray[j][RU_BAND_LIST_IDX].numelt; /* sf_extension is in unit of samples for 30.72MHz here, has to be scaled later */ ru->sf_extension = *(RUParamList.paramarray[j][RU_SF_EXTENSION_IDX].uptr); for (int i=0; inum_bands; i++) ru->band[i] = RUParamList.paramarray[j][RU_BAND_LIST_IDX].iptr[i]; } //strcmp(local_rf, "yes") == 0 else { printf("RU %d: Transport %s\n",j,*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr)); ru->eth_params.local_if_name = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr)); ru->eth_params.my_addr = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr)); ru->eth_params.remote_addr = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr)); ru->eth_params.my_portc = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr); ru->eth_params.remote_portc = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr); ru->eth_params.my_portd = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr); ru->eth_params.remote_portd = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr); if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp") == 0) { ru->if_south = REMOTE_IF5; ru->function = NGFI_RAU_IF5; ru->eth_params.transp_preference = ETH_UDP_MODE; } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw") == 0) { ru->if_south = REMOTE_IF5; ru->function = NGFI_RAU_IF5; ru->eth_params.transp_preference = ETH_RAW_MODE; } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_if4p5") == 0) { ru->if_south = REMOTE_IF4p5; ru->function = NGFI_RAU_IF4p5; ru->eth_params.transp_preference = ETH_UDP_IF4p5_MODE; } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if4p5") == 0) { ru->if_south = REMOTE_IF4p5; ru->function = NGFI_RAU_IF4p5; ru->eth_params.transp_preference = ETH_RAW_IF4p5_MODE; } if (strcmp(*(RUParamList.paramarray[j][RU_IS_SLAVE_IDX].strptr), "yes") == 0) ru->is_slave=1; else ru->is_slave=0; } /* strcmp(local_rf, "yes") != 0 */ ru->nb_tx = *(RUParamList.paramarray[j][RU_NB_TX_IDX].uptr); ru->nb_rx = *(RUParamList.paramarray[j][RU_NB_RX_IDX].uptr); ru->att_tx = *(RUParamList.paramarray[j][RU_ATT_TX_IDX].uptr); ru->att_rx = *(RUParamList.paramarray[j][RU_ATT_RX_IDX].uptr); set_worker_conf("WORKER_ENABLE"); pthread_cond_init(&sync_cond,NULL); pthread_mutex_init(&sync_mutex, NULL); init_RU0(ru,0,get_softmodem_params()->rf_config_file,get_softmodem_params()->send_dmrs_sync); ru->rf_map.card=0; ru->rf_map.chain=(get_softmodem_params()->chain_offset); LOG_I(PHY, "Initializing RRU descriptor : (%s,%s,%d)\n", ru_if_types[ru->if_south], NB_timing[ru->if_timing], ru->function); set_function_spec_param(ru); LOG_I(PHY, "Starting ru_thread , is_slave %d, send_dmrs %d\n", ru->is_slave, ru->generate_dmrs_sync); init_RU_proc(ru); pthread_mutex_lock(&ru_mutex); while (ru_mask>0) pthread_cond_wait(&ru_cond,&ru_mutex); pthread_mutex_unlock(&ru_mutex); LOG_I(PHY,"RU configured, unlocking threads\n"); config_sync_var=0; pthread_mutex_lock(&sync_mutex); sync_var=0; pthread_cond_broadcast(&sync_cond); pthread_mutex_unlock(&sync_mutex); while (oai_exit==0) sleep(1); // stop threads kill_RU_proc(ru); phy_free_RU(ru); free_lte_top(); end_configmodule(uniqCfg); if (ru->rfdevice.trx_end_func) { if (ru->rfdevice.trx_get_stats_func) { ru->rfdevice.trx_get_stats_func(&ru->rfdevice); ru->rfdevice.trx_get_stats_func = NULL; } ru->rfdevice.trx_end_func(&ru->rfdevice); ru->rfdevice.trx_end_func = NULL; } if (ru->ifdevice.trx_end_func) { if (ru->ifdevice.trx_get_stats_func) { ru->ifdevice.trx_get_stats_func(&ru->ifdevice); ru->ifdevice.trx_get_stats_func = NULL; } ru->ifdevice.trx_end_func(&ru->ifdevice); ru->ifdevice.trx_end_func = NULL; } logClean(); printf("Bye.\n"); return 0; }