A C++ template library for embedded applications
MIT licensed
Designed and
maintained by
John Wellbelove

Message Router


This page documents version 20.0.0 and above.

For version 19.x.x or earlier see this page.


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.

 

Defines the following classes:-

etl::imessage_router

etl::message_router

etl::null_message_router

 

Note: 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

____________________________________________________________________________________________________

Message router ID

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::imassage_router::MESSAGE_ROUTER.

 

Scenario 1

You never send a message to a router using it's ID.

You never use the ID to uniquely identify a router.
You do not require the router ID to act as a priority level when subscribing to a message bus.

You do not require that messages can be sent to a group.

 

All message router IDs can be identical.

____________________________________________________________________________________________________

Scenario 2

You never use the ID to uniquely identify a router.

You may use the router ID to send to a particular router group.

You require the router ID to act as a priority level when subscribing to a message bus.

Router IDs will be assigned in groups. i.e. Some routers may share IDs.

____________________________________________________________________________________________________

Scenario 3

You use the ID to uniquely identify a router.

You use the router ID to send to a particular router.

You require the router ID to act as a priority level when subscribing to a message bus.
You require all priority levels to be unique.

 

All router IDs are unique

____________________________________________________________________________________________________

imessage_router

The base class for all routers.

 

Member functions

 

virtual ~imessage_router() {}

____________________________________________________________________________________________________

virtual void receive(const etl::imessage& message) = 0;

Overridden by the derived class.

____________________________________________________________________________________________________

virtual void receive(etl::message_router_id_t destination_router_id,

                     const etl::imessage& message)

Receive a message for a specific destination id.
If the destination id is the router's id, then the message is forwarded to receive(message);

Can be overridden by the derived class.

____________________________________________________________________________________________________

virtual void receive(etl::shared_message shared_msg)

Receive a shared message.

By default, forwards to receive(shared_msg.get_message());

____________________________________________________________________________________________________

virtual void receive(etl::message_router_id_t destination_router_id,

                     etl::shared_message shared_msg)

Receive a message for a specific destination id.
By default, forwards to receive(destination_router_id, shared_msg.get_message());

____________________________________________________________________________________________________

virtual bool accepts(etl::message_id_t id) const = 0;

Returns true if the router accepts the message id.

Overridden by the derived class.

____________________________________________________________________________________________________

bool accepts(const etl::imessage& msg) const;

Returns true if the router accepts the message.

____________________________________________________________________________________________________

etl::message_router_id_t get_message_router_id() const;

Returns the router id.

____________________________________________________________________________________________________

virtual bool is_null_router() const = 0; DEPRECATED

Returns true if the router is a null message router, otherwise false.

____________________________________________________________________________________________________

virtual bool is_producer() const = 0;

Returns true if the router is a producer of messages, otherwise false.

____________________________________________________________________________________________________

virtual bool is_consumer() const = 0;

Returns true if the router is a consumer of messages, otherwise false.

____________________________________________________________________________________________________

void set_successor(etl::imessage_router& successor);

Sets the successor router. Any unhandled message will be sent here.

Allows the router to implement the Chain Of Responsibility design pattern.

 

Enumerations

NULL_MESSAGE_ROUTER

MESSAGE_BUS

ALL_MESSAGE_ROUTERS

MAX_MESSAGE_ROUTER

____________________________________________________________________________________________________

message_router

User defined message routers are derived from this class.

Derived from imessage_router

____________________________________________________________________________________________________

For C++03 to C++14


template <typename TDerived,

          typename T1,         typename T2  = void, typename T3  = void, typename T4  = void,

          typename T5  = void, typename T6  = void, typename T7  = void, typename T8  = void,

          typename T9  = void, typename T10 = void, typename T11 = void, typename T12 = void,

          typename T13 = void, typename T14 = void, typename T15 = void, typename T16 = void>

class message_router

 

Template parameters

TDerived The derived class.

T1       The first message type.

T2...    The additional message types.

         The maximum number of types can be set by running the generator for this file.
         The default is 16.This may be changed by running a modified version of generate_message_router.bat.
         See Generators

____________________________________________________________________________________________________

For C++17 and above


template <typename TDerived, typename... TMessageTypes>

class message_router

 

Template parameters

TDerived      The derived class.

TMessageTypes The list of message types.

 

This definition will automatically be selected if the compiler supports C++17. It uses fold expressions to resolve on_receive() calls.
To use the older C++03 compatible definition, define ETL_MESSAGE_ROUTER_FORCE_CPP03 as a project setting or in the optional etl_profile.h.

____________________________________________________________________________________________________

The derived class must define the following member functions.

 

void on_receive(const Type& msg);

Replace Type with each concrete message type.

Define for all of the template parameter types.

____________________________________________________________________________________________________

void on_receive_unknown(const etl::imessage& msg)

Called when a message type is received that is not in the template list.

___________________________________________________________________________________________________

Member classes

message_packet

See etl::message_packet

____________________________________________________________________________________________________

Member functions

message_router()

Constructs the router.

The router id is set to etl::imassage_router::MESSAGE_ROUTER.

