Merge remote-tracking branch 'origin/if5_ECPRI_rework' into integration_2022_wk38
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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>
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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, ×tamp_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;
|
||||
|
||||
|
||||
@@ -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
@@ -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");
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,"];");
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 *)ð->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 *)ð->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*)ð->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);
|
||||
|
||||
@@ -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 *)ð->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 *)ð->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*)ð->dest_addrd,
|
||||
eth->addr_len);
|
||||
|
||||
/* Send packet */
|
||||
bytes_sent = sendto(eth->sockfdd[0],
|
||||
buff2,
|
||||
UDP_PACKET_SIZE_BYTES(len>>2),
|
||||
sendto_flag,
|
||||
(struct sockaddr*)ð->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 *)ð->dest_addrd,
|
||||
(socklen_t *)ð->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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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, ×tamp_tx, *subframe, IF5_RRH_GW_DL);
|
||||
openair0_timestamp timestamp_tx=0;
|
||||
//recv_IF5(ru, ×tamp_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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user