mirror of https://github.com/PentHertz/srsLTE.git
Merge branch 'next' into rlc_updates
This commit is contained in:
commit
a2f6166365
|
@ -1,6 +1,10 @@
|
|||
Change Log for Releases
|
||||
==============================
|
||||
|
||||
## 18.03.1
|
||||
* Fixed compilation for NEON
|
||||
* Fixed logging and RLC AM issue
|
||||
|
||||
## 18.03
|
||||
* Many bug-fixes and improved stability and performance in all parts
|
||||
|
||||
|
|
|
@ -20,5 +20,5 @@
|
|||
|
||||
SET(SRSLTE_VERSION_MAJOR 18)
|
||||
SET(SRSLTE_VERSION_MINOR 3)
|
||||
SET(SRSLTE_VERSION_PATCH 0)
|
||||
SET(SRSLTE_VERSION_PATCH 1)
|
||||
SET(SRSLTE_VERSION_STRING "${SRSLTE_VERSION_MAJOR}.${SRSLTE_VERSION_MINOR}.${SRSLTE_VERSION_PATCH}")
|
||||
|
|
|
@ -51,9 +51,11 @@
|
|||
|
||||
// FIXME: This was chosen arbitrarily
|
||||
#define LIBLTE_ASN1_OID_MAXSUBIDS 128
|
||||
|
||||
// Caution these values must match SRSLTE_ ones in common.h
|
||||
#define LIBLTE_MAX_MSG_SIZE_BITS 102048
|
||||
#define LIBLTE_MAX_MSG_SIZE_BYTES 12756
|
||||
#define LIBLTE_MSG_HEADER_OFFSET 1024
|
||||
#define LIBLTE_MSG_HEADER_OFFSET 1020
|
||||
|
||||
/*******************************************************************************
|
||||
TYPEDEFS
|
||||
|
@ -82,6 +84,8 @@ static const char liblte_error_text[LIBLTE_ERROR_N_ITEMS][64] = {
|
|||
"Decode failure",
|
||||
};
|
||||
|
||||
#define LIBLTE_STRING_LEN 128
|
||||
|
||||
typedef void* LIBLTE_ASN1_OPEN_TYPE_STRUCT;
|
||||
|
||||
typedef struct {
|
||||
|
@ -96,86 +100,15 @@ typedef struct{
|
|||
|
||||
typedef struct{
|
||||
uint32 N_bits;
|
||||
uint8 header[LIBLTE_MSG_HEADER_OFFSET];
|
||||
uint8 msg[LIBLTE_MAX_MSG_SIZE_BITS];
|
||||
}LIBLTE_SIMPLE_BIT_MSG_STRUCT;
|
||||
}LIBLTE_BIT_MSG_STRUCT;
|
||||
|
||||
typedef struct{
|
||||
uint32 N_bytes;
|
||||
uint8 header[LIBLTE_MSG_HEADER_OFFSET];
|
||||
uint8 msg[LIBLTE_MAX_MSG_SIZE_BYTES];
|
||||
}LIBLTE_SIMPLE_BYTE_MSG_STRUCT;
|
||||
|
||||
|
||||
struct LIBLTE_BYTE_MSG_STRUCT{
|
||||
uint32 N_bytes;
|
||||
uint8 buffer[LIBLTE_MAX_MSG_SIZE_BYTES];
|
||||
uint8 *msg;
|
||||
|
||||
LIBLTE_BYTE_MSG_STRUCT():N_bytes(0)
|
||||
{
|
||||
msg = &buffer[LIBLTE_MSG_HEADER_OFFSET];
|
||||
}
|
||||
LIBLTE_BYTE_MSG_STRUCT(const LIBLTE_BYTE_MSG_STRUCT& buf)
|
||||
{
|
||||
N_bytes = buf.N_bytes;
|
||||
memcpy(msg, buf.msg, N_bytes);
|
||||
}
|
||||
LIBLTE_BYTE_MSG_STRUCT & operator= (const LIBLTE_BYTE_MSG_STRUCT & buf)
|
||||
{
|
||||
// avoid self assignment
|
||||
if (&buf == this)
|
||||
return *this;
|
||||
N_bytes = buf.N_bytes;
|
||||
memcpy(msg, buf.msg, N_bytes);
|
||||
return *this;
|
||||
}
|
||||
uint32 get_headroom()
|
||||
{
|
||||
return msg-buffer;
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
N_bytes = 0;
|
||||
msg = &buffer[LIBLTE_MSG_HEADER_OFFSET];
|
||||
}
|
||||
};
|
||||
|
||||
struct LIBLTE_BIT_MSG_STRUCT{
|
||||
uint32 N_bits;
|
||||
uint8 buffer[LIBLTE_MAX_MSG_SIZE_BITS];
|
||||
uint8 *msg;
|
||||
|
||||
LIBLTE_BIT_MSG_STRUCT():N_bits(0)
|
||||
{
|
||||
msg = &buffer[LIBLTE_MSG_HEADER_OFFSET];
|
||||
while( (uint64_t)(msg) % 8 > 0) {
|
||||
msg++;
|
||||
}
|
||||
}
|
||||
LIBLTE_BIT_MSG_STRUCT(const LIBLTE_BIT_MSG_STRUCT& buf){
|
||||
N_bits = buf.N_bits;
|
||||
memcpy(msg, buf.msg, N_bits);
|
||||
}
|
||||
LIBLTE_BIT_MSG_STRUCT & operator= (const LIBLTE_BIT_MSG_STRUCT & buf){
|
||||
// avoid self assignment
|
||||
if (&buf == this)
|
||||
return *this;
|
||||
N_bits = buf.N_bits;
|
||||
memcpy(msg, buf.msg, N_bits);
|
||||
return *this;
|
||||
}
|
||||
uint32 get_headroom()
|
||||
{
|
||||
return msg-buffer;
|
||||
}
|
||||
void reset()
|
||||
{
|
||||
N_bits = 0;
|
||||
msg = &buffer[LIBLTE_MSG_HEADER_OFFSET];
|
||||
while( (uint64_t)(msg) % 8 > 0) {
|
||||
msg++;
|
||||
}
|
||||
}
|
||||
};
|
||||
}LIBLTE_BYTE_MSG_STRUCT;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
|
|
@ -1209,7 +1209,7 @@ static const char liblte_mme_add_ci_text[LIBLTE_MME_ADD_CI_N_ITEMS][20] = {"Don'
|
|||
"Add"};
|
||||
// Structs
|
||||
typedef struct{
|
||||
std::string name;
|
||||
char name[LIBLTE_STRING_LEN];
|
||||
LIBLTE_MME_ADD_CI_ENUM add_ci;
|
||||
}LIBLTE_MME_NETWORK_NAME_STRUCT;
|
||||
// Functions
|
||||
|
@ -1752,7 +1752,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_guti_type_ie(uint8 **ie_
|
|||
// Enums
|
||||
// Structs
|
||||
typedef struct{
|
||||
std::string apn;
|
||||
char apn[LIBLTE_STRING_LEN];
|
||||
}LIBLTE_MME_ACCESS_POINT_NAME_STRUCT;
|
||||
// Functions
|
||||
LIBLTE_ERROR_ENUM liblte_mme_pack_access_point_name_ie(LIBLTE_MME_ACCESS_POINT_NAME_STRUCT *apn,
|
||||
|
|
|
@ -5579,7 +5579,7 @@ static const char liblte_rrc_ul_information_transfer_type_text[LIBLTE_RRC_UL_INF
|
|||
"CDMA2000-HRPD"};
|
||||
// Structs
|
||||
typedef struct{
|
||||
LIBLTE_SIMPLE_BYTE_MSG_STRUCT dedicated_info;
|
||||
LIBLTE_BYTE_MSG_STRUCT dedicated_info;
|
||||
LIBLTE_RRC_UL_INFORMATION_TRANSFER_TYPE_ENUM dedicated_info_type;
|
||||
}LIBLTE_RRC_UL_INFORMATION_TRANSFER_STRUCT;
|
||||
// Functions
|
||||
|
@ -5960,7 +5960,7 @@ typedef struct{
|
|||
}LIBLTE_RRC_REGISTERED_MME_STRUCT;
|
||||
typedef struct{
|
||||
LIBLTE_RRC_REGISTERED_MME_STRUCT registered_mme;
|
||||
LIBLTE_SIMPLE_BYTE_MSG_STRUCT dedicated_info_nas;
|
||||
LIBLTE_BYTE_MSG_STRUCT dedicated_info_nas;
|
||||
uint8 rrc_transaction_id;
|
||||
uint8 selected_plmn_id;
|
||||
bool registered_mme_present;
|
||||
|
@ -6245,7 +6245,7 @@ typedef struct{
|
|||
typedef struct{
|
||||
LIBLTE_RRC_MEAS_CONFIG_STRUCT meas_cnfg;
|
||||
LIBLTE_RRC_MOBILITY_CONTROL_INFO_STRUCT mob_ctrl_info;
|
||||
LIBLTE_SIMPLE_BYTE_MSG_STRUCT ded_info_nas_list[LIBLTE_RRC_MAX_DRB];
|
||||
LIBLTE_BYTE_MSG_STRUCT ded_info_nas_list[LIBLTE_RRC_MAX_DRB];
|
||||
LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT rr_cnfg_ded;
|
||||
LIBLTE_RRC_SECURITY_CONFIG_HO_STRUCT sec_cnfg_ho;
|
||||
uint32 N_ded_info_nas;
|
||||
|
@ -6626,7 +6626,7 @@ static const char liblte_rrc_dl_information_transfer_type_text[LIBLTE_RRC_DL_INF
|
|||
"CDMA2000-HRPD"};
|
||||
// Structs
|
||||
typedef struct{
|
||||
LIBLTE_SIMPLE_BYTE_MSG_STRUCT dedicated_info;
|
||||
LIBLTE_BYTE_MSG_STRUCT dedicated_info;
|
||||
LIBLTE_RRC_DL_INFORMATION_TRANSFER_TYPE_ENUM dedicated_info_type;
|
||||
uint8 rrc_transaction_id;
|
||||
}LIBLTE_RRC_DL_INFORMATION_TRANSFER_STRUCT;
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
// 3GPP 36.306 Table 4.1.1
|
||||
#define SRSLTE_MAX_BUFFER_SIZE_BITS 102048
|
||||
#define SRSLTE_MAX_BUFFER_SIZE_BYTES 12756
|
||||
#define SRSLTE_BUFFER_HEADER_OFFSET 1024
|
||||
#define SRSLTE_BUFFER_HEADER_OFFSET 1020
|
||||
|
||||
#define SRSLTE_BUFFER_POOL_LOG_ENABLED
|
||||
|
||||
|
@ -116,15 +116,17 @@ public:
|
|||
|
||||
byte_buffer_t():N_bytes(0)
|
||||
{
|
||||
timestamp_is_set = false;
|
||||
bzero(buffer, SRSLTE_MAX_BUFFER_SIZE_BYTES);
|
||||
timestamp_is_set = false;
|
||||
msg = &buffer[SRSLTE_BUFFER_HEADER_OFFSET];
|
||||
next = NULL;
|
||||
#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED
|
||||
debug_name[0] = 0;
|
||||
bzero(debug_name, SRSLTE_BUFFER_POOL_LOG_NAME_LEN);
|
||||
#endif
|
||||
}
|
||||
byte_buffer_t(const byte_buffer_t& buf)
|
||||
{
|
||||
bzero(buffer, SRSLTE_MAX_BUFFER_SIZE_BYTES);
|
||||
N_bytes = buf.N_bytes;
|
||||
memcpy(msg, buf.msg, N_bytes);
|
||||
}
|
||||
|
@ -133,6 +135,7 @@ public:
|
|||
// avoid self assignment
|
||||
if (&buf == this)
|
||||
return *this;
|
||||
bzero(buffer, SRSLTE_MAX_BUFFER_SIZE_BYTES);
|
||||
N_bytes = buf.N_bytes;
|
||||
memcpy(msg, buf.msg, N_bytes);
|
||||
return *this;
|
||||
|
|
|
@ -41,29 +41,35 @@ namespace srslte {
|
|||
class pdu_queue
|
||||
{
|
||||
public:
|
||||
typedef enum {
|
||||
DCH,
|
||||
BCH,
|
||||
MCH
|
||||
} channel_t;
|
||||
class process_callback
|
||||
{
|
||||
public:
|
||||
virtual void process_pdu(uint8_t *buff, uint32_t len, uint32_t tstamp) = 0;
|
||||
public:
|
||||
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) {}
|
||||
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 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();
|
||||
|
||||
|
||||
private:
|
||||
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 DEFAULT_POOL_SIZE = 64; // Number of PDU buffers in total
|
||||
const static int MAX_PDU_LEN = 150*1024/8; // ~ 150 Mbps
|
||||
|
||||
typedef struct {
|
||||
uint8_t ptr[MAX_PDU_LEN];
|
||||
uint32_t len;
|
||||
uint32_t tstamp;
|
||||
uint8_t ptr[MAX_PDU_LEN];
|
||||
uint32_t len;
|
||||
uint32_t tstamp;
|
||||
channel_t channel;
|
||||
#ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED
|
||||
char debug_name[128];
|
||||
#endif
|
||||
|
|
|
@ -89,7 +89,7 @@ public:
|
|||
period_us = period_us_;
|
||||
start(priority);
|
||||
}
|
||||
void stop() {
|
||||
void stop_thread() {
|
||||
run_enable = false;
|
||||
wait_thread_finish();
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ public:
|
|||
return (counter < timeout) && running;
|
||||
}
|
||||
bool is_expired() {
|
||||
return (timeout > 0) && (counter >= timeout || !running);
|
||||
return (timeout > 0) && (counter >= timeout);
|
||||
}
|
||||
uint32_t get_timeout() {
|
||||
return timeout;
|
||||
|
|
|
@ -112,30 +112,34 @@ public:
|
|||
class nas_interface_rrc
|
||||
{
|
||||
public:
|
||||
typedef enum {
|
||||
BARRING_NONE = 0,
|
||||
BARRING_MO_DATA,
|
||||
BARRING_MO_SIGNALLING,
|
||||
BARRING_MT,
|
||||
BARRING_ALL
|
||||
} barring_t;
|
||||
virtual void set_barring(barring_t barring) = 0;
|
||||
virtual void paging(LIBLTE_RRC_S_TMSI_STRUCT *ue_identiy) = 0;
|
||||
virtual bool is_attached() = 0;
|
||||
virtual bool is_attaching() = 0;
|
||||
virtual void notify_connection_setup() = 0;
|
||||
virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0;
|
||||
virtual uint32_t get_ul_count() = 0;
|
||||
virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 0;
|
||||
virtual bool get_k_asme(uint8_t *k_asme_, uint32_t n) = 0;
|
||||
virtual bool plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) = 0;
|
||||
virtual void plmn_search_end() = 0;
|
||||
};
|
||||
|
||||
// NAS interface for UE
|
||||
class nas_interface_ue
|
||||
{
|
||||
public:
|
||||
virtual void attach_request() = 0;
|
||||
virtual void deattach_request() = 0;
|
||||
virtual bool attach_request() = 0;
|
||||
virtual bool deattach_request() = 0;
|
||||
};
|
||||
|
||||
// NAS interface for UE
|
||||
class nas_interface_gw
|
||||
{
|
||||
public:
|
||||
virtual void attach_request() = 0;
|
||||
virtual bool attach_request() = 0;
|
||||
};
|
||||
|
||||
// RRC interface for MAC
|
||||
|
@ -159,8 +163,6 @@ class rrc_interface_phy
|
|||
public:
|
||||
virtual void in_sync() = 0;
|
||||
virtual void out_of_sync() = 0;
|
||||
virtual void earfcn_end() = 0;
|
||||
virtual void cell_camping(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp = NAN) = 0;
|
||||
virtual void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn = -1, int pci = -1) = 0;
|
||||
};
|
||||
|
||||
|
@ -168,12 +170,23 @@ public:
|
|||
class rrc_interface_nas
|
||||
{
|
||||
public:
|
||||
typedef struct {
|
||||
LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id;
|
||||
uint16_t tac;
|
||||
} found_plmn_t;
|
||||
|
||||
const static int MAX_FOUND_PLMNS = 16;
|
||||
|
||||
virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0;
|
||||
virtual uint16_t get_mcc() = 0;
|
||||
virtual uint16_t get_mnc() = 0;
|
||||
virtual void enable_capabilities() = 0;
|
||||
virtual void plmn_search() = 0;
|
||||
virtual void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, bool connect_request = false) = 0;
|
||||
virtual int plmn_search(found_plmn_t found_plmns[MAX_FOUND_PLMNS]) = 0;
|
||||
virtual void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) = 0;
|
||||
virtual bool connection_request(LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM cause,
|
||||
srslte::byte_buffer_t *dedicatedInfoNAS) = 0;
|
||||
virtual void set_ue_idenity(LIBLTE_RRC_S_TMSI_STRUCT s_tmsi) = 0;
|
||||
virtual bool is_connected() = 0;
|
||||
virtual std::string get_rb_name(uint32_t lcid) = 0;
|
||||
};
|
||||
|
||||
|
@ -380,12 +393,7 @@ public:
|
|||
|
||||
/* Indicate successfull decoding of PCH TB through PDSCH */
|
||||
virtual void pch_decoded_ok(uint32_t len) = 0;
|
||||
|
||||
/* Function called every start of a subframe (TTI). Warning, this function is called
|
||||
* from a high priority thread and should terminate asap
|
||||
*/
|
||||
virtual void tti_clock(uint32_t tti) = 0;
|
||||
|
||||
|
||||
};
|
||||
|
||||
/* Interface RRC -> MAC shared between different RATs */
|
||||
|
@ -420,15 +428,14 @@ public:
|
|||
uint32_t prach_config_index;
|
||||
} mac_cfg_t;
|
||||
|
||||
virtual void clear_rntis() = 0;
|
||||
|
||||
/* Instructs the MAC to start receiving BCCH */
|
||||
virtual void bcch_start_rx() = 0;
|
||||
virtual void bcch_stop_rx() = 0;
|
||||
virtual void bcch_start_rx(int si_window_start, int si_window_length) = 0;
|
||||
|
||||
/* Instructs the MAC to start receiving PCCH */
|
||||
virtual void pcch_start_rx() = 0;
|
||||
virtual void pcch_stop_rx() = 0;
|
||||
|
||||
|
||||
/* RRC configures a logical channel */
|
||||
virtual void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) = 0;
|
||||
|
||||
|
@ -487,9 +494,10 @@ typedef struct {
|
|||
uint32_t cfo_loop_pss_conv;
|
||||
uint32_t cfo_ref_mask;
|
||||
bool average_subframe_enabled;
|
||||
int time_correct_period;
|
||||
bool estimator_fil_auto;
|
||||
float estimator_fil_stddev;
|
||||
uint32_t estimator_fil_order;
|
||||
std::string sss_algorithm;
|
||||
float estimator_fil_w;
|
||||
bool rssi_sensor_enabled;
|
||||
bool sic_pss_enabled;
|
||||
float rx_gain_offset;
|
||||
|
@ -503,9 +511,7 @@ typedef struct {
|
|||
class phy_interface_mac_common
|
||||
{
|
||||
public:
|
||||
/* Start synchronization with strongest cell in the current carrier frequency */
|
||||
virtual bool sync_status() = 0;
|
||||
|
||||
|
||||
/* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */
|
||||
virtual void set_crnti(uint16_t rnti) = 0;
|
||||
|
||||
|
@ -581,15 +587,20 @@ public:
|
|||
virtual int meas_start(uint32_t earfcn, int pci = -1) = 0;
|
||||
virtual int meas_stop(uint32_t earfcn, int pci = -1) = 0;
|
||||
|
||||
/* Cell search and selection procedures */
|
||||
virtual void cell_search_start() = 0;
|
||||
virtual void cell_search_next() = 0;
|
||||
virtual void cell_select(uint32_t earfcn, srslte_cell_t cell) = 0;
|
||||
virtual bool cell_handover(srslte_cell_t cell) = 0;
|
||||
typedef struct {
|
||||
enum {CELL_FOUND = 0, CELL_NOT_FOUND, ERROR} found;
|
||||
enum {MORE_FREQS = 0, NO_MORE_FREQS} last_freq;
|
||||
} cell_search_ret_t;
|
||||
|
||||
/* Is the PHY downlink synchronized? */
|
||||
virtual bool sync_status() = 0;
|
||||
virtual void sync_reset() = 0;
|
||||
typedef struct {
|
||||
srslte_cell_t cell;
|
||||
uint32_t earfcn;
|
||||
} phy_cell_t;
|
||||
|
||||
/* Cell search and selection procedures */
|
||||
virtual cell_search_ret_t cell_search(phy_cell_t *cell) = 0;
|
||||
virtual bool cell_select(phy_cell_t *cell = NULL) = 0;
|
||||
virtual bool cell_is_camping() = 0;
|
||||
|
||||
/* Configure UL using parameters written with set_param() */
|
||||
virtual void configure_ul_params(bool pregen_disabled = false) = 0;
|
||||
|
|
|
@ -74,6 +74,7 @@ typedef struct {
|
|||
float snr_vector[12000];
|
||||
float pilot_power[12000];
|
||||
#endif
|
||||
bool smooth_filter_auto;
|
||||
uint32_t smooth_filter_len;
|
||||
float smooth_filter[SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN];
|
||||
|
||||
|
@ -112,10 +113,10 @@ SRSLTE_API void srslte_chest_dl_free(srslte_chest_dl_t *q);
|
|||
|
||||
SRSLTE_API int srslte_chest_dl_set_mbsfn_area_id(srslte_chest_dl_t *q,
|
||||
uint16_t mbsfn_area_id);
|
||||
|
||||
SRSLTE_API int srslte_chest_dl_set_cell(srslte_chest_dl_t *q,
|
||||
srslte_cell_t cell);
|
||||
|
||||
|
||||
SRSLTE_API void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q,
|
||||
float *filter,
|
||||
uint32_t filter_len);
|
||||
|
@ -123,6 +124,13 @@ SRSLTE_API void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q,
|
|||
SRSLTE_API void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q,
|
||||
float w);
|
||||
|
||||
SRSLTE_API void srslte_chest_dl_set_smooth_filter_gauss(srslte_chest_dl_t* q,
|
||||
uint32_t order,
|
||||
float std_dev);
|
||||
|
||||
SRSLTE_API void srslte_chest_dl_set_smooth_filter_auto(srslte_chest_dl_t* q,
|
||||
bool enable);
|
||||
|
||||
SRSLTE_API void srslte_chest_dl_set_noise_alg(srslte_chest_dl_t *q,
|
||||
srslte_chest_dl_noise_alg_t noise_estimation_alg);
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ SRSLTE_API int srslte_predecoding_single(cf_t *y,
|
|||
SRSLTE_API int srslte_predecoding_single_multi(cf_t *y[SRSLTE_MAX_PORTS],
|
||||
cf_t *h[SRSLTE_MAX_PORTS],
|
||||
cf_t *x,
|
||||
float *csi,
|
||||
float *csi[SRSLTE_MAX_CODEWORDS],
|
||||
int nof_rxant,
|
||||
int nof_symbols,
|
||||
float scaling,
|
||||
|
@ -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],
|
||||
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_ports,
|
||||
int nof_symbols,
|
||||
|
@ -113,7 +114,7 @@ SRSLTE_API void srslte_predecoding_set_mimo_decoder (srslte_mimo_decoder_t _mimo
|
|||
SRSLTE_API int srslte_predecoding_type(cf_t *y[SRSLTE_MAX_PORTS],
|
||||
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
|
||||
cf_t *x[SRSLTE_MAX_LAYERS],
|
||||
float *csi,
|
||||
float *csi[SRSLTE_MAX_CODEWORDS],
|
||||
int nof_rxant,
|
||||
int nof_ports,
|
||||
int nof_layers,
|
||||
|
|
|
@ -64,7 +64,7 @@ typedef struct SRSLTE_API {
|
|||
uint8_t *parity_bits;
|
||||
void *e;
|
||||
uint8_t *temp_g_bits;
|
||||
uint16_t *ul_interleaver;
|
||||
uint32_t *ul_interleaver;
|
||||
srslte_uci_bit_t ack_ri_bits[12*288];
|
||||
uint32_t nof_ri_ack_bits;
|
||||
|
||||
|
|
|
@ -70,6 +70,17 @@ SRSLTE_API void srslte_bit_copy(uint8_t *dst,
|
|||
uint32_t src_offset,
|
||||
uint32_t nof_bits);
|
||||
|
||||
SRSLTE_API void srslte_bit_interleave_i(uint8_t *input,
|
||||
uint8_t *output,
|
||||
uint32_t *interleaver,
|
||||
uint32_t nof_bits);
|
||||
|
||||
SRSLTE_API void srslte_bit_interleave_i_w_offset(uint8_t *input,
|
||||
uint8_t *output,
|
||||
uint32_t *interleaver,
|
||||
uint32_t nof_bits,
|
||||
uint32_t w_offset);
|
||||
|
||||
SRSLTE_API void srslte_bit_interleave_w_offset(uint8_t *input,
|
||||
uint8_t *output,
|
||||
uint16_t *interleaver,
|
||||
|
|
|
@ -53,12 +53,17 @@ SRSLTE_API void srslte_mat_2x2_mmse_gen(cf_t y0, cf_t y1,
|
|||
float noise_estimate,
|
||||
float norm);
|
||||
|
||||
SRSLTE_API void srslte_mat_2x2_mmse_csi_gen(cf_t y0, cf_t y1,
|
||||
cf_t h00, cf_t h01, cf_t h10, cf_t h11,
|
||||
cf_t *x0, cf_t *x1, float *csi0, float *csi1,
|
||||
float noise_estimate,
|
||||
float norm);
|
||||
|
||||
SRSLTE_API float srslte_mat_2x2_cn(cf_t h00,
|
||||
cf_t h01,
|
||||
cf_t h10,
|
||||
cf_t h11);
|
||||
|
||||
|
||||
#ifdef LV_HAVE_SSE
|
||||
|
||||
/* SSE implementation for complex reciprocal */
|
||||
|
@ -103,4 +108,114 @@ SRSLTE_API void srslte_mat_2x2_mmse_avx(__m256 y0, __m256 y1,
|
|||
|
||||
#endif /* LV_HAVE_AVX */
|
||||
|
||||
#endif // SRSLTE_MAT_H
|
||||
#if SRSLTE_SIMD_CF_SIZE != 0
|
||||
|
||||
/* Generic SIMD implementation for 2x2 determinant */
|
||||
static inline simd_cf_t srslte_mat_2x2_det_simd(simd_cf_t a00, simd_cf_t a01, simd_cf_t a10, simd_cf_t a11) {
|
||||
return srslte_simd_cf_sub(srslte_simd_cf_prod(a00, a11), srslte_simd_cf_prod(a01, a10));
|
||||
}
|
||||
|
||||
/* Generic SIMD implementation for Zero Forcing (ZF) solver */
|
||||
static inline void srslte_mat_2x2_zf_csi_simd(simd_cf_t y0,
|
||||
simd_cf_t y1,
|
||||
simd_cf_t h00,
|
||||
simd_cf_t h01,
|
||||
simd_cf_t h10,
|
||||
simd_cf_t h11,
|
||||
simd_cf_t *x0,
|
||||
simd_cf_t *x1,
|
||||
simd_f_t *csi0,
|
||||
simd_f_t *csi1,
|
||||
float norm) {
|
||||
simd_cf_t det = srslte_mat_2x2_det_simd(h00, h01, h10, h11);
|
||||
simd_cf_t detrec = srslte_simd_cf_mul(srslte_simd_cf_rcp(det), srslte_simd_f_set1(norm));
|
||||
|
||||
*x0 = srslte_simd_cf_prod(srslte_simd_cf_sub(srslte_simd_cf_prod(h11, y0), srslte_simd_cf_prod(h01, y1)), detrec);
|
||||
*x1 = srslte_simd_cf_prod(srslte_simd_cf_sub(srslte_simd_cf_prod(h00, y1), srslte_simd_cf_prod(h10, y0)), detrec);
|
||||
|
||||
*csi0 = srslte_simd_f_set1(1.0f);
|
||||
*csi1 = srslte_simd_f_set1(1.0f);
|
||||
}
|
||||
|
||||
static inline void srslte_mat_2x2_zf_simd(simd_cf_t y0,
|
||||
simd_cf_t y1,
|
||||
simd_cf_t h00,
|
||||
simd_cf_t h01,
|
||||
simd_cf_t h10,
|
||||
simd_cf_t h11,
|
||||
simd_cf_t *x0,
|
||||
simd_cf_t *x1,
|
||||
float norm) {
|
||||
simd_f_t csi1, csi2;
|
||||
srslte_mat_2x2_zf_csi_simd(y0, y1, h00, h01, h10, h11, x0, x1, &csi1, &csi2, norm);
|
||||
}
|
||||
|
||||
/* Generic SIMD implementation for Minimum Mean Squared Error (MMSE) solver */
|
||||
static inline void srslte_mat_2x2_mmse_csi_simd(simd_cf_t y0,
|
||||
simd_cf_t y1,
|
||||
simd_cf_t h00,
|
||||
simd_cf_t h01,
|
||||
simd_cf_t h10,
|
||||
simd_cf_t h11,
|
||||
simd_cf_t *x0,
|
||||
simd_cf_t *x1,
|
||||
simd_f_t *csi0,
|
||||
simd_f_t *csi1,
|
||||
float noise_estimate,
|
||||
float norm) {
|
||||
simd_cf_t _noise_estimate;
|
||||
simd_f_t _norm = srslte_simd_f_set1(norm);
|
||||
|
||||
_noise_estimate.re = srslte_simd_f_set1(noise_estimate);
|
||||
_noise_estimate.im = srslte_simd_f_zero();
|
||||
|
||||
/* 1. A = H' x H + No*/
|
||||
simd_cf_t a00 =
|
||||
srslte_simd_cf_add(srslte_simd_cf_add(srslte_simd_cf_conjprod(h00, h00), srslte_simd_cf_conjprod(h10, h10)),
|
||||
_noise_estimate);
|
||||
simd_cf_t a01 = srslte_simd_cf_add(srslte_simd_cf_conjprod(h01, h00), srslte_simd_cf_conjprod(h11, h10));
|
||||
simd_cf_t a10 = srslte_simd_cf_add(srslte_simd_cf_conjprod(h00, h01), srslte_simd_cf_conjprod(h10, h11));
|
||||
simd_cf_t a11 =
|
||||
srslte_simd_cf_add(srslte_simd_cf_add(srslte_simd_cf_conjprod(h01, h01), srslte_simd_cf_conjprod(h11, h11)),
|
||||
_noise_estimate);
|
||||
simd_cf_t a_det_rcp = srslte_simd_cf_rcp(srslte_mat_2x2_det_simd(a00, a01, a10, a11));
|
||||
|
||||
/* 2. B = inv(H' x H + No) = inv(A) */
|
||||
simd_cf_t _norm2 = srslte_simd_cf_mul(a_det_rcp, _norm);
|
||||
simd_cf_t b00 = srslte_simd_cf_prod(a11, _norm2);
|
||||
simd_cf_t b01 = srslte_simd_cf_prod(srslte_simd_cf_neg(a01), _norm2);
|
||||
simd_cf_t b10 = srslte_simd_cf_prod(srslte_simd_cf_neg(a10), _norm2);
|
||||
simd_cf_t b11 = srslte_simd_cf_prod(a00, _norm2);
|
||||
|
||||
|
||||
/* 3. W = inv(H' x H + No) x H' = B x H' */
|
||||
simd_cf_t w00 = srslte_simd_cf_add(srslte_simd_cf_conjprod(b00, h00), srslte_simd_cf_conjprod(b01, h01));
|
||||
simd_cf_t w01 = srslte_simd_cf_add(srslte_simd_cf_conjprod(b00, h10), srslte_simd_cf_conjprod(b01, h11));
|
||||
simd_cf_t w10 = srslte_simd_cf_add(srslte_simd_cf_conjprod(b10, h00), srslte_simd_cf_conjprod(b11, h01));
|
||||
simd_cf_t w11 = srslte_simd_cf_add(srslte_simd_cf_conjprod(b10, h10), srslte_simd_cf_conjprod(b11, h11));
|
||||
|
||||
/* 4. X = W x Y */
|
||||
*x0 = srslte_simd_cf_add(srslte_simd_cf_prod(y0, w00), srslte_simd_cf_prod(y1, w01));
|
||||
*x1 = srslte_simd_cf_add(srslte_simd_cf_prod(y0, w10), srslte_simd_cf_prod(y1, w11));
|
||||
|
||||
/* 5. Extract CSI */
|
||||
*csi0 = srslte_simd_f_rcp(srslte_simd_cf_re(b00));
|
||||
*csi1 = srslte_simd_f_rcp(srslte_simd_cf_re(b11));
|
||||
}
|
||||
|
||||
static inline void srslte_mat_2x2_mmse_simd(simd_cf_t y0,
|
||||
simd_cf_t y1,
|
||||
simd_cf_t h00,
|
||||
simd_cf_t h01,
|
||||
simd_cf_t h10,
|
||||
simd_cf_t h11,
|
||||
simd_cf_t *x0,
|
||||
simd_cf_t *x1,
|
||||
float noise_estimate,
|
||||
float norm) {
|
||||
simd_f_t csi0, csi1;
|
||||
srslte_mat_2x2_mmse_csi_simd(y0, y1, h00, h01, h10, h11, x0, x1, &csi0, &csi1, noise_estimate, norm);
|
||||
}
|
||||
|
||||
#endif /* SRSLTE_SIMD_CF_SIZE != 0 */
|
||||
#endif /* SRSLTE_MAT_H */
|
||||
|
|
|
@ -197,7 +197,7 @@ static inline simd_f_t srslte_simd_f_loadu(const float *ptr) {
|
|||
#ifdef LV_HAVE_AVX512
|
||||
return _mm512_loadu_ps(ptr);
|
||||
#else /* LV_HAVE_AVX512 */
|
||||
#ifdef LV_HAVE_AVX2
|
||||
#ifdef LV_HAVE_AVX2
|
||||
return _mm256_loadu_ps(ptr);
|
||||
#else /* LV_HAVE_AVX2 */
|
||||
#ifdef LV_HAVE_SSE
|
||||
|
@ -233,7 +233,7 @@ static inline void srslte_simd_f_storeu(float *ptr, simd_f_t simdreg) {
|
|||
#ifdef LV_HAVE_AVX512
|
||||
_mm512_storeu_ps(ptr, simdreg);
|
||||
#else /* LV_HAVE_AVX512 */
|
||||
#ifdef LV_HAVE_AVX2
|
||||
#ifdef LV_HAVE_AVX2
|
||||
_mm256_storeu_ps(ptr, simdreg);
|
||||
#else /* LV_HAVE_AVX2 */
|
||||
#ifdef LV_HAVE_SSE
|
||||
|
@ -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
|
||||
return _mm256_add_ps(a, b);
|
||||
#else /* LV_HAVE_AVX2 */
|
||||
#ifdef LV_HAVE_SSE
|
||||
#ifdef LV_HAVE_SSE
|
||||
return _mm_add_ps(a, b);
|
||||
#else /* LV_HAVE_SSE */
|
||||
#ifdef HAVE_NEON
|
||||
|
@ -376,9 +376,9 @@ static inline simd_f_t srslte_simd_f_zero (void) {
|
|||
return _mm512_setzero_ps();
|
||||
#else /* LV_HAVE_AVX512 */
|
||||
#ifdef LV_HAVE_AVX2
|
||||
return _mm256_setzero_ps();
|
||||
return _mm256_setzero_ps();
|
||||
#else /* LV_HAVE_AVX2 */
|
||||
#ifdef LV_HAVE_SSE
|
||||
#ifdef LV_HAVE_SSE
|
||||
return _mm_setzero_ps();
|
||||
#else /* LV_HAVE_SSE */
|
||||
#ifdef HAVE_NEON
|
||||
|
@ -401,7 +401,7 @@ static inline simd_f_t srslte_simd_f_swap(simd_f_t a) {
|
|||
#else /* LV_HAVE_SSE */
|
||||
#ifdef HAVE_NEON
|
||||
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_AVX2 */
|
||||
#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
|
||||
return _mm512_sqrt_ps(a);
|
||||
#else /* LV_HAVE_AVX512 */
|
||||
#ifdef LV_HAVE_AVX2
|
||||
#ifdef LV_HAVE_AVX2
|
||||
return _mm256_sqrt_ps(a);
|
||||
#else /* LV_HAVE_AVX2 */
|
||||
#ifdef LV_HAVE_SSE
|
||||
|
@ -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 */
|
||||
uint32x4_t mask = vceqq_f32(a, zeros); /* Zero vector mask */
|
||||
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_AVX2 */
|
||||
#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
|
||||
|
||||
#ifdef HAVE_NEON
|
||||
typedef float32x4x2_t simd_cf_t;
|
||||
typedef float32x4x2_t simd_cf_t;
|
||||
#else
|
||||
typedef struct {
|
||||
simd_f_t re;
|
||||
simd_f_t im;
|
||||
|
||||
} simd_cf_t;
|
||||
#endif
|
||||
|
||||
|
@ -667,8 +702,8 @@ static inline void srslte_simd_cf_store(float *re, float *im, simd_cf_t simdreg)
|
|||
_mm512_store_ps(im, simdreg.im);
|
||||
#else /* LV_HAVE_AVX512 */
|
||||
#ifdef LV_HAVE_AVX2
|
||||
_mm256_store_ps((float *) re, simdreg.re);
|
||||
_mm256_store_ps((float *) im, simdreg.im);
|
||||
_mm256_store_ps(re, simdreg.re);
|
||||
_mm256_store_ps(im, simdreg.im);
|
||||
#else /* LV_HAVE_AVX512 */
|
||||
#ifdef LV_HAVE_SSE
|
||||
_mm_store_ps((float *) re, simdreg.re);
|
||||
|
@ -689,8 +724,8 @@ static inline void srslte_simd_cf_storeu(float *re, float *im, simd_cf_t simdreg
|
|||
_mm512_storeu_ps(im, simdreg.im);
|
||||
#else /* LV_HAVE_AVX512 */
|
||||
#ifdef LV_HAVE_AVX2
|
||||
_mm256_storeu_ps((float *) re, simdreg.re);
|
||||
_mm256_storeu_ps((float *) im, simdreg.im);
|
||||
_mm256_storeu_ps(re, simdreg.re);
|
||||
_mm256_storeu_ps(im, simdreg.im);
|
||||
#else /* LV_HAVE_AVX512 */
|
||||
#ifdef LV_HAVE_SSE
|
||||
_mm_storeu_ps((float *) re, simdreg.re);
|
||||
|
@ -833,8 +868,32 @@ static inline simd_cf_t srslte_simd_cf_add (simd_cf_t a, simd_cf_t b) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline simd_cf_t srslte_simd_cf_sub (simd_cf_t a, simd_cf_t b) {
|
||||
simd_cf_t ret;
|
||||
#ifdef LV_HAVE_AVX512
|
||||
ret.re = _mm512_sub_ps(a.re, b.re);
|
||||
ret.im = _mm512_sub_ps(a.im, b.im);
|
||||
#else /* LV_HAVE_AVX512 */
|
||||
#ifdef LV_HAVE_AVX2
|
||||
ret.re = _mm256_sub_ps(a.re, b.re);
|
||||
ret.im = _mm256_sub_ps(a.im, b.im);
|
||||
#else /* LV_HAVE_AVX2 */
|
||||
#ifdef LV_HAVE_SSE
|
||||
ret.re = _mm_sub_ps(a.re, b.re);
|
||||
ret.im = _mm_sub_ps(a.im, b.im);
|
||||
#else /* LV_HAVE_SSE */
|
||||
#ifdef HAVE_NEON
|
||||
ret.val[0] = vsubq_f32(a.val[0],b.val[0]);
|
||||
ret.val[1] = vsubq_f32(a.val[1],b.val[1]);
|
||||
#endif /* HAVE_NEON */
|
||||
#endif /* LV_HAVE_SSE */
|
||||
#endif /* LV_HAVE_AVX2 */
|
||||
#endif /* LV_HAVE_AVX512 */
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline simd_cf_t srslte_simd_cf_mul (simd_cf_t a, simd_f_t b) {
|
||||
simd_cf_t ret;
|
||||
simd_cf_t ret;
|
||||
#ifdef LV_HAVE_AVX512
|
||||
ret.re = _mm512_mul_ps(a.re, b);
|
||||
ret.im = _mm512_mul_ps(a.im, b);
|
||||
|
@ -855,7 +914,7 @@ static inline simd_cf_t srslte_simd_cf_mul (simd_cf_t a, simd_f_t b) {
|
|||
#endif /* LV_HAVE_SSE */
|
||||
#endif /* LV_HAVE_AVX2 */
|
||||
#endif /* LV_HAVE_AVX512 */
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline simd_cf_t srslte_simd_cf_rcp (simd_cf_t a) {
|
||||
|
@ -902,6 +961,59 @@ static inline simd_cf_t srslte_simd_cf_rcp (simd_cf_t a) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline simd_cf_t srslte_simd_cf_neg (simd_cf_t a) {
|
||||
simd_cf_t ret;
|
||||
#if LV_HAVE_NEON
|
||||
ret.val[0] = srslte_simd_f_neg(a.val[0]);
|
||||
ret.val[1] = srslte_simd_f_neg(a.val[1]);
|
||||
#else /* LV_HAVE_NEON */
|
||||
ret.re = srslte_simd_f_neg(a.re);
|
||||
ret.im = srslte_simd_f_neg(a.im);
|
||||
#endif /* LV_HAVE_NEON */
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline simd_cf_t srslte_simd_cf_neg_mask (simd_cf_t a, simd_f_t mask) {
|
||||
simd_cf_t ret;
|
||||
#ifndef LV_HAVE_AVX512
|
||||
#ifdef LV_HAVE_AVX2
|
||||
mask = _mm256_permutevar8x32_ps(mask, _mm256_setr_epi32(0,4,1,5,2,6,3,7));
|
||||
#endif /* LV_HAVE_AVX2 */
|
||||
#endif /* LV_HAVE_AVX512 */
|
||||
#if LV_HAVE_NEON
|
||||
ret.val[0] = srslte_simd_f_neg_mask(a.val[0], mask);
|
||||
ret.val[1] = srslte_simd_f_neg_mask(a.val[1], mask);
|
||||
#else /* LV_HAVE_NEON */
|
||||
ret.re = srslte_simd_f_neg_mask(a.re, mask);
|
||||
ret.im = srslte_simd_f_neg_mask(a.im, mask);
|
||||
#endif /* LV_HAVE_NEON */
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline simd_cf_t srslte_simd_cf_conj (simd_cf_t a) {
|
||||
simd_cf_t ret;
|
||||
#if LV_HAVE_NEON
|
||||
ret.val[0] = a.val[0];
|
||||
ret.val[1] = srslte_simd_f_neg(a.val[1]);
|
||||
#else /* LV_HAVE_NEON */
|
||||
ret.re = a.re;
|
||||
ret.im = srslte_simd_f_neg(a.im);
|
||||
#endif /* LV_HAVE_NEON */
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline simd_cf_t srslte_simd_cf_mulj (simd_cf_t a) {
|
||||
simd_cf_t ret;
|
||||
#if LV_HAVE_NEON
|
||||
ret.val[0] = srslte_simd_f_neg(a.val[1]);
|
||||
ret.val[1] = a.val[0];
|
||||
#else /* LV_HAVE_NEON */
|
||||
ret.re = srslte_simd_f_neg(a.im);
|
||||
ret.im = a.re;
|
||||
#endif /* LV_HAVE_NEON */
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline simd_cf_t srslte_simd_cf_zero (void) {
|
||||
simd_cf_t ret;
|
||||
#ifdef LV_HAVE_AVX512
|
||||
|
@ -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* c_ptr = (int*) &ret;
|
||||
for(int i = 0;i<4;i++)
|
||||
{
|
||||
{
|
||||
if(sel[i] == -1){
|
||||
c_ptr[i] = b_ptr[i];
|
||||
}else{
|
||||
|
@ -1115,7 +1227,7 @@ static inline simd_s_t srslte_simd_s_loadu(const int16_t *ptr) {
|
|||
#ifdef LV_HAVE_AVX512
|
||||
return _mm512_loadu_si512(ptr);
|
||||
#else /* LV_HAVE_AVX512 */
|
||||
#ifdef LV_HAVE_AVX2
|
||||
#ifdef LV_HAVE_AVX2
|
||||
return _mm256_loadu_si256((__m256i*) ptr);
|
||||
#else /* LV_HAVE_AVX2 */
|
||||
#ifdef LV_HAVE_SSE
|
||||
|
|
|
@ -99,6 +99,7 @@ SRSLTE_API void srslte_vec_convert_fi(const float *x, const float scale, int16_t
|
|||
SRSLTE_API void srslte_vec_convert_if(const int16_t *x, const float scale, float *z, const uint32_t len);
|
||||
|
||||
SRSLTE_API void srslte_vec_lut_sss(const short *x, const unsigned short *lut, short *y, const uint32_t len);
|
||||
SRSLTE_API void srslte_vec_lut_sis(const short *x, const unsigned int *lut, short *y, const uint32_t len);
|
||||
|
||||
/* vector product (element-wise) */
|
||||
SRSLTE_API void srslte_vec_prod_ccc(const cf_t *x, const cf_t *y, cf_t *z, const uint32_t len);
|
||||
|
|
|
@ -34,150 +34,152 @@
|
|||
#define SRSLTE_RADIO_H
|
||||
|
||||
typedef struct {
|
||||
float tx_corr_dc_gain;
|
||||
float tx_corr_dc_phase;
|
||||
float tx_corr_iq_i;
|
||||
float tx_corr_iq_q;
|
||||
float rx_corr_dc_gain;
|
||||
float rx_corr_dc_phase;
|
||||
float rx_corr_iq_i;
|
||||
float rx_corr_iq_q;
|
||||
}rf_cal_t;
|
||||
|
||||
float tx_corr_dc_gain;
|
||||
float tx_corr_dc_phase;
|
||||
float tx_corr_iq_i;
|
||||
float tx_corr_iq_q;
|
||||
float rx_corr_dc_gain;
|
||||
float rx_corr_dc_phase;
|
||||
float rx_corr_iq_i;
|
||||
float rx_corr_iq_q;
|
||||
} rf_cal_t;
|
||||
|
||||
namespace srslte {
|
||||
|
||||
|
||||
/* Interface to the RF frontend.
|
||||
*/
|
||||
class radio
|
||||
{
|
||||
public:
|
||||
radio() : tr_local_time(1024*10), tr_usrp_time(1024*10), tr_tx_time(1024*10), tr_is_eob(1024*10) {
|
||||
bzero(&rf_device, sizeof(srslte_rf_t));
|
||||
bzero(&end_of_burst_time, sizeof(srslte_timestamp_t));
|
||||
bzero(zeros, burst_preamble_max_samples*sizeof(cf_t));
|
||||
|
||||
burst_preamble_sec = 0;
|
||||
is_start_of_burst = false;
|
||||
burst_preamble_samples = 0;
|
||||
burst_preamble_time_rounded = 0;
|
||||
|
||||
cur_tx_srate = 0;
|
||||
tx_adv_sec = 0;
|
||||
tx_adv_nsamples = 0;
|
||||
tx_adv_auto = false;
|
||||
tx_adv_negative = false;
|
||||
tx_freq = 0;
|
||||
rx_freq = 0;
|
||||
trace_enabled = false;
|
||||
tti = 0;
|
||||
agc_enabled = false;
|
||||
radio_is_streaming = false;
|
||||
is_initialized = false;
|
||||
};
|
||||
|
||||
bool init(char *args = NULL, char *devname = NULL, uint32_t nof_channels = 1);
|
||||
void stop();
|
||||
void reset();
|
||||
bool start_agc(bool tx_gain_same_rx);
|
||||
|
||||
void set_burst_preamble(double preamble_us);
|
||||
void set_tx_adv(int nsamples);
|
||||
void set_tx_adv_neg(bool tx_adv_is_neg);
|
||||
|
||||
void set_manual_calibration(rf_cal_t *calibration);
|
||||
|
||||
void get_time(srslte_timestamp_t *now);
|
||||
bool tx_single(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
|
||||
bool tx(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time);
|
||||
void tx_end();
|
||||
bool rx_now(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t *rxd_time);
|
||||
bool rx_at(void *buffer, uint32_t nof_samples, srslte_timestamp_t rx_time);
|
||||
class radio {
|
||||
public:
|
||||
radio() : tr_local_time(1024 * 10), tr_usrp_time(1024 * 10), tr_tx_time(1024 * 10), tr_is_eob(1024 * 10) {
|
||||
bzero(&rf_device, sizeof(srslte_rf_t));
|
||||
bzero(&end_of_burst_time, sizeof(srslte_timestamp_t));
|
||||
bzero(zeros, burst_preamble_max_samples * sizeof(cf_t));
|
||||
|
||||
void set_tx_gain(float gain);
|
||||
void set_rx_gain(float gain);
|
||||
void set_tx_rx_gain_offset(float offset);
|
||||
double set_rx_gain_th(float gain);
|
||||
burst_preamble_sec = 0;
|
||||
is_start_of_burst = false;
|
||||
burst_preamble_samples = 0;
|
||||
burst_preamble_time_rounded = 0;
|
||||
|
||||
void set_freq_offset(double freq);
|
||||
void set_tx_freq(double freq);
|
||||
void set_rx_freq(double freq);
|
||||
cur_tx_srate = 0;
|
||||
tx_adv_sec = 0;
|
||||
tx_adv_nsamples = 0;
|
||||
tx_adv_auto = false;
|
||||
tx_adv_negative = false;
|
||||
tx_freq = 0;
|
||||
rx_freq = 0;
|
||||
trace_enabled = false;
|
||||
tti = 0;
|
||||
agc_enabled = false;
|
||||
radio_is_streaming = false;
|
||||
is_initialized = false;
|
||||
continuous_tx = false;
|
||||
};
|
||||
|
||||
double get_freq_offset();
|
||||
double get_tx_freq();
|
||||
double get_rx_freq();
|
||||
bool init(char *args = NULL, char *devname = NULL, uint32_t nof_channels = 1);
|
||||
void stop();
|
||||
void reset();
|
||||
bool start_agc(bool tx_gain_same_rx);
|
||||
|
||||
void set_master_clock_rate(double rate);
|
||||
void set_tx_srate(double srate);
|
||||
void set_rx_srate(double srate);
|
||||
void set_burst_preamble(double preamble_us);
|
||||
void set_tx_adv(int nsamples);
|
||||
void set_tx_adv_neg(bool tx_adv_is_neg);
|
||||
|
||||
float get_tx_gain();
|
||||
float get_rx_gain();
|
||||
|
||||
float get_max_tx_power();
|
||||
float set_tx_power(float power);
|
||||
float get_rssi();
|
||||
bool has_rssi();
|
||||
|
||||
void start_trace();
|
||||
void write_trace(std::string filename);
|
||||
void set_manual_calibration(rf_cal_t *calibration);
|
||||
|
||||
void set_tti(uint32_t tti);
|
||||
bool is_continuous_tx();
|
||||
void set_continuous_tx(bool enable);
|
||||
|
||||
bool is_first_of_burst();
|
||||
void get_time(srslte_timestamp_t *now);
|
||||
bool tx_single(void *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time);
|
||||
bool tx(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t tx_time);
|
||||
void tx_end();
|
||||
bool rx_now(void *buffer[SRSLTE_MAX_PORTS], uint32_t nof_samples, srslte_timestamp_t *rxd_time);
|
||||
bool rx_at(void *buffer, uint32_t nof_samples, srslte_timestamp_t rx_time);
|
||||
|
||||
bool is_init();
|
||||
void set_tx_gain(float gain);
|
||||
void set_rx_gain(float gain);
|
||||
void set_tx_rx_gain_offset(float offset);
|
||||
double set_rx_gain_th(float gain);
|
||||
|
||||
void register_error_handler(srslte_rf_error_handler_t h);
|
||||
|
||||
protected:
|
||||
|
||||
void save_trace(uint32_t is_eob, srslte_timestamp_t *usrp_time);
|
||||
|
||||
srslte_rf_t rf_device;
|
||||
|
||||
|
||||
const static uint32_t burst_preamble_max_samples = 30720000; // 30.72 MHz is maximum frequency
|
||||
double burst_preamble_sec;// Start of burst preamble time (off->on RF transition time)
|
||||
srslte_timestamp_t end_of_burst_time;
|
||||
bool is_start_of_burst;
|
||||
uint32_t burst_preamble_samples;
|
||||
double burst_preamble_time_rounded; // preamble time rounded to sample time
|
||||
cf_t zeros[burst_preamble_max_samples];
|
||||
double cur_tx_srate;
|
||||
void set_freq_offset(double freq);
|
||||
void set_tx_freq(double freq);
|
||||
void set_rx_freq(double freq);
|
||||
|
||||
double tx_adv_sec; // Transmission time advance to compensate for antenna->timestamp delay
|
||||
int tx_adv_nsamples; // Transmision time advance in number of samples
|
||||
|
||||
// Define default values for known radios
|
||||
bool tx_adv_auto;
|
||||
bool tx_adv_negative;
|
||||
const static double uhd_default_burst_preamble_sec = 600*1e-6;
|
||||
const static double uhd_default_tx_adv_samples = 98;
|
||||
const static double uhd_default_tx_adv_offset_sec = 4*1e-6;
|
||||
|
||||
const static double blade_default_burst_preamble_sec = 0.0;
|
||||
const static double blade_default_tx_adv_samples = 27;
|
||||
const static double blade_default_tx_adv_offset_sec = 1e-6;
|
||||
double get_freq_offset();
|
||||
double get_tx_freq();
|
||||
double get_rx_freq();
|
||||
|
||||
double tx_freq, rx_freq, freq_offset;
|
||||
|
||||
trace<uint32_t> tr_local_time;
|
||||
trace<uint32_t> tr_usrp_time;
|
||||
trace<uint32_t> tr_tx_time;
|
||||
trace<uint32_t> tr_is_eob;
|
||||
bool trace_enabled;
|
||||
uint32_t tti;
|
||||
bool agc_enabled;
|
||||
void set_master_clock_rate(double rate);
|
||||
void set_tx_srate(double srate);
|
||||
void set_rx_srate(double srate);
|
||||
|
||||
bool is_initialized = true;;
|
||||
bool radio_is_streaming;
|
||||
float get_tx_gain();
|
||||
float get_rx_gain();
|
||||
|
||||
uint32_t saved_nof_channels;
|
||||
char saved_args[128];
|
||||
char saved_devname[128];
|
||||
float get_max_tx_power();
|
||||
float set_tx_power(float power);
|
||||
float get_rssi();
|
||||
bool has_rssi();
|
||||
|
||||
};
|
||||
void start_trace();
|
||||
void write_trace(std::string filename);
|
||||
|
||||
void set_tti(uint32_t tti);
|
||||
|
||||
bool is_first_of_burst();
|
||||
|
||||
bool is_init();
|
||||
|
||||
void register_error_handler(srslte_rf_error_handler_t h);
|
||||
|
||||
protected:
|
||||
|
||||
void save_trace(uint32_t is_eob, srslte_timestamp_t *usrp_time);
|
||||
|
||||
srslte_rf_t rf_device;
|
||||
|
||||
const static uint32_t burst_preamble_max_samples = 30720000; // 30.72 MHz is maximum frequency
|
||||
double burst_preamble_sec;// Start of burst preamble time (off->on RF transition time)
|
||||
srslte_timestamp_t end_of_burst_time;
|
||||
bool is_start_of_burst;
|
||||
uint32_t burst_preamble_samples;
|
||||
double burst_preamble_time_rounded; // preamble time rounded to sample time
|
||||
cf_t zeros[burst_preamble_max_samples];
|
||||
double cur_tx_srate;
|
||||
|
||||
double tx_adv_sec; // Transmission time advance to compensate for antenna->timestamp delay
|
||||
int tx_adv_nsamples; // Transmision time advance in number of samples
|
||||
|
||||
// Define default values for known radios
|
||||
bool tx_adv_auto;
|
||||
bool tx_adv_negative;
|
||||
const static double uhd_default_burst_preamble_sec = 600 * 1e-6;
|
||||
const static double uhd_default_tx_adv_samples = 98;
|
||||
const static double uhd_default_tx_adv_offset_sec = 4 * 1e-6;
|
||||
|
||||
const static double blade_default_burst_preamble_sec = 0.0;
|
||||
const static double blade_default_tx_adv_samples = 27;
|
||||
const static double blade_default_tx_adv_offset_sec = 1e-6;
|
||||
|
||||
double tx_freq, rx_freq, freq_offset;
|
||||
|
||||
trace<uint32_t> tr_local_time;
|
||||
trace<uint32_t> tr_usrp_time;
|
||||
trace<uint32_t> tr_tx_time;
|
||||
trace<uint32_t> tr_is_eob;
|
||||
bool trace_enabled;
|
||||
uint32_t tti;
|
||||
bool agc_enabled;
|
||||
|
||||
bool continuous_tx;
|
||||
bool is_initialized;
|
||||
bool radio_is_streaming;
|
||||
|
||||
uint32_t saved_nof_channels;
|
||||
char saved_args[128];
|
||||
char saved_devname[128];
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif // SRSLTE_RADIO_H
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include "srslte/common/common.h"
|
||||
#include "srslte/interfaces/ue_interfaces.h"
|
||||
#include "srslte/common/security.h"
|
||||
#include "srslte/common/msg_queue.h"
|
||||
#include "srslte/common/threads.h"
|
||||
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include "srslte/common/log.h"
|
||||
#include "srslte/common/common.h"
|
||||
#include "srslte/interfaces/ue_interfaces.h"
|
||||
#include "srslte/common/msg_queue.h"
|
||||
#include "srslte/upper/rlc_entity.h"
|
||||
#include "srslte/upper/rlc_metrics.h"
|
||||
#include "srslte/upper/rlc_common.h"
|
||||
|
|
|
@ -2225,14 +2225,14 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_network_name_ie(LIBLTE_MME_NETWORK_NAME_STRUCT
|
|||
uint32 i;
|
||||
uint32 bit_offset;
|
||||
uint32 byte_offset;
|
||||
const char *char_str = net_name->name.c_str();
|
||||
const char *char_str = net_name->name;
|
||||
|
||||
if(net_name != NULL &&
|
||||
ie_ptr != NULL)
|
||||
{
|
||||
bit_offset = 0;
|
||||
byte_offset = 2;
|
||||
for(i=0; i<net_name->name.size(); i++)
|
||||
for(i=0; i<strnlen(char_str, LIBLTE_STRING_LEN); i++)
|
||||
{
|
||||
if(char_str[i] == 0x0A ||
|
||||
char_str[i] == 0x0D ||
|
||||
|
@ -2319,6 +2319,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_network_name_ie(uint8
|
|||
uint32 N_bytes;
|
||||
uint8 spare_field;
|
||||
char tmp_char;
|
||||
uint32 str_cnt;
|
||||
|
||||
if(ie_ptr != NULL &&
|
||||
net_name != NULL)
|
||||
|
@ -2328,8 +2329,9 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_network_name_ie(uint8
|
|||
N_bytes = (*ie_ptr)[0];
|
||||
bit_offset = 0;
|
||||
byte_offset = 2;
|
||||
net_name->name = "";
|
||||
while(byte_offset < N_bytes)
|
||||
str_cnt = 0;
|
||||
|
||||
while(byte_offset < N_bytes && str_cnt < LIBLTE_STRING_LEN)
|
||||
{
|
||||
switch(bit_offset)
|
||||
{
|
||||
|
@ -2389,7 +2391,10 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_network_name_ie(uint8
|
|||
(tmp_char >= 0x61 &&
|
||||
tmp_char <= 0x7A))
|
||||
{
|
||||
net_name->name += tmp_char;
|
||||
if (str_cnt < LIBLTE_STRING_LEN) {
|
||||
net_name->name[str_cnt] = tmp_char;
|
||||
str_cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2412,10 +2417,18 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_network_name_ie(uint8
|
|||
(tmp_char >= 0x61 &&
|
||||
tmp_char <= 0x7A))
|
||||
{
|
||||
net_name->name += tmp_char;
|
||||
if (str_cnt < LIBLTE_STRING_LEN) {
|
||||
net_name->name[str_cnt] = tmp_char;
|
||||
str_cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (str_cnt < LIBLTE_STRING_LEN) {
|
||||
net_name->name[str_cnt] = '\0';
|
||||
str_cnt++;
|
||||
}
|
||||
|
||||
*ie_ptr += byte_offset + 1;
|
||||
|
||||
err = LIBLTE_SUCCESS;
|
||||
|
@ -3765,12 +3778,12 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_access_point_name_ie(LIBLTE_MME_ACCESS_POINT_N
|
|||
if(apn != NULL &&
|
||||
ie_ptr != NULL)
|
||||
{
|
||||
apn_str = apn->apn.c_str();
|
||||
(*ie_ptr)[0] = apn->apn.length()+1;
|
||||
apn_str = apn->apn;
|
||||
(*ie_ptr)[0] = strnlen(apn->apn, LIBLTE_STRING_LEN)+1;
|
||||
len_idx = 0;
|
||||
apn_idx = 0;
|
||||
label_len = 0;
|
||||
while(apn->apn.length() > apn_idx)
|
||||
while(strnlen(apn->apn, LIBLTE_STRING_LEN) > apn_idx)
|
||||
{
|
||||
(*ie_ptr)[1+apn_idx+1] = (uint8)apn_str[apn_idx];
|
||||
apn_idx++;
|
||||
|
@ -3785,7 +3798,7 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_access_point_name_ie(LIBLTE_MME_ACCESS_POINT_N
|
|||
}
|
||||
}
|
||||
(*ie_ptr)[1+len_idx] = label_len;
|
||||
*ie_ptr += apn->apn.length() + 2;
|
||||
*ie_ptr += strnlen(apn->apn, LIBLTE_STRING_LEN) + 2;
|
||||
|
||||
err = LIBLTE_SUCCESS;
|
||||
}
|
||||
|
@ -3799,26 +3812,31 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_access_point_name_ie(uint8
|
|||
uint32 i;
|
||||
uint32 ie_idx;
|
||||
uint32 label_len;
|
||||
uint32 str_cnt;
|
||||
|
||||
if(ie_ptr != NULL &&
|
||||
apn != NULL)
|
||||
{
|
||||
apn->apn.clear();
|
||||
ie_idx = 0;
|
||||
while(ie_idx < (*ie_ptr)[0])
|
||||
str_cnt = 0;
|
||||
while(ie_idx < (*ie_ptr)[0] && str_cnt < LIBLTE_STRING_LEN)
|
||||
{
|
||||
label_len = (*ie_ptr)[1+ie_idx];
|
||||
for(i=0; i<label_len; i++)
|
||||
for(i=0; i<label_len && str_cnt < LIBLTE_STRING_LEN; i++)
|
||||
{
|
||||
apn->apn += (char)((*ie_ptr)[1+ie_idx+i+1]);
|
||||
apn->apn[str_cnt] = (char)((*ie_ptr)[1+ie_idx+i+1]);
|
||||
str_cnt++;
|
||||
}
|
||||
ie_idx += label_len + 1;
|
||||
if(ie_idx < (*ie_ptr)[0])
|
||||
if(ie_idx < (*ie_ptr)[0] && str_cnt < LIBLTE_STRING_LEN)
|
||||
{
|
||||
apn->apn += '.';
|
||||
apn->apn[str_cnt] = '.';
|
||||
str_cnt++;
|
||||
}
|
||||
}
|
||||
apn->apn += "\0";
|
||||
if (str_cnt < LIBLTE_STRING_LEN) {
|
||||
apn->apn[str_cnt] = '\0';
|
||||
}
|
||||
*ie_ptr += (*ie_ptr)[0] + 1;
|
||||
|
||||
err = LIBLTE_SUCCESS;
|
||||
|
|
|
@ -380,7 +380,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_c_rnti_ie(uint8 **ie_ptr,
|
|||
|
||||
Document Reference: 36.331 v10.0.0 Section 6.3.6
|
||||
*********************************************************************/
|
||||
LIBLTE_ERROR_ENUM liblte_rrc_pack_dedicated_info_cdma2000_ie(LIBLTE_SIMPLE_BYTE_MSG_STRUCT *ded_info_cdma2000,
|
||||
LIBLTE_ERROR_ENUM liblte_rrc_pack_dedicated_info_cdma2000_ie(LIBLTE_BYTE_MSG_STRUCT *ded_info_cdma2000,
|
||||
uint8 **ie_ptr)
|
||||
{
|
||||
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
@ -412,7 +412,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_pack_dedicated_info_cdma2000_ie(LIBLTE_SIMPLE_BYTE_
|
|||
return(err);
|
||||
}
|
||||
LIBLTE_ERROR_ENUM liblte_rrc_unpack_dedicated_info_cdma2000_ie(uint8 **ie_ptr,
|
||||
LIBLTE_SIMPLE_BYTE_MSG_STRUCT *ded_info_cdma2000)
|
||||
LIBLTE_BYTE_MSG_STRUCT *ded_info_cdma2000)
|
||||
{
|
||||
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
uint32 i;
|
||||
|
@ -452,7 +452,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_unpack_dedicated_info_cdma2000_ie(uint8
|
|||
|
||||
Document Reference: 36.331 v10.0.0 Section 6.3.6
|
||||
*********************************************************************/
|
||||
LIBLTE_ERROR_ENUM liblte_rrc_pack_dedicated_info_nas_ie(LIBLTE_SIMPLE_BYTE_MSG_STRUCT *ded_info_nas,
|
||||
LIBLTE_ERROR_ENUM liblte_rrc_pack_dedicated_info_nas_ie(LIBLTE_BYTE_MSG_STRUCT *ded_info_nas,
|
||||
uint8 **ie_ptr)
|
||||
{
|
||||
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
|
@ -484,7 +484,7 @@ LIBLTE_ERROR_ENUM liblte_rrc_pack_dedicated_info_nas_ie(LIBLTE_SIMPLE_BYTE_MSG_S
|
|||
return(err);
|
||||
}
|
||||
LIBLTE_ERROR_ENUM liblte_rrc_unpack_dedicated_info_nas_ie(uint8 **ie_ptr,
|
||||
LIBLTE_SIMPLE_BYTE_MSG_STRUCT *ded_info_nas)
|
||||
LIBLTE_BYTE_MSG_STRUCT *ded_info_nas)
|
||||
{
|
||||
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
uint32 i;
|
||||
|
@ -2715,8 +2715,10 @@ LIBLTE_ERROR_ENUM liblte_rrc_pack_report_config_eutra_ie(LIBLTE_RRC_REPORT_CONFI
|
|||
liblte_value_2_bits(rep_cnfg_eutra->trigger_type, ie_ptr, 1);
|
||||
if(LIBLTE_RRC_TRIGGER_TYPE_EUTRA_EVENT == rep_cnfg_eutra->trigger_type)
|
||||
{
|
||||
// Event ID choice extension indicator
|
||||
liblte_value_2_bits(0, ie_ptr, 1); // Choice with extension - unlikely to be >63 choices
|
||||
|
||||
// Event ID
|
||||
// FIXME: Handle extension properly
|
||||
liblte_value_2_bits(rep_cnfg_eutra->event.event_id, ie_ptr, 3);
|
||||
if(LIBLTE_RRC_EVENT_ID_EUTRA_A1 == rep_cnfg_eutra->event.event_id)
|
||||
{
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -136,7 +136,7 @@ void log_filter::all_log(srslte::LOG_LEVEL_ENUM level,
|
|||
}
|
||||
|
||||
void log_filter::console(const char * message, ...) {
|
||||
char *args_msg;
|
||||
char *args_msg = NULL;
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
if(vasprintf(&args_msg, message, args) > 0)
|
||||
|
@ -147,7 +147,7 @@ void log_filter::console(const char * message, ...) {
|
|||
|
||||
void log_filter::error(const char * message, ...) {
|
||||
if (level >= LOG_LEVEL_ERROR) {
|
||||
char *args_msg;
|
||||
char *args_msg = NULL;
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
if(vasprintf(&args_msg, message, args) > 0)
|
||||
|
@ -158,7 +158,7 @@ void log_filter::error(const char * message, ...) {
|
|||
}
|
||||
void log_filter::warning(const char * message, ...) {
|
||||
if (level >= LOG_LEVEL_WARNING) {
|
||||
char *args_msg;
|
||||
char *args_msg = NULL;
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
if(vasprintf(&args_msg, message, args) > 0)
|
||||
|
@ -169,7 +169,7 @@ void log_filter::warning(const char * message, ...) {
|
|||
}
|
||||
void log_filter::info(const char * message, ...) {
|
||||
if (level >= LOG_LEVEL_INFO) {
|
||||
char *args_msg;
|
||||
char *args_msg = NULL;
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
if(vasprintf(&args_msg, message, args) > 0)
|
||||
|
@ -180,7 +180,7 @@ void log_filter::info(const char * message, ...) {
|
|||
}
|
||||
void log_filter::debug(const char * message, ...) {
|
||||
if (level >= LOG_LEVEL_DEBUG) {
|
||||
char *args_msg;
|
||||
char *args_msg = NULL;
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
if(vasprintf(&args_msg, message, args) > 0)
|
||||
|
@ -192,7 +192,7 @@ void log_filter::debug(const char * message, ...) {
|
|||
|
||||
void log_filter::error_hex(const uint8_t *hex, int size, const char * message, ...) {
|
||||
if (level >= LOG_LEVEL_ERROR) {
|
||||
char *args_msg;
|
||||
char *args_msg = NULL;
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
if(vasprintf(&args_msg, message, args) > 0)
|
||||
|
@ -203,7 +203,7 @@ void log_filter::error_hex(const uint8_t *hex, int size, const char * message, .
|
|||
}
|
||||
void log_filter::warning_hex(const uint8_t *hex, int size, const char * message, ...) {
|
||||
if (level >= LOG_LEVEL_WARNING) {
|
||||
char *args_msg;
|
||||
char *args_msg = NULL;
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
if(vasprintf(&args_msg, message, args) > 0)
|
||||
|
@ -214,7 +214,7 @@ void log_filter::warning_hex(const uint8_t *hex, int size, const char * message,
|
|||
}
|
||||
void log_filter::info_hex(const uint8_t *hex, int size, const char * message, ...) {
|
||||
if (level >= LOG_LEVEL_INFO) {
|
||||
char *args_msg;
|
||||
char *args_msg = NULL;
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
if(vasprintf(&args_msg, message, args) > 0)
|
||||
|
@ -225,7 +225,7 @@ void log_filter::info_hex(const uint8_t *hex, int size, const char * message, ..
|
|||
}
|
||||
void log_filter::debug_hex(const uint8_t *hex, int size, const char * message, ...) {
|
||||
if (level >= LOG_LEVEL_DEBUG) {
|
||||
char *args_msg;
|
||||
char *args_msg = NULL;
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
if(vasprintf(&args_msg, message, args) > 0)
|
||||
|
|
|
@ -74,12 +74,13 @@ void pdu_queue::deallocate(uint8_t* pdu)
|
|||
* This function enqueues the packet and returns quicly because ACK
|
||||
* deadline is important here.
|
||||
*/
|
||||
void pdu_queue::push(uint8_t *ptr, uint32_t len, uint32_t tstamp)
|
||||
void pdu_queue::push(uint8_t *ptr, uint32_t len, channel_t channel, uint32_t tstamp)
|
||||
{
|
||||
if (ptr) {
|
||||
pdu_t *pdu = (pdu_t*) ptr;
|
||||
pdu->len = len;
|
||||
pdu->tstamp = tstamp;
|
||||
pdu->channel = channel;
|
||||
pdu_q.push(pdu);
|
||||
} else {
|
||||
log_h->warning("Error pushing pdu: ptr is empty\n");
|
||||
|
@ -88,15 +89,17 @@ void pdu_queue::push(uint8_t *ptr, uint32_t len, uint32_t tstamp)
|
|||
|
||||
bool pdu_queue::process_pdus()
|
||||
{
|
||||
bool have_data = false;
|
||||
uint32_t cnt = 0;
|
||||
pdu_t *pdu;
|
||||
bool have_data = false;
|
||||
uint32_t cnt = 0;
|
||||
pdu_t *pdu;
|
||||
while(pdu_q.try_pop(&pdu)) {
|
||||
if (callback) {
|
||||
callback->process_pdu(pdu->ptr, pdu->len, pdu->tstamp);
|
||||
callback->process_pdu(pdu->ptr, pdu->len, pdu->channel, pdu->tstamp);
|
||||
}
|
||||
if (!pool.deallocate(pdu)) {
|
||||
log_h->warning("Error deallocating from buffer pool in process_pdus(): buffer not created in this pool.\n");
|
||||
if (pdu->channel == DCH) {
|
||||
if (!pool.deallocate(pdu)) {
|
||||
log_h->warning("Error deallocating from buffer pool in process_pdus(): buffer not created in this pool.\n");
|
||||
}
|
||||
}
|
||||
cnt++;
|
||||
have_data = true;
|
||||
|
|
|
@ -155,6 +155,7 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb)
|
|||
|
||||
q->rsrp_neighbour = false;
|
||||
|
||||
q->smooth_filter_auto = false;
|
||||
q->smooth_filter_len = 3;
|
||||
srslte_chest_dl_set_smooth_filter3_coeff(q, 0.1);
|
||||
|
||||
|
@ -263,41 +264,66 @@ int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, srslte_cell_t cell)
|
|||
/* Uses the difference between the averaged and non-averaged pilot estimates */
|
||||
static float estimate_noise_pilots(srslte_chest_dl_t *q, uint32_t port_id, srslte_sf_t ch_mode)
|
||||
{
|
||||
int nref=SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id);
|
||||
const float weight = 1.0f;
|
||||
float sum_power = 0.0f;
|
||||
uint32_t count = 0;
|
||||
uint32_t npilots = SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id);
|
||||
uint32_t nsymbols =
|
||||
(ch_mode == SRSLTE_SF_MBSFN) ? srslte_refsignal_mbsfn_nof_symbols() : srslte_refsignal_cs_nof_symbols(port_id);
|
||||
uint32_t nref = npilots / nsymbols;
|
||||
uint32_t fidx = srslte_refsignal_cs_fidx(q->cell, 0, port_id, 0);
|
||||
|
||||
if (q->average_subframe) {
|
||||
if (ch_mode == SRSLTE_SF_MBSFN) {
|
||||
nref /= 4;
|
||||
} else {
|
||||
nref /= 2;
|
||||
}
|
||||
cf_t *input2d[nsymbols + 2];
|
||||
cf_t *tmp_noise = q->tmp_noise;
|
||||
|
||||
for (int i = 0; i < nsymbols; i++) {
|
||||
input2d[i + 1] = &q->pilot_estimates[i * nref];
|
||||
}
|
||||
|
||||
/* Substract noisy pilot estimates */
|
||||
srslte_vec_sub_ccc(q->pilot_estimates_average, q->pilot_estimates, q->tmp_noise, nref);
|
||||
|
||||
#ifdef FREQ_SEL_SNR
|
||||
/* Compute frequency-selective SNR */
|
||||
srslte_vec_abs_square_cf(q->tmp_noise, q->snr_vector, nref);
|
||||
srslte_vec_abs_square_cf(q->pilot_estimates, q->pilot_power, nref);
|
||||
srslte_vec_div_fff(q->pilot_power, q->snr_vector, q->snr_vector, nref);
|
||||
|
||||
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;
|
||||
input2d[0] = &q->tmp_noise[0];
|
||||
if (nsymbols > 3) {
|
||||
srslte_vec_sc_prod_cfc(input2d[2], 2.0f, input2d[0], nref);
|
||||
srslte_vec_sub_ccc(input2d[0], input2d[4], input2d[0], nref);
|
||||
} else {
|
||||
if (q->smooth_filter_len == 3) {
|
||||
float a = q->smooth_filter[0];
|
||||
float norm3 = 6.143*a*a+0.04859*a-0.002774;
|
||||
norm /= norm3;
|
||||
}
|
||||
srslte_vec_sc_prod_cfc(input2d[2], 1.0f, input2d[0], nref);
|
||||
}
|
||||
float power = norm*srslte_vec_avg_power_cf(q->tmp_noise, nref);
|
||||
return power;
|
||||
|
||||
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++;
|
||||
}
|
||||
|
||||
return sum_power / (float) count * sqrtf(weight + 4.0f);
|
||||
}
|
||||
|
||||
static float estimate_noise_pss(srslte_chest_dl_t *q, cf_t *input, cf_t *ce)
|
||||
|
@ -443,6 +469,53 @@ void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q, float w)
|
|||
q->smooth_filter[1] = 1-2*w;
|
||||
}
|
||||
|
||||
void srslte_chest_dl_set_smooth_filter_gauss(srslte_chest_dl_t* q, uint32_t order, float std_dev)
|
||||
{
|
||||
const uint32_t filterlen = order + 1;
|
||||
const int center = (filterlen - 1) / 2;
|
||||
float *filter = q->smooth_filter;
|
||||
float norm_p = 0.0f;
|
||||
|
||||
if (filterlen) {
|
||||
|
||||
for (int i = 0; i < filterlen; i++) {
|
||||
filter[i] = expf(-powf(i - center, 2) / (2.0f * powf(std_dev, 2)));
|
||||
norm_p += powf(filter[i], 2);
|
||||
}
|
||||
|
||||
const float norm = srslte_vec_acc_ff(filter, filterlen);
|
||||
|
||||
srslte_vec_sc_prod_fff(filter, 1.0f / norm, filter, filterlen);
|
||||
q->smooth_filter_len = filterlen;
|
||||
}
|
||||
}
|
||||
|
||||
void srslte_chest_dl_set_smooth_filter_auto(srslte_chest_dl_t *q, bool enable) {
|
||||
q->smooth_filter_auto = enable;
|
||||
}
|
||||
|
||||
uint32_t srslte_chest_dl_interleave_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *tmp, cf_t *output, uint32_t port_id, srslte_sf_t ch_mode) {
|
||||
uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_nof_symbols(port_id):srslte_refsignal_cs_nof_symbols(port_id);
|
||||
uint32_t nref = (ch_mode == SRSLTE_SF_MBSFN)?6*q->cell.nof_prb:2*q->cell.nof_prb;
|
||||
|
||||
if (srslte_refsignal_cs_fidx(q->cell, 0, port_id, 0) < 3) {
|
||||
srslte_vec_interleave(input, &input[nref], tmp, nref);
|
||||
for (int l = 2; l < nsymbols - 1; l += 2) {
|
||||
srslte_vec_interleave_add(&input[l * nref], &input[(l + 1) * nref], tmp, nref);
|
||||
}
|
||||
} else {
|
||||
srslte_vec_interleave(&input[nref], input, tmp, nref);
|
||||
for (int l = 2; l < nsymbols - 1; l += 2) {
|
||||
srslte_vec_interleave_add(&input[(l + 1) * nref], &input[l * nref], tmp, nref);
|
||||
}
|
||||
}
|
||||
|
||||
nref *= 2;
|
||||
srslte_vec_sc_prod_cfc(tmp, 2.0f / nsymbols, output, nref);
|
||||
|
||||
return nref;
|
||||
}
|
||||
|
||||
static void average_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *output, uint32_t port_id, srslte_sf_t ch_mode) {
|
||||
uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_nof_symbols(port_id):srslte_refsignal_cs_nof_symbols(port_id);
|
||||
uint32_t nref = (ch_mode == SRSLTE_SF_MBSFN)?6*q->cell.nof_prb:2*q->cell.nof_prb;
|
||||
|
@ -523,7 +596,16 @@ void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, ui
|
|||
q->cfo = chest_estimate_cfo(q);
|
||||
}
|
||||
|
||||
/* Estimate noise */
|
||||
if (q->noise_alg == SRSLTE_NOISE_ALG_REFS) {
|
||||
q->noise_estimate[rxant_id][port_id] = estimate_noise_pilots(q, port_id, ch_mode);
|
||||
}
|
||||
|
||||
if (ce != NULL) {
|
||||
if (q->smooth_filter_auto) {
|
||||
srslte_chest_dl_set_smooth_filter_gauss(q, 4, q->noise_estimate[rxant_id][port_id] * 200.0f);
|
||||
}
|
||||
|
||||
/* Smooth estimates (if applicable) and interpolate */
|
||||
if (q->smooth_filter_len == 0 || (q->smooth_filter_len == 3 && q->smooth_filter[0] == 0)) {
|
||||
interpolate_pilots(q, q->pilot_estimates, ce, port_id, ch_mode);
|
||||
|
@ -533,13 +615,11 @@ void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, ui
|
|||
}
|
||||
|
||||
/* Estimate noise power */
|
||||
if (q->noise_alg == SRSLTE_NOISE_ALG_REFS && q->smooth_filter_len > 0) {
|
||||
q->noise_estimate[rxant_id][port_id] = estimate_noise_pilots(q, port_id, ch_mode);
|
||||
} else if (q->noise_alg == SRSLTE_NOISE_ALG_PSS) {
|
||||
if (q->noise_alg == SRSLTE_NOISE_ALG_PSS) {
|
||||
if (sf_idx == 0 || sf_idx == 5) {
|
||||
q->noise_estimate[rxant_id][port_id] = estimate_noise_pss(q, input, ce);
|
||||
}
|
||||
} else {
|
||||
} else if (q->noise_alg != SRSLTE_NOISE_ALG_REFS) {
|
||||
if (sf_idx == 0 || sf_idx == 5) {
|
||||
q->noise_estimate[rxant_id][port_id] = estimate_noise_empty_sc(q, input);
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ int srslte_layermap_multiplex(cf_t *d[SRSLTE_MAX_CODEWORDS], cf_t *x[SRSLTE_MAX_
|
|||
int nof_symbols[SRSLTE_MAX_CODEWORDS]) {
|
||||
if (nof_cw == nof_layers) {
|
||||
for (int i = 0; i < nof_cw; i++) {
|
||||
srs_vec_cf_cpy(x[i], d[i], (uint32_t) nof_symbols[0]);
|
||||
srs_vec_cf_cpy(d[i], x[i], (uint32_t) nof_symbols[0]);
|
||||
}
|
||||
return nof_symbols[0];
|
||||
} else if (nof_cw == 1) {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -221,7 +221,7 @@ int srslte_pcfich_decode_multi(srslte_pcfich_t *q, cf_t *sf_symbols[SRSLTE_MAX_P
|
|||
/* no need for layer demapping */
|
||||
srslte_predecoding_single_multi(q_symbols, q_ce[0], q->d, NULL, q->nof_rx_antennas, q->nof_symbols, 1.0f, noise_estimate);
|
||||
} else {
|
||||
srslte_predecoding_diversity_multi(q_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, q->nof_symbols, 1.0f);
|
||||
srslte_predecoding_diversity_multi(q_symbols, q_ce, x, NULL, q->nof_rx_antennas, q->cell.nof_ports, q->nof_symbols, 1.0f);
|
||||
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, q->nof_symbols / q->cell.nof_ports);
|
||||
}
|
||||
|
||||
|
|
|
@ -492,7 +492,7 @@ int srslte_pdcch_extract_llr_multi(srslte_pdcch_t *q, cf_t *sf_symbols[SRSLTE_MA
|
|||
/* no need for layer demapping */
|
||||
srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, NULL, q->nof_rx_antennas, nof_symbols, 1.0f, noise_estimate/2);
|
||||
} else {
|
||||
srslte_predecoding_diversity_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, nof_symbols, 1.0f);
|
||||
srslte_predecoding_diversity_multi(q->symbols, q->ce, x, NULL, q->nof_rx_antennas, q->cell.nof_ports, nof_symbols, 1.0f);
|
||||
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports);
|
||||
}
|
||||
|
||||
|
|
|
@ -402,7 +402,7 @@ int srslte_pdsch_enable_csi(srslte_pdsch_t *q, bool enable) {
|
|||
if (enable) {
|
||||
for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
|
||||
if (!q->csi[i]) {
|
||||
q->csi[i] = srslte_vec_malloc(sizeof(float) * q->max_re);
|
||||
q->csi[i] = srslte_vec_malloc(sizeof(float) * q->max_re * 2);
|
||||
if (!q->csi[i]) {
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
@ -757,7 +757,7 @@ int srslte_pdsch_decode(srslte_pdsch_t *q,
|
|||
}
|
||||
|
||||
// Pre-decoder
|
||||
if (srslte_predecoding_type(q->symbols, q->ce, x, q->csi[0], q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers,
|
||||
if (srslte_predecoding_type(q->symbols, q->ce, x, q->csi, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers,
|
||||
cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, pdsch_scaling, noise_estimate)<0) {
|
||||
DEBUG("Error predecoding\n");
|
||||
return SRSLTE_ERROR;
|
||||
|
|
|
@ -241,7 +241,7 @@ int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS],
|
|||
/* no need for layer demapping */
|
||||
srslte_predecoding_single_multi(q_sf_symbols, q_ce[0], q->d0, NULL, q->nof_rx_antennas, SRSLTE_PHICH_MAX_NSYMB, 1.0f, noise_estimate);
|
||||
} else {
|
||||
srslte_predecoding_diversity_multi(q_sf_symbols, q_ce, x, q->nof_rx_antennas, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB, 1.0f);
|
||||
srslte_predecoding_diversity_multi(q_sf_symbols, q_ce, x, NULL, q->nof_rx_antennas, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB, 1.0f);
|
||||
srslte_layerdemap_diversity(x, q->d0, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports);
|
||||
}
|
||||
DEBUG("Recv!!: \n");
|
||||
|
|
|
@ -130,7 +130,7 @@ int srslte_sch_init(srslte_sch_t *q) {
|
|||
goto clean;
|
||||
}
|
||||
bzero(q->temp_g_bits, SRSLTE_MAX_PRB*12*12*12);
|
||||
q->ul_interleaver = srslte_vec_malloc(sizeof(uint16_t)*SRSLTE_MAX_PRB*12*12*12);
|
||||
q->ul_interleaver = srslte_vec_malloc(sizeof(uint32_t)*SRSLTE_MAX_PRB*12*12*12);
|
||||
if (!q->ul_interleaver) {
|
||||
goto clean;
|
||||
}
|
||||
|
@ -577,7 +577,7 @@ int srslte_dlsch_encode2(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbu
|
|||
* Profiling show that the computation of this matrix is neglegible.
|
||||
*/
|
||||
static void ulsch_interleave_gen(uint32_t H_prime_total, uint32_t N_pusch_symbs, uint32_t Qm,
|
||||
uint8_t *ri_present, uint16_t *interleaver_lut)
|
||||
uint8_t *ri_present, uint32_t *interleaver_lut)
|
||||
{
|
||||
uint32_t rows = H_prime_total/N_pusch_symbs;
|
||||
uint32_t cols = N_pusch_symbs;
|
||||
|
@ -599,7 +599,7 @@ static void ulsch_interleave_gen(uint32_t H_prime_total, uint32_t N_pusch_symbs,
|
|||
/* UL-SCH channel interleaver according to 5.2.2.8 of 36.212 */
|
||||
void ulsch_interleave(uint8_t *g_bits, uint32_t Qm, uint32_t H_prime_total,
|
||||
uint32_t N_pusch_symbs, uint8_t *q_bits, srslte_uci_bit_t *ri_bits, uint32_t nof_ri_bits,
|
||||
uint8_t *ri_present, uint16_t *inteleaver_lut)
|
||||
uint8_t *ri_present, uint32_t *inteleaver_lut)
|
||||
{
|
||||
|
||||
// Prepare ri_bits for fast search using temp_buffer
|
||||
|
@ -611,7 +611,7 @@ void ulsch_interleave(uint8_t *g_bits, uint32_t Qm, uint32_t H_prime_total,
|
|||
|
||||
// Genearate interleaver table and interleave bits
|
||||
ulsch_interleave_gen(H_prime_total, N_pusch_symbs, Qm, ri_present, inteleaver_lut);
|
||||
srslte_bit_interleave(g_bits, q_bits, inteleaver_lut, H_prime_total*Qm);
|
||||
srslte_bit_interleave_i(g_bits, q_bits, inteleaver_lut, H_prime_total*Qm);
|
||||
|
||||
// Reset temp_buffer because will be reused next time
|
||||
if (nof_ri_bits > 0) {
|
||||
|
@ -624,7 +624,7 @@ void ulsch_interleave(uint8_t *g_bits, uint32_t Qm, uint32_t H_prime_total,
|
|||
/* UL-SCH channel deinterleaver according to 5.2.2.8 of 36.212 */
|
||||
void ulsch_deinterleave(int16_t *q_bits, uint32_t Qm, uint32_t H_prime_total,
|
||||
uint32_t N_pusch_symbs, int16_t *g_bits, srslte_uci_bit_t *ri_bits, uint32_t nof_ri_bits,
|
||||
uint8_t *ri_present, uint16_t *inteleaver_lut)
|
||||
uint8_t *ri_present, uint32_t *inteleaver_lut)
|
||||
{
|
||||
// Prepare ri_bits for fast search using temp_buffer
|
||||
if (nof_ri_bits > 0) {
|
||||
|
@ -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
|
||||
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);
|
||||
ulsch_interleave_gen(H_prime_total, N_pusch_symbs, Qm, ri_present, inteleaver_lut);
|
||||
srslte_vec_lut_sis(q_bits, inteleaver_lut, g_bits, H_prime_total*Qm);
|
||||
|
||||
// Reset temp_buffer because will be reused next time
|
||||
if (nof_ri_bits > 0) {
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
|
||||
#define MAX_TIME_OFFSET 128
|
||||
|
||||
#define TRACK_MAX_LOST 4
|
||||
#define TRACK_MAX_LOST 100
|
||||
#define TRACK_FRAME_SIZE 32
|
||||
#define FIND_NOF_AVG_FRAMES 4
|
||||
#define DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD 0
|
||||
|
|
|
@ -205,6 +205,163 @@ void srslte_bit_interleaver_run(srslte_bit_interleaver_t *q, uint8_t *input, uin
|
|||
}
|
||||
|
||||
|
||||
void srslte_bit_interleave_i(uint8_t *input, uint8_t *output, uint32_t *interleaver, uint32_t nof_bits) {
|
||||
srslte_bit_interleave_i_w_offset(input, output, interleaver, nof_bits, 0);
|
||||
}
|
||||
|
||||
void srslte_bit_interleave_i_w_offset(uint8_t *input, uint8_t *output, uint32_t *interleaver, uint32_t nof_bits, uint32_t w_offset) {
|
||||
uint32_t st=0, w_offset_p=0;
|
||||
static const uint8_t mask[] = { 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 };
|
||||
|
||||
if (w_offset < 8 && w_offset > 0) {
|
||||
st=1;
|
||||
for (uint32_t j=0;j<8-w_offset;j++) {
|
||||
uint32_t i_p = interleaver[j];
|
||||
if (input[i_p/8] & mask[i_p%8]) {
|
||||
output[0] |= mask[j+w_offset];
|
||||
} else {
|
||||
output[0] &= ~(mask[j+w_offset]);
|
||||
}
|
||||
}
|
||||
w_offset_p=8-w_offset;
|
||||
}
|
||||
|
||||
#ifdef LV_HAVE_SSE
|
||||
__m64 m64mask = _mm_setr_pi8((uint8_t) 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1);
|
||||
|
||||
union {
|
||||
uint8_t v[8];
|
||||
__m64 m64;
|
||||
} a, b, c;
|
||||
|
||||
union {
|
||||
__m128i m128;
|
||||
uint16_t u32[4];
|
||||
uint16_t u16[8];
|
||||
uint8_t u8[16];
|
||||
struct {
|
||||
__m64 reg_a;
|
||||
__m64 reg_b;
|
||||
} m64;
|
||||
struct {
|
||||
uint16_t i0, i1, i2, i3, i4, i5, i6, i7;
|
||||
} v16;
|
||||
struct {
|
||||
uint32_t i0, i1, i2, i3;
|
||||
} v32;
|
||||
} ipx1, ipx2, epx1, epx2;
|
||||
for (uint32_t i = st; i < nof_bits / 8; i++) {
|
||||
ipx1.m128 = _mm_loadu_si128((__m128i *) (interleaver + (i * 8 + 0) - w_offset_p));
|
||||
epx1.m128 = _mm_shuffle_epi8(ipx1.m128, _mm_set_epi8(0x00, 0x04, 0x08, 0x0C,
|
||||
0x00, 0x04, 0x08, 0x0C,
|
||||
0x00, 0x04, 0x08, 0x0C,
|
||||
0x00, 0x04, 0x08, 0x0C));
|
||||
ipx2.m128 = _mm_loadu_si128((__m128i *) (interleaver + (i * 8 + 4) - w_offset_p));
|
||||
epx2.m128 = _mm_shuffle_epi8(ipx2.m128, _mm_set_epi8(0x00, 0x04, 0x08, 0x0C,
|
||||
0x00, 0x04, 0x08, 0x0C,
|
||||
0x00, 0x04, 0x08, 0x0C,
|
||||
0x00, 0x04, 0x08, 0x0C));
|
||||
|
||||
epx1.m128 = _mm_blendv_epi8(epx2.m128, epx1.m128, _mm_setr_epi8(+1, +1, +1, +1,
|
||||
-1, -1, -1, -1,
|
||||
+1, +1, +1, +1,
|
||||
-1, -1, -1, -1));
|
||||
|
||||
b.m64 = _mm_and_si64(epx1.m64.reg_a, _mm_set1_pi8(0x7));
|
||||
b.m64 = _mm_shuffle_pi8(m64mask, b.m64);
|
||||
|
||||
ipx1.m128 = _mm_srli_epi32(ipx1.m128, 3);
|
||||
ipx2.m128 = _mm_srli_epi32(ipx2.m128, 3);
|
||||
|
||||
a.m64 = _mm_set_pi8(input[ipx1.v32.i0],
|
||||
input[ipx1.v32.i1],
|
||||
input[ipx1.v32.i2],
|
||||
input[ipx1.v32.i3],
|
||||
input[ipx2.v32.i0],
|
||||
input[ipx2.v32.i1],
|
||||
input[ipx2.v32.i2],
|
||||
input[ipx2.v32.i3]);
|
||||
|
||||
c.m64 = _mm_cmpeq_pi8(_mm_and_si64(a.m64, b.m64), b.m64);
|
||||
output[i] = (uint8_t) _mm_movemask_pi8(c.m64);
|
||||
}
|
||||
|
||||
#if 0 /* Disabled */
|
||||
/* THIS PIECE OF CODE IS FOR CHECKING SIMD BEHAVIOUR. DO NOT ENABLE. */
|
||||
uint8_t *output2 = malloc(nof_bits/8);
|
||||
for (uint32_t i=st;i<nof_bits/8;i++) {
|
||||
|
||||
uint16_t i_p0 = interleaver[i*8+0-w_offset_p];
|
||||
uint16_t i_p1 = interleaver[i*8+1-w_offset_p];
|
||||
uint16_t i_p2 = interleaver[i*8+2-w_offset_p];
|
||||
uint16_t i_p3 = interleaver[i*8+3-w_offset_p];
|
||||
uint16_t i_p4 = interleaver[i*8+4-w_offset_p];
|
||||
uint16_t i_p5 = interleaver[i*8+5-w_offset_p];
|
||||
uint16_t i_p6 = interleaver[i*8+6-w_offset_p];
|
||||
uint16_t i_p7 = interleaver[i*8+7-w_offset_p];
|
||||
|
||||
uint8_t out0 = (input[i_p0/8] & mask[i_p0%8])?mask[0]:(uint8_t)0;
|
||||
uint8_t out1 = (input[i_p1/8] & mask[i_p1%8])?mask[1]:(uint8_t)0;
|
||||
uint8_t out2 = (input[i_p2/8] & mask[i_p2%8])?mask[2]:(uint8_t)0;
|
||||
uint8_t out3 = (input[i_p3/8] & mask[i_p3%8])?mask[3]:(uint8_t)0;
|
||||
uint8_t out4 = (input[i_p4/8] & mask[i_p4%8])?mask[4]:(uint8_t)0;
|
||||
uint8_t out5 = (input[i_p5/8] & mask[i_p5%8])?mask[5]:(uint8_t)0;
|
||||
uint8_t out6 = (input[i_p6/8] & mask[i_p6%8])?mask[6]:(uint8_t)0;
|
||||
uint8_t out7 = (input[i_p7/8] & mask[i_p7%8])?mask[7]:(uint8_t)0;
|
||||
|
||||
output2[i] = out0 | out1 | out2 | out3 | out4 | out5 | out6 | out7;
|
||||
}
|
||||
|
||||
for(uint32_t i = st; i < nof_bits/8; i++) {
|
||||
if (output[i] != output2[i]) {
|
||||
printf("%05d/%05d %02X %02X\n", i, nof_bits/8, output[i], output2[i]);
|
||||
}
|
||||
//output[i] = output2[i];
|
||||
}
|
||||
free(output2);
|
||||
#endif /* Disabled */
|
||||
#else /* LV_HAVE_SSE */
|
||||
for (uint32_t i=st;i<nof_bits/8;i++) {
|
||||
|
||||
uint32_t i_p0 = interleaver[i*8+0-w_offset_p];
|
||||
uint32_t i_p1 = interleaver[i*8+1-w_offset_p];
|
||||
uint32_t i_p2 = interleaver[i*8+2-w_offset_p];
|
||||
uint32_t i_p3 = interleaver[i*8+3-w_offset_p];
|
||||
uint32_t i_p4 = interleaver[i*8+4-w_offset_p];
|
||||
uint32_t i_p5 = interleaver[i*8+5-w_offset_p];
|
||||
uint32_t i_p6 = interleaver[i*8+6-w_offset_p];
|
||||
uint32_t i_p7 = interleaver[i*8+7-w_offset_p];
|
||||
|
||||
uint8_t out0 = (input[i_p0/8] & mask[i_p0%8])?mask[0]:0;
|
||||
uint8_t out1 = (input[i_p1/8] & mask[i_p1%8])?mask[1]:0;
|
||||
uint8_t out2 = (input[i_p2/8] & mask[i_p2%8])?mask[2]:0;
|
||||
uint8_t out3 = (input[i_p3/8] & mask[i_p3%8])?mask[3]:0;
|
||||
uint8_t out4 = (input[i_p4/8] & mask[i_p4%8])?mask[4]:0;
|
||||
uint8_t out5 = (input[i_p5/8] & mask[i_p5%8])?mask[5]:0;
|
||||
uint8_t out6 = (input[i_p6/8] & mask[i_p6%8])?mask[6]:0;
|
||||
uint8_t out7 = (input[i_p7/8] & mask[i_p7%8])?mask[7]:0;
|
||||
|
||||
output[i] = out0 | out1 | out2 | out3 | out4 | out5 | out6 | out7;
|
||||
}
|
||||
#endif /* LV_HAVE_SSE */
|
||||
|
||||
for (uint32_t j=0;j<nof_bits%8;j++) {
|
||||
uint32_t i_p = interleaver[(nof_bits/8)*8+j-w_offset];
|
||||
if (input[i_p/8] & mask[i_p%8]) {
|
||||
output[nof_bits/8] |= mask[j];
|
||||
} else {
|
||||
output[nof_bits/8] &= ~(mask[j]);
|
||||
}
|
||||
}
|
||||
for (uint32_t j=0;j<w_offset;j++) {
|
||||
uint32_t i_p = interleaver[(nof_bits/8)*8+j-w_offset];
|
||||
if (input[i_p/8] & (1<<(7-i_p%8))) {
|
||||
output[nof_bits/8] |= mask[j];
|
||||
} else {
|
||||
output[nof_bits/8] &= ~(mask[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void srslte_bit_interleave(uint8_t *input, uint8_t *output, uint16_t *interleaver, uint32_t nof_bits) {
|
||||
srslte_bit_interleave_w_offset(input, output, interleaver, nof_bits, 0);
|
||||
|
|
|
@ -60,8 +60,8 @@ inline void srslte_mat_2x2_zf_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf_t h10
|
|||
}
|
||||
|
||||
/* Generic implementation for Minimum Mean Squared Error (MMSE) solver */
|
||||
inline void srslte_mat_2x2_mmse_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf_t h10, cf_t h11,
|
||||
cf_t *x0, cf_t *x1, float noise_estimate, float norm) {
|
||||
inline void srslte_mat_2x2_mmse_csi_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf_t h10, cf_t h11,
|
||||
cf_t *x0, cf_t *x1, float *csi0, float *csi1, float noise_estimate, float norm) {
|
||||
/* Create conjugated matrix */
|
||||
cf_t _h00 = conjf(h00);
|
||||
cf_t _h01 = conjf(h01);
|
||||
|
@ -73,14 +73,14 @@ inline void srslte_mat_2x2_mmse_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf_t h
|
|||
cf_t a01 = _h00 * h01 + _h10 * h11;
|
||||
cf_t a10 = _h01 * h00 + _h11 * h10;
|
||||
cf_t a11 = _h01 * h01 + _h11 * h11 + noise_estimate;
|
||||
cf_t a_det_rcp = srslte_mat_cf_recip_gen(srslte_mat_2x2_det_gen(a00, a01, a10, a11));
|
||||
|
||||
/* 2. B = inv(H' x H + No) = inv(A) */
|
||||
cf_t b00 = a11;
|
||||
cf_t b01 = -a01;
|
||||
cf_t b10 = -a10;
|
||||
cf_t b11 = a00;
|
||||
cf_t _norm = norm * srslte_mat_cf_recip_gen(srslte_mat_2x2_det_gen(a00, a01, a10, a11));
|
||||
|
||||
cf_t _norm = norm * a_det_rcp;
|
||||
cf_t b00 = a11 * _norm;
|
||||
cf_t b01 = -a01 * _norm;
|
||||
cf_t b10 = -a10 * _norm;
|
||||
cf_t b11 = a00 * _norm;
|
||||
|
||||
/* 3. W = inv(H' x H + No) x H' = B x H' */
|
||||
cf_t w00 = b00 * _h00 + b01 * _h01;
|
||||
|
@ -89,8 +89,19 @@ inline void srslte_mat_2x2_mmse_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf_t h
|
|||
cf_t w11 = b10 * _h10 + b11 * _h11;
|
||||
|
||||
/* 4. X = W x Y */
|
||||
*x0 = (y0 * w00 + y1 * w01) * _norm;
|
||||
*x1 = (y0 * w10 + y1 * w11) * _norm;
|
||||
*x0 = (y0 * w00 + y1 * w01);
|
||||
*x1 = (y0 * w10 + y1 * w11);
|
||||
|
||||
/* 5. Set CSI */
|
||||
*csi0 = 1.0f / crealf(b00);
|
||||
*csi1 = 1.0f / crealf(b11);
|
||||
}
|
||||
|
||||
/* Generic implementation for Minimum Mean Squared Error (MMSE) solver */
|
||||
void srslte_mat_2x2_mmse_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf_t h10, cf_t h11,
|
||||
cf_t *x0, cf_t *x1, float noise_estimate, float norm) {
|
||||
float csi0, csi1;
|
||||
srslte_mat_2x2_mmse_csi_gen(y0, y1, h00, h01, h10, h11, x0, x1, &csi0, &csi1, noise_estimate, norm);
|
||||
}
|
||||
|
||||
inline float srslte_mat_2x2_cn(cf_t h00, cf_t h01, cf_t h10, cf_t h11) {
|
||||
|
|
|
@ -32,8 +32,8 @@
|
|||
#include <sys/time.h>
|
||||
|
||||
#include "srslte/phy/utils/mat.h"
|
||||
#include "srslte/phy/utils/simd.h"
|
||||
#include "srslte/phy/utils/vector.h"
|
||||
#include "srslte/phy/utils/vector_simd.h"
|
||||
|
||||
|
||||
bool zf_solver = false;
|
||||
|
@ -378,6 +378,98 @@ bool test_mmse_solver_avx(void) {
|
|||
|
||||
#endif /* LV_HAVE_AVX */
|
||||
|
||||
#if SRSLTE_SIMD_CF_SIZE != 0
|
||||
|
||||
bool test_zf_solver_simd(void) {
|
||||
cf_t cf_error0, cf_error1;
|
||||
float error = 0.0f;
|
||||
|
||||
cf_t x0_gold_1 = RANDOM_CF();
|
||||
cf_t x1_gold_1 = RANDOM_CF();
|
||||
cf_t h00_1 = RANDOM_CF();
|
||||
cf_t h01_1 = RANDOM_CF();
|
||||
cf_t h10_1 = RANDOM_CF();
|
||||
cf_t h11_1 = (1 - h01_1 * h10_1) / h00_1;
|
||||
cf_t y0_1 = x0_gold_1 * h00_1 + x1_gold_1 * h01_1;
|
||||
cf_t y1_1 = x0_gold_1 * h10_1 + x1_gold_1 * h11_1;
|
||||
|
||||
simd_cf_t _y0 = srslte_simd_cf_set1(y0_1);
|
||||
simd_cf_t _y1 = srslte_simd_cf_set1(y1_1);
|
||||
|
||||
simd_cf_t _h00 = srslte_simd_cf_set1(h00_1);
|
||||
simd_cf_t _h01 = srslte_simd_cf_set1(h01_1);
|
||||
simd_cf_t _h10 = srslte_simd_cf_set1(h10_1);
|
||||
simd_cf_t _h11 = srslte_simd_cf_set1(h11_1);
|
||||
|
||||
simd_cf_t _x0, _x1;
|
||||
|
||||
srslte_mat_2x2_zf_simd(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 1.0f);
|
||||
|
||||
__attribute__((aligned(SRSLTE_SIMD_BIT_ALIGN))) cf_t x0[SRSLTE_SIMD_CF_SIZE];
|
||||
__attribute__((aligned(SRSLTE_SIMD_BIT_ALIGN))) cf_t x1[SRSLTE_SIMD_CF_SIZE];
|
||||
|
||||
srslte_simd_cfi_store(x0, _x0);
|
||||
srslte_simd_cfi_store(x1, _x1);
|
||||
|
||||
cf_error0 = x0[1] - x0_gold_1;
|
||||
cf_error1 = x1[1] - x1_gold_1;
|
||||
error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
|
||||
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
|
||||
|
||||
return (error < 1e-3);
|
||||
}
|
||||
|
||||
bool test_mmse_solver_simd(void) {
|
||||
cf_t cf_error0, cf_error1;
|
||||
float error = 0.0f;
|
||||
|
||||
cf_t x0_gold[SRSLTE_SIMD_CF_SIZE];
|
||||
cf_t x1_gold[SRSLTE_SIMD_CF_SIZE];
|
||||
cf_t h00[SRSLTE_SIMD_CF_SIZE];
|
||||
cf_t h01[SRSLTE_SIMD_CF_SIZE];
|
||||
cf_t h10[SRSLTE_SIMD_CF_SIZE];
|
||||
cf_t h11[SRSLTE_SIMD_CF_SIZE];
|
||||
cf_t y0[SRSLTE_SIMD_CF_SIZE];
|
||||
cf_t y1[SRSLTE_SIMD_CF_SIZE];
|
||||
for (int i = 0; i < SRSLTE_SIMD_CF_SIZE; i++) {
|
||||
x0_gold[i] = RANDOM_CF();
|
||||
x1_gold[i] = RANDOM_CF();
|
||||
h00[i] = RANDOM_CF();
|
||||
h01[i] = RANDOM_CF();
|
||||
h10[i] = RANDOM_CF();
|
||||
h11[i] = (1 - h01[i] * h10[i]) / h00[i];
|
||||
y0[i] = x0_gold[i] * h00[i]+ x1_gold[i] * h01[i];
|
||||
y1[i] = x0_gold[i] * h10[i] + x1_gold[i] * h11[i];
|
||||
}
|
||||
|
||||
simd_cf_t _y0 = srslte_simd_cfi_loadu(y0);
|
||||
simd_cf_t _y1 = srslte_simd_cfi_loadu(y1);
|
||||
|
||||
simd_cf_t _h00 = srslte_simd_cfi_loadu(h00);
|
||||
simd_cf_t _h01 = srslte_simd_cfi_loadu(h01);
|
||||
simd_cf_t _h10 = srslte_simd_cfi_loadu(h10);
|
||||
simd_cf_t _h11 = srslte_simd_cfi_loadu(h11);
|
||||
|
||||
simd_cf_t _x0, _x1;
|
||||
|
||||
srslte_mat_2x2_mmse_simd(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 0.0f, 1.0f);
|
||||
|
||||
__attribute__((aligned(SRSLTE_SIMD_BIT_ALIGN))) cf_t x0[SRSLTE_SIMD_CF_SIZE];
|
||||
__attribute__((aligned(SRSLTE_SIMD_BIT_ALIGN))) cf_t x1[SRSLTE_SIMD_CF_SIZE];
|
||||
|
||||
srslte_simd_cfi_store(x0, _x0);
|
||||
srslte_simd_cfi_store(x1, _x1);
|
||||
|
||||
cf_error0 = x0[1] - x0_gold[1];
|
||||
cf_error1 = x1[1] - x1_gold[1];
|
||||
error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
|
||||
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
|
||||
|
||||
return (error < 1e-3);
|
||||
}
|
||||
|
||||
#endif /* SRSLTE_SIMD_CF_SIZE != 0 */
|
||||
|
||||
bool test_vec_dot_prod_ccc(void) {
|
||||
__attribute__((aligned(256))) cf_t a[14];
|
||||
__attribute__((aligned(256))) cf_t b[14];
|
||||
|
@ -413,6 +505,10 @@ int main(int argc, char **argv) {
|
|||
#ifdef LV_HAVE_AVX
|
||||
RUN_TEST(test_zf_solver_avx);
|
||||
#endif /* LV_HAVE_AVX */
|
||||
|
||||
#if SRSLTE_SIMD_CF_SIZE != 0
|
||||
RUN_TEST(test_zf_solver_simd);
|
||||
#endif /* SRSLTE_SIMD_CF_SIZE != 0*/
|
||||
}
|
||||
|
||||
if (mmse_solver) {
|
||||
|
@ -426,6 +522,10 @@ int main(int argc, char **argv) {
|
|||
#ifdef LV_HAVE_AVX
|
||||
RUN_TEST(test_mmse_solver_avx);
|
||||
#endif /* LV_HAVE_AVX */
|
||||
|
||||
#if SRSLTE_SIMD_CF_SIZE != 0
|
||||
RUN_TEST(test_mmse_solver_simd);
|
||||
#endif /* SRSLTE_SIMD_CF_SIZE != 0*/
|
||||
}
|
||||
|
||||
RUN_TEST(test_vec_dot_prod_ccc);
|
||||
|
|
|
@ -104,6 +104,12 @@ void srslte_vec_lut_sss(const short *x, const unsigned short *lut, short *y, con
|
|||
srslte_vec_lut_sss_simd(x, lut, y, len);
|
||||
}
|
||||
|
||||
void srslte_vec_lut_sis(const short *x, const unsigned int *lut, short *y, const uint32_t len) {
|
||||
for (int i=0; i < len; i++) {
|
||||
y[lut[i]] = x[i];
|
||||
}
|
||||
}
|
||||
|
||||
void *srslte_vec_malloc(uint32_t size) {
|
||||
void *ptr;
|
||||
if (posix_memalign(&ptr, SRSLTE_SIMD_BIT_ALIGN, size)) {
|
||||
|
@ -421,8 +427,8 @@ void srslte_vec_quant_sus(const int16_t *in, uint16_t *out, const float gain, co
|
|||
}
|
||||
}
|
||||
|
||||
void srs_vec_cf_cpy(const cf_t *dst, cf_t *src, int len) {
|
||||
srslte_vec_cp_simd(dst, src, len);
|
||||
void srs_vec_cf_cpy(const cf_t *src, cf_t *dst, int len) {
|
||||
srslte_vec_cp_simd(src, dst, len);
|
||||
}
|
||||
|
||||
void srslte_vec_interleave(const cf_t *x, const cf_t *y, cf_t *z, const int len) {
|
||||
|
|
|
@ -50,12 +50,14 @@ bool radio::init(char *args, char *devname, uint32_t nof_channels)
|
|||
|
||||
// Suppress radio stdout
|
||||
srslte_rf_suppress_stdout(&rf_device);
|
||||
|
||||
tx_adv_auto = true;
|
||||
|
||||
continuous_tx = false;
|
||||
tx_adv_auto = true;
|
||||
// Set default preamble length each known device
|
||||
// We distinguish by device family, maybe we should calibrate per device
|
||||
if (strstr(srslte_rf_name(&rf_device), "uhd")) {
|
||||
burst_preamble_sec = uhd_default_burst_preamble_sec;
|
||||
continuous_tx = true;
|
||||
} else if (strstr(srslte_rf_name(&rf_device), "bladerf")) {
|
||||
burst_preamble_sec = blade_default_burst_preamble_sec;
|
||||
} else {
|
||||
|
@ -89,6 +91,7 @@ void radio::reset()
|
|||
printf("Resetting Radio...\n");
|
||||
srslte_rf_stop_rx_stream(&rf_device);
|
||||
radio_is_streaming = false;
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
void radio::set_manual_calibration(rf_cal_t* calibration)
|
||||
|
@ -110,6 +113,14 @@ void radio::set_burst_preamble(double preamble_us)
|
|||
burst_preamble_sec = (double) preamble_us/1e6;
|
||||
}
|
||||
|
||||
void radio::set_continuous_tx(bool enable) {
|
||||
continuous_tx = enable;
|
||||
}
|
||||
|
||||
bool radio::is_continuous_tx() {
|
||||
return continuous_tx;
|
||||
}
|
||||
|
||||
void radio::set_tx_adv(int nsamples)
|
||||
{
|
||||
tx_adv_auto = false;
|
||||
|
@ -175,7 +186,7 @@ float radio::set_tx_power(float power)
|
|||
|
||||
float radio::get_max_tx_power()
|
||||
{
|
||||
return 10;
|
||||
return 40;
|
||||
}
|
||||
|
||||
float radio::get_rssi()
|
||||
|
@ -450,6 +461,10 @@ void radio::set_tx_srate(double srate)
|
|||
|
||||
// Calculate TX advance in seconds from samples and sampling rate
|
||||
tx_adv_sec = nsamples/cur_tx_srate;
|
||||
if (tx_adv_sec<0) {
|
||||
tx_adv_sec *= -1;
|
||||
tx_adv_negative = true;
|
||||
}
|
||||
}
|
||||
|
||||
void radio::register_error_handler(srslte_rf_error_handler_t h)
|
||||
|
|
|
@ -60,8 +60,9 @@ void rlc_tm::empty_queue()
|
|||
// Drop all messages in TX queue
|
||||
byte_buffer_t *buf;
|
||||
while(ul_queue.size() > 0) {
|
||||
ul_queue.read(&buf);
|
||||
pool->deallocate(buf);
|
||||
if (ul_queue.try_read(&buf)) {
|
||||
pool->deallocate(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,14 +113,18 @@ int rlc_tm::read_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|||
return 0;
|
||||
}
|
||||
byte_buffer_t *buf;
|
||||
ul_queue.read(&buf);
|
||||
pdu_size = buf->N_bytes;
|
||||
memcpy(payload, buf->msg, buf->N_bytes);
|
||||
log->debug("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
|
||||
rrc->get_rb_name(lcid).c_str(), buf->get_latency_us());
|
||||
pool->deallocate(buf);
|
||||
log->info_hex(payload, pdu_size, "TX %s, %s PDU", rrc->get_rb_name(lcid).c_str(), rlc_mode_text[RLC_MODE_TM]);
|
||||
return pdu_size;
|
||||
if (ul_queue.try_read(&buf)) {
|
||||
pdu_size = buf->N_bytes;
|
||||
memcpy(payload, buf->msg, buf->N_bytes);
|
||||
log->debug("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
|
||||
rrc->get_rb_name(lcid).c_str(), buf->get_latency_us());
|
||||
pool->deallocate(buf);
|
||||
log->info_hex(payload, pdu_size, "TX %s, %s PDU", rrc->get_rb_name(lcid).c_str(), rlc_mode_text[RLC_MODE_TM]);
|
||||
return pdu_size;
|
||||
} else {
|
||||
log->warning("Queue empty while trying to read\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void rlc_tm::write_pdu(uint8_t *payload, uint32_t nof_bytes)
|
||||
|
|
|
@ -42,18 +42,17 @@ private:
|
|||
|
||||
bool new_allocation(uint32_t nof_rbg, uint32_t* rbgmask);
|
||||
void update_allocation(uint32_t new_mask);
|
||||
bool allocation_is_valid(uint32_t mask);
|
||||
|
||||
|
||||
bool allocation_is_valid(uint32_t mask);
|
||||
dl_harq_proc* apply_user_allocation(sched_ue *user);
|
||||
|
||||
uint32_t get_required_rbg(sched_ue *user, uint32_t tti);
|
||||
uint32_t count_rbg(uint32_t mask);
|
||||
uint32_t calc_rbg_mask(bool mask[25]);
|
||||
|
||||
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 used_rb_mask;
|
||||
uint32_t nof_ctrl_symbols;
|
||||
|
@ -72,8 +71,8 @@ private:
|
|||
|
||||
bool new_allocation(uint32_t L, ul_harq_proc::ul_alloc_t *alloc);
|
||||
bool allocation_is_valid(ul_harq_proc::ul_alloc_t alloc);
|
||||
ul_harq_proc* apply_user_allocation(sched_ue *user);
|
||||
|
||||
uint32_t nof_users_with_data;
|
||||
|
||||
bool used_rb[MAX_PRB];
|
||||
uint32_t current_tti;
|
||||
|
|
|
@ -40,7 +40,8 @@ class sched_ue {
|
|||
public:
|
||||
|
||||
// used by sched_metric
|
||||
uint32_t ue_idx;
|
||||
dl_harq_proc* dl_next_alloc;
|
||||
ul_harq_proc* ul_next_alloc;
|
||||
|
||||
bool has_pucch;
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ public:
|
|||
|
||||
bool process_pdus();
|
||||
uint8_t *request_buffer(uint32_t tti, uint32_t len);
|
||||
void process_pdu(uint8_t *pdu, uint32_t nof_bytes, uint32_t tstamp);
|
||||
void process_pdu(uint8_t *pdu, uint32_t nof_bytes, srslte::pdu_queue::channel_t channel, uint32_t tstamp);
|
||||
void push_pdu(uint32_t tti, uint32_t len);
|
||||
void deallocate_pdu(uint32_t tti);
|
||||
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include "srslte/common/buffer_pool.h"
|
||||
#include "srslte/common/log.h"
|
||||
#include "srslte/common/common.h"
|
||||
#include "srslte/common/msg_queue.h"
|
||||
#include "srslte/common/threads.h"
|
||||
#include "srslte/interfaces/enb_interfaces.h"
|
||||
#include "common_enb.h"
|
||||
|
|
|
@ -78,7 +78,6 @@ uint32_t dl_metric_rr::get_required_rbg(sched_ue *user, uint32_t tti)
|
|||
|
||||
void dl_metric_rr::new_tti(std::map<uint16_t,sched_ue> &ue_db, uint32_t start_rb, uint32_t nof_rb, uint32_t nof_ctrl_symbols_, uint32_t tti)
|
||||
{
|
||||
|
||||
total_rb = start_rb+nof_rb;
|
||||
for (uint32_t i=0;i<total_rb;i++) {
|
||||
if (i<start_rb) {
|
||||
|
@ -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;
|
||||
used_rb_mask = calc_rbg_mask(used_rb);
|
||||
current_tti = tti;
|
||||
nof_ctrl_symbols = nof_ctrl_symbols_;
|
||||
|
||||
nof_users_with_data = 0;
|
||||
for(std::map<uint16_t, sched_ue>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
|
||||
sched_ue *user = (sched_ue*) &iter->second;
|
||||
if (user->get_pending_dl_new_data(current_tti) || user->get_pending_dl_harq(current_tti)) {
|
||||
user->ue_idx = nof_users_with_data;
|
||||
nof_users_with_data++;
|
||||
current_tti = tti;
|
||||
nof_ctrl_symbols = nof_ctrl_symbols_;
|
||||
|
||||
if(ue_db.size()==0)
|
||||
return;
|
||||
|
||||
// give priority in a time-domain RR basis
|
||||
uint32_t priority_idx = current_tti % ue_db.size();
|
||||
std::map<uint16_t, sched_ue>::iterator iter = ue_db.begin();
|
||||
std::advance(iter,priority_idx);
|
||||
for(uint32_t ue_count = 0 ; ue_count < ue_db.size() ; ++iter, ++ue_count) {
|
||||
if(iter==ue_db.end()) {
|
||||
iter = ue_db.begin(); // wrap around
|
||||
}
|
||||
sched_ue *user = (sched_ue*) &iter->second;
|
||||
user->dl_next_alloc = apply_user_allocation(user);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,25 +141,11 @@ bool dl_metric_rr::allocation_is_valid(uint32_t mask)
|
|||
return (mask & used_rb_mask);
|
||||
}
|
||||
|
||||
dl_harq_proc* dl_metric_rr::get_user_allocation(sched_ue *user)
|
||||
{
|
||||
uint32_t pending_data = user->get_pending_dl_new_data(current_tti);
|
||||
dl_harq_proc* dl_metric_rr::apply_user_allocation(sched_ue *user) {
|
||||
uint32_t pending_data = user->get_pending_dl_new_data(current_tti);
|
||||
dl_harq_proc *h = user->get_pending_dl_harq(current_tti);
|
||||
|
||||
// Time-domain RR scheduling
|
||||
#if ASYNC_DL_SCHED
|
||||
if (pending_data || h) {
|
||||
#else
|
||||
if (pending_data || (h && !h->is_empty())) {
|
||||
#endif
|
||||
if (nof_users_with_data) {
|
||||
if ((current_tti%nof_users_with_data) != user->ue_idx) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Schedule retx if we have space
|
||||
// Schedule retx if we have space
|
||||
#if ASYNC_DL_SCHED
|
||||
if (h) {
|
||||
#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 (!allocation_is_valid(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);
|
||||
if (nof_rbg < available_rb) {
|
||||
if (new_allocation(nof_rbg, &retx_mask)) {
|
||||
update_allocation(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 ASYNC_DL_SCHED
|
||||
h = user->get_empty_dl_harq();
|
||||
h = user->get_empty_dl_harq();
|
||||
if (h) {
|
||||
#else
|
||||
if (h && h->is_empty()) {
|
||||
if (h && h->is_empty()) {
|
||||
#endif
|
||||
// Allocate resources based on pending data
|
||||
if (pending_data) {
|
||||
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);
|
||||
if (newtx_mask) {
|
||||
update_allocation(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_;
|
||||
bzero(used_rb, nof_rb*sizeof(bool));
|
||||
|
||||
nof_users_with_data = 0;
|
||||
for(std::map<uint16_t, sched_ue>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
|
||||
sched_ue *user = (sched_ue*) &iter->second;
|
||||
if (user->get_pending_ul_new_data(current_tti) || !user->get_ul_harq(current_tti)->is_empty(0)) {
|
||||
user->ue_idx = nof_users_with_data;
|
||||
nof_users_with_data++;
|
||||
}
|
||||
}
|
||||
if(ue_db.size()==0)
|
||||
return;
|
||||
|
||||
// give priority in a time-domain RR basis
|
||||
uint32_t priority_idx = (current_tti+ue_db.size()/2) % ue_db.size(); // make DL and UL interleaved
|
||||
std::map<uint16_t, sched_ue>::iterator iter = ue_db.begin();
|
||||
std::advance(iter,priority_idx);
|
||||
for(uint32_t ue_count = 0 ; ue_count < ue_db.size() ; ++iter, ++ue_count) {
|
||||
if(iter==ue_db.end()) {
|
||||
iter = ue_db.begin(); // wrap around
|
||||
}
|
||||
sched_ue *user = (sched_ue*) &iter->second;
|
||||
user->ul_next_alloc = apply_user_allocation(user);
|
||||
}
|
||||
}
|
||||
|
||||
bool ul_metric_rr::allocation_is_valid(ul_harq_proc::ul_alloc_t alloc)
|
||||
|
@ -288,56 +291,49 @@ void ul_metric_rr::update_allocation(ul_harq_proc::ul_alloc_t alloc)
|
|||
available_rb -= alloc.L;
|
||||
}
|
||||
|
||||
ul_harq_proc* ul_metric_rr::get_user_allocation(sched_ue *user)
|
||||
{
|
||||
ul_harq_proc* ul_metric_rr::apply_user_allocation(sched_ue *user) {
|
||||
// Time-domain RR scheduling
|
||||
uint32_t pending_data = user->get_pending_ul_new_data(current_tti);
|
||||
uint32_t pending_data = user->get_pending_ul_new_data(current_tti);
|
||||
ul_harq_proc *h = user->get_ul_harq(current_tti);
|
||||
|
||||
if (pending_data || !h->is_empty(0)) {
|
||||
if (nof_users_with_data) {
|
||||
if ((current_tti%nof_users_with_data) != user->ue_idx) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Schedule retx if we have space
|
||||
|
||||
// Schedule retx if we have space
|
||||
if (!h->is_empty(0)) {
|
||||
|
||||
ul_harq_proc::ul_alloc_t alloc = h->get_alloc();
|
||||
|
||||
|
||||
// If can schedule the same mask, do it
|
||||
if (allocation_is_valid(alloc)) {
|
||||
update_allocation(alloc);
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
// If not, try to find another mask in the current tti
|
||||
if (new_allocation(alloc.L, &alloc)) {
|
||||
update_allocation(alloc);
|
||||
h->set_alloc(alloc);
|
||||
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)) {
|
||||
// Allocate resources based on pending data
|
||||
// Allocate resources based on pending data
|
||||
if (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);
|
||||
if (alloc.L) {
|
||||
update_allocation(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)
|
||||
{
|
||||
log_h = NULL;
|
||||
|
|
|
@ -142,7 +142,7 @@ void ue::set_tti(uint32_t tti) {
|
|||
|
||||
#include <assert.h>
|
||||
|
||||
void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, uint32_t tstamp)
|
||||
void ue::process_pdu(uint8_t* pdu, uint32_t nof_bytes, srslte::pdu_queue::channel_t channel, uint32_t tstamp)
|
||||
{
|
||||
// Unpack ULSCH MAC PDU
|
||||
mac_msg_ul.init_rx(nof_bytes, true);
|
||||
|
|
|
@ -121,7 +121,7 @@ uint32_t rrc::generate_sibs()
|
|||
|
||||
// msg is array of SI messages, each SI message msg[i] may contain multiple SIBs
|
||||
// all SIBs in a SI message msg[i] share the same periodicity
|
||||
LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT *msg = (LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT*)calloc(nof_messages, sizeof(LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT));
|
||||
LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT *msg = (LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT*)calloc(nof_messages+1, sizeof(LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT));
|
||||
|
||||
// Copy SIB1 to first SI message
|
||||
msg[0].N_sibs = 1;
|
||||
|
@ -1090,9 +1090,13 @@ void rrc::ue::notify_s1ap_ue_ctxt_setup_complete()
|
|||
void rrc::ue::notify_s1ap_ue_erab_setup_response(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e)
|
||||
{
|
||||
LIBLTE_S1AP_MESSAGE_E_RABSETUPRESPONSE_STRUCT res;
|
||||
res.ext=false;
|
||||
res.E_RABSetupListBearerSURes.len = 0;
|
||||
res.E_RABFailedToSetupListBearerSURes.len = 0;
|
||||
|
||||
res.CriticalityDiagnostics_present = false;
|
||||
res.E_RABFailedToSetupListBearerSURes_present = false;
|
||||
|
||||
for(uint32_t i=0; i<e->len; i++) {
|
||||
res.E_RABSetupListBearerSURes_present = true;
|
||||
LIBLTE_S1AP_E_RABTOBESETUPITEMBEARERSUREQ_STRUCT *erab = &e->buffer[i];
|
||||
|
@ -1447,6 +1451,8 @@ void rrc::ue::send_connection_reconf(srslte::byte_buffer_t *pdu)
|
|||
// Get DRB1 configuration
|
||||
if (get_drbid_config(&conn_reconf->rr_cnfg_ded.drb_to_add_mod_list[0], 1)) {
|
||||
parent->rrc_log->error("Getting DRB1 configuration\n");
|
||||
printf("The QCI %d for DRB1 is invalid or not configured.\n", erabs[5].qos_params.qCI.QCI);
|
||||
return;
|
||||
} else {
|
||||
conn_reconf->rr_cnfg_ded.drb_to_add_mod_list_size = 1;
|
||||
}
|
||||
|
@ -1524,8 +1530,10 @@ void rrc::ue::send_connection_reconf_new_bearer(LIBLTE_S1AP_E_RABTOBESETUPLISTBE
|
|||
uint8_t lcid = id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1)
|
||||
|
||||
// Get DRB configuration
|
||||
if (get_drbid_config(&conn_reconf->rr_cnfg_ded.drb_to_add_mod_list[i], lcid)) {
|
||||
parent->rrc_log->error("Getting DRB configuration\n");
|
||||
if (get_drbid_config(&conn_reconf->rr_cnfg_ded.drb_to_add_mod_list[i], lcid-2)) {
|
||||
parent->rrc_log->error("Getting DRB configuration\n");
|
||||
printf("ERROR: The QCI %d is invalid or not configured.\n", erabs[lcid+4].qos_params.qCI.QCI);
|
||||
return;
|
||||
} else {
|
||||
conn_reconf->rr_cnfg_ded.drb_to_add_mod_list_size++;
|
||||
}
|
||||
|
|
|
@ -1806,7 +1806,7 @@ s1ap_nas_transport::pack_attach_accept(ue_emm_ctx_t *ue_emm_ctx, ue_ecm_ctx_t *u
|
|||
act_def_eps_bearer_context_req.eps_qos.mbr_dl_ext = 250; //FIXME check
|
||||
|
||||
//set apn
|
||||
act_def_eps_bearer_context_req.apn.apn = m_s1ap->m_s1ap_args.mme_apn;
|
||||
strncpy(act_def_eps_bearer_context_req.apn.apn, m_s1ap->m_s1ap_args.mme_apn.c_str(), LIBLTE_STRING_LEN);
|
||||
act_def_eps_bearer_context_req.proc_transaction_id = ue_emm_ctx->procedure_transaction_id; //FIXME
|
||||
|
||||
//Set DNS server
|
||||
|
@ -1933,10 +1933,10 @@ s1ap_nas_transport::pack_emm_information( ue_ctx_t *ue_ctx, srslte::byte_buffer_
|
|||
|
||||
LIBLTE_MME_EMM_INFORMATION_MSG_STRUCT emm_info;
|
||||
emm_info.full_net_name_present = true;
|
||||
emm_info.full_net_name.name = std::string("Software Radio Systems LTE");
|
||||
strncpy(emm_info.full_net_name.name, "Software Radio Systems LTE", LIBLTE_STRING_LEN);
|
||||
emm_info.full_net_name.add_ci = LIBLTE_MME_ADD_CI_DONT_ADD;
|
||||
emm_info.short_net_name_present = true;
|
||||
emm_info.short_net_name.name = std::string("srsLTE");
|
||||
strncpy(emm_info.short_net_name.name, "srsLTE", LIBLTE_STRING_LEN);
|
||||
emm_info.short_net_name.add_ci = LIBLTE_MME_ADD_CI_DONT_ADD;
|
||||
|
||||
emm_info.local_time_zone_present = false;
|
||||
|
|
|
@ -51,12 +51,13 @@ public:
|
|||
|
||||
void push_pdu(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp);
|
||||
void push_pdu_bcch(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp);
|
||||
void push_pdu_mch(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp);
|
||||
void push_pdu_temp_crnti(uint8_t *buff, uint32_t nof_bytes);
|
||||
|
||||
void set_uecrid_callback(bool (*callback)(void*, uint64_t), void *arg);
|
||||
bool get_uecrid_successful();
|
||||
|
||||
void process_pdu(uint8_t *pdu, uint32_t nof_bytes, uint32_t tstamp);
|
||||
|
||||
void process_pdu(uint8_t *pdu, uint32_t nof_bytes, srslte::pdu_queue::channel_t channel, uint32_t tstamp);
|
||||
|
||||
private:
|
||||
const static int MAX_PDU_LEN = 150*1024/8; // ~ 150 Mbps
|
||||
|
|
|
@ -50,7 +50,7 @@ class mac
|
|||
,public mac_interface_rrc
|
||||
,public srslte::timer_callback
|
||||
,public srslte::mac_interface_timers
|
||||
,public thread
|
||||
,public periodic_thread
|
||||
{
|
||||
public:
|
||||
mac();
|
||||
|
@ -68,15 +68,13 @@ public:
|
|||
void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid);
|
||||
void bch_decoded_ok(uint8_t *payload, uint32_t len);
|
||||
void pch_decoded_ok(uint32_t len);
|
||||
void tti_clock(uint32_t tti);
|
||||
|
||||
|
||||
/******** Interface from RLC (RLC -> MAC) ****************/
|
||||
void bcch_start_rx();
|
||||
void bcch_stop_rx();
|
||||
void bcch_start_rx(int si_window_start, int si_window_length);
|
||||
void pcch_start_rx();
|
||||
void pcch_stop_rx();
|
||||
void clear_rntis();
|
||||
void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD);
|
||||
void reconfiguration();
|
||||
void reset();
|
||||
|
@ -110,15 +108,14 @@ public:
|
|||
|
||||
|
||||
private:
|
||||
void run_thread();
|
||||
void run_period();
|
||||
|
||||
static const int MAC_MAIN_THREAD_PRIO = -1; // Use default high-priority below UHD
|
||||
static const int MAC_PDU_THREAD_PRIO = DEFAULT_PRIORITY-5;
|
||||
static const int MAC_NOF_HARQ_PROC = 2*HARQ_DELAY_MS;
|
||||
|
||||
// Interaction with PHY
|
||||
srslte::tti_sync_cv ttisync;
|
||||
phy_interface_mac *phy_h;
|
||||
phy_interface_mac *phy_h;
|
||||
rlc_interface_mac *rlc_h;
|
||||
rrc_interface_mac *rrc_h;
|
||||
srslte::log *log_h;
|
||||
|
@ -130,11 +127,7 @@ private:
|
|||
ue_rnti_t uernti;
|
||||
|
||||
uint32_t tti;
|
||||
bool started;
|
||||
bool is_synchronized;
|
||||
uint16_t last_temporal_crnti;
|
||||
uint16_t phy_rnti;
|
||||
|
||||
|
||||
/* Multiplexing/Demultiplexing Units */
|
||||
mux mux_unit;
|
||||
demux demux_unit;
|
||||
|
@ -168,19 +161,6 @@ private:
|
|||
|
||||
mac_metrics_t metrics;
|
||||
|
||||
/* Class to run Timers in a dedicated thread */
|
||||
class mac_timers : public periodic_thread {
|
||||
public:
|
||||
void init(srslte::timers *timers, srslte::log *log_h);
|
||||
private:
|
||||
void run_period();
|
||||
srslte::timers *timers;
|
||||
bool running;
|
||||
srslte::log *log_h;
|
||||
};
|
||||
|
||||
mac_timers mactimers;
|
||||
|
||||
/* Class to process MAC PDUs from DEMUX unit */
|
||||
class pdu_process : public thread {
|
||||
public:
|
||||
|
|
|
@ -27,9 +27,6 @@
|
|||
#ifndef SRSUE_PHCH_COMMON_H
|
||||
#define SRSUE_PHCH_COMMON_H
|
||||
|
||||
#define TX_MODE_CONTINUOUS 1
|
||||
|
||||
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
@ -68,15 +65,17 @@ public:
|
|||
float cur_radio_power;
|
||||
float cur_pusch_power;
|
||||
float avg_rsrp;
|
||||
float avg_rsrp_cqi;
|
||||
float avg_rsrp_dbm;
|
||||
float avg_rsrp_sync_dbm;
|
||||
float avg_rsrq_db;
|
||||
float avg_rssi_dbm;
|
||||
float last_radio_rssi;
|
||||
float rx_gain_offset;
|
||||
float avg_snr_db;
|
||||
float avg_snr_db_cqi;
|
||||
float avg_snr_db_sync;
|
||||
float avg_noise;
|
||||
|
||||
bool pcell_meas_enabled;
|
||||
uint32_t pcell_report_period;
|
||||
|
||||
// Save last TBS for mcs>28 cases
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#define SRSUE_PHCH_RECV_H
|
||||
|
||||
#include <map>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "srslte/srslte.h"
|
||||
#include "srslte/common/log.h"
|
||||
|
@ -50,29 +51,23 @@ class phch_recv : public thread, public chest_feedback_itf
|
|||
public:
|
||||
phch_recv();
|
||||
~phch_recv();
|
||||
|
||||
void init(srslte::radio_multi* radio_handler, mac_interface_phy *mac,rrc_interface_phy *rrc,
|
||||
prach *prach_buffer, srslte::thread_pool *_workers_pool,
|
||||
phch_common *_worker_com, srslte::log* _log_h, srslte::log *_log_phy_lib_h, uint32_t nof_rx_antennas, uint32_t prio, int sync_cpu_affinity = -1);
|
||||
void stop();
|
||||
void set_agc_enable(bool enable);
|
||||
void radio_overflow();
|
||||
|
||||
void set_earfcn(std::vector<uint32_t> earfcn);
|
||||
void force_freq(float dl_freq, float ul_freq);
|
||||
|
||||
void reset_sync();
|
||||
void cell_search_start();
|
||||
void cell_search_next(bool reset = false);
|
||||
void cell_select(uint32_t earfcn, srslte_cell_t cell);
|
||||
bool cell_handover(srslte_cell_t cell);
|
||||
// RRC interface for controling the SYNC state
|
||||
phy_interface_rrc::cell_search_ret_t cell_search(phy_interface_rrc::phy_cell_t *cell);
|
||||
bool cell_select(phy_interface_rrc::phy_cell_t *cell);
|
||||
bool cell_is_camping();
|
||||
|
||||
// RRC interface for controlling the neighbour cell measurement
|
||||
void meas_reset();
|
||||
int meas_start(uint32_t earfcn, int pci);
|
||||
int meas_stop(uint32_t earfcn, int pci);
|
||||
|
||||
uint32_t get_current_tti();
|
||||
|
||||
bool status_is_sync();
|
||||
|
||||
// from chest_feedback_itf
|
||||
void in_sync();
|
||||
void out_of_sync();
|
||||
|
@ -80,37 +75,21 @@ public:
|
|||
|
||||
void set_time_adv_sec(float time_adv_sec);
|
||||
void get_current_cell(srslte_cell_t *cell, uint32_t *earfcn = NULL);
|
||||
uint32_t get_current_tti();
|
||||
|
||||
// From UE configuration
|
||||
void set_agc_enable(bool enable);
|
||||
void set_earfcn(std::vector<uint32_t> earfcn);
|
||||
void force_freq(float dl_freq, float ul_freq);
|
||||
|
||||
// Other functions
|
||||
const static int MUTEX_X_WORKER = 4;
|
||||
|
||||
double set_rx_gain(double gain);
|
||||
int radio_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time);
|
||||
int scell_recv_fnc(cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time);
|
||||
|
||||
private:
|
||||
|
||||
std::vector<uint32_t> earfcn;
|
||||
|
||||
void reset();
|
||||
void radio_error();
|
||||
void set_ue_sync_opts(srslte_ue_sync_t *q, float cfo);
|
||||
void run_thread();
|
||||
|
||||
void set_sampling_rate();
|
||||
bool set_frequency();
|
||||
bool set_cell();
|
||||
|
||||
void cell_search_inc();
|
||||
void cell_reselect();
|
||||
|
||||
float get_cfo();
|
||||
|
||||
uint32_t new_earfcn;
|
||||
srslte_cell_t new_cell;
|
||||
|
||||
bool running;
|
||||
|
||||
// Class to run cell search
|
||||
class search {
|
||||
public:
|
||||
|
@ -119,9 +98,7 @@ private:
|
|||
~search();
|
||||
void init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, phch_recv *parent);
|
||||
void reset();
|
||||
float get_last_gain();
|
||||
float get_last_cfo();
|
||||
void set_N_id_2(int N_id_2);
|
||||
void set_agc_enable(bool enable);
|
||||
ret_code run(srslte_cell_t *cell);
|
||||
|
||||
|
@ -137,22 +114,23 @@ private:
|
|||
// Class to synchronize system frame number
|
||||
class sfn_sync {
|
||||
public:
|
||||
typedef enum {IDLE, SFN_FOUND, SFX0_FOUND, ERROR, TIMEOUT} ret_code;
|
||||
typedef enum {IDLE, SFN_FOUND, SFX0_FOUND, SFN_NOFOUND, ERROR} ret_code;
|
||||
|
||||
~sfn_sync();
|
||||
void init(srslte_ue_sync_t *ue_sync, cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t timeout = SYNC_SFN_TIMEOUT);
|
||||
void init(srslte_ue_sync_t *ue_sync, cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_subframes = SFN_SYNC_NOF_SUBFRAMES);
|
||||
void reset();
|
||||
bool set_cell(srslte_cell_t cell);
|
||||
ret_code run_subframe(srslte_cell_t *cell, uint32_t *tti_cnt, bool sfidx_only = false);
|
||||
|
||||
private:
|
||||
const static int SFN_SYNC_NOF_SUBFRAMES = 100;
|
||||
|
||||
uint32_t cnt;
|
||||
uint32_t timeout;
|
||||
srslte::log *log_h;
|
||||
srslte_ue_sync_t *ue_sync;
|
||||
cf_t *buffer[SRSLTE_MAX_PORTS];
|
||||
srslte_ue_mib_t ue_mib;
|
||||
uint32_t cnt;
|
||||
uint32_t timeout;
|
||||
const static uint32_t SYNC_SFN_TIMEOUT = 80;
|
||||
};
|
||||
|
||||
// Class to perform cell measurements
|
||||
|
@ -170,7 +148,7 @@ private:
|
|||
void set_cell(srslte_cell_t cell);
|
||||
ret_code run_subframe(uint32_t sf_idx);
|
||||
ret_code run_subframe_sync(srslte_ue_sync_t *ue_sync, uint32_t sf_idx);
|
||||
ret_code run_multiple_subframes(cf_t *buffer, int offset, uint32_t sf_idx, uint32_t nof_sf);
|
||||
ret_code run_multiple_subframes(cf_t *buffer, uint32_t offset, uint32_t sf_idx, uint32_t nof_sf);
|
||||
float rssi();
|
||||
float rsrp();
|
||||
float rsrq();
|
||||
|
@ -261,9 +239,26 @@ private:
|
|||
// 36.133 9.1.2.1 for band 7
|
||||
const static float ABSOLUTE_RSRP_THRESHOLD_DBM = -125;
|
||||
|
||||
std::vector<uint32_t> earfcn;
|
||||
|
||||
void reset();
|
||||
void radio_error();
|
||||
void set_ue_sync_opts(srslte_ue_sync_t *q, float cfo);
|
||||
void run_thread();
|
||||
float get_tx_cfo();
|
||||
|
||||
void set_sampling_rate();
|
||||
bool set_frequency();
|
||||
bool set_cell();
|
||||
|
||||
uint32_t new_earfcn;
|
||||
srslte_cell_t new_cell;
|
||||
|
||||
bool radio_is_overflow;
|
||||
bool radio_overflow_return;
|
||||
bool running;
|
||||
|
||||
// Objects for internal use
|
||||
measure measure_p;
|
||||
search search_p;
|
||||
sfn_sync sfn_p;
|
||||
intra_measure intra_freq_meas;
|
||||
|
@ -298,19 +293,128 @@ private:
|
|||
const static uint32_t NOF_OUT_OF_SYNC_SF = 200;
|
||||
const static uint32_t NOF_IN_SYNC_SF = 100;
|
||||
|
||||
// State for primary cell
|
||||
typedef enum {
|
||||
IDLE = 0,
|
||||
CELL_SEARCH,
|
||||
CELL_SELECT,
|
||||
CELL_RESELECT,
|
||||
CELL_MEASURE,
|
||||
CELL_CAMP,
|
||||
} phy_state_t;
|
||||
// State machine for SYNC thread
|
||||
class sync_state {
|
||||
public:
|
||||
typedef enum {
|
||||
IDLE = 0,
|
||||
CELL_SEARCH,
|
||||
SFN_SYNC,
|
||||
CAMPING,
|
||||
} state_t;
|
||||
|
||||
phy_state_t phy_state, prev_state;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
bool is_in_idle;
|
||||
// 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;
|
||||
|
||||
sync_state phy_state;
|
||||
|
||||
search::ret_code cell_search_ret;
|
||||
|
||||
// Sampling rate mode (find is 1.96 MHz, camp is the full cell BW)
|
||||
enum {
|
||||
|
@ -320,9 +424,8 @@ private:
|
|||
|
||||
// This is the primary cell
|
||||
srslte_cell_t cell;
|
||||
bool cell_is_set;
|
||||
bool started;
|
||||
float time_adv_sec;
|
||||
float time_adv_sec, next_time_adv_sec;
|
||||
uint32_t tti;
|
||||
bool do_agc;
|
||||
|
||||
|
@ -330,8 +433,8 @@ private:
|
|||
uint32_t tx_mutex_cnt;
|
||||
|
||||
float ul_dl_factor;
|
||||
uint32_t current_earfcn;
|
||||
int cur_earfcn_index;
|
||||
int current_earfcn;
|
||||
uint32_t cellsearch_earfcn_index;
|
||||
|
||||
float dl_freq;
|
||||
float ul_freq;
|
||||
|
|
|
@ -53,6 +53,7 @@ public:
|
|||
cf_t* get_buffer(uint32_t antenna_idx);
|
||||
void set_tti(uint32_t tti, uint32_t tx_tti);
|
||||
void set_tx_time(srslte_timestamp_t tx_time, uint32_t next_offset);
|
||||
void set_prach(cf_t *prach_ptr, float prach_power);
|
||||
void set_cfo(float cfo);
|
||||
|
||||
void set_ul_params(bool pregen_disabled = false);
|
||||
|
@ -169,6 +170,8 @@ private:
|
|||
bool sr_configured;
|
||||
float cfo;
|
||||
bool rar_cqi_request;
|
||||
cf_t *prach_ptr;
|
||||
float prach_power;
|
||||
|
||||
uint32_t rssi_read_cnt;
|
||||
|
||||
|
|
|
@ -82,21 +82,18 @@ public:
|
|||
|
||||
/********** RRC INTERFACE ********************/
|
||||
void reset();
|
||||
void sync_reset();
|
||||
void configure_ul_params(bool pregen_disabled = false);
|
||||
void cell_search_start();
|
||||
void cell_search_next();
|
||||
void cell_select(uint32_t earfcn, srslte_cell_t phy_cell);
|
||||
bool cell_handover(srslte_cell_t cell);
|
||||
cell_search_ret_t cell_search(phy_cell_t *cell);
|
||||
bool cell_select(phy_cell_t *cell);
|
||||
|
||||
void meas_reset();
|
||||
int meas_start(uint32_t earfcn, int pci);
|
||||
int meas_stop(uint32_t earfcn, int pci);
|
||||
|
||||
/********** MAC INTERFACE ********************/
|
||||
/* Functions to synchronize with a cell */
|
||||
bool sync_status(); // this is also RRC interface
|
||||
// also MAC interface
|
||||
bool cell_is_camping();
|
||||
|
||||
/********** MAC INTERFACE ********************/
|
||||
/* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */
|
||||
void set_crnti(uint16_t rnti);
|
||||
|
||||
|
|
|
@ -58,13 +58,11 @@ namespace srsue {
|
|||
bool is_ready_to_send(uint32_t current_tti);
|
||||
bool is_pending();
|
||||
int tx_tti();
|
||||
|
||||
void send(srslte::radio* radio_handler, float cfo, float pathloss, srslte_timestamp_t rx_time);
|
||||
float get_p0_preamble();
|
||||
|
||||
static const uint32_t tx_advance_sf = 4; // Number of subframes to advance transmission
|
||||
|
||||
private:
|
||||
cf_t* generate(float cfo, uint32_t *nof_sf, float *target_power = NULL);
|
||||
|
||||
private:
|
||||
|
||||
const static int MAX_LEN_SF = 3;
|
||||
|
||||
LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config;
|
||||
phy_args_t *args;
|
||||
|
@ -81,7 +79,7 @@ namespace srsue {
|
|||
srslte_cell_t cell;
|
||||
cf_t *signal_buffer;
|
||||
srslte_cfo_t cfo_h;
|
||||
float target_power_dbm;
|
||||
float target_power_dbm;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -69,6 +69,8 @@ public:
|
|||
|
||||
bool init(all_args_t *args_);
|
||||
void stop();
|
||||
bool attach();
|
||||
bool deattach();
|
||||
bool is_attached();
|
||||
void start_plot();
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ typedef struct {
|
|||
std::string device_args;
|
||||
std::string time_adv_nsamples;
|
||||
std::string burst_preamble;
|
||||
std::string continuous_tx;
|
||||
}rf_args_t;
|
||||
|
||||
typedef struct {
|
||||
|
@ -112,6 +113,7 @@ typedef struct {
|
|||
phy_args_t phy;
|
||||
float metrics_period_secs;
|
||||
bool pregenerate_signals;
|
||||
bool print_buffer_state;
|
||||
bool metrics_csv_enable;
|
||||
std::string metrics_csv_filename;
|
||||
}expert_args_t;
|
||||
|
@ -155,6 +157,8 @@ public:
|
|||
|
||||
virtual bool init(all_args_t *args_) = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual bool attach() = 0;
|
||||
virtual bool deattach() = 0;
|
||||
virtual bool is_attached() = 0;
|
||||
virtual void start_plot() = 0;
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#include "srslte/common/buffer_pool.h"
|
||||
#include "srslte/common/log.h"
|
||||
#include "srslte/common/common.h"
|
||||
#include "srslte/common/msg_queue.h"
|
||||
#include "srslte/common/interfaces_common.h"
|
||||
#include "srslte/interfaces/ue_interfaces.h"
|
||||
#include "srslte/common/threads.h"
|
||||
|
|
|
@ -43,29 +43,20 @@ namespace srsue {
|
|||
typedef enum {
|
||||
EMM_STATE_NULL = 0,
|
||||
EMM_STATE_DEREGISTERED,
|
||||
EMM_STATE_REGISTERED_INITIATED,
|
||||
EMM_STATE_REGISTERED,
|
||||
EMM_STATE_SERVICE_REQUEST_INITIATED,
|
||||
EMM_STATE_DEREGISTERED_INITIATED,
|
||||
EMM_STATE_TAU_INITIATED,
|
||||
EMM_STATE_N_ITEMS,
|
||||
} emm_state_t;
|
||||
static const char emm_state_text[EMM_STATE_N_ITEMS][100] = {"NULL",
|
||||
"DEREGISTERED",
|
||||
"REGISTERED INITIATED",
|
||||
"REGISTERED",
|
||||
"SERVICE REQUEST INITIATED",
|
||||
"DEREGISTERED INITIATED",
|
||||
"TRACKING AREA UPDATE INITIATED"};
|
||||
|
||||
static const bool eia_caps[8] = {false, true, true, false, false, false, false, false};
|
||||
static const bool eea_caps[8] = {true, true, true, false, false, false, false, false};
|
||||
|
||||
typedef enum {
|
||||
PLMN_NOT_SELECTED = 0,
|
||||
PLMN_SELECTED
|
||||
} plmn_selection_state_t;
|
||||
|
||||
class nas
|
||||
: public nas_interface_rrc,
|
||||
public nas_interface_ue,
|
||||
|
@ -83,20 +74,16 @@ public:
|
|||
emm_state_t get_state();
|
||||
|
||||
// RRC interface
|
||||
void notify_connection_setup();
|
||||
void paging(LIBLTE_RRC_S_TMSI_STRUCT *ue_identiy);
|
||||
void set_barring(barring_t barring);
|
||||
void write_pdu(uint32_t lcid, byte_buffer_t *pdu);
|
||||
uint32_t get_ul_count();
|
||||
bool is_attached();
|
||||
bool is_attaching();
|
||||
bool is_data_requested();
|
||||
bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi);
|
||||
bool get_k_asme(uint8_t *k_asme_, uint32_t n);
|
||||
bool plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code);
|
||||
void plmn_search_end();
|
||||
|
||||
// UE interface
|
||||
void attach_request();
|
||||
void deattach_request();
|
||||
bool attach_request();
|
||||
bool deattach_request();
|
||||
|
||||
// PCAP
|
||||
void start_pcap(srslte::nas_pcap *pcap_);
|
||||
|
@ -112,9 +99,10 @@ private:
|
|||
|
||||
emm_state_t state;
|
||||
|
||||
plmn_selection_state_t plmn_selection;
|
||||
nas_interface_rrc::barring_t current_barring;
|
||||
|
||||
bool plmn_is_selected;
|
||||
LIBLTE_RRC_PLMN_IDENTITY_STRUCT current_plmn;
|
||||
LIBLTE_RRC_PLMN_IDENTITY_STRUCT selecting_plmn;
|
||||
LIBLTE_RRC_PLMN_IDENTITY_STRUCT home_plmn;
|
||||
|
||||
std::vector<LIBLTE_RRC_PLMN_IDENTITY_STRUCT > known_plmns;
|
||||
|
@ -148,6 +136,10 @@ private:
|
|||
// PCAP
|
||||
srslte::nas_pcap *pcap = NULL;
|
||||
|
||||
bool running;
|
||||
|
||||
bool rrc_connect();
|
||||
|
||||
void integrity_generate(uint8_t *key_128,
|
||||
uint32_t count,
|
||||
uint8_t direction,
|
||||
|
@ -160,6 +152,8 @@ private:
|
|||
|
||||
bool check_cap_replay(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT *caps);
|
||||
|
||||
void select_plmn();
|
||||
|
||||
// Parsers
|
||||
void parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu);
|
||||
void parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu);
|
||||
|
@ -171,10 +165,12 @@ private:
|
|||
void parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu);
|
||||
void parse_emm_information(uint32_t lcid, byte_buffer_t *pdu);
|
||||
|
||||
// Packet generators
|
||||
void gen_attach_request(byte_buffer_t *msg);
|
||||
void gen_service_request(byte_buffer_t *msg);
|
||||
|
||||
// Senders
|
||||
void send_attach_request();
|
||||
void send_identity_response();
|
||||
void send_service_request();
|
||||
void send_esm_information_response();
|
||||
void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg);
|
||||
void send_security_mode_reject(uint8_t cause);
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "srslte/interfaces/ue_interfaces.h"
|
||||
#include "srslte/common/security.h"
|
||||
#include "srslte/common/threads.h"
|
||||
#include "srslte/common/block_queue.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <map>
|
||||
|
@ -52,21 +53,21 @@ using srslte::byte_buffer_t;
|
|||
|
||||
namespace srsue {
|
||||
|
||||
|
||||
class cell_t
|
||||
{
|
||||
public:
|
||||
bool is_valid() {
|
||||
return earfcn != 0 && srslte_cell_isvalid(&phy_cell);
|
||||
return phy_cell.earfcn != 0 && srslte_cell_isvalid(&phy_cell.cell);
|
||||
}
|
||||
bool equals(cell_t *x) {
|
||||
return equals(x->earfcn, x->phy_cell.id);
|
||||
return equals(x->phy_cell.earfcn, x->phy_cell.cell.id);
|
||||
}
|
||||
bool equals(uint32_t earfcn, uint32_t pci) {
|
||||
return earfcn == this->earfcn && pci == phy_cell.id;
|
||||
return earfcn == this->phy_cell.earfcn && pci == phy_cell.cell.id;
|
||||
}
|
||||
// NaN means an RSRP value has not yet been obtained. Keep then in the list and clean them if never updated
|
||||
bool greater(cell_t *x) {
|
||||
return rsrp > x->rsrp;
|
||||
return rsrp > x->rsrp || isnan(rsrp);
|
||||
}
|
||||
bool plmn_equals(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) {
|
||||
if (has_valid_sib1) {
|
||||
|
@ -78,11 +79,39 @@ class cell_t
|
|||
}
|
||||
return false;
|
||||
}
|
||||
cell_t() {
|
||||
srslte_cell_t tmp = {};
|
||||
cell_t(tmp, 0, 0);
|
||||
|
||||
uint32_t nof_plmns() {
|
||||
if (has_valid_sib1) {
|
||||
return sib1.N_plmn_ids;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
cell_t(srslte_cell_t phy_cell, uint32_t earfcn, float rsrp) {
|
||||
|
||||
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() {
|
||||
phy_interface_rrc::phy_cell_t tmp = {};
|
||||
cell_t(tmp, 0);
|
||||
}
|
||||
cell_t(phy_interface_rrc::phy_cell_t phy_cell, float rsrp) {
|
||||
gettimeofday(&last_update, NULL);
|
||||
this->has_valid_sib1 = false;
|
||||
this->has_valid_sib2 = false;
|
||||
|
@ -90,7 +119,6 @@ class cell_t
|
|||
this->has_valid_sib13 = false;
|
||||
this->phy_cell = phy_cell;
|
||||
this->rsrp = rsrp;
|
||||
this->earfcn = earfcn;
|
||||
in_sync = true;
|
||||
bzero(&sib1, sizeof(sib1));
|
||||
bzero(&sib2, sizeof(sib2));
|
||||
|
@ -99,15 +127,15 @@ class cell_t
|
|||
}
|
||||
|
||||
uint32_t get_earfcn() {
|
||||
return earfcn;
|
||||
return phy_cell.earfcn;
|
||||
}
|
||||
|
||||
uint32_t get_pci() {
|
||||
return phy_cell.id;
|
||||
return phy_cell.cell.id;
|
||||
}
|
||||
|
||||
void set_rsrp(float rsrp) {
|
||||
if (~isnan(rsrp)) {
|
||||
if (!isnan(rsrp)) {
|
||||
this->rsrp = rsrp;
|
||||
}
|
||||
in_sync = true;
|
||||
|
@ -170,6 +198,20 @@ class cell_t
|
|||
return has_valid_sib13;
|
||||
}
|
||||
|
||||
bool has_sib(uint32_t index) {
|
||||
switch(index) {
|
||||
case 0:
|
||||
return has_sib1();
|
||||
case 1:
|
||||
return has_sib2();
|
||||
case 2:
|
||||
return has_sib3();
|
||||
case 12:
|
||||
return has_sib13();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t get_mcc() {
|
||||
if (has_valid_sib1) {
|
||||
if (sib1.N_plmn_ids > 0) {
|
||||
|
@ -188,12 +230,11 @@ class cell_t
|
|||
return 0;
|
||||
}
|
||||
|
||||
srslte_cell_t phy_cell;
|
||||
phy_interface_rrc::phy_cell_t phy_cell;
|
||||
bool in_sync;
|
||||
|
||||
private:
|
||||
float rsrp;
|
||||
uint32_t earfcn;
|
||||
struct timeval last_update;
|
||||
|
||||
bool has_valid_sib1;
|
||||
|
@ -231,56 +272,61 @@ public:
|
|||
void stop();
|
||||
|
||||
rrc_state_t get_state();
|
||||
|
||||
void set_args(rrc_args_t *args);
|
||||
|
||||
// Timeout callback interface
|
||||
void timer_expired(uint32_t timeout_id);
|
||||
|
||||
void liblte_rrc_log(char *str);
|
||||
|
||||
|
||||
// NAS interface
|
||||
void write_sdu(uint32_t lcid, byte_buffer_t *sdu);
|
||||
|
||||
uint16_t get_mcc();
|
||||
|
||||
uint16_t get_mnc();
|
||||
|
||||
void enable_capabilities();
|
||||
void plmn_search();
|
||||
void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, bool connect_request);
|
||||
uint16_t get_mcc();
|
||||
uint16_t get_mnc();
|
||||
int plmn_search(found_plmn_t found_plmns[MAX_FOUND_PLMNS]);
|
||||
void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id);
|
||||
bool connection_request(LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM cause,
|
||||
srslte::byte_buffer_t *dedicatedInfoNAS);
|
||||
void set_ue_idenity(LIBLTE_RRC_S_TMSI_STRUCT s_tmsi);
|
||||
|
||||
// PHY interface
|
||||
void in_sync();
|
||||
void out_of_sync();
|
||||
void earfcn_end();
|
||||
void cell_camping(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp);
|
||||
void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn, int pci);
|
||||
|
||||
// MAC interface
|
||||
void ho_ra_completed(bool ra_successful);
|
||||
void release_pucch_srs();
|
||||
void run_tti(uint32_t tti);
|
||||
|
||||
void ra_problem();
|
||||
|
||||
// GW interface
|
||||
bool is_connected();
|
||||
|
||||
bool is_connected(); // this is also NAS interface
|
||||
bool have_drb();
|
||||
|
||||
// PDCP interface
|
||||
void write_pdu(uint32_t lcid, byte_buffer_t *pdu);
|
||||
|
||||
void write_pdu_bcch_bch(byte_buffer_t *pdu);
|
||||
|
||||
void write_pdu_bcch_dlsch(byte_buffer_t *pdu);
|
||||
|
||||
void write_pdu_pcch(byte_buffer_t *pdu);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
typedef struct {
|
||||
enum {
|
||||
PCCH,
|
||||
STOP
|
||||
} command;
|
||||
byte_buffer_t *pdu;
|
||||
} cmd_msg_t;
|
||||
|
||||
bool running;
|
||||
srslte::block_queue<cmd_msg_t> cmd_q;
|
||||
void run_thread();
|
||||
|
||||
void process_pcch(byte_buffer_t *pdu);
|
||||
|
||||
srslte::byte_buffer_pool *pool;
|
||||
srslte::log *rrc_log;
|
||||
phy_interface_rrc *phy;
|
||||
|
@ -295,6 +341,8 @@ private:
|
|||
LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg;
|
||||
LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg;
|
||||
|
||||
byte_buffer_t *dedicatedInfoNAS;
|
||||
|
||||
byte_buffer_t* byte_align_and_pack();
|
||||
void send_ul_ccch_msg();
|
||||
void send_ul_dcch_msg();
|
||||
|
@ -304,28 +352,22 @@ private:
|
|||
|
||||
rrc_state_t state;
|
||||
uint8_t transaction_id;
|
||||
LIBLTE_RRC_S_TMSI_STRUCT ueIdentity;
|
||||
bool ueIdentity_configured;
|
||||
|
||||
bool drb_up;
|
||||
|
||||
rrc_args_t args;
|
||||
bool first_stimsi_attempt;
|
||||
|
||||
uint32_t cell_clean_cnt;
|
||||
|
||||
uint16_t ho_src_rnti;
|
||||
cell_t ho_src_cell;
|
||||
uint32_t ho_target_pci;
|
||||
bool ho_syncing;
|
||||
phy_interface_rrc::phy_cfg_t ho_src_phy_cfg;
|
||||
mac_interface_rrc::mac_cfg_t ho_src_mac_cfg;
|
||||
phy_interface_rrc::phy_cfg_t previous_phy_cfg;
|
||||
mac_interface_rrc::mac_cfg_t previous_mac_cfg;
|
||||
bool pending_mob_reconf;
|
||||
LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT mob_reconf;
|
||||
|
||||
// timeouts in ms
|
||||
|
||||
uint32_t connecting_timeout;
|
||||
static const uint32_t RRC_CONNECTING_TIMEOUT = 5000;
|
||||
|
||||
uint32_t plmn_select_timeout;
|
||||
static const uint32_t RRC_PLMN_SELECT_TIMEOUT = 10000;
|
||||
|
||||
uint8_t k_rrc_enc[32];
|
||||
uint8_t k_rrc_int[32];
|
||||
uint8_t k_up_enc[32];
|
||||
|
@ -341,7 +383,7 @@ private:
|
|||
srslte::mac_interface_timers *mac_timers;
|
||||
uint32_t n310_cnt, N310;
|
||||
uint32_t n311_cnt, N311;
|
||||
uint32_t t300, t301, t310, t311, t304;
|
||||
uint32_t t300, t301, t302, t310, t311, t304;
|
||||
|
||||
// Radio bearers
|
||||
typedef enum{
|
||||
|
@ -376,42 +418,35 @@ private:
|
|||
std::vector<cell_t*> neighbour_cells;
|
||||
cell_t *serving_cell;
|
||||
void set_serving_cell(uint32_t cell_idx);
|
||||
void set_serving_cell(uint32_t earfcn, uint32_t pci);
|
||||
void set_serving_cell(phy_interface_rrc::phy_cell_t phy_cell);
|
||||
|
||||
int find_neighbour_cell(uint32_t earfcn, uint32_t pci);
|
||||
bool add_neighbour_cell(uint32_t earfcn, uint32_t pci, float rsrp);
|
||||
bool add_neighbour_cell(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp);
|
||||
bool add_neighbour_cell(phy_interface_rrc::phy_cell_t phy_cell, float rsrp);
|
||||
bool add_neighbour_cell(cell_t *cell);
|
||||
void sort_neighbour_cells();
|
||||
void clean_neighbours();
|
||||
std::vector<cell_t*>::iterator delete_neighbour(std::vector<cell_t*>::iterator it);
|
||||
void delete_neighbour(uint32_t cell_idx);
|
||||
|
||||
typedef enum {
|
||||
SI_ACQUIRE_IDLE = 0,
|
||||
SI_ACQUIRE_SIB1,
|
||||
SI_ACQUIRE_SIB2
|
||||
} si_acquire_state_t;
|
||||
bool configure_serving_cell();
|
||||
|
||||
si_acquire_state_t si_acquire_state;
|
||||
void run_si_acquisition_procedure();
|
||||
bool si_acquire(uint32_t index);
|
||||
uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t offset, uint32_t sf);
|
||||
uint32_t nof_sib1_trials;
|
||||
uint16_t sysinfo_index;
|
||||
uint32_t last_win_start;
|
||||
const static int SIB_SEARCH_TIMEOUT_MS = 1000;
|
||||
|
||||
bool select_next_cell_in_plmn();
|
||||
LIBLTE_RRC_PLMN_IDENTITY_STRUCT selected_plmn_id;
|
||||
const static uint32_t NOF_REQUIRED_SIBS = 3; // SIB1, SIB2 and SIB3
|
||||
|
||||
bool thread_running;
|
||||
void run_thread();
|
||||
bool initiated;
|
||||
bool ho_start;
|
||||
bool go_idle;
|
||||
|
||||
// Measurements sub-class
|
||||
class rrc_meas {
|
||||
public:
|
||||
void init(rrc *parent);
|
||||
void reset();
|
||||
void parse_meas_config(LIBLTE_RRC_MEAS_CONFIG_STRUCT *meas_config);
|
||||
bool parse_meas_config(LIBLTE_RRC_MEAS_CONFIG_STRUCT *meas_config);
|
||||
void new_phy_meas(uint32_t earfcn, uint32_t pci, float rsrp, float rsrq, uint32_t tti);
|
||||
void run_tti(uint32_t tti);
|
||||
bool timer_expired(uint32_t timer_id);
|
||||
|
@ -500,6 +535,18 @@ private:
|
|||
|
||||
rrc_meas measurements;
|
||||
|
||||
// Measurement object from phy
|
||||
typedef struct {
|
||||
float rsrp;
|
||||
float rsrq;
|
||||
uint32_t tti;
|
||||
uint32_t earfcn;
|
||||
uint32_t pci;
|
||||
} phy_meas_t;
|
||||
|
||||
void process_phy_meas();
|
||||
void process_new_phy_meas(phy_meas_t meas);
|
||||
std::queue<phy_meas_t> phy_meas_q;
|
||||
|
||||
// Cell selection/reselection functions/variables
|
||||
typedef struct {
|
||||
|
@ -510,25 +557,36 @@ private:
|
|||
float s_intrasearchP;
|
||||
float q_hyst;
|
||||
float threshservinglow;
|
||||
|
||||
} cell_resel_cfg_t;
|
||||
|
||||
cell_resel_cfg_t cell_resel_cfg;
|
||||
|
||||
float get_srxlev(float Qrxlevmeas);
|
||||
float get_squal(float Qqualmeas);
|
||||
void cell_reselection_eval(float rsrp, float rsrq);
|
||||
bool cell_selection_eval(float rsrp, float rsrq = 0);
|
||||
|
||||
bool connection_requested;
|
||||
void plmn_select_rrc(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id);
|
||||
typedef enum {
|
||||
CHANGED_CELL = 0,
|
||||
SAME_CELL = 1,
|
||||
NO_CELL = 2
|
||||
} cs_ret_t;
|
||||
|
||||
cs_ret_t cell_selection();
|
||||
bool cell_selection_criteria(float rsrp, float rsrq = 0);
|
||||
void cell_reselection(float rsrp, float rsrq);
|
||||
|
||||
phy_interface_rrc::cell_search_ret_t cell_search();
|
||||
|
||||
LIBLTE_RRC_PLMN_IDENTITY_STRUCT selected_plmn_id;
|
||||
bool plmn_is_selected;
|
||||
|
||||
bool security_is_activated;
|
||||
|
||||
// RLC interface
|
||||
void max_retx_attempted();
|
||||
|
||||
// Senders
|
||||
void send_con_request();
|
||||
void send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_ENUM cause, uint16_t crnti);
|
||||
void send_con_request(LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM cause);
|
||||
void send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_ENUM cause);
|
||||
void send_con_restablish_complete();
|
||||
void send_con_setup_complete(byte_buffer_t *nas_msg);
|
||||
void send_ul_info_transfer(byte_buffer_t *nas_msg);
|
||||
|
@ -542,16 +600,15 @@ private:
|
|||
void parse_dl_info_transfer(uint32_t lcid, byte_buffer_t *pdu);
|
||||
|
||||
// Helpers
|
||||
void ho_failed();
|
||||
bool con_reconfig(LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig);
|
||||
void con_reconfig_failed();
|
||||
bool con_reconfig_ho(LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig);
|
||||
bool ho_prepare();
|
||||
void ho_synced(uint32_t target_pci);
|
||||
void ho_failed();
|
||||
void rrc_connection_release();
|
||||
void con_restablish_cell_reselected();
|
||||
void radio_link_failure();
|
||||
void leave_connected();
|
||||
|
||||
static void* start_sib_thread(void *rrc_);
|
||||
void sib_search();
|
||||
void apply_rr_config_common_dl(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *config);
|
||||
void apply_rr_config_common_ul(LIBLTE_RRC_RR_CONFIG_COMMON_STRUCT *config);
|
||||
void handle_sib1();
|
||||
|
@ -566,7 +623,7 @@ private:
|
|||
void add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg);
|
||||
void add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg);
|
||||
void release_drb(uint8_t lcid);
|
||||
void apply_rr_config_dedicated(LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT *cnfg);
|
||||
bool apply_rr_config_dedicated(LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT *cnfg);
|
||||
void apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *phy_cnfg, bool apply_defaults);
|
||||
void apply_mac_config_dedicated(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_cfg, bool apply_defaults);
|
||||
|
||||
|
|
|
@ -33,27 +33,11 @@ namespace srsue {
|
|||
// RRC states (3GPP 36.331 v10.0.0)
|
||||
typedef enum {
|
||||
RRC_STATE_IDLE = 0,
|
||||
RRC_STATE_PLMN_START,
|
||||
RRC_STATE_PLMN_SELECTION,
|
||||
RRC_STATE_CELL_SELECTING,
|
||||
RRC_STATE_CELL_SELECTED,
|
||||
RRC_STATE_CONNECTING,
|
||||
RRC_STATE_CONNECTED,
|
||||
RRC_STATE_HO_PREPARE,
|
||||
RRC_STATE_HO_PROCESS,
|
||||
RRC_STATE_LEAVE_CONNECTED,
|
||||
RRC_STATE_N_ITEMS,
|
||||
} rrc_state_t;
|
||||
static const char rrc_state_text[RRC_STATE_N_ITEMS][100] = {"IDLE",
|
||||
"PLMN SELECTED",
|
||||
"PLMN SELECTION",
|
||||
"CELL SELECTING",
|
||||
"CELL SELECTED",
|
||||
"CONNECTING",
|
||||
"CONNECTED",
|
||||
"HO PREPARE",
|
||||
"HO PROCESS",
|
||||
"LEAVE CONNECTED"};
|
||||
"CONNECTED"};
|
||||
|
||||
} // namespace srsue
|
||||
|
||||
|
|
|
@ -107,27 +107,29 @@ void demux::push_pdu_temp_crnti(uint8_t *buff, uint32_t nof_bytes)
|
|||
|
||||
Debug("Saved MAC PDU with Temporal C-RNTI in buffer\n");
|
||||
|
||||
pdus.push(buff, nof_bytes);
|
||||
pdus.push(buff, nof_bytes, srslte::pdu_queue::DCH);
|
||||
} else {
|
||||
Warning("Trying to push PDU with payload size zero\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Demultiplexing of logical channels and dissassemble of MAC CE
|
||||
* This function enqueues the packet and returns quicly because ACK
|
||||
* deadline is important here.
|
||||
*/
|
||||
/* Demultiplexing of logical channels and dissassemble of MAC CE
|
||||
* This function enqueues the packet and returns quickly because ACK
|
||||
* deadline is important here.
|
||||
*/
|
||||
void demux::push_pdu(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) {
|
||||
return pdus.push(buff, nof_bytes, tstamp);
|
||||
return pdus.push(buff, nof_bytes, srslte::pdu_queue::DCH, tstamp);
|
||||
}
|
||||
|
||||
/* Demultiplexing of MAC PDU associated with SI-RNTI. The PDU passes through
|
||||
* the MAC in transparent mode.
|
||||
* Warning: In this case function sends the message to RLC now, since SI blocks do not
|
||||
* require ACK feedback to be transmitted quickly.
|
||||
*/
|
||||
void demux::push_pdu_bcch(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) {
|
||||
rlc->write_pdu_bcch_dlsch(buff, nof_bytes);
|
||||
pdus.push(buff, nof_bytes, srslte::pdu_queue::BCH, tstamp);
|
||||
}
|
||||
|
||||
void demux::push_pdu_mch(uint8_t *buff, uint32_t nof_bytes, uint32_t tstamp) {
|
||||
pdus.push(buff, nof_bytes, srslte::pdu_queue::MCH, tstamp);
|
||||
}
|
||||
|
||||
bool demux::process_pdus()
|
||||
|
@ -135,15 +137,25 @@ bool demux::process_pdus()
|
|||
return pdus.process_pdus();
|
||||
}
|
||||
|
||||
void demux::process_pdu(uint8_t *mac_pdu, uint32_t nof_bytes, uint32_t tstamp)
|
||||
void demux::process_pdu(uint8_t *mac_pdu, uint32_t nof_bytes, srslte::pdu_queue::channel_t channel, uint32_t tstamp)
|
||||
{
|
||||
// Unpack DLSCH MAC PDU
|
||||
mac_msg.init_rx(nof_bytes);
|
||||
mac_msg.parse_packet(mac_pdu);
|
||||
Debug("Processing MAC PDU channel %d\n", channel);
|
||||
switch(channel) {
|
||||
case srslte::pdu_queue::DCH:
|
||||
// Unpack DLSCH MAC PDU
|
||||
mac_msg.init_rx(nof_bytes);
|
||||
mac_msg.parse_packet(mac_pdu);
|
||||
|
||||
process_sch_pdu(&mac_msg);
|
||||
//srslte_vec_fprint_byte(stdout, mac_pdu, nof_bytes);
|
||||
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)
|
||||
|
|
|
@ -41,27 +41,21 @@
|
|||
|
||||
namespace srsue {
|
||||
|
||||
mac::mac() : ttisync(10240),
|
||||
timers(64),
|
||||
mac::mac() : timers(64),
|
||||
mux_unit(MAC_NOF_HARQ_PROC),
|
||||
pdu_process_thread(&demux_unit)
|
||||
{
|
||||
started = false;
|
||||
pcap = NULL;
|
||||
bzero(&metrics, sizeof(mac_metrics_t));
|
||||
}
|
||||
|
||||
bool mac::init(phy_interface_mac *phy, rlc_interface_mac *rlc, rrc_interface_mac *rrc, srslte::log *log_h_)
|
||||
{
|
||||
started = false;
|
||||
phy_h = phy;
|
||||
rlc_h = rlc;
|
||||
rrc_h = rrc;
|
||||
log_h = log_h_;
|
||||
tti = 0;
|
||||
is_synchronized = false;
|
||||
last_temporal_crnti = 0;
|
||||
phy_rnti = 0;
|
||||
|
||||
srslte_softbuffer_rx_init(&pch_softbuffer, 100);
|
||||
|
||||
|
@ -79,23 +73,18 @@ bool mac::init(phy_interface_mac *phy, rlc_interface_mac *rlc, rrc_interface_mac
|
|||
|
||||
reset();
|
||||
|
||||
started = true;
|
||||
start(MAC_MAIN_THREAD_PRIO);
|
||||
start_periodic(1000, MAC_MAIN_THREAD_PRIO);
|
||||
|
||||
mactimers.init(&timers, log_h);
|
||||
|
||||
return started;
|
||||
return true;
|
||||
}
|
||||
|
||||
void mac::stop()
|
||||
{
|
||||
srslte_softbuffer_rx_free(&pch_softbuffer);
|
||||
|
||||
started = false;
|
||||
ttisync.increase();
|
||||
pdu_process_thread.stop();
|
||||
stop_thread();
|
||||
wait_thread_finish();
|
||||
mactimers.stop();
|
||||
}
|
||||
|
||||
void mac::start_pcap(srslte::mac_pcap* pcap_)
|
||||
|
@ -150,59 +139,38 @@ void mac::reset()
|
|||
bzero(&uernti, sizeof(ue_rnti_t));
|
||||
}
|
||||
|
||||
void mac::mac_timers::init(srslte::timers *timers, srslte::log *log_h) {
|
||||
this->timers = timers;
|
||||
running = true;
|
||||
this->log_h = log_h;
|
||||
start_periodic(1000);
|
||||
}
|
||||
void mac::run_period() {
|
||||
|
||||
void mac::mac_timers::run_period() {
|
||||
timers->step_all();
|
||||
}
|
||||
/* Warning: Here order of invocation of procedures is important!! */
|
||||
|
||||
void mac::run_thread() {
|
||||
int cnt=0;
|
||||
tti = phy_h->get_current_tti();
|
||||
|
||||
while (!phy_h->sync_status() && started) {
|
||||
usleep(5000);
|
||||
if (phy_h->sync_status()) {
|
||||
Debug("Setting ttysync to %d\n", phy_h->get_current_tti());
|
||||
ttisync.set_producer_cntr(phy_h->get_current_tti());
|
||||
}
|
||||
log_h->step(tti);
|
||||
|
||||
// Step all procedures
|
||||
bsr_procedure.step(tti);
|
||||
phr_procedure.step(tti);
|
||||
|
||||
// Check if BSR procedure need to start SR
|
||||
|
||||
if (bsr_procedure.need_to_send_sr(tti)) {
|
||||
Debug("Starting SR procedure by BSR request, PHY TTI=%d\n", tti);
|
||||
sr_procedure.start();
|
||||
}
|
||||
if (bsr_procedure.need_to_reset_sr()) {
|
||||
Debug("Resetting SR procedure by BSR request\n");
|
||||
sr_procedure.reset();
|
||||
}
|
||||
sr_procedure.step(tti);
|
||||
|
||||
// Check SR if we need to start RA
|
||||
if (sr_procedure.need_random_access()) {
|
||||
ra_procedure.start_mac_order();
|
||||
}
|
||||
|
||||
while(started) {
|
||||
|
||||
/* Warning: Here order of invocation of procedures is important!! */
|
||||
tti = ttisync.wait();
|
||||
|
||||
log_h->step(tti);
|
||||
|
||||
// Step all procedures
|
||||
bsr_procedure.step(tti);
|
||||
phr_procedure.step(tti);
|
||||
|
||||
// Check if BSR procedure need to start SR
|
||||
|
||||
if (bsr_procedure.need_to_send_sr(tti)) {
|
||||
Debug("Starting SR procedure by BSR request, PHY TTI=%d\n", tti);
|
||||
sr_procedure.start();
|
||||
}
|
||||
if (bsr_procedure.need_to_reset_sr()) {
|
||||
Debug("Resetting SR procedure by BSR request\n");
|
||||
sr_procedure.reset();
|
||||
}
|
||||
sr_procedure.step(tti);
|
||||
|
||||
// Check SR if we need to start RA
|
||||
if (sr_procedure.need_random_access()) {
|
||||
ra_procedure.start_mac_order();
|
||||
}
|
||||
ra_procedure.step(tti);
|
||||
|
||||
rrc_h->run_tti(tti);
|
||||
}
|
||||
ra_procedure.step(tti);
|
||||
timers.step_all();
|
||||
rrc_h->run_tti(tti);
|
||||
}
|
||||
|
||||
void mac::bcch_start_rx()
|
||||
|
@ -221,28 +189,17 @@ void mac::bcch_start_rx(int si_window_start, int si_window_length)
|
|||
Info("SCHED: Searching for DL grant for SI-RNTI window_st=%d, window_len=%d\n", si_window_start, si_window_length);
|
||||
}
|
||||
|
||||
void mac::bcch_stop_rx()
|
||||
{
|
||||
phy_h->pdcch_dl_search_reset();
|
||||
}
|
||||
|
||||
void mac::pcch_start_rx()
|
||||
{
|
||||
phy_h->pdcch_dl_search(SRSLTE_RNTI_PCH, SRSLTE_PRNTI);
|
||||
Info("SCHED: Searching for DL grant for P-RNTI\n");
|
||||
}
|
||||
|
||||
void mac::pcch_stop_rx()
|
||||
void mac::clear_rntis()
|
||||
{
|
||||
phy_h->pdcch_dl_search_reset();
|
||||
}
|
||||
|
||||
|
||||
void mac::tti_clock(uint32_t tti)
|
||||
{
|
||||
ttisync.increase(tti);
|
||||
}
|
||||
|
||||
void mac::bch_decoded_ok(uint8_t* payload, uint32_t len)
|
||||
{
|
||||
// Send MIB to RLC
|
||||
|
|
|
@ -77,6 +77,7 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
|
|||
("rf.time_adv_nsamples", bpo::value<string>(&args->rf.time_adv_nsamples)->default_value("auto"),
|
||||
"Transmission time advance")
|
||||
("rf.burst_preamble_us", bpo::value<string>(&args->rf.burst_preamble)->default_value("auto"), "Transmission time advance")
|
||||
("rf.continuous_tx", bpo::value<string>(&args->rf.continuous_tx)->default_value("auto"), "Transmit samples continuously to the radio or on bursts (auto/yes/no). Default is auto (yes for UHD, no for rest)")
|
||||
|
||||
("rrc.feature_group", bpo::value<uint32_t>(&args->rrc.feature_group)->default_value(0xe6041c00), "Hex value of the featureGroupIndicators field in the"
|
||||
"UECapabilityInformation message. Default 0xe6041c00")
|
||||
|
@ -159,6 +160,10 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
|
|||
bpo::value<bool>(&args->expert.pregenerate_signals)->default_value(false),
|
||||
"Pregenerate uplink signals after attach. Improves CPU performance.")
|
||||
|
||||
("expert.print_buffer_state",
|
||||
bpo::value<bool>(&args->expert.print_buffer_state)->default_value(false),
|
||||
"Prints on the console the buffer state every 10 seconds")
|
||||
|
||||
("expert.rssi_sensor_enabled",
|
||||
bpo::value<bool>(&args->expert.phy.rssi_sensor_enabled)->default_value(false),
|
||||
"Enable or disable RF frontend RSSI sensor. In some USRP devices can cause segmentation fault")
|
||||
|
@ -261,18 +266,22 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
|
|||
bpo::value<bool>(&args->expert.phy.average_subframe_enabled)->default_value(true),
|
||||
"Averages in the time domain the channel estimates within 1 subframe. Needs accurate CFO correction.")
|
||||
|
||||
("expert.time_correct_period",
|
||||
bpo::value<int>(&args->expert.phy.time_correct_period)->default_value(5),
|
||||
"Period for sampling time offset correction.")
|
||||
("expert.estimator_fil_auto",
|
||||
bpo::value<bool>(&args->expert.phy.estimator_fil_auto)->default_value(false),
|
||||
"The channel estimator smooths the channel estimate with an adaptative filter.")
|
||||
|
||||
("expert.estimator_fil_stddev",
|
||||
bpo::value<float>(&args->expert.phy.estimator_fil_stddev)->default_value(1.0f),
|
||||
"Sets the channel estimator smooth gaussian filter standard deviation.")
|
||||
|
||||
("expert.estimator_fil_order",
|
||||
bpo::value<uint32_t>(&args->expert.phy.estimator_fil_order)->default_value(4),
|
||||
"Sets the channel estimator smooth gaussian filter order (even values perform better).")
|
||||
|
||||
("expert.sss_algorithm",
|
||||
bpo::value<string>(&args->expert.phy.sss_algorithm)->default_value("full"),
|
||||
"Selects the SSS estimation algorithm.")
|
||||
|
||||
("expert.estimator_fil_w",
|
||||
bpo::value<float>(&args->expert.phy.estimator_fil_w)->default_value(0.1),
|
||||
"Chooses the coefficients for the 3-tap channel estimator centered filter.")
|
||||
|
||||
("expert.pdsch_csi_enabled",
|
||||
bpo::value<bool>(&args->expert.phy.pdsch_csi_enabled)->default_value(false),
|
||||
"Stores the Channel State Information and uses it for weightening the softbits. It is only compatible with TM1.")
|
||||
|
@ -470,18 +479,25 @@ int main(int argc, char *argv[])
|
|||
pthread_t input;
|
||||
pthread_create(&input, NULL, &input_loop, &args);
|
||||
|
||||
bool plot_started = false;
|
||||
bool signals_pregenerated = false;
|
||||
|
||||
printf("Attaching UE...\n");
|
||||
while (!ue->attach() && running) {
|
||||
sleep(1);
|
||||
}
|
||||
if (running) {
|
||||
if (args.expert.pregenerate_signals) {
|
||||
ue->pregenerate_signals(true);
|
||||
}
|
||||
if (args.gui.enable) {
|
||||
ue->start_plot();
|
||||
}
|
||||
}
|
||||
int cnt=0;
|
||||
while (running) {
|
||||
if (ue->is_attached()) {
|
||||
if (!signals_pregenerated && args.expert.pregenerate_signals) {
|
||||
ue->pregenerate_signals(true);
|
||||
signals_pregenerated = true;
|
||||
}
|
||||
if (!plot_started && args.gui.enable) {
|
||||
ue->start_plot();
|
||||
plot_started = true;
|
||||
if (args.expert.print_buffer_state) {
|
||||
cnt++;
|
||||
if (cnt==10) {
|
||||
cnt=0;
|
||||
ue->print_pool();
|
||||
}
|
||||
}
|
||||
sleep(1);
|
||||
|
|
|
@ -248,7 +248,7 @@ void phch_common::worker_end(uint32_t tti, bool tx_enable,
|
|||
radio_h->tx_single(buffer, nof_samples, tx_time);
|
||||
is_first_of_burst = false;
|
||||
} else {
|
||||
if (TX_MODE_CONTINUOUS) {
|
||||
if (radio_h->is_continuous_tx()) {
|
||||
if (!is_first_of_burst) {
|
||||
radio_h->tx_single(zeros, nof_samples, tx_time);
|
||||
}
|
||||
|
@ -342,11 +342,13 @@ void phch_common::reset() {
|
|||
cur_radio_power = 0;
|
||||
sr_last_tx_tti = -1;
|
||||
cur_pusch_power = 0;
|
||||
avg_snr_db_cqi = 0;
|
||||
avg_snr_db_sync = 0;
|
||||
avg_rsrp = 0;
|
||||
avg_rsrp_cqi = 0;
|
||||
avg_rsrp_dbm = 0;
|
||||
avg_rsrq_db = 0;
|
||||
|
||||
pcell_meas_enabled = false;
|
||||
pcell_report_period = 20;
|
||||
|
||||
bzero(pending_ack, sizeof(pending_ack_t)*TTIMOD_SZ);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -133,6 +133,7 @@ bool phch_worker::init(uint32_t max_prb, srslte::log *log_h, srslte::log *log_ph
|
|||
return false;
|
||||
}
|
||||
|
||||
srslte_chest_dl_set_rsrp_neighbour(&ue_dl.chest, true);
|
||||
srslte_chest_dl_average_subframe(&ue_dl.chest, phy->args->average_subframe_enabled);
|
||||
srslte_chest_dl_cfo_estimate_enable(&ue_dl.chest, phy->args->cfo_ref_mask!=0, phy->args->cfo_ref_mask);
|
||||
srslte_ue_ul_set_normalization(&ue_ul, true);
|
||||
|
@ -185,6 +186,11 @@ void phch_worker::set_tti(uint32_t tti_, uint32_t tx_tti_)
|
|||
log_phy_lib_h->step(tti);
|
||||
}
|
||||
|
||||
void phch_worker::set_prach(cf_t *prach_ptr, float prach_power) {
|
||||
this->prach_ptr = prach_ptr;
|
||||
this->prach_power = prach_power;
|
||||
}
|
||||
|
||||
void phch_worker::set_cfo(float cfo_)
|
||||
{
|
||||
cfo = cfo_;
|
||||
|
@ -318,60 +324,70 @@ void phch_worker::work_imp()
|
|||
|
||||
|
||||
/***** Uplink Processing + Transmission *******/
|
||||
|
||||
/* Generate SR if required*/
|
||||
set_uci_sr();
|
||||
|
||||
/* Check if we have UL grant. ul_phy_grant will be overwritten by new grant */
|
||||
ul_grant_available = decode_pdcch_ul(&ul_mac_grant);
|
||||
bool signal_ready = false;
|
||||
cf_t *signal_ptr = NULL;
|
||||
|
||||
/* Generate CQI reports if required, note that in case both aperiodic
|
||||
and periodic ones present, only aperiodic is sent (36.213 section 7.2) */
|
||||
if (ul_grant_available && ul_mac_grant.has_cqi_request) {
|
||||
set_uci_aperiodic_cqi();
|
||||
/* Transmit PRACH if pending, or PUSCH/PUCCH otherwise */
|
||||
if (prach_ptr) {
|
||||
signal_ready = true;
|
||||
signal_ptr = prach_ptr;
|
||||
} else {
|
||||
set_uci_periodic_cqi();
|
||||
}
|
||||
/* Generate SR if required*/
|
||||
set_uci_sr();
|
||||
|
||||
/* TTI offset for UL */
|
||||
ul_action.tti_offset = HARQ_DELAY_MS;
|
||||
/* Check if we have UL grant. ul_phy_grant will be overwritten by new grant */
|
||||
ul_grant_available = decode_pdcch_ul(&ul_mac_grant);
|
||||
|
||||
/* Send UL grant or HARQ information (from PHICH) to MAC */
|
||||
if (ul_grant_available && ul_ack_available) {
|
||||
phy->mac->new_grant_ul_ack(ul_mac_grant, ul_ack, &ul_action);
|
||||
} else if (ul_grant_available && !ul_ack_available) {
|
||||
phy->mac->new_grant_ul(ul_mac_grant, &ul_action);
|
||||
} else if (!ul_grant_available && ul_ack_available) {
|
||||
phy->mac->harq_recv(tti, ul_ack, &ul_action);
|
||||
}
|
||||
|
||||
/* Set UL CFO before transmission */
|
||||
srslte_ue_ul_set_cfo(&ue_ul, cfo);
|
||||
|
||||
/* Transmit PUSCH, PUCCH or SRS */
|
||||
bool signal_ready = false;
|
||||
if (ul_action.tx_enabled) {
|
||||
encode_pusch(&ul_action.phy_grant.ul, ul_action.payload_ptr[0], ul_action.current_tx_nb,
|
||||
&ul_action.softbuffers[0], ul_action.rv[0], ul_action.rnti, ul_mac_grant.is_from_rar);
|
||||
signal_ready = true;
|
||||
if (ul_action.expect_ack) {
|
||||
phy->set_pending_ack(TTI_RX_ACK(tti), ue_ul.pusch_cfg.grant.n_prb_tilde[0], ul_action.phy_grant.ul.ncs_dmrs);
|
||||
/* Generate CQI reports if required, note that in case both aperiodic
|
||||
and periodic ones present, only aperiodic is sent (36.213 section 7.2) */
|
||||
if (ul_grant_available && ul_mac_grant.has_cqi_request) {
|
||||
set_uci_aperiodic_cqi();
|
||||
} else {
|
||||
set_uci_periodic_cqi();
|
||||
}
|
||||
|
||||
} 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;
|
||||
}
|
||||
/* TTI offset for UL */
|
||||
ul_action.tti_offset = HARQ_DELAY_MS;
|
||||
|
||||
/* Send UL grant or HARQ information (from PHICH) to MAC */
|
||||
if (ul_grant_available && ul_ack_available) {
|
||||
phy->mac->new_grant_ul_ack(ul_mac_grant, ul_ack, &ul_action);
|
||||
} else if (ul_grant_available && !ul_ack_available) {
|
||||
phy->mac->new_grant_ul(ul_mac_grant, &ul_action);
|
||||
} else if (!ul_grant_available && ul_ack_available) {
|
||||
phy->mac->harq_recv(tti, ul_ack, &ul_action);
|
||||
}
|
||||
|
||||
/* Set UL CFO before transmission */
|
||||
srslte_ue_ul_set_cfo(&ue_ul, cfo);
|
||||
|
||||
/* Transmit PUSCH, PUCCH or SRS */
|
||||
if (ul_action.tx_enabled) {
|
||||
encode_pusch(&ul_action.phy_grant.ul, ul_action.payload_ptr[0], ul_action.current_tx_nb,
|
||||
&ul_action.softbuffers[0], ul_action.rv[0], ul_action.rnti, ul_mac_grant.is_from_rar);
|
||||
signal_ready = true;
|
||||
if (ul_action.expect_ack) {
|
||||
phy->set_pending_ack(TTI_RX_ACK(tti), ue_ul.pusch_cfg.grant.n_prb_tilde[0], ul_action.phy_grant.ul.ncs_dmrs);
|
||||
}
|
||||
|
||||
} else if (dl_action.generate_ack || uci_data.scheduling_request || uci_data.uci_cqi_len > 0 || uci_data.uci_ri_len > 0) {
|
||||
encode_pucch();
|
||||
signal_ready = true;
|
||||
} else if (srs_is_ready_to_send()) {
|
||||
encode_srs();
|
||||
signal_ready = true;
|
||||
}
|
||||
signal_ptr = signal_buffer[0];
|
||||
}
|
||||
|
||||
|
||||
tr_log_end();
|
||||
|
||||
if (next_offset > 0) {
|
||||
phy->worker_end(tx_tti, signal_ready, signal_buffer[0], SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time);
|
||||
phy->worker_end(tx_tti, signal_ready, signal_ptr, SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time);
|
||||
} else {
|
||||
phy->worker_end(tx_tti, signal_ready, &signal_buffer[0][-next_offset], SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time);
|
||||
phy->worker_end(tx_tti, signal_ready, &signal_ptr[-next_offset], SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time);
|
||||
}
|
||||
|
||||
if (!dl_action.generate_ack_callback) {
|
||||
|
@ -391,13 +407,13 @@ void phch_worker::work_imp()
|
|||
update_measurements();
|
||||
|
||||
if (chest_ok) {
|
||||
if (phy->avg_rsrp_dbm > -130.0 && phy->avg_snr_db > -10.0) {
|
||||
if (phy->avg_rsrp_sync_dbm > -130.0 && phy->avg_snr_db_sync > -10.0) {
|
||||
log_h->debug("SNR=%.1f dB, RSRP=%.1f dBm sync=in-sync from channel estimator\n",
|
||||
phy->avg_snr_db, phy->avg_rsrp_dbm);
|
||||
phy->avg_snr_db_sync, phy->avg_rsrp_sync_dbm);
|
||||
chest_loop->in_sync();
|
||||
} else {
|
||||
log_h->warning("SNR=%.1f dB RSRP=%.1f dBm, sync=out-of-sync from channel estimator\n",
|
||||
phy->avg_snr_db, phy->avg_rsrp_dbm);
|
||||
phy->avg_snr_db_sync, phy->avg_rsrp_sync_dbm);
|
||||
chest_loop->out_of_sync();
|
||||
}
|
||||
}
|
||||
|
@ -429,41 +445,45 @@ void phch_worker::compute_ri(uint8_t *ri, uint8_t *pmi, float *sinr) {
|
|||
}
|
||||
uci_data.uci_ri_len = 1;
|
||||
} else if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) {
|
||||
srslte_ue_dl_ri_pmi_select(&ue_dl, ri, pmi, sinr);
|
||||
Debug("TM4 ri=%d; pmi=%d; SINR=%.1fdB\n", ue_dl.ri, ue_dl.pmi[ue_dl.ri], 10*log10f(ue_dl.sinr[ue_dl.ri][ue_dl.pmi[ue_dl.ri]]));
|
||||
if (sinr) {
|
||||
srslte_ue_dl_ri_pmi_select(&ue_dl, ri, pmi, sinr);
|
||||
Debug("TM4 ri=%d; pmi=%d; SINR=%.1fdB\n", ue_dl.ri, ue_dl.pmi[ue_dl.ri], 10*log10f(ue_dl.sinr[ue_dl.ri][ue_dl.pmi[ue_dl.ri]]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool phch_worker::extract_fft_and_pdcch_llr() {
|
||||
bool decode_pdcch = true;
|
||||
|
||||
/* Without a grant, we might need to do fft processing if need to decode PHICH */
|
||||
if (phy->get_pending_ack(tti) || decode_pdcch) {
|
||||
|
||||
// Setup estimator filter
|
||||
float w_coeff = phy->args->estimator_fil_w;
|
||||
if (w_coeff > 0.0) {
|
||||
srslte_chest_dl_set_smooth_filter3_coeff(&ue_dl.chest, w_coeff);
|
||||
} else if (w_coeff == 0.0) {
|
||||
srslte_chest_dl_set_smooth_filter(&ue_dl.chest, NULL, 0);
|
||||
}
|
||||
|
||||
if (!phy->args->snr_estim_alg.compare("refs")) {
|
||||
srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_REFS);
|
||||
} else if (!phy->args->snr_estim_alg.compare("empty")) {
|
||||
srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_EMPTY);
|
||||
} else {
|
||||
srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_PSS);
|
||||
}
|
||||
|
||||
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, tti%10, &cfi) < 0) {
|
||||
Error("Getting PDCCH FFT estimate\n");
|
||||
return false;
|
||||
}
|
||||
chest_done = true;
|
||||
// Do always channel estimation to keep track of out-of-sync and send measurements to RRC
|
||||
|
||||
// Setup estimator filter
|
||||
srslte_chest_dl_set_smooth_filter_gauss(&ue_dl.chest,
|
||||
phy->args->estimator_fil_order,
|
||||
phy->args->estimator_fil_stddev);
|
||||
srslte_chest_dl_set_smooth_filter_auto(&ue_dl.chest, phy->args->estimator_fil_auto);
|
||||
|
||||
if (!phy->args->snr_estim_alg.compare("refs")) {
|
||||
srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_REFS);
|
||||
} else if (!phy->args->snr_estim_alg.compare("empty")) {
|
||||
srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_EMPTY);
|
||||
} else {
|
||||
chest_done = false;
|
||||
srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_PSS);
|
||||
}
|
||||
|
||||
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, tti%10, &cfi) < 0) {
|
||||
Error("Getting PDCCH FFT estimate\n");
|
||||
return false;
|
||||
}
|
||||
chest_done = true;
|
||||
|
||||
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, tti%10, &cfi) < 0) {
|
||||
Error("Getting PDCCH FFT estimate\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
chest_done = true;
|
||||
|
||||
if (chest_done && decode_pdcch) { /* and not in DRX mode */
|
||||
|
||||
float noise_estimate = phy->avg_noise;
|
||||
|
@ -504,13 +524,13 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant)
|
|||
srslte_ra_dl_dci_t dci_unpacked;
|
||||
|
||||
if (type == SRSLTE_RNTI_RAR) {
|
||||
Info("Looking for RNTI=0x%x\n", dl_rnti);
|
||||
Debug("Looking for RNTI=0x%x\n", dl_rnti);
|
||||
}
|
||||
|
||||
if (srslte_ue_dl_find_dl_dci_type(&ue_dl, phy->config->dedicated.antenna_info_explicit_value.tx_mode, cfi, tti%10,
|
||||
dl_rnti, type, &dci_msg) != 1) {
|
||||
if (type == SRSLTE_RNTI_RAR) {
|
||||
Info("RAR not found, SNR=%.1f dB, tti=%d, cfi=%d, tx_mode=%d, cell_id=%d\n",
|
||||
Debug("RAR not found, SNR=%.1f dB, tti=%d, cfi=%d, tx_mode=%d, cell_id=%d\n",
|
||||
10*log10(srslte_chest_dl_get_snr(&ue_dl.chest)), tti, cfi,
|
||||
phy->config->dedicated.antenna_info_explicit_value.tx_mode, cell.id);
|
||||
}
|
||||
|
@ -908,16 +928,16 @@ void phch_worker::set_uci_periodic_cqi()
|
|||
if (period_cqi.format_is_subband) {
|
||||
// TODO: Implement subband periodic reports
|
||||
cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND;
|
||||
cqi_report.subband.subband_cqi = srslte_cqi_from_snr(phy->avg_snr_db);
|
||||
cqi_report.subband.subband_cqi = srslte_cqi_from_snr(phy->avg_snr_db_cqi);
|
||||
cqi_report.subband.subband_label = 0;
|
||||
log_h->console("Warning: Subband CQI periodic reports not implemented\n");
|
||||
Debug("PUCCH: Periodic CQI=%d, SNR=%.1f dB\n", cqi_report.subband.subband_cqi, phy->avg_snr_db);
|
||||
Debug("PUCCH: Periodic CQI=%d, SNR=%.1f dB\n", cqi_report.subband.subband_cqi, phy->avg_snr_db_cqi);
|
||||
} else {
|
||||
cqi_report.type = SRSLTE_CQI_TYPE_WIDEBAND;
|
||||
if (cqi_fixed >= 0) {
|
||||
cqi_report.wideband.wideband_cqi = cqi_fixed;
|
||||
} else {
|
||||
cqi_report.wideband.wideband_cqi = srslte_cqi_from_snr(phy->avg_snr_db);
|
||||
cqi_report.wideband.wideband_cqi = srslte_cqi_from_snr(phy->avg_snr_db_cqi);
|
||||
}
|
||||
if (cqi_max >= 0 && cqi_report.wideband.wideband_cqi > cqi_max) {
|
||||
cqi_report.wideband.wideband_cqi = cqi_max;
|
||||
|
@ -927,7 +947,7 @@ void phch_worker::set_uci_periodic_cqi()
|
|||
cqi_report.wideband.pmi = phy->last_pmi;
|
||||
cqi_report.wideband.rank_is_not_one = (phy->last_ri != 0);
|
||||
}
|
||||
Debug("PUCCH: Periodic CQI=%d, SNR=%.1f dB\n", cqi_report.wideband.wideband_cqi, phy->avg_snr_db);
|
||||
Debug("PUCCH: Periodic CQI=%d, SNR=%.1f dB\n", cqi_report.wideband.wideband_cqi, phy->avg_snr_db_cqi);
|
||||
}
|
||||
uci_data.uci_cqi_len = (uint32_t) srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi);
|
||||
rar_cqi_request = false;
|
||||
|
@ -957,7 +977,7 @@ void phch_worker::set_uci_aperiodic_cqi()
|
|||
if (rnti_is_set) {
|
||||
srslte_cqi_value_t cqi_report = {0};
|
||||
cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND_HL;
|
||||
cqi_report.subband_hl.wideband_cqi_cw0 = srslte_cqi_from_snr(phy->avg_snr_db);
|
||||
cqi_report.subband_hl.wideband_cqi_cw0 = srslte_cqi_from_snr(phy->avg_snr_db_cqi);
|
||||
|
||||
// TODO: implement subband CQI properly
|
||||
cqi_report.subband_hl.subband_diff_cqi_cw0 = 0; // Always report zero offset on all subbands
|
||||
|
@ -983,7 +1003,7 @@ void phch_worker::set_uci_aperiodic_cqi()
|
|||
}
|
||||
|
||||
Info("PUSCH: Aperiodic RM30 CQI=%s, %sSNR=%.1f dB, for %d subbands\n",
|
||||
cqi_str, (uci_data.uci_ri_len)?((uci_data.uci_ri == 0)?"ri=0, ":"ri=1, "):"", phy->avg_snr_db, cqi_report.subband_hl.N);
|
||||
cqi_str, (uci_data.uci_ri_len)?((uci_data.uci_ri == 0)?"ri=0, ":"ri=1, "):"", phy->avg_snr_db_cqi, cqi_report.subband_hl.N);
|
||||
}
|
||||
break;
|
||||
case LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM31:
|
||||
|
@ -1396,18 +1416,18 @@ void phch_worker::update_measurements()
|
|||
}
|
||||
}
|
||||
|
||||
// Average RSRQ
|
||||
// Average RSRQ over DEFAULT_MEAS_PERIOD_MS then sent to RRC
|
||||
float rsrq_db = 10*log10(srslte_chest_dl_get_rsrq(&ue_dl.chest));
|
||||
if (isnormal(rsrq_db)) {
|
||||
if (!phy->avg_rsrq_db) {
|
||||
phy->avg_rsrq_db = SRSLTE_VEC_EMA(rsrq_db, phy->avg_rsrq_db, snr_ema_coeff);
|
||||
} else {
|
||||
if (!(tti%phy->pcell_report_period) || !phy->avg_rsrq_db) {
|
||||
phy->avg_rsrq_db = rsrq_db;
|
||||
} else {
|
||||
phy->avg_rsrq_db = SRSLTE_VEC_CMA(rsrq_db, phy->avg_rsrq_db, tti%phy->pcell_report_period);
|
||||
}
|
||||
}
|
||||
|
||||
// Average RSRP
|
||||
float rsrp_lin = srslte_chest_dl_get_rsrp(&ue_dl.chest);
|
||||
// Average RSRP taken from CRS
|
||||
float rsrp_lin = srslte_chest_dl_get_rsrp_neighbour(&ue_dl.chest);
|
||||
if (isnormal(rsrp_lin)) {
|
||||
if (!phy->avg_rsrp) {
|
||||
phy->avg_rsrp = SRSLTE_VEC_EMA(rsrp_lin, phy->avg_rsrp, snr_ema_coeff);
|
||||
|
@ -1419,18 +1439,20 @@ void phch_worker::update_measurements()
|
|||
/* Correct absolute power measurements by RX gain offset */
|
||||
float rsrp_dbm = 10*log10(rsrp_lin) + 30 - phy->rx_gain_offset;
|
||||
|
||||
// Serving cell measurements are averaged over DEFAULT_MEAS_PERIOD_MS then sent to RRC
|
||||
// Serving cell RSRP measurements are averaged over DEFAULT_MEAS_PERIOD_MS then sent to RRC
|
||||
if (isnormal(rsrp_dbm)) {
|
||||
if (!phy->avg_rsrp_dbm) {
|
||||
if (!(tti%phy->pcell_report_period) || !phy->avg_rsrp_dbm) {
|
||||
phy->avg_rsrp_dbm = rsrp_dbm;
|
||||
} else {
|
||||
phy->avg_rsrp_dbm = SRSLTE_VEC_EMA(rsrp_dbm, phy->avg_rsrp_dbm, snr_ema_coeff);
|
||||
}
|
||||
if ((tti%phy->pcell_report_period) == 0 && phy->pcell_meas_enabled) {
|
||||
phy->rrc->new_phy_meas(phy->avg_rsrp_dbm, phy->avg_rsrq_db, tti);
|
||||
phy->avg_rsrp_dbm = SRSLTE_VEC_CMA(rsrp_dbm, phy->avg_rsrp_dbm, tti%phy->pcell_report_period);
|
||||
}
|
||||
}
|
||||
|
||||
// Send PCell measurement
|
||||
if ((tti%phy->pcell_report_period) == phy->pcell_report_period-1) {
|
||||
phy->rrc->new_phy_meas(phy->avg_rsrp_dbm, phy->avg_rsrq_db, tti);
|
||||
}
|
||||
|
||||
// Compute PL
|
||||
float tx_crs_power = phy->config->common.pdsch_cnfg.rs_power;
|
||||
phy->pathloss = tx_crs_power - phy->avg_rsrp_dbm;
|
||||
|
@ -1444,20 +1466,40 @@ void phch_worker::update_measurements()
|
|||
phy->avg_noise = SRSLTE_VEC_EMA(cur_noise, phy->avg_noise, snr_ema_coeff);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute SNR
|
||||
phy->avg_snr_db = 10*log10(phy->avg_rsrp/phy->avg_noise);
|
||||
|
||||
|
||||
// To compute CQI use RSRP measurements from resource elements in RS since is more robust to time offset
|
||||
float rsrp_lin_cqi = srslte_chest_dl_get_rsrp(&ue_dl.chest);
|
||||
if (isnormal(rsrp_lin_cqi)) {
|
||||
if (!phy->avg_rsrp_cqi) {
|
||||
phy->avg_rsrp_cqi = SRSLTE_VEC_EMA(rsrp_lin_cqi, phy->avg_rsrp_cqi, snr_ema_coeff);
|
||||
} else {
|
||||
phy->avg_rsrp_cqi = rsrp_lin_cqi;
|
||||
}
|
||||
}
|
||||
float rsrp_sync_dbm = 10*log10(rsrp_lin_cqi) + 30 - phy->rx_gain_offset;
|
||||
if (isnormal(rsrp_sync_dbm)) {
|
||||
if (!phy->avg_rsrp_sync_dbm) {
|
||||
phy->avg_rsrp_sync_dbm = rsrp_sync_dbm;
|
||||
} else {
|
||||
phy->avg_rsrp_sync_dbm = SRSLTE_VEC_EMA(rsrp_sync_dbm, phy->avg_rsrp_sync_dbm, snr_ema_coeff);
|
||||
}
|
||||
}
|
||||
|
||||
// We compute 2 SNR metrics, 1 for deciding in-sync/out-of-sync and another for CQI measurements
|
||||
phy->avg_snr_db_cqi = 10*log10(phy->avg_rsrp_cqi/phy->avg_noise); // this for CQI
|
||||
phy->avg_snr_db_sync = 10*log10(phy->avg_rsrp/phy->avg_noise); // this for sync
|
||||
|
||||
|
||||
// Store metrics
|
||||
dl_metrics.n = phy->avg_noise;
|
||||
dl_metrics.rsrp = phy->avg_rsrp_dbm;
|
||||
dl_metrics.rsrq = phy->avg_rsrq_db;
|
||||
dl_metrics.rssi = phy->avg_rssi_dbm;
|
||||
dl_metrics.pathloss = phy->pathloss;
|
||||
dl_metrics.sinr = phy->avg_snr_db;
|
||||
dl_metrics.sinr = phy->avg_snr_db_cqi;
|
||||
dl_metrics.turbo_iters = srslte_pdsch_last_noi(&ue_dl.pdsch);
|
||||
phy->set_dl_metrics(dl_metrics);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -96,9 +96,10 @@ void phy::set_default_args(phy_args_t *args)
|
|||
args->equalizer_mode = "mmse";
|
||||
args->cfo_integer_enabled = false;
|
||||
args->cfo_correct_tol_hz = 50;
|
||||
args->time_correct_period = 5;
|
||||
args->sss_algorithm = "full";
|
||||
args->estimator_fil_w = 0.1;
|
||||
args->estimator_fil_auto = false;
|
||||
args->estimator_fil_stddev = 1.0f;
|
||||
args->estimator_fil_order = 4;
|
||||
}
|
||||
|
||||
bool phy::check_args(phy_args_t *args)
|
||||
|
@ -107,10 +108,6 @@ bool phy::check_args(phy_args_t *args)
|
|||
log_h->console("Error in PHY args: nof_phy_threads must be 1, 2 or 3\n");
|
||||
return false;
|
||||
}
|
||||
if (args->estimator_fil_w > 1.0) {
|
||||
log_h->console("Error in PHY args: estimator_fil_w must be 0<=w<=1\n");
|
||||
return false;
|
||||
}
|
||||
if (args->snr_ema_coeff > 1.0) {
|
||||
log_h->console("Error in PHY args: snr_ema_coeff must be 0<=w<=1\n");
|
||||
return false;
|
||||
|
@ -250,20 +247,6 @@ void phy::configure_ul_params(bool pregen_disabled)
|
|||
}
|
||||
}
|
||||
|
||||
void phy::cell_search_start()
|
||||
{
|
||||
sf_recv.cell_search_start();
|
||||
}
|
||||
|
||||
void phy::cell_search_next()
|
||||
{
|
||||
sf_recv.cell_search_next();
|
||||
}
|
||||
|
||||
void phy::sync_reset() {
|
||||
sf_recv.reset_sync();
|
||||
}
|
||||
|
||||
void phy::meas_reset() {
|
||||
sf_recv.meas_reset();
|
||||
}
|
||||
|
@ -276,13 +259,16 @@ int phy::meas_stop(uint32_t earfcn, int pci) {
|
|||
return sf_recv.meas_stop(earfcn, pci);
|
||||
}
|
||||
|
||||
void phy::cell_select(uint32_t earfcn, srslte_cell_t phy_cell)
|
||||
{
|
||||
sf_recv.cell_select(earfcn, phy_cell);
|
||||
bool phy::cell_select(phy_cell_t *cell) {
|
||||
return sf_recv.cell_select(cell);
|
||||
}
|
||||
|
||||
bool phy::cell_handover(srslte_cell_t cell) {
|
||||
return sf_recv.cell_handover(cell);
|
||||
phy_interface_rrc::cell_search_ret_t phy::cell_search(phy_cell_t *cell) {
|
||||
return sf_recv.cell_search(cell);
|
||||
}
|
||||
|
||||
bool phy::cell_is_camping() {
|
||||
return sf_recv.cell_is_camping();
|
||||
}
|
||||
|
||||
float phy::get_phr()
|
||||
|
@ -348,13 +334,14 @@ int phy::prach_tx_tti()
|
|||
|
||||
// Handle the case of a radio overflow. Resynchronise inmediatly
|
||||
void phy::radio_overflow() {
|
||||
sf_recv.reset_sync();
|
||||
sf_recv.radio_overflow();
|
||||
}
|
||||
|
||||
void phy::reset()
|
||||
{
|
||||
Info("Resetting PHY\n");
|
||||
n_ta = 0;
|
||||
sf_recv.set_time_adv_sec(0);
|
||||
pdcch_dl_search_reset();
|
||||
for(uint32_t i=0;i<nof_workers;i++) {
|
||||
workers[i].reset();
|
||||
|
@ -388,11 +375,6 @@ void phy::force_freq(float dl_freq, float ul_freq)
|
|||
sf_recv.force_freq(dl_freq, ul_freq);
|
||||
}
|
||||
|
||||
bool phy::sync_status()
|
||||
{
|
||||
return sf_recv.status_is_sync();
|
||||
}
|
||||
|
||||
void phy::set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN])
|
||||
{
|
||||
workers_common.set_rar_grant(tti, grant_payload);
|
||||
|
|
|
@ -75,7 +75,7 @@ void prach::init(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT *config_, uint32_t max_prb,
|
|||
return;
|
||||
}
|
||||
srslte_cfo_set_tol(&cfo_h, 0);
|
||||
signal_buffer = (cf_t *) srslte_vec_malloc(SRSLTE_PRACH_MAX_LEN * sizeof(cf_t));
|
||||
signal_buffer = (cf_t *) srslte_vec_malloc(MAX_LEN_SF * 30720 * sizeof(cf_t));
|
||||
if (!signal_buffer) {
|
||||
perror("malloc");
|
||||
return;
|
||||
|
@ -159,10 +159,10 @@ bool prach::is_pending() {
|
|||
bool prach::is_ready_to_send(uint32_t current_tti_) {
|
||||
if (is_pending()) {
|
||||
// consider the number of subframes the transmission must be anticipated
|
||||
uint32_t current_tti = (current_tti_ + tx_advance_sf)%10240;
|
||||
if (srslte_prach_tti_opportunity(&prach_obj, current_tti, allowed_subframe)) {
|
||||
Debug("PRACH Buffer: Ready to send at tti: %d (now is %d)\n", current_tti, current_tti_);
|
||||
transmitted_tti = current_tti;
|
||||
uint32_t tti_tx = TTI_TX(current_tti_);
|
||||
if (srslte_prach_tti_opportunity(&prach_obj, tti_tx, allowed_subframe)) {
|
||||
Debug("PRACH Buffer: Ready to send at tti: %d (now is %d)\n", tti_tx, current_tti_);
|
||||
transmitted_tti = tti_tx;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -173,55 +173,31 @@ int prach::tx_tti() {
|
|||
return transmitted_tti;
|
||||
}
|
||||
|
||||
float prach::get_p0_preamble()
|
||||
{
|
||||
return target_power_dbm;
|
||||
}
|
||||
cf_t *prach::generate(float cfo, uint32_t *nof_sf, float *target_power) {
|
||||
|
||||
if (cell_initiated && preamble_idx >= 0 && nof_sf) {
|
||||
|
||||
void prach::send(srslte::radio *radio_handler, float cfo, float pathloss, srslte_timestamp_t tx_time)
|
||||
{
|
||||
|
||||
// Get current TX gain
|
||||
float old_gain = radio_handler->get_tx_gain();
|
||||
|
||||
// Correct CFO before transmission FIXME: UL SISO Only
|
||||
srslte_cfo_correct(&cfo_h, buffer[preamble_idx], signal_buffer, cfo / srslte_symbol_sz(cell.nof_prb));
|
||||
// Correct CFO before transmission FIXME: UL SISO Only
|
||||
srslte_cfo_correct(&cfo_h, buffer[preamble_idx], signal_buffer, cfo / srslte_symbol_sz(cell.nof_prb));
|
||||
|
||||
// If power control is enabled, choose amplitude and power
|
||||
if (args->ul_pwr_ctrl_en) {
|
||||
// Get PRACH transmission power
|
||||
float tx_power = SRSLTE_MIN(SRSLTE_PC_MAX, pathloss + target_power_dbm);
|
||||
|
||||
// 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);
|
||||
// pad guard symbols with zeros
|
||||
uint32_t nsf = (len-1)/SRSLTE_SF_LEN_PRB(cell.nof_prb)+1;
|
||||
bzero(&signal_buffer[len], (nsf*SRSLTE_SF_LEN_PRB(cell.nof_prb)-len)*sizeof(cf_t));
|
||||
|
||||
*nof_sf = nsf;
|
||||
|
||||
if (target_power) {
|
||||
*target_power = target_power_dbm;
|
||||
}
|
||||
Debug("TX PRACH: Power control for PRACH is disabled, setting gain to %.0f dB\n", prach_gain);
|
||||
|
||||
Info("PRACH: Transmitted preamble=%d, CFO=%.2f KHz, nof_sf=%d, target_power=%.1f dBm\n",
|
||||
preamble_idx, cfo*15, nsf, target_power_dbm);
|
||||
preamble_idx = -1;
|
||||
|
||||
return signal_buffer;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *tmp_buffer[SRSLTE_MAX_PORTS] = {signal_buffer, NULL, NULL, NULL};
|
||||
radio_handler->tx(tmp_buffer, len, tx_time);
|
||||
radio_handler->tx_end();
|
||||
|
||||
Info("PRACH: Transmitted preamble=%d, CFO=%.2f KHz, tx_time=%f\n",
|
||||
preamble_idx, cfo*15, tx_time.frac_secs);
|
||||
preamble_idx = -1;
|
||||
|
||||
radio_handler->set_tx_gain(old_gain);
|
||||
Debug("Restoring TX gain to %.0f dB\n", old_gain);
|
||||
}
|
||||
|
||||
} // namespace srsue
|
||||
|
|
|
@ -160,7 +160,10 @@ bool ue::init(all_args_t *args_)
|
|||
if (args->rf.burst_preamble.compare("auto")) {
|
||||
radio.set_burst_preamble(atof(args->rf.burst_preamble.c_str()));
|
||||
}
|
||||
|
||||
if (args->rf.continuous_tx.compare("auto")) {
|
||||
radio.set_continuous_tx(args->rf.continuous_tx.compare("yes")?false:true);
|
||||
}
|
||||
|
||||
radio.set_manual_calibration(&args->rf_cal);
|
||||
|
||||
// Set PHY options
|
||||
|
@ -226,7 +229,6 @@ bool ue::init(all_args_t *args_)
|
|||
}
|
||||
|
||||
printf("...\n");
|
||||
nas.attach_request();
|
||||
|
||||
started = true;
|
||||
return true;
|
||||
|
@ -273,6 +275,14 @@ void ue::stop()
|
|||
}
|
||||
}
|
||||
|
||||
bool ue::attach() {
|
||||
return nas.attach_request();
|
||||
}
|
||||
|
||||
bool ue::deattach() {
|
||||
return nas.deattach_request();
|
||||
}
|
||||
|
||||
bool ue::is_attached()
|
||||
{
|
||||
return rrc.is_connected();
|
||||
|
|
|
@ -248,10 +248,8 @@ void gw::run_thread()
|
|||
return;
|
||||
}
|
||||
|
||||
const static uint32_t ATTACH_TIMEOUT_MS = 10000;
|
||||
const static uint32_t ATTACH_MAX_ATTEMPTS = 3;
|
||||
uint32_t attach_cnt = 0;
|
||||
uint32_t attach_attempts = 0;
|
||||
const static uint32_t ATTACH_WAIT_TOUT = 40; // 4 sec
|
||||
uint32_t attach_wait = 0;
|
||||
|
||||
gw_log->info("GW IP packet receiver thread run_enable\n");
|
||||
|
||||
|
@ -278,25 +276,18 @@ void gw::run_thread()
|
|||
{
|
||||
gw_log->info_hex(pdu->msg, pdu->N_bytes, "TX PDU");
|
||||
|
||||
while(run_enable && !pdcp->is_drb_enabled(cfg.lcid) && attach_attempts < ATTACH_MAX_ATTEMPTS) {
|
||||
if (attach_cnt == 0) {
|
||||
gw_log->info("LCID=%d not active, requesting NAS attach (%d/%d)\n", cfg.lcid, attach_attempts, ATTACH_MAX_ATTEMPTS);
|
||||
nas->attach_request();
|
||||
attach_attempts++;
|
||||
while(run_enable && !pdcp->is_drb_enabled(cfg.lcid) && attach_wait < ATTACH_WAIT_TOUT) {
|
||||
if (!attach_wait) {
|
||||
gw_log->info("LCID=%d not active, requesting NAS attach (%d/%d)\n", cfg.lcid, attach_wait, ATTACH_WAIT_TOUT);
|
||||
if (!nas->attach_request()) {
|
||||
gw_log->warning("Could not re-establish the connection\n");
|
||||
}
|
||||
}
|
||||
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_cnt = 0;
|
||||
attach_wait = 0;
|
||||
|
||||
if (!run_enable) {
|
||||
break;
|
||||
|
|
|
@ -45,10 +45,13 @@ namespace srsue {
|
|||
********************************************************************/
|
||||
|
||||
nas::nas()
|
||||
: state(EMM_STATE_DEREGISTERED), plmn_selection(PLMN_SELECTED), have_guti(false), have_ctxt(false), ip_addr(0), eps_bearer_id(0)
|
||||
: state(EMM_STATE_DEREGISTERED), have_guti(false), have_ctxt(false), ip_addr(0), eps_bearer_id(0)
|
||||
{
|
||||
ctxt.rx_count = 0;
|
||||
ctxt.tx_count = 0;
|
||||
ctxt.cipher_algo = CIPHERING_ALGORITHM_ID_EEA0;
|
||||
ctxt.integ_algo = INTEGRITY_ALGORITHM_ID_EIA0;
|
||||
plmn_is_selected = false;
|
||||
}
|
||||
|
||||
void nas::init(usim_interface_nas *usim_,
|
||||
|
@ -63,7 +66,6 @@ void nas::init(usim_interface_nas *usim_,
|
|||
gw = gw_;
|
||||
nas_log = nas_log_;
|
||||
state = EMM_STATE_DEREGISTERED;
|
||||
plmn_selection = PLMN_NOT_SELECTED;
|
||||
|
||||
if (!usim->get_home_plmn_id(&home_plmn)) {
|
||||
nas_log->error("Getting Home PLMN Id from USIM. Defaulting to 001-01\n");
|
||||
|
@ -80,9 +82,11 @@ void nas::init(usim_interface_nas *usim_,
|
|||
have_guti = true;
|
||||
have_ctxt = true;
|
||||
}
|
||||
running = true;
|
||||
}
|
||||
|
||||
void nas::stop() {
|
||||
running = false;
|
||||
write_ctxt_file(ctxt);
|
||||
}
|
||||
|
||||
|
@ -94,105 +98,186 @@ emm_state_t nas::get_state() {
|
|||
* UE interface
|
||||
******************************************************************************/
|
||||
|
||||
void nas::attach_request() {
|
||||
/** Blocking function to Attach to the network and establish RRC connection if not established.
|
||||
* The function returns true if the UE could attach correctly or false in case of error or timeout during attachment.
|
||||
*
|
||||
*/
|
||||
bool nas::attach_request() {
|
||||
rrc_interface_nas::found_plmn_t found_plmns[rrc_interface_nas::MAX_FOUND_PLMNS];
|
||||
int nof_plmns = 0;
|
||||
|
||||
nas_log->info("Attach Request\n");
|
||||
if (state == EMM_STATE_DEREGISTERED) {
|
||||
state = EMM_STATE_REGISTERED_INITIATED;
|
||||
if (plmn_selection == PLMN_NOT_SELECTED) {
|
||||
nas_log->info("Starting PLMN Search...\n");
|
||||
rrc->plmn_search();
|
||||
} else if (plmn_selection == PLMN_SELECTED) {
|
||||
nas_log->info("Selecting PLMN %s\n", plmn_id_to_string(current_plmn).c_str());
|
||||
rrc->plmn_select(current_plmn);
|
||||
selecting_plmn = current_plmn;
|
||||
}
|
||||
} else if (state == EMM_STATE_REGISTERED) {
|
||||
nas_log->info("NAS state is registered, selecting current PLMN\n");
|
||||
rrc->plmn_select(current_plmn, true);
|
||||
} else {
|
||||
nas_log->info("Attach request ignored. State = %s\n", emm_state_text[state]);
|
||||
}
|
||||
}
|
||||
switch (state) {
|
||||
case EMM_STATE_DEREGISTERED:
|
||||
|
||||
void nas::deattach_request() {
|
||||
state = EMM_STATE_DEREGISTERED_INITIATED;
|
||||
nas_log->info("Dettach request not supported\n");
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* RRC interface
|
||||
******************************************************************************/
|
||||
|
||||
bool nas::plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) {
|
||||
|
||||
// Check if already registered
|
||||
for (uint32_t i=0;i<known_plmns.size();i++) {
|
||||
if (plmn_id.mcc == known_plmns[i].mcc && plmn_id.mnc == known_plmns[i].mnc) {
|
||||
nas_log->info("Found known PLMN Id=%s\n", plmn_id_to_string(plmn_id).c_str());
|
||||
if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) {
|
||||
nas_log->info("Connecting Home PLMN Id=%s\n", plmn_id_to_string(plmn_id).c_str());
|
||||
rrc->plmn_select(plmn_id, state == EMM_STATE_REGISTERED_INITIATED);
|
||||
selecting_plmn = plmn_id;
|
||||
return true;
|
||||
// Search PLMN is not selected
|
||||
if (!plmn_is_selected) {
|
||||
nas_log->info("No PLMN selected. Starting PLMN Search...\n");
|
||||
nof_plmns = rrc->plmn_search(found_plmns);
|
||||
if (nof_plmns > 0) {
|
||||
// Save PLMNs
|
||||
known_plmns.clear();
|
||||
for (int i=0;i<nof_plmns;i++) {
|
||||
known_plmns.push_back(found_plmns[i].plmn_id);
|
||||
nas_log->info("Found PLMN: Id=%s, TAC=%d\n", plmn_id_to_string(found_plmns[i].plmn_id).c_str(),
|
||||
found_plmns[i].tac);
|
||||
nas_log->console("Found PLMN: Id=%s, TAC=%d\n", plmn_id_to_string(found_plmns[i].plmn_id).c_str(),
|
||||
found_plmns[i].tac);
|
||||
}
|
||||
select_plmn();
|
||||
} else if (nof_plmns == 0) {
|
||||
nas_log->warning("Did not find any PLMN in the set of frequencies\n");
|
||||
return false;
|
||||
} else if (nof_plmns < 0) {
|
||||
nas_log->error("Error while searching for PLMNs\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Save if new PLMN
|
||||
known_plmns.push_back(plmn_id);
|
||||
|
||||
nas_log->info("Found PLMN: Id=%s, TAC=%d\n", plmn_id_to_string(plmn_id).c_str(),
|
||||
tracking_area_code);
|
||||
nas_log->console("Found PLMN: Id=%s, TAC=%d\n", plmn_id_to_string(plmn_id).c_str(),
|
||||
tracking_area_code);
|
||||
|
||||
if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) {
|
||||
rrc->plmn_select(plmn_id, state == EMM_STATE_REGISTERED_INITIATED);
|
||||
selecting_plmn = plmn_id;
|
||||
return true;
|
||||
// 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;
|
||||
}
|
||||
|
||||
// RRC indicates that the UE has gone through all EARFCN and finished PLMN selection
|
||||
void nas::plmn_search_end() {
|
||||
if (known_plmns.size() > 0) {
|
||||
if (home_plmn.mcc != known_plmns[0].mcc && home_plmn.mnc != known_plmns[0].mnc) {
|
||||
nas_log->info("Could not find Home PLMN Id=%s, trying to connect to PLMN Id=%s\n",
|
||||
plmn_id_to_string(home_plmn).c_str(),
|
||||
plmn_id_to_string(known_plmns[0]).c_str());
|
||||
|
||||
nas_log->console("Could not find Home PLMN Id=%s, trying to connect to PLMN Id=%s\n",
|
||||
plmn_id_to_string(home_plmn).c_str(),
|
||||
plmn_id_to_string(known_plmns[0]).c_str());
|
||||
}
|
||||
rrc->plmn_select(known_plmns[0], state == EMM_STATE_REGISTERED_INITIATED);
|
||||
} else {
|
||||
nas_log->info("Finished searching PLMN in current EARFCN set but no networks were found.\n");
|
||||
if (state == EMM_STATE_REGISTERED_INITIATED && plmn_selection == PLMN_NOT_SELECTED) {
|
||||
rrc->plmn_search();
|
||||
}
|
||||
}
|
||||
bool nas::deattach_request() {
|
||||
state = EMM_STATE_DEREGISTERED_INITIATED;
|
||||
nas_log->info("Dettach request not supported\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool nas::is_attached() {
|
||||
return state == EMM_STATE_REGISTERED;
|
||||
}
|
||||
|
||||
bool nas::is_attaching() {
|
||||
return state == EMM_STATE_REGISTERED_INITIATED;
|
||||
}
|
||||
|
||||
void nas::notify_connection_setup() {
|
||||
nas_log->debug("State = %s\n", emm_state_text[state]);
|
||||
if (EMM_STATE_REGISTERED_INITIATED == state) {
|
||||
send_attach_request();
|
||||
void nas::paging(LIBLTE_RRC_S_TMSI_STRUCT *ue_identiy) {
|
||||
if (state == EMM_STATE_REGISTERED) {
|
||||
nas_log->info("Received paging: requesting RRC connection establishment\n");
|
||||
if (rrc_connect()) {
|
||||
nas_log->info("Attached successfully\n");
|
||||
} else {
|
||||
nas_log->error("Could not attach from paging\n");
|
||||
}
|
||||
} else {
|
||||
send_service_request();
|
||||
nas_log->warning("Received paging while in state %s\n", emm_state_text[state]);
|
||||
}
|
||||
}
|
||||
|
||||
void nas::set_barring(barring_t barring) {
|
||||
current_barring = barring;
|
||||
}
|
||||
|
||||
/* Internal function that requests RRC connection, waits for positive or negative response and returns true/false
|
||||
*/
|
||||
bool nas::rrc_connect() {
|
||||
if (rrc->is_connected()) {
|
||||
nas_log->info("Already connected\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Generate service request or attach request message
|
||||
byte_buffer_t *dedicatedInfoNAS = pool_allocate;
|
||||
if (state == EMM_STATE_REGISTERED) {
|
||||
gen_service_request(dedicatedInfoNAS);
|
||||
} else {
|
||||
gen_attach_request(dedicatedInfoNAS);
|
||||
}
|
||||
|
||||
// Provide UE-Identity to RRC if have one
|
||||
if (have_guti) {
|
||||
LIBLTE_RRC_S_TMSI_STRUCT s_tmsi;
|
||||
s_tmsi.mmec = ctxt.guti.mme_code;
|
||||
s_tmsi.m_tmsi = ctxt.guti.m_tmsi;
|
||||
rrc->set_ue_idenity(s_tmsi);
|
||||
}
|
||||
|
||||
// Set establishment cause
|
||||
LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM establish_cause = LIBLTE_RRC_CON_REQ_EST_CAUSE_MO_SIGNALLING;
|
||||
|
||||
if (rrc->connection_request(establish_cause, dedicatedInfoNAS))
|
||||
{
|
||||
nas_log->info("Connection established correctly. Waiting for Attach\n");
|
||||
|
||||
// Wait until attachment. If doing a service request is already attached
|
||||
uint32_t tout = 0;
|
||||
while (tout < 5000 && state != EMM_STATE_REGISTERED && running && rrc->is_connected()) {
|
||||
usleep(1000);
|
||||
tout++;
|
||||
}
|
||||
if (state == EMM_STATE_REGISTERED) {
|
||||
nas_log->info("EMM Registered correctly\n");
|
||||
return true;
|
||||
} else if (state == EMM_STATE_DEREGISTERED) {
|
||||
nas_log->error("Timeout or received attach reject while trying to attach\n");
|
||||
nas_log->console("Failed to Attach\n");
|
||||
} else if (!rrc->is_connected()) {
|
||||
nas_log->error("Was disconnected while attaching\n");
|
||||
} else {
|
||||
nas_log->error("Timed out while trying to attach\n");
|
||||
}
|
||||
} else {
|
||||
nas_log->error("Could not establish RRC connection\n");
|
||||
pool->deallocate(dedicatedInfoNAS);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void nas::select_plmn() {
|
||||
|
||||
plmn_is_selected = false;
|
||||
|
||||
// First find if Home PLMN is available
|
||||
for (uint32_t i=0;i<known_plmns.size();i++) {
|
||||
if (known_plmns[i].mcc == home_plmn.mcc && known_plmns[i].mnc == home_plmn.mnc) {
|
||||
nas_log->info("Selecting Home PLMN Id=%s\n", plmn_id_to_string(known_plmns[i]).c_str());
|
||||
plmn_is_selected = true;
|
||||
current_plmn = known_plmns[i];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If not, select the first available PLMN
|
||||
if (known_plmns.size() > 0) {
|
||||
nas_log->info("Could not find Home PLMN Id=%s, trying to connect to PLMN Id=%s\n",
|
||||
plmn_id_to_string(home_plmn).c_str(),
|
||||
plmn_id_to_string(known_plmns[0]).c_str());
|
||||
|
||||
nas_log->console("Could not find Home PLMN Id=%s, trying to connect to PLMN Id=%s\n",
|
||||
plmn_id_to_string(home_plmn).c_str(),
|
||||
plmn_id_to_string(known_plmns[0]).c_str());
|
||||
plmn_is_selected = true;
|
||||
current_plmn = known_plmns[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu) {
|
||||
uint8 pd = 0;
|
||||
uint8 msg_type = 0;
|
||||
|
@ -271,16 +356,6 @@ uint32_t nas::get_ul_count() {
|
|||
return ctxt.tx_count;
|
||||
}
|
||||
|
||||
bool nas::get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) {
|
||||
if (have_guti) {
|
||||
s_tmsi->mmec = ctxt.guti.mme_code;
|
||||
s_tmsi->m_tmsi = ctxt.guti.m_tmsi;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool nas::get_k_asme(uint8_t *k_asme_, uint32_t n) {
|
||||
if(!have_ctxt) {
|
||||
nas_log->error("K_asme requested before security context established\n");
|
||||
|
@ -350,7 +425,7 @@ bool nas::integrity_check(byte_buffer_t *pdu)
|
|||
return NULL;
|
||||
}
|
||||
if (pdu->N_bytes > 5) {
|
||||
uint8_t exp_mac[4];
|
||||
uint8_t exp_mac[4] = {0};
|
||||
uint8_t *mac = &pdu->msg[1];
|
||||
int i;
|
||||
|
||||
|
@ -408,7 +483,7 @@ void nas::cipher_encrypt(byte_buffer_t *pdu)
|
|||
memcpy(&pdu->msg[6], &pdu_tmp.msg[6], pdu->N_bytes-6);
|
||||
break;
|
||||
default:
|
||||
nas_log->error("Ciphering algorithmus not known");
|
||||
nas_log->error("Ciphering algorithm not known\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -474,10 +549,10 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
|
|||
return;
|
||||
}
|
||||
|
||||
LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT attach_accept;
|
||||
LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT act_def_eps_bearer_context_req;
|
||||
LIBLTE_MME_ATTACH_COMPLETE_MSG_STRUCT attach_complete;
|
||||
LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT act_def_eps_bearer_context_accept;
|
||||
LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT attach_accept = {0};
|
||||
LIBLTE_MME_ATTACH_COMPLETE_MSG_STRUCT attach_complete = {0};
|
||||
LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT act_def_eps_bearer_context_req = {0};
|
||||
LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MSG_STRUCT act_def_eps_bearer_context_accept = {0};
|
||||
|
||||
nas_log->info("Received Attach Accept\n");
|
||||
|
||||
|
@ -489,6 +564,11 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
|
|||
if (attach_accept.guti_present) {
|
||||
memcpy(&ctxt.guti, &attach_accept.guti.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT));
|
||||
have_guti = true;
|
||||
// Update RRC UE-Idenity
|
||||
LIBLTE_RRC_S_TMSI_STRUCT s_tmsi;
|
||||
s_tmsi.mmec = ctxt.guti.mme_code;
|
||||
s_tmsi.m_tmsi = ctxt.guti.m_tmsi;
|
||||
rrc->set_ue_idenity(s_tmsi);
|
||||
}
|
||||
if (attach_accept.lai_present) {}
|
||||
if (attach_accept.ms_id_present) {}
|
||||
|
@ -511,7 +591,7 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
|
|||
ip_addr |= act_def_eps_bearer_context_req.pdn_addr.addr[3];
|
||||
|
||||
nas_log->info("Network attach successful. APN: %s, IP: %u.%u.%u.%u\n",
|
||||
act_def_eps_bearer_context_req.apn.apn.c_str(),
|
||||
act_def_eps_bearer_context_req.apn.apn,
|
||||
act_def_eps_bearer_context_req.pdn_addr.addr[0],
|
||||
act_def_eps_bearer_context_req.pdn_addr.addr[1],
|
||||
act_def_eps_bearer_context_req.pdn_addr.addr[2],
|
||||
|
@ -554,8 +634,6 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
|
|||
// FIXME: Setup the default EPS bearer context
|
||||
|
||||
state = EMM_STATE_REGISTERED;
|
||||
current_plmn = selecting_plmn;
|
||||
plmn_selection = PLMN_SELECTED;
|
||||
|
||||
ctxt.rx_count++;
|
||||
|
||||
|
@ -599,7 +677,7 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
|
|||
}
|
||||
|
||||
void nas::parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu) {
|
||||
LIBLTE_MME_ATTACH_REJECT_MSG_STRUCT attach_rej;
|
||||
LIBLTE_MME_ATTACH_REJECT_MSG_STRUCT attach_rej = {0};
|
||||
|
||||
liblte_mme_unpack_attach_reject_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &attach_rej);
|
||||
nas_log->warning("Received Attach Reject. Cause= %02X\n", attach_rej.emm_cause);
|
||||
|
@ -611,7 +689,9 @@ void nas::parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu) {
|
|||
|
||||
void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) {
|
||||
LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT auth_req;
|
||||
bzero(&auth_req, sizeof(LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT));
|
||||
LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT auth_res;
|
||||
bzero(&auth_res, sizeof(LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT));
|
||||
|
||||
nas_log->info("Received Authentication Request\n");
|
||||
liblte_mme_unpack_authentication_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &auth_req);
|
||||
|
@ -666,8 +746,8 @@ void nas::parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu) {
|
|||
}
|
||||
|
||||
void nas::parse_identity_request(uint32_t lcid, byte_buffer_t *pdu) {
|
||||
LIBLTE_MME_ID_REQUEST_MSG_STRUCT id_req;
|
||||
LIBLTE_MME_ID_RESPONSE_MSG_STRUCT id_resp;
|
||||
LIBLTE_MME_ID_REQUEST_MSG_STRUCT id_req = {0};
|
||||
LIBLTE_MME_ID_RESPONSE_MSG_STRUCT id_resp = {0};
|
||||
|
||||
liblte_mme_unpack_identity_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &id_req);
|
||||
nas_log->info("Received Identity Request. ID type: %d\n", id_req.id_type);
|
||||
|
@ -711,7 +791,9 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu)
|
|||
}
|
||||
|
||||
LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT sec_mode_cmd;
|
||||
bzero(&sec_mode_cmd, sizeof(LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT));
|
||||
LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT sec_mode_comp;
|
||||
bzero(&sec_mode_comp, sizeof(LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT));
|
||||
|
||||
liblte_mme_unpack_security_mode_command_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &sec_mode_cmd);
|
||||
nas_log->info("Received Security Mode Command ksi: %d, eea: %s, eia: %s\n",
|
||||
|
@ -838,21 +920,19 @@ void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) {
|
|||
* Senders
|
||||
******************************************************************************/
|
||||
|
||||
void nas::send_attach_request() {
|
||||
|
||||
|
||||
LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT attach_req;
|
||||
byte_buffer_t *msg = pool_allocate;
|
||||
void nas::gen_attach_request(byte_buffer_t *msg) {
|
||||
if (!msg) {
|
||||
nas_log->error("Fatal Error: Couldn't allocate PDU in send_attach_request().\n");
|
||||
nas_log->error("Fatal Error: Couldn't allocate PDU in gen_attach_request().\n");
|
||||
return;
|
||||
}
|
||||
LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT attach_req;
|
||||
bzero(&attach_req, sizeof(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT));
|
||||
|
||||
u_int32_t i;
|
||||
nas_log->info("Generating attach request\n");
|
||||
|
||||
attach_req.eps_attach_type = LIBLTE_MME_EPS_ATTACH_TYPE_EPS_ATTACH;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
for (u_int32_t i = 0; i < 8; i++) {
|
||||
attach_req.ue_network_cap.eea[i] = eea_caps[i];
|
||||
attach_req.ue_network_cap.eia[i] = eia_caps[i];
|
||||
}
|
||||
|
@ -915,67 +995,19 @@ void nas::send_attach_request() {
|
|||
pcap->write_nas(msg->msg, msg->N_bytes);
|
||||
}
|
||||
|
||||
nas_log->info("Sending attach request\n");
|
||||
rrc->write_sdu(cfg.lcid, msg);
|
||||
|
||||
if (have_ctxt) {
|
||||
ctxt.tx_count++;
|
||||
}
|
||||
}
|
||||
|
||||
void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) {
|
||||
LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT pdn_con_req;
|
||||
|
||||
nas_log->info("Generating PDN Connectivity Request\n");
|
||||
|
||||
// Set the PDN con req parameters
|
||||
pdn_con_req.eps_bearer_id = 0x00; // Unassigned bearer ID
|
||||
pdn_con_req.proc_transaction_id = 0x01; // First transaction ID
|
||||
pdn_con_req.pdn_type = LIBLTE_MME_PDN_TYPE_IPV4;
|
||||
pdn_con_req.request_type = LIBLTE_MME_REQUEST_TYPE_INITIAL_REQUEST;
|
||||
|
||||
// Set the optional flags
|
||||
pdn_con_req.esm_info_transfer_flag_present = false; //FIXME: Check if this is needed
|
||||
if (cfg.apn == "") {
|
||||
pdn_con_req.apn_present = false;
|
||||
} else {
|
||||
pdn_con_req.apn_present = true;
|
||||
LIBLTE_MME_ACCESS_POINT_NAME_STRUCT apn;
|
||||
apn.apn = cfg.apn;
|
||||
pdn_con_req.apn = apn;
|
||||
}
|
||||
pdn_con_req.protocol_cnfg_opts_present = false;
|
||||
pdn_con_req.device_properties_present = false;
|
||||
|
||||
// Pack the message
|
||||
liblte_mme_pack_pdn_connectivity_request_msg(&pdn_con_req, msg);
|
||||
}
|
||||
|
||||
void nas::send_security_mode_reject(uint8_t cause) {
|
||||
byte_buffer_t *msg = pool_allocate;
|
||||
void nas::gen_service_request(byte_buffer_t *msg) {
|
||||
if (!msg) {
|
||||
nas_log->error("Fatal Error: Couldn't allocate PDU in send_security_mode_reject().\n");
|
||||
nas_log->error("Fatal Error: Couldn't allocate PDU in gen_service_request().\n");
|
||||
return;
|
||||
}
|
||||
|
||||
LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT sec_mode_rej;
|
||||
sec_mode_rej.emm_cause = cause;
|
||||
liblte_mme_pack_security_mode_reject_msg(&sec_mode_rej, (LIBLTE_BYTE_MSG_STRUCT *) msg);
|
||||
if(pcap != NULL) {
|
||||
pcap->write_nas(msg->msg, msg->N_bytes);
|
||||
}
|
||||
nas_log->info("Sending security mode reject\n");
|
||||
rrc->write_sdu(cfg.lcid, msg);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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);
|
||||
|
@ -1001,11 +1033,56 @@ void nas::send_service_request() {
|
|||
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::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) {
|
||||
LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT pdn_con_req = {0};
|
||||
|
||||
nas_log->info("Generating PDN Connectivity Request\n");
|
||||
|
||||
// Set the PDN con req parameters
|
||||
pdn_con_req.eps_bearer_id = 0x00; // Unassigned bearer ID
|
||||
pdn_con_req.proc_transaction_id = 0x01; // First transaction ID
|
||||
pdn_con_req.pdn_type = LIBLTE_MME_PDN_TYPE_IPV4;
|
||||
pdn_con_req.request_type = LIBLTE_MME_REQUEST_TYPE_INITIAL_REQUEST;
|
||||
|
||||
// Set the optional flags
|
||||
pdn_con_req.esm_info_transfer_flag_present = false; //FIXME: Check if this is needed
|
||||
if (cfg.apn == "") {
|
||||
pdn_con_req.apn_present = false;
|
||||
} else {
|
||||
pdn_con_req.apn_present = true;
|
||||
LIBLTE_MME_ACCESS_POINT_NAME_STRUCT apn = {0};
|
||||
strncpy(apn.apn, cfg.apn.c_str(), LIBLTE_STRING_LEN);
|
||||
pdn_con_req.apn = apn;
|
||||
}
|
||||
pdn_con_req.protocol_cnfg_opts_present = false;
|
||||
pdn_con_req.device_properties_present = false;
|
||||
|
||||
// Pack the message
|
||||
liblte_mme_pack_pdn_connectivity_request_msg(&pdn_con_req, msg);
|
||||
}
|
||||
|
||||
void nas::send_security_mode_reject(uint8_t cause) {
|
||||
byte_buffer_t *msg = pool_allocate;
|
||||
if (!msg) {
|
||||
nas_log->error("Fatal Error: Couldn't allocate PDU in send_security_mode_reject().\n");
|
||||
return;
|
||||
}
|
||||
|
||||
LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT sec_mode_rej = {0};
|
||||
sec_mode_rej.emm_cause = cause;
|
||||
liblte_mme_pack_security_mode_reject_msg(&sec_mode_rej, (LIBLTE_BYTE_MSG_STRUCT *) msg);
|
||||
if(pcap != NULL) {
|
||||
pcap->write_nas(msg->msg, msg->N_bytes);
|
||||
}
|
||||
nas_log->info("Sending security mode reject\n");
|
||||
rrc->write_sdu(cfg.lcid, msg);
|
||||
}
|
||||
|
||||
void nas::send_identity_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",
|
||||
nof_bytes, dlsch_msg.sibs[0].sib.sib1.cell_id&0xfff, si_window_len, sib2_period);
|
||||
sib1_decoded = true;
|
||||
mac.bcch_stop_rx();
|
||||
mac.clear_rntis();
|
||||
} else if (dlsch_msg.sibs[0].sib_type == LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2) {
|
||||
|
||||
printf("SIB2 received %d bytes\n", nof_bytes);
|
||||
setup_mac_phy_sib2(&dlsch_msg.sibs[0].sib.sib2, &mac, &phy);
|
||||
sib2_decoded = true;
|
||||
mac.bcch_stop_rx();
|
||||
mac.clear_rntis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -380,7 +380,7 @@ int main(int argc, char *argv[])
|
|||
radio.set_tx_freq(prog_args.rf_tx_freq);
|
||||
|
||||
// Instruct the PHY to configure PRACH parameters and sync to current cell
|
||||
while(!my_phy.sync_status()) {
|
||||
while(!my_phy.cell_is_camping()) {
|
||||
usleep(20000);
|
||||
}
|
||||
|
||||
|
|
|
@ -196,7 +196,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
bool running = true;
|
||||
while(running) {
|
||||
if (bch_decoded && my_phy.sync_status()) {
|
||||
if (bch_decoded && my_phy.cell_is_camping()) {
|
||||
uint32_t tti = my_phy.get_current_tti();
|
||||
|
||||
// SIB1 is scheduled in subframe #5 of even frames, try to decode next frame SIB1
|
||||
|
@ -206,7 +206,7 @@ int main(int argc, char *argv[])
|
|||
total_pkts++;
|
||||
}
|
||||
usleep(30000);
|
||||
if (bch_decoded && my_phy.sync_status() && total_pkts > 0) {
|
||||
if (bch_decoded && my_phy.cell_is_camping() && total_pkts > 0) {
|
||||
if (srslte_verbose == SRSLTE_VERBOSE_NONE && srsapps_verbose == 0) {
|
||||
float gain = prog_args.rf_gain;
|
||||
if (gain < 0) {
|
||||
|
|
|
@ -50,6 +50,15 @@ uint8_t auth_request_pdu[] = { 0x07, 0x52, 0x01, 0x0c, 0x63, 0xa8, 0x54, 0x13, 0
|
|||
uint8_t sec_mode_command_pdu[] = { 0x37, 0x37, 0xc7, 0x67, 0xae, 0x00, 0x07, 0x5d, 0x02, 0x01,
|
||||
0x02, 0xe0, 0x60, 0xc1 };
|
||||
|
||||
uint8_t attach_accept_pdu[] = { 0x27, 0x0f, 0x4f, 0xb3, 0xef, 0x01, 0x07, 0x42, 0x01, 0x3e,
|
||||
0x06, 0x00, 0x00, 0xf1, 0x10, 0x00, 0x01, 0x00, 0x2a, 0x52,
|
||||
0x01, 0xc1, 0x01, 0x04, 0x1b, 0x07, 0x74, 0x65, 0x73, 0x74,
|
||||
0x31, 0x32, 0x33, 0x06, 0x6d, 0x6e, 0x63, 0x30, 0x30, 0x31,
|
||||
0x06, 0x6d, 0x63, 0x63, 0x30, 0x30, 0x31, 0x04, 0x67, 0x70,
|
||||
0x72, 0x73, 0x05, 0x01, 0xc0, 0xa8, 0x05, 0x02, 0x27, 0x01,
|
||||
0x80, 0x50, 0x0b, 0xf6, 0x00, 0xf1, 0x10, 0x80, 0x01, 0x01,
|
||||
0x35, 0x16, 0x6d, 0xbc, 0x64, 0x01, 0x00 };
|
||||
|
||||
uint16 mcc = 61441;
|
||||
uint16 mnc = 65281;
|
||||
|
||||
|
@ -71,18 +80,35 @@ public:
|
|||
class rrc_dummy : public rrc_interface_nas
|
||||
{
|
||||
public:
|
||||
rrc_dummy() : last_sdu_len(0) {
|
||||
plmns.plmn_id.mcc = mcc;
|
||||
plmns.plmn_id.mnc = mnc;
|
||||
plmns.tac = 0xffff;
|
||||
}
|
||||
void write_sdu(uint32_t lcid, byte_buffer_t *sdu)
|
||||
{
|
||||
printf("NAS generated SDU (len=%d):\n", sdu->N_bytes);
|
||||
last_sdu_len = sdu->N_bytes;
|
||||
srslte_vec_fprint_byte(stdout, sdu->msg, sdu->N_bytes);
|
||||
//printf("NAS generated SDU (len=%d):\n", sdu->N_bytes);
|
||||
//srslte_vec_fprint_byte(stdout, sdu->msg, sdu->N_bytes);
|
||||
byte_buffer_pool::get_instance()->deallocate(sdu);
|
||||
}
|
||||
std::string get_rb_name(uint32_t lcid) { return std::string("lcid"); }
|
||||
uint32_t get_last_sdu_len() { return last_sdu_len; }
|
||||
|
||||
void plmn_search() {};
|
||||
void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, bool con_req) {};
|
||||
int plmn_search(srsue::rrc_interface_nas::found_plmn_t* found) {
|
||||
memcpy(found, &plmns, sizeof(found_plmn_t));
|
||||
return 1;
|
||||
};
|
||||
void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) {};
|
||||
void set_ue_idenity(LIBLTE_RRC_S_TMSI_STRUCT s_tmsi) {}
|
||||
bool connection_request(LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM cause, srslte::byte_buffer_t *sdu) {
|
||||
printf("NAS generated SDU (len=%d):\n", sdu->N_bytes);
|
||||
last_sdu_len = sdu->N_bytes;
|
||||
srslte_vec_fprint_byte(stdout, sdu->msg, sdu->N_bytes);
|
||||
byte_buffer_pool::get_instance()->deallocate(sdu);
|
||||
return true;
|
||||
}
|
||||
bool is_connected() {return false;}
|
||||
|
||||
uint16_t get_mcc() { return mcc; }
|
||||
uint16_t get_mnc() { return mnc; }
|
||||
|
@ -90,6 +116,7 @@ public:
|
|||
|
||||
private:
|
||||
uint32_t last_sdu_len;
|
||||
found_plmn_t plmns;
|
||||
};
|
||||
|
||||
class gw_dummy : public gw_interface_nas, public gw_interface_pdcp
|
||||
|
@ -130,15 +157,12 @@ int security_command_test()
|
|||
uint8_t res[16];
|
||||
usim.init(&args, &usim_log);
|
||||
|
||||
srslte::byte_buffer_pool *pool;
|
||||
pool = byte_buffer_pool::get_instance();
|
||||
|
||||
srsue::nas nas;
|
||||
srslte_nas_config_t cfg;
|
||||
nas.init(&usim, &rrc_dummy, &gw, &nas_log, cfg);
|
||||
|
||||
// push auth request PDU to NAS to generate security context
|
||||
byte_buffer_t* tmp = pool->allocate();
|
||||
byte_buffer_t* tmp = byte_buffer_pool::get_instance()->allocate();
|
||||
memcpy(tmp->msg, auth_request_pdu, sizeof(auth_request_pdu));
|
||||
tmp->N_bytes = sizeof(auth_request_pdu);
|
||||
nas.write_pdu(LCID, tmp);
|
||||
|
@ -155,7 +179,7 @@ int security_command_test()
|
|||
ret = SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
pool->cleanup();
|
||||
byte_buffer_pool::get_instance()->cleanup();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -190,13 +214,22 @@ int mme_attach_request_test()
|
|||
nas.init(&usim, &rrc_dummy, &gw, &nas_log, nas_cfg);
|
||||
|
||||
nas.attach_request();
|
||||
nas.notify_connection_setup();
|
||||
|
||||
// check length of generated NAS SDU
|
||||
// this will time out in the first place
|
||||
|
||||
// finally push attach accept
|
||||
byte_buffer_t* tmp = byte_buffer_pool::get_instance()->allocate();
|
||||
memcpy(tmp->msg, attach_accept_pdu, sizeof(attach_accept_pdu));
|
||||
tmp->N_bytes = sizeof(attach_accept_pdu);
|
||||
nas.write_pdu(LCID, tmp);
|
||||
|
||||
// check length of generated NAS SDU (attach complete)
|
||||
if (rrc_dummy.get_last_sdu_len() > 3) {
|
||||
ret = SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
byte_buffer_pool::get_instance()->cleanup();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,9 @@
|
|||
# from antenna to timestamp insertion.
|
||||
# Default "auto". B210 USRP: 100 samples, bladeRF: 27.
|
||||
# burst_preamble_us: Preamble length to transmit before start of burst.
|
||||
# Default "auto". B210 USRP: 400 us, bladeRF: 0 us.
|
||||
# Default "auto". B210 USRP: 400 us, bladeRF: 0 us.
|
||||
# continuous_tx: Transmit samples continuously to the radio or on bursts (auto/yes/no).
|
||||
# Default is auto (yes for UHD, no for rest)
|
||||
#####################################################################
|
||||
[rf]
|
||||
dl_earfcn = 3400
|
||||
|
@ -33,6 +35,7 @@ rx_gain = 40
|
|||
#device_args = auto
|
||||
#time_adv_nsamples = auto
|
||||
#burst_preamble_us = auto
|
||||
#continuous_tx = auto
|
||||
|
||||
|
||||
#####################################################################
|
||||
|
@ -150,7 +153,9 @@ enable = false
|
|||
# sampling frequency offset. Default is enabled.
|
||||
# sss_algorithm: Selects the SSS estimation algorithm. Can choose between
|
||||
# {full, partial, diff}.
|
||||
# estimator_fil_w: Chooses the coefficients for the 3-tap channel estimator centered filter.
|
||||
# estimator_fil_auto: The channel estimator smooths the channel estimate with an adaptative filter.
|
||||
# estimator_fil_stddev: Sets the channel estimator smooth gaussian filter standard deviation.
|
||||
# estimator_fil_order: Sets the channel estimator smooth gaussian filter order (even values perform better).
|
||||
# The taps are [w, 1-2w, w]
|
||||
# metrics_period_secs: Sets the period at which metrics are requested from the UE.
|
||||
#
|
||||
|
@ -204,7 +209,9 @@ enable = false
|
|||
#time_correct_period = 5
|
||||
#sfo_correct_disable = false
|
||||
#sss_algorithm = full
|
||||
#estimator_fil_w = 0.1
|
||||
#estimator_fil_auto = false
|
||||
#estimator_fil_stddev = 1.0
|
||||
#estimator_fil_order = 4
|
||||
#average_subframe_enabled = true
|
||||
#sic_pss_enabled = true
|
||||
#pregenerate_signals = false
|
||||
|
|
Loading…
Reference in New Issue