Merge latest next into next. Small conflict due to a debug print.

master
Pedro Alvarez 7 years ago
commit c39823ab90

@ -74,6 +74,7 @@ option(ENABLE_BLADERF "Enable BladeRF" ON)
option(BUILD_STATIC "Attempt to statically link external deps" OFF) option(BUILD_STATIC "Attempt to statically link external deps" OFF)
option(RPATH "Enable RPATH" OFF) option(RPATH "Enable RPATH" OFF)
option(ENABLE_ASAN "Enable gcc address sanitizer" OFF)
option(USE_LTE_RATES "Use standard LTE sampling rates" OFF) option(USE_LTE_RATES "Use standard LTE sampling rates" OFF)
@ -256,9 +257,14 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
if(${CMAKE_BUILD_TYPE} STREQUAL "Debug") if(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -DDEBUG_MODE") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -DDEBUG_MODE")
else(${CMAKE_BUILD_TYPE} STREQUAL "Debug") else(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
if(${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDEBUG_MODE")
else(${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
endif(${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo")
endif(${CMAKE_BUILD_TYPE} STREQUAL "Debug") endif(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
if (USE_LTE_RATES) if (USE_LTE_RATES)
message(STATUS "Using standard LTE sampling rates") message(STATUS "Using standard LTE sampling rates")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFORCE_STANDARD_RATE") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFORCE_STANDARD_RATE")
@ -303,6 +309,10 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
if(NOT WIN32) if(NOT WIN32)
ADD_CXX_COMPILER_FLAG_IF_AVAILABLE(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN) ADD_CXX_COMPILER_FLAG_IF_AVAILABLE(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN)
endif(NOT WIN32) endif(NOT WIN32)
if (ENABLE_ASAN)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
endif (ENABLE_ASAN)
endif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") endif(CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")

@ -451,9 +451,6 @@ int main(int argc, char **argv) {
exit(0); exit(0);
} }
srslte_rf_stop_rx_stream(&rf);
srslte_rf_flush_buffer(&rf);
/* set sampling frequency */ /* set sampling frequency */
int srate = srslte_sampling_freq_hz(cell.nof_prb); int srate = srslte_sampling_freq_hz(cell.nof_prb);
if (srate != -1) { if (srate != -1) {

@ -30,6 +30,8 @@
#include <pthread.h> #include <pthread.h>
#include <vector> #include <vector>
#include <stack> #include <stack>
#include <map>
#include <string>
#include <algorithm> #include <algorithm>
/******************************************************************************* /*******************************************************************************
@ -70,14 +72,23 @@ public:
delete available.top(); delete available.top();
available.pop(); available.pop();
} }
for (uint32_t i = 0; i < used.size(); i++) {
delete used[i];
}
} }
void print_all_buffers() void print_all_buffers()
{ {
printf("%d buffers in queue\n", (int) used.size()); printf("%d buffers in queue\n", (int) used.size());
#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED #ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED
std::map<std::string, uint32_t> buffer_cnt;
for (uint32_t i=0;i<used.size();i++) { for (uint32_t i=0;i<used.size();i++) {
printf("%s\n", strlen(used[i]->debug_name)?used[i]->debug_name:"Undefined"); buffer_cnt[strlen(used[i]->debug_name)?used[i]->debug_name:"Undefined"]++;
}
std::map<std::string, uint32_t>::iterator it;
for (it = buffer_cnt.begin(); it != buffer_cnt.end(); it++) {
printf(" - %dx %s\n", it->second, it->first.c_str());
} }
#endif #endif
} }
@ -166,6 +177,9 @@ public:
pool->deallocate(b); pool->deallocate(b);
b = NULL; b = NULL;
} }
void print_all_buffers() {
pool->print_all_buffers();
}
private: private:
buffer_pool<byte_buffer_t> *pool; buffer_pool<byte_buffer_t> *pool;
}; };

@ -63,7 +63,7 @@
#define SRSLTE_MAX_BUFFER_SIZE_BYTES 12756 #define SRSLTE_MAX_BUFFER_SIZE_BYTES 12756
#define SRSLTE_BUFFER_HEADER_OFFSET 1024 #define SRSLTE_BUFFER_HEADER_OFFSET 1024
//#define SRSLTE_BUFFER_POOL_LOG_ENABLED #define SRSLTE_BUFFER_POOL_LOG_ENABLED
#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED #ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED
#define pool_allocate (pool->allocate(__FUNCTION__)) #define pool_allocate (pool->allocate(__FUNCTION__))
@ -96,6 +96,8 @@ static const char error_text[ERROR_N_ITEMS][20] = { "None",
"Can't start", "Can't start",
"Already started"}; "Already started"};
//#define ENABLE_TIMESTAMP
/****************************************************************************** /******************************************************************************
* Byte and Bit buffers * Byte and Bit buffers
* *
@ -147,33 +149,27 @@ public:
} }
long get_latency_us() long get_latency_us()
{ {
#ifdef ENABLE_TIMESTAMP
if(!timestamp_is_set) if(!timestamp_is_set)
return 0; return 0;
gettimeofday(&timestamp[2], NULL); gettimeofday(&timestamp[2], NULL);
get_time_interval(timestamp); get_time_interval(timestamp);
return timestamp[0].tv_usec; return timestamp[0].tv_usec;
#else
return 0;
#endif
} }
void set_timestamp() void set_timestamp()
{ {
#ifdef ENABLE_TIMESTAMP
gettimeofday(&timestamp[1], NULL); gettimeofday(&timestamp[1], NULL);
timestamp_is_set = true; timestamp_is_set = true;
#endif
} }
private: private:
void get_time_interval(struct timeval * tdata) {
tdata[0].tv_sec = tdata[2].tv_sec - tdata[1].tv_sec;
tdata[0].tv_usec = tdata[2].tv_usec - tdata[1].tv_usec;
if (tdata[0].tv_usec < 0) {
tdata[0].tv_sec--;
tdata[0].tv_usec += 1000000;
}
}
struct timeval timestamp[3]; struct timeval timestamp[3];
bool timestamp_is_set; bool timestamp_is_set;
byte_buffer_t *next; byte_buffer_t *next;
@ -215,15 +211,21 @@ struct bit_buffer_t{
} }
long get_latency_us() long get_latency_us()
{ {
#ifdef ENABLE_TIMESTAMP
if(!timestamp_is_set) if(!timestamp_is_set)
return 0; return 0;
gettimeofday(&timestamp[2], NULL); gettimeofday(&timestamp[2], NULL);
return timestamp[0].tv_usec; return timestamp[0].tv_usec;
#else
return 0;
#endif
} }
void set_timestamp() void set_timestamp()
{ {
#ifdef ENABLE_TIMESTAMP
gettimeofday(&timestamp[1], NULL); gettimeofday(&timestamp[1], NULL);
timestamp_is_set = true; timestamp_is_set = true;
#endif
} }
private: private:

@ -30,6 +30,7 @@
#include "srslte/common/timers.h" #include "srslte/common/timers.h"
#include "srslte/common/security.h" #include "srslte/common/security.h"
#include "srslte/asn1/liblte_rrc.h" #include "srslte/asn1/liblte_rrc.h"
#include <string>
namespace srslte { namespace srslte {
@ -37,11 +38,13 @@ namespace srslte {
class srslte_nas_config_t class srslte_nas_config_t
{ {
public: public:
srslte_nas_config_t(uint32_t lcid_ = 0) srslte_nas_config_t(uint32_t lcid_ = 0, std::string apn_ = "")
:lcid(lcid_) :lcid(lcid_),
apn(apn_)
{} {}
uint32_t lcid; uint32_t lcid;
std::string apn;
}; };

@ -84,6 +84,8 @@ public:
level_text_short = true; level_text_short = true;
} }
virtual ~log() {};
// This function shall be called at the start of every tti for printing tti // This function shall be called at the start of every tti for printing tti
void step(uint32_t tti_) { void step(uint32_t tti_) {
tti = tti_; tti = tti_;

@ -56,6 +56,9 @@ public:
~msg_queue() ~msg_queue()
{ {
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&not_empty);
pthread_cond_destroy(&not_full);
delete [] buf; delete [] buf;
} }

@ -84,7 +84,6 @@ public:
} }
void thread_func() void thread_func()
{ {
// substract time elapsed until now from timer duration // substract time elapsed until now from timer duration
gettimeofday(&start_time[2], NULL); gettimeofday(&start_time[2], NULL);
get_time_interval(start_time); get_time_interval(start_time);
@ -105,6 +104,14 @@ public:
return false; return false;
} }
} }
int32_t get_msec_to_expire() {
if (running) {
gettimeofday(&start_time[2], NULL);
get_time_interval(start_time);
return (duration_msec*1000 - start_time[0].tv_usec)/1000;
}
return 0;
}
bool is_running() bool is_running()
{ {
return running; return running;

@ -151,15 +151,16 @@ public:
fprintf(stderr, "Error getting unique timer id: no more timers available\n"); fprintf(stderr, "Error getting unique timer id: no more timers available\n");
return 0; return 0;
} else { } else {
while(used_timers[next_timer]) { for (uint32_t i=0;i<nof_timers;i++) {
next_timer++; if (!used_timers[i]) {
if (next_timer >= nof_timers) { used_timers[i] = true;
next_timer=0; nof_used_timers++;
return i;
} }
} }
used_timers[next_timer] = true; fprintf(stderr, "Error getting unique timer id: no more timers available but nof_used_timers=%d, nof_timers=%d\n",
nof_used_timers++; nof_used_timers, nof_timers);
return next_timer; return 0;
} }
} }
private: private:

@ -119,7 +119,7 @@ public:
virtual uint32_t get_ul_count() = 0; virtual uint32_t get_ul_count() = 0;
virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 0; virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 0;
virtual bool get_k_asme(uint8_t *k_asme_, uint32_t n) = 0; virtual bool get_k_asme(uint8_t *k_asme_, uint32_t n) = 0;
virtual void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) = 0; virtual bool plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) = 0;
virtual void plmn_search_end() = 0; virtual void plmn_search_end() = 0;
}; };
@ -160,7 +160,7 @@ public:
virtual void in_sync() = 0; virtual void in_sync() = 0;
virtual void out_of_sync() = 0; virtual void out_of_sync() = 0;
virtual void earfcn_end() = 0; virtual void earfcn_end() = 0;
virtual void cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) = 0; virtual void cell_camping(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp = NAN) = 0;
virtual void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn = -1, int pci = -1) = 0; virtual void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn = -1, int pci = -1) = 0;
}; };
@ -173,7 +173,7 @@ public:
virtual uint16_t get_mnc() = 0; virtual uint16_t get_mnc() = 0;
virtual void enable_capabilities() = 0; virtual void enable_capabilities() = 0;
virtual void plmn_search() = 0; virtual void plmn_search() = 0;
virtual void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) = 0; virtual void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, bool connect_request = false) = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0; virtual std::string get_rb_name(uint32_t lcid) = 0;
}; };
@ -475,6 +475,7 @@ typedef struct {
int cqi_fixed; int cqi_fixed;
float snr_ema_coeff; float snr_ema_coeff;
std::string snr_estim_alg; std::string snr_estim_alg;
bool cfo_is_doppler;
bool cfo_integer_enabled; bool cfo_integer_enabled;
float cfo_correct_tol_hz; float cfo_correct_tol_hz;
float cfo_pss_ema; float cfo_pss_ema;
@ -487,12 +488,12 @@ typedef struct {
uint32_t cfo_ref_mask; uint32_t cfo_ref_mask;
bool average_subframe_enabled; bool average_subframe_enabled;
int time_correct_period; int time_correct_period;
bool sfo_correct_disable;
std::string sss_algorithm; std::string sss_algorithm;
float estimator_fil_w; float estimator_fil_w;
bool rssi_sensor_enabled; bool rssi_sensor_enabled;
bool sic_pss_enabled; bool sic_pss_enabled;
float rx_gain_offset; float rx_gain_offset;
bool pdsch_csi_enabled;
} phy_args_t; } phy_args_t;
@ -580,9 +581,8 @@ public:
/* Cell search and selection procedures */ /* Cell search and selection procedures */
virtual void cell_search_start() = 0; virtual void cell_search_start() = 0;
virtual void cell_search_stop() = 0;
virtual void cell_search_next() = 0; virtual void cell_search_next() = 0;
virtual bool cell_select(uint32_t earfcn, srslte_cell_t cell) = 0; virtual void cell_select(uint32_t earfcn, srslte_cell_t cell) = 0;
virtual bool cell_handover(srslte_cell_t cell) = 0; virtual bool cell_handover(srslte_cell_t cell) = 0;
/* Is the PHY downlink synchronized? */ /* Is the PHY downlink synchronized? */

@ -83,9 +83,12 @@ typedef struct {
srslte_interp_lin_t srslte_interp_lin_mbsfn; srslte_interp_lin_t srslte_interp_lin_mbsfn;
float rssi[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; float rssi[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
float rsrp[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; float rsrp[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
float rsrp_corr[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
float noise_estimate[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; float noise_estimate[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
float cfo; float cfo;
bool rsrp_neighbour;
bool cfo_estimate_enable; bool cfo_estimate_enable;
uint32_t cfo_estimate_sf_mask; uint32_t cfo_estimate_sf_mask;
@ -158,6 +161,9 @@ SRSLTE_API void srslte_chest_dl_cfo_estimate_enable(srslte_chest_dl_t *q,
SRSLTE_API void srslte_chest_dl_average_subframe(srslte_chest_dl_t *q, SRSLTE_API void srslte_chest_dl_average_subframe(srslte_chest_dl_t *q,
bool enable); bool enable);
SRSLTE_API void srslte_chest_dl_set_rsrp_neighbour(srslte_chest_dl_t *q,
bool rsrp_for_neighbour);
SRSLTE_API float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q); SRSLTE_API float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q);
SRSLTE_API float srslte_chest_dl_get_cfo(srslte_chest_dl_t *q); SRSLTE_API float srslte_chest_dl_get_cfo(srslte_chest_dl_t *q);
@ -185,4 +191,6 @@ SRSLTE_API float srslte_chest_dl_get_rsrp_port(srslte_chest_dl_t *q,
SRSLTE_API float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q); SRSLTE_API float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q);
SRSLTE_API float srslte_chest_dl_get_rsrp_neighbour(srslte_chest_dl_t *q);
#endif #endif

@ -42,6 +42,9 @@
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
uint32_t max_cb; uint32_t max_cb;
int16_t **buffer_f; int16_t **buffer_f;
uint8_t **data;
bool *cb_crc;
bool tb_crc;
} srslte_softbuffer_rx_t; } srslte_softbuffer_rx_t;
typedef struct SRSLTE_API { typedef struct SRSLTE_API {

@ -79,6 +79,7 @@ SRSLTE_API int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS],
SRSLTE_API int srslte_predecoding_single(cf_t *y, SRSLTE_API int srslte_predecoding_single(cf_t *y,
cf_t *h, cf_t *h,
cf_t *x, cf_t *x,
float *csi,
int nof_symbols, int nof_symbols,
float scaling, float scaling,
float noise_estimate); float noise_estimate);
@ -86,6 +87,7 @@ SRSLTE_API int srslte_predecoding_single(cf_t *y,
SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS],
cf_t *x, cf_t *x,
float *csi,
int nof_rxant, int nof_rxant,
int nof_symbols, int nof_symbols,
float scaling, float scaling,
@ -111,6 +113,7 @@ SRSLTE_API void srslte_predecoding_set_mimo_decoder (srslte_mimo_decoder_t _mimo
SRSLTE_API int srslte_predecoding_type(cf_t *y[SRSLTE_MAX_PORTS], SRSLTE_API int srslte_predecoding_type(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
float *csi,
int nof_rxant, int nof_rxant,
int nof_ports, int nof_ports,
int nof_layers, int nof_layers,

@ -76,6 +76,9 @@ typedef struct SRSLTE_API {
cf_t *d[SRSLTE_MAX_CODEWORDS]; /* Modulated/Demodulated codewords */ cf_t *d[SRSLTE_MAX_CODEWORDS]; /* Modulated/Demodulated codewords */
void *e[SRSLTE_MAX_CODEWORDS]; void *e[SRSLTE_MAX_CODEWORDS];
bool csi_enabled;
float *csi[SRSLTE_MAX_CODEWORDS]; /* Channel Strengh Indicator */
/* tx & rx objects */ /* tx & rx objects */
srslte_modem_table_t mod[4]; srslte_modem_table_t mod[4];
@ -107,6 +110,9 @@ SRSLTE_API int srslte_pdsch_set_rnti(srslte_pdsch_t *q,
SRSLTE_API void srslte_pdsch_set_power_allocation(srslte_pdsch_t *q, SRSLTE_API void srslte_pdsch_set_power_allocation(srslte_pdsch_t *q,
float rho_a); float rho_a);
SRSLTE_API int srslte_pdsch_enable_csi(srslte_pdsch_t *q,
bool enable);
SRSLTE_API void srslte_pdsch_free_rnti(srslte_pdsch_t *q, SRSLTE_API void srslte_pdsch_free_rnti(srslte_pdsch_t *q,
uint16_t rnti); uint16_t rnti);

@ -60,6 +60,7 @@ typedef struct {
SRSLTE_RF_ERROR_LATE, SRSLTE_RF_ERROR_LATE,
SRSLTE_RF_ERROR_UNDERFLOW, SRSLTE_RF_ERROR_UNDERFLOW,
SRSLTE_RF_ERROR_OVERFLOW, SRSLTE_RF_ERROR_OVERFLOW,
SRSLTE_RF_ERROR_RX,
SRSLTE_RF_ERROR_OTHER SRSLTE_RF_ERROR_OTHER
} type; } type;
int opt; int opt;

@ -84,8 +84,6 @@ typedef struct SRSLTE_API {
srslte_ofdm_t fft_mbsfn; srslte_ofdm_t fft_mbsfn;
srslte_chest_dl_t chest; srslte_chest_dl_t chest;
srslte_cfo_t sfo_correct;
srslte_pdsch_cfg_t pdsch_cfg; srslte_pdsch_cfg_t pdsch_cfg;
srslte_pdsch_cfg_t pmch_cfg; srslte_pdsch_cfg_t pmch_cfg;
srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS]; srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS];
@ -126,8 +124,6 @@ typedef struct SRSLTE_API {
srslte_dci_msg_t pending_ul_dci_msg; srslte_dci_msg_t pending_ul_dci_msg;
uint16_t pending_ul_dci_rnti; uint16_t pending_ul_dci_rnti;
float sample_offset;
float last_phich_corr; float last_phich_corr;
}srslte_ue_dl_t; }srslte_ue_dl_t;
@ -195,9 +191,6 @@ SRSLTE_API int srslte_ue_dl_find_dl_dci_type(srslte_ue_dl_t *q,
SRSLTE_API uint32_t srslte_ue_dl_get_ncce(srslte_ue_dl_t *q); SRSLTE_API uint32_t srslte_ue_dl_get_ncce(srslte_ue_dl_t *q);
SRSLTE_API void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q,
float sample_offset);
SRSLTE_API int srslte_ue_dl_decode(srslte_ue_dl_t *q, SRSLTE_API int srslte_ue_dl_decode(srslte_ue_dl_t *q,
uint8_t *data[SRSLTE_MAX_CODEWORDS], uint8_t *data[SRSLTE_MAX_CODEWORDS],
uint32_t tm, uint32_t tm,

@ -705,6 +705,18 @@ static inline void srslte_simd_cf_storeu(float *re, float *im, simd_cf_t simdreg
#endif /* LV_HAVE_AVX512 */ #endif /* LV_HAVE_AVX512 */
} }
static inline simd_f_t srslte_simd_cf_re(simd_cf_t in) {
simd_f_t out = in.re;
#ifndef LV_HAVE_AVX512
#ifdef LV_HAVE_AVX2
/* Permute for AVX registers (mis SSE registers) */
const __m256i idx = _mm256_setr_epi32(0, 2, 4, 6, 1, 3, 5, 7);
out = _mm256_permutevar8x32_ps(out, idx);
#endif /* LV_HAVE_AVX2 */
#endif /* LV_HAVE_AVX512 */
return out;
}
static inline simd_cf_t srslte_simd_cf_set1 (cf_t x) { static inline simd_cf_t srslte_simd_cf_set1 (cf_t x) {
simd_cf_t ret; simd_cf_t ret;
#ifdef LV_HAVE_AVX512 #ifdef LV_HAVE_AVX512

@ -73,7 +73,7 @@ SRSLTE_API void srslte_vec_fprint_byte(FILE *stream, uint8_t *x, const uint32_t
SRSLTE_API void srslte_vec_fprint_i(FILE *stream, int *x, const uint32_t len); SRSLTE_API void srslte_vec_fprint_i(FILE *stream, int *x, const uint32_t len);
SRSLTE_API void srslte_vec_fprint_s(FILE *stream, short *x, const uint32_t len); SRSLTE_API void srslte_vec_fprint_s(FILE *stream, short *x, const uint32_t len);
SRSLTE_API void srslte_vec_fprint_hex(FILE *stream, uint8_t *x, const uint32_t len); SRSLTE_API void srslte_vec_fprint_hex(FILE *stream, uint8_t *x, const uint32_t len);
SRSLTE_API void srslte_vec_sprint_hex(char *str, uint8_t *x, const uint32_t len); SRSLTE_API void srslte_vec_sprint_hex(char *str, const uint32_t max_str_len, uint8_t *x, const uint32_t len);
/* Saves/loads a vector to a file */ /* Saves/loads a vector to a file */
SRSLTE_API void srslte_vec_save_file(char *filename, const void *buffer, const uint32_t len); SRSLTE_API void srslte_vec_save_file(char *filename, const void *buffer, const uint32_t len);

@ -72,6 +72,8 @@ namespace srslte {
trace_enabled = false; trace_enabled = false;
tti = 0; tti = 0;
agc_enabled = false; agc_enabled = false;
radio_is_streaming = false;
is_initialized = false;
}; };
bool init(char *args = NULL, char *devname = NULL, uint32_t nof_channels = 1); bool init(char *args = NULL, char *devname = NULL, uint32_t nof_channels = 1);
@ -119,13 +121,13 @@ namespace srslte {
void start_trace(); void start_trace();
void write_trace(std::string filename); void write_trace(std::string filename);
void start_rx(bool now = false);
void stop_rx();
void set_tti(uint32_t tti); void set_tti(uint32_t tti);
bool is_first_of_burst(); bool is_first_of_burst();
bool is_init();
void register_error_handler(srslte_rf_error_handler_t h); void register_error_handler(srslte_rf_error_handler_t h);
protected: protected:
@ -168,6 +170,9 @@ namespace srslte {
uint32_t tti; uint32_t tti;
bool agc_enabled; bool agc_enabled;
bool is_initialized = true;;
bool radio_is_streaming;
uint32_t saved_nof_channels; uint32_t saved_nof_channels;
char saved_args[128]; char saved_args[128];
char saved_devname[128]; char saved_devname[128];

@ -55,11 +55,4 @@ void byte_buffer_pool::cleanup(void)
pthread_mutex_unlock(&instance_mutex); pthread_mutex_unlock(&instance_mutex);
} }
} // namespace srsue } // namespace srsue

@ -40,6 +40,7 @@ log_filter::log_filter()
do_tti = false; do_tti = false;
time_src = NULL; time_src = NULL;
time_format = TIME; time_format = TIME;
logger_h = NULL;
} }
log_filter::log_filter(std::string layer) log_filter::log_filter(std::string layer)

@ -35,6 +35,7 @@ namespace srslte{
logger_file::logger_file() logger_file::logger_file()
:inited(false) :inited(false)
,logfile(NULL)
,not_done(true) ,not_done(true)
,cur_length(0) ,cur_length(0)
,max_length(0) ,max_length(0)
@ -46,9 +47,11 @@ logger_file::~logger_file() {
if(inited) { if(inited) {
wait_thread_finish(); wait_thread_finish();
flush(); flush();
if (logfile) {
fclose(logfile); fclose(logfile);
} }
} }
}
void logger_file::init(std::string file, int max_length_) { void logger_file::init(std::string file, int max_length_) {
pthread_mutex_init(&mutex, NULL); pthread_mutex_init(&mutex, NULL);

@ -122,6 +122,12 @@ uint8_t* sch_pdu::write_packet(srslte::log *log_h)
sch_subh padding; sch_subh padding;
padding.set_padding(); padding.set_padding();
if (nof_subheaders <= 0) {
log_h->error("Trying to write packet with invalid number of subheaders (nof_subheaders=%d).\n", nof_subheaders);
log_h->console("Trying to write packet with invalid number of subheaders (nof_subheaders=%d).\n", nof_subheaders);
return NULL;
}
if (init_rem_len < 0) { if (init_rem_len < 0) {
log_h->error("init_rem_len=%d\n", init_rem_len); log_h->error("init_rem_len=%d\n", init_rem_len);
return NULL; return NULL;

@ -76,10 +76,14 @@ void pdu_queue::deallocate(uint8_t* pdu)
*/ */
void pdu_queue::push(uint8_t *ptr, uint32_t len, uint32_t tstamp) void pdu_queue::push(uint8_t *ptr, uint32_t len, uint32_t tstamp)
{ {
if (ptr) {
pdu_t *pdu = (pdu_t*) ptr; pdu_t *pdu = (pdu_t*) ptr;
pdu->len = len; pdu->len = len;
pdu->tstamp = tstamp; pdu->tstamp = tstamp;
pdu_q.push(pdu); pdu_q.push(pdu);
} else {
log_h->warning("Error pushing pdu: ptr is empty\n");
}
} }
bool pdu_queue::process_pdus() bool pdu_queue::process_pdus()

@ -88,7 +88,7 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb)
goto clean_exit; goto clean_exit;
} }
q->mbsfn_refs = calloc(SRSLTE_MAX_MBSFN_AREA_IDS, sizeof(srslte_refsignal_t*)); q->mbsfn_refs = calloc(SRSLTE_MAX_MBSFN_AREA_IDS, sizeof(srslte_refsignal_t));
if (!q->mbsfn_refs) { if (!q->mbsfn_refs) {
fprintf(stderr, "Calloc error initializing mbsfn_refs (%d)\n", ret); fprintf(stderr, "Calloc error initializing mbsfn_refs (%d)\n", ret);
goto clean_exit; goto clean_exit;
@ -153,6 +153,8 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb)
q->noise_alg = SRSLTE_NOISE_ALG_REFS; q->noise_alg = SRSLTE_NOISE_ALG_REFS;
q->rsrp_neighbour = false;
q->smooth_filter_len = 3; q->smooth_filter_len = 3;
srslte_chest_dl_set_smooth_filter3_coeff(q, 0.1); srslte_chest_dl_set_smooth_filter3_coeff(q, 0.1);
@ -169,14 +171,14 @@ clean_exit:
void srslte_chest_dl_free(srslte_chest_dl_t *q) void srslte_chest_dl_free(srslte_chest_dl_t *q)
{ {
int i;
if(&q->csr_refs) if(&q->csr_refs)
srslte_refsignal_free(&q->csr_refs); srslte_refsignal_free(&q->csr_refs);
if (q->mbsfn_refs) { if (q->mbsfn_refs) {
for (i=0; i<SRSLTE_MAX_MBSFN_AREA_IDS; i++) { for (int i=0; i<SRSLTE_MAX_MBSFN_AREA_IDS; i++) {
if (q->mbsfn_refs[i]) { if (q->mbsfn_refs[i]) {
srslte_refsignal_free(q->mbsfn_refs[i]); srslte_refsignal_free(q->mbsfn_refs[i]);
free(q->mbsfn_refs[i]);
} }
} }
free(q->mbsfn_refs); free(q->mbsfn_refs);
@ -206,6 +208,7 @@ void srslte_chest_dl_free(srslte_chest_dl_t *q)
int srslte_chest_dl_set_mbsfn_area_id(srslte_chest_dl_t *q, uint16_t mbsfn_area_id){ int srslte_chest_dl_set_mbsfn_area_id(srslte_chest_dl_t *q, uint16_t mbsfn_area_id){
if (mbsfn_area_id < SRSLTE_MAX_MBSFN_AREA_IDS) {
if(!q->mbsfn_refs[mbsfn_area_id]) { if(!q->mbsfn_refs[mbsfn_area_id]) {
q->mbsfn_refs[mbsfn_area_id] = calloc(1, sizeof(srslte_refsignal_t)); q->mbsfn_refs[mbsfn_area_id] = calloc(1, sizeof(srslte_refsignal_t));
} }
@ -216,6 +219,8 @@ int srslte_chest_dl_set_mbsfn_area_id(srslte_chest_dl_t *q, uint16_t mbsfn_area_
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
return SRSLTE_ERROR;
}
int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, srslte_cell_t cell) int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, srslte_cell_t cell)
{ {
@ -540,27 +545,32 @@ void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, ui
} }
} }
} }
/* Compute RSRP for the channel estimates in this port */
uint32_t npilots = SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id);
q->rsrp[rxant_id][port_id] = srslte_vec_avg_power_cf(q->pilot_estimates, npilots);
q->rssi[rxant_id][port_id] = srslte_chest_dl_rssi(q, input, port_id);
} }
int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id) int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id)
{ {
uint32_t npilots = SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id);
/* Get references from the input signal */ /* Get references from the input signal */
srslte_refsignal_cs_get_sf(q->cell, port_id, input, q->pilot_recv_signal); srslte_refsignal_cs_get_sf(q->cell, port_id, input, q->pilot_recv_signal);
/* Use the known CSR signal to compute Least-squares estimates */ /* Use the known CSR signal to compute Least-squares estimates */
srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_refs.pilots[port_id/2][sf_idx], srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_refs.pilots[port_id/2][sf_idx],
q->pilot_estimates, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); q->pilot_estimates, npilots);
/* Compute RSRP for the channel estimates in this port */
if (q->rsrp_neighbour) {
double energy = cabs(srslte_vec_acc_cc(q->pilot_estimates, npilots)/npilots);
q->rsrp_corr[rxant_id][port_id] = energy*energy;
}
q->rsrp[rxant_id][port_id] = srslte_vec_avg_power_cf(q->pilot_recv_signal, npilots);
q->rssi[rxant_id][port_id] = srslte_chest_dl_rssi(q, input, port_id);
chest_interpolate_noise_est(q, input, ce, sf_idx, port_id, rxant_id, SRSLTE_SF_NORM); chest_interpolate_noise_est(q, input, ce, sf_idx, port_id, rxant_id, SRSLTE_SF_NORM);
return 0; return 0;
} }
int srslte_chest_dl_estimate_port_mbsfn(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id, uint16_t mbsfn_area_id) int srslte_chest_dl_estimate_port_mbsfn(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id, uint16_t mbsfn_area_id)
{ {
@ -619,6 +629,10 @@ int srslte_chest_dl_estimate_multi_mbsfn(srslte_chest_dl_t *q, cf_t *input[SRSLT
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
void srslte_chest_dl_set_rsrp_neighbour(srslte_chest_dl_t *q, bool rsrp_for_neighbour) {
q->rsrp_neighbour = rsrp_for_neighbour;
}
void srslte_chest_dl_average_subframe(srslte_chest_dl_t *q, bool enable) void srslte_chest_dl_average_subframe(srslte_chest_dl_t *q, bool enable)
{ {
q->average_subframe = enable; q->average_subframe = enable;
@ -706,8 +720,21 @@ float srslte_chest_dl_get_rsrp_port(srslte_chest_dl_t *q, uint32_t port) {
return sum; return sum;
} }
float srslte_chest_dl_get_rsrp_neighbour_port(srslte_chest_dl_t *q, uint32_t port) {
float sum = 0.0f;
for (int j = 0; j < q->cell.nof_ports; ++j) {
sum +=q->rsrp_corr[port][j];
}
if (q->cell.nof_ports) {
sum /= q->cell.nof_ports;
}
return sum;
}
float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) { float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) {
float max = -0.0f; float max = -1e9;
for (int i = 0; i < q->last_nof_antennas; ++i) { for (int i = 0; i < q->last_nof_antennas; ++i) {
float v = srslte_chest_dl_get_rsrp_port(q, i); float v = srslte_chest_dl_get_rsrp_port(q, i);
if (v > max) { if (v > max) {
@ -716,3 +743,14 @@ float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) {
} }
return max; return max;
} }
float srslte_chest_dl_get_rsrp_neighbour(srslte_chest_dl_t *q) {
float max = -1e9;
for (int i = 0; i < q->last_nof_antennas; ++i) {
float v = srslte_chest_dl_get_rsrp_neighbour_port(q, i);
if (v > max) {
max = v;
}
}
return max;
}

@ -173,7 +173,7 @@ int main(int argc, char **argv) {
gettimeofday(&t[1], NULL); gettimeofday(&t[1], NULL);
for (int j=0;j<100;j++) { for (int j=0;j<100;j++) {
srslte_predecoding_single(input, ce, output, num_re, 1.0f, 0); srslte_predecoding_single(input, ce, output, NULL, num_re, 1.0f, 0);
} }
gettimeofday(&t[2], NULL); gettimeofday(&t[2], NULL);
get_time_interval(t); get_time_interval(t);
@ -188,7 +188,7 @@ int main(int argc, char **argv) {
gettimeofday(&t[1], NULL); gettimeofday(&t[1], NULL);
for (int j=0;j<100;j++) { for (int j=0;j<100;j++) {
srslte_predecoding_single(input, ce, output, num_re, 1.0f, srslte_chest_dl_get_noise_estimate(&est)); srslte_predecoding_single(input, ce, output, NULL, num_re, 1.0f, srslte_chest_dl_get_noise_estimate(&est));
} }
gettimeofday(&t[2], NULL); gettimeofday(&t[2], NULL);
get_time_interval(t); get_time_interval(t);

@ -45,6 +45,7 @@
#define FFTW_TYPE 0 #define FFTW_TYPE 0
#endif #endif
pthread_mutex_t fft_mutex = PTHREAD_MUTEX_INITIALIZER;
void srslte_dft_load() { void srslte_dft_load() {
#ifdef FFTW_WISDOM_FILE #ifdef FFTW_WISDOM_FILE
@ -58,10 +59,12 @@ void srslte_dft_exit() {
#ifdef FFTW_WISDOM_FILE #ifdef FFTW_WISDOM_FILE
fftwf_export_wisdom_to_filename(FFTW_WISDOM_FILE); fftwf_export_wisdom_to_filename(FFTW_WISDOM_FILE);
#endif #endif
fftwf_cleanup();
} }
int srslte_dft_plan(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_dir_t dir, int srslte_dft_plan(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_dir_t dir,
srslte_dft_mode_t mode) { srslte_dft_mode_t mode) {
bzero(plan, sizeof(srslte_dft_plan_t));
if(mode == SRSLTE_DFT_COMPLEX){ if(mode == SRSLTE_DFT_COMPLEX){
return srslte_dft_plan_c(plan,dft_points,dir); return srslte_dft_plan_c(plan,dft_points,dir);
} else { } else {
@ -99,10 +102,15 @@ int srslte_dft_replan_guru_c(srslte_dft_plan_t *plan, const int new_dft_points,
const fftwf_iodim iodim = {new_dft_points, istride, ostride}; const fftwf_iodim iodim = {new_dft_points, istride, ostride};
const fftwf_iodim howmany_dims = {how_many, idist, odist}; const fftwf_iodim howmany_dims = {how_many, idist, odist};
pthread_mutex_lock(&fft_mutex);
/* Destroy current plan */ /* Destroy current plan */
fftwf_destroy_plan(plan->p); fftwf_destroy_plan(plan->p);
plan->p = fftwf_plan_guru_dft(1, &iodim, 1, &howmany_dims, in_buffer, out_buffer, sign, FFTW_TYPE); plan->p = fftwf_plan_guru_dft(1, &iodim, 1, &howmany_dims, in_buffer, out_buffer, sign, FFTW_TYPE);
pthread_mutex_unlock(&fft_mutex);
if (!plan->p) { if (!plan->p) {
return -1; return -1;
} }
@ -114,11 +122,15 @@ int srslte_dft_replan_guru_c(srslte_dft_plan_t *plan, const int new_dft_points,
int srslte_dft_replan_c(srslte_dft_plan_t *plan, const int new_dft_points) { int srslte_dft_replan_c(srslte_dft_plan_t *plan, const int new_dft_points) {
int sign = (plan->dir == SRSLTE_DFT_FORWARD) ? FFTW_FORWARD : FFTW_BACKWARD; int sign = (plan->dir == SRSLTE_DFT_FORWARD) ? FFTW_FORWARD : FFTW_BACKWARD;
pthread_mutex_lock(&fft_mutex);
if (plan->p) { if (plan->p) {
fftwf_destroy_plan(plan->p); fftwf_destroy_plan(plan->p);
plan->p = NULL; plan->p = NULL;
} }
plan->p = fftwf_plan_dft_1d(new_dft_points, plan->in, plan->out, sign, FFTW_TYPE); plan->p = fftwf_plan_dft_1d(new_dft_points, plan->in, plan->out, sign, FFTW_TYPE);
pthread_mutex_unlock(&fft_mutex);
if (!plan->p) { if (!plan->p) {
return -1; return -1;
} }
@ -134,10 +146,14 @@ int srslte_dft_plan_guru_c(srslte_dft_plan_t *plan, const int dft_points, srslte
const fftwf_iodim iodim = {dft_points, istride, ostride}; const fftwf_iodim iodim = {dft_points, istride, ostride};
const fftwf_iodim howmany_dims = {how_many, idist, odist}; const fftwf_iodim howmany_dims = {how_many, idist, odist};
pthread_mutex_lock(&fft_mutex);
plan->p = fftwf_plan_guru_dft(1, &iodim, 1, &howmany_dims, in_buffer, out_buffer, sign, FFTW_TYPE); plan->p = fftwf_plan_guru_dft(1, &iodim, 1, &howmany_dims, in_buffer, out_buffer, sign, FFTW_TYPE);
if (!plan->p) { if (!plan->p) {
return -1; return -1;
} }
pthread_mutex_unlock(&fft_mutex);
plan->size = dft_points; plan->size = dft_points;
plan->init_size = plan->size; plan->init_size = plan->size;
plan->mode = SRSLTE_DFT_COMPLEX; plan->mode = SRSLTE_DFT_COMPLEX;
@ -154,8 +170,14 @@ int srslte_dft_plan_guru_c(srslte_dft_plan_t *plan, const int dft_points, srslte
int srslte_dft_plan_c(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_dir_t dir) { int srslte_dft_plan_c(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_dir_t dir) {
allocate(plan,sizeof(fftwf_complex),sizeof(fftwf_complex), dft_points); allocate(plan,sizeof(fftwf_complex),sizeof(fftwf_complex), dft_points);
pthread_mutex_lock(&fft_mutex);
int sign = (dir == SRSLTE_DFT_FORWARD) ? FFTW_FORWARD : FFTW_BACKWARD; int sign = (dir == SRSLTE_DFT_FORWARD) ? FFTW_FORWARD : FFTW_BACKWARD;
plan->p = fftwf_plan_dft_1d(dft_points, plan->in, plan->out, sign, FFTW_TYPE); plan->p = fftwf_plan_dft_1d(dft_points, plan->in, plan->out, sign, FFTW_TYPE);
pthread_mutex_unlock(&fft_mutex);
if (!plan->p) { if (!plan->p) {
return -1; return -1;
} }
@ -175,11 +197,15 @@ int srslte_dft_plan_c(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_
int srslte_dft_replan_r(srslte_dft_plan_t *plan, const int new_dft_points) { int srslte_dft_replan_r(srslte_dft_plan_t *plan, const int new_dft_points) {
int sign = (plan->dir == SRSLTE_DFT_FORWARD) ? FFTW_R2HC : FFTW_HC2R; int sign = (plan->dir == SRSLTE_DFT_FORWARD) ? FFTW_R2HC : FFTW_HC2R;
pthread_mutex_lock(&fft_mutex);
if (plan->p) { if (plan->p) {
fftwf_destroy_plan(plan->p); fftwf_destroy_plan(plan->p);
plan->p = NULL; plan->p = NULL;
} }
plan->p = fftwf_plan_r2r_1d(new_dft_points, plan->in, plan->out, sign, FFTW_TYPE); plan->p = fftwf_plan_r2r_1d(new_dft_points, plan->in, plan->out, sign, FFTW_TYPE);
pthread_mutex_unlock(&fft_mutex);
if (!plan->p) { if (!plan->p) {
return -1; return -1;
} }
@ -190,7 +216,11 @@ int srslte_dft_replan_r(srslte_dft_plan_t *plan, const int new_dft_points) {
int srslte_dft_plan_r(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_dir_t dir) { int srslte_dft_plan_r(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_dir_t dir) {
allocate(plan,sizeof(float),sizeof(float), dft_points); allocate(plan,sizeof(float),sizeof(float), dft_points);
int sign = (dir == SRSLTE_DFT_FORWARD) ? FFTW_R2HC : FFTW_HC2R; int sign = (dir == SRSLTE_DFT_FORWARD) ? FFTW_R2HC : FFTW_HC2R;
pthread_mutex_lock(&fft_mutex);
plan->p = fftwf_plan_r2r_1d(dft_points, plan->in, plan->out, sign, FFTW_TYPE); plan->p = fftwf_plan_r2r_1d(dft_points, plan->in, plan->out, sign, FFTW_TYPE);
pthread_mutex_unlock(&fft_mutex);
if (!plan->p) { if (!plan->p) {
return -1; return -1;
} }
@ -309,11 +339,15 @@ void srslte_dft_run_r(srslte_dft_plan_t *plan, const float *in, float *out) {
void srslte_dft_plan_free(srslte_dft_plan_t *plan) { void srslte_dft_plan_free(srslte_dft_plan_t *plan) {
if (!plan) return; if (!plan) return;
if (!plan->size) return; if (!plan->size) return;
pthread_mutex_lock(&fft_mutex);
if (!plan->is_guru) { if (!plan->is_guru) {
if (plan->in) fftwf_free(plan->in); if (plan->in) fftwf_free(plan->in);
if (plan->out) fftwf_free(plan->out); if (plan->out) fftwf_free(plan->out);
} }
if (plan->p) fftwf_destroy_plan(plan->p); if (plan->p) fftwf_destroy_plan(plan->p);
pthread_mutex_unlock(&fft_mutex);
bzero(plan, sizeof(srslte_dft_plan_t)); bzero(plan, sizeof(srslte_dft_plan_t));
} }

@ -128,6 +128,8 @@ int srslte_ofdm_init_mbsfn_(srslte_ofdm_t *q, srslte_cp_t cp, cf_t *in_buffer, c
if (sf_type == SRSLTE_SF_MBSFN) { if (sf_type == SRSLTE_SF_MBSFN) {
q->mbsfn_subframe = true; q->mbsfn_subframe = true;
q->non_mbsfn_region = 2; // default set to 2 q->non_mbsfn_region = 2; // default set to 2
} else {
q->mbsfn_subframe = false;
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;

@ -171,5 +171,8 @@ int main(int argc, char **argv) {
n_prb++; n_prb++;
} }
srslte_dft_exit();
exit(0); exit(0);
} }

@ -47,32 +47,56 @@ int srslte_softbuffer_rx_init(srslte_softbuffer_rx_t *q, uint32_t nof_prb) {
int ret = SRSLTE_ERROR_INVALID_INPUTS; int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL) { if (q != NULL) {
ret = SRSLTE_ERROR;
bzero(q, sizeof(srslte_softbuffer_rx_t)); bzero(q, sizeof(srslte_softbuffer_rx_t));
ret = srslte_ra_tbs_from_idx(26, nof_prb); ret = srslte_ra_tbs_from_idx(26, nof_prb);
if (ret != SRSLTE_ERROR) { if (ret != SRSLTE_ERROR) {
q->max_cb = (uint32_t) ret / (SRSLTE_TCOD_MAX_LEN_CB - 24) + 1; q->max_cb = (uint32_t) ret / (SRSLTE_TCOD_MAX_LEN_CB - 24) + 1;
ret = SRSLTE_ERROR;
q->buffer_f = srslte_vec_malloc(sizeof(int16_t*) * q->max_cb); q->buffer_f = srslte_vec_malloc(sizeof(int16_t*) * q->max_cb);
if (!q->buffer_f) { if (!q->buffer_f) {
perror("malloc"); perror("malloc");
return SRSLTE_ERROR; goto clean_exit;
}
q->data = srslte_vec_malloc(sizeof(uint8_t*) * q->max_cb);
if (!q->data) {
perror("malloc");
goto clean_exit;
}
q->cb_crc = srslte_vec_malloc(sizeof(bool) * q->max_cb);
if (!q->cb_crc) {
perror("malloc");
goto clean_exit;
} }
bzero(q->cb_crc, sizeof(bool) * q->max_cb);
// FIXME: Use HARQ buffer limitation based on UE category // FIXME: Use HARQ buffer limitation based on UE category
for (uint32_t i=0;i<q->max_cb;i++) { for (uint32_t i=0;i<q->max_cb;i++) {
q->buffer_f[i] = srslte_vec_malloc(sizeof(int16_t) * SOFTBUFFER_SIZE); q->buffer_f[i] = srslte_vec_malloc(sizeof(int16_t) * SOFTBUFFER_SIZE);
if (!q->buffer_f[i]) { if (!q->buffer_f[i]) {
perror("malloc"); perror("malloc");
return SRSLTE_ERROR; goto clean_exit;
}
q->data[i] = srslte_vec_malloc(sizeof(uint8_t) * 6144/8);
if (!q->data[i]) {
perror("malloc");
goto clean_exit;
} }
} }
//srslte_softbuffer_rx_reset(q); //srslte_softbuffer_rx_reset(q);
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} }
} }
clean_exit:
if (ret != SRSLTE_SUCCESS) {
srslte_softbuffer_rx_free(q);
}
return ret; return ret;
} }
@ -86,6 +110,17 @@ void srslte_softbuffer_rx_free(srslte_softbuffer_rx_t *q) {
} }
free(q->buffer_f); free(q->buffer_f);
} }
if (q->data) {
for (uint32_t i=0;i<q->max_cb;i++) {
if (q->data[i]) {
free(q->data[i]);
}
}
free(q->data);
}
if (q->cb_crc) {
free(q->cb_crc);
}
bzero(q, sizeof(srslte_softbuffer_rx_t)); bzero(q, sizeof(srslte_softbuffer_rx_t));
} }
} }
@ -110,6 +145,9 @@ void srslte_softbuffer_rx_reset_cb(srslte_softbuffer_rx_t *q, uint32_t nof_cb) {
} }
} }
} }
if (q->cb_crc) {
bzero(q->cb_crc, sizeof(bool) * q->max_cb);
}
} }

@ -198,6 +198,8 @@ int main(int argc, char **argv) {
} }
srslte_rm_turbo_free_tables(); srslte_rm_turbo_free_tables();
free(rm_bits_s);
free(rm_bits_f);
free(rm_bits); free(rm_bits);
free(rm_bits2); free(rm_bits2);
free(rm_bits2_bytes); free(rm_bits2_bytes);

@ -71,8 +71,6 @@ int main(int argc, char **argv) {
parse_args(argc, argv); parse_args(argc, argv);
srslte_tcod_gentable();
srslte_tcod_t tcod; srslte_tcod_t tcod;
srslte_tcod_init(&tcod, 6144); srslte_tcod_init(&tcod, 6144);

@ -279,6 +279,7 @@ int main(int argc, char **argv) {
free(llr); free(llr);
free(llr_c); free(llr_c);
free(data_rx); free(data_rx);
free(data_rx2);
if (snr_points == 1) { if (snr_points == 1) {
int expected_errors = get_expected_errors(nof_frames, seed, frame_length, tail_biting, ebno_db); int expected_errors = get_expected_errors(nof_frames, seed, frame_length, tail_biting, ebno_db);

@ -34,6 +34,7 @@
#include "srslte/phy/utils/vector.h" #include "srslte/phy/utils/vector.h"
#include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/mat.h" #include "srslte/phy/utils/mat.h"
#include "srslte/phy/utils/simd.h"
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
#include <immintrin.h> #include <immintrin.h>
@ -252,8 +253,49 @@ int srslte_predecoding_single_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
return nof_symbols; return nof_symbols;
} }
int srslte_predecoding_single_csi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, float *csi, int nof_rxant, int nof_symbols, float scaling, float noise_estimate) {
int i = 0;
#if SRSLTE_SIMD_CF_SIZE
const simd_f_t _noise = srslte_simd_f_set1(noise_estimate);
const simd_f_t _scaling = srslte_simd_f_set1(1.0f / scaling);
for (; i < nof_symbols - SRSLTE_SIMD_CF_SIZE + 1; i += SRSLTE_SIMD_CF_SIZE) {
simd_cf_t _r = srslte_simd_cf_zero();
simd_f_t _hh = srslte_simd_f_zero();
for (int p = 0; p < nof_rxant; p++) {
simd_cf_t _y = srslte_simd_cfi_load(&y[p][i]);
simd_cf_t _h = srslte_simd_cfi_load(&h[p][i]);
_r = srslte_simd_cf_add(_r, srslte_simd_cf_conjprod(_y, _h));
_hh = srslte_simd_f_add(_hh, srslte_simd_cf_re(srslte_simd_cf_conjprod(_h, _h)));
}
simd_f_t _csi = srslte_simd_f_add(_hh, _noise);
simd_cf_t _x = srslte_simd_cf_mul(srslte_simd_cf_mul(_r, _scaling), srslte_simd_f_rcp(_csi));
srslte_simd_f_store(&csi[i], _csi);
srslte_simd_cfi_store(&x[i], _x);
}
#endif
for (; i < nof_symbols; i++) {
cf_t r = 0;
float hh = 0;
float _scaling = 1.0f / scaling;
for (int p = 0; p < nof_rxant; p++) {
r += y[p][i] * conj(h[p][i]);
hh += (__real__ h[p][i] * __real__ h[p][i]) + (__imag__ h[p][i] * __imag__ h[p][i]);
}
csi[i] = hh + noise_estimate;
x[i] = r * _scaling / csi[i];
}
return nof_symbols;
}
/* ZF/MMSE SISO equalizer x=y(h'h+no)^(-1)h' (ZF if n0=0.0)*/ /* ZF/MMSE SISO equalizer x=y(h'h+no)^(-1)h' (ZF if n0=0.0)*/
int srslte_predecoding_single(cf_t *y_, cf_t *h_, cf_t *x, int nof_symbols, float scaling, float noise_estimate) { int srslte_predecoding_single(cf_t *y_, cf_t *h_, cf_t *x, float *csi, int nof_symbols, float scaling, float noise_estimate) {
cf_t *y[SRSLTE_MAX_PORTS]; cf_t *y[SRSLTE_MAX_PORTS];
cf_t *h[SRSLTE_MAX_PORTS]; cf_t *h[SRSLTE_MAX_PORTS];
@ -261,6 +303,10 @@ int srslte_predecoding_single(cf_t *y_, cf_t *h_, cf_t *x, int nof_symbols, floa
h[0] = h_; h[0] = h_;
int nof_rxant = 1; int nof_rxant = 1;
if (csi) {
return srslte_predecoding_single_csi(y, h, x, csi, nof_rxant, nof_symbols, scaling, noise_estimate);
}
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
if (nof_symbols > 32 && nof_rxant <= 2) { if (nof_symbols > 32 && nof_rxant <= 2) {
return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate); return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
@ -281,8 +327,12 @@ int srslte_predecoding_single(cf_t *y_, cf_t *h_, cf_t *x, int nof_symbols, floa
} }
/* ZF/MMSE SISO equalizer x=y(h'h+no)^(-1)h' (ZF if n0=0.0)*/ /* ZF/MMSE SISO equalizer x=y(h'h+no)^(-1)h' (ZF if n0=0.0)*/
int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, float *csi,
int nof_rxant, int nof_symbols, float scaling, float noise_estimate) { int nof_rxant, int nof_symbols, float scaling, float noise_estimate) {
if (csi) {
return srslte_predecoding_single_csi(y, h, x, csi, nof_rxant, nof_symbols, scaling, noise_estimate);
}
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
if (nof_symbols > 32) { if (nof_symbols > 32) {
return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate); return srslte_predecoding_single_avx(y, h, x, nof_rxant, nof_symbols, scaling, noise_estimate);
@ -1418,7 +1468,7 @@ void srslte_predecoding_set_mimo_decoder (srslte_mimo_decoder_t _mimo_decoder) {
/* 36.211 v10.3.0 Section 6.3.4 */ /* 36.211 v10.3.0 Section 6.3.4 */
int srslte_predecoding_type(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], int srslte_predecoding_type(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], int nof_rxant, int nof_ports, int nof_layers, cf_t *x[SRSLTE_MAX_LAYERS], float *csi, int nof_rxant, int nof_ports, int nof_layers,
int codebook_idx, int nof_symbols, srslte_mimo_type_t type, float scaling, int codebook_idx, int nof_symbols, srslte_mimo_type_t type, float scaling,
float noise_estimate) { float noise_estimate) {
@ -1451,7 +1501,7 @@ int srslte_predecoding_type(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS]
return -1; return -1;
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
if (nof_ports == 1 && nof_layers == 1) { if (nof_ports == 1 && nof_layers == 1) {
return srslte_predecoding_single_multi(y, h[0], x[0], nof_rxant, nof_symbols, scaling, noise_estimate); return srslte_predecoding_single_multi(y, h[0], x[0], csi, nof_rxant, nof_symbols, scaling, noise_estimate);
} else { } else {
fprintf(stderr, fprintf(stderr,
"Number of ports and layers must be 1 for transmission on single antenna ports (%d, %d)\n", nof_ports, nof_layers); "Number of ports and layers must be 1 for transmission on single antenna ports (%d, %d)\n", nof_ports, nof_layers);

@ -291,7 +291,7 @@ int main(int argc, char **argv) {
/* predecoding / equalization */ /* predecoding / equalization */
struct timeval t[3]; struct timeval t[3];
gettimeofday(&t[1], NULL); gettimeofday(&t[1], NULL);
srslte_predecoding_type(r, h, xr, nof_rx_ports, nof_tx_ports, nof_layers, srslte_predecoding_type(r, h, xr, NULL, nof_rx_ports, nof_tx_ports, nof_layers,
codebook_idx, nof_re, type, scaling, powf(10, -snr_db / 10)); codebook_idx, nof_re, type, scaling, powf(10, -snr_db / 10));
gettimeofday(&t[2], NULL); gettimeofday(&t[2], NULL);
get_time_interval(t); get_time_interval(t);

@ -197,6 +197,7 @@ int main(int argc, char **argv) {
} }
} }
free(llr2);
free(llr); free(llr);
free(symbols); free(symbols);
free(symbols_bytes); free(symbols_bytes);

@ -407,7 +407,7 @@ float srslte_cqi_to_coderate(uint32_t cqi) {
* Table III. * Table III.
*/ */
// From paper // From paper
static float cqi_to_snr_table[15] = { 1.95, 4, 6, 8, 10, 11.95, 14.05, 16, 17.9, 19.9, 21.5, 23.45, 25.0, 27.30, 29}; static float cqi_to_snr_table[15] = { 1.95, 4, 6, 8, 10, 11.95, 14.05, 16, 17.9, 20.9, 22.5, 24.75, 25.5, 27.30, 29};
// From experimental measurements @ 5 MHz // From experimental measurements @ 5 MHz
//static float cqi_to_snr_table[15] = { 1, 1.75, 3, 4, 5, 6, 7.5, 9, 11.5, 13.0, 15.0, 18, 20, 22.5, 26.5}; //static float cqi_to_snr_table[15] = { 1, 1.75, 3, 4, 5, 6, 7.5, 9, 11.5, 13.0, 15.0, 18, 20, 22.5, 26.5};

@ -400,6 +400,7 @@ int decode_frame(srslte_pbch_t *q, uint32_t src, uint32_t dst, uint32_t n,
uint32_t nof_bits, uint32_t nof_ports) { uint32_t nof_bits, uint32_t nof_ports) {
int j; int j;
if (dst + n <= 4 && src + n <= 4) {
memcpy(&q->temp[dst * nof_bits], &q->llr[src * nof_bits], memcpy(&q->temp[dst * nof_bits], &q->llr[src * nof_bits],
n * nof_bits * sizeof(float)); n * nof_bits * sizeof(float));
@ -428,6 +429,11 @@ int decode_frame(srslte_pbch_t *q, uint32_t src, uint32_t dst, uint32_t n,
} else { } else {
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
} else {
fprintf(stderr, "Error in PBCH decoder: Invalid frame pointers dst=%d, src=%d, n=%d\n", src, dst, n);
return -1;
}
} }
/* Decodes the PBCH channel /* Decodes the PBCH channel
@ -483,6 +489,8 @@ int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRS
q->frame_idx++; q->frame_idx++;
ret = 0; ret = 0;
uint32_t frame_idx = q->frame_idx;
/* Try decoding for 1 to cell.nof_ports antennas */ /* Try decoding for 1 to cell.nof_ports antennas */
if (q->search_all_ports) { if (q->search_all_ports) {
nant = 1; nant = 1;
@ -492,12 +500,12 @@ int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRS
do { do {
if (nant != 3) { if (nant != 3) {
DEBUG("Trying %d TX antennas with %d frames\n", nant, q->frame_idx); DEBUG("Trying %d TX antennas with %d frames\n", nant, frame_idx);
/* in control channels, only diversity is supported */ /* in control channels, only diversity is supported */
if (nant == 1) { if (nant == 1) {
/* no need for layer demapping */ /* no need for layer demapping */
srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, q->nof_symbols, 1.0f, noise_estimate); srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, NULL, q->nof_symbols, 1.0f, noise_estimate);
} else { } else {
srslte_predecoding_diversity(q->symbols[0], q->ce, x, nant, srslte_predecoding_diversity(q->symbols[0], q->ce, x, nant,
q->nof_symbols, 1.0f); q->nof_symbols, 1.0f);
@ -505,19 +513,19 @@ int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRS
} }
/* demodulate symbols */ /* demodulate symbols */
srslte_demod_soft_demodulate(SRSLTE_MOD_QPSK, q->d, &q->llr[nof_bits * (q->frame_idx - 1)], q->nof_symbols); srslte_demod_soft_demodulate(SRSLTE_MOD_QPSK, q->d, &q->llr[nof_bits * (frame_idx - 1)], q->nof_symbols);
/* We don't know where the 40 ms begin, so we try all combinations. E.g. if we received /* We don't know where the 40 ms begin, so we try all combinations. E.g. if we received
* 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234. * 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234.
* We know they are ordered. * We know they are ordered.
*/ */
for (nb = 0; nb < q->frame_idx; nb++) { for (nb = 0; nb < frame_idx; nb++) {
for (dst = 0; (dst < 4 - nb); dst++) { for (dst = 0; (dst < 4 - nb); dst++) {
for (src = 0; src < q->frame_idx - nb; src++) { for (src = 0; src < frame_idx - nb; src++) {
ret = decode_frame(q, src, dst, nb + 1, nof_bits, nant); ret = decode_frame(q, src, dst, nb + 1, nof_bits, nant);
if (ret == 1) { if (ret == 1) {
if (sfn_offset) { if (sfn_offset) {
*sfn_offset = (int) dst - src + q->frame_idx - 1; *sfn_offset = (int) dst - src + frame_idx - 1;
} }
if (nof_tx_ports) { if (nof_tx_ports) {
*nof_tx_ports = nant; *nof_tx_ports = nant;
@ -525,7 +533,8 @@ int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRS
if (bch_payload) { if (bch_payload) {
memcpy(bch_payload, q->data, sizeof(uint8_t) * SRSLTE_BCH_PAYLOAD_LEN); memcpy(bch_payload, q->data, sizeof(uint8_t) * SRSLTE_BCH_PAYLOAD_LEN);
} }
INFO("Decoded PBCH: src=%d, dst=%d, nb=%d, sfn_offset=%d\n", src, dst, nb+1, (int) dst - src + q->frame_idx - 1); INFO("Decoded PBCH: src=%d, dst=%d, nb=%d, sfn_offset=%d\n", src, dst, nb+1, (int) dst - src + frame_idx - 1);
srslte_pbch_decode_reset(q);
return 1; return 1;
} }
} }

@ -219,7 +219,7 @@ int srslte_pcfich_decode_multi(srslte_pcfich_t *q, cf_t *sf_symbols[SRSLTE_MAX_P
/* in control channels, only diversity is supported */ /* in control channels, only diversity is supported */
if (q->cell.nof_ports == 1) { if (q->cell.nof_ports == 1) {
/* no need for layer demapping */ /* no need for layer demapping */
srslte_predecoding_single_multi(q_symbols, q_ce[0], q->d, q->nof_rx_antennas, q->nof_symbols, 1.0f, noise_estimate); srslte_predecoding_single_multi(q_symbols, q_ce[0], q->d, NULL, q->nof_rx_antennas, q->nof_symbols, 1.0f, noise_estimate);
} else { } else {
srslte_predecoding_diversity_multi(q_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, q->nof_symbols, 1.0f); srslte_predecoding_diversity_multi(q_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, q->nof_symbols, 1.0f);
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports); srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports);

@ -490,7 +490,7 @@ int srslte_pdcch_extract_llr_multi(srslte_pdcch_t *q, cf_t *sf_symbols[SRSLTE_MA
/* in control channels, only diversity is supported */ /* in control channels, only diversity is supported */
if (q->cell.nof_ports == 1) { if (q->cell.nof_ports == 1) {
/* no need for layer demapping */ /* no need for layer demapping */
srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, nof_symbols, 1.0f, noise_estimate/2); srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, NULL, q->nof_rx_antennas, nof_symbols, 1.0f, noise_estimate/2);
} else { } else {
srslte_predecoding_diversity_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, nof_symbols, 1.0f); srslte_predecoding_diversity_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, nof_symbols, 1.0f);
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports); srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports);

@ -294,6 +294,10 @@ void srslte_pdsch_free(srslte_pdsch_t *q) {
if (q->d[i]) { if (q->d[i]) {
free(q->d[i]); free(q->d[i]);
} }
if (q->csi[i]) {
free(q->csi[i]);
}
} }
/* Free sch objects */ /* Free sch objects */
@ -394,6 +398,22 @@ void srslte_pdsch_set_power_allocation(srslte_pdsch_t *q, float rho_a) {
} }
} }
int srslte_pdsch_enable_csi(srslte_pdsch_t *q, bool enable) {
if (enable) {
for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
if (!q->csi[i]) {
q->csi[i] = srslte_vec_malloc(sizeof(float) * q->max_re);
if (!q->csi[i]) {
return SRSLTE_ERROR;
}
}
}
}
q->csi_enabled = enable;
return SRSLTE_SUCCESS;
}
void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti) void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti)
{ {
uint32_t rnti_idx = q->is_ue?0:rnti; uint32_t rnti_idx = q->is_ue?0:rnti;
@ -617,6 +637,41 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *c
/* Bit scrambling */ /* Bit scrambling */
srslte_scrambling_s_offset(seq, q->e[codeword_idx], 0, nbits->nof_bits); srslte_scrambling_s_offset(seq, q->e[codeword_idx], 0, nbits->nof_bits);
uint32_t qm = nbits->nof_bits/nbits->nof_re;
switch(cfg->grant.mcs[tb_idx].mod) {
case SRSLTE_MOD_BPSK:
qm = 1;
break;
case SRSLTE_MOD_QPSK:
qm = 2;
break;
case SRSLTE_MOD_16QAM:
qm = 4;
break;
case SRSLTE_MOD_64QAM:
qm = 6;
break;
default:
ERROR("No modulation");
}
int16_t *e = q->e[codeword_idx];
if (q->csi_enabled) {
const uint32_t csi_max_idx = srslte_vec_max_fi(q->csi[codeword_idx], nbits->nof_bits / qm);
float csi_max = 1.0f;
if (csi_max_idx < nbits->nof_bits / qm) {
csi_max = q->csi[codeword_idx][csi_max_idx];
}
for (int i = 0; i < nbits->nof_bits / qm; i++) {
const float csi = q->csi[codeword_idx][i] / csi_max;
for (int k = 0; k < qm; k++) {
e[qm * i + k] = (int16_t) ((float) e[qm * i + k] * csi);
}
}
}
/* Return */ /* Return */
ret = srslte_dlsch_decode2(&q->dl_sch, cfg, softbuffer, q->e[codeword_idx], data, tb_idx); ret = srslte_dlsch_decode2(&q->dl_sch, cfg, softbuffer, q->e[codeword_idx], data, tb_idx);
@ -702,7 +757,7 @@ int srslte_pdsch_decode(srslte_pdsch_t *q,
} }
// Pre-decoder // Pre-decoder
if (srslte_predecoding_type(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers, if (srslte_predecoding_type(q->symbols, q->ce, x, q->csi[0], q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers,
cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, pdsch_scaling, noise_estimate)<0) { cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, pdsch_scaling, noise_estimate)<0) {
DEBUG("Error predecoding\n"); DEBUG("Error predecoding\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;

@ -239,7 +239,7 @@ int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS],
/* in control channels, only diversity is supported */ /* in control channels, only diversity is supported */
if (q->cell.nof_ports == 1) { if (q->cell.nof_ports == 1) {
/* no need for layer demapping */ /* no need for layer demapping */
srslte_predecoding_single_multi(q_sf_symbols, q_ce[0], q->d0, q->nof_rx_antennas, SRSLTE_PHICH_MAX_NSYMB, 1.0f, noise_estimate); srslte_predecoding_single_multi(q_sf_symbols, q_ce[0], q->d0, NULL, q->nof_rx_antennas, SRSLTE_PHICH_MAX_NSYMB, 1.0f, noise_estimate);
} else { } else {
srslte_predecoding_diversity_multi(q_sf_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB, 1.0f); srslte_predecoding_diversity_multi(q_sf_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB, 1.0f);
srslte_layerdemap_diversity(x, q->d0, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports); srslte_layerdemap_diversity(x, q->d0, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports);

@ -152,7 +152,6 @@ int srslte_pmch_init(srslte_pmch_t *q, uint32_t max_prb)
int srslte_pmch_init_multi(srslte_pmch_t *q, uint32_t max_prb, uint32_t nof_rx_antennas) int srslte_pmch_init_multi(srslte_pmch_t *q, uint32_t max_prb, uint32_t nof_rx_antennas)
{ {
int ret = SRSLTE_ERROR_INVALID_INPUTS; int ret = SRSLTE_ERROR_INVALID_INPUTS;
int i;
if (q != NULL && if (q != NULL &&
nof_rx_antennas <= SRSLTE_MAX_PORTS) nof_rx_antennas <= SRSLTE_MAX_PORTS)
@ -169,7 +168,7 @@ int srslte_pmch_init_multi(srslte_pmch_t *q, uint32_t max_prb, uint32_t nof_rx_a
INFO("Init PMCH: %d PRBs, max_symbols: %d\n", INFO("Init PMCH: %d PRBs, max_symbols: %d\n",
max_prb, q->max_re); max_prb, q->max_re);
for (i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
if (srslte_modem_table_lte(&q->mod[i], modulations[i])) { if (srslte_modem_table_lte(&q->mod[i], modulations[i])) {
goto clean; goto clean;
} }
@ -189,7 +188,7 @@ int srslte_pmch_init_multi(srslte_pmch_t *q, uint32_t max_prb, uint32_t nof_rx_a
goto clean; goto clean;
} }
for (i = 0; i < SRSLTE_MAX_PORTS; i++) { for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->x[i]) { if (!q->x[i]) {
goto clean; goto clean;
@ -232,7 +231,7 @@ void srslte_pmch_free(srslte_pmch_t *q) {
if (q->d) { if (q->d) {
free(q->d); free(q->d);
} }
for (i = 0; i < q->cell.nof_ports; i++) { for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
if (q->x[i]) { if (q->x[i]) {
free(q->x[i]); free(q->x[i]);
} }
@ -378,7 +377,7 @@ int srslte_pmch_decode_multi(srslte_pmch_t *q,
} }
// No tx diversity in MBSFN // No tx diversity in MBSFN
srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, cfg->nbits[0].nof_re, 1.0f, noise_estimate); srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, NULL, q->nof_rx_antennas, cfg->nbits[0].nof_re, 1.0f, noise_estimate);
if (SRSLTE_VERBOSE_ISDEBUG()) { if (SRSLTE_VERBOSE_ISDEBUG()) {
DEBUG("SAVED FILE subframe.dat: received subframe symbols\n"); DEBUG("SAVED FILE subframe.dat: received subframe symbols\n");

@ -787,7 +787,7 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format,
} }
// Equalization // Equalization
srslte_predecoding_single(q->z_tmp, q->ce, q->z, nof_re, 1.0f, noise_estimate); srslte_predecoding_single(q->z_tmp, q->ce, q->z, NULL, nof_re, 1.0f, noise_estimate);
// Perform ML-decoding // Perform ML-decoding
float corr=0, corr_max=-1e9; float corr=0, corr_max=-1e9;

@ -596,7 +596,7 @@ int srslte_pusch_decode(srslte_pusch_t *q,
} }
// Equalization // Equalization
srslte_predecoding_single(q->d, q->ce, q->z, cfg->nbits.nof_re, 1.0f, noise_estimate); srslte_predecoding_single(q->d, q->ce, q->z, NULL, cfg->nbits.nof_re, 1.0f, noise_estimate);
// DFT predecoding // DFT predecoding
srslte_dft_precoding(&q->dft_precoding, q->z, q->d, cfg->grant.L_prb, cfg->nbits.nof_symb); srslte_dft_precoding(&q->dft_precoding, q->z, q->d, cfg->grant.L_prb, cfg->nbits.nof_symb);

@ -336,14 +336,17 @@ bool decode_tb_cb(srslte_sch_t *q,
decoder_input[i] = NULL; decoder_input[i] = NULL;
} }
uint32_t remaining_cb = 0;
for (int i=0;i<nof_cb;i++) { for (int i=0;i<nof_cb;i++) {
cb_map[i] = false; /* Do not process blocks with CRC Ok */
cb_map[i] = softbuffer->cb_crc[i];
if (softbuffer->cb_crc[i] == false) {
remaining_cb ++;
}
} }
srslte_tdec_reset(&q->decoder, cb_len); srslte_tdec_reset(&q->decoder, cb_len);
uint32_t remaining_cb = nof_cb;
q->nof_iterations = 0; q->nof_iterations = 0;
while(remaining_cb>0) { while(remaining_cb>0) {
@ -401,7 +404,8 @@ bool decode_tb_cb(srslte_sch_t *q,
// CRC is OK // CRC is OK
if (!srslte_crc_checksum_byte(crc_ptr, q->cb_in, len_crc)) { if (!srslte_crc_checksum_byte(crc_ptr, q->cb_in, len_crc)) {
memcpy(&data[(cb_idx[i]*rlen)/8], q->cb_in, rlen/8 * sizeof(uint8_t)); memcpy(softbuffer->data[cb_idx[i]], q->cb_in, rlen/8 * sizeof(uint8_t));
softbuffer->cb_crc[cb_idx[i]] = true;
q->nof_iterations += srslte_tdec_get_nof_iterations_cb(&q->decoder, i); q->nof_iterations += srslte_tdec_get_nof_iterations_cb(&q->decoder, i);
@ -418,15 +422,28 @@ bool decode_tb_cb(srslte_sch_t *q,
cb_idx[i], remaining_cb, i, first_cb, nof_cb); cb_idx[i], remaining_cb, i, first_cb, nof_cb);
q->nof_iterations += q->max_iterations; q->nof_iterations += q->max_iterations;
q->nof_iterations /= (nof_cb-remaining_cb+1); srslte_tdec_reset_cb(&q->decoder, i);
return false; remaining_cb--;
decoder_input[i] = NULL;
cb_idx[i] = 0;
}
}
} }
} }
softbuffer->tb_crc = true;
for (int i = 0; i < nof_cb && softbuffer->tb_crc; i++) {
/* If one CB failed return false */
softbuffer->tb_crc = softbuffer->cb_crc[i];
}
if (softbuffer->tb_crc) {
for (int i = 0; i < nof_cb; i++) {
memcpy(&data[i * rlen / 8], softbuffer->data[i], rlen/8 * sizeof(uint8_t));
} }
} }
q->nof_iterations /= nof_cb; q->nof_iterations /= nof_cb;
return true; return softbuffer->tb_crc;
} }
/** /**

@ -157,6 +157,7 @@ int main(int argc, char **argv) {
bzero(ce, sizeof(cf_t*)*SRSLTE_MAX_PORTS); bzero(ce, sizeof(cf_t*)*SRSLTE_MAX_PORTS);
bzero(tx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS); bzero(tx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS);
bzero(rx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS); bzero(rx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS);
bzero(t, 3 * sizeof(struct timeval));
cell.nof_ports = 1; cell.nof_ports = 1;
@ -469,5 +470,8 @@ quit:
} else { } else {
printf("Ok\n"); printf("Ok\n");
} }
srslte_dft_exit();
exit(ret); exit(ret);
} }

@ -80,8 +80,8 @@ static void log_overflow(rf_uhd_handler_t *h) {
static void log_late(rf_uhd_handler_t *h, bool is_rx) { static void log_late(rf_uhd_handler_t *h, bool is_rx) {
if (h->uhd_error_handler) { if (h->uhd_error_handler) {
srslte_rf_error_t error; srslte_rf_error_t error;
error.opt = is_rx?1:0;
bzero(&error, sizeof(srslte_rf_error_t)); bzero(&error, sizeof(srslte_rf_error_t));
error.opt = is_rx?1:0;
error.type = SRSLTE_RF_ERROR_LATE; error.type = SRSLTE_RF_ERROR_LATE;
h->uhd_error_handler(error); h->uhd_error_handler(error);
} }
@ -96,6 +96,19 @@ static void log_underflow(rf_uhd_handler_t *h) {
} }
} }
static void log_rx_error(rf_uhd_handler_t *h) {
if (h->uhd_error_handler) {
char error_string[512];
uhd_usrp_last_error(h->usrp, error_string, 512);
fprintf(stderr, "USRP reported the following error: %s\n", error_string);
srslte_rf_error_t error;
bzero(&error, sizeof(srslte_rf_error_t));
error.type = SRSLTE_RF_ERROR_RX;
h->uhd_error_handler(error);
}
}
static void* async_thread(void *h) { static void* async_thread(void *h) {
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h; rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
uhd_async_metadata_handle md; uhd_async_metadata_handle md;
@ -334,6 +347,7 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
perror("malloc"); perror("malloc");
return -1; return -1;
} }
bzero(handler, sizeof(rf_uhd_handler_t));
*h = handler; *h = handler;
/* Set priority to UHD threads */ /* Set priority to UHD threads */
@ -557,11 +571,12 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
uhd_meta_range_free(&gain_range); uhd_meta_range_free(&gain_range);
// Start low priority thread to receive async commands // Start low priority thread to receive async commands
/*
handler->async_thread_running = true; handler->async_thread_running = true;
if (pthread_create(&handler->async_thread, NULL, async_thread, handler)) { if (pthread_create(&handler->async_thread, NULL, async_thread, handler)) {
perror("pthread_create"); perror("pthread_create");
return -1; return -1;
} }*/
/* Restore priorities */ /* Restore priorities */
uhd_set_thread_priority(0, false); uhd_set_thread_priority(0, false);
@ -738,6 +753,7 @@ int rf_uhd_recv_with_time_multi(void *h,
num_rx_samples, md, 1.0, false, &rxd_samples); num_rx_samples, md, 1.0, false, &rxd_samples);
if (error) { if (error) {
fprintf(stderr, "Error receiving from UHD: %d\n", error); fprintf(stderr, "Error receiving from UHD: %d\n", error);
log_rx_error(handler);
return -1; return -1;
} }
@ -760,8 +776,12 @@ int rf_uhd_recv_with_time_multi(void *h,
} }
} }
} else { } else {
return uhd_rx_streamer_recv(handler->rx_stream, data, uhd_error error = uhd_rx_streamer_recv(handler->rx_stream, data, nsamples, md, 0.0, false, &rxd_samples);
nsamples, md, 0.0, false, &rxd_samples); if (error) {
fprintf(stderr, "Error receiving from UHD: %d\n", error);
log_rx_error(handler);
return -1;
}
} }
if (secs && frac_secs) { if (secs && frac_secs) {
uhd_rx_metadata_time_spec(handler->rx_md_first, secs, frac_secs); uhd_rx_metadata_time_spec(handler->rx_md_first, secs, frac_secs);

@ -152,21 +152,19 @@ clean_exit:
void srslte_sync_free(srslte_sync_t *q) void srslte_sync_free(srslte_sync_t *q)
{ {
if (q) { if (q) {
srslte_pss_free(&q->pss); srslte_pss_free(&q->pss);
srslte_sss_free(&q->sss); srslte_sss_free(&q->sss);
srslte_cfo_free(&q->cfo_corr_frame); srslte_cfo_free(&q->cfo_corr_frame);
srslte_cfo_free(&q->cfo_corr_symbol); srslte_cfo_free(&q->cfo_corr_symbol);
srslte_cp_synch_free(&q->cp_synch); srslte_cp_synch_free(&q->cp_synch);
if (q->cfo_i_initiated) {
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
if (q->cfo_i_corr[i]) { if (q->cfo_i_corr[i]) {
free(q->cfo_i_corr[i]); free(q->cfo_i_corr[i]);
} }
srslte_pss_free(&q->pss_i[i]); srslte_pss_free(&q->pss_i[i]);
} }
}
if (q->temp) { if (q->temp) {
free(q->temp); free(q->temp);
} }

@ -74,7 +74,7 @@ void usage(char *prog) {
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "adgetvsfil")) != -1) { while ((opt = getopt(argc, argv, "adgetvnsfil")) != -1) {
switch (opt) { switch (opt) {
case 'a': case 'a':
rf_args = argv[optind]; rf_args = argv[optind];

@ -71,7 +71,6 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q,
q->pmch_pkt_errors = 0; q->pmch_pkt_errors = 0;
q->pmch_pkts_total = 0; q->pmch_pkts_total = 0;
q->pending_ul_dci_rnti = 0; q->pending_ul_dci_rnti = 0;
q->sample_offset = 0;
q->nof_rx_antennas = nof_rx_antennas; q->nof_rx_antennas = nof_rx_antennas;
for (int j = 0; j < SRSLTE_MAX_PORTS; j++) { for (int j = 0; j < SRSLTE_MAX_PORTS; j++) {
@ -147,11 +146,6 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q,
goto clean_exit; goto clean_exit;
} }
} }
if (srslte_cfo_init(&q->sfo_correct, max_prb*SRSLTE_NRE)) {
fprintf(stderr, "Error initiating SFO correct\n");
goto clean_exit;
}
srslte_cfo_set_tol(&q->sfo_correct, 1e-5f/q->fft[0].symbol_sz);
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} else { } else {
@ -178,7 +172,6 @@ void srslte_ue_dl_free(srslte_ue_dl_t *q) {
srslte_pdcch_free(&q->pdcch); srslte_pdcch_free(&q->pdcch);
srslte_pdsch_free(&q->pdsch); srslte_pdsch_free(&q->pdsch);
srslte_pmch_free(&q->pmch); srslte_pmch_free(&q->pmch);
srslte_cfo_free(&q->sfo_correct);
for (int i = 0; i < SRSLTE_MAX_TB; i++) { for (int i = 0; i < SRSLTE_MAX_TB; i++) {
srslte_softbuffer_rx_free(q->softbuffers[i]); srslte_softbuffer_rx_free(q->softbuffers[i]);
if (q->softbuffers[i]) { if (q->softbuffers[i]) {
@ -209,7 +202,6 @@ int srslte_ue_dl_set_cell(srslte_ue_dl_t *q, srslte_cell_t cell)
q->pkt_errors = 0; q->pkt_errors = 0;
q->pkts_total = 0; q->pkts_total = 0;
q->pending_ul_dci_rnti = 0; q->pending_ul_dci_rnti = 0;
q->sample_offset = 0;
if (q->cell.id != cell.id || q->cell.nof_prb == 0) { if (q->cell.id != cell.id || q->cell.nof_prb == 0) {
if (q->cell.nof_prb != 0) { if (q->cell.nof_prb != 0) {
@ -220,11 +212,6 @@ int srslte_ue_dl_set_cell(srslte_ue_dl_t *q, srslte_cell_t cell)
fprintf(stderr, "Error resizing REGs\n"); fprintf(stderr, "Error resizing REGs\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
if (srslte_cfo_resize(&q->sfo_correct, q->cell.nof_prb*SRSLTE_NRE)) {
fprintf(stderr, "Error resizing SFO correct\n");
return SRSLTE_ERROR;
}
srslte_cfo_set_tol(&q->sfo_correct, 1e-5f/q->fft[0].symbol_sz);
for (int port = 0; port < q->nof_rx_antennas; port++) { for (int port = 0; port < q->nof_rx_antennas; port++) {
if (srslte_ofdm_rx_set_prb(&q->fft[port], q->cell.cp, q->cell.nof_prb)) { if (srslte_ofdm_rx_set_prb(&q->fft[port], q->cell.cp, q->cell.nof_prb)) {
fprintf(stderr, "Error resizing FFT\n"); fprintf(stderr, "Error resizing FFT\n");
@ -348,10 +335,6 @@ void srslte_ue_dl_reset(srslte_ue_dl_t *q) {
bzero(&q->pdsch_cfg, sizeof(srslte_pdsch_cfg_t)); bzero(&q->pdsch_cfg, sizeof(srslte_pdsch_cfg_t));
} }
void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q, float sample_offset) {
q->sample_offset = sample_offset;
}
/** Applies the following operations to a subframe of synchronized samples: /** Applies the following operations to a subframe of synchronized samples:
* - OFDM demodulation * - OFDM demodulation
* - Channel estimation * - Channel estimation
@ -395,17 +378,6 @@ int srslte_ue_dl_decode_fft_estimate_noguru(srslte_ue_dl_t *q, cf_t *input[SRSLT
/* Run FFT for all subframe data */ /* Run FFT for all subframe data */
for (int j=0;j<q->nof_rx_antennas;j++) { for (int j=0;j<q->nof_rx_antennas;j++) {
srslte_ofdm_rx_sf_ng(&q->fft[j], input[j], q->sf_symbols_m[j]); srslte_ofdm_rx_sf_ng(&q->fft[j], input[j], q->sf_symbols_m[j]);
/* Correct SFO multiplying by complex exponential in the time domain */
if (q->sample_offset) {
int nsym = SRSLTE_CP_NSYMB(q->cell.cp);
for (int i=0;i<2*nsym;i++) {
srslte_cfo_correct(&q->sfo_correct,
&q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE],
&q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE],
q->sample_offset / q->fft[j].symbol_sz);
}
}
} }
return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM); return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM);
} else { } else {

@ -756,6 +756,8 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE
srslte_agc_process(&q->agc, input_buffer[0], q->sf_len); srslte_agc_process(&q->agc, input_buffer[0], q->sf_len);
} }
INFO("SYNC FIND: sf_idx=%d, ret=%d, next_state=%d\n", q->sf_idx, ret, q->state);
break; break;
case SF_TRACK: case SF_TRACK:
@ -817,6 +819,9 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE
q->frame_total_cnt++; q->frame_total_cnt++;
} }
INFO("SYNC TRACK: sf_idx=%d, ret=%d, next_state=%d\n", q->sf_idx, ret, q->state);
break; break;
} }
} }

@ -157,6 +157,8 @@ int main(int argc, char **argv) {
if(test_dft(in) != 0) if(test_dft(in) != 0)
return -1; return -1;
srslte_dft_exit();
free(in); free(in);
printf("Done\n"); printf("Done\n");
exit(0); exit(0);

@ -265,6 +265,7 @@ TEST(srslte_vec_sum_fff,
free(x); free(x);
free(y); free(y);
free(z);
) )
TEST(srslte_vec_sub_fff, TEST(srslte_vec_sub_fff,
@ -287,6 +288,7 @@ TEST(srslte_vec_sub_fff,
free(x); free(x);
free(y); free(y);
free(z);
) )
TEST(srslte_vec_dot_prod_ccc, TEST(srslte_vec_dot_prod_ccc,
@ -354,6 +356,7 @@ TEST(srslte_vec_prod_ccc,
} }
free(x); free(x);
free(y);
free(z); free(z);
) )
@ -407,6 +410,7 @@ TEST(srslte_vec_prod_conj_ccc,
} }
free(x); free(x);
free(y);
free(z); free(z);
) )

@ -200,10 +200,16 @@ void srslte_vec_fprint_hex(FILE *stream, uint8_t *x, const uint32_t len) {
fprintf(stream, "];\n"); fprintf(stream, "];\n");
} }
void srslte_vec_sprint_hex(char *str, uint8_t *x, const uint32_t len) { void srslte_vec_sprint_hex(char *str, const uint32_t max_str_len, uint8_t *x, const uint32_t len) {
uint32_t i, nbytes; uint32_t i, nbytes;
uint8_t byte; uint8_t byte;
nbytes = len/8; nbytes = len/8;
// check that hex string fits in buffer (every byte takes 3 characters, plus brackets)
if ((3*(len/8 + ((len%8)?1:0))) + 2 >= max_str_len) {
fprintf(stderr, "Buffer too small for printing hex string (max_str_len=%d, payload_len=%d).\n", max_str_len, len);
return;
}
int n=0; int n=0;
n+=sprintf(&str[n], "["); n+=sprintf(&str[n], "[");
for (i=0;i<nbytes;i++) { for (i=0;i<nbytes;i++) {
@ -215,6 +221,7 @@ void srslte_vec_sprint_hex(char *str, uint8_t *x, const uint32_t len) {
n+=sprintf(&str[n], "%02x ", byte); n+=sprintf(&str[n], "%02x ", byte);
} }
n+=sprintf(&str[n], "]"); n+=sprintf(&str[n], "]");
str[max_str_len-1] = 0;
} }
void srslte_vec_save_file(char *filename, const void *buffer, const uint32_t len) { void srslte_vec_save_file(char *filename, const void *buffer, const uint32_t len) {

@ -71,9 +71,14 @@ bool radio::init(char *args, char *devname, uint32_t nof_channels)
} }
saved_nof_channels = nof_channels; saved_nof_channels = nof_channels;
is_initialized = true;
return true; return true;
} }
bool radio::is_init() {
return is_initialized;
}
void radio::stop() void radio::stop()
{ {
srslte_rf_close(&rf_device); srslte_rf_close(&rf_device);
@ -82,11 +87,8 @@ void radio::stop()
void radio::reset() void radio::reset()
{ {
printf("Resetting Radio...\n"); printf("Resetting Radio...\n");
srslte_rf_close(&rf_device); srslte_rf_stop_rx_stream(&rf_device);
sleep(3); radio_is_streaming = false;
if (srslte_rf_open_devname(&rf_device, saved_devname, saved_args, saved_nof_channels)) {
fprintf(stderr, "Error opening RF device\n");
}
} }
void radio::set_manual_calibration(rf_cal_t* calibration) void radio::set_manual_calibration(rf_cal_t* calibration)
@ -141,6 +143,10 @@ bool radio::rx_at(void* buffer, uint32_t nof_samples, srslte_timestamp_t rx_time
bool radio::rx_now(void* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t* rxd_time) bool radio::rx_now(void* buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t* rxd_time)
{ {
if (!radio_is_streaming) {
srslte_rf_start_rx_stream(&rf_device, false);
radio_is_streaming = true;
}
if (srslte_rf_recv_with_time_multi(&rf_device, buffer, nof_samples, true, if (srslte_rf_recv_with_time_multi(&rf_device, buffer, nof_samples, true,
rxd_time?&rxd_time->full_secs:NULL, rxd_time?&rxd_time->frac_secs:NULL) > 0) { rxd_time?&rxd_time->full_secs:NULL, rxd_time?&rxd_time->frac_secs:NULL) > 0) {
return true; return true;
@ -295,7 +301,9 @@ void radio::set_master_clock_rate(double rate)
void radio::set_rx_srate(double srate) void radio::set_rx_srate(double srate)
{ {
srslte_rf_stop_rx_stream(&rf_device);
srslte_rf_set_rx_srate(&rf_device, srate); srslte_rf_set_rx_srate(&rf_device, srate);
srslte_rf_start_rx_stream(&rf_device, false);
} }
void radio::set_tx_freq(double freq) void radio::set_tx_freq(double freq)
@ -446,16 +454,6 @@ void radio::set_tx_srate(double srate)
tx_adv_sec = nsamples/cur_tx_srate; tx_adv_sec = nsamples/cur_tx_srate;
} }
void radio::start_rx(bool now)
{
srslte_rf_start_rx_stream(&rf_device, now);
}
void radio::stop_rx()
{
srslte_rf_stop_rx_stream(&rf_device);
}
void radio::register_error_handler(srslte_rf_error_handler_t h) void radio::register_error_handler(srslte_rf_error_handler_t h)
{ {
srslte_rf_register_error_handler(&rf_device, h); srslte_rf_register_error_handler(&rf_device, h);

@ -37,6 +37,7 @@ bool radio_multi::init_multi(uint32_t nof_rx_antennas, char* args, char* devname
strncpy(saved_devname, devname, 127); strncpy(saved_devname, devname, 127);
} }
is_initialized = true;
return true; return true;
} }
@ -46,6 +47,10 @@ bool radio_multi::rx_now(cf_t *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, s
for (int i=0;i<SRSLTE_MAX_PORTS;i++) { for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
ptr[i] = buffer[i]; ptr[i] = buffer[i];
} }
if (!radio_is_streaming) {
srslte_rf_start_rx_stream(&rf_device, false);
radio_is_streaming = true;
}
if (srslte_rf_recv_with_time_multi(&rf_device, ptr, nof_samples, true, if (srslte_rf_recv_with_time_multi(&rf_device, ptr, nof_samples, true,
rxd_time?&rxd_time->full_secs:NULL, rxd_time?&rxd_time->frac_secs:NULL) > 0) { rxd_time?&rxd_time->full_secs:NULL, rxd_time?&rxd_time->frac_secs:NULL) > 0) {
return true; return true;

@ -92,8 +92,12 @@ bool pdcp::is_drb_enabled(uint32_t lcid)
void pdcp::write_sdu(uint32_t lcid, byte_buffer_t *sdu) void pdcp::write_sdu(uint32_t lcid, byte_buffer_t *sdu)
{ {
if(valid_lcid(lcid)) if(valid_lcid(lcid)) {
pdcp_array[lcid].write_sdu(sdu); pdcp_array[lcid].write_sdu(sdu);
} else {
pdcp_log->warning("Writing sdu: lcid=%d. Deallocating sdu\n", lcid);
byte_buffer_pool::get_instance()->deallocate(sdu);
}
} }
void pdcp::add_bearer(uint32_t lcid, srslte_pdcp_config_t cfg) void pdcp::add_bearer(uint32_t lcid, srslte_pdcp_config_t cfg)
@ -149,8 +153,12 @@ void pdcp::enable_encryption(uint32_t lcid)
*******************************************************************************/ *******************************************************************************/
void pdcp::write_pdu(uint32_t lcid, byte_buffer_t *pdu) void pdcp::write_pdu(uint32_t lcid, byte_buffer_t *pdu)
{ {
if(valid_lcid(lcid)) if(valid_lcid(lcid)) {
pdcp_array[lcid].write_pdu(pdu); pdcp_array[lcid].write_pdu(pdu);
} else {
pdcp_log->warning("Writing pdu: lcid=%d. Deallocating pdu\n", lcid);
byte_buffer_pool::get_instance()->deallocate(pdu);
}
} }
void pdcp::write_pdu_bcch_bch(byte_buffer_t *sdu) void pdcp::write_pdu_bcch_bch(byte_buffer_t *sdu)

@ -187,10 +187,14 @@ void rlc::write_pdu_bcch_bch(uint8_t *payload, uint32_t nof_bytes)
rlc_log->info_hex(payload, nof_bytes, "BCCH BCH message received."); rlc_log->info_hex(payload, nof_bytes, "BCCH BCH message received.");
dl_tput_bytes[0] += nof_bytes; dl_tput_bytes[0] += nof_bytes;
byte_buffer_t *buf = pool_allocate; byte_buffer_t *buf = pool_allocate;
if (buf) {
memcpy(buf->msg, payload, nof_bytes); memcpy(buf->msg, payload, nof_bytes);
buf->N_bytes = nof_bytes; buf->N_bytes = nof_bytes;
buf->set_timestamp(); buf->set_timestamp();
pdcp->write_pdu_bcch_bch(buf); pdcp->write_pdu_bcch_bch(buf);
} else {
rlc_log->error("Fatal error: Out of buffers from the pool in write_pdu_bcch_bch()\n");
}
} }
void rlc::write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes) void rlc::write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes)
@ -198,10 +202,14 @@ void rlc::write_pdu_bcch_dlsch(uint8_t *payload, uint32_t nof_bytes)
rlc_log->info_hex(payload, nof_bytes, "BCCH TXSCH message received."); rlc_log->info_hex(payload, nof_bytes, "BCCH TXSCH message received.");
dl_tput_bytes[0] += nof_bytes; dl_tput_bytes[0] += nof_bytes;
byte_buffer_t *buf = pool_allocate; byte_buffer_t *buf = pool_allocate;
if (buf) {
memcpy(buf->msg, payload, nof_bytes); memcpy(buf->msg, payload, nof_bytes);
buf->N_bytes = nof_bytes; buf->N_bytes = nof_bytes;
buf->set_timestamp(); buf->set_timestamp();
pdcp->write_pdu_bcch_dlsch(buf); pdcp->write_pdu_bcch_dlsch(buf);
} else {
rlc_log->error("Fatal error: Out of buffers from the pool in write_pdu_bcch_dlsch()\n");
}
} }
void rlc::write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes) void rlc::write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes)
@ -209,10 +217,14 @@ void rlc::write_pdu_pcch(uint8_t *payload, uint32_t nof_bytes)
rlc_log->info_hex(payload, nof_bytes, "PCCH message received."); rlc_log->info_hex(payload, nof_bytes, "PCCH message received.");
dl_tput_bytes[0] += nof_bytes; dl_tput_bytes[0] += nof_bytes;
byte_buffer_t *buf = pool_allocate; byte_buffer_t *buf = pool_allocate;
if (buf) {
memcpy(buf->msg, payload, nof_bytes); memcpy(buf->msg, payload, nof_bytes);
buf->N_bytes = nof_bytes; buf->N_bytes = nof_bytes;
buf->set_timestamp(); buf->set_timestamp();
pdcp->write_pdu_pcch(buf); pdcp->write_pdu_pcch(buf);
} else {
rlc_log->error("Fatal error: Out of buffers from the pool in write_pdu_pcch()\n");
}
} }
/******************************************************************************* /*******************************************************************************
@ -281,6 +293,7 @@ void rlc::add_bearer(uint32_t lcid, srslte_rlc_config_t cnfg)
bool rlc::valid_lcid(uint32_t lcid) bool rlc::valid_lcid(uint32_t lcid)
{ {
if(lcid >= SRSLTE_N_RADIO_BEARERS) { if(lcid >= SRSLTE_N_RADIO_BEARERS) {
rlc_log->warning("Invalid LCID=%d\n", lcid);
return false; return false;
} else if(!rlc_array[lcid].active()) { } else if(!rlc_array[lcid].active()) {
return false; return false;

@ -72,6 +72,14 @@ rlc_am::~rlc_am()
{ {
// reset RLC and dealloc SDUs // reset RLC and dealloc SDUs
stop(); stop();
if(rx_sdu) {
pool->deallocate(rx_sdu);
}
if(tx_sdu) {
pool->deallocate(tx_sdu);
}
} }
void rlc_am::init(srslte::log *log_, void rlc_am::init(srslte::log *log_,
@ -190,7 +198,7 @@ uint32_t rlc_am::get_bearer()
void rlc_am::write_sdu(byte_buffer_t *sdu) void rlc_am::write_sdu(byte_buffer_t *sdu)
{ {
tx_sdu_queue.write(sdu); tx_sdu_queue.write(sdu);
log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU, tx_sdu_len=%d", rrc->get_rb_name(lcid).c_str(), tx_sdu_queue.size()); log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU (%d B, tx_sdu_queue_len=%d)", rrc->get_rb_name(lcid).c_str(), sdu->N_bytes, tx_sdu_queue.size());
} }
/**************************************************************************** /****************************************************************************
@ -265,6 +273,27 @@ uint32_t rlc_am::get_buffer_state()
goto unlock_and_return; goto unlock_and_return;
} }
// check if pollRetx timer expired (Section 5.2.2.3 in TS 36.322)
if (poll_retx()) {
// if both tx and retx buffer are empty, retransmit next PDU to be ack'ed
log->info("Poll reTx timer expired (lcid=%d)\n", lcid);
if ((tx_window.size() > 0 && retx_queue.size() == 0 && tx_sdu_queue.size() == 0)) {
std::map<uint32_t, rlc_amd_tx_pdu_t>::iterator it = tx_window.find(vt_s - 1);
if (it != tx_window.end()) {
log->info("Schedule last PDU (SN=%d) for reTx.\n", vt_s - 1);
rlc_amd_retx_t retx;
retx.is_segment = false;
retx.so_start = 0;
retx.so_end = tx_window[vt_s - 1].buf->N_bytes;
retx.sn = vt_s - 1;
retx_queue.push_back(retx);
} else {
log->error("Found invalid PDU in tx_window.\n");
}
poll_retx_timeout.start(cfg.t_poll_retx);
}
}
// Bytes needed for retx // Bytes needed for retx
if(retx_queue.size() > 0) { if(retx_queue.size() > 0) {
rlc_amd_retx_t retx = retx_queue.front(); rlc_amd_retx_t retx = retx_queue.front();
@ -819,7 +848,7 @@ int rlc_am::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
// Set SN // Set SN
header.sn = vt_s; header.sn = vt_s;
vt_s = (vt_s + 1)%MOD; vt_s = (vt_s + 1)%MOD;
log->info("%s PDU scheduled for tx. SN: %d\n", rrc->get_rb_name(lcid).c_str(), header.sn); log->info("%s PDU scheduled for tx. SN: %d (%d B)\n", rrc->get_rb_name(lcid).c_str(), header.sn, pdu->N_bytes);
// Place PDU in tx_window, write header and TX // Place PDU in tx_window, write header and TX
tx_window[header.sn].buf = pdu; tx_window[header.sn].buf = pdu;

@ -125,10 +125,14 @@ int rlc_tm::read_pdu(uint8_t *payload, uint32_t nof_bytes)
void rlc_tm::write_pdu(uint8_t *payload, uint32_t nof_bytes) void rlc_tm::write_pdu(uint8_t *payload, uint32_t nof_bytes)
{ {
byte_buffer_t *buf = pool_allocate; byte_buffer_t *buf = pool_allocate;
if (buf) {
memcpy(buf->msg, payload, nof_bytes); memcpy(buf->msg, payload, nof_bytes);
buf->N_bytes = nof_bytes; buf->N_bytes = nof_bytes;
buf->set_timestamp(); buf->set_timestamp();
pdcp->write_pdu(lcid, buf); pdcp->write_pdu(lcid, buf);
} else {
log->error("Fatal Error: Couldn't allocate buffer in rlc_tm::write_pdu().\n");
}
} }
} // namespace srsue } // namespace srsue

@ -136,11 +136,11 @@ void rlc_um::reset()
vr_uh = 0; vr_uh = 0;
pdu_lost = false; pdu_lost = false;
if(rx_sdu) { if(rx_sdu) {
rx_sdu->reset(); pool->deallocate(rx_sdu);
} }
if(tx_sdu) { if(tx_sdu) {
tx_sdu->reset(); pool->deallocate(tx_sdu);
} }
if(mac_timers) { if(mac_timers) {
@ -173,7 +173,7 @@ uint32_t rlc_um::get_bearer()
void rlc_um::write_sdu(byte_buffer_t *sdu) void rlc_um::write_sdu(byte_buffer_t *sdu)
{ {
tx_sdu_queue.write(sdu); tx_sdu_queue.write(sdu);
log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU, tx_sdu_len=%d", rrc->get_rb_name(lcid).c_str(), tx_sdu_queue.size()); log->info_hex(sdu->msg, sdu->N_bytes, "%s Tx SDU (% B ,tx_sdu_queue_len=%d)", rrc->get_rb_name(lcid).c_str(), sdu->N_bytes, tx_sdu_queue.size());
} }
/**************************************************************************** /****************************************************************************
@ -448,8 +448,13 @@ void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes)
void rlc_um::reassemble_rx_sdus() void rlc_um::reassemble_rx_sdus()
{ {
if(!rx_sdu) if(!rx_sdu) {
rx_sdu = pool_allocate; rx_sdu = pool_allocate;
if (!rx_sdu) {
log->error("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus().\n");
return;
}
}
// First catch up with lower edge of reordering window // First catch up with lower edge of reordering window
while(!inside_reordering_window(vr_ur)) while(!inside_reordering_window(vr_ur))
@ -474,6 +479,10 @@ void rlc_um::reassemble_rx_sdus()
rx_sdu->set_timestamp(); rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu); pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate; rx_sdu = pool_allocate;
if (!rx_sdu) {
log->error("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus().\n");
return;
}
} }
pdu_lost = false; pdu_lost = false;
} }
@ -494,6 +503,10 @@ void rlc_um::reassemble_rx_sdus()
rx_sdu->set_timestamp(); rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu); pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate; rx_sdu = pool_allocate;
if (!rx_sdu) {
log->error("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus().\n");
return;
}
} }
pdu_lost = false; pdu_lost = false;
} }
@ -528,6 +541,10 @@ void rlc_um::reassemble_rx_sdus()
rx_sdu->set_timestamp(); rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu); pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate; rx_sdu = pool_allocate;
if (!rx_sdu) {
log->error("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus().\n");
return;
}
} }
pdu_lost = false; pdu_lost = false;
} }
@ -557,6 +574,10 @@ void rlc_um::reassemble_rx_sdus()
rx_sdu->set_timestamp(); rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu); pdcp->write_pdu(lcid, rx_sdu);
rx_sdu = pool_allocate; rx_sdu = pool_allocate;
if (!rx_sdu) {
log->error("Fatal Error: Couldn't allocate buffer in rlc_um::reassemble_rx_sdus().\n");
return;
}
} }
pdu_lost = false; pdu_lost = false;
} }

@ -64,7 +64,43 @@ private:
pthread_mutex_t mutex; pthread_mutex_t mutex;
}; };
int main(int argc, char **argv) {
int timer_thread_test()
{
bool result;
uint32_t id = 0;
uint32_t duration_msec = 5;
uint32_t result_tolerance = 1;
callback c;
timeout t;
gettimeofday(&c.start_time[1], NULL);
t.start(duration_msec);
while (t.is_running() && !t.expired()) {
printf("time to expire=%dms\n", t.get_msec_to_expire());
usleep(1000);
}
gettimeofday(&c.start_time[2], NULL);
get_time_interval(c.start_time);
uint32_t diff_ms = c.start_time[0].tv_usec*1e-3;
printf("Target duration: %dms, started: %ld:%ld, ended: %ld:%ld, actual duration %dms\n",
duration_msec, c.start_time[1].tv_sec, c.start_time[1].tv_usec, c.start_time[2].tv_sec, c.start_time[2].tv_usec, diff_ms);
result = ((duration_msec - result_tolerance) < diff_ms || diff_ms < (duration_msec + result_tolerance));
if(result) {
printf("Timer thread test passed\n");
return 0;
}else{
return -1;
}
}
int single_thread_test()
{
bool result; bool result;
uint32_t id = 0; uint32_t id = 0;
uint32_t duration_msec = 5; uint32_t duration_msec = 5;
@ -84,10 +120,25 @@ int main(int argc, char **argv) {
result = (diff_ms == duration_msec); result = (diff_ms == duration_msec);
if(result) { if(result) {
printf("Passed\n"); printf("Single thread test passed\n");
exit(0); return 0;
}else{ }else{
printf("Failed\n;"); return -1;
exit(1);
} }
} }
int main(int argc, char **argv)
{
if (single_thread_test()) {
printf("Single thread test failed.\n");
return -1;
}
if (timer_thread_test()) {
printf("Timer thread test failed.\n");
return -1;
}
return 0;
}

@ -31,7 +31,8 @@ target_link_libraries(rlc_am_test srslte_upper srslte_phy srslte_common)
add_test(rlc_am_test rlc_am_test) add_test(rlc_am_test rlc_am_test)
add_executable(rlc_am_stress_test rlc_am_stress_test.cc) add_executable(rlc_am_stress_test rlc_am_stress_test.cc)
target_link_libraries(rlc_am_stress_test srslte_upper srslte_phy srslte_common) target_link_libraries(rlc_am_stress_test srslte_upper srslte_phy srslte_common ${Boost_LIBRARIES})
add_test(rlc_am_stress_test rlc_am_stress_test --duration 10)
add_executable(rlc_um_data_test rlc_um_data_test.cc) add_executable(rlc_um_data_test rlc_um_data_test.cc)
target_link_libraries(rlc_um_data_test srslte_upper srslte_phy srslte_common) target_link_libraries(rlc_um_data_test srslte_upper srslte_phy srslte_common)

@ -31,23 +31,77 @@
#include "srslte/common/logger_stdout.h" #include "srslte/common/logger_stdout.h"
#include "srslte/common/threads.h" #include "srslte/common/threads.h"
#include "srslte/upper/rlc.h" #include "srslte/upper/rlc.h"
#include <boost/program_options.hpp>
#include <boost/program_options/parsers.hpp>
#include <assert.h> #include <assert.h>
#define NBUFS 5
using namespace std;
using namespace srsue; using namespace srsue;
using namespace srslte; using namespace srslte;
namespace bpo = boost::program_options;
typedef struct {
uint32_t test_duration_sec;
float error_rate;
uint32_t sdu_gen_delay_usec;
uint32_t pdu_tx_delay_usec;
bool reestablish;
uint32_t log_level;
} stress_test_args_t;
void parse_args(stress_test_args_t *args, int argc, char *argv[]) {
// Command line only options
bpo::options_description general("General options");
general.add_options()
("help,h", "Produce help message")
("version,v", "Print version information and exit");
// Command line or config file options
bpo::options_description common("Configuration options");
common.add_options()
("duration", bpo::value<uint32_t>(&args->test_duration_sec)->default_value(10), "Duration (sec)")
("sdu_gen_delay", bpo::value<uint32_t>(&args->sdu_gen_delay_usec)->default_value(10), "SDU generation delay (usec)")
("pdu_tx_delay", bpo::value<uint32_t>(&args->pdu_tx_delay_usec)->default_value(10), "Delay in MAC for transfering PDU from tx'ing RLC to rx'ing RLC (usec)")
("error_rate", bpo::value<float>(&args->error_rate)->default_value(0.1), "Rate at which RLC PDUs are dropped")
("reestablish", bpo::value<bool>(&args->reestablish)->default_value(false), "Mimic RLC reestablish during execution")
("loglevel", bpo::value<uint32_t>(&args->log_level)->default_value(srslte::LOG_LEVEL_DEBUG), "Log level (1=Error,2=Warning,3=Info,4=Debug");
// these options are allowed on the command line
bpo::options_description cmdline_options;
cmdline_options.add(common).add(general);
// parse the command line and store result in vm
bpo::variables_map vm;
bpo::store(bpo::command_line_parser(argc, argv).options(cmdline_options).run(), vm);
bpo::notify(vm);
// help option was given - print usage and exit
if (vm.count("help")) {
cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl;
cout << common << endl << general << endl;
exit(0);
}
if (args->log_level > 4) {
args->log_level = 4;
printf("Set log level to %d (%s)\n", args->log_level, srslte::log_level_text[args->log_level]);
}
}
class mac_reader class mac_reader
:public thread :public thread
{ {
public: public:
mac_reader(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_) mac_reader(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_, uint32_t pdu_tx_delay_usec_)
{ {
rlc1 = rlc1_; rlc1 = rlc1_;
rlc2 = rlc2_; rlc2 = rlc2_;
fail_rate = fail_rate_; fail_rate = fail_rate_;
run_enable = true; run_enable = true;
running = false; running = false;
pdu_tx_delay_usec = pdu_tx_delay_usec_;
} }
void stop() void stop()
@ -82,7 +136,7 @@ private:
if(((float)rand()/RAND_MAX > fail_rate) && read>0) { if(((float)rand()/RAND_MAX > fail_rate) && read>0) {
rlc2->write_pdu(1, pdu->msg, opp_size); rlc2->write_pdu(1, pdu->msg, opp_size);
} }
usleep(100); usleep(pdu_tx_delay_usec);
} }
running = false; running = false;
byte_buffer_pool::get_instance()->deallocate(pdu); byte_buffer_pool::get_instance()->deallocate(pdu);
@ -91,6 +145,7 @@ private:
rlc_interface_mac *rlc1; rlc_interface_mac *rlc1;
rlc_interface_mac *rlc2; rlc_interface_mac *rlc2;
float fail_rate; float fail_rate;
uint32_t pdu_tx_delay_usec;
bool run_enable; bool run_enable;
bool running; bool running;
@ -100,9 +155,9 @@ class mac_dummy
:public srslte::mac_interface_timers :public srslte::mac_interface_timers
{ {
public: public:
mac_dummy(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_) mac_dummy(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_, uint32_t pdu_tx_delay)
:r1(rlc1_, rlc2_, fail_rate_) :r1(rlc1_, rlc2_, fail_rate_, pdu_tx_delay)
,r2(rlc2_, rlc1_, fail_rate_) ,r2(rlc2_, rlc1_, fail_rate_, pdu_tx_delay)
{ {
} }
@ -140,12 +195,13 @@ class rlc_am_tester
,public thread ,public thread
{ {
public: public:
rlc_am_tester(rlc_interface_pdcp *rlc_, std::string name_=""){ rlc_am_tester(rlc_interface_pdcp *rlc_, std::string name_, uint32_t sdu_gen_delay_usec_){
rlc = rlc_; rlc = rlc_;
run_enable = true; run_enable = true;
running = false; running = false;
rx_pdus = 0; rx_pdus = 0;
name = name_; name = name_;
sdu_gen_delay_usec = sdu_gen_delay_usec_;
} }
void stop() void stop()
@ -191,7 +247,7 @@ private:
pdu->N_bytes = 1500; pdu->N_bytes = 1500;
pdu->msg[0] = sn++; pdu->msg[0] = sn++;
rlc->write_sdu(1, pdu); rlc->write_sdu(1, pdu);
usleep(100); usleep(sdu_gen_delay_usec);
} }
running = false; running = false;
} }
@ -202,26 +258,26 @@ private:
std::string name; std::string name;
uint32_t sdu_gen_delay_usec;
rlc_interface_pdcp *rlc; rlc_interface_pdcp *rlc;
}; };
void stress_test() void stress_test(stress_test_args_t args)
{ {
srslte::log_filter log1("RLC_AM_1"); srslte::log_filter log1("RLC_AM_1");
srslte::log_filter log2("RLC_AM_2"); srslte::log_filter log2("RLC_AM_2");
log1.set_level(srslte::LOG_LEVEL_DEBUG); log1.set_level((LOG_LEVEL_ENUM)args.log_level);
log2.set_level(srslte::LOG_LEVEL_DEBUG); log2.set_level((LOG_LEVEL_ENUM)args.log_level);
log1.set_hex_limit(-1); log1.set_hex_limit(-1);
log2.set_hex_limit(-1); log2.set_hex_limit(-1);
float fail_rate = 0.1;
rlc rlc1; rlc rlc1;
rlc rlc2; rlc rlc2;
rlc_am_tester tester1(&rlc1, "tester1"); rlc_am_tester tester1(&rlc1, "tester1", args.sdu_gen_delay_usec);
rlc_am_tester tester2(&rlc2, "tester2"); rlc_am_tester tester2(&rlc2, "tester2", args.sdu_gen_delay_usec);
mac_dummy mac(&rlc1, &rlc2, fail_rate); mac_dummy mac(&rlc1, &rlc2, args.error_rate, args.pdu_tx_delay_usec);
ue_interface ue; ue_interface ue;
rlc1.init(&tester1, &tester1, &ue, &log1, &mac, 0); rlc1.init(&tester1, &tester1, &ue, &log1, &mac, 0);
@ -245,7 +301,14 @@ void stress_test()
tester2.start(7); tester2.start(7);
mac.start(); mac.start();
usleep(100e6); for (uint32_t i = 0; i < args.test_duration_sec; i++) {
// if enabled, mimic reestablishment every second
if (args.reestablish) {
rlc1.reestablish();
rlc2.reestablish();
}
usleep(1e6);
}
tester1.stop(); tester1.stop();
tester2.stop(); tester2.stop();
@ -254,6 +317,9 @@ void stress_test()
int main(int argc, char **argv) { int main(int argc, char **argv) {
stress_test(); stress_test_args_t args;
parse_args(&args, argc, argv);
stress_test(args);
byte_buffer_pool::get_instance()->cleanup(); byte_buffer_pool::get_instance()->cleanup();
} }

@ -13,6 +13,8 @@
# mme_addr: IP address of MME for S1 connnection # mme_addr: IP address of MME for S1 connnection
# gtp_bind_addr: Local IP address to bind for GTP connection # gtp_bind_addr: Local IP address to bind for GTP connection
# n_prb: Number of Physical Resource Blocks (6,15,25,50,75,100) # n_prb: Number of Physical Resource Blocks (6,15,25,50,75,100)
# tm: Transmission mode 1-4 (TM1 default)
# nof_ports: Number of Tx ports (1 port default, set to 2 for TM2/3/4)
# #
##################################################################### #####################################################################
[enb] [enb]
@ -25,6 +27,9 @@ mnc = 01
mme_addr = 127.0.1.100 mme_addr = 127.0.1.100
gtp_bind_addr = 127.0.0.1 gtp_bind_addr = 127.0.0.1
n_prb = 50 n_prb = 50
#tm = 4
#nof_ports = 2
##################################################################### #####################################################################
# eNB configuration files # eNB configuration files

@ -104,8 +104,6 @@ void txrx::run_thread()
log_h->info("Starting RX/TX thread nof_prb=%d, sf_len=%d\n",worker_com->cell.nof_prb, sf_len); log_h->info("Starting RX/TX thread nof_prb=%d, sf_len=%d\n",worker_com->cell.nof_prb, sf_len);
// Start streaming RX samples
radio_h->start_rx();
// Set TTI so that first TX is at tti=0 // Set TTI so that first TX is at tti=0
tti = 10235; tti = 10235;

@ -195,6 +195,10 @@ void gtpu::rem_user(uint16_t rnti)
void gtpu::run_thread() void gtpu::run_thread()
{ {
byte_buffer_t *pdu = pool_allocate; byte_buffer_t *pdu = pool_allocate;
if (!pdu) {
gtpu_log->error("Fatal Error: Couldn't allocate buffer in gtpu::run_thread().\n");
return;
}
run_enable = true; run_enable = true;
running=true; running=true;

@ -88,6 +88,10 @@ void s1ap::get_metrics(s1ap_metrics_t &m)
void s1ap::run_thread() void s1ap::run_thread()
{ {
srslte::byte_buffer_t *pdu = pool_allocate; srslte::byte_buffer_t *pdu = pool_allocate;
if (!pdu) {
s1ap_log->error("Fatal Error: Couldn't allocate buffer in s1ap::run_thread().\n");
return;
}
uint32_t sz = SRSLTE_MAX_BUFFER_SIZE_BYTES - SRSLTE_BUFFER_HEADER_OFFSET; uint32_t sz = SRSLTE_MAX_BUFFER_SIZE_BYTES - SRSLTE_BUFFER_HEADER_OFFSET;
running = true; running = true;
@ -514,10 +518,15 @@ bool s1ap::handle_dlnastransport(LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT
} }
srslte::byte_buffer_t *pdu = pool_allocate; srslte::byte_buffer_t *pdu = pool_allocate;
if (pdu) {
memcpy(pdu->msg, msg->NAS_PDU.buffer, msg->NAS_PDU.n_octets); memcpy(pdu->msg, msg->NAS_PDU.buffer, msg->NAS_PDU.n_octets);
pdu->N_bytes = msg->NAS_PDU.n_octets; pdu->N_bytes = msg->NAS_PDU.n_octets;
rrc->write_dl_info(rnti, pdu); rrc->write_dl_info(rnti, pdu);
return true; return true;
} else {
s1ap_log->error("Fatal Error: Couldn't allocate buffer in s1ap::run_thread().\n");
return false;
}
} }
bool s1ap::handle_initialctxtsetuprequest(LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT *msg) bool s1ap::handle_initialctxtsetuprequest(LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT *msg)
@ -850,6 +859,11 @@ bool s1ap::send_initial_ctxt_setup_response(uint16_t rnti, LIBLTE_S1AP_MESSAGE_I
return false; return false;
} }
srslte::byte_buffer_t *buf = pool_allocate; srslte::byte_buffer_t *buf = pool_allocate;
if (!buf) {
s1ap_log->error("Fatal Error: Couldn't allocate buffer in s1ap::send_initial_ctxt_setup_response().\n");
return false;
}
LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu; LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu;
tx_pdu.ext = false; tx_pdu.ext = false;
@ -896,6 +910,11 @@ bool s1ap::send_erab_setup_response(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETU
return false; return false;
} }
srslte::byte_buffer_t *buf = pool_allocate; srslte::byte_buffer_t *buf = pool_allocate;
if (!buf) {
s1ap_log->error("Fatal Error: Couldn't allocate buffer in s1ap::send_erab_setup_response().\n");
return false;
}
LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu; LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu;
tx_pdu.ext = false; tx_pdu.ext = false;
@ -942,6 +961,11 @@ bool s1ap::send_initial_ctxt_setup_failure(uint16_t rnti)
return false; return false;
} }
srslte::byte_buffer_t *buf = pool_allocate; srslte::byte_buffer_t *buf = pool_allocate;
if (!buf) {
s1ap_log->error("Fatal Error: Couldn't allocate buffer in s1ap::send_initial_ctxt_setup_failure().\n");
return false;
}
LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu; LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu;
tx_pdu.ext = false; tx_pdu.ext = false;
tx_pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_UNSUCCESSFULOUTCOME; tx_pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_UNSUCCESSFULOUTCOME;

@ -11,6 +11,7 @@
# mcc: Mobile Country Code # mcc: Mobile Country Code
# mnc: Mobile Network Code # mnc: Mobile Network Code
# mme_bindx_addr: IP subnet to listen for eNB S1 connnections # mme_bindx_addr: IP subnet to listen for eNB S1 connnections
# apn: Set Access Point Name (APN)
# #
##################################################################### #####################################################################
[mme] [mme]
@ -20,6 +21,7 @@ tac = 0x0007
mcc = 001 mcc = 001
mnc = 01 mnc = 01
mme_bind_addr = 127.0.1.100 mme_bind_addr = 127.0.1.100
apn = test123
##################################################################### #####################################################################
# HSS configuration # HSS configuration

@ -49,6 +49,7 @@ typedef struct{
uint16_t mnc; // BCD-coded with 0xF filler uint16_t mnc; // BCD-coded with 0xF filler
std::string mme_bind_addr; std::string mme_bind_addr;
std::string mme_name; std::string mme_name;
std::string mme_apn;
} s1ap_args_t; } s1ap_args_t;
typedef struct{ typedef struct{
@ -96,6 +97,7 @@ typedef struct{
LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT ms_network_cap; LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT ms_network_cap;
bool eit; bool eit;
uint8_t procedure_transaction_id; uint8_t procedure_transaction_id;
uint8_t attach_type;
} ue_ctx_t; } ue_ctx_t;
}//namespace }//namespace
#endif #endif

@ -84,6 +84,7 @@ public:
bool pack_identity_request(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id); bool pack_identity_request(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id);
bool pack_emm_information(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id); bool pack_emm_information(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id);
bool pack_service_reject(srslte::byte_buffer_t *reply_msg, uint8_t emm_cause, uint32_t enb_ue_s1ap_id);
void log_unhandled_attach_request_ies(const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req); void log_unhandled_attach_request_ies(const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req);
void log_unhandled_pdn_con_request_ies(const LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT *pdn_con_req); void log_unhandled_pdn_con_request_ies(const LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT *pdn_con_req);

@ -81,6 +81,7 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
string mcc; string mcc;
string mnc; string mnc;
string mme_bind_addr; string mme_bind_addr;
string mme_apn;
string spgw_bind_addr; string spgw_bind_addr;
string sgi_if_addr; string sgi_if_addr;
string hss_db_file; string hss_db_file;
@ -105,6 +106,7 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
("mme.mcc", bpo::value<string>(&mcc)->default_value("001"), "Mobile Country Code") ("mme.mcc", bpo::value<string>(&mcc)->default_value("001"), "Mobile Country Code")
("mme.mnc", bpo::value<string>(&mnc)->default_value("01"), "Mobile Network Code") ("mme.mnc", bpo::value<string>(&mnc)->default_value("01"), "Mobile Network Code")
("mme.mme_bind_addr", bpo::value<string>(&mme_bind_addr)->default_value("127.0.0.1"),"IP address of MME for S1 connnection") ("mme.mme_bind_addr", bpo::value<string>(&mme_bind_addr)->default_value("127.0.0.1"),"IP address of MME for S1 connnection")
("mme.apn", bpo::value<string>(&mme_apn)->default_value(""), "Set Access Point Name (APN) for data services")
("hss.db_file", bpo::value<string>(&hss_db_file)->default_value("ue_db.csv"),".csv file that stores UE's keys") ("hss.db_file", bpo::value<string>(&hss_db_file)->default_value("ue_db.csv"),".csv file that stores UE's keys")
("hss.auth_algo", bpo::value<string>(&hss_auth_algo)->default_value("milenage"),"HSS uthentication algorithm.") ("hss.auth_algo", bpo::value<string>(&hss_auth_algo)->default_value("milenage"),"HSS uthentication algorithm.")
("spgw.gtpu_bind_addr", bpo::value<string>(&spgw_bind_addr)->default_value("127.0.0.1"),"IP address of SP-GW for the S1-U connection") ("spgw.gtpu_bind_addr", bpo::value<string>(&spgw_bind_addr)->default_value("127.0.0.1"),"IP address of SP-GW for the S1-U connection")
@ -204,6 +206,7 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
} }
args->mme_args.s1ap_args.mme_bind_addr = mme_bind_addr; args->mme_args.s1ap_args.mme_bind_addr = mme_bind_addr;
args->mme_args.s1ap_args.mme_apn = mme_apn;
args->spgw_args.gtpu_bind_addr = spgw_bind_addr; args->spgw_args.gtpu_bind_addr = spgw_bind_addr;
args->spgw_args.sgi_if_addr = sgi_if_addr; args->spgw_args.sgi_if_addr = sgi_if_addr;
args->hss_args.db_file = hss_db_file; args->hss_args.db_file = hss_db_file;

@ -118,7 +118,8 @@ mme_gtpc::send_create_session_request(uint64_t imsi, uint32_t mme_ue_s1ap_id)
m_mme_gtpc_log->console("Creating Session Response -- IMSI: %015lu \n", imsi); m_mme_gtpc_log->console("Creating Session Response -- IMSI: %015lu \n", imsi);
m_mme_gtpc_log->console("Creating Session Response -- MME control TEID: %lu \n", cs_req->sender_f_teid.teid); m_mme_gtpc_log->console("Creating Session Response -- MME control TEID: %lu \n", cs_req->sender_f_teid.teid);
// APN // APN
memcpy(cs_req->apn, "internet", sizeof("internet")); strncpy(cs_req->apn, m_s1ap->m_s1ap_args.mme_apn.c_str(), sizeof(cs_req->apn)-1);
cs_req->apn[sizeof(cs_req->apn)-1] = 0;
// RAT Type // RAT Type
//cs_req->rat_type = srslte::GTPC_RAT_TYPE::EUTRAN; //cs_req->rat_type = srslte::GTPC_RAT_TYPE::EUTRAN;

@ -38,7 +38,9 @@ boost::mutex s1ap_instance_mutex;
s1ap::s1ap(): s1ap::s1ap():
m_s1mme(-1), m_s1mme(-1),
m_next_mme_ue_s1ap_id(1) m_next_mme_ue_s1ap_id(1),
m_mme_gtpc(NULL),
m_pool(NULL)
{ {
} }

@ -121,7 +121,12 @@ s1ap_nas_transport::handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUEMESSA
m_s1ap_log->info("Received Service Request \n"); m_s1ap_log->info("Received Service Request \n");
m_s1ap_log->console("Received Service Request \n"); m_s1ap_log->console("Received Service Request \n");
liblte_mme_unpack_service_request_msg((LIBLTE_BYTE_MSG_STRUCT*) nas_msg, &service_req); liblte_mme_unpack_service_request_msg((LIBLTE_BYTE_MSG_STRUCT*) nas_msg, &service_req);
return false;
m_s1ap_log->info("Service Request not implemented. Sending Service Reject.");
m_s1ap_log->console("Service Request not implemented. Sending Service Reject.");
/* Force UE to re-attach */
pack_service_reject(reply_buffer, LIBLTE_MME_EMM_CAUSE_IMPLICITLY_DETACHED, enb_ue_s1ap_id);
*reply_flag = true;
} }
m_pool->deallocate(nas_msg); m_pool->deallocate(nas_msg);
@ -200,11 +205,8 @@ s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRA
if(*reply_flag == true) if(*reply_flag == true)
{ {
if(ue_ctx != NULL) m_s1ap_log->info("DL NAS: Sent Downlink NAS message\n");
{ m_s1ap_log->console("DL NAS: Sent Downlink NAS Message\n");
m_s1ap_log->console("DL NAS: Sent Downlink NAs Message. DL NAS Count=%d, UL NAS Count=%d\n",ue_ctx->security_ctxt.dl_nas_count, ue_ctx->security_ctxt.ul_nas_count);
m_s1ap_log->info("DL NAS: Sent Downlink NAS message. DL NAS Count=%d, UL NAS Count=%d\n",ue_ctx->security_ctxt.dl_nas_count, ue_ctx->security_ctxt.ul_nas_count);
}
} }
m_pool->deallocate(nas_msg); m_pool->deallocate(nas_msg);
@ -291,6 +293,10 @@ s1ap_nas_transport::handle_nas_imsi_attach_request(uint32_t enb_ue_s1ap_id,
m_s1ap_log->console("Attach request -- IMSI: %015lu\n", ue_ctx.imsi); m_s1ap_log->console("Attach request -- IMSI: %015lu\n", ue_ctx.imsi);
m_s1ap_log->info("Attach request -- IMSI: %015lu\n", ue_ctx.imsi); m_s1ap_log->info("Attach request -- IMSI: %015lu\n", ue_ctx.imsi);
m_s1ap_log->console("Attach request -- Attach type: %d\n", attach_req.eps_attach_type);
m_s1ap_log->info("Attach request -- Attach type: %d\n", attach_req.eps_attach_type);
m_s1ap_log->console("Attach request -- eNB-UE S1AP Id: %d, MME-UE S1AP Id: %d\n", ue_ctx.enb_ue_s1ap_id, ue_ctx.mme_ue_s1ap_id); m_s1ap_log->console("Attach request -- eNB-UE S1AP Id: %d, MME-UE S1AP Id: %d\n", ue_ctx.enb_ue_s1ap_id, ue_ctx.mme_ue_s1ap_id);
m_s1ap_log->console("Attach Request -- UE Network Capabilities EEA: %d%d%d%d%d%d%d%d\n", m_s1ap_log->console("Attach Request -- UE Network Capabilities EEA: %d%d%d%d%d%d%d%d\n",
attach_req.ue_network_cap.eea[0], attach_req.ue_network_cap.eea[0],
@ -315,6 +321,9 @@ s1ap_nas_transport::handle_nas_imsi_attach_request(uint32_t enb_ue_s1ap_id,
m_s1ap_log->console("PDN Connectivity Request -- Procedure Transaction Id: %d\n", pdn_con_req.proc_transaction_id); m_s1ap_log->console("PDN Connectivity Request -- Procedure Transaction Id: %d\n", pdn_con_req.proc_transaction_id);
m_s1ap_log->console("PDN Connectivity Request -- ESM Information Transfer requested: %s\n", pdn_con_req.esm_info_transfer_flag_present ? "true" : "false"); m_s1ap_log->console("PDN Connectivity Request -- ESM Information Transfer requested: %s\n", pdn_con_req.esm_info_transfer_flag_present ? "true" : "false");
//Save attach request type
ue_ctx.attach_type = attach_req.eps_attach_type;
//Get Authentication Vectors from HSS //Get Authentication Vectors from HSS
if(!m_hss->gen_auth_info_answer(ue_ctx.imsi, ue_ctx.security_ctxt.k_asme, autn, rand, ue_ctx.security_ctxt.xres)) if(!m_hss->gen_auth_info_answer(ue_ctx.imsi, ue_ctx.security_ctxt.k_asme, autn, rand, ue_ctx.security_ctxt.xres))
{ {
@ -329,8 +338,8 @@ s1ap_nas_transport::handle_nas_imsi_attach_request(uint32_t enb_ue_s1ap_id,
//Send reply to eNB //Send reply to eNB
*reply_flag = true; *reply_flag = true;
m_s1ap_log->info("Downlink NAS: Sending Athentication Request\n"); m_s1ap_log->info("Downlink NAS: Sending Authentication Request\n");
m_s1ap_log->console("Downlink NAS: Sending Athentication Request\n"); m_s1ap_log->console("Downlink NAS: Sending Authentication Request\n");
return true; return true;
} }
@ -363,6 +372,9 @@ s1ap_nas_transport::handle_nas_guti_attach_request(uint32_t enb_ue_s1ap_id,
uint8_t eps_bearer_id = pdn_con_req.eps_bearer_id; //TODO: Unused uint8_t eps_bearer_id = pdn_con_req.eps_bearer_id; //TODO: Unused
ue_ctx.procedure_transaction_id = pdn_con_req.proc_transaction_id; ue_ctx.procedure_transaction_id = pdn_con_req.proc_transaction_id;
//Save attach request type
ue_ctx.attach_type = attach_req.eps_attach_type;
//Save whether ESM information transfer is necessary //Save whether ESM information transfer is necessary
ue_ctx.eit = pdn_con_req.esm_info_transfer_flag_present; ue_ctx.eit = pdn_con_req.esm_info_transfer_flag_present;
//m_s1ap_log->console("EPS Bearer id: %d\n", eps_bearer_id); //m_s1ap_log->console("EPS Bearer id: %d\n", eps_bearer_id);
@ -415,6 +427,8 @@ s1ap_nas_transport::handle_nas_guti_attach_request(uint32_t enb_ue_s1ap_id,
ue_ctx_t *ue_ctx_ptr = m_s1ap->find_ue_ctx(it->second); ue_ctx_t *ue_ctx_ptr = m_s1ap->find_ue_ctx(it->second);
if(ue_ctx_ptr!=NULL) if(ue_ctx_ptr!=NULL)
{ {
//Save attach request type
ue_ctx_ptr->attach_type = attach_req.eps_attach_type;
m_s1ap_log->console("Found UE context. IMSI: %015lu\n",ue_ctx_ptr->imsi); m_s1ap_log->console("Found UE context. IMSI: %015lu\n",ue_ctx_ptr->imsi);
m_mme_gtpc->send_create_session_request(ue_ctx_ptr->imsi, ue_ctx_ptr->mme_ue_s1ap_id); m_mme_gtpc->send_create_session_request(ue_ctx_ptr->imsi, ue_ctx_ptr->mme_ue_s1ap_id);
*reply_flag = false; //No reply needed *reply_flag = false; //No reply needed
@ -470,7 +484,7 @@ s1ap_nas_transport::handle_nas_authentication_response(srslte::byte_buffer_t *na
m_s1ap_log->console("UE Authentication Rejected.\n"); m_s1ap_log->console("UE Authentication Rejected.\n");
m_s1ap_log->warning("UE Authentication Rejected.\n"); m_s1ap_log->warning("UE Authentication Rejected.\n");
//Send back Athentication Reject //Send back Authentication Reject
pack_authentication_reject(reply_buffer, ue_ctx->enb_ue_s1ap_id, ue_ctx->mme_ue_s1ap_id); pack_authentication_reject(reply_buffer, ue_ctx->enb_ue_s1ap_id, ue_ctx->mme_ue_s1ap_id);
*reply_flag = true; *reply_flag = true;
m_s1ap_log->console("Downlink NAS: Sending Authentication Reject.\n"); m_s1ap_log->console("Downlink NAS: Sending Authentication Reject.\n");
@ -514,6 +528,7 @@ s1ap_nas_transport::handle_nas_security_mode_complete(srslte::byte_buffer_t *nas
{ {
pack_esm_information_request(reply_buffer, ue_ctx); pack_esm_information_request(reply_buffer, ue_ctx);
m_s1ap_log->console("Sending ESM information request\n"); m_s1ap_log->console("Sending ESM information request\n");
m_s1ap_log->info("Sending ESM information request\n");
*reply_flag = true; *reply_flag = true;
} }
else else
@ -535,7 +550,7 @@ s1ap_nas_transport::handle_nas_attach_complete(srslte::byte_buffer_t *nas_msg, u
srslte::byte_buffer_t *esm_msg = m_pool->allocate(); srslte::byte_buffer_t *esm_msg = m_pool->allocate();
LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT act_bearer; LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT act_bearer;
m_s1ap_log->info_hex(nas_msg->msg, nas_msg->N_bytes, "NAS Attach complte"); m_s1ap_log->info_hex(nas_msg->msg, nas_msg->N_bytes, "NAS Attach complete");
//Get NAS authentication response //Get NAS authentication response
LIBLTE_ERROR_ENUM err = liblte_mme_unpack_attach_complete_msg((LIBLTE_BYTE_MSG_STRUCT *) nas_msg, &attach_comp); LIBLTE_ERROR_ENUM err = liblte_mme_unpack_attach_complete_msg((LIBLTE_BYTE_MSG_STRUCT *) nas_msg, &attach_comp);
@ -551,7 +566,7 @@ s1ap_nas_transport::handle_nas_attach_complete(srslte::byte_buffer_t *nas_msg, u
} }
m_s1ap_log->console("Unpacked Attached Complete Message\n"); m_s1ap_log->console("Unpacked Attached Complete Message\n");
m_s1ap_log->console("Unpacked Activavate Default EPS Bearer message. EPS Bearer id %d\n",act_bearer.eps_bearer_id); m_s1ap_log->console("Unpacked Activate Default EPS Bearer message. EPS Bearer id %d\n",act_bearer.eps_bearer_id);
//ue_ctx->erabs_ctx[act_bearer->eps_bearer_id].enb_fteid; //ue_ctx->erabs_ctx[act_bearer->eps_bearer_id].enb_fteid;
if(act_bearer.eps_bearer_id < 5 || act_bearer.eps_bearer_id > 15) if(act_bearer.eps_bearer_id < 5 || act_bearer.eps_bearer_id > 15)
{ {
@ -579,6 +594,11 @@ s1ap_nas_transport::handle_esm_information_response(srslte::byte_buffer_t *nas_m
m_s1ap_log->info("ESM Info: APN %s\n",esm_info_resp.eps_bearer_id); m_s1ap_log->info("ESM Info: APN %s\n",esm_info_resp.eps_bearer_id);
m_s1ap_log->console("ESM Info: APN %s\n",esm_info_resp.eps_bearer_id); m_s1ap_log->console("ESM Info: APN %s\n",esm_info_resp.eps_bearer_id);
} }
if(esm_info_resp.protocol_cnfg_opts_present)
{
m_s1ap_log->info("ESM Info: %d Protocol Configuration Options %s\n",esm_info_resp.protocol_cnfg_opts.N_opts);
m_s1ap_log->console("ESM Info: %d Protocol Configuration Options %s\n",esm_info_resp.protocol_cnfg_opts.N_opts);
}
//FIXME The packging of GTP-C messages is not ready. //FIXME The packging of GTP-C messages is not ready.
//This means that GTP-U tunnels are created with function calls, as opposed to GTP-C. //This means that GTP-U tunnels are created with function calls, as opposed to GTP-C.
@ -797,8 +817,8 @@ s1ap_nas_transport::pack_authentication_request(srslte::byte_buffer_t *reply_msg
LIBLTE_ERROR_ENUM err = liblte_mme_pack_authentication_request_msg(&auth_req, (LIBLTE_BYTE_MSG_STRUCT *) nas_buffer); LIBLTE_ERROR_ENUM err = liblte_mme_pack_authentication_request_msg(&auth_req, (LIBLTE_BYTE_MSG_STRUCT *) nas_buffer);
if(err != LIBLTE_SUCCESS) if(err != LIBLTE_SUCCESS)
{ {
m_s1ap_log->error("Error packing Athentication Request\n"); m_s1ap_log->error("Error packing Authentication Request\n");
m_s1ap_log->console("Error packing Athentication Request\n"); m_s1ap_log->console("Error packing Authentication Request\n");
return false; return false;
} }
@ -810,8 +830,8 @@ s1ap_nas_transport::pack_authentication_request(srslte::byte_buffer_t *reply_msg
err = liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT *) reply_msg); err = liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT *) reply_msg);
if(err != LIBLTE_SUCCESS) if(err != LIBLTE_SUCCESS)
{ {
m_s1ap_log->error("Error packing Athentication Request\n"); m_s1ap_log->error("Error packing Authentication Request\n");
m_s1ap_log->console("Error packing Athentication Request\n"); m_s1ap_log->console("Error packing Authentication Request\n");
return false; return false;
} }
@ -848,8 +868,8 @@ s1ap_nas_transport::pack_authentication_reject(srslte::byte_buffer_t *reply_msg,
LIBLTE_ERROR_ENUM err = liblte_mme_pack_authentication_reject_msg(&auth_rej, (LIBLTE_BYTE_MSG_STRUCT *) nas_buffer); LIBLTE_ERROR_ENUM err = liblte_mme_pack_authentication_reject_msg(&auth_rej, (LIBLTE_BYTE_MSG_STRUCT *) nas_buffer);
if(err != LIBLTE_SUCCESS) if(err != LIBLTE_SUCCESS)
{ {
m_s1ap_log->error("Error packing Athentication Reject\n"); m_s1ap_log->error("Error packing Authentication Reject\n");
m_s1ap_log->console("Error packing Athentication Reject\n"); m_s1ap_log->console("Error packing Authentication Reject\n");
return false; return false;
} }
@ -861,8 +881,8 @@ s1ap_nas_transport::pack_authentication_reject(srslte::byte_buffer_t *reply_msg,
err = liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT *) reply_msg); err = liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT *) reply_msg);
if(err != LIBLTE_SUCCESS) if(err != LIBLTE_SUCCESS)
{ {
m_s1ap_log->error("Error packing Dw NAS Transport: Athentication Reject\n"); m_s1ap_log->error("Error packing Dw NAS Transport: Authentication Reject\n");
m_s1ap_log->console("Error packing Downlink NAS Transport: Athentication Reject\n"); m_s1ap_log->console("Error packing Downlink NAS Transport: Authentication Reject\n");
return false; return false;
} }
@ -951,7 +971,7 @@ s1ap_nas_transport::pack_security_mode_command(srslte::byte_buffer_t *reply_msg,
LIBLTE_ERROR_ENUM err = liblte_mme_pack_security_mode_command_msg(&sm_cmd,sec_hdr_type, ue_ctx->security_ctxt.dl_nas_count,(LIBLTE_BYTE_MSG_STRUCT *) nas_buffer); LIBLTE_ERROR_ENUM err = liblte_mme_pack_security_mode_command_msg(&sm_cmd,sec_hdr_type, ue_ctx->security_ctxt.dl_nas_count,(LIBLTE_BYTE_MSG_STRUCT *) nas_buffer);
if(err != LIBLTE_SUCCESS) if(err != LIBLTE_SUCCESS)
{ {
m_s1ap_log->console("Error packing Athentication Request\n"); m_s1ap_log->console("Error packing Authentication Request\n");
return false; return false;
} }
@ -985,7 +1005,7 @@ s1ap_nas_transport::pack_security_mode_command(srslte::byte_buffer_t *reply_msg,
err = liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT *) reply_msg); err = liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT *) reply_msg);
if(err != LIBLTE_SUCCESS) if(err != LIBLTE_SUCCESS)
{ {
m_s1ap_log->console("Error packing Athentication Request\n"); m_s1ap_log->console("Error packing Authentication Request\n");
return false; return false;
} }
m_s1ap_log->debug_hex(reply_msg->msg, reply_msg->N_bytes, "Security Mode Command: "); m_s1ap_log->debug_hex(reply_msg->msg, reply_msg->N_bytes, "Security Mode Command: ");
@ -1051,8 +1071,8 @@ s1ap_nas_transport::pack_esm_information_request(srslte::byte_buffer_t *reply_ms
err = liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT *) reply_msg); err = liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT *) reply_msg);
if(err != LIBLTE_SUCCESS) if(err != LIBLTE_SUCCESS)
{ {
m_s1ap_log->error("Error packing Dw NAS Transport: Athentication Reject\n"); m_s1ap_log->error("Error packing Dw NAS Transport: Authentication Reject\n");
m_s1ap_log->console("Error packing Downlink NAS Transport: Athentication Reject\n"); m_s1ap_log->console("Error packing Downlink NAS Transport: Authentication Reject\n");
return false; return false;
} }
@ -1090,7 +1110,7 @@ s1ap_nas_transport::pack_attach_accept(ue_ctx_t *ue_ctx, LIBLTE_S1AP_E_RABTOBESE
} }
//Attach accept //Attach accept
attach_accept.eps_attach_result = LIBLTE_MME_EPS_ATTACH_RESULT_EPS_ONLY; attach_accept.eps_attach_result = ue_ctx->attach_type;
//Mandatory //Mandatory
//FIXME: Set t3412 from config //FIXME: Set t3412 from config
attach_accept.t3412.unit = LIBLTE_MME_GPRS_TIMER_UNIT_1_MINUTE; // GPRS 1 minute unit attach_accept.t3412.unit = LIBLTE_MME_GPRS_TIMER_UNIT_1_MINUTE; // GPRS 1 minute unit
@ -1143,8 +1163,7 @@ s1ap_nas_transport::pack_attach_accept(ue_ctx_t *ue_ctx, LIBLTE_S1AP_E_RABTOBESE
act_def_eps_bearer_context_req.eps_qos.mbr_dl_ext = 250; //FIXME check act_def_eps_bearer_context_req.eps_qos.mbr_dl_ext = 250; //FIXME check
//set apn //set apn
//act_def_eps_bearer_context_req.apn //act_def_eps_bearer_context_req.apn
std::string apn("test123"); act_def_eps_bearer_context_req.apn.apn = m_s1ap->m_s1ap_args.mme_apn;
act_def_eps_bearer_context_req.apn.apn = apn; //FIXME
act_def_eps_bearer_context_req.proc_transaction_id = ue_ctx->procedure_transaction_id; //FIXME act_def_eps_bearer_context_req.proc_transaction_id = ue_ctx->procedure_transaction_id; //FIXME
//Set DNS server //Set DNS server
@ -1164,6 +1183,7 @@ s1ap_nas_transport::pack_attach_accept(ue_ctx_t *ue_ctx, LIBLTE_S1AP_E_RABTOBESE
act_def_eps_bearer_context_req.packet_flow_id_present = false; act_def_eps_bearer_context_req.packet_flow_id_present = false;
act_def_eps_bearer_context_req.apn_ambr_present = false; act_def_eps_bearer_context_req.apn_ambr_present = false;
act_def_eps_bearer_context_req.esm_cause_present = false; act_def_eps_bearer_context_req.esm_cause_present = false;
act_def_eps_bearer_context_req.connectivity_type_present = false;
uint8_t sec_hdr_type =2; uint8_t sec_hdr_type =2;
ue_ctx->security_ctxt.dl_nas_count++; ue_ctx->security_ctxt.dl_nas_count++;
@ -1233,8 +1253,8 @@ s1ap_nas_transport::pack_identity_request(srslte::byte_buffer_t *reply_msg, uint
err = liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT *) reply_msg); err = liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT *) reply_msg);
if(err != LIBLTE_SUCCESS) if(err != LIBLTE_SUCCESS)
{ {
m_s1ap_log->error("Error packing Dw NAS Transport: Athentication Reject\n"); m_s1ap_log->error("Error packing Dw NAS Transport: Authentication Reject\n");
m_s1ap_log->console("Error packing Downlink NAS Transport: Athentication Reject\n"); m_s1ap_log->console("Error packing Downlink NAS Transport: Authentication Reject\n");
return false; return false;
} }
@ -1311,6 +1331,59 @@ s1ap_nas_transport::pack_emm_information(srslte::byte_buffer_t *reply_msg, uint3
return true; return true;
} }
bool
s1ap_nas_transport::pack_service_reject(srslte::byte_buffer_t *reply_msg, uint8_t emm_cause, uint32_t enb_ue_s1ap_id)
{
srslte::byte_buffer_t *nas_buffer = m_pool->allocate();
//Setup initiating message
LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu;
bzero(&tx_pdu, sizeof(LIBLTE_S1AP_S1AP_PDU_STRUCT));
tx_pdu.ext = false;
tx_pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE;
LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *init = &tx_pdu.choice.initiatingMessage;
init->procedureCode = LIBLTE_S1AP_PROC_ID_DOWNLINKNASTRANSPORT;
init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_DOWNLINKNASTRANSPORT;
//Setup Dw NAS structure
LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT *dw_nas = &init->choice.DownlinkNASTransport;
dw_nas->ext=false;
dw_nas->MME_UE_S1AP_ID.MME_UE_S1AP_ID = m_s1ap->get_next_mme_ue_s1ap_id();
dw_nas->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = enb_ue_s1ap_id;
dw_nas->HandoverRestrictionList_present=false;
dw_nas->SubscriberProfileIDforRFP_present=false;
LIBLTE_MME_SERVICE_REJECT_MSG_STRUCT service_rej;
service_rej.t3442_present = true;
service_rej.t3442.unit = LIBLTE_MME_GPRS_TIMER_DEACTIVATED;
service_rej.t3442.value = 0;
service_rej.t3446_present = true;
service_rej.t3446 = 0;
service_rej.emm_cause = emm_cause;
LIBLTE_ERROR_ENUM err = liblte_mme_pack_service_reject_msg(&service_rej, LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS, 0, (LIBLTE_BYTE_MSG_STRUCT *) nas_buffer);
if(err != LIBLTE_SUCCESS)
{
m_s1ap_log->error("Error packing Service Reject\n");
m_s1ap_log->console("Error packing Service Reject\n");
return false;
}
//Copy NAS PDU to Downlink NAS Trasport message buffer
memcpy(dw_nas->NAS_PDU.buffer, nas_buffer->msg, nas_buffer->N_bytes);
dw_nas->NAS_PDU.n_octets = nas_buffer->N_bytes;
//Pack Downlink NAS Transport Message
err = liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT *) reply_msg);
if(err != LIBLTE_SUCCESS)
{
m_s1ap_log->error("Error packing Dw NAS Transport: Service Reject\n");
m_s1ap_log->console("Error packing Downlink NAS Transport: Service Reject\n");
return false;
}
return true;
}
/*Helper functions*/ /*Helper functions*/
void void
s1ap_nas_transport::log_unhandled_attach_request_ies(const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req) s1ap_nas_transport::log_unhandled_attach_request_ies(const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req)

@ -190,12 +190,17 @@ private:
} }
private: private:
const static int RESET_DUPLICATE_TIMEOUT = 8*6;
class dl_tb_process { class dl_tb_process {
public: public:
dl_tb_process(void) { dl_tb_process(void) {
is_initiated = false; is_initiated = false;
ack = false; ack = false;
bzero(&cur_grant, sizeof(Tgrant)); bzero(&cur_grant, sizeof(Tgrant));
payload_buffer_ptr = NULL;
pthread_mutex_init(&mutex, NULL);
} }
~dl_tb_process() { ~dl_tb_process() {
@ -220,16 +225,26 @@ private:
} }
void reset(void) { void reset(void) {
pthread_mutex_lock(&mutex);
is_first_tb = true; is_first_tb = true;
ack = false; ack = false;
if (payload_buffer_ptr) {
if (pid != HARQ_BCCH_PID) {
harq_entity->demux_unit->deallocate(payload_buffer_ptr);
}
payload_buffer_ptr = NULL; payload_buffer_ptr = NULL;
}
bzero(&cur_grant, sizeof(Tgrant)); bzero(&cur_grant, sizeof(Tgrant));
if (is_initiated) { if (is_initiated) {
srslte_softbuffer_rx_reset(&softbuffer); srslte_softbuffer_rx_reset(&softbuffer);
} }
pthread_mutex_unlock(&mutex);
} }
void new_grant_dl(Tgrant grant, Taction *action) { void new_grant_dl(Tgrant grant, Taction *action) {
pthread_mutex_lock(&mutex);
// Compute RV for BCCH when not specified in PDCCH format // Compute RV for BCCH when not specified in PDCCH format
if (pid == HARQ_BCCH_PID && grant.rv[tid] == -1) { if (pid == HARQ_BCCH_PID && grant.rv[tid] == -1) {
uint32_t k; uint32_t k;
@ -253,13 +268,17 @@ private:
n_retx = 0; n_retx = 0;
} }
// If data has not yet been successfully decoded
if (!ack) {
// Save grant // Save grant
grant.last_ndi[tid] = cur_grant.ndi[tid]; grant.last_ndi[tid] = cur_grant.ndi[tid];
grant.last_tti = cur_grant.tti; grant.last_tti = cur_grant.tti;
memcpy(&cur_grant, &grant, sizeof(Tgrant)); memcpy(&cur_grant, &grant, sizeof(Tgrant));
// If data has not yet been successfully decoded if (payload_buffer_ptr) {
if (!ack) { Warning("DL PID %d: Allocating buffer already allocated\n", pid);
}
// Instruct the PHY To combine the received data and attempt to decode it // Instruct the PHY To combine the received data and attempt to decode it
if (pid == HARQ_BCCH_PID) { if (pid == HARQ_BCCH_PID) {
@ -271,6 +290,7 @@ private:
if (!action->payload_ptr[tid]) { if (!action->payload_ptr[tid]) {
action->decode_enabled[tid] = false; action->decode_enabled[tid] = false;
Error("Can't get a buffer for TBS=%d\n", cur_grant.n_bytes[tid]); Error("Can't get a buffer for TBS=%d\n", cur_grant.n_bytes[tid]);
pthread_mutex_unlock(&mutex);
return; return;
} }
action->decode_enabled[tid]= true; action->decode_enabled[tid]= true;
@ -281,7 +301,14 @@ private:
} else { } else {
action->default_ack[tid] = true; action->default_ack[tid] = true;
Warning("DL PID %d: Received duplicate TB. Discarting and retransmitting ACK\n", pid); uint32_t interval = srslte_tti_interval(grant.tti, cur_grant.tti);
Warning("DL PID %d: Received duplicate TB. Discarting and retransmitting ACK (grant_tti=%d, ndi=%d, sz=%d, reset=%s)\n",
pid, cur_grant.tti, cur_grant.ndi[tid], cur_grant.n_bytes[tid], interval>RESET_DUPLICATE_TIMEOUT?"yes":"no");
if (interval > RESET_DUPLICATE_TIMEOUT) {
pthread_mutex_unlock(&mutex);
reset();
pthread_mutex_lock(&mutex);
}
} }
if (pid == HARQ_BCCH_PID || harq_entity->timer_aligment_timer->is_expired()) { if (pid == HARQ_BCCH_PID || harq_entity->timer_aligment_timer->is_expired()) {
@ -298,9 +325,12 @@ private:
Debug("Generating ACK\n"); Debug("Generating ACK\n");
} }
} }
pthread_mutex_unlock(&mutex);
} }
void tb_decoded(bool ack_) { void tb_decoded(bool ack_) {
pthread_mutex_lock(&mutex);
ack = ack_; ack = ack_;
if (ack) { if (ack) {
if (pid == HARQ_BCCH_PID) { if (pid == HARQ_BCCH_PID) {
@ -327,15 +357,19 @@ private:
harq_entity->nof_pkts++); harq_entity->nof_pkts++);
} }
} }
} else { } else if (pid != HARQ_BCCH_PID) {
harq_entity->demux_unit->deallocate(payload_buffer_ptr); harq_entity->demux_unit->deallocate(payload_buffer_ptr);
} }
payload_buffer_ptr = NULL;
Info("DL %d (TB %d): %s tbs=%d, rv=%d, ack=%s, ndi=%d (%d), tti=%d (%d)\n", Info("DL %d (TB %d): %s tbs=%d, rv=%d, ack=%s, ndi=%d (%d), tti=%d (%d)\n",
pid, tid, is_new_transmission ? "newTX" : "reTX ", pid, tid, is_new_transmission ? "newTX" : "reTX ",
cur_grant.n_bytes[tid], cur_grant.rv[tid], ack ? "OK" : "KO", cur_grant.n_bytes[tid], cur_grant.rv[tid], ack ? "OK" : "KO",
cur_grant.ndi[tid], cur_grant.last_ndi[tid], cur_grant.tti, cur_grant.last_tti); cur_grant.ndi[tid], cur_grant.last_ndi[tid], cur_grant.tti, cur_grant.last_tti);
pthread_mutex_unlock(&mutex);
if (ack && pid == HARQ_BCCH_PID) { if (ack && pid == HARQ_BCCH_PID) {
reset(); reset();
} }
@ -363,6 +397,8 @@ private:
return is_new_transmission; return is_new_transmission;
} }
pthread_mutex_t mutex;
bool is_initiated; bool is_initiated;
dl_harq_entity *harq_entity; dl_harq_entity *harq_entity;
srslte::log *log_h; srslte::log *log_h;

@ -162,14 +162,25 @@ private:
void timer_alignment_expire(); void timer_alignment_expire();
srslte::timers timers; srslte::timers timers;
// pointer to MAC PCAP object // pointer to MAC PCAP object
srslte::mac_pcap* pcap; srslte::mac_pcap* pcap;
bool is_first_ul_grant; bool is_first_ul_grant;
mac_metrics_t metrics; mac_metrics_t metrics;
/* Class to run Timers in a dedicated thread */
class mac_timers : public periodic_thread {
public:
void init(srslte::timers *timers, srslte::log *log_h);
private:
void run_period();
srslte::timers *timers;
bool running;
srslte::log *log_h;
};
mac_timers mactimers;
/* Class to process MAC PDUs from DEMUX unit */ /* Class to process MAC PDUs from DEMUX unit */
class pdu_process : public thread { class pdu_process : public thread {
public: public:

@ -104,6 +104,7 @@ private:
/* Msg3 Buffer */ /* Msg3 Buffer */
static const uint32_t MSG3_BUFF_SZ = 1024; static const uint32_t MSG3_BUFF_SZ = 1024;
uint8_t msg3_buff[MSG3_BUFF_SZ]; uint8_t msg3_buff[MSG3_BUFF_SZ];
uint8_t *msg3_buff_start_pdu;
/* PDU Buffer */ /* PDU Buffer */
srslte::sch_pdu pdu_msg; srslte::sch_pdu pdu_msg;

@ -246,7 +246,6 @@ private:
} else { } else {
Warning("UL RAR grant available but no Msg3 on buffer\n"); Warning("UL RAR grant available but no Msg3 on buffer\n");
} }
printf("Transmitted Msg3\n");
// Normal UL grant // Normal UL grant
} else { } else {

@ -61,9 +61,8 @@ public:
void reset_sync(); void reset_sync();
void cell_search_start(); void cell_search_start();
void cell_search_stop();
void cell_search_next(bool reset = false); void cell_search_next(bool reset = false);
bool cell_select(uint32_t earfcn, srslte_cell_t cell); void cell_select(uint32_t earfcn, srslte_cell_t cell);
bool cell_handover(srslte_cell_t cell); bool cell_handover(srslte_cell_t cell);
void meas_reset(); void meas_reset();
@ -95,7 +94,6 @@ private:
void reset(); void reset();
void radio_error(); void radio_error();
bool wait_radio_reset();
void set_ue_sync_opts(srslte_ue_sync_t *q, float cfo); void set_ue_sync_opts(srslte_ue_sync_t *q, float cfo);
void run_thread(); void run_thread();
@ -104,14 +102,13 @@ private:
bool set_cell(); bool set_cell();
void cell_search_inc(); void cell_search_inc();
void resync_sfn(bool is_connected = false, bool rx_now = false); void cell_reselect();
bool stop_sync();
void stop_rx(); float get_cfo();
void start_rx(bool now = false);
bool radio_is_rx; uint32_t new_earfcn;
srslte_cell_t new_cell;
bool radio_is_resetting;
bool running; bool running;
// Class to run cell search // Class to run cell search
@ -155,7 +152,7 @@ private:
srslte_ue_mib_t ue_mib; srslte_ue_mib_t ue_mib;
uint32_t cnt; uint32_t cnt;
uint32_t timeout; uint32_t timeout;
const static uint32_t SYNC_SFN_TIMEOUT = 500; const static uint32_t SYNC_SFN_TIMEOUT = 80;
}; };
// Class to perform cell measurements // Class to perform cell measurements
@ -167,13 +164,14 @@ private:
typedef enum {IDLE, MEASURE_OK, ERROR} ret_code; typedef enum {IDLE, MEASURE_OK, ERROR} ret_code;
~measure(); ~measure();
void init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, srslte::radio *radio_h, void init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h,
uint32_t nof_rx_antennas, uint32_t nof_subframes = RSRP_MEASURE_NOF_FRAMES); uint32_t nof_rx_antennas, uint32_t nof_subframes = RSRP_MEASURE_NOF_FRAMES);
void reset(); void reset();
void set_cell(srslte_cell_t cell); void set_cell(srslte_cell_t cell);
ret_code run_subframe(uint32_t sf_idx); ret_code run_subframe(uint32_t sf_idx);
ret_code run_subframe_sync(srslte_ue_sync_t *ue_sync, uint32_t sf_idx); ret_code run_subframe_sync(srslte_ue_sync_t *ue_sync, uint32_t sf_idx);
ret_code run_multiple_subframes(cf_t *buffer, uint32_t offset, uint32_t sf_idx, uint32_t nof_sf); ret_code run_multiple_subframes(cf_t *buffer, int offset, uint32_t sf_idx, uint32_t nof_sf);
float rssi();
float rsrp(); float rsrp();
float rsrq(); float rsrq();
float snr(); float snr();
@ -183,7 +181,6 @@ private:
srslte::log *log_h; srslte::log *log_h;
srslte_ue_dl_t ue_dl; srslte_ue_dl_t ue_dl;
cf_t *buffer[SRSLTE_MAX_PORTS]; cf_t *buffer[SRSLTE_MAX_PORTS];
srslte::radio *radio_h;
uint32_t cnt; uint32_t cnt;
uint32_t nof_subframes; uint32_t nof_subframes;
uint32_t current_prb; uint32_t current_prb;
@ -204,11 +201,11 @@ private:
uint32_t offset; uint32_t offset;
} cell_info_t; } cell_info_t;
void init(srslte::log *log_h, bool sic_pss_enabled, uint32_t max_sf_window); void init(srslte::log *log_h, bool sic_pss_enabled, uint32_t max_sf_window);
void deinit();
void reset(); void reset();
int find_cells(cf_t *input_buffer, float rx_gain_offset, srslte_cell_t current_cell, uint32_t nof_sf, cell_info_t found_cells[MAX_CELLS]); int find_cells(cf_t *input_buffer, float rx_gain_offset, srslte_cell_t current_cell, uint32_t nof_sf, cell_info_t found_cells[MAX_CELLS]);
private: private:
cf_t *input_cfo_corrected;
cf_t *sf_buffer[SRSLTE_MAX_PORTS]; cf_t *sf_buffer[SRSLTE_MAX_PORTS];
srslte::log *log_h; srslte::log *log_h;
srslte_sync_t sync_find; srslte_sync_t sync_find;
@ -225,6 +222,7 @@ private:
// Class to perform intra-frequency measurements // Class to perform intra-frequency measurements
class intra_measure : public thread { class intra_measure : public thread {
public: public:
~intra_measure();
void init(phch_common *common, rrc_interface_phy *rrc, srslte::log *log_h); void init(phch_common *common, rrc_interface_phy *rrc, srslte::log *log_h);
void stop(); void stop();
void add_cell(int pci); void add_cell(int pci);
@ -303,17 +301,18 @@ private:
const static uint32_t NOF_IN_SYNC_SF = 100; const static uint32_t NOF_IN_SYNC_SF = 100;
// State for primary cell // State for primary cell
enum { typedef enum {
IDLE = 0, IDLE = 0,
CELL_SEARCH, CELL_SEARCH,
CELL_SELECT, CELL_SELECT,
CELL_RESELECT, CELL_RESELECT,
CELL_MEASURE, CELL_MEASURE,
CELL_CAMP, CELL_CAMP,
IDLE_RX } phy_state_t;
} phy_state;
phy_state_t phy_state, prev_state;
bool is_in_idle, is_in_idle_rx; bool is_in_idle;
// Sampling rate mode (find is 1.96 MHz, camp is the full cell BW) // Sampling rate mode (find is 1.96 MHz, camp is the full cell BW)
enum { enum {
@ -335,7 +334,6 @@ private:
float ul_dl_factor; float ul_dl_factor;
uint32_t current_earfcn; uint32_t current_earfcn;
int cur_earfcn_index; int cur_earfcn_index;
bool cell_search_in_progress;
float dl_freq; float dl_freq;
float ul_freq; float ul_freq;

@ -54,7 +54,6 @@ public:
void set_tti(uint32_t tti, uint32_t tx_tti); void set_tti(uint32_t tti, uint32_t tx_tti);
void set_tx_time(srslte_timestamp_t tx_time, uint32_t next_offset); void set_tx_time(srslte_timestamp_t tx_time, uint32_t next_offset);
void set_cfo(float cfo); void set_cfo(float cfo);
void set_sample_offset(float sample_offset);
void set_ul_params(bool pregen_disabled = false); void set_ul_params(bool pregen_disabled = false);
void set_crnti(uint16_t rnti); void set_crnti(uint16_t rnti);
@ -74,7 +73,6 @@ public:
float get_rsrp(); float get_rsrp();
float get_noise(); float get_noise();
float get_cfo(); float get_cfo();
float get_ul_cfo();
private: private:
/* Inherited from thread_pool::worker. Function called every subframe to run the DL/UL processing */ /* Inherited from thread_pool::worker. Function called every subframe to run the DL/UL processing */
@ -120,6 +118,7 @@ private:
srslte::trace<uint32_t> tr_exec; srslte::trace<uint32_t> tr_exec;
bool trace_enabled; bool trace_enabled;
pthread_mutex_t mutex;
/* Common objects */ /* Common objects */
phch_common *phy; phch_common *phy;

@ -28,7 +28,7 @@
#define UEPHY_H #define UEPHY_H
#include "srslte/srslte.h" #include "srslte/srslte.h"
#include "srslte/common/log.h" #include "srslte/common/log_filter.h"
#include "phy/phy_metrics.h" #include "phy/phy_metrics.h"
#include "phy/phch_recv.h" #include "phy/phch_recv.h"
#include "phy/prach.h" #include "phy/prach.h"
@ -53,7 +53,7 @@ public:
bool init(srslte::radio_multi *radio_handler, bool init(srslte::radio_multi *radio_handler,
mac_interface_phy *mac, mac_interface_phy *mac,
rrc_interface_phy *rrc, rrc_interface_phy *rrc,
std::vector<srslte::log*> log_vec, std::vector<srslte::log_filter*> log_vec,
phy_args_t *args = NULL); phy_args_t *args = NULL);
void stop(); void stop();
@ -85,9 +85,8 @@ public:
void sync_reset(); void sync_reset();
void configure_ul_params(bool pregen_disabled = false); void configure_ul_params(bool pregen_disabled = false);
void cell_search_start(); void cell_search_start();
void cell_search_stop();
void cell_search_next(); void cell_search_next();
bool cell_select(uint32_t earfcn, srslte_cell_t phy_cell); void cell_select(uint32_t earfcn, srslte_cell_t phy_cell);
bool cell_handover(srslte_cell_t cell); bool cell_handover(srslte_cell_t cell);
void meas_reset(); void meas_reset();
@ -159,7 +158,7 @@ private:
const static int WORKERS_THREAD_PRIO = 0; const static int WORKERS_THREAD_PRIO = 0;
srslte::radio_multi *radio_handler; srslte::radio_multi *radio_handler;
std::vector<srslte::log*> log_vec; std::vector<srslte::log_filter*> log_vec;
srslte::log *log_h; srslte::log *log_h;
srslte::log *log_phy_lib_h; srslte::log *log_phy_lib_h;
srsue::mac_interface_phy *mac; srsue::mac_interface_phy *mac;

@ -72,6 +72,8 @@ public:
bool is_attached(); bool is_attached();
void start_plot(); void start_plot();
void print_pool();
static void rf_msg(srslte_rf_error_t error); static void rf_msg(srslte_rf_error_t error);
// UE metrics interface // UE metrics interface
@ -101,7 +103,7 @@ private:
srslte::logger *logger; srslte::logger *logger;
// rf_log is on ue_base // rf_log is on ue_base
std::vector<srslte::log*> phy_log; std::vector<srslte::log_filter*> phy_log;
srslte::log_filter mac_log; srslte::log_filter mac_log;
srslte::log_filter rlc_log; srslte::log_filter rlc_log;
srslte::log_filter pdcp_log; srslte::log_filter pdcp_log;
@ -110,8 +112,6 @@ private:
srslte::log_filter gw_log; srslte::log_filter gw_log;
srslte::log_filter usim_log; srslte::log_filter usim_log;
srslte::byte_buffer_pool *pool;
all_args_t *args; all_args_t *args;
bool started; bool started;

@ -126,6 +126,7 @@ typedef struct {
usim_args_t usim; usim_args_t usim;
rrc_args_t rrc; rrc_args_t rrc;
std::string ue_category_str; std::string ue_category_str;
std::string apn;
expert_args_t expert; expert_args_t expert;
}all_args_t; }all_args_t;
@ -146,7 +147,7 @@ class ue_base
{ {
public: public:
ue_base(); ue_base();
virtual ~ue_base() {} virtual ~ue_base();
static ue_base* get_instance(srsue_instance_type_t type); static ue_base* get_instance(srsue_instance_type_t type);
@ -157,6 +158,8 @@ public:
virtual bool is_attached() = 0; virtual bool is_attached() = 0;
virtual void start_plot() = 0; virtual void start_plot() = 0;
virtual void print_pool() = 0;
virtual void radio_overflow() = 0; virtual void radio_overflow() = 0;
void handle_rf_msg(srslte_rf_error_t error); void handle_rf_msg(srslte_rf_error_t error);
@ -173,6 +176,9 @@ public:
std::string get_build_mode(); std::string get_build_mode();
std::string get_build_info(); std::string get_build_info();
std::string get_build_string(); std::string get_build_string();
private:
srslte::byte_buffer_pool *pool;
}; };
} // namespace srsue } // namespace srsue

@ -88,9 +88,10 @@ public:
uint32_t get_ul_count(); uint32_t get_ul_count();
bool is_attached(); bool is_attached();
bool is_attaching(); bool is_attaching();
bool is_data_requested();
bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi); bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi);
bool get_k_asme(uint8_t *k_asme_, uint32_t n); bool get_k_asme(uint8_t *k_asme_, uint32_t n);
void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code); bool plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code);
void plmn_search_end(); void plmn_search_end();
// UE interface // UE interface

@ -37,6 +37,7 @@
#include "srslte/common/security.h" #include "srslte/common/security.h"
#include "srslte/common/threads.h" #include "srslte/common/threads.h"
#include <math.h>
#include <map> #include <map>
#include <queue> #include <queue>
@ -65,14 +66,16 @@ class cell_t
return earfcn == this->earfcn && pci == phy_cell.id; return earfcn == this->earfcn && pci == phy_cell.id;
} }
bool greater(cell_t *x) { bool greater(cell_t *x) {
return x->rsrp > rsrp; return rsrp > x->rsrp;
} }
bool plmn_equals(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) { bool plmn_equals(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) {
if (has_valid_sib1) {
for (uint32_t i = 0; i < sib1.N_plmn_ids; i++) { for (uint32_t i = 0; i < sib1.N_plmn_ids; i++) {
if (plmn_id.mcc == sib1.plmn_id[i].id.mcc && plmn_id.mnc == sib1.plmn_id[i].id.mnc) { if (plmn_id.mcc == sib1.plmn_id[i].id.mcc && plmn_id.mnc == sib1.plmn_id[i].id.mnc) {
return true; return true;
} }
} }
}
return false; return false;
} }
cell_t() { cell_t() {
@ -80,6 +83,7 @@ class cell_t
cell_t(tmp, 0, 0); cell_t(tmp, 0, 0);
} }
cell_t(srslte_cell_t phy_cell, uint32_t earfcn, float rsrp) { cell_t(srslte_cell_t phy_cell, uint32_t earfcn, float rsrp) {
gettimeofday(&last_update, NULL);
this->has_valid_sib1 = false; this->has_valid_sib1 = false;
this->has_valid_sib2 = false; this->has_valid_sib2 = false;
this->has_valid_sib3 = false; this->has_valid_sib3 = false;
@ -94,14 +98,108 @@ class cell_t
bzero(&sib13, sizeof(sib13)); bzero(&sib13, sizeof(sib13));
} }
uint32_t earfcn; uint32_t get_earfcn() {
return earfcn;
}
uint32_t get_pci() {
return phy_cell.id;
}
void set_rsrp(float rsrp) {
if (~isnan(rsrp)) {
this->rsrp = rsrp;
}
in_sync = true;
gettimeofday(&last_update, NULL);
}
float get_rsrp() {
return rsrp;
}
void set_sib1(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT *sib1) {
memcpy(&this->sib1, sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT));
has_valid_sib1 = true;
}
void set_sib2(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2) {
memcpy(&this->sib2, sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT));
has_valid_sib2 = true;
}
void set_sib3(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *sib3) {
memcpy(&this->sib3, sib3, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT));
has_valid_sib3 = true;
}
void set_sib13(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT *sib13) {
memcpy(&this->sib13, sib13, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_13_STRUCT));
has_valid_sib13 = true;
}
uint32_t timeout_secs(struct timeval now) {
struct timeval t[3];
memcpy(&t[2], &now, sizeof(struct timeval));
memcpy(&t[1], &last_update, sizeof(struct timeval));
get_time_interval(t);
return t[0].tv_sec;
}
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT *sib1ptr() {
return &sib1;
}
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2ptr() {
return &sib2;
}
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT *sib3ptr() {
return &sib3;
}
uint32_t get_cell_id() {
return sib1.cell_id;
}
bool has_sib1() {
return has_valid_sib1;
}
bool has_sib2() {
return has_valid_sib2;
}
bool has_sib3() {
return has_valid_sib3;
}
bool has_sib13() {
return has_valid_sib13;
}
uint16_t get_mcc() {
if (has_valid_sib1) {
if (sib1.N_plmn_ids > 0) {
return sib1.plmn_id[0].id.mcc;
}
}
return 0;
}
uint16_t get_mnc() {
if (has_valid_sib1) {
if (sib1.N_plmn_ids > 0) {
return sib1.plmn_id[0].id.mnc;
}
}
return 0;
}
srslte_cell_t phy_cell; srslte_cell_t phy_cell;
bool in_sync;
private:
float rsrp; float rsrp;
uint32_t earfcn;
struct timeval last_update;
bool has_valid_sib1; bool has_valid_sib1;
bool has_valid_sib2; bool has_valid_sib2;
bool has_valid_sib3; bool has_valid_sib3;
bool has_valid_sib13; bool has_valid_sib13;
bool in_sync;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1; LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2; LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT sib3; LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT sib3;
@ -151,13 +249,13 @@ public:
void enable_capabilities(); void enable_capabilities();
void plmn_search(); void plmn_search();
void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id); void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, bool connect_request);
// PHY interface // PHY interface
void in_sync(); void in_sync();
void out_of_sync(); void out_of_sync();
void earfcn_end(); void earfcn_end();
void cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp); void cell_camping(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp);
void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn, int pci); void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn, int pci);
// MAC interface // MAC interface
@ -197,9 +295,9 @@ private:
LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg; LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg;
LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg; LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg;
byte_buffer_t* byte_align_and_pack(byte_buffer_t *pdu = NULL); byte_buffer_t* byte_align_and_pack();
void send_ul_ccch_msg(byte_buffer_t *pdu = NULL); void send_ul_ccch_msg();
void send_ul_dcch_msg(byte_buffer_t *pdu = NULL); void send_ul_dcch_msg();
srslte::bit_buffer_t bit_buf; srslte::bit_buffer_t bit_buf;
pthread_mutex_t mutex; pthread_mutex_t mutex;
@ -213,6 +311,8 @@ private:
uint16_t ho_src_rnti; uint16_t ho_src_rnti;
cell_t ho_src_cell; cell_t ho_src_cell;
uint32_t ho_target_pci;
bool ho_syncing;
phy_interface_rrc::phy_cfg_t ho_src_phy_cfg; phy_interface_rrc::phy_cfg_t ho_src_phy_cfg;
mac_interface_rrc::mac_cfg_t ho_src_mac_cfg; mac_interface_rrc::mac_cfg_t ho_src_mac_cfg;
bool pending_mob_reconf; bool pending_mob_reconf;
@ -226,9 +326,6 @@ private:
uint32_t plmn_select_timeout; uint32_t plmn_select_timeout;
static const uint32_t RRC_PLMN_SELECT_TIMEOUT = 10000; static const uint32_t RRC_PLMN_SELECT_TIMEOUT = 10000;
uint32_t select_cell_timeout;
static const uint32_t RRC_SELECT_CELL_TIMEOUT = 2000;
uint8_t k_rrc_enc[32]; uint8_t k_rrc_enc[32];
uint8_t k_rrc_int[32]; uint8_t k_rrc_int[32];
uint8_t k_up_enc[32]; uint8_t k_up_enc[32];
@ -244,7 +341,7 @@ private:
srslte::mac_interface_timers *mac_timers; srslte::mac_interface_timers *mac_timers;
uint32_t n310_cnt, N310; uint32_t n310_cnt, N310;
uint32_t n311_cnt, N311; uint32_t n311_cnt, N311;
uint32_t t301, t310, t311, t304; uint32_t t300, t301, t310, t311, t304;
// Radio bearers // Radio bearers
typedef enum{ typedef enum{
@ -274,6 +371,7 @@ private:
} }
// List of strongest neighbour cell // List of strongest neighbour cell
const static int NEIGHBOUR_TIMEOUT = 5;
const static int NOF_NEIGHBOUR_CELLS = 8; const static int NOF_NEIGHBOUR_CELLS = 8;
std::vector<cell_t*> neighbour_cells; std::vector<cell_t*> neighbour_cells;
cell_t *serving_cell; cell_t *serving_cell;
@ -285,6 +383,9 @@ private:
bool add_neighbour_cell(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp); bool add_neighbour_cell(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp);
bool add_neighbour_cell(cell_t *cell); bool add_neighbour_cell(cell_t *cell);
void sort_neighbour_cells(); void sort_neighbour_cells();
void clean_neighbours();
std::vector<cell_t*>::iterator delete_neighbour(std::vector<cell_t*>::iterator it);
void delete_neighbour(uint32_t cell_idx);
typedef enum { typedef enum {
SI_ACQUIRE_IDLE = 0, SI_ACQUIRE_IDLE = 0,
@ -299,7 +400,7 @@ private:
uint16_t sysinfo_index; uint16_t sysinfo_index;
uint32_t last_win_start; uint32_t last_win_start;
void select_next_cell_in_plmn(); bool select_next_cell_in_plmn();
LIBLTE_RRC_PLMN_IDENTITY_STRUCT selected_plmn_id; LIBLTE_RRC_PLMN_IDENTITY_STRUCT selected_plmn_id;
bool thread_running; bool thread_running;
@ -315,6 +416,7 @@ private:
void run_tti(uint32_t tti); void run_tti(uint32_t tti);
bool timer_expired(uint32_t timer_id); bool timer_expired(uint32_t timer_id);
void ho_finish(); void ho_finish();
void delete_report(uint32_t earfcn, uint32_t pci);
private: private:
const static int NOF_MEASUREMENTS = 3; const static int NOF_MEASUREMENTS = 3;
@ -429,10 +531,10 @@ private:
void send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_ENUM cause, uint16_t crnti); void send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_ENUM cause, uint16_t crnti);
void send_con_restablish_complete(); void send_con_restablish_complete();
void send_con_setup_complete(byte_buffer_t *nas_msg); void send_con_setup_complete(byte_buffer_t *nas_msg);
void send_ul_info_transfer(uint32_t lcid, byte_buffer_t *sdu); void send_ul_info_transfer(byte_buffer_t *nas_msg);
void send_security_mode_complete(uint32_t lcid, byte_buffer_t *pdu); void send_security_mode_complete();
void send_rrc_con_reconfig_complete(byte_buffer_t *pdu); void send_rrc_con_reconfig_complete();
void send_rrc_ue_cap_info(byte_buffer_t *pdu); void send_rrc_ue_cap_info();
// Parsers // Parsers
void parse_dl_ccch(byte_buffer_t *pdu); void parse_dl_ccch(byte_buffer_t *pdu);
@ -442,6 +544,7 @@ private:
// Helpers // Helpers
void ho_failed(); void ho_failed();
bool ho_prepare(); bool ho_prepare();
void ho_synced(uint32_t target_pci);
void rrc_connection_release(); void rrc_connection_release();
void con_restablish_cell_reselected(); void con_restablish_cell_reselected();
void radio_link_failure(); void radio_link_failure();
@ -459,7 +562,7 @@ private:
void apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2); void apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2);
void handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup); void handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup);
void handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup); void handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup);
void handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig, byte_buffer_t *pdu); void handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig);
void add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg); void add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg);
void add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg); void add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg);
void release_drb(uint8_t lcid); void release_drb(uint8_t lcid);

