From cdcb1533b93984c5c69c0f52cc1e83385721b354 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 6 May 2021 15:23:41 +0200 Subject: [PATCH] Prep for MQTT Settings save --- tasmota/settings.ino | 230 +++++++++++++++++++++------------- tasmota/support_tasmota.ino | 1 - tasmota/xdrv_01_webserver.ino | 66 +--------- 3 files changed, 151 insertions(+), 146 deletions(-) diff --git a/tasmota/settings.ino b/tasmota/settings.ino index 0fc0f3f74..5b512ee75 100644 --- a/tasmota/settings.ino +++ b/tasmota/settings.ino @@ -204,6 +204,7 @@ const uint8_t CFG_ROTATES = 7; // Number of flash sectors used (handles upl uint32_t settings_location = EEPROM_LOCATION; uint32_t settings_crc32 = 0; uint8_t *settings_buffer = nullptr; +uint8_t config_xor_on_set = CONFIG_FILE_XOR; void SettingsInit(void) { if (SETTINGS_LOCATION > 0xFA) { @@ -211,91 +212,6 @@ void SettingsInit(void) { } } -/********************************************************************************************/ -/* - * Based on cores/esp8266/Updater.cpp - */ -void SetFlashModeDout(void) { -#ifdef ESP8266 - uint8_t *_buffer; - uint32_t address; - - eboot_command ebcmd; - eboot_command_read(&ebcmd); - address = ebcmd.args[0]; - _buffer = new uint8_t[FLASH_SECTOR_SIZE]; - - if (ESP.flashRead(address, (uint32_t*)_buffer, FLASH_SECTOR_SIZE)) { - if (_buffer[2] != 3) { // DOUT - _buffer[2] = 3; - if (ESP.flashEraseSector(address / FLASH_SECTOR_SIZE)) { - ESP.flashWrite(address, (uint32_t*)_buffer, FLASH_SECTOR_SIZE); - } - } - } - delete[] _buffer; -#endif // ESP8266 -} - -void SettingsBufferFree(void) { - if (settings_buffer != nullptr) { - free(settings_buffer); - settings_buffer = nullptr; - } -} - -bool SettingsBufferAlloc(void) { - SettingsBufferFree(); - if (!(settings_buffer = (uint8_t *)malloc(sizeof(Settings)))) { - AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_UPLOAD_ERR_2)); // Not enough (memory) space - return false; - } - return true; -} - -uint16_t GetCfgCrc16(uint8_t *bytes, uint32_t size) { - uint16_t crc = 0; - - for (uint32_t i = 0; i < size; i++) { - if ((i < 14) || (i > 15)) { crc += bytes[i]*(i+1); } // Skip crc - } - return crc; -} - -uint16_t GetSettingsCrc(void) { - // Fix miscalculation if previous Settings was 3584 and current Settings is 4096 between 0x06060007 and 0x0606000A - uint32_t size = ((Settings.version < 0x06060007) || (Settings.version > 0x0606000A)) ? 3584 : sizeof(Settings); - return GetCfgCrc16((uint8_t*)&Settings, size); -} - -uint32_t GetCfgCrc32(uint8_t *bytes, uint32_t size) { - // https://create.stephan-brumme.com/crc32/#bitwise - uint32_t crc = 0; - - while (size--) { - crc ^= *bytes++; - for (uint32_t j = 0; j < 8; j++) { - crc = (crc >> 1) ^ (-int(crc & 1) & 0xEDB88320); - } - } - return ~crc; -} - -uint32_t GetSettingsCrc32(void) { - return GetCfgCrc32((uint8_t*)&Settings, sizeof(Settings) -4); // Skip crc32 -} - -void SettingsSaveAll(void) { - if (Settings.flag.save_state) { - Settings.power = TasmotaGlobal.power; - } else { - Settings.power = 0; - } - XsnsCall(FUNC_SAVE_BEFORE_RESTART); - XdrvCall(FUNC_SAVE_BEFORE_RESTART); - SettingsSave(0); -} - /*********************************************************************************************\ * Quick power cycle monitoring \*********************************************************************************************/ @@ -360,6 +276,150 @@ void UpdateQuickPowerCycle(bool update) { #endif // FIRMWARE_MINIMAL } +/*********************************************************************************************\ + * Settings services +\*********************************************************************************************/ + +uint16_t GetCfgCrc16(uint8_t *bytes, uint32_t size) { + uint16_t crc = 0; + + for (uint32_t i = 0; i < size; i++) { + if ((i < 14) || (i > 15)) { crc += bytes[i]*(i+1); } // Skip crc + } + return crc; +} + +uint16_t GetSettingsCrc(void) { + // Fix miscalculation if previous Settings was 3584 and current Settings is 4096 between 0x06060007 and 0x0606000A + uint32_t size = ((Settings.version < 0x06060007) || (Settings.version > 0x0606000A)) ? 3584 : sizeof(Settings); + return GetCfgCrc16((uint8_t*)&Settings, size); +} + +uint32_t GetCfgCrc32(uint8_t *bytes, uint32_t size) { + // https://create.stephan-brumme.com/crc32/#bitwise + uint32_t crc = 0; + + while (size--) { + crc ^= *bytes++; + for (uint32_t j = 0; j < 8; j++) { + crc = (crc >> 1) ^ (-int(crc & 1) & 0xEDB88320); + } + } + return ~crc; +} + +uint32_t GetSettingsCrc32(void) { + return GetCfgCrc32((uint8_t*)&Settings, sizeof(Settings) -4); // Skip crc32 +} + +void SettingsSaveAll(void) { + if (Settings.flag.save_state) { + Settings.power = TasmotaGlobal.power; + } else { + Settings.power = 0; + } + XsnsCall(FUNC_SAVE_BEFORE_RESTART); + XdrvCall(FUNC_SAVE_BEFORE_RESTART); + SettingsSave(0); +} + +/*********************************************************************************************\ + * Settings backup and restore +\*********************************************************************************************/ + +void SettingsBufferFree(void) { + if (settings_buffer != nullptr) { + free(settings_buffer); + settings_buffer = nullptr; + } +} + +bool SettingsBufferAlloc(void) { + SettingsBufferFree(); + if (!(settings_buffer = (uint8_t *)malloc(sizeof(Settings)))) { + AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_UPLOAD_ERR_2)); // Not enough (memory) space + return false; + } + return true; +} + +String SettingsConfigFilename(void) { + char filename[TOPSZ]; + char hostname[sizeof(TasmotaGlobal.hostname)]; + snprintf_P(filename, sizeof(filename), PSTR("Config_%s_%s.dmp"), NoAlNumToUnderscore(hostname, TasmotaGlobal.hostname), TasmotaGlobal.version); + return String(filename); +} + +uint32_t SettingsConfigBackup(void) { + if (!SettingsBufferAlloc()) { return 0; } + + uint32_t cfg_crc32 = Settings.cfg_crc32; + Settings.cfg_crc32 = GetSettingsCrc32(); // Calculate crc (again) as it might be wrong when savedata = 0 (#3918) + + uint32_t config_len = sizeof(Settings); + memcpy(settings_buffer, &Settings, config_len); + + Settings.cfg_crc32 = cfg_crc32; // Restore crc in case savedata = 0 to make sure settings will be noted as changed + + if (config_xor_on_set) { + for (uint32_t i = 2; i < config_len; i++) { + settings_buffer[i] ^= (config_xor_on_set +i); + } + } + return config_len; +} + +bool SettingsConfigRestore(void) { + uint32_t config_len = sizeof(Settings); + + if (config_xor_on_set) { + for (uint32_t i = 2; i < config_len; i++) { + settings_buffer[i] ^= (config_xor_on_set +i); + } + } + + bool valid_settings = false; + + // unsigned long version; // 008 + unsigned long buffer_version = settings_buffer[11] << 24 | settings_buffer[10] << 16 | settings_buffer[9] << 8 | settings_buffer[8]; + if (buffer_version > 0x06000000) { + // uint16_t cfg_size; // 002 + uint32_t buffer_size = settings_buffer[3] << 8 | settings_buffer[2]; + if (buffer_version > 0x0606000A) { + // uint32_t cfg_crc32; // FFC + uint32_t buffer_crc32 = settings_buffer[4095] << 24 | settings_buffer[4094] << 16 | settings_buffer[4093] << 8 | settings_buffer[4092]; + valid_settings = (GetCfgCrc32(settings_buffer, buffer_size -4) == buffer_crc32); + } else { + // uint16_t cfg_crc; // 00E + uint16_t buffer_crc16 = settings_buffer[15] << 8 | settings_buffer[14]; + valid_settings = (GetCfgCrc16(settings_buffer, buffer_size) == buffer_crc16); + } + } else { + valid_settings = (settings_buffer[0] == CONFIG_FILE_SIGN); + } + + if (valid_settings) { +#ifdef ESP8266 + // uint8_t config_version; // F36 + valid_settings = (0 == settings_buffer[0xF36]); // Settings.config_version +#endif // ESP8266 +#ifdef ESP32 + // uint8_t config_version; // F36 + valid_settings = (1 == settings_buffer[0xF36]); // Settings.config_version +#endif // ESP32 + } + + if (valid_settings) { + SettingsDefaultSet2(); + memcpy((char*)&Settings +16, settings_buffer +16, config_len -16); + Settings.version = buffer_version; // Restore version and auto upgrade after restart + } + + SettingsBufferFree(); + + return valid_settings; +} + /*********************************************************************************************\ * Config Settings.text char array support \*********************************************************************************************/ diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index 2d322cff8..a7c55bab3 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -1179,7 +1179,6 @@ void Every250mSeconds(void) TasmotaGlobal.ota_state_flag = 0; Response_P(PSTR("{\"" D_CMND_UPGRADE "\":\"")); if (ota_result) { -// SetFlashModeDout(); // Force DOUT for both ESP8266 and ESP8285 ResponseAppend_P(PSTR(D_JSON_SUCCESSFUL ". " D_JSON_RESTARTING)); TasmotaGlobal.restart_flag = 2; } else { diff --git a/tasmota/xdrv_01_webserver.ino b/tasmota/xdrv_01_webserver.ino index 066ba4773..3daa78ed5 100644 --- a/tasmota/xdrv_01_webserver.ino +++ b/tasmota/xdrv_01_webserver.ino @@ -400,8 +400,6 @@ struct WEB { uint8_t state = HTTP_OFF; uint8_t upload_file_type; uint8_t config_block_count = 0; - uint8_t config_xor_on = 0; - uint8_t config_xor_on_set = CONFIG_FILE_XOR; bool upload_services_stopped = false; bool reset_web_log_flag = false; // Reset web console log bool initial_config = false; @@ -2182,38 +2180,20 @@ void HandleBackupConfiguration(void) AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_BACKUP_CONFIGURATION)); - if (!SettingsBufferAlloc()) { return; } + uint32_t config_len = SettingsConfigBackup(); + if (!config_len) { return; } WiFiClient myClient = Webserver->client(); - Webserver->setContentLength(sizeof(Settings)); + Webserver->setContentLength(config_len); char attachment[TOPSZ]; - -// char friendlyname[TOPSZ]; -// snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=Config_%s_%s.dmp"), NoAlNumToUnderscore(friendlyname, SettingsText(SET_FRIENDLYNAME1)), TasmotaGlobal.version); - - char hostname[sizeof(TasmotaGlobal.hostname)]; - snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=Config_%s_%s.dmp"), NoAlNumToUnderscore(hostname, TasmotaGlobal.hostname), TasmotaGlobal.version); - + snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=%s"), SettingsConfigFilename().c_str()); Webserver->sendHeader(F("Content-Disposition"), attachment); WSSend(200, CT_APP_STREAM, ""); - - uint32_t cfg_crc32 = Settings.cfg_crc32; - Settings.cfg_crc32 = GetSettingsCrc32(); // Calculate crc (again) as it might be wrong when savedata = 0 (#3918) - - memcpy(settings_buffer, &Settings, sizeof(Settings)); - if (Web.config_xor_on_set) { - for (uint32_t i = 2; i < sizeof(Settings); i++) { - settings_buffer[i] ^= (Web.config_xor_on_set +i); - } - } - - myClient.write((const char*)settings_buffer, sizeof(Settings)); + myClient.write((const char*)settings_buffer, config_len); SettingsBufferFree(); - - Settings.cfg_crc32 = cfg_crc32; // Restore crc in case savedata = 0 to make sure settings will be noted as changed } /*-------------------------------------------------------------------------------------------*/ @@ -2745,41 +2725,7 @@ void HandleUploadLoop(void) { else if (UPLOAD_FILE_END == upload.status) { UploadServices(1); if (UPL_SETTINGS == Web.upload_file_type) { - if (Web.config_xor_on_set) { - for (uint32_t i = 2; i < sizeof(Settings); i++) { - settings_buffer[i] ^= (Web.config_xor_on_set +i); - } - } - bool valid_settings = false; - unsigned long buffer_version = settings_buffer[11] << 24 | settings_buffer[10] << 16 | settings_buffer[9] << 8 | settings_buffer[8]; - if (buffer_version > 0x06000000) { - uint32_t buffer_size = settings_buffer[3] << 8 | settings_buffer[2]; - if (buffer_version > 0x0606000A) { - uint32_t buffer_crc32 = settings_buffer[4095] << 24 | settings_buffer[4094] << 16 | settings_buffer[4093] << 8 | settings_buffer[4092]; - valid_settings = (GetCfgCrc32(settings_buffer, buffer_size -4) == buffer_crc32); - } else { - uint16_t buffer_crc16 = settings_buffer[15] << 8 | settings_buffer[14]; - valid_settings = (GetCfgCrc16(settings_buffer, buffer_size) == buffer_crc16); - } - } else { - valid_settings = (settings_buffer[0] == CONFIG_FILE_SIGN); - } - - if (valid_settings) { -#ifdef ESP8266 - valid_settings = (0 == settings_buffer[0xF36]); // Settings.config_version -#endif // ESP8266 -#ifdef ESP32 - valid_settings = (1 == settings_buffer[0xF36]); // Settings.config_version -#endif // ESP32 - } - - if (valid_settings) { - SettingsDefaultSet2(); - memcpy((char*)&Settings +16, settings_buffer +16, sizeof(Settings) -16); - Settings.version = buffer_version; // Restore version and auto upgrade after restart - SettingsBufferFree(); - } else { + if (!SettingsConfigRestore()) { Web.upload_error = 8; // File invalid return; }