123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763 |
- /*
- * 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
- * repeater and gateway builds a routing tables in EEPROM which keeps track of the
- * network topology allowing messages to be routed to nodes.
- *
- * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
- * Copyright (C) 2013-2018 Sensnology AB
- * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
- *
- * Documentation: http://www.mysensors.org
- * Support Forum: http://forum.mysensors.org
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- */
-
- #include "MySensorsCore.h"
-
- #if defined(__linux__)
- #include <stdlib.h>
- #include <unistd.h>
- #endif
-
- // debug output
- #if defined(MY_DEBUG_VERBOSE_CORE)
- #define CORE_DEBUG(x,...) DEBUG_OUTPUT(x, ##__VA_ARGS__) //!< debug
- #else
- #define CORE_DEBUG(x,...) //!< debug NULL
- #endif
-
- // message buffers
-
- MyMessage _msg; // Buffer for incoming messages
- MyMessage _msgTmp; // Buffer for temporary messages (acks and nonces among others)
-
- // core configuration
- static coreConfig_t _coreConfig;
-
- #if defined(DEBUG_OUTPUT_ENABLED)
- char _convBuf[MAX_PAYLOAD*2+1];
- #endif
-
- // Callback for transport=ok transition
- void _callbackTransportReady(void)
- {
- if (!_coreConfig.presentationSent) {
- #if !defined(MY_GATEWAY_FEATURE) // GW calls presentNode() when client connected
- presentNode();
- #endif
- _registerNode();
- _coreConfig.presentationSent = true;
- }
- }
-
- void _process(void)
- {
- doYield();
-
- #if defined(MY_INCLUSION_MODE_FEATURE)
- inclusionProcess();
- #endif
-
- #if defined(MY_GATEWAY_FEATURE)
- gatewayTransportProcess();
- #endif
-
- #if defined(MY_SENSOR_NETWORK)
- transportProcess();
- #endif
-
- #if defined(__linux__)
- // To avoid high cpu usage
- usleep(10000); // 10ms
- #endif
- }
-
- void _infiniteLoop(void)
- {
- while(1) {
- doYield();
- #if defined(__linux__)
- exit(1);
- #endif
- }
- }
-
- void _begin(void)
- {
- #if defined(MY_CORE_ONLY)
- // initialize HW and run setup if present
- (void)hwInit();
- if (setup) {
- setup();
- }
- return;
- #endif
- // reset wdt
- hwWatchdogReset();
-
- if (preHwInit) {
- preHwInit();
- }
-
- const bool hwInitResult = hwInit();
-
- #if !defined(MY_SPLASH_SCREEN_DISABLED) && !defined(MY_GATEWAY_FEATURE)
- displaySplashScreen();
- #endif
-
- CORE_DEBUG(PSTR("MCO:BGN:INIT " MY_NODE_TYPE ",CP=" MY_CAPABILITIES ",REL=%" PRIu8 ",VER="
- MYSENSORS_LIBRARY_VERSION "\n"), MYSENSORS_LIBRARY_VERSION_PRERELEASE_NUMBER);
- if (!hwInitResult) {
- CORE_DEBUG(PSTR("!MCO:BGN:HW ERR\n"));
- setIndication(INDICATION_ERR_HW_INIT);
- _infiniteLoop();
- }
-
- // set defaults
- _coreConfig.presentationSent = false;
-
- // Call sketch before() (if defined)
- if (before) {
- CORE_DEBUG(PSTR("MCO:BGN:BFR\n")); // before callback
- before();
- }
-
- #if defined(MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN)
- ledsInit();
- #endif
-
- signerInit();
-
- // Read latest received controller configuration from EEPROM
- // Note: _coreConfig.isMetric is bool, hence empty EEPROM (=0xFF) evaluates to true (default)
- hwReadConfigBlock((void*)&_coreConfig.controllerConfig, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS,
- sizeof(controllerConfig_t));
-
- #if defined(MY_OTA_FIRMWARE_FEATURE)
- // Read firmware config from EEPROM, i.e. type, version, CRC, blocks
- readFirmwareSettings();
- #endif
-
- #if defined(MY_SENSOR_NETWORK)
- // Save static parent ID in eeprom (used by bootloader)
- hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, MY_PARENT_NODE_ID);
- // Initialise transport layer
- transportInitialise();
- // Register transport=ready callback
- transportRegisterReadyCallback(_callbackTransportReady);
- // wait until transport is ready
- (void)transportWaitUntilReady(MY_TRANSPORT_WAIT_READY_MS);
- #endif
-
- _checkNodeLock();
-
- #if defined(MY_GATEWAY_FEATURE)
- #if defined(MY_INCLUSION_BUTTON_FEATURE)
- inclusionInit();
- #endif
-
- // initialise the transport driver
- if (!gatewayTransportInit()) {
- setIndication(INDICATION_ERR_INIT_GWTRANSPORT);
- CORE_DEBUG(PSTR("!MCO:BGN:TSP FAIL\n"));
- // Nothing more we can do
- _infiniteLoop();
- }
- #endif
-
- // Call sketch setup() (if defined)
- if (setup) {
- CORE_DEBUG(PSTR("MCO:BGN:STP\n")); // setup callback
- setup();
- }
- #if defined(MY_SENSOR_NETWORK)
- CORE_DEBUG(PSTR("MCO:BGN:INIT OK,TSP=%" PRIu8 "\n"), isTransportReady() && transportSanityCheck());
- #else
- // no sensor network defined, call presentation & registration
- _callbackTransportReady();
- CORE_DEBUG(PSTR("MCO:BGN:INIT OK,TSP=NA\n"));
- #endif
- // reset wdt before handing over to loop
- hwWatchdogReset();
- }
-
-
- void _registerNode(void)
- {
- #if defined (MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE)
- CORE_DEBUG(PSTR("MCO:REG:REQ\n")); // registration request
- setIndication(INDICATION_REQ_REGISTRATION);
- _coreConfig.nodeRegistered = MY_REGISTRATION_DEFAULT;
- uint8_t counter = MY_REGISTRATION_RETRIES;
- // only proceed if register response received or retries exceeded
- do {
- (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL,
- I_REGISTRATION_REQUEST).set(MY_CORE_VERSION));
- } while (!wait(2000, C_INTERNAL, I_REGISTRATION_RESPONSE) && counter--);
- #else
- _coreConfig.nodeRegistered = true;
- CORE_DEBUG(PSTR("MCO:REG:NOT NEEDED\n"));
- #endif
- }
-
- void presentNode(void)
- {
- setIndication(INDICATION_PRESENT);
- // Present node and request config
- #if defined(MY_GATEWAY_FEATURE)
- // Send presentation for this gateway device
- #if defined(MY_REPEATER_FEATURE)
- (void)present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE);
- #else
- (void)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)
- (void)present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE);
- #else
- (void)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
- (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL,
- I_CONFIG).set(getParentNodeId()));
-
- // Wait configuration reply.
- (void)wait(2000, C_INTERNAL, I_CONFIG);
-
- #endif
-
- if (presentation) {
- presentation();
- }
- }
-
-
- uint8_t getNodeId(void)
- {
- uint8_t result;
- #if defined(MY_GATEWAY_FEATURE)
- result = GATEWAY_ADDRESS;
- #elif defined(MY_SENSOR_NETWORK)
- result = transportGetNodeId();
- #else
- result = VALUE_NOT_DEFINED;
- #endif
- return result;
- }
-
- uint8_t getParentNodeId(void)
- {
- uint8_t result;
- #if defined(MY_GATEWAY_FEATURE)
- result = VALUE_NOT_DEFINED; // GW doesn't have a parent
- #elif defined(MY_SENSOR_NETWORK)
- result = transportGetParentNodeId();
- #else
- result = VALUE_NOT_DEFINED;
- #endif
- return result;
- }
-
- uint8_t getDistanceGW(void)
- {
- uint8_t result;
- #if defined(MY_GATEWAY_FEATURE)
- result = 0;
- #elif defined(MY_SENSOR_NETWORK)
- result = transportGetDistanceGW();
- #else
- result = VALUE_NOT_DEFINED;
- #endif
- return result;
- }
-
- controllerConfig_t getControllerConfig(void)
- {
- return _coreConfig.controllerConfig;
- }
-
-
- bool _sendRoute(MyMessage &message)
- {
- #if defined(MY_CORE_ONLY)
- (void)message;
- #endif
- #if defined(MY_GATEWAY_FEATURE)
- if (message.destination == getNodeId()) {
- // This is a message sent from a sensor attached on the gateway node.
- // Pass it directly to the gateway transport layer.
- return gatewayTransportSend(message);
- }
- #endif
- #if defined(MY_SENSOR_NETWORK)
- return transportSendRoute(message);
- #else
- return false;
- #endif
- }
-
- bool send(MyMessage &message, const bool enableAck)
- {
- message.sender = getNodeId();
- mSetCommand(message, C_SET);
- mSetRequestAck(message, enableAck);
-
- #if defined(MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE)
- if (_coreConfig.nodeRegistered) {
- return _sendRoute(message);
- } else {
- CORE_DEBUG(PSTR("!MCO:SND:NODE NOT REG\n")); // node not registered
- return false;
- }
- #else
- return _sendRoute(message);
- #endif
- }
-
- bool sendBatteryLevel(const uint8_t value, const bool ack)
- {
- return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL,
- ack).set(value));
- }
-
- bool sendHeartbeat(const bool ack)
- {
- #if defined(MY_SENSOR_NETWORK)
- const uint32_t heartbeat = transportGetHeartbeat();
- return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_HEARTBEAT_RESPONSE,
- ack).set(heartbeat));
- #else
- (void)ack;
- return false;
- #endif
- }
-
-
-
- bool present(const uint8_t childSensorId, const uint8_t sensorType, const char *description,
- const bool ack)
- {
- return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType,
- ack).set(childSensorId == NODE_SENSOR_ID ? MYSENSORS_LIBRARY_VERSION : description));
- }
-
- #if !defined(__linux__)
- bool present(const uint8_t childSensorId, const uint8_t sensorType,
- const __FlashStringHelper *description,
- const bool ack)
- {
- return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType,
- ack).set(childSensorId == NODE_SENSOR_ID ? F(" MYSENSORS_LIBRARY_VERSION "): description));
- }
- #endif
-
-
- bool sendSketchInfo(const char *name, const char *version, const bool ack)
- {
- bool result = true;
- if (name) {
- result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME,
- ack).set(name));
- }
- if (version) {
- result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION,
- ack).set(version));
- }
- return result;
- }
-
- #if !defined(__linux__)
- bool sendSketchInfo(const __FlashStringHelper *name, const __FlashStringHelper *version,
- const bool ack)
- {
- bool result = true;
- if (name) {
- result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME,
- ack).set(name));
- }
- if (version) {
- result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION,
- ack).set(version));
- }
- return result;
- }
- #endif
-
- bool request(const uint8_t childSensorId, const uint8_t variableType, const uint8_t destination)
- {
- return _sendRoute(build(_msgTmp, destination, childSensorId, C_REQ, variableType).set(""));
- }
-
- bool requestTime(const bool ack)
- {
- return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_TIME, ack).set(""));
- }
-
- // Message delivered through _msg
- bool _processInternalCoreMessage(void)
- {
- const uint8_t type = _msg.type;
- if (_msg.sender == GATEWAY_ADDRESS) {
- if (type == I_REBOOT) {
- #if !defined(MY_DISABLE_REMOTE_RESET)
- setIndication(INDICATION_REBOOT);
- // WDT fuse should be enabled
- hwReboot();
- #endif
- } else if (type == I_REGISTRATION_RESPONSE) {
- #if defined (MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE)
- _coreConfig.nodeRegistered = _msg.getBool();
- setIndication(INDICATION_GOT_REGISTRATION);
- CORE_DEBUG(PSTR("MCO:PIM:NODE REG=%" PRIu8 "\n"), _coreConfig.nodeRegistered); // node registration
- #endif
- } else if (type == I_CONFIG) {
- // Pick up configuration from controller (currently only metric/imperial) and store it in eeprom if changed
- _coreConfig.controllerConfig.isMetric = _msg.data[0] == 0x00 ||
- _msg.data[0] == 'M'; // metric if null terminated or M
- hwWriteConfigBlock((void*)&_coreConfig.controllerConfig, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS,
- sizeof(controllerConfig_t));
- } else if (type == I_PRESENTATION) {
- // Re-send node presentation to controller
- presentNode();
- } else if (type == I_HEARTBEAT_REQUEST) {
- (void)sendHeartbeat();
- } else if (_msg.type == I_VERSION) {
- #if !defined(MY_GATEWAY_FEATURE)
- (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL,
- I_VERSION).set(MYSENSORS_LIBRARY_VERSION_INT));
- #endif
- } else if (type == I_TIME) {
- // Deliver time to callback
- if (receiveTime) {
- receiveTime(_msg.getULong());
- }
- } else if (type == I_CHILDREN) {
- if (_msg.data[0] == 'C') {
- #if defined(MY_REPEATER_FEATURE) && defined(MY_SENSOR_NETWORK)
- // Clears child relay data for this node
- setIndication(INDICATION_CLEAR_ROUTING);
- transportClearRoutingTable();
- (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN).set("OK"));
- #endif
- }
- } else if (type == I_DEBUG) {
- #if defined(MY_SPECIAL_DEBUG)
- const char debug_msg = _msg.data[0];
- if (debug_msg == 'R') { // routing table
- #if defined(MY_REPEATER_FEATURE) && defined(MY_SENSOR_NETWORK)
- transportReportRoutingTable();
- #endif
- } else if (debug_msg == 'V') { // CPU voltage
- (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL,
- I_DEBUG).set(hwCPUVoltage()));
- } else if (debug_msg == 'F') { // CPU frequency in 1/10Mhz
- (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL,
- I_DEBUG).set(hwCPUFrequency()));
- } else if (debug_msg == 'M') { // free memory
- (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL,
- I_DEBUG).set(hwFreeMem()));
- } else if (debug_msg == 'E') { // clear MySensors eeprom area and reboot
- (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG).set("OK"));
- for (uint16_t i = EEPROM_START; i<EEPROM_LOCAL_CONFIG_ADDRESS; i++) {
- hwWriteConfig(i, 0xFF);
- }
- setIndication(INDICATION_REBOOT);
- hwReboot();
- }
- #endif
- } else {
- return false; // further processing required
- }
- } else {
- // sender is a node
- if (type == I_REGISTRATION_REQUEST) {
- #if defined(MY_GATEWAY_FEATURE)
- // registration requests are exclusively handled by GW/Controller
- #if !defined(MY_REGISTRATION_CONTROLLER)
- bool approveRegistration;
-
- #if defined(MY_CORE_COMPATIBILITY_CHECK)
- approveRegistration = (_msg.getByte() >= MY_CORE_MIN_VERSION);
- #else
- // auto registration if version compatible
- approveRegistration = true;
- #endif
-
- #if (F_CPU>16000000)
- // delay for fast GW and slow nodes
- delay(5);
- #endif
- (void)_sendRoute(build(_msgTmp, _msg.sender, NODE_SENSOR_ID, C_INTERNAL,
- I_REGISTRATION_RESPONSE).set(approveRegistration));
- #else
- return false; // processing of this request via controller
- #endif
- #endif
- } else {
- return false; // further processing required
- }
- }
- return true; // if not GW or no further processing required
- }
-
-
- void saveState(const uint8_t pos, const uint8_t value)
- {
- hwWriteConfig(EEPROM_LOCAL_CONFIG_ADDRESS+pos, value);
- }
- uint8_t loadState(const uint8_t pos)
- {
- return hwReadConfig(EEPROM_LOCAL_CONFIG_ADDRESS+pos);
- }
-
-
- void wait(const uint32_t waitingMS)
- {
- const uint32_t enteringMS = hwMillis();
- while (hwMillis() - enteringMS < waitingMS) {
- _process();
- }
- }
-
- bool wait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t msgType)
- {
- const uint32_t enteringMS = hwMillis();
- // invalidate msg type
- _msg.type = !msgType;
- bool expectedResponse = false;
- while ( (hwMillis() - enteringMS < waitingMS) && !expectedResponse ) {
- _process();
- expectedResponse = (mGetCommand(_msg) == cmd && _msg.type == msgType);
- }
- return expectedResponse;
- }
-
- void doYield(void)
- {
- hwWatchdogReset();
-
- yield();
-
- #if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN)
- ledsProcess();
- #endif
- }
-
- int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep, const uint8_t interrupt1,
- const uint8_t mode1, const uint8_t interrupt2, const uint8_t mode2)
- {
- CORE_DEBUG(PSTR("MCO:SLP:MS=%" PRIu32 ",SMS=%" PRIu8 ",I1=%" PRIu8 ",M1=%" PRIu8 ",I2=%" PRIu8
- ",M2=%" PRIu8 "\n"), sleepingMS, smartSleep,
- interrupt1, mode1, interrupt2, mode2);
- // repeater feature: sleeping not possible
- #if defined(MY_REPEATER_FEATURE)
- (void)smartSleep;
- (void)interrupt1;
- (void)mode1;
- (void)interrupt2;
- (void)mode2;
-
- CORE_DEBUG(PSTR("!MCO:SLP:REP\n")); // sleeping not possible, repeater feature enabled
- wait(sleepingMS);
- return MY_SLEEP_NOT_POSSIBLE;
- #else
- uint32_t sleepingTimeMS = sleepingMS;
- #if defined(MY_SENSOR_NETWORK)
- // Do not sleep if transport not ready
- if (!isTransportReady()) {
- CORE_DEBUG(PSTR("!MCO:SLP:TNR\n")); // sleeping not possible, transport not ready
- const uint32_t sleepEnterMS = hwMillis();
- uint32_t sleepDeltaMS = 0;
- while (!isTransportReady() && (sleepDeltaMS < sleepingTimeMS) &&
- (sleepDeltaMS < MY_SLEEP_TRANSPORT_RECONNECT_TIMEOUT_MS)) {
- _process();
- sleepDeltaMS = hwMillis() - sleepEnterMS;
- }
- // sleep remainder
- if (sleepDeltaMS < sleepingTimeMS) {
- sleepingTimeMS -= sleepDeltaMS; // calculate remaining sleeping time
- CORE_DEBUG(PSTR("MCO:SLP:MS=%" PRIu32 "\n"), sleepingTimeMS);
- } else {
- // no sleeping time left
- return MY_SLEEP_NOT_POSSIBLE;
- }
- }
- // OTA FW feature: do not sleep if FW update ongoing
- #if defined(MY_OTA_FIRMWARE_FEATURE)
- while (isFirmwareUpdateOngoing() && sleepingTimeMS) {
- CORE_DEBUG(PSTR("!MCO:SLP:FWUPD\n")); // sleeping not possible, FW update ongoing
- wait(1000ul);
- sleepingTimeMS = sleepingTimeMS >= 1000ul ? sleepingTimeMS - 1000ul : 1000ul;
- }
- #endif // MY_OTA_FIRMWARE_FEATURE
- if (smartSleep) {
- // sleeping time left?
- if (sleepingTimeMS > 0 && sleepingTimeMS < ((uint32_t)MY_SMART_SLEEP_WAIT_DURATION_MS)) {
- wait(sleepingMS);
- CORE_DEBUG(PSTR("!MCO:SLP:NTL\n")); // sleeping not possible, no time left
- return MY_SLEEP_NOT_POSSIBLE;
- }
- // notify controller about going to sleep, payload indicates smartsleep waiting time in MS
- (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL,
- I_PRE_SLEEP_NOTIFICATION).set((uint32_t)MY_SMART_SLEEP_WAIT_DURATION_MS));
- wait(MY_SMART_SLEEP_WAIT_DURATION_MS); // listen for incoming messages
- #if defined(MY_OTA_FIRMWARE_FEATURE)
- // check if during smart sleep waiting period a FOTA request was received
- if (isFirmwareUpdateOngoing()) {
- CORE_DEBUG(PSTR("!MCO:SLP:FWUPD\n")); // sleeping not possible, FW update ongoing
- return MY_SLEEP_NOT_POSSIBLE;
- }
- #endif // MY_OTA_FIRMWARE_FEATURE
- }
- #else
- (void)smartSleep;
- #endif // MY_SENSOR_NETWORK
-
- #if defined(MY_SENSOR_NETWORK)
- transportDisable();
- #endif
- setIndication(INDICATION_SLEEP);
-
- #if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN)
- // Wait until leds finish their blinking pattern
- while (ledsBlinking()) {
- doYield();
- }
- #endif
-
- int8_t result = MY_SLEEP_NOT_POSSIBLE; // default
- if (interrupt1 != INTERRUPT_NOT_DEFINED && interrupt2 != INTERRUPT_NOT_DEFINED) {
- // both IRQs
- result = hwSleep(interrupt1, mode1, interrupt2, mode2, sleepingTimeMS);
- } else if (interrupt1 != INTERRUPT_NOT_DEFINED && interrupt2 == INTERRUPT_NOT_DEFINED) {
- // one IRQ
- result = hwSleep(interrupt1, mode1, sleepingTimeMS);
- } else if (interrupt1 == INTERRUPT_NOT_DEFINED && interrupt2 == INTERRUPT_NOT_DEFINED) {
- // no IRQ
- result = hwSleep(sleepingTimeMS);
- }
- setIndication(INDICATION_WAKEUP);
- CORE_DEBUG(PSTR("MCO:SLP:WUP=%" PRIi8 "\n"), result); // sleep wake-up
- #if defined(MY_SENSOR_NETWORK)
- transportReInitialise();
- #endif
- if (smartSleep) {
- // notify controller about waking up, payload indicates sleeping time in MS
- (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL,
- I_POST_SLEEP_NOTIFICATION).set(sleepingTimeMS));
- }
- return result;
- #endif
- }
-
- // sleep functions
- int8_t sleep(const uint32_t sleepingMS, const bool smartSleep)
- {
- return _sleep(sleepingMS, smartSleep);
- }
-
- int8_t sleep(const uint8_t interrupt, const uint8_t mode, const uint32_t sleepingMS,
- const bool smartSleep)
- {
- return _sleep(sleepingMS, smartSleep, interrupt, mode);
- }
-
- int8_t sleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,
- const uint8_t mode2, const uint32_t sleepingMS, const bool smartSleep)
- {
- return _sleep(sleepingMS, smartSleep, interrupt1, mode1, interrupt2, mode2);
- }
-
- // deprecated smartSleep() functions
- int8_t smartSleep(const uint32_t sleepingMS)
- {
- // compatibility
- return _sleep(sleepingMS, true);
- }
-
- int8_t smartSleep(const uint8_t interrupt, const uint8_t mode, const uint32_t sleepingMS)
- {
- // compatibility
- return _sleep(sleepingMS, true, interrupt, mode);
- }
-
- int8_t smartSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,
- const uint8_t mode2, const uint32_t sleepingMS)
- {
- // compatibility
- return _sleep(sleepingMS, true, interrupt1, mode1, interrupt2, mode2);
- }
-
-
-
- void _nodeLock(const char* str)
- {
- #ifdef MY_NODE_LOCK_FEATURE
- // Make sure EEPROM is updated to locked status
- hwWriteConfig(EEPROM_NODE_LOCK_COUNTER_ADDRESS, 0);
- while (1) {
- setIndication(INDICATION_ERR_LOCKED);
- CORE_DEBUG(PSTR("MCO:NLK:NODE LOCKED. TO UNLOCK, GND PIN %" PRIu8 " AND RESET\n"),
- MY_NODE_UNLOCK_PIN);
- doYield();
- (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID,C_INTERNAL, I_LOCKED).set(str));
- #if defined(MY_SENSOR_NETWORK)
- transportSleep();
- CORE_DEBUG(PSTR("MCO:NLK:TSL\n")); // sleep transport
- #endif
- setIndication(INDICATION_SLEEP);
- (void)hwSleep((uint32_t)1000*60*30); // Sleep for 30 min before resending LOCKED message
- setIndication(INDICATION_WAKEUP);
- }
- #else
- (void)str;
- #endif
- }
-
- void _checkNodeLock(void)
- {
- #ifdef MY_NODE_LOCK_FEATURE
- // Check if node has been locked down
- if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER_ADDRESS) == 0) {
- // Node is locked, check if unlock pin is asserted, else hang the node
- hwPinMode(MY_NODE_UNLOCK_PIN, INPUT_PULLUP);
- // Make a short delay so we are sure any large external nets are fully pulled
- uint32_t enter = hwMillis();
- while (hwMillis() - enter < 2) {}
- if (hwDigitalRead(MY_NODE_UNLOCK_PIN) == 0) {
- // Pin is grounded, reset lock counter
- hwWriteConfig(EEPROM_NODE_LOCK_COUNTER_ADDRESS, MY_NODE_LOCK_COUNTER_MAX);
- // Disable pullup
- hwPinMode(MY_NODE_UNLOCK_PIN, INPUT);
- setIndication(INDICATION_ERR_LOCKED);
- CORE_DEBUG(PSTR("MCO:BGN:NODE UNLOCKED\n"));
- } else {
- // Disable pullup
- hwPinMode(MY_NODE_UNLOCK_PIN, INPUT);
- _nodeLock("LDB"); //Locked during boot
- }
- } else if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER_ADDRESS) == 0xFF) {
- // Reset value
- hwWriteConfig(EEPROM_NODE_LOCK_COUNTER_ADDRESS, MY_NODE_LOCK_COUNTER_MAX);
- }
- #endif
- }
- #if DOXYGEN
-
- #endif
|