diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index 28cfdca55..024b04aec 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -28,8 +28,8 @@ #ifndef SRSLTE_UE_INTERFACES_H #define SRSLTE_UE_INTERFACES_H -#include #include +#include #include "rrc_interface_types.h" #include "srslte/asn1/liblte_mme.h" @@ -527,10 +527,10 @@ typedef struct { bool pregenerate_signals = false; float force_ul_amplitude = 0.0f; - float in_sync_rsrp_dbm_th = -130.0f; - float in_sync_snr_db_th = 1.0f; - uint32_t nof_in_sync_events = 10; - uint32_t nof_out_of_sync_events = 20; + float in_sync_rsrp_dbm_th = -130.0f; + float in_sync_snr_db_th = 1.0f; + uint32_t nof_in_sync_events = 10; + uint32_t nof_out_of_sync_events = 20; srslte::channel::args_t dl_channel_args; srslte::channel::args_t ul_channel_args; @@ -610,9 +610,9 @@ public: } phy_cell_t; /* Cell search and selection procedures */ - virtual cell_search_ret_t cell_search(phy_cell_t* cell) = 0; - virtual bool cell_select(phy_cell_t* cell = NULL) = 0; - virtual bool cell_is_camping() = 0; + virtual cell_search_ret_t cell_search(phy_cell_t* cell) = 0; + virtual bool cell_select(const phy_cell_t* cell = NULL) = 0; + virtual bool cell_is_camping() = 0; virtual void reset() = 0; @@ -643,7 +643,8 @@ public: class stack_interface_rrc { public: - virtual void start_cell_search() = 0; + virtual void start_cell_search() = 0; + virtual void start_cell_select(const phy_interface_rrc_lte::phy_cell_t* cell) = 0; }; // Combined interface for PHY to access stack (MAC and RRC) diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h index 8546b3e10..9ba218a22 100644 --- a/srsue/hdr/phy/phy.h +++ b/srsue/hdr/phy/phy.h @@ -70,7 +70,7 @@ public: /********** RRC INTERFACE ********************/ void reset() final; cell_search_ret_t cell_search(phy_cell_t* cell) final; - bool cell_select(phy_cell_t* cell) final; + bool cell_select(const phy_cell_t* cell) final; void set_cells_to_meas(uint32_t earfcn, const std::set& pci) final; void meas_stop() final; diff --git a/srsue/hdr/phy/sync.h b/srsue/hdr/phy/sync.h index 89db04454..1128c51ad 100644 --- a/srsue/hdr/phy/sync.h +++ b/srsue/hdr/phy/sync.h @@ -66,7 +66,7 @@ public: // RRC interface for controling the SYNC state phy_interface_rrc_lte::cell_search_ret_t cell_search(phy_interface_rrc_lte::phy_cell_t* cell); - bool cell_select(phy_interface_rrc_lte::phy_cell_t* cell); + bool cell_select(const phy_interface_rrc_lte::phy_cell_t* cell); bool cell_is_camping(); // RRC interface for controlling the neighbour cell measurement diff --git a/srsue/hdr/stack/rrc/rrc.h b/srsue/hdr/stack/rrc/rrc.h index 9e9b34cbd..ea6538b14 100644 --- a/srsue/hdr/stack/rrc/rrc.h +++ b/srsue/hdr/stack/rrc/rrc.h @@ -356,6 +356,7 @@ public: // STACK interface void cell_search_completed(const phy_interface_rrc_lte::cell_search_ret_t& cs_ret, const phy_interface_rrc_lte::phy_cell_t& found_cell); + void cell_select_completed(bool cs_ret); protected: // Moved to protected to be accessible by unit tests diff --git a/srsue/hdr/stack/rrc/rrc_procedures.h b/srsue/hdr/stack/rrc/rrc_procedures.h index 528181586..3c32af334 100644 --- a/srsue/hdr/stack/rrc/rrc_procedures.h +++ b/srsue/hdr/stack/rrc/rrc_procedures.h @@ -29,6 +29,20 @@ namespace srsue { +/******************************** + * Events + *******************************/ + +// background workers use this event to signal the result of a cell select phy procedure +struct cell_select_event_t { + cell_select_event_t(bool c_) : cs_ret(c_) {} + bool cs_ret; +}; + +/******************************** + * Procedures + *******************************/ + class rrc::cell_search_proc { public: @@ -36,13 +50,15 @@ public: phy_interface_rrc_lte::cell_search_ret_t cs_ret; phy_interface_rrc_lte::phy_cell_t found_cell; }; - enum class state_t { phy_cell_search, si_acquire, wait_measurement }; + enum class state_t { phy_cell_search, si_acquire, wait_measurement, phy_cell_select }; explicit cell_search_proc(rrc* parent_); srslte::proc_outcome_t init(); srslte::proc_outcome_t step(); + srslte::proc_outcome_t step_si_acquire(); srslte::proc_outcome_t react(const cell_search_event_t& event); - srslte::proc_outcome_t check_sib(); + srslte::proc_outcome_t react(const cell_select_event_t& event); + srslte::proc_outcome_t step_wait_measurement(); phy_interface_rrc_lte::cell_search_ret_t get_result() const { return search_result.cs_ret; } static const char* name() { return "Cell Search"; } @@ -116,9 +132,12 @@ public: void then(const srslte::proc_result_t& proc_result) const; cs_result_t get_result() const { return cs_result; } static const char* name() { return "Cell Selection"; } + srslte::proc_outcome_t react(const cell_select_event_t& event); private: - srslte::proc_outcome_t step_cell_selection(); + srslte::proc_outcome_t start_cell_selection(); + srslte::proc_outcome_t step_cell_selection(const cell_select_event_t& event); + srslte::proc_outcome_t step_serv_cell_camp(const cell_select_event_t& event); srslte::proc_outcome_t step_wait_in_sync(); srslte::proc_outcome_t step_cell_search(); srslte::proc_outcome_t step_cell_config(); @@ -127,7 +146,7 @@ private: rrc* rrc_ptr; // state variables - enum class search_state_t { cell_selection, wait_in_sync, cell_config, cell_search }; + enum class search_state_t { cell_selection, serv_cell_camp, wait_in_sync, cell_config, cell_search }; cs_result_t cs_result; search_state_t state; uint32_t neigh_index; @@ -247,10 +266,10 @@ public: private: enum class state_t { cell_reselection, cell_configuration } state; - rrc* rrc_ptr = nullptr; - asn1::rrc::reest_cause_e reest_cause = asn1::rrc::reest_cause_e::nulltype; - uint16_t reest_rnti = 0; - uint16_t reest_source_pci = 0; + rrc* rrc_ptr = nullptr; + asn1::rrc::reest_cause_e reest_cause = asn1::rrc::reest_cause_e::nulltype; + uint16_t reest_rnti = 0; + uint16_t reest_source_pci = 0; uint32_t reest_source_freq = 0; srslte::proc_outcome_t step_cell_reselection(); diff --git a/srsue/hdr/stack/ue_stack_lte.h b/srsue/hdr/stack/ue_stack_lte.h index 5c0fa323d..aef541618 100644 --- a/srsue/hdr/stack/ue_stack_lte.h +++ b/srsue/hdr/stack/ue_stack_lte.h @@ -120,6 +120,7 @@ public: // Interface for RRC void start_cell_search() final; + void start_cell_select(const phy_interface_rrc_lte::phy_cell_t* cell) final; private: void run_thread() final; diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index eea54f863..dfc2e2eac 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -325,7 +325,7 @@ void phy::meas_stop() sfsync.meas_stop(); } -bool phy::cell_select(phy_cell_t* cell) +bool phy::cell_select(const phy_cell_t* cell) { return sfsync.cell_select(cell); } diff --git a/srsue/src/phy/sync.cc b/srsue/src/phy/sync.cc index 63b1680ae..72279710c 100644 --- a/srsue/src/phy/sync.cc +++ b/srsue/src/phy/sync.cc @@ -264,7 +264,7 @@ phy_interface_rrc_lte::cell_search_ret_t sync::cell_search(phy_interface_rrc_lte /* Cell select synchronizes to a new cell (e.g. during HO or during cell reselection on IDLE) or * re-synchronizes with the current cell if cell argument is NULL */ -bool sync::cell_select(phy_interface_rrc_lte::phy_cell_t* new_cell) +bool sync::cell_select(const phy_interface_rrc_lte::phy_cell_t* new_cell) { std::unique_lock ul(rrc_mutex); @@ -272,7 +272,7 @@ bool sync::cell_select(phy_interface_rrc_lte::phy_cell_t* new_cell) int cnt = 0; // Move state to IDLE - if (!new_cell) { + if (new_cell == nullptr) { Info("Cell Select: Starting cell resynchronization\n"); } else { if (!srslte_cellid_isvalid(new_cell->pci)) { @@ -298,12 +298,12 @@ bool sync::cell_select(phy_interface_rrc_lte::phy_cell_t* new_cell) srslte_ue_sync_reset(&ue_sync); /* Reconfigure cell if necessary */ - if (new_cell) { - cell.id = new_cell->pci; - if (!set_cell()) { - Error("Cell Select: Reconfiguring cell\n"); - return ret; - } + if (new_cell != nullptr) { + cell.id = new_cell->pci; + if (!set_cell()) { + Error("Cell Select: Reconfiguring cell\n"); + return ret; + } /* Select new frequency if necessary */ if ((int)new_cell->earfcn != current_earfcn) { diff --git a/srsue/src/stack/rrc/rrc.cc b/srsue/src/stack/rrc/rrc.cc index 446d95f62..19758a71c 100644 --- a/srsue/src/stack/rrc/rrc.cc +++ b/srsue/src/stack/rrc/rrc.cc @@ -1385,6 +1385,13 @@ void rrc::cell_search_completed(const phy_interface_rrc_lte::cell_search_ret_t& cell_searcher.trigger(cell_search_proc::cell_search_event_t{cs_ret, found_cell}); } +void rrc::cell_select_completed(bool cs_ret) +{ + cell_select_event_t ev{cs_ret}; + cell_searcher.trigger(ev); + cell_selector.trigger(ev); +} + /******************************************************************************* * * Interface from RRC measurements class diff --git a/srsue/src/stack/rrc/rrc_procedures.cc b/srsue/src/stack/rrc/rrc_procedures.cc index 18962a4d1..882ff1f64 100644 --- a/srsue/src/stack/rrc/rrc_procedures.cc +++ b/srsue/src/stack/rrc/rrc_procedures.cc @@ -49,26 +49,33 @@ proc_outcome_t rrc::cell_search_proc::init() /* Implements the SI acquisition procedure. Configures MAC/PHY scheduling to retrieve SI messages.*/ proc_outcome_t rrc::cell_search_proc::step() { - if (state == state_t::phy_cell_search) { - // Waits for cell search to complete - return proc_outcome_t::yield; - } else if (state == state_t::si_acquire) { - if (rrc_ptr->si_acquirer.run()) { + switch (state) { + case state_t::phy_cell_search: + case state_t::phy_cell_select: + // Waits for cell select/search to complete return proc_outcome_t::yield; - } - // SI Acquire has completed - if (si_acquire_fut.is_error()) { - Error("Failed to trigger SI acquire for SIB0\n"); - return proc_outcome_t::error; - } - Info("Completed successfully\n"); - return proc_outcome_t::success; - } else if (state == state_t::wait_measurement && std::isnormal(rrc_ptr->serving_cell->get_rsrp())) { - return check_sib(); + case state_t::si_acquire: + return step_si_acquire(); + case state_t::wait_measurement: + return step_wait_measurement(); } return proc_outcome_t::yield; } +proc_outcome_t rrc::cell_search_proc::step_si_acquire() +{ + if (rrc_ptr->si_acquirer.run()) { + return proc_outcome_t::yield; + } + // SI Acquire has completed + if (si_acquire_fut.is_error()) { + Error("Failed to trigger SI acquire for SIB0\n"); + return proc_outcome_t::error; + } + Info("Completed successfully\n"); + return proc_outcome_t::success; +} + proc_outcome_t rrc::cell_search_proc::handle_cell_found(const phy_interface_rrc_lte::phy_cell_t& new_cell) { Info("Cell found in this frequency. Setting new serving cell...\n"); @@ -82,27 +89,17 @@ proc_outcome_t rrc::cell_search_proc::handle_cell_found(const phy_interface_rrc_ rrc_ptr->set_serving_cell(new_cell, false); // set new serving cell in PHY - if (not rrc_ptr->phy->cell_select(&rrc_ptr->serving_cell->phy_cell)) { - Error("Couldn't select new serving cell\n"); - return proc_outcome_t::error; - } - - if (not rrc_ptr->phy->cell_is_camping()) { - Warning("Could not camp on found cell.\n"); - return proc_outcome_t::error; - } + state = state_t::phy_cell_select; + rrc_ptr->stack->start_cell_select(&rrc_ptr->serving_cell->phy_cell); + return proc_outcome_t::yield; +} +proc_outcome_t rrc::cell_search_proc::step_wait_measurement() +{ if (not std::isnormal(rrc_ptr->serving_cell->get_rsrp())) { - Info("No valid measurement found for the serving cell. Wait for valid measurement...\n"); - state = state_t::wait_measurement; return proc_outcome_t::yield; } - return check_sib(); -} - -proc_outcome_t rrc::cell_search_proc::check_sib() -{ if (rrc_ptr->serving_cell->has_sib1()) { Info("Cell has SIB1\n"); // What do we do???? @@ -119,6 +116,30 @@ proc_outcome_t rrc::cell_search_proc::check_sib() return step(); } +proc_outcome_t rrc::cell_search_proc::react(const cell_select_event_t& event) +{ + if (state != state_t::phy_cell_select) { + Warning("Received unexpected cell search result\n"); + return proc_outcome_t::yield; + } + + if (not event.cs_ret) { + Error("Couldn't select new serving cell\n"); + return proc_outcome_t::error; + } + + if (not rrc_ptr->phy->cell_is_camping()) { + Warning("Could not camp on found cell.\n"); + return proc_outcome_t::error; + } + + if (not std::isnormal(rrc_ptr->serving_cell->get_rsrp())) { + Info("No valid measurement found for the serving cell. Wait for valid measurement...\n"); + } + state = state_t::wait_measurement; + return proc_outcome_t::yield; +} + proc_outcome_t rrc::cell_search_proc::react(const cell_search_event_t& event) { if (state != state_t::phy_cell_search) { @@ -357,7 +378,25 @@ proc_outcome_t rrc::cell_selection_proc::init() return step(); } -proc_outcome_t rrc::cell_selection_proc::step_cell_selection() +proc_outcome_t rrc::cell_selection_proc::react(const cell_select_event_t& event) +{ + switch (state) { + case search_state_t::cell_selection: { + return step_cell_selection(event); + } + case search_state_t::serv_cell_camp: { + return step_serv_cell_camp(event); + } + case search_state_t::cell_search: + // cell search may call cell_select + break; + default: + Warning("Unexpected cell selection event received\n"); + } + return proc_outcome_t::yield; +} + +proc_outcome_t rrc::cell_selection_proc::start_cell_selection() { Info("Current serving cell: %s\n", rrc_ptr->serving_cell->to_string().c_str()); @@ -377,32 +416,20 @@ proc_outcome_t rrc::cell_selection_proc::step_cell_selection() Info("Selected cell: %s\n", rrc_ptr->serving_cell->to_string().c_str()); /* BLOCKING CALL */ - if (rrc_ptr->phy->cell_select(&rrc_ptr->serving_cell->phy_cell)) { - Info("Wait PHY to be in-synch\n"); - state = search_state_t::wait_in_sync; - rrc_ptr->phy_sync_state = phy_unknown_sync; - return step(); - } else { - rrc_ptr->phy_sync_state = phy_unknown_sync; - Error("Could not camp on serving cell.\n"); - discard_serving = true; - // Continue to next neighbour cell - } + state = search_state_t::cell_selection; + rrc_ptr->stack->start_cell_select(&rrc_ptr->serving_cell->phy_cell); + return proc_outcome_t::yield; } } + // Iteration over neighbor cells is over. + if (rrc_ptr->phy_sync_state == phy_in_sync && rrc_ptr->cell_selection_criteria(rrc_ptr->serving_cell->get_rsrp())) { if (not rrc_ptr->phy->cell_is_camping()) { Info("Serving cell %s is in-sync but not camping. Selecting it...\n", rrc_ptr->serving_cell->to_string().c_str()); - /* BLOCKING CALL */ - if (rrc_ptr->phy->cell_select(&rrc_ptr->serving_cell->phy_cell)) { - Info("Selected serving cell OK.\n"); - } else { - rrc_ptr->phy_sync_state = phy_unknown_sync; - rrc_ptr->serving_cell->set_rsrp(-INFINITY); - Error("Could not camp on serving cell.\n"); - return proc_outcome_t::error; - } + state = search_state_t::serv_cell_camp; + rrc_ptr->stack->start_cell_select(&rrc_ptr->serving_cell->phy_cell); + return proc_outcome_t::yield; } cs_result = cs_result_t::same_cell; return proc_outcome_t::success; @@ -417,22 +444,54 @@ proc_outcome_t rrc::cell_selection_proc::step_cell_selection() return step(); } +proc_outcome_t rrc::cell_selection_proc::step_cell_selection(const cell_select_event_t& event) +{ + rrc_ptr->phy_sync_state = phy_unknown_sync; + + if (event.cs_ret) { + // successful selection + Info("Wait PHY to be in-synch\n"); + state = search_state_t::wait_in_sync; + return step(); + } + + Error("Could not camp on serving cell.\n"); + discard_serving = true; + // Continue to next neighbour cell + ++neigh_index; + return start_cell_selection(); +} + +srslte::proc_outcome_t rrc::cell_selection_proc::step_serv_cell_camp(const cell_select_event_t& event) +{ + // if we are now camping, the proc was successful + if (event.cs_ret) { + Info("Selected serving cell OK.\n"); + cs_result = cs_result_t::same_cell; + } else { + rrc_ptr->phy_sync_state = phy_unknown_sync; + rrc_ptr->serving_cell->set_rsrp(-INFINITY); + Error("Could not camp on serving cell.\n"); + } + + return event.cs_ret ? proc_outcome_t::success : proc_outcome_t::error; +} + proc_outcome_t rrc::cell_selection_proc::step_wait_in_sync() { if (rrc_ptr->phy_sync_state == phy_in_sync) { if (rrc_ptr->cell_selection_criteria(rrc_ptr->serving_cell->get_rsrp())) { Info("PHY is in SYNC and cell selection passed\n"); - serv_cell_cfg_fut = rrc_ptr->serv_cell_cfg.get_future(); if (not rrc_ptr->serv_cell_cfg.launch(&serv_cell_cfg_fut, rrc_ptr->ue_required_sibs)) { return proc_outcome_t::error; } state = search_state_t::cell_config; } else { Info("PHY is in SYNC but cell selection did not pass. Go back to select step.\n"); - neigh_index = 0; cs_result = cs_result_t::no_cell; - state = search_state_t::cell_selection; + neigh_index = 0; // TODO: go back to the start? discard_serving = true; // Discard this cell + return start_cell_selection(); } } return proc_outcome_t::yield; @@ -467,16 +526,19 @@ proc_outcome_t rrc::cell_selection_proc::step_cell_config() } Error("While configuring serving cell\n"); // resume cell selection - state = search_state_t::cell_selection; ++neigh_index; - return step(); + return start_cell_selection(); } proc_outcome_t rrc::cell_selection_proc::step() { switch (state) { case search_state_t::cell_selection: - return step_cell_selection(); + // this state waits for phy event + return proc_outcome_t::yield; + case search_state_t::serv_cell_camp: + // this state waits for phy event + return proc_outcome_t::yield; case search_state_t::wait_in_sync: return step_wait_in_sync(); case search_state_t::cell_config: @@ -654,7 +716,7 @@ proc_outcome_t rrc::connection_request_proc::step() } Info("Waiting for RRCConnectionSetup/Reject or expiry\n"); - state = state_t::wait_t300; + state = state_t::wait_t300; return step(); } else if (state == state_t::wait_t300) { diff --git a/srsue/src/stack/ue_stack_lte.cc b/srsue/src/stack/ue_stack_lte.cc index 49dcb5b91..db39388a1 100644 --- a/srsue/src/stack/ue_stack_lte.cc +++ b/srsue/src/stack/ue_stack_lte.cc @@ -319,7 +319,6 @@ void ue_stack_lte::start_prach_configuration() }); } - /******************** * RRC Interface *******************/ @@ -334,4 +333,13 @@ void ue_stack_lte::start_cell_search() }); } +void ue_stack_lte::start_cell_select(const phy_interface_rrc_lte::phy_cell_t* phy_cell) +{ + background_tasks.push_task([this, phy_cell](uint32_t worker_id) { + bool ret = phy->cell_select(phy_cell); + // notify back RRC + pending_tasks.push(background_queue_id, [this, ret]() { rrc.cell_select_completed(ret); }); + }); +} + } // namespace srsue diff --git a/srsue/test/ttcn3/hdr/lte_ttcn3_phy.h b/srsue/test/ttcn3/hdr/lte_ttcn3_phy.h index ca15b9d3a..c5742fc80 100644 --- a/srsue/test/ttcn3/hdr/lte_ttcn3_phy.h +++ b/srsue/test/ttcn3/hdr/lte_ttcn3_phy.h @@ -87,7 +87,7 @@ public: // Cell search and selection procedures cell_search_ret_t cell_search(phy_cell_t* found_cell); - bool cell_select(phy_cell_t* cell); + bool cell_select(const phy_cell_t* cell) override; bool cell_is_camping(); void reset(); diff --git a/srsue/test/ttcn3/src/lte_ttcn3_phy.cc b/srsue/test/ttcn3/src/lte_ttcn3_phy.cc index 7b1ac27df..7a2c6744f 100644 --- a/srsue/test/ttcn3/src/lte_ttcn3_phy.cc +++ b/srsue/test/ttcn3/src/lte_ttcn3_phy.cc @@ -153,7 +153,7 @@ phy_interface_rrc_lte::cell_search_ret_t lte_ttcn3_phy::cell_search(phy_cell_t* return ret; }; -bool lte_ttcn3_phy::cell_select(phy_cell_t* rrc_cell) +bool lte_ttcn3_phy::cell_select(const phy_cell_t* rrc_cell) { // try to find RRC cell in current cell map for (auto& cell : cells) { diff --git a/srsue/test/upper/rrc_meas_test.cc b/srsue/test/upper/rrc_meas_test.cc index 8af9a3aac..39adfb62c 100644 --- a/srsue/test/upper/rrc_meas_test.cc +++ b/srsue/test/upper/rrc_meas_test.cc @@ -54,7 +54,7 @@ public: void set_config_mbsfn_mcch(const srslte::mcch_msg_t& mcch) override {} cell_search_ret_t cell_search(phy_cell_t* cell) override { return {}; } bool cell_is_camping() override { return false; } - bool cell_select(phy_cell_t* cell = nullptr) override { return false; } + bool cell_select(const phy_cell_t* cell = nullptr) override { return false; } void reset() override {} void enable_pregen_signals(bool enable) override {}