Add support for RRC redirect.

master
Fabian Eckermann 3 years ago committed by Fabian Eckermann
parent dcf178a8a5
commit 12cc7cb4d7

@ -96,7 +96,6 @@ struct phy_args_t {
srsran::channel::args_t dl_channel_args; srsran::channel::args_t dl_channel_args;
srsran::channel::args_t ul_channel_args; srsran::channel::args_t ul_channel_args;
}; };
/* RAT agnostic Interface MAC -> PHY */ /* RAT agnostic Interface MAC -> PHY */
@ -158,7 +157,7 @@ public:
virtual void meas_stop() = 0; virtual void meas_stop() = 0;
/* Cell search and selection procedures */ /* Cell search and selection procedures */
virtual bool cell_search() = 0; virtual bool cell_search(int earfcn) = 0;
virtual bool cell_select(phy_cell_t cell) = 0; virtual bool cell_select(phy_cell_t cell) = 0;
virtual bool cell_is_camping() = 0; virtual bool cell_is_camping() = 0;
}; };

@ -76,7 +76,7 @@ class phy_dummy_interface : public phy_interface_rrc_lte
void meas_stop() override {} void meas_stop() override {}
/* Cell search and selection procedures */ /* Cell search and selection procedures */
bool cell_search() override { return true; } bool cell_search(int earfcn) override { return true; }
bool cell_select(phy_cell_t cell) override { return true; } bool cell_select(phy_cell_t cell) override { return true; }
bool cell_is_camping() override { return false; } bool cell_is_camping() override { return false; }
}; };

@ -53,7 +53,7 @@ public:
void meas_stop() final {} void meas_stop() final {}
/* Cell search and selection procedures */ /* Cell search and selection procedures */
bool cell_search() final { return false; } bool cell_search(int earfcn) final { return false; }
bool cell_select(phy_cell_t cell) final { return false; } bool cell_select(phy_cell_t cell) final { return false; }
bool cell_is_camping() final { return false; } bool cell_is_camping() final { return false; }

@ -68,7 +68,7 @@ public:
/********** RRC INTERFACE ********************/ /********** RRC INTERFACE ********************/
bool cell_search() final; bool cell_search(int earfcn) final;
bool cell_select(phy_cell_t cell) final; bool cell_select(phy_cell_t cell) final;
// Sets the new PHY configuration for the given CC. The configuration is applied in the background. The notify() // Sets the new PHY configuration for the given CC. The configuration is applied in the background. The notify()

@ -68,7 +68,7 @@ public:
// RRC interface for controling the SYNC state // RRC interface for controling the SYNC state
bool cell_search_init(); bool cell_search_init();
rrc_interface_phy_lte::cell_search_ret_t cell_search_start(phy_cell_t* cell); rrc_interface_phy_lte::cell_search_ret_t cell_search_start(phy_cell_t* cell, int earfcn);
bool cell_select_init(phy_cell_t cell); bool cell_select_init(phy_cell_t cell);
bool cell_select_start(phy_cell_t cell); bool cell_select_start(phy_cell_t cell);
bool cell_is_camping(); bool cell_is_camping();

@ -40,7 +40,9 @@ public:
struct cell_sel_cmd { struct cell_sel_cmd {
phy_cell_t phy_cell; phy_cell_t phy_cell;
}; };
struct cell_search_cmd {}; struct cell_search_cmd {
int earfcn;
};
struct in_sync_ev { struct in_sync_ev {
static const bool log_verbose = false; static const bool log_verbose = false;
}; };
@ -52,7 +54,7 @@ public:
// PHY procedures interfaces // PHY procedures interfaces
bool start_cell_select(const phy_cell_t& phy_cell, srsran::event_observer<bool> observer = {}); bool start_cell_select(const phy_cell_t& phy_cell, srsran::event_observer<bool> observer = {});
bool start_cell_search(srsran::event_observer<cell_srch_res> observer); bool start_cell_search(srsran::event_observer<cell_srch_res> observer, int earfcn);
void cell_search_completed(cell_search_ret_t cs_ret, phy_cell_t found_cell); void cell_search_completed(cell_search_ret_t cs_ret, phy_cell_t found_cell);
void cell_selection_completed(bool outcome); void cell_selection_completed(bool outcome);
void in_sync(); void in_sync();
@ -117,7 +119,7 @@ public:
// clang-format on // clang-format on
}; };
struct searching_cell { struct searching_cell {
void enter(phy_controller* f); void enter(phy_controller* f, const cell_search_cmd& ev);
}; };
private: private:

@ -211,6 +211,9 @@ private:
meas_cell_list<meas_cell_nr> meas_cells_nr; meas_cell_list<meas_cell_nr> meas_cells_nr;
// if this is set to a valid earfcn, this earfcn will be used for cell search
int cell_search_earfcn = -1;
bool initiated = false; bool initiated = false;
asn1::rrc::reest_cause_e m_reest_cause = asn1::rrc::reest_cause_e::nulltype; asn1::rrc::reest_cause_e m_reest_cause = asn1::rrc::reest_cause_e::nulltype;
uint16_t m_reest_rnti = 0; uint16_t m_reest_rnti = 0;
@ -328,7 +331,8 @@ private:
bool con_reconfig_ho(const asn1::rrc::rrc_conn_recfg_s& reconfig); bool con_reconfig_ho(const asn1::rrc::rrc_conn_recfg_s& reconfig);
void ho_failed(); void ho_failed();
void start_go_idle(); void start_go_idle();
void rrc_connection_release(const std::string& cause); void handle_rrc_connection_release(const asn1::rrc::rrc_conn_release_s& release);
void start_rrc_redirect(uint32_t new_dl_earfcn);
void radio_link_failure_push_cmd(); void radio_link_failure_push_cmd();
void radio_link_failure_process(); void radio_link_failure_process();
void leave_connected(); void leave_connected();

@ -342,12 +342,12 @@ bool phy::cell_select(phy_cell_t cell)
// This function executes one part of the procedure immediatly and returns to continue in the background. // This function executes one part of the procedure immediatly and returns to continue in the background.
// When it returns, the caller thread can expect the PHY to have switched to IDLE and have stopped all DL/UL/PRACH // When it returns, the caller thread can expect the PHY to have switched to IDLE and have stopped all DL/UL/PRACH
// processing. // processing. If a valid EARFCN (>0) is given, this is used for cell search.
bool phy::cell_search() bool phy::cell_search(int earfcn)
{ {
sfsync.scell_sync_stop(); sfsync.scell_sync_stop();
if (sfsync.cell_search_init()) { if (sfsync.cell_search_init()) {
cmd_worker_cell.add_cmd([this]() { cmd_worker_cell.add_cmd([this, earfcn]() {
// Wait SYNC transitions to IDLE // Wait SYNC transitions to IDLE
sfsync.wait_idle(); sfsync.wait_idle();
@ -355,7 +355,7 @@ bool phy::cell_search()
reset(); reset();
phy_cell_t found_cell = {}; phy_cell_t found_cell = {};
rrc_interface_phy_lte::cell_search_ret_t ret = sfsync.cell_search_start(&found_cell); rrc_interface_phy_lte::cell_search_ret_t ret = sfsync.cell_search_start(&found_cell, earfcn);
stack->cell_search_complete(ret, found_cell); stack->cell_search_complete(ret, found_cell);
}); });
} else { } else {

@ -179,10 +179,10 @@ void sync::reset()
* *
*/ */
/* A call to cell_search() finds the strongest cell in the set of supported EARFCNs. When the first cell is found, /* A call to cell_search() finds the strongest cell at a given EARFCN or in the set of supported EARFCNs. When the first
* returns 1 and stores cell information and RSRP values in the pointers (if provided). If a cell is not found in the * cell is found, returns 1 and stores cell information and RSRP values in the pointers (if provided). If a cell is not
* current frequency it moves to the next one and the next call to cell_search() will look in the next EARFCN in the * found in the current frequency it moves to the next one and the next call to cell_search() will look in the next
* set. If no cells are found in any frequency it returns 0. If error returns -1. * EARFCN in the set. If no cells are found in any frequency it returns 0. If error returns -1.
* *
* The first part of the procedure (call to _init()) moves the PHY To IDLE, ensuring that no UL/DL/PRACH will happen * The first part of the procedure (call to _init()) moves the PHY To IDLE, ensuring that no UL/DL/PRACH will happen
* *
@ -197,7 +197,6 @@ bool sync::cell_search_init()
} }
// Move state to IDLE // Move state to IDLE
Info("Cell Search: Start EARFCN index=%u/%zd", cellsearch_earfcn_index, worker_com->args->dl_earfcn_list.size());
phy_state.go_idle(); phy_state.go_idle();
// Stop all intra-frequency measurement before changing frequency // Stop all intra-frequency measurement before changing frequency
@ -208,10 +207,16 @@ bool sync::cell_search_init()
return true; return true;
} }
rrc_interface_phy_lte::cell_search_ret_t sync::cell_search_start(phy_cell_t* found_cell) rrc_interface_phy_lte::cell_search_ret_t sync::cell_search_start(phy_cell_t* found_cell, int earfcn)
{ {
std::unique_lock<std::mutex> ul(rrc_mutex); std::unique_lock<std::mutex> ul(rrc_mutex);
if (earfcn < 0) {
Info("Cell Search: Start EARFCN index=%u/%zd", cellsearch_earfcn_index, worker_com->args->dl_earfcn_list.size());
} else {
Info("Cell Search: Start EARFCN=%d", earfcn);
}
rrc_interface_phy_lte::cell_search_ret_t ret = {}; rrc_interface_phy_lte::cell_search_ret_t ret = {};
ret.found = rrc_interface_phy_lte::cell_search_ret_t::ERROR; ret.found = rrc_interface_phy_lte::cell_search_ret_t::ERROR;
ret.last_freq = rrc_interface_phy_lte::cell_search_ret_t::NO_MORE_FREQS; ret.last_freq = rrc_interface_phy_lte::cell_search_ret_t::NO_MORE_FREQS;
@ -229,16 +234,20 @@ rrc_interface_phy_lte::cell_search_ret_t sync::cell_search_start(phy_cell_t* fou
Info("SYNC: Setting Cell Search sampling rate"); Info("SYNC: Setting Cell Search sampling rate");
} }
if (earfcn < 0) {
try { try {
if (current_earfcn != (int)worker_com->args->dl_earfcn_list.at(cellsearch_earfcn_index)) { if (current_earfcn != (int)worker_com->args->dl_earfcn_list.at(cellsearch_earfcn_index)) {
current_earfcn = (int)worker_com->args->dl_earfcn_list[cellsearch_earfcn_index]; current_earfcn = (int)worker_com->args->dl_earfcn_list[cellsearch_earfcn_index];
Info("Cell Search: changing frequency to EARFCN=%d", current_earfcn);
set_frequency();
} }
} catch (const std::out_of_range& oor) { } catch (const std::out_of_range& oor) {
Error("Index %d is not a valid EARFCN element.", cellsearch_earfcn_index); Error("Index %d is not a valid EARFCN element.", cellsearch_earfcn_index);
return ret; return ret;
} }
} else {
current_earfcn = earfcn;
}
Info("Cell Search: changing frequency to EARFCN=%d", current_earfcn);
set_frequency();
// Move to CELL SEARCH and wait to finish // Move to CELL SEARCH and wait to finish
Info("Cell Search: Setting Cell search state"); Info("Cell Search: Setting Cell search state");
@ -266,7 +275,7 @@ rrc_interface_phy_lte::cell_search_ret_t sync::cell_search_start(phy_cell_t* fou
} }
cellsearch_earfcn_index++; cellsearch_earfcn_index++;
if (cellsearch_earfcn_index >= worker_com->args->dl_earfcn_list.size()) { if (cellsearch_earfcn_index >= worker_com->args->dl_earfcn_list.size() or earfcn < 0) {
Info("Cell Search: No more frequencies in the current EARFCN set"); Info("Cell Search: No more frequencies in the current EARFCN set");
cellsearch_earfcn_index = 0; cellsearch_earfcn_index = 0;
ret.last_freq = rrc_interface_phy_lte::cell_search_ret_t::NO_MORE_FREQS; ret.last_freq = rrc_interface_phy_lte::cell_search_ret_t::NO_MORE_FREQS;

@ -508,7 +508,7 @@ int main(int argc, char** argv)
phy_test->start(); phy_test->start();
// 1. Cell search // 1. Cell search
TESTASSERT(phy_test->get_phy_interface_rrc()->cell_search()); TESTASSERT(phy_test->get_phy_interface_rrc()->cell_search(-1));
TESTASSERT(phy_test->get_stack()->wait_cell_search(default_timeout)); TESTASSERT(phy_test->get_stack()->wait_cell_search(default_timeout));
TESTASSERT(phy_test->get_stack()->cell_search_ret.found == TESTASSERT(phy_test->get_stack()->cell_search_ret.found ==
srsue::rrc_interface_phy_lte::cell_search_ret_t::CELL_FOUND); srsue::rrc_interface_phy_lte::cell_search_ret_t::CELL_FOUND);

@ -166,13 +166,13 @@ void phy_controller::selecting_cell::wait_in_sync::enter(selecting_cell* f)
*************************************/ *************************************/
//! Searches for a cell in the current frequency and retrieves SIB1 if not retrieved yet //! Searches for a cell in the current frequency and retrieves SIB1 if not retrieved yet
bool phy_controller::start_cell_search(srsran::event_observer<cell_srch_res> observer) bool phy_controller::start_cell_search(srsran::event_observer<cell_srch_res> observer, int earfcn)
{ {
if (is_in_state<searching_cell>()) { if (is_in_state<searching_cell>()) {
fsmInfo("Cell search already launched."); fsmInfo("Cell search already launched.");
return true; return true;
} }
trigger(cell_search_cmd{}); trigger(cell_search_cmd{earfcn});
if (not is_in_state<searching_cell>()) { if (not is_in_state<searching_cell>()) {
fsmWarning("Failed to launch cell search"); fsmWarning("Failed to launch cell search");
return false; return false;
@ -186,10 +186,10 @@ void phy_controller::cell_search_completed(cell_search_ret_t cs_ret, phy_cell_t
trigger(cell_srch_res{cs_ret, found_cell}); trigger(cell_srch_res{cs_ret, found_cell});
} }
void phy_controller::searching_cell::enter(phy_controller* f) void phy_controller::searching_cell::enter(phy_controller* f, const cell_search_cmd& ev)
{ {
otherfsmInfo(f, "Initiating Cell search"); otherfsmInfo(f, "Initiating Cell search");
f->phy->cell_search(); f->phy->cell_search(ev.earfcn);
} }
void phy_controller::handle_cell_search_res(searching_cell& s, const cell_srch_res& result) void phy_controller::handle_cell_search_res(searching_cell& s, const cell_srch_res& result)

@ -1153,8 +1153,9 @@ void rrc::handle_rrc_con_reconfig(uint32_t lcid, const rrc_conn_recfg_s& reconfi
} }
/* Actions upon reception of RRCConnectionRelease 5.3.8.3 */ /* Actions upon reception of RRCConnectionRelease 5.3.8.3 */
void rrc::rrc_connection_release(const std::string& cause) void rrc::handle_rrc_connection_release(const asn1::rrc::rrc_conn_release_s& release)
{ {
std::string cause = release.crit_exts.c1().rrc_conn_release_r8().release_cause.to_string();
// Save idleModeMobilityControlInfo, etc. // Save idleModeMobilityControlInfo, etc.
srsran::console("Received RRC Connection Release (releaseCause: %s)\n", cause.c_str()); srsran::console("Received RRC Connection Release (releaseCause: %s)\n", cause.c_str());
@ -1164,6 +1165,36 @@ void rrc::rrc_connection_release(const std::string& cause)
// delay actions by 60ms as per 5.3.8.3 // delay actions by 60ms as per 5.3.8.3
task_sched.defer_callback(60, [this]() { start_go_idle(); }); task_sched.defer_callback(60, [this]() { start_go_idle(); });
uint32_t earfcn = 0;
if (release.crit_exts.c1().rrc_conn_release_r8().redirected_carrier_info_present) {
switch (release.crit_exts.c1().rrc_conn_release_r8().redirected_carrier_info.type()) {
case asn1::rrc::redirected_carrier_info_c::types_opts::options::eutra:
earfcn = release.crit_exts.c1().rrc_conn_release_r8().redirected_carrier_info.eutra();
break;
default:
srsran::console("Ignoring RedirectedCarrierInfo with unsupported type (%s)\n",
release.crit_exts.c1().rrc_conn_release_r8().redirected_carrier_info.type().to_string());
break;
}
if (earfcn != 0) {
srsran::console("RedirectedCarrierInfo present (type %s, earfcn: %d) - Redirecting\n",
release.crit_exts.c1().rrc_conn_release_r8().redirected_carrier_info.type().to_string(),
earfcn);
logger.info("RedirectedCarrierInfo present (type %s, earfcn: %d) - Redirecting",
release.crit_exts.c1().rrc_conn_release_r8().redirected_carrier_info.type().to_string(),
earfcn);
// delay actions by 60ms as per 5.3.8.3
task_sched.defer_callback(60, [this, earfcn]() { start_rrc_redirect(earfcn); });
}
}
}
void rrc::start_rrc_redirect(uint32_t new_dl_earfcn)
{
cell_search_earfcn = (int)new_dl_earfcn;
plmn_search();
} }
/// TS 36.331, 5.3.12 - UE actions upon leaving RRC_CONNECTED /// TS 36.331, 5.3.12 - UE actions upon leaving RRC_CONNECTED
@ -1818,7 +1849,7 @@ void rrc::parse_dl_dcch(uint32_t lcid, unique_byte_buffer_t pdu)
handle_ue_capability_enquiry(c1->ue_cap_enquiry()); handle_ue_capability_enquiry(c1->ue_cap_enquiry());
break; break;
case dl_dcch_msg_type_c::c1_c_::types::rrc_conn_release: case dl_dcch_msg_type_c::c1_c_::types::rrc_conn_release:
rrc_connection_release(c1->rrc_conn_release().crit_exts.c1().rrc_conn_release_r8().release_cause.to_string()); handle_rrc_connection_release(c1->rrc_conn_release());
break; break;
case dl_dcch_msg_type_c::c1_c_::types::ue_info_request_r9: case dl_dcch_msg_type_c::c1_c_::types::ue_info_request_r9:
transaction_id = c1->ue_info_request_r9().rrc_transaction_id; transaction_id = c1->ue_info_request_r9().rrc_transaction_id;

@ -41,7 +41,7 @@ proc_outcome_t rrc::cell_search_proc::init()
{ {
Info("Starting..."); Info("Starting...");
state = state_t::phy_cell_search; state = state_t::phy_cell_search;
if (not rrc_ptr->phy_ctrl->start_cell_search(rrc_ptr->cell_searcher)) { if (not rrc_ptr->phy_ctrl->start_cell_search(rrc_ptr->cell_searcher, rrc_ptr->cell_search_earfcn)) {
Warning("Failed to initiate Cell Search."); Warning("Failed to initiate Cell Search.");
return proc_outcome_t::error; return proc_outcome_t::error;
} }
@ -1256,12 +1256,15 @@ proc_outcome_t rrc::go_idle_proc::step()
void rrc::go_idle_proc::then(const srsran::proc_state_t& result) void rrc::go_idle_proc::then(const srsran::proc_state_t& result)
{ {
// only start cell reselection if no RRC redirect is present (redirect will trigger a cell search)
if (rrc_ptr->cell_search_earfcn < 0) {
if (rrc_ptr->nas->is_registered() and not rrc_ptr->cell_reselector.launch()) { if (rrc_ptr->nas->is_registered() and not rrc_ptr->cell_reselector.launch()) {
rrc_ptr->logger.error("Failed to initiate a Cell Reselection procedure..."); rrc_ptr->logger.error("Failed to initiate a Cell Reselection procedure...");
return; return;
} }
rrc_ptr->callback_list.add_proc(rrc_ptr->cell_reselector); rrc_ptr->callback_list.add_proc(rrc_ptr->cell_reselector);
} }
}
/************************************** /**************************************
* Cell Reselection procedure * Cell Reselection procedure
@ -1384,9 +1387,9 @@ proc_outcome_t rrc::connection_reest_proc::init(asn1::rrc::reest_cause_e cause)
reest_cellid = rrc_ptr->meas_cells.find_cell(reest_source_freq, reest_source_pci)->get_cell_id(); reest_cellid = rrc_ptr->meas_cells.find_cell(reest_source_freq, reest_source_pci)->get_cell_id();
Info("Starting... cause: \"%s\", UE context: {C-RNTI=0x%x, PCI=%d, CELL ID=%d}", Info("Starting... cause: \"%s\", UE context: {C-RNTI=0x%x, PCI=%d, CELL ID=%d}",
reest_cause == asn1::rrc::reest_cause_opts::recfg_fail reest_cause == asn1::rrc::reest_cause_opts::recfg_fail ? "Reconfiguration failure"
? "Reconfiguration failure" : cause == asn1::rrc::reest_cause_opts::ho_fail ? "Handover failure"
: cause == asn1::rrc::reest_cause_opts::ho_fail ? "Handover failure" : "Other failure", : "Other failure",
reest_rnti, reest_rnti,
reest_source_pci, reest_source_pci,
reest_cellid); reest_cellid);

@ -40,7 +40,7 @@ public:
void set_config_mbsfn_sib2(srsran::mbsfn_sf_cfg_t* cfg_list, uint32_t nof_cfgs) override {} void set_config_mbsfn_sib2(srsran::mbsfn_sf_cfg_t* cfg_list, uint32_t nof_cfgs) override {}
void set_config_mbsfn_sib13(const srsran::sib13_t& sib13) override {} void set_config_mbsfn_sib13(const srsran::sib13_t& sib13) override {}
void set_config_mbsfn_mcch(const srsran::mcch_msg_t& mcch) override {} void set_config_mbsfn_mcch(const srsran::mcch_msg_t& mcch) override {}
bool cell_search() override { return true; } bool cell_search(int earfcn) override { return true; }
bool cell_is_camping() override { return true; } bool cell_is_camping() override { return true; }
void deactivate_scells() override {} void deactivate_scells() override {}
bool cell_select(phy_cell_t cell) override bool cell_select(phy_cell_t cell) override

@ -81,7 +81,7 @@ int test_phy_ctrl_fsm()
TESTASSERT(phy_ctrl.is_in_sync()); TESTASSERT(phy_ctrl.is_in_sync());
// TEST: Correct initiation of Cell Search state // TEST: Correct initiation of Cell Search state
TESTASSERT(phy_ctrl.start_cell_search(csearch_tester)); TESTASSERT(phy_ctrl.start_cell_search(csearch_tester, -1));
TESTASSERT(not phy_ctrl.is_in_sync()); TESTASSERT(not phy_ctrl.is_in_sync());
// TEST: Cell Search only listens to a cell search result event // TEST: Cell Search only listens to a cell search result event

@ -69,7 +69,7 @@ public:
void set_mch_period_stop(uint32_t stop) override{}; void set_mch_period_stop(uint32_t stop) override{};
// Cell search and selection procedures // Cell search and selection procedures
bool cell_search() override; bool cell_search(int earfcn) override;
bool cell_select(phy_cell_t cell) override; bool cell_select(phy_cell_t cell) override;
bool cell_is_camping() override; bool cell_is_camping() override;

@ -87,7 +87,7 @@ void lte_ttcn3_phy::meas_stop() {}
// configured by the SS, including the ones that we should not even detect because // configured by the SS, including the ones that we should not even detect because
// their power is too weak. The cell search should only report the cells that // their power is too weak. The cell search should only report the cells that
// are actually visible though. // are actually visible though.
bool lte_ttcn3_phy::cell_search() bool lte_ttcn3_phy::cell_search(int earfcn)
{ {
std::lock_guard<std::mutex> lock(phy_mutex); std::lock_guard<std::mutex> lock(phy_mutex);

Loading…
Cancel
Save