@ -33,6 +33,7 @@ namespace srsue {
// RRC states (3GPP 36.331 v10.0.0) // RRC states (3GPP 36.331 v10.0.0)
typedef enum { typedef enum {
RRC_STATE_IDLE = 0, RRC_STATE_IDLE = 0,
RRC_STATE_PLMN_START,
RRC_STATE_PLMN_SELECTION, RRC_STATE_PLMN_SELECTION,
RRC_STATE_CELL_SELECTING, RRC_STATE_CELL_SELECTING,
RRC_STATE_CELL_SELECTED, RRC_STATE_CELL_SELECTED,
@ -44,11 +45,14 @@ typedef enum {
RRC_STATE_N_ITEMS, RRC_STATE_N_ITEMS,
} rrc_state_t; } rrc_state_t;
static const char rrc_state_text[RRC_STATE_N_ITEMS][100] = {"IDLE", static const char rrc_state_text[RRC_STATE_N_ITEMS][100] = {"IDLE",
"PLMN SELECTED",
"PLMN SELECTION", "PLMN SELECTION",
"CELL SELECTING", "CELL SELECTING",
"CELL SELECTED", "CELL SELECTED",
"CONNECTING", "CONNECTING",
"CONNECTED", "CONNECTED",
"HO PREPARE",
"HO PROCESS",
"LEAVE CONNECTED"}; "LEAVE CONNECTED"};
} // namespace srsue } // namespace srsue

@ -165,7 +165,14 @@ void demux::process_sch_pdu(srslte::sch_pdu *pdu_msg)
// Route logical channel // Route logical channel
if (route_pdu) { if (route_pdu) {
Info("Delivering PDU for lcid=%d, %d bytes\n", pdu_msg->get()->get_sdu_lcid(), pdu_msg->get()->get_payload_size()); Info("Delivering PDU for lcid=%d, %d bytes\n", pdu_msg->get()->get_sdu_lcid(), pdu_msg->get()->get_payload_size());
if (pdu_msg->get()->get_payload_size() < MAX_PDU_LEN) {
rlc->write_pdu(pdu_msg->get()->get_sdu_lcid(), pdu_msg->get()->get_sdu_ptr(), pdu_msg->get()->get_payload_size()); rlc->write_pdu(pdu_msg->get()->get_sdu_lcid(), pdu_msg->get()->get_sdu_ptr(), pdu_msg->get()->get_payload_size());
} else {
char tmp[1024];
srslte_vec_sprint_hex(tmp, sizeof(tmp), pdu_msg->get()->get_sdu_ptr(), 32);
Error("PDU size %d exceeds maximum PDU buffer size, lcid=%d, hex=[%s]\n",
pdu_msg->get()->get_payload_size(), pdu_msg->get()->get_sdu_lcid(), tmp);
}
} }
} else { } else {
// Process MAC Control Element // Process MAC Control Element

@ -82,6 +82,7 @@ bool mac::init(phy_interface_mac *phy, rlc_interface_mac *rlc, rrc_interface_mac
started = true; started = true;
start(MAC_MAIN_THREAD_PRIO); start(MAC_MAIN_THREAD_PRIO);
mactimers.init(&timers, log_h);
return started; return started;
} }
@ -94,6 +95,7 @@ void mac::stop()
ttisync.increase(); ttisync.increase();
pdu_process_thread.stop(); pdu_process_thread.stop();
wait_thread_finish(); wait_thread_finish();
mactimers.stop();
} }
void mac::start_pcap(srslte::mac_pcap* pcap_) void mac::start_pcap(srslte::mac_pcap* pcap_)
@ -148,6 +150,17 @@ void mac::reset()
bzero(&uernti, sizeof(ue_rnti_t)); bzero(&uernti, sizeof(ue_rnti_t));
} }
void mac::mac_timers::init(srslte::timers *timers, srslte::log *log_h) {
this->timers = timers;
running = true;
this->log_h = log_h;
start_periodic(1000);
}
void mac::mac_timers::run_period() {
timers->step_all();
}
void mac::run_thread() { void mac::run_thread() {
int cnt=0; int cnt=0;
@ -165,7 +178,6 @@ void mac::run_thread() {
tti = ttisync.wait(); tti = ttisync.wait();
log_h->step(tti); log_h->step(tti);
timers.step_all();
// Step all procedures // Step all procedures
bsr_procedure.step(tti); bsr_procedure.step(tti);

@ -47,6 +47,7 @@ mux::mux(uint8_t nof_harq_proc_) : pdu_msg(MAX_NOF_SUBHEADERS), pid_has_bsr(nof_
rlc = NULL; rlc = NULL;
bsr_procedure = NULL; bsr_procedure = NULL;
phr_procedure = NULL; phr_procedure = NULL;
msg3_buff_start_pdu = NULL;
msg3_flush(); msg3_flush();
} }
@ -166,7 +167,6 @@ uint8_t* mux::pdu_get(uint8_t *payload, uint32_t pdu_sz, uint32_t tx_tti, uint32
} }
// Logical Channel Procedure // Logical Channel Procedure
bool is_rar = false; bool is_rar = false;
pdu_msg.init_tx(payload, pdu_sz, true); pdu_msg.init_tx(payload, pdu_sz, true);
@ -324,7 +324,6 @@ bool mux::allocate_sdu(uint32_t lcid, srslte::sch_pdu* pdu_msg, int max_sdu_sz)
if (pdu_msg->new_subh()) { // there is space for a new subheader if (pdu_msg->new_subh()) { // there is space for a new subheader
sdu_len = pdu_msg->get()->set_sdu(lcid, sdu_len, rlc); sdu_len = pdu_msg->get()->set_sdu(lcid, sdu_len, rlc);
if (sdu_len > 0) { // new SDU could be added if (sdu_len > 0) { // new SDU could be added
Debug("SDU: allocated lcid=%d, rlc_buffer=%d, allocated=%d/%d, max_sdu_sz=%d, remaining=%d\n", Debug("SDU: allocated lcid=%d, rlc_buffer=%d, allocated=%d/%d, max_sdu_sz=%d, remaining=%d\n",
lcid, buffer_state, sdu_len, sdu_space, max_sdu_sz, pdu_msg->rem_size()); lcid, buffer_state, sdu_len, sdu_space, max_sdu_sz, pdu_msg->rem_size());
return true; return true;
@ -347,6 +346,7 @@ void mux::msg3_flush()
msg3_has_been_transmitted = false; msg3_has_been_transmitted = false;
msg3_pending = false; msg3_pending = false;
bzero(msg3_buff, sizeof(MSG3_BUFF_SZ)); bzero(msg3_buff, sizeof(MSG3_BUFF_SZ));
msg3_buff_start_pdu = NULL;
} }
bool mux::msg3_is_transmitted() bool mux::msg3_is_transmitted()
@ -366,19 +366,22 @@ bool mux::msg3_is_pending() {
uint8_t* mux::msg3_get(uint8_t *payload, uint32_t pdu_sz) uint8_t* mux::msg3_get(uint8_t *payload, uint32_t pdu_sz)
{ {
if (pdu_sz < MSG3_BUFF_SZ - 32) { if (pdu_sz < MSG3_BUFF_SZ - 32) {
uint8_t* msg3_buff_start_pdu = pdu_get(msg3_buff, pdu_sz, 0, 0); if (!msg3_buff_start_pdu) {
msg3_buff_start_pdu = pdu_get(msg3_buff, pdu_sz, 0, 0);
if (!msg3_buff_start_pdu) { if (!msg3_buff_start_pdu) {
Error("Moving PDU from Mux unit to Msg3 buffer\n"); Error("Moving PDU from Mux unit to Msg3 buffer\n");
return NULL; return NULL;
} }
memcpy(payload, msg3_buff_start_pdu, sizeof(uint8_t)*pdu_sz);
msg3_has_been_transmitted = true; msg3_has_been_transmitted = true;
msg3_pending = false; msg3_pending = false;
return payload; }
} else { } else {
Error("Msg3 size (%d) is longer than internal msg3_buff size=%d, (see mux.h)\n", pdu_sz, MSG3_BUFF_SZ-32); Error("Msg3 size (%d) is longer than internal msg3_buff size=%d, (see mux.h)\n", pdu_sz, MSG3_BUFF_SZ-32);
return NULL; return NULL;
} }
memcpy(payload, msg3_buff_start_pdu, sizeof(uint8_t)*pdu_sz);
msg3_has_been_transmitted = true;
return payload;
} }

@ -82,6 +82,7 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
"UECapabilityInformation message. Default 0xe6041c00") "UECapabilityInformation message. Default 0xe6041c00")
("rrc.ue_category", bpo::value<string>(&args->ue_category_str)->default_value("4"), "UE Category (1 to 5)") ("rrc.ue_category", bpo::value<string>(&args->ue_category_str)->default_value("4"), "UE Category (1 to 5)")
("nas.apn", bpo::value<string>(&args->apn)->default_value(""), "Set Access Point Name (APN) for data services")
("pcap.enable", bpo::value<bool>(&args->pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark") ("pcap.enable", bpo::value<bool>(&args->pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark")
("pcap.filename", bpo::value<string>(&args->pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename") ("pcap.filename", bpo::value<string>(&args->pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename")
@ -159,11 +160,11 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
"Pregenerate uplink signals after attach. Improves CPU performance.") "Pregenerate uplink signals after attach. Improves CPU performance.")
("expert.rssi_sensor_enabled", ("expert.rssi_sensor_enabled",
bpo::value<bool>(&args->expert.phy.rssi_sensor_enabled)->default_value(true), bpo::value<bool>(&args->expert.phy.rssi_sensor_enabled)->default_value(false),
"Enable or disable RF frontend RSSI sensor. In some USRP devices can cause segmentation fault") "Enable or disable RF frontend RSSI sensor. In some USRP devices can cause segmentation fault")
("expert.rx_gain_offset", ("expert.rx_gain_offset",
bpo::value<float>(&args->expert.phy.rx_gain_offset)->default_value(10), bpo::value<float>(&args->expert.phy.rx_gain_offset)->default_value(62),
"RX Gain offset to add to rx_gain to correct RSRP value") "RX Gain offset to add to rx_gain to correct RSRP value")
("expert.prach_gain", ("expert.prach_gain",
@ -202,6 +203,11 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
bpo::value<string>(&args->expert.phy.equalizer_mode)->default_value("mmse"), bpo::value<string>(&args->expert.phy.equalizer_mode)->default_value("mmse"),
"Equalizer mode") "Equalizer mode")
("expert.cfo_is_doppler",
bpo::value<bool>(&args->expert.phy.cfo_is_doppler)->default_value(false),
"Assume detected CFO is doppler and correct the UL in the same direction. If disabled, the CFO is assumed"
"to be caused by the local oscillator and the UL correction is in the opposite direction. Default assumes oscillator.")
("expert.cfo_integer_enabled", ("expert.cfo_integer_enabled",
bpo::value<bool>(&args->expert.phy.cfo_integer_enabled)->default_value(false), bpo::value<bool>(&args->expert.phy.cfo_integer_enabled)->default_value(false),
"Enables integer CFO estimation and correction.") "Enables integer CFO estimation and correction.")
@ -214,12 +220,6 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
bpo::value<float>(&args->expert.phy.cfo_pss_ema)->default_value(DEFAULT_CFO_EMA_TRACK), bpo::value<float>(&args->expert.phy.cfo_pss_ema)->default_value(DEFAULT_CFO_EMA_TRACK),
"CFO Exponential Moving Average coefficient for PSS estimation during TRACK.") "CFO Exponential Moving Average coefficient for PSS estimation during TRACK.")
/* REF EMA is currently not used
("expert.cfo_ref_ema",
bpo::value<float>(&args->expert.phy.cfo_ref_ema)->default_value(0.01),
"CFO Exponential Moving Average coefficient for RS estimation after PSS acquisition")
*/
("expert.cfo_ref_mask", ("expert.cfo_ref_mask",
bpo::value<uint32_t>(&args->expert.phy.cfo_ref_mask)->default_value(1023), bpo::value<uint32_t>(&args->expert.phy.cfo_ref_mask)->default_value(1023),
"Bitmask for subframes on which to run RS estimation (set to 0 to disable, default all sf)") "Bitmask for subframes on which to run RS estimation (set to 0 to disable, default all sf)")
@ -257,10 +257,6 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
bpo::value<int>(&args->expert.phy.time_correct_period)->default_value(5), bpo::value<int>(&args->expert.phy.time_correct_period)->default_value(5),
"Period for sampling time offset correction.") "Period for sampling time offset correction.")
("expert.sfo_correct_disable",
bpo::value<bool>(&args->expert.phy.sfo_correct_disable)->default_value(false),
"Disables phase correction before channel estimation.")
("expert.sss_algorithm", ("expert.sss_algorithm",
bpo::value<string>(&args->expert.phy.sss_algorithm)->default_value("full"), bpo::value<string>(&args->expert.phy.sss_algorithm)->default_value("full"),
"Selects the SSS estimation algorithm.") "Selects the SSS estimation algorithm.")
@ -269,6 +265,9 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
bpo::value<float>(&args->expert.phy.estimator_fil_w)->default_value(0.1), bpo::value<float>(&args->expert.phy.estimator_fil_w)->default_value(0.1),
"Chooses the coefficients for the 3-tap channel estimator centered filter.") "Chooses the coefficients for the 3-tap channel estimator centered filter.")
("expert.pdsch_csi_enabled",
bpo::value<bool>(&args->expert.phy.pdsch_csi_enabled)->default_value(false),
"Stores the Channel State Information and uses it for weightening the softbits. It is only compatible with TM1.")
("rf_calibration.tx_corr_dc_gain", bpo::value<float>(&args->rf_cal.tx_corr_dc_gain)->default_value(0.0), ("rf_calibration.tx_corr_dc_gain", bpo::value<float>(&args->rf_cal.tx_corr_dc_gain)->default_value(0.0),
"TX DC offset gain correction") "TX DC offset gain correction")
@ -418,6 +417,9 @@ void *input_loop(void *m) {
cout << "Enter t to restart trace." << endl; cout << "Enter t to restart trace." << endl;
} }
metrics_screen.toggle_print(do_metrics); metrics_screen.toggle_print(do_metrics);
} else
if ('q' == key) {
running = false;
} }
} }
} }
@ -474,7 +476,8 @@ int main(int argc, char *argv[])
plot_started = true; plot_started = true;
} }
} }
sleep(1); ue->print_pool();
sleep(10);
} }
pthread_cancel(input); pthread_cancel(input);
metricshub.stop(); metricshub.stop();

