diff --git a/code/espurna/config/general.h b/code/espurna/config/general.h index 9747690f..48139989 100644 --- a/code/espurna/config/general.h +++ b/code/espurna/config/general.h @@ -399,6 +399,11 @@ #define RELAY_MQTT_OFF "0" #endif +// TODO Only single EEPROM address is used to store state, which is 1 byte +// Relay status is stored using bitfield. +// This means that, atm, we are only storing the status of the first 8 relays. +#define RELAY_SAVE_MASK_MAX 8 + // ----------------------------------------------------------------------------- // WIFI // ----------------------------------------------------------------------------- diff --git a/code/espurna/config/prototypes.h b/code/espurna/config/prototypes.h index 684637c4..74bfcc8b 100644 --- a/code/espurna/config/prototypes.h +++ b/code/espurna/config/prototypes.h @@ -6,10 +6,19 @@ extern "C" { #include "user_interface.h" + extern struct rst_info resetInfo; } #define UNUSED(x) (void)(x) +// ----------------------------------------------------------------------------- +// System +// ----------------------------------------------------------------------------- + +uint32_t systemResetReason(); +uint8_t systemStabilityCounter(); +void systemStabilityCounter(uint8_t); + // ----------------------------------------------------------------------------- // API // ----------------------------------------------------------------------------- @@ -134,6 +143,11 @@ typedef struct { int16_t rssi; } packet_t; +// ----------------------------------------------------------------------------- +// Relay +// ----------------------------------------------------------------------------- +#include + // ----------------------------------------------------------------------------- // Settings // ----------------------------------------------------------------------------- @@ -214,7 +228,6 @@ typedef std::function wifi_cal void wifiRegister(wifi_callback_f callback); bool wifiConnected(); -// ----------------------------------------------------------------------------- // THERMOSTAT // ----------------------------------------------------------------------------- #if THERMOSTAT_SUPPORT @@ -224,3 +237,8 @@ bool wifiConnected(); #define thermostat_callback_f void * #endif +// ----------------------------------------------------------------------------- +// RTC MEMORY +// ----------------------------------------------------------------------------- +#include "rtcmem.h" + diff --git a/code/espurna/config/rtcmem.h b/code/espurna/config/rtcmem.h new file mode 100644 index 00000000..ae58ae59 --- /dev/null +++ b/code/espurna/config/rtcmem.h @@ -0,0 +1,44 @@ +#pragma once + +// Base address of USER RTC memory +// https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map#memmory-mapped-io-registers +#define RTCMEM_ADDR_BASE (0x60001200) + +// RTC memory is accessed using blocks of 4 bytes. +// Blocks 0..63 are reserved by the SDK, 64..192 are available to the user. +// Blocks 64..96 are reserved by the eboot 'struct eboot_command' (128 -> (128 / 4) -> 32): +// https://github.com/esp8266/Arduino/blob/master/bootloaders/eboot/eboot_command.h +#define RTCMEM_OFFSET 32u +#define RTCMEM_ADDR (RTCMEM_ADDR_BASE + (RTCMEM_OFFSET * 4u)) + +#define RTCMEM_BLOCKS 96u + +// Change this when modifying RtcmemData +#define RTCMEM_MAGIC 0x45535075 + +// XXX When using bitfields / inner structs / etc: +// ... +// uint32_t a : 8; +// uint32_t b : 8; +// uint32_t c : 8; +// uint32_t d : 8; +// ... +// mem->d = 4; +// At the same time writes 4 to the a, b and c + +// TODO replace with custom memory segment in ldscript +struct RtcmemData { + uint32_t magic; + uint32_t sys; + uint32_t relay; + uint32_t mqtt; + uint64_t light; + double energy; +}; + +static_assert(sizeof(RtcmemData) <= (RTCMEM_BLOCKS * 4u), "RTCMEM struct is too big"); +constexpr uint8_t RtcmemSize = (sizeof(RtcmemData) / 4u); + +auto Rtcmem = reinterpret_cast(RTCMEM_ADDR); + +bool rtcmemStatus(); diff --git a/code/espurna/espurna.ino b/code/espurna/espurna.ino index 74c96524..7f368110 100644 --- a/code/espurna/espurna.ino +++ b/code/espurna/espurna.ino @@ -67,6 +67,9 @@ void setup() { debugSetup(); #endif + // Init RTCMEM + rtcmemSetup(); + // Init EEPROM eepromSetup(); diff --git a/code/espurna/light.ino b/code/espurna/light.ino index d3db6adf..5e58b5b3 100644 --- a/code/espurna/light.ino +++ b/code/espurna/light.ino @@ -470,7 +470,47 @@ void _lightProviderUpdate() { // PERSISTANCE // ----------------------------------------------------------------------------- -void _lightColorSave() { +union light_rtcmem_t { + struct { + uint8_t channels[5]; + uint8_t brightness; + uint16_t mired; + } packed; + uint64_t value; +}; + +#define LIGHT_RTCMEM_CHANNELS_MAX sizeof(light_rtcmem_t().packed.channels) + +void _lightSaveRtcmem() { + if (lightChannels() > LIGHT_RTCMEM_CHANNELS_MAX) return; + + light_rtcmem_t light; + + for (unsigned int i=0; i < lightChannels(); i++) { + light.packed.channels[i] = _light_channel[i].inputValue; + } + + light.packed.brightness = _light_brightness; + light.packed.mired = _light_mireds; + + Rtcmem->light = light.value; +} + +void _lightRestoreRtcmem() { + if (lightChannels() > LIGHT_RTCMEM_CHANNELS_MAX) return; + + light_rtcmem_t light; + light.value = Rtcmem->light; + + for (unsigned int i=0; i < lightChannels(); i++) { + _light_channel[i].inputValue = light.packed.channels[i]; + } + + _light_brightness = light.packed.brightness; + _light_mireds = light.packed.mired; +} + +void _lightSaveSettings() { for (unsigned int i=0; i < _light_channel.size(); i++) { setSetting("ch", i, _light_channel[i].inputValue); } @@ -479,7 +519,7 @@ void _lightColorSave() { saveSettings(); } -void _lightColorRestore() { +void _lightRestoreSettings() { for (unsigned int i=0; i < _light_channel.size(); i++) { _light_channel[i].inputValue = getSetting("ch", i, i==0 ? 255 : 0).toInt(); } @@ -699,9 +739,11 @@ void lightUpdate(bool save, bool forward, bool group_forward) { if (group_forward) mask += 2; _light_comms_ticker.once_ms(LIGHT_COMMS_DELAY, _lightComms, mask); + _lightSaveRtcmem(); + #if LIGHT_SAVE_ENABLED // Delay saving to EEPROM 5 seconds to avoid wearing it out unnecessarily - if (save) _light_save_ticker.once(LIGHT_SAVE_DELAY, _lightColorSave); + if (save) _light_save_ticker.once(LIGHT_SAVE_DELAY, _lightSaveSettings); #endif }; @@ -712,7 +754,7 @@ void lightUpdate(bool save, bool forward) { #if LIGHT_SAVE_ENABLED == 0 void lightSave() { - _lightColorSave(); + _lightSaveSettings(); } #endif @@ -1166,7 +1208,11 @@ void lightSetup() { DEBUG_MSG_P(PSTR("[LIGHT] Number of channels: %d\n"), _light_channel.size()); _lightConfigure(); - _lightColorRestore(); + if (rtcmemStatus()) { + _lightRestoreRtcmem(); + } else { + _lightRestoreSettings(); + } #if WEB_SUPPORT wsOnSendRegister(_lightWebSocketOnSend); diff --git a/code/espurna/mqtt.ino b/code/espurna/mqtt.ino index 066417bf..e4db050f 100644 --- a/code/espurna/mqtt.ino +++ b/code/espurna/mqtt.ino @@ -267,48 +267,6 @@ void _mqttBackwards() { } } -unsigned long _mqttNextMessageId() { - - static unsigned long id = 0; - - // just reboot, get last count from EEPROM - if (id == 0) { - - // read id from EEPROM and shift it - id = EEPROMr.read(EEPROM_MESSAGE_ID); - if (id == 0xFF) { - - // There was nothing in EEPROM, - // next message is first message - id = 0; - - } else { - - id = (id << 8) + EEPROMr.read(EEPROM_MESSAGE_ID + 1); - id = (id << 8) + EEPROMr.read(EEPROM_MESSAGE_ID + 2); - id = (id << 8) + EEPROMr.read(EEPROM_MESSAGE_ID + 3); - - // Calculate next block and start from there - id = MQTT_MESSAGE_ID_SHIFT * (1 + (id / MQTT_MESSAGE_ID_SHIFT)); - - } - - } - - // Save to EEPROM every MQTT_MESSAGE_ID_SHIFT - if (id % MQTT_MESSAGE_ID_SHIFT == 0) { - EEPROMr.write(EEPROM_MESSAGE_ID + 0, (id >> 24) & 0xFF); - EEPROMr.write(EEPROM_MESSAGE_ID + 1, (id >> 16) & 0xFF); - EEPROMr.write(EEPROM_MESSAGE_ID + 2, (id >> 8) & 0xFF); - EEPROMr.write(EEPROM_MESSAGE_ID + 3, (id >> 0) & 0xFF); - eepromCommit(); - } - - id++; - return id; - -} - // ----------------------------------------------------------------------------- // WEB // ----------------------------------------------------------------------------- @@ -628,7 +586,7 @@ void mqttFlush() { root[MQTT_TOPIC_IP] = getIP(); #endif #if MQTT_ENQUEUE_MESSAGE_ID - root[MQTT_TOPIC_MESSAGE_ID] = _mqttNextMessageId(); + root[MQTT_TOPIC_MESSAGE_ID] = (Rtcmem->mqtt)++; #endif // Send diff --git a/code/espurna/relay.ino b/code/espurna/relay.ino index 2294a122..8f3eb5e6 100644 --- a/code/espurna/relay.ino +++ b/code/espurna/relay.ino @@ -196,11 +196,11 @@ void _relayProcess(bool mode) { relayPulse(id); - // We will trigger a commit only if + // We will trigger a eeprom save only if // we care about current relay status on boot unsigned char boot_mode = getSetting("relayBoot", id, RELAY_BOOT_MODE).toInt(); - bool do_commit = ((RELAY_BOOT_SAME == boot_mode) || (RELAY_BOOT_TOGGLE == boot_mode)); - _relaySaveTicker.once_ms(RELAY_SAVE_DELAY, relaySave, do_commit); + bool save_eeprom = ((RELAY_BOOT_SAME == boot_mode) || (RELAY_BOOT_TOGGLE == boot_mode)); + _relaySaveTicker.once_ms(RELAY_SAVE_DELAY, relaySave, save_eeprom); #if WEB_SUPPORT wsSend(_relayWebSocketUpdate); @@ -247,6 +247,14 @@ void setSpeed(unsigned char speed) { // RELAY // ----------------------------------------------------------------------------- +void _relayMaskRtcmem(uint32_t mask) { + Rtcmem->relay = mask; +} + +uint32_t _relayMaskRtcmem() { + return Rtcmem->relay; +} + void relayPulse(unsigned char id) { _relays[id].pulseTicker.detach(); @@ -401,41 +409,41 @@ void relaySync(unsigned char id) { } -void relaySave(bool do_commit) { - - // Relay status is stored in a single byte - // This means that, atm, - // we are only storing the status of the first 8 relays. - unsigned char bit = 1; - unsigned char mask = 0; - unsigned char count = _relays.size(); - if (count > 8) count = 8; - for (unsigned int i=0; i < count; i++) { - if (relayStatus(i)) mask += bit; - bit += bit; +void relaySave(bool eeprom) { + + auto mask = std::bitset(0); + + unsigned char count = relayCount(); + if (count > RELAY_SAVE_MASK_MAX) count = RELAY_SAVE_MASK_MAX; + + for (unsigned int i=0; i < count; ++i) { + mask.set(i, relayStatus(i)); } - EEPROMr.write(EEPROM_RELAY_STATUS, mask); - DEBUG_MSG_P(PSTR("[RELAY] Setting relay mask: %d\n"), mask); + const uint32_t mask_value = mask.to_ulong(); + + DEBUG_MSG_P(PSTR("[RELAY] Setting relay mask: %u\n"), mask_value); + + // Persist only to rtcmem, unless requested to save to the eeprom + _relayMaskRtcmem(mask_value); - // The 'do_commit' flag controls wether we are commiting this change or not. + // The 'eeprom' flag controls wether we are commiting this change or not. // It is useful to set it to 'false' if the relay change triggering the // save involves a relay whose boot mode is independent from current mode, // thus storing the last relay value is not absolutely necessary. // Nevertheless, we store the value in the EEPROM buffer so it will be written // on the next commit. - if (do_commit) { - + if (eeprom) { + EEPROMr.write(EEPROM_RELAY_STATUS, mask_value); // We are actually enqueuing the commit so it will be - // executed on the main loop, in case this is called from a callback + // executed on the main loop, in case this is called from a system context callback eepromCommit(); - } } void relaySave() { - relaySave(true); + relaySave(false); } void relayToggle(unsigned char id, bool report, bool group_report) { @@ -514,32 +522,37 @@ void _relayBackwards() { void _relayBoot() { _relayRecursive = true; - - unsigned char bit = 1; bool trigger_save = false; + uint32_t stored_mask = 0; - // Get last statuses from EEPROM - unsigned char mask = EEPROMr.read(EEPROM_RELAY_STATUS); - DEBUG_MSG_P(PSTR("[RELAY] Retrieving mask: %d\n"), mask); + if (rtcmemStatus()) { + stored_mask = _relayMaskRtcmem(); + } else { + stored_mask = EEPROMr.read(EEPROM_RELAY_STATUS); + } + + DEBUG_MSG_P(PSTR("[RELAY] Retrieving mask: %u\n"), stored_mask); + + auto mask = std::bitset(stored_mask); // Walk the relays bool status; - for (unsigned int i=0; i<_relays.size(); i++) { + for (unsigned char i=0; imagic = RTCMEM_MAGIC; +} + +// Treat memory as dirty on cold boot, hardware wdt reset and rst pin +bool _rtcmemStatus() { + bool readable; + + switch (systemResetReason()) { + case REASON_EXT_SYS_RST: + case REASON_WDT_RST: + case REASON_DEFAULT_RST: + readable = false; + break; + default: + readable = true; + } + + readable = readable and (RTCMEM_MAGIC == Rtcmem->magic); + + return readable; +} + +#if TERMINAL_SUPPORT + +void _rtcmemInitCommands() { + terminalRegisterCommand(F("RTCMEM.REINIT"), [](Embedis* e) { + _rtcmemInit(); + }); + + terminalRegisterCommand(F("RTCMEM.TEST"), [](Embedis* e) { + }); + + terminalRegisterCommand(F("RTCMEM.DUMP"), [](Embedis* e) { + DEBUG_MSG_P(PSTR("[RTCMEM] status:%u blocks:%u addr:0x%p\n"), + _rtcmemStatus(), RtcmemSize, Rtcmem); + + for (uint8_t block=0; block(RTCMEM_ADDR)[block]); + } + }); +} + +#endif + +bool rtcmemStatus() { + return _rtcmem_status; +} + +void rtcmemSetup() { + _rtcmem_status = _rtcmemStatus(); + if (!_rtcmem_status) { + _rtcmemInit(); + } + + #if TERMINAL_SUPPORT + _rtcmemInitCommands(); + #endif +} diff --git a/code/espurna/sensor.ino b/code/espurna/sensor.ino index 282b37dc..6bf718c1 100644 --- a/code/espurna/sensor.ino +++ b/code/espurna/sensor.ino @@ -423,6 +423,35 @@ void _sensorResetTS() { #endif } +double _sensorEnergyTotal() { + double value = 0; + + if (rtcmemStatus()) { + value = Rtcmem->energy; + } else { + value = (_sensor_save_every > 0) ? getSetting("eneTotal", 0).toInt() : 0; + } + + return value; +} + + +void _sensorEnergyTotal(double value) { + static unsigned long save_count = 0; + + // Save to EEPROM every '_sensor_save_every' readings + if (_sensor_save_every > 0) { + save_count = (save_count + 1) % _sensor_save_every; + if (0 == save_count) { + setSetting("eneTotal", value); + saveSettings(); + } + } + + // Always save to RTCMEM + Rtcmem->energy = value; +} + // ----------------------------------------------------------------------------- // Sensor initialization // ----------------------------------------------------------------------------- @@ -939,7 +968,9 @@ void _sensorInit() { EmonAnalogSensor * sensor = (EmonAnalogSensor *) _sensors[i]; sensor->setCurrentRatio(0, getSetting("pwrRatioC", EMON_CURRENT_RATIO).toFloat()); sensor->setVoltage(getSetting("pwrVoltage", EMON_MAINS_VOLTAGE).toInt()); - double value = (_sensor_save_every > 0) ? getSetting("eneTotal", 0).toInt() : 0; + + double value = _sensorEnergyTotal(); + if (value > 0) sensor->resetEnergy(0, value); } @@ -962,7 +993,7 @@ void _sensorInit() { value = getSetting("pwrRatioP", HLW8012_POWER_RATIO).toFloat(); if (value > 0) sensor->setPowerRatio(value); - value = (_sensor_save_every > 0) ? getSetting("eneTotal", 0).toInt() : 0; + value = _sensorEnergyTotal(); if (value > 0) sensor->resetEnergy(value); } @@ -986,7 +1017,7 @@ void _sensorInit() { value = getSetting("pwrRatioP", 0).toFloat(); if (value > 0) sensor->setPowerRatio(value); - value = (_sensor_save_every > 0) ? getSetting("eneTotal", 0).toInt() : 0; + value = _sensorEnergyTotal(); if (value > 0) sensor->resetEnergy(value); } @@ -1426,7 +1457,6 @@ void sensorLoop() { // Check if we should read new data static unsigned long last_update = 0; static unsigned long report_count = 0; - static unsigned long save_count = 0; if (millis() - last_update > _sensor_read_interval) { last_update = millis(); @@ -1532,23 +1562,11 @@ void sensorLoop() { _sensorReport(i, value_filtered); } // if (fabs(value_filtered - magnitude.reported) >= magnitude.min_change) - // ------------------------------------------------------------- - // Saving to EEPROM - // (we do it every _sensor_save_every readings) - // ------------------------------------------------------------- - - if (_sensor_save_every > 0) { - - save_count = (save_count + 1) % _sensor_save_every; - if (0 == save_count) { - if (MAGNITUDE_ENERGY == magnitude.type) { - setSetting("eneTotal", value_raw); - saveSettings(); - } - } // if (0 == save_count) - - } // if (_sensor_save_every > 0) + // Persist total energy value + if (MAGNITUDE_ENERGY == magnitude.type) { + _sensorEnergyTotal(value_raw); + } } // if (report_count == 0) diff --git a/code/espurna/settings.ino b/code/espurna/settings.ino index 6c45a6ac..00b00686 100644 --- a/code/espurna/settings.ino +++ b/code/espurna/settings.ino @@ -245,4 +245,4 @@ void settingsSetup() { #endif ); -} \ No newline at end of file +} diff --git a/code/espurna/system.ino b/code/espurna/system.ino index bf03c6de..5853fb6d 100644 --- a/code/espurna/system.ino +++ b/code/espurna/system.ino @@ -6,6 +6,7 @@ Copyright (C) 2019 by Xose Pérez */ +#include #include // ----------------------------------------------------------------------------- @@ -19,6 +20,41 @@ unsigned short int _load_average = 100; // ----------------------------------------------------------------------------- +union system_rtcmem_t { + struct { + uint8_t stability_counter; + uint8_t reset_reason; + uint16_t _reserved_; + } parts; + uint32_t value; +}; + +uint8_t systemStabilityCounter() { + system_rtcmem_t data; + data.value = Rtcmem->sys; + return data.parts.stability_counter; +} + +void systemStabilityCounter(uint8_t counter) { + system_rtcmem_t data; + data.value = Rtcmem->sys; + data.parts.stability_counter = counter; + Rtcmem->sys = data.value; +} + +uint8_t _systemResetReason() { + system_rtcmem_t data; + data.value = Rtcmem->sys; + return data.parts.reset_reason; +} + +void _systemResetReason(uint8_t reason) { + system_rtcmem_t data; + data.value = Rtcmem->sys; + data.parts.reset_reason = reason; + Rtcmem->sys = data.value; +} + #if SYSTEM_CHECK_ENABLED // Call this method on boot with start=true to increase the crash counter @@ -31,19 +67,27 @@ unsigned short int _load_average = 100; bool _systemStable = true; void systemCheck(bool stable) { - unsigned char value = EEPROMr.read(EEPROM_CRASH_COUNTER); + uint8_t value = 0; + if (stable) { value = 0; DEBUG_MSG_P(PSTR("[MAIN] System OK\n")); } else { + if (!rtcmemStatus()) { + systemStabilityCounter(1); + return; + } + + value = systemStabilityCounter(); + if (++value > SYSTEM_CHECK_MAX) { _systemStable = false; value = 0; DEBUG_MSG_P(PSTR("[MAIN] System UNSTABLE\n")); } } - EEPROMr.write(EEPROM_CRASH_COUNTER, value); - eepromCommit(); + + systemStabilityCounter(value); } bool systemCheck() { @@ -53,7 +97,7 @@ bool systemCheck() { void systemCheckLoop() { static bool checked = false; if (!checked && (millis() > SYSTEM_CHECK_TIME)) { - // Check system as stable + // Flag system as stable systemCheck(true); checked = true; } @@ -61,6 +105,44 @@ void systemCheckLoop() { #endif +// ----------------------------------------------------------------------------- +// Reset +// ----------------------------------------------------------------------------- +Ticker _defer_reset; +uint8_t _reset_reason = 0; + +// system_get_rst_info() result is cached by the Core init for internal use +uint32_t systemResetReason() { + return resetInfo.reason; +} + +void customResetReason(unsigned char reason) { + _reset_reason = reason; + _systemResetReason(reason); +} + +unsigned char customResetReason() { + static unsigned char status = 255; + if (status == 255) { + if (rtcmemStatus()) status = _systemResetReason(); + if (status > 0) customResetReason(0); + if (status > CUSTOM_RESET_MAX) status = 0; + } + return status; +} + +void reset() { + ESP.restart(); +} + +void deferredReset(unsigned long delay, unsigned char reason) { + _defer_reset.once_ms(delay, customResetReason, reason); +} + +bool checkNeedsReset() { + return _reset_reason > 0; +} + // ----------------------------------------------------------------------------- void systemSendHeartbeat() { diff --git a/code/espurna/terminal.ino b/code/espurna/terminal.ino index 4e97d970..c67d6fd6 100644 --- a/code/espurna/terminal.ino +++ b/code/espurna/terminal.ino @@ -95,8 +95,7 @@ void _terminalInitCommand() { terminalRegisterCommand(F("ERASE.CONFIG"), [](Embedis* e) { terminalOK(); - resetReason(CUSTOM_RESET_TERMINAL); - _eepromCommit(); + customResetReason(CUSTOM_RESET_TERMINAL); eraseSDKConfig(); *((int*) 0) = 0; // see https://github.com/esp8266/Arduino/issues/1494 }); @@ -180,7 +179,7 @@ void _terminalInitCommand() { }); terminalRegisterCommand(F("RESET.SAFE"), [](Embedis* e) { - EEPROMr.write(EEPROM_CRASH_COUNTER, SYSTEM_CHECK_MAX); + systemStabilityCounter(SYSTEM_CHECK_MAX); terminalOK(); deferredReset(100, CUSTOM_RESET_TERMINAL); }); diff --git a/code/espurna/utils.ino b/code/espurna/utils.ino index d1134779..3067f45f 100644 --- a/code/espurna/utils.ino +++ b/code/espurna/utils.ino @@ -7,9 +7,6 @@ Copyright (C) 2017-2019 by Xose Pérez */ #include -Ticker _defer_reset; - -uint8_t _reset_reason = 0; String getIdentifier() { char buffer[20]; @@ -473,7 +470,7 @@ void info() { DEBUG_MSG_P(PSTR("[MAIN] Boot version: %d\n"), ESP.getBootVersion()); DEBUG_MSG_P(PSTR("[MAIN] Boot mode: %d\n"), ESP.getBootMode()); - unsigned char reason = resetReason(); + unsigned char reason = customResetReason(); if (reason > 0) { char buffer[32]; strcpy_P(buffer, custom_reset_string[reason-1]); @@ -571,34 +568,6 @@ bool sslFingerPrintChar(const char * fingerprint, char * destination) { // Reset // ----------------------------------------------------------------------------- -unsigned char resetReason() { - static unsigned char status = 255; - if (status == 255) { - status = EEPROMr.read(EEPROM_CUSTOM_RESET); - if (status > 0) resetReason(0); - if (status > CUSTOM_RESET_MAX) status = 0; - } - return status; -} - -void resetReason(unsigned char reason) { - _reset_reason = reason; - EEPROMr.write(EEPROM_CUSTOM_RESET, reason); - eepromCommit(); -} - -void reset() { - ESP.restart(); -} - -void deferredReset(unsigned long delay, unsigned char reason) { - _defer_reset.once_ms(delay, resetReason, reason); -} - -bool checkNeedsReset() { - return _reset_reason > 0; -} - // Use fixed method for Core 2.3.0, because it erases only 2 out of 4 SDK-reserved sectors // Fixed since 2.4.0, see: esp8266/core/esp8266/Esp.cpp: ESP::eraseConfig() bool eraseSDKConfig() { @@ -618,6 +587,8 @@ bool eraseSDKConfig() { #endif } +// ----------------------------------------------------------------------------- +// Helper functions // ----------------------------------------------------------------------------- char * ltrim(char * s) {