Attach and paging ok. Reselection on IDLE not working

master
Ismael Gomez 7 years ago
parent 2c3386a486
commit b3be54b274

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

@ -112,12 +112,18 @@ public:
class nas_interface_rrc class nas_interface_rrc
{ {
public: public:
virtual void rrc_connection_failure() = 0; typedef enum {
BARRING_NONE = 0,
BARRING_MO_DATA,
BARRING_MO_SIGNALLING,
BARRING_MT,
BARRING_ALL
} barring_t;
virtual void set_barring(barring_t barring) = 0;
virtual void paging(LIBLTE_RRC_S_TMSI_STRUCT *ue_identiy) = 0; virtual void paging(LIBLTE_RRC_S_TMSI_STRUCT *ue_identiy) = 0;
virtual bool is_attached() = 0; virtual bool is_attached() = 0;
virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0; virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0;
virtual uint32_t get_ul_count() = 0; virtual uint32_t get_ul_count() = 0;
virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 0;
virtual bool get_k_asme(uint8_t *k_asme_, uint32_t n) = 0; virtual bool get_k_asme(uint8_t *k_asme_, uint32_t n) = 0;
}; };
@ -177,7 +183,9 @@ public:
virtual void enable_capabilities() = 0; virtual void enable_capabilities() = 0;
virtual int plmn_search(found_plmn_t found_plmns[MAX_FOUND_PLMNS]) = 0; virtual int plmn_search(found_plmn_t found_plmns[MAX_FOUND_PLMNS]) = 0;
virtual void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) = 0; virtual void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) = 0;
virtual bool connection_request() = 0; virtual bool connection_request(LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM cause,
srslte::byte_buffer_t *dedicatedInfoNAS) = 0;
virtual void set_ue_idenity(LIBLTE_RRC_S_TMSI_STRUCT s_tmsi) = 0;
virtual bool is_connected() = 0; virtual bool is_connected() = 0;
virtual std::string get_rb_name(uint32_t lcid) = 0; virtual std::string get_rb_name(uint32_t lcid) = 0;
}; };
@ -420,14 +428,13 @@ public:
uint32_t prach_config_index; uint32_t prach_config_index;
} mac_cfg_t; } mac_cfg_t;
virtual void clear_rntis() = 0;
/* Instructs the MAC to start receiving BCCH */ /* Instructs the MAC to start receiving BCCH */
virtual void bcch_start_rx() = 0;
virtual void bcch_stop_rx() = 0;
virtual void bcch_start_rx(int si_window_start, int si_window_length) = 0; virtual void bcch_start_rx(int si_window_start, int si_window_length) = 0;
/* Instructs the MAC to start receiving PCCH */ /* Instructs the MAC to start receiving PCCH */
virtual void pcch_start_rx() = 0; virtual void pcch_start_rx() = 0;
virtual void pcch_stop_rx() = 0;
/* RRC configures a logical channel */ /* RRC configures a logical channel */
virtual void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) = 0; virtual void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) = 0;
@ -487,7 +494,6 @@ typedef struct {
uint32_t cfo_loop_pss_conv; uint32_t cfo_loop_pss_conv;
uint32_t cfo_ref_mask; uint32_t cfo_ref_mask;
bool average_subframe_enabled; bool average_subframe_enabled;
int time_correct_period;
std::string sss_algorithm; std::string sss_algorithm;
float estimator_fil_w; float estimator_fil_w;
bool rssi_sensor_enabled; bool rssi_sensor_enabled;
@ -579,11 +585,9 @@ public:
virtual int meas_start(uint32_t earfcn, int pci = -1) = 0; virtual int meas_start(uint32_t earfcn, int pci = -1) = 0;
virtual int meas_stop(uint32_t earfcn, int pci = -1) = 0; virtual int meas_stop(uint32_t earfcn, int pci = -1) = 0;
typedef enum { typedef struct {
CELL_NOT_FOUND = 0, enum {CELL_FOUND = 0, CELL_NOT_FOUND, ERROR} found;
CELL_FOUND, enum {MORE_FREQS = 0, NO_MORE_FREQS} last_freq;
NO_MORE_FREQS,
ERROR
} cell_search_ret_t; } cell_search_ret_t;
typedef struct { typedef struct {
@ -592,7 +596,7 @@ public:
} phy_cell_t; } phy_cell_t;
/* Cell search and selection procedures */ /* Cell search and selection procedures */
virtual cell_search_ret_t cell_search(phy_cell_t *cell, float *rsrp) = 0; virtual cell_search_ret_t cell_search(phy_cell_t *cell) = 0;
virtual bool cell_select(phy_cell_t *cell = NULL) = 0; virtual bool cell_select(phy_cell_t *cell = NULL) = 0;
virtual bool cell_is_camping() = 0; virtual bool cell_is_camping() = 0;

@ -765,6 +765,7 @@ int rf_uhd_recv_with_time_multi(void *h,
trials++; trials++;
if (error_code == UHD_RX_METADATA_ERROR_CODE_OVERFLOW) { if (error_code == UHD_RX_METADATA_ERROR_CODE_OVERFLOW) {
printf("OVERFLOW\n");
log_overflow(handler); log_overflow(handler);
} else if (error_code == UHD_RX_METADATA_ERROR_CODE_LATE_COMMAND) { } else if (error_code == UHD_RX_METADATA_ERROR_CODE_LATE_COMMAND) {
log_late(handler, true); log_late(handler, true);

@ -72,10 +72,9 @@ public:
/******** Interface from RLC (RLC -> MAC) ****************/ /******** Interface from RLC (RLC -> MAC) ****************/
void bcch_start_rx(); void bcch_start_rx();
void bcch_stop_rx();
void bcch_start_rx(int si_window_start, int si_window_length); void bcch_start_rx(int si_window_start, int si_window_length);
void pcch_start_rx(); void pcch_start_rx();
void pcch_stop_rx(); void clear_rntis();
void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD); void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD);
void reconfiguration(); void reconfiguration();
void reset(); void reset();

@ -76,7 +76,7 @@ public:
float avg_snr_db; float avg_snr_db;
float avg_noise; float avg_noise;
bool pcell_meas_enabled; bool pcell_first_measurement;
uint32_t pcell_report_period; uint32_t pcell_report_period;
// Save last TBS for mcs>28 cases // Save last TBS for mcs>28 cases

@ -59,7 +59,7 @@ public:
void radio_overflow(); void radio_overflow();
// RRC interface for controling the SYNC state // RRC interface for controling the SYNC state
phy_interface_rrc::cell_search_ret_t cell_search(phy_interface_rrc::phy_cell_t *cell, float *rsrpq); phy_interface_rrc::cell_search_ret_t cell_search(phy_interface_rrc::phy_cell_t *cell);
bool cell_select(phy_interface_rrc::phy_cell_t *cell); bool cell_select(phy_interface_rrc::phy_cell_t *cell);
bool cell_is_camping(); bool cell_is_camping();
@ -98,9 +98,7 @@ private:
~search(); ~search();
void init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, phch_recv *parent); void init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, phch_recv *parent);
void reset(); void reset();
float get_last_gain();
float get_last_cfo(); float get_last_cfo();
void set_N_id_2(int N_id_2);
void set_agc_enable(bool enable); void set_agc_enable(bool enable);
ret_code run(srslte_cell_t *cell); ret_code run(srslte_cell_t *cell);
@ -247,6 +245,7 @@ private:
void radio_error(); void radio_error();
void set_ue_sync_opts(srslte_ue_sync_t *q, float cfo); void set_ue_sync_opts(srslte_ue_sync_t *q, float cfo);
void run_thread(); void run_thread();
float get_tx_cfo();
void set_sampling_rate(); void set_sampling_rate();
bool set_frequency(); bool set_frequency();
@ -302,7 +301,6 @@ private:
IDLE = 0, IDLE = 0,
CELL_SEARCH, CELL_SEARCH,
SFN_SYNC, SFN_SYNC,
MEASURE,
CAMPING, CAMPING,
} state_t; } state_t;
@ -318,9 +316,13 @@ private:
} }
// Called by the main thread at the end of each state to indicate it has finished. // Called by the main thread at the end of each state to indicate it has finished.
void state_exit() { void state_exit(bool exit_ok = true) {
pthread_mutex_lock(&inside); pthread_mutex_lock(&inside);
next_state = IDLE; if (cur_state == SFN_SYNC && exit_ok == true) {
next_state = CAMPING;
} else {
next_state = IDLE;
}
pthread_mutex_unlock(&inside); pthread_mutex_unlock(&inside);
} }
void force_sfn_sync() { void force_sfn_sync() {
@ -328,11 +330,6 @@ private:
next_state = SFN_SYNC; next_state = SFN_SYNC;
pthread_mutex_unlock(&inside); pthread_mutex_unlock(&inside);
} }
void force_camping() {
pthread_mutex_lock(&inside);
next_state = CAMPING;
pthread_mutex_unlock(&inside);
}
/* Functions to be called from outside the STM thread to instruct the STM to switch state. /* Functions to be called from outside the STM thread to instruct the STM to switch state.
* The functions change the state and wait until it has changed it. * The functions change the state and wait until it has changed it.
@ -344,27 +341,16 @@ private:
go_state(IDLE); go_state(IDLE);
pthread_mutex_unlock(&outside); pthread_mutex_unlock(&outside);
} }
void go_camping() {
pthread_mutex_lock(&outside);
go_state(CAMPING);
pthread_mutex_unlock(&outside);
}
void run_cell_search() { void run_cell_search() {
pthread_mutex_lock(&outside); pthread_mutex_lock(&outside);
go_state(CELL_SEARCH); go_state(CELL_SEARCH);
wait_idle(); wait_state_change(CELL_SEARCH);
pthread_mutex_unlock(&outside); pthread_mutex_unlock(&outside);
} }
void run_sfn_sync() { void run_sfn_sync() {
pthread_mutex_lock(&outside); pthread_mutex_lock(&outside);
go_state(SFN_SYNC); go_state(SFN_SYNC);
wait_idle(); wait_state_change(SFN_SYNC);
pthread_mutex_unlock(&outside);
}
void run_measure() {
pthread_mutex_lock(&outside);
go_state(MEASURE);
wait_idle();
pthread_mutex_unlock(&outside); pthread_mutex_unlock(&outside);
} }
@ -377,6 +363,21 @@ private:
return cur_state == CAMPING; return cur_state == CAMPING;
} }
const char *to_string() {
switch(cur_state) {
case IDLE:
return "IDLE";
case CELL_SEARCH:
return "SEARCH";
case SFN_SYNC:
return "SYNC";
case CAMPING:
return "CAMPING";
default:
return "UNKNOWN";
}
}
sync_state() { sync_state() {
pthread_mutex_init(&inside, NULL); pthread_mutex_init(&inside, NULL);
pthread_mutex_init(&outside, NULL); pthread_mutex_init(&outside, NULL);
@ -396,9 +397,9 @@ private:
} }
/* Waits until there is a call to set_state() and then run_state(). Returns when run_state() returns */ /* Waits until there is a call to set_state() and then run_state(). Returns when run_state() returns */
void wait_idle() { void wait_state_change(state_t prev_state) {
pthread_mutex_lock(&inside); pthread_mutex_lock(&inside);
while(cur_state != IDLE) { while(cur_state == prev_state) {
pthread_cond_wait(&cvar, &inside); pthread_cond_wait(&cvar, &inside);
} }
pthread_mutex_unlock(&inside); pthread_mutex_unlock(&inside);
@ -415,8 +416,6 @@ private:
sync_state phy_state; sync_state phy_state;
search::ret_code cell_search_ret; search::ret_code cell_search_ret;
sfn_sync::ret_code sfn_sync_ret;
measure::ret_code measure_ret;
// Sampling rate mode (find is 1.96 MHz, camp is the full cell BW) // Sampling rate mode (find is 1.96 MHz, camp is the full cell BW)
enum { enum {
@ -426,7 +425,6 @@ private:
// This is the primary cell // This is the primary cell
srslte_cell_t cell; srslte_cell_t cell;
bool cell_is_set;
bool started; bool started;
float time_adv_sec; float time_adv_sec;
uint32_t tti; uint32_t tti;

@ -83,7 +83,7 @@ public:
/********** RRC INTERFACE ********************/ /********** RRC INTERFACE ********************/
void reset(); void reset();
void configure_ul_params(bool pregen_disabled = false); void configure_ul_params(bool pregen_disabled = false);
cell_search_ret_t cell_search(phy_cell_t *cell, float *rsrp); cell_search_ret_t cell_search(phy_cell_t *cell);
bool cell_select(phy_cell_t *cell); bool cell_select(phy_cell_t *cell);
void meas_reset(); void meas_reset();

@ -43,18 +43,14 @@ namespace srsue {
typedef enum { typedef enum {
EMM_STATE_NULL = 0, EMM_STATE_NULL = 0,
EMM_STATE_DEREGISTERED, EMM_STATE_DEREGISTERED,
EMM_STATE_REGISTERED_INITIATED,
EMM_STATE_REGISTERED, EMM_STATE_REGISTERED,
EMM_STATE_SERVICE_REQUEST_INITIATED,
EMM_STATE_DEREGISTERED_INITIATED, EMM_STATE_DEREGISTERED_INITIATED,
EMM_STATE_TAU_INITIATED, EMM_STATE_TAU_INITIATED,
EMM_STATE_N_ITEMS, EMM_STATE_N_ITEMS,
} emm_state_t; } emm_state_t;
static const char emm_state_text[EMM_STATE_N_ITEMS][100] = {"NULL", static const char emm_state_text[EMM_STATE_N_ITEMS][100] = {"NULL",
"DEREGISTERED", "DEREGISTERED",
"REGISTERED INITIATED",
"REGISTERED", "REGISTERED",
"SERVICE REQUEST INITIATED",
"DEREGISTERED INITIATED", "DEREGISTERED INITIATED",
"TRACKING AREA UPDATE INITIATED"}; "TRACKING AREA UPDATE INITIATED"};
@ -79,11 +75,10 @@ public:
// RRC interface // RRC interface
void paging(LIBLTE_RRC_S_TMSI_STRUCT *ue_identiy); void paging(LIBLTE_RRC_S_TMSI_STRUCT *ue_identiy);
void rrc_connection_failure(); void set_barring(barring_t barring);
void write_pdu(uint32_t lcid, byte_buffer_t *pdu); void write_pdu(uint32_t lcid, byte_buffer_t *pdu);
uint32_t get_ul_count(); uint32_t get_ul_count();
bool is_attached(); bool is_attached();
bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi);
bool get_k_asme(uint8_t *k_asme_, uint32_t n); bool get_k_asme(uint8_t *k_asme_, uint32_t n);
// UE interface // UE interface
@ -104,7 +99,8 @@ private:
emm_state_t state; emm_state_t state;
bool rrc_connection_is_failure; nas_interface_rrc::barring_t current_barring;
bool plmn_is_selected; bool plmn_is_selected;
LIBLTE_RRC_PLMN_IDENTITY_STRUCT current_plmn; LIBLTE_RRC_PLMN_IDENTITY_STRUCT current_plmn;
LIBLTE_RRC_PLMN_IDENTITY_STRUCT home_plmn; LIBLTE_RRC_PLMN_IDENTITY_STRUCT home_plmn;
@ -140,8 +136,9 @@ private:
// PCAP // PCAP
srslte::nas_pcap *pcap = NULL; srslte::nas_pcap *pcap = NULL;
bool running;
bool rrc_connect(); bool rrc_connect();
bool attach(bool is_service_req);
void integrity_generate(uint8_t *key_128, void integrity_generate(uint8_t *key_128,
uint32_t count, uint32_t count,
@ -168,10 +165,12 @@ private:
void parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu); void parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu);
void parse_emm_information(uint32_t lcid, byte_buffer_t *pdu); void parse_emm_information(uint32_t lcid, byte_buffer_t *pdu);
// Packet generators
void gen_attach_request(byte_buffer_t *msg);
void gen_service_request(byte_buffer_t *msg);
// Senders // Senders
void send_attach_request();
void send_identity_response(); void send_identity_response();
void send_service_request();
void send_esm_information_response(); void send_esm_information_response();
void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg); void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg);
void send_security_mode_reject(uint8_t cause); void send_security_mode_reject(uint8_t cause);

@ -64,8 +64,9 @@ class cell_t
bool equals(uint32_t earfcn, uint32_t pci) { bool equals(uint32_t earfcn, uint32_t pci) {
return earfcn == this->phy_cell.earfcn && pci == phy_cell.cell.id; return earfcn == this->phy_cell.earfcn && pci == phy_cell.cell.id;
} }
// NaN means an RSRP value has not yet been obtained. Keep then in the list and clean them if never updated
bool greater(cell_t *x) { bool greater(cell_t *x) {
return rsrp > x->rsrp; return rsrp > x->rsrp || isnan(rsrp);
} }
bool plmn_equals(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) { bool plmn_equals(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) {
if (has_valid_sib1) { if (has_valid_sib1) {
@ -282,7 +283,9 @@ public:
uint16_t get_mnc(); uint16_t get_mnc();
int plmn_search(found_plmn_t found_plmns[MAX_FOUND_PLMNS]); int plmn_search(found_plmn_t found_plmns[MAX_FOUND_PLMNS]);
void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id); void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id);
bool connection_request(); bool connection_request(LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM cause,
srslte::byte_buffer_t *dedicatedInfoNAS);
void set_ue_idenity(LIBLTE_RRC_S_TMSI_STRUCT s_tmsi);
// PHY interface // PHY interface
void in_sync(); void in_sync();
@ -321,6 +324,8 @@ private:
LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg; LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg;
LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg; LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg;
byte_buffer_t *dedicatedInfoNAS;
byte_buffer_t* byte_align_and_pack(); byte_buffer_t* byte_align_and_pack();
void send_ul_ccch_msg(); void send_ul_ccch_msg();
void send_ul_dcch_msg(); void send_ul_dcch_msg();
@ -330,6 +335,9 @@ private:
rrc_state_t state; rrc_state_t state;
uint8_t transaction_id; uint8_t transaction_id;
LIBLTE_RRC_S_TMSI_STRUCT ueIdentity;
bool ueIdentity_configured;
bool drb_up; bool drb_up;
rrc_args_t args; rrc_args_t args;
@ -358,7 +366,7 @@ private:
srslte::mac_interface_timers *mac_timers; srslte::mac_interface_timers *mac_timers;
uint32_t n310_cnt, N310; uint32_t n310_cnt, N310;
uint32_t n311_cnt, N311; uint32_t n311_cnt, N311;
uint32_t t300, t301, t310, t311, t304; uint32_t t300, t301, t302, t310, t311, t304;
// Radio bearers // Radio bearers
typedef enum{ typedef enum{
@ -408,7 +416,7 @@ private:
bool si_acquire(uint32_t index); bool si_acquire(uint32_t index);
uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t offset, uint32_t sf); uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t offset, uint32_t sf);
const static int SIB_SEARCH_TIMEOUT_MS = 5000; const static int SIB_SEARCH_TIMEOUT_MS = 1000;
const static uint32_t NOF_REQUIRED_SIBS = 3; // SIB1, SIB2 and SIB3 const static uint32_t NOF_REQUIRED_SIBS = 3; // SIB1, SIB2 and SIB3
@ -510,6 +518,18 @@ private:
rrc_meas measurements; rrc_meas measurements;
// Measurement object from phy
typedef struct {
float rsrp;
float rsrq;
uint32_t tti;
uint32_t earfcn;
uint32_t pci;
} phy_meas_t;
void process_phy_meas();
void process_new_phy_meas(phy_meas_t meas);
std::queue<phy_meas_t> phy_meas_q;
// Cell selection/reselection functions/variables // Cell selection/reselection functions/variables
typedef struct { typedef struct {
@ -542,7 +562,7 @@ private:
void max_retx_attempted(); void max_retx_attempted();
// Senders // Senders
void send_con_request(); void send_con_request(LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM cause);
void send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_ENUM cause); void send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_ENUM cause);
void send_con_restablish_complete(); void send_con_restablish_complete();
void send_con_setup_complete(byte_buffer_t *nas_msg); void send_con_setup_complete(byte_buffer_t *nas_msg);

@ -189,18 +189,13 @@ void mac::bcch_start_rx(int si_window_start, int si_window_length)
Info("SCHED: Searching for DL grant for SI-RNTI window_st=%d, window_len=%d\n", si_window_start, si_window_length); Info("SCHED: Searching for DL grant for SI-RNTI window_st=%d, window_len=%d\n", si_window_start, si_window_length);
} }
void mac::bcch_stop_rx()
{
phy_h->pdcch_dl_search_reset();
}
void mac::pcch_start_rx() void mac::pcch_start_rx()
{ {
phy_h->pdcch_dl_search(SRSLTE_RNTI_PCH, SRSLTE_PRNTI); phy_h->pdcch_dl_search(SRSLTE_RNTI_PCH, SRSLTE_PRNTI);
Info("SCHED: Searching for DL grant for P-RNTI\n"); Info("SCHED: Searching for DL grant for P-RNTI\n");
} }
void mac::pcch_stop_rx() void mac::clear_rntis()
{ {
phy_h->pdcch_dl_search_reset(); phy_h->pdcch_dl_search_reset();
} }

@ -261,10 +261,6 @@ void parse_args(all_args_t *args, int argc, char *argv[]) {
bpo::value<bool>(&args->expert.phy.average_subframe_enabled)->default_value(true), bpo::value<bool>(&args->expert.phy.average_subframe_enabled)->default_value(true),
"Averages in the time domain the channel estimates within 1 subframe. Needs accurate CFO correction.") "Averages in the time domain the channel estimates within 1 subframe. Needs accurate CFO correction.")
("expert.time_correct_period",
bpo::value<int>(&args->expert.phy.time_correct_period)->default_value(5),
"Period for sampling time offset correction.")
("expert.sss_algorithm", ("expert.sss_algorithm",
bpo::value<string>(&args->expert.phy.sss_algorithm)->default_value("full"), bpo::value<string>(&args->expert.phy.sss_algorithm)->default_value("full"),
"Selects the SSS estimation algorithm.") "Selects the SSS estimation algorithm.")

@ -346,7 +346,6 @@ void phch_common::reset() {
avg_rsrp_dbm = 0; avg_rsrp_dbm = 0;
avg_rsrq_db = 0; avg_rsrq_db = 0;
pcell_meas_enabled = false;
pcell_report_period = 20; pcell_report_period = 20;
bzero(pending_ack, sizeof(pending_ack_t)*TTIMOD_SZ); bzero(pending_ack, sizeof(pending_ack_t)*TTIMOD_SZ);

@ -134,7 +134,6 @@ void phch_recv::reset()
tx_mutex_cnt = 0; tx_mutex_cnt = 0;
time_adv_sec = 0; time_adv_sec = 0;
next_offset = 0; next_offset = 0;
cell_is_set = false;
srate_mode = SRATE_NONE; srate_mode = SRATE_NONE;
current_earfcn = -1; current_earfcn = -1;
sfn_p.reset(); sfn_p.reset();
@ -183,9 +182,12 @@ void phch_recv::reset()
* If no cells are found in any frequency it returns 0. If error returns -1. * If no cells are found in any frequency it returns 0. If error returns -1.
*/ */
phy_interface_rrc::cell_search_ret_t phch_recv::cell_search(phy_interface_rrc::phy_cell_t *found_cell, float *rsrp) phy_interface_rrc::cell_search_ret_t phch_recv::cell_search(phy_interface_rrc::phy_cell_t *found_cell)
{ {
phy_interface_rrc::cell_search_ret_t ret = phy_interface_rrc::ERROR; phy_interface_rrc::cell_search_ret_t ret;
ret.found = phy_interface_rrc::cell_search_ret_t::ERROR;
ret.last_freq = phy_interface_rrc::cell_search_ret_t::NO_MORE_FREQS;
pthread_mutex_lock(&rrc_mutex); pthread_mutex_lock(&rrc_mutex);
@ -213,51 +215,24 @@ phy_interface_rrc::cell_search_ret_t phch_recv::cell_search(phy_interface_rrc::p
set_sampling_rate(); set_sampling_rate();
phy_state.run_sfn_sync(); phy_state.run_sfn_sync();
switch (sfn_sync_ret) if (phy_state.is_camping()) {
{ log_h->info("Cell Search: Sync OK. Camping on cell PCI=%d\n", cell.id);
case sfn_sync::SFN_FOUND: if (found_cell) {
log_h->info("Cell Search. Sync OK. Measuring PCI=%d...\n", cell.id); found_cell->earfcn = current_earfcn;
measure_p.reset(); found_cell->cell = cell;
phy_state.run_measure(); }
ret = phy_interface_rrc::CELL_FOUND; ret.found = phy_interface_rrc::cell_search_ret_t::CELL_FOUND;
if (found_cell) { } else {
found_cell->earfcn = current_earfcn; log_h->info("Cell Search: Could not synchronize with cell\n");
found_cell->cell = cell; ret.found = phy_interface_rrc::cell_search_ret_t::CELL_NOT_FOUND;
}
switch(measure_ret) {
case measure::MEASURE_OK:
log_h->info("SYNC: Measured OK. Camping on cell PCI=%d...\n", cell.id);
if (rsrp) {
*rsrp = measure_p.rsrp() - worker_com->args->rx_gain_offset;
}
phy_state.go_camping();
break;
default:
log_h->error("Cell Search: Error running cell measurement\n");
break;
}
break;
case sfn_sync::ERROR:
log_h->error("Cell Search: Error running SFN synchronization\n");
break;
default:
log_h->info("Cell Search: Could not synchronize with cell\n");
ret = phy_interface_rrc::CELL_NOT_FOUND;
break;
} }
} else { } else {
Error("Cell Search: Setting cell PCI=%d, nof_prb=%d\n", cell.id, cell.nof_prb); Error("Cell Search: Setting cell PCI=%d, nof_prb=%d\n", cell.id, cell.nof_prb);
} }
break; break;
case search::CELL_NOT_FOUND: case search::CELL_NOT_FOUND:
cellsearch_earfcn_index++; Info("Cell Search: No cell found in this frequency\n");
if (cellsearch_earfcn_index >= earfcn.size()) { ret.found = phy_interface_rrc::cell_search_ret_t::CELL_NOT_FOUND;
Info("Cell Search: No cells were found in the current set\n");
cellsearch_earfcn_index = 0;
ret = phy_interface_rrc::NO_MORE_FREQS;
} else {
ret = phy_interface_rrc::CELL_NOT_FOUND;
}
break; break;
default: default:
Error("Cell Search: while receiving samples\n"); Error("Cell Search: while receiving samples\n");
@ -265,6 +240,15 @@ phy_interface_rrc::cell_search_ret_t phch_recv::cell_search(phy_interface_rrc::p
break; break;
} }
cellsearch_earfcn_index++;
if (cellsearch_earfcn_index >= earfcn.size()) {
Info("Cell Search: No more frequencies in the current EARFCN set\n");
cellsearch_earfcn_index = 0;
ret.last_freq = phy_interface_rrc::cell_search_ret_t::NO_MORE_FREQS;
} else {
ret.last_freq = phy_interface_rrc::cell_search_ret_t::MORE_FREQS;
}
pthread_mutex_unlock(&rrc_mutex); pthread_mutex_unlock(&rrc_mutex);
return ret; return ret;
} }
@ -337,22 +321,13 @@ bool phch_recv::cell_select(phy_interface_rrc::phy_cell_t *new_cell) {
} }
/* SFN synchronization */ /* SFN synchronization */
phy_state.run_sfn_sync();
bool ret = false; bool ret = false;
switch(sfn_sync_ret) { phy_state.run_sfn_sync();
case sfn_sync::SFN_FOUND: if (phy_state.is_camping()) {
Info("Cell Select: SFN syncrhonized, going to CAMPING\n"); Info("Cell Select: SFN synchronized. CAMPING...\n");
phy_state.go_camping(); ret = true;
ret = true; } else {
break; Info("Cell Select: Could not synchronize SFN\n");
case sfn_sync::ERROR:
Error("Cell Select: Error receiving samples when synchronizing SFN\n");
radio_error();
break;
default:
Info("Cell Select: Could not synchronize SFN\n");
break;
} }
pthread_mutex_unlock(&rrc_mutex); pthread_mutex_unlock(&rrc_mutex);
@ -398,7 +373,7 @@ void phch_recv::run_thread()
while (running) while (running)
{ {
Debug("SYNC: state=%d\n", phy_state); Debug("SYNC: state=%s\n", phy_state.to_string());
log_phy_lib_h->step(tti); log_phy_lib_h->step(tti);
@ -416,15 +391,15 @@ void phch_recv::run_thread()
/* SFN synchronization using MIB. run_subframe() receives and processes 1 subframe /* SFN synchronization using MIB. run_subframe() receives and processes 1 subframe
* and returns * and returns
*/ */
sfn_sync_ret = sfn_p.run_subframe(&cell, &tti); switch(sfn_p.run_subframe(&cell, &tti)) {
if (sfn_sync_ret != sfn_sync::IDLE) { case sfn_sync::SFN_FOUND:
phy_state.state_exit(); phy_state.state_exit();
} break;
break; case sfn_sync::IDLE:
case sync_state::MEASURE: break;
measure_ret = measure_p.run_subframe_sync(&ue_sync, sf_idx); default:
if (measure_ret != measure::IDLE) { phy_state.state_exit(false);
phy_state.state_exit(); break;
} }
break; break;
case sync_state::CAMPING: case sync_state::CAMPING:
@ -452,7 +427,7 @@ void phch_recv::run_thread()
metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync); metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync);
metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync); metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync);
worker->set_cfo(ul_dl_factor * metrics.cfo / 15000); worker->set_cfo(get_tx_cfo());
worker_com->set_sync_metrics(metrics); worker_com->set_sync_metrics(metrics);
/* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */ /* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */
@ -478,7 +453,7 @@ void phch_recv::run_thread()
if (prach_buffer->is_ready_to_send(tti)) { if (prach_buffer->is_ready_to_send(tti)) {
srslte_timestamp_copy(&tx_time_prach, &rx_time); srslte_timestamp_copy(&tx_time_prach, &rx_time);
srslte_timestamp_add(&tx_time_prach, 0, prach::tx_advance_sf * 1e-3); srslte_timestamp_add(&tx_time_prach, 0, prach::tx_advance_sf * 1e-3);
prach_buffer->send(radio_h, ul_dl_factor * metrics.cfo / 15000, worker_com->pathloss, tx_time_prach); prach_buffer->send(radio_h, get_tx_cfo(), worker_com->pathloss, tx_time_prach);
radio_h->tx_end(); radio_h->tx_end();
worker_com->p0_preamble = prach_buffer->get_p0_preamble(); worker_com->p0_preamble = prach_buffer->get_p0_preamble();
worker_com->cur_radio_power = SRSLTE_MIN(SRSLTE_PC_MAX, worker_com->pathloss+worker_com->p0_preamble); worker_com->cur_radio_power = SRSLTE_MIN(SRSLTE_PC_MAX, worker_com->pathloss+worker_com->p0_preamble);
@ -514,6 +489,7 @@ void phch_recv::run_thread()
if (current_srate > 0) { if (current_srate > 0) {
nsamples = current_srate/1000; nsamples = current_srate/1000;
} }
Debug("Discarting %d samples\n", nsamples);
if (!radio_h->rx_now(dummy_buffer, nsamples, NULL)) { if (!radio_h->rx_now(dummy_buffer, nsamples, NULL)) {
printf("SYNC: Receiving from radio while in IDLE_RX\n"); printf("SYNC: Receiving from radio while in IDLE_RX\n");
} }
@ -527,37 +503,29 @@ void phch_recv::run_thread()
* SFN is found again go back to camping * SFN is found again go back to camping
*/ */
if (radio_is_overflow) { if (radio_is_overflow) {
// Overflow has occurred now while camping // If we are coming back from an overflow
if (phy_state.is_camping()) { if (radio_overflow_return) {
log_h->info("Detected radio overflow while camping. Resynchronizing cell\n"); if (phy_state.is_camping()) {
sfn_p.reset(); log_h->info("Successfully resynchronized after overflow. Returning to CAMPING\n");
phy_state.force_sfn_sync(); radio_overflow_return = false;
radio_overflow_return = true; radio_is_overflow = false;
// This means that it finished running sfn_sync } else if (phy_state.is_idle()) {
} else if (phy_state.is_idle() && radio_overflow_return) { log_h->warning("Could not synchronize SFN after radio overflow. Trying again\n");
switch (sfn_sync_ret) { rrc->out_of_sync();
case sfn_sync::SFN_FOUND: phy_state.force_sfn_sync();
log_h->info("Successfully resynchronized after overflow. Returning to CAMPING\n");
radio_overflow_return = false;
radio_is_overflow = false;
phy_state.force_camping();
break;
case sfn_sync::ERROR:
log_h->error("Error while recovering from overflow. Trying again\n");
radio_error();
rrc->out_of_sync();
phy_state.force_sfn_sync();
break;
case sfn_sync::SFN_NOFOUND:
log_h->warning("Could not syncrhonize SFN after radio overflow. Trying again\n");
rrc->out_of_sync();
phy_state.force_sfn_sync();
break;
default:
break;
} }
} else {
// Overflow has occurred now while camping
if (phy_state.is_camping()) {
log_h->warning("Detected radio overflow while camping. Resynchronizing cell\n");
sfn_p.reset();
phy_state.force_sfn_sync();
radio_overflow_return = true;
} else {
radio_is_overflow = false;
}
// If overflow occurs in any other state, it does not harm
} }
// If overflow occurs in any other state, it does not harm
} }
// Increase TTI counter // Increase TTI counter
@ -582,6 +550,7 @@ void phch_recv::run_thread()
* *
*/ */
void phch_recv::radio_overflow() { void phch_recv::radio_overflow() {
log_h->warning("Overflow\n");
radio_is_overflow = true; radio_is_overflow = true;
} }
@ -639,6 +608,25 @@ void phch_recv::set_time_adv_sec(float time_adv_sec)
this->time_adv_sec = time_adv_sec; this->time_adv_sec = time_adv_sec;
} }
float phch_recv::get_tx_cfo()
{
float cfo = srslte_ue_sync_get_cfo(&ue_sync);
float ret = cfo*ul_dl_factor;
if (worker_com->args->cfo_is_doppler) {
ret *= -1;
}
if (radio_h->get_freq_offset() != 0.0f) {
/* Compensates the radio frequency offset applied equally to DL and UL */
const float offset_hz = (float) radio_h->get_freq_offset() * (1.0f - ul_dl_factor);
ret = cfo - offset_hz;
}
return ret/15000;
}
void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q, float cfo) void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q, float cfo)
{ {
if (worker_com->args->cfo_integer_enabled) { if (worker_com->args->cfo_integer_enabled) {
@ -663,11 +651,6 @@ void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q, float cfo)
srslte_sync_set_cfo_cp_enable(&q->sfind, false, 0); srslte_sync_set_cfo_cp_enable(&q->sfind, false, 0);
} }
int time_correct_period = worker_com->args->time_correct_period;
if (time_correct_period > 0) {
srslte_ue_sync_set_sample_offset_correct_period(q, time_correct_period);
}
sss_alg_t sss_alg = SSS_FULL; sss_alg_t sss_alg = SSS_FULL;
if (!worker_com->args->sss_algorithm.compare("diff")) { if (!worker_com->args->sss_algorithm.compare("diff")) {
sss_alg = SSS_DIFF; sss_alg = SSS_DIFF;
@ -689,8 +672,6 @@ bool phch_recv::set_cell() {
return false; return false;
} }
cell_is_set = false;
// Set cell in all objects // Set cell in all objects
if (srslte_ue_sync_set_cell(&ue_sync, cell)) { if (srslte_ue_sync_set_cell(&ue_sync, cell)) {
Error("SYNC: Setting cell: initiating ue_sync\n"); Error("SYNC: Setting cell: initiating ue_sync\n");
@ -714,9 +695,7 @@ bool phch_recv::set_cell() {
// Reset ue_sync and set CFO/gain from search procedure // Reset ue_sync and set CFO/gain from search procedure
srslte_ue_sync_reset(&ue_sync); srslte_ue_sync_reset(&ue_sync);
cell_is_set = true; return true;
return cell_is_set;
} }
void phch_recv::set_earfcn(std::vector<uint32_t> earfcn) { void phch_recv::set_earfcn(std::vector<uint32_t> earfcn) {
@ -864,20 +843,11 @@ void phch_recv::search::init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h,
force_N_id_2 = -1; force_N_id_2 = -1;
} }
void phch_recv::search::set_N_id_2(int N_id_2) {
force_N_id_2 = N_id_2;
}
void phch_recv::search::reset() void phch_recv::search::reset()
{ {
srslte_ue_sync_reset(&ue_mib_sync.ue_sync); srslte_ue_sync_reset(&ue_mib_sync.ue_sync);
} }
float phch_recv::search::get_last_gain()
{
return srslte_agc_get_gain(&ue_mib_sync.ue_sync.agc);
}
float phch_recv::search::get_last_cfo() float phch_recv::search::get_last_cfo()
{ {
return srslte_ue_sync_get_cfo(&ue_mib_sync.ue_sync); return srslte_ue_sync_get_cfo(&ue_mib_sync.ue_sync);
@ -1072,7 +1042,7 @@ phch_recv::sfn_sync::ret_code phch_recv::sfn_sync::run_subframe(srslte_cell_t *c
} }
} }
} else { } else {
Debug("SYNC: PSS/SSS not found...\n"); Info("SYNC: PSS/SSS not found...\n");
} }
cnt++; cnt++;
@ -1296,7 +1266,7 @@ void phch_recv::scell_recv::init(srslte::log *log_h, bool sic_pss_enabled, uint3
sf_buffer[0] = (cf_t*) srslte_vec_malloc(sizeof(cf_t)*max_sf_size); sf_buffer[0] = (cf_t*) srslte_vec_malloc(sizeof(cf_t)*max_sf_size);
if (!sf_buffer[0]) { if (!sf_buffer[0]) {
fprintf(stderr, "Error allocating %d bytes for scell\n", sizeof(cf_t)*max_sf_size); fprintf(stderr, "Error allocating %d samples for scell\n", max_sf_size);
return; return;
} }
measure_p.init(sf_buffer, log_h, 1, max_sf_window); measure_p.init(sf_buffer, log_h, 1, max_sf_window);
@ -1475,14 +1445,10 @@ int phch_recv::scell_recv::find_cells(cf_t *input_buffer, float rx_gain_offset,
void phch_recv::meas_reset() { void phch_recv::meas_reset() {
// Stop all measurements // Stop all measurements
intra_freq_meas.clear_cells(); intra_freq_meas.clear_cells();
if (worker_com) {
worker_com->pcell_meas_enabled = false;
}
} }
int phch_recv::meas_start(uint32_t earfcn, int pci) { int phch_recv::meas_start(uint32_t earfcn, int pci) {
if ((int) earfcn == current_earfcn) { if ((int) earfcn == current_earfcn) {
worker_com->pcell_meas_enabled = true;
if (pci != (int) cell.id) { if (pci != (int) cell.id) {
intra_freq_meas.add_cell(pci); intra_freq_meas.add_cell(pci);
} }

@ -164,6 +164,8 @@ bool phch_worker::set_cell(srslte_cell_t cell_)
srslte_ue_ul_set_normalization(&ue_ul, true); srslte_ue_ul_set_normalization(&ue_ul, true);
srslte_ue_ul_set_cfo_enable(&ue_ul, true); srslte_ue_ul_set_cfo_enable(&ue_ul, true);
phy->pcell_first_measurement = true;
cell_initiated = true; cell_initiated = true;
} }
ret = true; ret = true;
@ -439,33 +441,31 @@ void phch_worker::compute_ri(uint8_t *ri, uint8_t *pmi, float *sinr) {
bool phch_worker::extract_fft_and_pdcch_llr() { bool phch_worker::extract_fft_and_pdcch_llr() {
bool decode_pdcch = true; bool decode_pdcch = true;
/* Without a grant, we might need to do fft processing if need to decode PHICH */ // Do always channel estimation to keep track of out-of-sync and send measurements to RRC
if (phy->get_pending_ack(tti) || decode_pdcch) {
// Setup estimator filter
float w_coeff = phy->args->estimator_fil_w;
if (w_coeff > 0.0) {
srslte_chest_dl_set_smooth_filter3_coeff(&ue_dl.chest, w_coeff);
} else if (w_coeff == 0.0) {
srslte_chest_dl_set_smooth_filter(&ue_dl.chest, NULL, 0);
}
if (!phy->args->snr_estim_alg.compare("refs")) { // Setup estimator filter
srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_REFS); float w_coeff = phy->args->estimator_fil_w;
} else if (!phy->args->snr_estim_alg.compare("empty")) { if (w_coeff > 0.0) {
srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_EMPTY); srslte_chest_dl_set_smooth_filter3_coeff(&ue_dl.chest, w_coeff);
} else { } else if (w_coeff == 0.0) {
srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_PSS); srslte_chest_dl_set_smooth_filter(&ue_dl.chest, NULL, 0);
} }
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, tti%10, &cfi) < 0) { if (!phy->args->snr_estim_alg.compare("refs")) {
Error("Getting PDCCH FFT estimate\n"); srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_REFS);
return false; } else if (!phy->args->snr_estim_alg.compare("empty")) {
} srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_EMPTY);
chest_done = true;
} else { } else {
chest_done = false; srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_PSS);
}
if (srslte_ue_dl_decode_fft_estimate(&ue_dl, tti%10, &cfi) < 0) {
Error("Getting PDCCH FFT estimate\n");
return false;
} }
chest_done = true;
if (chest_done && decode_pdcch) { /* and not in DRX mode */ if (chest_done && decode_pdcch) { /* and not in DRX mode */
float noise_estimate = phy->avg_noise; float noise_estimate = phy->avg_noise;
@ -1427,7 +1427,8 @@ void phch_worker::update_measurements()
} else { } else {
phy->avg_rsrp_dbm = SRSLTE_VEC_EMA(rsrp_dbm, phy->avg_rsrp_dbm, snr_ema_coeff); phy->avg_rsrp_dbm = SRSLTE_VEC_EMA(rsrp_dbm, phy->avg_rsrp_dbm, snr_ema_coeff);
} }
if ((tti%phy->pcell_report_period) == 0 && phy->pcell_meas_enabled) { if ((tti%phy->pcell_report_period) == 0 || phy->pcell_first_measurement) {
phy->pcell_first_measurement = false;
phy->rrc->new_phy_meas(phy->avg_rsrp_dbm, phy->avg_rsrq_db, tti); phy->rrc->new_phy_meas(phy->avg_rsrp_dbm, phy->avg_rsrq_db, tti);
} }
} }

@ -96,7 +96,6 @@ void phy::set_default_args(phy_args_t *args)
args->equalizer_mode = "mmse"; args->equalizer_mode = "mmse";
args->cfo_integer_enabled = false; args->cfo_integer_enabled = false;
args->cfo_correct_tol_hz = 50; args->cfo_correct_tol_hz = 50;
args->time_correct_period = 5;
args->sss_algorithm = "full"; args->sss_algorithm = "full";
args->estimator_fil_w = 0.1; args->estimator_fil_w = 0.1;
} }
@ -266,8 +265,8 @@ bool phy::cell_select(phy_cell_t *cell) {
return sf_recv.cell_select(cell); return sf_recv.cell_select(cell);
} }
phy_interface_rrc::cell_search_ret_t phy::cell_search(phy_cell_t *cell, float *rsrp) { phy_interface_rrc::cell_search_ret_t phy::cell_search(phy_cell_t *cell) {
return sf_recv.cell_search(cell, rsrp); return sf_recv.cell_search(cell);
} }
bool phy::cell_is_camping() { bool phy::cell_is_camping() {

@ -248,9 +248,8 @@ void gw::run_thread()
return; return;
} }
const static uint32_t ATTACH_TIMEOUT_MS = 10000; const static uint32_t ATTACH_TIMEOUT_S = 4;
const static uint32_t ATTACH_MAX_ATTEMPTS = 3; const static uint32_t ATTACH_MAX_ATTEMPTS = 3;
uint32_t attach_cnt = 0;
uint32_t attach_attempts = 0; uint32_t attach_attempts = 0;
gw_log->info("GW IP packet receiver thread run_enable\n"); gw_log->info("GW IP packet receiver thread run_enable\n");
@ -279,16 +278,13 @@ void gw::run_thread()
gw_log->info_hex(pdu->msg, pdu->N_bytes, "TX PDU"); gw_log->info_hex(pdu->msg, pdu->N_bytes, "TX PDU");
while(run_enable && !pdcp->is_drb_enabled(cfg.lcid) && attach_attempts < ATTACH_MAX_ATTEMPTS) { while(run_enable && !pdcp->is_drb_enabled(cfg.lcid) && attach_attempts < ATTACH_MAX_ATTEMPTS) {
if (attach_cnt == 0) { gw_log->info("LCID=%d not active, requesting NAS attach (%d/%d)\n", cfg.lcid, attach_attempts, ATTACH_MAX_ATTEMPTS);
gw_log->info("LCID=%d not active, requesting NAS attach (%d/%d)\n", cfg.lcid, attach_attempts, ATTACH_MAX_ATTEMPTS); if (!nas->attach_request()) {
nas->attach_request();
attach_attempts++; attach_attempts++;
sleep(ATTACH_TIMEOUT_S);
} else {
attach_attempts = 0;
} }
attach_cnt++;
if (attach_cnt == ATTACH_TIMEOUT_MS) {
attach_cnt = 0;
}
usleep(1000);
} }
if (attach_attempts == ATTACH_MAX_ATTEMPTS) { if (attach_attempts == ATTACH_MAX_ATTEMPTS) {
@ -296,7 +292,6 @@ void gw::run_thread()
} }
attach_attempts = 0; attach_attempts = 0;
attach_cnt = 0;
if (!run_enable) { if (!run_enable) {
break; break;

@ -79,9 +79,11 @@ void nas::init(usim_interface_nas *usim_,
have_guti = true; have_guti = true;
have_ctxt = true; have_ctxt = true;
} }
running = true;
} }
void nas::stop() { void nas::stop() {
running = false;
write_ctxt_file(ctxt); write_ctxt_file(ctxt);
} }
@ -133,11 +135,10 @@ bool nas::attach_request() {
if (plmn_is_selected) { if (plmn_is_selected) {
rrc->plmn_select(current_plmn); rrc->plmn_select(current_plmn);
if (rrc_connect()) { if (rrc_connect()) {
nas_log->info("RRC connection established. Sending NAS attach request\n"); nas_log->info("NAS attached successfully.\n");
if (attach(false)) { return true;
nas_log->info("NAS attached successfully.\n"); } else {
return true; nas_log->error("Could not attach\n");
}
} }
} else { } else {
nas_log->error("PLMN is not selected because no suitable PLMN was found\n"); nas_log->error("PLMN is not selected because no suitable PLMN was found\n");
@ -150,11 +151,9 @@ bool nas::attach_request() {
} else { } else {
nas_log->info("NAS is already registered but RRC disconnected. Connecting now...\n"); nas_log->info("NAS is already registered but RRC disconnected. Connecting now...\n");
if (rrc_connect()) { if (rrc_connect()) {
nas_log->info("RRC connection established. Sending NAS attach request\n"); nas_log->info("NAS attached successfully.\n");
if (attach(true)) { } else {
nas_log->info("NAS attached successfully.\n"); nas_log->error("Could not attach\n");
return true;
}
} }
} }
break; break;
@ -179,21 +178,17 @@ void nas::paging(LIBLTE_RRC_S_TMSI_STRUCT *ue_identiy) {
if (state == EMM_STATE_REGISTERED) { if (state == EMM_STATE_REGISTERED) {
nas_log->info("Received paging: requesting RRC connection establishment\n"); nas_log->info("Received paging: requesting RRC connection establishment\n");
if (rrc_connect()) { if (rrc_connect()) {
nas_log->info("Connected successfully. Initiating service request\n"); nas_log->info("Attached successfully\n");
if (attach(true)) {
nas_log->info("Attached successfully\n");
} else {
nas_log->error("Could not attach\n");
}
} else { } else {
nas_log->error("Could not establish RRC connection\n"); nas_log->error("Could not attach\n");
} }
} else {
nas_log->warning("Received paging while in state %s\n", emm_state_text[state]);
} }
} }
void nas::rrc_connection_failure() { void nas::set_barring(barring_t barring) {
nas_log->debug("Received RRC Connection Failure\n"); current_barring = barring;
rrc_connection_is_failure = true;
} }
/* Internal function that requests RRC connection, waits for positive or negative response and returns true/false /* Internal function that requests RRC connection, waits for positive or negative response and returns true/false
@ -203,54 +198,49 @@ bool nas::rrc_connect() {
nas_log->info("Already connected\n"); nas_log->info("Already connected\n");
return true; return true;
} }
uint32_t tout;
rrc_connection_is_failure = false; // Generate service request or attach request message
if (rrc->connection_request()) { byte_buffer_t *dedicatedInfoNAS = pool_allocate;
// Wait until RRCConnected or connection error if (state == EMM_STATE_REGISTERED) {
tout = 0; gen_service_request(dedicatedInfoNAS);
while (tout < 10000 && !rrc->is_connected() && !rrc_connection_is_failure) {
usleep(1000);
tout++;
}
if (rrc->is_connected()) {
rrc_connection_is_failure = false;
return true;
} else if (rrc_connection_is_failure) {
nas_log->info("Failed to establish RRC connection\n");
} else {
nas_log->error("Timed out while establishing RRC connection (%d s)\n", tout/1000);
}
} else { } else {
nas_log->warning("Could initiate RRC connection request\n"); gen_attach_request(dedicatedInfoNAS);
} }
return false;
}
/* Internal function that requests NAS attach, waits for positive or negative response and returns true/false
*/
bool nas::attach(bool is_service_req) {
uint32_t tout;
if (is_service_req) { // Provide UE-Identity to RRC if have one
send_service_request(); if (have_guti) {
} else { LIBLTE_RRC_S_TMSI_STRUCT s_tmsi;
send_attach_request(); s_tmsi.mmec = ctxt.guti.mme_code;
s_tmsi.m_tmsi = ctxt.guti.m_tmsi;
rrc->set_ue_idenity(s_tmsi);
} }
state = EMM_STATE_REGISTERED_INITIATED; // Set establishment cause
LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM establish_cause = LIBLTE_RRC_CON_REQ_EST_CAUSE_MO_SIGNALLING;
// Wait until NAS is registered if (rrc->connection_request(establish_cause, dedicatedInfoNAS))
tout = 0; {
while (tout < 10000 && state == EMM_STATE_REGISTERED_INITIATED) { nas_log->info("Connection established correctly. Waiting for Attach\n");
usleep(1000);
tout++; // Wait until attachment. If doing a service request is already attached
} uint32_t tout = 0;
if (state == EMM_STATE_REGISTERED) { while (tout < 5000 && state != EMM_STATE_REGISTERED && running && rrc->is_connected()) {
return true; usleep(1000);
} else if (state == EMM_STATE_DEREGISTERED) { tout++;
nas_log->error("Received attach reject while trying to attach\n"); }
if (state == EMM_STATE_REGISTERED) {
nas_log->info("EMM Registered correctly\n");
return true;
} else if (state == EMM_STATE_DEREGISTERED) {
nas_log->error("Received attach reject while trying to attach\n");
nas_log->console("Failed to Attach\n");
} else if (!rrc->is_connected()) {
nas_log->error("Was disconnected while attaching\n");
} else {
nas_log->error("Timed out while trying to attach\n");
}
} else { } else {
nas_log->error("Timed out while trying to attach\n"); nas_log->error("Could not establish RRC connection\n");
} }
return false; return false;
} }
@ -362,16 +352,6 @@ uint32_t nas::get_ul_count() {
return ctxt.tx_count; return ctxt.tx_count;
} }
bool nas::get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) {
if (have_guti) {
s_tmsi->mmec = ctxt.guti.mme_code;
s_tmsi->m_tmsi = ctxt.guti.m_tmsi;
return true;
} else {
return false;
}
}
bool nas::get_k_asme(uint8_t *k_asme_, uint32_t n) { bool nas::get_k_asme(uint8_t *k_asme_, uint32_t n) {
if(!have_ctxt) { if(!have_ctxt) {
nas_log->error("K_asme requested before security context established\n"); nas_log->error("K_asme requested before security context established\n");
@ -560,6 +540,11 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) {
if (attach_accept.guti_present) { if (attach_accept.guti_present) {
memcpy(&ctxt.guti, &attach_accept.guti.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT)); memcpy(&ctxt.guti, &attach_accept.guti.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT));
have_guti = true; have_guti = true;
// Update RRC UE-Idenity
LIBLTE_RRC_S_TMSI_STRUCT s_tmsi;
s_tmsi.mmec = ctxt.guti.mme_code;
s_tmsi.m_tmsi = ctxt.guti.m_tmsi;
rrc->set_ue_idenity(s_tmsi);
} }
if (attach_accept.lai_present) {} if (attach_accept.lai_present) {}
if (attach_accept.ms_id_present) {} if (attach_accept.ms_id_present) {}
@ -896,19 +881,18 @@ void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) {
* Senders * Senders
******************************************************************************/ ******************************************************************************/
void nas::send_attach_request() { void nas::gen_attach_request(byte_buffer_t *msg) {
LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT attach_req;
byte_buffer_t *msg = pool_allocate;
if (!msg) { if (!msg) {
nas_log->error("Fatal Error: Couldn't allocate PDU in send_attach_request().\n"); nas_log->error("Fatal Error: Couldn't allocate PDU in gen_attach_request().\n");
return; return;
} }
LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT attach_req;
u_int32_t i; nas_log->info("Generating attach request\n");
attach_req.eps_attach_type = LIBLTE_MME_EPS_ATTACH_TYPE_EPS_ATTACH; attach_req.eps_attach_type = LIBLTE_MME_EPS_ATTACH_TYPE_EPS_ATTACH;
for (i = 0; i < 8; i++) { for (u_int32_t i = 0; i < 8; i++) {
attach_req.ue_network_cap.eea[i] = eea_caps[i]; attach_req.ue_network_cap.eea[i] = eea_caps[i];
attach_req.ue_network_cap.eia[i] = eia_caps[i]; attach_req.ue_network_cap.eia[i] = eia_caps[i];
} }
@ -967,14 +951,47 @@ void nas::send_attach_request() {
pcap->write_nas(msg->msg, msg->N_bytes); pcap->write_nas(msg->msg, msg->N_bytes);
} }
nas_log->info("Sending attach request\n");
rrc->write_sdu(cfg.lcid, msg);
if (have_ctxt) { if (have_ctxt) {
ctxt.tx_count++; ctxt.tx_count++;
} }
} }
void nas::gen_service_request(byte_buffer_t *msg) {
if (!msg) {
nas_log->error("Fatal Error: Couldn't allocate PDU in gen_service_request().\n");
return;
}
nas_log->info("Generating service request\n");
// Pack the service request message directly
msg->msg[0] = (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);
msg->N_bytes++;
msg->msg[1] = (ctxt.ksi & 0x07) << 5;
msg->msg[1] |= ctxt.tx_count & 0x1F;
msg->N_bytes++;
uint8_t mac[4];
integrity_generate(&k_nas_int[16],
ctxt.tx_count,
SECURITY_DIRECTION_UPLINK,
&msg->msg[0],
2,
&mac[0]);
// Set the short MAC
msg->msg[2] = mac[2];
msg->N_bytes++;
msg->msg[3] = mac[3];
msg->N_bytes++;
if(pcap != NULL) {
pcap->write_nas(msg->msg, msg->N_bytes);
}
ctxt.tx_count++;
}
void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) { void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) {
LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT pdn_con_req; LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT pdn_con_req;
@ -1022,42 +1039,6 @@ void nas::send_security_mode_reject(uint8_t cause) {
void nas::send_identity_response() {} void nas::send_identity_response() {}
void nas::send_service_request() {
byte_buffer_t *msg = pool_allocate;
if (!msg) {
nas_log->error("Fatal Error: Couldn't allocate PDU in send_service_request().\n");
return;
}
// Pack the service request message directly
msg->msg[0] = (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT);
msg->N_bytes++;
msg->msg[1] = (ctxt.ksi & 0x07) << 5;
msg->msg[1] |= ctxt.tx_count & 0x1F;
msg->N_bytes++;
uint8_t mac[4];
integrity_generate(&k_nas_int[16],
ctxt.tx_count,
SECURITY_DIRECTION_UPLINK,
&msg->msg[0],
2,
&mac[0]);
// Set the short MAC
msg->msg[2] = mac[2];
msg->N_bytes++;
msg->msg[3] = mac[3];
msg->N_bytes++;
if(pcap != NULL) {
pcap->write_nas(msg->msg, msg->N_bytes);
}
nas_log->info("Sending service request\n");
rrc->write_sdu(cfg.lcid, msg);
ctxt.tx_count++;
}
void nas::send_esm_information_response() {} void nas::send_esm_information_response() {}

@ -110,10 +110,14 @@ void rrc::init(phy_interface_rrc *phy_,
t300 = mac_timers->timer_get_unique_id(); t300 = mac_timers->timer_get_unique_id();
t301 = mac_timers->timer_get_unique_id(); t301 = mac_timers->timer_get_unique_id();
t302 = mac_timers->timer_get_unique_id();
t310 = mac_timers->timer_get_unique_id(); t310 = mac_timers->timer_get_unique_id();
t311 = mac_timers->timer_get_unique_id(); t311 = mac_timers->timer_get_unique_id();
t304 = mac_timers->timer_get_unique_id(); t304 = mac_timers->timer_get_unique_id();
dedicatedInfoNAS = NULL;
ueIdentity_configured = false;
transaction_id = 0; transaction_id = 0;
// Register logging handler with liblte_rrc // Register logging handler with liblte_rrc
@ -167,38 +171,71 @@ void rrc::run_tti(uint32_t tti) {
return; return;
} }
rrc_log->debug("State %s\n", rrc_state_text[state]); /* We can not block in this thread because it is called from
switch(state) { * the MAC TTI timer and needs to return immediatly to perform other
case RRC_STATE_IDLE: * tasks. Therefore in this function we use trylock() instead of lock() and
// If attached but not camping on the cell, perform cell reselection * skip function if currently locked, since none of the functions here is urgent
if (nas->is_attached()) { */
rrc_log->info("Running cell selection and reselection in IDLE\n"); if (!pthread_mutex_trylock(&mutex)) {
if (!cell_selection()) {
// If can not camp on any cell, search again for new cells // Process pending PHY measurements in IDLE/CONNECTED
cell_search(); process_phy_meas();
// Run state machine
rrc_log->debug("State %s\n", rrc_state_text[state]);
switch (state) {
case RRC_STATE_IDLE:
/* CAUTION: The execution of cell_search() and cell_selection() take more than 1 ms
* and will slow down MAC TTI ticks. This has no major effect at the moment because
* the UE is in IDLE but we could consider splitting MAC and RRC threads to avoid this
*/
// If attached but not camping on the cell, perform cell reselection
if (nas->is_attached()) {
rrc_log->debug("Running cell selection and reselection in IDLE\n");
if (!cell_selection()) {
if (!serving_cell->in_sync) {
rrc_log->info("Cell selection and reselection in IDLE did not find any suitable cell. Searching again\n");
// If can not camp on any cell, search again for new cells
phy_interface_rrc::cell_search_ret_t ret = cell_search();
// TODO: Should not camp on it until we have checked is a valid PLMN
if (ret.found == phy_interface_rrc::cell_search_ret_t::CELL_FOUND) {
// New cell has been selected, start receiving PCCH
mac->pcch_start_rx();
}
}
} else {
// New cell has been selected, start receiving PCCH
mac->pcch_start_rx();
}
} }
} break;
break; case RRC_STATE_CONNECTED:
case RRC_STATE_CONNECTED: if (ho_start) {
if (ho_start) { ho_start = false;
ho_start = false; if (!ho_prepare()) {
if (!ho_prepare()) { con_reconfig_failed();
con_reconfig_failed(); }
} }
} measurements.run_tti(tti);
measurements.run_tti(tti); if (go_idle) {
if (go_idle) { go_idle = false;
leave_connected(); leave_connected();
} }
break; break;
default: default:break;
break; }
}
cell_clean_cnt++; // Clean old neighbours
if (cell_clean_cnt==1000) { cell_clean_cnt++;
clean_neighbours(); if (cell_clean_cnt == 1000) {
cell_clean_cnt = 0; clean_neighbours();
} cell_clean_cnt = 0;
}
pthread_mutex_unlock(&mutex);
} // Skip TTI if mutex is locked
} }
@ -244,7 +281,7 @@ int rrc::plmn_search(found_plmn_t found_plmns[MAX_FOUND_PLMNS])
phy_interface_rrc::cell_search_ret_t ret; phy_interface_rrc::cell_search_ret_t ret;
do { do {
ret = cell_search(); ret = cell_search();
if (ret == phy_interface_rrc::CELL_FOUND) { if (ret.found == phy_interface_rrc::cell_search_ret_t::CELL_FOUND) {
if (serving_cell->has_sib1()) { if (serving_cell->has_sib1()) {
// Save PLMN and TAC to NAS // Save PLMN and TAC to NAS
for (uint32_t i = 0; i < serving_cell->nof_plmns(); i++) { for (uint32_t i = 0; i < serving_cell->nof_plmns(); i++) {
@ -260,11 +297,15 @@ int rrc::plmn_search(found_plmn_t found_plmns[MAX_FOUND_PLMNS])
rrc_log->error("SIB1 not acquired\n"); rrc_log->error("SIB1 not acquired\n");
} }
} }
} while (ret == phy_interface_rrc::CELL_NOT_FOUND || ret == phy_interface_rrc::CELL_FOUND); } while (ret.last_freq == phy_interface_rrc::cell_search_ret_t::MORE_FREQS &&
ret.found != phy_interface_rrc::cell_search_ret_t::ERROR);
// Process all pending measurements before returning
process_phy_meas();
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
if (ret == phy_interface_rrc::ERROR) { if (ret.found == phy_interface_rrc::cell_search_ret_t::ERROR) {
return -1; return -1;
} else { } else {
return nof_plmns; return nof_plmns;
@ -277,6 +318,8 @@ int rrc::plmn_search(found_plmn_t found_plmns[MAX_FOUND_PLMNS])
void rrc::plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) { void rrc::plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) {
plmn_is_selected = true; plmn_is_selected = true;
selected_plmn_id = plmn_id; selected_plmn_id = plmn_id;
rrc_log->info("PLMN Selected %s\n", plmn_id_to_string(plmn_id).c_str());
} }
/* 5.3.3.2 Initiation of RRC Connection Establishment procedure /* 5.3.3.2 Initiation of RRC Connection Establishment procedure
@ -287,7 +330,9 @@ void rrc::plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) {
* it. Sends connectionRequest message and returns if message transmitted successfully. * it. Sends connectionRequest message and returns if message transmitted successfully.
* It does not wait until completition of Connection Establishment procedure * It does not wait until completition of Connection Establishment procedure
*/ */
bool rrc::connection_request() { bool rrc::connection_request(LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM cause,
srslte::byte_buffer_t *dedicatedInfoNAS)
{
if (!plmn_is_selected) { if (!plmn_is_selected) {
rrc_log->error("Trying to connect but PLMN not selected.\n"); rrc_log->error("Trying to connect but PLMN not selected.\n");
@ -295,7 +340,13 @@ bool rrc::connection_request() {
} }
if (state != RRC_STATE_IDLE) { if (state != RRC_STATE_IDLE) {
rrc_log->warning("Requested RRC connection establishment while in state %s\n", rrc_state_text[state]); rrc_log->warning("Requested RRC connection establishment while not in IDLE\n");
return false;
}
if (mac_timers->timer_get(t302)->is_running()) {
rrc_log->info("Requested RRC connection establishment while T302 is running\n");
nas->set_barring(nas_interface_rrc::BARRING_MO_DATA);
return false; return false;
} }
@ -303,16 +354,13 @@ bool rrc::connection_request() {
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
// Perform cell re-selection rrc_log->info("Initiation of Connection establishment procedure\n");
int cnt = 0;
while(!(serving_cell->plmn_equals(selected_plmn_id) && phy->cell_is_camping()) && cnt<10) { // Perform cell selection & reselection for the selected PLMN
rrc_log->info("Not camping on any suitable cell. Selecting another cell\n"); cell_selection();
cell_selection();
cnt++;
}
// .. and SI acquisition // .. and SI acquisition
if (cnt<10) { if (phy->cell_is_camping()) {
// Set default configurations // Set default configurations
set_phy_default(); set_phy_default();
@ -327,9 +375,37 @@ bool rrc::connection_request() {
mac_timers->timer_get(t300)->reset(); mac_timers->timer_get(t300)->reset();
mac_timers->timer_get(t300)->run(); mac_timers->timer_get(t300)->run();
rrc_log->info("Sending ConnectionRequest\n"); // Send connectionRequest message to lower layers
send_con_request(); send_con_request(cause);
ret = true;
// Save dedicatedInfoNAS SDU
if (this->dedicatedInfoNAS) {
rrc_log->warning("Received a new dedicatedInfoNAS SDU but there was one still in queue. Removing it\n");
pool->deallocate(this->dedicatedInfoNAS);
}
this->dedicatedInfoNAS = dedicatedInfoNAS;
// Wait until t300 stops due to RRCConnectionSetup/Reject or expiry
while (mac_timers->timer_get(t300)->is_running()) {
usleep(1000);
}
if (state == RRC_STATE_CONNECTED) {
// Received ConnectionSetup
ret = true;
} else if (mac_timers->timer_get(t300)->is_expired()) {
// T300 is expired: 5.3.3.6
rrc_log->info("Timer T300 expired: ConnectionRequest timed out\n");
mac->reset();
set_mac_default();
rlc->reestablish();
} else {
// T300 is stopped but RRC not Connected is because received Reject: Section 5.3.3.8
rrc_log->info("Timer T300 stopped: Received ConnectionReject\n");
mac->reset();
set_mac_default();
}
} else { } else {
rrc_log->error("Configuring serving cell\n"); rrc_log->error("Configuring serving cell\n");
} }
@ -341,6 +417,12 @@ bool rrc::connection_request() {
return ret; return ret;
} }
void rrc::set_ue_idenity(LIBLTE_RRC_S_TMSI_STRUCT s_tmsi) {
ueIdentity_configured = true;
ueIdentity = s_tmsi;
rrc_log->info("Set ue-Identity to 0x%x:0x%x\n", ueIdentity.mmec, ueIdentity.m_tmsi);
}
/* Retrieves all required SIB or configures them if already retrieved before /* Retrieves all required SIB or configures them if already retrieved before
*/ */
bool rrc::configure_serving_cell() { bool rrc::configure_serving_cell() {
@ -349,15 +431,20 @@ bool rrc::configure_serving_cell() {
rrc_log->error("Trying to configure Cell while not camping on it\n"); rrc_log->error("Trying to configure Cell while not camping on it\n");
return false; return false;
} }
// Apply configurations if already retrieved SIB2
if (serving_cell->has_sib2()) {
apply_sib2_configs(serving_cell->sib2ptr());
}
// Obtain the rest of required SIBs (configuration is applied when received)
for (uint32_t i = 0; i < NOF_REQUIRED_SIBS; i++) { for (uint32_t i = 0; i < NOF_REQUIRED_SIBS; i++) {
if (!serving_cell->has_sib(i)) { if (!serving_cell->has_sib(i)) {
rrc_log->info("Cell has no SIB%d. Obtaining SIB%d\n", i+1, i+1);
if (!si_acquire(i)) { if (!si_acquire(i)) {
rrc_log->info("Timeout while acquiring SIB%d\n", i + 1); rrc_log->info("Timeout while acquiring SIB%d\n", i+1);
return false; return false;
} }
} else if (i == 1) { } else {
// Re-apply SIB2 configuration acquired previously rrc_log->info("Cell has SIB%d\n", i+1);
apply_sib2_configs(serving_cell->sib2ptr());
} }
} }
return true; return true;
@ -378,19 +465,41 @@ bool rrc::configure_serving_cell() {
* *
*******************************************************************************/ *******************************************************************************/
/* This function is called from a PHY worker thus must return very quickly.
* Queue the values of the measurements and process them from the RRC thread
*/
void rrc::new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn_i, int pci_i) { void rrc::new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn_i, int pci_i) {
if (earfcn_i < 0) {
earfcn_i = (int) serving_cell->get_earfcn();
}
if (pci_i < 0) {
pci_i = (int) serving_cell->get_pci();
}
pthread_mutex_lock(&mutex); phy_meas_t new_meas = {rsrp, rsrq, tti, (uint32_t) earfcn_i, (uint32_t) pci_i};
phy_meas_q.push(new_meas);
rrc_log->info("MEAS: New measurement pci=%d, rsrp=%.1f dBm.\n", pci_i, rsrp);
}
if (earfcn_i < 0 || pci_i < 0) { /* Processes all pending PHY measurements in queue. Must be called from a mutexed function
earfcn_i = serving_cell->get_earfcn(); */
pci_i = serving_cell->get_pci(); void rrc::process_phy_meas() {
while(!phy_meas_q.empty()) {
rrc_log->debug("MEAS: Processing measurement. %d measurements in queue\n", phy_meas_q.size());
process_new_phy_meas(phy_meas_q.front());
phy_meas_q.pop();
} }
}
uint32_t earfcn = (uint32_t) earfcn_i; void rrc::process_new_phy_meas(phy_meas_t meas)
uint32_t pci = (uint32_t) pci_i; {
float rsrp = meas.rsrp;
float rsrq = meas.rsrq;
uint32_t tti = meas.tti;
uint32_t earfcn = meas.earfcn;
uint32_t pci = meas.pci;
// Measurements in RRC_CONNECTED go through measuremnt class to log reports etc. // Measurements in RRC_CONNECTED go through measurement class to log reports etc.
if (state != RRC_STATE_IDLE) { if (state != RRC_STATE_IDLE) {
measurements.new_phy_meas(earfcn, pci, rsrp, rsrq, tti); measurements.new_phy_meas(earfcn, pci, rsrp, rsrq, tti);
@ -399,24 +508,20 @@ void rrc::new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn_i, int p
// Update serving cell // Update serving cell
if (serving_cell->equals(earfcn, pci)) { if (serving_cell->equals(earfcn, pci)) {
cell_reselection(rsrp, rsrq);
serving_cell->set_rsrp(rsrp); serving_cell->set_rsrp(rsrp);
rrc_log->info("MEAS: New measurement serving cell in IDLE, rsrp=%f, rsrq=%f, tti=%d\n", rsrp, rsrq, tti);
// Or update/add neighbour cell // Or update/add neighbour cell
} else { } else {
if (add_neighbour_cell(earfcn, pci, rsrp)) { add_neighbour_cell(earfcn, pci, rsrp);
rrc_log->info("MEAS: New measurement neighbour in IDLE, PCI=%d, RSRP=%.1f dBm.\n", pci, rsrp);
} else {
rrc_log->info("MEAS: Neighbour Cell in IDLE PCI=%d, RSRP=%.1f dBm not added. Worse than current neighbours\n", pci, rsrp);
}
} }
} }
pthread_mutex_unlock(&mutex);
} }
// Detection of physical layer problems in RRC_CONNECTED (5.3.11.1) // Detection of physical layer problems in RRC_CONNECTED (5.3.11.1)
void rrc::out_of_sync() { void rrc::out_of_sync()
{
// CAUTION: We do not lock in this function since they are called from real-time threads
serving_cell->in_sync = false; serving_cell->in_sync = false;
rrc_log->info("Received out-of-sync while in state %s. n310=%d, t311=%s, t310=%s\n", rrc_log->info("Received out-of-sync while in state %s. n310=%d, t311=%s, t310=%s\n",
rrc_state_text[state], n310_cnt, rrc_state_text[state], n310_cnt,
@ -433,17 +538,15 @@ void rrc::out_of_sync() {
n310_cnt = 0; n310_cnt = 0;
} }
} }
} else {
if (!mac_timers->timer_get(t311)->is_running()) {
rrc_log->info("Detected out-of-sync while in IDLE\n");
} else {
rrc_log->info("Detected out-of-sync while in IDLE and T311 running\n");
}
} }
} }
// Recovery of physical layer problems (5.3.11.2) // Recovery of physical layer problems (5.3.11.2)
void rrc::in_sync() { void rrc::in_sync()
{
// CAUTION: We do not lock in this function since they are called from real-time threads
serving_cell->in_sync = true; serving_cell->in_sync = true;
if (mac_timers->timer_get(t310)->is_running()) { if (mac_timers->timer_get(t310)->is_running()) {
n311_cnt++; n311_cnt++;
@ -582,41 +685,37 @@ bool rrc::si_acquire(uint32_t sib_index)
phy_interface_rrc::cell_search_ret_t rrc::cell_search() phy_interface_rrc::cell_search_ret_t rrc::cell_search()
{ {
phy_interface_rrc::phy_cell_t new_cell; phy_interface_rrc::phy_cell_t new_cell;
float rsrp;
phy_interface_rrc::cell_search_ret_t ret = phy->cell_search(&new_cell, &rsrp); phy_interface_rrc::cell_search_ret_t ret = phy->cell_search(&new_cell);
switch(ret) { switch(ret.found) {
case phy_interface_rrc::CELL_FOUND: case phy_interface_rrc::cell_search_ret_t::CELL_FOUND:
rrc_log->info("Cell found in this frequency. Setting new serving cell...\n"); rrc_log->info("Cell found in this frequency. Setting new serving cell...\n");
if (!add_neighbour_cell(new_cell, rsrp)) { // Create cell with NaN RSRP. Will be updated by new_phy_meas() during SIB search.
rrc_log->info("No more space for neighbour cells (detected cell RSRP=%.1f dBm worse than current %d neighbours)\n", rsrp, NOF_NEIGHBOUR_CELLS); if (!add_neighbour_cell(new_cell, NAN)) {
rrc_log->info("No more space for neighbour cells\n");
break; break;
} }
set_serving_cell(new_cell); set_serving_cell(new_cell);
rrc_log->info("Camping on cell...\n"); if (phy->cell_is_camping()) {
if (phy->cell_select(&new_cell)) {
if (!serving_cell->has_sib1()) { if (!serving_cell->has_sib1()) {
rrc_log->info("Camping OK. Obtaining SIB1\n"); rrc_log->info("Cell has no SIB1. Obtaining SIB1\n");
if (!si_acquire(0)) { if (!si_acquire(0)) {
rrc_log->error("Timeout while acquiring SIB1\n"); rrc_log->error("Timeout while acquiring SIB1\n");
} }
} else { } else {
rrc_log->info("Camping OK. Already has SIB1\n"); rrc_log->info("Cell has SIB1\n");
} }
} else { } else {
rrc_log->warning("Could not camp on found cell. Trying next one...\n"); rrc_log->warning("Could not camp on found cell. Trying next one...\n");
} }
break; break;
case phy_interface_rrc::CELL_NOT_FOUND: case phy_interface_rrc::cell_search_ret_t::CELL_NOT_FOUND:
rrc_log->info("No cells found. Trying next frequency\n"); rrc_log->info("No cells found.\n");
break; break;
case phy_interface_rrc::NO_MORE_FREQS: case phy_interface_rrc::cell_search_ret_t::ERROR:
rrc_log->info("Finished searching for cells in current EARFCN set\n");
break;
case phy_interface_rrc::ERROR:
rrc_log->error("In cell search. Finishing PLMN search\n"); rrc_log->error("In cell search. Finishing PLMN search\n");
break; break;
} }
@ -774,8 +873,6 @@ void rrc::clean_neighbours()
struct timeval now; struct timeval now;
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
pthread_mutex_lock(&mutex);
std::vector<cell_t*>::iterator it = neighbour_cells.begin(); std::vector<cell_t*>::iterator it = neighbour_cells.begin();
while(it != neighbour_cells.end()) { while(it != neighbour_cells.end()) {
if ((*it)->timeout_secs(now) > NEIGHBOUR_TIMEOUT) { if ((*it)->timeout_secs(now) > NEIGHBOUR_TIMEOUT) {
@ -785,7 +882,6 @@ void rrc::clean_neighbours()
++it; ++it;
} }
} }
pthread_mutex_unlock(&mutex);
} }
// Sort neighbour cells by decreasing order of RSRP // Sort neighbour cells by decreasing order of RSRP
@ -807,7 +903,7 @@ void rrc::sort_neighbour_cells()
if (neighbour_cells.size() > 0) { if (neighbour_cells.size() > 0) {
char ordered[512]; char ordered[512];
int n=0; int n=0;
n += snprintf(ordered, 512, "[pci=%d, rsrsp=%.2f", neighbour_cells[0]->phy_cell.cell.id, neighbour_cells[0]->get_rsrp()); n += snprintf(ordered, 512, "[pci=%d, rsrp=%.2f", neighbour_cells[0]->phy_cell.cell.id, neighbour_cells[0]->get_rsrp());
for (uint32_t i=1;i<neighbour_cells.size();i++) { for (uint32_t i=1;i<neighbour_cells.size();i++) {
n += snprintf(&ordered[n], 512-n, " | pci=%d, rsrp=%.2f", neighbour_cells[i]->get_pci(), neighbour_cells[i]->get_rsrp()); n += snprintf(&ordered[n], 512-n, " | pci=%d, rsrp=%.2f", neighbour_cells[i]->get_pci(), neighbour_cells[i]->get_rsrp());
} }
@ -854,8 +950,8 @@ bool rrc::add_neighbour_cell(phy_interface_rrc::phy_cell_t phy_cell, float rsrp)
rrc_log->info("Adding PCI=%d, earfcn=%d, cell_idx=%d\n", phy_cell.cell.id, phy_cell.earfcn, cell_idx); rrc_log->info("Adding PCI=%d, earfcn=%d, cell_idx=%d\n", phy_cell.cell.id, phy_cell.earfcn, cell_idx);
// If exists, update RSRP, sort again and return // If exists, update RSRP if provided, sort again and return
if (cell_idx >= 0) { if (cell_idx >= 0 && isnormal(rsrp)) {
neighbour_cells[cell_idx]->set_rsrp(rsrp); neighbour_cells[cell_idx]->set_rsrp(rsrp);
sort_neighbour_cells(); sort_neighbour_cells();
return true; return true;
@ -934,13 +1030,11 @@ void rrc::timer_expired(uint32_t timeout_id) {
rrc_log->info("Timer T301 expired: Going to RRC IDLE\n"); rrc_log->info("Timer T301 expired: Going to RRC IDLE\n");
go_idle = true; go_idle = true;
} }
} else if (timeout_id == t302) {
rrc_log->info("Timer T302 expired. Informing NAS about barrier alleviation\n");
nas->set_barring(nas_interface_rrc::BARRING_NONE);
} else if (timeout_id == t300) { } else if (timeout_id == t300) {
// 5.3.3.6 // Do nothing, handled in connection_request()
rrc_log->info("Timer T300 expired: ConnectionRequest timed out\n");
mac->reset();
set_mac_default();
rlc->reestablish();
nas->rrc_connection_failure();
} else if (timeout_id == t304) { } else if (timeout_id == t304) {
rrc_log->console("Timer T304 expired: Handover failed\n"); rrc_log->console("Timer T304 expired: Handover failed\n");
ho_failed(); ho_failed();
@ -967,16 +1061,16 @@ void rrc::timer_expired(uint32_t timeout_id) {
* *
*******************************************************************************/ *******************************************************************************/
void rrc::send_con_request() { void rrc::send_con_request(LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM cause) {
rrc_log->debug("Preparing RRC Connection Request\n"); rrc_log->debug("Preparing RRC Connection Request\n");
LIBLTE_RRC_S_TMSI_STRUCT s_tmsi;
// Prepare ConnectionRequest packet // Prepare ConnectionRequest packet
ul_ccch_msg.msg_type = LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REQ; ul_ccch_msg.msg_type = LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REQ;
if (nas->get_s_tmsi(&s_tmsi)) { if (ueIdentity_configured) {
ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_S_TMSI; ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_S_TMSI;
ul_ccch_msg.msg.rrc_con_req.ue_id.s_tmsi = s_tmsi; ul_ccch_msg.msg.rrc_con_req.ue_id.s_tmsi.m_tmsi = ueIdentity.m_tmsi;
ul_ccch_msg.msg.rrc_con_req.ue_id.s_tmsi.mmec = ueIdentity.mmec;
} else { } else {
ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_RANDOM_VALUE; ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_RANDOM_VALUE;
// TODO use proper RNG // TODO use proper RNG
@ -987,10 +1081,9 @@ void rrc::send_con_request() {
ul_ccch_msg.msg.rrc_con_req.ue_id.random = random_id; ul_ccch_msg.msg.rrc_con_req.ue_id.random = random_id;
} }
ul_ccch_msg.msg.rrc_con_req.cause = LIBLTE_RRC_CON_REQ_EST_CAUSE_MO_SIGNALLING; ul_ccch_msg.msg.rrc_con_req.cause = cause;
send_ul_ccch_msg(); send_ul_ccch_msg();
} }
/* RRC connection re-establishment procedure (5.3.7) */ /* RRC connection re-establishment procedure (5.3.7) */
@ -1067,24 +1160,29 @@ void rrc::send_con_restablish_request(LIBLTE_RRC_CON_REEST_REQ_CAUSE_ENUM cause)
set_mac_default(); set_mac_default();
// Perform cell selection in accordance to 36.304 // Perform cell selection in accordance to 36.304
if (cell_selection()) { if (cell_selection_criteria(serving_cell->get_rsrp()) && serving_cell->in_sync) {
if (phy->cell_select(&serving_cell->phy_cell)) {
if (mac_timers->timer_get(t311)->is_running()) {
// Actions following cell reselection while T311 is running 5.3.7.3 if (mac_timers->timer_get(t311)->is_running()) {
rrc_log->info("Cell Selection finished. Initiating transmission of RRC Connection Reestablishment Request\n"); // Actions following cell reselection while T311 is running 5.3.7.3
liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf); rrc_log->info("Cell Selection finished. Initiating transmission of RRC Connection Reestablishment Request\n");
liblte_rrc_pack_ul_ccch_msg(&ul_ccch_msg, (LIBLTE_BIT_MSG_STRUCT *) &bit_buf);
mac_timers->timer_get(t301)->reset();
mac_timers->timer_get(t301)->run(); mac_timers->timer_get(t301)->reset();
mac_timers->timer_get(t311)->stop(); mac_timers->timer_get(t301)->run();
send_ul_ccch_msg(); mac_timers->timer_get(t311)->stop();
send_ul_ccch_msg();
} else {
rrc_log->info("T311 expired while selecting cell. Going to IDLE\n");
go_idle = true;
}
} else { } else {
go_idle = true; rrc_log->warning("Could not re-synchronize with cell.\n");
} }
} else { } else {
rrc_log->warning("Could not re-synchronize with cell.\n"); rrc_log->info("Selected cell no longer suitable for camping. Going to IDLE\n");
go_idle = true;
} }
} }
void rrc::send_con_restablish_complete() { void rrc::send_con_restablish_complete() {
@ -1102,9 +1200,6 @@ void rrc::send_con_restablish_complete() {
void rrc::send_con_setup_complete(byte_buffer_t *nas_msg) { void rrc::send_con_setup_complete(byte_buffer_t *nas_msg) {
rrc_log->debug("Preparing RRC Connection Setup Complete\n"); rrc_log->debug("Preparing RRC Connection Setup Complete\n");
state = RRC_STATE_CONNECTED;
rrc_log->console("RRC Connected\n");
// Prepare ConnectionSetupComplete packet // Prepare ConnectionSetupComplete packet
ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_SETUP_COMPLETE; ul_dcch_msg.msg_type = LIBLTE_RRC_UL_DCCH_MSG_TYPE_RRC_CON_SETUP_COMPLETE;
ul_dcch_msg.msg.rrc_con_setup_complete.registered_mme_present = false; ul_dcch_msg.msg.rrc_con_setup_complete.registered_mme_present = false;
@ -1179,7 +1274,7 @@ bool rrc::ho_prepare() {
ho_src_rnti = uernti.crnti; ho_src_rnti = uernti.crnti;
// Reset/Reestablish stack // Reset/Reestablish stack
mac->bcch_stop_rx(); // FIXME: change function name mac->clear_rntis();
phy->meas_reset(); phy->meas_reset();
mac->wait_uplink(); mac->wait_uplink();
pdcp->reestablish(); pdcp->reestablish();
@ -1331,7 +1426,8 @@ void rrc::con_reconfig_failed()
} }
void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig) { void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig) {
uint32_t i;
pthread_mutex_lock(&mutex);
phy->get_config(&previous_phy_cfg); phy->get_config(&previous_phy_cfg);
mac->get_config(&previous_mac_cfg); mac->get_config(&previous_mac_cfg);
@ -1345,6 +1441,8 @@ void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGU
con_reconfig_failed(); con_reconfig_failed();
} }
} }
pthread_mutex_unlock(&mutex);
} }
/* Actions upon reception of RRCConnectionRelease 5.3.8.3 */ /* Actions upon reception of RRCConnectionRelease 5.3.8.3 */
@ -1372,8 +1470,10 @@ void rrc::leave_connected()
mac_timers->timer_get(t310)->stop(); mac_timers->timer_get(t310)->stop();
mac_timers->timer_get(t311)->stop(); mac_timers->timer_get(t311)->stop();
mac_timers->timer_get(t304)->stop(); mac_timers->timer_get(t304)->stop();
rrc_log->info("Going RRC_IDLE\n");
state = RRC_STATE_IDLE;
if (phy->cell_is_camping()) { if (phy->cell_is_camping()) {
// Instruct MAC to look for P-RNTI // Receive paging
mac->pcch_start_rx(); mac->pcch_start_rx();
// Instruct PHY to measure serving cell for cell reselection // Instruct PHY to measure serving cell for cell reselection
phy->meas_start(phy->get_current_earfcn(), phy->get_current_pci()); phy->meas_start(phy->get_current_earfcn(), phy->get_current_pci());
@ -1401,7 +1501,7 @@ void rrc::write_pdu_bcch_bch(byte_buffer_t *pdu) {
} }
void rrc::write_pdu_bcch_dlsch(byte_buffer_t *pdu) { void rrc::write_pdu_bcch_dlsch(byte_buffer_t *pdu) {
mac->bcch_stop_rx(); mac->clear_rntis();
rrc_log->info_hex(pdu->msg, pdu->N_bytes, "BCCH DLSCH message received."); 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()); rrc_log->info("BCCH DLSCH message Stack latency: %ld us\n", pdu->get_latency_us());
@ -1523,12 +1623,10 @@ void rrc::write_pdu_pcch(byte_buffer_t *pdu) {
pcch_msg.paging_record_list_size = LIBLTE_RRC_MAX_PAGE_REC; pcch_msg.paging_record_list_size = LIBLTE_RRC_MAX_PAGE_REC;
} }
LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; if (!ueIdentity_configured) {
if (!nas->get_s_tmsi(&s_tmsi)) { rrc_log->warning("Received paging message but no ue-Identity is configured\n");
rrc_log->info("No S-TMSI present in NAS\n");
return; return;
} }
LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi_paged; LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi_paged;
for (uint32_t i = 0; i < pcch_msg.paging_record_list_size; i++) { for (uint32_t i = 0; i < pcch_msg.paging_record_list_size; i++) {
s_tmsi_paged = &pcch_msg.paging_record_list[i].ue_identity.s_tmsi; s_tmsi_paged = &pcch_msg.paging_record_list[i].ue_identity.s_tmsi;
@ -1538,12 +1636,16 @@ void rrc::write_pdu_pcch(byte_buffer_t *pdu) {
rrc_log->console("Received paging (%d/%d) for UE %x:%x\n", i + 1, pcch_msg.paging_record_list_size, rrc_log->console("Received paging (%d/%d) for UE %x:%x\n", i + 1, pcch_msg.paging_record_list_size,
pcch_msg.paging_record_list[i].ue_identity.s_tmsi.mmec, pcch_msg.paging_record_list[i].ue_identity.s_tmsi.mmec,
pcch_msg.paging_record_list[i].ue_identity.s_tmsi.m_tmsi); pcch_msg.paging_record_list[i].ue_identity.s_tmsi.m_tmsi);
if (s_tmsi.mmec == s_tmsi_paged->mmec && s_tmsi.m_tmsi == s_tmsi_paged->m_tmsi) { if (ueIdentity.mmec == s_tmsi_paged->mmec && ueIdentity.m_tmsi == s_tmsi_paged->m_tmsi) {
if (RRC_STATE_IDLE == state) { if (RRC_STATE_IDLE == state) {
rrc_log->info("S-TMSI match in paging message\n"); rrc_log->info("S-TMSI match in paging message\n");
rrc_log->console("S-TMSI match in paging message\n"); rrc_log->console("S-TMSI match in paging message\n");
nas->paging(s_tmsi_paged); nas->paging(s_tmsi_paged);
} else {
rrc_log->warning("Received paging while in CONNECT\n");
} }
} else {
rrc_log->info("Received paging for unknown identity\n");
} }
} }
} }
@ -1621,18 +1723,12 @@ void rrc::send_ul_dcch_msg()
void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) { void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) {
rrc_log->info_hex(sdu->msg, sdu->N_bytes, "TX %s SDU", get_rb_name(lcid).c_str()); if (state == RRC_STATE_IDLE) {
switch (state) { rrc_log->warning("Received ULInformationTransfer SDU when in IDLE\n");
case RRC_STATE_IDLE: return;
send_con_setup_complete(sdu);
break;
case RRC_STATE_CONNECTED:
send_ul_info_transfer(sdu);
break;
default:
rrc_log->error("SDU received from NAS while RRC state = %s\n", rrc_state_text[state]);
break;
} }
rrc_log->info_hex(sdu->msg, sdu->N_bytes, "TX %s SDU", get_rb_name(lcid).c_str());
send_ul_info_transfer(sdu);
} }
void rrc::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { void rrc::write_pdu(uint32_t lcid, byte_buffer_t *pdu) {
@ -1665,28 +1761,37 @@ void rrc::parse_dl_ccch(byte_buffer_t *pdu) {
switch (dl_ccch_msg.msg_type) { switch (dl_ccch_msg.msg_type) {
case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REJ: case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REJ:
// 5.3.3.8 // 5.3.3.8
rrc_log->info("Connection Reject received. Wait time: %d\n", rrc_log->info("Received ConnectionReject. Wait time: %d\n",
dl_ccch_msg.msg.rrc_con_rej.wait_time);
rrc_log->console("Received ConnectionReject. Wait time: %d\n",
dl_ccch_msg.msg.rrc_con_rej.wait_time); dl_ccch_msg.msg.rrc_con_rej.wait_time);
mac_timers->timer_get(t300)->stop(); mac_timers->timer_get(t300)->stop();
mac->reset();
set_mac_default(); if (dl_ccch_msg.msg.rrc_con_rej.wait_time) {
nas->rrc_connection_failure(); nas->set_barring(nas_interface_rrc::BARRING_ALL);
mac_timers->timer_get(t302)->set(this, dl_ccch_msg.msg.rrc_con_rej.wait_time*1000);
mac_timers->timer_get(t302)->run();
} else {
// Perform the actions upon expiry of T302 if wait time is zero
nas->set_barring(nas_interface_rrc::BARRING_NONE);
go_idle = true;
}
break; break;
case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_SETUP: case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_SETUP:
rrc_log->info("Connection Setup received\n"); rrc_log->info("ConnectionSetup received\n");
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");
break; break;
case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST: case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST:
rrc_log->info("Connection Reestablishment received\n"); rrc_log->info("ConnectionReestablishment received\n");
rrc_log->console("Reestablishment OK\n"); rrc_log->console("Reestablishment OK\n");
transaction_id = dl_ccch_msg.msg.rrc_con_reest.rrc_transaction_id; transaction_id = dl_ccch_msg.msg.rrc_con_reest.rrc_transaction_id;
handle_con_reest(&dl_ccch_msg.msg.rrc_con_reest); handle_con_reest(&dl_ccch_msg.msg.rrc_con_reest);
break; break;
/* Reception of RRCConnectionReestablishmentReject 5.3.7.8 */ /* Reception of RRCConnectionReestablishmentReject 5.3.7.8 */
case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST_REJ: case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST_REJ:
rrc_log->info("Connection Reestablishment Reject received\n"); rrc_log->info("ConnectionReestablishmentReject received\n");
rrc_log->console("Reestablishment Reject\n"); rrc_log->console("Reestablishment Reject\n");
go_idle = true; go_idle = true;
break; break;
@ -2229,22 +2334,34 @@ bool rrc::apply_rr_config_dedicated(LIBLTE_RRC_RR_CONFIG_DEDICATED_STRUCT *cnfg)
void rrc::handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup) { void rrc::handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup) {
// Apply the Radio Resource configuration // Apply the Radio Resource configuration
apply_rr_config_dedicated(&setup->rr_cnfg); apply_rr_config_dedicated(&setup->rr_cnfg);
// Must enter CONNECT before stopping T300
state = RRC_STATE_CONNECTED;
rrc_log->console("RRC Connected\n");
mac_timers->timer_get(t300)->stop();
mac_timers->timer_get(t302)->stop();
nas->set_barring(nas_interface_rrc::BARRING_NONE);
if (dedicatedInfoNAS) {
send_con_setup_complete(dedicatedInfoNAS);
dedicatedInfoNAS = NULL; // deallocated Inside!
} else {
rrc_log->error("Pending to transmit a ConnectionSetupComplete but no dedicatedInfoNAS was in queue\n");
}
} }
/* Reception of RRCConnectionReestablishment by the UE 5.3.7.5 */ /* Reception of RRCConnectionReestablishment by the UE 5.3.7.5 */
void rrc::handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup) { void rrc::handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup) {
// TODO: Reestablish DRB1. Not done because never was suspended mac_timers->timer_get(t301)->stop();
pdcp->reestablish();
rlc->reestablish();
// Apply the Radio Resource configuration // Apply the Radio Resource configuration
apply_rr_config_dedicated(&setup->rr_cnfg); apply_rr_config_dedicated(&setup->rr_cnfg);
mac_timers->timer_get(t300)->stop();
// Enter RRC_CONNECTED
state = RRC_STATE_CONNECTED;
// Send ConnectionSetupComplete message // Send ConnectionSetupComplete message
send_con_restablish_complete(); send_con_restablish_complete();
} }
@ -2466,7 +2583,7 @@ void rrc::rrc_meas::new_phy_meas(uint32_t earfcn, uint32_t pci, float rsrp, floa
// This indicates serving cell // This indicates serving cell
if (parent->serving_cell->equals(earfcn, pci)) { if (parent->serving_cell->equals(earfcn, pci)) {
log_h->info("MEAS: New measurement serving cell, rsrp=%f, rsrq=%f, tti=%d\n", rsrp, rsrq, tti); log_h->debug("MEAS: New measurement serving cell, rsrp=%f, rsrq=%f, tti=%d\n", rsrp, rsrq, tti);
L3_filter(&pcell_measurement, values); L3_filter(&pcell_measurement, values);
@ -2478,7 +2595,7 @@ void rrc::rrc_meas::new_phy_meas(uint32_t earfcn, uint32_t pci, float rsrp, floa
// Add to list of neighbour cells // Add to list of neighbour cells
bool added = parent->add_neighbour_cell(earfcn, pci, rsrp); bool added = parent->add_neighbour_cell(earfcn, pci, rsrp);
log_h->info("MEAS: New measurement %s earfcn=%d, pci=%d, rsrp=%f, rsrq=%f, tti=%d\n", log_h->debug("MEAS: New measurement %s earfcn=%d, pci=%d, rsrp=%f, rsrq=%f, tti=%d\n",
added?"added":"not added", earfcn, pci, rsrp, rsrq, tti); added?"added":"not added", earfcn, pci, rsrp, rsrq, tti);
// Only report measurements of 8th strongest cells // Only report measurements of 8th strongest cells

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

@ -83,7 +83,9 @@ public:
int plmn_search(srsue::rrc_interface_nas::found_plmn_t*) { return 0; }; int plmn_search(srsue::rrc_interface_nas::found_plmn_t*) { return 0; };
void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) {}; void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) {};
bool connection_request() {return true;} void set_ue_idenity(LIBLTE_RRC_S_TMSI_STRUCT s_tmsi) {}
bool connection_request(LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM cause,
srslte::byte_buffer_t *dedicatedInfoNAS) {return true;}
bool is_connected() {return true;} bool is_connected() {return true;}
uint16_t get_mcc() { return mcc; } uint16_t get_mcc() { return mcc; }

Loading…
Cancel
Save