A C++ template library for embedded applications
Designed and maintained by
Aster Consulting Ltd

Message Router

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. If a sender router is not specified then the on_receive function is passed an instance of
etl::null:message_router.

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

etl::imessage_router

The base class for all routers.


Member functions

virtual ~imessage_router() {}

virtual void receive(const etl::imessage& message) = 0;
Receive a message.
Overridden by the derived class.

virtual void receive(imessage_router& sender, const etl::imessage& message) = 0;
Receive a message from a defined sender.
Overridden by the derived class.

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.

bool is_null_router() const;
Returns true if the router is a null message router, otherwise false.

bool is_bus() const;
Returns true if the router is a message bus, otherwise false.

void set_successor(etl::imessage_router& successor);
Sets the successor router to this one. 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

etl::message_router

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.

The derived class must define the following member functions.

void on_receive(etl::imessage_router& sender, const Type& msg);
Replace Type with the concrete message type.
And so on for all of the template parameter types.

void on_receive_unknown(etl::imessage_router& sender, const etl::imessage& msg);
Called when a message type is received that is not in the template list.

Member classes

message_packet

A class that can hold any of messages declared in the template parameter list.
Maybe useful for use in message queues for this class.

template <typename T>
explicit message_packet(const T& msg);
Copies a message to the packet.
Static asserts if T is not one of those in the template parameter list.

~message_packet()
Destructs the packet and its contents.

etl::imessage& get()
const etl::imessage& get() const
Gets a reference to the contained message.

SIZE      The size of the largest type.
ALIGNMENT The largest alignment of all of the types.

Member functions

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.
Emits 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 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.
Sets the successor router to this one. Any unhandled message will be sent here.

void receive(const etl::imessage& msg);
Receive a message.

void receive(etl::imessage_router& sender, const etl::imessage& msg);
Receive a message from a defined sender router.

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

etl::null_message_router
This message router may either be a sink for messages or be the router for components that only ever emit messages.

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.

void receive(etl::imessage_router& source, const etl::imessage& message);
Receives a message.
Does nothing.

bool accepts(etl::message_id_t id) const;
Returns false.

static null_message_router& instance()
Returns an instance of etl::null_message_router.

Global functions

void send_message(etl::imessage_router& destination,
                  const etl::imessage&  message);

void send_message(etl::imessage_router& source,
                  etl::imessage_router& destination,
                  const etl::imessage&  message);

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 : 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(etl::imessage_router& sender, const Stop& msg)
  {
    std::cout << "Start message received\n";
  }

  // Received a set speed message.
  void on_receive(etl::imessage_router& sender, const SetSpeed& msg)
  {
    std::cout << "SetSpeed(" << msg.speed << ") message received\n";
  }

  // Received an unknown message.
  void on_receive_unknown(etl::imessage_router& sender, const etl::imessage& msg)
  {
    std::cout << "Unknown message " << msg.get_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();
}
message_router.h