Containers (STL-compatible) StateMachines MessageBus and more for Embedded Systems. See www.etlcpp.com

Revision:
0:b47c2a7920c2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/message_router.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,2531 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#if 0
+#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE.
+#endif
+
+//***************************************************************************
+// This file has been auto generated. Do not edit this file.
+//***************************************************************************
+
+//***************************************************************************
+// To generate to header file, run this at the command line.
+// Note: You will need Python and COG installed.
+//
+// python -m cogapp -d -e -omessage_router.h -DHandlers=<n> message_router_generator.h 
+// Where <n> is the number of messages to support.
+//
+// e.g.
+// To generate handlers for up to 16 messages...
+// python -m cogapp -d -e -omessage_router.h -DHandlers=16 message_router_generator.h 
+//
+// See generate.bat
+//***************************************************************************
+
+#ifndef __ETL_MESSAGE_ROUTER__
+#define __ETL_MESSAGE_ROUTER__
+
+#include <stdint.h>
+
+#include "platform.h"
+#include "message.h"
+#include "message_types.h"
+#include "alignment.h"
+#include "error_handler.h"
+#include "exception.h"
+#include "largest.h"
+#include "nullptr.h"
+
+#undef ETL_FILE
+#define ETL_FILE "35"
+
+namespace etl
+{
+  //***************************************************************************
+  /// Base exception class for message router
+  //***************************************************************************
+  class message_router_exception : public etl::exception
+  {
+  public:
+
+    message_router_exception(string_type 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_FILE"A"), file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  class imessage_router
+  {
+  public:
+
+    virtual ~imessage_router() {}
+    virtual void receive(const etl::imessage& message) = 0;
+    virtual void receive(imessage_router& source, const etl::imessage& message) = 0;
+    virtual bool accepts(etl::message_id_t id) const = 0;
+
+    //********************************************
+    bool accepts(const etl::imessage& msg) const
+    {
+      return accepts(msg.message_id);
+    }
+
+    //********************************************
+    etl::message_router_id_t get_message_router_id() const
+    {
+      return message_router_id;
+    }
+
+    //********************************************
+    bool is_null_router() const
+    {
+      return (message_router_id == NULL_MESSAGE_ROUTER);
+    }
+
+    //********************************************
+    bool is_bus() const
+    {
+      return (message_router_id == MESSAGE_BUS);
+    }
+
+    //********************************************
+    void set_successor(imessage_router& successor_)
+    {
+      successor = &successor_;
+    }
+
+    //********************************************
+    imessage_router& get_successor() const
+    {
+      return *successor;
+    }
+
+    //********************************************
+    bool has_successor() const
+    {
+      return (successor != nullptr);
+    }
+
+    enum
+    {
+      NULL_MESSAGE_ROUTER = 255,
+      MESSAGE_BUS         = 254,
+      ALL_MESSAGE_ROUTERS = 253,
+      MAX_MESSAGE_ROUTER  = 249
+    };
+
+  protected:
+
+    imessage_router(etl::message_router_id_t id_)
+      : successor(nullptr),
+        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::imessage_router* successor;
+
+    etl::message_router_id_t  message_router_id;
+  };
+
+  //***************************************************************************
+  /// This router can be used either as a sink for messages
+  /// or as a producer-only of messages such an interrupt routine.
+  //***************************************************************************
+  class null_message_router : public imessage_router
+  {
+  public:
+
+    null_message_router()
+      : imessage_router(imessage_router::NULL_MESSAGE_ROUTER)
+    {
+    }
+
+    //********************************************
+    void receive(const etl::imessage&)
+    {
+    }
+
+    //********************************************
+    void receive(etl::imessage_router&, const etl::imessage&)
+    {
+    }
+
+    //********************************************
+    bool accepts(etl::message_id_t) const
+    {
+      return false;
+    }
+
+    //********************************************
+    static null_message_router& instance()
+    {
+      static null_message_router nmr;
+      return nmr;
+    }
+  };
+
+  //***************************************************************************
+  /// Send a message to a router.
+  /// Sets the 'sender' to etl::null_message_router type.
+  //***************************************************************************
+  inline static void send_message(etl::imessage_router& destination, 
+                                  const etl::imessage&  message)
+  {
+    destination.receive(message);
+  }
+
+  //***************************************************************************
+  /// Send a message to a router.
+  //***************************************************************************
+  inline static void send_message(etl::imessage_router& source, 
+                                  etl::imessage_router& destination, 
+                                  const etl::imessage&  message)
+  {
+    destination.receive(source, message);
+  }
+  
+  //***************************************************************************
+  // The definition for all 16 message types.
+  //***************************************************************************
+  template <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  : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break;
+          case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break;
+          case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break;
+          case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break;
+          case T10::ID: ::new (p) T10(static_cast<const T10&>(msg)); break;
+          case T11::ID: ::new (p) T11(static_cast<const T11&>(msg)); break;
+          case T12::ID: ::new (p) T12(static_cast<const T12&>(msg)); break;
+          case T13::ID: ::new (p) T13(static_cast<const T13&>(msg)); break;
+          case T14::ID: ::new (p) T14(static_cast<const T14&>(msg)); break;
+          case T15::ID: ::new (p) T15(static_cast<const T15&>(msg)); break;
+          case T16::ID: ::new (p) T16(static_cast<const T16&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    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));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const etl::message_id_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break;
+        case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break;
+        case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break;
+        case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break;
+        case T10::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T10&>(msg)); break;
+        case T11::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T11&>(msg)); break;
+        case T12::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T12&>(msg)); break;
+        case T13::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T13&>(msg)); break;
+        case T14::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T14&>(msg)); break;
+        case T15::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T15&>(msg)); break;
+        case T16::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T16&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: 
+        case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: case T14::ID: case T15::ID: case T16::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 15 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8, 
+            typename T9, typename T10, typename T11, typename T12, 
+            typename T13, typename T14, typename T15>
+  class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break;
+          case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break;
+          case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break;
+          case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break;
+          case T10::ID: ::new (p) T10(static_cast<const T10&>(msg)); break;
+          case T11::ID: ::new (p) T11(static_cast<const T11&>(msg)); break;
+          case T12::ID: ::new (p) T12(static_cast<const T12&>(msg)); break;
+          case T13::ID: ::new (p) T13(static_cast<const T13&>(msg)); break;
+          case T14::ID: ::new (p) T14(static_cast<const T14&>(msg)); break;
+          case T15::ID: ::new (p) T15(static_cast<const T15&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    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));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break;
+        case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break;
+        case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break;
+        case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break;
+        case T10::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T10&>(msg)); break;
+        case T11::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T11&>(msg)); break;
+        case T12::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T12&>(msg)); break;
+        case T13::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T13&>(msg)); break;
+        case T14::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T14&>(msg)); break;
+        case T15::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T15&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: 
+        case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: case T14::ID: case T15::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 14 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8, 
+            typename T9, typename T10, typename T11, typename T12, 
+            typename T13, typename T14>
+  class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break;
+          case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break;
+          case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break;
+          case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break;
+          case T10::ID: ::new (p) T10(static_cast<const T10&>(msg)); break;
+          case T11::ID: ::new (p) T11(static_cast<const T11&>(msg)); break;
+          case T12::ID: ::new (p) T12(static_cast<const T12&>(msg)); break;
+          case T13::ID: ::new (p) T13(static_cast<const T13&>(msg)); break;
+          case T14::ID: ::new (p) T14(static_cast<const T14&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    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));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break;
+        case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break;
+        case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break;
+        case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break;
+        case T10::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T10&>(msg)); break;
+        case T11::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T11&>(msg)); break;
+        case T12::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T12&>(msg)); break;
+        case T13::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T13&>(msg)); break;
+        case T14::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T14&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: 
+        case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: case T14::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 13 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8, 
+            typename T9, typename T10, typename T11, typename T12, 
+            typename T13>
+  class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break;
+          case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break;
+          case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break;
+          case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break;
+          case T10::ID: ::new (p) T10(static_cast<const T10&>(msg)); break;
+          case T11::ID: ::new (p) T11(static_cast<const T11&>(msg)); break;
+          case T12::ID: ::new (p) T12(static_cast<const T12&>(msg)); break;
+          case T13::ID: ::new (p) T13(static_cast<const T13&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    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));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break;
+        case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break;
+        case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break;
+        case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break;
+        case T10::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T10&>(msg)); break;
+        case T11::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T11&>(msg)); break;
+        case T12::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T12&>(msg)); break;
+        case T13::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T13&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: 
+        case T9::ID: case T10::ID: case T11::ID: case T12::ID: case T13::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 12 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8, 
+            typename T9, typename T10, typename T11, typename T12>
+  class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break;
+          case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break;
+          case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break;
+          case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break;
+          case T10::ID: ::new (p) T10(static_cast<const T10&>(msg)); break;
+          case T11::ID: ::new (p) T11(static_cast<const T11&>(msg)); break;
+          case T12::ID: ::new (p) T12(static_cast<const T12&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    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));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break;
+        case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break;
+        case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break;
+        case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break;
+        case T10::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T10&>(msg)); break;
+        case T11::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T11&>(msg)); break;
+        case T12::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T12&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: 
+        case T9::ID: case T10::ID: case T11::ID: case T12::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 11 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8, 
+            typename T9, typename T10, typename T11>
+  class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, void, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break;
+          case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break;
+          case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break;
+          case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break;
+          case T10::ID: ::new (p) T10(static_cast<const T10&>(msg)); break;
+          case T11::ID: ::new (p) T11(static_cast<const T11&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    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));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break;
+        case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break;
+        case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break;
+        case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break;
+        case T10::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T10&>(msg)); break;
+        case T11::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T11&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: 
+        case T9::ID: case T10::ID: case T11::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 10 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8, 
+            typename T9, typename T10>
+  class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, void, void, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break;
+          case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break;
+          case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break;
+          case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break;
+          case T10::ID: ::new (p) T10(static_cast<const T10&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    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));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break;
+        case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break;
+        case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break;
+        case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break;
+        case T10::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T10&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: 
+        case T9::ID: case T10::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 9 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8, 
+            typename T9>
+  class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, T9, void, void, void, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break;
+          case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break;
+          case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break;
+          case T9::ID: ::new (p) T9(static_cast<const T9&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    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));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break;
+        case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break;
+        case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break;
+        case T9::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T9&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: 
+        case T9::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 8 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7, typename T8>
+  class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, T8, void, void, void, void, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break;
+          case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break;
+          case T8::ID: ::new (p) T8(static_cast<const T8&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7, T8>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    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));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break;
+        case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break;
+        case T8::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T8&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: case T8::ID: 
+        
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 7 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6, typename T7>
+  class message_router<TDerived, T1, T2, T3, T4, T5, T6, T7, void, void, void, void, void, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break;
+          case T7::ID: ::new (p) T7(static_cast<const T7&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5, T6, T7>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6, T7>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    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));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break;
+        case T7::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T7&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: case T7::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 6 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5, typename T6>
+  class message_router<TDerived, T1, T2, T3, T4, T5, T6, void, void, void, void, void, void, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          case T6::ID: ::new (p) T6(static_cast<const T6&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5, T6>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5, T6>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    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));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        case T6::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T6&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: case T6::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 5 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4, 
+            typename T5>
+  class message_router<TDerived, T1, T2, T3, T4, T5, void, void, void, void, void, void, void, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          case T5::ID: ::new (p) T5(static_cast<const T5&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4, T5>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4, T5>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    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));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        case T5::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T5&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: case T5::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 4 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3, typename T4>
+  class message_router<TDerived, T1, T2, T3, T4, void, void, void, void, void, void, void, void, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          case T4::ID: ::new (p) T4(static_cast<const T4&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3, T4>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3, T4>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    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));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        case T4::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T4&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: case T4::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 3 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2, typename T3>
+  class message_router<TDerived, T1, T2, T3, void, void, void, void, void, void, void, void, void, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          case T3::ID: ::new (p) T3(static_cast<const T3&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2, T3>::size,
+        ALIGNMENT = etl::largest<T1, T2, T3>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    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));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        case T3::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T3&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: case T3::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 2 message types.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1, typename T2>
+  class message_router<TDerived, T1, T2, void, void, void, void, void, void, void, void, void, void, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          case T2::ID: ::new (p) T2(static_cast<const T2&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1, T2>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1, T2>::size,
+        ALIGNMENT = etl::largest<T1, T2>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    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));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        case T2::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T2&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: case T2::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+
+  //***************************************************************************
+  // Specialisation for 1 message type.
+  //***************************************************************************
+  template <typename TDerived, 
+            typename T1>
+  class message_router<TDerived, T1, void, void, void, void, void, void, void, void, void, void, void, void, void, void, void>
+   : public imessage_router
+  {
+  public:
+
+    //**********************************************
+    class message_packet
+    {
+    public:
+
+      //********************************************
+      explicit message_packet(const etl::imessage& msg)
+      {
+        const size_t id = msg.message_id;
+
+        void* p = data;
+
+        switch (id)
+        {
+          case T1::ID: ::new (p) T1(static_cast<const T1&>(msg)); break;
+          default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;
+        }
+      }
+
+      //********************************************
+      template <typename T>
+      explicit message_packet(const T& msg)
+      {
+        STATIC_ASSERT((etl::is_one_of<T, T1>::value), "Unsupported type for this message packet");
+
+        void* p = data;
+        ::new (p) T(static_cast<const T&>(msg));
+      }
+
+      //********************************************
+      ~message_packet()
+      {
+        static_cast<etl::imessage*>(data)->~imessage();
+      }
+
+      //********************************************
+      etl::imessage& get()
+      {
+        return *static_cast<etl::imessage*>(data);
+      }
+
+      //********************************************
+      const etl::imessage& get() const
+      {
+        return *static_cast<const etl::imessage*>(data);
+      }
+
+      enum
+      {
+        SIZE      = etl::largest<T1>::size,
+        ALIGNMENT = etl::largest<T1>::alignment
+      };
+
+    private:
+
+      typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;
+    };
+
+    //**********************************************
+    message_router(etl::message_router_id_t id_)
+      : imessage_router(id_)
+    {
+      ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));
+    }
+
+    //**********************************************
+    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));
+    }
+
+    //**********************************************
+    void receive(const etl::imessage& msg)
+    {
+      receive(etl::null_message_router::instance(), msg);
+    }
+
+    //**********************************************
+    void receive(etl::imessage_router& source, const etl::imessage& msg)
+    {
+      const size_t id = msg.message_id;
+
+      switch (id)
+      {
+        case T1::ID: static_cast<TDerived*>(this)->on_receive(source, static_cast<const T1&>(msg)); break;
+        default:
+        {
+           if (has_successor())
+           {
+             get_successor().receive(source, msg);
+           }
+           else
+           {
+             static_cast<TDerived*>(this)->on_receive_unknown(source, msg);
+           }
+           break;
+        }
+      }
+    }
+
+    using imessage_router::accepts;
+
+    //**********************************************
+    bool accepts(etl::message_id_t id) const
+    {
+      switch (id)
+      {
+        case T1::ID: 
+          return true; break;
+        default:
+          return false; break;
+      }
+    }
+  };
+}
+
+#undef ETL_FILE
+
+#endif
+