diff --git a/lib/include/srslte/common/timers.h b/lib/include/srslte/common/timers.h index 5e8b1cfd5..9809cc260 100644 --- a/lib/include/srslte/common/timers.h +++ b/lib/include/srslte/common/timers.h @@ -64,7 +64,7 @@ public: return (counter < timeout) && running; } bool is_expired() { - return (timeout > 0) && (counter >= timeout || !running); + return (timeout > 0) && (counter >= timeout); } uint32_t get_timeout() { return timeout; diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index c05ab4231..0ddebee47 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -112,12 +112,18 @@ public: class nas_interface_rrc { 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 bool is_attached() = 0; virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0; virtual uint32_t get_ul_count() = 0; - virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 0; virtual bool get_k_asme(uint8_t *k_asme_, uint32_t n) = 0; }; @@ -177,7 +183,9 @@ public: virtual void enable_capabilities() = 0; virtual int plmn_search(found_plmn_t found_plmns[MAX_FOUND_PLMNS]) = 0; virtual void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) = 0; - virtual bool connection_request() = 0; + virtual bool connection_request(LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM cause, + srslte::byte_buffer_t *dedicatedInfoNAS) = 0; + virtual void set_ue_idenity(LIBLTE_RRC_S_TMSI_STRUCT s_tmsi) = 0; virtual bool is_connected() = 0; virtual std::string get_rb_name(uint32_t lcid) = 0; }; @@ -420,15 +428,14 @@ public: uint32_t prach_config_index; } mac_cfg_t; + virtual void clear_rntis() = 0; + /* Instructs the MAC to start receiving BCCH */ - virtual void bcch_start_rx() = 0; - virtual void bcch_stop_rx() = 0; virtual void bcch_start_rx(int si_window_start, int si_window_length) = 0; /* Instructs the MAC to start receiving PCCH */ virtual void pcch_start_rx() = 0; - virtual void pcch_stop_rx() = 0; - + /* RRC configures a logical channel */ virtual void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) = 0; @@ -487,7 +494,6 @@ typedef struct { uint32_t cfo_loop_pss_conv; uint32_t cfo_ref_mask; bool average_subframe_enabled; - int time_correct_period; std::string sss_algorithm; float estimator_fil_w; bool rssi_sensor_enabled; @@ -579,11 +585,9 @@ public: virtual int meas_start(uint32_t earfcn, int pci = -1) = 0; virtual int meas_stop(uint32_t earfcn, int pci = -1) = 0; - typedef enum { - CELL_NOT_FOUND = 0, - CELL_FOUND, - NO_MORE_FREQS, - ERROR + typedef struct { + enum {CELL_FOUND = 0, CELL_NOT_FOUND, ERROR} found; + enum {MORE_FREQS = 0, NO_MORE_FREQS} last_freq; } cell_search_ret_t; typedef struct { @@ -592,7 +596,7 @@ public: } phy_cell_t; /* 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_is_camping() = 0; diff --git a/lib/src/phy/rf/rf_uhd_imp.c b/lib/src/phy/rf/rf_uhd_imp.c index b4b0cfcd6..1331495e9 100644 --- a/lib/src/phy/rf/rf_uhd_imp.c +++ b/lib/src/phy/rf/rf_uhd_imp.c @@ -765,6 +765,7 @@ int rf_uhd_recv_with_time_multi(void *h, trials++; if (error_code == UHD_RX_METADATA_ERROR_CODE_OVERFLOW) { + printf("OVERFLOW\n"); log_overflow(handler); } else if (error_code == UHD_RX_METADATA_ERROR_CODE_LATE_COMMAND) { log_late(handler, true); diff --git a/srsue/hdr/mac/mac.h b/srsue/hdr/mac/mac.h index 1f41c5bc0..4bf888e49 100644 --- a/srsue/hdr/mac/mac.h +++ b/srsue/hdr/mac/mac.h @@ -72,10 +72,9 @@ public: /******** Interface from RLC (RLC -> MAC) ****************/ void bcch_start_rx(); - void bcch_stop_rx(); void bcch_start_rx(int si_window_start, int si_window_length); void pcch_start_rx(); - void pcch_stop_rx(); + void clear_rntis(); void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD); void reconfiguration(); void reset(); diff --git a/srsue/hdr/phy/phch_common.h b/srsue/hdr/phy/phch_common.h index f21738b6b..698b3de94 100644 --- a/srsue/hdr/phy/phch_common.h +++ b/srsue/hdr/phy/phch_common.h @@ -76,7 +76,7 @@ public: float avg_snr_db; float avg_noise; - bool pcell_meas_enabled; + bool pcell_first_measurement; uint32_t pcell_report_period; // Save last TBS for mcs>28 cases diff --git a/srsue/hdr/phy/phch_recv.h b/srsue/hdr/phy/phch_recv.h index edfe7da2a..19b8ad17d 100644 --- a/srsue/hdr/phy/phch_recv.h +++ b/srsue/hdr/phy/phch_recv.h @@ -59,7 +59,7 @@ public: void radio_overflow(); // 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_is_camping(); @@ -98,9 +98,7 @@ private: ~search(); void init(cf_t *buffer[SRSLTE_MAX_PORTS], srslte::log *log_h, uint32_t nof_rx_antennas, phch_recv *parent); void reset(); - float get_last_gain(); float get_last_cfo(); - void set_N_id_2(int N_id_2); void set_agc_enable(bool enable); ret_code run(srslte_cell_t *cell); @@ -247,6 +245,7 @@ private: void radio_error(); void set_ue_sync_opts(srslte_ue_sync_t *q, float cfo); void run_thread(); + float get_tx_cfo(); void set_sampling_rate(); bool set_frequency(); @@ -302,7 +301,6 @@ private: IDLE = 0, CELL_SEARCH, SFN_SYNC, - MEASURE, CAMPING, } state_t; @@ -318,9 +316,13 @@ private: } // 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); - next_state = IDLE; + if (cur_state == SFN_SYNC && exit_ok == true) { + next_state = CAMPING; + } else { + next_state = IDLE; + } pthread_mutex_unlock(&inside); } void force_sfn_sync() { @@ -328,11 +330,6 @@ private: next_state = SFN_SYNC; 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. * The functions change the state and wait until it has changed it. @@ -344,27 +341,16 @@ private: go_state(IDLE); pthread_mutex_unlock(&outside); } - void go_camping() { - pthread_mutex_lock(&outside); - go_state(CAMPING); - pthread_mutex_unlock(&outside); - } void run_cell_search() { pthread_mutex_lock(&outside); go_state(CELL_SEARCH); - wait_idle(); + wait_state_change(CELL_SEARCH); pthread_mutex_unlock(&outside); } void run_sfn_sync() { pthread_mutex_lock(&outside); go_state(SFN_SYNC); - wait_idle(); - pthread_mutex_unlock(&outside); - } - void run_measure() { - pthread_mutex_lock(&outside); - go_state(MEASURE); - wait_idle(); + wait_state_change(SFN_SYNC); pthread_mutex_unlock(&outside); } @@ -377,6 +363,21 @@ private: return cur_state == CAMPING; } + const char *to_string() { + switch(cur_state) { + case IDLE: + return "IDLE"; + case CELL_SEARCH: + return "SEARCH"; + case SFN_SYNC: + return "SYNC"; + case CAMPING: + return "CAMPING"; + default: + return "UNKNOWN"; + } + } + sync_state() { pthread_mutex_init(&inside, NULL); pthread_mutex_init(&outside, NULL); @@ -396,9 +397,9 @@ private: } /* 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); - while(cur_state != IDLE) { + while(cur_state == prev_state) { pthread_cond_wait(&cvar, &inside); } pthread_mutex_unlock(&inside); @@ -415,8 +416,6 @@ private: sync_state phy_state; 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) enum { @@ -426,7 +425,6 @@ private: // This is the primary cell srslte_cell_t cell; - bool cell_is_set; bool started; float time_adv_sec; uint32_t tti; diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h index a00cfd5a5..e05fbfd4c 100644 --- a/srsue/hdr/phy/phy.h +++ b/srsue/hdr/phy/phy.h @@ -83,7 +83,7 @@ public: /********** RRC INTERFACE ********************/ void reset(); 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); void meas_reset(); diff --git a/srsue/hdr/upper/nas.h b/srsue/hdr/upper/nas.h index afa9b3343..463040fa1 100644 --- a/srsue/hdr/upper/nas.h +++ b/srsue/hdr/upper/nas.h @@ -43,18 +43,14 @@ namespace srsue { typedef enum { EMM_STATE_NULL = 0, EMM_STATE_DEREGISTERED, - EMM_STATE_REGISTERED_INITIATED, EMM_STATE_REGISTERED, - EMM_STATE_SERVICE_REQUEST_INITIATED, EMM_STATE_DEREGISTERED_INITIATED, EMM_STATE_TAU_INITIATED, EMM_STATE_N_ITEMS, } emm_state_t; static const char emm_state_text[EMM_STATE_N_ITEMS][100] = {"NULL", "DEREGISTERED", - "REGISTERED INITIATED", "REGISTERED", - "SERVICE REQUEST INITIATED", "DEREGISTERED INITIATED", "TRACKING AREA UPDATE INITIATED"}; @@ -79,11 +75,10 @@ public: // RRC interface 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); uint32_t get_ul_count(); 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); // UE interface @@ -104,7 +99,8 @@ private: emm_state_t state; - bool rrc_connection_is_failure; + nas_interface_rrc::barring_t current_barring; + bool plmn_is_selected; LIBLTE_RRC_PLMN_IDENTITY_STRUCT current_plmn; LIBLTE_RRC_PLMN_IDENTITY_STRUCT home_plmn; @@ -140,8 +136,9 @@ private: // PCAP srslte::nas_pcap *pcap = NULL; + bool running; + bool rrc_connect(); - bool attach(bool is_service_req); void integrity_generate(uint8_t *key_128, uint32_t count, @@ -168,10 +165,12 @@ private: void parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu); void parse_emm_information(uint32_t lcid, byte_buffer_t *pdu); + // Packet generators + void gen_attach_request(byte_buffer_t *msg); + void gen_service_request(byte_buffer_t *msg); + // Senders - void send_attach_request(); void send_identity_response(); - void send_service_request(); void send_esm_information_response(); void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg); void send_security_mode_reject(uint8_t cause); diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index f91d35354..bc27aa324 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -64,8 +64,9 @@ class cell_t bool equals(uint32_t earfcn, uint32_t pci) { return earfcn == this->phy_cell.earfcn && pci == phy_cell.cell.id; } + // NaN means an RSRP value has not yet been obtained. Keep then in the list and clean them if never updated bool greater(cell_t *x) { - return rsrp > x->rsrp; + return rsrp > x->rsrp || isnan(rsrp); } bool plmn_equals(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) { if (has_valid_sib1) { @@ -282,7 +283,9 @@ public: uint16_t get_mnc(); int plmn_search(found_plmn_t found_plmns[MAX_FOUND_PLMNS]); void plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id); - bool connection_request(); + bool connection_request(LIBLTE_RRC_CON_REQ_EST_CAUSE_ENUM cause, + srslte::byte_buffer_t *dedicatedInfoNAS); + void set_ue_idenity(LIBLTE_RRC_S_TMSI_STRUCT s_tmsi); // PHY interface void in_sync(); @@ -321,6 +324,8 @@ private: LIBLTE_RRC_DL_CCCH_MSG_STRUCT dl_ccch_msg; LIBLTE_RRC_DL_DCCH_MSG_STRUCT dl_dcch_msg; + byte_buffer_t *dedicatedInfoNAS; + byte_buffer_t* byte_align_and_pack(); void send_ul_ccch_msg(); void send_ul_dcch_msg(); @@ -330,6 +335,9 @@ private: rrc_state_t state; uint8_t transaction_id; + LIBLTE_RRC_S_TMSI_STRUCT ueIdentity; + bool ueIdentity_configured; + bool drb_up; rrc_args_t args; @@ -358,7 +366,7 @@ private: srslte::mac_interface_timers *mac_timers; uint32_t n310_cnt, N310; uint32_t n311_cnt, N311; - uint32_t t300, t301, t310, t311, t304; + uint32_t t300, t301, t302, t310, t311, t304; // Radio bearers typedef enum{ @@ -408,7 +416,7 @@ private: bool si_acquire(uint32_t index); 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 @@ -510,6 +518,18 @@ private: rrc_meas measurements; + // Measurement object from phy + typedef struct { + float rsrp; + float rsrq; + uint32_t tti; + uint32_t earfcn; + uint32_t pci; + } phy_meas_t; + + void process_phy_meas(); + void process_new_phy_meas(phy_meas_t meas); + std::queue phy_meas_q; // Cell selection/reselection functions/variables typedef struct { @@ -542,7 +562,7 @@ private: void max_retx_attempted(); // 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_complete(); void send_con_setup_complete(byte_buffer_t *nas_msg); diff --git a/srsue/src/mac/mac.cc b/srsue/src/mac/mac.cc index 4f49d6d01..4372085d7 100644 --- a/srsue/src/mac/mac.cc +++ b/srsue/src/mac/mac.cc @@ -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); } -void mac::bcch_stop_rx() -{ - phy_h->pdcch_dl_search_reset(); -} - void mac::pcch_start_rx() { phy_h->pdcch_dl_search(SRSLTE_RNTI_PCH, SRSLTE_PRNTI); Info("SCHED: Searching for DL grant for P-RNTI\n"); } -void mac::pcch_stop_rx() +void mac::clear_rntis() { phy_h->pdcch_dl_search_reset(); } diff --git a/srsue/src/main.cc b/srsue/src/main.cc index 2912f7cd1..63d0e12ab 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -261,10 +261,6 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { bpo::value(&args->expert.phy.average_subframe_enabled)->default_value(true), "Averages in the time domain the channel estimates within 1 subframe. Needs accurate CFO correction.") - ("expert.time_correct_period", - bpo::value(&args->expert.phy.time_correct_period)->default_value(5), - "Period for sampling time offset correction.") - ("expert.sss_algorithm", bpo::value(&args->expert.phy.sss_algorithm)->default_value("full"), "Selects the SSS estimation algorithm.") diff --git a/srsue/src/phy/phch_common.cc b/srsue/src/phy/phch_common.cc index 3c3cf1641..29e1e3541 100644 --- a/srsue/src/phy/phch_common.cc +++ b/srsue/src/phy/phch_common.cc @@ -346,7 +346,6 @@ void phch_common::reset() { avg_rsrp_dbm = 0; avg_rsrq_db = 0; - pcell_meas_enabled = false; pcell_report_period = 20; bzero(pending_ack, sizeof(pending_ack_t)*TTIMOD_SZ); diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index 428003d84..58883aefe 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -134,7 +134,6 @@ void phch_recv::reset() tx_mutex_cnt = 0; time_adv_sec = 0; next_offset = 0; - cell_is_set = false; srate_mode = SRATE_NONE; current_earfcn = -1; 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. */ -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); @@ -213,51 +215,24 @@ phy_interface_rrc::cell_search_ret_t phch_recv::cell_search(phy_interface_rrc::p set_sampling_rate(); phy_state.run_sfn_sync(); - switch (sfn_sync_ret) - { - case sfn_sync::SFN_FOUND: - log_h->info("Cell Search. Sync OK. Measuring PCI=%d...\n", cell.id); - measure_p.reset(); - phy_state.run_measure(); - ret = phy_interface_rrc::CELL_FOUND; - if (found_cell) { - found_cell->earfcn = current_earfcn; - found_cell->cell = cell; - } - 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; + if (phy_state.is_camping()) { + log_h->info("Cell Search: Sync OK. Camping on cell PCI=%d\n", cell.id); + if (found_cell) { + found_cell->earfcn = current_earfcn; + found_cell->cell = cell; + } + ret.found = phy_interface_rrc::cell_search_ret_t::CELL_FOUND; + } else { + log_h->info("Cell Search: Could not synchronize with cell\n"); + ret.found = phy_interface_rrc::cell_search_ret_t::CELL_NOT_FOUND; } } else { Error("Cell Search: Setting cell PCI=%d, nof_prb=%d\n", cell.id, cell.nof_prb); } break; case search::CELL_NOT_FOUND: - cellsearch_earfcn_index++; - if (cellsearch_earfcn_index >= earfcn.size()) { - 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; - } + Info("Cell Search: No cell found in this frequency\n"); + ret.found = phy_interface_rrc::cell_search_ret_t::CELL_NOT_FOUND; break; default: 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; } + 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); return ret; } @@ -337,22 +321,13 @@ bool phch_recv::cell_select(phy_interface_rrc::phy_cell_t *new_cell) { } /* SFN synchronization */ - phy_state.run_sfn_sync(); - bool ret = false; - switch(sfn_sync_ret) { - case sfn_sync::SFN_FOUND: - Info("Cell Select: SFN syncrhonized, going to CAMPING\n"); - phy_state.go_camping(); - ret = true; - break; - 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; + phy_state.run_sfn_sync(); + if (phy_state.is_camping()) { + Info("Cell Select: SFN synchronized. CAMPING...\n"); + ret = true; + } else { + Info("Cell Select: Could not synchronize SFN\n"); } pthread_mutex_unlock(&rrc_mutex); @@ -398,7 +373,7 @@ void phch_recv::run_thread() while (running) { - Debug("SYNC: state=%d\n", phy_state); + Debug("SYNC: state=%s\n", phy_state.to_string()); 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 * and returns */ - sfn_sync_ret = sfn_p.run_subframe(&cell, &tti); - if (sfn_sync_ret != sfn_sync::IDLE) { - phy_state.state_exit(); - } - break; - case sync_state::MEASURE: - measure_ret = measure_p.run_subframe_sync(&ue_sync, sf_idx); - if (measure_ret != measure::IDLE) { - phy_state.state_exit(); + switch(sfn_p.run_subframe(&cell, &tti)) { + case sfn_sync::SFN_FOUND: + phy_state.state_exit(); + break; + case sfn_sync::IDLE: + break; + default: + phy_state.state_exit(false); + break; } break; case sync_state::CAMPING: @@ -452,7 +427,7 @@ void phch_recv::run_thread() metrics.sfo = srslte_ue_sync_get_sfo(&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); /* 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)) { srslte_timestamp_copy(&tx_time_prach, &rx_time); 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(); 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); @@ -514,6 +489,7 @@ void phch_recv::run_thread() if (current_srate > 0) { nsamples = current_srate/1000; } + Debug("Discarting %d samples\n", nsamples); if (!radio_h->rx_now(dummy_buffer, nsamples, NULL)) { 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 */ if (radio_is_overflow) { - // Overflow has occurred now while camping - if (phy_state.is_camping()) { - log_h->info("Detected radio overflow while camping. Resynchronizing cell\n"); - sfn_p.reset(); - phy_state.force_sfn_sync(); - radio_overflow_return = true; - // This means that it finished running sfn_sync - } else if (phy_state.is_idle() && radio_overflow_return) { - switch (sfn_sync_ret) { - case sfn_sync::SFN_FOUND: - 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; + // If we are coming back from an overflow + if (radio_overflow_return) { + if (phy_state.is_camping()) { + log_h->info("Successfully resynchronized after overflow. Returning to CAMPING\n"); + radio_overflow_return = false; + radio_is_overflow = false; + } else if (phy_state.is_idle()) { + log_h->warning("Could not synchronize SFN after radio overflow. Trying again\n"); + rrc->out_of_sync(); + phy_state.force_sfn_sync(); } + } 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 @@ -582,6 +550,7 @@ void phch_recv::run_thread() * */ void phch_recv::radio_overflow() { + log_h->warning("Overflow\n"); 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; } +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) { 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); } - 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; if (!worker_com->args->sss_algorithm.compare("diff")) { sss_alg = SSS_DIFF; @@ -689,8 +672,6 @@ bool phch_recv::set_cell() { return false; } - cell_is_set = false; - // Set cell in all objects if (srslte_ue_sync_set_cell(&ue_sync, cell)) { 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 srslte_ue_sync_reset(&ue_sync); - cell_is_set = true; - - return cell_is_set; + return true; } void phch_recv::set_earfcn(std::vector 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; } -void phch_recv::search::set_N_id_2(int N_id_2) { - force_N_id_2 = N_id_2; -} - void phch_recv::search::reset() { 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() { 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 { - Debug("SYNC: PSS/SSS not found...\n"); + Info("SYNC: PSS/SSS not found...\n"); } 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); 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; } 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() { // Stop all measurements intra_freq_meas.clear_cells(); - if (worker_com) { - worker_com->pcell_meas_enabled = false; - } } int phch_recv::meas_start(uint32_t earfcn, int pci) { if ((int) earfcn == current_earfcn) { - worker_com->pcell_meas_enabled = true; if (pci != (int) cell.id) { intra_freq_meas.add_cell(pci); } diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index f10bc2b67..911429690 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -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_cfo_enable(&ue_ul, true); + phy->pcell_first_measurement = true; + cell_initiated = 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 decode_pdcch = true; - /* Without a grant, we might need to do fft processing if need to decode PHICH */ - if (phy->get_pending_ack(tti) || decode_pdcch) { - - // Setup estimator filter - float w_coeff = phy->args->estimator_fil_w; - if (w_coeff > 0.0) { - srslte_chest_dl_set_smooth_filter3_coeff(&ue_dl.chest, w_coeff); - } else if (w_coeff == 0.0) { - srslte_chest_dl_set_smooth_filter(&ue_dl.chest, NULL, 0); - } - - if (!phy->args->snr_estim_alg.compare("refs")) { - srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_REFS); - } else if (!phy->args->snr_estim_alg.compare("empty")) { - srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_EMPTY); - } else { - srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_PSS); - } - - if (srslte_ue_dl_decode_fft_estimate(&ue_dl, tti%10, &cfi) < 0) { - Error("Getting PDCCH FFT estimate\n"); - return false; - } - chest_done = true; + // Do always channel estimation to keep track of out-of-sync and send measurements to RRC + + // Setup estimator filter + float w_coeff = phy->args->estimator_fil_w; + if (w_coeff > 0.0) { + srslte_chest_dl_set_smooth_filter3_coeff(&ue_dl.chest, w_coeff); + } else if (w_coeff == 0.0) { + srslte_chest_dl_set_smooth_filter(&ue_dl.chest, NULL, 0); + } + + if (!phy->args->snr_estim_alg.compare("refs")) { + srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_REFS); + } else if (!phy->args->snr_estim_alg.compare("empty")) { + srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_EMPTY); } else { - 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 */ float noise_estimate = phy->avg_noise; @@ -1427,7 +1427,8 @@ void phch_worker::update_measurements() } else { phy->avg_rsrp_dbm = SRSLTE_VEC_EMA(rsrp_dbm, phy->avg_rsrp_dbm, snr_ema_coeff); } - if ((tti%phy->pcell_report_period) == 0 && phy->pcell_meas_enabled) { + 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); } } diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index ad8c8dce3..06f802f9b 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -96,7 +96,6 @@ void phy::set_default_args(phy_args_t *args) args->equalizer_mode = "mmse"; args->cfo_integer_enabled = false; args->cfo_correct_tol_hz = 50; - args->time_correct_period = 5; args->sss_algorithm = "full"; args->estimator_fil_w = 0.1; } @@ -266,8 +265,8 @@ bool phy::cell_select(phy_cell_t *cell) { return sf_recv.cell_select(cell); } -phy_interface_rrc::cell_search_ret_t phy::cell_search(phy_cell_t *cell, float *rsrp) { - return sf_recv.cell_search(cell, rsrp); +phy_interface_rrc::cell_search_ret_t phy::cell_search(phy_cell_t *cell) { + return sf_recv.cell_search(cell); } bool phy::cell_is_camping() { diff --git a/srsue/src/upper/gw.cc b/srsue/src/upper/gw.cc index fbf4bca9f..4ab6d9460 100644 --- a/srsue/src/upper/gw.cc +++ b/srsue/src/upper/gw.cc @@ -248,9 +248,8 @@ void gw::run_thread() 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; - uint32_t attach_cnt = 0; uint32_t attach_attempts = 0; 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"); while(run_enable && !pdcp->is_drb_enabled(cfg.lcid) && attach_attempts < ATTACH_MAX_ATTEMPTS) { - if (attach_cnt == 0) { - gw_log->info("LCID=%d not active, requesting NAS attach (%d/%d)\n", cfg.lcid, attach_attempts, ATTACH_MAX_ATTEMPTS); - nas->attach_request(); + gw_log->info("LCID=%d not active, requesting NAS attach (%d/%d)\n", cfg.lcid, attach_attempts, ATTACH_MAX_ATTEMPTS); + if (!nas->attach_request()) { 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) { @@ -296,7 +292,6 @@ void gw::run_thread() } attach_attempts = 0; - attach_cnt = 0; if (!run_enable) { break; diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index 6904abc1e..f8ee8b4ce 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -79,9 +79,11 @@ void nas::init(usim_interface_nas *usim_, have_guti = true; have_ctxt = true; } + running = true; } void nas::stop() { + running = false; write_ctxt_file(ctxt); } @@ -133,11 +135,10 @@ bool nas::attach_request() { if (plmn_is_selected) { rrc->plmn_select(current_plmn); if (rrc_connect()) { - nas_log->info("RRC connection established. Sending NAS attach request\n"); - if (attach(false)) { - nas_log->info("NAS attached successfully.\n"); - return true; - } + nas_log->info("NAS attached successfully.\n"); + return true; + } else { + nas_log->error("Could not attach\n"); } } else { nas_log->error("PLMN is not selected because no suitable PLMN was found\n"); @@ -150,11 +151,9 @@ bool nas::attach_request() { } else { nas_log->info("NAS is already registered but RRC disconnected. Connecting now...\n"); if (rrc_connect()) { - nas_log->info("RRC connection established. Sending NAS attach request\n"); - if (attach(true)) { - nas_log->info("NAS attached successfully.\n"); - return true; - } + nas_log->info("NAS attached successfully.\n"); + } else { + nas_log->error("Could not attach\n"); } } break; @@ -179,21 +178,17 @@ void nas::paging(LIBLTE_RRC_S_TMSI_STRUCT *ue_identiy) { if (state == EMM_STATE_REGISTERED) { nas_log->info("Received paging: requesting RRC connection establishment\n"); if (rrc_connect()) { - nas_log->info("Connected successfully. Initiating service request\n"); - if (attach(true)) { - nas_log->info("Attached successfully\n"); - } else { - nas_log->error("Could not attach\n"); - } + nas_log->info("Attached successfully\n"); } 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() { - nas_log->debug("Received RRC Connection Failure\n"); - rrc_connection_is_failure = true; +void nas::set_barring(barring_t barring) { + current_barring = barring; } /* Internal function that requests RRC connection, waits for positive or negative response and returns true/false @@ -203,54 +198,49 @@ bool nas::rrc_connect() { nas_log->info("Already connected\n"); return true; } - uint32_t tout; - rrc_connection_is_failure = false; - if (rrc->connection_request()) { - // Wait until RRCConnected or connection error - tout = 0; - 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); - } + + // Generate service request or attach request message + byte_buffer_t *dedicatedInfoNAS = pool_allocate; + if (state == EMM_STATE_REGISTERED) { + gen_service_request(dedicatedInfoNAS); } else { - nas_log->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) { - send_service_request(); - } else { - send_attach_request(); + // Provide UE-Identity to RRC if have one + if (have_guti) { + LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; + s_tmsi.mmec = ctxt.guti.mme_code; + s_tmsi.m_tmsi = ctxt.guti.m_tmsi; + rrc->set_ue_idenity(s_tmsi); } - 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 - tout = 0; - while (tout < 10000 && state == EMM_STATE_REGISTERED_INITIATED) { - usleep(1000); - tout++; - } - if (state == EMM_STATE_REGISTERED) { - return true; - } else if (state == EMM_STATE_DEREGISTERED) { - nas_log->error("Received attach reject while trying to attach\n"); + if (rrc->connection_request(establish_cause, dedicatedInfoNAS)) + { + nas_log->info("Connection established correctly. Waiting for Attach\n"); + + // Wait until attachment. If doing a service request is already attached + uint32_t tout = 0; + while (tout < 5000 && state != EMM_STATE_REGISTERED && running && rrc->is_connected()) { + usleep(1000); + tout++; + } + if (state == EMM_STATE_REGISTERED) { + nas_log->info("EMM Registered correctly\n"); + return true; + } else if (state == EMM_STATE_DEREGISTERED) { + nas_log->error("Received attach reject while trying to attach\n"); + nas_log->console("Failed to Attach\n"); + } else if (!rrc->is_connected()) { + nas_log->error("Was disconnected while attaching\n"); + } else { + nas_log->error("Timed out while trying to attach\n"); + } } else { - nas_log->error("Timed out while trying to attach\n"); + nas_log->error("Could not establish RRC connection\n"); } return false; } @@ -362,16 +352,6 @@ uint32_t nas::get_ul_count() { return ctxt.tx_count; } -bool nas::get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) { - if (have_guti) { - s_tmsi->mmec = ctxt.guti.mme_code; - s_tmsi->m_tmsi = ctxt.guti.m_tmsi; - return true; - } else { - return false; - } -} - bool nas::get_k_asme(uint8_t *k_asme_, uint32_t n) { if(!have_ctxt) { nas_log->error("K_asme requested before security context established\n"); @@ -560,6 +540,11 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { if (attach_accept.guti_present) { memcpy(&ctxt.guti, &attach_accept.guti.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT)); have_guti = true; + // Update RRC UE-Idenity + LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; + s_tmsi.mmec = ctxt.guti.mme_code; + s_tmsi.m_tmsi = ctxt.guti.m_tmsi; + rrc->set_ue_idenity(s_tmsi); } if (attach_accept.lai_present) {} if (attach_accept.ms_id_present) {} @@ -896,19 +881,18 @@ void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) { * Senders ******************************************************************************/ -void nas::send_attach_request() { - LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT attach_req; - byte_buffer_t *msg = pool_allocate; +void nas::gen_attach_request(byte_buffer_t *msg) { if (!msg) { - nas_log->error("Fatal Error: Couldn't allocate PDU in send_attach_request().\n"); + nas_log->error("Fatal Error: Couldn't allocate PDU in gen_attach_request().\n"); return; } + LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT attach_req; - u_int32_t i; + nas_log->info("Generating attach request\n"); attach_req.eps_attach_type = LIBLTE_MME_EPS_ATTACH_TYPE_EPS_ATTACH; - for (i = 0; i < 8; i++) { + for (u_int32_t i = 0; i < 8; i++) { attach_req.ue_network_cap.eea[i] = eea_caps[i]; attach_req.ue_network_cap.eia[i] = eia_caps[i]; } @@ -967,14 +951,47 @@ void nas::send_attach_request() { pcap->write_nas(msg->msg, msg->N_bytes); } - nas_log->info("Sending attach request\n"); - rrc->write_sdu(cfg.lcid, msg); - if (have_ctxt) { ctxt.tx_count++; } } + +void nas::gen_service_request(byte_buffer_t *msg) { + if (!msg) { + nas_log->error("Fatal Error: Couldn't allocate PDU in gen_service_request().\n"); + return; + } + + nas_log->info("Generating service request\n"); + + // Pack the service request message directly + msg->msg[0] = (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); + msg->N_bytes++; + msg->msg[1] = (ctxt.ksi & 0x07) << 5; + msg->msg[1] |= ctxt.tx_count & 0x1F; + msg->N_bytes++; + + uint8_t mac[4]; + integrity_generate(&k_nas_int[16], + ctxt.tx_count, + SECURITY_DIRECTION_UPLINK, + &msg->msg[0], + 2, + &mac[0]); + // Set the short MAC + msg->msg[2] = mac[2]; + msg->N_bytes++; + msg->msg[3] = mac[3]; + msg->N_bytes++; + + if(pcap != NULL) { + pcap->write_nas(msg->msg, msg->N_bytes); + } + + ctxt.tx_count++; +} + void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) { LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT pdn_con_req; @@ -1022,42 +1039,6 @@ void nas::send_security_mode_reject(uint8_t cause) { void nas::send_identity_response() {} -void nas::send_service_request() { - byte_buffer_t *msg = pool_allocate; - if (!msg) { - nas_log->error("Fatal Error: Couldn't allocate PDU in send_service_request().\n"); - return; - } - - // Pack the service request message directly - msg->msg[0] = (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); - msg->N_bytes++; - msg->msg[1] = (ctxt.ksi & 0x07) << 5; - msg->msg[1] |= ctxt.tx_count & 0x1F; - msg->N_bytes++; - - uint8_t mac[4]; - integrity_generate(&k_nas_int[16], - ctxt.tx_count, - SECURITY_DIRECTION_UPLINK, - &msg->msg[0], - 2, - &mac[0]); - // Set the short MAC - msg->msg[2] = mac[2]; - msg->N_bytes++; - msg->msg[3] = mac[3]; - msg->N_bytes++; - - if(pcap != NULL) { - pcap->write_nas(msg->msg, msg->N_bytes); - } - - nas_log->info("Sending service request\n"); - rrc->write_sdu(cfg.lcid, msg); - ctxt.tx_count++; -} - void nas::send_esm_information_response() {} diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index d3ae1e341..c72f8063f 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -110,10 +110,14 @@ void rrc::init(phy_interface_rrc *phy_, t300 = 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(); t311 = mac_timers->timer_get_unique_id(); t304 = mac_timers->timer_get_unique_id(); + dedicatedInfoNAS = NULL; + ueIdentity_configured = false; + transaction_id = 0; // Register logging handler with liblte_rrc @@ -167,38 +171,71 @@ void rrc::run_tti(uint32_t tti) { return; } - rrc_log->debug("State %s\n", rrc_state_text[state]); - switch(state) { - case RRC_STATE_IDLE: - // If attached but not camping on the cell, perform cell reselection - if (nas->is_attached()) { - rrc_log->info("Running cell selection and reselection in IDLE\n"); - if (!cell_selection()) { - // If can not camp on any cell, search again for new cells - cell_search(); + /* We can not block in this thread because it is called from + * the MAC TTI timer and needs to return immediatly to perform other + * tasks. Therefore in this function we use trylock() instead of lock() and + * skip function if currently locked, since none of the functions here is urgent + */ + if (!pthread_mutex_trylock(&mutex)) { + + // Process pending PHY measurements in IDLE/CONNECTED + 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; - case RRC_STATE_CONNECTED: - if (ho_start) { - ho_start = false; - if (!ho_prepare()) { - con_reconfig_failed(); + break; + case RRC_STATE_CONNECTED: + if (ho_start) { + ho_start = false; + if (!ho_prepare()) { + con_reconfig_failed(); + } } - } - measurements.run_tti(tti); - if (go_idle) { - leave_connected(); - } - break; - default: - break; - } - cell_clean_cnt++; - if (cell_clean_cnt==1000) { - clean_neighbours(); - cell_clean_cnt = 0; - } + measurements.run_tti(tti); + if (go_idle) { + go_idle = false; + leave_connected(); + } + break; + default:break; + } + + // Clean old neighbours + cell_clean_cnt++; + if (cell_clean_cnt == 1000) { + 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; do { 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()) { // Save PLMN and TAC to NAS 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"); } } - } 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); - if (ret == phy_interface_rrc::ERROR) { + if (ret.found == phy_interface_rrc::cell_search_ret_t::ERROR) { return -1; } else { 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) { plmn_is_selected = true; 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 @@ -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 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) { rrc_log->error("Trying to connect but PLMN not selected.\n"); @@ -295,7 +340,13 @@ bool rrc::connection_request() { } 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; } @@ -303,16 +354,13 @@ bool rrc::connection_request() { pthread_mutex_lock(&mutex); - // Perform cell re-selection - int cnt = 0; - while(!(serving_cell->plmn_equals(selected_plmn_id) && phy->cell_is_camping()) && cnt<10) { - rrc_log->info("Not camping on any suitable cell. Selecting another cell\n"); - cell_selection(); - cnt++; - } + rrc_log->info("Initiation of Connection establishment procedure\n"); + + // Perform cell selection & reselection for the selected PLMN + cell_selection(); // .. and SI acquisition - if (cnt<10) { + if (phy->cell_is_camping()) { // Set default configurations set_phy_default(); @@ -327,9 +375,37 @@ bool rrc::connection_request() { mac_timers->timer_get(t300)->reset(); mac_timers->timer_get(t300)->run(); - rrc_log->info("Sending ConnectionRequest\n"); - send_con_request(); - ret = true; + // Send connectionRequest message to lower layers + send_con_request(cause); + + // 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 { rrc_log->error("Configuring serving cell\n"); } @@ -341,6 +417,12 @@ bool rrc::connection_request() { 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 */ 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"); 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++) { 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)) { - rrc_log->info("Timeout while acquiring SIB%d\n", i + 1); + rrc_log->info("Timeout while acquiring SIB%d\n", i+1); return false; } - } else if (i == 1) { - // Re-apply SIB2 configuration acquired previously - apply_sib2_configs(serving_cell->sib2ptr()); + } else { + rrc_log->info("Cell has SIB%d\n", i+1); } } 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) { + 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) { - earfcn_i = serving_cell->get_earfcn(); - pci_i = serving_cell->get_pci(); +/* Processes all pending PHY measurements in queue. Must be called from a mutexed function + */ +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; - uint32_t pci = (uint32_t) pci_i; +void rrc::process_new_phy_meas(phy_meas_t meas) +{ + 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) { 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 if (serving_cell->equals(earfcn, pci)) { - cell_reselection(rsrp, rsrq); 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 } else { - if (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); - } + add_neighbour_cell(earfcn, pci, rsrp); } } - pthread_mutex_unlock(&mutex); } // 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; rrc_log->info("Received out-of-sync while in state %s. n310=%d, t311=%s, t310=%s\n", rrc_state_text[state], n310_cnt, @@ -433,17 +538,15 @@ void rrc::out_of_sync() { 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) -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; if (mac_timers->timer_get(t310)->is_running()) { 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::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) { - case phy_interface_rrc::CELL_FOUND: + switch(ret.found) { + case phy_interface_rrc::cell_search_ret_t::CELL_FOUND: rrc_log->info("Cell found in this frequency. Setting new serving cell...\n"); - if (!add_neighbour_cell(new_cell, rsrp)) { - rrc_log->info("No more space for neighbour cells (detected cell RSRP=%.1f dBm worse than current %d neighbours)\n", rsrp, NOF_NEIGHBOUR_CELLS); + // Create cell with NaN RSRP. Will be updated by new_phy_meas() during SIB search. + if (!add_neighbour_cell(new_cell, NAN)) { + rrc_log->info("No more space for neighbour cells\n"); break; } set_serving_cell(new_cell); - rrc_log->info("Camping on cell...\n"); - if (phy->cell_select(&new_cell)) { + if (phy->cell_is_camping()) { 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)) { rrc_log->error("Timeout while acquiring SIB1\n"); } } else { - rrc_log->info("Camping OK. Already has SIB1\n"); + rrc_log->info("Cell has SIB1\n"); } } else { rrc_log->warning("Could not camp on found cell. Trying next one...\n"); } break; - case phy_interface_rrc::CELL_NOT_FOUND: - rrc_log->info("No cells found. Trying next frequency\n"); + case phy_interface_rrc::cell_search_ret_t::CELL_NOT_FOUND: + rrc_log->info("No cells found.\n"); break; - case phy_interface_rrc::NO_MORE_FREQS: - rrc_log->info("Finished searching for cells in current EARFCN set\n"); - break; - case phy_interface_rrc::ERROR: + case phy_interface_rrc::cell_search_ret_t::ERROR: rrc_log->error("In cell search. Finishing PLMN search\n"); break; } @@ -774,8 +873,6 @@ void rrc::clean_neighbours() struct timeval now; gettimeofday(&now, NULL); - pthread_mutex_lock(&mutex); - std::vector::iterator it = neighbour_cells.begin(); while(it != neighbour_cells.end()) { if ((*it)->timeout_secs(now) > NEIGHBOUR_TIMEOUT) { @@ -785,7 +882,6 @@ void rrc::clean_neighbours() ++it; } } - pthread_mutex_unlock(&mutex); } // Sort neighbour cells by decreasing order of RSRP @@ -807,7 +903,7 @@ void rrc::sort_neighbour_cells() if (neighbour_cells.size() > 0) { char ordered[512]; 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;iget_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); - // If exists, update RSRP, sort again and return - if (cell_idx >= 0) { + // If exists, update RSRP if provided, sort again and return + if (cell_idx >= 0 && isnormal(rsrp)) { neighbour_cells[cell_idx]->set_rsrp(rsrp); sort_neighbour_cells(); 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"); 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) { - // 5.3.3.6 - rrc_log->info("Timer T300 expired: ConnectionRequest timed out\n"); - mac->reset(); - set_mac_default(); - rlc->reestablish(); - nas->rrc_connection_failure(); + // Do nothing, handled in connection_request() } else if (timeout_id == t304) { rrc_log->console("Timer T304 expired: Handover failed\n"); 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"); - LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; // Prepare ConnectionRequest packet 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.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 { ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_RANDOM_VALUE; // 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.cause = LIBLTE_RRC_CON_REQ_EST_CAUSE_MO_SIGNALLING; + ul_ccch_msg.msg.rrc_con_req.cause = cause; send_ul_ccch_msg(); - } /* 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(); // Perform cell selection in accordance to 36.304 - if (cell_selection()) { - - if (mac_timers->timer_get(t311)->is_running()) { - // Actions following cell reselection while T311 is running 5.3.7.3 - 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(t311)->stop(); - send_ul_ccch_msg(); + 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 + 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(t311)->stop(); + send_ul_ccch_msg(); + } else { + rrc_log->info("T311 expired while selecting cell. Going to IDLE\n"); + go_idle = true; + } } else { - go_idle = true; + rrc_log->warning("Could not re-synchronize with cell.\n"); } } 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() { @@ -1102,9 +1200,6 @@ void rrc::send_con_restablish_complete() { void rrc::send_con_setup_complete(byte_buffer_t *nas_msg) { rrc_log->debug("Preparing RRC Connection Setup Complete\n"); - state = RRC_STATE_CONNECTED; - rrc_log->console("RRC Connected\n"); - // Prepare ConnectionSetupComplete packet 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; @@ -1179,7 +1274,7 @@ bool rrc::ho_prepare() { ho_src_rnti = uernti.crnti; // Reset/Reestablish stack - mac->bcch_stop_rx(); // FIXME: change function name + mac->clear_rntis(); phy->meas_reset(); mac->wait_uplink(); 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) { - uint32_t i; + + pthread_mutex_lock(&mutex); phy->get_config(&previous_phy_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(); } } + + pthread_mutex_unlock(&mutex); } /* 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(t311)->stop(); mac_timers->timer_get(t304)->stop(); + rrc_log->info("Going RRC_IDLE\n"); + state = RRC_STATE_IDLE; if (phy->cell_is_camping()) { - // Instruct MAC to look for P-RNTI + // Receive paging mac->pcch_start_rx(); // Instruct PHY to measure serving cell for cell reselection 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) { - mac->bcch_stop_rx(); + mac->clear_rntis(); 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()); @@ -1523,12 +1623,10 @@ void rrc::write_pdu_pcch(byte_buffer_t *pdu) { pcch_msg.paging_record_list_size = LIBLTE_RRC_MAX_PAGE_REC; } - LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; - if (!nas->get_s_tmsi(&s_tmsi)) { - rrc_log->info("No S-TMSI present in NAS\n"); + if (!ueIdentity_configured) { + rrc_log->warning("Received paging message but no ue-Identity is configured\n"); return; } - LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi_paged; 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; @@ -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, pcch_msg.paging_record_list[i].ue_identity.s_tmsi.mmec, 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) { rrc_log->info("S-TMSI match in paging message\n"); rrc_log->console("S-TMSI match in paging message\n"); 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) { - rrc_log->info_hex(sdu->msg, sdu->N_bytes, "TX %s SDU", get_rb_name(lcid).c_str()); - switch (state) { - case RRC_STATE_IDLE: - 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; + if (state == RRC_STATE_IDLE) { + rrc_log->warning("Received ULInformationTransfer SDU when in IDLE\n"); + return; } + 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) { @@ -1665,28 +1761,37 @@ void rrc::parse_dl_ccch(byte_buffer_t *pdu) { switch (dl_ccch_msg.msg_type) { case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REJ: // 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); + mac_timers->timer_get(t300)->stop(); - mac->reset(); - set_mac_default(); - nas->rrc_connection_failure(); + + if (dl_ccch_msg.msg.rrc_con_rej.wait_time) { + 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; 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; handle_con_setup(&dl_ccch_msg.msg.rrc_con_setup); - rrc_log->info("Notifying NAS of connection setup\n"); break; 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"); transaction_id = dl_ccch_msg.msg.rrc_con_reest.rrc_transaction_id; handle_con_reest(&dl_ccch_msg.msg.rrc_con_reest); break; /* Reception of RRCConnectionReestablishmentReject 5.3.7.8 */ 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"); go_idle = true; 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) { // Apply the Radio Resource configuration 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 */ 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_rr_config_dedicated(&setup->rr_cnfg); - - mac_timers->timer_get(t300)->stop(); - - // Enter RRC_CONNECTED - state = RRC_STATE_CONNECTED; - // Send ConnectionSetupComplete message 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 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); @@ -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 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); // Only report measurements of 8th strongest cells diff --git a/srsue/test/mac/mac_test.cc b/srsue/test/mac/mac_test.cc index 3d21720d4..f8d3a1f80 100644 --- a/srsue/test/mac/mac_test.cc +++ b/srsue/test/mac/mac_test.cc @@ -406,13 +406,13 @@ public: printf("SIB1 received %d bytes, CellID=%d, si_window=%d, sib2_period=%d\n", nof_bytes, dlsch_msg.sibs[0].sib.sib1.cell_id&0xfff, si_window_len, sib2_period); sib1_decoded = true; - mac.bcch_stop_rx(); + mac.clear_rntis(); } else if (dlsch_msg.sibs[0].sib_type == LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2) { printf("SIB2 received %d bytes\n", nof_bytes); setup_mac_phy_sib2(&dlsch_msg.sibs[0].sib.sib2, &mac, &phy); sib2_decoded = true; - mac.bcch_stop_rx(); + mac.clear_rntis(); } } } diff --git a/srsue/test/upper/nas_test.cc b/srsue/test/upper/nas_test.cc index 1c6f5f0e3..107a577b6 100644 --- a/srsue/test/upper/nas_test.cc +++ b/srsue/test/upper/nas_test.cc @@ -83,7 +83,9 @@ public: int plmn_search(srsue::rrc_interface_nas::found_plmn_t*) { return 0; }; 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;} uint16_t get_mcc() { return mcc; }