Library for HopeRF RFM22 transceiver module ported to mbed. Original Software from Mike McCauley (mikem@open.com.au) . See http://www.open.com.au/mikem/arduino/RF22/

Fork of RF22 by Karl Zweimüller

Committer:
floha
Date:
Thu Aug 29 21:57:14 2013 +0000
Revision:
9:46fb41f4259d
Parent:
5:0386600f3408
changed the LED default numbers in the RF22 constructor as the former values interfered with pins used on an KL25Z board. The library didn't work with those.

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