summaryrefslogtreecommitdiff
path: root/digital
diff options
context:
space:
mode:
authorNicolas Schodet2012-12-05 00:14:56 +0100
committerNicolas Schodet2012-12-05 00:28:21 +0100
commitf9624f37283dbfd9489205ba0e3f8d29b0f83db2 (patch)
tree31ffda3cd97fec1e08bf441d9dde2a68bab27fa9 /digital
parentb937879b60f88a67e580b054071c099f66ff32e2 (diff)
digital/ucoolib/ucoolib/arch/host/mex: add mex module
Diffstat (limited to 'digital')
-rw-r--r--digital/ucoolib/build/setup.mk2
-rw-r--r--digital/ucoolib/ucoolib/arch/host/mex/Config2
-rw-r--r--digital/ucoolib/ucoolib/arch/host/mex/Module2
-rw-r--r--digital/ucoolib/ucoolib/arch/host/mex/mex.hh56
-rw-r--r--digital/ucoolib/ucoolib/arch/host/mex/mex_msg.hh148
-rw-r--r--digital/ucoolib/ucoolib/arch/host/mex/mex_msg.host.cc290
-rw-r--r--digital/ucoolib/ucoolib/arch/host/mex/mex_node.hh123
-rw-r--r--digital/ucoolib/ucoolib/arch/host/mex/mex_node.host.cc185
-rw-r--r--digital/ucoolib/ucoolib/arch/host/mex/mex_socket.hh59
-rw-r--r--digital/ucoolib/ucoolib/arch/host/mex/mex_socket.host.cc95
-rw-r--r--digital/ucoolib/ucoolib/arch/host/mex/socket.h39
-rw-r--r--digital/ucoolib/ucoolib/arch/host/mex/socket.host.c87
-rw-r--r--digital/ucoolib/ucoolib/arch/host/mex/test/Makefile9
-rw-r--r--digital/ucoolib/ucoolib/arch/host/mex/test/hub.py6
-rw-r--r--digital/ucoolib/ucoolib/arch/host/mex/test/test_mex.cc247
15 files changed, 1349 insertions, 1 deletions
diff --git a/digital/ucoolib/build/setup.mk b/digital/ucoolib/build/setup.mk
index 4ccd1cc3..91185019 100644
--- a/digital/ucoolib/build/setup.mk
+++ b/digital/ucoolib/build/setup.mk
@@ -4,7 +4,7 @@
TARGETS ?= host
-DEFAULT_MODULES ?= arch
+DEFAULT_MODULES ?= arch arch/host/mex
ALL_PROGS := $(PROGS) $(foreach target,$(TARGETS),$($(target)_PROGS))
diff --git a/digital/ucoolib/ucoolib/arch/host/mex/Config b/digital/ucoolib/ucoolib/arch/host/mex/Config
new file mode 100644
index 00000000..de679f08
--- /dev/null
+++ b/digital/ucoolib/ucoolib/arch/host/mex/Config
@@ -0,0 +1,2 @@
+[arch/host/mex]
+default_address = "localhost", "2442"
diff --git a/digital/ucoolib/ucoolib/arch/host/mex/Module b/digital/ucoolib/ucoolib/arch/host/mex/Module
new file mode 100644
index 00000000..941482ba
--- /dev/null
+++ b/digital/ucoolib/ucoolib/arch/host/mex/Module
@@ -0,0 +1,2 @@
+arch_host_mex_SOURCES := mex_msg.host.cc mex_node.host.cc mex_socket.host.cc \
+ socket.host.c
diff --git a/digital/ucoolib/ucoolib/arch/host/mex/mex.hh b/digital/ucoolib/ucoolib/arch/host/mex/mex.hh
new file mode 100644
index 00000000..682d9d2d
--- /dev/null
+++ b/digital/ucoolib/ucoolib/arch/host/mex/mex.hh
@@ -0,0 +1,56 @@
+#ifndef ucoolib_arch_host_mex_mex_hh
+#define ucoolib_arch_host_mex_mex_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// APBTeam:
+// Web: http://apbteam.org/
+// Email: team AT apbteam DOT org
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// }}}
+
+namespace ucoo {
+namespace mex {
+
+/// Message type identifiers.
+enum mtype_t
+{
+ /// IDLE message, sent by nodes to the hub to signal it had handled all
+ /// messages. It can have an optional parameter: the date at which the
+ /// node will not be idle anymore.
+ MTYPE_IDLE = 0,
+ /// DATE message, sent by the hub to the nodes to update the current date
+ /// value, sent by a node to request the current date (useful at startup).
+ MTYPE_DATE = 1,
+ /// REQ (request) message, sent from a node to other nodes to request a
+ /// response message.
+ MTYPE_REQ = 2,
+ /// RSP (response) message, response to a REQ message, only sent to the
+ /// requesting node.
+ MTYPE_RSP = 3,
+ /// RES (reserve) message, sent to the hub to request a message type, sent
+ /// to a node with the allocated message type.
+ MTYPE_RES = 4,
+ /// First unreserved message identifier, to be used by user messages.
+ MTYPE_USER_MIN = 0x20,
+};
+
+} // namespace mex
+} // namespace ucoo
+
+#endif // ucoolib_arch_host_mex_mex_hh
diff --git a/digital/ucoolib/ucoolib/arch/host/mex/mex_msg.hh b/digital/ucoolib/ucoolib/arch/host/mex/mex_msg.hh
new file mode 100644
index 00000000..d717f18b
--- /dev/null
+++ b/digital/ucoolib/ucoolib/arch/host/mex/mex_msg.hh
@@ -0,0 +1,148 @@
+#ifndef ucoolib_arch_host_mex_mex_msg_hh
+#define ucoolib_arch_host_mex_mex_msg_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// APBTeam:
+// Web: http://apbteam.org/
+// Email: team AT apbteam DOT org
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// }}}
+#include "ucoolib/common.hh"
+
+#include "ucoolib/arch/host/mex/mex.hh"
+
+#include <vector>
+
+namespace ucoo {
+namespace mex {
+
+class MsgPusher;
+class MsgPoper;
+class MsgReader;
+class MsgWriter;
+
+/// Mex message.
+///
+/// Format used for payload push and pop:
+/// - b: 8 bits.
+/// - h: 16 bits.
+/// - l: 32 bits.
+/// Uppercase is used for unsigned.
+class Msg
+{
+ public:
+ /// New message with the given MTYPE.
+ explicit Msg (mtype_t mtype);
+ /// Read a new message.
+ explicit Msg (MsgReader &reader);
+ /// Write a message.
+ void write (MsgWriter &writer);
+ /// Add data to the message payload. FMT string describes the provided
+ /// data. Return a pusher which will do the actual push, using the
+ /// operator<<.
+ MsgPusher push (const char *fmt);
+ /// Add data to the message payload from a buffer.
+ void push (const char *buffer, int size);
+ /// Extract data from the message payload. FMT string describes the
+ /// requested data. Return a poper which will do the actual pop, using
+ /// the operator>>.
+ MsgPoper pop (const char *fmt);
+ /// Pop buffer of given size. Data is kept valid as long as this object
+ /// is alive.
+ const char *pop (int size);
+ /// Encapsulate a message in another one, adding header data. Return a
+ /// pusher which will do the actual header data push, using the
+ /// operator<<.
+ MsgPusher encapsulate (mtype_t mtype, const char *fmt);
+ /// Decapsulate a message from payload. The current payload becomes the
+ /// full message.
+ void decapsulate ();
+ /// Get remaining length.
+ int len () const;
+ /// Get message type.
+ mtype_t mtype () const { return mtype_; }
+ private:
+ /// Message payload, not including message type.
+ std::vector<char> payload_;
+ /// Unused space at head of payload.
+ int head_skip_;
+ /// Message type.
+ mtype_t mtype_;
+};
+
+/// Helper used to push data to message.
+class MsgPusher
+{
+ public:
+ /// Push an integer.
+ MsgPusher &operator<< (int32_t v);
+ /// Push an unsigned integer, used when an int is not enough.
+ MsgPusher &operator<< (uint32_t v);
+ private:
+ MsgPusher (std::vector<char>::iterator out, const char *fmt);
+ void push (int64_t v);
+ private:
+ friend class Msg;
+ std::vector<char>::iterator out_;
+ const char *fmt_;
+};
+
+/// Helper used to pop data from message.
+class MsgPoper
+{
+ public:
+ /// Pop for each supported types.
+ MsgPoper &operator>> (int32_t &v);
+ MsgPoper &operator>> (uint32_t &v);
+ MsgPoper &operator>> (int16_t &v);
+ MsgPoper &operator>> (uint16_t &v);
+ MsgPoper &operator>> (int8_t &v);
+ MsgPoper &operator>> (uint8_t &v);
+ private:
+ MsgPoper (std::vector<char>::const_iterator in, const char *fmt);
+ uint32_t pop_bytes (int bytes);
+ int64_t pop (int bits, bool sign);
+ private:
+ friend class Msg;
+ std::vector<char>::const_iterator in_;
+ const char *fmt_;
+};
+
+/// Abstract Msg reader.
+class MsgReader
+{
+ public:
+ /// Get message size.
+ virtual int size () = 0;
+ /// Read message bytes to provided buffer.
+ virtual void read (char *buf) = 0;
+};
+
+/// Abstract Msg writer.
+class MsgWriter
+{
+ public:
+ /// Write COUNT bytes from provided buffer.
+ virtual void write (const char *buf, int count) = 0;
+};
+
+} // namespace mex
+} // namespace ucoo
+
+#endif // ucoolib_arch_host_mex_mex_msg_hh
diff --git a/digital/ucoolib/ucoolib/arch/host/mex/mex_msg.host.cc b/digital/ucoolib/ucoolib/arch/host/mex/mex_msg.host.cc
new file mode 100644
index 00000000..93d40956
--- /dev/null
+++ b/digital/ucoolib/ucoolib/arch/host/mex/mex_msg.host.cc
@@ -0,0 +1,290 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// APBTeam:
+// Web: http://apbteam.org/
+// Email: team AT apbteam DOT org
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// }}}
+#define __STDC_LIMIT_MACROS 1
+#include "mex_msg.hh"
+
+namespace ucoo {
+namespace mex {
+
+const int default_head_skip = 3;
+
+/// Compute needed size to store given format.
+static int
+calcsize (const char *fmt)
+{
+ int size = 0;
+ for (; *fmt; fmt++)
+ {
+ switch (*fmt)
+ {
+ case 'l':
+ case 'L':
+ size += 4;
+ break;
+ case 'h':
+ case 'H':
+ size += 2;
+ break;
+ case 'b':
+ case 'B':
+ size += 1;
+ break;
+ }
+ }
+ return size;
+}
+
+Msg::Msg (mtype_t mtype)
+ : head_skip_ (default_head_skip),
+ mtype_ (mtype)
+{
+ payload_.resize (head_skip_);
+}
+
+Msg::Msg (MsgReader &reader)
+ : head_skip_ (default_head_skip),
+ mtype_ (MTYPE_IDLE)
+{
+ int size = reader.size ();
+ payload_.resize (head_skip_ - 1 + size);
+ reader.read (&payload_.front () + head_skip_ - 1);
+ mtype_ = static_cast<mtype_t> (payload_[head_skip_ - 1]);
+}
+
+void
+Msg::write (MsgWriter &writer)
+{
+ assert (head_skip_ >= 1);
+ payload_[head_skip_ - 1] = static_cast<int> (mtype_);
+ writer.write (&payload_.front () + head_skip_ - 1,
+ payload_.size () - head_skip_ + 1);
+}
+
+MsgPusher
+Msg::push (const char *fmt)
+{
+ int push_index = payload_.size ();
+ payload_.resize (push_index + calcsize (fmt));
+ return MsgPusher (payload_.begin () + push_index, fmt);
+}
+
+void
+Msg::push (const char *buffer, int size)
+{
+ payload_.insert (payload_.end (), buffer, buffer + size);
+}
+
+MsgPoper
+Msg::pop (const char *fmt)
+{
+ int pop_size = calcsize (fmt);
+ assert (pop_size <= (int) payload_.size () - head_skip_);
+ int pop_index = head_skip_;
+ head_skip_ += pop_size;
+ return MsgPoper (payload_.begin () + pop_index, fmt);
+}
+
+const char *
+Msg::pop (int size)
+{
+ assert (size <= (int) payload_.size () - head_skip_);
+ const char *r = &payload_.front () + head_skip_;
+ head_skip_ += size;
+ return r;
+}
+
+MsgPusher
+Msg::encapsulate (mtype_t mtype, const char *fmt)
+{
+ int head_size = calcsize (fmt) + 1;
+ assert (head_size <= head_skip_);
+ payload_[head_skip_ - 1] = static_cast<int> (mtype_);
+ mtype_ = mtype;
+ head_skip_ -= head_size;
+ return MsgPusher (payload_.begin () + head_skip_, fmt);
+}
+
+void
+Msg::decapsulate ()
+{
+ assert (1 <= payload_.size () - head_skip_);
+ mtype_ = static_cast<mtype_t> (payload_[head_skip_]);
+ head_skip_++;
+}
+
+int
+Msg::len () const
+{
+ return payload_.size () - head_skip_;
+}
+
+MsgPusher &
+MsgPusher::operator<< (int32_t v)
+{
+ push (v);
+ return *this;
+}
+
+MsgPusher &
+MsgPusher::operator<< (uint32_t v)
+{
+ push (v);
+ return *this;
+}
+
+MsgPusher::MsgPusher (std::vector<char>::iterator out, const char *fmt)
+ : out_ (out),
+ fmt_ (fmt)
+{
+}
+
+void
+MsgPusher::push (int64_t v)
+{
+ switch (*fmt_)
+ {
+ case 'l':
+ assert (v >= INT32_MIN && v <= INT32_MAX);
+ break;
+ case 'L':
+ assert (v >= 0 && v <= UINT32_MAX);
+ break;
+ case 'h':
+ assert (v >= INT16_MIN && v <= INT16_MAX);
+ break;
+ case 'H':
+ assert (v >= 0 && v <= UINT16_MAX);
+ break;
+ case 'b':
+ assert (v >= INT8_MIN && v <= INT8_MAX);
+ break;
+ case 'B':
+ assert (v >= 0 && v <= UINT8_MAX);
+ break;
+ default:
+ assert (0);
+ }
+ switch (*fmt_)
+ {
+ case 'l':
+ case 'L':
+ *out_++ = v >> 24;
+ *out_++ = v >> 16;
+ case 'h':
+ case 'H':
+ *out_++ = v >> 8;
+ case 'b':
+ case 'B':
+ *out_++ = v >> 0;
+ }
+ fmt_++;
+}
+
+MsgPoper &
+MsgPoper::operator>> (int32_t &v)
+{
+ v = pop (31, true);
+ return *this;
+}
+
+MsgPoper &
+MsgPoper::operator>> (uint32_t &v)
+{
+ v = pop (32, false);
+ return *this;
+}
+
+MsgPoper &
+MsgPoper::operator>> (int16_t &v)
+{
+ v = pop (15, true);
+ return *this;
+}
+
+MsgPoper &
+MsgPoper::operator>> (uint16_t &v)
+{
+ v = pop (16, false);
+ return *this;
+}
+
+MsgPoper &
+MsgPoper::operator>> (int8_t &v)
+{
+ v = pop (7, true);
+ return *this;
+}
+
+MsgPoper &
+MsgPoper::operator>> (uint8_t &v)
+{
+ v = pop (8, false);
+ return *this;
+}
+
+MsgPoper::MsgPoper (std::vector<char>::const_iterator in, const char *fmt)
+ : in_ (in),
+ fmt_ (fmt)
+{
+}
+
+uint32_t
+MsgPoper::pop_bytes (int bytes)
+{
+ uint32_t r = 0;
+ while (bytes--)
+ r = r << 8 | static_cast<unsigned char> (*in_++);
+ return r;
+}
+
+int64_t
+MsgPoper::pop (int bits, bool sign)
+{
+ switch (*fmt_++)
+ {
+ case 'l':
+ assert (bits >= 31 && sign);
+ return static_cast<int32_t> (pop_bytes (4));
+ case 'L':
+ assert (bits >= 32);
+ return static_cast<uint32_t> (pop_bytes (4));
+ case 'h':
+ assert (bits >= 15 && sign);
+ return static_cast<int16_t> (pop_bytes (2));
+ case 'H':
+ assert (bits >= 16);
+ return static_cast<uint16_t> (pop_bytes (2));
+ case 'b':
+ assert (bits >= 7 && sign);
+ return static_cast<int8_t> (pop_bytes (1));
+ case 'B':
+ assert (bits >= 8);
+ return static_cast<uint8_t> (pop_bytes (1));
+ default:
+ assert_unreachable ();
+ }
+}
+
+} // namespace mex
+} // namespace ucoo
diff --git a/digital/ucoolib/ucoolib/arch/host/mex/mex_node.hh b/digital/ucoolib/ucoolib/arch/host/mex/mex_node.hh
new file mode 100644
index 00000000..fecb8c00
--- /dev/null
+++ b/digital/ucoolib/ucoolib/arch/host/mex/mex_node.hh
@@ -0,0 +1,123 @@
+#ifndef ucoolib_arch_host_mex_mex_node_hh
+#define ucoolib_arch_host_mex_mex_node_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// APBTeam:
+// Web: http://apbteam.org/
+// Email: team AT apbteam DOT org
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// }}}
+#include "ucoolib/common.hh"
+#include "mex_msg.hh"
+#include "mex_socket.hh"
+
+#include <memory>
+#include <map>
+
+namespace ucoo {
+namespace mex {
+
+class Node;
+
+/// Abstract message reception handler.
+class Handler
+{
+ public:
+ /// Handle a received message or request.
+ virtual void handle (Msg &msg) = 0;
+};
+
+/// Helper class for member function reception handler.
+template<class T>
+class HandlerMemfun : public Handler
+{
+ public:
+ HandlerMemfun (T &obj, void (T::*f) (Msg &))
+ : obj_ (obj), f_ (f) { }
+ void handle (Msg &msg) { (obj_.*f_) (msg); }
+ private:
+ T &obj_;
+ void (T::*f_) (Msg &);
+};
+
+/// Helper class for static function reception handler.
+class HandlerPtrfun : public Handler
+{
+ public:
+ HandlerPtrfun (void (*f) (Msg &)) : f_ (f) { }
+ void handle (Msg &msg) { f_ (msg); }
+ private:
+ void (*f_) (Msg &);
+};
+
+/// Mex node, singleton.
+class Node
+{
+ public:
+ /// Connect to mex hub.
+ Node ();
+ /// Disconnect.
+ ~Node ();
+ /// Get single instance, may return NULL if none constructed.
+ static Node *instance () { return instance_; }
+ /// Wait forever.
+ void wait ();
+ /// Wait until date is reached.
+ void wait (uint32_t date);
+ /// Return current date.
+ uint32_t date () const { return date_; }
+ /// Send a message.
+ void send (Msg &msg);
+ /// Send a request and return response.
+ std::auto_ptr<Msg> request (Msg &msg);
+ /// Send a response while handling a request.
+ void response (Msg &msg);
+ /// Reserve a message type.
+ mtype_t reserve (const char *name);
+ /// Register an handler for a message type.
+ void handler_register (mtype_t mtype, Handler &handler);
+ private:
+ /// Receive one message.
+ std::auto_ptr<Msg> recv ();
+ /// Dispatch message to the right handler.
+ void dispatch (Msg &msg);
+ /// Handle an incomming DATE message.
+ void handle_date (Msg &msg);
+ /// Handle an incomming REQ message.
+ void handle_req (Msg &msg);
+ private:
+ /// Pointer to single instance.
+ static Node *instance_;
+ /// Connection to hub.
+ Socket socket_;
+ /// Current date.
+ uint32_t date_;
+ /// When handling a request, this is the request identifier, else -1.
+ int req_;
+ /// Registered handlers.
+ typedef std::map<mtype_t, Handler *> handlers_type;
+ handlers_type handlers_;
+ /// Handlers objects.
+ HandlerMemfun<Node> handler_date, handler_req;
+};
+
+} // namespace mex
+} // namespace ucoo
+
+#endif // ucoolib_arch_host_mex_mex_node_hh
diff --git a/digital/ucoolib/ucoolib/arch/host/mex/mex_node.host.cc b/digital/ucoolib/ucoolib/arch/host/mex/mex_node.host.cc
new file mode 100644
index 00000000..5fdd81ae
--- /dev/null
+++ b/digital/ucoolib/ucoolib/arch/host/mex/mex_node.host.cc
@@ -0,0 +1,185 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// APBTeam:
+// Web: http://apbteam.org/
+// Email: team AT apbteam DOT org
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// }}}
+#include "mex_node.hh"
+
+#include <cstring>
+
+namespace ucoo {
+namespace mex {
+
+Node *Node::instance_;
+
+Node::Node ()
+ : date_ (0),
+ req_ (-1),
+ handler_date (*this, &Node::handle_date),
+ handler_req (*this, &Node::handle_req)
+{
+ assert (!instance_);
+ instance_ = this;
+ // Connect.
+ socket_.connect ();
+ // Setup default handlers.
+ handler_register (MTYPE_DATE, handler_date);
+ handler_register (MTYPE_REQ, handler_req);
+ // Synchronise with the hub.
+ bool sync = false;
+ while (!sync)
+ {
+ std::auto_ptr<Msg> msg = recv ();
+ if (msg->mtype () == MTYPE_DATE)
+ sync = true;
+ dispatch (*msg);
+ }
+}
+
+Node::~Node ()
+{
+ instance_ = 0;
+}
+
+void
+Node::wait ()
+{
+ while (1)
+ {
+ // Signal IDLE state.
+ Msg idle (MTYPE_IDLE);
+ send (idle);
+ // Receive and dispatch messages.
+ std::auto_ptr<Msg> msg = recv ();
+ dispatch (*msg);
+ }
+}
+
+void
+Node::wait (uint32_t date)
+{
+ while (date_ != date)
+ {
+ // Signal IDLE state.
+ Msg idle (MTYPE_IDLE);
+ idle.push ("L") << date;
+ send (idle);
+ // Receive and dispatch messages.
+ std::auto_ptr<Msg> msg = recv ();
+ dispatch (*msg);
+ }
+}
+
+void
+Node::send (Msg &msg)
+{
+ msg.write (socket_);
+}
+
+std::auto_ptr<Msg>
+Node::request (Msg &msg)
+{
+ // Send request.
+ msg.encapsulate (MTYPE_REQ, "B") << 0;
+ send (msg);
+ // Wait for response.
+ std::auto_ptr<Msg> rsp;
+ rsp = recv ();
+ while (rsp->mtype () != MTYPE_RSP)
+ {
+ dispatch (*rsp);
+ rsp = recv ();
+ }
+ // Eat unused request identifier.
+ rsp->pop ("B");
+ rsp->decapsulate ();
+ return rsp;
+}
+
+void
+Node::response (Msg &msg)
+{
+ assert (req_ != -1);
+ msg.encapsulate (MTYPE_RSP, "B") << req_;
+ send (msg);
+ req_ = -1;
+}
+
+mtype_t
+Node::reserve (const char *name)
+{
+ // Send request.
+ Msg msg (MTYPE_RES);
+ msg.push (name, std::strlen (name));
+ send (msg);
+ // Wait for response.
+ std::auto_ptr<Msg> rsp;
+ rsp = recv ();
+ while (rsp->mtype () != MTYPE_RES)
+ {
+ dispatch (*rsp);
+ rsp = recv ();
+ }
+ // Return allocated message type.
+ int mtype;
+ rsp->pop ("B") >> mtype;
+ return static_cast<mtype_t> (mtype);
+}
+
+void
+Node::handler_register (mtype_t mtype, Handler &handler)
+{
+ std::pair<handlers_type::iterator, bool> r =
+ handlers_.insert (handlers_type::value_type (mtype, &handler));
+ assert (r.second);
+}
+
+std::auto_ptr<Msg>
+Node::recv ()
+{
+ return std::auto_ptr<Msg> (new Msg (socket_));
+}
+
+void
+Node::dispatch (Msg &msg)
+{
+ handlers_type::const_iterator it = handlers_.find (msg.mtype ());
+ if (it != handlers_.end ())
+ it->second->handle (msg);
+}
+
+void
+Node::handle_date (Msg &msg)
+{
+ msg.pop ("L") >> date_;
+}
+
+void
+Node::handle_req (Msg &msg)
+{
+ msg.pop ("B") >> req_;
+ msg.decapsulate ();
+ dispatch (msg);
+ req_ = -1;
+}
+
+} // namespace mex
+} // namespace ucoo
diff --git a/digital/ucoolib/ucoolib/arch/host/mex/mex_socket.hh b/digital/ucoolib/ucoolib/arch/host/mex/mex_socket.hh
new file mode 100644
index 00000000..0c28bab2
--- /dev/null
+++ b/digital/ucoolib/ucoolib/arch/host/mex/mex_socket.hh
@@ -0,0 +1,59 @@
+#ifndef ucoolib_arch_host_mex_mex_socket_hh
+#define ucoolib_arch_host_mex_mex_socket_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// APBTeam:
+// Web: http://apbteam.org/
+// Email: team AT apbteam DOT org
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// }}}
+#include "mex_msg.hh"
+
+namespace ucoo {
+namespace mex {
+
+/// Mex socket, able to read and write messages.
+class Socket : public MsgReader, public MsgWriter
+{
+ public:
+ /// Default constructor.
+ Socket () : fd_ (-1), read_size_ (-1) { }
+ /// Destructor, close the connection.
+ ~Socket ();
+ /// Connect to Mex hub.
+ void connect ();
+ /// See MsgReader::size.
+ int size ();
+ /// See MsgReader::read.
+ void read (char *buf);
+ /// See MsgWriter::write.
+ void write (const char *buf, int count);
+ private:
+ /// File descriptor to open socket, or -1 if not open.
+ int fd_;
+ /// Size of the next message to be read, or -1 if not known yet.
+ int read_size_;
+ /// This socket sequence number.
+ int seq_;
+};
+
+} // namespace mex
+} // namespace ucoo
+
+#endif // ucoolib_arch_host_mex_mex_socket_hh
diff --git a/digital/ucoolib/ucoolib/arch/host/mex/mex_socket.host.cc b/digital/ucoolib/ucoolib/arch/host/mex/mex_socket.host.cc
new file mode 100644
index 00000000..15bff8a8
--- /dev/null
+++ b/digital/ucoolib/ucoolib/arch/host/mex/mex_socket.host.cc
@@ -0,0 +1,95 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// APBTeam:
+// Web: http://apbteam.org/
+// Email: team AT apbteam DOT org
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// }}}
+#include "mex_socket.hh"
+
+#include "ucoolib/common.hh"
+
+#include "config/arch/host/mex.hh"
+#include "socket.h"
+
+#include <unistd.h>
+#include <cstdlib>
+
+namespace ucoo {
+namespace mex {
+
+Socket::~Socket ()
+{
+ if (fd_ != -1)
+ close (fd_);
+}
+
+void
+Socket::connect ()
+{
+ fd_ = socket_client UCOO_CONFIG_ARCH_HOST_MEX_DEFAULT_ADDRESS;
+}
+
+int
+Socket::size ()
+{
+ uint8_t header[3];
+ int r = ::read (fd_, header, sizeof (header));
+ assert_perror (r != -1);
+ if (r == 0)
+ exit (0);
+ else
+ {
+ assert (r == sizeof (header));
+ read_size_ = (header[0] << 8) | header[1];
+ seq_ = header[2];
+ return read_size_;
+ }
+}
+
+void
+Socket::read (char *buf)
+{
+ assert (fd_ != -1);
+ assert (read_size_ > 0);
+ int r = ::read (fd_, buf, read_size_);
+ assert_perror (r != -1);
+ assert (r == read_size_);
+ read_size_ = -1;
+}
+
+void
+Socket::write (const char *buf, int count)
+{
+ assert (fd_ != -1);
+ assert (read_size_ == -1);
+ uint8_t header[3];
+ header[0] = count >> 8;
+ header[1] = count;
+ header[2] = seq_;
+ int r = ::write (fd_, header, sizeof (header));
+ assert_perror (r != -1);
+ assert (r == sizeof (header));
+ r = ::write (fd_, buf, count);
+ assert_perror (r != -1);
+ assert (r == count);
+}
+
+} // namespace mex
+} // namespace ucoo
diff --git a/digital/ucoolib/ucoolib/arch/host/mex/socket.h b/digital/ucoolib/ucoolib/arch/host/mex/socket.h
new file mode 100644
index 00000000..c77d7e47
--- /dev/null
+++ b/digital/ucoolib/ucoolib/arch/host/mex/socket.h
@@ -0,0 +1,39 @@
+#ifndef ucoolib_arch_host_mex_socket_h
+#define ucoolib_arch_host_mex_socket_h
+/* ucoolib - Microcontroller object oriented library. {{{
+ *
+ * Copyright (C) 2012 Nicolas Schodet
+ *
+ * APBTeam:
+ * Web: http://apbteam.org/
+ * Email: team AT apbteam DOT org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * }}} */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Create and connect a client socket. */
+int
+socket_client (const char *addr, const char *port);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ucoolib_arch_host_mex_socket_h */
diff --git a/digital/ucoolib/ucoolib/arch/host/mex/socket.host.c b/digital/ucoolib/ucoolib/arch/host/mex/socket.host.c
new file mode 100644
index 00000000..213b667f
--- /dev/null
+++ b/digital/ucoolib/ucoolib/arch/host/mex/socket.host.c
@@ -0,0 +1,87 @@
+/* imported from mysock library and modified for ucoolib.
+ * mysock library - client functions. {{{
+ *
+ * Copyright (C) 2001 Nicolas Schodet
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contact :
+ * Web: http://ni.fr.eu.org/
+ *
+ * }}} */
+#include "socket.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+int
+socket_client (const char *addr, const char *port)
+{
+ int s;
+ struct sockaddr_in saddr;
+ struct servent *port_info;
+ struct hostent *host_info;
+ unsigned short int iport;
+ unsigned int iaddr;
+ iport = htons (atoi (port));
+ if (!iport)
+ {
+ port_info = getservbyname (port, "tcp");
+ if (!port_info)
+ {
+ fprintf (stderr, "Service %s unknown\n", port);
+ exit (EXIT_FAILURE);
+ }
+ iport = port_info->s_port;
+ }
+ iaddr = inet_addr (addr);
+ if (iaddr == INADDR_NONE)
+ {
+ host_info = gethostbyname (addr);
+ if (!host_info)
+ {
+ fprintf (stderr, "Host %s unknown\n", addr);
+ exit (EXIT_FAILURE);
+ }
+ iaddr = * (int *) host_info->h_addr;
+ }
+ saddr.sin_family = AF_INET;
+ saddr.sin_addr.s_addr = iaddr;
+ saddr.sin_port = iport;
+ s = socket (AF_INET, SOCK_STREAM, 0);
+ if (s < 0)
+ {
+ perror ("socket");
+ exit (EXIT_FAILURE);
+ }
+ int on = 1;
+ if (setsockopt (s, IPPROTO_TCP, TCP_NODELAY, (void *) &on, sizeof (on))
+ < 0)
+ {
+ perror ("setsockopt (NODELAY)");
+ exit (EXIT_FAILURE);
+ }
+ if (connect (s, (struct sockaddr *) &saddr, sizeof (saddr)) < 0)
+ {
+ perror ("connect");
+ exit (EXIT_FAILURE);
+ }
+ return s;
+}
diff --git a/digital/ucoolib/ucoolib/arch/host/mex/test/Makefile b/digital/ucoolib/ucoolib/arch/host/mex/test/Makefile
new file mode 100644
index 00000000..d54907cc
--- /dev/null
+++ b/digital/ucoolib/ucoolib/arch/host/mex/test/Makefile
@@ -0,0 +1,9 @@
+BASE = ../../../../..
+
+TARGETS = host
+host_PROGS = test_mex
+test_mex_SOURCES = test_mex.cc
+
+MODULES =
+
+include $(BASE)/build/top.mk
diff --git a/digital/ucoolib/ucoolib/arch/host/mex/test/hub.py b/digital/ucoolib/ucoolib/arch/host/mex/test/hub.py
new file mode 100644
index 00000000..31dcec1d
--- /dev/null
+++ b/digital/ucoolib/ucoolib/arch/host/mex/test/hub.py
@@ -0,0 +1,6 @@
+# Hub for test.
+from mex.hub import Hub
+def log (x):
+ print x
+h = Hub (min_clients = 2, log = log)
+h.wait ()
diff --git a/digital/ucoolib/ucoolib/arch/host/mex/test/test_mex.cc b/digital/ucoolib/ucoolib/arch/host/mex/test/test_mex.cc
new file mode 100644
index 00000000..f260203b
--- /dev/null
+++ b/digital/ucoolib/ucoolib/arch/host/mex/test/test_mex.cc
@@ -0,0 +1,247 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2012 Nicolas Schodet
+//
+// APBTeam:
+// Web: http://apbteam.org/
+// Email: team AT apbteam DOT org
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// }}}
+#include "ucoolib/arch/host/mex/mex_msg.hh"
+#include "ucoolib/arch/host/mex/mex_node.hh"
+#include "ucoolib/arch/arch.hh"
+#include "ucoolib/common.hh"
+
+#include <cstdio>
+#include <cstring>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+using namespace ucoo::mex;
+
+/// Global error number, should be zero at end of test.
+static int error;
+
+/// Helper function, print a buffer.
+static void
+printbuf (const char *head, const char *buf, int count)
+{
+ printf ("%s:", head);
+ for (int i = 0; i < count; i++)
+ printf (" %02x", (unsigned char) buf[i]);
+ printf ("\n");
+}
+
+/// Helper function, check for equality.
+static void
+check (int64_t a, int64_t b, const char *name = NULL)
+{
+ printf ("%s: %Lx\n", name ? name : "pop", a);
+ if (a != b)
+ {
+ printf (" expected: %Lx\n", b);
+ error++;
+ }
+}
+
+/// Test writer, will check what is written and display it.
+class TestWriter : public MsgWriter
+{
+ const char *exbuf_;
+ int excount_;
+ public:
+ template<int count>
+ TestWriter (const char (&buf)[count])
+ : exbuf_ (buf), excount_ (count) { }
+ void write (const char *buf, int count)
+ {
+ printbuf ("write", buf, count);
+ if (count != excount_ || memcmp (buf, exbuf_, count) != 0)
+ {
+ printbuf (" expected", exbuf_, excount_);
+ error++;
+ }
+ }
+};
+
+/// Test reader, will return a predefined message and display it.
+class TestReader : public MsgReader
+{
+ const char *buf_;
+ int count_;
+ public:
+ template<int count>
+ TestReader (const char (&buf)[count])
+ : buf_ (buf), count_ (count) { }
+ int size () { return count_; }
+ void read (char *buf)
+ {
+ printbuf ("read", buf_, count_);
+ memcpy (buf, buf_, count_);
+ }
+};
+
+/// Test message class.
+void
+test_msg ()
+{
+ {
+ Msg m (MTYPE_DATE);
+ const char w1b[] = { 0x01 };
+ TestWriter w1 (w1b);
+ m.write (w1);
+ m.push ("BHl") << 1 << 2 << 3;
+ m.push ("\x04\x05", 2);
+ const char w2b[] = { 0x01, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03,
+ 0x04, 0x05 };
+ TestWriter w2 (w2b);
+ m.write (w2);
+ }
+ {
+ uint32_t ua, ub, uc;
+ int32_t a, b, c;
+ const char rb[] = { 0x01, 0xff, 0xfe, 0xfd, 0xfc, 1, 2, 3, 4 };
+ TestReader r (rb);
+ Msg m (r);
+ check (m.mtype (), 1, "mtype");
+ check (m.len (), 8, "len");
+ m.pop ("BBH") >> ua >> ub >> uc;
+ check (ua, 0xff); check (ub, 0xfe); check (uc, 0xfdfc);
+ m.pop ("BBH") >> ua >> ub >> uc;
+ check (ua, 1); check (ub, 2); check (uc, 0x304);
+ m = Msg (r);
+ m.pop ("bbh") >> a >> b >> c;
+ check (a, -1); check (b, -2); check (c, -0x204);
+ m.pop ("bbh") >> a >> b >> c;
+ check (a, 1); check (b, 2); check (c, 0x304);
+ m = Msg (r);
+ m.pop ("LL") >> ua >> ub;
+ check (ua, 0xfffefdfc); check (ub, 0x01020304);
+ m = Msg (r);
+ m.pop ("ll") >> a >> b;
+ check (a, -0x010204); check (b, 0x01020304);
+ m = Msg (r);
+ const char *s;
+ s = m.pop (8);
+ printbuf ("pop", s, 8);
+ if (memcmp (s, &rb[1], 8) != 0)
+ {
+ printbuf (" expected", &rb[1], 8);
+ error++;
+ }
+ }
+ {
+ Msg m (static_cast<mtype_t> (0x20));
+ m.push ("bb") << 1 << 2;
+ m.encapsulate (static_cast<mtype_t> (0x21), "b") << 5;
+ check (m.mtype (), 0x21, "mtype");
+ check (m.len (), 4, "len");
+ const char w1b[] = { 0x21, 0x05, 0x20, 0x01, 0x02 };
+ TestWriter w1 (w1b);
+ m.write (w1);
+ m.pop ("b");
+ m.decapsulate ();
+ check (m.mtype (), 0x20, "mtype");
+ check (m.len (), 2, "len");
+ }
+}
+
+void
+test_node_1 ()
+{
+ Node node;
+ mtype_t hello_mtype, world_mtype;
+ hello_mtype = node.reserve ("hello");
+ world_mtype = node.reserve ("world");
+ node.wait (42);
+ Msg hello (hello_mtype);
+ hello.push ("l") << 42;
+ node.send (hello);
+ Msg world (world_mtype);
+ world.push ("bh") << 12 << 5678;
+ std::auto_ptr<Msg> resp (node.request (world));
+ int sum;
+ resp->pop ("l") >> sum;
+ ucoo::assert (sum == 12 + 5678);
+ node.wait (42 * 2);
+}
+
+void
+test_node_2_handle_hello (Msg &msg)
+{
+ int pass;
+ msg.pop ("l") >> pass;
+ ucoo::assert (pass == 42);
+ printf ("hello\n");
+}
+
+void
+test_node_2_handle_world (Msg &msg)
+{
+ int a, b;
+ msg.pop ("bh") >> a >> b;
+ printf ("world\n");
+ Msg resp (msg.mtype ());
+ resp.push ("l") << a + b;
+ Node::instance ()->response (resp);
+}
+
+void
+test_node_2 ()
+{
+ Node node;
+ mtype_t hello_mtype, world_mtype;
+ hello_mtype = node.reserve ("hello");
+ world_mtype = node.reserve ("world");
+ HandlerPtrfun hello_handler (test_node_2_handle_hello);
+ HandlerPtrfun world_handler (test_node_2_handle_world);
+ node.handler_register (hello_mtype, hello_handler);
+ node.handler_register (world_mtype, world_handler);
+ node.wait ();
+}
+
+/// Test node operation, need a Mex hub to work.
+void
+test_node ()
+{
+ int pid;
+ pid = fork ();
+ ucoo::assert_perror (pid != -1);
+ if (pid)
+ {
+ test_node_1 ();
+ int status;
+ waitpid (pid, &status, 0);
+ }
+ else
+ {
+ test_node_2 ();
+ ucoo::assert_unreachable ();
+ }
+}
+
+int
+main (int argc, const char **argv)
+{
+ ucoo::arch_init (argc, argv);
+ test_msg ();
+ test_node ();
+ printf ("%s\n", error ? "FAIL" : "PASS");
+ return error ? 1 : 0;
+}