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
3140MySensor::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,29 +62,26 @@ 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 ();
7582 }
7683
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 );
7885
7986 // Open reading pipe for messages directed to this node (set write pipe to same)
8087 RF24::openReadingPipe (WRITE_PIPE, TO_ADDR (nc.nodeId ));
@@ -93,8 +100,6 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b
93100}
94101
95102void 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,12 @@ void MySensor::requestNodeId() {
139144
140145
141146void 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+ // Write msg, but suppress recursive parent search
152+ sendWrite (BROADCAST_ADDRESS, msg, false );
150153
151154 // Wait for ping response.
152155 waitForReply ();
@@ -182,44 +185,64 @@ boolean MySensor::sendRoute(MyMessage &message) {
182185 } else if (isInternal && message.type == I_ID_RESPONSE && dest==BROADCAST_ADDRESS) {
183186 // Node has not yet received any id. We need to send it
184187 // by doing a broadcast sending,
185- return sendWrite (BROADCAST_ADDRESS, message, true );
188+ return sendWrite (BROADCAST_ADDRESS, message);
186189 }
187190 }
188191
189192 if (!isGateway) {
190- // --- debug(PSTR("route parent\n"));
191193 // 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);
205195 }
206196 return false ;
207197}
208198
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+ }
222213
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+ }
223246 return ok;
224247}
225248
@@ -267,7 +290,6 @@ boolean MySensor::process() {
267290
268291 uint8_t len = RF24::getDynamicPayloadSize ();
269292 RF24::read (&msg, len);
270- RF24::writeAckPayload (pipe,&pipe, 1 );
271293
272294 // Add string termination, good if we later would want to print it.
273295 msg.data [mGetLength (msg)] = ' \0 ' ;
@@ -287,10 +309,10 @@ boolean MySensor::process() {
287309
288310 if (repeaterMode && command == C_INTERNAL && type == I_FIND_PARENT) {
289311 // 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
291313 // between ping ack messages from other relaying nodes
292314 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 ));
294316 return false ;
295317 } else if (destination == nc.nodeId ) {
296318 // Check if sender requests an ack back.
@@ -315,13 +337,18 @@ boolean MySensor::process() {
315337 // We've received a reply to a FIND_PARENT message. Check if the distance is
316338 // shorter than we already have.
317339 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+ }
325352 }
326353 return false ;
327354 } else if (sender == GATEWAY_ADDRESS) {
0 commit comments