diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index 04098b0..2e135c0 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -81,6 +81,40 @@ //#define MY_RADIO_RFM69 //#define MY_RS485 +/** + * @def MY_REGISTRATION_FEATURE + * @brief If enabled, node has to register to gateway/controller before allowed to send sensor data. + */ +#define MY_REGISTRATION_FEATURE + + /** + * @def MY_REGISTRATION_RETRIES + * @brief Number of registration retries if no reply received from GW/controller + */ + +#ifndef MY_REGISTRATION_RETRIES +#define MY_REGISTRATION_RETRIES 3 +#endif + + /** + * @def MY_REGISTRATION_DEFAULT + * @brief Node registration default - this applies if no registration response is recieved from controller + */ + +#define MY_REGISTRATION_DEFAULT true + + /** + * @def MY_REGISTRATION_CONTROLLER + * @brief If enabled, node registration request has to be handled by controller + */ + // #define MY_REGISTRATION_CONTROLLER + + /** + * @def MY_CORE_COMPATIBILITY_CHECK + * @brief If enabled, library compatibility is checked during node registration. Incompatible libraries are unable to send sensor data. + */ +#define MY_CORE_COMPATIBILITY_CHECK + /** * @def MY_NODE_ID * @brief Node id defaults to AUTO (tries to fetch id from controller). @@ -97,6 +131,12 @@ #define MY_PARENT_NODE_ID AUTO #endif +/** + * @def MY_PARENT_NODE_IS_STATIC + * @brief Enable MY_PARENT_NODE_IS_STATIC to disable fall back if parent node fails + */ +//#define MY_PARENT_NODE_IS_STATIC + // Enables repeater functionality (relays messages from other nodes) // #define MY_REPEATER_FEATURE @@ -646,4 +686,6 @@ #define MY_SIGNING_REQUEST_SIGNATURES #define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01}}} #define MY_IS_RFM69HW +#define MY_PARENT_NODE_IS_STATIC +#define MY_DEBUG_VERBOSE_RF24 #endif diff --git a/libraries/MySensors/MySensors.h b/libraries/MySensors/MySensors.h index e268214..8f7b53a 100644 --- a/libraries/MySensors/MySensors.h +++ b/libraries/MySensors/MySensors.h @@ -172,6 +172,11 @@ #endif +// FLASH +#if defined(MY_OTA_FIRMWARE_FEATURE) + #include "drivers/SPIFlash/SPIFlash.cpp" + #include "core/MyOTAFirmwareUpdate.cpp" +#endif // GATEWAY - TRANSPORT #if defined(MY_GATEWAY_MQTT_CLIENT) @@ -245,11 +250,6 @@ #include "drivers/AVR/DigitalIO/DigitalIO.h" #endif - // FLASH - #ifdef MY_OTA_FIRMWARE_FEATURE - #include "drivers/SPIFlash/SPIFlash.cpp" - #include "core/MyOTAFirmwareUpdate.cpp" - #endif #include "core/MyTransport.cpp" #if (defined(MY_RADIO_NRF24) && defined(MY_RADIO_RFM69)) || (defined(MY_RADIO_NRF24) && defined(MY_RS485)) || (defined(MY_RADIO_RFM69) && defined(MY_RS485)) #error Only one forward link driver can be activated diff --git a/libraries/MySensors/core/MyGatewayTransport.cpp b/libraries/MySensors/core/MyGatewayTransport.cpp index 26d9818..ebbec28 100644 --- a/libraries/MySensors/core/MyGatewayTransport.cpp +++ b/libraries/MySensors/core/MyGatewayTransport.cpp @@ -19,7 +19,7 @@ #include "MyGatewayTransport.h" -extern boolean transportSendRoute(MyMessage &message); +extern bool transportSendRoute(MyMessage &message); extern MyMessage _msg; inline void gatewayTransportProcess() { diff --git a/libraries/MySensors/core/MyInclusionMode.h b/libraries/MySensors/core/MyInclusionMode.h index 87533a1..b52b261 100644 --- a/libraries/MySensors/core/MyInclusionMode.h +++ b/libraries/MySensors/core/MyInclusionMode.h @@ -1,4 +1,4 @@ -/** +/* * The MySensors Arduino library handles the wireless radio link and protocol * between your home built sensors/actuators and HA controller of choice. * The sensors forms a self healing radio network with optional repeaters. Each diff --git a/libraries/MySensors/core/MyIndication.cpp b/libraries/MySensors/core/MyIndication.cpp index 9b4fd89..8e5e65b 100644 --- a/libraries/MySensors/core/MyIndication.cpp +++ b/libraries/MySensors/core/MyIndication.cpp @@ -1,4 +1,4 @@ -/** +/* * The MySensors Arduino library handles the wireless radio link and protocol * between your home built sensors/actuators and HA controller of choice. * The sensors forms a self healing radio network with optional repeaters. Each diff --git a/libraries/MySensors/core/MyIndication.h b/libraries/MySensors/core/MyIndication.h index 342fc1d..fe3f192 100644 --- a/libraries/MySensors/core/MyIndication.h +++ b/libraries/MySensors/core/MyIndication.h @@ -1,4 +1,4 @@ -/** +/* * The MySensors Arduino library handles the wireless radio link and protocol * between your home built sensors/actuators and HA controller of choice. * The sensors forms a self healing radio network with optional repeaters. Each @@ -34,6 +34,8 @@ typedef enum { INDICATION_GOT_PARENT, //!< Found parent node. INDICATION_REQ_NODEID, //!< Request node ID. INDICATION_GOT_NODEID, //!< Got a node ID. + INDICATION_REQ_REGISTRATION, //!< Request node registration. + INDICATION_GOT_REGISTRATION, //!< Got registration reponse. INDICATION_REBOOT, //!< Rebooting node. INDICATION_PRESENT, //!< Presenting node to gateway. INDICATION_CLEAR_ROUTING, //!< Clear rrouting table requested. diff --git a/libraries/MySensors/core/MyMessage.h b/libraries/MySensors/core/MyMessage.h index 2b81fbf..2e2a74a 100644 --- a/libraries/MySensors/core/MyMessage.h +++ b/libraries/MySensors/core/MyMessage.h @@ -188,8 +188,8 @@ typedef enum { I_LOCKED = 23, //!< Node is locked (reason in string-payload) I_PING = 24, //!< Ping sent to node, payload incremental hop counter I_PONG = 25, //!< In return to ping, sent back to sender, payload incremental hop counter - I_REGISTER_REQUEST = 26, //!< Register request to GW - I_REGISTER_RESPONSE = 27, //!< Register response from GW + I_REGISTRATION_REQUEST = 26, //!< Register request to GW + I_REGISTRATION_RESPONSE = 27, //!< Register response from GW I_DEBUG = 28 //!< Debug message } mysensor_internal; diff --git a/libraries/MySensors/core/MySensorsCore.cpp b/libraries/MySensors/core/MySensorsCore.cpp index f236247..7e6da88 100644 --- a/libraries/MySensors/core/MySensorsCore.cpp +++ b/libraries/MySensors/core/MySensorsCore.cpp @@ -1,4 +1,4 @@ -/** +/* * The MySensors Arduino library handles the wireless radio link and protocol * between your home built sensors/actuators and HA controller of choice. * The sensors forms a self healing radio network with optional repeaters. Each @@ -24,18 +24,17 @@ NodeConfig _nc; // Essential settings for node to work MyMessage _msg; // Buffer for incoming messages. MyMessage _msgTmp; // Buffer for temporary messages (acks and nonces among others). -#ifdef MY_DEBUG +boolean _nodeRegistered = false; + +#if defined(MY_DEBUG) char _convBuf[MAX_PAYLOAD*2+1]; #endif -uint32_t _heartbeat = 0; void (*_timeCallback)(unsigned long); // Callback for requested time messages - void _process() { hwWatchdogReset(); - #if defined (MY_LEDS_BLINKING_FEATURE) ledsProcess(); #endif @@ -51,23 +50,17 @@ void _process() { #if defined(MY_RADIO_FEATURE) transportProcess(); #endif - -} -#if defined(MY_RADIO_FEATURE) -static inline bool isValidParent( const uint8_t parent ) { - return parent != AUTO; } -#endif void _infiniteLoop() { while(1) { - #if defined(MY_GATEWAY_ESP8266) + #if defined(ARDUINO_ARCH_ESP8266) yield(); #endif - #if defined (MY_LEDS_BLINKING_FEATURE) - ledsProcess(); - #endif + #if defined (MY_LEDS_BLINKING_FEATURE) + ledsProcess(); + #endif } } @@ -88,20 +81,6 @@ void _begin() { signerInit(); - #if defined(MY_RADIO_FEATURE) - _failedTransmissions = 0; - - // Setup radio - if (!transportInit()) { - setIndication(INDICATION_ERR_INIT_TRANSPORT); - debug(PSTR("Radio init failed. Check wiring.\n")); - // Nothing more we can do - _infiniteLoop(); - } else { - debug(PSTR("Radio init successful.\n")); - } - #endif - #if defined(MY_GATEWAY_FEATURE) #if defined(MY_INCLUSION_BUTTON_FEATURE) inclusionInit(); @@ -109,101 +88,134 @@ void _begin() { // initialize the transport driver if (!gatewayTransportInit()) { - setIndication(INDICATION_ERR_INIT_GWTRANSPORT); + setIndication(INDICATION_ERR_INIT_GWTRANSPORT); debug(PSTR("Transport driver init fail\n")); // Nothing more we can do _infiniteLoop(); } - #endif - + #endif // Read latest received controller configuration from EEPROM hwReadConfigBlock((void*)&_cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig)); - if (_cc.isMetric == 0xff) { - // Eeprom empty, set default to metric - _cc.isMetric = 0x01; - } + // isMetric is bool, hence empty EEPROM (=0xFF) evaluates to true + + #if defined(MY_OTA_FIRMWARE_FEATURE) + // Read firmware config from EEPROM, i.e. type, version, CRC, blocks + readFirmwareSettings(); + #endif - #if defined(MY_GATEWAY_FEATURE) - // Set configuration for gateway - _nc.parentNodeId = GATEWAY_ADDRESS; - _nc.distance = 0; - _nc.nodeId = GATEWAY_ADDRESS; - #elif defined(MY_RADIO_FEATURE) - // Read settings from eeprom - hwReadConfigBlock((void*)&_nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); - #if defined(MY_OTA_FIRMWARE_FEATURE) - // Read firmware config from EEPROM, i.e. type, version, CRC, blocks - readFirmwareSettings(); - #endif - - _autoFindParent = MY_PARENT_NODE_ID == AUTO; - if (!_autoFindParent) { - _nc.parentNodeId = MY_PARENT_NODE_ID; - // Save static parent id in eeprom (used by bootloader) - hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, MY_PARENT_NODE_ID); - // We don't actually know the distance to gw here. Let's pretend it is 1. - // If the current node is also repeater, be aware of this. - _nc.distance = 1; - setIndication(INDICATION_GOT_PARENT); - } else if (!isValidParent(_nc.parentNodeId)) { - // Auto find parent, but parent in eeprom is invalid. Try find one. - transportFindParentNode(); - } - - if (MY_NODE_ID != AUTO) { - // Set static id - _nc.nodeId = MY_NODE_ID; - // Save static id in eeprom - hwWriteConfig(EEPROM_NODE_ID_ADDRESS, MY_NODE_ID); - setIndication(INDICATION_GOT_NODEID); - } else if (_nc.nodeId == AUTO && isValidParent(_nc.parentNodeId)) { - // Try to fetch node-id from gateway - transportRequestNodeId(); + #if defined(MY_RADIO_FEATURE) + // Save static parent id in eeprom (used by bootloader) + hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, MY_PARENT_NODE_ID); + transportInitialize(); + while (!isTransportOK()) { + hwWatchdogReset(); + transportProcess(); + #if defined(ARDUINO_ARCH_ESP8266) + yield(); + #endif } #endif -#ifdef MY_NODE_LOCK_FEATURE - // Check if node has been locked down - if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER) == 0) { - // Node is locked, check if unlock pin is asserted, else hang the node - pinMode(MY_NODE_UNLOCK_PIN, INPUT_PULLUP); - // Make a short delay so we are sure any large external nets are fully pulled - unsigned long enter = hwMillis(); - while (hwMillis() - enter < 2); - if (digitalRead(MY_NODE_UNLOCK_PIN) == 0) { - // Pin is grounded, reset lock counter + + + #ifdef MY_NODE_LOCK_FEATURE + // Check if node has been locked down + if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER) == 0) { + // Node is locked, check if unlock pin is asserted, else hang the node + pinMode(MY_NODE_UNLOCK_PIN, INPUT_PULLUP); + // Make a short delay so we are sure any large external nets are fully pulled + unsigned long enter = hwMillis(); + while (hwMillis() - enter < 2); + if (digitalRead(MY_NODE_UNLOCK_PIN) == 0) { + // Pin is grounded, reset lock counter + hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, MY_NODE_LOCK_COUNTER_MAX); + // Disable pullup + pinMode(MY_NODE_UNLOCK_PIN, INPUT); + setIndication(INDICATION_ERR_LOCKED); + debug(PSTR("Node is unlocked.\n")); + } else { + // Disable pullup + pinMode(MY_NODE_UNLOCK_PIN, INPUT); + nodeLock("LDB"); //Locked during boot + } + } else if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER) == 0xFF) { + // Reset walue hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, MY_NODE_LOCK_COUNTER_MAX); - // Disable pullup - pinMode(MY_NODE_UNLOCK_PIN, INPUT); - debug(PSTR("Node is unlocked.\n")); - } else { - // Disable pullup - pinMode(MY_NODE_UNLOCK_PIN, INPUT); - setIndication(INDICATION_ERR_LOCKED); - nodeLock("LDB"); //Locked during boot } - } else if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER) == 0xFF) { - // Reset walue - hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, MY_NODE_LOCK_COUNTER_MAX); - } -#endif + #endif // Call sketch setup if (setup) setup(); - #if defined(MY_RADIO_FEATURE) - transportPresentNode(); + presentNode(); #endif - if (presentation) - presentation(); + + // register node + _registerNode(); - debug(PSTR("Init complete, id=%d, parent=%d, distance=%d\n"), _nc.nodeId, _nc.parentNodeId, _nc.distance); + debug(PSTR("Init complete, id=%d, parent=%d, distance=%d, registration=%d\n"), _nc.nodeId, _nc.parentNodeId, _nc.distance, _nodeRegistered); } +void _registerNode() { + #if defined (MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE) + debug(PSTR("Request registration...\n")); // registration request + setIndication(INDICATION_REQ_REGISTRATION); + _nodeRegistered = MY_REGISTRATION_DEFAULT; + uint8_t counter = MY_REGISTRATION_RETRIES; + // only proceed if register response received or retries exceeded + do { + _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REGISTRATION_REQUEST, false).set(MY_CORE_VERSION)); + } while (!wait(2000, C_INTERNAL, I_REGISTRATION_RESPONSE) && counter--); + + #else + _nodeRegistered = true; + debug(PSTR("No registration required\n")); + #endif +} + +void presentNode() { + setIndication(INDICATION_PRESENT); + // Present node and request config + #if defined(MY_GATEWAY_FEATURE) + // Send presentation for this gateway device + #if defined(MY_REPEATER_FEATURE) + present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE); + #else + present(NODE_SENSOR_ID, S_ARDUINO_NODE); + #endif + #else + + #if defined(MY_OTA_FIRMWARE_FEATURE) + presentBootloaderInformation(); + #endif + + // Send signing preferences for this node to the GW + signerPresentation(_msgTmp, GATEWAY_ADDRESS); + + // Send presentation for this radio node + #if defined(MY_REPEATER_FEATURE) + present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE); + #else + present(NODE_SENSOR_ID, S_ARDUINO_NODE); + #endif + + // Send a configuration exchange request to controller + // Node sends parent node. Controller answers with latest node configuration + _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CONFIG, false).set(_nc.parentNodeId)); + + // Wait configuration reply. + wait(2000, C_INTERNAL, I_CONFIG); + + #endif + + if (presentation) + presentation(); + +} uint8_t getNodeId() { @@ -220,8 +232,6 @@ ControllerConfig getConfig() { boolean _sendRoute(MyMessage &message) { - // increment heartbeat counter - _heartbeat++; #if defined(MY_CORE_ONLY) (void)message; #endif @@ -241,132 +251,154 @@ boolean _sendRoute(MyMessage &message) { bool send(MyMessage &message, bool enableAck) { message.sender = _nc.nodeId; - mSetCommand(message,C_SET); - mSetRequestAck(message,enableAck); - return _sendRoute(message); -} + mSetCommand(message, C_SET); + mSetRequestAck(message, enableAck); + + #if defined(MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE) + if (_nodeRegistered) { + return _sendRoute(message); + } + else { + debug(PSTR("NODE:!REG\n")); + return false; + } + #else + return _sendRoute(message); + #endif + } void sendBatteryLevel(uint8_t value, bool enableAck) { - _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL, enableAck).set(value)); + _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL, enableAck).set(value)); } void sendHeartbeat(void) { - _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_HEARTBEAT_RESPONSE, false).set(_heartbeat)); - + #if !defined(MY_CORE_ONLY) + _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_HEARTBEAT_RESPONSE, false).set(transportGetHeartbeat())); + #endif } void present(uint8_t childSensorId, uint8_t sensorType, const char *description, bool enableAck) { - _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, enableAck).set(childSensorId==NODE_SENSOR_ID?LIBRARY_VERSION:description)); + _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, enableAck).set(childSensorId==NODE_SENSOR_ID?LIBRARY_VERSION:description)); } void sendSketchInfo(const char *name, const char *version, bool enableAck) { - if (name != NULL) { - _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME, enableAck).set(name)); - } - if (version != NULL) { - _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION, enableAck).set(version)); - } + if (name) _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME, enableAck).set(name)); + if (version) _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION, enableAck).set(version)); } void request(uint8_t childSensorId, uint8_t variableType, uint8_t destination) { - _sendRoute(build(_msg, _nc.nodeId, destination, childSensorId, C_REQ, variableType, false).set("")); + _sendRoute(build(_msgTmp, _nc.nodeId, destination, childSensorId, C_REQ, variableType, false).set("")); } void requestTime() { - _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_TIME, false).set("")); + _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_TIME, false).set("")); } // Message delivered through _msg -void _processInternalMessages() { - bool isMetric; +bool _processInternalMessages() { uint8_t type = _msg.type; - #if !defined(MY_DISABLE_REMOTE_RESET) + if (_msg.sender == GATEWAY_ADDRESS) { if (type == I_REBOOT) { - // Requires MySensors or other bootloader with watchdogs enabled - setIndication(INDICATION_REBOOT); - hwReboot(); - } else - #endif - if (type == I_CONFIG) { - // Pick up configuration from controller (currently only metric/imperial) - // and store it in eeprom if changed - if (_msg.getString() == NULL) { - isMetric = true; - } else { - isMetric = _msg.getString()[0] == 'M'; + #if !defined(MY_DISABLE_REMOTE_RESET) + // Requires MySensors or other bootloader with watchdogs enabled + setIndication(INDICATION_REBOOT); + hwReboot(); + #endif } - _cc.isMetric = isMetric; - hwWriteConfig(EEPROM_CONTROLLER_CONFIG_ADDRESS, isMetric); - } else if (type == I_PRESENTATION) { - if (!mGetAck(_msg)) { + else if (type == I_REGISTRATION_RESPONSE) { + #if defined (MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE) + _nodeRegistered = _msg.getBool(); + setIndication(INDICATION_GOT_REGISTRATION); + debug(PSTR("Node registration=%d\n"), _nodeRegistered); + #endif + } + else if (type == I_CONFIG) { + // Pick up configuration from controller (currently only metric/imperial) and store it in eeprom if changed + _cc.isMetric = _msg.data[0] == 0x00 || _msg.data[0] == 'M'; // metric if null terminated or M + hwWriteConfig(EEPROM_CONTROLLER_CONFIG_ADDRESS, _cc.isMetric); + } + else if (type == I_PRESENTATION) { // Re-send node presentation to controller #if defined(MY_RADIO_FEATURE) - transportPresentNode(); + presentNode(); #endif - if (presentation) - presentation(); } - } else if (type == I_HEARTBEAT) { - sendHeartbeat(); - } else if (type == I_TIME) { - // Deliver time to callback - if (receiveTime) - receiveTime(_msg.getULong()); - } else if (type == I_CHILDREN) { + else if (type == I_HEARTBEAT) { + sendHeartbeat(); + } + else if (type == I_TIME) { + // Deliver time to callback + if (receiveTime) + receiveTime(_msg.getULong()); + } + else if (type == I_CHILDREN) { #if defined(MY_REPEATER_FEATURE) if (_msg.data[0] == 'C') { // Clears child relay data for this node - setIndication(INDICATION_CLEAR_ROUTING); - debug(PSTR("clear routing table\n")); - uint8_t i = 255; - do { - hwWriteConfig(EEPROM_ROUTES_ADDRESS+i, BROADCAST_ADDRESS); - } while (i--); - // Clear parent node id & distance to gw - hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, AUTO); - hwWriteConfig(EEPROM_DISTANCE_ADDRESS, DISTANCE_INVALID); - // Find parent node - transportFindParentNode(); - _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN,false).set("ok")); + setIndication(INDICATION_CLEAR_ROUTING); + transportClearRoutingTable(); + _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN, false).set("ok")); } #endif - } else if (type == I_DEBUG) { - #if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG) - char debug_msg = _msg.data[0]; - if(debug_msg == 'R'){ + } + else if (type == I_DEBUG) { + #if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG) + char debug_msg = _msg.data[0]; + if (debug_msg == 'R') { // routing table #if defined(MY_REPEATER_FEATURE) - // routing table - for(uint8_t cnt=0; cnt!=255;cnt++){ - uint8_t route = hwReadConfig(EEPROM_ROUTES_ADDRESS+cnt); - if (route!=BROADCAST_ADDRESS){ - debug(PSTR("ID: %d via %d\n"),cnt,route); - uint8_t OutBuf[2] = {cnt,route}; - _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG,false).set(OutBuf,2)); - wait(100); + for (uint8_t cnt = 0; cnt != 255; cnt++) { + uint8_t route = hwReadConfig(EEPROM_ROUTES_ADDRESS + cnt); + if (route != BROADCAST_ADDRESS) { + debug(PSTR("ID: %d via %d\n"), cnt, route); + uint8_t OutBuf[2] = { cnt,route }; + _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set(OutBuf, 2)); + wait(200); } } #endif - } else if(debug_msg == 'V'){ - // CPU voltage - _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG,false).set(hwCPUVoltage())); - } else if (debug_msg == 'F') { - // CPU frequency in 1/10Mhz - _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG,false).set(hwCPUFrequency())); - } else if (debug_msg == 'M') { - // free memory - _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG,false).set(hwFreeMem())); - } else if (debug_msg == 'E') { - // clear MySensors eeprom area and reboot - _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN,false).set("ok")); - for (int i=EEPROM_START;i= MY_CORE_MIN_VERSION); + #endif + _sendRoute(build(_msgTmp, _nc.nodeId, _msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REGISTRATION_RESPONSE, false).set(approveRegistration)); + #else + return false; // processing of this request via controller + #endif + #endif + } + else return false; } + return true; } @@ -382,7 +414,7 @@ void wait(unsigned long ms) { unsigned long enter = hwMillis(); while (hwMillis() - enter < ms) { _process(); - #if defined(MY_GATEWAY_ESP8266) + #if defined(ARDUINO_ARCH_ESP8266) yield(); #endif } @@ -395,7 +427,7 @@ bool wait(unsigned long ms, uint8_t cmd, uint8_t msgtype) { bool expectedResponse = false; while ( (hwMillis() - enter < ms) && !expectedResponse ) { _process(); - #if defined(MY_GATEWAY_ESP8266) + #if defined(ARDUINO_ARCH_ESP8266) yield(); #endif expectedResponse = (mGetCommand(_msg) == cmd && _msg.type == msgtype); @@ -420,10 +452,10 @@ int8_t sleep(unsigned long ms) { #if defined(MY_RADIO_FEATURE) transportPowerDown(); #endif - setIndication(INDICATION_SLEEP); + setIndication(INDICATION_SLEEP); const int8_t res = hwSleep(ms); - setIndication(INDICATION_WAKEUP); - return res; + setIndication(INDICATION_WAKEUP); + return res; #endif } @@ -453,10 +485,10 @@ int8_t sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { #if defined(MY_RADIO_FEATURE) transportPowerDown(); #endif - setIndication(INDICATION_SLEEP); + setIndication(INDICATION_SLEEP); const int8_t res = hwSleep(interrupt, mode, ms); - setIndication(INDICATION_WAKEUP); - return res; + setIndication(INDICATION_WAKEUP); + return res; #endif } @@ -488,10 +520,10 @@ int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode #if defined(MY_RADIO_FEATURE) transportPowerDown(); #endif - setIndication(INDICATION_SLEEP); + setIndication(INDICATION_SLEEP); const int8_t res = hwSleep(interrupt1, mode1, interrupt2, mode2, ms); - setIndication(INDICATION_WAKEUP); - return res; + setIndication(INDICATION_WAKEUP); + return res; #endif } @@ -509,19 +541,18 @@ void nodeLock(const char* str) { // Make sure EEPROM is updated to locked status hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, 0); while (1) { - setIndication(INDICATION_ERR_LOCKED); + setIndication(INDICATION_ERR_LOCKED); debug(PSTR("Node is locked. Ground pin %d and reset to unlock.\n"), MY_NODE_UNLOCK_PIN); - #if defined(MY_GATEWAY_ESP8266) + #if defined(ARDUINO_ARCH_ESP8266) yield(); #endif - _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, - C_INTERNAL, I_LOCKED, false).set(str)); + _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID,C_INTERNAL, I_LOCKED, false).set(str)); #if defined(MY_RADIO_FEATURE) transportPowerDown(); #endif - setIndication(INDICATION_SLEEP); + setIndication(INDICATION_SLEEP); (void)hwSleep((unsigned long)1000*60*30); // Sleep for 30 min before resending LOCKED message - setIndication(INDICATION_WAKEUP); + setIndication(INDICATION_WAKEUP); } } #endif diff --git a/libraries/MySensors/core/MySensorsCore.h b/libraries/MySensors/core/MySensorsCore.h index 2e7554d..4f3233e 100644 --- a/libraries/MySensors/core/MySensorsCore.h +++ b/libraries/MySensors/core/MySensorsCore.h @@ -29,15 +29,15 @@ #include #ifdef MY_DEBUG -#define debug(x,...) hwDebugPrint(x, ##__VA_ARGS__) + #define debug(x,...) hwDebugPrint(x, ##__VA_ARGS__) #else -#define debug(x,...) + #define debug(x,...) #endif -// This is the nodeId for sensor net gateway receiver sketch (where all sensors should send their data). -#define GATEWAY_ADDRESS ((uint8_t)0) -// Node child is always created/presented when a node is started -#define NODE_SENSOR_ID 0xFF +#define GATEWAY_ADDRESS ((uint8_t)0) //!< Node ID for GW sketch +#define NODE_SENSOR_ID 0xFF //!< Node child is always created/presented when a node is started +#define MY_CORE_VERSION ((uint8_t)2) //!< core version +#define MY_CORE_MIN_VERSION ((uint8_t)2) //!< min core version required for compatibility /** @@ -72,6 +72,11 @@ uint8_t getNodeId(); */ uint8_t getParentNodeId(); +/** +* Sends node information to the gateway. +*/ +void presentNode(); + /** * Each node must present all attached sensors before any values can be handled correctly by the controller. * It is usually good to present all attached sensors after power-up in setup(). @@ -236,10 +241,12 @@ void _begin(); void _process(void); -void _processInternalMessages(); +bool _processInternalMessages(); void _infiniteLoop(); +void _registerNode(); + boolean _sendRoute(MyMessage &message); extern NodeConfig _nc; diff --git a/libraries/MySensors/core/MyTransport.cpp b/libraries/MySensors/core/MyTransport.cpp index cd83c3e..bbea217 100644 --- a/libraries/MySensors/core/MyTransport.cpp +++ b/libraries/MySensors/core/MyTransport.cpp @@ -1,4 +1,4 @@ -/** +/* * The MySensors Arduino library handles the wireless radio link and protocol * between your home built sensors/actuators and HA controller of choice. * The sensors forms a self healing radio network with optional repeaters. Each @@ -20,65 +20,370 @@ #include "MyTransport.h" -bool _autoFindParent; -uint8_t _failedTransmissions; +// SM: transitions and update states +static State stInit = { stInitTransition, NULL }; +static State stParent = { stParentTransition, stParentUpdate }; +static State stID = { stIDTransition, stIDUpdate }; +static State stUplink = { stUplinkTransition, NULL }; +static State stOK = { stOKTransition, stOKUpdate }; +static State stFailure = { stFailureTransition, stFailureUpdate }; -static inline bool isValidDistance( const uint8_t distance ) { - return distance != DISTANCE_INVALID; +static transportSM _transportSM; + +// stInit: initialize transport HW +void stInitTransition() { + debug(PSTR("TSM:INIT\n")); + // initialize status variables + _transportSM.failedUplinkTransmissions = 0; + _transportSM.pingActive = false; + + // Read node settings (ID, parentId, GW distance) from EEPROM + hwReadConfigBlock((void*)&_nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); + + // initialize radio + if (!transportInit()) { + debug(PSTR("!RADIO:fail\n")); + setIndication(INDICATION_ERR_INIT_TRANSPORT); + transportSwitchSM(stFailure); + } + else { + debug(PSTR("RADIO:OK\n")); + #if defined(MY_GATEWAY_FEATURE) + // Set configuration for gateway + debug(PSTR("TSM:GW MODE\n")); + _nc.parentNodeId = GATEWAY_ADDRESS; + _nc.distance = 0; + _nc.nodeId = GATEWAY_ADDRESS; + transportSetAddress(GATEWAY_ADDRESS); + transportSwitchSM(stOK); + #else + if (MY_NODE_ID != AUTO) { + // Set static id + _nc.nodeId = MY_NODE_ID; + // Save static id in eeprom + hwWriteConfig(EEPROM_NODE_ID_ADDRESS, MY_NODE_ID); + } + // set ID if static or set in EEPROM + if(_nc.nodeId!=AUTO) transportAssignNodeID(_nc.nodeId); + transportSwitchSM(stParent); + #endif + } +} + +// stParent: find parent +void stParentTransition() { + debug(PSTR("TSM:PARENT\n")); + _transportSM.preferredParentFound = false; + _transportSM.findingParentNode = true; + _transportSM.failedUplinkTransmissions = 0; + _transportSM.uplinkOk = false; + // Set distance to max and invalidate parent node id + _nc.distance = DISTANCE_INVALID; + _nc.parentNodeId = AUTO; + // Broadcast find parent request + setIndication(INDICATION_FIND_PARENT); + transportRouteMessage(build(_msgTmp, _nc.nodeId, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT, false).set("")); +} + +// stParentUpdate +void stParentUpdate() { + if (transportTimeInState() > STATE_TIMEOUT || _transportSM.preferredParentFound) { + // timeout or preferred parent found + if (_nc.parentNodeId != AUTO) { + _transportSM.findingParentNode = false; + setIndication(INDICATION_GOT_PARENT); + transportSwitchSM(stID); + } + else if (transportTimeInState() > STATE_TIMEOUT) { + if (_transportSM.retries < STATE_RETRIES) { + // reenter if timeout and retries left + transportSwitchSM(stParent); + } + else { + setIndication(INDICATION_ERR_FIND_PARENT); + transportSwitchSM(stFailure); + } + } + } +} + +// stID: verify and request ID if necessary +void stIDTransition() { + debug(PSTR("TSM:ID\n")); + if (_nc.nodeId == AUTO) { + // send ID request + setIndication(INDICATION_REQ_NODEID); + transportRouteMessage(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_ID_REQUEST, false).set("")); + } +} + +void stIDUpdate() { + if (_nc.nodeId != AUTO) { + // current node ID is valid, proceed to uplink check + debug(PSTR("node ID=%d\n"), _nc.nodeId); + setIndication(INDICATION_GOT_NODEID); + // check uplink + transportSwitchSM(stUplink); + + } + if (transportTimeInState() > STATE_TIMEOUT) { + if (_transportSM.retries < STATE_RETRIES) { + // re-enter if retries left + transportSwitchSM(stID); + } + else { + // fail + setIndication(INDICATION_ERR_GET_NODEID); + transportSwitchSM(stFailure); + } + } +} + +void stUplinkTransition() { + if (transportPingNode(GATEWAY_ADDRESS) == _nc.distance) { + transportSwitchSM(stOK); + } + else transportSwitchSM(stParent); +} + +void stOKTransition() { + debug(PSTR("TSM:OK\n")); + _transportSM.uplinkOk = true; +} + +// stOK update: monitors uplink failures +void stOKUpdate() { + #if !defined(MY_GATEWAY_FEATURE) + if (_transportSM.failedUplinkTransmissions > TRANSMISSION_FAILURES) { + // too many uplink transmissions failed, find new parent + #if !defined(MY_PARENT_NODE_IS_STATIC) + debug(PSTR("!TSM:UPL fail, SNP\n")); + transportSwitchSM(stParent); + #else + debug(PSTR("!TSM:UPL fail, STATP\n")); + _transportSM.failedUplinkTransmissions = 0; + #endif + } + #endif +} + +// stFailure: ented upon HW init failure or max retries exceeded +void stFailureTransition() { + debug(PSTR("!TSM:FAILURE\n")); + _transportSM.uplinkOk = false; + // power down transport, no need until re-init + debug(PSTR("TSM:PDT\n")); + transportPowerDown(); +} + +void stFailureUpdate() { + if (transportTimeInState()> TIMEOUT_FAILURE_STATE) { + transportSwitchSM(stInit); + } +} + +void transportSwitchSM(State& newState) { + if (_transportSM.currentState != &newState) { + // state change, reset retry counter + _transportSM.retries = 0; + // change state + _transportSM.currentState = &newState; + } + else { + _transportSM.retries++; // increment retries + } + // Transition event + if (_transportSM.currentState->Transition) _transportSM.currentState->Transition(); + // save time + _transportSM.stateEnter = hwMillis(); +} + +uint32_t transportTimeInState() { + return hwMillis() - _transportSM.stateEnter; +} + +void transportUpdateSM(){ + if (_transportSM.currentState->Update) _transportSM.currentState->Update(); +} + +bool isTransportOK() { + return (_transportSM.uplinkOk); } -inline void transportProcess() { - uint8_t to = 0; - if (!transportAvailable(&to)) - { - #ifdef MY_OTA_FIRMWARE_FEATURE - firmwareOTAUpdateRequest(); - #endif - return; +void transportInitialize() { + // intial state + _transportSM.currentState = &stFailure; + transportSwitchSM(stInit); +} + +// update TSM and process incoming messages +void transportProcess() { + // update state machine + transportUpdateSM(); + // process transport FIFO + transportProcessFIFO(); +} + + +void transportAssignNodeID(uint8_t newNodeId) { + // verify if ID valid + if (newNodeId != GATEWAY_ADDRESS && newNodeId != AUTO) { + _nc.nodeId = newNodeId; + transportSetAddress(newNodeId); + // Write ID to EEPROM + hwWriteConfig(EEPROM_NODE_ID_ADDRESS, newNodeId); + debug(PSTR("assign node ID=%d\n"),newNodeId); + } + else { + debug(PSTR("node ID invalid (%d)\n"),newNodeId); + setIndication(INDICATION_ERR_NET_FULL); + // Nothing else we can do... + transportSwitchSM(stFailure); + } +} + +bool transportRouteMessage(MyMessage &message) { + uint8_t destination = message.destination; + uint8_t route; + + if (_transportSM.findingParentNode && destination != BROADCAST_ADDRESS) { + debug(PSTR("finding parent active, msg not send\n")); + // request to send a non-BC message while finding parent active, abort + return false; } + if (destination == GATEWAY_ADDRESS) { + route = _nc.parentNodeId; // message to GW always routes via parent + } + else if (destination == BROADCAST_ADDRESS) { + route = BROADCAST_ADDRESS; // message to BC does not require routing + } + else { + #if defined(MY_REPEATER_FEATURE) + // destination not GW & not BC, get route + route = hwReadConfig(EEPROM_ROUTES_ADDRESS + destination); + if (route == AUTO) { + // route unknown + if (message.last != _nc.parentNodeId) { + // message not from parent, i.e. child node - route it to parent + debug(PSTR("Destination %d unknown, send to parent %d\n"), destination, _nc.parentNodeId); + route = _nc.parentNodeId; + } + else { + // route unknown and msg received from parent, send it to destination assuming in rx radius + route = destination; + } + } + #else + route = _nc.parentNodeId; // not a repeater, all traffic routed via parent + #endif + } + // send message + bool ok = transportSendWrite(route, message); + #if !defined(MY_GATEWAY_FEATURE) + // update counter + if (route == _nc.parentNodeId) { + if (!ok) { + setIndication(INDICATION_ERR_TX); + _transportSM.failedUplinkTransmissions++; + } + else _transportSM.failedUplinkTransmissions = 0; + } + #else + if(!ok) setIndication(INDICATION_ERR_TX); + + #endif + + return ok; +} + +bool transportSendRoute(MyMessage &message) { + if (isTransportOK()) { + return transportRouteMessage(message); + } + else { + // TNR: transport not ready + debug(PSTR("!TNR\n")); + return false; + } +} + +// only be used inside transport +bool transportWait(uint32_t ms, uint8_t cmd, uint8_t msgtype){ + uint32_t enter = hwMillis(); + // invalidate msg type + _msg.type = !msgtype; + bool expectedResponse = false; + while ((hwMillis() - enter < ms) && !expectedResponse) { + transportProcess(); + #if defined(ARDUINO_ARCH_ESP8266) + yield(); + #endif + expectedResponse = (mGetCommand(_msg) == cmd && _msg.type == msgtype); + } + return expectedResponse; +} + +uint8_t transportPingNode(uint8_t targetId) { + if(!_transportSM.pingActive){ + if(targetId == _nc.nodeId) { + // ping to ourself + return 0; + } + _transportSM.pingActive = true; + _transportSM.pingResponse = INVALID_HOPS; + debug(PSTR("pinging node %d\n"), targetId); + transportRouteMessage(build(_msgTmp, _nc.nodeId, targetId, NODE_SENSOR_ID, C_INTERNAL, I_PING, false).set((uint8_t)0x01)); + // Wait for ping reply or timeout + transportWait(2000, C_INTERNAL, I_PONG); + return _transportSM.pingResponse; + } + else { + return INVALID_HOPS; + } +} + +void transportClearRoutingTable() { + debug(PSTR("CRT\n")); // clear routing table + for(uint8_t i = 0; i!=255; i++) + hwWriteConfig(EEPROM_ROUTES_ADDRESS+i, BROADCAST_ADDRESS); +} + +uint32_t transportGetHeartbeat() { + return transportTimeInState(); +} + +void transportProcessMessage() { (void)signerCheckTimer(); // Manage signing timeout uint8_t payloadLength = transportReceive((uint8_t *)&_msg); - (void)payloadLength; //until somebody makes use of it + (void)payloadLength; // currently not used, but good to test for CRC-ok but corrupt msgs setIndication(INDICATION_RX); - + // verify protocol version + if(mGetVersion(_msg) != PROTOCOL_VERSION) { + setIndication(INDICATION_ERR_VERSION); + debug(PSTR("!PVER mismatch\n")); + return; + } + + // Reject massages that do not pass verification + if (!signerVerifyMsg(_msg)) { + setIndication(INDICATION_ERR_SIGN); + debug(PSTR("!SIGN verify fail\n")); + return; + } + uint8_t command = mGetCommand(_msg); uint8_t type = _msg.type; uint8_t sender = _msg.sender; uint8_t last = _msg.last; uint8_t destination = _msg.destination; - - // Reject massages that do not pass verification - if (!signerVerifyMsg(_msg)) { - setIndication(INDICATION_ERR_SIGN); - debug(PSTR("verify fail\n")); - return; - } + debug(PSTR("read: %d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d:%s\n"), + sender, last, destination, _msg.sensor, mGetCommand(_msg), type, mGetPayloadType(_msg), mGetLength(_msg), mGetSigned(_msg), _msg.getString(_convBuf)); - if (destination == _nc.nodeId) { - debug(PSTR("read: %d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d:%s\n"), - sender, _msg.last, destination, _msg.sensor, mGetCommand(_msg), type, mGetPayloadType(_msg), mGetLength(_msg), mGetSigned(_msg), _msg.getString(_convBuf)); - } - else - { - #if defined(MY_REPEATER_FEATURE) - debug(PSTR("read and forward: %d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d\n"), - sender, _msg.last, destination, _msg.sensor, mGetCommand(_msg), type, mGetPayloadType(_msg), mGetLength(_msg), mGetSigned(_msg), _msg.getString(_convBuf)); - #else - debug(PSTR("read and drop: %d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d:%s\n"), - sender, _msg.last, destination, _msg.sensor, mGetCommand(_msg), type, mGetPayloadType(_msg), mGetLength(_msg), mGetSigned(_msg), _msg.getString(_convBuf)); - #endif - } - - if(!(mGetVersion(_msg) == PROTOCOL_VERSION)) { - setIndication(INDICATION_ERR_VERSION); - debug(PSTR("ver mismatch\n")); - return; - } if (destination == _nc.nodeId) { // This message is addressed to this node @@ -86,326 +391,215 @@ inline void transportProcess() { mSetLength(_msg, min(mGetLength(_msg),MAX_PAYLOAD)); // null terminate data _msg.data[mGetLength(_msg)] = 0x00; - + + // update routing table if msg not from parent #if defined(MY_REPEATER_FEATURE) - if (_msg.last != _nc.parentNodeId) { + if (last != _nc.parentNodeId) { // Message is from one of the child nodes. Add it to routing table. - hwWriteConfig(EEPROM_ROUTES_ADDRESS+sender, _msg.last); + hwWriteConfig(EEPROM_ROUTES_ADDRESS+sender, last); } #endif // Check if sender requests an ack back. if (mGetRequestAck(_msg)) { - // Copy message - _msgTmp = _msg; - mSetRequestAck(_msgTmp,false); // Reply without ack flag (otherwise we would end up in an eternal loop) - mSetAck(_msgTmp,true); + _msgTmp = _msg; // Copy message + mSetRequestAck(_msgTmp, false); // Reply without ack flag (otherwise we would end up in an eternal loop) + mSetAck(_msgTmp, true); // set ACK flag _msgTmp.sender = _nc.nodeId; _msgTmp.destination = sender; - _sendRoute(_msgTmp); - } + // send ACK + debug(PSTR("ACK msg\n")); + // use transportSendRoute since ACK reply is not internal, i.e. if !transportOK do not reply + transportSendRoute(_msgTmp); + } + if(!mGetAck(_msg)) { + // only process if not ACK + if (command == C_INTERNAL) { + // Process signing related internal messages + if (signerProcessInternal(_msg)) { + return; // Signer processing indicated no further action needed + } + #if !defined(MY_GATEWAY_FEATURE) + if (type == I_ID_RESPONSE) { + #if (MY_NODE_ID == AUTO) + // only active if node ID dynamic + transportAssignNodeID(_msg.getByte()); + #endif + return; // no further processing required + } + if (type == I_FIND_PARENT_RESPONSE) { + #if !defined(MY_GATEWAY_FEATURE) + // Reply to a I_FIND_PARENT message. Check if the distance is shorter than we already have. + uint8_t distance = _msg.getByte(); + debug(PSTR("node %d replied, d=%d, _nc.distance=%d\n"), sender, distance,_nc.distance); + if (isValidDistance(distance)) { + // Distance to gateway is one more for us w.r.t. parent + distance++; + // update settings if distance shorter or preferred parent found + if (((isValidDistance(distance) && distance < _nc.distance) || (!_autoFindParent && sender == MY_PARENT_NODE_ID)) && !_transportSM.preferredParentFound) { + // Found a neighbor closer to GW than previously found + if (!_autoFindParent && sender == MY_PARENT_NODE_ID) { + _transportSM.preferredParentFound = true; + debug(PSTR("preferred parent found\n")); + } + _nc.distance = distance; + _nc.parentNodeId = sender; + debug(PSTR("parent=%d, d=%d\n"), _nc.parentNodeId, _nc.distance); + } + } + return; + #endif + } + #endif + // general + if (type == I_PING) { + debug(PSTR("node pinged by %d, hops=%d\n"), sender, _msg.getByte()); + transportRouteMessage(build(_msgTmp, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_PONG, false).set((uint8_t)0x01)); + return; // no further processing required + } + if (type == I_PONG) { + if (_transportSM.pingActive) { + _transportSM.pingActive = false; + _transportSM.pingResponse = _msg.getByte(); + debug(PSTR("ping replied, hops=%d\n"), _transportSM.pingResponse); + } + return; // no further processing required + } - if (command == C_INTERNAL) { - // Process signing related internal messages - if (signerProcessInternal(_msg)) { - return; // Signer processing indicated no further action needed - } - if (type == I_FIND_PARENT_RESPONSE) { - if (_autoFindParent) { - // 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 - setIndication(INDICATION_GOT_PARENT); - _nc.distance = distance; - _nc.parentNodeId = sender; - hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, _nc.parentNodeId); - hwWriteConfig(EEPROM_DISTANCE_ADDRESS, _nc.distance); - debug(PSTR("parent=%d, d=%d\n"), _nc.parentNodeId, _nc.distance); - } + if (_processInternalMessages()) { + return; // no further processing required + } + } else if (command == C_STREAM) { + #if defined(MY_OTA_FIRMWARE_FEATURE) + if(firmwareOTAUpdateProcess()){ + return; // OTA FW update processing indicated no further action needed } - } - return; - } else if (sender == GATEWAY_ADDRESS) { - if (type == I_ID_RESPONSE) { - _nc.nodeId = _msg.getByte(); - if (_nc.nodeId == AUTO) { - // sensor net gateway will return max id if all sensor id are taken - setIndication(INDICATION_ERR_NET_FULL); - debug(PSTR("full\n")); - // Nothing else we can do... - _infiniteLoop(); - - } - setIndication(INDICATION_GOT_NODEID); - transportPresentNode(); - if (presentation) - presentation(); - // Write id to EEPROM - hwWriteConfig(EEPROM_NODE_ID_ADDRESS, _nc.nodeId); - debug(PSTR("id=%d\n"), _nc.nodeId); - } else { - _processInternalMessages(); - } - return; + #endif } - } else if (command == C_STREAM) { - #if defined(MY_OTA_FIRMWARE_FEATURE) - if(firmwareOTAUpdateProcess()){ - return; // OTA FW update processing indicated no further action needed - } - #endif } #if defined(MY_GATEWAY_FEATURE) // Hand over message to controller gatewayTransportSend(_msg); + #else + // Call incoming message callback if available + if (receive) { + receive(_msg); + } #endif - // Call incoming message callback if available - if (receive) { + return; + } + else if (destination == BROADCAST_ADDRESS) { + // broadcast + debug(PSTR("MSG:BC\n")); + if (command == C_INTERNAL) { + if (isTransportOK()) { + // only reply if node is fully operational + if (type == I_FIND_PARENT) { + #if defined(MY_REPEATER_FEATURE) + if (sender != _nc.parentNodeId) { // no circular reference + debug(PSTR("FPREQ from %d\n"), sender); // FPR: find parent request + // node is in our range, update routing table - important if node has new repeater as parent + hwWriteConfig(EEPROM_ROUTES_ADDRESS + sender, sender); + // check if uplink functional - node can only be parent node if link to GW functional + // this also prevents circular references in case GW ooo + if (transportPingNode(GATEWAY_ADDRESS) != INVALID_HOPS) { // eventually use _nc.distance instead of INVALID_HOPS + // random wait to minimize collisions + debug(PSTR("GWL ok, FPRES to %d\n"), sender); // GW link ok, respond to request + delay(hwMillis() & 0x3ff); + transportRouteMessage(build(_msgTmp, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(_nc.distance)); + } + } + + #endif + return; // no further processing required + } + } + if (type == I_DISCOVER) { + if (last == _nc.parentNodeId) { + // random wait to minimize collisions + delay(hwMillis() & 0x3ff); + transportRouteMessage(build(_msgTmp, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_DISCOVER_RESPONSE, false).set(_nc.parentNodeId)); + // no return here (for fwd if repeater) + } + } + } + // controlled BC relay + #if defined(MY_REPEATER_FEATURE) + // controlled BC repeating: forward only if message received from parent and sender not self to prevent circular fwds + if(last == _nc.parentNodeId && sender != _nc.nodeId && isTransportOK()){ + debug(PSTR("FWD BC msg\n")); // forward BC msg + transportRouteMessage(_msg); + } + #endif + + // Call incoming message callback if available, but only if message received from parent + if (command != C_INTERNAL && last == _nc.parentNodeId && receive) { receive(_msg); } - return; - } else if (destination == BROADCAST_ADDRESS) { - if (command == C_INTERNAL) { - if (type==I_DISCOVER && last==_nc.parentNodeId) { - // only process if received from parent - debug(PSTR("discovery signal\n")); - // random wait to minimize collisions - wait(hwMillis() & 0x3ff); - _sendRoute(build(_msgTmp, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_DISCOVER_RESPONSE, false).set(_nc.parentNodeId)); - // repeat bc signal - #if defined(MY_REPEATER_FEATURE) - // controlled repeating - debug(PSTR("repeat discovery signal\n")); - _sendRoute(_msg); - #endif - return; + + } + else { + // msg not no us and not BC, relay msg + #if defined(MY_REPEATER_FEATURE) + if (isTransportOK()) { + debug(PSTR("REL MSG\n")); // relay msg + // only update routing table to uplink + if (last != _nc.parentNodeId) { + hwWriteConfig(EEPROM_ROUTES_ADDRESS + sender, last); } - } - } - #if defined(MY_REPEATER_FEATURE) - if (_nc.nodeId != AUTO) { - // If this node have an id, relay the message - if (command == C_INTERNAL && type == I_FIND_PARENT) { - if (sender != _nc.parentNodeId) { - if (_nc.distance == DISTANCE_INVALID) - transportFindParentNode(); - - if (_nc.distance != DISTANCE_INVALID) { - // Relaying nodes should always answer ping messages - // Wait a random delay of 0-2 seconds to minimize collision - // between ping ack messages from other relaying nodes - wait(hwMillis() & 0x3ff); - transportSendWrite(sender, build(_msg, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(_nc.distance)); + if (command == C_INTERNAL) { + if (type == I_PING || type == I_PONG) { + uint8_t hopsCnt = _msg.getByte(); + if (hopsCnt != MAX_HOPS) { + debug(PSTR("relay ping/pong, hops=%d\n"), hopsCnt); + _msg.set((uint8_t)(hopsCnt + 1)); } } - } else if (to == _nc.nodeId) { - // We should try to relay this message to another node - _sendRoute(_msg); } + // Relay this message to another node + transportRouteMessage(_msg); + } + #else + debug(PSTR("REL MSG, but not a repeater\n")); + #endif + } +} + +inline void transportProcessFIFO() { + // process all msgs in FIFO + while (transportAvailable()) { + transportProcessMessage(); + } + #if defined(MY_OTA_FIRMWARE_FEATURE) + if (isTransportOK()) { + // only process if transport ok + firmwareOTAUpdateRequest(); } #endif } -boolean transportSendWrite(uint8_t to, MyMessage &message) { - +bool transportSendWrite(uint8_t to, MyMessage &message) { + // set protocol version and update last mSetVersion(message, PROTOCOL_VERSION); - uint8_t length = mGetSigned(message) ? MAX_MESSAGE_LENGTH : mGetLength(message); message.last = _nc.nodeId; - setIndication(INDICATION_TX); + // sign message if required + if (!signerSignMsg(message)) { + debug(PSTR("!sign fail\n")); + setIndication(INDICATION_ERR_SIGN); + } + + // msg length changes if signed + uint8_t length = mGetSigned(message) ? MAX_MESSAGE_LENGTH : mGetLength(message); + + // send + setIndication(INDICATION_TX); bool ok = transportSend(to, &message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length)); - if (!ok) setIndication(INDICATION_ERR_TX); - + debug(PSTR("send: %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d,st=%s:%s\n"), message.sender,message.last, to, message.destination, message.sensor, mGetCommand(message), message.type, mGetPayloadType(message), mGetLength(message), mGetSigned(message), to==BROADCAST_ADDRESS ? "bc" : (ok ? "ok":"fail"), message.getString(_convBuf)); - - return ok; + + return (ok || to==BROADCAST_ADDRESS); } - -boolean transportSendRoute(MyMessage &message) { - #if defined(MY_REPEATER_FEATURE) - uint8_t last = message.last; - #endif - bool ok; - - // If we still don't have any parent id, re-request and skip this message. - if (_nc.parentNodeId == AUTO) { - setIndication(INDICATION_ERR_FIND_PARENT); - transportFindParentNode(); - return false; - } - - // If we still don't have any node id, re-request and skip this message. - if (_nc.nodeId == AUTO) { - setIndication(INDICATION_ERR_GET_NODEID); - transportRequestNodeId(); - return false; - } - - mSetVersion(message, PROTOCOL_VERSION); - - if (!signerSignMsg(message)) { - setIndication(INDICATION_ERR_SIGN); - debug(PSTR("sign fail\n")); - } - - #if !defined(MY_REPEATER_FEATURE) - - // None repeating node... We can only send to our parent - ok = transportSendWrite(_nc.parentNodeId, message); - #else - uint8_t sender = message.sender; - uint8_t dest = message.destination; - if (dest == GATEWAY_ADDRESS) { - // Store this address in routing table (if repeater) - hwWriteConfig(EEPROM_ROUTES_ADDRESS+sender, last); - // If destination is the gateway or if we aren't a repeater, let - // our parent take care of the message - ok = transportSendWrite(_nc.parentNodeId, message); - } else { - // Relay the message - uint8_t route; - // INTERMEDIATE FIX: make sure corrupted routing table is not interfering with BC - observed several cases -tekka - if (dest!=BROADCAST_ADDRESS) { - route = hwReadConfig(EEPROM_ROUTES_ADDRESS+dest); - } else route = BROADCAST_ADDRESS; - if (route > GATEWAY_ADDRESS && route < BROADCAST_ADDRESS) { - // This message should be forwarded to a child node. If we send message - // to this nodes pipe then all children will receive it because the are - // all listening to this nodes pipe. - // - // +----B - // -A - // +----C------D - // - // We're node C, Message comes from A and has destination D - // - // Message destination is not gateway and is in routing table for this node. - // Send it downstream - return transportSendWrite(route, message); - } else if (sender == GATEWAY_ADDRESS && dest == BROADCAST_ADDRESS) { - // Node has not yet received any id. We need to send it - // by doing a broadcast sending, - return transportSendWrite(BROADCAST_ADDRESS, message); - } - #if defined (MY_GATEWAY_FEATURE) - // Destination isn't in our routing table and isn't a broadcast address - // Nothing to do here - debug(PSTR("Destination %d unknown\n"), dest); - return false; - # else - // A message comes from a child node and we have no - // route for it. - // - // +----B - // -A - // +----C------D <-- Message comes from D - // - // We're node C - // - // Message should be passed to node A (this nodes relay) - - // This message should be routed back towards sensor net gateway - ok = transportSendWrite(_nc.parentNodeId, message); - - // Add this child to our "routing table" if it not already exist - hwWriteConfig(EEPROM_ROUTES_ADDRESS+sender, last); - - #endif - } - #endif - - if (!ok) { - // Failure when sending to parent node. The parent node might be down and we - // need to find another route to gateway. - _failedTransmissions++; - if (_autoFindParent && _failedTransmissions > SEARCH_FAILURES) { - transportFindParentNode(); - } - } else { - _failedTransmissions = 0; - } - - return ok; -} - - -void transportRequestNodeId() { - setIndication(INDICATION_REQ_NODEID); - debug(PSTR("req id\n")); - transportSetAddress(_nc.nodeId); - build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_ID_REQUEST, false).set(""); - transportSendWrite(_nc.parentNodeId, _msg); - wait(2000, C_INTERNAL, I_ID_RESPONSE); -} - -void transportPresentNode() { - setIndication(INDICATION_PRESENT); - // Open reading pipe for messages directed to this node (set write pipe to same) - transportSetAddress(_nc.nodeId); - // Present node and request config - #ifdef MY_GATEWAY_FEATURE - // Send presentation for this gateway device - #ifdef MY_REPEATER_FEATURE - present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE); - #else - present(NODE_SENSOR_ID, S_ARDUINO_NODE); - #endif - #else - if (_nc.nodeId != AUTO) { - #ifdef MY_OTA_FIRMWARE_FEATURE - presentBootloaderInformation(); - #endif - // Send signing preferences for this node to the GW - signerPresentation(_msg, GATEWAY_ADDRESS); - - // Send presentation for this radio node - #ifdef MY_REPEATER_FEATURE - present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE); - #else - present(NODE_SENSOR_ID, S_ARDUINO_NODE); - #endif - // Send a configuration exchange request to controller - // Node sends parent node. Controller answers with latest node configuration - // which is picked up in process() - _sendRoute(build(_msg, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CONFIG, false).set(_nc.parentNodeId)); - - // Wait configuration reply. - wait(2000, C_INTERNAL, I_CONFIG); - } - #endif -} - -void transportFindParentNode() { - static boolean findingParentNode = false; - - if (findingParentNode) - return; - findingParentNode = true; - - setIndication(INDICATION_FIND_PARENT); - - _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) - debug(PSTR("find parent\n")); - - build(_msg, _nc.nodeId, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT, false).set(""); - // Write msg, but suppress recursive parent search - transportSendWrite(BROADCAST_ADDRESS, _msg); - - // Wait for ping response. - wait(2000); - findingParentNode = false; -} diff --git a/libraries/MySensors/core/MyTransport.h b/libraries/MySensors/core/MyTransport.h index d3085f7..4530a45 100644 --- a/libraries/MySensors/core/MyTransport.h +++ b/libraries/MySensors/core/MyTransport.h @@ -17,43 +17,228 @@ * version 2 as published by the Free Software Foundation. */ + /** + * @file MyTransport.h + * + * @brief API declaration for MyTransport + */ #ifndef MyTransport_h #define MyTransport_h -#include #include "MySensorsCore.h" -// Search for a new parent node after this many transmission failures -#define SEARCH_FAILURES 5 +#define TRANSMISSION_FAILURES 5 //!< search for a new parent node after this many transmission failures +#define TIMEOUT_FAILURE_STATE 10000 //!< duration failure state +#define STATE_TIMEOUT 2000 //!< general state timeout +#define STATE_RETRIES 3 //!< retries before switching to FAILURE +#define AUTO 255 //!< ID 255 is reserved for auto initialization of nodeId. +#define BROADCAST_ADDRESS ((uint8_t)255) //!< broadcasts are addressed to ID 255 +#define DISTANCE_INVALID ((uint8_t)255) //!< invalid distance when searching for parent +#define MAX_HOPS ((uint8_t)254) //!< maximal mumber of hops for ping/pong +#define INVALID_HOPS ((uint8_t)255) //!< invalid hops -#define AUTO 0xFF // 0-254. Id 255 is reserved for auto initialization of nodeId. +#define _autoFindParent (bool)(MY_PARENT_NODE_ID == AUTO) //!< returns true if static parent id is undefined +#define isValidDistance(distance) (bool)(distance!=DISTANCE_INVALID) //!< returns true if distance is valid +#define isValidParent(parent) (bool)(parent != AUTO) //!< returns true if parent is valid -#define BROADCAST_ADDRESS ((uint8_t)0xFF) + /** + * @brief SM state + * + * This structure stores SM state definitions + */ +struct State { + void(*Transition)(); //!< state transition function + void(*Update)(); //!< state update function +}; -// invalid distance when searching for parent -#define DISTANCE_INVALID (0xFF) - -// Common functions in all radio drivers -#ifdef MY_OTA_FIRMWARE_FEATURE - // do a crc16 on the whole received firmware - bool transportIsValidFirmware(); -#endif +/** +* @brief Status variables and SM state +* +* This structure stores transport status and SM variables +*/ +typedef struct { + State* currentState; //!< pointer to current fsm state + uint32_t stateEnter; //!< state enter timepoint + bool findingParentNode : 1; //!< flag finding parent node is active + bool preferredParentFound : 1; //!< flag preferred parent found + bool uplinkOk : 1; //!< flag uplink ok + bool pingActive : 1; //!< flag ping active + uint8_t reserved : 4; //!< reserved + uint8_t retries : 4; //!< retries / state re-enter + uint8_t failedUplinkTransmissions : 4; //!< counter failed uplink transmissions + uint8_t pingResponse; //!< stores hops received in I_PONG +} __attribute__((packed)) transportSM; +// PRIVATE functions + +/** +* @brief Initialize SM variables and transport HW +*/ +void stInitTransition(); +/** +* @brief Find parent +*/ +void stParentTransition(); +/** +* @brief Verify find parent responses +*/ +void stParentUpdate(); +/** +* @brief Send ID request +*/ +void stIDTransition(); +/** +* @brief Verify ID response and GW link +*/ +void stIDUpdate(); +/** +* @brief Send uplink ping request +*/ +void stUplinkTransition(); +/** +* @brief Set transport OK +*/ +void stOKTransition(); +/** +* @brief Monitor transport link +*/ +void stOKUpdate(); +/** +* @brief Transport failure and power down radio +*/ +void stFailureTransition(); +/** +* @brief Re-initialize transport after timeout +*/ +void stFailureUpdate(); +/** +* @brief Switch SM state +* @param newState New state to switch SM to +*/ +void transportSwitchSM(State& newState); +/** +* @brief Update SM state +*/ +void transportUpdateSM(); +/** +* @brief Request time in current SM state +* @return ms in current state +*/ +uint32_t transportTimeInState(); + +/** +* @brief Process all pending messages in RX FIFO +*/ +void transportProcessFIFO(); +/** +* @brief Receive message from RX FIFO and process +*/ +void transportProcessMessage(); +/** +* @brief Assign node ID +* @param newNodeId New node ID +*/ +void transportAssignNodeID(uint8_t newNodeId); +/** +* @brief Wait and process messages for a defined amount of time until specified message received +* @param ms Time to wait and process incoming messages in ms +* @param cmd Specific command +* @param msgtype Specific message type +* @return true if specified command received within waiting time +*/ +bool transportWait(uint32_t ms, uint8_t cmd, uint8_t msgtype); +/** +* @brief Ping node +* @param targetId Node to be pinged +* @return hops from pinged node or 255 if no answer received within 2000ms +*/ +uint8_t transportPingNode(uint8_t targetId); +/** +* @brief Send and route message according to destination +* +* This function is used in MyTransport and omits the transport state check, i.e. message can be sent even if transport is !OK +* +* @param message +* @return true if message sent successfully +*/ +bool transportRouteMessage(MyMessage &message); +/** +* @brief Send and route message according to destination with transport state check +* @param message +* @return true if message sent successfully and false if sending error or transport !OK +*/ +bool transportSendRoute(MyMessage &message); +/** +* @brief Send message to recipient +* @param to Recipient of message +* @param message +* @return true if message sent successfully +*/ +bool transportSendWrite(uint8_t to, MyMessage &message); + +// PUBLIC functions + +/** +* @brief Initialize transport and SM +*/ +void transportInitialize(); +/** +* @brief Process FIFO msg and update SM +*/ void transportProcess(); -void transportRequestNodeId(); -void transportPresentNode(); -void transportFindParentNode(); -boolean transportSendRoute(MyMessage &message); -boolean transportSendWrite(uint8_t to, MyMessage &message); +/** +* @brief Verify transport status +* @return true if transport is initialize and ready +*/ +bool isTransportOK(); +/** +* @brief Clear routing table +*/ +void transportClearRoutingTable(); +/** +* @brief Return heart beat, i.e. ms in current state +*/ +uint32_t transportGetHeartbeat(); -// "Interface" functions for radio driver +// interface functions for radio driver + +/** +* @brief Initialize transport HW +* @return true if initalization successful +*/ bool transportInit(); +/** +* @brief Set node address +*/ void transportSetAddress(uint8_t address); +/** +* @brief Retrieve node address +*/ uint8_t transportGetAddress(); +/** +* @brief Send message +* @param to recipient +* @param data message to be sent +* @param len length of message (header + payload) +* @return true if message sent successfully +*/ bool transportSend(uint8_t to, const void* data, uint8_t len); -bool transportAvailable(uint8_t *to); -uint8_t transportReceive(void* data); +/** +* @brief Verify if RX FIFO has pending messages +* @return true if message available in RX FIFO +*/ +bool transportAvailable(); +/** +* @brief Receive message from FIFO +* @return length of recevied message (header + payload) +*/ +uint8_t transportReceive(void* data); +/** +* @brief Power down transport HW +*/ void transportPowerDown(); -#endif + +#endif // MyTransport_h +/** @}*/ diff --git a/libraries/MySensors/core/MyTransportNRF24.cpp b/libraries/MySensors/core/MyTransportNRF24.cpp index 47adf56..3db404c 100644 --- a/libraries/MySensors/core/MyTransportNRF24.cpp +++ b/libraries/MySensors/core/MyTransportNRF24.cpp @@ -1,4 +1,4 @@ -/** +/* * The MySensors Arduino library handles the wireless radio link and protocol * between your home built sensors/actuators and HA controller of choice. * The sensors forms a self healing radio network with optional repeaters. Each @@ -70,8 +70,8 @@ bool transportSend(uint8_t recipient, const void* data, uint8_t len) { return status; } -bool transportAvailable(uint8_t *to) { - bool avail = RF24_isDataAvailable(to); +bool transportAvailable() { + bool avail = RF24_isDataAvailable(); return avail; } diff --git a/libraries/MySensors/core/MyTransportRFM69.cpp b/libraries/MySensors/core/MyTransportRFM69.cpp index 7f69460..776b2ae 100644 --- a/libraries/MySensors/core/MyTransportRFM69.cpp +++ b/libraries/MySensors/core/MyTransportRFM69.cpp @@ -1,4 +1,4 @@ -/** +/* * The MySensors Arduino library handles the wireless radio link and protocol * between your home built sensors/actuators and HA controller of choice. * The sensors forms a self healing radio network with optional repeaters. Each @@ -53,11 +53,7 @@ bool transportSend(uint8_t to, const void* data, uint8_t len) { return _radio.sendWithRetry(to,data,len); } -bool transportAvailable(uint8_t *to) { - if (_radio.TARGETID == BROADCAST_ADDRESS) - *to = BROADCAST_ADDRESS; - else - *to = _address; +bool transportAvailable() { return _radio.receiveDone(); } diff --git a/libraries/MySensors/core/MyTransportRS485.cpp b/libraries/MySensors/core/MyTransportRS485.cpp index dff19b2..8b62dc6 100644 --- a/libraries/MySensors/core/MyTransportRS485.cpp +++ b/libraries/MySensors/core/MyTransportRS485.cpp @@ -1,4 +1,4 @@ -/** +/* * The MySensors Arduino library handles the wireless radio link and protocol * between your home built sensors/actuators and HA controller of choice. * The sensors forms a self healing radio network with optional repeaters. Each @@ -332,14 +332,8 @@ uint8_t transportGetAddress() { } -bool transportAvailable(uint8_t *to) { +bool transportAvailable() { _serialProcess(); - if (_packet_received == true) { - if (_recStation==BROADCAST_ADDRESS) { - *to = BROADCAST_ADDRESS; - } - else { *to = _nodeId; } - } return _packet_received; } diff --git a/libraries/MySensors/drivers/RF24/RF24.cpp b/libraries/MySensors/drivers/RF24/RF24.cpp index c65a673..0378107 100644 --- a/libraries/MySensors/drivers/RF24/RF24.cpp +++ b/libraries/MySensors/drivers/RF24/RF24.cpp @@ -216,16 +216,12 @@ LOCAL uint8_t RF24_getDynamicPayloadSize(void) { } -LOCAL bool RF24_isDataAvailable(uint8_t* to) { +LOCAL bool RF24_isDataAvailable() { uint8_t pipe_num = ( RF24_getStatus() >> RX_P_NO ) & 0b0111; - #if defined(MY_DEBUG_VERBOSE_RF24) + #if defined(MY_DEBUG_VERBOSE_RF24) && defined(MY_DEBUG) if(pipe_num <= 5) RF24_DEBUG(PSTR("Data available on pipe %d\n"),pipe_num); #endif - if (pipe_num == NODE_PIPE) - *to = MY_RF24_NODE_ADDRESS; - else if (pipe_num == BROADCAST_PIPE) - *to = BROADCAST_ADDRESS; return (pipe_num <= 5); } diff --git a/libraries/MySensors/drivers/RF24/RF24.h b/libraries/MySensors/drivers/RF24/RF24.h index c4b6a50..744020f 100644 --- a/libraries/MySensors/drivers/RF24/RF24.h +++ b/libraries/MySensors/drivers/RF24/RF24.h @@ -228,7 +228,7 @@ LOCAL void RF24_stopListening(void); LOCAL void RF24_powerDown(void); LOCAL bool RF24_sendMessage(uint8_t recipient, const void* buf, uint8_t len); LOCAL uint8_t RF24_getDynamicPayloadSize(void); -LOCAL bool RF24_isDataAvailable(uint8_t* to); +LOCAL bool RF24_isDataAvailable(); LOCAL uint8_t RF24_readMessage(void* buf); LOCAL void RF24_setNodeAddress(uint8_t address); LOCAL uint8_t RF24_getNodeID(void); diff --git a/libraries/MySensors/keywords.txt b/libraries/MySensors/keywords.txt index a92d3b3..d8ca7d5 100644 --- a/libraries/MySensors/keywords.txt +++ b/libraries/MySensors/keywords.txt @@ -41,8 +41,13 @@ MY_REPEATER_FEATURE LITERAL1 MY_RADIO_NRF24 LITERAL1 MY_RADIO_RFM69 LITERAL1 MY_BAUD_RATE LITERAL1 +MY_REGISTRATION_FEATURE LITERAL1 +MY_REGISTRATION_DEFAULT LITERAL1 +MY_REGISTRATION_CONTROLLER LITERAL1 +MY_CORE_COMPATIBILITY_CHECK LITERAL1 MY_NODE_ID LITERAL1 MY_PARENT_NODE_ID LITERAL1 +MY_PARENT_NODE_IS_STATIC LITERAL1 MY_OTA_FIRMWARE_FEATURE LITERAL1 MY_OTA_FLASH_SS LITERAL1 MY_OTA_FLASH_JDECID LITERAL1