-
Notifications
You must be signed in to change notification settings - Fork 129
/
RF24Network.h
351 lines (322 loc) · 12.9 KB
/
RF24Network.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
/*
Copyright (C) 2011 James Coliz, Jr. <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
#ifndef __RF24NETWORK_H__
#define __RF24NETWORK_H__
/**
* @file RF24Network.h
*
* Class declaration for RF24Network
*/
#include <stddef.h>
#include <stdint.h>
class RF24;
/**
* Header which is sent with each message
*
* The frame put over the air consists of this header and a message
*/
struct RF24NetworkHeader
{
uint16_t from_node; /**< Logical address where the message was generated */
uint16_t to_node; /**< Logical address where the message is going */
uint16_t id; /**< Sequential message ID, incremented every message */
unsigned char type; /**< Type of the packet. 0-127 are user-defined types, 128-255 are reserved for system */
unsigned char reserved; /**< Reserved for future use */
static uint16_t next_id; /**< The message ID of the next message to be sent */
/**
* Default constructor
*
* Simply constructs a blank header
*/
RF24NetworkHeader() {}
/**
* Send constructor
*
* Use this constructor to create a header and then send a message
*
* @code
* RF24NetworkHeader header(recipient_address,'t');
* network.write(header,&message,sizeof(message));
* @endcode
*
* @param _to The logical node address where the message is going
* @param _type The type of message which follows. Only 0-127 are allowed for
* user messages.
*/
RF24NetworkHeader(uint16_t _to, unsigned char _type = 0): to_node(_to), id(next_id++), type(_type&0x7f) {}
/**
* Create debugging string
*
* Useful for debugging. Dumps all members into a single string, using
* internal static memory. This memory will get overridden next time
* you call the method.
*
* @return String representation of this object
*/
const char* toString(void) const;
};
/**
* Network Layer for RF24 Radios
*
* This class implements an OSI Network Layer using nRF24L01(+) radios driven
* by RF24 library.
*/
class RF24Network
{
public:
/**
* Construct the network
*
* @param _radio The underlying radio driver instance
*
*/
RF24Network( RF24& _radio );
/**
* Bring up the network
*
* @warning Be sure to 'begin' the radio first.
*
* @param _channel The RF channel to operate on
* @param _node_address The logical address of this node
*/
void begin(uint8_t _channel, uint16_t _node_address );
/**
* Main layer loop
*
* This function must be called regularly to keep the layer going. This is where all
* the action happens!
*/
void update(void);
/**
* Test whether there is a message available for this node
*
* @return Whether there is a message available for this node
*/
bool available(void);
/**
* Read the next available header
*
* Reads the next available header without advancing to the next
* incoming message. Useful for doing a switch on the message type
*
* If there is no message available, the header is not touched
*
* @param[out] header The header (envelope) of the next message
*/
void peek(RF24NetworkHeader& header);
/**
* Read a message
*
* @param[out] header The header (envelope) of this message
* @param[out] message Pointer to memory where the message should be placed
* @param maxlen The largest message size which can be held in @p message
* @return The total number of bytes copied into @p message
*/
size_t read(RF24NetworkHeader& header, void* message, size_t maxlen);
/**
* Send a message
*
* @param[in,out] header The header (envelope) of this message. The critical
* thing to fill in is the @p to_node field so we know where to send the
* message. It is then updated with the details of the actual header sent.
* @param message Pointer to memory where the message is located
* @param len The size of the message
* @return Whether the message was successfully received
*/
bool write(RF24NetworkHeader& header,const void* message, size_t len);
/**
* This node's parent address
*
* @return This node's parent address, or -1 if this is the base
*/
uint16_t parent() const;
protected:
void open_pipes(void);
uint16_t find_node( uint16_t current_node, uint16_t target_node );
bool write(uint16_t);
bool write_to_pipe( uint16_t node, uint8_t pipe );
bool enqueue(void);
bool is_direct_child( uint16_t node );
bool is_descendant( uint16_t node );
uint16_t direct_child_route_to( uint16_t node );
uint8_t pipe_to_descendant( uint16_t node );
void setup_address(void);
private:
RF24& radio; /**< Underlying radio driver, provides link/physical layers */
uint16_t node_address; /**< Logical node address of this unit, 1 .. UINT_MAX */
const static int frame_size = 32; /**< How large is each frame over the air */
uint8_t frame_buffer[frame_size]; /**< Space to put the frame that will be sent/received over the air */
uint8_t frame_queue[5*frame_size]; /**< Space for a small set of frames that need to be delivered to the app layer */
uint8_t* next_frame; /**< Pointer into the @p frame_queue where we should place the next received frame */
uint16_t parent_node; /**< Our parent's node address */
uint8_t parent_pipe; /**< The pipe our parent uses to listen to us */
uint16_t node_mask; /**< The bits which contain signfificant node address information */
};
/**
* @example helloworld_tx.pde
*
* Simplest possible example of using RF24Network. Put this sketch
* on one node, and helloworld_rx.pde on the other. Tx will send
* Rx a nice message every 2 seconds which rx will print out for us.
*/
/**
* @example helloworld_rx.pde
*
* Simplest possible example of using RF24Network. Put this sketch
* on one node, and helloworld_tx.pde on the other. Tx will send
* Rx a nice message every 2 seconds which rx will print out for us.
*/
/**
* @example meshping.pde
*
* Example of pinging across a mesh network
* Using this sketch, each node will send a ping to the base every
* few seconds. The RF24Network library will route the message across
* the mesh to the correct node.
*/
/**
* @example sensornet.pde
*
* Example of a sensor network.
* This sketch demonstrates how to use the RF24Network library to
* manage a set of low-power sensor nodes which mostly sleep but
* awake regularly to send readings to the base.
*/
/**
* @mainpage Network Layer for RF24 Radios
*
* This class implements an <a href="http://en.wikipedia.org/wiki/Network_layer">OSI Network Layer</a> using nRF24L01(+) radios driven
* by the <a href="http://maniacbug.github.com/RF24/">RF24</a> library.
*
* @section Purpose Purpose/Goal
*
* Create an alternative to ZigBee radios for Arduino communication.
*
* Xbees are excellent little radios, backed up by a mature and robust standard
* protocol stack. They are also expensive.
*
* For many Arduino uses, they seem like overkill. So I am working to build
* an alternative using nRF24L01 radios. Modules are available for less than
* $6 from many sources. With the RF24Network layer, I hope to cover many
* common communication scenarios.
*
* Please see the @ref Zigbee page for a comparison against the ZigBee protocols
*
* @section Features Features
*
* The layer provides:
* @li Host Addressing. Each node has a logical address on the local network.
* @li Message Forwarding. Messages can be sent from one node to any other, and
* this layer will get them there no matter how many hops it takes.
* @li Ad-hoc Joining. A node can join a network without any changes to any
* existing nodes.
*
* The layer does not (yet) provide:
* @li Fragmentation/reassembly. Ability to send longer messages and put them
* all back together before exposing them up to the app.
* @li Power-efficient listening. It would be useful for nodes who are listening
* to sleep for extended periods of time if they could know that they would miss
* no traffic.
* @li Dynamic address assignment.
*
* @section More How to learn more
*
* @li <a href="http://maniacbug.github.com/RF24/">RF24: Underlying radio driver</a>
* @li <a href="classRF24Network.html">RF24Network Class Documentation</a>
* @li <a href="https://github.com/maniacbug/RF24Network/">Source Code</a>
* @li <a href="https://github.com/maniacbug/RF24Network/archives/master">Downloads Page</a>
* @li <a href="examples.html">Examples Page</a>. Start with <a href="helloworld_rx_8pde-example.html">helloworld_rx</a> and <a href="helloworld_tx_8pde-example.html">helloworld_tx</a>.
*
* @section Topology Topology for Mesh Networks using nRF24L01(+)
*
* This network layer takes advantage of the fundamental capability of the nRF24L01(+) radio to
* listen actively to up to 6 other radios at once. The network is arranged in a
* <a href="http://en.wikipedia.org/wiki/Network_Topology#Tree">Tree Topology</a>, where
* one node is the base, and all other nodes are children either of that node, or of another.
* Unlike a true mesh network, multiple nodes are not connected together, so there is only one
* path to any given node.
*
* @section Octal Octal Addressing
*
* Each node must be assigned an 15-bit address by the administrator. This address exactly
* describes the position of the node within the tree. The address is an octal number. Each
* digit in the address represents a position in the tree further from the base.
*
* @li Node 00 is the base node.
* @li Nodes 01-05 are nodes whose parent is the base.
* @li Node 021 is the second child of node 01.
* @li Node 0321 is the third child of node 021, an so on.
* @li The largest node address is 05555, so 3,125 nodes are allowed on a single channel.
*
* @section Routing How routing is handled
*
* When sending a message using RF24Network::write(), you fill in the header with the logical
* node address. The network layer figures out the right path to find that node, and sends
* it through the system until it gets to the right place. This works even if the two nodes
* are far separated, as it will send the message down to the base node, and then back out
* to the final destination.
*
* All of this work is handled by the RF24Network::update() method, so be sure to call it
* regularly or your network will miss packets.
*
* @section Startup Starting up a node
*
* When a node starts up, it only has to contact its parent to establish communication.
* No direct connection to the Base node is needed. This is useful in situations where
* relay nodes are being used to bridge the distance to the base, so leaf nodes are out
* of range of the base.
*
* @section Directionality Directionality
*
* By default all nodes are always listening, so messages will quickly reach
* their destination.
*
* You may choose to sleep any nodes which do not have any active children on the network
* (i.e. leaf nodes). This is useful in a case where
* the leaf nodes are operating on batteries and need to sleep.
* This is useful for a sensor network. The leaf nodes can sleep most of the time, and wake
* every few minutes to send in a reading. However, messages cannot be sent to these
* sleeping nodes.
*
* In the future, I plan to write a system where messages can still be passed upward from
* the base, and get delivered when a sleeping node is ready to receive them. The radio
* and underlying driver support 'ack payloads', which will be a handy mechanism for this.
*
* @page Zigbee Comparison to ZigBee
*
* This network layer is influenced by the design of ZigBee, but does not implement it
* directly.
*
* @section Advantage Which is better?
*
* ZigBee is a much more robust, feature-rich set of protocols, with many different vendors
* providing compatible chips.
*
* RF24Network is cheap. While ZigBee radios are well over $20, nRF24L01 modules can be found
* for under $6. My personal favorite is
* <a href="http://www.mdfly.com/index.php?main_page=product_info&products_id=82">MDFly RF-IS2401</a>.
*
* @section Contrast Similiarities & Differences
*
* Here are some comparisons between RF24Network and ZigBee.
*
* @li Both networks support Star and Tree topologies. Only Zigbee supports a true mesh.
* @li In both networks, only leaf nodes can sleep (see @ref NodeNames).
* @li ZigBee nodes are configured using AT commands, or a separate Windows application.
* RF24 nodes are configured by recompiliing the firmware or writing to EEPROM.
*
* @section NodeNames Node Naming
*
* @li Leaf node: A node at the outer edge of the network with no children. ZigBee calls it
* an End Device node.
* @li Relay node: A node which has both parents and children, and relays messages from one
* to the other. ZigBee calls it a Router.
* @li Base node. The top of the tree node with no parents, only children. Typically this node
* will bridge to another kind of network like Ethernet. ZigBee calls it a Co-ordinator node.
*/
#endif // __RF24NETWORK_H__
// vim:ai:cin:sts=2 sw=2 ft=cpp