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_generator.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,589 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+/*[[[cog
+import cog
+cog.outl("#if 0")
+]]]*/
+/*[[[end]]]*/
+#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE.
+/*[[[cog
+import cog
+cog.outl("#endif")
+]]]*/
+/*[[[end]]]*/
+
+/*[[[cog
+import cog
+cog.outl("//***************************************************************************")
+cog.outl("// This file has been auto generated. Do not edit this file.")
+cog.outl("//***************************************************************************")
+]]]*/
+/*[[[end]]]*/
+
+//***************************************************************************
+// To generate to header file, run this at the command line.
+// Note: You will need Python and COG installed.
+//
+// python -m cogapp -d -e -omessage_router.h -DHandlers=<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 != std::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(std::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);
+  }
+  
+  /*[[[cog
+      import cog
+      ################################################
+      # The first definition for all of the messages.
+      ################################################
+      cog.outl("//***************************************************************************")
+      cog.outl("// The definition for all %s message types." % Handlers)
+      cog.outl("//***************************************************************************")
+      cog.outl("template <typename TDerived,")
+      cog.out("          ")
+      cog.out("typename T1, ")
+      for n in range(2, int(Handlers)):
+          cog.out("typename T%s = void, " % n)
+          if n % 4 == 0:
+              cog.outl("")
+              cog.out("          ")
+      cog.outl("typename T%s = void>" % int(Handlers))
+      cog.out("class message_router")
+      cog.outl("  : public imessage_router")
+      cog.outl("{")
+      cog.outl("public:")
+      cog.outl("")
+      cog.outl("  //**********************************************")
+      cog.outl("  class message_packet")
+      cog.outl("  {")
+      cog.outl("  public:")
+      cog.outl("")
+      cog.outl("    //********************************************")
+      cog.outl("    explicit message_packet(const etl::imessage& msg)")
+      cog.outl("    {")
+      cog.outl("      const size_t id = msg.message_id;")
+      cog.outl("")
+      cog.outl("      void* p = data;")
+      cog.outl("")
+      cog.outl("      switch (id)")
+      cog.outl("      {")
+      for n in range(1, int(Handlers) + 1):
+          cog.outl("        case T%s::ID: ::new (p) T%s(static_cast<const T%s&>(msg)); break;" % (n, n, n))
+      cog.outl("        default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;")
+      cog.outl("      }")
+      cog.outl("    }")
+      cog.outl("")      
+      cog.outl("    //********************************************")
+      cog.outl("    template <typename T>")
+      cog.outl("    explicit message_packet(const T& msg)")
+      cog.outl("    {")
+      cog.out("      STATIC_ASSERT((etl::is_one_of<T, ")
+      for n in range(1, int(Handlers)):
+          cog.out("T%s, " % n)
+          if n % 16 == 0:
+              cog.outl("")
+              cog.out("                                       ")
+      cog.outl("""T%s>::value), "Unsupported type for this message packet");""" % int(Handlers))
+      cog.outl("")
+      cog.outl("      void* p = data;")
+      cog.outl("      ::new (p) T(static_cast<const T&>(msg));")
+      cog.outl("    }")
+      cog.outl("")
+      cog.outl("    //********************************************")
+      cog.outl("    ~message_packet()")
+      cog.outl("    {")
+      cog.outl("      static_cast<etl::imessage*>(data)->~imessage();")
+      cog.outl("    }")
+      cog.outl("")
+      cog.outl("    //********************************************")
+      cog.outl("    etl::imessage& get()")
+      cog.outl("    {")
+      cog.outl("      return *static_cast<etl::imessage*>(data);")
+      cog.outl("    }")
+      cog.outl("")
+      cog.outl("    //********************************************")
+      cog.outl("    const etl::imessage& get() const")
+      cog.outl("    {")
+      cog.outl("      return *static_cast<const etl::imessage*>(data);")
+      cog.outl("    }")
+      cog.outl("")
+      cog.outl("    enum")
+      cog.outl("    {")
+      cog.out("      SIZE      = etl::largest<")
+      for n in range(1, int(Handlers)):
+          cog.out("T%s, " % n)
+      cog.outl("T%s>::size," % int(Handlers))
+      cog.out("      ALIGNMENT = etl::largest<")
+      for n in range(1, int(Handlers)):
+          cog.out("T%s, " % n)
+      cog.outl("T%s>::alignment" % int(Handlers))
+      cog.outl("    };")
+      cog.outl("")
+      cog.outl("  private:")
+      cog.outl("")
+      cog.outl("    typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;")
+      cog.outl("  };")
+      cog.outl("")
+      cog.outl("  //**********************************************")
+      cog.outl("  message_router(etl::message_router_id_t id_)")
+      cog.outl("    : imessage_router(id_)")
+      cog.outl("  {")
+      cog.outl("    ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));")
+      cog.outl("  }")
+      cog.outl("")
+      cog.outl("  //**********************************************")
+      cog.outl("  message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)")
+      cog.outl("    : imessage_router(id_, successor_)")
+      cog.outl("  {")
+      cog.outl("    ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));")
+      cog.outl("  }")
+      cog.outl("")
+      cog.outl("  //**********************************************")
+      cog.outl("  void receive(const etl::imessage& msg)")
+      cog.outl("  {")
+      cog.outl("    receive(etl::null_message_router::instance(), msg);")
+      cog.outl("  }")
+      cog.outl("")
+      cog.outl("  //**********************************************")
+      cog.outl("  void receive(etl::imessage_router& source, const etl::imessage& msg)")
+      cog.outl("  {")
+      cog.outl("    const etl::message_id_t id = msg.message_id;")
+      cog.outl("")
+      cog.outl("    switch (id)")
+      cog.outl("    {")
+      for n in range(1, int(Handlers) + 1):
+          cog.out("      case T%d::ID:" % n)
+          cog.out(" static_cast<TDerived*>(this)->on_receive(source, static_cast<const T%d&>(msg));" % n)
+          cog.outl(" break;")
+      cog.outl("      default:")
+      cog.outl("      {")
+      cog.outl("         if (has_successor())")
+      cog.outl("         {")
+      cog.outl("           get_successor().receive(source, msg);")
+      cog.outl("         }")
+      cog.outl("         else")
+      cog.outl("         {")
+      cog.outl("           static_cast<TDerived*>(this)->on_receive_unknown(source, msg);")
+      cog.outl("         }")
+      cog.outl("         break;")
+      cog.outl("      }")
+      cog.outl("    }")
+      cog.outl("  }")
+      cog.outl("")
+      cog.outl("  using imessage_router::accepts;")
+      cog.outl("")
+      cog.outl("  //**********************************************")
+      cog.outl("  bool accepts(etl::message_id_t id) const")
+      cog.outl("  {")
+      cog.outl("    switch (id)")
+      cog.outl("    {")
+      cog.out("      ")
+      for n in range(1, int(Handlers) + 1):
+          cog.out("case T%d::ID: " % n)
+          if n % 8 == 0:
+              cog.outl("")
+              cog.out("      ")
+      cog.outl("  return true; break;")
+      cog.outl("      default:")
+      cog.outl("        return false; break;")
+      cog.outl("    }")
+      cog.outl("  }")
+      cog.outl("};")
+
+      ####################################
+      # All of the other specialisations.
+      ####################################
+      for n in range(int(Handlers) - 1, 0, -1):
+          cog.outl("")
+          cog.outl("//***************************************************************************")
+          if n == 1:
+              cog.outl("// Specialisation for %d message type." % n)
+          else:
+              cog.outl("// Specialisation for %d message types." % n)
+          cog.outl("//***************************************************************************")
+          cog.outl("template <typename TDerived, ")
+          cog.out("          ")
+          for t in range(1, n):
+              cog.out("typename T%d, " % t)
+              if t % 4 == 0:
+                  cog.outl("")
+                  cog.out("          ")
+          cog.outl("typename T%d>" % n)
+          cog.out("class message_router<TDerived, ")
+          for t in range(1, n + 1):
+              cog.out("T%d, " % t)
+              if t % 16 == 0:
+                  cog.outl("")
+                  cog.out("               ")
+          for t in range(n + 1, int(Handlers)):
+              cog.out("void, ")
+              if t % 16 == 0:
+                  cog.outl("")
+                  cog.out("               ")
+          cog.outl("void>")
+          cog.outl(" : public imessage_router")
+          cog.outl("{")
+          cog.outl("public:")
+          cog.outl("")
+          cog.outl("  //**********************************************")
+          cog.outl("  class message_packet")
+          cog.outl("  {")
+          cog.outl("  public:")
+          cog.outl("")
+          cog.outl("    //********************************************")
+          cog.outl("    explicit message_packet(const etl::imessage& msg)")
+          cog.outl("    {")
+          cog.outl("      const size_t id = msg.message_id;")
+          cog.outl("")
+          cog.outl("      void* p = data;")
+          cog.outl("")
+          cog.outl("      switch (id)")
+          cog.outl("      {")
+          for t in range(1, n + 1):
+              cog.outl("        case T%s::ID: ::new (p) T%s(static_cast<const T%s&>(msg)); break;" % (t, t, t))
+          cog.outl("        default: ETL_ASSERT(false, ETL_ERROR(unhandled_message_exception)); break;")
+          cog.outl("      }")
+          cog.outl("    }")
+          cog.outl("")
+          cog.outl("    //********************************************")
+          cog.outl("    template <typename T>")
+          cog.outl("    explicit message_packet(const T& msg)")
+          cog.outl("    {")
+          cog.out("      STATIC_ASSERT((etl::is_one_of<T, ")
+          for t in range(1, n):
+              cog.out("T%s, " % t)
+              if t % 16 == 0:
+                  cog.outl("")
+                  cog.out("                                       ")
+          cog.outl("""T%s>::value), "Unsupported type for this message packet");""" % n)
+          cog.outl("")
+          cog.outl("      void* p = data;")
+          cog.outl("      ::new (p) T(static_cast<const T&>(msg));")
+          cog.outl("    }")
+          cog.outl("")
+          cog.outl("    //********************************************")
+          cog.outl("    ~message_packet()")
+          cog.outl("    {")
+          cog.outl("      static_cast<etl::imessage*>(data)->~imessage();")
+          cog.outl("    }")
+          cog.outl("")
+          cog.outl("    //********************************************")
+          cog.outl("    etl::imessage& get()")
+          cog.outl("    {")
+          cog.outl("      return *static_cast<etl::imessage*>(data);")
+          cog.outl("    }")
+          cog.outl("")
+          cog.outl("    //********************************************")
+          cog.outl("    const etl::imessage& get() const")
+          cog.outl("    {")
+          cog.outl("      return *static_cast<const etl::imessage*>(data);")
+          cog.outl("    }")
+          cog.outl("")
+          cog.outl("    enum")
+          cog.outl("    {")
+          cog.out("      SIZE      = etl::largest<")
+          for t in range(1, n):
+              cog.out("T%s, " % t)
+          cog.outl("T%s>::size," % n)
+          cog.out("      ALIGNMENT = etl::largest<")
+          for t in range(1, n):
+              cog.out("T%s, " % t)
+          cog.outl("T%s>::alignment" % n)
+          cog.outl("    };")
+          cog.outl("")
+          cog.outl("  private:")
+          cog.outl("")
+          cog.outl("    typename etl::aligned_storage<SIZE, ALIGNMENT>::type data;")
+          cog.outl("  };")
+          cog.outl("")
+          cog.outl("  //**********************************************")
+          cog.outl("  message_router(etl::message_router_id_t id_)")
+          cog.outl("    : imessage_router(id_)")
+          cog.outl("  {")
+          cog.outl("    ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));")
+          cog.outl("  }")
+          cog.outl("")
+          cog.outl("  //**********************************************")
+          cog.outl("  message_router(etl::message_router_id_t id_, etl::imessage_router& successor_)")
+          cog.outl("    : imessage_router(id_, successor_)")
+          cog.outl("  {")
+          cog.outl("    ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));")
+          cog.outl("  }")
+          cog.outl("")
+          cog.outl("  //**********************************************")
+          cog.outl("  void receive(const etl::imessage& msg)")
+          cog.outl("  {")
+          cog.outl("    receive(etl::null_message_router::instance(), msg);")
+          cog.outl("  }")
+          cog.outl("")
+          cog.outl("  //**********************************************")
+          cog.outl("  void receive(etl::imessage_router& source, const etl::imessage& msg)")
+          cog.outl("  {")
+          cog.outl("    const size_t id = msg.message_id;")
+          cog.outl("")
+          cog.outl("    switch (id)")
+          cog.outl("    {")
+          for t in range(1, n + 1):
+              cog.out("      case T%d::ID:" % t)
+              cog.out(" static_cast<TDerived*>(this)->on_receive(source, static_cast<const T%d&>(msg));" % t)
+              cog.outl(" break;")
+          cog.outl("      default:")
+          cog.outl("      {")
+          cog.outl("         if (has_successor())")
+          cog.outl("         {")
+          cog.outl("           get_successor().receive(source, msg);")
+          cog.outl("         }")
+          cog.outl("         else")
+          cog.outl("         {")
+          cog.outl("           static_cast<TDerived*>(this)->on_receive_unknown(source, msg);")
+          cog.outl("         }")
+          cog.outl("         break;")
+          cog.outl("      }")
+          cog.outl("    }")
+          cog.outl("  }")
+          cog.outl("")
+          cog.outl("  using imessage_router::accepts;")
+          cog.outl("")
+          cog.outl("  //**********************************************")
+          cog.outl("  bool accepts(etl::message_id_t id) const")
+          cog.outl("  {")
+          cog.outl("    switch (id)")
+          cog.outl("    {")
+          cog.out("      ")
+          for t in range(1, n + 1):
+              cog.out("case T%d::ID: " % t)
+              if t % 8 == 0:
+                  cog.outl("")
+                  cog.out("      ")
+          cog.outl("")
+          cog.outl("        return true; break;")
+          cog.outl("      default:")
+          cog.outl("        return false; break;")
+          cog.outl("    }")
+          cog.outl("  }")
+          cog.outl("};")
+  ]]]*/
+  /*[[[end]]]*/
+}
+
+#undef ETL_FILE
+
+#endif
+