use of transition table to support guards in fsms

This commit is contained in:
Francisco Paisana 2020-05-01 16:24:06 +01:00 committed by Francisco Paisana
parent 04e192eb0f
commit 9b48130ae1
3 changed files with 259 additions and 234 deletions

View File

@ -51,7 +51,7 @@ struct filter_transition_type<Event, SrcState, type_list<> > {
using type = type_list<>; using type = type_list<>;
}; };
//! Visitor to get a state's name string //! Visitor to get current state's name string
struct state_name_visitor { struct state_name_visitor {
template <typename State> template <typename State>
void operator()(State&& s) void operator()(State&& s)
@ -91,70 +91,98 @@ using enable_if_subfsm = typename std::enable_if<is_subfsm<FSM>()>::type;
template <typename FSM> template <typename FSM>
using disable_if_subfsm = typename std::enable_if<not is_subfsm<FSM>()>::type; using disable_if_subfsm = typename std::enable_if<not is_subfsm<FSM>()>::type;
struct fsm_helper { //! Metafunction to determine if FSM can hold given State type
//! Metafunction to determine if FSM can hold given State type template <typename FSM>
template <typename FSM> using fsm_state_list_type = decltype(std::declval<typename FSM::derived_view>().states);
using fsm_state_list_type = decltype(std::declval<typename FSM::derived_view>().states); template <typename FSM>
template <typename FSM> using fsm_transitions = typename FSM::derived_view::transitions;
using fsm_transitions = typename FSM::derived_view::transitions;
//! Call FSM/State enter method. If subfsm, call enter of subfsm init state as well template <typename FSM, typename T>
template <typename FSM, typename State> using state_enter_t = decltype(std::declval<typename FSM::derived_view>().enter(std::declval<T&>()));
static enable_if_subfsm<State> call_enter(FSM* f, State* s) template <typename FSM, typename T>
using state_exit_t = decltype(std::declval<typename FSM::derived_view>().exit(std::declval<T&>()));
//! Find State in FSM recursively (e.g. find State in FSM,FSM::parentFSM,FSM::parentFSM::parentFSM,...)
template <typename State, typename FSM>
static auto get_state_recursive(FSM* f) -> enable_if_fsm_state<FSM, State, State*>
{
return &f->states.template get_unchecked<State>();
}
struct derived_access {
template <typename T>
static typename T::derived_view* get(T* f)
{
return f->derived();
}
template <typename T>
static typename T::parent_t::derived_view* get_parent(T* f)
{
return f->parent_fsm()->derived();
}
};
template <typename State, typename FSM>
static auto get_state_recursive(FSM* f) -> disable_if_fsm_state<FSM, State, State*>
{
static_assert(FSM::is_nested, "State is not present in the FSM list of valid states");
return get_state_recursive<State>(derived_access::get_parent(f));
}
//! Helper type for FSM state-related operations
template <typename FSM, typename State>
struct state_traits {
static_assert(FSM::template can_hold_state<State>(), "FSM type does not hold provided State\n");
using state_t = State;
using is_subfsm = std::integral_constant<bool, ::srslte::fsm_details::is_subfsm<State>()>;
using has_enter = type_utils::is_detected<state_enter_t, FSM, State>;
using has_exit = type_utils::is_detected<state_exit_t, FSM, State>;
//! enter new state. enter is called recursively for subFSMs
static void enter_state(FSM* f, State* s) { enter_(f, s, is_subfsm{}); }
//! Change state. If DestState is not a state of FSM, call same function for parentFSM recursively
template <typename DestState>
static enable_if_fsm_state<FSM, DestState> transit_state(FSM* f)
{
exit_if_exists_(f, &f->states.template get_unchecked<State>(), has_exit{});
f->states.template transit<DestState>();
state_traits<FSM, DestState>::enter_state(f, &f->states.template get_unchecked<DestState>());
}
template <typename DestState>
static disable_if_fsm_state<FSM, DestState> transit_state(FSM* f)
{
exit_if_exists_(f, &f->states.template get_unchecked<State>(), has_exit{});
state_traits<typename FSM::parent_t::derived_view, typename FSM::derived_t>::template transit_state<DestState>(
derived_access::get_parent(f));
}
private:
//! In case of State is a subFSM
static void enter_(FSM* f, State* s, std::true_type)
{ {
using init_type = typename fsm_state_list_type<State>::init_state_t; using init_type = typename fsm_state_list_type<State>::init_state_t;
// set default FSM type // set default FSM type
s->derived()->states.template transit<init_type>(); derived_access::get(s)->states.template transit<init_type>();
// call FSM enter function // call FSM enter function
f->enter(*s); enter_if_exists_(f, s, has_enter{});
// call initial substate enter // call initial substate enter
call_enter(s->derived(), &s->derived()->states.template get_unchecked<init_type>()); state_traits<typename State::derived_view, init_type>::enter_state(
derived_access::get(s), &derived_access::get(s)->states.template get_unchecked<init_type>());
} }
//! In case of State is basic state
static void enter_(FSM* f, State* s, std::false_type) { enter_if_exists_(f, s, has_enter{}); }
static void enter_if_exists_(FSM* f, State* s, std::true_type) { f->enter(*s); }
static void enter_if_exists_(FSM* f, State* s, std::false_type) {}
static void exit_if_exists_(FSM* f, State* s, std::true_type) { f->exit(*s); }
static void exit_if_exists_(FSM* f, State* s, std::false_type) {}
};
template <typename FSM, typename State, typename... Args> //! Trigger Event reaction for the first Row for which the Guard passes
static disable_if_subfsm<State> call_enter(FSM* f, State* s) template <typename FSM, typename... Types>
{ struct apply_first_guard_pass;
f->enter(*s);
}
//! Simple state transition in FSM template <typename FSM, typename First, typename... Rows>
template <typename FSM, typename SrcState, typename DestState> struct apply_first_guard_pass<FSM, type_list<First, Rows...> > {
static auto handle_state_transition(FSM* f) -> enable_if_fsm_state<FSM, DestState>
{
f->exit(f->states.template get_unchecked<SrcState>());
f->states.template transit<DestState>();
call_enter(f, &f->states.template get_unchecked<DestState>());
}
//! State not present in current FSM. Attempt state transition in parent FSM in the case of NestedFSM
template <typename FSM, typename SrcState, typename DestState>
static auto handle_state_transition(FSM* f) -> disable_if_fsm_state<FSM, DestState>
{
static_assert(FSM::is_nested, "State is not present in the FSM list of valid states");
f->exit(f->states.template get_unchecked<SrcState>());
handle_state_transition<typename FSM::parent_t::derived_view, typename FSM::derived_t, DestState>(
f->parent_fsm()->derived());
}
template <typename State, typename FSM>
static auto get_state_recursive(FSM* f) -> enable_if_fsm_state<FSM, State, State*>
{
return &f->states.template get_unchecked<State>();
}
template <typename State, typename FSM>
static auto get_state_recursive(FSM* f) -> disable_if_fsm_state<FSM, State, State*>
{
static_assert(FSM::is_nested, "State is not present in the FSM list of valid states");
return get_state_recursive<State>(f->parent_fsm()->derived());
}
//! Trigger in first Row for which the Guard passes
template <typename FSM, typename... Types>
struct apply_first_guard_pass;
template <typename FSM, typename First, typename... Rows>
struct apply_first_guard_pass<FSM, type_list<First, Rows...> > {
template <typename SrcState> template <typename SrcState>
static bool trigger(FSM* f, SrcState& s, const typename First::event_t& ev) static bool trigger(FSM* f, SrcState& s, const typename First::event_t& ev)
{ {
@ -166,58 +194,27 @@ struct fsm_helper {
if (triggered) { if (triggered) {
// Log Transition // Log Transition
if (std::is_same<src_state, dest_state>::value) { if (std::is_same<src_state, dest_state>::value) {
f->log_h->info("FSM \"%s\": Event \"%s\" updated state \"%s\"\n", f->log_fsm_activity("FSM \"%s\": Event \"%s\" updated state \"%s\"\n",
get_type_name<typename FSM::derived_t>().c_str(), get_type_name<typename FSM::derived_t>().c_str(),
get_type_name<event_type>().c_str(), get_type_name<event_type>().c_str(),
get_type_name<src_state>().c_str()); get_type_name<src_state>().c_str());
} else { } else {
f->log_h->info("FSM \"%s\": Transition %s-->%s (cause: %s)", f->log_fsm_activity("FSM \"%s\": Transition detected - %s -> %s (cause: %s)",
get_type_name<typename FSM::derived_t>().c_str(), get_type_name<typename FSM::derived_t>().c_str(),
get_type_name<src_state>().c_str(), get_type_name<src_state>().c_str(),
get_type_name<dest_state>().c_str(), get_type_name<dest_state>().c_str(),
get_type_name<event_type>().c_str()); get_type_name<event_type>().c_str());
// Apply state change operations // Apply state change operations
handle_state_transition<FSM, src_state, dest_state>(f); state_traits<FSM, src_state>::template transit_state<dest_state>(f);
} }
return true; return true;
} }
return apply_first_guard_pass<FSM, type_list<Rows...> >::trigger(f, s, ev); return apply_first_guard_pass<FSM, type_list<Rows...> >::trigger(f, s, ev);
} }
};
// template<typename SrcState> template <typename FSM>
// bool test_react(FSM *f, SrcState &s, const typename First::event_t &ev) { struct apply_first_guard_pass<FSM, type_list<> > {
// using dest_state = typename First::dest_state_t;
// if (First::guard == nullptr or (f->*First::guard)(ev)) {
// // Guard Passed. Apply react method
// dest_state *d = get_state_recursive<dest_state, FSM>(f);
// if (First::react != nullptr) {
// (f->*First::react)(*d, ev);
// }
// return true;
// }
// return false;
// }
//
// template<>
// bool
// test_react<typename First::src_state_t>(FSM *f, typename First::src_state_t &s, const typename First::event_t
// &ev) {
// using dest_state = typename First::dest_state_t;
//
// if (First::guard == nullptr or (f->*First::guard)(s, ev)) {
// // Guard Passed. Apply react method
// dest_state *d = get_state_recursive<dest_state, FSM>(f);
// if (First::react != nullptr) {
// (f->*First::react)(s, *d, ev);
// }
// return true;
// }
// return false;
// }
};
template <typename FSM>
struct apply_first_guard_pass<FSM, type_list<> > {
template <typename SrcState, typename Event> template <typename SrcState, typename Event>
static bool trigger(FSM* f, SrcState& s, const Event& ev) static bool trigger(FSM* f, SrcState& s, const Event& ev)
{ {
@ -226,11 +223,11 @@ struct fsm_helper {
get_type_name<Event>().c_str()); get_type_name<Event>().c_str());
return false; return false;
} }
}; };
//! Trigger Event, that will result in a state transition //! Trigger Event, that will result in a state transition
template <typename FSM, typename Event> template <typename FSM, typename Event>
struct trigger_visitor { struct trigger_visitor {
using event_t = typename std::decay<Event>::type; using event_t = typename std::decay<Event>::type;
trigger_visitor(FSM* f_, Event&& ev_) : f(f_), ev(std::forward<Event>(ev_)) {} trigger_visitor(FSM* f_, Event&& ev_) : f(f_), ev(std::forward<Event>(ev_)) {}
@ -268,7 +265,6 @@ struct fsm_helper {
FSM* f; FSM* f;
Event ev; Event ev;
bool result = false; bool result = false;
};
}; };
} // namespace fsm_details } // namespace fsm_details
@ -285,13 +281,12 @@ protected:
template <typename SubFSM> template <typename SubFSM>
using subfsm_t = nested_fsm_t<SubFSM, Derived>; using subfsm_t = nested_fsm_t<SubFSM, Derived>;
public:
//! 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
{ {
public: public:
using derived_t = Derived; using derived_t = Derived;
using derived_t::base_t::enter;
using derived_t::base_t::exit;
// propagate user fsm methods // propagate user fsm methods
using Derived::enter; using Derived::enter;
using Derived::exit; using Derived::exit;
@ -317,7 +312,7 @@ protected:
static bool react(derived_view* f, src_state_t& s, const event_t& ev) static bool react(derived_view* f, src_state_t& s, const event_t& ev)
{ {
if (guard_fn == nullptr or (f->*guard_fn)(s, ev)) { if (guard_fn == nullptr or (f->*guard_fn)(s, ev)) {
dest_state_t* d = fsm_details::fsm_helper::get_state_recursive<dest_state_t, derived_view>(f); dest_state_t* d = fsm_details::get_state_recursive<dest_state_t, derived_view>(f);
if (react_fn != nullptr) { if (react_fn != nullptr) {
(f->*react_fn)(s, *d, ev); (f->*react_fn)(s, *d, ev);
} }
@ -346,7 +341,7 @@ protected:
static bool react(derived_view* f, SrcState& s, const event_t& ev) static bool react(derived_view* f, SrcState& s, const event_t& ev)
{ {
if (guard_fn == nullptr or (f->*guard_fn)(ev)) { if (guard_fn == nullptr or (f->*guard_fn)(ev)) {
dest_state_t* d = fsm_details::fsm_helper::get_state_recursive<dest_state_t, derived_view>(f); dest_state_t* d = fsm_details::get_state_recursive<dest_state_t, derived_view>(f);
if (react_fn != nullptr) { if (react_fn != nullptr) {
(f->*react_fn)(*d, ev); (f->*react_fn)(*d, ev);
} }
@ -362,7 +357,6 @@ protected:
template <typename... Rows> template <typename... Rows>
using transition_table = type_list<Rows...>; using transition_table = type_list<Rows...>;
public:
static const bool is_nested = false; static const bool is_nested = false;
//! Struct used to store FSM states //! Struct used to store FSM states
@ -377,7 +371,8 @@ public:
{ {
if (not Derived::is_nested) { if (not Derived::is_nested) {
// If Root FSM, call initial state enter method // If Root FSM, call initial state enter method
fsm_details::fsm_helper::call_enter(f->derived(), &get_unchecked<init_state_t>()); fsm_details::state_traits<derived_view, init_state_t>::enter_state(f->derived(),
&get_unchecked<init_state_t>());
} }
} }
@ -429,7 +424,7 @@ public:
template <typename Ev> template <typename Ev>
bool trigger(Ev&& e) bool trigger(Ev&& e)
{ {
fsm_details::fsm_helper::trigger_visitor<derived_view, Ev> visitor{derived(), std::forward<Ev>(e)}; fsm_details::trigger_visitor<derived_view, Ev> visitor{derived(), std::forward<Ev>(e)};
srslte::visit(visitor, derived()->states); srslte::visit(visitor, derived()->states);
return visitor.result; return visitor.result;
} }
@ -469,33 +464,13 @@ public:
template <typename State> template <typename State>
constexpr static bool can_hold_state() constexpr static bool can_hold_state()
{ {
return fsm_details::fsm_helper::fsm_state_list_type<fsm_t<Derived> >::template can_hold_type<State>(); return fsm_details::fsm_state_list_type<fsm_t<Derived> >::template can_hold_type<State>();
} }
void set_fsm_event_log_level(srslte::LOG_LEVEL_ENUM e) { fsm_event_log_level = e; } 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; } srslte::log_ref get_log() const { return log_h; }
protected:
friend struct fsm_details::fsm_helper;
// Access to CRTP derived class
derived_view* derived() { return static_cast<derived_view*>(this); }
const derived_view* derived() const { return static_cast<const derived_view*>(this); }
template <typename State>
void enter(State& s)
{
// do nothing by default
}
template <typename State>
void exit(State& s)
{
// do nothing by default
}
//! Log FSM activity method, e.g. state transitions //! Log FSM activity method, e.g. state transitions
template <typename... Args> template <typename... Args>
void log_fsm_activity(const char* format, Args&&... args) void log_fsm_activity(const char* format, Args&&... args)
@ -518,6 +493,17 @@ protected:
} }
} }
protected:
friend struct fsm_details::derived_access;
// Access to CRTP derived class
derived_view* derived() { return static_cast<derived_view*>(this); }
const derived_view* derived() const { return static_cast<const derived_view*>(this); }
void enter() {}
void exit() {}
srslte::log_ref log_h; srslte::log_ref log_h;
srslte::LOG_LEVEL_ENUM fsm_event_log_level = LOG_LEVEL_INFO; srslte::LOG_LEVEL_ENUM fsm_event_log_level = LOG_LEVEL_INFO;
}; };
@ -539,19 +525,11 @@ public:
protected: protected:
using parent_fsm_t = ParentFSM; using parent_fsm_t = ParentFSM;
using fsm_t<Derived>::enter;
using fsm_t<Derived>::exit; using fsm_t<Derived>::exit;
ParentFSM* fsm_ptr = nullptr; ParentFSM* fsm_ptr = nullptr;
}; };
template <typename Proc>
struct proc_complete_ev {
proc_complete_ev(bool success_) : success(success_) {}
bool success;
};
// event // event
template <typename... Args> template <typename... Args>
struct proc_launch_ev { struct proc_launch_ev {
@ -565,12 +543,9 @@ 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: protected:
using fsm_t<Derived>::log_h; using fsm_t<Derived>::log_h;
using fsm_t<Derived>::enter;
using fsm_t<Derived>::exit;
public: public:
using base_t = proc_fsm_t<Derived, Result>; using base_t = proc_fsm_t<Derived, Result>;
@ -581,7 +556,17 @@ public:
// states // states
struct idle_st { struct idle_st {
bool success = false; idle_st() = default;
template <typename T>
idle_st(bool success_, T&& r) : success(success_), result(std::forward<T>(r)), value_set(true)
{}
bool is_result_set() const { return value_set; }
bool is_success() const { return value_set and success; }
const Result& get_result() const { return result; }
private:
bool success = false, value_set = false;
Result result = {}; Result result = {};
}; };
@ -589,6 +574,16 @@ public:
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>(); }
bool is_success() const { return base_t::template get_state<idle_st>()->is_success(); }
const Result& get_result() const
{
if (is_success()) {
return base_t::template get_state<idle_st>->get_result();
}
THROW_BAD_ACCESS("in proc_fsm_t::get_result");
}
template <typename... Args> template <typename... Args>
void launch(Args&&... args) void launch(Args&&... args)
{ {
@ -599,26 +594,24 @@ protected:
void enter(idle_st& s) void enter(idle_st& s)
{ {
if (launch_counter > 0) { if (launch_counter > 0) {
log_h->info("Finished run no. %d %s\n", launch_counter, s.success ? "successfully" : "with an error"); log_h->info("FSM \"%s\": Finished run no. %d %s\n",
get_type_name<Derived>().c_str(),
launch_counter,
s.is_success() ? "successfully" : "with an error");
if (not s.is_result_set()) {
log_h->error(
"FSM \"%s\": No result was set for run no. %d\n", get_type_name<Derived>().c_str(), launch_counter);
}
} }
} }
void exit(idle_st& s) void exit(idle_st& s)
{ {
s = {};
launch_counter++; launch_counter++;
log_h->info("FSM \"%s\": Starting run no. %d\n", get_type_name<Derived>().c_str(), launch_counter); log_h->info("FSM \"%s\": Starting run no. %d\n", get_type_name<Derived>().c_str(), launch_counter);
} }
bool is_success() const { return base_t::template get_state<idle_st>()->success; }
const Result& get_result() const
{
if (is_success()) {
return base_t::template get_state<idle_st>->result;
}
THROW_BAD_ACCESS("in proc_fsm_t::get_result");
}
private: private:
int launch_counter = 0; int launch_counter = 0;
}; };

View File

@ -209,6 +209,37 @@ struct filter<Predicate> {
using type = type_list<>; using type = type_list<>;
}; };
/**************************
* Detect Pattern
*************************/
template <typename...>
using voider = void;
template <class Default, class AlwaysVoid, template <class...> class Op, class... Args>
struct detector {
using value_t = std::false_type;
using type = Default;
};
template <class Default, template <class...> class Op, class... Args>
struct detector<Default, voider<Op<Args...> >, Op, Args...> {
using value_t = std::true_type;
using type = Op<Args...>;
};
template <template <class...> class Op, class... Args>
using is_detected = typename detector<std::false_type, void, Op, Args...>::value_t;
template <template <class...> class Op, class... Args>
using detected_t = typename detector<std::false_type, void, Op, Args...>::type;
template <class Default, template <class...> class Op, class... Args>
using detected_or = detector<Default, void, Op, Args...>;
template <bool Condition, typename T = void>
using enable_if_t = typename std::enable_if<Condition, T>::type;
} // namespace type_utils } // namespace type_utils
/************************************ /************************************

View File

@ -51,6 +51,11 @@ public:
explicit fsm2(fsm1* f_) : nested_fsm_t(f_) {} explicit fsm2(fsm1* f_) : nested_fsm_t(f_) {}
~fsm2() { log_h->info("%s being destroyed!", get_type_name(*this).c_str()); } ~fsm2() { log_h->info("%s being destroyed!", get_type_name(*this).c_str()); }
private:
void inner_action1(state_inner& s, state_inner& d, const ev1& e);
void inner_action2(state_inner& s, state_inner2& d, const ev2& e);
void inner_action3(state_inner2& s, state1& d, const ev2& e);
protected: protected:
void enter(state_inner& s) void enter(state_inner& s)
{ {
@ -60,13 +65,6 @@ public:
void enter(state_inner2& s) { log_h->info("fsm1::%s::enter called\n", srslte::get_type_name(s).c_str()); } void enter(state_inner2& s) { log_h->info("fsm1::%s::enter called\n", srslte::get_type_name(s).c_str()); }
void exit(state_inner2& s) { log_h->info("fsm1::%s::exit called\n", srslte::get_type_name(s).c_str()); } void exit(state_inner2& s) { log_h->info("fsm1::%s::exit called\n", srslte::get_type_name(s).c_str()); }
// FSM2 transitions
void inner_action1(state_inner& s, state_inner& d, const ev1& e);
void inner_action2(state_inner& s, state_inner2& d, const ev2& e);
void inner_action3(state_inner2& s, state1& d, const ev2& e);
// list of states // list of states
state_list<state_inner, state_inner2> states{this}; state_list<state_inner, state_inner2> states{this};
using transitions = transition_table<row<state_inner, state_inner, ev1, &fsm2::inner_action1>, using transitions = transition_table<row<state_inner, state_inner, ev1, &fsm2::inner_action1>,
@ -74,16 +72,16 @@ public:
row<state_inner2, state1, ev2, &fsm2::inner_action3> >; row<state_inner2, state1, ev2, &fsm2::inner_action3> >;
}; };
private:
void action1(idle_st& s, state1& d, const ev1& e);
void action2(state1& s, fsm2& d, const ev1& e);
void action3(state1& s, idle_st& d, const ev2& e);
protected: protected:
// enter/exit // enter/exit
void enter(idle_st& s); void enter(idle_st& s);
void enter(state1& s); void enter(state1& s);
void exit(state1& s);
void action1(idle_st& s, state1& d, const ev1& e);
void action2(state1& s, fsm2& d, const ev1& e);
void action3(state1& s, idle_st& d, const ev2& e);
void foo(ev1 e) { foo_counter++; } void foo(ev1 e) { foo_counter++; }
@ -106,6 +104,11 @@ void fsm1::enter(state1& s)
state1_enter_counter++; state1_enter_counter++;
} }
void fsm1::exit(state1& s)
{
log_h->info("%s::exit custom called\n", srslte::get_type_name(s).c_str());
}
// FSM event handlers // FSM event handlers
void fsm1::fsm2::inner_action1(state_inner& s, state_inner& d, const ev1& e) void fsm1::fsm2::inner_action1(state_inner& s, state_inner& d, const ev1& e)
{ {
@ -145,16 +148,16 @@ namespace fsm_details {
static_assert(is_fsm<fsm1>(), "invalid metafunction\n"); static_assert(is_fsm<fsm1>(), "invalid metafunction\n");
static_assert(is_subfsm<fsm1::fsm2>(), "invalid metafunction\n"); static_assert(is_subfsm<fsm1::fsm2>(), "invalid metafunction\n");
static_assert( static_assert(type_list_size(typename filter_transition_type<ev1, fsm1::idle_st, fsm_transitions<fsm1> >::type{}) > 0,
type_list_size(typename filter_transition_type<ev1, fsm1::idle_st, fsm_helper::fsm_transitions<fsm1> >::type{}) > 0,
"invalid filter metafunction\n"); "invalid filter metafunction\n");
static_assert(std::is_same<fsm_helper::fsm_state_list_type<fsm1>, static_assert(
fsm1::state_list<fsm1::idle_st, fsm1::state1, fsm1::fsm2> >::value, std::is_same<fsm_state_list_type<fsm1>, fsm1::state_list<fsm1::idle_st, fsm1::state1, fsm1::fsm2> >::value,
"get state list failed\n"); "get state list failed\n");
static_assert(fsm1::can_hold_state<fsm1::state1>(), "failed can_hold_state check\n"); static_assert(fsm1::can_hold_state<fsm1::state1>(), "failed can_hold_state check\n");
static_assert(std::is_same<enable_if_fsm_state<fsm1, fsm1::idle_st>, void>::value, "get state list failed\n"); static_assert(std::is_same<enable_if_fsm_state<fsm1, fsm1::idle_st>, void>::value, "get state list failed\n");
static_assert(std::is_same<disable_if_fsm_state<fsm1, fsm1::fsm2::state_inner>, void>::value, static_assert(std::is_same<disable_if_fsm_state<fsm1, fsm1::fsm2::state_inner>, void>::value,
"get state list failed\n"); "get state list failed\n");
static_assert(type_utils::is_detected<state_enter_t, fsm1, fsm1::idle_st>::value, "Failed detection of enter method\n");
} // namespace fsm_details } // namespace fsm_details
} // namespace srslte } // namespace srslte
@ -264,15 +267,13 @@ void proc1::init(idle_st& s, procstate1& d, const srslte::proc_launch_ev<int*>&
void proc1::handle_success(procstate1& s, idle_st& d, const procevent1& ev) void proc1::handle_success(procstate1& s, idle_st& d, const procevent1& ev)
{ {
log_h->info("success!\n"); log_h->info("success!\n");
d.success = true; d = {true, 5};
d.result = 5;
} }
void proc1::handle_failure(procstate1& s, idle_st& d, const procevent1& ev) void proc1::handle_failure(procstate1& s, idle_st& d, const procevent1& ev)
{ {
log_h->info("failure!\n"); log_h->info("failure!\n");
d.success = false; d = {false, 3};
d.result = 3;
} }
int test_fsm_proc() int test_fsm_proc()
@ -291,12 +292,12 @@ int test_fsm_proc()
TESTASSERT(proc.current_state_name() == "procstate1"); TESTASSERT(proc.current_state_name() == "procstate1");
proc.trigger(procevent1{true}); proc.trigger(procevent1{true});
TESTASSERT(proc.current_state_name() == "idle_st"); TESTASSERT(proc.current_state_name() == "idle_st");
TESTASSERT(proc.get_state<proc1::idle_st>()->success); TESTASSERT(proc.get_state<proc1::idle_st>()->is_success());
proc.launch(&v); proc.launch(&v);
TESTASSERT(proc.current_state_name() == "procstate1"); TESTASSERT(proc.current_state_name() == "procstate1");
proc.trigger(procevent1{false}); proc.trigger(procevent1{false});
TESTASSERT(proc.current_state_name() == "idle_st"); TESTASSERT(proc.current_state_name() == "idle_st");
TESTASSERT(not proc.get_state<proc1::idle_st>()->success); TESTASSERT(not proc.get_state<proc1::idle_st>()->is_success());
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }