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