mirror of https://github.com/PentHertz/srsLTE.git
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:
parent
9ad1328bbd
commit
585d7c923a
|
@ -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; }
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue