mirror of https://github.com/arendst/Tasmota.git
Prep for MQTT Settings save
This commit is contained in:
parent
c8de5437a3
commit
cdcb1533b9
|
@ -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
|
||||||
\*********************************************************************************************/
|
\*********************************************************************************************/
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue