mirror of https://github.com/PentHertz/srsLTE.git
use of transition table to support guards in fsms
This commit is contained in:
parent
04e192eb0f
commit
9b48130ae1
|
@ -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,65 +91,93 @@ 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&>()));
|
||||||
using init_type = typename fsm_state_list_type<State>::init_state_t;
|
|
||||||
// set default FSM type
|
|
||||||
s->derived()->states.template transit<init_type>();
|
|
||||||
// call FSM enter function
|
|
||||||
f->enter(*s);
|
|
||||||
// call initial substate enter
|
|
||||||
call_enter(s->derived(), &s->derived()->states.template get_unchecked<init_type>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename FSM, typename State, typename... Args>
|
|
||||||
static disable_if_subfsm<State> call_enter(FSM* f, State* s)
|
|
||||||
{
|
|
||||||
f->enter(*s);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Simple state transition in FSM
|
|
||||||
template <typename FSM, typename SrcState, typename DestState>
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
//! Find State in FSM recursively (e.g. find State in FSM,FSM::parentFSM,FSM::parentFSM::parentFSM,...)
|
||||||
template <typename State, typename FSM>
|
template <typename State, typename FSM>
|
||||||
static auto get_state_recursive(FSM* f) -> enable_if_fsm_state<FSM, State, State*>
|
static auto get_state_recursive(FSM* f) -> enable_if_fsm_state<FSM, State, State*>
|
||||||
{
|
{
|
||||||
return &f->states.template get_unchecked<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>
|
template <typename State, typename FSM>
|
||||||
static auto get_state_recursive(FSM* f) -> disable_if_fsm_state<FSM, State, State*>
|
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");
|
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());
|
return get_state_recursive<State>(derived_access::get_parent(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Trigger in first Row for which the Guard passes
|
//! 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;
|
||||||
|
// set default FSM type
|
||||||
|
derived_access::get(s)->states.template transit<init_type>();
|
||||||
|
// call FSM enter function
|
||||||
|
enter_if_exists_(f, s, has_enter{});
|
||||||
|
// call initial substate enter
|
||||||
|
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) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Trigger Event reaction for the first Row for which the Guard passes
|
||||||
template <typename FSM, typename... Types>
|
template <typename FSM, typename... Types>
|
||||||
struct apply_first_guard_pass;
|
struct apply_first_guard_pass;
|
||||||
|
|
||||||
|
@ -166,54 +194,23 @@ 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>
|
|
||||||
// bool test_react(FSM *f, SrcState &s, const typename First::event_t &ev) {
|
|
||||||
// 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>
|
template <typename FSM>
|
||||||
|
@ -269,7 +266,6 @@ struct fsm_helper {
|
||||||
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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
/************************************
|
/************************************
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue