diff --git a/lib/include/srslte/common/choice_type.h b/lib/include/srslte/common/choice_type.h index 8be6b0b95..5d951c623 100644 --- a/lib/include/srslte/common/choice_type.h +++ b/lib/include/srslte/common/choice_type.h @@ -401,8 +401,8 @@ bool holds_alternative(const Choice& u) return u.template is(); } -template -T* get_if(Choice& c) +template +T* get_if(choice_t& c) { return c.template get_if(); } diff --git a/lib/include/srslte/common/fsm.h b/lib/include/srslte/common/fsm.h index fbaf7a2a5..0100b87e7 100644 --- a/lib/include/srslte/common/fsm.h +++ b/lib/include/srslte/common/fsm.h @@ -35,8 +35,6 @@ namespace srslte { // using same_state = mpark::monostate; struct same_state { }; -template -using state_list = choice_t; namespace fsm_details { @@ -60,7 +58,7 @@ struct variant_convert { if (p != nullptr) { srslte::get(*v).exit(); } - *v = std::move(s); + v->transit(std::move(s)); srslte::get(*v).enter(); } TargetVariant* v; @@ -76,6 +74,14 @@ struct fsm_helper { template using disable_if_fsm_state = typename get_fsm_state_list::template disable_if_can_hold; + struct enter_visitor { + template + void operator()(State&& s) + { + s.do_enter(); + } + }; + //! Stayed in same state template static void handle_state_change(FSM* f, same_state* s, PrevState* p) @@ -97,8 +103,8 @@ struct fsm_helper { if (p != nullptr) { srslte::get(f->states).exit(); } - f->states = std::move(*s); - srslte::get(f->states).enter(); + f->states.transit(std::move(*s)); + srslte::get(f->states).do_enter(); } //! State not present in current FSM. Attempt state transition in parent FSM in the case of NestedFSM template @@ -164,8 +170,12 @@ class state_t public: state_t() = default; virtual const char* name() const = 0; - virtual void enter() {} - virtual void exit() {} + void do_enter() { enter(); } + void do_exit() { exit(); } + +protected: + virtual void enter() {} + virtual void exit() {} }; //! CRTP Class for all non-nested FSMs @@ -185,6 +195,24 @@ protected: public: static const bool is_nested = false; + template + struct state_list : public choice_t { + using base_t = choice_t; + template + state_list(Args&&... args) : base_t(std::forward(args)...) + { + if (not Derived::is_nested) { + fsm_details::fsm_helper::enter_visitor visitor{}; + this->visit(visitor); + } + } + template + void transit(State&& s) + { + this->template emplace(std::forward(s)); + } + }; + // Push Events to FSM template void trigger(Ev&& e) @@ -225,6 +253,13 @@ protected: // Access to CRTP derived class derived_view* derived() { return static_cast(this); } const derived_view* derived() const { return static_cast(this); } + + void do_enter() + { + enter(); + fsm_details::fsm_helper::enter_visitor visitor{}; + derived()->states.visit(visitor); + } }; template diff --git a/lib/test/common/fsm_test.cc b/lib/test/common/fsm_test.cc index ee96b6979..f2f7f9735 100644 --- a/lib/test/common/fsm_test.cc +++ b/lib/test/common/fsm_test.cc @@ -79,19 +79,19 @@ public: auto react(state_inner& s, ev2 e) -> state1; // list of states - srslte::state_list states; + state_list states; }; protected: // transitions auto react(idle_st& s, ev1 e) -> state1; auto react(state1& s, ev1 e) -> fsm2; - auto react(state1& s, ev2 e) -> srslte::state_list; + auto react(state1& s, ev2 e) -> srslte::choice_t; void foo(ev1 e) { foo_counter++; } // list of states - srslte::state_list states{idle_st{this}}; + state_list states{idle_st{this}}; }; // FSM event handlers @@ -118,7 +118,7 @@ auto fsm1::react(state1& s, ev1 e) -> fsm2 test_log->info("fsm1::%s::react called\n", s.name()); return fsm2{this}; } -auto fsm1::react(state1& s, ev2 e) -> srslte::state_list +auto fsm1::react(state1& s, ev2 e) -> srslte::choice_t { test_log->info("fsm1::%s::react called\n", s.name()); return idle_st{this}; @@ -130,7 +130,7 @@ namespace srslte { namespace fsm_details { static_assert(std::is_same, - srslte::state_list >::value, + fsm1::state_list >::value, "get state list failed\n"); static_assert(std::is_same, void>::value, "get state list failed\n");