Library for HopeRF RFM22 / RFM22B transceiver module ported to mbed. Original Software from Mike McCauley (mikem@open.com.au) . See http://www.open.com.au/mikem/arduino/RF22/
Dependents: RF22_MAX_test_Send Geofence_receiver Geofence_sender Geofence_sender ... more
More Info about RFM22-modules like connecting and a demo-program see RF22-Notebook
Diff: RF22Router.cpp
- Revision:
- 0:79c6d0071c4c
- Child:
- 5:0386600f3408
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RF22Router.cpp Tue Feb 14 19:39:36 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; +} +