PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

263 lines
15KB

  1. // RHMesh.h
  2. //
  3. // Author: Mike McCauley (mikem@airspayce.com)
  4. // Copyright (C) 2011 Mike McCauley
  5. // $Id: RHMesh.h,v 1.15 2015/08/13 02:45:47 mikem Exp $
  6. #ifndef RHMesh_h
  7. #define RHMesh_h
  8. #include <RHRouter.h>
  9. // Types of RHMesh message, used to set msgType in the RHMeshHeader
  10. #define RH_MESH_MESSAGE_TYPE_APPLICATION 0
  11. #define RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST 1
  12. #define RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE 2
  13. #define RH_MESH_MESSAGE_TYPE_ROUTE_FAILURE 3
  14. // Timeout for address resolution in milliecs
  15. #define RH_MESH_ARP_TIMEOUT 4000
  16. /////////////////////////////////////////////////////////////////////
  17. /// \class RHMesh RHMesh.h <RHMesh.h>
  18. /// \brief RHRouter subclass for sending addressed, optionally acknowledged datagrams
  19. /// multi-hop routed across a network, with automatic route discovery
  20. ///
  21. /// Manager class that extends RHRouter to add automatic route discovery within a mesh of adjacent nodes,
  22. /// and route signalling.
  23. ///
  24. /// Unlike RHRouter, RHMesh can be used in networks where the network topology is fluid, or unknown,
  25. /// or if nodes can mode around or go in or out of service. When a node wants to send a
  26. /// message to another node, it will automatically discover a route to the destination node and use it.
  27. /// If the route becomes unavailable, a new route will be discovered.
  28. ///
  29. /// \par Route Discovery
  30. ///
  31. /// When a RHMesh mesh node is initialised, it doe not know any routes to any other nodes
  32. /// (see RHRouter for details on route and the routing table).
  33. /// When you attempt to send a message with sendtoWait, will first check to see if there is a route to the
  34. /// destinastion node in the routing tabl;e. If not, it wil initialite 'Route Discovery'.
  35. /// When a node needs to discover a route to another node, it broadcasts MeshRouteDiscoveryMessage
  36. /// with a message type of RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST.
  37. /// Any node that receives such a request checks to see if it is a request for a route to itself
  38. /// (in which case it makes a unicast reply to the originating node with a
  39. /// MeshRouteDiscoveryMessage
  40. /// with a message type of RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE)
  41. /// otherwise it rebroadcasts the request, after adding itself to the list of nodes visited so
  42. /// far by the request.
  43. ///
  44. /// If a node receives a RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST that already has itself
  45. /// listed in the visited nodes, it knows it has already seen and rebroadcast this request,
  46. /// and threfore ignores it. This prevents broadcast storms.
  47. /// When a node receives a RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST it can use the list of
  48. /// nodes aready visited to deduce routes back towards the originating (requesting node).
  49. /// This also means that when the destination node of the request is reached, it (and all
  50. /// the previous nodes the request visited) will have a route back to the originating node.
  51. /// This means the unicast RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE
  52. /// reply will be routed successfully back to the original route requester.
  53. ///
  54. /// The RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE sent back by the destination node contains
  55. /// the full list of nodes that were visited on the way to the destination.
  56. /// Therefore, intermediate nodes that route the reply back towards the originating node can use the
  57. /// node list in the reply to deduce routes to all the nodes between it and the destination node.
  58. ///
  59. /// Therefore, RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST and
  60. /// RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE together ensure the original requester and all
  61. /// the intermediate nodes know how to route to the source and destination nodes and every node along the path.
  62. ///
  63. /// Note that there is a race condition here that can effect routing on multipath routes. For example,
  64. /// if the route to the destination can traverse several paths, last reply from the destination
  65. /// will be the one used.
  66. ///
  67. /// \par Route Failure
  68. ///
  69. /// RHRouter (and therefore RHMesh) use reliable hop-to-hop delivery of messages using
  70. /// hop-to-hop acknowledgements, but not end-to-end acknowledgements. When sendtoWait() returns,
  71. /// you know that the message has been delivered to the next hop, but not if it is (or even if it can be)
  72. /// delivered to the destination node. If during the course of hop-to-hop routing of a message,
  73. /// one of the intermediate RHMesh nodes finds it cannot deliver to the next hop
  74. /// (say due to a lost route or no acknwledgement from the next hop), it replies to the
  75. /// originator with a unicast MeshRouteFailureMessage RH_MESH_MESSAGE_TYPE_ROUTE_FAILURE message.
  76. /// Intermediate nodes (on the way beack to the originator)
  77. /// and the originating node use this message to delete the route to the destination
  78. /// node of the original message. This means that if a route to a destination becomes unusable
  79. /// (either because an intermediate node is off the air, or has moved out of range) a new route
  80. /// will be established the next time a message is to be sent.
  81. ///
  82. /// \par Message Format
  83. ///
  84. /// RHMesh uses a number of message formats layered on top of RHRouter:
  85. /// - MeshApplicationMessage (message type RH_MESH_MESSAGE_TYPE_APPLICATION).
  86. /// Carries an application layer message for the caller of RHMesh
  87. /// - MeshRouteDiscoveryMessage (message types RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST
  88. /// and RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_RESPONSE). Carries Route Discovery messages
  89. /// (broadcast) and replies (unicast).
  90. /// - MeshRouteFailureMessage (message type RH_MESH_MESSAGE_TYPE_ROUTE_FAILURE) Informs nodes of
  91. /// route failures.
  92. ///
  93. /// Part of the Arduino RH library for operating with HopeRF RH compatible transceivers
  94. /// (see http://www.hoperf.com)
  95. ///
  96. /// \par Memory
  97. ///
  98. /// RHMesh programs require significant amount of SRAM, often approaching 2kbytes,
  99. /// which is beyond or at the limits of some Arduinos and other processors. Programs
  100. /// with additional software besides basic RHMesh programs may well require even more. If you have insufficient
  101. /// SRAM for your program, it may result in failure to run, or wierd crashes and other hard to trace behaviour.
  102. /// In this event you should consider a processor with more SRAM, such as the MotienoMEGA with 16k
  103. /// (https://lowpowerlab.com/shop/moteinomega) or others.
  104. ///
  105. /// \par Performance
  106. /// This class (in the interests of simple implemtenation and low memory use) does not have
  107. /// message queueing. This means that only one message at a time can be handled. Message transmission
  108. /// failures can have a severe impact on network performance.
  109. /// If you need high performance mesh networking under all conditions consider XBee or similar.
  110. class RHMesh : public RHRouter
  111. {
  112. public:
  113. /// The maximum length permitted for the application payload data in a RHMesh message
  114. #define RH_MESH_MAX_MESSAGE_LEN (RH_ROUTER_MAX_MESSAGE_LEN - sizeof(RHMesh::MeshMessageHeader))
  115. /// Structure of the basic RHMesh header.
  116. typedef struct
  117. {
  118. uint8_t msgType; ///< Type of RHMesh message, one of RH_MESH_MESSAGE_TYPE_*
  119. } MeshMessageHeader;
  120. /// Signals an application layer message for the caller of RHMesh
  121. typedef struct
  122. {
  123. MeshMessageHeader header; ///< msgType = RH_MESH_MESSAGE_TYPE_APPLICATION
  124. uint8_t data[RH_MESH_MAX_MESSAGE_LEN]; ///< Application layer payload data
  125. } MeshApplicationMessage;
  126. /// Signals a route discovery request or reply (At present only supports physical dest addresses of length 1 octet)
  127. typedef struct
  128. {
  129. MeshMessageHeader header; ///< msgType = RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_*
  130. uint8_t destlen; ///< Reserved. Must be 1.g
  131. uint8_t dest; ///< The address of the destination node whose route is being sought
  132. uint8_t route[RH_MESH_MAX_MESSAGE_LEN - 1]; ///< List of node addresses visited so far. Length is implcit
  133. } MeshRouteDiscoveryMessage;
  134. /// Signals a route failure
  135. typedef struct
  136. {
  137. MeshMessageHeader header; ///< msgType = RH_MESH_MESSAGE_TYPE_ROUTE_FAILURE
  138. uint8_t dest; ///< The address of the destination towards which the route failed
  139. } MeshRouteFailureMessage;
  140. /// Constructor.
  141. /// \param[in] driver The RadioHead driver to use to transport messages.
  142. /// \param[in] thisAddress The address to assign to this node. Defaults to 0
  143. RHMesh(RHGenericDriver& driver, uint8_t thisAddress = 0);
  144. /// Sends a message to the destination node. Initialises the RHRouter message header
  145. /// (the SOURCE address is set to the address of this node, HOPS to 0) and calls
  146. /// route() which looks up in the routing table the next hop to deliver to.
  147. /// If no route is known, initiates route discovery and waits for a reply.
  148. /// Then sends the message to the next hop
  149. /// Then waits for an acknowledgement from the next hop
  150. /// (but not from the destination node (if that is different).
  151. /// \param [in] buf The application message data
  152. /// \param [in] len Number of octets in the application message data. 0 is permitted
  153. /// \param [in] dest The destination node address. If the address is RH_BROADCAST_ADDRESS (255)
  154. /// the message will be broadcast to all the nearby nodes, but not routed or relayed.
  155. /// \param [in] flags Optional flags for use by subclasses or application layer,
  156. /// delivered end-to-end to the dest address. The receiver can recover the flags with recvFromAck().
  157. /// \return The result code:
  158. /// - RH_ROUTER_ERROR_NONE Message was routed and delivered to the next hop
  159. /// (not necessarily to the final dest address)
  160. /// - RH_ROUTER_ERROR_NO_ROUTE There was no route for dest in the local routing table
  161. /// - RH_ROUTER_ERROR_UNABLE_TO_DELIVER Not able to deliver to the next hop
  162. /// (usually because it dod not acknowledge due to being off the air or out of range
  163. uint8_t sendtoWait(uint8_t* buf, uint8_t len, uint8_t dest, uint8_t flags = 0);
  164. /// Starts the receiver if it is not running already, processes and possibly routes any received messages
  165. /// addressed to other nodes
  166. /// and delivers any messages addressed to this node.
  167. /// If there is a valid application layer message available for this node (or RH_BROADCAST_ADDRESS),
  168. /// send an acknowledgement to the last hop
  169. /// address (blocking until this is complete), then copy the application message payload data
  170. /// to buf and return true
  171. /// else return false.
  172. /// If a message is copied, *len is set to the length..
  173. /// If from is not NULL, the originator SOURCE address is placed in *source.
  174. /// If to is not NULL, the DEST address is placed in *dest. This might be this nodes address or
  175. /// RH_BROADCAST_ADDRESS.
  176. /// This is the preferred function for getting messages addressed to this node.
  177. /// If the message is not a broadcast, acknowledge to the sender before returning.
  178. /// \param[in] buf Location to copy the received message
  179. /// \param[in,out] len Available space in buf. Set to the actual number of octets copied.
  180. /// \param[in] source If present and not NULL, the referenced uint8_t will be set to the SOURCE address
  181. /// \param[in] dest If present and not NULL, the referenced uint8_t will be set to the DEST address
  182. /// \param[in] id If present and not NULL, the referenced uint8_t will be set to the ID
  183. /// \param[in] flags If present and not NULL, the referenced uint8_t will be set to the FLAGS
  184. /// (not just those addressed to this node).
  185. /// \return true if a valid message was received for this node and copied to buf
  186. bool recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* source = NULL, uint8_t* dest = NULL, uint8_t* id = NULL, uint8_t* flags = NULL);
  187. /// Starts the receiver if it is not running already.
  188. /// Similar to recvfromAck(), this will block until either a valid application layer
  189. /// message available for this node
  190. /// or the timeout expires.
  191. /// \param[in] buf Location to copy the received message
  192. /// \param[in,out] len Available space in buf. Set to the actual number of octets copied.
  193. /// \param[in] timeout Maximum time to wait in milliseconds
  194. /// \param[in] source If present and not NULL, the referenced uint8_t will be set to the SOURCE address
  195. /// \param[in] dest If present and not NULL, the referenced uint8_t will be set to the DEST address
  196. /// \param[in] id If present and not NULL, the referenced uint8_t will be set to the ID
  197. /// \param[in] flags If present and not NULL, the referenced uint8_t will be set to the FLAGS
  198. /// (not just those addressed to this node).
  199. /// \return true if a valid message was copied to buf
  200. bool recvfromAckTimeout(uint8_t* buf, uint8_t* len, uint16_t timeout, uint8_t* source = NULL, uint8_t* dest = NULL, uint8_t* id = NULL, uint8_t* flags = NULL);
  201. protected:
  202. /// Internal function that inspects messages being received and adjusts the routing table if necessary.
  203. /// Called by recvfromAck() immediately after it gets the message from RHReliableDatagram
  204. /// \param [in] message Pointer to the RHRouter message that was received.
  205. /// \param [in] messageLen Length of message in octets
  206. virtual void peekAtMessage(RoutedMessage* message, uint8_t messageLen);
  207. /// Internal function that inspects messages being received and adjusts the routing table if necessary.
  208. /// This is virtual, which lets subclasses override or intercept the route() function.
  209. /// Called by sendtoWait after the message header has been filled in.
  210. /// \param [in] message Pointer to the RHRouter message to be sent.
  211. /// \param [in] messageLen Length of message in octets
  212. virtual uint8_t route(RoutedMessage* message, uint8_t messageLen);
  213. /// Try to resolve a route for the given address. Blocks while discovering the route
  214. /// which may take up to 4000 msec.
  215. /// Virtual so subclasses can override.
  216. /// \param [in] address The physical address to resolve
  217. /// \return true if the address was resolved and added to the local routing table
  218. virtual bool doArp(uint8_t address);
  219. /// Tests if the given address of length addresslen is indentical to the
  220. /// physical address of this node.
  221. /// RHMesh always implements physical addresses as the 1 octet address of the node
  222. /// given by _thisAddress
  223. /// Called by recvfromAck() to test whether a RH_MESH_MESSAGE_TYPE_ROUTE_DISCOVERY_REQUEST
  224. /// is for this node.
  225. /// Subclasses may want to override to implement more complicated or longer physical addresses
  226. /// \param [in] address Address of the pyysical addres being tested
  227. /// \param [in] addresslen Lengthof the address in bytes
  228. /// \return true if the physical address of this node is identical to address
  229. virtual bool isPhysicalAddress(uint8_t* address, uint8_t addresslen);
  230. private:
  231. /// Temporary message buffer
  232. static uint8_t _tmpMessage[RH_ROUTER_MAX_MESSAGE_LEN];
  233. };
  234. /// @example rf22_mesh_client.pde
  235. /// @example rf22_mesh_server1.pde
  236. /// @example rf22_mesh_server2.pde
  237. /// @example rf22_mesh_server3.pde
  238. #endif