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
RF22Mesh.cpp@9:46fb41f4259d, 2013-08-29 (annotated)
- 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?
User | Revision | Line number | New 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 |