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