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.

278 lines
7.1 KiB

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
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 <Ticker.h>
  6. #include <EEPROM_Rotate.h>
  7. #include "system.h"
  8. // -----------------------------------------------------------------------------
  9. bool _system_send_heartbeat = false;
  10. unsigned char _heartbeat_mode = HEARTBEAT_MODE;
  11. unsigned long _heartbeat_interval = HEARTBEAT_INTERVAL;
  12. // Calculated load average 0 to 100;
  13. unsigned short int _load_average = 100;
  14. // -----------------------------------------------------------------------------
  15. union system_rtcmem_t {
  16. struct {
  17. uint8_t stability_counter;
  18. uint8_t reset_reason;
  19. uint16_t _reserved_;
  20. } packed;
  21. uint32_t value;
  22. };
  23. uint8_t systemStabilityCounter() {
  24. system_rtcmem_t data;
  25. data.value = Rtcmem->sys;
  26. return data.packed.stability_counter;
  27. }
  28. void systemStabilityCounter(uint8_t count) {
  29. system_rtcmem_t data;
  30. data.value = Rtcmem->sys;
  31. data.packed.stability_counter = count;
  32. Rtcmem->sys = data.value;
  33. }
  34. uint8_t _systemResetReason() {
  35. system_rtcmem_t data;
  36. data.value = Rtcmem->sys;
  37. return data.packed.reset_reason;
  38. }
  39. void _systemResetReason(uint8_t reason) {
  40. system_rtcmem_t data;
  41. data.value = Rtcmem->sys;
  42. data.packed.reset_reason = reason;
  43. Rtcmem->sys = data.value;
  44. }
  45. #if SYSTEM_CHECK_ENABLED
  46. // Call this method on boot with start=true to increase the crash counter
  47. // Call it again once the system is stable to decrease the counter
  48. // If the counter reaches SYSTEM_CHECK_MAX then the system is flagged as unstable
  49. // setting _systemOK = false;
  50. //
  51. // An unstable system will only have serial access, WiFi in AP mode and OTA
  52. bool _systemStable = true;
  53. void systemCheck(bool stable) {
  54. uint8_t value = 0;
  55. if (stable) {
  56. value = 0;
  57. DEBUG_MSG_P(PSTR("[MAIN] System OK\n"));
  58. } else {
  59. if (!rtcmemStatus()) {
  60. systemStabilityCounter(1);
  61. return;
  62. }
  63. value = systemStabilityCounter();
  64. if (++value > SYSTEM_CHECK_MAX) {
  65. _systemStable = false;
  66. value = 0;
  67. DEBUG_MSG_P(PSTR("[MAIN] System UNSTABLE\n"));
  68. }
  69. }
  70. systemStabilityCounter(value);
  71. }
  72. bool systemCheck() {
  73. return _systemStable;
  74. }
  75. void systemCheckLoop() {
  76. static bool checked = false;
  77. if (!checked && (millis() > SYSTEM_CHECK_TIME)) {
  78. // Flag system as stable
  79. systemCheck(true);
  80. checked = true;
  81. }
  82. }
  83. #endif
  84. // -----------------------------------------------------------------------------
  85. // Reset
  86. // -----------------------------------------------------------------------------
  87. Ticker _defer_reset;
  88. uint8_t _reset_reason = 0;
  89. // system_get_rst_info() result is cached by the Core init for internal use
  90. uint32_t systemResetReason() {
  91. return resetInfo.reason;
  92. }
  93. void customResetReason(unsigned char reason) {
  94. _reset_reason = reason;
  95. _systemResetReason(reason);
  96. }
  97. unsigned char customResetReason() {
  98. static unsigned char status = 255;
  99. if (status == 255) {
  100. if (rtcmemStatus()) status = _systemResetReason();
  101. if (status > 0) customResetReason(0);
  102. if (status > CUSTOM_RESET_MAX) status = 0;
  103. }
  104. return status;
  105. }
  106. void reset() {
  107. ESP.restart();
  108. }
  109. void deferredReset(unsigned long delay, unsigned char reason) {
  110. _defer_reset.once_ms(delay, customResetReason, reason);
  111. }
  112. bool checkNeedsReset() {
  113. return _reset_reason > 0;
  114. }
  115. // -----------------------------------------------------------------------------
  116. void systemSendHeartbeat() {
  117. _system_send_heartbeat = true;
  118. }
  119. bool systemGetHeartbeat() {
  120. return _system_send_heartbeat;
  121. }
  122. unsigned long systemLoadAverage() {
  123. return _load_average;
  124. }
  125. void _systemSetupHeartbeat() {
  126. _heartbeat_mode = getSetting("hbMode", HEARTBEAT_MODE).toInt();
  127. _heartbeat_interval = getSetting("hbInterval", HEARTBEAT_INTERVAL).toInt();
  128. }
  129. #if WEB_SUPPORT
  130. bool _systemWebSocketOnKeyCheck(const char * key, JsonVariant& value) {
  131. if (strncmp(key, "sys", 3) == 0) return true;
  132. if (strncmp(key, "hb", 2) == 0) return true;
  133. return false;
  134. }
  135. #endif
  136. void systemLoop() {
  137. // -------------------------------------------------------------------------
  138. // User requested reset
  139. // -------------------------------------------------------------------------
  140. if (checkNeedsReset()) {
  141. reset();
  142. }
  143. // -------------------------------------------------------------------------
  144. // Check system stability
  145. // -------------------------------------------------------------------------
  146. #if SYSTEM_CHECK_ENABLED
  147. systemCheckLoop();
  148. #endif
  149. // -------------------------------------------------------------------------
  150. // Heartbeat
  151. // -------------------------------------------------------------------------
  152. if (_system_send_heartbeat && _heartbeat_mode == HEARTBEAT_ONCE) {
  153. heartbeat();
  154. _system_send_heartbeat = false;
  155. } else if (_heartbeat_mode == HEARTBEAT_REPEAT || _heartbeat_mode == HEARTBEAT_REPEAT_STATUS) {
  156. static unsigned long last_hbeat = 0;
  157. #if NTP_SUPPORT
  158. if ((_system_send_heartbeat && ntpSynced()) || (millis() - last_hbeat > _heartbeat_interval * 1000)) {
  159. #else
  160. if (_system_send_heartbeat || (millis() - last_hbeat > _heartbeat_interval * 1000)) {
  161. #endif
  162. last_hbeat = millis();
  163. heartbeat();
  164. _system_send_heartbeat = false;
  165. }
  166. }
  167. // -------------------------------------------------------------------------
  168. // Load Average calculation
  169. // -------------------------------------------------------------------------
  170. static unsigned long last_loadcheck = 0;
  171. static unsigned long load_counter_temp = 0;
  172. load_counter_temp++;
  173. if (millis() - last_loadcheck > LOADAVG_INTERVAL) {
  174. static unsigned long load_counter = 0;
  175. static unsigned long load_counter_max = 1;
  176. load_counter = load_counter_temp;
  177. load_counter_temp = 0;
  178. if (load_counter > load_counter_max) {
  179. load_counter_max = load_counter;
  180. }
  181. _load_average = 100 - (100 * load_counter / load_counter_max);
  182. last_loadcheck = millis();
  183. }
  184. }
  185. void _systemSetupSpecificHardware() {
  186. //The ESPLive has an ADC MUX which needs to be configured.
  187. #if defined(MANCAVEMADE_ESPLIVE)
  188. pinMode(16, OUTPUT);
  189. digitalWrite(16, HIGH); //Defualt CT input (pin B, solder jumper B)
  190. #endif
  191. // These devices use the hardware UART
  192. // to communicate to secondary microcontrollers
  193. #if (RF_SUPPORT && !RFB_DIRECT) || (RELAY_PROVIDER == RELAY_PROVIDER_DUAL) || (RELAY_PROVIDER == RELAY_PROVIDER_STM)
  194. Serial.begin(SERIAL_BAUDRATE);
  195. #endif
  196. }
  197. void systemSetup() {
  198. #if SPIFFS_SUPPORT
  199. SPIFFS.begin();
  200. #endif
  201. // Question system stability
  202. #if SYSTEM_CHECK_ENABLED
  203. systemCheck(false);
  204. #endif
  205. #if WEB_SUPPORT
  206. wsRegister().onKeyCheck(_systemWebSocketOnKeyCheck);
  207. #endif
  208. // Init device-specific hardware
  209. _systemSetupSpecificHardware();
  210. // Register Loop
  211. espurnaRegisterLoop(systemLoop);
  212. // Cache Heartbeat values
  213. _systemSetupHeartbeat();
  214. }