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.

285 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. return;
  147. }
  148. // -------------------------------------------------------------------------
  149. // Check system stability
  150. // -------------------------------------------------------------------------
  151. #if SYSTEM_CHECK_ENABLED
  152. systemCheckLoop();
  153. #endif
  154. // -------------------------------------------------------------------------
  155. // Heartbeat
  156. // -------------------------------------------------------------------------
  157. if (_system_send_heartbeat && _heartbeat_mode == HEARTBEAT_ONCE) {
  158. heartbeat();
  159. _system_send_heartbeat = false;
  160. } else if (_heartbeat_mode == HEARTBEAT_REPEAT || _heartbeat_mode == HEARTBEAT_REPEAT_STATUS) {
  161. static unsigned long last_hbeat = 0;
  162. #if NTP_SUPPORT
  163. if ((_system_send_heartbeat && ntpSynced()) || (millis() - last_hbeat > _heartbeat_interval * 1000)) {
  164. #else
  165. if (_system_send_heartbeat || (millis() - last_hbeat > _heartbeat_interval * 1000)) {
  166. #endif
  167. last_hbeat = millis();
  168. heartbeat();
  169. _system_send_heartbeat = false;
  170. }
  171. }
  172. // -------------------------------------------------------------------------
  173. // Load Average calculation
  174. // -------------------------------------------------------------------------
  175. static unsigned long last_loadcheck = 0;
  176. static unsigned long load_counter_temp = 0;
  177. load_counter_temp++;
  178. if (millis() - last_loadcheck > LOADAVG_INTERVAL) {
  179. static unsigned long load_counter = 0;
  180. static unsigned long load_counter_max = 1;
  181. load_counter = load_counter_temp;
  182. load_counter_temp = 0;
  183. if (load_counter > load_counter_max) {
  184. load_counter_max = load_counter;
  185. }
  186. _load_average = 100 - (100 * load_counter / load_counter_max);
  187. last_loadcheck = millis();
  188. }
  189. }
  190. void _systemSetupSpecificHardware() {
  191. //The ESPLive has an ADC MUX which needs to be configured.
  192. #if defined(MANCAVEMADE_ESPLIVE)
  193. pinMode(16, OUTPUT);
  194. digitalWrite(16, HIGH); //Defualt CT input (pin B, solder jumper B)
  195. #endif
  196. // These devices use the hardware UART
  197. // to communicate to secondary microcontrollers
  198. #if (RFB_SUPPORT && (RFB_PROVIDER == RFB_PROVIDER_EFM8BB1)) || (RELAY_PROVIDER == RELAY_PROVIDER_DUAL) || (RELAY_PROVIDER == RELAY_PROVIDER_STM)
  199. Serial.begin(SERIAL_BAUDRATE);
  200. #endif
  201. }
  202. void systemSetup() {
  203. #if SPIFFS_SUPPORT
  204. SPIFFS.begin();
  205. #endif
  206. // Question system stability
  207. #if SYSTEM_CHECK_ENABLED
  208. systemCheck(false);
  209. #endif
  210. #if WEB_SUPPORT
  211. wsRegister().onKeyCheck(_systemWebSocketOnKeyCheck);
  212. #endif
  213. // Init device-specific hardware
  214. _systemSetupSpecificHardware();
  215. // Register Loop
  216. espurnaRegisterLoop(systemLoop);
  217. // Cache Heartbeat values
  218. _systemSetupHeartbeat();
  219. }