Diff: RF22Router.cpp
- Revision:
- 0:e16ffa7cb900
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RF22Router.cpp Mon Jul 02 01:29:58 2012 +0000
@@ -0,0 +1,308 @@
+// RF22Router.cpp
+//
+// Define addressed datagram
+//
+// Part of the Arduino RF22 library for operating with HopeRF RF22 compatible transceivers
+// (see http://www.hoperf.com)
+// RF22Datagram will be received only by the addressed node or all nodes within range if the
+// to address is RF22_BROADCAST_ADDRESS
+//
+// Author: Mike McCauley (mikem@open.com.au)
+// Copyright (C) 2011 Mike McCauley
+// $Id: RF22Router.cpp,v 1.6 2011/02/15 01:18:03 mikem Exp $
+// ported to mbed by Karl Zweimueller
+
+#include <mbed.h>
+#include <RF22Router.h>
+//#include <SPI.h>
+
+
+RF22Router::RoutedMessage RF22Router::_tmpMessage;
+
+////////////////////////////////////////////////////////////////////
+// Constructors
+RF22Router::RF22Router(uint8_t thisAddress ,PinName slaveSelectPin , PinName mosi, PinName miso, PinName sclk, PinName interrupt )
+ : RF22ReliableDatagram(thisAddress, slaveSelectPin, mosi, miso, sclk, interrupt )
+{
+ _max_hops = RF22_DEFAULT_MAX_HOPS;
+ clearRoutingTable();
+}
+
+////////////////////////////////////////////////////////////////////
+// Public methods
+boolean RF22Router::init()
+{
+ boolean ret = RF22ReliableDatagram::init();
+ if (ret)
+ _max_hops = RF22_DEFAULT_MAX_HOPS;
+ return ret;
+}
+
+////////////////////////////////////////////////////////////////////
+void RF22Router::setMaxHops(uint8_t max_hops)
+{
+ _max_hops = max_hops;
+}
+
+////////////////////////////////////////////////////////////////////
+void RF22Router::addRouteTo(uint8_t dest, uint8_t next_hop, uint8_t state)
+{
+ uint8_t i;
+
+ // First look for an existing entry we can update
+ for (i = 0; i < RF22_ROUTING_TABLE_SIZE; i++)
+ {
+ if (_routes[i].dest == dest)
+ {
+ _routes[i].dest = dest;
+ _routes[i].next_hop = next_hop;
+ _routes[i].state = state;
+ return;
+ }
+ }
+
+ // Look for an invalid entry we can use
+ for (i = 0; i < RF22_ROUTING_TABLE_SIZE; i++)
+ {
+ if (_routes[i].state == Invalid)
+ {
+ _routes[i].dest = dest;
+ _routes[i].next_hop = next_hop;
+ _routes[i].state = state;
+ return;
+ }
+ }
+
+ // Need to make room for a new one
+ retireOldestRoute();
+ // Should be an invalid slot now
+ for (i = 0; i < RF22_ROUTING_TABLE_SIZE; i++)
+ {
+ if (_routes[i].state == Invalid)
+ {
+ _routes[i].dest = dest;
+ _routes[i].next_hop = next_hop;
+ _routes[i].state = state;
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////
+RF22Router::RoutingTableEntry* RF22Router::getRouteTo(uint8_t dest)
+{
+ uint8_t i;
+ for (i = 0; i < RF22_ROUTING_TABLE_SIZE; i++)
+ if (_routes[i].dest == dest && _routes[i].state != Invalid)
+ return &_routes[i];
+ return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+void RF22Router::deleteRoute(uint8_t index)
+{
+ // Delete a route by copying following routes on top of it
+ memcpy(&_routes[index], &_routes[index+1],
+ sizeof(RoutingTableEntry) * (RF22_ROUTING_TABLE_SIZE - index - 1));
+ _routes[RF22_ROUTING_TABLE_SIZE - 1].state = Invalid;
+}
+
+#ifdef RF22_HAVE_SERIAL
+////////////////////////////////////////////////////////////////////
+void RF22Router::printRoutingTable()
+{
+ uint8_t i;
+ for (i = 0; i < RF22_ROUTING_TABLE_SIZE; i++)
+ {
+ Serial.print(i, DEC);
+ Serial.print(" Dest: ");
+ Serial.print(_routes[i].dest, DEC);
+ Serial.print(" Next Hop: ");
+ Serial.print(_routes[i].next_hop, DEC);
+ Serial.print(" State: ");
+ Serial.println(_routes[i].state, DEC);
+ }
+}
+#endif
+
+////////////////////////////////////////////////////////////////////
+boolean RF22Router::deleteRouteTo(uint8_t dest)
+{
+ uint8_t i;
+ for (i = 0; i < RF22_ROUTING_TABLE_SIZE; i++)
+ {
+ if (_routes[i].dest == dest)
+ {
+ deleteRoute(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////
+void RF22Router::retireOldestRoute()
+{
+ // We just obliterate the first in the table and clear the last
+ deleteRoute(0);
+}
+
+////////////////////////////////////////////////////////////////////
+void RF22Router::clearRoutingTable()
+{
+ uint8_t i;
+ for (i = 0; i < RF22_ROUTING_TABLE_SIZE; i++)
+ _routes[i].state = Invalid;
+}
+
+
+uint8_t RF22Router::sendtoWait(uint8_t* buf, uint8_t len, uint8_t dest)
+{
+ return sendtoWait(buf, len, dest, _thisAddress);
+}
+
+////////////////////////////////////////////////////////////////////
+// Waits for delivery to the next hop (but not for delivery to the final destination)
+uint8_t RF22Router::sendtoWait(uint8_t* buf, uint8_t len, uint8_t dest, uint8_t source)
+{
+ if (((uint16_t)len + sizeof(RoutedMessageHeader)) > RF22_MAX_MESSAGE_LEN)
+ return RF22_ROUTER_ERROR_INVALID_LENGTH;
+
+ // Construct a RF22 RouterMessage message
+ _tmpMessage.header.source = source;
+ _tmpMessage.header.dest = dest;
+ _tmpMessage.header.hops = 0;
+ _tmpMessage.header.id = _lastE2ESequenceNumber++;
+ _tmpMessage.header.flags = 0;
+ memcpy(_tmpMessage.data, buf, len);
+
+ return route(&_tmpMessage, sizeof(RoutedMessageHeader)+len);
+}
+
+////////////////////////////////////////////////////////////////////
+uint8_t RF22Router::route(RoutedMessage* message, uint8_t messageLen)
+{
+ // Reliably deliver it if possible. See if we have a route:
+ uint8_t next_hop = RF22_BROADCAST_ADDRESS;
+ if (message->header.dest != RF22_BROADCAST_ADDRESS)
+ {
+ RoutingTableEntry* route = getRouteTo(message->header.dest);
+ if (!route)
+ return RF22_ROUTER_ERROR_NO_ROUTE;
+ next_hop = route->next_hop;
+ }
+
+ if (!RF22ReliableDatagram::sendtoWait((uint8_t*)message, messageLen, next_hop))
+ return RF22_ROUTER_ERROR_UNABLE_TO_DELIVER;
+
+ return RF22_ROUTER_ERROR_NONE;
+}
+
+////////////////////////////////////////////////////////////////////
+// Subclasses may want to override this to peek at messages going past
+void RF22Router::peekAtMessage(RoutedMessage* message, uint8_t messageLen)
+{
+ // Default does nothing
+}
+
+////////////////////////////////////////////////////////////////////
+boolean RF22Router::recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* source, uint8_t* dest, uint8_t* id, uint8_t* flags)
+{
+ uint8_t tmpMessageLen = sizeof(_tmpMessage);
+ uint8_t _from;
+ uint8_t _to;
+ uint8_t _id;
+ uint8_t _flags;
+ if (RF22ReliableDatagram::recvfromAck((uint8_t*)&_tmpMessage, &tmpMessageLen, &_from, &_to, &_id, &_flags))
+ {
+ // Here we simulate networks with limited visibility between nodes
+ // so we can test routing
+#ifdef RF22_TEST_NETWORK
+ if (
+#if RF22_TEST_NETWORK==1
+ // This looks like 1-2-3-4
+ (_thisAddress == 1 && _from == 2)
+ || (_thisAddress == 2 && (_from == 1 || _from == 3))
+ || (_thisAddress == 3 && (_from == 2 || _from == 4))
+ || (_thisAddress == 4 && _from == 3)
+
+#elif RF22_TEST_NETWORK==2
+ // This looks like 1-2-4
+ // | | |
+ // --3--
+ (_thisAddress == 1 && (_from == 2 || _from == 3))
+ || _thisAddress == 2
+ || _thisAddress == 3
+ || (_thisAddress == 4 && (_from == 2 || _from == 3))
+
+#elif RF22_TEST_NETWORK==3
+ // This looks like 1-2-4
+ // | |
+ // --3--
+ (_thisAddress == 1 && (_from == 2 || _from == 3))
+ || (_thisAddress == 2 && (_from == 1 || _from == 4))
+ || (_thisAddress == 3 && (_from == 1 || _from == 4))
+ || (_thisAddress == 4 && (_from == 2 || _from == 3))
+
+#elif RF22_TEST_NETWORK==4
+ // This looks like 1-2-3
+ // |
+ // 4
+ (_thisAddress == 1 && _from == 2)
+ || _thisAddress == 2
+ || (_thisAddress == 3 && _from == 2)
+ || (_thisAddress == 4 && _from == 2)
+
+#endif
+)
+ {
+ // OK
+ }
+ else
+ {
+ return false; // Pretend we got nothing
+ }
+#endif
+
+ peekAtMessage(&_tmpMessage, tmpMessageLen);
+ // See if its for us or has to be routed
+ if (_tmpMessage.header.dest == _thisAddress || _tmpMessage.header.dest == RF22_BROADCAST_ADDRESS)
+ {
+ // Deliver it here
+ if (source) *source = _tmpMessage.header.source;
+ if (dest) *dest = _tmpMessage.header.dest;
+ if (id) *id = _tmpMessage.header.id;
+ if (flags) *flags = _tmpMessage.header.flags;
+ uint8_t msgLen = tmpMessageLen - sizeof(RoutedMessageHeader);
+ if (*len > msgLen)
+ *len = msgLen;
+ memcpy(buf, _tmpMessage.data, *len);
+ return true; // Its for you!
+ }
+ else if ( _tmpMessage.header.dest != RF22_BROADCAST_ADDRESS
+ && _tmpMessage.header.hops++ < _max_hops)
+ {
+ // Maybe it has to be routed to the next hop
+ // REVISIT: if it fails due to no route or unable to deliver to the next hop,
+ // tell the originator. BUT HOW?
+ route(&_tmpMessage, tmpMessageLen);
+ }
+ // Discard it and maybe wait for another
+ }
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////
+boolean RF22Router::recvfromAckTimeout(uint8_t* buf, uint8_t* len, uint16_t timeout, uint8_t* source, uint8_t* dest, uint8_t* id, uint8_t* flags)
+{
+ Timer t;
+
+ t.start();
+ unsigned long endtime = t.read_ms() + timeout;
+ while (t.read_ms() < endtime)
+ {
+ if (recvfromAck(buf, len, source, dest, id, flags))
+ return true;
+ }
+ return false;
+}
+