Smart-Home am Beispiel der Präsenzerkennung im Raum Projektarbeit Lennart Heimbs, Johannes Krug, Sebastian Dohle und Kevin Holzschuh bei Prof. Oliver Hofmann SS2019
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

MySensorsCore.cpp 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  1. /*
  2. * The MySensors Arduino library handles the wireless radio link and protocol
  3. * between your home built sensors/actuators and HA controller of choice.
  4. * The sensors forms a self healing radio network with optional repeaters. Each
  5. * repeater and gateway builds a routing tables in EEPROM which keeps track of the
  6. * network topology allowing messages to be routed to nodes.
  7. *
  8. * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
  9. * Copyright (C) 2013-2018 Sensnology AB
  10. * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
  11. *
  12. * Documentation: http://www.mysensors.org
  13. * Support Forum: http://forum.mysensors.org
  14. *
  15. * This program is free software; you can redistribute it and/or
  16. * modify it under the terms of the GNU General Public License
  17. * version 2 as published by the Free Software Foundation.
  18. */
  19. #include "MySensorsCore.h"
  20. #if defined(__linux__)
  21. #include <stdlib.h>
  22. #include <unistd.h>
  23. #endif
  24. // debug output
  25. #if defined(MY_DEBUG_VERBOSE_CORE)
  26. #define CORE_DEBUG(x,...) DEBUG_OUTPUT(x, ##__VA_ARGS__) //!< debug
  27. #else
  28. #define CORE_DEBUG(x,...) //!< debug NULL
  29. #endif
  30. // message buffers
  31. MyMessage _msg; // Buffer for incoming messages
  32. MyMessage _msgTmp; // Buffer for temporary messages (acks and nonces among others)
  33. // core configuration
  34. static coreConfig_t _coreConfig;
  35. #if defined(DEBUG_OUTPUT_ENABLED)
  36. char _convBuf[MAX_PAYLOAD*2+1];
  37. #endif
  38. // Callback for transport=ok transition
  39. void _callbackTransportReady(void)
  40. {
  41. if (!_coreConfig.presentationSent) {
  42. #if !defined(MY_GATEWAY_FEATURE) // GW calls presentNode() when client connected
  43. presentNode();
  44. #endif
  45. _registerNode();
  46. _coreConfig.presentationSent = true;
  47. }
  48. }
  49. void _process(void)
  50. {
  51. doYield();
  52. #if defined(MY_INCLUSION_MODE_FEATURE)
  53. inclusionProcess();
  54. #endif
  55. #if defined(MY_GATEWAY_FEATURE)
  56. gatewayTransportProcess();
  57. #endif
  58. #if defined(MY_SENSOR_NETWORK)
  59. transportProcess();
  60. #endif
  61. #if defined(__linux__)
  62. // To avoid high cpu usage
  63. usleep(10000); // 10ms
  64. #endif
  65. }
  66. void _infiniteLoop(void)
  67. {
  68. while(1) {
  69. doYield();
  70. #if defined(__linux__)
  71. exit(1);
  72. #endif
  73. }
  74. }
  75. void _begin(void)
  76. {
  77. #if defined(MY_CORE_ONLY)
  78. // initialize HW and run setup if present
  79. (void)hwInit();
  80. if (setup) {
  81. setup();
  82. }
  83. return;
  84. #endif
  85. // reset wdt
  86. hwWatchdogReset();
  87. if (preHwInit) {
  88. preHwInit();
  89. }
  90. const bool hwInitResult = hwInit();
  91. #if !defined(MY_SPLASH_SCREEN_DISABLED) && !defined(MY_GATEWAY_FEATURE)
  92. displaySplashScreen();
  93. #endif
  94. CORE_DEBUG(PSTR("MCO:BGN:INIT " MY_NODE_TYPE ",CP=" MY_CAPABILITIES ",REL=%" PRIu8 ",VER="
  95. MYSENSORS_LIBRARY_VERSION "\n"), MYSENSORS_LIBRARY_VERSION_PRERELEASE_NUMBER);
  96. if (!hwInitResult) {
  97. CORE_DEBUG(PSTR("!MCO:BGN:HW ERR\n"));
  98. setIndication(INDICATION_ERR_HW_INIT);
  99. _infiniteLoop();
  100. }
  101. // set defaults
  102. _coreConfig.presentationSent = false;
  103. // Call sketch before() (if defined)
  104. if (before) {
  105. CORE_DEBUG(PSTR("MCO:BGN:BFR\n")); // before callback
  106. before();
  107. }
  108. #if defined(MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN)
  109. ledsInit();
  110. #endif
  111. signerInit();
  112. // Read latest received controller configuration from EEPROM
  113. // Note: _coreConfig.isMetric is bool, hence empty EEPROM (=0xFF) evaluates to true (default)
  114. hwReadConfigBlock((void*)&_coreConfig.controllerConfig, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS,
  115. sizeof(controllerConfig_t));
  116. #if defined(MY_OTA_FIRMWARE_FEATURE)
  117. // Read firmware config from EEPROM, i.e. type, version, CRC, blocks
  118. readFirmwareSettings();
  119. #endif
  120. #if defined(MY_SENSOR_NETWORK)
  121. // Save static parent ID in eeprom (used by bootloader)
  122. hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, MY_PARENT_NODE_ID);
  123. // Initialise transport layer
  124. transportInitialise();
  125. // Register transport=ready callback
  126. transportRegisterReadyCallback(_callbackTransportReady);
  127. // wait until transport is ready
  128. (void)transportWaitUntilReady(MY_TRANSPORT_WAIT_READY_MS);
  129. #endif
  130. _checkNodeLock();
  131. #if defined(MY_GATEWAY_FEATURE)
  132. #if defined(MY_INCLUSION_BUTTON_FEATURE)
  133. inclusionInit();
  134. #endif
  135. // initialise the transport driver
  136. if (!gatewayTransportInit()) {
  137. setIndication(INDICATION_ERR_INIT_GWTRANSPORT);
  138. CORE_DEBUG(PSTR("!MCO:BGN:TSP FAIL\n"));
  139. // Nothing more we can do
  140. _infiniteLoop();
  141. }
  142. #endif
  143. // Call sketch setup() (if defined)
  144. if (setup) {
  145. CORE_DEBUG(PSTR("MCO:BGN:STP\n")); // setup callback
  146. setup();
  147. }
  148. #if defined(MY_SENSOR_NETWORK)
  149. CORE_DEBUG(PSTR("MCO:BGN:INIT OK,TSP=%" PRIu8 "\n"), isTransportReady() && transportSanityCheck());
  150. #else
  151. // no sensor network defined, call presentation & registration
  152. _callbackTransportReady();
  153. CORE_DEBUG(PSTR("MCO:BGN:INIT OK,TSP=NA\n"));
  154. #endif
  155. // reset wdt before handing over to loop
  156. hwWatchdogReset();
  157. }
  158. void _registerNode(void)
  159. {
  160. #if defined (MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE)
  161. CORE_DEBUG(PSTR("MCO:REG:REQ\n")); // registration request
  162. setIndication(INDICATION_REQ_REGISTRATION);
  163. _coreConfig.nodeRegistered = MY_REGISTRATION_DEFAULT;
  164. uint8_t counter = MY_REGISTRATION_RETRIES;
  165. // only proceed if register response received or retries exceeded
  166. do {
  167. (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL,
  168. I_REGISTRATION_REQUEST).set(MY_CORE_VERSION));
  169. } while (!wait(2000, C_INTERNAL, I_REGISTRATION_RESPONSE) && counter--);
  170. #else
  171. _coreConfig.nodeRegistered = true;
  172. CORE_DEBUG(PSTR("MCO:REG:NOT NEEDED\n"));
  173. #endif
  174. }
  175. void presentNode(void)
  176. {
  177. setIndication(INDICATION_PRESENT);
  178. // Present node and request config
  179. #if defined(MY_GATEWAY_FEATURE)
  180. // Send presentation for this gateway device
  181. #if defined(MY_REPEATER_FEATURE)
  182. (void)present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE);
  183. #else
  184. (void)present(NODE_SENSOR_ID, S_ARDUINO_NODE);
  185. #endif
  186. #else
  187. #if defined(MY_OTA_FIRMWARE_FEATURE)
  188. presentBootloaderInformation();
  189. #endif
  190. // Send signing preferences for this node to the GW
  191. signerPresentation(_msgTmp, GATEWAY_ADDRESS);
  192. // Send presentation for this radio node
  193. #if defined(MY_REPEATER_FEATURE)
  194. (void)present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE);
  195. #else
  196. (void)present(NODE_SENSOR_ID, S_ARDUINO_NODE);
  197. #endif
  198. // Send a configuration exchange request to controller
  199. // Node sends parent node. Controller answers with latest node configuration
  200. (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL,
  201. I_CONFIG).set(getParentNodeId()));
  202. // Wait configuration reply.
  203. (void)wait(2000, C_INTERNAL, I_CONFIG);
  204. #endif
  205. if (presentation) {
  206. presentation();
  207. }
  208. }
  209. uint8_t getNodeId(void)
  210. {
  211. uint8_t result;
  212. #if defined(MY_GATEWAY_FEATURE)
  213. result = GATEWAY_ADDRESS;
  214. #elif defined(MY_SENSOR_NETWORK)
  215. result = transportGetNodeId();
  216. #else
  217. result = VALUE_NOT_DEFINED;
  218. #endif
  219. return result;
  220. }
  221. uint8_t getParentNodeId(void)
  222. {
  223. uint8_t result;
  224. #if defined(MY_GATEWAY_FEATURE)
  225. result = VALUE_NOT_DEFINED; // GW doesn't have a parent
  226. #elif defined(MY_SENSOR_NETWORK)
  227. result = transportGetParentNodeId();
  228. #else
  229. result = VALUE_NOT_DEFINED;
  230. #endif
  231. return result;
  232. }
  233. uint8_t getDistanceGW(void)
  234. {
  235. uint8_t result;
  236. #if defined(MY_GATEWAY_FEATURE)
  237. result = 0;
  238. #elif defined(MY_SENSOR_NETWORK)
  239. result = transportGetDistanceGW();
  240. #else
  241. result = VALUE_NOT_DEFINED;
  242. #endif
  243. return result;
  244. }
  245. controllerConfig_t getControllerConfig(void)
  246. {
  247. return _coreConfig.controllerConfig;
  248. }
  249. bool _sendRoute(MyMessage &message)
  250. {
  251. #if defined(MY_CORE_ONLY)
  252. (void)message;
  253. #endif
  254. #if defined(MY_GATEWAY_FEATURE)
  255. if (message.destination == getNodeId()) {
  256. // This is a message sent from a sensor attached on the gateway node.
  257. // Pass it directly to the gateway transport layer.
  258. return gatewayTransportSend(message);
  259. }
  260. #endif
  261. #if defined(MY_SENSOR_NETWORK)
  262. return transportSendRoute(message);
  263. #else
  264. return false;
  265. #endif
  266. }
  267. bool send(MyMessage &message, const bool enableAck)
  268. {
  269. message.sender = getNodeId();
  270. mSetCommand(message, C_SET);
  271. mSetRequestAck(message, enableAck);
  272. #if defined(MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE)
  273. if (_coreConfig.nodeRegistered) {
  274. return _sendRoute(message);
  275. } else {
  276. CORE_DEBUG(PSTR("!MCO:SND:NODE NOT REG\n")); // node not registered
  277. return false;
  278. }
  279. #else
  280. return _sendRoute(message);
  281. #endif
  282. }
  283. bool sendBatteryLevel(const uint8_t value, const bool ack)
  284. {
  285. return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL,
  286. ack).set(value));
  287. }
  288. bool sendHeartbeat(const bool ack)
  289. {
  290. #if defined(MY_SENSOR_NETWORK)
  291. const uint32_t heartbeat = transportGetHeartbeat();
  292. return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_HEARTBEAT_RESPONSE,
  293. ack).set(heartbeat));
  294. #else
  295. (void)ack;
  296. return false;
  297. #endif
  298. }
  299. bool present(const uint8_t childSensorId, const uint8_t sensorType, const char *description,
  300. const bool ack)
  301. {
  302. return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType,
  303. ack).set(childSensorId == NODE_SENSOR_ID ? MYSENSORS_LIBRARY_VERSION : description));
  304. }
  305. #if !defined(__linux__)
  306. bool present(const uint8_t childSensorId, const uint8_t sensorType,
  307. const __FlashStringHelper *description,
  308. const bool ack)
  309. {
  310. return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType,
  311. ack).set(childSensorId == NODE_SENSOR_ID ? F(" MYSENSORS_LIBRARY_VERSION "): description));
  312. }
  313. #endif
  314. bool sendSketchInfo(const char *name, const char *version, const bool ack)
  315. {
  316. bool result = true;
  317. if (name) {
  318. result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME,
  319. ack).set(name));
  320. }
  321. if (version) {
  322. result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION,
  323. ack).set(version));
  324. }
  325. return result;
  326. }
  327. #if !defined(__linux__)
  328. bool sendSketchInfo(const __FlashStringHelper *name, const __FlashStringHelper *version,
  329. const bool ack)
  330. {
  331. bool result = true;
  332. if (name) {
  333. result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME,
  334. ack).set(name));
  335. }
  336. if (version) {
  337. result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION,
  338. ack).set(version));
  339. }
  340. return result;
  341. }
  342. #endif
  343. bool request(const uint8_t childSensorId, const uint8_t variableType, const uint8_t destination)
  344. {
  345. return _sendRoute(build(_msgTmp, destination, childSensorId, C_REQ, variableType).set(""));
  346. }
  347. bool requestTime(const bool ack)
  348. {
  349. return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_TIME, ack).set(""));
  350. }
  351. // Message delivered through _msg
  352. bool _processInternalCoreMessage(void)
  353. {
  354. const uint8_t type = _msg.type;
  355. if (_msg.sender == GATEWAY_ADDRESS) {
  356. if (type == I_REBOOT) {
  357. #if !defined(MY_DISABLE_REMOTE_RESET)
  358. setIndication(INDICATION_REBOOT);
  359. // WDT fuse should be enabled
  360. hwReboot();
  361. #endif
  362. } else if (type == I_REGISTRATION_RESPONSE) {
  363. #if defined (MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE)
  364. _coreConfig.nodeRegistered = _msg.getBool();
  365. setIndication(INDICATION_GOT_REGISTRATION);
  366. CORE_DEBUG(PSTR("MCO:PIM:NODE REG=%" PRIu8 "\n"), _coreConfig.nodeRegistered); // node registration
  367. #endif
  368. } else if (type == I_CONFIG) {
  369. // Pick up configuration from controller (currently only metric/imperial) and store it in eeprom if changed
  370. _coreConfig.controllerConfig.isMetric = _msg.data[0] == 0x00 ||
  371. _msg.data[0] == 'M'; // metric if null terminated or M
  372. hwWriteConfigBlock((void*)&_coreConfig.controllerConfig, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS,
  373. sizeof(controllerConfig_t));
  374. } else if (type == I_PRESENTATION) {
  375. // Re-send node presentation to controller
  376. presentNode();
  377. } else if (type == I_HEARTBEAT_REQUEST) {
  378. (void)sendHeartbeat();
  379. } else if (_msg.type == I_VERSION) {
  380. #if !defined(MY_GATEWAY_FEATURE)
  381. (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL,
  382. I_VERSION).set(MYSENSORS_LIBRARY_VERSION_INT));
  383. #endif
  384. } else if (type == I_TIME) {
  385. // Deliver time to callback
  386. if (receiveTime) {
  387. receiveTime(_msg.getULong());
  388. }
  389. } else if (type == I_CHILDREN) {
  390. if (_msg.data[0] == 'C') {
  391. #if defined(MY_REPEATER_FEATURE) && defined(MY_SENSOR_NETWORK)
  392. // Clears child relay data for this node
  393. setIndication(INDICATION_CLEAR_ROUTING);
  394. transportClearRoutingTable();
  395. (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN).set("OK"));
  396. #endif
  397. }
  398. } else if (type == I_DEBUG) {
  399. #if defined(MY_SPECIAL_DEBUG)
  400. const char debug_msg = _msg.data[0];
  401. if (debug_msg == 'R') { // routing table
  402. #if defined(MY_REPEATER_FEATURE) && defined(MY_SENSOR_NETWORK)
  403. transportReportRoutingTable();
  404. #endif
  405. } else if (debug_msg == 'V') { // CPU voltage
  406. (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL,
  407. I_DEBUG).set(hwCPUVoltage()));
  408. } else if (debug_msg == 'F') { // CPU frequency in 1/10Mhz
  409. (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL,
  410. I_DEBUG).set(hwCPUFrequency()));
  411. } else if (debug_msg == 'M') { // free memory
  412. (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL,
  413. I_DEBUG).set(hwFreeMem()));
  414. } else if (debug_msg == 'E') { // clear MySensors eeprom area and reboot
  415. (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG).set("OK"));
  416. for (uint16_t i = EEPROM_START; i<EEPROM_LOCAL_CONFIG_ADDRESS; i++) {
  417. hwWriteConfig(i, 0xFF);
  418. }
  419. setIndication(INDICATION_REBOOT);
  420. hwReboot();
  421. }
  422. #endif
  423. } else {
  424. return false; // further processing required
  425. }
  426. } else {
  427. // sender is a node
  428. if (type == I_REGISTRATION_REQUEST) {
  429. #if defined(MY_GATEWAY_FEATURE)
  430. // registration requests are exclusively handled by GW/Controller
  431. #if !defined(MY_REGISTRATION_CONTROLLER)
  432. bool approveRegistration;
  433. #if defined(MY_CORE_COMPATIBILITY_CHECK)
  434. approveRegistration = (_msg.getByte() >= MY_CORE_MIN_VERSION);
  435. #else
  436. // auto registration if version compatible
  437. approveRegistration = true;
  438. #endif
  439. #if (F_CPU>16000000)
  440. // delay for fast GW and slow nodes
  441. delay(5);
  442. #endif
  443. (void)_sendRoute(build(_msgTmp, _msg.sender, NODE_SENSOR_ID, C_INTERNAL,
  444. I_REGISTRATION_RESPONSE).set(approveRegistration));
  445. #else
  446. return false; // processing of this request via controller
  447. #endif
  448. #endif
  449. } else {
  450. return false; // further processing required
  451. }
  452. }
  453. return true; // if not GW or no further processing required
  454. }
  455. void saveState(const uint8_t pos, const uint8_t value)
  456. {
  457. hwWriteConfig(EEPROM_LOCAL_CONFIG_ADDRESS+pos, value);
  458. }
  459. uint8_t loadState(const uint8_t pos)
  460. {
  461. return hwReadConfig(EEPROM_LOCAL_CONFIG_ADDRESS+pos);
  462. }
  463. void wait(const uint32_t waitingMS)
  464. {
  465. const uint32_t enteringMS = hwMillis();
  466. while (hwMillis() - enteringMS < waitingMS) {
  467. _process();
  468. }
  469. }
  470. bool wait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t msgType)
  471. {
  472. const uint32_t enteringMS = hwMillis();
  473. // invalidate msg type
  474. _msg.type = !msgType;
  475. bool expectedResponse = false;
  476. while ( (hwMillis() - enteringMS < waitingMS) && !expectedResponse ) {
  477. _process();
  478. expectedResponse = (mGetCommand(_msg) == cmd && _msg.type == msgType);
  479. }
  480. return expectedResponse;
  481. }
  482. void doYield(void)
  483. {
  484. hwWatchdogReset();
  485. yield();
  486. #if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN)
  487. ledsProcess();
  488. #endif
  489. }
  490. int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep, const uint8_t interrupt1,
  491. const uint8_t mode1, const uint8_t interrupt2, const uint8_t mode2)
  492. {
  493. CORE_DEBUG(PSTR("MCO:SLP:MS=%" PRIu32 ",SMS=%" PRIu8 ",I1=%" PRIu8 ",M1=%" PRIu8 ",I2=%" PRIu8
  494. ",M2=%" PRIu8 "\n"), sleepingMS, smartSleep,
  495. interrupt1, mode1, interrupt2, mode2);
  496. // repeater feature: sleeping not possible
  497. #if defined(MY_REPEATER_FEATURE)
  498. (void)smartSleep;
  499. (void)interrupt1;
  500. (void)mode1;
  501. (void)interrupt2;
  502. (void)mode2;
  503. CORE_DEBUG(PSTR("!MCO:SLP:REP\n")); // sleeping not possible, repeater feature enabled
  504. wait(sleepingMS);
  505. return MY_SLEEP_NOT_POSSIBLE;
  506. #else
  507. uint32_t sleepingTimeMS = sleepingMS;
  508. #if defined(MY_SENSOR_NETWORK)
  509. // Do not sleep if transport not ready
  510. if (!isTransportReady()) {
  511. CORE_DEBUG(PSTR("!MCO:SLP:TNR\n")); // sleeping not possible, transport not ready
  512. const uint32_t sleepEnterMS = hwMillis();
  513. uint32_t sleepDeltaMS = 0;
  514. while (!isTransportReady() && (sleepDeltaMS < sleepingTimeMS) &&
  515. (sleepDeltaMS < MY_SLEEP_TRANSPORT_RECONNECT_TIMEOUT_MS)) {
  516. _process();
  517. sleepDeltaMS = hwMillis() - sleepEnterMS;
  518. }
  519. // sleep remainder
  520. if (sleepDeltaMS < sleepingTimeMS) {
  521. sleepingTimeMS -= sleepDeltaMS; // calculate remaining sleeping time
  522. CORE_DEBUG(PSTR("MCO:SLP:MS=%" PRIu32 "\n"), sleepingTimeMS);
  523. } else {
  524. // no sleeping time left
  525. return MY_SLEEP_NOT_POSSIBLE;
  526. }
  527. }
  528. // OTA FW feature: do not sleep if FW update ongoing
  529. #if defined(MY_OTA_FIRMWARE_FEATURE)
  530. while (isFirmwareUpdateOngoing() && sleepingTimeMS) {
  531. CORE_DEBUG(PSTR("!MCO:SLP:FWUPD\n")); // sleeping not possible, FW update ongoing
  532. wait(1000ul);
  533. sleepingTimeMS = sleepingTimeMS >= 1000ul ? sleepingTimeMS - 1000ul : 1000ul;
  534. }
  535. #endif // MY_OTA_FIRMWARE_FEATURE
  536. if (smartSleep) {
  537. // sleeping time left?
  538. if (sleepingTimeMS > 0 && sleepingTimeMS < ((uint32_t)MY_SMART_SLEEP_WAIT_DURATION_MS)) {
  539. wait(sleepingMS);
  540. CORE_DEBUG(PSTR("!MCO:SLP:NTL\n")); // sleeping not possible, no time left
  541. return MY_SLEEP_NOT_POSSIBLE;
  542. }
  543. // notify controller about going to sleep, payload indicates smartsleep waiting time in MS
  544. (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL,
  545. I_PRE_SLEEP_NOTIFICATION).set((uint32_t)MY_SMART_SLEEP_WAIT_DURATION_MS));
  546. wait(MY_SMART_SLEEP_WAIT_DURATION_MS); // listen for incoming messages
  547. #if defined(MY_OTA_FIRMWARE_FEATURE)
  548. // check if during smart sleep waiting period a FOTA request was received
  549. if (isFirmwareUpdateOngoing()) {
  550. CORE_DEBUG(PSTR("!MCO:SLP:FWUPD\n")); // sleeping not possible, FW update ongoing
  551. return MY_SLEEP_NOT_POSSIBLE;
  552. }
  553. #endif // MY_OTA_FIRMWARE_FEATURE
  554. }
  555. #else
  556. (void)smartSleep;
  557. #endif // MY_SENSOR_NETWORK
  558. #if defined(MY_SENSOR_NETWORK)
  559. transportDisable();
  560. #endif
  561. setIndication(INDICATION_SLEEP);
  562. #if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN)
  563. // Wait until leds finish their blinking pattern
  564. while (ledsBlinking()) {
  565. doYield();
  566. }
  567. #endif
  568. int8_t result = MY_SLEEP_NOT_POSSIBLE; // default
  569. if (interrupt1 != INTERRUPT_NOT_DEFINED && interrupt2 != INTERRUPT_NOT_DEFINED) {
  570. // both IRQs
  571. result = hwSleep(interrupt1, mode1, interrupt2, mode2, sleepingTimeMS);
  572. } else if (interrupt1 != INTERRUPT_NOT_DEFINED && interrupt2 == INTERRUPT_NOT_DEFINED) {
  573. // one IRQ
  574. result = hwSleep(interrupt1, mode1, sleepingTimeMS);
  575. } else if (interrupt1 == INTERRUPT_NOT_DEFINED && interrupt2 == INTERRUPT_NOT_DEFINED) {
  576. // no IRQ
  577. result = hwSleep(sleepingTimeMS);
  578. }
  579. setIndication(INDICATION_WAKEUP);
  580. CORE_DEBUG(PSTR("MCO:SLP:WUP=%" PRIi8 "\n"), result); // sleep wake-up
  581. #if defined(MY_SENSOR_NETWORK)
  582. transportReInitialise();
  583. #endif
  584. if (smartSleep) {
  585. // notify controller about waking up, payload indicates sleeping time in MS
  586. (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL,
  587. I_POST_SLEEP_NOTIFICATION).set(sleepingTimeMS));
  588. }
  589. return result;
  590. #endif
  591. }
  592. // sleep functions
  593. int8_t sleep(const uint32_t sleepingMS, const bool smartSleep)
  594. {
  595. return _sleep(sleepingMS, smartSleep);
  596. }
  597. int8_t sleep(const uint8_t interrupt, const uint8_t mode, const uint32_t sleepingMS,
  598. const bool smartSleep)
  599. {
  600. return _sleep(sleepingMS, smartSleep, interrupt, mode);
  601. }
  602. int8_t sleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,
  603. const uint8_t mode2, const uint32_t sleepingMS, const bool smartSleep)
  604. {
  605. return _sleep(sleepingMS, smartSleep, interrupt1, mode1, interrupt2, mode2);
  606. }
  607. // deprecated smartSleep() functions
  608. int8_t smartSleep(const uint32_t sleepingMS)
  609. {
  610. // compatibility
  611. return _sleep(sleepingMS, true);
  612. }
  613. int8_t smartSleep(const uint8_t interrupt, const uint8_t mode, const uint32_t sleepingMS)
  614. {
  615. // compatibility
  616. return _sleep(sleepingMS, true, interrupt, mode);
  617. }
  618. int8_t smartSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,
  619. const uint8_t mode2, const uint32_t sleepingMS)
  620. {
  621. // compatibility
  622. return _sleep(sleepingMS, true, interrupt1, mode1, interrupt2, mode2);
  623. }
  624. void _nodeLock(const char* str)
  625. {
  626. #ifdef MY_NODE_LOCK_FEATURE
  627. // Make sure EEPROM is updated to locked status
  628. hwWriteConfig(EEPROM_NODE_LOCK_COUNTER_ADDRESS, 0);
  629. while (1) {
  630. setIndication(INDICATION_ERR_LOCKED);
  631. CORE_DEBUG(PSTR("MCO:NLK:NODE LOCKED. TO UNLOCK, GND PIN %" PRIu8 " AND RESET\n"),
  632. MY_NODE_UNLOCK_PIN);
  633. doYield();
  634. (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID,C_INTERNAL, I_LOCKED).set(str));
  635. #if defined(MY_SENSOR_NETWORK)
  636. transportSleep();
  637. CORE_DEBUG(PSTR("MCO:NLK:TSL\n")); // sleep transport
  638. #endif
  639. setIndication(INDICATION_SLEEP);
  640. (void)hwSleep((uint32_t)1000*60*30); // Sleep for 30 min before resending LOCKED message
  641. setIndication(INDICATION_WAKEUP);
  642. }
  643. #else
  644. (void)str;
  645. #endif
  646. }
  647. void _checkNodeLock(void)
  648. {
  649. #ifdef MY_NODE_LOCK_FEATURE
  650. // Check if node has been locked down
  651. if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER_ADDRESS) == 0) {
  652. // Node is locked, check if unlock pin is asserted, else hang the node
  653. hwPinMode(MY_NODE_UNLOCK_PIN, INPUT_PULLUP);
  654. // Make a short delay so we are sure any large external nets are fully pulled
  655. uint32_t enter = hwMillis();
  656. while (hwMillis() - enter < 2) {}
  657. if (hwDigitalRead(MY_NODE_UNLOCK_PIN) == 0) {
  658. // Pin is grounded, reset lock counter
  659. hwWriteConfig(EEPROM_NODE_LOCK_COUNTER_ADDRESS, MY_NODE_LOCK_COUNTER_MAX);
  660. // Disable pullup
  661. hwPinMode(MY_NODE_UNLOCK_PIN, INPUT);
  662. setIndication(INDICATION_ERR_LOCKED);
  663. CORE_DEBUG(PSTR("MCO:BGN:NODE UNLOCKED\n"));
  664. } else {
  665. // Disable pullup
  666. hwPinMode(MY_NODE_UNLOCK_PIN, INPUT);
  667. _nodeLock("LDB"); //Locked during boot
  668. }
  669. } else if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER_ADDRESS) == 0xFF) {
  670. // Reset value
  671. hwWriteConfig(EEPROM_NODE_LOCK_COUNTER_ADDRESS, MY_NODE_LOCK_COUNTER_MAX);
  672. }
  673. #endif
  674. }
  675. #if DOXYGEN
  676. #endif