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