Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: Threaded_LoRa_Modem
RHMesh.cpp
00001 // RHMesh.cpp 00002 // 00003 // Define addressed datagram 00004 // 00005 // Part of the Arduino RH library for operating with HopeRF RH compatible transceivers 00006 // (see http://www.hoperf.com) 00007 // RHDatagram will be received only by the addressed node or all nodes within range if the 00008 // to address is RH_BROADCAST_ADDRESS 00009 // 00010 // Author: Mike McCauley (mikem@airspayce.com) 00011 // Copyright (C) 2011 Mike McCauley 00012 // $Id: RHMesh.cpp,v 1.9 2015/08/13 02:45:47 mikem Exp $ 00013 00014 #include <RHMesh.h> 00015 00016 uint8_t RHMesh::_tmpMessage[RH_ROUTER_MAX_MESSAGE_LEN]; 00017 00018 //////////////////////////////////////////////////////////////////// 00019 // Constructors 00020 RHMesh::RHMesh(RHGenericDriver& driver, uint8_t thisAddress) 00021 : RHRouter(driver, thisAddress) 00022 { 00023 } 00024 00025 //////////////////////////////////////////////////////////////////// 00026 // Public methods 00027 00028 //////////////////////////////////////////////////////////////////// 00029 // Discovers a route to the destination (if necessary), sends and 00030 // waits for delivery to the next hop (but not for delivery to the final destination) 00031 uint8_t RHMesh::sendtoWait(uint8_t* buf, uint8_t len, uint8_t address, uint8_t flags) 00032 { 00033 if (len > RH_MESH_MAX_MESSAGE_LEN) 00034 return RH_ROUTER_ERROR_INVALID_LENGTH; 00035 00036 if (address != RH_BROADCAST_ADDRESS) 00037 { 00038 RoutingTableEntry* route = getRouteTo(address); 00039 if (!route && !doArp(address)) 00040 return RH_ROUTER_ERROR_NO_ROUTE; 00041 } 00042 00043 // Now have a route. Contruct an application layer message and send it via that route 00044 MeshApplicationMessage* a = (MeshApplicationMessage*)&_tmpMessage; 00045 a->header.msgType = RH_MESH_MESSAGE_TYPE_APPLICATION; 00046 memcpy(a->data, buf, len); 00047 return RHRouter::sendtoWait(_tmpMessage, sizeof(RHMesh::MeshMessageHeader) + len, address, flags); 00048 } 00049 00050 //////////////////////////////////////////////////////////////////// 00051 bool RHMesh::doArp(uint8_t address) 00052 { 00053 // Need to discover a route 00054 // Broadcast a route discovery message with nothing in it 00055 MeshRouteDiscoveryMessage* p = (MeshRouteDiscoveryMessage*)&_tmpMessage; 00056 p->header.msgType = RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST; 00057 p->destlen = 1; 00058 p->dest = address; // Who we are looking for 00059 uint8_t error = RHRouter::sendtoWait((uint8_t*)p, sizeof(RHMesh::MeshMessageHeader) + 2, RH_BROADCAST_ADDRESS); 00060 if (error != RH_ROUTER_ERROR_NONE) 00061 return false; 00062 00063 // Wait for a reply, which will be unicast back to us 00064 // It will contain the complete route to the destination 00065 uint8_t messageLen = sizeof(_tmpMessage); 00066 // FIXME: timeout should be configurable 00067 unsigned long starttime = millis(); 00068 int32_t timeLeft; 00069 while ((timeLeft = RH_MESH_ARP_TIMEOUT - (millis() - starttime)) > 0) 00070 { 00071 if (waitAvailableTimeout(timeLeft)) 00072 { 00073 if (RHRouter::recvfromAck(_tmpMessage, &messageLen)) 00074 { 00075 if ( messageLen > 1 00076 && p->header.msgType == RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE) 00077 { 00078 // Got a reply, now add the next hop to the dest to the routing table 00079 // The first hop taken is the first octet 00080 addRouteTo(address, headerFrom()); 00081 return true; 00082 } 00083 } 00084 } 00085 YIELD; 00086 } 00087 return false; 00088 } 00089 00090 //////////////////////////////////////////////////////////////////// 00091 // Called by RHRouter::recvfromAck whenever a message goes past 00092 void RHMesh::peekAtMessage(RoutedMessage* message, uint8_t messageLen) 00093 { 00094 MeshMessageHeader* m = (MeshMessageHeader*)message->data; 00095 if ( messageLen > 1 00096 && m->msgType == RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE) 00097 { 00098 // This is a unicast RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE messages 00099 // being routed back to the originator here. Want to scrape some routing data out of the response 00100 // We can find the routes to all the nodes between here and the responding node 00101 MeshRouteDiscoveryMessage* d = (MeshRouteDiscoveryMessage*)message->data; 00102 addRouteTo(d->dest, headerFrom()); 00103 uint8_t numRoutes = messageLen - sizeof(RoutedMessageHeader) - sizeof(MeshMessageHeader) - 2; 00104 uint8_t i; 00105 // Find us in the list of nodes that were traversed to get to the responding node 00106 for (i = 0; i < numRoutes; i++) 00107 if (d->route[i] == _thisAddress) 00108 break; 00109 i++; 00110 while (i++ < numRoutes) 00111 addRouteTo(d->route[i], headerFrom()); 00112 } 00113 else if ( messageLen > 1 00114 && m->msgType == RH_MESH_MESSAGE_TYPE_ROUTE_FAILURE) 00115 { 00116 MeshRouteFailureMessage* d = (MeshRouteFailureMessage*)message->data; 00117 deleteRouteTo(d->dest); 00118 } 00119 } 00120 00121 //////////////////////////////////////////////////////////////////// 00122 // This is called when a message is to be delivered to the next hop 00123 uint8_t RHMesh::route(RoutedMessage* message, uint8_t messageLen) 00124 { 00125 uint8_t from = headerFrom(); // Might get clobbered during call to superclass route() 00126 uint8_t ret = RHRouter::route(message, messageLen); 00127 if ( ret == RH_ROUTER_ERROR_NO_ROUTE 00128 || ret == RH_ROUTER_ERROR_UNABLE_TO_DELIVER) 00129 { 00130 // Cant deliver to the next hop. Delete the route 00131 deleteRouteTo(message->header.dest); 00132 if (message->header.source != _thisAddress) 00133 { 00134 // This is being proxied, so tell the originator about it 00135 MeshRouteFailureMessage* p = (MeshRouteFailureMessage*)&_tmpMessage; 00136 p->header.msgType = RH_MESH_MESSAGE_TYPE_ROUTE_FAILURE; 00137 p->dest = message->header.dest; // Who you were trying to deliver to 00138 // Make sure there is a route back towards whoever sent the original message 00139 addRouteTo(message->header.source, from); 00140 ret = RHRouter::sendtoWait((uint8_t*)p, sizeof(RHMesh::MeshMessageHeader) + 1, message->header.source); 00141 } 00142 } 00143 return ret; 00144 } 00145 00146 //////////////////////////////////////////////////////////////////// 00147 // Subclasses may want to override 00148 bool RHMesh::isPhysicalAddress(uint8_t* address, uint8_t addresslen) 00149 { 00150 // Can only handle physical addresses 1 octet long, which is the physical node address 00151 return addresslen == 1 && address[0] == _thisAddress; 00152 } 00153 00154 //////////////////////////////////////////////////////////////////// 00155 bool RHMesh::recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* source, uint8_t* dest, uint8_t* id, uint8_t* flags) 00156 { 00157 uint8_t tmpMessageLen = sizeof(_tmpMessage); 00158 uint8_t _source; 00159 uint8_t _dest; 00160 uint8_t _id; 00161 uint8_t _flags; 00162 if (RHRouter::recvfromAck(_tmpMessage, &tmpMessageLen, &_source, &_dest, &_id, &_flags)) 00163 { 00164 MeshMessageHeader* p = (MeshMessageHeader*)&_tmpMessage; 00165 00166 if ( tmpMessageLen >= 1 00167 && p->msgType == RH_MESH_MESSAGE_TYPE_APPLICATION) 00168 { 00169 MeshApplicationMessage* a = (MeshApplicationMessage*)p; 00170 // Handle application layer messages, presumably for our caller 00171 if (source) *source = _source; 00172 if (dest) *dest = _dest; 00173 if (id) *id = _id; 00174 if (flags) *flags = _flags; 00175 uint8_t msgLen = tmpMessageLen - sizeof(MeshMessageHeader); 00176 if (*len > msgLen) 00177 *len = msgLen; 00178 memcpy(buf, a->data, *len); 00179 00180 return true; 00181 } 00182 else if ( _dest == RH_BROADCAST_ADDRESS 00183 && tmpMessageLen > 1 00184 && p->msgType == RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST) 00185 { 00186 MeshRouteDiscoveryMessage* d = (MeshRouteDiscoveryMessage*)p; 00187 // Handle Route discovery requests 00188 // Message is an array of node addresses the route request has already passed through 00189 // If it originally came from us, ignore it 00190 if (_source == _thisAddress) 00191 return false; 00192 00193 uint8_t numRoutes = tmpMessageLen - sizeof(MeshMessageHeader) - 2; 00194 uint8_t i; 00195 // Are we already mentioned? 00196 for (i = 0; i < numRoutes; i++) 00197 if (d->route[i] == _thisAddress) 00198 return false; // Already been through us. Discard 00199 00200 // Hasnt been past us yet, record routes back to the earlier nodes 00201 addRouteTo(_source, headerFrom()); // The originator 00202 for (i = 0; i < numRoutes; i++) 00203 addRouteTo(d->route[i], headerFrom()); 00204 if (isPhysicalAddress(&d->dest, d->destlen)) 00205 { 00206 // This route discovery is for us. Unicast the whole route back to the originator 00207 // as a RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE 00208 // We are certain to have a route there, because we just got it 00209 d->header.msgType = RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE; 00210 RHRouter::sendtoWait((uint8_t*)d, tmpMessageLen, _source); 00211 } 00212 else if (i < _max_hops) 00213 { 00214 // Its for someone else, rebroadcast it, after adding ourselves to the list 00215 d->route[numRoutes] = _thisAddress; 00216 tmpMessageLen++; 00217 // Have to impersonate the source 00218 // REVISIT: if this fails what can we do? 00219 RHRouter::sendtoFromSourceWait(_tmpMessage, tmpMessageLen, RH_BROADCAST_ADDRESS, _source); 00220 } 00221 } 00222 } 00223 return false; 00224 } 00225 00226 //////////////////////////////////////////////////////////////////// 00227 bool RHMesh::recvfromAckTimeout(uint8_t* buf, uint8_t* len, uint16_t timeout, uint8_t* from, uint8_t* to, uint8_t* id, uint8_t* flags) 00228 { 00229 unsigned long starttime = millis(); 00230 int32_t timeLeft; 00231 while ((timeLeft = timeout - (millis() - starttime)) > 0) 00232 { 00233 if (waitAvailableTimeout(timeLeft)) 00234 { 00235 if (recvfromAck(buf, len, from, to, id, flags)) 00236 return true; 00237 YIELD; 00238 } 00239 } 00240 return false; 00241 } 00242 00243 00244
Generated on Thu Jul 14 2022 12:14:49 by
1.7.2