Port of RadioHead version 1.48 to mbed. It is a little messy and only works for SPI at this time.

Committer:
davidr99
Date:
Thu Oct 15 01:27:00 2015 +0000
Revision:
0:ab4e012489ef
Messy start, but a port for RadioHead.; Currently the SPI modulus are the only ones that work.

Who changed what in which revision?

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