Merge branch 'next' into rlc_updates

master
Andre Puschmann 7 years ago
commit a2f6166365

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

@ -20,5 +20,5 @@
SET(SRSLTE_VERSION_MAJOR 18) SET(SRSLTE_VERSION_MAJOR 18)
SET(SRSLTE_VERSION_MINOR 3) 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}") SET(SRSLTE_VERSION_STRING "${SRSLTE_VERSION_MAJOR}.${SRSLTE_VERSION_MINOR}.${SRSLTE_VERSION_PATCH}")

@ -51,9 +51,11 @@
// FIXME: This was chosen arbitrarily // FIXME: This was chosen arbitrarily
#define LIBLTE_ASN1_OID_MAXSUBIDS 128 #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_BITS 102048
#define LIBLTE_MAX_MSG_SIZE_BYTES 12756 #define LIBLTE_MAX_MSG_SIZE_BYTES 12756
#define LIBLTE_MSG_HEADER_OFFSET 1024 #define LIBLTE_MSG_HEADER_OFFSET 1020
/******************************************************************************* /*******************************************************************************
TYPEDEFS TYPEDEFS
@ -82,6 +84,8 @@ static const char liblte_error_text[LIBLTE_ERROR_N_ITEMS][64] = {
"Decode failure", "Decode failure",
}; };
#define LIBLTE_STRING_LEN 128
typedef void* LIBLTE_ASN1_OPEN_TYPE_STRUCT; typedef void* LIBLTE_ASN1_OPEN_TYPE_STRUCT;
typedef struct { typedef struct {
@ -96,86 +100,15 @@ typedef struct{
typedef struct{ typedef struct{
uint32 N_bits; uint32 N_bits;
uint8 header[LIBLTE_MSG_HEADER_OFFSET];
uint8 msg[LIBLTE_MAX_MSG_SIZE_BITS]; uint8 msg[LIBLTE_MAX_MSG_SIZE_BITS];
}LIBLTE_SIMPLE_BIT_MSG_STRUCT; }LIBLTE_BIT_MSG_STRUCT;
typedef struct{ typedef struct{
uint32 N_bytes; uint32 N_bytes;
uint8 header[LIBLTE_MSG_HEADER_OFFSET];
uint8 msg[LIBLTE_MAX_MSG_SIZE_BYTES]; uint8 msg[LIBLTE_MAX_MSG_SIZE_BYTES];
}LIBLTE_SIMPLE_BYTE_MSG_STRUCT; }LIBLTE_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++;
}
}
};
/******************************************************************************* /*******************************************************************************

@ -1209,7 +1209,7 @@ static const char liblte_mme_add_ci_text[LIBLTE_MME_ADD_CI_N_ITEMS][20] = {"Don'
"Add"}; "Add"};
// Structs // Structs
typedef struct{ typedef struct{
std::string name; char name[LIBLTE_STRING_LEN];
LIBLTE_MME_ADD_CI_ENUM add_ci; LIBLTE_MME_ADD_CI_ENUM add_ci;
}LIBLTE_MME_NETWORK_NAME_STRUCT; }LIBLTE_MME_NETWORK_NAME_STRUCT;
// Functions // Functions
@ -1752,7 +1752,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_guti_type_ie(uint8 **ie_
// Enums // Enums
// Structs // Structs
typedef struct{ typedef struct{
std::string apn; char apn[LIBLTE_STRING_LEN];
}LIBLTE_MME_ACCESS_POINT_NAME_STRUCT; }LIBLTE_MME_ACCESS_POINT_NAME_STRUCT;
// Functions // Functions
LIBLTE_ERROR_ENUM liblte_mme_pack_access_point_name_ie(LIBLTE_MME_ACCESS_POINT_NAME_STRUCT *apn, 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"}; "CDMA2000-HRPD"};
// Structs // Structs
typedef struct{ 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_TYPE_ENUM dedicated_info_type;
}LIBLTE_RRC_UL_INFORMATION_TRANSFER_STRUCT; }LIBLTE_RRC_UL_INFORMATION_TRANSFER_STRUCT;
// Functions // Functions
@ -5960,7 +5960,7 @@ typedef struct{
}LIBLTE_RRC_REGISTERED_MME_STRUCT; }LIBLTE_RRC_REGISTERED_MME_STRUCT;
typedef struct{ typedef struct{
LIBLTE_RRC_REGISTERED_MME_STRUCT registered_mme; 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 rrc_transaction_id;
uint8 selected_plmn_id; uint8 selected_plmn_id;
bool registered_mme_present; bool registered_mme_present;
@ -6245,7 +6245,7 @@ typedef struct{
typedef struct{ typedef struct{
LIBLTE_RRC_MEAS_CONFIG_STRUCT meas_cnfg; LIBLTE_RRC_MEAS_CONFIG_STRUCT meas_cnfg;
LIBLTE_RRC_MOBILITY_CONTROL_INFO_STRUCT mob_ctrl_info; 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_RR_CONFIG_DEDICATED_STRUCT rr_cnfg_ded;
LIBLTE_RRC_SECURITY_CONFIG_HO_STRUCT sec_cnfg_ho; LIBLTE_RRC_SECURITY_CONFIG_HO_STRUCT sec_cnfg_ho;
uint32 N_ded_info_nas; 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"}; "CDMA2000-HRPD"};
// Structs // Structs
typedef struct{ 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; LIBLTE_RRC_DL_INFORMATION_TRANSFER_TYPE_ENUM dedicated_info_type;
uint8 rrc_transaction_id; uint8 rrc_transaction_id;
}LIBLTE_RRC_DL_INFORMATION_TRANSFER_STRUCT; }LIBLTE_RRC_DL_INFORMATION_TRANSFER_STRUCT;

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

@ -41,29 +41,35 @@ namespace srslte {
class pdu_queue class pdu_queue
{ {
public: public:
typedef enum {
DCH,
BCH,
MCH
} channel_t;
class process_callback class process_callback
{ {
public: 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) {} pdu_queue(uint32_t pool_size = DEFAULT_POOL_SIZE) : pool(pool_size), callback(NULL), log_h(NULL) {}
void init(process_callback *callback, log* log_h_); void init(process_callback *callback, log* log_h_);
uint8_t* request(uint32_t len); uint8_t* request(uint32_t len);
void deallocate(uint8_t* pdu); 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(); bool process_pdus();
private: private:
const static int DEFAULT_POOL_SIZE = 64; // Number of PDU buffers in total const static int DEFAULT_POOL_SIZE = 64; // Number of PDU buffers in total
const static int MAX_PDU_LEN = 150*1024/8; // ~ 150 Mbps const static int MAX_PDU_LEN = 150*1024/8; // ~ 150 Mbps
typedef struct { typedef struct {
uint8_t ptr[MAX_PDU_LEN]; uint8_t ptr[MAX_PDU_LEN];
uint32_t len; uint32_t len;
uint32_t tstamp; uint32_t tstamp;
channel_t channel;
#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED #ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED
char debug_name[128]; char debug_name[128];
#endif #endif

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

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

@ -112,30 +112,34 @@ public:
class nas_interface_rrc class nas_interface_rrc
{ {
public: 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_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 void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0;
virtual uint32_t get_ul_count() = 0; virtual uint32_t get_ul_count() = 0;
virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 0;
virtual bool get_k_asme(uint8_t *k_asme_, uint32_t n) = 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 // NAS interface for UE
class nas_interface_ue class nas_interface_ue
{ {
public: public:
virtual void attach_request() = 0; virtual bool attach_request() = 0;
virtual void deattach_request() = 0; virtual bool deattach_request() = 0;
}; };
// NAS interface for UE // NAS interface for UE
class nas_interface_gw class nas_interface_gw
{ {
public: public:
virtual void attach_request() = 0; virtual bool attach_request() = 0;
}; };
// RRC interface for MAC // RRC interface for MAC
@ -159,8 +163,6 @@ class rrc_interface_phy
public: public:
virtual void in_sync() = 0; virtual void in_sync() = 0;
virtual void out_of_sync() = 0; virtual void out_of_sync() = 0;
virtual void earfcn_end() = 0;
virtual void cell_camping(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp = NAN) = 0;
virtual void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn = -1, int pci = -1) = 0; virtual void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn = -1, int pci = -1) = 0;
}; };
@ -168,12 +170,23 @@ public:
class rrc_interface_nas class rrc_interface_nas
{ {
public: 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 void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0;
virtual uint16_t get_mcc() = 0; virtual uint16_t get_mcc() = 0;
virtual uint16_t get_mnc() = 0; virtual uint16_t get_mnc() = 0;
virtual void enable_capabilities() = 0; virtual void enable_capabilities() = 0;
virtual void plmn_search() = 0; virtual int plmn_search(found_plmn_t found_plmns[MAX_FOUND_PLMNS]) = 0;
virtual void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, bool connect_request = false) = 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; virtual std::string get_rb_name(uint32_t lcid) = 0;
}; };
@ -380,12 +393,7 @@ public:
/* Indicate successfull decoding of PCH TB through PDSCH */ /* Indicate successfull decoding of PCH TB through PDSCH */
virtual void pch_decoded_ok(uint32_t len) = 0; 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 */ /* Interface RRC -> MAC shared between different RATs */
@ -420,15 +428,14 @@ public:
uint32_t prach_config_index; uint32_t prach_config_index;
} mac_cfg_t; } mac_cfg_t;
virtual void clear_rntis() = 0;
/* Instructs the MAC to start receiving BCCH */ /* 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; virtual void bcch_start_rx(int si_window_start, int si_window_length) = 0;
/* Instructs the MAC to start receiving PCCH */ /* Instructs the MAC to start receiving PCCH */
virtual void pcch_start_rx() = 0; virtual void pcch_start_rx() = 0;
virtual void pcch_stop_rx() = 0;
/* RRC configures a logical channel */ /* 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; 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_loop_pss_conv;
uint32_t cfo_ref_mask; uint32_t cfo_ref_mask;
bool average_subframe_enabled; 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; std::string sss_algorithm;
float estimator_fil_w;
bool rssi_sensor_enabled; bool rssi_sensor_enabled;
bool sic_pss_enabled; bool sic_pss_enabled;
float rx_gain_offset; float rx_gain_offset;
@ -503,9 +511,7 @@ typedef struct {
class phy_interface_mac_common class phy_interface_mac_common
{ {
public: 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 */ /* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */
virtual void set_crnti(uint16_t rnti) = 0; 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_start(uint32_t earfcn, int pci = -1) = 0;
virtual int meas_stop(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 */ /* Cell search and selection procedures */
virtual void cell_search_start() = 0; virtual cell_search_ret_t cell_search(phy_cell_t *cell) = 0;
virtual void cell_search_next() = 0; virtual bool cell_select(phy_cell_t *cell = NULL) = 0;
virtual void cell_select(uint32_t earfcn, srslte_cell_t cell) = 0; virtual bool cell_is_camping() = 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;
/* Configure UL using parameters written with set_param() */ /* Configure UL using parameters written with set_param() */
virtual void configure_ul_params(bool pregen_disabled = false) = 0; virtual void configure_ul_params(bool pregen_disabled = false) = 0;

@ -74,6 +74,7 @@ typedef struct {
float snr_vector[12000]; float snr_vector[12000];
float pilot_power[12000]; float pilot_power[12000];
#endif #endif
bool smooth_filter_auto;
uint32_t smooth_filter_len; uint32_t smooth_filter_len;
float smooth_filter[SRSLTE_CHEST_MAX_SMOOTH_FIL_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, SRSLTE_API int srslte_chest_dl_set_mbsfn_area_id(srslte_chest_dl_t *q,
uint16_t mbsfn_area_id); uint16_t mbsfn_area_id);
SRSLTE_API int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, SRSLTE_API int srslte_chest_dl_set_cell(srslte_chest_dl_t *q,
srslte_cell_t cell); srslte_cell_t cell);
SRSLTE_API void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q, SRSLTE_API void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q,
float *filter, float *filter,
uint32_t filter_len); 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, SRSLTE_API void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q,
float w); 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_API void srslte_chest_dl_set_noise_alg(srslte_chest_dl_t *q,
srslte_chest_dl_noise_alg_t noise_estimation_alg); 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], SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS],
cf_t *x, cf_t *x,
float *csi, float *csi[SRSLTE_MAX_CODEWORDS],
int nof_rxant, int nof_rxant,
int nof_symbols, int nof_symbols,
float scaling, float scaling,
@ -102,7 +102,8 @@ SRSLTE_API int srslte_predecoding_diversity(cf_t *y,
SRSLTE_API int srslte_predecoding_diversity_multi(cf_t *y[SRSLTE_MAX_PORTS], SRSLTE_API int srslte_predecoding_diversity_multi(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
float *csi[SRSLTE_MAX_LAYERS],
int nof_rxant, int nof_rxant,
int nof_ports, int nof_ports,
int nof_symbols, 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], SRSLTE_API int srslte_predecoding_type(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], cf_t *x[SRSLTE_MAX_LAYERS],
float *csi, float *csi[SRSLTE_MAX_CODEWORDS],
int nof_rxant, int nof_rxant,
int nof_ports, int nof_ports,
int nof_layers, int nof_layers,

@ -64,7 +64,7 @@ typedef struct SRSLTE_API {
uint8_t *parity_bits; uint8_t *parity_bits;
void *e; void *e;
uint8_t *temp_g_bits; uint8_t *temp_g_bits;
uint16_t *ul_interleaver; uint32_t *ul_interleaver;
srslte_uci_bit_t ack_ri_bits[12*288]; srslte_uci_bit_t ack_ri_bits[12*288];
uint32_t nof_ri_ack_bits; 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 src_offset,
uint32_t nof_bits); 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, SRSLTE_API void srslte_bit_interleave_w_offset(uint8_t *input,
uint8_t *output, uint8_t *output,
uint16_t *interleaver, 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 noise_estimate,
float norm); 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, SRSLTE_API float srslte_mat_2x2_cn(cf_t h00,
cf_t h01, cf_t h01,
cf_t h10, cf_t h10,
cf_t h11); cf_t h11);
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
/* SSE implementation for complex reciprocal */ /* 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 /* 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 #ifdef LV_HAVE_AVX512
return _mm512_loadu_ps(ptr); return _mm512_loadu_ps(ptr);
#else /* LV_HAVE_AVX512 */ #else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2 #ifdef LV_HAVE_AVX2
return _mm256_loadu_ps(ptr); return _mm256_loadu_ps(ptr);
#else /* LV_HAVE_AVX2 */ #else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE #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 #ifdef LV_HAVE_AVX512
_mm512_storeu_ps(ptr, simdreg); _mm512_storeu_ps(ptr, simdreg);
#else /* LV_HAVE_AVX512 */ #else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2 #ifdef LV_HAVE_AVX2
_mm256_storeu_ps(ptr, simdreg); _mm256_storeu_ps(ptr, simdreg);
#else /* LV_HAVE_AVX2 */ #else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
@ -360,7 +360,7 @@ static inline simd_f_t srslte_simd_f_add(simd_f_t a, simd_f_t b) {
#ifdef LV_HAVE_AVX2 #ifdef LV_HAVE_AVX2
return _mm256_add_ps(a, b); return _mm256_add_ps(a, b);
#else /* LV_HAVE_AVX2 */ #else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
return _mm_add_ps(a, b); return _mm_add_ps(a, b);
#else /* LV_HAVE_SSE */ #else /* LV_HAVE_SSE */
#ifdef HAVE_NEON #ifdef HAVE_NEON
@ -376,9 +376,9 @@ static inline simd_f_t srslte_simd_f_zero (void) {
return _mm512_setzero_ps(); return _mm512_setzero_ps();
#else /* LV_HAVE_AVX512 */ #else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2 #ifdef LV_HAVE_AVX2
return _mm256_setzero_ps(); return _mm256_setzero_ps();
#else /* LV_HAVE_AVX2 */ #else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
return _mm_setzero_ps(); return _mm_setzero_ps();
#else /* LV_HAVE_SSE */ #else /* LV_HAVE_SSE */
#ifdef HAVE_NEON #ifdef HAVE_NEON
@ -401,7 +401,7 @@ static inline simd_f_t srslte_simd_f_swap(simd_f_t a) {
#else /* LV_HAVE_SSE */ #else /* LV_HAVE_SSE */
#ifdef HAVE_NEON #ifdef HAVE_NEON
return vcombine_f32(vrev64_f32(vget_low_f32(a)), vrev64_f32(vget_high_f32(a))); return vcombine_f32(vrev64_f32(vget_low_f32(a)), vrev64_f32(vget_high_f32(a)));
#endif /* HAVE_NEON */ #endif /* HAVE_NEON */
#endif /* LV_HAVE_SSE */ #endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX2 */ #endif /* LV_HAVE_AVX2 */
#endif /* LV_HAVE_AVX512 */ #endif /* LV_HAVE_AVX512 */
@ -443,7 +443,7 @@ static inline simd_f_t srslte_simd_f_sqrt(simd_f_t a) {
#ifdef LV_HAVE_AVX512 #ifdef LV_HAVE_AVX512
return _mm512_sqrt_ps(a); return _mm512_sqrt_ps(a);
#else /* LV_HAVE_AVX512 */ #else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2 #ifdef LV_HAVE_AVX2
return _mm256_sqrt_ps(a); return _mm256_sqrt_ps(a);
#else /* LV_HAVE_AVX2 */ #else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
@ -458,7 +458,43 @@ static inline simd_f_t srslte_simd_f_sqrt(simd_f_t a) {
float32x4_t zeros = vmovq_n_f32(0); /* Zero vector */ float32x4_t zeros = vmovq_n_f32(0); /* Zero vector */
uint32x4_t mask = vceqq_f32(a, zeros); /* Zero vector mask */ uint32x4_t mask = vceqq_f32(a, zeros); /* Zero vector mask */
return vbslq_f32(mask, zeros, result); /* Force zero results and return */ return vbslq_f32(mask, zeros, result); /* Force zero results and return */
#endif /* HAVE_NEON */ #endif /* HAVE_NEON */
#endif /* LV_HAVE_SSE */
#endif /* LV_HAVE_AVX2 */
#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_SSE */
#endif /* LV_HAVE_AVX2 */ #endif /* LV_HAVE_AVX2 */
#endif /* LV_HAVE_AVX512 */ #endif /* LV_HAVE_AVX512 */
@ -470,12 +506,11 @@ static inline simd_f_t srslte_simd_f_sqrt(simd_f_t a) {
#if SRSLTE_SIMD_CF_SIZE #if SRSLTE_SIMD_CF_SIZE
#ifdef HAVE_NEON #ifdef HAVE_NEON
typedef float32x4x2_t simd_cf_t; typedef float32x4x2_t simd_cf_t;
#else #else
typedef struct { typedef struct {
simd_f_t re; simd_f_t re;
simd_f_t im; simd_f_t im;
} simd_cf_t; } simd_cf_t;
#endif #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); _mm512_store_ps(im, simdreg.im);
#else /* LV_HAVE_AVX512 */ #else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2 #ifdef LV_HAVE_AVX2
_mm256_store_ps((float *) re, simdreg.re); _mm256_store_ps(re, simdreg.re);
_mm256_store_ps((float *) im, simdreg.im); _mm256_store_ps(im, simdreg.im);
#else /* LV_HAVE_AVX512 */ #else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
_mm_store_ps((float *) re, simdreg.re); _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); _mm512_storeu_ps(im, simdreg.im);
#else /* LV_HAVE_AVX512 */ #else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2 #ifdef LV_HAVE_AVX2
_mm256_storeu_ps((float *) re, simdreg.re); _mm256_storeu_ps(re, simdreg.re);
_mm256_storeu_ps((float *) im, simdreg.im); _mm256_storeu_ps(im, simdreg.im);
#else /* LV_HAVE_AVX512 */ #else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_SSE #ifdef LV_HAVE_SSE
_mm_storeu_ps((float *) re, simdreg.re); _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; 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) { 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 #ifdef LV_HAVE_AVX512
ret.re = _mm512_mul_ps(a.re, b); ret.re = _mm512_mul_ps(a.re, b);
ret.im = _mm512_mul_ps(a.im, 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_SSE */
#endif /* LV_HAVE_AVX2 */ #endif /* LV_HAVE_AVX2 */
#endif /* LV_HAVE_AVX512 */ #endif /* LV_HAVE_AVX512 */
return ret; return ret;
} }
static inline simd_cf_t srslte_simd_cf_rcp (simd_cf_t a) { 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; 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) { static inline simd_cf_t srslte_simd_cf_zero (void) {
simd_cf_t ret; simd_cf_t ret;
#ifdef LV_HAVE_AVX512 #ifdef LV_HAVE_AVX512
@ -1057,7 +1169,7 @@ static inline simd_i_t srslte_simd_i_select(simd_i_t a, simd_i_t b, simd_sel_t s
int* sel = (int*) &selector; int* sel = (int*) &selector;
int* c_ptr = (int*) &ret; int* c_ptr = (int*) &ret;
for(int i = 0;i<4;i++) for(int i = 0;i<4;i++)
{ {
if(sel[i] == -1){ if(sel[i] == -1){
c_ptr[i] = b_ptr[i]; c_ptr[i] = b_ptr[i];
}else{ }else{
@ -1115,7 +1227,7 @@ static inline simd_s_t srslte_simd_s_loadu(const int16_t *ptr) {
#ifdef LV_HAVE_AVX512 #ifdef LV_HAVE_AVX512
return _mm512_loadu_si512(ptr); return _mm512_loadu_si512(ptr);
#else /* LV_HAVE_AVX512 */ #else /* LV_HAVE_AVX512 */
#ifdef LV_HAVE_AVX2 #ifdef LV_HAVE_AVX2
return _mm256_loadu_si256((__m256i*) ptr); return _mm256_loadu_si256((__m256i*) ptr);
#else /* LV_HAVE_AVX2 */ #else /* LV_HAVE_AVX2 */
#ifdef LV_HAVE_SSE #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_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_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) */ /* 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); 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 #define SRSLTE_RADIO_H
typedef struct { typedef struct {
float tx_corr_dc_gain; float tx_corr_dc_gain;
float tx_corr_dc_phase; float tx_corr_dc_phase;
float tx_corr_iq_i; float tx_corr_iq_i;
float tx_corr_iq_q; float tx_corr_iq_q;
float rx_corr_dc_gain; float rx_corr_dc_gain;
float rx_corr_dc_phase; float rx_corr_dc_phase;
float rx_corr_iq_i; float rx_corr_iq_i;
float rx_corr_iq_q; float rx_corr_iq_q;
}rf_cal_t; } rf_cal_t;
namespace srslte { namespace srslte {
/* Interface to the RF frontend. /* Interface to the RF frontend.
*/ */
class radio class radio {
{ public:
public: radio() : tr_local_time(1024 * 10), tr_usrp_time(1024 * 10), tr_tx_time(1024 * 10), tr_is_eob(1024 * 10) {
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(&rf_device, sizeof(srslte_rf_t)); bzero(&end_of_burst_time, sizeof(srslte_timestamp_t));
bzero(&end_of_burst_time, sizeof(srslte_timestamp_t)); bzero(zeros, burst_preamble_max_samples * sizeof(cf_t));
bzero(zeros, burst_preamble_max_samples*sizeof(cf_t));
burst_preamble_sec = 0;
burst_preamble_sec = 0; is_start_of_burst = false;
is_start_of_burst = false; burst_preamble_samples = 0;
burst_preamble_samples = 0; burst_preamble_time_rounded = 0;
burst_preamble_time_rounded = 0;
cur_tx_srate = 0;
cur_tx_srate = 0; tx_adv_sec = 0;
tx_adv_sec = 0; tx_adv_nsamples = 0;
tx_adv_nsamples = 0; tx_adv_auto = false;
tx_adv_auto = false; tx_adv_negative = false;
tx_adv_negative = false; tx_freq = 0;
tx_freq = 0; rx_freq = 0;
rx_freq = 0; trace_enabled = false;
trace_enabled = false; tti = 0;
tti = 0; agc_enabled = false;
agc_enabled = false; radio_is_streaming = false;
radio_is_streaming = false; is_initialized = false;
is_initialized = false; continuous_tx = false;
}; };
bool init(char *args = NULL, char *devname = NULL, uint32_t nof_channels = 1); bool init(char *args = NULL, char *devname = NULL, uint32_t nof_channels = 1);
void stop(); void stop();
void reset(); void reset();
bool start_agc(bool tx_gain_same_rx); bool start_agc(bool tx_gain_same_rx);
void set_burst_preamble(double preamble_us); void set_burst_preamble(double preamble_us);
void set_tx_adv(int nsamples); void set_tx_adv(int nsamples);
void set_tx_adv_neg(bool tx_adv_is_neg); void set_tx_adv_neg(bool tx_adv_is_neg);
void set_manual_calibration(rf_cal_t *calibration); void set_manual_calibration(rf_cal_t *calibration);
void get_time(srslte_timestamp_t *now); bool is_continuous_tx();
bool tx_single(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); void set_continuous_tx(bool enable);
bool tx(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time);
void tx_end(); void get_time(srslte_timestamp_t *now);
bool rx_now(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t *rxd_time); bool tx_single(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
bool rx_at(void *buffer, uint32_t nof_samples, srslte_timestamp_t rx_time); bool tx(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time);
void tx_end();
void set_tx_gain(float gain); bool rx_now(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t *rxd_time);
void set_rx_gain(float gain); bool rx_at(void *buffer, uint32_t nof_samples, srslte_timestamp_t rx_time);
void set_tx_rx_gain_offset(float offset);
double set_rx_gain_th(float gain); void set_tx_gain(float gain);
void set_rx_gain(float gain);
void set_freq_offset(double freq); void set_tx_rx_gain_offset(float offset);
void set_tx_freq(double freq); double set_rx_gain_th(float gain);
void set_rx_freq(double freq);
void set_freq_offset(double freq);
double get_freq_offset(); void set_tx_freq(double freq);
double get_tx_freq(); void set_rx_freq(double freq);
double get_rx_freq();
double get_freq_offset();
void set_master_clock_rate(double rate); double get_tx_freq();
void set_tx_srate(double srate); double get_rx_freq();
void set_rx_srate(double srate);
void set_master_clock_rate(double rate);
float get_tx_gain(); void set_tx_srate(double srate);
float get_rx_gain(); void set_rx_srate(double srate);
float get_max_tx_power(); float get_tx_gain();
float set_tx_power(float power); float get_rx_gain();
float get_rssi();
bool has_rssi(); float get_max_tx_power();
float set_tx_power(float power);
void start_trace(); float get_rssi();
void write_trace(std::string filename); bool has_rssi();
void set_tti(uint32_t tti); void start_trace();
void write_trace(std::string filename);
bool is_first_of_burst();
void set_tti(uint32_t tti);
bool is_init();
bool is_first_of_burst();
void register_error_handler(srslte_rf_error_handler_t h);
bool is_init();
protected:
void register_error_handler(srslte_rf_error_handler_t h);
void save_trace(uint32_t is_eob, srslte_timestamp_t *usrp_time);
protected:
srslte_rf_t rf_device;
void save_trace(uint32_t is_eob, srslte_timestamp_t *usrp_time);
const static uint32_t burst_preamble_max_samples = 30720000; // 30.72 MHz is maximum frequency srslte_rf_t rf_device;
double burst_preamble_sec;// Start of burst preamble time (off->on RF transition time)
srslte_timestamp_t end_of_burst_time; const static uint32_t burst_preamble_max_samples = 30720000; // 30.72 MHz is maximum frequency
bool is_start_of_burst; double burst_preamble_sec;// Start of burst preamble time (off->on RF transition time)
uint32_t burst_preamble_samples; srslte_timestamp_t end_of_burst_time;
double burst_preamble_time_rounded; // preamble time rounded to sample time bool is_start_of_burst;
cf_t zeros[burst_preamble_max_samples]; uint32_t burst_preamble_samples;
double cur_tx_srate; double burst_preamble_time_rounded; // preamble time rounded to sample time
cf_t zeros[burst_preamble_max_samples];
double tx_adv_sec; // Transmission time advance to compensate for antenna->timestamp delay double cur_tx_srate;
int tx_adv_nsamples; // Transmision time advance in number of samples
double tx_adv_sec; // Transmission time advance to compensate for antenna->timestamp delay
// Define default values for known radios int tx_adv_nsamples; // Transmision time advance in number of samples
bool tx_adv_auto;
bool tx_adv_negative; // Define default values for known radios
const static double uhd_default_burst_preamble_sec = 600*1e-6; bool tx_adv_auto;
const static double uhd_default_tx_adv_samples = 98; bool tx_adv_negative;
const static double uhd_default_tx_adv_offset_sec = 4*1e-6; const static double uhd_default_burst_preamble_sec = 600 * 1e-6;
const static double uhd_default_tx_adv_samples = 98;
const static double blade_default_burst_preamble_sec = 0.0; const static double uhd_default_tx_adv_offset_sec = 4 * 1e-6;
const static double blade_default_tx_adv_samples = 27;
const static double blade_default_tx_adv_offset_sec = 1e-6; const static double blade_default_burst_preamble_sec = 0.0;
const static double blade_default_tx_adv_samples = 27;
double tx_freq, rx_freq, freq_offset; const static double blade_default_tx_adv_offset_sec = 1e-6;
trace<uint32_t> tr_local_time; double tx_freq, rx_freq, freq_offset;
trace<uint32_t> tr_usrp_time;
trace<uint32_t> tr_tx_time; trace<uint32_t> tr_local_time;
trace<uint32_t> tr_is_eob; trace<uint32_t> tr_usrp_time;
bool trace_enabled; trace<uint32_t> tr_tx_time;
uint32_t tti; trace<uint32_t> tr_is_eob;
bool agc_enabled; bool trace_enabled;
uint32_t tti;
bool is_initialized = true;; bool agc_enabled;
bool radio_is_streaming;
bool continuous_tx;
uint32_t saved_nof_channels; bool is_initialized;
char saved_args[128]; bool radio_is_streaming;
char saved_devname[128];
uint32_t saved_nof_channels;
}; char saved_args[128];
char saved_devname[128];
};
} }
#endif // SRSLTE_RADIO_H #endif // SRSLTE_RADIO_H

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

@ -31,7 +31,6 @@
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/msg_queue.h"
#include "srslte/upper/rlc_entity.h" #include "srslte/upper/rlc_entity.h"
#include "srslte/upper/rlc_metrics.h" #include "srslte/upper/rlc_metrics.h"
#include "srslte/upper/rlc_common.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 i;
uint32 bit_offset; uint32 bit_offset;
uint32 byte_offset; uint32 byte_offset;
const char *char_str = net_name->name.c_str(); const char *char_str = net_name->name;
if(net_name != NULL && if(net_name != NULL &&
ie_ptr != NULL) ie_ptr != NULL)
{ {
bit_offset = 0; bit_offset = 0;
byte_offset = 2; 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 || if(char_str[i] == 0x0A ||
char_str[i] == 0x0D || char_str[i] == 0x0D ||
@ -2319,6 +2319,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_network_name_ie(uint8
uint32 N_bytes; uint32 N_bytes;
uint8 spare_field; uint8 spare_field;
char tmp_char; char tmp_char;
uint32 str_cnt;
if(ie_ptr != NULL && if(ie_ptr != NULL &&
net_name != NULL) net_name != NULL)
@ -2328,8 +2329,9 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_network_name_ie(uint8
N_bytes = (*ie_ptr)[0]; N_bytes = (*ie_ptr)[0];
bit_offset = 0; bit_offset = 0;
byte_offset = 2; byte_offset = 2;
net_name->name = ""; str_cnt = 0;
while(byte_offset < N_bytes)
while(byte_offset < N_bytes && str_cnt < LIBLTE_STRING_LEN)
{ {
switch(bit_offset) switch(bit_offset)
{ {
@ -2389,7 +2391,10 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_network_name_ie(uint8
(tmp_char >= 0x61 && (tmp_char >= 0x61 &&
tmp_char <= 0x7A)) 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 >= 0x61 &&
tmp_char <= 0x7A)) 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; *ie_ptr += byte_offset + 1;
err = LIBLTE_SUCCESS; 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 && if(apn != NULL &&
ie_ptr != NULL) ie_ptr != NULL)
{ {
apn_str = apn->apn.c_str(); apn_str = apn->apn;
(*ie_ptr)[0] = apn->apn.length()+1; (*ie_ptr)[0] = strnlen(apn->apn, LIBLTE_STRING_LEN)+1;
len_idx = 0; len_idx = 0;
apn_idx = 0; apn_idx = 0;
label_len = 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]; (*ie_ptr)[1+apn_idx+1] = (uint8)apn_str[apn_idx];
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)[1+len_idx] = label_len;
*ie_ptr += apn->apn.length() + 2; *ie_ptr += strnlen(apn->apn, LIBLTE_STRING_LEN) + 2;
err = LIBLTE_SUCCESS; err = LIBLTE_SUCCESS;
} }
@ -3799,26 +3812,31 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_access_point_name_ie(uint8
uint32 i; uint32 i;
uint32 ie_idx; uint32 ie_idx;
uint32 label_len; uint32 label_len;
uint32 str_cnt;
if(ie_ptr != NULL && if(ie_ptr != NULL &&
apn != NULL) apn != NULL)
{ {
apn->apn.clear();
ie_idx = 0; 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]; 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; 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; *ie_ptr += (*ie_ptr)[0] + 1;
err = LIBLTE_SUCCESS; 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 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) uint8 **ie_ptr)
{ {
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; 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); return(err);
} }
LIBLTE_ERROR_ENUM liblte_rrc_unpack_dedicated_info_cdma2000_ie(uint8 **ie_ptr, 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; LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint32 i; 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 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) uint8 **ie_ptr)
{ {
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; 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); return(err);
} }
LIBLTE_ERROR_ENUM liblte_rrc_unpack_dedicated_info_nas_ie(uint8 **ie_ptr, 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; LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint32 i; 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); liblte_value_2_bits(rep_cnfg_eutra->trigger_type, ie_ptr, 1);
if(LIBLTE_RRC_TRIGGER_TYPE_EUTRA_EVENT == rep_cnfg_eutra->trigger_type) 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 // Event ID
// FIXME: Handle extension properly
liblte_value_2_bits(rep_cnfg_eutra->event.event_id, ie_ptr, 3); 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) 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, ...) { void log_filter::console(const char * message, ...) {
char *args_msg; char *args_msg = NULL;
va_list args; va_list args;
va_start(args, message); va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0) 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, ...) { void log_filter::error(const char * message, ...) {
if (level >= LOG_LEVEL_ERROR) { if (level >= LOG_LEVEL_ERROR) {
char *args_msg; char *args_msg = NULL;
va_list args; va_list args;
va_start(args, message); va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0) 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, ...) { void log_filter::warning(const char * message, ...) {
if (level >= LOG_LEVEL_WARNING) { if (level >= LOG_LEVEL_WARNING) {
char *args_msg; char *args_msg = NULL;
va_list args; va_list args;
va_start(args, message); va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0) 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, ...) { void log_filter::info(const char * message, ...) {
if (level >= LOG_LEVEL_INFO) { if (level >= LOG_LEVEL_INFO) {
char *args_msg; char *args_msg = NULL;
va_list args; va_list args;
va_start(args, message); va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0) 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, ...) { void log_filter::debug(const char * message, ...) {
if (level >= LOG_LEVEL_DEBUG) { if (level >= LOG_LEVEL_DEBUG) {
char *args_msg; char *args_msg = NULL;
va_list args; va_list args;
va_start(args, message); va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0) 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, ...) { void log_filter::error_hex(const uint8_t *hex, int size, const char * message, ...) {
if (level >= LOG_LEVEL_ERROR) { if (level >= LOG_LEVEL_ERROR) {
char *args_msg; char *args_msg = NULL;
va_list args; va_list args;
va_start(args, message); va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0) 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, ...) { void log_filter::warning_hex(const uint8_t *hex, int size, const char * message, ...) {
if (level >= LOG_LEVEL_WARNING) { if (level >= LOG_LEVEL_WARNING) {
char *args_msg; char *args_msg = NULL;
va_list args; va_list args;
va_start(args, message); va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0) 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, ...) { void log_filter::info_hex(const uint8_t *hex, int size, const char * message, ...) {
if (level >= LOG_LEVEL_INFO) { if (level >= LOG_LEVEL_INFO) {
char *args_msg; char *args_msg = NULL;
va_list args; va_list args;
va_start(args, message); va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0) 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, ...) { void log_filter::debug_hex(const uint8_t *hex, int size, const char * message, ...) {
if (level >= LOG_LEVEL_DEBUG) { if (level >= LOG_LEVEL_DEBUG) {
char *args_msg; char *args_msg = NULL;
va_list args; va_list args;
va_start(args, message); va_start(args, message);
if(vasprintf(&args_msg, message, args) > 0) 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 * This function enqueues the packet and returns quicly because ACK
* deadline is important here. * 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) { if (ptr) {
pdu_t *pdu = (pdu_t*) ptr; pdu_t *pdu = (pdu_t*) ptr;
pdu->len = len; pdu->len = len;
pdu->tstamp = tstamp; pdu->tstamp = tstamp;
pdu->channel = channel;
pdu_q.push(pdu); pdu_q.push(pdu);
} else { } else {
log_h->warning("Error pushing pdu: ptr is empty\n"); log_h->warning("Error pushing pdu: ptr is empty\n");
@ -88,15 +89,17 @@ void pdu_queue::push(uint8_t *ptr, uint32_t len, uint32_t tstamp)
bool pdu_queue::process_pdus() bool pdu_queue::process_pdus()
{ {
bool have_data = false; bool have_data = false;
uint32_t cnt = 0; uint32_t cnt = 0;
pdu_t *pdu; pdu_t *pdu;
while(pdu_q.try_pop(&pdu)) { while(pdu_q.try_pop(&pdu)) {
if (callback) { 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)) { if (pdu->channel == DCH) {
log_h->warning("Error deallocating from buffer pool in process_pdus(): buffer not created in this pool.\n"); if (!pool.deallocate(pdu)) {
log_h->warning("Error deallocating from buffer pool in process_pdus(): buffer not created in this pool.\n");
}
} }
cnt++; cnt++;
have_data = true; 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->rsrp_neighbour = false;
q->smooth_filter_auto = false;
q->smooth_filter_len = 3; q->smooth_filter_len = 3;
srslte_chest_dl_set_smooth_filter3_coeff(q, 0.1); srslte_chest_dl_set_smooth_filter3_coeff(q, 0.1);
@ -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 */ /* 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) 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) { cf_t *input2d[nsymbols + 2];
if (ch_mode == SRSLTE_SF_MBSFN) { cf_t *tmp_noise = q->tmp_noise;
nref /= 4;
} else { for (int i = 0; i < nsymbols; i++) {
nref /= 2; input2d[i + 1] = &q->pilot_estimates[i * nref];
}
} }
/* Substract noisy pilot estimates */ input2d[0] = &q->tmp_noise[0];
srslte_vec_sub_ccc(q->pilot_estimates_average, q->pilot_estimates, q->tmp_noise, nref); if (nsymbols > 3) {
srslte_vec_sc_prod_cfc(input2d[2], 2.0f, input2d[0], nref);
#ifdef FREQ_SEL_SNR srslte_vec_sub_ccc(input2d[0], input2d[4], input2d[0], nref);
/* 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);
srslte_vec_fprint_f(stdout, q->snr_vector, nref);
#endif
/* Compute average power. Normalized for filter len 3 using matlab */
float norm = 1;
if (q->average_subframe) {
norm = 32;
} else { } else {
if (q->smooth_filter_len == 3) { srslte_vec_sc_prod_cfc(input2d[2], 1.0f, input2d[0], nref);
float a = q->smooth_filter[0]; }
float norm3 = 6.143*a*a+0.04859*a-0.002774;
norm /= norm3; 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);
}
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);
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) 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; 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) { 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 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; 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); 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 (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 */ /* Smooth estimates (if applicable) and interpolate */
if (q->smooth_filter_len == 0 || (q->smooth_filter_len == 3 && q->smooth_filter[0] == 0)) { 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); 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 */ /* Estimate noise power */
if (q->noise_alg == SRSLTE_NOISE_ALG_REFS && q->smooth_filter_len > 0) { if (q->noise_alg == SRSLTE_NOISE_ALG_PSS) {
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 (sf_idx == 0 || sf_idx == 5) { if (sf_idx == 0 || sf_idx == 5) {
q->noise_estimate[rxant_id][port_id] = estimate_noise_pss(q, input, ce); 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) { if (sf_idx == 0 || sf_idx == 5) {
q->noise_estimate[rxant_id][port_id] = estimate_noise_empty_sc(q, input); 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]) { int nof_symbols[SRSLTE_MAX_CODEWORDS]) {
if (nof_cw == nof_layers) { if (nof_cw == nof_layers) {
for (int i = 0; i < nof_cw; i++) { 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]; return nof_symbols[0];
} else if (nof_cw == 1) { } 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 */ /* 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); srslte_predecoding_single_multi(q_symbols, q_ce[0], q->d, NULL, q->nof_rx_antennas, q->nof_symbols, 1.0f, noise_estimate);
} else { } else {
srslte_predecoding_diversity_multi(q_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, q->nof_symbols, 1.0f); srslte_predecoding_diversity_multi(q_symbols, q_ce, x, 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); 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 */ /* 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); srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, NULL, q->nof_rx_antennas, nof_symbols, 1.0f, noise_estimate/2);
} else { } else {
srslte_predecoding_diversity_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, nof_symbols, 1.0f); srslte_predecoding_diversity_multi(q->symbols, q->ce, x, 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); 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) { if (enable) {
for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
if (!q->csi[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]) { if (!q->csi[i]) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -757,7 +757,7 @@ int srslte_pdsch_decode(srslte_pdsch_t *q,
} }
// Pre-decoder // Pre-decoder
if (srslte_predecoding_type(q->symbols, q->ce, x, q->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) { cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, pdsch_scaling, noise_estimate)<0) {
DEBUG("Error predecoding\n"); DEBUG("Error predecoding\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;

@ -241,7 +241,7 @@ int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS],
/* no need for layer demapping */ /* 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); srslte_predecoding_single_multi(q_sf_symbols, q_ce[0], q->d0, NULL, q->nof_rx_antennas, SRSLTE_PHICH_MAX_NSYMB, 1.0f, noise_estimate);
} else { } else {
srslte_predecoding_diversity_multi(q_sf_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB, 1.0f); srslte_predecoding_diversity_multi(q_sf_symbols, q_ce, x, 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); srslte_layerdemap_diversity(x, q->d0, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports);
} }
DEBUG("Recv!!: \n"); DEBUG("Recv!!: \n");

@ -130,7 +130,7 @@ int srslte_sch_init(srslte_sch_t *q) {
goto clean; goto clean;
} }
bzero(q->temp_g_bits, SRSLTE_MAX_PRB*12*12*12); 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) { if (!q->ul_interleaver) {
goto clean; 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. * 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, 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 rows = H_prime_total/N_pusch_symbs;
uint32_t cols = 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 */ /* 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, 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, 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 // 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 // Genearate interleaver table and interleave bits
ulsch_interleave_gen(H_prime_total, N_pusch_symbs, Qm, ri_present, inteleaver_lut); 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 // Reset temp_buffer because will be reused next time
if (nof_ri_bits > 0) { 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 */ /* 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, 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, 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 // Prepare ri_bits for fast search using temp_buffer
if (nof_ri_bits > 0) { if (nof_ri_bits > 0) {
@ -634,8 +634,8 @@ void ulsch_deinterleave(int16_t *q_bits, uint32_t Qm, uint32_t H_prime_total,
} }
// Generate interleaver table and interleave samples // Generate interleaver table and interleave samples
ulsch_interleave_gen(H_prime_total, N_pusch_symbs, Qm, ri_present, inteleaver_lut); 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 // Reset temp_buffer because will be reused next time
if (nof_ri_bits > 0) { if (nof_ri_bits > 0) {

@ -41,7 +41,7 @@
#define MAX_TIME_OFFSET 128 #define MAX_TIME_OFFSET 128
#define TRACK_MAX_LOST 4 #define TRACK_MAX_LOST 100
#define TRACK_FRAME_SIZE 32 #define TRACK_FRAME_SIZE 32
#define FIND_NOF_AVG_FRAMES 4 #define FIND_NOF_AVG_FRAMES 4
#define DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD 0 #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) { 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); 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 */ /* 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, 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 noise_estimate, float norm) { cf_t *x0, cf_t *x1, float *csi0, float *csi1, float noise_estimate, float norm) {
/* Create conjugated matrix */ /* Create conjugated matrix */
cf_t _h00 = conjf(h00); cf_t _h00 = conjf(h00);
cf_t _h01 = conjf(h01); 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 a01 = _h00 * h01 + _h10 * h11;
cf_t a10 = _h01 * h00 + _h11 * h10; cf_t a10 = _h01 * h00 + _h11 * h10;
cf_t a11 = _h01 * h01 + _h11 * h11 + noise_estimate; 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) */ /* 2. B = inv(H' x H + No) = inv(A) */
cf_t b00 = a11; cf_t _norm = norm * a_det_rcp;
cf_t b01 = -a01; cf_t b00 = a11 * _norm;
cf_t b10 = -a10; cf_t b01 = -a01 * _norm;
cf_t b11 = a00; cf_t b10 = -a10 * _norm;
cf_t _norm = norm * srslte_mat_cf_recip_gen(srslte_mat_2x2_det_gen(a00, a01, a10, a11)); cf_t b11 = a00 * _norm;
/* 3. W = inv(H' x H + No) x H' = B x H' */ /* 3. W = inv(H' x H + No) x H' = B x H' */
cf_t w00 = b00 * _h00 + b01 * _h01; 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; cf_t w11 = b10 * _h10 + b11 * _h11;
/* 4. X = W x Y */ /* 4. X = W x Y */
*x0 = (y0 * w00 + y1 * w01) * _norm; *x0 = (y0 * w00 + y1 * w01);
*x1 = (y0 * w10 + y1 * w11) * _norm; *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) { 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 <sys/time.h>
#include "srslte/phy/utils/mat.h" #include "srslte/phy/utils/mat.h"
#include "srslte/phy/utils/simd.h"
#include "srslte/phy/utils/vector.h" #include "srslte/phy/utils/vector.h"
#include "srslte/phy/utils/vector_simd.h"
bool zf_solver = false; bool zf_solver = false;
@ -378,6 +378,98 @@ bool test_mmse_solver_avx(void) {
#endif /* LV_HAVE_AVX */ #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) { bool test_vec_dot_prod_ccc(void) {
__attribute__((aligned(256))) cf_t a[14]; __attribute__((aligned(256))) cf_t a[14];
__attribute__((aligned(256))) cf_t b[14]; __attribute__((aligned(256))) cf_t b[14];
@ -413,6 +505,10 @@ int main(int argc, char **argv) {
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
RUN_TEST(test_zf_solver_avx); RUN_TEST(test_zf_solver_avx);
#endif /* LV_HAVE_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) { if (mmse_solver) {
@ -426,6 +522,10 @@ int main(int argc, char **argv) {
#ifdef LV_HAVE_AVX #ifdef LV_HAVE_AVX
RUN_TEST(test_mmse_solver_avx); RUN_TEST(test_mmse_solver_avx);
#endif /* LV_HAVE_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); 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); 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 *srslte_vec_malloc(uint32_t size) {
void *ptr; void *ptr;
if (posix_memalign(&ptr, SRSLTE_SIMD_BIT_ALIGN, size)) { 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) { void srs_vec_cf_cpy(const cf_t *src, cf_t *dst, int len) {
srslte_vec_cp_simd(dst, src, 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) { void srslte_vec_interleave(const cf_t *x, const cf_t *y, cf_t *z, const int len) {

@ -50,12 +50,14 @@ bool radio::init(char *args, char *devname, uint32_t nof_channels)
// Suppress radio stdout // Suppress radio stdout
srslte_rf_suppress_stdout(&rf_device); srslte_rf_suppress_stdout(&rf_device);
tx_adv_auto = true; continuous_tx = false;
tx_adv_auto = true;
// Set default preamble length each known device // Set default preamble length each known device
// We distinguish by device family, maybe we should calibrate per device // We distinguish by device family, maybe we should calibrate per device
if (strstr(srslte_rf_name(&rf_device), "uhd")) { if (strstr(srslte_rf_name(&rf_device), "uhd")) {
burst_preamble_sec = uhd_default_burst_preamble_sec; burst_preamble_sec = uhd_default_burst_preamble_sec;
continuous_tx = true;
} else if (strstr(srslte_rf_name(&rf_device), "bladerf")) { } else if (strstr(srslte_rf_name(&rf_device), "bladerf")) {
burst_preamble_sec = blade_default_burst_preamble_sec; burst_preamble_sec = blade_default_burst_preamble_sec;
} else { } else {
@ -89,6 +91,7 @@ void radio::reset()
printf("Resetting Radio...\n"); printf("Resetting Radio...\n");
srslte_rf_stop_rx_stream(&rf_device); srslte_rf_stop_rx_stream(&rf_device);
radio_is_streaming = false; radio_is_streaming = false;
usleep(100000);
} }
void radio::set_manual_calibration(rf_cal_t* calibration) 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; 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) void radio::set_tx_adv(int nsamples)
{ {
tx_adv_auto = false; tx_adv_auto = false;
@ -175,7 +186,7 @@ float radio::set_tx_power(float power)
float radio::get_max_tx_power() float radio::get_max_tx_power()
{ {
return 10; return 40;
} }
float radio::get_rssi() 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 // Calculate TX advance in seconds from samples and sampling rate
tx_adv_sec = nsamples/cur_tx_srate; 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) 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 // Drop all messages in TX queue
byte_buffer_t *buf; byte_buffer_t *buf;
while(ul_queue.size() > 0) { while(ul_queue.size() > 0) {
ul_queue.read(&buf); if (ul_queue.try_read(&buf)) {
pool->deallocate(buf); pool->deallocate(buf);
}
} }
} }
@ -112,14 +113,18 @@ int rlc_tm::read_pdu(uint8_t *payload, uint32_t nof_bytes)
return 0; return 0;
} }
byte_buffer_t *buf; byte_buffer_t *buf;
ul_queue.read(&buf); if (ul_queue.try_read(&buf)) {
pdu_size = buf->N_bytes; pdu_size = buf->N_bytes;
memcpy(payload, buf->msg, buf->N_bytes); memcpy(payload, buf->msg, buf->N_bytes);
log->debug("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", log->debug("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
rrc->get_rb_name(lcid).c_str(), buf->get_latency_us()); rrc->get_rb_name(lcid).c_str(), buf->get_latency_us());
pool->deallocate(buf); 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]); 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; 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) void rlc_tm::write_pdu(uint8_t *payload, uint32_t nof_bytes)

@ -42,18 +42,17 @@ private:
bool new_allocation(uint32_t nof_rbg, uint32_t* rbgmask); bool new_allocation(uint32_t nof_rbg, uint32_t* rbgmask);
void update_allocation(uint32_t new_mask); void update_allocation(uint32_t new_mask);
bool allocation_is_valid(uint32_t 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 get_required_rbg(sched_ue *user, uint32_t tti);
uint32_t count_rbg(uint32_t mask); uint32_t count_rbg(uint32_t mask);
uint32_t calc_rbg_mask(bool mask[25]); uint32_t calc_rbg_mask(bool mask[25]);
bool used_rb[MAX_RBG]; bool used_rb[MAX_RBG];
uint32_t nof_users_with_data;
uint32_t current_tti;
uint32_t current_tti;
uint32_t total_rb; uint32_t total_rb;
uint32_t used_rb_mask; uint32_t used_rb_mask;
uint32_t nof_ctrl_symbols; uint32_t nof_ctrl_symbols;
@ -72,8 +71,8 @@ private:
bool new_allocation(uint32_t L, ul_harq_proc::ul_alloc_t *alloc); bool new_allocation(uint32_t L, ul_harq_proc::ul_alloc_t *alloc);
bool allocation_is_valid(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]; bool used_rb[MAX_PRB];
uint32_t current_tti; uint32_t current_tti;

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

@ -95,7 +95,7 @@ public:
bool process_pdus(); bool process_pdus();
uint8_t *request_buffer(uint32_t tti, uint32_t len); 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 push_pdu(uint32_t tti, uint32_t len);
void deallocate_pdu(uint32_t tti); void deallocate_pdu(uint32_t tti);

@ -32,7 +32,6 @@
#include "srslte/common/buffer_pool.h" #include "srslte/common/buffer_pool.h"
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/msg_queue.h"
#include "srslte/common/threads.h" #include "srslte/common/threads.h"
#include "srslte/interfaces/enb_interfaces.h" #include "srslte/interfaces/enb_interfaces.h"
#include "common_enb.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) 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; total_rb = start_rb+nof_rb;
for (uint32_t i=0;i<total_rb;i++) { for (uint32_t i=0;i<total_rb;i++) {
if (i<start_rb) { if (i<start_rb) {
@ -89,16 +88,22 @@ void dl_metric_rr::new_tti(std::map<uint16_t,sched_ue> &ue_db, uint32_t start_rb
} }
available_rb = nof_rb; available_rb = nof_rb;
used_rb_mask = calc_rbg_mask(used_rb); used_rb_mask = calc_rbg_mask(used_rb);
current_tti = tti; current_tti = tti;
nof_ctrl_symbols = nof_ctrl_symbols_; nof_ctrl_symbols = nof_ctrl_symbols_;
nof_users_with_data = 0; if(ue_db.size()==0)
for(std::map<uint16_t, sched_ue>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { return;
sched_ue *user = (sched_ue*) &iter->second;
if (user->get_pending_dl_new_data(current_tti) || user->get_pending_dl_harq(current_tti)) { // give priority in a time-domain RR basis
user->ue_idx = nof_users_with_data; uint32_t priority_idx = current_tti % ue_db.size();
nof_users_with_data++; 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,25 +141,11 @@ bool dl_metric_rr::allocation_is_valid(uint32_t mask)
return (mask & used_rb_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);
uint32_t pending_data = user->get_pending_dl_new_data(current_tti);
dl_harq_proc *h = user->get_pending_dl_harq(current_tti); dl_harq_proc *h = user->get_pending_dl_harq(current_tti);
// Time-domain RR scheduling // Schedule retx if we have space
#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 ASYNC_DL_SCHED
if (h) { if (h) {
#else #else
@ -164,38 +155,45 @@ dl_harq_proc* dl_metric_rr::get_user_allocation(sched_ue *user)
// If can schedule the same mask, do it // If can schedule the same mask, do it
if (!allocation_is_valid(retx_mask)) { if (!allocation_is_valid(retx_mask)) {
update_allocation(retx_mask); update_allocation(retx_mask);
return h; return h;
} }
// If not, try to find another mask in the current tti
// If not, try to find another mask in the current tti
uint32_t nof_rbg = count_rbg(retx_mask); uint32_t nof_rbg = count_rbg(retx_mask);
if (nof_rbg < available_rb) { if (nof_rbg < available_rb) {
if (new_allocation(nof_rbg, &retx_mask)) { if (new_allocation(nof_rbg, &retx_mask)) {
update_allocation(retx_mask); update_allocation(retx_mask);
h->set_rbgmask(retx_mask); h->set_rbgmask(retx_mask);
return h; return h;
} }
} }
} }
// If could not schedule the reTx, or there wasn't any pending retx, find an empty PID // If could not schedule the reTx, or there wasn't any pending retx, find an empty PID
#if ASYNC_DL_SCHED #if ASYNC_DL_SCHED
h = user->get_empty_dl_harq(); h = user->get_empty_dl_harq();
if (h) { if (h) {
#else #else
if (h && h->is_empty()) { if (h && h->is_empty()) {
#endif #endif
// Allocate resources based on pending data // Allocate resources based on pending data
if (pending_data) { if (pending_data) {
uint32_t pending_rb = user->get_required_prb_dl(pending_data, nof_ctrl_symbols); uint32_t pending_rb = user->get_required_prb_dl(pending_data, nof_ctrl_symbols);
uint32_t newtx_mask = 0; uint32_t newtx_mask = 0;
new_allocation(pending_rb, &newtx_mask); new_allocation(pending_rb, &newtx_mask);
if (newtx_mask) { if (newtx_mask) {
update_allocation(newtx_mask); update_allocation(newtx_mask);
h->set_rbgmask(newtx_mask); h->set_rbgmask(newtx_mask);
return h; return h;
} }
} }
} }
return NULL;
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_; available_rb = nof_rb_;
bzero(used_rb, nof_rb*sizeof(bool)); bzero(used_rb, nof_rb*sizeof(bool));
nof_users_with_data = 0; if(ue_db.size()==0)
for(std::map<uint16_t, sched_ue>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { return;
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)) { // give priority in a time-domain RR basis
user->ue_idx = nof_users_with_data; uint32_t priority_idx = (current_tti+ue_db.size()/2) % ue_db.size(); // make DL and UL interleaved
nof_users_with_data++; 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) bool ul_metric_rr::allocation_is_valid(ul_harq_proc::ul_alloc_t alloc)
@ -288,56 +291,49 @@ void ul_metric_rr::update_allocation(ul_harq_proc::ul_alloc_t alloc)
available_rb -= alloc.L; 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 // Time-domain RR scheduling
uint32_t pending_data = user->get_pending_ul_new_data(current_tti); uint32_t pending_data = user->get_pending_ul_new_data(current_tti);
ul_harq_proc *h = user->get_ul_harq(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 // Schedule retx if we have space
if (!h->is_empty(0)) { if (!h->is_empty(0)) {
ul_harq_proc::ul_alloc_t alloc = h->get_alloc(); ul_harq_proc::ul_alloc_t alloc = h->get_alloc();
// If can schedule the same mask, do it // If can schedule the same mask, do it
if (allocation_is_valid(alloc)) { if (allocation_is_valid(alloc)) {
update_allocation(alloc); update_allocation(alloc);
return h; return h;
} }
// If not, try to find another mask in the current tti // If not, try to find another mask in the current tti
if (new_allocation(alloc.L, &alloc)) { if (new_allocation(alloc.L, &alloc)) {
update_allocation(alloc); update_allocation(alloc);
h->set_alloc(alloc); h->set_alloc(alloc);
return h; return h;
} }
} }
// If could not schedule the reTx, or there wasn't any pending retx, find an empty PID
// If could not schedule the reTx, or there wasn't any pending retx, find an empty PID
if (h->is_empty(0)) { if (h->is_empty(0)) {
// Allocate resources based on pending data // Allocate resources based on pending data
if (pending_data) { if (pending_data) {
uint32_t pending_rb = user->get_required_prb_ul(pending_data); uint32_t pending_rb = user->get_required_prb_ul(pending_data);
ul_harq_proc::ul_alloc_t alloc; ul_harq_proc::ul_alloc_t alloc;
new_allocation(pending_rb, &alloc); new_allocation(pending_rb, &alloc);
if (alloc.L) { if (alloc.L) {
update_allocation(alloc); update_allocation(alloc);
h->set_alloc(alloc); h->set_alloc(alloc);
return h; return h;
} }
} }
} }
return NULL; 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) fixed_mcs_ul(0), fixed_mcs_dl(0), phy_config_dedicated_enabled(false)
{ {
log_h = NULL; log_h = NULL;

@ -142,7 +142,7 @@ void ue::set_tti(uint32_t tti) {
#include <assert.h> #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 // Unpack ULSCH MAC PDU
mac_msg_ul.init_rx(nof_bytes, true); 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 // 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 // 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 // Copy SIB1 to first SI message
msg[0].N_sibs = 1; 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) void rrc::ue::notify_s1ap_ue_erab_setup_response(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e)
{ {
LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT res; LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT res;
res.ext=false;
res.E_RABSetupListBearerSURes.len = 0; res.E_RABSetupListBearerSURes.len = 0;
res.E_RABFailedToSetupListBearerSURes.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++) { for(uint32_t i=0; i<e->len; i++) {
res.E_RABSetupListBearerSURes_present = true; res.E_RABSetupListBearerSURes_present = true;
LIBLTE_S1AP_E_RABTOBESETUPITEMBEARERSUREQ_STRUCT *erab = &e->buffer[i]; 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 // Get DRB1 configuration
if (get_drbid_config(&conn_reconf->rr_cnfg_ded.drb_to_add_mod_list[0], 1)) { if (get_drbid_config(&conn_reconf->rr_cnfg_ded.drb_to_add_mod_list[0], 1)) {
parent->rrc_log->error("Getting DRB1 configuration\n"); 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 { } else {
conn_reconf->rr_cnfg_ded.drb_to_add_mod_list_size = 1; 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) uint8_t lcid = id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1)
// Get DRB configuration // 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"); 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 { } else {
conn_reconf->rr_cnfg_ded.drb_to_add_mod_list_size++; 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 act_def_eps_bearer_context_req.eps_qos.mbr_dl_ext = 250; //FIXME check
//set apn //set apn
act_def_eps_bearer_context_req.apn.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 act_def_eps_bearer_context_req.proc_transaction_id = ue_emm_ctx->procedure_transaction_id; //FIXME
//Set DNS server //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; LIBLTE_MME_EMM_INFORMATION_MSG_STRUCT emm_info;
emm_info.full_net_name_present = true; 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.full_net_name.add_ci = LIBLTE_MME_ADD_CI_DONT_ADD;
emm_info.short_net_name_present = true; 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.short_net_name.add_ci = LIBLTE_MME_ADD_CI_DONT_ADD;
emm_info.local_time_zone_present = false; 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(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_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 push_pdu_temp_crnti(uint8_t *buff, uint32_t nof_bytes);
void set_uecrid_callback(bool (*callback)(void*, uint64_t), void *arg); void set_uecrid_callback(bool (*callback)(void*, uint64_t), void *arg);
bool get_uecrid_successful(); 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: private:
const static int MAX_PDU_LEN = 150*1024/8; // ~ 150 Mbps const static int MAX_PDU_LEN = 150*1024/8; // ~ 150 Mbps

@ -50,7 +50,7 @@ class mac
,public mac_interface_rrc ,public mac_interface_rrc
,public srslte::timer_callback ,public srslte::timer_callback
,public srslte::mac_interface_timers ,public srslte::mac_interface_timers
,public thread ,public periodic_thread
{ {
public: public:
mac(); 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 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 bch_decoded_ok(uint8_t *payload, uint32_t len);
void pch_decoded_ok(uint32_t len); void pch_decoded_ok(uint32_t len);
void tti_clock(uint32_t tti);
/******** Interface from RLC (RLC -> MAC) ****************/ /******** Interface from RLC (RLC -> MAC) ****************/
void bcch_start_rx(); void bcch_start_rx();
void bcch_stop_rx();
void bcch_start_rx(int si_window_start, int si_window_length); void bcch_start_rx(int si_window_start, int si_window_length);
void pcch_start_rx(); 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 setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD);
void reconfiguration(); void reconfiguration();
void reset(); void reset();
@ -110,15 +108,14 @@ public:
private: 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_MAIN_THREAD_PRIO = -1; // Use default high-priority below UHD
static const int MAC_PDU_THREAD_PRIO = DEFAULT_PRIORITY-5; static const int MAC_PDU_THREAD_PRIO = DEFAULT_PRIORITY-5;
static const int MAC_NOF_HARQ_PROC = 2*HARQ_DELAY_MS; static const int MAC_NOF_HARQ_PROC = 2*HARQ_DELAY_MS;
// Interaction with PHY // Interaction with PHY
srslte::tti_sync_cv ttisync; phy_interface_mac *phy_h;
phy_interface_mac *phy_h;
rlc_interface_mac *rlc_h; rlc_interface_mac *rlc_h;
rrc_interface_mac *rrc_h; rrc_interface_mac *rrc_h;
srslte::log *log_h; srslte::log *log_h;
@ -130,11 +127,7 @@ private:
ue_rnti_t uernti; ue_rnti_t uernti;
uint32_t tti; uint32_t tti;
bool started;
bool is_synchronized;
uint16_t last_temporal_crnti;
uint16_t phy_rnti;
/* Multiplexing/Demultiplexing Units */ /* Multiplexing/Demultiplexing Units */
mux mux_unit; mux mux_unit;
demux demux_unit; demux demux_unit;
@ -168,19 +161,6 @@ private:
mac_metrics_t metrics; mac_metrics_t metrics;
/* Class to run Timers in a dedicated thread */
class mac_timers : public periodic_thread {
public:
void init(srslte::timers *timers, srslte::log *log_h);
private:
void run_period();
srslte::timers *timers;
bool running;
srslte::log *log_h;
};
mac_timers mactimers;
/* Class to process MAC PDUs from DEMUX unit */ /* Class to process MAC PDUs from DEMUX unit */
class pdu_process : public thread { class pdu_process : public thread {
public: public:

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

@ -28,6 +28,7 @@
#define SRSUE_PHCH_RECV_H #define SRSUE_PHCH_RECV_H
#include <map> #include <map>
#include <pthread.h>
#include "srslte/srslte.h" #include "srslte/srslte.h"
#include "srslte/common/log.h" #include "srslte/common/log.h"
@ -50,29 +51,23 @@ class phch_recv : public thread, public chest_feedback_itf
public: public:
phch_recv(); phch_recv();
~phch_recv(); ~phch_recv();
void init(srslte::radio_multi* radio_handler, mac_interface_phy *mac,rrc_interface_phy *rrc, void init(srslte::radio_multi* radio_handler, mac_interface_phy *mac,rrc_interface_phy *rrc,
prach *prach_buffer, srslte::thread_pool *_workers_pool, 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); 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 stop();
void set_agc_enable(bool enable); void radio_overflow();
void set_earfcn(std::vector<uint32_t> earfcn); // RRC interface for controling the SYNC state
void force_freq(float dl_freq, float ul_freq); 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);
void reset_sync(); bool cell_is_camping();
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 controlling the neighbour cell measurement
void meas_reset(); void meas_reset();
int meas_start(uint32_t earfcn, int pci); int meas_start(uint32_t earfcn, int pci);
int meas_stop(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 // from chest_feedback_itf
void in_sync(); void in_sync();
void out_of_sync(); void out_of_sync();
@ -80,37 +75,21 @@ public:
void set_time_adv_sec(float time_adv_sec); void set_time_adv_sec(float time_adv_sec);
void get_current_cell(srslte_cell_t *cell, uint32_t *earfcn = NULL); 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; const static int MUTEX_X_WORKER = 4;
double set_rx_gain(double gain); 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 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); int scell_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time);
private: 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 to run cell search
class search { class search {
public: public:
@ -119,9 +98,7 @@ private:
~search(); ~search();
void init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, phch_recv *parent); void init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, phch_recv *parent);
void reset(); void reset();
float get_last_gain();
float get_last_cfo(); float get_last_cfo();
void set_N_id_2(int N_id_2);
void set_agc_enable(bool enable); void set_agc_enable(bool enable);
ret_code run(srslte_cell_t *cell); ret_code run(srslte_cell_t *cell);
@ -137,22 +114,23 @@ private:
// Class to synchronize system frame number // Class to synchronize system frame number
class sfn_sync { class sfn_sync {
public: 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(); ~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(); void reset();
bool set_cell(srslte_cell_t cell); bool set_cell(srslte_cell_t cell);
ret_code run_subframe(srslte_cell_t *cell, uint32_t *tti_cnt, bool sfidx_only = false); ret_code run_subframe(srslte_cell_t *cell, uint32_t *tti_cnt, bool sfidx_only = false);
private: private:
const static int SFN_SYNC_NOF_SUBFRAMES = 100;
uint32_t cnt;
uint32_t timeout;
srslte::log *log_h; srslte::log *log_h;
srslte_ue_sync_t *ue_sync; srslte_ue_sync_t *ue_sync;
cf_t *buffer[SRSLTE_MAX_PORTS]; cf_t *buffer[SRSLTE_MAX_PORTS];
srslte_ue_mib_t ue_mib; 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 // Class to perform cell measurements
@ -170,7 +148,7 @@ private:
void set_cell(srslte_cell_t cell); void set_cell(srslte_cell_t cell);
ret_code run_subframe(uint32_t sf_idx); ret_code run_subframe(uint32_t sf_idx);
ret_code run_subframe_sync(srslte_ue_sync_t *ue_sync, uint32_t sf_idx); ret_code run_subframe_sync(srslte_ue_sync_t *ue_sync, uint32_t sf_idx);
ret_code run_multiple_subframes(cf_t *buffer, 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 rssi();
float rsrp(); float rsrp();
float rsrq(); float rsrq();
@ -261,9 +239,26 @@ private:
// 36.133 9.1.2.1 for band 7 // 36.133 9.1.2.1 for band 7
const static float ABSOLUTE_RSRP_THRESHOLD_DBM = -125; 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 // Objects for internal use
measure measure_p;
search search_p; search search_p;
sfn_sync sfn_p; sfn_sync sfn_p;
intra_measure intra_freq_meas; 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_OUT_OF_SYNC_SF = 200;
const static uint32_t NOF_IN_SYNC_SF = 100; const static uint32_t NOF_IN_SYNC_SF = 100;
// State for primary cell // State machine for SYNC thread
typedef enum { class sync_state {
IDLE = 0, public:
CELL_SEARCH, typedef enum {
CELL_SELECT, IDLE = 0,
CELL_RESELECT, CELL_SEARCH,
CELL_MEASURE, SFN_SYNC,
CELL_CAMP, CAMPING,
} phy_state_t; } 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) // Sampling rate mode (find is 1.96 MHz, camp is the full cell BW)
enum { enum {
@ -320,9 +424,8 @@ private:
// This is the primary cell // This is the primary cell
srslte_cell_t cell; srslte_cell_t cell;
bool cell_is_set;
bool started; bool started;
float time_adv_sec; float time_adv_sec, next_time_adv_sec;
uint32_t tti; uint32_t tti;
bool do_agc; bool do_agc;
@ -330,8 +433,8 @@ private:
uint32_t tx_mutex_cnt; uint32_t tx_mutex_cnt;
float ul_dl_factor; float ul_dl_factor;
uint32_t current_earfcn; int current_earfcn;
int cur_earfcn_index; uint32_t cellsearch_earfcn_index;
float dl_freq; float dl_freq;
float ul_freq; float ul_freq;

@ -53,6 +53,7 @@ public:
cf_t* get_buffer(uint32_t antenna_idx); cf_t* get_buffer(uint32_t antenna_idx);
void set_tti(uint32_t tti, uint32_t tx_tti); void set_tti(uint32_t tti, uint32_t tx_tti);
void set_tx_time(srslte_timestamp_t tx_time, uint32_t next_offset); void set_tx_time(srslte_timestamp_t tx_time, uint32_t next_offset);
void set_prach(cf_t *prach_ptr, float prach_power);
void set_cfo(float cfo); void set_cfo(float cfo);
void set_ul_params(bool pregen_disabled = false); void set_ul_params(bool pregen_disabled = false);
@ -169,6 +170,8 @@ private:
bool sr_configured; bool sr_configured;
float cfo; float cfo;
bool rar_cqi_request; bool rar_cqi_request;
cf_t *prach_ptr;
float prach_power;
uint32_t rssi_read_cnt; uint32_t rssi_read_cnt;

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

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

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

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

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

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

@ -36,6 +36,7 @@
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
#include "srslte/common/security.h" #include "srslte/common/security.h"
#include "srslte/common/threads.h" #include "srslte/common/threads.h"
#include "srslte/common/block_queue.h"
#include <math.h> #include <math.h>
#include <map> #include <map>
@ -52,21 +53,21 @@ using srslte::byte_buffer_t;
namespace srsue { namespace srsue {
class cell_t class cell_t
{ {
public: public:
bool is_valid() { 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) { 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) { 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) { 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) { bool plmn_equals(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) {
if (has_valid_sib1) { if (has_valid_sib1) {
@ -78,11 +79,39 @@ class cell_t
} }
return false; 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() { cell_t() {
srslte_cell_t tmp = {}; phy_interface_rrc::phy_cell_t tmp = {};
cell_t(tmp, 0, 0); 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); gettimeofday(&last_update, NULL);
this->has_valid_sib1 = false; this->has_valid_sib1 = false;
this->has_valid_sib2 = false; this->has_valid_sib2 = false;
@ -90,7 +119,6 @@ class cell_t
this->has_valid_sib13 = false; this->has_valid_sib13 = false;
this->phy_cell = phy_cell; this->phy_cell = phy_cell;
this->rsrp = rsrp; this->rsrp = rsrp;
this->earfcn = earfcn;
in_sync = true; in_sync = true;
bzero(&sib1, sizeof(sib1)); bzero(&sib1, sizeof(sib1));
bzero(&sib2, sizeof(sib2)); bzero(&sib2, sizeof(sib2));
@ -99,15 +127,15 @@ class cell_t
} }
uint32_t get_earfcn() { uint32_t get_earfcn() {
return earfcn; return phy_cell.earfcn;
} }
uint32_t get_pci() { uint32_t get_pci() {
return phy_cell.id; return phy_cell.cell.id;
} }
void set_rsrp(float rsrp) { void set_rsrp(float rsrp) {
if (~isnan(rsrp)) { if (!isnan(rsrp)) {
this->rsrp = rsrp; this->rsrp = rsrp;
} }
in_sync = true; in_sync = true;
@ -170,6 +198,20 @@ class cell_t
return has_valid_sib13; 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() { uint16_t get_mcc() {
if (has_valid_sib1) { if (has_valid_sib1) {
if (sib1.N_plmn_ids > 0) { if (sib1.N_plmn_ids > 0) {
@ -188,12 +230,11 @@ class cell_t
return 0; return 0;
} }
srslte_cell_t phy_cell; phy_interface_rrc::phy_cell_t phy_cell;
bool in_sync; bool in_sync;
private: private:
float rsrp; float rsrp;
uint32_t earfcn;
struct timeval last_update; struct timeval last_update;
bool has_valid_sib1; bool has_valid_sib1;
@ -231,56 +272,61 @@ public:
void stop(); void stop();
rrc_state_t get_state(); rrc_state_t get_state();
void set_args(rrc_args_t *args); void set_args(rrc_args_t *args);
// Timeout callback interface // Timeout callback interface
void timer_expired(uint32_t timeout_id); void timer_expired(uint32_t timeout_id);
void liblte_rrc_log(char *str); void liblte_rrc_log(char *str);
// NAS interface // NAS interface
void write_sdu(uint32_t lcid, byte_buffer_t *sdu); void write_sdu(uint32_t lcid, byte_buffer_t *sdu);
void enable_capabilities();
uint16_t get_mcc(); uint16_t get_mcc();
uint16_t get_mnc(); uint16_t get_mnc();
int plmn_search(found_plmn_t found_plmns[MAX_FOUND_PLMNS]);
void enable_capabilities(); void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id);
void plmn_search(); bool connection_request(LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM cause,
void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, bool connect_request); srslte::byte_buffer_t *dedicatedInfoNAS);
void set_ue_idenity(LIBLTE_RRC_S_TMSI_STRUCT s_tmsi);
// PHY interface // PHY interface
void in_sync(); void in_sync();
void out_of_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); void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn, int pci);
// MAC interface // MAC interface
void ho_ra_completed(bool ra_successful); void ho_ra_completed(bool ra_successful);
void release_pucch_srs(); void release_pucch_srs();
void run_tti(uint32_t tti); void run_tti(uint32_t tti);
void ra_problem(); void ra_problem();
// GW interface // GW interface
bool is_connected(); bool is_connected(); // this is also NAS interface
bool have_drb(); bool have_drb();
// PDCP interface // PDCP interface
void write_pdu(uint32_t lcid, byte_buffer_t *pdu); void write_pdu(uint32_t lcid, byte_buffer_t *pdu);
void write_pdu_bcch_bch(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_bcch_dlsch(byte_buffer_t *pdu);
void write_pdu_pcch(byte_buffer_t *pdu); void write_pdu_pcch(byte_buffer_t *pdu);
private: 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::byte_buffer_pool *pool;
srslte::log *rrc_log; srslte::log *rrc_log;
phy_interface_rrc *phy; phy_interface_rrc *phy;
@ -295,6 +341,8 @@ private:
LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg; LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg;
LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg; LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg;
byte_buffer_t *dedicatedInfoNAS;
byte_buffer_t* byte_align_and_pack(); byte_buffer_t* byte_align_and_pack();
void send_ul_ccch_msg(); void send_ul_ccch_msg();
void send_ul_dcch_msg(); void send_ul_dcch_msg();
@ -304,28 +352,22 @@ private:
rrc_state_t state; rrc_state_t state;
uint8_t transaction_id; uint8_t transaction_id;
LIBLTE_RRC_S_TMSI_STRUCT ueIdentity;
bool ueIdentity_configured;
bool drb_up; bool drb_up;
rrc_args_t args; rrc_args_t args;
bool first_stimsi_attempt;
uint32_t cell_clean_cnt;
uint16_t ho_src_rnti; uint16_t ho_src_rnti;
cell_t ho_src_cell; cell_t ho_src_cell;
uint32_t ho_target_pci; phy_interface_rrc::phy_cfg_t previous_phy_cfg;
bool ho_syncing; mac_interface_rrc::mac_cfg_t previous_mac_cfg;
phy_interface_rrc::phy_cfg_t ho_src_phy_cfg;
mac_interface_rrc::mac_cfg_t ho_src_mac_cfg;
bool pending_mob_reconf; bool pending_mob_reconf;
LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT 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_enc[32];
uint8_t k_rrc_int[32]; uint8_t k_rrc_int[32];
uint8_t k_up_enc[32]; uint8_t k_up_enc[32];
@ -341,7 +383,7 @@ private:
srslte::mac_interface_timers *mac_timers; srslte::mac_interface_timers *mac_timers;
uint32_t n310_cnt, N310; uint32_t n310_cnt, N310;
uint32_t n311_cnt, N311; uint32_t n311_cnt, N311;
uint32_t t300, t301, t310, t311, t304; uint32_t t300, t301, t302, t310, t311, t304;
// Radio bearers // Radio bearers
typedef enum{ typedef enum{
@ -376,42 +418,35 @@ private:
std::vector<cell_t*> neighbour_cells; std::vector<cell_t*> neighbour_cells;
cell_t *serving_cell; cell_t *serving_cell;
void set_serving_cell(uint32_t cell_idx); 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); 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, 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); bool add_neighbour_cell(cell_t *cell);
void sort_neighbour_cells(); void sort_neighbour_cells();
void clean_neighbours(); void clean_neighbours();
std::vector<cell_t*>::iterator delete_neighbour(std::vector<cell_t*>::iterator it); std::vector<cell_t*>::iterator delete_neighbour(std::vector<cell_t*>::iterator it);
void delete_neighbour(uint32_t cell_idx); void delete_neighbour(uint32_t cell_idx);
typedef enum { bool configure_serving_cell();
SI_ACQUIRE_IDLE = 0,
SI_ACQUIRE_SIB1,
SI_ACQUIRE_SIB2
} si_acquire_state_t;
si_acquire_state_t si_acquire_state; bool si_acquire(uint32_t index);
void run_si_acquisition_procedure();
uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t offset, uint32_t sf); uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t offset, uint32_t sf);
uint32_t nof_sib1_trials; const static int SIB_SEARCH_TIMEOUT_MS = 1000;
uint16_t sysinfo_index;
uint32_t last_win_start;
bool select_next_cell_in_plmn(); const static uint32_t NOF_REQUIRED_SIBS = 3; // SIB1, SIB2 and SIB3
LIBLTE_RRC_PLMN_IDENTITY_STRUCT selected_plmn_id;
bool thread_running; bool initiated;
void run_thread(); bool ho_start;
bool go_idle;
// Measurements sub-class // Measurements sub-class
class rrc_meas { class rrc_meas {
public: public:
void init(rrc *parent); void init(rrc *parent);
void reset(); 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 new_phy_meas(uint32_t earfcn, uint32_t pci, float rsrp, float rsrq, uint32_t tti);
void run_tti(uint32_t tti); void run_tti(uint32_t tti);
bool timer_expired(uint32_t timer_id); bool timer_expired(uint32_t timer_id);
@ -500,6 +535,18 @@ private:
rrc_meas measurements; 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 // Cell selection/reselection functions/variables
typedef struct { typedef struct {
@ -510,25 +557,36 @@ private:
float s_intrasearchP; float s_intrasearchP;
float q_hyst; float q_hyst;
float threshservinglow; float threshservinglow;
} cell_resel_cfg_t; } cell_resel_cfg_t;
cell_resel_cfg_t cell_resel_cfg; cell_resel_cfg_t cell_resel_cfg;
float get_srxlev(float Qrxlevmeas); float get_srxlev(float Qrxlevmeas);
float get_squal(float Qqualmeas); 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; typedef enum {
void plmn_select_rrc(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id); 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 // RLC interface
void max_retx_attempted(); void max_retx_attempted();
// Senders // Senders
void send_con_request(); 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, uint16_t crnti); void send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_ENUM cause);
void send_con_restablish_complete(); void send_con_restablish_complete();
void send_con_setup_complete(byte_buffer_t *nas_msg); void send_con_setup_complete(byte_buffer_t *nas_msg);
void send_ul_info_transfer(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); void parse_dl_info_transfer(uint32_t lcid, byte_buffer_t *pdu);
// Helpers // 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(); bool ho_prepare();
void ho_synced(uint32_t target_pci); void ho_failed();
void rrc_connection_release(); void rrc_connection_release();
void con_restablish_cell_reselected();
void radio_link_failure(); void radio_link_failure();
void leave_connected(); 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_dl(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *config);
void apply_rr_config_common_ul(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *config); void apply_rr_config_common_ul(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *config);
void handle_sib1(); void handle_sib1();
@ -566,7 +623,7 @@ private:
void add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg); void add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg);
void add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg); void add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg);
void release_drb(uint8_t lcid); void release_drb(uint8_t lcid);
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_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); 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) // RRC states (3GPP 36.331 v10.0.0)
typedef enum { typedef enum {
RRC_STATE_IDLE = 0, RRC_STATE_IDLE = 0,
RRC_STATE_PLMN_START,
RRC_STATE_PLMN_SELECTION,
RRC_STATE_CELL_SELECTING,
RRC_STATE_CELL_SELECTED,
RRC_STATE_CONNECTING,
RRC_STATE_CONNECTED, RRC_STATE_CONNECTED,
RRC_STATE_HO_PREPARE,
RRC_STATE_HO_PROCESS,
RRC_STATE_LEAVE_CONNECTED,
RRC_STATE_N_ITEMS, RRC_STATE_N_ITEMS,
} rrc_state_t; } rrc_state_t;
static const char rrc_state_text[RRC_STATE_N_ITEMS][100] = {"IDLE", static const char rrc_state_text[RRC_STATE_N_ITEMS][100] = {"IDLE",
"PLMN SELECTED", "CONNECTED"};
"PLMN SELECTION",
"CELL SELECTING",
"CELL SELECTED",
"CONNECTING",
"CONNECTED",
"HO PREPARE",
"HO PROCESS",
"LEAVE CONNECTED"};
} // namespace srsue } // 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"); 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 { } else {
Warning("Trying to push PDU with payload size zero\n"); Warning("Trying to push PDU with payload size zero\n");
} }
} }
/* Demultiplexing of logical channels and dissassemble of MAC CE /* 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. * deadline is important here.
*/ */
void demux::push_pdu(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) { 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 /* Demultiplexing of MAC PDU associated with SI-RNTI. The PDU passes through
* the MAC in transparent mode. * 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) { 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() bool demux::process_pdus()
@ -135,15 +137,25 @@ bool demux::process_pdus()
return pdus.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 Debug("Processing MAC PDU channel %d\n", channel);
mac_msg.init_rx(nof_bytes); switch(channel) {
mac_msg.parse_packet(mac_pdu); case srslte::pdu_queue::DCH:
// Unpack DLSCH MAC PDU
process_sch_pdu(&mac_msg); mac_msg.init_rx(nof_bytes);
//srslte_vec_fprint_byte(stdout, mac_pdu, nof_bytes); mac_msg.parse_packet(mac_pdu);
Debug("MAC PDU processed\n");
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) void demux::process_sch_pdu(srslte::sch_pdu *pdu_msg)

@ -41,27 +41,21 @@
namespace srsue { namespace srsue {
mac::mac() : ttisync(10240), mac::mac() : timers(64),
timers(64),
mux_unit(MAC_NOF_HARQ_PROC), mux_unit(MAC_NOF_HARQ_PROC),
pdu_process_thread(&demux_unit) pdu_process_thread(&demux_unit)
{ {
started = false;
pcap = NULL; pcap = NULL;
bzero(&metrics, sizeof(mac_metrics_t)); 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_) bool mac::init(phy_interface_mac *phy, rlc_interface_mac *rlc, rrc_interface_mac *rrc, srslte::log *log_h_)
{ {
started = false;
phy_h = phy; phy_h = phy;
rlc_h = rlc; rlc_h = rlc;
rrc_h = rrc; rrc_h = rrc;
log_h = log_h_; log_h = log_h_;
tti = 0; tti = 0;
is_synchronized = false;
last_temporal_crnti = 0;
phy_rnti = 0;
srslte_softbuffer_rx_init(&pch_softbuffer, 100); 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(); reset();
started = true; start_periodic(1000, MAC_MAIN_THREAD_PRIO);
start(MAC_MAIN_THREAD_PRIO);
mactimers.init(&timers, log_h); return true;
return started;
} }
void mac::stop() void mac::stop()
{ {
srslte_softbuffer_rx_free(&pch_softbuffer); srslte_softbuffer_rx_free(&pch_softbuffer);
started = false;
ttisync.increase();
pdu_process_thread.stop(); pdu_process_thread.stop();
stop_thread();
wait_thread_finish(); wait_thread_finish();
mactimers.stop();
} }
void mac::start_pcap(srslte::mac_pcap* pcap_) void mac::start_pcap(srslte::mac_pcap* pcap_)
@ -150,59 +139,38 @@ void mac::reset()
bzero(&uernti, sizeof(ue_rnti_t)); bzero(&uernti, sizeof(ue_rnti_t));
} }
void mac::mac_timers::init(srslte::timers *timers, srslte::log *log_h) { void mac::run_period() {
this->timers = timers;
running = true;
this->log_h = log_h;
start_periodic(1000);
}
void mac::mac_timers::run_period() {
timers->step_all();
}
void mac::run_thread() {
int cnt=0;
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());
}
}
while(started) {
/* Warning: Here order of invocation of procedures is important!! */ /* Warning: Here order of invocation of procedures is important!! */
tti = ttisync.wait();
log_h->step(tti); tti = phy_h->get_current_tti();
// Step all procedures log_h->step(tti);
bsr_procedure.step(tti);
phr_procedure.step(tti);
// Check if BSR procedure need to start SR // Step all procedures
bsr_procedure.step(tti);
phr_procedure.step(tti);
if (bsr_procedure.need_to_send_sr(tti)) { // Check if BSR procedure need to start SR
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 SR if we need to start RA if (bsr_procedure.need_to_send_sr(tti)) {
if (sr_procedure.need_random_access()) { Debug("Starting SR procedure by BSR request, PHY TTI=%d\n", tti);
ra_procedure.start_mac_order(); sr_procedure.start();
} }
ra_procedure.step(tti); 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() 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); 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() void mac::pcch_start_rx()
{ {
phy_h->pdcch_dl_search(SRSLTE_RNTI_PCH, SRSLTE_PRNTI); phy_h->pdcch_dl_search(SRSLTE_RNTI_PCH, SRSLTE_PRNTI);
Info("SCHED: Searching for DL grant for P-RNTI\n"); 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(); 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) void mac::bch_decoded_ok(uint8_t* payload, uint32_t len)
{ {
// Send MIB to RLC // 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"), ("rf.time_adv_nsamples", bpo::value<string>(&args->rf.time_adv_nsamples)->default_value("auto"),
"Transmission time advance") "Transmission time advance")
("rf.burst_preamble_us", bpo::value<string>(&args->rf.burst_preamble)->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" ("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") "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), bpo::value<bool>(&args->expert.pregenerate_signals)->default_value(false),
"Pregenerate uplink signals after attach. Improves CPU performance.") "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", ("expert.rssi_sensor_enabled",
bpo::value<bool>(&args->expert.phy.rssi_sensor_enabled)->default_value(false), bpo::value<bool>(&args->expert.phy.rssi_sensor_enabled)->default_value(false),
"Enable or disable RF frontend RSSI sensor. In some USRP devices can cause segmentation fault") "Enable or disable RF frontend RSSI sensor. In some USRP devices can cause segmentation fault")
@ -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), 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.") "Averages in the time domain the channel estimates within 1 subframe. Needs accurate CFO correction.")
("expert.time_correct_period", ("expert.estimator_fil_auto",
bpo::value<int>(&args->expert.phy.time_correct_period)->default_value(5), bpo::value<bool>(&args->expert.phy.estimator_fil_auto)->default_value(false),
"Period for sampling time offset correction.") "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", ("expert.sss_algorithm",
bpo::value<string>(&args->expert.phy.sss_algorithm)->default_value("full"), bpo::value<string>(&args->expert.phy.sss_algorithm)->default_value("full"),
"Selects the SSS estimation algorithm.") "Selects the SSS estimation algorithm.")
("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", ("expert.pdsch_csi_enabled",
bpo::value<bool>(&args->expert.phy.pdsch_csi_enabled)->default_value(false), 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.") "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_t input;
pthread_create(&input, NULL, &input_loop, &args); pthread_create(&input, NULL, &input_loop, &args);
bool plot_started = false; printf("Attaching UE...\n");
bool signals_pregenerated = false; 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) { while (running) {
if (ue->is_attached()) { if (args.expert.print_buffer_state) {
if (!signals_pregenerated && args.expert.pregenerate_signals) { cnt++;
ue->pregenerate_signals(true); if (cnt==10) {
signals_pregenerated = true; cnt=0;
} ue->print_pool();
if (!plot_started && args.gui.enable) {
ue->start_plot();
plot_started = true;
} }
} }
sleep(1); 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); radio_h->tx_single(buffer, nof_samples, tx_time);
is_first_of_burst = false; is_first_of_burst = false;
} else { } else {
if (TX_MODE_CONTINUOUS) { if (radio_h->is_continuous_tx()) {
if (!is_first_of_burst) { if (!is_first_of_burst) {
radio_h->tx_single(zeros, nof_samples, tx_time); radio_h->tx_single(zeros, nof_samples, tx_time);
} }
@ -342,11 +342,13 @@ void phch_common::reset() {
cur_radio_power = 0; cur_radio_power = 0;
sr_last_tx_tti = -1; sr_last_tx_tti = -1;
cur_pusch_power = 0; cur_pusch_power = 0;
avg_snr_db_cqi = 0;
avg_snr_db_sync = 0;
avg_rsrp = 0; avg_rsrp = 0;
avg_rsrp_cqi = 0;
avg_rsrp_dbm = 0; avg_rsrp_dbm = 0;
avg_rsrq_db = 0; avg_rsrq_db = 0;
pcell_meas_enabled = false;
pcell_report_period = 20; pcell_report_period = 20;
bzero(pending_ack, sizeof(pending_ack_t)*TTIMOD_SZ); 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; 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_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_chest_dl_cfo_estimate_enable(&ue_dl.chest, phy->args->cfo_ref_mask!=0, phy->args->cfo_ref_mask);
srslte_ue_ul_set_normalization(&ue_ul, true); srslte_ue_ul_set_normalization(&ue_ul, true);
@ -185,6 +186,11 @@ void phch_worker::set_tti(uint32_t tti_, uint32_t tx_tti_)
log_phy_lib_h->step(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_) void phch_worker::set_cfo(float cfo_)
{ {
cfo = cfo_; cfo = cfo_;
@ -318,60 +324,70 @@ void phch_worker::work_imp()
/***** Uplink Processing + Transmission *******/ /***** 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 */ bool signal_ready = false;
ul_grant_available = decode_pdcch_ul(&ul_mac_grant); cf_t *signal_ptr = NULL;
/* Generate CQI reports if required, note that in case both aperiodic /* Transmit PRACH if pending, or PUSCH/PUCCH otherwise */
and periodic ones present, only aperiodic is sent (36.213 section 7.2) */ if (prach_ptr) {
if (ul_grant_available && ul_mac_grant.has_cqi_request) { signal_ready = true;
set_uci_aperiodic_cqi(); signal_ptr = prach_ptr;
} else { } else {
set_uci_periodic_cqi(); /* Generate SR if required*/
} set_uci_sr();
/* TTI offset for UL */ /* Check if we have UL grant. ul_phy_grant will be overwritten by new grant */
ul_action.tti_offset = HARQ_DELAY_MS; ul_grant_available = decode_pdcch_ul(&ul_mac_grant);
/* Send UL grant or HARQ information (from PHICH) to MAC */ /* Generate CQI reports if required, note that in case both aperiodic
if (ul_grant_available && ul_ack_available) { and periodic ones present, only aperiodic is sent (36.213 section 7.2) */
phy->mac->new_grant_ul_ack(ul_mac_grant, ul_ack, &ul_action); if (ul_grant_available && ul_mac_grant.has_cqi_request) {
} else if (ul_grant_available && !ul_ack_available) { set_uci_aperiodic_cqi();
phy->mac->new_grant_ul(ul_mac_grant, &ul_action); } else {
} else if (!ul_grant_available && ul_ack_available) { set_uci_periodic_cqi();
phy->mac->harq_recv(tti, ul_ack, &ul_action); }
}
/* Set UL CFO before transmission */ /* TTI offset for UL */
srslte_ue_ul_set_cfo(&ue_ul, cfo); ul_action.tti_offset = HARQ_DELAY_MS;
/* Transmit PUSCH, PUCCH or SRS */ /* Send UL grant or HARQ information (from PHICH) to MAC */
bool signal_ready = false; if (ul_grant_available && ul_ack_available) {
if (ul_action.tx_enabled) { phy->mac->new_grant_ul_ack(ul_mac_grant, ul_ack, &ul_action);
encode_pusch(&ul_action.phy_grant.ul, ul_action.payload_ptr[0], ul_action.current_tx_nb, } else if (ul_grant_available && !ul_ack_available) {
&ul_action.softbuffers[0], ul_action.rv[0], ul_action.rnti, ul_mac_grant.is_from_rar); phy->mac->new_grant_ul(ul_mac_grant, &ul_action);
signal_ready = true; } else if (!ul_grant_available && ul_ack_available) {
if (ul_action.expect_ack) { phy->mac->harq_recv(tti, ul_ack, &ul_action);
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) { /* Set UL CFO before transmission */
encode_pucch(); srslte_ue_ul_set_cfo(&ue_ul, cfo);
signal_ready = true;
} else if (srs_is_ready_to_send()) { /* Transmit PUSCH, PUCCH or SRS */
encode_srs(); if (ul_action.tx_enabled) {
signal_ready = true; 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(); tr_log_end();
if (next_offset > 0) { 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 { } 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) { if (!dl_action.generate_ack_callback) {
@ -391,13 +407,13 @@ void phch_worker::work_imp()
update_measurements(); update_measurements();
if (chest_ok) { if (chest_ok) {
if (phy->avg_rsrp_dbm > -130.0 && phy->avg_snr_db > -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", 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(); chest_loop->in_sync();
} else { } else {
log_h->warning("SNR=%.1f dB RSRP=%.1f dBm, sync=out-of-sync from channel estimator\n", log_h->warning("SNR=%.1f dB RSRP=%.1f dBm, sync=out-of-sync from channel estimator\n",
phy->avg_snr_db, phy->avg_rsrp_dbm); phy->avg_snr_db_sync, phy->avg_rsrp_sync_dbm);
chest_loop->out_of_sync(); 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; uci_data.uci_ri_len = 1;
} else if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) { } 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); if (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]])); 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 phch_worker::extract_fft_and_pdcch_llr() {
bool decode_pdcch = true; bool decode_pdcch = true;
/* Without a grant, we might need to do fft processing if need to decode PHICH */ // Do always channel estimation to keep track of out-of-sync and send measurements to RRC
if (phy->get_pending_ack(tti) || decode_pdcch) {
// Setup estimator filter
// Setup estimator filter srslte_chest_dl_set_smooth_filter_gauss(&ue_dl.chest,
float w_coeff = phy->args->estimator_fil_w; phy->args->estimator_fil_order,
if (w_coeff > 0.0) { phy->args->estimator_fil_stddev);
srslte_chest_dl_set_smooth_filter3_coeff(&ue_dl.chest, w_coeff); srslte_chest_dl_set_smooth_filter_auto(&ue_dl.chest, phy->args->estimator_fil_auto);
} else if (w_coeff == 0.0) {
srslte_chest_dl_set_smooth_filter(&ue_dl.chest, NULL, 0); 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")) {
if (!phy->args->snr_estim_alg.compare("refs")) { srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_EMPTY);
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);
}
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, tti%10, &cfi) < 0) {
Error("Getting PDCCH FFT estimate\n");
return false;
}
chest_done = true;
} else { } 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 */ if (chest_done && decode_pdcch) { /* and not in DRX mode */
float noise_estimate = phy->avg_noise; 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; srslte_ra_dl_dci_t dci_unpacked;
if (type == SRSLTE_RNTI_RAR) { 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, if (srslte_ue_dl_find_dl_dci_type(&ue_dl, phy->config->dedicated.antenna_info_explicit_value.tx_mode, cfi, tti%10,
dl_rnti, type, &dci_msg) != 1) { dl_rnti, type, &dci_msg) != 1) {
if (type == SRSLTE_RNTI_RAR) { 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, 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)), tti, cfi,
phy->config->dedicated.antenna_info_explicit_value.tx_mode, cell.id); 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) { if (period_cqi.format_is_subband) {
// TODO: Implement subband periodic reports // TODO: Implement subband periodic reports
cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND; 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; cqi_report.subband.subband_label = 0;
log_h->console("Warning: Subband CQI periodic reports not implemented\n"); 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 { } else {
cqi_report.type = SRSLTE_CQI_TYPE_WIDEBAND; cqi_report.type = SRSLTE_CQI_TYPE_WIDEBAND;
if (cqi_fixed >= 0) { if (cqi_fixed >= 0) {
cqi_report.wideband.wideband_cqi = cqi_fixed; cqi_report.wideband.wideband_cqi = cqi_fixed;
} else { } 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) { if (cqi_max >= 0 && cqi_report.wideband.wideband_cqi > cqi_max) {
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.pmi = phy->last_pmi;
cqi_report.wideband.rank_is_not_one = (phy->last_ri != 0); 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); uci_data.uci_cqi_len = (uint32_t) srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi);
rar_cqi_request = false; rar_cqi_request = false;
@ -957,7 +977,7 @@ void phch_worker::set_uci_aperiodic_cqi()
if (rnti_is_set) { if (rnti_is_set) {
srslte_cqi_value_t cqi_report = {0}; srslte_cqi_value_t cqi_report = {0};
cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND_HL; 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 // TODO: implement subband CQI properly
cqi_report.subband_hl.subband_diff_cqi_cw0 = 0; // Always report zero offset on all subbands 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", 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; break;
case LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM31: 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)); float rsrq_db = 10*log10(srslte_chest_dl_get_rsrq(&ue_dl.chest));
if (isnormal(rsrq_db)) { if (isnormal(rsrq_db)) {
if (!phy->avg_rsrq_db) { if (!(tti%phy->pcell_report_period) || !phy->avg_rsrq_db) {
phy->avg_rsrq_db = SRSLTE_VEC_EMA(rsrq_db, phy->avg_rsrq_db, snr_ema_coeff);
} else {
phy->avg_rsrq_db = 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 // Average RSRP taken from CRS
float rsrp_lin = srslte_chest_dl_get_rsrp(&ue_dl.chest); float rsrp_lin = srslte_chest_dl_get_rsrp_neighbour(&ue_dl.chest);
if (isnormal(rsrp_lin)) { if (isnormal(rsrp_lin)) {
if (!phy->avg_rsrp) { if (!phy->avg_rsrp) {
phy->avg_rsrp = SRSLTE_VEC_EMA(rsrp_lin, phy->avg_rsrp, snr_ema_coeff); 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 */ /* Correct absolute power measurements by RX gain offset */
float rsrp_dbm = 10*log10(rsrp_lin) + 30 - phy->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 (isnormal(rsrp_dbm)) {
if (!phy->avg_rsrp_dbm) { if (!(tti%phy->pcell_report_period) || !phy->avg_rsrp_dbm) {
phy->avg_rsrp_dbm = rsrp_dbm; phy->avg_rsrp_dbm = rsrp_dbm;
} else { } else {
phy->avg_rsrp_dbm = SRSLTE_VEC_EMA(rsrp_dbm, phy->avg_rsrp_dbm, snr_ema_coeff); phy->avg_rsrp_dbm = SRSLTE_VEC_CMA(rsrp_dbm, phy->avg_rsrp_dbm, tti%phy->pcell_report_period);
}
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);
} }
} }
// 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 // Compute PL
float tx_crs_power = phy->config->common.pdsch_cnfg.rs_power; float tx_crs_power = phy->config->common.pdsch_cnfg.rs_power;
phy->pathloss = tx_crs_power - phy->avg_rsrp_dbm; phy->pathloss = tx_crs_power - phy->avg_rsrp_dbm;
@ -1444,20 +1466,40 @@ void phch_worker::update_measurements()
phy->avg_noise = SRSLTE_VEC_EMA(cur_noise, phy->avg_noise, snr_ema_coeff); phy->avg_noise = SRSLTE_VEC_EMA(cur_noise, phy->avg_noise, snr_ema_coeff);
} }
} }
// Compute SNR // To compute CQI use RSRP measurements from resource elements in RS since is more robust to time offset
phy->avg_snr_db = 10*log10(phy->avg_rsrp/phy->avg_noise); 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 // Store metrics
dl_metrics.n = phy->avg_noise; dl_metrics.n = phy->avg_noise;
dl_metrics.rsrp = phy->avg_rsrp_dbm; dl_metrics.rsrp = phy->avg_rsrp_dbm;
dl_metrics.rsrq = phy->avg_rsrq_db; dl_metrics.rsrq = phy->avg_rsrq_db;
dl_metrics.rssi = phy->avg_rssi_dbm; dl_metrics.rssi = phy->avg_rssi_dbm;
dl_metrics.pathloss = phy->pathloss; 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); dl_metrics.turbo_iters = srslte_pdsch_last_noi(&ue_dl.pdsch);
phy->set_dl_metrics(dl_metrics); phy->set_dl_metrics(dl_metrics);
} }
} }

@ -96,9 +96,10 @@ void phy::set_default_args(phy_args_t *args)
args->equalizer_mode = "mmse"; args->equalizer_mode = "mmse";
args->cfo_integer_enabled = false; args->cfo_integer_enabled = false;
args->cfo_correct_tol_hz = 50; args->cfo_correct_tol_hz = 50;
args->time_correct_period = 5;
args->sss_algorithm = "full"; 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) 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"); log_h->console("Error in PHY args: nof_phy_threads must be 1, 2 or 3\n");
return false; 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) { if (args->snr_ema_coeff > 1.0) {
log_h->console("Error in PHY args: snr_ema_coeff must be 0<=w<=1\n"); log_h->console("Error in PHY args: snr_ema_coeff must be 0<=w<=1\n");
return false; 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() { void phy::meas_reset() {
sf_recv.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); return sf_recv.meas_stop(earfcn, pci);
} }
void phy::cell_select(uint32_t earfcn, srslte_cell_t phy_cell) bool phy::cell_select(phy_cell_t *cell) {
{ return sf_recv.cell_select(cell);
sf_recv.cell_select(earfcn, phy_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) { bool phy::cell_is_camping() {
return sf_recv.cell_handover(cell); return sf_recv.cell_is_camping();
} }
float phy::get_phr() float phy::get_phr()
@ -348,13 +334,14 @@ int phy::prach_tx_tti()
// Handle the case of a radio overflow. Resynchronise inmediatly // Handle the case of a radio overflow. Resynchronise inmediatly
void phy::radio_overflow() { void phy::radio_overflow() {
sf_recv.reset_sync(); sf_recv.radio_overflow();
} }
void phy::reset() void phy::reset()
{ {
Info("Resetting PHY\n"); Info("Resetting PHY\n");
n_ta = 0; n_ta = 0;
sf_recv.set_time_adv_sec(0);
pdcch_dl_search_reset(); pdcch_dl_search_reset();
for(uint32_t i=0;i<nof_workers;i++) { for(uint32_t i=0;i<nof_workers;i++) {
workers[i].reset(); 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); 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]) void phy::set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN])
{ {
workers_common.set_rar_grant(tti, grant_payload); 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; return;
} }
srslte_cfo_set_tol(&cfo_h, 0); 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) { if (!signal_buffer) {
perror("malloc"); perror("malloc");
return; return;
@ -159,10 +159,10 @@ bool prach::is_pending() {
bool prach::is_ready_to_send(uint32_t current_tti_) { bool prach::is_ready_to_send(uint32_t current_tti_) {
if (is_pending()) { if (is_pending()) {
// consider the number of subframes the transmission must be anticipated // consider the number of subframes the transmission must be anticipated
uint32_t current_tti = (current_tti_ + tx_advance_sf)%10240; uint32_t tti_tx = TTI_TX(current_tti_);
if (srslte_prach_tti_opportunity(&prach_obj, current_tti, allowed_subframe)) { if (srslte_prach_tti_opportunity(&prach_obj, tti_tx, allowed_subframe)) {
Debug("PRACH Buffer: Ready to send at tti: %d (now is %d)\n", current_tti, current_tti_); Debug("PRACH Buffer: Ready to send at tti: %d (now is %d)\n", tti_tx, current_tti_);
transmitted_tti = current_tti; transmitted_tti = tti_tx;
return true; return true;
} }
} }
@ -173,55 +173,31 @@ int prach::tx_tti() {
return transmitted_tti; return transmitted_tti;
} }
float prach::get_p0_preamble() cf_t *prach::generate(float cfo, uint32_t *nof_sf, float *target_power) {
{
return target_power_dbm;
}
if (cell_initiated && preamble_idx >= 0 && nof_sf) {
void prach::send(srslte::radio *radio_handler, float cfo, float pathloss, srslte_timestamp_t tx_time) // 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));
// Get current TX gain // pad guard symbols with zeros
float old_gain = radio_handler->get_tx_gain(); 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));
// 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)); *nof_sf = nsf;
// If power control is enabled, choose amplitude and power if (target_power) {
if (args->ul_pwr_ctrl_en) { *target_power = target_power_dbm;
// Get PRACH transmission power
float tx_power = SRSLTE_MIN(SRSLTE_PC_MAX, pathloss + target_power_dbm);
// Get output power for amplitude 1
radio_handler->set_tx_power(tx_power);
// Scale signal
float digital_power = srslte_vec_avg_power_cf(signal_buffer, len);
float scale = sqrtf(pow(10,tx_power/10)/digital_power);
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);
} 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);
}
void *tmp_buffer[SRSLTE_MAX_PORTS] = {signal_buffer, NULL, NULL, NULL}; Info("PRACH: Transmitted preamble=%d, CFO=%.2f KHz, nof_sf=%d, target_power=%.1f dBm\n",
radio_handler->tx(tmp_buffer, len, tx_time); preamble_idx, cfo*15, nsf, target_power_dbm);
radio_handler->tx_end(); preamble_idx = -1;
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); return signal_buffer;
Debug("Restoring TX gain to %.0f dB\n", old_gain); } else {
return NULL;
}
} }
} // namespace srsue } // namespace srsue

@ -160,7 +160,10 @@ bool ue::init(all_args_t *args_)
if (args->rf.burst_preamble.compare("auto")) { if (args->rf.burst_preamble.compare("auto")) {
radio.set_burst_preamble(atof(args->rf.burst_preamble.c_str())); 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); radio.set_manual_calibration(&args->rf_cal);
// Set PHY options // Set PHY options
@ -226,7 +229,6 @@ bool ue::init(all_args_t *args_)
} }
printf("...\n"); printf("...\n");
nas.attach_request();
started = true; started = true;
return 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() bool ue::is_attached()
{ {
return rrc.is_connected(); return rrc.is_connected();

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

@ -45,10 +45,13 @@ namespace srsue {
********************************************************************/ ********************************************************************/
nas::nas() 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.rx_count = 0;
ctxt.tx_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_, void nas::init(usim_interface_nas *usim_,
@ -63,7 +66,6 @@ void nas::init(usim_interface_nas *usim_,
gw = gw_; gw = gw_;
nas_log = nas_log_; nas_log = nas_log_;
state = EMM_STATE_DEREGISTERED; state = EMM_STATE_DEREGISTERED;
plmn_selection = PLMN_NOT_SELECTED;
if (!usim->get_home_plmn_id(&home_plmn)) { if (!usim->get_home_plmn_id(&home_plmn)) {
nas_log->error("Getting Home PLMN Id from USIM. Defaulting to 001-01\n"); 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_guti = true;
have_ctxt = true; have_ctxt = true;
} }
running = true;
} }
void nas::stop() { void nas::stop() {
running = false;
write_ctxt_file(ctxt); write_ctxt_file(ctxt);
} }
@ -94,105 +98,186 @@ emm_state_t nas::get_state() {
* UE interface * 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"); nas_log->info("Attach Request\n");
if (state == EMM_STATE_DEREGISTERED) { switch (state) {
state = EMM_STATE_REGISTERED_INITIATED; case EMM_STATE_DEREGISTERED:
if (plmn_selection == PLMN_NOT_SELECTED) {
nas_log->info("Starting PLMN Search...\n"); // Search PLMN is not selected
rrc->plmn_search(); if (!plmn_is_selected) {
} else if (plmn_selection == PLMN_SELECTED) { nas_log->info("No PLMN selected. Starting PLMN Search...\n");
nas_log->info("Selecting PLMN %s\n", plmn_id_to_string(current_plmn).c_str()); nof_plmns = rrc->plmn_search(found_plmns);
rrc->plmn_select(current_plmn); if (nof_plmns > 0) {
selecting_plmn = current_plmn; // Save PLMNs
} known_plmns.clear();
} else if (state == EMM_STATE_REGISTERED) { for (int i=0;i<nof_plmns;i++) {
nas_log->info("NAS state is registered, selecting current PLMN\n"); known_plmns.push_back(found_plmns[i].plmn_id);
rrc->plmn_select(current_plmn, true); nas_log->info("Found PLMN: Id=%s, TAC=%d\n", plmn_id_to_string(found_plmns[i].plmn_id).c_str(),
} else { found_plmns[i].tac);
nas_log->info("Attach request ignored. State = %s\n", emm_state_text[state]); 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; state = EMM_STATE_DEREGISTERED_INITIATED;
nas_log->info("Dettach request not supported\n"); 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 void nas::paging(LIBLTE_RRC_S_TMSI_STRUCT *ue_identiy) {
for (uint32_t i=0;i<known_plmns.size();i++) { if (state == EMM_STATE_REGISTERED) {
if (plmn_id.mcc == known_plmns[i].mcc && plmn_id.mnc == known_plmns[i].mnc) { nas_log->info("Received paging: requesting RRC connection establishment\n");
nas_log->info("Found known PLMN Id=%s\n", plmn_id_to_string(plmn_id).c_str()); if (rrc_connect()) {
if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) { nas_log->info("Attached successfully\n");
nas_log->info("Connecting Home PLMN Id=%s\n", plmn_id_to_string(plmn_id).c_str()); } else {
rrc->plmn_select(plmn_id, state == EMM_STATE_REGISTERED_INITIATED); nas_log->error("Could not attach from paging\n");
selecting_plmn = plmn_id;
return true;
}
return false;
} }
} else {
nas_log->warning("Received paging while in state %s\n", emm_state_text[state]);
} }
}
// Save if new PLMN void nas::set_barring(barring_t barring) {
known_plmns.push_back(plmn_id); current_barring = barring;
}
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);
if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) { /* Internal function that requests RRC connection, waits for positive or negative response and returns true/false
rrc->plmn_select(plmn_id, state == EMM_STATE_REGISTERED_INITIATED); */
selecting_plmn = plmn_id; bool nas::rrc_connect() {
if (rrc->is_connected()) {
nas_log->info("Already connected\n");
return true; return true;
} }
return false;
}
// RRC indicates that the UE has gone through all EARFCN and finished PLMN selection // Generate service request or attach request message
void nas::plmn_search_end() { byte_buffer_t *dedicatedInfoNAS = pool_allocate;
if (known_plmns.size() > 0) { if (state == EMM_STATE_REGISTERED) {
if (home_plmn.mcc != known_plmns[0].mcc && home_plmn.mnc != known_plmns[0].mnc) { gen_service_request(dedicatedInfoNAS);
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);
} else { } else {
nas_log->info("Finished searching PLMN in current EARFCN set but no networks were found.\n"); gen_attach_request(dedicatedInfoNAS);
if (state == EMM_STATE_REGISTERED_INITIATED && plmn_selection == PLMN_NOT_SELECTED) { }
rrc->plmn_search();
// 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() { void nas::select_plmn() {
return state == EMM_STATE_REGISTERED;
}
bool nas::is_attaching() { plmn_is_selected = false;
return state == EMM_STATE_REGISTERED_INITIATED;
}
void nas::notify_connection_setup() { // First find if Home PLMN is available
nas_log->debug("State = %s\n", emm_state_text[state]); for (uint32_t i=0;i<known_plmns.size();i++) {
if (EMM_STATE_REGISTERED_INITIATED == state) { if (known_plmns[i].mcc == home_plmn.mcc && known_plmns[i].mnc == home_plmn.mnc) {
send_attach_request(); nas_log->info("Selecting Home PLMN Id=%s\n", plmn_id_to_string(known_plmns[i]).c_str());
} else { plmn_is_selected = true;
send_service_request(); 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) { void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu) {
uint8 pd = 0; uint8 pd = 0;
uint8 msg_type = 0; uint8 msg_type = 0;
@ -271,16 +356,6 @@ uint32_t nas::get_ul_count() {
return ctxt.tx_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) { bool nas::get_k_asme(uint8_t *k_asme_, uint32_t n) {
if(!have_ctxt) { if(!have_ctxt) {
nas_log->error("K_asme requested before security context established\n"); 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; return NULL;
} }
if (pdu->N_bytes > 5) { if (pdu->N_bytes > 5) {
uint8_t exp_mac[4]; uint8_t exp_mac[4] = {0};
uint8_t *mac = &pdu->msg[1]; uint8_t *mac = &pdu->msg[1];
int i; 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); memcpy(&pdu->msg[6], &pdu_tmp.msg[6], pdu->N_bytes-6);
break; break;
default: default:
nas_log->error("Ciphering algorithmus not known"); nas_log->error("Ciphering algorithm not known\n");
break; break;
} }
} }
@ -474,10 +549,10 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
return; return;
} }
LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT attach_accept; LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT attach_accept = {0};
LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT act_def_eps_bearer_context_req; LIBLTE_MME_ATTACH_COMPLETE_MSG_STRUCT attach_complete = {0};
LIBLTE_MME_ATTACH_COMPLETE_MSG_STRUCT attach_complete; 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; LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT act_def_eps_bearer_context_accept = {0};
nas_log->info("Received Attach Accept\n"); 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) { if (attach_accept.guti_present) {
memcpy(&ctxt.guti, &attach_accept.guti.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT)); memcpy(&ctxt.guti, &attach_accept.guti.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT));
have_guti = true; 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.lai_present) {}
if (attach_accept.ms_id_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]; 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", 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[0],
act_def_eps_bearer_context_req.pdn_addr.addr[1], act_def_eps_bearer_context_req.pdn_addr.addr[1],
act_def_eps_bearer_context_req.pdn_addr.addr[2], 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 // FIXME: Setup the default EPS bearer context
state = EMM_STATE_REGISTERED; state = EMM_STATE_REGISTERED;
current_plmn = selecting_plmn;
plmn_selection = PLMN_SELECTED;
ctxt.rx_count++; 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) { 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); 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); 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) { void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) {
LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT auth_req; 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; 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"); nas_log->info("Received Authentication Request\n");
liblte_mme_unpack_authentication_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &auth_req); 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) { void nas::parse_identity_request(uint32_t lcid, byte_buffer_t *pdu) {
LIBLTE_MME_ID_REQUEST_MSG_STRUCT id_req; LIBLTE_MME_ID_REQUEST_MSG_STRUCT id_req = {0};
LIBLTE_MME_ID_RESPONSE_MSG_STRUCT id_resp; LIBLTE_MME_ID_RESPONSE_MSG_STRUCT id_resp = {0};
liblte_mme_unpack_identity_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &id_req); 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); 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; 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; 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); 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", 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 * Senders
******************************************************************************/ ******************************************************************************/
void nas::send_attach_request() { void nas::gen_attach_request(byte_buffer_t *msg) {
LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT attach_req;
byte_buffer_t *msg = pool_allocate;
if (!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; 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; 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.eea[i] = eea_caps[i];
attach_req.ue_network_cap.eia[i] = eia_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); pcap->write_nas(msg->msg, msg->N_bytes);
} }
nas_log->info("Sending attach request\n");
rrc->write_sdu(cfg.lcid, msg);
if (have_ctxt) { if (have_ctxt) {
ctxt.tx_count++; 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) { 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"); 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; pdn_con_req.apn_present = false;
} else { } else {
pdn_con_req.apn_present = true; pdn_con_req.apn_present = true;
LIBLTE_MME_ACCESS_POINT_NAME_STRUCT apn; LIBLTE_MME_ACCESS_POINT_NAME_STRUCT apn = {0};
apn.apn = cfg.apn; strncpy(apn.apn, cfg.apn.c_str(), LIBLTE_STRING_LEN);
pdn_con_req.apn = apn; pdn_con_req.apn = apn;
} }
pdn_con_req.protocol_cnfg_opts_present = false; pdn_con_req.protocol_cnfg_opts_present = false;
@ -958,7 +1071,7 @@ void nas::send_security_mode_reject(uint8_t cause) {
return; 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; sec_mode_rej.emm_cause = cause;
liblte_mme_pack_security_mode_reject_msg(&sec_mode_rej, (LIBLTE_BYTE_MSG_STRUCT *) msg); liblte_mme_pack_security_mode_reject_msg(&sec_mode_rej, (LIBLTE_BYTE_MSG_STRUCT *) msg);
if(pcap != NULL) { if(pcap != NULL) {
@ -970,42 +1083,6 @@ void nas::send_security_mode_reject(uint8_t cause) {
void nas::send_identity_response() {} 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() {} 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", 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); nof_bytes, dlsch_msg.sibs[0].sib.sib1.cell_id&0xfff, si_window_len, sib2_period);
sib1_decoded = true; 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) { } else if (dlsch_msg.sibs[0].sib_type == LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2) {
printf("SIB2 received %d bytes\n", nof_bytes); printf("SIB2 received %d bytes\n", nof_bytes);
setup_mac_phy_sib2(&dlsch_msg.sibs[0].sib.sib2, &mac, &phy); setup_mac_phy_sib2(&dlsch_msg.sibs[0].sib.sib2, &mac, &phy);
sib2_decoded = true; 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); radio.set_tx_freq(prog_args.rf_tx_freq);
// Instruct the PHY to configure PRACH parameters and sync to current cell // 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); usleep(20000);
} }

@ -196,7 +196,7 @@ int main(int argc, char *argv[])
bool running = true; bool running = true;
while(running) { 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(); uint32_t tti = my_phy.get_current_tti();
// SIB1 is scheduled in subframe #5 of even frames, try to decode next frame SIB1 // 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++; total_pkts++;
} }
usleep(30000); 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) { if (srslte_verbose == SRSLTE_VERBOSE_NONE && srsapps_verbose == 0) {
float gain = prog_args.rf_gain; float gain = prog_args.rf_gain;
if (gain < 0) { 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, uint8_t sec_mode_command_pdu[] = { 0x37, 0x37, 0xc7, 0x67, 0xae, 0x00, 0x07, 0x5d, 0x02, 0x01,
0x02, 0xe0, 0x60, 0xc1 }; 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 mcc = 61441;
uint16 mnc = 65281; uint16 mnc = 65281;
@ -71,18 +80,35 @@ public:
class rrc_dummy : public rrc_interface_nas class rrc_dummy : public rrc_interface_nas
{ {
public: 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) 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; 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); byte_buffer_pool::get_instance()->deallocate(sdu);
} }
std::string get_rb_name(uint32_t lcid) { return std::string("lcid"); } std::string get_rb_name(uint32_t lcid) { return std::string("lcid"); }
uint32_t get_last_sdu_len() { return last_sdu_len; } uint32_t get_last_sdu_len() { return last_sdu_len; }
void plmn_search() {}; int plmn_search(srsue::rrc_interface_nas::found_plmn_t* found) {
void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, bool con_req) {}; 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_mcc() { return mcc; }
uint16_t get_mnc() { return mnc; } uint16_t get_mnc() { return mnc; }
@ -90,6 +116,7 @@ public:
private: private:
uint32_t last_sdu_len; uint32_t last_sdu_len;
found_plmn_t plmns;
}; };
class gw_dummy : public gw_interface_nas, public gw_interface_pdcp class gw_dummy : public gw_interface_nas, public gw_interface_pdcp
@ -130,15 +157,12 @@ int security_command_test()
uint8_t res[16]; uint8_t res[16];
usim.init(&args, &usim_log); usim.init(&args, &usim_log);
srslte::byte_buffer_pool *pool;
pool = byte_buffer_pool::get_instance();
srsue::nas nas; srsue::nas nas;
srslte_nas_config_t cfg; srslte_nas_config_t cfg;
nas.init(&usim, &rrc_dummy, &gw, &nas_log, cfg); nas.init(&usim, &rrc_dummy, &gw, &nas_log, cfg);
// push auth request PDU to NAS to generate security context // 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)); memcpy(tmp->msg, auth_request_pdu, sizeof(auth_request_pdu));
tmp->N_bytes = sizeof(auth_request_pdu); tmp->N_bytes = sizeof(auth_request_pdu);
nas.write_pdu(LCID, tmp); nas.write_pdu(LCID, tmp);
@ -155,7 +179,7 @@ int security_command_test()
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} }
pool->cleanup(); byte_buffer_pool::get_instance()->cleanup();
return ret; return ret;
} }
@ -190,13 +214,22 @@ int mme_attach_request_test()
nas.init(&usim, &rrc_dummy, &gw, &nas_log, nas_cfg); nas.init(&usim, &rrc_dummy, &gw, &nas_log, nas_cfg);
nas.attach_request(); 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) { if (rrc_dummy.get_last_sdu_len() > 3) {
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} }
byte_buffer_pool::get_instance()->cleanup();
return ret; return ret;
} }

@ -20,7 +20,9 @@
# from antenna to timestamp insertion. # from antenna to timestamp insertion.
# Default "auto". B210 USRP: 100 samples, bladeRF: 27. # Default "auto". B210 USRP: 100 samples, bladeRF: 27.
# burst_preamble_us: Preamble length to transmit before start of burst. # burst_preamble_us: Preamble length to transmit before start of burst.
# Default "auto". B210 USRP: 400 us, bladeRF: 0 us. # 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] [rf]
dl_earfcn = 3400 dl_earfcn = 3400
@ -33,6 +35,7 @@ rx_gain = 40
#device_args = auto #device_args = auto
#time_adv_nsamples = auto #time_adv_nsamples = auto
#burst_preamble_us = auto #burst_preamble_us = auto
#continuous_tx = auto
##################################################################### #####################################################################
@ -150,7 +153,9 @@ enable = false
# sampling frequency offset. Default is enabled. # sampling frequency offset. Default is enabled.
# sss_algorithm: Selects the SSS estimation algorithm. Can choose between # sss_algorithm: Selects the SSS estimation algorithm. Can choose between
# {full, partial, diff}. # {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] # The taps are [w, 1-2w, w]
# metrics_period_secs: Sets the period at which metrics are requested from the UE. # metrics_period_secs: Sets the period at which metrics are requested from the UE.
# #
@ -204,7 +209,9 @@ enable = false
#time_correct_period = 5 #time_correct_period = 5
#sfo_correct_disable = false #sfo_correct_disable = false
#sss_algorithm = full #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 #average_subframe_enabled = true
#sic_pss_enabled = true #sic_pss_enabled = true
#pregenerate_signals = false #pregenerate_signals = false

Loading…
Cancel
Save