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)