From ef128fdafb5ac56f9ba23cb088e02a2a94350412 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 13 Aug 2020 16:25:48 +0200 Subject: [PATCH] Make Quick Power Cycle Detection Actually work --- tasmota/settings.ino | 80 +++++++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 31 deletions(-) diff --git a/tasmota/settings.ino b/tasmota/settings.ino index 09184b093..9beb8f7de 100644 --- a/tasmota/settings.ino +++ b/tasmota/settings.ino @@ -334,46 +334,62 @@ void SettingsSaveAll(void) * Quick power cycle monitoring \*********************************************************************************************/ -void UpdateQuickPowerCycle(bool update) -{ +void UpdateQuickPowerCycle(bool update) { #ifndef FIRMWARE_MINIMAL if (Settings.flag3.fast_power_cycle_disable) { return; } // SetOption65 - Disable fast power cycle detection for device reset - uint32_t pc_register; - uint32_t pc_location = SETTINGS_LOCATION - CFG_ROTATES; + const uint32_t QPC_COUNT = 7; // Number of Power Cycles before Settings erase + const uint32_t QPC_SIGNATURE = 0xFFA55AFF; #ifdef ESP8266 - ESP.flashRead(pc_location * SPI_FLASH_SEC_SIZE, (uint32*)&pc_register, sizeof(pc_register)); -#else // ESP32 - QPCRead(&pc_register, sizeof(pc_register)); -#endif // ESP8266 - ESP32 - if (update && ((pc_register & 0xFFFFFF80) == 0xFFA55A80)) { - uint32_t counter = ((pc_register & 0x7F) << 1) & 0x7F; - if (0 == counter) { // 7 power cycles in a row - SettingsErase(3); // Quickly reset all settings including QuickPowerCycle flag - EspRestart(); // And restart + const uint32_t qpc_sector = SETTINGS_LOCATION - CFG_ROTATES; + const uint32_t qpc_location = qpc_sector * SPI_FLASH_SEC_SIZE; + + uint32_t qpc_buffer[QPC_COUNT +1]; + ESP.flashRead(qpc_location, (uint32*)&qpc_buffer, sizeof(qpc_buffer)); + if (update && (QPC_SIGNATURE == qpc_buffer[0])) { + uint32_t counter = 1; + while ((0 == qpc_buffer[counter]) && (counter <= QPC_COUNT)) { counter++; } + if (QPC_COUNT == counter) { // 7 power cycles in a row + SettingsErase(3); // Quickly reset all settings including QuickPowerCycle flag + EspRestart(); // And restart } else { - pc_register = 0xFFA55AB0 | counter; -#ifdef ESP8266 - ESP.flashWrite(pc_location * SPI_FLASH_SEC_SIZE, (uint32*)&pc_register, sizeof(pc_register)); -#else // ESP32 - QPCWrite(&pc_register, sizeof(pc_register)); -#endif // ESP8266 - ESP32 - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("QPC: Flag %02X"), counter); + qpc_buffer[0] = 0; + ESP.flashWrite(qpc_location + (counter * 4), (uint32*)&qpc_buffer, 4); + AddLog_P2(LOG_LEVEL_INFO, PSTR("QPC: Count %d"), counter); } } - else if (pc_register != 0xFFA55AFF) { - pc_register = 0xFFA55AFF; -#ifdef ESP8266 + else if ((qpc_buffer[0] != QPC_SIGNATURE) || (0 == qpc_buffer[1])) { + qpc_buffer[0] = QPC_SIGNATURE; // Assume flash is default all ones and setting a bit to zero does not need an erase - if (ESP.flashEraseSector(pc_location)) { - ESP.flashWrite(pc_location * SPI_FLASH_SEC_SIZE, (uint32*)&pc_register, sizeof(pc_register)); + if (ESP.flashEraseSector(qpc_sector)) { + ESP.flashWrite(qpc_location, (uint32*)&qpc_buffer, 4); + AddLog_P2(LOG_LEVEL_INFO, PSTR("QPC: Reset")); } -#else // ESP32 - QPCWrite(&pc_register, sizeof(pc_register)); -#endif // ESP8266 - ESP32 - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("QPC: Reset")); } +#else // ESP32 + uint32_t pc_register; + QPCRead(&pc_register, sizeof(pc_register)); + if (update && ((pc_register & 0xFFFFFFF0) == 0xFFA55AF0)) { + uint32_t counter = pc_register & 0xF; // Allow up to 15 cycles + if (0xF == counter) { counter = 0; } + counter++; + if (QPC_COUNT == counter) { // 7 power cycles in a row + SettingsErase(3); // Quickly reset all settings including QuickPowerCycle flag + EspRestart(); // And restart + } else { + pc_register = 0xFFA55AF0 | counter; + QPCWrite(&pc_register, sizeof(pc_register)); + AddLog_P2(LOG_LEVEL_INFO, PSTR("QPC: Count %d"), counter); + } + } + else if (pc_register != QPC_SIGNATURE) { + pc_register = QPC_SIGNATURE; + QPCWrite(&pc_register, sizeof(pc_register)); + AddLog_P2(LOG_LEVEL_INFO, PSTR("QPC: Reset")); + } +#endif // ESP8266 or ESP32 + #endif // FIRMWARE_MINIMAL } @@ -556,6 +572,7 @@ void SettingsLoad(void) { #ifdef ESP8266 // Load configuration from eeprom or one of 7 slots below if first valid load does not stop_flash_rotate #ifdef CFG_LEGACY_LOAD + // Active until version 8.4.0.2 struct { uint16_t cfg_holder; // 000 uint16_t cfg_size; // 002 @@ -598,11 +615,11 @@ void SettingsLoad(void) { AddLog_P2(LOG_LEVEL_NONE, PSTR(D_LOG_CONFIG D_LOADED_FROM_FLASH_AT " %X, " D_COUNT " %lu"), settings_location, Settings.save_flag); } #else // CFG_RESILIENT + // Activated with version 8.4.0.2 settings_location = 0; uint32_t save_flag = 0; - uint32_t flash_location = SETTINGS_LOCATION +1; + uint32_t flash_location = SETTINGS_LOCATION; for (uint32_t i = 0; i < CFG_ROTATES; i++) { // Read all config pages in search of valid and latest - flash_location--; ESP.flashRead(flash_location * SPI_FLASH_SEC_SIZE, (uint32*)&Settings, sizeof(Settings)); if ((Settings.cfg_crc32 != 0xFFFFFFFF) && (Settings.cfg_crc32 != 0x00000000) && (Settings.cfg_crc32 == GetSettingsCrc32())) { if (Settings.save_flag > save_flag) { // Find latest page based on incrementing save_flag @@ -613,6 +630,7 @@ void SettingsLoad(void) { } } } + flash_location--; delay(1); } if (settings_location > 0) {