mirror of https://github.com/PentHertz/srsLTE.git
created a method to detect unhandled events
This commit is contained in:
parent
ec3ef4474e
commit
4a4827a603
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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")};
|
||||||
|
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;
|
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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue