created a method to detect unhandled events

This commit is contained in:
Francisco Paisana 2020-04-03 13:34:23 +01:00 committed by Francisco Paisana
parent ec3ef4474e
commit 4a4827a603
2 changed files with 103 additions and 30 deletions

View File

@ -31,9 +31,25 @@
#include <memory> #include <memory>
#include <tuple> #include <tuple>
// Helper to print a type name for logging
#if defined(__GNUC__) && !defined(__clang__)
template <typename T>
std::string get_type_name()
{
static const char* s = __PRETTY_FUNCTION__;
static const char* pos1 = strchr(s, '=') + 2;
return std::string{pos1, strchr(pos1, ';')};
}
#else
template <typename T>
std::string get_type_name()
{
return "anonymous";
}
#endif
namespace srslte { namespace srslte {
// using same_state = mpark::monostate;
struct same_state { struct same_state {
}; };
@ -156,7 +172,7 @@ struct fsm_helper {
s->trigger(std::move(ev)); s->trigger(std::move(ev));
} }
//! No trigger or react method found. Do nothing //! No trigger or react method found. Do nothing
void call_trigger2(...) {} void call_trigger2(...) { f->unhandled_event(std::move(ev)); }
FSM* f; FSM* f;
Event ev; Event ev;
@ -184,6 +200,7 @@ template <typename Derived>
class fsm_t : public state_t class fsm_t : public state_t
{ {
protected: protected:
using base_t = fsm_t<Derived>;
// get access to derived protected members from the base // get access to derived protected members from the base
class derived_view : public Derived class derived_view : public Derived
{ {
@ -191,6 +208,8 @@ protected:
using derived_t = Derived; using derived_t = Derived;
using Derived::react; using Derived::react;
using Derived::states; using Derived::states;
using Derived::unhandled_event;
using Derived::base_t::unhandled_event;
}; };
public: public:
@ -214,6 +233,8 @@ public:
} }
}; };
explicit fsm_t(srslte::log_ref log_) : log_h(log_) {}
// Push Events to FSM // Push Events to FSM
template <typename Ev> template <typename Ev>
void trigger(Ev&& e) void trigger(Ev&& e)
@ -248,6 +269,9 @@ public:
return fsm_details::fsm_helper::get_fsm_state_list<fsm_t<Derived> >::template can_hold_type<State>(); return fsm_details::fsm_helper::get_fsm_state_list<fsm_t<Derived> >::template can_hold_type<State>();
} }
void set_fsm_event_log_level(srslte::LOG_LEVEL_ENUM e) { fsm_event_log_level = e; }
srslte::log_ref get_log() const { return log_h; }
protected: protected:
friend struct fsm_details::fsm_helper; friend struct fsm_details::fsm_helper;
@ -261,6 +285,30 @@ protected:
fsm_details::fsm_helper::enter_visitor visitor{}; fsm_details::fsm_helper::enter_visitor visitor{};
derived()->states.visit(visitor); derived()->states.visit(visitor);
} }
template <typename Event>
void unhandled_event(Event&& e)
{
switch (fsm_event_log_level) {
case LOG_LEVEL_DEBUG:
log_h->debug("Unhandled event caught: \"%s\"\n", get_type_name<Event>().c_str());
break;
case LOG_LEVEL_INFO:
log_h->info("Unhandled event caught: \"%s\"\n", get_type_name<Event>().c_str());
break;
case LOG_LEVEL_WARNING:
log_h->warning("Unhandled event caught: \"%s\"\n", get_type_name<Event>().c_str());
break;
case LOG_LEVEL_ERROR:
log_h->error("Unhandled event caught: \"%s\"\n", get_type_name<Event>().c_str());
break;
default:
break;
}
}
srslte::log_ref log_h;
srslte::LOG_LEVEL_ENUM fsm_event_log_level = LOG_LEVEL_DEBUG;
}; };
template <typename Derived, typename ParentFSM> template <typename Derived, typename ParentFSM>
@ -271,7 +319,7 @@ public:
using parent_t = ParentFSM; using parent_t = ParentFSM;
static const bool is_nested = true; static const bool is_nested = true;
explicit nested_fsm_t(ParentFSM* parent_fsm_) : fsm_ptr(parent_fsm_) {} explicit nested_fsm_t(ParentFSM* parent_fsm_) : fsm_t<Derived>(parent_fsm_->get_log()), fsm_ptr(parent_fsm_) {}
// Get pointer to outer FSM in case of HSM // Get pointer to outer FSM in case of HSM
const parent_t* parent_fsm() const { return fsm_ptr; } const parent_t* parent_fsm() const { return fsm_ptr; }
@ -301,6 +349,15 @@ class proc_fsm_t : public fsm_t<Derived>
{ {
using fsm_type = Derived; using fsm_type = Derived;
using fsm_t<Derived>::derived; using fsm_t<Derived>::derived;
friend struct fsm_details::fsm_helper;
protected:
using fsm_t<Derived>::log_h;
using fsm_t<Derived>::unhandled_event;
void unhandled_event(srslte::proc_launch_ev<int*> e)
{
log_h->warning("Unhandled event \"launch\" caught when procedure is already running\n");
}
public: public:
using base_t = proc_fsm_t<Derived, Result>; using base_t = proc_fsm_t<Derived, Result>;
@ -325,12 +382,10 @@ public:
bool success; bool success;
}; };
explicit proc_fsm_t(srslte::log_ref log_) : log_h(log_) {} explicit proc_fsm_t(srslte::log_ref log_) : fsm_t<Derived>(log_) {}
bool is_running() const { return base_t::template is_in_state<idle_st>(); } bool is_running() const { return base_t::template is_in_state<idle_st>(); }
srslte::log_ref log_h;
template <typename... Args> template <typename... Args>
void launch(Args&&... args) void launch(Args&&... args)
{ {

View File

@ -22,8 +22,6 @@
#include "srslte/common/fsm.h" #include "srslte/common/fsm.h"
#include "srslte/common/test_common.h" #include "srslte/common/test_common.h"
srslte::log_ref test_log{"TEST"};
///////////////////////////// /////////////////////////////
// Events // Events
@ -39,23 +37,26 @@ public:
uint32_t foo_counter = 0; uint32_t foo_counter = 0;
const char* name() const override { return "fsm1"; } const char* name() const override { return "fsm1"; }
fsm1(srslte::log_ref log_) : srslte::fsm_t<fsm1>(log_) {}
// idle state // idle state
struct idle_st : public srslte::state_t { struct idle_st : public srslte::state_t {
idle_st(fsm1* f) { f->idle_enter_counter++; } idle_st(fsm1* f_) : f(f_) { f->idle_enter_counter++; }
void enter() final { test_log->info("fsm1::%s::enter called\n", name()); } void enter() final { f->log_h->info("fsm1::%s::enter called\n", name()); }
void exit() final { test_log->info("fsm1::%s::exit called\n", name()); } void exit() final { f->log_h->info("fsm1::%s::exit called\n", name()); }
const char* name() const final { return "idle"; } const char* name() const final { return "idle"; }
fsm1* f;
}; };
// simple state // simple state
class state1 : public srslte::state_t class state1 : public srslte::state_t
{ {
public: public:
state1(fsm1* f) { f->state1_enter_counter++; } state1(fsm1* f_) : f(f_) { f->state1_enter_counter++; }
void enter() final { test_log->info("fsm1::%s::enter called\n", name()); } void enter() final { f->log_h->info("fsm1::%s::enter called\n", name()); }
void exit() final { test_log->info("fsm1::%s::exit called\n", name()); } void exit() final { f->log_h->info("fsm1::%s::exit called\n", name()); }
const char* name() const final { return "state1"; } const char* name() const final { return "state1"; }
fsm1* f;
}; };
// this state is another FSM // this state is another FSM
@ -64,13 +65,16 @@ public:
public: public:
struct state_inner : public srslte::state_t { struct state_inner : public srslte::state_t {
const char* name() const final { return "state_inner"; } const char* name() const final { return "state_inner"; }
void enter() { test_log->info("fsm2::%s::enter called\n", name()); } state_inner(fsm2* f_) : f(f_) {}
void exit() final { test_log->info("fsm2::%s::exit called\n", name()); } void enter() { f->log_h->info("fsm2::%s::enter called\n", name()); }
// void exit() final { f->log_h->info("fsm2::%s::exit called\n", name()); }
fsm2* f;
}; };
fsm2(fsm1* f_) : nested_fsm_t(f_) {} fsm2(fsm1* f_) : nested_fsm_t(f_) {}
void enter() final { test_log->info("%s::enter called\n", name()); } ~fsm2() { log_h->info("%s being destroyed!", name()); }
void exit() { test_log->info("%s::exit called\n", name()); } void enter() final { log_h->info("%s::enter called\n", name()); }
void exit() { log_h->info("%s::exit called\n", name()); }
const char* name() const final { return "fsm2"; } const char* name() const final { return "fsm2"; }
protected: protected:
@ -79,7 +83,7 @@ public:
auto react(state_inner& s, ev2 e) -> state1; auto react(state_inner& s, ev2 e) -> state1;
// list of states // list of states
state_list<state_inner> states; state_list<state_inner> states{this};
}; };
protected: protected:
@ -97,30 +101,30 @@ protected:
// FSM event handlers // FSM event handlers
auto fsm1::fsm2::react(state_inner& s, ev1 e) -> srslte::same_state auto fsm1::fsm2::react(state_inner& s, ev1 e) -> srslte::same_state
{ {
test_log->info("fsm2::state_inner::react called\n"); log_h->info("fsm2::state_inner::react called\n");
return {}; return {};
} }
auto fsm1::fsm2::react(state_inner& s, ev2 e) -> state1 auto fsm1::fsm2::react(state_inner& s, ev2 e) -> state1
{ {
test_log->info("fsm2::state_inner::react called\n"); log_h->info("fsm2::state_inner::react called\n");
return state1{parent_fsm()}; return state1{parent_fsm()};
} }
auto fsm1::react(idle_st& s, ev1 e) -> state1 auto fsm1::react(idle_st& s, ev1 e) -> state1
{ {
test_log->info("fsm1::%s::react called\n", s.name()); log_h->info("fsm1::%s::react called\n", s.name());
foo(e); foo(e);
return state1{this}; return state1{this};
} }
auto fsm1::react(state1& s, ev1 e) -> fsm2 auto fsm1::react(state1& s, ev1 e) -> fsm2
{ {
test_log->info("fsm1::%s::react called\n", s.name()); log_h->info("fsm1::%s::react called\n", s.name());
return fsm2{this}; return fsm2{this};
} }
auto fsm1::react(state1& s, ev2 e) -> srslte::choice_t<idle_st, fsm2> auto fsm1::react(state1& s, ev2 e) -> srslte::choice_t<idle_st, fsm2>
{ {
test_log->info("fsm1::%s::react called\n", s.name()); log_h->info("fsm1::%s::react called\n", s.name());
return idle_st{this}; return idle_st{this};
} }
@ -145,9 +149,11 @@ static_assert(fsm1::can_hold_state<fsm1::state1>(), "can hold state method faile
int test_hsm() int test_hsm()
{ {
test_log->set_level(srslte::LOG_LEVEL_INFO); srslte::log_ref log_h{"HSM"};
log_h->prepend_string("HSM: ");
log_h->set_level(srslte::LOG_LEVEL_INFO);
fsm1 f; fsm1 f{log_h};
TESTASSERT(std::string{f.name()} == "fsm1"); TESTASSERT(std::string{f.name()} == "fsm1");
TESTASSERT(std::string{f.get_state_name()} == "idle"); TESTASSERT(std::string{f.get_state_name()} == "idle");
TESTASSERT(f.is_in_state<fsm1::idle_st>()); TESTASSERT(f.is_in_state<fsm1::idle_st>());
@ -212,6 +218,9 @@ protected:
auto react(procstate1& s, procevent2 ev) -> complete_st; auto react(procstate1& s, procevent2 ev) -> complete_st;
auto react(complete_st& s, srslte::proc_complete_ev<bool> ev) -> idle_st; auto react(complete_st& s, srslte::proc_complete_ev<bool> ev) -> idle_st;
// example of uncaught event handling
void unhandled_event(int e) { log_h->info("I dont know how to handle an \"int\" event\n"); }
state_list<idle_st, procstate1, complete_st> states{this}; state_list<idle_st, procstate1, complete_st> states{this};
}; };
@ -238,10 +247,14 @@ auto proc1::react(complete_st& s, srslte::proc_complete_ev<bool> ev) -> idle_st
int test_fsm_proc() int test_fsm_proc()
{ {
proc1 proc{srslte::logmap::get("TEST")}; proc1 proc{srslte::logmap::get("PROC")};
int v = 2; proc.get_log()->prepend_string("Proc1: ");
proc.get_log()->set_level(srslte::LOG_LEVEL_INFO);
proc.set_fsm_event_log_level(srslte::LOG_LEVEL_INFO);
int v = 2;
proc.launch(&v); proc.launch(&v);
proc.launch(&v); proc.launch(&v);
proc.trigger(5);
proc.trigger(procevent1{}); proc.trigger(procevent1{});
proc.launch(&v); proc.launch(&v);
proc.trigger(procevent2{}); proc.trigger(procevent2{});
@ -249,11 +262,16 @@ int test_fsm_proc()
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }
///////////////////////////
int main() int main()
{ {
srslte::logmap::get("TEST")->set_level(srslte::LOG_LEVEL_INFO); srslte::log_ref testlog{"TEST"};
// TESTASSERT(test_hsm() == SRSLTE_SUCCESS); testlog->set_level(srslte::LOG_LEVEL_INFO);
TESTASSERT(test_hsm() == SRSLTE_SUCCESS);
testlog->info("TEST \"hsm\" finished successfully\n\n");
TESTASSERT(test_fsm_proc() == SRSLTE_SUCCESS); TESTASSERT(test_fsm_proc() == SRSLTE_SUCCESS);
testlog->info("TEST \"proc\" finished successfully\n\n");
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }