diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 52d0196..a619171 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -14,11 +14,9 @@ #include "utility/RF24.h" #include "utility/RF24_config.h" -#define DISTANCE_INVALID (0xFF) - // Inline function and macros -static inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destination, uint8_t sensor, uint8_t command, uint8_t type, bool enableAck) { +inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destination, uint8_t sensor, uint8_t command, uint8_t type, bool enableAck) { msg.sender = sender; msg.destination = destination; msg.sensor = sensor; @@ -29,13 +27,6 @@ static inline MyMessage& build (MyMessage &msg, uint8_t sender, uint8_t destinat return msg; } -static inline bool isValidParent( const uint8_t parent ) { - return parent != AUTO; -} -static inline bool isValidDistance( const uint8_t distance ) { - return distance != DISTANCE_INVALID; -} - MySensor::MySensor(uint8_t _cepin, uint8_t _cspin) : RF24(_cepin, _cspin) { } @@ -46,7 +37,6 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b isGateway = false; repeaterMode = _repeaterMode; msgCallback = _msgCallback; - failedTransmissions = 0; if (repeaterMode) { setupRepeaterMode(); @@ -62,13 +52,11 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b cc.isMetric = 0x01; } - autoFindParent = _parentNodeId == AUTO; - if (!autoFindParent) { + if (_parentNodeId != AUTO) { nc.parentNodeId = _parentNodeId; - nc.distance = 0; - } else if (!isValidParent(nc.parentNodeId)) { - // Auto find parent, but parent in eeprom is invalid. Force parent search on first transmit. - nc.distance = DISTANCE_INVALID; + autoFindParent = false; + } else { + autoFindParent = true; } if (_nodeId != AUTO) { @@ -76,12 +64,17 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b nc.nodeId = _nodeId; } + // If no parent was found in eeprom. Try to find one. + if (autoFindParent && nc.parentNodeId == 0xff) { + findParentNode(); + } + // Try to fetch node-id from gateway if (nc.nodeId == AUTO) { requestNodeId(); } - debug(PSTR("%s started, id=%d, parent=%d, distance=%d\n"), repeaterMode?"repeater":"sensor", nc.nodeId, nc.parentNodeId, nc.distance); + debug(PSTR("%s started, id %d\n"), repeaterMode?"repeater":"sensor", nc.nodeId); // Open reading pipe for messages directed to this node (set write pipe to same) RF24::openReadingPipe(WRITE_PIPE, TO_ADDR(nc.nodeId)); @@ -100,6 +93,8 @@ void MySensor::begin(void (*_msgCallback)(const MyMessage &), uint8_t _nodeId, b } void MySensor::setupRadio(rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_e dataRate) { + failedTransmissions = 0; + // Start up the radio library RF24::begin(); @@ -109,13 +104,13 @@ void MySensor::setupRadio(rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_ } RF24::setAutoAck(1); RF24::setAutoAck(BROADCAST_PIPE,false); // Turn off auto ack for broadcast + RF24::enableAckPayload(); RF24::setChannel(channel); RF24::setPALevel(paLevel); RF24::setDataRate(dataRate); RF24::setRetries(5,15); RF24::setCRCLength(RF24_CRC_16); RF24::enableDynamicPayloads(); - RF24::enableDynamicAck();// Required to disable ack-sending for broadcast messages // All nodes listen to broadcast pipe (for FIND_PARENT_RESPONSE messages) RF24::openReadingPipe(BROADCAST_PIPE, TO_ADDR(BROADCAST_ADDRESS)); @@ -144,12 +139,14 @@ void MySensor::requestNodeId() { void MySensor::findParentNode() { - // Send ping message to BROADCAST_ADDRESS (to which all relaying nodes and gateway listens and should reply to) - debug(PSTR("find parent\n")); + failedTransmissions = 0; + // Set distance to max + nc.distance = 255; + + // Send ping message to BROADCAST_ADDRESS (to which all relaying nodes and gateway listens and should reply to) build(msg, nc.nodeId, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT, false).set(""); - // Write msg, but suppress recursive parent search - sendWrite(BROADCAST_ADDRESS, msg, false); + sendWrite(BROADCAST_ADDRESS, msg, true); // Wait for ping response. waitForReply(); @@ -185,64 +182,44 @@ boolean MySensor::sendRoute(MyMessage &message) { } else if (isInternal && message.type == I_ID_RESPONSE && dest==BROADCAST_ADDRESS) { // Node has not yet received any id. We need to send it // by doing a broadcast sending, - return sendWrite(BROADCAST_ADDRESS, message); + return sendWrite(BROADCAST_ADDRESS, message, true); } } if (!isGateway) { + // --- debug(PSTR("route parent\n")); // Should be routed back to gateway. - return sendWrite(nc.parentNodeId, message); + bool ok = sendWrite(nc.parentNodeId, message); + + if (!ok) { + // Failure when sending to parent node. The parent node might be down and we + // need to find another route to gateway. + if (autoFindParent && failedTransmissions > SEARCH_FAILURES) { + findParentNode(); + } + failedTransmissions++; + } else { + failedTransmissions = 0; + } + return ok; } return false; } -boolean MySensor::sendWrite(uint8_t next, MyMessage &message, const bool allowFindParent) { - bool ok = true; - const bool broadcast = next == BROADCAST_ADDRESS; - const bool toParent = next == nc.parentNodeId; - // With current implementation parent node Id can equal the broadcast address when - // starting with empty eeprom and AUTO node Id is active. - // This behavior is undesired, as possible parents will report back to broadcast address. -// debug(PSTR("sendWrite next=%d, parent=%d, distance=%d\n"), next, nc.parentNodeId, nc.distance); - // If sending directly to parent node and distance is not set, then try to find parent now. - if ( allowFindParent && toParent && !isValidDistance(nc.distance) ) { - findParentNode(); - // Known distance indicates parent has been found - ok = isValidDistance(nc.distance); - } +boolean MySensor::sendWrite(uint8_t next, MyMessage &message, bool broadcast) { + uint8_t length = mGetLength(message); + message.last = nc.nodeId; + mSetVersion(message, PROTOCOL_VERSION); + // Make sure radio has powered up + RF24::powerUp(); + RF24::stopListening(); + RF24::openWritingPipe(TO_ADDR(next)); + bool ok = RF24::write(&message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length), broadcast); + RF24::startListening(); - if (ok) { - uint8_t length = mGetLength(message); - message.last = nc.nodeId; - mSetVersion(message, PROTOCOL_VERSION); - // Make sure radio has powered up - RF24::powerUp(); - RF24::stopListening(); - RF24::openWritingPipe(TO_ADDR(next)); - // Send message. Disable auto-ack for broadcasts. - ok = RF24::write(&message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length), broadcast); - RF24::startListening(); + debug(PSTR("send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,st=%s:%s\n"), + message.sender,message.last, next, message.destination, message.sensor, mGetCommand(message), message.type, mGetPayloadType(message), mGetLength(message), ok?"ok":"fail", message.getString(convBuf)); - debug(PSTR("send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,st=%s:%s\n"), - message.sender,message.last, next, message.destination, message.sensor, mGetCommand(message), message.type, - mGetPayloadType(message), mGetLength(message), broadcast ? "bc" : (ok ? "ok":"fail"), message.getString(convBuf)); - - // If many successive transmissions to parent failed, the parent node might be down and we - // need to find another route to gateway. - if (toParent) { - if (ok) { - failedTransmissions = 0; - } else { - failedTransmissions++; - if ( autoFindParent && (failedTransmissions >= SEARCH_FAILURES)) { - debug(PSTR("lost parent\n")); - // Set distance invalid to trigger parent search on next write. - nc.distance = DISTANCE_INVALID; - failedTransmissions = 0; - } - } - } - } return ok; } @@ -290,7 +267,7 @@ boolean MySensor::process() { uint8_t len = RF24::getDynamicPayloadSize(); RF24::read(&msg, len); -// RF24::writeAckPayload(pipe,&pipe, 1 ); + RF24::writeAckPayload(pipe,&pipe, 1 ); // Add string termination, good if we later would want to print it. msg.data[mGetLength(msg)] = '\0'; @@ -310,10 +287,10 @@ boolean MySensor::process() { if (repeaterMode && command == C_INTERNAL && type == I_FIND_PARENT) { // Relaying nodes should always answer ping messages - // Wait a random delay of 0-1.023 seconds to minimize collision + // Wait a random delay of 0-2 seconds to minimize collision // between ping ack messages from other relaying nodes delay(millis() & 0x3ff); - sendWrite(sender, build(msg, nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(nc.distance)); + sendWrite(sender, build(msg, nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(nc.distance), true); return false; } else if (destination == nc.nodeId) { // Check if sender requests an ack back. @@ -338,18 +315,13 @@ boolean MySensor::process() { // We've received a reply to a FIND_PARENT message. Check if the distance is // shorter than we already have. uint8_t distance = msg.getByte(); - if (isValidDistance(distance)) - { - // Distance to gateway is one more for us w.r.t. parent - distance++; - if (isValidDistance(distance) && (distance < nc.distance)) { - // Found a neighbor closer to GW than previously found - nc.distance = distance; - nc.parentNodeId = msg.sender; - eeprom_write_byte((uint8_t*)EEPROM_PARENT_NODE_ID_ADDRESS, nc.parentNodeId); - eeprom_write_byte((uint8_t*)EEPROM_DISTANCE_ADDRESS, nc.distance); - debug(PSTR("new parent=%d, d=%d\n"), nc.parentNodeId, nc.distance); - } + if (distance