diff --git a/lib/include/srslte/common/fsm.h b/lib/include/srslte/common/fsm.h index 6ccbe1133..8e4537b67 100644 --- a/lib/include/srslte/common/fsm.h +++ b/lib/include/srslte/common/fsm.h @@ -25,6 +25,7 @@ #include "srslte/common/logmap.h" #include "type_utils.h" #include +#include #include #include #include @@ -418,9 +419,18 @@ public: template bool trigger(Ev&& e) { - fsm_details::trigger_visitor visitor{derived(), std::forward(e)}; - srslte::visit(visitor, derived()->states); - return visitor.result; + if (trigger_locked) { + pending_events.emplace_back([e](fsm_t* d) { d->process_event(e); }); + return false; + } + trigger_locked = true; + bool ret = process_event(std::forward(e)); + while (not pending_events.empty()) { + pending_events.front()(this); + pending_events.pop_front(); + } + trigger_locked = false; + return ret; } template @@ -493,8 +503,18 @@ protected: const derived_view* derived() const { return static_cast(this); } - srslte::log_ref log_h; - srslte::LOG_LEVEL_ENUM fsm_event_log_level = LOG_LEVEL_INFO; + template + bool process_event(Ev&& e) + { + fsm_details::trigger_visitor visitor{derived(), std::forward(e)}; + srslte::visit(visitor, derived()->states); + return visitor.result; + } + + srslte::log_ref log_h; + srslte::LOG_LEVEL_ENUM fsm_event_log_level = LOG_LEVEL_INFO; + bool trigger_locked = false; + std::deque*)> > pending_events; }; template diff --git a/lib/test/common/fsm_test.cc b/lib/test/common/fsm_test.cc index 785903a82..8d416dd22 100644 --- a/lib/test/common/fsm_test.cc +++ b/lib/test/common/fsm_test.cc @@ -451,6 +451,46 @@ int test_nas_fsm() return SRSLTE_SUCCESS; } +struct fsm3 : public srslte::fsm_t { + struct st1 {}; + struct st2 { + int counter = 0; + void enter(fsm3* fsm) { counter++; } + }; + + fsm3() : base_t(srslte::log_ref{"TEST"}) {} + +protected: + void handle_ev1(st1& s, st2& d, const ev1& ev) { trigger(ev2{}); } + void handle_ev2(st2& s, st1& d, const ev2& ev) + { + if (s.counter < 2) { + trigger(ev1{}); + } + } + + state_list states{this}; + // clang-format off + using transitions = transition_table< + // Start Target Event Action + // +------------------------+-------------------------+-------------------+--------------------+ + row< st1, st2, ev1, &fsm3::handle_ev1>, + row< st2, st1, ev2, &fsm3::handle_ev2> + >; + // clang-format on +}; + +int test_fsm_self_trigger() +{ + fsm3 fsm; + + TESTASSERT(fsm.is_in_state()); + fsm.trigger(ev1{}); + TESTASSERT(fsm.is_in_state()); + + return SRSLTE_SUCCESS; +} + int main() { srslte::log_ref testlog{"TEST"}; @@ -461,6 +501,8 @@ int main() testlog->info("TEST \"proc\" finished successfully\n\n"); TESTASSERT(test_nas_fsm() == SRSLTE_SUCCESS); testlog->info("TEST \"nas fsm\" finished successfully\n\n"); + TESTASSERT(test_fsm_self_trigger() == SRSLTE_SUCCESS); + testlog->info("TEST \"fsm self trigger\" finished successfully\n\n"); return SRSLTE_SUCCESS; }