Merge remote-tracking branch 'origin/develop' into ru_rau_enhancement_L1_renaming
Conflicts: cmake_targets/build_oai cmake_targets/oaisim_build_oai/CMakeLists.template cmake_targets/oaisim_mme_build_oai/CMakeLists.template cmake_targets/oaisim_noS1_build_oai/CMakeLists.template openair1/PHY/LTE_ESTIMATION/lte_sync_time.c openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c openair1/PHY/LTE_TRANSPORT/dci_tools.c openair1/PHY/LTE_TRANSPORT/if4_tools.c openair1/PHY/LTE_TRANSPORT/prach.c openair1/PHY/LTE_TRANSPORT/pucch.c openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c openair1/PHY/impl_defs_lte.h openair1/SCHED/fapi_l1.c openair1/SCHED/phy_procedures_lte_eNb.c openair1/SIMULATION/LTE_PHY/dlsim.c openair2/ENB_APP/enb_config.c openair2/ENB_APP/enb_paramdef.h openair2/LAYER2/MAC/eNB_scheduler_RA.c openair2/LAYER2/MAC/eNB_scheduler_primitives.c targets/ARCH/ETHERNET/USERSPACE/LIB/eth_udp.c targets/ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.c targets/RT/USER/lte-enb.c targets/RT/USER/lte-ru.c targets/RT/USER/lte-softmodem.c targets/RT/USER/lte-softmodem.h
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -19,8 +19,8 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file common_lib.c
|
||||
* \brief common APIs for different RF frontend device
|
||||
/*! \file common_lib.c
|
||||
* \brief common APIs for different RF frontend device
|
||||
* \author HongliangXU, Navid Nikaein
|
||||
* \date 2015
|
||||
* \version 0.2
|
||||
@@ -37,79 +37,94 @@
|
||||
|
||||
#include "common_lib.h"
|
||||
#include "common/utils/load_module_shlib.h"
|
||||
#include "targets/RT/USER/lte-softmodem.h"
|
||||
|
||||
int set_device(openair0_device *device) {
|
||||
|
||||
switch (device->type) {
|
||||
|
||||
case EXMIMO_DEV:
|
||||
printf("[%s] has loaded EXPRESS MIMO device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
break;
|
||||
case USRP_B200_DEV:
|
||||
printf("[%s] has loaded USRP B200 device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
break;
|
||||
case USRP_X300_DEV:
|
||||
printf("[%s] has loaded USRP X300 device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
break;
|
||||
case BLADERF_DEV:
|
||||
printf("[%s] has loaded BLADERF device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
break;
|
||||
case LMSSDR_DEV:
|
||||
printf("[%s] has loaded LMSSDR device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
break;
|
||||
case IRIS_DEV:
|
||||
printf("[%s] has loaded Iris device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
break;
|
||||
case NONE_DEV:
|
||||
printf("[%s] has not loaded a HW device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
break;
|
||||
default:
|
||||
printf("[%s] invalid HW device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
return -1;
|
||||
case EXMIMO_DEV:
|
||||
printf("[%s] has loaded EXPRESS MIMO device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
break;
|
||||
|
||||
case USRP_B200_DEV:
|
||||
printf("[%s] has loaded USRP B200 device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
break;
|
||||
|
||||
case USRP_X300_DEV:
|
||||
printf("[%s] has loaded USRP X300 device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
break;
|
||||
|
||||
case BLADERF_DEV:
|
||||
printf("[%s] has loaded BLADERF device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
break;
|
||||
|
||||
case LMSSDR_DEV:
|
||||
printf("[%s] has loaded LMSSDR device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
break;
|
||||
|
||||
case IRIS_DEV:
|
||||
printf("[%s] has loaded Iris device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
break;
|
||||
|
||||
case NONE_DEV:
|
||||
printf("[%s] has not loaded a HW device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("[%s] invalid HW device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int set_transport(openair0_device *device) {
|
||||
|
||||
switch (device->transp_type) {
|
||||
|
||||
case ETHERNET_TP:
|
||||
printf("[%s] has loaded ETHERNET trasport protocol.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
return 0;
|
||||
break;
|
||||
case NONE_TP:
|
||||
printf("[%s] has not loaded a transport protocol.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
printf("[%s] invalid transport protocol.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
return -1;
|
||||
break;
|
||||
case ETHERNET_TP:
|
||||
printf("[%s] has loaded ETHERNET trasport protocol.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case NONE_TP:
|
||||
printf("[%s] has not loaded a transport protocol.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
return 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("[%s] invalid transport protocol.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
typedef int(*devfunc_t)(openair0_device *, openair0_config_t *, eth_params_t *);
|
||||
/* look for the interface library and load it */
|
||||
int load_lib(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t * cfg, uint8_t flag) {
|
||||
|
||||
int load_lib(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t *cfg, uint8_t flag) {
|
||||
loader_shlibfunc_t shlib_fdesc[1];
|
||||
int ret=0;
|
||||
char *libname;
|
||||
if (flag == RAU_LOCAL_RADIO_HEAD) {
|
||||
libname=OAI_RF_LIBNAME;
|
||||
shlib_fdesc[0].fname="device_init";
|
||||
} else {
|
||||
libname=OAI_TP_LIBNAME;
|
||||
shlib_fdesc[0].fname="transport_init";
|
||||
}
|
||||
ret=load_module_shlib(libname,shlib_fdesc,1,NULL);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr,"Library %s couldn't be loaded\n",libname);
|
||||
|
||||
if ( IS_SOFTMODEM_BASICSIM ) {
|
||||
libname=OAI_BASICSIM_LIBNAME;
|
||||
shlib_fdesc[0].fname="device_init";
|
||||
} else if ( IS_SOFTMODEM_RFSIM ) {
|
||||
libname=OAI_RFSIM_LIBNAME;
|
||||
shlib_fdesc[0].fname="device_init";
|
||||
} else if (flag == RAU_LOCAL_RADIO_HEAD) {
|
||||
libname=OAI_RF_LIBNAME;
|
||||
shlib_fdesc[0].fname="device_init";
|
||||
} else {
|
||||
ret=((devfunc_t)shlib_fdesc[0].fptr)(device,openair0_cfg,cfg);
|
||||
}
|
||||
return ret;
|
||||
libname=OAI_TP_LIBNAME;
|
||||
shlib_fdesc[0].fname="transport_init";
|
||||
}
|
||||
|
||||
ret=load_module_shlib(libname,shlib_fdesc,1,NULL);
|
||||
|
||||
if (ret < 0) {
|
||||
fprintf(stderr,"Library %s couldn't be loaded\n",libname);
|
||||
} else {
|
||||
ret=((devfunc_t)shlib_fdesc[0].fptr)(device,openair0_cfg,cfg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int openair0_check_device_loaded(){
|
||||
@@ -118,30 +133,31 @@ int openair0_check_device_loaded(){
|
||||
|
||||
|
||||
int openair0_device_load(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
|
||||
int rc=0;
|
||||
rc=load_lib(device, openair0_cfg, NULL,RAU_LOCAL_RADIO_HEAD );
|
||||
|
||||
if ( rc >= 0) {
|
||||
if ( set_device(device) < 0) {
|
||||
if ( rc >= 0) {
|
||||
if ( set_device(device) < 0) {
|
||||
fprintf(stderr, "%s %d:Unsupported radio head\n",__FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int openair0_transport_load(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t * eth_params) {
|
||||
int openair0_transport_load(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t *eth_params) {
|
||||
int rc;
|
||||
rc=load_lib(device, openair0_cfg, eth_params, RAU_REMOTE_RADIO_HEAD);
|
||||
if ( rc >= 0) {
|
||||
|
||||
if ( rc >= 0) {
|
||||
if ( set_transport(device) < 0) {
|
||||
fprintf(stderr, "%s %d:Unsupported transport protocol\n",__FILE__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file common_lib.h
|
||||
* \brief common APIs for different RF frontend device
|
||||
/*! \file common_lib.h
|
||||
* \brief common APIs for different RF frontend device
|
||||
* \author HongliangXU, Navid Nikaein
|
||||
* \date 2015
|
||||
* \version 0.2
|
||||
@@ -39,19 +39,22 @@
|
||||
#define OAI_RF_LIBNAME "oai_device"
|
||||
/* name of shared library implementing the transport */
|
||||
#define OAI_TP_LIBNAME "oai_transpro"
|
||||
|
||||
/* name of shared library implementing the basic/rf simulator */
|
||||
#define OAI_RFSIM_LIBNAME "rfsimulator"
|
||||
/* name of shared library implementing the basic/rf simulator */
|
||||
#define OAI_BASICSIM_LIBNAME "tcp_bridge_oai"
|
||||
/* flags for BBU to determine whether the attached radio head is local or remote */
|
||||
#define RAU_LOCAL_RADIO_HEAD 0
|
||||
#define RAU_REMOTE_RADIO_HEAD 1
|
||||
|
||||
#ifndef MAX_CARDS
|
||||
#define MAX_CARDS 8
|
||||
#define MAX_CARDS 8
|
||||
#endif
|
||||
|
||||
typedef int64_t openair0_timestamp;
|
||||
typedef volatile int64_t openair0_vtimestamp;
|
||||
|
||||
|
||||
|
||||
/*!\brief structrue holds the parameters to configure USRP devices*/
|
||||
typedef struct openair0_device_t openair0_device;
|
||||
|
||||
@@ -120,16 +123,16 @@ typedef enum {
|
||||
/*!\brief openair0 device host type */
|
||||
typedef enum {
|
||||
MIN_HOST_TYPE = 0,
|
||||
/*!\brief device functions within a RAU */
|
||||
/*!\brief device functions within a RAU */
|
||||
RAU_HOST,
|
||||
/*!\brief device functions within a RRU */
|
||||
/*!\brief device functions within a RRU */
|
||||
RRU_HOST,
|
||||
MAX_HOST_TYPE
|
||||
|
||||
}host_type_t;
|
||||
} host_type_t;
|
||||
|
||||
|
||||
/*! \brief RF Gain clibration */
|
||||
/*! \brief RF Gain clibration */
|
||||
typedef struct {
|
||||
//! Frequency for which RX chain was calibrated
|
||||
double freq;
|
||||
@@ -157,7 +160,7 @@ typedef struct {
|
||||
duplex_mode_t duplex_mode;
|
||||
//! number of downlink resource blocks
|
||||
int num_rb_dl;
|
||||
//! number of samples per frame
|
||||
//! number of samples per frame
|
||||
unsigned int samples_per_frame;
|
||||
//! the sample rate for both transmit and receive.
|
||||
double sample_rate;
|
||||
@@ -172,9 +175,9 @@ typedef struct {
|
||||
//! number of TX channels (=TX antennas)
|
||||
int tx_num_channels;
|
||||
//! \brief RX base addresses for mmapped_dma
|
||||
int32_t* rxbase[4];
|
||||
int32_t *rxbase[4];
|
||||
//! \brief TX base addresses for mmapped_dma
|
||||
int32_t* txbase[4];
|
||||
int32_t *txbase[4];
|
||||
//! \brief Center frequency in Hz for RX.
|
||||
//! index: [0..rx_num_channels[
|
||||
double rx_freq[4];
|
||||
@@ -185,7 +188,7 @@ typedef struct {
|
||||
//! \brief Pointer to Calibration table for RX gains
|
||||
rx_gain_calib_table_t *rx_gain_calib_table;
|
||||
|
||||
//! mode for rxgain (ExpressMIMO2)
|
||||
//! mode for rxgain (ExpressMIMO2)
|
||||
rx_gain_t rxg_mode[4];
|
||||
//! \brief Gain for RX in dB.
|
||||
//! index: [0..rx_num_channels]
|
||||
@@ -199,7 +202,7 @@ typedef struct {
|
||||
double rx_bw;
|
||||
//! TX bandwidth in Hz
|
||||
double tx_bw;
|
||||
//! clock source
|
||||
//! clock source
|
||||
clock_source_t clock_source;
|
||||
//! timing_source
|
||||
clock_source_t time_source;
|
||||
@@ -208,7 +211,7 @@ typedef struct {
|
||||
//! Auto calibration flag
|
||||
int autocal[4];
|
||||
//! rf devices work with x bits iqs when oai have its own iq format
|
||||
//! the two following parameters are used to convert iqs
|
||||
//! the two following parameters are used to convert iqs
|
||||
int iq_txshift;
|
||||
int iq_rxrescale;
|
||||
//! Configuration file for LMS7002M
|
||||
@@ -221,10 +224,10 @@ typedef struct {
|
||||
unsigned int sf_read_delay; // read delay in replay mode
|
||||
unsigned int sf_write_delay; // write delay in replay mode
|
||||
unsigned int eth_mtu; // ethernet MTU
|
||||
#endif
|
||||
#endif
|
||||
} openair0_config_t;
|
||||
|
||||
/*! \brief RF mapping */
|
||||
/*! \brief RF mapping */
|
||||
typedef struct {
|
||||
//! card id
|
||||
int card;
|
||||
@@ -271,14 +274,14 @@ struct openair0_device_t {
|
||||
|
||||
/*!brief Component Carrier ID of this device */
|
||||
int CC_id;
|
||||
|
||||
|
||||
/*!brief Type of this device */
|
||||
dev_type_t type;
|
||||
|
||||
/*!brief Transport protocol type that the device suppports (in case I/Q samples need to be transported) */
|
||||
transport_type_t transp_type;
|
||||
|
||||
/*!brief Type of the device's host (RAU/RRU) */
|
||||
/*!brief Type of the device's host (RAU/RRU) */
|
||||
host_type_t host_type;
|
||||
|
||||
/* !brief RF frontend parameters set by application */
|
||||
@@ -311,25 +314,25 @@ struct openair0_device_t {
|
||||
/*! \brief Called to send a request message between RAU-RRU on control port
|
||||
@param device pointer to the device structure specific to the RF hardware target
|
||||
@param msg pointer to the message structure passed between RAU-RRU
|
||||
@param msg_len length of the message
|
||||
*/
|
||||
@param msg_len length of the message
|
||||
*/
|
||||
int (*trx_ctlsend_func)(openair0_device *device, void *msg, ssize_t msg_len);
|
||||
|
||||
/*! \brief Called to receive a reply message between RAU-RRU on control port
|
||||
@param device pointer to the device structure specific to the RF hardware target
|
||||
@param msg pointer to the message structure passed between RAU-RRU
|
||||
@param msg_len length of the message
|
||||
*/
|
||||
@param msg_len length of the message
|
||||
*/
|
||||
int (*trx_ctlrecv_func)(openair0_device *device, void *msg, ssize_t msg_len);
|
||||
|
||||
/*! \brief Called to send samples to the RF target
|
||||
@param device pointer to the device structure specific to the RF hardware target
|
||||
@param timestamp The timestamp at whicch the first sample MUST be sent
|
||||
@param timestamp The timestamp at whicch the first sample MUST be sent
|
||||
@param buff Buffer which holds the samples
|
||||
@param nsamps number of samples to be sent
|
||||
@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_func)(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int antenna_id, int flags);
|
||||
|
||||
/*! \brief Receive samples from hardware.
|
||||
@@ -345,55 +348,55 @@ struct openair0_device_t {
|
||||
*/
|
||||
int (*trx_read_func)(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps,int antenna_id);
|
||||
|
||||
/*! \brief print the device statistics
|
||||
/*! \brief print the device statistics
|
||||
* \param device the hardware to use
|
||||
* \returns 0 on success
|
||||
*/
|
||||
int (*trx_get_stats_func)(openair0_device *device);
|
||||
|
||||
/*! \brief Reset device statistics
|
||||
/*! \brief Reset device statistics
|
||||
* \param device the hardware to use
|
||||
* \returns 0 in success
|
||||
* \returns 0 in success
|
||||
*/
|
||||
int (*trx_reset_stats_func)(openair0_device *device);
|
||||
|
||||
/*! \brief Terminate operation of the transceiver -- free all associated resources
|
||||
/*! \brief Terminate operation of the transceiver -- free all associated resources
|
||||
* \param device the hardware to use
|
||||
*/
|
||||
void (*trx_end_func)(openair0_device *device);
|
||||
|
||||
/*! \brief Stop operation of the transceiver
|
||||
/*! \brief Stop operation of the transceiver
|
||||
*/
|
||||
int (*trx_stop_func)(openair0_device *device);
|
||||
|
||||
/* Functions API related to UE*/
|
||||
|
||||
/*! \brief Set RX feaquencies
|
||||
/*! \brief Set RX feaquencies
|
||||
* \param device the hardware to use
|
||||
* \param openair0_cfg RF frontend parameters set by application
|
||||
* \param exmimo_dump_config dump EXMIMO configuration
|
||||
* \returns 0 in success
|
||||
* \param exmimo_dump_config dump EXMIMO configuration
|
||||
* \returns 0 in success
|
||||
*/
|
||||
int (*trx_set_freq_func)(openair0_device* device, openair0_config_t *openair0_cfg,int exmimo_dump_config);
|
||||
|
||||
int (*trx_set_freq_func)(openair0_device *device, openair0_config_t *openair0_cfg,int exmimo_dump_config);
|
||||
|
||||
/*! \brief Set gains
|
||||
* \param device the hardware to use
|
||||
* \param openair0_cfg RF frontend parameters set by application
|
||||
* \returns 0 in success
|
||||
* \returns 0 in success
|
||||
*/
|
||||
int (*trx_set_gains_func)(openair0_device* device, openair0_config_t *openair0_cfg);
|
||||
int (*trx_set_gains_func)(openair0_device *device, openair0_config_t *openair0_cfg);
|
||||
|
||||
/*! \brief RRU Configuration callback
|
||||
* \param idx RU index
|
||||
* \param arg pointer to capabilities or configuration
|
||||
*/
|
||||
void (*configure_rru)(int idx, void* arg);
|
||||
void (*configure_rru)(int idx, void *arg);
|
||||
};
|
||||
|
||||
/* type of device init function, implemented in shared lib */
|
||||
typedef int(*oai_device_initfunc_t)(openair0_device *device, openair0_config_t *openair0_cfg);
|
||||
/* type of transport init function, implemented in shared lib */
|
||||
typedef int(*oai_transport_initfunc_t)(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t * eth_params);
|
||||
typedef int(*oai_transport_initfunc_t)(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t *eth_params);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
@@ -401,23 +404,23 @@ extern "C"
|
||||
#endif
|
||||
|
||||
|
||||
/*! \brief Initialize openair RF target. It returns 0 if OK */
|
||||
int openair0_device_load(openair0_device *device, openair0_config_t *openair0_cfg);
|
||||
/*! \brief Initialize transport protocol . It returns 0 if OK */
|
||||
int openair0_transport_load(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t * eth_params);
|
||||
/*! \brief Initialize openair RF target. It returns 0 if OK */
|
||||
int openair0_device_load(openair0_device *device, openair0_config_t *openair0_cfg);
|
||||
/*! \brief Initialize transport protocol . It returns 0 if OK */
|
||||
int openair0_transport_load(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t *eth_params);
|
||||
|
||||
|
||||
/*! \brief Get current timestamp of USRP
|
||||
* \param device the hardware to use
|
||||
*/
|
||||
openair0_timestamp get_usrp_time(openair0_device *device);
|
||||
|
||||
/*! \brief Set RX frequencies
|
||||
* \param device the hardware to use
|
||||
* \param openair0_cfg RF frontend parameters set by application
|
||||
* \returns 0 in success
|
||||
*/
|
||||
int openair0_set_rx_frequencies(openair0_device* device, openair0_config_t *openair0_cfg);
|
||||
/*! \brief Get current timestamp of USRP
|
||||
* \param device the hardware to use
|
||||
*/
|
||||
openair0_timestamp get_usrp_time(openair0_device *device);
|
||||
|
||||
/*! \brief Set RX frequencies
|
||||
* \param device the hardware to use
|
||||
* \param openair0_cfg RF frontend parameters set by application
|
||||
* \returns 0 in success
|
||||
*/
|
||||
int openair0_set_rx_frequencies(openair0_device *device, openair0_config_t *openair0_cfg);
|
||||
|
||||
/*@}*/
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ int eth_socket_init_raw(openair0_device *device) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* 09/03/2019: fix obvious inconsistencies, but this code hasn't be tested for sure */
|
||||
int trx_eth_write_raw(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps,int cc, int flags) {
|
||||
|
||||
int bytes_sent=0;
|
||||
@@ -148,7 +148,12 @@ int trx_eth_write_raw(openair0_device *device, openair0_timestamp timestamp, voi
|
||||
//sendto_flag|=flags;
|
||||
|
||||
eth->tx_nsamps=nsamps;
|
||||
|
||||
int pktsize;
|
||||
if (eth->compression == ALAW_COMPRESS) {
|
||||
pktsize = RAW_PACKET_SIZE_BYTES_ALAW(nsamps);
|
||||
} else {
|
||||
pktsize = RAW_PACKET_SIZE_BYTES(nsamps);
|
||||
}
|
||||
for (i=0;i<cc;i++) {
|
||||
/* 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 */
|
||||
@@ -162,44 +167,27 @@ int trx_eth_write_raw(openair0_device *device, openair0_timestamp timestamp, voi
|
||||
bytes_sent = 0;
|
||||
memcpy(buff2,(void*)ð->ehd,MAC_HEADER_SIZE_BYTES);
|
||||
*(int16_t *)(buff2 + MAC_HEADER_SIZE_BYTES + sizeof(int16_t))=1+(i<<1);
|
||||
*(openair0_timestamp *)(buff2 + MAC_HEADER_SIZE_BYTES + sizeof(int32_t)) = timestamp;
|
||||
|
||||
int sent_byte;
|
||||
|
||||
*(openair0_timestamp *)(buff2 + MAC_HEADER_SIZE_BYTES + sizeof(int32_t)) = timestamp;
|
||||
|
||||
/*printf("[RRU]write mod_%d %d , len %d, buff %p \n",
|
||||
Mod_id,eth->sockfd[Mod_id],RAW_PACKET_SIZE_BYTES(nsamps), buff2);*/
|
||||
|
||||
while(bytes_sent < sent_byte) {
|
||||
#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
|
||||
while(bytes_sent < pktsize) {
|
||||
|
||||
/* Send packet */
|
||||
|
||||
bytes_sent += send(eth->sockfdd,
|
||||
buff2,
|
||||
sent_byte,
|
||||
pktsize,
|
||||
sendto_flag);
|
||||
if ( bytes_sent == -1) {
|
||||
eth->num_tx_errors++;
|
||||
perror("ETHERNET WRITE: ");
|
||||
exit(-1);
|
||||
} else {
|
||||
#if DEBUG
|
||||
printf("------- TX ------: nu=%x an_id=%d ts%d bytes_sent=%d\n",
|
||||
*(uint8_t *)(buff2+ETH_ALEN),
|
||||
*(int16_t *)(buff2 + MAC_HEADER_SIZE_BYTES + sizeof(int16_t)),
|
||||
*(openair0_timestamp *)(buff2 + MAC_HEADER_SIZE_BYTES + sizeof(int32_t)),
|
||||
bytes_sent);
|
||||
|
||||
dump_packet((device->host_type == RAU_HOST)? "RAU":"RRU", buff2, sent_byte, TX_FLAG);
|
||||
|
||||
#endif
|
||||
eth->tx_actual_nsamps=bytes_sent>>2;
|
||||
eth->tx_count++;
|
||||
eth->tx_actual_nsamps=bytes_sent>>2;
|
||||
eth->tx_count++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -245,7 +245,6 @@ int trx_eth_write_udp_IF4p5(openair0_device *device, openair0_timestamp timestam
|
||||
}
|
||||
|
||||
eth->tx_nsamps = nblocks;
|
||||
//printf("Sending %d bytes to %s:%d\n",packet_size,str,ntohs(eth->local_addrd.sin_port));
|
||||
|
||||
bytes_sent = sendto(eth->sockfdd,
|
||||
buff[0],
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file ethernet_lib.c
|
||||
/*! \file ethernet_lib.c
|
||||
* \brief API to stream I/Q samples over standard ethernet
|
||||
* \author add alcatel Katerina Trilyraki, Navid Nikaein, Pedro Dinis, Lucio Ferreira, Raymond Knopp
|
||||
* \date 2015
|
||||
@@ -55,114 +55,114 @@ int dest_addr_len[MAX_INST];
|
||||
|
||||
int trx_eth_start(openair0_device *device) {
|
||||
|
||||
eth_state_t *eth = (eth_state_t*)device->priv;
|
||||
|
||||
/* 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;
|
||||
/* RRU gets device configuration - RAU sets device configuration*/
|
||||
eth_state_t *eth = (eth_state_t*)device->priv;
|
||||
|
||||
printf("Setting Timenout to 999999 usecs\n");
|
||||
if(ethernet_tune (device,RCV_TIMEOUT,999999)!=0) return -1;
|
||||
/* 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;
|
||||
/* RRU gets device configuration - RAU sets device configuration*/
|
||||
|
||||
printf("Setting Timenout to 999999 usecs\n");
|
||||
if(ethernet_tune (device,RCV_TIMEOUT,999999)!=0) return -1;
|
||||
|
||||
/*
|
||||
if (device->host_type == RAU_HOST) {
|
||||
if(eth_set_dev_conf_raw(device)!=0) return -1;
|
||||
} else {
|
||||
if(eth_get_dev_conf_raw(device)!=0) return -1;
|
||||
}*/
|
||||
|
||||
/* adjust MTU wrt number of samples per packet */
|
||||
if(eth->compression == ALAW_COMPRESS) {
|
||||
if(ethernet_tune (device,MTU_SIZE,RAW_PACKET_SIZE_BYTES_ALAW(device->openair0_cfg->samples_per_packet))!=0) return -1;
|
||||
} else {
|
||||
if(ethernet_tune (device,MTU_SIZE,RAW_PACKET_SIZE_BYTES(device->openair0_cfg->samples_per_packet))!=0) return -1;
|
||||
}
|
||||
if(ethernet_tune (device,RCV_TIMEOUT,999999)!=0) return -1;
|
||||
} else if (eth->flags == ETH_RAW_IF4p5_MODE) {
|
||||
|
||||
printf("Setting ETHERNET to ETH_RAW_IF4p5_MODE\n");
|
||||
if (eth_socket_init_raw(device)!=0) return -1;
|
||||
|
||||
printf("Setting Timenout to 999999 usecs\n");
|
||||
if(ethernet_tune (device,RCV_TIMEOUT,999999)!=0) return -1;
|
||||
|
||||
/*
|
||||
if (device->host_type == RAU_HOST) {
|
||||
if(eth_set_dev_conf_raw_IF4p5(device)!=0) return -1;
|
||||
} else {
|
||||
if(eth_get_dev_conf_raw_IF4p5(device)!=0) return -1;
|
||||
}
|
||||
*/
|
||||
|
||||
/* adjust MTU wrt number of samples per packet */
|
||||
if(ethernet_tune (device,MTU_SIZE,RAW_IF4p5_PRACH_SIZE_BYTES)!=0) return -1;
|
||||
|
||||
if(ethernet_tune (device,RCV_TIMEOUT,999999)!=0) return -1;
|
||||
} else if (eth->flags == ETH_UDP_IF4p5_MODE) {
|
||||
printf("Setting ETHERNET to UDP_IF4p5_MODE\n");
|
||||
if (eth_socket_init_udp(device)!=0) return -1;
|
||||
|
||||
printf("Setting Timeout to 999999 usecs\n");
|
||||
if(ethernet_tune (device,RCV_TIMEOUT,999999)!=0) return -1;
|
||||
|
||||
/*
|
||||
if (device->host_type == RAU_HOST) {
|
||||
if(eth_set_dev_conf_udp(device)!=0) return -1;
|
||||
} else {
|
||||
if(eth_get_dev_conf_udp(device)!=0) return -1;
|
||||
}
|
||||
*/
|
||||
|
||||
/* adjust MTU wrt number of samples per packet */
|
||||
// if(ethernet_tune (device,MTU_SIZE,UDP_IF4p5_PRACH_SIZE_BYTES)!=0) return -1;
|
||||
|
||||
|
||||
|
||||
|
||||
} else if (eth->flags == ETH_RAW_IF5_MOBIPASS) {
|
||||
printf("Setting ETHERNET to RAW_IF5_MODE\n");
|
||||
if (eth_socket_init_raw(device)!=0) return -1;
|
||||
if(ethernet_tune (device,RCV_TIMEOUT,999999)!=0) return -1;
|
||||
|
||||
/*
|
||||
if (device->host_type == RAU_HOST) {
|
||||
if(eth_set_dev_conf_raw(device)!=0) return -1;
|
||||
} else {
|
||||
if(eth_get_dev_conf_raw(device)!=0) return -1;
|
||||
}*/
|
||||
printf("Setting ETHERNET to UDP_IF5_MODE\n");
|
||||
if (eth_socket_init_udp(device)!=0) return -1;
|
||||
|
||||
/* adjust MTU wrt number of samples per packet */
|
||||
if(eth->compression == ALAW_COMPRESS) {
|
||||
if(ethernet_tune (device,MTU_SIZE,RAW_PACKET_SIZE_BYTES_ALAW(device->openair0_cfg->samples_per_packet))!=0) return -1;
|
||||
} else {
|
||||
if(ethernet_tune (device,MTU_SIZE,RAW_PACKET_SIZE_BYTES(device->openair0_cfg->samples_per_packet))!=0) return -1;
|
||||
/*
|
||||
if (device->host_type == RAU_HOST) {
|
||||
if(eth_set_dev_conf_udp(device)!=0) return -1;
|
||||
} else {
|
||||
if(eth_get_dev_conf_udp(device)!=0) return -1;
|
||||
}*/
|
||||
|
||||
/* adjust MTU wrt number of samples per packet */
|
||||
if(ethernet_tune (device,MTU_SIZE,UDP_IF4p5_PRACH_SIZE_BYTES)!=0) return -1;
|
||||
|
||||
if(ethernet_tune (device,RCV_TIMEOUT,999999)!=0) return -1;
|
||||
}
|
||||
if(ethernet_tune (device,RCV_TIMEOUT,999999)!=0) return -1;
|
||||
} else if (eth->flags == ETH_RAW_IF4p5_MODE) {
|
||||
|
||||
printf("Setting ETHERNET to ETH_RAW_IF4p5_MODE\n");
|
||||
if (eth_socket_init_raw(device)!=0) return -1;
|
||||
|
||||
printf("Setting Timenout to 999999 usecs\n");
|
||||
if(ethernet_tune (device,RCV_TIMEOUT,999999)!=0) return -1;
|
||||
|
||||
/*
|
||||
if (device->host_type == RAU_HOST) {
|
||||
if(eth_set_dev_conf_raw_IF4p5(device)!=0) return -1;
|
||||
} else {
|
||||
if(eth_get_dev_conf_raw_IF4p5(device)!=0) return -1;
|
||||
}
|
||||
*/
|
||||
|
||||
/* adjust MTU wrt number of samples per packet */
|
||||
if(ethernet_tune (device,MTU_SIZE,RAW_IF4p5_PRACH_SIZE_BYTES)!=0) return -1;
|
||||
|
||||
if(ethernet_tune (device,RCV_TIMEOUT,999999)!=0) return -1;
|
||||
} else if (eth->flags == ETH_UDP_IF4p5_MODE) {
|
||||
printf("Setting ETHERNET to UDP_IF4p5_MODE\n");
|
||||
if (eth_socket_init_udp(device)!=0) return -1;
|
||||
|
||||
printf("Setting Timeout to 4999999 usecs\n");
|
||||
if(ethernet_tune (device,RCV_TIMEOUT,4999999)!=0) return -1;
|
||||
|
||||
/*
|
||||
if (device->host_type == RAU_HOST) {
|
||||
if(eth_set_dev_conf_udp(device)!=0) return -1;
|
||||
} else {
|
||||
if(eth_get_dev_conf_udp(device)!=0) return -1;
|
||||
}
|
||||
*/
|
||||
|
||||
/* adjust MTU wrt number of samples per packet */
|
||||
//if(ethernet_tune (device,MTU_SIZE,UDP_IF4p5_PRACH_SIZE_BYTES)!=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;
|
||||
|
||||
|
||||
|
||||
} else if (eth->flags == ETH_RAW_IF5_MOBIPASS) {
|
||||
printf("Setting ETHERNET to RAW_IF5_MODE\n");
|
||||
if (eth_socket_init_raw(device)!=0) return -1;
|
||||
if(ethernet_tune (device,RCV_TIMEOUT,999999)!=0) return -1;
|
||||
|
||||
} else {
|
||||
printf("Setting ETHERNET to UDP_IF5_MODE\n");
|
||||
if (eth_socket_init_udp(device)!=0) return -1;
|
||||
|
||||
/*
|
||||
if (device->host_type == RAU_HOST) {
|
||||
if(eth_set_dev_conf_udp(device)!=0) return -1;
|
||||
} else {
|
||||
if(eth_get_dev_conf_udp(device)!=0) return -1;
|
||||
}*/
|
||||
|
||||
/* adjust MTU wrt number of samples per packet */
|
||||
//if(ethernet_tune (device,MTU_SIZE,UDP_IF4p5_PRACH_SIZE_BYTES)!=0) return -1;
|
||||
|
||||
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;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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");
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -188,282 +188,282 @@ int trx_eth_reset_stats(openair0_device* device) {
|
||||
|
||||
|
||||
int ethernet_tune(openair0_device *device, unsigned int option, int value) {
|
||||
|
||||
eth_state_t *eth = (eth_state_t*)device->priv;
|
||||
struct timeval timeout;
|
||||
struct ifreq ifr;
|
||||
char system_cmd[256];
|
||||
int rname[] = { CTL_NET, NET_CORE, NET_CORE_RMEM_MAX };
|
||||
int wname[] = { CTL_NET, NET_CORE, NET_CORE_WMEM_MAX };
|
||||
int namelen=3;
|
||||
int newval[1];
|
||||
int newlen=sizeof(newval);
|
||||
int ret=0;
|
||||
// int i=0;
|
||||
|
||||
/****************** socket level options ************************/
|
||||
switch(option) {
|
||||
case SND_BUF_SIZE: /* transmit socket buffer size */
|
||||
if (setsockopt(eth->sockfdd,
|
||||
SOL_SOCKET,
|
||||
SO_SNDBUF,
|
||||
&value,sizeof(value))) {
|
||||
perror("[ETHERNET] setsockopt()");
|
||||
} else {
|
||||
printf("send buffer size= %d bytes\n",value);
|
||||
}
|
||||
break;
|
||||
|
||||
case RCV_BUF_SIZE: /* receive socket buffer size */
|
||||
if (setsockopt(eth->sockfdd,
|
||||
SOL_SOCKET,
|
||||
SO_RCVBUF,
|
||||
&value,sizeof(value))) {
|
||||
perror("[ETHERNET] setsockopt()");
|
||||
} else {
|
||||
printf("receive bufffer size= %d bytes\n",value);
|
||||
}
|
||||
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()");
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
break;
|
||||
|
||||
case SND_TIMEOUT:
|
||||
timeout.tv_sec = value/1000000000;
|
||||
timeout.tv_usec = value%1000000000;//less than rt_period?
|
||||
if (setsockopt(eth->sockfdc,
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
eth_state_t *eth = (eth_state_t*)device->priv;
|
||||
struct timeval timeout;
|
||||
struct ifreq ifr;
|
||||
char system_cmd[256];
|
||||
int rname[] = { CTL_NET, NET_CORE, NET_CORE_RMEM_MAX };
|
||||
int wname[] = { CTL_NET, NET_CORE, NET_CORE_WMEM_MAX };
|
||||
int namelen=3;
|
||||
int newval[1];
|
||||
int newlen=sizeof(newval);
|
||||
int ret=0;
|
||||
// int i=0;
|
||||
|
||||
/****************** socket level options ************************/
|
||||
switch(option) {
|
||||
case SND_BUF_SIZE: /* transmit socket buffer size */
|
||||
if (setsockopt(eth->sockfdd,
|
||||
SOL_SOCKET,
|
||||
SO_SNDBUF,
|
||||
&value,sizeof(value))) {
|
||||
perror("[ETHERNET] setsockopt()");
|
||||
} else {
|
||||
printf("send buffer size= %d bytes\n",value);
|
||||
}
|
||||
break;
|
||||
|
||||
case RCV_BUF_SIZE: /* receive socket buffer size */
|
||||
if (setsockopt(eth->sockfdd,
|
||||
SOL_SOCKET,
|
||||
SO_RCVBUF,
|
||||
&value,sizeof(value))) {
|
||||
perror("[ETHERNET] setsockopt()");
|
||||
} else {
|
||||
printf("receive bufffer size= %d bytes\n",value);
|
||||
}
|
||||
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()");
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
break;
|
||||
|
||||
case SND_TIMEOUT:
|
||||
timeout.tv_sec = value/1000000000;
|
||||
timeout.tv_usec = value%1000000000;//less than rt_period?
|
||||
if (setsockopt(eth->sockfdc,
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
/******************* interface level options *************************/
|
||||
case MTU_SIZE: /* change MTU of the eth interface */
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
strncpy(ifr.ifr_name,eth->if_name, sizeof(ifr.ifr_name));
|
||||
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);
|
||||
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));
|
||||
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);
|
||||
break;
|
||||
|
||||
case MTU_SIZE: /* change MTU of the eth interface */
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
strncpy(ifr.ifr_name,eth->if_name, sizeof(ifr.ifr_name));
|
||||
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);
|
||||
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));
|
||||
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);
|
||||
break;
|
||||
|
||||
/******************* device level options *************************/
|
||||
case COALESCE_PAR:
|
||||
ret=snprintf(system_cmd,sizeof(system_cmd),"ethtool -C %s rx-usecs %d",eth->if_name,value);
|
||||
if (ret > 0) {
|
||||
ret=system(system_cmd);
|
||||
if (ret == -1) {
|
||||
fprintf (stderr,"[ETHERNET] Can't start shell to execute %s %s",system_cmd, strerror(errno));
|
||||
} else {
|
||||
printf ("[ETHERNET] status of %s is %d\n", system_cmd, WEXITSTATUS(ret));
|
||||
}
|
||||
printf("[ETHERNET] Coalesce parameters %s\n",system_cmd);
|
||||
} else {
|
||||
perror("[ETHERNET] Can't set coalesce parameters\n");
|
||||
case COALESCE_PAR:
|
||||
ret=snprintf(system_cmd,sizeof(system_cmd),"ethtool -C %s rx-usecs %d",eth->if_name,value);
|
||||
if (ret > 0) {
|
||||
ret=system(system_cmd);
|
||||
if (ret == -1) {
|
||||
fprintf (stderr,"[ETHERNET] Can't start shell to execute %s %s",system_cmd, strerror(errno));
|
||||
} else {
|
||||
printf ("[ETHERNET] status of %s is %d\n", system_cmd, WEXITSTATUS(ret));
|
||||
}
|
||||
printf("[ETHERNET] Coalesce parameters %s\n",system_cmd);
|
||||
} else {
|
||||
perror("[ETHERNET] Can't set coalesce parameters\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case PAUSE_PAR:
|
||||
if (value==1) ret=snprintf(system_cmd,sizeof(system_cmd),"ethtool -A %s autoneg off rx off tx off",eth->if_name);
|
||||
else if (value==0) ret=snprintf(system_cmd,sizeof(system_cmd),"ethtool -A %s autoneg on rx on tx on",eth->if_name);
|
||||
else break;
|
||||
if (ret > 0) {
|
||||
ret=system(system_cmd);
|
||||
if (ret == -1) {
|
||||
fprintf (stderr,"[ETHERNET] Can't start shell to execute %s %s",system_cmd, strerror(errno));
|
||||
} else {
|
||||
printf ("[ETHERNET] status of %s is %d\n", system_cmd, WEXITSTATUS(ret));
|
||||
}
|
||||
printf("[ETHERNET] Pause parameters %s\n",system_cmd);
|
||||
} else {
|
||||
perror("[ETHERNET] Can't set pause parameters\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case RING_PAR:
|
||||
ret=snprintf(system_cmd,sizeof(system_cmd),"ethtool -G %s val %d",eth->if_name,value);
|
||||
if (ret > 0) {
|
||||
ret=system(system_cmd);
|
||||
if (ret == -1) {
|
||||
fprintf (stderr,"[ETHERNET] Can't start shell to execute %s %s",system_cmd, strerror(errno));
|
||||
} else {
|
||||
printf ("[ETHERNET] status of %s is %d\n", system_cmd, WEXITSTATUS(ret));
|
||||
}
|
||||
printf("[ETHERNET] Ring parameters %s\n",system_cmd);
|
||||
} else {
|
||||
perror("[ETHERNET] Can't set ring parameters\n");
|
||||
}
|
||||
break;
|
||||
case KERNEL_RCV_BUF_MAX_SIZE:
|
||||
newval[0] = value;
|
||||
ret=sysctl(rname, namelen, NULL, 0, newval, newlen);
|
||||
if (ret) {
|
||||
fprintf(stderr,"[ETHERNET] Error using sysctl():%s\n",strerror(errno));
|
||||
} else {
|
||||
printf("[ETHERNET] Kernel network receive buffer max size is set to %u\n",(unsigned int)newval[0]);
|
||||
}
|
||||
break;
|
||||
case KERNEL_SND_BUF_MAX_SIZE:
|
||||
newval[0] = value;
|
||||
ret=sysctl(wname, namelen, NULL, 0, newval, newlen);
|
||||
if (ret) {
|
||||
fprintf(stderr,"[ETHERNET] Error using sysctl():%s\n",strerror(errno));
|
||||
} else {
|
||||
printf("[ETHERNET] Kernel network send buffer max size is set to %u\n",(unsigned int)newval[0]);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case PAUSE_PAR:
|
||||
if (value==1) ret=snprintf(system_cmd,sizeof(system_cmd),"ethtool -A %s autoneg off rx off tx off",eth->if_name);
|
||||
else if (value==0) ret=snprintf(system_cmd,sizeof(system_cmd),"ethtool -A %s autoneg on rx on tx on",eth->if_name);
|
||||
else break;
|
||||
if (ret > 0) {
|
||||
ret=system(system_cmd);
|
||||
if (ret == -1) {
|
||||
fprintf (stderr,"[ETHERNET] Can't start shell to execute %s %s",system_cmd, strerror(errno));
|
||||
} else {
|
||||
printf ("[ETHERNET] status of %s is %d\n", system_cmd, WEXITSTATUS(ret));
|
||||
}
|
||||
printf("[ETHERNET] Pause parameters %s\n",system_cmd);
|
||||
} else {
|
||||
perror("[ETHERNET] Can't set pause parameters\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case RING_PAR:
|
||||
ret=snprintf(system_cmd,sizeof(system_cmd),"ethtool -G %s val %d",eth->if_name,value);
|
||||
if (ret > 0) {
|
||||
ret=system(system_cmd);
|
||||
if (ret == -1) {
|
||||
fprintf (stderr,"[ETHERNET] Can't start shell to execute %s %s",system_cmd, strerror(errno));
|
||||
} else {
|
||||
printf ("[ETHERNET] status of %s is %d\n", system_cmd, WEXITSTATUS(ret));
|
||||
}
|
||||
printf("[ETHERNET] Ring parameters %s\n",system_cmd);
|
||||
} else {
|
||||
perror("[ETHERNET] Can't set ring parameters\n");
|
||||
}
|
||||
break;
|
||||
case KERNEL_RCV_BUF_MAX_SIZE:
|
||||
newval[0] = value;
|
||||
ret=sysctl(rname, namelen, NULL, 0, newval, newlen);
|
||||
if (ret) {
|
||||
fprintf(stderr,"[ETHERNET] Error using sysctl():%s\n",strerror(errno));
|
||||
} else{
|
||||
printf("[ETHERNET] Kernel network receive buffer max size is set to %u\n",newval[0]);
|
||||
}
|
||||
break;
|
||||
case KERNEL_SND_BUF_MAX_SIZE:
|
||||
newval[0] = value;
|
||||
ret=sysctl(wname, namelen, NULL, 0, newval, newlen);
|
||||
if (ret) {
|
||||
fprintf(stderr,"[ETHERNET] Error using sysctl():%s\n",strerror(errno));
|
||||
} else{
|
||||
printf("[ETHERNET] Kernel network send buffer max size is set to %u\n",newval[0]);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int transport_init(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t * eth_params ) {
|
||||
|
||||
eth_state_t *eth = (eth_state_t*)malloc(sizeof(eth_state_t));
|
||||
memset(eth, 0, sizeof(eth_state_t));
|
||||
|
||||
if (eth_params->transp_preference == 1) {
|
||||
eth->flags = ETH_RAW_MODE;
|
||||
} else if (eth_params->transp_preference == 0) {
|
||||
eth->flags = ETH_UDP_MODE;
|
||||
} else if (eth_params->transp_preference == 3) {
|
||||
eth->flags = ETH_RAW_IF4p5_MODE;
|
||||
} else if (eth_params->transp_preference == 2) {
|
||||
eth->flags = ETH_UDP_IF4p5_MODE;
|
||||
} else if (eth_params->transp_preference == 4) {
|
||||
eth->flags = ETH_RAW_IF5_MOBIPASS;
|
||||
} else {
|
||||
printf("transport_init: Unknown transport preference %d - default to RAW", eth_params->transp_preference);
|
||||
eth->flags = ETH_RAW_MODE;
|
||||
}
|
||||
eth_state_t *eth = (eth_state_t*)malloc(sizeof(eth_state_t));
|
||||
memset(eth, 0, sizeof(eth_state_t));
|
||||
|
||||
if (eth_params->if_compress == 0) {
|
||||
eth->compression = NO_COMPRESS;
|
||||
} else if (eth_params->if_compress == 1) {
|
||||
eth->compression = ALAW_COMPRESS;
|
||||
} else {
|
||||
printf("transport_init: Unknown compression scheme %d - default to ALAW", eth_params->if_compress);
|
||||
eth->compression = ALAW_COMPRESS;
|
||||
}
|
||||
|
||||
printf("[ETHERNET]: Initializing openair0_device for %s ...\n", ((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
device->Mod_id = 0;//num_devices_eth++;
|
||||
device->transp_type = ETHERNET_TP;
|
||||
device->trx_start_func = trx_eth_start;
|
||||
device->trx_get_stats_func = trx_eth_get_stats;
|
||||
device->trx_reset_stats_func = trx_eth_reset_stats;
|
||||
device->trx_end_func = trx_eth_end;
|
||||
device->trx_stop_func = trx_eth_stop;
|
||||
device->trx_set_freq_func = trx_eth_set_freq;
|
||||
device->trx_set_gains_func = trx_eth_set_gains;
|
||||
|
||||
if (eth->flags == ETH_RAW_MODE) {
|
||||
device->trx_write_func = trx_eth_write_raw;
|
||||
device->trx_read_func = trx_eth_read_raw;
|
||||
} else if (eth->flags == ETH_UDP_MODE) {
|
||||
device->trx_write_func = trx_eth_write_udp;
|
||||
device->trx_read_func = trx_eth_read_udp;
|
||||
device->trx_ctlsend_func = trx_eth_ctlsend_udp;
|
||||
device->trx_ctlrecv_func = trx_eth_ctlrecv_udp;
|
||||
} 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;
|
||||
} else if (eth->flags == ETH_UDP_IF4p5_MODE) {
|
||||
device->trx_write_func = trx_eth_write_udp_IF4p5;
|
||||
device->trx_read_func = trx_eth_read_udp_IF4p5;
|
||||
device->trx_ctlsend_func = trx_eth_ctlsend_udp;
|
||||
device->trx_ctlrecv_func = trx_eth_ctlrecv_udp;
|
||||
} else if (eth->flags == ETH_RAW_IF5_MOBIPASS) {
|
||||
device->trx_write_func = trx_eth_write_raw_IF4p5;
|
||||
device->trx_read_func = trx_eth_read_raw_IF5_mobipass;
|
||||
} else {
|
||||
//device->trx_write_func = trx_eth_write_udp_IF4p5;
|
||||
//device->trx_read_func = trx_eth_read_udp_IF4p5;
|
||||
}
|
||||
|
||||
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
|
||||
// openair0_cfg[0].tx_sample_advance = eth_params->tx_sample_advance;
|
||||
|
||||
/* RRU does not have any information to make this configuration atm */
|
||||
/*
|
||||
if (device->host_type == RAU_HOST) {
|
||||
|
||||
switch ((int)openair0_cfg[0].sample_rate) {
|
||||
case 30720000:
|
||||
openair0_cfg[0].samples_per_packet = 3840;
|
||||
break;
|
||||
case 23040000:
|
||||
openair0_cfg[0].samples_per_packet = 2880;
|
||||
break;
|
||||
case 15360000:
|
||||
openair0_cfg[0].samples_per_packet = 1920;
|
||||
break;
|
||||
case 7680000:
|
||||
openair0_cfg[0].samples_per_packet = 960;
|
||||
break;
|
||||
case 1920000:
|
||||
openair0_cfg[0].samples_per_packet = 240;
|
||||
break;
|
||||
default:
|
||||
printf("Error: unknown sampling rate %f\n",openair0_cfg[0].sample_rate);
|
||||
exit(-1);
|
||||
break;
|
||||
if (eth_params->transp_preference == 1) {
|
||||
eth->flags = ETH_RAW_MODE;
|
||||
} else if (eth_params->transp_preference == 0) {
|
||||
eth->flags = ETH_UDP_MODE;
|
||||
} else if (eth_params->transp_preference == 3) {
|
||||
eth->flags = ETH_RAW_IF4p5_MODE;
|
||||
} else if (eth_params->transp_preference == 2) {
|
||||
eth->flags = ETH_UDP_IF4p5_MODE;
|
||||
} else if (eth_params->transp_preference == 4) {
|
||||
eth->flags = ETH_RAW_IF5_MOBIPASS;
|
||||
} else {
|
||||
printf("transport_init: Unknown transport preference %d - default to RAW", eth_params->transp_preference);
|
||||
eth->flags = ETH_RAW_MODE;
|
||||
}
|
||||
}*/
|
||||
|
||||
device->openair0_cfg=&openair0_cfg[0];
|
||||
return 0;
|
||||
if (eth_params->if_compress == 0) {
|
||||
eth->compression = NO_COMPRESS;
|
||||
} else if (eth_params->if_compress == 1) {
|
||||
eth->compression = ALAW_COMPRESS;
|
||||
} else {
|
||||
printf("transport_init: Unknown compression scheme %d - default to ALAW", eth_params->if_compress);
|
||||
eth->compression = ALAW_COMPRESS;
|
||||
}
|
||||
|
||||
printf("[ETHERNET]: Initializing openair0_device for %s ...\n", ((device->host_type == RAU_HOST) ? "RAU": "RRU"));
|
||||
device->Mod_id = 0;//num_devices_eth++;
|
||||
device->transp_type = ETHERNET_TP;
|
||||
device->trx_start_func = trx_eth_start;
|
||||
device->trx_get_stats_func = trx_eth_get_stats;
|
||||
device->trx_reset_stats_func = trx_eth_reset_stats;
|
||||
device->trx_end_func = trx_eth_end;
|
||||
device->trx_stop_func = trx_eth_stop;
|
||||
device->trx_set_freq_func = trx_eth_set_freq;
|
||||
device->trx_set_gains_func = trx_eth_set_gains;
|
||||
|
||||
if (eth->flags == ETH_RAW_MODE) {
|
||||
device->trx_write_func = trx_eth_write_raw;
|
||||
device->trx_read_func = trx_eth_read_raw;
|
||||
} else if (eth->flags == ETH_UDP_MODE) {
|
||||
device->trx_write_func = trx_eth_write_udp;
|
||||
device->trx_read_func = trx_eth_read_udp;
|
||||
device->trx_ctlsend_func = trx_eth_ctlsend_udp;
|
||||
device->trx_ctlrecv_func = trx_eth_ctlrecv_udp;
|
||||
} 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;
|
||||
} else if (eth->flags == ETH_UDP_IF4p5_MODE) {
|
||||
device->trx_write_func = trx_eth_write_udp_IF4p5;
|
||||
device->trx_read_func = trx_eth_read_udp_IF4p5;
|
||||
device->trx_ctlsend_func = trx_eth_ctlsend_udp;
|
||||
device->trx_ctlrecv_func = trx_eth_ctlrecv_udp;
|
||||
} else if (eth->flags == ETH_RAW_IF5_MOBIPASS) {
|
||||
device->trx_write_func = trx_eth_write_raw_IF4p5;
|
||||
device->trx_read_func = trx_eth_read_raw_IF5_mobipass;
|
||||
} else {
|
||||
//device->trx_write_func = trx_eth_write_udp_IF4p5;
|
||||
//device->trx_read_func = trx_eth_read_udp_IF4p5;
|
||||
}
|
||||
|
||||
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
|
||||
// openair0_cfg[0].tx_sample_advance = eth_params->tx_sample_advance;
|
||||
|
||||
/* RRU does not have any information to make this configuration atm */
|
||||
/*
|
||||
if (device->host_type == RAU_HOST) {
|
||||
|
||||
switch ((int)openair0_cfg[0].sample_rate) {
|
||||
case 30720000:
|
||||
openair0_cfg[0].samples_per_packet = 3840;
|
||||
break;
|
||||
case 23040000:
|
||||
openair0_cfg[0].samples_per_packet = 2880;
|
||||
break;
|
||||
case 15360000:
|
||||
openair0_cfg[0].samples_per_packet = 1920;
|
||||
break;
|
||||
case 7680000:
|
||||
openair0_cfg[0].samples_per_packet = 960;
|
||||
break;
|
||||
case 1920000:
|
||||
openair0_cfg[0].samples_per_packet = 240;
|
||||
break;
|
||||
default:
|
||||
printf("Error: unknown sampling rate %f\n",openair0_cfg[0].sample_rate);
|
||||
exit(-1);
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
|
||||
device->openair0_cfg=&openair0_cfg[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Executable → Regular
Executable → Regular
@@ -444,7 +444,7 @@ static void *watchdog_thread(void *arg) {
|
||||
(diff > 16)&&
|
||||
(first_acquisition==0)) {// we're too late so exit
|
||||
exm->watchdog_exit = 1;
|
||||
printf("exiting, too late to keep up - diff = %d\n", diff);
|
||||
printf("exiting, too late to keep up - diff = %u\n", diff);
|
||||
}
|
||||
first_acquisition=0;
|
||||
|
||||
@@ -625,7 +625,7 @@ int trx_exmimo_read(openair0_device *device, openair0_timestamp *ptimestamp, voi
|
||||
if (cfg->mmapped_dma == 0) { // if buff is not the dma buffer, do a memcpy, otherwise do nothing
|
||||
for (i=0;i<cc;i++) {
|
||||
#ifdef DEBUG_EXMIMO
|
||||
printf("copying to %p (%lu), from %llu\n",buff[i]+(ntot*sizeof(int)),ntot*sizeof(int),(exm->last_ts_rx % exm->samples_per_frame));
|
||||
printf("copying to %p (%zu), from %llu\n",buff[i]+(ntot*sizeof(int)),ntot*sizeof(int),(exm->last_ts_rx % exm->samples_per_frame));
|
||||
#endif
|
||||
if ((n+(exm->last_ts_rx%exm->samples_per_frame))<exm->samples_per_frame) {
|
||||
memcpy(buff[i]+(ntot*sizeof(int)),
|
||||
@@ -733,7 +733,7 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
|
||||
if (ret == -3)
|
||||
printf("Error mapping RX or TX buffer");
|
||||
|
||||
free(exm);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
@@ -752,6 +752,7 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
// check if the software matches firmware
|
||||
if (p_exmimo_id->board_swrev!=BOARD_SWREV_CNTL2) {
|
||||
printf("Software revision %d and firmware revision %d do not match. Please update either the firmware or the software!\n",BOARD_SWREV_CNTL2,p_exmimo_id->board_swrev);
|
||||
free(exm);
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
@@ -905,7 +906,7 @@ int openair0_config(openair0_config_t *openair0_cfg, int UE_flag)
|
||||
p_exmimo_config->rf.rx_gain[ant][0] = 30 - (rxg_max[ant] - (int)openair0_cfg[card].rx_gain[ant]); //was measured at rxgain=30;
|
||||
}
|
||||
else {
|
||||
printf("openair0: RX RF gain too high, reduce by %d dB\n", (int)openair0_cfg[card].rx_gain[ant]-rxg_max[ant]);
|
||||
printf("openair0: RX RF gain too high, reduce by %u dB\n", (int)openair0_cfg[card].rx_gain[ant]-rxg_max[ant]);
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
@@ -916,7 +917,7 @@ int openair0_config(openair0_config_t *openair0_cfg, int UE_flag)
|
||||
p_exmimo_config->rf.rx_gain[ant][0] = 30 - (rxg_med[ant] - (int)openair0_cfg[card].rx_gain[ant]); //was measured at rxgain=30;
|
||||
}
|
||||
else {
|
||||
printf("openair0: RX RF gain too high, reduce by %d dB\n", (int)openair0_cfg[card].rx_gain[ant]-rxg_med[ant]);
|
||||
printf("openair0: RX RF gain too high, reduce by %u dB\n", (int)openair0_cfg[card].rx_gain[ant]-rxg_med[ant]);
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
@@ -927,7 +928,7 @@ int openair0_config(openair0_config_t *openair0_cfg, int UE_flag)
|
||||
p_exmimo_config->rf.rx_gain[ant][0] = 30 - (rxg_byp[ant] - (int)openair0_cfg[card].rx_gain[ant]); //was measured at rxgain=30;
|
||||
}
|
||||
else {
|
||||
printf("openair0: RX RF gain too high, reduce by %d dB\n", (int)openair0_cfg[card].rx_gain[ant]-rxg_byp[ant]);
|
||||
printf("openair0: RX RF gain too high, reduce by %u dB\n", (int)openair0_cfg[card].rx_gain[ant]-rxg_byp[ant]);
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -211,22 +211,25 @@ void find_and_transfer_section(char* section_name, unsigned int verboselevel) {
|
||||
int nbread;
|
||||
unsigned int secnb = 0;
|
||||
|
||||
if(p_elfimage == NULL) {
|
||||
fprintf(stderr, "%s %d:Error, firmware file not opened\n",__FILE__,__LINE__);
|
||||
}
|
||||
for (secnb = 0 ; secnb < elf_Ehdr.e_shnum; secnb++) {
|
||||
get_elf_section_header(&elf_Shdr, p_elfimage, secnb);
|
||||
|
||||
if (!strcmp(SecNameStnTable + elf_Shdr.sh_name, section_name)) {
|
||||
if (verboselevel >= VERBOSE_LEVEL_SECTION_DETAILS)
|
||||
printf("Info: ok, found section %s (as section nb. %d)\n", SecNameStnTable + elf_Shdr.sh_name, secnb);
|
||||
printf("Info: ok, found section %s (as section nb. %u)\n", SecNameStnTable + elf_Shdr.sh_name, secnb);
|
||||
|
||||
/* Check that section size is a multiple of 4 bytes. */
|
||||
if (elf_Shdr.sh_size % 4) {
|
||||
fprintf(stderr, "Error: section %s has a non-multiple-of-4-bytes size (%d).\n",
|
||||
SecNameStnTable + elf_Shdr.sh_name, elf_Shdr.sh_size);
|
||||
fprintf(stderr, "Error: section %s has a non-multiple-of-4-bytes size (%lu).\n",
|
||||
SecNameStnTable + elf_Shdr.sh_name, (unsigned long)elf_Shdr.sh_size);
|
||||
fclose(p_elfimage);
|
||||
exit(-1);
|
||||
} else if (verboselevel >= VERBOSE_LEVEL_SECTION_DETAILS) {
|
||||
printf("Info: ok, section %s has size %d bytes (multiple of 4 bytes).\n",
|
||||
SecNameStnTable + elf_Shdr.sh_name, elf_Shdr.sh_size);
|
||||
printf("Info: ok, section %s has size %lu bytes (multiple of 4 bytes).\n",
|
||||
SecNameStnTable + elf_Shdr.sh_name, (unsigned long)elf_Shdr.sh_size);
|
||||
}
|
||||
|
||||
/* Dynamically allocate a chunk of memory to store the section into. */
|
||||
@@ -245,13 +248,13 @@ void find_and_transfer_section(char* section_name, unsigned int verboselevel) {
|
||||
}
|
||||
|
||||
if (!section_content) {
|
||||
fprintf(stderr, "Error: could not dynamically allocate %d bytes for section %s.\n",
|
||||
elf_Shdr.sh_size, SecNameStnTable + elf_Shdr.sh_name);
|
||||
fprintf(stderr, "Error: could not dynamically allocate %lu bytes for section %s.\n",
|
||||
(unsigned long)elf_Shdr.sh_size, (SecNameStnTable + elf_Shdr.sh_name));
|
||||
fclose(p_elfimage);
|
||||
exit(-1);
|
||||
} else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
|
||||
printf("Info: ok, dynamically allocated a %d bytes buffer for section %s.\n",
|
||||
elf_Shdr.sh_size, SecNameStnTable + elf_Shdr.sh_name);
|
||||
printf("Info: ok, dynamically allocated a %lu bytes buffer for section %s.\n",
|
||||
(unsigned long)elf_Shdr.sh_size, SecNameStnTable + elf_Shdr.sh_name);
|
||||
}
|
||||
|
||||
/* Position the file cursor at the begining of proper section. */
|
||||
@@ -260,13 +263,13 @@ void find_and_transfer_section(char* section_name, unsigned int verboselevel) {
|
||||
nbread = fread(section_content, elf_Shdr.sh_size, 1, p_elfimage);
|
||||
|
||||
if (nbread != 1) {
|
||||
fprintf(stderr, "Error: could not read %d bytes from ELF file into dynamic buffer.\n", elf_Shdr.sh_size);
|
||||
fprintf(stderr, "Error: could not read %lu bytes from ELF file into dynamic buffer.\n", (unsigned long)elf_Shdr.sh_size);
|
||||
free(section_content);
|
||||
fclose(p_elfimage);
|
||||
exit(-1);
|
||||
} else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
|
||||
printf("Info: ok, copied content of section %s into dynamic buffer (%d bytes copied).\n",
|
||||
SecNameStnTable + elf_Shdr.sh_name, elf_Shdr.sh_size);
|
||||
printf("Info: ok, copied content of section %s into dynamic buffer (%lu bytes copied).\n",
|
||||
SecNameStnTable + elf_Shdr.sh_name, (unsigned long)elf_Shdr.sh_size);
|
||||
}
|
||||
|
||||
/* Open the special device file. */
|
||||
@@ -324,12 +327,15 @@ void find_and_clear_section_bss(unsigned int verboselevel) {
|
||||
int ifile;
|
||||
unsigned int secnb = 0;
|
||||
|
||||
if(p_elfimage == NULL) {
|
||||
fprintf(stderr, "%s %d:Error, firmware file not opened\n",__FILE__,__LINE__);
|
||||
}
|
||||
for (secnb = 0 ; secnb < elf_Ehdr.e_shnum; secnb++) {
|
||||
get_elf_section_header(&elf_Shdr, p_elfimage, secnb);
|
||||
|
||||
if (!strcmp(SecNameStnTable + elf_Shdr.sh_name, ".bss")) {
|
||||
if (verboselevel >= VERBOSE_LEVEL_SECTION_DETAILS)
|
||||
printf("Info: ok, found section %s (as section nb. %d)\n", SecNameStnTable + elf_Shdr.sh_name, secnb);
|
||||
printf("Info: ok, found section %s (as section nb. %u)\n", SecNameStnTable + elf_Shdr.sh_name, secnb);
|
||||
|
||||
/* Open the special device file. */
|
||||
if (!pflag) {
|
||||
@@ -491,6 +497,10 @@ int main(int argc, char** argv) {
|
||||
|
||||
/* Open firmware file in READ_ONLY mode. */
|
||||
filename = p_str_fwn;
|
||||
if (filename == NULL) {
|
||||
fprintf(stderr, "%s %d: No filename specified\n", __FILE__, __LINE__);
|
||||
exit(-1);
|
||||
}
|
||||
p_elfimage = fopen(filename, READ_FILE_MODE);
|
||||
|
||||
if (p_elfimage == NULL) {
|
||||
@@ -505,6 +515,7 @@ int main(int argc, char** argv) {
|
||||
/* Get informations from header file */
|
||||
if (!(get_elf_header(&elf_Ehdr, p_elfimage))) {
|
||||
fprintf(stderr, "Error : file doesn't match expected format.\n");
|
||||
fclose(p_elfimage);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
@@ -522,9 +533,10 @@ int main(int argc, char** argv) {
|
||||
|
||||
/* copy the string table into global variable */
|
||||
if (StringSec_size > MAX_SIZE_STRING_TABLE) {
|
||||
fprintf(stderr, "Error: section name string table too big (%d > %d);"
|
||||
fprintf(stderr, "Error: section name string table too big (%ld > %d);"
|
||||
" increase max. allowed value in source code and recompile\n",
|
||||
StringSec_size, MAX_SIZE_STRING_TABLE);
|
||||
fclose(p_elfimage);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
@@ -626,7 +638,7 @@ int main(int argc, char** argv) {
|
||||
if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: entering action #5 (Jump to firmware/set stack-pointer).\n");
|
||||
|
||||
if (verboselevel >= VERBOSE_LEVEL_SECTION_DETAILS)
|
||||
printf("Info: Firmware entry point = 0x%08x, setting stack pointer = 0x%08x.\n", elf_Ehdr.e_entry, stackpointer);
|
||||
printf("Info: Firmware entry point = 0x%08x, setting stack pointer = 0x%08x.\n", (unsigned int)elf_Ehdr.e_entry, stackpointer);
|
||||
|
||||
/* Open the special device file. */
|
||||
if (!pflag) {
|
||||
|
||||
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
@@ -116,7 +116,7 @@ DEFUN_DLD (oarf_send_frame, args, nargout,"Send frame")
|
||||
|
||||
for (i=0;i<4;i++) {
|
||||
resampling_factor[i] = (openair0_exmimo_pci[card].exmimo_config_ptr)->framing.resampling_factor[i];
|
||||
printf("card %d, ant %d, resampling %d\n",card,i,resampling_factor[i]);
|
||||
printf("card %d, ant %d, resampling %u\n",card,i,resampling_factor[i]);
|
||||
}
|
||||
|
||||
for (i=0;i<numcols;i++){
|
||||
|
||||
Executable → Regular
Executable → Regular
Executable → Regular
@@ -1,4 +1,3 @@
|
||||
IRIS_OBJ += $(OPENAIR_TARGETS)/ARCH/IRIS/USERSPACE/LIB/iris_lib.o
|
||||
IRIS_FILE_OBJ += $(OPENAIR_TARGETS)/ARCH/IRIS/USERSPACE/LIB/iris_lib.cpp
|
||||
IRIS_CFLAGS += -I$(OPENAIR_TARGETS)/ARCH/COMMON -I$(OPENAIR_TARGETS)/ARCH/IRIS/USERSPACE/LIB/ -I$(OPENAIR_TARGETS)/COMMON
|
||||
|
||||
|
||||
@@ -35,7 +35,8 @@
|
||||
#define SAMPLE_RATE_DOWN 1
|
||||
|
||||
/*! \brief Iris Configuration */
|
||||
typedef struct {
|
||||
extern "C" {
|
||||
typedef struct {
|
||||
|
||||
// --------------------------------
|
||||
// variables for Iris configuration
|
||||
@@ -78,8 +79,8 @@ typedef struct {
|
||||
//! timestamp of RX packet
|
||||
openair0_timestamp rx_timestamp;
|
||||
|
||||
} iris_state_t;
|
||||
|
||||
} iris_state_t;
|
||||
}
|
||||
/*! \brief Called to start the Iris lime transceiver. Return 0 if OK, < 0 if error
|
||||
@param device pointer to the device structure specific to the RF hardware target
|
||||
*/
|
||||
@@ -151,13 +152,15 @@ trx_iris_write(openair0_device *device, openair0_timestamp timestamp, void **buf
|
||||
iris_state_t *s = (iris_state_t *) device->priv;
|
||||
int nsamps2; // aligned to upper 32 or 16 byte boundary
|
||||
#if defined(__x86_64) || defined(__i386__)
|
||||
#ifdef __AVX2__
|
||||
#ifdef __AVX2__
|
||||
nsamps2 = (nsamps+7)>>3;
|
||||
__m256i buff_tx[2][nsamps2];
|
||||
#else
|
||||
#else
|
||||
nsamps2 = (nsamps+3)>>2;
|
||||
__m128i buff_tx[2][nsamps2];
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#error unsupported CPU architecture, iris device cannot be built
|
||||
#endif
|
||||
|
||||
// bring RX data into 12 LSBs for softmodem RX
|
||||
@@ -332,8 +335,8 @@ static int trx_iris_read(openair0_device *device, openair0_timestamp *ptimestamp
|
||||
((__m256i *)buff[i])[j] = _mm256_srai_epi16(buff_tmp[i][j],4);
|
||||
#else
|
||||
((__m128i *)buff[i])[j] = _mm_srai_epi16(buff_tmp[i][j],4);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -531,7 +534,7 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
args["driver"] = "iris";
|
||||
char *iris_addrs = device->openair0_cfg[0].sdr_addrs;
|
||||
if (iris_addrs == NULL)
|
||||
{
|
||||
{
|
||||
s->iris.push_back(SoapySDR::Device::make(args));
|
||||
}
|
||||
else
|
||||
@@ -692,20 +695,20 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
printf("Actual master clock: %fMHz...\n", (s->iris[r]->getMasterClockRate() / 1e6));
|
||||
|
||||
int tx_filt_bw = openair0_cfg[0].tx_bw;
|
||||
int rx_filt_bw = openair0_cfg[0].rx_bw;
|
||||
#ifdef MOVE_DC //the filter is centered around the carrier, so we have to expand it if we have moved the DC tone.
|
||||
tx_filt_bw *= 3;
|
||||
rx_filt_bw *= 3;
|
||||
tx_filt_bw *= 3;
|
||||
rx_filt_bw *= 3;
|
||||
#endif
|
||||
/* Setting TX/RX BW */
|
||||
for (i = 0; i < s->tx_num_channels; i++) {
|
||||
if (i < s->iris[r]->getNumChannels(SOAPY_SDR_TX)) {
|
||||
s->iris[r]->setBandwidth(SOAPY_SDR_TX, i, tx_filt_bw);
|
||||
printf("Setting tx bandwidth on channel %lu/%lu: BW %f (readback %f)\n", i,
|
||||
printf("Setting tx bandwidth on channel %zu/%lu: BW %f (readback %f)\n", i,
|
||||
s->iris[r]->getNumChannels(SOAPY_SDR_TX), tx_filt_bw / 1e6,
|
||||
s->iris[r]->getBandwidth(SOAPY_SDR_TX, i) / 1e6);
|
||||
}
|
||||
@@ -713,7 +716,7 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
for (i = 0; i < s->rx_num_channels; i++) {
|
||||
if (i < s->iris[r]->getNumChannels(SOAPY_SDR_RX)) {
|
||||
s->iris[r]->setBandwidth(SOAPY_SDR_RX, i, rx_filt_bw);
|
||||
printf("Setting rx bandwidth on channel %lu/%lu : BW %f (readback %f)\n", i,
|
||||
printf("Setting rx bandwidth on channel %zu/%lu : BW %f (readback %f)\n", i,
|
||||
s->iris[r]->getNumChannels(SOAPY_SDR_RX), rx_filt_bw / 1e6,
|
||||
s->iris[r]->getBandwidth(SOAPY_SDR_RX, i) / 1e6);
|
||||
}
|
||||
@@ -776,7 +779,7 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
std::cout << "Front end detected: " << s->iris[r]->getHardwareInfo()["frontend"] << "\n";
|
||||
for (i = 0; i < s->rx_num_channels; i++) {
|
||||
if (i < s->iris[r]->getNumChannels(SOAPY_SDR_RX)) {
|
||||
printf("RX Channel %lu\n", i);
|
||||
printf("RX Channel %zu\n", i);
|
||||
printf("Actual RX sample rate: %fMSps...\n", (s->iris[r]->getSampleRate(SOAPY_SDR_RX, i) / 1e6));
|
||||
printf("Actual RX frequency: %fGHz...\n", (s->iris[r]->getFrequency(SOAPY_SDR_RX, i) / 1e9));
|
||||
printf("Actual RX gain: %f...\n", (s->iris[r]->getGain(SOAPY_SDR_RX, i)));
|
||||
@@ -794,7 +797,7 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
|
||||
for (i = 0; i < s->tx_num_channels; i++) {
|
||||
if (i < s->iris[r]->getNumChannels(SOAPY_SDR_TX)) {
|
||||
printf("TX Channel %lu\n", i);
|
||||
printf("TX Channel %zu\n", i);
|
||||
printf("Actual TX sample rate: %fMSps...\n", (s->iris[r]->getSampleRate(SOAPY_SDR_TX, i) / 1e6));
|
||||
printf("Actual TX frequency: %fGHz...\n", (s->iris[r]->getFrequency(SOAPY_SDR_TX, i) / 1e9));
|
||||
printf("Actual TX gain: %f...\n", (s->iris[r]->getGain(SOAPY_SDR_TX, i)));
|
||||
@@ -845,8 +848,3 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
}
|
||||
}
|
||||
/*@}*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
@@ -1,4 +0,0 @@
|
||||
USRP_OBJ += $(OPENAIR_TARGETS)/ARCH/USRP/USERSPACE/LIB/usrp_lib.o
|
||||
USRP_FILE_OBJ += $(OPENAIR_TARGETS)/ARCH/USRP/USERSPACE/LIB/usrp_lib.cpp
|
||||
USRP_CFLAGS += -I$(OPENAIR_TARGETS)/ARCH/COMMON -I$(OPENAIR_TARGETS)/ARCH/USRP/USERSPACE/LIB/ -I$(OPENAIR_TARGETS)/COMMON
|
||||
|
||||
@@ -28,7 +28,12 @@
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <uhd/version.hpp>
|
||||
#if UHD_VERSION < 3110000
|
||||
#include <uhd/utils/thread_priority.hpp>
|
||||
#else
|
||||
#include <uhd/utils/thread.hpp>
|
||||
#endif
|
||||
#include <uhd/usrp/multi_usrp.hpp>
|
||||
#include <uhd/version.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
@@ -183,7 +188,7 @@ static int sync_to_gps(openair0_device *device) {
|
||||
num_gps_locked++;
|
||||
std::cout << boost::format("GPS Locked\n");
|
||||
} else {
|
||||
std::cerr << "WARNING: GPS not locked - time will not be accurate until locked" << std::endl;
|
||||
LOG_W(HW,"WARNING: GPS not locked - time will not be accurate until locked\n");
|
||||
}
|
||||
|
||||
//Set to GPS time
|
||||
@@ -346,6 +351,7 @@ static void trx_usrp_end(openair0_device *device) {
|
||||
|
||||
done = 1;
|
||||
|
||||
|
||||
if (u_sf_mode != 2) { // not subframes replay
|
||||
#endif
|
||||
usrp_state_t *s = (usrp_state_t *)device->priv;
|
||||
@@ -435,17 +441,20 @@ static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp,
|
||||
#endif
|
||||
usrp_state_t *s = (usrp_state_t *)device->priv;
|
||||
int nsamps2; // aligned to upper 32 or 16 byte boundary
|
||||
|
||||
#if defined(__x86_64) || defined(__i386__)
|
||||
#ifdef __AVX2__
|
||||
nsamps2 = (nsamps+7)>>3;
|
||||
__m256i buff_tx[2][nsamps2];
|
||||
#else
|
||||
#ifdef __AVX2__
|
||||
nsamps2 = (nsamps+7)>>3;
|
||||
__m256i buff_tx[2][nsamps2];
|
||||
#else
|
||||
nsamps2 = (nsamps+3)>>2;
|
||||
__m128i buff_tx[2][nsamps2];
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(__arm__)
|
||||
nsamps2 = (nsamps+3)>>2;
|
||||
int16x8_t buff_tx[2][nsamps2];
|
||||
#else
|
||||
#error Unsupported CPU architecture, USRP device cannot be built
|
||||
#endif
|
||||
|
||||
// bring RX data into 12 LSBs for softmodem RX
|
||||
@@ -720,6 +729,7 @@ void *freq_thread(void *arg) {
|
||||
usrp_state_t *s = (usrp_state_t *)device->priv;
|
||||
s->usrp->set_tx_freq(device->openair0_cfg[0].tx_freq[0]);
|
||||
s->usrp->set_rx_freq(device->openair0_cfg[0].rx_freq[0]);
|
||||
return NULL;
|
||||
}
|
||||
/*! \brief Set frequencies (TX/RX). Spawns a thread to handle the frequency change to not block the calling thread
|
||||
* \param device the hardware to use
|
||||
@@ -1065,16 +1075,16 @@ extern "C" {
|
||||
uhd::device_addrs_t device_adds = uhd::device::find(args);
|
||||
|
||||
if (device_adds.size() == 0) {
|
||||
std::cerr<<"No USRP Device Found. " << std::endl;
|
||||
LOG_E(HW,"No USRP Device Found.\n ");
|
||||
free(s);
|
||||
return -1;
|
||||
} else if (device_adds.size() > 1) {
|
||||
std::cerr<<"More than one USRP Device Found. Please specify device more precisely in config file." << std::endl;
|
||||
LOG_E(HW,"More than one USRP Device Found. Please specify device more precisely in config file.\n");
|
||||
free(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::cerr << "Found USRP " << device_adds[0].get("type") << "\n";
|
||||
LOG_I(HW,"Found USRP %s\n", device_adds[0].get("type").c_str());
|
||||
double usrp_master_clock;
|
||||
|
||||
if (device_adds[0].get("type") == "b200") {
|
||||
@@ -1082,7 +1092,7 @@ extern "C" {
|
||||
device->type = USRP_B200_DEV;
|
||||
usrp_master_clock = 30.72e6;
|
||||
args += boost::str(boost::format(",master_clock_rate=%f") % usrp_master_clock);
|
||||
args += ",num_send_frames=256,num_recv_frames=256, send_frame_size=15360, recv_frame_size=15360" ;
|
||||
args += ",num_send_frames=256,num_recv_frames=256, send_frame_size=7680, recv_frame_size=7680" ;
|
||||
}
|
||||
if (device_adds[0].get("type") == "n3xx") {
|
||||
printf("Found USRP n300\n");
|
||||
@@ -1281,8 +1291,9 @@ extern "C" {
|
||||
samples/=10000;
|
||||
LOG_I(PHY,"RF board max packet size %u, size for 100µs jitter %d \n", max, samples);
|
||||
|
||||
if ( samples < max )
|
||||
if ( samples < max ) {
|
||||
stream_args_rx.args["spp"] = str(boost::format("%d") % samples );
|
||||
}
|
||||
|
||||
LOG_I(PHY,"rx_max_num_samps %zu\n",
|
||||
s->usrp->get_rx_stream(stream_args_rx)->get_max_num_samps());
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
## General
|
||||
|
||||
This is a RF simulator that allows to test OAI without a RF board.
|
||||
It replaces a actual RF board driver.
|
||||
|
||||
As much as possible, it works like a RF board, but not in realtime: it can run faster than realtime if there is enough CPU or slower (it is CPU bound instead of real time RF sampling bound)
|
||||
|
||||
## build
|
||||
|
||||
No specific build is required, use the [oai softmodem build procedure](../../../doc/BUILD.md)
|
||||
|
||||
After any regular build, you can compile the driver
|
||||
```bash
|
||||
cd <the_compilation_dir_from_bouild_oai_script>/build
|
||||
make rfsimulator
|
||||
```
|
||||
Then, you can use it freely
|
||||
|
||||
# Usage
|
||||
Setting the env variable RFSIMULATOR enables the RF board simulator
|
||||
It should the set to "enb" in the eNB
|
||||
|
||||
## 4G case
|
||||
For the UE, it should be set to the IP address of the eNB
|
||||
example:
|
||||
|
||||
```bash
|
||||
sudo RFSIMULATOR=192.168.2.200 ./lte-uesoftmodem -C 2685000000 -r 50 --rfsim
|
||||
```
|
||||
For the eNodeB, use a valid configuration file setup for USRP board tests and start the softmodem as usual, but adding the `--rfsim` option.
|
||||
|
||||
|
||||
|
||||
```bash
|
||||
sudo RFSIMULATOR=enb ./lte-softmodem -O <config file> --rfsim
|
||||
```
|
||||
|
||||
|
||||
|
||||
Except this, the UE and the eNB can be used as it the RF is real
|
||||
|
||||
If you reach 'RA not active' on UE, be careful to generate a valid SIM
|
||||
```bash
|
||||
$OPENAIR_DIR/targets/bin/conf2uedata -c $OPENAIR_DIR/openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf -o .
|
||||
```
|
||||
This simulator can also be used with the `--noS1` option, in this case you must run the eNodeB and the UE on different PCs.
|
||||
|
||||
## 5G case
|
||||
|
||||
After regular build, add the simulation driver
|
||||
(don't use ./build_oai -w SIMU until we merge 4G and 5G branches)
|
||||
```bash
|
||||
cd ran_build/build
|
||||
make rfsimulator
|
||||
```
|
||||
### Launch gNB in one window
|
||||
```bash
|
||||
sudo RFSIMULATOR=enb ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf --parallel-config PARALLEL_SINGLE_THREAD
|
||||
```
|
||||
### Launch UE in another window
|
||||
```bash
|
||||
sudo RFSIMULATOR=127.0.0.1 ./nr-uesoftmodem --numerology 1 -r 106 -C 3510000000
|
||||
```
|
||||
Of course, set the gNB machine IP address if the UE and the gNB are not on the same machine
|
||||
In UE, you can add "-d" to get the softscope
|
||||
|
||||
## Caveacts
|
||||
|
||||
Still issues in power control: txgain, rxgain are not used
|
||||
|
||||
|
||||
@@ -0,0 +1,475 @@
|
||||
/*
|
||||
Author: Laurent THOMAS, Open Cells for Nokia
|
||||
copyleft: OpenAirInterface Software Alliance and it's licence
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <common/utils/assertions.h>
|
||||
#include <common/utils/LOG/log.h>
|
||||
#include "common_lib.h"
|
||||
#include <openair1/PHY/defs_eNB.h>
|
||||
#include "openair1/PHY/defs_UE.h"
|
||||
|
||||
#define PORT 4043 //TCP port for this simulator
|
||||
#define CirSize 3072000 // 100ms is enough
|
||||
#define sample_t uint32_t // 2*16 bits complex number
|
||||
#define sampleToByte(a,b) ((a)*(b)*sizeof(sample_t))
|
||||
#define byteToSample(a,b) ((a)/(sizeof(sample_t)*(b)))
|
||||
#define MAGICeNB 0xA5A5A5A5A5A5A5A5
|
||||
#define MAGICUE 0x5A5A5A5A5A5A5A5A
|
||||
|
||||
typedef struct {
|
||||
uint64_t magic;
|
||||
uint32_t size;
|
||||
uint32_t nbAnt;
|
||||
uint64_t timestamp;
|
||||
} transferHeader;
|
||||
|
||||
typedef struct buffer_s {
|
||||
int conn_sock;
|
||||
bool alreadyRead;
|
||||
uint64_t lastReceivedTS;
|
||||
bool headerMode;
|
||||
transferHeader th;
|
||||
char *transferPtr;
|
||||
uint64_t remainToTransfer;
|
||||
char *circularBufEnd;
|
||||
sample_t *circularBuf;
|
||||
} buffer_t;
|
||||
|
||||
typedef struct {
|
||||
int listen_sock, epollfd;
|
||||
uint64_t nextTimestamp;
|
||||
uint64_t typeStamp;
|
||||
uint64_t initialAhead;
|
||||
char *ip;
|
||||
buffer_t buf[FD_SETSIZE];
|
||||
} rfsimulator_state_t;
|
||||
|
||||
void allocCirBuf(rfsimulator_state_t *bridge, int sock) {
|
||||
buffer_t *ptr=&bridge->buf[sock];
|
||||
AssertFatal ( (ptr->circularBuf=(sample_t *) malloc(sampleToByte(CirSize,1))) != NULL, "");
|
||||
ptr->circularBufEnd=((char *)ptr->circularBuf)+sampleToByte(CirSize,1);
|
||||
ptr->conn_sock=sock;
|
||||
ptr->headerMode=true;
|
||||
ptr->transferPtr=(char *)&ptr->th;
|
||||
ptr->remainToTransfer=sizeof(transferHeader);
|
||||
int sendbuff=1000*1000*10;
|
||||
AssertFatal ( setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff)) == 0, "");
|
||||
struct epoll_event ev= {0};
|
||||
ev.events = EPOLLIN | EPOLLRDHUP;
|
||||
ev.data.fd = sock;
|
||||
AssertFatal(epoll_ctl(bridge->epollfd, EPOLL_CTL_ADD, sock, &ev) != -1, "");
|
||||
}
|
||||
|
||||
void removeCirBuf(rfsimulator_state_t *bridge, int sock) {
|
||||
AssertFatal( epoll_ctl(bridge->epollfd, EPOLL_CTL_DEL, sock, NULL) != -1, "");
|
||||
close(sock);
|
||||
free(bridge->buf[sock].circularBuf);
|
||||
memset(&bridge->buf[sock], 0, sizeof(buffer_t));
|
||||
bridge->buf[sock].conn_sock=-1;
|
||||
}
|
||||
|
||||
void socketError(rfsimulator_state_t *bridge, int sock) {
|
||||
if (bridge->buf[sock].conn_sock!=-1) {
|
||||
LOG_W(HW,"Lost socket \n");
|
||||
removeCirBuf(bridge, sock);
|
||||
|
||||
if (bridge->typeStamp==MAGICUE)
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define helpTxt "\
|
||||
\x1b[31m\
|
||||
rfsimulator: error: you have to run one UE and one eNB\n\
|
||||
For this, export RFSIMULATOR=enb (eNB case) or \n\
|
||||
RFSIMULATOR=<an ip address> (UE case)\n\
|
||||
\x1b[m"
|
||||
|
||||
enum blocking_t {
|
||||
notBlocking,
|
||||
blocking
|
||||
};
|
||||
|
||||
void setblocking(int sock, enum blocking_t active) {
|
||||
int opts;
|
||||
AssertFatal( (opts = fcntl(sock, F_GETFL)) >= 0,"");
|
||||
|
||||
if (active==blocking)
|
||||
opts = opts & ~O_NONBLOCK;
|
||||
else
|
||||
opts = opts | O_NONBLOCK;
|
||||
|
||||
AssertFatal(fcntl(sock, F_SETFL, opts) >= 0, "");
|
||||
}
|
||||
|
||||
static bool flushInput(rfsimulator_state_t *t);
|
||||
|
||||
void fullwrite(int fd, void *_buf, int count, rfsimulator_state_t *t) {
|
||||
char *buf = _buf;
|
||||
int l;
|
||||
setblocking(fd, notBlocking);
|
||||
|
||||
while (count) {
|
||||
l = write(fd, buf, count);
|
||||
|
||||
if (l <= 0) {
|
||||
if (errno==EINTR)
|
||||
continue;
|
||||
|
||||
if(errno==EAGAIN) {
|
||||
flushInput(t);
|
||||
continue;
|
||||
} else
|
||||
return;
|
||||
}
|
||||
|
||||
count -= l;
|
||||
buf += l;
|
||||
}
|
||||
}
|
||||
|
||||
int server_start(openair0_device *device) {
|
||||
rfsimulator_state_t *t = (rfsimulator_state_t *) device->priv;
|
||||
t->typeStamp=MAGICeNB;
|
||||
AssertFatal((t->listen_sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0, "");
|
||||
int enable = 1;
|
||||
AssertFatal(setsockopt(t->listen_sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) == 0, "");
|
||||
struct sockaddr_in addr = {
|
||||
sin_family:
|
||||
AF_INET,
|
||||
sin_port:
|
||||
htons(PORT),
|
||||
sin_addr:
|
||||
{ s_addr: INADDR_ANY }
|
||||
};
|
||||
bind(t->listen_sock, (struct sockaddr *)&addr, sizeof(addr));
|
||||
AssertFatal(listen(t->listen_sock, 5) == 0, "");
|
||||
struct epoll_event ev;
|
||||
ev.events = EPOLLIN;
|
||||
ev.data.fd = t->listen_sock;
|
||||
AssertFatal(epoll_ctl(t->epollfd, EPOLL_CTL_ADD, t->listen_sock, &ev) != -1, "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int start_ue(openair0_device *device) {
|
||||
rfsimulator_state_t *t = device->priv;
|
||||
t->typeStamp=MAGICUE;
|
||||
int sock;
|
||||
AssertFatal((sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0, "");
|
||||
struct sockaddr_in addr = {
|
||||
sin_family:
|
||||
AF_INET,
|
||||
sin_port:
|
||||
htons(PORT),
|
||||
sin_addr:
|
||||
{ s_addr: INADDR_ANY }
|
||||
};
|
||||
addr.sin_addr.s_addr = inet_addr(t->ip);
|
||||
bool connected=false;
|
||||
|
||||
while(!connected) {
|
||||
LOG_I(HW,"rfsimulator: trying to connect to %s:%d\n", t->ip, PORT);
|
||||
|
||||
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
|
||||
LOG_I(HW,"rfsimulator: connection established\n");
|
||||
connected=true;
|
||||
}
|
||||
|
||||
perror("rfsimulator");
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
setblocking(sock, notBlocking);
|
||||
allocCirBuf(t, sock);
|
||||
t->buf[sock].alreadyRead=true; // UE will start blocking on read
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) {
|
||||
rfsimulator_state_t *t = device->priv;
|
||||
|
||||
for (int i=0; i<FD_SETSIZE; i++) {
|
||||
buffer_t *ptr=&t->buf[i];
|
||||
|
||||
if (ptr->conn_sock >= 0 ) {
|
||||
transferHeader header= {t->typeStamp, nsamps, nbAnt, timestamp};
|
||||
fullwrite(ptr->conn_sock,&header, sizeof(header), t);
|
||||
sample_t tmpSamples[nsamps][nbAnt];
|
||||
|
||||
for(int a=0; a<nbAnt; a++) {
|
||||
sample_t *in=(sample_t *)samplesVoid[a];
|
||||
|
||||
for(int s=0; s<nsamps; s++)
|
||||
tmpSamples[s][a]=in[s];
|
||||
}
|
||||
|
||||
if (ptr->conn_sock >= 0 )
|
||||
fullwrite(ptr->conn_sock, (void *)tmpSamples, sampleToByte(nsamps,nbAnt), t);
|
||||
}
|
||||
}
|
||||
|
||||
LOG_D(HW,"sent %d samples at time: %ld->%ld, energy in first antenna: %d\n",
|
||||
nsamps, timestamp, timestamp+nsamps, signal_energy(samplesVoid[0], nsamps) );
|
||||
return nsamps;
|
||||
}
|
||||
|
||||
static bool flushInput(rfsimulator_state_t *t) {
|
||||
// Process all incoming events on sockets
|
||||
// store the data in lists
|
||||
struct epoll_event events[FD_SETSIZE]= {0};
|
||||
int nfds = epoll_wait(t->epollfd, events, FD_SETSIZE, 200);
|
||||
|
||||
if ( nfds==-1 ) {
|
||||
if ( errno==EINTR || errno==EAGAIN )
|
||||
return false;
|
||||
else
|
||||
AssertFatal(false,"error in epoll_wait\n");
|
||||
}
|
||||
|
||||
for (int nbEv = 0; nbEv < nfds; ++nbEv) {
|
||||
int fd=events[nbEv].data.fd;
|
||||
|
||||
if (events[nbEv].events & EPOLLIN && fd == t->listen_sock) {
|
||||
int conn_sock;
|
||||
AssertFatal( (conn_sock = accept(t->listen_sock,NULL,NULL)) != -1, "");
|
||||
setblocking(conn_sock, notBlocking);
|
||||
allocCirBuf(t, conn_sock);
|
||||
LOG_I(HW,"A ue connected\n");
|
||||
} else {
|
||||
if ( events[nbEv].events & (EPOLLHUP | EPOLLERR | EPOLLRDHUP) ) {
|
||||
socketError(t,fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer_t *b=&t->buf[fd];
|
||||
|
||||
if ( b->circularBuf == NULL ) {
|
||||
LOG_E(HW, "received data on not connected socket %d\n", events[nbEv].data.fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
int blockSz;
|
||||
|
||||
if ( b->headerMode)
|
||||
blockSz=b->remainToTransfer;
|
||||
else
|
||||
blockSz= b->transferPtr+b->remainToTransfer < b->circularBufEnd ?
|
||||
b->remainToTransfer :
|
||||
b->circularBufEnd - 1 - b->transferPtr ;
|
||||
|
||||
int sz=recv(fd, b->transferPtr, blockSz, MSG_DONTWAIT);
|
||||
|
||||
if ( sz < 0 ) {
|
||||
if ( errno != EAGAIN ) {
|
||||
LOG_E(HW,"socket failed %s\n", strerror(errno));
|
||||
abort();
|
||||
}
|
||||
} else if ( sz == 0 )
|
||||
continue;
|
||||
|
||||
AssertFatal((b->remainToTransfer-=sz) >= 0, "");
|
||||
b->transferPtr+=sz;
|
||||
|
||||
if (b->transferPtr==b->circularBufEnd - 1)
|
||||
b->transferPtr=(char *)b->circularBuf;
|
||||
|
||||
// check the header and start block transfer
|
||||
if ( b->headerMode==true && b->remainToTransfer==0) {
|
||||
AssertFatal( (t->typeStamp == MAGICUE && b->th.magic==MAGICeNB) ||
|
||||
(t->typeStamp == MAGICeNB && b->th.magic==MAGICUE), "Socket Error in protocol");
|
||||
b->headerMode=false;
|
||||
b->alreadyRead=true;
|
||||
|
||||
if ( b->lastReceivedTS != b->th.timestamp) {
|
||||
int nbAnt= b->th.nbAnt;
|
||||
|
||||
for (uint64_t index=b->lastReceivedTS; index < b->th.timestamp; index++ )
|
||||
for (int a=0; a < nbAnt; a++)
|
||||
b->circularBuf[(index*nbAnt+a)%CirSize]=0;
|
||||
|
||||
LOG_W(HW,"gap of: %ld in reception\n", b->th.timestamp-b->lastReceivedTS );
|
||||
}
|
||||
|
||||
b->lastReceivedTS=b->th.timestamp;
|
||||
b->transferPtr=(char *)&b->circularBuf[b->lastReceivedTS%CirSize];
|
||||
b->remainToTransfer=sampleToByte(b->th.size, b->th.nbAnt);
|
||||
}
|
||||
|
||||
if ( b->headerMode==false ) {
|
||||
b->lastReceivedTS=b->th.timestamp+b->th.size-byteToSample(b->remainToTransfer,b->th.nbAnt);
|
||||
|
||||
if ( b->remainToTransfer==0) {
|
||||
LOG_D(HW,"Completed block reception: %ld\n", b->lastReceivedTS);
|
||||
|
||||
// First block in UE, resync with the eNB current TS
|
||||
if ( t->nextTimestamp == 0 )
|
||||
t->nextTimestamp=b->lastReceivedTS-b->th.size;
|
||||
|
||||
b->headerMode=true;
|
||||
b->transferPtr=(char *)&b->th;
|
||||
b->remainToTransfer=sizeof(transferHeader);
|
||||
b->th.magic=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nfds>0;
|
||||
}
|
||||
|
||||
int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, void **samplesVoid, int nsamps, int nbAnt) {
|
||||
if (nbAnt != 1) {
|
||||
LOG_E(HW, "rfsimulator: only 1 antenna tested\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
rfsimulator_state_t *t = device->priv;
|
||||
LOG_D(HW, "Enter rfsimulator_read, expect %d samples, will release at TS: %ld\n", nsamps, t->nextTimestamp+nsamps);
|
||||
// deliver data from received data
|
||||
// check if a UE is connected
|
||||
int first_sock;
|
||||
|
||||
for (first_sock=0; first_sock<FD_SETSIZE; first_sock++)
|
||||
if (t->buf[first_sock].circularBuf != NULL )
|
||||
break;
|
||||
|
||||
if ( first_sock == FD_SETSIZE ) {
|
||||
// no connected device (we are eNB, no UE is connected)
|
||||
if (!flushInput(t)) {
|
||||
for (int x=0; x < nbAnt; x++)
|
||||
memset(samplesVoid[x],0,sampleToByte(nsamps,1));
|
||||
|
||||
t->nextTimestamp+=nsamps;
|
||||
LOG_W(HW,"Generated void samples for Rx: %ld\n", t->nextTimestamp);
|
||||
*ptimestamp = t->nextTimestamp-nsamps;
|
||||
return nsamps;
|
||||
}
|
||||
} else {
|
||||
bool have_to_wait;
|
||||
|
||||
do {
|
||||
have_to_wait=false;
|
||||
|
||||
for ( int sock=0; sock<FD_SETSIZE; sock++)
|
||||
if ( t->buf[sock].circularBuf &&
|
||||
t->buf[sock].alreadyRead && //>= t->initialAhead &&
|
||||
(t->nextTimestamp+nsamps) > t->buf[sock].lastReceivedTS ) {
|
||||
have_to_wait=true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (have_to_wait)
|
||||
/*printf("Waiting on socket, current last ts: %ld, expected at least : %ld\n",
|
||||
ptr->lastReceivedTS,
|
||||
t->nextTimestamp+nsamps);
|
||||
*/
|
||||
flushInput(t);
|
||||
} while (have_to_wait);
|
||||
}
|
||||
|
||||
// Clear the output buffer
|
||||
for (int a=0; a<nbAnt; a++)
|
||||
memset(samplesVoid[a],0,sampleToByte(nsamps,1));
|
||||
|
||||
// Add all input signal in the output buffer
|
||||
for (int sock=0; sock<FD_SETSIZE; sock++) {
|
||||
buffer_t *ptr=&t->buf[sock];
|
||||
|
||||
if ( ptr->circularBuf && ptr->alreadyRead ) {
|
||||
for (int a=0; a<nbAnt; a++) {
|
||||
sample_t *out=(sample_t *)samplesVoid[a];
|
||||
|
||||
for ( int i=0; i < nsamps; i++ )
|
||||
out[i]+=ptr->circularBuf[((t->nextTimestamp+i)*nbAnt+a)%CirSize]<<1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*ptimestamp = t->nextTimestamp; // return the time of the first sample
|
||||
t->nextTimestamp+=nsamps;
|
||||
LOG_D(HW,"Rx to upper layer: %d from %ld to %ld, energy in first antenna %d\n",
|
||||
nsamps,
|
||||
*ptimestamp, t->nextTimestamp,
|
||||
signal_energy(samplesVoid[0], nsamps));
|
||||
return nsamps;
|
||||
}
|
||||
|
||||
|
||||
int rfsimulator_request(openair0_device *device, void *msg, ssize_t msg_len) {
|
||||
abort();
|
||||
return 0;
|
||||
}
|
||||
int rfsimulator_reply(openair0_device *device, void *msg, ssize_t msg_len) {
|
||||
abort();
|
||||
return 0;
|
||||
}
|
||||
int rfsimulator_get_stats(openair0_device *device) {
|
||||
return 0;
|
||||
}
|
||||
int rfsimulator_reset_stats(openair0_device *device) {
|
||||
return 0;
|
||||
}
|
||||
void rfsimulator_end(openair0_device *device) {}
|
||||
int rfsimulator_stop(openair0_device *device) {
|
||||
return 0;
|
||||
}
|
||||
int rfsimulator_set_freq(openair0_device *device, openair0_config_t *openair0_cfg,int exmimo_dump_config) {
|
||||
return 0;
|
||||
}
|
||||
int rfsimulator_set_gains(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
__attribute__((__visibility__("default")))
|
||||
int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
//set_log(HW,OAILOG_DEBUG);
|
||||
rfsimulator_state_t *rfsimulator = (rfsimulator_state_t *)calloc(sizeof(rfsimulator_state_t),1);
|
||||
|
||||
if ((rfsimulator->ip=getenv("RFSIMULATOR")) == NULL ) {
|
||||
LOG_E(HW,helpTxt);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
rfsimulator->typeStamp = strncasecmp(rfsimulator->ip,"enb",3) == 0 ?
|
||||
MAGICeNB:
|
||||
MAGICUE;
|
||||
LOG_I(HW,"rfsimulator: running as %s\n", rfsimulator-> typeStamp == MAGICeNB ? "eNB" : "UE");
|
||||
device->trx_start_func = rfsimulator->typeStamp == MAGICeNB ?
|
||||
server_start :
|
||||
start_ue;
|
||||
device->trx_get_stats_func = rfsimulator_get_stats;
|
||||
device->trx_reset_stats_func = rfsimulator_reset_stats;
|
||||
device->trx_end_func = rfsimulator_end;
|
||||
device->trx_stop_func = rfsimulator_stop;
|
||||
device->trx_set_freq_func = rfsimulator_set_freq;
|
||||
device->trx_set_gains_func = rfsimulator_set_gains;
|
||||
device->trx_write_func = rfsimulator_write;
|
||||
device->trx_read_func = rfsimulator_read;
|
||||
/* let's pretend to be a b2x0 */
|
||||
device->type = USRP_B200_DEV;
|
||||
device->openair0_cfg=&openair0_cfg[0];
|
||||
device->priv = rfsimulator;
|
||||
|
||||
for (int i=0; i<FD_SETSIZE; i++)
|
||||
rfsimulator->buf[i].conn_sock=-1;
|
||||
|
||||
AssertFatal((rfsimulator->epollfd = epoll_create1(0)) != -1,"");
|
||||
rfsimulator->initialAhead=openair0_cfg[0].sample_rate/1000; // One sub frame
|
||||
return 0;
|
||||
}
|
||||
@@ -354,6 +354,29 @@ int tcp_bridge_ue_first_read(openair0_device *device, openair0_timestamp *timest
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Due to some unknown bug in the eNB (or UE, or both), the first frames
|
||||
* are not correctly generated (or handled), which leads to a bad behavior
|
||||
* of the simulator in some cases (seen with 100 RBs: the UE reads a bad
|
||||
* MIB and switches to 25 RBs, which results in a deadlock in this driver).
|
||||
* Let's skip 10 frames to avoid this issue.
|
||||
*/
|
||||
for (int i = 0; i < 10 * 10; i++) {
|
||||
memset(b, 0, t->samples_per_subframe * 4);
|
||||
n = fullwrite(t->sock, b, t->samples_per_subframe * 4);
|
||||
|
||||
if (n != t->samples_per_subframe * 4) {
|
||||
printf("tcp_bridge: write error ret %d error %s\n", n, strerror(errno));
|
||||
abort();
|
||||
}
|
||||
|
||||
n = fullread(t->sock, b, t->samples_per_subframe * 4);
|
||||
|
||||
if (n != t->samples_per_subframe * 4) {
|
||||
printf("tcp_bridge: read error ret %d error %s\n", n, strerror(errno));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
device->trx_read_func = tcp_bridge_read_ue;
|
||||
return tcp_bridge_read_ue(device, timestamp, buff, nsamps, cc);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user