]> oss.titaniummirror.com Git - tinyos-2.x.git/commitdiff
Initial tymo commit
authorstrabest <strabest>
Mon, 18 Feb 2008 20:24:55 +0000 (20:24 +0000)
committerstrabest <strabest>
Mon, 18 Feb 2008 20:24:55 +0000 (20:24 +0000)
28 files changed:
tos/lib/net/tymo/ForwardingEngineM.nc [new file with mode: 0644]
tos/lib/net/tymo/LinkMonitor.nc [new file with mode: 0644]
tos/lib/net/tymo/LoopBackM.nc [new file with mode: 0644]
tos/lib/net/tymo/RouteSelect.nc [new file with mode: 0644]
tos/lib/net/tymo/RoutingTable.nc [new file with mode: 0644]
tos/lib/net/tymo/RoutingTableInfo.nc [new file with mode: 0644]
tos/lib/net/tymo/dymo/DymoEngineM.nc [new file with mode: 0644]
tos/lib/net/tymo/dymo/DymoMonitor.nc [new file with mode: 0644]
tos/lib/net/tymo/dymo/DymoNetworkC.nc [new file with mode: 0644]
tos/lib/net/tymo/dymo/DymoPacket.nc [new file with mode: 0644]
tos/lib/net/tymo/dymo/DymoPacketM.nc [new file with mode: 0644]
tos/lib/net/tymo/dymo/DymoServiceC.nc [new file with mode: 0644]
tos/lib/net/tymo/dymo/DymoTable.nc [new file with mode: 0644]
tos/lib/net/tymo/dymo/DymoTableC.nc [new file with mode: 0644]
tos/lib/net/tymo/dymo/DymoTableM.nc [new file with mode: 0644]
tos/lib/net/tymo/dymo/NetControlM.nc [new file with mode: 0644]
tos/lib/net/tymo/dymo/PacketMaker.nc [new file with mode: 0644]
tos/lib/net/tymo/dymo/dymo_packet.h [new file with mode: 0644]
tos/lib/net/tymo/dymo/dymo_table.h [new file with mode: 0644]
tos/lib/net/tymo/dymo/sim/DymoEngineM.nc [new file with mode: 0644]
tos/lib/net/tymo/dymo/sim/DymoServiceC.nc [new file with mode: 0644]
tos/lib/net/tymo/mh/MHControl.nc [new file with mode: 0644]
tos/lib/net/tymo/mh/MHEngineM.nc [new file with mode: 0644]
tos/lib/net/tymo/mh/MHPacketM.nc [new file with mode: 0644]
tos/lib/net/tymo/mh/MHServiceC.nc [new file with mode: 0644]
tos/lib/net/tymo/mh/mhpacket.h [new file with mode: 0644]
tos/lib/net/tymo/routing.h [new file with mode: 0644]
tos/lib/net/tymo/routing_table.h [new file with mode: 0644]

