mirror of https://github.com/PentHertz/srsLTE.git
reintroduced optional enter/exit methods for each state
This commit is contained in:
parent
7c76a64238
commit
7dc1489ea7
|
@ -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>())
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue