integrated observer pattern into rrc phy ctrl fsm

master
Francisco Paisana 4 years ago
parent b2313e3631
commit 48dd436d86

@ -81,6 +81,8 @@ public:
return count; return count;
} }
void unsubscribe_all() { observers.clear(); }
//! Signal result to observers //! Signal result to observers
void dispatch(Args... args) void dispatch(Args... args)
{ {

@ -22,6 +22,7 @@
#ifndef SRSLTE_PHY_CONTROLLER_H #ifndef SRSLTE_PHY_CONTROLLER_H
#define SRSLTE_PHY_CONTROLLER_H #define SRSLTE_PHY_CONTROLLER_H
#include "srslte/adt/observer.h"
#include "srslte/common/fsm.h" #include "srslte/common/fsm.h"
#include "srslte/common/logmap.h" #include "srslte/common/logmap.h"
#include "srslte/interfaces/ue_interfaces.h" #include "srslte/interfaces/ue_interfaces.h"
@ -45,30 +46,31 @@ public:
bool result; bool result;
}; };
struct cell_sel_cmd { struct cell_sel_cmd {
phy_cell_t phy_cell; phy_cell_t phy_cell;
srslte::event_callback<bool> callback;
};
struct cell_search_cmd {
srslte::event_callback<cell_srch_res> callback;
}; };
struct cell_search_cmd {};
struct in_sync_ev {}; struct in_sync_ev {};
struct out_sync_ev {}; struct out_sync_ev {};
explicit phy_controller(phy_interface_rrc_lte* phy_, srslte::task_sched_handle task_sched_); explicit phy_controller(phy_interface_rrc_lte* phy_, srslte::task_sched_handle task_sched_);
// PHY procedures interfaces // PHY procedures interfaces
bool start_cell_select(const phy_cell_t& phy_cell, const srslte::event_callback<bool>& on_complete); bool start_cell_select(const phy_cell_t& phy_cell);
bool start_cell_search(const srslte::event_callback<cell_srch_res>& on_complete); bool start_cell_search();
bool 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);
bool cell_selection_completed(bool outcome); void cell_selection_completed(bool outcome);
void in_sync(); void in_sync();
void out_sync() { trigger(out_sync_ev{}); } void out_sync() { trigger(out_sync_ev{}); }
// Event Observers
srslte::event_dispatcher<cell_srch_res> cell_search_observers;
srslte::event_dispatcher<bool> cell_selection_observers;
// state getters // state getters
bool cell_is_camping() { return phy->cell_is_camping(); } bool cell_is_camping() { return phy->cell_is_camping(); }
bool is_in_sync() const { return is_in_state<in_sync_st>(); } bool is_in_sync() const { return is_in_state<in_sync_st>(); }
// states // FSM states
struct unknown_st {}; struct unknown_st {};
struct in_sync_st {}; struct in_sync_st {};
struct out_sync_st {}; struct out_sync_st {};
@ -87,7 +89,6 @@ public:
srslte::timer_handler::unique_timer wait_in_sync_timer; srslte::timer_handler::unique_timer wait_in_sync_timer;
phy_cell_t target_cell = {}; phy_cell_t target_cell = {};
cell_sel_res csel_res = {}; cell_sel_res csel_res = {};
srslte::event_callback<bool> csel_callback;
protected: protected:
// guard functions // guard functions
@ -113,15 +114,13 @@ public:
// clang-format on // clang-format on
}; };
struct searching_cell { struct searching_cell {
void enter(phy_controller* f, const cell_search_cmd& cmd); void enter(phy_controller* f);
}; };
private: private:
phy_interface_rrc_lte* phy = nullptr; phy_interface_rrc_lte* phy = nullptr;
srslte::task_sched_handle task_sched; srslte::task_sched_handle task_sched;
std::vector<srslte::event_callback<cell_srch_res> > csearch_callbacks;
protected: protected:
state_list<unknown_st, in_sync_st, out_sync_st, searching_cell, selecting_cell> states{this, state_list<unknown_st, in_sync_st, out_sync_st, searching_cell, selecting_cell> states{this,
unknown_st{}, unknown_st{},
@ -132,7 +131,6 @@ protected:
// event handlers // event handlers
void handle_cell_search_res(searching_cell& s, const cell_srch_res& result); void handle_cell_search_res(searching_cell& s, const cell_srch_res& result);
void share_cell_search_res(searching_cell& s, const cell_search_cmd& cmd);
// clang-format off // clang-format off
using c = phy_controller; using c = phy_controller;
@ -152,8 +150,7 @@ protected:
row< out_sync_st, searching_cell, cell_search_cmd >, row< out_sync_st, searching_cell, cell_search_cmd >,
row< out_sync_st, in_sync_st, in_sync_ev >, row< out_sync_st, in_sync_st, in_sync_ev >,
// +----------------+-----------------+------------------+------------------------------+ // +----------------+-----------------+------------------+------------------------------+
row< searching_cell, unknown_st, cell_srch_res, &c::handle_cell_search_res >, row< searching_cell, unknown_st, cell_srch_res, &c::handle_cell_search_res >
upd< searching_cell, cell_search_cmd, &c::share_cell_search_res >
// +----------------+-----------------+------------------+------------------------------+ // +----------------+-----------------+------------------+------------------------------+
>; >;
// clang-format on // clang-format on

@ -36,13 +36,22 @@ phy_controller::phy_controller(srsue::phy_interface_rrc_lte* phy_, srslte::task_
task_sched(task_sched_) task_sched(task_sched_)
{} {}
void phy_controller::in_sync()
{
trigger(in_sync_ev{});
}
/************************************** /**************************************
* PHY Cell Select Procedure * PHY Cell Select Procedure
*************************************/ *************************************/
bool phy_controller::start_cell_select(const phy_cell_t& phy_cell, const srslte::event_callback<bool>& on_complete) bool phy_controller::start_cell_select(const phy_cell_t& phy_cell)
{ {
trigger(cell_sel_cmd{phy_cell, on_complete}); if (is_in_state<selecting_cell>()) {
log_h->warning("Failed to launch cell selection as it is already running\n");
return false;
}
trigger(cell_sel_cmd{phy_cell});
if (not is_in_state<selecting_cell>()) { if (not is_in_state<selecting_cell>()) {
log_h->warning("Failed to launch cell selection. Current state: %s\n", current_state_name().c_str()); log_h->warning("Failed to launch cell selection. Current state: %s\n", current_state_name().c_str());
return false; return false;
@ -50,14 +59,9 @@ bool phy_controller::start_cell_select(const phy_cell_t& phy_cell, const srslte:
return true; return true;
} }
bool phy_controller::cell_selection_completed(bool outcome) void phy_controller::cell_selection_completed(bool outcome)
{ {
return trigger(cell_sel_res{outcome}); trigger(cell_sel_res{outcome});
}
void phy_controller::in_sync()
{
trigger(in_sync_ev{});
} }
phy_controller::selecting_cell::selecting_cell(phy_controller* parent_) : composite_fsm_t(parent_) phy_controller::selecting_cell::selecting_cell(phy_controller* parent_) : composite_fsm_t(parent_)
@ -68,7 +72,6 @@ phy_controller::selecting_cell::selecting_cell(phy_controller* parent_) : compos
void phy_controller::selecting_cell::enter(phy_controller* f, const cell_sel_cmd& ev) void phy_controller::selecting_cell::enter(phy_controller* f, const cell_sel_cmd& ev)
{ {
target_cell = ev.phy_cell; target_cell = ev.phy_cell;
csel_callback = ev.callback;
csel_res.result = false; csel_res.result = false;
fsmInfo("Starting for pci=%d, earfcn=%d\n", target_cell.pci, target_cell.earfcn); fsmInfo("Starting for pci=%d, earfcn=%d\n", target_cell.pci, target_cell.earfcn);
@ -91,7 +94,11 @@ void phy_controller::selecting_cell::exit(phy_controller* f)
} }
// Signal result back to FSM that called cell selection // Signal result back to FSM that called cell selection
f->task_sched.defer_task(srslte::make_move_task(csel_callback, csel_res.result)); bool result = csel_res.result;
f->task_sched.defer_task([f, result]() {
f->cell_selection_observers.dispatch(result);
f->cell_selection_observers.unsubscribe_all();
});
} }
void phy_controller::selecting_cell::wait_in_sync::enter(selecting_cell* f, const cell_sel_res& ev) void phy_controller::selecting_cell::wait_in_sync::enter(selecting_cell* f, const cell_sel_res& ev)
@ -105,9 +112,13 @@ void phy_controller::selecting_cell::wait_in_sync::enter(selecting_cell* f, cons
*************************************/ *************************************/
//! 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(const srslte::event_callback<cell_srch_res>& on_complete) bool phy_controller::start_cell_search()
{ {
trigger(cell_search_cmd{on_complete}); if (is_in_state<searching_cell>()) {
fsmInfo("Cell search already launched.\n");
return true;
}
trigger(cell_search_cmd{});
if (not is_in_state<searching_cell>()) { if (not is_in_state<searching_cell>()) {
fsmWarning("Failed to launch cell search\n"); fsmWarning("Failed to launch cell search\n");
return false; return false;
@ -115,24 +126,14 @@ bool phy_controller::start_cell_search(const srslte::event_callback<cell_srch_re
return true; return true;
} }
bool phy_controller::cell_search_completed(cell_search_ret_t cs_ret, phy_cell_t found_cell) void phy_controller::cell_search_completed(cell_search_ret_t cs_ret, phy_cell_t found_cell)
{ {
cell_srch_res res{cs_ret, found_cell}; trigger(cell_srch_res{cs_ret, found_cell});
if (trigger(res)) {
// Signal callers the result of cell search
for (auto& f : csearch_callbacks) {
f(res);
}
csearch_callbacks.clear();
return true;
}
return false;
} }
void phy_controller::searching_cell::enter(phy_controller* f, const cell_search_cmd& cmd) void phy_controller::searching_cell::enter(phy_controller* f)
{ {
otherfsmInfo(f, "Initiating Cell search\n"); otherfsmInfo(f, "Initiating Cell search\n");
f->csearch_callbacks.emplace_back(cmd.callback);
f->task_sched.enqueue_background_task([f](uint32_t worker_id) { f->task_sched.enqueue_background_task([f](uint32_t worker_id) {
phy_interface_rrc_lte::phy_cell_t found_cell; phy_interface_rrc_lte::phy_cell_t found_cell;
phy_interface_rrc_lte::cell_search_ret_t ret = f->phy->cell_search(&found_cell); phy_interface_rrc_lte::cell_search_ret_t ret = f->phy->cell_search(&found_cell);
@ -156,13 +157,11 @@ void phy_controller::handle_cell_search_res(searching_cell& s, const cell_srch_r
} }
// Signal result back to FSM that called cell search // Signal result back to FSM that called cell search
task_sched.defer_task(srslte::make_move_task(std::move(csearch_callbacks), result)); auto copy = result;
} task_sched.defer_task([this, copy]() {
cell_search_observers.dispatch(copy);
void phy_controller::share_cell_search_res(searching_cell& s, const cell_search_cmd& cmd) cell_search_observers.unsubscribe_all();
{ });
log_h->info("Cell Search already running. Re-utilizing result.\n");
csearch_callbacks.emplace_back(cmd.callback);
} }
} // namespace srsue } // namespace srsue

@ -46,11 +46,11 @@ proc_outcome_t rrc::cell_search_proc::init()
{ {
Info("Starting...\n"); Info("Starting...\n");
state = state_t::phy_cell_search; state = state_t::phy_cell_search;
rrc_ptr->phy_ctrl->start_cell_search(srslte::event_callback<phy_controller::cell_srch_res>{&rrc_ptr->cell_searcher}); if (not rrc_ptr->phy_ctrl->start_cell_search()) {
if (not rrc_ptr->phy_ctrl->is_in_state<phy_controller::searching_cell>()) {
Warning("Failed to initiate Cell Search.\n"); Warning("Failed to initiate Cell Search.\n");
return proc_outcome_t::error; return proc_outcome_t::error;
} }
rrc_ptr->phy_ctrl->cell_search_observers.subscribe(rrc_ptr->cell_searcher);
return proc_outcome_t::yield; return proc_outcome_t::yield;
} }
@ -98,11 +98,11 @@ proc_outcome_t rrc::cell_search_proc::handle_cell_found(const phy_interface_rrc_
// set new serving cell in PHY // set new serving cell in PHY
state = state_t::phy_cell_select; state = state_t::phy_cell_select;
if (not rrc_ptr->phy_ctrl->start_cell_select(rrc_ptr->meas_cells.serving_cell().phy_cell, if (not rrc_ptr->phy_ctrl->start_cell_select(rrc_ptr->meas_cells.serving_cell().phy_cell)) {
srslte::event_callback<bool>{&rrc_ptr->cell_searcher})) {
Error("Couldn't start phy cell selection\n"); Error("Couldn't start phy cell selection\n");
return proc_outcome_t::error; return proc_outcome_t::error;
} }
rrc_ptr->phy_ctrl->cell_selection_observers.subscribe(rrc_ptr->cell_searcher);
return proc_outcome_t::yield; return proc_outcome_t::yield;
} }
@ -511,11 +511,11 @@ proc_outcome_t rrc::cell_selection_proc::start_serv_cell_selection()
Info("Not camping on serving cell %s. Selecting it...\n", rrc_ptr->meas_cells.serving_cell().to_string().c_str()); 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; state = search_state_t::serv_cell_camp;
if (not rrc_ptr->phy_ctrl->start_cell_select(rrc_ptr->meas_cells.serving_cell().phy_cell, if (not rrc_ptr->phy_ctrl->start_cell_select(rrc_ptr->meas_cells.serving_cell().phy_cell)) {
srslte::event_callback<bool>{&rrc_ptr->cell_selector})) {
Error("Failed to launch PHY Cell Selection\n"); Error("Failed to launch PHY Cell Selection\n");
return proc_outcome_t::error; return proc_outcome_t::error;
} }
rrc_ptr->phy_ctrl->cell_selection_observers.subscribe(rrc_ptr->cell_selector);
serv_cell_select_attempted = true; serv_cell_select_attempted = true;
return proc_outcome_t::yield; return proc_outcome_t::yield;
} }
@ -553,12 +553,11 @@ proc_outcome_t rrc::cell_selection_proc::start_cell_selection()
Info("Selected cell: %s\n", rrc_ptr->meas_cells.serving_cell().to_string().c_str()); Info("Selected cell: %s\n", rrc_ptr->meas_cells.serving_cell().to_string().c_str());
state = search_state_t::cell_selection; state = search_state_t::cell_selection;
rrc_ptr->phy_ctrl->start_cell_select(rrc_ptr->meas_cells.serving_cell().phy_cell, if (not rrc_ptr->phy_ctrl->start_cell_select(rrc_ptr->meas_cells.serving_cell().phy_cell)) {
srslte::event_callback<bool>{&rrc_ptr->cell_selector});
if (not rrc_ptr->phy_ctrl->is_in_state<phy_controller::selecting_cell>()) {
Error("Failed to launch PHY Cell Selection\n"); Error("Failed to launch PHY Cell Selection\n");
return proc_outcome_t::error; return proc_outcome_t::error;
} }
rrc_ptr->phy_ctrl->cell_selection_observers.subscribe(rrc_ptr->cell_selector);
return proc_outcome_t::yield; return proc_outcome_t::yield;
} }
} }
@ -1493,11 +1492,11 @@ srslte::proc_outcome_t rrc::ho_proc::step()
Info("Starting cell selection of target cell %s\n", target_cell->to_string().c_str()); Info("Starting cell selection of target cell %s\n", target_cell->to_string().c_str());
rrc_ptr->phy_ctrl->start_cell_select(target_cell->phy_cell, srslte::event_callback<bool>{&rrc_ptr->ho_handler}); if (not rrc_ptr->phy_ctrl->start_cell_select(target_cell->phy_cell)) {
if (not rrc_ptr->phy_ctrl->is_in_state<phy_controller::selecting_cell>()) {
Error("Failed to launch the selection of target cell %s\n", target_cell->to_string().c_str()); Error("Failed to launch the selection of target cell %s\n", target_cell->to_string().c_str());
return proc_outcome_t::error; return proc_outcome_t::error;
} }
rrc_ptr->phy_ctrl->cell_selection_observers.subscribe(rrc_ptr->ho_handler);
state = wait_phy_cell_select_complete; state = wait_phy_cell_select_complete;
} }
return proc_outcome_t::yield; return proc_outcome_t::yield;

@ -83,7 +83,8 @@ 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(srslte::event_callback<phy_controller::cell_srch_res>{&csearch_tester})); TESTASSERT(phy_ctrl.start_cell_search());
phy_ctrl.cell_search_observers.subscribe(csearch_tester);
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
@ -111,14 +112,15 @@ int test_phy_ctrl_fsm()
phy_ctrl.out_sync(); phy_ctrl.out_sync();
// TEST: Correct initiation of Cell Select state // TEST: Correct initiation of Cell Select state
phy_ctrl.start_cell_select(found_cell, srslte::event_callback<bool>{&csel_tester}); phy_ctrl.start_cell_select(found_cell);
phy_ctrl.cell_selection_observers.subscribe(csel_tester);
TESTASSERT(not phy_ctrl.is_in_sync()); TESTASSERT(not phy_ctrl.is_in_sync());
TESTASSERT(phy_ctrl.current_state_name() == "selecting_cell"); TESTASSERT(phy_ctrl.current_state_name() == "selecting_cell");
// TEST: Cell Selection state ignores events other than the cell selection result, and callback is called // TEST: Cell Selection state ignores events other than the cell selection result, and callback is called
phy_ctrl.in_sync(); phy_ctrl.in_sync();
TESTASSERT(not phy_ctrl.is_in_sync()); TESTASSERT(not phy_ctrl.is_in_sync());
TESTASSERT(phy_ctrl.cell_selection_completed(true)); phy_ctrl.cell_selection_completed(true);
// Note: Still in cell selection, but now waiting for the first in_sync // Note: Still in cell selection, but now waiting for the first in_sync
TESTASSERT(phy_ctrl.current_state_name() == "selecting_cell"); TESTASSERT(phy_ctrl.current_state_name() == "selecting_cell");
TESTASSERT(not phy_ctrl.is_in_sync()); TESTASSERT(not phy_ctrl.is_in_sync());
@ -133,7 +135,8 @@ int test_phy_ctrl_fsm()
// TEST: Cell Selection with timeout being reached // TEST: Cell Selection with timeout being reached
csel_tester.result = -1; csel_tester.result = -1;
TESTASSERT(phy_ctrl.start_cell_select(found_cell, srslte::event_callback<bool>{&csel_tester})); TESTASSERT(phy_ctrl.start_cell_select(found_cell));
phy_ctrl.cell_selection_observers.subscribe(csel_tester);
TESTASSERT(not phy_ctrl.is_in_sync()); TESTASSERT(not phy_ctrl.is_in_sync());
phy_ctrl.cell_selection_completed(true); phy_ctrl.cell_selection_completed(true);
TESTASSERT(phy_ctrl.current_state_name() == "selecting_cell"); TESTASSERT(phy_ctrl.current_state_name() == "selecting_cell");

Loading…
Cancel
Save