This driver is a stripped down version of the Radiohead 1.45 driver, and covers fewer radios. Threading and an event queue have been added to make the ISR's more stable across architectures. Specifically The STM32L4 parts

Dependents:   Threaded_LoRa_Modem

Committer:
rlanders73
Date:
Wed Jun 23 15:53:12 2021 +0000
Revision:
7:250d1c72df36
Parent:
0:ab4e012489ef
explicitly not disabling interrupts for mbed

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