PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RHRouter.h 17KB

3 yıl önce
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. // RHRouter.h
  2. //
  3. // Author: Mike McCauley (mikem@airspayce.com)
  4. // Copyright (C) 2011 Mike McCauley
  5. // $Id: RHRouter.h,v 1.9 2014/08/10 20:55:17 mikem Exp $
  6. #ifndef RHRouter_h
  7. #define RHRouter_h
  8. #include <RHReliableDatagram.h>
  9. // Default max number of hops we will route
  10. #define RH_DEFAULT_MAX_HOPS 30
  11. // The default size of the routing table we keep
  12. #define RH_ROUTING_TABLE_SIZE 10
  13. // Error codes
  14. #define RH_ROUTER_ERROR_NONE 0
  15. #define RH_ROUTER_ERROR_INVALID_LENGTH 1
  16. #define RH_ROUTER_ERROR_NO_ROUTE 2
  17. #define RH_ROUTER_ERROR_TIMEOUT 3
  18. #define RH_ROUTER_ERROR_NO_REPLY 4
  19. #define RH_ROUTER_ERROR_UNABLE_TO_DELIVER 5
  20. // This size of RH_ROUTER_MAX_MESSAGE_LEN is OK for Arduino Mega, but too big for
  21. // Duemilanova. Size of 50 works with the sample router programs on Duemilanova.
  22. #define RH_ROUTER_MAX_MESSAGE_LEN (RH_MAX_MESSAGE_LEN - sizeof(RHRouter::RoutedMessageHeader))
  23. //#define RH_ROUTER_MAX_MESSAGE_LEN 50
  24. // These allow us to define a simulated network topology for testing purposes
  25. // See RHRouter.cpp for details
  26. //#define RH_TEST_NETWORK 1
  27. //#define RH_TEST_NETWORK 2
  28. //#define RH_TEST_NETWORK 3
  29. //#define RH_TEST_NETWORK 4
  30. /////////////////////////////////////////////////////////////////////
  31. /// \class RHRouter RHRouter.h <RHRouter.h>
  32. /// \brief RHReliableDatagram subclass for sending addressed, optionally acknowledged datagrams
  33. /// multi-hop routed across a network.
  34. ///
  35. /// Manager class that extends RHReliableDatagram to define addressed messages
  36. /// That are reliably transmitted and routed across a network. Each message is transmitted reliably
  37. /// between each hop in order to get from the source node to the destination node.
  38. ///
  39. /// With RHRouter, routes are hard wired. This means that each node must have programmed
  40. /// in it how to reach each of the other nodes it will be trying to communicate with.
  41. /// This means you must specify the next-hop node address for each of the destination nodes,
  42. /// using the addRouteTo() function.
  43. ///
  44. /// When sendtoWait() is called with a new message to deliver, and the destination address,
  45. /// RHRouter looks up the next hop node for the destination node. It then uses
  46. /// RHReliableDatagram to (reliably) deliver the message to the next hop
  47. /// (which is expected also to be running an RHRouter). If that next-hop node is not
  48. /// the final destination, it will also look up the next hop for the destination node and
  49. /// (reliably) deliver the message to the next hop. By this method, messages can be delivered
  50. /// across a network of nodes, even if each node cannot hear all of the others in the network.
  51. /// Each time a message is received for another node and retransmitted to the next hop,
  52. /// the HOPS filed in teh header is incremented. If a message is received for routing to another node
  53. /// which has exceed the routers max_hops, the message wioll be dropped and ignored.
  54. /// This helps prevent infinite routing loops.
  55. ///
  56. /// RHRouter supports messages with a dest of RH_BROADCAST_ADDRESS. Such messages are not routed,
  57. /// and are broadcast (once) to all nodes within range.
  58. ///
  59. /// The recvfromAck() function is responsible not just for receiving and delivering
  60. /// messages addressed to this node (or RH_BROADCAST_ADDRESS), but
  61. /// it is also responsible for routing other message to their next hop. This means that it is important to
  62. /// call recvfromAck() or recvfromAckTimeout() frequently in your main loop. recvfromAck() will return
  63. /// false if it receives a message but it is not for this node.
  64. ///
  65. /// RHRouter does not provide reliable end-to-end delivery, but uses reliable hop-to-hop delivery.
  66. /// If a message is unable to be delivered to an end node during to a delivery failure between 2 hops,
  67. /// the source node will not be told about it.
  68. ///
  69. /// Note: This class is most useful for networks of nodes that are essentially static
  70. /// (i.e. the nodes dont move around), and for which the
  71. /// routing never changes. If that is not the case for your proposed network, see RHMesh instead.
  72. ///
  73. /// \par The Routing Table
  74. ///
  75. /// The routing table is a local table in RHRouter that holds the information about the next hop node
  76. /// address for each destination address you may want to send a message to. It is your responsibility
  77. /// to make sure every node in an RHRouter network has been configured with a unique address and the
  78. /// routing information so that messages are correctly routed across the network from source node to
  79. /// destination node. This is usually done once in setup() by calling addRouteTo().
  80. /// The hardwired routing will in general be different on each node, and will depend on the physical
  81. /// topololgy of the network.
  82. /// You can also use addRouteTo() to change a route and
  83. /// deleteRouteTo() to delete a route at run time. Youcan also clear the entire routing table
  84. ///
  85. /// The Routing Table has limited capacity for entries (defined by RH_ROUTING_TABLE_SIZE, which is 10)
  86. /// if more than RH_ROUTING_TABLE_SIZE are added, the oldest (first) one will be removed by calling
  87. /// retireOldestRoute()
  88. ///
  89. /// \par Message Format
  90. ///
  91. /// RHRouter add to the lower level RHReliableDatagram (and even lower level RH) class message formats.
  92. /// In those lower level classes, the hop-to-hop message headers are in the RH message headers,
  93. /// and are handled automcatically by tyhe RH hardware.
  94. /// RHRouter and its subclasses add an end-to-end addressing header in the payload of the RH message,
  95. /// and before the RHRouter application data.
  96. /// - 1 octet DEST, the destination node address (ie the address of the final
  97. /// destination node for this message)
  98. /// - 1 octet SOURCE, the source node address (ie the address of the originating node that first sent
  99. /// the message).
  100. /// - 1 octet HOPS, the number of hops this message has traversed so far.
  101. /// - 1 octet ID, an incrementing message ID for end-to-end message tracking for use by subclasses.
  102. /// Not used by RHRouter.
  103. /// - 1 octet FLAGS, a bitmask for use by subclasses. Not used by RHRouter.
  104. /// - 0 or more octets DATA, the application payload data. The length of this data is implicit
  105. /// in the length of the entire message.
  106. ///
  107. /// You should be careful to note that there are ID and FLAGS fields in the low level per-hop
  108. /// message header too. These are used only for hop-to-hop, and in general will be different to
  109. /// the ones at the RHRouter level.
  110. ///
  111. /// \par Testing
  112. ///
  113. /// Bench testing of such networks is notoriously difficult, especially simulating limited radio
  114. /// connectivity between some nodes.
  115. /// To assist testing (both during RH development and for your own networks)
  116. /// RHRouter.cpp has the ability to
  117. /// simulate a number of different small network topologies. Each simulated network supports 4 nodes with
  118. /// addresses 1 to 4. It operates by pretending to not hear RH messages from certain other nodes.
  119. /// You can enable testing with a \#define TEST_NETWORK in RHRouter.h
  120. /// The sample programs rf22_mesh_* rely on this feature.
  121. ///
  122. /// Part of the Arduino RH library for operating with HopeRF RH compatible transceivers
  123. /// (see http://www.hoperf.com)
  124. class RHRouter : public RHReliableDatagram
  125. {
  126. public:
  127. /// Defines the structure of the RHRouter message header, used to keep track of end-to-end delivery parameters
  128. typedef struct
  129. {
  130. uint8_t dest; ///< Destination node address
  131. uint8_t source; ///< Originator node address
  132. uint8_t hops; ///< Hops traversed so far
  133. uint8_t id; ///< Originator sequence number
  134. uint8_t flags; ///< Originator flags
  135. // Data follows, Length is implicit in the overall message length
  136. } RoutedMessageHeader;
  137. /// Defines the structure of a RHRouter message
  138. typedef struct
  139. {
  140. RoutedMessageHeader header; ///< end-to-end delivery header
  141. uint8_t data[RH_ROUTER_MAX_MESSAGE_LEN]; ///< Application payload data
  142. } RoutedMessage;
  143. /// Values for the possible states for routes
  144. typedef enum
  145. {
  146. Invalid = 0, ///< No valid route is known
  147. Discovering, ///< Discovering a route (not currently used)
  148. Valid ///< Route is valid
  149. } RouteState;
  150. /// Defines an entry in the routing table
  151. typedef struct
  152. {
  153. uint8_t dest; ///< Destination node address
  154. uint8_t next_hop; ///< Send via this next hop address
  155. uint8_t state; ///< State of this route, one of RouteState
  156. } RoutingTableEntry;
  157. /// Constructor.
  158. /// \param[in] driver The RadioHead driver to use to transport messages.
  159. /// \param[in] thisAddress The address to assign to this node. Defaults to 0
  160. RHRouter(RHGenericDriver& driver, uint8_t thisAddress = 0);
  161. /// Initialises this instance and the radio module connected to it.
  162. /// Overrides the init() function in RH.
  163. /// Sets max_hops to the default of RH_DEFAULT_MAX_HOPS (30)
  164. bool init();
  165. /// Sets the max_hops to the given value
  166. /// This controls the maximum number of hops allowed between source and destination nodes
  167. /// Messages that are not delivered by the time their HOPS field exceeds max_hops on a
  168. /// routing node will be dropped and ignored.
  169. /// \param [in] max_hops The new value for max_hops
  170. void setMaxHops(uint8_t max_hops);
  171. /// Adds a route to the local routing table, or updates it if already present.
  172. /// If there is not enough room the oldest (first) route will be deleted by calling retireOldestRoute().
  173. /// \param [in] dest The destination node address. RH_BROADCAST_ADDRESS is permitted.
  174. /// \param [in] next_hop The address of the next hop to send messages destined for dest
  175. /// \param [in] state The satte of the route. Defaults to Valid
  176. void addRouteTo(uint8_t dest, uint8_t next_hop, uint8_t state = Valid);
  177. /// Finds and returns a RoutingTableEntry for the given destination node
  178. /// \param [in] dest The desired destination node address.
  179. /// \return pointer to a RoutingTableEntry for dest
  180. RoutingTableEntry* getRouteTo(uint8_t dest);
  181. /// Deletes from the local routing table any route for the destination node.
  182. /// \param [in] dest The destination node address
  183. /// \return true if the route was present
  184. bool deleteRouteTo(uint8_t dest);
  185. /// Deletes the oldest (first) route from the
  186. /// local routing table
  187. void retireOldestRoute();
  188. /// Clears all entries from the
  189. /// local routing table
  190. void clearRoutingTable();
  191. /// If RH_HAVE_SERIAL is defined, this will print out the contents of the local
  192. /// routing table using Serial
  193. void printRoutingTable();
  194. /// Sends a message to the destination node. Initialises the RHRouter message header
  195. /// (the SOURCE address is set to the address of this node, HOPS to 0) and calls
  196. /// route() which looks up in the routing table the next hop to deliver to and sends the
  197. /// message to the next hop. Waits for an acknowledgement from the next hop
  198. /// (but not from the destination node (if that is different).
  199. /// \param [in] buf The application message data
  200. /// \param [in] len Number of octets in the application message data. 0 is permitted
  201. /// \param [in] dest The destination node address
  202. /// \param [in] flags Optional flags for use by subclasses or application layer,
  203. /// delivered end-to-end to the dest address. The receiver can recover the flags with recvFromAck().
  204. /// \return The result code:
  205. /// - RH_ROUTER_ERROR_NONE Message was routed and delivered to the next hop
  206. /// (not necessarily to the final dest address)
  207. /// - RH_ROUTER_ERROR_NO_ROUTE There was no route for dest in the local routing table
  208. /// - RH_ROUTER_ERROR_UNABLE_TO_DELIVER Not able to deliver to the next hop
  209. /// (usually because it dod not acknowledge due to being off the air or out of range
  210. uint8_t sendtoWait(uint8_t* buf, uint8_t len, uint8_t dest, uint8_t flags = 0);
  211. /// Similar to sendtoWait() above, but spoofs the source address.
  212. /// For internal use only during routing
  213. /// \param [in] buf The application message data.
  214. /// \param [in] len Number of octets in the application message data. 0 is permitted.
  215. /// \param [in] dest The destination node address.
  216. /// \param [in] source The (fake) originating node address.
  217. /// \param [in] flags Optional flags for use by subclasses or application layer,
  218. /// delivered end-to-end to the dest address. The receiver can recover the flags with recvFromAck().
  219. /// \return The result code:
  220. /// - RH_ROUTER_ERROR_NONE Message was routed and deliverd to the next hop
  221. /// (not necessarily to the final dest address)
  222. /// - RH_ROUTER_ERROR_NO_ROUTE There was no route for dest in the local routing table
  223. /// - RH_ROUTER_ERROR_UNABLE_TO_DELIVER Noyt able to deliver to the next hop
  224. /// (usually because it dod not acknowledge due to being off the air or out of range
  225. uint8_t sendtoFromSourceWait(uint8_t* buf, uint8_t len, uint8_t dest, uint8_t source, uint8_t flags = 0);
  226. /// Starts the receiver if it is not running already.
  227. /// If there is a valid message available for this node (or RH_BROADCAST_ADDRESS),
  228. /// send an acknowledgement to the last hop
  229. /// address (blocking until this is complete), then copy the application message payload data
  230. /// to buf and return true
  231. /// else return false.
  232. /// If a message is copied, *len is set to the length..
  233. /// If from is not NULL, the originator SOURCE address is placed in *source.
  234. /// If to is not NULL, the DEST address is placed in *dest. This might be this nodes address or
  235. /// RH_BROADCAST_ADDRESS.
  236. /// This is the preferred function for getting messages addressed to this node.
  237. /// If the message is not a broadcast, acknowledge to the sender before returning.
  238. /// \param[in] buf Location to copy the received message
  239. /// \param[in,out] len Available space in buf. Set to the actual number of octets copied.
  240. /// \param[in] source If present and not NULL, the referenced uint8_t will be set to the SOURCE address
  241. /// \param[in] dest If present and not NULL, the referenced uint8_t will be set to the DEST address
  242. /// \param[in] id If present and not NULL, the referenced uint8_t will be set to the ID
  243. /// \param[in] flags If present and not NULL, the referenced uint8_t will be set to the FLAGS
  244. /// (not just those addressed to this node).
  245. /// \return true if a valid message was recvived for this node copied to buf
  246. bool recvfromAck(uint8_t* buf, uint8_t* len, uint8_t* source = NULL, uint8_t* dest = NULL, uint8_t* id = NULL, uint8_t* flags = NULL);
  247. /// Starts the receiver if it is not running already.
  248. /// Similar to recvfromAck(), this will block until either a valid message available for this node
  249. /// or the timeout expires.
  250. /// \param[in] buf Location to copy the received message
  251. /// \param[in,out] len Available space in buf. Set to the actual number of octets copied.
  252. /// \param[in] timeout Maximum time to wait in milliseconds
  253. /// \param[in] source If present and not NULL, the referenced uint8_t will be set to the SOURCE address
  254. /// \param[in] dest If present and not NULL, the referenced uint8_t will be set to the DEST address
  255. /// \param[in] id If present and not NULL, the referenced uint8_t will be set to the ID
  256. /// \param[in] flags If present and not NULL, the referenced uint8_t will be set to the FLAGS
  257. /// (not just those addressed to this node).
  258. /// \return true if a valid message was copied to buf
  259. 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);
  260. protected:
  261. /// Lets sublasses peek at messages going
  262. /// past before routing or local delivery.
  263. /// Called by recvfromAck() immediately after it gets the message from RHReliableDatagram
  264. /// \param [in] message Pointer to the RHRouter message that was received.
  265. /// \param [in] messageLen Length of message in octets
  266. virtual void peekAtMessage(RoutedMessage* message, uint8_t messageLen);
  267. /// Finds the next-hop route and sends the message via RHReliableDatagram::sendtoWait().
  268. /// This is virtual, which lets subclasses override or intercept the route() function.
  269. /// Called by sendtoWait after the message header has been filled in.
  270. /// \param [in] message Pointer to the RHRouter message to be sent.
  271. /// \param [in] messageLen Length of message in octets
  272. virtual uint8_t route(RoutedMessage* message, uint8_t messageLen);
  273. /// Deletes a specific rout entry from therouting table
  274. /// \param [in] index The 0 based index of the routing table entry to delete
  275. void deleteRoute(uint8_t index);
  276. /// The last end-to-end sequence number to be used
  277. /// Defaults to 0
  278. uint8_t _lastE2ESequenceNumber;
  279. /// The maximum number of hops permitted in routed messages.
  280. /// If a routed message would exceed this number of hops it is dropped and ignored.
  281. uint8_t _max_hops;
  282. private:
  283. /// Temporary mesage buffer
  284. static RoutedMessage _tmpMessage;
  285. /// Local routing table
  286. RoutingTableEntry _routes[RH_ROUTING_TABLE_SIZE];
  287. };
  288. /// @example rf22_router_client.pde
  289. /// @example rf22_router_server1.pde
  290. /// @example rf22_router_server2.pde
  291. /// @example rf22_router_server3.pde
  292. #endif