refactor and simplification of cell selection procedure. Using now a SIB3 threshold to decide whether to select neighbor cell while in RRC_IDLE

This commit is contained in:
Francisco Paisana 2020-10-08 16:57:30 +01:00
parent 9ad1328bbd
commit 585d7c923a
6 changed files with 233 additions and 160 deletions

View File

@ -96,7 +96,7 @@ public:
uint32_t get_cell_id() const { return (uint32_t)sib1.cell_access_related_info.cell_id.to_number(); } uint32_t get_cell_id() const { return (uint32_t)sib1.cell_access_related_info.cell_id.to_number(); }
bool has_sibs(srslte::span<uint32_t> indexes) const; bool has_sibs(srslte::span<const uint32_t> indexes) const;
bool has_sib(uint32_t index) const; bool has_sib(uint32_t index) const;
bool has_sib1() const { return has_valid_sib1; } bool has_sib1() const { return has_valid_sib1; }
bool has_sib2() const { return has_valid_sib2; } bool has_sib2() const { return has_valid_sib2; }

View File

@ -125,21 +125,24 @@ public:
explicit cell_selection_proc(rrc* parent_); explicit cell_selection_proc(rrc* parent_);
srslte::proc_outcome_t init(std::vector<uint32_t> required_sibs_ = {}); srslte::proc_outcome_t init(std::vector<uint32_t> required_sibs_ = {});
srslte::proc_outcome_t step(); srslte::proc_outcome_t step();
void then(const srslte::proc_result_t<cs_result_t>& proc_result) const;
cs_result_t get_result() const { return cs_result; } cs_result_t get_result() const { return cs_result; }
static const char* name() { return "Cell Selection"; } static const char* name() { return "Cell Selection"; }
srslte::proc_outcome_t react(const bool& event); srslte::proc_outcome_t react(const bool& event);
void then(const srslte::proc_result_t<cs_result_t>& proc_result) const;
private: private:
srslte::proc_outcome_t start_serv_cell_selection(); srslte::proc_outcome_t start_next_cell_selection();
srslte::proc_outcome_t start_cell_selection();
srslte::proc_outcome_t step_cell_selection(const bool& event);
srslte::proc_outcome_t step_serv_cell_camp(const bool& event);
srslte::proc_outcome_t step_cell_search(); srslte::proc_outcome_t step_cell_search();
srslte::proc_outcome_t step_cell_config(); srslte::proc_outcome_t step_cell_config();
bool is_serv_cell_suitable() const;
bool is_sib_acq_required() const;
srslte::proc_outcome_t set_proc_complete();
srslte::proc_outcome_t start_phy_cell_selection(const meas_cell& cell);
srslte::proc_outcome_t start_sib_acquisition();
// consts // consts
rrc* rrc_ptr; rrc* rrc_ptr;
meas_cell_list* meas_cells;
// state variables // state variables
enum class search_state_t { cell_selection, serv_cell_camp, cell_config, cell_search }; enum class search_state_t { cell_selection, serv_cell_camp, cell_config, cell_search };
@ -151,6 +154,7 @@ private:
srslte::proc_future_t<void> serv_cell_cfg_fut; srslte::proc_future_t<void> serv_cell_cfg_fut;
bool discard_serving = false, cell_search_called = false; bool discard_serving = false, cell_search_called = false;
std::vector<uint32_t> required_sibs = {}; std::vector<uint32_t> required_sibs = {};
phy_cell_t init_serv_cell;
}; };
class rrc::plmn_search_proc class rrc::plmn_search_proc

View File

@ -471,7 +471,7 @@ void rrc::in_sync()
// Cell selection criteria Section 5.2.3.2 of 36.304 // Cell selection criteria Section 5.2.3.2 of 36.304
bool rrc::cell_selection_criteria(float rsrp, float rsrq) bool rrc::cell_selection_criteria(float rsrp, float rsrq)
{ {
return std::isnormal(rsrp) && (get_srxlev(rsrp) > 0 || !meas_cells.serving_cell().has_sib3()); return std::isnormal(rsrp) and (meas_cells.serving_cell().has_sib3() and get_srxlev(rsrp) > 0);
} }
float rrc::get_srxlev(float Qrxlevmeas) float rrc::get_srxlev(float Qrxlevmeas)
@ -1141,23 +1141,23 @@ void rrc::parse_pdu_bcch_dlsch(unique_byte_buffer_t pdu)
case sib_info_item_c::types::sib2: case sib_info_item_c::types::sib2:
if (not meas_cells.serving_cell().has_sib2()) { if (not meas_cells.serving_cell().has_sib2()) {
meas_cells.serving_cell().set_sib2(sib_list[i].sib2()); meas_cells.serving_cell().set_sib2(sib_list[i].sib2());
si_acquirer.trigger(si_acquire_proc::sib_received_ev{});
} }
handle_sib2(); handle_sib2();
si_acquirer.trigger(si_acquire_proc::sib_received_ev{});
break; break;
case sib_info_item_c::types::sib3: case sib_info_item_c::types::sib3:
if (not meas_cells.serving_cell().has_sib3()) { if (not meas_cells.serving_cell().has_sib3()) {
meas_cells.serving_cell().set_sib3(sib_list[i].sib3()); meas_cells.serving_cell().set_sib3(sib_list[i].sib3());
si_acquirer.trigger(si_acquire_proc::sib_received_ev{});
} }
handle_sib3(); handle_sib3();
si_acquirer.trigger(si_acquire_proc::sib_received_ev{});
break; break;
case sib_info_item_c::types::sib13_v920: case sib_info_item_c::types::sib13_v920:
if (not meas_cells.serving_cell().has_sib13()) { if (not meas_cells.serving_cell().has_sib13()) {
meas_cells.serving_cell().set_sib13(sib_list[i].sib13_v920()); meas_cells.serving_cell().set_sib13(sib_list[i].sib13_v920());
si_acquirer.trigger(si_acquire_proc::sib_received_ev{});
} }
handle_sib13(); handle_sib13();
si_acquirer.trigger(si_acquire_proc::sib_received_ev{});
break; break;
default: default:
rrc_log->warning("SIB%d is not supported\n", sib_list[i].type().to_number()); rrc_log->warning("SIB%d is not supported\n", sib_list[i].type().to_number());

View File

