upgraded to new code restruct
This commit is contained in:
parent
c47c4b8b03
commit
4b5cbafdb5
|
@ -101,6 +101,16 @@ public:
|
||||||
virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0;
|
virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0;
|
||||||
virtual uint32_t get_ul_count() = 0;
|
virtual uint32_t get_ul_count() = 0;
|
||||||
virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 0;
|
virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 0;
|
||||||
|
virtual void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) = 0;
|
||||||
|
virtual void cell_selected() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// NAS interface for UE
|
||||||
|
class nas_interface_ue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void attach_request() = 0;
|
||||||
|
virtual void deattach_request() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// RRC interface for MAC
|
// RRC interface for MAC
|
||||||
|
@ -117,6 +127,7 @@ class rrc_interface_phy
|
||||||
public:
|
public:
|
||||||
virtual void in_sync() = 0;
|
virtual void in_sync() = 0;
|
||||||
virtual void out_of_sync() = 0;
|
virtual void out_of_sync() = 0;
|
||||||
|
virtual void cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// RRC interface for NAS
|
// RRC interface for NAS
|
||||||
|
@ -127,14 +138,18 @@ public:
|
||||||
virtual uint16_t get_mcc() = 0;
|
virtual uint16_t get_mcc() = 0;
|
||||||
virtual uint16_t get_mnc() = 0;
|
virtual uint16_t get_mnc() = 0;
|
||||||
virtual void enable_capabilities() = 0;
|
virtual void enable_capabilities() = 0;
|
||||||
|
virtual void plmn_search() = 0;
|
||||||
|
virtual void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) = 0;
|
||||||
|
virtual void connect() = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// RRC interface for GW
|
// RRC interface for GW
|
||||||
class rrc_interface_gw
|
class rrc_interface_gw
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual bool rrc_connected() = 0;
|
virtual bool is_connected() = 0;
|
||||||
virtual void rrc_connect() = 0;
|
virtual void connect() = 0;
|
||||||
virtual bool have_drb() = 0;
|
virtual bool have_drb() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -400,8 +415,7 @@ public:
|
||||||
virtual void configure_prach_params() = 0;
|
virtual void configure_prach_params() = 0;
|
||||||
|
|
||||||
/* Start synchronization with strongest cell in the current carrier frequency */
|
/* Start synchronization with strongest cell in the current carrier frequency */
|
||||||
virtual void sync_start() = 0;
|
virtual bool sync_status() = 0;
|
||||||
virtual void sync_stop() = 0;
|
|
||||||
|
|
||||||
/* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */
|
/* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */
|
||||||
virtual void set_crnti(uint16_t rnti) = 0;
|
virtual void set_crnti(uint16_t rnti) = 0;
|
||||||
|
@ -463,8 +477,13 @@ public:
|
||||||
virtual void set_config_tdd(LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd) = 0;
|
virtual void set_config_tdd(LIBLTE_RRC_TDD_CONFIG_STRUCT *tdd) = 0;
|
||||||
virtual void set_config_64qam_en(bool enable) = 0;
|
virtual void set_config_64qam_en(bool enable) = 0;
|
||||||
|
|
||||||
|
/* Cell search and selection procedures */
|
||||||
|
virtual void cell_search_start() = 0;
|
||||||
|
virtual void cell_search_next() = 0;
|
||||||
|
virtual bool cell_select(uint32_t earfcn, srslte_cell_t cell) = 0;
|
||||||
|
|
||||||
/* Is the PHY downlink synchronized? */
|
/* Is the PHY downlink synchronized? */
|
||||||
virtual bool status_is_sync() = 0;
|
virtual bool sync_status() = 0;
|
||||||
|
|
||||||
/* Configure UL using parameters written with set_param() */
|
/* Configure UL using parameters written with set_param() */
|
||||||
virtual void configure_ul_params(bool pregen_disabled = false) = 0;
|
virtual void configure_ul_params(bool pregen_disabled = false) = 0;
|
||||||
|
|
|
@ -249,8 +249,8 @@ void gw::run_thread()
|
||||||
{
|
{
|
||||||
gw_log->info_hex(pdu->msg, pdu->N_bytes, "TX PDU");
|
gw_log->info_hex(pdu->msg, pdu->N_bytes, "TX PDU");
|
||||||
|
|
||||||
while(run_enable && (!rrc->rrc_connected() || !rrc->have_drb())) {
|
while(run_enable && (!rrc->is_connected() || !rrc->have_drb())) {
|
||||||
rrc->rrc_connect();
|
rrc->connect();
|
||||||
usleep(1000);
|
usleep(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,10 +53,14 @@ public:
|
||||||
|
|
||||||
void resync_sfn();
|
void resync_sfn();
|
||||||
|
|
||||||
|
void set_earfcn(std::vector<uint32_t> earfcn);
|
||||||
|
|
||||||
|
void cell_search_start();
|
||||||
|
void cell_search_next();
|
||||||
|
bool cell_select(uint32_t earfcn, srslte_cell_t cell);
|
||||||
|
|
||||||
uint32_t get_current_tti();
|
uint32_t get_current_tti();
|
||||||
|
|
||||||
void sync_start();
|
|
||||||
void sync_stop();
|
|
||||||
bool status_is_sync();
|
bool status_is_sync();
|
||||||
|
|
||||||
void set_time_adv_sec(float time_adv_sec);
|
void set_time_adv_sec(float time_adv_sec);
|
||||||
|
@ -66,6 +70,8 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
std::vector<uint32_t> earfcn;
|
||||||
|
|
||||||
void set_ue_sync_opts(srslte_ue_sync_t *q);
|
void set_ue_sync_opts(srslte_ue_sync_t *q);
|
||||||
void run_thread();
|
void run_thread();
|
||||||
int sync_sfn();
|
int sync_sfn();
|
||||||
|
@ -91,7 +97,7 @@ private:
|
||||||
sync_metrics_t metrics;
|
sync_metrics_t metrics;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
IDLE, CELL_SEARCH, SYNCING, SYNC_DONE
|
IDLE, CELL_SEARCH, CELL_SELECT, CAMPING
|
||||||
} phy_state;
|
} phy_state;
|
||||||
|
|
||||||
srslte_cell_t cell;
|
srslte_cell_t cell;
|
||||||
|
@ -111,6 +117,7 @@ private:
|
||||||
uint32_t sync_sfn_cnt;
|
uint32_t sync_sfn_cnt;
|
||||||
const static uint32_t SYNC_SFN_TIMEOUT = 5000;
|
const static uint32_t SYNC_SFN_TIMEOUT = 5000;
|
||||||
float ul_dl_factor;
|
float ul_dl_factor;
|
||||||
|
int cur_earfcn_index;
|
||||||
|
|
||||||
bool cell_search(int force_N_id_2 = -1);
|
bool cell_search(int force_N_id_2 = -1);
|
||||||
bool init_cell();
|
bool init_cell();
|
||||||
|
|
|
@ -71,16 +71,19 @@ public:
|
||||||
void start_trace();
|
void start_trace();
|
||||||
void write_trace(std::string filename);
|
void write_trace(std::string filename);
|
||||||
|
|
||||||
|
void set_earfcn(std::vector<uint32_t> earfcns);
|
||||||
|
|
||||||
/********** RRC INTERFACE ********************/
|
/********** RRC INTERFACE ********************/
|
||||||
void reset();
|
void reset();
|
||||||
bool status_is_sync();
|
|
||||||
void configure_ul_params(bool pregen_disabled = false);
|
void configure_ul_params(bool pregen_disabled = false);
|
||||||
void resync_sfn();
|
void resync_sfn();
|
||||||
|
void cell_search_start();
|
||||||
|
void cell_search_next();
|
||||||
|
bool cell_select(uint32_t earfcn, srslte_cell_t phy_cell);
|
||||||
|
|
||||||
/********** MAC INTERFACE ********************/
|
/********** MAC INTERFACE ********************/
|
||||||
/* Functions to synchronize with a cell */
|
/* Functions to synchronize with a cell */
|
||||||
void sync_start();
|
bool sync_status(); // this is also RRC interface
|
||||||
void sync_stop();
|
|
||||||
|
|
||||||
/* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */
|
/* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */
|
||||||
void set_crnti(uint16_t rnti);
|
void set_crnti(uint16_t rnti);
|
||||||
|
|
|
@ -57,26 +57,45 @@ static const char emm_state_text[EMM_STATE_N_ITEMS][100] = {"NULL",
|
||||||
"DEREGISTERED INITIATED",
|
"DEREGISTERED INITIATED",
|
||||||
"TRACKING AREA UPDATE INITIATED"};
|
"TRACKING AREA UPDATE INITIATED"};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PLMN_NOT_SELECTED = 0,
|
||||||
|
PLMN_SELECTED
|
||||||
|
} plmn_selection_state_t;
|
||||||
|
|
||||||
class nas
|
class nas
|
||||||
:public nas_interface_rrc
|
: public nas_interface_rrc, public nas_interface_ue {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
nas();
|
nas();
|
||||||
|
|
||||||
void init(usim_interface_nas *usim_,
|
void init(usim_interface_nas *usim_,
|
||||||
rrc_interface_nas *rrc_,
|
rrc_interface_nas *rrc_,
|
||||||
gw_interface_nas *gw_,
|
gw_interface_nas *gw_,
|
||||||
srslte::log *nas_log_);
|
srslte::log *nas_log_);
|
||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
emm_state_t get_state();
|
emm_state_t get_state();
|
||||||
|
|
||||||
// RRC interface
|
// RRC interface
|
||||||
void notify_connection_setup();
|
void notify_connection_setup();
|
||||||
|
|
||||||
void write_pdu(uint32_t lcid, byte_buffer_t *pdu);
|
void write_pdu(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
uint32_t get_ul_count();
|
uint32_t get_ul_count();
|
||||||
|
|
||||||
bool is_attached();
|
bool is_attached();
|
||||||
|
|
||||||
bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi);
|
bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi);
|
||||||
|
|
||||||
|
void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code);
|
||||||
|
|
||||||
|
void cell_selected();
|
||||||
|
|
||||||
|
// UE interface
|
||||||
|
void attach_request();
|
||||||
|
|
||||||
|
void deattach_request();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
srslte::byte_buffer_pool *pool;
|
srslte::byte_buffer_pool *pool;
|
||||||
srslte::log *nas_log;
|
srslte::log *nas_log;
|
||||||
|
@ -86,6 +105,9 @@ private:
|
||||||
|
|
||||||
emm_state_t state;
|
emm_state_t state;
|
||||||
|
|
||||||
|
plmn_selection_state_t plmn_selection;
|
||||||
|
LIBLTE_RRC_PLMN_IDENTITY_STRUCT current_plmn;
|
||||||
|
|
||||||
// Save short MAC
|
// Save short MAC
|
||||||
|
|
||||||
// Identifiers
|
// Identifiers
|
||||||
|
@ -116,25 +138,39 @@ private:
|
||||||
uint8_t *msg,
|
uint8_t *msg,
|
||||||
uint32_t msg_len,
|
uint32_t msg_len,
|
||||||
uint8_t *mac);
|
uint8_t *mac);
|
||||||
|
|
||||||
void integrity_check();
|
void integrity_check();
|
||||||
|
|
||||||
void cipher_encrypt();
|
void cipher_encrypt();
|
||||||
|
|
||||||
void cipher_decrypt();
|
void cipher_decrypt();
|
||||||
|
|
||||||
// Parsers
|
// Parsers
|
||||||
void parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu);
|
void parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
void parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu);
|
void parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
void parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu);
|
void parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
void parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu);
|
void parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
void parse_identity_request(uint32_t lcid, byte_buffer_t *pdu);
|
void parse_identity_request(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
void parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu);
|
void parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
void parse_service_reject(uint32_t lcid, byte_buffer_t *pdu);
|
void parse_service_reject(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
void parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu);
|
void parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
void parse_emm_information(uint32_t lcid, byte_buffer_t *pdu);
|
void parse_emm_information(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
// Senders
|
// Senders
|
||||||
void send_attach_request();
|
void send_attach_request();
|
||||||
|
|
||||||
void send_identity_response();
|
void send_identity_response();
|
||||||
|
|
||||||
void send_service_request();
|
void send_service_request();
|
||||||
|
|
||||||
void send_esm_information_response();
|
void send_esm_information_response();
|
||||||
|
|
||||||
void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg);
|
void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg);
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "srslte/common/common.h"
|
#include "srslte/common/common.h"
|
||||||
#include "srslte/interfaces/ue_interfaces.h"
|
#include "srslte/interfaces/ue_interfaces.h"
|
||||||
#include "srslte/common/security.h"
|
#include "srslte/common/security.h"
|
||||||
|
#include "srslte/common/threads.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
@ -44,32 +45,40 @@ namespace srsue {
|
||||||
// RRC states (3GPP 36.331 v10.0.0)
|
// RRC states (3GPP 36.331 v10.0.0)
|
||||||
typedef enum {
|
typedef enum {
|
||||||
RRC_STATE_IDLE = 0,
|
RRC_STATE_IDLE = 0,
|
||||||
RRC_STATE_SIB1_SEARCH,
|
RRC_STATE_PLMN_SELECTION,
|
||||||
RRC_STATE_SIB2_SEARCH,
|
RRC_STATE_CELL_SELECTING,
|
||||||
RRC_STATE_WAIT_FOR_CON_SETUP,
|
RRC_STATE_CELL_SELECTED,
|
||||||
RRC_STATE_COMPLETING_SETUP,
|
RRC_STATE_CONNECTING,
|
||||||
RRC_STATE_RRC_CONNECTED,
|
RRC_STATE_CONNECTED,
|
||||||
RRC_STATE_N_ITEMS,
|
RRC_STATE_N_ITEMS,
|
||||||
} rrc_state_t;
|
} rrc_state_t;
|
||||||
static const char rrc_state_text[RRC_STATE_N_ITEMS][100] = {"IDLE",
|
static const char rrc_state_text[RRC_STATE_N_ITEMS][100] = {"IDLE",
|
||||||
"SIB1_SEARCH",
|
"PLMN SELECTION",
|
||||||
"SIB2_SEARCH",
|
"CELL SELECTION",
|
||||||
"WAIT FOR CON SETUP",
|
"CONNECTING",
|
||||||
"COMPLETING SETUP",
|
"CONNECTED",
|
||||||
"RRC CONNECTED"};
|
"RRC CONNECTED"};
|
||||||
|
typedef enum {
|
||||||
|
SI_ACQUIRE_IDLE = 0,
|
||||||
|
SI_ACQUIRE_SIB1,
|
||||||
|
SI_ACQUIRE_SIB2,
|
||||||
|
SI_ACQUIRE_DONE
|
||||||
|
} si_acquire_state_t;
|
||||||
|
|
||||||
|
|
||||||
class rrc
|
class rrc
|
||||||
:public rrc_interface_nas
|
: public rrc_interface_nas,
|
||||||
,public rrc_interface_phy
|
public rrc_interface_phy,
|
||||||
,public rrc_interface_mac
|
public rrc_interface_mac,
|
||||||
,public rrc_interface_gw
|
public rrc_interface_gw,
|
||||||
,public rrc_interface_pdcp
|
public rrc_interface_pdcp,
|
||||||
,public rrc_interface_rlc
|
public rrc_interface_rlc,
|
||||||
,public srslte::timer_callback
|
public srslte::timer_callback,
|
||||||
|
public thread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
rrc();
|
rrc();
|
||||||
|
|
||||||
void init(phy_interface_rrc *phy_,
|
void init(phy_interface_rrc *phy_,
|
||||||
mac_interface_rrc *mac_,
|
mac_interface_rrc *mac_,
|
||||||
rlc_interface_rrc *rlc_,
|
rlc_interface_rrc *rlc_,
|
||||||
|
@ -78,15 +87,18 @@ public:
|
||||||
usim_interface_rrc *usim_,
|
usim_interface_rrc *usim_,
|
||||||
srslte::mac_interface_timers *mac_timers_,
|
srslte::mac_interface_timers *mac_timers_,
|
||||||
srslte::log *rrc_log_);
|
srslte::log *rrc_log_);
|
||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
rrc_state_t get_state();
|
rrc_state_t get_state();
|
||||||
|
|
||||||
void set_ue_category(int category);
|
void set_ue_category(int category);
|
||||||
|
|
||||||
// Timeout callback interface
|
// Timeout callback interface
|
||||||
void timer_expired(uint32_t timeout_id);
|
void timer_expired(uint32_t timeout_id);
|
||||||
|
|
||||||
void test_con_restablishment();
|
void test_con_restablishment();
|
||||||
|
|
||||||
void liblte_rrc_log(char *str);
|
void liblte_rrc_log(char *str);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -107,6 +119,7 @@ private:
|
||||||
uint8_t transaction_id;
|
uint8_t transaction_id;
|
||||||
bool drb_up;
|
bool drb_up;
|
||||||
|
|
||||||
|
|
||||||
uint8_t k_rrc_enc[32];
|
uint8_t k_rrc_enc[32];
|
||||||
uint8_t k_rrc_int[32];
|
uint8_t k_rrc_int[32];
|
||||||
uint8_t k_up_enc[32];
|
uint8_t k_up_enc[32];
|
||||||
|
@ -115,18 +128,12 @@ private:
|
||||||
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo;
|
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo;
|
||||||
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo;
|
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo;
|
||||||
|
|
||||||
LIBLTE_RRC_MIB_STRUCT mib;
|
|
||||||
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1;
|
|
||||||
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2;
|
|
||||||
|
|
||||||
std::map<uint32_t, LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT> srbs;
|
std::map<uint32_t, LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT> srbs;
|
||||||
std::map<uint32_t, LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT> drbs;
|
std::map<uint32_t, LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT> drbs;
|
||||||
|
|
||||||
LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg;
|
LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg;
|
||||||
LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg;
|
LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg;
|
||||||
|
|
||||||
pthread_t sib_search_thread;
|
|
||||||
|
|
||||||
// RRC constants and timers
|
// RRC constants and timers
|
||||||
srslte::mac_interface_timers *mac_timers;
|
srslte::mac_interface_timers *mac_timers;
|
||||||
uint32_t n310_cnt, N310;
|
uint32_t n310_cnt, N310;
|
||||||
|
@ -135,30 +142,63 @@ private:
|
||||||
uint32_t safe_reset_timer;
|
uint32_t safe_reset_timer;
|
||||||
int ue_category;
|
int ue_category;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t earfcn;
|
||||||
|
srslte_cell_t phy_cell;
|
||||||
|
float rsrp;
|
||||||
|
bool has_valid_sib1;
|
||||||
|
bool has_valid_sib2;
|
||||||
|
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1;
|
||||||
|
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2;
|
||||||
|
} cell_t;
|
||||||
|
|
||||||
|
std::vector<cell_t> known_cells;
|
||||||
|
cell_t *current_cell;
|
||||||
|
|
||||||
|
si_acquire_state_t si_acquire_state;
|
||||||
|
|
||||||
|
void select_next_cell_in_plmn();
|
||||||
|
LIBLTE_RRC_PLMN_IDENTITY_STRUCT selected_plmn_id;
|
||||||
|
int last_selected_cell;
|
||||||
|
|
||||||
|
bool thread_running;
|
||||||
|
void run_thread();
|
||||||
|
|
||||||
// NAS interface
|
// NAS interface
|
||||||
void write_sdu(uint32_t lcid, byte_buffer_t *sdu);
|
void write_sdu(uint32_t lcid, byte_buffer_t *sdu);
|
||||||
|
|
||||||
uint16_t get_mcc();
|
uint16_t get_mcc();
|
||||||
|
|
||||||
uint16_t get_mnc();
|
uint16_t get_mnc();
|
||||||
|
|
||||||
void enable_capabilities();
|
void enable_capabilities();
|
||||||
|
void plmn_search();
|
||||||
|
void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id);
|
||||||
|
void connect();
|
||||||
|
|
||||||
// PHY interface
|
// PHY interface
|
||||||
void in_sync();
|
void in_sync();
|
||||||
|
|
||||||
void out_of_sync();
|
void out_of_sync();
|
||||||
|
void cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp);
|
||||||
|
|
||||||
// MAC interface
|
// MAC interface
|
||||||
void release_pucch_srs();
|
void release_pucch_srs();
|
||||||
|
|
||||||
void ra_problem();
|
void ra_problem();
|
||||||
|
|
||||||
// GW interface
|
// GW interface
|
||||||
bool rrc_connected();
|
bool is_connected();
|
||||||
void rrc_connect();
|
|
||||||
bool have_drb();
|
bool have_drb();
|
||||||
|
|
||||||
// PDCP interface
|
// PDCP interface
|
||||||
void write_pdu(uint32_t lcid, byte_buffer_t *pdu);
|
void write_pdu(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
void write_pdu_bcch_bch(byte_buffer_t *pdu);
|
void write_pdu_bcch_bch(byte_buffer_t *pdu);
|
||||||
|
|
||||||
void write_pdu_bcch_dlsch(byte_buffer_t *pdu);
|
void write_pdu_bcch_dlsch(byte_buffer_t *pdu);
|
||||||
|
|
||||||
void write_pdu_pcch(byte_buffer_t *pdu);
|
void write_pdu_pcch(byte_buffer_t *pdu);
|
||||||
|
|
||||||
// RLC interface
|
// RLC interface
|
||||||
|
@ -166,41 +206,65 @@ private:
|
||||||
|
|
||||||
// Senders
|
// Senders
|
||||||
void send_con_request();
|
void send_con_request();
|
||||||
|
|
||||||
void send_con_restablish_request();
|
void send_con_restablish_request();
|
||||||
|
|
||||||
void send_con_restablish_complete();
|
void send_con_restablish_complete();
|
||||||
|
|
||||||
void send_con_setup_complete(byte_buffer_t *nas_msg);
|
void send_con_setup_complete(byte_buffer_t *nas_msg);
|
||||||
|
|
||||||
void send_ul_info_transfer(uint32_t lcid, byte_buffer_t *sdu);
|
void send_ul_info_transfer(uint32_t lcid, byte_buffer_t *sdu);
|
||||||
|
|
||||||
void send_security_mode_complete(uint32_t lcid, byte_buffer_t *pdu);
|
void send_security_mode_complete(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
void send_rrc_con_reconfig_complete(uint32_t lcid, byte_buffer_t *pdu);
|
void send_rrc_con_reconfig_complete(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
void send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu);
|
void send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
// Parsers
|
// Parsers
|
||||||
void parse_dl_ccch(byte_buffer_t *pdu);
|
void parse_dl_ccch(byte_buffer_t *pdu);
|
||||||
|
|
||||||
void parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu);
|
void parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
void parse_dl_info_transfer(uint32_t lcid, byte_buffer_t *pdu);
|
void parse_dl_info_transfer(uint32_t lcid, byte_buffer_t *pdu);
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
void reset_ue();
|
void reset_ue();
|
||||||
|
|
||||||
void rrc_connection_release();
|
void rrc_connection_release();
|
||||||
|
|
||||||
void radio_link_failure();
|
void radio_link_failure();
|
||||||
static void* start_sib_thread(void *rrc_);
|
|
||||||
void sib_search();
|
|
||||||
uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t x);
|
uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t x);
|
||||||
void apply_sib2_configs();
|
|
||||||
|
void apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2);
|
||||||
|
|
||||||
void handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup);
|
void handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup);
|
||||||
|
|
||||||
void handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup);
|
void handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup);
|
||||||
void handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig, byte_buffer_t *pdu);
|
|
||||||
|
void
|
||||||
|
handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig, byte_buffer_t *pdu);
|
||||||
|
|
||||||
void add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg);
|
void add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg);
|
||||||
|
|
||||||
void add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg);
|
void add_drb(LIBLTE_RRC_DRB_TO_ADD_MOD_STRUCT *drb_cnfg);
|
||||||
|
|
||||||
void release_drb(uint8_t lcid);
|
void release_drb(uint8_t lcid);
|
||||||
|
|
||||||
void apply_rr_config_dedicated(LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT *cnfg);
|
void apply_rr_config_dedicated(LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT *cnfg);
|
||||||
|
|
||||||
void apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *phy_cnfg, bool apply_defaults);
|
void apply_phy_config_dedicated(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *phy_cnfg, bool apply_defaults);
|
||||||
|
|
||||||
void apply_mac_config_dedicated(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_cfg, bool apply_defaults);
|
void apply_mac_config_dedicated(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT *mac_cfg, bool apply_defaults);
|
||||||
|
|
||||||
// Helpers for setting default values
|
// Helpers for setting default values
|
||||||
void set_phy_default_pucch_srs();
|
void set_phy_default_pucch_srs();
|
||||||
|
|
||||||
void set_phy_default();
|
void set_phy_default();
|
||||||
|
|
||||||
void set_mac_default();
|
void set_mac_default();
|
||||||
|
|
||||||
void set_rrc_default();
|
void set_rrc_default();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -139,23 +139,22 @@ void mac::reset()
|
||||||
void mac::run_thread() {
|
void mac::run_thread() {
|
||||||
int cnt=0;
|
int cnt=0;
|
||||||
|
|
||||||
Info("Waiting PHY to synchronize with cell\n");
|
|
||||||
phy_h->sync_start();
|
|
||||||
while(!phy_h->get_current_tti() && started) {
|
|
||||||
usleep(50000);
|
|
||||||
}
|
|
||||||
Debug("Setting ttysync to %d\n", phy_h->get_current_tti());
|
|
||||||
ttisync.set_producer_cntr(phy_h->get_current_tti());
|
|
||||||
|
|
||||||
while(started) {
|
while(started) {
|
||||||
|
|
||||||
|
while (!phy_h->sync_status()) {
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (started && phy_h->sync_status()) {
|
||||||
/* Warning: Here order of invocation of procedures is important!! */
|
/* Warning: Here order of invocation of procedures is important!! */
|
||||||
ttisync.wait();
|
ttisync.wait();
|
||||||
tti = phy_h->get_current_tti();
|
tti = phy_h->get_current_tti();
|
||||||
|
|
||||||
if (started) {
|
|
||||||
log_h->step(tti);
|
log_h->step(tti);
|
||||||
|
|
||||||
timers_db.step_all();
|
timers_db.step_all();
|
||||||
|
|
||||||
// Step all procedures
|
// Step all procedures
|
||||||
|
@ -488,7 +487,7 @@ void mac::upper_timers::reset()
|
||||||
/********************************************************
|
/********************************************************
|
||||||
*
|
*
|
||||||
* Class that runs a thread to process DL MAC PDUs from
|
* Class that runs a thread to process DL MAC PDUs from
|
||||||
* DEMU unit
|
* DEMUX unit
|
||||||
*
|
*
|
||||||
*******************************************************/
|
*******************************************************/
|
||||||
mac::pdu_process::pdu_process(demux *demux_unit_)
|
mac::pdu_process::pdu_process(demux *demux_unit_)
|
||||||
|
|
|
@ -45,8 +45,8 @@ phch_recv::phch_recv() {
|
||||||
|
|
||||||
void phch_recv::init(srslte::radio_multi *_radio_handler, mac_interface_phy *_mac, rrc_interface_phy *_rrc,
|
void phch_recv::init(srslte::radio_multi *_radio_handler, mac_interface_phy *_mac, rrc_interface_phy *_rrc,
|
||||||
prach *_prach_buffer, srslte::thread_pool *_workers_pool,
|
prach *_prach_buffer, srslte::thread_pool *_workers_pool,
|
||||||
phch_common* _worker_com, srslte::log* _log_h, uint32_t nof_rx_antennas_, uint32_t prio, int sync_cpu_affinity)
|
phch_common *_worker_com, srslte::log *_log_h, uint32_t nof_rx_antennas_, uint32_t prio,
|
||||||
{
|
int sync_cpu_affinity) {
|
||||||
radio_h = _radio_handler;
|
radio_h = _radio_handler;
|
||||||
log_h = _log_h;
|
log_h = _log_h;
|
||||||
mac = _mac;
|
mac = _mac;
|
||||||
|
@ -88,13 +88,11 @@ void phch_recv::stop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void phch_recv::set_agc_enable(bool enable)
|
void phch_recv::set_agc_enable(bool enable) {
|
||||||
{
|
|
||||||
do_agc = enable;
|
do_agc = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
int radio_recv_wrapper_cs(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time)
|
int radio_recv_wrapper_cs(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) {
|
||||||
{
|
|
||||||
srslte::radio_multi *radio_h = (srslte::radio_multi *) h;
|
srslte::radio_multi *radio_h = (srslte::radio_multi *) h;
|
||||||
if (radio_h->rx_now(data, nsamples, rx_time)) {
|
if (radio_h->rx_now(data, nsamples, rx_time)) {
|
||||||
int offset = nsamples - radio_h->get_tti_len();
|
int offset = nsamples - radio_h->get_tti_len();
|
||||||
|
@ -148,10 +146,8 @@ void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q) {
|
||||||
|
|
||||||
bool phch_recv::init_cell() {
|
bool phch_recv::init_cell() {
|
||||||
cell_is_set = false;
|
cell_is_set = false;
|
||||||
if (!srslte_ue_mib_init(&ue_mib, cell))
|
if (!srslte_ue_mib_init(&ue_mib, cell)) {
|
||||||
{
|
if (!srslte_ue_sync_init_multi(&ue_sync, cell, radio_recv_wrapper_cs, nof_rx_antennas, radio_h)) {
|
||||||
if (!srslte_ue_sync_init_multi(&ue_sync, cell, radio_recv_wrapper_cs, nof_rx_antennas, radio_h))
|
|
||||||
{
|
|
||||||
|
|
||||||
// Set options defined in expert section
|
// Set options defined in expert section
|
||||||
set_ue_sync_opts(&ue_sync);
|
set_ue_sync_opts(&ue_sync);
|
||||||
|
@ -177,19 +173,23 @@ bool phch_recv::init_cell() {
|
||||||
return cell_is_set;
|
return cell_is_set;
|
||||||
}
|
}
|
||||||
|
|
||||||
void phch_recv::free_cell()
|
void phch_recv::free_cell() {
|
||||||
{
|
if (phy_state != IDLE) {
|
||||||
|
phy_state = IDLE;
|
||||||
|
usleep(2000);
|
||||||
|
}
|
||||||
|
|
||||||
if (cell_is_set) {
|
if (cell_is_set) {
|
||||||
for (uint32_t i = 0; i < workers_pool->get_nof_workers(); i++) {
|
for (uint32_t i = 0; i < workers_pool->get_nof_workers(); i++) {
|
||||||
((phch_worker *) workers_pool->get_worker(i))->free_cell();
|
((phch_worker *) workers_pool->get_worker(i))->free_cell();
|
||||||
}
|
}
|
||||||
prach_buffer->free_cell();
|
prach_buffer->free_cell();
|
||||||
|
cell_is_set = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool phch_recv::cell_search(int force_N_id_2)
|
bool phch_recv::cell_search(int force_N_id_2) {
|
||||||
{
|
|
||||||
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
|
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
|
||||||
uint8_t bch_payload_bits[SRSLTE_BCH_PAYLOAD_LEN / 8];
|
uint8_t bch_payload_bits[SRSLTE_BCH_PAYLOAD_LEN / 8];
|
||||||
|
|
||||||
|
@ -199,7 +199,8 @@ bool phch_recv::cell_search(int force_N_id_2)
|
||||||
bzero(found_cells, 3 * sizeof(srslte_ue_cellsearch_result_t));
|
bzero(found_cells, 3 * sizeof(srslte_ue_cellsearch_result_t));
|
||||||
|
|
||||||
log_h->console("Searching for cell...\n");
|
log_h->console("Searching for cell...\n");
|
||||||
if (srslte_ue_cellsearch_init_multi(&cs, SRSLTE_DEFAULT_MAX_FRAMES_PSS, radio_recv_wrapper_cs, nof_rx_antennas, radio_h)) {
|
if (srslte_ue_cellsearch_init_multi(&cs, SRSLTE_DEFAULT_MAX_FRAMES_PSS, radio_recv_wrapper_cs, nof_rx_antennas,
|
||||||
|
radio_h)) {
|
||||||
Error("Initiating UE cell search\n");
|
Error("Initiating UE cell search\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -250,7 +251,8 @@ bool phch_recv::cell_search(int force_N_id_2)
|
||||||
|
|
||||||
srslte_ue_mib_sync_t ue_mib_sync;
|
srslte_ue_mib_sync_t ue_mib_sync;
|
||||||
|
|
||||||
if (srslte_ue_mib_sync_init_multi(&ue_mib_sync, cell.id, cell.cp, radio_recv_wrapper_cs, nof_rx_antennas, radio_h)) {
|
if (srslte_ue_mib_sync_init_multi(&ue_mib_sync, cell.id, cell.cp, radio_recv_wrapper_cs, nof_rx_antennas,
|
||||||
|
radio_h)) {
|
||||||
Error("Initiating UE MIB synchronization\n");
|
Error("Initiating UE MIB synchronization\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -332,11 +334,71 @@ int phch_recv::sync_sfn(void) {
|
||||||
|
|
||||||
void phch_recv::resync_sfn() {
|
void phch_recv::resync_sfn() {
|
||||||
sync_sfn_cnt = 0;
|
sync_sfn_cnt = 0;
|
||||||
phy_state = SYNCING;
|
phy_state = CELL_SELECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void phch_recv::run_thread()
|
void phch_recv::set_earfcn(std::vector<uint32_t> earfcn) {
|
||||||
{
|
this->earfcn = earfcn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void phch_recv::cell_search_next() {
|
||||||
|
cur_earfcn_index++;
|
||||||
|
if (cur_earfcn_index >= 0) {
|
||||||
|
if ((uint32_t) cur_earfcn_index >= earfcn.size() - 1) {
|
||||||
|
cur_earfcn_index = 0;
|
||||||
|
}
|
||||||
|
// If PHY is running, stop and free resources
|
||||||
|
free_cell();
|
||||||
|
|
||||||
|
float dl_freq = srslte_band_fd(earfcn[cur_earfcn_index]);
|
||||||
|
if (dl_freq >= 0) {
|
||||||
|
log_h->console("Cell Search: Set DL EARFCN=%d, frequency=%.1f MHz\n", earfcn[cur_earfcn_index], dl_freq / 1e6);
|
||||||
|
log_h->info("Cell Search: Set DL EARFCN=%d, frequency=%.1f MHz, channel_index=%d\n", earfcn[cur_earfcn_index],
|
||||||
|
dl_freq / 1e6, cur_earfcn_index);
|
||||||
|
radio_h->set_rx_freq(dl_freq);
|
||||||
|
|
||||||
|
// Start PHY cell search (finds maximum cell in frequency)
|
||||||
|
phy_state = CELL_SEARCH;
|
||||||
|
} else {
|
||||||
|
log_h->error("Cell Search: Invalid EARFCN=%d, channel_index=%d\n", earfcn[cur_earfcn_index], cur_earfcn_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void phch_recv::cell_search_start() {
|
||||||
|
cur_earfcn_index = -1;
|
||||||
|
log_h->console("Cell Search: Starting procedure...\n");
|
||||||
|
log_h->info("Cell Search: Starting procedure...\n");
|
||||||
|
cell_search_next();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell) {
|
||||||
|
free_cell();
|
||||||
|
|
||||||
|
float dl_freq = srslte_band_fd(earfcn);
|
||||||
|
float ul_freq = srslte_band_ul_earfcn(earfcn);
|
||||||
|
if (dl_freq >= 0 || ul_freq <= 0) {
|
||||||
|
log_h->console("Cell Select: Set EARFCN=%d, DL frequency=%.1f MHz, UL frequency=%.1f MHz\n", earfcn,
|
||||||
|
dl_freq / 1e6, ul_freq / 1e6);
|
||||||
|
log_h->info("Cell Select: Set EARFCN=%d, frequency=%.1f MHz, UL frequency=%.1f MHz\n", earfcn, dl_freq / 1e6,
|
||||||
|
ul_freq / 1e6);
|
||||||
|
radio_h->set_rx_freq(dl_freq);
|
||||||
|
radio_h->set_tx_freq(ul_freq);
|
||||||
|
|
||||||
|
this->cell = cell;
|
||||||
|
if (init_cell()) {
|
||||||
|
phy_state = CELL_SELECT;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
log_h->error("Cell Select: Initializing cell in EARFCN=%d, PCI=%d\n", earfcn, cell.id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log_h->error("Cell Select: Invalid EARFCN=%d\n", earfcn);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void phch_recv::run_thread() {
|
||||||
int sync_res;
|
int sync_res;
|
||||||
phch_worker *worker = NULL;
|
phch_worker *worker = NULL;
|
||||||
cf_t *buffer[SRSLTE_MAX_PORTS];
|
cf_t *buffer[SRSLTE_MAX_PORTS];
|
||||||
|
@ -361,12 +423,12 @@ void phch_recv::run_thread()
|
||||||
ul_dl_factor = radio_h->get_tx_freq() / radio_h->get_rx_freq();
|
ul_dl_factor = radio_h->get_tx_freq() / radio_h->get_rx_freq();
|
||||||
|
|
||||||
Info("SYNC: Cell found. Synchronizing...\n");
|
Info("SYNC: Cell found. Synchronizing...\n");
|
||||||
phy_state = SYNCING;
|
phy_state = CELL_SELECT;
|
||||||
sync_sfn_cnt = 0;
|
sync_sfn_cnt = 0;
|
||||||
srslte_ue_mib_reset(&ue_mib);
|
srslte_ue_mib_reset(&ue_mib);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SYNCING:
|
case CELL_SELECT:
|
||||||
|
|
||||||
srslte_ue_sync_decode_sss_on_track(&ue_sync, true);
|
srslte_ue_sync_decode_sss_on_track(&ue_sync, true);
|
||||||
|
|
||||||
|
@ -383,7 +445,7 @@ void phch_recv::run_thread()
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
srslte_ue_sync_set_agc_period(&ue_sync, 20);
|
srslte_ue_sync_set_agc_period(&ue_sync, 20);
|
||||||
phy_state = SYNC_DONE;
|
phy_state = CAMPING;
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
|
@ -397,7 +459,7 @@ void phch_recv::run_thread()
|
||||||
log_h->warning("Timeout while synchronizing SFN\n");
|
log_h->warning("Timeout while synchronizing SFN\n");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SYNC_DONE:
|
case CAMPING:
|
||||||
tti = (tti+1) % 10240;
|
tti = (tti+1) % 10240;
|
||||||
worker = (phch_worker *) workers_pool->wait_worker(tti);
|
worker = (phch_worker *) workers_pool->wait_worker(tti);
|
||||||
sync_res = 0;
|
sync_res = 0;
|
||||||
|
@ -421,7 +483,7 @@ void phch_recv::run_thread()
|
||||||
float sample_offset = (float) srslte_ue_sync_get_sfo(&ue_sync) / 1000;
|
float sample_offset = (float) srslte_ue_sync_get_sfo(&ue_sync) / 1000;
|
||||||
worker->set_sample_offset(sample_offset);
|
worker->set_sample_offset(sample_offset);
|
||||||
|
|
||||||
/* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */
|
/* Compute TX time: Any transmission happens in TTI4 thus advance 4 ms the reception time */
|
||||||
srslte_timestamp_t rx_time, tx_time, tx_time_prach;
|
srslte_timestamp_t rx_time, tx_time, tx_time_prach;
|
||||||
srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time);
|
srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time);
|
||||||
srslte_timestamp_copy(&tx_time, &rx_time);
|
srslte_timestamp_copy(&tx_time, &rx_time);
|
||||||
|
@ -454,7 +516,7 @@ void phch_recv::run_thread()
|
||||||
rrc->out_of_sync();
|
rrc->out_of_sync();
|
||||||
worker->release();
|
worker->release();
|
||||||
worker_com->reset_ul();
|
worker_com->reset_ul();
|
||||||
phy_state = SYNCING;
|
phy_state = CELL_SELECT;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// wait_worker() only returns NULL if it's being closed. Quit now to avoid unnecessary loops here
|
// wait_worker() only returns NULL if it's being closed. Quit now to avoid unnecessary loops here
|
||||||
|
@ -468,35 +530,17 @@ void phch_recv::run_thread()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t phch_recv::get_current_tti()
|
uint32_t phch_recv::get_current_tti() {
|
||||||
{
|
|
||||||
return tti;
|
return tti;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool phch_recv::status_is_sync()
|
bool phch_recv::status_is_sync() {
|
||||||
{
|
return phy_state == CAMPING;
|
||||||
return phy_state == SYNC_DONE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void phch_recv::get_current_cell(srslte_cell_t* cell_)
|
void phch_recv::get_current_cell(srslte_cell_t *cell_) {
|
||||||
{
|
|
||||||
if (cell_) {
|
if (cell_) {
|
||||||
memcpy(cell_, &cell, sizeof(srslte_cell_t));
|
memcpy(cell_, &cell, sizeof(srslte_cell_t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void phch_recv::sync_start()
|
|
||||||
{
|
|
||||||
radio_h->set_master_clock_rate(30.72e6);
|
|
||||||
phy_state = CELL_SEARCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
void phch_recv::sync_stop()
|
|
||||||
{
|
|
||||||
free_cell();
|
|
||||||
radio_h->stop_rx();
|
|
||||||
radio_is_streaming = false;
|
|
||||||
phy_state = IDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -205,6 +205,21 @@ 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool phy::cell_select(uint32_t earfcn, srslte_cell_t phy_cell)
|
||||||
|
{
|
||||||
|
return sf_recv.cell_select(earfcn, phy_cell);
|
||||||
|
}
|
||||||
|
|
||||||
float phy::get_phr()
|
float phy::get_phr()
|
||||||
{
|
{
|
||||||
float phr = radio_handler->get_max_tx_power() - workers_common.cur_pusch_power;
|
float phr = radio_handler->get_max_tx_power() - workers_common.cur_pusch_power;
|
||||||
|
@ -280,23 +295,18 @@ int phy::sr_last_tx_tti()
|
||||||
return workers_common.sr_last_tx_tti;
|
return workers_common.sr_last_tx_tti;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool phy::status_is_sync()
|
|
||||||
{
|
|
||||||
return sf_recv.status_is_sync();
|
|
||||||
}
|
|
||||||
|
|
||||||
void phy::resync_sfn() {
|
void phy::resync_sfn() {
|
||||||
sf_recv.resync_sfn();
|
sf_recv.resync_sfn();
|
||||||
}
|
}
|
||||||
|
|
||||||
void phy::sync_start()
|
void phy::set_earfcn(vector< uint32_t > earfcns)
|
||||||
{
|
{
|
||||||
sf_recv.sync_start();
|
sf_recv.set_earfcn(earfcns);
|
||||||
}
|
}
|
||||||
|
|
||||||
void phy::sync_stop()
|
bool phy::sync_status()
|
||||||
{
|
{
|
||||||
sf_recv.sync_stop();
|
return sf_recv.status_is_sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
void phy::set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN])
|
void phy::set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN])
|
||||||
|
|
|
@ -178,11 +178,6 @@ bool ue::init(all_args_t *args_)
|
||||||
|
|
||||||
radio.register_error_handler(rf_msg);
|
radio.register_error_handler(rf_msg);
|
||||||
|
|
||||||
radio.set_rx_freq(args->rf.dl_freq);
|
|
||||||
radio.set_tx_freq(args->rf.ul_freq);
|
|
||||||
|
|
||||||
phy_log.console("Setting frequency: DL=%.1f Mhz, UL=%.1f MHz\n", args->rf.dl_freq/1e6, args->rf.ul_freq/1e6);
|
|
||||||
|
|
||||||
mac.init(&phy, &rlc, &rrc, &mac_log);
|
mac.init(&phy, &rlc, &rrc, &mac_log);
|
||||||
rlc.init(&pdcp, &rrc, this, &rlc_log, &mac);
|
rlc.init(&pdcp, &rrc, this, &rlc_log, &mac);
|
||||||
pdcp.init(&rlc, &rrc, &gw, &pdcp_log, SECURITY_DIRECTION_UPLINK);
|
pdcp.init(&rlc, &rrc, &gw, &pdcp_log, SECURITY_DIRECTION_UPLINK);
|
||||||
|
@ -258,7 +253,7 @@ bool ue::get_metrics(ue_metrics_t &m)
|
||||||
rf_metrics.rf_error = false; // Reset error flag
|
rf_metrics.rf_error = false; // Reset error flag
|
||||||
|
|
||||||
if(EMM_STATE_REGISTERED == nas.get_state()) {
|
if(EMM_STATE_REGISTERED == nas.get_state()) {
|
||||||
if(RRC_STATE_RRC_CONNECTED == rrc.get_state()) {
|
if(RRC_STATE_CONNECTED == rrc.get_state()) {
|
||||||
phy.get_metrics(m.phy);
|
phy.get_metrics(m.phy);
|
||||||
mac.get_metrics(m.mac);
|
mac.get_metrics(m.mac);
|
||||||
rlc.get_metrics(m.rlc);
|
rlc.get_metrics(m.rlc);
|
||||||
|
|
|
@ -32,39 +32,69 @@ using namespace srslte;
|
||||||
namespace srsue {
|
namespace srsue {
|
||||||
|
|
||||||
nas::nas()
|
nas::nas()
|
||||||
:state(EMM_STATE_DEREGISTERED)
|
: state(EMM_STATE_DEREGISTERED), plmn_selection(PLMN_SELECTED), is_guti_set(false), ip_addr(0), eps_bearer_id(0),
|
||||||
,is_guti_set(false)
|
count_ul(0), count_dl(0) {}
|
||||||
,ip_addr(0)
|
|
||||||
,eps_bearer_id(0)
|
|
||||||
,count_ul(0)
|
|
||||||
,count_dl(0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void nas::init(usim_interface_nas *usim_,
|
void nas::init(usim_interface_nas *usim_,
|
||||||
rrc_interface_nas *rrc_,
|
rrc_interface_nas *rrc_,
|
||||||
gw_interface_nas *gw_,
|
gw_interface_nas *gw_,
|
||||||
srslte::log *nas_log_)
|
srslte::log *nas_log_) {
|
||||||
{
|
|
||||||
pool = byte_buffer_pool::get_instance();
|
pool = byte_buffer_pool::get_instance();
|
||||||
usim = usim_;
|
usim = usim_;
|
||||||
rrc = rrc_;
|
rrc = rrc_;
|
||||||
gw = gw_;
|
gw = gw_;
|
||||||
nas_log = nas_log_;
|
nas_log = nas_log_;
|
||||||
|
state = EMM_STATE_DEREGISTERED;
|
||||||
|
|
||||||
|
// Manual PLMN selection procedure
|
||||||
|
current_plmn.mcc = 1;
|
||||||
|
current_plmn.mnc = 1;
|
||||||
|
plmn_selection = PLMN_SELECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nas::stop()
|
void nas::stop() {}
|
||||||
{}
|
|
||||||
|
|
||||||
emm_state_t nas::get_state()
|
emm_state_t nas::get_state() {
|
||||||
{
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
UE interface
|
||||||
|
*******************************************************************************/
|
||||||
|
void nas::attach_request() {
|
||||||
|
if (state == EMM_STATE_DEREGISTERED) {
|
||||||
|
state = EMM_STATE_REGISTERED_INITIATED;
|
||||||
|
if (plmn_selection == PLMN_NOT_SELECTED) {
|
||||||
|
rrc->plmn_search();
|
||||||
|
} else if (plmn_selection == PLMN_SELECTED) {
|
||||||
|
rrc->plmn_select(current_plmn);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nas_log->info("Attach request ignored. State = %s\n", emm_state_text[state]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nas::deattach_request() {
|
||||||
|
state = EMM_STATE_DEREGISTERED_INITIATED;
|
||||||
|
nas_log->info("Dettach request not supported\n");
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
RRC interface
|
RRC interface
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
void nas::plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) {
|
||||||
|
// if it's the plmn we want rrc->plmn_select() and plmn_selection = PLMN_SELECTED
|
||||||
|
}
|
||||||
|
|
||||||
|
void nas::cell_selected() {
|
||||||
|
if (state == EMM_STATE_REGISTERED_INITIATED) {
|
||||||
|
rrc->connect();
|
||||||
|
} else {
|
||||||
|
nas_log->info("Cell selcted in invalid state = %s\n", emm_state_text[state]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool nas::is_attached()
|
bool nas::is_attached()
|
||||||
{
|
{
|
||||||
return state == EMM_STATE_REGISTERED;
|
return state == EMM_STATE_REGISTERED;
|
||||||
|
@ -73,7 +103,7 @@ bool nas::is_attached()
|
||||||
void nas::notify_connection_setup()
|
void nas::notify_connection_setup()
|
||||||
{
|
{
|
||||||
nas_log->debug("State = %s\n", emm_state_text[state]);
|
nas_log->debug("State = %s\n", emm_state_text[state]);
|
||||||
if(EMM_STATE_DEREGISTERED == state) {
|
if(EMM_STATE_REGISTERED_INITIATED == state) {
|
||||||
send_attach_request();
|
send_attach_request();
|
||||||
} else {
|
} else {
|
||||||
send_service_request();
|
send_service_request();
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include "upper/rrc.h"
|
#include "upper/rrc.h"
|
||||||
#include "srslte/phy/utils/bit.h"
|
|
||||||
#include "srslte/common/security.h"
|
#include "srslte/common/security.h"
|
||||||
#include "srslte/common/bcd_helpers.h"
|
#include "srslte/common/bcd_helpers.h"
|
||||||
|
|
||||||
|
@ -39,6 +38,11 @@ using namespace srslte;
|
||||||
|
|
||||||
namespace srsue{
|
namespace srsue{
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
Base functions
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
rrc::rrc()
|
rrc::rrc()
|
||||||
:state(RRC_STATE_IDLE)
|
:state(RRC_STATE_IDLE)
|
||||||
,drb_up(false)
|
,drb_up(false)
|
||||||
|
@ -76,6 +80,11 @@ void rrc::init(phy_interface_rrc *phy_,
|
||||||
usim = usim_;
|
usim = usim_;
|
||||||
rrc_log = rrc_log_;
|
rrc_log = rrc_log_;
|
||||||
mac_timers = mac_timers_;
|
mac_timers = mac_timers_;
|
||||||
|
state = RRC_STATE_IDLE;
|
||||||
|
si_acquire_state = SI_ACQUIRE_IDLE;
|
||||||
|
|
||||||
|
thread_running = true;
|
||||||
|
start();
|
||||||
|
|
||||||
pthread_mutex_init(&mutex, NULL);
|
pthread_mutex_init(&mutex, NULL);
|
||||||
|
|
||||||
|
@ -93,7 +102,10 @@ void rrc::init(phy_interface_rrc *phy_,
|
||||||
}
|
}
|
||||||
|
|
||||||
void rrc::stop()
|
void rrc::stop()
|
||||||
{}
|
{
|
||||||
|
thread_running = false;
|
||||||
|
wait_thread_finish();
|
||||||
|
}
|
||||||
|
|
||||||
rrc_state_t rrc::get_state()
|
rrc_state_t rrc::get_state()
|
||||||
{
|
{
|
||||||
|
@ -110,66 +122,127 @@ void rrc::set_ue_category(int category)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* PLMN selection, cell selection/reselection and acquisition of SI procedures
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
NAS interface
|
NAS interface
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu)
|
|
||||||
{
|
|
||||||
rrc_log->info_hex(sdu->msg, sdu->N_bytes, "RX %s SDU", rb_id_text[lcid]);
|
|
||||||
|
|
||||||
switch(state)
|
|
||||||
{
|
|
||||||
case RRC_STATE_COMPLETING_SETUP:
|
|
||||||
send_con_setup_complete(sdu);
|
|
||||||
break;
|
|
||||||
case RRC_STATE_RRC_CONNECTED:
|
|
||||||
send_ul_info_transfer(lcid, sdu);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
rrc_log->error("SDU received from NAS while RRC state = %s", rrc_state_text[state]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t rrc::get_mcc()
|
uint16_t rrc::get_mcc()
|
||||||
{
|
{
|
||||||
if(sib1.N_plmn_ids > 0)
|
if (current_cell) {
|
||||||
return sib1.plmn_id[0].id.mcc;
|
if(current_cell->sib1.N_plmn_ids > 0) {
|
||||||
else
|
return current_cell->sib1.plmn_id[0].id.mcc;
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t rrc::get_mnc()
|
uint16_t rrc::get_mnc()
|
||||||
{
|
{
|
||||||
if(sib1.N_plmn_ids > 0)
|
if (current_cell) {
|
||||||
return sib1.plmn_id[0].id.mnc;
|
if(current_cell->sib1.N_plmn_ids > 0) {
|
||||||
else
|
return current_cell->sib1.plmn_id[0].id.mnc;
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
void rrc::plmn_search()
|
||||||
MAC interface
|
|
||||||
*******************************************************************************/
|
|
||||||
/* Reception of PUCCH/SRS release procedure (Section 5.3.13) */
|
|
||||||
void rrc::release_pucch_srs()
|
|
||||||
{
|
{
|
||||||
// Apply default configuration for PUCCH (CQI and SR) and SRS (release)
|
state = RRC_STATE_PLMN_SELECTION;
|
||||||
set_phy_default_pucch_srs();
|
phy->cell_search_start();
|
||||||
|
|
||||||
// Configure RX signals without pregeneration because default option is release
|
|
||||||
phy->configure_ul_params(true);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rrc::ra_problem() {
|
void rrc::plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id)
|
||||||
radio_link_failure();
|
{
|
||||||
|
bool sync_ok = false;
|
||||||
|
|
||||||
|
state = RRC_STATE_CELL_SELECTING;
|
||||||
|
|
||||||
|
// Sort cells according to RSRP
|
||||||
|
|
||||||
|
selected_plmn_id = plmn_id;
|
||||||
|
last_selected_cell = -1;
|
||||||
|
|
||||||
|
select_next_cell_in_plmn();
|
||||||
|
}
|
||||||
|
|
||||||
|
void rrc::connect()
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&mutex);
|
||||||
|
if(RRC_STATE_CELL_SELECTED == state) {
|
||||||
|
if (si_acquire_state == SI_ACQUIRE_IDLE) {
|
||||||
|
rrc_log->info("RRC in IDLE state - sending connection request.\n");
|
||||||
|
state = RRC_STATE_CONNECTING;
|
||||||
|
send_con_request();
|
||||||
|
} else {
|
||||||
|
rrc_log->warning("Received connect() but SI not acquired\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rrc_log->warning("Received connect() but cell is not selected\n");
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rrc::select_next_cell_in_plmn() {
|
||||||
|
for (uint32_t i=last_selected_cell+1;i<known_cells.size();i++) {
|
||||||
|
for (uint32_t j=0;j<known_cells[i].sib1.N_plmn_ids;j++) {
|
||||||
|
if (known_cells[i].sib1.plmn_id[j].id.mcc == selected_plmn_id.mcc ||
|
||||||
|
known_cells[i].sib1.plmn_id[j].id.mnc == selected_plmn_id.mnc)
|
||||||
|
{
|
||||||
|
// Check that cell satisfies S criteria
|
||||||
|
if (phy->cell_select(known_cells[i].earfcn, known_cells[i].phy_cell)) {
|
||||||
|
si_acquire_state = SI_ACQUIRE_SIB1;
|
||||||
|
last_selected_cell = i;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
PHY interface
|
PHY interface
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) {
|
||||||
|
|
||||||
|
// find if cell_id-earfcn combination already exists
|
||||||
|
for (uint32_t i=0;i<known_cells.size();i++) {
|
||||||
|
if (earfcn == known_cells[i].earfcn && phy_cell.id == known_cells[i].phy_cell.id) {
|
||||||
|
known_cells[i].rsrp = rsrp;
|
||||||
|
current_cell = &known_cells[i];
|
||||||
|
rrc_log->info("Updating cell EARFCN=%d, PCI=%d, RSRP=%d dBm\n", known_cells[i].earfcn, known_cells[i].phy_cell.id, known_cells[i].rsrp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add to list of known cells
|
||||||
|
cell_t cell;
|
||||||
|
cell.phy_cell = phy_cell;
|
||||||
|
cell.rsrp = rsrp;
|
||||||
|
cell.earfcn = earfcn;
|
||||||
|
cell.has_valid_sib1 = false;
|
||||||
|
cell.has_valid_sib2 = false;
|
||||||
|
known_cells.push_back(cell);
|
||||||
|
|
||||||
|
// save current cell
|
||||||
|
current_cell = &known_cells.back();
|
||||||
|
|
||||||
|
rrc_log->info("Found new cell EARFCN=%d, PCI=%d, RSRP=%d dBm\n", cell.earfcn, cell.phy_cell.id, cell.rsrp);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Detection of physical layer problems (5.3.11.1)
|
// Detection of physical layer problems (5.3.11.1)
|
||||||
void rrc::out_of_sync()
|
void rrc::out_of_sync()
|
||||||
{
|
{
|
||||||
|
@ -197,23 +270,237 @@ void rrc::in_sync()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
PDCP interface
|
||||||
|
*******************************************************************************/
|
||||||
|
void rrc::write_pdu_bcch_bch(byte_buffer_t *pdu)
|
||||||
|
{
|
||||||
|
pool->deallocate(pdu);
|
||||||
|
if (state == RRC_STATE_PLMN_SELECTION) {
|
||||||
|
// Do we need to do something with BCH?
|
||||||
|
rrc_log->info_hex(pdu->msg, pdu->N_bytes, "BCCH BCH message received.");
|
||||||
|
si_acquire_state = SI_ACQUIRE_SIB1;
|
||||||
|
} else {
|
||||||
|
rrc_log->warning("Received BCCH BCH in incorrect state\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rrc::write_pdu_bcch_dlsch(byte_buffer_t *pdu)
|
||||||
|
{
|
||||||
|
rrc_log->info_hex(pdu->msg, pdu->N_bytes, "BCCH DLSCH message received.");
|
||||||
|
rrc_log->info("BCCH DLSCH message Stack latency: %ld us\n", pdu->get_latency_us());
|
||||||
|
LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT dlsch_msg;
|
||||||
|
srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes*8);
|
||||||
|
bit_buf.N_bits = pdu->N_bytes*8;
|
||||||
|
pool->deallocate(pdu);
|
||||||
|
liblte_rrc_unpack_bcch_dlsch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &dlsch_msg);
|
||||||
|
|
||||||
|
if (dlsch_msg.N_sibs > 0) {
|
||||||
|
if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1 == dlsch_msg.sibs[0].sib_type && SI_ACQUIRE_SIB1 == si_acquire_state)
|
||||||
|
{
|
||||||
|
mac->bcch_stop_rx();
|
||||||
|
|
||||||
|
// Handle SIB1
|
||||||
|
memcpy(¤t_cell->sib1, &dlsch_msg.sibs[0].sib.sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT));
|
||||||
|
|
||||||
|
rrc_log->info("SIB1 received, CellID=%d, si_window=%d, sib2_period=%d\n",
|
||||||
|
current_cell->sib1.cell_id&0xfff,
|
||||||
|
liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length],
|
||||||
|
liblte_rrc_si_periodicity_num[current_cell->sib1.sched_info[0].si_periodicity]);
|
||||||
|
|
||||||
|
// Send PLMN and TAC to NAS
|
||||||
|
std::stringstream ss;
|
||||||
|
for(uint32_t i=0;i<current_cell->sib1.N_plmn_ids;i++){
|
||||||
|
std::string mcc;
|
||||||
|
std::string mnc;
|
||||||
|
mcc_to_string(current_cell->sib1.plmn_id[i].id.mcc, &mcc);
|
||||||
|
mnc_to_string(current_cell->sib1.plmn_id[i].id.mnc, &mnc);
|
||||||
|
ss << " PLMN Id: MCC " << mcc << " MNC " << mnc;
|
||||||
|
|
||||||
|
nas->plmn_found(current_cell->sib1.plmn_id[i].id, current_cell->sib1.tracking_area_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set TDD Config
|
||||||
|
if (current_cell->sib1.tdd) {
|
||||||
|
phy->set_config_tdd(¤t_cell->sib1.tdd_cnfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
rrc_log->console("SIB1 received, CellID=%d, %s\n",
|
||||||
|
current_cell->sib1.cell_id&0xfff,
|
||||||
|
ss.str().c_str());
|
||||||
|
|
||||||
|
current_cell->has_valid_sib1 = true;
|
||||||
|
si_acquire_state = SI_ACQUIRE_SIB2;
|
||||||
|
|
||||||
|
} else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2 == dlsch_msg.sibs[0].sib_type && SI_ACQUIRE_SIB2 == si_acquire_state)
|
||||||
|
{
|
||||||
|
mac->bcch_stop_rx();
|
||||||
|
|
||||||
|
// Handle SIB2
|
||||||
|
memcpy(¤t_cell->sib2, &dlsch_msg.sibs[0].sib.sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT));
|
||||||
|
rrc_log->console("SIB2 received\n");
|
||||||
|
rrc_log->info("SIB2 received\n");
|
||||||
|
|
||||||
|
apply_sib2_configs(¤t_cell->sib2);
|
||||||
|
|
||||||
|
current_cell->has_valid_sib2 = true;
|
||||||
|
si_acquire_state = SI_ACQUIRE_IDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Right now, this thread only controls System Information acquisition procedure
|
||||||
|
void rrc::run_thread()
|
||||||
|
{
|
||||||
|
uint32_t tti ;
|
||||||
|
uint32_t si_win_start, si_win_len;
|
||||||
|
uint16_t period;
|
||||||
|
uint32_t nof_sib1_trials = 0;
|
||||||
|
const int SIB1_SEARCH_TIMEOUT = 30;
|
||||||
|
|
||||||
|
while(thread_running)
|
||||||
|
{
|
||||||
|
switch(si_acquire_state)
|
||||||
|
{
|
||||||
|
case SI_ACQUIRE_SIB1:
|
||||||
|
// Instruct MAC to look for SIB1
|
||||||
|
if (!current_cell->has_valid_sib1) {
|
||||||
|
tti = mac->get_current_tti();
|
||||||
|
si_win_start = sib_start_tti(tti, 2, 5);
|
||||||
|
mac->bcch_start_rx(si_win_start, 1);
|
||||||
|
rrc_log->debug("Instructed MAC to search for SIB1, win_start=%d, win_len=%d\n",
|
||||||
|
si_win_start, 1);
|
||||||
|
nof_sib1_trials++;
|
||||||
|
if (nof_sib1_trials >= SIB1_SEARCH_TIMEOUT) {
|
||||||
|
if (state == RRC_STATE_CELL_SELECTING) {
|
||||||
|
select_next_cell_in_plmn();
|
||||||
|
si_acquire_state = SI_ACQUIRE_IDLE;
|
||||||
|
} else if (state == RRC_STATE_PLMN_SELECTION) {
|
||||||
|
phy->cell_search_next();
|
||||||
|
}
|
||||||
|
nof_sib1_trials = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
si_acquire_state = SI_ACQUIRE_SIB2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SI_ACQUIRE_SIB2:
|
||||||
|
// Instruct MAC to look for SIB2 only when selecting a cell
|
||||||
|
if (state == RRC_STATE_CELL_SELECTING && !current_cell->has_valid_sib2) {
|
||||||
|
tti = mac->get_current_tti();
|
||||||
|
period = liblte_rrc_si_periodicity_num[current_cell->sib1.sched_info[0].si_periodicity];
|
||||||
|
si_win_start = sib_start_tti(tti, period, 0);
|
||||||
|
si_win_len = liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length];
|
||||||
|
|
||||||
|
mac->bcch_start_rx(si_win_start, si_win_len);
|
||||||
|
rrc_log->debug("Instructed MAC to search for SIB2, win_start=%d, win_len=%d\n",
|
||||||
|
si_win_start, si_win_len);
|
||||||
|
} else {
|
||||||
|
si_acquire_state = SI_ACQUIRE_DONE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SI_ACQUIRE_DONE:
|
||||||
|
|
||||||
|
// After acquiring SI, tell NAS that the cell is selected or go to next cell in case of PLMN selection
|
||||||
|
|
||||||
|
if (state == RRC_STATE_CELL_SELECTING) {
|
||||||
|
nas->cell_selected();
|
||||||
|
state = RRC_STATE_CELL_SELECTED;
|
||||||
|
} else if (state == RRC_STATE_PLMN_SELECTION) {
|
||||||
|
phy->cell_search_next();
|
||||||
|
}
|
||||||
|
si_acquire_state = SI_ACQUIRE_IDLE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
usleep(10000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Connection control and establishment/reestablishment procedures
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
NAS interface
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu)
|
||||||
|
{
|
||||||
|
rrc_log->info_hex(sdu->msg, sdu->N_bytes, "RX %s SDU", rb_id_text[lcid]);
|
||||||
|
|
||||||
|
switch(state)
|
||||||
|
{
|
||||||
|
case RRC_STATE_CONNECTING:
|
||||||
|
send_con_setup_complete(sdu);
|
||||||
|
break;
|
||||||
|
case RRC_STATE_CONNECTED:
|
||||||
|
send_ul_info_transfer(lcid, sdu);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rrc_log->error("SDU received from NAS while RRC state = %s", rrc_state_text[state]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
MAC interface
|
||||||
|
*******************************************************************************/
|
||||||
|
/* Reception of PUCCH/SRS release procedure (Section 5.3.13) */
|
||||||
|
void rrc::release_pucch_srs()
|
||||||
|
{
|
||||||
|
// Apply default configuration for PUCCH (CQI and SR) and SRS (release)
|
||||||
|
set_phy_default_pucch_srs();
|
||||||
|
|
||||||
|
// Configure RX signals without pregeneration because default option is release
|
||||||
|
phy->configure_ul_params(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rrc::ra_problem() {
|
||||||
|
radio_link_failure();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
GW interface
|
GW interface
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
bool rrc::rrc_connected()
|
bool rrc::is_connected()
|
||||||
{
|
{
|
||||||
return (RRC_STATE_RRC_CONNECTED == state);
|
return (RRC_STATE_CONNECTED == state);
|
||||||
}
|
|
||||||
|
|
||||||
void rrc::rrc_connect() {
|
|
||||||
pthread_mutex_lock(&mutex);
|
|
||||||
if(RRC_STATE_IDLE == state) {
|
|
||||||
rrc_log->info("RRC in IDLE state - sending connection request.\n");
|
|
||||||
state = RRC_STATE_WAIT_FOR_CON_SETUP;
|
|
||||||
send_con_request();
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rrc::have_drb()
|
bool rrc::have_drb()
|
||||||
|
@ -246,75 +533,6 @@ void rrc::write_pdu(uint32_t lcid, byte_buffer_t *pdu)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rrc::write_pdu_bcch_bch(byte_buffer_t *pdu)
|
|
||||||
{
|
|
||||||
// Unpack the MIB
|
|
||||||
rrc_log->info_hex(pdu->msg, pdu->N_bytes, "BCCH BCH message received.");
|
|
||||||
rrc_log->info("BCCH BCH message Stack latency: %ld us\n", pdu->get_latency_us());
|
|
||||||
srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes*8);
|
|
||||||
bit_buf.N_bits = pdu->N_bytes*8;
|
|
||||||
pool->deallocate(pdu);
|
|
||||||
liblte_rrc_unpack_bcch_bch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &mib);
|
|
||||||
rrc_log->info("MIB received BW=%s MHz\n", liblte_rrc_dl_bandwidth_text[mib.dl_bw]);
|
|
||||||
rrc_log->console("MIB received BW=%s MHz\n", liblte_rrc_dl_bandwidth_text[mib.dl_bw]);
|
|
||||||
|
|
||||||
// Start the SIB search state machine
|
|
||||||
state = RRC_STATE_SIB1_SEARCH;
|
|
||||||
pthread_create(&sib_search_thread, NULL, &rrc::start_sib_thread, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rrc::write_pdu_bcch_dlsch(byte_buffer_t *pdu)
|
|
||||||
{
|
|
||||||
rrc_log->info_hex(pdu->msg, pdu->N_bytes, "BCCH DLSCH message received.");
|
|
||||||
rrc_log->info("BCCH DLSCH message Stack latency: %ld us\n", pdu->get_latency_us());
|
|
||||||
LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT dlsch_msg;
|
|
||||||
srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes*8);
|
|
||||||
bit_buf.N_bits = pdu->N_bytes*8;
|
|
||||||
pool->deallocate(pdu);
|
|
||||||
liblte_rrc_unpack_bcch_dlsch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &dlsch_msg);
|
|
||||||
|
|
||||||
if (dlsch_msg.N_sibs > 0) {
|
|
||||||
if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1 == dlsch_msg.sibs[0].sib_type && RRC_STATE_SIB1_SEARCH == state) {
|
|
||||||
// Handle SIB1
|
|
||||||
memcpy(&sib1, &dlsch_msg.sibs[0].sib.sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT));
|
|
||||||
rrc_log->info("SIB1 received, CellID=%d, si_window=%d, sib2_period=%d\n",
|
|
||||||
sib1.cell_id&0xfff,
|
|
||||||
liblte_rrc_si_window_length_num[sib1.si_window_length],
|
|
||||||
liblte_rrc_si_periodicity_num[sib1.sched_info[0].si_periodicity]);
|
|
||||||
std::stringstream ss;
|
|
||||||
for(uint32_t i=0;i<sib1.N_plmn_ids;i++){
|
|
||||||
std::string mcc;
|
|
||||||
std::string mnc;
|
|
||||||
mcc_to_string(sib1.plmn_id[i].id.mcc, &mcc);
|
|
||||||
mnc_to_string(sib1.plmn_id[i].id.mnc, &mnc);
|
|
||||||
ss << " PLMN Id: MCC " << mcc << " MNC " << mnc;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set TDD Config
|
|
||||||
if (dlsch_msg.sibs[0].sib.sib1.tdd) {
|
|
||||||
phy->set_config_tdd(&dlsch_msg.sibs[0].sib.sib1.tdd_cnfg);
|
|
||||||
}
|
|
||||||
|
|
||||||
rrc_log->console("SIB1 received, CellID=%d, %s\n",
|
|
||||||
sib1.cell_id&0xfff,
|
|
||||||
ss.str().c_str());
|
|
||||||
|
|
||||||
state = RRC_STATE_SIB2_SEARCH;
|
|
||||||
mac->bcch_stop_rx();
|
|
||||||
//TODO: Use all SIB1 info
|
|
||||||
|
|
||||||
} else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2 == dlsch_msg.sibs[0].sib_type && RRC_STATE_SIB2_SEARCH == state) {
|
|
||||||
// Handle SIB2
|
|
||||||
memcpy(&sib2, &dlsch_msg.sibs[0].sib.sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT));
|
|
||||||
rrc_log->console("SIB2 received\n");
|
|
||||||
rrc_log->info("SIB2 received\n");
|
|
||||||
state = RRC_STATE_WAIT_FOR_CON_SETUP;
|
|
||||||
mac->bcch_stop_rx();
|
|
||||||
apply_sib2_configs();
|
|
||||||
send_con_request();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rrc::write_pdu_pcch(byte_buffer_t *pdu)
|
void rrc::write_pdu_pcch(byte_buffer_t *pdu)
|
||||||
{
|
{
|
||||||
|
@ -352,7 +570,7 @@ void rrc::write_pdu_pcch(byte_buffer_t *pdu)
|
||||||
mac->pcch_stop_rx();
|
mac->pcch_stop_rx();
|
||||||
if(RRC_STATE_IDLE == state) {
|
if(RRC_STATE_IDLE == state) {
|
||||||
rrc_log->info("RRC in IDLE state - sending connection request.\n");
|
rrc_log->info("RRC in IDLE state - sending connection request.\n");
|
||||||
state = RRC_STATE_WAIT_FOR_CON_SETUP;
|
state = RRC_STATE_CONNECTING;
|
||||||
send_con_request();
|
send_con_request();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -400,7 +618,7 @@ void rrc::send_con_request()
|
||||||
bit_buf.msg[bit_buf.N_bits + i] = 0;
|
bit_buf.msg[bit_buf.N_bits + i] = 0;
|
||||||
bit_buf.N_bits += 8 - (bit_buf.N_bits % 8);
|
bit_buf.N_bits += 8 - (bit_buf.N_bits % 8);
|
||||||
}
|
}
|
||||||
byte_buffer_t *pdcp_buf = pool_allocate;
|
byte_buffer_t *pdcp_buf = pool_allocate;;
|
||||||
srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits);
|
srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits);
|
||||||
pdcp_buf->N_bytes = bit_buf.N_bits/8;
|
pdcp_buf->N_bytes = bit_buf.N_bits/8;
|
||||||
pdcp_buf->set_timestamp();
|
pdcp_buf->set_timestamp();
|
||||||
|
@ -417,7 +635,6 @@ void rrc::send_con_request()
|
||||||
mac->set_contention_id(uecri);
|
mac->set_contention_id(uecri);
|
||||||
|
|
||||||
rrc_log->info("Sending RRC Connection Request on SRB0\n");
|
rrc_log->info("Sending RRC Connection Request on SRB0\n");
|
||||||
state = RRC_STATE_WAIT_FOR_CON_SETUP;
|
|
||||||
pdcp->write_sdu(RB_ID_SRB0, pdcp_buf);
|
pdcp->write_sdu(RB_ID_SRB0, pdcp_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,7 +695,7 @@ void rrc::send_con_restablish_request()
|
||||||
|
|
||||||
// Wait for cell re-synchronization
|
// Wait for cell re-synchronization
|
||||||
uint32_t timeout_cnt = 0;
|
uint32_t timeout_cnt = 0;
|
||||||
while(!phy->status_is_sync() && timeout_cnt < TIMEOUT_RESYNC_REESTABLISH){
|
while(!phy->sync_status() && timeout_cnt < TIMEOUT_RESYNC_REESTABLISH){
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
timeout_cnt++;
|
timeout_cnt++;
|
||||||
}
|
}
|
||||||
|
@ -494,7 +711,7 @@ void rrc::send_con_restablish_request()
|
||||||
bit_buf.msg[bit_buf.N_bits + i] = 0;
|
bit_buf.msg[bit_buf.N_bits + i] = 0;
|
||||||
bit_buf.N_bits += 8 - (bit_buf.N_bits % 8);
|
bit_buf.N_bits += 8 - (bit_buf.N_bits % 8);
|
||||||
}
|
}
|
||||||
byte_buffer_t *pdcp_buf = pool_allocate;
|
byte_buffer_t *pdcp_buf = pool_allocate;;
|
||||||
srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits);
|
srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits);
|
||||||
pdcp_buf->N_bytes = bit_buf.N_bits/8;
|
pdcp_buf->N_bytes = bit_buf.N_bits/8;
|
||||||
|
|
||||||
|
@ -509,7 +726,6 @@ void rrc::send_con_restablish_request()
|
||||||
mac->set_contention_id(uecri);
|
mac->set_contention_id(uecri);
|
||||||
|
|
||||||
rrc_log->info("Sending RRC Connection Resetablishment Request on SRB0\n");
|
rrc_log->info("Sending RRC Connection Resetablishment Request on SRB0\n");
|
||||||
state = RRC_STATE_WAIT_FOR_CON_SETUP;
|
|
||||||
pdcp->write_sdu(RB_ID_SRB0, pdcp_buf);
|
pdcp->write_sdu(RB_ID_SRB0, pdcp_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,11 +747,11 @@ void rrc::send_con_restablish_complete()
|
||||||
bit_buf.msg[bit_buf.N_bits + i] = 0;
|
bit_buf.msg[bit_buf.N_bits + i] = 0;
|
||||||
bit_buf.N_bits += 8 - (bit_buf.N_bits % 8);
|
bit_buf.N_bits += 8 - (bit_buf.N_bits % 8);
|
||||||
}
|
}
|
||||||
byte_buffer_t *pdcp_buf = pool_allocate;
|
byte_buffer_t *pdcp_buf = pool_allocate;;
|
||||||
srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits);
|
srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits);
|
||||||
pdcp_buf->N_bytes = bit_buf.N_bits/8;
|
pdcp_buf->N_bytes = bit_buf.N_bits/8;
|
||||||
|
|
||||||
state = RRC_STATE_RRC_CONNECTED;
|
state = RRC_STATE_CONNECTED;
|
||||||
rrc_log->console("RRC Connected\n");
|
rrc_log->console("RRC Connected\n");
|
||||||
rrc_log->info("Sending RRC Connection Reestablishment Complete\n");
|
rrc_log->info("Sending RRC Connection Reestablishment Complete\n");
|
||||||
pdcp->write_sdu(RB_ID_SRB1, pdcp_buf);
|
pdcp->write_sdu(RB_ID_SRB1, pdcp_buf);
|
||||||
|
@ -562,12 +778,12 @@ void rrc::send_con_setup_complete(byte_buffer_t *nas_msg)
|
||||||
bit_buf.msg[bit_buf.N_bits + i] = 0;
|
bit_buf.msg[bit_buf.N_bits + i] = 0;
|
||||||
bit_buf.N_bits += 8 - (bit_buf.N_bits % 8);
|
bit_buf.N_bits += 8 - (bit_buf.N_bits % 8);
|
||||||
}
|
}
|
||||||
byte_buffer_t *pdcp_buf = pool_allocate;
|
byte_buffer_t *pdcp_buf = pool_allocate;;
|
||||||
srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits);
|
srslte_bit_pack_vector(bit_buf.msg, pdcp_buf->msg, bit_buf.N_bits);
|
||||||
pdcp_buf->N_bytes = bit_buf.N_bits/8;
|
pdcp_buf->N_bytes = bit_buf.N_bits/8;
|
||||||
pdcp_buf->set_timestamp();
|
pdcp_buf->set_timestamp();
|
||||||
|
|
||||||
state = RRC_STATE_RRC_CONNECTED;
|
state = RRC_STATE_CONNECTED;
|
||||||
rrc_log->console("RRC Connected\n");
|
rrc_log->console("RRC Connected\n");
|
||||||
rrc_log->info("Sending RRC Connection Setup Complete\n");
|
rrc_log->info("Sending RRC Connection Setup Complete\n");
|
||||||
pdcp->write_sdu(RB_ID_SRB1, pdcp_buf);
|
pdcp->write_sdu(RB_ID_SRB1, pdcp_buf);
|
||||||
|
@ -654,7 +870,7 @@ void rrc::send_rrc_con_reconfig_complete(uint32_t lcid, byte_buffer_t *pdu)
|
||||||
|
|
||||||
void rrc::enable_capabilities()
|
void rrc::enable_capabilities()
|
||||||
{
|
{
|
||||||
bool enable_ul_64 = ue_category>=5 && sib2.rr_config_common_sib.pusch_cnfg.enable_64_qam;
|
bool enable_ul_64 = ue_category>=5 && current_cell->sib2.rr_config_common_sib.pusch_cnfg.enable_64_qam;
|
||||||
rrc_log->info("%s 64QAM PUSCH\n", enable_ul_64?"Enabling":"Disabling");
|
rrc_log->info("%s 64QAM PUSCH\n", enable_ul_64?"Enabling":"Disabling");
|
||||||
phy->set_config_64qam_en(enable_ul_64);
|
phy->set_config_64qam_en(enable_ul_64);
|
||||||
}
|
}
|
||||||
|
@ -766,7 +982,6 @@ void rrc::parse_dl_ccch(byte_buffer_t *pdu)
|
||||||
transaction_id = dl_ccch_msg.msg.rrc_con_setup.rrc_transaction_id;
|
transaction_id = dl_ccch_msg.msg.rrc_con_setup.rrc_transaction_id;
|
||||||
handle_con_setup(&dl_ccch_msg.msg.rrc_con_setup);
|
handle_con_setup(&dl_ccch_msg.msg.rrc_con_setup);
|
||||||
rrc_log->info("Notifying NAS of connection setup\n");
|
rrc_log->info("Notifying NAS of connection setup\n");
|
||||||
state = RRC_STATE_COMPLETING_SETUP;
|
|
||||||
nas->notify_connection_setup();
|
nas->notify_connection_setup();
|
||||||
break;
|
break;
|
||||||
case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST:
|
case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST:
|
||||||
|
@ -904,108 +1119,44 @@ void rrc::radio_link_failure() {
|
||||||
|
|
||||||
rrc_log->warning("Detected Radio-Link Failure\n");
|
rrc_log->warning("Detected Radio-Link Failure\n");
|
||||||
rrc_log->console("Warning: Detected Radio-Link Failure\n");
|
rrc_log->console("Warning: Detected Radio-Link Failure\n");
|
||||||
if (state != RRC_STATE_RRC_CONNECTED) {
|
if (state != RRC_STATE_CONNECTED) {
|
||||||
rrc_connection_release();
|
rrc_connection_release();
|
||||||
} else {
|
} else {
|
||||||
send_con_restablish_request();
|
send_con_restablish_request();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void* rrc::start_sib_thread(void *rrc_)
|
|
||||||
{
|
|
||||||
rrc *r = (rrc*)rrc_;
|
|
||||||
r->sib_search();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rrc::sib_search()
|
|
||||||
{
|
|
||||||
bool searching = true;
|
|
||||||
uint32_t tti ;
|
|
||||||
uint32_t si_win_start, si_win_len;
|
|
||||||
uint16_t period;
|
|
||||||
uint32_t nof_sib1_trials = 0;
|
|
||||||
const int SIB1_SEARCH_TIMEOUT = 30;
|
|
||||||
|
|
||||||
while(searching)
|
|
||||||
{
|
|
||||||
switch(state)
|
|
||||||
{
|
|
||||||
case RRC_STATE_SIB1_SEARCH:
|
|
||||||
// Instruct MAC to look for SIB1
|
|
||||||
while(!phy->status_is_sync()){
|
|
||||||
usleep(50000);
|
|
||||||
}
|
|
||||||
usleep(10000);
|
|
||||||
tti = mac->get_current_tti();
|
|
||||||
si_win_start = sib_start_tti(tti, 2, 5);
|
|
||||||
mac->bcch_start_rx(si_win_start, 1);
|
|
||||||
rrc_log->debug("Instructed MAC to search for SIB1, win_start=%d, win_len=%d\n",
|
|
||||||
si_win_start, 1);
|
|
||||||
nof_sib1_trials++;
|
|
||||||
if (nof_sib1_trials >= SIB1_SEARCH_TIMEOUT) {
|
|
||||||
rrc_log->info("Timeout while searching for SIB1. Resynchronizing SFN...\n");
|
|
||||||
rrc_log->console("Timeout while searching for SIB1. Resynchronizing SFN...\n");
|
|
||||||
phy->resync_sfn();
|
|
||||||
nof_sib1_trials = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case RRC_STATE_SIB2_SEARCH:
|
|
||||||
// Instruct MAC to look for SIB2
|
|
||||||
usleep(10000);
|
|
||||||
tti = mac->get_current_tti();
|
|
||||||
period = liblte_rrc_si_periodicity_num[sib1.sched_info[0].si_periodicity];
|
|
||||||
si_win_start = sib_start_tti(tti, period, 0);
|
|
||||||
si_win_len = liblte_rrc_si_window_length_num[sib1.si_window_length];
|
|
||||||
|
|
||||||
mac->bcch_start_rx(si_win_start, si_win_len);
|
|
||||||
rrc_log->debug("Instructed MAC to search for SIB2, win_start=%d, win_len=%d\n",
|
|
||||||
si_win_start, si_win_len);
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
searching = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
usleep(100000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine SI messages scheduling as in 36.331 5.2.3 Acquisition of an SI message
|
// Determine SI messages scheduling as in 36.331 5.2.3 Acquisition of an SI message
|
||||||
uint32_t rrc::sib_start_tti(uint32_t tti, uint32_t period, uint32_t x) {
|
uint32_t rrc::sib_start_tti(uint32_t tti, uint32_t period, uint32_t x) {
|
||||||
return (period*10*(1+tti/(period*10))+x)%10240; // the 1 means next opportunity
|
return (period*10*(1+tti/(period*10))+x)%10240; // the 1 means next opportunity
|
||||||
}
|
}
|
||||||
|
|
||||||
void rrc::apply_sib2_configs()
|
void rrc::apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2)
|
||||||
{
|
{
|
||||||
if(RRC_STATE_WAIT_FOR_CON_SETUP != state){
|
|
||||||
rrc_log->error("State must be RRC_STATE_WAIT_FOR_CON_SETUP to handle SIB2. Actual state: %s\n",
|
|
||||||
rrc_state_text[state]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply RACH timeAlginmentTimer configuration
|
// Apply RACH timeAlginmentTimer configuration
|
||||||
mac_interface_rrc::mac_cfg_t cfg;
|
mac_interface_rrc::mac_cfg_t cfg;
|
||||||
mac->get_config(&cfg);
|
mac->get_config(&cfg);
|
||||||
cfg.main.time_alignment_timer = sib2.time_alignment_timer;
|
cfg.main.time_alignment_timer = sib2->time_alignment_timer;
|
||||||
memcpy(&cfg.rach, &sib2.rr_config_common_sib.rach_cnfg, sizeof(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT));
|
memcpy(&cfg.rach, &sib2->rr_config_common_sib.rach_cnfg, sizeof(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT));
|
||||||
cfg.prach_config_index = sib2.rr_config_common_sib.prach_cnfg.root_sequence_index;
|
cfg.prach_config_index = sib2->rr_config_common_sib.prach_cnfg.root_sequence_index;
|
||||||
mac->set_config(&cfg);
|
mac->set_config(&cfg);
|
||||||
|
|
||||||
rrc_log->info("Set RACH ConfigCommon: NofPreambles=%d, ResponseWindow=%d, ContentionResolutionTimer=%d ms\n",
|
rrc_log->info("Set RACH ConfigCommon: NofPreambles=%d, ResponseWindow=%d, ContentionResolutionTimer=%d ms\n",
|
||||||
liblte_rrc_number_of_ra_preambles_num[sib2.rr_config_common_sib.rach_cnfg.num_ra_preambles],
|
liblte_rrc_number_of_ra_preambles_num[sib2->rr_config_common_sib.rach_cnfg.num_ra_preambles],
|
||||||
liblte_rrc_ra_response_window_size_num[sib2.rr_config_common_sib.rach_cnfg.ra_resp_win_size],
|
liblte_rrc_ra_response_window_size_num[sib2->rr_config_common_sib.rach_cnfg.ra_resp_win_size],
|
||||||
liblte_rrc_mac_contention_resolution_timer_num[sib2.rr_config_common_sib.rach_cnfg.mac_con_res_timer]);
|
liblte_rrc_mac_contention_resolution_timer_num[sib2->rr_config_common_sib.rach_cnfg.mac_con_res_timer]);
|
||||||
|
|
||||||
// Apply PHY RR Config Common
|
// Apply PHY RR Config Common
|
||||||
phy_interface_rrc::phy_cfg_common_t common;
|
phy_interface_rrc::phy_cfg_common_t common;
|
||||||
memcpy(&common.pdsch_cnfg, &sib2.rr_config_common_sib.pdsch_cnfg, sizeof(LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT));
|
memcpy(&common.pdsch_cnfg, &sib2->rr_config_common_sib.pdsch_cnfg, sizeof(LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT));
|
||||||
memcpy(&common.pusch_cnfg, &sib2.rr_config_common_sib.pusch_cnfg, sizeof(LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT));
|
memcpy(&common.pusch_cnfg, &sib2->rr_config_common_sib.pusch_cnfg, sizeof(LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT));
|
||||||
memcpy(&common.pucch_cnfg, &sib2.rr_config_common_sib.pucch_cnfg, sizeof(LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT));
|
memcpy(&common.pucch_cnfg, &sib2->rr_config_common_sib.pucch_cnfg, sizeof(LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT));
|
||||||
memcpy(&common.ul_pwr_ctrl, &sib2.rr_config_common_sib.ul_pwr_ctrl, sizeof(LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT));
|
memcpy(&common.ul_pwr_ctrl, &sib2->rr_config_common_sib.ul_pwr_ctrl, sizeof(LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT));
|
||||||
memcpy(&common.prach_cnfg, &sib2.rr_config_common_sib.prach_cnfg, sizeof(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT));
|
memcpy(&common.prach_cnfg, &sib2->rr_config_common_sib.prach_cnfg, sizeof(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT));
|
||||||
if (sib2.rr_config_common_sib.srs_ul_cnfg.present) {
|
if (sib2->rr_config_common_sib.srs_ul_cnfg.present) {
|
||||||
memcpy(&common.srs_ul_cnfg, &sib2.rr_config_common_sib.srs_ul_cnfg, sizeof(LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT));
|
memcpy(&common.srs_ul_cnfg, &sib2->rr_config_common_sib.srs_ul_cnfg, sizeof(LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT));
|
||||||
} else {
|
} else {
|
||||||
// default is release
|
// default is release
|
||||||
common.srs_ul_cnfg.present = false;
|
common.srs_ul_cnfg.present = false;
|
||||||
|
@ -1015,34 +1166,34 @@ void rrc::apply_sib2_configs()
|
||||||
phy->configure_ul_params();
|
phy->configure_ul_params();
|
||||||
|
|
||||||
rrc_log->info("Set PUSCH ConfigCommon: HopOffset=%d, RSGroup=%d, RSNcs=%d, N_sb=%d\n",
|
rrc_log->info("Set PUSCH ConfigCommon: HopOffset=%d, RSGroup=%d, RSNcs=%d, N_sb=%d\n",
|
||||||
sib2.rr_config_common_sib.pusch_cnfg.pusch_hopping_offset,
|
sib2->rr_config_common_sib.pusch_cnfg.pusch_hopping_offset,
|
||||||
sib2.rr_config_common_sib.pusch_cnfg.ul_rs.group_assignment_pusch,
|
sib2->rr_config_common_sib.pusch_cnfg.ul_rs.group_assignment_pusch,
|
||||||
sib2.rr_config_common_sib.pusch_cnfg.ul_rs.cyclic_shift,
|
sib2->rr_config_common_sib.pusch_cnfg.ul_rs.cyclic_shift,
|
||||||
sib2.rr_config_common_sib.pusch_cnfg.n_sb);
|
sib2->rr_config_common_sib.pusch_cnfg.n_sb);
|
||||||
|
|
||||||
rrc_log->info("Set PUCCH ConfigCommon: DeltaShift=%d, CyclicShift=%d, N1=%d, NRB=%d\n",
|
rrc_log->info("Set PUCCH ConfigCommon: DeltaShift=%d, CyclicShift=%d, N1=%d, NRB=%d\n",
|
||||||
liblte_rrc_delta_pucch_shift_num[sib2.rr_config_common_sib.pucch_cnfg.delta_pucch_shift],
|
liblte_rrc_delta_pucch_shift_num[sib2->rr_config_common_sib.pucch_cnfg.delta_pucch_shift],
|
||||||
sib2.rr_config_common_sib.pucch_cnfg.n_cs_an,
|
sib2->rr_config_common_sib.pucch_cnfg.n_cs_an,
|
||||||
sib2.rr_config_common_sib.pucch_cnfg.n1_pucch_an,
|
sib2->rr_config_common_sib.pucch_cnfg.n1_pucch_an,
|
||||||
sib2.rr_config_common_sib.pucch_cnfg.n_rb_cqi);
|
sib2->rr_config_common_sib.pucch_cnfg.n_rb_cqi);
|
||||||
|
|
||||||
rrc_log->info("Set PRACH ConfigCommon: SeqIdx=%d, HS=%s, FreqOffset=%d, ZC=%d, ConfigIndex=%d\n",
|
rrc_log->info("Set PRACH ConfigCommon: SeqIdx=%d, HS=%s, FreqOffset=%d, ZC=%d, ConfigIndex=%d\n",
|
||||||
sib2.rr_config_common_sib.prach_cnfg.root_sequence_index,
|
sib2->rr_config_common_sib.prach_cnfg.root_sequence_index,
|
||||||
sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.high_speed_flag?"yes":"no",
|
sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.high_speed_flag?"yes":"no",
|
||||||
sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_freq_offset,
|
sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_freq_offset,
|
||||||
sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.zero_correlation_zone_config,
|
sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.zero_correlation_zone_config,
|
||||||
sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_config_index);
|
sib2->rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_config_index);
|
||||||
|
|
||||||
rrc_log->info("Set SRS ConfigCommon: BW-Configuration=%d, SF-Configuration=%d, ACKNACK=%s\n",
|
rrc_log->info("Set SRS ConfigCommon: BW-Configuration=%d, SF-Configuration=%d, ACKNACK=%s\n",
|
||||||
liblte_rrc_srs_bw_config_num[sib2.rr_config_common_sib.srs_ul_cnfg.bw_cnfg],
|
liblte_rrc_srs_bw_config_num[sib2->rr_config_common_sib.srs_ul_cnfg.bw_cnfg],
|
||||||
liblte_rrc_srs_subfr_config_num[sib2.rr_config_common_sib.srs_ul_cnfg.subfr_cnfg],
|
liblte_rrc_srs_subfr_config_num[sib2->rr_config_common_sib.srs_ul_cnfg.subfr_cnfg],
|
||||||
sib2.rr_config_common_sib.srs_ul_cnfg.ack_nack_simul_tx?"yes":"no");
|
sib2->rr_config_common_sib.srs_ul_cnfg.ack_nack_simul_tx?"yes":"no");
|
||||||
|
|
||||||
mac_timers->get(t301)->set(this, liblte_rrc_t301_num[sib2.ue_timers_and_constants.t301]);
|
mac_timers->get(t301)->set(this, liblte_rrc_t301_num[sib2->ue_timers_and_constants.t301]);
|
||||||
mac_timers->get(t310)->set(this, liblte_rrc_t310_num[sib2.ue_timers_and_constants.t310]);
|
mac_timers->get(t310)->set(this, liblte_rrc_t310_num[sib2->ue_timers_and_constants.t310]);
|
||||||
mac_timers->get(t311)->set(this, liblte_rrc_t311_num[sib2.ue_timers_and_constants.t311]);
|
mac_timers->get(t311)->set(this, liblte_rrc_t311_num[sib2->ue_timers_and_constants.t311]);
|
||||||
N310 = liblte_rrc_n310_num[sib2.ue_timers_and_constants.n310];
|
N310 = liblte_rrc_n310_num[sib2->ue_timers_and_constants.n310];
|
||||||
N311 = liblte_rrc_n311_num[sib2.ue_timers_and_constants.n311];
|
N311 = liblte_rrc_n311_num[sib2->ue_timers_and_constants.n311];
|
||||||
|
|
||||||
rrc_log->info("Set Constants and Timers: N310=%d, N311=%d, t301=%d, t310=%d, t311=%d\n",
|
rrc_log->info("Set Constants and Timers: N310=%d, N311=%d, t301=%d, t310=%d, t311=%d\n",
|
||||||
N310, N311, mac_timers->get(t301)->get_timeout(),
|
N310, N311, mac_timers->get(t301)->get_timeout(),
|
||||||
|
@ -1309,7 +1460,7 @@ void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGU
|
||||||
byte_buffer_t *nas_sdu;
|
byte_buffer_t *nas_sdu;
|
||||||
for(i=0;i<reconfig->N_ded_info_nas;i++)
|
for(i=0;i<reconfig->N_ded_info_nas;i++)
|
||||||
{
|
{
|
||||||
nas_sdu = pool_allocate;
|
nas_sdu = pool_allocate;;
|
||||||
memcpy(nas_sdu->msg, &reconfig->ded_info_nas_list[i].msg, reconfig->ded_info_nas_list[i].N_bytes);
|
memcpy(nas_sdu->msg, &reconfig->ded_info_nas_list[i].msg, reconfig->ded_info_nas_list[i].N_bytes);
|
||||||
nas_sdu->N_bytes = reconfig->ded_info_nas_list[i].N_bytes;
|
nas_sdu->N_bytes = reconfig->ded_info_nas_list[i].N_bytes;
|
||||||
nas->write_pdu(lcid, nas_sdu);
|
nas->write_pdu(lcid, nas_sdu);
|
||||||
|
|
|
@ -363,9 +363,7 @@ int main(int argc, char *argv[])
|
||||||
radio.set_tx_freq(prog_args.rf_tx_freq);
|
radio.set_tx_freq(prog_args.rf_tx_freq);
|
||||||
|
|
||||||
// Instruct the PHY to configure PRACH parameters and sync to current cell
|
// Instruct the PHY to configure PRACH parameters and sync to current cell
|
||||||
my_phy.sync_start();
|
while(!my_phy.sync_status()) {
|
||||||
|
|
||||||
while(!my_phy.status_is_sync()) {
|
|
||||||
usleep(20000);
|
usleep(20000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -182,11 +182,9 @@ int main(int argc, char *argv[])
|
||||||
// Set RX freq and gain
|
// Set RX freq and gain
|
||||||
radio.set_rx_freq(prog_args.rf_freq);
|
radio.set_rx_freq(prog_args.rf_freq);
|
||||||
|
|
||||||
my_phy.sync_start();
|
|
||||||
|
|
||||||
bool running = true;
|
bool running = true;
|
||||||
while(running) {
|
while(running) {
|
||||||
if (bch_decoded && my_phy.status_is_sync()) {
|
if (bch_decoded && my_phy.sync_status()) {
|
||||||
uint32_t tti = my_phy.get_current_tti();
|
uint32_t tti = my_phy.get_current_tti();
|
||||||
|
|
||||||
// SIB1 is scheduled in subframe #5 of even frames, try to decode next frame SIB1
|
// SIB1 is scheduled in subframe #5 of even frames, try to decode next frame SIB1
|
||||||
|
@ -196,7 +194,7 @@ int main(int argc, char *argv[])
|
||||||
total_pkts++;
|
total_pkts++;
|
||||||
}
|
}
|
||||||
usleep(30000);
|
usleep(30000);
|
||||||
if (bch_decoded && my_phy.status_is_sync() && total_pkts > 0) {
|
if (bch_decoded && my_phy.sync_status() && total_pkts > 0) {
|
||||||
if (srslte_verbose == SRSLTE_VERBOSE_NONE && srsapps_verbose == 0) {
|
if (srslte_verbose == SRSLTE_VERBOSE_NONE && srsapps_verbose == 0) {
|
||||||
float gain = prog_args.rf_gain;
|
float gain = prog_args.rf_gain;
|
||||||
if (gain < 0) {
|
if (gain < 0) {
|
||||||
|
|
|
@ -18,17 +18,6 @@
|
||||||
# and at http://www.gnu.org/licenses/.
|
# and at http://www.gnu.org/licenses/.
|
||||||
#
|
#
|
||||||
|
|
||||||
# IP traffic over RLC test
|
|
||||||
add_executable(ip_test ip_test.cc)
|
|
||||||
target_link_libraries(ip_test srsue_mac
|
|
||||||
srsue_phy
|
|
||||||
srslte_common
|
|
||||||
srslte_phy
|
|
||||||
srslte_radio
|
|
||||||
srslte_upper
|
|
||||||
${CMAKE_THREAD_LIBS_INIT}
|
|
||||||
${Boost_LIBRARIES})
|
|
||||||
|
|
||||||
add_executable(usim_test usim_test.cc)
|
add_executable(usim_test usim_test.cc)
|
||||||
target_link_libraries(usim_test srsue_upper srslte_upper srslte_phy)
|
target_link_libraries(usim_test srsue_upper srslte_upper srslte_phy)
|
||||||
add_test(usim_test usim_test)
|
add_test(usim_test usim_test)
|
||||||
|
|
|
@ -1,645 +0,0 @@
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <linux/ip.h>
|
|
||||||
#include <linux/if.h>
|
|
||||||
#include <linux/if_tun.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include <sstream>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include "srslte/phy/utils/debug.h"
|
|
||||||
#include "mac/mac.h"
|
|
||||||
#include "phy/phy.h"
|
|
||||||
#include "srslte/common/threads.h"
|
|
||||||
#include "srslte/common/common.h"
|
|
||||||
#include "srslte/common/buffer_pool.h"
|
|
||||||
#include "srslte/common/logger.h"
|
|
||||||
#include "srslte/common/log_filter.h"
|
|
||||||
#include "srslte/upper/rlc.h"
|
|
||||||
#include "upper/rrc.h"
|
|
||||||
#include "srslte/radio/radio_multi.h"
|
|
||||||
|
|
||||||
#define START_TUNTAP
|
|
||||||
#define USE_RADIO
|
|
||||||
#define PRINT_GW 0
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* Program arguments processing
|
|
||||||
***********************************************************************/
|
|
||||||
|
|
||||||
#define LCID 3
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
float rx_freq;
|
|
||||||
float tx_freq;
|
|
||||||
float rx_gain;
|
|
||||||
float tx_gain;
|
|
||||||
int time_adv;
|
|
||||||
std::string ip_address;
|
|
||||||
}prog_args_t;
|
|
||||||
|
|
||||||
uint32_t srsapps_verbose = 1;
|
|
||||||
|
|
||||||
prog_args_t prog_args;
|
|
||||||
|
|
||||||
void args_default(prog_args_t *args) {
|
|
||||||
args->tx_freq = 2.505e9;
|
|
||||||
args->rx_freq = 2.625e9;
|
|
||||||
args->rx_gain = 50.0;
|
|
||||||
args->tx_gain = 70.0;
|
|
||||||
args->time_adv = -1; // calibrated for b210
|
|
||||||
args->ip_address = "192.168.3.2";
|
|
||||||
}
|
|
||||||
|
|
||||||
void usage(prog_args_t *args, char *prog) {
|
|
||||||
printf("Usage: %s [gGIrfFtv]\n", prog);
|
|
||||||
printf("\t-f RX frequency [Default %.1f MHz]\n", args->rx_freq/1e6);
|
|
||||||
printf("\t-F TX frequency [Default %.1f MHz]\n", args->tx_freq/1e6);
|
|
||||||
printf("\t-g RX gain [Default %.1f]\n", args->rx_gain);
|
|
||||||
printf("\t-G TX gain [Default %.1f]\n", args->tx_gain);
|
|
||||||
printf("\t-I IP address [Default %s]\n", args->ip_address.c_str());
|
|
||||||
printf("\t-t time advance (in samples) [Default %d]\n", args->time_adv);
|
|
||||||
printf("\t-v [increase verbosity, default none]\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void parse_args(prog_args_t *args, int argc, char **argv) {
|
|
||||||
int opt;
|
|
||||||
args_default(args);
|
|
||||||
while ((opt = getopt(argc, argv, "gGfFItv")) != -1) {
|
|
||||||
switch (opt) {
|
|
||||||
case 'g':
|
|
||||||
args->rx_gain = atof(argv[optind]);
|
|
||||||
break;
|
|
||||||
case 'G':
|
|
||||||
args->tx_gain = atof(argv[optind]);
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
args->rx_freq = atof(argv[optind]);
|
|
||||||
break;
|
|
||||||
case 'F':
|
|
||||||
args->tx_freq = atof(argv[optind]);
|
|
||||||
break;
|
|
||||||
case 'I':
|
|
||||||
args->ip_address = argv[optind];
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
args->time_adv = atoi(argv[optind]);
|
|
||||||
break;
|
|
||||||
case 'v':
|
|
||||||
srsapps_verbose++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
usage(args, argv[0]);
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (args->rx_freq < 0 || args->tx_freq < 0) {
|
|
||||||
usage(args, argv[0]);
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int setup_if_addr(char *ip_addr);
|
|
||||||
|
|
||||||
// Define dummy RLC always transmitts
|
|
||||||
class tester : public srsue::pdcp_interface_rlc,
|
|
||||||
public srsue::rrc_interface_rlc,
|
|
||||||
public srsue::rrc_interface_phy,
|
|
||||||
public srsue::rrc_interface_mac,
|
|
||||||
public srsue::ue_interface,
|
|
||||||
public thread
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
tester() {
|
|
||||||
state = srsue::RRC_STATE_SIB1_SEARCH;
|
|
||||||
read_enable = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void init(srsue::phy *phy_, srsue::mac *mac_, srslte::rlc *rlc_, srslte::log *log_h_, std::string ip_address) {
|
|
||||||
log_h = log_h_;
|
|
||||||
rlc = rlc_;
|
|
||||||
mac = mac_;
|
|
||||||
phy = phy_;
|
|
||||||
|
|
||||||
#ifdef START_TUNTAP
|
|
||||||
if (init_tuntap((char*) ip_address.c_str())) {
|
|
||||||
log_h->error("Initiating IP address\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pool = srslte::byte_buffer_pool::get_instance();
|
|
||||||
|
|
||||||
// Start reader thread
|
|
||||||
running=true;
|
|
||||||
start();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void sib_search()
|
|
||||||
{
|
|
||||||
bool searching = true;
|
|
||||||
uint32_t tti ;
|
|
||||||
uint32_t si_win_start, si_win_len;
|
|
||||||
uint16_t period;
|
|
||||||
uint32_t nof_sib1_trials = 0;
|
|
||||||
const int SIB1_SEARCH_TIMEOUT = 30;
|
|
||||||
|
|
||||||
while(searching)
|
|
||||||
{
|
|
||||||
switch(state)
|
|
||||||
{
|
|
||||||
case srsue::RRC_STATE_SIB1_SEARCH:
|
|
||||||
// Instruct MAC to look for SIB1
|
|
||||||
while(!phy->status_is_sync()){
|
|
||||||
usleep(50000);
|
|
||||||
}
|
|
||||||
usleep(10000);
|
|
||||||
tti = mac->get_current_tti();
|
|
||||||
si_win_start = sib_start_tti(tti, 2, 5);
|
|
||||||
mac->bcch_start_rx(si_win_start, 1);
|
|
||||||
log_h->info("Instructed MAC to search for SIB1, win_start=%d, win_len=%d\n",
|
|
||||||
si_win_start, 1);
|
|
||||||
nof_sib1_trials++;
|
|
||||||
if (nof_sib1_trials >= SIB1_SEARCH_TIMEOUT) {
|
|
||||||
log_h->info("Timeout while searching for SIB1. Resynchronizing SFN...\n");
|
|
||||||
log_h->console("Timeout while searching for SIB1. Resynchronizing SFN...\n");
|
|
||||||
phy->resync_sfn();
|
|
||||||
nof_sib1_trials = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case srsue::RRC_STATE_SIB2_SEARCH:
|
|
||||||
// Instruct MAC to look for SIB2
|
|
||||||
usleep(10000);
|
|
||||||
tti = mac->get_current_tti();
|
|
||||||
period = liblte_rrc_si_periodicity_num[sib1.sched_info[0].si_periodicity];
|
|
||||||
si_win_start = sib_start_tti(tti, period, 0);
|
|
||||||
si_win_len = liblte_rrc_si_window_length_num[sib1.si_window_length];
|
|
||||||
|
|
||||||
mac->bcch_start_rx(si_win_start, si_win_len);
|
|
||||||
log_h->info("Instructed MAC to search for SIB2, win_start=%d, win_len=%d\n",
|
|
||||||
si_win_start, si_win_len);
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
searching = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
usleep(100000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_sib_received() {
|
|
||||||
return state == srsue::RRC_STATE_WAIT_FOR_CON_SETUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void release_pucch_srs() {}
|
|
||||||
void ra_problem() {}
|
|
||||||
void write_pdu_bcch_bch(srslte::byte_buffer_t *pdu) {}
|
|
||||||
void write_pdu_bcch_dlsch(srslte::byte_buffer_t *pdu)
|
|
||||||
{
|
|
||||||
log_h->info_hex(pdu->msg, pdu->N_bytes, "BCCH DLSCH message received.");
|
|
||||||
log_h->info("BCCH DLSCH message Stack latency: %ld us\n", pdu->get_latency_us());
|
|
||||||
LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT dlsch_msg;
|
|
||||||
srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes*8);
|
|
||||||
bit_buf.N_bits = pdu->N_bytes*8;
|
|
||||||
pool->deallocate(pdu);
|
|
||||||
liblte_rrc_unpack_bcch_dlsch_msg((LIBLTE_BIT_MSG_STRUCT*)&bit_buf, &dlsch_msg);
|
|
||||||
|
|
||||||
if (dlsch_msg.N_sibs > 0) {
|
|
||||||
if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1 == dlsch_msg.sibs[0].sib_type && srsue::RRC_STATE_SIB1_SEARCH == state) {
|
|
||||||
// Handle SIB1
|
|
||||||
memcpy(&sib1, &dlsch_msg.sibs[0].sib.sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT));
|
|
||||||
log_h->info("SIB1 received, CellID=%d, si_window=%d, sib2_period=%d\n",
|
|
||||||
sib1.cell_id&0xfff,
|
|
||||||
liblte_rrc_si_window_length_num[sib1.si_window_length],
|
|
||||||
liblte_rrc_si_periodicity_num[sib1.sched_info[0].si_periodicity]);
|
|
||||||
std::stringstream ss;
|
|
||||||
for(uint32_t i=0;i<sib1.N_plmn_ids;i++){
|
|
||||||
ss << " PLMN Id: MCC " << sib1.plmn_id[i].id.mcc << " MNC " << sib1.plmn_id[i].id.mnc;
|
|
||||||
}
|
|
||||||
log_h->console("SIB1 received, CellID=%d, %s\n",
|
|
||||||
sib1.cell_id&0xfff,
|
|
||||||
ss.str().c_str());
|
|
||||||
|
|
||||||
state = srsue::RRC_STATE_SIB2_SEARCH;
|
|
||||||
mac->bcch_stop_rx();
|
|
||||||
//TODO: Use all SIB1 info
|
|
||||||
|
|
||||||
} else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2 == dlsch_msg.sibs[0].sib_type && srsue::RRC_STATE_SIB2_SEARCH == state) {
|
|
||||||
// Handle SIB2
|
|
||||||
memcpy(&sib2, &dlsch_msg.sibs[0].sib.sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT));
|
|
||||||
log_h->console("SIB2 received\n");
|
|
||||||
log_h->info("SIB2 received\n");
|
|
||||||
state = srsue::RRC_STATE_WAIT_FOR_CON_SETUP;
|
|
||||||
mac->bcch_stop_rx();
|
|
||||||
apply_sib2_configs();
|
|
||||||
|
|
||||||
srslte::byte_buffer_t *sdu = pool_allocate;
|
|
||||||
assert(sdu);
|
|
||||||
|
|
||||||
// Send Msg3
|
|
||||||
sdu->N_bytes = 10;
|
|
||||||
for (uint32_t i=0;i<sdu->N_bytes;i++) {
|
|
||||||
sdu->msg[i] = i+1;
|
|
||||||
}
|
|
||||||
uint64_t uecri = 0;
|
|
||||||
uint8_t *ue_cri_ptr = (uint8_t*) &uecri;
|
|
||||||
uint32_t nbytes = 6;
|
|
||||||
for (uint32_t i=0;i<nbytes;i++) {
|
|
||||||
ue_cri_ptr[nbytes-i-1] = sdu->msg[i];
|
|
||||||
}
|
|
||||||
log_h->info("Setting UE contention resolution ID: %d\n", uecri);
|
|
||||||
mac->set_contention_id(uecri);
|
|
||||||
|
|
||||||
rlc->write_sdu(0, sdu);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void write_pdu_pcch(srslte::byte_buffer_t *sdu) {}
|
|
||||||
void max_retx_attempted(){}
|
|
||||||
void in_sync() {};
|
|
||||||
void out_of_sync() {};
|
|
||||||
|
|
||||||
void write_pdu(uint32_t lcid, srslte::byte_buffer_t *sdu)
|
|
||||||
{
|
|
||||||
uint32_t n=0;
|
|
||||||
switch(lcid) {
|
|
||||||
case LCID:
|
|
||||||
n = write(tun_fd, sdu->msg, sdu->N_bytes);
|
|
||||||
if (n != sdu->N_bytes) {
|
|
||||||
log_h->error("TUN/TAP write failure n=%d, nof_bytes=%d\n", n, sdu->N_bytes);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
log_h->debug_hex(sdu->msg, sdu->N_bytes,
|
|
||||||
"Wrote %d bytes to TUN/TAP\n",
|
|
||||||
sdu->N_bytes);
|
|
||||||
pool->deallocate(sdu);
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
log_h->info("Received ConnectionSetupComplete\n");
|
|
||||||
|
|
||||||
// Setup a single UM bearer
|
|
||||||
LIBLTE_RRC_RLC_CONFIG_STRUCT cfg;
|
|
||||||
bzero(&cfg, sizeof(LIBLTE_RRC_RLC_CONFIG_STRUCT));
|
|
||||||
cfg.rlc_mode = LIBLTE_RRC_RLC_MODE_UM_BI;
|
|
||||||
cfg.dl_um_bi_rlc.t_reordering = LIBLTE_RRC_T_REORDERING_MS100;
|
|
||||||
cfg.dl_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10;
|
|
||||||
cfg.ul_um_bi_rlc.sn_field_len = LIBLTE_RRC_SN_FIELD_LENGTH_SIZE10;
|
|
||||||
rlc->add_bearer(LCID, &cfg);
|
|
||||||
|
|
||||||
mac->setup_lcid(LCID, 0, 1, -1, 100000);
|
|
||||||
|
|
||||||
LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT dedicated;
|
|
||||||
bzero(&dedicated, sizeof(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT));
|
|
||||||
dedicated.pusch_cnfg_ded.beta_offset_ack_idx = 5;
|
|
||||||
dedicated.pusch_cnfg_ded.beta_offset_ri_idx = 12;
|
|
||||||
dedicated.pusch_cnfg_ded.beta_offset_cqi_idx = 15;
|
|
||||||
dedicated.pusch_cnfg_ded_present = true;
|
|
||||||
dedicated.sched_request_cnfg.dsr_trans_max = LIBLTE_RRC_DSR_TRANS_MAX_N4;
|
|
||||||
dedicated.sched_request_cnfg.sr_pucch_resource_idx = 0;
|
|
||||||
dedicated.sched_request_cnfg.sr_cnfg_idx = 35;
|
|
||||||
dedicated.sched_request_cnfg.setup_present = true;
|
|
||||||
dedicated.sched_request_cnfg_present = true;
|
|
||||||
phy->set_config_dedicated(&dedicated);
|
|
||||||
phy->configure_ul_params();
|
|
||||||
|
|
||||||
srsue::mac_interface_rrc::mac_cfg_t mac_cfg;
|
|
||||||
mac->get_config(&mac_cfg);
|
|
||||||
memcpy(&mac_cfg.sr, &dedicated.sched_request_cnfg, sizeof(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT));
|
|
||||||
mac_cfg.main.ulsch_cnfg.periodic_bsr_timer = LIBLTE_RRC_PERIODIC_BSR_TIMER_SF40;
|
|
||||||
mac->set_config(&mac_cfg);
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
log_h->error("Received message for lcid=%d\n", lcid);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int tun_fd;
|
|
||||||
bool running;
|
|
||||||
srslte::log *log_h;
|
|
||||||
srslte::byte_buffer_pool *pool;
|
|
||||||
srslte::rlc *rlc;
|
|
||||||
srsue::mac *mac;
|
|
||||||
srsue::phy *phy;
|
|
||||||
srslte::bit_buffer_t bit_buf;
|
|
||||||
srsue::rrc_state_t state;
|
|
||||||
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT sib1;
|
|
||||||
LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT sib2;
|
|
||||||
bool read_enable;
|
|
||||||
|
|
||||||
|
|
||||||
// Determine SI messages scheduling as in 36.331 5.2.3 Acquisition of an SI message
|
|
||||||
uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t x) {
|
|
||||||
return (period*10*(1+tti/(period*10))+x)%10240; // the 1 means next opportunity
|
|
||||||
}
|
|
||||||
|
|
||||||
int init_tuntap(char *ip_address) {
|
|
||||||
read_enable = true;
|
|
||||||
tun_fd = setup_if_addr(ip_address);
|
|
||||||
if (tun_fd<0) {
|
|
||||||
fprintf(stderr, "Error setting up IP %s\n", ip_address);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Created tun/tap interface at IP %s\n", ip_address);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void run_thread() {
|
|
||||||
struct iphdr *ip_pkt;
|
|
||||||
uint32_t idx = 0;
|
|
||||||
int32_t N_bytes;
|
|
||||||
srslte::byte_buffer_t *pdu = pool_allocate;
|
|
||||||
|
|
||||||
log_h->info("TUN/TAP reader thread running\n");
|
|
||||||
|
|
||||||
while(running) {
|
|
||||||
N_bytes = read(tun_fd, &pdu->msg[idx], SRSLTE_MAX_BUFFER_SIZE_BYTES-SRSLTE_BUFFER_HEADER_OFFSET - idx);
|
|
||||||
if(N_bytes > 0 && read_enable)
|
|
||||||
{
|
|
||||||
pdu->N_bytes = idx + N_bytes;
|
|
||||||
ip_pkt = (struct iphdr*)pdu->msg;
|
|
||||||
|
|
||||||
log_h->debug_hex(pdu->msg, pdu->N_bytes,
|
|
||||||
"Read %d bytes from TUN/TAP\n",
|
|
||||||
N_bytes);
|
|
||||||
|
|
||||||
// Check if entire packet was received
|
|
||||||
if(ntohs(ip_pkt->tot_len) == pdu->N_bytes)
|
|
||||||
{
|
|
||||||
log_h->info_hex(pdu->msg, pdu->N_bytes, "UL PDU");
|
|
||||||
|
|
||||||
// Send PDU directly to PDCP
|
|
||||||
pdu->set_timestamp();
|
|
||||||
rlc->write_sdu(LCID, pdu);
|
|
||||||
|
|
||||||
pdu = pool_allocate;
|
|
||||||
idx = 0;
|
|
||||||
} else{
|
|
||||||
idx += N_bytes;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
log_h->error("Failed to read from TUN interface - gw receive thread exiting.\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void apply_sib2_configs()
|
|
||||||
{
|
|
||||||
|
|
||||||
// Apply RACH timeAlginmentTimer configuration
|
|
||||||
srsue::mac_interface_rrc::mac_cfg_t cfg;
|
|
||||||
mac->get_config(&cfg);
|
|
||||||
cfg.main.time_alignment_timer = sib2.time_alignment_timer;
|
|
||||||
memcpy(&cfg.rach, &sib2.rr_config_common_sib.rach_cnfg, sizeof(LIBLTE_RRC_RACH_CONFIG_COMMON_STRUCT));
|
|
||||||
cfg.prach_config_index = sib2.rr_config_common_sib.prach_cnfg.root_sequence_index;
|
|
||||||
mac->set_config(&cfg);
|
|
||||||
|
|
||||||
log_h->info("Set RACH ConfigCommon: NofPreambles=%d, ResponseWindow=%d, ContentionResolutionTimer=%d ms\n",
|
|
||||||
liblte_rrc_number_of_ra_preambles_num[sib2.rr_config_common_sib.rach_cnfg.num_ra_preambles],
|
|
||||||
liblte_rrc_ra_response_window_size_num[sib2.rr_config_common_sib.rach_cnfg.ra_resp_win_size],
|
|
||||||
liblte_rrc_mac_contention_resolution_timer_num[sib2.rr_config_common_sib.rach_cnfg.mac_con_res_timer]);
|
|
||||||
|
|
||||||
// Apply PHY RR Config Common
|
|
||||||
srsue::phy_interface_rrc::phy_cfg_common_t common;
|
|
||||||
memcpy(&common.pdsch_cnfg, &sib2.rr_config_common_sib.pdsch_cnfg, sizeof(LIBLTE_RRC_PDSCH_CONFIG_COMMON_STRUCT));
|
|
||||||
memcpy(&common.pusch_cnfg, &sib2.rr_config_common_sib.pusch_cnfg, sizeof(LIBLTE_RRC_PUSCH_CONFIG_COMMON_STRUCT));
|
|
||||||
memcpy(&common.pucch_cnfg, &sib2.rr_config_common_sib.pucch_cnfg, sizeof(LIBLTE_RRC_PUCCH_CONFIG_COMMON_STRUCT));
|
|
||||||
memcpy(&common.ul_pwr_ctrl, &sib2.rr_config_common_sib.ul_pwr_ctrl, sizeof(LIBLTE_RRC_UL_POWER_CONTROL_COMMON_STRUCT));
|
|
||||||
memcpy(&common.prach_cnfg, &sib2.rr_config_common_sib.prach_cnfg, sizeof(LIBLTE_RRC_PRACH_CONFIG_SIB_STRUCT));
|
|
||||||
if (sib2.rr_config_common_sib.srs_ul_cnfg.present) {
|
|
||||||
memcpy(&common.srs_ul_cnfg, &sib2.rr_config_common_sib.srs_ul_cnfg, sizeof(LIBLTE_RRC_SRS_UL_CONFIG_COMMON_STRUCT));
|
|
||||||
} else {
|
|
||||||
// default is release
|
|
||||||
common.srs_ul_cnfg.present = false;
|
|
||||||
}
|
|
||||||
phy->set_config_common(&common);
|
|
||||||
|
|
||||||
phy->configure_ul_params();
|
|
||||||
|
|
||||||
log_h->info("Set PUSCH ConfigCommon: HopOffset=%d, RSGroup=%d, RSNcs=%d, N_sb=%d\n",
|
|
||||||
sib2.rr_config_common_sib.pusch_cnfg.pusch_hopping_offset,
|
|
||||||
sib2.rr_config_common_sib.pusch_cnfg.ul_rs.group_assignment_pusch,
|
|
||||||
sib2.rr_config_common_sib.pusch_cnfg.ul_rs.cyclic_shift,
|
|
||||||
sib2.rr_config_common_sib.pusch_cnfg.n_sb);
|
|
||||||
|
|
||||||
log_h->info("Set PUCCH ConfigCommon: DeltaShift=%d, CyclicShift=%d, N1=%d, NRB=%d\n",
|
|
||||||
liblte_rrc_delta_pucch_shift_num[sib2.rr_config_common_sib.pucch_cnfg.delta_pucch_shift],
|
|
||||||
sib2.rr_config_common_sib.pucch_cnfg.n_cs_an,
|
|
||||||
sib2.rr_config_common_sib.pucch_cnfg.n1_pucch_an,
|
|
||||||
sib2.rr_config_common_sib.pucch_cnfg.n_rb_cqi);
|
|
||||||
|
|
||||||
log_h->info("Set PRACH ConfigCommon: SeqIdx=%d, HS=%d, FreqOffset=%d, ZC=%d, ConfigIndex=%d\n",
|
|
||||||
sib2.rr_config_common_sib.prach_cnfg.root_sequence_index,
|
|
||||||
sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.high_speed_flag?1:0,
|
|
||||||
sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_freq_offset,
|
|
||||||
sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.zero_correlation_zone_config,
|
|
||||||
sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_config_index);
|
|
||||||
|
|
||||||
log_h->info("Set SRS ConfigCommon: BW-Configuration=%d, SF-Configuration=%d, ACKNACK=%d\n",
|
|
||||||
sib2.rr_config_common_sib.srs_ul_cnfg.bw_cnfg,
|
|
||||||
sib2.rr_config_common_sib.srs_ul_cnfg.subfr_cnfg,
|
|
||||||
sib2.rr_config_common_sib.srs_ul_cnfg.ack_nack_simul_tx);
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Create classes
|
|
||||||
srslte::logger logger;
|
|
||||||
srslte::log_filter log_phy;
|
|
||||||
srslte::log_filter log_mac;
|
|
||||||
srslte::log_filter log_rlc;
|
|
||||||
srslte::log_filter log_tester;
|
|
||||||
srslte::mac_pcap mac_pcap;
|
|
||||||
srsue::phy my_phy;
|
|
||||||
srsue::mac my_mac;
|
|
||||||
srslte::rlc rlc;
|
|
||||||
srslte::radio_multi my_radio;
|
|
||||||
|
|
||||||
// Local classes for testing
|
|
||||||
tester my_tester;
|
|
||||||
|
|
||||||
|
|
||||||
bool running = true;
|
|
||||||
|
|
||||||
void sig_int_handler(int signo)
|
|
||||||
{
|
|
||||||
running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
|
|
||||||
parse_args(&prog_args, argc, argv);
|
|
||||||
|
|
||||||
// set to null to disable pcap
|
|
||||||
const char *pcap_filename = "/tmp/ip_test.pcap";
|
|
||||||
|
|
||||||
logger.init("/tmp/ip_test_ue.log");
|
|
||||||
log_phy.init("PHY ", &logger, true);
|
|
||||||
log_mac.init("MAC ", &logger, true);
|
|
||||||
log_rlc.init("RLC ", &logger);
|
|
||||||
log_tester.init("TEST", &logger);
|
|
||||||
logger.log("\n\n");
|
|
||||||
|
|
||||||
if (srsapps_verbose == 1) {
|
|
||||||
log_phy.set_level(srslte::LOG_LEVEL_INFO);
|
|
||||||
log_phy.set_hex_limit(100);
|
|
||||||
log_mac.set_level(srslte::LOG_LEVEL_DEBUG);
|
|
||||||
log_mac.set_hex_limit(100);
|
|
||||||
log_rlc.set_level(srslte::LOG_LEVEL_DEBUG);
|
|
||||||
log_rlc.set_hex_limit(1000);
|
|
||||||
log_tester.set_level(srslte::LOG_LEVEL_DEBUG);
|
|
||||||
log_tester.set_hex_limit(100);
|
|
||||||
printf("Log level info\n");
|
|
||||||
}
|
|
||||||
if (srsapps_verbose == 2) {
|
|
||||||
log_phy.set_level(srslte::LOG_LEVEL_DEBUG);
|
|
||||||
log_phy.set_hex_limit(100);
|
|
||||||
log_mac.set_level(srslte::LOG_LEVEL_DEBUG);
|
|
||||||
log_mac.set_hex_limit(100);
|
|
||||||
log_rlc.set_level(srslte::LOG_LEVEL_DEBUG);
|
|
||||||
log_rlc.set_hex_limit(100);
|
|
||||||
log_tester.set_level(srslte::LOG_LEVEL_DEBUG);
|
|
||||||
log_tester.set_hex_limit(100);
|
|
||||||
srslte_verbose = SRSLTE_VERBOSE_DEBUG;
|
|
||||||
printf("Log level debug\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init Radio and PHY
|
|
||||||
#ifdef USE_RADIO
|
|
||||||
my_radio.init();
|
|
||||||
#else
|
|
||||||
my_radio.init(NULL, "dummy");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
my_radio.set_tx_freq(prog_args.tx_freq);
|
|
||||||
my_radio.set_tx_gain(prog_args.tx_gain);
|
|
||||||
my_radio.set_rx_freq(prog_args.rx_freq);
|
|
||||||
my_radio.set_rx_gain(prog_args.rx_gain);
|
|
||||||
if (prog_args.time_adv >= 0) {
|
|
||||||
printf("Setting TA=%d samples\n",prog_args.time_adv);
|
|
||||||
my_radio.set_tx_adv(prog_args.time_adv);
|
|
||||||
}
|
|
||||||
|
|
||||||
my_phy.init(&my_radio, &my_mac, &my_tester, &log_phy, NULL);
|
|
||||||
my_mac.init(&my_phy, &rlc, &my_tester, &log_mac);
|
|
||||||
rlc.init(&my_tester, &my_tester, &my_tester, &log_rlc, &my_mac);
|
|
||||||
my_tester.init(&my_phy, &my_mac, &rlc, &log_tester, prog_args.ip_address);
|
|
||||||
|
|
||||||
|
|
||||||
if (pcap_filename) {
|
|
||||||
mac_pcap.open(pcap_filename);
|
|
||||||
my_mac.start_pcap(&mac_pcap);
|
|
||||||
signal(SIGINT, sig_int_handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set MAC defaults
|
|
||||||
LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT default_cfg;
|
|
||||||
bzero(&default_cfg, sizeof(LIBLTE_RRC_MAC_MAIN_CONFIG_STRUCT));
|
|
||||||
default_cfg.ulsch_cnfg.max_harq_tx = LIBLTE_RRC_MAX_HARQ_TX_N5;
|
|
||||||
default_cfg.ulsch_cnfg.periodic_bsr_timer = LIBLTE_RRC_PERIODIC_BSR_TIMER_INFINITY;
|
|
||||||
default_cfg.ulsch_cnfg.retx_bsr_timer = LIBLTE_RRC_RETRANSMISSION_BSR_TIMER_SF2560;
|
|
||||||
default_cfg.ulsch_cnfg.tti_bundling = false;
|
|
||||||
default_cfg.drx_cnfg.setup_present = false;
|
|
||||||
default_cfg.phr_cnfg.setup_present = false;
|
|
||||||
default_cfg.time_alignment_timer = LIBLTE_RRC_TIME_ALIGNMENT_TIMER_INFINITY;
|
|
||||||
my_mac.set_config_main(&default_cfg);
|
|
||||||
|
|
||||||
while(running) {
|
|
||||||
if (my_tester.is_sib_received()) {
|
|
||||||
printf("Main running\n");
|
|
||||||
sleep(1);
|
|
||||||
} else {
|
|
||||||
my_tester.sib_search();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pcap_filename) {
|
|
||||||
mac_pcap.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
my_phy.stop();
|
|
||||||
my_mac.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/******************* This is copied from srsue gw **********************/
|
|
||||||
int setup_if_addr(char *ip_addr)
|
|
||||||
{
|
|
||||||
|
|
||||||
char *dev = (char*) "tun_srsue";
|
|
||||||
|
|
||||||
// Construct the TUN device
|
|
||||||
int tun_fd = open("/dev/net/tun", O_RDWR);
|
|
||||||
if(0 > tun_fd)
|
|
||||||
{
|
|
||||||
perror("open");
|
|
||||||
return(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ifreq ifr;
|
|
||||||
|
|
||||||
memset(&ifr, 0, sizeof(ifr));
|
|
||||||
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
|
|
||||||
strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ);
|
|
||||||
if(0 > ioctl(tun_fd, TUNSETIFF, &ifr))
|
|
||||||
{
|
|
||||||
perror("ioctl");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bring up the interface
|
|
||||||
int sock = socket(AF_INET, SOCK_DGRAM, 0);
|
|
||||||
if(0 > ioctl(sock, SIOCGIFFLAGS, &ifr))
|
|
||||||
{
|
|
||||||
perror("socket");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
|
|
||||||
if(0 > ioctl(sock, SIOCSIFFLAGS, &ifr))
|
|
||||||
{
|
|
||||||
perror("ioctl");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup the IP address
|
|
||||||
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
|
||||||
ifr.ifr_addr.sa_family = AF_INET;
|
|
||||||
((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = inet_addr(ip_addr);
|
|
||||||
if(0 > ioctl(sock, SIOCSIFADDR, &ifr))
|
|
||||||
{
|
|
||||||
perror("ioctl");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
ifr.ifr_netmask.sa_family = AF_INET;
|
|
||||||
((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr("255.255.255.0");
|
|
||||||
if(0 > ioctl(sock, SIOCSIFNETMASK, &ifr))
|
|
||||||
{
|
|
||||||
perror("ioctl");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return(tun_fd);
|
|
||||||
}
|
|
Loading…
Reference in New Issue