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.
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 Tue Jul 12 2022 18:05:56 by
