RF24Gateway - TCP/IP over RF24Network v2.1.2
TMRh20 - Pushing the practical limits of RF24 modules
Loading...
Searching...
No Matches
RF24Gateway.h
1
2
3#ifndef __RF24GATEWAY_H__
4#define __RF24GATEWAY_H__
5
6/**
7 * @file RF24Gateway.h
8 *
9 * Class declaration for RF24Gateway
10 */
11#include "net/if_arp.h"
12#include <cstdlib>
13#include <cstdint>
14#include <iostream>
15#include <string>
16#include <sys/socket.h>
17#include <netinet/in.h>
18#include <linux/if.h>
19#include <linux/if_tun.h>
20#include <ifaddrs.h>
21#include <arpa/inet.h>
22#include <fcntl.h>
23#include <unistd.h>
24#include <sys/ioctl.h>
25#include <netdb.h>
26#include <fstream>
27
28#include <RF24/RF24.h>
29#include <RF24Network/RF24Network.h>
30#include <RF24Mesh/RF24Mesh.h>
31
32#ifndef IFF_MULTI_QUEUE
33 #define IFF_MULTI_QUEUE 0x0100
34#endif
35
36#ifndef RF24GATEWAY_DEBUG_LEVEL
37 #define RF24GATEWAY_DEBUG_LEVEL 0
38#endif // RF24GATEWAY_DEBUG_LEVEL
39
40#define BACKLOG 10 /* Passed to listen() */
41
42class RF24;
43
44template<class radio_t>
46
47template<class network_t, class radio_t>
48class ESBMesh;
49
50/**
51 * @tparam mesh_t The `mesh` object's type. Defaults to `RF24Mesh` for legacy behavior.
52 * This new abstraction is really meant for using the nRF52840 SoC as a drop-in replacement
53 * for the nRF24L01 radio. For more detail, see the
54 * [nrf_to_nrf Arduino library](https://github.com/TMRh20/nrf_to_nrf).
55 * @tparam network_t The `network` object's type. Defaults to `RF24Network` for legacy behavior.
56 * This new abstraction is really meant for using the nRF52840 SoC as a drop-in replacement
57 * for the nRF24L01 radio. For more detail, see the
58 * [nrf_to_nrf Arduino library](https://github.com/TMRh20/nrf_to_nrf).
59 * @tparam radio_t The `radio` object's type. Defaults to `RF24` for legacy behavior.
60 * This new abstraction is really meant for using the nRF52840 SoC as a drop-in replacement
61 * for the nRF24L01 radio. For more detail, see the
62 * [nrf_to_nrf Arduino library](https://github.com/TMRh20/nrf_to_nrf).
63 */
64template<class mesh_t = ESBMesh<ESBNetwork<RF24>, RF24>, class network_t = ESBNetwork<RF24>, class radio_t = RF24>
66{
67
68 /**
69 * @name RF24Gateway (RPi/Linux)
70 *
71 * RF24Gateway library for devices with an IP stack
72 */
73 /**@{*/
74
75public:
76 /**
77 * ESBGateway constructor.
78 * @code
79 * RF24 radio(7,8);
80 * RF24Network network(radio);
81 * RF24Mesh mesh(radio,network);
82 * RF24Gateway gateway(radio,network,mesh);
83 * @endcode
84 */
85 ESBGateway(radio_t& _radio, network_t& _network, mesh_t& _mesh);
86
87 /**
88 * Begin function for use with RF24Mesh (TUN interface)
89 *
90 * @param nodeID The RF24Mesh nodeID to use
91 * @param channel The radio channel to use (1-127)
92 * @param data_rate The RF24 datarate to use (RF24_250KBPS, RF24_1MBPS, RF24_2MBPS)
93 *
94 * @code gw.begin(); //Start the gateway using RF24Mesh, with nodeID 0 (Master) @endcode
95 * @code uint8_t nodeID; gw.begin(nodeID); //Start the gateway using RF24Mesh, with nodeID 1 (Child node) @endcode
96 */
97 void begin(uint8_t nodeID = 0, uint8_t channel = 97, rf24_datarate_e data_rate = RF24_1MBPS);
98
99 /**
100 * Begin function for use with a TAP (Ethernet) interface. RF24Mesh can be used for address assignment, but
101 * ARP will be used to perform the lookups.
102 *
103 * @param address The RF24Network address to use
104 * @param channel The radio channel (0-127) to use
105 * @param data_rate The RF24 datarate to use (RF24_250KBPS, RF24_1MBPS, RF24_2MBPS)
106 * @param meshEnable Whether to use RF24Mesh for address assignment
107 * @param nodeID The RF24Mesh nodeID to use **if** meshEnable has been set to true
108 *
109 * @code uint16_t address=00; gw.begin(address); //Start the gateway without using RF24Mesh, with RF24Network address 00 (Master) @endcode
110 * @code uint16_t address=01; gw.begin(address); //Start the gateway without using RF24Mesh, with RF24Network address 01 (Child) @endcode
111 */
112 void begin(uint16_t address, uint8_t channel = 97, rf24_datarate_e data_rate = RF24_1MBPS, bool meshEnable = 0, uint8_t nodeID = 0);
113
114 /**
115 * Once the Gateway has been started via begin() , call setIP to configure the IP and
116 * subnet mask.
117 *
118 * @param ip_addr A character array containing the numeric IP address ie: 192.168.1.1
119 * @param mask A character array containing the subnet mask ie: 255.255.255.0
120 * @return -1 if failed, 0 on success
121 */
122 int setIP(char* ip_addr, char* mask);
123
124 /**
125 * Calling update() keeps the network and mesh layers active and processing data. This needs to be called regularly.
126 * @code
127 * gw.update();
128 * if(network.available()){
129 * ...do something
130 * }
131 * @endcode
132 * @param interrupts Set true if called from an interrupt handler & call poll() from the main loop or a thread.
133 */
134 void update(bool interrupts = 0);
135
136 /**
137 * gw.poll(); needs to be called to handle incoming data from the network interface.
138 * The function will perform a delayed wait of max 3ms unless otherwise specified.
139 * @param waitDelay How long in milliseconds this function will wait for incoming data.
140 */
141 void poll(uint32_t waitDelay = 3);
142
143 /**
144 * When using interrupts (gwNodeInt, ncursesInt examples) users need to call
145 * this function to disable interrupts before accessing the radio and again to
146 * re-enable interrupts when complete
147 * @param enable 0 to disable interrupts and access the radio, 1 to re-enable
148 */
149 void interrupts(bool enable = 1);
150
151 /**@}*/
152 /**
153 * @name Advanced Operation
154 *
155 * More advanced methods and options
156 */
157 /**@{*/
158
159 uint16_t thisNodeAddress; /**< Address of our node in Octal format (01,021, etc) */
160 uint8_t thisNodeID; /**< NodeID (0-255) */
161
162 bool meshEnabled(); /**< Is RF24Mesh enabled? */
163 bool config_TUN; /**< Using a TAP(false) or TUN(true) interface */
165
166 uint32_t ifDropped()
167 {
168 return droppedIncoming;
169 }
170
171 void sendUDP(uint8_t nodeID, RF24NetworkFrame frame);
172
173 /**@}*/
174 /**
175 * @name Routing Table
176 *
177 * Utilizing a routing table to provide complete connectivity
178 */
179 /**@{*/
180
181 /**
182 * If a user has created a file "routing.txt" in the RF24Gateway working directory, it will be loaded <br>
183 * at startup into the routing table. The file should contain standard routing table entries as follows: <br>
184 * IP<space>NetMask<space>Gateway <br>
185 * ie: routing.txt
186 * @code
187 * 10.1.4.0 255.255.255.0 10.1.3.33
188 * 0.0.0.0 0.0.0.0 10.1.3.34 @endcode
189 *
190 * The first example entry would route all traffic to the 10.1.4.x subnet to 10.1.3.33 <br>
191 * All other traffic not destined for the RF24 nodes will use 10.1.3.34 as the gateway
192 *
193 * Data can be accessed using standard linux Internet address manipulation routines as follows:
194 * @code
195 * printf("**IP\t\tMask\t\tGateway**\n");
196 * for(int i=0; i<gw.routingTableSize; i++){
197 * printf("%s \t",inet_ntoa(gw.routingStruct[i].ip));//inet_ntoa uses a statically assigned buffer, so the printf calls need to be done separately
198 * printf("%s \t",inet_ntoa(gw.routingStruct[i].mask));
199 * printf("%s\n", inet_ntoa(gw.routingStruct[i].gw));
200 * //std::cout << inet_ntoa(gw.routingStruct[i].ip) << " \t" << inet_ntoa(gw.routingStruct[i].mask) << " \t" << inet_ntoa(gw.routingStruct[i].gw) << std::endl;
201 * }
202 * printf("*****\n");
203 *
204 * Users can modify the routing table as desired, but changes made in code will not currently be saved to file
205 *
206 * @endcode
207 *
208 */
210 {
211 struct in_addr ip;
212 struct in_addr mask;
213 struct in_addr gw;
214 };
215
216 /**
217 * The array that holds the routing structure data. See routeStruct
218 */
219 routeStruct routingStruct[256];
220
221 /**
222 * The size of the existing routing table loaded into memory. See routeStruct
223 */
225
226 /**
227 * How many times the network has returned error 160 NETWORK_OVERRUN
228 */
230
231 /**
232 * How many times the network has returned error 161 NETWORK_CORRUPTION
233 */
235
236private:
237 radio_t& radio;
238 network_t& network;
239 mesh_t& mesh;
240
241 bool begin(bool configTUN, bool meshEnable, uint16_t address, uint8_t mesh_nodeID, rf24_datarate_e data_rate, uint8_t _channel);
242 bool mesh_enabled;
243
244 uint32_t droppedIncoming;
245
246 uint8_t channel;
247 rf24_datarate_e dataRate;
248 char tunName[IFNAMSIZ];
249 int tunFd;
250
251 unsigned long packets_sent; /**< How many have we sent already */
252 uint32_t interfaceInTimer;
253
254 void handleRadioOut();
255 void handleRadioIn();
256 void handleRX(uint32_t waitDelay = 0);
257 void handleTX();
258 volatile bool gotInterrupt;
259 int configDevice(uint16_t address);
260 int allocateTunDevice(char* dev, int flags, uint16_t address);
261
262 struct msgStruct
263 {
264 std::uint8_t message[MAX_PAYLOAD_SIZE];
265 std::size_t size;
266 };
267
268 std::queue<msgStruct> rxQueue;
269 std::queue<msgStruct> txQueue;
270
271 // void printPayload(std::string buffer, std::string debugMsg = "");
272 // void printPayload(char* buffer, int nread, std::string debugMsg = "");
273
274 int s; // Socket variable for sending UDP
275 void setupSocket();
276 struct sockaddr_in addr;
277 struct in_addr getLocalIP();
278
279 void loadRoutingTable();
280};
281
282/**
283 * A type definition of the template class `ESBGateway` to maintain backward compatibility.
284 *
285 * ```.cpp
286 * RF24 radio(7, 8);
287 * RF24Network network(radio);
288 * RF24Mesh mesh(radio, network);
289 *
290 * RF24Gateway gateway(radio, network, mesh);
291 * // is equivalent to
292 * ESBGateway<ESBMesh<ESBNetwork<RF24>, RF24>, ESBNetwork<RF24>, RF24> gateway(radio, network, mesh);
293 * ```
294 */
295typedef ESBGateway<ESBMesh<ESBNetwork<RF24>, RF24>, ESBNetwork<RF24>, RF24> RF24Gateway;
296
297/**
298 * @example RF24GatewayNode.cpp
299 *
300 * A simple example of using RF24Gateway node to forward IP traffic automatically to a network interface, while
301 * managing standard RF24Network user payloads independently.
302 */
303
304/**
305 * @example RF24Gateway_ncurses.cpp
306 * RF24Gateway NCurses interface - TMRh20 2015 <br>
307 * This is a generic tool for nodes supporting or combining with RF24Ethernet and/or RF24Network.
308 *
309 * The tool provides a simple interface for monitoring information and activity regarding the RF24Gateway: <br>
310 * a: Interface statistics from /proc/net/dev <br>
311 * b: RF24Mesh address/id assignments <br>
312 * c: RF24Network/Radio information <br>
313 * d: Active IP connections (optional) <br>
314 *
315 * **Requirements: NCurses** <br>
316 * Install NCurses: apt-get install libncurses5-dev
317 * Optional: Enable nf_conntrack: @code modprobe nf_conntrack_ipv4 @endcode
318 *
319 * @image html ncurses.JPG
320 */
321
322/**
323 * @example RF24GatewayNodeInt.cpp
324 * A copy of the RF24GatewayNode example using interrupts.
325 */
326
327/**
328 * @example RF24Gateway_ncursesInt.cpp
329 * A copy of the ncurses example using interrupts.
330 */
331
332/**
333 * @example bClient.sh
334 * Once RF24Gateway and RF24Ethernet are configured, standard tools can be used to interact with
335 * the sensor nodes. <br>Example of on demand LED/Lighting control using a Bash script.
336 */
337
338/**
339 * @example nodeClient.js
340 * Once RF24Gateway and RF24Ethernet are configured, standard tools can be used to interact with
341 * the sensor nodes. <br> Example of on demand LED/Lighting control using a NodeJS script.
342 */
343
344/**
345 * @example pyClient.py
346 * Once RF24Gateway and RF24Ethernet are configured, standard tools can be used to interact with
347 * the sensor nodes. <br> Example of scheduled LED/Lighting control using a Python script.
348 */
349
350#endif
bool meshEnabled()
int setIP(char *ip_addr, char *mask)
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 begin(uint16_t address, uint8_t channel=97, rf24_datarate_e data_rate=RF24_1MBPS, bool meshEnable=0, uint8_t nodeID=0)
uint32_t ifDropped()
void update(bool interrupts=0)
void sendUDP(uint8_t nodeID, RF24NetworkFrame frame)