@ -355,13 +355,16 @@ void phch_common::reset() {
void phch_common::reset_ul() void phch_common::reset_ul()
{ {
/*
is_first_tx = true; is_first_tx = true;
is_first_of_burst = true; is_first_of_burst = true;
for (uint32_t i=0;i<nof_mutex;i++) { for (uint32_t i=0;i<nof_mutex;i++) {
pthread_mutex_trylock(&tx_mutex[i]); pthread_mutex_trylock(&tx_mutex[i]);
pthread_mutex_unlock(&tx_mutex[i]); pthread_mutex_unlock(&tx_mutex[i]);
} }
radio_h->tx_end(); radio_h->tx_end();
*/
} }
} }

@ -91,7 +91,7 @@ void phch_recv::init(srslte::radio_multi *_radio_handler, mac_interface_phy *_ma
sfn_p.init(&ue_sync, sf_buffer, log_h); sfn_p.init(&ue_sync, sf_buffer, log_h);
// Initialize measurement class for the primary cell // Initialize measurement class for the primary cell
measure_p.init(sf_buffer, log_h, radio_h, nof_rx_antennas); measure_p.init(sf_buffer, log_h, nof_rx_antennas);
// Start intra-frequency measurement // Start intra-frequency measurement
intra_freq_meas.init(worker_com, rrc, log_h); intra_freq_meas.init(worker_com, rrc, log_h);
@ -132,9 +132,7 @@ void phch_recv::reset()
next_offset = 0; next_offset = 0;
cell_is_set = false; cell_is_set = false;
srate_mode = SRATE_NONE; srate_mode = SRATE_NONE;
cell_search_in_progress = false;
current_earfcn = 0; current_earfcn = 0;
radio_is_resetting = false;
sfn_p.reset(); sfn_p.reset();
measure_p.reset(); measure_p.reset();
search_p.reset(); search_p.reset();
@ -144,33 +142,16 @@ void phch_recv::reset()
void phch_recv::radio_error() void phch_recv::radio_error()
{ {
log_h->error("SYNC: Receiving from radio.\n"); log_h->error("SYNC: Receiving from radio.\n");
phy_state = IDLE;
radio_is_resetting=true;
// Need to find a method to effectively reset radio, reloading the driver does not work
//radio_h->reset();
radio_h->stop();
fprintf(stdout, "Error while receiving samples. Restart srsUE\n");
exit(-1);
reset(); reset();
radio_is_resetting=false; phy_state = CELL_SEARCH;
// Need to find a method to effectively reset radio, reloading the driver does not work
radio_h->reset();
} }
void phch_recv::set_cfo(float cfo) { void phch_recv::set_cfo(float cfo) {
srslte_ue_sync_set_cfo_ref(&ue_sync, cfo); srslte_ue_sync_set_cfo_ref(&ue_sync, cfo);
} }
bool phch_recv::wait_radio_reset() {
int cnt=0;
while(cnt < 20 && radio_is_resetting) {
sleep(1);
cnt++;
}
return radio_is_resetting;
}
void phch_recv::set_agc_enable(bool enable) void phch_recv::set_agc_enable(bool enable)
{ {
do_agc = enable; do_agc = enable;
@ -239,7 +220,7 @@ bool phch_recv::set_cell() {
// Set cell in all objects // Set cell in all objects
if (srslte_ue_sync_set_cell(&ue_sync, cell)) { if (srslte_ue_sync_set_cell(&ue_sync, cell)) {
Error("SYNC: Setting cell: initiating ue_sync"); Error("SYNC: Setting cell: initiating ue_sync\n");
return false; return false;
} }
measure_p.set_cell(cell); measure_p.set_cell(cell);
@ -265,19 +246,6 @@ bool phch_recv::set_cell() {
return cell_is_set; return cell_is_set;
} }
void phch_recv::resync_sfn(bool is_connected, bool now) {
if (!now) {
wait_radio_reset();
stop_rx();
}
start_rx(now);
sfn_p.reset();
Info("SYNC: Starting SFN synchronization\n");
phy_state = is_connected?CELL_RESELECT:CELL_SELECT;
}
void phch_recv::set_earfcn(std::vector<uint32_t> earfcn) { void phch_recv::set_earfcn(std::vector<uint32_t> earfcn) {
this->earfcn = earfcn; this->earfcn = earfcn;
} }
@ -287,34 +255,14 @@ void phch_recv::force_freq(float dl_freq, float ul_freq) {
this->ul_freq = ul_freq; this->ul_freq = ul_freq;
} }
bool phch_recv::stop_sync() {
wait_radio_reset();
if (phy_state == IDLE && is_in_idle) {
return true;
} else {
Info("SYNC: Going to IDLE\n");
phy_state = IDLE;
int cnt = 0;
while (!is_in_idle && cnt < 100) {
usleep(10000);
cnt++;
}
if (!is_in_idle) {
Warning("SYNC: Could not go to IDLE\n");
}
return is_in_idle;
}
}
void phch_recv::reset_sync() { void phch_recv::reset_sync() {
Warning("SYNC: Resetting sync, cell_search_in_progress=%s\n", cell_search_in_progress?"yes":"no"); Info("SYNC: Reset. Going to Cell Select\n");
sfn_p.reset();
search_p.reset(); search_p.reset();
measure_p.reset();
srslte_ue_sync_reset(&ue_sync); srslte_ue_sync_reset(&ue_sync);
resync_sfn(true, true); phy_state = CELL_SELECT;
} }
void phch_recv::cell_search_inc() void phch_recv::cell_search_inc()
@ -322,7 +270,9 @@ void phch_recv::cell_search_inc()
cur_earfcn_index++; cur_earfcn_index++;
if (cur_earfcn_index >= 0) { if (cur_earfcn_index >= 0) {
if (cur_earfcn_index >= (int) earfcn.size()) { if (cur_earfcn_index >= (int) earfcn.size()) {
Info("SYNC: Cell Search finished. Going to IDLE\n");
cur_earfcn_index = 0; cur_earfcn_index = 0;
phy_state = IDLE;
rrc->earfcn_end(); rrc->earfcn_end();
} else { } else {
Info("SYNC: Cell Search idx %d/%d\n", cur_earfcn_index, earfcn.size()); Info("SYNC: Cell Search idx %d/%d\n", cur_earfcn_index, earfcn.size());
@ -330,23 +280,16 @@ void phch_recv::cell_search_inc()
current_earfcn = earfcn[cur_earfcn_index]; current_earfcn = earfcn[cur_earfcn_index];
set_frequency(); set_frequency();
} }
phy_state = CELL_SEARCH;
} }
} }
} }
void phch_recv::cell_search_next(bool reset) { void phch_recv::cell_search_next(bool reset) {
if (cell_search_in_progress || reset) {
cell_search_in_progress = false;
if (!stop_sync()) {
log_h->warning("SYNC: Couldn't stop PHY\n");
}
if (reset) { if (reset) {
cur_earfcn_index = -1; cur_earfcn_index = -1;
} }
cell_search_inc(); cell_search_inc();
phy_state = CELL_SEARCH;
cell_search_in_progress = true;
}
} }
void phch_recv::cell_search_start() { void phch_recv::cell_search_start() {
@ -363,16 +306,13 @@ void phch_recv::cell_search_start() {
} }
} }
void phch_recv::cell_search_stop() {
Info("SYNC: Stopping Cell Search procedure...\n");
if (!stop_sync()) {
Error("SYNC: Stopping cell search\n");
}
cell_search_in_progress = false;
}
bool phch_recv::cell_handover(srslte_cell_t cell) bool phch_recv::cell_handover(srslte_cell_t cell)
{ {
if (!srslte_cell_isvalid(&cell)) {
log_h->error("Received HO command to invalid cell. ID=%d, PRB=%d, ports=%d\n", cell.id, cell.nof_prb, cell.nof_ports);
return false;
}
int cnt = 0; int cnt = 0;
while(worker_com->is_any_pending_ack() && cnt < 10) { while(worker_com->is_any_pending_ack() && cnt < 10) {
usleep(1000); usleep(1000);
@ -383,20 +323,21 @@ bool phch_recv::cell_handover(srslte_cell_t cell)
bool ret = false; bool ret = false;
this->cell = cell; this->cell = cell;
Info("Cell HO: Stopping sync with current cell\n"); Info("Cell HO: Stopping sync with current cell\n");
worker_com->reset_ul(); phy_state = IDLE;
phy_state = IDLE_RX;
cnt = 0; cnt = 0;
while(!is_in_idle_rx && cnt<20) { while(!is_in_idle && cnt<20) {
usleep(1000); usleep(1000);
cnt++; cnt++;
} }
if (is_in_idle_rx) { for(uint32_t i=0;i<workers_pool->get_nof_workers();i++) {
((phch_worker*) workers_pool->get_worker(i))->reset();
}
worker_com->reset();
if (is_in_idle) {
Info("Cell HO: Reconfiguring cell\n"); Info("Cell HO: Reconfiguring cell\n");
if (set_cell()) { if (set_cell()) {
//resync_sfn(true, true);
sfn_p.reset();
phy_state = CELL_RESELECT;
Info("Cell HO: Synchronizing with new cell\n"); Info("Cell HO: Synchronizing with new cell\n");
phy_state = CELL_SELECT;
ret = true; ret = true;
} else { } else {
log_h->error("Cell HO: Configuring cell PCI=%d\n", cell.id); log_h->error("Cell HO: Configuring cell PCI=%d\n", cell.id);
@ -409,31 +350,35 @@ bool phch_recv::cell_handover(srslte_cell_t cell)
return ret; return ret;
} }
bool phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell) { /* interface from higher layers to select a new cell */
void phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell)
{
Info("SYNC: Cell Reselect to EARFCN=%d, PCI=%d\n", earfcn, cell.id);
new_earfcn = earfcn;
new_cell = cell;
phy_state = CELL_RESELECT;
}
/* Perform cell (re)-selection on IDLE or CAMP */
void phch_recv::cell_reselect()
{
uint32_t earfcn = new_earfcn;
srslte_cell_t cell = new_cell;
reset_sync();
// Check if we are already camping in this cell // If we are already in the new cell, just resynchronize
if (earfcn == current_earfcn && this->cell.id == cell.id) { if (earfcn == current_earfcn && this->cell.id == cell.id) {
log_h->info("Cell Select: Already in cell EARFCN=%d\n", earfcn); log_h->info("Cell Select: Already in cell EARFCN=%d, PCI=%d\n", earfcn, cell.id);
cell_search_in_progress = false;
if (srate_mode != SRATE_CAMP) { if (srate_mode != SRATE_CAMP) {
set_sampling_rate(); set_sampling_rate();
log_h->info("Cell Select: Setting Camping sampling rate\n");
} }
if (phy_state < CELL_SELECT) {
resync_sfn();
}
return true;
} else { } else {
cell_search_in_progress = false;
if (!stop_sync()) {
log_h->warning("Still not in idle\n");
}
if (earfcn != current_earfcn) { if (earfcn != current_earfcn) {
if (set_frequency()) { if (set_frequency()) {
log_h->error("Cell Select: Configuring cell in EARFCN=%d, PCI=%d\n", earfcn, cell.id); log_h->error("Cell Select: Configuring cell in EARFCN=%d, PCI=%d\n", earfcn, cell.id);
return false;
} }
current_earfcn = earfcn; current_earfcn = earfcn;
} }
@ -443,13 +388,7 @@ bool phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell) {
if (set_cell()) { if (set_cell()) {
log_h->info("Cell Select: Synchronizing on cell...\n"); log_h->info("Cell Select: Synchronizing on cell...\n");
resync_sfn();
usleep(500000); // Time offset we set start_rx to start receiving samples
return true;
} }
return false;
} }
} }
@ -485,6 +424,25 @@ bool phch_recv::set_frequency()
} }
} }
float phch_recv::get_cfo()
{
float cfo = srslte_ue_sync_get_cfo(&ue_sync);
float ret = cfo*ul_dl_factor;
if (worker_com->args->cfo_is_doppler) {
ret *= -1;
}
if (radio_h->get_freq_offset() != 0.0f) {
/* Compensates the radio frequency offset applied equally to DL and UL */
const float offset_hz = (float) radio_h->get_freq_offset() * (1.0f - ul_dl_factor);
ret = cfo - offset_hz;
}
return ret/15000;
}
void phch_recv::set_sampling_rate() void phch_recv::set_sampling_rate()
{ {
current_srate = (float) srslte_sampling_freq_hz(cell.nof_prb); current_srate = (float) srslte_sampling_freq_hz(cell.nof_prb);
@ -514,22 +472,6 @@ void phch_recv::set_sampling_rate()
} }
} }
void phch_recv::stop_rx() {
if (radio_is_rx) {
Info("SYNC: Stopping RX streaming\n");
radio_h->stop_rx();
}
radio_is_rx = false;
}
void phch_recv::start_rx(bool now) {
if (!radio_is_rx) {
Info("SYNC: Starting RX streaming\n");
radio_h->start_rx(now);
}
radio_is_rx = true;
}
uint32_t phch_recv::get_current_tti() { uint32_t phch_recv::get_current_tti() {
return tti; return tti;
} }
@ -584,60 +526,62 @@ void phch_recv::run_thread()
uint32_t sf_idx = 0; uint32_t sf_idx = 0;
phy_state = IDLE; phy_state = IDLE;
is_in_idle = true; is_in_idle = true;
is_in_idle_rx = false;
cf_t *dummy_buffer[SRSLTE_MAX_PORTS];
for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
dummy_buffer[i] = (cf_t*) malloc(sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100));
}
while (running) while (running)
{ {
if (phy_state != IDLE) { if (phy_state != IDLE) {
is_in_idle = false; is_in_idle = false;
Debug("SYNC: state=%d\n", phy_state);
}
if (phy_state != IDLE_RX) {
is_in_idle_rx = false;
} }
Debug("SYNC: state=%d\n", phy_state);
log_h->step(tti); log_h->step(tti);
log_phy_lib_h->step(tti); log_phy_lib_h->step(tti);
sf_idx = tti%10; sf_idx = tti%10;
prev_state = phy_state;
switch (phy_state) { switch (phy_state) {
case CELL_SEARCH: case CELL_SEARCH:
if (cell_search_in_progress)
{
switch(search_p.run(&cell)) switch(search_p.run(&cell))
{ {
case search::CELL_FOUND: case search::CELL_FOUND:
if (!srslte_cell_isvalid(&cell)) { if (!srslte_cell_isvalid(&cell)) {
Error("SYNC: Detected invalid cell\n"); Error("SYNC: Detected invalid cell. Going to IDLE\n");
phy_state = IDLE; phy_state = IDLE;
break; break;
} }
if (set_cell()) { if (set_cell()) {
Info("SYNC: Setting sampling rate and going to Cell Select\n");
set_sampling_rate(); set_sampling_rate();
resync_sfn(); phy_state = CELL_SELECT;
} }
break; break;
case search::CELL_NOT_FOUND: case search::CELL_NOT_FOUND:
if (cell_search_in_progress) {
cell_search_inc(); cell_search_inc();
}
break; break;
default: default:
radio_error(); radio_error();
break; break;
} }
}
break; break;
case CELL_RESELECT: case CELL_RESELECT:
cell_reselect();
break;
case CELL_SELECT: case CELL_SELECT:
switch (sfn_p.run_subframe(&cell, &tti)) switch (sfn_p.run_subframe(&cell, &tti))
{ {
case sfn_sync::SFN_FOUND: case sfn_sync::SFN_FOUND:
if (!cell_search_in_progress) { if (prev_state != CELL_SEARCH) {
log_h->info("Sync OK. Camping on cell PCI=%d...\n", cell.id); log_h->info("Sync OK. Camping on cell PCI=%d...\n", cell.id);
phy_state = CELL_CAMP; phy_state = CELL_CAMP;
rrc->cell_camping(earfcn[cur_earfcn_index], cell);
} else { } else {
log_h->info("Sync OK. Measuring PCI=%d...\n", cell.id); log_h->info("Sync OK. Measuring PCI=%d...\n", cell.id);
measure_p.reset(); measure_p.reset();
@ -645,13 +589,8 @@ void phch_recv::run_thread()
} }
break; break;
case sfn_sync::TIMEOUT: case sfn_sync::TIMEOUT:
if (cell_search_in_progress) { log_h->warning("SYNC: Timeout while synchronizing SFN\n");
log_h->warning("SYNC: Timeout while synchronizing SFN. Going back to cell search\n"); rrc->out_of_sync();
phy_state = CELL_SEARCH;
} else {
log_h->warning("SYNC: Timeout while synchronizing SFN. Reselecting cell\n");
resync_sfn(true, true);
}
break; break;
case sfn_sync::IDLE: case sfn_sync::IDLE:
break; break;
@ -661,12 +600,21 @@ void phch_recv::run_thread()
} }
break; break;
case CELL_MEASURE: case CELL_MEASURE:
switch(measure_p.run_subframe_sync(&ue_sync, sf_idx)) switch(measure_p.run_subframe_sync(&ue_sync, sf_idx))
{ {
case measure::MEASURE_OK: case measure::MEASURE_OK:
// Calibrate measure object since worker not yet calibrated
if (worker_com->args->rssi_sensor_enabled) {
measure_p.set_rx_gain_offset(measure_p.rssi() - radio_h->get_rssi() + 30);
} else {
measure_p.set_rx_gain_offset(worker_com->args->rx_gain_offset + radio_h->get_rx_gain());
}
log_h->info("SYNC: Measured OK. Camping on cell PCI=%d...\n", cell.id); log_h->info("SYNC: Measured OK. Camping on cell PCI=%d...\n", cell.id);
phy_state = CELL_CAMP; phy_state = CELL_CAMP;
rrc->cell_found(earfcn[cur_earfcn_index], cell, measure_p.rsrp()); rrc->cell_camping(earfcn[cur_earfcn_index], cell, measure_p.rsrp());
break; break;
case measure::IDLE: case measure::IDLE:
break; break;
@ -700,11 +648,9 @@ void phch_recv::run_thread()
metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync); metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync);
metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync); metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync);
worker->set_cfo(ul_dl_factor * metrics.cfo / 15000); worker->set_cfo(get_cfo());
worker_com->set_sync_metrics(metrics); worker_com->set_sync_metrics(metrics);
worker->set_sample_offset(srslte_ue_sync_get_sfo(&ue_sync)/1000);
/* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */ /* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */
srslte_timestamp_t rx_time, tx_time, tx_time_prach; srslte_timestamp_t rx_time, tx_time, tx_time_prach;
srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time); srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time);
@ -718,16 +664,17 @@ void phch_recv::run_thread()
tx_mutex_cnt = (tx_mutex_cnt+1) % nof_tx_mutex; tx_mutex_cnt = (tx_mutex_cnt+1) % nof_tx_mutex;
// Reset Uplink TX buffer to avoid mixing packets in TX queue // Reset Uplink TX buffer to avoid mixing packets in TX queue
/*
if (prach_buffer->is_pending()) { if (prach_buffer->is_pending()) {
Info("SYNC: PRACH pending: Reset UL\n"); Info("SYNC: PRACH pending: Reset UL\n");
worker_com->reset_ul(); radio_h->tx_end();
} }*/
// Check if we need to TX a PRACH // Check if we need to TX a PRACH
if (prach_buffer->is_ready_to_send(tti)) { if (prach_buffer->is_ready_to_send(tti)) {
srslte_timestamp_copy(&tx_time_prach, &rx_time); srslte_timestamp_copy(&tx_time_prach, &rx_time);
srslte_timestamp_add(&tx_time_prach, 0, prach::tx_advance_sf * 1e-3); srslte_timestamp_add(&tx_time_prach, 0, prach::tx_advance_sf * 1e-3);
prach_buffer->send(radio_h, ul_dl_factor * metrics.cfo / 15000, worker_com->pathloss, tx_time_prach); prach_buffer->send(radio_h, get_cfo(), worker_com->pathloss, tx_time_prach);
radio_h->tx_end(); radio_h->tx_end();
worker_com->p0_preamble = prach_buffer->get_p0_preamble(); worker_com->p0_preamble = prach_buffer->get_p0_preamble();
worker_com->cur_radio_power = SRSLTE_MIN(SRSLTE_PC_MAX, worker_com->pathloss+worker_com->p0_preamble); worker_com->cur_radio_power = SRSLTE_MIN(SRSLTE_PC_MAX, worker_com->pathloss+worker_com->p0_preamble);
@ -738,7 +685,9 @@ void phch_recv::run_thread()
if ((tti%5) == 0 && worker_com->args->sic_pss_enabled) { if ((tti%5) == 0 && worker_com->args->sic_pss_enabled) {
srslte_pss_sic(&ue_sync.strack.pss, &buffer[0][SRSLTE_SF_LEN_PRB(cell.nof_prb)/2-ue_sync.strack.fft_size]); srslte_pss_sic(&ue_sync.strack.pss, &buffer[0][SRSLTE_SF_LEN_PRB(cell.nof_prb)/2-ue_sync.strack.fft_size]);
} }
if (srslte_cell_isvalid(&cell)) {
intra_freq_meas.write(tti, buffer[0], SRSLTE_SF_LEN_PRB(cell.nof_prb)); intra_freq_meas.write(tti, buffer[0], SRSLTE_SF_LEN_PRB(cell.nof_prb));
}
break; break;
case 0: case 0:
Warning("SYNC: Out-of-sync detected in PSS/SSS\n"); Warning("SYNC: Out-of-sync detected in PSS/SSS\n");
@ -756,28 +705,18 @@ void phch_recv::run_thread()
} }
break; break;
case IDLE: case IDLE:
if (!is_in_idle) { if (radio_h->is_init()) {
stop_rx(); uint32_t nsamples = 1920;
} if (current_srate > 0) {
is_in_idle = true; nsamples = current_srate/1000;
usleep(1000);
break;
case IDLE_RX:
if (!worker) {
worker = (phch_worker *) workers_pool->wait_worker(tti);
}
is_in_idle_rx = true;
if (worker) {
for (uint32_t i = 0; i < SRSLTE_MAX_PORTS; i++) {
buffer[i] = worker->get_buffer(i);
} }
if (!radio_h->rx_now(buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb), NULL)) { if (!radio_h->rx_now(dummy_buffer, nsamples, NULL)) {
Error("SYNC: Receiving from radio while in IDLE_RX\n"); printf("SYNC: Receiving from radio while in IDLE_RX\n");
} }
} else { } else {
// wait_worker() only returns NULL if it's being closed. Quit now to avoid unnecessary loops here usleep(1000);
running = false;
} }
is_in_idle = true;
break; break;
} }
@ -785,26 +724,34 @@ void phch_recv::run_thread()
mac->tti_clock(tti); mac->tti_clock(tti);
tti = (tti+1) % 10240; tti = (tti+1) % 10240;
} }
for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
if (dummy_buffer[i]) {
free(dummy_buffer[i]);
}
}
} }
void phch_recv::in_sync() { void phch_recv::in_sync() {
out_of_sync_cnt = 0;
in_sync_cnt++; in_sync_cnt++;
// Send RRC in-sync signal after 100 ms consecutive subframes // Send RRC in-sync signal after 100 ms consecutive subframes
if (in_sync_cnt == NOF_IN_SYNC_SF) { if (in_sync_cnt == NOF_IN_SYNC_SF) {
rrc->in_sync(); rrc->in_sync();
in_sync_cnt = 0; in_sync_cnt = 0;
out_of_sync_cnt = 0;
} }
} }
// Out of sync called by worker or phch_recv every 1 or 5 ms // Out of sync called by worker or phch_recv every 1 or 5 ms
void phch_recv::out_of_sync() { void phch_recv::out_of_sync() {
in_sync_cnt = 0;
// Send RRC out-of-sync signal after 200 ms consecutive subframes // Send RRC out-of-sync signal after 200 ms consecutive subframes
Info("Out-of-sync %d/%d\n", out_of_sync_cnt, NOF_OUT_OF_SYNC_SF);
out_of_sync_cnt++; out_of_sync_cnt++;
if (out_of_sync_cnt >= NOF_OUT_OF_SYNC_SF) { if (out_of_sync_cnt >= NOF_OUT_OF_SYNC_SF) {
Info("Sending to RRC\n");
rrc->out_of_sync(); rrc->out_of_sync();
out_of_sync_cnt = 0; out_of_sync_cnt = 0;
in_sync_cnt = 0;
} }
} }
@ -897,8 +844,8 @@ phch_recv::search::ret_code phch_recv::search::run(srslte_cell_t *cell)
if (p->srate_mode != SRATE_FIND) { if (p->srate_mode != SRATE_FIND) {
p->srate_mode = SRATE_FIND; p->srate_mode = SRATE_FIND;
p->radio_h->set_rx_srate(1.92e6); p->radio_h->set_rx_srate(1.92e6);
Info("SYNC: Setting Cell Search sampling rate\n");
} }
p->start_rx();
/* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */ /* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */
uint32_t max_peak_cell = 0; uint32_t max_peak_cell = 0;
@ -918,7 +865,6 @@ phch_recv::search::ret_code phch_recv::search::run(srslte_cell_t *cell)
Error("SYNC: Error decoding MIB: Error searching PSS\n"); Error("SYNC: Error decoding MIB: Error searching PSS\n");
return ERROR; return ERROR;
} else if (ret == 0) { } else if (ret == 0) {
p->stop_rx();
Info("SYNC: Could not find any cell in this frequency\n"); Info("SYNC: Could not find any cell in this frequency\n");
return CELL_NOT_FOUND; return CELL_NOT_FOUND;
} }
@ -946,8 +892,6 @@ phch_recv::search::ret_code phch_recv::search::run(srslte_cell_t *cell)
ret = srslte_ue_mib_sync_decode(&ue_mib_sync, ret = srslte_ue_mib_sync_decode(&ue_mib_sync,
40, 40,
bch_payload, &cell->nof_ports, &sfn_offset); bch_payload, &cell->nof_ports, &sfn_offset);
p->stop_rx();
if (ret == 1) { if (ret == 1) {
srslte_pbch_mib_unpack(bch_payload, cell, NULL); srslte_pbch_mib_unpack(bch_payload, cell, NULL);
@ -1022,7 +966,7 @@ phch_recv::sfn_sync::ret_code phch_recv::sfn_sync::run_subframe(srslte_cell_t *c
srslte_ue_sync_decode_sss_on_track(ue_sync, true); srslte_ue_sync_decode_sss_on_track(ue_sync, true);
int ret = srslte_ue_sync_zerocopy_multi(ue_sync, buffer); int ret = srslte_ue_sync_zerocopy_multi(ue_sync, buffer);
if (ret < 0) { if (ret < 0) {
Error("SYNC: Error calling ue_sync_get_buffer"); Error("SYNC: Error calling ue_sync_get_buffer.\n");
return ERROR; return ERROR;
} }
@ -1080,10 +1024,9 @@ phch_recv::sfn_sync::ret_code phch_recv::sfn_sync::run_subframe(srslte_cell_t *c
/********* /*********
* Measurement class * Measurement class
*/ */
void phch_recv::measure::init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, srslte::radio *radio_h, uint32_t nof_rx_antennas, uint32_t nof_subframes) void phch_recv::measure::init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, uint32_t nof_subframes)
{ {
this->radio_h = radio_h;
this->log_h = log_h; this->log_h = log_h;
this->nof_subframes = nof_subframes; this->nof_subframes = nof_subframes;
for (int i=0;i<SRSLTE_MAX_PORTS;i++) { for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
@ -1094,6 +1037,7 @@ void phch_recv::measure::init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h
Error("SYNC: Initiating ue_dl_measure\n"); Error("SYNC: Initiating ue_dl_measure\n");
return; return;
} }
srslte_chest_dl_set_rsrp_neighbour(&ue_dl.chest, true);
reset(); reset();
} }
@ -1118,16 +1062,20 @@ void phch_recv::measure::set_cell(srslte_cell_t cell)
reset(); reset();
} }
float phch_recv::measure::rssi() {
return 10*log10(mean_rssi);
}
float phch_recv::measure::rsrp() { float phch_recv::measure::rsrp() {
return mean_rsrp; return 10*log10(mean_rsrp) + 30 - rx_gain_offset;
} }
float phch_recv::measure::rsrq() { float phch_recv::measure::rsrq() {
return mean_rsrq; return 10*log10(mean_rsrq);
} }
float phch_recv::measure::snr() { float phch_recv::measure::snr() {
return mean_snr; return 10*log10(mean_snr);
} }
uint32_t phch_recv::measure::frame_st_idx() { uint32_t phch_recv::measure::frame_st_idx() {
@ -1153,7 +1101,7 @@ phch_recv::measure::ret_code phch_recv::measure::run_subframe_sync(srslte_ue_syn
} }
phch_recv::measure::ret_code phch_recv::measure::run_multiple_subframes(cf_t *input_buffer, phch_recv::measure::ret_code phch_recv::measure::run_multiple_subframes(cf_t *input_buffer,
uint32_t offset, int offset,
uint32_t sf_idx, uint32_t sf_idx,
uint32_t max_sf) uint32_t max_sf)
{ {
@ -1162,17 +1110,18 @@ phch_recv::measure::ret_code phch_recv::measure::run_multiple_subframes(cf_t *in
ret_code ret = IDLE; ret_code ret = IDLE;
offset = offset-sf_len/2; offset = offset-sf_len/2;
if (offset < 0) { while (offset < 0 && sf_idx < max_sf) {
offset += sf_len; offset += sf_len;
sf_idx ++; sf_idx ++;
} }
// Fine-tune offset using RS
#ifdef FINE_TUNE_OFFSET_WITH_RS
float max_rsrp = -200; float max_rsrp = -200;
int best_test_offset = 0; int best_test_offset = 0;
int test_offset = 0; int test_offset = 0;
bool found_best = false; bool found_best = false;
// Fine-tune offset using RS
for (uint32_t n=0;n<5;n++) { for (uint32_t n=0;n<5;n++) {
test_offset = offset-2+n; test_offset = offset-2+n;
@ -1196,11 +1145,14 @@ phch_recv::measure::ret_code phch_recv::measure::run_multiple_subframes(cf_t *in
} }
} }
Debug("INTRA: fine-tuning offset: %d, found_best=%d, rem_sf=%d\n", offset, found_best, nof_sf);
offset = found_best?best_test_offset:offset; offset = found_best?best_test_offset:offset;
if (offset >= 0 && offset < sf_len*max_sf) { #endif
if (offset >= 0 && offset < (int) sf_len*max_sf) {
uint32_t nof_sf = (sf_len*max_sf - offset)/sf_len; uint32_t nof_sf = (sf_len*max_sf - offset)/sf_len;
Debug("INTRA: fine-tuning offset: %d, found_best=%d, rem_sf=%d\n", offset, found_best, nof_sf);
final_offset = offset; final_offset = offset;
@ -1228,10 +1180,10 @@ phch_recv::measure::ret_code phch_recv::measure::run_subframe(uint32_t sf_idx)
return ERROR; return ERROR;
} }
float rsrp = 10*log10(srslte_chest_dl_get_rsrp(&ue_dl.chest)) + 30 - rx_gain_offset; float rsrp = srslte_chest_dl_get_rsrp_neighbour(&ue_dl.chest);
float rsrq = 10*log10(srslte_chest_dl_get_rsrq(&ue_dl.chest)); float rsrq = srslte_chest_dl_get_rsrq(&ue_dl.chest);
float snr = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)); float snr = srslte_chest_dl_get_snr(&ue_dl.chest);
float rssi = 10*log10(srslte_vec_avg_power_cf(buffer[0], SRSLTE_SF_LEN_PRB(current_prb))) + 30; float rssi = srslte_vec_avg_power_cf(buffer[0], SRSLTE_SF_LEN_PRB(current_prb));
if (cnt == 0) { if (cnt == 0) {
mean_rsrp = rsrp; mean_rsrp = rsrp;
@ -1246,21 +1198,10 @@ phch_recv::measure::ret_code phch_recv::measure::run_subframe(uint32_t sf_idx)
} }
cnt++; cnt++;
log_h->debug("SYNC: Measuring RSRP %d/%d, sf_idx=%d, RSRP=%.1f dBm, SNR=%.1f dB\n", log_h->debug("SYNC: Measuring RSRP %d/%d, sf_idx=%d, RSRP=%.1f dBm, corr-RSRP=%.1f dBm, SNR=%.1f dB\n",
cnt, nof_subframes, sf_idx, rsrp, snr); cnt, nof_subframes, sf_idx, rsrp, snr);
if (cnt >= nof_subframes) { if (cnt >= nof_subframes) {
// Calibrate RSRP if no gain offset measurements
if (fabsf(rx_gain_offset) < 1.0 && radio_h) {
float temporal_offset = 0;
if (radio_h->has_rssi()) {
temporal_offset = mean_rssi - radio_h->get_rssi() + 30;
} else {
temporal_offset = radio_h->get_rx_gain();
}
mean_rsrp -= temporal_offset;
}
return MEASURE_OK; return MEASURE_OK;
} else { } else {
return IDLE; return IDLE;
@ -1287,15 +1228,15 @@ void phch_recv::scell_recv::init(srslte::log *log_h, bool sic_pss_enabled, uint3
uint32_t max_sf_size = SRSLTE_SF_LEN(max_fft_sz); uint32_t max_sf_size = SRSLTE_SF_LEN(max_fft_sz);
sf_buffer[0] = (cf_t*) srslte_vec_malloc(sizeof(cf_t)*max_sf_size); sf_buffer[0] = (cf_t*) srslte_vec_malloc(sizeof(cf_t)*max_sf_size);
input_cfo_corrected = (cf_t*) srslte_vec_malloc(sizeof(cf_t)*15*max_sf_size);
measure_p.init(sf_buffer, log_h, NULL, 1, max_sf_window); measure_p.init(sf_buffer, log_h, 1, max_sf_window);
//do this different we don't need all this search window. //do this different we don't need all this search window.
if(srslte_sync_init(&sync_find, max_sf_window*max_sf_size, 5*max_sf_size, max_fft_sz)) { if(srslte_sync_init(&sync_find, max_sf_window*max_sf_size, 5*max_sf_size, max_fft_sz)) {
fprintf(stderr, "Error initiating sync_find\n"); fprintf(stderr, "Error initiating sync_find\n");
return; return;
} }
srslte_sync_set_sss_algorithm(&sync_find, SSS_FULL);
srslte_sync_cp_en(&sync_find, false); srslte_sync_cp_en(&sync_find, false);
srslte_sync_set_cfo_pss_enable(&sync_find, true); srslte_sync_set_cfo_pss_enable(&sync_find, true);
srslte_sync_set_threshold(&sync_find, 1.7); srslte_sync_set_threshold(&sync_find, 1.7);
@ -1309,8 +1250,7 @@ void phch_recv::scell_recv::init(srslte::log *log_h, bool sic_pss_enabled, uint3
srslte_sync_set_sss_eq_enable(&sync_find, true); srslte_sync_set_sss_eq_enable(&sync_find, true);
sync_find.pss.chest_on_filter = true; sync_find.pss.chest_on_filter = true;
sync_find.sss_channel_equalize = false;
sync_find.sss_channel_equalize = true;
reset(); reset();
} }
@ -1321,6 +1261,12 @@ void phch_recv::scell_recv::reset()
measure_p.reset(); measure_p.reset();
} }
void phch_recv::scell_recv::deinit()
{
srslte_sync_free(&sync_find);
free(sf_buffer[0]);
}
int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset, srslte_cell_t cell, uint32_t nof_sf, cell_info_t cells[MAX_CELLS]) int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset, srslte_cell_t cell, uint32_t nof_sf, cell_info_t cells[MAX_CELLS])
{ {
uint32_t fft_sz = srslte_symbol_sz(cell.nof_prb); uint32_t fft_sz = srslte_symbol_sz(cell.nof_prb);
@ -1365,7 +1311,7 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset,
for (uint32_t sf5_cnt=0;sf5_cnt<nof_sf/5;sf5_cnt++) { for (uint32_t sf5_cnt=0;sf5_cnt<nof_sf/5;sf5_cnt++) {
sync_res = srslte_sync_find(&sync_find, input_buffer, sf5_cnt*5*sf_len, &peak_idx); sync_res = srslte_sync_find(&sync_find, input_buffer, sf5_cnt*5*sf_len, &peak_idx);
Info("INTRA: n_id_2=%d, cnt=%d/%d, sync_res=%d, sf_idx=%d, peak_idx=%d, peak_value=%f\n", Debug("INTRA: n_id_2=%d, cnt=%d/%d, sync_res=%d, sf_idx=%d, peak_idx=%d, peak_value=%f\n",
n_id_2, sf5_cnt, nof_sf/5, sync_res, srslte_sync_get_sf_idx(&sync_find), peak_idx, sync_find.peak_value); n_id_2, sf5_cnt, nof_sf/5, sync_res, srslte_sync_get_sf_idx(&sync_find), peak_idx, sync_find.peak_value);
if (sync_find.peak_value > max_peak && sync_res == SRSLTE_SYNC_FOUND) { if (sync_find.peak_value > max_peak && sync_res == SRSLTE_SYNC_FOUND) {
@ -1395,28 +1341,21 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset,
found_cell.nof_ports = 1; // Use port 0 only for measurement found_cell.nof_ports = 1; // Use port 0 only for measurement
measure_p.set_cell(found_cell); measure_p.set_cell(found_cell);
// Correct CFO
/*
srslte_cfo_correct(&sync_find.cfo_corr_frame,
input_buffer,
input_cfo_corrected,
-srslte_sync_get_cfo(&sync_find)/sync_find.fft_size);
*/
switch(measure_p.run_multiple_subframes(input_buffer, peak_idx, sf_idx, nof_sf)) switch(measure_p.run_multiple_subframes(input_buffer, peak_idx, sf_idx, nof_sf))
{ {
case measure::MEASURE_OK: case measure::MEASURE_OK:
// Consider a cell to be detectable 8.1.2.2.1.1 from 36.133. Currently only using first condition // Consider a cell to be detectable 8.1.2.2.1.1 from 36.133. Currently only using first condition
if (measure_p.rsrp() > ABSOLUTE_RSRP_THRESHOLD_DBM) { if (measure_p.rsrp() > ABSOLUTE_RSRP_THRESHOLD_DBM) {
cells[nof_cells].pci = found_cell.id; cells[nof_cells].pci = found_cell.id;
cells[nof_cells].rsrp = measure_p.rsrp(); cells[nof_cells].rsrp = measure_p.rsrp();
cells[nof_cells].rsrq = measure_p.rsrq(); cells[nof_cells].rsrq = measure_p.rsrq();
cells[nof_cells].offset = measure_p.frame_st_idx(); cells[nof_cells].offset = measure_p.frame_st_idx();
Info( Info(
"INTRA: Found neighbour cell %d: PCI=%03d, RSRP=%5.1f dBm, peak_idx=%5d, peak_value=%3.2f, sf=%d, max_sf=%d, n_id_2=%d, CFO=%6.1f Hz\n", "INTRA: Found neighbour cell %d: PCI=%03d, RSRP=%5.1f dBm, peak_idx=%5d, peak_value=%3.2f, sf=%d, nof_sf=%d, n_id_2=%d, CFO=%6.1f Hz\n",
nof_cells, cell_id, measure_p.rsrp(), measure_p.frame_st_idx(), sync_find.peak_value, nof_cells, cell_id, measure_p.rsrp(), measure_p.frame_st_idx(), sync_find.peak_value,
sf_idx, max_sf5, n_id_2, 15000 * srslte_sync_get_cfo(&sync_find)); sf_idx, nof_sf, n_id_2, 15000 * srslte_sync_get_cfo(&sync_find));
nof_cells++; nof_cells++;
@ -1516,6 +1455,12 @@ void phch_recv::intra_measure::stop() {
wait_thread_finish(); wait_thread_finish();
} }
phch_recv::intra_measure::~intra_measure() {
srslte_ringbuffer_free(&ring_buffer);
scell.deinit();
free(search_buffer);
}
void phch_recv::intra_measure::set_primay_cell(uint32_t earfcn, srslte_cell_t cell) { void phch_recv::intra_measure::set_primay_cell(uint32_t earfcn, srslte_cell_t cell) {
this->current_earfcn = earfcn; this->current_earfcn = earfcn;
current_sflen = SRSLTE_SF_LEN_PRB(cell.nof_prb); current_sflen = SRSLTE_SF_LEN_PRB(cell.nof_prb);
@ -1594,6 +1539,7 @@ void phch_recv::intra_measure::run_thread()
} }
if (running) { if (running) {
// Read data from buffer and find cells in it // Read data from buffer and find cells in it
srslte_ringbuffer_read(&ring_buffer, search_buffer, INTRA_FREQ_MEAS_LEN_MS*current_sflen*sizeof(cf_t)); srslte_ringbuffer_read(&ring_buffer, search_buffer, INTRA_FREQ_MEAS_LEN_MS*current_sflen*sizeof(cf_t));
int found_cells = scell.find_cells(search_buffer, common->rx_gain_offset, primary_cell, INTRA_FREQ_MEAS_LEN_MS, info); int found_cells = scell.find_cells(search_buffer, common->rx_gain_offset, primary_cell, INTRA_FREQ_MEAS_LEN_MS, info);

@ -137,32 +137,39 @@ bool phch_worker::init(uint32_t max_prb, srslte::log *log_h, srslte::log *log_ph
srslte_chest_dl_cfo_estimate_enable(&ue_dl.chest, phy->args->cfo_ref_mask!=0, phy->args->cfo_ref_mask); srslte_chest_dl_cfo_estimate_enable(&ue_dl.chest, phy->args->cfo_ref_mask!=0, phy->args->cfo_ref_mask);
srslte_ue_ul_set_normalization(&ue_ul, true); srslte_ue_ul_set_normalization(&ue_ul, true);
srslte_ue_ul_set_cfo_enable(&ue_ul, true); srslte_ue_ul_set_cfo_enable(&ue_ul, true);
srslte_pdsch_enable_csi(&ue_dl.pdsch, phy->args->pdsch_csi_enabled);
mem_initiated = true; mem_initiated = true;
pthread_mutex_init(&mutex, NULL);
return true; return true;
} }
bool phch_worker::set_cell(srslte_cell_t cell_) bool phch_worker::set_cell(srslte_cell_t cell_)
{ {
bool ret = false;
pthread_mutex_lock(&mutex);
if (cell.id != cell_.id || !cell_initiated) { if (cell.id != cell_.id || !cell_initiated) {
memcpy(&cell, &cell_, sizeof(srslte_cell_t)); memcpy(&cell, &cell_, sizeof(srslte_cell_t));
if (srslte_ue_dl_set_cell(&ue_dl, cell)) { if (srslte_ue_dl_set_cell(&ue_dl, cell)) {
Error("Initiating UE DL\n"); Error("Initiating UE DL\n");
return false; goto unlock;
} }
if (srslte_ue_ul_set_cell(&ue_ul, cell)) { if (srslte_ue_ul_set_cell(&ue_ul, cell)) {
Error("Initiating UE UL\n"); Error("Initiating UE UL\n");
return false; goto unlock;
} }
srslte_ue_ul_set_normalization(&ue_ul, true); srslte_ue_ul_set_normalization(&ue_ul, true);
srslte_ue_ul_set_cfo_enable(&ue_ul, true); srslte_ue_ul_set_cfo_enable(&ue_ul, true);
cell_initiated = true; cell_initiated = true;
} }
return true; ret = true;
unlock:
pthread_mutex_unlock(&mutex);
return ret;
} }
cf_t* phch_worker::get_buffer(uint32_t antenna_idx) cf_t* phch_worker::get_buffer(uint32_t antenna_idx)
@ -183,14 +190,6 @@ void phch_worker::set_cfo(float cfo_)
cfo = cfo_; cfo = cfo_;
} }
void phch_worker::set_sample_offset(float sample_offset)
{
if (phy->args->sfo_correct_disable) {
sample_offset = 0;
}
srslte_ue_dl_set_sample_offset(&ue_dl, sample_offset);
}
void phch_worker::set_crnti(uint16_t rnti) void phch_worker::set_crnti(uint16_t rnti)
{ {
srslte_ue_dl_set_rnti(&ue_dl, rnti); srslte_ue_dl_set_rnti(&ue_dl, rnti);
@ -224,26 +223,14 @@ float phch_worker::get_cfo()
return cfo; return cfo;
} }
float phch_worker::get_ul_cfo() {
srslte::radio *radio = phy->get_radio();
if (radio->get_freq_offset() != 0.0f) {
/* Compensates the radio frequency offset applied equally to DL and UL */
const float ul_dl_ratio = (float) radio->get_tx_freq() / (float) radio->get_rx_freq();
const float offset_hz = (float) radio->get_freq_offset() * (1.0f - ul_dl_ratio);
return cfo - offset_hz / (15000);
} else {
return cfo;
}
}
void phch_worker::work_imp() void phch_worker::work_imp()
{ {
if (!cell_initiated) { if (!cell_initiated) {
return; return;
} }
pthread_mutex_lock(&mutex);
Debug("TTI %d running\n", tti); Debug("TTI %d running\n", tti);
#ifdef LOG_EXECTIME #ifdef LOG_EXECTIME
@ -359,7 +346,7 @@ void phch_worker::work_imp()
} }
/* Set UL CFO before transmission */ /* Set UL CFO before transmission */
srslte_ue_ul_set_cfo(&ue_ul, get_ul_cfo()); srslte_ue_ul_set_cfo(&ue_ul, cfo);
/* Transmit PUSCH, PUCCH or SRS */ /* Transmit PUSCH, PUCCH or SRS */
bool signal_ready = false; bool signal_ready = false;
@ -389,7 +376,9 @@ void phch_worker::work_imp()
if (!dl_action.generate_ack_callback) { if (!dl_action.generate_ack_callback) {
if (dl_mac_grant.rnti_type == SRSLTE_RNTI_PCH && dl_action.decode_enabled[0]) { if (dl_mac_grant.rnti_type == SRSLTE_RNTI_PCH && dl_action.decode_enabled[0]) {
if (dl_ack[0]) {
phy->mac->pch_decoded_ok(dl_mac_grant.n_bytes[0]); phy->mac->pch_decoded_ok(dl_mac_grant.n_bytes[0]);
}
} else if (!rar_delivered) { } else if (!rar_delivered) {
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
if (dl_action.decode_enabled[tb]) { if (dl_action.decode_enabled[tb]) {
@ -402,17 +391,19 @@ void phch_worker::work_imp()
update_measurements(); update_measurements();
if (chest_ok) { if (chest_ok) {
if (phy->avg_rsrp_dbm > -130.0 && phy->avg_snr_db > -30.0) { if (phy->avg_rsrp_dbm > -130.0 && phy->avg_snr_db > -10.0) {
log_h->debug("SNR=%.1f dB, RSRP=%.1f dBm sync=in-sync from channel estimator\n", log_h->debug("SNR=%.1f dB, RSRP=%.1f dBm sync=in-sync from channel estimator\n",
10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)), phy->avg_rsrp_dbm); phy->avg_snr_db, phy->avg_rsrp_dbm);
chest_loop->in_sync(); chest_loop->in_sync();
} else { } else {
log_h->warning("SNR=%.1f dB RSRP=%.1f dBm, sync=out-of-sync from channel estimator\n", log_h->warning("SNR=%.1f dB RSRP=%.1f dBm, sync=out-of-sync from channel estimator\n",
10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)), phy->avg_rsrp_dbm); phy->avg_snr_db, phy->avg_rsrp_dbm);
chest_loop->out_of_sync(); chest_loop->out_of_sync();
} }
} }
pthread_mutex_unlock(&mutex);
/* Tell the plotting thread to draw the plots */ /* Tell the plotting thread to draw the plots */
#ifdef ENABLE_GUI #ifdef ENABLE_GUI
if ((int) get_id() == plot_worker_id) { if ((int) get_id() == plot_worker_id) {
@ -510,10 +501,17 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant)
srslte_dci_msg_t dci_msg; srslte_dci_msg_t dci_msg;
srslte_ra_dl_dci_t dci_unpacked; srslte_ra_dl_dci_t dci_unpacked;
Debug("Looking for RNTI=0x%x\n", dl_rnti); if (type == SRSLTE_RNTI_RAR) {
Info("Looking for RNTI=0x%x\n", dl_rnti);
}
if (srslte_ue_dl_find_dl_dci_type(&ue_dl, phy->config->dedicated.antenna_info_explicit_value.tx_mode, cfi, tti%10, if (srslte_ue_dl_find_dl_dci_type(&ue_dl, phy->config->dedicated.antenna_info_explicit_value.tx_mode, cfi, tti%10,
dl_rnti, type, &dci_msg) != 1) { dl_rnti, type, &dci_msg) != 1) {
if (type == SRSLTE_RNTI_RAR) {
Info("RAR not found, SNR=%.1f dB, tti=%d, cfi=%d, tx_mode=%d, cell_id=%d\n",
10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)), tti, cfi,
phy->config->dedicated.antenna_info_explicit_value.tx_mode, cell.id);
}
return false; return false;
} }
@ -554,10 +552,10 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant)
last_dl_pdcch_ncce = srslte_ue_dl_get_ncce(&ue_dl); last_dl_pdcch_ncce = srslte_ue_dl_get_ncce(&ue_dl);
char hexstr[16]; char hexstr[512];
hexstr[0]='\0'; hexstr[0]='\0';
if (log_h->get_level() >= srslte::LOG_LEVEL_INFO) { if (log_h->get_level() >= srslte::LOG_LEVEL_INFO) {
srslte_vec_sprint_hex(hexstr, dci_msg.data, dci_msg.nof_bits); srslte_vec_sprint_hex(hexstr, sizeof(hexstr), dci_msg.data, dci_msg.nof_bits);
} }
Info("PDCCH: DL DCI %s cce_index=%2d, L=%d, n_data_bits=%d, hex=%s\n", srslte_dci_format_string(dci_msg.format), Info("PDCCH: DL DCI %s cce_index=%2d, L=%d, n_data_bits=%d, hex=%s\n", srslte_dci_format_string(dci_msg.format),
last_dl_pdcch_ncce, (1<<ue_dl.last_location.L), dci_msg.nof_bits, hexstr); last_dl_pdcch_ncce, (1<<ue_dl.last_location.L), dci_msg.nof_bits, hexstr);
@ -792,10 +790,10 @@ bool phch_worker::decode_pdcch_ul(mac_interface_phy::mac_grant_t* grant)
grant->has_cqi_request = dci_unpacked.cqi_request; grant->has_cqi_request = dci_unpacked.cqi_request;
ret = true; ret = true;
char hexstr[16]; char hexstr[512];
hexstr[0]='\0'; hexstr[0]='\0';
if (log_h->get_level() >= srslte::LOG_LEVEL_INFO) { if (log_h->get_level() >= srslte::LOG_LEVEL_INFO) {
srslte_vec_sprint_hex(hexstr, dci_msg.data, dci_msg.nof_bits); srslte_vec_sprint_hex(hexstr, sizeof(hexstr), dci_msg.data, dci_msg.nof_bits);
} }
// Change to last_location_ul // Change to last_location_ul
Info("PDCCH: UL DCI Format0 cce_index=%d, L=%d, n_data_bits=%d, hex=%s\n", Info("PDCCH: UL DCI Format0 cce_index=%d, L=%d, n_data_bits=%d, hex=%s\n",
@ -1211,6 +1209,7 @@ void phch_worker::enable_pregen_signals(bool enabled)
void phch_worker::set_ul_params(bool pregen_disabled) void phch_worker::set_ul_params(bool pregen_disabled)
{ {
phy_interface_rrc::phy_cfg_common_t *common = &phy->config->common; phy_interface_rrc::phy_cfg_common_t *common = &phy->config->common;
LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *dedicated = &phy->config->dedicated; LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *dedicated = &phy->config->dedicated;
@ -1380,7 +1379,7 @@ void phch_worker::update_measurements()
/* Only worker 0 reads the RSSI sensor every ~1-nof_cores s */ /* Only worker 0 reads the RSSI sensor every ~1-nof_cores s */
if (get_id() == 0) { if (get_id() == 0) {
if (rssi_read_cnt) { if (!rssi_read_cnt) {
if (phy->get_radio()->has_rssi() && phy->args->rssi_sensor_enabled) { if (phy->get_radio()->has_rssi() && phy->args->rssi_sensor_enabled) {
phy->last_radio_rssi = phy->get_radio()->get_rssi(); phy->last_radio_rssi = phy->get_radio()->get_rssi();
phy->rx_gain_offset = phy->avg_rssi_dbm - phy->last_radio_rssi + 30; phy->rx_gain_offset = phy->avg_rssi_dbm - phy->last_radio_rssi + 30;

@ -97,7 +97,6 @@ void phy::set_default_args(phy_args_t *args)
args->cfo_integer_enabled = false; args->cfo_integer_enabled = false;
args->cfo_correct_tol_hz = 50; args->cfo_correct_tol_hz = 50;
args->time_correct_period = 5; args->time_correct_period = 5;
args->sfo_correct_disable = false;
args->sss_algorithm = "full"; args->sss_algorithm = "full";
args->estimator_fil_w = 0.1; args->estimator_fil_w = 0.1;
} }
@ -120,7 +119,7 @@ bool phy::check_args(phy_args_t *args)
} }
bool phy::init(srslte::radio_multi* radio_handler, mac_interface_phy *mac, rrc_interface_phy *rrc, bool phy::init(srslte::radio_multi* radio_handler, mac_interface_phy *mac, rrc_interface_phy *rrc,
std::vector<srslte::log*> log_vec, phy_args_t *phy_args) { std::vector<srslte::log_filter*> log_vec, phy_args_t *phy_args) {
mlockall(MCL_CURRENT | MCL_FUTURE); mlockall(MCL_CURRENT | MCL_FUTURE);
@ -256,11 +255,6 @@ void phy::cell_search_start()
sf_recv.cell_search_start(); sf_recv.cell_search_start();
} }
void phy::cell_search_stop()
{
sf_recv.cell_search_stop();
}
void phy::cell_search_next() void phy::cell_search_next()
{ {
sf_recv.cell_search_next(); sf_recv.cell_search_next();
@ -282,9 +276,9 @@ int phy::meas_stop(uint32_t earfcn, int pci) {
return sf_recv.meas_stop(earfcn, pci); return sf_recv.meas_stop(earfcn, pci);
} }
bool phy::cell_select(uint32_t earfcn, srslte_cell_t phy_cell) void phy::cell_select(uint32_t earfcn, srslte_cell_t phy_cell)
{ {
return sf_recv.cell_select(earfcn, phy_cell); sf_recv.cell_select(earfcn, phy_cell);
} }
bool phy::cell_handover(srslte_cell_t cell) { bool phy::cell_handover(srslte_cell_t cell) {
@ -366,8 +360,6 @@ void phy::reset()
workers[i].reset(); workers[i].reset();
} }
workers_common.reset(); workers_common.reset();
usleep(4000);
workers_common.reset_ul();
} }
uint32_t phy::get_current_tti() uint32_t phy::get_current_tti()

@ -40,12 +40,13 @@ namespace srsue{
ue::ue() ue::ue()
:started(false) :started(false)
{ {
pool = byte_buffer_pool::get_instance();
} }
ue::~ue() ue::~ue()
{ {
byte_buffer_pool::cleanup(); for (uint32_t i = 0; i < phy_log.size(); i++) {
delete(phy_log[i]);
}
} }
bool ue::init(all_args_t *args_) bool ue::init(all_args_t *args_)
@ -192,7 +193,8 @@ bool ue::init(all_args_t *args_)
pdcp.init(&rlc, &rrc, &gw, &pdcp_log, 0 /* RB_ID_SRB0 */, SECURITY_DIRECTION_UPLINK); pdcp.init(&rlc, &rrc, &gw, &pdcp_log, 0 /* RB_ID_SRB0 */, SECURITY_DIRECTION_UPLINK);
usim.init(&args->usim, &usim_log); usim.init(&args->usim, &usim_log);
nas.init(&usim, &rrc, &gw, &nas_log, 1 /* RB_ID_SRB1 */); srslte_nas_config_t nas_cfg(1, args->apn); /* RB_ID_SRB1 */
nas.init(&usim, &rrc, &gw, &nas_log, nas_cfg);
gw.init(&pdcp, &nas, &gw_log, 3 /* RB_ID_DRB1 */); gw.init(&pdcp, &nas, &gw_log, 3 /* RB_ID_DRB1 */);
gw.set_netmask(args->expert.ip_netmask); gw.set_netmask(args->expert.ip_netmask);
@ -273,13 +275,17 @@ void ue::stop()
bool ue::is_attached() bool ue::is_attached()
{ {
return (RRC_STATE_CONNECTED == rrc.get_state()); return rrc.is_connected();
} }
void ue::start_plot() { void ue::start_plot() {
phy.start_plot(); phy.start_plot();
} }
void ue::print_pool() {
byte_buffer_pool::get_instance()->print_all_buffers();
}
bool ue::get_metrics(ue_metrics_t &m) bool ue::get_metrics(ue_metrics_t &m)
{ {
m.rf = rf_metrics; m.rf = rf_metrics;
@ -308,6 +314,11 @@ void ue::rf_msg(srslte_rf_error_t error)
ue->handle_rf_msg(error); ue->handle_rf_msg(error);
if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OVERFLOW) { if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OVERFLOW) {
ue->radio_overflow(); ue->radio_overflow();
} else
if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_RX) {
ue->stop();
ue->cleanup();
exit(-1);
} }
} }

@ -64,6 +64,12 @@ ue_base::ue_base() {
// load FFTW wisdom // load FFTW wisdom
srslte_dft_load(); srslte_dft_load();
pool = byte_buffer_pool::get_instance();
}
ue_base::~ue_base() {
byte_buffer_pool::cleanup();
} }
void ue_base::cleanup(void) void ue_base::cleanup(void)

@ -243,6 +243,10 @@ void gw::run_thread()
uint32 idx = 0; uint32 idx = 0;
int32 N_bytes; int32 N_bytes;
srslte::byte_buffer_t *pdu = pool_allocate; srslte::byte_buffer_t *pdu = pool_allocate;
if (!pdu) {
gw_log->error("Fatal Error: Couldn't allocate PDU in run_thread().\n");
return;
}
const static uint32_t ATTACH_TIMEOUT_MS = 10000; const static uint32_t ATTACH_TIMEOUT_MS = 10000;
const static uint32_t ATTACH_MAX_ATTEMPTS = 3; const static uint32_t ATTACH_MAX_ATTEMPTS = 3;
@ -307,7 +311,7 @@ void gw::run_thread()
do { do {
pdu = pool_allocate; pdu = pool_allocate;
if (!pdu) { if (!pdu) {
printf("Not enough buffers in pool\n"); gw_log->error("Fatal Error: Couldn't allocate PDU in run_thread().\n");
usleep(100000); usleep(100000);
} }
} while(!pdu); } while(!pdu);

@ -107,8 +107,8 @@ void nas::attach_request() {
selecting_plmn = current_plmn; selecting_plmn = current_plmn;
} }
} else if (state == EMM_STATE_REGISTERED) { } else if (state == EMM_STATE_REGISTERED) {
nas_log->info("NAS state is registered, connecting to same PLMN\n"); nas_log->info("NAS state is registered, selecting current PLMN\n");
rrc->plmn_select(current_plmn); rrc->plmn_select(current_plmn, true);
} else { } else {
nas_log->info("Attach request ignored. State = %s\n", emm_state_text[state]); nas_log->info("Attach request ignored. State = %s\n", emm_state_text[state]);
} }
@ -123,12 +123,7 @@ void nas::deattach_request() {
* RRC interface * RRC interface
******************************************************************************/ ******************************************************************************/
void nas::plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) { bool nas::plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) {
// Do not process new PLMN if already selected
if (plmn_selection == PLMN_SELECTED) {
return;
}
// Check if already registered // Check if already registered
for (uint32_t i=0;i<known_plmns.size();i++) { for (uint32_t i=0;i<known_plmns.size();i++) {
@ -136,10 +131,11 @@ void nas::plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_
nas_log->info("Found known PLMN Id=%s\n", plmn_id_to_string(plmn_id).c_str()); nas_log->info("Found known PLMN Id=%s\n", plmn_id_to_string(plmn_id).c_str());
if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) { if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) {
nas_log->info("Connecting Home PLMN Id=%s\n", plmn_id_to_string(plmn_id).c_str()); nas_log->info("Connecting Home PLMN Id=%s\n", plmn_id_to_string(plmn_id).c_str());
rrc->plmn_select(plmn_id); rrc->plmn_select(plmn_id, state == EMM_STATE_REGISTERED_INITIATED);
selecting_plmn = plmn_id; selecting_plmn = plmn_id;
return true;
} }
return; return false;
} }
} }
@ -152,15 +148,17 @@ void nas::plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_
tracking_area_code); tracking_area_code);
if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) { if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) {
rrc->plmn_select(plmn_id); rrc->plmn_select(plmn_id, state == EMM_STATE_REGISTERED_INITIATED);
selecting_plmn = plmn_id; selecting_plmn = plmn_id;
return true;
} }
return false;
} }
// RRC indicates that the UE has gone through all EARFCN and finished PLMN selection // RRC indicates that the UE has gone through all EARFCN and finished PLMN selection
void nas::plmn_search_end() { void nas::plmn_search_end() {
if (known_plmns.size() > 0) { if (known_plmns.size() > 0) {
if (home_plmn.mcc != known_plmns[0].mcc && home_plmn.mnc != known_plmns[0].mnc) {
nas_log->info("Could not find Home PLMN Id=%s, trying to connect to PLMN Id=%s\n", nas_log->info("Could not find Home PLMN Id=%s, trying to connect to PLMN Id=%s\n",
plmn_id_to_string(home_plmn).c_str(), plmn_id_to_string(home_plmn).c_str(),
plmn_id_to_string(known_plmns[0]).c_str()); plmn_id_to_string(known_plmns[0]).c_str());
@ -168,10 +166,13 @@ void nas::plmn_search_end() {
nas_log->console("Could not find Home PLMN Id=%s, trying to connect to PLMN Id=%s\n", nas_log->console("Could not find Home PLMN Id=%s, trying to connect to PLMN Id=%s\n",
plmn_id_to_string(home_plmn).c_str(), plmn_id_to_string(home_plmn).c_str(),
plmn_id_to_string(known_plmns[0]).c_str()); plmn_id_to_string(known_plmns[0]).c_str());
}
rrc->plmn_select(known_plmns[0]); rrc->plmn_select(known_plmns[0], state == EMM_STATE_REGISTERED_INITIATED);
} else { } else {
nas_log->debug("Finished searching PLMN in current EARFCN set but no networks were found.\n"); nas_log->info("Finished searching PLMN in current EARFCN set but no networks were found.\n");
if (state == EMM_STATE_REGISTERED_INITIATED && plmn_selection == PLMN_NOT_SELECTED) {
rrc->plmn_search();
}
} }
} }
@ -218,7 +219,7 @@ void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu) {
default: default:
nas_log->error("Not handling NAS message with SEC_HDR_TYPE=%02X\n", sec_hdr_type); nas_log->error("Not handling NAS message with SEC_HDR_TYPE=%02X\n", sec_hdr_type);
pool->deallocate(pdu); pool->deallocate(pdu);
break; return;
} }
// Write NAS pcap // Write NAS pcap
@ -262,7 +263,7 @@ void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu) {
default: default:
nas_log->error("Not handling NAS message with MSG_TYPE=%02X\n", msg_type); nas_log->error("Not handling NAS message with MSG_TYPE=%02X\n", msg_type);
pool->deallocate(pdu); pool->deallocate(pdu);
break; return;
} }
} }
@ -534,6 +535,7 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
state = EMM_STATE_REGISTERED; state = EMM_STATE_REGISTERED;
current_plmn = selecting_plmn; current_plmn = selecting_plmn;
plmn_selection = PLMN_SELECTED;
ctxt.rx_count++; ctxt.rx_count++;
@ -543,6 +545,8 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
act_def_eps_bearer_context_accept.protocol_cnfg_opts_present = false; act_def_eps_bearer_context_accept.protocol_cnfg_opts_present = false;
liblte_mme_pack_activate_default_eps_bearer_context_accept_msg(&act_def_eps_bearer_context_accept, liblte_mme_pack_activate_default_eps_bearer_context_accept_msg(&act_def_eps_bearer_context_accept,
&attach_complete.esm_msg); &attach_complete.esm_msg);
pdu->reset();
liblte_mme_pack_attach_complete_msg(&attach_complete, liblte_mme_pack_attach_complete_msg(&attach_complete,
LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED,
ctxt.tx_count, ctxt.tx_count,
@ -758,36 +762,36 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu)
} }
// Send response // Send response
byte_buffer_t *sdu = pool_allocate; pdu->reset();
liblte_mme_pack_security_mode_complete_msg(&sec_mode_comp, liblte_mme_pack_security_mode_complete_msg(&sec_mode_comp,
LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT, LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT,
ctxt.tx_count, ctxt.tx_count,
(LIBLTE_BYTE_MSG_STRUCT *) sdu); (LIBLTE_BYTE_MSG_STRUCT *) pdu);
if(pcap != NULL) { if(pcap != NULL) {
pcap->write_nas(sdu->msg, sdu->N_bytes); pcap->write_nas(pdu->msg, pdu->N_bytes);
} }
cipher_encrypt(sdu); cipher_encrypt(pdu);
integrity_generate(&k_nas_int[16], integrity_generate(&k_nas_int[16],
ctxt.tx_count, ctxt.tx_count,
SECURITY_DIRECTION_UPLINK, SECURITY_DIRECTION_UPLINK,
&sdu->msg[5], &pdu->msg[5],
sdu->N_bytes - 5, pdu->N_bytes - 5,
&sdu->msg[1]); &pdu->msg[1]);
nas_log->info("Sending Security Mode Complete nas_current_ctxt.tx_count=%d, RB=%s\n", nas_log->info("Sending Security Mode Complete nas_current_ctxt.tx_count=%d, RB=%s\n",
ctxt.tx_count, ctxt.tx_count,
rrc->get_rb_name(lcid).c_str()); rrc->get_rb_name(lcid).c_str());
rrc->write_sdu(lcid, sdu); rrc->write_sdu(lcid, pdu);
ctxt.tx_count++; ctxt.tx_count++;
pool->deallocate(pdu);
} }
void nas::parse_service_reject(uint32_t lcid, byte_buffer_t *pdu) { void nas::parse_service_reject(uint32_t lcid, byte_buffer_t *pdu) {
nas_log->error("TODO:parse_service_reject\n"); nas_log->error("TODO:parse_service_reject\n");
pool->deallocate(pdu);
} }
void nas::parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu) { void nas::parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu) {
nas_log->error("TODO:parse_esm_information_request\n"); nas_log->error("TODO:parse_esm_information_request\n");
pool->deallocate(pdu);
} }
void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) { void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) {
@ -796,6 +800,7 @@ void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) {
nas_log->info("Received EMM Information: %s\n", str.c_str()); nas_log->info("Received EMM Information: %s\n", str.c_str());
nas_log->console("%s\n", str.c_str()); nas_log->console("%s\n", str.c_str());
ctxt.rx_count++; ctxt.rx_count++;
pool->deallocate(pdu);
} }
/******************************************************************************* /*******************************************************************************
@ -805,6 +810,11 @@ void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) {
void nas::send_attach_request() { void nas::send_attach_request() {
LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT attach_req; LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT attach_req;
byte_buffer_t *msg = pool_allocate; byte_buffer_t *msg = pool_allocate;
if (!msg) {
nas_log->error("Fatal Error: Couldn't allocate PDU in send_attach_request().\n");
return;
}
u_int32_t i; u_int32_t i;
attach_req.eps_attach_type = LIBLTE_MME_EPS_ATTACH_TYPE_EPS_ATTACH; attach_req.eps_attach_type = LIBLTE_MME_EPS_ATTACH_TYPE_EPS_ATTACH;
@ -889,7 +899,14 @@ void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) {
// Set the optional flags // Set the optional flags
pdn_con_req.esm_info_transfer_flag_present = false; //FIXME: Check if this is needed pdn_con_req.esm_info_transfer_flag_present = false; //FIXME: Check if this is needed
if (cfg.apn == "") {
pdn_con_req.apn_present = false; pdn_con_req.apn_present = false;
} else {
pdn_con_req.apn_present = true;
LIBLTE_MME_ACCESS_POINT_NAME_STRUCT apn;
apn.apn = cfg.apn;
pdn_con_req.apn = apn;
}
pdn_con_req.protocol_cnfg_opts_present = false; pdn_con_req.protocol_cnfg_opts_present = false;
pdn_con_req.device_properties_present = false; pdn_con_req.device_properties_present = false;
@ -899,6 +916,10 @@ void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) {
void nas::send_security_mode_reject(uint8_t cause) { void nas::send_security_mode_reject(uint8_t cause) {
byte_buffer_t *msg = pool_allocate; byte_buffer_t *msg = pool_allocate;
if (!msg) {
nas_log->error("Fatal Error: Couldn't allocate PDU in send_security_mode_reject().\n");
return;
}
LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT sec_mode_rej; LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT sec_mode_rej;
sec_mode_rej.emm_cause = cause; sec_mode_rej.emm_cause = cause;
@ -914,6 +935,10 @@ void nas::send_identity_response() {}
void nas::send_service_request() { void nas::send_service_request() {
byte_buffer_t *msg = pool_allocate; byte_buffer_t *msg = pool_allocate;
if (!msg) {
nas_log->error("Fatal Error: Couldn't allocate PDU in send_service_request().\n");
return;
}
// Pack the service request message directly // Pack the service request message directly
msg->msg[0] = (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg->msg[0] = (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save