Fork of the espurna firmware for `mhsw` switches
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.

284 lines
7.2 KiB

6 years ago
6 years ago
Rework settings (#2282) * wip based on early draft. todo benchmarking * fixup eraser, assume keys are unique * fix cursor copy, test removal at random * small benchmark via permutations. todo lambdas and novirtual * fix empty condition / reset * overwrite optimizations, fix move offsets overflows * ...erase using 0xff instead of 0 * test the theory with code, different length kv were bugged * try to check for out-of-bounds writes / reads * style * trying to fix mover again * clarify length, defend against reading len on edge * fix uncommited rewind change * prove space assumptions * more concise traces, fix move condition (agrh!!!) * slightly more internal knowledge (estimates API?) * make sure cursor is only valid within the range * ensure 0 does not blow things * go back up * cursor comments * comments * rewrite writes through cursor * in del too * estimate kv storage requirements, return available size * move raw erase / move into a method, allow ::set to avoid scanning storage twice * refactor naming, use in code * amend storage slicing test * fix crash handler offsets, cleanup configuration * start -> begin * eeprom readiness * dependencies * unused * SPI_FLASH constants for older Core * vtables -> templates * less include dependencies * gcov help, move estimate outside of the class * writer position can never match, use begin + offset * tweak save_crash to trigger only once in a serious crash * doh, header function should be inline * foreach api, tweak structs for public api * use test helper class * when not using foreach, move cursor reset closer to the loop using read_kv * coverage comments, fix typo in tests decltype * ensure set() does not break with offset * make codacy happy again
4 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. /*
  2. SYSTEM MODULE
  3. Copyright (C) 2019 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #include "espurna.h"
  6. #include <Ticker.h>
  7. #include <Schedule.h>
  8. #include <cstdint>
  9. #include "rtcmem.h"
  10. #include "ws.h"
  11. #include "ntp.h"
  12. // -----------------------------------------------------------------------------
  13. bool _system_send_heartbeat = false;
  14. int _heartbeat_mode = HEARTBEAT_MODE;
  15. unsigned long _heartbeat_interval = HEARTBEAT_INTERVAL;
  16. // Calculated load average 0 to 100;
  17. unsigned short int _load_average = 100;
  18. // -----------------------------------------------------------------------------
  19. union system_rtcmem_t {
  20. struct {
  21. uint8_t stability_counter;
  22. uint8_t reset_reason;
  23. uint16_t _reserved_;
  24. } packed;
  25. uint32_t value;
  26. };
  27. uint8_t systemStabilityCounter() {
  28. system_rtcmem_t data;
  29. data.value = Rtcmem->sys;
  30. return data.packed.stability_counter;
  31. }
  32. void systemStabilityCounter(uint8_t count) {
  33. system_rtcmem_t data;
  34. data.value = Rtcmem->sys;
  35. data.packed.stability_counter = count;
  36. Rtcmem->sys = data.value;
  37. }
  38. uint8_t _systemResetReason() {
  39. system_rtcmem_t data;
  40. data.value = Rtcmem->sys;
  41. return data.packed.reset_reason;
  42. }
  43. void _systemResetReason(uint8_t reason) {
  44. system_rtcmem_t data;
  45. data.value = Rtcmem->sys;
  46. data.packed.reset_reason = reason;
  47. Rtcmem->sys = data.value;
  48. }
  49. #if SYSTEM_CHECK_ENABLED
  50. // Call this method on boot with start=true to increase the crash counter
  51. // Call it again once the system is stable to decrease the counter
  52. // If the counter reaches SYSTEM_CHECK_MAX then the system is flagged as unstable
  53. // setting _systemOK = false;
  54. //
  55. // An unstable system will only have serial access, WiFi in AP mode and OTA
  56. bool _systemStable = true;
  57. void systemCheck(bool stable) {
  58. uint8_t value = 0;
  59. if (stable) {
  60. value = 0;
  61. DEBUG_MSG_P(PSTR("[MAIN] System OK\n"));
  62. } else {
  63. if (!rtcmemStatus()) {
  64. systemStabilityCounter(1);
  65. return;
  66. }
  67. value = systemStabilityCounter();
  68. if (++value > SYSTEM_CHECK_MAX) {
  69. _systemStable = false;
  70. value = 0;
  71. DEBUG_MSG_P(PSTR("[MAIN] System UNSTABLE\n"));
  72. }
  73. }
  74. systemStabilityCounter(value);
  75. }
  76. bool systemCheck() {
  77. return _systemStable;
  78. }
  79. void systemCheckLoop() {
  80. static bool checked = false;
  81. if (!checked && (millis() > SYSTEM_CHECK_TIME)) {
  82. // Flag system as stable
  83. systemCheck(true);
  84. checked = true;
  85. }
  86. }
  87. #endif
  88. // -----------------------------------------------------------------------------
  89. // Reset
  90. // -----------------------------------------------------------------------------
  91. Ticker _defer_reset;
  92. uint8_t _reset_reason = 0;
  93. // system_get_rst_info() result is cached by the Core init for internal use
  94. uint32_t systemResetReason() {
  95. return resetInfo.reason;
  96. }
  97. void customResetReason(unsigned char reason) {
  98. _reset_reason = reason;
  99. _systemResetReason(reason);
  100. }
  101. unsigned char customResetReason() {
  102. static unsigned char status = 255;
  103. if (status == 255) {
  104. if (rtcmemStatus()) status = _systemResetReason();
  105. if (status > 0) customResetReason(0);
  106. if (status > CUSTOM_RESET_MAX) status = 0;
  107. }
  108. return status;
  109. }
  110. void reset() {
  111. ESP.restart();
  112. }
  113. void deferredReset(unsigned long delay, unsigned char reason) {
  114. _defer_reset.once_ms(delay, customResetReason, reason);
  115. }
  116. bool checkNeedsReset() {
  117. return _reset_reason > 0;
  118. }
  119. // -----------------------------------------------------------------------------
  120. void systemSendHeartbeat() {
  121. _system_send_heartbeat = true;
  122. }
  123. bool systemGetHeartbeat() {
  124. return _system_send_heartbeat;
  125. }
  126. unsigned long systemLoadAverage() {
  127. return _load_average;
  128. }
  129. void _systemSetupHeartbeat() {
  130. _heartbeat_mode = getSetting("hbMode", HEARTBEAT_MODE);
  131. _heartbeat_interval = getSetting("hbInterval", HEARTBEAT_INTERVAL);
  132. }
  133. #if WEB_SUPPORT
  134. bool _systemWebSocketOnKeyCheck(const char * key, JsonVariant& value) {
  135. if (strncmp(key, "sys", 3) == 0) return true;
  136. if (strncmp(key, "hb", 2) == 0) return true;
  137. return false;
  138. }
  139. #endif
  140. void systemLoop() {
  141. // -------------------------------------------------------------------------
  142. // User requested reset
  143. // -------------------------------------------------------------------------
  144. if (checkNeedsReset()) {
  145. reset();
  146. }
  147. // -------------------------------------------------------------------------
  148. // Check system stability
  149. // -------------------------------------------------------------------------
  150. #if SYSTEM_CHECK_ENABLED
  151. systemCheckLoop();
  152. #endif
  153. // -------------------------------------------------------------------------
  154. // Heartbeat
  155. // -------------------------------------------------------------------------
  156. if (_system_send_heartbeat && _heartbeat_mode == HEARTBEAT_ONCE) {
  157. heartbeat();
  158. _system_send_heartbeat = false;
  159. } else if (_heartbeat_mode == HEARTBEAT_REPEAT || _heartbeat_mode == HEARTBEAT_REPEAT_STATUS) {
  160. static unsigned long last_hbeat = 0;
  161. #if NTP_SUPPORT
  162. if ((_system_send_heartbeat && ntpSynced()) || (millis() - last_hbeat > _heartbeat_interval * 1000)) {
  163. #else
  164. if (_system_send_heartbeat || (millis() - last_hbeat > _heartbeat_interval * 1000)) {
  165. #endif
  166. last_hbeat = millis();
  167. heartbeat();
  168. _system_send_heartbeat = false;
  169. }
  170. }
  171. // -------------------------------------------------------------------------
  172. // Load Average calculation
  173. // -------------------------------------------------------------------------
  174. static unsigned long last_loadcheck = 0;
  175. static unsigned long load_counter_temp = 0;
  176. load_counter_temp++;
  177. if (millis() - last_loadcheck > LOADAVG_INTERVAL) {
  178. static unsigned long load_counter = 0;
  179. static unsigned long load_counter_max = 1;
  180. load_counter = load_counter_temp;
  181. load_counter_temp = 0;
  182. if (load_counter > load_counter_max) {
  183. load_counter_max = load_counter;
  184. }
  185. _load_average = 100 - (100 * load_counter / load_counter_max);
  186. last_loadcheck = millis();
  187. }
  188. }
  189. void _systemSetupSpecificHardware() {
  190. //The ESPLive has an ADC MUX which needs to be configured.
  191. #if defined(MANCAVEMADE_ESPLIVE)
  192. pinMode(16, OUTPUT);
  193. digitalWrite(16, HIGH); //Defualt CT input (pin B, solder jumper B)
  194. #endif
  195. // These devices use the hardware UART
  196. // to communicate to secondary microcontrollers
  197. #if (RF_SUPPORT && !RFB_DIRECT) || (RELAY_PROVIDER == RELAY_PROVIDER_DUAL) || (RELAY_PROVIDER == RELAY_PROVIDER_STM)
  198. Serial.begin(SERIAL_BAUDRATE);
  199. #endif
  200. }
  201. void systemSetup() {
  202. #if SPIFFS_SUPPORT
  203. SPIFFS.begin();
  204. #endif
  205. // Question system stability
  206. #if SYSTEM_CHECK_ENABLED
  207. systemCheck(false);
  208. #endif
  209. #if WEB_SUPPORT
  210. wsRegister().onKeyCheck(_systemWebSocketOnKeyCheck);
  211. #endif
  212. // Init device-specific hardware
  213. _systemSetupSpecificHardware();
  214. // Register Loop
  215. espurnaRegisterLoop(systemLoop);
  216. // Cache Heartbeat values
  217. _systemSetupHeartbeat();
  218. }