From 714409be19ad395ec522df077f82c2bf2ca902a9 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 20 Sep 2026 17:49:48 +0100 Subject: [PATCH] Initial changes --- docs/messaging/message-broker.md | 11 +- docs/messaging/message-bus.md | 29 +- docs/messaging/message-router.md | 90 ++- include/etl/message_broker.h | 58 +- include/etl/message_bus.h | 172 ++--- include/etl/message_processor.h | 1013 ++++++++++++++++++++++++++++++ include/etl/message_router.h | 872 +------------------------ include/etl/message_types.h | 3 +- test/vs2022/etl.vcxproj | 3 +- test/vs2022/etl.vcxproj.filters | 5 +- 10 files changed, 1229 insertions(+), 1027 deletions(-) create mode 100644 include/etl/message_processor.h diff --git a/docs/messaging/message-broker.md b/docs/messaging/message-broker.md index ffc5df6d..c9cc3a46 100644 --- a/docs/messaging/message-broker.md +++ b/docs/messaging/message-broker.md @@ -9,10 +9,17 @@ weight: 6 Message Broker -A variant of the observer pattern in that message routers and derived types are be able to subscribe to selected sets of messages. The message_broker is similar to the message_bus, but it provides more control over the routing of messages. While the message_bus simply broadcasts every message to all subscribers, the message_broker allows you to specify which subscribers should receive each message. +A variant of the observer pattern in that message routers and derived types are be able to subscribe to selected sets of messages. The `message_broker` is similar to the `message_bus`, but it provides more control over the routing of messages. While `message_bus` simply broadcasts every message to all subscribers, `message_broker` allows you to specify which subscribers should receive each message. -Derived from `imessage_router`. +```mermaid +classDiagram + direction TB + + class message_processor + class message_broker + message_processor <|-- message_broker +``` ## Types ```cpp diff --git a/docs/messaging/message-bus.md b/docs/messaging/message-bus.md index 7277c01d..6922d8f3 100644 --- a/docs/messaging/message-bus.md +++ b/docs/messaging/message-bus.md @@ -12,30 +12,39 @@ Message Bus This page documents version `20.0.0` and above. -A variant of the observer pattern in that message routers and derived types are be able to subscribe to messages on a bus. The messages can be either broadcast, to be automatically picked up by any router that has a handler, or addressed to a particular router or router id. Message buses may be nested by setting a successor. +A variant of the observer pattern in that message routers and derived types are be able to subscribe to messages on a bus. The messages can be either broadcast, to be automatically picked up by any router that has a handler, or addressed to a particular router or router id. Message buses may be chained by setting a successor. -## imessage_bus -Derived from imessage_router. +```mermaid +classDiagram + direction TB + + class message_processor + class message_bus + + message_processor <|-- message_bus +``` + +## imessage_bus The base for all message buses. -Inherits publicly from `etl::imessage_router`. +Inherits publicly from `etl::message_processor`. Message buses are therefore also a type of router. Objects of type `etl::imessage_bus` cannot be directly constructed. ## Member functions ```cpp -bool subscribe(etl::imessage_router& router) +bool subscribe(etl::message_processor& router) ``` -Subscribes an `etl::imessage_router` derived class to the bus. +Subscribes an `etl::message_processor` derived class to the bus. Returns `true` on success. --- ```cpp -void unsubscribe(etl::imessage_router& router) +void unsubscribe(etl::message_processor& router) ``` -Unsubscribes the specified `etl::imessage_router` derived class from the bus. +Unsubscribes the specified `etl::message_processor` derived class from the bus. Does not unsubscribe from nested buses. --- @@ -100,7 +109,7 @@ void clear() ``` Clears the bus of all subscribers. -Message buses inherit all of the public functions of `etl::imessage_router`. +Message buses inherit all of the public functions of `etl::message_processor`. ## Errors @@ -134,7 +143,7 @@ Constructs a message bus. Message buses always have a router id of `etl::imessage::MESSAGE_BUS`. ```cpp -message_bus(etl::imessage_router& successor) +message_bus(etl::message_processor& successor) ``` Constructs a message bus and sets the successor. Message buses always have a router id of `etl::imessage::MESSAGE_BUS`. diff --git a/docs/messaging/message-router.md b/docs/messaging/message-router.md index 9253f69e..16fde427 100644 --- a/docs/messaging/message-router.md +++ b/docs/messaging/message-router.md @@ -5,25 +5,57 @@ weight: 3 A class that will automatically route incoming messages to specific handlers based on the message types declared in the template parameter list. Messages are passed to the receive member function which will static cast it to its real type and call the matching `on_receive` function in the derived class. A compilation error will occur if the matching `on_receive` does not exist. -The `on_receive` functions are not virtual. The template base class uses `CRTP` to directly call the derived class's functions. +The `on_receive` functions are not virtual. The template base class uses [CRTP](https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern) to directly call the derived class's functions. -**Defines the following classes** -```cpp -etl::imessage_router -etl::message_router -etl::null_message_router -``` Note: This C++03 portion of this header is a generated from `message_router_generator.h`. To handle more than the standard 16 message types then a new one must be generated. See [Generators](./generators-tutorial) +**Defines the following classes** +```cpp +etl::message_processor +etl::message_router +etl::null_message_router +etl::message_producer +etl::message_router_from_type_list +etl::message_router_from_type_list_t +``` +## Class diagram + +```mermaid +classDiagram + class successor~TDerived~ + + class message_processor_tag { + All_Message_Processors + Null_Message_Router + Message_Bus + Message_Broker + Message_Router + Max_Message_Router + } + + class message_processor + class message_router~TDerived, TMessageTypes...~ + class null_message_router + class message_producer + + successor <|-- message_processor + message_processor_tag <|-- message_processor + + message_processor <|-- message_router + + message_router <|-- null_message_router + message_router <|-- message_producer +``` + ## Message router ID -Allowable router IDs run from `0` to `MAX_MESSAGE_ROUTER` (`249`) inclusive. +Allowable router IDs run from `0` to `Max_Message_Router` (`249`) inclusive. Each message router is given an ID. Whether this ID is unique or not depends on how you are using and identifying message routers. -Note: A message router 'group' is deemed to be a set of routers with identical IDs. -The default router id is `etl::imessage_router::MESSAGE_ROUTER`. +Note: A message router *group* is deemed to be a set of routers with identical IDs. +The default router id is `etl::message_processor::Message_Router`. ### Scenario 1 - You never send a message to a router using it's ID. @@ -48,12 +80,12 @@ Router IDs will be assigned in groups. i.e. Some routers may share IDs. All router IDs are unique -## imessage_router +## message_processor The base class for all routers. #### Member functions ```cpp -virtual ~imessage_router() {} +virtual ~message_processor() {} ``` --- @@ -137,7 +169,7 @@ Returns `true` if the router is a consumer of messages, otherwise `false`. --- ```cpp -void set_successor(etl::imessage_router& successor); +void set_successor(etl::message_processor& successor); ``` Sets the successor router. Any unhandled message will be sent here. Allows the router to implement the Chain Of Responsibility design pattern. @@ -147,14 +179,14 @@ Allows the router to implement the Chain Of Responsibility design pattern. NULL_MESSAGE_ROUTER MESSAGE_BUS ALL_MESSAGE_ROUTERS -MAX_MESSAGE_ROUTER +Max_Message_Router ``` --- ## message_router User defined message routers are derived from this class. -Derived from `imessage_router`. +Derived from `message_processor`. --- @@ -223,15 +255,15 @@ See [etl::message_packet](./message-packet) message_router() ``` Constructs the router. -The router id is set to `etl::imassage_router::MESSAGE_ROUTER`. +The router id is set to `etl::imassage_router::Message_Router`. --- ```cpp -message_router(etl::imessage_router& successor) +message_router(etl::message_processor& successor) ``` Constructs the router. -The router id must be between `0` and `MAX_MESSAGE_ROUTER` (`249`). Other IDs are reserved for ETL use. +The router id must be between `0` and `Max_Message_Router` (`249`). Other IDs are reserved for ETL use. Emits an error if the id is outside the legal range. Routers may have duplicate ids. Sets the successor router to this one. Any unhandled message will be sent here. @@ -249,10 +281,10 @@ Routers may have duplicate ids. --- ```cpp -message_router(etl::message_router_id_t id, etl::imessage_router& successor) +message_router(etl::message_router_id_t id, etl::message_processor& successor) ``` Constructs the router. -The router id must be between 0 and MAX_MESSAGE_ROUTER (249) . Other IDs are reserved for ETL use. +The router id must be between 0 and Max_Message_Router (249) . Other IDs are reserved for ETL use. Sets the successor router to this one. Any unhandled message will be sent here. --- @@ -301,7 +333,7 @@ Derived from `etl::message_router_exception`. ### null_message_router This router can be used as a sink for messages or a 'null source' router. -Derived from `etl::imessage_router`. +Derived from `etl::message_processor`. --- @@ -309,7 +341,7 @@ Derived from `etl::imessage_router`. null_message_router() ``` Constructs a null message router. -The router id will be `etl::imessage_router::NULL_MESSAGE_ROUTER`. +The router id will be `etl::message_processor::NULL_MESSAGE_ROUTER`. --- @@ -336,7 +368,7 @@ Returns an instance of `etl::null_message_router`. ## message_producer This router can be used as a producer-only of messages, such an interrupt routine. -Derived from `etl::imessage_router`. +Derived from `etl::message_processor`. --- @@ -376,7 +408,7 @@ Returns an instance of `etl::null_message_router`. ## Global functions ```cpp -void send_message(etl::imessage_router& router, +void send_message(etl::message_processor& router, const etl::imessage& message) ``` Send the message to the router. @@ -384,7 +416,7 @@ Send the message to the router. --- ```cpp -void send_message(etl::imessage_router& router, +void send_message(etl::message_processor& router, etl::message_router_id_t id, const etl::imessage& message) ``` @@ -393,7 +425,7 @@ Send the message to the router if it has the specified id. --- ```cpp -void send_message(etl::imessage_router& router, +void send_message(etl::message_processor& router, etl::shared_message& message) ``` Send the shared message to the router. @@ -401,7 +433,7 @@ Send the shared message to the router. --- ```cpp -void send_message(etl::imessage_router& router, +void send_message(etl::message_processor& router, etl::message_router_id_t id, etl::shared_message& message) ``` @@ -451,7 +483,7 @@ public: } // Received a start message. - void on_receive(etl::imessage_router& sender, const Start& msg) + void on_receive(const Start& msg) { std::cout << "Start message received\n"; } @@ -459,7 +491,7 @@ public: // Received a stop message. void on_receive(const Stop& msg) { - std::cout << "Start message received\n"; + std::cout << "Stop message received\n"; } // Received a set speed message. diff --git a/include/etl/message_broker.h b/include/etl/message_broker.h index 25e54f62..f6ef4a88 100644 --- a/include/etl/message_broker.h +++ b/include/etl/message_broker.h @@ -31,7 +31,7 @@ SOFTWARE. #include "platform.h" #include "message.h" -#include "message_router.h" +#include "message_processor.h" #include "message_types.h" #include "nullptr.h" #include "span.h" @@ -41,7 +41,7 @@ namespace etl //*************************************************************************** /// Message broker //*************************************************************************** - class message_broker : public etl::imessage_router + class message_broker : public etl::message_processor { private: @@ -101,7 +101,7 @@ namespace etl friend class message_broker; //******************************* - subscription(etl::imessage_router& router_) + subscription(etl::message_processor& router_) : p_router(&router_) { } @@ -112,7 +112,7 @@ namespace etl virtual message_id_span_t message_id_list() const = 0; //******************************* - etl::imessage_router* get_router() const + etl::message_processor* get_router() const { return p_router; } @@ -123,16 +123,16 @@ namespace etl return static_cast(get_next()); } - etl::imessage_router* const p_router; + etl::message_processor* const p_router; }; - using etl::imessage_router::receive; + using etl::message_processor::receive; //******************************************* /// Constructor. //******************************************* message_broker() - : imessage_router(etl::imessage_router::MESSAGE_BROKER) + : message_processor(etl::message_processor::MESSAGE_BROKER) , head() { } @@ -140,8 +140,8 @@ namespace etl //******************************************* /// Constructor. //******************************************* - message_broker(etl::imessage_router& successor_) - : imessage_router(etl::imessage_router::MESSAGE_BROKER, successor_) + message_broker(etl::message_processor& successor_) + : message_processor(etl::message_processor::MESSAGE_BROKER, successor_) , head() { } @@ -150,21 +150,21 @@ namespace etl /// Constructor. //******************************************* message_broker(etl::message_router_id_t id_) - : imessage_router(id_) + : message_processor(id_) , head() { - ETL_ASSERT((id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER) || (id_ == etl::imessage_router::MESSAGE_BROKER), + ETL_ASSERT((id_ <= etl::message_processor::MAX_MESSAGE_ROUTER) || (id_ == etl::message_processor::MESSAGE_BROKER), ETL_ERROR(etl::message_router_illegal_id)); } //******************************************* /// Constructor. //******************************************* - message_broker(etl::message_router_id_t id_, etl::imessage_router& successor_) - : imessage_router(id_, successor_) + message_broker(etl::message_router_id_t id_, etl::message_processor& successor_) + : message_processor(id_, successor_) , head() { - ETL_ASSERT((id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER) || (id_ == etl::imessage_router::MESSAGE_BROKER), + ETL_ASSERT((id_ <= etl::message_processor::MAX_MESSAGE_ROUTER) || (id_ == etl::message_processor::MESSAGE_BROKER), ETL_ERROR(etl::message_router_illegal_id)); } @@ -177,7 +177,7 @@ namespace etl } //******************************************* - void unsubscribe(etl::imessage_router& router) + void unsubscribe(etl::message_processor& router) { initialise_insertion_point(&router, ETL_NULLPTR); } @@ -185,16 +185,16 @@ namespace etl //******************************************* virtual void receive(const etl::imessage& msg) ETL_OVERRIDE { - receive(etl::imessage_router::ALL_MESSAGE_ROUTERS, msg); + receive(etl::message_processor::ALL_MESSAGE_ROUTERS, msg); } virtual void receive(etl::shared_message shared_msg) ETL_OVERRIDE { - receive(etl::imessage_router::ALL_MESSAGE_ROUTERS, shared_msg); + receive(etl::message_processor::ALL_MESSAGE_ROUTERS, shared_msg); } //******************************************* - virtual void receive(etl::message_router_id_t destination_router_id, const etl::imessage& msg) ETL_OVERRIDE + virtual void receive(etl::message_router_id_t destination_processor_id, const etl::imessage& msg) ETL_OVERRIDE { const etl::message_id_t id = msg.get_message_id(); @@ -211,9 +211,9 @@ namespace etl if (itr != message_ids.end()) { - etl::imessage_router* router = sub->get_router(); + etl::message_processor* router = sub->get_router(); - if (destination_router_id == etl::imessage_router::ALL_MESSAGE_ROUTERS || destination_router_id == router->get_message_router_id()) + if (destination_processor_id == etl::message_processor::ALL_MESSAGE_ROUTERS || destination_processor_id == router->get_message_processor_id()) { router->receive(msg); } @@ -226,12 +226,12 @@ namespace etl // Always pass the message on to the successor. if (has_successor()) { - get_successor().receive(destination_router_id, msg); + get_successor().receive(destination_processor_id, msg); } } //******************************************* - virtual void receive(etl::message_router_id_t destination_router_id, etl::shared_message shared_msg) ETL_OVERRIDE + virtual void receive(etl::message_router_id_t destination_processor_id, etl::shared_message shared_msg) ETL_OVERRIDE { const etl::message_id_t id = shared_msg.get_message().get_message_id(); @@ -248,9 +248,9 @@ namespace etl if (itr != message_ids.end()) { - etl::imessage_router* router = sub->get_router(); + etl::message_processor* router = sub->get_router(); - if (destination_router_id == etl::imessage_router::ALL_MESSAGE_ROUTERS || destination_router_id == router->get_message_router_id()) + if (destination_processor_id == etl::message_processor::ALL_MESSAGE_ROUTERS || destination_processor_id == router->get_message_processor_id()) { router->receive(shared_msg); } @@ -263,11 +263,11 @@ namespace etl // Always pass the message on to a successor. if (has_successor()) { - get_successor().receive(destination_router_id, shared_msg); + get_successor().receive(destination_processor_id, shared_msg); } } - using imessage_router::accepts; + using message_processor::accepts; //******************************************* /// Message brokers accept messages determined @@ -288,7 +288,7 @@ namespace etl if (itr != message_ids.end()) { - etl::imessage_router* router = sub->get_router(); + etl::message_processor* router = sub->get_router(); if (router->accepts(id)) { @@ -348,9 +348,9 @@ namespace etl private: //******************************************* - void initialise_insertion_point(const etl::imessage_router* p_router, etl::message_broker::subscription* p_new_sub) + void initialise_insertion_point(const etl::message_processor* p_router, etl::message_broker::subscription* p_new_sub) { - const etl::imessage_router* p_target_router = p_router; + const etl::message_processor* p_target_router = p_router; subscription_node* p_sub = head.get_next(); subscription_node* p_sub_previous = &head; diff --git a/include/etl/message_bus.h b/include/etl/message_bus.h index a5310ae8..9fb3d1cf 100644 --- a/include/etl/message_bus.h +++ b/include/etl/message_bus.h @@ -34,7 +34,7 @@ SOFTWARE. #include "error_handler.h" #include "exception.h" #include "message.h" -#include "message_router.h" +#include "message_processor.h" #include "message_types.h" #include "vector.h" @@ -73,36 +73,36 @@ namespace etl //*************************************************************************** /// Interface for message bus //*************************************************************************** - class imessage_bus : public etl::imessage_router + class imessage_bus : public etl::message_processor { private: - typedef etl::ivector router_list_t; + typedef etl::ivector processor_list_t; public: - using etl::imessage_router::receive; + using etl::message_processor::receive; //******************************************* /// Subscribe to the bus. //******************************************* - bool subscribe(etl::imessage_router& router) + bool subscribe(etl::message_processor& processor) { bool ok = true; - // There's no point adding routers that don't consume messages. - if (router.is_consumer()) + // There's no point adding processors that don't consume messages. + if (processor.is_consumer()) { - ok = !router_list.full(); + ok = !processor_list.full(); ETL_ASSERT(ok, ETL_ERROR(etl::message_bus_too_many_subscribers)); if (ok) { - router_list_t::iterator irouter = - etl::upper_bound(router_list.begin(), router_list.end(), router.get_message_router_id(), compare_router_id()); + processor_list_t::iterator iprocessor = + etl::upper_bound(processor_list.begin(), processor_list.end(), processor.get_message_processor_id(), compare_processor_id()); - router_list.insert(irouter, &router); + processor_list.insert(iprocessor, &processor); } } @@ -112,7 +112,7 @@ namespace etl //******************************************* /// Unsubscribe from the bus. //******************************************* - void unsubscribe(etl::message_router_id_t id) + void unsubscribe(etl::message_processor_id_t id) { if (id == etl::imessage_bus::ALL_MESSAGE_ROUTERS) { @@ -120,58 +120,58 @@ namespace etl } else { - ETL_OR_STD::pair range = - etl::equal_range(router_list.begin(), router_list.end(), id, compare_router_id()); + ETL_OR_STD::pair range = + etl::equal_range(processor_list.begin(), processor_list.end(), id, compare_processor_id()); - router_list.erase(range.first, range.second); + processor_list.erase(range.first, range.second); } } //******************************************* - void unsubscribe(etl::imessage_router& router) + void unsubscribe(etl::message_processor& processor) { - router_list_t::iterator irouter = etl::find(router_list.begin(), router_list.end(), &router); + processor_list_t::iterator iprocessor = etl::find(processor_list.begin(), processor_list.end(), &processor); - if (irouter != router_list.end()) + if (iprocessor != processor_list.end()) { - router_list.erase(irouter); + processor_list.erase(iprocessor); } } //******************************************* virtual void receive(const etl::imessage& message) ETL_OVERRIDE { - receive(etl::imessage_router::ALL_MESSAGE_ROUTERS, message); + receive(etl::message_processor::ALL_MESSAGE_ROUTERS, message); } //******************************************* virtual void receive(etl::shared_message shared_msg) ETL_OVERRIDE { - receive(etl::imessage_router::ALL_MESSAGE_ROUTERS, shared_msg); + receive(etl::message_processor::ALL_MESSAGE_ROUTERS, shared_msg); } //******************************************* - virtual void receive(etl::message_router_id_t destination_router_id, const etl::imessage& message) ETL_OVERRIDE + virtual void receive(etl::message_processor_id_t destination_processor_id, const etl::imessage& message) ETL_OVERRIDE { - switch (destination_router_id) + switch (destination_processor_id) { //***************************** - // Broadcast to all routers. - case etl::imessage_router::ALL_MESSAGE_ROUTERS: + // Broadcast to all processors. + case etl::message_processor::ALL_MESSAGE_ROUTERS: { - router_list_t::iterator irouter = router_list.begin(); + processor_list_t::iterator iprocessor = processor_list.begin(); // Broadcast to everyone. - while (irouter != router_list.end()) + while (iprocessor != processor_list.end()) { - etl::imessage_router& router = **irouter; + etl::message_processor& processor = **iprocessor; - if (router.accepts(message.get_message_id())) + if (processor.accepts(message.get_message_id())) { - router.receive(message); + processor.receive(message); } - ++irouter; + ++iprocessor; } break; @@ -181,11 +181,11 @@ namespace etl // Must be an addressed message. default: { - router_list_t::iterator irouter = router_list.begin(); + processor_list_t::iterator iprocessor = processor_list.begin(); - // Find routers with the id. - ETL_OR_STD::pair range = - etl::equal_range(router_list.begin(), router_list.end(), destination_router_id, compare_router_id()); + // Find processors with the id. + ETL_OR_STD::pair range = + etl::equal_range(processor_list.begin(), processor_list.end(), destination_processor_id, compare_processor_id()); // Call all of them. while (range.first != range.second) @@ -200,14 +200,14 @@ namespace etl // Do any message buses. // These are always at the end of the list. - irouter = etl::lower_bound(router_list.begin(), router_list.end(), etl::imessage_bus::MESSAGE_BUS, compare_router_id()); + iprocessor = etl::lower_bound(processor_list.begin(), processor_list.end(), etl::imessage_bus::MESSAGE_BUS, compare_processor_id()); - while (irouter != router_list.end()) + while (iprocessor != processor_list.end()) { // So pass it on. - (*irouter)->receive(destination_router_id, message); + (*iprocessor)->receive(destination_processor_id, message); - ++irouter; + ++iprocessor; } break; @@ -218,33 +218,33 @@ namespace etl { if (get_successor().accepts(message.get_message_id())) { - get_successor().receive(destination_router_id, message); + get_successor().receive(destination_processor_id, message); } } } //******************************************** - virtual void receive(etl::message_router_id_t destination_router_id, etl::shared_message shared_msg) ETL_OVERRIDE + virtual void receive(etl::message_processor_id_t destination_processor_id, etl::shared_message shared_msg) ETL_OVERRIDE { - switch (destination_router_id) + switch (destination_processor_id) { //***************************** - // Broadcast to all routers. - case etl::imessage_router::ALL_MESSAGE_ROUTERS: + // Broadcast to all processors. + case etl::message_processor::ALL_MESSAGE_ROUTERS: { - router_list_t::iterator irouter = router_list.begin(); + processor_list_t::iterator iprocessor = processor_list.begin(); // Broadcast to everyone. - while (irouter != router_list.end()) + while (iprocessor != processor_list.end()) { - etl::imessage_router& router = **irouter; + etl::message_processor& processor = **iprocessor; - if (router.accepts(shared_msg.get_message().get_message_id())) + if (processor.accepts(shared_msg.get_message().get_message_id())) { - router.receive(shared_msg); + processor.receive(shared_msg); } - ++irouter; + ++iprocessor; } break; @@ -254,9 +254,9 @@ namespace etl // Must be an addressed message. default: { - // Find routers with the id. - ETL_OR_STD::pair range = - etl::equal_range(router_list.begin(), router_list.end(), destination_router_id, compare_router_id()); + // Find processors with the id. + ETL_OR_STD::pair range = + etl::equal_range(processor_list.begin(), processor_list.end(), destination_processor_id, compare_processor_id()); // Call all of them. while (range.first != range.second) @@ -271,15 +271,15 @@ namespace etl // Do any message buses. // These are always at the end of the list. - router_list_t::iterator irouter = - etl::lower_bound(router_list.begin(), router_list.end(), etl::imessage_bus::MESSAGE_BUS, compare_router_id()); + processor_list_t::iterator iprocessor = + etl::lower_bound(processor_list.begin(), processor_list.end(), etl::imessage_bus::MESSAGE_BUS, compare_processor_id()); - while (irouter != router_list.end()) + while (iprocessor != processor_list.end()) { // So pass it on. - (*irouter)->receive(destination_router_id, shared_msg); + (*iprocessor)->receive(destination_processor_id, shared_msg); - ++irouter; + ++iprocessor; } break; @@ -290,32 +290,32 @@ namespace etl { if (get_successor().accepts(shared_msg.get_message().get_message_id())) { - get_successor().receive(destination_router_id, shared_msg); + get_successor().receive(destination_processor_id, shared_msg); } } } - using imessage_router::accepts; + using message_processor::accepts; //******************************************* /// Does this message bus accept the message id? - /// Returns true on the first router that does. + /// Returns true on the first processor that does. //******************************************* bool accepts(etl::message_id_t id) const ETL_OVERRIDE { - // Check the list of subscribed routers. - router_list_t::iterator irouter = router_list.begin(); + // Check the list of subscribed processors. + processor_list_t::iterator iprocessor = processor_list.begin(); - while (irouter != router_list.end()) + while (iprocessor != processor_list.end()) { - etl::imessage_router& router = **irouter; + etl::message_processor& processor = **iprocessor; - if (router.accepts(id)) + if (processor.accepts(id)) { return true; } - ++irouter; + ++iprocessor; } // Check any successor. @@ -333,13 +333,13 @@ namespace etl //******************************************* size_t size() const { - return router_list.size(); + return processor_list.size(); } //******************************************* void clear() { - router_list.clear(); + processor_list.clear(); } //******************************************** @@ -366,40 +366,40 @@ namespace etl //******************************************* /// Constructor. //******************************************* - imessage_bus(router_list_t& list) - : imessage_router(etl::imessage_router::MESSAGE_BUS) - , router_list(list) + imessage_bus(processor_list_t& list) + : message_processor(etl::message_processor::MESSAGE_BUS) + , processor_list(list) { } //******************************************* /// Constructor. //******************************************* - imessage_bus(router_list_t& router_list_, etl::imessage_router& successor_) - : imessage_router(etl::imessage_router::MESSAGE_BUS, successor_) - , router_list(router_list_) + imessage_bus(processor_list_t& processor_list_, etl::message_processor& successor_) + : message_processor(etl::message_processor::MESSAGE_BUS, successor_) + , processor_list(processor_list_) { } private: //******************************************* - // How to compare routers to router ids. + // How to compare processors to processor ids. //******************************************* - struct compare_router_id + struct compare_processor_id { - bool operator()(const etl::imessage_router* prouter, etl::message_router_id_t id) const + bool operator()(const etl::message_processor* pprocessor, etl::message_processor_id_t id) const { - return prouter->get_message_router_id() < id; + return pprocessor->get_message_processor_id() < id; } - bool operator()(etl::message_router_id_t id, const etl::imessage_router* prouter) const + bool operator()(etl::message_processor_id_t id, const etl::message_processor* pprocessor) const { - return id < prouter->get_message_router_id(); + return id < pprocessor->get_message_processor_id(); } }; - router_list_t& router_list; + processor_list_t& processor_list; }; //*************************************************************************** @@ -414,21 +414,21 @@ namespace etl /// Constructor. //******************************************* message_bus() - : imessage_bus(router_list) + : imessage_bus(processor_list) { } //******************************************* /// Constructor. //******************************************* - message_bus(etl::imessage_router& successor_) - : imessage_bus(router_list, successor_) + message_bus(etl::message_processor& successor_) + : imessage_bus(processor_list, successor_) { } private: - etl::vector router_list; + etl::vector processor_list; }; } // namespace etl diff --git a/include/etl/message_processor.h b/include/etl/message_processor.h new file mode 100644 index 00000000..ea20b568 --- /dev/null +++ b/include/etl/message_processor.h @@ -0,0 +1,1013 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 John Wellbelove + +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_PROCESSOR_INCLUDED +#define ETL_MESSAGE_PROCESSOR_INCLUDED + +#include "platform.h" +#include "alignment.h" +#include "array.h" +#include "error_handler.h" +#include "exception.h" +#include "largest.h" +#include "message.h" +#include "message_packet.h" +#include "message_types.h" +#include "shared_message.h" +#include "successor.h" +#include "type_list.h" +#include "type_traits.h" + +#include + +namespace etl +{ + struct message_processor_tag + { + enum + { + // Old constants for backwards compatibility. + NULL_MESSAGE_ROUTER = 255, + MESSAGE_BUS = 254, + ALL_MESSAGE_ROUTERS = 253, + MESSAGE_BROKER = 252, + MESSAGE_ROUTER = 251, + MAX_MESSAGE_ROUTER = 249, + + // New constants, compatible with the old ones. + Null_Message_Router = NULL_MESSAGE_ROUTER, + Message_Bus = MESSAGE_BUS, + All_Message_Processors = ALL_MESSAGE_ROUTERS, + Message_Broker = MESSAGE_BROKER, + Message_Router = MESSAGE_ROUTER, + Max_Message_Router = MAX_MESSAGE_ROUTER + }; + }; + + //*************************************************************************** + /// + //*************************************************************************** + class router_id + { + public: + + typedef etl::message_router_id_t value_type; + + //*********************************** + explicit ETL_CONSTEXPR router_id(value_type id_) + : id(id_) + { + } + + //*********************************** + ETL_CONSTEXPR value_type value() const + { + return id; + } + + //*********************************** + ETL_CONSTEXPR operator value_type() const + { + return value(); + } + + //*********************************** + ETL_CONSTEXPR bool is_all_routers() const + { + return (id == message_processor_tag::All_Message_Processors); + } + + //*********************************** + ETL_CONSTEXPR bool is_null_router() const + { + return (id == message_processor_tag::Null_Message_Router); + } + + //*********************************** + ETL_CONSTEXPR bool is_message_bus() const + { + return (id == message_processor_tag::Message_Bus); + } + + //*********************************** + ETL_CONSTEXPR bool is_message_broker() const + { + return (id == message_processor_tag::Message_Broker); + } + + private: + + etl::message_router_id_t id; + }; + + //*************************************************************************** + /// + //*************************************************************************** + class source_router_id : public router_id + { + public: + + typedef etl::message_router_id_t value_type; + + explicit ETL_CONSTEXPR source_router_id(value_type id_) + : router_id(id_) + { + } + }; + + //*************************************************************************** + /// + //*************************************************************************** + class destination_router_id : public router_id + { + public: + + typedef etl::message_router_id_t value_type; + + explicit ETL_CONSTEXPR destination_router_id(value_type id_) + : router_id(id_) + { + } + }; + + //*************************************************************************** + /// Base exception class for message router + //*************************************************************************** + class message_router_exception : public etl::exception + { + public: + + message_router_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : etl::exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Router id is out of the legal range. + //*************************************************************************** + class message_processor_illegal_id : public etl::message_router_exception + { + public: + + message_processor_illegal_id(string_type file_name_, numeric_type line_number_) + : message_router_exception(ETL_ERROR_TEXT("message processor:illegal id", ETL_MESSAGE_ROUTER_FILE_ID"A"), file_name_, line_number_) + { + } + }; + + // For backward compatibility. + typedef message_processor_illegal_id message_router_illegal_id; + + namespace private_message_router + { +#if ETL_USING_CPP11 + //*************************************************************************** + // Traits for a message router. + // message packet type + // message type_list + // sorted message type_list. + //*************************************************************************** + template + class traits + { + private: + + using message_id_sequence = etl::index_sequence; + + public: + + using message_packet = etl::message_packet; + using message_types = etl::type_list; + using sorted_message_types = etl::type_list_sort_t; + + static_assert(etl::type_list_is_unique::value, "All TMessageTypes must be unique"); + static_assert(etl::type_list_all_of::value, + "All TMessageTypes must satisfy the condition etl::is_message_type"); + static_assert(etl::index_sequence_is_unique::value, "All message IDs must be unique"); + }; + + //*************************************************************************** + // Specialisation of traits for no message types. + // message packet type + // message type_list + // sorted message type_list. + //*************************************************************************** + template <> + class traits<> + { + public: + + using message_packet = etl::message_packet<>; + using message_types = etl::type_list<>; + using sorted_message_types = etl::type_list<>; + }; +#else + //*************************************************************************** + // C++03 empty traits placeholder. + //*************************************************************************** + template + class traits + { + }; +#endif + } // namespace private_message_router + + //*************************************************************************** + /// Forward declare null message router functionality. + //*************************************************************************** + class message_processor; + + etl::message_processor& get_null_message_router(); + + //*************************************************************************** + /// This is the base of all message routers. + //*************************************************************************** + class message_processor + : public etl::successor + , public etl::message_processor_tag + + { + public: + + virtual ~message_processor() {} + virtual void receive(const etl::imessage&) = 0; + virtual bool accepts(etl::message_id_t) const = 0; + virtual bool is_null_router() const = 0; + virtual bool is_producer() const = 0; + virtual bool is_consumer() const = 0; + + //******************************************** + virtual void receive(etl::message_router_id_t destination_router_id, const etl::imessage& message) + { + if ((destination_router_id == get_message_processor_id()) || (destination_router_id == message_processor::All_Message_Processors)) + { + receive(message); + } + } + + //******************************************** + virtual void receive(etl::shared_message shared_msg) + { + receive(shared_msg.get_message()); + } + + //******************************************** + virtual void receive(etl::message_router_id_t destination_router_id, etl::shared_message shared_msg) + { + if ((destination_router_id == get_message_processor_id()) || (destination_router_id == message_processor::All_Message_Processors)) + { + receive(shared_msg); + } + } + + //******************************************** + 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_processor_id; + } + + //******************************************** + etl::message_processor_id_t get_message_processor_id() const + { + return message_processor_id; + } + + protected: + + message_processor(etl::message_router_id_t id_) + : message_processor_id(id_) + { + } + + message_processor(etl::message_router_id_t id_, message_processor& successor_) + : successor(successor_) + , message_processor_id(id_) + { + } + + private: + + // Disabled. + message_processor(const message_processor&); + message_processor& operator=(const message_processor&); + + etl::message_router_id_t message_processor_id; + }; + + // For backward compatibility + typedef message_processor imessage_router; + + //*************************************************************************** + /// This router can be used as a sink for messages or a 'null source' router. + //*************************************************************************** + class null_message_router + : public message_processor + , public private_message_router::traits<> + { + public: + + //******************************************** + null_message_router() + : message_processor(message_processor::Null_Message_Router) + { + } + + //******************************************** + null_message_router(etl::message_processor& successor_) + : message_processor(message_processor::Null_Message_Router, successor_) + { + } + + //******************************************** + using etl::message_processor::receive; + + void receive(const etl::imessage& msg) ETL_OVERRIDE + { + if (has_successor()) + { + get_successor().receive(msg); + } + } + + //******************************************** + using etl::message_processor::accepts; + + bool accepts(etl::message_id_t id) const ETL_OVERRIDE + { + if (has_successor()) + { + return get_successor().accepts(id); + } + else + { + return false; + } + } + + //******************************************** + ETL_DEPRECATED + bool is_null_router() const ETL_OVERRIDE + { + return true; + } + + //******************************************** + bool is_producer() const ETL_OVERRIDE + { + return false; + } + + //******************************************** + bool is_consumer() const ETL_OVERRIDE + { + return false; + } + + //******************************************** + static null_message_router& instance() + { + static null_message_router nmr; + return nmr; + } + }; + + //*********************************************** + /// null message router functionality. + inline etl::message_processor& get_null_message_router() + { + return etl::null_message_router::instance(); + } + + //*************************************************************************** + /// This router can be used as a producer-only of messages, such an interrupt + /// routine. + //*************************************************************************** + class message_producer + : public message_processor + , public private_message_router::traits<> + { + public: + + //******************************************** + message_producer() + : message_processor(etl::message_processor::Message_Router) + { + } + + //******************************************** + message_producer(etl::message_processor& successor_) + : message_processor(message_processor::Null_Message_Router, successor_) + { + } + + //******************************************** + message_producer(etl::message_router_id_t id_) + : message_processor(id_) + { + ETL_ASSERT(id_ <= etl::message_processor::Max_Message_Router, ETL_ERROR(etl::message_processor_illegal_id)); + } + + //******************************************** + message_producer(etl::message_router_id_t id_, etl::message_processor& successor_) + : message_processor(id_, successor_) + { + ETL_ASSERT(id_ <= etl::message_processor::Max_Message_Router, ETL_ERROR(etl::message_processor_illegal_id)); + } + + //******************************************** + using etl::message_processor::receive; + + void receive(const etl::imessage& msg) ETL_OVERRIDE + { + if (has_successor()) + { + get_successor().receive(msg); + } + } + + //******************************************** + using etl::message_processor::accepts; + + bool accepts(etl::message_id_t id) const ETL_OVERRIDE + { + if (has_successor()) + { + return get_successor().accepts(id); + } + else + { + return false; + } + } + + //******************************************** + ETL_DEPRECATED + bool is_null_router() const ETL_OVERRIDE + { + return false; + } + + //******************************************** + bool is_producer() const ETL_OVERRIDE + { + return true; + } + + //******************************************** + bool is_consumer() const ETL_OVERRIDE + { + return false; + } + }; + + //*************************************************************************** + /// Is T ultimately derived from etl::message_processor? + //*************************************************************************** + template + struct is_message_router : public etl::bool_constant< etl::is_base_of< etl::message_processor, typename etl::remove_cvref::type>::value> + { + }; + + //*************************************************************************** + /// Send a message to a router. + //*************************************************************************** + template + static typename etl::enable_if< etl::is_message_router::value && etl::is_message::value, void>::type + send_message(TRouter& destination, const TMessage& message) + { + destination.receive(message); + } + + //*************************************************************************** + /// Send a shared message to a router. + //*************************************************************************** + template + static typename etl::enable_if::value, void>::type send_message(TRouter& destination, etl::shared_message message) + { + destination.receive(message); + } + + //*************************************************************************** + /// Send a message to a router with a particular id. + //*************************************************************************** + template + static typename etl::enable_if< etl::is_message_router::value && etl::is_message::value, void>::type + send_message(TRouter& destination, etl::message_router_id_t id, const TMessage& message) + { + destination.receive(id, message); + } + + //*************************************************************************** + /// Send a shared message to a router with a particular id. + //*************************************************************************** + template + static typename etl::enable_if::value, void>::type send_message(TRouter& destination, etl::message_router_id_t id, + etl::shared_message message) + { + destination.receive(id, message); + } + + //************************************************************************************************* + // For C++11 and above. + //************************************************************************************************* +#if ETL_USING_CPP11 && !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION) + //*************************************************************************** + // The definition for all message types. + //*************************************************************************** + template + class message_router + : public message_processor + , public private_message_router::traits + { + public: + + using typename private_message_router::traits::message_packet; + using typename private_message_router::traits::message_types; + using typename private_message_router::traits< TMessageTypes...>::sorted_message_types; + + //********************************************** + /// Default constructor. The message router id will be MESSAGE_ROUTER. + //********************************************** + message_router() + : message_processor(etl::message_processor::Message_Router) + { + } + + //********************************************** + /// Constructor with successor. The message router id will be + /// MESSAGE_ROUTER. + //********************************************** + message_router(etl::message_processor& successor_) + : message_processor(etl::message_processor::Message_Router, successor_) + { + } + + //********************************************** + /// Constructor with message router id. + //********************************************** + message_router(etl::message_router_id_t id_) + : message_processor(id_) + { + ETL_ASSERT(id_ <= etl::message_processor::Max_Message_Router, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + /// Constructor with message router id and successor. + //********************************************** + message_router(etl::message_router_id_t id_, etl::message_processor& successor_) + : message_processor(id_, successor_) + { + ETL_ASSERT(id_ <= etl::message_processor::Max_Message_Router, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + /// Allow visibility of base class receive() methods. + //********************************************** + using etl::message_processor::receive; + + //********************************************** + /// This will be called for all messages passed as an etl::imessage. + /// It will dispatch the message to the correct handler based on the message + /// id, or pass it to a successor if there is no handler for the message id. + /// \param msg The message. + //*********************************************** + void receive(const etl::imessage& msg) ETL_OVERRIDE + { + const etl::message_id_t id = msg.get_message_id(); + + // The IDs are sorted, so an ID less than the first is not handled by this + // router. + if (id >= Message_Id_Start) + { + const size_t index = get_dispatch_index_from_message_id(id); + + // If the index is less than Number_Of_Messages, then we have a handler + // for this message type, so dispatch it. + if (index < Number_Of_Messages) + { + dispatch(msg, index); + return; + } + } + + // We don't have a handler for this message type, so pass it to a + // successor if there is one, or call on_receive_unknown() if there isn't. + if (has_successor()) + { + get_successor().receive(msg); + } + else + { + #include "etl/private/diagnostic_array_bounds_push.h" + static_cast(this)->on_receive_unknown(msg); + #include "etl/private/diagnostic_pop.h" + } + } + + //********************************************** + /// This will be called for messages where TMessage is in the message type + /// list. \tparam TMessage The message type. \param msg The message. Enabled + /// if TMessage is in the message type list. + //********************************************** + template < typename TMessage, typename etl::enable_if::value, int>::type = 0> + void receive(const TMessage& msg) + { + #include "etl/private/diagnostic_array_bounds_push.h" + static_cast(this)->on_receive(msg); + #include "etl/private/diagnostic_pop.h" + } + + //********************************************** + /// This will be called for messages where TMessage is a message type, but + /// not in the message type list. \tparam TMessage The message type. \param + /// msg The message. Enabled if TMessage is a message type, but not in the + /// message type list. + //********************************************** + template ::value && !etl::is_one_of::value, int>::type = 0> + void receive(const TMessage& msg) + { + if (has_successor()) + { + get_successor().receive(msg); + } + else + { + #include "etl/private/diagnostic_array_bounds_push.h" + static_cast(this)->on_receive_unknown(msg); + #include "etl/private/diagnostic_pop.h" + } + } + + //********************************************** + /// Allow visibility of base class accepts() methods. + //********************************************** + using message_processor::accepts; + + //********************************************** + /// This will return true if the message id is in the message type list, or + /// if a successor accepts the message id. + //*********************************************** + bool accepts(etl::message_id_t id) const ETL_OVERRIDE + { + if (id >= Message_Id_Start) + { + const size_t index = get_dispatch_index_from_message_id(id); + + if (index < Number_Of_Messages) + { + return true; + } + } + + return has_successor() ? get_successor().accepts(id) : false; + } + + //******************************************** + ETL_DEPRECATED + bool is_null_router() const ETL_OVERRIDE + { + return false; + } + + //******************************************** + bool is_producer() const ETL_OVERRIDE + { + return true; + } + + //******************************************** + bool is_consumer() const ETL_OVERRIDE + { + return true; + } + + private: + + static constexpr size_t Number_Of_Messages = sizeof...(TMessageTypes); + static constexpr etl::message_id_t Message_Id_Start = etl::type_list_type_at_index_t::ID; + + //********************************************** + // Checks that the message ids are contiguous. + //********************************************** + template = Number_Of_Messages)> + struct contiguous_impl; + + template + struct contiguous_impl : etl::true_type + { + }; + + template + struct contiguous_impl + : etl::bool_constant< (etl::type_list_type_at_index_t::ID + 1U + == etl::type_list_type_at_index_t::ID) + && contiguous_impl::value> + { + }; + + // The message ids are contiguous if there are 0 or 1 message types, or if + // each message id is one greater than the previous message id. + static constexpr bool Message_Ids_Are_Contiguous = (Number_Of_Messages <= 1U) ? true : contiguous_impl<0U>::value; + + using handler_ptr = void (*)(TDerived&, + const etl::imessage&); ///< Pointer to a handler function that + ///< takes a reference to the derived + ///< class and a reference to the message. + using message_dispatch_table_t = etl::array; ///< The dispatch table type. An array of + ///< handler pointers, one for each + ///< message type. + using message_id_table_t = etl::array; ///< The message id table type. An + ///< array of message ids, one for + ///< each message type. + + //********************************************** + // Call for a single message type + //********************************************** + template + static void call_on_receive(TDerived& derived, const imessage& msg) + { + derived.on_receive(static_cast(msg)); + } + + //********************************************** + // Get the handler for a single message type at the index in the sorted + // type_list. This will be called for each message type to generate the + // dispatch table. + //********************************************** + template + static constexpr handler_ptr get_message_handler() + { + return &call_on_receive< etl::type_list_type_at_index_t>; + } + + //********************************************** + // Generate the dispatch table at compile time. + // This will create an array of handler pointers, one for each message type. + //********************************************** + template + static constexpr message_dispatch_table_t make_message_dispatch_table(etl::index_sequence) + { + return message_dispatch_table_t{{get_message_handler()...}}; + } + + //********************************************** + // Get the message id for a single message type at an index in the sorted + // type_list. This will be called for each message type to generate the + // message id table. + //********************************************** + template + static constexpr etl::message_id_t get_message_id_from_index() + { + return etl::type_list_type_at_index_t::ID; + } + + //********************************************** + // Generate the message id table at compile time. + // This will create an array of message ids, one for each message type. + //********************************************** + template + static constexpr message_id_table_t make_message_id_table(etl::index_sequence) + { + return message_id_table_t{{get_message_id_from_index()...}}; + } + + //********************************************** + // Get the dispatch index for a message id. + // This will be used at runtime to find the handler for a message id. + // If the message ids are contiguous, we can calculate the index directly. + // If they are not contiguous, we need to do a binary search. This will + // return Number_Of_Messages if the message id is not found, which indicates + // that the message should be passed to the successor. + //********************************************** + static size_t get_dispatch_index_from_message_id(etl::message_id_t id) + { + if ETL_IF_CONSTEXPR (Message_Ids_Are_Contiguous) + { + // The IDs are contiguous, so we can calculate the index directly. + return static_cast(id - Message_Id_Start); + } + else + { + // The IDs are not contiguous, so we need to do a binary search. + size_t left = 0; + size_t right = Number_Of_Messages; + + while (left < right) + { + size_t mid = (left + right) / 2; + + if (message_id_table[mid] == id) + { + return mid; + } + else if (message_id_table[mid] < id) + { + left = mid + 1; + } + else + { + right = mid; + } + } + } + + return Number_Of_Messages; // Not found + } + + //********************************************** + // Dispatch the message to the appropriate handler based on the index in the + // dispatch table. + //********************************************** + void dispatch(const etl::imessage& msg, size_t index) + { + message_dispatch_table[index](static_cast(*this), msg); + } + + //********************************************** + // The dispatch table is generated at compile time. The dispatch table + // contains pointers to the on_receive handlers for each message type. + //********************************************** + static ETL_INLINE_VAR constexpr message_dispatch_table_t message_dispatch_table = + etl::message_router::make_message_dispatch_table( + etl::make_index_sequence< etl::message_router< TDerived, TMessageTypes...>::Number_Of_Messages>{}); + + //********************************************** + // The message id table is generated at compile time. The message id table + // contains the corresponding message ids for each message type. + //********************************************** + static ETL_INLINE_VAR constexpr message_id_table_t message_id_table = etl::message_router::make_message_id_table( + etl::make_index_sequence< etl::message_router< TDerived, TMessageTypes...>::Number_Of_Messages>{}); + }; + + #if ETL_USING_CPP11 && !ETL_USING_CPP17 + template + constexpr const typename etl::message_router< TDerived, TMessageTypes...>::message_dispatch_table_t + etl::message_router::message_dispatch_table; + + template + constexpr const typename etl::message_router< TDerived, TMessageTypes...>::message_id_table_t + etl::message_router::message_id_table; + #endif + + //*************************************************************************** + // The definition of a message_router for zero message types. + //*************************************************************************** + template + class message_router + : public message_processor + , public private_message_router::traits<> + { + public: + + //********************************************** + /// Default constructor. The message router id will be MESSAGE_ROUTER. + //********************************************** + message_router() + : message_processor(etl::message_processor::Message_Router) + { + } + + //********************************************** + /// Constructor with successor. The message router id will be + /// MESSAGE_ROUTER. + //********************************************** + message_router(etl::message_processor& successor_) + : message_processor(etl::message_processor::Message_Router, successor_) + { + } + + //********************************************** + /// Constructor with message router id. + //********************************************** + message_router(etl::message_router_id_t id_) + : message_processor(id_) + { + ETL_ASSERT(id_ <= etl::message_processor::Max_Message_Router, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + /// Constructor with message router id and successor. + //********************************************** + message_router(etl::message_router_id_t id_, etl::message_processor& successor_) + : message_processor(id_, successor_) + { + ETL_ASSERT(id_ <= etl::message_processor::Max_Message_Router, ETL_ERROR(etl::message_router_illegal_id)); + } + + //********************************************** + /// Allow visibility of base class receive() methods. + using etl::message_processor::receive; + + //********************************************** + /// This will be called for all messages passed as an etl::imessage. + /// Since there are no message types, this will just pass the message to a + /// successor if there is one, or call on_receive_unknown() if there isn't. + /// \param msg The message. + //*********************************************** + void receive(const etl::imessage& msg) ETL_OVERRIDE + { + #include "etl/private/diagnostic_array_bounds_push.h" + if (has_successor()) + { + get_successor().receive(msg); + } + #include "etl/private/diagnostic_pop.h" + } + + //********************************************** + /// Allow visibility of base class accepts() methods. + //********************************************** + using message_processor::accepts; + + //********************************************** + /// This will return true if a successor accepts the message id. + //*********************************************** + bool accepts(etl::message_id_t id) const ETL_OVERRIDE + { + if (has_successor()) + { + return get_successor().accepts(id); + } + else + { + return false; + } + } + + //******************************************** + ETL_DEPRECATED + bool is_null_router() const ETL_OVERRIDE + { + return false; + } + + //******************************************** + bool is_producer() const ETL_OVERRIDE + { + return true; + } + + //******************************************** + bool is_consumer() const ETL_OVERRIDE + { + return true; + } + }; + + //*************************************************************************** + /// Helper to turn etl::type_list into + /// etl::message_router + //*************************************************************************** + template + struct message_router_from_type_list; + + template + struct message_router_from_type_list> + { + using type = etl::message_router; + }; + + template + using message_router_from_type_list_t = typename message_router_from_type_list::type; + +#else + #include "private/message_router_cpp03.h" +#endif +} // namespace etl + +#endif diff --git a/include/etl/message_router.h b/include/etl/message_router.h index 6461da00..ca39959d 100644 --- a/include/etl/message_router.h +++ b/include/etl/message_router.h @@ -5,7 +5,7 @@ Embedded Template Library. https://github.com/ETLCPP/etl https://www.etlcpp.com -Copyright(c) 2017 John Wellbelove +Copyright(c) 2026 John Wellbelove Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal @@ -29,872 +29,8 @@ SOFTWARE. #ifndef ETL_MESSAGE_ROUTER_INCLUDED #define ETL_MESSAGE_ROUTER_INCLUDED -#include "platform.h" -#include "alignment.h" -#include "array.h" -#include "error_handler.h" -#include "exception.h" -#include "largest.h" -#include "message.h" -#include "message_packet.h" -#include "message_types.h" -#include "shared_message.h" -#include "successor.h" -#include "type_list.h" -#include "type_traits.h" - -#include - -namespace etl -{ - //*************************************************************************** - /// Base exception class for message router - //*************************************************************************** - class message_router_exception : public etl::exception - { - public: - - message_router_exception(string_type reason_, string_type file_name_, numeric_type line_number_) - : etl::exception(reason_, 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_MESSAGE_ROUTER_FILE_ID"A"), file_name_, line_number_) - { - } - }; - - namespace private_message_router - { -#if ETL_USING_CPP11 - //*************************************************************************** - // Traits for a message router. - // message packet type - // message type_list - // sorted message type_list. - //*************************************************************************** - template - class traits - { - private: - - using message_id_sequence = etl::index_sequence; - - public: - - using message_packet = etl::message_packet; - using message_types = etl::type_list; - using sorted_message_types = etl::type_list_sort_t; - - static_assert(etl::type_list_is_unique::value, "All TMessageTypes must be unique"); - static_assert(etl::type_list_all_of::value, - "All TMessageTypes must satisfy the condition etl::is_message_type"); - static_assert(etl::index_sequence_is_unique::value, "All message IDs must be unique"); - }; - - //*************************************************************************** - // Specialisation of traits for no message types. - // message packet type - // message type_list - // sorted message type_list. - //*************************************************************************** - template <> - class traits<> - { - public: - - using message_packet = etl::message_packet<>; - using message_types = etl::type_list<>; - using sorted_message_types = etl::type_list<>; - }; -#else - //*************************************************************************** - // C++03 empty traits placeholder. - //*************************************************************************** - template - class traits - { - }; -#endif - } // namespace private_message_router - - //*************************************************************************** - /// Forward declare null message router functionality. - //*************************************************************************** - class imessage_router; - - etl::imessage_router& get_null_message_router(); - - //*************************************************************************** - /// This is the base of all message routers. - //*************************************************************************** - class imessage_router : public etl::successor - { - public: - - virtual ~imessage_router() {} - virtual void receive(const etl::imessage&) = 0; - virtual bool accepts(etl::message_id_t) const = 0; - virtual bool is_null_router() const = 0; - virtual bool is_producer() const = 0; - virtual bool is_consumer() const = 0; - - //******************************************** - virtual void receive(etl::message_router_id_t destination_router_id, const etl::imessage& message) - { - if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) - { - receive(message); - } - } - - //******************************************** - virtual void receive(etl::shared_message shared_msg) - { - receive(shared_msg.get_message()); - } - - //******************************************** - virtual void receive(etl::message_router_id_t destination_router_id, etl::shared_message shared_msg) - { - if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) - { - receive(shared_msg); - } - } - - //******************************************** - 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, - MESSAGE_BROKER = 252, - MESSAGE_ROUTER = 251, - MAX_MESSAGE_ROUTER = 249 - }; - - protected: - - imessage_router(etl::message_router_id_t id_) - : message_router_id(id_) - { - } - - imessage_router(etl::message_router_id_t id_, imessage_router& successor_) - : successor(successor_) - , 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 as a sink for messages or a 'null source' router. - //*************************************************************************** - class null_message_router - : public imessage_router - , public private_message_router::traits<> - { - public: - - //******************************************** - null_message_router() - : imessage_router(imessage_router::NULL_MESSAGE_ROUTER) - { - } - - //******************************************** - null_message_router(etl::imessage_router& successor_) - : imessage_router(imessage_router::NULL_MESSAGE_ROUTER, successor_) - { - } - - //******************************************** - using etl::imessage_router::receive; - - void receive(const etl::imessage& msg) ETL_OVERRIDE - { - if (has_successor()) - { - get_successor().receive(msg); - } - } - - //******************************************** - using etl::imessage_router::accepts; - - bool accepts(etl::message_id_t id) const ETL_OVERRIDE - { - if (has_successor()) - { - return get_successor().accepts(id); - } - else - { - return false; - } - } - - //******************************************** - ETL_DEPRECATED - bool is_null_router() const ETL_OVERRIDE - { - return true; - } - - //******************************************** - bool is_producer() const ETL_OVERRIDE - { - return false; - } - - //******************************************** - bool is_consumer() const ETL_OVERRIDE - { - return false; - } - - //******************************************** - static null_message_router& instance() - { - static null_message_router nmr; - return nmr; - } - }; - - //*********************************************** - /// null message router functionality. - inline etl::imessage_router& get_null_message_router() - { - return etl::null_message_router::instance(); - } - - //*************************************************************************** - /// This router can be used as a producer-only of messages, such an interrupt - /// routine. - //*************************************************************************** - class message_producer - : public imessage_router - , public private_message_router::traits<> - { - public: - - //******************************************** - message_producer() - : imessage_router(etl::imessage_router::MESSAGE_ROUTER) - { - } - - //******************************************** - message_producer(etl::imessage_router& successor_) - : imessage_router(imessage_router::NULL_MESSAGE_ROUTER, successor_) - { - } - - //******************************************** - message_producer(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)); - } - - //******************************************** - message_producer(etl::message_router_id_t id_, etl::imessage_router& successor_) - : imessage_router(id_, successor_) - { - ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); - } - - //******************************************** - using etl::imessage_router::receive; - - void receive(const etl::imessage& msg) ETL_OVERRIDE - { - if (has_successor()) - { - get_successor().receive(msg); - } - } - - //******************************************** - using etl::imessage_router::accepts; - - bool accepts(etl::message_id_t id) const ETL_OVERRIDE - { - if (has_successor()) - { - return get_successor().accepts(id); - } - else - { - return false; - } - } - - //******************************************** - ETL_DEPRECATED - bool is_null_router() const ETL_OVERRIDE - { - return false; - } - - //******************************************** - bool is_producer() const ETL_OVERRIDE - { - return true; - } - - //******************************************** - bool is_consumer() const ETL_OVERRIDE - { - return false; - } - }; - - //*************************************************************************** - /// Is T ultimately derived from etl::imessage_router? - //*************************************************************************** - template - struct is_message_router : public etl::bool_constant< etl::is_base_of< etl::imessage_router, typename etl::remove_cvref::type>::value> - { - }; - - //*************************************************************************** - /// Send a message to a router. - //*************************************************************************** - template - static typename etl::enable_if< etl::is_message_router::value && etl::is_message::value, void>::type - send_message(TRouter& destination, const TMessage& message) - { - destination.receive(message); - } - - //*************************************************************************** - /// Send a shared message to a router. - //*************************************************************************** - template - static typename etl::enable_if::value, void>::type send_message(TRouter& destination, etl::shared_message message) - { - destination.receive(message); - } - - //*************************************************************************** - /// Send a message to a router with a particular id. - //*************************************************************************** - template - static typename etl::enable_if< etl::is_message_router::value && etl::is_message::value, void>::type - send_message(TRouter& destination, etl::message_router_id_t id, const TMessage& message) - { - destination.receive(id, message); - } - - //*************************************************************************** - /// Send a shared message to a router with a particular id. - //*************************************************************************** - template - static typename etl::enable_if::value, void>::type send_message(TRouter& destination, etl::message_router_id_t id, - etl::shared_message message) - { - destination.receive(id, message); - } - - //************************************************************************************************* - // For C++11 and above. - //************************************************************************************************* -#if ETL_USING_CPP11 && !defined(ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION) - //*************************************************************************** - // The definition for all message types. - //*************************************************************************** - template - class message_router - : public imessage_router - , public private_message_router::traits - { - public: - - using typename private_message_router::traits::message_packet; - using typename private_message_router::traits::message_types; - using typename private_message_router::traits< TMessageTypes...>::sorted_message_types; - - //********************************************** - /// Default constructor. The message router id will be MESSAGE_ROUTER. - //********************************************** - message_router() - : imessage_router(etl::imessage_router::MESSAGE_ROUTER) - { - } - - //********************************************** - /// Constructor with successor. The message router id will be - /// MESSAGE_ROUTER. - //********************************************** - message_router(etl::imessage_router& successor_) - : imessage_router(etl::imessage_router::MESSAGE_ROUTER, successor_) - { - } - - //********************************************** - /// Constructor with message router id. - //********************************************** - 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)); - } - - //********************************************** - /// Constructor with message router id and successor. - //********************************************** - message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) - : imessage_router(id_, successor_) - { - ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); - } - - //********************************************** - /// Allow visibility of base class receive() methods. - //********************************************** - using etl::imessage_router::receive; - - //********************************************** - /// This will be called for all messages passed as an etl::imessage. - /// It will dispatch the message to the correct handler based on the message - /// id, or pass it to a successor if there is no handler for the message id. - /// \param msg The message. - //*********************************************** - void receive(const etl::imessage& msg) ETL_OVERRIDE - { - const etl::message_id_t id = msg.get_message_id(); - - // The IDs are sorted, so an ID less than the first is not handled by this - // router. - if (id >= Message_Id_Start) - { - const size_t index = get_dispatch_index_from_message_id(id); - - // If the index is less than Number_Of_Messages, then we have a handler - // for this message type, so dispatch it. - if (index < Number_Of_Messages) - { - dispatch(msg, index); - return; - } - } - - // We don't have a handler for this message type, so pass it to a - // successor if there is one, or call on_receive_unknown() if there isn't. - if (has_successor()) - { - get_successor().receive(msg); - } - else - { - #include "etl/private/diagnostic_array_bounds_push.h" - static_cast(this)->on_receive_unknown(msg); - #include "etl/private/diagnostic_pop.h" - } - } - - //********************************************** - /// This will be called for messages where TMessage is in the message type - /// list. \tparam TMessage The message type. \param msg The message. Enabled - /// if TMessage is in the message type list. - //********************************************** - template < typename TMessage, typename etl::enable_if::value, int>::type = 0> - void receive(const TMessage& msg) - { - #include "etl/private/diagnostic_array_bounds_push.h" - static_cast(this)->on_receive(msg); - #include "etl/private/diagnostic_pop.h" - } - - //********************************************** - /// This will be called for messages where TMessage is a message type, but - /// not in the message type list. \tparam TMessage The message type. \param - /// msg The message. Enabled if TMessage is a message type, but not in the - /// message type list. - //********************************************** - template ::value && !etl::is_one_of::value, int>::type = 0> - void receive(const TMessage& msg) - { - if (has_successor()) - { - get_successor().receive(msg); - } - else - { - #include "etl/private/diagnostic_array_bounds_push.h" - static_cast(this)->on_receive_unknown(msg); - #include "etl/private/diagnostic_pop.h" - } - } - - //********************************************** - /// Allow visibility of base class accepts() methods. - //********************************************** - using imessage_router::accepts; - - //********************************************** - /// This will return true if the message id is in the message type list, or - /// if a successor accepts the message id. - //*********************************************** - bool accepts(etl::message_id_t id) const ETL_OVERRIDE - { - if (id >= Message_Id_Start) - { - const size_t index = get_dispatch_index_from_message_id(id); - - if (index < Number_Of_Messages) - { - return true; - } - } - - return has_successor() ? get_successor().accepts(id) : false; - } - - //******************************************** - ETL_DEPRECATED - bool is_null_router() const ETL_OVERRIDE - { - return false; - } - - //******************************************** - bool is_producer() const ETL_OVERRIDE - { - return true; - } - - //******************************************** - bool is_consumer() const ETL_OVERRIDE - { - return true; - } - - private: - - static constexpr size_t Number_Of_Messages = sizeof...(TMessageTypes); - static constexpr etl::message_id_t Message_Id_Start = etl::type_list_type_at_index_t::ID; - - //********************************************** - // Checks that the message ids are contiguous. - //********************************************** - template = Number_Of_Messages)> - struct contiguous_impl; - - template - struct contiguous_impl : etl::true_type - { - }; - - template - struct contiguous_impl - : etl::bool_constant< (etl::type_list_type_at_index_t::ID + 1U - == etl::type_list_type_at_index_t::ID) - && contiguous_impl::value> - { - }; - - // The message ids are contiguous if there are 0 or 1 message types, or if - // each message id is one greater than the previous message id. - static constexpr bool Message_Ids_Are_Contiguous = (Number_Of_Messages <= 1U) ? true : contiguous_impl<0U>::value; - - using handler_ptr = void (*)(TDerived&, - const etl::imessage&); ///< Pointer to a handler function that - ///< takes a reference to the derived - ///< class and a reference to the message. - using message_dispatch_table_t = etl::array; ///< The dispatch table type. An array of - ///< handler pointers, one for each - ///< message type. - using message_id_table_t = etl::array; ///< The message id table type. An - ///< array of message ids, one for - ///< each message type. - - //********************************************** - // Call for a single message type - //********************************************** - template - static void call_on_receive(TDerived& derived, const imessage& msg) - { - derived.on_receive(static_cast(msg)); - } - - //********************************************** - // Get the handler for a single message type at the index in the sorted - // type_list. This will be called for each message type to generate the - // dispatch table. - //********************************************** - template - static constexpr handler_ptr get_message_handler() - { - return &call_on_receive< etl::type_list_type_at_index_t>; - } - - //********************************************** - // Generate the dispatch table at compile time. - // This will create an array of handler pointers, one for each message type. - //********************************************** - template - static constexpr message_dispatch_table_t make_message_dispatch_table(etl::index_sequence) - { - return message_dispatch_table_t{{get_message_handler()...}}; - } - - //********************************************** - // Get the message id for a single message type at an index in the sorted - // type_list. This will be called for each message type to generate the - // message id table. - //********************************************** - template - static constexpr etl::message_id_t get_message_id_from_index() - { - return etl::type_list_type_at_index_t::ID; - } - - //********************************************** - // Generate the message id table at compile time. - // This will create an array of message ids, one for each message type. - //********************************************** - template - static constexpr message_id_table_t make_message_id_table(etl::index_sequence) - { - return message_id_table_t{{get_message_id_from_index()...}}; - } - - //********************************************** - // Get the dispatch index for a message id. - // This will be used at runtime to find the handler for a message id. - // If the message ids are contiguous, we can calculate the index directly. - // If they are not contiguous, we need to do a binary search. This will - // return Number_Of_Messages if the message id is not found, which indicates - // that the message should be passed to the successor. - //********************************************** - static size_t get_dispatch_index_from_message_id(etl::message_id_t id) - { - if ETL_IF_CONSTEXPR (Message_Ids_Are_Contiguous) - { - // The IDs are contiguous, so we can calculate the index directly. - return static_cast(id - Message_Id_Start); - } - else - { - // The IDs are not contiguous, so we need to do a binary search. - size_t left = 0; - size_t right = Number_Of_Messages; - - while (left < right) - { - size_t mid = (left + right) / 2; - - if (message_id_table[mid] == id) - { - return mid; - } - else if (message_id_table[mid] < id) - { - left = mid + 1; - } - else - { - right = mid; - } - } - } - - return Number_Of_Messages; // Not found - } - - //********************************************** - // Dispatch the message to the appropriate handler based on the index in the - // dispatch table. - //********************************************** - void dispatch(const etl::imessage& msg, size_t index) - { - message_dispatch_table[index](static_cast(*this), msg); - } - - //********************************************** - // The dispatch table is generated at compile time. The dispatch table - // contains pointers to the on_receive handlers for each message type. - //********************************************** - static ETL_INLINE_VAR constexpr message_dispatch_table_t message_dispatch_table = - etl::message_router::make_message_dispatch_table( - etl::make_index_sequence< etl::message_router< TDerived, TMessageTypes...>::Number_Of_Messages>{}); - - //********************************************** - // The message id table is generated at compile time. The message id table - // contains the corresponding message ids for each message type. - //********************************************** - static ETL_INLINE_VAR constexpr message_id_table_t message_id_table = etl::message_router::make_message_id_table( - etl::make_index_sequence< etl::message_router< TDerived, TMessageTypes...>::Number_Of_Messages>{}); - }; - - #if ETL_USING_CPP11 && !ETL_USING_CPP17 - template - constexpr const typename etl::message_router< TDerived, TMessageTypes...>::message_dispatch_table_t - etl::message_router::message_dispatch_table; - - template - constexpr const typename etl::message_router< TDerived, TMessageTypes...>::message_id_table_t - etl::message_router::message_id_table; - #endif - - //*************************************************************************** - // The definition of a message_router for zero message types. - //*************************************************************************** - template - class message_router - : public imessage_router - , public private_message_router::traits<> - { - public: - - //********************************************** - /// Default constructor. The message router id will be MESSAGE_ROUTER. - //********************************************** - message_router() - : imessage_router(etl::imessage_router::MESSAGE_ROUTER) - { - } - - //********************************************** - /// Constructor with successor. The message router id will be - /// MESSAGE_ROUTER. - //********************************************** - message_router(etl::imessage_router& successor_) - : imessage_router(etl::imessage_router::MESSAGE_ROUTER, successor_) - { - } - - //********************************************** - /// Constructor with message router id. - //********************************************** - 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)); - } - - //********************************************** - /// Constructor with message router id and successor. - //********************************************** - message_router(etl::message_router_id_t id_, etl::imessage_router& successor_) - : imessage_router(id_, successor_) - { - ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id)); - } - - //********************************************** - /// Allow visibility of base class receive() methods. - using etl::imessage_router::receive; - - //********************************************** - /// This will be called for all messages passed as an etl::imessage. - /// Since there are no message types, this will just pass the message to a - /// successor if there is one, or call on_receive_unknown() if there isn't. - /// \param msg The message. - //*********************************************** - void receive(const etl::imessage& msg) ETL_OVERRIDE - { - #include "etl/private/diagnostic_array_bounds_push.h" - if (has_successor()) - { - get_successor().receive(msg); - } - #include "etl/private/diagnostic_pop.h" - } - - //********************************************** - /// Allow visibility of base class accepts() methods. - //********************************************** - using imessage_router::accepts; - - //********************************************** - /// This will return true if a successor accepts the message id. - //*********************************************** - bool accepts(etl::message_id_t id) const ETL_OVERRIDE - { - if (has_successor()) - { - return get_successor().accepts(id); - } - else - { - return false; - } - } - - //******************************************** - ETL_DEPRECATED - bool is_null_router() const ETL_OVERRIDE - { - return false; - } - - //******************************************** - bool is_producer() const ETL_OVERRIDE - { - return true; - } - - //******************************************** - bool is_consumer() const ETL_OVERRIDE - { - return true; - } - }; - - //*************************************************************************** - /// Helper to turn etl::type_list into - /// etl::message_router - //*************************************************************************** - template - struct message_router_from_type_list; - - template - struct message_router_from_type_list> - { - using type = etl::message_router; - }; - - template - using message_router_from_type_list_t = typename message_router_from_type_list::type; - -#else - #include "private/message_router_cpp03.h" -#endif -} // namespace etl +// message_router is a typedef of message_processor, which is the new name for this class. +// The old name is kept for backwards compatibility. +#include "message_processor.h" #endif diff --git a/include/etl/message_types.h b/include/etl/message_types.h index ab97f95e..2e25555b 100644 --- a/include/etl/message_types.h +++ b/include/etl/message_types.h @@ -42,7 +42,8 @@ namespace etl typedef ETL_MESSAGE_ID_TYPE message_id_t; #endif - typedef uint_least8_t message_router_id_t; + typedef uint_least8_t message_router_id_t; + typedef message_router_id_t message_processor_id_t; } // namespace etl #endif diff --git a/test/vs2022/etl.vcxproj b/test/vs2022/etl.vcxproj index 7a69c37e..744bef04 100644 --- a/test/vs2022/etl.vcxproj +++ b/test/vs2022/etl.vcxproj @@ -3563,6 +3563,7 @@ + @@ -11807,4 +11808,4 @@ - + \ No newline at end of file diff --git a/test/vs2022/etl.vcxproj.filters b/test/vs2022/etl.vcxproj.filters index 10afee24..5c230e82 100644 --- a/test/vs2022/etl.vcxproj.filters +++ b/test/vs2022/etl.vcxproj.filters @@ -1572,6 +1572,9 @@ UnitTest++\Header Files + + ETL\Messaging + @@ -4124,4 +4127,4 @@ Resource Files\Images - + \ No newline at end of file