mirror of
https://github.com/ETLCPP/etl.git
synced 2026-04-30 19:09:10 +08:00
Enforce o(log n) dispatch for messages when using fsm for c++11 and up (#1337)
* Updated message handling to be worst case O(logN) * Copied optimised message handling from etl::fsm * Updated fsm generator * Updated message_router generator * Added optimised accepts() member function * Modified comment, as the FSM doesn't support a successor * Updated version and release notes * Hotfix/etl multiset iterator invalidation during erase leads to incorrect sorted order in depth first traversal (#1317) * Fixed issue for both multiset and multimap * Added std::is_sorted checks to all map/set tests * Updated with coderabbit suggestions --------- Co-authored-by: John Wellbelove <john.wellbelove@etlcpp.com> * Updated release notes and version * Changed std::is_same to etl::is_same in struct type_list_is_unique (#1320) Co-authored-by: John Wellbelove <john.wellbelove@etlcpp.com> * Updated release notes and version * Fix etl::rotate (#1327) Per the C++ standard, std::rotate returns first + (last - middle): * When first == middle, return last * When middle == last, return first * Added missing files from VS2022 project * Fix greater_equal and less_equal (#1331) * Align comparison operators (#1330) In functional.h, the comparison operators for equal_to and not_equal_to mismatch between the actual comparison execution and the type inference for the return type. This change adjusts it by using the same operator==() in the return type inference as used in the comparison execution. Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com> * Add missing tests (#1321) * Add missing tests * Typo fixes --------- Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com> * Add ETL_FORMAT_NO_FLOATING_POINT control macro for etl::format (#1329) When ETL_FORMAT_NO_FLOATING_POINT is defined, all floating-point formatting support (float, double, long double) is excluded from etl::format. This reduces code size on targets that do not require floating-point formatting. Guarded sections: - #include <cmath> - float/double/long double in supported_format_types variant - float/double/long double constructors in basic_format_arg - format_floating_* functions and format_aligned_floating - formatter<float>, formatter<double>, formatter<long double> - Floating-point test cases in test_format.cpp Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com> * Manchester documentation (#1325) * manchester * Added manchester code and test * manchester * Formatting and added missing file * manchester * Some functions can only be constexpr since C++14 * manchester * Manchester decode and some refactoring * manchester * Added some missing typenames * manchester * constexpr void function not allowed in C++11 * manchester * condition on static_assert tests * manchester * revert CMakeLists.txt * Using ETL_STATIC_ASSERT * Some cleanup * manchester * Added static_assert message * manchester * Added compile time tests * manchester * Added invert manchester * Some refactoring * manchester * Disable test for now * Move ETL_NODISCARD before static * manchester * Test for valid_span * manchester * Remove redundant (?) storage specifiers for template specializations. Storage specifier already given in base template * manchester * refactoring to get rid of specialized template functions in template class * manchester * cleanup * manchester * Added documentation comments * Some refactoring * manchester * introducing namespace detail_manchester * manchester * Some refactoring * Update tests * manchester * Some refactoring * Removed possible undefined behavior by refactoring encode_span * constexpr version of encode_span * Static assertion for rare case where code doesn't work because CHAR_BIT is not the same as the number of bits in uint_least8_t * manchester * renamed valid to is_valid * manchester * renamed is_valid_span to is_valid * Using etl exceptions in ETL_ASSERT * manchester * Removed _fast functions * merged encode_in_place with encode and decode_in_place with decode * removed _span to create normal overloads of encode and decode for span * Some renaming and minor refactoring * manchester * Fix build issues * manchester * Conditionally compile manchester_decoded * Update test_manchester.cpp Removed redundant semicolon * #1258 Manchester coding * Formatting * consistency: hex literals with lower case 0x * #1258 Manchester coding * Moved copyright to top of file * Make constexpr encode/decode span functions equal for little and big endian platforms * #1258 Manchester coding * Added missing include * Added missing 8bit/64bit guards * Fixed is_valid for big endian platforms * #1258 Manchester coding * private memcpy alias * #1258 Manchester coding * Review comments * #1258 Manchester coding * Cleanup * Fix build error * #1258 Manchester coding * Add manchester documentation * #1258 Manchester coding * Preparation for GitHub pages * #1324 Manchester documentation * Some small fixes --------- Co-authored-by: Timon Zijnge <timon.zijnge@imec.nl> * Changes from review of algorithm.h on development branch (#1340) * Add missing constexpr in algorithm.h * Fix call of nth_element 2nd argument (nth) was missing * Replace partition point with O(log(N)) algorithm The C++ standard defines O(log(N)) calls of predicate as the complexity of partition_point(). The old algorithm was linear. * Use predicate in calculation of is_permutation consistently In case of predicate not equal_to, the calculation previously returned wron results * Omit swap in selection_sort if iterators are equal * Use difference_type in rotate_general() instead of int * Typo fix in algorithm.h * Simplifications in algorithm.h Application of plain refactoring by keeping semantics * Guard against past-end iterator in etl::rotate() And fix scope of rotate_right_by_one for etl::rotate() * Support empty ranges in selection_sort * Add tests for swap_ranges * Add tests for binary_search * Add tests for find_end * Add tests for accumulate * Add tests for move_s * Added tests for is_heap and sort_heap * Remove early exit for empty input * Add adjacent_find * Add unique * Add unique_copy * Add merge * Add inplace_merge * Add partial_sort * Add partial_sort_copy * copilot review change --------- Co-authored-by: John Wellbelove <john.wellbelove@etlcpp.com> Co-authored-by: Roland Reichwein <Roland.Reichwein@bmw.de> Co-authored-by: Niu Zhihong <zhihong@nzhnb.com> Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> Co-authored-by: Timon Zijnge <47081647+tzijnge@users.noreply.github.com> Co-authored-by: Timon Zijnge <timon.zijnge@imec.nl>
This commit is contained in:
parent
0a56d40bdd
commit
d3affac417
@ -62,6 +62,7 @@ SOFTWARE.
|
||||
#include "largest.h"
|
||||
#if ETL_USING_CPP11
|
||||
#include "tuple.h"
|
||||
#include "type_list.h"
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
@ -83,14 +84,14 @@ namespace etl
|
||||
// For internal FSM use.
|
||||
typedef typename etl::larger_type<etl::message_id_t>::type fsm_internal_id_t;
|
||||
|
||||
#if ETL_USING_CPP17 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++17 and above
|
||||
#if ETL_USING_CPP11 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++11 and above
|
||||
template <typename, typename, etl::fsm_state_id_t, typename...>
|
||||
class fsm_state;
|
||||
#else
|
||||
template <typename, typename, etl::fsm_state_id_t,
|
||||
typename, typename, typename, typename,
|
||||
typename, typename, typename, typename,
|
||||
typename, typename, typename, typename,
|
||||
typename, typename, typename, typename,
|
||||
typename, typename, typename, typename,
|
||||
typename, typename, typename, typename,
|
||||
typename, typename, typename, typename>
|
||||
class fsm_state;
|
||||
#endif
|
||||
@ -195,7 +196,7 @@ namespace etl
|
||||
// Pass this whenever no state change is desired.
|
||||
// The highest unsigned value of fsm_state_id_t.
|
||||
static ETL_CONSTANT fsm_state_id_t No_State_Change = etl::integral_limits<fsm_state_id_t>::max;
|
||||
|
||||
|
||||
// Pass this when this event also needs to be passed to the parent.
|
||||
static ETL_CONSTANT fsm_state_id_t Pass_To_Parent = No_State_Change - 1U;
|
||||
|
||||
@ -213,15 +214,15 @@ namespace etl
|
||||
ETL_CONSTANT fsm_state_id_t ifsm_state_helper<T>::Self_Transition;
|
||||
|
||||
// Compile-time: TState::ID must equal its index in the type list (0..N-1)
|
||||
template <size_t Id, typename...> struct check_ids : etl::true_type
|
||||
template <size_t Id, typename...> struct check_ids : etl::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <size_t Id, typename TState0, typename... TRest>
|
||||
struct check_ids<Id, TState0, TRest...>
|
||||
: etl::integral_constant<bool, (TState0::STATE_ID == Id) && private_fsm::check_ids<Id + 1, TRest...>::value>
|
||||
: etl::integral_constant<bool, (TState0::STATE_ID == Id) && private_fsm::check_ids<Id + 1, TRest...>::value>
|
||||
{
|
||||
};
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// RAII detection mechanism to catch reentrant calls to methods that might
|
||||
@ -250,11 +251,11 @@ namespace etl
|
||||
{
|
||||
is_locked = false;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
// Reference to the flag signifying a lock on the state machine.
|
||||
bool& is_locked;
|
||||
|
||||
|
||||
// Copy & move semantics disabled since this is a guard.
|
||||
fsm_reentrancy_guard(fsm_reentrancy_guard const&) ETL_DELETE;
|
||||
fsm_reentrancy_guard& operator= (fsm_reentrancy_guard const&) ETL_DELETE;
|
||||
@ -272,7 +273,7 @@ namespace etl
|
||||
/// A class to store FSM states.
|
||||
//***************************************************************************
|
||||
template <typename... TStates>
|
||||
class fsm_state_pack
|
||||
class fsm_state_pack
|
||||
{
|
||||
public:
|
||||
|
||||
@ -294,18 +295,18 @@ namespace etl
|
||||
/// Gets a reference to the state.
|
||||
//*********************************
|
||||
template <typename TState>
|
||||
TState& get()
|
||||
{
|
||||
return etl::get<TState>(storage);
|
||||
TState& get()
|
||||
{
|
||||
return etl::get<TState>(storage);
|
||||
}
|
||||
|
||||
//*********************************
|
||||
/// Gets a const reference to the state.
|
||||
//*********************************
|
||||
template <typename TState>
|
||||
const TState& get() const
|
||||
{
|
||||
return etl::get<TState>(storage);
|
||||
const TState& get() const
|
||||
{
|
||||
return etl::get<TState>(storage);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -341,14 +342,14 @@ namespace etl
|
||||
using private_fsm::ifsm_state_helper<>::Pass_To_Parent;
|
||||
using private_fsm::ifsm_state_helper<>::Self_Transition;
|
||||
|
||||
#if ETL_USING_CPP17 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++17 and above
|
||||
#if ETL_USING_CPP11 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++11 and above
|
||||
template <typename, typename, etl::fsm_state_id_t, typename...>
|
||||
friend class fsm_state;
|
||||
#else
|
||||
template <typename, typename, etl::fsm_state_id_t,
|
||||
typename, typename, typename, typename,
|
||||
typename, typename, typename, typename,
|
||||
typename, typename, typename, typename,
|
||||
typename, typename, typename, typename,
|
||||
typename, typename, typename, typename,
|
||||
typename, typename, typename, typename,
|
||||
typename, typename, typename, typename>
|
||||
friend class etl::fsm_state;
|
||||
#endif
|
||||
@ -560,7 +561,7 @@ namespace etl
|
||||
{
|
||||
etl::fsm_state_id_t next_state_id = p_state->process_event(message);
|
||||
|
||||
process_state_change(next_state_id);
|
||||
process_state_change(next_state_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -691,7 +692,7 @@ namespace etl
|
||||
p_state->on_exit_state();
|
||||
next_state_id = p_state->on_enter_state();
|
||||
}
|
||||
|
||||
|
||||
if (have_changed_state(next_state_id))
|
||||
{
|
||||
ETL_ASSERT_OR_RETURN_VALUE(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception), p_state->get_state_id());
|
||||
@ -722,17 +723,249 @@ namespace etl
|
||||
};
|
||||
|
||||
//*************************************************************************************************
|
||||
// For C++17 and above.
|
||||
// For C++11 and above.
|
||||
//*************************************************************************************************
|
||||
#if ETL_USING_CPP17 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++17 and above
|
||||
#if ETL_USING_CPP11 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++11 and above
|
||||
//***************************************************************************
|
||||
// The definition for all types.
|
||||
//***************************************************************************
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, typename... TMessageTypes>
|
||||
class fsm_state : public ifsm_state
|
||||
{
|
||||
private:
|
||||
|
||||
using message_id_sequence = etl::index_sequence<TMessageTypes::ID...>;
|
||||
|
||||
public:
|
||||
|
||||
using message_types = etl::type_list<TMessageTypes...>;
|
||||
using sorted_message_types = etl::type_list_sort_t<message_types, etl::compare_message_id_less>;
|
||||
|
||||
static_assert(etl::type_list_is_unique<message_types>::value, "All TMessageTypes must be unique");
|
||||
static_assert(etl::type_list_all_of<message_types, etl::is_message_type>::value, "All TMessageTypes must satisfy the condition etl::is_message_type");
|
||||
static_assert(etl::index_sequence_is_unique<message_id_sequence>::value, "All message IDs must be unique");
|
||||
|
||||
static ETL_CONSTANT etl::fsm_state_id_t STATE_ID = STATE_ID_;
|
||||
|
||||
fsm_state()
|
||||
: ifsm_state(STATE_ID)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
~fsm_state()
|
||||
{
|
||||
}
|
||||
|
||||
TContext& get_fsm_context() const
|
||||
{
|
||||
return static_cast<TContext&>(ifsm_state::get_fsm_context());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static constexpr size_t Number_Of_Messages = sizeof...(TMessageTypes);
|
||||
static constexpr etl::message_id_t Message_Id_Start = etl::type_list_type_at_index_t<sorted_message_types, 0>::ID;
|
||||
|
||||
static_assert(Number_Of_Messages > 0, "Zero messages");
|
||||
|
||||
//**********************************************
|
||||
// Checks that the message ids are contiguous.
|
||||
//**********************************************
|
||||
template <size_t Index, bool Last = (Index + 1U >= Number_Of_Messages)>
|
||||
struct contiguous_impl;
|
||||
|
||||
template <size_t Index>
|
||||
struct contiguous_impl<Index, true> : etl::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <size_t Index>
|
||||
struct contiguous_impl<Index, false>
|
||||
: etl::bool_constant<(etl::type_list_type_at_index_t<sorted_message_types, Index>::ID + 1U ==
|
||||
etl::type_list_type_at_index_t<sorted_message_types, Index + 1U>::ID) &&
|
||||
contiguous_impl<Index + 1U>::value>
|
||||
{
|
||||
|
||||
|
||||
};
|
||||
|
||||
// The message ids are contiguous if there are 0 or 1 message types, or if each message id is one greater than the previous message id.
|
||||
static constexpr bool Message_Ids_Are_Contiguous = (Number_Of_Messages <= 1U) ? true : contiguous_impl<0U>::value;
|
||||
|
||||
using handler_ptr = etl::fsm_state_id_t (*)(TDerived&, const etl::imessage&); ///< Pointer to a handler function that takes a reference to the derived class and a reference to the message.
|
||||
using message_dispatch_table_t = etl::array<handler_ptr, Number_Of_Messages>; ///< The dispatch table type. An array of handler pointers, one for each message type.
|
||||
using message_id_table_t = etl::array<etl::message_id_t, Number_Of_Messages>; ///< The message id table type. An array of message ids, one for each message type.
|
||||
|
||||
//********************************************
|
||||
etl::fsm_state_id_t process_event(const etl::imessage& message)
|
||||
{
|
||||
const etl::message_id_t id = message.get_message_id();
|
||||
|
||||
// The IDs are sorted, so an ID less than the first is not handled by this router.
|
||||
if (id >= Message_Id_Start)
|
||||
{
|
||||
const size_t index = get_dispatch_index_from_message_id(id);
|
||||
|
||||
// If the index is less than Number_Of_Messages, then we have a handler for this message type, so dispatch it.
|
||||
if (index < Number_Of_Messages)
|
||||
{
|
||||
const etl::fsm_state_id_t new_state_id = dispatch(message, index);
|
||||
|
||||
if (new_state_id != Pass_To_Parent)
|
||||
{
|
||||
return new_state_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
// If we get here, then we don't have a handler for this message type, so pass it to the parent if we have one, otherwise call on_event_unknown.
|
||||
return (p_parent != nullptr) ? p_parent->process_event(message) : static_cast<TDerived*>(this)->on_event_unknown(message);
|
||||
#include "etl/private/diagnostic_pop.h"
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Call for a single message type
|
||||
//**********************************************
|
||||
template <typename TMessage>
|
||||
static etl::fsm_state_id_t call_on_event(TDerived& derived, const imessage& msg)
|
||||
{
|
||||
return derived.on_event(static_cast<const TMessage&>(msg));
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Get the handler for a single message type at the index in the sorted type_list.
|
||||
// This will be called for each message type to generate the dispatch table.
|
||||
//**********************************************
|
||||
template <size_t Index>
|
||||
static constexpr handler_ptr get_message_handler()
|
||||
{
|
||||
return &call_on_event<etl::type_list_type_at_index_t<sorted_message_types, Index>>;
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Generate the dispatch table at compile time.
|
||||
// This will create an array of handler pointers, one for each message type.
|
||||
//**********************************************
|
||||
template <size_t... Indices>
|
||||
static constexpr message_dispatch_table_t make_message_dispatch_table(etl::index_sequence<Indices...>)
|
||||
{
|
||||
return message_dispatch_table_t{ { get_message_handler<Indices>()... } };
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Get the message id for a single message type at an index in the sorted type_list.
|
||||
// This will be called for each message type to generate the message id table.
|
||||
//**********************************************
|
||||
template <size_t Index>
|
||||
static constexpr etl::message_id_t get_message_id_from_index()
|
||||
{
|
||||
return etl::type_list_type_at_index_t<sorted_message_types, Index>::ID;
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Generate the message id table at compile time.
|
||||
// This will create an array of message ids, one for each message type.
|
||||
//**********************************************
|
||||
template <size_t... Indices>
|
||||
static constexpr message_id_table_t make_message_id_table(etl::index_sequence<Indices...>)
|
||||
{
|
||||
return message_id_table_t{ { get_message_id_from_index<Indices>()... } };
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Get the dispatch index for a message id.
|
||||
// This will be used at runtime to find the handler for a message id.
|
||||
// If the message ids are contiguous, we can calculate the index directly. If they are not contiguous, we need to do a binary search.
|
||||
// This will return Number_Of_Messages if the message id is not found.
|
||||
//**********************************************
|
||||
static size_t get_dispatch_index_from_message_id(etl::message_id_t id)
|
||||
{
|
||||
if ETL_IF_CONSTEXPR(Message_Ids_Are_Contiguous)
|
||||
{
|
||||
// The IDs are contiguous, so we can calculate the index directly.
|
||||
return static_cast<size_t>(id - Message_Id_Start);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The IDs are not contiguous, so we need to do a binary search.
|
||||
size_t left = 0;
|
||||
size_t right = Number_Of_Messages;
|
||||
|
||||
while (left < right)
|
||||
{
|
||||
size_t mid = (left + right) / 2;
|
||||
|
||||
if (message_id_table[mid] == id)
|
||||
{
|
||||
return mid;
|
||||
}
|
||||
else if (message_id_table[mid] < id)
|
||||
{
|
||||
left = mid + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
right = mid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Number_Of_Messages; // Not found
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Dispatch the message to the appropriate handler based on the index in the dispatch table.
|
||||
//**********************************************
|
||||
etl::fsm_state_id_t dispatch(const etl::imessage& msg, size_t index)
|
||||
{
|
||||
return message_dispatch_table[index](static_cast<TDerived&>(*this), msg);
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// The dispatch table is generated at compile time. The dispatch table contains pointers to the on_receive handlers for each message type.
|
||||
//**********************************************
|
||||
static ETL_INLINE_VAR constexpr message_dispatch_table_t message_dispatch_table =
|
||||
etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::make_message_dispatch_table(etl::make_index_sequence<etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::Number_Of_Messages>{});
|
||||
|
||||
//**********************************************
|
||||
// The message id table is generated at compile time. The message id table contains the corresponding message ids for each message type.
|
||||
//**********************************************
|
||||
static ETL_INLINE_VAR constexpr message_id_table_t message_id_table =
|
||||
etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::make_message_id_table(etl::make_index_sequence<etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::Number_Of_Messages>{});
|
||||
};
|
||||
|
||||
#if ETL_USING_CPP11 && !ETL_USING_CPP17
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, typename... TMessageTypes>
|
||||
constexpr const typename etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::message_dispatch_table_t
|
||||
etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::message_dispatch_table;
|
||||
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, typename... TMessageTypes>
|
||||
constexpr const typename etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::message_id_table_t
|
||||
etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::message_id_table;
|
||||
#endif
|
||||
|
||||
/// Definition of STATE_ID
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, typename... TMessageTypes>
|
||||
ETL_CONSTANT etl::fsm_state_id_t fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::STATE_ID;
|
||||
|
||||
//***************************************************************************
|
||||
// The definition for no messages.
|
||||
//***************************************************************************
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_>
|
||||
class fsm_state<TContext, TDerived, STATE_ID_> : public ifsm_state
|
||||
{
|
||||
private:
|
||||
|
||||
using message_id_sequence = etl::index_sequence<>;
|
||||
|
||||
public:
|
||||
|
||||
using message_types = etl::type_list<>;
|
||||
using sorted_message_types = etl::type_list<>;
|
||||
|
||||
static ETL_CONSTANT etl::fsm_state_id_t STATE_ID = STATE_ID_;
|
||||
|
||||
fsm_state()
|
||||
@ -753,59 +986,24 @@ namespace etl
|
||||
|
||||
private:
|
||||
|
||||
//********************************************
|
||||
struct result_t
|
||||
{
|
||||
bool was_handled;
|
||||
etl::fsm_state_id_t state_id;
|
||||
};
|
||||
|
||||
//********************************************
|
||||
etl::fsm_state_id_t process_event(const etl::imessage& message)
|
||||
{
|
||||
etl::fsm_state_id_t new_state_id;
|
||||
|
||||
const bool was_handled = (process_event_type<TMessageTypes>(message, new_state_id) || ...);
|
||||
|
||||
if (!was_handled || (new_state_id == Pass_To_Parent))
|
||||
{
|
||||
new_state_id = (p_parent != nullptr) ? p_parent->process_event(message) : static_cast<TDerived*>(this)->on_event_unknown(message);
|
||||
}
|
||||
|
||||
return new_state_id;
|
||||
}
|
||||
|
||||
//********************************************
|
||||
template <typename TMessage>
|
||||
bool process_event_type(const etl::imessage& msg, etl::fsm_state_id_t& new_state_id)
|
||||
{
|
||||
if (TMessage::ID == msg.get_message_id())
|
||||
{
|
||||
new_state_id = static_cast<TDerived*>(this)->on_event(static_cast<const TMessage&>(msg));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (p_parent != nullptr) ? p_parent->process_event(message) : static_cast<TDerived*>(this)->on_event_unknown(message);
|
||||
}
|
||||
};
|
||||
|
||||
/// Definition of STATE_ID
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, typename... TMessageTypes>
|
||||
ETL_CONSTANT etl::fsm_state_id_t fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::STATE_ID;
|
||||
|
||||
#else
|
||||
//*************************************************************************************************
|
||||
// For C++14 and below.
|
||||
// For C++03 and below.
|
||||
//*************************************************************************************************
|
||||
//***************************************************************************
|
||||
// The definition for all 16 message types.
|
||||
//***************************************************************************
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void,
|
||||
typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void,
|
||||
typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void,
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void,
|
||||
typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void,
|
||||
typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void,
|
||||
typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void>
|
||||
class fsm_state : public ifsm_state
|
||||
{
|
||||
@ -864,10 +1062,10 @@ namespace etl
|
||||
//***************************************************************************
|
||||
// Specialisation for 15 message types.
|
||||
//***************************************************************************
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8,
|
||||
typename T9, typename T10, typename T11, typename T12,
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8,
|
||||
typename T9, typename T10, typename T11, typename T12,
|
||||
typename T13, typename T14, typename T15>
|
||||
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, void> : public ifsm_state
|
||||
{
|
||||
@ -925,10 +1123,10 @@ namespace etl
|
||||
//***************************************************************************
|
||||
// Specialisation for 14 message types.
|
||||
//***************************************************************************
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8,
|
||||
typename T9, typename T10, typename T11, typename T12,
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8,
|
||||
typename T9, typename T10, typename T11, typename T12,
|
||||
typename T13, typename T14>
|
||||
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, void, void> : public ifsm_state
|
||||
{
|
||||
@ -985,10 +1183,10 @@ namespace etl
|
||||
//***************************************************************************
|
||||
// Specialisation for 13 message types.
|
||||
//***************************************************************************
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8,
|
||||
typename T9, typename T10, typename T11, typename T12,
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8,
|
||||
typename T9, typename T10, typename T11, typename T12,
|
||||
typename T13>
|
||||
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, void, void, void> : public ifsm_state
|
||||
{
|
||||
@ -1044,9 +1242,9 @@ namespace etl
|
||||
//***************************************************************************
|
||||
// Specialisation for 12 message types.
|
||||
//***************************************************************************
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8,
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8,
|
||||
typename T9, typename T10, typename T11, typename T12>
|
||||
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, void, void, void, void> : public ifsm_state
|
||||
{
|
||||
@ -1101,9 +1299,9 @@ namespace etl
|
||||
//***************************************************************************
|
||||
// Specialisation for 11 message types.
|
||||
//***************************************************************************
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8,
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8,
|
||||
typename T9, typename T10, typename T11>
|
||||
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, void, void, void, void, void> : public ifsm_state
|
||||
{
|
||||
@ -1157,9 +1355,9 @@ namespace etl
|
||||
//***************************************************************************
|
||||
// Specialisation for 10 message types.
|
||||
//***************************************************************************
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8,
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8,
|
||||
typename T9, typename T10>
|
||||
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, void, void, void, void, void, void> : public ifsm_state
|
||||
{
|
||||
@ -1212,9 +1410,9 @@ namespace etl
|
||||
//***************************************************************************
|
||||
// Specialisation for 9 message types.
|
||||
//***************************************************************************
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8,
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8,
|
||||
typename T9>
|
||||
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, void, void, void, void, void, void, void> : public ifsm_state
|
||||
{
|
||||
@ -1266,8 +1464,8 @@ namespace etl
|
||||
//***************************************************************************
|
||||
// Specialisation for 8 message types.
|
||||
//***************************************************************************
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8>
|
||||
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, void, void, void, void, void, void, void, void> : public ifsm_state
|
||||
{
|
||||
@ -1318,8 +1516,8 @@ namespace etl
|
||||
//***************************************************************************
|
||||
// Specialisation for 7 message types.
|
||||
//***************************************************************************
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7>
|
||||
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, void, void, void, void, void, void, void, void, void> : public ifsm_state
|
||||
{
|
||||
@ -1369,8 +1567,8 @@ namespace etl
|
||||
//***************************************************************************
|
||||
// Specialisation for 6 message types.
|
||||
//***************************************************************************
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6>
|
||||
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, void, void, void, void, void, void, void, void, void, void> : public ifsm_state
|
||||
{
|
||||
@ -1419,8 +1617,8 @@ namespace etl
|
||||
//***************************************************************************
|
||||
// Specialisation for 5 message types.
|
||||
//***************************************************************************
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5>
|
||||
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state
|
||||
{
|
||||
@ -1468,7 +1666,7 @@ namespace etl
|
||||
//***************************************************************************
|
||||
// Specialisation for 4 message types.
|
||||
//***************************************************************************
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4>
|
||||
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state
|
||||
{
|
||||
@ -1515,7 +1713,7 @@ namespace etl
|
||||
//***************************************************************************
|
||||
// Specialisation for 3 message types.
|
||||
//***************************************************************************
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3>
|
||||
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, void, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state
|
||||
{
|
||||
@ -1561,7 +1759,7 @@ namespace etl
|
||||
//***************************************************************************
|
||||
// Specialisation for 2 message types.
|
||||
//***************************************************************************
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2>
|
||||
class fsm_state<TContext, TDerived, STATE_ID_, T1, T2, void, void, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state
|
||||
{
|
||||
@ -1606,7 +1804,7 @@ namespace etl
|
||||
//***************************************************************************
|
||||
// Specialisation for 1 message type.
|
||||
//***************************************************************************
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1>
|
||||
class fsm_state<TContext, TDerived, STATE_ID_, T1, void, void, void, void, void, void, void, void, void, void, void, void, void, void, void> : public ifsm_state
|
||||
{
|
||||
@ -1680,10 +1878,10 @@ namespace etl
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8,
|
||||
typename T9, typename T10, typename T11, typename T12,
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,
|
||||
typename T1, typename T2, typename T3, typename T4,
|
||||
typename T5, typename T6, typename T7, typename T8,
|
||||
typename T9, typename T10, typename T11, typename T12,
|
||||
typename T13, typename T14, typename T15, typename T16>
|
||||
ETL_CONSTANT etl::fsm_state_id_t fsm_state<TContext, TDerived, STATE_ID_, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::STATE_ID;
|
||||
#endif
|
||||
|
||||
@ -74,6 +74,7 @@ cog.outl("//********************************************************************
|
||||
#include "largest.h"
|
||||
#if ETL_USING_CPP11
|
||||
#include "tuple.h"
|
||||
#include "type_list.h"
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
@ -95,20 +96,20 @@ namespace etl
|
||||
// For internal FSM use.
|
||||
typedef typename etl::larger_type<etl::message_id_t>::type fsm_internal_id_t;
|
||||
|
||||
#if ETL_USING_CPP17 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++17 and above
|
||||
#if ETL_USING_CPP11 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++11 and above
|
||||
template <typename, typename, etl::fsm_state_id_t, typename...>
|
||||
class fsm_state;
|
||||
#else
|
||||
/*[[[cog
|
||||
import cog
|
||||
cog.outl("template <typename, typename, etl::fsm_state_id_t,")
|
||||
cog.out(" ")
|
||||
cog.out(" ")
|
||||
for n in range(1, int(Handlers)):
|
||||
cog.out("typename, ")
|
||||
cog.out(" typename,")
|
||||
if n % 4 == 0:
|
||||
cog.outl("")
|
||||
cog.out(" ")
|
||||
cog.outl("typename>")
|
||||
cog.out(" ")
|
||||
cog.outl(" typename>")
|
||||
cog.outl("class fsm_state;")
|
||||
]]]*/
|
||||
/*[[[end]]]*/
|
||||
@ -214,7 +215,7 @@ namespace etl
|
||||
// Pass this whenever no state change is desired.
|
||||
// The highest unsigned value of fsm_state_id_t.
|
||||
static ETL_CONSTANT fsm_state_id_t No_State_Change = etl::integral_limits<fsm_state_id_t>::max;
|
||||
|
||||
|
||||
// Pass this when this event also needs to be passed to the parent.
|
||||
static ETL_CONSTANT fsm_state_id_t Pass_To_Parent = No_State_Change - 1U;
|
||||
|
||||
@ -232,15 +233,15 @@ namespace etl
|
||||
ETL_CONSTANT fsm_state_id_t ifsm_state_helper<T>::Self_Transition;
|
||||
|
||||
// Compile-time: TState::ID must equal its index in the type list (0..N-1)
|
||||
template <size_t Id, typename...> struct check_ids : etl::true_type
|
||||
template <size_t Id, typename...> struct check_ids : etl::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <size_t Id, typename TState0, typename... TRest>
|
||||
struct check_ids<Id, TState0, TRest...>
|
||||
: etl::integral_constant<bool, (TState0::STATE_ID == Id) && private_fsm::check_ids<Id + 1, TRest...>::value>
|
||||
: etl::integral_constant<bool, (TState0::STATE_ID == Id) && private_fsm::check_ids<Id + 1, TRest...>::value>
|
||||
{
|
||||
};
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// RAII detection mechanism to catch reentrant calls to methods that might
|
||||
@ -269,11 +270,11 @@ namespace etl
|
||||
{
|
||||
is_locked = false;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
// Reference to the flag signifying a lock on the state machine.
|
||||
bool& is_locked;
|
||||
|
||||
|
||||
// Copy & move semantics disabled since this is a guard.
|
||||
fsm_reentrancy_guard(fsm_reentrancy_guard const&) ETL_DELETE;
|
||||
fsm_reentrancy_guard& operator= (fsm_reentrancy_guard const&) ETL_DELETE;
|
||||
@ -291,7 +292,7 @@ namespace etl
|
||||
/// A class to store FSM states.
|
||||
//***************************************************************************
|
||||
template <typename... TStates>
|
||||
class fsm_state_pack
|
||||
class fsm_state_pack
|
||||
{
|
||||
public:
|
||||
|
||||
@ -313,18 +314,18 @@ namespace etl
|
||||
/// Gets a reference to the state.
|
||||
//*********************************
|
||||
template <typename TState>
|
||||
TState& get()
|
||||
{
|
||||
return etl::get<TState>(storage);
|
||||
TState& get()
|
||||
{
|
||||
return etl::get<TState>(storage);
|
||||
}
|
||||
|
||||
//*********************************
|
||||
/// Gets a const reference to the state.
|
||||
//*********************************
|
||||
template <typename TState>
|
||||
const TState& get() const
|
||||
{
|
||||
return etl::get<TState>(storage);
|
||||
const TState& get() const
|
||||
{
|
||||
return etl::get<TState>(storage);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -360,20 +361,20 @@ namespace etl
|
||||
using private_fsm::ifsm_state_helper<>::Pass_To_Parent;
|
||||
using private_fsm::ifsm_state_helper<>::Self_Transition;
|
||||
|
||||
#if ETL_USING_CPP17 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++17 and above
|
||||
#if ETL_USING_CPP11 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++11 and above
|
||||
template <typename, typename, etl::fsm_state_id_t, typename...>
|
||||
friend class fsm_state;
|
||||
#else
|
||||
/*[[[cog
|
||||
import cog
|
||||
cog.outl(" template <typename, typename, etl::fsm_state_id_t,")
|
||||
cog.out(" ")
|
||||
cog.out(" ")
|
||||
for n in range(1, int(Handlers)):
|
||||
cog.out("typename, ")
|
||||
cog.out(" typename,")
|
||||
if n % 4 == 0:
|
||||
cog.outl("")
|
||||
cog.out(" ")
|
||||
cog.outl("typename>")
|
||||
cog.out(" ")
|
||||
cog.outl(" typename>")
|
||||
]]]*/
|
||||
/*[[[end]]]*/
|
||||
friend class etl::fsm_state;
|
||||
@ -586,7 +587,7 @@ namespace etl
|
||||
{
|
||||
etl::fsm_state_id_t next_state_id = p_state->process_event(message);
|
||||
|
||||
process_state_change(next_state_id);
|
||||
process_state_change(next_state_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -717,7 +718,7 @@ namespace etl
|
||||
p_state->on_exit_state();
|
||||
next_state_id = p_state->on_enter_state();
|
||||
}
|
||||
|
||||
|
||||
if (have_changed_state(next_state_id))
|
||||
{
|
||||
ETL_ASSERT_OR_RETURN_VALUE(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception), p_state->get_state_id());
|
||||
@ -748,17 +749,249 @@ namespace etl
|
||||
};
|
||||
|
||||
//*************************************************************************************************
|
||||
// For C++17 and above.
|
||||
// For C++11 and above.
|
||||
//*************************************************************************************************
|
||||
#if ETL_USING_CPP17 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++17 and above
|
||||
#if ETL_USING_CPP11 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++11 and above
|
||||
//***************************************************************************
|
||||
// The definition for all types.
|
||||
//***************************************************************************
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, typename... TMessageTypes>
|
||||
class fsm_state : public ifsm_state
|
||||
{
|
||||
private:
|
||||
|
||||
using message_id_sequence = etl::index_sequence<TMessageTypes::ID...>;
|
||||
|
||||
public:
|
||||
|
||||
using message_types = etl::type_list<TMessageTypes...>;
|
||||
using sorted_message_types = etl::type_list_sort_t<message_types, etl::compare_message_id_less>;
|
||||
|
||||
static_assert(etl::type_list_is_unique<message_types>::value, "All TMessageTypes must be unique");
|
||||
static_assert(etl::type_list_all_of<message_types, etl::is_message_type>::value, "All TMessageTypes must satisfy the condition etl::is_message_type");
|
||||
static_assert(etl::index_sequence_is_unique<message_id_sequence>::value, "All message IDs must be unique");
|
||||
|
||||
static ETL_CONSTANT etl::fsm_state_id_t STATE_ID = STATE_ID_;
|
||||
|
||||
fsm_state()
|
||||
: ifsm_state(STATE_ID)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
~fsm_state()
|
||||
{
|
||||
}
|
||||
|
||||
TContext& get_fsm_context() const
|
||||
{
|
||||
return static_cast<TContext&>(ifsm_state::get_fsm_context());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static constexpr size_t Number_Of_Messages = sizeof...(TMessageTypes);
|
||||
static constexpr etl::message_id_t Message_Id_Start = etl::type_list_type_at_index_t<sorted_message_types, 0>::ID;
|
||||
|
||||
static_assert(Number_Of_Messages > 0, "Zero messages");
|
||||
|
||||
//**********************************************
|
||||
// Checks that the message ids are contiguous.
|
||||
//**********************************************
|
||||
template <size_t Index, bool Last = (Index + 1U >= Number_Of_Messages)>
|
||||
struct contiguous_impl;
|
||||
|
||||
template <size_t Index>
|
||||
struct contiguous_impl<Index, true> : etl::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <size_t Index>
|
||||
struct contiguous_impl<Index, false>
|
||||
: etl::bool_constant<(etl::type_list_type_at_index_t<sorted_message_types, Index>::ID + 1U ==
|
||||
etl::type_list_type_at_index_t<sorted_message_types, Index + 1U>::ID) &&
|
||||
contiguous_impl<Index + 1U>::value>
|
||||
{
|
||||
|
||||
|
||||
};
|
||||
|
||||
// The message ids are contiguous if there are 0 or 1 message types, or if each message id is one greater than the previous message id.
|
||||
static constexpr bool Message_Ids_Are_Contiguous = (Number_Of_Messages <= 1U) ? true : contiguous_impl<0U>::value;
|
||||
|
||||
using handler_ptr = etl::fsm_state_id_t (*)(TDerived&, const etl::imessage&); ///< Pointer to a handler function that takes a reference to the derived class and a reference to the message.
|
||||
using message_dispatch_table_t = etl::array<handler_ptr, Number_Of_Messages>; ///< The dispatch table type. An array of handler pointers, one for each message type.
|
||||
using message_id_table_t = etl::array<etl::message_id_t, Number_Of_Messages>; ///< The message id table type. An array of message ids, one for each message type.
|
||||
|
||||
//********************************************
|
||||
etl::fsm_state_id_t process_event(const etl::imessage& message)
|
||||
{
|
||||
const etl::message_id_t id = message.get_message_id();
|
||||
|
||||
// The IDs are sorted, so an ID less than the first is not handled by this router.
|
||||
if (id >= Message_Id_Start)
|
||||
{
|
||||
const size_t index = get_dispatch_index_from_message_id(id);
|
||||
|
||||
// If the index is less than Number_Of_Messages, then we have a handler for this message type, so dispatch it.
|
||||
if (index < Number_Of_Messages)
|
||||
{
|
||||
const etl::fsm_state_id_t new_state_id = dispatch(message, index);
|
||||
|
||||
if (new_state_id != Pass_To_Parent)
|
||||
{
|
||||
return new_state_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
// If we get here, then we don't have a handler for this message type, so pass it to the parent if we have one, otherwise call on_event_unknown.
|
||||
return (p_parent != nullptr) ? p_parent->process_event(message) : static_cast<TDerived*>(this)->on_event_unknown(message);
|
||||
#include "etl/private/diagnostic_pop.h"
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Call for a single message type
|
||||
//**********************************************
|
||||
template <typename TMessage>
|
||||
static etl::fsm_state_id_t call_on_event(TDerived& derived, const imessage& msg)
|
||||
{
|
||||
return derived.on_event(static_cast<const TMessage&>(msg));
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Get the handler for a single message type at the index in the sorted type_list.
|
||||
// This will be called for each message type to generate the dispatch table.
|
||||
//**********************************************
|
||||
template <size_t Index>
|
||||
static constexpr handler_ptr get_message_handler()
|
||||
{
|
||||
return &call_on_event<etl::type_list_type_at_index_t<sorted_message_types, Index>>;
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Generate the dispatch table at compile time.
|
||||
// This will create an array of handler pointers, one for each message type.
|
||||
//**********************************************
|
||||
template <size_t... Indices>
|
||||
static constexpr message_dispatch_table_t make_message_dispatch_table(etl::index_sequence<Indices...>)
|
||||
{
|
||||
return message_dispatch_table_t{ { get_message_handler<Indices>()... } };
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Get the message id for a single message type at an index in the sorted type_list.
|
||||
// This will be called for each message type to generate the message id table.
|
||||
//**********************************************
|
||||
template <size_t Index>
|
||||
static constexpr etl::message_id_t get_message_id_from_index()
|
||||
{
|
||||
return etl::type_list_type_at_index_t<sorted_message_types, Index>::ID;
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Generate the message id table at compile time.
|
||||
// This will create an array of message ids, one for each message type.
|
||||
//**********************************************
|
||||
template <size_t... Indices>
|
||||
static constexpr message_id_table_t make_message_id_table(etl::index_sequence<Indices...>)
|
||||
{
|
||||
return message_id_table_t{ { get_message_id_from_index<Indices>()... } };
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Get the dispatch index for a message id.
|
||||
// This will be used at runtime to find the handler for a message id.
|
||||
// If the message ids are contiguous, we can calculate the index directly. If they are not contiguous, we need to do a binary search.
|
||||
// This will return Number_Of_Messages if the message id is not found.
|
||||
//**********************************************
|
||||
static size_t get_dispatch_index_from_message_id(etl::message_id_t id)
|
||||
{
|
||||
if ETL_IF_CONSTEXPR(Message_Ids_Are_Contiguous)
|
||||
{
|
||||
// The IDs are contiguous, so we can calculate the index directly.
|
||||
return static_cast<size_t>(id - Message_Id_Start);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The IDs are not contiguous, so we need to do a binary search.
|
||||
size_t left = 0;
|
||||
size_t right = Number_Of_Messages;
|
||||
|
||||
while (left < right)
|
||||
{
|
||||
size_t mid = (left + right) / 2;
|
||||
|
||||
if (message_id_table[mid] == id)
|
||||
{
|
||||
return mid;
|
||||
}
|
||||
else if (message_id_table[mid] < id)
|
||||
{
|
||||
left = mid + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
right = mid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Number_Of_Messages; // Not found
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// Dispatch the message to the appropriate handler based on the index in the dispatch table.
|
||||
//**********************************************
|
||||
etl::fsm_state_id_t dispatch(const etl::imessage& msg, size_t index)
|
||||
{
|
||||
return message_dispatch_table[index](static_cast<TDerived&>(*this), msg);
|
||||
}
|
||||
|
||||
//**********************************************
|
||||
// The dispatch table is generated at compile time. The dispatch table contains pointers to the on_receive handlers for each message type.
|
||||
//**********************************************
|
||||
static ETL_INLINE_VAR constexpr message_dispatch_table_t message_dispatch_table =
|
||||
etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::make_message_dispatch_table(etl::make_index_sequence<etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::Number_Of_Messages>{});
|
||||
|
||||
//**********************************************
|
||||
// The message id table is generated at compile time. The message id table contains the corresponding message ids for each message type.
|
||||
//**********************************************
|
||||
static ETL_INLINE_VAR constexpr message_id_table_t message_id_table =
|
||||
etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::make_message_id_table(etl::make_index_sequence<etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::Number_Of_Messages>{});
|
||||
};
|
||||
|
||||
#if ETL_USING_CPP11 && !ETL_USING_CPP17
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, typename... TMessageTypes>
|
||||
constexpr const typename etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::message_dispatch_table_t
|
||||
etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::message_dispatch_table;
|
||||
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, typename... TMessageTypes>
|
||||
constexpr const typename etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::message_id_table_t
|
||||
etl::fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::message_id_table;
|
||||
#endif
|
||||
|
||||
/// Definition of STATE_ID
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, typename... TMessageTypes>
|
||||
ETL_CONSTANT etl::fsm_state_id_t fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::STATE_ID;
|
||||
|
||||
//***************************************************************************
|
||||
// The definition for no messages.
|
||||
//***************************************************************************
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_>
|
||||
class fsm_state<TContext, TDerived, STATE_ID_> : public ifsm_state
|
||||
{
|
||||
private:
|
||||
|
||||
using message_id_sequence = etl::index_sequence<>;
|
||||
|
||||
public:
|
||||
|
||||
using message_types = etl::type_list<>;
|
||||
using sorted_message_types = etl::type_list<>;
|
||||
|
||||
static ETL_CONSTANT etl::fsm_state_id_t STATE_ID = STATE_ID_;
|
||||
|
||||
fsm_state()
|
||||
@ -779,51 +1012,16 @@ namespace etl
|
||||
|
||||
private:
|
||||
|
||||
//********************************************
|
||||
struct result_t
|
||||
{
|
||||
bool was_handled;
|
||||
etl::fsm_state_id_t state_id;
|
||||
};
|
||||
|
||||
//********************************************
|
||||
etl::fsm_state_id_t process_event(const etl::imessage& message)
|
||||
{
|
||||
etl::fsm_state_id_t new_state_id;
|
||||
|
||||
const bool was_handled = (process_event_type<TMessageTypes>(message, new_state_id) || ...);
|
||||
|
||||
if (!was_handled || (new_state_id == Pass_To_Parent))
|
||||
{
|
||||
new_state_id = (p_parent != nullptr) ? p_parent->process_event(message) : static_cast<TDerived*>(this)->on_event_unknown(message);
|
||||
}
|
||||
|
||||
return new_state_id;
|
||||
}
|
||||
|
||||
//********************************************
|
||||
template <typename TMessage>
|
||||
bool process_event_type(const etl::imessage& msg, etl::fsm_state_id_t& new_state_id)
|
||||
{
|
||||
if (TMessage::ID == msg.get_message_id())
|
||||
{
|
||||
new_state_id = static_cast<TDerived*>(this)->on_event(static_cast<const TMessage&>(msg));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (p_parent != nullptr) ? p_parent->process_event(message) : static_cast<TDerived*>(this)->on_event_unknown(message);
|
||||
}
|
||||
};
|
||||
|
||||
/// Definition of STATE_ID
|
||||
template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, typename... TMessageTypes>
|
||||
ETL_CONSTANT etl::fsm_state_id_t fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::STATE_ID;
|
||||
|
||||
#else
|
||||
//*************************************************************************************************
|
||||
// For C++14 and below.
|
||||
// For C++03 and below.
|
||||
//*************************************************************************************************
|
||||
/*[[[cog
|
||||
import cog
|
||||
@ -833,14 +1031,14 @@ namespace etl
|
||||
cog.outl("//***************************************************************************")
|
||||
cog.outl("// The definition for all %s message types." % Handlers)
|
||||
cog.outl("//***************************************************************************")
|
||||
cog.outl("template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, ")
|
||||
cog.out(" ")
|
||||
cog.outl("template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,")
|
||||
cog.out(" ")
|
||||
for n in range(1, int(Handlers)):
|
||||
cog.out("typename T%s = void, " % n)
|
||||
cog.out(" typename T%s = void," % n)
|
||||
if n % 4 == 0:
|
||||
cog.outl("")
|
||||
cog.out(" ")
|
||||
cog.outl("typename T%s = void>" % Handlers)
|
||||
cog.out(" ")
|
||||
cog.outl(" typename T%s = void>" % Handlers)
|
||||
cog.outl("class fsm_state : public ifsm_state")
|
||||
cog.outl("{")
|
||||
cog.outl("public:")
|
||||
@ -896,26 +1094,26 @@ namespace etl
|
||||
else:
|
||||
cog.outl("// Specialisation for %d message types." % n)
|
||||
cog.outl("//***************************************************************************")
|
||||
cog.outl("template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, ")
|
||||
cog.out(" ")
|
||||
cog.outl("template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,")
|
||||
cog.out(" ")
|
||||
for t in range(1, n):
|
||||
cog.out("typename T%d, " % t)
|
||||
cog.out(" typename T%d," % t)
|
||||
if t % 4 == 0:
|
||||
cog.outl("")
|
||||
cog.out(" ")
|
||||
cog.outl("typename T%d>" % n)
|
||||
cog.out("class fsm_state<TContext, TDerived, STATE_ID_, ")
|
||||
cog.out(" ")
|
||||
cog.outl(" typename T%d>" % n)
|
||||
cog.out("class fsm_state<TContext, TDerived, STATE_ID_,")
|
||||
for t in range(1, n + 1):
|
||||
cog.out("T%d, " % t)
|
||||
cog.out(" T%d," % t)
|
||||
if t % 16 == 0:
|
||||
cog.outl("")
|
||||
cog.out(" ")
|
||||
for t in range(n + 1, int(Handlers)):
|
||||
cog.out("void, ")
|
||||
cog.out(" void,")
|
||||
if t % 16 == 0:
|
||||
cog.outl("")
|
||||
cog.out(" ")
|
||||
cog.outl("void> : public ifsm_state")
|
||||
cog.outl(" void> : public ifsm_state")
|
||||
cog.outl("{")
|
||||
cog.outl("public:")
|
||||
cog.outl("")
|
||||
@ -966,13 +1164,13 @@ namespace etl
|
||||
cog.outl("// Specialisation for 0 message types.")
|
||||
cog.outl("//***************************************************************************")
|
||||
cog.outl("template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_>")
|
||||
cog.out("class fsm_state<TContext, TDerived, STATE_ID_, ")
|
||||
cog.out("class fsm_state<TContext, TDerived, STATE_ID_,")
|
||||
for t in range(1, int(Handlers)):
|
||||
cog.out("void, ")
|
||||
cog.out(" void,")
|
||||
if t % 16 == 0:
|
||||
cog.outl("")
|
||||
cog.out(" ")
|
||||
cog.outl("void> : public ifsm_state")
|
||||
cog.outl(" void> : public ifsm_state")
|
||||
cog.outl("{")
|
||||
cog.outl("public:")
|
||||
cog.outl("")
|
||||
@ -1002,18 +1200,18 @@ namespace etl
|
||||
cog.outl("};")
|
||||
|
||||
cog.outl("")
|
||||
cog.outl("template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, ")
|
||||
cog.out(" ")
|
||||
cog.outl("template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_,")
|
||||
cog.out(" ")
|
||||
for n in range(1, int(Handlers)):
|
||||
cog.out("typename T%s, " % n)
|
||||
cog.out(" typename T%s," % n)
|
||||
if n % 4 == 0:
|
||||
cog.outl("")
|
||||
cog.out(" ")
|
||||
cog.outl("typename T%s>" % Handlers)
|
||||
cog.out("ETL_CONSTANT etl::fsm_state_id_t fsm_state<TContext, TDerived, STATE_ID_, ")
|
||||
cog.out(" ")
|
||||
cog.outl(" typename T%s>" % Handlers)
|
||||
cog.out("ETL_CONSTANT etl::fsm_state_id_t fsm_state<TContext, TDerived, STATE_ID_,")
|
||||
for n in range(1, int(Handlers)):
|
||||
cog.out("T%s, " % n)
|
||||
cog.outl("T%s>::STATE_ID;" % Handlers)
|
||||
cog.out(" T%s," % n)
|
||||
cog.outl(" T%s>::STATE_ID;" % Handlers)
|
||||
]]]*/
|
||||
/*[[[end]]]*/
|
||||
#endif
|
||||
|
||||
@ -525,33 +525,31 @@ namespace etl
|
||||
//***********************************************
|
||||
void receive(const etl::imessage& msg) ETL_OVERRIDE
|
||||
{
|
||||
etl::message_id_t id = msg.get_message_id();
|
||||
size_t index = Number_Of_Messages;
|
||||
const etl::message_id_t id = msg.get_message_id();
|
||||
|
||||
// The IDs are sorted, so an ID less than the first is not handled by this router.
|
||||
if (id >= Message_Id_Start)
|
||||
{
|
||||
index = get_dispatch_index_from_message_id(id);
|
||||
const size_t index = get_dispatch_index_from_message_id(id);
|
||||
|
||||
// If the index is less than Number_Of_Messages, then we have a handler for this message type, so dispatch it.
|
||||
if (index < Number_Of_Messages)
|
||||
{
|
||||
dispatch(msg, index);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If the index is less than Number_Of_Messages, then we have a handler for this message type, so dispatch it.
|
||||
if (index < Number_Of_Messages)
|
||||
// We don't have a handler for this message type, so pass it to a successor if there is one, or call on_receive_unknown() if there isn't.
|
||||
if (has_successor())
|
||||
{
|
||||
dispatch(msg, index);
|
||||
get_successor().receive(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We don't have a handler for this message type, so pass it to a successor if there is one, or call on_receive_unknown() if there isn't.
|
||||
if (has_successor())
|
||||
{
|
||||
get_successor().receive(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
static_cast<TDerived*>(this)->on_receive_unknown(msg);
|
||||
static_cast<TDerived*>(this)->on_receive_unknown(msg);
|
||||
#include "etl/private/diagnostic_pop.h"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -601,29 +599,17 @@ namespace etl
|
||||
//***********************************************
|
||||
bool accepts(etl::message_id_t id) const ETL_OVERRIDE
|
||||
{
|
||||
size_t index = Number_Of_Messages;
|
||||
|
||||
// The IDs are sorted, so an ID less than the first is not handled by this router.
|
||||
if (id >= Message_Id_Start)
|
||||
{
|
||||
index = get_dispatch_index_from_message_id(id);
|
||||
const size_t index = get_dispatch_index_from_message_id(id);
|
||||
|
||||
if (index < Number_Of_Messages)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < Number_Of_Messages)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (has_successor())
|
||||
{
|
||||
return get_successor().accepts(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return has_successor() ? get_successor().accepts(id) : false;
|
||||
}
|
||||
|
||||
//********************************************
|
||||
|
||||
@ -513,33 +513,31 @@ namespace etl
|
||||
//***********************************************
|
||||
void receive(const etl::imessage& msg) ETL_OVERRIDE
|
||||
{
|
||||
etl::message_id_t id = msg.get_message_id();
|
||||
size_t index = Number_Of_Messages;
|
||||
const etl::message_id_t id = msg.get_message_id();
|
||||
|
||||
// The IDs are sorted, so an ID less than the first is not handled by this router.
|
||||
if (id >= Message_Id_Start)
|
||||
{
|
||||
index = get_dispatch_index_from_message_id(id);
|
||||
const size_t index = get_dispatch_index_from_message_id(id);
|
||||
|
||||
// If the index is less than Number_Of_Messages, then we have a handler for this message type, so dispatch it.
|
||||
if (index < Number_Of_Messages)
|
||||
{
|
||||
dispatch(msg, index);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If the index is less than Number_Of_Messages, then we have a handler for this message type, so dispatch it.
|
||||
if (index < Number_Of_Messages)
|
||||
// We don't have a handler for this message type, so pass it to a successor if there is one, or call on_receive_unknown() if there isn't.
|
||||
if (has_successor())
|
||||
{
|
||||
dispatch(msg, index);
|
||||
get_successor().receive(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We don't have a handler for this message type, so pass it to a successor if there is one, or call on_receive_unknown() if there isn't.
|
||||
if (has_successor())
|
||||
{
|
||||
get_successor().receive(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
#include "etl/private/diagnostic_array_bounds_push.h"
|
||||
static_cast<TDerived*>(this)->on_receive_unknown(msg);
|
||||
static_cast<TDerived*>(this)->on_receive_unknown(msg);
|
||||
#include "etl/private/diagnostic_pop.h"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -589,29 +587,17 @@ namespace etl
|
||||
//***********************************************
|
||||
bool accepts(etl::message_id_t id) const ETL_OVERRIDE
|
||||
{
|
||||
size_t index = Number_Of_Messages;
|
||||
|
||||
// The IDs are sorted, so an ID less than the first is not handled by this router.
|
||||
if (id >= Message_Id_Start)
|
||||
{
|
||||
index = get_dispatch_index_from_message_id(id);
|
||||
const size_t index = get_dispatch_index_from_message_id(id);
|
||||
|
||||
if (index < Number_Of_Messages)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < Number_Of_Messages)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (has_successor())
|
||||
{
|
||||
return get_successor().accepts(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return has_successor() ? get_successor().accepts(id) : false;
|
||||
}
|
||||
|
||||
//********************************************
|
||||
|
||||
@ -515,7 +515,7 @@ namespace
|
||||
//*************************************************************************
|
||||
TEST(test_fsm_emergency_stop)
|
||||
{
|
||||
motorControl.Initialise(stateList, ETL_OR_STD17::size(stateList));
|
||||
motorControl.Initialise(stateList, ETL_OR_STD17::size(stateList));
|
||||
motorControl.reset();
|
||||
motorControl.ClearStatistics();
|
||||
|
||||
@ -758,7 +758,7 @@ namespace
|
||||
CHECK_EQUAL(StateId::Running, int(motorControl.get_state().get_state_id()));
|
||||
|
||||
auto id2 = motorControl.transition_to(StateId::Idle);
|
||||
|
||||
|
||||
// Now in Locked state.
|
||||
CHECK_EQUAL(StateId::Locked, int(id2));
|
||||
CHECK_EQUAL(StateId::Locked, int(motorControl.get_state_id()));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user