501 virtual void start(
bool call_on_enter_state =
true)
508 p_state = state_list[0];
511 if (call_on_enter_state)
517 p_last_state = p_state;
518 next_state_id = p_state->on_enter_state();
519 if (next_state_id != ifsm_state::No_State_Change)
522 p_state = state_list[next_state_id];
524 }
while (p_last_state != p_state);
540 process_state_change(next_state_id);
557 return process_state_change(new_state_id);
561 return ifsm_state::No_State_Change;
565 using imessage_router::accepts;
582 return p_state->get_state_id();
608 return p_state != ETL_NULLPTR;
616 virtual void reset(
bool call_on_exit_state =
false)
622 p_state->on_exit_state();
625 p_state = ETL_NULLPTR;
630 bool is_null_router() const ETL_OVERRIDE
636 bool is_producer() const ETL_OVERRIDE
642 bool is_consumer() const ETL_OVERRIDE
652 return (next_state_id != p_state->get_state_id()) && (next_state_id != ifsm_state::No_State_Change)
653 && (next_state_id != ifsm_state::Self_Transition);
659 return (next_state_id == ifsm_state::Self_Transition);
667 if (is_self_transition(next_state_id))
669 p_state->on_exit_state();
670 next_state_id = p_state->on_enter_state();
673 if (have_changed_state(next_state_id))
679 p_state->on_exit_state();
680 p_state = p_next_state;
682 next_state_id = p_state->on_enter_state();
684 if (have_changed_state(next_state_id))
687 p_next_state = state_list[next_state_id];
689 }
while (p_next_state != p_state);
692 return p_state->get_state_id();
695 etl::ifsm_state* p_state;
696 etl::ifsm_state** state_list;
698 bool is_processing_state_change;
706#if ETL_USING_CPP11 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION)
710 template <
typename TContext,
typename TDerived,
etl::fsm_state_id_t STATE_ID_,
typename... TMessageTypes>
715 using message_id_sequence = etl::index_sequence<TMessageTypes::ID...>;
719 using message_types = etl::type_list<TMessageTypes...>;
720 using sorted_message_types = etl::type_list_sort_t<message_types, etl::compare_message_id_less>;
722 static_assert(etl::type_list_is_unique<message_types>::value,
"All TMessageTypes must be unique");
723 static_assert(etl::type_list_all_of<message_types, etl::is_message_type>::value,
724 "All TMessageTypes must satisfy the condition etl::is_message_type");
725 static_assert(etl::index_sequence_is_unique<message_id_sequence>::value,
"All message IDs must be unique");
738 TContext& get_fsm_context()
const
740 return static_cast<TContext&
>(ifsm_state::get_fsm_context());
745 static constexpr size_t Number_Of_Messages =
sizeof...(TMessageTypes);
746 static constexpr etl::message_id_t Message_Id_Start = etl::type_list_type_at_index_t<sorted_message_types, 0>::ID;
748 static_assert(Number_Of_Messages > 0,
"Zero messages");
753 template <
size_t Index,
bool Last = (Index + 1U >= Number_Of_Messages)>
754 struct contiguous_impl;
756 template <
size_t Index>
757 struct contiguous_impl<Index, true> : etl::true_type
761 template <
size_t Index>
762 struct contiguous_impl<Index, false>
763 :
etl::bool_constant< (etl::type_list_type_at_index_t<sorted_message_types, Index>::ID + 1U
764 == etl::type_list_type_at_index_t<sorted_message_types, Index + 1U>::ID)
765 && contiguous_impl<Index + 1U>::value>
771 static constexpr bool Message_Ids_Are_Contiguous = (Number_Of_Messages <= 1U) ? true : contiguous_impl<0U>::value;
777 using message_dispatch_table_t =
etl::array<handler_ptr,
793 if (
id >= Message_Id_Start)
795 const size_t index = get_dispatch_index_from_message_id(
id);
799 if (index < Number_Of_Messages)
803 if (new_state_id != Pass_To_Parent)
813 return (p_parent !=
nullptr) ? p_parent->process_event(message) :
static_cast<TDerived*
>(
this)->on_event_unknown(message);
820 template <
typename TMessage>
823 return derived.on_event(
static_cast<const TMessage&
>(msg));
831 template <
size_t Index>
832 static constexpr handler_ptr get_message_handler()
834 return &call_on_event< etl::type_list_type_at_index_t<sorted_message_types, Index>>;
841 template <
size_t... Indices>
842 static constexpr message_dispatch_table_t make_message_dispatch_table(etl::index_sequence<Indices...>)
844 return message_dispatch_table_t{{get_message_handler<Indices>()...}};
852 template <
size_t Index>
855 return etl::type_list_type_at_index_t<sorted_message_types, Index>::ID;
862 template <
size_t... Indices>
863 static constexpr message_id_table_t make_message_id_table(etl::index_sequence<Indices...>)
865 return message_id_table_t{{get_message_id_from_index<Indices>()...}};
877 if ETL_IF_CONSTEXPR (Message_Ids_Are_Contiguous)
880 return static_cast<size_t>(
id - Message_Id_Start);
886 size_t right = Number_Of_Messages;
890 size_t mid = (left + right) / 2;
892 if (message_id_table[mid] ==
id)
896 else if (message_id_table[mid] <
id)
907 return Number_Of_Messages;
916 return message_dispatch_table[index](
static_cast<TDerived&
>(*this), msg);
923 static ETL_INLINE_VAR
constexpr message_dispatch_table_t message_dispatch_table =
924 etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::make_message_dispatch_table(
925 etl::make_index_sequence< etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::Number_Of_Messages>{});
931 static ETL_INLINE_VAR
constexpr message_id_table_t message_id_table =
932 etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::make_message_id_table(
933 etl::make_index_sequence< etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::Number_Of_Messages>{});
936 #if ETL_USING_CPP11 && !ETL_USING_CPP17
937 template <
typename TContext,
typename TDerived,
etl::fsm_state_id_t STATE_ID_,
typename... TMessageTypes>
938 constexpr const typename etl::fsm_state< TContext, TDerived, STATE_ID_, TMessageTypes...>::message_dispatch_table_t
939 etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::message_dispatch_table;
941 template <
typename TContext,
typename TDerived,
etl::fsm_state_id_t STATE_ID_,
typename... TMessageTypes>
942 constexpr const typename etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::message_id_table_t
943 etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::message_id_table;
947 template <
typename TContext,
typename TDerived,
etl::fsm_state_id_t STATE_ID_,
typename... TMessageTypes>
953 template <
typename TContext,
typename TDerived, etl::fsm_state_
id_t STATE_ID_>
958 using message_id_sequence = etl::index_sequence<>;
962 using message_types = etl::type_list<>;
963 using sorted_message_types = etl::type_list<>;
976 TContext& get_fsm_context()
const
978 return static_cast<TContext&
>(ifsm_state::get_fsm_context());
986 return (p_parent !=
nullptr) ? p_parent->process_event(message) :
static_cast<TDerived*
>(
this)->on_event_unknown(message);
991 #include "private/fsm_cpp03.h"