Skip to content

Commit 0f34bb3

Browse files
author
Yveaux
committed
Improved parent node search
Retry parent node search with each transmit when parent has not been found. Transmit does not block on transmit when no parent has been found as this depletes batteries on battery powered nodes. Fix nRF24 configuration for dynamic ACK's. This bug caused broadcasts to be sent with auto-ACK's.
1 parent bf341ab commit 0f34bb3

File tree

2 files changed

+81
-59
lines changed

2 files changed

+81
-59
lines changed

libraries/MySensors/MySensor.cpp

Lines changed: 79 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
#include "utility/RF24.h"
1515
#include "utility/RF24_config.h"
1616

17+
#define DISTANCE_INVALID (0xFF)
18+
1719

1820
// 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) {
2022
msg.sender = sender;
2123
msg.destination = destination;
2224
msg.sensor = sensor;
@@ -27,6 +29,13 @@ inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destination, ui
2729
return msg;
2830
}
2931

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+
3039

3140
MySensor::MySensor(uint8_t _cepin, uint8_t _cspin) : RF24(_cepin, _cspin) {
3241
}
@@ -37,6 +46,7 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b
3746
isGateway = false;
3847
repeaterMode = _repeaterMode;
3948
msgCallback = _msgCallback;
49+
failedTransmissions = 0;
4050

4151
if (repeaterMode) {
4252
setupRepeaterMode();
@@ -52,23 +62,20 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b
5262
cc.isMetric = 0x01;
5363
}
5464

55-
if (_parentNodeId != AUTO) {
65+
autoFindParent = _parentNodeId == AUTO;
66+
if (!autoFindParent) {
5667
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;
6072
}
6173

6274
if (_nodeId != AUTO) {
6375
// Set static id
6476
nc.nodeId = _nodeId;
6577
}
6678

67-
// If no parent was found in eeprom. Try to find one.
68-
if (autoFindParent && nc.parentNodeId == 0xff) {
69-
findParentNode();
70-
}
71-
7279
// Try to fetch node-id from gateway
7380
if (nc.nodeId == AUTO) {
7481
requestNodeId();
@@ -93,8 +100,6 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b
93100
}
94101

95102
void MySensor::setupRadio(rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_e dataRate) {
96-
failedTransmissions = 0;
97-
98103
// Start up the radio library
99104
RF24::begin();
100105

@@ -104,13 +109,13 @@ void MySensor::setupRadio(rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_
104109
}
105110
RF24::setAutoAck(1);
106111
RF24::setAutoAck(BROADCAST_PIPE,false); // Turn off auto ack for broadcast
107-
RF24::enableAckPayload();
108112
RF24::setChannel(channel);
109113
RF24::setPALevel(paLevel);
110114
RF24::setDataRate(dataRate);
111115
RF24::setRetries(5,15);
112116
RF24::setCRCLength(RF24_CRC_16);
113117
RF24::enableDynamicPayloads();
118+
RF24::enableDynamicAck();// Required to disable ack-sending for broadcast messages
114119

115120
// All nodes listen to broadcast pipe (for FIND_PARENT_RESPONSE messages)
116121
RF24::openReadingPipe(BROADCAST_PIPE, TO_ADDR(BROADCAST_ADDRESS));
@@ -139,14 +144,11 @@ void MySensor::requestNodeId() {
139144

140145

141146
void MySensor::findParentNode() {
142-
failedTransmissions = 0;
143-
144-
// Set distance to max
145-
nc.distance = 255;
146-
147147
// 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+
148150
build(msg, nc.nodeId, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT, false).set("");
149-
sendWrite(BROADCAST_ADDRESS, msg, true);
151+
sendWrite(BROADCAST_ADDRESS, msg);
150152

151153
// Wait for ping response.
152154
waitForReply();
@@ -182,44 +184,59 @@ boolean MySensor::sendRoute(MyMessage &message) {
182184
} else if (isInternal && message.type == I_ID_RESPONSE && dest==BROADCAST_ADDRESS) {
183185
// Node has not yet received any id. We need to send it
184186
// by doing a broadcast sending,
185-
return sendWrite(BROADCAST_ADDRESS, message, true);
187+
return sendWrite(BROADCAST_ADDRESS, message);
186188
}
187189
}
188190

189191
if (!isGateway) {
190-
// --- debug(PSTR("route parent\n"));
191192
// 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;
193+
return sendWrite(nc.parentNodeId, message);
205194
}
206195
return false;
207196
}
208197

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));
198+
boolean MySensor::sendWrite(uint8_t next, MyMessage &message) {
199+
bool ok = true;
200+
const bool broadcast = next == BROADCAST_ADDRESS;
201+
const bool toParent = !broadcast && (next == nc.parentNodeId);
202+
// If sending directly to parent node and distance is not set, then try to find parent now.
203+
if ( toParent && !isValidDistance(nc.distance) ) {
204+
findParentNode();
205+
// Known distance indicates parent has been found
206+
ok = isValidDistance(nc.distance);
207+
}
222208

209+
if (ok) {
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+
// Send message. Disable auto-ack for broadcasts.
218+
ok = RF24::write(&message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length), broadcast);
219+
RF24::startListening();
220+
221+
debug(PSTR("send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,st=%s:%s\n"),
222+
message.sender,message.last, next, message.destination, message.sensor, mGetCommand(message), message.type, mGetPayloadType(message), mGetLength(message), ok?"ok":"fail", message.getString(convBuf));
223+
224+
// If many successive transmissions to parent failed, the parent node might be down and we
225+
// need to find another route to gateway.
226+
if (toParent) {
227+
if (ok) {
228+
failedTransmissions = 0;
229+
} else {
230+
failedTransmissions++;
231+
if ( autoFindParent && (failedTransmissions >= SEARCH_FAILURES)) {
232+
debug(PSTR("lost parent\n"));
233+
// Set distance invalid to trigger parent search on next write.
234+
nc.distance = DISTANCE_INVALID;
235+
failedTransmissions = 0;
236+
}
237+
}
238+
}
239+
}
223240
return ok;
224241
}
225242

@@ -267,7 +284,7 @@ boolean MySensor::process() {
267284

268285
uint8_t len = RF24::getDynamicPayloadSize();
269286
RF24::read(&msg, len);
270-
RF24::writeAckPayload(pipe,&pipe, 1 );
287+
// RF24::writeAckPayload(pipe,&pipe, 1 );
271288

272289
// Add string termination, good if we later would want to print it.
273290
msg.data[mGetLength(msg)] = '\0';
@@ -287,10 +304,10 @@ boolean MySensor::process() {
287304

288305
if (repeaterMode && command == C_INTERNAL && type == I_FIND_PARENT) {
289306
// Relaying nodes should always answer ping messages
290-
// Wait a random delay of 0-2 seconds to minimize collision
307+
// Wait a random delay of 0-1.023 seconds to minimize collision
291308
// between ping ack messages from other relaying nodes
292309
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);
310+
sendWrite(sender, build(msg, nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(nc.distance));
294311
return false;
295312
} else if (destination == nc.nodeId) {
296313
// Check if sender requests an ack back.
@@ -315,13 +332,18 @@ boolean MySensor::process() {
315332
// We've received a reply to a FIND_PARENT message. Check if the distance is
316333
// shorter than we already have.
317334
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);
335+
if (isValidDistance(distance))
336+
{
337+
// Distance to gateway is one more for us w.r.t. parent
338+
distance++;
339+
if (isValidDistance(distance) && (distance < nc.distance)) {
340+
// Found a neighbor closer to GW than previously found
341+
nc.distance = distance;
342+
nc.parentNodeId = msg.sender;
343+
eeprom_write_byte((uint8_t*)EEPROM_PARENT_NODE_ID_ADDRESS, nc.parentNodeId);
344+
eeprom_write_byte((uint8_t*)EEPROM_DISTANCE_ADDRESS, nc.distance);
345+
debug(PSTR("new parent=%d, d=%d\n"), nc.parentNodeId, nc.distance);
346+
}
325347
}
326348
return false;
327349
} else if (sender == GATEWAY_ADDRESS) {

libraries/MySensors/MySensor.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
#define BROADCAST_PIPE ((uint8_t)2)
6767

6868
// Search for a new parent node after this many transmission failures
69-
#define SEARCH_FAILURES 5
69+
#define SEARCH_FAILURES 2
7070

7171
struct NodeConfig
7272
{
@@ -254,7 +254,7 @@ class MySensor : public RF24
254254
void setupRepeaterMode();
255255
void setupRadio(rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_e dataRate);
256256
boolean sendRoute(MyMessage &message);
257-
boolean sendWrite(uint8_t dest, MyMessage &message, bool broadcast=false);
257+
boolean sendWrite(uint8_t dest, MyMessage &message);
258258

259259
private:
260260
#ifdef DEBUG

0 commit comments

Comments
 (0)