From f9624f37283dbfd9489205ba0e3f8d29b0f83db2 Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Wed, 5 Dec 2012 00:14:56 +0100 Subject: digital/ucoolib/ucoolib/arch/host/mex: add mex module --- digital/ucoolib/build/setup.mk | 2 +- digital/ucoolib/ucoolib/arch/host/mex/Config | 2 + digital/ucoolib/ucoolib/arch/host/mex/Module | 2 + digital/ucoolib/ucoolib/arch/host/mex/mex.hh | 56 ++++ digital/ucoolib/ucoolib/arch/host/mex/mex_msg.hh | 148 +++++++++++ .../ucoolib/ucoolib/arch/host/mex/mex_msg.host.cc | 290 +++++++++++++++++++++ digital/ucoolib/ucoolib/arch/host/mex/mex_node.hh | 123 +++++++++ .../ucoolib/ucoolib/arch/host/mex/mex_node.host.cc | 185 +++++++++++++ .../ucoolib/ucoolib/arch/host/mex/mex_socket.hh | 59 +++++ .../ucoolib/arch/host/mex/mex_socket.host.cc | 95 +++++++ digital/ucoolib/ucoolib/arch/host/mex/socket.h | 39 +++ .../ucoolib/ucoolib/arch/host/mex/socket.host.c | 87 +++++++ .../ucoolib/ucoolib/arch/host/mex/test/Makefile | 9 + digital/ucoolib/ucoolib/arch/host/mex/test/hub.py | 6 + .../ucoolib/ucoolib/arch/host/mex/test/test_mex.cc | 247 ++++++++++++++++++ 15 files changed, 1349 insertions(+), 1 deletion(-) create mode 100644 digital/ucoolib/ucoolib/arch/host/mex/Config create mode 100644 digital/ucoolib/ucoolib/arch/host/mex/Module create mode 100644 digital/ucoolib/ucoolib/arch/host/mex/mex.hh create mode 100644 digital/ucoolib/ucoolib/arch/host/mex/mex_msg.hh create mode 100644 digital/ucoolib/ucoolib/arch/host/mex/mex_msg.host.cc create mode 100644 digital/ucoolib/ucoolib/arch/host/mex/mex_node.hh create mode 100644 digital/ucoolib/ucoolib/arch/host/mex/mex_node.host.cc create mode 100644 digital/ucoolib/ucoolib/arch/host/mex/mex_socket.hh create mode 100644 digital/ucoolib/ucoolib/arch/host/mex/mex_socket.host.cc create mode 100644 digital/ucoolib/ucoolib/arch/host/mex/socket.h create mode 100644 digital/ucoolib/ucoolib/arch/host/mex/socket.host.c create mode 100644 digital/ucoolib/ucoolib/arch/host/mex/test/Makefile create mode 100644 digital/ucoolib/ucoolib/arch/host/mex/test/hub.py create mode 100644 digital/ucoolib/ucoolib/arch/host/mex/test/test_mex.cc (limited to 'digital') 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 + +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 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::iterator out, const char *fmt); + void push (int64_t v); + private: + friend class Msg; + std::vector::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::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::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 (payload_[head_skip_ - 1]); +} + +void +Msg::write (MsgWriter &writer) +{ + assert (head_skip_ >= 1); + payload_[head_skip_ - 1] = static_cast (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 (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 (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::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::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 (*in_++); + return r; +} + +int64_t +MsgPoper::pop (int bits, bool sign) +{ + switch (*fmt_++) + { + case 'l': + assert (bits >= 31 && sign); + return static_cast (pop_bytes (4)); + case 'L': + assert (bits >= 32); + return static_cast (pop_bytes (4)); + case 'h': + assert (bits >= 15 && sign); + return static_cast (pop_bytes (2)); + case 'H': + assert (bits >= 16); + return static_cast (pop_bytes (2)); + case 'b': + assert (bits >= 7 && sign); + return static_cast (pop_bytes (1)); + case 'B': + assert (bits >= 8); + return static_cast (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 +#include + +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 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 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 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 handlers_type; + handlers_type handlers_; + /// Handlers objects. + HandlerMemfun 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 + +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 = 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 = 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 = recv (); + dispatch (*msg); + } +} + +void +Node::send (Msg &msg) +{ + msg.write (socket_); +} + +std::auto_ptr +Node::request (Msg &msg) +{ + // Send request. + msg.encapsulate (MTYPE_REQ, "B") << 0; + send (msg); + // Wait for response. + std::auto_ptr 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 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); +} + +void +Node::handler_register (mtype_t mtype, Handler &handler) +{ + std::pair r = + handlers_.insert (handlers_type::value_type (mtype, &handler)); + assert (r.second); +} + +std::auto_ptr +Node::recv () +{ + return std::auto_ptr (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 +#include + +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 +#include +#include +#include +#include +#include +#include +#include + +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 +#include + +#include +#include +#include + +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 + 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 + 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 (0x20)); + m.push ("bb") << 1 << 2; + m.encapsulate (static_cast (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 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; +} -- cgit v1.2.3