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 <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 {
// using same_state = mpark::monostate;
struct same_state {
};
@ -156,7 +172,7 @@ struct fsm_helper {
s->trigger(std::move(ev));
}
//! No trigger or react method found. Do nothing
void call_trigger2(...) {}
void call_trigger2(...) { f->unhandled_event(std::move(ev)); }
FSM* f;
Event ev;
@ -184,6 +200,7 @@ template <typename Derived>
class fsm_t : public state_t
{
protected:
using base_t = fsm_t<Derived>;
// get access to derived protected members from the base
class derived_view : public Derived
{
@ -191,6 +208,8 @@ protected:
using derived_t = Derived;
using Derived::react;
using Derived::states;
using Derived::unhandled_event;
using Derived::base_t::unhandled_event;
};
public:
@ -214,6 +233,8 @@ public:
}
};
explicit fsm_t(srslte::log_ref log_) : log_h(log_) {}
// Push Events to FSM
template <typename Ev>
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>();
}
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:
friend struct fsm_details::fsm_helper;
@ -261,6 +285,30 @@ protected:
fsm_details::fsm_helper::enter_visitor 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>
@ -271,7 +319,7 @@ public:
using parent_t = ParentFSM;
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
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_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:
using base_t = proc_fsm_t<Derived, Result>;
@ -325,12 +382,10 @@ public:
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>(); }
srslte::log_ref log_h;
template <typename... Args>
void launch(Args&&... args)
{

View File

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