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

Committer:
charly
Date:
Mon Sep 02 20:32:54 2013 +0000
Revision:
9:4002a2c117cc
Parent:
5:0386600f3408
removed DEBUG-LEDs LED1 .. LED4 as they make problems on other platforms (KL25Z)

Who changed what in which revision?

UserRevisionLine numberNew contents of line
charly 0:79c6d0071c4c 1 // RF22Mesh.cpp
charly 0:79c6d0071c4c 2 //
charly 0:79c6d0071c4c 3 // Define addressed datagram
charly 0:79c6d0071c4c 4 //
charly 0:79c6d0071c4c 5 // Part of the Arduino RF22 library for operating with HopeRF RF22 compatible transceivers
charly 0:79c6d0071c4c 6 // (see http://www.hoperf.com)
charly 0:79c6d0071c4c 7 // RF22Datagram will be received only by the addressed node or all nodes within range if the
charly 0:79c6d0071c4c 8 // to address is RF22_BROADCAST_ADDRESS
charly 0:79c6d0071c4c 9 //
charly 0:79c6d0071c4c 10 // Author: Mike McCauley (mikem@open.com.au)
charly 0:79c6d0071c4c 11 // Copyright (C) 2011 Mike McCauley
charly 0:79c6d0071c4c 12 // $Id: RF22Mesh.cpp,v 1.4 2011/02/15 04:51:59 mikem Exp $
charly 0:79c6d0071c4c 13 // ported to mbed by Karl Zweimueller
charly 0:79c6d0071c4c 14
charly 0:79c6d0071c4c 15 #include <mbed.h>
charly 0:79c6d0071c4c 16 #include <RF22Mesh.h>
charly 0:79c6d0071c4c 17 //#include <SPI.h>
charly 0:79c6d0071c4c 18
charly 0:79c6d0071c4c 19
charly 0:79c6d0071c4c 20 uint8_t RF22Mesh::_tmpMessage[RF22_ROUTER_MAX_MESSAGE_LEN];
charly 0:79c6d0071c4c 21
charly 0:79c6d0071c4c 22 ////////////////////////////////////////////////////////////////////
charly 0:79c6d0071c4c 23 // Constructors
charly 0:79c6d0071c4c 24 RF22Mesh::RF22Mesh(uint8_t thisAddress ,PinName slaveSelectPin , PinName mosi, PinName miso, PinName sclk, PinName interrupt )
charly 0:79c6d0071c4c 25 : RF22Router(thisAddress, slaveSelectPin, mosi, miso, sclk, interrupt )
charly 0:79c6d0071c4c 26 {
charly 0:79c6d0071c4c 27 }
charly 0:79c6d0071c4c 28
charly 0:79c6d0071c4c 29 ////////////////////////////////////////////////////////////////////
charly 0:79c6d0071c4c 30 // Public methods
charly 0:79c6d0071c4c 31
charly 0:79c6d0071c4c 32 ////////////////////////////////////////////////////////////////////
charly 0:79c6d0071c4c 33 // Discovers a route to the destination (if necessary), sends and
charly 0:79c6d0071c4c 34 // waits for delivery to the next hop (but not for delivery to the final destination)
charly 0:79c6d0071c4c 35 uint8_t RF22Mesh::sendtoWait(uint8_t* buf, uint8_t len, uint8_t address)
charly 0:79c6d0071c4c 36 {
charly 0:79c6d0071c4c 37 if (len > RF22_MESH_MAX_MESSAGE_LEN)
charly 0:79c6d0071c4c 38 return RF22_ROUTER_ERROR_INVALID_LENGTH;
charly 0:79c6d0071c4c 39
charly 0:79c6d0071c4c 40 RoutingTableEntry* route = getRouteTo(address);
charly 0:79c6d0071c4c 41 if (!route && !doArp(address))
charly 0:79c6d0071c4c 42 return RF22_ROUTER_ERROR_NO_ROUTE;
charly 0:79c6d0071c4c 43
charly 0:79c6d0071c4c 44 // Now have a route. Contruct an applicaiotn layer message and dend it via that route
charly 0:79c6d0071c4c 45 MeshApplicationMessage* a = (MeshApplicationMessage*)&_tmpMessage;
charly 0:79c6d0071c4c 46 a->header.msgType = RF22_MESH_MESSAGE_TYPE_APPLICATION;
charly 0:79c6d0071c4c 47 memcpy(a->data, buf, len);
charly 0:79c6d0071c4c 48 return RF22Router::sendtoWait(_tmpMessage, sizeof(RF22Mesh::MeshMessageHeader) + len, address);
charly 0:79c6d0071c4c 49 }
charly 0:79c6d0071c4c 50
charly 0:79c6d0071c4c 51 ////////////////////////////////////////////////////////////////////
charly 0:79c6d0071c4c 52 boolean RF22Mesh::doArp(uint8_t address)
charly 0:79c6d0071c4c 53 {
charly 0:79c6d0071c4c 54 // Need to discover a route
charly 0:79c6d0071c4c 55 // Broadcast a route discovery message with nothing in it
charly 0:79c6d0071c4c 56 MeshRouteDiscoveryMessage* p = (MeshRouteDiscoveryMessage*)&_tmpMessage;
charly 0:79c6d0071c4c 57 p->header.msgType = RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST;
charly 0:79c6d0071c4c 58 p->destlen = 1;
charly 0:79c6d0071c4c 59 p->dest = address; // Who we are looking for
charly 0:79c6d0071c4c 60 uint8_t error = RF22Router::sendtoWait((uint8_t*)p, sizeof(RF22Mesh::MeshMessageHeader) + 2, RF22_BROADCAST_ADDRESS);
charly 0:79c6d0071c4c 61 if (error != RF22_ROUTER_ERROR_NONE)
charly 0:79c6d0071c4c 62 return false;
charly 0:79c6d0071c4c 63
charly 0:79c6d0071c4c 64 // Wait for a reply, which will be unicast back to us
charly 0:79c6d0071c4c 65 // It will contain the complete route to the destination
charly 0:79c6d0071c4c 66 uint8_t messageLen = sizeof(_tmpMessage);
charly 0:79c6d0071c4c 67 // FIXME: timeout should be configurable
charly 0:79c6d0071c4c 68 Timer t;
charly 0:79c6d0071c4c 69 t.start();
charly 0:79c6d0071c4c 70 unsigned long endtime = t.read_ms() + 4000;
charly 0:79c6d0071c4c 71 while (t.read_ms() < endtime)
charly 0:79c6d0071c4c 72 {
charly 0:79c6d0071c4c 73 if (RF22Router::recvfromAck(_tmpMessage, &messageLen))
charly 0:79c6d0071c4c 74 {
charly 0:79c6d0071c4c 75 if ( messageLen > 1
charly 0:79c6d0071c4c 76 && p->header.msgType == RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE)
charly 0:79c6d0071c4c 77 {
charly 0:79c6d0071c4c 78 MeshRouteDiscoveryMessage* d = (MeshRouteDiscoveryMessage*)p;
charly 0:79c6d0071c4c 79 // Got a reply, now add the next hop to the dest to the routing table
charly 0:79c6d0071c4c 80 // The first hop taken is the first octet
charly 0:79c6d0071c4c 81 addRouteTo(address, headerFrom());
charly 0:79c6d0071c4c 82 return true;
charly 0:79c6d0071c4c 83 }
charly 0:79c6d0071c4c 84 }
charly 0:79c6d0071c4c 85 }
charly 0:79c6d0071c4c 86 return false;
charly 0:79c6d0071c4c 87 }
charly 0:79c6d0071c4c 88
charly 0:79c6d0071c4c 89 ////////////////////////////////////////////////////////////////////
charly 0:79c6d0071c4c 90 // Called by RF22Router::recvfromAck whenever a message goes past
charly 0:79c6d0071c4c 91 void RF22Mesh::peekAtMessage(RoutedMessage* message, uint8_t messageLen)
charly 0:79c6d0071c4c 92 {
charly 0:79c6d0071c4c 93 MeshMessageHeader* m = (MeshMessageHeader*)message->data;
charly 0:79c6d0071c4c 94 if ( messageLen > 1
charly 0:79c6d0071c4c 95 && m->msgType == RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE)
charly 0:79c6d0071c4c 96 {
charly 0:79c6d0071c4c 97 // This is a unicast RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE messages
charly 0:79c6d0071c4c 98 // being routed back to the originator here. Want to scrape some routing data out of the response
charly 0:79c6d0071c4c 99 // We can find the routes to all the nodes between here and the responding node
charly 0:79c6d0071c4c 100 MeshRouteDiscoveryMessage* d = (MeshRouteDiscoveryMessage*)message->data;
charly 0:79c6d0071c4c 101 addRouteTo(d->dest, headerFrom());
charly 0:79c6d0071c4c 102 uint8_t numRoutes = messageLen - sizeof(RoutedMessageHeader) - sizeof(MeshMessageHeader) - 2;
charly 0:79c6d0071c4c 103 uint8_t i;
charly 0:79c6d0071c4c 104 // Find us in the list of nodes that were traversed to get to the responding node
charly 0:79c6d0071c4c 105 for (i = 0; i < numRoutes; i++)
charly 0:79c6d0071c4c 106 if (d->route[i] == _thisAddress)
charly 0:79c6d0071c4c 107 break;
charly 0:79c6d0071c4c 108 i++;
charly 0:79c6d0071c4c 109 while (i++ < numRoutes)
charly 0:79c6d0071c4c 110 addRouteTo(d->route[i], headerFrom());
charly 0:79c6d0071c4c 111 }
charly 0:79c6d0071c4c 112 else if ( messageLen > 1
charly 0:79c6d0071c4c 113 && m->msgType == RF22_MESH_MESSAGE_TYPE_ROUTE_FAILURE)
charly 0:79c6d0071c4c 114 {
charly 0:79c6d0071c4c 115 MeshRouteFailureMessage* d = (MeshRouteFailureMessage*)message->data;
charly 0:79c6d0071c4c 116 deleteRouteTo(d->dest);
charly 0:79c6d0071c4c 117 }
charly 0:79c6d0071c4c 118 }
charly 0:79c6d0071c4c 119
charly 0:79c6d0071c4c 120 ////////////////////////////////////////////////////////////////////
charly 0:79c6d0071c4c 121 // This is called when a message is to be delivered to the next hop
charly 0:79c6d0071c4c 122 uint8_t RF22Mesh::route(RoutedMessage* message, uint8_t messageLen)
charly 0:79c6d0071c4c 123 {
charly 0:79c6d0071c4c 124 uint8_t from = headerFrom(); // Might get clobbered during call to superclass route()
charly 0:79c6d0071c4c 125 uint8_t ret = RF22Router::route(message, messageLen);
charly 0:79c6d0071c4c 126 if ( ret == RF22_ROUTER_ERROR_NO_ROUTE
charly 0:79c6d0071c4c 127 || ret == RF22_ROUTER_ERROR_UNABLE_TO_DELIVER)
charly 0:79c6d0071c4c 128 {
charly 0:79c6d0071c4c 129 // Cant deliver to the next hop. Delete the route
charly 0:79c6d0071c4c 130 deleteRouteTo(message->header.dest);
charly 0:79c6d0071c4c 131 if (message->header.source != _thisAddress)
charly 0:79c6d0071c4c 132 {
charly 0:79c6d0071c4c 133 // This is being proxied, so tell the originator about it
charly 0:79c6d0071c4c 134 MeshRouteFailureMessage* p = (MeshRouteFailureMessage*)&_tmpMessage;
charly 0:79c6d0071c4c 135 p->header.msgType = RF22_MESH_MESSAGE_TYPE_ROUTE_FAILURE;
charly 0:79c6d0071c4c 136 p->dest = message->header.dest; // Who you were trying to deliver to
charly 0:79c6d0071c4c 137 // Make sure there is a route back towards whoever sent the original message
charly 0:79c6d0071c4c 138 addRouteTo(message->header.source, from);
charly 0:79c6d0071c4c 139 ret = RF22Router::sendtoWait((uint8_t*)p, sizeof(RF22Mesh::MeshMessageHeader) + 1, message->header.source);
charly 0:79c6d0071c4c 140 }
charly 0:79c6d0071c4c 141 }
charly 0:79c6d0071c4c 142 return ret;
charly 0:79c6d0071c4c 143 }
charly 0:79c6d0071c4c 144
charly 0:79c6d0071c4c 145 ////////////////////////////////////////////////////////////////////
charly 0:79c6d0071c4c 146 // Subclasses may want to override
charly 0:79c6d0071c4c 147 boolean RF22Mesh::isPhysicalAddress(uint8_t* address, uint8_t addresslen)
charly 0:79c6d0071c4c 148 {
charly 0:79c6d0071c4c 149 // Can only handle physical addresses 1 octet long, which is the physical node address
charly 0:79c6d0071c4c 150 return addresslen == 1 && address[0] == _thisAddress;
charly 0:79c6d0071c4c 151 }
charly 0:79c6d0071c4c 152
charly 0:79c6d0071c4c 153 ////////////////////////////////////////////////////////////////////
charly 0:79c6d0071c4c 154 boolean RF22Mesh::recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* source, uint8_t* dest, uint8_t* id, uint8_t* flags)
charly 0:79c6d0071c4c 155 {
charly 0:79c6d0071c4c 156 uint8_t tmpMessageLen = sizeof(_tmpMessage);
charly 0:79c6d0071c4c 157 uint8_t _source;
charly 0:79c6d0071c4c 158 uint8_t _dest;
charly 0:79c6d0071c4c 159 uint8_t _id;
charly 0:79c6d0071c4c 160 uint8_t _flags;
charly 0:79c6d0071c4c 161 if (RF22Router::recvfromAck(_tmpMessage, &tmpMessageLen, &_source, &_dest, &_id, &_flags))
charly 0:79c6d0071c4c 162 {
charly 0:79c6d0071c4c 163 MeshMessageHeader* p = (MeshMessageHeader*)&_tmpMessage;
charly 0:79c6d0071c4c 164
charly 0:79c6d0071c4c 165 if ( tmpMessageLen >= 1
charly 0:79c6d0071c4c 166 && p->msgType == RF22_MESH_MESSAGE_TYPE_APPLICATION)
charly 0:79c6d0071c4c 167 {
charly 0:79c6d0071c4c 168 MeshApplicationMessage* a = (MeshApplicationMessage*)p;
charly 0:79c6d0071c4c 169 // Handle application layer messages, presumably for our caller
charly 0:79c6d0071c4c 170 if (source) *source = _source;
charly 0:79c6d0071c4c 171 if (dest) *dest = _dest;
charly 0:79c6d0071c4c 172 if (id) *id = _id;
charly 0:79c6d0071c4c 173 if (flags) *flags = _flags;
charly 0:79c6d0071c4c 174 uint8_t msgLen = tmpMessageLen - sizeof(MeshMessageHeader);
charly 0:79c6d0071c4c 175 if (*len > msgLen)
charly 0:79c6d0071c4c 176 *len = msgLen;
charly 0:79c6d0071c4c 177 memcpy(buf, a->data, *len);
charly 0:79c6d0071c4c 178
charly 0:79c6d0071c4c 179 return true;
charly 0:79c6d0071c4c 180 }
charly 0:79c6d0071c4c 181 else if ( _dest == RF22_BROADCAST_ADDRESS
charly 0:79c6d0071c4c 182 && tmpMessageLen > 1
charly 0:79c6d0071c4c 183 && p->msgType == RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST)
charly 0:79c6d0071c4c 184 {
charly 0:79c6d0071c4c 185 MeshRouteDiscoveryMessage* d = (MeshRouteDiscoveryMessage*)p;
charly 0:79c6d0071c4c 186 // Handle Route discovery requests
charly 0:79c6d0071c4c 187 // Message is an array of node addresses the route request has already passed through
charly 0:79c6d0071c4c 188 // If it originally came from us, ignore it
charly 0:79c6d0071c4c 189 if (_source == _thisAddress)
charly 0:79c6d0071c4c 190 return false;
charly 0:79c6d0071c4c 191
charly 0:79c6d0071c4c 192 uint8_t numRoutes = tmpMessageLen - sizeof(MeshMessageHeader) - 2;
charly 0:79c6d0071c4c 193 uint8_t i;
charly 0:79c6d0071c4c 194 // Are we already mentioned?
charly 0:79c6d0071c4c 195 for (i = 0; i < numRoutes; i++)
charly 0:79c6d0071c4c 196 if (d->route[i] == _thisAddress)
charly 0:79c6d0071c4c 197 return false; // Already been through us. Discard
charly 0:79c6d0071c4c 198
charly 0:79c6d0071c4c 199 // Hasnt been past us yet, record routes back to the earlier nodes
charly 0:79c6d0071c4c 200 addRouteTo(_source, headerFrom()); // The originator
charly 0:79c6d0071c4c 201 for (i = 0; i < numRoutes; i++)
charly 0:79c6d0071c4c 202 addRouteTo(d->route[i], headerFrom());
charly 0:79c6d0071c4c 203 if (isPhysicalAddress(&d->dest, d->destlen))
charly 0:79c6d0071c4c 204 {
charly 0:79c6d0071c4c 205 // This route discovery is for us. Unicast the whole route back to the originator
charly 0:79c6d0071c4c 206 // as a RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE
charly 0:79c6d0071c4c 207 // We are certain to have a route there, becuase we just got it
charly 0:79c6d0071c4c 208 d->header.msgType = RF22_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE;
charly 0:79c6d0071c4c 209 RF22Router::sendtoWait((uint8_t*)d, tmpMessageLen, _source);
charly 0:79c6d0071c4c 210 }
charly 0:79c6d0071c4c 211 else if (i < _max_hops)
charly 0:79c6d0071c4c 212 {
charly 0:79c6d0071c4c 213 // Its for someone else, rebroadcast it, after adding ourselves to the list
charly 0:79c6d0071c4c 214 d->route[numRoutes] = _thisAddress;
charly 0:79c6d0071c4c 215 tmpMessageLen++;
charly 0:79c6d0071c4c 216 // Have to impersonate the source
charly 0:79c6d0071c4c 217 // REVISIT: if this fails what can we do?
charly 0:79c6d0071c4c 218 RF22Router::sendtoWait(_tmpMessage, tmpMessageLen, RF22_BROADCAST_ADDRESS, _source);
charly 0:79c6d0071c4c 219 }
charly 0:79c6d0071c4c 220 }
charly 0:79c6d0071c4c 221 }
charly 0:79c6d0071c4c 222 return false;
charly 0:79c6d0071c4c 223 }
charly 0:79c6d0071c4c 224
charly 0:79c6d0071c4c 225 ////////////////////////////////////////////////////////////////////
charly 0:79c6d0071c4c 226 boolean RF22Mesh::recvfromAckTimeout(uint8_t* buf, uint8_t* len, uint16_t timeout, uint8_t* from, uint8_t* to, uint8_t* id, uint8_t* flags)
charly 0:79c6d0071c4c 227 {
charly 0:79c6d0071c4c 228 Timer t;
charly 0:79c6d0071c4c 229
charly 0:79c6d0071c4c 230 t.start();
charly 0:79c6d0071c4c 231 unsigned long endtime = t.read_ms() + timeout;
charly 0:79c6d0071c4c 232 while (t.read_ms() < endtime)
charly 0:79c6d0071c4c 233 {
charly 0:79c6d0071c4c 234 if (recvfromAck(buf, len, from, to, id, flags))
charly 0:79c6d0071c4c 235 return true;
charly 0:79c6d0071c4c 236 }
charly 0:79c6d0071c4c 237 return false;
charly 0:79c6d0071c4c 238 }
charly 0:79c6d0071c4c 239
charly 0:79c6d0071c4c 240