reintroduced optional enter/exit methods for each state

This commit is contained in:
Francisco Paisana 2020-03-31 12:33:03 +01:00 committed by Francisco Paisana
parent 7c76a64238
commit 7dc1489ea7
4 changed files with 66 additions and 18 deletions

View File

@ -310,11 +310,16 @@ template <typename... Args>
class choice_t : private choice_details::tagged_union_t<Args...>
{
using base_t = choice_details::tagged_union_t<Args...>;
public:
//! Useful metafunction
template <typename T>
using enable_if_can_hold =
typename std::enable_if<base_t::template can_hold_type<typename std::decay<T>::type>()>::type;
template <typename T>
using disable_if_can_hold =
typename std::enable_if<not base_t::template can_hold_type<typename std::decay<T>::type>()>::type;
public:
using base_t::can_hold_type;
using base_t::get;
using base_t::get_if;
@ -408,6 +413,12 @@ const T* get_if(const choice_t<Args...>& c)
return c.template get_if<T>();
}
template <typename T, typename... Args>
T& get(choice_t<Args...>& c)
{
return c.template get<T>();
}
template <std::size_t I, typename... Args>
auto get(const choice_t<Args...>& c) -> decltype(c.template get<I>())
{

View File

@ -57,13 +57,25 @@ struct variant_convert {
{
static_assert(not std::is_same<typename std::decay<State>::type, typename std::decay<PrevState>::type>::value,
"State cannot transition to itself.\n");
if (p != nullptr) {
srslte::get<PrevState>(*v).exit();
}
*v = std::move(s);
srslte::get<State>(*v).enter();
}
TargetVariant* v;
PrevState* p;
};
struct fsm_helper {
//! Metafunction to determine if FSM can hold given State type
template <typename FSM>
using get_fsm_state_list = decltype(std::declval<typename FSM::derived_view>().states);
template <typename FSM, typename State>
using enable_if_fsm_state = typename get_fsm_state_list<FSM>::template enable_if_can_hold<State>;
template <typename FSM, typename State>
using disable_if_fsm_state = typename get_fsm_state_list<FSM>::template disable_if_can_hold<State>;
//! Stayed in same state
template <typename FSM, typename PrevState>
static void handle_state_change(FSM* f, same_state* s, PrevState* p)
@ -79,17 +91,25 @@ struct fsm_helper {
}
//! Simple state transition in FSM
template <typename FSM, typename State, typename PrevState>
static auto handle_state_change(FSM* f, State* s, PrevState* p) -> decltype(f->states = std::move(*s), void())
static enable_if_fsm_state<FSM, State> handle_state_change(FSM* f, State* s, PrevState* p)
{
static_assert(not std::is_same<State, PrevState>::value, "State cannot transition to itself.\n");
if (p != nullptr) {
srslte::get<PrevState>(f->states).exit();
}
f->states = std::move(*s);
srslte::get<State>(f->states).enter();
}
//! State not present in current FSM. Attempt state transition in parent FSM in the case of NestedFSM
template <typename FSM, typename... Args>
static void handle_state_change(FSM* f, Args&&... args)
template <typename FSM, typename State, typename PrevState>
static disable_if_fsm_state<FSM, State> handle_state_change(FSM* f, State* s, PrevState* p)
{
static_assert(FSM::is_nested, "State is not present in the FSM list of valid states");
handle_state_change(f->parent_fsm()->derived(), args...);
if (p != nullptr) {
srslte::get<PrevState>(f->states).exit();
p = nullptr;
}
handle_state_change(f->parent_fsm()->derived(), s, p);
}
//! Trigger Event, that will result in a state transition
@ -140,10 +160,12 @@ class state_t
public:
state_t() = default;
virtual const char* name() const = 0;
virtual void enter() {}
virtual void exit() {}
};
template <typename Derived>
class fsm_t
class fsm_t : public state_t
{
public:
// get access to derived protected members from the base
@ -155,8 +177,6 @@ public:
};
static const bool is_nested = false;
virtual const char* name() const = 0;
// Push Events to FSM
template <typename Ev>
void trigger(Ev&& e)

View File

@ -77,6 +77,10 @@ static_assert(std::is_same<tagged_union_t<char, int, double>::default_type, char
static_assert(tagged_union_t<char, int, double>::can_hold_type<int>(), "Can hold type implementation is incorrect\n");
static_assert(not tagged_union_t<char, int, double>::can_hold_type<uint8_t>(),
"Can hold type implementation is incorrect\n");
static_assert(std::is_same<choice_t<char, int, double>::enable_if_can_hold<char>, void>::value,
"Metafunction enable if not working\n");
static_assert(std::is_same<choice_t<char, int, double>::disable_if_can_hold<float>, void>::value,
"Metafunction enable if not working\n");
} // namespace choice_details
} // namespace srslte

View File

@ -38,18 +38,13 @@ public:
uint32_t idle_enter_counter = 0, state1_enter_counter = 0;
uint32_t foo_counter = 0;
fsm1() : states(idle_st{this}) {}
const char* name() const override { return "fsm1"; }
// idle state
struct idle_st : srslte::state_t {
idle_st(fsm1* f)
{
test_log->info("fsm1::%s::enter called\n", name());
f->idle_enter_counter++;
}
~idle_st() { test_log->info("fsm1::%s::exit called\n", name()); }
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()); }
const char* name() const final { return "idle"; }
};
@ -72,7 +67,7 @@ public:
struct state_inner : public srslte::state_t {
const char* name() const final { return "state_inner"; }
state_inner() { test_log->info("fsm2::%s::enter called\n", name()); }
~state_inner() { test_log->info("fsm2::%s::exit called\n", name()); }
void exit() final { test_log->info("fsm2::%s::exit called\n", name()); }
};
fsm2(fsm1* f_) : nested_fsm_t(f_) { test_log->info("%s::enter called\n", name()); }
@ -130,6 +125,24 @@ auto fsm1::react(state1& s, ev2 e) -> srslte::state_list<idle_st, fsm2>
return idle_st{this};
}
// Static Checks
namespace srslte {
namespace fsm_details {
static_assert(std::is_same<fsm_helper::get_fsm_state_list<fsm1>,
srslte::state_list<fsm1::idle_st, fsm1::state1, fsm1::fsm2> >::value,
"get state list failed\n");
static_assert(std::is_same<fsm_helper::enable_if_fsm_state<fsm1, fsm1::idle_st>, void>::value,
"get state list failed\n");
static_assert(std::is_same<fsm_helper::disable_if_fsm_state<fsm1, fsm1::fsm2::state_inner>, void>::value,
"get state list failed\n");
} // namespace fsm_details
} // namespace srslte
// Runtime checks
int test_hsm()
{
test_log->set_level(srslte::LOG_LEVEL_INFO);