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(RPATH "Enable RPATH" OFF)
option(ENABLE_ASAN "Enable gcc address sanitizer" 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")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -DDEBUG_MODE")
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")
endif(${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo")
endif(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
if (USE_LTE_RATES)
message(STATUS "Using standard LTE sampling rates")
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)
ADD_CXX_COMPILER_FLAG_IF_AVAILABLE(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN)
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")
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")

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

@ -30,6 +30,8 @@
#include <pthread.h>
#include <vector>
#include <stack>
#include <map>
#include <string>
#include <algorithm>
/*******************************************************************************
@ -70,14 +72,23 @@ public:
delete available.top();
available.pop();
}
for (uint32_t i = 0; i < used.size(); i++) {
delete used[i];
}
}
void print_all_buffers()
{
printf("%d buffers in queue\n", (int) used.size());
#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED
std::map<std::string, uint32_t> buffer_cnt;
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
}
@ -166,6 +177,9 @@ public:
pool->deallocate(b);
b = NULL;
}
void print_all_buffers() {
pool->print_all_buffers();
}
private:
buffer_pool<byte_buffer_t> *pool;
};

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

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

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

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

@ -84,7 +84,6 @@ public:
}
void thread_func()
{
// substract time elapsed until now from timer duration
gettimeofday(&start_time[2], NULL);
get_time_interval(start_time);
@ -105,6 +104,14 @@ public:
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()
{
return running;

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

@ -119,7 +119,7 @@ public:
virtual uint32_t get_ul_count() = 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 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;
};
@ -160,7 +160,7 @@ public:
virtual void in_sync() = 0;
virtual void out_of_sync() = 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;
};
@ -173,7 +173,7 @@ public:
virtual uint16_t get_mnc() = 0;
virtual void enable_capabilities() = 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;
};
@ -475,6 +475,7 @@ typedef struct {
int cqi_fixed;
float snr_ema_coeff;
std::string snr_estim_alg;
bool cfo_is_doppler;
bool cfo_integer_enabled;
float cfo_correct_tol_hz;
float cfo_pss_ema;
@ -487,12 +488,12 @@ typedef struct {
uint32_t cfo_ref_mask;
bool average_subframe_enabled;
int time_correct_period;
bool sfo_correct_disable;
std::string sss_algorithm;
float estimator_fil_w;
bool rssi_sensor_enabled;
bool sic_pss_enabled;
float rx_gain_offset;
bool pdsch_csi_enabled;
} phy_args_t;
@ -580,9 +581,8 @@ public:
/* Cell search and selection procedures */
virtual void cell_search_start() = 0;
virtual void cell_search_stop() = 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;
/* Is the PHY downlink synchronized? */

@ -83,9 +83,12 @@ typedef struct {
srslte_interp_lin_t srslte_interp_lin_mbsfn;
float rssi[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 cfo;
bool rsrp_neighbour;
bool cfo_estimate_enable;
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,
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_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_neighbour(srslte_chest_dl_t *q);
#endif

@ -42,6 +42,9 @@
typedef struct SRSLTE_API {
uint32_t max_cb;
int16_t **buffer_f;
uint8_t **data;
bool *cb_crc;
bool tb_crc;
} srslte_softbuffer_rx_t;
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,
cf_t *h,
cf_t *x,
float *csi,
int nof_symbols,
float scaling,
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],
cf_t *h[SRSLTE_MAX_PORTS],
cf_t *x,
float *csi,
int nof_rxant,
int nof_symbols,
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],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS],
float *csi,
int nof_rxant,
int nof_ports,
int nof_layers,

@ -76,6 +76,9 @@ typedef struct SRSLTE_API {
cf_t *d[SRSLTE_MAX_CODEWORDS]; /* Modulated/Demodulated codewords */
void *e[SRSLTE_MAX_CODEWORDS];
bool csi_enabled;
float *csi[SRSLTE_MAX_CODEWORDS]; /* Channel Strengh Indicator */
/* tx & rx objects */
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,
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,
uint16_t rnti);

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

@ -84,8 +84,6 @@ typedef struct SRSLTE_API {
srslte_ofdm_t fft_mbsfn;
srslte_chest_dl_t chest;
srslte_cfo_t sfo_correct;
srslte_pdsch_cfg_t pdsch_cfg;
srslte_pdsch_cfg_t pmch_cfg;
srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS];
@ -126,8 +124,6 @@ typedef struct SRSLTE_API {
srslte_dci_msg_t pending_ul_dci_msg;
uint16_t pending_ul_dci_rnti;
float sample_offset;
float last_phich_corr;
}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 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,
uint8_t *data[SRSLTE_MAX_CODEWORDS],
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 */
}
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) {
simd_cf_t ret;
#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_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_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 */
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;
tti = 0;
agc_enabled = false;
radio_is_streaming = false;
is_initialized = false;
};
bool init(char *args = NULL, char *devname = NULL, uint32_t nof_channels = 1);
@ -119,13 +121,13 @@ namespace srslte {
void start_trace();
void write_trace(std::string filename);
void start_rx(bool now = false);
void stop_rx();
void set_tti(uint32_t tti);
bool is_first_of_burst();
bool is_init();
void register_error_handler(srslte_rf_error_handler_t h);
protected:
@ -168,6 +170,9 @@ namespace srslte {
uint32_t tti;
bool agc_enabled;
bool is_initialized = true;;
bool radio_is_streaming;
uint32_t saved_nof_channels;
char saved_args[128];
char saved_devname[128];

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

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

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

@ -122,6 +122,12 @@ uint8_t* sch_pdu::write_packet(srslte::log *log_h)
sch_subh 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) {
log_h->error("init_rem_len=%d\n", init_rem_len);
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)
{
if (ptr) {
pdu_t *pdu = (pdu_t*) ptr;
pdu->len = len;
pdu->tstamp = tstamp;
pdu_q.push(pdu);
} else {
log_h->warning("Error pushing pdu: ptr is empty\n");
}
}
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;
}
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) {
fprintf(stderr, "Calloc error initializing mbsfn_refs (%d)\n", ret);
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->rsrp_neighbour = false;
q->smooth_filter_len = 3;
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)
{
int i;
if(&q->csr_refs)
srslte_refsignal_free(&q->csr_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]) {
srslte_refsignal_free(q->mbsfn_refs[i]);
free(q->mbsfn_refs[i]);
}
}
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){
if (mbsfn_area_id < SRSLTE_MAX_MBSFN_AREA_IDS) {
if(!q->mbsfn_refs[mbsfn_area_id]) {
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_ERROR;
}
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)
{
uint32_t npilots = SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id);
/* Get references from the input 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 */
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);
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)
{
@ -619,6 +629,10 @@ int srslte_chest_dl_estimate_multi_mbsfn(srslte_chest_dl_t *q, cf_t *input[SRSLT
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)
{
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;
}
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 max = -0.0f;
float max = -1e9;
for (int i = 0; i < q->last_nof_antennas; ++i) {
float v = srslte_chest_dl_get_rsrp_port(q, i);
if (v > max) {
@ -716,3 +743,14 @@ float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) {
}
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);
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);
get_time_interval(t);
@ -188,7 +188,7 @@ int main(int argc, char **argv) {
gettimeofday(&t[1], NULL);
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);
get_time_interval(t);

@ -45,6 +45,7 @@
#define FFTW_TYPE 0
#endif
pthread_mutex_t fft_mutex = PTHREAD_MUTEX_INITIALIZER;
void srslte_dft_load() {
#ifdef FFTW_WISDOM_FILE
@ -58,10 +59,12 @@ void srslte_dft_exit() {
#ifdef FFTW_WISDOM_FILE
fftwf_export_wisdom_to_filename(FFTW_WISDOM_FILE);
#endif
fftwf_cleanup();
}
int srslte_dft_plan(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_dir_t dir,
srslte_dft_mode_t mode) {
bzero(plan, sizeof(srslte_dft_plan_t));
if(mode == SRSLTE_DFT_COMPLEX){
return srslte_dft_plan_c(plan,dft_points,dir);
} 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 howmany_dims = {how_many, idist, odist};
pthread_mutex_lock(&fft_mutex);
/* Destroy current plan */
fftwf_destroy_plan(plan->p);
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) {
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 sign = (plan->dir == SRSLTE_DFT_FORWARD) ? FFTW_FORWARD : FFTW_BACKWARD;
pthread_mutex_lock(&fft_mutex);
if (plan->p) {
fftwf_destroy_plan(plan->p);
plan->p = NULL;
}
plan->p = fftwf_plan_dft_1d(new_dft_points, plan->in, plan->out, sign, FFTW_TYPE);
pthread_mutex_unlock(&fft_mutex);
if (!plan->p) {
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 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);
if (!plan->p) {
return -1;
}
pthread_mutex_unlock(&fft_mutex);
plan->size = dft_points;
plan->init_size = plan->size;
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) {
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;
plan->p = fftwf_plan_dft_1d(dft_points, plan->in, plan->out, sign, FFTW_TYPE);
pthread_mutex_unlock(&fft_mutex);
if (!plan->p) {
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 sign = (plan->dir == SRSLTE_DFT_FORWARD) ? FFTW_R2HC : FFTW_HC2R;
pthread_mutex_lock(&fft_mutex);
if (plan->p) {
fftwf_destroy_plan(plan->p);
plan->p = NULL;
}
plan->p = fftwf_plan_r2r_1d(new_dft_points, plan->in, plan->out, sign, FFTW_TYPE);
pthread_mutex_unlock(&fft_mutex);
if (!plan->p) {
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) {
allocate(plan,sizeof(float),sizeof(float), dft_points);
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);
pthread_mutex_unlock(&fft_mutex);
if (!plan->p) {
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) {
if (!plan) return;
if (!plan->size) return;
pthread_mutex_lock(&fft_mutex);
if (!plan->is_guru) {
if (plan->in) fftwf_free(plan->in);
if (plan->out) fftwf_free(plan->out);
}
if (plan->p) fftwf_destroy_plan(plan->p);
pthread_mutex_unlock(&fft_mutex);
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) {
q->mbsfn_subframe = true;
q->non_mbsfn_region = 2; // default set to 2
} else {
q->mbsfn_subframe = false;
}
return SRSLTE_SUCCESS;

@ -171,5 +171,8 @@ int main(int argc, char **argv) {
n_prb++;
}
srslte_dft_exit();
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;
if (q != NULL) {
ret = SRSLTE_ERROR;
bzero(q, sizeof(srslte_softbuffer_rx_t));
ret = srslte_ra_tbs_from_idx(26, nof_prb);
if (ret != SRSLTE_ERROR) {
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);
if (!q->buffer_f) {
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
for (uint32_t i=0;i<q->max_cb;i++) {
q->buffer_f[i] = srslte_vec_malloc(sizeof(int16_t) * SOFTBUFFER_SIZE);
if (!q->buffer_f[i]) {
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);
ret = SRSLTE_SUCCESS;
}
}
clean_exit:
if (ret != SRSLTE_SUCCESS) {
srslte_softbuffer_rx_free(q);
}
return ret;
}
@ -86,6 +110,17 @@ void srslte_softbuffer_rx_free(srslte_softbuffer_rx_t *q) {
}
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));
}
}
@ -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();
free(rm_bits_s);
free(rm_bits_f);
free(rm_bits);
free(rm_bits2);
free(rm_bits2_bytes);

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

@ -279,6 +279,7 @@ int main(int argc, char **argv) {
free(llr);
free(llr_c);
free(data_rx);
free(data_rx2);
if (snr_points == 1) {
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/debug.h"
#include "srslte/phy/utils/mat.h"
#include "srslte/phy/utils/simd.h"
#ifdef LV_HAVE_SSE
#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;
}
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)*/
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 *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_;
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
if (nof_symbols > 32 && nof_rxant <= 2) {
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)*/
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) {
if (csi) {
return srslte_predecoding_single_csi(y, h, x, csi, nof_rxant, nof_symbols, scaling, noise_estimate);
}
#ifdef LV_HAVE_AVX
if (nof_symbols > 32) {
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 */
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,
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;
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
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 {
fprintf(stderr,
"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 */
struct timeval t[3];
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));
gettimeofday(&t[2], NULL);
get_time_interval(t);

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

@ -407,7 +407,7 @@ float srslte_cqi_to_coderate(uint32_t cqi) {
* Table III.
*/
// 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
//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) {
int j;
if (dst + n <= 4 && src + n <= 4) {
memcpy(&q->temp[dst * nof_bits], &q->llr[src * nof_bits],
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 {
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
@ -483,6 +489,8 @@ int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRS
q->frame_idx++;
ret = 0;
uint32_t frame_idx = q->frame_idx;
/* Try decoding for 1 to cell.nof_ports antennas */
if (q->search_all_ports) {
nant = 1;
@ -492,12 +500,12 @@ int srslte_pbch_decode(srslte_pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[SRS
do {
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 */
if (nant == 1) {
/* 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 {
srslte_predecoding_diversity(q->symbols[0], q->ce, x, nant,
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 */
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
* 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234.
* 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 (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);
if (ret == 1) {
if (sfn_offset) {
*sfn_offset = (int) dst - src + q->frame_idx - 1;
*sfn_offset = (int) dst - src + frame_idx - 1;
}
if (nof_tx_ports) {
*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) {
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;
}
}

@ -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 */
if (q->cell.nof_ports == 1) {
/* 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 {
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);

@ -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 */
if (q->cell.nof_ports == 1) {
/* 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 {
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);

@ -294,6 +294,10 @@ void srslte_pdsch_free(srslte_pdsch_t *q) {
if (q->d[i]) {
free(q->d[i]);
}
if (q->csi[i]) {
free(q->csi[i]);
}
}
/* 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)
{
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 */
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 */
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
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) {
DEBUG("Error predecoding\n");
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 */
if (q->cell.nof_ports == 1) {
/* 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 {
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);

@ -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 ret = SRSLTE_ERROR_INVALID_INPUTS;
int i;
if (q != NULL &&
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",
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])) {
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;
}
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);
if (!q->x[i]) {
goto clean;
@ -232,7 +231,7 @@ void srslte_pmch_free(srslte_pmch_t *q) {
if (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]) {
free(q->x[i]);
}
@ -378,7 +377,7 @@ int srslte_pmch_decode_multi(srslte_pmch_t *q,
}
// 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()) {
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
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
float corr=0, corr_max=-1e9;

@ -596,7 +596,7 @@ int srslte_pusch_decode(srslte_pusch_t *q,
}
// 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
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;
}
uint32_t remaining_cb = 0;
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);
uint32_t remaining_cb = nof_cb;
q->nof_iterations = 0;
while(remaining_cb>0) {
@ -401,7 +404,8 @@ bool decode_tb_cb(srslte_sch_t *q,
// CRC is OK
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);
@ -418,15 +422,28 @@ bool decode_tb_cb(srslte_sch_t *q,
cb_idx[i], remaining_cb, i, first_cb, nof_cb);
q->nof_iterations += q->max_iterations;
q->nof_iterations /= (nof_cb-remaining_cb+1);
return false;
srslte_tdec_reset_cb(&q->decoder, i);
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;
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(tx_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;
@ -469,5 +470,8 @@ quit:
} else {
printf("Ok\n");
}
srslte_dft_exit();
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) {
if (h->uhd_error_handler) {
srslte_rf_error_t error;
error.opt = is_rx?1:0;
bzero(&error, sizeof(srslte_rf_error_t));
error.opt = is_rx?1:0;
error.type = SRSLTE_RF_ERROR_LATE;
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) {
rf_uhd_handler_t *handler = (rf_uhd_handler_t*) h;
uhd_async_metadata_handle md;
@ -334,6 +347,7 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
perror("malloc");
return -1;
}
bzero(handler, sizeof(rf_uhd_handler_t));
*h = handler;
/* 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);
// Start low priority thread to receive async commands
/*
handler->async_thread_running = true;
if (pthread_create(&handler->async_thread, NULL, async_thread, handler)) {
perror("pthread_create");
return -1;
}
}*/
/* Restore priorities */
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);
if (error) {
fprintf(stderr, "Error receiving from UHD: %d\n", error);
log_rx_error(handler);
return -1;
}
@ -760,8 +776,12 @@ int rf_uhd_recv_with_time_multi(void *h,
}
}
} else {
return uhd_rx_streamer_recv(handler->rx_stream, data,
nsamples, md, 0.0, false, &rxd_samples);
uhd_error error = uhd_rx_streamer_recv(handler->rx_stream, data, 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) {
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)
{
if (q) {
srslte_pss_free(&q->pss);
srslte_sss_free(&q->sss);
srslte_cfo_free(&q->cfo_corr_frame);
srslte_cfo_free(&q->cfo_corr_symbol);
srslte_cp_synch_free(&q->cp_synch);
if (q->cfo_i_initiated) {
for (int i = 0; i < 2; i++) {
if (q->cfo_i_corr[i]) {
free(q->cfo_i_corr[i]);
}
srslte_pss_free(&q->pss_i[i]);
}
}
if (q->temp) {
free(q->temp);
}

@ -74,7 +74,7 @@ void usage(char *prog) {
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "adgetvsfil")) != -1) {
while ((opt = getopt(argc, argv, "adgetvnsfil")) != -1) {
switch (opt) {
case 'a':
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_pkts_total = 0;
q->pending_ul_dci_rnti = 0;
q->sample_offset = 0;
q->nof_rx_antennas = nof_rx_antennas;
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;
}
}
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;
} else {
@ -178,7 +172,6 @@ void srslte_ue_dl_free(srslte_ue_dl_t *q) {
srslte_pdcch_free(&q->pdcch);
srslte_pdsch_free(&q->pdsch);
srslte_pmch_free(&q->pmch);
srslte_cfo_free(&q->sfo_correct);
for (int i = 0; i < SRSLTE_MAX_TB; i++) {
srslte_softbuffer_rx_free(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->pkts_total = 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.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");
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++) {
if (srslte_ofdm_rx_set_prb(&q->fft[port], q->cell.cp, q->cell.nof_prb)) {
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));
}
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:
* - OFDM demodulation
* - 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 */
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]);
/* 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);
} 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);
}
INFO("SYNC FIND: sf_idx=%d, ret=%d, next_state=%d\n", q->sf_idx, ret, q->state);
break;
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++;
}
INFO("SYNC TRACK: sf_idx=%d, ret=%d, next_state=%d\n", q->sf_idx, ret, q->state);
break;
}
}

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

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

@ -200,10 +200,16 @@ void srslte_vec_fprint_hex(FILE *stream, uint8_t *x, const uint32_t len) {
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;
uint8_t byte;
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;
n+=sprintf(&str[n], "[");
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], "]");
str[max_str_len-1] = 0;
}
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;
is_initialized = true;
return true;
}
bool radio::is_init() {
return is_initialized;
}
void radio::stop()
{
srslte_rf_close(&rf_device);
@ -82,11 +87,8 @@ void radio::stop()
void radio::reset()
{
printf("Resetting Radio...\n");
srslte_rf_close(&rf_device);
sleep(3);
if (srslte_rf_open_devname(&rf_device, saved_devname, saved_args, saved_nof_channels)) {
fprintf(stderr, "Error opening RF device\n");
}
srslte_rf_stop_rx_stream(&rf_device);
radio_is_streaming = false;
}
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)
{
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,
rxd_time?&rxd_time->full_secs:NULL, rxd_time?&rxd_time->frac_secs:NULL) > 0) {
return true;
@ -295,7 +301,9 @@ void radio::set_master_clock_rate(double rate)
void radio::set_rx_srate(double srate)
{
srslte_rf_stop_rx_stream(&rf_device);
srslte_rf_set_rx_srate(&rf_device, srate);
srslte_rf_start_rx_stream(&rf_device, false);
}
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;
}
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)
{
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);
}
is_initialized = 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++) {
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,
rxd_time?&rxd_time->full_secs:NULL, rxd_time?&rxd_time->frac_secs:NULL) > 0) {
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)
{
if(valid_lcid(lcid))
if(valid_lcid(lcid)) {
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)
@ -149,8 +153,12 @@ void pdcp::enable_encryption(uint32_t lcid)
*******************************************************************************/
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);
} 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)

@ -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.");
dl_tput_bytes[0] += nof_bytes;
byte_buffer_t *buf = pool_allocate;
if (buf) {
memcpy(buf->msg, payload, nof_bytes);
buf->N_bytes = nof_bytes;
buf->set_timestamp();
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)
@ -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.");
dl_tput_bytes[0] += nof_bytes;
byte_buffer_t *buf = pool_allocate;
if (buf) {
memcpy(buf->msg, payload, nof_bytes);
buf->N_bytes = nof_bytes;
buf->set_timestamp();
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)
@ -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.");
dl_tput_bytes[0] += nof_bytes;
byte_buffer_t *buf = pool_allocate;
if (buf) {
memcpy(buf->msg, payload, nof_bytes);
buf->N_bytes = nof_bytes;
buf->set_timestamp();
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)
{
if(lcid >= SRSLTE_N_RADIO_BEARERS) {
rlc_log->warning("Invalid LCID=%d\n", lcid);
return false;
} else if(!rlc_array[lcid].active()) {
return false;

@ -72,6 +72,14 @@ rlc_am::~rlc_am()
{
// reset RLC and dealloc SDUs
stop();
if(rx_sdu) {
pool->deallocate(rx_sdu);
}
if(tx_sdu) {
pool->deallocate(tx_sdu);
}
}
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)
{
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;
}
// 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
if(retx_queue.size() > 0) {
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
header.sn = vt_s;
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
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)
{
byte_buffer_t *buf = pool_allocate;
if (buf) {
memcpy(buf->msg, payload, nof_bytes);
buf->N_bytes = nof_bytes;
buf->set_timestamp();
pdcp->write_pdu(lcid, buf);
} else {
log->error("Fatal Error: Couldn't allocate buffer in rlc_tm::write_pdu().\n");
}
}
} // namespace srsue

@ -136,11 +136,11 @@ void rlc_um::reset()
vr_uh = 0;
pdu_lost = false;
if(rx_sdu) {
rx_sdu->reset();
pool->deallocate(rx_sdu);
}
if(tx_sdu) {
tx_sdu->reset();
pool->deallocate(tx_sdu);
}
if(mac_timers) {
@ -173,7 +173,7 @@ uint32_t rlc_um::get_bearer()
void rlc_um::write_sdu(byte_buffer_t *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()
{
if(!rx_sdu)
if(!rx_sdu) {
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
while(!inside_reordering_window(vr_ur))
@ -474,6 +479,10 @@ void rlc_um::reassemble_rx_sdus()
rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu);
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;
}
@ -494,6 +503,10 @@ void rlc_um::reassemble_rx_sdus()
rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu);
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;
}
@ -528,6 +541,10 @@ void rlc_um::reassemble_rx_sdus()
rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu);
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;
}
@ -557,6 +574,10 @@ void rlc_um::reassemble_rx_sdus()
rx_sdu->set_timestamp();
pdcp->write_pdu(lcid, rx_sdu);
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;
}

@ -64,7 +64,43 @@ private:
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;
uint32_t id = 0;
uint32_t duration_msec = 5;
@ -84,10 +120,25 @@ int main(int argc, char **argv) {
result = (diff_ms == duration_msec);
if(result) {
printf("Passed\n");
exit(0);
printf("Single thread test passed\n");
return 0;
}else{
printf("Failed\n;");
exit(1);
return -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_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)
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/threads.h"
#include "srslte/upper/rlc.h"
#include <boost/program_options.hpp>
#include <boost/program_options/parsers.hpp>
#include <assert.h>
#define NBUFS 5
using namespace std;
using namespace srsue;
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
:public thread
{
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_;
rlc2 = rlc2_;
fail_rate = fail_rate_;
run_enable = true;
running = false;
pdu_tx_delay_usec = pdu_tx_delay_usec_;
}
void stop()
@ -82,7 +136,7 @@ private:
if(((float)rand()/RAND_MAX > fail_rate) && read>0) {
rlc2->write_pdu(1, pdu->msg, opp_size);
}
usleep(100);
usleep(pdu_tx_delay_usec);
}
running = false;
byte_buffer_pool::get_instance()->deallocate(pdu);
@ -91,6 +145,7 @@ private:
rlc_interface_mac *rlc1;
rlc_interface_mac *rlc2;
float fail_rate;
uint32_t pdu_tx_delay_usec;
bool run_enable;
bool running;
@ -100,9 +155,9 @@ class mac_dummy
:public srslte::mac_interface_timers
{
public:
mac_dummy(rlc_interface_mac *rlc1_, rlc_interface_mac *rlc2_, float fail_rate_)
:r1(rlc1_, rlc2_, fail_rate_)
,r2(rlc2_, rlc1_, 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_, pdu_tx_delay)
,r2(rlc2_, rlc1_, fail_rate_, pdu_tx_delay)
{
}
@ -140,12 +195,13 @@ class rlc_am_tester
,public thread
{
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_;
run_enable = true;
running = false;
rx_pdus = 0;
name = name_;
sdu_gen_delay_usec = sdu_gen_delay_usec_;
}
void stop()
@ -191,7 +247,7 @@ private:
pdu->N_bytes = 1500;
pdu->msg[0] = sn++;
rlc->write_sdu(1, pdu);
usleep(100);
usleep(sdu_gen_delay_usec);
}
running = false;
}
@ -202,26 +258,26 @@ private:
std::string name;
uint32_t sdu_gen_delay_usec;
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 log2("RLC_AM_2");
log1.set_level(srslte::LOG_LEVEL_DEBUG);
log2.set_level(srslte::LOG_LEVEL_DEBUG);
log1.set_level((LOG_LEVEL_ENUM)args.log_level);
log2.set_level((LOG_LEVEL_ENUM)args.log_level);
log1.set_hex_limit(-1);
log2.set_hex_limit(-1);
float fail_rate = 0.1;
rlc rlc1;
rlc rlc2;
rlc_am_tester tester1(&rlc1, "tester1");
rlc_am_tester tester2(&rlc2, "tester2");
mac_dummy mac(&rlc1, &rlc2, fail_rate);
rlc_am_tester tester1(&rlc1, "tester1", args.sdu_gen_delay_usec);
rlc_am_tester tester2(&rlc2, "tester2", args.sdu_gen_delay_usec);
mac_dummy mac(&rlc1, &rlc2, args.error_rate, args.pdu_tx_delay_usec);
ue_interface ue;
rlc1.init(&tester1, &tester1, &ue, &log1, &mac, 0);
@ -245,7 +301,14 @@ void stress_test()
tester2.start(7);
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();
tester2.stop();
@ -254,6 +317,9 @@ void stress_test()
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();
}

@ -13,6 +13,8 @@
# mme_addr: IP address of MME for S1 connnection
# gtp_bind_addr: Local IP address to bind for GTP connection
# 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]
@ -25,6 +27,9 @@ mnc = 01
mme_addr = 127.0.1.100
gtp_bind_addr = 127.0.0.1
n_prb = 50
#tm = 4
#nof_ports = 2
#####################################################################
# 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);
// Start streaming RX samples
radio_h->start_rx();
// Set TTI so that first TX is at tti=0
tti = 10235;

@ -195,6 +195,10 @@ void gtpu::rem_user(uint16_t rnti)
void gtpu::run_thread()
{
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;
running=true;

@ -88,6 +88,10 @@ void s1ap::get_metrics(s1ap_metrics_t &m)
void s1ap::run_thread()
{
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;
running = true;
@ -514,10 +518,15 @@ bool s1ap::handle_dlnastransport(LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT
}
srslte::byte_buffer_t *pdu = pool_allocate;
if (pdu) {
memcpy(pdu->msg, msg->NAS_PDU.buffer, msg->NAS_PDU.n_octets);
pdu->N_bytes = msg->NAS_PDU.n_octets;
rrc->write_dl_info(rnti, pdu);
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)
@ -850,6 +859,11 @@ bool s1ap::send_initial_ctxt_setup_response(uint16_t rnti, LIBLTE_S1AP_MESSAGE_I
return false;
}
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;
tx_pdu.ext = false;
@ -896,6 +910,11 @@ bool s1ap::send_erab_setup_response(uint16_t rnti, LIBLTE_S1AP_MESSAGE_E_RABSETU
return false;
}
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;
tx_pdu.ext = false;
@ -942,6 +961,11 @@ bool s1ap::send_initial_ctxt_setup_failure(uint16_t rnti)
return false;
}
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;
tx_pdu.ext = false;
tx_pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_UNSUCCESSFULOUTCOME;

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

@ -49,6 +49,7 @@ typedef struct{
uint16_t mnc; // BCD-coded with 0xF filler
std::string mme_bind_addr;
std::string mme_name;
std::string mme_apn;
} s1ap_args_t;
typedef struct{
@ -96,6 +97,7 @@ typedef struct{
LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT ms_network_cap;
bool eit;
uint8_t procedure_transaction_id;
uint8_t attach_type;
} ue_ctx_t;
}//namespace
#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_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_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 mnc;
string mme_bind_addr;
string mme_apn;
string spgw_bind_addr;
string sgi_if_addr;
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.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.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.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")
@ -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_apn = mme_apn;
args->spgw_args.gtpu_bind_addr = spgw_bind_addr;
args->spgw_args.sgi_if_addr = sgi_if_addr;
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 -- MME control TEID: %lu \n", cs_req->sender_f_teid.teid);
// 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
//cs_req->rat_type = srslte::GTPC_RAT_TYPE::EUTRAN;

@ -38,7 +38,9 @@ boost::mutex s1ap_instance_mutex;
s1ap::s1ap():
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->console("Received Service Request \n");
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);
@ -200,11 +205,8 @@ s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRA
if(*reply_flag == true)
{
if(ue_ctx != NULL)
{
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_s1ap_log->info("DL NAS: Sent Downlink NAS message\n");
m_s1ap_log->console("DL NAS: Sent Downlink NAS Message\n");
}
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->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 -- UE Network Capabilities EEA: %d%d%d%d%d%d%d%d\n",
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 -- 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
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
*reply_flag = true;
m_s1ap_log->info("Downlink NAS: Sending Athentication Request\n");
m_s1ap_log->console("Downlink NAS: Sending Athentication Request\n");
m_s1ap_log->info("Downlink NAS: Sending Authentication Request\n");
m_s1ap_log->console("Downlink NAS: Sending Authentication Request\n");
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
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
ue_ctx.eit = pdn_con_req.esm_info_transfer_flag_present;
//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);
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_mme_gtpc->send_create_session_request(ue_ctx_ptr->imsi, ue_ctx_ptr->mme_ue_s1ap_id);
*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->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);
*reply_flag = true;
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);
m_s1ap_log->console("Sending ESM information request\n");
m_s1ap_log->info("Sending ESM information request\n");
*reply_flag = true;
}
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();
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
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 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;
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->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.
//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);
if(err != LIBLTE_SUCCESS)
{
m_s1ap_log->error("Error packing Athentication Request\n");
m_s1ap_log->console("Error packing Athentication Request\n");
m_s1ap_log->error("Error packing Authentication Request\n");
m_s1ap_log->console("Error packing Authentication Request\n");
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);
if(err != LIBLTE_SUCCESS)
{
m_s1ap_log->error("Error packing Athentication Request\n");
m_s1ap_log->console("Error packing Athentication Request\n");
m_s1ap_log->error("Error packing Authentication Request\n");
m_s1ap_log->console("Error packing Authentication Request\n");
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);
if(err != LIBLTE_SUCCESS)
{
m_s1ap_log->error("Error packing Athentication Reject\n");
m_s1ap_log->console("Error packing Athentication Reject\n");
m_s1ap_log->error("Error packing Authentication Reject\n");
m_s1ap_log->console("Error packing Authentication Reject\n");
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);
if(err != LIBLTE_SUCCESS)
{
m_s1ap_log->error("Error packing Dw NAS Transport: Athentication Reject\n");
m_s1ap_log->console("Error packing Downlink 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: Authentication Reject\n");
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);
if(err != LIBLTE_SUCCESS)
{
m_s1ap_log->console("Error packing Athentication Request\n");
m_s1ap_log->console("Error packing Authentication Request\n");
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);
if(err != LIBLTE_SUCCESS)
{
m_s1ap_log->console("Error packing Athentication Request\n");
m_s1ap_log->console("Error packing Authentication Request\n");
return false;
}
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);
if(err != LIBLTE_SUCCESS)
{
m_s1ap_log->error("Error packing Dw NAS Transport: Athentication Reject\n");
m_s1ap_log->console("Error packing Downlink 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: Authentication Reject\n");
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.eps_attach_result = LIBLTE_MME_EPS_ATTACH_RESULT_EPS_ONLY;
attach_accept.eps_attach_result = ue_ctx->attach_type;
//Mandatory
//FIXME: Set t3412 from config
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
//set apn
//act_def_eps_bearer_context_req.apn
std::string apn("test123");
act_def_eps_bearer_context_req.apn.apn = apn; //FIXME
act_def_eps_bearer_context_req.apn.apn = m_s1ap->m_s1ap_args.mme_apn;
act_def_eps_bearer_context_req.proc_transaction_id = ue_ctx->procedure_transaction_id; //FIXME
//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.apn_ambr_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;
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);
if(err != LIBLTE_SUCCESS)
{
m_s1ap_log->error("Error packing Dw NAS Transport: Athentication Reject\n");
m_s1ap_log->console("Error packing Downlink 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: Authentication Reject\n");
return false;
}
@ -1311,6 +1331,59 @@ s1ap_nas_transport::pack_emm_information(srslte::byte_buffer_t *reply_msg, uint3
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*/
void
s1ap_nas_transport::log_unhandled_attach_request_ies(const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req)

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

@ -162,14 +162,25 @@ private:
void timer_alignment_expire();
srslte::timers timers;
// pointer to MAC PCAP object
srslte::mac_pcap* pcap;
bool is_first_ul_grant;
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 pdu_process : public thread {
public:

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

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

@ -61,9 +61,8 @@ public:
void reset_sync();
void cell_search_start();
void cell_search_stop();
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);
void meas_reset();
@ -95,7 +94,6 @@ private:
void reset();
void radio_error();
bool wait_radio_reset();
void set_ue_sync_opts(srslte_ue_sync_t *q, float cfo);
void run_thread();
@ -104,14 +102,13 @@ private:
bool set_cell();
void cell_search_inc();
void resync_sfn(bool is_connected = false, bool rx_now = false);
bool stop_sync();
void cell_reselect();
void stop_rx();
void start_rx(bool now = false);
bool radio_is_rx;
float get_cfo();
uint32_t new_earfcn;
srslte_cell_t new_cell;
bool radio_is_resetting;
bool running;
// Class to run cell search
@ -155,7 +152,7 @@ private:
srslte_ue_mib_t ue_mib;
uint32_t cnt;
uint32_t timeout;
const static uint32_t SYNC_SFN_TIMEOUT = 500;
const static uint32_t SYNC_SFN_TIMEOUT = 80;
};
// Class to perform cell measurements
@ -167,13 +164,14 @@ private:
typedef enum {IDLE, MEASURE_OK, ERROR} ret_code;
~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);
void reset();
void set_cell(srslte_cell_t cell);
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_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 rsrq();
float snr();
@ -183,7 +181,6 @@ private:
srslte::log *log_h;
srslte_ue_dl_t ue_dl;
cf_t *buffer[SRSLTE_MAX_PORTS];
srslte::radio *radio_h;
uint32_t cnt;
uint32_t nof_subframes;
uint32_t current_prb;
@ -204,11 +201,11 @@ private:
uint32_t offset;
} cell_info_t;
void init(srslte::log *log_h, bool sic_pss_enabled, uint32_t max_sf_window);
void deinit();
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]);
private:
cf_t *input_cfo_corrected;
cf_t *sf_buffer[SRSLTE_MAX_PORTS];
srslte::log *log_h;
srslte_sync_t sync_find;
@ -225,6 +222,7 @@ private:
// Class to perform intra-frequency measurements
class intra_measure : public thread {
public:
~intra_measure();
void init(phch_common *common, rrc_interface_phy *rrc, srslte::log *log_h);
void stop();
void add_cell(int pci);
@ -303,17 +301,18 @@ private:
const static uint32_t NOF_IN_SYNC_SF = 100;
// State for primary cell
enum {
typedef enum {
IDLE = 0,
CELL_SEARCH,
CELL_SELECT,
CELL_RESELECT,
CELL_MEASURE,
CELL_CAMP,
IDLE_RX
} phy_state;
} phy_state_t;
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)
enum {
@ -335,7 +334,6 @@ private:
float ul_dl_factor;
uint32_t current_earfcn;
int cur_earfcn_index;
bool cell_search_in_progress;
float dl_freq;
float ul_freq;

@ -54,7 +54,6 @@ public:
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_cfo(float cfo);
void set_sample_offset(float sample_offset);
void set_ul_params(bool pregen_disabled = false);
void set_crnti(uint16_t rnti);
@ -74,7 +73,6 @@ public:
float get_rsrp();
float get_noise();
float get_cfo();
float get_ul_cfo();
private:
/* 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;
bool trace_enabled;
pthread_mutex_t mutex;
/* Common objects */
phch_common *phy;

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

@ -72,6 +72,8 @@ public:
bool is_attached();
void start_plot();
void print_pool();
static void rf_msg(srslte_rf_error_t error);
// UE metrics interface
@ -101,7 +103,7 @@ private:
srslte::logger *logger;
// 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 rlc_log;
srslte::log_filter pdcp_log;
@ -110,8 +112,6 @@ private:
srslte::log_filter gw_log;
srslte::log_filter usim_log;
srslte::byte_buffer_pool *pool;
all_args_t *args;
bool started;

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

@ -88,9 +88,10 @@ public:
uint32_t get_ul_count();
bool is_attached();
bool is_attaching();
bool is_data_requested();
bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi);
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();
// UE interface

@ -37,6 +37,7 @@
#include "srslte/common/security.h"
#include "srslte/common/threads.h"
#include <math.h>
#include <map>
#include <queue>
@ -65,14 +66,16 @@ class cell_t
return earfcn == this->earfcn && pci == phy_cell.id;
}
bool greater(cell_t *x) {
return x->rsrp > rsrp;
return rsrp > x->rsrp;
}
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++) {
if (plmn_id.mcc == sib1.plmn_id[i].id.mcc && plmn_id.mnc == sib1.plmn_id[i].id.mnc) {
return true;
}
}
}
return false;
}
cell_t() {
@ -80,6 +83,7 @@ class cell_t
cell_t(tmp, 0, 0);
}
cell_t(srslte_cell_t phy_cell, uint32_t earfcn, float rsrp) {
gettimeofday(&last_update, NULL);
this->has_valid_sib1 = false;
this->has_valid_sib2 = false;
this->has_valid_sib3 = false;
@ -94,14 +98,108 @@ class cell_t
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;
bool in_sync;
private:
float rsrp;
uint32_t earfcn;
struct timeval last_update;
bool has_valid_sib1;
bool has_valid_sib2;
bool has_valid_sib3;
bool has_valid_sib13;
bool in_sync;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2;
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_3_STRUCT sib3;
@ -151,13 +249,13 @@ public:
void enable_capabilities();
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
void in_sync();
void out_of_sync();
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);
// MAC interface
@ -197,9 +295,9 @@ private:
LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg;
LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg;
byte_buffer_t* byte_align_and_pack(byte_buffer_t *pdu = NULL);
void send_ul_ccch_msg(byte_buffer_t *pdu = NULL);
void send_ul_dcch_msg(byte_buffer_t *pdu = NULL);
byte_buffer_t* byte_align_and_pack();
void send_ul_ccch_msg();
void send_ul_dcch_msg();
srslte::bit_buffer_t bit_buf;
pthread_mutex_t mutex;
@ -213,6 +311,8 @@ private:
uint16_t ho_src_rnti;
cell_t ho_src_cell;
uint32_t ho_target_pci;
bool ho_syncing;
phy_interface_rrc::phy_cfg_t ho_src_phy_cfg;
mac_interface_rrc::mac_cfg_t ho_src_mac_cfg;
bool pending_mob_reconf;
@ -226,9 +326,6 @@ private:
uint32_t plmn_select_timeout;
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_int[32];
uint8_t k_up_enc[32];
@ -244,7 +341,7 @@ private:
srslte::mac_interface_timers *mac_timers;
uint32_t n310_cnt, N310;
uint32_t n311_cnt, N311;
uint32_t t301, t310, t311, t304;
uint32_t t300, t301, t310, t311, t304;
// Radio bearers
typedef enum{
@ -274,6 +371,7 @@ private:
}
// List of strongest neighbour cell
const static int NEIGHBOUR_TIMEOUT = 5;
const static int NOF_NEIGHBOUR_CELLS = 8;
std::vector<cell_t*> neighbour_cells;
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(cell_t *cell);
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 {
SI_ACQUIRE_IDLE = 0,
@ -299,7 +400,7 @@ private:
uint16_t sysinfo_index;
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;
bool thread_running;
@ -315,6 +416,7 @@ private:
void run_tti(uint32_t tti);
bool timer_expired(uint32_t timer_id);
void ho_finish();
void delete_report(uint32_t earfcn, uint32_t pci);
private:
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_complete();
void send_con_setup_complete(byte_buffer_t *nas_msg);
void send_ul_info_transfer(uint32_t lcid, byte_buffer_t *sdu);
void send_security_mode_complete(uint32_t lcid, byte_buffer_t *pdu);
void send_rrc_con_reconfig_complete(byte_buffer_t *pdu);
void send_rrc_ue_cap_info(byte_buffer_t *pdu);
void send_ul_info_transfer(byte_buffer_t *nas_msg);
void send_security_mode_complete();
void send_rrc_con_reconfig_complete();
void send_rrc_ue_cap_info();
// Parsers
void parse_dl_ccch(byte_buffer_t *pdu);
@ -442,6 +544,7 @@ private:
// Helpers
void ho_failed();
bool ho_prepare();
void ho_synced(uint32_t target_pci);
void rrc_connection_release();
void con_restablish_cell_reselected();
void radio_link_failure();
@ -459,7 +562,7 @@ private:
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_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_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg);
void release_drb(uint8_t lcid);

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

@ -165,7 +165,14 @@ void demux::process_sch_pdu(srslte::sch_pdu *pdu_msg)
// Route logical channel
if (route_pdu) {
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());
} 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 {
// Process MAC Control Element

@ -82,6 +82,7 @@ bool mac::init(phy_interface_mac *phy, rlc_interface_mac *rlc, rrc_interface_mac
started = true;
start(MAC_MAIN_THREAD_PRIO);
mactimers.init(&timers, log_h);
return started;
}
@ -94,6 +95,7 @@ void mac::stop()
ttisync.increase();
pdu_process_thread.stop();
wait_thread_finish();
mactimers.stop();
}
void mac::start_pcap(srslte::mac_pcap* pcap_)
@ -148,6 +150,17 @@ void mac::reset()
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() {
int cnt=0;
@ -165,7 +178,6 @@ void mac::run_thread() {
tti = ttisync.wait();
log_h->step(tti);
timers.step_all();
// Step all procedures
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;
bsr_procedure = NULL;
phr_procedure = NULL;
msg3_buff_start_pdu = NULL;
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
bool is_rar = false;
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
sdu_len = pdu_msg->get()->set_sdu(lcid, sdu_len, rlc);
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",
lcid, buffer_state, sdu_len, sdu_space, max_sdu_sz, pdu_msg->rem_size());
return true;
@ -347,6 +346,7 @@ void mux::msg3_flush()
msg3_has_been_transmitted = false;
msg3_pending = false;
bzero(msg3_buff, sizeof(MSG3_BUFF_SZ));
msg3_buff_start_pdu = NULL;
}
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)
{
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) {
Error("Moving PDU from Mux unit to Msg3 buffer\n");
return NULL;
}
memcpy(payload, msg3_buff_start_pdu, sizeof(uint8_t)*pdu_sz);
msg3_has_been_transmitted = true;
msg3_pending = false;
return payload;
}
} else {
Error("Msg3 size (%d) is longer than internal msg3_buff size=%d, (see mux.h)\n", pdu_sz, MSG3_BUFF_SZ-32);
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")
("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.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.")
("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")
("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")
("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"),
"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",
bpo::value<bool>(&args->expert.phy.cfo_integer_enabled)->default_value(false),
"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),
"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",
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)")
@ -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),
"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",
bpo::value<string>(&args->expert.phy.sss_algorithm)->default_value("full"),
"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),
"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),
"TX DC offset gain correction")
@ -418,6 +417,9 @@ void *input_loop(void *m) {
cout << "Enter t to restart trace." << endl;
}
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;
}
}
sleep(1);
ue->print_pool();
sleep(10);
}
pthread_cancel(input);
metricshub.stop();

@ -355,13 +355,16 @@ void phch_common::reset() {
void phch_common::reset_ul()
{
/*
is_first_tx = true;
is_first_of_burst = true;
for (uint32_t i=0;i<nof_mutex;i++) {
pthread_mutex_trylock(&tx_mutex[i]);
pthread_mutex_unlock(&tx_mutex[i]);
}
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);
// 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
intra_freq_meas.init(worker_com, rrc, log_h);
@ -132,9 +132,7 @@ void phch_recv::reset()
next_offset = 0;
cell_is_set = false;
srate_mode = SRATE_NONE;
cell_search_in_progress = false;
current_earfcn = 0;
radio_is_resetting = false;
sfn_p.reset();
measure_p.reset();
search_p.reset();
@ -144,33 +142,16 @@ void phch_recv::reset()
void phch_recv::radio_error()
{
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();
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) {
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)
{
do_agc = enable;
@ -239,7 +220,7 @@ bool phch_recv::set_cell() {
// Set cell in all objects
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;
}
measure_p.set_cell(cell);
@ -265,19 +246,6 @@ bool phch_recv::set_cell() {
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) {
this->earfcn = earfcn;
}
@ -287,34 +255,14 @@ void phch_recv::force_freq(float dl_freq, float 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() {
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();
measure_p.reset();
srslte_ue_sync_reset(&ue_sync);
resync_sfn(true, true);
phy_state = CELL_SELECT;
}
void phch_recv::cell_search_inc()
@ -322,7 +270,9 @@ void phch_recv::cell_search_inc()
cur_earfcn_index++;
if (cur_earfcn_index >= 0) {
if (cur_earfcn_index >= (int) earfcn.size()) {
Info("SYNC: Cell Search finished. Going to IDLE\n");
cur_earfcn_index = 0;
phy_state = IDLE;
rrc->earfcn_end();
} else {
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];
set_frequency();
}
phy_state = CELL_SEARCH;
}
}
}
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) {
cur_earfcn_index = -1;
}
cell_search_inc();
phy_state = CELL_SEARCH;
cell_search_in_progress = true;
}
}
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)
{
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;
while(worker_com->is_any_pending_ack() && cnt < 10) {
usleep(1000);
@ -383,20 +323,21 @@ bool phch_recv::cell_handover(srslte_cell_t cell)
bool ret = false;
this->cell = cell;
Info("Cell HO: Stopping sync with current cell\n");
worker_com->reset_ul();
phy_state = IDLE_RX;
phy_state = IDLE;
cnt = 0;
while(!is_in_idle_rx && cnt<20) {
while(!is_in_idle && cnt<20) {
usleep(1000);
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");
if (set_cell()) {
//resync_sfn(true, true);
sfn_p.reset();
phy_state = CELL_RESELECT;
Info("Cell HO: Synchronizing with new cell\n");
phy_state = CELL_SELECT;
ret = true;
} else {
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;
}
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) {
log_h->info("Cell Select: Already in cell EARFCN=%d\n", earfcn);
cell_search_in_progress = false;
log_h->info("Cell Select: Already in cell EARFCN=%d, PCI=%d\n", earfcn, cell.id);
if (srate_mode != SRATE_CAMP) {
set_sampling_rate();
log_h->info("Cell Select: Setting Camping sampling rate\n");
}
if (phy_state < CELL_SELECT) {
resync_sfn();
}
return true;
} else {
cell_search_in_progress = false;
if (!stop_sync()) {
log_h->warning("Still not in idle\n");
}
if (earfcn != current_earfcn) {
if (set_frequency()) {
log_h->error("Cell Select: Configuring cell in EARFCN=%d, PCI=%d\n", earfcn, cell.id);
return false;
}
current_earfcn = earfcn;
}
@ -443,13 +388,7 @@ bool phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell) {
if (set_cell()) {
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()
{
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() {
return tti;
}
@ -584,60 +526,62 @@ void phch_recv::run_thread()
uint32_t sf_idx = 0;
phy_state = IDLE;
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)
{
if (phy_state != IDLE) {
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_phy_lib_h->step(tti);
sf_idx = tti%10;
prev_state = phy_state;
switch (phy_state) {
case CELL_SEARCH:
if (cell_search_in_progress)
{
switch(search_p.run(&cell))
{
case search::CELL_FOUND:
if (!srslte_cell_isvalid(&cell)) {
Error("SYNC: Detected invalid cell\n");
Error("SYNC: Detected invalid cell. Going to IDLE\n");
phy_state = IDLE;
break;
}
if (set_cell()) {
Info("SYNC: Setting sampling rate and going to Cell Select\n");
set_sampling_rate();
resync_sfn();
phy_state = CELL_SELECT;
}
break;
case search::CELL_NOT_FOUND:
if (cell_search_in_progress) {
cell_search_inc();
}
break;
default:
radio_error();
break;
}
}
break;
case CELL_RESELECT:
cell_reselect();
break;
case CELL_SELECT:
switch (sfn_p.run_subframe(&cell, &tti))
{
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);
phy_state = CELL_CAMP;
rrc->cell_camping(earfcn[cur_earfcn_index], cell);
} else {
log_h->info("Sync OK. Measuring PCI=%d...\n", cell.id);
measure_p.reset();
@ -645,13 +589,8 @@ void phch_recv::run_thread()
}
break;
case sfn_sync::TIMEOUT:
if (cell_search_in_progress) {
log_h->warning("SYNC: Timeout while synchronizing SFN. Going back to cell search\n");
phy_state = CELL_SEARCH;
} else {
log_h->warning("SYNC: Timeout while synchronizing SFN. Reselecting cell\n");
resync_sfn(true, true);
}
log_h->warning("SYNC: Timeout while synchronizing SFN\n");
rrc->out_of_sync();
break;
case sfn_sync::IDLE:
break;
@ -661,12 +600,21 @@ void phch_recv::run_thread()
}
break;
case CELL_MEASURE:
switch(measure_p.run_subframe_sync(&ue_sync, sf_idx))
{
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);
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;
case measure::IDLE:
break;
@ -700,11 +648,9 @@ void phch_recv::run_thread()
metrics.sfo = srslte_ue_sync_get_sfo(&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->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 */
srslte_timestamp_t rx_time, tx_time, tx_time_prach;
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;
// Reset Uplink TX buffer to avoid mixing packets in TX queue
/*
if (prach_buffer->is_pending()) {
Info("SYNC: PRACH pending: Reset UL\n");
worker_com->reset_ul();
}
radio_h->tx_end();
}*/
// Check if we need to TX a PRACH
if (prach_buffer->is_ready_to_send(tti)) {
srslte_timestamp_copy(&tx_time_prach, &rx_time);
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();
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);
@ -738,7 +685,9 @@ void phch_recv::run_thread()
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]);
}
if (srslte_cell_isvalid(&cell)) {
intra_freq_meas.write(tti, buffer[0], SRSLTE_SF_LEN_PRB(cell.nof_prb));
}
break;
case 0:
Warning("SYNC: Out-of-sync detected in PSS/SSS\n");
@ -756,28 +705,18 @@ void phch_recv::run_thread()
}
break;
case IDLE:
if (!is_in_idle) {
stop_rx();
}
is_in_idle = true;
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->is_init()) {
uint32_t nsamples = 1920;
if (current_srate > 0) {
nsamples = current_srate/1000;
}
if (!radio_h->rx_now(buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb), NULL)) {
Error("SYNC: Receiving from radio while in IDLE_RX\n");
if (!radio_h->rx_now(dummy_buffer, nsamples, NULL)) {
printf("SYNC: Receiving from radio while in IDLE_RX\n");
}
} else {
// wait_worker() only returns NULL if it's being closed. Quit now to avoid unnecessary loops here
running = false;
usleep(1000);
}
is_in_idle = true;
break;
}
@ -785,26 +724,34 @@ void phch_recv::run_thread()
mac->tti_clock(tti);
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() {
out_of_sync_cnt = 0;
in_sync_cnt++;
// Send RRC in-sync signal after 100 ms consecutive subframes
if (in_sync_cnt == NOF_IN_SYNC_SF) {
rrc->in_sync();
in_sync_cnt = 0;
out_of_sync_cnt = 0;
}
}
// Out of sync called by worker or phch_recv every 1 or 5 ms
void phch_recv::out_of_sync() {
in_sync_cnt = 0;
// 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++;
if (out_of_sync_cnt >= NOF_OUT_OF_SYNC_SF) {
Info("Sending to RRC\n");
rrc->out_of_sync();
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) {
p->srate_mode = SRATE_FIND;
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 */
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");
return ERROR;
} else if (ret == 0) {
p->stop_rx();
Info("SYNC: Could not find any cell in this frequency\n");
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,
40,
bch_payload, &cell->nof_ports, &sfn_offset);
p->stop_rx();
if (ret == 1) {
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);
int ret = srslte_ue_sync_zerocopy_multi(ue_sync, buffer);
if (ret < 0) {
Error("SYNC: Error calling ue_sync_get_buffer");
Error("SYNC: Error calling ue_sync_get_buffer.\n");
return ERROR;
}
@ -1080,10 +1024,9 @@ phch_recv::sfn_sync::ret_code phch_recv::sfn_sync::run_subframe(srslte_cell_t *c
/*********
* 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->nof_subframes = nof_subframes;
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");
return;
}
srslte_chest_dl_set_rsrp_neighbour(&ue_dl.chest, true);
reset();
}
@ -1118,16 +1062,20 @@ void phch_recv::measure::set_cell(srslte_cell_t cell)
reset();
}
float phch_recv::measure::rssi() {
return 10*log10(mean_rssi);
}
float phch_recv::measure::rsrp() {
return mean_rsrp;
return 10*log10(mean_rsrp) + 30 - rx_gain_offset;
}
float phch_recv::measure::rsrq() {
return mean_rsrq;
return 10*log10(mean_rsrq);
}
float phch_recv::measure::snr() {
return mean_snr;
return 10*log10(mean_snr);
}
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,
uint32_t offset,
int offset,
uint32_t sf_idx,
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;
offset = offset-sf_len/2;
if (offset < 0) {
while (offset < 0 && sf_idx < max_sf) {
offset += sf_len;
sf_idx ++;
}
// Fine-tune offset using RS
#ifdef FINE_TUNE_OFFSET_WITH_RS
float max_rsrp = -200;
int best_test_offset = 0;
int test_offset = 0;
bool found_best = false;
// Fine-tune offset using RS
for (uint32_t n=0;n<5;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;
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;
Debug("INTRA: fine-tuning offset: %d, found_best=%d, rem_sf=%d\n", offset, found_best, nof_sf);
final_offset = offset;
@ -1228,10 +1180,10 @@ phch_recv::measure::ret_code phch_recv::measure::run_subframe(uint32_t sf_idx)
return ERROR;
}
float rsrp = 10*log10(srslte_chest_dl_get_rsrp(&ue_dl.chest)) + 30 - rx_gain_offset;
float rsrq = 10*log10(srslte_chest_dl_get_rsrq(&ue_dl.chest));
float snr = 10*log10(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 rsrp = srslte_chest_dl_get_rsrp_neighbour(&ue_dl.chest);
float rsrq = srslte_chest_dl_get_rsrq(&ue_dl.chest);
float snr = srslte_chest_dl_get_snr(&ue_dl.chest);
float rssi = srslte_vec_avg_power_cf(buffer[0], SRSLTE_SF_LEN_PRB(current_prb));
if (cnt == 0) {
mean_rsrp = rsrp;
@ -1246,21 +1198,10 @@ phch_recv::measure::ret_code phch_recv::measure::run_subframe(uint32_t sf_idx)
}
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);
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;
} else {
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);
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.
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");
return;
}
srslte_sync_set_sss_algorithm(&sync_find, SSS_FULL);
srslte_sync_cp_en(&sync_find, false);
srslte_sync_set_cfo_pss_enable(&sync_find, true);
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);
sync_find.pss.chest_on_filter = true;
sync_find.sss_channel_equalize = true;
sync_find.sss_channel_equalize = false;
reset();
}
@ -1321,6 +1261,12 @@ void phch_recv::scell_recv::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])
{
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++) {
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);
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
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))
{
case measure::MEASURE_OK:
// 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) {
cells[nof_cells].pci = found_cell.id;
cells[nof_cells].rsrp = measure_p.rsrp();
cells[nof_cells].rsrq = measure_p.rsrq();
cells[nof_cells].offset = measure_p.frame_st_idx();
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,
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++;
@ -1516,6 +1455,12 @@ void phch_recv::intra_measure::stop() {
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) {
this->current_earfcn = earfcn;
current_sflen = SRSLTE_SF_LEN_PRB(cell.nof_prb);
@ -1594,6 +1539,7 @@ void phch_recv::intra_measure::run_thread()
}
if (running) {
// 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));
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_ue_ul_set_normalization(&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;
pthread_mutex_init(&mutex, NULL);
return true;
}
bool phch_worker::set_cell(srslte_cell_t cell_)
{
bool ret = false;
pthread_mutex_lock(&mutex);
if (cell.id != cell_.id || !cell_initiated) {
memcpy(&cell, &cell_, sizeof(srslte_cell_t));
if (srslte_ue_dl_set_cell(&ue_dl, cell)) {
Error("Initiating UE DL\n");
return false;
goto unlock;
}
if (srslte_ue_ul_set_cell(&ue_ul, cell)) {
Error("Initiating UE UL\n");
return false;
goto unlock;
}
srslte_ue_ul_set_normalization(&ue_ul, true);
srslte_ue_ul_set_cfo_enable(&ue_ul, 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)
@ -183,14 +190,6 @@ void phch_worker::set_cfo(float 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)
{
srslte_ue_dl_set_rnti(&ue_dl, rnti);
@ -224,26 +223,14 @@ float phch_worker::get_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()
{
if (!cell_initiated) {
return;
}
pthread_mutex_lock(&mutex);
Debug("TTI %d running\n", tti);
#ifdef LOG_EXECTIME
@ -359,7 +346,7 @@ void phch_worker::work_imp()
}
/* 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 */
bool signal_ready = false;
@ -389,7 +376,9 @@ void phch_worker::work_imp()
if (!dl_action.generate_ack_callback) {
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]);
}
} else if (!rar_delivered) {
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
if (dl_action.decode_enabled[tb]) {
@ -402,17 +391,19 @@ void phch_worker::work_imp()
update_measurements();
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",
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();
} else {
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();
}
}
pthread_mutex_unlock(&mutex);
/* Tell the plotting thread to draw the plots */
#ifdef ENABLE_GUI
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_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,
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;
}
@ -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);
char hexstr[16];
char hexstr[512];
hexstr[0]='\0';
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),
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;
ret = true;
char hexstr[16];
char hexstr[512];
hexstr[0]='\0';
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
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)
{
phy_interface_rrc::phy_cfg_common_t *common = &phy->config->common;
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 */
if (get_id() == 0) {
if (rssi_read_cnt) {
if (!rssi_read_cnt) {
if (phy->get_radio()->has_rssi() && phy->args->rssi_sensor_enabled) {
phy->last_radio_rssi = phy->get_radio()->get_rssi();
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_correct_tol_hz = 50;
args->time_correct_period = 5;
args->sfo_correct_disable = false;
args->sss_algorithm = "full";
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,
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);
@ -256,11 +255,6 @@ void phy::cell_search_start()
sf_recv.cell_search_start();
}
void phy::cell_search_stop()
{
sf_recv.cell_search_stop();
}
void phy::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);
}
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) {
@ -366,8 +360,6 @@ void phy::reset()
workers[i].reset();
}
workers_common.reset();
usleep(4000);
workers_common.reset_ul();
}
uint32_t phy::get_current_tti()

@ -40,12 +40,13 @@ namespace srsue{
ue::ue()
:started(false)
{
pool = byte_buffer_pool::get_instance();
}
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_)
@ -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);
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.set_netmask(args->expert.ip_netmask);
@ -273,13 +275,17 @@ void ue::stop()
bool ue::is_attached()
{
return (RRC_STATE_CONNECTED == rrc.get_state());
return rrc.is_connected();
}
void ue::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)
{
m.rf = rf_metrics;
@ -308,6 +314,11 @@ void ue::rf_msg(srslte_rf_error_t error)
ue->handle_rf_msg(error);
if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_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
srslte_dft_load();
pool = byte_buffer_pool::get_instance();
}
ue_base::~ue_base() {
byte_buffer_pool::cleanup();
}
void ue_base::cleanup(void)

@ -243,6 +243,10 @@ void gw::run_thread()
uint32 idx = 0;
int32 N_bytes;
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_MAX_ATTEMPTS = 3;
@ -307,7 +311,7 @@ void gw::run_thread()
do {
pdu = pool_allocate;
if (!pdu) {
printf("Not enough buffers in pool\n");
gw_log->error("Fatal Error: Couldn't allocate PDU in run_thread().\n");
usleep(100000);
}
} while(!pdu);

@ -107,8 +107,8 @@ void nas::attach_request() {
selecting_plmn = current_plmn;
}
} else if (state == EMM_STATE_REGISTERED) {
nas_log->info("NAS state is registered, connecting to same PLMN\n");
rrc->plmn_select(current_plmn);
nas_log->info("NAS state is registered, selecting current PLMN\n");
rrc->plmn_select(current_plmn, true);
} else {
nas_log->info("Attach request ignored. State = %s\n", emm_state_text[state]);
}
@ -123,12 +123,7 @@ void nas::deattach_request() {
* RRC interface
******************************************************************************/
void 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;
}
bool nas::plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) {
// Check if already registered
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());
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());
rrc->plmn_select(plmn_id);
rrc->plmn_select(plmn_id, state == EMM_STATE_REGISTERED_INITIATED);
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);
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;
return true;
}
return false;
}
// RRC indicates that the UE has gone through all EARFCN and finished PLMN selection
void nas::plmn_search_end() {
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",
plmn_id_to_string(home_plmn).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",
plmn_id_to_string(home_plmn).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 {
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:
nas_log->error("Not handling NAS message with SEC_HDR_TYPE=%02X\n", sec_hdr_type);
pool->deallocate(pdu);
break;
return;
}
// Write NAS pcap
@ -262,7 +263,7 @@ void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu) {
default:
nas_log->error("Not handling NAS message with MSG_TYPE=%02X\n", msg_type);
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;
current_plmn = selecting_plmn;
plmn_selection = PLMN_SELECTED;
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;
liblte_mme_pack_activate_default_eps_bearer_context_accept_msg(&act_def_eps_bearer_context_accept,
&attach_complete.esm_msg);
pdu->reset();
liblte_mme_pack_attach_complete_msg(&attach_complete,
LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED,
ctxt.tx_count,
@ -758,36 +762,36 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu)
}
// Send response
byte_buffer_t *sdu = pool_allocate;
pdu->reset();
liblte_mme_pack_security_mode_complete_msg(&sec_mode_comp,
LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT,
ctxt.tx_count,
(LIBLTE_BYTE_MSG_STRUCT *) sdu);
(LIBLTE_BYTE_MSG_STRUCT *) pdu);
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],
ctxt.tx_count,
SECURITY_DIRECTION_UPLINK,
&sdu->msg[5],
sdu->N_bytes - 5,
&sdu->msg[1]);
&pdu->msg[5],
pdu->N_bytes - 5,
&pdu->msg[1]);
nas_log->info("Sending Security Mode Complete nas_current_ctxt.tx_count=%d, RB=%s\n",
ctxt.tx_count,
rrc->get_rb_name(lcid).c_str());
rrc->write_sdu(lcid, sdu);
rrc->write_sdu(lcid, pdu);
ctxt.tx_count++;
pool->deallocate(pdu);
}
void nas::parse_service_reject(uint32_t lcid, byte_buffer_t *pdu) {
nas_log->error("TODO:parse_service_reject\n");
pool->deallocate(pdu);
}
void nas::parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu) {
nas_log->error("TODO:parse_esm_information_request\n");
pool->deallocate(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->console("%s\n", str.c_str());
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() {
LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT attach_req;
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;
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
pdn_con_req.esm_info_transfer_flag_present = false; //FIXME: Check if this is needed
if (cfg.apn == "") {
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.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) {
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;
sec_mode_rej.emm_cause = cause;
@ -914,6 +935,10 @@ void nas::send_identity_response() {}
void nas::send_service_request() {
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
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