RF24Mesh - Automated Networking for nrf24L01 & nrf52x radios v2.1.1
2024 - A user friendly mesh overlay for sensor neworks using RF24Network
Loading...
Searching...
No Matches
RF24Mesh.cpp
Go to the documentation of this file.
1
6
7#include "RF24Mesh.h"
8#include "RF24Mesh_config.h"
9#if defined(__linux) && !defined(__ARDUINO_X86__)
10 #include <fstream>
11#endif
12#if defined(RF24NETWORK_CCM)
13 #include <RF24Network/RF24CCM.h>
14#endif
15
16template<class network_t, class radio_t>
17ESBMesh<network_t, radio_t>::ESBMesh(radio_t& _radio, network_t& _network) : radio(_radio), network(_network)
18{
19 setCallback(NULL);
20 meshStarted = false;
21#if !defined(MESH_NOMASTER)
22 addrList = nullptr;
23 addrListTop = 0;
24#endif
25}
26
27/*****************************************************/
28
29template<class network_t, class radio_t>
30bool ESBMesh<network_t, radio_t>::begin(uint8_t channel, rf24_datarate_e data_rate, uint32_t timeout)
31{
32 //delay(1); // Found problems w/SPIDEV & ncurses. Without this, getch() returns a stream of garbage
33 if (meshStarted) {
34 radio.stopListening();
35 }
36 meshStarted = true;
37 if (!radio.begin())
38 return 0;
39 radio.setChannel(channel);
40 radio.setDataRate(data_rate);
41 network.returnSysMsgs = true;
42
43 if (getNodeID() > 0) { //Not master node
44 if (renewAddress(timeout) == MESH_DEFAULT_ADDRESS) {
45 return false;
46 }
47 }
48 else {
49 mesh_address = 0;
50 network.begin(mesh_address);
51 }
52
53 return true;
54}
55
56/*****************************************************/
57
58template<class network_t, class radio_t>
60{
61 uint8_t type = network.update();
62 if (mesh_address == MESH_DEFAULT_ADDRESS) return type;
63
64#if !defined(MESH_NOMASTER)
65 if (type == NETWORK_REQ_ADDRESS) {
66 doDHCP = 1;
67 }
68
69 if (!getNodeID()) {
70 if ((type == MESH_ADDR_LOOKUP || type == MESH_ID_LOOKUP)) {
71 RF24NetworkHeader* header = (RF24NetworkHeader*)(&network.frame_buffer);
72 header->to_node = header->from_node;
73
74 int16_t returnAddr = 0;
75 if (type == MESH_ADDR_LOOKUP) {
76 returnAddr = getAddress(network.frame_buffer[sizeof(RF24NetworkHeader)]);
77 network.write(*header, &returnAddr, sizeof(returnAddr));
78 }
79 else {
80 int16_t addr = 0;
81 memcpy(&addr, &network.frame_buffer[sizeof(RF24NetworkHeader)], sizeof(addr));
82 returnAddr = getNodeID(addr);
83 network.write(*header, &returnAddr, sizeof(returnAddr));
84 }
85 }
86 else if (type == MESH_ADDR_RELEASE) {
87 uint16_t* fromAddr = (uint16_t*)network.frame_buffer;
88 releaseAddress(*fromAddr);
89 }
90 }
91#endif
92
93 return type;
94}
95
96/*****************************************************/
97
98template<class network_t, class radio_t>
99bool ESBMesh<network_t, radio_t>::write(uint16_t to_node, const void* data, uint8_t msg_type, size_t size)
100{
101 if (mesh_address == MESH_DEFAULT_ADDRESS) return 0;
102
103 RF24NetworkHeader header(to_node, msg_type);
104 return network.write(header, data, size);
105}
106
107/*****************************************************/
108
109template<class network_t, class radio_t>
110bool ESBMesh<network_t, radio_t>::write(const void* data, uint8_t msg_type, size_t size, uint8_t nodeID)
111{
112 if (mesh_address == MESH_DEFAULT_ADDRESS) return 0;
113
114 int16_t toNode = 0;
115 uint32_t lookupStart = millis();
116 uint32_t retryDelay = 5;
117
118 if (nodeID) {
119 while ((toNode = getAddress(nodeID)) < 0) {
120 if (millis() - lookupStart > MESH_WRITE_TIMEOUT || toNode == -2) {
121 return 0;
122 }
123 retryDelay += 10;
124 delay(retryDelay);
125 }
126 }
127 return write(toNode, data, msg_type, size);
128}
129
130/*****************************************************/
131
132template<class network_t, class radio_t>
134{
135 radio.stopListening();
136 radio.setChannel(_channel);
137 radio.startListening();
138}
139
140/*****************************************************/
141
142template<class network_t, class radio_t>
144{
145 network.networkFlags = allow ? network.networkFlags & ~FLAG_NO_POLL : network.networkFlags | FLAG_NO_POLL;
146}
147
148/*****************************************************/
149
150template<class network_t, class radio_t>
152{
153
154 if (!_nodeID) return false;
155 if (mesh_address == MESH_DEFAULT_ADDRESS) return false;
156
157// Connection check via parent node
158#if RF24MESH_CONN_CHECK_TYPE == RF24MESH_CONN_CHECK_PARENT
159 RF24NetworkHeader header;
160 header.to_node = network.parent();
161 header.type = NETWORK_PING;
162 for (uint8_t i = 0; i < MESH_CONNECTION_CHECK_ATTEMPTS; ++i) {
163 if (network.write(header, 0, 0)) {
164 return true;
165 }
166 }
167 return false;
168
169#else // Connection check via master node
170 // getAddress() doesn't use auto-ack; check connectivity multiple times
171 for (uint8_t i = 0; i < MESH_CONNECTION_CHECK_ATTEMPTS; ++i) {
172
173 int16_t result = getAddress(_nodeID);
174 switch (result) {
175 case -2: return false; // Address not found in list or is default
176 case -1: continue; // Write failed or timed out
177 case 0: return false; // This is a master node
178 default:
179 if ((uint16_t)result == mesh_address) { // Successful address lookup if result == RF24Network address
180 return true;
181 }
182 break;
183 }
184 }
185 return false;
186#endif
187}
188
189/*****************************************************/
190
191template<class network_t, class radio_t>
193{ // Master will return and send 00 address for a nodeID with address 0, -1 if not found
194
195 //if (nodeID == _nodeID) return mesh_address;
196 if (!nodeID) return 0;
197 if (mesh_address == MESH_DEFAULT_ADDRESS) return -2;
198
199// Lets say 0 if nodeID 0, -1 if write failed or timed out, -2 if not found in list or address is default,
200#if !defined(MESH_NOMASTER)
201 if (!getNodeID()) { //Master Node
202 for (uint8_t i = 0; i < addrListTop; i++) {
203 if (addrList[i].nodeID == nodeID) {
204 return addrList[i].address;
205 }
206 }
207 return -2;
208 }
209#endif
210
211 RF24NetworkHeader header(00, MESH_ADDR_LOOKUP);
212 if (network.write(header, &nodeID, sizeof(nodeID))) {
213 uint32_t timer = millis();
214 while (network.update() != MESH_ADDR_LOOKUP) {
216 if (millis() - timer > MESH_LOOKUP_TIMEOUT) {
217 return -1;
218 }
219 }
220 int16_t address = 0;
221 memcpy(&address, network.frame_buffer + sizeof(RF24NetworkHeader), sizeof(address));
222 return address;
223 }
224 return -1;
225}
226
227/*****************************************************/
228
229template<class network_t, class radio_t>
231{
232 if (address == MESH_BLANK_ID) return _nodeID;
233 if (address == 0) return 0;
234 if (mesh_address == MESH_DEFAULT_ADDRESS) return -2;
235
236#if !defined(MESH_NOMASTER)
237 if (!mesh_address) { //Master Node
238 for (uint8_t i = 0; i < addrListTop; i++) {
239 if (addrList[i].address == address) {
240 return addrList[i].nodeID;
241 }
242 }
243 return -2;
244 }
245#endif
246
247 RF24NetworkHeader header(00, MESH_ID_LOOKUP);
248 if (network.write(header, &address, sizeof(address))) {
249 uint32_t timer = millis();
250 while (network.update() != MESH_ID_LOOKUP) {
252 if (millis() - timer > MESH_LOOKUP_TIMEOUT) return -1;
253 }
254 int16_t ID = 0;
255 memcpy(&ID, &network.frame_buffer[sizeof(RF24NetworkHeader)], sizeof(ID));
256 return ID;
257 }
258 return -1;
259}
260
261/*****************************************************/
262
263template<class network_t, class radio_t>
264uint8_t ESBMesh<network_t, radio_t>::getLevel(uint16_t address)
265{
266 uint8_t count = 0;
267 while (address) {
268 address >>= 3;
269 count++;
270 }
271 return count;
272}
273
274/*****************************************************/
275
276template<class network_t, class radio_t>
277void ESBMesh<network_t, radio_t>::beginDefault()
278{
279 radio.stopListening();
280 network.begin(MESH_DEFAULT_ADDRESS);
281 mesh_address = MESH_DEFAULT_ADDRESS;
282}
283
284/*****************************************************/
285
286template<class network_t, class radio_t>
288{
289 if (mesh_address == MESH_DEFAULT_ADDRESS) return 0;
290
291 RF24NetworkHeader header(00, MESH_ADDR_RELEASE);
292 if (network.write(header, 0, 0)) {
293 beginDefault();
294 return 1;
295 }
296 return 0;
297}
298
299/*****************************************************/
300
301#ifndef MESH_NOMASTER
302template<class network_t, class radio_t>
304{
305 for (uint8_t i = 0; i < addrListTop; ++i) {
306 if (addrList[i].address == address) {
307 addrList[i].address = 0;
308 return true;
309 }
310 }
311 return false;
312}
313#endif
314
315/*****************************************************/
316
317template<class network_t, class radio_t>
319{
320 if (radio.available()) network.update();
321
322 uint8_t reqCounter = 0;
323 uint8_t totalReqs = 0;
324
325 beginDefault();
326
327 uint32_t start = millis();
328 while (!requestAddress(reqCounter)) {
329 if (millis() - start > timeout) break;
330
331 uint32_t timeoutInternal = 50 + ((totalReqs + 1) * (reqCounter + 1)) * 2;
332 uint32_t startInternal = millis();
333 while (millis() - startInternal < timeoutInternal) {
335 delay(1);
336 }
337 reqCounter++;
338 reqCounter = reqCounter % 4;
339 totalReqs++;
340 totalReqs = totalReqs % 10;
341 }
342 return mesh_address;
343}
344
345/*****************************************************/
346
347template<class network_t, class radio_t>
348bool ESBMesh<network_t, radio_t>::requestAddress(uint8_t level)
349{
350 RF24NetworkHeader header(MESH_MULTICAST_ADDRESS, NETWORK_POLL);
351 //Find another radio, starting with level 0 multicast
352 IF_RF24MESH_DEBUG(printf_P(PSTR("MSH Poll Level %d\n"), level));
353 network.multicast(header, 0, 0, level);
354
355 const uint32_t pollStart = millis();
356#define MESH_MAXPOLLS 4
357 uint16_t contactNode[MESH_MAXPOLLS];
358 uint8_t pollCount = 0;
359
360 while (millis() - pollStart < 55 && pollCount < MESH_MAXPOLLS) {
361#if defined(RF24MESH_DEBUG)
362 bool goodSignal = radio.testRPD();
363#endif
364 if (network.update() == NETWORK_POLL) {
365 uint16_t contact = 0;
366 memcpy(&contact, &network.frame_buffer[0], sizeof(contact));
367
368 // Drop duplicate polls to help prevent duplicate requests
369 bool isDupe = false;
370 for (uint8_t i = 0; i < pollCount; ++i) {
371 if (contact == contactNode[i]) {
372 isDupe = true;
373 break;
374 }
375 }
376 if (!isDupe) {
377 contactNode[pollCount] = contact;
378 ++pollCount;
379 IF_RF24MESH_DEBUG(printf_P(PSTR("MSH Poll %c -64dbm from 0%o \n"), (goodSignal ? '>' : '<'), contact));
380 }
381
382 } // end if
383
385 } // end while
386
387 IF_RF24MESH_DEBUG(printf_P(PSTR("MSH Polls from level %d: %d\n"), level, pollCount));
388
389 if (!pollCount) return 0;
390
391 for (uint8_t i = 0; i < pollCount; i++) {
392
393 bool gotResponse = 0;
394
395 // Request an address via the contact node
396 header.type = NETWORK_REQ_ADDRESS;
397 header.reserved = _nodeID;
398 header.to_node = contactNode[i];
399
400 // Do a direct write (no ack) to the contact node. Include the nodeId and address.
401 network.write(header, 0, 0, contactNode[i]);
402
403 IF_RF24MESH_DEBUG(printf_P(PSTR("MSH Request address from: 0%o\n"), contactNode[i]));
404
405 const uint32_t responseStart = millis();
406
407 while (millis() - responseStart < 225) {
408 if (network.update() == NETWORK_ADDR_RESPONSE) {
409 if (network.frame_buffer[7] == _nodeID) {
410 uint16_t newAddy = 0;
411 memcpy(&newAddy, &network.frame_buffer[sizeof(RF24NetworkHeader)], sizeof(newAddy));
412 uint16_t mask = 0xFFFF;
413 newAddy &= ~(mask << (3 * getLevel(contactNode[i]))); // Get the level of contact node. Multiply by 3 to get the number of bits to shift (3 per digit)
414 if (newAddy == contactNode[i]) { // Then shift the mask by this much, and invert it bitwise. Apply the mask to the newly received
415 gotResponse = 1; // address to evalute whether 'subnet' of the assigned address matches the contact node address.
416 break;
417 }
418 }
419 }
421 }
422
423 if (!gotResponse) {
424 continue;
425 }
426
427 uint16_t newAddress = 0;
428 memcpy(&newAddress, network.frame_buffer + sizeof(RF24NetworkHeader), sizeof(newAddress));
429
430 IF_RF24MESH_DEBUG(printf_P(PSTR("Set address: Current: 0%o New: 0%o\n"), mesh_address, newAddress));
431 mesh_address = newAddress;
432
433 radio.stopListening();
434 network.begin(mesh_address);
435
436 // getNodeID() doesn't use auto-ack; do a double-check to manually retry 1 more time
437 if (getNodeID(mesh_address) != _nodeID) {
438 if (getNodeID(mesh_address) != _nodeID) {
439 beginDefault();
440 continue;
441 }
442 }
443 return 1;
444 } // end for
445
446 return 0;
447}
448
449/*****************************************************/
450
451template<class network_t, class radio_t>
453{
454 _nodeID = nodeID;
455#if !defined(MESH_NOMASTER)
456 if (nodeID == 0 && addrList == nullptr) {
458 if (!addrList) {
459 return;
460 }
461 addrListTop = 0;
462 loadDHCP();
463 }
464#endif
465}
466
467/*****************************************************/
468#if !defined(MESH_NOMASTER)
469
470template<class network_t, class radio_t>
471void ESBMesh<network_t, radio_t>::setStaticAddress(uint8_t nodeID, uint16_t address)
472{
473 setAddress(nodeID, address);
474}
475
476/*****************************************************/
477
478template<class network_t, class radio_t>
479void ESBMesh<network_t, radio_t>::setAddress(uint8_t nodeID, uint16_t address, bool searchBy)
480{
481
482 if (_nodeID) {
483 return;
484 }
485
486 //Look for the node in the list
487 for (uint8_t i = 0; i < addrListTop; i++) {
488 if (searchBy == false) {
489 if (addrList[i].nodeID == nodeID) {
490 addrList[i].address = address;
491 #if defined(__linux) && !defined(__ARDUINO_X86__)
492 saveDHCP();
493 #endif
494 return; //Found & set, complete
495 }
496 }
497 else { // Search by address, set the nodeID
498 if (addrList[i].address == address) {
499 //printf("*** Addr 0%o Found, reassign fr ID %d to ID %d ***\n", addrList[i].address, addrList[i].nodeID, nodeID);
500 addrList[i].nodeID = nodeID;
501 #if defined(__linux) && !defined(__ARDUINO_X86__)
502 saveDHCP();
503 #endif
504 return;
505 }
506 }
507 }
508
509 if (addrListTop > 0 && addrListTop % MESH_MEM_ALLOC_SIZE == 0) {
511 if (!newList) {
512 return;
513 }
514 addrList = newList;
515 }
516 if (!addrList) {
517 return;
518 }
519 addrList[addrListTop].address = address;
520 addrList[addrListTop++].nodeID = nodeID; //Set the value AND increment Top without another line of code
521 #if defined(__linux) && !defined(__ARDUINO_X86__)
522 saveDHCP();
523 #endif
524}
525
526/*****************************************************/
527
528template<class network_t, class radio_t>
530{
531
532 #if defined(__linux) && !defined(__ARDUINO_X86__)
533 std::ifstream infile("dhcplist.txt", std::ifstream::binary);
534 if (!infile) return;
535
536 infile.seekg(0, infile.end);
537 int length = infile.tellg();
538 infile.seekg(0, infile.beg);
539
540 addrListStruct tmpNode;
541
542 for (uint8_t i = 0; i < (length / sizeof(addrListStruct)); i++) {
543 infile.read((char*)&tmpNode, sizeof(addrListStruct));
544 setAddress(tmpNode.nodeID, tmpNode.address);
545 }
546 infile.close();
547 #endif
548}
549
550/*****************************************************/
551
552template<class network_t, class radio_t>
554{
555 #if defined(__linux) && !defined(__ARDUINO_X86__)
556 std::ofstream outfile("dhcplist.txt", std::ofstream::binary | std::ofstream::trunc);
557
558 for (int i = 0; i < addrListTop; i++) {
559 outfile.write((char*)&addrList[i], sizeof(addrListStruct));
560 }
561 outfile.close();
562 #endif // __linux & not X86
563}
564
565/*****************************************************/
566
567template<class network_t, class radio_t>
569{
570 if (doDHCP)
571 doDHCP = false;
572 else
573 return;
574
575 RF24NetworkHeader header;
576 memcpy(&header, network.frame_buffer, sizeof(RF24NetworkHeader));
577
578 uint16_t newAddress;
579
580 // Get the unique id of the requester (ID is in header.reserved)
581 if (!header.reserved || header.type != NETWORK_REQ_ADDRESS) {
582 IF_RF24MESH_DEBUG(printf_P(PSTR("MSH Invalid id or type rcvd\n")));
583 return;
584 }
585
586 uint16_t fwd_by = 0;
587 uint8_t shiftVal = 0;
588 bool extraChild = false;
589
590 if (header.from_node != MESH_DEFAULT_ADDRESS) {
591 fwd_by = header.from_node;
592 uint16_t m = fwd_by;
593 uint8_t count = 0;
594
595 while (m) { //Octal addresses convert nicely to binary in threes. Address 03 = B011 Address 033 = B011011
596 m >>= 3; //Find out how many digits are in the octal address
597 count += 3;
598 }
599 shiftVal = count; //Now we know how many bits to shift when adding a child node 1-5 (B001 to B101) to any address
600 }
601 else {
602 //If request is coming from level 1, add an extra child to the master
603 extraChild = 1;
604 }
605
606 // IF_RF24MESH_DEBUG(printf_P(PSTR("%u: MSH Rcv addr req from_id %d\n"), millis(), header.reserved));
607
608 for (int i = MESH_MAX_CHILDREN + extraChild; i > 0; i--) { // For each of the possible addresses (5 max)
609
610 bool found = false;
611 newAddress = fwd_by | (i << shiftVal);
612
613 if (newAddress == MESH_DEFAULT_ADDRESS) continue;
614
615 for (uint8_t i = 0; i < addrListTop; i++) {
616 IF_RF24MESH_DEBUG_MINIMAL(printf_P(PSTR("ID: %d ADDR: 0%o\n"), addrList[i].nodeID, addrList[i].address));
617 if (addrList[i].address == newAddress && addrList[i].nodeID != header.reserved) {
618 found = true;
619 break;
620 }
621 } // 3 conditions: 1. address in list = assigned to somebody else (bad); 2. address in list = assigned to this nodeID (ok); 3. address not in list (ok)
622
623 if (!found) {
624 header.type = NETWORK_ADDR_RESPONSE;
625 header.to_node = header.from_node;
626 //This is a routed request to 00
627
628 setAddress(header.reserved, newAddress);
629 // without this delay, address renewal fails for children with slower execution speed
630 #if defined(SLOW_ADDR_POLL_RESPONSE)
631 delay(SLOW_ADDR_POLL_RESPONSE);
632 #endif // defined (SLOW_ADDR_POLL_RESPONSE)
633
634 if (header.from_node != MESH_DEFAULT_ADDRESS) { //Is NOT node 01 to 05
635 //delay(2);
636 if (!network.write(header, &newAddress, sizeof(newAddress))) {
637 network.write(header, &newAddress, sizeof(newAddress));
638 }
639 }
640 else {
641 //delay(2);
642 network.write(header, &newAddress, sizeof(newAddress), header.to_node);
643 }
644
645 IF_RF24MESH_DEBUG(printf_P(PSTR("Sent to 0%o phys: 0%o new: 0%o id: %d\n"), header.to_node, MESH_DEFAULT_ADDRESS, newAddress, header.reserved));
646 break;
647 }
648 else {
649 IF_RF24MESH_DEBUG(printf_P(PSTR("not allocated\n")));
650 }
651 } // end for
652}
653
654/*****************************************************/
655
656#endif // !MESH_NOMASTER
657
658template<class network_t, class radio_t>
659void ESBMesh<network_t, radio_t>::setCallback(void (*meshCallback)(void))
660{
661
662 this->meshCallback = meshCallback;
663}
664
665/*****************************************************/
666
667// ensure the compiler is aware of the possible datatype for the template class
668template class ESBMesh<ESBNetwork<RF24>, RF24>;
669#if defined(RF24NETWORK_CCM)
670template class ESBMesh<ESBNetwork<RF24CCM>, RF24CCM>;
671#endif
672#if defined(ARDUINO_ARCH_NRF52) || defined(ARDUINO_ARCH_NRF52840) || defined(ARDUINO_NRF54L15)
673template class ESBMesh<ESBNetwork<nrf_to_nrf>, nrf_to_nrf>;
674#endif
#define MESH_MAXPOLLS
#define MESH_ADDR_LOOKUP
Definition RF24Mesh.h:25
#define MESH_ID_LOOKUP
Definition RF24Mesh.h:27
#define MESH_CALLBACK
Definition RF24Mesh.h:260
#define MESH_ADDR_RELEASE
Definition RF24Mesh.h:26
#define MESH_BLANK_ID
Definition RF24Mesh.h:29
#define MESH_MULTICAST_ADDRESS
#define IF_RF24MESH_DEBUG(x)
#define MESH_MAX_CHILDREN
Set 1 to 4 (Default: 4) Restricts the maximum children per node.
#define MESH_LOOKUP_TIMEOUT
How long to wait in ms for a response during individual address lookups.
#define IF_RF24MESH_DEBUG_MINIMAL(x)
#define MESH_DEFAULT_ADDRESS
#define MESH_CONNECTION_CHECK_ATTEMPTS
Number of attempts to verify a connection.
#define MESH_MEM_ALLOC_SIZE
master node memory allocation
#define MESH_WRITE_TIMEOUT
How long RF24Mesh::write() retries address lookups before timing out. Allows multiple attempts.
int16_t getNodeID(uint16_t address=MESH_BLANK_ID)
Definition RF24Mesh.cpp:230
void setStaticAddress(uint8_t nodeID, uint16_t address)
Definition RF24Mesh.cpp:471
void loadDHCP()
Definition RF24Mesh.cpp:529
uint16_t renewAddress(uint32_t timeout=MESH_RENEWAL_TIMEOUT)
Reconnect to the mesh and renew the current RF24Network address.
Definition RF24Mesh.cpp:318
void setChild(bool allow)
Definition RF24Mesh.cpp:143
uint8_t _nodeID
Definition RF24Mesh.h:321
bool checkConnection()
Definition RF24Mesh.cpp:151
bool begin(uint8_t channel=MESH_DEFAULT_CHANNEL, rf24_datarate_e data_rate=RF24_1MBPS, uint32_t timeout=MESH_RENEWAL_TIMEOUT)
Definition RF24Mesh.cpp:30
void DHCP()
Definition RF24Mesh.cpp:568
bool releaseAddress()
Definition RF24Mesh.cpp:287
void saveDHCP()
Definition RF24Mesh.cpp:553
void setCallback(void(*meshCallback)(void))
Definition RF24Mesh.cpp:659
uint8_t update()
Definition RF24Mesh.cpp:59
uint8_t addrListTop
The number of entries in the addrListStruct of assigned addresses.
Definition RF24Mesh.h:352
ESBMesh(radio_t &_radio, network_t &_network)
Definition RF24Mesh.cpp:17
addrListStruct * addrList
A array of addrListStruct elements for assigned addresses.
Definition RF24Mesh.h:350
void setNodeID(uint8_t nodeID)
Definition RF24Mesh.cpp:452
bool write(const void *data, uint8_t msg_type, size_t size, uint8_t nodeID=0)
Definition RF24Mesh.cpp:110
void setChannel(uint8_t _channel)
Definition RF24Mesh.cpp:133
void setAddress(uint8_t nodeID, uint16_t address, bool searchBy=false)
Definition RF24Mesh.cpp:479
uint16_t mesh_address
Definition RF24Mesh.h:217
int16_t getAddress(uint8_t nodeID)
Convert a nodeID into an RF24Network address.
Definition RF24Mesh.cpp:192
A struct for storing a nodeID and an address in a single element of the ESBMesh::addrList array.
Definition RF24Mesh.h:331