From 099b3f8cfdfdc228aa18b52bafd4c2d2da98ebb0 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Mon, 7 Aug 2017 15:54:21 +0100 Subject: [PATCH] Merge remote-tracking branch 'origin/development' # Conflicts: # test/codeblocks/ETL.depend # test/codeblocks/ETL.layout --- src/algorithm.h | 46 + src/alignment.h | 16 +- src/file_error_numbers.txt | 4 +- src/fsm.h | 1204 +++++++++++++++ src/fsm_generator.h | 569 +++++++ src/generate.bat | 5 + src/generate_fsm.bat | 1 + src/generate_message_router.bat | 1 + src/largest.h | 107 +- src/largest_generator.h | 323 ++++ src/memory.h | 21 + src/message.h | 96 ++ src/message_bus.h | 389 +++++ src/message_router.h | 2200 ++++++++++++++++++++++++++++ src/message_router_generator.h | 514 +++++++ src/message_types.h | 46 + src/packet.h | 128 ++ src/scheduler.h | 410 ++++++ src/smallest.h | 44 +- src/smallest_generator.h | 336 +++++ src/task.h | 125 ++ src/type_traits.h | 101 +- src/type_traits_generator.h | 500 +++++++ src/user_type.h | 43 +- src/variant.h | 124 +- temp/message_router.h | 984 +++++++++++++ test/codeblocks/ETL.cbp | 18 + test/codeblocks/ETL.depend | 173 ++- test/codeblocks/ETL.layout | 313 +--- test/test_algorithm.cpp | 65 +- test/test_fsm.cpp | 503 +++++++ test/test_memory.cpp | 26 + test/test_message_bus.cpp | 729 +++++++++ test/test_message_router.cpp | 421 ++++++ test/test_packet.cpp | 183 +++ test/test_task_scheduler.cpp | 263 ++++ test/test_type_traits.cpp | 68 +- test/test_user_type.cpp | 224 +++ test/test_variant.cpp | 124 +- test/vs2017/etl.vcxproj | 24 +- test/vs2017/etl.vcxproj.filters | 81 +- uml/FSM example.png | Bin 0 -> 3455 bytes uml/Framework.png | Bin 0 -> 4445 bytes uml/MessageFramework.png | Bin 0 -> 8529 bytes uml/source/FSM example.zargo | Bin 0 -> 6601 bytes uml/source/Message Framework.zargo | Bin 0 -> 9028 bytes 46 files changed, 11019 insertions(+), 533 deletions(-) create mode 100644 src/fsm.h create mode 100644 src/fsm_generator.h create mode 100644 src/generate.bat create mode 100644 src/generate_fsm.bat create mode 100644 src/generate_message_router.bat create mode 100644 src/largest_generator.h create mode 100644 src/message.h create mode 100644 src/message_bus.h create mode 100644 src/message_router.h create mode 100644 src/message_router_generator.h create mode 100644 src/message_types.h create mode 100644 src/packet.h create mode 100644 src/scheduler.h create mode 100644 src/smallest_generator.h create mode 100644 src/task.h create mode 100644 src/type_traits_generator.h create mode 100644 temp/message_router.h create mode 100644 test/test_fsm.cpp create mode 100644 test/test_message_bus.cpp create mode 100644 test/test_message_router.cpp create mode 100644 test/test_packet.cpp create mode 100644 test/test_task_scheduler.cpp create mode 100644 test/test_user_type.cpp create mode 100644 uml/FSM example.png create mode 100644 uml/Framework.png create mode 100644 uml/MessageFramework.png create mode 100644 uml/source/FSM example.zargo create mode 100644 uml/source/Message Framework.zargo diff --git a/src/algorithm.h b/src/algorithm.h index 2a7f236b..3f2b0575 100644 --- a/src/algorithm.h +++ b/src/algorithm.h @@ -418,6 +418,52 @@ namespace etl return o_begin; } + //*************************************************************************** + /// binary_find + ///\ingroup algorithm + /// Does a binary search and returns an iterator to the value or end if not found. + //*************************************************************************** + template + TIterator binary_find(TIterator begin, + TIterator end, + const TValue& value) + { + TIterator it = std::lower_bound(begin, end, value); + + if ((it == end) || (*it != value)) + { + it = end; + } + + return it; + } + + //*************************************************************************** + /// binary_find + ///\ingroup algorithm + /// Does a binary search and returns an iterator to the value or end if not found. + //*************************************************************************** + template + TIterator binary_find(TIterator begin, + TIterator end, + const TValue& value, + TBinaryPredicate predicate, + TBinaryEquality equality) + { + TIterator it = std::lower_bound(begin, end, value, predicate); + + if ((it == end) || !equality(*it, value)) + { + it = end; + } + + return it; + } + //*************************************************************************** /// find_if_not ///\ingroup algorithm diff --git a/src/alignment.h b/src/alignment.h index 18f20aea..578ae40c 100644 --- a/src/alignment.h +++ b/src/alignment.h @@ -113,7 +113,7 @@ namespace etl template operator T& () { - STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + STATIC_ASSERT((etl::is_same:: value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); return reinterpret_cast(*data); } @@ -121,7 +121,7 @@ namespace etl template operator const T& () const { - STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + STATIC_ASSERT((etl::is_same:: value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); return reinterpret_cast(*data); } @@ -129,7 +129,7 @@ namespace etl template operator T* () { - STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + STATIC_ASSERT((etl::is_same:: value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); return reinterpret_cast(data); } @@ -137,7 +137,7 @@ namespace etl template operator const T* () const { - STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + STATIC_ASSERT((etl::is_same:: value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); return reinterpret_cast(data); } @@ -145,7 +145,7 @@ namespace etl template T& get_reference() { - STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + STATIC_ASSERT((etl::is_same:: value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); return reinterpret_cast(*data); } @@ -153,7 +153,7 @@ namespace etl template const T& get_reference() const { - STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + STATIC_ASSERT((etl::is_same:: value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); return reinterpret_cast(*data); } @@ -161,7 +161,7 @@ namespace etl template T* get_address() { - STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + STATIC_ASSERT((etl::is_same:: value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); return reinterpret_cast(data); } @@ -169,7 +169,7 @@ namespace etl template const T* get_address() const { - STATIC_ASSERT(ALIGNMENT % etl::alignment_of::value == 0, "Incompatible alignment"); + STATIC_ASSERT((etl::is_same:: value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); return reinterpret_cast(data); } diff --git a/src/file_error_numbers.txt b/src/file_error_numbers.txt index 5cea1e44..24ffa829 100644 --- a/src/file_error_numbers.txt +++ b/src/file_error_numbers.txt @@ -34,4 +34,6 @@ 34 fsm 35 message_router 36 scheduler -37 task \ No newline at end of file +37 task +38 message +39 message_bus diff --git a/src/fsm.h b/src/fsm.h new file mode 100644 index 00000000..7c31acfc --- /dev/null +++ b/src/fsm.h @@ -0,0 +1,1204 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#if 0 +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +#endif + +//*************************************************************************** +// This file has been auto generated. Do not edit this file. +//*************************************************************************** + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -ofsm.h -DHandlers= fsm_generator.h +// Where is the number of messages to support. +// +// e.g. +// To generate handlers for up to 16 events... +// python -m cogapp -d -e -ofsm.h -DHandlers=16 fsm_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_FSM__ +#define __ETL_FSM__ + +#include + +#include "array.h" +#include "nullptr.h" +#include "error_handler.h" +#include "exception.h" +#include "user_type.h" +#include "message_router.h" +#include "integral_limits.h" +#include "largest.h" + +#undef ETL_FILE +#define ETL_FILE "34" + +#ifdef ETL_COMPILER_MICROSOFT +#undef max +#endif + +namespace etl +{ + class fsm; + + /// Allow alternative type for state id. +#if !defined(ETL_FSM_STATE_ID_TYPE) + typedef uint_least8_t fsm_state_id_t; +#else + typedef ETL_FSM_STATE_ID_TYPE fsm_state_id_t; +#endif + + // For internal FSM use. + typedef typename etl::larger_type::type fsm_internal_id_t; + + //*************************************************************************** + /// Base exception class for FSM. + //*************************************************************************** + class fsm_exception : public etl::exception + { + public: + + fsm_exception(string_type what, string_type file_name, numeric_type line_number) + : etl::exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Exception for null state pointer. + //*************************************************************************** + class fsm_null_state_exception : public etl::fsm_exception + { + public: + + fsm_null_state_exception(string_type file_name, numeric_type line_number) + : etl::fsm_exception(ETL_ERROR_TEXT("fsm:null state", ETL_FILE"A"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Exception for invalid state id. + //*************************************************************************** + class fsm_state_id_exception : public etl::fsm_exception + { + public: + + fsm_state_id_exception(string_type file_name, numeric_type line_number) + : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state id", ETL_FILE"B"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Exception for incompatible state list. + //*************************************************************************** + class fsm_state_list_exception : public etl::fsm_exception + { + public: + + fsm_state_list_exception(string_type file_name, numeric_type line_number) + : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state list", ETL_FILE"C"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Interface class for FSM states. + //*************************************************************************** + class ifsm_state + { + public: + + /// Allows ifsm_state functions to be private. + friend class fsm_helper; + + //******************************************* + /// Gets the id for this state. + //******************************************* + etl::fsm_state_id_t get_state_id() const + { + return state_id; + } + + protected: + + //******************************************* + /// Constructor. + //******************************************* + ifsm_state(etl::fsm_state_id_t state_id_) + : state_id(state_id_), + p_context(nullptr) + { + } + + //******************************************* + inline etl::fsm& get_fsm_context() const + { + return *p_context; + } + + private: + + virtual fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) = 0; + + virtual fsm_state_id_t on_enter_state() { return state_id; } // By default, do nothing. + virtual void on_exit_state() {} // By default, do nothing. + + //******************************************* + void set_fsm_context(etl::fsm& context) + { + p_context = &context; + } + + // The state id. + const etl::fsm_state_id_t state_id; + + // A pointer to the FSM context. + etl::fsm* p_context; + + // Disabled. + ifsm_state(const ifsm_state&); + ifsm_state& operator =(const ifsm_state&); + }; + + //*************************************************************************** + /// Helper class for FSM. + /// Allows ifsm_state functions to be private. + //*************************************************************************** + class fsm_helper + { + public: + + //******************************************* + inline void set_fsm_context(etl::ifsm_state& state, + etl::fsm& context) + { + state.set_fsm_context(context); + } + + //******************************************* + inline fsm_state_id_t process_event(etl::ifsm_state& state, + etl::imessage_router& source, + const etl::imessage& message) + { + return state.process_event(source, message); + } + + //******************************************* + inline fsm_state_id_t on_enter_state(etl::ifsm_state& state) + { + return state.on_enter_state(); + } + + //******************************************* + inline void on_exit_state(etl::ifsm_state& state) + { + state.on_exit_state(); + } + }; + + //*************************************************************************** + /// The FSM class. + //*************************************************************************** + class fsm : public etl::imessage_router, protected etl::fsm_helper + { + public: + + //******************************************* + /// Constructor. + //******************************************* + fsm(etl::message_router_id_t id) + : imessage_router(id), + p_state(nullptr) + { + } + + //******************************************* + /// Set the states for the FSM + //******************************************* + template + void set_states(etl::ifsm_state** p_states, TSize size) + { + state_list = p_states; + number_of_states = etl::fsm_state_id_t(size); + + ETL_ASSERT((number_of_states > 0), ETL_ERROR(etl::fsm_state_list_exception)); + + for (etl::fsm_state_id_t i = 0; i < size; ++i) + { + ETL_ASSERT((state_list[i] != nullptr), ETL_ERROR(etl::fsm_null_state_exception)); + fsm_helper::set_fsm_context(*state_list[i], *this); + } + } + + //******************************************* + /// Starts the FSM. + /// Can only be called once. + /// Subsequent calls will do nothing. + //******************************************* + void start() + { + // Can only be started once. + if (p_state == nullptr) + { + p_state = state_list[0]; + ETL_ASSERT(p_state != nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + + fsm_helper::on_enter_state(*p_state); + } + } + + //******************************************* + /// Top level message handler for the FSM. + //******************************************* + void receive(const etl::imessage& message) + { + etl::null_message_router nmr; + receive(nmr, message); + } + + //******************************************* + /// Top level message handler for the FSM. + //******************************************* + void receive(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t next_state_id = fsm_helper::process_event(*p_state, source, message); + ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); + + etl::ifsm_state* p_next_state = state_list[next_state_id]; + + // Have we changed state? + if (p_next_state != p_state) + { + do + { + p_state = p_next_state; + fsm_helper::on_exit_state(*p_state); + + next_state_id = fsm_helper::on_enter_state(*p_state); + ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); + + p_next_state = state_list[next_state_id]; + + } while (p_next_state != p_state); // Have we changed state again? + } + } + + using imessage_router::accepts; + + //******************************************* + /// Does this FSM accept the message id? + /// Yes, it accepts everything! + //******************************************* + bool accepts(etl::message_id_t id) const + { + return true; + } + + //******************************************* + /// Gets the current state id. + //******************************************* + etl::fsm_state_id_t get_state_id() const + { + ETL_ASSERT(p_state != nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + return p_state->get_state_id(); + } + + //******************************************* + /// Gets a reference to the current state interface. + //******************************************* + ifsm_state& get_state() + { + ETL_ASSERT(p_state != nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + return *p_state; + } + + //******************************************* + /// Gets a const reference to the current state interface. + //******************************************* + const ifsm_state& get_state() const + { + ETL_ASSERT(p_state != nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + return *p_state; + } + + //******************************************* + /// Checks if the FSM has been started. + //******************************************* + bool is_started() const + { + return p_state != nullptr; + } + + //******************************************* + /// Reset the FSM to pre-started state. + //******************************************* + void reset() + { + p_state = nullptr; + } + + private: + + etl::ifsm_state* p_state; ///< A pointer to the current state. + etl::ifsm_state** state_list; ///< The list of added states. + etl::fsm_state_id_t number_of_states; ///< The number of states. + }; + + + //*************************************************************************** + // The definition for all 16 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T6::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T7::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T8::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T9::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T10::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T11::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T12::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T13::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T14::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T15::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T16::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 15 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T6::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T7::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T8::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T9::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T10::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T11::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T12::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T13::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T14::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T15::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 14 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T6::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T7::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T8::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T9::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T10::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T11::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T12::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T13::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T14::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 13 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T6::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T7::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T8::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T9::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T10::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T11::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T12::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T13::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 12 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T6::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T7::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T8::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T9::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T10::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T11::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T12::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 11 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T6::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T7::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T8::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T9::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T10::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T11::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 10 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T6::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T7::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T8::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T9::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T10::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 9 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T6::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T7::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T8::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T9::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 8 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T6::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T7::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T8::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 7 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T6::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T7::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 6 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T6::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 5 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T5::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 4 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T4::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 3 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T3::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 2 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + case T2::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 1 message type. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t new_state_id; + etl::message_id_t event_id = message.get_message_id(); + + switch (event_id) + { + case T1::ID: new_state_id = static_cast(this)->on_event(source, static_cast(message)); break; + default: new_state_id = static_cast(this)->on_event_unknown(source, message); break; + } + + return new_state_id; + } + }; + + //*************************************************************************** + // Specialisation for 0 message types. + //*************************************************************************** + template + class fsm_state : public ifsm_state + { + public: + + enum + { + STATE_ID = STATE_ID_ + }; + + fsm_state() + : ifsm_state(STATE_ID) + { + } + + inline TContext& get_fsm_context() const + { + return static_cast(ifsm_state::get_fsm_context()); + } + private: + + etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) + { + return static_cast(this)->on_event_unknown(source, message); + } + }; +} + +#undef ETL_FILE + +#ifdef ETL_COMPILER_MICROSOFT +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#endif diff --git a/src/fsm_generator.h b/src/fsm_generator.h new file mode 100644 index 00000000..0072dbd0 --- /dev/null +++ b/src/fsm_generator.h @@ -0,0 +1,569 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +/*[[[cog +import cog +cog.outl("#if 0") +]]]*/ +/*[[[end]]]*/ +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +/*[[[cog +import cog +cog.outl("#endif") +]]]*/ +/*[[[end]]]*/ + +/*[[[cog +import cog +cog.outl("//***************************************************************************") +cog.outl("// This file has been auto generated. Do not edit this file.") +cog.outl("//***************************************************************************") +]]]*/ +/*[[[end]]]*/ + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -ofsm.h -DHandlers= fsm_generator.h +// Where is the number of messages to support. +// +// e.g. +// To generate handlers for up to 16 events... +// python -m cogapp -d -e -ofsm.h -DHandlers=16 fsm_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_FSM__ +#define __ETL_FSM__ + +#include + +#include "array.h" +#include "nullptr.h" +#include "error_handler.h" +#include "exception.h" +#include "user_type.h" +#include "message_router.h" +#include "integral_limits.h" +#include "largest.h" + +#undef ETL_FILE +#define ETL_FILE "34" + +#ifdef ETL_COMPILER_MICROSOFT +#undef max +#endif + +namespace etl +{ + class fsm; + + /// Allow alternative type for state id. +#if !defined(ETL_FSM_STATE_ID_TYPE) + typedef uint_least8_t fsm_state_id_t; +#else + typedef ETL_FSM_STATE_ID_TYPE fsm_state_id_t; +#endif + + // For internal FSM use. + typedef typename etl::larger_type::type fsm_internal_id_t; + + //*************************************************************************** + /// Base exception class for FSM. + //*************************************************************************** + class fsm_exception : public etl::exception + { + public: + + fsm_exception(string_type what, string_type file_name, numeric_type line_number) + : etl::exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Exception for null state pointer. + //*************************************************************************** + class fsm_null_state_exception : public etl::fsm_exception + { + public: + + fsm_null_state_exception(string_type file_name, numeric_type line_number) + : etl::fsm_exception(ETL_ERROR_TEXT("fsm:null state", ETL_FILE"A"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Exception for invalid state id. + //*************************************************************************** + class fsm_state_id_exception : public etl::fsm_exception + { + public: + + fsm_state_id_exception(string_type file_name, numeric_type line_number) + : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state id", ETL_FILE"B"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Exception for incompatible state list. + //*************************************************************************** + class fsm_state_list_exception : public etl::fsm_exception + { + public: + + fsm_state_list_exception(string_type file_name, numeric_type line_number) + : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state list", ETL_FILE"C"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Interface class for FSM states. + //*************************************************************************** + class ifsm_state + { + public: + + /// Allows ifsm_state functions to be private. + friend class fsm_helper; + + //******************************************* + /// Gets the id for this state. + //******************************************* + etl::fsm_state_id_t get_state_id() const + { + return state_id; + } + + protected: + + //******************************************* + /// Constructor. + //******************************************* + ifsm_state(etl::fsm_state_id_t state_id_) + : state_id(state_id_), + p_context(nullptr) + { + } + + //******************************************* + inline etl::fsm& get_fsm_context() const + { + return *p_context; + } + + private: + + virtual fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) = 0; + + virtual fsm_state_id_t on_enter_state() { return state_id; } // By default, do nothing. + virtual void on_exit_state() {} // By default, do nothing. + + //******************************************* + void set_fsm_context(etl::fsm& context) + { + p_context = &context; + } + + // The state id. + const etl::fsm_state_id_t state_id; + + // A pointer to the FSM context. + etl::fsm* p_context; + + // Disabled. + ifsm_state(const ifsm_state&); + ifsm_state& operator =(const ifsm_state&); + }; + + //*************************************************************************** + /// Helper class for FSM. + /// Allows ifsm_state functions to be private. + //*************************************************************************** + class fsm_helper + { + public: + + //******************************************* + inline void set_fsm_context(etl::ifsm_state& state, + etl::fsm& context) + { + state.set_fsm_context(context); + } + + //******************************************* + inline fsm_state_id_t process_event(etl::ifsm_state& state, + etl::imessage_router& source, + const etl::imessage& message) + { + return state.process_event(source, message); + } + + //******************************************* + inline fsm_state_id_t on_enter_state(etl::ifsm_state& state) + { + return state.on_enter_state(); + } + + //******************************************* + inline void on_exit_state(etl::ifsm_state& state) + { + state.on_exit_state(); + } + }; + + //*************************************************************************** + /// The FSM class. + //*************************************************************************** + class fsm : public etl::imessage_router, protected etl::fsm_helper + { + public: + + //******************************************* + /// Constructor. + //******************************************* + fsm(etl::message_router_id_t id) + : imessage_router(id), + p_state(nullptr) + { + } + + //******************************************* + /// Set the states for the FSM + //******************************************* + template + void set_states(etl::ifsm_state** p_states, TSize size) + { + state_list = p_states; + number_of_states = etl::fsm_state_id_t(size); + + ETL_ASSERT((number_of_states > 0), ETL_ERROR(etl::fsm_state_list_exception)); + + for (etl::fsm_state_id_t i = 0; i < size; ++i) + { + ETL_ASSERT((state_list[i] != nullptr), ETL_ERROR(etl::fsm_null_state_exception)); + fsm_helper::set_fsm_context(*state_list[i], *this); + } + } + + //******************************************* + /// Starts the FSM. + /// Can only be called once. + /// Subsequent calls will do nothing. + //******************************************* + void start() + { + // Can only be started once. + if (p_state == nullptr) + { + p_state = state_list[0]; + ETL_ASSERT(p_state != nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + + fsm_helper::on_enter_state(*p_state); + } + } + + //******************************************* + /// Top level message handler for the FSM. + //******************************************* + void receive(const etl::imessage& message) + { + etl::null_message_router nmr; + receive(nmr, message); + } + + //******************************************* + /// Top level message handler for the FSM. + //******************************************* + void receive(etl::imessage_router& source, const etl::imessage& message) + { + etl::fsm_state_id_t next_state_id = fsm_helper::process_event(*p_state, source, message); + ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); + + etl::ifsm_state* p_next_state = state_list[next_state_id]; + + // Have we changed state? + if (p_next_state != p_state) + { + do + { + p_state = p_next_state; + fsm_helper::on_exit_state(*p_state); + + next_state_id = fsm_helper::on_enter_state(*p_state); + ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); + + p_next_state = state_list[next_state_id]; + + } while (p_next_state != p_state); // Have we changed state again? + } + } + + using imessage_router::accepts; + + //******************************************* + /// Does this FSM accept the message id? + /// Yes, it accepts everything! + //******************************************* + bool accepts(etl::message_id_t id) const + { + return true; + } + + //******************************************* + /// Gets the current state id. + //******************************************* + etl::fsm_state_id_t get_state_id() const + { + ETL_ASSERT(p_state != nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + return p_state->get_state_id(); + } + + //******************************************* + /// Gets a reference to the current state interface. + //******************************************* + ifsm_state& get_state() + { + ETL_ASSERT(p_state != nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + return *p_state; + } + + //******************************************* + /// Gets a const reference to the current state interface. + //******************************************* + const ifsm_state& get_state() const + { + ETL_ASSERT(p_state != nullptr, ETL_ERROR(etl::fsm_null_state_exception)); + return *p_state; + } + + //******************************************* + /// Checks if the FSM has been started. + //******************************************* + bool is_started() const + { + return p_state != nullptr; + } + + //******************************************* + /// Reset the FSM to pre-started state. + //******************************************* + void reset() + { + p_state = nullptr; + } + + private: + + etl::ifsm_state* p_state; ///< A pointer to the current state. + etl::ifsm_state** state_list; ///< The list of added states. + etl::fsm_state_id_t number_of_states; ///< The number of states. + }; + + /*[[[cog + import cog + cog.outl("") + ################################################ + # The first definition for all of the events. + ################################################ + cog.outl("//***************************************************************************") + cog.outl("// The definition for all %s message types." % Handlers) + cog.outl("//***************************************************************************") + cog.outl("template " % Handlers) + cog.outl("class fsm_state : public ifsm_state") + cog.outl("{") + cog.outl("public:") + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" STATE_ID = STATE_ID_") + cog.outl(" };") + cog.outl("") + cog.outl(" fsm_state()") + cog.outl(" : ifsm_state(STATE_ID)") + cog.outl(" {") + cog.outl(" }") + cog.outl("") + cog.outl(" inline TContext& get_fsm_context() const") + cog.outl(" {") + cog.outl(" return static_cast(ifsm_state::get_fsm_context());") + cog.outl(" }") + cog.outl("") + cog.outl("private:") + cog.outl("") + cog.outl(" etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)") + cog.outl(" {") + cog.outl(" etl::fsm_state_id_t new_state_id;") + cog.outl(" etl::message_id_t event_id = message.get_message_id();") + cog.outl("") + cog.outl(" switch (event_id)") + cog.outl(" {") + for n in range(1, int(Handlers) + 1): + cog.out(" case T%d::ID:" % n) + cog.out(" new_state_id = static_cast(this)->on_event(source, static_cast(message));" % n) + cog.outl(" break;") + cog.out(" default:") + cog.out(" new_state_id = static_cast(this)->on_event_unknown(source, message);") + cog.outl(" break;") + cog.outl(" }") + cog.outl("") + cog.outl(" return new_state_id;") + cog.outl(" }") + cog.outl("};") + + #################################### + # All of the other specialisations. + #################################### + for n in range(int(Handlers) - 1, 0, -1): + cog.outl("") + cog.outl("//***************************************************************************") + if n == 1: + cog.outl("// Specialisation for %d message type." % n) + else: + cog.outl("// Specialisation for %d message types." % n) + cog.outl("//***************************************************************************") + cog.outl("template " % n) + cog.out("class fsm_state : public ifsm_state") + cog.outl("{") + cog.outl("public:") + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" STATE_ID = STATE_ID_") + cog.outl(" };") + cog.outl("") + cog.outl(" fsm_state()") + cog.outl(" : ifsm_state(STATE_ID)") + cog.outl(" {") + cog.outl(" }") + cog.outl("") + cog.outl(" inline TContext& get_fsm_context() const") + cog.outl(" {") + cog.outl(" return static_cast(ifsm_state::get_fsm_context());") + cog.outl(" }") + cog.outl("private:") + cog.outl("") + cog.outl(" etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)") + cog.outl(" {") + cog.outl(" etl::fsm_state_id_t new_state_id;") + cog.outl(" etl::message_id_t event_id = message.get_message_id();") + cog.outl("") + cog.outl(" switch (event_id)") + cog.outl(" {") + for n in range(1, n + 1): + cog.out(" case T%d::ID:" % n) + cog.out(" new_state_id = static_cast(this)->on_event(source, static_cast(message));" % n) + cog.outl(" break;") + cog.out(" default:") + cog.out(" new_state_id = static_cast(this)->on_event_unknown(source, message);") + cog.outl(" break;") + cog.outl(" }") + cog.outl("") + cog.outl(" return new_state_id;") + cog.outl(" }") + cog.outl("};") + #################################### + # Specialisation for zero messages. + #################################### + cog.outl("") + cog.outl("//***************************************************************************") + cog.outl("// Specialisation for 0 message types.") + cog.outl("//***************************************************************************") + cog.outl("template ") + cog.out("class fsm_state : public ifsm_state") + cog.outl("{") + cog.outl("public:") + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" STATE_ID = STATE_ID_") + cog.outl(" };") + cog.outl("") + cog.outl(" fsm_state()") + cog.outl(" : ifsm_state(STATE_ID)") + cog.outl(" {") + cog.outl(" }") + cog.outl("") + cog.outl(" inline TContext& get_fsm_context() const") + cog.outl(" {") + cog.outl(" return static_cast(ifsm_state::get_fsm_context());") + cog.outl(" }") + cog.outl("private:") + cog.outl("") + cog.outl(" etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)") + cog.outl(" {") + cog.outl(" return static_cast(this)->on_event_unknown(source, message);") + cog.outl(" }") + cog.outl("};") + ]]]*/ + /*[[[end]]]*/ +} + +#undef ETL_FILE + +#ifdef ETL_COMPILER_MICROSOFT +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#endif diff --git a/src/generate.bat b/src/generate.bat new file mode 100644 index 00000000..8902cbde --- /dev/null +++ b/src/generate.bat @@ -0,0 +1,5 @@ +python -m cogapp -d -e -ofsm.h -DHandlers=16 fsm_generator.h +python -m cogapp -d -e -omessage_router.h -DHandlers=16 message_router_generator.h +python -m cogapp -d -e -olargest.h -DNTypes=16 largest_generator.h +python -m cogapp -d -e -osmallest.h -DNTypes=16 smallest_generator.h +python -m cogapp -d -e -otype_traits.h -DIsOneOf=16 type_traits_generator.h \ No newline at end of file diff --git a/src/generate_fsm.bat b/src/generate_fsm.bat new file mode 100644 index 00000000..07c25ece --- /dev/null +++ b/src/generate_fsm.bat @@ -0,0 +1 @@ +python -m cogapp -d -e -ofsm.h -DHandlers=16 fsm_generator.h diff --git a/src/generate_message_router.bat b/src/generate_message_router.bat new file mode 100644 index 00000000..b30597fb --- /dev/null +++ b/src/generate_message_router.bat @@ -0,0 +1 @@ +python -m cogapp -d -e -omessage_router.h -DHandlers=16 message_router_generator.h diff --git a/src/largest.h b/src/largest.h index 311adc0b..a3334c99 100644 --- a/src/largest.h +++ b/src/largest.h @@ -5,7 +5,7 @@ The MIT License(MIT) Embedded Template Library. https://github.com/ETLCPP/etl -http://www.etlcpp.com +https://www.etlcpp.com Copyright(c) 2014 jwellbelove @@ -28,6 +28,28 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************************/ +#if 0 +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +#endif + +//*************************************************************************** +// This file has been auto generated. Do not edit this file. +//*************************************************************************** + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -olargest.h -DNTypes= largest_generator.h +// Where is the number of types to support. +// +// e.g. +// To generate handlers for up to 16 types... +// python -m cogapp -d -e -olargest.h -DNTypes=16 largest_generator.h +// +// See generate.bat +//*************************************************************************** + #ifndef __ETL_LARGEST__ #define __ETL_LARGEST__ @@ -47,9 +69,9 @@ namespace etl /// Defines 'size' which is the size of the largest parameter. ///\ingroup largest //*************************************************************************** - template struct largest_type { @@ -78,14 +100,14 @@ namespace etl public: // Define 'largest_other' as 'largest_type' with all but the first parameter. - typedef typename largest_type::type largest_other; + typedef typename largest_type::type largest_other; // Set 'type' to be the largest of the first parameter and any of the others. // This is recursive. typedef typename choose_type<(sizeof(T1) > sizeof(largest_other)), // Boolean - T1, // TrueType - largest_other> // FalseType - ::type type; // The largest type of the two. + T1, // TrueType + largest_other> // FalseType + ::type type; // The largest type of the two. // The size of the largest type. enum @@ -98,10 +120,8 @@ namespace etl // Specialisation for one template parameter. //*************************************************************************** template - struct largest_type + struct largest_type { typedef T1 type; @@ -117,12 +137,14 @@ namespace etl /// Defines value which is the largest alignment of all the parameters. ///\ingroup largest //*************************************************************************** - template + template struct largest_alignment { + private: + // Determine the largest size. template struct max_size @@ -136,22 +158,22 @@ namespace etl // All of the alignments. enum { - t1 = alignment_of::value, - t2 = alignment_of::value, - t3 = alignment_of::value, - t4 = alignment_of::value, - t5 = alignment_of::value, - t6 = alignment_of::value, - t7 = alignment_of::value, - t8 = alignment_of::value, - t9 = alignment_of::value, - t10 = alignment_of::value, - t11 = alignment_of::value, - t12 = alignment_of::value, - t13 = alignment_of::value, - t14 = alignment_of::value, - t15 = alignment_of::value, - t16 = alignment_of::value + t1 = etl::alignment_of::value, + t2 = etl::alignment_of::value, + t3 = etl::alignment_of::value, + t4 = etl::alignment_of::value, + t5 = etl::alignment_of::value, + t6 = etl::alignment_of::value, + t7 = etl::alignment_of::value, + t8 = etl::alignment_of::value, + t9 = etl::alignment_of::value, + t10 = etl::alignment_of::value, + t11 = etl::alignment_of::value, + t12 = etl::alignment_of::value, + t13 = etl::alignment_of::value, + t14 = etl::alignment_of::value, + t15 = etl::alignment_of::value, + t16 = etl::alignment_of::value }; public: @@ -216,6 +238,27 @@ namespace etl typedef typename etl::smallest_int_for_bits::bits + 1>::type type; }; + + //*************************************************************************** + /// Template to determine the largest type, size and alignment. + /// Supports up to 16 types. + /// Defines value which is the largest type, size and alignment of all the parameters. + ///\ingroup largest + //*************************************************************************** + template + struct largest + { + typedef typename etl::largest_type::type type; + + enum + { + size = etl::largest_type::size, + alignment = etl::largest_alignment::value + }; + }; } #endif diff --git a/src/largest_generator.h b/src/largest_generator.h new file mode 100644 index 00000000..27464662 --- /dev/null +++ b/src/largest_generator.h @@ -0,0 +1,323 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +/*[[[cog +import cog +cog.outl("#if 0") +]]]*/ +/*[[[end]]]*/ +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +/*[[[cog +import cog +cog.outl("#endif") +]]]*/ +/*[[[end]]]*/ + +/*[[[cog +import cog +cog.outl("//***************************************************************************") +cog.outl("// This file has been auto generated. Do not edit this file.") +cog.outl("//***************************************************************************") +]]]*/ +/*[[[end]]]*/ + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -olargest.h -DNTypes= largest_generator.h +// Where is the number of types to support. +// +// e.g. +// To generate handlers for up to 16 types... +// python -m cogapp -d -e -olargest.h -DNTypes=16 largest_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_LARGEST__ +#define __ETL_LARGEST__ + +///\defgroup largest largest +///\ingroup utilities + +#include "type_traits.h" +#include "smallest.h" +#include "static_assert.h" + +namespace etl +{ + /*[[[cog + import cog + cog.outl("//***************************************************************************") + cog.outl("/// Template to determine the largest type and size.") + cog.outl("/// Supports up to %s types." % NTypes) + cog.outl("/// Defines 'value_type' which is the type of the largest parameter.") + cog.outl("/// Defines 'size' which is the size of the largest parameter.") + cog.outl("///\ingroup largest") + cog.outl("//***************************************************************************") + cog.out("template " % int(NTypes)) + cog.outl("struct largest_type") + cog.outl("{") + cog.outl("private:") + cog.outl("") + cog.outl(" // Declaration.") + cog.outl(" template ") + cog.outl(" struct choose_type;") + cog.outl("") + cog.outl(" // Specialisation for 'true'.") + cog.outl(" // Defines 'type' as 'TrueType'.") + cog.outl(" template ") + cog.outl(" struct choose_type") + cog.outl(" {") + cog.outl(" typedef TrueType type;") + cog.outl(" };") + cog.outl("") + cog.outl(" // Specialisation for 'false'. ") + cog.outl(" // Defines 'type' as 'FalseType'.") + cog.outl(" template ") + cog.outl(" struct choose_type") + cog.outl(" {") + cog.outl(" typedef FalseType type;") + cog.outl(" };") + cog.outl("") + cog.outl("public:") + cog.outl("") + cog.outl(" // Define 'largest_other' as 'largest_type' with all but the first parameter. ") + cog.out(" typedef typename largest_type<") + for n in range(2, int(NTypes)): + cog.out("T%s, " % n) + if n % 16 == 0: + cog.outl("") + cog.out(" ") + cog.outl("T%s>::type largest_other;" % int(NTypes)) + cog.outl("") + cog.outl(" // Set 'type' to be the largest of the first parameter and any of the others.") + cog.outl(" // This is recursive.") + cog.outl(" typedef typename choose_type<(sizeof(T1) > sizeof(largest_other)), // Boolean") + cog.outl(" T1, // TrueType") + cog.outl(" largest_other> // FalseType") + cog.outl(" ::type type; // The largest type of the two.") + cog.outl("") + cog.outl(" // The size of the largest type.") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" size = sizeof(type)") + cog.outl(" };") + cog.outl("};") + cog.outl("") + cog.outl("//***************************************************************************") + cog.outl("// Specialisation for one template parameter.") + cog.outl("//***************************************************************************") + cog.outl("template ") + cog.out("struct largest_type") + cog.outl("{") + cog.outl(" typedef T1 type;") + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" size = sizeof(type)") + cog.outl(" };") + cog.outl("};") + ]]]*/ + /*[[[end]]]*/ + + /*[[[cog + import cog + cog.outl("//***************************************************************************") + cog.outl("/// Template to determine the largest alignment.") + cog.outl("/// Supports up to %s types." % int(NTypes)) + cog.outl("/// Defines value which is the largest alignment of all the parameters.") + cog.outl("///\ingroup largest") + cog.outl("//***************************************************************************") + cog.out("template " % NTypes) + cog.outl("struct largest_alignment") + cog.outl("{") + cog.outl("private:") + cog.outl("") + cog.outl(" // Determine the largest size.") + cog.outl(" template ") + cog.outl(" struct max_size") + cog.outl(" {") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" value = (size1 > size2) ? size1 : size2") + cog.outl(" };") + cog.outl(" };") + cog.outl("") + cog.outl(" // All of the alignments.") + cog.outl(" enum") + cog.outl(" {") + for n in range(1, int(NTypes)): + cog.outl(" t%s = etl::alignment_of::value," %(n, n)) + cog.outl(" t%s = etl::alignment_of::value" % (NTypes, NTypes)) + cog.outl(" };") + cog.outl("") + cog.outl("public:") + cog.outl("") + cog.outl(" // The largest of all of them.") + cog.outl(" enum") + cog.outl(" {") + cog.out(" value = ") + for n in range(1, int(NTypes)): + cog.out("max_size" % int(NTypes)) + cog.out(" ") + for n in range(1, int(NTypes) - 1): + cog.out("::value>") + if n % 8 == 0: + cog.outl("") + cog.out(" ") + cog.outl("::value") + cog.outl(" };") + cog.outl("};") + ]]]*/ + /*[[[end]]]*/ + + //*************************************************************************** + /// Defines a type that is as larger or larger than the specified type. + /// Will return the specified type is there is not a larger type. + ///\ingroup largest + //*************************************************************************** + template + struct larger_int_type + { + STATIC_ASSERT(etl::is_integral::value, "Must be an integral type"); + + typedef typename etl::smallest_int_for_bits::type>::bits + 1>::type type; + }; + + //*************************************************************************** + /// Defines a type that is as larger or larger than the specified type. + /// Will return the specified type is there is not a larger type. + ///\ingroup largest + //*************************************************************************** + template + struct larger_uint_type + { + STATIC_ASSERT(etl::is_integral::value, "Must be an integral type"); + + typedef typename etl::smallest_uint_for_bits::type>::bits + 1>::type type; + }; + + //*************************************************************************** + /// Defines a type that is as larger or larger than the specified type. + /// Will return the specified type is there is not a larger type. + /// The returned type will be of the same sign. + ///\ingroup largest + //*************************************************************************** + template ::value> + struct larger_type; + + template + struct larger_type + { + STATIC_ASSERT(etl::is_integral::value, "Must be an integral type"); + + typedef typename etl::smallest_uint_for_bits::bits + 1>::type type; + }; + + template + struct larger_type + { + STATIC_ASSERT(etl::is_integral::value, "Must be an integral type"); + + typedef typename etl::smallest_int_for_bits::bits + 1>::type type; + }; + + /*[[[cog + import cog + cog.outl("//***************************************************************************") + cog.outl("/// Template to determine the largest type, size and alignment.") + cog.outl("/// Supports up to %s types." % NTypes) + cog.outl("/// Defines value which is the largest type, size and alignment of all the parameters.") + cog.outl("///\ingroup largest") + cog.outl("//***************************************************************************") + cog.out("template " % NTypes) + cog.outl("struct largest") + cog.outl("{") + cog.out(" typedef typename etl::largest_type<") + for n in range(1, int(NTypes)): + cog.out("T%s, " % n) + if n % 16 == 0: + cog.outl("") + cog.out(" ") + cog.outl("T%s>::type type;" % NTypes) + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.out(" size = etl::largest_type<") + for n in range(1, int(NTypes)): + cog.out("T%s, " % n) + if n % 16 == 0: + cog.outl("") + cog.out(" ") + cog.outl("T%s>::size," % NTypes) + cog.out(" alignment = etl::largest_alignment<") + for n in range(1, int(NTypes)): + cog.out("T%s, " % n) + if n % 16 == 0: + cog.outl("") + cog.out(" ") + cog.outl("T%s>::value" % NTypes) + cog.outl(" };") + cog.outl("};") + ]]]*/ + /*[[[end]]]*/ +} + +#endif diff --git a/src/memory.h b/src/memory.h index 947c1124..1920f0b2 100644 --- a/src/memory.h +++ b/src/memory.h @@ -662,6 +662,27 @@ namespace etl return i_begin; } + + //***************************************************************************** + /// Copy constructs a derived class to an address. + ///\tparam T The derived type. + ///\ingroup memory + //***************************************************************************** + template + struct create_copy + { + void create_copy_at(void* p) + { + new (p) T(static_cast(*this)); + } + + template + void create_copy_at(void* p, TCounter& count) + { + new (p) T(static_cast(*this)); + ++count; + } + }; } #endif diff --git a/src/message.h b/src/message.h new file mode 100644 index 00000000..d422e7b5 --- /dev/null +++ b/src/message.h @@ -0,0 +1,96 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef __ETL_MESSAGE__ +#define __ETL_MESSAGE__ + +#include + +#include "error_handler.h" +#include "exception.h" +#include "message_types.h" + +#undef ETL_FILE +#define ETL_FILE "38" + +namespace etl +{ + //*************************************************************************** + class message_exception : public etl::exception + { + public: + + message_exception(string_type what, string_type file_name, numeric_type line_number) + : exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + class unhandled_message_exception : public etl::message_exception + { + public: + + unhandled_message_exception(string_type file_name, numeric_type line_number) + : message_exception(ETL_ERROR_TEXT("message:unknown", ETL_FILE"A"), file_name, line_number) + { + } + }; + + //*************************************************************************** + class imessage + { + public: + + //******************************************** + virtual ~imessage() {} + virtual etl::message_id_t get_message_id() const = 0; + }; + + //*************************************************************************** + template + class message : public imessage + { + public: + + enum + { + ID = ID_ + }; + + //******************************************** + etl::message_id_t get_message_id() const + { + return ID; + } + }; +} + +#undef ETL_FILE + +#endif diff --git a/src/message_bus.h b/src/message_bus.h new file mode 100644 index 00000000..ef8c811b --- /dev/null +++ b/src/message_bus.h @@ -0,0 +1,389 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef __ETL_MESSAGE_BUS_ +#define __ETL_MESSAGE_BUS_ + +#include +#include + +#include "algorithm.h" +#include "vector.h" +#include "nullptr.h" +#include "error_handler.h" +#include "exception.h" +#include "message_types.h" +#include "message.h" +#include "message_router.h" + +#undef ETL_FILE +#define ETL_FILE "39" + +namespace etl +{ + //*************************************************************************** + /// Base exception class for message bus + //*************************************************************************** + class message_bus_exception : public etl::exception + { + public: + + message_bus_exception(string_type what, string_type file_name, numeric_type line_number) + : etl::exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Too many subscribers. + //*************************************************************************** + class message_bus_too_many_subscribers : public etl::message_bus_exception + { + public: + + message_bus_too_many_subscribers(string_type file_name, numeric_type line_number) + : message_bus_exception(ETL_ERROR_TEXT("message bus:too many subscribers", ETL_FILE"A"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Interface for message bus + //*************************************************************************** + class imessage_bus : public etl::imessage_router + { + private: + + typedef etl::ivector router_list_t; + + public: + + using etl::imessage_router::receive; + + //******************************************* + /// Subscribe to the bus. + //******************************************* + bool subscribe(etl::imessage_router& router) + { + bool ok = true; + + // There's no point actually adding null routers. + if (router.get_message_router_id() != etl::imessage_router::NULL_MESSAGE_ROUTER) + { + ok = !router_list.full(); + + ETL_ASSERT(ok, ETL_ERROR(etl::message_bus_too_many_subscribers)); + + if (ok) + { + if (router.get_message_router_id() == etl::imessage_router::MESSAGE_BUS) + { + // Message busses get added to the end. + router_list.push_back(&router); + } + else + { + // Routers get added in id order. + router_list_t::iterator irouter = std::upper_bound(router_list.begin(), + router_list.end(), + router.get_message_router_id(), + compare_router_id()); + + router_list.insert(irouter, &router); + } + } + } + + return ok; + } + + //******************************************* + /// Unsubscribe from the bus. + //******************************************* + void unsubscribe(etl::message_router_id_t id) + { + if (id == etl::imessage_bus::ALL_MESSAGE_ROUTERS) + { + clear(); + } + else + { + std::pair range = std::equal_range(router_list.begin(), + router_list.end(), + id, + compare_router_id()); + + router_list.erase(range.first, range.second); + } + } + + //******************************************* + void unsubscribe(etl::imessage_router& router) + { + router_list_t::iterator irouter = std::find(router_list.begin(), + router_list.end(), + &router); + + if (irouter != router_list.end()) + { + router_list.erase(irouter); + } + } + + //******************************************* + void receive(const etl::imessage& message) + { + etl::null_message_router nmr; + receive(nmr, etl::imessage_router::ALL_MESSAGE_ROUTERS, message); + } + + //******************************************* + void receive(etl::message_router_id_t destination_router_id, + const etl::imessage& message) + { + etl::null_message_router nmr; + receive(nmr, destination_router_id, message); + } + + //******************************************* + void receive(etl::imessage_router& source, + const etl::imessage& message) + { + receive(source, etl::imessage_router::ALL_MESSAGE_ROUTERS, message); + } + + //******************************************* + void receive(etl::imessage_router& source, + etl::message_router_id_t destination_router_id, + const etl::imessage& message) + { + switch (destination_router_id) + { + //***************************** + // Null message router. These routers can never be subscribed. + case etl::imessage_router::NULL_MESSAGE_ROUTER: + { + break; + } + + //***************************** + // Broadcast to all routers. + case etl::imessage_router::ALL_MESSAGE_ROUTERS: + { + router_list_t::iterator irouter = router_list.begin(); + + // Broadcast to everyone. + while (irouter != router_list.end()) + { + etl::imessage_router& router = **irouter; + + if (router.get_message_router_id() == etl::imessage_router::MESSAGE_BUS) + { + // The router is actually a bus. + etl::imessage_bus& bus = static_cast(router); + + // So pass it on. + bus.receive(source, destination_router_id, message); + } + else if (router.accepts(message.get_message_id())) + { + router.receive(source, message); + } + + ++irouter; + } + + break; + } + + //***************************** + // Must be an addressed message. + default: + { + router_list_t::iterator irouter = router_list.begin(); + + // Find routers with the id. + std::pair range = std::equal_range(router_list.begin(), + router_list.end(), + destination_router_id, + compare_router_id()); + + // Call all of them. + while (range.first != range.second) + { + if ((*(range.first))->accepts(message.get_message_id())) + { + (*(range.first))->receive(source, message); + } + + ++range.first; + } + + // Do any message buses. + // These are always at the end of the list. + irouter = std::lower_bound(router_list.begin(), + router_list.end(), + etl::imessage_bus::MESSAGE_BUS, + compare_router_id()); + + while (irouter != router_list.end()) + { + // The router is actually a bus. + etl::imessage_bus& bus = static_cast(**irouter); + + // So pass it on. + bus.receive(source, destination_router_id, message); + + ++irouter; + } + + break; + } + } + } + + using imessage_router::accepts; + + //******************************************* + /// Does this message bus accept the message id? + /// Yes!, it accepts everything! + //******************************************* + bool accepts(etl::message_id_t id) const + { + return true; + } + + //******************************************* + size_t size() const + { + return router_list.size(); + } + + //******************************************* + void clear() + { + return router_list.clear(); + } + + protected: + + //******************************************* + /// Constructor. + //******************************************* + imessage_bus(router_list_t& list) + : imessage_router(etl::imessage_router::MESSAGE_BUS), + router_list(list) + { + } + + private: + + //******************************************* + // How to compare routers to router ids. + //******************************************* + struct compare_router_id + { + bool operator()(const etl::imessage_router* prouter, etl::message_router_id_t id) const + { + return prouter->get_message_router_id() < id; + } + + bool operator()(etl::message_router_id_t id, const etl::imessage_router* prouter) const + { + return id < prouter->get_message_router_id(); + } + }; + + router_list_t& router_list; + }; + + //*************************************************************************** + /// The message bus + //*************************************************************************** + template + class message_bus : public etl::imessage_bus + { + public: + + //******************************************* + /// Constructor. + //******************************************* + message_bus() + : imessage_bus(router_list) + { + } + + private: + + etl::vector router_list; + }; + + //*************************************************************************** + /// Send a message to a bus. + //*************************************************************************** + inline static void send_message(etl::imessage_bus& bus, + const etl::imessage& message) + { + bus.receive(message); + } + + //*************************************************************************** + /// Send a message to a bus. + //*************************************************************************** + inline static void send_message(etl::imessage_bus& bus, + etl::message_router_id_t id, + const etl::imessage& message) + { + bus.receive(id, message); + } + + //*************************************************************************** + /// Send a message to a bus. + //*************************************************************************** + inline static void send_message(etl::imessage_router& source, + etl::imessage_bus& bus, + const etl::imessage& message) + { + bus.receive(source, message); + } + + //*************************************************************************** + /// Send a message to a bus. + //*************************************************************************** + inline static void send_message(etl::imessage_router& source, + etl::imessage_bus& bus, + etl::message_router_id_t id, + const etl::imessage& message) + { + bus.receive(source, id, message); + } +} + +#undef ETL_FILE + +#endif diff --git a/src/message_router.h b/src/message_router.h new file mode 100644 index 00000000..c024391b --- /dev/null +++ b/src/message_router.h @@ -0,0 +1,2200 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#if 0 +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +#endif + +//*************************************************************************** +// This file has been auto generated. Do not edit this file. +//*************************************************************************** + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -omessage_router.h -DHandlers= message_router_generator.h +// Where is the number of messages to support. +// +// e.g. +// To generate handlers for up to 16 messages... +// python -m cogapp -d -e -omessage_router.h -DHandlers=16 message_router_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_MESSAGE_ROUTER__ +#define __ETL_MESSAGE_ROUTER__ + +#include + +#include "message.h" +#include "message_types.h" +#include "alignment.h" +#include "error_handler.h" +#include "exception.h" +#include "largest.h" + +#undef ETL_FILE +#define ETL_FILE "35" + +namespace etl +{ + //*************************************************************************** + /// Base exception class for message router + //*************************************************************************** + class message_router_exception : public etl::exception + { + public: + + message_router_exception(string_type what, string_type file_name, numeric_type line_number) + : etl::exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Router id is out of the legal range. + //*************************************************************************** + class message_router_illegal_id : public etl::message_router_exception + { + public: + + message_router_illegal_id(string_type file_name, numeric_type line_number) + : message_router_exception(ETL_ERROR_TEXT("message router:illegal id", ETL_FILE"A"), file_name, line_number) + { + } + }; + + //*************************************************************************** + class imessage_router + { + public: + + virtual ~imessage_router() {} + virtual void receive(const etl::imessage& message) = 0; + virtual void receive(imessage_router& source, const etl::imessage& message) = 0; + virtual bool accepts(etl::message_id_t id) const = 0; + + //******************************************** + bool accepts(const etl::imessage& msg) const + { + return accepts(msg.get_message_id()); + } + + //******************************************** + etl::message_router_id_t get_message_router_id() const + { + return message_router_id; + } + + enum + { + NULL_MESSAGE_ROUTER = 255, + MESSAGE_BUS = 254, + ALL_MESSAGE_ROUTERS = 253, + MAX_MESSAGE_ROUTER = 249 + }; + + protected: + + imessage_router(etl::message_router_id_t id) + : message_router_id(id) + { + } + + private: + + // Disabled. + imessage_router(const imessage_router&); + imessage_router& operator =(const imessage_router&); + + etl::message_router_id_t message_router_id; + }; + + //*************************************************************************** + /// This router can be used either as a sink for messages + /// or as a producer-only of messages such an interrupt routine. + //*************************************************************************** + class null_message_router : public imessage_router + { + public: + + null_message_router() + : imessage_router(imessage_router::NULL_MESSAGE_ROUTER) + { + } + + //******************************************** + void receive(const etl::imessage& message) + { + } + + //******************************************** + void receive(etl::imessage_router& source, const etl::imessage& message) + { + } + + //******************************************** + bool accepts(etl::message_id_t id) const + { + return false; + } + + //******************************************** + static null_message_router& instance() + { + static null_message_router nmr; + return nmr; + } + }; + + //*************************************************************************** + /// Send a message to a router. + /// Sets the 'sender' to etl::null_message_router type. + //*************************************************************************** + inline static void send_message(etl::imessage_router& destination, + const etl::imessage& message) + { + destination.receive(message); + } + + //*************************************************************************** + /// Send a message to a router. + //*************************************************************************** + inline static void send_message(etl::imessage_router& source, + etl::imessage_router& destination, + const etl::imessage& message) + { + destination.receive(source, message); + } + + //*************************************************************************** + // The definition for all 16 message types. + //*************************************************************************** + template + class message_router : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + case T6::ID: ::new (p) T6(static_cast(msg)); break; + case T7::ID: ::new (p) T7(static_cast(msg)); break; + case T8::ID: ::new (p) T8(static_cast(msg)); break; + case T9::ID: ::new (p) T9(static_cast(msg)); break; + case T10::ID: ::new (p) T10(static_cast(msg)); break; + case T11::ID: ::new (p) T11(static_cast(msg)); break; + case T12::ID: ::new (p) T12(static_cast(msg)); break; + case T13::ID: ::new (p) T13(static_cast(msg)); break; + case T14::ID: ::new (p) T14(static_cast(msg)); break; + case T15::ID: ::new (p) T15(static_cast(msg)); break; + case T16::ID: ::new (p) T16(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const etl::message_id_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T12::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T13::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T14::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T15::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T16::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: case T14::ID: case T15::ID: case T16::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 15 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + case T6::ID: ::new (p) T6(static_cast(msg)); break; + case T7::ID: ::new (p) T7(static_cast(msg)); break; + case T8::ID: ::new (p) T8(static_cast(msg)); break; + case T9::ID: ::new (p) T9(static_cast(msg)); break; + case T10::ID: ::new (p) T10(static_cast(msg)); break; + case T11::ID: ::new (p) T11(static_cast(msg)); break; + case T12::ID: ::new (p) T12(static_cast(msg)); break; + case T13::ID: ::new (p) T13(static_cast(msg)); break; + case T14::ID: ::new (p) T14(static_cast(msg)); break; + case T15::ID: ::new (p) T15(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T12::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T13::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T14::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T15::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: case T14::ID: case T15::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 14 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + case T6::ID: ::new (p) T6(static_cast(msg)); break; + case T7::ID: ::new (p) T7(static_cast(msg)); break; + case T8::ID: ::new (p) T8(static_cast(msg)); break; + case T9::ID: ::new (p) T9(static_cast(msg)); break; + case T10::ID: ::new (p) T10(static_cast(msg)); break; + case T11::ID: ::new (p) T11(static_cast(msg)); break; + case T12::ID: ::new (p) T12(static_cast(msg)); break; + case T13::ID: ::new (p) T13(static_cast(msg)); break; + case T14::ID: ::new (p) T14(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T12::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T13::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T14::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: case T14::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 13 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + case T6::ID: ::new (p) T6(static_cast(msg)); break; + case T7::ID: ::new (p) T7(static_cast(msg)); break; + case T8::ID: ::new (p) T8(static_cast(msg)); break; + case T9::ID: ::new (p) T9(static_cast(msg)); break; + case T10::ID: ::new (p) T10(static_cast(msg)); break; + case T11::ID: ::new (p) T11(static_cast(msg)); break; + case T12::ID: ::new (p) T12(static_cast(msg)); break; + case T13::ID: ::new (p) T13(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T12::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T13::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 12 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + case T6::ID: ::new (p) T6(static_cast(msg)); break; + case T7::ID: ::new (p) T7(static_cast(msg)); break; + case T8::ID: ::new (p) T8(static_cast(msg)); break; + case T9::ID: ::new (p) T9(static_cast(msg)); break; + case T10::ID: ::new (p) T10(static_cast(msg)); break; + case T11::ID: ::new (p) T11(static_cast(msg)); break; + case T12::ID: ::new (p) T12(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T12::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 11 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + case T6::ID: ::new (p) T6(static_cast(msg)); break; + case T7::ID: ::new (p) T7(static_cast(msg)); break; + case T8::ID: ::new (p) T8(static_cast(msg)); break; + case T9::ID: ::new (p) T9(static_cast(msg)); break; + case T10::ID: ::new (p) T10(static_cast(msg)); break; + case T11::ID: ::new (p) T11(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 10 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + case T6::ID: ::new (p) T6(static_cast(msg)); break; + case T7::ID: ::new (p) T7(static_cast(msg)); break; + case T8::ID: ::new (p) T8(static_cast(msg)); break; + case T9::ID: ::new (p) T9(static_cast(msg)); break; + case T10::ID: ::new (p) T10(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 9 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + case T6::ID: ::new (p) T6(static_cast(msg)); break; + case T7::ID: ::new (p) T7(static_cast(msg)); break; + case T8::ID: ::new (p) T8(static_cast(msg)); break; + case T9::ID: ::new (p) T9(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 8 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + case T6::ID: ::new (p) T6(static_cast(msg)); break; + case T7::ID: ::new (p) T7(static_cast(msg)); break; + case T8::ID: ::new (p) T8(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 7 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + case T6::ID: ::new (p) T6(static_cast(msg)); break; + case T7::ID: ::new (p) T7(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 6 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + case T6::ID: ::new (p) T6(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 5 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + case T5::ID: ::new (p) T5(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 4 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + case T4::ID: ::new (p) T4(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 3 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + case T3::ID: ::new (p) T3(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 2 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + case T2::ID: ::new (p) T2(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 1 message type. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + //********************************************** + class message_packet + { + public: + + //******************************************** + explicit message_packet(const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + void* p = data; + + switch (id) + { + case T1::ID: ::new (p) T1(static_cast(msg)); break; + default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break; + } + } + + //******************************************** + template + explicit message_packet(const T& msg) + { + STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet"); + + void* p = data; + ::new (p) T(static_cast(msg)); + } + + //******************************************** + ~message_packet() + { + static_cast(data)->~imessage(); + } + + //******************************************** + etl::imessage& get() + { + return *static_cast(data); + } + + //******************************************** + const etl::imessage& get() const + { + return *static_cast(data); + } + + enum + { + SIZE = etl::largest::size, + ALIGNMENT = etl::largest::alignment + }; + + private: + + typename etl::aligned_storage::type data; + }; + + //********************************************** + message_router(etl::message_router_id_t id) + : imessage_router(id) + { + ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::instance(), msg); + } + + //********************************************** + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + using imessage_router::accepts; + + //********************************************** + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: + return true; break; + default: + return false; break; + } + } + }; +} + +#undef ETL_FILE + +#endif diff --git a/src/message_router_generator.h b/src/message_router_generator.h new file mode 100644 index 00000000..cf1c3685 --- /dev/null +++ b/src/message_router_generator.h @@ -0,0 +1,514 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +/*[[[cog +import cog +cog.outl("#if 0") +]]]*/ +/*[[[end]]]*/ +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +/*[[[cog +import cog +cog.outl("#endif") +]]]*/ +/*[[[end]]]*/ + +/*[[[cog +import cog +cog.outl("//***************************************************************************") +cog.outl("// This file has been auto generated. Do not edit this file.") +cog.outl("//***************************************************************************") +]]]*/ +/*[[[end]]]*/ + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -omessage_router.h -DHandlers= message_router_generator.h +// Where is the number of messages to support. +// +// e.g. +// To generate handlers for up to 16 messages... +// python -m cogapp -d -e -omessage_router.h -DHandlers=16 message_router_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_MESSAGE_ROUTER__ +#define __ETL_MESSAGE_ROUTER__ + +#include + +#include "message.h" +#include "message_types.h" +#include "alignment.h" +#include "error_handler.h" +#include "exception.h" +#include "largest.h" + +#undef ETL_FILE +#define ETL_FILE "35" + +namespace etl +{ + //*************************************************************************** + /// Base exception class for message router + //*************************************************************************** + class message_router_exception : public etl::exception + { + public: + + message_router_exception(string_type what, string_type file_name, numeric_type line_number) + : etl::exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Router id is out of the legal range. + //*************************************************************************** + class message_router_illegal_id : public etl::message_router_exception + { + public: + + message_router_illegal_id(string_type file_name, numeric_type line_number) + : message_router_exception(ETL_ERROR_TEXT("message router:illegal id", ETL_FILE"A"), file_name, line_number) + { + } + }; + + //*************************************************************************** + class imessage_router + { + public: + + virtual ~imessage_router() {} + virtual void receive(const etl::imessage& message) = 0; + virtual void receive(imessage_router& source, const etl::imessage& message) = 0; + virtual bool accepts(etl::message_id_t id) const = 0; + + //******************************************** + bool accepts(const etl::imessage& msg) const + { + return accepts(msg.get_message_id()); + } + + //******************************************** + etl::message_router_id_t get_message_router_id() const + { + return message_router_id; + } + + enum + { + NULL_MESSAGE_ROUTER = 255, + MESSAGE_BUS = 254, + ALL_MESSAGE_ROUTERS = 253, + MAX_MESSAGE_ROUTER = 249 + }; + + protected: + + imessage_router(etl::message_router_id_t id) + : message_router_id(id) + { + } + + private: + + // Disabled. + imessage_router(const imessage_router&); + imessage_router& operator =(const imessage_router&); + + etl::message_router_id_t message_router_id; + }; + + //*************************************************************************** + /// This router can be used either as a sink for messages + /// or as a producer-only of messages such an interrupt routine. + //*************************************************************************** + class null_message_router : public imessage_router + { + public: + + null_message_router() + : imessage_router(imessage_router::NULL_MESSAGE_ROUTER) + { + } + + //******************************************** + void receive(const etl::imessage& message) + { + } + + //******************************************** + void receive(etl::imessage_router& source, const etl::imessage& message) + { + } + + //******************************************** + bool accepts(etl::message_id_t id) const + { + return false; + } + + //******************************************** + static null_message_router& instance() + { + static null_message_router nmr; + return nmr; + } + }; + + //*************************************************************************** + /// Send a message to a router. + /// Sets the 'sender' to etl::null_message_router type. + //*************************************************************************** + inline static void send_message(etl::imessage_router& destination, + const etl::imessage& message) + { + destination.receive(message); + } + + //*************************************************************************** + /// Send a message to a router. + //*************************************************************************** + inline static void send_message(etl::imessage_router& source, + etl::imessage_router& destination, + const etl::imessage& message) + { + destination.receive(source, message); + } + + /*[[[cog + import cog + ################################################ + # The first definition for all of the messages. + ################################################ + cog.outl("//***************************************************************************") + cog.outl("// The definition for all %s message types." % Handlers) + cog.outl("//***************************************************************************") + cog.outl("template " % int(Handlers)) + cog.out("class message_router") + cog.outl(" : public imessage_router") + cog.outl("{") + cog.outl("public:") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" class message_packet") + cog.outl(" {") + cog.outl(" public:") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" explicit message_packet(const etl::imessage& msg)") + cog.outl(" {") + cog.outl(" const size_t id = msg.get_message_id();") + cog.outl("") + cog.outl(" void* p = data;") + cog.outl("") + cog.outl(" switch (id)") + cog.outl(" {") + for n in range(1, int(Handlers) + 1): + cog.outl(" case T%s::ID: ::new (p) T%s(static_cast(msg)); break;" % (n, n, n)) + cog.outl(" default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;") + cog.outl(" }") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" template ") + cog.outl(" explicit message_packet(const T& msg)") + cog.outl(" {") + cog.out(" STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet");""" % int(Handlers)) + cog.outl("") + cog.outl(" void* p = data;") + cog.outl(" ::new (p) T(static_cast(msg));") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" ~message_packet()") + cog.outl(" {") + cog.outl(" static_cast(data)->~imessage();") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" etl::imessage& get()") + cog.outl(" {") + cog.outl(" return *static_cast(data);") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" const etl::imessage& get() const") + cog.outl(" {") + cog.outl(" return *static_cast(data);") + cog.outl(" }") + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.out(" SIZE = etl::largest<") + for n in range(1, int(Handlers)): + cog.out("T%s, " % n) + cog.outl("T%s>::size," % int(Handlers)) + cog.out(" ALIGNMENT = etl::largest<") + for n in range(1, int(Handlers)): + cog.out("T%s, " % n) + cog.outl("T%s>::alignment" % int(Handlers)) + cog.outl(" };") + cog.outl("") + cog.outl(" private:") + cog.outl("") + cog.outl(" typename etl::aligned_storage::type data;") + cog.outl(" };") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" message_router(etl::message_router_id_t id)") + cog.outl(" : imessage_router(id)") + cog.outl(" {") + cog.outl(" ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));") + cog.outl(" }") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" void receive(const etl::imessage& msg)") + cog.outl(" {") + cog.outl(" receive(etl::null_message_router::instance(), msg);") + cog.outl(" }") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" void receive(etl::imessage_router& source, const etl::imessage& msg)") + cog.outl(" {") + cog.outl(" const etl::message_id_t id = msg.get_message_id();") + cog.outl("") + cog.outl(" switch (id)") + cog.outl(" {") + for n in range(1, int(Handlers) + 1): + cog.out(" case T%d::ID:" % n) + cog.out(" static_cast(this)->on_receive(source, static_cast(msg));" % n) + cog.outl(" break;") + cog.out(" default:") + cog.out(" static_cast(this)->on_receive_unknown(source, msg);") + cog.outl(" break;") + cog.outl(" }") + cog.outl(" }") + cog.outl("") + cog.outl(" using imessage_router::accepts;") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" bool accepts(etl::message_id_t id) const") + cog.outl(" {") + cog.outl(" switch (id)") + cog.outl(" {") + cog.out(" ") + for n in range(1, int(Handlers) + 1): + cog.out("case T%d::ID: " % n) + if n % 8 == 0: + cog.outl("") + cog.out(" ") + cog.outl(" return true; break;") + cog.outl(" default:") + cog.outl(" return false; break;") + cog.outl(" }") + cog.outl(" }") + cog.outl("};") + + #################################### + # All of the other specialisations. + #################################### + for n in range(int(Handlers) - 1, 0, -1): + cog.outl("") + cog.outl("//***************************************************************************") + if n == 1: + cog.outl("// Specialisation for %d message type." % n) + else: + cog.outl("// Specialisation for %d message types." % n) + cog.outl("//***************************************************************************") + cog.outl("template " % n) + cog.out("class message_router") + cog.outl(" : public imessage_router") + cog.outl("{") + cog.outl("public:") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" class message_packet") + cog.outl(" {") + cog.outl(" public:") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" explicit message_packet(const etl::imessage& msg)") + cog.outl(" {") + cog.outl(" const size_t id = msg.get_message_id();") + cog.outl("") + cog.outl(" void* p = data;") + cog.outl("") + cog.outl(" switch (id)") + cog.outl(" {") + for t in range(1, n + 1): + cog.outl(" case T%s::ID: ::new (p) T%s(static_cast(msg)); break;" % (t, t, t)) + cog.outl(" default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;") + cog.outl(" }") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" template ") + cog.outl(" explicit message_packet(const T& msg)") + cog.outl(" {") + cog.out(" STATIC_ASSERT((etl::is_one_of::value), "Unsupported type for this message packet");""" % n) + cog.outl("") + cog.outl(" void* p = data;") + cog.outl(" ::new (p) T(static_cast(msg));") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" ~message_packet()") + cog.outl(" {") + cog.outl(" static_cast(data)->~imessage();") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" etl::imessage& get()") + cog.outl(" {") + cog.outl(" return *static_cast(data);") + cog.outl(" }") + cog.outl("") + cog.outl(" //********************************************") + cog.outl(" const etl::imessage& get() const") + cog.outl(" {") + cog.outl(" return *static_cast(data);") + cog.outl(" }") + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.out(" SIZE = etl::largest<") + for t in range(1, n): + cog.out("T%s, " % t) + cog.outl("T%s>::size," % n) + cog.out(" ALIGNMENT = etl::largest<") + for t in range(1, n): + cog.out("T%s, " % t) + cog.outl("T%s>::alignment" % n) + cog.outl(" };") + cog.outl("") + cog.outl(" private:") + cog.outl("") + cog.outl(" typename etl::aligned_storage::type data;") + cog.outl(" };") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" message_router(etl::message_router_id_t id)") + cog.outl(" : imessage_router(id)") + cog.outl(" {") + cog.outl(" ETL_ASSERT(id <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));") + cog.outl(" }") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" void receive(const etl::imessage& msg)") + cog.outl(" {") + cog.outl(" receive(etl::null_message_router::instance(), msg);") + cog.outl(" }") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" void receive(etl::imessage_router& source, const etl::imessage& msg)") + cog.outl(" {") + cog.outl(" const size_t id = msg.get_message_id();") + cog.outl("") + cog.outl(" switch (id)") + cog.outl(" {") + for t in range(1, n + 1): + cog.out(" case T%d::ID:" % t) + cog.out(" static_cast(this)->on_receive(source, static_cast(msg));" % t) + cog.outl(" break;") + cog.out(" default:") + cog.out(" static_cast(this)->on_receive_unknown(source, msg);") + cog.outl(" break;") + cog.outl(" }") + cog.outl(" }") + cog.outl("") + cog.outl(" using imessage_router::accepts;") + cog.outl("") + cog.outl(" //**********************************************") + cog.outl(" bool accepts(etl::message_id_t id) const") + cog.outl(" {") + cog.outl(" switch (id)") + cog.outl(" {") + cog.out(" ") + for t in range(1, n + 1): + cog.out("case T%d::ID: " % t) + if t % 8 == 0: + cog.outl("") + cog.out(" ") + cog.outl("") + cog.outl(" return true; break;") + cog.outl(" default:") + cog.outl(" return false; break;") + cog.outl(" }") + cog.outl(" }") + cog.outl("};") + ]]]*/ + /*[[[end]]]*/ +} + +#undef ETL_FILE + +#endif diff --git a/src/message_types.h b/src/message_types.h new file mode 100644 index 00000000..a049dae9 --- /dev/null +++ b/src/message_types.h @@ -0,0 +1,46 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef __ETL_MESSAGE_DEFS__ +#define __ETL_MESSAGE_DEFS__ + +#include + +namespace etl +{ + /// Allow alternative type for message id. +#if !defined(ETL_MESSAGE_ID_TYPE) + typedef uint_least8_t message_id_t; +#else + typedef ETL_MESSAGE_ID_TYPE message_id_t; +#endif + + typedef uint_least8_t message_router_id_t; +} + +#endif diff --git a/src/packet.h b/src/packet.h new file mode 100644 index 00000000..ef0e2d79 --- /dev/null +++ b/src/packet.h @@ -0,0 +1,128 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef __ETL_PACKET__ +#define __ETL_PACKET__ + +#include "platform.h" +#include "static_assert.h" +#include "alignment.h" + +#undef ETL_FILE +#define ETL_FILE "38" + +//***************************************************************************** +///\defgroup packet packet +/// A class that can contain one a several related types. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// A template class that can store any types derived from TBase that conform + /// to the size and alignment requirements. + ///\ingroup packet + //*************************************************************************** + template + class packet + { + public: + + //*************************************************************************** + /// Constructor that static asserts any types that do not conform to the max size and alignment. + //*************************************************************************** + template + explicit packet(const T& value) + { + STATIC_ASSERT((etl::is_base_of::value), "Unsupported type"); + STATIC_ASSERT(sizeof(T) <= SIZE, "Unsupported size"); + STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT, "Unsupported alignment"); + + ::new (static_cast(data)) T(value); + } + + //*************************************************************************** + /// Destructor + //*************************************************************************** + ~packet() + { + static_cast(data)->~TBase(); + } + + //*************************************************************************** + /// Assignment operator for type. + ///\param value The value to assign. + //*************************************************************************** + template + packet& operator =(const T& value) + { + STATIC_ASSERT((etl::is_base_of::value), "Unsupported type"); + STATIC_ASSERT(sizeof(T) <= SIZE, "Unsupported size"); + STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT, "Unsupported alignment"); + + static_cast(data)->~TBase(); + ::new (static_cast(data)) T(value); + + return *this; + } + + //*************************************************************************** + /// Get access to the contained object. + //*************************************************************************** + TBase& get() + { + return *static_cast(data); + } + + //*************************************************************************** + /// Get access to the contained object. + //*************************************************************************** + const TBase& get() const + { + return *static_cast(data); + } + + private: + + packet(const packet& other); + packet& operator =(const packet& other); + + //*************************************************************************** + /// The internal storage. + /// Aligned on a suitable boundary, which should be good for all types. + //*************************************************************************** + typename etl::aligned_storage::type data; + }; +} + +#undef ETL_FILE + +#endif diff --git a/src/scheduler.h b/src/scheduler.h new file mode 100644 index 00000000..388b0a8c --- /dev/null +++ b/src/scheduler.h @@ -0,0 +1,410 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef __ETL_SCHEDULER__ +#define __ETL_SCHEDULER__ + +#include + +#include "vector.h" +#include "nullptr.h" +#include "error_handler.h" +#include "exception.h" +#include "task.h" +#include "type_traits.h" +#include "function.h" + +#undef ETL_FILE +#define ETL_FILE "36" + +namespace etl +{ + //*************************************************************************** + /// Base exception class for scheduler. + //*************************************************************************** + class scheduler_exception : public etl::exception + { + public: + + scheduler_exception(string_type what, string_type file_name, numeric_type line_number) + : etl::exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + /// 'No tasks' exception. + //*************************************************************************** + class scheduler_no_tasks_exception : public etl::scheduler_exception + { + public: + + scheduler_no_tasks_exception(string_type file_name, numeric_type line_number) + : etl::scheduler_exception(ETL_ERROR_TEXT("scheduler:no tasks", ETL_FILE"A"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// 'Null tasks' exception. + //*************************************************************************** + class scheduler_null_task_exception : public etl::scheduler_exception + { + public: + + scheduler_null_task_exception(string_type file_name, numeric_type line_number) + : etl::scheduler_exception(ETL_ERROR_TEXT("scheduler:null task", ETL_FILE"B"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// 'Too many tasks' exception. + //*************************************************************************** + class scheduler_too_many_tasks_exception : public etl::scheduler_exception + { + public: + + scheduler_too_many_tasks_exception(string_type file_name, numeric_type line_number) + : etl::scheduler_exception(ETL_ERROR_TEXT("scheduler:too many tasks", ETL_FILE"C"), file_name, line_number) + { + } + }; + + //*************************************************************************** + /// Sequencial Single. + /// A policy the scheduler can use to decide what to do next. + /// Only calls the task to process work once, if it has work to do. + //*************************************************************************** + struct scheduler_policy_sequencial_single + { + bool schedule_tasks(etl::ivector& task_list) + { + bool idle = true; + + for (size_t index = 0; index < task_list.size(); ++index) + { + etl::task& task = *(task_list[index]); + + if (task.task_request_work() > 0) + { + task.task_process_work(); + idle = false; + } + } + + return idle; + } + }; + + //*************************************************************************** + /// Sequencial Multiple. + /// A policy the scheduler can use to decide what to do next. + /// Calls the task to process work until it reports that it has no more. + //*************************************************************************** + struct scheduler_policy_sequencial_multiple + { + bool schedule_tasks(etl::ivector& task_list) + { + bool idle = true; + + for (size_t index = 0; index < task_list.size(); ++index) + { + etl::task& task = *(task_list[index]); + + while (task.task_request_work() > 0) + { + task.task_process_work(); + idle = false; + } + } + + return idle; + } + }; + + //*************************************************************************** + /// Highest Priority. + /// A policy the scheduler can use to decide what to do next. + /// Calls the highest priority task that has work. + //*************************************************************************** + struct scheduler_policy_highest_priority + { + bool schedule_tasks(etl::ivector& task_list) + { + bool idle = true; + + size_t index = 0; + while (index < task_list.size()) + { + etl::task& task = *(task_list[index]); + + if (task.task_request_work() > 0) + { + task.task_process_work(); + idle = false; + break; + } + else + { + ++index; + } + } + + return idle; + } + }; + + //*************************************************************************** + /// Most Work. + /// A policy the scheduler can use to decide what to do next. + /// Calls the task that has the most work. + /// Starts looking from the task with the highest priority. + //*************************************************************************** + struct scheduler_policy_most_work + { + bool schedule_tasks(etl::ivector& task_list) + { + bool idle = true; + + size_t most_index = 0; + uint_least8_t most_work = 0; + + for (size_t index = 0; index < task_list.size(); ++index) + { + etl::task& task = *(task_list[index]); + + uint_least8_t n_work = task.task_request_work(); + + if (n_work > most_work) + { + most_index = index; + most_work = n_work; + idle = false; + } + } + + if (!idle) + { + task_list[most_index]->task_process_work(); + } + + return idle; + } + }; + + //*************************************************************************** + /// Scheduler base. + //*************************************************************************** + class ischeduler + { + public: + + //******************************************* + // Virtuals. + //******************************************* + virtual void start() = 0; + + virtual ~ischeduler() + { + } + + //******************************************* + /// Set the idle callback. + //******************************************* + void set_idle_callback(etl::ifunction& callback) + { + p_idle_callback = &callback; + } + + //******************************************* + /// Set the watchdog callback. + //******************************************* + void set_watchdog_callback(etl::ifunction& callback) + { + p_watchdog_callback = &callback; + } + + //******************************************* + /// Set the running state for the scheduler. + //******************************************* + void set_scheduler_running(bool scheduler_running_) + { + scheduler_running = scheduler_running_; + } + + //******************************************* + /// Get the running state for the scheduler. + //******************************************* + bool scheduler_is_running() const + { + return scheduler_running; + } + + //******************************************* + /// Force the scheduler to exit. + //******************************************* + void exit_scheduler() + { + scheduler_exit = true; + } + + //******************************************* + /// Add a task. + /// Add to the task list in priority order. + //******************************************* + void add_task(etl::task& task) + { + ETL_ASSERT(!task_list.full(), ETL_ERROR(etl::scheduler_too_many_tasks_exception)) + + if (!task_list.full()) + { + typename task_list_t::iterator itask = std::upper_bound(task_list.begin(), + task_list.end(), + task.get_task_priority(), + compare_priority()); + + task_list.insert(itask, &task); + } + } + + //******************************************* + /// Add a task list. + /// Adds to the tasks to the internal task list in priority order. + /// Input order is ignored. + //******************************************* + template + void add_task_list(etl::task** p_tasks, TSize size) + { + for (TSize i = 0; i < size; ++i) + { + ETL_ASSERT((p_tasks[i] != nullptr), ETL_ERROR(etl::scheduler_null_task_exception)); + add_task(*(p_tasks[i])); + } + } + + protected: + + //******************************************* + /// Constructor. + //******************************************* + ischeduler(etl::ivector& task_list_) + : scheduler_running(false), + scheduler_exit(false), + p_idle_callback(nullptr), + p_watchdog_callback(nullptr), + task_list(task_list_) + { + } + + bool scheduler_running; + bool scheduler_exit; + etl::ifunction* p_idle_callback; + etl::ifunction* p_watchdog_callback; + + private: + + //******************************************* + // Used to order tasks in descending priority. + //******************************************* + struct compare_priority + { + bool operator()(etl::task* ptask, etl::task_priority_t priority) const + { + return ptask->get_task_priority() > priority; + } + + bool operator()(etl::task_priority_t priority, etl::task* ptask) const + { + return priority > ptask->get_task_priority(); + } + }; + + typedef etl::ivector task_list_t; + task_list_t& task_list; + }; + + //*************************************************************************** + /// Scheduler. + //*************************************************************************** + template + class scheduler : public etl::ischeduler, protected TSchedulerPolicy + { + public: + + enum + { + MAX_TASKS = MAX_TASKS_, + }; + + scheduler() + : ischeduler(task_list) + { + } + + //******************************************* + /// Start the scheduler. SEQUENCIAL_SINGLE + /// Only calls the task to process work once, if it has work to do. + //******************************************* + void start() + { + ETL_ASSERT(task_list.size() > 0, ETL_ERROR(etl::scheduler_no_tasks_exception)); + + const size_t task_list_size = task_list.size(); + + scheduler_running = true; + + while (!scheduler_exit) + { + if (scheduler_running) + { + bool idle = TSchedulerPolicy::schedule_tasks(task_list); + + if (p_watchdog_callback) + { + (*p_watchdog_callback)(); + } + + if (idle && p_idle_callback) + { + (*p_idle_callback)(); + } + } + } + } + + private: + + typedef etl::vector task_list_t; + task_list_t task_list; + }; +} + +#undef ETL_FILE + +#endif diff --git a/src/smallest.h b/src/smallest.h index b9ac9e22..16a2ed7c 100644 --- a/src/smallest.h +++ b/src/smallest.h @@ -5,7 +5,7 @@ The MIT License(MIT) Embedded Template Library. https://github.com/ETLCPP/etl -http://www.etlcpp.com +https://www.etlcpp.com Copyright(c) 2014 jwellbelove @@ -28,6 +28,28 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************************/ +#if 0 +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +#endif + +//*************************************************************************** +// This file has been auto generated. Do not edit this file. +//*************************************************************************** + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -osmallest.h -DNTypes= smallest_generator.h +// Where is the number of types to support. +// +// e.g. +// To generate handlers for up to 16 types... +// python -m cogapp -d -e -osmallest.h -DNTypes=16 smallest_generator.h +// +// See generate.bat +//*************************************************************************** + #ifndef __ETL_SMALLEST__ #define __ETL_SMALLEST__ @@ -47,9 +69,9 @@ namespace etl /// Defines 'size' which is the size of the smallest parameter. ///\ingroup smallest //*************************************************************************** - template struct smallest_type { @@ -82,10 +104,10 @@ namespace etl // Set 'type' to be the smallest of the first parameter and any of the others. // This is recursive. - typedef typename choose_type<(sizeof(T1) < sizeof(smallest_other)),// Boolean - T1, // TrueType - smallest_other> // FalseType - ::type type; // The smallest type of the two. + typedef typename choose_type<(sizeof(T1) < sizeof(smallest_other)), // Boolean + T1, // TrueType + smallest_other> // FalseType + ::type type; // The smallest type of the two. // The size of the smallest type. enum @@ -98,10 +120,8 @@ namespace etl // Specialisation for one template parameter. //*************************************************************************** template - struct smallest_type + struct smallest_type { typedef T1 type; diff --git a/src/smallest_generator.h b/src/smallest_generator.h new file mode 100644 index 00000000..1c99c09c --- /dev/null +++ b/src/smallest_generator.h @@ -0,0 +1,336 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +/*[[[cog +import cog +cog.outl("#if 0") +]]]*/ +/*[[[end]]]*/ +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +/*[[[cog +import cog +cog.outl("#endif") +]]]*/ +/*[[[end]]]*/ + +/*[[[cog +import cog +cog.outl("//***************************************************************************") +cog.outl("// This file has been auto generated. Do not edit this file.") +cog.outl("//***************************************************************************") +]]]*/ +/*[[[end]]]*/ + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -osmallest.h -DNTypes= smallest_generator.h +// Where is the number of types to support. +// +// e.g. +// To generate handlers for up to 16 types... +// python -m cogapp -d -e -osmallest.h -DNTypes=16 smallest_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_SMALLEST__ +#define __ETL_SMALLEST__ + +#include + +#include "integral_limits.h" + +///\defgroup smallest smallest +///\ingroup utilities + +namespace etl +{ + /*[[[cog + import cog + cog.outl("//***************************************************************************") + cog.outl("/// Template to determine the smallest type and size.") + cog.outl("/// Supports up to %s types." % NTypes) + cog.outl("/// Defines 'value_type' which is the type of the smallest parameter.") + cog.outl("/// Defines 'size' which is the size of the smallest parameter.") + cog.outl("///\ingroup smallest") + cog.outl("//***************************************************************************") + cog.out("template " % int(NTypes)) + cog.outl("struct smallest_type") + cog.outl("{") + cog.outl("private:") + cog.outl("") + cog.outl(" // Declaration.") + cog.outl(" template ") + cog.outl(" struct choose_type;") + cog.outl("") + cog.outl(" // Specialisation for 'true'.") + cog.outl(" // Defines 'type' as 'TrueType'.") + cog.outl(" template ") + cog.outl(" struct choose_type") + cog.outl(" {") + cog.outl(" typedef TrueType type;") + cog.outl(" };") + cog.outl("") + cog.outl(" // Specialisation for 'false'. ") + cog.outl(" // Defines 'type' as 'FalseType'.") + cog.outl(" template ") + cog.outl(" struct choose_type") + cog.outl(" {") + cog.outl(" typedef FalseType type;") + cog.outl(" };") + cog.outl("") + cog.outl("public:") + cog.outl("") + cog.outl(" // Define 'smallest_other' as 'smallest_type' with all but the first parameter. ") + cog.out(" typedef typename smallest_type<") + for n in range(2, int(NTypes)): + cog.out("T%s, " % n) + if n % 16 == 0: + cog.outl("") + cog.out(" ") + cog.outl("T%s>::type smallest_other;" % int(NTypes)) + cog.outl("") + cog.outl(" // Set 'type' to be the smallest of the first parameter and any of the others.") + cog.outl(" // This is recursive.") + cog.outl(" typedef typename choose_type<(sizeof(T1) < sizeof(smallest_other)), // Boolean") + cog.outl(" T1, // TrueType") + cog.outl(" smallest_other> // FalseType") + cog.outl(" ::type type; // The smallest type of the two.") + cog.outl("") + cog.outl(" // The size of the smallest type.") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" size = sizeof(type)") + cog.outl(" };") + cog.outl("};") + cog.outl("") + cog.outl("//***************************************************************************") + cog.outl("// Specialisation for one template parameter.") + cog.outl("//***************************************************************************") + cog.outl("template ") + cog.out("struct smallest_type") + cog.outl("{") + cog.outl(" typedef T1 type;") + cog.outl("") + cog.outl(" enum") + cog.outl(" {") + cog.outl(" size = sizeof(type)") + cog.outl(" };") + cog.outl("};") + ]]]*/ + /*[[[end]]]*/ + + namespace __private_smallest__ + { + //************************************************************************* + // Determine the type to hold the number of bits based on the index. + //************************************************************************* + template + struct best_fit_uint_type; + + //************************************************************************* + // Less than or equal to 8 bits. + //************************************************************************* + template <> + struct best_fit_uint_type<0> + { + typedef uint_least8_t type; + }; + + //************************************************************************* + // 9 to 16 bits. + //************************************************************************* + template <> + struct best_fit_uint_type<1> + { + typedef uint_least16_t type; + }; + + //************************************************************************* + // 17 to 31 bits. + //************************************************************************* + template <> + struct best_fit_uint_type<2> + { + typedef uint_least32_t type; + }; + + //************************************************************************* + // Greater than 32 bits. + //************************************************************************* + template <> + struct best_fit_uint_type<3> + { + typedef uint_least64_t type; + }; + + //************************************************************************* + // Determine the type to hold the number of bits based on the index. + //************************************************************************* + template + struct best_fit_int_type; + + //************************************************************************* + // Less than or equal to 8 bits. + //************************************************************************* + template <> + struct best_fit_int_type<0> + { + typedef int_least8_t type; + }; + + //************************************************************************* + // 9 to 16 bits. + //************************************************************************* + template <> + struct best_fit_int_type<1> + { + typedef int_least16_t type; + }; + + //************************************************************************* + // 17 to 31 bits. + //************************************************************************* + template <> + struct best_fit_int_type<2> + { + typedef int_least32_t type; + }; + + //************************************************************************* + // Greater than 32 bits. + //************************************************************************* + template <> + struct best_fit_int_type<3> + { + typedef int_least64_t type; + }; + } + + //*************************************************************************** + /// Template to determine the smallest unsigned int type that can contain a + /// value with the specified number of bits. + /// Defines 'type' which is the type of the smallest unsigned integer. + ///\ingroup smallest + //*************************************************************************** + template + struct smallest_uint_for_bits + { + private: + + // Determines the index of the best unsigned type for the required number of bits. + static const int TYPE_INDEX = ((NBITS > 8) ? 1 : 0) + + ((NBITS > 16) ? 1 : 0) + + ((NBITS > 32) ? 1 : 0); + + public: + + typedef typename __private_smallest__::best_fit_uint_type::type type; + }; + + //*************************************************************************** + /// Template to determine the smallest signed int type that can contain a + /// value with the specified number of bits. + /// Defines 'type' which is the type of the smallest signed integer. + ///\ingroup smallest + //*************************************************************************** + template + struct smallest_int_for_bits + { + private: + + // Determines the index of the best unsigned type for the required number of bits. + static const int TYPE_INDEX = ((NBITS > 8) ? 1 : 0) + + ((NBITS > 16) ? 1 : 0) + + ((NBITS > 32) ? 1 : 0); + + public: + + typedef typename __private_smallest__::best_fit_int_type::type type; + }; + + //*************************************************************************** + /// Template to determine the smallest unsigned int type that can contain the + /// specified unsigned value. + /// Defines 'type' which is the type of the smallest unsigned integer. + ///\ingroup smallest + //*************************************************************************** + template + struct smallest_uint_for_value + { + private: + + // Determines the index of the best unsigned type for the required value. + static const int TYPE_INDEX = ((VALUE > UINT_LEAST8_MAX) ? 1 : 0) + + ((VALUE > UINT16_MAX) ? 1 : 0) + + ((VALUE > UINT32_MAX) ? 1 : 0); + + public: + + typedef typename __private_smallest__::best_fit_uint_type::type type; + }; + + //*************************************************************************** + /// Template to determine the smallest int type that can contain the + /// specified signed value. + /// Defines 'type' which is the type of the smallest signed integer. + ///\ingroup smallest + //*************************************************************************** + template + struct smallest_int_for_value + { + private: + + // Determines the index of the best signed type for the required value. + static const int TYPE_INDEX = (((VALUE > INT_LEAST8_MAX) || (VALUE < INT_LEAST8_MIN)) ? 1 : 0) + + (((VALUE > INT16_MAX) || (VALUE < INT16_MIN)) ? 1 : 0) + + (((VALUE > INT32_MAX) || (VALUE < INT32_MIN)) ? 1 : 0); + + public: + + typedef typename __private_smallest__::best_fit_int_type::type type; + }; +} + +#endif diff --git a/src/task.h b/src/task.h new file mode 100644 index 00000000..dbe410f1 --- /dev/null +++ b/src/task.h @@ -0,0 +1,125 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef __ETL_TASK__ +#define __ETL_TASK__ + +#include + +#include "error_handler.h" +#include "exception.h" + +#undef ETL_FILE +#define ETL_FILE "37" + +namespace etl +{ + //*************************************************************************** + /// Base exception class for task. + //*************************************************************************** + class task_exception : public etl::exception + { + public: + + task_exception(string_type what, string_type file_name, numeric_type line_number) + : etl::exception(what, file_name, line_number) + { + } + }; + + typedef uint_least8_t task_priority_t; + + //*************************************************************************** + /// Scheduler. + //*************************************************************************** + class task + { + public: + + //******************************************* + /// Constructor. + //******************************************* + task(task_priority_t priority) + : task_running(true), + task_priority(priority) + { + } + + //******************************************* + /// Destructor. + //******************************************* + virtual ~task() + { + } + + //******************************************* + /// Called to check if the task has work. + /// Returns a score as to the amount of work it has to do. + //******************************************* + virtual uint32_t task_request_work() const = 0; + + //******************************************* + /// Called to get the task to do work. + //******************************************* + virtual void task_process_work() = 0; + + //******************************************* + /// Set the running state for the task. + //******************************************* + void set_task_running(bool task_running_) + { + task_running = task_running_; + } + + //******************************************* + /// Get the running state for the task. + //******************************************* + bool task_is_running() const + { + return task_running; + } + + //******************************************* + /// Get the priority of the task. + /// Higher value = higher priority. + //******************************************* + etl::task_priority_t get_task_priority() const + { + return task_priority; + } + + private: + + bool task_running; + etl::task_priority_t task_priority; + }; +} + +#undef ETL_FILE + +#endif diff --git a/src/type_traits.h b/src/type_traits.h index 5c9876a5..afd8be8d 100644 --- a/src/type_traits.h +++ b/src/type_traits.h @@ -5,7 +5,7 @@ The MIT License(MIT) Embedded Template Library. https://github.com/ETLCPP/etl -http://www.etlcpp.com +https://www.etlcpp.com Copyright(c) 2014 jwellbelove @@ -28,6 +28,28 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************************/ +#if 0 +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +#endif + +//*************************************************************************** +// This file has been auto generated. Do not edit this file. +//*************************************************************************** + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -otypes.h -DHandlers= types_generator.h +// Where is the number of types to support. +// +// e.g. +// To generate handlers for up to 16 types... +// python -m cogapp -d -e -otype_traits.h -DIsOneOf=16 type_traits_generator.h +// +// See generate.bat +//*************************************************************************** + #ifndef __ETL_TYPE_TRAITS__ #define __ETL_TYPE_TRAITS__ @@ -152,7 +174,6 @@ namespace etl template struct is_integral : is_integral {}; template struct is_integral : is_integral {}; - /// is_signed ///\ingroup type_traits template struct is_signed : false_type {}; @@ -237,15 +258,15 @@ namespace etl template struct is_reference : true_type {}; /// is_pod + /// For C++03, only fundamental and pointers types are recognised. ///\ingroup type_traits - #if defined(ETL_C11_TYPE_TRAITS_SUPPORTED)// && !defined(ETL_IN_UNIT_TEST) // For compilers that support C++11 template struct is_pod : std::is_pod {}; #else /// For C++03, only fundamental and pointers types are recognised. template struct is_pod : etl::integral_constant::value || - etl::is_pointer::value> {}; + etl::is_pointer::value> {}; #endif #if defined(ETL_C11_TYPE_TRAITS_SUPPORTED) && defined(ETL_C11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED)// && !defined(ETL_IN_UNIT_TEST) @@ -290,6 +311,7 @@ namespace etl template struct is_trivially_copy_assignable : etl::is_pod {}; #endif + /// conditional ///\ingroup type_traits template struct conditional { typedef T type; }; @@ -392,29 +414,80 @@ namespace etl typename etl::remove_cv::type>::type type; }; + /// is_base_of + ///\ingroup type_traits + template + struct is_base_of + { + private: + + template struct dummy {}; + struct internal: TDerived, dummy{}; + + static TBase* check(TBase*); + template static char check(dummy*); + + public: + + static const bool value = (sizeof(check((internal*)0)) == sizeof(TBase*)); + }; + /// Alignment templates. /// These require compiler specific intrinsics. ///\ingroup type_traits -#if defined(ETL_C11_ALIGNOF_SUPPORTED) - template struct alignment_of : integral_constant {}; -#elif defined(ETL_COMPILER_MICROSOFT) +#ifdef ETL_COMPILER_MICROSOFT template struct alignment_of : integral_constant {}; -#elif defined(ETL_COMPILER_GCC) +#endif + +#ifdef ETL_COMPILER_GCC template struct alignment_of : integral_constant {}; -#elif defined(ETL_COMPILER_KEIL) +#endif + +#ifdef ETL_COMPILER_KEIL template struct alignment_of : integral_constant {}; -#elif defined(ETL_COMPILER_IAR) +#endif + +#ifdef ETL_COMPILER_IAR template struct alignment_of : integral_constant {}; -#elif defined(ETL_COMPILER_TI) +#endif + +#ifdef ETL_COMPILER_TI template struct alignment_of : integral_constant {}; -#else - // Best guess! - template struct alignment_of : integral_constant {}; #endif /// Specialisation of 'alignment_of' for 'void'. ///\ingroup type_traits template <> struct alignment_of : integral_constant {}; + + //*************************************************************************** + /// Template to determine if a type is one of a specified list. + ///\ingroup types + //*************************************************************************** + template + struct is_one_of + { + static const bool value = + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value || + etl::is_same::value; + }; } #endif diff --git a/src/type_traits_generator.h b/src/type_traits_generator.h new file mode 100644 index 00000000..68a2202d --- /dev/null +++ b/src/type_traits_generator.h @@ -0,0 +1,500 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +/*[[[cog +import cog +cog.outl("#if 0") +]]]*/ +/*[[[end]]]*/ +#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE. +/*[[[cog +import cog +cog.outl("#endif") +]]]*/ +/*[[[end]]]*/ + +/*[[[cog +import cog +cog.outl("//***************************************************************************") +cog.outl("// This file has been auto generated. Do not edit this file.") +cog.outl("//***************************************************************************") +]]]*/ +/*[[[end]]]*/ + +//*************************************************************************** +// To generate to header file, run this at the command line. +// Note: You will need Python and COG installed. +// +// python -m cogapp -d -e -otypes.h -DHandlers= types_generator.h +// Where is the number of types to support. +// +// e.g. +// To generate handlers for up to 16 types... +// python -m cogapp -d -e -otype_traits.h -DIsOneOf=16 type_traits_generator.h +// +// See generate.bat +//*************************************************************************** + +#ifndef __ETL_TYPE_TRAITS__ +#define __ETL_TYPE_TRAITS__ + +#include + +#include "platform.h" +#include "nullptr.h" + +#if defined(ETL_C11_TYPE_TRAITS_SUPPORTED) + #include +#endif + +///\defgroup type_traits type_traits +/// A set of type traits definitions for compilers that do not support the standard header. +/// \ingroup utilities + +namespace etl +{ + /// integral_constant + ///\ingroup type_traits + template + struct integral_constant + { + static const T value = VALUE; + + typedef T value_type; + typedef integral_constant type; + + operator value_type() const + { + return value; + } + }; + + /// integral_constant specialisations + ///\ingroup type_traits + typedef integral_constant false_type; + typedef integral_constant true_type; + + /// remove_reference + ///\ingroup type_traits + template struct remove_reference { typedef T type; }; + template struct remove_reference { typedef T type; }; + + /// add_reference + ///\ingroup type_traits + template struct add_reference { typedef T& type; }; + template struct add_reference { typedef T& type; }; + + /// remove_pointer + ///\ingroup type_traits + template struct remove_pointer { typedef T type; }; + template struct remove_pointer { typedef T type; }; + + /// add_pointer + ///\ingroup type_traits + template struct add_pointer { typedef typename remove_reference::type* type; }; + + /// is_const + ///\ingroup type_traits + template struct is_const : false_type {}; + template struct is_const : true_type {}; + template struct is_const : true_type {}; + + /// remove_const + ///\ingroup type_traits + template struct remove_const { typedef T type; }; + template struct remove_const { typedef T type; }; + + /// add_const + ///\ingroup type_traits + template struct add_const { typedef const T type; }; + template struct add_const { typedef const T type; }; + + /// is_volatile + ///\ingroup type_traits + template struct is_volatile : false_type {}; + template struct is_volatile : true_type {}; + template struct is_volatile : true_type {}; + + /// remove_volatile + ///\ingroup type_traits + template struct remove_volatile { typedef T type; }; + template struct remove_volatile { typedef T type; }; + + /// add_volatile + ///\ingroup type_traits + template struct add_volatile { typedef volatile T type; }; + template struct add_volatile { typedef volatile T type; }; + + /// remove_cv + ///\ingroup type_traits + template struct remove_cv + { + typedef typename remove_volatile::type>::type type; + }; + + /// add_cv + ///\ingroup type_traits + template struct add_cv + { + typedef typename add_volatile::type>::type type; + }; + + /// is_integral + ///\ingroup type_traits + template struct is_integral : false_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template <> struct is_integral : true_type {}; + template struct is_integral : is_integral {}; + template struct is_integral : is_integral {}; + template struct is_integral : is_integral {}; + + /// is_signed + ///\ingroup type_traits + template struct is_signed : false_type {}; + template <> struct is_signed : integral_constant {}; + template <> struct is_signed : public etl::integral_constant(wchar_t(-1) < wchar_t(0))> {}; + template <> struct is_signed : true_type {}; + template <> struct is_signed : true_type {}; + template <> struct is_signed : true_type {}; + template <> struct is_signed : true_type {}; + template <> struct is_signed : true_type {}; + template <> struct is_signed : true_type{}; + template <> struct is_signed : true_type{}; + template <> struct is_signed : true_type{}; + template struct is_signed : is_signed {}; + template struct is_signed : is_signed {}; + template struct is_signed : is_signed {}; + + /// is_unsigned + ///\ingroup type_traits + template struct is_unsigned : false_type {}; + template <> struct is_unsigned : true_type {}; + template <> struct is_unsigned : integral_constant 0)> {}; + template <> struct is_unsigned : true_type {}; + template <> struct is_unsigned : public etl::integral_constant wchar_t(0))> {}; + template <> struct is_unsigned : true_type {}; + template <> struct is_unsigned : true_type {}; + template <> struct is_unsigned : true_type {}; + template <> struct is_unsigned : true_type {}; + template struct is_unsigned : is_unsigned {}; + template struct is_unsigned : is_unsigned {}; + template struct is_unsigned : is_unsigned {}; + + /// is_floating_point + ///\ingroup type_traits + template struct is_floating_point : false_type {}; + template <> struct is_floating_point : true_type {}; + template <> struct is_floating_point : true_type {}; + template <> struct is_floating_point : true_type {}; + template struct is_floating_point : is_floating_point {}; + template struct is_floating_point : is_floating_point {}; + template struct is_floating_point : is_floating_point {}; + + /// is_same + ///\ingroup type_traits + template struct is_same : public false_type {}; + template struct is_same : public true_type {}; + + /// is_void + ///\ingroup type_traits + template struct is_void : false_type {}; + template<> struct is_void : true_type {}; + + /// is_arithmetic + ///\ingroup type_traits + template struct is_arithmetic : integral_constant::value || is_floating_point::value> {}; + + /// is_fundamental + ///\ingroup type_traits + template struct is_fundamental : integral_constant::value || + is_void::value || + is_same::type>::value> {}; + + /// is_compound + ///\ingroup type_traits + template struct is_compound : integral_constant::value> {}; + + /// is_array + ///\ingroup type_traits + template struct is_array : false_type {}; + template struct is_array : true_type {}; + template struct is_array : true_type {}; + + /// is_pointer + ///\ingroup type_traits + template struct is_pointer : false_type {}; + template struct is_pointer : true_type {}; + + /// is_reference + ///\ingroup type_traits + template struct is_reference : false_type {}; + template struct is_reference : true_type {}; + + /// is_pod + /// For C++03, only fundamental and pointers types are recognised. + ///\ingroup type_traits +#if defined(ETL_C11_TYPE_TRAITS_SUPPORTED)// && !defined(ETL_IN_UNIT_TEST) + // For compilers that support C++11 + template struct is_pod : std::is_pod {}; +#else + /// For C++03, only fundamental and pointers types are recognised. + template struct is_pod : etl::integral_constant::value || + etl::is_pointer::value> {}; +#endif + +#if defined(ETL_C11_TYPE_TRAITS_SUPPORTED) && defined(ETL_C11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED)// && !defined(ETL_IN_UNIT_TEST) + /// is_trivially_constructible + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template struct is_trivially_constructible : std::is_trivially_constructible {}; + + /// is_trivially_copy_constructible + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template struct is_trivially_copy_constructible : std::is_trivially_copy_constructible {}; + + /// is_trivially_destructible + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template struct is_trivially_destructible : std::is_trivially_destructible {}; + + /// is_trivially_copy_assignable + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template struct is_trivially_copy_assignable : std::is_trivially_copy_assignable {}; +#else + /// is_trivially_constructible + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template struct is_trivially_constructible : etl::is_pod {}; + + /// is_trivially_copy_constructible + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template struct is_trivially_copy_constructible : etl::is_pod {}; + + /// is_trivially_destructible + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template struct is_trivially_destructible : etl::is_pod {}; + + /// is_trivially_copy_assignable + /// For C++03, only POD types are recognised. + ///\ingroup type_traits + template struct is_trivially_copy_assignable : etl::is_pod {}; +#endif + + + /// conditional + ///\ingroup type_traits + template struct conditional { typedef T type; }; + template struct conditional { typedef F type; }; + + /// make_signed + ///\ingroup type_traits + template struct make_signed { typedef T type; }; + template <> struct make_signed { typedef signed char type; }; + template <> struct make_signed { typedef signed char type; }; + + template <> struct make_signed + { + typedef etl::conditional::type>::type type; + }; + + template <> struct make_signed { typedef short type; }; + template <> struct make_signed { typedef int type; }; + template <> struct make_signed { typedef long type; }; + template <> struct make_signed { typedef long long type; }; + template struct make_signed : add_const::type> {}; + template struct make_signed : add_volatile::type> {}; + template struct make_signed : add_const::type>::type> {}; + + /// make_unsigned + ///\ingroup type_traits + template struct make_unsigned { typedef T type; }; + template <> struct make_unsigned { typedef unsigned char type; }; + template <> struct make_unsigned { typedef unsigned char type; }; + template <> struct make_unsigned { typedef unsigned short type; }; + + template <> struct make_unsigned + { + typedef etl::conditional::type>::type type; + }; + + template <> struct make_unsigned { typedef unsigned int type; }; + template <> struct make_unsigned { typedef unsigned long type; }; + template <> struct make_unsigned { typedef unsigned long long type; }; + template struct make_unsigned : add_const::type> {}; + template struct make_unsigned : add_volatile::type> {}; + template struct make_unsigned : add_const::type>::type> {}; + + /// enable_if + ///\ingroup type_traits + template struct enable_if {}; + template struct enable_if { typedef T type; }; + + /// extent + ///\ingroup type_traits + template + struct extent : integral_constant {}; + + template + struct extent : integral_constant {}; + + template + struct extent : integral_constant::value> {}; + + template + struct extent : integral_constant {}; + + template + struct extent : integral_constant::value> {}; + + /// remove_extent + ///\ingroup type_traits + template struct remove_extent { typedef T type; }; + template struct remove_extent { typedef T type; }; + template struct remove_extent { typedef T type;}; + + /// remove_all_extents + ///\ingroup type_traits + template struct remove_all_extents { typedef T type;}; + template struct remove_all_extents { typedef typename remove_all_extents::type type; }; + template struct remove_all_extents { typedef typename remove_all_extents::type type; }; + + /// rank + ///\ingroup type_traits + template struct rank : integral_constant {}; + template struct rank : public integral_constant::value + 1> {}; + template struct rank : public integral_constant::value + 1> {}; + + /// decay + ///\ingroup type_traits + template + struct decay + { + typedef typename etl::remove_reference::type U; + typedef typename etl::conditional::value, + typename etl::remove_extent::type*, + typename etl::remove_cv::type>::type type; + }; + + /// is_base_of + ///\ingroup type_traits + template + struct is_base_of + { + private: + + template struct dummy {}; + struct internal: TDerived, dummy{}; + + static TBase* check(TBase*); + template static char check(dummy*); + + public: + + static const bool value = (sizeof(check((internal*)0)) == sizeof(TBase*)); + }; + + /// Alignment templates. + /// These require compiler specific intrinsics. + ///\ingroup type_traits +#ifdef ETL_COMPILER_MICROSOFT + template struct alignment_of : integral_constant {}; +#endif + +#ifdef ETL_COMPILER_GCC + template struct alignment_of : integral_constant {}; +#endif + +#ifdef ETL_COMPILER_KEIL + template struct alignment_of : integral_constant {}; +#endif + +#ifdef ETL_COMPILER_IAR + template struct alignment_of : integral_constant {}; +#endif + +#ifdef ETL_COMPILER_TI + template struct alignment_of : integral_constant {}; +#endif + + /// Specialisation of 'alignment_of' for 'void'. + ///\ingroup type_traits + template <> struct alignment_of : integral_constant {}; + + /*[[[cog + import cog + cog.outl("//***************************************************************************") + cog.outl("/// Template to determine if a type is one of a specified list.") + cog.outl("///\ingroup types") + cog.outl("//***************************************************************************") + cog.outl("template " % IsOneOf) + cog.outl("struct is_one_of") + cog.outl("{") + cog.outl(" static const bool value = ") + for n in range(1, int(IsOneOf)): + cog.outl(" etl::is_same::value ||" % n) + cog.outl(" etl::is_same::value;" % IsOneOf) + cog.outl("};") + ]]]*/ + /*[[[end]]]*/ +} + +#endif diff --git a/src/user_type.h b/src/user_type.h index 98837a92..4ecb193c 100644 --- a/src/user_type.h +++ b/src/user_type.h @@ -89,43 +89,16 @@ SOFTWARE. TypeName operator ++(int) { TypeName temp(*this); TypeName::operator ++(); return temp; } \ TypeName& operator --() { --value; return *this; } \ TypeName operator --(int) { TypeName temp(*this); TypeName::operator --(); return temp; } \ - TypeName& operator +=(const TypeName& rhs) { value += rhs.value; return *this; } \ - TypeName& operator -=(const TypeName& rhs) { value -= rhs.value; return *this; } \ - TypeName& operator *=(const TypeName& rhs) { value *= rhs.value; return *this; } \ - TypeName& operator /=(const TypeName& rhs) { value /= rhs.value; return *this; } \ - TypeName& operator %=(const TypeName& rhs) { value %= rhs.value; return *this; } \ - TypeName& operator &=(const TypeName& rhs) { value &= rhs.value; return *this; } \ - TypeName& operator &=(ValueType mask) { value &= mask; return *this; } \ - TypeName& operator |=(const TypeName& rhs) { value |= rhs.value; return *this; } \ - TypeName& operator |=(ValueType mask) { value &= mask; return *this; } \ - TypeName& operator ^=(const TypeName& rhs) { value ^= rhs.value; return *this; } \ - TypeName& operator ^=(ValueType mask) { value ^= mask; return *this; } \ + TypeName& operator +=(const ValueType& rhs) { value += rhs; return *this; } \ + TypeName& operator -=(const ValueType& rhs) { value -= rhs; return *this; } \ + TypeName& operator *=(const ValueType& rhs) { value *= rhs; return *this; } \ + TypeName& operator /=(const ValueType& rhs) { value /= rhs; return *this; } \ + TypeName& operator %=(const ValueType& rhs) { value %= rhs; return *this; } \ + TypeName& operator &=(const ValueType& rhs) { value &= rhs; return *this; } \ + TypeName& operator |=(const ValueType& rhs) { value |= rhs; return *this; } \ + TypeName& operator ^=(const ValueType& rhs) { value ^= rhs; return *this; } \ TypeName& operator <<=(ValueType distance) { value <<= distance; return *this; } \ TypeName& operator >>=(ValueType distance) { value >>= distance; return *this; } \ - \ - /* Volatile definitions.*/ \ - TypeName(const volatile TypeName &other) : value(other.value) {} \ - void operator=(const volatile TypeName &other) volatile { value = other.value; } \ - operator ValueType() volatile const { return value; } \ - volatile ValueType& get() volatile { return value; } \ - const volatile ValueType& get() volatile const { return value; } \ - void operator ++() volatile { ++value; } \ - volatile TypeName operator ++(int) volatile { volatile TypeName temp(*this); TypeName::operator ++(); return temp; } \ - void operator --() volatile { --value; } \ - volatile TypeName operator --(int) volatile { volatile TypeName temp(*this); TypeName::operator --(); return temp; } \ - void operator +=(const volatile TypeName& rhs) volatile { value += rhs.value; } \ - void operator -=(const volatile TypeName& rhs) volatile { value -= rhs.value; } \ - void operator *=(const volatile TypeName& rhs) volatile { value *= rhs.value; } \ - void operator /=(const volatile TypeName& rhs) volatile { value /= rhs.value; } \ - void operator %=(const volatile TypeName& rhs) volatile { value %= rhs.value; } \ - void operator &=(const volatile TypeName& rhs) volatile { value &= rhs.value; } \ - void operator &=(ValueType mask) volatile { value &= mask; } \ - void operator |=(const volatile TypeName& rhs) volatile { value |= rhs.value; } \ - void operator |=(ValueType mask) volatile { value &= mask; } \ - void operator ^=(const volatile TypeName& rhs) volatile { value ^= rhs.value; } \ - void operator ^=(ValueType mask) volatile { value ^= mask; } \ - void operator <<=(ValueType distance) volatile { value <<= distance; } \ - void operator >>=(ValueType distance) volatile { value >>= distance; } \ private: \ ValueType value; \ public: \ diff --git a/src/variant.h b/src/variant.h index 6b2931eb..0d57a4a4 100644 --- a/src/variant.h +++ b/src/variant.h @@ -5,7 +5,7 @@ The MIT License(MIT) Embedded Template Library. https://github.com/ETLCPP/etl -http://www.etlcpp.com +https://www.etlcpp.com Copyright(c) 2014 jwellbelove @@ -42,7 +42,6 @@ SOFTWARE. #include "static_assert.h" #include "alignment.h" #include "error_handler.h" -#include "largest.h" #if defined(ETL_COMPILER_KEIL) #pragma diag_suppress 940 @@ -124,6 +123,11 @@ namespace etl //*************************************************************************** typedef typename largest_type::type largest_t; + //*************************************************************************** + /// The largest size. + //*************************************************************************** + static const size_t SIZE = sizeof(largest_t); + //*************************************************************************** /// The largest alignment. //*************************************************************************** @@ -139,46 +143,6 @@ namespace etl //*************************************************************************** static const type_id_t UNSUPPORTED_TYPE_ID = integral_limits::max; - //*************************************************************************** - /// Do we pass this type by value? - //*************************************************************************** - template - struct pass_by_value : integral_constant::value || etl::is_pointer::value> - { - }; - - //*************************************************************************** - /// Define the type for a parameter. - //*************************************************************************** - template - struct type_definition; - - //*************************************************************************** - /// Pass by value. - //*************************************************************************** - template - struct type_definition - { - typedef T type; - }; - - //*************************************************************************** - /// Pass by const reference. - //*************************************************************************** - template - struct type_definition - { - typedef const T& type; - }; - - //*************************************************************************** - /// Determines the type for parameters. - //*************************************************************************** - template - struct parameter_type : public type_definition::value> - { - }; - //*************************************************************************** /// Short form of no_type placeholders. //*************************************************************************** @@ -249,14 +213,14 @@ namespace etl friend class variant; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; }; //************************************************************************* @@ -269,13 +233,13 @@ namespace etl friend class variant; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; private: @@ -292,12 +256,12 @@ namespace etl friend class variant; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; private: @@ -315,11 +279,11 @@ namespace etl friend class variant; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; private: @@ -338,10 +302,10 @@ namespace etl friend class variant; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; private: @@ -361,9 +325,9 @@ namespace etl friend class variant; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; private: @@ -384,8 +348,8 @@ namespace etl friend class variant; - virtual void read(typename parameter_type::type value) = 0; - virtual void read(typename parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; private: @@ -407,7 +371,7 @@ namespace etl friend class variant; - virtual void read(typename parameter_type::type value) = 0; + virtual void read(typename etl::parameter_type::type value) = 0; private: @@ -862,7 +826,7 @@ namespace etl //*************************************************************************** void clear() { - type_id = UNSUPPORTED_TYPE_ID; + destruct_current(); } //*************************************************************************** @@ -962,7 +926,7 @@ namespace etl /// The internal storage. /// Aligned on a suitable boundary, which should be good for all types. //*************************************************************************** - typename etl::aligned_storage::value>::type data; + typename etl::aligned_storage::type data; //*************************************************************************** /// The id of the current stored type. diff --git a/temp/message_router.h b/temp/message_router.h new file mode 100644 index 00000000..85d95fe0 --- /dev/null +++ b/temp/message_router.h @@ -0,0 +1,984 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef __ETL_MESSAGE_ROUTER__ +#define __ETL_MESSAGE_ROUTER__ + +#include + +namespace etl +{ + /// Allow alternative type for message id. +#if !defined(ETL_MESSAGE_ID_TYPE) + typedef uint_least8_t message_id_t; +#else + typedef ETL_MESSAGE_ID_TYPE message_id_t; +#endif + + //*************************************************************************** + class imessage + { + public: + + virtual ~imessage() {} + virtual etl::message_id_t get_message_id() const = 0; + }; + + //*************************************************************************** + template + class message : public imessage + { + public: + + enum + { + ID = ID_ + }; + + //******************************************* + etl::message_id_t get_message_id() const + { + return etl::message_id_t(ID); + } + }; + + //*************************************************************************** + class imessage_router + { + public: + + virtual ~imessage_router() {} + virtual void receive(const etl::imessage& message) = 0; + virtual void receive(imessage_router& source, const etl::imessage& message) = 0; + virtual bool accepts(etl::message_id_t id) const = 0; + + //******************************************* + bool accepts(const etl::imessage& msg) const + { + return accepts(msg.get_message_id()); + } + + //******************************************* + void send_message(imessage_router& destination, + const etl::imessage& message) + { + destination.receive(*this, message); + } + }; + + //*************************************************************************** + /// This router can be used either as a sink for messages + /// or as a producer-only of messages such an interrupt routine. + //*************************************************************************** + class null_message_router : public imessage_router + { + public: + + //******************************************* + void receive(const etl::imessage& message) + { + } + + //******************************************* + void receive(etl::imessage_router& source, const etl::imessage& message) + { + } + + //******************************************* + bool accepts(etl::message_id_t id) const + { + return false; + } + + //******************************************* + static null_message_router& get() + { + static null_message_router instance; + return instance; + } + }; + + //*************************************************************************** + /// Send a message to a router. + /// Sets the 'sender' to etl::null_message_router type. + //*************************************************************************** + inline static void send_message(etl::imessage_router& destination, + const etl::imessage& message) + { + destination.receive(message); + } + + //*************************************************************************** + /// Send a message to a router. + //*************************************************************************** + inline static void send_message(etl::imessage_router& source, + etl::imessage_router& destination, + const etl::imessage& message) + { + destination.receive(source, message); + } + + //*************************************************************************** + // To generate to header file, run this at the command line. + // Note: You will need Python and COG installed. + // + // python -m cogapp -d -e -omessage_router.h -DHandlers= message_router_generator.h + // Where is the number of messages to support. + // + // e.g. + // To generate handlers for up to 16 messages... + // python -m cogapp -d -e -omessage_router.h -DHandlers=16 message_router_generator.h + // + // See CreateMessageProcessor.bat + //*************************************************************************** + + //*************************************************************************** + // The code below has been auto generated. Do not manually edit. + //*************************************************************************** + + //*************************************************************************** + // The definition for all 16 message types. + //*************************************************************************** + template + class message_router : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const etl::message_id_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T12::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T13::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T14::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T15::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T16::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: case T14::ID: case T15::ID: case T16::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 15 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T12::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T13::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T14::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T15::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: case T14::ID: case T15::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 14 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T12::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T13::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T14::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: case T14::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 13 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T12::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T13::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 12 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T12::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: case T12::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 11 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T11::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: case T11::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 10 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T10::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: case T10::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 9 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T9::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + case T9::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 8 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T8::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: + + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 7 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T7::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 6 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T6::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 5 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T5::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 4 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T4::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: case T4::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 3 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T3::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: case T3::ID: + return true; break; + default: + return false; break; + } + } + + class message_packet + { + public: + + explicit message_packet(const imessage& msg) + { + const etl::message_id_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: new (&storage) T1(static_cast(msg)); break; + case T2::ID: new (&storage) T2(static_cast(msg)); break; + case T3::ID: new (&storage) T3(static_cast(msg)); break; + default: break; + } + } + + ~message_packet() + { + static_cast(storage).~imessage(); + } + + message_packet(const message_packet& other) + { + const etl::message_id_t id = other.get_imessage().get_message_id(); + + switch (id) + { + case T1::ID: new (&storage) T1(static_cast(msg)); break; + case T2::ID: new (&storage) T2(static_cast(msg)); break; + case T3::ID: new (&storage) T3(static_cast(msg)); break; + default: break; + } + } + + message_packet& operator = (const message_packet& other) + { + if (this != &other) + { + static_cast(storage).~imessage(); + new (this) message_packet(other); + } + } + + const etl::imessage& get_imessage() const + { + return *reiniterpret_cast(storage); + } + + operator const imessage&() const + { + return get_imessage(); + } + + private: + + etl::aligned_storage::size, etl::largest_alignment::value>::type storage; + }; + }; + + //*************************************************************************** + // Specialisation for 2 message types. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + case T2::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: case T2::ID: + return true; break; + default: + return false; break; + } + } + }; + + //*************************************************************************** + // Specialisation for 1 message type. + //*************************************************************************** + template + class message_router + : public imessage_router + { + public: + + void receive(const etl::imessage& msg) + { + receive(etl::null_message_router::get(), msg); + } + + void receive(etl::imessage_router& source, const etl::imessage& msg) + { + const size_t id = msg.get_message_id(); + + switch (id) + { + case T1::ID: static_cast(this)->on_receive(source, static_cast(msg)); break; + default: static_cast(this)->on_receive_unknown(source, msg); break; + } + } + + bool accepts(etl::message_id_t id) const + { + switch (id) + { + case T1::ID: + return true; break; + default: + return false; break; + } + } + }; +} + +#endif diff --git a/test/codeblocks/ETL.cbp b/test/codeblocks/ETL.cbp index 963db74b..60485a23 100644 --- a/test/codeblocks/ETL.cbp +++ b/test/codeblocks/ETL.cbp @@ -172,6 +172,8 @@ + + @@ -193,12 +195,17 @@ + + + + + @@ -206,6 +213,7 @@ + @@ -226,12 +234,16 @@ + + + + @@ -273,6 +285,7 @@ + @@ -291,12 +304,15 @@ + + + @@ -314,12 +330,14 @@ + + diff --git a/test/codeblocks/ETL.depend b/test/codeblocks/ETL.depend index c4e17a7b..1b6a961c 100644 --- a/test/codeblocks/ETL.depend +++ b/test/codeblocks/ETL.depend @@ -3289,7 +3289,7 @@ "CurrentTest.h" "ReportAssertImpl.h" -1501066687 source:d:\users\john\documents\programming\github\etl\test\test_algorithm.cpp +1501803139 source:d:\users\john\documents\programming\github\etl\test\test_algorithm.cpp "UnitTest++.h" "algorithm.h" "container.h" @@ -3538,7 +3538,7 @@ "static_assert.h" "exception.h" -1501067284 source:d:\users\john\documents\programming\github\etl\test\test_deque.cpp +1501803126 source:d:\users\john\documents\programming\github\etl\test\test_deque.cpp "UnitTest++.h" "ExtraCheckMacros.h" "deque.h" @@ -3727,7 +3727,7 @@ 1482623723 v_1.h" -1497713618 source:d:\users\john\documents\programming\github\etl\test\test_forward_list.cpp +1501803126 source:d:\users\john\documents\programming\github\etl\test\test_forward_list.cpp "UnitTest++.h" "ExtraCheckMacros.h" "data.h" @@ -4151,12 +4151,12 @@ "../exception.h" "../error_handler.h" -1500986416 source:d:\users\john\documents\programming\github\etl\test\test_type_traits.cpp +1501803140 source:d:\users\john\documents\programming\github\etl\test\test_type_traits.cpp "UnitTest++.h" "type_traits.h" -1500986416 source:d:\users\john\documents\programming\github\etl\test\test_variant.cpp +1501803140 source:d:\users\john\documents\programming\github\etl\test\test_variant.cpp "UnitTest++.h" "ExtraCheckMacros.h" "variant.h" @@ -5302,7 +5302,7 @@ "platform.h" "static_assert.h" -1501066686 d:\users\john\documents\programming\github\etl\src\algorithm.h +1502118978 d:\users\john\documents\programming\github\etl\src\algorithm.h @@ -5312,7 +5312,7 @@ "iterator.h" "type_traits.h" -1501066686 d:\users\john\documents\programming\github\etl\src\type_traits.h +1502118978 d:\users\john\documents\programming\github\etl\src\type_traits.h "platform.h" "nullptr.h" @@ -5322,7 +5322,7 @@ -1500986416 d:\users\john\documents\programming\github\etl\src\alignment.h +1502118978 d:\users\john\documents\programming\github\etl\src\alignment.h "type_traits.h" "static_assert.h" @@ -5370,7 +5370,7 @@ "log.h" -1501066686 d:\users\john\documents\programming\github\etl\src\smallest.h +1502118978 d:\users\john\documents\programming\github\etl\src\smallest.h "integral_limits.h" @@ -5484,7 +5484,7 @@ "static_assert.h" "exception.h" -1501067284 d:\users\john\documents\programming\github\etl\src\deque.h +1501803126 d:\users\john\documents\programming\github\etl\src\deque.h @@ -5561,7 +5561,7 @@ "../error_handler.h" "../debug_count.h" -1501067284 d:\users\john\documents\programming\github\etl\src\vector.h +1501803126 d:\users\john\documents\programming\github\etl\src\vector.h @@ -5606,7 +5606,7 @@ "../ivector.h" "../error_handler.h" -1497713617 d:\users\john\documents\programming\github\etl\src\forward_list.h +1501803126 d:\users\john\documents\programming\github\etl\src\forward_list.h @@ -5703,12 +5703,12 @@ "nullptr.h" "parameter_type.h" -1501067284 d:\users\john\documents\programming\github\etl\src\largest.h +1502118978 d:\users\john\documents\programming\github\etl\src\largest.h "type_traits.h" "smallest.h" "static_assert.h" -1501067284 d:\users\john\documents\programming\github\etl\src\list.h +1502118941 d:\users\john\documents\programming\github\etl\src\list.h @@ -5930,7 +5930,7 @@ "exception.h" "error_handler.h" -1500986416 d:\users\john\documents\programming\github\etl\src\variant.h +1501803139 d:\users\john\documents\programming\github\etl\src\variant.h "platform.h" "array.h" @@ -5941,7 +5941,6 @@ "static_assert.h" "alignment.h" "error_handler.h" - "largest.h" 1479515291 d:\users\john\documents\programming\github\etl\src\visitor.h @@ -7825,7 +7824,7 @@ "type_traits.h" -1501066686 d:\users\john\documents\programming\github\etl\src\memory.h +1502118978 d:\users\john\documents\programming\github\etl\src\memory.h "type_traits.h" @@ -7835,10 +7834,10 @@ "platform.h" -1501067284 source:d:\users\john\documents\programming\github\etl\src\random.cpp +1501803126 source:d:\users\john\documents\programming\github\etl\src\random.cpp "random.h" -1501067284 d:\users\john\documents\programming\github\etl\src\random.h +1501803126 d:\users\john\documents\programming\github\etl\src\random.h 1494277861 source:d:\users\john\documents\programming\github\etl\test\test_intrusive_flat_map.cpp @@ -7933,7 +7932,7 @@ "UnitTest++.h" "iterator.h" -1500986416 source:d:\users\john\documents\programming\github\etl\test\test_memory.cpp +1501803139 source:d:\users\john\documents\programming\github\etl\test\test_memory.cpp "UnitTest++.h" "memory.h" "debug_count.h" @@ -7944,7 +7943,7 @@ -1501067284 source:d:\users\john\documents\programming\github\etl\test\test_random.cpp +1501803126 source:d:\users\john\documents\programming\github\etl\test\test_random.cpp "UnitTest++.h" "random.h" @@ -7952,7 +7951,7 @@ -1501067284 source:d:\users\john\documents\programming\github\etl\test\test_vector_non_trivial.cpp +1501803126 source:d:\users\john\documents\programming\github\etl\test\test_vector_non_trivial.cpp "UnitTest++.h" @@ -8229,3 +8228,133 @@ "exception.h" "vector.h" +1479515291 source:d:\users\john\documents\programming\github\etl\test\test_compile.cpp + "algorithm.h" + "alignment.h" + "array.h" + "bitset.h" + "container.h" + "crc8_ccitt.h" + "crc16.h" + "crc16_ccitt.h" + "crc16_kermit.h" + "crc32.h" + "crc64_ecma.h" + "cyclic_value.h" + "deque.h" + "io_port.h" + "vector.h" + "variant.h" + "list.h" + "map.h" + + +1501803139 source:d:\users\john\documents\programming\github\etl\test\test_fsm.cpp + "UnitTest++.h" + "fsm.h" + "enum_type.h" + "container.h" + + +1501803139 d:\users\john\documents\programming\github\etl\src\fsm.h + + "array.h" + "nullptr.h" + "error_handler.h" + "exception.h" + "user_type.h" + "message_router.h" + "integral_limits.h" + "largest.h" + +1501803139 d:\users\john\documents\programming\github\etl\src\user_type.h + +1501803139 d:\users\john\documents\programming\github\etl\src\message_router.h + + "message.h" + "message_types.h" + "alignment.h" + "error_handler.h" + "exception.h" + "largest.h" + +1501803140 source:d:\users\john\documents\programming\github\etl\test\test_message_router.cpp + "UnitTest++.h" + "ExtraCheckMacros.h" + "message_router.h" + "queue.h" + "largest.h" + "packet.h" + +1501803139 d:\users\john\documents\programming\github\etl\src\packet.h + "platform.h" + "static_assert.h" + "alignment.h" + +1501803140 source:d:\users\john\documents\programming\github\etl\test\test_packet.cpp + "UnitTest++.h" + "ExtraCheckMacros.h" + "packet.h" + "largest.h" + "queue.h" + "pool.h" + +1501803140 source:d:\users\john\documents\programming\github\etl\test\test_task_scheduler.cpp + "UnitTest++.h" + + + + "task.h" + "scheduler.h" + "container.h" + +1501803139 d:\users\john\documents\programming\github\etl\src\task.h + + "error_handler.h" + "exception.h" + +1501803139 d:\users\john\documents\programming\github\etl\src\scheduler.h + + "vector.h" + "nullptr.h" + "error_handler.h" + "exception.h" + "task.h" + "type_traits.h" + "function.h" + +1501803139 d:\users\john\documents\programming\github\etl\src\message.h + + "error_handler.h" + "exception.h" + "message_types.h" + +1501803139 d:\users\john\documents\programming\github\etl\src\message_types.h + + +1501803139 source:d:\users\john\documents\programming\github\etl\test\test_message_bus.cpp + "UnitTest++.h" + "ExtraCheckMacros.h" + "message_router.h" + "message_bus.h" + "queue.h" + "largest.h" + "packet.h" + +1501803139 d:\users\john\documents\programming\github\etl\src\message_bus.h + + + "algorithm.h" + "vector.h" + "nullptr.h" + "error_handler.h" + "exception.h" + "message_types.h" + "message.h" + "message_router.h" + +1501803140 source:d:\users\john\documents\programming\github\etl\test\test_user_type.cpp + "UnitTest++.h" + + "user_type.h" + diff --git a/test/codeblocks/ETL.layout b/test/codeblocks/ETL.layout index 613556e7..7fc9cd9e 100644 --- a/test/codeblocks/ETL.layout +++ b/test/codeblocks/ETL.layout @@ -2,269 +2,24 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - - - - - - - - - - - + @@ -272,4 +27,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/test_algorithm.cpp b/test/test_algorithm.cpp index 6403aa23..eb631739 100644 --- a/test/test_algorithm.cpp +++ b/test/test_algorithm.cpp @@ -42,6 +42,39 @@ namespace typedef std::vector Data; Data data = { 2, 1, 4, 3, 6, 5, 8, 7, 10, 9 }; + struct StructData + { + int a; + int b; + }; + + bool operator ==(const StructData& lhs, const StructData& rhs) + { + return (lhs.a == rhs.a) && (lhs.b == rhs.b); + } + + struct StructDataPredicate + { + bool operator ()(const StructData& lhs, const StructData& rhs) const + { + return lhs.a < rhs.a; + } + }; + + struct StructDataEquality + { + bool operator ()(const StructData& lhs, const StructData& rhs) const + { + return lhs.a == rhs.a; + } + }; + + std::ostream& operator << (std::ostream& os, const StructData& data) + { + os << data.a << "," << data.b; + return os; + } + SUITE(test_algorithm) { //========================================================================= @@ -543,10 +576,40 @@ namespace int data1[] = { 1, 2, 3, 5, 6, 7, 8 }; // Find the element not less than 4. - int* p = std::find_if_not(std::begin(data1), std::end(data1), std::bind2nd(std::less(), 4)); + int* p = etl::find_if_not(std::begin(data1), std::end(data1), std::bind2nd(std::less(), 4)); CHECK_EQUAL(5, *p); } + //========================================================================= + TEST(binary_find) + { + int data1[] = { 1, 2, 3, 5, 6, 7, 8 }; + + // Find the element of value 5. + int* p = etl::binary_find(std::begin(data1), std::end(data1), 5); + CHECK_EQUAL(5, *p); + + // Find the element of value 4. + p = etl::binary_find(std::begin(data1), std::end(data1), 4); + CHECK_EQUAL(std::end(data1), p); + } + + //========================================================================= + TEST(binary_find_StructDataPredicate_StructDataEquality) + { + StructData data1[] = { { 1, 8 }, { 2, 7 }, { 3, 6 },{ 4, 5 },{ 5, 4 },{ 6, 3 },{ 7, 2 },{ 8, 1 } }; + StructData test1 = { 4, 5 }; + StructData test2 = { 9, 0 }; + + // Find the element of value 5. + StructData* p = etl::binary_find(std::begin(data1), std::end(data1), test1, StructDataPredicate(), StructDataEquality()); + CHECK_EQUAL(test1, *p); + + // Find the element of value 4. + p = etl::binary_find(std::begin(data1), std::end(data1), test2, StructDataPredicate(), StructDataEquality()); + CHECK_EQUAL(std::end(data1), p); + } + //========================================================================= TEST(for_each_if) { diff --git a/test/test_fsm.cpp b/test/test_fsm.cpp new file mode 100644 index 00000000..71a78263 --- /dev/null +++ b/test/test_fsm.cpp @@ -0,0 +1,503 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "UnitTest++.h" + +#include "fsm.h" +#include "enum_type.h" +#include "container.h" + +#include + +namespace +{ + const etl::message_router_id_t MOTOR_CONTROL = 0; + + + //*************************************************************************** + // Events + struct EventId + { + enum enum_type + { + START, + STOP, + STOPPED, + SET_SPEED, + UNSUPPORTED + }; + + ETL_DECLARE_ENUM_TYPE(EventId, etl::message_id_t) + ETL_ENUM_TYPE(START, "Start") + ETL_ENUM_TYPE(STOP, "Stop") + ETL_ENUM_TYPE(STOPPED, "Stopped") + ETL_ENUM_TYPE(SET_SPEED, "Set Speed") + ETL_ENUM_TYPE(UNSUPPORTED, "Unsupported") + ETL_END_ENUM_TYPE + }; + + //*********************************** + class Start : public etl::message + { + }; + + //*********************************** + class Stop : public etl::message + { + public: + + Stop() : isEmergencyStop(false) {} + Stop(bool emergency) : isEmergencyStop(emergency) {} + + const bool isEmergencyStop; + }; + + //*********************************** + class SetSpeed : public etl::message + { + public: + + SetSpeed(int speed) : speed(speed) {} + + const int speed; + }; + + //*********************************** + class Stopped : public etl::message + { + }; + + //*********************************** + class Unsupported : public etl::message + { + }; + + //*************************************************************************** + // States + struct StateId + { + enum enum_type + { + IDLE, + RUNNING, + WINDING_DOWN, + LOCKED, + NUMBER_OF_STATES + }; + + ETL_DECLARE_ENUM_TYPE(StateId, etl::fsm_state_id_t) + ETL_ENUM_TYPE(IDLE, "Idle") + ETL_ENUM_TYPE(RUNNING, "Running") + ETL_ENUM_TYPE(WINDING_DOWN, "Winding Down") + ETL_ENUM_TYPE(LOCKED, "Locked") + ETL_END_ENUM_TYPE + }; + + //*********************************** + // The motor control FSM. + //*********************************** + class MotorControl : public etl::fsm + { + public: + + MotorControl(etl::ifsm_state** p_states, size_t size) + : fsm(MOTOR_CONTROL) + { + set_states(p_states, size); + ClearStatistics(); + } + + //*********************************** + void ClearStatistics() + { + startCount = 0; + stopCount = 0; + setSpeedCount = 0; + unknownCount = 0; + stoppedCount = 0; + isLampOn = false; + speed = 0; + } + + //*********************************** + void SetSpeed(int speed_) + { + speed = speed_; + } + + //*********************************** + void TurnRunningLampOn() + { + isLampOn = true; + } + + //*********************************** + void TurnRunningLampOff() + { + isLampOn = false; + } + + int startCount; + int stopCount; + int setSpeedCount; + int unknownCount; + int stoppedCount; + bool isLampOn; + int speed; + }; + + //*********************************** + // The idle state. + //*********************************** + class Idle : public etl::fsm_state + { + public: + + //*********************************** + etl::fsm_state_id_t on_event(etl::imessage_router& sender, const Start& event) + { + ++get_fsm_context().startCount; + return StateId::RUNNING; + } + + //*********************************** + etl::fsm_state_id_t on_event_unknown(etl::imessage_router& sender, const etl::imessage& event) + { + ++get_fsm_context().unknownCount; + return STATE_ID; + } + + //*********************************** + etl::fsm_state_id_t on_enter_state() + { + get_fsm_context().TurnRunningLampOff(); + return StateId::LOCKED; + } + }; + + //*********************************** + // The running state. + //*********************************** + class Running : public etl::fsm_state + { + public: + + //*********************************** + etl::fsm_state_id_t on_event(etl::imessage_router& sender, const Stop& event) + { + ++get_fsm_context().stopCount; + + if (event.isEmergencyStop) + { + return StateId::IDLE; + } + else + { + return StateId::WINDING_DOWN; + } + } + + //*********************************** + etl::fsm_state_id_t on_event(etl::imessage_router& sender, const SetSpeed& event) + { + ++get_fsm_context().setSpeedCount; + get_fsm_context().SetSpeed(event.speed); + return STATE_ID; + } + + //*********************************** + etl::fsm_state_id_t on_event_unknown(etl::imessage_router& sender, const etl::imessage& event) + { + ++get_fsm_context().unknownCount; + return STATE_ID; + } + + //*********************************** + etl::fsm_state_id_t on_enter_state() + { + get_fsm_context().TurnRunningLampOn(); + + return STATE_ID; + } + }; + + //*********************************** + // The winding down state. + //*********************************** + class WindingDown : public etl::fsm_state + { + public: + + //*********************************** + etl::fsm_state_id_t on_event(etl::imessage_router& source, const Stopped& event) + { + ++get_fsm_context().stoppedCount; + return StateId::IDLE; + } + + //*********************************** + etl::fsm_state_id_t on_event_unknown(etl::imessage_router& source, const etl::imessage& event) + { + ++get_fsm_context().unknownCount; + return STATE_ID; + } + }; + + //*********************************** + // The locked state. + //*********************************** + class Locked : public etl::fsm_state + { + public: + + //*********************************** + etl::fsm_state_id_t on_event_unknown(etl::imessage_router& source, const etl::imessage& event) + { + ++get_fsm_context().unknownCount; + return STATE_ID; + } + }; + + // The states. + Idle idle; + Running running; + WindingDown windingDown; + Locked locked; + + etl::ifsm_state* stateList[StateId::NUMBER_OF_STATES] = + { + &idle, &running, &windingDown, &locked + }; + + MotorControl motorControl(stateList, etl::size(stateList)); + + SUITE(test_map) + { + //************************************************************************* + TEST(test_fsm) + { + etl::null_message_router nmr; + + motorControl.reset(); + motorControl.ClearStatistics(); + + CHECK(!motorControl.is_started()); + + // Start the FSM. + motorControl.start(); + CHECK(motorControl.is_started()); + + // Now in Idle state. + + CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id())); + CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state().get_state_id())); + + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(0, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.unknownCount); + + // Send unhandled events. + motorControl.receive(nmr, Stop()); + motorControl.receive(nmr, Stopped()); + motorControl.receive(nmr, SetSpeed(10)); + + CHECK_EQUAL(StateId::IDLE, motorControl.get_state_id()); + CHECK_EQUAL(StateId::IDLE, motorControl.get_state().get_state_id()); + + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(0, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(3, motorControl.unknownCount); + + // Send Start event. + motorControl.receive(nmr, Start()); + + // Now in Running state. + + CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state_id())); + CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state().get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(3, motorControl.unknownCount); + + // Send unhandled events. + motorControl.receive(nmr, Start()); + motorControl.receive(nmr, Stopped()); + + CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state_id())); + CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state().get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(5, motorControl.unknownCount); + + // Send SetSpeed event. + motorControl.receive(nmr, SetSpeed(100)); + + // Still in Running state. + + CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state_id())); + CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state().get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(5, motorControl.unknownCount); + + // Send Stop event. + motorControl.receive(nmr, Stop()); + + // Now in WindingDown state. + + CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControl.get_state_id())); + CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControl.get_state().get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(1, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(5, motorControl.unknownCount); + + // Send unhandled events. + motorControl.receive(nmr, Start()); + motorControl.receive(nmr, Stop()); + motorControl.receive(nmr, SetSpeed(100)); + + CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControl.get_state_id())); + CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControl.get_state().get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(1, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(8, motorControl.unknownCount); + + // Send Stopped event. + motorControl.receive(nmr, Stopped()); + + // Now in Locked state via Idle state. + CHECK_EQUAL(StateId::LOCKED, int(motorControl.get_state_id())); + CHECK_EQUAL(StateId::LOCKED, int(motorControl.get_state().get_state_id())); + + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(1, motorControl.setSpeedCount); + CHECK_EQUAL(100, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(1, motorControl.stopCount); + CHECK_EQUAL(1, motorControl.stoppedCount); + CHECK_EQUAL(8, motorControl.unknownCount); + } + + //************************************************************************* + TEST(test_fsm_emergency_stop) + { + etl::null_message_router nmr; + + motorControl.reset(); + motorControl.ClearStatistics(); + + CHECK(!motorControl.is_started()); + + // Start the FSM. + motorControl.start(); + CHECK(motorControl.is_started()); + + // Now in Idle state. + + // Send Start event. + motorControl.receive(nmr, Start()); + + // Now in Running state. + + CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state_id())); + CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state().get_state_id())); + + CHECK_EQUAL(true, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(0, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.unknownCount); + + // Send emergency Stop event. + motorControl.receive(nmr, Stop(true)); + + // Now in Locked state via Idle state. + CHECK_EQUAL(StateId::LOCKED, int(motorControl.get_state_id())); + CHECK_EQUAL(StateId::LOCKED, int(motorControl.get_state().get_state_id())); + + CHECK_EQUAL(false, motorControl.isLampOn); + CHECK_EQUAL(0, motorControl.setSpeedCount); + CHECK_EQUAL(0, motorControl.speed); + CHECK_EQUAL(1, motorControl.startCount); + CHECK_EQUAL(1, motorControl.stopCount); + CHECK_EQUAL(0, motorControl.stoppedCount); + CHECK_EQUAL(0, motorControl.unknownCount); + } + + //************************************************************************* + TEST(test_fsm_supported) + { + CHECK(motorControl.accepts(EventId::SET_SPEED)); + CHECK(motorControl.accepts(EventId::START)); + CHECK(motorControl.accepts(EventId::STOP)); + CHECK(motorControl.accepts(EventId::STOPPED)); + CHECK(motorControl.accepts(EventId::UNSUPPORTED)); + + CHECK(motorControl.accepts(SetSpeed(0))); + CHECK(motorControl.accepts(Start())); + CHECK(motorControl.accepts(Stop())); + CHECK(motorControl.accepts(Stopped())); + CHECK(motorControl.accepts(Unsupported())); + } + }; +} diff --git a/test/test_memory.cpp b/test/test_memory.cpp index 44b5f0d6..1e237565 100644 --- a/test/test_memory.cpp +++ b/test/test_memory.cpp @@ -445,5 +445,31 @@ namespace etl::destroy(p, p + SIZE, count); CHECK_EQUAL(0U, count); } + + //************************************************************************* + TEST(test_create_copy) + { + struct Test : etl::create_copy + { + std::string text; + }; + + char buffer[sizeof(Test)]; + + Test test1; + test1.text = "12345678"; + test1.create_copy_at(buffer); + test1.text = "87654321"; + + Test& test2 = *reinterpret_cast(buffer); + + CHECK_EQUAL(std::string("87654321"), test1.text); + CHECK_EQUAL(std::string("12345678"), test2.text); + + int count = 0; + test1.create_copy_at(buffer, count); + + CHECK_EQUAL(1, count); + } }; } diff --git a/test/test_message_bus.cpp b/test/test_message_bus.cpp new file mode 100644 index 00000000..66e079f5 --- /dev/null +++ b/test/test_message_bus.cpp @@ -0,0 +1,729 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "UnitTest++.h" +#include "ExtraCheckMacros.h" + +#include "message_router.h" +#include "message_bus.h" +#include "queue.h" +#include "largest.h" +#include "packet.h" + +//*************************************************************************** +// The set of messages. +//*************************************************************************** +namespace +{ + enum + { + MESSAGE1, + MESSAGE2, + MESSAGE3, + MESSAGE4, + MESSAGE5 + }; + + enum + { + ROUTER1 = 1, + ROUTER2 = 2, + ROUTER3 = 3, + ROUTER4 = 4, + ROUTER5 = 5 + }; + + struct Message1 : public etl::message + { + }; + + struct Message2 : public etl::message + { + }; + + struct Message3 : public etl::message + { + int value[10]; + }; + + struct Message4 : public etl::message + { + }; + + struct Message5 : public etl::message + { + }; + + Message1 message1; + Message2 message2; + Message3 message3; + Message4 message4; + Message5 message5; + + int call_order; + + //*************************************************************************** + // Router that handles messages 1, 2, 3, 4, 5. + //*************************************************************************** + class RouterA : public etl::message_router + { + public: + + RouterA(etl::message_router_id_t id) + : message_router(id), + message1_count(0), + message2_count(0), + message3_count(0), + message4_count(0), + message5_count(0), + message_unknown_count(0) + { + + } + + void on_receive(etl::imessage_router& sender, const Message1& msg) + { + ++message1_count; + etl::send_message(sender, message5); + + order = call_order++; + } + + void on_receive(etl::imessage_router& sender, const Message2& msg) + { + ++message2_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message3& msg) + { + ++message3_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message4& msg) + { + ++message4_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message5& msg) + { + ++message5_count; + } + + void on_receive_unknown(etl::imessage_router& sender, const etl::imessage& msg) + { + ++message_unknown_count; + } + + int message1_count; + int message2_count; + int message3_count; + int message4_count; + int message5_count; + int message_unknown_count; + int order; + }; + + //*************************************************************************** + // Router that handles messages 1, 2, 4 and 5 and returns nothing. + //*************************************************************************** + class RouterB : public etl::message_router + { + public: + + RouterB(etl::message_router_id_t id) + : message_router(id), + message1_count(0), + message2_count(0), + message4_count(0), + message5_count(0), + message_unknown_count(0) + { + + } + + void on_receive(etl::imessage_router& sender, const Message1& msg) + { + ++message1_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message2& msg) + { + ++message2_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message4& msg) + { + ++message4_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message5& msg) + { + ++message5_count; + } + + void on_receive_unknown(etl::imessage_router& sender, const etl::imessage& msg) + { + ++message_unknown_count; + etl::send_message(sender, message5); + } + + int message1_count; + int message2_count; + int message4_count; + int message5_count; + int message_unknown_count; + }; + + etl::imessage_router* p_router; + etl::imessage_bus* p_bus; + + SUITE(test_message_router) + { + //========================================================================= + TEST(message_bus_subscribe_unsubscribe) + { + etl::message_bus<2> bus1; + + RouterA router1(0); + RouterB router2(1); + RouterA router3(2); + + CHECK_EQUAL(0U, bus1.size()); + + CHECK_NO_THROW(bus1.subscribe(router1)); + CHECK_EQUAL(1U, bus1.size()); + + CHECK_NO_THROW(bus1.subscribe(router2)); + CHECK_EQUAL(2U, bus1.size()); + + CHECK_THROW(bus1.subscribe(router3), etl::message_bus_too_many_subscribers); + CHECK_EQUAL(2U, bus1.size()); + + bus1.unsubscribe(router1); + CHECK_EQUAL(1U, bus1.size()); + + // Erase router not in list. + bus1.unsubscribe(router3); + CHECK_EQUAL(1U, bus1.size()); + + // Erase using id. + bus1.unsubscribe(router2.get_message_router_id()); + CHECK_EQUAL(0U, bus1.size()); + + // Erase router from empty list. + bus1.unsubscribe(router2); + CHECK_EQUAL(0U, bus1.size()); + } + + //========================================================================= + TEST(message_bus_subscribe_unsubscribe_sub_bus) + { + etl::message_bus<4> bus1; + etl::message_bus<2> bus2; + etl::message_bus<3> bus3; + + RouterA router1(ROUTER1); + RouterA router2(ROUTER2); + RouterA router3(ROUTER3); + RouterA router4(ROUTER4); + + bus1.subscribe(router1); + bus1.subscribe(router2); + bus1.subscribe(bus2); + bus1.subscribe(bus3); + + bus2.subscribe(router3); + bus3.subscribe(router4); + + CHECK_EQUAL(4U, bus1.size()); + + bus1.unsubscribe(etl::imessage_bus::MESSAGE_BUS); + CHECK_EQUAL(2U, bus1.size()); + + bus1.unsubscribe(etl::imessage_bus::ALL_MESSAGE_ROUTERS); + CHECK_EQUAL(0U, bus1.size()); + } + + //========================================================================= + TEST(message_bus_broadcast) + { + etl::message_bus<2> bus1; + + RouterA router1(ROUTER1); + RouterB router2(ROUTER2); + RouterA sender(ROUTER3); + + bus1.subscribe(router1); + bus1.subscribe(router2); + + bus1.receive(sender, message1); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(0, router1.message2_count); + CHECK_EQUAL(0, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(1, router2.message1_count); + CHECK_EQUAL(0, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(2, sender.message5_count); + + bus1.receive(sender, message2); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(1, router1.message2_count); + CHECK_EQUAL(0, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(1, router2.message1_count); + CHECK_EQUAL(1, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(4, sender.message5_count); + + bus1.receive(sender, message3); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(1, router1.message2_count); + CHECK_EQUAL(1, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(1, router2.message1_count); + CHECK_EQUAL(1, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(5, sender.message5_count); + + // Use global function. + etl::send_message(sender, bus1, message4); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(1, router1.message2_count); + CHECK_EQUAL(1, router1.message3_count); + CHECK_EQUAL(1, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(1, router2.message1_count); + CHECK_EQUAL(1, router2.message2_count); + CHECK_EQUAL(1, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(7, sender.message5_count); + } + + //========================================================================= + TEST(message_bus_broadcast_as_router) + { + etl::message_bus<2> bus1; + + RouterA router1(ROUTER1); + RouterB router2(ROUTER2); + RouterA sender(ROUTER3); + + bus1.subscribe(router1); + bus1.subscribe(router2); + + // Reference to router sub-type + etl::imessage_router& irouter = bus1; + + irouter.receive(sender, message1); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(0, router1.message2_count); + CHECK_EQUAL(0, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(1, router2.message1_count); + CHECK_EQUAL(0, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(2, sender.message5_count); + + irouter.receive(sender, message2); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(1, router1.message2_count); + CHECK_EQUAL(0, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(1, router2.message1_count); + CHECK_EQUAL(1, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(4, sender.message5_count); + + irouter.receive(sender, message3); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(1, router1.message2_count); + CHECK_EQUAL(1, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(1, router2.message1_count); + CHECK_EQUAL(1, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(5, sender.message5_count); + + // Use global function. + etl::send_message(sender, irouter, message4); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(1, router1.message2_count); + CHECK_EQUAL(1, router1.message3_count); + CHECK_EQUAL(1, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(1, router2.message1_count); + CHECK_EQUAL(1, router2.message2_count); + CHECK_EQUAL(1, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(7, sender.message5_count); + } + + //========================================================================= + TEST(message_bus_addressed) + { + etl::message_bus<2> bus1; + + RouterA router1(ROUTER1); + RouterB router2(ROUTER2); + RouterA sender(ROUTER3); + + bus1.subscribe(router1); + bus1.subscribe(router2); + + bus1.receive(sender, ROUTER1, message1); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(0, router1.message2_count); + CHECK_EQUAL(0, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(0, router2.message1_count); + CHECK_EQUAL(0, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(1, sender.message5_count); + + bus1.receive(sender, ROUTER2, message2); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(0, router1.message2_count); + CHECK_EQUAL(0, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(0, router2.message1_count); + CHECK_EQUAL(1, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(2, sender.message5_count); + + bus1.receive(sender, ROUTER1, message3); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(0, router1.message2_count); + CHECK_EQUAL(1, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(0, router2.message1_count); + CHECK_EQUAL(1, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(3, sender.message5_count); + + // Use global function. + etl::send_message(sender, bus1, ROUTER2, message4); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(0, router1.message2_count); + CHECK_EQUAL(1, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(0, router2.message1_count); + CHECK_EQUAL(1, router2.message2_count); + CHECK_EQUAL(1, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(4, sender.message5_count); + + // Send to a router not subscribed to the bus. + bus1.receive(sender, ROUTER5, message1); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(0, router1.message2_count); + CHECK_EQUAL(1, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(0, router2.message1_count); + CHECK_EQUAL(1, router2.message2_count); + CHECK_EQUAL(1, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(4, sender.message5_count); + } + + //========================================================================= + TEST(message_bus_addressed_duplicate_router_id) + { + etl::message_bus<3> bus1; + + RouterA router1(ROUTER1); + RouterB router2(ROUTER1); + RouterB router3(ROUTER2); + RouterA sender(ROUTER3); + + bus1.subscribe(router1); + bus1.subscribe(router2); + bus1.subscribe(router3); + + bus1.receive(sender, ROUTER1, message1); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(0, router1.message2_count); + CHECK_EQUAL(0, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(1, router2.message1_count); + CHECK_EQUAL(0, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(0, router3.message1_count); + CHECK_EQUAL(0, router3.message2_count); + CHECK_EQUAL(0, router3.message4_count); + CHECK_EQUAL(0, router3.message5_count); + CHECK_EQUAL(0, router3.message_unknown_count); + + CHECK_EQUAL(2, sender.message5_count); + } + + //========================================================================= + TEST(message_bus_broadcast_addressed_sub_bus) + { + etl::message_bus<3> bus1; + etl::message_bus<2> bus2; + + RouterA router1(ROUTER1); + RouterA router2(ROUTER2); + RouterA router3(ROUTER3); + RouterA router4(ROUTER4); + + RouterA sender(ROUTER5); + + bus1.subscribe(router1); + bus1.subscribe(router2); + bus1.subscribe(bus2); + + bus2.subscribe(router3); + bus2.subscribe(router4); + + // Broadcast to bus1 + bus1.receive(sender, message1); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(0, router1.message2_count); + CHECK_EQUAL(0, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(1, router2.message1_count); + CHECK_EQUAL(0, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(1, router3.message1_count); + CHECK_EQUAL(0, router3.message2_count); + CHECK_EQUAL(0, router3.message4_count); + CHECK_EQUAL(0, router3.message5_count); + CHECK_EQUAL(0, router3.message_unknown_count); + + CHECK_EQUAL(1, router4.message1_count); + CHECK_EQUAL(0, router4.message2_count); + CHECK_EQUAL(0, router4.message4_count); + CHECK_EQUAL(0, router4.message5_count); + CHECK_EQUAL(0, router4.message_unknown_count); + + CHECK_EQUAL(4, sender.message5_count); + + // Addressed to ROUTER2 + bus1.receive(sender, ROUTER2, message1); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(0, router1.message2_count); + CHECK_EQUAL(0, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(2, router2.message1_count); + CHECK_EQUAL(0, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(1, router3.message1_count); + CHECK_EQUAL(0, router3.message2_count); + CHECK_EQUAL(0, router3.message4_count); + CHECK_EQUAL(0, router3.message5_count); + CHECK_EQUAL(0, router3.message_unknown_count); + + CHECK_EQUAL(1, router4.message1_count); + CHECK_EQUAL(0, router4.message2_count); + CHECK_EQUAL(0, router4.message4_count); + CHECK_EQUAL(0, router4.message5_count); + CHECK_EQUAL(0, router4.message_unknown_count); + + CHECK_EQUAL(5, sender.message5_count); + + // Addressed to ROUTER3 via bus2 + bus1.receive(sender, ROUTER3, message1); + + CHECK_EQUAL(1, router1.message1_count); + CHECK_EQUAL(0, router1.message2_count); + CHECK_EQUAL(0, router1.message3_count); + CHECK_EQUAL(0, router1.message4_count); + CHECK_EQUAL(0, router1.message5_count); + CHECK_EQUAL(0, router1.message_unknown_count); + + CHECK_EQUAL(2, router2.message1_count); + CHECK_EQUAL(0, router2.message2_count); + CHECK_EQUAL(0, router2.message4_count); + CHECK_EQUAL(0, router2.message5_count); + CHECK_EQUAL(0, router2.message_unknown_count); + + CHECK_EQUAL(2, router3.message1_count); + CHECK_EQUAL(0, router3.message2_count); + CHECK_EQUAL(0, router3.message4_count); + CHECK_EQUAL(0, router3.message5_count); + CHECK_EQUAL(0, router3.message_unknown_count); + + CHECK_EQUAL(1, router4.message1_count); + CHECK_EQUAL(0, router4.message2_count); + CHECK_EQUAL(0, router4.message4_count); + CHECK_EQUAL(0, router4.message5_count); + CHECK_EQUAL(0, router4.message_unknown_count); + + CHECK_EQUAL(6, sender.message5_count); + } + + //========================================================================= + TEST(message_bus_broadcast_order) + { + etl::message_bus<4> bus1; + etl::message_bus<2> bus2; + etl::message_bus<2> bus3; + + RouterA router1(ROUTER1); + RouterA router2(ROUTER2); + RouterA router3(ROUTER3); + RouterA router4a(ROUTER4); + RouterA router4b(ROUTER4); + + RouterA sender(ROUTER5); + + bus1.subscribe(router1); + bus1.subscribe(bus3); + bus1.subscribe(bus2); + bus1.subscribe(router2); + + bus2.subscribe(router3); + bus3.subscribe(router4b); + bus3.subscribe(router4a); + + call_order = 0; + + bus1.receive(sender, message1); + + CHECK_EQUAL(0, router1.order); + CHECK_EQUAL(1, router2.order); + CHECK_EQUAL(2, router4b.order); + CHECK_EQUAL(3, router4a.order); + CHECK_EQUAL(4, router3.order); + } + }; +} diff --git a/test/test_message_router.cpp b/test/test_message_router.cpp new file mode 100644 index 00000000..c2890fb0 --- /dev/null +++ b/test/test_message_router.cpp @@ -0,0 +1,421 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "UnitTest++.h" +#include "ExtraCheckMacros.h" + +#include "message_router.h" +#include "queue.h" +#include "largest.h" +#include "packet.h" + +//*************************************************************************** +// The set of messages. +//*************************************************************************** +namespace +{ + enum + { + MESSAGE1, + MESSAGE2, + MESSAGE3, + MESSAGE4, + MESSAGE5 + }; + + enum + { + ROUTER1, + ROUTER2 + }; + + struct Message1 : public etl::message + { + }; + + struct Message2 : public etl::message + { + }; + + struct Message3 : public etl::message + { + int value[10]; + }; + + struct Message4 : public etl::message + { + }; + + struct Message5 : public etl::message + { + }; + + Message1 message1; + Message2 message2; + Message3 message3; + Message4 message4; + Message5 message5; + + //*************************************************************************** + // Router that handles messages 1, 2, 3, 4 and 5 and returns nothing. + //*************************************************************************** + class Router1 : public etl::message_router + { + public: + + Router1() + : message_router(ROUTER1), + message1_count(0), + message2_count(0), + message3_count(0), + message4_count(0), + message_unknown_count(0), + callback_count(0) + { + + } + + void on_receive(etl::imessage_router& sender, const Message1& msg) + { + ++message1_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message2& msg) + { + ++message2_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message3& msg) + { + ++message3_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message4& msg) + { + ++message4_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message5& msg) + { + ++callback_count; + } + + void on_receive_unknown(etl::imessage_router& sender, const etl::imessage& msg) + { + ++message_unknown_count; + } + + int message1_count; + int message2_count; + int message3_count; + int message4_count; + int message_unknown_count; + int callback_count; + }; + + //*************************************************************************** + // Router that handles messages 1, 2, 4 and 5 and returns nothing. + //*************************************************************************** + class Router2 : public etl::message_router + { + public: + + Router2() + : message_router(ROUTER2), + message1_count(0), + message2_count(0), + message4_count(0), + message_unknown_count(0), + callback_count(0) + { + + } + + void on_receive(etl::imessage_router& sender, const Message1& msg) + { + ++message1_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message2& msg) + { + ++message2_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message4& msg) + { + ++message4_count; + etl::send_message(sender, message5); + } + + void on_receive(etl::imessage_router& sender, const Message5& msg) + { + ++callback_count; + } + + void on_receive_unknown(etl::imessage_router& sender, const etl::imessage& msg) + { + ++message_unknown_count; + etl::send_message(sender, message5); + } + + int message1_count; + int message2_count; + int message4_count; + int message_unknown_count; + int callback_count; + }; + + + etl::imessage_router* p_router; + + SUITE(test_message_router) + { + //========================================================================= + TEST(message_router) + { + Router1 r1; + Router2 r2; + + p_router = &r1; + + p_router->receive(r2, message1); + CHECK_EQUAL(1, r1.message1_count); + CHECK_EQUAL(0, r1.message2_count); + CHECK_EQUAL(0, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + CHECK_EQUAL(1, r2.callback_count); + + p_router->receive(r2, message2); + CHECK_EQUAL(1, r1.message1_count); + CHECK_EQUAL(1, r1.message2_count); + CHECK_EQUAL(0, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + CHECK_EQUAL(2, r2.callback_count); + + p_router->receive(r2, message3); + CHECK_EQUAL(1, r1.message1_count); + CHECK_EQUAL(1, r1.message2_count); + CHECK_EQUAL(1, r1.message3_count); + CHECK_EQUAL(0, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + CHECK_EQUAL(3, r2.callback_count); + + p_router->receive(r2, message4); + CHECK_EQUAL(1, r1.message1_count); + CHECK_EQUAL(1, r1.message2_count); + CHECK_EQUAL(1, r1.message3_count); + CHECK_EQUAL(1, r1.message4_count); + CHECK_EQUAL(0, r1.message_unknown_count); + CHECK_EQUAL(4, r2.callback_count); + + p_router = &r2; + + p_router->receive(r1, message1); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(0, r2.message2_count); + CHECK_EQUAL(0, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + CHECK_EQUAL(1, r1.callback_count); + + p_router->receive(r1, message2); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(0, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + CHECK_EQUAL(2, r1.callback_count); + + p_router->receive(r1, message3); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(0, r2.message4_count); + CHECK_EQUAL(1, r2.message_unknown_count); + CHECK_EQUAL(3, r1.callback_count); + + p_router->receive(r1, message4); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(1, r2.message4_count); + CHECK_EQUAL(1, r2.message_unknown_count); + CHECK_EQUAL(4, r1.callback_count); + } + + //========================================================================= + TEST(message_null_router) + { + Router2 router; + etl::null_message_router null_router; + + // Send from the null router. + etl::send_message(router, message1); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(0, router.message2_count); + CHECK_EQUAL(0, router.message4_count); + CHECK_EQUAL(0, router.message_unknown_count); + + etl::send_message(router, message2); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(0, router.message4_count); + CHECK_EQUAL(0, router.message_unknown_count); + + etl::send_message(router, message3); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(0, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + etl::send_message(router, message4); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + // Send to the null router. + etl::send_message(null_router, message1); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + etl::send_message(null_router, message2); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + etl::send_message(null_router, message3); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + + etl::send_message(null_router, message4); + CHECK_EQUAL(1, router.message1_count); + CHECK_EQUAL(1, router.message2_count); + CHECK_EQUAL(1, router.message4_count); + CHECK_EQUAL(1, router.message_unknown_count); + } + + //========================================================================= + TEST(message_router_accepts) + { + Router2 r2; + + CHECK(r2.accepts(message1)); + CHECK(r2.accepts(message1.get_message_id())); + + CHECK(r2.accepts(message2)); + CHECK(r2.accepts(message2.get_message_id())); + + CHECK(!r2.accepts(message3)); + CHECK(!r2.accepts(message3.get_message_id())); + + CHECK(r2.accepts(message4)); + CHECK(r2.accepts(message4.get_message_id())); + + CHECK(r2.accepts(message5)); + CHECK(r2.accepts(message5.get_message_id())); + } + + //========================================================================= + TEST(message_router_queue) + { + Router1 r1; + Router2 r2; + + typedef Router2::message_packet Packet; + typedef etl::queue Queue; + + Queue queue; + + etl::imessage* im; + + // Queue some messages in the message packet queue. + im = &message1; + queue.emplace(*im); + + im = &message2; + queue.emplace(*im); + + // The router2 queue doesn't accept Message3 types. + im = &message3; + CHECK_THROW(queue.emplace(*im), etl::unhandled_message_exception); + + im = &message4; + queue.emplace(*im); + + im = &message4; + queue.emplace(*im); + + etl::imessage& imr1 = queue.front().get(); + r2.receive(r1, imr1); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(0, r2.message2_count); + CHECK_EQUAL(0, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + CHECK_EQUAL(1, r1.callback_count); + queue.pop(); + + etl::imessage& imr2 = queue.front().get(); + r2.receive(r1, imr2); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(0, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + CHECK_EQUAL(2, r1.callback_count); + queue.pop(); + + const etl::imessage& imr3 = queue.front().get(); + r2.receive(r1, imr3); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(1, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + CHECK_EQUAL(3, r1.callback_count); + queue.pop(); + + const Queue& crqueue = queue; + const etl::imessage& imr4 = crqueue.front().get(); + r2.receive(r1, imr4); + CHECK_EQUAL(1, r2.message1_count); + CHECK_EQUAL(1, r2.message2_count); + CHECK_EQUAL(2, r2.message4_count); + CHECK_EQUAL(0, r2.message_unknown_count); + CHECK_EQUAL(4, r1.callback_count); + queue.pop(); + } + }; +} diff --git a/test/test_packet.cpp b/test/test_packet.cpp new file mode 100644 index 00000000..90f70c67 --- /dev/null +++ b/test/test_packet.cpp @@ -0,0 +1,183 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "UnitTest++.h" +#include "ExtraCheckMacros.h" + +#include "packet.h" +#include "largest.h" +#include "queue.h" +#include "pool.h" + +namespace +{ + // Test classes for polymorphic tests. + struct base + { + base(int v_) + : v(v_) + { + } + + virtual ~base() + { + } + + virtual int value() const = 0; + + protected: + + const int v; + }; + + struct not_base + { + not_base() + { + } + }; + + struct derived_1 : public base + { + derived_1(int value) + : base(value) + { + } + + int value() const + { + return v; + } + + static int count; + }; + + struct derived_2 : public base + { + derived_2(int value) + : base(value) + { + } + + int value() const + { + return v; + } + }; + + typedef etl::largest types; + // + //// Test packet types. + typedef etl::packet packet1_t; + typedef etl::packet packet2_t; + + SUITE(test_packet) + { + //************************************************************************* + TEST(test_constructor_value) + { + derived_1 d1(1); + derived_2 d2(2); + + packet1_t p11(d1); + packet1_t p12(d2); + + base* b; + b = &p11.get(); + CHECK_EQUAL(d1.value(), b->value()); + + b = &p12.get(); + CHECK_EQUAL(d2.value(), b->value()); + + // These lines should fail to compile. + //p11 = p12; + //packet2_t p21(d1); + //packet2_t p22(d1); + } + + //************************************************************************* + TEST(test_assignment) + { + derived_1 d1(1); + derived_2 d2(2); + + packet1_t p(d1); + + base* b; + b = &p.get(); + CHECK_EQUAL(d1.value(), b->value()); + + p = d2; + CHECK_EQUAL(d2.value(), b->value()); + } + + //************************************************************************* + TEST(test_packet_queueing) + { + derived_1 da(1); + derived_2 db(2); + derived_1 dc(3); + derived_2 dd(4); + + etl::queue queue; + + queue.emplace(da); + queue.emplace(db); + queue.emplace(dc); + queue.emplace(dd); + + CHECK_EQUAL(da.value(), queue.front().get().value()); + queue.pop(); + + CHECK_EQUAL(db.value(), queue.front().get().value()); + queue.pop(); + + CHECK_EQUAL(dc.value(), queue.front().get().value()); + queue.pop(); + + CHECK_EQUAL(dd.value(), queue.front().get().value()); + queue.pop(); + } + + //************************************************************************* + TEST(test_packet_get) + { + derived_1 da(1); + + // Non-const. + packet1_t p1(da); + base& rb = p1.get(); + CHECK_EQUAL(da.value(), rb.value()); + + // Const. + const packet1_t p2(da); + const base& crb = p2.get(); + CHECK_EQUAL(da.value(), crb.value()); + } + } +} diff --git a/test/test_task_scheduler.cpp b/test/test_task_scheduler.cpp new file mode 100644 index 00000000..7680e37f --- /dev/null +++ b/test/test_task_scheduler.cpp @@ -0,0 +1,263 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "UnitTest++.h" + +#include +#include +#include + +#include "task.h" +#include "scheduler.h" +#include "container.h" + +typedef std::vector WorkList_t; + +//***************************************************************************** +struct Common +{ + //********************************************* + Common() + : idle_callback(*this, &Common::IdleCallback), + watchdog_callback(*this, &Common::WatchdogCallback), + watchdog_called(false) + { + } + + //********************************************* + void Clear() + { + workList.clear(); + } + + //********************************************* + void IdleCallback() + { + pScheduler->exit_scheduler(); + } + + //********************************************* + void WatchdogCallback() + { + watchdog_called = true; + } + + WorkList_t workList; + etl::function idle_callback; + etl::function watchdog_callback; + etl::ischeduler* pScheduler; + bool watchdog_called; +}; + +//***************************************************************************** +class Task : public etl::task +{ +public: + + //********************************************* + Task(etl::task_priority_t priority, WorkList_t& work, Common& common) + : task(priority), + work(work), + common(common), + workIndex(0), + addAtIndex(0), + workToAdd(""), + pTaskToAddTo(nullptr) + { + workCopy = work; + } + + //********************************************* + void Reset() + { + workIndex = 0; + addAtIndex = 0; + workToAdd = ""; + pTaskToAddTo = nullptr; + work = workCopy; + } + + //********************************************* + void WorkToAdd(int addAtIndex_, const std::string& workToAdd_, Task& taskToAddTo_) + { + addAtIndex = addAtIndex_; + workToAdd = workToAdd_; + pTaskToAddTo = &taskToAddTo_; + } + + //********************************************* + uint32_t task_request_work() const + { + return uint_least8_t(work.size() - workIndex); + } + + //********************************************* + void task_process_work() + { + common.workList.push_back(work[workIndex]); + ++workIndex; + + if (workIndex == addAtIndex) + { + pTaskToAddTo->work.push_back(workToAdd); + } + } + +private: + + WorkList_t work; + WorkList_t workCopy; + Common &common; + uint_least8_t workIndex; + int addAtIndex; + std::string workToAdd; + Task* pTaskToAddTo; +}; + +Common common; + +WorkList_t work1 = { "T1W1", "T1W2", "T1W3" }; +WorkList_t work2 = { "T2W1", "T2W2", "T2W3", "T2W4" }; +WorkList_t work3 = { "T3W1", "T3W2" }; + +Task task1(1, work1, common); +Task task2(2, work2, common); +Task task3(3, work3, common); + +etl::task* taskList[] = { &task1, &task2, &task3 }; + +typedef etl::scheduler SchedulerSequencialSingle; +typedef etl::scheduler SchedulerSequencialMultiple; +typedef etl::scheduler SchedulerHighestPriority; +typedef etl::scheduler SchedulerMostWork; + +namespace +{ + SUITE(test_task_scheduler) + { + //========================================================================= + TEST(test_scheduler_sequencial_single) + { + SchedulerSequencialSingle s; + + task1.Reset(); + task2.Reset(); + task3.Reset(); + + task2.WorkToAdd(2, "T3W3", task3); + + common.Clear(); + common.pScheduler = &s; + + s.set_idle_callback(common.idle_callback); + s.set_watchdog_callback(common.watchdog_callback); + s.add_task_list(taskList, etl::size(taskList)); + s.start(); // If 'start' returns then the idle callback was sucessfully called. + + WorkList_t expected = { "T3W1", "T2W1", "T1W1", "T3W2", "T2W2", "T1W2", "T3W3", "T2W3", "T1W3", "T2W4" }; + + CHECK(expected == common.workList); + CHECK(common.watchdog_called); + } + + //========================================================================= + TEST(test_scheduler_sequencial_multiple) + { + SchedulerSequencialMultiple s; + + task1.Reset(); + task2.Reset(); + task3.Reset(); + + task2.WorkToAdd(2, "T3W3", task3); + + common.Clear(); + common.pScheduler = &s; + + s.set_idle_callback(common.idle_callback); + s.set_watchdog_callback(common.watchdog_callback); + s.add_task_list(taskList, etl::size(taskList)); + s.start(); // If 'start' returns then the idle callback was sucessfully called. + + WorkList_t expected = { "T3W1", "T3W2", "T2W1", "T2W2", "T2W3", "T2W4", "T1W1", "T1W2", "T1W3", "T3W3" }; + + CHECK(expected == common.workList); + CHECK(common.watchdog_called); + } + + //========================================================================= + TEST(test_scheduler_highest_priority) + { + SchedulerHighestPriority s; + + task1.Reset(); + task2.Reset(); + task3.Reset(); + + task2.WorkToAdd(2, "T3W3", task3); + + common.Clear(); + common.pScheduler = &s; + + s.set_idle_callback(common.idle_callback); + s.set_watchdog_callback(common.watchdog_callback); + s.add_task_list(taskList, etl::size(taskList)); + s.start(); // If 'start' returns then the idle callback was sucessfully called. + + WorkList_t expected = { "T3W1", "T3W2", "T2W1", "T2W2", "T3W3", "T2W3", "T2W4", "T1W1", "T1W2", "T1W3" }; + + CHECK(expected == common.workList); + CHECK(common.watchdog_called); + } + + //========================================================================= + TEST(test_scheduler_most_work) + { + SchedulerMostWork s; + + task1.Reset(); + task2.Reset(); + task3.Reset(); + + task2.WorkToAdd(3, "T3W3", task3); + + common.Clear(); + common.pScheduler = &s; + + s.set_idle_callback(common.idle_callback); + s.set_watchdog_callback(common.watchdog_callback); + s.add_task_list(taskList, etl::size(taskList)); + s.start(); // If 'start' returns then the idle callback was sucessfully called. + + WorkList_t expected = { "T2W1", "T2W2", "T1W1", "T3W1", "T2W3", "T3W2", "T1W2", "T3W3", "T2W4", "T1W3" }; + + CHECK(expected == common.workList); + CHECK(common.watchdog_called); + } + }; +} diff --git a/test/test_type_traits.cpp b/test/test_type_traits.cpp index b9e624d7..5f80210e 100644 --- a/test/test_type_traits.cpp +++ b/test/test_type_traits.cpp @@ -41,14 +41,20 @@ namespace std #include "type_traits.h" #include -// A class to test non-fundamental types. -struct Test -{ - int a; -}; - namespace { + // A class to test non-fundamental types. + struct Test + { + int a; + }; + + // A class to test etl::is_one_of + template + struct Type + { + }; + SUITE(test_type_traits) { //************************************************************************* @@ -525,5 +531,55 @@ namespace CHECK(std::alignment_of::value == etl::alignment_of::value); CHECK(std::alignment_of::value == etl::alignment_of::value); } + + //************************************************************************* + TEST(test_is_one_of) + { + typedef Type<0> T0; + typedef Type<1> T1; + typedef Type<2> T2; + typedef Type<3> T3; + typedef Type<4> T4; + + CHECK(bool(etl::is_one_of::value)); + CHECK(!(etl::is_one_of::value)); + + CHECK(bool(etl::is_one_of::value)); + CHECK(!(etl::is_one_of::value)); + + CHECK(bool(etl::is_one_of::value)); + CHECK(!(etl::is_one_of::value)); + + CHECK(bool(etl::is_one_of::value)); + CHECK(!(etl::is_one_of::value)); + + CHECK(bool(etl::is_one_of::value)); + CHECK(!(etl::is_one_of::value)); + + CHECK(bool(etl::is_one_of::value)); + CHECK(bool(etl::is_one_of::value)); + CHECK(bool(etl::is_one_of::value)); + CHECK(bool(etl::is_one_of::value)); + CHECK(bool(etl::is_one_of::value)); + CHECK(!(etl::is_one_of::value)); + } + + //************************************************************************* + TEST(test_is_base_of) + { + struct A { }; + struct B : public A { }; + struct C { }; + + CHECK((std::is_base_of::value) == (etl::is_base_of::value)); + CHECK((std::is_base_of::value) == (etl::is_base_of::value)); + CHECK((std::is_base_of::value) == (etl::is_base_of::value)); + CHECK((std::is_base_of::value) == (etl::is_base_of::value)); + CHECK((std::is_base_of::value) == (etl::is_base_of::value)); + CHECK((std::is_base_of::value) == (etl::is_base_of::value)); + CHECK((std::is_base_of::value) == (etl::is_base_of::value)); + CHECK((std::is_base_of::value) == (etl::is_base_of::value)); + CHECK((std::is_base_of::value) == (etl::is_base_of::value)); + } }; } diff --git a/test/test_user_type.cpp b/test/test_user_type.cpp new file mode 100644 index 00000000..0e3e5da7 --- /dev/null +++ b/test/test_user_type.cpp @@ -0,0 +1,224 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "UnitTest++.h" +#include + +#include "user_type.h" + +ETL_DECLARE_USER_TYPE(CompassDirection, int) +ETL_USER_TYPE(North, 0) +ETL_USER_TYPE(South, 180) +ETL_USER_TYPE(East, 90) +ETL_USER_TYPE(West, 270) +ETL_END_USER_TYPE(CompassDirection) + +namespace +{ + SUITE(test_user_type) + { + //************************************************************************* + TEST(Values) + { + CHECK_EQUAL(0, CompassDirection::North); + CHECK_EQUAL(180, CompassDirection::South); + CHECK_EQUAL(90, CompassDirection::East); + CHECK_EQUAL(270, CompassDirection::West); + } + + //************************************************************************* + TEST(test_assignment) + { + CompassDirection value1 = CompassDirection::North; + CompassDirection value2 = CompassDirection(135); + + value1 = value2; + + CHECK_EQUAL(135, value1); + } + + //************************************************************************* + TEST(test_equality) + { + CompassDirection value1 = CompassDirection::North; + CompassDirection value2 = CompassDirection::South; + CompassDirection value3 = CompassDirection::South; + + CHECK(value1 != value2); + CHECK(value2 == value3); + } + + //************************************************************************* + TEST(test_get_value) + { + CompassDirection actual = CompassDirection::North; + CompassDirection expected = CompassDirection::North; + + CHECK_EQUAL(expected, actual.get()); + } + + //************************************************************************* + TEST(test_pre_increment) + { + CompassDirection value = CompassDirection::North; + CompassDirection expected = CompassDirection(CompassDirection::North + 1); + + CHECK_EQUAL(expected, ++value); + } + + //************************************************************************* + TEST(test_post_increment) + { + CompassDirection value = CompassDirection::North; + CompassDirection expected = CompassDirection(CompassDirection::North + 1); + + CHECK_EQUAL(CompassDirection::North, value++); + CHECK_EQUAL(expected, value); + } + + + //************************************************************************* + TEST(test_pre_decrement) + { + CompassDirection value = CompassDirection::North; + CompassDirection expected = CompassDirection(CompassDirection::North - 1); + + CHECK_EQUAL(expected, --value); + } + + //************************************************************************* + TEST(test_post_decrement) + { + CompassDirection value = CompassDirection::North; + CompassDirection expected = CompassDirection(CompassDirection::North - 1); + + CHECK_EQUAL(CompassDirection::North, value--); + CHECK_EQUAL(expected, value); + } + + //************************************************************************* + TEST(test_add_equal) + { + CompassDirection value = CompassDirection::North; + value += 3; + CompassDirection expected = CompassDirection(CompassDirection::North + 3); + + CHECK_EQUAL(expected, value); + } + + //************************************************************************* + TEST(test_subtract_equal) + { + CompassDirection value = CompassDirection::North; + value -= 3; + CompassDirection expected = CompassDirection(CompassDirection::North - 3); + + CHECK_EQUAL(expected, value); + } + + //************************************************************************* + TEST(test_muliply_equal) + { + CompassDirection value = CompassDirection::North; + value *= 3; + CompassDirection expected = CompassDirection(CompassDirection::North * 3); + + CHECK_EQUAL(expected, value); + } + + //************************************************************************* + TEST(test_divide_equal) + { + CompassDirection value = CompassDirection::North; + value /= 3; + CompassDirection expected = CompassDirection(CompassDirection::North / 3); + + CHECK_EQUAL(expected, value); + } + + //************************************************************************* + TEST(test_mod_equal) + { + CompassDirection value = CompassDirection::North; + value %= 3; + CompassDirection expected = CompassDirection(CompassDirection::North % 3); + + CHECK_EQUAL(expected, value); + } + + //************************************************************************* + TEST(test_and_equal) + { + CompassDirection value = CompassDirection::North; + value &= 0xAAAAAAAA; + CompassDirection expected = CompassDirection(CompassDirection::North & 0xAAAAAAAA); + + CHECK_EQUAL(expected, value); + } + + //************************************************************************* + TEST(test_or_equal) + { + CompassDirection value = CompassDirection::North; + value |= 0xAAAAAAAA; + CompassDirection expected = CompassDirection(CompassDirection::North | 0xAAAAAAAA); + + CHECK_EQUAL(expected, value); + } + + //************************************************************************* + TEST(test_xor_equal) + { + CompassDirection value = CompassDirection::North; + value ^= 0xAAAAAAAA; + CompassDirection expected = CompassDirection(CompassDirection::North ^ 0xAAAAAAAA); + + CHECK_EQUAL(expected, value); + } + + //************************************************************************* + TEST(test_shift_left) + { + CompassDirection value = CompassDirection::North; + value <<= 2; + CompassDirection expected = CompassDirection(CompassDirection::North << 2); + + CHECK_EQUAL(expected, value); + } + + //************************************************************************* + TEST(test_shift_right) + { + CompassDirection value = CompassDirection::North; + value >>= 2; + CompassDirection expected = CompassDirection(CompassDirection::North >> 2); + + CHECK_EQUAL(expected, value); + } + }; +} \ No newline at end of file diff --git a/test/test_variant.cpp b/test/test_variant.cpp index 0430c7f6..5b3324e9 100644 --- a/test/test_variant.cpp +++ b/test/test_variant.cpp @@ -35,70 +35,70 @@ SOFTWARE. #include #include -// Test classes for polymorphic tests. -struct base -{ - virtual ~base() - { - } - - base() - : value(0) - { - } - - virtual void set() = 0; - int value; -}; - -struct not_base -{ - not_base() - : value(0) - { - } - - virtual void set() = 0; - int value; -}; - -struct derived_1 : public base -{ - void set() - { - value = 1; - } -}; - -struct derived_2 : public base -{ - void set() - { - value = 2; - } -}; - -// Test variant types. -typedef etl::variant test_variant_3a; -typedef etl::variant test_variant_3b; - -typedef etl::variant test_variant_1; -typedef etl::variant test_variant_2; -typedef etl::variant test_variant_3; -typedef etl::variant test_variant_4; -typedef etl::variant test_variant_5; -typedef etl::variant test_variant_6; -typedef etl::variant test_variant_7; -typedef etl::variant test_variant_8; - -typedef etl::variant test_variant_polymorphic; -typedef etl::variant test_variant_max_types; - -// This line should compile with no errors. -test_variant_max_types variant_max; - namespace { + // Test classes for polymorphic tests. + struct base + { + virtual ~base() + { + } + + base() + : value(0) + { + } + + virtual void set() = 0; + int value; + }; + + struct not_base + { + not_base() + : value(0) + { + } + + virtual void set() = 0; + int value; + }; + + struct derived_1 : public base + { + void set() + { + value = 1; + } + }; + + struct derived_2 : public base + { + void set() + { + value = 2; + } + }; + + // Test variant types. + typedef etl::variant test_variant_3a; + typedef etl::variant test_variant_3b; + + typedef etl::variant test_variant_1; + typedef etl::variant test_variant_2; + typedef etl::variant test_variant_3; + typedef etl::variant test_variant_4; + typedef etl::variant test_variant_5; + typedef etl::variant test_variant_6; + typedef etl::variant test_variant_7; + typedef etl::variant test_variant_8; + + typedef etl::variant test_variant_polymorphic; + typedef etl::variant test_variant_max_types; + + // This line should compile with no errors. + test_variant_max_types variant_max; + SUITE(test_variant) { TEST(test_alignment) diff --git a/test/vs2017/etl.vcxproj b/test/vs2017/etl.vcxproj index e2eddc14..a1356245 100644 --- a/test/vs2017/etl.vcxproj +++ b/test/vs2017/etl.vcxproj @@ -128,6 +128,19 @@ + + + + + + + + + + + + + @@ -212,7 +225,6 @@ - @@ -236,7 +248,6 @@ - @@ -329,6 +340,7 @@ + @@ -364,6 +376,8 @@ + + @@ -373,6 +387,7 @@ false + @@ -393,12 +408,14 @@ + + @@ -410,6 +427,9 @@ + + + diff --git a/test/vs2017/etl.vcxproj.filters b/test/vs2017/etl.vcxproj.filters index 6c40bcc4..df04c8df 100644 --- a/test/vs2017/etl.vcxproj.filters +++ b/test/vs2017/etl.vcxproj.filters @@ -38,7 +38,13 @@ {7028012c-30c4-4993-b2d9-3b1521a610ae} - {5de50c3d-4679-4eb3-9b76-e43e1aad6a66} + {6be3bc76-e17c-4be0-8b0b-d1053e1a1761} + + + {c1264f38-22fa-4fcb-8cab-f254b1290eab} + + + {39015d44-a7cb-47f0-a7dd-27714f852363} @@ -261,12 +267,6 @@ ETL\Containers - - ETL\Containers - - - ETL\Containers - ETL\Containers @@ -438,6 +438,45 @@ Header Files + + ETL\Frameworks + + + ETL\Frameworks + + + ETL\Containers + + + ETL\Frameworks\Generators + + + ETL\Frameworks\Generators + + + ETL\Utilities\Generators + + + ETL\Utilities\Generators + + + ETL\Utilities\Generators + + + ETL\Frameworks + + + ETL\Frameworks + + + ETL\Frameworks + + + ETL\Frameworks + + + ETL\Frameworks + @@ -761,6 +800,24 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + @@ -769,8 +826,14 @@ Resource Files - - Source Files + + Resource Files + + + Resource Files + + + Resource Files diff --git a/uml/FSM example.png b/uml/FSM example.png new file mode 100644 index 0000000000000000000000000000000000000000..4bc0bfbceb8125f54f47f1dc55a3690523b755ba GIT binary patch literal 3455 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 G|M@S9;2EI+ literal 0 HcmV?d00001 diff --git a/uml/Framework.png b/uml/Framework.png new file mode 100644 index 0000000000000000000000000000000000000000..3ff74411286880d0f68ad5ee8a7583c81ac117c4 GIT binary patch literal 4445 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 literal 0 HcmV?d00001 diff --git a/uml/source/FSM example.zargo b/uml/source/FSM example.zargo new file mode 100644 index 0000000000000000000000000000000000000000..89bfb9b50f952d480def9bed304673e8a1b15066 GIT binary patch literal 6601 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 literal 0 HcmV?d00001 diff --git a/uml/source/Message Framework.zargo b/uml/source/Message Framework.zargo new file mode 100644 index 0000000000000000000000000000000000000000..f874146ed6811dd854cf1574f94efac19806f1fc GIT binary patch literal 9028 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 D-&TvI literal 0 HcmV?d00001