PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

245 líneas
8.8KB

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