Merge remote-tracking branch 'origin/rf_emulator_and_timers_fix' into integration_2025_w34 (!3589)
RF emulator and improvements of the timers RF emulator: Add an RF library emulating a real device without the need of a real device. This is thought to enable using phy-test without requiring a radio device or channel simulation. The library synchronizes on the real time clock, drops TX and generate noise on RX. Noise generation can be disabled and the noise level configured. Timers improvements: - Fix standard deviation for merged timers - Add display of ULSCH decoding timers - Add decoding timer in AAL
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
<!--
|
||||
|
||||
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
|
||||
|
||||
-->
|
||||
<testCaseList>
|
||||
<htmlTabRef>gNB-PHY-Test-100-2x2-RFemu</htmlTabRef>
|
||||
<htmlTabName>Timing phytest 100 MHz 2x2 RFemulator</htmlTabName>
|
||||
<htmlTabIcon>tasks</htmlTabIcon>
|
||||
<TestCaseRequestedList>
|
||||
100000 390101 000001 390109 200000
|
||||
</TestCaseRequestedList>
|
||||
<TestCaseExclusionList></TestCaseExclusionList>
|
||||
<testCase id="100000">
|
||||
<class>Custom_Command</class>
|
||||
<desc>Disable Sleep States</desc>
|
||||
<node>caracal</node>
|
||||
<command>sudo cpupower idle-set -D 0</command>
|
||||
</testCase>
|
||||
<testCase id="200000">
|
||||
<class>Custom_Command</class>
|
||||
<always_exec>true</always_exec>
|
||||
<desc>Enable Sleep States</desc>
|
||||
<node>caracal</node>
|
||||
<command>sudo cpupower idle-set -E</command>
|
||||
</testCase>
|
||||
|
||||
<testCase id="390101">
|
||||
<class>Initialize_eNB</class>
|
||||
<desc>Initialize gNB USRP</desc>
|
||||
<node>caracal</node>
|
||||
<Initialize_eNB_args>-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</Initialize_eNB_args>
|
||||
<rt_stats_cfg>datalog_rt_stats.100.2x2.yaml</rt_stats_cfg>
|
||||
<air_interface>NR</air_interface>
|
||||
<cmd_prefix>numactl --cpunodebind=netdev:enp94s0f0np0 --membind=netdev:enp94s0f0np0</cmd_prefix>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000001">
|
||||
<class>IdleSleep</class>
|
||||
<desc>Sleep</desc>
|
||||
<idle_sleep_time_in_sec>60</idle_sleep_time_in_sec>
|
||||
</testCase>
|
||||
|
||||
|
||||
<testCase id="390109">
|
||||
<class>Terminate_eNB</class>
|
||||
<node>caracal</node>
|
||||
<always_exec>true</always_exec>
|
||||
<desc>Terminate gNB</desc>
|
||||
<air_interface>NR</air_interface>
|
||||
</testCase>
|
||||
|
||||
</testCaseList>
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
+39
-137
@@ -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; i<ru->nb_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<<ru->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; i<ru->nb_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 );
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
+69
-139
@@ -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; i<ru->nb_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]);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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!");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
@@ -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 <enable>` Enables (enable = 1) or disables (enable = 0) noise generation on RX. By default noise generation is enabled.
|
||||
* `--rf_emulator.noise_level_dBFS <noise_level>` Sets the level of noise generated in dB. If omitted no noise is generated.
|
||||
@@ -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 <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <common/utils/assertions.h>
|
||||
#include <common/utils/LOG/log.h>
|
||||
#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;
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user