summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Schodet2011-03-30 20:08:34 +0200
committerNicolas Schodet2011-03-30 20:08:34 +0200
commit057180987cacfe47edbe21bf2f8c0573901ded2f (patch)
treece5eb7c68525ead0430d43051428a9234ebfa053
parentc9a004ed32389dd17167f19be7916ef9320e8e39 (diff)
host/mex, digital/avr/modules/host: add message type reservation, refs #157
-rw-r--r--digital/avr/modules/host/mex.h10
-rw-r--r--digital/avr/modules/host/mex.host.c37
-rw-r--r--digital/avr/modules/host/test/test_mex.c31
-rw-r--r--host/mex/__init__.py4
-rw-r--r--host/mex/doc/mex.txt21
-rw-r--r--host/mex/hub.py18
-rw-r--r--host/mex/node.py15
-rw-r--r--host/mex/test/test.py14
8 files changed, 130 insertions, 20 deletions
diff --git a/digital/avr/modules/host/mex.h b/digital/avr/modules/host/mex.h
index feb91188..82e65103 100644
--- a/digital/avr/modules/host/mex.h
+++ b/digital/avr/modules/host/mex.h
@@ -35,6 +35,7 @@ enum mex_mtype_t
MEX_MTYPE_DATE = 1,
MEX_MTYPE_REQ = 2,
MEX_MTYPE_RSP = 3,
+ MEX_MTYPE_RES = 4,
};
/** Message structure opaque definition. */
@@ -121,4 +122,13 @@ mex_node_response (mex_msg_t *msg);
void
mex_node_register (u8 mtype, mex_handler_t *handler, void *user);
+/** Request a message type reservation. */
+u8
+mex_node_reserve (const char *mtype_str);
+
+/** Request a message type reservation, using formated string. */
+u8
+mex_node_reservef (const char *mtype_fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
#endif /* mex_h */
diff --git a/digital/avr/modules/host/mex.host.c b/digital/avr/modules/host/mex.host.c
index d82a4947..8921cadd 100644
--- a/digital/avr/modules/host/mex.host.c
+++ b/digital/avr/modules/host/mex.host.c
@@ -30,6 +30,7 @@
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
+#include <stdio.h>
#include <unistd.h>
#include <errno.h>
@@ -501,6 +502,42 @@ mex_node_register (u8 mtype, mex_handler_t *handler, void *user)
mex_node_global.handlers_user[mtype] = user;
}
+/** Request a message type reservation. */
+u8
+mex_node_reserve (const char *mtype_str)
+{
+ /* Send request. */
+ mex_msg_t *m = mex_msg_new (MEX_MTYPE_RES);
+ mex_msg_push_buffer (m, mtype_str, strlen (mtype_str));
+ mex_node_send (m);
+ /* Wait for response. */
+ mex_msg_t *rsp;
+ rsp = mex_node_recv ();
+ while (rsp->mtype != MEX_MTYPE_RES)
+ {
+ mex_node_dispatch (rsp);
+ mex_msg_delete (rsp);
+ rsp = mex_node_recv ();
+ }
+ /* Return allocated message type. */
+ u8 mtype;
+ mex_msg_pop (rsp, "B", &mtype);
+ return mtype;
+}
+
+/** Request a message type reservation, using formated string. */
+u8
+mex_node_reservef (const char *mtype_fmt, ...)
+{
+ va_list ap;
+ char mtype_str[MEX_MSG_NEW_PAYLOAD_SIZE + 1];
+ va_start (ap, mtype_fmt);
+ int r = vsnprintf (mtype_str, sizeof (mtype_str), mtype_fmt, ap);
+ assert (r < (int) sizeof (mtype_str));
+ va_end (ap);
+ return mex_node_reserve (mtype_str);
+}
+
/** Receive one message. */
static mex_msg_t *
mex_node_recv (void)
diff --git a/digital/avr/modules/host/test/test_mex.c b/digital/avr/modules/host/test/test_mex.c
index 1e5d303e..e79e6f68 100644
--- a/digital/avr/modules/host/test/test_mex.c
+++ b/digital/avr/modules/host/test/test_mex.c
@@ -28,8 +28,10 @@
#include <stdio.h>
+u8 mtype_coucou1, mtype_coucou2, mtype_oucouc;
+
void
-a82 (void *user, mex_msg_t *msg)
+handle_oucouc (void *user, mex_msg_t *msg)
{
printf ("oucouc\n");
u8 nb;
@@ -41,14 +43,14 @@ a82 (void *user, mex_msg_t *msg)
}
void
-a801 (void *user, mex_msg_t *msg)
+handle_coucou (void *user, mex_msg_t *msg)
{
printf ("coucou\n");
u8 b;
u16 h;
u32 l;
mex_msg_pop (msg, "BHL", &b, &h, &l);
- if (mex_msg_mtype (msg) == 0x80)
+ if (mex_msg_mtype (msg) == mtype_coucou1)
assert (b == 1 && h == 2 && l == 3);
else
assert (b == 4 && h == 5 && l == 6);
@@ -66,22 +68,27 @@ main (int argc, char **argv)
fprintf (stderr, "%s 1|2\n", argv[0]);
return 1;
}
+ mex_node_connect ();
+ mtype_coucou1 = mex_node_reservef ("%s%d", "coucou", 1);
+ mtype_coucou2 = mex_node_reservef ("%s%d", "coucou", 2);
+ mtype_oucouc = mex_node_reserve ("oucouc");
if (argv[1][0] == '1')
{
- mex_node_register (0x82, a82, NULL);
- mex_node_connect ();
+ mex_node_register (mtype_oucouc, handle_oucouc, NULL);
i = host_fetch_integer ("reseted");
if (i == -1)
{
- mex_msg_t *m = mex_msg_new (0x80);
+ mex_node_wait_date (1);
+ mex_msg_t *m = mex_msg_new (mtype_coucou1);
mex_msg_push (m, "BHL", 1, 2, 3);
mex_node_send (m);
host_register_integer ("reseted", 1);
+ mex_node_wait_date (2);
host_reset ();
}
else
{
- mex_msg_t *m = mex_msg_new (0x81);
+ mex_msg_t *m = mex_msg_new (mtype_coucou2);
mex_msg_push (m, "BHL", 4, 5, 6);
mex_node_send (m);
mex_node_wait ();
@@ -89,13 +96,13 @@ main (int argc, char **argv)
}
else
{
- mex_node_register (0x80, a801, NULL);
- mex_node_register (0x81, a801, NULL);
- mex_node_connect ();
- mex_msg_t *m = mex_msg_new (0x82);
+ mex_node_register (mtype_coucou1, handle_coucou, NULL);
+ mex_node_register (mtype_coucou2, handle_coucou, NULL);
+ mex_node_wait_date (1);
+ mex_msg_t *m = mex_msg_new (mtype_oucouc);
mex_msg_push (m, "B", 42);
mex_msg_t *r = mex_node_request (m);
- assert (mex_msg_mtype (r) == 0x82);
+ assert (mex_msg_mtype (r) == mtype_oucouc);
u8 rb;
mex_msg_pop (r, "B", &rb);
assert (rb == 43);
diff --git a/host/mex/__init__.py b/host/mex/__init__.py
index 1855d708..f87cf856 100644
--- a/host/mex/__init__.py
+++ b/host/mex/__init__.py
@@ -40,6 +40,10 @@ RSP = 3
"""RSP (response) message, response to a REQ message, only sent to the
requesting node."""
+RES = 4
+"""RES (reserve) message, sent to the hub to request a message type, sent to a
+node with the allocated message type."""
+
DEFAULT_ADDR = ('localhost', 2442)
HEADER_FMT = '!HB'
diff --git a/host/mex/doc/mex.txt b/host/mex/doc/mex.txt
index 4c8eb559..ef299d56 100644
--- a/host/mex/doc/mex.txt
+++ b/host/mex/doc/mex.txt
@@ -37,9 +37,8 @@ been handled (or discarded).
The minimum required information in a message is the message type. This is a
single byte (with some reserved values) which should be sufficient to decode
-the rest of the message. There is for the moment no central message type
-identifier repository, the developer is responsible to ensure no collision
-occurs.
+the rest of the message. Message types should be reserved by requesting them
+from the hub.
When the message is sent to another process, it is prepended with its size and
sequence number (which are not part of the message, neither its size). The
@@ -167,6 +166,22 @@ RSP
The receiving node will decapsulate the message and will use it as a
response to its request.
+RES
+ This is a message type reservation request.
+
+ When sent to the hub, it contains a reservation string which identify the
+ message type.
+
+ +------------+--------------------+
+ | RES (B: 4) | reservation string |
+ +------------+--------------------+
+
+ When sent to the node, it contains the allocated message type.
+
+ +------------+-----------------+
+ | RES (B: 4) | allocated mtype |
+ +------------+-----------------+
+
Programmer interface
====================
diff --git a/host/mex/hub.py b/host/mex/hub.py
index 4dd796a4..274f5448 100644
--- a/host/mex/hub.py
+++ b/host/mex/hub.py
@@ -36,6 +36,7 @@ class Hub:
self.log = log
self.clients = { }
self.next_client_id = 1
+ self.reserved_mtype = { }
self.date = 0
self.socket = socket.socket ()
self.socket.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
@@ -109,6 +110,18 @@ class Hub:
if c is not exclude:
c.send (msg)
+ def reserve (self, mtype_str):
+ """Reserve a message type."""
+ if mtype_str in self.reserved_mtype:
+ mtype = self.reserved_mtype[mtype_str]
+ else:
+ mtype = 0x20 + len (self.reserved_mtype)
+ self.reserved_mtype[mtype_str] = mtype
+ if self.log:
+ self.log ('[%d] reserve "%s" as %02x' % (self.date,
+ mtype_str, mtype))
+ return mtype
+
class Client:
def __init__ (self, hub, socket, id):
@@ -159,6 +172,11 @@ class Hub:
mr.push ('B', 0)
mr.push (m.pop ())
self.hub.clients[to].send (mr)
+ elif m.mtype == mex.RES:
+ mtype_str = m.pop ()
+ mr = Msg (mex.RES)
+ mr.push ('B', self.hub.reserve (mtype_str))
+ self.send (mr)
else:
self.hub.broadcast (m, self)
diff --git a/host/mex/node.py b/host/mex/node.py
index 8fcf9ae0..a1f226cd 100644
--- a/host/mex/node.py
+++ b/host/mex/node.py
@@ -122,6 +122,21 @@ class Node:
assert mtype not in self.__handlers
self.__handlers[mtype] = handler
+ def reserve (self, mtype_str):
+ """Request a message type reservation."""
+ # Send request.
+ res = Msg (mex.RES)
+ res.push (mtype_str)
+ self.send (res)
+ # Wait for response.
+ rsp = self.__recv ()
+ while rsp.mtype != mex.RES:
+ self.__dispatch (rsp)
+ rsp = self.__recv ()
+ # Return allocated message type.
+ mtype, = rsp.pop ('B')
+ return mtype
+
def schedule (self, date, action):
"""Schedule an action for the given date, return the event identifier."""
assert date > self.date
diff --git a/host/mex/test/test.py b/host/mex/test/test.py
index b9d06e00..91e49ee0 100644
--- a/host/mex/test/test.py
+++ b/host/mex/test/test.py
@@ -35,6 +35,8 @@ h = Hub (min_clients = 2, log = log)
def c1 ():
n = Node ()
+ mtype_oucouc = n.reserve ('oucouc')
+ mtype_coucou = n.reserve ('coucou')
def a (msg):
print 'oucouc'
nb, = msg.pop ('B')
@@ -42,7 +44,7 @@ def c1 ():
m = Msg (msg.mtype)
m.push ('B', nb)
n.response (m)
- n.register (0x82, a)
+ n.register (mtype_oucouc, a)
def b ():
assert False
eb = n.schedule (31, b)
@@ -50,7 +52,7 @@ def c1 ():
print 'hello'
n.cancel (eb)
n.schedule (28, c)
- m = Msg (0x81)
+ m = Msg (mtype_coucou)
n.send (m)
n.wait ()
@@ -58,13 +60,15 @@ f1 = Forked (c1)
def c2 ():
n = Node ()
+ mtype_oucouc = n.reserve ('oucouc')
+ mtype_coucou = n.reserve ('coucou')
def a (msg):
print 'coucou'
- n.register (0x81, a)
- m = Msg (0x82)
+ n.register (mtype_coucou, a)
+ m = Msg (mtype_oucouc)
m.push ('B', 42)
r = n.request (m)
- assert r.mtype == 0x82
+ assert r.mtype == mtype_oucouc
assert r.pop ('B') == (43,)
n.wait_async (42)
while not n.sync ():