diff --git a/tos/lib/net/tymo/ForwardingEngineM.nc b/tos/lib/net/tymo/ForwardingEngineM.nc
new file mode 100644 (file)
index 0000000..5890ea4
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+#include "routing.h"
+
+/**
+ * ForwardingEngineM - Handles received packets of a certain protocol
+ * in a multihop context.  The component uses a route selector to
+ * determine if the packet should be forwarded or passed to the upper
+ * layer. If the packet is forwarded, the next hop is given by the
+ * route selector.
+ *
+ * @author Romain Thouvenin
+ */
+
+//TODO probably need a lot of cleaning, and to be moved elsewhere
+generic module ForwardingEngineM () {
+  provides { //For the upper layer
+    interface AMSend[uint8_t id];
+    interface Receive[uint8_t id];
+    interface Intercept[uint8_t id];
+    interface LinkMonitor;
+  }
+  uses {
+    interface RouteSelect;
+    interface AMSend as SubSend;
+    interface AMPacket;
+    interface Packet as PPacket; 
+    interface Packet as SubPacket;
+    interface PacketAcknowledgements as Acks;
+    interface Receive as SubReceive;
+    interface Timer<TMilli>;
+  }
+
+  provides interface MHControl;
+}
+
+implementation {
+  message_t buf; //first available, do NOT use it
+  message_t * avail = &buf;
+  message_t * waiting;
+  uint8_t typebuf;
+  uint8_t lenWaiting;
+  uint8_t amWaiting;
+  am_addr_t bufAddr;
+  am_addr_t * addrWaiting;
+  bool lockAvail, lockWaiting;
+  uint32_t wait_time;
+  bool acks;
+
+  enum {
+    WAIT_BEFORE_RETRY = 100,
+    MAX_WAIT = 10 * WAIT_BEFORE_RETRY
+  };
+
+  command error_t AMSend.send[uint8_t am](am_addr_t addr, message_t * msg, uint8_t len){
+    switch(call RouteSelect.selectRoute(msg, &addr, &am)){
+    case FW_SEND:
+      call PPacket.setPayloadLength(msg, len);
+      acks = DYMO_LINK_FEEDBACK && (call Acks.requestAck(msg) == SUCCESS);
+      return call SubSend.send(call AMPacket.destination(msg), msg, call SubPacket.payloadLength(msg));
+
+    case FW_WAIT: 
+      atomic {
+       if(lockWaiting)
+         return EBUSY;
+       lockWaiting = TRUE;
+      }
+      waiting = msg;
+      amWaiting = am;
+      call PPacket.setPayloadLength(msg, len);
+      lenWaiting = call SubPacket.payloadLength(msg);
+      bufAddr = addr;
+      addrWaiting = &bufAddr;
+      wait_time = 0;
+      call Timer.startOneShot(WAIT_BEFORE_RETRY); 
+      dbg("fwe", "FE: I'll retry later.\n");
+      return SUCCESS;
+      
+    default: //We don't allow sending to oneself
+      return FAIL; 
+    }
+  }
+
+  event message_t * SubReceive.receive(message_t * msg, void * payload, uint8_t len){
+    dbg("fwe", "FE: Received a message from %u\n", call AMPacket.source(msg));
+    signal MHControl.msgReceived(msg);
+    switch(call RouteSelect.selectRoute(msg, NULL, &typebuf)){
+    case FW_SEND:
+      atomic {
+       if(lockAvail)
+         return msg;
+       lockAvail = TRUE;
+      }
+      if ( signal Intercept.forward[typebuf](msg, call PPacket.getPayload(msg, call PPacket.payloadLength(msg)), call PPacket.payloadLength(msg)) ) {
+         call SubSend.send(call AMPacket.destination(msg), msg, len);
+      }
+      return avail;
+
+    case FW_RECEIVE:
+      payload = call PPacket.getPayload(msg, call PPacket.payloadLength(msg));
+      return signal Receive.receive[typebuf](msg, payload, call PPacket.payloadLength(msg));
+
+    case FW_WAIT:
+      atomic {
+       if(lockAvail || lockWaiting)
+         return msg;
+       lockAvail = lockWaiting = TRUE;
+      }
+      waiting = msg;
+      lenWaiting = len;
+      addrWaiting = NULL;
+      wait_time = 0;
+      call Timer.startOneShot(WAIT_BEFORE_RETRY);
+      return avail;
+
+    default:
+      return msg;
+    }
+  }
+
+  event void SubSend.sendDone(message_t * msg, error_t e){
+    dbg("fwe", "FE: Sending done.\n");
+    if( (e == SUCCESS) && acks ){
+      if( !(call Acks.wasAcked(msg)) ){
+       e = FAIL;
+       dbg("fwe", "FE: The message was not acked => FAIL.\n");
+       signal MHControl.sendFailed(msg, 2);
+       signal LinkMonitor.brokenLink(call AMPacket.destination(msg));
+      }
+    } else if (e != SUCCESS) {
+      dbg("fwe", "FE: But failed!\n");
+      signal MHControl.sendFailed(msg, 1);
+    }
+
+    if(lockAvail){
+      avail = msg;
+      atomic {
+       lockAvail = FALSE;
+      }
+    } else {
+      signal AMSend.sendDone[amWaiting](msg, e);
+      atomic {
+       lockWaiting = FALSE;
+      }
+    }
+  }
+
+  event void Timer.fired(){
+    switch(call RouteSelect.selectRoute(waiting, addrWaiting, &amWaiting)){
+    case FW_SEND:
+      dbg("fwe", "FE: I'm retrying to send my message.\n");
+      if (addrWaiting) {
+       call SubSend.send(call AMPacket.destination(waiting), waiting, lenWaiting);
+      } else if ( signal Intercept.forward[amWaiting](waiting, 
+                                     call PPacket.getPayload(waiting, call PPacket.payloadLength(waiting)), 
+                                     call PPacket.payloadLength(waiting)) ) {
+       call SubSend.send(call AMPacket.destination(waiting), waiting, lenWaiting);
+      }
+      call Timer.stop();
+      break;
+
+    case FW_WAIT:
+      dbg("fwe", "FE: I'll retry later again.\n");
+      wait_time += call Timer.getdt();
+      if(wait_time < MAX_WAIT){
+       call Timer.startOneShot(wait_time);
+       break;
+      }
+      //else: Continue to default
+
+    default:
+      if(addrWaiting)
+       signal AMSend.sendDone[amWaiting](waiting, FAIL);
+      if(lockAvail){
+       avail = waiting;
+       atomic {
+         lockAvail = FALSE;
+       }
+      }
+      atomic {
+       lockWaiting = FALSE;
+      }
+    }
+  }
+
+  command error_t AMSend.cancel[uint8_t am](message_t *msg){
+    if(lockWaiting){
+      call Timer.stop();
+      atomic {
+       lockWaiting = FALSE;
+      }
+      return SUCCESS;
+    } else {
+      return call SubSend.cancel(msg);
+    }
+  }
+
+  command void * AMSend.getPayload[uint8_t am](message_t *msg, uint8_t len){
+    return call PPacket.getPayload(msg, len);
+  }
+
+  command uint8_t AMSend.maxPayloadLength[uint8_t am](){
+    return call PPacket.maxPayloadLength();
+  }
+
+
+  /*** defaults ***/
+
+ default event message_t * Receive.receive[uint8_t am](message_t * msg, void * payload, uint8_t len){
+   return msg;
+ }
+
+ default event void AMSend.sendDone[uint8_t am](message_t * msg, error_t e){}
+
+ default event bool Intercept.forward[uint8_t am](message_t * msg, void * payload, uint8_t len){
+   return TRUE;
+ }
+
+ default event void MHControl.msgReceived(message_t * msg){ }
+
+ default event void MHControl.sendFailed(message_t * msg, uint8_t why){ }
+
+ default event void LinkMonitor.brokenLink(addr_t neighbor){ }
+}
diff --git a/tos/lib/net/tymo/LinkMonitor.nc b/tos/lib/net/tymo/LinkMonitor.nc
new file mode 100644 (file)
index 0000000..fd86277
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+#include "AM.h"
+
+/**
+ * LinkMonitor - Interface to signals broken links in the neighborhood.
+ *
+ * @author Romain Thouvenin
+ */
+
+interface LinkMonitor {
+
+  event void brokenLink(am_addr_t neighbor);
+
+}
diff --git a/tos/lib/net/tymo/LoopBackM.nc b/tos/lib/net/tymo/LoopBackM.nc
new file mode 100644 (file)
index 0000000..54ec7de
--- /dev/null
@@ -0,0 +1,75 @@
+module LoopBackM {
+  provides {
+    interface AMSend[uint8_t id];
+    interface Receive[uint8_t id];
+  }
+  uses {
+    interface AMSend as SubSend[uint8_t id];
+    interface Receive as SubReceive[uint8_t id];
+    interface AMPacket;
+    interface Packet;
+  }
+}
+implementation {
+
+  message_t first_avail;
+  message_t * avail = &first_avail;
+
+  message_t * buf_msg;
+  uint8_t buf_am;
+
+  task void sendDoneTask(){
+    signal AMSend.sendDone[buf_am](buf_msg, SUCCESS);
+  }
+
+  command error_t AMSend.send[uint8_t am](am_addr_t addr, message_t *msg, uint8_t len){ //TODO set acks
+    if(addr == call AMPacket.address()){
+      buf_am = am;
+      buf_msg = msg;
+      *avail = *msg;
+      dbg("lo", "LO: I am sending the buffer %p.\n", avail);
+      dbg("lo", "LO: its length is %hhu.\n", len);
+      call Packet.setPayloadLength(avail, len);
+      call AMPacket.setDestination(avail, addr);
+      call AMPacket.setSource(avail, addr);
+      post sendDoneTask();
+      avail = signal Receive.receive[call AMPacket.type(msg)](
+                                avail, 
+                                call Packet.getPayload(avail, len),
+                                len);
+      return SUCCESS;
+    } else {
+      return call SubSend.send[am](addr, msg, len);
+    }
+  }
+
+  command error_t AMSend.cancel[uint8_t am](message_t *msg){
+    if(call AMPacket.destination(msg) == call AMPacket.address()){
+      return FAIL;
+    } else {
+      return call SubSend.cancel[am](msg);
+    }
+  }
+
+  command void * AMSend.getPayload[uint8_t am](message_t *msg, uint8_t len){
+    return call SubSend.getPayload[am](msg, len);
+  }
+
+  command uint8_t AMSend.maxPayloadLength[uint8_t am](){
+    return call SubSend.maxPayloadLength[am]();
+  }
+
+  event void SubSend.sendDone[uint8_t am](message_t *msg, error_t error){
+    signal AMSend.sendDone[am](msg, error);
+  }
+
+
+  event message_t * SubReceive.receive[uint8_t am](message_t *msg, void *payload, uint8_t len){
+    return signal Receive.receive[am](msg, payload, len);
+  }
+
+ default event void AMSend.sendDone[uint8_t am](message_t *msg, error_t error){ }
+
+ default event message_t * Receive.receive[uint8_t am](message_t *msg, void *payload, uint8_t len){ return msg; }
+
+}
diff --git a/tos/lib/net/tymo/RouteSelect.nc b/tos/lib/net/tymo/RouteSelect.nc
new file mode 100644 (file)
index 0000000..d7103f9
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+#include "routing.h"
+
+/**
+ * Interface to a route selection in a multi-hop context.
+ *
+ * @author Romain Thouvenin
+ */
+
+interface RouteSelect {
+
+  /**
+   * Ask the routing engine to fill a message with routing
+   * information, in order to send it to its target.
+   *
+   * @param msg The message to be sent
+   * @param destination The target of the route. If NULL, it is assumed it can be read in the packet
+   * @return The action that should be taken by the forwarding engine.
+   */
+  command fw_action_t selectRoute(message_t * msg, addr_t * destination, uint8_t * am_type);
+  
+}
diff --git a/tos/lib/net/tymo/RoutingTable.nc b/tos/lib/net/tymo/RoutingTable.nc
new file mode 100644 (file)
index 0000000..a268d7c
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+#include "routing_table.h"
+
+/**
+ * RoutingTable - Interface to manipulate a data structure that stores
+ * a table of routes toward a number of destinations.
+ *
+ * @author Romain Thouvenin
+ */
+
+interface RoutingTable {
+
+  /**
+   * Request for a route toward a destination.
+   * @param Address of the destination node
+   * @param info A pointer where to store the routing information 
+   *        associated to the destination, ignored if NULL
+   * @return SUCCESS if the route exists<br/>
+   *         EBUSY if the route does not exist but may be available soon
+   *         FAIL  if the route exists but is broken
+   */
+  command error_t getRoute(addr_t address, rt_info_t * info);
+
+  command error_t getForwardingRoute(addr_t address, rt_info_t * info);
+
+  /**
+   * Signal that a route has been removed from the table.
+   * @param route_info Routing information associated to the evicted entry
+   * @param r reason of the eviction
+   */
+  event void evicted(const rt_info_t * route_info, reason_t r);
+
+}
diff --git a/tos/lib/net/tymo/RoutingTableInfo.nc b/tos/lib/net/tymo/RoutingTableInfo.nc
new file mode 100644 (file)
index 0000000..d88ea0f
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+#include "routing_table.h"
+
+typedef nx_struct rt_link {
+  nx_addr_t target;
+  nx_addr_t nexthop;
+} rt_link_t;
+
+interface RoutingTableInfo {
+
+  /**
+   * Size of the table.
+   * @return the number of entries stored in the table
+   */
+  command uint8_t size();
+
+  command uint8_t maxSize();
+
+  command uint8_t getTableContent(rt_info_t * buf);
+
+  command uint8_t getLinks(rt_link_t * buf);
+
+}
diff --git a/tos/lib/net/tymo/dymo/DymoEngineM.nc b/tos/lib/net/tymo/dymo/DymoEngineM.nc
new file mode 100644 (file)
index 0000000..dfecec2
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+#include "routing.h"
+#include "routing_table.h"
+
+/**
+ * DymoEngineM - Implements the algorithms to generate and process
+ * DYMO messages.
+ *
+ * @author Romain Thouvenin
+ */
+
+module DymoEngineM {
+  provides {
+    interface SplitControl;
+  }
+  uses {
+    interface DymoTable;
+    interface RoutingTable;
+    interface DymoPacket;
+    interface AMSend;
+    interface AMPacket;
+    interface Receive;
+    
+    interface Mount;
+    interface ConfigStorage;
+  }
+
+#ifdef DYMO_MONITORING
+  provides interface DymoMonitor;
+  uses {
+    interface Timer<TMilli>;
+  }
+#endif
+}
+
+implementation {
+  message_t * avail_msg; //to be returned by receive
+  message_t buf_avail;   //first avail_msg
+  message_t buf_packet;
+  rt_info_t me;
+  rt_info_t buf_info;
+  addr_t ignoreNeeded;
+  bool busySend;
+
+  /* for processing */
+  bool busyProcess, busyIssue;
+  uint8_t cur_hopcnt;
+  uint8_t cur_info_pos;
+  rt_info_t buf_target;
+  addr_t fw_address; //set to 0 if the message must not be forwarded
+  message_t fw_msg;
+  bool sendRREP;
+
+#ifdef DYMO_MONITORING
+  uint32_t rreq_time;
+#endif
+
+  command error_t SplitControl.start(){
+    me.address = call AMPacket.address();
+    me.has_hopcnt = 1;
+    me.hopcnt = 0;
+
+    avail_msg = &buf_avail;
+    ignoreNeeded = 0;
+    sendRREP = FALSE;
+    busyProcess = FALSE;
+    busyIssue = FALSE;
+    busySend = FALSE;
+    buf_target.address = 0;
+    
+#ifdef DYMO_MONITORING
+    rreq_time = 0;
+#endif
+
+    return call Mount.mount();
+  }
+
+  void incr_seqnum(){
+    if(me.seqnum == 65535)
+      me.seqnum = 256;
+    else
+      me.seqnum++;
+
+    call ConfigStorage.write(0x0, &me.seqnum, sizeof(me.seqnum));
+  }
+
+  event void ConfigStorage.writeDone(storage_addr_t addr, void *buf, 
+    storage_len_t len, error_t err) {
+    // Verify addr and len
+
+    if (err == SUCCESS) {
+      if (call ConfigStorage.commit() != SUCCESS) {
+        // Handle failure
+      }
+    }
+    else {
+      // Handle failure
+    }
+  }
+
+  event void Mount.mountDone(error_t error) {
+    if (error == SUCCESS) {
+      if (call ConfigStorage.valid() == TRUE) {
+        if (call ConfigStorage.read(0x0, &me.seqnum, sizeof(me.seqnum)) != SUCCESS) {
+          me.seqnum = 1;
+         signal SplitControl.startDone(SUCCESS);
+       }
+      }
+      else {
+       // Invalid volume.  Commit to make valid.
+       if (call ConfigStorage.commit() == SUCCESS) {
+         me.seqnum = 1;
+       }
+       else {
+         signal SplitControl.startDone(FAIL);
+       }
+      }
+    }
+    else{
+      signal SplitControl.startDone(error);
+    }
+  }
+
+  event void ConfigStorage.commitDone(error_t err) {
+    if ((err != SUCCESS) && (me.seqnum == 1)) {
+      signal SplitControl.startDone(err);
+    } else if (me.seqnum == 1) {
+      signal SplitControl.startDone(SUCCESS);
+    }
+  }
+
+  event void ConfigStorage.readDone(storage_addr_t addr, void* buf, 
+    storage_len_t len, error_t err) __attribute__((noinline)) {
+
+    if (err == SUCCESS) {
+      me.seqnum = *(seqnum_t *)buf;
+      signal SplitControl.startDone(SUCCESS);
+    } else {
+      signal SplitControl.startDone(err);
+    }
+  }
+
+
+  /* Send a RREQ for buf_info */
+  task void issueRREQ(){
+    atomic {
+      if(busySend)
+       post issueRREQ();
+      else {
+       busySend = TRUE;
+       incr_seqnum();
+       call DymoPacket.createRM(&buf_packet, DYMO_RREQ, &me, &buf_info);
+       call AMSend.send(AM_BROADCAST_ADDR, &buf_packet, call DymoPacket.getSize(&buf_packet));
+      }
+    }
+  }
+
+  /* Send a RREP to buf_info */
+  task void issueRREP(){
+    atomic {
+      if(busySend)
+       post issueRREP();
+      else {
+       busySend = TRUE;
+       call DymoPacket.createRM(&buf_packet, DYMO_RREP, &me, &buf_info);
+       if(buf_target.address)
+         call DymoPacket.addInfo(&buf_packet, &buf_target);
+       call AMSend.send(buf_info.nexthop, &buf_packet, call DymoPacket.getSize(&buf_packet));
+       buf_target.address = 0;
+      }
+    }
+  }
+
+  /* Send a RERR with buf_info as unreachable */
+  task void issueRERR(){
+    atomic {
+      if(busySend)
+       post issueRERR();
+      else {
+       busySend = TRUE;
+       call DymoPacket.createRM(&buf_packet, DYMO_RERR, NULL, &buf_info);
+       call AMSend.send(AM_BROADCAST_ADDR, &buf_packet, call DymoPacket.getSize(&buf_packet));
+      }
+    }
+  }
+
+  /* Send current fw_msg to fw_address */
+  task void forward(){
+    atomic {
+      if(busySend)
+       post forward();
+      else {
+       busySend = TRUE;
+       call AMSend.send(fw_address, &fw_msg, call DymoPacket.getSize(&fw_msg));
+      }
+    }
+  }
+
+  event message_t* Receive.receive(message_t* msg, void* payload, uint8_t len){
+#ifdef DYMO_MONITORING
+    signal DymoMonitor.msgReceived(msg);
+#endif
+    dbg("de", "DE: Message (type %hhu) received.\n", call DymoPacket.getType(msg));
+    atomic {
+      if(busyProcess){
+       dbg("de", "DE: I'm busy, I can't handle this message, sorry.\n");
+       return msg; //we discard msg if a message is already being processed
+      } else {
+       busyProcess = TRUE;
+      }
+    }
+    cur_info_pos = 0;
+    fw_address = AM_BROADCAST_ADDR;
+    call DymoPacket.startProcessing(msg, &fw_msg);
+    return avail_msg;
+  }
+
+  event proc_action_t DymoPacket.hopsProcessed(message_t * msg, uint8_t hop_limit, uint8_t hop_count){
+    cur_hopcnt = hop_count; //TODO use this
+    if(hop_limit == 0){
+      fw_address = 0;
+      dbg("de", "DE: This message has reached its HL (%hhu hops) => discard.\n", hop_count);
+      return ACTION_DISCARD_MSG;
+    } else {
+      return ACTION_KEEP;
+    }
+  }
+
+  proc_action_t process_rm_info(message_t * msg, rt_info_t * info){
+    cur_info_pos++;
+    if(cur_info_pos == 1){ //target
+
+      if(info->address == me.address){
+
+       if(call DymoPacket.getType(msg) == DYMO_RREQ){
+         dbg("de", "DE: This RREQ is for me => RREP.\n");
+         if(info->seqnum < me.seqnum)
+           incr_seqnum();
+         sendRREP = TRUE; //to send a RREP when we receive the next event (= originator info)
+       } else {
+         dbg("de", "DE: This RREP is for me, cool!\n");
+       }
+       fw_address = 0;
+       return ACTION_DISCARD_MSG;
+
+      } else { //not for me
+
+       info->nexthop = call AMPacket.source(msg);
+       if(call DymoPacket.getType(msg) == DYMO_RREQ){
+
+#if DYMO_INTER_RREP
+         //if we know a route to the target, we send a intermediate RREP and don't forward the message
+         ignoreNeeded = info->address;
+         if (call RoutingTable.getRoute(info->address, &buf_info) == SUCCESS) {
+#if DYMO_FORCE_INTER_RREP
+           if( !info->seqnum || !(call DymoTable.isSuperior(info, DYMO_RREQ)) ){
+#else
+           if( info->seqnum && !(call DymoTable.isSuperior(info, DYMO_RREQ)) ){
+#endif
+             dbg("de", "DE: This RREQ is for %u, but I know the route => RREP.\n", info->address);
+             buf_target = buf_info;
+             sendRREP = TRUE;
+             fw_address = 0;
+             return ACTION_DISCARD_MSG;
+           }
+         }
+#endif
+         return ACTION_KEEP;
+
+       } else { //RREP
+
+         ignoreNeeded = info->address;
+         dbg("de", "DE: This RREP is for %u.\n", info->address);
+         if(call RoutingTable.getForwardingRoute(info->address, &buf_info) == SUCCESS){
+           fw_address = buf_info.nexthop;
+           return ACTION_KEEP;
+         } else {
+           fw_address = 0;
+           return ACTION_DISCARD_MSG;
+         }
+
+       }//end RREP
+
+      }//end not for me
+
+    } else if((call DymoPacket.getType(msg) == DYMO_RREQ) //end if(info==target)
+             && (cur_info_pos == 2)
+             && (info->address == me.address)){
+
+      fw_address = 0;
+      sendRREP = FALSE;
+      return ACTION_DISCARD_MSG;
+
+    } else {
+
+      info->nexthop = call AMPacket.source(msg);
+      if(call DymoTable.update(info, call DymoPacket.getType(msg)) == EINVAL){
+
+       if(cur_info_pos == 2){ //origin
+         dbg("de", "DE: I am discarding a msg with a bad origin (%u)\n", info->address);
+         fw_address = 0;
+         return ACTION_DISCARD_MSG;
+       } else {               //Additional info
+         return ACTION_DISCARD;
+       }
+
+      } else {
+
+       if((cur_info_pos == 2) && sendRREP){
+         buf_info = *info;
+         atomic {
+           if(!busyIssue){
+             busyIssue = 1;
+             post issueRREP();
+           }
+         }
+         sendRREP = 0;
+       }
+
+#ifdef DYMO_MONITORING 
+       if( rreq_time    //TODO probably misses a test
+           && (cur_info_pos == 2)
+           && (call DymoPacket.getType(msg) == DYMO_RREP) ) {
+         rreq_time = (call Timer.getNow()) - rreq_time;
+         signal DymoMonitor.routeDiscovered(rreq_time, info->address);
+         rreq_time = 0;
+       }
+#endif
+       return ACTION_KEEP;
+
+      }
+
+    } //end info!=target
+  }//end event
+
+  proc_action_t process_err_info(message_t * msg, rt_info_t * info){
+    info->nexthop = call AMPacket.source(msg);
+    if(call DymoTable.update(info, call DymoPacket.getType(msg)) == EINVAL){
+      return ACTION_DISCARD;       
+    } else {
+      cur_info_pos++; //we only count kept pieces of info
+      return ACTION_KEEP;
+    }
+  }
+
+  event proc_action_t DymoPacket.infoProcessed(message_t * msg, rt_info_t * info){
+    if(call DymoPacket.getType(msg) == DYMO_RERR)
+      return process_err_info(msg, info);
+    else
+      return process_rm_info(msg, info);
+  }
+
+  event void DymoPacket.messageProcessed(message_t * msg){
+    avail_msg = msg;
+    if( (call DymoPacket.getType(msg) == DYMO_RERR) && cur_info_pos ){
+
+      post forward();
+
+    } else if( (call DymoPacket.getType(msg) != DYMO_RERR) && fw_address ){
+
+#if DYMO_APPEND_INFO
+      call DymoPacket.addInfo(&fw_msg, me);
+#endif
+      dbg("de", "DE: I'll forward this RM.\n");
+      post forward();
+
+    } else {
+
+      atomic {
+       busyProcess = 0;
+      }
+      dbg("de", "DE: I'm not busy anymore.\n");
+
+    }
+    dbg("de", "DE: Message (type %hhu) successfully processed.\n", call DymoPacket.getType(msg));
+  }
+
+  event void DymoTable.routeNeeded(addr_t destination){
+    if(ignoreNeeded == destination){
+      ignoreNeeded = 0;
+    } else {
+      buf_info.address = destination;
+      buf_info.seqnum = 0;
+      buf_info.has_hopcnt = FALSE;
+      atomic {
+       if(!busyIssue){
+         busyIssue = TRUE;
+#ifdef DYMO_MONITORING
+         rreq_time = call Timer.getNow();
+#endif
+         post issueRREQ();
+       }
+      }
+    }
+  }
+  
+  event void DymoTable.brokenRouteNeeded(const rt_info_t * route_info){
+    buf_info = *route_info;
+    buf_info.has_hopcnt = FALSE;
+    atomic {
+      if(!busyIssue){
+       busyIssue = TRUE;
+       post issueRERR();
+      }
+    }
+  }
+
+  event void RoutingTable.evicted(const rt_info_t * route_info, reason_t r){
+    if(r == REASON_UNREACHABLE){
+      buf_info = *route_info;
+      buf_info.has_hopcnt = FALSE;
+      atomic {
+       if(!busyIssue){
+         busyIssue = TRUE;
+         post issueRERR();
+       }
+      }
+    }
+  }
+
+  event void AMSend.sendDone(message_t *msg, error_t error){
+    atomic {
+      busySend = FALSE;
+    }
+    if(msg == &fw_msg){
+      atomic{
+       busyProcess = FALSE;
+      }
+    } else if(msg == &buf_packet) {
+      atomic {
+       busyIssue = FALSE;
+      }
+    }
+
+    if(error == SUCCESS){
+      if(msg == &fw_msg)
+       dbg("de", "DE: Message (type %hhu) forwarded.\n", call DymoPacket.getType(msg));
+      else
+       dbg("de", "DE: Message (type %hhu) sent.\n", call DymoPacket.getType(msg));
+    } else
+      dbg("de", "DE: Failed to send message (type %hhu).\n", call DymoPacket.getType(msg));
+
+#ifdef DYMO_MONITORING
+    if(error == SUCCESS)
+      signal DymoMonitor.msgSent(msg);
+#endif
+  }
+
+  command error_t SplitControl.stop(){ }
+
+#ifdef DYMO_MONITORING
+
+  event void Timer.fired(){}
+
+ default event void DymoMonitor.msgReceived(message_t * msg){}
+
+ default event void DymoMonitor.msgSent(message_t * msg){}
+
+ default event void DymoMonitor.routeDiscovered(uint32_t delay, addr_t target){}
+
+#endif
+}
+
diff --git a/tos/lib/net/tymo/dymo/DymoMonitor.nc b/tos/lib/net/tymo/dymo/DymoMonitor.nc
new file mode 100644 (file)
index 0000000..f8ec2ed
--- /dev/null
@@ -0,0 +1,11 @@
+#include "message.h"
+
+interface DymoMonitor {
+
+  event void msgReceived(message_t * msg);
+
+  event void msgSent(message_t * msg);
+
+  event void routeDiscovered(uint32_t delay, addr_t target);
+
+}
diff --git a/tos/lib/net/tymo/dymo/DymoNetworkC.nc b/tos/lib/net/tymo/dymo/DymoNetworkC.nc
new file mode 100644 (file)
index 0000000..ecd8315
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+#include "routing.h"
+
+/**
+ * DymoNetworkC - Top level configuration providing a multihop network
+ * layer and implementing DYMO (DYnamic Manet On-demand) routing.
+ *
+ * @author Romain Thouvenin
+ */
+
+configuration DymoNetworkC {
+  provides {
+    interface AMSend as MHSend[uint8_t id];
+    interface AMPacket as MHPacket;
+    interface Packet;
+    interface Receive[uint8_t id];
+    interface Intercept[uint8_t id];
+    interface SplitControl;
+  }
+
+#ifdef DYMO_MONITORING
+  provides {
+    interface DymoMonitor;
+    interface RoutingTableInfo;
+  }
+#endif
+  provides interface MHControl;
+}
+
+implementation {
+  components ActiveMessageC;
+  components new AMReceiverC(AM_MULTIHOP) as MHReceiver, new AMReceiverC(AM_DYMO) as DymoReceiver;
+  components new AMSenderC(AM_MULTIHOP) as MHQueue, new AMSenderC(AM_DYMO) as DymoQueue;
+  components MHServiceC, DymoServiceC, NetControlM, DymoTableC;
+#ifdef LOOPBACK
+  components LoopBackM;
+#endif
+
+#ifdef LOOPBACK
+  MHSend    = LoopBackM.AMSend;
+  Receive   = LoopBackM.Receive;
+#else
+  MHSend    = MHServiceC.MHSend;
+  Receive   = MHServiceC.Receive;
+#endif
+  MHPacket  = MHServiceC.MHPacket;
+  Packet    = MHServiceC.Packet;
+  Intercept = MHServiceC.Intercept;
+
+  SplitControl = NetControlM.SplitControl;
+
+#ifdef LOOPBACK
+  LoopBackM.SubSend    -> MHServiceC.MHSend;
+  LoopBackM.SubReceive -> MHServiceC.Receive;
+  LoopBackM.AMPacket   -> MHServiceC.MHPacket;
+  LoopBackM.Packet     -> MHServiceC.Packet;
+#endif
+
+  MHServiceC.AMPacket    -> ActiveMessageC;
+  MHServiceC.SubPacket   -> ActiveMessageC;
+  MHServiceC.AMSend      -> MHQueue;
+  MHServiceC.SubReceive  -> MHReceiver;
+  MHServiceC.Acks        -> MHQueue;
+
+  DymoServiceC.AMPacket    -> ActiveMessageC;
+  DymoServiceC.Packet      -> ActiveMessageC;
+  DymoServiceC.AMSend      -> DymoQueue;
+  DymoServiceC.Receive     -> DymoReceiver;
+#if DYMO_LINK_FEEDBACK
+  DymoServiceC.LinkMonitor -> MHServiceC;
+#endif
+
+  NetControlM.AMControl     -> ActiveMessageC.SplitControl;
+  NetControlM.TableControl  -> DymoTableC.StdControl;
+  NetControlM.EngineControl -> DymoServiceC.SplitControl;
+
+#ifdef DYMO_MONITORING  
+  RoutingTableInfo = DymoTableC.RoutingTableInfo;
+  DymoMonitor = DymoServiceC.DymoMonitor;
+#endif
+  MHControl   = MHServiceC.MHControl;
+
+}
diff --git a/tos/lib/net/tymo/dymo/DymoPacket.nc b/tos/lib/net/tymo/dymo/DymoPacket.nc
new file mode 100644 (file)
index 0000000..cce1e21
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+#include "routing_table.h"
+
+/**
+ * DymoPacket - Interface to manipulate DYMO packets.
+ *
+ * @author Romain Thouvenin
+ */
+
+interface DymoPacket {
+
+  /*****************
+   * Packet header *
+   *****************/
+
+  /**
+   * Type of the packet.
+   * @return DYMO_RREQ, DYMO_RREP or DYMO_RERR
+   */
+  command dymo_msg_t getType(message_t * msg);
+
+  /**
+   * Size of the packet (all fields included).
+   */
+  command uint16_t getSize(message_t * msg);
+
+
+  /*********************
+   * Creating a packet *
+   *********************/
+
+  /**
+   * Create a routing message.  This is not strictly a Routing Message
+   * as defined by DYMO specs: this is also the command to create a
+   * RERR.
+   * @param msg the buffer to fill
+   * @param msg_type The type of message (RREQ, RREP or RERR)
+   * @param origin The originator of the routing message, should be NULL for a RERR
+   * @param target The target of the routing message, or first unreachable node for a RERR
+   */
+  command void createRM(message_t * msg, dymo_msg_t msg_type, 
+                       const rt_info_t * origin, const rt_info_t * target);
+
+  /**
+   * Append additional information to a message.  This is up to the
+   * implementation to choose where in the message the information
+   * should be added. In anycase, it must not be added before the
+   * target and originator.
+   * @param msg the existing message 
+   * @param info The piece of information to append @return
+   * @return ESIZE if the payload has reached its maximum size<br/>
+   *         SUCCESS otherwise
+   */
+  command error_t addInfo(message_t * msg, const rt_info_t * info);
+
+
+  /***********************
+   * Processing a packet *
+   ***********************/
+
+  /**
+   * Start the processing task of a DYMO message.  Currently, the only
+   * way to access the content of a message is to read it entirely
+   * with this command. It will report all information found thanks to
+   * events above.
+   * @param msg The message to process
+   * @param newmsg The message that will contain the processed message
+   * to be forwarded. May be NULL if such a message is not wanted.
+   */
+  command void startProcessing(message_t * msg, message_t * newmsg);
+
+  /**
+   * Hop values have been extracted from the processed packet.
+   * @param msg the message being processed
+   * @param hop_limit the (decremented) hop limit value of the message
+   * @param hop_count the (incremented) hop count value of the message
+   * @return ACTION_DISCARD_MSG if a building a message to be forwarded
+   * is not wanted anymore (typically when hop_limit==0), 
+   * anything else otherwise.
+   */
+  event proc_action_t hopsProcessed(message_t * msg, uint8_t hop_limit, uint8_t hop_count);
+
+  /**
+   * A piece of routing information has been extracted from the processed packet.
+   * @param msg the message being processed
+   * @param info the extracted piece of information. If present, hopcnt has been decremented.
+   * @return ACTION_KEEP to keep this information in the forwarded message<br/>
+   *         ACTION_DISCARD to remove this information in the forwardedmessage<br/>
+   *         ACTION_DISCARD_MSG to cancel the creation of the forwarded message.
+   */
+  event proc_action_t infoProcessed(message_t * msg, rt_info_t * info);
+
+  /**
+   * Processing task finished.
+   * No further processing event will be signaled for this message.
+   */
+  event void messageProcessed(message_t * msg);
+}
diff --git a/tos/lib/net/tymo/dymo/DymoPacketM.nc b/tos/lib/net/tymo/dymo/DymoPacketM.nc
new file mode 100644 (file)
index 0000000..1ccd18f
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+#include "dymo_packet.h"
+
+/**
+ * DymoPacketM - Implementation of the DYMO packets format.
+ *
+ * @author Romain Thouvenin
+ */
+
+module DymoPacketM {
+  provides {
+    interface DymoPacket;
+    interface PacketMaker; //For tests and debugging
+  }
+  uses interface Packet;
+}
+//TODO generalize size values
+implementation {
+  message_t * currentMsg;
+  message_t * processedMsg;
+
+  /* Local functions */
+  void    create_block(nx_uint8_t * payload, const rt_info_t * info);
+  uint8_t block_size(nx_uint8_t * block);
+  uint8_t block_info_size(nx_uint8_t * block);
+  uint8_t block_header_size(nx_uint8_t * block);
+  uint8_t block_num_addr(nx_uint8_t * block);
+  void    block_get_info(nx_uint8_t * block, uint8_t pos, rt_info_t * info, bool update);
+  nx_uint8_t * block_get_pointer(nx_uint8_t * block, uint8_t pos, uint8_t * size);
+  bool block_can_contain(nx_uint8_t * block, const rt_info_t * info);
+  void block_add_info(nx_uint8_t * block, const rt_info_t * info);
+  void move_data(nx_uint8_t * data, uint8_t amount, uint8_t offset);
+
+
+  /*****************
+   * Packet header *
+   *****************/
+
+  command dymo_msg_t DymoPacket.getType(message_t * msg){
+    nx_uint8_t * p = call Packet.getPayload(msg, 1);
+    return *p;
+  }
+
+  command uint16_t DymoPacket.getSize(message_t * msg){
+    nx_uint8_t * p = call Packet.getPayload(msg, 3);
+    return *(nx_uint16_t *)(p + 1);
+  }
+
+
+  /*********************
+   * Creating a packet *
+   *********************/
+
+  command void DymoPacket.createRM(message_t * msg, dymo_msg_t msg_type, 
+                       const rt_info_t * origin, const rt_info_t * target){
+    nx_uint8_t * payload = call Packet.getPayload(msg, call Packet.maxPayloadLength());
+    nx_uint16_t * size_p;
+    *(payload++) = msg_type;
+    size_p = (nx_uint16_t *) payload;
+    payload += 2;
+    *(payload++) = DYMO_HOPLIMIT;
+    *(payload++) = 0;
+
+    create_block(payload, target);
+   
+    if(origin){
+      if(block_can_contain(payload, origin)){
+       block_add_info(payload, origin);
+       *size_p = block_size(payload);
+      } else {
+       *size_p = block_size(payload);
+       payload += *size_p;
+       create_block(payload, origin);
+       *size_p += block_size(payload);
+      }
+    } else {
+      *size_p = block_size(payload);
+    }
+
+    //size of msg header
+    //it is here to save a few instructions or a byte
+    *size_p += 5; 
+  }
+
+  command error_t DymoPacket.addInfo(message_t * msg, const rt_info_t * info){
+    nx_uint8_t * payload = call Packet.getPayload(msg, call Packet.maxPayloadLength());
+    nx_uint16_t * size_p = (nx_uint16_t *)(payload + 1);
+    nx_uint8_t * block = payload + 5;
+    uint8_t bsize;
+
+    while(block < payload + *size_p){
+      //We don't want to add something before the origin
+      if ( ((block > payload + 5) && block_can_contain(block, info))
+          || ((block == payload + 5) && (block_num_addr(block) > 1)) ) {
+
+       uint8_t isize = block_info_size(block);
+       if(*size_p + isize > call Packet.maxPayloadLength()){
+         return ESIZE;
+       } else {
+         bsize = block_size(block);
+         move_data(block + bsize, payload + *size_p - (block + bsize), isize);
+         block_add_info(block, info);
+         *size_p += isize;
+         return SUCCESS;
+       }
+
+      } else {
+       block += block_size(block);
+      }
+    }
+
+    create_block(block, info);
+    bsize = block_size(block);
+    if(*size_p +  bsize > call Packet.maxPayloadLength()){
+      return ESIZE;
+    } else {
+      *size_p += bsize;
+      return SUCCESS;
+    }
+  }
+
+
+  /***********************
+   * Processing a packet *
+   ***********************/
+
+  task void processMessage(){
+    nx_uint8_t * payload = call Packet.getPayload(currentMsg, call Packet.maxPayloadLength());
+    nx_uint8_t * end = payload + *(nx_uint16_t *)(payload+1);
+    nx_uint8_t * fw_payload = NULL;
+    nx_uint16_t * fw_size = NULL;
+    nx_uint8_t *fw_block, *info_p;
+    rt_info_t info;
+    uint8_t i,n,s;
+    bool first_block = 1;
+    proc_action_t action;
+
+    payload += 3;
+    *(payload++) -= 1; //decr hopL
+    *(payload++) += 1; //incr hopC
+    action = signal DymoPacket.hopsProcessed(currentMsg, *(payload-2), *(payload-1));
+    if(processedMsg){
+      if(action != ACTION_DISCARD_MSG){
+       fw_payload = call Packet.getPayload(processedMsg, call Packet.maxPayloadLength());
+       memcpy(fw_payload, payload - 5, 5);
+       fw_size = (nx_uint16_t *)(fw_payload + 1);
+       *fw_size = 5;
+       fw_payload += 5;
+      } else {
+       processedMsg = NULL;
+      }
+    }
+
+    while(payload < end){
+      fw_block = NULL;
+      n = block_num_addr(payload);
+
+      for(i=0;i<n;i++){
+       block_get_info(payload, i, &info, !first_block || i);
+       action = signal DymoPacket.infoProcessed(currentMsg, &info);
+
+       if(processedMsg){
+         switch(action){
+         case ACTION_KEEP:
+           if(!fw_block){
+             s = block_header_size(payload);
+             memcpy(fw_payload, payload, s);
+             fw_block = fw_payload;
+             *(fw_block+1) = 0;
+             fw_payload += s;
+           }
+           info_p = block_get_pointer(payload, i, &s);
+           memcpy(fw_payload, info_p, s);
+           fw_payload += s;
+           *(fw_block+1) += 1; //increments NumAddr
+           break;
+
+         case ACTION_DISCARD_MSG:
+           processedMsg = NULL;
+         default:
+         }
+       }//if
+
+      }//for
+      payload += block_size(payload);
+      first_block = 0;
+      if(fw_block)
+       *fw_size += block_size(fw_block);
+    }
+    
+    signal DymoPacket.messageProcessed(currentMsg);
+  }
+
+  command void DymoPacket.startProcessing(message_t * msg, message_t * newmsg){
+    currentMsg = msg;
+    processedMsg = newmsg;
+    post processMessage();
+  }
+
+
+
+  //TODO return block_size, it is always needed after a block creation
+  void create_block(nx_uint8_t * payload, const rt_info_t * info){
+    uint8_t semantics;
+
+    semantics = BLOCK_HEAD;
+    if(info->seqnum)
+      semantics |= BLOCK_SEQNUM;
+    if(info->has_hopcnt)
+      semantics |= BLOCK_HOPCNT;
+
+    *(payload++) = semantics;
+    *(payload++) = 1;
+    *(nx_addr_t *)payload = info->address;
+    payload += sizeof(addr_t);
+    if(info->seqnum){
+      *(nx_seqnum_t *)payload = info->seqnum;
+      payload += 2;
+    }
+    if(info->has_hopcnt){
+      *(payload++) = info->hopcnt;
+    }
+  }
+
+  void block_add_info(nx_uint8_t * block, const rt_info_t * info){
+    uint8_t semantics = *block;
+    nx_uint8_t * size_p = block + 1;
+    block += block_size(block);
+    *size_p += 1;
+    if(semantics & BLOCK_HEAD){
+      *block = info->address % 256;
+      block++;
+    } else {
+      *(nx_addr_t *)block = info->address;
+      block += sizeof(addr_t);
+    }
+
+    if(semantics & BLOCK_SEQNUM){
+      *(nx_seqnum_t *)block = info->seqnum;
+      block += sizeof(seqnum_t);
+    }
+
+    if(semantics & BLOCK_HOPCNT){
+      *block = info->hopcnt;
+    }
+  }
+
+  bool block_can_contain(nx_uint8_t * block, const rt_info_t * info){
+    if( (*block & BLOCK_SEQNUM) && !info->seqnum )
+      return 0;
+    if( !(*block & BLOCK_SEQNUM) && info->seqnum )
+      return 0;
+
+    if( (*block & BLOCK_HOPCNT) && !info->has_hopcnt )
+      return 0;
+    if( !(*block & BLOCK_HOPCNT) && info->has_hopcnt )
+      return 0;
+
+    if( (*block & BLOCK_HEAD) && (*(block + 2) != (info->address / 256)) )
+      return 0;
+
+    return 1;
+  }
+
+  uint8_t block_info_size(nx_uint8_t * block){
+    uint8_t result = 1;
+    if(!(*block & BLOCK_HEAD))
+      result++;
+    if(*block & BLOCK_SEQNUM)
+      result += 2;
+    if(*block & BLOCK_HOPCNT)
+      result++;
+    //TODO add max age
+    return result;
+  }
+
+  uint8_t block_header_size(nx_uint8_t * block){
+    if(*block & BLOCK_HEAD)
+      return 3;
+    else
+      return 2;
+  }
+
+  uint8_t block_num_addr(nx_uint8_t * block){
+    return *(block + 1);
+  }
+
+  uint8_t block_size(nx_uint8_t * block){
+    uint8_t result = 2;
+    if(*block & BLOCK_HEAD){
+      result++;
+    }
+    return result + block_num_addr(block) * block_info_size(block);
+  }
+
+  nx_uint8_t * block_get_pointer(nx_uint8_t * block, uint8_t pos, uint8_t * size){
+    if(size){
+      *size = block_info_size(block);
+      return block + block_header_size(block) + pos * (*size);
+    } else {
+      return block + block_header_size(block) + pos * block_info_size(block);
+    }
+  }
+
+  void block_get_info(nx_uint8_t * block, uint8_t pos, rt_info_t * info, bool update){
+    nx_uint8_t * semantics = block;
+    block = block_get_pointer(block, pos, NULL);
+    
+    if(*semantics & BLOCK_HEAD){
+      info->address = *(semantics + 2) * 256 + *block;
+      block++;
+    } else {
+      info->address = *(nx_addr_t *)block;
+      block += sizeof(addr_t);
+    }
+
+    if(*semantics & BLOCK_SEQNUM){
+      info->seqnum = *(nx_seqnum_t *)block;
+      block += sizeof(seqnum_t);
+    } else {
+      info->seqnum = 0;
+    }
+
+    if(*semantics & BLOCK_HOPCNT){
+      info->has_hopcnt = 1;
+      if(update)
+       *block += 1;
+      info->hopcnt = *block;
+      block++;
+    } else {
+      info->has_hopcnt = 0;
+    }
+  }
+
+  void move_data(nx_uint8_t * data, uint8_t amount, uint8_t offset){
+    nx_uint8_t * newdata = data + amount + offset;
+    data += amount;
+    for(; amount > 0; amount--)
+      *--newdata = *--data;
+  }
+
+
+  /**************
+   * PakerMaker *
+   **************/
+
+  command uint16_t PacketMaker.getSize(message_t * msg){
+    return call DymoPacket.getSize(msg);
+  }
+
+  command void PacketMaker.createRM(message_t * msg, dymo_msg_t msg_type, 
+                                  const rt_info_t * origin, const rt_info_t * target){
+    call DymoPacket.createRM(msg, msg_type, origin, target);
+  }
+
+  command error_t PacketMaker.addInfo(message_t * msg, const rt_info_t * info){
+    return call DymoPacket.addInfo(msg, info);
+  }
+}
diff --git a/tos/lib/net/tymo/dymo/DymoServiceC.nc b/tos/lib/net/tymo/dymo/DymoServiceC.nc
new file mode 100644 (file)
index 0000000..fe66338
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+#include "StorageVolumes.h"
+
+/**
+ * DymoServiceC - Implements the DYMO routing protocol
+ *
+ * @author Romain Thouvenin
+ */
+
+configuration DymoServiceC {
+  provides {
+    interface SplitControl;
+  }
+  uses {
+    interface Packet;
+    interface AMPacket;
+    interface AMSend;
+    interface Receive;
+    interface LinkMonitor;
+  }
+
+#ifdef DYMO_MONITORING
+  provides {
+    interface DymoMonitor;
+  }
+#endif
+}
+
+implementation {
+  components DymoTableC, DymoEngineM, DymoPacketM;
+  components new ConfigStorageC(VOLUME_DYMODATA);
+
+  SplitControl = DymoEngineM.SplitControl;
+  Packet       = DymoPacketM.Packet;
+  AMPacket     = DymoEngineM.AMPacket;
+  AMSend       = DymoEngineM.AMSend;
+  Receive      = DymoEngineM.Receive;
+  LinkMonitor  = DymoTableC.LinkMonitor;
+
+  DymoEngineM.DymoPacket   -> DymoPacketM;
+  DymoEngineM.RoutingTable -> DymoTableC;
+  DymoEngineM.DymoTable    -> DymoTableC;
+
+  DymoEngineM.Mount         -> ConfigStorageC;
+  DymoEngineM.ConfigStorage -> ConfigStorageC;
+
+#ifdef DYMO_MONITORING
+  components new TimerMilliC();
+
+  DymoMonitor = DymoEngineM.DymoMonitor;
+  DymoEngineM.Timer     -> TimerMilliC;
+#endif
+}
diff --git a/tos/lib/net/tymo/dymo/DymoTable.nc b/tos/lib/net/tymo/dymo/DymoTable.nc
new file mode 100644 (file)
index 0000000..c24e849
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+#include "routing_table.h"
+
+/**
+ * DymoTable - Interface to manipulate a dymo routing table
+ *
+ * @author Romain Thouvenin
+ */
+
+interface DymoTable {
+
+  /**
+   * Update the table with fresh information about a destination.
+   * @param route_info The routing information associated to the destination
+   * @param msg_type The type of message that provided this info
+   * @return SUCCESS if the route was added or updated<br/>
+   *         EINVAL  if route_info was inferior to existing route, 
+   *                 or msg_type = rerr and the route does not exist
+   *         FAIL    if the table was full and no existing route could be deleted<br/>
+   */
+  command error_t update(const rt_info_t * route_info, dymo_msg_t msg_type);
+
+  command bool isSuperior(const rt_info_t * route_info, dymo_msg_t msg_type);
+
+  /**
+   * Signal that a component asked for an unknown route, a RREQ should
+   * be generated.
+   * @param destination Target node of the needed route.
+   */
+  event void routeNeeded(addr_t destination);
+
+  event void brokenRouteNeeded(const rt_info_t * route_info);
+}
diff --git a/tos/lib/net/tymo/dymo/DymoTableC.nc b/tos/lib/net/tymo/dymo/DymoTableC.nc
new file mode 100644 (file)
index 0000000..ed18c6a
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+#include "dymo_table.h"
+
+/**
+ * DymoTableC - Provides a routing table with DYMO routing information.
+ *
+ * @author Romain Thouvenin
+ */
+
+configuration DymoTableC {
+  provides {
+    interface StdControl;
+    interface RoutingTable;
+    interface DymoTable;
+  }
+#ifdef DYMO_MONITORING
+  provides interface RoutingTableInfo;
+#endif
+
+  uses interface LinkMonitor;
+}
+
+implementation {
+  components new DymoTableM(MAX_TABLE_SIZE); 
+  components new TimerMilliC() as BaseTimer;
+  components new VirtualizeTimerC(TMilli, MAX_TABLE_SIZE * NB_ROUTE_TIMERS) as Timers;
+  components TinySchedulerC;
+
+  StdControl   = DymoTableM.StdControl;
+  RoutingTable = DymoTableM.RoutingTable;
+  DymoTable    = DymoTableM.DymoTable;
+  LinkMonitor  = DymoTableM.LinkMonitor;
+
+  DymoTableM.Timer -> Timers;
+
+  Timers.TimerFrom -> BaseTimer.Timer;
+
+#ifdef DYMO_MONITORING
+  RoutingTableInfo = DymoTableM.RoutingTableInfo;
+#endif
+}
diff --git a/tos/lib/net/tymo/dymo/DymoTableM.nc b/tos/lib/net/tymo/dymo/DymoTableM.nc
new file mode 100644 (file)
index 0000000..d0e00dd
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+#include "dymo_table.h"
+
+/**
+ * DymoTableM - Implements a routing table with DYMO routing information.
+ * @param maxsize maximum number of entries in the table, cannot be higher than 51
+ *
+ * @author Romain Thouvenin
+ */
+
+generic module DymoTableM(uint8_t maxsize) {
+  provides {
+    interface StdControl;
+    interface RoutingTable;
+    interface DymoTable;
+  }
+  uses {
+    interface Timer<TMilli>[uint8_t id];
+    interface LinkMonitor;
+  }
+#ifdef DYMO_MONITORING
+  provides interface RoutingTableInfo;
+#endif
+}
+
+implementation {
+
+  rt_entry_t table[maxsize];
+  rt_info_t buf_info;
+  uint8_t size; 
+  uint8_t num_entries;
+  uint8_t replace;
+
+  /* declared at the end */
+  void replace_info(uint8_t entry_id, const rt_info_t * route_info);
+  int8_t get_route(addr_t address);
+  void delete_route(uint8_t entry_id, reason_t r);
+  bool is_superior(const rt_info_t * info1, const rt_entry_t * entry, dymo_msg_t msg_type);
+  void set_timer(uint8_t entry_id, rt_timer_t timer_id);
+  void cancel_timer(uint8_t entry_id, rt_timer_t timer);
+  void cancel_timers(uint8_t entry_id);
+
+  command error_t StdControl.start(){
+    num_entries = 0;
+    size = 0;
+    replace = 0;
+    return SUCCESS;
+  }
+
+  command error_t StdControl.stop(){
+    uint8_t i;
+    for(i=0; i<num_entries; i++){
+      if( !(table[i].flags & FLAG_DELETED) ){
+       cancel_timers(i);
+      }
+    }
+    return SUCCESS;
+  }
+
+  command error_t RoutingTable.getForwardingRoute(addr_t address, rt_info_t * info){
+    int8_t i = get_route(address);
+    dbg("dt", "DT: Someone wants a forwarding route for %u.\n", address);
+    if(i == -1){
+      dbg("dt", "DT: But I don't have it. => brokenRouteNeeded\n");
+      buf_info.address = address;
+      buf_info.seqnum = 0;
+      buf_info.has_hopcnt = 0;
+      signal DymoTable.brokenRouteNeeded(&buf_info);
+      return FAIL;
+    }
+
+    //The caller may want to know what is in the table even if it is broken
+    if(info && !(table[i].flags & FLAG_DELETED)){
+      *info = table[i].info;
+    }
+
+    if(table[i].flags & (FLAG_BROKEN | FLAG_DELETED)){
+      dbg("dt", "DT: But it is deleted. => brokenRouteNeeded\n");
+      signal DymoTable.brokenRouteNeeded(&table[i].info); //TODO not if not used recently (for other signals too)
+      return FAIL;
+    }
+
+    cancel_timer(i, ROUTE_NEW);
+    table[i].flags &= ~FLAG_NEW;
+    cancel_timer(i, ROUTE_DELETE);
+    set_timer(i, ROUTE_USED);
+    table[i].flags |= FLAG_USED;
+    dbg("dt", "DT: Here it is: %u.\n", table[i].info.nexthop);
+    return SUCCESS;
+  }
+
+  command error_t RoutingTable.getRoute(addr_t address, rt_info_t * info){
+    int i = get_route(address);
+    dbg("dt", "DT: Someone wants a sending route for %u.\n", address);
+    if(i == -1){
+      dbg("dt", "DT: But I don't have it. => routeNeeded\n");
+      signal DymoTable.routeNeeded(address);
+      return EBUSY;
+    }
+
+    //The caller may want to know what is in the table even if it is broken
+    if(info){
+      *info = table[i].info;
+    }
+
+    if(table[i].flags & (FLAG_DELETED | FLAG_BROKEN)){
+      dbg("dt", "DT: But it is deleted or broken. => routeNeeded\n");
+      signal DymoTable.routeNeeded(address);
+      return EBUSY;
+    }
+    
+    //We assume the route is going to be used
+    cancel_timer(i, ROUTE_NEW);
+    table[i].flags &= ~FLAG_NEW;
+    cancel_timer(i, ROUTE_DELETE);
+    set_timer(i, ROUTE_USED);
+    table[i].flags |= FLAG_USED;
+    dbg("dt", "DT: Here it is: %u-%u-%hhu.\n", table[i].info.nexthop, table[i].info.seqnum, table[i].info.hopcnt);
+    return SUCCESS;
+  }
+
+  command error_t DymoTable.update(const rt_info_t * route_info, dymo_msg_t msg_type){
+    int8_t i = get_route(route_info->address);
+
+    if(msg_type == DYMO_RERR){
+
+      if(i != -1){
+       if( (table[i].info.nexthop == route_info->nexthop) 
+           && ((table[i].info.seqnum == 0)
+               || (route_info->seqnum == 0)
+               || (route_info->seqnum >= table[i].info.seqnum)) ){
+         table[i].flags |= FLAG_BROKEN;
+         dbg("dt", "DT: Route for %u evicted because of a RERR.\n", route_info->address);
+         signal RoutingTable.evicted(&table[i].info, REASON_UNREACHABLE);
+         return SUCCESS;
+       } else {
+         return EINVAL;
+       }
+      } else {
+       return EINVAL;
+      }
+
+    } else {
+
+      if(i == -1){
+       
+       if(num_entries < maxsize){ //We have room to add a new route
+         
+         replace_info(num_entries, route_info);
+         num_entries++;
+         size++;
+         dbg("dt", "DT: Updated route for %u in entry %hhu.\n", route_info->address, num_entries-1); //TODO debug below too
+         return SUCCESS;
+
+       } else { //We have to find a route to replace
+         //TODO possible optimization : caching the last deleted and broken route
+         int8_t j = -1; //will be set to a non-new route if found
+         
+         //We look for a deleted route
+         for(i=0; i<num_entries; i++){
+           if(table[i].flags & FLAG_DELETED){
+             replace_info(i, route_info);
+             return SUCCESS;
+           }
+         }
+
+         //the table is full, we try to replace an existing route
+         for(i=0; i<num_entries; i++){
+           if(table[i].flags & FLAG_BROKEN){
+             replace_info(i, route_info);
+             return SUCCESS;
+           } else if( !(table[i].flags & FLAG_NEW) ){
+             j = i;
+           }
+         }
+
+         //no broken route found, we a take a non-new route
+         //TODO rather take a non-used route
+         if(j != -1){
+           delete_route(j, REASON_FULL);
+           replace_info(j, route_info);
+           return SUCCESS;
+         }
+
+         /* No room found. We delete a random route */
+         delete_route(replace, REASON_FULL);
+         replace_info(replace++, route_info);
+         if (replace == maxsize)
+           replace = 0;
+         return SUCCESS;
+
+       }
+
+      } else { //if(i == -1)
+
+       if(is_superior(route_info, table + i, msg_type)){
+         replace_info(i, route_info);
+         return SUCCESS;
+       } else {
+         return EINVAL;
+       }
+
+      }
+
+    }
+  }
+
+  command bool DymoTable.isSuperior(const rt_info_t * info, dymo_msg_t t){
+    int8_t i = get_route(info->address);
+    return ((i == -1) || is_superior(info, table + i, t));
+  }
+
+  event void Timer.fired[uint8_t timer_id](){
+    uint8_t e = timer_id / NB_ROUTE_TIMERS;
+    switch(timer_id % NB_ROUTE_TIMERS){
+    case ROUTE_AGE_MIN:
+      table[e].flags &= ~FLAG_NEW;
+      break;
+    case ROUTE_AGE_MAX:
+      dbg("dt", "DT: Route for %u is really old, I delete it.\n", table[e].info.address);
+      delete_route(e, REASON_OLD);
+      break;
+    case ROUTE_NEW:
+      table[e].flags &= ~FLAG_NEW;
+      set_timer(e, ROUTE_DELETE);
+      break;
+    case ROUTE_USED:
+      table[e].flags &= ~FLAG_USED;
+      set_timer(e, ROUTE_DELETE);
+      break;
+    case ROUTE_DELETE:
+      dbg("dt", "DT: Route for %u is unused, I delete it.\n", table[e].info.address);
+      delete_route(e, REASON_OLD);
+      break;
+    }
+  }
+
+  event void LinkMonitor.brokenLink(addr_t neighbor){
+    int8_t i = get_route(neighbor);
+    if (i != -1) {
+      table[i].flags |= FLAG_BROKEN;
+      signal RoutingTable.evicted(&table[i].info, REASON_UNREACHABLE);
+      if (table[i].flags & (FLAG_NEW | FLAG_USED)) {
+       cancel_timer(i, ROUTE_NEW);
+       cancel_timer(i, ROUTE_USED);
+       set_timer(i, ROUTE_DELETE);
+      }
+    }
+  }
+
+  void replace_info(uint8_t pos, const rt_info_t * route_info){
+    table[pos].info = *route_info;
+    table[pos].flags = FLAG_NEW;
+    cancel_timers(pos);
+    set_timer(pos, ROUTE_AGE_MIN);
+    set_timer(pos, ROUTE_AGE_MAX);
+    set_timer(pos, ROUTE_NEW);
+  }
+
+  /* Return the index of the route toward address if it exists, -1 otherwise */
+  int8_t get_route(addr_t address){
+    uint8_t i = 0;
+    for(i=0;i<num_entries;i++){
+      if(table[i].info.address == address){
+       return i;
+      }
+    }
+    return -1;
+  }
+
+  /* Remove a route from the table */
+  void delete_route(uint8_t entry_id, reason_t r){
+    table[entry_id].flags = FLAG_DELETED;
+    cancel_timers(entry_id);
+    dbg("dt", "DT: I'm deleting route number %hhu (for node %u).\n", entry_id, table[entry_id].info.address);
+    signal RoutingTable.evicted(&table[entry_id].info, r);
+  }
+
+  /* compare two pieces of routing information
+   * returns true if info1 > entry->info */
+  bool is_superior(const rt_info_t * info1, const rt_entry_t * entry, dymo_msg_t msg_type){
+    //a copy of the superior test in the specifications
+    //with nil values discarded
+    return ((info1->seqnum > entry->info.seqnum)
+           || ((info1->seqnum == entry->info.seqnum)
+               && info1->has_hopcnt
+               && entry->info.has_hopcnt
+               && ((info1->hopcnt < entry->info.has_hopcnt)
+                   || ((info1->hopcnt == entry->info.has_hopcnt)
+                       && ((msg_type == DYMO_RREP)
+                           || (entry->flags & FLAG_BROKEN))))));
+  }
+
+  /* Start a timer for a route */
+  void set_timer(uint8_t entry_id, rt_timer_t timer_id){
+    call Timer.startOneShot[entry_id * NB_ROUTE_TIMERS + timer_id](timer_values[timer_id]);
+  }
+
+  /* Cancel a timer for a route */
+  void cancel_timer(uint8_t entry_id, rt_timer_t timer_id){
+    call Timer.stop[entry_id * NB_ROUTE_TIMERS + timer_id]();
+  }
+
+  /* Cancel all the timers of an entry */
+  void cancel_timers(uint8_t entry_id){
+    uint8_t i = entry_id * NB_ROUTE_TIMERS;
+    for(i=0; i<NB_ROUTE_TIMERS; i++){
+      call Timer.stop[i]();
+    }
+  }
+
+#ifdef DYMO_MONITORING
+
+  command uint8_t RoutingTableInfo.size(){
+    return size;
+  }
+
+  command uint8_t RoutingTableInfo.maxSize(){
+    return maxsize;
+  }
+
+  command uint8_t  RoutingTableInfo.getTableContent(rt_info_t * buf){
+    uint8_t i=0, j=0;
+    for(i=0; i<num_entries; i++){
+      if( !(table[i].flags & (FLAG_DELETED | FLAG_BROKEN)) ){
+       buf[j++] = table[i].info;
+      }
+    }
+    return j;
+  }
+
+  command uint8_t RoutingTableInfo.getLinks(rt_link_t * buf){
+    uint8_t i=0, j=0;
+    for(i=0; i<num_entries; i++){
+      if( !(table[i].flags & (FLAG_DELETED | FLAG_BROKEN)) ){
+       buf[j].target = table[i].info.address;
+       buf[j].nexthop = table[i].info.nexthop;
+       j++;
+      }
+    }
+    return j;
+  }
+
+#endif
+
+ default event void RoutingTable.evicted(const rt_info_t * route_info, reason_t r){ }
+
+}
+
diff --git a/tos/lib/net/tymo/dymo/NetControlM.nc b/tos/lib/net/tymo/dymo/NetControlM.nc
new file mode 100644 (file)
index 0000000..a50b859
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+/**
+ * NetControlM - Manages the control of all components involved in the
+ * DymoNetwork component.
+ *
+ * @author Romain Thouvenin
+ */
+
+// TODO generalize to a multiControl
+module NetControlM {
+  provides interface SplitControl;
+  uses {
+    interface SplitControl as AMControl;
+    interface StdControl   as TableControl;
+    interface SplitControl as EngineControl;
+  }
+}
+
+implementation {
+  uint8_t started;
+
+  command error_t SplitControl.start(){
+    error_t e = call TableControl.start();
+    started = 1;
+
+    if(e == SUCCESS){
+
+      e = call AMControl.start();
+      if(e == SUCCESS)
+       return call EngineControl.start();
+      else
+       return e;
+      
+    } else {
+      return e;
+    }
+  }
+
+  event void AMControl.startDone(error_t e){
+    if (e == SUCCESS) {
+      if (started++ == 2)
+       signal SplitControl.startDone(e);
+    } else if (started) {
+      started = 0;
+      signal SplitControl.startDone(e);
+    }
+  }
+
+  event void EngineControl.startDone(error_t e) {
+    if (e == SUCCESS) {
+      if (started++ == 2)
+       signal SplitControl.startDone(e);
+    } else if (started) {
+      started = 0;
+      signal SplitControl.startDone(e);
+    }
+  }
+
+  command error_t SplitControl.stop(){
+    if(call AMControl.stop() == SUCCESS)
+      return call TableControl.stop();
+    else
+      return FAIL;
+  }
+
+  event void AMControl.stopDone(error_t e){
+    signal SplitControl.stopDone(e);
+  }
+
+  event void EngineControl.stopDone(error_t e){ }
+
+}
diff --git a/tos/lib/net/tymo/dymo/PacketMaker.nc b/tos/lib/net/tymo/dymo/PacketMaker.nc
new file mode 100644 (file)
index 0000000..9444b9c
--- /dev/null
@@ -0,0 +1,10 @@
+interface PacketMaker {
+
+  command uint16_t getSize(message_t * msg);
+
+  command void createRM(message_t * msg, dymo_msg_t msg_type, 
+                       const rt_info_t * origin, const rt_info_t * target);
+
+  command error_t addInfo(message_t * msg, const rt_info_t * info);
+
+}
diff --git a/tos/lib/net/tymo/dymo/dymo_packet.h b/tos/lib/net/tymo/dymo/dymo_packet.h
new file mode 100644 (file)
index 0000000..646ac86
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+#include "routing.h"
+
+typedef enum block_semantics {
+  BLOCK_HEAD = 0x1,
+  BLOCK_SEQNUM = 0x2,
+  BLOCK_HOPCNT = 0x4
+} block_semantics_t;
diff --git a/tos/lib/net/tymo/dymo/dymo_table.h b/tos/lib/net/tymo/dymo/dymo_table.h
new file mode 100644 (file)
index 0000000..2b2d931
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+#ifndef _DYMO_TABLE_H_
+#define _DYMO_TABLE_H_
+
+#include "routing_table.h"
+
+/**
+ * Types associated to a dymo routing table.
+ * @author Romain Thouvenin
+ */
+
+typedef struct rt_entry {
+  rt_info_t info;
+  uint8_t flags;
+} rt_entry_t;
+
+typedef enum {
+  FLAG_BROKEN = 0x01,
+  FLAG_NEW = 0x02,
+  FLAG_USED = 0x04,
+  FLAG_DELETED = 0x08,
+} rt_flag_t;
+
+typedef enum { //TODO optimize the number of timers
+  ROUTE_AGE_MIN = 0,
+  ROUTE_AGE_MAX,
+  ROUTE_NEW,
+  ROUTE_USED,
+  ROUTE_DELETE,
+  NB_ROUTE_TIMERS
+} rt_timer_t;
+
+uint32_t timer_values[NB_ROUTE_TIMERS] = {
+  1000,                //ROUTE_AGE_MIN
+  DYMO_ROUTE_AGE_MAX,  //ROUTE_AGE_MAX
+  DYMO_ROUTE_TIMEOUT,   //ROUTE_NEW
+  DYMO_ROUTE_TIMEOUT,   //ROUTE_USED
+  DYMO_ROUTE_TIMEOUT * 2   //ROUTE_DELETE
+};
+
+
+#endif
diff --git a/tos/lib/net/tymo/dymo/sim/DymoEngineM.nc b/tos/lib/net/tymo/dymo/sim/DymoEngineM.nc
new file mode 100644 (file)
index 0000000..3b070f6
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+#include "routing.h"
+#include "routing_table.h"
+
+/**
+ * DymoEngineM - Implements the algorithms to generate and process
+ * DYMO messages. This the simultor version, without persistent
+ * storage of the seqnum.
+ *
+ * @author Romain Thouvenin
+ */
+
+module DymoEngineM {
+  provides {
+    interface SplitControl;
+  }
+  uses {
+    interface DymoTable;
+    interface RoutingTable;
+    interface DymoPacket;
+    interface AMSend;
+    interface AMPacket;
+    interface Receive;
+  }
+
+#ifdef DYMO_MONITORING
+  provides interface DymoMonitor;
+  uses {
+    interface Timer<TMilli>;
+  }
+#endif
+}
+
+implementation {
+  message_t * avail_msg; //to be returned by receive
+  message_t buf_avail;   //first avail_msg
+  message_t buf_packet;
+  rt_info_t me;
+  rt_info_t buf_info;
+  addr_t ignoreNeeded;
+  bool busySend;
+
+  /* for processing */
+  bool busyProcess, busyIssue;
+  uint8_t cur_hopcnt;
+  uint8_t cur_info_pos;
+  rt_info_t buf_target;
+  addr_t fw_address; //set to 0 if the message must not be forwarded
+  message_t fw_msg;
+  bool sendRREP;
+
+#ifdef DYMO_MONITORING
+  uint32_t rreq_time;
+#endif
+
+
+  task void startDoneTask() {
+    signal SplitControl.startDone(SUCCESS);
+  }
+
+  command error_t SplitControl.start(){
+    me.address = call AMPacket.address();
+    me.seqnum = 1;
+    me.has_hopcnt = 1;
+    me.hopcnt = 0;
+
+    avail_msg = &buf_avail;
+    ignoreNeeded = 0;
+    sendRREP = FALSE;
+    busyProcess = FALSE;
+    busyIssue = FALSE;
+    busySend = FALSE;
+    buf_target.address = 0;
+    
+#ifdef DYMO_MONITORING
+    rreq_time = 0;
+#endif
+
+    post startDoneTask();
+    return SUCCESS;
+  }
+
+  void incr_seqnum(){
+    if(me.seqnum == 65535)
+      me.seqnum = 256;
+    else
+      me.seqnum++;
+  }
+
+  /* Send a RREQ for buf_info */
+  task void issueRREQ(){
+    atomic {
+      if(busySend)
+       post issueRREQ();
+      else {
+       busySend = TRUE;
+       incr_seqnum();
+       call DymoPacket.createRM(&buf_packet, DYMO_RREQ, &me, &buf_info);
+       call AMSend.send(AM_BROADCAST_ADDR, &buf_packet, call DymoPacket.getSize(&buf_packet));
+      }
+    }
+  }
+
+  /* Send a RREP to buf_info */
+  task void issueRREP(){
+    atomic {
+      if(busySend)
+       post issueRREP();
+      else {
+       busySend = TRUE;
+       call DymoPacket.createRM(&buf_packet, DYMO_RREP, &me, &buf_info);
+       if(buf_target.address)
+         call DymoPacket.addInfo(&buf_packet, &buf_target);
+       call AMSend.send(buf_info.nexthop, &buf_packet, call DymoPacket.getSize(&buf_packet));
+       buf_target.address = 0;
+      }
+    }
+  }
+
+  /* Send a RERR with buf_info as unreachable */
+  task void issueRERR(){
+    atomic {
+      if(busySend)
+       post issueRERR();
+      else {
+       busySend = TRUE;
+       call DymoPacket.createRM(&buf_packet, DYMO_RERR, NULL, &buf_info);
+       call AMSend.send(AM_BROADCAST_ADDR, &buf_packet, call DymoPacket.getSize(&buf_packet));
+      }
+    }
+  }
+
+  /* Send current fw_msg to fw_address */
+  task void forward(){
+    atomic {
+      if(busySend)
+       post forward();
+      else {
+       busySend = TRUE;
+       call AMSend.send(fw_address, &fw_msg, call DymoPacket.getSize(&fw_msg));
+      }
+    }
+  }
+
+  event message_t* Receive.receive(message_t* msg, void* payload, uint8_t len){
+#ifdef DYMO_MONITORING
+    signal DymoMonitor.msgReceived(msg);
+#endif
+    dbg("de", "DE: Message (type %hhu) received.\n", call DymoPacket.getType(msg));
+    atomic {
+      if(busyProcess){
+       dbg("de", "DE: I'm busy, I can't handle this message, sorry.\n");
+       return msg; //we discard msg if a message is already being processed
+      } else {
+       busyProcess = TRUE;
+      }
+    }
+    cur_info_pos = 0;
+    fw_address = AM_BROADCAST_ADDR;
+    call DymoPacket.startProcessing(msg, &fw_msg);
+    return avail_msg;
+  }
+
+  event proc_action_t DymoPacket.hopsProcessed(message_t * msg, uint8_t hop_limit, uint8_t hop_count){
+    cur_hopcnt = hop_count; //TODO use this
+    if(hop_limit == 0){
+      fw_address = 0;
+      dbg("de", "DE: This message has reached its HL (%hhu hops) => discard.\n", hop_count);
+      return ACTION_DISCARD_MSG;
+    } else {
+      return ACTION_KEEP;
+    }
+  }
+
+  proc_action_t process_rm_info(message_t * msg, rt_info_t * info){
+    cur_info_pos++;
+    if(cur_info_pos == 1){ //target
+
+      if(info->address == me.address){
+
+       if(call DymoPacket.getType(msg) == DYMO_RREQ){
+         dbg("de", "DE: This RREQ is for me => RREP.\n");
+         if(info->seqnum < me.seqnum)
+           incr_seqnum();
+         dbg("de", "DE: My seqnum for the RREP: %u.\n", me.seqnum);
+         sendRREP = TRUE; //to send a RREP when we receive the next event (= originator info)
+       } else {
+         dbg("de", "DE: This RREP is for me, cool!\n");
+       }
+       fw_address = 0;
+       return ACTION_DISCARD_MSG;
+
+      } else { //not for me
+
+       info->nexthop = call AMPacket.source(msg);
+       if(call DymoPacket.getType(msg) == DYMO_RREQ){
+
+#if DYMO_INTER_RREP
+         //if we know a route to the target, we send a intermediate RREP and don't forward the message
+         ignoreNeeded = info->address;
+         if (call RoutingTable.getRoute(info->address, &buf_info) == SUCCESS) {
+#if DYMO_FORCE_INTER_RREP
+           if( !info->seqnum || !(call DymoTable.isSuperior(info, DYMO_RREQ)) ){
+#else
+           if( info->seqnum && !(call DymoTable.isSuperior(info, DYMO_RREQ)) ){
+#endif
+             dbg("de", "DE: This RREQ is for %u, but I know the route => RREP.\n", info->address);
+             dbg("de", "DE: My seqnum for the RREP: %u.\n", me.seqnum);
+             buf_target = buf_info;
+             sendRREP = TRUE;
+             fw_address = 0;
+             return ACTION_DISCARD_MSG;
+           }
+         }
+#endif
+         return ACTION_KEEP;
+
+       } else { //RREP
+
+         ignoreNeeded = info->address;
+         dbg("de", "DE: This RREP is for %u.\n", info->address);
+         if(call RoutingTable.getForwardingRoute(info->address, &buf_info) == SUCCESS){
+           fw_address = buf_info.nexthop;
+           return ACTION_KEEP;
+         } else {
+           fw_address = 0;
+           return ACTION_DISCARD_MSG;
+         }
+
+       }//end RREP
+
+      }//end not for me
+
+    } else if((call DymoPacket.getType(msg) == DYMO_RREQ) //end if(info==target)
+             && (cur_info_pos == 2)
+             && (info->address == me.address)){
+
+      fw_address = 0;
+      sendRREP = FALSE;
+      return ACTION_DISCARD_MSG;
+
+    } else {
+
+      info->nexthop = call AMPacket.source(msg);
+      if(call DymoTable.update(info, call DymoPacket.getType(msg)) == EINVAL){
+
+       if(cur_info_pos == 2){ //origin
+         dbg("de", "DE: I am discarding a msg with a bad origin (%u-%u-%hhu)\n", info->address, info->seqnum, info->hopcnt);
+         fw_address = 0;
+         return ACTION_DISCARD_MSG;
+       } else {               //Additional info
+         dbg("de", "DE: I am discarding a bad piece of info (%u-%u-%hhu)\n", info->address, info->seqnum, info->hopcnt);
+         return ACTION_DISCARD;
+       }
+
+      } else {
+
+       if((cur_info_pos == 2) && sendRREP){
+         buf_info = *info;
+         atomic {
+           if(!busyIssue){
+             busyIssue = 1;
+             post issueRREP();
+           }
+         }
+         sendRREP = 0;
+       }
+
+#ifdef DYMO_MONITORING 
+       if( rreq_time    //TODO probably misses a test
+           && (cur_info_pos == 2)
+           && (call DymoPacket.getType(msg) == DYMO_RREP) ) {
+         rreq_time = (call Timer.getNow()) - rreq_time;
+         signal DymoMonitor.routeDiscovered(rreq_time, info->address);
+         rreq_time = 0;
+       }
+#endif
+       return ACTION_KEEP;
+
+      }
+
+    } //end info!=target
+  }//end event
+
+  proc_action_t process_err_info(message_t * msg, rt_info_t * info){
+    info->nexthop = call AMPacket.source(msg);
+    if(call DymoTable.update(info, call DymoPacket.getType(msg)) == EINVAL){
+      return ACTION_DISCARD;       
+    } else {
+      cur_info_pos++; //we only count kept pieces of info
+      return ACTION_KEEP;
+    }
+  }
+
+  event proc_action_t DymoPacket.infoProcessed(message_t * msg, rt_info_t * info){
+    if(call DymoPacket.getType(msg) == DYMO_RERR)
+      return process_err_info(msg, info);
+    else
+      return process_rm_info(msg, info);
+  }
+
+  event void DymoPacket.messageProcessed(message_t * msg){
+    avail_msg = msg;
+    if( (call DymoPacket.getType(msg) == DYMO_RERR) && cur_info_pos ){
+
+      post forward();
+
+    } else if( (call DymoPacket.getType(msg) != DYMO_RERR) && fw_address ){
+
+#if DYMO_APPEND_INFO
+      call DymoPacket.addInfo(&fw_msg, me);
+#endif
+      dbg("de", "DE: I'll forward this RM.\n");
+      post forward();
+
+    } else {
+
+      atomic {
+       busyProcess = 0;
+      }
+      dbg("de", "DE: I'm not busy anymore.\n");
+
+    }
+    dbg("de", "DE: Message (type %hhu) successfully processed.\n", call DymoPacket.getType(msg));
+  }
+
+  event void DymoTable.routeNeeded(addr_t destination){
+    if(ignoreNeeded == destination){
+      ignoreNeeded = 0;
+    } else {
+      buf_info.address = destination;
+      buf_info.seqnum = 0;
+      buf_info.has_hopcnt = FALSE;
+      atomic {
+       if(!busyIssue){
+         busyIssue = TRUE;
+#ifdef DYMO_MONITORING
+         rreq_time = call Timer.getNow();
+#endif
+         post issueRREQ();
+       }
+      }
+    }
+  }
+  
+  event void DymoTable.brokenRouteNeeded(const rt_info_t * route_info){
+    buf_info = *route_info;
+    buf_info.has_hopcnt = FALSE;
+    atomic {
+      if(!busyIssue){
+       busyIssue = TRUE;
+       post issueRERR();
+      }
+    }
+  }
+
+  event void RoutingTable.evicted(const rt_info_t * route_info, reason_t r){
+    if(r == REASON_UNREACHABLE){
+      buf_info = *route_info;
+      buf_info.has_hopcnt = FALSE;
+      atomic {
+       if(!busyIssue){
+         busyIssue = TRUE;
+         post issueRERR();
+       }
+      }
+    }
+  }
+
+  event void AMSend.sendDone(message_t *msg, error_t error){
+    atomic {
+      busySend = FALSE;
+    }
+    if(msg == &fw_msg){
+      atomic{
+       busyProcess = FALSE;
+      }
+    } else if(msg == &buf_packet) {
+      atomic {
+       busyIssue = FALSE;
+      }
+    }
+
+    if(error == SUCCESS){
+      if(msg == &fw_msg)
+       dbg("de", "DE: Message (type %hhu) forwarded.\n", call DymoPacket.getType(msg));
+      else
+       dbg("de", "DE: Message (type %hhu) sent.\n", call DymoPacket.getType(msg));
+    } else
+      dbg("de", "DE: Failed to send message (type %hhu).\n", call DymoPacket.getType(msg));
+
+#ifdef DYMO_MONITORING
+    if(error == SUCCESS)
+      signal DymoMonitor.msgSent(msg);
+#endif
+  }
+
+  command error_t SplitControl.stop(){ }
+
+#ifdef DYMO_MONITORING
+
+  event void Timer.fired(){}
+
+ default event void DymoMonitor.msgReceived(message_t * msg){}
+
+ default event void DymoMonitor.msgSent(message_t * msg){}
+
+ default event void DymoMonitor.routeDiscovered(uint32_t delay, addr_t target){}
+
+#endif
+}
+
diff --git a/tos/lib/net/tymo/dymo/sim/DymoServiceC.nc b/tos/lib/net/tymo/dymo/sim/DymoServiceC.nc
new file mode 100644 (file)
index 0000000..5817075
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+/**
+ * DymoServiceC - Implements the DYMO routing protocol This is the
+ * simulator version, without persistent storage of the sequence
+ * number.
+ *
+ *  @author Romain Thouvenin
+ */
+
+configuration DymoServiceC {
+  provides {
+    interface SplitControl;
+  }
+  uses {
+    interface Packet;
+    interface AMPacket;
+    interface AMSend;
+    interface Receive;
+    interface LinkMonitor;
+  }
+
+#ifdef DYMO_MONITORING
+  provides {
+    interface DymoMonitor;
+  }
+#endif
+}
+
+implementation {
+  components DymoTableC, DymoEngineM, DymoPacketM;
+
+  SplitControl = DymoEngineM.SplitControl;
+  Packet       = DymoPacketM.Packet;
+  AMPacket     = DymoEngineM.AMPacket;
+  AMSend       = DymoEngineM.AMSend;
+  Receive      = DymoEngineM.Receive;
+  LinkMonitor  = DymoTableC.LinkMonitor;
+
+  DymoEngineM.DymoPacket   -> DymoPacketM;
+  DymoEngineM.RoutingTable -> DymoTableC;
+  DymoEngineM.DymoTable    -> DymoTableC;
+
+#ifdef DYMO_MONITORING
+  components new TimerMilliC();
+
+  DymoMonitor = DymoEngineM.DymoMonitor;
+  DymoEngineM.Timer     -> TimerMilliC;
+#endif
+}
diff --git a/tos/lib/net/tymo/mh/MHControl.nc b/tos/lib/net/tymo/mh/MHControl.nc
new file mode 100644 (file)
index 0000000..a0cff2f
--- /dev/null
@@ -0,0 +1,7 @@
+interface MHControl {
+
+  event void msgReceived(message_t * msg);
+
+  event void sendFailed(message_t * msg, uint8_t why);
+
+}
diff --git a/tos/lib/net/tymo/mh/MHEngineM.nc b/tos/lib/net/tymo/mh/MHEngineM.nc
new file mode 100644 (file)
index 0000000..d8efe3b
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+#include "routing.h"
+
+/**
+ * MHEngineM - Implements a simple transport protocol, which is
+ * nothing more than AM on top of the existing AM stack.
+ *
+ * @author Romain Thouvenin
+ */
+module MHEngineM {
+  provides interface RouteSelect;
+  uses {
+    interface AMPacket as MHPacket;
+    interface AMPacket;
+    interface RoutingTable;
+  }
+}
+
+implementation {
+
+  rt_info_t info;
+
+  command fw_action_t RouteSelect.selectRoute(message_t * msg, addr_t * destination, uint8_t * am_type){
+    dbg("mhe", "MHE: Somebody wants a route, let's see...\n");
+    if( call MHPacket.isForMe(msg) 
+       || (destination && (*destination == call MHPacket.address())) ){
+      
+      *am_type = call MHPacket.type(msg);
+      return FW_RECEIVE;
+
+    } else {
+      
+      error_t e;
+      if(destination)
+       e = call RoutingTable.getRoute(*destination, &info);
+      else
+       e = call RoutingTable.getForwardingRoute(call MHPacket.destination(msg), &info);
+
+      if(e == SUCCESS){
+
+       dbg("mhe", "MHE: I've selected a route to %u through %u.\n", info.address, info.nexthop);
+       call AMPacket.setDestination(msg, info.nexthop);
+
+       if(destination){
+         call MHPacket.setType(msg, *am_type);
+         call MHPacket.setDestination(msg, *destination);
+         call MHPacket.setSource(msg, call MHPacket.address());
+       } else {
+         *am_type = call MHPacket.type(msg);
+       }
+       return FW_SEND;
+
+      } else if(e == EBUSY){
+       dbg("mhe", "MHE: No route is available for now.\n");
+       return FW_WAIT;
+      } else {
+       dbg("mhe", "MHE: I'm discarding the message.\n");
+       return FW_DISCARD;
+      }
+
+    }
+  }
+
+  event void RoutingTable.evicted(const rt_info_t * rt_info, reason_t r){}
+
+}
diff --git a/tos/lib/net/tymo/mh/MHPacketM.nc b/tos/lib/net/tymo/mh/MHPacketM.nc
new file mode 100644 (file)
index 0000000..470fb6d
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+#include "mhpacket.h"
+
+#define HEADER  ((mhpacket_header_t *)(call SubPacket.getPayload(amsg, call SubPacket.maxPayloadLength())))
+
+/**
+ * MHPacketM - Implements ActiveMessage on top of ActiveMessage,
+ * to transport data in a multihop network.
+ *
+ * @author Romain Thouvenin
+ */
+
+module MHPacketM {
+  provides {
+    interface Packet;
+    interface AMPacket as MHPacket;
+  }
+  uses {
+    interface Packet as SubPacket;
+    interface AMPacket;
+  }
+}
+
+implementation {
+  
+  /**********
+   * Packet *
+   **********/
+
+  command void Packet.clear(message_t *msg){
+    call SubPacket.clear(msg);
+  }
+
+  command void * Packet.getPayload(message_t *msg, uint8_t len){
+    nx_uint8_t * p = call SubPacket.getPayload(msg, len);
+    return (void *)(p + sizeof(mhpacket_header_t));
+  }
+
+  command uint8_t Packet.maxPayloadLength(){
+    return call SubPacket.maxPayloadLength() - sizeof(mhpacket_header_t);
+  }
+
+  command uint8_t Packet.payloadLength(message_t *amsg){
+    return HEADER->len;
+  }
+
+  command void Packet.setPayloadLength(message_t *amsg, uint8_t len){
+    HEADER->len = len;
+    call SubPacket.setPayloadLength(amsg, len + sizeof(mhpacket_header_t));
+  }
+
+  
+  /**********
+   * AMPacket *
+   **********/
+
+  command am_addr_t MHPacket.address(){
+    return call AMPacket.address();
+  }
+
+  command am_addr_t MHPacket.destination(message_t *amsg){
+    return HEADER->dest;
+  }
+
+  command bool MHPacket.isForMe(message_t *amsg){
+    return ((HEADER->dest == call MHPacket.address()) || (HEADER->dest == AM_BROADCAST_ADDR));
+  }
+
+  command void MHPacket.setDestination(message_t *amsg, am_addr_t addr){
+    HEADER->dest = addr;
+  }
+
+  command void MHPacket.setSource(message_t *amsg, am_addr_t addr){
+    HEADER->src = addr;
+  }
+
+  command void MHPacket.setType(message_t *amsg, am_id_t t){
+    HEADER->type = t;
+    call AMPacket.setType(amsg, AM_MULTIHOP);
+  }
+
+  command am_addr_t MHPacket.source(message_t *amsg){
+    return HEADER->src;
+  }
+
+  command am_id_t MHPacket.type(message_t *amsg){
+    return HEADER->type;
+  }
+
+  /* *** UNIMPLEMENTED ! *** */
+  //TODO what to do with this?
+
+  command am_group_t MHPacket.group(message_t* amsg) {
+    return 0;
+  }
+
+  command void MHPacket.setGroup(message_t* amsg, am_group_t grp) { }
+
+  command am_group_t MHPacket.localGroup() {
+    return 0;
+  }
+
+}
diff --git a/tos/lib/net/tymo/mh/MHServiceC.nc b/tos/lib/net/tymo/mh/MHServiceC.nc
new file mode 100644 (file)
index 0000000..af0e96e
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+/**
+ * MHServiceC - Implements a simple multihop transport protocol
+ *
+ * @author Romain Thouvenin
+ */
+
+configuration MHServiceC {
+  provides { //For upper layer
+    interface AMSend as MHSend[uint8_t id];
+    interface Receive[uint8_t id];
+    interface Intercept[uint8_t id];
+    interface AMPacket as MHPacket;
+    interface Packet;
+    interface LinkMonitor;
+  }
+  uses {  //From lower layer
+    interface AMPacket;
+    interface Packet as SubPacket;
+    interface AMSend;
+    interface Receive as SubReceive;
+    interface PacketAcknowledgements as Acks;
+  }
+
+  provides interface MHControl;
+}
+
+implementation {
+  components DymoTableC, MHEngineM, MHPacketM;
+  components new ForwardingEngineM(), new TimerMilliC();
+
+  //provides
+  MHSend      = ForwardingEngineM.AMSend;
+  Receive     = ForwardingEngineM.Receive;
+  Intercept   = ForwardingEngineM.Intercept;
+  LinkMonitor = ForwardingEngineM.LinkMonitor;
+  MHPacket    = MHPacketM.MHPacket;
+  Packet      = MHPacketM.Packet;
+  Acks        = ForwardingEngineM.Acks;
+
+  //uses
+  ForwardingEngineM.AMPacket   = AMPacket;  
+  MHEngineM.AMPacket          = AMPacket;  
+  MHPacketM.AMPacket          = AMPacket;  
+  MHPacketM.SubPacket         = SubPacket; 
+  ForwardingEngineM.SubPacket  = SubPacket; 
+  ForwardingEngineM.SubSend    = AMSend;    
+  ForwardingEngineM.SubReceive = SubReceive;
+
+  //MHEngine
+  MHEngineM.MHPacket     -> MHPacketM.MHPacket;
+  MHEngineM.RoutingTable -> DymoTableC;
+
+  //ForwardingEngine
+  ForwardingEngineM.RouteSelect -> MHEngineM;
+  ForwardingEngineM.PPacket     -> MHPacketM.Packet;
+  ForwardingEngineM.Timer       -> TimerMilliC;
+
+  MHControl = ForwardingEngineM.MHControl;
+}
diff --git a/tos/lib/net/tymo/mh/mhpacket.h b/tos/lib/net/tymo/mh/mhpacket.h
new file mode 100644 (file)
index 0000000..1b33f61
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef MHPACKET_H
+#define MHPACKET_H
+
+#include "AM.h"
+#include "message.h"
+#include "routing.h"
+
+typedef nx_struct mhpacket_header {
+  nx_uint8_t len;
+  nx_uint8_t type;
+  nx_am_addr_t src;
+  nx_am_addr_t dest;
+} mhpacket_header_t;
+
+typedef nx_struct mhpacket {
+  mhpacket_header_t header;
+  nx_uint8_t data[];
+} mhpacket_t;
+
+enum { //for mig
+  AM_MHPACKET = AM_MULTIHOP,
+};
+
+#endif
diff --git a/tos/lib/net/tymo/routing.h b/tos/lib/net/tymo/routing.h
new file mode 100644 (file)
index 0000000..95ca305
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+#ifndef _DYMO_ROUTING_H_
+#define _DYMO_ROUTING_H_
+
+#include "AM.h"
+
+typedef am_addr_t addr_t;
+typedef nx_am_addr_t nx_addr_t;
+typedef uint16_t seqnum_t;
+typedef nx_uint16_t nx_seqnum_t;
+
+#ifndef MAX_TABLE_SIZE
+#define MAX_TABLE_SIZE 5
+#endif
+
+#ifndef DYMO_HOPLIMIT
+#define DYMO_HOPLIMIT 10
+#endif
+
+#ifndef DYMO_ROUTE_AGE_MAX
+#define DYMO_ROUTE_AGE_MAX 300000
+#endif
+
+#ifndef DYMO_ROUTE_TIMEOUT
+#define DYMO_ROUTE_TIMEOUT 10000
+#endif
+
+#ifndef DYMO_APPEND_INFO
+#define DYMO_APPEND_INFO      0      //1 to append info to forwarded RMs
+#endif
+
+#ifndef DYMO_INTER_RREP
+#define DYMO_INTER_RREP       1      //1 to allow intermediate RREP 
+#endif
+
+#ifndef DYMO_FORCE_INTER_RREP
+#define DYMO_FORCE_INTER_RREP 1      //1 to send intermediate RREP even without target's seqnum in the RREQ
+#endif
+
+#ifndef DYMO_LINK_FEEDBACK
+#define DYMO_LINK_FEEDBACK    1      //1 to use acks to detect broken links
+#endif
+
+enum {
+  AM_MULTIHOP = 9,
+  AM_DYMO = 8
+};
+
+typedef enum {
+  DYMO_RREQ = 10,
+  DYMO_RREP,
+  DYMO_RERR
+} dymo_msg_t;
+
+//processing action
+typedef enum {
+  ACTION_KEEP,   //info is kept in the forwarded message
+  //  ACTION_UPDATE, //info is kept, and updated with the provided info
+  ACTION_DISCARD, //info is not kept in the forwarded message
+  ACTION_DISCARD_MSG //The message won't be forwarded, no need to build a forwarded message anymore
+} proc_action_t;
+
+typedef enum {
+  FW_SEND,      //Put the message in the sending queue
+  FW_RECEIVE,   //Give the message to the upper layer
+  FW_WAIT,      //Retry later
+  FW_DISCARD,   //Discard the message
+} fw_action_t;
+
+
+#endif
diff --git a/tos/lib/net/tymo/routing_table.h b/tos/lib/net/tymo/routing_table.h
new file mode 100644 (file)
index 0000000..b9a54cd
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2007 Romain Thouvenin <romain.thouvenin@gmail.com>
+ * Published under the terms of the GNU General Public License (GPLv2).
+ */
+
+#ifndef _ROUTING_TABLE_H_
+#define _ROUTING_TABLE_H_
+
+#include "routing.h"
+
+/**
+ * Types associated to a routing table.
+ */
+
+typedef struct rt_info {
+  addr_t address;
+  addr_t nexthop;
+  seqnum_t seqnum;
+  bool has_hopcnt;
+  uint8_t hopcnt;
+} rt_info_t;
+
+typedef enum {
+  REASON_FULL,
+  REASON_OLD,
+  REASON_UNREACHABLE
+} reason_t;
+
+#endif