Commit cedde4ad authored by laurent's avatar laurent
Browse files

realtime for UE

parent 3bf8768d
......@@ -65,7 +65,7 @@ _Assert_(cOND, _Assert_Exit_, #vALUE1 ": %" PRIdMAX "\n" #vALUE2 ": %" PRIdMAX "
(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", \
_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)
......
......@@ -371,6 +371,9 @@ typedef struct {
pthread_mutex_t mutex_rxtx;
/// scheduling parameters for RXn-TXnp4 thread
struct sched_param sched_param_rxtx;
int sub_frame_start;
int sub_frame_step;
unsigned long long gotIQs;
} UE_rxtx_proc_t;
/// Context data structure for eNB subframe processing
......
......@@ -255,7 +255,7 @@ typedef struct protocol_ctxt_s {
(Ctxt_Pp)->subframe = sUBfRAME; \
PROTOCOL_CTXT_COMPUTE_MODULE_ID(Ctxt_Pp)
#define PROTOCOL_CTXT_FMT "[FRAME %05u][%s][MOD %02u][RNTI %"PRIx16"]"
#define PROTOCOL_CTXT_FMT "[FRAME %05u][%s][MOD %02u][RNTI %" PRIx16 "]"
#define PROTOCOL_CTXT_ARGS(CTXT_Pp) \
(CTXT_Pp)->frame, \
((CTXT_Pp)->enb_flag == ENB_FLAG_YES) ? "eNB":" UE", \
......
......@@ -53,6 +53,26 @@
extern "C" {
#endif
extern double cpuf;
static inline unsigned long long rdtsc(void) {
unsigned long long a, d;
__asm__ volatile ("rdtsc" : "=a" (a), "=d" (d));
return (d<<32) | a;
}
static inline unsigned long long checkT(int timeout, char * file, int line) {
static unsigned long long __thread last=0;
unsigned long long cur=rdtsc();
int microCycles=(int)(cpuf*1000);
int duration=(int)((cur-last)/microCycles);
if ( last!=0 && duration > timeout )
printf("%s:%d lte-ue delay %d (exceed %d)\n", file, line,
duration, timeout);
last=cur;
return cur;
}
#define check(a) checkT(a,__FILE__,__LINE__)
/** @defgroup _LOG LOG Generator
* @{*/
/* @}*/
......
......@@ -40,6 +40,8 @@
#include <time.h>
#include "UTIL/LOG/log_extern.h"
#include "common_lib.h"
#include "assertions.h"
#ifdef __SSE4_1__
# include <smmintrin.h>
#endif
......@@ -57,15 +59,13 @@
*/
/*! \brief USRP Configuration */
typedef struct
{
typedef struct {
// --------------------------------
// variables for USRP configuration
// --------------------------------
//! USRP device pointer
uhd::usrp::multi_usrp::sptr usrp;
//uhd::usrp::multi_usrp::sptr rx_usrp;
//create a send streamer and a receive streamer
//! USRP TX Stream
......@@ -78,53 +78,38 @@ typedef struct
//! USRP RX Metadata
uhd::rx_metadata_t rx_md;
//! USRP Timestamp Information
uhd::time_spec_t tm_spec;
//setup variables and allocate buffer
//! USRP Metadata
uhd::async_metadata_t async_md;
//! Sampling rate
double sample_rate;
//! time offset between transmiter timestamp and receiver timestamp;
double tdiff;
//! TX forward samples. We use usrp_time_offset to get this value
int tx_forward_nsamps; //166 for 20Mhz
// --------------------------------
// Debug and output control
// --------------------------------
//! Number of underflows
int num_underflows;
//! Number of overflows
int num_overflows;
//! Number of sequential errors
int num_seq_errors;
//! tx count
int64_t tx_count;
//! rx count
int64_t rx_count;
//! timestamp of RX packet
openair0_timestamp rx_timestamp;
} usrp_state_t;
/*! \brief Called to start the USRP transceiver. Return 0 if OK, < 0 if error
@param device pointer to the device structure specific to the RF hardware target
*/
static int trx_usrp_start(openair0_device *device)
{
static int trx_usrp_start(openair0_device *device) {
usrp_state_t *s = (usrp_state_t*)device->priv;
// init recv and send streaming
uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
cmd.time_spec = s->usrp->get_time_now() + uhd::time_spec_t(0.05);
cmd.stream_now = false; // start at constant delay
cmd.stream_now = true;
s->rx_stream->issue_stream_cmd(cmd);
s->tx_md.time_spec = cmd.time_spec + uhd::time_spec_t(1-(double)s->tx_forward_nsamps/s->sample_rate);
......@@ -132,22 +117,18 @@ static int trx_usrp_start(openair0_device *device)
s->tx_md.start_of_burst = true;
s->tx_md.end_of_burst = false;
s->rx_count = 0;
s->tx_count = 0;
s->rx_timestamp = 0;
return 0;
}
/*! \brief Terminate operation of the USRP transceiver -- free all associated resources
* \param device the hardware to use
*/
static void trx_usrp_end(openair0_device *device)
{
static void trx_usrp_end(openair0_device *device) {
usrp_state_t *s = (usrp_state_t*)device->priv;
s->rx_stream->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
//send a mini EOB packet
s->tx_md.end_of_burst = true;
s->tx_stream->send("", 0, s->tx_md);
......@@ -163,55 +144,26 @@ static void trx_usrp_end(openair0_device *device)
@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
*/
static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags)
{
static long long int loop=0;
static long time_min=0, time_max=0, time_avg=0;
struct timespec tp_start, tp_end;
long time_diff;
clock_gettime(CLOCK_MONOTONIC_RAW, &tp_start);
int ret=0, ret_i=0;
static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags) {
int ret=0;
usrp_state_t *s = (usrp_state_t*)device->priv;
s->tx_md.time_spec = uhd::time_spec_t::from_ticks(timestamp, s->sample_rate);
if(flags)
s->tx_md.has_time_spec = true;
else
s->tx_md.has_time_spec = false;
s->tx_md.has_time_spec = flags;
if (cc>1) {
std::vector<void *> buff_ptrs;
for (int i=0;i<cc;i++) buff_ptrs.push_back(buff[i]);
for (int i=0; i<cc; i++)
buff_ptrs.push_back(buff[i]);
ret = (int)s->tx_stream->send(buff_ptrs, nsamps, s->tx_md,1e-3);
}
else
} else
ret = (int)s->tx_stream->send(buff[0], nsamps, s->tx_md,1e-3);
s->tx_md.start_of_burst = false;
if (ret != nsamps) {
printf("[xmit] tx samples %d != %d\n",ret,nsamps);
}
if (ret != nsamps)
LOG_E(PHY,"[xmit] tx samples %d != %d\n",ret,nsamps);
clock_gettime(CLOCK_MONOTONIC_RAW, &tp_end);
time_diff = (tp_end.tv_sec - tp_start.tv_sec) *1E09 + (tp_end.tv_nsec - tp_start.tv_nsec);
if (time_min==0 ||loop==1 || time_min > time_diff)
time_min=time_diff;
if (time_max==0 ||loop==1 || time_max < time_diff)
time_max=time_diff;
if (time_avg ==0 ||loop==1)
time_avg= time_diff;
else
time_avg=(time_diff+time_avg) /2.0;
/* //prints statics of uhd every 10 seconds
if ( loop % (10 * ((int)device->openair0_cfg[0].sample_rate /(int)nsamps )) ==0)
LOG_I(HW,"usrp_write: min(ns)=%d, max(ns)=%d, avg(ns)=%d\n", (int)time_min, (int)time_max,(int)time_avg);
*/
loop++;
return ret;
}
......@@ -226,13 +178,7 @@ static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp,
* \param antenna_id Index of antenna for which to receive samples
* \returns the number of sample read
*/
static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc)
{
static long long int loop=0;
static long time_min=0, time_max=0, time_avg=0;
struct timespec tp_start, tp_end;
long time_diff;
clock_gettime(CLOCK_MONOTONIC_RAW, &tp_start);
static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc) {
usrp_state_t *s = (usrp_state_t*)device->priv;
int samples_received=0,i,j;
int nsamps2; // aligned to upper 32 or 16 byte boundary
......@@ -249,21 +195,24 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp
int16x8_t buff_tmp[2][nsamps2];
#endif
if (device->type == USRP_B200_DEV) {
if (cc>1) {
// receive multiple channels (e.g. RF A and RF B)
std::vector<void *> buff_ptrs;
for (int i=0;i<cc;i++) buff_ptrs.push_back(buff_tmp[i]);
for (int i=0; i<cc; i++) buff_ptrs.push_back(buff_tmp[i]);
samples_received = s->rx_stream->recv(buff_ptrs, nsamps, s->rx_md);
} else {
// receive a single channel (e.g. from connector RF A)
samples_received = s->rx_stream->recv(buff_tmp[0], nsamps, s->rx_md);
samples_received=0;
while (samples_received != nsamps) {
samples_received += s->rx_stream->recv(buff_tmp[0]+samples_received,
nsamps-samples_received, s->rx_md);
if (s->rx_md.error_code!=uhd::rx_metadata_t::ERROR_CODE_NONE)
break;
}
}
// bring RX data into 12 LSBs for softmodem RX
for (int i=0;i<cc;i++) {
for (int i=0; i<cc; i++) {
for (int j=0; j<nsamps2; j++) {
#if defined(__x86_64__) || defined(__i386__)
#ifdef __AVX2__
......@@ -288,67 +237,26 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp
samples_received = s->rx_stream->recv(buff[0], nsamps, s->rx_md);
}
}
if (samples_received < nsamps)
LOG_E(PHY,"[recv] received %d samples out of %d\n",samples_received,nsamps);
if (samples_received < nsamps) {
printf("[recv] received %d samples out of %d\n",samples_received,nsamps);
if ( s->rx_md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE)
LOG_E(PHY,s->rx_md.to_pp_string(true).c_str());
}
//handle the error code
switch(s->rx_md.error_code){
case uhd::rx_metadata_t::ERROR_CODE_NONE:
break;
case uhd::rx_metadata_t::ERROR_CODE_OVERFLOW:
printf("[recv] USRP RX OVERFLOW!\n");
s->num_overflows++;
break;
case uhd::rx_metadata_t::ERROR_CODE_TIMEOUT:
printf("[recv] USRP RX TIMEOUT!\n");
break;
default:
printf("[recv] Unexpected error on RX, Error code: 0x%x\n",s->rx_md.error_code);
break;
}
s->rx_count += nsamps;
s->rx_timestamp = s->rx_md.time_spec.to_ticks(s->sample_rate);
*ptimestamp = s->rx_timestamp;
clock_gettime(CLOCK_MONOTONIC_RAW, &tp_end);
time_diff = (tp_end.tv_sec - tp_start.tv_sec) *1E09 + (tp_end.tv_nsec - tp_start.tv_nsec);
if (time_min==0 ||loop==1 || time_min > time_diff)
time_min=time_diff;
if (time_max==0 ||loop==1 || time_max < time_diff)
time_max=time_diff;
if (time_avg ==0 ||loop==1)
time_avg= time_diff;
else
time_avg=(time_diff+time_avg) /2.0;
/*
//prints statics of uhd every 10 seconds
if ( loop % (10 * ((int)device->openair0_cfg[0].sample_rate /(int)nsamps )) ==0)
LOG_I(HW,"usrp_read: min(ns)=%d, max(ns)=%d, avg(ns)=%d\n", (int)time_min, (int)time_max,(int)time_avg);
loop++;*/
#ifdef DEBUG_USRP
check(50);
#endif
return samples_received;
}
/*! \brief Get current timestamp of USRP
* \param device the hardware to use
*/
openair0_timestamp get_usrp_time(openair0_device *device)
{
usrp_state_t *s = (usrp_state_t*)device->priv;
return s->usrp->get_time_now().to_ticks(s->sample_rate);
}
/*! \brief Compares two variables within precision
* \param a first variable
* \param b second variable
*/
static bool is_equal(double a, double b)
{
static bool is_equal(double a, double b) {
return std::fabs(a-b) < std::numeric_limits<double>::epsilon();
}
......@@ -362,7 +270,7 @@ int trx_usrp_set_freq(openair0_device* device, openair0_config_t *openair0_cfg,
usrp_state_t *s = (usrp_state_t*)device->priv;
printf("Setting USRP TX Freq %f, RX Freq %f\n",openair0_cfg[0].tx_freq[0],openair0_cfg[0].rx_freq[0]);
LOG_I(PHY,"Setting USRP TX Freq %f, RX Freq %f\n",openair0_cfg[0].tx_freq[0],openair0_cfg[0].rx_freq[0]);
s->usrp->set_tx_freq(openair0_cfg[0].tx_freq[0]);
s->usrp->set_rx_freq(openair0_cfg[0].rx_freq[0]);
......@@ -406,13 +314,14 @@ int trx_usrp_set_gains(openair0_device* device,
::uhd::gain_range_t gain_range = s->usrp->get_rx_gain_range(0);
// limit to maximum gain
if (openair0_cfg[0].rx_gain[0]-openair0_cfg[0].rx_gain_offset[0] > gain_range.stop()) {
printf("RX Gain 0 too high, reduce by %f dB\n",
LOG_E(PHY,"RX Gain 0 too high, reduce by %f dB\n",
openair0_cfg[0].rx_gain[0]-openair0_cfg[0].rx_gain_offset[0] - gain_range.stop());
exit(-1);
}
s->usrp->set_rx_gain(openair0_cfg[0].rx_gain[0]-openair0_cfg[0].rx_gain_offset[0]);
printf("Setting USRP RX gain to %f (rx_gain %f,gain_range.stop() %f)\n", openair0_cfg[0].rx_gain[0]-openair0_cfg[0].rx_gain_offset[0],openair0_cfg[0].rx_gain[0],gain_range.stop());
LOG_I(PHY,"Setting USRP RX gain to %f (rx_gain %f,gain_range.stop() %f)\n",
openair0_cfg[0].rx_gain[0]-openair0_cfg[0].rx_gain_offset[0],
openair0_cfg[0].rx_gain[0],gain_range.stop());
return(0);
}
......@@ -431,7 +340,8 @@ rx_gain_calib_table_t calib_table_b210[] = {
{2300000000.0,50.0},
{1880000000.0,53.0},
{816000000.0,58.0},
{-1,0}};
{-1,0}
};
/*! \brief USRPB210 RX calibration table */
rx_gain_calib_table_t calib_table_b210_38[] = {
......@@ -440,7 +350,8 @@ rx_gain_calib_table_t calib_table_b210_38[] = {
{2300000000.0,51.0},
{1880000000.0,53.0},
{816000000.0,57.0},
{-1,0}};
{-1,0}
};
/*! \brief USRPx310 RX calibration table */
rx_gain_calib_table_t calib_table_x310[] = {
......@@ -449,7 +360,8 @@ rx_gain_calib_table_t calib_table_x310[] = {
{2300000000.0,81.0},
{1880000000.0,82.0},
{816000000.0,85.0},
{-1,0}};
{-1,0}
};
/*! \brief Set RX gain offset
* \param openair0_cfg RF frontend parameters set by application
......@@ -481,14 +393,14 @@ void set_rx_gain_offset(openair0_config_t *openair0_cfg, int chain_index,int bw_
gain_adj=12.0;
break;
default:
printf("unknown sampling rate %d\n",(int)openair0_cfg[0].sample_rate);
LOG_E(PHY,"unknown sampling rate %d\n",(int)openair0_cfg[0].sample_rate);
exit(-1);
break;
}
}
while (openair0_cfg->rx_gain_calib_table[i].freq>0) {
diff = fabs(openair0_cfg->rx_freq[chain_index] - openair0_cfg->rx_gain_calib_table[i].freq);
printf("cal %d: freq %f, offset %f, diff %f\n",
LOG_I(PHY,"cal %d: freq %f, offset %f, diff %f\n",
i,
openair0_cfg->rx_gain_calib_table[i].freq,
openair0_cfg->rx_gain_calib_table[i].offset,diff);
......@@ -498,7 +410,6 @@ void set_rx_gain_offset(openair0_config_t *openair0_cfg, int chain_index,int bw_
}
i++;
}
}
/*! \brief print the USRP statistics
......@@ -506,78 +417,55 @@ void set_rx_gain_offset(openair0_config_t *openair0_cfg, int chain_index,int bw_
* \returns 0 on success
*/
int trx_usrp_get_stats(openair0_device* device) {
return(0);
}
/*! \brief Reset the USRP statistics
* \param device the hardware to use
* \returns 0 on success
*/
* \param device the hardware to use
* \returns 0 on success
*/
int trx_usrp_reset_stats(openair0_device* device) {
return(0);
}
extern "C" {
/*! \brief Initialize Openair USRP target. It returns 0 if OK
* \param device the hardware to use
* \param openair0_cfg RF frontend parameters set by application
*/
/*! \brief Initialize Openair USRP target. It returns 0 if OK
* \param device the hardware to use
* \param openair0_cfg RF frontend parameters set by application
*/
int device_init(openair0_device* device, openair0_config_t *openair0_cfg) {
uhd::set_thread_priority_safe(1.0);
usrp_state_t *s = (usrp_state_t*)malloc(sizeof(usrp_state_t));
memset(s, 0, sizeof(usrp_state_t));
//uhd::set_thread_priority_safe(1.0);
usrp_state_t *s = (usrp_state_t*)calloc(sizeof(usrp_state_t),1);
// Initialize USRP device
device->openair0_cfg = openair0_cfg;
std::string args = "type=b200";
uhd::device_addrs_t device_adds = uhd::device::find(args);
size_t i;
int vers=0,subvers=0,subsubvers=0;
int bw_gain_adjust=0;
sscanf(uhd::get_version_string().c_str(),"%d.%d.%d",&vers,&subvers,&subsubvers);
LOG_I(PHY,"Checking for USRPs : UHD %s (%d.%d.%d)\n",
uhd::get_version_string().c_str(),vers,subvers,subsubvers);
printf("Checking for USRPs : UHD %s (%d.%d.%d)\n",uhd::get_version_string().c_str(),vers,subvers,subsubvers);
if(device_adds.size() == 0)
{
if(device_adds.size() == 0) {
double usrp_master_clock = 184.32e6;
std::string args = "type=x300";
// workaround for an api problem, master clock has to be set with the constructor not via set_master_clock_rate
args += boost::str(boost::format(",master_clock_rate=%f") % usrp_master_clock);
// args += ",num_send_frames=256,num_recv_frames=256, send_frame_size=4096, recv_frame_size=4096";
// args += ",num_send_frames=256,num_recv_frames=256, send_frame_size=4096, recv_frame_size=4096";
uhd::device_addrs_t device_adds = uhd::device::find(args);
if(device_adds.size() == 0)
{
if(device_adds.size() == 0) {
std::cerr<<"No USRP Device Found. " << std::endl;
free(s);
return -1;
}
printf("Found USRP X300\n");
LOG_I(PHY,"Found USRP X300\n");
s->usrp = uhd::usrp::multi_usrp::make(args);
// s->usrp->set_rx_subdev_spec(rx_subdev);
// s->usrp->set_tx_subdev_spec(tx_subdev);
// lock mboard clocks
s->usrp->set_clock_source("internal");
......@@ -593,56 +481,40 @@ extern "C" {
switch ((int)openair0_cfg[0].sample_rate) {
case 30720000:
// from usrp_time_offset
//openair0_cfg[0].samples_per_packet = 2048;
openair0_cfg[0].tx_sample_advance = 15;
openair0_cfg[0].tx_bw = 20e6;
openair0_cfg[0].rx_bw = 20e6;
break;
case 15360000:
//openair0_cfg[0].samples_per_packet = 2048;
openair0_cfg[0].tx_sample_advance = 45;
openair0_cfg[0].tx_bw = 10e6;
openair0_cfg[0].rx_bw = 10e6;
break;
case 7680000:
//openair0_cfg[0].samples_per_packet = 2048;
openair0_cfg[0].tx_sample_advance = 50;
openair0_cfg[0].tx_bw = 5e6;
openair0_cfg[0].rx_bw = 5e6;
break;
case 1920000:
//openair0_cfg[0].samples_per_packet = 2048;
openair0_cfg[0].tx_sample_advance = 50;
openair0_cfg[0].tx_bw = 1.25e6;
openair0_cfg[0].rx_bw = 1.25e6;
break;
default:
printf("Error: unknown sampling rate %f\n",openair0_cfg[0].sample_rate);
LOG_E(PHY,"Error: unknown sampling rate %f\n",openair0_cfg[0].sample_rate);
exit(-1);
break;
}
} else {
printf("Found USRP B200");
LOG_I(PHY,"Found USRP B200\n");
args += ",num_send_frames=256,num_recv_frames=256, send_frame_size=15360, recv_frame_size=15360" ;
s->usrp = uhd::usrp::multi_usrp::make(args);
// s->usrp->set_rx_subdev_spec(rx_subdev);
// s->usrp->set_tx_subdev_spec(tx_subdev);
// do not explicitly set the clock to "internal", because this will disable the gpsdo
// // lock mboard clocks
// s->usrp->set_clock_source("internal");
// set master clock rate and sample rate for tx & rx for streaming
device->type = USRP_B200_DEV;
if ((vers == 3) && (subvers == 9) && (subsubvers>=2)) {
openair0_cfg[0].rx_gain_calib_table = calib_table_b210;
bw_gain_adjust=0;
}
else {
} else {
openair0_cfg[0].rx_gain_calib_table = calib_table_b210_38;
bw_gain_adjust=1;
}
......@@ -650,147 +522,118 @@ extern "C" {
switch ((int)openair0_cfg[0].sample_rate) {
case 30720000:
s->usrp->set_master_clock_rate(30.72e6);
//openair0_cfg[0].samples_per_packet = 1024;
openair0_cfg[0].tx_sample_advance = 115;
openair0_cfg[0].tx_bw = 20e6;
openair0_cfg[0].rx_bw = 20e6;
break;
case 23040000:
s->usrp->set_master_clock_rate(23.04e6); //to be checked
//openair0_cfg[0].samples_per_packet = 1024;
openair0_cfg[0].tx_sample_advance = 113;
openair0_cfg[0].tx_bw = 20e6;
openair0_cfg[0].rx_bw = 20e6;
break;
case 15360000:
s->usrp->set_master_clock_rate(30.72e06);
//openair0_cfg[0].samples_per_packet = 1024;
openair0_cfg[0].tx_sample_advance = 103;
openair0_cfg[0].tx_bw = 20e6;
openair0_cfg[0].rx_bw = 20e6;
break;