-
Notifications
You must be signed in to change notification settings - Fork 152
/
RF24Mesh.h
481 lines (422 loc) · 17.1 KB
/
RF24Mesh.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
/**
* @file RF24Mesh.h
*
* Class declaration for RF24Mesh
*/
#ifndef __RF24MESH_H__
#define __RF24MESH_H__
#include <stdio.h>
#include <stdlib.h>
/**
* Network/Mesh Response Types
* The network will determine whether to automatically acknowledge payloads based on their type
* RF24Mesh uses pre-defined system types for interacting with RF24Network at the system level
*
*/
// Network ACK types
// None defined
// No Network ACK types
#define MESH_ADDR_LOOKUP 196
#define MESH_ADDR_RELEASE 197
#define MESH_ID_LOOKUP 198
#define MESH_BLANK_ID 65535
#if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny84__)
#define RF24_TINY
#endif
#include "RF24Mesh_config.h"
#if defined(__linux) && !defined(__ARDUINO_X86__) && !defined(USE_RF24_LIB_SRC)
#include <RF24/RF24.h>
#include <RF24Network/RF24Network.h>
#define RF24_LINUX
#else
#include <RF24.h>
#include <RF24Network.h>
#if defined(ARDUINO_ARCH_NRF52) || defined(ARDUINO_ARCH_NRF52840)
#include <nrf_to_nrf.h>
#endif
#endif
#include <stddef.h>
#include <stdint.h>
class RF24;
#if defined(ARDUINO_ARCH_NRF52) || defined(ARDUINO_ARCH_NRF52840) || defined(ARDUINO_ARCH_NRF52833)
class nrf_to_nrf;
#endif
template<class radio_t>
class ESBNetwork;
/**
* @tparam network_t The `network` object's type. Defaults to `RF24Network` for legacy behavior.
* This new abstraction is really meant for using the nRF52840 SoC as a drop-in replacement
* for the nRF24L01 radio. For more detail, see the
* [nrf_to_nrf Arduino library](https://github.com/TMRh20/nrf_to_nrf).
* @tparam radio_t The `radio` object's type. Defaults to `RF24` for legacy behavior.
* This new abstraction is really meant for using the nRF52840 SoC as a drop-in replacement
* for the nRF24L01 radio. For more detail, see the
* [nrf_to_nrf Arduino library](https://github.com/TMRh20/nrf_to_nrf).
*/
template<class network_t = ESBNetwork<RF24>, class radio_t = RF24>
class ESBMesh
{
/**
* @name RF24Mesh
*
* The mesh library and class documentation is currently in active development and usage may change.
*/
/**@{*/
public:
/**
* Construct the mesh.
*
* v2.0 supports a backward compatible constructor:
* @code
* RF24 radio(7, 8);
* RF24Network network(radio);
* RF24Mesh mesh(radio, network); // for nRF24L01
*
* nrf_to_nrf radio1;
* RF52Network network1(radio1);
* RF52Mesh mesh1(network1, radio1); // for nRF52xxx family
* @endcode
*
* @see v2.0 supports [nrf_to_nrf Arduino library](https://github.com/TMRh20/nrf_to_nrf)
* for nrf52 chips' internal radio.
* @param _radio The underlying radio driver instance
* @param _network The underlying network instance
*/
ESBMesh(radio_t& _radio, network_t& _network);
/**
* Call this in setup() to configure the mesh and request an address. <br>
*
* @code mesh.begin(); @endcode
* This may take a few moments to complete.
*
* The following parameters are optional:
* @param channel The radio channel (0 - 125). Default is 97.
* @param data_rate The data rate (RF24_250KBPS, RF24_1MBPS, RF24_2MBPS). Default is RF24_1MBPS.
* @param timeout How long to attempt address renewal in milliseconds. Default is 7500.
*/
bool begin(uint8_t channel = MESH_DEFAULT_CHANNEL, rf24_datarate_e data_rate = RF24_1MBPS, uint32_t timeout = MESH_RENEWAL_TIMEOUT);
/**
* Very similar to network.update(), it needs to be called regularly to keep the network
* and the mesh going.
*/
uint8_t update();
/**
* Automatically construct a header and send a payload.
* Very similar to the standard network.write() function, which can be used directly.
*
* @note Including the @ref _nodeID "nodeID" parameter will result in an automatic address lookup being performed.
* @note Message types 1 - 64 (decimal) will NOT be acknowledged by the network, types 65 - 127 will be. Use as appropriate to manage traffic:
* if expecting a response, no ack is needed.
*
* @param data Send any type of data of any length (maximum length determined by RF24Network layer).
* @param msg_type The user-defined (1 - 127) message header_type to send. Used to distinguish between different types of data being transmitted.
* @param size The size of the data being sent
* @param nodeID **Optional**: The @ref _nodeID "nodeID" of the recipient if not sending to master.
* @return True if success; false if failed
*/
bool write(const void* data, uint8_t msg_type, size_t size, uint8_t nodeID = 0);
/**
* Set a unique @ref _nodeID "nodeID" for this node.
*
* This needs to be called before ESBMesh::begin(). The parameter value passed can be fetched
* via serial connection, EEPROM, etc when configuring a large number of nodes.
* @note If using RF24Gateway and/or RF24Ethernet, nodeIDs 0 & 1 are used by the master node.
* @param nodeID Can be any unique value ranging from 1 to 255 (reserving 0 for the master node).
*/
void setNodeID(uint8_t nodeID);
/**
* @brief Reconnect to the mesh and renew the current RF24Network address.
*
* This is used to re-establish a connection to the mesh network if physical location of a node
* or surrounding nodes has changed (or a routing node becomes unavailable).
*
* @note If all nodes are set to verify connectivity and reconnect at a specified period, then
* restarting the master (and deleting dhcplist.txt on Linux) will result in complete
* network/mesh re-convergence.
* @param timeout How long to attempt address renewal in milliseconds. Default is 7500
* @return The newly assigned RF24Network address. If the connecting process fails, then
* MESH_DEFAULT_ADDRESS is returned because all consciously unconnected nodes use that address.
*/
uint16_t renewAddress(uint32_t timeout = MESH_RENEWAL_TIMEOUT);
#if !defined(MESH_NOMASTER)
/**
* This is only to be used on the master node because it manages allocation of network addresses
* for any requesting (non-master) node's ID, similar to DHCP.
*
* @warning On master nodes, It is required to call this function immediately after calling
* ESBMesh::update() to ensure address requests are handled appropriately.
*/
void DHCP();
#endif
/**@}*/
/**
* @name Advanced Operation
*
* For advanced configuration and usage of the mesh
*/
/**@{*/
/**
* Convert an RF24Network address into a nodeId.
* @param address If no address is provided, returns the local @ref _nodeID "nodeID",
* otherwise a lookup request is sent to the master node
* @return The unique identifier of the node in the range [1, 255] or -1 if node was not found.
*/
int16_t getNodeID(uint16_t address = MESH_BLANK_ID);
/**
* Tests connectivity of this node to the mesh.
* @note If this function fails, address renewal should typically be done.
*
* The current behavior will only ping this node's parent to validate connection to mesh.
* Previously, this function would validate connection by looking up this node's assigned address with
* the master node's `RF24Mesh::addrList`.
* The old behavior can be mandated by changing @ref RF24MESH_CONN_CHECK_TYPE in RF24Mesh_config.h,
* although a large mesh network might suffer a performance cost using the old behavior.
*
* @return
* - True if connected.
* - False if not connected, mesh is not responding, or this node is the master node.
*/
bool checkConnection();
/**
* Releases the currently assigned address lease. Useful for nodes that will be sleeping etc.
* @note Nodes should ensure that addresses are released successfully prior to going offline.
* @return True if successfully released, otherwise false.
*/
bool releaseAddress();
/**
* The assigned RF24Network (Octal) address of this node
* @return An unsigned 16-bit integer containing the RF24Network address in octal format.
*/
uint16_t mesh_address;
/**
* @brief Convert a @ref _nodeID "nodeID" into an RF24Network address
* @note If printing or displaying the address, it needs to be converted to octal format:
* @code{.ino} Serial.println(address, OCT); @endcode
*
* Results in a lookup request being sent to the master node.
* @param nodeID The unique identifier of the node in the range [1, 255].
* @return The RF24Network address of the node, -2 if successful but not in list, -1 if failed.
*/
int16_t getAddress(uint8_t nodeID);
/** @brief Write to a specific node by RF24Network address. */
bool write(uint16_t to_node, const void* data, uint8_t msg_type, size_t size);
/**
* Change the active radio channel after the mesh has been started.
* @param _channel The value passed to `RF24::setChannel()`
*/
void setChannel(uint8_t _channel);
/**
* Allow child nodes to discover and attach to this node.
* @param allow True to allow children, False to prevent children from attaching automatically.
*/
void setChild(bool allow);
/**
* RF24Mesh ID and Address lookups as well as address renewal can take some time.
* Set a callback function to enable additional processing while the mesh is working
*
* @code
* void myCallbackFunction(){
* someValue = someOtherValue;
* }
* mesh.setCallback(myCallbackFunction);
* @endcode
*
* @param meshCallback The name of a function to call. This function should consume no required input parameters.
*/
void setCallback(void (*meshCallback)(void));
#define MESH_CALLBACK \
if (meshCallback) meshCallback();
/**
* Set or change a @ref _nodeID "nodeID" : node address (key : value) pair manually.
* This function is for use on the master node only.
*
* @code
* // Set a static address for node 02, with nodeID 23, since it will just be
* // a static routing node for example running on an ATTiny chip.
* mesh.setAddress(23, 02);
* @endcode
* @code
* // Change or set the nodeID for an existing address
* uint16_t address = 012;
* mesh.setAddress(3, address, true);
* @endcode
*
* @param nodeID The @ref _nodeID "nodeID" to assign
* @param address The octal RF24Network address to assign
* @param searchBy Optional parameter. Default is search by @ref _nodeID "nodeID" and
* set the address. True allows searching by address and setting @ref _nodeID "nodeID".
*/
void setAddress(uint8_t nodeID, uint16_t address, bool searchBy = false);
#if !defined(MESH_NOMASTER)
/**
* Save the @ref addrList to a binary file named "dhcplist.txt".
* @note This function is for use on the master node only and only on Linux or x86 platforms.
*/
void saveDHCP();
/**
* Load the @ref addrList from a binary file named "dhcplist.txt".
* @note This function is for use on the master node only and only on Linux or x86 platforms.
*/
void loadDHCP();
/**
* @name Deprecated
*
* Methods provided for backwards compatibility with old/testing code.
*/
/**@{*/
/** @deprecated For backward compatibility with older code. Use the synonymous setAddress() instead. */
void setStaticAddress(uint8_t nodeID, uint16_t address);
#endif // !defined(MESH_NOMASTER)
/**@}*/
/**
* The unique identifying number used to differentiate mesh nodes' from their assigned network
* address. Ideally, this is set before calling begin() or renewAddress(). It is up to the
* network administrator to make sure that this number is unique to each mesh/network node.
*
* This nodeID number is typically in the range [0, 255], but remember that `0` is reserved for
* the master node. Other external systems may reserve other node ID numbers, for instance
* RF24Gateway/RF24Ethernet reserves the node ID number `1` in addition to the master node ID
* `0`.
*/
uint8_t _nodeID;
#if !defined(MESH_NOMASTER)
/**
* @brief A struct for storing a @ref _nodeID "nodeID" and an address in a single element of
* the ESBMesh::addrList array.
*
* @note This array only exists on the mesh network's master node.
*/
typedef struct
{
/** @brief The @ref _nodeID "nodeID" of an network node (child) */
uint8_t nodeID;
/** @brief The logical address of an network node (child) */
uint16_t address;
} addrListStruct;
/**
* @name Address list struct
* @brief helping members for managing the list of assigned addresses
* @see the addrListStruct struct reference
*/
/**@{*/
// Pointer used for dynamic memory allocation of address list
/**
* @brief A array of addrListStruct elements for assigned addresses.
* @see addrListStruct class reference
*/
addrListStruct* addrList;
/** @brief The number of entries in the addrListStruct of assigned addresses. */
uint8_t addrListTop;
/**
* Releases the specified address if leased to a mesh node's ID.
*
* This is specific to master nodes, so network administrators can
* manage assigned addresses without notifying the nodes that
* might be appropriating them.
*
* @param address The address to release from any mesh node.
* @return True if successfully released, otherwise false.
*/
bool releaseAddress(uint16_t address);
#endif
/**@}*/
private:
radio_t& radio;
network_t& network;
/** Function pointer for customized callback usage in long running algorithms. */
void (*meshCallback)(void);
/** Actual requesting of the address once a contact node is discovered or supplied **/
bool requestAddress(uint8_t level);
#if !defined(MESH_NOMASTER)
/** Indicator that an address request is available. */
bool doDHCP;
/** Just ensures we don't re-allocate the memory buffer if restarting the mesh on master. **/
bool addrMemAllocated;
#endif
/** Starts up the network layer with default address. */
void beginDefault();
/** A flag asserted in begin() after putting the radio in TX mode. */
bool meshStarted;
/** Returns the number of octal digits in the specified address. */
uint8_t getLevel(uint16_t address);
};
/**
* A type definition of the template class `ESBMesh` to maintain backward compatibility.
*
* ```.cpp
* RF24 radio(7, 8);
* RF24Network network(radio);
*
* RF24Mesh mesh(radio, network);
* // is equivalent to
* ESBMesh<ESBNetwork<RF24>, RF24> mesh(radio, network);
* ```
*/
typedef ESBMesh<ESBNetwork<RF24>, RF24> RF24Mesh;
#if defined(ARDUINO_ARCH_NRF52) || defined(ARDUINO_ARCH_NRF52840) || defined(ARDUINO_ARCH_NRF52833)
typedef ESBMesh<ESBNetwork<nrf_to_nrf>, nrf_to_nrf> RF52Mesh;
#endif
/**
* @example RF24Mesh_Example.ino
* <b> Arduino Example Sketch </b><br>
* This example sketch shows how to manually configure a node via RF24Mesh, and send data to the
* master node.
* The nodes will refresh their network address as soon as a single write fails. This allows the
* nodes to change position in relation to each other and the master node.
*/
/**
* @example RF24Mesh_Example_Master.ino
* <b> Arduino Example Sketch </b><br>
* @note This sketch only functions on -Arduino Due-
*
* This example sketch shows how to manually configure a node via RF24Mesh as a master node, which
* will receive all data from sensor nodes.
*
* The nodes can change physical or logical position in the network, and reconnect through different
* routing nodes as required. The master node manages the address assignments for the individual nodes
* in a manner similar to DHCP.
*
*/
/**
* @example RF24Mesh_Example_Node2Node.ino
* Example of node to node communication using RF24Mesh
*/
/**
* @example RF24Mesh_Example_Node2NodeExtra.ino
* Extended Example of node to node communication using RF24Mesh
*/
/**
* @example RF24Mesh_SerialConfig.ino
*
* This example sketch shows how the same sketch can be written to a large number of devices, which are
* configured later via Serial input.
*
*/
/**
* @example RF24Mesh_Example.cpp
*
* <b> Raspberry Pi Example Sketch </b><br>
* This example sketch shows how to manually configure a node via RF24Mesh, and send data to the
* master node.
* The nodes will refresh their network address as soon as a single write fails. This allows the
* nodes to change position in relation to each other and the master node.
*/
/**
* @example RF24Mesh_Example_Master.cpp
*
* <b> Raspberry Pi Example Sketch </b><br>
*
* This example sketch shows how to manually configure a node via RF24Mesh as a master node, which
* will receive all data from sensor nodes.
*
* The nodes can change physical or logical position in the network, and reconnect through different
* routing nodes as required. The master node manages the address assignments for the individual nodes
* in a manner similar to DHCP.
*
*/
/**
* @example RF24Mesh_Ncurses_Master.cpp
* A very limited ncurses interface used for initial monitoring/testing of RF24Mesh
* @image html "images/RF24Mesh_Ncurses.JPG"
*/
#endif // define __RF24MESH_H__