From ec3ef4474edb863902c0543202d716d9847ed8ea Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Thu, 2 Apr 2020 20:30:33 +0100 Subject: [PATCH] created a simple procedure fsm --- lib/include/srslte/common/fsm.h | 78 ++++++++++++++++++++++++++++++++- lib/test/common/fsm_test.cc | 65 ++++++++++++++++++++++++++- 2 files changed, 140 insertions(+), 3 deletions(-) diff --git a/lib/include/srslte/common/fsm.h b/lib/include/srslte/common/fsm.h index 0100b87e7..ed1329870 100644 --- a/lib/include/srslte/common/fsm.h +++ b/lib/include/srslte/common/fsm.h @@ -23,6 +23,7 @@ #define SRSLTE_FSM_H #include "choice_type.h" +#include "srslte/common/logmap.h" #include #include #include @@ -101,7 +102,7 @@ struct fsm_helper { { static_assert(not std::is_same::value, "State cannot transition to itself.\n"); if (p != nullptr) { - srslte::get(f->states).exit(); + srslte::get(f->states).do_exit(); } f->states.transit(std::move(*s)); srslte::get(f->states).do_enter(); @@ -112,7 +113,7 @@ struct fsm_helper { { static_assert(FSM::is_nested, "State is not present in the FSM list of valid states"); if (p != nullptr) { - srslte::get(f->states).exit(); + srslte::get(f->states).do_exit(); } handle_state_change(f->parent_fsm()->derived(), s, static_cast(f)); } @@ -282,6 +283,79 @@ protected: ParentFSM* fsm_ptr = nullptr; }; +template +struct proc_complete_ev { + proc_complete_ev(bool success_) : success(success_) {} + bool success; +}; + +// event +template +struct proc_launch_ev { + std::tuple args; + explicit proc_launch_ev(Args&&... args_) : args(std::forward(args_)...) {} +}; + +template +class proc_fsm_t : public fsm_t +{ + using fsm_type = Derived; + using fsm_t::derived; + +public: + using base_t = proc_fsm_t; + using fsm_t::trigger; + + // states + struct idle_st : public state_t { + const char* name() const final { return "idle"; } + idle_st(Derived* f_) : fsm(f_) {} + void exit() + { + fsm->launch_counter++; + fsm->log_h->info("Proc %s: Starting run no. %d\n", fsm->derived()->name(), fsm->launch_counter); + } + Derived* fsm; + }; + struct complete_st : public srslte::state_t { + complete_st(Derived* fsm_, bool success_) : fsm(fsm_), success(success_) {} + const char* name() const final { return "complete"; } + void enter() { fsm->trigger(srslte::proc_complete_ev{success}); } + Derived* fsm; + bool success; + }; + + explicit proc_fsm_t(srslte::log_ref log_) : log_h(log_) {} + + bool is_running() const { return base_t::template is_in_state(); } + + srslte::log_ref log_h; + + template + void launch(Args&&... args) + { + trigger(proc_launch_ev(std::forward(args)...)); + } + + // template + // void trigger(proc_launch_ev e) + // { + // if (not base_t::template is_in_state()) { + // log_h->error("Proc %s: Ignoring launch because procedure is already running\n", base_t::derived()->name()); + // return; + // } + // base_t::trigger(std::move(e)); + // } + // template + // void trigger(T&& t) + // { + // base_t::trigger(std::forward(t)); + // } + +private: + int launch_counter = 0; +}; + } // namespace srslte #endif // SRSLTE_FSM_H diff --git a/lib/test/common/fsm_test.cc b/lib/test/common/fsm_test.cc index f2f7f9735..47156c975 100644 --- a/lib/test/common/fsm_test.cc +++ b/lib/test/common/fsm_test.cc @@ -188,9 +188,72 @@ int test_hsm() return SRSLTE_SUCCESS; } +/////////////////////////// + +struct procevent1 { +}; +struct procevent2 { +}; + +struct proc1 : public srslte::proc_fsm_t { +public: + struct procstate1 : public srslte::state_t { + const char* name() const final { return "procstate1"; } + }; + + proc1(srslte::log_ref log_) : base_t(log_) {} + + const char* name() const final { return "proc1"; } + +protected: + // Transitions + auto react(idle_st& s, srslte::proc_launch_ev ev) -> procstate1; + auto react(procstate1& s, procevent1 ev) -> complete_st; + auto react(procstate1& s, procevent2 ev) -> complete_st; + auto react(complete_st& s, srslte::proc_complete_ev ev) -> idle_st; + + state_list states{this}; +}; + +auto proc1::react(idle_st& s, srslte::proc_launch_ev ev) -> procstate1 +{ + log_h->info("started!\n"); + return {}; +} +auto proc1::react(procstate1& s, procevent1 ev) -> complete_st +{ + log_h->info("success!\n"); + return {this, true}; +} +auto proc1::react(procstate1& s, procevent2 ev) -> complete_st +{ + log_h->info("failure!\n"); + return {this, false}; +} +auto proc1::react(complete_st& s, srslte::proc_complete_ev ev) -> idle_st +{ + log_h->info("propagate results %s\n", s.success ? "success" : "failure"); + return {this}; +} + +int test_fsm_proc() +{ + proc1 proc{srslte::logmap::get("TEST")}; + int v = 2; + proc.launch(&v); + proc.launch(&v); + proc.trigger(procevent1{}); + proc.launch(&v); + proc.trigger(procevent2{}); + + return SRSLTE_SUCCESS; +} + int main() { - TESTASSERT(test_hsm() == SRSLTE_SUCCESS); + srslte::logmap::get("TEST")->set_level(srslte::LOG_LEVEL_INFO); + // TESTASSERT(test_hsm() == SRSLTE_SUCCESS); + TESTASSERT(test_fsm_proc() == SRSLTE_SUCCESS); return SRSLTE_SUCCESS; }