14
14
#include " utility/RF24.h"
15
15
#include " utility/RF24_config.h"
16
16
17
+ #define DISTANCE_INVALID (0xFF )
18
+
17
19
18
20
// Inline function and macros
19
- inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destination, uint8_t sensor, uint8_t command, uint8_t type, bool enableAck) {
21
+ static inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destination, uint8_t sensor, uint8_t command, uint8_t type, bool enableAck) {
20
22
msg.sender = sender;
21
23
msg.destination = destination;
22
24
msg.sensor = sensor;
@@ -27,6 +29,13 @@ inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destination, ui
27
29
return msg;
28
30
}
29
31
32
+ static inline bool isValidParent ( const uint8_t parent ) {
33
+ return parent != AUTO;
34
+ }
35
+ static inline bool isValidDistance ( const uint8_t distance ) {
36
+ return distance != DISTANCE_INVALID;
37
+ }
38
+
30
39
31
40
MySensor::MySensor (uint8_t _cepin, uint8_t _cspin) : RF24(_cepin, _cspin) {
32
41
}
@@ -37,6 +46,7 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b
37
46
isGateway = false ;
38
47
repeaterMode = _repeaterMode;
39
48
msgCallback = _msgCallback;
49
+ failedTransmissions = 0 ;
40
50
41
51
if (repeaterMode) {
42
52
setupRepeaterMode ();
@@ -52,29 +62,26 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b
52
62
cc.isMetric = 0x01 ;
53
63
}
54
64
55
- if (_parentNodeId != AUTO) {
65
+ autoFindParent = _parentNodeId == AUTO;
66
+ if (!autoFindParent) {
56
67
nc.parentNodeId = _parentNodeId;
57
- autoFindParent = false ;
58
- } else {
59
- autoFindParent = true ;
68
+ nc.distance = 0 ;
69
+ } else if (!isValidParent (nc.parentNodeId )) {
70
+ // Auto find parent, but parent in eeprom is invalid. Force parent search on first transmit.
71
+ nc.distance = DISTANCE_INVALID;
60
72
}
61
73
62
74
if (_nodeId != AUTO) {
63
75
// Set static id
64
76
nc.nodeId = _nodeId;
65
77
}
66
78
67
- // If no parent was found in eeprom. Try to find one.
68
- if (autoFindParent && nc.parentNodeId == 0xff ) {
69
- findParentNode ();
70
- }
71
-
72
79
// Try to fetch node-id from gateway
73
80
if (nc.nodeId == AUTO) {
74
81
requestNodeId ();
75
82
}
76
83
77
- debug (PSTR (" %s started, id %d \n " ), repeaterMode?" repeater" :" sensor" , nc.nodeId );
84
+ debug (PSTR (" %s started, id=%d, parent=%d, distance=%d \n " ), repeaterMode?" repeater" :" sensor" , nc.nodeId , nc. parentNodeId , nc. distance );
78
85
79
86
// Open reading pipe for messages directed to this node (set write pipe to same)
80
87
RF24::openReadingPipe (WRITE_PIPE, TO_ADDR (nc.nodeId ));
@@ -93,8 +100,6 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b
93
100
}
94
101
95
102
void MySensor::setupRadio (rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_e dataRate) {
96
- failedTransmissions = 0 ;
97
-
98
103
// Start up the radio library
99
104
RF24::begin ();
100
105
@@ -104,13 +109,13 @@ void MySensor::setupRadio(rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_
104
109
}
105
110
RF24::setAutoAck (1 );
106
111
RF24::setAutoAck (BROADCAST_PIPE,false ); // Turn off auto ack for broadcast
107
- RF24::enableAckPayload ();
108
112
RF24::setChannel (channel);
109
113
RF24::setPALevel (paLevel);
110
114
RF24::setDataRate (dataRate);
111
115
RF24::setRetries (5 ,15 );
112
116
RF24::setCRCLength (RF24_CRC_16);
113
117
RF24::enableDynamicPayloads ();
118
+ RF24::enableDynamicAck (); // Required to disable ack-sending for broadcast messages
114
119
115
120
// All nodes listen to broadcast pipe (for FIND_PARENT_RESPONSE messages)
116
121
RF24::openReadingPipe (BROADCAST_PIPE, TO_ADDR (BROADCAST_ADDRESS));
@@ -139,14 +144,12 @@ void MySensor::requestNodeId() {
139
144
140
145
141
146
void MySensor::findParentNode () {
142
- failedTransmissions = 0 ;
143
-
144
- // Set distance to max
145
- nc.distance = 255 ;
146
-
147
147
// Send ping message to BROADCAST_ADDRESS (to which all relaying nodes and gateway listens and should reply to)
148
+ debug (PSTR (" find parent\n " ));
149
+
148
150
build (msg, nc.nodeId , BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT, false ).set (" " );
149
- sendWrite (BROADCAST_ADDRESS, msg, true );
151
+ // Write msg, but suppress recursive parent search
152
+ sendWrite (BROADCAST_ADDRESS, msg, false );
150
153
151
154
// Wait for ping response.
152
155
waitForReply ();
@@ -182,44 +185,64 @@ boolean MySensor::sendRoute(MyMessage &message) {
182
185
} else if (isInternal && message.type == I_ID_RESPONSE && dest==BROADCAST_ADDRESS) {
183
186
// Node has not yet received any id. We need to send it
184
187
// by doing a broadcast sending,
185
- return sendWrite (BROADCAST_ADDRESS, message, true );
188
+ return sendWrite (BROADCAST_ADDRESS, message);
186
189
}
187
190
}
188
191
189
192
if (!isGateway) {
190
- // --- debug(PSTR("route parent\n"));
191
193
// Should be routed back to gateway.
192
- bool ok = sendWrite (nc.parentNodeId , message);
193
-
194
- if (!ok) {
195
- // Failure when sending to parent node. The parent node might be down and we
196
- // need to find another route to gateway.
197
- if (autoFindParent && failedTransmissions > SEARCH_FAILURES) {
198
- findParentNode ();
199
- }
200
- failedTransmissions++;
201
- } else {
202
- failedTransmissions = 0 ;
203
- }
204
- return ok;
194
+ return sendWrite (nc.parentNodeId , message);
205
195
}
206
196
return false ;
207
197
}
208
198
209
- boolean MySensor::sendWrite (uint8_t next, MyMessage &message, bool broadcast) {
210
- uint8_t length = mGetLength (message);
211
- message.last = nc.nodeId ;
212
- mSetVersion (message, PROTOCOL_VERSION);
213
- // Make sure radio has powered up
214
- RF24::powerUp ();
215
- RF24::stopListening ();
216
- RF24::openWritingPipe (TO_ADDR (next));
217
- bool ok = RF24::write (&message, min (MAX_MESSAGE_LENGTH, HEADER_SIZE + length), broadcast);
218
- RF24::startListening ();
219
-
220
- debug (PSTR (" send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,st=%s:%s\n " ),
221
- message.sender ,message.last , next, message.destination , message.sensor , mGetCommand (message), message.type , mGetPayloadType (message), mGetLength (message), ok?" ok" :" fail" , message.getString (convBuf));
199
+ boolean MySensor::sendWrite (uint8_t next, MyMessage &message, const bool allowFindParent) {
200
+ bool ok = true ;
201
+ const bool broadcast = next == BROADCAST_ADDRESS;
202
+ const bool toParent = next == nc.parentNodeId ;
203
+ // With current implementation parent node Id can equal the broadcast address when
204
+ // starting with empty eeprom and AUTO node Id is active.
205
+ // This behavior is undesired, as possible parents will report back to broadcast address.
206
+ // debug(PSTR("sendWrite next=%d, parent=%d, distance=%d\n"), next, nc.parentNodeId, nc.distance);
207
+ // If sending directly to parent node and distance is not set, then try to find parent now.
208
+ if ( allowFindParent && toParent && !isValidDistance (nc.distance ) ) {
209
+ findParentNode ();
210
+ // Known distance indicates parent has been found
211
+ ok = isValidDistance (nc.distance );
212
+ }
222
213
214
+ if (ok) {
215
+ uint8_t length = mGetLength (message);
216
+ message.last = nc.nodeId ;
217
+ mSetVersion (message, PROTOCOL_VERSION);
218
+ // Make sure radio has powered up
219
+ RF24::powerUp ();
220
+ RF24::stopListening ();
221
+ RF24::openWritingPipe (TO_ADDR (next));
222
+ // Send message. Disable auto-ack for broadcasts.
223
+ ok = RF24::write (&message, min (MAX_MESSAGE_LENGTH, HEADER_SIZE + length), broadcast);
224
+ RF24::startListening ();
225
+
226
+ debug (PSTR (" send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,st=%s:%s\n " ),
227
+ message.sender ,message.last , next, message.destination , message.sensor , mGetCommand (message), message.type ,
228
+ mGetPayloadType (message), mGetLength (message), broadcast ? " bc" : (ok ? " ok" :" fail" ), message.getString (convBuf));
229
+
230
+ // If many successive transmissions to parent failed, the parent node might be down and we
231
+ // need to find another route to gateway.
232
+ if (toParent) {
233
+ if (ok) {
234
+ failedTransmissions = 0 ;
235
+ } else {
236
+ failedTransmissions++;
237
+ if ( autoFindParent && (failedTransmissions >= SEARCH_FAILURES)) {
238
+ debug (PSTR (" lost parent\n " ));
239
+ // Set distance invalid to trigger parent search on next write.
240
+ nc.distance = DISTANCE_INVALID;
241
+ failedTransmissions = 0 ;
242
+ }
243
+ }
244
+ }
245
+ }
223
246
return ok;
224
247
}
225
248
@@ -267,7 +290,6 @@ boolean MySensor::process() {
267
290
268
291
uint8_t len = RF24::getDynamicPayloadSize ();
269
292
RF24::read (&msg, len);
270
- RF24::writeAckPayload (pipe,&pipe, 1 );
271
293
272
294
// Add string termination, good if we later would want to print it.
273
295
msg.data [mGetLength (msg)] = ' \0 ' ;
@@ -287,10 +309,10 @@ boolean MySensor::process() {
287
309
288
310
if (repeaterMode && command == C_INTERNAL && type == I_FIND_PARENT) {
289
311
// Relaying nodes should always answer ping messages
290
- // Wait a random delay of 0-2 seconds to minimize collision
312
+ // Wait a random delay of 0-1.023 seconds to minimize collision
291
313
// between ping ack messages from other relaying nodes
292
314
delay (millis () & 0x3ff );
293
- sendWrite (sender, build (msg, nc.nodeId , sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false ).set (nc.distance ), true );
315
+ sendWrite (sender, build (msg, nc.nodeId , sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false ).set (nc.distance ));
294
316
return false ;
295
317
} else if (destination == nc.nodeId ) {
296
318
// Check if sender requests an ack back.
@@ -315,13 +337,18 @@ boolean MySensor::process() {
315
337
// We've received a reply to a FIND_PARENT message. Check if the distance is
316
338
// shorter than we already have.
317
339
uint8_t distance = msg.getByte ();
318
- if (distance<nc.distance -1 ) {
319
- // Found a neighbor closer to GW than previously found
320
- nc.distance = distance + 1 ;
321
- nc.parentNodeId = msg.sender ;
322
- eeprom_write_byte ((uint8_t *)EEPROM_PARENT_NODE_ID_ADDRESS, nc.parentNodeId );
323
- eeprom_write_byte ((uint8_t *)EEPROM_DISTANCE_ADDRESS, nc.distance );
324
- debug (PSTR (" new parent=%d, d=%d\n " ), nc.parentNodeId , nc.distance );
340
+ if (isValidDistance (distance))
341
+ {
342
+ // Distance to gateway is one more for us w.r.t. parent
343
+ distance++;
344
+ if (isValidDistance (distance) && (distance < nc.distance )) {
345
+ // Found a neighbor closer to GW than previously found
346
+ nc.distance = distance;
347
+ nc.parentNodeId = msg.sender ;
348
+ eeprom_write_byte ((uint8_t *)EEPROM_PARENT_NODE_ID_ADDRESS, nc.parentNodeId );
349
+ eeprom_write_byte ((uint8_t *)EEPROM_DISTANCE_ADDRESS, nc.distance );
350
+ debug (PSTR (" new parent=%d, d=%d\n " ), nc.parentNodeId , nc.distance );
351
+ }
325
352
}
326
353
return false ;
327
354
} else if (sender == GATEWAY_ADDRESS) {
0 commit comments