Commit cedde4ad authored by laurent's avatar laurent

realtime for UE

parent 3bf8768d
...@@ -65,7 +65,7 @@ _Assert_(cOND, _Assert_Exit_, #vALUE1 ": %" PRIdMAX "\n" #vALUE2 ": %" PRIdMAX " ...@@ -65,7 +65,7 @@ _Assert_(cOND, _Assert_Exit_, #vALUE1 ": %" PRIdMAX "\n" #vALUE2 ": %" PRIdMAX "
(intmax_t)vALUE1, (intmax_t)vALUE2, (intmax_t)vALUE3) (intmax_t)vALUE1, (intmax_t)vALUE2, (intmax_t)vALUE3)
#define DevCheck4(cOND, vALUE1, vALUE2, vALUE3, vALUE4) \ #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) (intmax_t)vALUE1, (intmax_t)vALUE2, (intmax_t)vALUE3, (intmax_t)vALUE4)
#define DevParam(vALUE1, vALUE2, vALUE3) DevCheck(0, vALUE1, vALUE2, vALUE3) #define DevParam(vALUE1, vALUE2, vALUE3) DevCheck(0, vALUE1, vALUE2, vALUE3)
......
...@@ -371,6 +371,9 @@ typedef struct { ...@@ -371,6 +371,9 @@ typedef struct {
pthread_mutex_t mutex_rxtx; pthread_mutex_t mutex_rxtx;
/// scheduling parameters for RXn-TXnp4 thread /// scheduling parameters for RXn-TXnp4 thread
struct sched_param sched_param_rxtx; struct sched_param sched_param_rxtx;
int sub_frame_start;
int sub_frame_step;
unsigned long long gotIQs;
} UE_rxtx_proc_t; } UE_rxtx_proc_t;
/// Context data structure for eNB subframe processing /// Context data structure for eNB subframe processing
......
...@@ -255,7 +255,7 @@ typedef struct protocol_ctxt_s { ...@@ -255,7 +255,7 @@ typedef struct protocol_ctxt_s {
(Ctxt_Pp)->subframe = sUBfRAME; \ (Ctxt_Pp)->subframe = sUBfRAME; \
PROTOCOL_CTXT_COMPUTE_MODULE_ID(Ctxt_Pp) 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) \ #define PROTOCOL_CTXT_ARGS(CTXT_Pp) \
(CTXT_Pp)->frame, \ (CTXT_Pp)->frame, \
((CTXT_Pp)->enb_flag == ENB_FLAG_YES) ? "eNB":" UE", \ ((CTXT_Pp)->enb_flag == ENB_FLAG_YES) ? "eNB":" UE", \
......
...@@ -53,6 +53,26 @@ ...@@ -53,6 +53,26 @@
extern "C" { extern "C" {
#endif #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 /** @defgroup _LOG LOG Generator
* @{*/ * @{*/
/* @}*/ /* @}*/
......
...@@ -40,6 +40,8 @@ ...@@ -40,6 +40,8 @@
#include <time.h> #include <time.h>
#include "UTIL/LOG/log_extern.h" #include "UTIL/LOG/log_extern.h"
#include "common_lib.h" #include "common_lib.h"
#include "assertions.h"
#ifdef __SSE4_1__ #ifdef __SSE4_1__
# include <smmintrin.h> # include <smmintrin.h>
#endif #endif
...@@ -57,15 +59,13 @@ ...@@ -57,15 +59,13 @@
*/ */
/*! \brief USRP Configuration */ /*! \brief USRP Configuration */
typedef struct typedef struct {
{
// -------------------------------- // --------------------------------
// variables for USRP configuration // variables for USRP configuration
// -------------------------------- // --------------------------------
//! USRP device pointer //! USRP device pointer
uhd::usrp::multi_usrp::sptr usrp; uhd::usrp::multi_usrp::sptr usrp;
//uhd::usrp::multi_usrp::sptr rx_usrp;
//create a send streamer and a receive streamer //create a send streamer and a receive streamer
//! USRP TX Stream //! USRP TX Stream
...@@ -78,53 +78,38 @@ typedef struct ...@@ -78,53 +78,38 @@ typedef struct
//! USRP RX Metadata //! USRP RX Metadata
uhd::rx_metadata_t rx_md; 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 //! Sampling rate
double sample_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 //! TX forward samples. We use usrp_time_offset to get this value
int tx_forward_nsamps; //166 for 20Mhz int tx_forward_nsamps; //166 for 20Mhz
// -------------------------------- // --------------------------------
// Debug and output control // Debug and output control
// -------------------------------- // --------------------------------
//! Number of underflows
int num_underflows; int num_underflows;
//! Number of overflows
int num_overflows; int num_overflows;
//! Number of sequential errors
int num_seq_errors; int num_seq_errors;
//! tx count
int64_t tx_count; int64_t tx_count;
//! rx count
int64_t rx_count; int64_t rx_count;
//! timestamp of RX packet //! timestamp of RX packet
openair0_timestamp rx_timestamp; openair0_timestamp rx_timestamp;
} usrp_state_t; } usrp_state_t;
/*! \brief Called to start the USRP transceiver. Return 0 if OK, < 0 if error /*! \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 @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; usrp_state_t *s = (usrp_state_t*)device->priv;
// init recv and send streaming // init recv and send streaming
uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS); 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.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->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); 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) ...@@ -132,22 +117,18 @@ static int trx_usrp_start(openair0_device *device)
s->tx_md.start_of_burst = true; s->tx_md.start_of_burst = true;
s->tx_md.end_of_burst = false; s->tx_md.end_of_burst = false;
s->rx_count = 0; s->rx_count = 0;
s->tx_count = 0; s->tx_count = 0;
s->rx_timestamp = 0; s->rx_timestamp = 0;
return 0; return 0;
} }
/*! \brief Terminate operation of the USRP transceiver -- free all associated resources /*! \brief Terminate operation of the USRP transceiver -- free all associated resources
* \param device the hardware to use * \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; usrp_state_t *s = (usrp_state_t*)device->priv;
s->rx_stream->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); s->rx_stream->issue_stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
//send a mini EOB packet //send a mini EOB packet
s->tx_md.end_of_burst = true; s->tx_md.end_of_burst = true;
s->tx_stream->send("", 0, s->tx_md); s->tx_stream->send("", 0, s->tx_md);
...@@ -163,55 +144,26 @@ static void trx_usrp_end(openair0_device *device) ...@@ -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 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 @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 int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags) {
{ int ret=0;
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;
usrp_state_t *s = (usrp_state_t*)device->priv; usrp_state_t *s = (usrp_state_t*)device->priv;
s->tx_md.time_spec = uhd::time_spec_t::from_ticks(timestamp, s->sample_rate); s->tx_md.time_spec = uhd::time_spec_t::from_ticks(timestamp, s->sample_rate);
s->tx_md.has_time_spec = flags;
if(flags)
s->tx_md.has_time_spec = true;
else
s->tx_md.has_time_spec = false;
if (cc>1) { if (cc>1) {
std::vector<void *> buff_ptrs; 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); 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); ret = (int)s->tx_stream->send(buff[0], nsamps, s->tx_md,1e-3);
s->tx_md.start_of_burst = false; s->tx_md.start_of_burst = false;
if (ret != nsamps) { if (ret != nsamps)
printf("[xmit] tx samples %d != %d\n",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; return ret;
} }
...@@ -226,13 +178,7 @@ static int trx_usrp_write(openair0_device *device, openair0_timestamp timestamp, ...@@ -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 * \param antenna_id Index of antenna for which to receive samples
* \returns the number of sample read * \returns the number of sample read
*/ */
static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc) 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);
usrp_state_t *s = (usrp_state_t*)device->priv; usrp_state_t *s = (usrp_state_t*)device->priv;
int samples_received=0,i,j; int samples_received=0,i,j;
int nsamps2; // aligned to upper 32 or 16 byte boundary 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 ...@@ -249,21 +195,24 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp
int16x8_t buff_tmp[2][nsamps2]; int16x8_t buff_tmp[2][nsamps2];
#endif #endif
if (device->type == USRP_B200_DEV) { if (device->type == USRP_B200_DEV) {
if (cc>1) { if (cc>1) {
// receive multiple channels (e.g. RF A and RF B) // receive multiple channels (e.g. RF A and RF B)
std::vector<void *> buff_ptrs; 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); samples_received = s->rx_stream->recv(buff_ptrs, nsamps, s->rx_md);
} else { } else {
// receive a single channel (e.g. from connector RF A) // 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 // 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++) { for (int j=0; j<nsamps2; j++) {
#if defined(__x86_64__) || defined(__i386__) #if defined(__x86_64__) || defined(__i386__)
#ifdef __AVX2__ #ifdef __AVX2__
...@@ -288,67 +237,26 @@ static int trx_usrp_read(openair0_device *device, openair0_timestamp *ptimestamp ...@@ -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); 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) { if ( s->rx_md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE)
printf("[recv] received %d samples out of %d\n",samples_received,nsamps); 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_count += nsamps;
s->rx_timestamp = s->rx_md.time_spec.to_ticks(s->sample_rate); s->rx_timestamp = s->rx_md.time_spec.to_ticks(s->sample_rate);
*ptimestamp = s->rx_timestamp; *ptimestamp = s->rx_timestamp;
#ifdef DEBUG_USRP
clock_gettime(CLOCK_MONOTONIC_RAW, &tp_end); check(50);
time_diff = (tp_end.tv_sec - tp_start.tv_sec) *1E09 + (tp_end.tv_nsec - tp_start.tv_nsec); #endif
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++;*/
return samples_received; 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 /*! \brief Compares two variables within precision
* \param a first variable * \param a first variable
* \param b second 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(); 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, ...@@ -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; 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_tx_freq(openair0_cfg[0].tx_freq[0]);
s->usrp->set_rx_freq(openair0_cfg[0].rx_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, ...@@ -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); ::uhd::gain_range_t gain_range = s->usrp->get_rx_gain_range(0);
// limit to maximum gain // limit to maximum gain
if (openair0_cfg[0].rx_gain[0]-openair0_cfg[0].rx_gain_offset[0] > gain_range.stop()) { if (openair0_cfg[0].rx_gain[0]-openair0_cfg[0].rx_gain_offset[0] > gain_range.stop()) {
LOG_E(PHY,"RX Gain 0 too high, reduce by %f dB\n",
printf("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()); openair0_cfg[0].rx_gain[0]-openair0_cfg[0].rx_gain_offset[0] - gain_range.stop());
exit(-1); exit(-1);
} }
s->usrp->set_rx_gain(openair0_cfg[0].rx_gain[0]-openair0_cfg[0].rx_gain_offset[0]); 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); return(0);
} }
...@@ -431,7 +340,8 @@ rx_gain_calib_table_t calib_table_b210[] = { ...@@ -431,7 +340,8 @@ rx_gain_calib_table_t calib_table_b210[] = {
{2300000000.0,50.0}, {2300000000.0,50.0},
{1880000000.0,53.0}, {1880000000.0,53.0},
{816000000.0,58.0}, {816000000.0,58.0},
{-1,0}}; {-1,0}
};
/*! \brief USRPB210 RX calibration table */ /*! \brief USRPB210 RX calibration table */
rx_gain_calib_table_t calib_table_b210_38[] = { rx_gain_calib_table_t calib_table_b210_38[] = {
...@@ -440,7 +350,8 @@ 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}, {2300000000.0,51.0},
{1880000000.0,53.0}, {1880000000.0,53.0},
{816000000.0,57.0}, {816000000.0,57.0},
{-1,0}}; {-1,0}
};
/*! \brief USRPx310 RX calibration table */ /*! \brief USRPx310 RX calibration table */
rx_gain_calib_table_t calib_table_x310[] = { rx_gain_calib_table_t calib_table_x310[] = {
...@@ -449,7 +360,8 @@ rx_gain_calib_table_t calib_table_x310[] = { ...@@ -449,7 +360,8 @@ rx_gain_calib_table_t calib_table_x310[] = {
{2300000000.0,81.0}, {2300000000.0,81.0},
{1880000000.0,82.0}, {1880000000.0,82.0},
{816000000.0,85.0}, {816000000.0,85.0},
{-1,0}}; {-1,0}
};
/*! \brief Set RX gain offset /*! \brief Set RX gain offset
* \param openair0_cfg RF frontend parameters set by application * \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_ ...@@ -481,14 +393,14 @@ void set_rx_gain_offset(openair0_config_t *openair0_cfg, int chain_index,int bw_
gain_adj=12.0; gain_adj=12.0;
break; break;
default: 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); exit(-1);
break; break;
} }
} }
while (openair0_cfg->rx_gain_calib_table[i].freq>0) { 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); 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, i,
openair0_cfg->rx_gain_calib_table[i].freq, openair0_cfg->rx_gain_calib_table[i].freq,
openair0_cfg->rx_gain_calib_table[i].offset,diff); 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_ ...@@ -498,7 +410,6 @@ void set_rx_gain_offset(openair0_config_t *openair0_cfg, int chain_index,int bw_
} }
i++; i++;
} }
} }
/*! \brief print the USRP statistics /*! \brief print the USRP statistics
...@@ -506,78 +417,55 @@ void set_rx_gain_offset(openair0_config_t *openair0_cfg, int chain_index,int bw_ ...@@ -506,78 +417,55 @@ void set_rx_gain_offset(openair0_config_t *openair0_cfg, int chain_index,int bw_
* \returns 0 on success * \returns 0 on success
*/ */
int trx_usrp_get_stats(openair0_device* device) { int trx_usrp_get_stats(openair0_device* device) {
return(0); return(0);
} }
/*! \brief Reset the USRP statistics /*! \brief Reset the USRP statistics
* \param device the hardware to use * \param device the hardware to use
* \returns 0 on success * \returns 0 on success
*/ */
int trx_usrp_reset_stats(openair0_device* device) { int trx_usrp_reset_stats(openair0_device* device) {
return(0); return(0);
} }
extern "C" { extern "C" {
/*! \brief Initialize Openair USRP target. It returns 0 if OK /*! \brief Initialize Openair USRP target. It returns 0 if OK
* \param device the hardware to use * \param device the hardware to use
* \param openair0_cfg RF frontend parameters set by application * \param openair0_cfg RF frontend parameters set by application
*/ */
int device_init(openair0_device* device, openair0_config_t *openair0_cfg) { int device_init(openair0_device* device, openair0_config_t *openair0_cfg) {
//uhd::set_thread_priority_safe(1.0);
uhd::set_thread_priority_safe(1.0); usrp_state_t *s = (usrp_state_t*)calloc(sizeof(usrp_state_t),1);
usrp_state_t *s = (usrp_state_t*)malloc(sizeof(usrp_state_t));
memset(s, 0, sizeof(usrp_state_t));
// Initialize USRP device // Initialize USRP device
device->openair0_cfg = openair0_cfg; device->openair0_cfg = openair0_cfg;
std::string args = "type=b200"; std::string args = "type=b200";
uhd::device_addrs_t device_adds = uhd::device::find(args); uhd::device_addrs_t device_adds = uhd::device::find(args);
size_t i;
int vers=0,subvers=0,subsubvers=0; int vers=0,subvers=0,subsubvers=0;
int bw_gain_adjust=0; int bw_gain_adjust=0;
sscanf(uhd::get_version_string().c_str(),"%d.%d.%d",&vers,&subvers,&subsubvers); 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; double usrp_master_clock = 184.32e6;
std::string args = "type=x300"; 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 // 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 += 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); 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; std::cerr<<"No USRP Device Found. " << std::endl;
free(s); free(s);
return -1; return -1;
} }
LOG_I(PHY,"Found USRP X300\n");
printf("Found USRP X300\n");
s->usrp = uhd::usrp::multi_usrp::make(args); 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 // lock mboard clocks
s->usrp->set_clock_source("internal"); s->usrp->set_clock_source("internal");
...@@ -593,56 +481,40 @@ extern "C" { ...@@ -593,56 +481,40 @@ extern "C" {
switch ((int)openair0_cfg[0].sample_rate) { switch ((int)openair0_cfg[0].sample_rate) {
case 30720000: case 30720000:
// from usrp_time_offset // from usrp_time_offset
//openair0_cfg[0].samples_per_packet = 2048;
openair0_cfg[0].tx_sample_advance = 15; openair0_cfg[0].tx_sample_advance = 15;
openair0_cfg[0].tx_bw = 20e6; openair0_cfg[0].tx_bw = 20e6;
openair0_cfg[0].rx_bw = 20e6; openair0_cfg[0].rx_bw = 20e6;
break; break;
case 15360000: case 15360000:
//openair0_cfg[0].samples_per_packet = 2048;
openair0_cfg[0].tx_sample_advance = 45; openair0_cfg[0].tx_sample_advance = 45;
openair0_cfg[0].tx_bw = 10e6; openair0_cfg[0].tx_bw = 10e6;
openair0_cfg[0].rx_bw = 10e6; openair0_cfg[0].rx_bw = 10e6;
break; break;
case 7680000: case 7680000:
//openair0_cfg[0].samples_per_packet = 2048;
openair0_cfg[0].tx_sample_advance = 50; openair0_cfg[0].tx_sample_advance = 50;
openair0_cfg[0].tx_bw = 5e6; openair0_cfg[0].tx_bw = 5e6;
openair0_cfg[0].rx_bw = 5e6; openair0_cfg[0].rx_bw = 5e6;
break; break;
case 1920000: case 1920000:
//openair0_cfg[0].samples_per_packet = 2048;
openair0_cfg[0].tx_sample_advance = 50; openair0_cfg[0].tx_sample_advance = 50;
openair0_cfg[0].tx_bw = 1.25e6; openair0_cfg[0].tx_bw = 1.25e6;
openair0_cfg[0].rx_bw = 1.25e6; openair0_cfg[0].rx_bw = 1.25e6;
break; break;
default: 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); exit(-1);
break; break;
} }
} else { } 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" ; 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 = 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; device->type = USRP_B200_DEV;
if ((vers == 3) && (subvers == 9) && (subsubvers>=2)) { if ((vers == 3) && (subvers == 9) && (subsubvers>=2)) {
openair0_cfg[0].rx_gain_calib_table = calib_table_b210; openair0_cfg[0].rx_gain_calib_table = calib_table_b210;
bw_gain_adjust=0; bw_gain_adjust=0;
} } else {
else {
openair0_cfg[0].rx_gain_calib_table = calib_table_b210_38; openair0_cfg[0].rx_gain_calib_table = calib_table_b210_38;
bw_gain_adjust=1; bw_gain_adjust=1;
} }
...@@ -650,147 +522,118 @@ extern "C" { ...@@ -650,147 +522,118 @@ extern "C" {
switch ((int)openair0_cfg[0].sample_rate) { switch ((int)openair0_cfg[0].sample_rate) {
case 30720000: case 30720000:
s->usrp->set_master_clock_rate(30.72e6); 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_sample_advance = 115;
openair0_cfg[0].tx_bw = 20e6; openair0_cfg[0].tx_bw = 20e6;
openair0_cfg[0].rx_bw = 20e6; openair0_cfg[0].rx_bw = 20e6;
break; break;
case 23040000: case 23040000:
s->usrp->set_master_clock_rate(23.04e6); //to be checked 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_sample_advance = 113;
openair0_cfg[0].tx_bw = 20e6; openair0_cfg[0].tx_bw = 20e6;
openair0_cfg[0].rx_bw = 20e6; openair0_cfg[0].rx_bw = 20e6;
break; break;
case 15360000: case 15360000:
s->usrp->set_master_clock_rate(30.72e06); 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_sample_advance = 103;
openair0_cfg[0].tx_bw = 20e6; openair0_cfg[0].tx_bw = 20e6;
openair0_cfg[0].rx_bw = 20e6; openair0_cfg[0].rx_bw = 20e6;
break; break;
case 7680000: case 7680000:
s->usrp->set_master_clock_rate(30.72e6); s->usrp->set_master_clock_rate(30.72e6);
//openair0_cfg[0].samples_per_packet = 1024;
openair0_cfg[0].tx_sample_advance = 80; openair0_cfg[0].tx_sample_advance = 80;
openair0_cfg[0].tx_bw = 20e6; openair0_cfg[0].tx_bw = 20e6;
openair0_cfg[0].rx_bw = 20e6; openair0_cfg[0].rx_bw = 20e6;
break; break;
case 1920000: case 1920000:
s->usrp->set_master_clock_rate(30.72e6); s->usrp->set_master_clock_rate(30.72e6);
//openair0_cfg[0].samples_per_packet = 1024;
openair0_cfg[0].tx_sample_advance = 40; openair0_cfg[0].tx_sample_advance = 40;
openair0_cfg[0].tx_bw = 20e6; openair0_cfg[0].tx_bw = 20e6;
openair0_cfg[0].rx_bw = 20e6; openair0_cfg[0].rx_bw = 20e6;
break; break;
default: 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); exit(-1);
break; break;
} }
} }
/* device specific */
//openair0_cfg[0].txlaunch_wait = 1;//manage when TX processing is triggered
//openair0_cfg[0].txlaunch_wait_slotcount = 1; //manage when TX processing is triggered
openair0_cfg[0].iq_txshift = 4;//shift openair0_cfg[0].iq_txshift = 4;//shift
openair0_cfg[0].iq_rxrescale = 15;//rescale iqs openair0_cfg[0].iq_rxrescale = 15;//rescale iqs
for(i=0;i<s->usrp->get_rx_num_channels();i++) { for(int i=0; i<s->usrp->get_rx_num_channels(); i++) {
if (i<openair0_cfg[0].rx_num_channels) { if (i<openair0_cfg[0].rx_num_channels) {
s->usrp->set_rx_rate(openair0_cfg[0].sample_rate,i); s->usrp->set_rx_rate(openair0_cfg[0].sample_rate,i);
//s->usrp->set_rx_bandwidth(openair0_cfg[0].rx_bw,i);
//printf("Setting rx freq/gain on channel %lu/%lu : BW %f (readback %f)\n",i,s->usrp->get_rx_num_channels(),openair0_cfg[0].rx_bw/1e6,s->usrp->get_rx_bandwidth(i)/1e6);
s->usrp->set_rx_freq(openair0_cfg[0].rx_freq[i],i); s->usrp->set_rx_freq(openair0_cfg[0].rx_freq[i],i);
set_rx_gain_offset(&openair0_cfg[0],i,bw_gain_adjust); set_rx_gain_offset(&openair0_cfg[0],i,bw_gain_adjust);
::uhd::gain_range_t gain_range = s->usrp->get_rx_gain_range(i); ::uhd::gain_range_t gain_range = s->usrp->get_rx_gain_range(i);
// limit to maximum gain // limit to maximum gain
if (openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i] > gain_range.stop()) { AssertFatal( openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i] <= gain_range.stop(),
"RX Gain too high, lower by %f dB\n",
printf("RX Gain %lu too high, lower by %f dB\n",i,openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i] - gain_range.stop()); openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i] - gain_range.stop());
exit(-1);
}
s->usrp->set_rx_gain(openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i],i); s->usrp->set_rx_gain(openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i],i);
printf("RX Gain %lu %f (%f) => %f (max %f)\n",i, LOG_I(PHY,"RX Gain %d %f (%f) => %f (max %f)\n",i,
openair0_cfg[0].rx_gain[i],openair0_cfg[0].rx_gain_offset[i], openair0_cfg[0].rx_gain[i],openair0_cfg[0].rx_gain_offset[i],
openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i],gain_range.stop()); openair0_cfg[0].rx_gain[i]-openair0_cfg[0].rx_gain_offset[i],gain_range.stop());
} }
} }
for(i=0;i<s->usrp->get_tx_num_channels();i++) { for(int i=0; i<s->usrp->get_tx_num_channels(); i++) {
if (i<openair0_cfg[0].tx_num_channels) { if (i<openair0_cfg[0].tx_num_channels) {
s->usrp->set_tx_rate(openair0_cfg[0].sample_rate,i); s->usrp->set_tx_rate(openair0_cfg[0].sample_rate,i);
//s->usrp->set_tx_bandwidth(openair0_cfg[0].tx_bw,i);
//printf("Setting tx freq/gain on channel %lu/%lu: BW %f (readback %f)\n",i,s->usrp->get_tx_num_channels(),openair0_cfg[0].tx_bw/1e6,s->usrp->get_tx_bandwidth(i)/1e6);
s->usrp->set_tx_freq(openair0_cfg[0].tx_freq[i],i); s->usrp->set_tx_freq(openair0_cfg[0].tx_freq[i],i);
s->usrp->set_tx_gain(openair0_cfg[0].tx_gain[i],i); s->usrp->set_tx_gain(openair0_cfg[0].tx_gain[i],i);
} }
} }
//s->usrp->set_clock_source("external");
//s->usrp->set_time_source("external");
// display USRP settings // display USRP settings
std::cout << boost::format("Actual master clock: %fMHz...") % (s->usrp->get_master_clock_rate()/1e6) << std::endl; LOG_I(PHY,"Actual master clock: %fMHz...\n",s->usrp->get_master_clock_rate()/1e6);
sleep(1);
// create tx & rx streamer // create tx & rx streamer
uhd::stream_args_t stream_args_rx("sc16", "sc16"); uhd::stream_args_t stream_args_rx("sc16", "sc16");
//stream_args_rx.args["spp"] = str(boost::format("%d") % 2048);//(openair0_cfg[0].rx_num_channels*openair0_cfg[0].samples_per_packet)); int samples=openair0_cfg[0].sample_rate;
for (i = 0; i<openair0_cfg[0].rx_num_channels; i++) //while ( samples > s->rx_stream->get_max_num_samps())
samples/=24000;
stream_args_rx.args["spp"] = str(boost::format("%d") % samples );
for (int i = 0; i<openair0_cfg[0].rx_num_channels; i++)
stream_args_rx.channels.push_back(i); stream_args_rx.channels.push_back(i);
s->rx_stream = s->usrp->get_rx_stream(stream_args_rx); s->rx_stream = s->usrp->get_rx_stream(stream_args_rx);
std::cout << boost::format("rx_max_num_samps %u") % (s->rx_stream->get_max_num_samps()) << std::endl; LOG_I(PHY,"rx_max_num_samps %u\n",s->rx_stream->get_max_num_samps());
//openair0_cfg[0].samples_per_packet = s->rx_stream->get_max_num_samps();
uhd::stream_args_t stream_args_tx("sc16", "sc16"); uhd::stream_args_t stream_args_tx("sc16", "sc16");
//stream_args_tx.args["spp"] = str(boost::format("%d") % 2048);//(openair0_cfg[0].tx_num_channels*openair0_cfg[0].samples_per_packet)); for (int i = 0; i<openair0_cfg[0].tx_num_channels; i++)
for (i = 0; i<openair0_cfg[0].tx_num_channels; i++)
stream_args_tx.channels.push_back(i); stream_args_tx.channels.push_back(i);
s->tx_stream = s->usrp->get_tx_stream(stream_args_tx); s->tx_stream = s->usrp->get_tx_stream(stream_args_tx);
std::cout << boost::format("tx_max_num_samps %u") % (s->tx_stream->get_max_num_samps()) << std::endl;
/* Setting TX/RX BW after streamers are created due to USRP calibration issue */ /* Setting TX/RX BW after streamers are created due to USRP calibration issue */
for(i=0;i<s->usrp->get_tx_num_channels();i++) { for(int i=0; i<s->usrp->get_tx_num_channels() && i<openair0_cfg[0].tx_num_channels; i++)
if (i<openair0_cfg[0].tx_num_channels) {
s->usrp->set_tx_bandwidth(openair0_cfg[0].tx_bw,i); s->usrp->set_tx_bandwidth(openair0_cfg[0].tx_bw,i);
printf("Setting tx freq/gain on channel %lu/%lu: BW %f (readback %f)\n",i,s->usrp->get_tx_num_channels(),openair0_cfg[0].tx_bw/1e6,s->usrp->get_tx_bandwidth(i)/1e6);
} for(int i=0; i<s->usrp->get_rx_num_channels() && i<openair0_cfg[0].rx_num_channels; i++)
}
for(i=0;i<s->usrp->get_rx_num_channels();i++) {
if (i<openair0_cfg[0].rx_num_channels) {
s->usrp->set_rx_bandwidth(openair0_cfg[0].rx_bw,i); s->usrp->set_rx_bandwidth(openair0_cfg[0].rx_bw,i);
printf("Setting rx freq/gain on channel %lu/%lu : BW %f (readback %f)\n",i,s->usrp->get_rx_num_channels(),openair0_cfg[0].rx_bw/1e6,s->usrp->get_rx_bandwidth(i)/1e6);
}
}
s->usrp->set_time_now(uhd::time_spec_t(0.0)); s->usrp->set_time_now(uhd::time_spec_t(0.0));
for (int i=0; i<openair0_cfg[0].rx_num_channels; i++) {
for (i=0;i<openair0_cfg[0].rx_num_channels;i++) { LOG_I(PHY,"RX Channel %d\n",i);
if (i<openair0_cfg[0].rx_num_channels) { LOG_I(PHY," Actual RX sample rate: %fMSps...\n",s->usrp->get_rx_rate(i)/1e6);
printf("RX Channel %lu\n",i); LOG_I(PHY," Actual RX frequency: %fGHz...\n", s->usrp->get_rx_freq(i)/1e9);
std::cout << boost::format("Actual RX sample rate: %fMSps...") % (s->usrp->get_rx_rate(i)/1e6) << std::endl; LOG_I(PHY," Actual RX gain: %f...\n", s->usrp->get_rx_gain(i));
std::cout << boost::format("Actual RX frequency: %fGHz...") % (s->usrp->get_rx_freq(i)/1e9) << std::endl; LOG_I(PHY," Actual RX bandwidth: %fM...\n", s->usrp->get_rx_bandwidth(i)/1e6);
std::cout << boost::format("Actual RX gain: %f...") % (s->usrp->get_rx_gain(i)) << std::endl; LOG_I(PHY," Actual RX antenna: %s...\n", s->usrp->get_rx_antenna(i).c_str());
std::cout << boost::format("Actual RX bandwidth: %fM...") % (s->usrp->get_rx_bandwidth(i)/1e6) << std::endl;
std::cout << boost::format("Actual RX antenna: %s...") % (s->usrp->get_rx_antenna(i)) << std::endl;
}
} }
for (i=0;i<openair0_cfg[0].tx_num_channels;i++) { for (int i=0; i<openair0_cfg[0].tx_num_channels; i++) {
LOG_I(PHY,"TX Channel %d\n",i);
if (i<openair0_cfg[0].tx_num_channels) { LOG_I(PHY," Actual TX sample rate: %fMSps...\n", s->usrp->get_tx_rate(i)/1e6);
printf("TX Channel %lu\n",i); LOG_I(PHY," Actual TX frequency: %fGHz...\n", s->usrp->get_tx_freq(i)/1e9);
std::cout << std::endl<<boost::format("Actual TX sample rate: %fMSps...") % (s->usrp->get_tx_rate(i)/1e6) << std::endl; LOG_I(PHY," Actual TX gain: %f...\n", s->usrp->get_tx_gain(i));
std::cout << boost::format("Actual TX frequency: %fGHz...") % (s->usrp->get_tx_freq(i)/1e9) << std::endl; LOG_I(PHY," Actual TX bandwidth: %fM...\n", s->usrp->get_tx_bandwidth(i)/1e6);
std::cout << boost::format("Actual TX gain: %f...") % (s->usrp->get_tx_gain(i)) << std::endl; LOG_I(PHY," Actual TX antenna: %s...\n", s->usrp->get_tx_antenna(i).c_str());
std::cout << boost::format("Actual TX bandwidth: %fM...") % (s->usrp->get_tx_bandwidth(i)/1e6) << std::endl;
std::cout << boost::format("Actual TX antenna: %s...") % (s->usrp->get_tx_antenna(i)) << std::endl;
}
} }
std::cout << boost::format("Device timestamp: %f...") % (s->usrp->get_time_now().get_real_secs()) << std::endl; LOG_I(PHY,"Device timestamp: %f...\n", s->usrp->get_time_now().get_real_secs());
device->priv = s; device->priv = s;
device->trx_start_func = trx_usrp_start; device->trx_start_func = trx_usrp_start;
......
...@@ -75,6 +75,103 @@ ...@@ -75,6 +75,103 @@
#include "UTIL/LOG/vcd_signal_dumper.h" #include "UTIL/LOG/vcd_signal_dumper.h"
#include "UTIL/OPT/opt.h" #include "UTIL/OPT/opt.h"
#define DEBUG_REALTIME 1
#if DEBUG_REALTIME
typedef struct latency_stat {
uint64_t counter;
uint64_t stat1100;
uint64_t stat1200;
uint64_t stat1500;
uint64_t stat2000;
uint64_t stat3000;
} latency_stat_t;
static inline void saif_meas(int frame_rx) {
static latency_stat_t __thread latency_stat;
static struct timespec __thread last= {0};
struct timespec now;
clock_gettime(CLOCK_MONOTONIC_RAW, &now);
if ( last.tv_sec ) {
uint64_t diffTime = ((uint64_t)now.tv_sec *1000 *1000 *1000 + now.tv_nsec) -
((uint64_t)last.tv_sec *1000 *1000 *1000 + last.tv_nsec);
diffTime/=1000;
latency_stat.counter++;
if ( diffTime >= 1100 ) {
if (diffTime < 1200 )
latency_stat.stat1100++;
else if ( diffTime < 1500 )
latency_stat.stat1200++;
else if ( diffTime < 2000 )
latency_stat.stat1500++;
else if ( diffTime < 3000 )
latency_stat.stat2000++;
else
latency_stat.stat3000++;
}
if ( diffTime>=1100 || latency_stat.counter%20000==0 ) {
time_t current=time(NULL);
LOG_W(HW,
"%.2f delay=%llu Period stats %2.6f%% below 100µs\ncumul of events: 1100=%ld 1200=%ld 1500=%ld 2000=%ld >3000=%ld - (frame_rx=%d) - %s",
now.tv_sec+(double)now.tv_nsec/1e9,
diffTime,
(latency_stat.counter-latency_stat.stat1100-latency_stat.stat1200-
latency_stat.stat1500-latency_stat.stat2000-latency_stat.stat3000)/
(float)latency_stat.counter *100,
latency_stat.stat1100, latency_stat.stat1200,
latency_stat.stat1500, latency_stat.stat2000,
latency_stat.stat3000,
frame_rx, ctime(&current));
fflush(stdout);
}
}
last=now;
}
typedef struct m {
unsigned long long iterations;
unsigned long long sum;
unsigned long long maxArray[11];
} Meas;
void printMeas(char * txt, Meas *M, int period) {
if (M->iterations%period == 0 ) {
char txt2[512];
sprintf(txt2,"%s avg=%llu, iterations=%llu, max=%llu/%llu/%llu/%llu/%llu/%llu/%llu/%llu/%llu/%llu\n",
txt, M->sum/M->iterations,M->iterations,
M->maxArray[1],M->maxArray[2], M->maxArray[3],M->maxArray[4],
M->maxArray[5], M->maxArray[6],M->maxArray[7], M->maxArray[8],M->maxArray[9],M->maxArray[10]);
LOG_W(PHY,txt2);
}
}
int cmpint(const void* a, const void* b) {
unsigned long long* aa=(unsigned long long*)a;
unsigned long long* bb=(unsigned long long*)b;
return (int)(*aa-*bb);
}
void updateTimes(unsigned long long start, Meas *M, int period, char * txt) {
unsigned long long end=rdtsc();
long long diff=(end-start)/(cpuf*1000);
M->maxArray[0]=diff;
M->sum+=diff;
M->iterations++;
qsort(M->maxArray, 11, sizeof(unsigned long long), cmpint);
printMeas(txt,M,period);
}
#else
#define check(a) do {} while (0)
#define saif_meas(a) do {} while (0)
#define update_max_times(a,b) do {} while (0)
#define print_meas(a,b) do {} while (0)
#endif
/* End of Changed by SYRTEM */
#define FRAME_PERIOD 100000000ULL #define FRAME_PERIOD 100000000ULL
#define DAQ_PERIOD 66667ULL #define DAQ_PERIOD 66667ULL
...@@ -84,6 +181,7 @@ typedef enum { ...@@ -84,6 +181,7 @@ typedef enum {
si=2 si=2
} sync_mode_t; } sync_mode_t;
void init_UE_threads(int nb_inst); void init_UE_threads(int nb_inst);
void *UE_thread(void *arg); void *UE_thread(void *arg);
void init_UE(int nb_inst); void init_UE(int nb_inst);
...@@ -92,7 +190,6 @@ extern pthread_cond_t sync_cond; ...@@ -92,7 +190,6 @@ extern pthread_cond_t sync_cond;
extern pthread_mutex_t sync_mutex; extern pthread_mutex_t sync_mutex;
extern int sync_var; extern int sync_var;
extern openair0_config_t openair0_cfg[MAX_CARDS]; extern openair0_config_t openair0_cfg[MAX_CARDS];
extern uint32_t downlink_frequency[MAX_NUM_CCs][4]; extern uint32_t downlink_frequency[MAX_NUM_CCs][4];
extern int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; extern int32_t uplink_frequency_offset[MAX_NUM_CCs][4];
...@@ -165,43 +262,69 @@ pthread_t main_ue_thread; ...@@ -165,43 +262,69 @@ pthread_t main_ue_thread;
pthread_attr_t attr_UE_thread; pthread_attr_t attr_UE_thread;
struct sched_param sched_param_UE_thread; struct sched_param sched_param_UE_thread;
void init_thread(int sched_runtime, int sched_deadline, int sched_fifo, cpu_set_t *cpuset, char * name) {
#ifdef DEADLINE_SCHEDULER
if (sched_runtime!=0) {
struct sched_attr attr= {0};
attr.size = sizeof(attr);
// This creates a .5 ms reservation
attr.sched_policy = SCHED_DEADLINE;
attr.sched_runtime = sched_runtime;
attr.sched_deadline = sched_deadline;
attr.sched_period = 0;
AssertFatal(sched_setattr(0, &attr, 0) == 0,
"[SCHED] main eNB thread: sched_setattr failed %s \n",perror(errno));
LOG_I(HW,"[SCHED][eNB] eNB main deadline thread %lu started on CPU %d\n",
(unsigned long)gettid(), sched_getcpu());
}
#else
if (cpuset!=NULL)
AssertFatal( 0 == pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), cpuset), "");
struct sched_param sp;
sp.sched_priority = sched_fifo;
AssertFatal(pthread_setschedparam(pthread_self(),SCHED_FIFO,&sp)==0,
"Can't set thread priority, Are you root?\n");
#endif
// Lock memory from swapping. This is a process wide call (not constraint to this thread).
mlockall(MCL_CURRENT | MCL_FUTURE);
pthread_setname_np( pthread_self(), name );
// LTS: this sync stuff should be wrong
printf("waiting for sync (%s)\n",name);
pthread_mutex_lock(&sync_mutex);
printf("Locked sync_mutex, waiting (%s)\n",name);
while (sync_var<0)
pthread_cond_wait(&sync_cond, &sync_mutex);
pthread_mutex_unlock(&sync_mutex);
printf("starting %s\n",name);
}
void init_UE(int nb_inst) { void init_UE(int nb_inst) {
int error_code;
int inst;
PHY_VARS_UE *UE; PHY_VARS_UE *UE;
int ret;
for (inst=0;inst<nb_inst;inst++) { for (int inst=0; inst<nb_inst; inst++) {
printf("Intializing UE Threads for instance %d ...\n",inst); printf("Intializing UE Threads for instance %d ...\n",inst);
init_UE_threads(inst); init_UE_threads(inst);
sleep(1); sleep(1);
UE = PHY_vars_UE_g[inst][0]; UE = PHY_vars_UE_g[inst][0];
ret = openair0_device_load(&(UE->rfdevice), &openair0_cfg[0]); AssertFatal(0== openair0_device_load(&(UE->rfdevice), &openair0_cfg[0]), "");
if (ret !=0){
exit_fun("Error loading device library");
}
UE->rfdevice.host_type = BBU_HOST; UE->rfdevice.host_type = BBU_HOST;
// UE->rfdevice.type = NONE_DEV; // UE->rfdevice.type = NONE_DEV;
error_code = pthread_create(&UE->proc.pthread_ue, &UE->proc.attr_ue, UE_thread, NULL); AssertFatal(0 == pthread_create(&UE->proc.pthread_ue, &UE->proc.attr_ue, UE_thread, NULL), "");
if (error_code!= 0) {
LOG_D(HW,"[lte-softmodem.c] Could not allocate UE_thread, error %d\n",error_code);
return;
} else {
LOG_D(HW, "[lte-softmodem.c] Allocate UE_thread successful\n" );
pthread_setname_np( UE->proc.pthread_ue, "main UE" ); pthread_setname_np( UE->proc.pthread_ue, "main UE" );
} }
}
printf("UE threads created\n"); printf("UE threads created\n");
#ifdef USE_MME #ifdef USE_MME
while (start_UE == 0) { while (start_UE == 0) {
sleep(1); sleep(1);
} }
#endif #endif
} }
...@@ -212,9 +335,8 @@ void init_UE(int nb_inst) { ...@@ -212,9 +335,8 @@ void init_UE(int nb_inst) {
* \param arg is a pointer to a \ref PHY_VARS_UE structure. * \param arg is a pointer to a \ref PHY_VARS_UE structure.
* \returns a pointer to an int. The storage is not on the heap and must not be freed. * \returns a pointer to an int. The storage is not on the heap and must not be freed.
*/ */
static void *UE_thread_synch(void *arg) static void *UE_thread_synch(void *arg) {
{ static int __thread UE_thread_synch_retval;
static int UE_thread_synch_retval;
int i, hw_slot_offset; int i, hw_slot_offset;
PHY_VARS_UE *UE = (PHY_VARS_UE*) arg; PHY_VARS_UE *UE = (PHY_VARS_UE*) arg;
int current_band = 0; int current_band = 0;
...@@ -239,33 +361,29 @@ static void *UE_thread_synch(void *arg) ...@@ -239,33 +361,29 @@ static void *UE_thread_synch(void *arg)
/* CPU 0 is reserved for UHD threads */ /* CPU 0 is reserved for UHD threads */
CPU_ZERO(&cpuset); CPU_ZERO(&cpuset);
#ifdef CPU_AFFINITY #ifdef CPU_AFFINITY
if (get_nprocs() >2) if (get_nprocs() >2) {
{
for (j = 1; j < get_nprocs(); j++) for (j = 1; j < get_nprocs(); j++)
CPU_SET(j, &cpuset); CPU_SET(j, &cpuset);
s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0) if (s != 0) {
{
perror( "pthread_setaffinity_np"); perror( "pthread_setaffinity_np");
exit_fun("Error setting processor affinity"); exit_fun("Error setting processor affinity");
} }
} }
#endif #endif
/* Check the actual affinity mask assigned to the thread */ /* Check the actual affinity mask assigned to the thread */
s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0) if (s != 0) {
{
perror( "pthread_getaffinity_np"); perror( "pthread_getaffinity_np");
exit_fun("Error getting processor affinity "); exit_fun("Error getting processor affinity ");
} }
memset(cpu_affinity, 0 , sizeof(cpu_affinity)); memset(cpu_affinity, 0 , sizeof(cpu_affinity));
for (j = 0; j < CPU_SETSIZE; j++) for (j = 0; j < CPU_SETSIZE; j++)
if (CPU_ISSET(j, &cpuset)) if (CPU_ISSET(j, &cpuset)) {
{
char temp[1024]; char temp[1024];
sprintf(temp, " CPU_%d ", j); sprintf(temp, " CPU_%d ", j);
strcat(cpu_affinity, temp); strcat(cpu_affinity, temp);
...@@ -276,14 +394,12 @@ static void *UE_thread_synch(void *arg) ...@@ -276,14 +394,12 @@ static void *UE_thread_synch(void *arg)
policy = SCHED_FIFO ; policy = SCHED_FIFO ;
s = pthread_setschedparam(pthread_self(), policy, &sparam); s = pthread_setschedparam(pthread_self(), policy, &sparam);
if (s != 0) if (s != 0) {
{
perror("pthread_setschedparam : "); perror("pthread_setschedparam : ");
exit_fun("Error setting thread priority"); exit_fun("Error setting thread priority");
} }
s = pthread_getschedparam(pthread_self(), &policy, &sparam); s = pthread_getschedparam(pthread_self(), &policy, &sparam);
if (s != 0) if (s != 0) {
{
perror("pthread_getschedparam : "); perror("pthread_getschedparam : ");
exit_fun("Error getting thread priority"); exit_fun("Error getting thread priority");
...@@ -298,9 +414,6 @@ static void *UE_thread_synch(void *arg) ...@@ -298,9 +414,6 @@ static void *UE_thread_synch(void *arg)
#endif #endif
printf("starting UE synch thread (IC %d)\n",UE->proc.instance_cnt_synch); printf("starting UE synch thread (IC %d)\n",UE->proc.instance_cnt_synch);
ind = 0; ind = 0;
found = 0; found = 0;
...@@ -334,7 +447,7 @@ static void *UE_thread_synch(void *arg) ...@@ -334,7 +447,7 @@ static void *UE_thread_synch(void *arg)
LOG_I( PHY, "[SCHED][UE] Check absolute frequency DL %"PRIu32", UL %"PRIu32" (oai_exit %d, rx_num_channels %d)\n", downlink_frequency[0][0], downlink_frequency[0][0]+uplink_frequency_offset[0][0],oai_exit, openair0_cfg[0].rx_num_channels); LOG_I( PHY, "[SCHED][UE] Check absolute frequency DL %"PRIu32", UL %"PRIu32" (oai_exit %d, rx_num_channels %d)\n", downlink_frequency[0][0], downlink_frequency[0][0]+uplink_frequency_offset[0][0],oai_exit, openair0_cfg[0].rx_num_channels);
for (i=0;i<openair0_cfg[UE->rf_map.card].rx_num_channels;i++) { for (i=0; i<openair0_cfg[UE->rf_map.card].rx_num_channels; i++) {
openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] = downlink_frequency[CC_id][i]; openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] = downlink_frequency[CC_id][i];
openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] = downlink_frequency[CC_id][i]+uplink_frequency_offset[CC_id][i]; openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] = downlink_frequency[CC_id][i]+uplink_frequency_offset[CC_id][i];
openair0_cfg[UE->rf_map.card].autocal[UE->rf_map.chain+i] = 1; openair0_cfg[UE->rf_map.card].autocal[UE->rf_map.chain+i] = 1;
...@@ -445,7 +558,7 @@ static void *UE_thread_synch(void *arg) ...@@ -445,7 +558,7 @@ static void *UE_thread_synch(void *arg)
UE->UE_scan_carrier = 0; UE->UE_scan_carrier = 0;
// rerun with new cell parameters and frequency-offset // rerun with new cell parameters and frequency-offset
for (i=0;i<openair0_cfg[UE->rf_map.card].rx_num_channels;i++) { for (i=0; i<openair0_cfg[UE->rf_map.card].rx_num_channels; i++) {
openair0_cfg[UE->rf_map.card].rx_gain[UE->rf_map.chain+i] = UE->rx_total_gain_dB;//-USRP_GAIN_OFFSET; openair0_cfg[UE->rf_map.card].rx_gain[UE->rf_map.chain+i] = UE->rx_total_gain_dB;//-USRP_GAIN_OFFSET;
openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] -= UE->common_vars.freq_offset; openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] -= UE->common_vars.freq_offset;
openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] = openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i]+uplink_frequency_offset[CC_id][i]; openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] = openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i]+uplink_frequency_offset[CC_id][i];
...@@ -490,11 +603,10 @@ static void *UE_thread_synch(void *arg) ...@@ -490,11 +603,10 @@ static void *UE_thread_synch(void *arg)
LOG_E(HW,"Could not start the device\n"); LOG_E(HW,"Could not start the device\n");
oai_exit=1; oai_exit=1;
} }
} } else {
else {
UE->is_synchronized = 1; UE->is_synchronized = 1;
if( UE->mode == rx_dump_frame ){ if( UE->mode == rx_dump_frame ) {
FILE *fd; FILE *fd;
if ((UE->proc.proc_rxtx[0].frame_rx&1) == 0) { // this guarantees SIB1 is present if ((UE->proc.proc_rxtx[0].frame_rx&1) == 0) { // this guarantees SIB1 is present
if ((fd = fopen("rxsig_frame0.dat","w")) != NULL) { if ((fd = fopen("rxsig_frame0.dat","w")) != NULL) {
...@@ -505,13 +617,11 @@ static void *UE_thread_synch(void *arg) ...@@ -505,13 +617,11 @@ static void *UE_thread_synch(void *arg)
LOG_I(PHY,"Dummping Frame ... bye bye \n"); LOG_I(PHY,"Dummping Frame ... bye bye \n");
fclose(fd); fclose(fd);
exit(0); exit(0);
} } else {
else {
LOG_E(PHY,"Cannot open file for writing\n"); LOG_E(PHY,"Cannot open file for writing\n");
exit(0); exit(0);
} }
} } else {
else {
UE->is_synchronized = 0; UE->is_synchronized = 0;
} }
} }
...@@ -542,8 +652,7 @@ static void *UE_thread_synch(void *arg) ...@@ -542,8 +652,7 @@ static void *UE_thread_synch(void *arg)
mac_xface->macphy_exit("No cell synchronization found, abandoning"); mac_xface->macphy_exit("No cell synchronization found, abandoning");
return &UE_thread_synch_retval; // not reached return &UE_thread_synch_retval; // not reached
} }
} } else {
else {
} }
LOG_I( PHY, "[initial_sync] trying carrier off %d Hz, rxgain %d (DL %u, UL %u)\n", LOG_I( PHY, "[initial_sync] trying carrier off %d Hz, rxgain %d (DL %u, UL %u)\n",
...@@ -606,159 +715,38 @@ static void *UE_thread_synch(void *arg) ...@@ -606,159 +715,38 @@ static void *UE_thread_synch(void *arg)
* \returns a pointer to an int. The storage is not on the heap and must not be freed. * \returns a pointer to an int. The storage is not on the heap and must not be freed.
*/ */
static void *UE_thread_rxn_txnp4(void *arg) static void *UE_thread_rxn_txnp4(void *arg) {
{ static __thread int UE_thread_rxtx_retval;
static int UE_thread_rxtx_retval;
UE_rxtx_proc_t *proc = (UE_rxtx_proc_t *)arg; UE_rxtx_proc_t *proc = (UE_rxtx_proc_t *)arg;
int ret; int ret;
PHY_VARS_UE *UE=PHY_vars_UE_g[0][proc->CC_id]; PHY_VARS_UE *UE=PHY_vars_UE_g[0][proc->CC_id];
proc->instance_cnt_rxtx=-1;
static long long __thread instance_cnt_rxtx=-1;
proc->subframe_rx=proc->sub_frame_start;
#ifdef DEADLINE_SCHEDULER char threadName[256]= {0};
sprintf(threadName,"UE_thread_rxn_txnp4_%d",proc->sub_frame_start);
struct sched_attr attr;
unsigned int flags = 0;
attr.size = sizeof(attr);
attr.sched_flags = 0;
attr.sched_nice = 0;
attr.sched_priority = 0;
// This creates a .5ms reservation every 1ms period
attr.sched_policy = SCHED_DEADLINE;
attr.sched_runtime = 900000; // each rx thread requires 1ms to finish its job
attr.sched_deadline = 1000000; // each rx thread will finish within 1ms
attr.sched_period = 1000000; // each rx thread has a period of 1ms from the starting point
if (sched_setattr(0, &attr, flags) < 0 ) {
perror("[SCHED] UE_thread_rxtx : sched_setattr failed\n");
return &UE_thread_rxtx_retval;
}
#else
int policy, s, j;
struct sched_param sparam;
char cpu_affinity[1024];
cpu_set_t cpuset; cpu_set_t cpuset;
/* Set affinity mask to include CPUs 1 to MAX_CPUS */
/* CPU 0 is reserved for UHD threads */
CPU_ZERO(&cpuset); CPU_ZERO(&cpuset);
CPU_SET(proc->sub_frame_start+1, &cpuset);
#ifdef CPU_AFFINITY init_thread(900000,1000000 , 40, &cpuset,//sched_get_priority_max(SCHED_FIFO)-1,
if (get_nprocs() >2) threadName);
{
for (j = 1; j < get_nprocs(); j++)
CPU_SET(j, &cpuset);
s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0)
{
perror( "pthread_setaffinity_np");
exit_fun("Error setting processor affinity");
}
}
#endif
/* Check the actual affinity mask assigned to the thread */
s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
if (s != 0)
{
perror( "pthread_getaffinity_np");
exit_fun("Error getting processor affinity ");
}
memset(cpu_affinity, 0 , sizeof(cpu_affinity));
for (j = 0; j < CPU_SETSIZE; j++)
if (CPU_ISSET(j, &cpuset))
{
char temp[1024];
sprintf(temp, " CPU_%d ", j);
strcat(cpu_affinity, temp);
}
memset(&sparam, 0 , sizeof (sparam));
sparam.sched_priority = sched_get_priority_max(SCHED_FIFO)-1;
policy = SCHED_FIFO ;
s = pthread_setschedparam(pthread_self(), policy, &sparam);
if (s != 0)
{
perror("pthread_setschedparam : ");
exit_fun("Error setting thread priority");
}
s = pthread_getschedparam(pthread_self(), &policy, &sparam);
if (s != 0)
{
perror("pthread_getschedparam : ");
exit_fun("Error getting thread priority");
}
LOG_I( HW, "[SCHED][UE] Started UE RX thread on CPU %d TID %ld , sched_policy = %s, priority = %d, CPU Affinity = %s \n", (int)sched_getcpu(), gettid(),
(policy == SCHED_FIFO) ? "SCHED_FIFO" :
(policy == SCHED_RR) ? "SCHED_RR" :
(policy == SCHED_OTHER) ? "SCHED_OTHER" :
"???",
(int) sparam.sched_priority, cpu_affinity);
#endif
// Lock memory from swapping. This is a process wide call (not constraint to this thread).
mlockall(MCL_CURRENT | MCL_FUTURE);
printf("waiting for sync (UE_thread_rxn_txnp4)\n");
pthread_mutex_lock(&sync_mutex);
printf("Locked sync_mutex, waiting (UE_thread_rxn_txnp4)\n");
while (sync_var<0)
pthread_cond_wait(&sync_cond, &sync_mutex);
#define THREAD_NAME_LEN 16
char threadname[THREAD_NAME_LEN];
ret = pthread_getname_np(proc->pthread_rxtx, threadname, THREAD_NAME_LEN);
if (ret != 0)
{
perror("pthread_getname_np : ");
exit_fun("Error getting thread name");
}
pthread_mutex_unlock(&sync_mutex);
printf("unlocked sync_mutex, waiting (UE_thread_rxtx)\n");
printf("Starting UE RXN_TXNP4 thread (%s)\n", threadname);
while (!oai_exit) { while (!oai_exit) {
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_COND_WAIT0+(proc->subframe_rx&1), 1 ); // Wait Rx data to process are available
if (pthread_mutex_lock(&proc->mutex_rxtx) != 0) { AssertFatal(pthread_mutex_lock(&proc->mutex_rxtx) ==0,"");
LOG_E( PHY, "[SCHED][UE] error locking mutex for UE RXTX\n" );
exit_fun("nothing to add");
return &UE_thread_rxtx_retval;
}
while (proc->instance_cnt_rxtx < 0) {
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_WAIT_COND_RXTX0+(proc->subframe_rx&1), 1 );
// most of the time, the thread is waiting here
pthread_cond_wait( &proc->cond_rxtx, &proc->mutex_rxtx ); pthread_cond_wait( &proc->cond_rxtx, &proc->mutex_rxtx );
} if ( (instance_cnt_rxtx+proc->sub_frame_step)%10 != proc->subframe_rx && instance_cnt_rxtx!=-1 )
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_WAIT_COND_RXTX0+(proc->subframe_rx&1), 0 ); LOG_W(PHY,"REAL TIME NOT MATCHED: missed a sub-frame: expecting %d, got %d\n",
(instance_cnt_rxtx+proc->sub_frame_step)%10, proc->subframe_rx);
if (pthread_mutex_unlock(&proc->mutex_rxtx) != 0) { instance_cnt_rxtx=proc->subframe_rx;
LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE RXn_TXnp4\n" ); AssertFatal(pthread_mutex_unlock(&proc->mutex_rxtx) ==0,"");
exit_fun("nothing to add");
return &UE_thread_rxtx_retval;
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_COND_WAIT0+(proc->subframe_rx&1), 0 );
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_RXTX0+(proc->subframe_rx&1), 1 ); static __thread Meas t2= {0}, t3= {0};
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX0_UE+(proc->subframe_rx&1), proc->subframe_rx ); unsigned long long current=rdtsc();
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX0_UE+(proc->subframe_tx&1), proc->subframe_tx ); updateTimes(proc->gotIQs, &t2, 10000, "saif: Delay to wake up UE_Thread_Rx (case 2)");
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_UE+(proc->subframe_rx&1), proc->frame_rx );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_UE+(proc->subframe_tx&1), proc->frame_tx );
// Process Rx data for one sub-frame
lte_subframe_t sf_type = subframe_select( &UE->frame_parms, proc->subframe_rx); lte_subframe_t sf_type = subframe_select( &UE->frame_parms, proc->subframe_rx);
if ((sf_type == SF_DL) || if ((sf_type == SF_DL) ||
(UE->frame_parms.frame_type == FDD) || (UE->frame_parms.frame_type == FDD) ||
...@@ -766,14 +754,14 @@ static void *UE_thread_rxn_txnp4(void *arg) ...@@ -766,14 +754,14 @@ static void *UE_thread_rxn_txnp4(void *arg)
if (UE->frame_parms.frame_type == TDD) { if (UE->frame_parms.frame_type == TDD) {
LOG_D(PHY, "%s,TDD%d,%s: calling UE_RX\n", LOG_D(PHY, "%s,TDD%d,%s: calling UE_RX\n",
threadname, threadName,
UE->frame_parms.tdd_config, UE->frame_parms.tdd_config,
(sf_type==SF_DL? "SF_DL" : (sf_type==SF_DL? "SF_DL" :
(sf_type==SF_UL? "SF_UL" : (sf_type==SF_UL? "SF_UL" :
(sf_type==SF_S ? "SF_S" : "UNKNOWN_SF_TYPE")))); (sf_type==SF_S ? "SF_S" : "UNKNOWN_SF_TYPE"))));
} else { } else {
LOG_D(PHY, "%s,%s,%s: calling UE_RX\n", LOG_D(PHY, "%s,%s,%s: calling UE_RX\n",
threadname, threadName,
(UE->frame_parms.frame_type==FDD? "FDD": (UE->frame_parms.frame_type==FDD? "FDD":
(UE->frame_parms.frame_type==TDD? "TDD":"UNKNOWN_DUPLEX_MODE")), (UE->frame_parms.frame_type==TDD? "TDD":"UNKNOWN_DUPLEX_MODE")),
(sf_type==SF_DL? "SF_DL" : (sf_type==SF_DL? "SF_DL" :
...@@ -793,67 +781,45 @@ static void *UE_thread_rxn_txnp4(void *arg) ...@@ -793,67 +781,45 @@ static void *UE_thread_rxn_txnp4(void *arg)
subframe_select(&UE->frame_parms,proc->subframe_tx), subframe_select(&UE->frame_parms,proc->subframe_tx),
0, 0,
0/*FIXME CC_id*/); 0/*FIXME CC_id*/);
if ( ret != CONNECTION_OK) {
if (ret == CONNECTION_LOST) { char *txt;
LOG_E( PHY, "[UE %"PRIu8"] Frame %"PRIu32", subframe %u RRC Connection lost, returning to PRACH\n", switch (ret) {
UE->Mod_id, proc->frame_rx, proc->subframe_tx ); case CONNECTION_LOST:
UE->UE_mode[0] = PRACH; txt="RRC Connection lost, returning to PRACH";
} else if (ret == PHY_RESYNCH) { break;
LOG_E( PHY, "[UE %"PRIu8"] Frame %"PRIu32", subframe %u RRC Connection lost, trying to resynch\n", case PHY_RESYNCH:
UE->Mod_id, proc->frame_rx, proc->subframe_tx ); txt="RRC Connection lost, trying to resynch";
UE->UE_mode[0] = RESYNCH; break;
} else if (ret == PHY_HO_PRACH) { case RESYNCH:
LOG_I( PHY, "[UE %"PRIu8"] Frame %"PRIu32", subframe %u, return to PRACH and perform a contention-free access\n", txt="return to PRACH and perform a contention-free access";
UE->Mod_id, proc->frame_rx, proc->subframe_tx ); break;
UE->UE_mode[0] = PRACH; default:
txt="UNKNOWN RETURN CODE";
};
LOG_E( PHY, "[UE %"PRIu8"] Frame %"PRIu32", subframe %u %s\n",
UE->Mod_id, proc->frame_rx, proc->subframe_tx,txt );
} }
} }
// Prepare the future Tx data
if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_UL) || if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_UL) ||
(UE->frame_parms.frame_type == FDD) ) { (UE->frame_parms.frame_type == FDD) )
if (UE->mode != loop_through_memory)
if (UE->mode != loop_through_memory) {
phy_procedures_UE_TX(UE,proc,0,0,UE->mode,no_relay); phy_procedures_UE_TX(UE,proc,0,0,UE->mode,no_relay);
}
}
if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_S) &&
(UE->frame_parms.frame_type == TDD)) {
if (UE->mode != loop_through_memory) { if ((subframe_select( &UE->frame_parms, proc->subframe_tx) == SF_S) &&
(UE->frame_parms.frame_type == TDD))
if (UE->mode != loop_through_memory)
phy_procedures_UE_S_TX(UE,0,0,no_relay); phy_procedures_UE_S_TX(UE,0,0,no_relay);
} updateTimes(current, &t3, 10000, "saif: Delay to process sub-frame (case 3)");
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_RXTX0+(proc->subframe_rx&1), 0 );
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_CNT_DECREMENT0+(proc->subframe_rx&1), 1 );
if (pthread_mutex_lock(&proc->mutex_rxtx) != 0) {
LOG_E( PHY, "[SCHED][UE] error locking mutex for UE RXTX\n" );
exit_fun("noting to add");
return &UE_thread_rxtx_retval;
}
proc->instance_cnt_rxtx--;
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE_INST_CNT_RX, proc->instance_cnt_rxtx);
if (pthread_mutex_unlock(&proc->mutex_rxtx) != 0) {
LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE RXTX\n" );
exit_fun("noting to add");
return &UE_thread_rxtx_retval;
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_CNT_DECREMENT0+(proc->subframe_rx&1), 0 );
} }
// thread finished // thread finished
return &UE_thread_rxtx_retval; return &UE_thread_rxtx_retval;
} }
#define RX_OFF_MAX 10 #define RX_OFF_MAX 10
#define RX_OFF_MIN 5 #define RX_OFF_MIN 5
#define RX_OFF_MID ((RX_OFF_MAX+RX_OFF_MIN)/2) #define RX_OFF_MID ((RX_OFF_MAX+RX_OFF_MIN)/2)
...@@ -870,122 +836,54 @@ static void *UE_thread_rxn_txnp4(void *arg) ...@@ -870,122 +836,54 @@ static void *UE_thread_rxn_txnp4(void *arg)
void *UE_thread(void *arg) { void *UE_thread(void *arg) {
static int UE_thread_retval;
PHY_VARS_UE *UE = PHY_vars_UE_g[0][0]; PHY_VARS_UE *UE = PHY_vars_UE_g[0][0];
// int tx_enabled = 0; // int tx_enabled = 0;
unsigned int rxs,txs;
int dummy_rx[UE->frame_parms.nb_antennas_rx][UE->frame_parms.samples_per_tti] __attribute__((aligned(32))); int dummy_rx[UE->frame_parms.nb_antennas_rx][UE->frame_parms.samples_per_tti] __attribute__((aligned(32)));
openair0_timestamp timestamp,timestamp1; openair0_timestamp timestamp,timestamp1;
void* rxp[2], *txp[2]; void* rxp[NB_ANTENNAS_RX], *txp[NB_ANTENNAS_TX];
#ifdef NAS_UE
MessageDef *message_p;
#endif
int start_rx_stream = 0; int start_rx_stream = 0;
int rx_off_diff = 0;
int rx_correction_timer = 0;
int i; int i;
#ifdef DEADLINE_SCHEDULER cpu_set_t cpuset;
CPU_ZERO(&cpuset);
struct sched_attr attr; CPU_SET(3, &cpuset);
unsigned int flags = 0; init_thread(100000, 500000, 40, &cpuset, //sched_get_priority_max(SCHED_FIFO),
"main UE");
attr.size = sizeof(attr);
attr.sched_flags = 0;
attr.sched_nice = 0;
attr.sched_priority = 0;//sched_get_priority_max(SCHED_DEADLINE);
// This creates a .5 ms reservation
attr.sched_policy = SCHED_DEADLINE;
attr.sched_runtime = 100000;
attr.sched_deadline = 500000;
attr.sched_period = 500000;
if (sched_setattr(0, &attr, flags) < 0 ) {
perror("[SCHED] main eNB thread: sched_setattr failed\n");
exit_fun("Nothing to add");
return &UE_thread_retval;
}
LOG_I(HW,"[SCHED][eNB] eNB main deadline thread %lu started on CPU %d\n",
(unsigned long)gettid(), sched_getcpu());
#else
struct sched_param sp;
sp.sched_priority = sched_get_priority_max(SCHED_FIFO);
pthread_setschedparam(pthread_self(),SCHED_FIFO,&sp);
#endif
// Lock memory from swapping. This is a process wide call (not constraint to this thread).
mlockall(MCL_CURRENT | MCL_FUTURE);
printf("waiting for sync (UE_thread)\n");
pthread_mutex_lock(&sync_mutex);
printf("Locked sync_mutex, waiting (UE_thread)\n");
while (sync_var<0)
pthread_cond_wait(&sync_cond, &sync_mutex);
pthread_mutex_unlock(&sync_mutex);
printf("unlocked sync_mutex, waiting (UE_thread)\n");
printf("starting UE thread\n");
#ifdef NAS_UE #ifdef NAS_UE
MessageDef *message_p;
message_p = itti_alloc_new_message(TASK_NAS_UE, INITIALIZE_MESSAGE); message_p = itti_alloc_new_message(TASK_NAS_UE, INITIALIZE_MESSAGE);
itti_send_msg_to_task (TASK_NAS_UE, INSTANCE_DEFAULT, message_p); itti_send_msg_to_task (TASK_NAS_UE, INSTANCE_DEFAULT, message_p);
#endif #endif
int sub_frame=-1;
int cumulated_shift=0;
while (!oai_exit) { while (!oai_exit) {
if (UE->is_synchronized == 0) { if (UE->is_synchronized == 0) {
if (pthread_mutex_lock(&UE->proc.mutex_synch) != 0) { AssertFatal ( 0== pthread_mutex_lock(&UE->proc.mutex_synch), "");
LOG_E( PHY, "[SCHED][UE] verror locking mutex for UE initial synch thread\n" );
exit_fun("nothing to add");
return &UE_thread_retval;
}
int instance_cnt_synch = UE->proc.instance_cnt_synch; int instance_cnt_synch = UE->proc.instance_cnt_synch;
AssertFatal ( 0== pthread_mutex_unlock(&UE->proc.mutex_synch), "");
if (pthread_mutex_unlock(&UE->proc.mutex_synch) != 0) {
LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE initial synch thread\n" );
exit_fun("nothing to add");
return &UE_thread_retval;
}
if (instance_cnt_synch < 0) { // we can invoke the synch if (instance_cnt_synch < 0) { // we can invoke the synch
// grab 10 ms of signal and wakeup synch thread // grab 10 ms of signal and wakeup synch thread
for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++) for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++)
rxp[i] = (void*)&rxdata[i][0]; rxp[i] = (void*)&rxdata[i][0];
if (UE->mode != loop_through_memory) { if (UE->mode != loop_through_memory)
rxs = UE->rfdevice.trx_read_func(&UE->rfdevice, AssertFatal( UE->frame_parms.samples_per_tti*10 ==
UE->rfdevice.trx_read_func(&UE->rfdevice,
&timestamp, &timestamp,
rxp, rxp,
UE->frame_parms.samples_per_tti*10, UE->frame_parms.samples_per_tti*10,
UE->frame_parms.nb_antennas_rx); UE->frame_parms.nb_antennas_rx), "");
if (rxs!=UE->frame_parms.samples_per_tti*10) {
LOG_E(PHY, "problem in rx 1! want #samples=%d but got only %d!\n", UE->frame_parms.samples_per_tti*10, rxs);
exit_fun("problem in rx 1");
return &UE_thread_retval;
}
}
instance_cnt_synch = ++UE->proc.instance_cnt_synch; instance_cnt_synch = ++UE->proc.instance_cnt_synch;
if (instance_cnt_synch == 0) { if (instance_cnt_synch == 0) {
if (pthread_cond_signal(&UE->proc.cond_synch) != 0) { AssertFatal( 0 == pthread_cond_signal(&UE->proc.cond_synch), "");
LOG_E( PHY, "[SCHED][UE] ERROR pthread_cond_signal for UE sync thread\n" );
exit_fun("nothing to add");
return &UE_thread_retval;
}
} else { } else {
LOG_E( PHY, "[SCHED][UE] UE sync thread busy!!\n" ); LOG_E( PHY, "[SCHED][UE] UE sync thread busy!!\n" );
exit_fun("nothing to add"); exit_fun("nothing to add");
return &UE_thread_retval;
} }
} // } //
else { else {
...@@ -994,19 +892,14 @@ void *UE_thread(void *arg) { ...@@ -994,19 +892,14 @@ void *UE_thread(void *arg) {
if (UE->mode != loop_through_memory) { if (UE->mode != loop_through_memory) {
for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++) for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++)
rxp[i] = (void*)&dummy_rx[i][0]; rxp[i] = (void*)&dummy_rx[i][0];
for (int sf=0;sf<10;sf++) { for (int sf=0; sf<10; sf++) {
// printf("Reading dummy sf %d\n",sf); // printf("Reading dummy sf %d\n",sf);
rxs = UE->rfdevice.trx_read_func(&UE->rfdevice, AssertFatal ( UE->frame_parms.samples_per_tti ==
UE->rfdevice.trx_read_func(&UE->rfdevice,
&timestamp, &timestamp,
rxp, rxp,
UE->frame_parms.samples_per_tti, UE->frame_parms.samples_per_tti,
UE->frame_parms.nb_antennas_rx); UE->frame_parms.nb_antennas_rx), "");
if (rxs!=UE->frame_parms.samples_per_tti){
LOG_E(PHY, "problem in rx 2! want #samples=%d but got only %d!\n", UE->frame_parms.samples_per_tti, rxs);
exit_fun("problem in rx 2");
return &UE_thread_retval;
}
} }
} }
...@@ -1017,617 +910,134 @@ void *UE_thread(void *arg) { ...@@ -1017,617 +910,134 @@ void *UE_thread(void *arg) {
if (start_rx_stream==0) { if (start_rx_stream==0) {
start_rx_stream=1; start_rx_stream=1;
if (UE->mode != loop_through_memory) { if (UE->mode != loop_through_memory) {
if (UE->no_timing_correction==0) { if (UE->no_timing_correction==0) {
LOG_I(PHY,"Resynchronizing RX by %d samples (mode = %d)\n",UE->rx_offset,UE->mode); LOG_I(PHY,"Resynchronizing RX by %d samples (mode = %d)\n",UE->rx_offset,UE->mode);
rxs = UE->rfdevice.trx_read_func(&UE->rfdevice, AssertFatal(UE->rx_offset ==
UE->rfdevice.trx_read_func(&UE->rfdevice,
&timestamp, &timestamp,
(void**)rxdata, (void**)rxdata,
UE->rx_offset, UE->rx_offset,
UE->frame_parms.nb_antennas_rx); UE->frame_parms.nb_antennas_rx),"");
if (rxs != UE->rx_offset) {
LOG_E(PHY, "problem in rx 3! want #samples=%d but got only %d!\n", UE->rx_offset, rxs);
exit_fun("problem in rx 3!");
return &UE_thread_retval;
}
} }
UE->rx_offset=0; UE->rx_offset=0;
UE->proc.proc_rxtx[0].frame_rx++; UE->proc.proc_rxtx[0].frame_rx++;
UE->proc.proc_rxtx[1].frame_rx++; UE->proc.proc_rxtx[1].frame_rx++;
// read in first symbol // read in first symbol
rxs = UE->rfdevice.trx_read_func(&UE->rfdevice, AssertFatal (UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0 ==
UE->rfdevice.trx_read_func(&UE->rfdevice,
&timestamp, &timestamp,
(void**)rxdata, (void**)rxdata,
UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0, UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0,
UE->frame_parms.nb_antennas_rx); UE->frame_parms.nb_antennas_rx),"");
if (rxs != (UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0)) { slot_fep(UE,0, 0, 0, 0, 0);
LOG_E(PHY, "problem in rx 4! want #samples=%d but got only %d!\n", UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0, rxs);
exit_fun("problem in rx 4!");
return &UE_thread_retval;
}
slot_fep(UE,
0,
0,
0,
0,
0);
if (rxs != UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0) {
exit_fun("problem in rx");
return &UE_thread_retval;
}
} //UE->mode != loop_through_memory } //UE->mode != loop_through_memory
else else
rt_sleep_ns(1000000); rt_sleep_ns(1000*1000);
}// start_rx_stream==0 } else {
else { sub_frame++;
//UE->proc.proc_rxtx[0].frame_rx++; sub_frame%=10;
//UE->proc.proc_rxtx[1].frame_rx++; UE_rxtx_proc_t *proc = &UE->proc.proc_rxtx[sub_frame&1];
for (int sf=0;sf<10;sf++) {
for (i=0; i<UE->frame_parms.nb_antennas_rx; i++)
rxp[i] = (void*)&rxdata[i][UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0+(sf*UE->frame_parms.samples_per_tti)];
// grab signal for subframe
if (UE->mode != loop_through_memory) { if (UE->mode != loop_through_memory) {
if (sf<9) { for (i=0; i<UE->frame_parms.nb_antennas_rx; i++)
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 ); rxp[i] = (void*)&rxdata[i][UE->frame_parms.ofdm_symbol_size+
rxs = UE->rfdevice.trx_read_func(&UE->rfdevice, UE->frame_parms.nb_prefix_samples0+
&timestamp, sub_frame*UE->frame_parms.samples_per_tti];
rxp,
UE->frame_parms.samples_per_tti,
UE->frame_parms.nb_antennas_rx);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_UE0_TRX_READ_NS, rxs );
if (rxs != UE->frame_parms.samples_per_tti) {
LOG_E(PHY, "problem in rx 5! want #samples=%d but got only %d!\n", UE->frame_parms.samples_per_tti, rxs);
exit_fun("problem in rx 5!");
return &UE_thread_retval;
}
// prepare tx buffer pointers
for (i=0; i<UE->frame_parms.nb_antennas_tx; i++) for (i=0; i<UE->frame_parms.nb_antennas_tx; i++)
txp[i] = (void*)&UE->common_vars.txdata[i][((sf+2)%10)*UE->frame_parms.samples_per_tti]; txp[i] = (void*)&UE->common_vars.txdata[i][((sub_frame+2)%10)*UE->frame_parms.samples_per_tti];
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 ); int readBlockSize, writeBlockSize;
txs = UE->rfdevice.trx_write_func(&UE->rfdevice, if (sub_frame<9) {
timestamp+ readBlockSize=UE->frame_parms.samples_per_tti;
(2*UE->frame_parms.samples_per_tti) - writeBlockSize=UE->frame_parms.samples_per_tti;
UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0 - } else {
openair0_cfg[0].tx_sample_advance, int rx_off_diff;
txp, if ( UE->rx_offset< 5*UE->frame_parms.samples_per_tti )
UE->frame_parms.samples_per_tti, rx_off_diff = -UE->rx_offset;
UE->frame_parms.nb_antennas_tx, else // moving to the left so drop rx_off_diff samples
1); rx_off_diff = 10*UE->frame_parms.samples_per_tti - RX_OFF_MIN - UE->rx_offset;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 ); cumulated_shift+=rx_off_diff;
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_UE0_TRX_WRITE_NS, rxs ); if ( rx_off_diff > 10 )
if (txs != UE->frame_parms.samples_per_tti) { LOG_E (PHY,"HUGE shift %d, cumul %d\n", rx_off_diff, cumulated_shift);
LOG_E(PHY,"TX : Timeout (sent %d/%d)\n",txs, UE->frame_parms.samples_per_tti); static __thread int printed_cumul=0;
exit_fun( "problem transmitting samples" ); if ( abs(cumulated_shift/1000) > printed_cumul ) {
LOG_W(PHY,"Shifted for 1000 samples: cumul %d\n", cumulated_shift);
printed_cumul=abs(cumulated_shift/1000);
} }
readBlockSize=UE->frame_parms.samples_per_tti-
UE->frame_parms.ofdm_symbol_size-
UE->frame_parms.nb_prefix_samples0;
writeBlockSize=UE->frame_parms.samples_per_tti - rx_off_diff;
} }
else { AssertFatal(readBlockSize ==
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_SF9, 1 ); UE->rfdevice.trx_read_func(&UE->rfdevice,
rxs = UE->rfdevice.trx_read_func(&UE->rfdevice,
&timestamp, &timestamp,
rxp, rxp,
UE->frame_parms.samples_per_tti-UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0, readBlockSize,
UE->frame_parms.nb_antennas_rx); UE->frame_parms.nb_antennas_rx),"");
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_SF9, 0 ); AssertFatal( writeBlockSize ==
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_UE0_TRX_READ_NS, rxs ); UE->rfdevice.trx_write_func(&UE->rfdevice,
if (rxs != (UE->frame_parms.samples_per_tti-UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0)) {
LOG_E(PHY, "problem in rx 6! want #samples=%d but got only %d!\n", UE->frame_parms.samples_per_tti-UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0, rxs);
exit_fun("problem in rx 6!");
return &UE_thread_retval;
}
// prepare tx buffer pointers
for (i=0; i<UE->frame_parms.nb_antennas_tx; i++)
txp[i] = (void*)&UE->common_vars.txdata[i][((sf+2)%10)*UE->frame_parms.samples_per_tti];
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_SF9, 1 );
txs = UE->rfdevice.trx_write_func(&UE->rfdevice,
timestamp+ timestamp+
(2*UE->frame_parms.samples_per_tti) - (2*UE->frame_parms.samples_per_tti) -
UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0 - UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0 -
openair0_cfg[0].tx_sample_advance, openair0_cfg[0].tx_sample_advance,
txp, txp,
UE->frame_parms.samples_per_tti - rx_off_diff, writeBlockSize,
UE->frame_parms.nb_antennas_tx, UE->frame_parms.nb_antennas_tx,
1); 1),"");
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE_SF9, 0 ); if( sub_frame==9) {
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_UE0_TRX_WRITE_NS, rxs );
if (txs != UE->frame_parms.samples_per_tti - rx_off_diff) {
LOG_E(PHY,"TX : Timeout (sent %d/%d)\n",txs, UE->frame_parms.samples_per_tti-rx_off_diff);
exit_fun( "problem transmitting samples" );
}
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_SF9, 1 );
// read in first symbol of next frame and adjust for timing drift // read in first symbol of next frame and adjust for timing drift
rxs = UE->rfdevice.trx_read_func(&UE->rfdevice, int first_symbols=writeBlockSize-readBlockSize;
if ( first_symbols > 0 )
AssertFatal(first_symbols ==
UE->rfdevice.trx_read_func(&UE->rfdevice,
&timestamp1, &timestamp1,
(void**)rxdata, (void**)rxdata,
UE->frame_parms.ofdm_symbol_size + UE->frame_parms.nb_prefix_samples0 - rx_off_diff, first_symbols,
UE->frame_parms.nb_antennas_rx); UE->frame_parms.nb_antennas_rx),"");
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ_SF9, 0 ); if ( first_symbols <0 )
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_UE0_TRX_READ_NS, rxs ); LOG_E(PHY,"can't compensate: diff =%d\n", first_symbols);
if (rxs != (UE->frame_parms.ofdm_symbol_size + UE->frame_parms.nb_prefix_samples0 - rx_off_diff)) {
LOG_E(PHY, "problem in rx 7! want #samples=%d but got only %d! rx_off_diff=%d\n", UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0 - rx_off_diff, rxs, rx_off_diff);
exit_fun("problem in rx 7!");
return &UE_thread_retval;
}
rx_off_diff = 0;
}
} }
unsigned long long gotIQs=rdtsc();
// operate on thread sf mod 2 // operate on thread sf mod 2
UE_rxtx_proc_t *proc = &UE->proc.proc_rxtx[sf&1]; AssertFatal(pthread_mutex_lock(&proc->mutex_rxtx) ==0,"");
if(sub_frame == 0) {
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_CNT_INCREMENT0+(proc->subframe_rx&1), 1 );
// lock mutex
if (pthread_mutex_lock(&proc->mutex_rxtx) != 0) {
LOG_E( PHY, "[SCHED][UE] error locking mutex for UE RX\n" );
exit_fun("nothing to add");
return &UE_thread_retval;
}
// increment instance count and change proc subframe/frame variables
int instance_cnt_rxtx = ++proc->instance_cnt_rxtx;
if(sf == 0)
{
UE->proc.proc_rxtx[0].frame_rx++; UE->proc.proc_rxtx[0].frame_rx++;
UE->proc.proc_rxtx[1].frame_rx++; UE->proc.proc_rxtx[1].frame_rx++;
} }
proc->subframe_rx=sf; UE->proc.proc_rxtx[0].gotIQs=gotIQs;
proc->subframe_tx=(sf+4)%10; UE->proc.proc_rxtx[1].gotIQs=gotIQs;
proc->frame_tx = proc->frame_rx + ((proc->subframe_rx>5)?1:0); proc->subframe_rx=sub_frame;
proc->timestamp_tx = timestamp+(4*UE->frame_parms.samples_per_tti)-UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0; proc->subframe_tx=(sub_frame+4)%10;
proc->frame_tx = proc->frame_rx + (proc->subframe_rx>5?1:0);
/* proc->timestamp_tx = timestamp+
if (sf != (timestamp/UE->frame_parms.samples_per_tti)%10) { (4*UE->frame_parms.samples_per_tti)-
LOG_E(PHY,"steady-state UE_thread error : frame_rx %d, subframe_rx %d, frame_tx %d, subframe_tx %d, rx subframe %d\n",proc->frame_rx,proc->subframe_rx,proc->frame_tx,proc->subframe_tx,(timestamp/UE->frame_parms.samples_per_tti)%10); UE->frame_parms.ofdm_symbol_size-UE->frame_parms.nb_prefix_samples0;
exit(-1);
} AssertFatal (pthread_cond_signal(&proc->cond_rxtx) ==0 ,"");
*/ AssertFatal(pthread_mutex_unlock(&proc->mutex_rxtx) ==0,"");
if (pthread_mutex_unlock(&proc->mutex_rxtx) != 0) { static __thread Meas t1= {0};
LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE RX\n" ); static unsigned long long lastTime=0;
exit_fun("nothing to add"); if ( lastTime != 0 )
return &UE_thread_retval; updateTimes(lastTime, &t1, 20000, "saif: Delay between two IQ acquisitions (case 1)");
} lastTime=rdtsc();
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_LOCK_MUTEX_RXTX_FOR_CNT_INCREMENT0+(proc->subframe_rx&1), 0 ); saif_meas(proc->frame_rx);
if (instance_cnt_rxtx == 0) {
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SIGNAL_COND_RXTX, 1 );
if (pthread_cond_signal(&proc->cond_rxtx) != 0) {
LOG_E( PHY, "[SCHED][UE] ERROR pthread_cond_signal for UE RX thread\n" );
exit_fun("nothing to add");
return &UE_thread_retval;
}
LOG_D(PHY, "firing up rxtx_thread[%d] at subframe %d\n", sf&1, sf);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SIGNAL_COND_RXTX, 0 );
} else { } else {
LOG_E( PHY, "[SCHED][UE] UE RX thread busy (IC %d)!!\n", instance_cnt_rxtx);
if (instance_cnt_rxtx > 2) {
sleep(1);
exit_fun("instance_cnt_rxtx > 2");
return &UE_thread_retval;
}
}
if (UE->mode == loop_through_memory) {
printf("Processing subframe %d",proc->subframe_rx); printf("Processing subframe %d",proc->subframe_rx);
getchar(); getchar();
} }
}// for sf=0..10
if ((UE->rx_offset<(5*UE->frame_parms.samples_per_tti)) &&
(UE->rx_offset > RX_OFF_MIN) &&
(rx_correction_timer == 0)) {
rx_off_diff = -UE->rx_offset + RX_OFF_MIN;
LOG_D(PHY,"UE->rx_offset %d > %d, diff %d\n",UE->rx_offset,RX_OFF_MIN,rx_off_diff);
rx_correction_timer = 5;
} else if ((UE->rx_offset>(5*UE->frame_parms.samples_per_tti)) &&
(UE->rx_offset < ((10*UE->frame_parms.samples_per_tti)-RX_OFF_MIN)) &&
(rx_correction_timer == 0)) { // moving to the left so drop rx_off_diff samples
rx_off_diff = 10*UE->frame_parms.samples_per_tti - RX_OFF_MIN - UE->rx_offset;
LOG_D(PHY,"UE->rx_offset %d < %d, diff %d\n",UE->rx_offset,10*UE->frame_parms.samples_per_tti-RX_OFF_MIN,rx_off_diff);
rx_correction_timer = 5;
}
if (rx_correction_timer>0)
rx_correction_timer--;
} // start_rx_stream==1 } // start_rx_stream==1
} // UE->is_synchronized==1 } // UE->is_synchronized==1
} // while !oai_exit } // while !oai_exit
return NULL; return NULL;
} // UE_thread
/*
void *UE_thread_old(void *arg)
{
UNUSED(arg)
static int UE_thread_retval;
PHY_VARS_UE *UE = PHY_vars_UE_g[0][0];
int spp = openair0_cfg[0].samples_per_packet;
int slot=1, frame=0, hw_subframe=0, rxpos=0, txpos=openair0_cfg[0].tx_scheduling_advance;
#ifdef __AVX2__
int dummy[2][spp] __attribute__((aligned(32)));
#else
int dummy[2][spp] __attribute__((aligned(16)));
#endif
int dummy_dump = 0;
int tx_enabled = 0;
int start_rx_stream = 0;
int rx_off_diff = 0;
int rx_correction_timer = 0;
int first_rx = 0;
RTIME T0;
unsigned int rxs;
void* rxp[2];
openair0_timestamp timestamp;
#ifdef NAS_UE
MessageDef *message_p;
#endif
#ifdef DEADLINE_SCHEDULER
struct sched_attr attr;
unsigned int flags = 0;
attr.size = sizeof(attr);
attr.sched_flags = 0;
attr.sched_nice = 0;
attr.sched_priority = 0;//sched_get_priority_max(SCHED_DEADLINE);
// This creates a .5 ms reservation
attr.sched_policy = SCHED_DEADLINE;
attr.sched_runtime = 100000;
attr.sched_deadline = 500000;
attr.sched_period = 500000;
if (sched_setattr(0, &attr, flags) < 0 ) {
perror("[SCHED] main eNB thread: sched_setattr failed\n");
exit_fun("Nothing to add");
return &UE_thread_retval;
}
LOG_I(HW,"[SCHED][eNB] eNB main deadline thread %lu started on CPU %d\n",
(unsigned long)gettid(), sched_getcpu());
#else
struct sched_param sp;
sp.sched_priority = sched_get_priority_max(SCHED_FIFO);
pthread_setschedparam(pthread_self(),SCHED_FIFO,&sp);
#endif
// Lock memory from swapping. This is a process wide call (not constraint to this thread).
mlockall(MCL_CURRENT | MCL_FUTURE);
printf("waiting for sync (UE_thread)\n");
pthread_mutex_lock(&sync_mutex);
printf("Locked sync_mutex, waiting (UE_thread)\n");
while (sync_var<0)
pthread_cond_wait(&sync_cond, &sync_mutex);
pthread_mutex_unlock(&sync_mutex);
printf("unlocked sync_mutex, waiting (UE_thread)\n");
printf("starting UE thread\n");
#ifdef NAS_UE
message_p = itti_alloc_new_message(TASK_NAS_UE, INITIALIZE_MESSAGE);
itti_send_msg_to_task (TASK_NAS_UE, INSTANCE_DEFAULT, message_p);
#endif
T0 = rt_get_time_ns();
first_rx = 1;
rxpos=0;
while (!oai_exit) {
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_HW_SUBFRAME, hw_subframe );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_HW_FRAME, frame );
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_DUMMY_DUMP, dummy_dump );
while (rxpos < (1+hw_subframe)*UE->frame_parms.samples_per_tti) {
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );
#ifndef USRP_DEBUG
DevAssert( UE->frame_parms.nb_antennas_rx <= 2 );
void* rxp[2];
for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++)
rxp[i] = (dummy_dump==0) ? (void*)&rxdata[i][rxpos] : (void*)dummy[i];
if (UE->mode != loop_through_memory) {
rxs = UE->rfdevice.trx_read_func(&UE->rfdevice,
&timestamp,
rxp,
spp - ((first_rx==1) ? rx_off_diff : 0),
UE->frame_parms.nb_antennas_rx);
if (rxs != (spp- ((first_rx==1) ? rx_off_diff : 0))) {
printf("rx error: asked %d got %d ",spp - ((first_rx==1) ? rx_off_diff : 0),rxs);
if (UE->is_synchronized == 1) {
exit_fun("problem in rx");
return &UE_thread_retval;
}
}
}
if (rx_off_diff !=0)
LOG_D(PHY,"frame %d, rx_offset %d, rx_off_diff %d\n",UE->frame_rx,UE->rx_offset,rx_off_diff);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
// Transmit TX buffer based on timestamp from RX
if ((tx_enabled==1) && (UE->mode!=loop_through_memory)) {
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 );
DevAssert( UE->frame_parms.nb_antennas_tx <= 2 );
void* txp[2];
for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
txp[i] = (void*)&txdata[i][txpos];
UE->rfdevice.trx_write_func(&openair0,
(timestamp+openair0_cfg[0].tx_scheduling_advance-openair0_cfg[0].tx_sample_advance),
txp,
spp - ((first_rx==1) ? rx_off_diff : 0),
UE->frame_parms.nb_antennas_tx,
1);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 );
}
else if (UE->mode == loop_through_memory)
rt_sleep_ns(1000000);
#else
// define USRP_DEBUG is active
rt_sleep_ns(1000000);
#endif
rx_off_diff = 0;
first_rx = 0;
rxpos += spp;
txpos += spp;
if (txpos >= 10*PHY_vars_UE_g[0][0]->frame_parms.samples_per_tti)
txpos -= 10*PHY_vars_UE_g[0][0]->frame_parms.samples_per_tti;
}
if (rxpos >= 10*PHY_vars_UE_g[0][0]->frame_parms.samples_per_tti)
rxpos -= 10*PHY_vars_UE_g[0][0]->frame_parms.samples_per_tti;
if (UE->is_synchronized == 1) {
LOG_D( HW, "UE_thread: hw_frame %d, hw_subframe %d (time %lli)\n", frame, hw_subframe, rt_get_time_ns()-T0 );
if (start_rx_stream == 1) {
LOG_D(PHY,"Locking mutex_rx (IC %d)\n",UE->instance_cnt_rx);
if (pthread_mutex_lock(&UE->mutex_rx) != 0) {
LOG_E( PHY, "[SCHED][UE] error locking mutex for UE RX thread\n" );
exit_fun("nothing to add");
return &UE_thread_retval;
}
int instance_cnt_rx = ++UE->instance_cnt_rx;
LOG_D(PHY,"Unlocking mutex_rx (IC %d)\n",instance_cnt_rx);
if (pthread_mutex_unlock(&UE->mutex_rx) != 0) {
LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE RX thread\n" );
exit_fun("nothing to add");
return &UE_thread_retval;
}
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE_INST_CNT_RX, instance_cnt_rx);
if (instance_cnt_rx == 0) {
LOG_D(HW,"signalling rx thread to wake up, hw_frame %d, hw_subframe %d (time %lli)\n", frame, hw_subframe, rt_get_time_ns()-T0 );
if (pthread_cond_signal(&UE->proc.cond_rx) != 0) {
LOG_E( PHY, "[SCHED][UE] ERROR pthread_cond_signal for UE RX thread\n" );
exit_fun("nothing to add");
return &UE_thread_retval;
}
LOG_D(HW,"signalled rx thread to wake up, hw_frame %d, hw_subframe %d (time %lli)\n", frame, hw_subframe, rt_get_time_ns()-T0 );
if (UE->mode == loop_through_memory) {
printf("Processing subframe %d",UE->slot_rx>>1);
getchar();
}
if (UE->mode == rx_calib_ue) {
if (frame == 10) {
LOG_D(PHY,
"[SCHED][UE] Found cell with N_RB_DL %"PRIu8", PHICH CONFIG (%d,%d), Nid_cell %"PRIu16", NB_ANTENNAS_TX %"PRIu8", frequency offset "PRIi32" Hz, RSSI (digital) %hu dB, measured Gain %d dB, total_rx_gain %"PRIu32" dB, USRP rx gain %f dB\n",
UE->frame_parms.N_RB_DL,
UE->frame_parms.phich_config_common.phich_duration,
UE->frame_parms.phich_config_common.phich_resource,
UE->frame_parms.Nid_cell,
UE->frame_parms.nb_antennas_tx_eNB,
UE->common_vars.freq_offset,
UE->measurements.rx_power_avg_dB[0],
UE->measurements.rx_power_avg_dB[0] - rx_input_level_dBm,
UE->rx_total_gain_dB,
openair0_cfg[0].rx_gain[0]
);
exit_fun("[HW][UE] UE in RX calibration mode, exiting");
return &UE_thread_retval;
}
}
} else {
LOG_E( PHY, "[SCHED][UE] UE RX thread busy (IC %d)!!\n", instance_cnt_rx);
if (instance_cnt_rx > 2) {
exit_fun("instance_cnt_rx > 1");
return &UE_thread_retval;
}
}
if ((tx_enabled==1)&&(UE->mode != loop_through_memory)) {
if (pthread_mutex_lock(&UE->mutex_tx) != 0) {
LOG_E( PHY, "[SCHED][UE] error locking mutex for UE TX thread\n" );
exit_fun("nothing to add");
return &UE_thread_retval;
}
int instance_cnt_tx = ++UE->instance_cnt_tx;
if (pthread_mutex_unlock(&UE->mutex_tx) != 0) {
LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE TX thread\n" );
exit_fun("nothing to add");
return &UE_thread_retval;
}
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE_INST_CNT_TX, instance_cnt_tx);
if (instance_cnt_tx == 0) {
if (pthread_cond_signal(&UE->cond_tx) != 0) {
LOG_E( PHY, "[SCHED][UE] ERROR pthread_cond_signal for UE TX thread\n" );
exit_fun("nothing to add");
return &UE_thread_retval;
}
LOG_D(HW,"signalled tx thread to wake up, hw_frame %d, hw_subframe %d (time %lli)\n", frame, hw_subframe, rt_get_time_ns()-T0 );
} else {
LOG_E( PHY, "[SCHED][UE] UE TX thread busy (IC %d)!!\n" );
if (instance_cnt_tx>2) {
exit_fun("instance_cnt_tx > 1");
return &UE_thread_retval;
}
}
}
}
} else {
// we are not yet synchronized
if ((hw_subframe == 9) && (dummy_dump == 0)) {
// Wake up initial synch thread
if (pthread_mutex_lock(&UE->mutex_synch) != 0) {
LOG_E( PHY, "[SCHED][UE] error locking mutex for UE initial synch thread\n" );
exit_fun("nothing to add");
return &UE_thread_retval;
}
int instance_cnt_synch = ++UE->instance_cnt_synch;
if (pthread_mutex_unlock(&UE->mutex_synch) != 0) {
LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE initial synch thread\n" );
exit_fun("nothing to add");
return &UE_thread_retval;
}
dummy_dump = 1;
if (instance_cnt_synch == 0) {
if (pthread_cond_signal(&UE->cond_synch) != 0) {
LOG_E( PHY, "[SCHED][UE] ERROR pthread_cond_signal for UE sync thread\n" );
exit_fun("nothing to add");
return &UE_thread_retval;
}
} else {
LOG_E( PHY, "[SCHED][UE] UE sync thread busy!!\n" );
exit_fun("nothing to add");
return &UE_thread_retval;
}
}
}
hw_subframe++;
slot+=2;
if (hw_subframe==10) {
hw_subframe = 0;
first_rx = 1;
frame++;
slot = 1;
int fail = pthread_mutex_lock(&UE->mutex_synch);
int instance_cnt_synch = UE->instance_cnt_synch;
fail = fail || pthread_mutex_unlock(&UE->mutex_synch);
if (fail) {
LOG_E( PHY, "[SCHED][UE] error (un-)locking mutex for UE synch\n" );
exit_fun("noting to add");
return &UE_thread_retval;
}
if (instance_cnt_synch < 0) {
// the UE_thread_synch is ready
if (UE->is_synchronized == 1) {
rx_off_diff = 0;
LTE_DL_FRAME_PARMS *frame_parms = &UE->frame_parms; // for macro FRAME_LENGTH_COMPLEX_SAMPLES
// LOG_I(PHY,"UE->rx_offset %d\n",UE->rx_offset);
if ((UE->rx_offset > RX_OFF_MAX) && (start_rx_stream == 0)) {
start_rx_stream=1;
frame=0;
// dump ahead in time to start of frame
#ifndef USRP_DEBUG
if (UE->mode != loop_through_memory) {
LOG_I(PHY,"Resynchronizing RX by %d samples\n",UE->rx_offset);
rxs = UE->rfdevice.trx_read_func(&UE->rfdevice,
&timestamp,
(void**)rxdata,
UE->rx_offset,
UE->frame_parms.nb_antennas_rx);
if (rxs != UE->rx_offset) {
exit_fun("problem in rx");
return &UE_thread_retval;
}
UE->rx_offset=0;
tx_enabled = 1;
}
else
rt_sleep_ns(1000000);
#else
rt_sleep_ns(10000000);
#endif
} else if ((UE->rx_offset<(FRAME_LENGTH_COMPLEX_SAMPLES/2)) &&
(UE->rx_offset > RX_OFF_MIN) &&
(start_rx_stream==1) &&
(rx_correction_timer == 0)) {
rx_off_diff = -UE->rx_offset + RX_OFF_MIN;
LOG_D(PHY,"UE->rx_offset %d > %d, diff %d\n",UE->rx_offset,RX_OFF_MIN,rx_off_diff);
rx_correction_timer = 5;
} else if ((UE->rx_offset>(FRAME_LENGTH_COMPLEX_SAMPLES/2)) &&
(UE->rx_offset < (FRAME_LENGTH_COMPLEX_SAMPLES-RX_OFF_MIN)) &&
(start_rx_stream==1) &&
(rx_correction_timer == 0)) { // moving to the left so drop rx_off_diff samples
rx_off_diff = FRAME_LENGTH_COMPLEX_SAMPLES - RX_OFF_MIN - UE->rx_offset;
LOG_D(PHY,"UE->rx_offset %d < %d, diff %d\n",UE->rx_offset,FRAME_LENGTH_COMPLEX_SAMPLES-RX_OFF_MIN,rx_off_diff);
rx_correction_timer = 5;
}
if (rx_correction_timer>0)
rx_correction_timer--;
}
dummy_dump=0;
}
}
#if defined(ENABLE_ITTI)
itti_update_lte_time(frame, slot);
#endif
}
return &UE_thread_retval;
} }
*/
/*! /*!
* \brief Initialize the UE theads. * \brief Initialize the UE theads.
* Creates the UE threads: * Creates the UE threads:
...@@ -1636,8 +1046,7 @@ void *UE_thread_old(void *arg) ...@@ -1636,8 +1046,7 @@ void *UE_thread_old(void *arg)
* - UE_thread_synch * - UE_thread_synch
* and the locking between them. * and the locking between them.
*/ */
void init_UE_threads(int inst) void init_UE_threads(int inst) {
{
PHY_VARS_UE *UE; PHY_VARS_UE *UE;
UE = PHY_vars_UE_g[inst][0]; UE = PHY_vars_UE_g[inst][0];
...@@ -1645,33 +1054,25 @@ void init_UE_threads(int inst) ...@@ -1645,33 +1054,25 @@ void init_UE_threads(int inst)
pthread_attr_init (&UE->proc.attr_ue); pthread_attr_init (&UE->proc.attr_ue);
pthread_attr_setstacksize(&UE->proc.attr_ue,8192);//5*PTHREAD_STACK_MIN); pthread_attr_setstacksize(&UE->proc.attr_ue,8192);//5*PTHREAD_STACK_MIN);
#ifndef LOWLATENCY
UE->proc.sched_param_ue.sched_priority = sched_get_priority_max(SCHED_FIFO);
pthread_attr_setschedparam(&UE->proc.attr_ue,&sched_param_UE_thread);
#endif
// the threads are not yet active, therefore access is allowed without locking // the threads are not yet active, therefore access is allowed without locking
UE->proc.proc_rxtx[0].instance_cnt_rxtx = -1; int nb_threads=2;
UE->proc.proc_rxtx[1].instance_cnt_rxtx = -1; for (int i=0; i<nb_threads; i++) {
UE->proc.instance_cnt_synch = -1; pthread_mutex_init(&UE->proc.proc_rxtx[i].mutex_rxtx,NULL);
pthread_mutex_init(&UE->proc.proc_rxtx[0].mutex_rxtx,NULL); pthread_cond_init(&UE->proc.proc_rxtx[i].cond_rxtx,NULL);
pthread_mutex_init(&UE->proc.proc_rxtx[1].mutex_rxtx,NULL); UE->proc.proc_rxtx[i].sub_frame_start=i;
UE->proc.proc_rxtx[i].sub_frame_step=nb_threads;
pthread_create(&UE->proc.proc_rxtx[i].pthread_rxtx,NULL,UE_thread_rxn_txnp4,(void*)&UE->proc.proc_rxtx[i]);
}
pthread_mutex_init(&UE->proc.mutex_synch,NULL); pthread_mutex_init(&UE->proc.mutex_synch,NULL);
pthread_cond_init(&UE->proc.proc_rxtx[0].cond_rxtx,NULL);
pthread_cond_init(&UE->proc.proc_rxtx[1].cond_rxtx,NULL);
pthread_cond_init(&UE->proc.cond_synch,NULL); pthread_cond_init(&UE->proc.cond_synch,NULL);
pthread_create(&UE->proc.proc_rxtx[0].pthread_rxtx,NULL,UE_thread_rxn_txnp4,(void*)&UE->proc.proc_rxtx[0]);
pthread_setname_np( UE->proc.proc_rxtx[0].pthread_rxtx, "UE_thread_rxn_txnp4_even" );
pthread_create(&UE->proc.proc_rxtx[1].pthread_rxtx,NULL,UE_thread_rxn_txnp4,(void*)&UE->proc.proc_rxtx[1]);
pthread_setname_np( UE->proc.proc_rxtx[1].pthread_rxtx, "UE_thread_rxn_txnp4_odd" );
pthread_create(&UE->proc.pthread_synch,NULL,UE_thread_synch,(void*)UE); pthread_create(&UE->proc.pthread_synch,NULL,UE_thread_synch,(void*)UE);
pthread_setname_np( UE->proc.pthread_synch, "UE_thread_synch" );
} }
#ifdef OPENAIR2 #ifdef OPENAIR2
void fill_ue_band_info(void) void fill_ue_band_info(void) {
{
UE_EUTRA_Capability_t *UE_EUTRA_Capability = UE_rrc_inst[0].UECap->UE_EUTRA_Capability; UE_EUTRA_Capability_t *UE_EUTRA_Capability = UE_rrc_inst[0].UECap->UE_EUTRA_Capability;
int i,j; int i,j;
...@@ -1700,8 +1101,7 @@ void fill_ue_band_info(void) ...@@ -1700,8 +1101,7 @@ void fill_ue_band_info(void)
} }
#endif #endif
int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, openair0_config_t *openair0_cfg) int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, openair0_config_t *openair0_cfg) {
{
int i, CC_id; int i, CC_id;
LTE_DL_FRAME_PARMS *frame_parms; LTE_DL_FRAME_PARMS *frame_parms;
...@@ -1710,50 +1110,33 @@ int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, openair0_config_t *openair0_cfg) ...@@ -1710,50 +1110,33 @@ int setup_ue_buffers(PHY_VARS_UE **phy_vars_ue, openair0_config_t *openair0_cfg)
for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) { for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
rf_map = &phy_vars_ue[CC_id]->rf_map; rf_map = &phy_vars_ue[CC_id]->rf_map;
if (phy_vars_ue[CC_id]) { AssertFatal( phy_vars_ue[CC_id] !=0, "");
frame_parms = &(phy_vars_ue[CC_id]->frame_parms); frame_parms = &(phy_vars_ue[CC_id]->frame_parms);
} else {
printf("phy_vars_UE[%d] not initialized\n", CC_id);
return(-1);
}
/*
if (frame_parms->frame_type == TDD) {
if (frame_parms->N_RB_DL == 100)
N_TA_offset = 624;
else if (frame_parms->N_RB_DL == 50)
N_TA_offset = 624/2;
else if (frame_parms->N_RB_DL == 25)
N_TA_offset = 624/4;
}
*/
// replace RX signal buffers with mmaped HW versions // replace RX signal buffers with mmaped HW versions
rxdata = (int32_t**)malloc16( frame_parms->nb_antennas_rx*sizeof(int32_t*) ); rxdata = (int32_t**)malloc16( frame_parms->nb_antennas_rx*sizeof(int32_t*) );
txdata = (int32_t**)malloc16( frame_parms->nb_antennas_tx*sizeof(int32_t*) ); txdata = (int32_t**)malloc16( frame_parms->nb_antennas_tx*sizeof(int32_t*) );
for (i=0; i<frame_parms->nb_antennas_rx; i++) { for (i=0; i<frame_parms->nb_antennas_rx; i++) {
printf( "Mapping UE CC_id %d, rx_ant %d, freq %u on card %d, chain %d\n", CC_id, i, downlink_frequency[CC_id][i], rf_map->card, rf_map->chain+i ); LOG_I(PHY, "Mapping UE CC_id %d, rx_ant %d, freq %u on card %d, chain %d\n",
CC_id, i, downlink_frequency[CC_id][i], rf_map->card, rf_map->chain+i );
free( phy_vars_ue[CC_id]->common_vars.rxdata[i] ); free( phy_vars_ue[CC_id]->common_vars.rxdata[i] );
rxdata[i] = (int32_t*)malloc16_clear( 307200*sizeof(int32_t) ); rxdata[i] = (int32_t*)malloc16_clear( 307200*sizeof(int32_t) );
phy_vars_ue[CC_id]->common_vars.rxdata[i] = rxdata[i]; // what about the "-N_TA_offset" ? // N_TA offset for TDD phy_vars_ue[CC_id]->common_vars.rxdata[i] = rxdata[i]; // what about the "-N_TA_offset" ? // N_TA offset for TDD
printf("rxdata[%d] : %p\n",i,rxdata[i]);
} }
for (i=0; i<frame_parms->nb_antennas_tx; i++) { for (i=0; i<frame_parms->nb_antennas_tx; i++) {
printf( "Mapping UE CC_id %d, tx_ant %d, freq %u on card %d, chain %d\n", CC_id, i, downlink_frequency[CC_id][i], rf_map->card, rf_map->chain+i ); LOG_I(PHY, "Mapping UE CC_id %d, tx_ant %d, freq %u on card %d, chain %d\n",
CC_id, i, downlink_frequency[CC_id][i], rf_map->card, rf_map->chain+i );
free( phy_vars_ue[CC_id]->common_vars.txdata[i] ); free( phy_vars_ue[CC_id]->common_vars.txdata[i] );
txdata[i] = (int32_t*)malloc16_clear( 307200*sizeof(int32_t) ); txdata[i] = (int32_t*)malloc16_clear( 307200*sizeof(int32_t) );
phy_vars_ue[CC_id]->common_vars.txdata[i] = txdata[i]; phy_vars_ue[CC_id]->common_vars.txdata[i] = txdata[i];
printf("txdata[%d] : %p\n",i,txdata[i]);
} }
// rxdata[x] points now to the same memory region as phy_vars_ue[CC_id]->common_vars.rxdata[x] // rxdata[x] points now to the same memory region as phy_vars_ue[CC_id]->common_vars.rxdata[x]
// txdata[x] points now to the same memory region as phy_vars_ue[CC_id]->common_vars.txdata[x] // txdata[x] points now to the same memory region as phy_vars_ue[CC_id]->common_vars.txdata[x]
// be careful when releasing memory! // be careful when releasing memory!
// because no "release_ue_buffers"-function is available, at least rxdata and txdata memory will leak (only some bytes) // because no "release_ue_buffers"-function is available, at least rxdata and txdata memory will leak (only some bytes)
} }
return 0; return 0;
} }
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