____________________________________________________________________________________________________

message_router(etl::imessage_router& successor)

Constructs the router.

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.

____________________________________________________________________________________________________

message_router(etl::message_router_id_t id)

Constructs the router.

The router id must be between 0 and 249. Ids 250 to 255 are reserved for ETL use.

Asserts an error if the id is outside the legal range.

Routers may have duplicate ids.

____________________________________________________________________________________________________

message_router(etl::message_router_id_t id, etl::imessage_router& successor)

Constructs the router.

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.

____________________________________________________________________________________________________

void receive(const etl::imessage& msg)

Receives a message and routes to the on_receive() handler.

If not handled, passes the message on to a successor, if it exists.

____________________________________________________________________________________________________

template <typename TMessage>

void receive(const TMessage& msg)

Receives a message and routes directly to the on_receive() handler.

This template  function will be chosen for concrete message types.

If not handled, passes the message on to a successor, if it exists.

____________________________________________________________________________________________________

bool accepts(etl::message_id_t id) const

Returns true if the router accepts the message id.

____________________________________________________________________________________________________

Errors

message_router_exception

Base exception for router errors.

Derived from etl::exception.

____________________________________________________________________________________________________

message_router_illegal_id

The router id is out of the legal range.

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 imessage_router

____________________________________________________________________________________________________

null_message_router()

Constructs a null message router.

The router id will be etl::imessage_router::NULL_MESSAGE_ROUTER.

____________________________________________________________________________________________________

void receive(const etl::imessage& message)

Receives a message.

Does nothing, except pass on to a successor, if it exists.

____________________________________________________________________________________________________

bool accepts(etl::message_id_t id) const

Returns false if no successor is set.
Returns true if a successor accepts the message id.

____________________________________________________________________________________________________

static null_message_router& instance()

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 imessage_router

____________________________________________________________________________________________________

message_producer(etl::message_router_id_t id);

Constructs the router.

The router id must be between 0 and 249. Ids 250 to 255 are reserved for ETL use.

Emits an error if the id is outside the legal range.

Routers may have duplicate ids.

____________________________________________________________________________________________________

void receive(const etl::imessage& message)

Receives a message.

Does nothing, except pass on to a successor, if it exists.

____________________________________________________________________________________________________

bool accepts(etl::message_id_t id) const

Returns false if no successor is set.
Returns true if a successor accepts the message id.

____________________________________________________________________________________________________

static null_message_router& instance()

Returns an instance of etl::null_message_router.

____________________________________________________________________________________________________

Global functions


 

void send_message(etl::imessage_router& router,

                  const etl::imessage&  message);

Send the message to the router.

____________________________________________________________________________________________________

void send_message(etl::imessage_router&    router,

                  etl::message_router_id_t id,

                  const etl::imessage&     message);

Send the message to the router if it has the specified id.

____________________________________________________________________________________________________

void send_message(etl::imessage_router& router,

                  etl::shared_message&  message);

Send the shared message to the router.

____________________________________________________________________________________________________

void send_message(etl::imessage_router&    router,

                  etl::message_router_id_t id,

                  etl::shared_message&     message);

Send the shared message to the router if it has the specified id.

____________________________________________________________________________________________________

Example

 

// Message ids.

enum

{

  START,

  STOP,

  SET_SPEED

};

 

// The start message.

struct Start : public etl::message<START>

{

};

 

// The stop message.

struct Stop : public etl::message<STOP>

{

};

 

// The set speed message.

struct SetSpeed : public etl::message<SET_SPEED>

{

  SetSpeed(uint32_t speed_)

    : speed(speed_)

  {

  }

 

  uint32_t speed;

};

 

// The router.

class Router : public etl::message_router<Router, Start, Stop, SetSpeed>

{

public:

 

  // Construct the router with an id of 0.

  Router()

    : message_router(0)

  {

  }

 

  // Received a start message.

  void on_receive(etl::imessage_router& sender, const Start& msg)

  {

    std::cout << "Start message received\n";

  }

 

  // Received a stop message.

  void on_receive(const Stop& msg)

  {

    std::cout << "Start message received\n";

  }

 

  // Received a set speed message.

  void on_receive(const SetSpeed& msg)

  {

    std::cout << "SetSpeed(" << msg.speed << ") message received\n";

  }

 

  // Received an unknown message.

  void on_receive_unknown(const etl::imessage& msg)

  {

    std::cout << "Unknown message " << msg.message_id << " received\n";

  }

}

 

// Router and message instances.

Router   router;

Start    start;

Stop     stop;

SetSpeed halfSpeed(50);

SetSpeed maxSpeed(100);

 

// A queue for Router messages.

etl::queue<Router::message_packet, 10> queue;

 

// Add to the queue.

queue.emplace(start);

queue.emplace(stop);

queue.emplace(maxSpeed);

queue.emplace(halfSpeed);

 

// Send the queued messages to 'router'.

while (!queue.empty())

{

  etl::send_message(router, queue.front().get());

  queue.pop();

}

 

____________________________________________________________________________________________________

An example of a queued message router can be found in the repository in examples/QueuedMessageRouter

message_router.h