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(); }
|
||||
|
||||
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_sib1() const { return has_valid_sib1; }
|
||||
bool has_sib2() const { return has_valid_sib2; }
|
||||
|
|
|
@ -125,21 +125,24 @@ public:
|
|||
explicit cell_selection_proc(rrc* parent_);
|
||||
srslte::proc_outcome_t init(std::vector<uint32_t> required_sibs_ = {});
|
||||
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; }
|
||||
static const char* name() { return "Cell Selection"; }
|
||||
srslte::proc_outcome_t react(const bool& event);
|
||||
void then(const srslte::proc_result_t<cs_result_t>& proc_result) const;
|
||||
|
||||
private:
|
||||
srslte::proc_outcome_t start_serv_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 start_next_cell_selection();
|
||||
srslte::proc_outcome_t step_cell_search();
|
||||
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
|
||||
rrc* rrc_ptr;
|
||||
meas_cell_list* meas_cells;
|
||||
|
||||
// state variables
|
||||
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;
|
||||
bool discard_serving = false, cell_search_called = false;
|
||||
std::vector<uint32_t> required_sibs = {};
|
||||
phy_cell_t init_serv_cell;
|
||||
};
|
||||
|
||||
class rrc::plmn_search_proc
|
||||
|
|
|
@ -471,7 +471,7 @@ void rrc::in_sync()
|
|||
// Cell selection criteria Section 5.2.3.2 of 36.304
|
||||
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)
|
||||
|
@ -1141,23 +1141,23 @@ void rrc::parse_pdu_bcch_dlsch(unique_byte_buffer_t pdu)
|
|||
case sib_info_item_c::types::sib2:
|
||||
if (not meas_cells.serving_cell().has_sib2()) {
|
||||
meas_cells.serving_cell().set_sib2(sib_list[i].sib2());
|
||||
si_acquirer.trigger(si_acquire_proc::sib_received_ev{});
|
||||
}
|
||||
handle_sib2();
|
||||
si_acquirer.trigger(si_acquire_proc::sib_received_ev{});
|
||||
break;
|
||||
case sib_info_item_c::types::sib3:
|
||||
if (not meas_cells.serving_cell().has_sib3()) {
|
||||
meas_cells.serving_cell().set_sib3(sib_list[i].sib3());
|
||||
si_acquirer.trigger(si_acquire_proc::sib_received_ev{});
|
||||
}
|
||||
handle_sib3();
|
||||
si_acquirer.trigger(si_acquire_proc::sib_received_ev{});
|
||||
break;
|
||||
case sib_info_item_c::types::sib13_v920:
|
||||
if (not meas_cells.serving_cell().has_sib13()) {
|
||||
meas_cells.serving_cell().set_sib13(sib_list[i].sib13_v920());
|
||||
si_acquirer.trigger(si_acquire_proc::sib_received_ev{});
|
||||
}
|
||||
handle_sib13();
|
||||
si_acquirer.trigger(si_acquire_proc::sib_received_ev{});
|
||||
break;
|
||||
default:
|
||||
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();
|
||||
}
|
||||
|
||||
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) {
|
||||
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_) :
|
||||
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)
|
||||
|
|
|
@ -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_)
|
||||
{
|
||||
// remove duplicates from list of 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");
|
||||
|
||||
|
@ -450,95 +453,98 @@ proc_outcome_t rrc::serving_cell_config_proc::step()
|
|||
* 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};
|
||||
|
||||
/*
|
||||
* Cell selection procedure 36.304 5.2.3
|
||||
* Select the best cell to camp on among the list of known cells
|
||||
rrc::cell_selection_proc::cell_selection_proc(rrc* parent_) : rrc_ptr(parent_), meas_cells(&rrc_ptr->meas_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_)
|
||||
{
|
||||
bool serv_cell_is_ok = rrc_ptr->phy_ctrl->is_in_sync() and rrc_ptr->phy->cell_is_camping();
|
||||
bool has_required_sibs = rrc_ptr->meas_cells.serving_cell().has_sibs(required_sibs_);
|
||||
if (rrc_ptr->meas_cells.nof_neighbours() == 0 and serv_cell_is_ok and has_required_sibs) {
|
||||
// don't bother with cell selection if there are no neighbours and we are already camping
|
||||
Debug("Skipping Cell Selection Procedure as there are no neighbour and cell is camping.\n");
|
||||
cs_result = cs_result_t::same_cell;
|
||||
return proc_outcome_t::success;
|
||||
if (required_sibs_.empty()) {
|
||||
required_sibs = rrc_ptr->ue_required_sibs;
|
||||
} else {
|
||||
required_sibs = std::move(required_sibs_);
|
||||
}
|
||||
required_sibs.insert(required_sibs.end(), mandatory_sibs.begin(), mandatory_sibs.end());
|
||||
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("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");
|
||||
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",
|
||||
rrc_ptr->cell_resel_cfg.Qrxlevmin,
|
||||
rrc_ptr->cell_resel_cfg.Qrxlevminoffset);
|
||||
} else {
|
||||
Info("Cell selection criteria: not available\n");
|
||||
}
|
||||
Info("Current serving cell: %s\n", rrc_ptr->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_);
|
||||
}
|
||||
Info("Current serving cell: %s\n", meas_cells->serving_cell().to_string().c_str());
|
||||
|
||||
neigh_index = 0;
|
||||
cs_result = cs_result_t::no_cell;
|
||||
discard_serving = false;
|
||||
serv_cell_select_attempted = false;
|
||||
serv_cell_select_attempted = stronger_neigh_in_earfcn;
|
||||
cell_search_called = false;
|
||||
if (serv_cell_is_ok and not has_required_sibs) {
|
||||
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 proc_outcome_t::error;
|
||||
}
|
||||
return proc_outcome_t::yield;
|
||||
}
|
||||
state = search_state_t::cell_selection;
|
||||
return start_cell_selection();
|
||||
return start_next_cell_selection();
|
||||
}
|
||||
|
||||
proc_outcome_t rrc::cell_selection_proc::react(const bool& 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_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
|
||||
/**
|
||||
* Implementation of the Cell Selection Procedure main steps
|
||||
* 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.
|
||||
* 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
|
||||
* 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
|
||||
if (not serv_cell_select_attempted and
|
||||
rrc_ptr->cell_selection_criteria(rrc_ptr->meas_cells.serving_cell().get_rsrp())) {
|
||||
return start_serv_cell_selection();
|
||||
if (not serv_cell_select_attempted) {
|
||||
serv_cell_select_attempted = true;
|
||||
return start_phy_cell_selection(meas_cells->serving_cell());
|
||||
}
|
||||
|
||||
// If serving is not available, use the stored information (known neighbours) to find the strongest
|
||||
// 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
|
||||
* meas_cells[i]->plmn_equals(selected_plmn_id) && */
|
||||
// Matches S criteria
|
||||
if (rrc_ptr->cell_selection_criteria(rrc_ptr->meas_cells.at(neigh_index).get_rsrp())) {
|
||||
// currently connected and verifies cell selection criteria
|
||||
// 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;
|
||||
if (rrc_ptr->cell_selection_criteria(neigh_cell.get_rsrp()) or not neigh_cell.has_sibs(required_sibs)) {
|
||||
neigh_index++;
|
||||
return start_phy_cell_selection(neigh_cell);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -591,43 +586,62 @@ proc_outcome_t rrc::cell_selection_proc::start_cell_selection()
|
|||
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) {
|
||||
Warning("Unexpected cell selection event received\n");
|
||||
return proc_outcome_t::yield;
|
||||
}
|
||||
|
||||
if (cell_selection_result) {
|
||||
// successful selection
|
||||
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;
|
||||
if (is_serv_cell_suitable()) {
|
||||
return set_proc_complete();
|
||||
}
|
||||
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::start_phy_cell_selection(const meas_cell& cell)
|
||||
{
|
||||
if (not is_same_cell(cell, meas_cells->serving_cell())) {
|
||||
rrc_ptr->set_serving_cell(cell.phy_cell, discard_serving);
|
||||
discard_serving = false;
|
||||
Info("Set serving cell: %s\n", meas_cells->serving_cell().to_string().c_str());
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
|
||||
state = search_state_t::cell_selection;
|
||||
if (not rrc_ptr->phy_ctrl->start_cell_select(meas_cells->serving_cell().phy_cell, rrc_ptr->cell_selector)) {
|
||||
Error("Failed to launch PHY Cell Selection\n");
|
||||
return set_proc_complete();
|
||||
}
|
||||
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);
|
||||
discard_serving = true; // Discard this cell
|
||||
// Continue to next neighbour cell
|
||||
++neigh_index;
|
||||
return start_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_sib_acquisition()
|
||||
{
|
||||
// if we are now camping, the proc was successful
|
||||
if (cs_ret) {
|
||||
Info("Selected serving cell OK.\n");
|
||||
cs_result = cs_result_t::same_cell;
|
||||
return proc_outcome_t::success;
|
||||
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();
|
||||
}
|
||||
|
||||
rrc_ptr->meas_cells.serving_cell().set_rsrp(-INFINITY);
|
||||
Warning("Could not camp on serving cell.\n");
|
||||
return start_cell_selection();
|
||||
return proc_outcome_t::yield;
|
||||
}
|
||||
|
||||
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()) {
|
||||
return proc_outcome_t::yield;
|
||||
}
|
||||
if (cell_search_fut.is_error()) {
|
||||
cs_result = cs_result_t::no_cell;
|
||||
return proc_outcome_t::error;
|
||||
|
||||
if (is_sib_acq_required()) {
|
||||
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;
|
||||
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;
|
||||
|
||||
return set_proc_complete();
|
||||
}
|
||||
|
||||
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()) {
|
||||
return proc_outcome_t::yield;
|
||||
}
|
||||
if (serv_cell_cfg_fut.is_success()) {
|
||||
Info("All SIBs of serving cell obtained successfully\n");
|
||||
cs_result = cs_result_t::changed_cell;
|
||||
return proc_outcome_t::success;
|
||||
if (is_serv_cell_suitable()) {
|
||||
return set_proc_complete();
|
||||
}
|
||||
Error("While configuring serving cell\n");
|
||||
// resume cell selection
|
||||
++neigh_index;
|
||||
return start_cell_selection();
|
||||
Error("Failed to configure serving cell\n");
|
||||
return start_next_cell_selection();
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
Info("Completed with %s.\n", proc_result.is_success() ? "success" : "failure");
|
||||
// Inform Connection Request Procedure
|
||||
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);
|
||||
} else if (rrc_ptr->connection_reest.is_busy()) {
|
||||
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_mcch(const srslte::mcch_msg_t& mcch) override {}
|
||||
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 {}
|
||||
bool cell_select(phy_cell_t cell) override
|
||||
{
|
||||
|
@ -107,6 +107,68 @@ private:
|
|||
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
|
||||
{
|
||||
public:
|
||||
|
@ -172,13 +234,16 @@ class rrc_test : public rrc
|
|||
stack_test_dummy* stack = nullptr;
|
||||
|
||||
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();
|
||||
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));
|
||||
}
|
||||
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_)
|
||||
{
|
||||
|
@ -269,6 +334,7 @@ public:
|
|||
bool get_meas_res(meas_results_s& meas_res) { return pdcptest->get_meas_res(meas_res); }
|
||||
|
||||
phy_test phytest;
|
||||
mac_test mactest;
|
||||
|
||||
private:
|
||||
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.in_sync();
|
||||
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.pci == 2);
|
||||
TESTASSERT(rrctest.has_neighbour_cell(1, 1));
|
||||
TESTASSERT(rrctest.has_neighbour_cell(2, 3));
|
||||
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 = {};
|
||||
rrc_interface_phy_lte::cell_search_ret_t cell_search_ret = {};
|
||||
cell_search_cell.pci = 5;
|
||||
|
|
Loading…
Reference in New Issue