Prep for MQTT Settings save

This commit is contained in:
Theo Arends 2021-05-06 15:23:41 +02:00
parent c8de5437a3
commit cdcb1533b9
3 changed files with 151 additions and 146 deletions

View File

@ -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_location = EEPROM_LOCATION;
uint32_t settings_crc32 = 0; uint32_t settings_crc32 = 0;
uint8_t *settings_buffer = nullptr; uint8_t *settings_buffer = nullptr;
uint8_t config_xor_on_set = CONFIG_FILE_XOR;
void SettingsInit(void) { void SettingsInit(void) {
if (SETTINGS_LOCATION > 0xFA) { 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 * Quick power cycle monitoring
\*********************************************************************************************/ \*********************************************************************************************/
@ -360,6 +276,150 @@ void UpdateQuickPowerCycle(bool update) {
#endif // FIRMWARE_MINIMAL #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 * Config Settings.text char array support
\*********************************************************************************************/ \*********************************************************************************************/

View File

@ -1179,7 +1179,6 @@ void Every250mSeconds(void)
TasmotaGlobal.ota_state_flag = 0; TasmotaGlobal.ota_state_flag = 0;
Response_P(PSTR("{\"" D_CMND_UPGRADE "\":\"")); Response_P(PSTR("{\"" D_CMND_UPGRADE "\":\""));
if (ota_result) { if (ota_result) {
// SetFlashModeDout(); // Force DOUT for both ESP8266 and ESP8285
ResponseAppend_P(PSTR(D_JSON_SUCCESSFUL ". " D_JSON_RESTARTING)); ResponseAppend_P(PSTR(D_JSON_SUCCESSFUL ". " D_JSON_RESTARTING));
TasmotaGlobal.restart_flag = 2; TasmotaGlobal.restart_flag = 2;
} else { } else {

View File

@ -400,8 +400,6 @@ struct WEB {
uint8_t state = HTTP_OFF; uint8_t state = HTTP_OFF;
uint8_t upload_file_type; uint8_t upload_file_type;
uint8_t config_block_count = 0; 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 upload_services_stopped = false;
bool reset_web_log_flag = false; // Reset web console log bool reset_web_log_flag = false; // Reset web console log
bool initial_config = false; bool initial_config = false;
@ -2182,38 +2180,20 @@ void HandleBackupConfiguration(void)
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_BACKUP_CONFIGURATION)); 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(); WiFiClient myClient = Webserver->client();
Webserver->setContentLength(sizeof(Settings)); Webserver->setContentLength(config_len);
char attachment[TOPSZ]; char attachment[TOPSZ];
snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=%s"), SettingsConfigFilename().c_str());
// 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);
Webserver->sendHeader(F("Content-Disposition"), attachment); Webserver->sendHeader(F("Content-Disposition"), attachment);
WSSend(200, CT_APP_STREAM, ""); WSSend(200, CT_APP_STREAM, "");
myClient.write((const char*)settings_buffer, config_len);
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));
SettingsBufferFree(); 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) { else if (UPLOAD_FILE_END == upload.status) {
UploadServices(1); UploadServices(1);
if (UPL_SETTINGS == Web.upload_file_type) { if (UPL_SETTINGS == Web.upload_file_type) {
if (Web.config_xor_on_set) { if (!SettingsConfigRestore()) {
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 {
Web.upload_error = 8; // File invalid Web.upload_error = 8; // File invalid
return; return;
} }