RF24Gateway - TCP/IP over RF24Network v2.1.1
TMRh20 - Pushing the practical limits of RF24 modules
Loading...
Searching...
No Matches
RF24Gateway.cpp
1/**
2 * @file RF24Gateway.cpp
3 *
4 * Class definitions for RF24Gateway
5 */
6
7#include "RF24Gateway.h"
8#include "RF24Mesh/RF24Mesh_config.h"
9
10/***************************************************************************************/
11
12template<class mesh_t, class network_t, class radio_t>
13ESBGateway<mesh_t, network_t, radio_t>::ESBGateway(radio_t& _radio, network_t& _network, mesh_t& _mesh) : radio(_radio), network(_network), mesh(_mesh)
14{
15 gotInterrupt = false;
16}
17
18/***************************************************************************************/
19
20template<class mesh_t, class network_t, class radio_t>
21void ESBGateway<mesh_t, network_t, radio_t>::begin(uint8_t nodeID, uint8_t _channel, rf24_datarate_e data_rate)
22{
23 mesh_enabled = true;
24 begin(true, mesh_enabled, 0, nodeID, data_rate, _channel);
25}
26
27/***************************************************************************************/
28
29template<class mesh_t, class network_t, class radio_t>
30void ESBGateway<mesh_t, network_t, radio_t>::begin(uint16_t address, uint8_t _channel, rf24_datarate_e data_rate, bool meshEnable, uint8_t nodeID)
31{
32 begin(0, mesh_enabled, address, nodeID, data_rate, _channel);
33}
34
35/***************************************************************************************/
36
37template<class mesh_t, class network_t, class radio_t>
38bool ESBGateway<mesh_t, network_t, radio_t>::begin(bool configTUN, bool meshEnable, uint16_t address, uint8_t mesh_nodeID, rf24_datarate_e data_rate, uint8_t _channel)
39{
40#if (RF24GATEWAY_DEBUG_LEVEL >= 1)
41 printf("GW Begin\n");
42 printf("Config Device address 0%o nodeID %d\n", address, mesh_nodeID);
43#endif
44 config_TUN = configTUN;
45
46 /// FIX
47
48 channel = _channel; // 97;
49
50 dataRate = data_rate;
51
52 configDevice(address);
53 mesh_enabled = meshEnable;
54 thisNodeID = mesh_nodeID;
55 thisNodeAddress = address;
56
57 if (meshEnable) {
58 // GW radio channel setting takes precedence over mesh_default_channel
59 if (channel == 97 && MESH_DEFAULT_CHANNEL != 97) {
60 channel = MESH_DEFAULT_CHANNEL;
61 }
62
63 if (!thisNodeAddress && !mesh_nodeID) {
64 mesh.setNodeID(0);
65 }
66 else {
67 if (!mesh_nodeID) {
68 mesh_nodeID = 253;
69 }
70 mesh.setNodeID(mesh_nodeID); // Try not to conflict with any low-numbered node-ids
71 }
72 mesh.begin(channel, data_rate);
73 thisNodeAddress = mesh.mesh_address;
74 }
75 else {
76 radio.begin();
77 delay(5);
78 const uint16_t this_node = address;
79 radio.setDataRate(dataRate);
80 radio.setChannel(channel);
81
82 network.begin(/*node address*/ this_node);
83 thisNodeAddress = this_node;
84 }
85 network.multicastRelay = 1;
86
87 //#if (RF24GATEWAY_DEBUG_LEVEL >= 1)
88 radio.printDetails();
89 //#endif
90
91 setupSocket();
92 loadRoutingTable();
93
94 return true;
95}
96
97/***************************************************************************************/
98
99template<class mesh_t, class network_t, class radio_t>
101{
102 std::ifstream infile("routing.txt", std::ifstream::in);
103 if (!infile) {
104 return;
105 }
106
107 std::string str;
108 std::string ip, mask, gw;
109 uint16_t count = 0;
110 std::string space = " ";
111
112 while (std::getline(infile, str)) {
113 size_t startLen = 0;
114 size_t subLen = str.find(space);
115 if (subLen != std::string::npos) {
116 ip = str.substr(0, subLen);
117 }
118 else {
119 continue;
120 }
121 startLen = subLen + 1;
122 subLen = str.find(space, startLen);
123 if (subLen != std::string::npos) {
124 subLen -= (startLen);
125 mask = str.substr(startLen, subLen);
126 }
127 else {
128 continue;
129 }
130 startLen = startLen + subLen + 1;
131 subLen = str.length() - (startLen);
132 gw = str.substr(startLen, subLen);
133
134 routingStruct[count].ip.s_addr = ntohl(inet_network(ip.c_str()));
135 routingStruct[count].mask.s_addr = ntohl(inet_network(mask.c_str()));
136 routingStruct[count].gw.s_addr = ntohl(inet_network(gw.c_str()));
137
138 count++;
139 if (count >= 256) {
140 break;
141 }
142 }
143 routingTableSize = count;
144
145 // for(int i=0; i<count; i++){
146 // std::cout << inet_ntoa(routingStruct[i].ip) << ";" << inet_ntoa(routingStruct[i].mask) << ";" << inet_ntoa(routingStruct[i].gw) << std::endl;
147 // }
148}
149
150/***************************************************************************************/
151
152template<class mesh_t, class network_t, class radio_t>
154{
155 return mesh_enabled;
156}
157
158/***************************************************************************************/
159
160template<class mesh_t, class network_t, class radio_t>
162{
163 std::string tunTapDevice = "tun_nrf24";
164 strcpy(tunName, tunTapDevice.c_str());
165
166 int flags;
167 if (config_TUN) {
168 flags = IFF_TUN | IFF_NO_PI | IFF_MULTI_QUEUE;
169 }
170 else {
171 flags = IFF_TAP | IFF_NO_PI | IFF_MULTI_QUEUE;
172 }
173 tunFd = allocateTunDevice(tunName, flags, address);
174#if RF24GATEWAY_DEBUG_LEVEL >= 1
175 if (tunFd >= 0) {
176 std::cout << "RF24Gw: Successfully attached to tun/tap device " << tunTapDevice << std::endl;
177 }
178 else {
179 std::cerr << "RF24Gw: Error allocating tun/tap interface: " << tunFd << std::endl;
180 exit(1);
181 }
182#endif
183 return tunFd;
184}
185
186/***************************************************************************************/
187
188template<class mesh_t, class network_t, class radio_t>
189int ESBGateway<mesh_t, network_t, radio_t>::allocateTunDevice(char* dev, int flags, uint16_t address)
190{
191 struct ifreq ifr;
192 int fd;
193
194 // open the device
195 if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
196 return fd;
197 }
198
199 memset(&ifr, 0, sizeof(ifr));
200
201 ifr.ifr_flags = flags; // IFF_TUN or IFF_TAP, plus maybe IFF_NO_PI
202
203 if (*dev) {
204 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
205 }
206
207 // Create device
208 if (ioctl(fd, TUNSETIFF, (void*)&ifr) < 0) {
209 // close(fd);
210 //#if (RF24GATEWAY_DEBUG_LEVEL >= 1)
211 std::cerr << "RF24Gw: Error: enabling TUNSETIFF" << std::endl;
212 uint32_t UID = getuid();
213 if (UID) {
214 std::cout << "Not running as root, preconfigure the interface as follows" << std::endl;
215 std::cout << "sudo ip tuntap add dev tun_nrf24 mode tun user " << getlogin() << " multi_queue" << std::endl;
216 std::cout << "sudo ifconfig tun_nrf24 10.10.2.2/24" << std::endl;
217 }
218 return -1;
219 //#endif
220 }
221
222 // Make persistent
223 if (ioctl(fd, TUNSETPERSIST, 1) < 0) {
224#if (RF24GATEWAY_DEBUG_LEVEL >= 1)
225 std::cerr << "RF24Gw: Error: enabling TUNSETPERSIST" << std::endl;
226#endif
227 return -1;
228 }
229
230 if (!config_TUN) {
231 struct sockaddr sap;
232 sap.sa_family = ARPHRD_ETHER;
233 ((char*)sap.sa_data)[4] = address;
234 ((char*)sap.sa_data)[5] = address >> 8;
235 ((char*)sap.sa_data)[0] = 0x52;
236 ((char*)sap.sa_data)[1] = 0x46;
237 ((char*)sap.sa_data)[2] = 0x32;
238 ((char*)sap.sa_data)[3] = 0x34;
239
240 // printf("Address 0%o first %u last %u\n",address,sap.sa_data[0],sap.sa_data[1]);
241 memcpy((char*)&ifr.ifr_hwaddr, (char*)&sap, sizeof(struct sockaddr));
242
243 if (ioctl(fd, SIOCSIFHWADDR, &ifr) < 0) {
244#if RF24GATEWAY_DEBUG_LEVEL >= 1
245 fprintf(stderr, "RF24Gw: Failed to set MAC address\n");
246#endif
247 }
248 }
249
250 strcpy(dev, ifr.ifr_name);
251 return fd;
252}
253
254/***************************************************************************************/
255
256template<class mesh_t, class network_t, class radio_t>
258{
259 struct ifreq ifr;
260 struct sockaddr_in sin;
261 int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
262 if (sockfd == -1) {
263 fprintf(stderr, "Could not get socket.\n");
264 return -1;
265 }
266
267 sin.sin_family = AF_INET;
268 // inet_aton(ip_addr,&sin.sin_addr.s_addr);
269 inet_aton(ip_addr, &sin.sin_addr);
270 strncpy(ifr.ifr_name, tunName, IFNAMSIZ);
271
272 if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
273 fprintf(stderr, "ifdown: shutdown ");
274 perror(ifr.ifr_name);
275 return -1;
276 }
277
278#ifdef ifr_flags
279 #define IRFFLAGS ifr_flags
280#else /* Present on kFreeBSD */
281 #define IRFFLAGS ifr_flagshigh
282#endif
283
284 if (!(ifr.IRFFLAGS & IFF_UP)) {
285 // fprintf(stdout, "Device is currently down..setting up.-- %u\n", ifr.IRFFLAGS);
286 ifr.IRFFLAGS |= IFF_UP;
287 if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
288 fprintf(stderr, "ifup: failed ");
289 perror(ifr.ifr_name);
290 return -1;
291 }
292 }
293
294 memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
295
296 // Set interface address
297 if (ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) {
298 fprintf(stderr, "Cannot set IP address. ");
299 perror(ifr.ifr_name);
300 return -1;
301 }
302
303 inet_aton(mask, &sin.sin_addr);
304 memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
305
306 if (ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) {
307 fprintf(stderr, "Cannot define subnet mask for this device");
308 perror(ifr.ifr_name);
309 return -1;
310 }
311
312#undef IRFFLAGS
313 return 0;
314}
315
316/***************************************************************************************/
317
318template<class mesh_t, class network_t, class radio_t>
320{
321 // No longer required
322}
323
324/***************************************************************************************/
325
326template<class mesh_t, class network_t, class radio_t>
328{
329
330 if (interrupts) {
331 gotInterrupt = true;
332 }
333 else {
334 handleRadioIn();
335 handleTX();
336 handleRX();
337 handleRadioOut();
338 }
339}
340
341/***************************************************************************************/
342
343template<class mesh_t, class network_t, class radio_t>
345{
346
347 if (gotInterrupt) {
348 gotInterrupt = false;
349 handleRadioIn();
350 handleTX();
351 }
352 else if (radio.rxFifoFull()) {
353 fifoCleared = true;
354 handleRadioIn();
355 handleRadioOut();
356 }
357 else {
358 delay(waitDelay);
359 }
360 handleRX();
361 handleRadioOut();
362}
363
364/***************************************************************************************/
365
366template<class mesh_t, class network_t, class radio_t>
368{
369 if (mesh_enabled) {
370 while (mesh.update()) {
371 if (!thisNodeAddress) {
372 mesh.DHCP();
373 }
374 }
375 }
376 else {
377 while (network.update()) {
378 }
379 }
380
381 RF24NetworkFrame f;
382 while (network.external_queue.size() > 0) {
383 f = network.external_queue.front();
384
385 msgStruct msg;
386
387 unsigned int bytesRead = f.message_size;
388
389 if (bytesRead > 0) {
390 memcpy(&msg.message, &f.message_buffer, bytesRead);
391 msg.size = bytesRead;
392
393#if (RF24GATEWAY_DEBUG_LEVEL >= 1)
394 std::cout << "Radio: Received " << bytesRead << " bytes ... " << std::endl;
395#endif
396#if (RF24GATEWAY_DEBUG_LEVEL >= 3)
397 // printPayload(msg.getPayloadStr(),"radio RX");
398 std::cout << "TunRead: " << std::endl;
399 for (size_t i = 0; i < msg.size; i++) {
400 // std::cout << std::hex << buffer[i];
401 printf(":%0x :", msg.message[i]);
402 }
403 std::cout << std::endl;
404
405#endif
406
407 rxQueue.push(msg);
408 }
409 else {
410 // std::cerr << "Radio: Error reading data from radio. Read '" << bytesRead << "' Bytes." << std::endl;
411 }
412 network.external_queue.pop();
413 }
414}
415
416/***************************************************************************************/
417
418template<class mesh_t, class network_t, class radio_t>
419struct in_addr ESBGateway<mesh_t, network_t, radio_t>::getLocalIP()
420{
421 struct ifaddrs *ifap, *ifa;
422 int family, s, n;
423 char host[NI_MAXHOST];
424 struct in_addr myNet;
425 memset(&myNet, 0, sizeof(myNet));
426
427 getifaddrs(&ifap);
428 for (ifa = ifap, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
429 if (std::string("tun_nrf24").compare(ifa->ifa_name) != 0 || ifa->ifa_addr == NULL) {
430 if (ifa->ifa_next == NULL) {
431 break;
432 }
433 else {
434 continue;
435 }
436 }
437
438 family = ifa->ifa_addr->sa_family;
439
440 // This is an IPv4 interface, get the IP
441 if (family == AF_INET) {
442 s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
443 if (s == 0) {
444 myNet.s_addr = ntohl(inet_network(host));
445 freeifaddrs(ifap);
446 return myNet;
447 }
448 }
449 }
450 freeifaddrs(ifap);
451 return myNet;
452}
453
454/***************************************************************************************/
455
456template<class mesh_t, class network_t, class radio_t>
458{
459 bool ok = 0;
460
461 while (!txQueue.empty() && network.external_queue.size() == 0) {
462
463 msgStruct* msgTx = &txQueue.front();
464
465#if (RF24GATEWAY_DEBUG_LEVEL >= 1)
466 std::cout << "Radio: Sending " << msgTx->size << " bytes ... ";
467 std::cout << std::endl;
468#endif
469#if (RF24GATEWAY_DEBUG_LEVEL >= 3)
470
471 // PrintDebug == 1 does not have an endline.
472 // printPayload(msg.getPayloadStr(),"radio TX");
473#endif
474
475 std::uint8_t* tmp = msgTx->message;
476
477 if (!config_TUN) { // TAP can use RF24Mesh for address assignment, but will still use ARP for address resolution
478
479 uint32_t RF24_STR = 0x34324652; // Identifies the mac as an RF24 mac
480 uint32_t ARP_BC = 0xFFFFFFFF; // Broadcast address
481 struct macStruct
482 {
483 uint32_t rf24_Verification;
484 uint16_t rf24_Addr;
485 };
486
487 macStruct macData;
488 memcpy(&macData.rf24_Addr, tmp + 4, 2);
489 memcpy(&macData.rf24_Verification, tmp, 4);
490
491 if (macData.rf24_Verification == RF24_STR) {
492 const uint16_t other_node = macData.rf24_Addr;
493 RF24NetworkHeader header(/*to node*/ other_node, EXTERNAL_DATA_TYPE);
494 ok = network.write(header, &msgTx->message, msgTx->size);
495 }
496 else if (macData.rf24_Verification == ARP_BC) {
497 RF24NetworkHeader header(/*to node*/ 00, EXTERNAL_DATA_TYPE); // Set to master node, will be modified by RF24Network if multi-casting
498 if (msgTx->size <= 42) {
499 if (thisNodeAddress == 00) { // Master Node
500
501 uint32_t arp_timeout = millis();
502
503 ok = network.multicast(header, &msgTx->message, msgTx->size, 1); // Send to Level 1
504 while (millis() - arp_timeout < 5) {
505 network.update();
506 }
507 network.multicast(header, &msgTx->message, msgTx->size, 1); // Send to Level 1
508 arp_timeout = millis();
509 while (millis() - arp_timeout < 15) {
510 network.update();
511 }
512 network.multicast(header, &msgTx->message, msgTx->size, 1); // Send to Level 1
513 }
514 else {
515 ok = network.write(header, &msgTx->message, msgTx->size);
516 }
517 }
518 }
519 }
520 else { // TUN always needs to use RF24Mesh for address assignment AND resolution
521
522 uint8_t lastOctet = tmp[19];
523 int16_t meshAddr;
524
525 RF24NetworkHeader header(00, EXTERNAL_DATA_TYPE);
526 bool sendData = false;
527
528 struct in_addr ipDestination;
529 memcpy(&ipDestination.s_addr, &tmp[16], 4);
530
531 if ((getLocalIP().s_addr & 0x00FFFFFF) == (ipDestination.s_addr & 0x00FFFFFF)) { // Is inside the RF24Mesh network
532 if ((meshAddr = mesh.getAddress(lastOctet)) > 0) {
533 header.to_node = meshAddr;
534 sendData = true;
535 }
536 else {
537 if (thisNodeID > 0) { // If IP is in mesh range, address lookup fails, and this is not master,
538 sendData = true; // send to 00 anyway in case destination is master, or the lookup just failed
539 }
540 // printf("Could not find matching mesh nodeID for IP ending in %d\n",lastOctet);
541 }
542 }
543 else if (thisNodeID > 0) { // If not master, send to master for routing etc. if target not within mesh
544 sendData = true;
545 }
546 else if (routingTableSize > 0) {
547 for (int i = 0; i < routingTableSize; i++) {
548 struct in_addr network;
549 network.s_addr = routingStruct[i].ip.s_addr & routingStruct[i].mask.s_addr;
550 struct in_addr destNet;
551 destNet.s_addr = ipDestination.s_addr & routingStruct[i].mask.s_addr;
552 // printf("network %s destNet: %s\n",inet_ntoa(network),inet_ntoa(destNet));
553 if (destNet.s_addr == network.s_addr) {
554 uint8_t toNode = routingStruct[i].gw.s_addr >> 24;
555 int16_t netAddr = 0;
556 if ((netAddr = mesh.getAddress(toNode)) > 0) {
557 header.to_node = netAddr;
558 sendData = true;
559 break;
560 }
561 }
562 }
563 }
564
565 if (sendData) {
566 ok = network.write(header, msgTx->message, msgTx->size);
567 // std::cout << "SendData " << header.to_node << std::endl;
568 }
569 }
570 // delay( rf24_min(msgTx->size/48,20));
571 txQueue.pop();
572
573 // printf("Addr: 0%#x\n",macData.rf24_Addr);
574 // printf("Verif: 0%#x\n",macData.rf24_Verification);
575 if (ok) {
576 // std::cout << "ok." << std::endl;
577 }
578 else {
579 // std::cerr << "failed." << std::endl;
580 }
581
582 } // End Tx
583}
584
585/***************************************************************************************/
586
587template<class mesh_t, class network_t, class radio_t>
589{
590 fd_set socketSet;
591 struct timeval selectTimeout;
592 uint8_t buffer[MAX_PAYLOAD_SIZE];
593 int nread;
594
595 FD_ZERO(&socketSet);
596 FD_SET(tunFd, &socketSet);
597
598 selectTimeout.tv_sec = 0;
599 selectTimeout.tv_usec = waitDelay * 1000;
600
601 if (select(tunFd + 1, &socketSet, NULL, NULL, &selectTimeout) != 0) {
602 if (FD_ISSET(tunFd, &socketSet)) {
603 if ((nread = read(tunFd, buffer, MAX_PAYLOAD_SIZE)) >= 0) {
604
605#if (RF24GATEWAY_DEBUG_LEVEL >= 1)
606 std::cout << "Tun: Successfully read " << nread << " bytes from tun device" << std::endl;
607#endif
608#if (RF24GATEWAY_DEBUG_LEVEL >= 3)
609 std::cout << "TunRead: " << std::endl;
610 for (int i = 0; i < nread; i++)
611 {
612 printf(":%0x :", buffer[i]);
613 }
614 std::cout << std::endl;
615#endif
616 msgStruct msg;
617 memcpy(&msg.message, &buffer, nread);
618 msg.size = nread;
619 if (txQueue.size() < 10) {
620 txQueue.push(msg);
621 }
622 else {
623 droppedIncoming++;
624 }
625 }
626 else {
627#if (RF24GATEWAY_DEBUG_LEVEL >= 1)
628 std::cerr << "Tun: Error while reading from tun/tap interface." << std::endl;
629#endif
630 }
631 }
632 }
633}
634
635/***************************************************************************************/
636
637template<class mesh_t, class network_t, class radio_t>
639{
640
641 if (rxQueue.size() < 1)
642 {
643 return;
644 }
645 msgStruct* msg = &rxQueue.front();
646
647 if (msg->size > MAX_PAYLOAD_SIZE)
648 {
649 // printf("*****WTF OVER *****");
650 rxQueue.pop();
651 return;
652 }
653
654 if (msg->size > 0)
655 {
656
657 size_t writtenBytes = write(tunFd, &msg->message, msg->size);
658 if (writtenBytes != msg->size)
659 {
660// std::cerr << "Tun: Less bytes written to tun/tap device then requested." << std::endl;
661#if RF24GATEWAY_DEBUG_LEVEL >= 1
662 printf("Tun: Less bytes written %d to tun/tap device then requested %d.", writtenBytes, msg->size);
663#endif
664 }
665 else
666 {
667#if (RF24GATEWAY_DEBUG_LEVEL >= 1)
668 std::cout << "Tun: Successfully wrote " << writtenBytes << " bytes to tun device" << std::endl;
669#endif
670 }
671
672#if (RF24GATEWAY_DEBUG_LEVEL >= 3)
673 // printPayload(msg.message,"tun write");
674 std::cout << "TunRead: " << std::endl;
675 for (size_t i = 0; i < msg->size; i++) {
676 // printf(":%0x :",msg->message[i]);
677 }
678 std::cout << std::endl;
679#endif
680 }
681
682 rxQueue.pop();
683}
684
685/***************************************************************************************
686
687template<class mesh_t, class network_t, class radio_t>
688void ESBGateway<mesh_t, network_t, radio_t>::printPayload(std::string buffer, std::string debugMsg)
689{
690}
691*/
692/***************************************************************************************
693
694template<class mesh_t, class network_t, class radio_t>
695void ESBGateway<mesh_t, network_t, radio_t>::printPayload(char* buffer, int nread, std::string debugMsg)
696{
697}
698*/
699/***************************************************************************************/
700
701template<class mesh_t, class network_t, class radio_t>
703{
704 int ret;
705 const char* myAddr = "127.0.0.1";
706
707 addr.sin_family = AF_INET;
708 ret = inet_aton(myAddr, &addr.sin_addr);
709 if (ret == 0) {
710 perror("inet_aton");
711 exit(1);
712 }
713 addr.sin_port = htons(32001);
714 // buf = "Hello UDP";
715 s = socket(PF_INET, SOCK_DGRAM, 0);
716 if (s == -1) {
717 perror("socket");
718 exit(1);
719 }
720}
721
722/***************************************************************************************/
723
724template<class mesh_t, class network_t, class radio_t>
725void ESBGateway<mesh_t, network_t, radio_t>::sendUDP(uint8_t nodeID, RF24NetworkFrame frame)
726{
727
728 uint8_t buffer[MAX_PAYLOAD_SIZE + 11];
729
730 memcpy(&buffer[0], &nodeID, 1);
731 memcpy(&buffer[1], &frame.header, 8);
732 memcpy(&buffer[9], &frame.message_size, 2);
733 memcpy(&buffer[11], &frame.message_buffer, frame.message_size);
734
735 int ret = sendto(s, &buffer, frame.message_size + 11, 0, (struct sockaddr*)&addr, sizeof(addr));
736 if (ret == -1)
737 {
738 perror("sendto");
739 exit(1);
740 }
741}
742
743// ensure the compiler is aware of the possible datatype for the template class
744template class ESBGateway<ESBMesh<ESBNetwork<RF24>, RF24>, ESBNetwork<RF24>, RF24>;
bool meshEnabled()
int setIP(char *ip_addr, char *mask)
void interrupts(bool enable=1)
void poll(uint32_t waitDelay=3)
ESBGateway(radio_t &_radio, network_t &_network, mesh_t &_mesh)
void begin(uint8_t nodeID=0, uint8_t channel=97, rf24_datarate_e data_rate=RF24_1MBPS)
void update(bool interrupts=0)
void sendUDP(uint8_t nodeID, RF24NetworkFrame frame)