Merge remote-tracking branch 'origin/if5_ECPRI_rework' into integration_2022_wk38

This commit is contained in:
Robert Schmidt
2022-09-22 18:56:59 +02:00
36 changed files with 1153 additions and 2450 deletions
-1
View File
@@ -1541,7 +1541,6 @@ set(PHY_SRC
set(PHY_SRC_RU
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/if4_tools.c
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/if5_tools.c
${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/drs_modulation.c
${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/ulsch_demodulation.c
${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c
+34
View File
@@ -0,0 +1,34 @@
#this is a configuration file
#used to build real time processing statistics
#for 5G NR phy test (gNB terminate)
Title : Processing Time (us)
ColNames :
- Metric
- Average; Max; Count
- Average vs Reference Deviation (Reference Value; Acceptability Threshold)
Ref :
feprx : 48.0
feptx_prec : 16.0
feptx_ofdm : 35.0
feptx_total : 59.0
L1 Tx processing : 210.0
DLSCH encoding : 129.0
L1 Rx processing : 287.0
PUSCH inner-receiver : 166.0
PUSCH decoding : 176.0
Schedule Response : 42.0
DL & UL scheduling timing : 13.0
UL Indication : 55.0
Threshold :
feprx : 1.25
feptx_prec : 1.25
feptx_ofdm : 1.25
feptx_total : 1.25
L1 Tx processing : 1.25
DLSCH encoding : 1.25
L1 Rx processing : 1.25
PUSCH inner-receiver : 1.25
PUSCH decoding : 1.25
Schedule Response : 1.25
DL & UL scheduling timing : 1.25
UL Indication : 1.25
+13 -12
View File
@@ -7,18 +7,18 @@ ColNames :
- Average; Max; Count
- Average vs Reference Deviation (Reference Value; Acceptability Threshold)
Ref :
feprx : 60.0
feptx_prec : 8.0
feptx_ofdm : 50.0
feptx_total : 75.0
L1 Tx processing : 300.0
DLSCH encoding : 230.0
L1 Rx processing : 175.0
PUSCH inner-receiver : 100.0
#PUSCH decoding : 180.0
PUSCH decoding : 240.0
DL & UL scheduling timing : 37.0
UL Indication : 38.0
feprx : 53.0
feptx_prec : 20.0
feptx_ofdm : 37.0
feptx_total : 62.0
L1 Tx processing : 170.0
DLSCH encoding : 118.0
L1 Rx processing : 223.0
PUSCH inner-receiver : 107.0
PUSCH decoding : 170.0
Schedule Response : 15.0
DL & UL scheduling timing : 10.0
UL Indication : 27.0
Threshold :
feprx : 1.25
feptx_prec : 1.25
@@ -29,5 +29,6 @@ Threshold :
L1 Rx processing : 1.25
PUSCH inner-receiver : 1.25
PUSCH decoding : 1.25
Schedule Response : 1.25
DL & UL scheduling timing : 1.25
UL Indication : 1.25
@@ -21,8 +21,8 @@
-->
<testCaseList>
<htmlTabRef>gNB-PHY-Test</htmlTabRef>
<htmlTabName>Run-gNB-PHY-Test</htmlTabName>
<htmlTabRef>gNB-PHY-Test-40</htmlTabRef>
<htmlTabName>Timing phytest 40 MHz</htmlTabName>
<htmlTabIcon>tasks</htmlTabIcon>
<repeatCount>1</repeatCount>
<TestCaseRequestedList>
@@ -33,7 +33,8 @@
<testCase id="090101">
<class>Initialize_eNB</class>
<desc>Initialize gNB USRP</desc>
<Initialize_eNB_args>-O ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf --phy-test -q -U 787200 -T 106 -t 28 -D 130175 -m 28 -M 106 --usrp-tx-thread-config 1 --log_config.global_log_options level,nocolor,time</Initialize_eNB_args>
<Initialize_eNB_args>-O ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf --phy-test -q -U 787200 -T 106 -t 23 -D 130175 -m 28 -M 106 --usrp-tx-thread-config 1 --log_config.global_log_options level,nocolor,time</Initialize_eNB_args>
<rt_stats_cfg>datalog_rt_stats.default.yaml</rt_stats_cfg>
<air_interface>NR</air_interface>
<USRP_IPAddress>192.168.20.2</USRP_IPAddress>
</testCase>
@@ -41,7 +42,7 @@
<testCase id="000001">
<class>IdleSleep</class>
<desc>Sleep</desc>
<idle_sleep_time_in_sec>300</idle_sleep_time_in_sec>
<idle_sleep_time_in_sec>60</idle_sleep_time_in_sec>
</testCase>
@@ -0,0 +1,55 @@
<!--
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-60</htmlTabRef>
<htmlTabName>Timing phytest 60 MHz</htmlTabName>
<htmlTabIcon>tasks</htmlTabIcon>
<repeatCount>1</repeatCount>
<TestCaseRequestedList>
190101 000001 190109
</TestCaseRequestedList>
<TestCaseExclusionList></TestCaseExclusionList>
<testCase id="190101">
<class>Initialize_eNB</class>
<desc>Initialize gNB USRP</desc>
<Initialize_eNB_args>-O ci-scripts/conf_files/gnb.band78.tm1.106PRB.usrpn300.conf --phy-test --gNBs.[0].servingCellConfigCommon.[0].dl_carrierBandwidth 162 --gNBs.[0].servingCellConfigCommon.[0].ul_carrierBandwidth 162 -q -U 787200 -T 162 -t 23 -D 130175 -m 23 -M 162 --usrp-tx-thread-config 1 --log_config.global_log_options level,nocolor,time</Initialize_eNB_args>
<rt_stats_cfg>datalog_rt_stats.1x1.60.yaml</rt_stats_cfg>
<air_interface>NR</air_interface>
<USRP_IPAddress>192.168.20.2</USRP_IPAddress>
</testCase>
<testCase id="000001">
<class>IdleSleep</class>
<desc>Sleep</desc>
<idle_sleep_time_in_sec>60</idle_sleep_time_in_sec>
</testCase>
<testCase id="190109">
<class>Terminate_eNB</class>
<desc>Terminate gNB</desc>
<air_interface>NR</air_interface>
</testCase>
</testCaseList>
+4 -4
View File
@@ -85,21 +85,21 @@ void print_meas(time_stats_t *ts,
first_time=1;
if ((total_exec_time == NULL) || (sf_exec_time== NULL))
fprintf(stderr, "%25s %25s %25s %25s %25s %6f\n","Name","Total","Per Trials", "Num Trials","CPU_F_GHz", cpu_freq_GHz);
fprintf(stderr, "%30s %25s %25s %25s %25s %6f\n","Name","Total","Per Trials", "Num Trials","CPU_F_GHz", cpu_freq_GHz);
else
fprintf(stderr, "%25s %25s %25s %20s %15s %6f\n","Name","Total","Average/Frame","Trials", "CPU_F_GHz", cpu_freq_GHz);
fprintf(stderr, "%30s %25s %25s %20s %15s %6f\n","Name","Total","Average/Frame","Trials", "CPU_F_GHz", cpu_freq_GHz);
}
if (ts->trials>0) {
//printf("%20s: total: %10.3f ms, average: %10.3f us (%10d trials)\n", name, ts->diff/cpu_freq_GHz/1000000.0, ts->diff/ts->trials/cpu_freq_GHz/1000.0, ts->trials);
if ((total_exec_time == NULL) || (sf_exec_time== NULL)) {
fprintf(stderr, "%25s: %15.3f us; %15d; %15.3f us;\n",
fprintf(stderr, "%30s: %15.3f us; %15d; %15.3f us;\n",
name,
(ts->diff/ts->trials/cpu_freq_GHz/1000.0),
ts->trials,
ts->max/cpu_freq_GHz/1000.0);
} else {
fprintf(stderr, "%25s: %15.3f ms (%5.2f%%); %15.3f us (%5.2f%%); %15d;\n",
fprintf(stderr, "%30s: %15.3f ms (%5.2f%%); %15.3f us (%5.2f%%); %15d;\n",
name,
(ts->diff/cpu_freq_GHz/1000000.0),
((ts->diff/cpu_freq_GHz/1000000.0)/(total_exec_time->diff/cpu_freq_GHz/1000000.0))*100, // percentage
+1
View File
@@ -66,6 +66,7 @@ static int DEFBANDS[] = {7};
static int DEFENBS[] = {0};
static int DEFBFW[] = {0x00007fff};
static int DEFRUTPCORES[] = {2,4,6,8};
THREAD_STRUCT thread_struct;
pthread_cond_t sync_cond;
+20 -2
View File
@@ -38,6 +38,7 @@
#include "assertions.h"
#include <common/utils/LOG/log.h>
#include <common/utils/system.h>
#include "rt_profiling.h"
#include "PHY/types.h"
@@ -59,7 +60,6 @@
//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
#include "PHY/LTE_TRANSPORT/if4_tools.h"
#include "PHY/LTE_TRANSPORT/if5_tools.h"
#include "PHY/phy_extern.h"
@@ -115,10 +115,17 @@ void tx_func(void *param) {
int frame_tx = info->frame;
int slot_tx = info->slot;
int absslot_tx = info->timestamp_tx/info->gNB->frame_parms.get_samples_per_slot(slot_tx,&info->gNB->frame_parms);
int absslot_rx = absslot_tx-info->gNB->RU_list[0]->sl_ahead;
int rt_prof_idx = absslot_rx % RT_PROF_DEPTH;
clock_gettime(CLOCK_MONOTONIC,&info->gNB->rt_L1_profiling.start_L1_TX[rt_prof_idx]);
phy_procedures_gNB_TX(info,
frame_tx,
slot_tx,
1);
clock_gettime(CLOCK_MONOTONIC,&info->gNB->rt_L1_profiling.return_L1_TX[rt_prof_idx]);
}
void rx_func(void *param) {
@@ -130,6 +137,11 @@ void rx_func(void *param) {
int slot_tx = info->slot_tx;
nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config;
int absslot_tx = info->timestamp_tx/gNB->frame_parms.get_samples_per_slot(slot_rx,&gNB->frame_parms);
int absslot_rx = absslot_tx - gNB->RU_list[0]->sl_ahead;
int rt_prof_idx = absslot_rx % RT_PROF_DEPTH;
clock_gettime(CLOCK_MONOTONIC,&info->gNB->rt_L1_profiling.start_L1_RX[rt_prof_idx]);
start_meas(&softmodem_stats_rxtx_sf);
// *******************************************************************
@@ -228,6 +240,7 @@ void rx_func(void *param) {
stop_meas( &softmodem_stats_rxtx_sf );
LOG_D(PHY,"%s() Exit proc[rx:%d%d tx:%d%d]\n", __FUNCTION__, frame_rx, slot_rx, frame_tx, slot_tx);
clock_gettime(CLOCK_MONOTONIC,&info->gNB->rt_L1_profiling.return_L1_RX[rt_prof_idx]);
// Call the scheduler
start_meas(&gNB->ul_indication_stats);
@@ -383,6 +396,8 @@ void *tx_reorder_thread(void* param) {
AssertFatal(resL1Reserve != NULL, "pullTpool() did not return start message in %s\n", __func__);
int next_tx_slot=((processingData_L1tx_t *)NotifiedFifoData(resL1Reserve))->slot;
LOG_I(PHY,"tx_reorder_thread started\n");
while (!oai_exit) {
notifiedFIFO_elt_t *resL1;
if (resL1Reserve) {
@@ -419,6 +434,7 @@ void *tx_reorder_thread(void* param) {
pushNotifiedFIFO(&gNB->L1_tx_free, resL1);
if (resL1==resL1Reserve)
resL1Reserve=NULL;
LOG_D(PHY,"gNB: %d.%d : calling RU TX function\n",syncMsgL1->frame,syncMsgL1->slot);
ru_tx_func((void*)&syncMsgRU);
}
return(NULL);
@@ -457,7 +473,9 @@ void init_gNB_Tpool(int inst) {
if ((!get_softmodem_params()->emulate_l1) && (!IS_SOFTMODEM_NOSTATS_BIT))
threadCreate(&proc->L1_stats_thread,nrL1_stats_thread,(void*)gNB,"L1_stats",-1,OAI_PRIORITY_RT_LOW);
threadCreate(&proc->pthread_tx_reorder, tx_reorder_thread, (void *)gNB, "thread_tx_reorder", -1, OAI_PRIORITY_RT_MAX);
LOG_I(PHY,"Creating thread for TX reordering and dispatching to RU\n");
threadCreate(&proc->pthread_tx_reorder, tx_reorder_thread, (void *)gNB, "thread_tx_reorder",
gNB->RU_list[0] ? gNB->RU_list[0]->tpcores[1] : -1, OAI_PRIORITY_RT_MAX);
}
+125 -72
View File
@@ -35,12 +35,12 @@
#include "common/utils/assertions.h"
#include "common/utils/system.h"
#include "common/ran_context.h"
#include "rt_profiling.h"
#include "../../ARCH/COMMON/common_lib.h"
#include "../../ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h"
#include "PHY/LTE_TRANSPORT/if4_tools.h"
#include "PHY/LTE_TRANSPORT/if5_tools.h"
#include "PHY/types.h"
#include "PHY/defs_nr_common.h"
@@ -59,11 +59,12 @@
unsigned short config_frames[4] = {2,9,11,13};
#endif
/* these variables have to be defined before including ENB_APP/enb_paramdef.h and GNB_APP/gnb_paramdef.h */
static int DEFBANDS[] = {7};
static int DEFENBS[] = {0};
static int DEFBFW[] = {0x00007fff};
static int DEFRUTPCORES[] = {-1,-1,-1,-1};
//static int DEFNRBANDS[] = {7};
//static int DEFGNBS[] = {0};
@@ -276,8 +277,21 @@ int connect_rau(RU_t *ru) {
// southbound IF5 fronthaul for 16-bit OAI format
void fh_if5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) {
if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
int offset = ru->nr_frame_parms->get_samples_slot_timestamp(slot,ru->nr_frame_parms,0);
void *buffs[ru->nb_tx];
for (int aid=0;aid<ru->nb_tx;aid++) buffs[aid] = (void*)&ru->common.txdata[aid][offset];
struct timespec txmeas;
clock_gettime(CLOCK_MONOTONIC, &txmeas);
LOG_D(PHY,"IF5 TX %d.%d, TS %llu, buffs[0] %p, buffs[1] %p ener0 %f dB, tx start %d\n",frame,slot,(unsigned long long)timestamp,buffs[0],buffs[1],
10*log10((double)signal_energy(buffs[0],ru->nr_frame_parms->get_samples_per_slot(slot,ru->nr_frame_parms))),(int)txmeas.tv_nsec);
ru->ifdevice.trx_write_func2(&ru->ifdevice,
timestamp,
buffs,
0,
ru->nr_frame_parms->get_samples_per_slot(slot,ru->nr_frame_parms),
0,
ru->nb_tx);
send_IF5(ru, timestamp, slot, &ru->seqno, IF5_RRH_GW_DL);
}
// southbound IF4p5 fronthaul
@@ -297,19 +311,19 @@ void fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) {
// Synchronous if5 from south
uint64_t ts_rx[20];
void fh_if5_south_in(RU_t *ru,
int *frame,
int *tti) {
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
RU_proc_t *proc = &ru->proc;
recv_IF5(ru, &proc->timestamp_rx, *tti, IF5_RRH_GW_UL);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_RECV_IF5, 1 );
start_meas(&ru->rx_fhaul);
ru->ifdevice.trx_read_func2(&ru->ifdevice,&proc->timestamp_rx,NULL,fp->get_samples_per_slot(*tti,fp));
if (proc->first_rx == 1) ru->ts_offset = proc->timestamp_rx;
proc->frame_rx = ((proc->timestamp_rx-ru->ts_offset) / (fp->samples_per_subframe*10))&1023;
proc->tti_rx = fp->get_slot_from_timestamp(proc->timestamp_rx-ru->ts_offset,fp);
//(idx_sf * fp->slots_per_subframe + (int)round((float)(proc->timestamp_rx % fp->samples_per_subframe) / fp->samples_per_slot0))%(fp->slots_per_frame);
ts_rx[*tti] = proc->timestamp_rx;
LOG_D(PHY,"IF5 %d.%d => RX %d.%d first_rx %d\n",*frame,*tti,proc->frame_rx,proc->tti_rx,proc->first_rx);
if (proc->first_rx == 0) {
if (proc->tti_rx != *tti) {
@@ -327,7 +341,15 @@ void fh_if5_south_in(RU_t *ru,
*tti = proc->tti_rx;
}
stop_meas(&ru->rx_fhaul);
struct timespec rxmeas;
clock_gettime(CLOCK_MONOTONIC, &rxmeas);
double fhtime = ru->rx_fhaul.p_time/(cpu_freq_GHz*1000.0);
if (fhtime > 800) LOG_W(PHY,"IF5 %d.%d => RX %d.%d first_rx %d: time %f, rxstart %d\n",*frame,*tti,proc->frame_rx,proc->tti_rx,proc->first_rx,ru->rx_fhaul.p_time/(cpu_freq_GHz*1000.0),(int)rxmeas.tv_nsec);
else LOG_D(PHY,"IF5 %d.%d => RX %d.%d first_rx %d: time %f, rxstart %d\n",*frame,*tti,proc->frame_rx,proc->tti_rx,proc->first_rx,ru->rx_fhaul.p_time/(cpu_freq_GHz*1000.0),(int)rxmeas.tv_nsec);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff );
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_RECV_IF5, 0 );
}
// Synchronous if4p5 from south
@@ -476,7 +498,7 @@ void fh_if5_north_asynch_in(RU_t *ru,int *frame,int *slot) {
RU_proc_t *proc = &ru->proc;
int tti_tx,frame_tx;
openair0_timestamp timestamp_tx;
recv_IF5(ru, &timestamp_tx, *slot, IF5_RRH_GW_DL);
AssertFatal(1==0,"Shouldn't get here\n");
// printf("Received subframe %d (TS %llu) from RCC\n",tti_tx,timestamp_tx);
frame_tx = (timestamp_tx / (fp->samples_per_subframe*10))&1023;
uint32_t idx_sf = timestamp_tx / fp->samples_per_subframe;
@@ -553,11 +575,9 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *slot) {
}
void fh_if5_north_out(RU_t *ru) {
RU_proc_t *proc=&ru->proc;
uint8_t seqno=0;
/// **** send_IF5 of rxdata to BBU **** ///
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 1 );
send_IF5(ru, proc->timestamp_rx, proc->tti_rx, &seqno, IF5_RRH_GW_UL);
AssertFatal(1==0,"Shouldn't get here\n");
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 0 );
}
@@ -827,6 +847,7 @@ void fill_rf_config(RU_t *ru, char *rf_config_file) {
cfg->num_rb_dl=N_RB;
cfg->tx_num_channels=ru->nb_tx;
cfg->rx_num_channels=ru->nb_rx;
LOG_I(PHY,"Setting RF config for N_RB %d, NB_RX %d, NB_TX %d\n",cfg->num_rb_dl,cfg->rx_num_channels,cfg->tx_num_channels);
for (i=0; i<ru->nb_tx; i++) {
if (ru->if_frequency == 0) {
@@ -957,17 +978,17 @@ void *ru_stats_thread(void *param) {
sleep(1);
if (opp_enabled == 1) {
if (ru->feprx) print_meas(&ru->ofdm_demod_stats,"feprx",NULL,NULL);
if (ru->feprx) print_meas(&ru->ofdm_demod_stats,"feprx (all ports)",NULL,NULL);
if (ru->feptx_ofdm) {
print_meas(&ru->precoding_stats,"feptx_prec",NULL,NULL);
print_meas(&ru->precoding_stats,(ru->half_slot_parallelization==0)?"feptx_prec (per port)":"feptx_prec (per port, half_slot)",NULL,NULL);
print_meas(&ru->ofdm_mod_stats,(ru->half_slot_parallelization==0)?"feptx_ofdm (per port)":"feptx_ofdm (per port, half_slot)",NULL,NULL);
print_meas(&ru->txdataF_copy_stats,"txdataF_copy",NULL,NULL);
print_meas(&ru->ofdm_mod_stats,"feptx_ofdm",NULL,NULL);
print_meas(&ru->ofdm_total_stats,"feptx_total",NULL,NULL);
}
print_meas(&ru->rx_fhaul,"rx_fhaul",NULL,NULL);
print_meas(&ru->tx_fhaul,"tx_fhaul",NULL,NULL);
if (ru->if_south == REMOTE_IF5) print_meas(&ru->ifdevice.tx_fhaul,"tx_fhaul (IF5)",NULL,NULL);
else print_meas(&ru->tx_fhaul,"tx_fhaul",NULL,NULL);
if (ru->fh_north_out) {
print_meas(&ru->compression,"compression",NULL,NULL);
@@ -987,7 +1008,13 @@ void ru_tx_func(void *param) {
int slot_tx = info->slot_tx;
int print_frame = 8;
char filename[40];
// note that this will break for 60/120 kHz, to be handled
int absslot_tx = info->timestamp_tx/fp->get_samples_per_slot(slot_tx,fp);
int absslot_rx = absslot_tx-ru->sl_ahead;
int rt_prof_idx = absslot_rx % RT_PROF_DEPTH;
clock_gettime(CLOCK_MONOTONIC,&ru->rt_ru_profiling.start_RU_TX[rt_prof_idx]);
// do TX front-end processing if needed (precoding and/or IDFTs)
if (ru->feptx_prec) ru->feptx_prec(ru,frame_tx,slot_tx);
@@ -1030,6 +1057,11 @@ void ru_tx_func(void *param) {
}//for (i=0; i<ru->nb_tx; i++)
}//if(frame_tx == print_frame)
}//else emulate_rf
clock_gettime(CLOCK_MONOTONIC,&ru->rt_ru_profiling.return_RU_TX[rt_prof_idx]);
struct timespec *t0=&ru->rt_ru_profiling.start_RU_TX[rt_prof_idx];
struct timespec *t1=&ru->rt_ru_profiling.return_RU_TX[rt_prof_idx];
LOG_D(PHY,"rt_prof_idx %d : RU_TX time %d\n",rt_prof_idx,(int)(1e9 * (t1->tv_sec - t0->tv_sec) + (t1->tv_nsec-t0->tv_nsec)));
}
void *ru_thread( void *param ) {
@@ -1054,9 +1086,9 @@ void *ru_thread( void *param ) {
memcpy((void *)&ru->config,(void *)&RC.gNB[0]->gNB_config,sizeof(ru->config));
if(emulate_rf) {
fill_rf_config(ru,ru->rf_config_file);
nr_init_frame_parms(&ru->config, fp);
nr_dump_frame_parms(fp);
fill_rf_config(ru,ru->rf_config_file);
nr_phy_init_RU(ru);
if (setup_RU_buffers(ru)!=0) {
@@ -1071,7 +1103,7 @@ void *ru_thread( void *param ) {
// Start IF device if any
if (ru->nr_start_if) {
LOG_I(PHY,"Starting IF interface for RU %d\n",ru->idx);
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) {
@@ -1111,7 +1143,7 @@ void *ru_thread( void *param ) {
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\n",ru->idx);
LOG_I(PHY,"RU %d RF started opp_enabled %d\n",ru->idx,opp_enabled);
// start trx write thread
if(usrp_tx_thread == 1) {
if (ru->start_write_thread) {
@@ -1166,6 +1198,7 @@ void *ru_thread( void *param ) {
if (ru->fh_south_in) ru->fh_south_in(ru,&frame,&slot);
else AssertFatal(1==0, "No fronthaul interface at south port");
if (initial_wait == 1 && proc->frame_rx < 300 && ru->fh_south_in == rx_rf) {
if (proc->frame_rx>0 && ((proc->frame_rx % 100) == 0) && proc->tti_rx==0) {
LOG_I(PHY,"delay processing to let RX stream settle, frame %d (trials %d)\n",proc->frame_rx,ru->rx_fhaul.trials);
@@ -1178,13 +1211,20 @@ void *ru_thread( void *param ) {
initial_wait=0;
opp_enabled = opp_enabled0;
}
if (initial_wait == 0 && ru->rx_fhaul.trials > 1000) reset_meas(&ru->rx_fhaul);
if (initial_wait == 0 && ru->rx_fhaul.trials > 1000) {
reset_meas(&ru->rx_fhaul);
/*if (ru->if_south == REMOTE_IF5) reset_meas(&ru->ifdevice.tx_fhaul);
else*/ reset_meas(&ru->tx_fhaul);
}
proc->timestamp_tx = proc->timestamp_rx;
int sl=proc->tti_tx;
for (int slidx=0;slidx<ru->sl_ahead;slidx++)
proc->timestamp_tx += fp->get_samples_per_slot((sl+slidx)%fp->slots_per_frame,fp);
proc->frame_tx = (proc->tti_rx > (fp->slots_per_frame-1-(ru->sl_ahead))) ? (proc->frame_rx+1)&1023 : proc->frame_rx;
proc->tti_tx = (proc->tti_rx + ru->sl_ahead)%fp->slots_per_frame;
int absslot_rx = proc->timestamp_rx/fp->get_samples_per_slot(proc->tti_rx,fp);
int rt_prof_idx = absslot_rx % RT_PROF_DEPTH;
clock_gettime(CLOCK_MONOTONIC,&ru->rt_ru_profiling.return_RU_south_in[rt_prof_idx]);
LOG_D(PHY,"AFTER fh_south_in - SFN/SL:%d%d RU->proc[RX:%d.%d TX:%d.%d] RC.gNB[0]:[RX:%d%d TX(SFN):%d]\n",
frame,slot,
proc->frame_rx,proc->tti_rx,
@@ -1200,15 +1240,9 @@ void *ru_thread( void *param ) {
if (slot_type == NR_UPLINK_SLOT || slot_type == NR_MIXED_SLOT) {
if (ru->feprx) {
ru->feprx(ru,proc->tti_rx);
clock_gettime(CLOCK_MONOTONIC,&ru->rt_ru_profiling.return_RU_feprx[rt_prof_idx]);
//LOG_M("rxdata.m","rxs",ru->common.rxdata[0],1228800,1,1);
LOG_D(PHY,"RU proc: frame_rx = %d, tti_rx = %d\n", proc->frame_rx, proc->tti_rx);
/*
LOG_D(PHY,"Copying rxdataF from RU to gNB\n");
for (int aa=0; aa<ru->nb_rx; aa++)
memcpy((void *)RC.gNB[0]->common_vars.rxdataF[aa],
(void *)ru->common.rxdataF[aa], fp->symbols_per_slot*fp->ofdm_symbol_size*sizeof(int32_t));
*/
if (IS_SOFTMODEM_DOSCOPE && RC.gNB[0]->scopeData)
((scopeData_t *)RC.gNB[0]->scopeData)->slotFunc(ru->common.rxdataF[0],proc->tti_rx, RC.gNB[0]->scopeData);
@@ -1216,24 +1250,12 @@ void *ru_thread( void *param ) {
int prach_id=find_nr_prach_ru(ru,proc->frame_rx,proc->tti_rx,SEARCH_EXIST);
uint8_t prachStartSymbol,N_dur;
if (prach_id>=0) {
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 1 );
T(T_GNB_PHY_PRACH_INPUT_SIGNAL, T_INT(proc->frame_rx), T_INT(proc->tti_rx), T_INT(0),
T_BUFFER(&ru->common.rxdata[0][fp->get_samples_slot_timestamp(proc->tti_rx-1,fp,0)]/*-ru->N_TA_offset*/, fp->get_samples_per_slot(proc->tti_rx,fp)*4*2));
N_dur = get_nr_prach_duration(ru->prach_list[prach_id].fmt);
/*
get_nr_prach_info_from_index(ru->config.prach_config.prach_ConfigurationIndex.value,
proc->frame_rx,proc->tti_rx,
ru->config.carrier_config.dl_frequency.value,
fp->numerology_index,
fp->frame_type,
&format,
&start_symbol,
&N_t_slot,
&N_dur,
&RA_sfn_index,
&N_RA_slot,
&config_period);
*/
for (int prach_oc = 0; prach_oc<ru->prach_list[prach_id].num_prach_ocas; prach_oc++) {
prachStartSymbol = ru->prach_list[prach_id].prachStartSymbol+prach_oc*N_dur;
//comment FK: the standard 38.211 section 5.3.2 has one extra term +14*N_RA_slot. This is because there prachStartSymbol is given wrt to start of the 15kHz slot or 60kHz slot. Here we work slot based, so this function is anyway only called in slots where there is PRACH. Its up to the MAC to schedule another PRACH PDU in the case there are there N_RA_slot \in {0,1}.
@@ -1244,11 +1266,16 @@ void *ru_thread( void *param ) {
prach_oc,
proc->frame_rx,proc->tti_rx);
}
clock_gettime(CLOCK_MONOTONIC,&ru->rt_ru_profiling.return_RU_prachrx[rt_prof_idx]);
free_nr_ru_prach_entry(ru,prach_id);
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 0 );
} // end if (prach_id > 0)
} // end if (ru->feprx)
else {
memset(&ru->rt_ru_profiling.return_RU_feprx[rt_prof_idx],0,sizeof(struct timespec));
memset(&ru->rt_ru_profiling.return_RU_prachrx[rt_prof_idx],0,sizeof(struct timespec));
}
}
} // end if (slot_type == NR_UPLINK_SLOT || slot_type == NR_MIXED_SLOT) {
// At this point, all information for subframe has been received on FH interface
res = pullTpool(&gNB->resp_L1, &gNB->threadPool);
@@ -1283,6 +1310,9 @@ int start_streaming(RU_t *ru) {
}
int nr_start_if(struct RU_t_s *ru, struct PHY_VARS_gNB_s *gNB) {
for (int i=0;i<ru->nb_rx;i++) ru->openair0_cfg.rxbase[i] = ru->common.rxdata[i];
ru->openair0_cfg.rxsize = ru->nr_frame_parms->samples_per_subframe*10;
reset_meas(&ru->ifdevice.tx_fhaul);
return(ru->ifdevice.trx_start_func(&ru->ifdevice));
}
@@ -1312,21 +1342,18 @@ void init_RU_proc(RU_t *ru) {
proc->frame_offset = 0;
proc->num_slaves = 0;
proc->frame_tx_unwrap = 0;
proc->feptx_mask = 0;
for (i=0; i<10; i++) proc->symbol_mask[i]=0;
pthread_mutex_init( &proc->mutex_emulateRF,NULL);
pthread_cond_init( &proc->cond_emulateRF, NULL);
threadCreate( &proc->pthread_FH, ru_thread, (void *)ru, "thread_FH", -1, OAI_PRIORITY_RT_MAX );
threadCreate( &proc->pthread_FH, ru_thread, (void *)ru, "ru_thread", ru->tpcores[0], OAI_PRIORITY_RT_MAX );
if(emulate_rf)
threadCreate( &proc->pthread_emulateRF, emulatedRF_thread, (void *)proc, "emulateRF", -1, OAI_PRIORITY_RT );
if (opp_enabled == 1)
threadCreate( &ru->ru_stats_thread, ru_stats_thread, (void *)ru,"ru_stats", -1, OAI_PRIORITY_RT );
if (get_thread_worker_conf() == WORKER_ENABLE) {
if (ru->feprx) nr_init_feprx_thread(ru);
if (ru->feptx_ofdm) nr_init_feptx_thread(ru);
}
}
@@ -1340,17 +1367,16 @@ void kill_NR_RU_proc(int inst) {
* mutex_fep/cond_fep. Thus, we unlocked above for pthread_FH above and do
* the same for FEP thread below again (using broadcast() to ensure both
* threads get the signal). This one will also destroy the mutex and cond. */
pthread_mutex_lock(&proc->mutex_fep);
proc->instance_cnt_fep = 0;
pthread_cond_broadcast(&proc->cond_fep);
pthread_mutex_unlock( &proc->mutex_fep );
pthread_mutex_lock(&proc->mutex_fep[0]);
proc->instance_cnt_fep[0] = 0;
pthread_cond_broadcast(&proc->cond_fep[0]);
pthread_mutex_unlock( &proc->mutex_fep[0] );
pthread_join(proc->pthread_FH, NULL);
if (ru->feprx)
nr_kill_feprx_thread(ru);
if (ru->feptx_ofdm)
nr_kill_feptx_thread(ru);
if (opp_enabled) {
LOG_D(PHY, "Joining ru_stats_thread\n");
pthread_join(ru->ru_stats_thread, NULL);
}
}
int check_capabilities(RU_t *ru,RRU_capabilities_t *cap) {
@@ -1554,8 +1580,8 @@ void set_function_spec_param(RU_t *ru) {
ru->fh_north_out = fh_if4p5_north_out; // send_IF4p5 on reception
ru->fh_south_out = tx_rf; // send output to RF
ru->fh_north_asynch_in = fh_if4p5_north_asynch_in; // TX packets come asynchronously
ru->feprx = (get_thread_worker_conf() == WORKER_ENABLE) ? nr_fep_full_2thread : nr_fep_full; // RX DFTs
ru->feptx_ofdm = (get_thread_worker_conf() == WORKER_ENABLE) ? nr_feptx_ofdm_2thread : nr_feptx_ofdm; // this is fep with idft only (no precoding in RRU)
ru->feprx = nr_fep_tp; // this is frequency-shift + DFTs
ru->feptx_ofdm = nr_feptx_tp; // this is fep with idft only (no precoding in RRU)
ru->feptx_prec = NULL;
ru->nr_start_if = nr_start_if; // need to start the if interface for if4p5
ru->ifdevice.host_type = RRU_HOST;
@@ -1575,9 +1601,9 @@ void set_function_spec_param(RU_t *ru) {
malloc_IF4p5_buffer(ru);
} else if (ru->function == gNodeB_3GPP) {
ru->do_prach = 0; // no prach processing in RU
ru->feprx = (get_thread_worker_conf() == WORKER_ENABLE) ? nr_fep_full_2thread : nr_fep_full; // RX DFTs
ru->feptx_ofdm = (get_thread_worker_conf() == WORKER_ENABLE) ? nr_feptx_ofdm_2thread : nr_feptx_ofdm; // this is fep with idft and precoding
ru->feptx_prec = (get_thread_worker_conf() == WORKER_ENABLE) ? NULL : nr_feptx_prec; // this is fep with idft and precoding
ru->feprx = nr_fep_tp; // this is frequency-shift + DFTs
ru->feptx_ofdm = nr_feptx_tp; // this is fep with idft and precoding
ru->feptx_prec = NULL;
ru->fh_north_in = NULL; // no incoming fronthaul from north
ru->fh_north_out = NULL; // no outgoing fronthaul to north
ru->nr_start_if = NULL; // no if interface
@@ -1606,11 +1632,12 @@ void set_function_spec_param(RU_t *ru) {
case REMOTE_IF5: // the remote unit is IF5 RRU
ru->do_prach = 0;
ru->feprx = (get_thread_worker_conf() == WORKER_ENABLE) ? nr_fep_full_2thread : nr_fep_full; // this is frequency-shift + DFTs
ru->feptx_prec = (get_thread_worker_conf() == WORKER_ENABLE) ? NULL : nr_feptx_prec; // need to do transmit Precoding + IDFTs
ru->feptx_ofdm = (get_thread_worker_conf() == WORKER_ENABLE) ? nr_feptx_ofdm_2thread : nr_feptx_ofdm; // need to do transmit Precoding + IDFTs
ru->txfh_in_fep = 0;
ru->feprx = nr_fep_tp; // this is frequency-shift + DFTs
ru->feptx_prec = NULL; // need to do transmit Precoding + IDFTs
ru->feptx_ofdm = nr_feptx_tp; // need to do transmit Precoding + IDFTs
ru->fh_south_in = fh_if5_south_in; // synchronous IF5 reception
ru->fh_south_out = fh_if5_south_out; // synchronous IF5 transmission
ru->fh_south_out = (ru->txfh_in_fep>0) ? NULL : fh_if5_south_out; // synchronous IF5 transmission
ru->fh_south_asynch_in = NULL; // no asynchronous UL
ru->start_rf = ru->eth_params.transp_preference == ETH_UDP_IF5_ECPRI_MODE ? start_streaming : NULL;
ru->stop_rf = NULL;
@@ -1619,6 +1646,8 @@ void set_function_spec_param(RU_t *ru) {
ru->ifdevice.host_type = RAU_HOST;
ru->ifdevice.eth_params = &ru->eth_params;
ru->ifdevice.configure_rru = configure_ru;
printf("starting transport : rx_num_antennas %d, tx_num_antennas %d\n",ru->openair0_cfg.rx_num_channels,ru->openair0_cfg.tx_num_channels);
ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params);
printf("openair0_transport_init returns %d for ru_id %u\n", ret, ru->idx);
@@ -1632,7 +1661,7 @@ void set_function_spec_param(RU_t *ru) {
case REMOTE_IF4p5:
ru->do_prach = 0;
ru->feprx = NULL; // DFTs
ru->feptx_prec = nr_feptx_prec; // Precoding operation
ru->feptx_prec = NULL; // Precoding operation
ru->feptx_ofdm = NULL; // no OFDM mod
ru->fh_south_in = fh_if4p5_south_in; // synchronous IF4p5 reception
ru->fh_south_out = fh_if4p5_south_out; // synchronous IF4p5 transmission
@@ -1709,7 +1738,6 @@ void init_NR_RU(char *rf_config_file) {
ru->gNB_list[0] = RC.gNB[0];
ru->num_gNB=1;
//
// DJP - feptx_prec() / feptx_ofdm() parses the gNB_list (based on num_gNB) and copies the txdata_F to txdata in RU
//
} else {
LOG_E(PHY,"DJP - delete code above this %s:%d\n", __FILE__, __LINE__);
@@ -1739,11 +1767,29 @@ void init_NR_RU(char *rf_config_file) {
}
}
}
ru->openair0_cfg.rx_num_channels = ru->nb_rx;
ru->openair0_cfg.tx_num_channels = ru->nb_tx;
//LOG_I(PHY,"Initializing RRU descriptor %d : (%s,%s,%d)\n",ru_id,ru_if_types[ru->if_south],NB_timing[ru->if_timing],ru->function);
set_function_spec_param(ru);
LOG_I(PHY,"Starting ru_thread %d\n",ru_id);
init_RU_proc(ru);
int threadCnt = ru->num_tpcores;
if (threadCnt < 2) LOG_E(PHY,"Number of threads for gNB should be more than 1. Allocated only %d\n",threadCnt);
else LOG_I(PHY,"RU Thread pool size %d\n",threadCnt);
char pool[80];
int s_offset = sprintf(pool,"%d",ru->tpcores[0]);
for (int icpu=1; icpu<threadCnt; icpu++) {
s_offset+=sprintf(pool+s_offset,",%d",ru->tpcores[icpu]);
}
LOG_I(PHY,"RU thread-pool core string %s\n",pool);
ru->threadPool = (tpool_t*)malloc(sizeof(tpool_t));
initTpool(pool, ru->threadPool, cpumeas(CPUMEAS_GETSTATE));
// FEP RX result FIFO
ru->respfeprx = (notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t));
initNotifiedFIFO(ru->respfeprx);
// FEP TX result FIFO
ru->respfeptx = (notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t));
initNotifiedFIFO(ru->respfeptx);
} // for ru_id
// sleep(1);
@@ -1918,6 +1964,13 @@ static void NRRCconfig_RU(void) {
RC.ru[j]->openair0_cfg.nr_band = RC.ru[j]->band[0];
RC.ru[j]->openair0_cfg.nr_scs_for_raster = *(RUParamList.paramarray[j][RU_NR_SCS_FOR_RASTER].iptr);
printf("[RU %d] Setting nr_flag %d, nr_band %d, nr_scs_for_raster %d\n",j,RC.ru[j]->openair0_cfg.nr_flag,RC.ru[j]->openair0_cfg.nr_band,RC.ru[j]->openair0_cfg.nr_scs_for_raster);
RC.ru[j]->openair0_cfg.rxfh_cores[0] = *(RUParamList.paramarray[j][RU_RXFH_CORE_ID].iptr);
RC.ru[j]->openair0_cfg.txfh_cores[0] = *(RUParamList.paramarray[j][RU_TXFH_CORE_ID].iptr);
RC.ru[j]->num_tpcores = *(RUParamList.paramarray[j][RU_NUM_TP_CORES].iptr);
RC.ru[j]->half_slot_parallelization = *(RUParamList.paramarray[j][RU_HALF_SLOT_PARALLELIZATION].iptr);
printf("[RU %d] Setting half-slot parallelization to %d\n",j,RC.ru[j]->half_slot_parallelization);
AssertFatal(RC.ru[j]->num_tpcores <= RUParamList.paramarray[j][RU_TP_CORES].numelt, "Number of TP cores should be <=16\n");
for (i=0; i<RC.ru[j]->num_tpcores; i++) RC.ru[j]->tpcores[i] = RUParamList.paramarray[j][RU_TP_CORES].iptr[i];
if (config_isparamset(RUParamList.paramarray[j], RU_BF_WEIGHTS_LIST_IDX)) {
RC.ru[j]->nb_bfw = RUParamList.paramarray[j][RU_BF_WEIGHTS_LIST_IDX].numelt;
+64
View File
@@ -0,0 +1,64 @@
/*
* 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 time_profiling.h
* \brief Definitions for proflling real-time scheduling
* \author
* \date 2022
* \version 0.1
* \company Eurecom
* \email:
* \note
* \warning
*/
#ifndef TIME_PROFILING_H
#define TIME_PROFILING_H
#ifdef __cplusplus
extern "C"
{
#endif
// depth of trace in slots
#define RT_PROF_DEPTH 100
typedef struct {
int absslot_rx[RT_PROF_DEPTH];
struct timespec return_RU_south_in[RT_PROF_DEPTH];
struct timespec return_RU_feprx[RT_PROF_DEPTH];
struct timespec return_RU_prachrx[RT_PROF_DEPTH];
struct timespec return_RU_pushL1[RT_PROF_DEPTH];
struct timespec start_RU_TX[RT_PROF_DEPTH];
struct timespec return_RU_TX[RT_PROF_DEPTH];
} rt_ru_profiling_t;
typedef struct {
int absslot_ux[RT_PROF_DEPTH];
struct timespec start_L1_RX[RT_PROF_DEPTH];
struct timespec return_L1_RX[RT_PROF_DEPTH];
struct timespec start_L1_TX[RT_PROF_DEPTH];
struct timespec return_L1_TX[RT_PROF_DEPTH];
struct timespec return_L1_prachrx[RT_PROF_DEPTH];
struct timespec return_L1_puschL1[RT_PROF_DEPTH];
} rt_L1_profiling_t;
#ifdef __cplusplus
}
#endif
#endif
File diff suppressed because it is too large Load Diff
-70
View File
@@ -1,70 +0,0 @@
/*
* 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 PHY/LTE_TRANSPORT/if5_tools.h
* \brief
* \author S. Sandeep Kumar, Raymond Knopp
* \date 2016
* \version 0.1
* \company Eurecom
* \email: ee13b1025@iith.ac.in, knopp@eurecom.fr
* \note
* \warning
*/
#ifndef __IF5_TOOLS_H__
#define __IF5_TOOLS_H__
#include <stdint.h>
#include "PHY/defs_eNB.h"
#define IF5_RRH_GW_DL 0x0022
#define IF5_RRH_GW_UL 0x0023
#define IF5_MOBIPASS 0xbffe
struct IF5_mobipass_header {
///
uint16_t flags;
///
uint16_t fifo_status;
///
uint8_t seqno;
///
uint8_t ack;
///
uint32_t word0;
///
uint32_t time_stamp;
} __attribute__ ((__packed__));
typedef struct IF5_mobipass_header IF5_mobipass_header_t;
#define sizeof_IF5_mobipass_header_t 14
void send_IF5(RU_t *, openair0_timestamp, int, uint8_t*, uint16_t);
void recv_IF5(RU_t *ru, openair0_timestamp *proc_timestamp, int subframe, uint16_t packet_type);
void malloc_IF5_buffer(RU_t *ru);
#endif
@@ -117,6 +117,7 @@ NR_gNB_DLSCH_t *new_gNB_dlsch(NR_DL_FRAME_PARMS *frame_parms,
a_segments = a_segments/273 +1;
}
LOG_I(PHY,"Allocating %d segments (MAX %d, N_PRB %d)\n",a_segments,MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER,N_RB);
uint32_t dlsch_bytes = a_segments*1056; // allocated bytes per segment
NR_gNB_DLSCH_t *dlsch = malloc16(sizeof(NR_gNB_DLSCH_t));
AssertFatal(dlsch, "cannot allocate dlsch\n");
+1 -1
View File
@@ -410,7 +410,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB,
uci_stats->pucch0_thres = gNB->pucch0_thres; /* + (10*max_n0);*/
bool no_conf=false;
if (nr_sequences>1) {
if (/*xrtmag_dBtimes10 < (30+xrtmag_next_dBtimes10) ||*/ SNRtimes10 < uci_stats->pucch0_thres) {
if (/*xrtmag_dBtimes10 < (30+xrtmag_next_dBtimes10) ||*/ SNRtimes10 < gNB->pucch0_thres) {
no_conf=true;
LOG_D(PHY,"%d.%d PUCCH bad confidence: %d threshold, %d, %d, %d\n",
frame, slot,
+43 -27
View File
@@ -39,6 +39,8 @@
#include "time_meas.h"
#include "defs_common.h"
#include "nfapi_nr_interface_scf.h"
#include <common/utils/threadPool/thread-pool.h>
#include <executables/rt_profiling.h>
#define MAX_BANDS_PER_RRU 4
#define MAX_RRU_CONFIG_SIZE 1024
@@ -168,25 +170,21 @@ typedef struct RU_prec_t_s{
int index;
} RU_prec_t;
typedef struct RU_feptx_t_s{
/// \internal This variable is protected by \ref mutex_feptx_prec
int instance_cnt_feptx;
/// pthread struct for RU TX FEP PREC worker thread
pthread_t pthread_feptx;
/// pthread attributes for worker feptx prec thread
pthread_attr_t attr_feptx;
/// condition varible for RU TX FEP PREC thread
pthread_cond_t cond_feptx;
/// mutex for fep PREC TX worker thread
pthread_mutex_t mutex_feptx;
struct RU_t_s *ru;
int aa;//physical MAX nb_tx
int half_slot;//first or second half of a slot
int slot;//current slot
int symbol;//current symbol
int nb_antenna_ports;//number of logical port
int index;
}RU_feptx_t;
typedef struct {
int aid;
struct RU_t_s *ru;
int startSymbol;
int endSymbol;
int slot;
} feprx_cmd_t;
typedef struct {
int aid;
struct RU_t_s *ru;
int slot;
int startSymbol;
int numSymbols;
} feptx_cmd_t;
typedef struct {
int frame;
@@ -246,7 +244,7 @@ typedef struct RU_proc_t_s {
/// \internal This variable is protected by \ref mutex_asynch_rxtx.
int instance_cnt_asynch_rxtx;
/// \internal This variable is protected by \ref mutex_fep
int instance_cnt_fep;
int instance_cnt_fep[8];
/// \internal This variable is protected by \ref mutex_feptx
int instance_cnt_feptx;
/// \internal This variable is protected by \ref mutex_ru_thread
@@ -265,7 +263,7 @@ typedef struct RU_proc_t_s {
/// pthread struct for RU synch thread
pthread_t pthread_synch;
/// pthread struct for RU RX FEP worker thread
pthread_t pthread_fep;
pthread_t pthread_fep[8];
/// pthread struct for RU TX FEP worker thread
pthread_t pthread_feptx;
/// pthread struct for emulated RF
@@ -318,7 +316,7 @@ typedef struct RU_proc_t_s {
/// condition variable for asynch RX/TX thread
pthread_cond_t cond_asynch_rxtx;
/// condition varible for RU RX FEP thread
pthread_cond_t cond_fep;
pthread_cond_t cond_fep[8];
/// condition varible for RU TX FEP thread
pthread_cond_t cond_feptx;
/// condition varible for emulated RF
@@ -345,7 +343,7 @@ typedef struct RU_proc_t_s {
/// mutex for asynch RX/TX thread
pthread_mutex_t mutex_asynch_rxtx;
/// mutex for fep RX worker thread
pthread_mutex_t mutex_fep;
pthread_mutex_t mutex_fep[8];
/// mutex for fep TX worker thread
pthread_mutex_t mutex_feptx;
/// mutex for ru_thread
@@ -395,10 +393,6 @@ typedef struct RU_proc_t_s {
/// structure for precoding thread
RU_prec_t prec[16];
/// structure for feptx thread
RU_feptx_t feptx[16];
/// mask for checking process finished
int feptx_mask;
} RU_proc_t;
typedef enum {
@@ -433,6 +427,8 @@ typedef enum {
typedef struct RU_t_s {
/// ThreadPool for RU
tpool_t *threadPool;
/// index of this ru
uint32_t idx;
/// pointer to first RU
@@ -507,6 +503,10 @@ typedef struct RU_t_s {
int sf_ahead;
/// TX processing advance in slots (for NR)
int sl_ahead;
/// flag to indicate TX FH is embedded in TX FEP
int txfh_in_fep;
/// flag to indicate half-slot parallelization
int half_slot_parallelization;
/// FAPI confiuration
nfapi_nr_config_request_scf_t config;
/// Frame parameters
@@ -645,6 +645,22 @@ typedef struct RU_t_s {
uint64_t if_frequency;
/// UL IF frequency offset to DL IF frequency in Hz
int if_freq_offset;
/// to signal end of feprx
notifiedFIFO_t *respfeprx;
/// to signal end of feptx
notifiedFIFO_t *respfeptx;
/// core id for RX fhaul (IF5 ECPRI)
int rxfh_core_id;
/// core id for RX fhaul (IF5 ECPRI)
int txfh_core_id;
/// number of RU interfaces
int num_fd;
/// list of cores for RU ThreadPool
int tpcores[16];
/// number of cores for RU ThreadPool
int num_tpcores;
/// structure for analyzing high-level RT measurements
rt_ru_profiling_t rt_ru_profiling;
} RU_t;
+3
View File
@@ -42,6 +42,7 @@
#include "PHY/defs_common.h"
#include "PHY/CODING/nrLDPC_extern.h"
#include "PHY/CODING/nrLDPC_decoder/nrLDPC_types.h"
#include "executables/rt_profiling.h"
#include "nfapi_nr_interface_scf.h"
@@ -897,6 +898,8 @@ typedef struct PHY_VARS_gNB_s {
int number_of_nr_dlsch_max;
int number_of_nr_ulsch_max;
void * scopeData;
/// structure for analyzing high-level RT measurements
rt_L1_profiling_t rt_L1_profiling;
} PHY_VARS_gNB;
typedef struct LDPCDecode_s {
+22 -23
View File
@@ -57,7 +57,6 @@
#include "SCHED/sched_eNB.h"
#include "PHY/MODULATION/modulation_eNB.h"
#include "PHY/LTE_TRANSPORT/if4_tools.h"
#include "PHY/LTE_TRANSPORT/if5_tools.h"
#include "PHY/LTE_TRANSPORT/transport_common_proto.h"
#include "PHY/LTE_TRANSPORT/transport_proto.h"
#include "PHY/LTE_UE_TRANSPORT/transport_proto_ue.h"
@@ -566,15 +565,15 @@ static void *fep_thread(void *param)
while (!oai_exit) {
if (wait_on_condition(&proc->mutex_fep,&proc->cond_fep,&proc->instance_cnt_fep,"fep thread")<0) break;
if (wait_on_condition(&proc->mutex_fep[0],&proc->cond_fep[0],&proc->instance_cnt_fep[0],"fep thread")<0) break;
if (oai_exit) break;
//stop_meas(&ru->ofdm_demod_wakeup_stats);
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX1, 1 );
fep0(ru,0);
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX1, 0 );
if (release_thread(&proc->mutex_fep,&proc->instance_cnt_fep,"fep thread")<0) break;
if (release_thread(&proc->mutex_fep[0],&proc->instance_cnt_fep[0],"fep thread")<0) break;
if (pthread_cond_signal(&proc->cond_fep) != 0) {
if (pthread_cond_signal(&proc->cond_fep[0]) != 0) {
printf("[eNB] ERROR pthread_cond_signal for fep thread exit\n");
exit_fun( "ERROR pthread_cond_signal" );
return NULL;
@@ -607,12 +606,12 @@ void init_fep_thread(RU_t *ru,
{
RU_proc_t *proc = &ru->proc;
proc->instance_cnt_fep = -1;
proc->instance_cnt_fep[0] = -1;
pthread_mutex_init( &proc->mutex_fep, NULL);
pthread_cond_init( &proc->cond_fep, NULL);
pthread_mutex_init( &proc->mutex_fep[0], NULL);
pthread_cond_init( &proc->cond_fep[0], NULL);
threadCreate(&proc->pthread_fep, fep_thread, (void*)ru, "fep", -1, OAI_PRIORITY_RT);
threadCreate(&proc->pthread_fep[0], fep_thread, (void*)ru, "fep", -1, OAI_PRIORITY_RT);
}
@@ -621,14 +620,14 @@ void kill_fep_thread(RU_t *ru)
RU_proc_t *proc = &ru->proc;
if (proc->pthread_fep == 0)
return;
pthread_mutex_lock( &proc->mutex_fep );
proc->instance_cnt_fep = 0;
pthread_cond_signal(&proc->cond_fep);
pthread_mutex_unlock( &proc->mutex_fep );
pthread_mutex_lock( &proc->mutex_fep[0] );
proc->instance_cnt_fep[0] = 0;
pthread_cond_signal(&proc->cond_fep[0]);
pthread_mutex_unlock( &proc->mutex_fep[0] );
LOG_D(PHY, "Joining pthread_fep\n");
pthread_join(proc->pthread_fep, NULL);
pthread_mutex_destroy( &proc->mutex_fep );
pthread_cond_destroy( &proc->cond_fep );
pthread_join(proc->pthread_fep[0], NULL);
pthread_mutex_destroy( &proc->mutex_fep[0] );
pthread_cond_destroy( &proc->cond_fep[0] );
}
@@ -670,35 +669,35 @@ void ru_fep_full_2thread(RU_t *ru,
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+ru->idx, 1 );
start_meas(&ru->ofdm_demod_stats);
if (pthread_mutex_timedlock(&proc->mutex_fep,&wait) != 0) {
printf("[RU] ERROR pthread_mutex_lock for fep thread (IC %d)\n", proc->instance_cnt_fep);
if (pthread_mutex_timedlock(&proc->mutex_fep[0],&wait) != 0) {
printf("[RU] ERROR pthread_mutex_lock for fep thread (IC %d)\n", proc->instance_cnt_fep[0]);
exit_fun( "error locking mutex_fep" );
return;
}
if (proc->instance_cnt_fep==0) {
if (proc->instance_cnt_fep[0]==0) {
printf("[RU] FEP thread busy\n");
exit_fun("FEP thread busy");
pthread_mutex_unlock( &proc->mutex_fep );
pthread_mutex_unlock( &proc->mutex_fep[0] );
return;
}
++proc->instance_cnt_fep;
++proc->instance_cnt_fep[0];
if (pthread_cond_signal(&proc->cond_fep) != 0) {
if (pthread_cond_signal(&proc->cond_fep[0]) != 0) {
printf("[RU] ERROR pthread_cond_signal for fep thread\n");
exit_fun( "ERROR pthread_cond_signal" );
return;
}
//start_meas(&ru->ofdm_demod_wakeup_stats);
pthread_mutex_unlock( &proc->mutex_fep );
pthread_mutex_unlock( &proc->mutex_fep[0] );
// call second slot in this symbol
fep0(ru,1);
start_meas(&ru->ofdm_demod_wait_stats);
wait_on_busy_condition(&proc->mutex_fep,&proc->cond_fep,&proc->instance_cnt_fep,"fep thread");
wait_on_busy_condition(&proc->mutex_fep[0],&proc->cond_fep[0],&proc->instance_cnt_fep[0],"fep thread");
stop_meas(&ru->ofdm_demod_wait_stats);
if(opp_enabled == 1 && ru->ofdm_demod_wakeup_stats.p_time>30*3000){
print_meas_now(&ru->ofdm_demod_wakeup_stats,"fep wakeup",stderr);
+178 -463
View File
@@ -35,7 +35,6 @@
#include "PHY/MODULATION/modulation_common.h"
#include "PHY/MODULATION/nr_modulation.h"
#include "PHY/LTE_TRANSPORT/if4_tools.h"
#include "PHY/LTE_TRANSPORT/if5_tools.h"
#include "common/utils/LOG/log.h"
#include "common/utils/system.h"
@@ -46,12 +45,14 @@
#include "assertions.h"
#include <time.h>
// RU OFDM Modulator gNodeB
extern openair0_config_t openair0_cfg[MAX_CARDS];
extern int oai_exit;
// OFDM modulation core routine, generates a first_symbol to first_symbol+num_symbols on a particular slot and TX antenna port
void nr_feptx0(RU_t *ru,int tti_tx,int first_symbol, int num_symbols, int aa) {
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
@@ -62,6 +63,7 @@ void nr_feptx0(RU_t *ru,int tti_tx,int first_symbol, int num_symbols, int aa) {
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM+(first_symbol!=0?1:0) , 1 );
if (aa==0 && first_symbol == 0) start_meas(&ru->ofdm_mod_stats);
slot_offset = fp->get_samples_slot_timestamp(slot,fp,0);
slot_offsetF = first_symbol*fp->ofdm_symbol_size;
@@ -72,16 +74,16 @@ void nr_feptx0(RU_t *ru,int tti_tx,int first_symbol, int num_symbols, int aa) {
slot_offset += fp->ofdm_symbol_size*first_symbol;
LOG_D(PHY,"SFN/SF:RU:TX:%d/%d Generating slot %d (first_symbol %d num_symbols %d)\n",ru->proc.frame_tx, ru->proc.tti_tx,slot,first_symbol,num_symbols);
LOG_D(PHY,"SFN/SF:RU:TX:%d/%d aa %d Generating slot %d (first_symbol %d num_symbols %d) slot_offset %d, slot_offsetF %d\n",ru->proc.frame_tx, ru->proc.tti_tx,aa,slot,first_symbol,num_symbols,slot_offset,slot_offsetF);
if (fp->Ncp == 1)
if (fp->Ncp == 1) {
PHY_ofdm_mod(&ru->common.txdataF_BF[aa][slot_offsetF],
(int*)&ru->common.txdata[aa][slot_offset],
fp->ofdm_symbol_size,
num_symbols,
fp->nb_prefix_samples,
CYCLIC_PREFIX);
else {
} else {
if (fp->numerology_index != 0) {
if (!(slot%(fp->slots_per_subframe/2))&&(first_symbol==0)) { // case where first symbol in slot has longer prefix
@@ -130,280 +132,16 @@ void nr_feptx0(RU_t *ru,int tti_tx,int first_symbol, int num_symbols, int aa) {
slot_offset += fp->nb_prefix_samples0+fp->ofdm_symbol_size;
slot_offsetF += fp->ofdm_symbol_size;
}
}
}
} // for(idx_symbol..
} // numerology 0
}
if (aa==0 && first_symbol==0) stop_meas(&ru->ofdm_mod_stats);
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM+(first_symbol!=0?1:0), 0);
}
void nr_feptx_ofdm_2thread(RU_t *ru,int frame_tx,int tti_tx) {
nfapi_nr_config_request_scf_t *cfg = &ru->gNB_list[0]->gNB_config;
RU_proc_t *proc = &ru->proc;
RU_feptx_t *feptx = proc->feptx;
PHY_VARS_gNB *gNB;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
int slot = tti_tx;
int i = 0;
int j = 0;//symbol
int aa = 0;//physical antenna number
int ret = 0;
int ofdm_mask_full = (1<<(ru->nb_tx*2))-1;
int txdataF_offset = (tti_tx*fp->samples_per_slot_wCP);
if (nr_slot_select(cfg,frame_tx,slot) == NR_UPLINK_SLOT) return;
for (aa=0; aa<ru->nb_tx; aa++) memset(ru->common.txdataF[aa],0,fp->samples_per_slot_wCP*sizeof(int32_t));
start_meas(&ru->ofdm_total_stats);
//if (nr_slot_select(cfg,frame_tx,slot)==NR_DOWNLINK_SLOT) {
if(ru->num_gNB != 0){//L1 RU on same machine
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM , 1 );
for(j=0; j<2; ++j){//half slot
for(i=0; i<ru->nb_tx; ++i){
if(j == 0){
AssertFatal((ret=pthread_mutex_lock(&feptx[i].mutex_feptx))==0,"mutex_lock return %d\n",ret);
feptx[i].aa = i;
feptx[i].index = i;
feptx[i].ru = ru;
feptx[i].symbol = 0;
feptx[i].slot = slot;
feptx[i].nb_antenna_ports = ru->nb_tx;
feptx[i].instance_cnt_feptx = 0;
AssertFatal(pthread_cond_signal(&feptx[i].cond_feptx) == 0,"ERROR pthread_cond_signal for feptx_ofdm_thread\n");
AssertFatal((ret=pthread_mutex_unlock(&feptx[i].mutex_feptx))==0,"mutex_lock returns %d\n",ret);
}//first half
else{
AssertFatal((ret=pthread_mutex_lock(&feptx[i+ru->nb_tx].mutex_feptx))==0,"mutex_lock return %d\n",ret);
feptx[i+ru->nb_tx].aa = i;
feptx[i+ru->nb_tx].index = i+ru->nb_tx;
feptx[i+ru->nb_tx].ru = ru;
feptx[i+ru->nb_tx].symbol = fp->symbols_per_slot>>1;
feptx[i+ru->nb_tx].slot = slot;
feptx[i+ru->nb_tx].nb_antenna_ports = ru->nb_tx;
feptx[i+ru->nb_tx].instance_cnt_feptx = 0;
AssertFatal(pthread_cond_signal(&feptx[i+ru->nb_tx].cond_feptx) == 0,"ERROR pthread_cond_signal for feptx_ofdm_thread\n");
AssertFatal((ret=pthread_mutex_unlock(&feptx[i+ru->nb_tx].mutex_feptx))==0,"mutex_lock returns %d\n",ret);
}//second half
}//physical antenna
}//half slot
}//if L1 RU on same machine
else{//(RU only machine)
for(j=0; j<fp->symbols_per_slot; ++j){
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_PREC+j , 1);
start_meas(&ru->txdataF_copy_stats);
AssertFatal(ru->num_gNB==1,"num_gNB>1, help\n");
gNB = ru->gNB_list[0];
cfg = &gNB->gNB_config;
for(i=0; i<ru->nb_tx; ++i){
memcpy((void*)&ru->common.txdataF[i][j*fp->ofdm_symbol_size],
(void*)&gNB->common_vars.txdataF[i][j*fp->ofdm_symbol_size + txdataF_offset],
fp->ofdm_symbol_size*sizeof(int32_t));
}
stop_meas(&ru->txdataF_copy_stats);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_PREC+j , 0);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM , 1 );
if (nr_slot_select(cfg,slot,frame_tx)==SF_DL) {
// If this is not an S-tti
for(i=0; i<ru->nb_tx; ++i){
if(j%2 == 0){
while(feptx[i].instance_cnt_feptx != -1){
usleep(5);
}
AssertFatal((ret=pthread_mutex_lock(&feptx[i].mutex_feptx))==0,"mutex_lock return %d\n",ret);
feptx[i].aa = i;
feptx[i].index = i;
feptx[i].ru = ru;
feptx[i].symbol = j;
feptx[i].slot = slot;
feptx[i].nb_antenna_ports = ru->nb_tx;
feptx[i].instance_cnt_feptx = 0;
AssertFatal(pthread_cond_signal(&feptx[i].cond_feptx) == 0,"ERROR pthread_cond_signal for feptx_ofdm_thread\n");
AssertFatal((ret=pthread_mutex_unlock(&feptx[i].mutex_feptx))==0,"mutex_lock returns %d\n",ret);
}
else{
while(feptx[i+ru->nb_tx].instance_cnt_feptx != -1){
usleep(5);
}
AssertFatal((ret=pthread_mutex_lock(&feptx[i+ru->nb_tx].mutex_feptx))==0,"mutex_lock return %d\n",ret);
feptx[i+ru->nb_tx].aa = i;
feptx[i+ru->nb_tx].index = i+ru->nb_tx;
feptx[i+ru->nb_tx].ru = ru;
feptx[i+ru->nb_tx].symbol = j;
feptx[i+ru->nb_tx].slot = slot;
feptx[i+ru->nb_tx].nb_antenna_ports = ru->nb_tx;
feptx[i+ru->nb_tx].instance_cnt_feptx = 0;
AssertFatal(pthread_cond_signal(&feptx[i+ru->nb_tx].cond_feptx) == 0,"ERROR pthread_cond_signal for feptx_ofdm_thread\n");
AssertFatal((ret=pthread_mutex_unlock(&feptx[i+ru->nb_tx].mutex_feptx))==0,"mutex_lock returns %d\n",ret);
}
}
}//if == SF_DL
else {
proc->feptx_mask = ofdm_mask_full;
}
}//j<fp->symbols_per_slot
}//else (RU only machine)
//}
// wait all process to finish
AssertFatal((ret=pthread_mutex_lock(&proc->mutex_feptx))==0,"mutex_lock return %d\n",ret);
while (proc->feptx_mask != ofdm_mask_full) {
// most of the time the thread is waiting here
// proc->instance_cnt_rxtx is -1
pthread_cond_wait(&proc->cond_feptx,&proc->mutex_feptx); // this unlocks mutex_rxtx while waiting and then locks it again
}
proc->feptx_mask = 0;
AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_feptx))==0,"mutex_lock return %d\n",ret);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RU_TX_OFDM_MASK, proc->feptx_mask );
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM , 0 );
stop_meas(&ru->ofdm_total_stats);
}
static void *nr_feptx_thread(void *param) {
RU_feptx_t *feptx = (RU_feptx_t *)param;
RU_t *ru;
int aa, slot, start, l, ret;
int i;
int32_t ***bw;
NR_DL_FRAME_PARMS *fp;
int ofdm_mask_full;
int txdataF_offset;
while (!oai_exit) {
ret = 0;
if (wait_on_condition(&feptx->mutex_feptx,&feptx->cond_feptx,&feptx->instance_cnt_feptx,"NR feptx thread")<0) break;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM+feptx->index+1 , 1 );
AssertFatal(feptx->ru->nb_log_antennas>0 && feptx->ru->nb_log_antennas < 13,"ru->nb_log_antennas is %d\n", feptx->ru->nb_log_antennas);
ru = feptx->ru;
slot = feptx->slot;
aa = feptx->aa;
l = feptx->symbol;
fp = ru->nr_frame_parms;
start = feptx->symbol;
ofdm_mask_full = (1<<(ru->nb_tx*2))-1;
if(ru->num_gNB != 0){
txdataF_offset = (slot*fp->samples_per_slot_wCP);
////////////precoding////////////
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_PREC+feptx->index+1 , 1);
if (aa==0 && l==0) start_meas(&ru->precoding_stats);
if (ru->do_precoding == 1) {
for(i=0; i<ru->nb_log_antennas; ++i) {
memcpy((void*) &ru->common.beam_id[i][slot*fp->symbols_per_slot+l],
(void*) &ru->gNB_list[0]->common_vars.beam_id[i][slot*fp->symbols_per_slot+l],
(fp->symbols_per_slot>>1)*sizeof(uint8_t));
}
}
if (ru->nb_tx == 1 && ru->nb_log_antennas == 1) {
memcpy((void*)&ru->common.txdataF_BF[0][l*fp->ofdm_symbol_size],
(void*)&ru->gNB_list[0]->common_vars.txdataF[0][txdataF_offset + l*fp->ofdm_symbol_size],
(fp->samples_per_slot_wCP>>1)*sizeof(int32_t));
}
else if (ru->do_precoding == 0) {
int gNB_tx = ru->gNB_list[0]->frame_parms.nb_antennas_tx;
memcpy((void*)&ru->common.txdataF_BF[aa][l*fp->ofdm_symbol_size],
(void*)&ru->gNB_list[0]->common_vars.txdataF[aa%gNB_tx][txdataF_offset + l*fp->ofdm_symbol_size],
(fp->samples_per_slot_wCP>>1)*sizeof(int32_t));
}
else {
bw = ru->beam_weights[0];
for(i=0; i<fp->symbols_per_slot>>1; ++i){
nr_beam_precoding(ru->gNB_list[0]->common_vars.txdataF,
ru->common.txdataF_BF,
fp,
bw,
slot,
l+i,
aa,
ru->nb_log_antennas,
txdataF_offset);//here
}
}
if (aa==0 && l==0) stop_meas(&ru->precoding_stats);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_PREC+feptx->index+1 , 0);
////////////FEPTX////////////
if (aa==0 && l==0) start_meas(&ru->ofdm_mod_stats);
nr_feptx0(ru,slot,start,fp->symbols_per_slot>>1,aa);
if (aa==0 && l==0) stop_meas(&ru->ofdm_mod_stats);
if (release_thread(&feptx->mutex_feptx,&feptx->instance_cnt_feptx,"NR feptx thread")<0) break;
AssertFatal((ret=pthread_mutex_lock(&ru->proc.mutex_feptx))==0,"mutex_lock return %d\n",ret);
ru->proc.feptx_mask |= 1<<(feptx->index);
if(ru->proc.feptx_mask == ofdm_mask_full)
AssertFatal(pthread_cond_signal(&ru->proc.cond_feptx) == 0,"ERROR pthread_cond_signal for precoding and ofdm finish\n");
AssertFatal((ret=pthread_mutex_unlock(&ru->proc.mutex_feptx))==0,"mutex_lock returns %d\n",ret);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RU_TX_OFDM_MASK, ru->proc.feptx_mask );
}// if L1 RU on same machine
else{
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_PREC+feptx->index+1 , 1);
start_meas(&ru->precoding_stats);
if (ru->nb_tx == 1 && ru->nb_log_antennas) {
memcpy((void*)&ru->common.txdataF_BF[0][l*fp->ofdm_symbol_size],
(void*)&ru->common.txdataF[0][l*fp->ofdm_symbol_size],
fp->ofdm_symbol_size*sizeof(int32_t));
}
else {
bw = ru->beam_weights[0];
nr_beam_precoding(ru->common.txdataF,
ru->common.txdataF_BF,
fp,
bw,
slot,
l,
aa,
ru->nb_log_antennas,
0);
}
stop_meas(&ru->precoding_stats);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_PREC+feptx->index+1 , 0);
start_meas(&ru->ofdm_mod_stats);
nr_feptx0(ru,slot,start,1,aa);
stop_meas(&ru->ofdm_mod_stats);
if (release_thread(&feptx->mutex_feptx,&feptx->instance_cnt_feptx,"NR feptx thread")<0) break;
if(l >= fp->symbols_per_slot -2){
AssertFatal((ret=pthread_mutex_lock(&ru->proc.mutex_feptx))==0,"mutex_lock return %d\n",ret);
ru->proc.feptx_mask |= 1<<(feptx->index);
if(ru->proc.feptx_mask == ofdm_mask_full)
AssertFatal(pthread_cond_signal(&ru->proc.cond_feptx) == 0,"ERROR pthread_cond_signal for precoding and ofdm finish\n");
AssertFatal((ret=pthread_mutex_unlock(&ru->proc.mutex_feptx))==0,"mutex_lock returns %d\n",ret);
}
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_RU_TX_OFDM_MASK, ru->proc.feptx_mask );
}// else (RU only machine)
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM+feptx->index+1 , 0 );
}// while (oai_exit)
return(NULL);
}
// is this supposed to generate a slot or a subframe???
// seems to be hardcoded to numerology 1 (2 slots=1 subframe)
// RU FEP TX OFDM modulation, single-thread
void nr_feptx_ofdm(RU_t *ru,int frame_tx,int tti_tx) {
nfapi_nr_config_request_scf_t *cfg = &ru->gNB_list[0]->gNB_config;
@@ -419,7 +157,6 @@ void nr_feptx_ofdm(RU_t *ru,int frame_tx,int tti_tx) {
if (nr_slot_select(cfg,frame_tx,slot) == NR_UPLINK_SLOT) return;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM , 1 );
start_meas(&ru->ofdm_mod_stats);
// LOG_D(HW,"Frame %d: Generating slot %d\n",frame,next_slot);
@@ -427,7 +164,6 @@ void nr_feptx_ofdm(RU_t *ru,int frame_tx,int tti_tx) {
nr_feptx0(ru,slot,0,NR_NUMBER_OF_SYMBOLS_PER_SLOT,aa);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM , 0 );
stop_meas(&ru->ofdm_mod_stats);
LOG_D(PHY,"feptx_ofdm (TXPATH): frame %d, slot %d: txp (time %p) %d dB, txp (freq) %d dB\n",
frame_tx,slot,txdata,dB_fixed(signal_energy((int32_t*)txdata,fp->get_samples_per_slot(
@@ -435,43 +171,6 @@ void nr_feptx_ofdm(RU_t *ru,int frame_tx,int tti_tx) {
}
void nr_init_feptx_thread(RU_t *ru) {
RU_proc_t *proc = &ru->proc;
RU_feptx_t *feptx = proc->feptx;
int i = 0;
for(i=0; i<(ru->nb_tx*2); i++){
feptx[i].instance_cnt_feptx = -1;
pthread_mutex_init( &feptx[i].mutex_feptx, NULL);
pthread_cond_init( &feptx[i].cond_feptx, NULL);
threadCreate(&feptx[i].pthread_feptx, nr_feptx_thread, (void*)&feptx[i], "feptx", -1, OAI_PRIORITY_RT);
LOG_I(PHY,"init feptx thread %d\n", i);
}
}
void nr_kill_feptx_thread(RU_t *ru) {
RU_proc_t *proc = &ru->proc;
for (int i = 0; i < ru->nb_tx * 2; i++) {
RU_feptx_t *feptx = &proc->feptx[i];
if (feptx->pthread_feptx == 0)
continue;
pthread_mutex_lock(&feptx->mutex_feptx);
feptx->instance_cnt_feptx = 0;
pthread_mutex_unlock(&feptx->mutex_feptx);
pthread_cond_signal(&feptx->cond_feptx);
LOG_I(PHY, "Joining pthread_feptx %d\n", i);
pthread_join(feptx->pthread_feptx, NULL);
pthread_mutex_destroy(&feptx->mutex_feptx);
pthread_cond_destroy(&feptx->cond_feptx);
}
}
void nr_feptx_prec(RU_t *ru,int frame_tx,int tti_tx) {
int l,aa;
@@ -530,157 +229,6 @@ void nr_feptx_prec(RU_t *ru,int frame_tx,int tti_tx) {
stop_meas(&ru->precoding_stats);
}
void nr_fep0(RU_t *ru, int first_half) {
uint8_t start_symbol, end_symbol, l, aa;
RU_proc_t *proc = &ru->proc;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
if(first_half == 1) {
start_symbol = 0;
end_symbol = NR_SYMBOLS_PER_SLOT/2;
} else {
start_symbol = NR_SYMBOLS_PER_SLOT/2;
end_symbol = NR_SYMBOLS_PER_SLOT;
}
LOG_D(PHY,"In fep0 for slot = %d, first_half = %d, start_symbol = %d, end_symbol = %d, nb_antennas_rx = %d,N_TA_offset = %d\n",
proc->tti_rx, first_half, start_symbol, end_symbol,fp->nb_antennas_rx,ru->N_TA_offset);
// printf("fep0: slot %d\n",slot);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+proc->tti_rx, 1);
int offset = (proc->tti_rx&3) * fp->symbols_per_slot * fp->ofdm_symbol_size;
for (l = start_symbol; l < end_symbol; l++) {
for (aa = 0; aa < fp->nb_antennas_rx; aa++) {
nr_slot_fep_ul(fp,
ru->common.rxdata[aa],
&ru->common.rxdataF[aa][offset],
l,
proc->tti_rx,
ru->N_TA_offset);
}
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+proc->tti_rx, 0);
}
static void *nr_feprx_thread(void *param) {
RU_t *ru = (RU_t *)param;
RU_proc_t *proc = &ru->proc;
while (!oai_exit) {
if (wait_on_condition(&proc->mutex_fep,&proc->cond_fep,&proc->instance_cnt_fep,"NR feprx thread")<0) break;
if (oai_exit) break;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX1, 1 );
nr_fep0(ru, 0);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX1, 0 );
if (release_thread(&proc->mutex_fep,&proc->instance_cnt_fep,"nr_feprx thread")<0) break;
if (pthread_cond_signal(&proc->cond_fep) != 0) {
printf("[gNB] ERROR pthread_cond_signal for nr_feprx thread exit\n");
exit_fun( "ERROR pthread_cond_signal" );
return NULL;
}
}
return NULL;
}
void nr_init_feprx_thread(RU_t *ru) {
RU_proc_t *proc = &ru->proc;
proc->instance_cnt_fep = -1;
pthread_mutex_init( &proc->mutex_fep, NULL);
pthread_cond_init( &proc->cond_fep, NULL);
threadCreate(&proc->pthread_fep, nr_feprx_thread, (void*)ru, "feprx", -1, OAI_PRIORITY_RT);
}
void nr_kill_feprx_thread(RU_t *ru) {
RU_proc_t *proc = &ru->proc;
if (proc->pthread_fep == 0)
return;
LOG_I(PHY, "Joining pthread_feprx\n");
pthread_mutex_lock(&proc->mutex_fep);
proc->instance_cnt_fep = 0;
pthread_mutex_unlock(&proc->mutex_fep);
pthread_cond_signal(&proc->cond_fep);
pthread_join(proc->pthread_fep, NULL);
pthread_mutex_destroy(&proc->mutex_fep);
pthread_cond_destroy(&proc->cond_fep);
}
void nr_fep_full_2thread(RU_t *ru, int slot) {
RU_proc_t *proc = &ru->proc;
struct timespec wait;
// NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
// if ((fp->frame_type == TDD) &&
// (subframe_select(fp,proc->tti_rx) != NR_UPLINK_SLOT)) return;
if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 1 );
wait.tv_sec=0;
wait.tv_nsec=5000000L;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 1 );
start_meas(&ru->ofdm_demod_stats);
if (pthread_mutex_timedlock(&proc->mutex_fep,&wait) != 0) {
printf("[RU] ERROR pthread_mutex_lock for nr_feprx thread (IC %d)\n", proc->instance_cnt_fep);
exit_fun( "error locking mutex_fep" );
return;
}
if (proc->instance_cnt_fep==0) {
LOG_E(PHY, "RU FEP thread busy, exiting %s\n", __func__);
pthread_mutex_unlock( &proc->mutex_fep );
return;
}
++proc->instance_cnt_fep;
if (pthread_cond_signal(&proc->cond_fep) != 0) {
printf("[RU] ERROR pthread_cond_signal for nr_feprx thread\n");
exit_fun( "ERROR pthread_cond_signal" );
return;
}
//start_meas(&ru->ofdm_demod_wakeup_stats);
pthread_mutex_unlock( &proc->mutex_fep );
// call second slot in this symbol
nr_fep0(ru, 1);
start_meas(&ru->ofdm_demod_wait_stats);
wait_on_busy_condition(&proc->mutex_fep,&proc->cond_fep,&proc->instance_cnt_fep,"nr_feprx thread");
stop_meas(&ru->ofdm_demod_wait_stats);
if(opp_enabled == 1 && ru->ofdm_demod_wakeup_stats.p_time>30*3000){
print_meas_now(&ru->ofdm_demod_wakeup_stats,"fep wakeup",stderr);
printf("delay in fep wait on codition in frame_rx: %d subframe_rx: %d \n",proc->frame_rx,proc->tti_rx);
}
stop_meas(&ru->ofdm_demod_stats);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 0 );
}
void nr_fep_full(RU_t *ru, int slot) {
@@ -716,3 +264,170 @@ void nr_fep_full(RU_t *ru, int slot) {
}
// core routine for FEP TX, called from threads in RU TX thread-pool
void nr_feptx(void *arg) {
feptx_cmd_t *feptx = (feptx_cmd_t *)arg;
RU_t *ru = feptx->ru;
int slot = feptx->slot;
int aa = feptx->aid;
int startSymbol = feptx->startSymbol;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
int numSymbols = feptx->numSymbols;
int numSamples = feptx->numSymbols*fp->ofdm_symbol_size;
int txdataF_offset = (slot*fp->samples_per_slot_wCP) + startSymbol*fp->ofdm_symbol_size;
int txdataF_BF_offset = startSymbol*fp->ofdm_symbol_size;
////////////precoding////////////
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_PREC+feptx->aid , 1);
if (aa==0) start_meas(&ru->precoding_stats);
if (ru->do_precoding == 1) {
for(int i=0; i<ru->nb_log_antennas; ++i) {
memcpy((void*) &ru->common.beam_id[i][slot*fp->symbols_per_slot],
(void*) &ru->gNB_list[0]->common_vars.beam_id[i][slot*fp->symbols_per_slot],
(fp->symbols_per_slot)*sizeof(uint8_t));
}
}
if (ru->nb_tx == 1 && ru->nb_log_antennas == 1) {
memcpy((void*)&ru->common.txdataF_BF[0][txdataF_BF_offset],
(void*)&ru->gNB_list[0]->common_vars.txdataF[0][txdataF_offset],
numSamples*sizeof(int32_t));
}
else if (ru->do_precoding == 0) {
int gNB_tx = ru->gNB_list[0]->frame_parms.nb_antennas_tx;
memcpy((void*)&ru->common.txdataF_BF[aa][txdataF_BF_offset],
(void*)&ru->gNB_list[0]->common_vars.txdataF[aa%gNB_tx][txdataF_offset],
numSamples*sizeof(int32_t));
}
else {
AssertFatal(1==0,"This needs to be fixed, do not use beamforming.\n");
int32_t ***bw = ru->beam_weights[0];
for(int i=0; i<fp->symbols_per_slot; ++i){
nr_beam_precoding(ru->gNB_list[0]->common_vars.txdataF,
ru->common.txdataF_BF,
fp,
bw,
slot,
i,
aa,
ru->nb_log_antennas,
txdataF_offset);//here
}
}
if (aa==0) stop_meas(&ru->precoding_stats);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_PREC+feptx->aid , 0);
////////////FEPTX////////////
nr_feptx0(ru,slot,startSymbol,numSymbols,aa);
}
// RU FEP TX using thread-pool
void nr_feptx_tp(RU_t *ru, int frame_tx, int slot) {
nfapi_nr_config_request_scf_t *cfg = &ru->gNB_list[0]->gNB_config;
int nbfeptx=0;
if (nr_slot_select(cfg,frame_tx,slot) == NR_UPLINK_SLOT) return;
// for (int aa=0; aa<ru->nb_tx; aa++) memset(ru->common.txdataF[aa],0,ru->nr_frame_parms->samples_per_slot_wCP*sizeof(int32_t));
if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM, 1 );
start_meas(&ru->ofdm_total_stats);
for (int aid=0;aid<ru->nb_tx;aid++) {
notifiedFIFO_elt_t *req=newNotifiedFIFO_elt(sizeof(feptx_cmd_t), 2000 + aid,ru->respfeptx,nr_feptx);
feptx_cmd_t *feptx_cmd=(feptx_cmd_t*)NotifiedFifoData(req);
feptx_cmd->aid = aid;
feptx_cmd->ru = ru;
feptx_cmd->slot = slot;
feptx_cmd->startSymbol = 0;
feptx_cmd->numSymbols = (ru->half_slot_parallelization>0)?ru->nr_frame_parms->symbols_per_slot>>1:ru->nr_frame_parms->symbols_per_slot;
pushTpool(ru->threadPool,req);
nbfeptx++;
if (ru->half_slot_parallelization>0) {
notifiedFIFO_elt_t *req=newNotifiedFIFO_elt(sizeof(feptx_cmd_t), 2000 + aid + ru->nb_tx,ru->respfeptx,nr_feptx);
feptx_cmd_t *feptx_cmd=(feptx_cmd_t*)NotifiedFifoData(req);
feptx_cmd->aid = aid;
feptx_cmd->ru = ru;
feptx_cmd->slot = slot;
feptx_cmd->startSymbol = ru->nr_frame_parms->symbols_per_slot>>1;
feptx_cmd->numSymbols = ru->nr_frame_parms->symbols_per_slot>>1;
pushTpool(ru->threadPool,req);
nbfeptx++;
}
}
while (nbfeptx>0) {
notifiedFIFO_elt_t *req=pullTpool(ru->respfeptx, ru->threadPool);
delNotifiedFIFO_elt(req);
nbfeptx--;
}
stop_meas(&ru->ofdm_total_stats);
if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM, 0 );
}
// core RX FEP routine, called by threads in RU thread-pool
void nr_fep(void* arg) {
feprx_cmd_t *feprx_cmd = (feprx_cmd_t *)arg;
RU_t *ru = feprx_cmd->ru;
int aid = feprx_cmd->aid;
int tti_rx = feprx_cmd->slot;
int startSymbol = feprx_cmd->startSymbol;
int endSymbol = feprx_cmd->endSymbol;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
LOG_D(PHY,"In nr_fep for aid %d, slot = %d, startSymbol %d, endSymbol %d\n", aid, tti_rx,startSymbol,endSymbol);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+aid, 1);
int offset = (tti_rx&3) * fp->symbols_per_slot * fp->ofdm_symbol_size;
for (int l = startSymbol; l <= endSymbol; l++)
nr_slot_fep_ul(fp,
ru->common.rxdata[aid],
&ru->common.rxdataF[aid][offset],
l,
tti_rx,
ru->N_TA_offset);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+aid, 0);
}
// RU RX FEP using thread-pool
void nr_fep_tp(RU_t *ru, int slot) {
int nbfeprx=0;
if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 1 );
start_meas(&ru->ofdm_demod_stats);
for (int aid=0;aid<ru->nb_rx;aid++) {
notifiedFIFO_elt_t *req=newNotifiedFIFO_elt(sizeof(feprx_cmd_t), 1000 + aid,ru->respfeprx,nr_fep);
feprx_cmd_t *feprx_cmd=(feprx_cmd_t*)NotifiedFifoData(req);
feprx_cmd->aid = aid;
feprx_cmd->ru = ru;
feprx_cmd->slot = ru->proc.tti_rx;
feprx_cmd->startSymbol = 0;
feprx_cmd->endSymbol = (ru->half_slot_parallelization > 0)?(ru->nr_frame_parms->symbols_per_slot>>1)-1:(ru->nr_frame_parms->symbols_per_slot-1);
pushTpool(ru->threadPool,req);
nbfeprx++;
if (ru->half_slot_parallelization>0) {
notifiedFIFO_elt_t *req=newNotifiedFIFO_elt(sizeof(feprx_cmd_t), 1000 + aid + ru->nb_rx,ru->respfeprx,nr_fep);
feprx_cmd_t *feprx_cmd=(feprx_cmd_t*)NotifiedFifoData(req);
feprx_cmd->aid = aid;
feprx_cmd->ru = ru;
feprx_cmd->slot = ru->proc.tti_rx;
feprx_cmd->startSymbol = ru->nr_frame_parms->symbols_per_slot>>1;
feprx_cmd->endSymbol = ru->nr_frame_parms->symbols_per_slot-1;
pushTpool(ru->threadPool,req);
nbfeprx++;
}
}
while (nbfeprx>0) {
notifiedFIFO_elt_t *req=pullTpool(ru->respfeprx, ru->threadPool);
delNotifiedFIFO_elt(req);
nbfeprx--;
}
stop_meas(&ru->ofdm_demod_stats);
if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 0 );
}
+3 -7
View File
@@ -41,18 +41,14 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx);
void L1_nr_prach_procedures(PHY_VARS_gNB *gNB,int frame,int slot);
void nr_common_signal_procedures (PHY_VARS_gNB *gNB,int frame,int slot,nfapi_nr_dl_tti_ssb_pdu ssb_pdu);
void nr_feptx_ofdm(RU_t *ru,int frame_tx,int tti_tx);
void nr_feptx_ofdm_2thread(RU_t *ru,int frame_tx,int tti_tx);
void nr_feptx0(RU_t *ru,int tti_tx,int first_symbol, int num_symbols, int aa);
void nr_init_feptx_thread(RU_t *ru);
void nr_kill_feptx_thread(RU_t *ru);
void fep_full(RU_t *ru,int slot);
void nr_feptx_prec(RU_t *ru,int frame_tx,int tti_tx);
void nr_init_feptx_prec_thread(RU_t *ru);
void nr_feptx_prec_control(RU_t *ru,int frame,int tti_tx);
void nr_init_feprx_thread(RU_t *ru);
void nr_kill_feprx_thread(RU_t *ru);
void nr_fep_full(RU_t *ru, int slot);
void nr_fep_full_2thread(RU_t *ru, int slot);
void nr_fep_tp(RU_t *ru, int slot);
void nr_feptx_tp(RU_t *ru, int frame_tx, int slot);
void feptx_prec(RU_t *ru,int frame_tx,int tti_tx);
int nr_phy_init_RU(RU_t *ru);
void nr_phy_free_RU(RU_t *ru);
+1 -1
View File
@@ -1533,7 +1533,7 @@ int main(int argc, char **argv) {
}//ch realization
oai_exit=1;
pthread_cond_signal(&ru->proc.cond_fep);
pthread_cond_signal(&ru->proc.cond_fep[0]);
if (abstx) { // ABSTRACTION
fprintf(csv_fdUL,"];");
-3
View File
@@ -1063,7 +1063,6 @@ int main(int argc, char **argv)
double blerStats[4][100];
double berStats[4][100];
double snrStats[100];
double ldpcDecStats[100] = {0};
memset(errors_scrambling, 0, sizeof(uint32_t)*4*100);
memset(n_errors, 0, sizeof(int)*4*100);
memset(round_trials, 0, sizeof(int)*4*100);
@@ -1633,8 +1632,6 @@ int main(int argc, char **argv)
printf("\n");
}
ldpcDecStats[snrRun] = gNB->ulsch_decoding_stats.trials?inMicroS(gNB->ulsch_decoding_stats.diff/gNB->ulsch_decoding_stats.trials):0;
if(n_trials==1)
break;
+24
View File
@@ -103,11 +103,23 @@ typedef enum {
#define CONFIG_STRING_RU_SL_AHEAD "sl_ahead"
#define CONFIG_STRING_RU_NR_FLAG "nr_flag"
#define CONFIG_STRING_RU_NR_SCS_FOR_RASTER "nr_scs_for_raster"
#define CONFIG_STRING_RU_RXFH_CORE_ID "rxfh_core_id"
#define CONFIG_STRING_RU_TXFH_CORE_ID "txfh_core_id"
#define CONFIG_STRING_RU_TP_CORES "tp_cores"
#define CONFIG_STRING_RU_NUM_TP_CORES "num_tp_cores"
#define CONFIG_STRING_RU_NUM_INTERFACES "num_interfaces"
#define CONFIG_STRING_RU_HALF_SLOT_PARALLELIZATION "half_slot_parallelization"
#define HLP_RU_SF_AHEAD "LTE TX processing advance"
#define HLP_RU_SL_AHEAD "NR TX processing advance"
#define HLP_RU_NR_FLAG "Use NR numerology (for AW2SORI)"
#define HLP_RU_NR_SCS_FOR_RASTER "NR SCS for raster (for AW2SORI)"
#define HLP_RU_RXFH_CORE_ID "Core ID for RX Fronthaul thread (ECPRI IF5)"
#define HLP_RU_TXFH_CORE_ID "Core ID for TX Fronthaul thread (ECPRI IF5)"
#define HLP_RU_TP_CORES "List of cores for RU ThreadPool"
#define HLP_RU_NUM_TP_CORES "Number of cores for RU ThreadPool"
#define HLP_RU_NUM_INTERFACES "Number of network interfaces for RU"
#define HLP_RU_HALF_SLOT_PARALLELIZATION "run half slots in parallel in RU FEP"
#define RU_LOCAL_IF_NAME_IDX 0
#define RU_LOCAL_ADDRESS_IDX 1
@@ -142,6 +154,12 @@ typedef enum {
#define RU_SL_AHEAD 30
#define RU_NR_FLAG 31
#define RU_NR_SCS_FOR_RASTER 32
#define RU_RXFH_CORE_ID 33
#define RU_TXFH_CORE_ID 34
#define RU_TP_CORES 35
#define RU_NUM_TP_CORES 36
#define RU_NUM_INTERFACES 37
#define RU_HALF_SLOT_PARALLELIZATION 38
/*-----------------------------------------------------------------------------------------------------------------------------------------*/
/* RU configuration parameters */
/* optname helpstr paramflags XXXptr defXXXval type numelt */
@@ -180,6 +198,12 @@ typedef enum {
{CONFIG_STRING_RU_SL_AHEAD, HLP_RU_SL_AHEAD, 0, iptr:NULL, defintval:6, TYPE_INT, 0}, \
{CONFIG_STRING_RU_NR_FLAG, HLP_RU_NR_FLAG, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \
{CONFIG_STRING_RU_NR_SCS_FOR_RASTER, HLP_RU_NR_SCS_FOR_RASTER, 0, iptr:NULL, defintval:1, TYPE_INT, 0}, \
{CONFIG_STRING_RU_RXFH_CORE_ID, HLP_RU_RXFH_CORE_ID, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_TXFH_CORE_ID, HLP_RU_TXFH_CORE_ID, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_TP_CORES, HLP_RU_TP_CORES, 0, uptr:NULL, defintarrayval:DEFRUTPCORES, TYPE_INTARRAY, 8}, \
{CONFIG_STRING_RU_NUM_TP_CORES, HLP_RU_NUM_TP_CORES, 0, uptr:NULL, defintval:2, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_NUM_INTERFACES, HLP_RU_NUM_INTERFACES, 0, uptr:NULL, defintval:1, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_HALF_SLOT_PARALLELIZATION, HLP_RU_HALF_SLOT_PARALLELIZATION, 0, uptr:NULL, defintval:1, TYPE_UINT, 0}, \
}
/*---------------------------------------------------------------------------------------------------------------------------------------*/
@@ -1962,7 +1962,7 @@ void get_delta_arfcn(int i, uint32_t nrarfcn, uint64_t N_OFFs){
uint32_t delta_arfcn = nrarfcn - N_OFFs;
if(delta_arfcn%(nr_bandtable[i].step_size)!=0)
AssertFatal(1 == 0, "nrarfcn %u is not on the channel raster for step size %lu", nrarfcn, nr_bandtable[i].step_size);
AssertFatal(1==0, "nrarfcn %u is not on the channel raster for step size %lu", nrarfcn, nr_bandtable[i].step_size);
}
@@ -1982,10 +1982,10 @@ uint32_t to_nrarfcn(int nr_bandP,
"Band %d, bw %u : DL carrier frequency %llu kHz < %llu\n",
nr_bandP, bw, (long long unsigned int)dl_CarrierFreq_by_1k,
(long long unsigned int)nr_bandtable[i].dl_min);
AssertFatal(dl_CarrierFreq_by_1k <= (nr_bandtable[i].dl_max - bw_kHz),
AssertFatal(dl_CarrierFreq_by_1k <= (nr_bandtable[i].dl_max - bw_kHz/2),
"Band %d, dl_CarrierFreq %llu bw %u: DL carrier frequency %llu kHz > %llu\n",
nr_bandP, (long long unsigned int)dl_CarrierFreq,bw, (long long unsigned int)dl_CarrierFreq_by_1k,
(long long unsigned int)(nr_bandtable[i].dl_max - bw_kHz));
(long long unsigned int)(nr_bandtable[i].dl_max - bw_kHz/2));
int deltaFglobal = 60;
uint32_t N_REF_Offs = 2016667;
@@ -2005,7 +2005,7 @@ uint32_t to_nrarfcn(int nr_bandP,
// This is equation before Table 5.4.2.1-1 in 38101-1-f30
// F_REF=F_REF_Offs + deltaF_Global(N_REF-NREF_REF_Offs)
nrarfcn = (((dl_CarrierFreq_by_1k - F_REF_Offs_khz)/deltaFglobal)+N_REF_Offs);
get_delta_arfcn(i, nrarfcn, nr_bandtable[i].N_OFFs_DL);
//get_delta_arfcn(i, nrarfcn, nr_bandtable[i].N_OFFs_DL);
return nrarfcn;
}
+1
View File
@@ -512,6 +512,7 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP,
int nr_dl_slots = n;
int nr_ulstart_slot = 0;
if (tdd) {
nr_ulstart_slot = tdd->nrofDownlinkSlots + (tdd->nrofUplinkSymbols == 0);
nr_dl_slots = tdd->nrofDownlinkSlots + (tdd->nrofDownlinkSymbols != 0);
nr_ulstart_slot = tdd->nrofDownlinkSlots + (tdd->nrofUplinkSymbols == 0);
nr_slots_period /= get_nb_periods_per_frame(tdd->dl_UL_TransmissionPeriodicity);
+3 -2
View File
@@ -868,11 +868,12 @@ rrc_gNB_generate_dedicatedRRCReconfiguration(
DRB_config->pdcp_Config->drb->integrityProtection = NULL;
DRB_config->pdcp_Config->drb->statusReportRequired = NULL;
DRB_config->pdcp_Config->drb->outOfOrderDelivery = NULL;
DRB_config->pdcp_Config->drb->outOfOrderDelivery = calloc(1,sizeof(*DRB_config->pdcp_Config->drb->outOfOrderDelivery));
*DRB_config->pdcp_Config->drb->outOfOrderDelivery = NR_PDCP_Config__drb__outOfOrderDelivery_true;
DRB_config->pdcp_Config->moreThanOneRLC = NULL;
DRB_config->pdcp_Config->t_Reordering = calloc(1, sizeof(*DRB_config->pdcp_Config->t_Reordering));
*DRB_config->pdcp_Config->t_Reordering = NR_PDCP_Config__t_Reordering_ms0;
*DRB_config->pdcp_Config->t_Reordering = NR_PDCP_Config__t_Reordering_ms20;
DRB_config->pdcp_Config->ext1 = NULL;
if (rrc->security.do_drb_integrity) {
+7 -35
View File
@@ -16,16 +16,18 @@
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <net/if.h>
#include <netinet/ether.h>
#include <unistd.h>
#include <errno.h>
#include <linux/sysctl.h>
#include <sys/sysctl.h>
#include <pthread.h>
#include "common_lib.h"
#include "ethernet_lib.h"
#include "common/utils/system.h"
#include "ori.h"
#include "targets/ARCH/COMMON/common_lib.h"
@@ -250,7 +252,6 @@ int aw2s_startstreaming(openair0_device *device) {
}
ORI_Object_s *link= ORI_FindObject(ori, ORI_ObjectType_ORILink, 0, NULL);
if (tx0 == NULL ||
(tx1 == NULL && openair0_cfg->tx_num_channels > 1) ||
(tx2 == NULL && openair0_cfg->tx_num_channels > 2) ||
@@ -335,7 +336,7 @@ int aw2s_startstreaming(openair0_device *device) {
printf("\n\n\n========================================================\n");
/* Put Tx3 into service */
result = ORI_ObjectStateModification(ori, tx1, ORI_AST_Unlocked, &RE_result);
result = ORI_ObjectStateModification(ori, tx3, ORI_AST_Unlocked, &RE_result);
if(result != ORI_Result_SUCCESS)
{
printf("ORI_ObjectStateModify failed with error: %s\n", ORI_Result_Print(result));
@@ -402,7 +403,7 @@ int aw2s_startstreaming(openair0_device *device) {
if (rx3) {
printf("\n\n\n========================================================\n");
/* Put Rx1 into service */
/* Put Rx3 into service */
result = ORI_ObjectStateModification(ori, rx3, ORI_AST_Unlocked, &RE_result);
if(result != ORI_Result_SUCCESS)
{
@@ -412,37 +413,8 @@ int aw2s_startstreaming(openair0_device *device) {
}
printf("ORI_ObjectStateModify: %s\n", ORI_Result_Print(RE_result));
}
/*
while (rx0->fst != ORI_FST_Operational ||
(openair0_cfg->rx_num_channels > 1 && rx1->fst != ORI_FST_Operational) ||
tx0->fst != ORI_FST_Operational ||
(openair0_cfg->tx_num_channels > 1 && tx1->fst != ORI_FST_Operational))
{}*/
// test RX interface
uint64_t TS;
char temp_rx[2048] __attribute__((aligned(32)));
int aid,r0=0,r1=(openair0_cfg->rx_num_channels > 1) ? 0 : 1;
int r2=(openair0_cfg->rx_num_channels > 2) ? 0 : 1;
int r3=(openair0_cfg->rx_num_channels > 3) ? 0 : 1;
int i;
int Npackets=1024000;
for (i=0;i<Npackets;i++) {
device->trx_read_func2(device,
(openair0_timestamp*)&TS,
(void*)temp_rx,
256,
&aid);
if (aid == 0) r0=1;
if (aid == 1) r1=1;
if (aid == 2) r2=1;
if (aid == 3) r3=1;
}
if (r0==1 && r1==1 && r2==1 && r3==1) printf("Streaming started, returning to OAI\n");
else {
printf("Didn't get anything from one antenna port after %d packets %d,%d,%d,%d\n",Npackets,r0,r1,r2,r3);
return(-1);
}
device->fhstate.active=1;
return(0);
}
@@ -924,7 +896,7 @@ int aw2s_oriinit(openair0_device *device) {
int transport_init(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t * eth_params ) {
printf("Initializing AW2S (%p,%p,%p)\n",aw2s_oriinit,aw2s_oricleanup,aw2s_startstreaming);
device->thirdparty_init = aw2s_oriinit;
device->thirdparty_cleanup = aw2s_oricleanup;
device->thirdparty_startstreaming = aw2s_startstreaming;
+56 -5
View File
@@ -37,6 +37,7 @@
#include <sys/types.h>
#include <openair1/PHY/TOOLS/tools_defs.h>
#include "record_player.h"
#include <common/utils/threadPool/thread-pool.h>
/* default name of shared library implementing the radio front end */
#define OAI_RF_LIBNAME "oai_device"
@@ -153,6 +154,14 @@ typedef enum {
gpsdo=2
} clock_source_t;
/*! \brief Structure used for initializing UDP read threads */
typedef struct {
openair0_device *device;
int thread_id;
pthread_t pthread;
notifiedFIFO_t *resp;
} udp_ctx_t;
/*! \brief RF frontend parameters set by application */
typedef struct {
@@ -178,9 +187,11 @@ typedef struct {
int rx_num_channels;
//! number of TX channels (=TX antennas)
int tx_num_channels;
//! \brief RX base addresses for mmapped_dma
//! \brief RX base addresses for mmapped_dma or direct access
int32_t *rxbase[4];
//! \brief TX base addresses for mmapped_dma
//! \brief RX buffer size for direct access
int rxsize;
//! \brief TX base addresses for mmapped_dma or direct access
int32_t *txbase[4];
//! \brief Center frequency in Hz for RX.
//! index: [0..rx_num_channels[
@@ -246,6 +257,10 @@ typedef struct {
int nr_band;
//! NR scs for raster
int nr_scs_for_raster;
//! Core IDs for RX FH
int rxfh_cores[4];
//! Core IDs for TX FH
int txfh_cores[4];
} openair0_config_t;
/*! \brief RF mapping */
@@ -314,6 +329,19 @@ typedef struct {
bool write_thread_exit;
} openair0_thread_t;
typedef struct fhstate_s {
openair0_timestamp TS[8];
openair0_timestamp TS0;
openair0_timestamp olddeltaTS[8];
openair0_timestamp oldTS[8];
openair0_timestamp TS_read;
int first_read;
uint32_t *buff[8];
uint32_t buff_size;
int r[8];
int active;
} fhstate_t;
/*!\brief structure holds the parameters to configure USRP devices */
struct openair0_device_t {
/*!tx write thread*/
@@ -348,6 +376,24 @@ struct openair0_device_t {
/*!brief Can be used by driver to hold internal structure*/
void *priv;
/*!brief pointer to FH state, used in ECPRI split 8*/
fhstate_t fhstate;
/*!brief message response for notification fifo*/
notifiedFIFO_t *respudpTX;
/*!brief UDP TX thread context*/
udp_ctx_t **utx;
/*!brief Used in ECPRI split 8 to indicate numerator of sampling rate ratio*/
int sampling_rate_ratio_n;
/*!brief Used in ECPRI split 8 to indicate denominator of sampling rate ratio*/
int sampling_rate_ratio_d;
/*!brief Used in ECPRI split 8 to indicate the TX/RX timing offset*/
int txrx_offset;
/* Functions API, which are called by the application*/
/*! \brief Called to start the transceiver. Return 0 if OK, < 0 if error
@@ -394,7 +440,7 @@ struct openair0_device_t {
@param antenna_id index of the antenna if the device has multiple anteannas
@param flags flags must be set to true if timestamp parameter needs to be applied
*/
int (*trx_write_func2)(openair0_device *device, openair0_timestamp timestamp, void *buff, int nsamps,int antenna_id, int flags);
int (*trx_write_func2)(openair0_device *device, openair0_timestamp timestamp, void **buff, int fd_ind,int nsamps, int flags,int nant);
/*! \brief Receive samples from hardware.
* Read \ref nsamps samples from each channel to buffers. buff[0] is the array for
@@ -416,12 +462,13 @@ struct openair0_device_t {
* was received.
* \param device the hardware to use
* \param[out] ptimestamp the time at which the first sample was received.
* \param[out] buff A pointers to a buffer for received samples. The buffer must be large enough to hold the number of samples \ref nsamps.
* \param[out] buff A pointer to a buffer[ant_id][] for received samples. The buffer[ant_id] must be large enough to hold the number of samples \ref nsamps * the number of packets.
* \param nsamps Number of samples. One sample is 2 byte I + 2 byte Q => 4 byte.
* \param packet_idx offset into
* \param antenna_id Index of antenna from which samples were received
* \returns the number of sample read
*/
int (*trx_read_func2)(openair0_device *device, openair0_timestamp *ptimestamp, void *buff, int nsamps,int *antenna_id);
int (*trx_read_func2)(openair0_device *device, openair0_timestamp *ptimestamp, uint32_t **buff, int nsamps);
/*! \brief print the device statistics
* \param device the hardware to use
@@ -470,6 +517,7 @@ struct openair0_device_t {
/*! \brief Pointer to generic RRU private information
*/
void *thirdparty_priv;
/*! \brief Callback for Third-party RRU Initialization routine
@@ -496,6 +544,9 @@ struct openair0_device_t {
* \return a pointer to the parameter
*/
void *(*get_internal_parameter)(char *id);
/* \brief timing statistics for TX fronthaul (ethernet)
*/
time_stats_t tx_fhaul;
};
/* type of device init function, implemented in shared lib */
+18 -15
View File
@@ -80,10 +80,11 @@ int eth_socket_init_raw(openair0_device *device) {
perror("ETHERNET: Error opening RAW socket (control)");
exit(0);
}
if ((eth->sockfdd = socket(sock_dom, sock_type, sock_proto)) == -1) {
perror("ETHERNET: Error opening RAW socket (user)");
exit(0);
}
for (int i=0;i<eth->num_fd;i++)
if ((eth->sockfdd[i] = socket(sock_dom, sock_type, sock_proto)) == -1) {
perror("ETHERNET: Error opening RAW socket (user)");
exit(0);
}
/* initialize destination address */
bzero((void *)&(eth->local_addrc_ll), sizeof(struct sockaddr_ll));
@@ -94,8 +95,9 @@ int eth_socket_init_raw(openair0_device *device) {
strcpy(eth->if_index.ifr_name,eth->if_name);
if (ioctl(eth->sockfdc, SIOCGIFINDEX, &(eth->if_index)) < 0)
perror("SIOCGIFINDEX");
if (ioctl(eth->sockfdd, SIOCGIFINDEX, &(eth->if_index)) < 0)
perror("SIOCGIFINDEX");
for (int i=0;i<eth->num_fd;i++)
if (ioctl(eth->sockfdd[i], SIOCGIFINDEX, &(eth->if_index)) < 0)
perror("SIOCGIFINDEX");
eth->local_addrc_ll.sll_family = AF_PACKET;
eth->local_addrc_ll.sll_ifindex = eth->if_index.ifr_ifindex;
@@ -111,10 +113,11 @@ int eth_socket_init_raw(openair0_device *device) {
eth->local_addrd_ll.sll_pkttype = PACKET_OTHERHOST;
eth->addr_len = sizeof(struct sockaddr_ll);
if (bind(eth->sockfdd,(struct sockaddr *)&eth->local_addrd_ll,eth->addr_len)<0) {
perror("ETHERNET: Cannot bind to socket (user)");
exit(0);
}
for (int i=0;i<eth->num_fd;i++)
if (bind(eth->sockfdd[i],(struct sockaddr *)&eth->local_addrd_ll,eth->addr_len)<0) {
perror("ETHERNET: Cannot bind to socket (user)");
exit(0);
}
/* Construct the Ethernet header */
ether_aton_r(local_mac, (struct ether_addr *)(&(eth->ehd.ether_shost)));
@@ -165,7 +168,7 @@ int trx_eth_write_raw(openair0_device *device, openair0_timestamp timestamp, voi
/* Send packet */
bytes_sent += send(eth->sockfdd,
bytes_sent += send(eth->sockfdd[cc % eth->num_fd],
buff2,
pktsize,
sendto_flag);
@@ -214,7 +217,7 @@ int trx_eth_write_raw_IF4p5(openair0_device *device, openair0_timestamp timestam
memcpy(buff[0], (void*)&eth->ehd, MAC_HEADER_SIZE_BYTES);
bytes_sent = send(eth->sockfdd,
bytes_sent = send(eth->sockfdd[cc % eth->num_fd],
buff[0],
packet_size,
0);
@@ -266,7 +269,7 @@ int trx_eth_read_raw(openair0_device *device, openair0_timestamp *timestamp, voi
while(bytes_received < receive_bytes) {
again:
ret = recv(eth->sockfdd,
ret = recv(eth->sockfdd[cc % eth->num_fd],
buff2,
receive_bytes,
rcvfrom_flag);
@@ -345,7 +348,7 @@ int trx_eth_read_raw_IF4p5(openair0_device *device, openair0_timestamp *timestam
while (bytes_received < packet_size) {
again:
ret = recv(eth->sockfdd,
ret = recv(eth->sockfdd[cc % eth->num_fd],
buff[0],
packet_size,
MSG_PEEK);
@@ -397,7 +400,7 @@ int trx_eth_read_raw_IF4p5(openair0_device *device, openair0_timestamp *timestam
}
while(bytes_received < packet_size) {
ret = recv(eth->sockfdd,
ret = recv(eth->sockfdd[cc % eth->num_fd],
buff[0],
packet_size,
0);
+232 -202
View File
@@ -30,6 +30,9 @@
* \warning
*/
// _GNU_SOURCE needed to have sched_getcpu() from sched.h
#define _GNU_SOURCE
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <stdio.h>
@@ -37,14 +40,17 @@
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/filter.h>
#include <net/if.h>
#include <netinet/ether.h>
#include <unistd.h>
#include <errno.h>
#include "common/utils/LOG/vcd_signal_dumper.h"
#include <sched.h>
#include "common_lib.h"
#include "ethernet_lib.h"
#include "common/utils/threadPool/thread-pool.h"
//#define DEBUG 1
@@ -101,10 +107,11 @@ int eth_socket_init_udp(openair0_device *device) {
exit(0);
}
if ((eth->sockfdd = socket(sock_dom, sock_type, sock_proto)) == -1) {
perror("ETHERNET: Error opening socket (user)");
exit(0);
}
for (int i = 0;i<eth->num_fd;i++)
if ((eth->sockfdd[i] = socket(sock_dom, sock_type, sock_proto)) == -1) {
printf("ETHERNET: Error opening socket (user %d)",i);
exit(0);
}
/* initialize addresses */
bzero((void *)&(eth->dest_addrc), sizeof(eth->dest_addrc));
@@ -141,9 +148,31 @@ int eth_socket_init_udp(openair0_device *device) {
perror("ETHERNET: Cannot set SO_REUSEADDR option on socket (control)");
exit(0);
}
if (setsockopt(eth->sockfdd, SOL_SOCKET, SO_NO_CHECK, &enable, sizeof(int))) {
perror("ETHERNET: Cannot set SO_NO_CHECK option on socket (user)");
exit(0);
for (int i=0;i<eth->num_fd;i++) {
if (setsockopt(eth->sockfdd[i], SOL_SOCKET, SO_NO_CHECK, &enable, sizeof(int))) {
printf("ETHERNET: Cannot set SO_NO_CHECK option on socket (user %d)",i);
exit(0);
}
#if 0 /*def SO_ATTACH_REUSEPORT_EBPF*/
if (setsockopt(eth->sockfdd[i], SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int))) {
printf("ETHERNET: Cannot set SO_REUSEPORT option on socket (user %d)",i);
exit(0);
}
struct sock_filter code[]={
{ BPF_LD | BPF_W | BPF_ABS, 0, 0, SKF_AD_OFF + SKF_AD_CPU }, // A = #cpu
{ BPF_RET | BPF_A, 0, 0, 0 }, // return A
};
struct sock_fprog bpf = {
.len = sizeof(code)/sizeof(struct sock_filter),
.filter = code,
};
if (i==0 && setsockopt(eth->sockfdd[i], SOL_SOCKET, SO_ATTACH_REUSEPORT_CBPF, &bpf, sizeof(bpf))) {
printf("ETHERNET: Cannot set SO_ATTACH_REUSEPORT_EBPF option on socket (user %d)",i);
exit(0);
}
else printf("ETHERNET: set SO_ATTACH_REUSEPORT_EBPF option on socket (user %d)\n",i);
#endif
}
/* want to receive -> so bind */
@@ -153,12 +182,13 @@ int eth_socket_init_udp(openair0_device *device) {
} else {
printf("[%s] binding to %s:%d (control)\n",str[hostind],str_local,ntohs(eth->local_addrc.sin_port));
}
if (bind(eth->sockfdd,(struct sockaddr *)&eth->local_addrd,eth->addr_len)<0) {
perror("ETHERNET: Cannot bind to socket (user)");
exit(0);
} else {
printf("[%s] binding to %s:%d (user)\n",str[hostind],str_local,ntohs(eth->local_addrd.sin_port));
}
for (int i=0;i<eth->num_fd;i++)
if (bind(eth->sockfdd[i],(struct sockaddr *)&eth->local_addrd,eth->addr_len)<0) {
printf("ETHERNET: Cannot bind to socket (user %d)",i);
exit(0);
} else {
printf("[%s] binding to %s:%d (user %d)\n",str[hostind],str_local,ntohs(eth->local_addrd.sin_port),i);
}
return 0;
}
@@ -180,7 +210,7 @@ int trx_eth_read_udp_IF4p5(openair0_device *device, openair0_timestamp *timestam
while(bytes_received == -1) {
again:
bytes_received = recvfrom(eth->sockfdd,
bytes_received = recvfrom(eth->sockfdd[0/*cc%eth->num_fd*/],
buff[0],
packet_size,
0,
@@ -211,7 +241,6 @@ int trx_eth_read_udp_IF4p5(openair0_device *device, openair0_timestamp *timestam
eth->rx_count++;
}
}
eth->rx_nsamps = nsamps;
return(bytes_received);
}
@@ -246,7 +275,7 @@ int trx_eth_write_udp_IF4p5(openair0_device *device, openair0_timestamp timestam
eth->tx_nsamps = nblocks;
bytes_sent = sendto(eth->sockfdd,
bytes_sent = sendto(eth->sockfdd[0/*cc%eth->num_fd*/],
buff[0],
packet_size,
0,
@@ -264,233 +293,234 @@ int trx_eth_write_udp_IF4p5(openair0_device *device, openair0_timestamp timestam
return (bytes_sent);
}
int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, void *buff, int nsamps,int cc, int flags) {
void *trx_eth_write_udp_cmd(udpTXelem_t *udpTXelem) {
openair0_device *device=udpTXelem->device;
openair0_timestamp timestamp = udpTXelem->timestamp;
void **buff = udpTXelem->buff;
int nsamps = udpTXelem->nsamps;
int nant = udpTXelem->nant;
int bytes_sent=0;
eth_state_t *eth = (eth_state_t*)device->priv;
int sendto_flag =0;
fhstate_t *fhstate = &device->fhstate;
//sendto_flag|=flags;
eth->tx_nsamps=nsamps;
uint64_t last_rxTS = fhstate->TS[0]-fhstate->TS0;
uint64_t TS_advance=0;
if (timestamp > last_rxTS) TS_advance = timestamp - last_rxTS;
int nsamps2; // aligned to upper 32 or 16 byte boundary
if (TS_advance < (nsamps/2)) LOG_W(PHY,"Starting TX FH for TS %llu absslot %llu(%llu) last_rxTS %llu TS_advance %llu samples\n",(unsigned long long)timestamp,(unsigned long long)timestamp/nsamps,((unsigned long long)timestamp/nsamps)%20,(unsigned long long)last_rxTS,(unsigned long long)TS_advance);
void *buff2;
#if defined(__x86_64) || defined(__i386__)
#ifdef __AVX2__
nsamps2 = (nsamps+7)>>3;
int nsamps2 = 256>>3;
__m256i buff_tx[nsamps2+1];
__m256i *buff_tx2=buff_tx+1;
buff2=(void*)&buff_tx[1] - APP_HEADER_SIZE_BYTES;
#else
nsamps2 = (nsamps+3)>>2;
int nsamps2 = 256>>2;
__m128i buff_tx[nsamps2+2];
__m128i *buff_tx2=buff_tx+2;
buff2=(void*)&buff_tx[2] - APP_HEADER_SIZE_BYTES;
#endif
#elif defined(__arm__) || defined(__aarch64__)
nsamps2 = (nsamps+3)>>2;
int nsamps2 = 256>>2;
int16x8_t buff_tx[nsamps2+2];
int16x8_t *buff_tx2=buff_tx+2;
buff2=(void*)&buff_tx[2] - APP_HEADER_SIZE_BYTES;
#else
#error Unsupported CPU architecture, ethernet device cannot be built
#endif
// bring TX data into 12 LSBs for softmodem RX
for (int j=0; j<nsamps2; j++) {
/* construct application header */
// ECPRI Protocol revision + reserved bits (1 byte)
*(uint8_t *)buff2 = ECPRIREV;
// ECPRI Message type (1 byte)
*(uint8_t *)(buff2 + 1) = 64;
openair0_timestamp TS = timestamp + fhstate->TS0;
TS = (6*device->sampling_rate_ratio_d*TS)/device->sampling_rate_ratio_n;
TS -= device->txrx_offset;
int TSinc = (6*256*device->sampling_rate_ratio_d)/device->sampling_rate_ratio_n;
int len=256;
LOG_D(PHY,"TS %llu (%llu),txrx_offset %d,d %d, n %d, buff[0] %p buff[1] %p\n",
(unsigned long long)TS,(unsigned long long)timestamp,device->txrx_offset,device->sampling_rate_ratio_d,device->sampling_rate_ratio_n,
buff[0],buff[1]);
for (int offset=0;offset<nsamps;offset+=256,TS+=TSinc) {
// OAI modified SEQ_ID (4 bytes)
*(uint64_t *)(buff2 + 6) = TS;
if ((offset + 256) <= nsamps) len=1024;
else len = (nsamps-offset)<<2;
// ECPRI Payload Size (2 bytes)
*(uint8_t *)(buff2 + 2) = len>>8;
*(uint8_t *)(buff2 + 3) = len&0xff;
for (int aid = 0; aid<nant; aid++) {
LOG_D(PHY,"TS %llu (TS0 %llu) aa %d : offset %d, len %d\n",(unsigned long long)TS,(unsigned long long)fhstate->TS0,aid,offset,len);
// ECPRI PC_ID (2 bytes)
*(uint16_t *)(buff2 + 4) = aid;
// bring TX data into 12 MSBs
#if defined(__x86_64__) || defined(__i386__)
#ifdef __AVX2__
buff_tx2[j] = _mm256_slli_epi16(((__m256i *)buff)[j],4);
__m256i *buff256 = (__m256i *)&(((int32_t*)buff[aid])[offset]);
for (int j=0; j<32; j+=8) {
buff_tx[1+j] = _mm256_slli_epi16(buff256[j],4);
buff_tx[2+j] = _mm256_slli_epi16(buff256[j+1],4);
buff_tx[3+j] = _mm256_slli_epi16(buff256[j+2],4);
buff_tx[4+j] = _mm256_slli_epi16(buff256[j+3],4);
buff_tx[5+j] = _mm256_slli_epi16(buff256[j+4],4);
buff_tx[6+j] = _mm256_slli_epi16(buff256[j+5],4);
buff_tx[7+j] = _mm256_slli_epi16(buff256[j+6],4);
buff_tx[8+j] = _mm256_slli_epi16(buff256[j+7],4);
}
#else
buff_tx2[j] = _mm_slli_epi16(((__m128i *)buff)[j],4);
__m128i *buff128 = (__m128i *)&buff[aid][offset];
for (int j=0; j<64; j++) buff_tx[2+j] = _mm_slli_epi16(buff128[j],4);
#endif
#elif defined(__arm__)
buff_tx2[j] = vshlq_n_s16(((int16x8_t *)buff)[j],4);
int16x8_t *buff128 = (__int16x8_t*)&buff[aid][offset];
for (int j=0; j<64; j++) buff_tx[2+j] = vshlq_n_s16(((int16x8_t *)buff128)[j],4);
#endif
}
/* buff[i] points to the position in tx buffer where the payload to be sent is
buff2 points to the position in tx buffer where the packet header will be placed */
void *buff2 = ((void*)buff_tx2)- APP_HEADER_SIZE_BYTES;
bytes_sent = 0;
/* constract application header */
// ECPRI Protocol revision + reserved bits (1 byte)
*(uint8_t *)buff2 = ECPRIREV;
// ECPRI Message type (1 byte)
*(uint8_t *)(buff2 + 1) = 64;
// ECPRI Payload Size (2 bytes)
AssertFatal(nsamps<16381,"nsamps > 16381\n");
*(uint8_t *)(buff2 + 2) = (nsamps<<2)>>8;
*(uint8_t *)(buff2 + 3) = (nsamps<<2)&0xff;
// ECPRI PC_ID (2 bytes)
*(uint16_t *)(buff2 + 4) = cc;
// OAI modified SEQ_ID (4 bytes)
*(uint64_t *)(buff2 + 6) = ((uint64_t )timestamp)*6;
/*
printf("ECPRI TX (REV %x, MessType %d, Payload size %d, PC_ID %d, TS %llu\n",
*(uint8_t *)buff2,
*(uint8_t *)(buff2+1),
*(uint16_t *)(buff2+2),
*(uint16_t *)(buff2+4),
*(uint64_t *)(buff2+6));
*/
int sent_byte;
if (eth->compression == ALAW_COMPRESS) {
sent_byte = UDP_PACKET_SIZE_BYTES_ALAW(nsamps);
} else {
sent_byte = UDP_PACKET_SIZE_BYTES(nsamps);
}
//while(bytes_sent < sent_byte) {
//printf("eth->pck_seq_num: %d\n", eth->pck_seq_num);
#if DEBUG
printf("------- TX ------: buff2 current position=%d remaining_bytes=%d bytes_sent=%d \n",
(void *)(buff2+bytes_sent),
sent_byte - bytes_sent,
bytes_sent);
#endif
/* Send packet */
bytes_sent = sendto(eth->sockfdd,
buff2,
sent_byte,
sendto_flag,
(struct sockaddr*)&eth->dest_addrd,
eth->addr_len);
/* Send packet */
bytes_sent = sendto(eth->sockfdd[0],
buff2,
UDP_PACKET_SIZE_BYTES(len>>2),
sendto_flag,
(struct sockaddr*)&eth->dest_addrd,
eth->addr_len);
if ( bytes_sent == -1) {
eth->num_tx_errors++;
eth->num_tx_errors++;
perror("ETHERNET WRITE: ");
exit(-1);
} else {
#if DEBUG
printf("------- TX ------: nu=%d an_id=%d ts%d bytes_send=%d\n",
*(int16_t *)buff2,
*(int16_t *)(buff2 + sizeof(int16_t)),
*(openair0_timestamp *)(buff2 + sizeof(int32_t)),
bytes_sent);
dump_packet((device->host_type == RAU_HOST)? "RAU":"RAU", buff2, UDP_PACKET_SIZE_BYTES(nsamps), TX_FLAG);
#endif
eth->tx_actual_nsamps=bytes_sent>>2;
eth->tx_count++;
eth->pck_seq_num++;
if ( eth->pck_seq_num > MAX_PACKET_SEQ_NUM(nsamps,device->openair0_cfg->samples_per_frame) ) eth->pck_seq_num = 1;
eth->tx_actual_nsamps=bytes_sent>>2;
eth->tx_count++;
}
//}
return (bytes_sent-APP_HEADER_SIZE_BYTES)>>2;
} // aid
} // offset
free(buff);
return(NULL);
}
#define NOSHIFT 1
int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, void **buff, int fd_ind, int nsamps, int flags, int nant) {
int trx_eth_read_udp(openair0_device *device, openair0_timestamp *timestamp, void *buff, int nsamps, int *cc) {
int bytes_received=0;
eth_state_t *eth = (eth_state_t*)device->priv;
// openair0_timestamp prev_timestamp = -1;
int rcvfrom_flag =0;
int block_cnt=0;
int again_cnt=0;
static int packet_cnt=0;
int payload_size = UDP_PACKET_SIZE_BYTES(nsamps);
union udpTXReqUnion id = {.s={(uint64_t)timestamp,nsamps,0}};
notifiedFIFO_elt_t *req=newNotifiedFIFO_elt(sizeof(udpTXelem_t), id.p, device->utx[fd_ind]->resp,NULL);
udpTXelem_t * udptxelem=(udpTXelem_t *) NotifiedFifoData(req);
udptxelem->device = device;
udptxelem->timestamp = timestamp;
udptxelem->buff = calloc(nant,sizeof(void*));
memcpy(udptxelem->buff,buff,nant*sizeof(void*));
udptxelem->fd_ind = fd_ind;
udptxelem->nsamps = nsamps;
udptxelem->flags = flags;
udptxelem->nant = nant;
pushNotifiedFIFO(device->utx[fd_ind]->resp, req);
LOG_D(PHY,"Pushed to TX FH FIFO, TS %llu, nsamps %d, nant %d buffs[0] %p buffs[1] %p\n",
(unsigned long long)timestamp,nsamps,nant,udptxelem->buff[0],udptxelem->buff[1]);
return(0);
}
extern int oai_exit;
#if defined(__x86_64__) || defined(__i386__)
#ifdef __AVX2__
int nsamps2 = (payload_size>>5)+1;
__m256i temp_rx[nsamps2];
char *temp_rx0 = ((char *)&temp_rx[1])-APP_HEADER_SIZE_BYTES;
#else
int nsamps2 = (payload_size>>4)+1;
__m128i temp_rx[nsamps2];
char *temp_rx0 = ((char *)&temp_rx[1])-APP_HEADER_SIZE_BYTES;
#endif
#elif defined(__arm__) || defined(__aarch64__)
int nsamps2 = (payload_size>>4)+1;
int16x8_t temp_rx[nsamps2];
char *temp_rx0 = ((char *)&temp_rx[1])-APP_HEADER_SIZE_BYTES;
#else
#error Unsupported CPU architecture device cannot be built
int nsamps2 = (payload_size>>2)+1;
int32_t temp_rx[payload_size>>2];
char* *temp_rx0 = ((char *)&temp_rx[1]) - APP_HEADER_SIZE_BYTES;
#endif
eth->rx_nsamps=nsamps;
void *udp_write_thread(void *arg) {
bytes_received=0;
block_cnt=0;
AssertFatal(eth->compression == NO_COMPRESS, "IF5 compression not supported for now\n");
while(bytes_received < payload_size) {
again:
bytes_received +=recvfrom(eth->sockfdd,
temp_rx0,
payload_size,
rcvfrom_flag,
(struct sockaddr *)&eth->dest_addrd,
(socklen_t *)&eth->addr_len);
packet_cnt++;
if (bytes_received ==-1) {
eth->num_rx_errors++;
if (errno == EAGAIN) {
again_cnt++;
usleep(10);
if (again_cnt == 1000) {
perror("ETHERNET READ: ");
exit(-1);
} else {
bytes_received=0;
goto again;
}
} else if (errno == EWOULDBLOCK) {
block_cnt++;
usleep(10);
if (block_cnt == 1000) {
perror("ETHERNET READ: ");
exit(-1);
} else {
printf("BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK BLOCK \n");
goto again;
}
}
} else {
udp_ctx_t *utx = (udp_ctx_t *)arg;
utx->resp = (notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_elt_t));
initNotifiedFIFO(utx->resp);
LOG_D(PHY,"UDP write thread started on core %d\n",sched_getcpu());
reset_meas(&utx->device->tx_fhaul);
while (oai_exit == 0) {
notifiedFIFO_elt_t *res = pullNotifiedFIFO(utx->resp);
udpTXelem_t *udptxelem = (udpTXelem_t *)NotifiedFifoData(res);
LOG_D(PHY,"Pulled from TX FH FIFO, TS %llu, nsamps %d, nant %d\n",(unsigned long long)udptxelem->timestamp,udptxelem->nsamps,udptxelem->nant);
start_meas(&utx->device->tx_fhaul);
trx_eth_write_udp_cmd(udptxelem);
stop_meas(&utx->device->tx_fhaul);
// send data to RU
delNotifiedFIFO_elt(res);
}
free(utx->resp);
return(NULL);
}
void *udp_read_thread(void *arg) {
openair0_timestamp TS;
int aid;
udp_ctx_t *u = (udp_ctx_t *)arg;
openair0_device *device=u->device;
fhstate_t *fhstate = &device->fhstate;
char buffer[UDP_PACKET_SIZE_BYTES(256)];
int first_read=0;
while (oai_exit == 0) {
LOG_I(PHY,"UDP read thread %d, waiting for start sampling_rate_d %d, sampling_rate_n %d\n",u->thread_id,device->sampling_rate_ratio_n,device->sampling_rate_ratio_d);
while (fhstate->active > 0) {
size_t count = recvfrom(((eth_state_t*)device->priv)->sockfdd[0],
buffer,sizeof(buffer),0,
(struct sockaddr *)&((eth_state_t*)device->priv)->dest_addrd,
(socklen_t *)&((eth_state_t*)device->priv)->addr_len);
aid = *(uint16_t*)(&buffer[ECPRICOMMON_BYTES]);
TS = *(openair0_timestamp *)(&buffer[ECPRICOMMON_BYTES+ECPRIPCID_BYTES]);
// convert TS to samples, /6 for AW2S @ 30.72 Ms/s, this is converted for other sample rates in OAI application
TS = (device->sampling_rate_ratio_n*TS)/(device->sampling_rate_ratio_d*6);
if ((int)count <= 0) continue;
AssertFatal(aid < 8,"Cannot handle more than 8 antennas, got aid %d\n",aid);
fhstate->r[aid]=1;
if (aid==0 && first_read == 0) fhstate->TS0 = TS;
first_read = 1;
/* store the timestamp value from packet's header */
*timestamp = *(openair0_timestamp *)(temp_rx0 + ECPRICOMMON_BYTES+ECPRIPCID_BYTES);
// convert TS to samples, /3 for 30.72 Ms/s, /6 for 15.36 Ms/s, /12 for 7.68 Ms/s, etc.
*timestamp = *timestamp/6;
// handle 1.4,3,5,10,15 MHz cases
*cc = *(uint16_t*)(temp_rx0 + ECPRICOMMON_BYTES);
}
eth->rx_actual_nsamps=payload_size>>2;
eth->rx_count++;
}
fhstate->TS[aid] = TS;
int64_t offset = TS - fhstate->TS0;
if (offset > 0) offset = offset % device->openair0_cfg->rxsize;
else offset = TS % device->openair0_cfg->rxsize + ((((uint64_t)1)<<63)-(fhstate->TS0-1)) % device->openair0_cfg->rxsize;
// need to do memcpy since there is no guarantee that aid is the same each time, otherwise we could have used
// zero-copy and corrected the header component.
#ifdef NOSHIFT
memcpy(buff,(void*)(temp_rx+1),payload_size);
#else
// populate receive buffer in lower 12-bits from 16-bit representation
for (int j=1; j<nsamps2; j++) {
#if defined(__x86_64__) || defined(__i386__)
#ifdef __AVX2__
((__m256i *)buff)[j-1] = _mm256_srai_epi16(temp_rx[j],2);
#else
((__m128i *)buff)[j-1] = _mm_srai_epi16(temp_rx[j],2);
#endif
#elif defined(__arm__)
((int16x8_t *)buff)[j] = vshrq_n_s16(temp_rx[i][j],2);
#endif
memcpy((void*)(device->openair0_cfg->rxbase[aid]+offset),
(void*)&buffer[APP_HEADER_SIZE_BYTES],
count-APP_HEADER_SIZE_BYTES);
LOG_D(PHY,"UDP read thread_id %d (%d), aid %d, TS %llu, TS0 %llu, offset %ld\n",(int)u->thread_id,(int)sched_getcpu(),aid,(unsigned long long)TS,(unsigned long long)fhstate->TS0,offset);
}
sleep(1);
}
#endif
return(0);
}
int trx_eth_read_udp(openair0_device *device, openair0_timestamp *timestamp, uint32_t **buff, int nsamps) {
return (payload_size>>2);
fhstate_t *fhstate = &device->fhstate;
openair0_timestamp prev_read_TS= fhstate->TS_read, min_TS;
// block until FH is ready
while (fhstate->r[0] == 0 || fhstate->r[1] == 0 || fhstate->r[2] == 0 || fhstate->r[3] == 0 ||
fhstate->r[4] == 0 || fhstate->r[5] == 0 || fhstate->r[6] == 0 || fhstate->r[7] == 0) usleep(100);
// get minimum TS over all antennas
min_TS = fhstate->TS[0];
for (int i=1;i<device->openair0_cfg->rx_num_channels;i++) min_TS = min(min_TS,fhstate->TS[i]);
// poll/sleep until we accumulated enough samples on each antenna port
int count=0;
while (fhstate->first_read == 1 && min_TS < (fhstate->TS0+prev_read_TS + nsamps)) {
usleep(50);
min_TS = fhstate->TS[0];
for (int i=1;i<device->openair0_cfg->rx_num_channels;i++) min_TS = min(min_TS,fhstate->TS[i]);
count++;
}
if (fhstate->first_read == 0) {
*timestamp = 0;
fhstate->TS_read = *timestamp+nsamps;
LOG_D(PHY,"first read : TS_read %llu, TS %llu state (%d,%d,%d,%d,%d,%d,%d,%d)\n",(unsigned long long)fhstate->TS_read,(unsigned long long)*timestamp,
fhstate->r[0],fhstate->r[1],fhstate->r[2],fhstate->r[3],fhstate->r[4],fhstate->r[5],fhstate->r[6],fhstate->r[7]);
}
else {
*timestamp = fhstate->TS_read;
fhstate->TS_read = prev_read_TS + nsamps;
LOG_D(PHY,"TS_read %llu (%llu, %llu), min_TS %llu, prev_read_TS %llu, nsamps %d, fhstate->TS0+prev_TS+nsamps %llu, wait count %d x 100us\n",(unsigned long long)fhstate->TS_read,(unsigned long long)*timestamp/nsamps,((unsigned long long)*timestamp/nsamps)%20,(unsigned long long)min_TS,(unsigned long long)prev_read_TS,nsamps,(unsigned long long)(fhstate->TS0+prev_read_TS+nsamps),count);
}
fhstate->first_read = 1;
return (nsamps);
}
@@ -0,0 +1,51 @@
# Ethernet drivers
This directory contains ethernet-based drivers for fronthaul. The only functional versions today are ECPRI time-domain (split 8) over UDP for AW2S and IF4.5 (split 7) for OAI RU over UDP. The RAW ethernet implementation is currently not tested and quite possibly obsolete.
## license
Author:
Raymond Knopp, EURECOM
OAI License V1.1
# Top-level
The files implement the OAI IF device interface which provides the transmit/receive (trx) functions for generic ethernet-based devices. Some minimal control-plane socket handling for IF4p5 is also provided. It comprises the following top-level functions (ethernet_lib.c) which are mapped to the OAI device structure:
* trx_eth_start : create sockets and threads to handle I/O
* trx_eth_end : close sockets
* trx_eth_stop : stops 3rd party (AW2S) device
* trx_eth_set_freq : empty
* trx_eth_set_gains : empty
* trx_eth_get_stats : empty
* trx_eth_reset_stats : empty
* trx_eth_write_init : empty
* ethernet_tune : write certain performance-related parameters to ethernet device
* transport_init : entry routine to fill device data structure with function pointers
# IF4p5 U-plane implementation
It is contained in the eth_udp.c and eth_raw.c files. The two basic routines are
* trx_eth_read_udp_IF4p5() : implements a blocking read for three particular IF4p5 packets, IF4p5_PULFFT (for OAI RCC/DU), IF4p5_PRACH and IF4p5_PDLFFT (for OAI RU). The packets are parsed and mapped to the appropriate physical channels by the OAI physical layer
* trx_eth_write_udp_IF4p5 : implements a write for the three IF4p5 packets.
* trx_eth_ctlsend_udp : implements the sending component for the control socket
* trx_eth_ctlrecv_udp : implements the receive component for the control socket (blocking read)
# ECPRI U-plane implementation
It is contained in the eth_udp.c file and only implements ECPRI/UDP. The implementation has 2 top-level functions:
* trx_eth_write_udp : This sends a stream of packets containing 16-bit I/ 16-bit Q samples to the ECPRI RU. It uses the proprietary AW2S format (user-defined). Each packet carries 256 samples and some header information (timestamp, antenna index) and fits inslightly more than 1024 bytes. Each packet with Ethernet, IP and UDP headers fits into a regular Ethernet frame. The transmit function does not block and pushes the data to a worker thread (udp_write_thread) which runs in the background. The worker thread scales the IQ samples to fit in 16-bit units and forms the ECPRI packets for each antenna. The signals are split into 256-sample chunks and antennas are handled in sequence for each chunk. This ensures that all antennas receive their signals more or less at the same time.
* trx_eth_read_udp : This is a blocking read which waits for a worker thread (udp_read_thread) listening on the U-plane socket to have acquired enough samples satisfying the request (nsamps). The requests are usually a slot (NR) or subframe (LTE) worth of samples. The worker thread identifies the antenna index (aid) and timestamp of each packet and copies the received chunk into the destination memory location according to the timestamp modulo the length of the receive buffer. The memory location for read is identifited during initialization of the interface and is written circularly. Typically the buffer would contain a frame's worth of samples, but this is not a requirement. There is only one memcpy in the driver and the end OAI application can use the data in its normal local buffer (RU.common.rxdata[aid]). The memcpy is needed since the destination address depends on the antenna index which is carried in the received packet itself. Kernel filtering and redirection (C/EBPF,XDP) doesn't seem to be possible with the AW2S packet format.
The two threads should be pinned to isolated CPUs to maximize performance. Their CPU id's can be passed to the driver from the OAI application. tx_fh_core and rx_fh_core in the RU section of the OAI .conf file.
# Obsolete code
Non ECPRI split 8 and IF4p5 with RAW sockets is not functional anymore (eth_raw.c). split-8 will be resusitated if an RU implementing ECPRI is integrated with OAI. IF4p5 with raw sockets is replaced with the FHI Split 7.2 interface.
@@ -64,8 +64,78 @@ int trx_eth_start(openair0_device *device)
AssertFatal(device->thirdparty_init != NULL, "device->thirdparty_init is null\n");
AssertFatal(device->thirdparty_init(device) == 0, "third-party init failed\n");
device->openair0_cfg->samples_per_packet = 256;
}
/* initialize socket */
eth->num_fd = 1; //max(device->openair0_cfg->rx_num_channels,device->openair0_cfg->tx_num_channels);
udp_ctx_t *u[1+eth->num_fd];
device->utx = (udp_ctx_t**)malloc(sizeof(device->utx));
for (int i=0;i<eth->num_fd;i++) {
u[i] = malloc(sizeof(udp_ctx_t));
u[i]->thread_id=i;
u[i]->device = device;
printf("UDP Read Thread %d on core %d\n",i,device->openair0_cfg->rxfh_cores[i]);
threadCreate(&u[i]->pthread,udp_read_thread,u[i],"udp read thread",device->openair0_cfg->rxfh_cores[i],OAI_PRIORITY_RT_MAX);
device->utx[i] = malloc(sizeof(udp_ctx_t));
device->utx[i]->thread_id=i;
device->utx[i]->device = device;
printf("UDP Write Thread %d on core %d\n",i,device->openair0_cfg->txfh_cores[i]);
threadCreate(&device->utx[i]->pthread,udp_write_thread,device->utx[i],"udp write thread",device->openair0_cfg->txfh_cores[i],OAI_PRIORITY_RT_MAX);
}
device->sampling_rate_ratio_n=1;
device->sampling_rate_ratio_d=1;
if (device->openair0_cfg->nr_flag==1) { // This check if RRU knows about NR numerologies
if (device->openair0_cfg->num_rb_dl <= 162 && device->openair0_cfg->num_rb_dl > 106) {
device->sampling_rate_ratio_n = 2;
device->txrx_offset=5500;
}
else if (device->openair0_cfg->num_rb_dl <= 106 && device->openair0_cfg->num_rb_dl > 51) {
device->sampling_rate_ratio_d=3;
device->sampling_rate_ratio_n=4;
device->txrx_offset=3750;
}
else if (device->openair0_cfg->num_rb_dl == 51) {
device->sampling_rate_ratio_n=1;
device->sampling_rate_ratio_d=1;
device->txrx_offset=7500;
}
else AssertFatal(1==0,"num_rb_dl %d not ok with ECPRI\n",device->openair0_cfg->num_rb_dl);
}
else {
if (device->openair0_cfg->num_rb_dl == 100 || device->openair0_cfg->num_rb_dl == 51) {
device->sampling_rate_ratio_d = 1;
device->txrx_offset=7500;
}
else if (device->openair0_cfg->num_rb_dl == 75) {
device->sampling_rate_ratio_d = 4;
device->sampling_rate_ratio_n=3;
device->txrx_offset=7500;
}
else if (device->openair0_cfg->num_rb_dl == 50) {
device->sampling_rate_ratio_d = 2;
device->txrx_offset=7500;
}
else if (device->openair0_cfg->num_rb_dl == 25) {
device->sampling_rate_ratio_d = 4;
device->txrx_offset=7500;
}
else AssertFatal(1==0,"num_rb_dl %d not ok with ECPRI\n",device->openair0_cfg->num_rb_dl);
}
#ifdef USE_TX_TPOOL
int threadCnt = device->openair0_cfg->tx_num_channels;
if (threadCnt < 2) LOG_E(PHY,"Number of threads for gNB should be more than 1. Allocated only %d\n",threadCnt);
char pool[80];
sprintf(pool,"-1");
int s_offset = 0;
for (int icpu=1; icpu<threadCnt; icpu++) {
sprintf(pool+2+s_offset,",-1");
s_offset += 3;
}
device->threadPool = (tpool_t*)malloc(sizeof(tpool_t));
initTpool(pool, device->threadPool, cpumeas(CPUMEAS_GETSTATE));
// ULSCH decoder result FIFO
device->respudpTX = (notifiedFIFO_elt_t*) malloc(sizeof(notifiedFIFO_elt_t));
initNotifiedFIFO(device->respudpTX);
#endif
}
/* initialize socket */
if (eth->flags == ETH_RAW_MODE) {
printf("Setting ETHERNET to ETH_RAW_IF5_MODE\n");
if (eth_socket_init_raw(device)!=0) return -1;
@@ -145,10 +215,11 @@ int trx_eth_start(openair0_device *device)
if(ethernet_tune (device,RCV_TIMEOUT,999999)!=0) return -1;
}
/* apply additional configuration */
if(ethernet_tune (device, SND_BUF_SIZE,2000000000)!=0) return -1;
if(ethernet_tune (device, RCV_BUF_SIZE,2000000000)!=0) return -1;
if(ethernet_tune (device, KERNEL_SND_BUF_MAX_SIZE, 200000000)!=0) return -1;
if(ethernet_tune (device, KERNEL_RCV_BUF_MAX_SIZE, 200000000)!=0) return -1;
if(ethernet_tune (device, SND_BUF_SIZE,67108864)!=0) return -1;
if(ethernet_tune (device, RCV_BUF_SIZE,67108864)!=0) return -1;
if(ethernet_tune (device, KERNEL_SND_BUF_MAX_SIZE, 67108864)!=0) return -1;
if(ethernet_tune (device, KERNEL_RCV_BUF_MAX_SIZE, 67108864)!=0) return -1;
if(ethernet_tune (device, TX_Q_LEN, 10000)!=0) return -1;
return 0;
@@ -159,12 +230,13 @@ void trx_eth_end(openair0_device *device)
{
eth_state_t *eth = (eth_state_t*)device->priv;
/* destroys socket only for the processes that call the eth_end fuction-- shutdown() for beaking the pipe */
if ( close(eth->sockfdd) <0 ) {
perror("ETHERNET: Failed to close socket");
exit(0);
} else {
printf("[%s] socket has been successfully closed.\n",(device->host_type == RAU_HOST)? "RAU":"RRU");
}
for (int i=0;i<eth->num_fd;i++)
if ( close(eth->sockfdd[i]) <0 ) {
perror("ETHERNET: Failed to close socket");
exit(0);
} else {
printf("[%s] socket has been successfully closed.\n",(device->host_type == RAU_HOST)? "RAU":"RRU");
}
}
@@ -224,7 +296,8 @@ int ethernet_tune(openair0_device *device,
/****************** socket level options ************************/
switch(option) {
case SND_BUF_SIZE: /* transmit socket buffer size */
if (setsockopt(eth->sockfdd,
for (int i=0;i<eth->num_fd;i++)
if (setsockopt(eth->sockfdd[i],
SOL_SOCKET,
SO_SNDBUF,
&value,sizeof(value))) {
@@ -232,10 +305,11 @@ int ethernet_tune(openair0_device *device,
} else {
printf("send buffer size= %d bytes\n",value);
}
break;
break;
case RCV_BUF_SIZE: /* receive socket buffer size */
if (setsockopt(eth->sockfdd,
for (int i=0;i<eth->num_fd;i++) {
if (setsockopt(eth->sockfdd[i],
SOL_SOCKET,
SO_RCVBUF,
&value,sizeof(value))) {
@@ -243,26 +317,29 @@ int ethernet_tune(openair0_device *device,
} else {
printf("receive bufffer size= %d bytes\n",value);
}
break;
}
break;
case RCV_TIMEOUT:
timeout.tv_sec = value/1000000;
timeout.tv_usec = value%1000000;//less than rt_period?
if (setsockopt(eth->sockfdc,
SOL_SOCKET,
SO_RCVTIMEO,
(char *)&timeout,sizeof(timeout))) {
perror("[ETHERNET] setsockopt()");
SOL_SOCKET,
SO_RCVTIMEO,
(char *)&timeout,sizeof(timeout))) {
perror("[ETHERNET] setsockopt()");
} else {
printf( "receive timeout= %u usec\n",(unsigned int)timeout.tv_usec);
printf( "receive timeout= %u usec\n",(unsigned int)timeout.tv_usec);
}
if (setsockopt(eth->sockfdd,
SOL_SOCKET,
SO_RCVTIMEO,
(char *)&timeout,sizeof(timeout))) {
perror("[ETHERNET] setsockopt()");
} else {
printf( "receive timeout= %u usec\n",(unsigned int)timeout.tv_usec);
for (int i=0;i<eth->num_fd;i++) {
if (setsockopt(eth->sockfdd[i],
SOL_SOCKET,
SO_RCVTIMEO,
(char *)&timeout,sizeof(timeout))) {
perror("[ETHERNET] setsockopt()");
} else {
printf( "receive timeout= %u usec\n",(unsigned int)timeout.tv_usec);
}
}
break;
@@ -277,13 +354,15 @@ int ethernet_tune(openair0_device *device,
} else {
printf( "send timeout= %d,%d sec\n",(int)timeout.tv_sec,(int)timeout.tv_usec);
}
if (setsockopt(eth->sockfdd,
SOL_SOCKET,
SO_SNDTIMEO,
(char *)&timeout,sizeof(timeout))) {
perror("[ETHERNET] setsockopt()");
} else {
printf( "send timeout= %d,%d sec\n",(int)timeout.tv_sec,(int)timeout.tv_usec);
for (int i=0;i<eth->num_fd;i++) {
if (setsockopt(eth->sockfdd[i],
SOL_SOCKET,
SO_SNDTIMEO,
(char *)&timeout,sizeof(timeout))) {
perror("[ETHERNET] setsockopt()");
} else {
printf( "send timeout= %d,%d sec\n",(int)timeout.tv_sec,(int)timeout.tv_usec);
}
}
break;
@@ -293,20 +372,24 @@ int ethernet_tune(openair0_device *device,
ifr.ifr_addr.sa_family = AF_INET;
strncpy(ifr.ifr_name,eth->if_name, sizeof(ifr.ifr_name)-1);
ifr.ifr_mtu =value;
if (ioctl(eth->sockfdd,SIOCSIFMTU,(caddr_t)&ifr) < 0 )
perror ("[ETHERNET] Can't set the MTU");
else
printf("[ETHERNET] %s MTU size has changed to %d\n",eth->if_name,ifr.ifr_mtu);
for (int i=0;i<eth->num_fd;i++) {
if (ioctl(eth->sockfdd[i],SIOCSIFMTU,(caddr_t)&ifr) < 0 )
perror ("[ETHERNET] Can't set the MTU");
else
printf("[ETHERNET] %s MTU size has changed to %d\n",eth->if_name,ifr.ifr_mtu);
}
break;
case TX_Q_LEN: /* change TX queue length of eth interface */
ifr.ifr_addr.sa_family = AF_INET;
strncpy(ifr.ifr_name,eth->if_name, sizeof(ifr.ifr_name)-1);
ifr.ifr_qlen =value;
if (ioctl(eth->sockfdd,SIOCSIFTXQLEN,(caddr_t)&ifr) < 0 )
perror ("[ETHERNET] Can't set the txqueuelen");
else
printf("[ETHERNET] %s txqueuelen size has changed to %d\n",eth->if_name,ifr.ifr_qlen);
for (int i=0;i<eth->num_fd;i++) {
if (ioctl(eth->sockfdd[i],SIOCSIFTXQLEN,(caddr_t)&ifr) < 0 )
perror ("[ETHERNET] Can't set the txqueuelen");
else
printf("[ETHERNET] %s txqueuelen size has changed to %d\n",eth->if_name,ifr.ifr_qlen);
}
break;
/******************* device level options *************************/
@@ -357,7 +440,7 @@ int ethernet_tune(openair0_device *device,
}
break;
case KERNEL_RCV_BUF_MAX_SIZE:
ret=snprintf(system_cmd,sizeof(system_cmd),"sysctl -w net.core.rmem_max=%d",value);
ret=snprintf(system_cmd,sizeof(system_cmd),"sysctl -w net.core.rmem_max=%d;sysctl -w net.core.rmem_default=%d",value,value);
if (ret > 0) {
ret=system(system_cmd);
if (ret == -1) {
@@ -371,7 +454,7 @@ int ethernet_tune(openair0_device *device,
}
break;
case KERNEL_SND_BUF_MAX_SIZE:
ret=snprintf(system_cmd,sizeof(system_cmd),"sysctl -w net.core.wmem_max=%d",value);
ret=snprintf(system_cmd,sizeof(system_cmd),"sysctl -w net.core.wmem_max=%d;sysctl -w net.core.wmem_default=%d;sysctl -w net.core.netdev_max_backlog=5000;sysctl -w net.core.optmem_max=524288;",value,value);
if (ret > 0) {
ret=system(system_cmd);
if (ret == -1) {
@@ -413,7 +496,10 @@ int transport_init(openair0_device *device,
eth->compression = ALAW_COMPRESS;
}
eth->num_fd = 1;
printf("[ETHERNET]: Initializing openair0_device for %s ...\n", ((device->host_type == RAU_HOST) ? "RAU": "RRU"));
printf("[ETHERNET]: num_fd %d\n",eth->num_fd);
device->Mod_id = 0;//num_devices_eth++;
device->transp_type = ETHERNET_TP;
device->trx_start_func = trx_eth_start;
@@ -438,6 +524,9 @@ int transport_init(openair0_device *device,
device->trx_read_func2 = trx_eth_read_udp;
device->trx_ctlsend_func = trx_eth_ctlsend_udp;
device->trx_ctlrecv_func = trx_eth_ctlrecv_udp;
memset((void*)&device->fhstate,0,sizeof(device->fhstate));
printf("Setting %d RX channels to waiting\n",openair0_cfg->rx_num_channels);
for (int i=openair0_cfg->rx_num_channels;i<8;i++) device->fhstate.r[i] = 1;
} else if (eth->flags == ETH_RAW_IF4p5_MODE) {
device->trx_write_func = trx_eth_write_raw_IF4p5;
device->trx_read_func = trx_eth_read_raw_IF4p5;
@@ -454,6 +543,7 @@ int transport_init(openair0_device *device,
eth->if_name = eth_params->local_if_name;
device->priv = eth;
/* device specific */
// openair0_cfg[0].iq_rxrescale = 15;//rescale iqs
// openair0_cfg[0].iq_txshift = eth_params->iq_txshift;// shift
@@ -41,6 +41,7 @@
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/ether.h>
#include <common/utils/threadPool/thread-pool.h>
#define MAX_INST 4
#define DEFAULT_IF "lo"
@@ -59,12 +60,16 @@ typedef struct {
/*!\brief socket file desc (control)*/
int sockfdc;
/*!\brief number of sockets for user-plane*/
int num_fd;
/*!\brief socket file desc (user)*/
int sockfdd;
int sockfdd[8];
/*!\brief interface name */
char *if_name;
/*!\brief buffer size */
unsigned int buffer_size;
/*!\brief Fronthaul state */
fhstate_t *fhstate;
/*!\brief destination address (control) for UDP socket*/
struct sockaddr_in dest_addrc;
/*!\brief local address (control) for UDP socket*/
@@ -205,6 +210,28 @@ typedef struct {
short q;
} iqoai_t ;
typedef struct udpTXelem_s {
openair0_device *device;
openair0_timestamp timestamp;
void **buff;
int fd_ind;
int nant;
int nsamps;
int flags;
} udpTXelem_t;
struct udpTXReqId {
uint64_t TS;
int aid;
int length;
uint16_t spare;
} __attribute__((packed));
union udpTXReqUnion {
struct udpTXReqId s;
uint64_t p;
};
void dump_packet(char *title, unsigned char* pkt, int bytes, unsigned int tx_rx_flag);
unsigned short calc_csum (unsigned short *buf, int nwords);
void dump_dev(openair0_device *device);
@@ -214,7 +241,8 @@ void inline dump_txcounters(openair0_device *device);
*/
void dump_iqs(char * buff, int iq_cnt);
void *udp_read_thread(void *arg);
void *udp_write_thread(void *arg);
/*! \fn int ethernet_tune (openair0_device *device, unsigned int option, int value);
* \brief this function allows you to configure certain ethernet parameters in socket or device level
@@ -237,8 +265,8 @@ int ethernet_tune(openair0_device *device, unsigned int option, int value);
* @ingroup _oai
*/
int eth_socket_init_udp(openair0_device *device);
int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, void *buff, int nsamps,int cc, int flags);
int trx_eth_read_udp(openair0_device *device, openair0_timestamp *timestamp, void *buff, int nsamps, int *cc);
int trx_eth_write_udp(openair0_device *device, openair0_timestamp timestamp, void **buf, int fd_ind, int nsamps, int flags,int nant);
int trx_eth_read_udp(openair0_device *device, openair0_timestamp *timestamp, uint32_t **buff, int nsamps);
int eth_socket_init_raw(openair0_device *device);
@@ -38,7 +38,6 @@
#ifndef LITE_COMPILATION
#include "PHY/LTE_TRANSPORT/if4_tools.h"
#include "PHY/LTE_TRANSPORT/if5_tools.h"
#endif
// ETH transport preference modes
-1
View File
@@ -67,7 +67,6 @@
//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
#include "PHY/LTE_TRANSPORT/if4_tools.h"
#include "PHY/LTE_TRANSPORT/if5_tools.h"
#include "PHY/LTE_ESTIMATION/lte_estimation.h"
#include "PHY/phy_extern.h"
+17 -8
View File
@@ -54,7 +54,6 @@
#include "PHY/LTE_ESTIMATION/lte_estimation.h"
#include "PHY/LTE_REFSIG/lte_refsig.h"
#include "PHY/LTE_TRANSPORT/if4_tools.h"
#include "PHY/LTE_TRANSPORT/if5_tools.h"
#include "PHY/LTE_TRANSPORT/transport_proto.h"
#include "SCHED/sched_common.h"
#include "common/utils/LOG/log.h"
@@ -66,6 +65,8 @@
static int DEFBANDS[] = {7};
static int DEFENBS[] = {0};
static int DEFBFW[] = {0x00007fff};
static int DEFRUTPCORES[] = {2,4,6,8};
#include "ENB_APP/enb_paramdef.h"
#include "common/config/config_userapi.h"
@@ -134,8 +135,18 @@ static inline void fh_if5_south_out(RU_t *ru,int frame, int subframe, uint64_t t
if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
ru->south_out_cnt++;
int offset = subframe*ru->frame_parms->samples_per_tti;
void *buffs[ru->nb_tx];
for (int aid=0;aid<ru->nb_tx;aid++) buffs[aid] = (void*)&ru->common.txdata[aid][offset];
ru->ifdevice.trx_write_func2(&ru->ifdevice,
timestamp,
buffs,
0,
ru->frame_parms->samples_per_tti,
0,
ru->nb_tx);
send_IF5(ru, timestamp, subframe, &ru->seqno, IF5_RRH_GW_DL);
}
@@ -172,7 +183,7 @@ void fh_if5_south_in(RU_t *ru,
int *subframe) {
LTE_DL_FRAME_PARMS *fp = ru->frame_parms;
RU_proc_t *proc = &ru->proc;
recv_IF5(ru, &proc->timestamp_rx, *subframe, IF5_RRH_GW_UL);
ru->ifdevice.trx_read_func2(&ru->ifdevice,&proc->timestamp_rx,NULL,fp->samples_per_tti);
proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023;
proc->tti_rx = (proc->timestamp_rx / fp->samples_per_tti)%10;
@@ -398,8 +409,8 @@ void fh_if5_north_asynch_in(RU_t *ru,
LTE_DL_FRAME_PARMS *fp = ru->frame_parms;
RU_proc_t *proc = &ru->proc;
int tti_tx,frame_tx;
openair0_timestamp timestamp_tx;
recv_IF5(ru, &timestamp_tx, *subframe, IF5_RRH_GW_DL);
openair0_timestamp timestamp_tx=0;
//recv_IF5(ru, &timestamp_tx, *subframe, IF5_RRH_GW_DL);
// LOG_I(PHY,"Received subframe %d (TS %llu) from RCC\n",tti_tx,timestamp_tx);
tti_tx = (timestamp_tx/fp->samples_per_tti)%10;
frame_tx = (timestamp_tx/(fp->samples_per_tti*10))&1023;
@@ -492,11 +503,9 @@ void fh_if4p5_north_asynch_in(RU_t *ru,
void fh_if5_north_out(RU_t *ru) {
RU_proc_t *proc=&ru->proc;
uint8_t seqno=0;
/// **** send_IF5 of rxdata to BBU **** ///
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 1 );
send_IF5(ru, proc->timestamp_rx, proc->tti_rx, &seqno, IF5_RRH_GW_UL);
// send_IF5(ru, proc->timestamp_rx, proc->tti_rx, &seqno, IF5_RRH_GW_UL);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 0 );
}
-1
View File
@@ -57,7 +57,6 @@
#include "../../ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h"
#include "PHY/LTE_TRANSPORT/if4_tools.h"
#include "PHY/LTE_TRANSPORT/if5_tools.h"
#include "PHY/LTE_TRANSPORT/transport_proto.h"
#include "SCHED/sched_eNB.h"