Commit f3d31d92 authored by Your Name's avatar Your Name

Initial commit

parents
/*
* 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
*/
#ifndef __COMMON_UTILS_ASSERTIONS__H__
#define __COMMON_UTILS_ASSERTIONS__H__
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <sys/types.h>
#include <unistd.h>
#include "platform_types.h"
#include "backtrace.h"
#define _Assert_Exit_ \
if (getenv("gdbStacks")) { \
char tmp [1000]; \
sprintf(tmp,"gdb -ex='set confirm off' -ex 'thread apply all bt' -ex q -p %d < /dev/null", getpid()); \
__attribute__((unused)) int dummy=system(tmp); \
} \
fprintf(stderr, "\nExiting execution\n"); \
fflush(stdout); \
fflush(stderr); \
abort();
#define _Assert_(cOND, aCTION, fORMAT, aRGS...) \
do { \
if (!(cOND)) { \
fprintf(stderr, "\nAssertion (%s) failed!\n" \
"In %s() %s:%d\n" fORMAT, \
#cOND, __FUNCTION__, __FILE__, __LINE__, ##aRGS); \
aCTION; \
} \
} while(0)
#define AssertFatal(cOND, fORMAT, aRGS...) _Assert_(cOND, _Assert_Exit_, fORMAT, ##aRGS)
#define AssertError(cOND, aCTION, fORMAT, aRGS...) _Assert_(cOND, aCTION, fORMAT, ##aRGS)
#define DevCheck(cOND, vALUE1, vALUE2, vALUE3) \
_Assert_(cOND, _Assert_Exit_, #vALUE1 ": %" PRIdMAX "\n" #vALUE2 ": %" PRIdMAX "\n" #vALUE3 ": %" PRIdMAX "\n\n", \
(intmax_t)vALUE1, (intmax_t)vALUE2, (intmax_t)vALUE3)
#define DevCheck4(cOND, vALUE1, vALUE2, vALUE3, vALUE4) \
_Assert_(cOND, _Assert_Exit_, #vALUE1": %" PRIdMAX "\n" #vALUE2 ": %" PRIdMAX "\n" #vALUE3 ": %" PRIdMAX "\n" #vALUE4 ": %" PRIdMAX "\n\n", \
(intmax_t)vALUE1, (intmax_t)vALUE2, (intmax_t)vALUE3, (intmax_t)vALUE4)
#define DevParam(vALUE1, vALUE2, vALUE3) DevCheck(0, vALUE1, vALUE2, vALUE3)
#define DevAssert(cOND) _Assert_(cOND, _Assert_Exit_, "")
#define DevMessage(mESSAGE) _Assert_(0, _Assert_Exit_, #mESSAGE)
#define CHECK_INIT_RETURN(fCT) \
do { \
int fct_ret; \
if ((fct_ret = (fCT)) != 0) { \
fprintf(stderr, "Function "#fCT" has failed\n" \
"returning %d\n", fct_ret); \
fflush(stdout); \
fflush(stderr); \
exit(EXIT_FAILURE); \
} \
} while(0)
#endif /* __COMMON_UTILS_ASSERTIONS__H__ */
/*
* 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 common_lib.c
* \brief common APIs for different RF frontend device
* \author HongliangXU, Navid Nikaein
* \date 2015
* \version 0.2
* \company Eurecom
* \maintainer: navid.nikaein@eurecom.fr
* \note
* \warning
*/
#include <stdio.h>
#include <strings.h>
#include <dlfcn.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include "common_lib.h"
#include "assertions.h"
#include "load_module_shlib.h"
const char* devtype_names[MAX_RF_DEV_TYPE] = {
"",
"EXMIMO",
"USRP B200",
"USRP X300",
"USRP N300",
"USRP X400",
"BLADERF",
"YunSDR",
"LMSSDR",
"IRIS",
"No HW",
"ADRV9371_ZC706",
"UEDv2",
"RFSIMULATOR"
};
const char *get_devname(int devtype) {
if (devtype < MAX_RF_DEV_TYPE && devtype !=MIN_RF_DEV_TYPE )
return devtype_names[devtype];
return "none";
}
int set_device(openair0_device *device)
{
const char *devname = get_devname(device->type);
if (strcmp(devname,"none") != 0) {
LOG_I(HW,"[%s] has loaded %s device.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"),devname);
} else {
LOG_E(HW,"[%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:
LOG_I(HW,"[%s] has loaded ETHERNET trasport protocol.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
return 0;
break;
case NONE_TP:
LOG_I(HW,"[%s] has not loaded a transport protocol.\n",((device->host_type == RAU_HOST) ? "RAU": "RRU"));
return 0;
break;
default:
LOG_E(HW,"[%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)
{
loader_shlibfunc_t shlib_fdesc[1];
int ret=0;
char *deflibname=OAI_RF_LIBNAME;
openair0_cfg->recplay_mode = read_recplayconfig(&(openair0_cfg->recplay_conf),&(device->recplay_state));
if ( openair0_cfg->recplay_mode == RECPLAY_REPLAYMODE ) {
deflibname=OAI_IQPLAYER_LIBNAME;
shlib_fdesc[0].fname="device_init";
set_softmodem_optmask(SOFTMODEM_RECPLAY_BIT); // softmodem has to know we use the iqplayer to workaround randomized algorithms
} else if (IS_SOFTMODEM_RFSIM && flag == RAU_LOCAL_RADIO_HEAD) {
deflibname=OAI_RFSIM_LIBNAME;
shlib_fdesc[0].fname="device_init";
} else if (flag == RAU_LOCAL_RADIO_HEAD) {
if (IS_SOFTMODEM_RFSIM)
deflibname="rfsimulator";
else
deflibname=OAI_RF_LIBNAME;
shlib_fdesc[0].fname="device_init";
} else if (flag == RAU_REMOTE_THIRDPARTY_RADIO_HEAD) {
deflibname=OAI_THIRDPARTY_TP_LIBNAME;
shlib_fdesc[0].fname="transport_init";
} else {
deflibname=OAI_TP_LIBNAME;
shlib_fdesc[0].fname="transport_init";
}
char *devname=NULL;
paramdef_t device_params[]=DEVICE_PARAMS_DESC ;
int numparams = sizeof(device_params)/sizeof(paramdef_t);
int devname_pidx = config_paramidx_fromname(device_params,numparams, CONFIG_DEVICEOPT_NAME);
device_params[devname_pidx].defstrval=deflibname;
config_get(device_params,numparams,DEVICE_SECTION);
ret=load_module_shlib(devname,shlib_fdesc,1,NULL);
AssertFatal( (ret >= 0),
"Library %s couldn't be loaded\n",devname);
return ((devfunc_t)shlib_fdesc[0].fptr)(device,openair0_cfg,cfg);
}
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) {
LOG_E(HW, "%s %d:Unsupported radio head\n", __FILE__, __LINE__);
return -1;
}
} else
AssertFatal(false, "can't open the radio device: %s\n", get_devname(device->type));
return rc;
}
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 ( set_transport(device) < 0) {
LOG_E(HW, "%s %d:Unsupported transport protocol\n", __FILE__, __LINE__);
return -1;
}
}
return rc;
}
/*
* 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 common_lib.h
* \brief common APIs for different RF frontend device
* \author HongliangXU, Navid Nikaein
* \date 2015
* \version 0.2
* \company Eurecom
* \maintainer: navid.nikaein@eurecom.fr
* \note
* \warning
*/
#ifndef COMMON_LIB_H
#define COMMON_LIB_H
#include <stdint.h>
#include <stdio.h>
#include <sys/types.h>
//#include <openair1/PHY/TOOLS/tools_defs.h>
//#include "record_player.h"
/* default name of shared library implementing the radio front end */
#define OAI_RF_LIBNAME "oai_device"
/* name of shared library implementing the transport */
#define OAI_TP_LIBNAME "oai_transpro"
/* name of shared library implementing a third-party transport */
#define OAI_THIRDPARTY_TP_LIBNAME "thirdparty_transpro"
/* name of shared library implementing the rf simulator */
#define OAI_RFSIM_LIBNAME "rfsimulator"
/* name of shared library implementing the iq player */
/* 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
#define RAU_REMOTE_THIRDPARTY_RADIO_HEAD 2
#define MAX_WRITE_THREAD_PACKAGE 10
#define MAX_WRITE_THREAD_BUFFER_SIZE 8
#define MAX_CARDS 8
typedef int64_t openair0_timestamp;
typedef volatile int64_t openair0_vtimestamp;
/*!\brief structure holds the parameters to configure USRP devices*/
typedef struct openair0_device_t openair0_device;
//#define USRP_GAIN_OFFSET (56.0) // 86 calibrated for USRP B210 @ 2.6 GHz to get equivalent RS EPRE in OAI to SMBV100 output
typedef enum {
max_gain=0,med_gain,byp_gain
} rx_gain_t;
typedef enum {
duplex_mode_TDD=1,duplex_mode_FDD=0
} duplex_mode_t;
/** @addtogroup _GENERIC_PHY_RF_INTERFACE_
* @{
*/
/*!\brief RF device types
*/
typedef enum {
MIN_RF_DEV_TYPE = 0,
/*!\brief device is ExpressMIMO */
EXMIMO_DEV,
/*!\brief device is USRP B200/B210*/
USRP_B200_DEV,
/*!\brief device is USRP X300/X310*/
USRP_X300_DEV,
/*!\brief device is USRP N300/N310*/
USRP_N300_DEV,
/*!\brief device is USRP X400/X410*/
USRP_X400_DEV,
/*!\brief device is BLADE RF*/
BLADERF_DEV,
/*!\brief device is YUNSDR pcie*/
YUNSDR_DEV,
/*!\brief device is LMSSDR (SoDeRa)*/
LMSSDR_DEV,
/*!\brief device is Iris */
IRIS_DEV,
/*!\brief device is NONE*/
NONE_DEV,
/*!\brief device is ADRV9371_ZC706 */
ADRV9371_ZC706_DEV,
/*!\brief device is UEDv2 */
UEDv2_DEV,
RFSIMULATOR,
MAX_RF_DEV_TYPE
} dev_type_t;
/* list of names of devices, needs to match dev_type_t */
extern const char* devtype_names[MAX_RF_DEV_TYPE];
/*!\brief transport protocol types
*/
typedef enum {
MIN_TRANSP_TYPE = 0,
/*!\brief transport protocol ETHERNET */
ETHERNET_TP,
/*!\brief no transport protocol*/
NONE_TP,
MAX_TRANSP_TYPE
} transport_type_t;
/*!\brief openair0 device host type */
typedef enum {
MIN_HOST_TYPE = 0,
/*!\brief device functions within a RAU */
RAU_HOST,
/*!\brief device functions within a RRU */
RRU_HOST,
MAX_HOST_TYPE
} host_type_t;
/*! \brief RF Gain clibration */
typedef struct {
//! Frequency for which RX chain was calibrated
double freq;
//! Offset to be applied to RX gain
double offset;
} rx_gain_calib_table_t;
/*! \brief Clock source types */
typedef enum {
//! this means the paramter has not been set
unset=-1,
//! This tells the underlying hardware to use the internal reference
internal=0,
//! This tells the underlying hardware to use the external reference
external=1,
//! This tells the underlying hardware to use the gpsdo reference
gpsdo=2
} clock_source_t;
/*! \brief RF frontend parameters set by application */
typedef struct {
//! Module ID for this configuration
int Mod_id;
//! device log level
int log_level;
//! duplexing mode
duplex_mode_t duplex_mode;
//! number of downlink resource blocks
int num_rb_dl;
//! number of samples per frame
unsigned int samples_per_frame;
//! the sample rate for both transmit and receive.
double sample_rate;
//! flag to indicate that the device is doing mmapped DMA transfers
int mmapped_dma;
//! offset in samples between TX and RX paths
int tx_sample_advance;
//! samples per packet on the fronthaul interface
int samples_per_packet;
//! number of RX channels (=RX antennas)
int rx_num_channels;
//! number of TX channels (=TX antennas)
int tx_num_channels;
//! \brief RX base addresses for mmapped_dma
int32_t *rxbase[4];
//! \brief TX base addresses for mmapped_dma
int32_t *txbase[4];
//! \brief Center frequency in Hz for RX.
//! index: [0..rx_num_channels[
double rx_freq[4];
//! \brief Center frequency in Hz for TX.
//! index: [0..rx_num_channels[ !!! see lte-ue.c:427 FIXME iterates over rx_num_channels
double tx_freq[4];
double tune_offset;
//! \brief memory
//! \brief Pointer to Calibration table for RX gains
rx_gain_calib_table_t *rx_gain_calib_table;
//! mode for rxgain (ExpressMIMO2)
rx_gain_t rxg_mode[4];
//! \brief Gain for RX in dB.
//! index: [0..rx_num_channels]
double rx_gain[4];
//! \brief Gain offset (for calibration) in dB
//! index: [0..rx_num_channels]
double rx_gain_offset[4];
//! gain for TX in dB
double tx_gain[4];
//! RX bandwidth in Hz
double rx_bw;
//! TX bandwidth in Hz
double tx_bw;
//! clock source
clock_source_t clock_source;
//! timing_source
clock_source_t time_source;
//! Manual SDR IP address
//#if defined(EXMIMO) || defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR) || defined(OAI_YUNSDR)
char *sdr_addrs;
//! 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
int iq_txshift;
int iq_rxrescale;
//! Configuration file for LMS7002M
char *configFilename;
//! remote IP/MAC addr for Ethernet interface
char *remote_addr;
//! remote port number for Ethernet interface
unsigned int remote_port;
//! local IP/MAC addr for Ethernet interface (eNB/BBU, UE)
char *my_addr;
//! local port number for Ethernet interface (eNB/BBU, UE)
unsigned int my_port;
//! record player configuration, definition in record_player.h
uint32_t recplay_mode;
//! number of samples per tti
unsigned int samples_per_tti;
//! the sample rate for receive.
double rx_sample_rate;
//! the sample rate for transmit.
double tx_sample_rate;
//! check for threequarter sampling rate
int8_t threequarter_fs;
//! Flag to indicate this configuration is for NR
int nr_flag;
//! NR band number
int nr_band;
//! NR scs for raster
int nr_scs_for_raster;
} openair0_config_t;
/*! \brief RF mapping */
typedef struct {
//! card id
int card;
//! rf chain id
int chain;
} openair0_rf_map;
typedef struct {
char *remote_addr;
//! remote port number for Ethernet interface (control)
uint16_t remote_portc;
//! remote port number for Ethernet interface (user)
uint16_t remote_portd;
//! local IP/MAC addr for Ethernet interface (eNB/RAU, UE)
char *my_addr;
//! local port number (control) for Ethernet interface (eNB/RAU, UE)
uint16_t my_portc;
//! local port number (user) for Ethernet interface (eNB/RAU, UE)
uint16_t my_portd;
//! local Ethernet interface (eNB/RAU, UE)
char *local_if_name;
//! transport type preference (RAW/UDP)
uint8_t transp_preference;
//! compression enable (0: No comp/ 1: A-LAW)
uint8_t if_compress;
} eth_params_t;
typedef struct {
//! Tx buffer for if device, keep one per subframe now to allow multithreading
void *tx[10];
//! Tx buffer (PRACH) for if device
void *tx_prach;
//! Rx buffer for if device
void *rx;
} if_buffer_t;
typedef struct {
openair0_timestamp timestamp;
void *buff[MAX_WRITE_THREAD_BUFFER_SIZE];// buffer to be write;
int nsamps;
int cc;
signed char first_packet;
signed char last_packet;
int flags_msb;
} openair0_write_package_t;
typedef struct {
openair0_write_package_t write_package[MAX_WRITE_THREAD_PACKAGE];
int start;
int end;
/// \internal This variable is protected by \ref mutex_write
int count_write;
/// pthread struct for trx write thread
pthread_t pthread_write;
/// pthread attributes for trx write thread
pthread_attr_t attr_write;
/// condition varible for trx write thread
pthread_cond_t cond_write;
/// mutex for trx write thread
pthread_mutex_t mutex_write;
} openair0_thread_t;
/*!\brief structure holds the parameters to configure USRP devices */
struct openair0_device_t {
/*!tx write thread*/
openair0_thread_t write_thread;
/*!brief Module ID of this device */
int Mod_id;
/*!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 supports (in case I/Q samples need to be transported) */
transport_type_t transp_type;
/*!brief Type of the device's host (RAU/RRU) */
host_type_t host_type;
/* !brief RF frontend parameters set by application */
openair0_config_t *openair0_cfg;
/* !brief ETH params set by application */
eth_params_t *eth_params;
/* !brief Indicates if device already initialized */
int is_init;
/*!brief Can be used by driver to hold internal structure*/
void *priv;
/* Functions API, which are called by the application*/
/*! \brief Called to start the transceiver. Return 0 if OK, < 0 if error
@param device pointer to the device structure specific to the RF hardware target
*/
int (*trx_start_func)(openair0_device *device);
/*! \brief Called to configure the device
@param device pointer to the device structure specific to the RF hardware target
*/
int (*trx_config_func)(openair0_device* device, openair0_config_t *openair0_cfg);
/*! \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
*/
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
*/
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 buff Buffer which holds the samples (2 dimensional)
@param nsamps number of samples to be sent
@param number of antennas
@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 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 buff Buffer which holds the samples (1 dimensional)
@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_func2)(openair0_device *device, openair0_timestamp timestamp, void *buff, int nsamps,int antenna_id, int flags);
/*! \brief Receive samples from hardware.
* Read \ref nsamps samples from each channel to buffers. buff[0] is the array for
* the first channel. *ptimestamp is the time at which the first sample
* was received.
* \param device the hardware to use
* \param[out] ptimestamp the time at which the first sample was received.
* \param[out] buff An array of pointers to buffers for received samples. The buffers must be large enough to hold the number of samples \ref nsamps.
* \param nsamps Number of samples. One sample is 2 byte I + 2 byte Q => 4 byte.
* \param num_antennas number of antennas from which to receive samples
* \returns the number of sample read
*/
int (*trx_read_func)(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps,int num_antennas);
/*! \brief Receive samples from hardware, this version provides a single antenna at a time and returns.
* Read \ref nsamps samples from each channel to buffers. buff[0] is the array for
* the first channel. *ptimestamp is the time at which the first sample
* 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 nsamps Number of samples. One sample is 2 byte I + 2 byte Q => 4 byte.
* \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);
/*! \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
* \param device the hardware to use
* \returns 0 in success
*/
int (*trx_reset_stats_func)(openair0_device *device);
/*! \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
*/
int (*trx_stop_func)(openair0_device *device);
/* Functions API related to UE*/
/*! \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
*/
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
*/
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);
/*! \brief Pointer to generic RRU private information
*/
void *thirdparty_priv;
/*! \brief Callback for Third-party RRU Initialization routine
\param device the hardware configuration to use
*/
int (*thirdparty_init)(openair0_device *device);
/*! \brief Callback for Third-party RRU Cleanup routine
\param device the hardware configuration to use
*/
int (*thirdparty_cleanup)(openair0_device *device);
/*! \brief Callback for Third-party start streaming routine
\param device the hardware configuration to use
*/
int (*thirdparty_startstreaming)(openair0_device *device);
/*! \brief RRU Configuration callback
* \param idx RU index
* \param arg pointer to capabilities or configuration
*/
int (*trx_write_init)(openair0_device *device);
/* \brief Get internal parameter
* \param id parameter to get
* \return a pointer to the parameter
*/
void *(*get_internal_parameter)(char *id);
};
/* 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);
#define UE_MAGICDL 0xA5A5A5A5A5A5A5A5 // UE DL FDD record
#define UE_MAGICUL 0x5A5A5A5A5A5A5A5A // UE UL FDD record
#define ENB_MAGICDL 0xB5B5B5B5B5B5B5B5 // eNB DL FDD record
#define ENB_MAGICUL 0x5B5B5B5B5B5B5B5B // eNB UL FDD record
#define OPTION_LZ4 0x00000001 // LZ4 compression (option_value is set to compressed size)
typedef struct {
uint64_t magic; // Magic value (see defines above)
uint32_t size; // Number of samples per antenna to follow this header
uint32_t nbAnt; // Total number of antennas following this header
// Samples per antenna follow this header,
// i.e. nbAnt = 2 => this header+samples_antenna_0+samples_antenna_1
// data following this header in bytes is nbAnt*size*sizeof(sample_t)
uint64_t timestamp; // Timestamp value of first sample
uint32_t option_value; // Option value
uint32_t option_flag; // Option flag
} samplesBlockHeader_t;
#ifdef __cplusplus
extern "C"
{
#endif
#define DEVICE_SECTION "device"
#define CONFIG_HLP_DEVICE "Identifies the oai device (the interface to RF) to use, the shared lib \"lib_<name>.so\" will be loaded"
#define CONFIG_DEVICEOPT_NAME "name"
/* inclusion for device configuration */
/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
/* config parameters for oai device */
/* optname helpstr paramflags XXXptr defXXXval type numelt */
/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
#define DEVICE_PARAMS_DESC {\
{ CONFIG_DEVICEOPT_NAME, CONFIG_HLP_DEVICE, 0, strptr:&devname, defstrval:NULL, TYPE_STRING, 0}\
}
/*! \brief get device name from device type */
const char *get_devname(int devtype);
/*! \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 store recorded iqs from memory to file. */
extern void iqrecorder_end(openair0_device *device);
#include <unistd.h>
#ifndef gettid
#define gettid() syscall(__NR_gettid)
#endif
/*@}*/
#ifdef __cplusplus
}
#endif
#endif // COMMON_LIB_H
/*
* 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
*/
/*
platform_types.h
-------------------
AUTHOR : Lionel GAUTHIER
COMPANY : EURECOM
EMAIL : Lionel.Gauthier@eurecom.fr
***************************************************************************/
#ifndef __PLATFORM_TYPES_H__
#define __PLATFORM_TYPES_H__
#if !defined(NAS_NETLINK)
#include <stdint.h>
#else
#include <linux/types.h>
typedef void * intptr_t;
#endif
//-----------------------------------------------------------------------------
// GENERIC TYPES
//-----------------------------------------------------------------------------
/* boolean_t is also defined in openair2/COMMON/commonDef.h,
* let's protect potential redefinition
*/
#ifndef _BOOLEAN_T_DEFINED_
#define _BOOLEAN_T_DEFINED_
typedef signed char boolean_t;
#if !defined(TRUE)
#define TRUE (boolean_t)0x01
#endif
#if !defined(FALSE)
#define FALSE (boolean_t)0x00
#endif
#define BOOL_NOT(b) (b^TRUE)
#endif /* _BOOLEAN_T_DEFINED_ */
//-----------------------------------------------------------------------------
// GENERIC ACCESS STRATUM TYPES
//-----------------------------------------------------------------------------
typedef int32_t sdu_size_t;
typedef uint32_t frame_t;
typedef int32_t sframe_t;
typedef uint32_t sub_frame_t;
typedef uint32_t slot_t;
typedef uint16_t module_id_t;
typedef uint8_t slice_id_t;
typedef uint8_t eNB_index_t;
typedef uint16_t ue_id_t;
typedef int16_t smodule_id_t;
typedef long rb_id_t;
typedef long srb_id_t;
typedef boolean_t MBMS_flag_t;
#define MBMS_FLAG_NO FALSE
#define MBMS_FLAG_YES TRUE
typedef boolean_t eNB_flag_t;
#define ENB_FLAG_NO FALSE
#define ENB_FLAG_YES TRUE
typedef boolean_t gNB_flag_t;
#define GNB_FLAG_NO FALSE
#define GNB_FLAG_YES TRUE
typedef boolean_t srb_flag_t;
#define SRB_FLAG_NO FALSE
#define SRB_FLAG_YES TRUE
typedef boolean_t sl_discovery_flag_t;
#define SL_DISCOVERY_FLAG_NO FALSE
#define SL_DISCOVERY_FLAG_YES TRUE
typedef enum link_direction_e {
UNKNOWN_DIR = 0,
DIR_UPLINK = 1,
DIR_DOWNLINK = 2
} link_direction_t;
typedef enum rb_type_e {
UNKNOWN_RADIO_BEARER = 0,
SIGNALLING_RADIO_BEARER = 1,
RADIO_ACCESS_BEARER = 2
} rb_type_t;
typedef enum {
CR_ROUND = 0,
CR_SRB12 = 1,
CR_HOL = 2,
CR_LC = 3,
CR_CQI = 4,
CR_LCP = 5,
CR_NUM = 6
} sorting_criterion_t;
typedef enum {
POL_FAIR = 0,
POL_GREEDY = 1,
POL_NUM = 2
} accounting_policy_t;
//-----------------------------------------------------------------------------
// PHY TYPES
//-----------------------------------------------------------------------------
typedef uint8_t crc8_t;
typedef uint16_t crc16_t;
typedef uint32_t crc32_t;
typedef unsigned int crc_t;
//-----------------------------------------------------------------------------
// MAC TYPES
//-----------------------------------------------------------------------------
typedef sdu_size_t tbs_size_t;
typedef sdu_size_t tb_size_t;
typedef unsigned int logical_chan_id_t;
typedef unsigned int num_tb_t;
typedef uint8_t mac_enb_index_t;
//-----------------------------------------------------------------------------
// RLC TYPES
//-----------------------------------------------------------------------------
typedef unsigned int mui_t;
typedef unsigned int confirm_t;
typedef unsigned int rlc_tx_status_t;
typedef int16_t rlc_sn_t;
typedef uint16_t rlc_usn_t;
typedef int32_t rlc_buffer_occupancy_t;
typedef signed int rlc_op_status_t;
#define SDU_CONFIRM_NO FALSE
#define SDU_CONFIRM_YES TRUE
//-----------------------------------------------------------------------------
// PDCP TYPES
//-----------------------------------------------------------------------------
typedef uint16_t pdcp_sn_t;
typedef uint32_t pdcp_hfn_t;
typedef int16_t pdcp_hfn_offset_t;
typedef enum pdcp_transmission_mode_e {
PDCP_TRANSMISSION_MODE_UNKNOWN = 0,
PDCP_TRANSMISSION_MODE_CONTROL = 1,
PDCP_TRANSMISSION_MODE_DATA = 2,
PDCP_TRANSMISSION_MODE_TRANSPARENT = 3
} pdcp_transmission_mode_t;
//-----------------------------------------------------------------------------
// IP DRIVER / PDCP TYPES
//-----------------------------------------------------------------------------
typedef uint16_t tcp_udp_port_t;
typedef enum ip_traffic_type_e {
TRAFFIC_IPVX_TYPE_UNKNOWN = 0,
TRAFFIC_IPV6_TYPE_UNICAST = 1,
TRAFFIC_IPV6_TYPE_MULTICAST = 2,
TRAFFIC_IPV6_TYPE_UNKNOWN = 3,
TRAFFIC_IPV4_TYPE_UNICAST = 5,
TRAFFIC_IPV4_TYPE_MULTICAST = 6,
TRAFFIC_IPV4_TYPE_BROADCAST = 7,
TRAFFIC_IPV4_TYPE_UNKNOWN = 8,
TRAFFIC_PC5S_SIGNALLING = 9,
TRAFFIC_PC5S_SESSION_INIT = 10
} ip_traffic_type_t;
//-----------------------------------------------------------------------------
// RRC TYPES
//-----------------------------------------------------------------------------
typedef uint32_t mbms_session_id_t;
typedef uint16_t mbms_service_id_t;
typedef uint16_t rnti_t;
typedef uint8_t rrc_enb_index_t;
typedef uint8_t mme_code_t;
typedef uint32_t m_tmsi_t;
//Random UE identity length = 40 bits
#define NOT_A_RANDOM_UE_IDENTITY (uint64_t)0xFFFFFFFF
#define NOT_A_RNTI (rnti_t)0
#define M_RNTI (rnti_t)0xFFFD
#define P_RNTI (rnti_t)0xFFFE
#define SI_RNTI (rnti_t)0xFFFF
#define CBA_RNTI (rnti_t)0xfff4
#define OAI_C_RNTI (rnti_t)0x1234
typedef enum config_action_e {
CONFIG_ACTION_NULL = 0,
CONFIG_ACTION_ADD = 1,
CONFIG_ACTION_REMOVE = 2,
CONFIG_ACTION_MODIFY = 3,
CONFIG_ACTION_SET_SECURITY_MODE = 4,
CONFIG_ACTION_MBMS_ADD = 10,
CONFIG_ACTION_MBMS_MODIFY = 11
} config_action_t;
/* Maximum size of any message we might send or receive (e.g., via a socket) */
#define MAX_MESSAGE_SIZE 8192
typedef struct nsa_msg_t {
uint8_t msg_type;
uint8_t msg_buffer[MAX_MESSAGE_SIZE];
} nsa_msg_t;
//-----------------------------------------------------------------------------
// GTPV1U TYPES
//-----------------------------------------------------------------------------
typedef uint32_t teid_t; // tunnel endpoint identifier
typedef uint8_t ebi_t; // eps bearer id
typedef uint8_t pdusessionid_t;
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
// may be ITTI not enabled, but type instance is useful also for OTG,
typedef intptr_t instance_t;
typedef struct protocol_ctxt_s {
module_id_t module_id; /*!< \brief Virtualized module identifier */
eNB_flag_t enb_flag; /*!< \brief Flag to indicate eNB (1) or UE (0) */
instance_t instance; /*!< \brief ITTI or OTG module identifier */
rnti_t rnti;
frame_t frame; /*!< \brief LTE frame number.*/
sub_frame_t subframe; /*!< \brief LTE sub frame number.*/
eNB_index_t eNB_index; /*!< \brief valid for UE indicating the index of connected eNB(s) */
boolean_t brOption;
} protocol_ctxt_t;
// warning time hardcoded
#define PROTOCOL_CTXT_TIME_MILLI_SECONDS(CtXt_h) ((CtXt_h)->frame*10+(CtXt_h)->subframe)
#define UE_MODULE_ID_TO_INSTANCE( mODULE_iD ) mODULE_iD + NB_eNB_INST
#define ENB_MODULE_ID_TO_INSTANCE( mODULE_iD ) mODULE_iD
#define UE_INSTANCE_TO_MODULE_ID( iNSTANCE ) iNSTANCE - NB_eNB_INST
#define ENB_INSTANCE_TO_MODULE_ID( iNSTANCE )iNSTANCE
//NR
#define GNB_MODULE_ID_TO_INSTANCE( mODULE_iD ) mODULE_iD
#define GNB_INSTANCE_TO_MODULE_ID( iNSTANCE )iNSTANCE
#define MODULE_ID_TO_INSTANCE(mODULE_iD, iNSTANCE, eNB_fLAG) \
if(eNB_fLAG == ENB_FLAG_YES) \
iNSTANCE = ENB_MODULE_ID_TO_INSTANCE(mODULE_iD); \
else \
iNSTANCE = UE_MODULE_ID_TO_INSTANCE(mODULE_iD)
#define INSTANCE_TO_MODULE_ID(iNSTANCE, mODULE_iD, eNB_fLAG) \
if(eNB_fLAG == ENB_FLAG_YES) \
mODULE_iD = ENB_INSTANCE_TO_MODULE_ID(iNSTANCE); \
else \
mODULE_iD = UE_INSTANCE_TO_MODULE_ID(iNSTANCE)
#define PROTOCOL_CTXT_COMPUTE_MODULE_ID(CtXt_h) \
INSTANCE_TO_MODULE_ID( (CtXt_h)->instance , (CtXt_h)->module_id , (CtXt_h)->enb_flag )
#define PROTOCOL_CTXT_COMPUTE_INSTANCE(CtXt_h) \
MODULE_ID_TO_INSTANCE( (CtXt_h)->module_id , (CtXt_h)->instance , (CtXt_h)->enb_flag )
#define PROTOCOL_CTXT_SET_BY_MODULE_ID(Ctxt_Pp, mODULE_iD, eNB_fLAG, rNTI, fRAME, sUBfRAME, eNB_iNDEX) \
(Ctxt_Pp)->module_id = mODULE_iD; \
(Ctxt_Pp)->enb_flag = eNB_fLAG; \
(Ctxt_Pp)->rnti = rNTI; \
(Ctxt_Pp)->frame = fRAME; \
(Ctxt_Pp)->subframe = sUBfRAME; \
(Ctxt_Pp)->eNB_index = eNB_iNDEX; \
PROTOCOL_CTXT_COMPUTE_INSTANCE(Ctxt_Pp)
#define PROTOCOL_CTXT_SET_BY_INSTANCE(Ctxt_Pp, iNSTANCE, eNB_fLAG, rNTI, fRAME, sUBfRAME) \
(Ctxt_Pp)->instance = iNSTANCE; \
(Ctxt_Pp)->enb_flag = eNB_fLAG; \
(Ctxt_Pp)->rnti = rNTI; \
(Ctxt_Pp)->frame = fRAME; \
(Ctxt_Pp)->subframe = sUBfRAME; \
PROTOCOL_CTXT_COMPUTE_MODULE_ID(Ctxt_Pp)
#define PROTOCOL_CTXT_FMT "[FRAME %05u][%s][MOD %02d][RNTI %" PRIx16 "]"
#define PROTOCOL_CTXT_ARGS(CTXT_Pp) \
(CTXT_Pp)->frame, \
((CTXT_Pp)->enb_flag == ENB_FLAG_YES) ? "eNB":" UE", \
(CTXT_Pp)->module_id, \
(CTXT_Pp)->rnti
#define PROTOCOL_NR_CTXT_ARGS(CTXT_Pp) \
(CTXT_Pp)->frame, \
((CTXT_Pp)->enb_flag == GNB_FLAG_YES) ? "gNB":" UE", \
(CTXT_Pp)->module_id, \
(CTXT_Pp)->rnti
#define CHECK_CTXT_ARGS(CTXT_Pp)
#define exit_fun(msg) exit_function(__FILE__,__FUNCTION__,__LINE__,msg)
#ifdef __cplusplus
extern "C"
{
#endif
void exit_function(const char *file, const char *function, const int line, const char *s);
#ifdef __cplusplus
}
#endif
#endif
/*
* Copyright 2013-2020 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef YUNSDR_RF_HELPER_H_
#define YUNSDR_RF_HELPER_H_
// A bunch of helper functions to process device arguments
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define REMOVE_SUBSTRING_WITHCOMAS(S, TOREMOVE) \
remove_substring(S, TOREMOVE ","); \
remove_substring(S, TOREMOVE ", "); \
remove_substring(S, "," TOREMOVE); \
remove_substring(S, ", " TOREMOVE); \
remove_substring(S, TOREMOVE)
static inline void remove_substring(char* s, const char* toremove)
{
while ((s = strstr(s, toremove))) {
memmove(s, s + strlen(toremove), 1 + strlen(s + strlen(toremove)));
}
}
static inline void copy_subdev_string(char* dst, char* src)
{
int n = 0;
int len = (int)strlen(src);
/* Copy until end of string or comma */
while (n < len && src[n] != '\0' && src[n] != ',') {
dst[n] = src[n];
n++;
}
dst[n] = '\0';
}
#endif /* YUNSDR_RF_HELPER_H_ */
#include "trx_test.h"
int txdata_size=57344;
int rxdata_size=2465792;
int absolute_slot=0;
int nb_slot_frame=2;
int samples_per_subframe=30720;
int NB_ANTENNAS_RX=4;
int NB_ANTENNAS_TX=4;
//samples_per_subframe 30720, samples_per_slot_wCP 14336.
//txdata_size 57344, txdataF_size 57344, rxdata_size 2465792.
#define VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(A,B)
#define NR_TIMESPEC_TO_DOUBLE_US(nr_t) ( ( (double)nr_t.tv_sec * 1000000 ) + ( (double)nr_t.tv_nsec / 1000 ) )
struct timespec nr_get_timespec_diff(
struct timespec *start,
struct timespec *stop )
{
struct timespec result;
if ( ( stop->tv_nsec - start->tv_nsec ) < 0 ) {
result.tv_sec = stop->tv_sec - start->tv_sec - 1;
result.tv_nsec = stop->tv_nsec - start->tv_nsec + 1000000000;
}
else {
result.tv_sec = stop->tv_sec - start->tv_sec;
result.tv_nsec = stop->tv_nsec - start->tv_nsec;
}
return result;
}
int main( int argc, char **argv ) {
// T_Config_Init();
openair0_config_t openair0_cfg[4];
openair0_device rfdevice;
int card=0;
openair0_cfg[card].sample_rate = 30720 * 1e3;
openair0_cfg[card].samples_per_frame = 30720;
openair0_cfg[card].duplex_mode = duplex_mode_TDD;
openair0_cfg[card].Mod_id = 0;
openair0_cfg[card].num_rb_dl = 51;
openair0_cfg[card].clock_source = 0;
openair0_cfg[card].time_source = 0;
openair0_cfg[card].tx_num_channels = 1;
openair0_cfg[card].rx_num_channels = 1;
printf("HW: Configuring card %d, sample_rate %f, tx/rx num_channels %d/%d, duplex_mode %d\n",
card,
openair0_cfg[card].sample_rate,
openair0_cfg[card].tx_num_channels,
openair0_cfg[card].rx_num_channels,
openair0_cfg[card].duplex_mode);
int dl_carrier = 3628380000;
int ul_carrier = 3628380000;
int freq_off = 0;
int rx_gain_off = 0;
int rf_chain = 0;
double freq_scale = (double)(dl_carrier + freq_off) / dl_carrier;
for (int i = rf_chain; i < rf_chain + 1; i++) {
printf("test\n");
if (i < openair0_cfg->rx_num_channels)
openair0_cfg->rx_freq[i + rf_chain] = dl_carrier * freq_scale;
else
openair0_cfg->rx_freq[i] = 0.0;
if (i<openair0_cfg->tx_num_channels)
openair0_cfg->tx_freq[i] = ul_carrier * freq_scale;
else
openair0_cfg->tx_freq[i] = 0.0;
openair0_cfg->autocal[i] = 1;
//if (i < openair0_cfg->rx_num_channels)
{
printf("HW: Configuring channel %d (rf_chain %d): setting tx_freq %f Hz, rx_freq %f Hz\n",
i,
rf_chain,
openair0_cfg->tx_freq[i],
openair0_cfg->rx_freq[i]);
}
}
// nr_rf_card_config_gain(&openair0_cfg[card], rx_gain_off);
openair0_cfg[card].sdr_addrs = "dev=pciex:0,auxdac1=300";
openair0_timestamp timestamp, writeTimestamp;
int32_t * rxp[NB_ANTENNAS_RX];
int32_t * txp[NB_ANTENNAS_TX];
int start_rx_stream = 1;
double clock_gettime_cur;
struct timespec time_start;
struct timespec time_stop;
for (int i=0; i<NB_ANTENNAS_RX; i++) {
txp[i] = (int32_t *) malloc16_clear( txdata_size );
rxp[i] = (int32_t *) malloc16_clear( rxdata_size );
}
int readBlockSize, writeBlockSize;
readBlockSize = samples_per_subframe/2;
writeBlockSize = readBlockSize;
device_init(&(rfdevice), &openair0_cfg[0]);
rfdevice.trx_start_func(&rfdevice);
//first time is very long, don't know why.
clock_gettime(CLOCK_REALTIME,&time_start);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, VCD_FUNCTION_IN );
rfdevice.trx_read_func(&rfdevice,
&timestamp,
(void **)rxp,
readBlockSize,
1);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, VCD_FUNCTION_OUT );
clock_gettime(CLOCK_REALTIME,&time_stop);
clock_gettime_cur = NR_TIMESPEC_TO_DOUBLE_US( nr_get_timespec_diff( &time_start, &time_stop ));//us
printf("using %.2lf msec in 1st time\n", clock_gettime_cur/1000);
clock_gettime(CLOCK_REALTIME,&time_start);
while (1) {
absolute_slot++;
clock_gettime(CLOCK_REALTIME,&time_stop);
clock_gettime_cur = NR_TIMESPEC_TO_DOUBLE_US( nr_get_timespec_diff( &time_start, &time_stop ));//us
if (clock_gettime_cur > 1000)
printf("slot_num %d, time = %.2f sec, delay_time=%.2lf msec\n", absolute_slot, ((float)absolute_slot)/2/1000, clock_gettime_cur/1000);
clock_gettime(CLOCK_REALTIME,&time_start);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, VCD_FUNCTION_IN );
rfdevice.trx_read_func(&rfdevice,
&timestamp,
(void **)rxp,
readBlockSize,
1);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, VCD_FUNCTION_OUT );
// use previous timing_advance value to compute writeTimestamp
writeTimestamp = timestamp+samples_per_subframe/20*5;// sent after 5 slot.
// but use current UE->timing_advance value to compute writeBlockSize
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, VCD_FUNCTION_IN );
rfdevice.trx_write_func(&rfdevice,
writeTimestamp,
(void **)txp,
writeBlockSize,
1,
1);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, VCD_FUNCTION_OUT );
} // while !oai_exit
return 0;
}
#include <stdint.h>
#include <stdio.h>
#include <sys/types.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
//#include "T.h"
#include "common_lib.h"
#include "yunsdr_lib.h"
#include "utils.h"
typedef long int openair0_timestamp;
typedef int int32_t;
#ifndef _UTILS_H
#define _UTILS_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <sys/types.h>
#include "assertions.h"
#ifdef MALLOC_TRACE
#define malloc myMalloc
#endif
#define sizeofArray(a) (sizeof(a)/sizeof(*(a)))
#define cmax(a,b) ((a>b) ? (a) : (b))
#define cmax3(a,b,c) ((cmax(a,b)>c) ? (cmax(a,b)) : (c))
#define cmin(a,b) ((a<b) ? (a) : (b))
#ifdef __cplusplus
#ifdef min
#undef min
#undef max
#endif
#else
#define max(a,b) cmax(a,b)
#define min(a,b) cmin(a,b)
#endif
#ifndef malloc16
# ifdef __AVX2__
# define malloc16(x) memalign(32,x+32)
# else
# define malloc16(x) memalign(16,x+16)
# endif
#endif
#define free16(y,x) free(y)
#define bigmalloc malloc
#define bigmalloc16 malloc16
#define openair_free(y,x) free((y))
#define PAGE_SIZE 4096
#define free_and_zero(PtR) do { \
if (PtR) { \
free(PtR); \
PtR = NULL; \
} \
} while (0)
static inline void *malloc16_clear( size_t size ) {
#ifdef __AVX2__
void *ptr = memalign(32, size+32);
#else
void *ptr = memalign(16, size+16);
#endif
DevAssert(ptr);
memset( ptr, 0, size );
return ptr;
}
static inline void *calloc_or_fail(size_t size) {
void *ptr = calloc(1, size);
if (ptr == NULL) {
fprintf(stderr, "[UE] Failed to calloc %zu bytes", size);
exit(EXIT_FAILURE);
}
return ptr;
}
static inline void *malloc_or_fail(size_t size) {
void *ptr = malloc(size);
if (ptr == NULL) {
fprintf(stderr, "[UE] Failed to malloc %zu bytes", size);
exit(EXIT_FAILURE);
}
return ptr;
}
#if !defined (msg)
# define msg(aRGS...) LOG_D(PHY, ##aRGS)
#endif
#ifndef malloc16
# ifdef __AVX2__
# define malloc16(x) memalign(32,x)
# else
# define malloc16(x) memalign(16,x)
# endif
#endif
#define free16(y,x) free(y)
#define bigmalloc malloc
#define bigmalloc16 malloc16
#define openair_free(y,x) free((y))
#define PAGE_SIZE 4096
#define PAGE_MASK 0xfffff000
#define virt_to_phys(x) (x)
const char *hexdump(const void *data, size_t data_len, char *out, size_t out_len);
// Converts an hexadecimal ASCII coded digit into its value. **
int hex_char_to_hex_value (char c);
// Converts an hexadecimal ASCII coded string into its value.**
int hex_string_to_hex_value (uint8_t *hex_value, const char *hex_string, int size);
void *memcpy1(void *dst,const void *src,size_t n);
void set_priority(int priority);
char *itoa(int i);
#define findInList(keY, result, list, element_type) {\
int i;\
for (i=0; i<sizeof(list)/sizeof(element_type) ; i++)\
if (list[i].key==keY) {\
result=list[i].val;\
break;\
}\
AssertFatal(i < sizeof(list)/sizeof(element_type), "List %s doesn't contain %s\n",#list, #keY); \
}
#ifdef __cplusplus
}
#endif
#endif
/*
* 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.0 (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
*/
/** yunsdr_lib.c
*
* Author: eric
* base on bladerf_lib.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <inttypes.h>
#include <math.h>
#include "yunsdr_lib.h"
#include "rf_helper.h"
/** @addtogroup _YUNSDR_PHY_RF_INTERFACE_
* @{
*/
#ifdef __SSE4_1__
# include <smmintrin.h>
#endif
#ifdef __AVX2__
# include <immintrin.h>
#endif
#ifdef __aarch64__
#include <arm_neon.h>
#endif
//! Number of YUNSDR devices
int num_devices = 0;
#ifdef __GNUC__
static int recving = 0;
static int transmiting = 0;
#endif
static bool running = false;
#define RX_MTU 15360 //30720
#define BUFFER_SIZE (122880 * 10 * sizeof(int))
#define NCHAN_PER_DEV 4
static void *cache_buf[NCHAN_PER_DEV];
static void *iq_buf[NCHAN_PER_DEV];
static uint32_t remain = 0;
static inline int channel_to_mask(int channel_count)
{
uint8_t ch_mask;
switch (channel_count) {
case 4:
ch_mask = 0xf;break;
case 3:
ch_mask = 0x7;break;
case 2:
ch_mask = 0x3;break;
case 1:
ch_mask = 0x1;break;
default:
ch_mask = 0x1;break;
}
return ch_mask;
}
/*! \brief get current timestamp
*\param device the hardware to use
*\returns timestamp of YunSDR
*/
openair0_timestamp trx_get_timestamp(openair0_device *device) {
return 0;
}
/*! \brief Start yunsdr
* \param device the hardware to use
* \returns 0 on success
*/
int trx_yunsdr_start(openair0_device *device) {
printf("[yunsdr] Start yunsdr ...\n");
running = true;
return 0;
}
/*! \brief Called to send samples to the yunsdr 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 buff Buffer which holds the samples
\param nsamps number of samples to be sent
\param cc index of the component carrier
\param flags Ignored for the moment
\returns 0 on success
*/
static int trx_yunsdr_write(openair0_device *device,openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags) {
int status;
yunsdr_state_t *yunsdr = (yunsdr_state_t*)device->priv;
#ifdef __GNUC__
__sync_fetch_and_add(&transmiting, 1);
#endif
#ifdef __AVX2__
__m256i a, *b;
int len = nsamps * 2;
int16_t *iq = buff[0];
while (len >= 16) {
a = *(__m256i *)&iq[0];
b = (__m256i *)&iq[0];
*b = _mm256_slli_epi16(a, 4);
iq += 16;
len -= 16;
}
#elif defined(__arm__) || defined(__aarch64__)
__m128i a, *b;
int len = nsamps * 2;
int16_t *iq = buff[0];
while (len >= 8) {
a = *(int16x8_t *)&iq[0];
b = (int16x8_t *)&iq[0];
*b = vshlq_n_s16(a, 4);
iq += 8;
len -= 8;
}
#endif
/* remaining data */
while (len != 0) {
iq[0] <<= 4;
iq++;
len--;
}
status = yunsdr_write_samples_multiport(yunsdr->dev, (const void **)buff, nsamps, channel_to_mask(yunsdr->tx_num_channels), timestamp, 0);
if (status < 0) {
yunsdr->num_tx_errors++;
printf("[yunsdr] Failed to TX samples\n");
exit(-1);
}
#ifdef __GNUC__
__sync_fetch_and_sub(&transmiting, 1);
#endif
//LOG_D(HW, "Provided TX timestamp: %u, nsamps: %u\n", ptimestamp, nsamps);
yunsdr->tx_current_ts = timestamp;
yunsdr->tx_nsamps += nsamps;
yunsdr->tx_count++;
return nsamps;
}
/*! \brief Receive samples from hardware.
* Read \ref nsamps samples from each channel to buffers. buff[0] is the array for
* the first channel. *ptimestamp is the time at which the first sample
* was received.
* \param device the hardware to use
* \param[out] ptimestamp the time at which the first sample was received.
* \param[out] buff An array of pointers to buffers for received samples. The buffers must be large enough to hold the number of samples \ref nsamps.
* \param nsamps Number of samples. One sample is 2 byte I + 2 byte Q => 4 byte.
* \param cc Index of component carrier
* \returns number of samples read
*/
static int trx_yunsdr_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc) {
int status;
yunsdr_state_t *yunsdr = (yunsdr_state_t *)device->priv;
uint64_t timestamp = 0L;
#ifdef __GNUC__
__sync_fetch_and_add(&recving, 1);
#endif
if(remain == 0) {
int recv = 0;
if(nsamps % RX_MTU)
recv = (nsamps / RX_MTU + 1) * RX_MTU;
else
recv = nsamps;
timestamp = 0L;
status = yunsdr_read_samples_multiport(yunsdr->dev, iq_buf, recv, channel_to_mask(yunsdr->rx_num_channels), &timestamp);
if (status < 0) {
printf("[yunsdr] Failed to read samples %d\n", nsamps);
yunsdr->num_rx_errors++;
exit(-1);
}
for(int i = 0; i < yunsdr->rx_num_channels; i++)
memcpy(buff[i], iq_buf[i], nsamps * 4);
if(recv > nsamps) {
for(int i = 0; i < yunsdr->rx_num_channels; i++)
memcpy(cache_buf[i], iq_buf[i] + nsamps * 4, (recv - nsamps) * 4);
remain = recv - nsamps;
}
*(uint64_t *)ptimestamp = timestamp;
yunsdr->rx_current_ts = timestamp + nsamps;
//LOG_D(HW, "case 0: Current RX timestamp %"PRIu64", hw ts %"PRIu64", nsamps %u, remain %u, recv: %u\n", *ptimestamp, timestamp, nsamps, remain, recv);
} else if(remain >= nsamps) {
for(int i = 0; i < yunsdr->rx_num_channels; i++)
memcpy(buff[i], cache_buf[i], nsamps * 4);
remain -= nsamps;
if(remain > 0) {
for(int i = 0; i < yunsdr->rx_num_channels; i++)
memmove(cache_buf[i], cache_buf[i] + nsamps * 4, remain * 4);
}
*(uint64_t *)ptimestamp = yunsdr->rx_current_ts;
yunsdr->rx_current_ts += nsamps;
//LOG_D(HW, "case 1: Current RX timestamp %"PRIu64", nsamps %u, remain %u\n", *ptimestamp, nsamps, remain);
} else {
int recv;
if(remain + RX_MTU >= nsamps)
recv = RX_MTU;
else
recv = (nsamps / RX_MTU + 1) * RX_MTU;
timestamp = 0L;
status = yunsdr_read_samples_multiport(yunsdr->dev, iq_buf, recv, channel_to_mask(yunsdr->rx_num_channels), &timestamp);
if (status < 0) {
printf("[yunsdr] Failed to read samples %d\n", nsamps);
yunsdr->num_rx_errors++;
exit(-1);
}
if(timestamp != (yunsdr->rx_current_ts + remain)) {
int overflow = timestamp - (yunsdr->rx_current_ts + remain);
//printf("Rx overflow %u samples\n", overflow);
remain += overflow;
}
for(int i = 0; i < yunsdr->rx_num_channels; i++)
memcpy(cache_buf[i] + remain * 4, iq_buf[i], recv * 4);
for(int i = 0; i < yunsdr->rx_num_channels; i++)
memcpy(buff[i], cache_buf[i], nsamps * 4);
remain = recv + remain - nsamps;
for(int i = 0; i < yunsdr->rx_num_channels; i++)
memmove(cache_buf[i], cache_buf[i] + nsamps * 4, remain * 4);
*(uint64_t *)ptimestamp = yunsdr->rx_current_ts;
yunsdr->rx_current_ts += nsamps;
//LOG_D(HW, "case 2: Current RX timestamp %"PRIu64", hw ts %"PRIu64", nsamps %u, remain %u, recv: %u\n", *ptimestamp, timestamp, nsamps, remain, recv);
}
#ifdef __GNUC__
__sync_fetch_and_sub(&recving, 1);
#endif
//LOG_D(HW, "Current RX timestamp %"PRIu64", nsamps %u\n", *ptimestamp, nsamps);
yunsdr->rx_nsamps += nsamps;
yunsdr->rx_count++;
return nsamps;
}
/*! \brief Terminate operation of the yunsdr transceiver -- free all associated resources
* \param device the hardware to use
*/
void trx_yunsdr_end(openair0_device *device) {
yunsdr_state_t *yunsdr = (yunsdr_state_t*)device->priv;
if(!running)
return;
running = false;
#ifdef __GNUC__
while(__sync_and_and_fetch(&recving, 1) ||
__sync_and_and_fetch(&transmiting, 1))
usleep(50000);
#endif
printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
uint32_t count = 0;
yunsdr_get_channel_event(yunsdr->dev, TX_CHANNEL_TIMEOUT, 1, &count);
printf("[yunsdr] TX%d Channel timeout: %u\n", 1, count);
yunsdr_get_channel_event(yunsdr->dev, RX_CHANNEL_OVERFLOW, 1, &count);
printf("[yunsdr] RX%d Channel overflow: %u\n", 1, count);
printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
yunsdr_close_device(yunsdr->dev);
//exit(1);
}
/*! \brief print the yunsdr statistics
* \param device the hardware to use
* \returns 0 on success
*/
int trx_yunsdr_get_stats(openair0_device* device) {
return(0);
}
/*! \brief Reset the yunsdr statistics
* \param device the hardware to use
* \returns 0 on success
*/
int trx_yunsdr_reset_stats(openair0_device* device) {
return(0);
}
/*! \brief Stop yunsdr
* \param card the hardware to use
* \returns 0 in success
*/
int trx_yunsdr_stop(openair0_device* device) {
return(0);
}
/*! \brief Set frequencies (TX/RX)
* \param device the hardware to use
* \param openair0_cfg1 openair0 Config structure (ignored. It is there to comply with RF common API)
* \param exmimo_dump_config (ignored)
* \returns 0 in success
*/
int trx_yunsdr_set_freq(openair0_device* device, openair0_config_t *openair0_cfg1,int exmimo_dump_config) {
int status;
yunsdr_state_t *yunsdr = (yunsdr_state_t *)device->priv;
openair0_config_t *openair0_cfg = (openair0_config_t *)device->openair0_cfg;
if ((status = yunsdr_set_tx_lo_freq(yunsdr->dev, 0, (uint64_t)(openair0_cfg->tx_freq[0]))) < 0) {
printf("[yunsdr] Failed to set TX frequency\n");
} else
printf("[yunsdr] set TX frequency to %lu\n",(uint64_t)(openair0_cfg->tx_freq[0]));
if ((status = yunsdr_set_rx_lo_freq(yunsdr->dev, 0, (uint64_t)(openair0_cfg->rx_freq[0]))) < 0) {
printf("[yunsdr] Failed to set RX frequency\n");
} else
printf("[yunsdr] set RX frequency to %lu\n",(uint64_t)(openair0_cfg->rx_freq[0]));
return(0);
}
/*! \brief Set Gains (TX/RX)
* \param device the hardware to use
* \param openair0_cfg openair0 Config structure
* \returns 0 in success
*/
int trx_yunsdr_set_gains(openair0_device* device, openair0_config_t *openair0_cfg) {
int ret = 0;
yunsdr_state_t *yunsdr = (yunsdr_state_t *)device->priv;
if (openair0_cfg->rx_gain[0] > 65+openair0_cfg->rx_gain_offset[0]) {
printf("[yunsdr] Reduce RX Gain 0 by %f dB\n", openair0_cfg->rx_gain[0] - openair0_cfg->rx_gain_offset[0] - 65);
return -1;
}
if ((ret = yunsdr_set_rx1_rf_gain(yunsdr->dev, 0, (uint32_t)(openair0_cfg->rx_gain[0] > 65?65:openair0_cfg->rx_gain[0]))) < 0) {
printf("[yunsdr] Failed to set RX1 gain\n");
} else
printf("[yunsdr] set RX1 gain to %u\n",(uint32_t)(openair0_cfg->rx_gain[0]));
if(yunsdr->rx_num_channels > 1) {
if ((ret = yunsdr_set_rx2_rf_gain(yunsdr->dev, 0, (uint32_t)(openair0_cfg->rx_gain[1] > 65?65:openair0_cfg->rx_gain[1]))) < 0) {
printf("[yunsdr] Failed to set RX2 gain\n");
} else
printf("[yunsdr] set RX gain to %u\n",(uint32_t)(openair0_cfg->rx_gain[1]));
}
int tx_gain = ((uint32_t)openair0_cfg->tx_gain[0] > 90?90:(uint32_t)openair0_cfg->tx_gain[0]);
if ((ret = yunsdr_set_tx1_attenuation(yunsdr->dev, 0, (90 - tx_gain) * 1000)) < 0) {
printf("[yunsdr] Failed to set TX1 gain\n");
} else
printf("[yunsdr] set the TX1 gain to %d\n", (uint32_t)openair0_cfg->tx_gain[0]);
if(yunsdr->tx_num_channels > 1) {
tx_gain = ((uint32_t)openair0_cfg->tx_gain[1] > 90?90:(uint32_t)openair0_cfg->tx_gain[1]);
if ((ret = yunsdr_set_tx2_attenuation(yunsdr->dev, 0, (90 - tx_gain) * 1000)) < 0) {
printf("[yunsdr] Failed to set TX2 gain\n");
} else
printf("[yunsdr] set the TX2 gain to %d\n", (uint32_t)openair0_cfg->tx_gain[1]);
}
return(ret);
}
/*! \brief Initialize Openair yunsdr target. It returns 0 if OK
* \param device the hardware to use
* \param openair0_cfg RF frontend parameters set by application
* \returns 0 on success
*/
int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
int status;
yunsdr_state_t *yunsdr = (yunsdr_state_t*)malloc(sizeof(yunsdr_state_t));
memset(yunsdr, 0, sizeof(yunsdr_state_t));
printf("[yunsdr] openair0_cfg[0].sdr_addrs == '%s'\n", openair0_cfg[0].sdr_addrs);
printf("[yunsdr] openair0_cfg[0].rx_num_channels == '%d'\n", openair0_cfg[0].rx_num_channels);
printf("[yunsdr] openair0_cfg[0].tx_num_channels == '%d'\n", openair0_cfg[0].tx_num_channels);
// init required params
switch ((int)openair0_cfg->sample_rate) {
case 122880000:
openair0_cfg->samples_per_packet = 122880;
openair0_cfg->tx_sample_advance = 70;
openair0_cfg[0].tx_bw = 100e6;
openair0_cfg[0].rx_bw = 100e6;
break;
case 61440000:
openair0_cfg->samples_per_packet = 61440;
openair0_cfg->tx_sample_advance = 70;
openair0_cfg[0].tx_bw = 40e6;
openair0_cfg[0].rx_bw = 40e6;
break;
case 30720000:
openair0_cfg->samples_per_packet = 30720;
openair0_cfg->tx_sample_advance = 70;
openair0_cfg[0].tx_bw = 20e6;
openair0_cfg[0].rx_bw = 20e6;
break;
case 15360000:
openair0_cfg->samples_per_packet = 15360;
openair0_cfg->tx_sample_advance = 68;
openair0_cfg[0].tx_bw = 10e6;
openair0_cfg[0].rx_bw = 10e6;
break;
case 7680000:
openair0_cfg->samples_per_packet = 7680;
openair0_cfg->tx_sample_advance = 34;
openair0_cfg[0].tx_bw = 5e6;
openair0_cfg[0].rx_bw = 5e6;
break;
case 1920000:
openair0_cfg->samples_per_packet = 1920;
openair0_cfg->tx_sample_advance = 9;
openair0_cfg[0].tx_bw = 1.25e6;
openair0_cfg[0].rx_bw = 1.25e6;
break;
default:
printf("[yunsdr] Error: unknown sampling rate %f\n", openair0_cfg->sample_rate);
free(yunsdr);
exit(-1);
break;
}
//openair0_cfg->iq_txshift = 2;
//openair0_cfg->iq_rxrescale = 14; /*not sure*/ //FIXME: adjust to yunsdr
yunsdr->sample_rate = (unsigned int)openair0_cfg->sample_rate;
printf("[yunsdr] sampling_rate %d\n", yunsdr->sample_rate);
yunsdr->rx_num_channels = openair0_cfg[0].rx_num_channels;
yunsdr->tx_num_channels = openair0_cfg[0].tx_num_channels;
int auxdac1 = 0;
char args[64];
if (openair0_cfg[0].sdr_addrs == NULL) {
strcpy(args, "dev=pcie:0");
} else {
strcpy(args, openair0_cfg[0].sdr_addrs);
}
char dev_str[64];
const char dev_arg[] = "dev=";
char *dev_ptr = strstr(args, dev_arg);
if(dev_ptr) {
copy_subdev_string(dev_str, dev_ptr + strlen(dev_arg));
remove_substring(args, dev_arg);
remove_substring(args, dev_str);
printf("[yunsdr] Using %s\n", dev_str);
}
const char auxdac1_arg[] = "auxdac1=";
char auxdac1_str[64] = {0};
char *auxdac1_ptr = strstr(args, auxdac1_arg);
if(auxdac1_ptr) {
copy_subdev_string(auxdac1_str, auxdac1_ptr + strlen(auxdac1_arg));
remove_substring(args, auxdac1_arg);
remove_substring(args, auxdac1_str);
auxdac1 = atoi(auxdac1_str);
printf("[yunsdr] Setting auxdac1:%u\n", auxdac1);
}
if ((yunsdr->dev = yunsdr_open_device(dev_str)) == NULL ) {
printf("[yunsdr] Failed to open yunsdr\n");
free(yunsdr);
return -1;
}
printf("[yunsdr] Initializing openair0_device\n");
switch (openair0_cfg[0].clock_source) {
case external:
printf("[yunsdr] clock_source: external\n");
yunsdr_set_ref_clock (yunsdr->dev, 0, EXTERNAL_REFERENCE);
yunsdr_set_pps_select (yunsdr->dev, 0, PPS_EXTERNAL_EN);
break;
case gpsdo:
printf("[yunsdr] clock_source: gpsdo\n");
break;
case internal:
default:
yunsdr_set_ref_clock (yunsdr->dev, 0, INTERNAL_REFERENCE);
yunsdr_set_pps_select (yunsdr->dev, 0, PPS_INTERNAL_EN);
//yunsdr_set_vco_select (yunsdr->dev, 0, AUXDAC1);
printf("[yunsdr] clock_source: internal\n");
break;
}
yunsdr_set_auxdac1 (yunsdr->dev, 0, auxdac1);
yunsdr_set_duplex_select (yunsdr->dev, 0, FDD);
yunsdr_set_trxsw_fpga_enable(yunsdr->dev, 0, 0);
yunsdr_set_rx_ant_enable (yunsdr->dev, 0, 1);
yunsdr_set_tx_fir_en_dis (yunsdr->dev, 0, 0);
yunsdr_set_rx_fir_en_dis (yunsdr->dev, 0, 0);
// RX port Initialize
if ((status = yunsdr_set_rx_lo_freq(yunsdr->dev, 0, (uint64_t)(openair0_cfg->rx_freq[0]))) < 0) {
printf("[yunsdr] Failed to set RX frequency\n");
} else
printf("[yunsdr] set RX frequency to %lu\n",(uint64_t)(openair0_cfg->rx_freq[0]));
if ((status = yunsdr_set_rx_sampling_freq(yunsdr->dev, 0, (uint32_t)(openair0_cfg->sample_rate))) < 0) {
printf("[yunsdr] Failed to set RX sample rate\n");
} else
printf("[yunsdr] set RX sample rate to %u\n", (uint32_t)(openair0_cfg->sample_rate));
if ((status = yunsdr_set_rx_rf_bandwidth(yunsdr->dev, 0, (uint32_t)(openair0_cfg->rx_bw))) < 0) {
printf("[yunsdr] Failed to set RX bandwidth\n");
} else
printf("[yunsdr] set RX bandwidth to %u\n",(uint32_t)(openair0_cfg->rx_bw));
if ((status = yunsdr_set_rx1_gain_control_mode(yunsdr->dev, 0, 0)) < 0){
printf("[yunsdr] Failed to set RX1 Gain Control Mode\n");
} else
printf("[yunsdr] set RX1 Gain Control Mode MGC\n");
if ((status = yunsdr_set_rx1_rf_gain(yunsdr->dev, 0, (uint32_t)(openair0_cfg->rx_gain[0] > 65?65:openair0_cfg->rx_gain[0]))) < 0) {
printf("[yunsdr] Failed to set RX1 gain\n");
} else
printf("[yunsdr] set RX1 gain to %u\n",(uint32_t)(openair0_cfg->rx_gain[0]));
if(yunsdr->rx_num_channels > 1) {
if ((status = yunsdr_set_rx2_gain_control_mode(yunsdr->dev, 0, 0)) < 0){
printf("[yunsdr] Failed to set RX2 Gain Control Mode\n");
} else
printf("[yunsdr] set RX2 Gain Control Mode MGC\n");
if ((status = yunsdr_set_rx2_rf_gain(yunsdr->dev, 0, (uint32_t)(openair0_cfg->rx_gain[1] > 65?65:openair0_cfg->rx_gain[1]))) < 0) {
printf("[yunsdr] Failed to set RX2 gain\n");
} else
printf("[yunsdr] set RX2 gain to %u\n",(uint32_t)(openair0_cfg->rx_gain[1]));
}
// TX port Initialize
if ((status = yunsdr_set_tx_lo_freq(yunsdr->dev, 0, (uint64_t)openair0_cfg->tx_freq[0])) < 0) {
printf("[yunsdr] Failed to set TX frequency\n");
} else
printf("[yunsdr] set TX Frequency to %lu\n", (uint64_t)openair0_cfg->tx_freq[0]);
if ((status = yunsdr_set_tx_sampling_freq(yunsdr->dev, 0, (uint32_t)openair0_cfg->sample_rate)) < 0) {
printf("[yunsdr] Failed to set TX sample rate\n");
} else
printf("[yunsdr] set TX sampling rate to %u\n", (uint32_t)openair0_cfg->sample_rate);
if ((status = yunsdr_set_tx_rf_bandwidth(yunsdr->dev, 0, (uint32_t)openair0_cfg->tx_bw)) <0) {
printf("[yunsdr] Failed to set TX bandwidth\n");
} else
printf("[yunsdr] set TX bandwidth to %u\n", (uint32_t)openair0_cfg->tx_bw);
int tx_gain = ((uint32_t)openair0_cfg->tx_gain[0] > 90?90:(uint32_t)openair0_cfg->tx_gain[0]);
if ((status = yunsdr_set_tx1_attenuation(yunsdr->dev, 0, (90 - tx_gain) * 1000)) < 0) {
printf("[yunsdr] Failed to set TX1 gain\n");
} else
printf("[yunsdr] set the TX1 gain to %d\n", (uint32_t)openair0_cfg->tx_gain[0]);
if(yunsdr->tx_num_channels > 1) {
tx_gain = ((uint32_t)openair0_cfg->tx_gain[1] > 90?90:(uint32_t)openair0_cfg->tx_gain[1]);
if ((status = yunsdr_set_tx2_attenuation(yunsdr->dev, 0, (90 - tx_gain) * 1000)) < 0) {
printf("[yunsdr] Failed to set TX2 gain\n");
} else
printf("[yunsdr] set the TX2 gain to %d\n", (uint32_t)openair0_cfg->tx_gain[1]);
}
yunsdr_enable_timestamp(yunsdr->dev, 0, 0);
usleep(5);
yunsdr_enable_timestamp(yunsdr->dev, 0, 1);
for(int i = 0; i < NCHAN_PER_DEV; i++) {
int ret = posix_memalign((void **)&cache_buf[i], 4096, BUFFER_SIZE);
if(ret) {
printf("Failed to alloc memory\n");
return -1;
}
ret = posix_memalign((void **)&iq_buf[i], 4096, BUFFER_SIZE);
if(ret) {
printf("Failed to alloc memory\n");
return -1;
}
}
device->Mod_id = num_devices++;
device->type = YUNSDR_DEV;
device->trx_start_func = trx_yunsdr_start;
device->trx_end_func = trx_yunsdr_end;
device->trx_read_func = trx_yunsdr_read;
device->trx_write_func = trx_yunsdr_write;
device->trx_get_stats_func = trx_yunsdr_get_stats;
device->trx_reset_stats_func = trx_yunsdr_reset_stats;
device->trx_stop_func = trx_yunsdr_stop;
device->trx_set_freq_func = trx_yunsdr_set_freq;
device->trx_set_gains_func = trx_yunsdr_set_gains;
device->openair0_cfg = openair0_cfg;
device->priv = (void *)yunsdr;
return 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.0 (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
*/
/** yunsdr_lib.h
*
* Author: eric
* base on bladerf_lib.h
*/
#include "yunsdr_api_ss.h"
#include "common_lib.h"
/** @addtogroup _YUNSDR_PHY_RF_INTERFACE_
* @{
*/
/*! \brief YunSDR specific data structure */
typedef struct {
//! opaque YunSDR device struct. An empty ("") or NULL device identifier will result in the first encountered device being opened (using the first discovered backend)
YUNSDR_DESCRIPTOR *dev;
int16_t *rx_buffer;
int16_t *tx_buffer;
//! Sample rate
unsigned int sample_rate;
int rx_num_channels;
int tx_num_channels;
uint64_t tx_lo_freq;
uint64_t rx_lo_freq;
// --------------------------------
// Debug and output control
// --------------------------------
//! Number of underflows
int num_underflows;
//! Number of overflows
int num_overflows;
//! number of RX errors
int num_rx_errors;
//! Number of TX errors
int num_tx_errors;
//! timestamp of current TX
uint64_t tx_current_ts;
//! timestamp of current RX
uint64_t rx_current_ts;
//! number of TX samples
uint64_t tx_nsamps;
//! number of RX samples
uint64_t rx_nsamps;
//! number of TX count
uint64_t tx_count;
//! number of RX count
uint64_t rx_count;
//! timestamp of RX packet
openair0_timestamp rx_timestamp;
} yunsdr_state_t;
/*! \brief get current timestamp
*\param device the hardware to use
*/
openair0_timestamp trx_get_timestamp(openair0_device *device);
int device_init(openair0_device *device, openair0_config_t *openair0_cfg);
/*@}*/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment