Merge branch 'next' into rlc_updates

master
Andre Puschmann 7 years ago
commit a2f6166365

@ -1,6 +1,10 @@
Change Log for Releases
==============================
## 18.03.1
* Fixed compilation for NEON
* Fixed logging and RLC AM issue
## 18.03
* Many bug-fixes and improved stability and performance in all parts

@ -20,5 +20,5 @@
SET(SRSLTE_VERSION_MAJOR 18)
SET(SRSLTE_VERSION_MINOR 3)
SET(SRSLTE_VERSION_PATCH 0)
SET(SRSLTE_VERSION_PATCH 1)
SET(SRSLTE_VERSION_STRING "${SRSLTE_VERSION_MAJOR}.${SRSLTE_VERSION_MINOR}.${SRSLTE_VERSION_PATCH}")

@ -51,9 +51,11 @@
// FIXME: This was chosen arbitrarily
#define LIBLTE_ASN1_OID_MAXSUBIDS 128
// Caution these values must match SRSLTE_ ones in common.h
#define LIBLTE_MAX_MSG_SIZE_BITS 102048
#define LIBLTE_MAX_MSG_SIZE_BYTES 12756
#define LIBLTE_MSG_HEADER_OFFSET 1024
#define LIBLTE_MSG_HEADER_OFFSET 1020
/*******************************************************************************
TYPEDEFS
@ -82,6 +84,8 @@ static const char liblte_error_text[LIBLTE_ERROR_N_ITEMS][64] = {
"Decode failure",
};
#define LIBLTE_STRING_LEN 128
typedef void* LIBLTE_ASN1_OPEN_TYPE_STRUCT;
typedef struct {
@ -96,86 +100,15 @@ typedef struct{
typedef struct{
uint32 N_bits;
uint8 header[LIBLTE_MSG_HEADER_OFFSET];
uint8 msg[LIBLTE_MAX_MSG_SIZE_BITS];
}LIBLTE_SIMPLE_BIT_MSG_STRUCT;
}LIBLTE_BIT_MSG_STRUCT;
typedef struct{
uint32 N_bytes;
uint8 header[LIBLTE_MSG_HEADER_OFFSET];
uint8 msg[LIBLTE_MAX_MSG_SIZE_BYTES];
}LIBLTE_SIMPLE_BYTE_MSG_STRUCT;
struct LIBLTE_BYTE_MSG_STRUCT{
uint32 N_bytes;
uint8 buffer[LIBLTE_MAX_MSG_SIZE_BYTES];
uint8 *msg;
LIBLTE_BYTE_MSG_STRUCT():N_bytes(0)
{
msg = &buffer[LIBLTE_MSG_HEADER_OFFSET];
}
LIBLTE_BYTE_MSG_STRUCT(const LIBLTE_BYTE_MSG_STRUCT& buf)
{
N_bytes = buf.N_bytes;
memcpy(msg, buf.msg, N_bytes);
}
LIBLTE_BYTE_MSG_STRUCT & operator= (const LIBLTE_BYTE_MSG_STRUCT & buf)
{
// avoid self assignment
if (&buf == this)
return *this;
N_bytes = buf.N_bytes;
memcpy(msg, buf.msg, N_bytes);
return *this;
}
uint32 get_headroom()
{
return msg-buffer;
}
void reset()
{
N_bytes = 0;
msg = &buffer[LIBLTE_MSG_HEADER_OFFSET];
}
};
struct LIBLTE_BIT_MSG_STRUCT{
uint32 N_bits;
uint8 buffer[LIBLTE_MAX_MSG_SIZE_BITS];
uint8 *msg;
LIBLTE_BIT_MSG_STRUCT():N_bits(0)
{
msg = &buffer[LIBLTE_MSG_HEADER_OFFSET];
while( (uint64_t)(msg) % 8 > 0) {
msg++;
}
}
LIBLTE_BIT_MSG_STRUCT(const LIBLTE_BIT_MSG_STRUCT& buf){
N_bits = buf.N_bits;
memcpy(msg, buf.msg, N_bits);
}
LIBLTE_BIT_MSG_STRUCT & operator= (const LIBLTE_BIT_MSG_STRUCT & buf){
// avoid self assignment
if (&buf == this)
return *this;
N_bits = buf.N_bits;
memcpy(msg, buf.msg, N_bits);
return *this;
}
uint32 get_headroom()
{
return msg-buffer;
}
void reset()
{
N_bits = 0;
msg = &buffer[LIBLTE_MSG_HEADER_OFFSET];
while( (uint64_t)(msg) % 8 > 0) {
msg++;
}
}
};
}LIBLTE_BYTE_MSG_STRUCT;
/*******************************************************************************

@ -1209,7 +1209,7 @@ static const char liblte_mme_add_ci_text[LIBLTE_MME_ADD_CI_N_ITEMS][20] = {"Don'
"Add"};
// Structs
typedef struct{
std::string name;
char name[LIBLTE_STRING_LEN];
LIBLTE_MME_ADD_CI_ENUM add_ci;
}LIBLTE_MME_NETWORK_NAME_STRUCT;
// Functions
@ -1752,7 +1752,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_guti_type_ie(uint8 **ie_
// Enums
// Structs
typedef struct{
std::string apn;
char apn[LIBLTE_STRING_LEN];
}LIBLTE_MME_ACCESS_POINT_NAME_STRUCT;
// Functions
LIBLTE_ERROR_ENUM liblte_mme_pack_access_point_name_ie(LIBLTE_MME_ACCESS_POINT_NAME_STRUCT *apn,

@ -5579,7 +5579,7 @@ static const char liblte_rrc_ul_information_transfer_type_text[LIBLTE_RRC_UL_INF
"CDMA2000-HRPD"};
// Structs
typedef struct{
LIBLTE_SIMPLE_BYTE_MSG_STRUCT dedicated_info;
LIBLTE_BYTE_MSG_STRUCT dedicated_info;
LIBLTE_RRC_UL_INFORMATION_TRANSFER_TYPE_ENUM dedicated_info_type;
}LIBLTE_RRC_UL_INFORMATION_TRANSFER_STRUCT;
// Functions
@ -5960,7 +5960,7 @@ typedef struct{
}LIBLTE_RRC_REGISTERED_MME_STRUCT;
typedef struct{
LIBLTE_RRC_REGISTERED_MME_STRUCT registered_mme;
LIBLTE_SIMPLE_BYTE_MSG_STRUCT dedicated_info_nas;
LIBLTE_BYTE_MSG_STRUCT dedicated_info_nas;
uint8 rrc_transaction_id;
uint8 selected_plmn_id;
bool registered_mme_present;
@ -6245,7 +6245,7 @@ typedef struct{
typedef struct{
LIBLTE_RRC_MEAS_CONFIG_STRUCT meas_cnfg;
LIBLTE_RRC_MOBILITY_CONTROL_INFO_STRUCT mob_ctrl_info;
LIBLTE_SIMPLE_BYTE_MSG_STRUCT ded_info_nas_list[LIBLTE_RRC_MAX_DRB];
LIBLTE_BYTE_MSG_STRUCT ded_info_nas_list[LIBLTE_RRC_MAX_DRB];
LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT rr_cnfg_ded;
LIBLTE_RRC_SECURITY_CONFIG_HO_STRUCT sec_cnfg_ho;
uint32 N_ded_info_nas;
@ -6626,7 +6626,7 @@ static const char liblte_rrc_dl_information_transfer_type_text[LIBLTE_RRC_DL_INF
"CDMA2000-HRPD"};
// Structs
typedef struct{
LIBLTE_SIMPLE_BYTE_MSG_STRUCT dedicated_info;
LIBLTE_BYTE_MSG_STRUCT dedicated_info;
LIBLTE_RRC_DL_INFORMATION_TRANSFER_TYPE_ENUM dedicated_info_type;
uint8 rrc_transaction_id;
}LIBLTE_RRC_DL_INFORMATION_TRANSFER_STRUCT;

@ -61,7 +61,7 @@
// 3GPP 36.306 Table 4.1.1
#define SRSLTE_MAX_BUFFER_SIZE_BITS 102048
#define SRSLTE_MAX_BUFFER_SIZE_BYTES 12756
#define SRSLTE_BUFFER_HEADER_OFFSET 1024
#define SRSLTE_BUFFER_HEADER_OFFSET 1020
#define SRSLTE_BUFFER_POOL_LOG_ENABLED
@ -116,15 +116,17 @@ public:
byte_buffer_t():N_bytes(0)
{
bzero(buffer, SRSLTE_MAX_BUFFER_SIZE_BYTES);
timestamp_is_set = false;
msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET];
next = NULL;
#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED
debug_name[0] = 0;
bzero(debug_name, SRSLTE_BUFFER_POOL_LOG_NAME_LEN);
#endif
}
byte_buffer_t(const byte_buffer_t& buf)
{
bzero(buffer, SRSLTE_MAX_BUFFER_SIZE_BYTES);
N_bytes = buf.N_bytes;
memcpy(msg, buf.msg, N_bytes);
}
@ -133,6 +135,7 @@ public:
// avoid self assignment
if (&buf == this)
return *this;
bzero(buffer, SRSLTE_MAX_BUFFER_SIZE_BYTES);
N_bytes = buf.N_bytes;
memcpy(msg, buf.msg, N_bytes);
return *this;

@ -41,10 +41,15 @@ namespace srslte {
class pdu_queue
{
public:
typedef enum {
DCH,
BCH,
MCH
} channel_t;
class process_callback
{
public:
virtual void process_pdu(uint8_t *buff, uint32_t len, uint32_t tstamp) = 0;
virtual void process_pdu(uint8_t *buff, uint32_t len, channel_t channel, uint32_t tstamp) = 0;
};
pdu_queue(uint32_t pool_size = DEFAULT_POOL_SIZE) : pool(pool_size), callback(NULL), log_h(NULL) {}
@ -52,7 +57,7 @@ public:
uint8_t* request(uint32_t len);
void deallocate(uint8_t* pdu);
void push(uint8_t *ptr, uint32_t len, uint32_t tstamp = 0);
void push(uint8_t *ptr, uint32_t len, channel_t channel = DCH, uint32_t tstamp = 0);
bool process_pdus();
@ -64,6 +69,7 @@ private:
uint8_t ptr[MAX_PDU_LEN];
uint32_t len;
uint32_t tstamp;
channel_t channel;
#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED
char debug_name[128];
#endif

@ -89,7 +89,7 @@ public:
period_us = period_us_;
start(priority);
}
void stop() {
void stop_thread() {
run_enable = false;
wait_thread_finish();
}

@ -64,7 +64,7 @@ public:
return (counter < timeout) && running;
}
bool is_expired() {
return (timeout > 0) && (counter >= timeout || !running);
return (timeout > 0) && (counter >= timeout);
}
uint32_t get_timeout() {
return timeout;

@ -112,30 +112,34 @@ public:
class nas_interface_rrc
{
public:
typedef enum {
BARRING_NONE = 0,
BARRING_MO_DATA,
BARRING_MO_SIGNALLING,
BARRING_MT,
BARRING_ALL
} barring_t;
virtual void set_barring(barring_t barring) = 0;
virtual void paging(LIBLTE_RRC_S_TMSI_STRUCT *ue_identiy) = 0;
virtual bool is_attached() = 0;
virtual bool is_attaching() = 0;
virtual void notify_connection_setup() = 0;
virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0;
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 bool plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) = 0;
virtual void plmn_search_end() = 0;
};
// NAS interface for UE
class nas_interface_ue
{
public:
virtual void attach_request() = 0;
virtual void deattach_request() = 0;
virtual bool attach_request() = 0;
virtual bool deattach_request() = 0;
};
// NAS interface for UE
class nas_interface_gw
{
public:
virtual void attach_request() = 0;
virtual bool attach_request() = 0;
};
// RRC interface for MAC
@ -159,8 +163,6 @@ class rrc_interface_phy
public:
virtual void in_sync() = 0;
virtual void out_of_sync() = 0;
virtual void earfcn_end() = 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;
};
@ -168,12 +170,23 @@ public:
class rrc_interface_nas
{
public:
typedef struct {
LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id;
uint16_t tac;
} found_plmn_t;
const static int MAX_FOUND_PLMNS = 16;
virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0;
virtual uint16_t get_mcc() = 0;
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, bool connect_request = false) = 0;
virtual int plmn_search(found_plmn_t found_plmns[MAX_FOUND_PLMNS]) = 0;
virtual void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) = 0;
virtual bool connection_request(LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM cause,
srslte::byte_buffer_t *dedicatedInfoNAS) = 0;
virtual void set_ue_idenity(LIBLTE_RRC_S_TMSI_STRUCT s_tmsi) = 0;
virtual bool is_connected() = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0;
};
@ -381,11 +394,6 @@ public:
/* Indicate successfull decoding of PCH TB through PDSCH */
virtual void pch_decoded_ok(uint32_t len) = 0;
/* Function called every start of a subframe (TTI). Warning, this function is called
* from a high priority thread and should terminate asap
*/
virtual void tti_clock(uint32_t tti) = 0;
};
/* Interface RRC -> MAC shared between different RATs */
@ -420,14 +428,13 @@ public:
uint32_t prach_config_index;
} mac_cfg_t;
virtual void clear_rntis() = 0;
/* Instructs the MAC to start receiving BCCH */
virtual void bcch_start_rx() = 0;
virtual void bcch_stop_rx() = 0;
virtual void bcch_start_rx(int si_window_start, int si_window_length) = 0;
/* Instructs the MAC to start receiving PCCH */
virtual void pcch_start_rx() = 0;
virtual void pcch_stop_rx() = 0;
/* RRC configures a logical channel */
virtual void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) = 0;
@ -487,9 +494,10 @@ typedef struct {
uint32_t cfo_loop_pss_conv;
uint32_t cfo_ref_mask;
bool average_subframe_enabled;
int time_correct_period;
bool estimator_fil_auto;
float estimator_fil_stddev;
uint32_t estimator_fil_order;
std::string sss_algorithm;
float estimator_fil_w;
bool rssi_sensor_enabled;
bool sic_pss_enabled;
float rx_gain_offset;
@ -503,8 +511,6 @@ typedef struct {
class phy_interface_mac_common
{
public:
/* Start synchronization with strongest cell in the current carrier frequency */
virtual bool sync_status() = 0;
/* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */
virtual void set_crnti(uint16_t rnti) = 0;
@ -581,15 +587,20 @@ public:
virtual int meas_start(uint32_t earfcn, int pci = -1) = 0;
virtual int meas_stop(uint32_t earfcn, int pci = -1) = 0;
typedef struct {
enum {CELL_FOUND = 0, CELL_NOT_FOUND, ERROR} found;
enum {MORE_FREQS = 0, NO_MORE_FREQS} last_freq;
} cell_search_ret_t;
typedef struct {
srslte_cell_t cell;
uint32_t earfcn;
} phy_cell_t;
/* Cell search and selection procedures */
virtual void cell_search_start() = 0;
virtual void cell_search_next() = 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? */
virtual bool sync_status() = 0;
virtual void sync_reset() = 0;
virtual cell_search_ret_t cell_search(phy_cell_t *cell) = 0;
virtual bool cell_select(phy_cell_t *cell = NULL) = 0;
virtual bool cell_is_camping() = 0;
/* Configure UL using parameters written with set_param() */
virtual void configure_ul_params(bool pregen_disabled = false) = 0;

@ -74,6 +74,7 @@ typedef struct {
float snr_vector[12000];
float pilot_power[12000];
#endif
bool smooth_filter_auto;
uint32_t smooth_filter_len;
float smooth_filter[SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN];
@ -112,10 +113,10 @@ SRSLTE_API void srslte_chest_dl_free(srslte_chest_dl_t *q);
SRSLTE_API int srslte_chest_dl_set_mbsfn_area_id(srslte_chest_dl_t *q,
uint16_t mbsfn_area_id);
SRSLTE_API int srslte_chest_dl_set_cell(srslte_chest_dl_t *q,
srslte_cell_t cell);
SRSLTE_API void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q,
float *filter,
uint32_t filter_len);
@ -123,6 +124,13 @@ SRSLTE_API void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q,
SRSLTE_API void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q,
float w);
SRSLTE_API void srslte_chest_dl_set_smooth_filter_gauss(srslte_chest_dl_t* q,
uint32_t order,
float std_dev);
SRSLTE_API void srslte_chest_dl_set_smooth_filter_auto(srslte_chest_dl_t* q,
bool enable);
SRSLTE_API void srslte_chest_dl_set_noise_alg(srslte_chest_dl_t *q,
srslte_chest_dl_noise_alg_t noise_estimation_alg);

@ -87,7 +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,
float *csi[SRSLTE_MAX_CODEWORDS],
int nof_rxant,
int nof_symbols,
float scaling,
@ -103,6 +103,7 @@ SRSLTE_API int srslte_predecoding_diversity(cf_t *y,
SRSLTE_API int srslte_predecoding_diversity_multi(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS],
float *csi[SRSLTE_MAX_LAYERS],
int nof_rxant,
int nof_ports,
int nof_symbols,
@ -113,7 +114,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,
float *csi[SRSLTE_MAX_CODEWORDS],
int nof_rxant,
int nof_ports,
int nof_layers,

@ -64,7 +64,7 @@ typedef struct SRSLTE_API {
uint8_t *parity_bits;
void *e;
uint8_t *temp_g_bits;
uint16_t *ul_interleaver;
uint32_t *ul_interleaver;
srslte_uci_bit_t ack_ri_bits[12*288];
uint32_t nof_ri_ack_bits;

@ -70,6 +70,17 @@ SRSLTE_API void srslte_bit_copy(uint8_t *dst,
uint32_t src_offset,
uint32_t nof_bits);
SRSLTE_API void srslte_bit_interleave_i(uint8_t *input,
uint8_t *output,
uint32_t *interleaver,
uint32_t nof_bits);
SRSLTE_API void srslte_bit_interleave_i_w_offset(uint8_t *input,
uint8_t *output,
uint32_t *interleaver,
uint32_t nof_bits,
uint32_t w_offset);
SRSLTE_API void srslte_bit_interleave_w_offset(uint8_t *input,
uint8_t *output,
uint16_t *interleaver,

@ -53,12 +53,17 @@ SRSLTE_API void srslte_mat_2x2_mmse_gen(cf_t y0, cf_t y1,
float noise_estimate,
float norm);
SRSLTE_API void srslte_mat_2x2_mmse_csi_gen(cf_t y0, cf_t y1,
cf_t h00, cf_t h01, cf_t h10, cf_t h11,
cf_t *x0, cf_t *x1, float *csi0, float *csi1,
float noise_estimate,
float norm);
SRSLTE_API float srslte_mat_2x2_cn(cf_t h00,
cf_t h01,
cf_t h10,
cf_t h11);
#ifdef LV_HAVE_SSE
/* SSE implementation for complex reciprocal */
@ -103,4 +108,114 @@ SRSLTE_API void srslte_mat_2x2_mmse_avx(__m256 y0, __m256 y1,
#endif /* LV_HAVE_AVX */
#endif // SRSLTE_MAT_H
#if SRSLTE_SIMD_CF_SIZE != 0
/* Generic SIMD implementation for 2x2 determinant */
static inline simd_cf_t srslte_mat_2x2_det_simd(simd_cf_t a00, simd_cf_t a01, simd_cf_t a10, simd_cf_t a11) {
return srslte_simd_cf_sub(srslte_simd_cf_prod(a00, a11), srslte_simd_cf_prod(a01, a10));
}
/* Generic SIMD implementation for Zero Forcing (ZF) solver */
static inline void srslte_mat_2x2_zf_csi_simd(simd_cf_t y0,
simd_cf_t y1,
simd_cf_t h00,
simd_cf_t h01,
simd_cf_t h10,
simd_cf_t h11,
simd_cf_t *x0,
simd_cf_t *x1,
simd_f_t *csi0,
simd_f_t *csi1,
float norm) {
simd_cf_t det = srslte_mat_2x2_det_simd(h00, h01, h10, h11);
simd_cf_t detrec = srslte_simd_cf_mul(srslte_simd_cf_rcp(det), srslte_simd_f_set1(norm));
*x0 = srslte_simd_cf_prod(srslte_simd_cf_sub(srslte_simd_cf_prod(h11, y0), srslte_simd_cf_prod(h01, y1)), detrec);
*x1 = srslte_simd_cf_prod(srslte_simd_cf_sub(srslte_simd_cf_prod(h00, y1), srslte_simd_cf_prod(h10, y0)), detrec);
*csi0 = srslte_simd_f_set1(1.0f);
*csi1 = srslte_simd_f_set1(1.0f);
}
static inline void srslte_mat_2x2_zf_simd(simd_cf_t y0,
simd_cf_t y1,
simd_cf_t h00,
simd_cf_t h01,
simd_cf_t h10,
simd_cf_t h11,
simd_cf_t *x0,
simd_cf_t *x1,
float norm) {
simd_f_t csi1, csi2;
srslte_mat_2x2_zf_csi_simd(y0, y1, h00, h01, h10, h11, x0, x1, &csi1, &csi2, norm);
}
/* Generic SIMD implementation for Minimum Mean Squared Error (MMSE) solver */
static inline void srslte_mat_2x2_mmse_csi_simd(simd_cf_t y0,
simd_cf_t y1,
simd_cf_t h00,
simd_cf_t h01,
simd_cf_t h10,
simd_cf_t h11,
simd_cf_t *x0,
simd_cf_t *x1,
simd_f_t *csi0,
simd_f_t *csi1,
float noise_estimate,
float norm) {
simd_cf_t _noise_estimate;
simd_f_t _norm = srslte_simd_f_set1(norm);
_noise_estimate.re = srslte_simd_f_set1(noise_estimate);
_noise_estimate.im = srslte_simd_f_zero();
/* 1. A = H' x H + No*/
simd_cf_t a00 =
srslte_simd_cf_add(srslte_simd_cf_add(srslte_simd_cf_conjprod(h00, h00), srslte_simd_cf_conjprod(h10, h10)),
_noise_estimate);
simd_cf_t a01 = srslte_simd_cf_add(srslte_simd_cf_conjprod(h01, h00), srslte_simd_cf_conjprod(h11, h10));
simd_cf_t a10 = srslte_simd_cf_add(srslte_simd_cf_conjprod(h00, h01), srslte_simd_cf_conjprod(h10, h11));
simd_cf_t a11 =
srslte_simd_cf_add(srslte_simd_cf_add(srslte_simd_cf_conjprod(h01, h01), srslte_simd_cf_conjprod(h11, h11)),
_noise_estimate);
simd_cf_t a_det_rcp = srslte_simd_cf_rcp(srslte_mat_2x2_det_simd(a00, a01, a10, a11));
/* 2. B = inv(H' x H + No) = inv(A) */
simd_cf_t _norm2 = srslte_simd_cf_mul(a_det_rcp, _norm);
simd_cf_t b00 = srslte_simd_cf_prod(a11, _norm2);
simd_cf_t b01 = srslte_simd_cf_prod(srslte_simd_cf_neg(a01), _norm2);
simd_cf_t b10 = srslte_simd_cf_prod(srslte_simd_cf_neg(a10), _norm2);
simd_cf_t b11 = srslte_simd_cf_prod(a00, _norm2);
/* 3. W = inv(H' x H + No) x H' = B x H' */
simd_cf_t w00 = srslte_simd_cf_add(srslte_simd_cf_conjprod(b00, h00), srslte_simd_cf_conjprod(b01, h01));
simd_cf_t w01 = srslte_simd_cf_add(srslte_simd_cf_conjprod(b00, h10), srslte_simd_cf_conjprod(b01, h11));
simd_cf_t w10 = srslte_simd_cf_add(srslte_simd_cf_conjprod(b10, h00), srslte_simd_cf_conjprod(b11, h01));
simd_cf_t w11 = srslte_simd_cf_add(srslte_simd_cf_conjprod(b10, h10), srslte_simd_cf_conjprod(b11, h11));
/* 4. X = W x Y */
*x0 = srslte_simd_cf_add(srslte_simd_cf_prod(y0, w00), srslte_simd_cf_prod(y1, w01));
*x1 = srslte_simd_cf_add(srslte_simd_cf_prod(y0, w10), srslte_simd_cf_prod(y1, w11));
/* 5. Extract CSI */
*csi0 = srslte_simd_f_rcp(srslte_simd_cf_re(b00));
*csi1 = srslte_simd_f_rcp(srslte_simd_cf_re(b11));
}
static inline void srslte_mat_2x2_mmse_simd(simd_cf_t y0,
simd_cf_t y1,
simd_cf_t h00,
simd_cf_t h01,
simd_cf_t h10,
simd_cf_t h11,
simd_cf_t *x0,
simd_cf_t *x1,
float noise_estimate,
float norm) {
simd_f_t csi0, csi1;
srslte_mat_2x2_mmse_csi_simd(y0, y1, h00, h01, h10, h11, x0, x1, &csi0, &csi1, noise_estimate, norm);
}
#endif /* SRSLTE_SIMD_CF_SIZE != 0 */
#endif /* SRSLTE_MAT_H */

@ -197,7 +197,7 @@ static inline simd_f_t srslte_simd_f_loadu(const float *ptr) {
#ifdef LV_HAVE_AVX512
return _mm512_loadu_ps(ptr);
#else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2
#ifdef LV_HAVE_AVX2
return _mm256_loadu_ps(ptr);
#else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE
@ -233,7 +233,7 @@ static inline void srslte_simd_f_storeu(float *ptr, simd_f_t simdreg) {
#ifdef LV_HAVE_AVX512
_mm512_storeu_ps(ptr, simdreg);
#else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2
#ifdef LV_HAVE_AVX2
_mm256_storeu_ps(ptr, simdreg);
#else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE
@ -376,7 +376,7 @@ static inline simd_f_t srslte_simd_f_zero (void) {
return _mm512_setzero_ps();
#else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2
return _mm256_setzero_ps();
return _mm256_setzero_ps();
#else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE
return _mm_setzero_ps();
@ -443,7 +443,7 @@ static inline simd_f_t srslte_simd_f_sqrt(simd_f_t a) {
#ifdef LV_HAVE_AVX512
return _mm512_sqrt_ps(a);
#else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2
#ifdef LV_HAVE_AVX2
return _mm256_sqrt_ps(a);
#else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE
@ -464,18 +464,53 @@ static inline simd_f_t srslte_simd_f_sqrt(simd_f_t a) {
#endif /* LV_HAVE_AVX512 */
}
static inline simd_f_t srslte_simd_f_neg(simd_f_t a) {
#ifdef LV_HAVE_AVX512
return _mm512_xor_ps(_mm512_set1_ps(-0.0f), a);
#else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2
return _mm256_xor_ps(_mm256_set1_ps(-0.0f), a);
#else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE
return _mm_xor_ps(_mm_set1_ps(-0.0f), a);
#else /* LV_HAVE_SSE */
#ifdef HAVE_NEON
return vnegq_f32(a);
#endif /* HAVE_NEON */
#endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX2 */
#endif /* LV_HAVE_AVX512 */
}
static inline simd_f_t srslte_simd_f_neg_mask(simd_f_t a, simd_f_t mask) {
#ifdef LV_HAVE_AVX512
return _mm512_xor_ps(mask, a);
#else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2
return _mm256_xor_ps(mask, a);
#else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE
return _mm_xor_ps(mask, a);
#else /* LV_HAVE_SSE */
#ifdef HAVE_NEON
return (float32x4_t) veorq_s32((int32x4_t) a, (int32x4_t) mask);
#endif /* HAVE_NEON */
#endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX2 */
#endif /* LV_HAVE_AVX512 */
}
#endif /* SRSLTE_SIMD_F_SIZE */
#if SRSLTE_SIMD_CF_SIZE
#ifdef HAVE_NEON
typedef float32x4x2_t simd_cf_t;
typedef float32x4x2_t simd_cf_t;
#else
typedef struct {
simd_f_t re;
simd_f_t im;
} simd_cf_t;
#endif
@ -667,8 +702,8 @@ static inline void srslte_simd_cf_store(float *re, float *im, simd_cf_t simdreg)
_mm512_store_ps(im, simdreg.im);
#else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2
_mm256_store_ps((float *) re, simdreg.re);
_mm256_store_ps((float *) im, simdreg.im);
_mm256_store_ps(re, simdreg.re);
_mm256_store_ps(im, simdreg.im);
#else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_SSE
_mm_store_ps((float *) re, simdreg.re);
@ -689,8 +724,8 @@ static inline void srslte_simd_cf_storeu(float *re, float *im, simd_cf_t simdreg
_mm512_storeu_ps(im, simdreg.im);
#else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2
_mm256_storeu_ps((float *) re, simdreg.re);
_mm256_storeu_ps((float *) im, simdreg.im);
_mm256_storeu_ps(re, simdreg.re);
_mm256_storeu_ps(im, simdreg.im);
#else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_SSE
_mm_storeu_ps((float *) re, simdreg.re);
@ -833,8 +868,32 @@ static inline simd_cf_t srslte_simd_cf_add (simd_cf_t a, simd_cf_t b) {
return ret;
}
static inline simd_cf_t srslte_simd_cf_sub (simd_cf_t a, simd_cf_t b) {
simd_cf_t ret;
#ifdef LV_HAVE_AVX512
ret.re = _mm512_sub_ps(a.re, b.re);
ret.im = _mm512_sub_ps(a.im, b.im);
#else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2
ret.re = _mm256_sub_ps(a.re, b.re);
ret.im = _mm256_sub_ps(a.im, b.im);
#else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE
ret.re = _mm_sub_ps(a.re, b.re);
ret.im = _mm_sub_ps(a.im, b.im);
#else /* LV_HAVE_SSE */
#ifdef HAVE_NEON
ret.val[0] = vsubq_f32(a.val[0],b.val[0]);
ret.val[1] = vsubq_f32(a.val[1],b.val[1]);
#endif /* HAVE_NEON */
#endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX2 */
#endif /* LV_HAVE_AVX512 */
return ret;
}
static inline simd_cf_t srslte_simd_cf_mul (simd_cf_t a, simd_f_t b) {
simd_cf_t ret;
simd_cf_t ret;
#ifdef LV_HAVE_AVX512
ret.re = _mm512_mul_ps(a.re, b);
ret.im = _mm512_mul_ps(a.im, b);
@ -855,7 +914,7 @@ static inline simd_cf_t srslte_simd_cf_mul (simd_cf_t a, simd_f_t b) {
#endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX2 */
#endif /* LV_HAVE_AVX512 */
return ret;
return ret;
}
static inline simd_cf_t srslte_simd_cf_rcp (simd_cf_t a) {
@ -902,6 +961,59 @@ static inline simd_cf_t srslte_simd_cf_rcp (simd_cf_t a) {
return ret;
}
static inline simd_cf_t srslte_simd_cf_neg (simd_cf_t a) {
simd_cf_t ret;
#if LV_HAVE_NEON
ret.val[0] = srslte_simd_f_neg(a.val[0]);
ret.val[1] = srslte_simd_f_neg(a.val[1]);
#else /* LV_HAVE_NEON */
ret.re = srslte_simd_f_neg(a.re);
ret.im = srslte_simd_f_neg(a.im);
#endif /* LV_HAVE_NEON */
return ret;
}
static inline simd_cf_t srslte_simd_cf_neg_mask (simd_cf_t a, simd_f_t mask) {
simd_cf_t ret;
#ifndef LV_HAVE_AVX512
#ifdef LV_HAVE_AVX2
mask = _mm256_permutevar8x32_ps(mask, _mm256_setr_epi32(0,4,1,5,2,6,3,7));
#endif /* LV_HAVE_AVX2 */
#endif /* LV_HAVE_AVX512 */
#if LV_HAVE_NEON
ret.val[0] = srslte_simd_f_neg_mask(a.val[0], mask);
ret.val[1] = srslte_simd_f_neg_mask(a.val[1], mask);
#else /* LV_HAVE_NEON */
ret.re = srslte_simd_f_neg_mask(a.re, mask);
ret.im = srslte_simd_f_neg_mask(a.im, mask);
#endif /* LV_HAVE_NEON */
return ret;
}
static inline simd_cf_t srslte_simd_cf_conj (simd_cf_t a) {
simd_cf_t ret;
#if LV_HAVE_NEON
ret.val[0] = a.val[0];
ret.val[1] = srslte_simd_f_neg(a.val[1]);
#else /* LV_HAVE_NEON */
ret.re = a.re;
ret.im = srslte_simd_f_neg(a.im);
#endif /* LV_HAVE_NEON */
return ret;
}
static inline simd_cf_t srslte_simd_cf_mulj (simd_cf_t a) {
simd_cf_t ret;
#if LV_HAVE_NEON
ret.val[0] = srslte_simd_f_neg(a.val[1]);
ret.val[1] = a.val[0];
#else /* LV_HAVE_NEON */
ret.re = srslte_simd_f_neg(a.im);
ret.im = a.re;
#endif /* LV_HAVE_NEON */
return ret;
}
static inline simd_cf_t srslte_simd_cf_zero (void) {
simd_cf_t ret;
#ifdef LV_HAVE_AVX512
@ -1115,7 +1227,7 @@ static inline simd_s_t srslte_simd_s_loadu(const int16_t *ptr) {
#ifdef LV_HAVE_AVX512
return _mm512_loadu_si512(ptr);
#else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2
#ifdef LV_HAVE_AVX2
return _mm256_loadu_si256((__m256i*) ptr);
#else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE

@ -99,6 +99,7 @@ SRSLTE_API void srslte_vec_convert_fi(const float *x, const float scale, int16_t
SRSLTE_API void srslte_vec_convert_if(const int16_t *x, const float scale, float *z, const uint32_t len);
SRSLTE_API void srslte_vec_lut_sss(const short *x, const unsigned short *lut, short *y, const uint32_t len);
SRSLTE_API void srslte_vec_lut_sis(const short *x, const unsigned int *lut, short *y, const uint32_t len);
/* vector product (element-wise) */
SRSLTE_API void srslte_vec_prod_ccc(const cf_t *x, const cf_t *y, cf_t *z, const uint32_t len);

@ -34,150 +34,152 @@
#define SRSLTE_RADIO_H
typedef struct {
float tx_corr_dc_gain;
float tx_corr_dc_phase;
float tx_corr_iq_i;
float tx_corr_iq_q;
float rx_corr_dc_gain;
float rx_corr_dc_phase;
float rx_corr_iq_i;
float rx_corr_iq_q;
}rf_cal_t;
float tx_corr_dc_gain;
float tx_corr_dc_phase;
float tx_corr_iq_i;
float tx_corr_iq_q;
float rx_corr_dc_gain;
float rx_corr_dc_phase;
float rx_corr_iq_i;
float rx_corr_iq_q;
} rf_cal_t;
namespace srslte {
/* Interface to the RF frontend.
*/
class radio
{
public:
radio() : tr_local_time(1024*10), tr_usrp_time(1024*10), tr_tx_time(1024*10), tr_is_eob(1024*10) {
bzero(&rf_device, sizeof(srslte_rf_t));
bzero(&end_of_burst_time, sizeof(srslte_timestamp_t));
bzero(zeros, burst_preamble_max_samples*sizeof(cf_t));
burst_preamble_sec = 0;
is_start_of_burst = false;
burst_preamble_samples = 0;
burst_preamble_time_rounded = 0;
cur_tx_srate = 0;
tx_adv_sec = 0;
tx_adv_nsamples = 0;
tx_adv_auto = false;
tx_adv_negative = false;
tx_freq = 0;
rx_freq = 0;
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);
void stop();
void reset();
bool start_agc(bool tx_gain_same_rx);
void set_burst_preamble(double preamble_us);
void set_tx_adv(int nsamples);
void set_tx_adv_neg(bool tx_adv_is_neg);
void set_manual_calibration(rf_cal_t *calibration);
void get_time(srslte_timestamp_t *now);
bool tx_single(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
bool tx(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time);
void tx_end();
bool rx_now(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t *rxd_time);
bool rx_at(void *buffer, uint32_t nof_samples, srslte_timestamp_t rx_time);
void set_tx_gain(float gain);
void set_rx_gain(float gain);
void set_tx_rx_gain_offset(float offset);
double set_rx_gain_th(float gain);
void set_freq_offset(double freq);
void set_tx_freq(double freq);
void set_rx_freq(double freq);
double get_freq_offset();
double get_tx_freq();
double get_rx_freq();
void set_master_clock_rate(double rate);
void set_tx_srate(double srate);
void set_rx_srate(double srate);
float get_tx_gain();
float get_rx_gain();
float get_max_tx_power();
float set_tx_power(float power);
float get_rssi();
bool has_rssi();
void start_trace();
void write_trace(std::string filename);
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:
void save_trace(uint32_t is_eob, srslte_timestamp_t *usrp_time);
srslte_rf_t rf_device;
const static uint32_t burst_preamble_max_samples = 30720000; // 30.72 MHz is maximum frequency
double burst_preamble_sec;// Start of burst preamble time (off->on RF transition time)
srslte_timestamp_t end_of_burst_time;
bool is_start_of_burst;
uint32_t burst_preamble_samples;
double burst_preamble_time_rounded; // preamble time rounded to sample time
cf_t zeros[burst_preamble_max_samples];
double cur_tx_srate;
double tx_adv_sec; // Transmission time advance to compensate for antenna->timestamp delay
int tx_adv_nsamples; // Transmision time advance in number of samples
// Define default values for known radios
bool tx_adv_auto;
bool tx_adv_negative;
const static double uhd_default_burst_preamble_sec = 600*1e-6;
const static double uhd_default_tx_adv_samples = 98;
const static double uhd_default_tx_adv_offset_sec = 4*1e-6;
class radio {
public:
radio() : tr_local_time(1024 * 10), tr_usrp_time(1024 * 10), tr_tx_time(1024 * 10), tr_is_eob(1024 * 10) {
bzero(&rf_device, sizeof(srslte_rf_t));
bzero(&end_of_burst_time, sizeof(srslte_timestamp_t));
bzero(zeros, burst_preamble_max_samples * sizeof(cf_t));
burst_preamble_sec = 0;
is_start_of_burst = false;
burst_preamble_samples = 0;
burst_preamble_time_rounded = 0;
cur_tx_srate = 0;
tx_adv_sec = 0;
tx_adv_nsamples = 0;
tx_adv_auto = false;
tx_adv_negative = false;
tx_freq = 0;
rx_freq = 0;
trace_enabled = false;
tti = 0;
agc_enabled = false;
radio_is_streaming = false;
is_initialized = false;
continuous_tx = false;
};
const static double blade_default_burst_preamble_sec = 0.0;
const static double blade_default_tx_adv_samples = 27;
const static double blade_default_tx_adv_offset_sec = 1e-6;
bool init(char *args = NULL, char *devname = NULL, uint32_t nof_channels = 1);
void stop();
void reset();
bool start_agc(bool tx_gain_same_rx);
double tx_freq, rx_freq, freq_offset;
void set_burst_preamble(double preamble_us);
void set_tx_adv(int nsamples);
void set_tx_adv_neg(bool tx_adv_is_neg);
trace<uint32_t> tr_local_time;
trace<uint32_t> tr_usrp_time;
trace<uint32_t> tr_tx_time;
trace<uint32_t> tr_is_eob;
bool trace_enabled;
uint32_t tti;
bool agc_enabled;
void set_manual_calibration(rf_cal_t *calibration);
bool is_initialized = true;;
bool radio_is_streaming;
bool is_continuous_tx();
void set_continuous_tx(bool enable);
uint32_t saved_nof_channels;
char saved_args[128];
char saved_devname[128];
void get_time(srslte_timestamp_t *now);
bool tx_single(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
bool tx(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time);
void tx_end();
bool rx_now(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t *rxd_time);
bool rx_at(void *buffer, uint32_t nof_samples, srslte_timestamp_t rx_time);
};
void set_tx_gain(float gain);
void set_rx_gain(float gain);
void set_tx_rx_gain_offset(float offset);
double set_rx_gain_th(float gain);
void set_freq_offset(double freq);
void set_tx_freq(double freq);
void set_rx_freq(double freq);
double get_freq_offset();
double get_tx_freq();
double get_rx_freq();
void set_master_clock_rate(double rate);
void set_tx_srate(double srate);
void set_rx_srate(double srate);
float get_tx_gain();
float get_rx_gain();
float get_max_tx_power();
float set_tx_power(float power);
float get_rssi();
bool has_rssi();
void start_trace();
void write_trace(std::string filename);
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:
void save_trace(uint32_t is_eob, srslte_timestamp_t *usrp_time);
srslte_rf_t rf_device;
const static uint32_t burst_preamble_max_samples = 30720000; // 30.72 MHz is maximum frequency
double burst_preamble_sec;// Start of burst preamble time (off->on RF transition time)
srslte_timestamp_t end_of_burst_time;
bool is_start_of_burst;
uint32_t burst_preamble_samples;
double burst_preamble_time_rounded; // preamble time rounded to sample time
cf_t zeros[burst_preamble_max_samples];
double cur_tx_srate;
double tx_adv_sec; // Transmission time advance to compensate for antenna->timestamp delay
int tx_adv_nsamples; // Transmision time advance in number of samples
// Define default values for known radios
bool tx_adv_auto;
bool tx_adv_negative;
const static double uhd_default_burst_preamble_sec = 600 * 1e-6;
const static double uhd_default_tx_adv_samples = 98;
const static double uhd_default_tx_adv_offset_sec = 4 * 1e-6;
const static double blade_default_burst_preamble_sec = 0.0;
const static double blade_default_tx_adv_samples = 27;
const static double blade_default_tx_adv_offset_sec = 1e-6;
double tx_freq, rx_freq, freq_offset;
trace<uint32_t> tr_local_time;
trace<uint32_t> tr_usrp_time;
trace<uint32_t> tr_tx_time;
trace<uint32_t> tr_is_eob;
bool trace_enabled;
uint32_t tti;
bool agc_enabled;
bool continuous_tx;
bool is_initialized;
bool radio_is_streaming;
uint32_t saved_nof_channels;
char saved_args[128];
char saved_devname[128];
};
}
#endif // SRSLTE_RADIO_H

@ -32,7 +32,6 @@
#include "srslte/common/common.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/security.h"
#include "srslte/common/msg_queue.h"
#include "srslte/common/threads.h"

@ -31,7 +31,6 @@
#include "srslte/common/log.h"
#include "srslte/common/common.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/msg_queue.h"
#include "srslte/upper/rlc_entity.h"
#include "srslte/upper/rlc_metrics.h"
#include "srslte/upper/rlc_common.h"

@ -2225,14 +2225,14 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_network_name_ie(LIBLTE_MME_NETWORK_NAME_STRUCT
uint32 i;
uint32 bit_offset;
uint32 byte_offset;
const char *char_str = net_name->name.c_str();
const char *char_str = net_name->name;
if(net_name != NULL &&
ie_ptr != NULL)
{
bit_offset = 0;
byte_offset = 2;
for(i=0; i<net_name->name.size(); i++)
for(i=0; i<strnlen(char_str, LIBLTE_STRING_LEN); i++)
{
if(char_str[i] == 0x0A ||
char_str[i] == 0x0D ||
@ -2319,6 +2319,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_network_name_ie(uint8
uint32 N_bytes;
uint8 spare_field;
char tmp_char;
uint32 str_cnt;
if(ie_ptr != NULL &&
net_name != NULL)
@ -2328,8 +2329,9 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_network_name_ie(uint8
N_bytes = (*ie_ptr)[0];
bit_offset = 0;
byte_offset = 2;
net_name->name = "";
while(byte_offset < N_bytes)
str_cnt = 0;
while(byte_offset < N_bytes && str_cnt < LIBLTE_STRING_LEN)
{
switch(bit_offset)
{
@ -2389,7 +2391,10 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_network_name_ie(uint8
(tmp_char >= 0x61 &&
tmp_char <= 0x7A))
{
net_name->name += tmp_char;
if (str_cnt < LIBLTE_STRING_LEN) {
net_name->name[str_cnt] = tmp_char;
str_cnt++;
}
}
}
@ -2412,10 +2417,18 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_network_name_ie(uint8
(tmp_char >= 0x61 &&
tmp_char <= 0x7A))
{
net_name->name += tmp_char;
if (str_cnt < LIBLTE_STRING_LEN) {
net_name->name[str_cnt] = tmp_char;
str_cnt++;
}
}
}
if (str_cnt < LIBLTE_STRING_LEN) {
net_name->name[str_cnt] = '\0';
str_cnt++;
}
*ie_ptr += byte_offset + 1;
err = LIBLTE_SUCCESS;
@ -3765,12 +3778,12 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_access_point_name_ie(LIBLTE_MME_ACCESS_POINT_N
if(apn != NULL &&
ie_ptr != NULL)
{
apn_str = apn->apn.c_str();
(*ie_ptr)[0] = apn->apn.length()+1;
apn_str = apn->apn;
(*ie_ptr)[0] = strnlen(apn->apn, LIBLTE_STRING_LEN)+1;
len_idx = 0;
apn_idx = 0;
label_len = 0;
while(apn->apn.length() > apn_idx)
while(strnlen(apn->apn, LIBLTE_STRING_LEN) > apn_idx)
{
(*ie_ptr)[1+apn_idx+1] = (uint8)apn_str[apn_idx];
apn_idx++;
@ -3785,7 +3798,7 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_access_point_name_ie(LIBLTE_MME_ACCESS_POINT_N
}
}
(*ie_ptr)[1+len_idx] = label_len;
*ie_ptr += apn->apn.length() + 2;
*ie_ptr += strnlen(apn->apn, LIBLTE_STRING_LEN) + 2;
err = LIBLTE_SUCCESS;
}
@ -3799,26 +3812,31 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_access_point_name_ie(uint8
uint32 i;
uint32 ie_idx;
uint32 label_len;
uint32 str_cnt;
if(ie_ptr != NULL &&
apn != NULL)
{
apn->apn.clear();
ie_idx = 0;
while(ie_idx < (*ie_ptr)[0])
str_cnt = 0;
while(ie_idx < (*ie_ptr)[0] && str_cnt < LIBLTE_STRING_LEN)
{
label_len = (*ie_ptr)[1+ie_idx];
for(i=0; i<label_len; i++)
for(i=0; i<label_len && str_cnt < LIBLTE_STRING_LEN; i++)
{
apn->apn += (char)((*ie_ptr)[1+ie_idx+i+1]);
apn->apn[str_cnt] = (char)((*ie_ptr)[1+ie_idx+i+1]);
str_cnt++;
}
ie_idx += label_len + 1;
if(ie_idx < (*ie_ptr)[0])
if(ie_idx < (*ie_ptr)[0] && str_cnt < LIBLTE_STRING_LEN)
{
apn->apn += '.';
apn->apn[str_cnt] = '.';
str_cnt++;
}
}
apn->apn += "\0";
if (str_cnt < LIBLTE_STRING_LEN) {
apn->apn[str_cnt] = '\0';
}
*ie_ptr += (*ie_ptr)[0] + 1;
err = LIBLTE_SUCCESS;

@ -380,7 +380,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_c_rnti_ie(uint8 **ie_ptr,
Document Reference: 36.331 v10.0.0 Section 6.3.6
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_rrc_pack_dedicated_info_cdma2000_ie(LIBLTE_SIMPLE_BYTE_MSG_STRUCT *ded_info_cdma2000,
LIBLTE_ERROR_ENUM liblte_rrc_pack_dedicated_info_cdma2000_ie(LIBLTE_BYTE_MSG_STRUCT *ded_info_cdma2000,
uint8 **ie_ptr)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
@ -412,7 +412,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_pack_dedicated_info_cdma2000_ie(LIBLTE_SIMPLE_BYTE_
return(err);
}
LIBLTE_ERROR_ENUM liblte_rrc_unpack_dedicated_info_cdma2000_ie(uint8 **ie_ptr,
LIBLTE_SIMPLE_BYTE_MSG_STRUCT *ded_info_cdma2000)
LIBLTE_BYTE_MSG_STRUCT *ded_info_cdma2000)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint32 i;
@ -452,7 +452,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_dedicated_info_cdma2000_ie(uint8
Document Reference: 36.331 v10.0.0 Section 6.3.6
*********************************************************************/
LIBLTE_ERROR_ENUM liblte_rrc_pack_dedicated_info_nas_ie(LIBLTE_SIMPLE_BYTE_MSG_STRUCT *ded_info_nas,
LIBLTE_ERROR_ENUM liblte_rrc_pack_dedicated_info_nas_ie(LIBLTE_BYTE_MSG_STRUCT *ded_info_nas,
uint8 **ie_ptr)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
@ -484,7 +484,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_pack_dedicated_info_nas_ie(LIBLTE_SIMPLE_BYTE_MSG_S
return(err);
}
LIBLTE_ERROR_ENUM liblte_rrc_unpack_dedicated_info_nas_ie(uint8 **ie_ptr,
LIBLTE_SIMPLE_BYTE_MSG_STRUCT *ded_info_nas)
LIBLTE_BYTE_MSG_STRUCT *ded_info_nas)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint32 i;
@ -2715,8 +2715,10 @@ LIBLTE_ERROR_ENUM liblte_rrc_pack_report_config_eutra_ie(LIBLTE_RRC_REPORT_CONFI
liblte_value_2_bits(rep_cnfg_eutra->trigger_type, ie_ptr, 1);
if(LIBLTE_RRC_TRIGGER_TYPE_EUTRA_EVENT == rep_cnfg_eutra->trigger_type)
{
// Event ID choice extension indicator
liblte_value_2_bits(0, ie_ptr, 1); // Choice with extension - unlikely to be >63 choices
// Event ID
// FIXME: Handle extension properly
liblte_value_2_bits(rep_cnfg_eutra->event.event_id, ie_ptr, 3);
if(LIBLTE_RRC_EVENT_ID_EUTRA_A1 == rep_cnfg_eutra->event.event_id)
{

File diff suppressed because it is too large Load Diff

@ -136,7 +136,7 @@ void log_filter::all_log(srslte::LOG_LEVEL_ENUM level,
}
void log_filter::console(const char * message, ...) {
char *args_msg;
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
@ -147,7 +147,7 @@ void log_filter::console(const char * message, ...) {
void log_filter::error(const char * message, ...) {
if (level >= LOG_LEVEL_ERROR) {
char *args_msg;
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
@ -158,7 +158,7 @@ void log_filter::error(const char * message, ...) {
}
void log_filter::warning(const char * message, ...) {
if (level >= LOG_LEVEL_WARNING) {
char *args_msg;
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
@ -169,7 +169,7 @@ void log_filter::warning(const char * message, ...) {
}
void log_filter::info(const char * message, ...) {
if (level >= LOG_LEVEL_INFO) {
char *args_msg;
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
@ -180,7 +180,7 @@ void log_filter::info(const char * message, ...) {
}
void log_filter::debug(const char * message, ...) {
if (level >= LOG_LEVEL_DEBUG) {
char *args_msg;
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
@ -192,7 +192,7 @@ void log_filter::debug(const char * message, ...) {
void log_filter::error_hex(const uint8_t *hex, int size, const char * message, ...) {
if (level >= LOG_LEVEL_ERROR) {
char *args_msg;
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
@ -203,7 +203,7 @@ void log_filter::error_hex(const uint8_t *hex, int size, const char * message, .
}
void log_filter::warning_hex(const uint8_t *hex, int size, const char * message, ...) {
if (level >= LOG_LEVEL_WARNING) {
char *args_msg;
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
@ -214,7 +214,7 @@ void log_filter::warning_hex(const uint8_t *hex, int size, const char * message,
}
void log_filter::info_hex(const uint8_t *hex, int size, const char * message, ...) {
if (level >= LOG_LEVEL_INFO) {
char *args_msg;
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)
@ -225,7 +225,7 @@ void log_filter::info_hex(const uint8_t *hex, int size, const char * message, ..
}
void log_filter::debug_hex(const uint8_t *hex, int size, const char * message, ...) {
if (level >= LOG_LEVEL_DEBUG) {
char *args_msg;
char *args_msg = NULL;
va_list args;
va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0)

@ -74,12 +74,13 @@ void pdu_queue::deallocate(uint8_t* pdu)
* This function enqueues the packet and returns quicly because ACK
* deadline is important here.
*/
void pdu_queue::push(uint8_t *ptr, uint32_t len, uint32_t tstamp)
void pdu_queue::push(uint8_t *ptr, uint32_t len, channel_t channel, uint32_t tstamp)
{
if (ptr) {
pdu_t *pdu = (pdu_t*) ptr;
pdu->len = len;
pdu->tstamp = tstamp;
pdu->channel = channel;
pdu_q.push(pdu);
} else {
log_h->warning("Error pushing pdu: ptr is empty\n");
@ -93,10 +94,12 @@ bool pdu_queue::process_pdus()
pdu_t *pdu;
while(pdu_q.try_pop(&pdu)) {
if (callback) {
callback->process_pdu(pdu->ptr, pdu->len, pdu->tstamp);
callback->process_pdu(pdu->ptr, pdu->len, pdu->channel, pdu->tstamp);
}
if (!pool.deallocate(pdu)) {
log_h->warning("Error deallocating from buffer pool in process_pdus(): buffer not created in this pool.\n");
if (pdu->channel == DCH) {
if (!pool.deallocate(pdu)) {
log_h->warning("Error deallocating from buffer pool in process_pdus(): buffer not created in this pool.\n");
}
}
cnt++;
have_data = true;

@ -155,6 +155,7 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb)
q->rsrp_neighbour = false;
q->smooth_filter_auto = false;
q->smooth_filter_len = 3;
srslte_chest_dl_set_smooth_filter3_coeff(q, 0.1);
@ -263,41 +264,66 @@ int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, srslte_cell_t cell)
/* Uses the difference between the averaged and non-averaged pilot estimates */
static float estimate_noise_pilots(srslte_chest_dl_t *q, uint32_t port_id, srslte_sf_t ch_mode)
{
int nref=SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id);
const float weight = 1.0f;
float sum_power = 0.0f;
uint32_t count = 0;
uint32_t npilots = SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id);
uint32_t nsymbols =
(ch_mode == SRSLTE_SF_MBSFN) ? srslte_refsignal_mbsfn_nof_symbols() : srslte_refsignal_cs_nof_symbols(port_id);
uint32_t nref = npilots / nsymbols;
uint32_t fidx = srslte_refsignal_cs_fidx(q->cell, 0, port_id, 0);
if (q->average_subframe) {
if (ch_mode == SRSLTE_SF_MBSFN) {
nref /= 4;
} else {
nref /= 2;
}
cf_t *input2d[nsymbols + 2];
cf_t *tmp_noise = q->tmp_noise;
for (int i = 0; i < nsymbols; i++) {
input2d[i + 1] = &q->pilot_estimates[i * nref];
}
/* Substract noisy pilot estimates */
srslte_vec_sub_ccc(q->pilot_estimates_average, q->pilot_estimates, q->tmp_noise, nref);
input2d[0] = &q->tmp_noise[0];
if (nsymbols > 3) {
srslte_vec_sc_prod_cfc(input2d[2], 2.0f, input2d[0], nref);
srslte_vec_sub_ccc(input2d[0], input2d[4], input2d[0], nref);
} else {
srslte_vec_sc_prod_cfc(input2d[2], 1.0f, input2d[0], nref);
}
#ifdef FREQ_SEL_SNR
/* Compute frequency-selective SNR */
srslte_vec_abs_square_cf(q->tmp_noise, q->snr_vector, nref);
srslte_vec_abs_square_cf(q->pilot_estimates, q->pilot_power, nref);
srslte_vec_div_fff(q->pilot_power, q->snr_vector, q->snr_vector, nref);
input2d[nsymbols + 1] = &q->tmp_noise[nref];
if (nsymbols > 3) {
srslte_vec_sc_prod_cfc(input2d[nsymbols - 1], 2.0f, input2d[nsymbols + 1], nref);
srslte_vec_sub_ccc(input2d[nsymbols + 1], input2d[nsymbols - 3], input2d[nsymbols + 1], nref);
} else {
srslte_vec_sc_prod_cfc(input2d[nsymbols - 1], 1.0f, input2d[nsymbols + 1], nref);
}
srslte_vec_fprint_f(stdout, q->snr_vector, nref);
#endif
for (int i = 1; i < nsymbols + 1; i++) {
uint32_t offset = ((fidx < 3) ^ (i & 1)) ? 0 : 1;
srslte_vec_sc_prod_cfc(input2d[i], weight, tmp_noise, nref);
/* Compute average power. Normalized for filter len 3 using matlab */
float norm = 1;
if (q->average_subframe) {
norm = 32;
} else {
if (q->smooth_filter_len == 3) {
float a = q->smooth_filter[0];
float norm3 = 6.143*a*a+0.04859*a-0.002774;
norm /= norm3;
srslte_vec_sum_ccc(&input2d[i - 1][0], &tmp_noise[offset], &tmp_noise[offset], nref - offset);
srslte_vec_sum_ccc(&input2d[i - 1][1 - offset], &tmp_noise[0], &tmp_noise[0], nref + offset - 1);
if (offset) {
tmp_noise[0] += 2.0f * input2d[i - 1][0] - input2d[i - 1][1];
} else {
tmp_noise[nref - 1] += 2.0f * input2d[i - 1][nref - 2] - input2d[i - 1][nref - 1];
}
srslte_vec_sum_ccc(&input2d[i + 1][0], &tmp_noise[offset], &tmp_noise[offset], nref - offset);
srslte_vec_sum_ccc(&input2d[i + 1][1 - offset], &tmp_noise[0], &tmp_noise[0], nref + offset - 1);
if (offset) {
tmp_noise[0] += 2.0f * input2d[i + 1][0] - input2d[i + 1][1];
} else {
tmp_noise[nref - 1] += 2.0f * input2d[i + 1][nref - 2] - input2d[i + 1][nref - 1];
}
srslte_vec_sc_prod_cfc(tmp_noise, 1.0f / (weight + 4.0f), tmp_noise, nref);
srslte_vec_sub_ccc(input2d[i], tmp_noise, tmp_noise, nref);
sum_power = srslte_vec_avg_power_cf(tmp_noise, nref);
count++;
}
float power = norm*srslte_vec_avg_power_cf(q->tmp_noise, nref);
return power;
return sum_power / (float) count * sqrtf(weight + 4.0f);
}
static float estimate_noise_pss(srslte_chest_dl_t *q, cf_t *input, cf_t *ce)
@ -443,6 +469,53 @@ void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q, float w)
q->smooth_filter[1] = 1-2*w;
}
void srslte_chest_dl_set_smooth_filter_gauss(srslte_chest_dl_t* q, uint32_t order, float std_dev)
{
const uint32_t filterlen = order + 1;
const int center = (filterlen - 1) / 2;
float *filter = q->smooth_filter;
float norm_p = 0.0f;
if (filterlen) {
for (int i = 0; i < filterlen; i++) {
filter[i] = expf(-powf(i - center, 2) / (2.0f * powf(std_dev, 2)));
norm_p += powf(filter[i], 2);
}
const float norm = srslte_vec_acc_ff(filter, filterlen);
srslte_vec_sc_prod_fff(filter, 1.0f / norm, filter, filterlen);
q->smooth_filter_len = filterlen;
}
}
void srslte_chest_dl_set_smooth_filter_auto(srslte_chest_dl_t *q, bool enable) {
q->smooth_filter_auto = enable;
}
uint32_t srslte_chest_dl_interleave_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *tmp, cf_t *output, uint32_t port_id, srslte_sf_t ch_mode) {
uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_nof_symbols(port_id):srslte_refsignal_cs_nof_symbols(port_id);
uint32_t nref = (ch_mode == SRSLTE_SF_MBSFN)?6*q->cell.nof_prb:2*q->cell.nof_prb;
if (srslte_refsignal_cs_fidx(q->cell, 0, port_id, 0) < 3) {
srslte_vec_interleave(input, &input[nref], tmp, nref);
for (int l = 2; l < nsymbols - 1; l += 2) {
srslte_vec_interleave_add(&input[l * nref], &input[(l + 1) * nref], tmp, nref);
}
} else {
srslte_vec_interleave(&input[nref], input, tmp, nref);
for (int l = 2; l < nsymbols - 1; l += 2) {
srslte_vec_interleave_add(&input[(l + 1) * nref], &input[l * nref], tmp, nref);
}
}
nref *= 2;
srslte_vec_sc_prod_cfc(tmp, 2.0f / nsymbols, output, nref);
return nref;
}
static void average_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *output, uint32_t port_id, srslte_sf_t ch_mode) {
uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_nof_symbols(port_id):srslte_refsignal_cs_nof_symbols(port_id);
uint32_t nref = (ch_mode == SRSLTE_SF_MBSFN)?6*q->cell.nof_prb:2*q->cell.nof_prb;
@ -523,7 +596,16 @@ void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, ui
q->cfo = chest_estimate_cfo(q);
}
/* Estimate noise */
if (q->noise_alg == SRSLTE_NOISE_ALG_REFS) {
q->noise_estimate[rxant_id][port_id] = estimate_noise_pilots(q, port_id, ch_mode);
}
if (ce != NULL) {
if (q->smooth_filter_auto) {
srslte_chest_dl_set_smooth_filter_gauss(q, 4, q->noise_estimate[rxant_id][port_id] * 200.0f);
}
/* Smooth estimates (if applicable) and interpolate */
if (q->smooth_filter_len == 0 || (q->smooth_filter_len == 3 && q->smooth_filter[0] == 0)) {
interpolate_pilots(q, q->pilot_estimates, ce, port_id, ch_mode);
@ -533,13 +615,11 @@ void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, ui
}
/* Estimate noise power */
if (q->noise_alg == SRSLTE_NOISE_ALG_REFS && q->smooth_filter_len > 0) {
q->noise_estimate[rxant_id][port_id] = estimate_noise_pilots(q, port_id, ch_mode);
} else if (q->noise_alg == SRSLTE_NOISE_ALG_PSS) {
if (q->noise_alg == SRSLTE_NOISE_ALG_PSS) {
if (sf_idx == 0 || sf_idx == 5) {
q->noise_estimate[rxant_id][port_id] = estimate_noise_pss(q, input, ce);
}
} else {
} else if (q->noise_alg != SRSLTE_NOISE_ALG_REFS) {
if (sf_idx == 0 || sf_idx == 5) {
q->noise_estimate[rxant_id][port_id] = estimate_noise_empty_sc(q, input);
}

@ -54,7 +54,7 @@ int srslte_layermap_multiplex(cf_t *d[SRSLTE_MAX_CODEWORDS], cf_t *x[SRSLTE_MAX_
int nof_symbols[SRSLTE_MAX_CODEWORDS]) {
if (nof_cw == nof_layers) {
for (int i = 0; i < nof_cw; i++) {
srs_vec_cf_cpy(x[i], d[i], (uint32_t) nof_symbols[0]);
srs_vec_cf_cpy(d[i], x[i], (uint32_t) nof_symbols[0]);
}
return nof_symbols[0];
} else if (nof_cw == 1) {

File diff suppressed because it is too large Load Diff

@ -221,7 +221,7 @@ int srslte_pcfich_decode_multi(srslte_pcfich_t *q, cf_t *sf_symbols[SRSLTE_MAX_P
/* no need for layer demapping */
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_predecoding_diversity_multi(q_symbols, q_ce, x, NULL, 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);
}

@ -492,7 +492,7 @@ int srslte_pdcch_extract_llr_multi(srslte_pdcch_t *q, cf_t *sf_symbols[SRSLTE_MA
/* no need for layer demapping */
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_predecoding_diversity_multi(q->symbols, q->ce, x, NULL, 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);
}

@ -402,7 +402,7 @@ 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);
q->csi[i] = srslte_vec_malloc(sizeof(float) * q->max_re * 2);
if (!q->csi[i]) {
return SRSLTE_ERROR;
}
@ -757,7 +757,7 @@ int srslte_pdsch_decode(srslte_pdsch_t *q,
}
// Pre-decoder
if (srslte_predecoding_type(q->symbols, q->ce, x, q->csi[0], q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers,
if (srslte_predecoding_type(q->symbols, q->ce, x, q->csi, 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;

@ -241,7 +241,7 @@ int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS],
/* no need for layer demapping */
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_predecoding_diversity_multi(q_sf_symbols, q_ce, x, NULL, 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);
}
DEBUG("Recv!!: \n");

@ -130,7 +130,7 @@ int srslte_sch_init(srslte_sch_t *q) {
goto clean;
}
bzero(q->temp_g_bits, SRSLTE_MAX_PRB*12*12*12);
q->ul_interleaver = srslte_vec_malloc(sizeof(uint16_t)*SRSLTE_MAX_PRB*12*12*12);
q->ul_interleaver = srslte_vec_malloc(sizeof(uint32_t)*SRSLTE_MAX_PRB*12*12*12);
if (!q->ul_interleaver) {
goto clean;
}
@ -577,7 +577,7 @@ int srslte_dlsch_encode2(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbu
* Profiling show that the computation of this matrix is neglegible.
*/
static void ulsch_interleave_gen(uint32_t H_prime_total, uint32_t N_pusch_symbs, uint32_t Qm,
uint8_t *ri_present, uint16_t *interleaver_lut)
uint8_t *ri_present, uint32_t *interleaver_lut)
{
uint32_t rows = H_prime_total/N_pusch_symbs;
uint32_t cols = N_pusch_symbs;
@ -599,7 +599,7 @@ static void ulsch_interleave_gen(uint32_t H_prime_total, uint32_t N_pusch_symbs,
/* UL-SCH channel interleaver according to 5.2.2.8 of 36.212 */
void ulsch_interleave(uint8_t *g_bits, uint32_t Qm, uint32_t H_prime_total,
uint32_t N_pusch_symbs, uint8_t *q_bits, srslte_uci_bit_t *ri_bits, uint32_t nof_ri_bits,
uint8_t *ri_present, uint16_t *inteleaver_lut)
uint8_t *ri_present, uint32_t *inteleaver_lut)
{
// Prepare ri_bits for fast search using temp_buffer
@ -611,7 +611,7 @@ void ulsch_interleave(uint8_t *g_bits, uint32_t Qm, uint32_t H_prime_total,
// Genearate interleaver table and interleave bits
ulsch_interleave_gen(H_prime_total, N_pusch_symbs, Qm, ri_present, inteleaver_lut);
srslte_bit_interleave(g_bits, q_bits, inteleaver_lut, H_prime_total*Qm);
srslte_bit_interleave_i(g_bits, q_bits, inteleaver_lut, H_prime_total*Qm);
// Reset temp_buffer because will be reused next time
if (nof_ri_bits > 0) {
@ -624,7 +624,7 @@ void ulsch_interleave(uint8_t *g_bits, uint32_t Qm, uint32_t H_prime_total,
/* UL-SCH channel deinterleaver according to 5.2.2.8 of 36.212 */
void ulsch_deinterleave(int16_t *q_bits, uint32_t Qm, uint32_t H_prime_total,
uint32_t N_pusch_symbs, int16_t *g_bits, srslte_uci_bit_t *ri_bits, uint32_t nof_ri_bits,
uint8_t *ri_present, uint16_t *inteleaver_lut)
uint8_t *ri_present, uint32_t *inteleaver_lut)
{
// Prepare ri_bits for fast search using temp_buffer
if (nof_ri_bits > 0) {
@ -635,7 +635,7 @@ void ulsch_deinterleave(int16_t *q_bits, uint32_t Qm, uint32_t H_prime_total,
// Generate interleaver table and interleave samples
ulsch_interleave_gen(H_prime_total, N_pusch_symbs, Qm, ri_present, inteleaver_lut);
srslte_vec_lut_sss(q_bits, inteleaver_lut, g_bits, H_prime_total*Qm);
srslte_vec_lut_sis(q_bits, inteleaver_lut, g_bits, H_prime_total*Qm);
// Reset temp_buffer because will be reused next time
if (nof_ri_bits > 0) {

@ -41,7 +41,7 @@
#define MAX_TIME_OFFSET 128
#define TRACK_MAX_LOST 4
#define TRACK_MAX_LOST 100
#define TRACK_FRAME_SIZE 32
#define FIND_NOF_AVG_FRAMES 4
#define DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD 0

@ -205,6 +205,163 @@ void srslte_bit_interleaver_run(srslte_bit_interleaver_t *q, uint8_t *input, uin
}
void srslte_bit_interleave_i(uint8_t *input, uint8_t *output, uint32_t *interleaver, uint32_t nof_bits) {
srslte_bit_interleave_i_w_offset(input, output, interleaver, nof_bits, 0);
}
void srslte_bit_interleave_i_w_offset(uint8_t *input, uint8_t *output, uint32_t *interleaver, uint32_t nof_bits, uint32_t w_offset) {
uint32_t st=0, w_offset_p=0;
static const uint8_t mask[] = { 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 };
if (w_offset < 8 && w_offset > 0) {
st=1;
for (uint32_t j=0;j<8-w_offset;j++) {
uint32_t i_p = interleaver[j];
if (input[i_p/8] & mask[i_p%8]) {
output[0] |= mask[j+w_offset];
} else {
output[0] &= ~(mask[j+w_offset]);
}
}
w_offset_p=8-w_offset;
}
#ifdef LV_HAVE_SSE
__m64 m64mask = _mm_setr_pi8((uint8_t) 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1);
union {
uint8_t v[8];
__m64 m64;
} a, b, c;
union {
__m128i m128;
uint16_t u32[4];
uint16_t u16[8];
uint8_t u8[16];
struct {
__m64 reg_a;
__m64 reg_b;
} m64;
struct {
uint16_t i0, i1, i2, i3, i4, i5, i6, i7;
} v16;
struct {
uint32_t i0, i1, i2, i3;
} v32;
} ipx1, ipx2, epx1, epx2;
for (uint32_t i = st; i < nof_bits / 8; i++) {
ipx1.m128 = _mm_loadu_si128((__m128i *) (interleaver + (i * 8 + 0) - w_offset_p));
epx1.m128 = _mm_shuffle_epi8(ipx1.m128, _mm_set_epi8(0x00, 0x04, 0x08, 0x0C,
0x00, 0x04, 0x08, 0x0C,
0x00, 0x04, 0x08, 0x0C,
0x00, 0x04, 0x08, 0x0C));
ipx2.m128 = _mm_loadu_si128((__m128i *) (interleaver + (i * 8 + 4) - w_offset_p));
epx2.m128 = _mm_shuffle_epi8(ipx2.m128, _mm_set_epi8(0x00, 0x04, 0x08, 0x0C,
0x00, 0x04, 0x08, 0x0C,
0x00, 0x04, 0x08, 0x0C,
0x00, 0x04, 0x08, 0x0C));
epx1.m128 = _mm_blendv_epi8(epx2.m128, epx1.m128, _mm_setr_epi8(+1, +1, +1, +1,
-1, -1, -1, -1,
+1, +1, +1, +1,
-1, -1, -1, -1));
b.m64 = _mm_and_si64(epx1.m64.reg_a, _mm_set1_pi8(0x7));
b.m64 = _mm_shuffle_pi8(m64mask, b.m64);
ipx1.m128 = _mm_srli_epi32(ipx1.m128, 3);
ipx2.m128 = _mm_srli_epi32(ipx2.m128, 3);
a.m64 = _mm_set_pi8(input[ipx1.v32.i0],
input[ipx1.v32.i1],
input[ipx1.v32.i2],
input[ipx1.v32.i3],
input[ipx2.v32.i0],
input[ipx2.v32.i1],
input[ipx2.v32.i2],
input[ipx2.v32.i3]);
c.m64 = _mm_cmpeq_pi8(_mm_and_si64(a.m64, b.m64), b.m64);
output[i] = (uint8_t) _mm_movemask_pi8(c.m64);
}
#if 0 /* Disabled */
/* THIS PIECE OF CODE IS FOR CHECKING SIMD BEHAVIOUR. DO NOT ENABLE. */
uint8_t *output2 = malloc(nof_bits/8);
for (uint32_t i=st;i<nof_bits/8;i++) {
uint16_t i_p0 = interleaver[i*8+0-w_offset_p];
uint16_t i_p1 = interleaver[i*8+1-w_offset_p];
uint16_t i_p2 = interleaver[i*8+2-w_offset_p];
uint16_t i_p3 = interleaver[i*8+3-w_offset_p];
uint16_t i_p4 = interleaver[i*8+4-w_offset_p];
uint16_t i_p5 = interleaver[i*8+5-w_offset_p];
uint16_t i_p6 = interleaver[i*8+6-w_offset_p];
uint16_t i_p7 = interleaver[i*8+7-w_offset_p];
uint8_t out0 = (input[i_p0/8] & mask[i_p0%8])?mask[0]:(uint8_t)0;
uint8_t out1 = (input[i_p1/8] & mask[i_p1%8])?mask[1]:(uint8_t)0;
uint8_t out2 = (input[i_p2/8] & mask[i_p2%8])?mask[2]:(uint8_t)0;
uint8_t out3 = (input[i_p3/8] & mask[i_p3%8])?mask[3]:(uint8_t)0;
uint8_t out4 = (input[i_p4/8] & mask[i_p4%8])?mask[4]:(uint8_t)0;
uint8_t out5 = (input[i_p5/8] & mask[i_p5%8])?mask[5]:(uint8_t)0;
uint8_t out6 = (input[i_p6/8] & mask[i_p6%8])?mask[6]:(uint8_t)0;
uint8_t out7 = (input[i_p7/8] & mask[i_p7%8])?mask[7]:(uint8_t)0;
output2[i] = out0 | out1 | out2 | out3 | out4 | out5 | out6 | out7;
}
for(uint32_t i = st; i < nof_bits/8; i++) {
if (output[i] != output2[i]) {
printf("%05d/%05d %02X %02X\n", i, nof_bits/8, output[i], output2[i]);
}
//output[i] = output2[i];
}
free(output2);
#endif /* Disabled */
#else /* LV_HAVE_SSE */
for (uint32_t i=st;i<nof_bits/8;i++) {
uint32_t i_p0 = interleaver[i*8+0-w_offset_p];
uint32_t i_p1 = interleaver[i*8+1-w_offset_p];
uint32_t i_p2 = interleaver[i*8+2-w_offset_p];
uint32_t i_p3 = interleaver[i*8+3-w_offset_p];
uint32_t i_p4 = interleaver[i*8+4-w_offset_p];
uint32_t i_p5 = interleaver[i*8+5-w_offset_p];
uint32_t i_p6 = interleaver[i*8+6-w_offset_p];
uint32_t i_p7 = interleaver[i*8+7-w_offset_p];
uint8_t out0 = (input[i_p0/8] & mask[i_p0%8])?mask[0]:0;
uint8_t out1 = (input[i_p1/8] & mask[i_p1%8])?mask[1]:0;
uint8_t out2 = (input[i_p2/8] & mask[i_p2%8])?mask[2]:0;
uint8_t out3 = (input[i_p3/8] & mask[i_p3%8])?mask[3]:0;
uint8_t out4 = (input[i_p4/8] & mask[i_p4%8])?mask[4]:0;
uint8_t out5 = (input[i_p5/8] & mask[i_p5%8])?mask[5]:0;
uint8_t out6 = (input[i_p6/8] & mask[i_p6%8])?mask[6]:0;
uint8_t out7 = (input[i_p7/8] & mask[i_p7%8])?mask[7]:0;
output[i] = out0 | out1 | out2 | out3 | out4 | out5 | out6 | out7;
}
#endif /* LV_HAVE_SSE */
for (uint32_t j=0;j<nof_bits%8;j++) {
uint32_t i_p = interleaver[(nof_bits/8)*8+j-w_offset];
if (input[i_p/8] & mask[i_p%8]) {
output[nof_bits/8] |= mask[j];
} else {
output[nof_bits/8] &= ~(mask[j]);
}
}
for (uint32_t j=0;j<w_offset;j++) {
uint32_t i_p = interleaver[(nof_bits/8)*8+j-w_offset];
if (input[i_p/8] & (1<<(7-i_p%8))) {
output[nof_bits/8] |= mask[j];
} else {
output[nof_bits/8] &= ~(mask[j]);
}
}
}
void srslte_bit_interleave(uint8_t *input, uint8_t *output, uint16_t *interleaver, uint32_t nof_bits) {
srslte_bit_interleave_w_offset(input, output, interleaver, nof_bits, 0);

@ -60,8 +60,8 @@ inline void srslte_mat_2x2_zf_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf_t h10
}
/* Generic implementation for Minimum Mean Squared Error (MMSE) solver */
inline void srslte_mat_2x2_mmse_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf_t h10, cf_t h11,
cf_t *x0, cf_t *x1, float noise_estimate, float norm) {
inline void srslte_mat_2x2_mmse_csi_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf_t h10, cf_t h11,
cf_t *x0, cf_t *x1, float *csi0, float *csi1, float noise_estimate, float norm) {
/* Create conjugated matrix */
cf_t _h00 = conjf(h00);
cf_t _h01 = conjf(h01);
@ -73,14 +73,14 @@ inline void srslte_mat_2x2_mmse_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf_t h
cf_t a01 = _h00 * h01 + _h10 * h11;
cf_t a10 = _h01 * h00 + _h11 * h10;
cf_t a11 = _h01 * h01 + _h11 * h11 + noise_estimate;
cf_t a_det_rcp = srslte_mat_cf_recip_gen(srslte_mat_2x2_det_gen(a00, a01, a10, a11));
/* 2. B = inv(H' x H + No) = inv(A) */
cf_t b00 = a11;
cf_t b01 = -a01;
cf_t b10 = -a10;
cf_t b11 = a00;
cf_t _norm = norm * srslte_mat_cf_recip_gen(srslte_mat_2x2_det_gen(a00, a01, a10, a11));
cf_t _norm = norm * a_det_rcp;
cf_t b00 = a11 * _norm;
cf_t b01 = -a01 * _norm;
cf_t b10 = -a10 * _norm;
cf_t b11 = a00 * _norm;
/* 3. W = inv(H' x H + No) x H' = B x H' */
cf_t w00 = b00 * _h00 + b01 * _h01;
@ -89,8 +89,19 @@ inline void srslte_mat_2x2_mmse_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf_t h
cf_t w11 = b10 * _h10 + b11 * _h11;
/* 4. X = W x Y */
*x0 = (y0 * w00 + y1 * w01) * _norm;
*x1 = (y0 * w10 + y1 * w11) * _norm;
*x0 = (y0 * w00 + y1 * w01);
*x1 = (y0 * w10 + y1 * w11);
/* 5. Set CSI */
*csi0 = 1.0f / crealf(b00);
*csi1 = 1.0f / crealf(b11);
}
/* Generic implementation for Minimum Mean Squared Error (MMSE) solver */
void srslte_mat_2x2_mmse_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf_t h10, cf_t h11,
cf_t *x0, cf_t *x1, float noise_estimate, float norm) {
float csi0, csi1;
srslte_mat_2x2_mmse_csi_gen(y0, y1, h00, h01, h10, h11, x0, x1, &csi0, &csi1, noise_estimate, norm);
}
inline float srslte_mat_2x2_cn(cf_t h00, cf_t h01, cf_t h10, cf_t h11) {

@ -32,8 +32,8 @@
#include <sys/time.h>
#include "srslte/phy/utils/mat.h"
#include "srslte/phy/utils/simd.h"
#include "srslte/phy/utils/vector.h"
#include "srslte/phy/utils/vector_simd.h"
bool zf_solver = false;
@ -378,6 +378,98 @@ bool test_mmse_solver_avx(void) {
#endif /* LV_HAVE_AVX */
#if SRSLTE_SIMD_CF_SIZE != 0
bool test_zf_solver_simd(void) {
cf_t cf_error0, cf_error1;
float error = 0.0f;
cf_t x0_gold_1 = RANDOM_CF();
cf_t x1_gold_1 = RANDOM_CF();
cf_t h00_1 = RANDOM_CF();
cf_t h01_1 = RANDOM_CF();
cf_t h10_1 = RANDOM_CF();
cf_t h11_1 = (1 - h01_1 * h10_1) / h00_1;
cf_t y0_1 = x0_gold_1 * h00_1 + x1_gold_1 * h01_1;
cf_t y1_1 = x0_gold_1 * h10_1 + x1_gold_1 * h11_1;
simd_cf_t _y0 = srslte_simd_cf_set1(y0_1);
simd_cf_t _y1 = srslte_simd_cf_set1(y1_1);
simd_cf_t _h00 = srslte_simd_cf_set1(h00_1);
simd_cf_t _h01 = srslte_simd_cf_set1(h01_1);
simd_cf_t _h10 = srslte_simd_cf_set1(h10_1);
simd_cf_t _h11 = srslte_simd_cf_set1(h11_1);
simd_cf_t _x0, _x1;
srslte_mat_2x2_zf_simd(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 1.0f);
__attribute__((aligned(SRSLTE_SIMD_BIT_ALIGN))) cf_t x0[SRSLTE_SIMD_CF_SIZE];
__attribute__((aligned(SRSLTE_SIMD_BIT_ALIGN))) cf_t x1[SRSLTE_SIMD_CF_SIZE];
srslte_simd_cfi_store(x0, _x0);
srslte_simd_cfi_store(x1, _x1);
cf_error0 = x0[1] - x0_gold_1;
cf_error1 = x1[1] - x1_gold_1;
error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
return (error < 1e-3);
}
bool test_mmse_solver_simd(void) {
cf_t cf_error0, cf_error1;
float error = 0.0f;
cf_t x0_gold[SRSLTE_SIMD_CF_SIZE];
cf_t x1_gold[SRSLTE_SIMD_CF_SIZE];
cf_t h00[SRSLTE_SIMD_CF_SIZE];
cf_t h01[SRSLTE_SIMD_CF_SIZE];
cf_t h10[SRSLTE_SIMD_CF_SIZE];
cf_t h11[SRSLTE_SIMD_CF_SIZE];
cf_t y0[SRSLTE_SIMD_CF_SIZE];
cf_t y1[SRSLTE_SIMD_CF_SIZE];
for (int i = 0; i < SRSLTE_SIMD_CF_SIZE; i++) {
x0_gold[i] = RANDOM_CF();
x1_gold[i] = RANDOM_CF();
h00[i] = RANDOM_CF();
h01[i] = RANDOM_CF();
h10[i] = RANDOM_CF();
h11[i] = (1 - h01[i] * h10[i]) / h00[i];
y0[i] = x0_gold[i] * h00[i]+ x1_gold[i] * h01[i];
y1[i] = x0_gold[i] * h10[i] + x1_gold[i] * h11[i];
}
simd_cf_t _y0 = srslte_simd_cfi_loadu(y0);
simd_cf_t _y1 = srslte_simd_cfi_loadu(y1);
simd_cf_t _h00 = srslte_simd_cfi_loadu(h00);
simd_cf_t _h01 = srslte_simd_cfi_loadu(h01);
simd_cf_t _h10 = srslte_simd_cfi_loadu(h10);
simd_cf_t _h11 = srslte_simd_cfi_loadu(h11);
simd_cf_t _x0, _x1;
srslte_mat_2x2_mmse_simd(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 0.0f, 1.0f);
__attribute__((aligned(SRSLTE_SIMD_BIT_ALIGN))) cf_t x0[SRSLTE_SIMD_CF_SIZE];
__attribute__((aligned(SRSLTE_SIMD_BIT_ALIGN))) cf_t x1[SRSLTE_SIMD_CF_SIZE];
srslte_simd_cfi_store(x0, _x0);
srslte_simd_cfi_store(x1, _x1);
cf_error0 = x0[1] - x0_gold[1];
cf_error1 = x1[1] - x1_gold[1];
error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
return (error < 1e-3);
}
#endif /* SRSLTE_SIMD_CF_SIZE != 0 */
bool test_vec_dot_prod_ccc(void) {
__attribute__((aligned(256))) cf_t a[14];
__attribute__((aligned(256))) cf_t b[14];
@ -413,6 +505,10 @@ int main(int argc, char **argv) {
#ifdef LV_HAVE_AVX
RUN_TEST(test_zf_solver_avx);
#endif /* LV_HAVE_AVX */
#if SRSLTE_SIMD_CF_SIZE != 0
RUN_TEST(test_zf_solver_simd);
#endif /* SRSLTE_SIMD_CF_SIZE != 0*/
}
if (mmse_solver) {
@ -426,6 +522,10 @@ int main(int argc, char **argv) {
#ifdef LV_HAVE_AVX
RUN_TEST(test_mmse_solver_avx);
#endif /* LV_HAVE_AVX */
#if SRSLTE_SIMD_CF_SIZE != 0
RUN_TEST(test_mmse_solver_simd);
#endif /* SRSLTE_SIMD_CF_SIZE != 0*/
}
RUN_TEST(test_vec_dot_prod_ccc);

@ -104,6 +104,12 @@ void srslte_vec_lut_sss(const short *x, const unsigned short *lut, short *y, con
srslte_vec_lut_sss_simd(x, lut, y, len);
}
void srslte_vec_lut_sis(const short *x, const unsigned int *lut, short *y, const uint32_t len) {
for (int i=0; i < len; i++) {
y[lut[i]] = x[i];
}
}
void *srslte_vec_malloc(uint32_t size) {
void *ptr;
if (posix_memalign(&ptr, SRSLTE_SIMD_BIT_ALIGN, size)) {
@ -421,8 +427,8 @@ void srslte_vec_quant_sus(const int16_t *in, uint16_t *out, const float gain, co
}
}
void srs_vec_cf_cpy(const cf_t *dst, cf_t *src, int len) {
srslte_vec_cp_simd(dst, src, len);
void srs_vec_cf_cpy(const cf_t *src, cf_t *dst, int len) {
srslte_vec_cp_simd(src, dst, len);
}
void srslte_vec_interleave(const cf_t *x, const cf_t *y, cf_t *z, const int len) {

@ -51,11 +51,13 @@ bool radio::init(char *args, char *devname, uint32_t nof_channels)
// Suppress radio stdout
srslte_rf_suppress_stdout(&rf_device);
continuous_tx = false;
tx_adv_auto = true;
// Set default preamble length each known device
// We distinguish by device family, maybe we should calibrate per device
if (strstr(srslte_rf_name(&rf_device), "uhd")) {
burst_preamble_sec = uhd_default_burst_preamble_sec;
continuous_tx = true;
} else if (strstr(srslte_rf_name(&rf_device), "bladerf")) {
burst_preamble_sec = blade_default_burst_preamble_sec;
} else {
@ -89,6 +91,7 @@ void radio::reset()
printf("Resetting Radio...\n");
srslte_rf_stop_rx_stream(&rf_device);
radio_is_streaming = false;
usleep(100000);
}
void radio::set_manual_calibration(rf_cal_t* calibration)
@ -110,6 +113,14 @@ void radio::set_burst_preamble(double preamble_us)
burst_preamble_sec = (double) preamble_us/1e6;
}
void radio::set_continuous_tx(bool enable) {
continuous_tx = enable;
}
bool radio::is_continuous_tx() {
return continuous_tx;
}
void radio::set_tx_adv(int nsamples)
{
tx_adv_auto = false;
@ -175,7 +186,7 @@ float radio::set_tx_power(float power)
float radio::get_max_tx_power()
{
return 10;
return 40;
}
float radio::get_rssi()
@ -450,6 +461,10 @@ void radio::set_tx_srate(double srate)
// Calculate TX advance in seconds from samples and sampling rate
tx_adv_sec = nsamples/cur_tx_srate;
if (tx_adv_sec<0) {
tx_adv_sec *= -1;
tx_adv_negative = true;
}
}
void radio::register_error_handler(srslte_rf_error_handler_t h)

@ -60,8 +60,9 @@ void rlc_tm::empty_queue()
// Drop all messages in TX queue
byte_buffer_t *buf;
while(ul_queue.size() > 0) {
ul_queue.read(&buf);
pool->deallocate(buf);
if (ul_queue.try_read(&buf)) {
pool->deallocate(buf);
}
}
}
@ -112,14 +113,18 @@ int rlc_tm::read_pdu(uint8_t *payload, uint32_t nof_bytes)
return 0;
}
byte_buffer_t *buf;
ul_queue.read(&buf);
pdu_size = buf->N_bytes;
memcpy(payload, buf->msg, buf->N_bytes);
log->debug("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
rrc->get_rb_name(lcid).c_str(), buf->get_latency_us());
pool->deallocate(buf);
log->info_hex(payload, pdu_size, "TX %s, %s PDU", rrc->get_rb_name(lcid).c_str(), rlc_mode_text[RLC_MODE_TM]);
return pdu_size;
if (ul_queue.try_read(&buf)) {
pdu_size = buf->N_bytes;
memcpy(payload, buf->msg, buf->N_bytes);
log->debug("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
rrc->get_rb_name(lcid).c_str(), buf->get_latency_us());
pool->deallocate(buf);
log->info_hex(payload, pdu_size, "TX %s, %s PDU", rrc->get_rb_name(lcid).c_str(), rlc_mode_text[RLC_MODE_TM]);
return pdu_size;
} else {
log->warning("Queue empty while trying to read\n");
return 0;
}
}
void rlc_tm::write_pdu(uint8_t *payload, uint32_t nof_bytes)

@ -43,7 +43,7 @@ private:
bool new_allocation(uint32_t nof_rbg, uint32_t* rbgmask);
void update_allocation(uint32_t new_mask);
bool allocation_is_valid(uint32_t mask);
dl_harq_proc* apply_user_allocation(sched_ue *user);
uint32_t get_required_rbg(sched_ue *user, uint32_t tti);
uint32_t count_rbg(uint32_t mask);
@ -51,7 +51,6 @@ private:
bool used_rb[MAX_RBG];
uint32_t nof_users_with_data;
uint32_t current_tti;
uint32_t total_rb;
@ -72,8 +71,8 @@ private:
bool new_allocation(uint32_t L, ul_harq_proc::ul_alloc_t *alloc);
bool allocation_is_valid(ul_harq_proc::ul_alloc_t alloc);
ul_harq_proc* apply_user_allocation(sched_ue *user);
uint32_t nof_users_with_data;
bool used_rb[MAX_PRB];
uint32_t current_tti;

@ -40,7 +40,8 @@ class sched_ue {
public:
// used by sched_metric
uint32_t ue_idx;
dl_harq_proc* dl_next_alloc;
ul_harq_proc* ul_next_alloc;
bool has_pucch;

@ -95,7 +95,7 @@ public:
bool process_pdus();
uint8_t *request_buffer(uint32_t tti, uint32_t len);
void process_pdu(uint8_t *pdu, uint32_t nof_bytes, uint32_t tstamp);
void process_pdu(uint8_t *pdu, uint32_t nof_bytes, srslte::pdu_queue::channel_t channel, uint32_t tstamp);
void push_pdu(uint32_t tti, uint32_t len);
void deallocate_pdu(uint32_t tti);

@ -32,7 +32,6 @@
#include "srslte/common/buffer_pool.h"
#include "srslte/common/log.h"
#include "srslte/common/common.h"
#include "srslte/common/msg_queue.h"
#include "srslte/common/threads.h"
#include "srslte/interfaces/enb_interfaces.h"
#include "common_enb.h"

@ -78,7 +78,6 @@ uint32_t dl_metric_rr::get_required_rbg(sched_ue *user, uint32_t tti)
void dl_metric_rr::new_tti(std::map<uint16_t,sched_ue> &ue_db, uint32_t start_rb, uint32_t nof_rb, uint32_t nof_ctrl_symbols_, uint32_t tti)
{
total_rb = start_rb+nof_rb;
for (uint32_t i=0;i<total_rb;i++) {
if (i<start_rb) {
@ -92,13 +91,19 @@ void dl_metric_rr::new_tti(std::map<uint16_t,sched_ue> &ue_db, uint32_t start_rb
current_tti = tti;
nof_ctrl_symbols = nof_ctrl_symbols_;
nof_users_with_data = 0;
for(std::map<uint16_t, sched_ue>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
sched_ue *user = (sched_ue*) &iter->second;
if (user->get_pending_dl_new_data(current_tti) || user->get_pending_dl_harq(current_tti)) {
user->ue_idx = nof_users_with_data;
nof_users_with_data++;
if(ue_db.size()==0)
return;
// give priority in a time-domain RR basis
uint32_t priority_idx = current_tti % ue_db.size();
std::map<uint16_t, sched_ue>::iterator iter = ue_db.begin();
std::advance(iter,priority_idx);
for(uint32_t ue_count = 0 ; ue_count < ue_db.size() ; ++iter, ++ue_count) {
if(iter==ue_db.end()) {
iter = ue_db.begin(); // wrap around
}
sched_ue *user = (sched_ue*) &iter->second;
user->dl_next_alloc = apply_user_allocation(user);
}
}
@ -136,24 +141,10 @@ bool dl_metric_rr::allocation_is_valid(uint32_t mask)
return (mask & used_rb_mask);
}
dl_harq_proc* dl_metric_rr::get_user_allocation(sched_ue *user)
{
dl_harq_proc* dl_metric_rr::apply_user_allocation(sched_ue *user) {
uint32_t pending_data = user->get_pending_dl_new_data(current_tti);
dl_harq_proc *h = user->get_pending_dl_harq(current_tti);
// Time-domain RR scheduling
#if ASYNC_DL_SCHED
if (pending_data || h) {
#else
if (pending_data || (h && !h->is_empty())) {
#endif
if (nof_users_with_data) {
if ((current_tti%nof_users_with_data) != user->ue_idx) {
return NULL;
}
}
}
// Schedule retx if we have space
#if ASYNC_DL_SCHED
if (h) {
@ -166,6 +157,7 @@ dl_harq_proc* dl_metric_rr::get_user_allocation(sched_ue *user)
update_allocation(retx_mask);
return h;
}
// If not, try to find another mask in the current tti
uint32_t nof_rbg = count_rbg(retx_mask);
if (nof_rbg < available_rb) {
@ -181,7 +173,7 @@ dl_harq_proc* dl_metric_rr::get_user_allocation(sched_ue *user)
h = user->get_empty_dl_harq();
if (h) {
#else
if (h && h->is_empty()) {
if (h && h->is_empty()) {
#endif
// Allocate resources based on pending data
if (pending_data) {
@ -195,9 +187,15 @@ dl_harq_proc* dl_metric_rr::get_user_allocation(sched_ue *user)
}
}
}
return NULL;
}
dl_harq_proc* dl_metric_rr::get_user_allocation(sched_ue *user)
{
return user->dl_next_alloc;
}
@ -219,15 +217,20 @@ void ul_metric_rr::new_tti(std::map<uint16_t,sched_ue> &ue_db, uint32_t nof_rb_,
available_rb = nof_rb_;
bzero(used_rb, nof_rb*sizeof(bool));
nof_users_with_data = 0;
for(std::map<uint16_t, sched_ue>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
sched_ue *user = (sched_ue*) &iter->second;
if (user->get_pending_ul_new_data(current_tti) || !user->get_ul_harq(current_tti)->is_empty(0)) {
user->ue_idx = nof_users_with_data;
nof_users_with_data++;
if(ue_db.size()==0)
return;
// give priority in a time-domain RR basis
uint32_t priority_idx = (current_tti+ue_db.size()/2) % ue_db.size(); // make DL and UL interleaved
std::map<uint16_t, sched_ue>::iterator iter = ue_db.begin();
std::advance(iter,priority_idx);
for(uint32_t ue_count = 0 ; ue_count < ue_db.size() ; ++iter, ++ue_count) {
if(iter==ue_db.end()) {
iter = ue_db.begin(); // wrap around
}
sched_ue *user = (sched_ue*) &iter->second;
user->ul_next_alloc = apply_user_allocation(user);
}
}
bool ul_metric_rr::allocation_is_valid(ul_harq_proc::ul_alloc_t alloc)
@ -288,24 +291,13 @@ void ul_metric_rr::update_allocation(ul_harq_proc::ul_alloc_t alloc)
available_rb -= alloc.L;
}
ul_harq_proc* ul_metric_rr::get_user_allocation(sched_ue *user)
{
ul_harq_proc* ul_metric_rr::apply_user_allocation(sched_ue *user) {
// Time-domain RR scheduling
uint32_t pending_data = user->get_pending_ul_new_data(current_tti);
ul_harq_proc *h = user->get_ul_harq(current_tti);
if (pending_data || !h->is_empty(0)) {
if (nof_users_with_data) {
if ((current_tti%nof_users_with_data) != user->ue_idx) {
return NULL;
}
}
}
// Schedule retx if we have space
if (!h->is_empty(0)) {
ul_harq_proc::ul_alloc_t alloc = h->get_alloc();
// If can schedule the same mask, do it
@ -321,6 +313,7 @@ ul_harq_proc* ul_metric_rr::get_user_allocation(sched_ue *user)
return h;
}
}
// If could not schedule the reTx, or there wasn't any pending retx, find an empty PID
if (h->is_empty(0)) {
// Allocate resources based on pending data
@ -338,6 +331,9 @@ ul_harq_proc* ul_metric_rr::get_user_allocation(sched_ue *user)
return NULL;
}
ul_harq_proc* ul_metric_rr::get_user_allocation(sched_ue *user)
{
return user->ul_next_alloc;
}
}

@ -49,7 +49,7 @@ namespace srsenb {
*
*******************************************************/
sched_ue::sched_ue() : ue_idx(0), has_pucch(false), power_headroom(0), rnti(0), max_mcs_dl(0), max_mcs_ul(0),
sched_ue::sched_ue() : dl_next_alloc(NULL), ul_next_alloc(NULL), has_pucch(false), power_headroom(0), rnti(0), max_mcs_dl(0), max_mcs_ul(0),
fixed_mcs_ul(0), fixed_mcs_dl(0), phy_config_dedicated_enabled(false)
{
log_h = NULL;

@ -142,7 +142,7 @@ void ue::set_tti(uint32_t tti) {
#include <assert.h>
void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, uint32_t tstamp)
void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, srslte::pdu_queue::channel_t channel, uint32_t tstamp)
{
// Unpack ULSCH MAC PDU
mac_msg_ul.init_rx(nof_bytes, true);

@ -121,7 +121,7 @@ uint32_t rrc::generate_sibs()
// msg is array of SI messages, each SI message msg[i] may contain multiple SIBs
// all SIBs in a SI message msg[i] share the same periodicity
LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT *msg = (LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT*)calloc(nof_messages, sizeof(LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT));
LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT *msg = (LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT*)calloc(nof_messages+1, sizeof(LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT));
// Copy SIB1 to first SI message
msg[0].N_sibs = 1;
@ -1090,9 +1090,13 @@ void rrc::ue::notify_s1ap_ue_ctxt_setup_complete()
void rrc::ue::notify_s1ap_ue_erab_setup_response(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e)
{
LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT res;
res.ext=false;
res.E_RABSetupListBearerSURes.len = 0;
res.E_RABFailedToSetupListBearerSURes.len = 0;
res.CriticalityDiagnostics_present = false;
res.E_RABFailedToSetupListBearerSURes_present = false;
for(uint32_t i=0; i<e->len; i++) {
res.E_RABSetupListBearerSURes_present = true;
LIBLTE_S1AP_E_RABTOBESETUPITEMBEARERSUREQ_STRUCT *erab = &e->buffer[i];
@ -1447,6 +1451,8 @@ void rrc::ue::send_connection_reconf(srslte::byte_buffer_t *pdu)
// Get DRB1 configuration
if (get_drbid_config(&conn_reconf->rr_cnfg_ded.drb_to_add_mod_list[0], 1)) {
parent->rrc_log->error("Getting DRB1 configuration\n");
printf("The QCI %d for DRB1 is invalid or not configured.\n", erabs[5].qos_params.qCI.QCI);
return;
} else {
conn_reconf->rr_cnfg_ded.drb_to_add_mod_list_size = 1;
}
@ -1524,8 +1530,10 @@ void rrc::ue::send_connection_reconf_new_bearer(LIBLTE_S1AP_E_RABTOBESETUPLISTBE
uint8_t lcid = id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1)
// Get DRB configuration
if (get_drbid_config(&conn_reconf->rr_cnfg_ded.drb_to_add_mod_list[i], lcid)) {
if (get_drbid_config(&conn_reconf->rr_cnfg_ded.drb_to_add_mod_list[i], lcid-2)) {
parent->rrc_log->error("Getting DRB configuration\n");
printf("ERROR: The QCI %d is invalid or not configured.\n", erabs[lcid+4].qos_params.qCI.QCI);
return;
} else {
conn_reconf->rr_cnfg_ded.drb_to_add_mod_list_size++;
}

@ -1806,7 +1806,7 @@ s1ap_nas_transport::pack_attach_accept(ue_emm_ctx_t *ue_emm_ctx, ue_ecm_ctx_t *u
act_def_eps_bearer_context_req.eps_qos.mbr_dl_ext = 250; //FIXME check
//set apn
act_def_eps_bearer_context_req.apn.apn = m_s1ap->m_s1ap_args.mme_apn;
strncpy(act_def_eps_bearer_context_req.apn.apn, m_s1ap->m_s1ap_args.mme_apn.c_str(), LIBLTE_STRING_LEN);
act_def_eps_bearer_context_req.proc_transaction_id = ue_emm_ctx->procedure_transaction_id; //FIXME
//Set DNS server
@ -1933,10 +1933,10 @@ s1ap_nas_transport::pack_emm_information( ue_ctx_t *ue_ctx, srslte::byte_buffer_
LIBLTE_MME_EMM_INFORMATION_MSG_STRUCT emm_info;
emm_info.full_net_name_present = true;
emm_info.full_net_name.name = std::string("Software Radio Systems LTE");
strncpy(emm_info.full_net_name.name, "Software Radio Systems LTE", LIBLTE_STRING_LEN);
emm_info.full_net_name.add_ci = LIBLTE_MME_ADD_CI_DONT_ADD;
emm_info.short_net_name_present = true;
emm_info.short_net_name.name = std::string("srsLTE");
strncpy(emm_info.short_net_name.name, "srsLTE", LIBLTE_STRING_LEN);
emm_info.short_net_name.add_ci = LIBLTE_MME_ADD_CI_DONT_ADD;
emm_info.local_time_zone_present = false;

@ -51,12 +51,13 @@ public:
void push_pdu(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp);
void push_pdu_bcch(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp);
void push_pdu_mch(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp);
void push_pdu_temp_crnti(uint8_t *buff, uint32_t nof_bytes);
void set_uecrid_callback(bool (*callback)(void*, uint64_t), void *arg);
bool get_uecrid_successful();
void process_pdu(uint8_t *pdu, uint32_t nof_bytes, uint32_t tstamp);
void process_pdu(uint8_t *pdu, uint32_t nof_bytes, srslte::pdu_queue::channel_t channel, uint32_t tstamp);
private:
const static int MAX_PDU_LEN = 150*1024/8; // ~ 150 Mbps

@ -50,7 +50,7 @@ class mac
,public mac_interface_rrc
,public srslte::timer_callback
,public srslte::mac_interface_timers
,public thread
,public periodic_thread
{
public:
mac();
@ -68,15 +68,13 @@ public:
void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid);
void bch_decoded_ok(uint8_t *payload, uint32_t len);
void pch_decoded_ok(uint32_t len);
void tti_clock(uint32_t tti);
/******** Interface from RLC (RLC -> MAC) ****************/
void bcch_start_rx();
void bcch_stop_rx();
void bcch_start_rx(int si_window_start, int si_window_length);
void pcch_start_rx();
void pcch_stop_rx();
void clear_rntis();
void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD);
void reconfiguration();
void reset();
@ -110,14 +108,13 @@ public:
private:
void run_thread();
void run_period();
static const int MAC_MAIN_THREAD_PRIO = -1; // Use default high-priority below UHD
static const int MAC_PDU_THREAD_PRIO = DEFAULT_PRIORITY-5;
static const int MAC_NOF_HARQ_PROC = 2*HARQ_DELAY_MS;
// Interaction with PHY
srslte::tti_sync_cv ttisync;
phy_interface_mac *phy_h;
rlc_interface_mac *rlc_h;
rrc_interface_mac *rrc_h;
@ -130,10 +127,6 @@ private:
ue_rnti_t uernti;
uint32_t tti;
bool started;
bool is_synchronized;
uint16_t last_temporal_crnti;
uint16_t phy_rnti;
/* Multiplexing/Demultiplexing Units */
mux mux_unit;
@ -168,19 +161,6 @@ private:
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:

@ -27,9 +27,6 @@
#ifndef SRSUE_PHCH_COMMON_H
#define SRSUE_PHCH_COMMON_H
#define TX_MODE_CONTINUOUS 1
#include <pthread.h>
#include <string.h>
#include <vector>
@ -68,15 +65,17 @@ public:
float cur_radio_power;
float cur_pusch_power;
float avg_rsrp;
float avg_rsrp_cqi;
float avg_rsrp_dbm;
float avg_rsrp_sync_dbm;
float avg_rsrq_db;
float avg_rssi_dbm;
float last_radio_rssi;
float rx_gain_offset;
float avg_snr_db;
float avg_snr_db_cqi;
float avg_snr_db_sync;
float avg_noise;
bool pcell_meas_enabled;
uint32_t pcell_report_period;
// Save last TBS for mcs>28 cases

@ -28,6 +28,7 @@
#define SRSUE_PHCH_RECV_H
#include <map>
#include <pthread.h>
#include "srslte/srslte.h"
#include "srslte/common/log.h"
@ -50,29 +51,23 @@ class phch_recv : public thread, public chest_feedback_itf
public:
phch_recv();
~phch_recv();
void init(srslte::radio_multi* radio_handler, mac_interface_phy *mac,rrc_interface_phy *rrc,
prach *prach_buffer, srslte::thread_pool *_workers_pool,
phch_common *_worker_com, srslte::log* _log_h, srslte::log *_log_phy_lib_h, uint32_t nof_rx_antennas, uint32_t prio, int sync_cpu_affinity = -1);
void stop();
void set_agc_enable(bool enable);
void set_earfcn(std::vector<uint32_t> earfcn);
void force_freq(float dl_freq, float ul_freq);
void radio_overflow();
void reset_sync();
void cell_search_start();
void cell_search_next(bool reset = false);
void cell_select(uint32_t earfcn, srslte_cell_t cell);
bool cell_handover(srslte_cell_t cell);
// RRC interface for controling the SYNC state
phy_interface_rrc::cell_search_ret_t cell_search(phy_interface_rrc::phy_cell_t *cell);
bool cell_select(phy_interface_rrc::phy_cell_t *cell);
bool cell_is_camping();
// RRC interface for controlling the neighbour cell measurement
void meas_reset();
int meas_start(uint32_t earfcn, int pci);
int meas_stop(uint32_t earfcn, int pci);
uint32_t get_current_tti();
bool status_is_sync();
// from chest_feedback_itf
void in_sync();
void out_of_sync();
@ -80,37 +75,21 @@ public:
void set_time_adv_sec(float time_adv_sec);
void get_current_cell(srslte_cell_t *cell, uint32_t *earfcn = NULL);
uint32_t get_current_tti();
// From UE configuration
void set_agc_enable(bool enable);
void set_earfcn(std::vector<uint32_t> earfcn);
void force_freq(float dl_freq, float ul_freq);
// Other functions
const static int MUTEX_X_WORKER = 4;
double set_rx_gain(double gain);
int radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time);
int scell_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time);
private:
std::vector<uint32_t> earfcn;
void reset();
void radio_error();
void set_ue_sync_opts(srslte_ue_sync_t *q, float cfo);
void run_thread();
void set_sampling_rate();
bool set_frequency();
bool set_cell();
void cell_search_inc();
void cell_reselect();
float get_cfo();
uint32_t new_earfcn;
srslte_cell_t new_cell;
bool running;
// Class to run cell search
class search {
public:
@ -119,9 +98,7 @@ private:
~search();
void init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, phch_recv *parent);
void reset();
float get_last_gain();
float get_last_cfo();
void set_N_id_2(int N_id_2);
void set_agc_enable(bool enable);
ret_code run(srslte_cell_t *cell);
@ -137,22 +114,23 @@ private:
// Class to synchronize system frame number
class sfn_sync {
public:
typedef enum {IDLE, SFN_FOUND, SFX0_FOUND, ERROR, TIMEOUT} ret_code;
typedef enum {IDLE, SFN_FOUND, SFX0_FOUND, SFN_NOFOUND, ERROR} ret_code;
~sfn_sync();
void init(srslte_ue_sync_t *ue_sync, cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t timeout = SYNC_SFN_TIMEOUT);
void init(srslte_ue_sync_t *ue_sync, cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_subframes = SFN_SYNC_NOF_SUBFRAMES);
void reset();
bool set_cell(srslte_cell_t cell);
ret_code run_subframe(srslte_cell_t *cell, uint32_t *tti_cnt, bool sfidx_only = false);
private:
const static int SFN_SYNC_NOF_SUBFRAMES = 100;
uint32_t cnt;
uint32_t timeout;
srslte::log *log_h;
srslte_ue_sync_t *ue_sync;
cf_t *buffer[SRSLTE_MAX_PORTS];
srslte_ue_mib_t ue_mib;
uint32_t cnt;
uint32_t timeout;
const static uint32_t SYNC_SFN_TIMEOUT = 80;
};
// Class to perform cell measurements
@ -170,7 +148,7 @@ private:
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, int offset, uint32_t sf_idx, uint32_t nof_sf);
ret_code run_multiple_subframes(cf_t *buffer, uint32_t offset, uint32_t sf_idx, uint32_t nof_sf);
float rssi();
float rsrp();
float rsrq();
@ -261,9 +239,26 @@ private:
// 36.133 9.1.2.1 for band 7
const static float ABSOLUTE_RSRP_THRESHOLD_DBM = -125;
std::vector<uint32_t> earfcn;
void reset();
void radio_error();
void set_ue_sync_opts(srslte_ue_sync_t *q, float cfo);
void run_thread();
float get_tx_cfo();
void set_sampling_rate();
bool set_frequency();
bool set_cell();
uint32_t new_earfcn;
srslte_cell_t new_cell;
bool radio_is_overflow;
bool radio_overflow_return;
bool running;
// Objects for internal use
measure measure_p;
search search_p;
sfn_sync sfn_p;
intra_measure intra_freq_meas;
@ -298,19 +293,128 @@ private:
const static uint32_t NOF_OUT_OF_SYNC_SF = 200;
const static uint32_t NOF_IN_SYNC_SF = 100;
// State for primary cell
typedef enum {
IDLE = 0,
CELL_SEARCH,
CELL_SELECT,
CELL_RESELECT,
CELL_MEASURE,
CELL_CAMP,
} phy_state_t;
// State machine for SYNC thread
class sync_state {
public:
typedef enum {
IDLE = 0,
CELL_SEARCH,
SFN_SYNC,
CAMPING,
} state_t;
/* Run_state is called by the main thread at the start of each loop. It updates the state
* and returns the current state
*/
state_t run_state() {
pthread_mutex_lock(&inside);
cur_state = next_state;
pthread_cond_broadcast(&cvar);
pthread_mutex_unlock(&inside);
return cur_state;
}
// Called by the main thread at the end of each state to indicate it has finished.
void state_exit(bool exit_ok = true) {
pthread_mutex_lock(&inside);
if (cur_state == SFN_SYNC && exit_ok == true) {
next_state = CAMPING;
} else {
next_state = IDLE;
}
pthread_mutex_unlock(&inside);
}
void force_sfn_sync() {
pthread_mutex_lock(&inside);
next_state = SFN_SYNC;
pthread_mutex_unlock(&inside);
}
/* Functions to be called from outside the STM thread to instruct the STM to switch state.
* The functions change the state and wait until it has changed it.
*
* These functions are mutexed and only 1 can be called at a time
*/
void go_idle() {
pthread_mutex_lock(&outside);
go_state(IDLE);
pthread_mutex_unlock(&outside);
}
void run_cell_search() {
pthread_mutex_lock(&outside);
go_state(CELL_SEARCH);
wait_state_change(CELL_SEARCH);
pthread_mutex_unlock(&outside);
}
void run_sfn_sync() {
pthread_mutex_lock(&outside);
go_state(SFN_SYNC);
wait_state_change(SFN_SYNC);
pthread_mutex_unlock(&outside);
}
/* Helpers below this */
bool is_idle() {
return cur_state == IDLE;
}
bool is_camping() {
return cur_state == CAMPING;
}
const char *to_string() {
switch(cur_state) {
case IDLE:
return "IDLE";
case CELL_SEARCH:
return "SEARCH";
case SFN_SYNC:
return "SYNC";
case CAMPING:
return "CAMPING";
default:
return "UNKNOWN";
}
}
sync_state() {
pthread_mutex_init(&inside, NULL);
pthread_mutex_init(&outside, NULL);
pthread_cond_init(&cvar, NULL);
cur_state = IDLE;
next_state = IDLE;
}
private:
void go_state(state_t s) {
pthread_mutex_lock(&inside);
next_state = s;
while(cur_state != s) {
pthread_cond_wait(&cvar, &inside);
}
pthread_mutex_unlock(&inside);
}
/* Waits until there is a call to set_state() and then run_state(). Returns when run_state() returns */
void wait_state_change(state_t prev_state) {
pthread_mutex_lock(&inside);
while(cur_state == prev_state) {
pthread_cond_wait(&cvar, &inside);
}
pthread_mutex_unlock(&inside);
}
state_t cur_state, next_state;
pthread_mutex_t inside, outside;
pthread_cond_t cvar;
};
pthread_mutex_t rrc_mutex;
phy_state_t phy_state, prev_state;
sync_state phy_state;
bool is_in_idle;
search::ret_code cell_search_ret;
// Sampling rate mode (find is 1.96 MHz, camp is the full cell BW)
enum {
@ -320,9 +424,8 @@ private:
// This is the primary cell
srslte_cell_t cell;
bool cell_is_set;
bool started;
float time_adv_sec;
float time_adv_sec, next_time_adv_sec;
uint32_t tti;
bool do_agc;
@ -330,8 +433,8 @@ private:
uint32_t tx_mutex_cnt;
float ul_dl_factor;
uint32_t current_earfcn;
int cur_earfcn_index;
int current_earfcn;
uint32_t cellsearch_earfcn_index;
float dl_freq;
float ul_freq;

@ -53,6 +53,7 @@ public:
cf_t* get_buffer(uint32_t antenna_idx);
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_prach(cf_t *prach_ptr, float prach_power);
void set_cfo(float cfo);
void set_ul_params(bool pregen_disabled = false);
@ -169,6 +170,8 @@ private:
bool sr_configured;
float cfo;
bool rar_cqi_request;
cf_t *prach_ptr;
float prach_power;
uint32_t rssi_read_cnt;

@ -82,21 +82,18 @@ public:
/********** RRC INTERFACE ********************/
void reset();
void sync_reset();
void configure_ul_params(bool pregen_disabled = false);
void cell_search_start();
void cell_search_next();
void cell_select(uint32_t earfcn, srslte_cell_t phy_cell);
bool cell_handover(srslte_cell_t cell);
cell_search_ret_t cell_search(phy_cell_t *cell);
bool cell_select(phy_cell_t *cell);
void meas_reset();
int meas_start(uint32_t earfcn, int pci);
int meas_stop(uint32_t earfcn, int pci);
/********** MAC INTERFACE ********************/
/* Functions to synchronize with a cell */
bool sync_status(); // this is also RRC interface
// also MAC interface
bool cell_is_camping();
/********** MAC INTERFACE ********************/
/* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */
void set_crnti(uint16_t rnti);

@ -58,14 +58,12 @@ namespace srsue {
bool is_ready_to_send(uint32_t current_tti);
bool is_pending();
int tx_tti();
void send(srslte::radio* radio_handler, float cfo, float pathloss, srslte_timestamp_t rx_time);
float get_p0_preamble();
static const uint32_t tx_advance_sf = 4; // Number of subframes to advance transmission
cf_t* generate(float cfo, uint32_t *nof_sf, float *target_power = NULL);
private:
const static int MAX_LEN_SF = 3;
LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config;
phy_args_t *args;
@ -81,7 +79,7 @@ namespace srsue {
srslte_cell_t cell;
cf_t *signal_buffer;
srslte_cfo_t cfo_h;
float target_power_dbm;
float target_power_dbm;
};

@ -69,6 +69,8 @@ public:
bool init(all_args_t *args_);
void stop();
bool attach();
bool deattach();
bool is_attached();
void start_plot();

@ -64,6 +64,7 @@ typedef struct {
std::string device_args;
std::string time_adv_nsamples;
std::string burst_preamble;
std::string continuous_tx;
}rf_args_t;
typedef struct {
@ -112,6 +113,7 @@ typedef struct {
phy_args_t phy;
float metrics_period_secs;
bool pregenerate_signals;
bool print_buffer_state;
bool metrics_csv_enable;
std::string metrics_csv_filename;
}expert_args_t;
@ -155,6 +157,8 @@ public:
virtual bool init(all_args_t *args_) = 0;
virtual void stop() = 0;
virtual bool attach() = 0;
virtual bool deattach() = 0;
virtual bool is_attached() = 0;
virtual void start_plot() = 0;

@ -30,7 +30,6 @@
#include "srslte/common/buffer_pool.h"
#include "srslte/common/log.h"
#include "srslte/common/common.h"
#include "srslte/common/msg_queue.h"
#include "srslte/common/interfaces_common.h"
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/threads.h"

@ -43,29 +43,20 @@ namespace srsue {
typedef enum {
EMM_STATE_NULL = 0,
EMM_STATE_DEREGISTERED,
EMM_STATE_REGISTERED_INITIATED,
EMM_STATE_REGISTERED,
EMM_STATE_SERVICE_REQUEST_INITIATED,
EMM_STATE_DEREGISTERED_INITIATED,
EMM_STATE_TAU_INITIATED,
EMM_STATE_N_ITEMS,
} emm_state_t;
static const char emm_state_text[EMM_STATE_N_ITEMS][100] = {"NULL",
"DEREGISTERED",
"REGISTERED INITIATED",
"REGISTERED",
"SERVICE REQUEST INITIATED",
"DEREGISTERED INITIATED",
"TRACKING AREA UPDATE INITIATED"};
static const bool eia_caps[8] = {false, true, true, false, false, false, false, false};
static const bool eea_caps[8] = {true, true, true, false, false, false, false, false};
typedef enum {
PLMN_NOT_SELECTED = 0,
PLMN_SELECTED
} plmn_selection_state_t;
class nas
: public nas_interface_rrc,
public nas_interface_ue,
@ -83,20 +74,16 @@ public:
emm_state_t get_state();
// RRC interface
void notify_connection_setup();
void paging(LIBLTE_RRC_S_TMSI_STRUCT *ue_identiy);
void set_barring(barring_t barring);
void write_pdu(uint32_t lcid, byte_buffer_t *pdu);
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);
bool plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code);
void plmn_search_end();
// UE interface
void attach_request();
void deattach_request();
bool attach_request();
bool deattach_request();
// PCAP
void start_pcap(srslte::nas_pcap *pcap_);
@ -112,9 +99,10 @@ private:
emm_state_t state;
plmn_selection_state_t plmn_selection;
nas_interface_rrc::barring_t current_barring;
bool plmn_is_selected;
LIBLTE_RRC_PLMN_IDENTITY_STRUCT current_plmn;
LIBLTE_RRC_PLMN_IDENTITY_STRUCT selecting_plmn;
LIBLTE_RRC_PLMN_IDENTITY_STRUCT home_plmn;
std::vector<LIBLTE_RRC_PLMN_IDENTITY_STRUCT > known_plmns;
@ -148,6 +136,10 @@ private:
// PCAP
srslte::nas_pcap *pcap = NULL;
bool running;
bool rrc_connect();
void integrity_generate(uint8_t *key_128,
uint32_t count,
uint8_t direction,
@ -160,6 +152,8 @@ private:
bool check_cap_replay(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT *caps);
void select_plmn();
// Parsers
void parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu);
void parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu);
@ -171,10 +165,12 @@ private:
void parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu);
void parse_emm_information(uint32_t lcid, byte_buffer_t *pdu);
// Packet generators
void gen_attach_request(byte_buffer_t *msg);
void gen_service_request(byte_buffer_t *msg);
// Senders
void send_attach_request();
void send_identity_response();
void send_service_request();
void send_esm_information_response();
void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg);
void send_security_mode_reject(uint8_t cause);

@ -36,6 +36,7 @@
#include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/security.h"
#include "srslte/common/threads.h"
#include "srslte/common/block_queue.h"
#include <math.h>
#include <map>
@ -52,21 +53,21 @@ using srslte::byte_buffer_t;
namespace srsue {
class cell_t
{
public:
bool is_valid() {
return earfcn != 0 && srslte_cell_isvalid(&phy_cell);
return phy_cell.earfcn != 0 && srslte_cell_isvalid(&phy_cell.cell);
}
bool equals(cell_t *x) {
return equals(x->earfcn, x->phy_cell.id);
return equals(x->phy_cell.earfcn, x->phy_cell.cell.id);
}
bool equals(uint32_t earfcn, uint32_t pci) {
return earfcn == this->earfcn && pci == phy_cell.id;
return earfcn == this->phy_cell.earfcn && pci == phy_cell.cell.id;
}
// NaN means an RSRP value has not yet been obtained. Keep then in the list and clean them if never updated
bool greater(cell_t *x) {
return rsrp > x->rsrp;
return rsrp > x->rsrp || isnan(rsrp);
}
bool plmn_equals(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) {
if (has_valid_sib1) {
@ -78,11 +79,39 @@ class cell_t
}
return false;
}
uint32_t nof_plmns() {
if (has_valid_sib1) {
return sib1.N_plmn_ids;
} else {
return 0;
}
}
LIBLTE_RRC_PLMN_IDENTITY_STRUCT get_plmn(uint32_t idx) {
if (idx < sib1.N_plmn_ids && has_valid_sib1) {
return sib1.plmn_id[idx].id;
} else {
LIBLTE_RRC_PLMN_IDENTITY_STRUCT null;
null.mnc = 0;
null.mcc = 0;
return null;
}
}
uint16_t get_tac() {
if (has_valid_sib1) {
return sib1.tracking_area_code;
} else {
return 0;
}
}
cell_t() {
srslte_cell_t tmp = {};
cell_t(tmp, 0, 0);
phy_interface_rrc::phy_cell_t tmp = {};
cell_t(tmp, 0);
}
cell_t(srslte_cell_t phy_cell, uint32_t earfcn, float rsrp) {
cell_t(phy_interface_rrc::phy_cell_t phy_cell, float rsrp) {
gettimeofday(&last_update, NULL);
this->has_valid_sib1 = false;
this->has_valid_sib2 = false;
@ -90,7 +119,6 @@ class cell_t
this->has_valid_sib13 = false;
this->phy_cell = phy_cell;
this->rsrp = rsrp;
this->earfcn = earfcn;
in_sync = true;
bzero(&sib1, sizeof(sib1));
bzero(&sib2, sizeof(sib2));
@ -99,15 +127,15 @@ class cell_t
}
uint32_t get_earfcn() {
return earfcn;
return phy_cell.earfcn;
}
uint32_t get_pci() {
return phy_cell.id;
return phy_cell.cell.id;
}
void set_rsrp(float rsrp) {
if (~isnan(rsrp)) {
if (!isnan(rsrp)) {
this->rsrp = rsrp;
}
in_sync = true;
@ -170,6 +198,20 @@ class cell_t
return has_valid_sib13;
}
bool has_sib(uint32_t index) {
switch(index) {
case 0:
return has_sib1();
case 1:
return has_sib2();
case 2:
return has_sib3();
case 12:
return has_sib13();
}
return false;
}
uint16_t get_mcc() {
if (has_valid_sib1) {
if (sib1.N_plmn_ids > 0) {
@ -188,12 +230,11 @@ class cell_t
return 0;
}
srslte_cell_t phy_cell;
phy_interface_rrc::phy_cell_t phy_cell;
bool in_sync;
private:
float rsrp;
uint32_t earfcn;
struct timeval last_update;
bool has_valid_sib1;
@ -231,56 +272,61 @@ public:
void stop();
rrc_state_t get_state();
void set_args(rrc_args_t *args);
// Timeout callback interface
void timer_expired(uint32_t timeout_id);
void liblte_rrc_log(char *str);
// NAS interface
void write_sdu(uint32_t lcid, byte_buffer_t *sdu);
void enable_capabilities();
uint16_t get_mcc();
uint16_t get_mnc();
void enable_capabilities();
void plmn_search();
void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, bool connect_request);
int plmn_search(found_plmn_t found_plmns[MAX_FOUND_PLMNS]);
void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id);
bool connection_request(LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM cause,
srslte::byte_buffer_t *dedicatedInfoNAS);
void set_ue_idenity(LIBLTE_RRC_S_TMSI_STRUCT s_tmsi);
// PHY interface
void in_sync();
void out_of_sync();
void earfcn_end();
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
void ho_ra_completed(bool ra_successful);
void release_pucch_srs();
void run_tti(uint32_t tti);
void ra_problem();
// GW interface
bool is_connected();
bool is_connected(); // this is also NAS interface
bool have_drb();
// PDCP interface
void write_pdu(uint32_t lcid, byte_buffer_t *pdu);
void write_pdu_bcch_bch(byte_buffer_t *pdu);
void write_pdu_bcch_dlsch(byte_buffer_t *pdu);
void write_pdu_pcch(byte_buffer_t *pdu);
private:
typedef struct {
enum {
PCCH,
STOP
} command;
byte_buffer_t *pdu;
} cmd_msg_t;
bool running;
srslte::block_queue<cmd_msg_t> cmd_q;
void run_thread();
void process_pcch(byte_buffer_t *pdu);
srslte::byte_buffer_pool *pool;
srslte::log *rrc_log;
phy_interface_rrc *phy;
@ -295,6 +341,8 @@ private:
LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg;
LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg;
byte_buffer_t *dedicatedInfoNAS;
byte_buffer_t* byte_align_and_pack();
void send_ul_ccch_msg();
void send_ul_dcch_msg();
@ -304,28 +352,22 @@ private:
rrc_state_t state;
uint8_t transaction_id;
LIBLTE_RRC_S_TMSI_STRUCT ueIdentity;
bool ueIdentity_configured;
bool drb_up;
rrc_args_t args;
bool first_stimsi_attempt;
uint32_t cell_clean_cnt;
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;
phy_interface_rrc::phy_cfg_t previous_phy_cfg;
mac_interface_rrc::mac_cfg_t previous_mac_cfg;
bool pending_mob_reconf;
LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT mob_reconf;
// timeouts in ms
uint32_t connecting_timeout;
static const uint32_t RRC_CONNECTING_TIMEOUT = 5000;
uint32_t plmn_select_timeout;
static const uint32_t RRC_PLMN_SELECT_TIMEOUT = 10000;
uint8_t k_rrc_enc[32];
uint8_t k_rrc_int[32];
uint8_t k_up_enc[32];
@ -341,7 +383,7 @@ private:
srslte::mac_interface_timers *mac_timers;
uint32_t n310_cnt, N310;
uint32_t n311_cnt, N311;
uint32_t t300, t301, t310, t311, t304;
uint32_t t300, t301, t302, t310, t311, t304;
// Radio bearers
typedef enum{
@ -376,42 +418,35 @@ private:
std::vector<cell_t*> neighbour_cells;
cell_t *serving_cell;
void set_serving_cell(uint32_t cell_idx);
void set_serving_cell(uint32_t earfcn, uint32_t pci);
void set_serving_cell(phy_interface_rrc::phy_cell_t phy_cell);
int find_neighbour_cell(uint32_t earfcn, uint32_t pci);
bool add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp);
bool add_neighbour_cell(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp);
bool add_neighbour_cell(phy_interface_rrc::phy_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,
SI_ACQUIRE_SIB1,
SI_ACQUIRE_SIB2
} si_acquire_state_t;
bool configure_serving_cell();
si_acquire_state_t si_acquire_state;
void run_si_acquisition_procedure();
bool si_acquire(uint32_t index);
uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t offset, uint32_t sf);
uint32_t nof_sib1_trials;
uint16_t sysinfo_index;
uint32_t last_win_start;
const static int SIB_SEARCH_TIMEOUT_MS = 1000;
bool select_next_cell_in_plmn();
LIBLTE_RRC_PLMN_IDENTITY_STRUCT selected_plmn_id;
const static uint32_t NOF_REQUIRED_SIBS = 3; // SIB1, SIB2 and SIB3
bool thread_running;
void run_thread();
bool initiated;
bool ho_start;
bool go_idle;
// Measurements sub-class
class rrc_meas {
public:
void init(rrc *parent);
void reset();
void parse_meas_config(LIBLTE_RRC_MEAS_CONFIG_STRUCT *meas_config);
bool parse_meas_config(LIBLTE_RRC_MEAS_CONFIG_STRUCT *meas_config);
void new_phy_meas(uint32_t earfcn, uint32_t pci, float rsrp, float rsrq, uint32_t tti);
void run_tti(uint32_t tti);
bool timer_expired(uint32_t timer_id);
@ -500,6 +535,18 @@ private:
rrc_meas measurements;
// Measurement object from phy
typedef struct {
float rsrp;
float rsrq;
uint32_t tti;
uint32_t earfcn;
uint32_t pci;
} phy_meas_t;
void process_phy_meas();
void process_new_phy_meas(phy_meas_t meas);
std::queue<phy_meas_t> phy_meas_q;
// Cell selection/reselection functions/variables
typedef struct {
@ -510,25 +557,36 @@ private:
float s_intrasearchP;
float q_hyst;
float threshservinglow;
} cell_resel_cfg_t;
cell_resel_cfg_t cell_resel_cfg;
float get_srxlev(float Qrxlevmeas);
float get_squal(float Qqualmeas);
void cell_reselection_eval(float rsrp, float rsrq);
bool cell_selection_eval(float rsrp, float rsrq = 0);
bool connection_requested;
void plmn_select_rrc(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id);
typedef enum {
CHANGED_CELL = 0,
SAME_CELL = 1,
NO_CELL = 2
} cs_ret_t;
cs_ret_t cell_selection();
bool cell_selection_criteria(float rsrp, float rsrq = 0);
void cell_reselection(float rsrp, float rsrq);
phy_interface_rrc::cell_search_ret_t cell_search();
LIBLTE_RRC_PLMN_IDENTITY_STRUCT selected_plmn_id;
bool plmn_is_selected;
bool security_is_activated;
// RLC interface
void max_retx_attempted();
// Senders
void send_con_request();
void send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_ENUM cause, uint16_t crnti);
void send_con_request(LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM cause);
void send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_ENUM cause);
void send_con_restablish_complete();
void send_con_setup_complete(byte_buffer_t *nas_msg);
void send_ul_info_transfer(byte_buffer_t *nas_msg);
@ -542,16 +600,15 @@ private:
void parse_dl_info_transfer(uint32_t lcid, byte_buffer_t *pdu);
// Helpers
void ho_failed();
bool con_reconfig(LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig);
void con_reconfig_failed();
bool con_reconfig_ho(LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig);
bool ho_prepare();
void ho_synced(uint32_t target_pci);
void ho_failed();
void rrc_connection_release();
void con_restablish_cell_reselected();
void radio_link_failure();
void leave_connected();
static void* start_sib_thread(void *rrc_);
void sib_search();
void apply_rr_config_common_dl(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *config);
void apply_rr_config_common_ul(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *config);
void handle_sib1();
@ -566,7 +623,7 @@ private:
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);
void apply_rr_config_dedicated(LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT *cnfg);
bool apply_rr_config_dedicated(LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT *cnfg);
void apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *phy_cnfg, bool apply_defaults);
void apply_mac_config_dedicated(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_cfg, bool apply_defaults);

@ -33,27 +33,11 @@ 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,
RRC_STATE_CONNECTING,
RRC_STATE_CONNECTED,
RRC_STATE_HO_PREPARE,
RRC_STATE_HO_PROCESS,
RRC_STATE_LEAVE_CONNECTED,
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"};
"CONNECTED"};
} // namespace srsue

@ -107,27 +107,29 @@ void demux::push_pdu_temp_crnti(uint8_t *buff, uint32_t nof_bytes)
Debug("Saved MAC PDU with Temporal C-RNTI in buffer\n");
pdus.push(buff, nof_bytes);
pdus.push(buff, nof_bytes, srslte::pdu_queue::DCH);
} else {
Warning("Trying to push PDU with payload size zero\n");
}
}
/* Demultiplexing of logical channels and dissassemble of MAC CE
* This function enqueues the packet and returns quicly because ACK
* This function enqueues the packet and returns quickly because ACK
* deadline is important here.
*/
void demux::push_pdu(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) {
return pdus.push(buff, nof_bytes, tstamp);
return pdus.push(buff, nof_bytes, srslte::pdu_queue::DCH, tstamp);
}
/* Demultiplexing of MAC PDU associated with SI-RNTI. The PDU passes through
* the MAC in transparent mode.
* Warning: In this case function sends the message to RLC now, since SI blocks do not
* require ACK feedback to be transmitted quickly.
*/
void demux::push_pdu_bcch(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) {
rlc->write_pdu_bcch_dlsch(buff, nof_bytes);
pdus.push(buff, nof_bytes, srslte::pdu_queue::BCH, tstamp);
}
void demux::push_pdu_mch(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) {
pdus.push(buff, nof_bytes, srslte::pdu_queue::MCH, tstamp);
}
bool demux::process_pdus()
@ -135,15 +137,25 @@ bool demux::process_pdus()
return pdus.process_pdus();
}
void demux::process_pdu(uint8_t *mac_pdu, uint32_t nof_bytes, uint32_t tstamp)
void demux::process_pdu(uint8_t *mac_pdu, uint32_t nof_bytes, srslte::pdu_queue::channel_t channel, uint32_t tstamp)
{
// Unpack DLSCH MAC PDU
mac_msg.init_rx(nof_bytes);
mac_msg.parse_packet(mac_pdu);
process_sch_pdu(&mac_msg);
//srslte_vec_fprint_byte(stdout, mac_pdu, nof_bytes);
Debug("MAC PDU processed\n");
Debug("Processing MAC PDU channel %d\n", channel);
switch(channel) {
case srslte::pdu_queue::DCH:
// Unpack DLSCH MAC PDU
mac_msg.init_rx(nof_bytes);
mac_msg.parse_packet(mac_pdu);
process_sch_pdu(&mac_msg);
//srslte_vec_fprint_byte(stdout, mac_pdu, nof_bytes);
break;
case srslte::pdu_queue::BCH:
rlc->write_pdu_bcch_dlsch(mac_pdu, nof_bytes);
break;
case srslte::pdu_queue::MCH:
// Process downlink MCH
break;
}
}
void demux::process_sch_pdu(srslte::sch_pdu *pdu_msg)

@ -41,27 +41,21 @@
namespace srsue {
mac::mac() : ttisync(10240),
timers(64),
mac::mac() : timers(64),
mux_unit(MAC_NOF_HARQ_PROC),
pdu_process_thread(&demux_unit)
{
started = false;
pcap = NULL;
bzero(&metrics, sizeof(mac_metrics_t));
}
bool mac::init(phy_interface_mac *phy, rlc_interface_mac *rlc, rrc_interface_mac *rrc, srslte::log *log_h_)
{
started = false;
phy_h = phy;
rlc_h = rlc;
rrc_h = rrc;
log_h = log_h_;
tti = 0;
is_synchronized = false;
last_temporal_crnti = 0;
phy_rnti = 0;
srslte_softbuffer_rx_init(&pch_softbuffer, 100);
@ -79,23 +73,18 @@ bool mac::init(phy_interface_mac *phy, rlc_interface_mac *rlc, rrc_interface_mac
reset();
started = true;
start(MAC_MAIN_THREAD_PRIO);
start_periodic(1000, MAC_MAIN_THREAD_PRIO);
mactimers.init(&timers, log_h);
return started;
return true;
}
void mac::stop()
{
srslte_softbuffer_rx_free(&pch_softbuffer);
started = false;
ttisync.increase();
pdu_process_thread.stop();
stop_thread();
wait_thread_finish();
mactimers.stop();
}
void mac::start_pcap(srslte::mac_pcap* pcap_)
@ -150,59 +139,38 @@ 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::run_period() {
void mac::mac_timers::run_period() {
timers->step_all();
}
/* Warning: Here order of invocation of procedures is important!! */
void mac::run_thread() {
int cnt=0;
tti = phy_h->get_current_tti();
while (!phy_h->sync_status() && started) {
usleep(5000);
if (phy_h->sync_status()) {
Debug("Setting ttysync to %d\n", phy_h->get_current_tti());
ttisync.set_producer_cntr(phy_h->get_current_tti());
}
}
log_h->step(tti);
while(started) {
// Step all procedures
bsr_procedure.step(tti);
phr_procedure.step(tti);
/* Warning: Here order of invocation of procedures is important!! */
tti = ttisync.wait();
log_h->step(tti);
// Step all procedures
bsr_procedure.step(tti);
phr_procedure.step(tti);
// Check if BSR procedure need to start SR
if (bsr_procedure.need_to_send_sr(tti)) {
Debug("Starting SR procedure by BSR request, PHY TTI=%d\n", tti);
sr_procedure.start();
}
if (bsr_procedure.need_to_reset_sr()) {
Debug("Resetting SR procedure by BSR request\n");
sr_procedure.reset();
}
sr_procedure.step(tti);
// Check if BSR procedure need to start SR
// Check SR if we need to start RA
if (sr_procedure.need_random_access()) {
ra_procedure.start_mac_order();
}
ra_procedure.step(tti);
if (bsr_procedure.need_to_send_sr(tti)) {
Debug("Starting SR procedure by BSR request, PHY TTI=%d\n", tti);
sr_procedure.start();
}
if (bsr_procedure.need_to_reset_sr()) {
Debug("Resetting SR procedure by BSR request\n");
sr_procedure.reset();
}
sr_procedure.step(tti);
rrc_h->run_tti(tti);
// Check SR if we need to start RA
if (sr_procedure.need_random_access()) {
ra_procedure.start_mac_order();
}
ra_procedure.step(tti);
timers.step_all();
rrc_h->run_tti(tti);
}
void mac::bcch_start_rx()
@ -221,28 +189,17 @@ void mac::bcch_start_rx(int si_window_start, int si_window_length)
Info("SCHED: Searching for DL grant for SI-RNTI window_st=%d, window_len=%d\n", si_window_start, si_window_length);
}
void mac::bcch_stop_rx()
{
phy_h->pdcch_dl_search_reset();
}
void mac::pcch_start_rx()
{
phy_h->pdcch_dl_search(SRSLTE_RNTI_PCH, SRSLTE_PRNTI);
Info("SCHED: Searching for DL grant for P-RNTI\n");
}
void mac::pcch_stop_rx()
void mac::clear_rntis()
{
phy_h->pdcch_dl_search_reset();
}
void mac::tti_clock(uint32_t tti)
{
ttisync.increase(tti);
}
void mac::bch_decoded_ok(uint8_t* payload, uint32_t len)
{
// Send MIB to RLC

@ -77,6 +77,7 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
("rf.time_adv_nsamples", bpo::value<string>(&args->rf.time_adv_nsamples)->default_value("auto"),
"Transmission time advance")
("rf.burst_preamble_us", bpo::value<string>(&args->rf.burst_preamble)->default_value("auto"), "Transmission time advance")
("rf.continuous_tx", bpo::value<string>(&args->rf.continuous_tx)->default_value("auto"), "Transmit samples continuously to the radio or on bursts (auto/yes/no). Default is auto (yes for UHD, no for rest)")
("rrc.feature_group", bpo::value<uint32_t>(&args->rrc.feature_group)->default_value(0xe6041c00), "Hex value of the featureGroupIndicators field in the"
"UECapabilityInformation message. Default 0xe6041c00")
@ -159,6 +160,10 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
bpo::value<bool>(&args->expert.pregenerate_signals)->default_value(false),
"Pregenerate uplink signals after attach. Improves CPU performance.")
("expert.print_buffer_state",
bpo::value<bool>(&args->expert.print_buffer_state)->default_value(false),
"Prints on the console the buffer state every 10 seconds")
("expert.rssi_sensor_enabled",
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")
@ -261,18 +266,22 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
bpo::value<bool>(&args->expert.phy.average_subframe_enabled)->default_value(true),
"Averages in the time domain the channel estimates within 1 subframe. Needs accurate CFO correction.")
("expert.time_correct_period",
bpo::value<int>(&args->expert.phy.time_correct_period)->default_value(5),
"Period for sampling time offset correction.")
("expert.estimator_fil_auto",
bpo::value<bool>(&args->expert.phy.estimator_fil_auto)->default_value(false),
"The channel estimator smooths the channel estimate with an adaptative filter.")
("expert.estimator_fil_stddev",
bpo::value<float>(&args->expert.phy.estimator_fil_stddev)->default_value(1.0f),
"Sets the channel estimator smooth gaussian filter standard deviation.")
("expert.estimator_fil_order",
bpo::value<uint32_t>(&args->expert.phy.estimator_fil_order)->default_value(4),
"Sets the channel estimator smooth gaussian filter order (even values perform better).")
("expert.sss_algorithm",
bpo::value<string>(&args->expert.phy.sss_algorithm)->default_value("full"),
"Selects the SSS estimation algorithm.")
("expert.estimator_fil_w",
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.")
@ -470,18 +479,25 @@ int main(int argc, char *argv[])
pthread_t input;
pthread_create(&input, NULL, &input_loop, &args);
bool plot_started = false;
bool signals_pregenerated = false;
printf("Attaching UE...\n");
while (!ue->attach() && running) {
sleep(1);
}
if (running) {
if (args.expert.pregenerate_signals) {
ue->pregenerate_signals(true);
}
if (args.gui.enable) {
ue->start_plot();
}
}
int cnt=0;
while (running) {
if (ue->is_attached()) {
if (!signals_pregenerated && args.expert.pregenerate_signals) {
ue->pregenerate_signals(true);
signals_pregenerated = true;
}
if (!plot_started && args.gui.enable) {
ue->start_plot();
plot_started = true;
if (args.expert.print_buffer_state) {
cnt++;
if (cnt==10) {
cnt=0;
ue->print_pool();
}
}
sleep(1);

@ -248,7 +248,7 @@ void phch_common::worker_end(uint32_t tti, bool tx_enable,
radio_h->tx_single(buffer, nof_samples, tx_time);
is_first_of_burst = false;
} else {
if (TX_MODE_CONTINUOUS) {
if (radio_h->is_continuous_tx()) {
if (!is_first_of_burst) {
radio_h->tx_single(zeros, nof_samples, tx_time);
}
@ -342,11 +342,13 @@ void phch_common::reset() {
cur_radio_power = 0;
sr_last_tx_tti = -1;
cur_pusch_power = 0;
avg_snr_db_cqi = 0;
avg_snr_db_sync = 0;
avg_rsrp = 0;
avg_rsrp_cqi = 0;
avg_rsrp_dbm = 0;
avg_rsrq_db = 0;
pcell_meas_enabled = false;
pcell_report_period = 20;
bzero(pending_ack, sizeof(pending_ack_t)*TTIMOD_SZ);

File diff suppressed because it is too large Load Diff

@ -133,6 +133,7 @@ bool phch_worker::init(uint32_t max_prb, srslte::log *log_h, srslte::log *log_ph
return false;
}
srslte_chest_dl_set_rsrp_neighbour(&ue_dl.chest, true);
srslte_chest_dl_average_subframe(&ue_dl.chest, phy->args->average_subframe_enabled);
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);
@ -185,6 +186,11 @@ void phch_worker::set_tti(uint32_t tti_, uint32_t tx_tti_)
log_phy_lib_h->step(tti);
}
void phch_worker::set_prach(cf_t *prach_ptr, float prach_power) {
this->prach_ptr = prach_ptr;
this->prach_power = prach_power;
}
void phch_worker::set_cfo(float cfo_)
{
cfo = cfo_;
@ -319,59 +325,69 @@ void phch_worker::work_imp()
/***** Uplink Processing + Transmission *******/
/* Generate SR if required*/
set_uci_sr();
/* Check if we have UL grant. ul_phy_grant will be overwritten by new grant */
ul_grant_available = decode_pdcch_ul(&ul_mac_grant);
bool signal_ready = false;
cf_t *signal_ptr = NULL;
/* Generate CQI reports if required, note that in case both aperiodic
and periodic ones present, only aperiodic is sent (36.213 section 7.2) */
if (ul_grant_available && ul_mac_grant.has_cqi_request) {
set_uci_aperiodic_cqi();
/* Transmit PRACH if pending, or PUSCH/PUCCH otherwise */
if (prach_ptr) {
signal_ready = true;
signal_ptr = prach_ptr;
} else {
set_uci_periodic_cqi();
}
/* Generate SR if required*/
set_uci_sr();
/* TTI offset for UL */
ul_action.tti_offset = HARQ_DELAY_MS;
/* Check if we have UL grant. ul_phy_grant will be overwritten by new grant */
ul_grant_available = decode_pdcch_ul(&ul_mac_grant);
/* Send UL grant or HARQ information (from PHICH) to MAC */
if (ul_grant_available && ul_ack_available) {
phy->mac->new_grant_ul_ack(ul_mac_grant, ul_ack, &ul_action);
} else if (ul_grant_available && !ul_ack_available) {
phy->mac->new_grant_ul(ul_mac_grant, &ul_action);
} else if (!ul_grant_available && ul_ack_available) {
phy->mac->harq_recv(tti, ul_ack, &ul_action);
}
/* Generate CQI reports if required, note that in case both aperiodic
and periodic ones present, only aperiodic is sent (36.213 section 7.2) */
if (ul_grant_available && ul_mac_grant.has_cqi_request) {
set_uci_aperiodic_cqi();
} else {
set_uci_periodic_cqi();
}
/* Set UL CFO before transmission */
srslte_ue_ul_set_cfo(&ue_ul, cfo);
/* TTI offset for UL */
ul_action.tti_offset = HARQ_DELAY_MS;
/* Transmit PUSCH, PUCCH or SRS */
bool signal_ready = false;
if (ul_action.tx_enabled) {
encode_pusch(&ul_action.phy_grant.ul, ul_action.payload_ptr[0], ul_action.current_tx_nb,
&ul_action.softbuffers[0], ul_action.rv[0], ul_action.rnti, ul_mac_grant.is_from_rar);
signal_ready = true;
if (ul_action.expect_ack) {
phy->set_pending_ack(TTI_RX_ACK(tti), ue_ul.pusch_cfg.grant.n_prb_tilde[0], ul_action.phy_grant.ul.ncs_dmrs);
/* Send UL grant or HARQ information (from PHICH) to MAC */
if (ul_grant_available && ul_ack_available) {
phy->mac->new_grant_ul_ack(ul_mac_grant, ul_ack, &ul_action);
} else if (ul_grant_available && !ul_ack_available) {
phy->mac->new_grant_ul(ul_mac_grant, &ul_action);
} else if (!ul_grant_available && ul_ack_available) {
phy->mac->harq_recv(tti, ul_ack, &ul_action);
}
} else if (dl_action.generate_ack || uci_data.scheduling_request || uci_data.uci_cqi_len > 0 || uci_data.uci_ri_len > 0) {
encode_pucch();
signal_ready = true;
} else if (srs_is_ready_to_send()) {
encode_srs();
signal_ready = true;
/* Set UL CFO before transmission */
srslte_ue_ul_set_cfo(&ue_ul, cfo);
/* Transmit PUSCH, PUCCH or SRS */
if (ul_action.tx_enabled) {
encode_pusch(&ul_action.phy_grant.ul, ul_action.payload_ptr[0], ul_action.current_tx_nb,
&ul_action.softbuffers[0], ul_action.rv[0], ul_action.rnti, ul_mac_grant.is_from_rar);
signal_ready = true;
if (ul_action.expect_ack) {
phy->set_pending_ack(TTI_RX_ACK(tti), ue_ul.pusch_cfg.grant.n_prb_tilde[0], ul_action.phy_grant.ul.ncs_dmrs);
}
} else if (dl_action.generate_ack || uci_data.scheduling_request || uci_data.uci_cqi_len > 0 || uci_data.uci_ri_len > 0) {
encode_pucch();
signal_ready = true;
} else if (srs_is_ready_to_send()) {
encode_srs();
signal_ready = true;
}
signal_ptr = signal_buffer[0];
}
tr_log_end();
if (next_offset > 0) {
phy->worker_end(tx_tti, signal_ready, signal_buffer[0], SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time);
phy->worker_end(tx_tti, signal_ready, signal_ptr, SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time);
} else {
phy->worker_end(tx_tti, signal_ready, &signal_buffer[0][-next_offset], SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time);
phy->worker_end(tx_tti, signal_ready, &signal_ptr[-next_offset], SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time);
}
if (!dl_action.generate_ack_callback) {
@ -391,13 +407,13 @@ void phch_worker::work_imp()
update_measurements();
if (chest_ok) {
if (phy->avg_rsrp_dbm > -130.0 && phy->avg_snr_db > -10.0) {
if (phy->avg_rsrp_sync_dbm > -130.0 && phy->avg_snr_db_sync > -10.0) {
log_h->debug("SNR=%.1f dB, RSRP=%.1f dBm sync=in-sync from channel estimator\n",
phy->avg_snr_db, phy->avg_rsrp_dbm);
phy->avg_snr_db_sync, phy->avg_rsrp_sync_dbm);
chest_loop->in_sync();
} else {
log_h->warning("SNR=%.1f dB RSRP=%.1f dBm, sync=out-of-sync from channel estimator\n",
phy->avg_snr_db, phy->avg_rsrp_dbm);
phy->avg_snr_db_sync, phy->avg_rsrp_sync_dbm);
chest_loop->out_of_sync();
}
}
@ -429,41 +445,45 @@ void phch_worker::compute_ri(uint8_t *ri, uint8_t *pmi, float *sinr) {
}
uci_data.uci_ri_len = 1;
} else if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) {
srslte_ue_dl_ri_pmi_select(&ue_dl, ri, pmi, sinr);
Debug("TM4 ri=%d; pmi=%d; SINR=%.1fdB\n", ue_dl.ri, ue_dl.pmi[ue_dl.ri], 10*log10f(ue_dl.sinr[ue_dl.ri][ue_dl.pmi[ue_dl.ri]]));
if (sinr) {
srslte_ue_dl_ri_pmi_select(&ue_dl, ri, pmi, sinr);
Debug("TM4 ri=%d; pmi=%d; SINR=%.1fdB\n", ue_dl.ri, ue_dl.pmi[ue_dl.ri], 10*log10f(ue_dl.sinr[ue_dl.ri][ue_dl.pmi[ue_dl.ri]]));
}
}
}
bool phch_worker::extract_fft_and_pdcch_llr() {
bool decode_pdcch = true;
/* Without a grant, we might need to do fft processing if need to decode PHICH */
if (phy->get_pending_ack(tti) || decode_pdcch) {
// Setup estimator filter
float w_coeff = phy->args->estimator_fil_w;
if (w_coeff > 0.0) {
srslte_chest_dl_set_smooth_filter3_coeff(&ue_dl.chest, w_coeff);
} else if (w_coeff == 0.0) {
srslte_chest_dl_set_smooth_filter(&ue_dl.chest, NULL, 0);
}
// Do always channel estimation to keep track of out-of-sync and send measurements to RRC
if (!phy->args->snr_estim_alg.compare("refs")) {
srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_REFS);
} else if (!phy->args->snr_estim_alg.compare("empty")) {
srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_EMPTY);
} else {
srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_PSS);
}
// Setup estimator filter
srslte_chest_dl_set_smooth_filter_gauss(&ue_dl.chest,
phy->args->estimator_fil_order,
phy->args->estimator_fil_stddev);
srslte_chest_dl_set_smooth_filter_auto(&ue_dl.chest, phy->args->estimator_fil_auto);
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, tti%10, &cfi) < 0) {
Error("Getting PDCCH FFT estimate\n");
return false;
}
chest_done = true;
if (!phy->args->snr_estim_alg.compare("refs")) {
srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_REFS);
} else if (!phy->args->snr_estim_alg.compare("empty")) {
srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_EMPTY);
} else {
chest_done = false;
srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_PSS);
}
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, tti%10, &cfi) < 0) {
Error("Getting PDCCH FFT estimate\n");
return false;
}
chest_done = true;
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, tti%10, &cfi) < 0) {
Error("Getting PDCCH FFT estimate\n");
return false;
}
chest_done = true;
if (chest_done && decode_pdcch) { /* and not in DRX mode */
float noise_estimate = phy->avg_noise;
@ -504,13 +524,13 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant)
srslte_ra_dl_dci_t dci_unpacked;
if (type == SRSLTE_RNTI_RAR) {
Info("Looking for RNTI=0x%x\n", dl_rnti);
Debug("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",
Debug("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);
}
@ -908,16 +928,16 @@ void phch_worker::set_uci_periodic_cqi()
if (period_cqi.format_is_subband) {
// TODO: Implement subband periodic reports
cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND;
cqi_report.subband.subband_cqi = srslte_cqi_from_snr(phy->avg_snr_db);
cqi_report.subband.subband_cqi = srslte_cqi_from_snr(phy->avg_snr_db_cqi);
cqi_report.subband.subband_label = 0;
log_h->console("Warning: Subband CQI periodic reports not implemented\n");
Debug("PUCCH: Periodic CQI=%d, SNR=%.1f dB\n", cqi_report.subband.subband_cqi, phy->avg_snr_db);
Debug("PUCCH: Periodic CQI=%d, SNR=%.1f dB\n", cqi_report.subband.subband_cqi, phy->avg_snr_db_cqi);
} else {
cqi_report.type = SRSLTE_CQI_TYPE_WIDEBAND;
if (cqi_fixed >= 0) {
cqi_report.wideband.wideband_cqi = cqi_fixed;
} else {
cqi_report.wideband.wideband_cqi = srslte_cqi_from_snr(phy->avg_snr_db);
cqi_report.wideband.wideband_cqi = srslte_cqi_from_snr(phy->avg_snr_db_cqi);
}
if (cqi_max >= 0 && cqi_report.wideband.wideband_cqi > cqi_max) {
cqi_report.wideband.wideband_cqi = cqi_max;
@ -927,7 +947,7 @@ void phch_worker::set_uci_periodic_cqi()
cqi_report.wideband.pmi = phy->last_pmi;
cqi_report.wideband.rank_is_not_one = (phy->last_ri != 0);
}
Debug("PUCCH: Periodic CQI=%d, SNR=%.1f dB\n", cqi_report.wideband.wideband_cqi, phy->avg_snr_db);
Debug("PUCCH: Periodic CQI=%d, SNR=%.1f dB\n", cqi_report.wideband.wideband_cqi, phy->avg_snr_db_cqi);
}
uci_data.uci_cqi_len = (uint32_t) srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi);
rar_cqi_request = false;
@ -957,7 +977,7 @@ void phch_worker::set_uci_aperiodic_cqi()
if (rnti_is_set) {
srslte_cqi_value_t cqi_report = {0};
cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND_HL;
cqi_report.subband_hl.wideband_cqi_cw0 = srslte_cqi_from_snr(phy->avg_snr_db);
cqi_report.subband_hl.wideband_cqi_cw0 = srslte_cqi_from_snr(phy->avg_snr_db_cqi);
// TODO: implement subband CQI properly
cqi_report.subband_hl.subband_diff_cqi_cw0 = 0; // Always report zero offset on all subbands
@ -983,7 +1003,7 @@ void phch_worker::set_uci_aperiodic_cqi()
}
Info("PUSCH: Aperiodic RM30 CQI=%s, %sSNR=%.1f dB, for %d subbands\n",
cqi_str, (uci_data.uci_ri_len)?((uci_data.uci_ri == 0)?"ri=0, ":"ri=1, "):"", phy->avg_snr_db, cqi_report.subband_hl.N);
cqi_str, (uci_data.uci_ri_len)?((uci_data.uci_ri == 0)?"ri=0, ":"ri=1, "):"", phy->avg_snr_db_cqi, cqi_report.subband_hl.N);
}
break;
case LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM31:
@ -1396,18 +1416,18 @@ void phch_worker::update_measurements()
}
}
// Average RSRQ
// Average RSRQ over DEFAULT_MEAS_PERIOD_MS then sent to RRC
float rsrq_db = 10*log10(srslte_chest_dl_get_rsrq(&ue_dl.chest));
if (isnormal(rsrq_db)) {
if (!phy->avg_rsrq_db) {
phy->avg_rsrq_db = SRSLTE_VEC_EMA(rsrq_db, phy->avg_rsrq_db, snr_ema_coeff);
} else {
if (!(tti%phy->pcell_report_period) || !phy->avg_rsrq_db) {
phy->avg_rsrq_db = rsrq_db;
} else {
phy->avg_rsrq_db = SRSLTE_VEC_CMA(rsrq_db, phy->avg_rsrq_db, tti%phy->pcell_report_period);
}
}
// Average RSRP
float rsrp_lin = srslte_chest_dl_get_rsrp(&ue_dl.chest);
// Average RSRP taken from CRS
float rsrp_lin = srslte_chest_dl_get_rsrp_neighbour(&ue_dl.chest);
if (isnormal(rsrp_lin)) {
if (!phy->avg_rsrp) {
phy->avg_rsrp = SRSLTE_VEC_EMA(rsrp_lin, phy->avg_rsrp, snr_ema_coeff);
@ -1419,18 +1439,20 @@ void phch_worker::update_measurements()
/* Correct absolute power measurements by RX gain offset */
float rsrp_dbm = 10*log10(rsrp_lin) + 30 - phy->rx_gain_offset;
// Serving cell measurements are averaged over DEFAULT_MEAS_PERIOD_MS then sent to RRC
// Serving cell RSRP measurements are averaged over DEFAULT_MEAS_PERIOD_MS then sent to RRC
if (isnormal(rsrp_dbm)) {
if (!phy->avg_rsrp_dbm) {
if (!(tti%phy->pcell_report_period) || !phy->avg_rsrp_dbm) {
phy->avg_rsrp_dbm = rsrp_dbm;
} else {
phy->avg_rsrp_dbm = SRSLTE_VEC_EMA(rsrp_dbm, phy->avg_rsrp_dbm, snr_ema_coeff);
}
if ((tti%phy->pcell_report_period) == 0 && phy->pcell_meas_enabled) {
phy->rrc->new_phy_meas(phy->avg_rsrp_dbm, phy->avg_rsrq_db, tti);
phy->avg_rsrp_dbm = SRSLTE_VEC_CMA(rsrp_dbm, phy->avg_rsrp_dbm, tti%phy->pcell_report_period);
}
}
// Send PCell measurement
if ((tti%phy->pcell_report_period) == phy->pcell_report_period-1) {
phy->rrc->new_phy_meas(phy->avg_rsrp_dbm, phy->avg_rsrq_db, tti);
}
// Compute PL
float tx_crs_power = phy->config->common.pdsch_cnfg.rs_power;
phy->pathloss = tx_crs_power - phy->avg_rsrp_dbm;
@ -1445,8 +1467,28 @@ void phch_worker::update_measurements()
}
}
// Compute SNR
phy->avg_snr_db = 10*log10(phy->avg_rsrp/phy->avg_noise);
// To compute CQI use RSRP measurements from resource elements in RS since is more robust to time offset
float rsrp_lin_cqi = srslte_chest_dl_get_rsrp(&ue_dl.chest);
if (isnormal(rsrp_lin_cqi)) {
if (!phy->avg_rsrp_cqi) {
phy->avg_rsrp_cqi = SRSLTE_VEC_EMA(rsrp_lin_cqi, phy->avg_rsrp_cqi, snr_ema_coeff);
} else {
phy->avg_rsrp_cqi = rsrp_lin_cqi;
}
}
float rsrp_sync_dbm = 10*log10(rsrp_lin_cqi) + 30 - phy->rx_gain_offset;
if (isnormal(rsrp_sync_dbm)) {
if (!phy->avg_rsrp_sync_dbm) {
phy->avg_rsrp_sync_dbm = rsrp_sync_dbm;
} else {
phy->avg_rsrp_sync_dbm = SRSLTE_VEC_EMA(rsrp_sync_dbm, phy->avg_rsrp_sync_dbm, snr_ema_coeff);
}
}
// We compute 2 SNR metrics, 1 for deciding in-sync/out-of-sync and another for CQI measurements
phy->avg_snr_db_cqi = 10*log10(phy->avg_rsrp_cqi/phy->avg_noise); // this for CQI
phy->avg_snr_db_sync = 10*log10(phy->avg_rsrp/phy->avg_noise); // this for sync
// Store metrics
dl_metrics.n = phy->avg_noise;
@ -1454,7 +1496,7 @@ void phch_worker::update_measurements()
dl_metrics.rsrq = phy->avg_rsrq_db;
dl_metrics.rssi = phy->avg_rssi_dbm;
dl_metrics.pathloss = phy->pathloss;
dl_metrics.sinr = phy->avg_snr_db;
dl_metrics.sinr = phy->avg_snr_db_cqi;
dl_metrics.turbo_iters = srslte_pdsch_last_noi(&ue_dl.pdsch);
phy->set_dl_metrics(dl_metrics);

@ -96,9 +96,10 @@ void phy::set_default_args(phy_args_t *args)
args->equalizer_mode = "mmse";
args->cfo_integer_enabled = false;
args->cfo_correct_tol_hz = 50;
args->time_correct_period = 5;
args->sss_algorithm = "full";
args->estimator_fil_w = 0.1;
args->estimator_fil_auto = false;
args->estimator_fil_stddev = 1.0f;
args->estimator_fil_order = 4;
}
bool phy::check_args(phy_args_t *args)
@ -107,10 +108,6 @@ bool phy::check_args(phy_args_t *args)
log_h->console("Error in PHY args: nof_phy_threads must be 1, 2 or 3\n");
return false;
}
if (args->estimator_fil_w > 1.0) {
log_h->console("Error in PHY args: estimator_fil_w must be 0<=w<=1\n");
return false;
}
if (args->snr_ema_coeff > 1.0) {
log_h->console("Error in PHY args: snr_ema_coeff must be 0<=w<=1\n");
return false;
@ -250,20 +247,6 @@ void phy::configure_ul_params(bool pregen_disabled)
}
}
void phy::cell_search_start()
{
sf_recv.cell_search_start();
}
void phy::cell_search_next()
{
sf_recv.cell_search_next();
}
void phy::sync_reset() {
sf_recv.reset_sync();
}
void phy::meas_reset() {
sf_recv.meas_reset();
}
@ -276,13 +259,16 @@ int phy::meas_stop(uint32_t earfcn, int pci) {
return sf_recv.meas_stop(earfcn, pci);
}
void phy::cell_select(uint32_t earfcn, srslte_cell_t phy_cell)
{
sf_recv.cell_select(earfcn, phy_cell);
bool phy::cell_select(phy_cell_t *cell) {
return sf_recv.cell_select(cell);
}
phy_interface_rrc::cell_search_ret_t phy::cell_search(phy_cell_t *cell) {
return sf_recv.cell_search(cell);
}
bool phy::cell_handover(srslte_cell_t cell) {
return sf_recv.cell_handover(cell);
bool phy::cell_is_camping() {
return sf_recv.cell_is_camping();
}
float phy::get_phr()
@ -348,13 +334,14 @@ int phy::prach_tx_tti()
// Handle the case of a radio overflow. Resynchronise inmediatly
void phy::radio_overflow() {
sf_recv.reset_sync();
sf_recv.radio_overflow();
}
void phy::reset()
{
Info("Resetting PHY\n");
n_ta = 0;
sf_recv.set_time_adv_sec(0);
pdcch_dl_search_reset();
for(uint32_t i=0;i<nof_workers;i++) {
workers[i].reset();
@ -388,11 +375,6 @@ void phy::force_freq(float dl_freq, float ul_freq)
sf_recv.force_freq(dl_freq, ul_freq);
}
bool phy::sync_status()
{
return sf_recv.status_is_sync();
}
void phy::set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN])
{
workers_common.set_rar_grant(tti, grant_payload);

@ -75,7 +75,7 @@ void prach::init(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config_, uint32_t max_prb,
return;
}
srslte_cfo_set_tol(&cfo_h, 0);
signal_buffer = (cf_t *) srslte_vec_malloc(SRSLTE_PRACH_MAX_LEN * sizeof(cf_t));
signal_buffer = (cf_t *) srslte_vec_malloc(MAX_LEN_SF * 30720 * sizeof(cf_t));
if (!signal_buffer) {
perror("malloc");
return;
@ -159,10 +159,10 @@ bool prach::is_pending() {
bool prach::is_ready_to_send(uint32_t current_tti_) {
if (is_pending()) {
// consider the number of subframes the transmission must be anticipated
uint32_t current_tti = (current_tti_ + tx_advance_sf)%10240;
if (srslte_prach_tti_opportunity(&prach_obj, current_tti, allowed_subframe)) {
Debug("PRACH Buffer: Ready to send at tti: %d (now is %d)\n", current_tti, current_tti_);
transmitted_tti = current_tti;
uint32_t tti_tx = TTI_TX(current_tti_);
if (srslte_prach_tti_opportunity(&prach_obj, tti_tx, allowed_subframe)) {
Debug("PRACH Buffer: Ready to send at tti: %d (now is %d)\n", tti_tx, current_tti_);
transmitted_tti = tti_tx;
return true;
}
}
@ -173,55 +173,31 @@ int prach::tx_tti() {
return transmitted_tti;
}
float prach::get_p0_preamble()
{
return target_power_dbm;
}
void prach::send(srslte::radio *radio_handler, float cfo, float pathloss, srslte_timestamp_t tx_time)
{
cf_t *prach::generate(float cfo, uint32_t *nof_sf, float *target_power) {
// Get current TX gain
float old_gain = radio_handler->get_tx_gain();
if (cell_initiated && preamble_idx >= 0 && nof_sf) {
// Correct CFO before transmission FIXME: UL SISO Only
srslte_cfo_correct(&cfo_h, buffer[preamble_idx], signal_buffer, cfo / srslte_symbol_sz(cell.nof_prb));
// Correct CFO before transmission FIXME: UL SISO Only
srslte_cfo_correct(&cfo_h, buffer[preamble_idx], signal_buffer, cfo / srslte_symbol_sz(cell.nof_prb));
// If power control is enabled, choose amplitude and power
if (args->ul_pwr_ctrl_en) {
// Get PRACH transmission power
float tx_power = SRSLTE_MIN(SRSLTE_PC_MAX, pathloss + target_power_dbm);
// pad guard symbols with zeros
uint32_t nsf = (len-1)/SRSLTE_SF_LEN_PRB(cell.nof_prb)+1;
bzero(&signal_buffer[len], (nsf*SRSLTE_SF_LEN_PRB(cell.nof_prb)-len)*sizeof(cf_t));
// Get output power for amplitude 1
radio_handler->set_tx_power(tx_power);
*nof_sf = nsf;
// Scale signal
float digital_power = srslte_vec_avg_power_cf(signal_buffer, len);
float scale = sqrtf(pow(10,tx_power/10)/digital_power);
if (target_power) {
*target_power = target_power_dbm;
}
srslte_vec_sc_prod_cfc(signal_buffer, scale, signal_buffer, len);
log_h->console("PRACH: Pathloss=%.2f dB, Target power %.2f dBm, TX_power %.2f dBm, TX_gain %.1f dB, scale %.2f\n",
pathloss, target_power_dbm, tx_power, radio_handler->get_tx_gain(), scale);
Info("PRACH: Transmitted preamble=%d, CFO=%.2f KHz, nof_sf=%d, target_power=%.1f dBm\n",
preamble_idx, cfo*15, nsf, target_power_dbm);
preamble_idx = -1;
return signal_buffer;
} else {
float prach_gain = args->prach_gain;
if (prach_gain > 0) {
radio_handler->set_tx_gain(prach_gain);
}
Debug("TX PRACH: Power control for PRACH is disabled, setting gain to %.0f dB\n", prach_gain);
return NULL;
}
void *tmp_buffer[SRSLTE_MAX_PORTS] = {signal_buffer, NULL, NULL, NULL};
radio_handler->tx(tmp_buffer, len, tx_time);
radio_handler->tx_end();
Info("PRACH: Transmitted preamble=%d, CFO=%.2f KHz, tx_time=%f\n",
preamble_idx, cfo*15, tx_time.frac_secs);
preamble_idx = -1;
radio_handler->set_tx_gain(old_gain);
Debug("Restoring TX gain to %.0f dB\n", old_gain);
}
} // namespace srsue

@ -160,6 +160,9 @@ bool ue::init(all_args_t *args_)
if (args->rf.burst_preamble.compare("auto")) {
radio.set_burst_preamble(atof(args->rf.burst_preamble.c_str()));
}
if (args->rf.continuous_tx.compare("auto")) {
radio.set_continuous_tx(args->rf.continuous_tx.compare("yes")?false:true);
}
radio.set_manual_calibration(&args->rf_cal);
@ -226,7 +229,6 @@ bool ue::init(all_args_t *args_)
}
printf("...\n");
nas.attach_request();
started = true;
return true;
@ -273,6 +275,14 @@ void ue::stop()
}
}
bool ue::attach() {
return nas.attach_request();
}
bool ue::deattach() {
return nas.deattach_request();
}
bool ue::is_attached()
{
return rrc.is_connected();

@ -248,10 +248,8 @@ void gw::run_thread()
return;
}
const static uint32_t ATTACH_TIMEOUT_MS = 10000;
const static uint32_t ATTACH_MAX_ATTEMPTS = 3;
uint32_t attach_cnt = 0;
uint32_t attach_attempts = 0;
const static uint32_t ATTACH_WAIT_TOUT = 40; // 4 sec
uint32_t attach_wait = 0;
gw_log->info("GW IP packet receiver thread run_enable\n");
@ -278,25 +276,18 @@ void gw::run_thread()
{
gw_log->info_hex(pdu->msg, pdu->N_bytes, "TX PDU");
while(run_enable && !pdcp->is_drb_enabled(cfg.lcid) && attach_attempts < ATTACH_MAX_ATTEMPTS) {
if (attach_cnt == 0) {
gw_log->info("LCID=%d not active, requesting NAS attach (%d/%d)\n", cfg.lcid, attach_attempts, ATTACH_MAX_ATTEMPTS);
nas->attach_request();
attach_attempts++;
}
attach_cnt++;
if (attach_cnt == ATTACH_TIMEOUT_MS) {
attach_cnt = 0;
while(run_enable && !pdcp->is_drb_enabled(cfg.lcid) && attach_wait < ATTACH_WAIT_TOUT) {
if (!attach_wait) {
gw_log->info("LCID=%d not active, requesting NAS attach (%d/%d)\n", cfg.lcid, attach_wait, ATTACH_WAIT_TOUT);
if (!nas->attach_request()) {
gw_log->warning("Could not re-establish the connection\n");
}
}
usleep(1000);
}
if (attach_attempts == ATTACH_MAX_ATTEMPTS) {
gw_log->warning("LCID=%d was not active after %d attempts\n", cfg.lcid, ATTACH_MAX_ATTEMPTS);
usleep(100000);
attach_wait++;
}
attach_attempts = 0;
attach_cnt = 0;
attach_wait = 0;
if (!run_enable) {
break;

@ -45,10 +45,13 @@ namespace srsue {
********************************************************************/
nas::nas()
: state(EMM_STATE_DEREGISTERED), plmn_selection(PLMN_SELECTED), have_guti(false), have_ctxt(false), ip_addr(0), eps_bearer_id(0)
: state(EMM_STATE_DEREGISTERED), have_guti(false), have_ctxt(false), ip_addr(0), eps_bearer_id(0)
{
ctxt.rx_count = 0;
ctxt.tx_count = 0;
ctxt.cipher_algo = CIPHERING_ALGORITHM_ID_EEA0;
ctxt.integ_algo = INTEGRITY_ALGORITHM_ID_EIA0;
plmn_is_selected = false;
}
void nas::init(usim_interface_nas *usim_,
@ -63,7 +66,6 @@ void nas::init(usim_interface_nas *usim_,
gw = gw_;
nas_log = nas_log_;
state = EMM_STATE_DEREGISTERED;
plmn_selection = PLMN_NOT_SELECTED;
if (!usim->get_home_plmn_id(&home_plmn)) {
nas_log->error("Getting Home PLMN Id from USIM. Defaulting to 001-01\n");
@ -80,9 +82,11 @@ void nas::init(usim_interface_nas *usim_,
have_guti = true;
have_ctxt = true;
}
running = true;
}
void nas::stop() {
running = false;
write_ctxt_file(ctxt);
}
@ -94,105 +98,186 @@ emm_state_t nas::get_state() {
* UE interface
******************************************************************************/
void nas::attach_request() {
/** Blocking function to Attach to the network and establish RRC connection if not established.
* The function returns true if the UE could attach correctly or false in case of error or timeout during attachment.
*
*/
bool nas::attach_request() {
rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS];
int nof_plmns = 0;
nas_log->info("Attach Request\n");
if (state == EMM_STATE_DEREGISTERED) {
state = EMM_STATE_REGISTERED_INITIATED;
if (plmn_selection == PLMN_NOT_SELECTED) {
nas_log->info("Starting PLMN Search...\n");
rrc->plmn_search();
} else if (plmn_selection == PLMN_SELECTED) {
nas_log->info("Selecting PLMN %s\n", plmn_id_to_string(current_plmn).c_str());
rrc->plmn_select(current_plmn);
selecting_plmn = current_plmn;
}
} else if (state == EMM_STATE_REGISTERED) {
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]);
switch (state) {
case EMM_STATE_DEREGISTERED:
// Search PLMN is not selected
if (!plmn_is_selected) {
nas_log->info("No PLMN selected. Starting PLMN Search...\n");
nof_plmns = rrc->plmn_search(found_plmns);
if (nof_plmns > 0) {
// Save PLMNs
known_plmns.clear();
for (int i=0;i<nof_plmns;i++) {
known_plmns.push_back(found_plmns[i].plmn_id);
nas_log->info("Found PLMN: Id=%s, TAC=%d\n", plmn_id_to_string(found_plmns[i].plmn_id).c_str(),
found_plmns[i].tac);
nas_log->console("Found PLMN: Id=%s, TAC=%d\n", plmn_id_to_string(found_plmns[i].plmn_id).c_str(),
found_plmns[i].tac);
}
select_plmn();
} else if (nof_plmns == 0) {
nas_log->warning("Did not find any PLMN in the set of frequencies\n");
return false;
} else if (nof_plmns < 0) {
nas_log->error("Error while searching for PLMNs\n");
return false;
}
}
// Select PLMN in request establishment of RRC connection
if (plmn_is_selected) {
rrc->plmn_select(current_plmn);
if (rrc_connect()) {
nas_log->info("NAS attached successfully.\n");
return true;
} else {
nas_log->error("Could not attach in attach request\n");
}
} else {
nas_log->error("PLMN is not selected because no suitable PLMN was found\n");
}
break;
case EMM_STATE_REGISTERED:
if (rrc->is_connected()) {
nas_log->info("NAS is already registered and RRC connected\n");
return true;
} else {
nas_log->info("NAS is already registered but RRC disconnected. Connecting now...\n");
if (rrc_connect()) {
nas_log->info("NAS attached successfully.\n");
return true;
} else {
nas_log->error("Could not attach from attach_request\n");
}
}
break;
default:
nas_log->info("Attach request ignored. State = %s\n", emm_state_text[state]);
}
return false;
}
void nas::deattach_request() {
bool nas::deattach_request() {
state = EMM_STATE_DEREGISTERED_INITIATED;
nas_log->info("Dettach request not supported\n");
return false;
}
/*******************************************************************************
* RRC interface
******************************************************************************/
bool nas::plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) {
bool nas::is_attached() {
return state == EMM_STATE_REGISTERED;
}
// Check if already registered
for (uint32_t i=0;i<known_plmns.size();i++) {
if (plmn_id.mcc == known_plmns[i].mcc && plmn_id.mnc == known_plmns[i].mnc) {
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, state == EMM_STATE_REGISTERED_INITIATED);
selecting_plmn = plmn_id;
return true;
}
return false;
void nas::paging(LIBLTE_RRC_S_TMSI_STRUCT *ue_identiy) {
if (state == EMM_STATE_REGISTERED) {
nas_log->info("Received paging: requesting RRC connection establishment\n");
if (rrc_connect()) {
nas_log->info("Attached successfully\n");
} else {
nas_log->error("Could not attach from paging\n");
}
} else {
nas_log->warning("Received paging while in state %s\n", emm_state_text[state]);
}
}
// Save if new PLMN
known_plmns.push_back(plmn_id);
nas_log->info("Found PLMN: Id=%s, TAC=%d\n", plmn_id_to_string(plmn_id).c_str(),
tracking_area_code);
nas_log->console("Found PLMN: Id=%s, TAC=%d\n", plmn_id_to_string(plmn_id).c_str(),
tracking_area_code);
void nas::set_barring(barring_t barring) {
current_barring = barring;
}
if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) {
rrc->plmn_select(plmn_id, state == EMM_STATE_REGISTERED_INITIATED);
selecting_plmn = plmn_id;
/* Internal function that requests RRC connection, waits for positive or negative response and returns true/false
*/
bool nas::rrc_connect() {
if (rrc->is_connected()) {
nas_log->info("Already connected\n");
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());
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], state == EMM_STATE_REGISTERED_INITIATED);
// Generate service request or attach request message
byte_buffer_t *dedicatedInfoNAS = pool_allocate;
if (state == EMM_STATE_REGISTERED) {
gen_service_request(dedicatedInfoNAS);
} else {
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();
gen_attach_request(dedicatedInfoNAS);
}
// Provide UE-Identity to RRC if have one
if (have_guti) {
LIBLTE_RRC_S_TMSI_STRUCT s_tmsi;
s_tmsi.mmec = ctxt.guti.mme_code;
s_tmsi.m_tmsi = ctxt.guti.m_tmsi;
rrc->set_ue_idenity(s_tmsi);
}
// Set establishment cause
LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM establish_cause = LIBLTE_RRC_CON_REQ_EST_CAUSE_MO_SIGNALLING;
if (rrc->connection_request(establish_cause, dedicatedInfoNAS))
{
nas_log->info("Connection established correctly. Waiting for Attach\n");
// Wait until attachment. If doing a service request is already attached
uint32_t tout = 0;
while (tout < 5000 && state != EMM_STATE_REGISTERED && running && rrc->is_connected()) {
usleep(1000);
tout++;
}
if (state == EMM_STATE_REGISTERED) {
nas_log->info("EMM Registered correctly\n");
return true;
} else if (state == EMM_STATE_DEREGISTERED) {
nas_log->error("Timeout or received attach reject while trying to attach\n");
nas_log->console("Failed to Attach\n");
} else if (!rrc->is_connected()) {
nas_log->error("Was disconnected while attaching\n");
} else {
nas_log->error("Timed out while trying to attach\n");
}
} else {
nas_log->error("Could not establish RRC connection\n");
pool->deallocate(dedicatedInfoNAS);
}
return false;
}
bool nas::is_attached() {
return state == EMM_STATE_REGISTERED;
}
void nas::select_plmn() {
bool nas::is_attaching() {
return state == EMM_STATE_REGISTERED_INITIATED;
}
plmn_is_selected = false;
void nas::notify_connection_setup() {
nas_log->debug("State = %s\n", emm_state_text[state]);
if (EMM_STATE_REGISTERED_INITIATED == state) {
send_attach_request();
} else {
send_service_request();
// First find if Home PLMN is available
for (uint32_t i=0;i<known_plmns.size();i++) {
if (known_plmns[i].mcc == home_plmn.mcc && known_plmns[i].mnc == home_plmn.mnc) {
nas_log->info("Selecting Home PLMN Id=%s\n", plmn_id_to_string(known_plmns[i]).c_str());
plmn_is_selected = true;
current_plmn = known_plmns[i];
return;
}
}
// If not, select the first available PLMN
if (known_plmns.size() > 0) {
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());
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());
plmn_is_selected = true;
current_plmn = known_plmns[0];
}
}
void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu) {
uint8 pd = 0;
uint8 msg_type = 0;
@ -271,16 +356,6 @@ uint32_t nas::get_ul_count() {
return ctxt.tx_count;
}
bool nas::get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) {
if (have_guti) {
s_tmsi->mmec = ctxt.guti.mme_code;
s_tmsi->m_tmsi = ctxt.guti.m_tmsi;
return true;
} else {
return false;
}
}
bool nas::get_k_asme(uint8_t *k_asme_, uint32_t n) {
if(!have_ctxt) {
nas_log->error("K_asme requested before security context established\n");
@ -350,7 +425,7 @@ bool nas::integrity_check(byte_buffer_t *pdu)
return NULL;
}
if (pdu->N_bytes > 5) {
uint8_t exp_mac[4];
uint8_t exp_mac[4] = {0};
uint8_t *mac = &pdu->msg[1];
int i;
@ -408,7 +483,7 @@ void nas::cipher_encrypt(byte_buffer_t *pdu)
memcpy(&pdu->msg[6], &pdu_tmp.msg[6], pdu->N_bytes-6);
break;
default:
nas_log->error("Ciphering algorithmus not known");
nas_log->error("Ciphering algorithm not known\n");
break;
}
}
@ -474,10 +549,10 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
return;
}
LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT attach_accept;
LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT act_def_eps_bearer_context_req;
LIBLTE_MME_ATTACH_COMPLETE_MSG_STRUCT attach_complete;
LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT act_def_eps_bearer_context_accept;
LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT attach_accept = {0};
LIBLTE_MME_ATTACH_COMPLETE_MSG_STRUCT attach_complete = {0};
LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT act_def_eps_bearer_context_req = {0};
LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT act_def_eps_bearer_context_accept = {0};
nas_log->info("Received Attach Accept\n");
@ -489,6 +564,11 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
if (attach_accept.guti_present) {
memcpy(&ctxt.guti, &attach_accept.guti.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT));
have_guti = true;
// Update RRC UE-Idenity
LIBLTE_RRC_S_TMSI_STRUCT s_tmsi;
s_tmsi.mmec = ctxt.guti.mme_code;
s_tmsi.m_tmsi = ctxt.guti.m_tmsi;
rrc->set_ue_idenity(s_tmsi);
}
if (attach_accept.lai_present) {}
if (attach_accept.ms_id_present) {}
@ -511,7 +591,7 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
ip_addr |= act_def_eps_bearer_context_req.pdn_addr.addr[3];
nas_log->info("Network attach successful. APN: %s, IP: %u.%u.%u.%u\n",
act_def_eps_bearer_context_req.apn.apn.c_str(),
act_def_eps_bearer_context_req.apn.apn,
act_def_eps_bearer_context_req.pdn_addr.addr[0],
act_def_eps_bearer_context_req.pdn_addr.addr[1],
act_def_eps_bearer_context_req.pdn_addr.addr[2],
@ -554,8 +634,6 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
// FIXME: Setup the default EPS bearer context
state = EMM_STATE_REGISTERED;
current_plmn = selecting_plmn;
plmn_selection = PLMN_SELECTED;
ctxt.rx_count++;
@ -599,7 +677,7 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
}
void nas::parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu) {
LIBLTE_MME_ATTACH_REJECT_MSG_STRUCT attach_rej;
LIBLTE_MME_ATTACH_REJECT_MSG_STRUCT attach_rej = {0};
liblte_mme_unpack_attach_reject_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &attach_rej);
nas_log->warning("Received Attach Reject. Cause= %02X\n", attach_rej.emm_cause);
@ -611,7 +689,9 @@ void nas::parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu) {
void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) {
LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT auth_req;
bzero(&auth_req, sizeof(LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT));
LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT auth_res;
bzero(&auth_res, sizeof(LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT));
nas_log->info("Received Authentication Request\n");
liblte_mme_unpack_authentication_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &auth_req);
@ -666,8 +746,8 @@ void nas::parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu) {
}
void nas::parse_identity_request(uint32_t lcid, byte_buffer_t *pdu) {
LIBLTE_MME_ID_REQUEST_MSG_STRUCT id_req;
LIBLTE_MME_ID_RESPONSE_MSG_STRUCT id_resp;
LIBLTE_MME_ID_REQUEST_MSG_STRUCT id_req = {0};
LIBLTE_MME_ID_RESPONSE_MSG_STRUCT id_resp = {0};
liblte_mme_unpack_identity_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &id_req);
nas_log->info("Received Identity Request. ID type: %d\n", id_req.id_type);
@ -711,7 +791,9 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu)
}
LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT sec_mode_cmd;
bzero(&sec_mode_cmd, sizeof(LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT));
LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT sec_mode_comp;
bzero(&sec_mode_comp, sizeof(LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT));
liblte_mme_unpack_security_mode_command_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &sec_mode_cmd);
nas_log->info("Received Security Mode Command ksi: %d, eea: %s, eia: %s\n",
@ -838,21 +920,19 @@ void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) {
* Senders
******************************************************************************/
void nas::send_attach_request() {
LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT attach_req;
byte_buffer_t *msg = pool_allocate;
void nas::gen_attach_request(byte_buffer_t *msg) {
if (!msg) {
nas_log->error("Fatal Error: Couldn't allocate PDU in send_attach_request().\n");
nas_log->error("Fatal Error: Couldn't allocate PDU in gen_attach_request().\n");
return;
}
LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT attach_req;
bzero(&attach_req, sizeof(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT));
u_int32_t i;
nas_log->info("Generating attach request\n");
attach_req.eps_attach_type = LIBLTE_MME_EPS_ATTACH_TYPE_EPS_ATTACH;
for (i = 0; i < 8; i++) {
for (u_int32_t i = 0; i < 8; i++) {
attach_req.ue_network_cap.eea[i] = eea_caps[i];
attach_req.ue_network_cap.eia[i] = eia_caps[i];
}
@ -915,16 +995,49 @@ void nas::send_attach_request() {
pcap->write_nas(msg->msg, msg->N_bytes);
}
nas_log->info("Sending attach request\n");
rrc->write_sdu(cfg.lcid, msg);
if (have_ctxt) {
ctxt.tx_count++;
}
}
void nas::gen_service_request(byte_buffer_t *msg) {
if (!msg) {
nas_log->error("Fatal Error: Couldn't allocate PDU in gen_service_request().\n");
return;
}
nas_log->info("Generating service request\n");
// Pack the service request message directly
msg->msg[0] = (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);
msg->N_bytes++;
msg->msg[1] = (ctxt.ksi & 0x07) << 5;
msg->msg[1] |= ctxt.tx_count & 0x1F;
msg->N_bytes++;
uint8_t mac[4];
integrity_generate(&k_nas_int[16],
ctxt.tx_count,
SECURITY_DIRECTION_UPLINK,
&msg->msg[0],
2,
&mac[0]);
// Set the short MAC
msg->msg[2] = mac[2];
msg->N_bytes++;
msg->msg[3] = mac[3];
msg->N_bytes++;
if(pcap != NULL) {
pcap->write_nas(msg->msg, msg->N_bytes);
}
ctxt.tx_count++;
}
void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) {
LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT pdn_con_req;
LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT pdn_con_req = {0};
nas_log->info("Generating PDN Connectivity Request\n");
@ -940,8 +1053,8 @@ void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) {
pdn_con_req.apn_present = false;
} else {
pdn_con_req.apn_present = true;
LIBLTE_MME_ACCESS_POINT_NAME_STRUCT apn;
apn.apn = cfg.apn;
LIBLTE_MME_ACCESS_POINT_NAME_STRUCT apn = {0};
strncpy(apn.apn, cfg.apn.c_str(), LIBLTE_STRING_LEN);
pdn_con_req.apn = apn;
}
pdn_con_req.protocol_cnfg_opts_present = false;
@ -958,7 +1071,7 @@ void nas::send_security_mode_reject(uint8_t cause) {
return;
}
LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT sec_mode_rej;
LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT sec_mode_rej = {0};
sec_mode_rej.emm_cause = cause;
liblte_mme_pack_security_mode_reject_msg(&sec_mode_rej, (LIBLTE_BYTE_MSG_STRUCT *) msg);
if(pcap != NULL) {
@ -970,42 +1083,6 @@ void nas::send_security_mode_reject(uint8_t cause) {
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);
msg->N_bytes++;
msg->msg[1] = (ctxt.ksi & 0x07) << 5;
msg->msg[1] |= ctxt.tx_count & 0x1F;
msg->N_bytes++;
uint8_t mac[4];
integrity_generate(&k_nas_int[16],
ctxt.tx_count,
SECURITY_DIRECTION_UPLINK,
&msg->msg[0],
2,
&mac[0]);
// Set the short MAC
msg->msg[2] = mac[2];
msg->N_bytes++;
msg->msg[3] = mac[3];
msg->N_bytes++;
if(pcap != NULL) {
pcap->write_nas(msg->msg, msg->N_bytes);
}
nas_log->info("Sending service request\n");
rrc->write_sdu(cfg.lcid, msg);
ctxt.tx_count++;
}
void nas::send_esm_information_response() {}

File diff suppressed because it is too large Load Diff

@ -406,13 +406,13 @@ public:
printf("SIB1 received %d bytes, CellID=%d, si_window=%d, sib2_period=%d\n",
nof_bytes, dlsch_msg.sibs[0].sib.sib1.cell_id&0xfff, si_window_len, sib2_period);
sib1_decoded = true;
mac.bcch_stop_rx();
mac.clear_rntis();
} else if (dlsch_msg.sibs[0].sib_type == LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2) {
printf("SIB2 received %d bytes\n", nof_bytes);
setup_mac_phy_sib2(&dlsch_msg.sibs[0].sib.sib2, &mac, &phy);
sib2_decoded = true;
mac.bcch_stop_rx();
mac.clear_rntis();
}
}
}

@ -380,7 +380,7 @@ int main(int argc, char *argv[])
radio.set_tx_freq(prog_args.rf_tx_freq);
// Instruct the PHY to configure PRACH parameters and sync to current cell
while(!my_phy.sync_status()) {
while(!my_phy.cell_is_camping()) {
usleep(20000);
}

@ -196,7 +196,7 @@ int main(int argc, char *argv[])
bool running = true;
while(running) {
if (bch_decoded && my_phy.sync_status()) {
if (bch_decoded && my_phy.cell_is_camping()) {
uint32_t tti = my_phy.get_current_tti();
// SIB1 is scheduled in subframe #5 of even frames, try to decode next frame SIB1
@ -206,7 +206,7 @@ int main(int argc, char *argv[])
total_pkts++;
}
usleep(30000);
if (bch_decoded && my_phy.sync_status() && total_pkts > 0) {
if (bch_decoded && my_phy.cell_is_camping() && total_pkts > 0) {
if (srslte_verbose == SRSLTE_VERBOSE_NONE && srsapps_verbose == 0) {
float gain = prog_args.rf_gain;
if (gain < 0) {

@ -50,6 +50,15 @@ uint8_t auth_request_pdu[] = { 0x07, 0x52, 0x01, 0x0c, 0x63, 0xa8, 0x54, 0x13, 0
uint8_t sec_mode_command_pdu[] = { 0x37, 0x37, 0xc7, 0x67, 0xae, 0x00, 0x07, 0x5d, 0x02, 0x01,
0x02, 0xe0, 0x60, 0xc1 };
uint8_t attach_accept_pdu[] = { 0x27, 0x0f, 0x4f, 0xb3, 0xef, 0x01, 0x07, 0x42, 0x01, 0x3e,
0x06, 0x00, 0x00, 0xf1, 0x10, 0x00, 0x01, 0x00, 0x2a, 0x52,
0x01, 0xc1, 0x01, 0x04, 0x1b, 0x07, 0x74, 0x65, 0x73, 0x74,
0x31, 0x32, 0x33, 0x06, 0x6d, 0x6e, 0x63, 0x30, 0x30, 0x31,
0x06, 0x6d, 0x63, 0x63, 0x30, 0x30, 0x31, 0x04, 0x67, 0x70,
0x72, 0x73, 0x05, 0x01, 0xc0, 0xa8, 0x05, 0x02, 0x27, 0x01,
0x80, 0x50, 0x0b, 0xf6, 0x00, 0xf1, 0x10, 0x80, 0x01, 0x01,
0x35, 0x16, 0x6d, 0xbc, 0x64, 0x01, 0x00 };
uint16 mcc = 61441;
uint16 mnc = 65281;
@ -71,18 +80,35 @@ public:
class rrc_dummy : public rrc_interface_nas
{
public:
rrc_dummy() : last_sdu_len(0) {
plmns.plmn_id.mcc = mcc;
plmns.plmn_id.mnc = mnc;
plmns.tac = 0xffff;
}
void write_sdu(uint32_t lcid, byte_buffer_t *sdu)
{
printf("NAS generated SDU (len=%d):\n", sdu->N_bytes);
last_sdu_len = sdu->N_bytes;
srslte_vec_fprint_byte(stdout, sdu->msg, sdu->N_bytes);
//printf("NAS generated SDU (len=%d):\n", sdu->N_bytes);
//srslte_vec_fprint_byte(stdout, sdu->msg, sdu->N_bytes);
byte_buffer_pool::get_instance()->deallocate(sdu);
}
std::string get_rb_name(uint32_t lcid) { return std::string("lcid"); }
uint32_t get_last_sdu_len() { return last_sdu_len; }
void plmn_search() {};
void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, bool con_req) {};
int plmn_search(srsue::rrc_interface_nas::found_plmn_t* found) {
memcpy(found, &plmns, sizeof(found_plmn_t));
return 1;
};
void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) {};
void set_ue_idenity(LIBLTE_RRC_S_TMSI_STRUCT s_tmsi) {}
bool connection_request(LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM cause, srslte::byte_buffer_t *sdu) {
printf("NAS generated SDU (len=%d):\n", sdu->N_bytes);
last_sdu_len = sdu->N_bytes;
srslte_vec_fprint_byte(stdout, sdu->msg, sdu->N_bytes);
byte_buffer_pool::get_instance()->deallocate(sdu);
return true;
}
bool is_connected() {return false;}
uint16_t get_mcc() { return mcc; }
uint16_t get_mnc() { return mnc; }
@ -90,6 +116,7 @@ public:
private:
uint32_t last_sdu_len;
found_plmn_t plmns;
};
class gw_dummy : public gw_interface_nas, public gw_interface_pdcp
@ -130,15 +157,12 @@ int security_command_test()
uint8_t res[16];
usim.init(&args, &usim_log);
srslte::byte_buffer_pool *pool;
pool = byte_buffer_pool::get_instance();
srsue::nas nas;
srslte_nas_config_t cfg;
nas.init(&usim, &rrc_dummy, &gw, &nas_log, cfg);
// push auth request PDU to NAS to generate security context
byte_buffer_t* tmp = pool->allocate();
byte_buffer_t* tmp = byte_buffer_pool::get_instance()->allocate();
memcpy(tmp->msg, auth_request_pdu, sizeof(auth_request_pdu));
tmp->N_bytes = sizeof(auth_request_pdu);
nas.write_pdu(LCID, tmp);
@ -155,7 +179,7 @@ int security_command_test()
ret = SRSLTE_SUCCESS;
}
pool->cleanup();
byte_buffer_pool::get_instance()->cleanup();
return ret;
}
@ -190,13 +214,22 @@ int mme_attach_request_test()
nas.init(&usim, &rrc_dummy, &gw, &nas_log, nas_cfg);
nas.attach_request();
nas.notify_connection_setup();
// check length of generated NAS SDU
// this will time out in the first place
// finally push attach accept
byte_buffer_t* tmp = byte_buffer_pool::get_instance()->allocate();
memcpy(tmp->msg, attach_accept_pdu, sizeof(attach_accept_pdu));
tmp->N_bytes = sizeof(attach_accept_pdu);
nas.write_pdu(LCID, tmp);
// check length of generated NAS SDU (attach complete)
if (rrc_dummy.get_last_sdu_len() > 3) {
ret = SRSLTE_SUCCESS;
}
byte_buffer_pool::get_instance()->cleanup();
return ret;
}

@ -21,6 +21,8 @@
# Default "auto". B210 USRP: 100 samples, bladeRF: 27.
# burst_preamble_us: Preamble length to transmit before start of burst.
# Default "auto". B210 USRP: 400 us, bladeRF: 0 us.
# continuous_tx: Transmit samples continuously to the radio or on bursts (auto/yes/no).
# Default is auto (yes for UHD, no for rest)
#####################################################################
[rf]
dl_earfcn = 3400
@ -33,6 +35,7 @@ rx_gain = 40
#device_args = auto
#time_adv_nsamples = auto
#burst_preamble_us = auto
#continuous_tx = auto
#####################################################################
@ -150,7 +153,9 @@ enable = false
# sampling frequency offset. Default is enabled.
# sss_algorithm: Selects the SSS estimation algorithm. Can choose between
# {full, partial, diff}.
# estimator_fil_w: Chooses the coefficients for the 3-tap channel estimator centered filter.
# estimator_fil_auto: The channel estimator smooths the channel estimate with an adaptative filter.
# estimator_fil_stddev: Sets the channel estimator smooth gaussian filter standard deviation.
# estimator_fil_order: Sets the channel estimator smooth gaussian filter order (even values perform better).
# The taps are [w, 1-2w, w]
# metrics_period_secs: Sets the period at which metrics are requested from the UE.
#
@ -204,7 +209,9 @@ enable = false
#time_correct_period = 5
#sfo_correct_disable = false
#sss_algorithm = full
#estimator_fil_w = 0.1
#estimator_fil_auto = false
#estimator_fil_stddev = 1.0
#estimator_fil_order = 4
#average_subframe_enabled = true
#sic_pss_enabled = true
#pregenerate_signals = false

Loading…
Cancel
Save