From 834c0b3929bc1d94a87b8b6595cc433d8950ed47 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 19 Aug 2020 10:01:56 +0100 Subject: [PATCH] integrated new observer pattern into phy controller fsm --- lib/include/srslte/adt/observer.h | 105 ++++++++++++++++---------- lib/test/adt/observer_test.cc | 3 + srsue/hdr/stack/rrc/phy_controller.h | 16 ++-- srsue/src/stack/rrc/phy_controller.cc | 12 +-- srsue/src/stack/rrc/rrc_procedures.cc | 16 ++-- srsue/test/upper/rrc_phy_ctrl_test.cc | 9 +-- 6 files changed, 93 insertions(+), 68 deletions(-) diff --git a/lib/include/srslte/adt/observer.h b/lib/include/srslte/adt/observer.h index 75b756fbb..38a881dee 100644 --- a/lib/include/srslte/adt/observer.h +++ b/lib/include/srslte/adt/observer.h @@ -33,33 +33,78 @@ using observer_id = std::size_t; const size_t invalid_observer_id = std::numeric_limits::max(); template -class base_observable +class observer; +template +struct is_observer : public std::false_type {}; +template +struct is_observer > : public std::true_type {}; + +//! Type-erasure of Observer +template +class observer { public: using callback_t = std::function; + template + using enable_if_callback_t = + typename std::enable_if::value and + not is_observer::type>::value>::type; + + observer() = default; //! Subscribe Observer that is a callback - template - typename std::enable_if::value, observer_id>::type - subscribe(Callable&& callable) + template > + observer(Callable&& callable) : callback(std::forward(callable)) + {} + + template ::value, observer_id>::type> + observer(Observer& observer) : callback([&observer](Args... args) { observer.trigger(std::forward(args)...); }) + {} + + template + observer(Observer& observer, void (Observer::*trigger_method)(Args...)) : + callback([&observer, trigger_method](Args... args) { (observer.*trigger_method)(std::forward(args)...); }) + {} + + void operator()(Args... args) { - return subscribe_common(callable); + if (callback) { + callback(std::forward(args)...); + } } - //! Subscribe Observer type with method Observer::trigger(Args...) - template - typename std::enable_if::value, observer_id>::type - subscribe(Observer& observer) - { - return subscribe_common([&observer](Args... args) { observer.trigger(std::forward(args)...); }); - } + explicit operator bool() const { return static_cast(callback); } - //! Subscribe Observer type with custom trigger method - template - observer_id subscribe(Observer& observer, void (Observer::*trigger_method)(Args...)) + void reset() { callback = nullptr; } + +private: + callback_t callback; +}; + +template +class base_observable +{ +public: + using this_observer_t = observer; + + //! Subscribe Observer that is a callback + template + observer_id subscribe(Args2&&... args) { - return subscribe_common( - [&observer, trigger_method](Args... args) { (observer.*trigger_method)(std::forward(args)...); }); + size_t id = 0; + for (auto& slot : observers) { + if (not static_cast(slot)) { + // empty slot found + slot = this_observer_t{std::forward(args)...}; + return id; + } + id++; + } + // append to end of list + observers.emplace_back(std::forward(args)...); + return observers.size() - 1; } //! Unsubscribe Observer @@ -87,34 +132,15 @@ public: void dispatch(Args... args) { for (auto& obs_callback : observers) { - if (obs_callback) { - obs_callback(std::forward(args)...); - } + obs_callback(std::forward(args)...); } } protected: - using observer_list_t = std::deque; + using observer_list_t = std::deque; ~base_observable() = default; - template - observer_id subscribe_common(Callable&& callable) - { - size_t id = 0; - for (auto& slot : observers) { - if (not static_cast(slot)) { - // empty slot found - slot = std::forward(callable); - return id; - } - id++; - } - // append to end of list - observers.emplace_back(std::forward(callable)); - return observers.size() - 1; - } - observer_list_t observers; }; @@ -122,6 +148,9 @@ template class observable : public base_observable {}; +template +using event_observer = observer; + //! Special case of observable for event types template class event_dispatcher : public base_observable diff --git a/lib/test/adt/observer_test.cc b/lib/test/adt/observer_test.cc index a416e6034..ba943c4b7 100644 --- a/lib/test/adt/observer_test.cc +++ b/lib/test/adt/observer_test.cc @@ -22,6 +22,9 @@ #include "srslte/adt/observer.h" #include "srslte/common/test_common.h" +static_assert(srslte::is_observer >::value, "is_observer<> meta-function failed"); +static_assert(not srslte::is_observer >::value, "is_observer<> meta-function failed"); + struct M { M() = default; explicit M(int v) : val(v) {} diff --git a/srsue/hdr/stack/rrc/phy_controller.h b/srsue/hdr/stack/rrc/phy_controller.h index d3fbfefba..2110798a5 100644 --- a/srsue/hdr/stack/rrc/phy_controller.h +++ b/srsue/hdr/stack/rrc/phy_controller.h @@ -55,17 +55,13 @@ public: explicit phy_controller(phy_interface_rrc_lte* phy_, srslte::task_sched_handle task_sched_); // PHY procedures interfaces - bool start_cell_select(const phy_cell_t& phy_cell); - bool start_cell_search(); + bool start_cell_select(const phy_cell_t& phy_cell, srslte::event_observer observer); + bool start_cell_search(srslte::event_observer observer); void cell_search_completed(cell_search_ret_t cs_ret, phy_cell_t found_cell); void cell_selection_completed(bool outcome); void in_sync(); void out_sync() { trigger(out_sync_ev{}); } - // Event Observers - srslte::event_dispatcher cell_search_observers; - srslte::event_dispatcher cell_selection_observers; - // state getters bool cell_is_camping() { return phy->cell_is_camping(); } bool is_in_sync() const { return is_in_state(); } @@ -79,7 +75,7 @@ public: struct wait_csel_res {}; struct wait_in_sync { - void enter(selecting_cell* f, const cell_sel_res& ev); + void enter(selecting_cell* f); }; explicit selecting_cell(phy_controller* parent_); @@ -118,8 +114,10 @@ public: }; private: - phy_interface_rrc_lte* phy = nullptr; - srslte::task_sched_handle task_sched; + phy_interface_rrc_lte* phy = nullptr; + srslte::task_sched_handle task_sched; + srslte::event_observer cell_selection_observer; + srslte::event_dispatcher cell_search_observers; protected: state_list states{this, diff --git a/srsue/src/stack/rrc/phy_controller.cc b/srsue/src/stack/rrc/phy_controller.cc index 4bef27a42..b42d43dba 100644 --- a/srsue/src/stack/rrc/phy_controller.cc +++ b/srsue/src/stack/rrc/phy_controller.cc @@ -45,7 +45,7 @@ void phy_controller::in_sync() * PHY Cell Select Procedure *************************************/ -bool phy_controller::start_cell_select(const phy_cell_t& phy_cell) +bool phy_controller::start_cell_select(const phy_cell_t& phy_cell, srslte::event_observer observer) { if (is_in_state()) { log_h->warning("Failed to launch cell selection as it is already running\n"); @@ -56,6 +56,7 @@ bool phy_controller::start_cell_select(const phy_cell_t& phy_cell) log_h->warning("Failed to launch cell selection. Current state: %s\n", current_state_name().c_str()); return false; } + cell_selection_observer = std::move(observer); return true; } @@ -96,12 +97,12 @@ void phy_controller::selecting_cell::exit(phy_controller* f) // Signal result back to FSM that called cell selection bool result = csel_res.result; f->task_sched.defer_task([f, result]() { - f->cell_selection_observers.dispatch(result); - f->cell_selection_observers.unsubscribe_all(); + f->cell_selection_observer(result); + f->cell_selection_observer.reset(); }); } -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) { f->wait_in_sync_timer.set(wait_sync_timeout_ms, [f](uint32_t tid) { f->parent_fsm()->trigger(timeout_ev{}); }); f->wait_in_sync_timer.run(); @@ -112,7 +113,7 @@ 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 -bool phy_controller::start_cell_search() +bool phy_controller::start_cell_search(srslte::event_observer observer) { if (is_in_state()) { fsmInfo("Cell search already launched.\n"); @@ -123,6 +124,7 @@ bool phy_controller::start_cell_search() fsmWarning("Failed to launch cell search\n"); return false; } + cell_search_observers.subscribe(observer); return true; } diff --git a/srsue/src/stack/rrc/rrc_procedures.cc b/srsue/src/stack/rrc/rrc_procedures.cc index 616f7be45..1fa9e85bd 100644 --- a/srsue/src/stack/rrc/rrc_procedures.cc +++ b/srsue/src/stack/rrc/rrc_procedures.cc @@ -46,11 +46,10 @@ proc_outcome_t rrc::cell_search_proc::init() { Info("Starting...\n"); state = state_t::phy_cell_search; - if (not rrc_ptr->phy_ctrl->start_cell_search()) { + if (not rrc_ptr->phy_ctrl->start_cell_search(rrc_ptr->cell_searcher)) { Warning("Failed to initiate Cell Search.\n"); return proc_outcome_t::error; } - rrc_ptr->phy_ctrl->cell_search_observers.subscribe(rrc_ptr->cell_searcher); return proc_outcome_t::yield; } @@ -98,11 +97,10 @@ proc_outcome_t rrc::cell_search_proc::handle_cell_found(const phy_interface_rrc_ // set new serving cell in PHY 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, rrc_ptr->cell_searcher)) { Error("Couldn't start phy cell selection\n"); return proc_outcome_t::error; } - rrc_ptr->phy_ctrl->cell_selection_observers.subscribe(rrc_ptr->cell_searcher); return proc_outcome_t::yield; } @@ -511,11 +509,10 @@ 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()); 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, rrc_ptr->cell_selector)) { Error("Failed to launch PHY Cell Selection\n"); return proc_outcome_t::error; } - rrc_ptr->phy_ctrl->cell_selection_observers.subscribe(rrc_ptr->cell_selector); serv_cell_select_attempted = true; return proc_outcome_t::yield; } @@ -553,11 +550,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()); state = search_state_t::cell_selection; - 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, + rrc_ptr->cell_selector)) { Error("Failed to launch PHY Cell Selection\n"); return proc_outcome_t::error; } - rrc_ptr->phy_ctrl->cell_selection_observers.subscribe(rrc_ptr->cell_selector); return proc_outcome_t::yield; } } @@ -1492,11 +1489,10 @@ srslte::proc_outcome_t rrc::ho_proc::step() Info("Starting cell selection of target cell %s\n", target_cell->to_string().c_str()); - if (not rrc_ptr->phy_ctrl->start_cell_select(target_cell->phy_cell)) { + if (not rrc_ptr->phy_ctrl->start_cell_select(target_cell->phy_cell, rrc_ptr->ho_handler)) { Error("Failed to launch the selection of target cell %s\n", target_cell->to_string().c_str()); return proc_outcome_t::error; } - rrc_ptr->phy_ctrl->cell_selection_observers.subscribe(rrc_ptr->ho_handler); state = wait_phy_cell_select_complete; } return proc_outcome_t::yield; diff --git a/srsue/test/upper/rrc_phy_ctrl_test.cc b/srsue/test/upper/rrc_phy_ctrl_test.cc index d5894e32e..90a250685 100644 --- a/srsue/test/upper/rrc_phy_ctrl_test.cc +++ b/srsue/test/upper/rrc_phy_ctrl_test.cc @@ -83,8 +83,7 @@ int test_phy_ctrl_fsm() TESTASSERT(phy_ctrl.is_in_sync()); // TEST: Correct initiation of Cell Search state - TESTASSERT(phy_ctrl.start_cell_search()); - phy_ctrl.cell_search_observers.subscribe(csearch_tester); + TESTASSERT(phy_ctrl.start_cell_search(csearch_tester)); TESTASSERT(not phy_ctrl.is_in_sync()); // TEST: Cell Search only listens to a cell search result event @@ -112,8 +111,7 @@ int test_phy_ctrl_fsm() phy_ctrl.out_sync(); // TEST: Correct initiation of Cell Select state - phy_ctrl.start_cell_select(found_cell); - phy_ctrl.cell_selection_observers.subscribe(csel_tester); + phy_ctrl.start_cell_select(found_cell, csel_tester); TESTASSERT(not phy_ctrl.is_in_sync()); TESTASSERT(phy_ctrl.current_state_name() == "selecting_cell"); @@ -135,8 +133,7 @@ int test_phy_ctrl_fsm() // TEST: Cell Selection with timeout being reached csel_tester.result = -1; - TESTASSERT(phy_ctrl.start_cell_select(found_cell)); - phy_ctrl.cell_selection_observers.subscribe(csel_tester); + TESTASSERT(phy_ctrl.start_cell_select(found_cell, csel_tester)); TESTASSERT(not phy_ctrl.is_in_sync()); phy_ctrl.cell_selection_completed(true); TESTASSERT(phy_ctrl.current_state_name() == "selecting_cell");