Skip to content

Commit 43bc810

Browse files
committed
Configuration file save and restore .xdrvsetXXX
Configuration file save and restore now backup and restore ``.xdrvsetXXX`` files too (#18295)
1 parent b1cc87d commit 43bc810

File tree

5 files changed

+135
-41
lines changed

5 files changed

+135
-41
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ All notable changes to this project will be documented in this file.
1212

1313
### Changed
1414
- ESP32 shutter driver support up to 16 shutters (#18295)
15+
- Configuration file save and restore now backup and restore ``.xdrvsetXXX`` files too (#18295)
1516

1617
### Fixed
1718

RELEASENOTES.md

+1
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
127127

128128
### Changed
129129
- ESP32 LVGL library from v8.3.7 to v8.3.8 (no functional change)
130+
- Configuration file save and restore now backup and restore ``.xdrvsetXXX`` files too [#18295](https://github.com/arendst/Tasmota/issues/18295)
130131
- ESP32 shutter driver support up to 16 shutters [#18295](https://github.com/arendst/Tasmota/issues/18295)
131132
- Matter support for temperature in Fahrenheit (`SetOption8 1`) [#18987](https://github.com/arendst/Tasmota/issues/18987)
132133
- Matter improve responsiveness [#19002](https://github.com/arendst/Tasmota/issues/19002)

tasmota/tasmota_support/settings.ino

+110-26
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ const uint8_t CFG_ROTATES = 7; // Number of flash sectors used (handles upl
217217

218218
uint32_t settings_location = EEPROM_LOCATION;
219219
uint32_t settings_crc32 = 0;
220+
uint32_t settings_size = 0;
220221
uint8_t *settings_buffer = nullptr;
221222
uint8_t config_xor_on_set = CONFIG_FILE_XOR;
222223

@@ -375,56 +376,124 @@ void SettingsSaveAll(void) {
375376
* Settings backup and restore
376377
\*********************************************************************************************/
377378

379+
String SettingsConfigFilename(void) {
380+
char filename[TOPSZ];
381+
char hostname[sizeof(TasmotaGlobal.hostname)];
382+
snprintf_P(filename, sizeof(filename), PSTR("Config_%s_%s.dmp"), NoAlNumToUnderscore(hostname, TasmotaGlobal.hostname), TasmotaGlobal.version);
383+
return String(filename);
384+
}
385+
386+
void SettingsBufferXor(void) {
387+
if (config_xor_on_set) {
388+
uint32_t xor_index = (settings_size > sizeof(TSettings)) ? 18 : 2;
389+
for (uint32_t i = xor_index; i < settings_size; i++) {
390+
settings_buffer[i] ^= (config_xor_on_set +i);
391+
}
392+
}
393+
}
394+
378395
void SettingsBufferFree(void) {
379396
if (settings_buffer != nullptr) {
380397
free(settings_buffer);
381398
settings_buffer = nullptr;
382399
}
400+
settings_size = 0;
383401
}
384402

385-
bool SettingsBufferAlloc(void) {
403+
bool SettingsBufferAlloc(uint32_t upload_size = 0);
404+
bool SettingsBufferAlloc(uint32_t upload_size) {
386405
SettingsBufferFree();
387-
if (!(settings_buffer = (uint8_t *)malloc(sizeof(TSettings)))) {
406+
407+
settings_size = sizeof(TSettings);
408+
if (upload_size >= sizeof(TSettings)) {
409+
uint32_t mem = ESP_getFreeHeap();
410+
if ((mem - upload_size) < (8 * 1024)) {
411+
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_UPLOAD_ERR_2)); // Not enough (memory) space
412+
return false;
413+
}
414+
settings_size = upload_size;
415+
} else {
416+
417+
#ifdef USE_UFILESYS
418+
char filename[14];
419+
for (uint32_t i = 0; i < 129; i++) {
420+
snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_DRIVER), i);
421+
uint32_t fsize = TfsFileSize(filename);
422+
if (fsize) {
423+
if (settings_size == sizeof(TSettings)) {
424+
settings_size += 16; // Add tar header for total file size
425+
}
426+
fsize = ((fsize / 16) * 16) + 16; // Use 16-byte boundary
427+
settings_size += (16 + fsize); // Tar header size is 16 bytes
428+
}
429+
}
430+
#endif // USE_UFILESYS
431+
432+
}
433+
434+
if (!(settings_buffer = (uint8_t *)calloc(settings_size, 1))) {
388435
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_UPLOAD_ERR_2)); // Not enough (memory) space
389436
return false;
390437
}
391438
return true;
392439
}
393440

394-
String SettingsConfigFilename(void) {
395-
char filename[TOPSZ];
396-
char hostname[sizeof(TasmotaGlobal.hostname)];
397-
snprintf_P(filename, sizeof(filename), PSTR("Config_%s_%s.dmp"), NoAlNumToUnderscore(hostname, TasmotaGlobal.hostname), TasmotaGlobal.version);
398-
return String(filename);
399-
}
400-
401441
uint32_t SettingsConfigBackup(void) {
402442
if (!SettingsBufferAlloc()) { return 0; }
403443

404-
uint32_t cfg_crc32 = Settings->cfg_crc32;
405-
Settings->cfg_crc32 = GetSettingsCrc32(); // Calculate crc (again) as it might be wrong when savedata = 0 (#3918)
444+
uint8_t *filebuf_ptr = settings_buffer;
406445

407-
uint32_t config_len = sizeof(TSettings);
408-
memcpy(settings_buffer, Settings, config_len);
446+
#ifdef USE_UFILESYS
447+
if (settings_size > sizeof(TSettings)) {
448+
snprintf_P((char*)filebuf_ptr, 14, PSTR(TASM_FILE_SETTINGS)); // /.settings
449+
filebuf_ptr += 14;
450+
*filebuf_ptr = settings_size;
451+
filebuf_ptr++;
452+
*filebuf_ptr = (settings_size >> 8);
453+
filebuf_ptr++;
454+
}
455+
#endif // USE_UFILESYS
409456

457+
uint32_t cfg_crc32 = Settings->cfg_crc32;
458+
Settings->cfg_crc32 = GetSettingsCrc32(); // Calculate crc (again) as it might be wrong when savedata = 0 (#3918)
459+
memcpy(filebuf_ptr, Settings, sizeof(TSettings));
410460
Settings->cfg_crc32 = cfg_crc32; // Restore crc in case savedata = 0 to make sure settings will be noted as changed
411461

412-
if (config_xor_on_set) {
413-
for (uint32_t i = 2; i < config_len; i++) {
414-
settings_buffer[i] ^= (config_xor_on_set +i);
462+
#ifdef USE_UFILESYS
463+
if (settings_size > sizeof(TSettings)) {
464+
filebuf_ptr += sizeof(TSettings);
465+
char filename[14];
466+
for (uint32_t i = 0; i < 129; i++) {
467+
snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_DRIVER), i); // /.drvset012
468+
uint32_t fsize = TfsFileSize(filename);
469+
if (fsize) {
470+
memcpy(filebuf_ptr, filename, 14);
471+
filebuf_ptr += 14;
472+
*filebuf_ptr = fsize;
473+
filebuf_ptr++;
474+
*filebuf_ptr = (fsize >> 8);
475+
filebuf_ptr++;
476+
AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: Backup file %s (%d)"), (char*)filebuf_ptr -16, fsize);
477+
TfsLoadFile((const char*)filebuf_ptr -16, (uint8_t*)filebuf_ptr, fsize);
478+
filebuf_ptr += ((fsize / 16) * 16) + 16;
479+
}
415480
}
416481
}
417-
return config_len;
482+
#endif // USE_UFILESYS
483+
484+
SettingsBufferXor();
485+
return settings_size;
418486
}
419487

420488
bool SettingsConfigRestore(void) {
421-
uint32_t config_len = sizeof(TSettings);
489+
SettingsBufferXor();
422490

423-
if (config_xor_on_set) {
424-
for (uint32_t i = 2; i < config_len; i++) {
425-
settings_buffer[i] ^= (config_xor_on_set +i);
426-
}
491+
#ifdef USE_UFILESYS
492+
if (settings_size > sizeof(TSettings)) {
493+
settings_size -= 16;
494+
memmove(settings_buffer, settings_buffer +16, settings_size); // Skip tar header
427495
}
496+
#endif // USE_UFILESYS
428497

429498
bool valid_settings = false;
430499

@@ -434,11 +503,11 @@ bool SettingsConfigRestore(void) {
434503
// uint16_t cfg_size; // 002
435504
uint32_t buffer_size = settings_buffer[3] << 8 | settings_buffer[2];
436505
if (buffer_version > 0x0606000A) {
437-
// uint32_t cfg_crc32; // FFC
506+
// uint32_t cfg_crc32; // FFC
438507
uint32_t buffer_crc32 = settings_buffer[4095] << 24 | settings_buffer[4094] << 16 | settings_buffer[4093] << 8 | settings_buffer[4092];
439508
valid_settings = (GetCfgCrc32(settings_buffer, buffer_size -4) == buffer_crc32);
440509
} else {
441-
// uint16_t cfg_crc; // 00E
510+
// uint16_t cfg_crc; // 00E
442511
uint16_t buffer_crc16 = settings_buffer[15] << 8 | settings_buffer[14];
443512
valid_settings = (GetCfgCrc16(settings_buffer, buffer_size) == buffer_crc16);
444513
}
@@ -467,12 +536,27 @@ bool SettingsConfigRestore(void) {
467536

468537
if (valid_settings) {
469538
SettingsDefaultSet2();
470-
memcpy((char*)Settings +16, settings_buffer +16, config_len -16);
539+
memcpy((char*)Settings +16, settings_buffer +16, sizeof(TSettings) -16);
471540
Settings->version = buffer_version; // Restore version and auto upgrade after restart
472541
}
473542

474-
SettingsBufferFree();
543+
#ifdef USE_UFILESYS
544+
if (settings_size > sizeof(TSettings)) {
545+
uint8_t *filebuf_ptr = settings_buffer + sizeof(TSettings);
546+
while ((filebuf_ptr - settings_buffer) < settings_size) {
547+
filebuf_ptr += 14;
548+
uint32_t fsize = *filebuf_ptr;
549+
filebuf_ptr++;
550+
fsize += *filebuf_ptr << 8;
551+
filebuf_ptr++;
552+
AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: Restore file %s (%d)"), (char*)filebuf_ptr -16, fsize);
553+
TfsSaveFile((const char*)filebuf_ptr -16, (uint8_t*)filebuf_ptr, fsize);
554+
filebuf_ptr += ((fsize / 16) * 16) + 16;
555+
}
556+
}
557+
#endif // USE_UFILESYS
475558

559+
SettingsBufferFree();
476560
return valid_settings;
477561
}
478562

tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino

+16-11
Original file line numberDiff line numberDiff line change
@@ -2236,7 +2236,7 @@ void HandleBackupConfiguration(void)
22362236
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_BACKUP_CONFIGURATION));
22372237

22382238
uint32_t config_len = SettingsConfigBackup();
2239-
if (!config_len) { return; }
2239+
if (!config_len) { return; } // Unable to allocate 4k buffer
22402240

22412241
WiFiClient myClient = Webserver->client();
22422242
Webserver->setContentLength(config_len);
@@ -2731,14 +2731,8 @@ void HandleUploadLoop(void) {
27312731

27322732
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_UPLOAD D_FILE " %s"), upload.filename.c_str());
27332733

2734-
if (UPL_SETTINGS == Web.upload_file_type) {
2735-
if (!SettingsBufferAlloc()) {
2736-
Web.upload_error = 2; // Not enough space
2737-
return;
2738-
}
2739-
}
27402734
#ifdef USE_UFILESYS
2741-
else if (UPL_UFSFILE == Web.upload_file_type) {
2735+
if (UPL_UFSFILE == Web.upload_file_type) {
27422736
if (!UfsUploadFileOpen(upload.filename.c_str())) {
27432737
Web.upload_error = 2;
27442738
return;
@@ -2751,6 +2745,16 @@ void HandleUploadLoop(void) {
27512745
else if (UPLOAD_FILE_WRITE == upload.status) {
27522746
if (0 == upload.totalSize) { // First block received
27532747
if (UPL_SETTINGS == Web.upload_file_type) {
2748+
uint32_t set_size = sizeof(TSettings);
2749+
#ifdef USE_UFILESYS
2750+
if (('s' == upload.buf[2]) && ('e' == upload.buf[3])) { // /.settings
2751+
set_size = upload.buf[14] + (upload.buf[15] << 8);
2752+
}
2753+
#endif // USE_UFILESYS
2754+
if (!SettingsBufferAlloc(set_size)) {
2755+
Web.upload_error = 2; // Not enough space
2756+
return;
2757+
}
27542758
Web.config_block_count = 0;
27552759
}
27562760
#ifdef USE_WEB_FW_UPGRADE
@@ -2820,7 +2824,7 @@ void HandleUploadLoop(void) {
28202824
} // First block received
28212825

28222826
if (UPL_SETTINGS == Web.upload_file_type) {
2823-
if (upload.currentSize > (sizeof(TSettings) - (Web.config_block_count * HTTP_UPLOAD_BUFLEN))) {
2827+
if (upload.currentSize > (settings_size - (Web.config_block_count * HTTP_UPLOAD_BUFLEN))) {
28242828
Web.upload_error = 9; // File too large
28252829
return;
28262830
}
@@ -3368,9 +3372,10 @@ int WebGetConfig(char *buffer) {
33683372
if (http_code == HTTP_CODE_OK || http_code == HTTP_CODE_MOVED_PERMANENTLY) {
33693373
WiFiClient *stream = http.getStreamPtr();
33703374
int len = http.getSize();
3371-
if ((len <= sizeof(TSettings)) && SettingsBufferAlloc()) {
3375+
// if ((len <= sizeof(TSettings)) && SettingsBufferAlloc()) {
3376+
if (SettingsBufferAlloc(len)) {
33723377
uint8_t *buff = settings_buffer;
3373-
if (len == -1) { len = sizeof(TSettings); }
3378+
if (len == -1) { len = settings_size; }
33743379
while (http.connected() && (len > 0)) {
33753380
size_t size = stream->available();
33763381
if (size) {

tasmota/tasmota_xdrv_driver/xdrv_02_1_mqtt_file.ino

+7-4
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,9 @@ uint32_t MqttFileUploadValidate(uint32_t rcv_id) {
9696

9797
// Check buffer size
9898
if (UPL_SETTINGS == FMqtt.file_type) {
99-
if (FMqtt.file_size > sizeof(TSettings)) {
100-
return 2; // Settings supports max 4k size
101-
}
99+
// if (FMqtt.file_size > sizeof(TSettings)) {
100+
// return 2; // Settings supports max 4k size
101+
// }
102102
} else { // Check enough flash space for intermediate upload
103103
uint32_t head_room = (FlashWriteMaxSector() - FlashWriteStartSector()) * SPI_FLASH_SEC_SIZE;
104104
uint32_t rounded_size = (FMqtt.file_size + SPI_FLASH_SEC_SIZE -1) & (~(SPI_FLASH_SEC_SIZE - 1));
@@ -109,8 +109,11 @@ uint32_t MqttFileUploadValidate(uint32_t rcv_id) {
109109

110110
// Init file_buffer
111111
if (UPL_SETTINGS == FMqtt.file_type) {
112-
if (SettingsConfigBackup()) {
112+
// if (SettingsConfigBackup()) {
113+
if (SettingsBufferAlloc(FMqtt.file_size)) {
113114
FMqtt.file_buffer = settings_buffer;
115+
} else {
116+
return 2; // Settings supports max size
114117
}
115118
}
116119
else {

0 commit comments

Comments
 (0)