@ -76,7 +76,7 @@ bool meas_cell::is_sib_scheduled(uint32_t sib_index) const
return sib_info_map.find(sib_index) != sib_info_map.end(); return sib_info_map.find(sib_index) != sib_info_map.end();
} }
bool meas_cell::has_sibs(srslte::span<uint32_t> indexes) const bool meas_cell::has_sibs(srslte::span<const uint32_t> indexes) const
{ {
for (uint32_t idx : indexes) { for (uint32_t idx : indexes) {
if (not has_sib(idx)) { if (not has_sib(idx)) {
@ -162,7 +162,8 @@ uint16_t meas_cell::get_mnc() const
********************************************/ ********************************************/
meas_cell_list::meas_cell_list(srslte::task_sched_handle task_sched_) : meas_cell_list::meas_cell_list(srslte::task_sched_handle task_sched_) :
serv_cell(new meas_cell(task_sched_.get_unique_timer())), task_sched(task_sched_) serv_cell(new meas_cell(task_sched_.get_unique_timer())),
task_sched(task_sched_)
{} {}
meas_cell* meas_cell_list::get_neighbour_cell_handle(uint32_t earfcn, uint32_t pci) meas_cell* meas_cell_list::get_neighbour_cell_handle(uint32_t earfcn, uint32_t pci)

View File

@ -378,7 +378,10 @@ rrc::serving_cell_config_proc::serving_cell_config_proc(rrc* parent_) :
*/ */
proc_outcome_t rrc::serving_cell_config_proc::init(const std::vector<uint32_t>& required_sibs_) proc_outcome_t rrc::serving_cell_config_proc::init(const std::vector<uint32_t>& required_sibs_)
{ {
// remove duplicates from list of required SIBs
required_sibs = required_sibs_; required_sibs = required_sibs_;
std::sort(required_sibs.begin(), required_sibs.end());
required_sibs.erase(std::unique(required_sibs.begin(), required_sibs.end()), required_sibs.end());
Info("Starting a Serving Cell Configuration Procedure\n"); Info("Starting a Serving Cell Configuration Procedure\n");
@ -450,95 +453,98 @@ proc_outcome_t rrc::serving_cell_config_proc::step()
* Cell Selection Procedure * Cell Selection Procedure
*************************************/ *************************************/
rrc::cell_selection_proc::cell_selection_proc(rrc* parent_) : rrc_ptr(parent_) {} constexpr std::array<uint32_t, 3> mandatory_sibs = {0, 1, 2};
/* rrc::cell_selection_proc::cell_selection_proc(rrc* parent_) : rrc_ptr(parent_), meas_cells(&rrc_ptr->meas_cells) {}
* Cell selection procedure 36.304 5.2.3
* Select the best cell to camp on among the list of known cells /// Verifies if serving cell passes selection criteria, UE is camping, and required SIBs were obtained
bool rrc::cell_selection_proc::is_serv_cell_suitable() const
{
return rrc_ptr->phy_ctrl->is_in_sync() and rrc_ptr->phy->cell_is_camping() and
rrc_ptr->cell_selection_criteria(meas_cells->serving_cell().get_rsrp()) and
meas_cells->serving_cell().has_sibs(mandatory_sibs);
}
/// Verifies if UE is camping, but not all required SIBs were obtained yet
bool rrc::cell_selection_proc::is_sib_acq_required() const
{
// cell passes the criteria that are available but is missing SIBs
return rrc_ptr->phy_ctrl->is_in_sync() and rrc_ptr->phy->cell_is_camping() and
not meas_cells->serving_cell().has_sibs(required_sibs) and
(not meas_cells->serving_cell().has_sib3() or
rrc_ptr->cell_selection_criteria(meas_cells->serving_cell().get_rsrp()));
}
/// Called on procedure exit to set result
proc_outcome_t rrc::cell_selection_proc::set_proc_complete()
{
if (is_serv_cell_suitable()) {
cs_result =
is_same_cell(init_serv_cell, meas_cells->serving_cell()) ? cs_result_t::same_cell : cs_result_t::changed_cell;
return proc_outcome_t::success;
}
cs_result = cs_result_t::no_cell;
return proc_outcome_t::error;
}
/**
* Initiation of Cell Selection Procedure. This procedure will iterate through serving cell and list of neighbors
* until it finds a suitable cell. To qualify as suitable, a cell has to meet the criteria:
* - the UE has to be able to camp on it
* - the cell RSRP passes the S-Criteria (see TS 36.304 5.2.3.2)
* - the passed SIBs were successfully acquired (including SIB3)
* @param required_sibs_ the list of SIBs to acquire
*/ */
proc_outcome_t rrc::cell_selection_proc::init(std::vector<uint32_t> required_sibs_) proc_outcome_t rrc::cell_selection_proc::init(std::vector<uint32_t> required_sibs_)
{ {
bool serv_cell_is_ok = rrc_ptr->phy_ctrl->is_in_sync() and rrc_ptr->phy->cell_is_camping(); if (required_sibs_.empty()) {
bool has_required_sibs = rrc_ptr->meas_cells.serving_cell().has_sibs(required_sibs_); required_sibs = rrc_ptr->ue_required_sibs;
if (rrc_ptr->meas_cells.nof_neighbours() == 0 and serv_cell_is_ok and has_required_sibs) { } else {
// don't bother with cell selection if there are no neighbours and we are already camping required_sibs = std::move(required_sibs_);
Debug("Skipping Cell Selection Procedure as there are no neighbour and cell is camping.\n"); }
cs_result = cs_result_t::same_cell; required_sibs.insert(required_sibs.end(), mandatory_sibs.begin(), mandatory_sibs.end());
return proc_outcome_t::success; init_serv_cell = meas_cells->serving_cell().phy_cell;
// Check if there are sronger neighbors in same EARFCN
const sib_type3_s* sib3 = meas_cells->serving_cell().sib3ptr();
uint32_t threshold = sib3 != nullptr ? sib3->cell_resel_serving_freq_info.thresh_serving_low * 2 : 5;
bool stronger_neigh_in_earfcn =
std::any_of(meas_cells->begin(), meas_cells->end(), [this, threshold](const unique_cell_t& c) {
return meas_cells->serving_cell().get_earfcn() == c->get_earfcn() and std::isnormal(c->get_rsrp()) and
meas_cells->serving_cell().get_rsrp() + threshold < c->get_rsrp();
});
// Skip cell selection if serving cell is suitable and there are no stronger neighbours in same earfcn
if (is_serv_cell_suitable() and not stronger_neigh_in_earfcn) {
Debug("Skipping cell selection procedure as there are no stronger neighbours in same EARFCN.\n");
return set_proc_complete();
} }
Info("Starting...\n"); Info("Starting...\n");
Info("Current neighbor cells: [%s]\n", rrc_ptr->meas_cells.print_neighbour_cells().c_str()); Info("Current neighbor cells: [%s]\n", meas_cells->print_neighbour_cells().c_str());
Info("Current PHY state: %s\n", rrc_ptr->phy_ctrl->is_in_sync() ? "in-sync" : "out-of-sync"); Info("Current PHY state: %s\n", rrc_ptr->phy_ctrl->is_in_sync() ? "in-sync" : "out-of-sync");
if (rrc_ptr->meas_cells.serving_cell().has_sib3()) { if (meas_cells->serving_cell().has_sib3()) {
Info("Cell selection criteria: Qrxlevmin=%f, Qrxlevminoffset=%f\n", Info("Cell selection criteria: Qrxlevmin=%f, Qrxlevminoffset=%f\n",
rrc_ptr->cell_resel_cfg.Qrxlevmin, rrc_ptr->cell_resel_cfg.Qrxlevmin,
rrc_ptr->cell_resel_cfg.Qrxlevminoffset); rrc_ptr->cell_resel_cfg.Qrxlevminoffset);
} else { } else {
Info("Cell selection criteria: not available\n"); Info("Cell selection criteria: not available\n");
} }
Info("Current serving cell: %s\n", rrc_ptr->meas_cells.serving_cell().to_string().c_str()); Info("Current serving cell: %s\n", meas_cells->serving_cell().to_string().c_str());
if (required_sibs_.empty()) {
required_sibs = rrc_ptr->ue_required_sibs;
} else {
required_sibs = std::move(required_sibs_);
}
neigh_index = 0; neigh_index = 0;
cs_result = cs_result_t::no_cell; cs_result = cs_result_t::no_cell;
discard_serving = false; discard_serving = false;
serv_cell_select_attempted = false; serv_cell_select_attempted = stronger_neigh_in_earfcn;
cell_search_called = false; cell_search_called = false;
if (serv_cell_is_ok and not has_required_sibs) { state = search_state_t::cell_selection;
state = search_state_t::cell_config; return start_next_cell_selection();
if (not rrc_ptr->serv_cell_cfg.launch(&serv_cell_cfg_fut, required_sibs)) {
Warning("Failed to launch %s procedure\n", rrc_ptr->serv_cell_cfg.get()->name());
return proc_outcome_t::error;
}
return proc_outcome_t::yield;
}
state = search_state_t::cell_selection;
return start_cell_selection();
} }
proc_outcome_t rrc::cell_selection_proc::react(const bool& event) /**
{ * Implementation of the Cell Selection Procedure main steps
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_serv_cell_selection()
{
if (rrc_ptr->phy_ctrl->is_in_sync() and rrc_ptr->phy->cell_is_camping()) {
cs_result = cs_result_t::same_cell;
return proc_outcome_t::success;
}
Info("Not camping on serving cell %s. Selecting it...\n", rrc_ptr->meas_cells.serving_cell().to_string().c_str());
state = search_state_t::serv_cell_camp;
if (not rrc_ptr->phy_ctrl->start_cell_select(rrc_ptr->meas_cells.serving_cell().phy_cell, rrc_ptr->cell_selector)) {
Error("Failed to launch PHY Cell Selection\n");
return proc_outcome_t::error;
}
serv_cell_select_attempted = true;
return proc_outcome_t::yield;
}
/** Cell selection procedure defined in 36.304 5.2
* The procedure starts with Stored Information Cell Selection. In our implementation, * The procedure starts with Stored Information Cell Selection. In our implementation,
* we use known neighbour cells. If that fails, the procedure continues with Initial Cell Selection . * we use known neighbour cells. If that fails, the procedure continues with Initial Cell Selection via cell search.
* *
* The standard requires the UE to attach to any cell that meets the Cell Selection Criteria on any frequency. * The standard requires the UE to attach to any cell that meets the Cell Selection Criteria on any frequency.
* On each frequency, the UE shall select the strongest cell. * On each frequency, the UE shall select the strongest cell.
@ -546,35 +552,24 @@ proc_outcome_t rrc::cell_selection_proc::start_serv_cell_selection()
* In our implementation, we will try to select the strongest cell of all known frequencies, if they are still * In our implementation, we will try to select the strongest cell of all known frequencies, if they are still
* available, or the strongest of all available cells we've found on any frequency. * available, or the strongest of all available cells we've found on any frequency.
*/ */
proc_outcome_t rrc::cell_selection_proc::start_cell_selection() proc_outcome_t rrc::cell_selection_proc::start_next_cell_selection()
{ {
// First of all, try to re-select the current serving cell if it meets the criteria // First of all, try to re-select the current serving cell if it meets the criteria
if (not serv_cell_select_attempted and if (not serv_cell_select_attempted) {
rrc_ptr->cell_selection_criteria(rrc_ptr->meas_cells.serving_cell().get_rsrp())) { serv_cell_select_attempted = true;
return start_serv_cell_selection(); return start_phy_cell_selection(meas_cells->serving_cell());
} }
// If serving is not available, use the stored information (known neighbours) to find the strongest // If serving is not available, use the stored information (known neighbours) to find the strongest
// cell that meets the selection criteria. // cell that meets the selection criteria.
for (; neigh_index < rrc_ptr->meas_cells.nof_neighbours(); ++neigh_index) { for (; neigh_index < meas_cells->nof_neighbours(); ++neigh_index) {
const meas_cell& neigh_cell = meas_cells->at(neigh_index);
/*TODO: CHECK that PLMN matches. Currently we don't receive SIB1 of neighbour cells /*TODO: CHECK that PLMN matches. Currently we don't receive SIB1 of neighbour cells
* meas_cells[i]->plmn_equals(selected_plmn_id) && */ * meas_cells[i]->plmn_equals(selected_plmn_id) && */
// Matches S criteria if (rrc_ptr->cell_selection_criteria(neigh_cell.get_rsrp()) or not neigh_cell.has_sibs(required_sibs)) {
if (rrc_ptr->cell_selection_criteria(rrc_ptr->meas_cells.at(neigh_index).get_rsrp())) { neigh_index++;
// currently connected and verifies cell selection criteria return start_phy_cell_selection(neigh_cell);
// Try to select Cell
rrc_ptr->set_serving_cell(rrc_ptr->meas_cells.at(neigh_index).phy_cell, discard_serving);
discard_serving = false;
Info("Selected cell: %s\n", rrc_ptr->meas_cells.serving_cell().to_string().c_str());
state = search_state_t::cell_selection;
if (not rrc_ptr->phy_ctrl->start_cell_select(rrc_ptr->meas_cells.serving_cell().phy_cell,
rrc_ptr->cell_selector)) {
Error("Failed to launch PHY Cell Selection\n");
return proc_outcome_t::error;
}
return proc_outcome_t::yield;
} }
} }
@ -591,43 +586,62 @@ proc_outcome_t rrc::cell_selection_proc::start_cell_selection()
return proc_outcome_t::error; return proc_outcome_t::error;
} }
proc_outcome_t rrc::cell_selection_proc::step_cell_selection(const bool& cs_ret) proc_outcome_t rrc::cell_selection_proc::react(const bool& cell_selection_result)
{ {
if (cs_ret) { if (state != search_state_t::cell_selection) {
// successful selection Warning("Unexpected cell selection event received\n");
if (rrc_ptr->cell_selection_criteria(rrc_ptr->meas_cells.serving_cell().get_rsrp())) { return proc_outcome_t::yield;
Info("PHY is in SYNC and cell selection passed\n");
state = search_state_t::cell_config;
if (not rrc_ptr->serv_cell_cfg.launch(&serv_cell_cfg_fut, required_sibs)) {
return proc_outcome_t::error;
}
return proc_outcome_t::yield;
}
Info("PHY is in SYNC but cell selection did not pass. Go back to select step.\n");
cs_result = cs_result_t::no_cell;
} else {
Error("Could not camp on serving cell.\n");
} }
rrc_ptr->meas_cells.serving_cell().set_rsrp(-INFINITY); if (cell_selection_result) {
discard_serving = true; // Discard this cell // successful selection
// Continue to next neighbour cell if (is_serv_cell_suitable()) {
++neigh_index; return set_proc_complete();
return start_cell_selection(); }
if (is_sib_acq_required()) {
return start_sib_acquisition();
}
}
Info("Cell selection criteria not passed.\n");
discard_serving = not is_same_cell(init_serv_cell, meas_cells->serving_cell());
return start_next_cell_selection();
} }
srslte::proc_outcome_t rrc::cell_selection_proc::step_serv_cell_camp(const bool& cs_ret) srslte::proc_outcome_t rrc::cell_selection_proc::start_phy_cell_selection(const meas_cell& cell)
{ {
// if we are now camping, the proc was successful if (not is_same_cell(cell, meas_cells->serving_cell())) {
if (cs_ret) { rrc_ptr->set_serving_cell(cell.phy_cell, discard_serving);
Info("Selected serving cell OK.\n"); discard_serving = false;
cs_result = cs_result_t::same_cell; Info("Set serving cell: %s\n", meas_cells->serving_cell().to_string().c_str());
return proc_outcome_t::success; } else {
// in case the cell had already been selected
if (is_serv_cell_suitable()) {
return set_proc_complete();
}
if (is_sib_acq_required()) {
return start_sib_acquisition();
}
} }
rrc_ptr->meas_cells.serving_cell().set_rsrp(-INFINITY); state = search_state_t::cell_selection;
Warning("Could not camp on serving cell.\n"); if (not rrc_ptr->phy_ctrl->start_cell_select(meas_cells->serving_cell().phy_cell, rrc_ptr->cell_selector)) {
return start_cell_selection(); Error("Failed to launch PHY Cell Selection\n");
return set_proc_complete();
}
return proc_outcome_t::yield;
}
srslte::proc_outcome_t rrc::cell_selection_proc::start_sib_acquisition()
{
Info("PHY is camping on serving cell, but SIBs need to be acquired\n");
state = search_state_t::cell_config;
if (not rrc_ptr->serv_cell_cfg.launch(&serv_cell_cfg_fut, required_sibs)) {
Warning("Failed to launch %s procedure\n", rrc_ptr->serv_cell_cfg.get()->name());
return set_proc_complete();
}
return proc_outcome_t::yield;
} }
proc_outcome_t rrc::cell_selection_proc::step_cell_search() proc_outcome_t rrc::cell_selection_proc::step_cell_search()
@ -635,22 +649,12 @@ proc_outcome_t rrc::cell_selection_proc::step_cell_search()
if (rrc_ptr->cell_searcher.run()) { if (rrc_ptr->cell_searcher.run()) {
return proc_outcome_t::yield; return proc_outcome_t::yield;
} }
if (cell_search_fut.is_error()) {
cs_result = cs_result_t::no_cell; if (is_sib_acq_required()) {
return proc_outcome_t::error; return start_sib_acquisition();
} }
cs_result = (cell_search_fut.value()->found == cell_search_ret_t::CELL_FOUND) ? cs_result_t::changed_cell
: cs_result_t::no_cell; return set_proc_complete();
if (rrc_ptr->cell_selection_criteria(rrc_ptr->meas_cells.serving_cell().get_rsrp())) {
Info("PHY is in SYNC and cell selection passed.\n");
state = search_state_t::cell_config;
if (not rrc_ptr->serv_cell_cfg.launch(&serv_cell_cfg_fut, required_sibs)) {
return proc_outcome_t::error;
}
return proc_outcome_t::yield;
}
Info("Cell Search of cell selection run successfully\n");
return proc_outcome_t::success;
} }
proc_outcome_t rrc::cell_selection_proc::step_cell_config() proc_outcome_t rrc::cell_selection_proc::step_cell_config()
@ -658,15 +662,11 @@ proc_outcome_t rrc::cell_selection_proc::step_cell_config()
if (rrc_ptr->serv_cell_cfg.run()) { if (rrc_ptr->serv_cell_cfg.run()) {
return proc_outcome_t::yield; return proc_outcome_t::yield;
} }
if (serv_cell_cfg_fut.is_success()) { if (is_serv_cell_suitable()) {
Info("All SIBs of serving cell obtained successfully\n"); return set_proc_complete();
cs_result = cs_result_t::changed_cell;
return proc_outcome_t::success;
} }
Error("While configuring serving cell\n"); Error("Failed to configure serving cell\n");
// resume cell selection return start_next_cell_selection();
++neigh_index;
return start_cell_selection();
} }
proc_outcome_t rrc::cell_selection_proc::step() proc_outcome_t rrc::cell_selection_proc::step()
@ -688,11 +688,9 @@ proc_outcome_t rrc::cell_selection_proc::step()
void rrc::cell_selection_proc::then(const srslte::proc_result_t<cs_result_t>& proc_result) const void rrc::cell_selection_proc::then(const srslte::proc_result_t<cs_result_t>& proc_result) const
{ {
Info("Completed with %s.\n", proc_result.is_success() ? "success" : "failure");
// Inform Connection Request Procedure // Inform Connection Request Procedure
if (rrc_ptr->conn_req_proc.is_busy()) { if (rrc_ptr->conn_req_proc.is_busy()) {
Info("Completed with %s. Informing proc %s\n",
proc_result.is_success() ? "success" : "failure",
rrc_ptr->conn_req_proc.get()->name());
rrc_ptr->conn_req_proc.trigger(proc_result); rrc_ptr->conn_req_proc.trigger(proc_result);
} else if (rrc_ptr->connection_reest.is_busy()) { } else if (rrc_ptr->connection_reest.is_busy()) {
rrc_ptr->connection_reest.trigger(proc_result); rrc_ptr->connection_reest.trigger(proc_result);

View File

@ -50,7 +50,7 @@ public:
void set_config_mbsfn_sib13(const srslte::sib13_t& sib13) override {} void set_config_mbsfn_sib13(const srslte::sib13_t& sib13) override {}
void set_config_mbsfn_mcch(const srslte::mcch_msg_t& mcch) override {} void set_config_mbsfn_mcch(const srslte::mcch_msg_t& mcch) override {}
bool cell_search() override { return true; } bool cell_search() override { return true; }
bool cell_is_camping() override { return false; } bool cell_is_camping() override { return true; }
void set_activation_deactivation_scell(uint32_t cmd) override {} void set_activation_deactivation_scell(uint32_t cmd) override {}
bool cell_select(phy_cell_t cell) override bool cell_select(phy_cell_t cell) override
{ {
@ -107,6 +107,68 @@ private:
uint32_t serving_earfcn = 0; uint32_t serving_earfcn = 0;
}; };
class mac_test : public srsue::mac_interface_rrc
{
public:
srslte::task_sched_handle task_sched;
rrc* rrc_ptr;
mac_test(rrc* rrc_, srslte::task_sched_handle task_sched_) : rrc_ptr(rrc_), task_sched(task_sched_) {}
int get_dlsch_with_sib1(bcch_dl_sch_msg_s& dlsch_msg)
{
sib_type1_s sib1;
uint8_t asn1_msg[] = {0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
asn1::cbit_ref bref{asn1_msg, sizeof(asn1_msg)};
return dlsch_msg.unpack(bref);
}
int get_dlsch_with_sys_info(bcch_dl_sch_msg_s& dlsch_msg)
{
sib_type1_s sib1;
uint8_t asn1_msg[] = {0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00};
asn1::cbit_ref bref{asn1_msg, sizeof(asn1_msg)};
return dlsch_msg.unpack(bref);
}
void bcch_start_rx(int si_window_start, int si_window_length) override
{
task_sched.defer_task([this]() {
srslte::unique_byte_buffer_t pdu;
for (uint32_t i = 0; i < 2; ++i) {
bcch_dl_sch_msg_s dlsch_msg;
if (i == 0) {
get_dlsch_with_sib1(dlsch_msg);
} else {
get_dlsch_with_sys_info(dlsch_msg);
}
pdu = srslte::allocate_unique_buffer(*srslte::byte_buffer_pool::get_instance());
asn1::bit_ref bref(pdu->msg, pdu->get_tailroom());
dlsch_msg.pack(bref);
pdu->N_bytes = bref.distance_bytes();
rrc_ptr->write_pdu_bcch_dlsch(std::move(pdu));
}
});
}
void bcch_stop_rx() override {}
void pcch_start_rx() override {}
void setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) override {}
void mch_start_rx(uint32_t lcid) override {}
void set_config(srslte::mac_cfg_t& mac_cfg) override {}
void set_rach_ded_cfg(uint32_t preamble_index, uint32_t prach_mask) override {}
void get_rntis(ue_rnti_t* rntis) override {}
void set_contention_id(uint64_t uecri) override {}
void set_ho_rnti(uint16_t crnti, uint16_t target_pci) override {}
void reconfiguration(const uint32_t& cc_idx, const bool& enable) override {}
void reset() override {}
};
class nas_test : public srsue::nas class nas_test : public srsue::nas
{ {
public: public:
@ -172,13 +234,16 @@ class rrc_test : public rrc
stack_test_dummy* stack = nullptr; stack_test_dummy* stack = nullptr;
public: public:
rrc_test(srslte::log_ref log_, stack_test_dummy* stack_) : rrc(stack_, &stack_->task_sched), stack(stack_) rrc_test(srslte::log_ref log_, stack_test_dummy* stack_) :
rrc(stack_, &stack_->task_sched),
stack(stack_),
mactest(this, &stack_->task_sched)
{ {
pool = srslte::byte_buffer_pool::get_instance(); pool = srslte::byte_buffer_pool::get_instance();
nastest = std::unique_ptr<nas_test>(new nas_test(&stack->task_sched)); nastest = std::unique_ptr<nas_test>(new nas_test(&stack->task_sched));
pdcptest = std::unique_ptr<pdcp_test>(new pdcp_test(log_->get_service_name().c_str(), &stack->task_sched)); pdcptest = std::unique_ptr<pdcp_test>(new pdcp_test(log_->get_service_name().c_str(), &stack->task_sched));
} }
void init() { rrc::init(&phytest, nullptr, nullptr, pdcptest.get(), nastest.get(), nullptr, nullptr, {}); } void init() { rrc::init(&phytest, &mactest, nullptr, pdcptest.get(), nastest.get(), nullptr, nullptr, {}); }
void run_tti(uint32_t tti_) void run_tti(uint32_t tti_)
{ {
@ -269,6 +334,7 @@ public:
bool get_meas_res(meas_results_s& meas_res) { return pdcptest->get_meas_res(meas_res); } bool get_meas_res(meas_results_s& meas_res) { return pdcptest->get_meas_res(meas_res); }
phy_test phytest; phy_test phytest;
mac_test mactest;
private: private:
std::unique_ptr<pdcp_test> pdcptest; std::unique_ptr<pdcp_test> pdcptest;
@ -347,13 +413,17 @@ int cell_select_test()
rrctest.cell_select_complete(true); // it will select pci=2 rrctest.cell_select_complete(true); // it will select pci=2
rrctest.in_sync(); rrctest.in_sync();
stack.run_pending_tasks(); // it will select pci=2 stack.run_pending_tasks(); // it will select pci=2
rrctest.run_tti(0); // Needed to advance si acquisition procedure
TESTASSERT(rrctest.phytest.last_selected_cell.earfcn == 2); TESTASSERT(rrctest.phytest.last_selected_cell.earfcn == 2);
TESTASSERT(rrctest.phytest.last_selected_cell.pci == 2); TESTASSERT(rrctest.phytest.last_selected_cell.pci == 2);
TESTASSERT(rrctest.has_neighbour_cell(1, 1)); TESTASSERT(rrctest.has_neighbour_cell(1, 1));
TESTASSERT(rrctest.has_neighbour_cell(2, 3)); TESTASSERT(rrctest.has_neighbour_cell(2, 3));
TESTASSERT(not rrctest.has_neighbour_cell(2, 2)); TESTASSERT(not rrctest.has_neighbour_cell(2, 2));
// Cell Selection fails, make sure it goes to Cell Search // CHECK: UE moves to stronger intra-freq neighbor
// CHECK: Cell Selection fails, make sure it goes to Cell Search
rrctest.add_neighbour_cell(4, 2, 100);
phy_cell_t cell_search_cell = {}; phy_cell_t cell_search_cell = {};
rrc_interface_phy_lte::cell_search_ret_t cell_search_ret = {}; rrc_interface_phy_lte::cell_search_ret_t cell_search_ret = {};
cell_search_cell.pci = 5; cell_search_cell.pci = 5;