diff --git a/ci-scripts/xml_files/gnb_phytest_rfemulator_run_100_2x2.xml b/ci-scripts/xml_files/gnb_phytest_rfemulator_run_100_2x2.xml new file mode 100644 index 0000000000..3d2efb5084 --- /dev/null +++ b/ci-scripts/xml_files/gnb_phytest_rfemulator_run_100_2x2.xml @@ -0,0 +1,70 @@ + + + gNB-PHY-Test-100-2x2-RFemu + Timing phytest 100 MHz 2x2 RFemulator + tasks + +100000 390101 000001 390109 200000 + + + + Custom_Command + Disable Sleep States + caracal + sudo cpupower idle-set -D 0 + + + Custom_Command + true + Enable Sleep States + caracal + sudo cpupower idle-set -E + + + + Initialize_eNB + Initialize gNB USRP + caracal + -O ci-scripts/conf_files/gnb.band79.273prb.usrpn300.phytest-dora.conf --phy-test -q -U 768 -T 273 -t 23 -D 127 -m 23 -M 273 -l 2 --device.name rf_emulator --rf_emulator.noise_level_dBFS -36 --log_config.global_log_options level,nocolor,time + datalog_rt_stats.100.2x2.yaml + NR + numactl --cpunodebind=netdev:enp94s0f0np0 --membind=netdev:enp94s0f0np0 + + + + IdleSleep + Sleep + 60 + + + + + Terminate_eNB + caracal + true + Terminate gNB + NR + + + diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index b1b305c596..658b0b858a 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -457,7 +457,7 @@ function main() { # 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 - TARGET_LIST="$TARGET_LIST params_libconfig coding rfsimulator dfts params_yaml vrtsim" + TARGET_LIST="$TARGET_LIST params_libconfig coding rfsimulator dfts params_yaml vrtsim rf_emulator" fi mkdir -p $DIR/$BUILD_DIR/build diff --git a/common/config/DOC/config/rtusage.md b/common/config/DOC/config/rtusage.md index 3b51e1afd2..7c42a6edcc 100644 --- a/common/config/DOC/config/rtusage.md +++ b/common/config/DOC/config/rtusage.md @@ -55,7 +55,6 @@ To get help on supported parameters you can use specific options: --ulsch-max-errors: set the eNodeB max ULSCH erros --phy-test: test UE phy layer, mac disabled --usim-test: use XOR autentication algo in case of test usim mode - --emulate-rf: Emulated RF enabled(disable by defult) --clock: tells hardware to use a clock reference (0:internal, 1:external, 2:gpsdo) --wait-for-sync: Help string not specified -C: Set the downlink frequency for all component carriers diff --git a/common/utils/time_meas.h b/common/utils/time_meas.h index f7c2810b60..de79a0252d 100644 --- a/common/utils/time_meas.h +++ b/common/utils/time_meas.h @@ -193,6 +193,7 @@ static inline void merge_meas(time_stats_t *dst_ts, const time_stats_t *src_ts) return; dst_ts->trials += src_ts->trials; dst_ts->diff += src_ts->diff; + dst_ts->diff_square += src_ts->diff_square; if (src_ts->max > dst_ts->max) dst_ts->max = src_ts->max; } diff --git a/doc/README.md b/doc/README.md index f2049bac04..9bd89480af 100644 --- a/doc/README.md +++ b/doc/README.md @@ -118,6 +118,7 @@ Some directories under `radio` contain READMEs: - [IQPlayer](../radio/iqplayer/DOC/iqrecordplayer_usage.md), and [general documentation](./iqrecordplayer_usage.md) - [fhi_72](../radio/fhi_72/README.md) - [vrtsim](../radio/vrtsim/README.md) +- [rf_emulator](../radio/emulator/README.md) The other SDRs (AW2S, LimeSDR, ...) have no READMEs. diff --git a/executables/lte-ru.c b/executables/lte-ru.c index 326e55b288..eed5a90eb9 100644 --- a/executables/lte-ru.c +++ b/executables/lte-ru.c @@ -531,44 +531,6 @@ volatile late_control_e late_control=STATE_BURST_NORMAL; /* add fail safe for late command end */ -static void *emulatedRF_thread(void *param) { - RU_proc_t *proc = (RU_proc_t *) param; - int microsec = 500; // length of time to sleep, in miliseconds - int numerology = 0 ; - struct timespec req = {0}; - req.tv_sec = 0; - req.tv_nsec = (numerology>0)? ((microsec * 1000L)/numerology):(microsec * 1000L)*2; - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - CPU_SET(1,&cpuset); - pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); - int policy; - int ret; - struct sched_param sparam; - memset(&sparam, 0, sizeof(sparam)); - sparam.sched_priority = sched_get_priority_max(SCHED_FIFO); - policy = SCHED_FIFO ; - pthread_setschedparam(pthread_self(), policy, &sparam); - wait_sync("emulatedRF_thread"); - - while(!oai_exit) { - nanosleep(&req, (struct timespec *)NULL); - - if(proc->emulate_rf_busy ) { - LOG_E(PHY,"rf being delayed in emulated RF\n"); - } - - proc->emulate_rf_busy = 1; - AssertFatal((ret=pthread_mutex_lock(&proc->mutex_emulateRF))==0,"mutex_lock returns %d\n",ret); - ++proc->instance_cnt_emulateRF; - pthread_cond_signal(&proc->cond_emulateRF); - AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_emulateRF))==0,"mutex_unlock returns %d\n",ret); - } - - return 0; -} - - void rx_rf(RU_t *ru, int *frame, int *subframe) { @@ -586,17 +548,7 @@ void rx_rf(RU_t *ru, VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 ); old_ts = proc->timestamp_rx; - if(ru->emulate_rf) { - wait_on_condition(&proc->mutex_emulateRF,&proc->cond_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread"); - release_thread(&proc->mutex_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread"); - rxs = fp->samples_per_tti; - } else { - rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, - &ts, - rxp, - fp->samples_per_tti, - ru->nb_rx); - } + rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, fp->samples_per_tti, ru->nb_rx); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 ); ru->south_in_cnt++; @@ -613,11 +565,7 @@ void rx_rf(RU_t *ru, resynch=1; } - if(get_softmodem_params()->emulate_rf) { - proc->timestamp_rx = old_ts + fp->samples_per_tti; - } else { - proc->timestamp_rx = ts-ru->ts_offset; - } + proc->timestamp_rx = ts-ru->ts_offset; // AssertFatal(rxs == fp->samples_per_tti, // "rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs); @@ -1229,7 +1177,6 @@ void wakeup_L1s(RU_t *ru) { // pthread_mutex_unlock(&proc->mutex_RU); // LOG_D(PHY,"wakeup eNB top for for subframe %d\n", ru->proc.tti_rx); // ru->eNB_top(eNB_list[0],ru->proc.frame_rx,ru->proc.tti_rx,string); - ru->proc.emulate_rf_busy = 0; } @@ -1497,7 +1444,6 @@ static void *ru_thread_tx( void *param ) { L1_rxtx_proc_t *L1_proc; cpu_set_t cpuset; CPU_ZERO(&cpuset); - char filename[256]; thread_top_init("ru_thread_tx",1,400000,500000,500000); //CPU_SET(5, &cpuset); //pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); @@ -1530,24 +1476,12 @@ static void *ru_thread_tx( void *param ) { // do OFDM if needed if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru,frame_tx,tti_tx); - if(!(ru->emulate_rf)) { //if(!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,tti_tx,timestamp_tx); + // do outgoing fronthaul (south) if needed + if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) + ru->fh_south_out(ru, frame_tx, tti_tx, timestamp_tx); - if (ru->fh_north_out) ru->fh_north_out(ru); - } else { - for (int i=0; inb_tx; i++) { - if(frame_tx == 2) { - sprintf(filename,"txdataF%d_frame%d_sf%d.m",i,frame_tx,tti_tx); - LOG_M(filename,"txdataF_frame",ru->common.txdataF_BF[i],fp->symbols_per_tti*fp->ofdm_symbol_size, 1, 1); - } - - if(frame_tx == 2 && tti_tx==0) { - sprintf(filename,"txdata%d_frame%d.m",i,frame_tx); - LOG_M(filename,"txdata_frame",ru->common.txdata[i],fp->samples_per_tti*10, 1, 1); - } - } - } + if (ru->fh_north_out) + ru->fh_north_out(ru); LOG_D(PHY,"ru_thread_tx: releasing RU TX in %d.%d\n", frame_tx, tti_tx); release_thread(&proc->mutex_eNBs,&proc->instance_cnt_eNBs,"ru_thread_tx"); @@ -1612,7 +1546,6 @@ static void *ru_thread( void *param ) { int ret; cpu_set_t cpuset; CPU_ZERO(&cpuset); - char filename[256]; // set default return value #if defined(PRE_SCD_THREAD) dlsch_ue_select_tbl_in_use = 1; @@ -1625,21 +1558,7 @@ static void *ru_thread( void *param ) { LOG_I(PHY,"thread ru created id=%ld\n", syscall(__NR_gettid)); LOG_I(PHY,"Starting RU %d (%s,%s),\n", ru->idx, NB_functions[ru->function], NB_timing[ru->if_timing]); - if(get_softmodem_params()->emulate_rf) { - phy_init_RU(ru); - - if (setup_RU_buffers(ru)!=0) { - LOG_I(PHY,"Exiting, cannot initialize RU Buffers\n"); - exit(-1); - } - - LOG_I(PHY, "Signaling main thread that RU %d is ready\n",ru->idx); - AssertFatal((ret=pthread_mutex_lock(ru->ru_mutex))==0,"mutex_lock returns %d\n",ret); - *ru->ru_mask &= ~(1<idx); - pthread_cond_signal(ru->ru_cond); - AssertFatal((ret=pthread_mutex_unlock(ru->ru_mutex))==0,"mutex_unlock returns %d\n",ret); - ru->state = RU_RUN; - } else if (ru->has_ctrl_prt == 0) { + if (ru->has_ctrl_prt == 0) { // There is no control port: start everything here LOG_I(PHY, "RU %d has no OAI ctrl port\n",ru->idx); @@ -1695,18 +1614,22 @@ static void *ru_thread( void *param ) { } else wait_sync("ru_thread"); LOG_D(PHY,"RU %d: Got start from control thread\n",ru->idx); - if(!(ru->emulate_rf)) { - if (ru->is_slave == 0) AssertFatal(ru->state == RU_RUN,"ru-%d state = %s != RU_RUN\n",ru->idx,ru_states[ru->state]); - else if (ru->is_slave == 1) AssertFatal(ru->state == RU_SYNC || ru->state == RU_RUN || - ru->state == RU_CHECK_SYNC,"ru %d state = %s != RU_SYNC or RU_RUN or RU_CHECK_SYNC\n",ru->idx,ru_states[ru->state]); + if (ru->is_slave == 0) + AssertFatal(ru->state == RU_RUN, "ru-%d state = %s != RU_RUN\n", ru->idx, ru_states[ru->state]); + else if (ru->is_slave == 1) + AssertFatal(ru->state == RU_SYNC || ru->state == RU_RUN || ru->state == RU_CHECK_SYNC, + "ru %d state = %s != RU_SYNC or RU_RUN or RU_CHECK_SYNC\n", + ru->idx, + ru_states[ru->state]); - // Start RF device if any - if (ru->start_rf) { - if (ru->start_rf(ru) != 0) - AssertFatal(1==0,"Could not start the RF device\n"); - else LOG_I(PHY,"RU %d rf device ready\n",ru->idx); - } else LOG_D(PHY,"RU %d no rf device\n",ru->idx); - } + // Start RF device if any + if (ru->start_rf) { + if (ru->start_rf(ru) != 0) + AssertFatal(1 == 0, "Could not start the RF device\n"); + else + LOG_I(PHY, "RU %d rf device ready\n", ru->idx); + } else + LOG_D(PHY, "RU %d no rf device\n", ru->idx); // if an asnych_rxtx thread exists // wakeup the thread because the devices are ready at this point @@ -1864,26 +1787,13 @@ static void *ru_thread( void *param ) { // do OFDM if needed if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru, proc->frame_tx, proc->tti_tx); - if(!(ru->emulate_rf)) { //if(!emulate_rf){ - // do outgoing fronthaul (south) if needed - if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru, proc->frame_tx, proc->tti_tx, proc->timestamp_tx); + // do outgoing fronthaul (south) if needed + if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) + ru->fh_south_out(ru, proc->frame_tx, proc->tti_tx, proc->timestamp_tx); - if ((ru->fh_north_out) && (ru->state!=RU_CHECK_SYNC)) ru->fh_north_out(ru); - } else { - for (int i=0; inb_tx; i++) { - if(proc->frame_tx == 2) { - sprintf(filename,"txdataF%d_frame%d_sf%d.m",i,proc->frame_tx,proc->tti_tx); - LOG_M(filename,"txdataF_frame",ru->common.txdataF_BF[i],ru->frame_parms->symbols_per_tti*ru->frame_parms->ofdm_symbol_size, 1, 1); - } + if ((ru->fh_north_out) && (ru->state != RU_CHECK_SYNC)) + ru->fh_north_out(ru); - if(proc->frame_tx == 2 && proc->tti_tx==0) { - sprintf(filename,"txdata%d_frame%d.m",i,proc->frame_tx); - LOG_M(filename,"txdata_frame",ru->common.txdata[i],ru->frame_parms->samples_per_tti*10, 1, 1); - } - } - } - - proc->emulate_rf_busy = 0; } #else @@ -1903,12 +1813,11 @@ static void *ru_thread( void *param ) { LOG_I(PHY, "Exiting ru_thread \n"); - if (!(ru->emulate_rf)) { - if (ru->stop_rf != NULL) { - if (ru->stop_rf(ru) != 0) - LOG_E(HW,"Could not stop the RF device\n"); - else LOG_I(PHY,"RU %d rf device stopped\n",ru->idx); - } + if (ru->stop_rf != NULL) { + if (ru->stop_rf(ru) != 0) + LOG_E(HW, "Could not stop the RF device\n"); + else + LOG_I(PHY, "RU %d rf device stopped\n", ru->idx); } return NULL; @@ -2128,12 +2037,12 @@ static void *rf_tx( void *param ) { // do OFDM if needed if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru,proc->frame_tx,proc->tti_tx); - 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,proc->frame_tx,proc->tti_tx,proc->timestamp_tx); + // do outgoing fronthaul (south) if needed + if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) + ru->fh_south_out(ru, proc->frame_tx, proc->tti_tx, proc->timestamp_tx); - if (ru->fh_north_out) ru->fh_north_out(ru); - } + if (ru->fh_north_out) + ru->fh_north_out(ru); } if (release_thread(&proc->mutex_rf_tx,&proc->instance_cnt_rf_tx,"rf_tx") < 0) break; @@ -2205,7 +2114,7 @@ int start_write_thread(RU_t *ru) { void init_RU_proc(RU_t *ru) { int i=0; RU_proc_t *proc; - pthread_attr_t *attr_FH=NULL, *attr_FH1=NULL, *attr_prach=NULL, *attr_asynch=NULL, *attr_synch=NULL, *attr_emulateRF=NULL, *attr_ctrl=NULL, *attr_prach_br=NULL; + pthread_attr_t *attr_FH=NULL, *attr_FH1=NULL, *attr_prach=NULL, *attr_asynch=NULL, *attr_synch=NULL, *attr_ctrl=NULL, *attr_prach_br=NULL; //pthread_attr_t *attr_fep=NULL; LOG_I(PHY,"Initializing RU proc %d (%s,%s),\n",ru->idx,NB_functions[ru->function],NB_timing[ru->if_timing]); proc = &ru->proc; @@ -2215,7 +2124,6 @@ void init_RU_proc(RU_t *ru) { proc->instance_cnt_synch = -1; proc->instance_cnt_FH = -1; proc->instance_cnt_FH1 = -1; - proc->instance_cnt_emulateRF = -1; proc->instance_cnt_asynch_rxtx = -1; proc->instance_cnt_ru = -1; proc->instance_cnt_eNBs = -1; @@ -2232,20 +2140,17 @@ void init_RU_proc(RU_t *ru) { pthread_mutex_init( &proc->mutex_synch,NULL); pthread_mutex_init( &proc->mutex_FH,NULL); pthread_mutex_init( &proc->mutex_FH1,NULL); - pthread_mutex_init( &proc->mutex_emulateRF,NULL); pthread_mutex_init( &proc->mutex_eNBs, NULL); pthread_mutex_init( &proc->mutex_ru,NULL); pthread_cond_init( &proc->cond_prach, NULL); pthread_cond_init( &proc->cond_FH, NULL); pthread_cond_init( &proc->cond_FH1, NULL); - pthread_cond_init( &proc->cond_emulateRF, NULL); pthread_cond_init( &proc->cond_asynch_rxtx, NULL); pthread_cond_init( &proc->cond_synch,NULL); pthread_cond_init( &proc->cond_eNBs, NULL); pthread_cond_init( &proc->cond_ru_thread,NULL); pthread_attr_init( &proc->attr_FH); pthread_attr_init( &proc->attr_FH1); - pthread_attr_init( &proc->attr_emulateRF); pthread_attr_init( &proc->attr_prach); pthread_attr_init( &proc->attr_synch); pthread_attr_init( &proc->attr_asynch_rxtx); @@ -2289,9 +2194,6 @@ void init_RU_proc(RU_t *ru) { pthread_create( &proc->pthread_rf_tx, NULL, rf_tx, (void *)ru ); #endif - if (ru->emulate_rf) - pthread_create( &proc->pthread_emulateRF, attr_emulateRF, emulatedRF_thread, (void *)proc ); - if (get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) pthread_create( &proc->pthread_FH1, attr_FH1, ru_thread_tx, (void *)ru ); diff --git a/executables/lte-softmodem.c b/executables/lte-softmodem.c index 3034512b2c..25a3c25aa9 100644 --- a/executables/lte-softmodem.c +++ b/executables/lte-softmodem.c @@ -138,7 +138,6 @@ RU_t **RCconfig_RU(int nb_RU,int nb_L1_inst,PHY_VARS_eNB ***eNB,uint64_t *ru_mas RU_t **RCconfig_RU(int nb_RU,int nb_L1_inst,PHY_VARS_eNB ***eNB,uint64_t *ru_mask,pthread_mutex_t *ru_mutex,pthread_cond_t *ru_cond); int transmission_mode=1; -int emulate_rf = 0; int numerology = 0; THREAD_STRUCT thread_struct; diff --git a/executables/lte-softmodem.h b/executables/lte-softmodem.h index 8c55f0dc65..db6136c351 100644 --- a/executables/lte-softmodem.h +++ b/executables/lte-softmodem.h @@ -127,7 +127,6 @@ extern int sync_var; extern int transmission_mode; extern double cpuf; -extern int emulate_rf; extern int numerology; extern int usrp_tx_thread; diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 345b58df7e..24870544b8 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -231,6 +231,9 @@ static size_t dump_L1_meas_stats(PHY_VARS_gNB *gNB, RU_t *ru, char *output, size output += print_meas_log(&gNB->dlsch_resource_mapping_stats, "DLSCH resource mapping", NULL, NULL, output,end-output); output += print_meas_log(&gNB->dlsch_precoding_stats, "DLSCH precoding", NULL, NULL, output,end-output); output += print_meas_log(&gNB->phy_proc_rx, "L1 Rx processing", NULL, NULL, output, end - output); + output += print_meas_log(&gNB->ts_deinterleave, "UL segment deinterleaving", NULL, NULL, output, end - output); + output += print_meas_log(&gNB->ts_rate_unmatch, "UL segment rate recovery", NULL, NULL, output, end - output); + output += print_meas_log(&gNB->ts_ldpc_decode, "UL segments decoding", NULL, NULL, output, end - output); output += print_meas_log(&gNB->ul_indication_stats, "UL Indication", NULL, NULL, output, end - output); output += print_meas_log(&gNB->slot_indication_stats, "Slot Indication", NULL, NULL, output, end - output); output += print_meas_log(&gNB->rx_pusch_stats, "PUSCH inner-receiver", NULL, NULL, output, end - output); @@ -288,6 +291,9 @@ void *nrL1_stats_thread(void *param) { reset_meas(&gNB->phy_proc_tx); reset_meas(&gNB->dlsch_encoding_stats); reset_meas(&gNB->phy_proc_rx); + reset_meas(&gNB->ts_deinterleave); + reset_meas(&gNB->ts_rate_unmatch); + reset_meas(&gNB->ts_ldpc_decode); reset_meas(&gNB->ul_indication_stats); reset_meas(&gNB->slot_indication_stats); reset_meas(&gNB->rx_pusch_stats); diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 72bc44bffb..de3a4b7875 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -561,25 +561,6 @@ void fh_if4p5_north_out(RU_t *ru) { stop_meas(&ru->tx_fhaul); } -void *emulatedRF_thread(void *param) { - RU_proc_t *proc = (RU_proc_t *) 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; - wait_sync("emulatedRF_thread"); - - while(!oai_exit) { - nanosleep(&req, (struct timespec *)NULL); - pthread_mutex_lock(&proc->mutex_emulateRF); - ++proc->instance_cnt_emulateRF; - pthread_mutex_unlock(&proc->mutex_emulateRF); - pthread_cond_signal(&proc->cond_emulateRF); - } - - return 0; -} - static void rx_rf(RU_t *ru, int *frame, int *slot) { RU_proc_t *proc = &ru->proc; @@ -600,14 +581,7 @@ static void rx_rf(RU_t *ru, int *frame, int *slot) openair0_timestamp ts; unsigned int rxs; - if(emulate_rf) { - wait_on_condition(&proc->mutex_emulateRF,&proc->cond_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread"); - release_thread(&proc->mutex_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread"); - rxs = samples_per_slot; - ts = old_ts + rxs; - } else { - rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, samples_per_slot, nb); - } + rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, samples_per_slot, nb); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 ); proc->timestamp_rx = ts-ru->ts_offset; @@ -682,10 +656,8 @@ static void rx_rf(RU_t *ru, int *frame, int *slot) *slot = proc->tti_rx; } - if (!emulate_rf) { - metadata mt = {.slot = *slot, .frame = *frame}; - gNBscopeCopyWithMetadata(ru, gNbTimeDomainSamples, rxp[0], sizeof(c16_t), 1, samples_per_slot, 0, &mt); - } + metadata mt = {.slot = *slot, .frame = *frame}; + gNBscopeCopyWithMetadata(ru, gNbTimeDomainSamples, rxp[0], sizeof(c16_t), 1, samples_per_slot, 0, &mt); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, (proc->timestamp_rx+ru->ts_offset)&0xffffffff ); @@ -988,11 +960,8 @@ void ru_tx_func(void *param) { processingData_RU_t *info = (processingData_RU_t *) param; RU_t *ru = info->ru; - NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; int frame_tx = info->frame_tx; int slot_tx = info->slot_tx; - int print_frame = 8; - char filename[40]; // do TX front-end processing if needed (precoding and/or IDFTs) if (ru->feptx_prec) @@ -1002,43 +971,10 @@ 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) { - // 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); - if (ru->fh_north_out) - ru->fh_north_out(ru); - } else { - if(frame_tx == print_frame) { - for (int i = 0; i < ru->nb_tx * ru->num_beams_period; i++) { - if(slot_tx == 0) { - sprintf(filename,"gNBdataF_frame%d_sl%d.m", print_frame, slot_tx); - LOG_M(filename,"txdataF_frame",&ru->gNB_list[0]->common_vars.txdataF[i][0],fp->samples_per_frame_wCP, 1, 1); - sprintf(filename,"tx%ddataF_frame%d_sl%d.m", i, print_frame, slot_tx); - LOG_M(filename,"txdataF_frame",&ru->common.txdataF[i][0],fp->samples_per_frame_wCP, 1, 1); - sprintf(filename,"tx%ddataF_BF_frame%d_sl%d.m", i, print_frame, slot_tx); - LOG_M(filename,"txdataF_BF_frame",&ru->common.txdataF_BF[i][0],fp->samples_per_subframe_wCP, 1, 1); - } - - if(slot_tx == 9) { - sprintf(filename,"tx%ddata_frame%d.m", i, print_frame); - LOG_M(filename,"txdata_frame",&ru->common.txdata[i][0],fp->samples_per_frame, 1, 1); - sprintf(filename,"tx%ddata_frame%d.dat", i, print_frame); - FILE *output_fd = fopen(filename,"w"); - - if (output_fd) { - fwrite(&ru->common.txdata[i][0], - sizeof(int32_t), - fp->samples_per_frame, - output_fd); - fclose(output_fd); - } else { - LOG_E(PHY,"Cannot write to file %s\n",filename); - } - }//if(slot_tx == 9) - }//for (i=0; inb_tx; i++) - }//if(frame_tx == print_frame) - }//else emulate_rf + if (ru->fh_north_asynch_in == NULL && ru->fh_south_out) + ru->fh_south_out(ru, frame_tx, slot_tx, info->timestamp_tx); + if (ru->fh_north_out) + ru->fh_north_out(ru); } /* @brief wait for the next RX TTI to be free @@ -1110,54 +1046,52 @@ 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) { - // Start IF device if any - if (ru->nr_start_if) { - LOG_I(PHY, "starting transport\n"); - 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) { - /* it seems the device can "overwrite" (request?) to set the callbacks - * for fh_south_in()/fh_south_out() differently */ - void *t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_in"); - if (t != NULL) - ru->fh_south_in = t; - t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_out"); - if (t != NULL) - ru->fh_south_out = t; - } else { - malloc_IF4p5_buffer(ru); - } - - 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); - } - - 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) { - if (ru->if_south == LOCAL_RF) - ret = connect_rau(ru); - else - ret = attach_rru(ru); - AssertFatal(ret==0,"Cannot connect to remote radio\n"); - } + // Start IF device if any + if (ru->nr_start_if) { + LOG_I(PHY, "starting transport\n"); + 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) { + /* it seems the device can "overwrite" (request?) to set the callbacks + * for fh_south_in()/fh_south_out() differently */ + void *t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_in"); + if (t != NULL) + ru->fh_south_in = t; + t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_out"); + if (t != NULL) + ru->fh_south_out = t; + } else { + malloc_IF4p5_buffer(ru); } - else if (ru->if_south == LOCAL_RF) { // configure RF parameters only - ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); - AssertFatal(ret==0,"Cannot connect to local radio\n"); + + 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); } + + 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) { + if (ru->if_south == LOCAL_RF) + ret = connect_rau(ru); + else + ret = attach_rru(ru); + + AssertFatal(ret == 0, "Cannot connect to remote radio\n"); + } + + } else if (ru->if_south == LOCAL_RF) { // configure RF parameters only + ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); + AssertFatal(ret==0,"Cannot connect to local radio\n"); } if (setup_RU_buffers(ru)!=0) { @@ -1172,23 +1106,23 @@ void *ru_thread(void *param) pthread_mutex_unlock(&RC.ru_mutex); wait_sync("ru_thread"); - if(!emulate_rf) { - // 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); + // 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"); - } + 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"); } } } @@ -1344,13 +1278,9 @@ int start_write_thread(RU_t *ru) { return ru->rfdevice.trx_write_init(&ru->rfdevice); } -void init_RU_proc(RU_t *ru) { - ru->proc = (RU_proc_t){.ru = ru, .instance_cnt_emulateRF = -1, .first_rx = 1, .first_tx = 1}; - pthread_mutex_init(&ru->proc.mutex_emulateRF, NULL); - pthread_cond_init(&ru->proc.cond_emulateRF, NULL); - - if(emulate_rf) - threadCreate(&ru->proc.pthread_emulateRF, emulatedRF_thread, (void *)&ru->proc, "emulateRF", -1, OAI_PRIORITY_RT); +void init_RU_proc(RU_t *ru) +{ + ru->proc = (RU_proc_t){.ru = ru, .first_rx = 1, .first_tx = 1}; LOG_I(PHY, "Initialized RU proc %d (%s,%s),\n", ru->idx, NB_functions[ru->function], NB_timing[ru->if_timing]); } diff --git a/executables/nr-softmodem-common.h b/executables/nr-softmodem-common.h index 3ab6d1e73d..61823d43cd 100644 --- a/executables/nr-softmodem-common.h +++ b/executables/nr-softmodem-common.h @@ -133,7 +133,6 @@ extern int sync_var; extern int transmission_mode; extern double cpuf; -extern int emulate_rf; extern int numerology; extern int usrp_tx_thread; void wait_gNBs(void); diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index c3875bf267..d8df770cb8 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -118,7 +118,6 @@ double rx_gain_off = 0.0; static int tx_max_power[MAX_NUM_CCs]; /* = {0,0}*/; int chain_offset = 0; -int emulate_rf = 0; int numerology = 0; double cpuf; diff --git a/executables/softmodem-common.h b/executables/softmodem-common.h index 33d4f4cf04..d122b1a1d5 100644 --- a/executables/softmodem-common.h +++ b/executables/softmodem-common.h @@ -96,7 +96,6 @@ extern "C" #define CONFIG_HLP_NUMEROLOGY "adding numerology for 5G\n" #define CONFIG_HLP_BAND "band index\n" -#define CONFIG_HLP_EMULATE_RF "Emulated RF enabled(disable by defult)\n" #define CONFIG_HLP_PARALLEL_CMD "three config for level of parallelism 'PARALLEL_SINGLE_THREAD', 'PARALLEL_RU_L1_SPLIT', or 'PARALLEL_RU_L1_TRX_SPLIT'\n" #define CONFIG_HLP_WORKER_CMD "two option for worker 'WORKER_DISABLE' or 'WORKER_ENABLE'\n" #define CONFIG_HLP_USRP_THREAD "having extra thead for usrp tx\n" @@ -128,7 +127,6 @@ extern "C" #define CHAIN_OFFSET softmodem_params.chain_offset #define NUMEROLOGY softmodem_params.numerology #define BAND softmodem_params.band -#define EMULATE_RF softmodem_params.emulate_rf #define CLOCK_SOURCE softmodem_params.clock_source #define TIMING_SOURCE softmodem_params.timing_source #define TUNE_OFFSET softmodem_params.tune_offset @@ -164,7 +162,6 @@ extern int usrp_tx_thread; {"q" , CONFIG_HLP_STMON, PARAMFLAG_BOOL, .iptr=&cpu_meas_enabled, .defintval=0, TYPE_INT, 0}, \ {"numerology" , CONFIG_HLP_NUMEROLOGY, 0, .iptr=&NUMEROLOGY, .defintval=1, TYPE_INT, 0}, \ {"band" , CONFIG_HLP_BAND, 0, .iptr=&BAND, .defintval=78, TYPE_INT, 0}, \ - {"emulate-rf" , CONFIG_HLP_EMULATE_RF, PARAMFLAG_BOOL, .iptr=&EMULATE_RF, .defintval=0, TYPE_INT, 0}, \ {"parallel-config", CONFIG_HLP_PARALLEL_CMD, 0, .strptr=¶llel_config, .defstrval=NULL, TYPE_STRING, 0}, \ {"worker-config", CONFIG_HLP_WORKER_CMD, 0, .strptr=&worker_config, .defstrval=NULL, TYPE_STRING, 0}, \ {"noS1", CONFIG_HLP_NOS1, PARAMFLAG_BOOL, .uptr=&noS1, .defintval=0, TYPE_UINT, 0}, \ @@ -217,7 +214,6 @@ extern int usrp_tx_thread; { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ - { .s5 = { NULL } }, \ { .s3a = { config_checkstr_assign_integer, \ {"MONOLITHIC", "PNF", "VNF", "AERIAL","UE_STUB_PNF","UE_STUB_OFFNET","STANDALONE_PNF"}, \ {NFAPI_MONOLITHIC, NFAPI_MODE_PNF, NFAPI_MODE_VNF, NFAPI_MODE_AERIAL,NFAPI_UE_STUB_PNF,NFAPI_UE_STUB_OFFNET,NFAPI_MODE_STANDALONE_PNF}, \ @@ -320,7 +316,6 @@ typedef struct { int phy_test; int do_ra; uint8_t sl_mode; - int emulate_rf; int chain_offset; int numerology; int band; diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.c index 62a20ef822..815ec9ce26 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.c @@ -815,6 +815,10 @@ static int pmd_lcore_ldpc_dec(void *arg) AssertFatal(ret == 0, "Allocation failed for %d ops", num_segments); set_ldpc_dec_op(ops_enq, bufs->inputs, bufs->hard_outputs, bufs->harq_outputs, nrLDPC_slot_decoding_parameters); + // Start timer + // We report timing only once in (0,0) since the timers are merged at the end + start_meas(&nrLDPC_slot_decoding_parameters->TBs[0].segments[0].ts_ldpc_decode); + uint16_t enq = 0, deq = 0; while (enq < num_segments) { uint16_t num_to_enq = num_segments - enq; @@ -828,6 +832,10 @@ static int pmd_lcore_ldpc_dec(void *arg) DevAssert(time_out <= TIME_OUT_POLL); } + // Stop timer + // We report timing only once in (0,0) since the timers are merged at the end + stop_meas(&nrLDPC_slot_decoding_parameters->TBs[0].segments[0].ts_ldpc_decode); + if (deq == enq) { ret = retrieve_ldpc_dec_op(ops_deq, nrLDPC_slot_decoding_parameters); AssertFatal(ret == 0, "LDPC offload decoder failed!"); diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c index 667c7146b0..239b6f2f29 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c @@ -305,6 +305,10 @@ int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, LOG_D(PHY, "ULSCH %d in error\n", ULSCH_id); } offset += ((harq_process->K >> 3) - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0)); + + merge_meas(&phy_vars_gNB->ts_deinterleave, &nrLDPC_segment_decoding_parameters.ts_deinterleave); + merge_meas(&phy_vars_gNB->ts_rate_unmatch, &nrLDPC_segment_decoding_parameters.ts_rate_unmatch); + merge_meas(&phy_vars_gNB->ts_ldpc_decode, &nrLDPC_segment_decoding_parameters.ts_ldpc_decode); } } diff --git a/openair1/PHY/defs_RU.h b/openair1/PHY/defs_RU.h index a2c39852f5..e72465c4a9 100644 --- a/openair1/PHY/defs_RU.h +++ b/openair1/PHY/defs_RU.h @@ -255,7 +255,6 @@ typedef struct RU_proc_t_s { int instance_cnt_feptx; /// \internal This variable is protected by \ref mutex_ru_thread int instance_cnt_ru; - int instance_cnt_emulateRF; /// pthread structure for RU FH processing thread pthread_t pthread_FH; pthread_t pthread_FH1; @@ -271,8 +270,6 @@ typedef struct RU_proc_t_s { pthread_t pthread_fep[8]; /// pthread struct for RU TX FEP worker thread pthread_t pthread_feptx; - /// pthread struct for emulated RF - pthread_t pthread_emulateRF; /// pthread structure for asychronous RX/TX processing thread pthread_t pthread_asynch_rxtx; /// flag to indicate first RX acquisition @@ -296,8 +293,6 @@ typedef struct RU_proc_t_s { pthread_attr_t attr_fep; /// pthread attributes for worker feptx thread pthread_attr_t attr_feptx; - /// pthread attributes for emulated RF - pthread_attr_t attr_emulateRF; /// scheduling parameters for RU FH thread struct sched_param sched_param_FH; struct sched_param sched_param_FH1; @@ -324,8 +319,6 @@ typedef struct RU_proc_t_s { pthread_cond_t cond_fep[8]; /// condition varible for RU TX FEP thread pthread_cond_t cond_feptx; - /// condition varible for emulated RF - pthread_cond_t cond_emulateRF; /// condition variable for eNB signal pthread_cond_t cond_eNBs; /// condition variable for gNB signal @@ -353,8 +346,6 @@ typedef struct RU_proc_t_s { pthread_mutex_t mutex_feptx; /// mutex for ru_thread pthread_mutex_t mutex_ru; - /// mutex for emulated RF thread - pthread_mutex_t mutex_emulateRF; /// symbol mask for IF4p5 reception per subframe uint32_t symbol_mask[10]; /// time measurements for each subframe @@ -394,7 +385,6 @@ typedef struct RU_proc_t_s { /// pipeline ready state int ru_rx_ready; int ru_tx_ready; - int emulate_rf_busy; /// structure for precoding thread RU_prec_t prec[16]; @@ -407,7 +397,6 @@ typedef enum { REMOTE_IF4p5 =3, REMOTE_IF1pp =4, MAX_RU_IF_TYPES =5 - //EMULATE_RF =6 } RU_if_south_t; @@ -453,8 +442,6 @@ typedef struct RU_t_s { node_function_t function; /// Ethernet parameters for fronthaul interface eth_params_t eth_params; - /// flag to indicate RF emulation mode - int emulate_rf; /// numerology index int numerology; /// flag to indicate the RU is in sync with a master reference diff --git a/openair1/PHY/defs_eNB.h b/openair1/PHY/defs_eNB.h index 98d1080ee3..ef1db2e05f 100644 --- a/openair1/PHY/defs_eNB.h +++ b/openair1/PHY/defs_eNB.h @@ -255,11 +255,6 @@ typedef struct { tpool_t *threadPool; int nbDecode; notifiedFIFO_t *respDecode; - pthread_mutex_t mutex_emulateRF; - int instance_cnt_emulateRF; - pthread_t pthread_emulateRF; - pthread_attr_t attr_emulateRF; - pthread_cond_t cond_emulateRF; int first_rx; } L1_rxtx_proc_t; diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index ad17c243ae..987f77d953 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -521,6 +521,9 @@ typedef struct PHY_VARS_gNB_s { time_stats_t slot_indication_stats; time_stats_t schedule_response_stats; time_stats_t ulsch_decoding_stats; + time_stats_t ts_deinterleave; + time_stats_t ts_rate_unmatch; + time_stats_t ts_ldpc_decode; time_stats_t ulsch_deinterleaving_stats; time_stats_t ulsch_channel_estimation_stats; time_stats_t pusch_channel_estimation_antenna_processing_stats; diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 5e6140db9d..a593a0dfb4 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -90,7 +90,6 @@ static int cmpdouble(const void *p1, const void *p2) { } RAN_CONTEXT_t RC; -int emulate_rf = 0; void handler(int sig) { void *array[10]; size_t size; diff --git a/openair1/SIMULATION/LTE_PHY/mbmssim.c b/openair1/SIMULATION/LTE_PHY/mbmssim.c index ac50bf62bd..dac151e4fe 100644 --- a/openair1/SIMULATION/LTE_PHY/mbmssim.c +++ b/openair1/SIMULATION/LTE_PHY/mbmssim.c @@ -89,8 +89,6 @@ int n_rx_dropped = 0; /*!< \brief initial max process time for rx */ THREAD_STRUCT thread_struct; -int emulate_rf = 0; - void handler(int sig) { void *array[10]; size_t size; diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index e355ca51c2..0f21fdb145 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -1341,7 +1341,7 @@ printf("%d\n", slot); printStatIndent3(&gNB->tprep,"DLSCH LDPC input preparation time"); printStatIndent3(&gNB->tparity,"DLSCH LDPC parity generation time"); printStatIndent3(&gNB->toutput,"DLSCH LDPC output generation time"); - printStatIndent3(&gNB->dlsch_rate_matching_stats,"DLSCH Rate Mataching time"); + printStatIndent3(&gNB->dlsch_rate_matching_stats,"DLSCH Rate Matching time"); printStatIndent3(&gNB->dlsch_interleaving_stats, "DLSCH Interleaving time"); printStatIndent2(&gNB->dlsch_modulation_stats,"DLSCH modulation time"); printStatIndent2(&gNB->dlsch_scrambling_stats, "DLSCH scrambling time"); diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index b5bd02aefd..e5361a3e2d 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -1028,6 +1028,9 @@ int main(int argc, char *argv[]) reset_meas(&gNB->rx_pusch_init_stats); reset_meas(&gNB->rx_pusch_symbol_processing_stats); reset_meas(&gNB->ulsch_decoding_stats); + reset_meas(&gNB->ts_deinterleave); + reset_meas(&gNB->ts_rate_unmatch); + reset_meas(&gNB->ts_ldpc_decode); reset_meas(&gNB->ulsch_channel_estimation_stats); reset_meas(&gNB->pusch_channel_estimation_antenna_processing_stats); reset_meas(&gNB->rx_srs_stats); @@ -1589,6 +1592,9 @@ int main(int argc, char *argv[]) printStatIndent2(&gNB->rx_pusch_init_stats, "RX PUSCH Initialization time"); printStatIndent2(&gNB->rx_pusch_symbol_processing_stats, "RX PUSCH Symbol Processing time"); printStatIndent(&gNB->ulsch_decoding_stats,"ULSCH total decoding time"); + printStatIndent2(&gNB->ts_deinterleave, "ULSCH segment deinterleaving time"); + printStatIndent2(&gNB->ts_rate_unmatch, "ULSCH segment rate recovery time"); + printStatIndent2(&gNB->ts_ldpc_decode, "ULSCH segments decoding time"); printf("\nUE TX\n"); for (int i = PHY_PROC_TX; i <= OFDM_MOD_STATS; i++) { diff --git a/radio/CMakeLists.txt b/radio/CMakeLists.txt index e68c84ec90..1159416afa 100644 --- a/radio/CMakeLists.txt +++ b/radio/CMakeLists.txt @@ -42,3 +42,8 @@ add_boolean_option(OAI_VRTSIM ON "Activate OAI's shared memory radio driver" OFF if(OAI_VRTSIM) add_subdirectory(vrtsim) endif() + +add_boolean_option(OAI_RF_EMULATOR ON "Activate OAI's RF emulator" OFF) +if(OAI_RF_EMULATOR) + add_subdirectory(emulator) +endif() diff --git a/radio/emulator/CMakeLists.txt b/radio/emulator/CMakeLists.txt new file mode 100644 index 0000000000..42b196ee95 --- /dev/null +++ b/radio/emulator/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(rf_emulator MODULE rf_emulator.c) +set_target_properties(rf_emulator PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +target_link_libraries(rf_emulator PRIVATE noise_device) +add_dependencies(rf_emulator generate_T) diff --git a/radio/emulator/README.md b/radio/emulator/README.md new file mode 100644 index 0000000000..b3b58ba6a7 --- /dev/null +++ b/radio/emulator/README.md @@ -0,0 +1,25 @@ +# RF emulator library + +The RF emulator is a simple network stack terminator on the RF side. +It is meant to run the network stack without real radio and without RF simulation. +It simply drops TX signal and generate noise as an RX signal. +It can be used in `phy-test` mode to simply benchmark the network stack in a determined scenario. +It synchronizes the network stack on the real time clock of the host to guarantee a realistic behavior of the network stack. +It detects and report late samples reads and writes to assess the real time behavior of the network stack. + +## Building + +`librf_emulator.so` is built by default by the `build_oai.sh` script. +It is then located in the root build directory (usually `cmake_targets/ran_build/build`). + +## Usage + +### Enabling `rf_emulator` + +Use the option `--device.name rf_emulator` of the softmodem to use the RF emulator. + +### Options + +Two options are available to configure the RF emulator: +* `--rf_emulator.enable_noise ` Enables (enable = 1) or disables (enable = 0) noise generation on RX. By default noise generation is enabled. +* `--rf_emulator.noise_level_dBFS ` Sets the level of noise generated in dB. If omitted no noise is generated. diff --git a/radio/emulator/rf_emulator.c b/radio/emulator/rf_emulator.c new file mode 100644 index 0000000000..861daab2ba --- /dev/null +++ b/radio/emulator/rf_emulator.c @@ -0,0 +1,369 @@ +/* + * 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 radio/emulator/rf_emulator.c + * \brief RF library that does nothing to be used in benchmarks with phy-test without RF + */ + +#include +#include + +#include +#include +#include "common/utils/threadPool/pthread_utils.h" +#include "common_lib.h" +#include "radio/vrtsim/noise_device.h" +#include "simde/x86/avx512.h" +#include "SIMULATION/TOOLS/sim.h" + +#define RF_EMULATOR_SECTION "rf_emulator" +// clang-format off +#define RF_EMULATOR_PARAMS_DESC \ + { \ + {"enable_noise", "Enable noise injection", 0, .iptr = &emulator_state->enable_noise, .defintval = 1, TYPE_INT, 0},\ + {"noise_level_dBFS", "Noise level", 0, .iptr = &emulator_state->noise_level_dBFS, .defintval = INVALID_DBFS_VALUE, TYPE_INT, 0},\ + }; +// clang-format on + +// structures and timing thread job for timing +typedef struct { + uint64_t timestamp; + pthread_mutex_t mutex; + pthread_cond_t cond; + uint64_t late_reads; + uint64_t late_writes; +} emulator_timestamp_t; + +typedef struct { + uint64_t last_received_sample; + double timescale; + double sample_rate; + emulator_timestamp_t emulator_timestamp; + pthread_t timing_thread; + bool run_timing_thread; + int enable_noise; + int noise_level_dBFS; +} emulator_state_t; + +static void *emulator_timing_job(void *arg) +{ + emulator_state_t *emulator_state = (emulator_state_t *)arg; + struct timespec timestamp; + if (clock_gettime(CLOCK_REALTIME, ×tamp)) { + LOG_E(UTIL, "clock_gettime failed\n"); + exit(1); + } + double leftover_samples = 0; + while (emulator_state->run_timing_thread) { + struct timespec current_time; + if (clock_gettime(CLOCK_REALTIME, ¤t_time)) { + LOG_E(UTIL, "clock_gettime failed\n"); + exit(1); + } + + emulator_timestamp_t *emulator_timestamp = &emulator_state->emulator_timestamp; + if (current_time.tv_sec != timestamp.tv_sec) { + if (emulator_timestamp->late_reads != 0) { + LOG_W(HW, "%ld RF reads were late\n", emulator_timestamp->late_reads); + } + emulator_timestamp->late_reads = 0; + if (emulator_timestamp->late_writes != 0) { + LOG_W(HW, "%ld RF writes were late\n", emulator_timestamp->late_writes); + } + emulator_timestamp->late_writes = 0; + } + + uint64_t diff = (current_time.tv_sec - timestamp.tv_sec) * 1000000000 + (current_time.tv_nsec - timestamp.tv_nsec); + timestamp = current_time; + double samples_to_produce = emulator_state->sample_rate * emulator_state->timescale * diff / 1e9; + + // Attempt to correct compounding rounding error + leftover_samples += samples_to_produce - (uint64_t)samples_to_produce; + if (leftover_samples > 1.0f) { + samples_to_produce += 1; + leftover_samples -= 1; + } + + mutexlock(emulator_timestamp->mutex); + emulator_timestamp->timestamp += samples_to_produce; + condbroadcast(emulator_timestamp->cond); + mutexunlock(emulator_timestamp->mutex); + + usleep(1); + } + return 0; +} + +/*! \brief Called to start the RF transceiver. Return 0 if OK, < 0 if error + * \param device pointer to the device structure specific to the RF hardware target + */ +static int emulator_start(openair0_device *device) +{ + // Start the timing thread and the noise device + emulator_state_t *emulator_state = (emulator_state_t *)device->priv; + if (!emulator_state->run_timing_thread) { + if (emulator_state->enable_noise > 0) { + float noise_level = emulator_state->noise_level_dBFS == INVALID_DBFS_VALUE + ? 0.0f + : (32767.0 / powf(10.0, .05 * -(emulator_state->noise_level_dBFS))); + init_noise_device(noise_level); + LOG_I(HW, "Using noise level with %d dBFS/%f\n", emulator_state->noise_level_dBFS, noise_level); + } + + emulator_timestamp_t *emulator_timestamp = &emulator_state->emulator_timestamp; + memset(emulator_timestamp, 0, sizeof(emulator_timestamp_t)); + + pthread_mutexattr_t mutex_attr; + pthread_condattr_t cond_attr; + int ret = pthread_mutexattr_init(&mutex_attr); + AssertFatal(ret == 0, "pthread_mutexattr_init() failed: errno %d, %s\n", errno, strerror(errno)); + + ret = pthread_condattr_init(&cond_attr); + AssertFatal(ret == 0, "pthread_condattr_init() failed: errno %d, %s\n", errno, strerror(errno)); + + ret = pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED); + AssertFatal(ret == 0, "pthread_mutexattr_setpshared() failed: errno %d, %s\n", errno, strerror(errno)); + + ret = pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED); + AssertFatal(ret == 0, "pthread_condattr_setpshared() failed: errno %d, %s\n", errno, strerror(errno)); + + ret = pthread_mutex_init(&emulator_timestamp->mutex, &mutex_attr); + AssertFatal(ret == 0, "pthread_mutex_init() failed: errno %d, %s\n", errno, strerror(errno)); + + ret = pthread_cond_init(&emulator_timestamp->cond, &cond_attr); + AssertFatal(ret == 0, "pthread_cond_init() failed: errno %d, %s\n", errno, strerror(errno)); + + emulator_state->run_timing_thread = true; + ret = pthread_create(&emulator_state->timing_thread, NULL, emulator_timing_job, emulator_state); + AssertFatal(ret == 0, "pthread_create() failed: errno: %d, %s\n", errno, strerror(errno)); + } + + return 0; +} + +/*! \brief print the RF statistics + * \param device pointer to the device structure specific to the RF hardware target + * \returns 0 on success + */ +int emulator_get_stats(openair0_device *device) +{ + return (0); +} + +/*! \brief Reset the RF statistics + * \param device pointer to the device structure specific to the RF hardware target + * \returns 0 on success + */ +int emulator_reset_stats(openair0_device *device) +{ + return (0); +} + +/*! \brief Terminate operation of the RF transceiver -- free all associated resources (if any) + * \param pointer to the device structure specific to the RF hardware target + */ +static void emulator_end(openair0_device *device) +{ + // Stop the timing thread and the noise device + emulator_state_t *emulator_state = (emulator_state_t *)device->priv; + if (emulator_state->run_timing_thread) { + emulator_state->run_timing_thread = false; + int ret = pthread_join(emulator_state->timing_thread, NULL); + AssertFatal(ret == 0, "pthread_join() failed: errno: %d, %s\n", errno, strerror(errno)); + if (emulator_state->enable_noise > 0) { + free_noise_device(); + } + } +} + +/*! \brief Stop RF + * \param device pointer to the device structure specific to the RF hardware target + */ +int emulator_stop(openair0_device *device) +{ + return (0); +} + +/*! \brief Set Gains (TX/RX) + * \param device pointer to the device structure specific to the RF hardware target + * \param openair0_cfg RF frontend parameters set by application + * \returns 0 in success + */ +int emulator_set_gains(openair0_device *device, openair0_config_t *openair0_cfg) +{ + return (0); +} + +/*! \brief Set frequencies (TX/RX). + * \param device pointer to the device structure specific to the RF hardware target + * \param openair0_cfg RF frontend parameters set by application + * \returns 0 in success + */ +int emulator_set_freq(openair0_device *device, openair0_config_t *openair0_cfg) +{ + return (0); +} + +int emulator_write_init(openair0_device *device) +{ + return (0); +} + +/*! \brief Called to send samples to the RF target + * \param device pointer to the device structure specific to the RF hardware target + * \param timestamp The timestamp at which the first sample MUST be sent + * \param buff Buffer which holds the samples + * \param nsamps number of samples to be sent + * \param nbAnt number of antennas + * \param flags flags must be set to true if timestamp parameter needs to be applied + */ +static int emulator_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int nbAnt, int flags) +{ + emulator_state_t *emulator_state = (emulator_state_t *)device->priv; + + // timestamp in the past + emulator_timestamp_t *emulator_timestamp = &emulator_state->emulator_timestamp; + uint64_t current_timestamp = emulator_timestamp->timestamp; + if (timestamp < current_timestamp) { + mutexlock(emulator_timestamp->mutex); + emulator_timestamp->late_writes++; + mutexunlock(emulator_timestamp->mutex); + } + + return 0; +} + +/*! \brief Store noise in the buffer buff + * \param[out] buff A buffer for received samples. + * The buffers must be large enough to hold the number of samples \ref nsamps. + * \param nsamps Number of samples. One sample is 2 byte I + 2 byte Q => 4 byte. + */ +static void read_noise(void *buff, int nsamps) +{ + int aligned_nsamps = ceil_mod(nsamps, (512 / 8) / sizeof(cf_t)); + cf_t samples[aligned_nsamps] __attribute__((aligned(64))); + // Apply noise from global settings + get_noise_vector((float *)samples, nsamps * 2); + + // Convert to c16_t + c16_t samples_out[aligned_nsamps] __attribute__((aligned(64))); +#if defined(__AVX512F__) + for (int i = 0; i < aligned_nsamps / 8; i++) { + simde__m512 *in = (simde__m512 *)&samples[i * 8]; + simde__m256i *out = (simde__m256i *)&samples_out[i * 8]; + *out = simde_mm512_cvtsepi32_epi16(simde_mm512_cvtps_epi32(*in)); + } +#elif defined(__AVX2__) + for (int i = 0; i < aligned_nsamps / 4; i++) { + simde__m256 *in = (simde__m256 *)&samples[i * 4]; + simde__m128i *out = (simde__m128i *)&samples_out[i * 4]; + *out = simde_mm256_cvtsepi32_epi16(simde_mm256_cvtps_epi32(*in)); + } +#else + for (int i = 0; i < nsamps; i++) { + samples_out[i].r = lroundf(samples[i].r); + samples_out[i].i = lroundf(samples[i].i); + } +#endif + memcpy(buff, samples_out, nsamps * sizeof(c16_t)); +} + +/*! \brief Receive samples from hardware. + * Read \ref nsamps samples from each channel to buffers. buff[0] is the array for + * the first channel. + * \param[out] ptimestamp time at which the first sample was received. + * \param device pointer to the device structure specific to the RF hardware target + * \param[out] ptimestamp the time at which the first sample was received. + * \param[out] buff An array of pointers to buffers for received samples. The buffers must be large enough to hold the number of + * samples \ref nsamps. \param nsamps Number of samples. One sample is 2 byte I + 2 byte Q => 4 byte. + * \param nbAnt number of antennas + * \returns the number of samples read + */ +static int emulator_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int nbAnt) +{ + emulator_state_t *emulator_state = (emulator_state_t *)device->priv; + + emulator_timestamp_t *emulator_timestamp = &emulator_state->emulator_timestamp; + uint64_t timestamp = emulator_state->last_received_sample + nsamps; + uint64_t current_timestamp = emulator_timestamp->timestamp; + if (current_timestamp < timestamp) { + mutexlock(emulator_timestamp->mutex); + while (current_timestamp < timestamp) { + condwait(emulator_timestamp->cond, emulator_timestamp->mutex); + current_timestamp = emulator_timestamp->timestamp; + } + mutexunlock(emulator_timestamp->mutex); + } else { + mutexlock(emulator_timestamp->mutex); + emulator_timestamp->late_reads++; + mutexunlock(emulator_timestamp->mutex); + } + *ptimestamp = emulator_state->last_received_sample; + emulator_state->last_received_sample += nsamps; + + if (emulator_state->enable_noise > 0) { + for (int i = 0; i < nbAnt; i++) { + read_noise(buff[i], nsamps); + } + } else { + for (int i = 0; i < nbAnt; i++) { + memset(buff[i], 0, nsamps * sizeof(c16_t)); + } + } + + return nsamps; +} + +static void emulator_readconfig(emulator_state_t *emulator_state) +{ + paramdef_t emulator_params[] = RF_EMULATOR_PARAMS_DESC; + int ret = config_get(config_get_if(), emulator_params, sizeofArray(emulator_params), RF_EMULATOR_SECTION); + AssertFatal(ret >= 0, "configuration couldn't be performed\n"); +} + +int device_init(openair0_device *device, openair0_config_t *openair0_cfg) +{ + LOG_I(HW, "This is emulator RF that does nothing\n"); + + emulator_state_t *emulator_state = calloc_or_fail(1, sizeof(emulator_state_t)); + emulator_state->last_received_sample = 0; + emulator_state->timescale = 1.0; + emulator_state->sample_rate = openair0_cfg->sample_rate; + emulator_state->run_timing_thread = false; + + device->priv = emulator_state; + device->openair0_cfg = openair0_cfg; + device->trx_start_func = emulator_start; + device->trx_get_stats_func = emulator_get_stats; + device->trx_reset_stats_func = emulator_reset_stats; + device->trx_end_func = emulator_end; + device->trx_stop_func = emulator_stop; + device->trx_set_freq_func = emulator_set_freq; + device->trx_set_gains_func = emulator_set_gains; + device->trx_write_init = emulator_write_init; + device->type = RFSIMULATOR; + device->trx_write_func = emulator_write; + device->trx_read_func = emulator_read; + + emulator_readconfig(emulator_state); + + return 0; +} diff --git a/radio/vrtsim/CMakeLists.txt b/radio/vrtsim/CMakeLists.txt index 9ac1555099..c5ee458666 100644 --- a/radio/vrtsim/CMakeLists.txt +++ b/radio/vrtsim/CMakeLists.txt @@ -1,6 +1,8 @@ -add_library(vrtsim MODULE vrtsim.c noise_device.c) +add_library(noise_device STATIC noise_device.c) + +add_library(vrtsim MODULE vrtsim.c) set_target_properties(vrtsim PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -target_link_libraries(vrtsim PRIVATE SIMU shm_td_iq_channel actor) +target_link_libraries(vrtsim PRIVATE SIMU shm_td_iq_channel actor noise_device) add_dependencies(vrtsim generate_T) add_boolean_option(OAI_VRTSIM_TAPS_CLIENT OFF "Enable taps client" ON)