From d26d1e1adc8c195cd9a78b9d14d3fa83a15a59e5 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Tue, 15 Aug 2023 20:10:02 +0200 Subject: [PATCH 1/7] [Core] Add extra storage space for Custom TaskSettings --- src/src/CustomBuild/StorageLayout.h | 61 +++++++---- src/src/CustomBuild/define_plugin_sets.h | 9 ++ src/src/DataTypes/ESPEasyFileType.cpp | 29 +++++- src/src/DataTypes/SettingsType.cpp | 10 +- src/src/DataTypes/SettingsType.h | 2 +- src/src/Helpers/ESPEasy_Storage.cpp | 123 +++++++++++++++++++++-- src/src/Helpers/ESPEasy_Storage.h | 9 ++ 7 files changed, 210 insertions(+), 33 deletions(-) diff --git a/src/src/CustomBuild/StorageLayout.h b/src/src/CustomBuild/StorageLayout.h index 4e1d4d90ef..072aebecb9 100644 --- a/src/src/CustomBuild/StorageLayout.h +++ b/src/src/CustomBuild/StorageLayout.h @@ -17,15 +17,15 @@ /* - The settings files have some reserved space for each struct stored in there. + The settings files have some reserved space for each struct stored in there. CONFIG_FILE_SIZE File size of config.dat - Settings struct is positioned at the start of the settings file Config.dat - + Settings struct is positioned at the start of the settings file Config.dat + DAT_BASIC_SETTINGS_SIZE Reserved size for Settings struct - Parameters used for locating the task data: + Parameters used for locating the task data: DAT_OFFSET_TASKS Position of first TaskSettings in the Settings file DAT_TASKS_SIZE Reserved size for TaskSettings @@ -36,8 +36,8 @@ DAT_TASKS_DISTANCE = DAT_TASKS_SIZE + DAT_TASKS_CUSTOM_SIZE - Parameters used for locating the controller data: - + Parameters used for locating the controller data: + DAT_OFFSET_CONTROLLER Position of first ControllerSettings in the Settings file DAT_CONTROLLER_SIZE Reserved size for ControllerSettings @@ -47,12 +47,12 @@ ControllerSettings and CustomControllerSettings are not located interleaved in the settings file. So there is no distance value for controller settings. (equal to the controller size) - Notification settings are located in a different file. + Notification settings are located in a different file. - DAT_NOTIFICATION_SIZE Reserved size for NotificationSettings + DAT_NOTIFICATION_SIZE Reserved size for NotificationSettings -*/ + */ #ifndef DAT_BASIC_SETTINGS_SIZE # define DAT_BASIC_SETTINGS_SIZE 4096 @@ -68,6 +68,25 @@ #ifndef DAT_TASKS_CUSTOM_SIZE # define DAT_TASKS_CUSTOM_SIZE 1024 #endif // ifndef DAT_TASKS_CUSTOM_SIZE +// FEATURE_EXTENDED_CUSTOM_SETTINGS: Default will be determined in define_plugin_sets.h, based on used plugins +#ifndef FEATURE_EXTENDED_CUSTOM_SETTINGS +# ifdef BUILD_MINIMAL_OTA +# define FEATURE_EXTENDED_CUSTOM_SETTINGS 0 // Never on minimal builds? +# else // ifdef BUILD_MINIMAL_OTA +# define FEATURE_EXTENDED_CUSTOM_SETTINGS 1 +# endif // ifdef BUILD_MINIMAL_OTA +#endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS +#ifndef DAT_TASKS_CUSTOM_EXTENSION_SIZE +# if FEATURE_EXTENDED_CUSTOM_SETTINGS +# define DAT_TASKS_CUSTOM_EXTENSION_SIZE 4096 // 4kB extension with external file extcfg.dat +# else // if FEATURE_EXTENDED_CUSTOM_SETTINGS +# define DAT_TASKS_CUSTOM_EXTENSION_SIZE 0 // No extension, but defined to avoid #if checks all over the code +# endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS +#endif // ifndef DAT_TASKS_CUSTOM_EXTENSION_SIZE +// Filename _must_ include the task number (1-based, as shown in the UI) and the % is also used elsewhere, so keep the %02d ! +#ifndef DAT_TASKS_CUSTOM_EXTENSION_FILEMASK +# define DAT_TASKS_CUSTOM_EXTENSION_FILEMASK "extcfg%02d.dat" +#endif // ifndef DAT_TASKS_CUSTOM_EXTENSION_FILEMASK #ifndef DAT_TASKS_DISTANCE # define DAT_TASKS_DISTANCE 2048 // DAT_TASKS_SIZE + DAT_TASKS_CUSTOM_SIZE #endif // ifndef DAT_TASKS_DISTANCE @@ -103,7 +122,8 @@ #define TASKS_MAX 24 #define DAT_OFFSET_CONTROLLER (DAT_OFFSET_TASKS + (DAT_TASKS_DISTANCE * TASKS_MAX)) // each controller = 1k, 4 max - #define DAT_OFFSET_CUSTOM_CONTROLLER (DAT_OFFSET_CONTROLLER + (DAT_CUSTOM_CONTROLLER_SIZE * CONTROLLER_MAX)) // each custom controller config = + #define DAT_OFFSET_CUSTOM_CONTROLLER (DAT_OFFSET_CONTROLLER + (DAT_CUSTOM_CONTROLLER_SIZE * CONTROLLER_MAX)) // each custom controller + config = 1k, 4 max @@ -120,13 +140,17 @@ #if defined(ESP8266) # if FEATURE_NON_STANDARD_24_TASKS # ifndef DAT_OFFSET_TASKS - # define DAT_OFFSET_TASKS 4096 // 0x1000 each task = 2k, (1024 basic + 1024 bytes custom) + # define DAT_OFFSET_TASKS 4096 // 0x1000 each task = 2k, + // (1024 basic + 1024 bytes + // custom) # endif // ifndef DAT_OFFSET_TASKS # ifndef DAT_OFFSET_CONTROLLER - # define DAT_OFFSET_CONTROLLER (DAT_OFFSET_TASKS + (DAT_TASKS_DISTANCE * TASKS_MAX)) // each controller = 1k, 4 max + # define DAT_OFFSET_CONTROLLER (DAT_OFFSET_TASKS + (DAT_TASKS_DISTANCE * TASKS_MAX)) // each controller = 1k, 4 + // max # endif // ifndef DAT_OFFSET_CONTROLLER # ifndef DAT_OFFSET_CUSTOM_CONTROLLER - # define DAT_OFFSET_CUSTOM_CONTROLLER (DAT_OFFSET_CONTROLLER + (DAT_CONTROLLER_SIZE * CONTROLLER_MAX)) // each custom controller config = 1k, 4 max + # define DAT_OFFSET_CUSTOM_CONTROLLER (DAT_OFFSET_CONTROLLER + (DAT_CONTROLLER_SIZE * CONTROLLER_MAX)) // each custom controller + // config = 1k, 4 max # endif // ifndef DAT_OFFSET_CUSTOM_CONTROLLER # ifndef CONFIG_FILE_SIZE # define CONFIG_FILE_SIZE 65536 @@ -144,24 +168,25 @@ # define DAT_OFFSET_CUSTOM_CONTROLLER 32768 // each custom controller config = 1k, 4 max. # endif // ifndef DAT_OFFSET_CUSTOM_CONTROLLER # ifdef LIMIT_BUILD_SIZE - // Limit the config size for 1M builds, since their file system is also quite small + +// Limit the config size for 1M builds, since their file system is also quite small # ifndef CONFIG_FILE_SIZE # define CONFIG_FILE_SIZE 36864 // DAT_OFFSET_CUSTOM_CONTROLLER + 4x DAT_CUSTOM_CONTROLLER_SIZE # endif // ifndef CONFIG_FILE_SIZE - # else + # else // ifdef LIMIT_BUILD_SIZE # ifndef CONFIG_FILE_SIZE # define CONFIG_FILE_SIZE 65536 # endif // ifndef CONFIG_FILE_SIZE - # endif + # endif // ifdef LIMIT_BUILD_SIZE # endif // if FEATURE_NON_STANDARD_24_TASKS #endif // if defined(ESP8266) #if defined(ESP32) # ifndef DAT_OFFSET_TASKS - # define DAT_OFFSET_TASKS 32768 // each task = 2k, (1024 basic + 1024 bytes custom), 32 max + # define DAT_OFFSET_TASKS 32768 // each task = 2k, (1024 basic + 1024 bytes custom), 32 max # endif // ifndef DAT_OFFSET_TASKS # ifndef DAT_OFFSET_CONTROLLER - # define DAT_OFFSET_CONTROLLER 8192 // each controller = 1k, 4 max + # define DAT_OFFSET_CONTROLLER 8192 // each controller = 1k, 4 max # endif // ifndef DAT_OFFSET_CONTROLLER # ifndef DAT_OFFSET_CUSTOM_CONTROLLER # define DAT_OFFSET_CUSTOM_CONTROLLER 12288 // each custom controller config = 1k, 4 max. diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 4f4121410f..84b66302c8 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -3061,4 +3061,13 @@ To create/register a plugin, you have to : #endif #endif +// Check for plugins that will use Extended Custom Settings storage when available +#ifndef FEATURE_EXTENDED_CUSTOM_SETTINGS + #if defined(USES_P094) || defined(USES_P095) || defined(USES_P096) || defined(USES_P099) || defined(USES_P104) || defined(USES_P116) || defined(USES_P123) || defined(USES_P131) + #define FEATURE_EXTENDED_CUSTOM_SETTINGS 1 + #else + #define FEATURE_EXTENDED_CUSTOM_SETTINGS 0 + #endif +#endif // ifndef FEATURE_EXTENDED_CUSTOM_SETTINGS + #endif // CUSTOMBUILD_DEFINE_PLUGIN_SETS_H diff --git a/src/src/DataTypes/ESPEasyFileType.cpp b/src/src/DataTypes/ESPEasyFileType.cpp index afb7268c21..077b34937e 100644 --- a/src/src/DataTypes/ESPEasyFileType.cpp +++ b/src/src/DataTypes/ESPEasyFileType.cpp @@ -2,8 +2,12 @@ #include "../../ESPEasy_common.h" +#include "../CustomBuild/StorageLayout.h" + #include "../Globals/ResetFactoryDefaultPref.h" +#include "../Helpers/StringConverter.h" + bool matchFileType(const String& filename, FileType::Enum filetype) { if (filename.startsWith(F("/"))) { @@ -14,10 +18,27 @@ bool matchFileType(const String& filename, FileType::Enum filetype) bool isProtectedFileType(const String& filename) { - return matchFileType(filename, FileType::CONFIG_DAT) || - matchFileType(filename, FileType::SECURITY_DAT) || - matchFileType(filename, FileType::NOTIFICATION_DAT) || - matchFileType(filename, FileType::PROVISIONING_DAT); + #if FEATURE_EXTENDED_CUSTOM_SETTINGS + bool isTaskSpecificConfig = false; + const String fname = filename.substring(filename.startsWith(F("/")) ? 1 : 0); + const String mask = F(DAT_TASKS_CUSTOM_EXTENSION_FILEMASK); + const uint8_t mPerc = mask.indexOf('%'); + + if (fname.startsWith(mask.substring(0, mPerc))) { + for (uint8_t n = 1; n <= TASKS_MAX && !isTaskSpecificConfig; n++) { + isTaskSpecificConfig |= (fname.equalsIgnoreCase(strformat(mask, n))); + } + } + #endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS + + return + #if FEATURE_EXTENDED_CUSTOM_SETTINGS + isTaskSpecificConfig || // Support for extcfgNN.dat + #endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS + matchFileType(filename, FileType::CONFIG_DAT) || + matchFileType(filename, FileType::SECURITY_DAT) || + matchFileType(filename, FileType::NOTIFICATION_DAT) || + matchFileType(filename, FileType::PROVISIONING_DAT); } const __FlashStringHelper* getFileName(FileType::Enum filetype) { diff --git a/src/src/DataTypes/SettingsType.cpp b/src/src/DataTypes/SettingsType.cpp index f2985f4a94..e8deed9d41 100644 --- a/src/src/DataTypes/SettingsType.cpp +++ b/src/src/DataTypes/SettingsType.cpp @@ -7,6 +7,7 @@ #include "../DataStructs/SecurityStruct.h" #include "../DataTypes/ESPEasyFileType.h" #include "../Globals/Settings.h" +#include "../Helpers/StringConverter.h" const __FlashStringHelper * SettingsType::getSettingsTypeString(Enum settingsType) { switch (settingsType) { @@ -57,7 +58,7 @@ bool SettingsType::getSettingsParameters(Enum settingsType, int index, int& max_ { getSettingsParameters(Enum::TaskSettings_Type, index, max_index, offset, max_size, struct_size); offset += (DAT_TASKS_CUSTOM_OFFSET); - max_size = DAT_TASKS_CUSTOM_SIZE; + max_size = (DAT_TASKS_CUSTOM_SIZE + DAT_TASKS_CUSTOM_EXTENSION_SIZE); // struct_size may differ. struct_size = 0; @@ -206,7 +207,12 @@ SettingsType::SettingsFileEnum SettingsType::getSettingsFile(Enum settingsType) return SettingsFileEnum::FILE_UNKNOWN_type; } -String SettingsType::getSettingsFileName(Enum settingsType) { +String SettingsType::getSettingsFileName(Enum settingsType, int index) { + #if FEATURE_EXTENDED_CUSTOM_SETTINGS + if ((Enum::CustomTaskSettings_Type == settingsType) && (INVALID_TASK_INDEX != index)) { + return strformat(F(DAT_TASKS_CUSTOM_EXTENSION_FILEMASK), index + 1); // Add 0/1 offset to match displayed task ID + } + #endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS return getSettingsFileName(getSettingsFile(settingsType)); } diff --git a/src/src/DataTypes/SettingsType.h b/src/src/DataTypes/SettingsType.h index a9f2477ee3..2ebec32845 100644 --- a/src/src/DataTypes/SettingsType.h +++ b/src/src/DataTypes/SettingsType.h @@ -47,7 +47,7 @@ class SettingsType { #endif // ifndef BUILD_MINIMAL_OTA static SettingsFileEnum getSettingsFile(Enum settingsType); - static String getSettingsFileName(Enum settingsType); + static String getSettingsFileName(Enum settingsType, int index = TASKS_MAX); static const __FlashStringHelper * getSettingsFileName(SettingsType::SettingsFileEnum file_type); static size_t getInitFileSize(SettingsType::SettingsFileEnum file_type); }; diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index a3efa8fd21..14c88fabf6 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -1025,6 +1025,13 @@ String SaveStringArray(SettingsType::Enum settingsType, int index, const String writePos += bufpos; } + #if FEATURE_EXTENDED_CUSTOM_SETTINGS + if ((SettingsType::Enum::CustomTaskSettings_Type == settingsType) && + ((writePos - posInBlock) <= DAT_TASKS_CUSTOM_SIZE)) { // Not needed, so can be deleted + DeleteExtendedCustomTaskSettingsFile(settingsType, index); + } + #endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS + if ((writePos >= max_size) && (stringCount < nrStrings)) { result += F("Error: Not all strings fit in custom settings."); } @@ -1678,8 +1685,42 @@ String LoadFromFile(SettingsType::Enum settingsType, int index, uint8_t *memAddr if ((datasize + offset_in_block) > max_size) { return getSettingsFileDatasizeError(read, settingsType, index, datasize, max_size); } - const String fname = SettingsType::getSettingsFileName(settingsType); - return LoadFromFile(fname.c_str(), (offset + offset_in_block), memAddress, datasize); + + int dataOffset = 0; + + #if FEATURE_EXTENDED_CUSTOM_SETTINGS + int taskIndex = INVALID_TASK_INDEX; // Use base filename + + if ((SettingsType::Enum::CustomTaskSettings_Type == settingsType) && + ((offset_in_block + datasize) > DAT_TASKS_CUSTOM_SIZE)) { + if (offset_in_block < DAT_TASKS_CUSTOM_SIZE) { // block starts in regular Custom config: Load first part + const String fname = SettingsType::getSettingsFileName(settingsType); + dataOffset = DAT_TASKS_CUSTOM_SIZE - offset_in_block; + const String res = LoadFromFile(fname.c_str(), offset + offset_in_block, memAddress, dataOffset); + + if (!res.isEmpty()) { return res; } // Error occurred? + + datasize -= dataOffset; + offset_in_block = DAT_TASKS_CUSTOM_SIZE; + } + const String fname = SettingsType::getSettingsFileName(settingsType, index); + + if (fileExists(fname)) { // Do we have a task-specific extension stored? + if (offset_in_block >= DAT_TASKS_CUSTOM_SIZE) { + offset_in_block -= DAT_TASKS_CUSTOM_SIZE; + } + offset = 0; + taskIndex = index; // Use task-specific filename + } + } + #endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS + + const String fname = SettingsType::getSettingsFileName(settingsType + #if FEATURE_EXTENDED_CUSTOM_SETTINGS + , taskIndex + #endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS + ); + return LoadFromFile(fname.c_str(), (offset + offset_in_block), memAddress + dataOffset, datasize); } String SaveToFile(SettingsType::Enum settingsType, int index, const uint8_t *memAddress, int datasize, int posInBlock) { @@ -1693,14 +1734,57 @@ String SaveToFile(SettingsType::Enum settingsType, int index, const uint8_t *mem if ((datasize > max_size) || ((posInBlock + datasize) > max_size)) { return getSettingsFileDatasizeError(read, settingsType, index, datasize, max_size); } - const String fname = SettingsType::getSettingsFileName(settingsType); + + int dataOffset = 0; + + #if FEATURE_EXTENDED_CUSTOM_SETTINGS + int taskIndex = INVALID_TASK_INDEX; // Use base filename + + if ((SettingsType::Enum::CustomTaskSettings_Type == settingsType) && + (posInBlock + datasize > (DAT_TASKS_CUSTOM_SIZE))) { // max_size already handled above + if (posInBlock < DAT_TASKS_CUSTOM_SIZE) { // Partial in regular config.dat, save that part first + const String fname = SettingsType::getSettingsFileName(settingsType); + dataOffset = (DAT_TASKS_CUSTOM_SIZE - posInBlock); // Bytes to keep 'local' + # ifndef BUILD_NO_DEBUG + const String styp = SettingsType::getSettingsTypeString(settingsType); + addLog(LOG_LEVEL_INFO, concat(F("ExtraSaveToFile: "), styp) + concat(F(" file: "), fname) + + strformat(F(" size: %d pos: %d"), dataOffset, posInBlock)); + # endif // ifndef BUILD_NO_DEBUG + const String res = SaveToFile(fname.c_str(), offset + posInBlock, memAddress, dataOffset); + + if (!res.isEmpty()) { return res; } // Error occurred + + datasize -= dataOffset; + posInBlock = 0; + } else { + posInBlock -= DAT_TASKS_CUSTOM_SIZE; + } + offset = 0; // Start of the extension file + taskIndex = index; // Use task-specific filename + } + #endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS + + const String fname = SettingsType::getSettingsFileName(settingsType + #if FEATURE_EXTENDED_CUSTOM_SETTINGS + , taskIndex + #endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS + ); if (!fileExists(fname)) { - InitFile(settingsType); + #if FEATURE_EXTENDED_CUSTOM_SETTINGS + if (INVALID_TASK_INDEX == taskIndex) { + #endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS + InitFile(settingsType); + #if FEATURE_EXTENDED_CUSTOM_SETTINGS + } else { + InitFile(fname, DAT_TASKS_CUSTOM_EXTENSION_SIZE); // Initialize task-specific file + } + #endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS } -#ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_INFO, concat(F("SaveToFile: "), SettingsType::getSettingsTypeString(settingsType)) + concat(F(" index: "), index)); -#endif - return SaveToFile(fname.c_str(), offset + posInBlock, memAddress, datasize); + #ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_INFO, concat(F("SaveToFile: "), SettingsType::getSettingsTypeString(settingsType)) + + strformat(F(" file: %s task: %d"), fname.c_str(), index + 1)); + #endif + return SaveToFile(fname.c_str(), offset + posInBlock, memAddress + dataOffset, datasize); } String ClearInFile(SettingsType::Enum settingsType, int index) { @@ -1710,10 +1794,33 @@ String ClearInFile(SettingsType::Enum settingsType, int index) { if (!getAndLogSettingsParameters(read, settingsType, index, offset, max_size)) { return getSettingsFileIndexRangeError(read, settingsType, index); } + #if FEATURE_EXTENDED_CUSTOM_SETTINGS + if (SettingsType::Enum::CustomTaskSettings_Type == settingsType) { + max_size = DAT_TASKS_CUSTOM_SIZE; // Don't also wipe the external size inside the config.dat file... + DeleteExtendedCustomTaskSettingsFile(settingsType, index); + } + #endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS + const String fname = SettingsType::getSettingsFileName(settingsType); return ClearInFile(fname.c_str(), offset, max_size); } +#if FEATURE_EXTENDED_CUSTOM_SETTINGS +bool DeleteExtendedCustomTaskSettingsFile(SettingsType::Enum settingsType, int index) { + if ((SettingsType::Enum::CustomTaskSettings_Type == settingsType) && (INVALID_TASK_INDEX !=index)) { + const String fname = SettingsType::getSettingsFileName(settingsType, index); + + if (fileExists(fname)) { + const bool deleted = tryDeleteFile(fname); // Don't need the extension file anymore, so delete it + # ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_INFO, concat(F("CustomTaskSettings: Removing no longer needed file: "), fname)); + # endif // ifndef BUILD_NO_DEBUG + return deleted; + } + } + return false; +} +#endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS /********************************************************************************************\ Check file system area settings \*********************************************************************************************/ diff --git a/src/src/Helpers/ESPEasy_Storage.h b/src/src/Helpers/ESPEasy_Storage.h index d32ea7a1e1..bc57c56e7e 100644 --- a/src/src/Helpers/ESPEasy_Storage.h +++ b/src/src/Helpers/ESPEasy_Storage.h @@ -6,6 +6,8 @@ #include "../Helpers/FS_Helper.h" +#include "../CustomBuild/StorageLayout.h" + #include "../DataStructs/ChecksumType.h" #include "../DataStructs/ProvisioningStruct.h" #include "../DataTypes/ESPEasyFileType.h" @@ -185,6 +187,13 @@ String getCustomTaskSettingsError(uint8_t varNr); \*********************************************************************************************/ String ClearCustomTaskSettings(taskIndex_t TaskIndex); +/********************************************************************************************\ + Delete Extended custom task settings file if it exists, with validity checks + \*********************************************************************************************/ +#if FEATURE_EXTENDED_CUSTOM_SETTINGS +bool DeleteExtendedCustomTaskSettingsFile(SettingsType::Enum settingsType, int index); +#endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS + /********************************************************************************************\ Load Custom Task settings from file system \*********************************************************************************************/ From 74b2a2cbd365a3e94667e1b7e2fee84b6446a68b Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Tue, 15 Aug 2023 20:19:21 +0200 Subject: [PATCH 2/7] [Plugins] Adjust check for max. CustomTaskSettings --- src/_P095_ILI9341.ino | 2 +- src/_P096_eInk.ino | 2 +- src/_P116_ST77xx.ino | 2 +- src/_P131_NeoPixelMatrix.ino | 2 +- src/src/PluginStructs/P037_data_struct.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/_P095_ILI9341.ino b/src/_P095_ILI9341.ino index 079f94cf3f..1ebac7bf3f 100644 --- a/src/_P095_ILI9341.ino +++ b/src/_P095_ILI9341.ino @@ -337,7 +337,7 @@ boolean Plugin_095(uint8_t function, struct EventStruct *event, String& string) F("pbgcolor"), P095_CONFIG_GET_COLOR_BACKGROUND); - uint16_t remain = DAT_TASKS_CUSTOM_SIZE; + uint16_t remain = DAT_TASKS_CUSTOM_SIZE + DAT_TASKS_CUSTOM_EXTENSION_SIZE; { String strings[P095_Nlines]; LoadCustomTaskSettings(event->TaskIndex, strings, P095_Nlines, 0); diff --git a/src/_P096_eInk.ino b/src/_P096_eInk.ino index b1ad73c9f5..3f0489f93e 100644 --- a/src/_P096_eInk.ino +++ b/src/_P096_eInk.ino @@ -410,7 +410,7 @@ boolean Plugin_096(uint8_t function, struct EventStruct *event, String& string) String strings[P096_Nlines]; LoadCustomTaskSettings(event->TaskIndex, strings, P096_Nlines, 0); - uint16_t remain = DAT_TASKS_CUSTOM_SIZE; + uint16_t remain = DAT_TASKS_CUSTOM_SIZE + DAT_TASKS_CUSTOM_EXTENSION_SIZE; for (uint8_t varNr = 0; varNr < P096_Nlines; varNr++) { addFormTextBox(concat(F("Line "), (varNr + 1)), getPluginCustomArgName(varNr), strings[varNr], P096_Nchars); diff --git a/src/_P116_ST77xx.ino b/src/_P116_ST77xx.ino index a11ce37ea1..281ad5e3e9 100644 --- a/src/_P116_ST77xx.ino +++ b/src/_P116_ST77xx.ino @@ -227,7 +227,7 @@ boolean Plugin_116(uint8_t function, struct EventStruct *event, String& string) String strings[P116_Nlines]; LoadCustomTaskSettings(event->TaskIndex, strings, P116_Nlines, 0); - uint16_t remain = DAT_TASKS_CUSTOM_SIZE; + uint16_t remain = DAT_TASKS_CUSTOM_SIZE + DAT_TASKS_CUSTOM_EXTENSION_SIZE; for (uint8_t varNr = 0; varNr < P116_Nlines; varNr++) { addFormTextBox(concat(F("Line "), varNr + 1), getPluginCustomArgName(varNr), strings[varNr], P116_Nchars); diff --git a/src/_P131_NeoPixelMatrix.ino b/src/_P131_NeoPixelMatrix.ino index ebcb7b29b8..c2c4924286 100644 --- a/src/_P131_NeoPixelMatrix.ino +++ b/src/_P131_NeoPixelMatrix.ino @@ -197,7 +197,7 @@ boolean Plugin_131(uint8_t function, struct EventStruct *event, String& string) String strings[P131_Nlines]; LoadCustomTaskSettings(event->TaskIndex, strings, P131_Nlines, 0); - uint16_t remain = DAT_TASKS_CUSTOM_SIZE; + uint16_t remain = DAT_TASKS_CUSTOM_SIZE + DAT_TASKS_CUSTOM_EXTENSION_SIZE; addFormSubHeader(F("Lines")); addRowLabel(F("Lines")); diff --git a/src/src/PluginStructs/P037_data_struct.cpp b/src/src/PluginStructs/P037_data_struct.cpp index fa4ea6de58..d4655052ed 100644 --- a/src/src/PluginStructs/P037_data_struct.cpp +++ b/src/src/PluginStructs/P037_data_struct.cpp @@ -60,7 +60,7 @@ bool P037_data_struct::loadSettings() { String P037_data_struct::saveSettings() { String res; - if (_taskIndex < TASKS_MAX) { + if (_taskIndex < TASKS_MAX) { // TODO tonhuisman: Combine saving the settings into 1 call size_t offset = 0; res += SaveCustomTaskSettings(_taskIndex, mqttTopics, VARS_PER_TASK, 41, offset); From b9d0e9609256eba6335a780b9294a1307cae385d Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Sat, 26 Aug 2023 11:40:28 +0200 Subject: [PATCH 3/7] [Core] ExtendedCustomTaskSettings code improvements based on feedback --- src/src/DataTypes/ESPEasyFileType.cpp | 12 ++++----- src/src/DataTypes/SettingsType.cpp | 2 +- src/src/DataTypes/SettingsType.h | 5 ++-- src/src/Helpers/ESPEasy_Storage.cpp | 38 +++++++++++++-------------- 4 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/src/DataTypes/ESPEasyFileType.cpp b/src/src/DataTypes/ESPEasyFileType.cpp index 077b34937e..9a2c060c57 100644 --- a/src/src/DataTypes/ESPEasyFileType.cpp +++ b/src/src/DataTypes/ESPEasyFileType.cpp @@ -20,13 +20,13 @@ bool isProtectedFileType(const String& filename) { #if FEATURE_EXTENDED_CUSTOM_SETTINGS bool isTaskSpecificConfig = false; - const String fname = filename.substring(filename.startsWith(F("/")) ? 1 : 0); - const String mask = F(DAT_TASKS_CUSTOM_EXTENSION_FILEMASK); - const uint8_t mPerc = mask.indexOf('%'); + const String fname = filename.substring(filename.startsWith(F("/")) ? 1 : 0); + const String mask = F(DAT_TASKS_CUSTOM_EXTENSION_FILEMASK); + const int8_t mPerc = mask.indexOf('%'); - if (fname.startsWith(mask.substring(0, mPerc))) { - for (uint8_t n = 1; n <= TASKS_MAX && !isTaskSpecificConfig; n++) { - isTaskSpecificConfig |= (fname.equalsIgnoreCase(strformat(mask, n))); + if ((mPerc > -1) && fname.startsWith(mask.substring(0, mPerc))) { + for (uint8_t n = 0; n < TASKS_MAX && !isTaskSpecificConfig; n++) { + isTaskSpecificConfig |= (fname.equalsIgnoreCase(strformat(mask, n + 1))); } } #endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS diff --git a/src/src/DataTypes/SettingsType.cpp b/src/src/DataTypes/SettingsType.cpp index e8deed9d41..3b87cb0f50 100644 --- a/src/src/DataTypes/SettingsType.cpp +++ b/src/src/DataTypes/SettingsType.cpp @@ -209,7 +209,7 @@ SettingsType::SettingsFileEnum SettingsType::getSettingsFile(Enum settingsType) String SettingsType::getSettingsFileName(Enum settingsType, int index) { #if FEATURE_EXTENDED_CUSTOM_SETTINGS - if ((Enum::CustomTaskSettings_Type == settingsType) && (INVALID_TASK_INDEX != index)) { + if ((Enum::CustomTaskSettings_Type == settingsType) && validTaskIndex(index)) { return strformat(F(DAT_TASKS_CUSTOM_EXTENSION_FILEMASK), index + 1); // Add 0/1 offset to match displayed task ID } #endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS diff --git a/src/src/DataTypes/SettingsType.h b/src/src/DataTypes/SettingsType.h index 2ebec32845..6e9174023e 100644 --- a/src/src/DataTypes/SettingsType.h +++ b/src/src/DataTypes/SettingsType.h @@ -2,7 +2,7 @@ #define DATATYPES_SETTINGSTYPE_H #include "../../ESPEasy_common.h" - +#include "../DataTypes/TaskIndex.h" class SettingsType { public: @@ -47,7 +47,8 @@ class SettingsType { #endif // ifndef BUILD_MINIMAL_OTA static SettingsFileEnum getSettingsFile(Enum settingsType); - static String getSettingsFileName(Enum settingsType, int index = TASKS_MAX); + static String getSettingsFileName(Enum settingsType, + int index = INVALID_TASK_INDEX); static const __FlashStringHelper * getSettingsFileName(SettingsType::SettingsFileEnum file_type); static size_t getInitFileSize(SettingsType::SettingsFileEnum file_type); }; diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index 9891da163b..9681fc6ad1 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -430,11 +430,7 @@ void fileSystemCheck() { clearAllCaches(); if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("FS : Mount successful, used "); - log += SpiffsUsedBytes(); - log += F(" bytes of "); - log += SpiffsTotalBytes(); - addLogMove(LOG_LEVEL_INFO, log); + addLogMove(LOG_LEVEL_INFO, strformat(F("FS : Mount successful, used %d bytes of %d"), SpiffsUsedBytes(), SpiffsTotalBytes())); } // Run garbage collection before any file is open. @@ -1466,9 +1462,7 @@ String doSaveToFile(const char *fname, int index, const uint8_t *memAddress, int #ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("SaveToFile: free stack: "); - log += getCurrentFreeStack(); - addLogMove(LOG_LEVEL_INFO, log); + addLogMove(LOG_LEVEL_INFO, concat(F("SaveToFile: free stack: "), getCurrentFreeStack())); } #endif delay(1); @@ -1528,9 +1522,7 @@ String doSaveToFile(const char *fname, int index, const uint8_t *memAddress, int STOP_TIMER(SAVEFILE_STATS); #ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("SaveToFile: free stack after: "); - log += getCurrentFreeStack(); - addLogMove(LOG_LEVEL_INFO, log); + addLogMove(LOG_LEVEL_INFO, concat(F("SaveToFile: free stack after: "), getCurrentFreeStack())); } #endif @@ -1746,8 +1738,10 @@ String SaveToFile(SettingsType::Enum settingsType, int index, const uint8_t *mem dataOffset = (DAT_TASKS_CUSTOM_SIZE - posInBlock); // Bytes to keep 'local' # ifndef BUILD_NO_DEBUG const String styp = SettingsType::getSettingsTypeString(settingsType); - addLog(LOG_LEVEL_INFO, concat(F("ExtraSaveToFile: "), styp) + concat(F(" file: "), fname) + - strformat(F(" size: %d pos: %d"), dataOffset, posInBlock)); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLog(LOG_LEVEL_INFO, strformat(F("ExtraSaveToFile: %s file: %s size: %d pos: %d"), + styp.c_str(), fname.c_str(), dataOffset, posInBlock)); + } # endif // ifndef BUILD_NO_DEBUG const String res = SaveToFile(fname.c_str(), offset + posInBlock, memAddress, dataOffset); @@ -1770,7 +1764,7 @@ String SaveToFile(SettingsType::Enum settingsType, int index, const uint8_t *mem ); if (!fileExists(fname)) { #if FEATURE_EXTENDED_CUSTOM_SETTINGS - if (INVALID_TASK_INDEX == taskIndex) { + if (!validTaskIndex(taskIndex)) { #endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS InitFile(settingsType); #if FEATURE_EXTENDED_CUSTOM_SETTINGS @@ -1780,8 +1774,10 @@ String SaveToFile(SettingsType::Enum settingsType, int index, const uint8_t *mem #endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS } #ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_INFO, concat(F("SaveToFile: "), SettingsType::getSettingsTypeString(settingsType)) + - strformat(F(" file: %s task: %d"), fname.c_str(), index + 1)); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLog(LOG_LEVEL_INFO, concat(F("SaveToFile: "), SettingsType::getSettingsTypeString(settingsType)) + + strformat(F(" file: %s task: %d"), fname.c_str(), index + 1)); + } #endif return SaveToFile(fname.c_str(), offset + posInBlock, memAddress + dataOffset, datasize); } @@ -1806,13 +1802,15 @@ String ClearInFile(SettingsType::Enum settingsType, int index) { #if FEATURE_EXTENDED_CUSTOM_SETTINGS bool DeleteExtendedCustomTaskSettingsFile(SettingsType::Enum settingsType, int index) { - if ((SettingsType::Enum::CustomTaskSettings_Type == settingsType) && (INVALID_TASK_INDEX !=index)) { + if ((SettingsType::Enum::CustomTaskSettings_Type == settingsType) && validTaskIndex(index)) { const String fname = SettingsType::getSettingsFileName(settingsType, index); if (fileExists(fname)) { const bool deleted = tryDeleteFile(fname); // Don't need the extension file anymore, so delete it # ifndef BUILD_NO_DEBUG - addLog(LOG_LEVEL_INFO, concat(F("CustomTaskSettings: Removing no longer needed file: "), fname)); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLog(LOG_LEVEL_INFO, concat(F("CustomTaskSettings: Removing no longer needed file: "), fname)); + } # endif // ifndef BUILD_NO_DEBUG return deleted; } @@ -2006,7 +2004,9 @@ bool getCacheFileCounters(uint16_t& lowest, uint16_t& highest, size_t& filesizeH } #ifndef BUILD_NO_DEBUG } else { - addLog(LOG_LEVEL_INFO, concat(F("RTC : Cannot get count from: "), fname)); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLog(LOG_LEVEL_INFO, concat(F("RTC : Cannot get count from: "), fname)); + } #endif } } From 4b7052e75b27b81ddda3a76a3b334351d9c822b3 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Thu, 31 Aug 2023 20:37:02 +0200 Subject: [PATCH 4/7] [Core] Re-enable Flash-formatting for LittleFS --- src/src/Helpers/ESPEasy_Storage.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index 26ca6ec7b5..676fdc2acd 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -439,7 +439,7 @@ void fileSystemCheck() --retries; } - fs::File f = tryOpenFile(SettingsType::getSettingsFileName(SettingsType::Enum::BasicSettings_Type).c_str(), "r"); + fs::File f = tryOpenFile(SettingsType::getSettingsFileName(SettingsType::Enum::BasicSettings_Type), "r"); if (f) { f.close(); } else { @@ -456,17 +456,18 @@ void fileSystemCheck() } bool FS_format() { - #ifdef USE_LITTLEFS - #ifdef ESP32 - const bool res = ESPEASY_FS.begin(true); - ESPEASY_FS.end(); - return res; - #else - return ESPEASY_FS.format(); - #endif - #else + // 'Fix' for IDF 4.4 LittleFS not needed anymore + // #ifdef USE_LITTLEFS + // #ifdef ESP32 + // const bool res = ESPEASY_FS.begin(true); + // ESPEASY_FS.end(); + // return res; + // #else + // return ESPEASY_FS.format(); + // #endif + // #else return ESPEASY_FS.format(); - #endif + // #endif } #ifdef ESP32 From 3c43a1b97df254f08f474148617df1a0ddd00090 Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Fri, 12 Jan 2024 23:26:57 +0100 Subject: [PATCH 5/7] [Core] String optimizations --- src/src/DataTypes/ESPEasyFileType.cpp | 2 +- src/src/Helpers/ESPEasy_Storage.cpp | 130 ++++++++------------------ 2 files changed, 38 insertions(+), 94 deletions(-) diff --git a/src/src/DataTypes/ESPEasyFileType.cpp b/src/src/DataTypes/ESPEasyFileType.cpp index 9a2c060c57..a8b3bf4bc0 100644 --- a/src/src/DataTypes/ESPEasyFileType.cpp +++ b/src/src/DataTypes/ESPEasyFileType.cpp @@ -25,7 +25,7 @@ bool isProtectedFileType(const String& filename) const int8_t mPerc = mask.indexOf('%'); if ((mPerc > -1) && fname.startsWith(mask.substring(0, mPerc))) { - for (uint8_t n = 0; n < TASKS_MAX && !isTaskSpecificConfig; n++) { + for (uint8_t n = 0; n < TASKS_MAX && !isTaskSpecificConfig; ++n) { isTaskSpecificConfig |= (fname.equalsIgnoreCase(strformat(mask, n + 1))); } } diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index 21008e2a96..e941789d20 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -867,10 +867,8 @@ bool getAndLogSettingsParameters(bool read, SettingsType::Enum settingsType, int if (loglevelActiveFor(LOG_LEVEL_DEBUG_DEV)) { String log = read ? F("Read") : F("Write"); - log += F(" settings: "); - log += SettingsType::getSettingsTypeString(settingsType); - log += F(" index: "); - log += index; + log += concat(F(" settings: "), SettingsType::getSettingsTypeString(settingsType)); + log += concat(F(" index: "), index); addLogMove(LOG_LEVEL_DEBUG_DEV, log); } #endif // ifndef BUILD_NO_DEBUG @@ -943,8 +941,7 @@ String LoadStringArray(SettingsType::Enum settingsType, int index, String string } if ((!tmpString.isEmpty()) && (stringCount < nrStrings)) { - result += F("Incomplete custom settings for index "); - result += (index + 1); + result += concat(F("Incomplete custom settings for index "), index + 1); move_special(strings[stringCount], std::move(tmpString)); } return result; @@ -1234,11 +1231,7 @@ String SaveCustomTaskSettings(taskIndex_t TaskIndex, String strings[], uint16_t } String getCustomTaskSettingsError(uint8_t varNr) { - String error = F("Error: Text too long for line "); - - error += varNr + 1; - error += '\n'; - return error; + return strformat(F("Error: Text too long for line %d\n"), varNr + 1); } /********************************************************************************************\ @@ -1501,10 +1494,7 @@ String doSaveToFile(const char *fname, int index, const uint8_t *memAddress, int #ifndef ESP32 if (allocatedOnStack(memAddress)) { - String log = F("SaveToFile: "); - log += fname; - log += F(" ERROR, Data allocated on stack"); - addLog(LOG_LEVEL_ERROR, log); + addLog(LOG_LEVEL_ERROR, strformat(F("SaveToFile: %s ERROR, Data allocated on stack"), fname)); // return log; // FIXME TD-er: Should this be considered a breaking error? } @@ -1513,11 +1503,9 @@ String doSaveToFile(const char *fname, int index, const uint8_t *memAddress, int if (index < 0) { #ifndef BUILD_NO_DEBUG - String log = F("SaveToFile: "); - log += fname; - log += F(" ERROR, invalid position in file"); + const String log = strformat(F("SaveToFile: %s ERROR, invalid position in file"), fname); #else - String log = F("Save error"); + const String log = F("Save error"); #endif addLog(LOG_LEVEL_ERROR, log); return log; @@ -1564,24 +1552,14 @@ String doSaveToFile(const char *fname, int index, const uint8_t *memAddress, int f.close(); #ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log; - log.reserve(48); - log += F("FILE : Saved "); - log += fname; - log += F(" offset: "); - log += index; - log += F(" size: "); - log += datasize; - addLogMove(LOG_LEVEL_INFO, log); + addLogMove(LOG_LEVEL_INFO, strformat(F("FILE : Saved %s offset: %d size: %d"), fname, index, datasize)); } #endif } else { #ifndef BUILD_NO_DEBUG - String log = F("SaveToFile: "); - log += fname; - log += F(" ERROR, Cannot save to file"); + const String log = strformat(F("SaveToFile: %s ERROR, Cannot save to file"), fname); #else - String log = F("Save error"); + const String log = F("Save error"); #endif addLog(LOG_LEVEL_ERROR, log); @@ -1605,11 +1583,9 @@ String ClearInFile(const char *fname, int index, int datasize) { if (index < 0) { #ifndef BUILD_NO_DEBUG - String log = F("ClearInFile: "); - log += fname; - log += F(" ERROR, invalid position in file"); + const String log = strformat(F("ClearInFile: %s ERROR, invalid position in file"), fname); #else - String log = F("Save error"); + const String log = F("Save error"); #endif addLog(LOG_LEVEL_ERROR, log); @@ -1635,11 +1611,9 @@ String ClearInFile(const char *fname, int index, int datasize) f.close(); } else { #ifndef BUILD_NO_DEBUG - String log = F("ClearInFile: "); - log += fname; - log += F(" ERROR, Cannot save to file"); + const String log = strformat(F("ClearInFile: %s ERROR, Cannot save to file"), fname); #else - String log = F("Save error"); + const String log = F("Save error"); #endif addLog(LOG_LEVEL_ERROR, log); return log; @@ -1656,11 +1630,9 @@ String LoadFromFile(const char *fname, int offset, uint8_t *memAddress, int data { if (offset < 0) { #ifndef BUILD_NO_DEBUG - String log = F("LoadFromFile: "); - log += fname; - log += F(" ERROR, invalid position in file"); + const String log = strformat(F("LoadFromFile: %s ERROR, invalid position in file"), fname); #else - String log = F("Load error"); + const String log = F("Load error"); #endif addLog(LOG_LEVEL_ERROR, log); return log; @@ -1700,15 +1672,12 @@ String LoadFromFile(const char *fname, int offset, uint8_t *memAddress, int data \*********************************************************************************************/ String getSettingsFileIndexRangeError(bool read, SettingsType::Enum settingsType, int index) { if (settingsType >= SettingsType::Enum::SettingsType_MAX) { - String error = F("Unknown settingsType: "); - error += static_cast(settingsType); - return error; + return concat(F("Unknown settingsType: "), static_cast(settingsType)); } String error = read ? F("Load") : F("Save"); #ifndef BUILD_NO_DEBUG error += SettingsType::getSettingsTypeString(settingsType); - error += F(" index out of range: "); - error += index; + error += concat(F(" index out of range: "), index); #else error += F(" error"); #endif @@ -1719,13 +1688,7 @@ String getSettingsFileDatasizeError(bool read, SettingsType::Enum settingsType, String error = read ? F("Load") : F("Save"); #ifndef BUILD_NO_DEBUG error += SettingsType::getSettingsTypeString(settingsType); - error += '('; - error += index; - error += F(") datasize("); - error += datasize; - error += F(") > max_size("); - error += max_size; - error += ')'; + error += strformat(F("(%d) datasize(%d) > max_size(%d)"), index, datasize, max_size); #else error += F(" error"); #endif @@ -1996,9 +1959,7 @@ String createCacheFilename(unsigned int count) { #ifdef ESP32 fname = '/'; #endif // ifdef ESP32 - fname += F("cache_"); - fname += String(count); - fname += F(".bin"); + fname += strformat(F("cache_%d.bin"), count); return fname; } @@ -2103,9 +2064,7 @@ String getPartitionType(uint8_t pType, uint8_t pSubType) { if (partitionType == ESP_PARTITION_TYPE_APP) { if ((partitionSubType >= ESP_PARTITION_SUBTYPE_APP_OTA_MIN) && (partitionSubType < ESP_PARTITION_SUBTYPE_APP_OTA_MAX)) { - String result = F("OTA partition "); - result += (partitionSubType - ESP_PARTITION_SUBTYPE_APP_OTA_MIN); - return result; + return concat(F("OTA partition "), partitionSubType - ESP_PARTITION_SUBTYPE_APP_OTA_MIN); } switch (partitionSubType) { @@ -2136,26 +2095,12 @@ String getPartitionType(uint8_t pType, uint8_t pSubType) { default: break; } } - String result = F("Unknown("); - result += partitionSubType; - result += ')'; - return result; + return strformat(F("Unknown(%d)"), partitionSubType); } String getPartitionTableHeader(const String& itemSep, const String& lineEnd) { - String result; - - result += F("Address"); - result += itemSep; - result += F("Size"); - result += itemSep; - result += F("Label"); - result += itemSep; - result += F("Partition Type"); - result += itemSep; - result += F("Encrypted"); - result += lineEnd; - return result; + return strformat(F("Address%sSize%sLabel%sPartition Type%sEncrypted%s"), + itemSep.c_str(), itemSep.c_str(), itemSep.c_str(), itemSep.c_str(), lineEnd.c_str()); } String getPartitionTable(uint8_t pType, const String& itemSep, const String& lineEnd) { @@ -2166,16 +2111,17 @@ String getPartitionTable(uint8_t pType, const String& itemSep, const String& lin if (_mypartiterator) { do { const esp_partition_t *_mypart = esp_partition_get(_mypartiterator); - result += formatToHex(_mypart->address); - result += itemSep; - result += formatToHex_decimal(_mypart->size, 1024); - result += itemSep; - result += _mypart->label; - result += itemSep; - result += getPartitionType(_mypart->type, _mypart->subtype); - result += itemSep; - result += (_mypart->encrypted ? F("Yes") : F("-")); - result += lineEnd; + result += strformat(F("%x%s%s%s%s%s%s%s%s%s"), + _mypart->address, + itemSep, + formatToHex_decimal(_mypart->size, 1024), + itemSep, + _mypart->label, + itemSep, + getPartitionType(_mypart->type, _mypart->subtype).c_str(), + itemSep, + String(_mypart->encrypted ? F("Yes") : F("-")).c_str(), + lineEnd); } while ((_mypartiterator = esp_partition_next(_mypartiterator)) != nullptr); } esp_partition_iterator_release(_mypartiterator); @@ -2206,8 +2152,7 @@ String downloadFileType(const String& url, const String& user, const String& pas } } else { if (fileExists(filename)) { - String filename_bak = filename; - filename_bak += F("_bak"); + const String filename_bak = strformat(F("%s_bak"), filename.c_str()); if (fileExists(filename_bak)) { if (!ResetFactoryDefaultPreference.delete_Bak_Files() || !tryDeleteFile(filename_bak)) { return F("Could not rename to _bak"); @@ -2215,8 +2160,7 @@ String downloadFileType(const String& url, const String& user, const String& pas } // Must download it to a tmp file. - String tmpfile = filename; - tmpfile += F("_tmp"); + const String tmpfile = strformat(F("%s_tmp"),filename.c_str()); if (!downloadFile(fullUrl, tmpfile, user, pass, error)) { return error; From a8247caba0ec05378d1ed4f292463aadd8772c9c Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Mon, 1 Apr 2024 14:43:21 +0200 Subject: [PATCH 6/7] [Storage] Use correct parameter-type for strformat() --- src/src/Helpers/ESPEasy_Storage.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index 3720f1f189..a42422b3b5 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -2129,15 +2129,15 @@ String getPartitionTable(uint8_t pType, const String& itemSep, const String& lin const esp_partition_t *_mypart = esp_partition_get(_mypartiterator); result += strformat(F("%x%s%s%s%s%s%s%s%s%s"), _mypart->address, - itemSep, + itemSep.c_str(), formatToHex_decimal(_mypart->size, 1024), - itemSep, + itemSep.c_str(), _mypart->label, - itemSep, + itemSep.c_str(), getPartitionType(_mypart->type, _mypart->subtype).c_str(), - itemSep, + itemSep.c_str(), String(_mypart->encrypted ? F("Yes") : F("-")).c_str(), - lineEnd); + lineEnd.c_str()); } while ((_mypartiterator = esp_partition_next(_mypartiterator)) != nullptr); } esp_partition_iterator_release(_mypartiterator); From 5a402acd16978f91eb3f98dab2a00bdbc1f29dea Mon Sep 17 00:00:00 2001 From: Ton Huisman Date: Mon, 1 Apr 2024 15:01:07 +0200 Subject: [PATCH 7/7] [Storage] Use correct parameter-type for strformat() --- src/src/Helpers/ESPEasy_Storage.cpp | 599 +++++++++++++++++----------- 1 file changed, 361 insertions(+), 238 deletions(-) diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index a42422b3b5..5941a5f6b2 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -12,8 +12,8 @@ #include "../DataTypes/SPI_options.h" #if FEATURE_MQTT -#include "../ESPEasyCore/Controller.h" -#endif +# include "../ESPEasyCore/Controller.h" +#endif // if FEATURE_MQTT #include "../ESPEasyCore/ESPEasy_Log.h" #include "../ESPEasyCore/ESPEasyNetwork.h" #include "../ESPEasyCore/ESPEasyWifi.h" @@ -53,11 +53,11 @@ #if FEATURE_RTC_CACHE_STORAGE # include "../Globals/C016_ControllerCache.h" -#endif +#endif // if FEATURE_RTC_CACHE_STORAGE #ifdef ESP32 -#include -#endif +# include +#endif // ifdef ESP32 #ifdef ESP32 String patch_fname(const String& fname) { @@ -66,7 +66,8 @@ String patch_fname(const String& fname) { } return String('/') + fname; } -#endif + +#endif // ifdef ESP32 /********************************************************************************************\ file system error handling @@ -75,6 +76,7 @@ String patch_fname(const String& fname) { String FileError(int line, const char *fname) { String log = strformat(F("FS : Error while reading/writing %s in %d"), fname, line); + addLog(LOG_LEVEL_ERROR, log); return log; } @@ -95,7 +97,7 @@ String flashGuard() { #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("flashGuard")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER if (RTC.flashDayCounter > MAX_FLASHWRITES_PER_DAY) { @@ -125,7 +127,7 @@ String appendToFile(const String& fname, const uint8_t *data, unsigned int size) return EMPTY_STRING; } -bool fileExists(const __FlashStringHelper * fname) +bool fileExists(const __FlashStringHelper *fname) { return fileExists(String(fname)); } @@ -133,30 +135,35 @@ bool fileExists(const __FlashStringHelper * fname) bool fileExists(const String& fname) { #ifdef USE_SECOND_HEAP HeapSelectDram ephemeral; - #endif + #endif // ifdef USE_SECOND_HEAP const String patched_fname = patch_fname(fname); - auto search = Cache.fileExistsMap.find(patched_fname); + auto search = Cache.fileExistsMap.find(patched_fname); + if (search != Cache.fileExistsMap.end()) { return search->second; } bool res = ESPEASY_FS.exists(patched_fname); #if FEATURE_SD + if (!res) { res = SD.exists(patched_fname); } - #endif + #endif // if FEATURE_SD + // Only keep track of existing files or non-existing filenames that may be requested several times. // Not the non-existing files from the cache controller #if FEATURE_RTC_CACHE_STORAGE - if (res || !isCacheFile(patched_fname)) - #endif + + if (res || !isCacheFile(patched_fname)) + #endif // if FEATURE_RTC_CACHE_STORAGE { Cache.fileExistsMap.emplace( std::make_pair( - patched_fname, + patched_fname, res)); } + if (Cache.fileCacheClearMoment == 0) { if (node_time.timeSource == timeSource_t::No_time_source) { // use some random value as we don't have a time yet @@ -171,6 +178,7 @@ bool fileExists(const String& fname) { fs::File tryOpenFile(const String& fname, const String& mode, FileDestination_e destination) { START_TIMER; fs::File f; + if (fname.isEmpty() || equals(fname, '/')) { return f; } @@ -183,15 +191,16 @@ fs::File tryOpenFile(const String& fname, const String& mode, FileDestination_e } clearFileCaches(); } + if ((destination == FileDestination_e::ANY) || (destination == FileDestination_e::FLASH)) { f = ESPEASY_FS.open(patch_fname(fname), mode.c_str()); } - # if FEATURE_SD + #if FEATURE_SD if (!f && ((destination == FileDestination_e::ANY) || (destination == FileDestination_e::SD))) { f = SD.open(patch_fname(fname).c_str(), mode.c_str()); } - # endif // if FEATURE_SD + #endif // if FEATURE_SD STOP_TIMER(TRY_OPEN_FILE); @@ -200,11 +209,13 @@ fs::File tryOpenFile(const String& fname, const String& mode, FileDestination_e bool fileMatchesTaskSettingsType(const String& fname) { const String config_dat_file = patch_fname(getFileName(FileType::CONFIG_DAT)); + return config_dat_file.equalsIgnoreCase(patch_fname(fname)); } bool tryRenameFile(const String& fname_old, const String& fname_new, FileDestination_e destination) { clearFileCaches(); + if (fileExists(fname_old) && !fileExists(fname_new)) { if (fileMatchesTaskSettingsType(fname_old)) { clearAllCaches(); @@ -212,10 +223,12 @@ bool tryRenameFile(const String& fname_old, const String& fname_new, FileDestina clearAllButTaskCaches(); } bool res = false; + if ((destination == FileDestination_e::ANY) || (destination == FileDestination_e::FLASH)) { res = ESPEASY_FS.rename(patch_fname(fname_old), patch_fname(fname_new)); } #if FEATURE_SD && defined(ESP32) // FIXME ESP8266 SDClass doesn't support rename + if (!res && ((destination == FileDestination_e::ANY) || (destination == FileDestination_e::SD))) { res = SD.rename(patch_fname(fname_old), patch_fname(fname_new)); } @@ -229,24 +242,28 @@ bool tryDeleteFile(const String& fname, FileDestination_e destination) { if (fname.length() > 0) { #if FEATURE_RTC_CACHE_STORAGE + if (isCacheFile(fname)) { ControllerCache.closeOpenFiles(); } - #endif + #endif // if FEATURE_RTC_CACHE_STORAGE + if (fileMatchesTaskSettingsType(fname)) { clearAllCaches(); } else { clearAllButTaskCaches(); } bool res = false; + if ((destination == FileDestination_e::ANY) || (destination == FileDestination_e::FLASH)) { res = ESPEASY_FS.remove(patch_fname(fname)); } #if FEATURE_SD + if (!res && ((destination == FileDestination_e::ANY) || (destination == FileDestination_e::SD))) { res = SD.remove(patch_fname(fname)); } - #endif + #endif // if FEATURE_SD // A call to GarbageCollection() will at most erase a single block. (e.g. 8k block size) // A deleted file may have covered more than a single block, so try to clear multiple blocks. @@ -271,7 +288,7 @@ bool BuildFixes() } #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("BuildFixes")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER serialPrintln(F("\nBuild changed!")); if (Settings.Build < 145) @@ -283,7 +300,7 @@ bool BuildFixes() { #ifdef LIMIT_BUILD_SIZE serialPrintln(F("Fix reset Pin")); - #endif + #endif // ifdef LIMIT_BUILD_SIZE Settings.Pin_Reset = -1; } @@ -292,10 +309,10 @@ bool BuildFixes() // Have to patch settings to make sure no bogus data is being used. #ifdef LIMIT_BUILD_SIZE serialPrintln(F("Fix settings with uninitalized data or corrupted by switching between versions")); - #endif - Settings.UseRTOSMultitasking = false; - Settings.Pin_Reset = -1; - Settings.SyslogFacility = DEFAULT_SYSLOG_FACILITY; + #endif // ifdef LIMIT_BUILD_SIZE + Settings.UseRTOSMultitasking = false; + Settings.Pin_Reset = -1; + Settings.SyslogFacility = DEFAULT_SYSLOG_FACILITY; Settings.MQTTUseUnitNameAsClientId_unused = DEFAULT_MQTT_USE_UNITNAME_AS_CLIENTID; } @@ -303,27 +320,33 @@ bool BuildFixes() Settings.ResetFactoryDefaultPreference = 0; Settings.OldRulesEngine(DEFAULT_RULES_OLDENGINE); } + if (Settings.Build < 20105) { Settings.I2C_clockSpeed = DEFAULT_I2C_CLOCK_SPEED; } + if (Settings.Build <= 20106) { // ClientID is now defined in the controller settings. #if FEATURE_MQTT controllerIndex_t controller_idx = firstEnabledMQTT_ControllerIndex(); + if (validControllerIndex(controller_idx)) { - MakeControllerSettings(ControllerSettings); //-V522 + MakeControllerSettings(ControllerSettings); // -V522 + if (AllocatedControllerSettings()) { LoadControllerSettings(controller_idx, *ControllerSettings); String clientid; + if (Settings.MQTTUseUnitNameAsClientId_unused) { clientid = F("%sysname%"); + if (Settings.appendUnitToHostname()) { clientid += F("_%unit%"); } } else { - clientid = F("ESPClient_%mac%"); + clientid = F("ESPClient_%mac%"); } safe_strncpy(ControllerSettings->ClientID, clientid, sizeof(ControllerSettings->ClientID)); @@ -334,50 +357,62 @@ bool BuildFixes() } #endif // if FEATURE_MQTT } + if (Settings.Build < 20107) { Settings.WebserverPort = 80; } + if (Settings.Build < 20108) { #ifdef ESP32 - // Ethernet related settings are never used on ESP8266 + + // Ethernet related settings are never used on ESP8266 Settings.ETH_Phy_Addr = DEFAULT_ETH_PHY_ADDR; Settings.ETH_Pin_mdc_cs = DEFAULT_ETH_PIN_MDC; Settings.ETH_Pin_mdio_irq = DEFAULT_ETH_PIN_MDIO; Settings.ETH_Pin_power_rst = DEFAULT_ETH_PIN_POWER; Settings.ETH_Phy_Type = DEFAULT_ETH_PHY_TYPE; Settings.ETH_Clock_Mode = DEFAULT_ETH_CLOCK_MODE; -#endif - Settings.NetworkMedium = DEFAULT_NETWORK_MEDIUM; +#endif // ifdef ESP32 + Settings.NetworkMedium = DEFAULT_NETWORK_MEDIUM; } + if (Settings.Build < 20109) { Settings.SyslogPort = 514; } + if (Settings.Build < 20110) { - Settings.I2C_clockSpeed_Slow = DEFAULT_I2C_CLOCK_SPEED_SLOW; + Settings.I2C_clockSpeed_Slow = DEFAULT_I2C_CLOCK_SPEED_SLOW; Settings.I2C_Multiplexer_Type = I2C_MULTIPLEXER_NONE; Settings.I2C_Multiplexer_Addr = -1; + for (taskIndex_t x = 0; x < TASKS_MAX; x++) { Settings.I2C_Multiplexer_Channel[x] = -1; } Settings.I2C_Multiplexer_ResetPin = -1; } + if (Settings.Build < 20111) { #ifdef ESP32 constexpr uint8_t maxStatesesp32 = NR_ELEMENTS(Settings.PinBootStates_ESP32); + for (uint8_t i = 0; i < maxStatesesp32; ++i) { Settings.PinBootStates_ESP32[i] = 0; } - #endif + #endif // ifdef ESP32 } + if (Settings.Build < 20112) { - Settings.WiFi_TX_power = 70; // 70 = 17.5dBm. unit: 0.25 dBm - Settings.WiFi_sensitivity_margin = 3; // Margin in dBm on top of sensitivity. + Settings.WiFi_TX_power = 70; // 70 = 17.5dBm. unit: 0.25 dBm + Settings.WiFi_sensitivity_margin = 3; // Margin in dBm on top of sensitivity. } + if (Settings.Build < 20113) { Settings.NumberExtraWiFiScans = 0; } + if (Settings.Build < 20114) { #ifdef USES_P003 + // P003_Pulse was always using the pull-up, now it is a setting. constexpr pluginID_t PLUGIN_ID_P003_PULSE(3); @@ -386,8 +421,9 @@ bool BuildFixes() Settings.TaskDevicePin1PullUp[taskIndex] = true; } } - #endif + #endif // ifdef USES_P003 } + if (Settings.Build < 20115) { if (Settings.InitSPI != static_cast(SPI_Options_e::UserDefined)) { // User-defined SPI pins set to None Settings.SPI_SCLK_pin = -1; @@ -396,6 +432,7 @@ bool BuildFixes() } } #ifdef USES_P053 + if (Settings.Build < 20116) { // Added PWR button, init to "-none-" constexpr pluginID_t PLUGIN_ID_P053_PMSx003(53); @@ -405,15 +442,16 @@ bool BuildFixes() Settings.TaskDevicePluginConfig[taskIndex][3] = -1; } } + // Remove PeriodicalScanWiFi // Reset to default 0 for future use. Settings.VariousBits_1.unused_15 = 0; } - #endif + #endif // ifdef USES_P053 // Starting 2022/08/18 // Use get_build_nr() value for settings transitions. - // This value will also be shown when building using PlatformIO, when showing the Compile time defines + // This value will also be shown when building using PlatformIO, when showing the Compile time defines Settings.Build = get_build_nr(); Settings.StructSize = sizeof(Settings); @@ -431,26 +469,29 @@ void fileSystemCheck() { #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("fileSystemCheck")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER addLog(LOG_LEVEL_INFO, F("FS : Mounting...")); #if defined(ESP32) && defined(USE_LITTLEFS) - if (getPartionCount(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS) != 0 + + if ((getPartionCount(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS) != 0) && ESPEASY_FS.begin()) -#else +#else // if defined(ESP32) && defined(USE_LITTLEFS) + if (ESPEASY_FS.begin()) -#endif +#endif // if defined(ESP32) && defined(USE_LITTLEFS) { clearAllCaches(); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { addLogMove(LOG_LEVEL_INFO, strformat( - F("FS : " + F("FS : " #ifdef USE_LITTLEFS - "LittleFS" -#else - "SPIFFS" -#endif - " mount successful, used %u bytes of %u"), - SpiffsUsedBytes(), SpiffsTotalBytes())); + "LittleFS" +#else // ifdef USE_LITTLEFS + "SPIFFS" +#endif // ifdef USE_LITTLEFS + " mount successful, used %u bytes of %u"), + SpiffsUsedBytes(), SpiffsTotalBytes())); } // Run garbage collection before any file is open. @@ -461,15 +502,16 @@ void fileSystemCheck() } fs::File f = tryOpenFile(SettingsType::getSettingsFileName(SettingsType::Enum::BasicSettings_Type), "r"); - if (f) { - f.close(); + + if (f) { + f.close(); } else { ResetFactory(false); } } else { - const __FlashStringHelper * log = F("FS : Mount failed"); + const __FlashStringHelper *log = F("FS : Mount failed"); serialPrintln(log); addLog(LOG_LEVEL_ERROR, log); ResetFactory(); @@ -488,6 +530,7 @@ bool FS_format() { // #endif // #else return ESPEASY_FS.format(); + // #endif } @@ -497,7 +540,7 @@ bool FS_format() { int getPartionCount(uint8_t pType, uint8_t pSubType) { esp_partition_type_t partitionType = static_cast(pType); - esp_partition_subtype_t subtype = static_cast(pSubType); + esp_partition_subtype_t subtype = static_cast(pSubType); esp_partition_iterator_t _mypartiterator = esp_partition_find(partitionType, subtype, NULL); int nrPartitions = 0; @@ -510,19 +553,18 @@ int getPartionCount(uint8_t pType, uint8_t pSubType) { return nrPartitions; } - -#endif +#endif // ifdef ESP32 #ifdef ESP8266 bool clearPartition(ESP8266_partition_type ptype) { uint32_t address; - int32_t size; - int32_t sector = getPartitionInfo(ESP8266_partition_type::rf_cal, address, size); + int32_t size; + int32_t sector = getPartitionInfo(ESP8266_partition_type::rf_cal, address, size); + while (size > 0) { - if (!ESP.flashEraseSector(sector)) return false; + if (!ESP.flashEraseSector(sector)) { return false; } ++sector; size -= SPI_FLASH_SEC_SIZE; - } return true; } @@ -535,7 +577,7 @@ bool clearWiFiSDKpartition() { return clearPartition(ESP8266_partition_type::wifi); } -#endif +#endif // ifdef ESP8266 /********************************************************************************************\ @@ -548,9 +590,9 @@ bool GarbageCollection() { START_TIMER; if (ESPEASY_FS.gc()) { -#ifndef BUILD_NO_DEBUG +# ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, F("FS : Success garbage collection")); -#endif +# endif // ifndef BUILD_NO_DEBUG STOP_TIMER(FS_GC_SUCCESS); return true; } @@ -570,8 +612,8 @@ String SaveSettings(bool forFactoryReset) { #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("SaveSettings")); - #endif - String err; + #endif // ifndef BUILD_NO_RAM_TRACKER + String err; { Settings.StructSize = sizeof(Settings); @@ -585,21 +627,25 @@ String SaveSettings(bool forFactoryReset) } if (!COMPUTE_STRUCT_CHECKSUM_UPDATE(SettingsStruct, Settings) - /* - computeChecksum( - Settings.md5, - reinterpret_cast(&Settings), - sizeof(SettingsStruct), - offsetof(SettingsStruct, md5)) - */ + + /* + computeChecksum( + Settings.md5, + reinterpret_cast(&Settings), + sizeof(SettingsStruct), + offsetof(SettingsStruct, md5)) + */ ) { - err = SaveToFile(SettingsType::getSettingsFileName(SettingsType::Enum::BasicSettings_Type).c_str(), 0, reinterpret_cast(&Settings), sizeof(Settings)); - } -#ifndef BUILD_NO_DEBUG + err = SaveToFile(SettingsType::getSettingsFileName(SettingsType::Enum::BasicSettings_Type).c_str(), + 0, + reinterpret_cast(&Settings), + sizeof(Settings)); + } +#ifndef BUILD_NO_DEBUG else { addLog(LOG_LEVEL_INFO, F("Skip saving settings, not changed")); } -#endif +#endif // ifndef BUILD_NO_DEBUG } if (err.length()) { @@ -607,10 +653,11 @@ String SaveSettings(bool forFactoryReset) } #ifndef BUILD_MINIMAL_OTA + // Must check this after saving, or else it is not possible to fix multiple // issues which can only corrected on different pages. if (!SettingsCheck(err)) { return err; } -#endif +#endif // ifndef BUILD_MINIMAL_OTA // } @@ -620,7 +667,7 @@ String SaveSettings(bool forFactoryReset) } String SaveSecuritySettings(bool forFactoryReset) { - String err; + String err; SecuritySettings.validate(); memcpy(SecuritySettings.ProgmemMd5, CRCValues.runTimeMD5, 16); @@ -631,23 +678,26 @@ String SaveSecuritySettings(bool forFactoryReset) { if (SecuritySettings.updateChecksum()) { // Settings have changed, save to file. - err = SaveToFile(SettingsType::getSettingsFileName(SettingsType::Enum::SecuritySettings_Type).c_str(), 0, reinterpret_cast(&SecuritySettings), sizeof(SecuritySettings)); + err = SaveToFile(SettingsType::getSettingsFileName(SettingsType::Enum::SecuritySettings_Type).c_str(), + 0, + reinterpret_cast(&SecuritySettings), + sizeof(SecuritySettings)); // Security settings are saved, may be update of WiFi settings or hostname. if (!forFactoryReset && !NetworkConnected()) { - if (SecuritySettings.hasWiFiCredentials() && active_network_medium == NetworkMedium_t::WIFI) { + if (SecuritySettings.hasWiFiCredentials() && (active_network_medium == NetworkMedium_t::WIFI)) { WiFiEventData.wifiConnectAttemptNeeded = true; WiFi_AP_Candidates.force_reload(); // Force reload of the credentials and found APs from the last scan resetWiFi(); AttemptWiFiConnect(); } } - } + } #ifndef BUILD_NO_DEBUG else { addLog(LOG_LEVEL_INFO, F("Skip saving SecuritySettings, not changed")); } -#endif +#endif // ifndef BUILD_NO_DEBUG // FIXME TD-er: How to check if these have changed? if (forFactoryReset) { @@ -655,13 +705,16 @@ String SaveSecuritySettings(bool forFactoryReset) { } ExtendedControllerCredentials.save(); - if (!forFactoryReset) + + if (!forFactoryReset) { afterloadSettings(); + } return err; } void afterloadSettings() { ExtraTaskSettings.clear(); // make sure these will not contain old settings. + if ((Settings.Version != VERSION) || (Settings.PID != ESP_PROJECT_PID)) { // Not valid settings, so do not continue return; @@ -670,7 +723,9 @@ void afterloadSettings() { // Load ResetFactoryDefaultPreference from provisioning.dat if available. // FIXME TD-er: Must actually move content of Provisioning.dat to NVS and then delete file uint32_t pref_temp = Settings.ResetFactoryDefaultPreference; + #ifdef ESP32 + if (pref_temp == 0) { if (ResetFactoryDefaultPreference.getPreference() == 0) { // Try loading from NVS @@ -679,25 +734,30 @@ void afterloadSettings() { pref_temp = ResetFactoryDefaultPreference.getPreference(); } } - #endif + #endif // ifdef ESP32 #if FEATURE_CUSTOM_PROVISIONING + if (fileExists(getFileName(FileType::PROVISIONING_DAT))) { MakeProvisioningSettings(ProvisioningSettings); + if (ProvisioningSettings.get()) { loadProvisioningSettings(*ProvisioningSettings); + if (ProvisioningSettings->matchingFlashSize()) { - if (pref_temp == 0 && ProvisioningSettings->ResetFactoryDefaultPreference.getPreference() != 0) + if ((pref_temp == 0) && (ProvisioningSettings->ResetFactoryDefaultPreference.getPreference() != 0)) { pref_temp = ProvisioningSettings->ResetFactoryDefaultPreference.getPreference(); + } } } } - #endif + #endif // if FEATURE_CUSTOM_PROVISIONING // TODO TD-er: Try to get the information from more locations to make it more persistent // Maybe EEPROM location? ResetFactoryDefaultPreference_struct pref(pref_temp); + if (modelMatchingFlashSize(pref.getDeviceModel())) { ResetFactoryDefaultPreference = pref_temp; } @@ -705,7 +765,7 @@ void afterloadSettings() { Scheduler.setEcoMode(Settings.EcoPowerMode()); #ifdef ESP32 setCpuFrequencyMhz(Settings.EcoPowerMode() ? getCPU_MinFreqMHz() : getCPU_MaxFreqMHz()); - #endif + #endif // ifdef ESP32 if (!Settings.UseRules) { eventQueue.clear(); @@ -721,15 +781,19 @@ String LoadSettings() clearAllButTaskCaches(); #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("LoadSettings")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER uint8_t oldSettingsChecksum[16] = { 0 }; memcpy(oldSettingsChecksum, Settings.md5, 16); - String err; + String err; - err = LoadFromFile(SettingsType::getSettingsFileName(SettingsType::Enum::BasicSettings_Type).c_str(), 0, reinterpret_cast(&Settings), sizeof(SettingsStruct)); + err = + LoadFromFile(SettingsType::getSettingsFileName(SettingsType::Enum::BasicSettings_Type).c_str(), + 0, + reinterpret_cast(&Settings), + sizeof(SettingsStruct)); if (memcmp(oldSettingsChecksum, Settings.md5, 16) != 0) { // File has changed, so need to flush all task caches. @@ -741,22 +805,27 @@ String LoadSettings() } if (!BuildFixes()) { - #ifndef BUILD_NO_DEBUG + if (COMPUTE_STRUCT_CHECKSUM(SettingsStruct, Settings)) { - addLog(LOG_LEVEL_INFO, concat(F("CRC : Settings CRC"), F("...OK"))); - } else{ + addLog(LOG_LEVEL_INFO, concat(F("CRC : Settings CRC"), F("...OK"))); + } else { addLog(LOG_LEVEL_ERROR, concat(F("CRC : Settings CRC"), F("...FAIL"))); } - #endif + #endif // ifndef BUILD_NO_DEBUG } Settings.validate(); initSerial(); - err = LoadFromFile(SettingsType::getSettingsFileName(SettingsType::Enum::SecuritySettings_Type).c_str(), 0, reinterpret_cast(&SecuritySettings), sizeof(SecurityStruct)); + err = + LoadFromFile(SettingsType::getSettingsFileName(SettingsType::Enum::SecuritySettings_Type).c_str(), + 0, + reinterpret_cast(&SecuritySettings), + sizeof(SecurityStruct)); #ifndef BUILD_NO_DEBUG + if (SecuritySettings.checksumMatch()) { addLog(LOG_LEVEL_INFO, concat(F("CRC : SecuritySettings CRC"), F("...OK "))); @@ -767,7 +836,7 @@ String LoadSettings() else { addLog(LOG_LEVEL_ERROR, concat(F("CRC : SecuritySettings CRC"), F("...FAIL"))); } -#endif +#endif // ifndef BUILD_NO_DEBUG ExtendedControllerCredentials.load(); @@ -778,8 +847,6 @@ String LoadSettings() return err; } - - /********************************************************************************************\ Disable Plugin, based on bootFailedCount \*********************************************************************************************/ @@ -801,16 +868,16 @@ uint8_t disablePlugin(uint8_t bootFailedCount) { uint8_t disableAllPlugins(uint8_t bootFailedCount) { if (bootFailedCount > 0) { --bootFailedCount; + for (taskIndex_t i = 0; i < TASKS_MAX; ++i) { - // Disable temporarily as unit crashed - // FIXME TD-er: Should this be stored? - Settings.TaskDeviceEnabled[i] = false; + // Disable temporarily as unit crashed + // FIXME TD-er: Should this be stored? + Settings.TaskDeviceEnabled[i] = false; } } return bootFailedCount; } - /********************************************************************************************\ Disable Controller, based on bootFailedCount \*********************************************************************************************/ @@ -830,6 +897,7 @@ uint8_t disableController(uint8_t bootFailedCount) { uint8_t disableAllControllers(uint8_t bootFailedCount) { if (bootFailedCount > 0) { --bootFailedCount; + for (controllerIndex_t i = 0; i < CONTROLLER_MAX; ++i) { Settings.ControllerEnabled[i] = false; } @@ -837,7 +905,6 @@ uint8_t disableAllControllers(uint8_t bootFailedCount) { return bootFailedCount; } - /********************************************************************************************\ Disable Notification, based on bootFailedCount \*********************************************************************************************/ @@ -858,13 +925,15 @@ uint8_t disableNotification(uint8_t bootFailedCount) { uint8_t disableAllNotifications(uint8_t bootFailedCount) { if (bootFailedCount > 0) { --bootFailedCount; + for (uint8_t i = 0; i < NOTIFICATION_MAX; ++i) { - Settings.NotificationEnabled[i] = false; + Settings.NotificationEnabled[i] = false; } } return bootFailedCount; } -#endif + +#endif // if FEATURE_NOTIFIER /********************************************************************************************\ Disable Rules, based on bootFailedCount @@ -877,7 +946,6 @@ uint8_t disableRules(uint8_t bootFailedCount) { return bootFailedCount; } - bool getAndLogSettingsParameters(bool read, SettingsType::Enum settingsType, int index, int& offset, int& max_size) { #ifndef BUILD_NO_DEBUG @@ -891,21 +959,26 @@ bool getAndLogSettingsParameters(bool read, SettingsType::Enum settingsType, int return SettingsType::getSettingsParameters(settingsType, index, offset, max_size); } - /********************************************************************************************\ Load array of Strings from Custom settings Use maxStringLength = 0 to optimize for size (strings will be concatenated) \*********************************************************************************************/ -String LoadStringArray(SettingsType::Enum settingsType, int index, String strings[], uint16_t nrStrings, uint16_t maxStringLength, uint32_t offset_in_block) +String LoadStringArray(SettingsType::Enum settingsType, + int index, + String strings[], + uint16_t nrStrings, + uint16_t maxStringLength, + uint32_t offset_in_block) { int offset, max_size; + if (!SettingsType::getSettingsParameters(settingsType, index, offset, max_size)) { #ifndef BUILD_NO_DEBUG return F("Invalid index for custom settings"); - #else + #else // ifndef BUILD_NO_DEBUG return F("Save error"); - #endif + #endif // ifndef BUILD_NO_DEBUG } const uint32_t bufferSize = 128; @@ -913,7 +986,7 @@ String LoadStringArray(SettingsType::Enum settingsType, int index, String string // FIXME TD-er: For now stack allocated, may need to be heap allocated? if (maxStringLength >= bufferSize) { return F("Max 128 chars allowed"); } - char buffer[bufferSize] = {0}; + char buffer[bufferSize] = { 0 }; String result; uint32_t readPos = offset_in_block; @@ -921,16 +994,16 @@ String LoadStringArray(SettingsType::Enum settingsType, int index, String string uint32_t stringCount = 0; const uint16_t estimatedStringSize = maxStringLength > 0 ? maxStringLength : bufferSize; - String tmpString; + String tmpString; tmpString.reserve(estimatedStringSize); { while (stringCount < nrStrings && static_cast(readPos) < max_size) { const uint32_t readSize = std::min(bufferSize, max_size - readPos); result += LoadFromFile(settingsType, - index, - reinterpret_cast(&buffer), - readSize, - readPos); + index, + reinterpret_cast(&buffer), + readSize, + readPos); for (uint32_t i = 0; i < readSize && stringCount < nrStrings; ++i) { const uint32_t curPos = readPos + i; @@ -967,25 +1040,32 @@ String LoadStringArray(SettingsType::Enum settingsType, int index, String string Save array of Strings from Custom settings Use maxStringLength = 0 to optimize for size (strings will be concatenated) \*********************************************************************************************/ -String SaveStringArray(SettingsType::Enum settingsType, int index, const String strings[], uint16_t nrStrings, uint16_t maxStringLength, uint32_t posInBlock) +String SaveStringArray(SettingsType::Enum settingsType, + int index, + const String strings[], + uint16_t nrStrings, + uint16_t maxStringLength, + uint32_t posInBlock) { // FIXME TD-er: Must add some check to see if the existing data has changed before saving. int offset, max_size; + if (!SettingsType::getSettingsParameters(settingsType, index, offset, max_size)) { #ifndef BUILD_NO_DEBUG return F("Invalid index for custom settings"); - #else + #else // ifndef BUILD_NO_DEBUG return F("Save error"); - #endif + #endif // ifndef BUILD_NO_DEBUG } #ifdef ESP8266 uint16_t bufferSize = 256; - #endif + #endif // ifdef ESP8266 #ifdef ESP32 uint16_t bufferSize = 1024; - #endif + #endif // ifdef ESP32 + if (bufferSize > max_size) { bufferSize = max_size; } @@ -1015,7 +1095,8 @@ String SaveStringArray(SettingsType::Enum settingsType, int index, const String } int bufpos = 0; - for ( ; bufpos < bufferSize && stringCount < nrStrings; ++bufpos) { + + for (; bufpos < bufferSize && stringCount < nrStrings; ++bufpos) { if (stringReadPos == 0) { // We're at the start of a string curStringLength = strings[stringCount].length(); @@ -1057,6 +1138,7 @@ String SaveStringArray(SettingsType::Enum settingsType, int index, const String } #if FEATURE_EXTENDED_CUSTOM_SETTINGS + if ((SettingsType::Enum::CustomTaskSettings_Type == settingsType) && ((writePos - posInBlock) <= DAT_TASKS_CUSTOM_SIZE)) { // Not needed, so can be deleted DeleteExtendedCustomTaskSettingsFile(settingsType, index); @@ -1069,8 +1151,6 @@ String SaveStringArray(SettingsType::Enum settingsType, int index, const String return result; } - - /********************************************************************************************\ Save Task settings to file system \*********************************************************************************************/ @@ -1078,14 +1158,14 @@ String SaveTaskSettings(taskIndex_t TaskIndex) { #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("SaveTaskSettings")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER if (ExtraTaskSettings.TaskIndex != TaskIndex) { #ifndef BUILD_NO_DEBUG return F("SaveTaskSettings taskIndex does not match"); - #else + #else // ifndef BUILD_NO_DEBUG return F("Save error"); - #endif + #endif // ifndef BUILD_NO_DEBUG } START_TIMER @@ -1094,32 +1174,34 @@ String SaveTaskSettings(taskIndex_t TaskIndex) if (!Cache.matchChecksumExtraTaskSettings(TaskIndex, ExtraTaskSettings.computeChecksum())) { // Clear task device value names before saving, will generate again when loading them later. ExtraTaskSettings.clearDefaultTaskDeviceValueNames(); - ExtraTaskSettings.validate(); // Validate before saving will reduce nr of saves as it is more likely to not have changed the next time it will be saved. + ExtraTaskSettings.validate(); // Validate before saving will reduce nr of saves as it is more likely to not have changed the next time + // it will be saved. // Call to validate() may have changed the content, so re-compute the checksum. - // This is how it is now stored, so we can now also update the + // This is how it is now stored, so we can now also update the // ExtraTaskSettings cache. This may prevent a reload. Cache.updateExtraTaskSettingsCache_afterLoad_Save(); err = SaveToFile(SettingsType::Enum::TaskSettings_Type, - TaskIndex, - reinterpret_cast(&ExtraTaskSettings), - sizeof(struct ExtraTaskSettingsStruct)); + TaskIndex, + reinterpret_cast(&ExtraTaskSettings), + sizeof(struct ExtraTaskSettingsStruct)); #if !defined(PLUGIN_BUILD_MINIMAL_OTA) && !defined(ESP8266_1M) + if (err.isEmpty()) { err = checkTaskSettings(TaskIndex); } -#endif +#endif // if !defined(PLUGIN_BUILD_MINIMAL_OTA) && !defined(ESP8266_1M) + // FIXME TD-er: Is this still needed as it is also cleared on PLUGIN_INIT and PLUGIN_EXIT? UserVar.clear_computed(ExtraTaskSettings.TaskIndex); - } + } #ifndef LIMIT_BUILD_SIZE else { addLog(LOG_LEVEL_INFO, F("Skip saving task settings, not changed")); - } -#endif +#endif // ifndef LIMIT_BUILD_SIZE STOP_TIMER(SAVE_TASK_SETTINGS); return err; } @@ -1132,6 +1214,7 @@ String LoadTaskSettings(taskIndex_t TaskIndex) if (ExtraTaskSettings.TaskIndex == TaskIndex) { return EMPTY_STRING; // already loaded } + if (!validTaskIndex(TaskIndex)) { return EMPTY_STRING; // Un-initialized task index. } @@ -1139,24 +1222,26 @@ String LoadTaskSettings(taskIndex_t TaskIndex) ExtraTaskSettings.clear(); const deviceIndex_t DeviceIndex = getDeviceIndex_from_TaskIndex(TaskIndex); + if (!validDeviceIndex(DeviceIndex)) { // No need to load from storage, as there is no plugin assigned to this task. ExtraTaskSettings.TaskIndex = TaskIndex; // Needed when an empty task was requested // FIXME TD-er: Do we need to keep a cache of an empty task? - // Maybe better to do this? - Cache.clearTaskCache(TaskIndex); -// Cache.updateExtraTaskSettingsCache_afterLoad_Save(); + // Maybe better to do this? + Cache.clearTaskCache(TaskIndex); + + // Cache.updateExtraTaskSettingsCache_afterLoad_Save(); return EMPTY_STRING; } #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("LoadTaskSettings")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER const String result = LoadFromFile( - SettingsType::Enum::TaskSettings_Type, - TaskIndex, - reinterpret_cast(&ExtraTaskSettings), + SettingsType::Enum::TaskSettings_Type, + TaskIndex, + reinterpret_cast(&ExtraTaskSettings), sizeof(struct ExtraTaskSettingsStruct)); // After loading, some settings may need patching. @@ -1166,10 +1251,10 @@ String LoadTaskSettings(taskIndex_t TaskIndex) // Nr of decimals cannot be configured, so set them to 0 just to be sure. for (uint8_t i = 0; i < VARS_PER_TASK; ++i) { ExtraTaskSettings.TaskDeviceValueDecimals[i] = 0; - } + } } loadDefaultTaskValueNames_ifEmpty(TaskIndex); - + ExtraTaskSettings.validate(); Cache.updateExtraTaskSettingsCache_afterLoad_Save(); STOP_TIMER(LOAD_TASK_SETTINGS); @@ -1183,7 +1268,7 @@ bool _CDN_url_loaded = false; String get_CDN_url_custom() { if (!_CDN_url_loaded) { - String strings[] = {EMPTY_STRING}; + String strings[] = { EMPTY_STRING }; LoadStringArray( SettingsType::Enum::CdnSettings_Type, 0, @@ -1194,9 +1279,10 @@ String get_CDN_url_custom() { return _CDN_url_cache; } -void set_CDN_url_custom(const String &url) { +void set_CDN_url_custom(const String& url) { _CDN_url_cache = url; _CDN_url_cache.trim(); + if (!_CDN_url_cache.isEmpty() && !_CDN_url_cache.endsWith(F("/"))) { _CDN_url_cache.concat('/'); } @@ -1219,6 +1305,7 @@ void set_CDN_url_custom(const String &url) { SettingsType::Enum::CdnSettings_Type, 0, strings, NR_ELEMENTS(strings), 255, 0); } + #endif // if FEATURE_ALTERNATIVE_CDN_URL /********************************************************************************************\ @@ -1228,7 +1315,7 @@ String SaveCustomTaskSettings(taskIndex_t TaskIndex, const uint8_t *memAddress, { #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("SaveCustomTaskSettings")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER return SaveToFile(SettingsType::Enum::CustomTaskSettings_Type, TaskIndex, memAddress, datasize, posInBlock); } @@ -1240,7 +1327,7 @@ String SaveCustomTaskSettings(taskIndex_t TaskIndex, String strings[], uint16_t { #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("SaveCustomTaskSettings")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER return SaveStringArray( SettingsType::Enum::CustomTaskSettings_Type, TaskIndex, strings, nrStrings, maxStringLength, posInBlock); @@ -1267,7 +1354,7 @@ String LoadCustomTaskSettings(taskIndex_t TaskIndex, uint8_t *memAddress, int da START_TIMER; #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("LoadCustomTaskSettings")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER String result = LoadFromFile(SettingsType::Enum::CustomTaskSettings_Type, TaskIndex, memAddress, datasize, offset_in_block); STOP_TIMER(LOAD_CUSTOM_TASK_STATS); return result; @@ -1282,10 +1369,10 @@ String LoadCustomTaskSettings(taskIndex_t TaskIndex, String strings[], uint16_t START_TIMER; #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("LoadCustomTaskSettings")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER String result = LoadStringArray(SettingsType::Enum::CustomTaskSettings_Type, - TaskIndex, - strings, nrStrings, maxStringLength, offset_in_block); + TaskIndex, + strings, nrStrings, maxStringLength, offset_in_block); STOP_TIMER(LOAD_CUSTOM_TASK_STATS); return result; } @@ -1297,7 +1384,7 @@ String SaveControllerSettings(controllerIndex_t ControllerIndex, ControllerSetti { #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("SaveControllerSettings")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER START_TIMER; @@ -1308,16 +1395,16 @@ String SaveControllerSettings(controllerIndex_t ControllerIndex, ControllerSetti if (checksum == (Cache.controllerSettings_checksums[ControllerIndex])) { #ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_INFO, concat(F("Skip saving ControllerSettings: "), checksum.toString())); -#endif +#endif // ifndef BUILD_NO_DEBUG return EMPTY_STRING; } const String res = SaveToFile(SettingsType::Enum::ControllerSettings_Type, ControllerIndex, - reinterpret_cast(&controller_settings), sizeof(controller_settings)); + reinterpret_cast(&controller_settings), sizeof(controller_settings)); Cache.controllerSettings_checksums[ControllerIndex] = checksum; #ifdef ESP32 Cache.setControllerSettings(ControllerIndex, controller_settings); - #endif + #endif // ifdef ESP32 STOP_TIMER(SAVE_CONTROLLER_SETTINGS); return res; @@ -1329,14 +1416,15 @@ String SaveControllerSettings(controllerIndex_t ControllerIndex, ControllerSetti String LoadControllerSettings(controllerIndex_t ControllerIndex, ControllerSettingsStruct& controller_settings) { #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("LoadControllerSettings")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER START_TIMER #ifdef ESP32 + if (Cache.getControllerSettings(ControllerIndex, controller_settings)) { STOP_TIMER(LOAD_CONTROLLER_SETTINGS_C); return EMPTY_STRING; } - #endif + #endif // ifdef ESP32 String result = LoadFromFile(SettingsType::Enum::ControllerSettings_Type, ControllerIndex, reinterpret_cast(&controller_settings), sizeof(controller_settings)); @@ -1346,7 +1434,7 @@ String LoadControllerSettings(controllerIndex_t ControllerIndex, ControllerSetti Cache.controllerSettings_checksums[ControllerIndex] = controller_settings.computeChecksum(); #ifdef ESP32 Cache.setControllerSettings(ControllerIndex, controller_settings); - #endif + #endif // ifdef ESP32 STOP_TIMER(LOAD_CONTROLLER_SETTINGS); return result; } @@ -1358,7 +1446,7 @@ String ClearCustomControllerSettings(controllerIndex_t ControllerIndex) { #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("ClearCustomControllerSettings")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER // addLog(LOG_LEVEL_DEBUG, F("Clearing custom controller settings")); return ClearInFile(SettingsType::Enum::CustomControllerSettings_Type, ControllerIndex); @@ -1371,7 +1459,7 @@ String SaveCustomControllerSettings(controllerIndex_t ControllerIndex, const uin { #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("SaveCustomControllerSettings")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER return SaveToFile(SettingsType::Enum::CustomControllerSettings_Type, ControllerIndex, memAddress, datasize); } @@ -1382,25 +1470,27 @@ String LoadCustomControllerSettings(controllerIndex_t ControllerIndex, uint8_t * { #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("LoadCustomControllerSettings")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER return LoadFromFile(SettingsType::Enum::CustomControllerSettings_Type, ControllerIndex, memAddress, datasize); } - #if FEATURE_CUSTOM_PROVISIONING + /********************************************************************************************\ Save Provisioning Settings \*********************************************************************************************/ String saveProvisioningSettings(ProvisioningStruct& ProvisioningSettings) { - String err; + String err; ProvisioningSettings.validate(); memcpy(ProvisioningSettings.ProgmemMd5, CRCValues.runTimeMD5, 16); + if (!COMPUTE_STRUCT_CHECKSUM_UPDATE(ProvisioningStruct, ProvisioningSettings)) { // Settings have changed, save to file. - err = SaveToFile_trunc(getFileName(FileType::PROVISIONING_DAT, 0).c_str(), 0, (uint8_t *)&ProvisioningSettings, sizeof(ProvisioningStruct)); + err = + SaveToFile_trunc(getFileName(FileType::PROVISIONING_DAT, 0).c_str(), 0, (uint8_t *)&ProvisioningSettings, sizeof(ProvisioningStruct)); } return err; } @@ -1410,8 +1500,13 @@ String saveProvisioningSettings(ProvisioningStruct& ProvisioningSettings) \*********************************************************************************************/ String loadProvisioningSettings(ProvisioningStruct& ProvisioningSettings) { - String err = LoadFromFile(getFileName(FileType::PROVISIONING_DAT, 0).c_str(), 0, (uint8_t *)&ProvisioningSettings, sizeof(ProvisioningStruct)); -#ifndef BUILD_NO_DEBUG + String err = LoadFromFile(getFileName(FileType::PROVISIONING_DAT, 0).c_str(), + 0, + (uint8_t *)&ProvisioningSettings, + sizeof(ProvisioningStruct)); + +# ifndef BUILD_NO_DEBUG + if (COMPUTE_STRUCT_CHECKSUM(ProvisioningStruct, ProvisioningSettings)) { addLog(LOG_LEVEL_INFO, F("CRC : ProvisioningSettings CRC ...OK ")); @@ -1423,22 +1518,23 @@ String loadProvisioningSettings(ProvisioningStruct& ProvisioningSettings) else { addLog(LOG_LEVEL_ERROR, F("CRC : ProvisioningSettings CRC ...FAIL")); } -#endif +# endif // ifndef BUILD_NO_DEBUG ProvisioningSettings.validate(); return err; } -#endif +#endif // if FEATURE_CUSTOM_PROVISIONING #if FEATURE_NOTIFIER + /********************************************************************************************\ Save Controller settings to file system \*********************************************************************************************/ String SaveNotificationSettings(int NotificationIndex, const uint8_t *memAddress, int datasize) { - #ifndef BUILD_NO_RAM_TRACKER + # ifndef BUILD_NO_RAM_TRACKER checkRAM(F("SaveNotificationSettings")); - #endif + # endif // ifndef BUILD_NO_RAM_TRACKER return SaveToFile(SettingsType::Enum::NotificationSettings_Type, NotificationIndex, memAddress, datasize); } @@ -1447,12 +1543,14 @@ String SaveNotificationSettings(int NotificationIndex, const uint8_t *memAddress \*********************************************************************************************/ String LoadNotificationSettings(int NotificationIndex, uint8_t *memAddress, int datasize) { - #ifndef BUILD_NO_RAM_TRACKER + # ifndef BUILD_NO_RAM_TRACKER checkRAM(F("LoadNotificationSettings")); - #endif + # endif // ifndef BUILD_NO_RAM_TRACKER return LoadFromFile(SettingsType::Enum::NotificationSettings_Type, NotificationIndex, memAddress, datasize); } -#endif + +#endif // if FEATURE_NOTIFIER + /********************************************************************************************\ Init a file with zeros on file system \*********************************************************************************************/ @@ -1460,7 +1558,7 @@ String InitFile(const String& fname, int datasize) { #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("InitFile")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER FLASH_GUARD(); fs::File f = tryOpenFile(fname, "w"); @@ -1486,7 +1584,7 @@ String InitFile(SettingsType::Enum settingsType) String InitFile(SettingsType::SettingsFileEnum file_type) { - return InitFile(SettingsType::getSettingsFileName(file_type), + return InitFile(SettingsType::getSettingsFileName(file_type), SettingsType::getInitFileSize(file_type)); } @@ -1507,36 +1605,37 @@ String SaveToFile_trunc(const char *fname, int index, const uint8_t *memAddress, String doSaveToFile(const char *fname, int index, const uint8_t *memAddress, int datasize, const char *mode) { #ifndef BUILD_NO_DEBUG -#ifndef ESP32 +# ifndef ESP32 if (allocatedOnStack(memAddress)) { addLog(LOG_LEVEL_ERROR, strformat(F("SaveToFile: %s ERROR, Data allocated on stack"), fname)); // return log; // FIXME TD-er: Should this be considered a breaking error? } -#endif // ifndef ESP32 -#endif +# endif // ifndef ESP32 +#endif // ifndef BUILD_NO_DEBUG if (index < 0) { #ifndef BUILD_NO_DEBUG const String log = strformat(F("SaveToFile: %s ERROR, invalid position in file"), fname); - #else + #else // ifndef BUILD_NO_DEBUG const String log = F("Save error"); - #endif + #endif // ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_ERROR, log); return log; } START_TIMER; #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("SaveToFile")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER FLASH_GUARD(); - + #ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_INFO)) { addLog(LOG_LEVEL_INFO, concat(F("SaveToFile: free stack: "), getCurrentFreeStack())); } - #endif + #endif // ifndef BUILD_NO_DEBUG delay(1); unsigned long timer = millis() + 50; fs::File f = tryOpenFile(fname, mode); @@ -1567,26 +1666,28 @@ String doSaveToFile(const char *fname, int index, const uint8_t *memAddress, int } f.close(); #ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_INFO)) { addLogMove(LOG_LEVEL_INFO, strformat(F("FILE : Saved %s offset: %d size: %d"), fname, index, datasize)); } - #endif + #endif // ifndef BUILD_NO_DEBUG } else { #ifndef BUILD_NO_DEBUG const String log = strformat(F("SaveToFile: %s ERROR, Cannot save to file"), fname); - #else + #else // ifndef BUILD_NO_DEBUG const String log = F("Save error"); - #endif + #endif // ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_ERROR, log); return log; } STOP_TIMER(SAVEFILE_STATS); #ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_INFO)) { addLogMove(LOG_LEVEL_INFO, concat(F("SaveToFile: free stack after: "), getCurrentFreeStack())); } - #endif + #endif // ifndef BUILD_NO_DEBUG // OK return EMPTY_STRING; @@ -1600,9 +1701,9 @@ String ClearInFile(const char *fname, int index, int datasize) if (index < 0) { #ifndef BUILD_NO_DEBUG const String log = strformat(F("ClearInFile: %s ERROR, invalid position in file"), fname); - #else + #else // ifndef BUILD_NO_DEBUG const String log = F("Save error"); - #endif + #endif // ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_ERROR, log); return log; @@ -1610,7 +1711,7 @@ String ClearInFile(const char *fname, int index, int datasize) #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("ClearInFile")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER FLASH_GUARD(); fs::File f = tryOpenFile(fname, "r+"); @@ -1628,9 +1729,9 @@ String ClearInFile(const char *fname, int index, int datasize) } else { #ifndef BUILD_NO_DEBUG const String log = strformat(F("ClearInFile: %s ERROR, Cannot save to file"), fname); - #else + #else // ifndef BUILD_NO_DEBUG const String log = F("Save error"); - #endif + #endif // ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_ERROR, log); return log; } @@ -1647,9 +1748,9 @@ String LoadFromFile(const char *fname, int offset, uint8_t *memAddress, int data if (offset < 0) { #ifndef BUILD_NO_DEBUG const String log = strformat(F("LoadFromFile: %s ERROR, invalid position in file"), fname); - #else + #else // ifndef BUILD_NO_DEBUG const String log = F("Load error"); - #endif + #endif // ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_ERROR, log); return log; } @@ -1657,14 +1758,15 @@ String LoadFromFile(const char *fname, int offset, uint8_t *memAddress, int data START_TIMER; #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("LoadFromFile")); - #endif - + #endif // ifndef BUILD_NO_RAM_TRACKER + fs::File f = tryOpenFile(fname, "r"); - SPIFFS_CHECK(f, fname); + SPIFFS_CHECK(f, fname); const int fileSize = f.size(); + if (fileSize > offset) { - SPIFFS_CHECK(f.seek(offset, fs::SeekSet), fname); - + SPIFFS_CHECK(f.seek(offset, fs::SeekSet), fname); + if (fileSize < (offset + datasize)) { const int newdatasize = datasize + offset - fileSize; @@ -1691,24 +1793,26 @@ String getSettingsFileIndexRangeError(bool read, SettingsType::Enum settingsType return concat(F("Unknown settingsType: "), static_cast(settingsType)); } String error = read ? F("Load") : F("Save"); + #ifndef BUILD_NO_DEBUG error += SettingsType::getSettingsTypeString(settingsType); error += concat(F(" index out of range: "), index); - #else + #else // ifndef BUILD_NO_DEBUG error += F(" error"); - #endif + #endif // ifndef BUILD_NO_DEBUG return error; } String getSettingsFileDatasizeError(bool read, SettingsType::Enum settingsType, int index, int datasize, int max_size) { String error = read ? F("Load") : F("Save"); + #ifndef BUILD_NO_DEBUG error += SettingsType::getSettingsTypeString(settingsType); error += strformat(F("(%d) datasize(%d) > max_size(%d)"), index, datasize, max_size); - #else + #else // ifndef BUILD_NO_DEBUG error += F(" error"); - #endif - + #endif // ifndef BUILD_NO_DEBUG + return error; } @@ -1757,7 +1861,7 @@ String LoadFromFile(SettingsType::Enum settingsType, int index, uint8_t *memAddr #if FEATURE_EXTENDED_CUSTOM_SETTINGS , taskIndex #endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS - ); + ); return LoadFromFile(fname.c_str(), (offset + offset_in_block), memAddress + dataOffset, datasize); } @@ -1776,7 +1880,7 @@ String SaveToFile(SettingsType::Enum settingsType, int index, const uint8_t *mem int dataOffset = 0; #if FEATURE_EXTENDED_CUSTOM_SETTINGS - int taskIndex = INVALID_TASK_INDEX; // Use base filename + int taskIndex = INVALID_TASK_INDEX; // Use base filename if ((SettingsType::Enum::CustomTaskSettings_Type == settingsType) && (posInBlock + datasize > (DAT_TASKS_CUSTOM_SIZE))) { // max_size already handled above @@ -1785,8 +1889,9 @@ String SaveToFile(SettingsType::Enum settingsType, int index, const uint8_t *mem dataOffset = (DAT_TASKS_CUSTOM_SIZE - posInBlock); // Bytes to keep 'local' # ifndef BUILD_NO_DEBUG const String styp = SettingsType::getSettingsTypeString(settingsType); + if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLog(LOG_LEVEL_INFO, strformat(F("ExtraSaveToFile: %s file: %s size: %d pos: %d"), + addLog(LOG_LEVEL_INFO, strformat(F("ExtraSaveToFile: %s file: %s size: %d pos: %d"), styp.c_str(), fname.c_str(), dataOffset, posInBlock)); } # endif // ifndef BUILD_NO_DEBUG @@ -1808,24 +1913,27 @@ String SaveToFile(SettingsType::Enum settingsType, int index, const uint8_t *mem #if FEATURE_EXTENDED_CUSTOM_SETTINGS , taskIndex #endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS - ); + ); + if (!fileExists(fname)) { #if FEATURE_EXTENDED_CUSTOM_SETTINGS + if (!validTaskIndex(taskIndex)) { #endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS - InitFile(settingsType); + InitFile(settingsType); #if FEATURE_EXTENDED_CUSTOM_SETTINGS - } else { - InitFile(fname, DAT_TASKS_CUSTOM_EXTENSION_SIZE); // Initialize task-specific file - } + } else { + InitFile(fname, DAT_TASKS_CUSTOM_EXTENSION_SIZE); // Initialize task-specific file + } #endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS } #ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_INFO)) { addLog(LOG_LEVEL_INFO, concat(F("SaveToFile: "), SettingsType::getSettingsTypeString(settingsType)) + strformat(F(" file: %s task: %d"), fname.c_str(), index + 1)); } - #endif + #endif // ifndef BUILD_NO_DEBUG return SaveToFile(fname.c_str(), offset + posInBlock, memAddress + dataOffset, datasize); } @@ -1837,6 +1945,7 @@ String ClearInFile(SettingsType::Enum settingsType, int index) { return getSettingsFileIndexRangeError(read, settingsType, index); } #if FEATURE_EXTENDED_CUSTOM_SETTINGS + if (SettingsType::Enum::CustomTaskSettings_Type == settingsType) { max_size = DAT_TASKS_CUSTOM_SIZE; // Don't also wipe the external size inside the config.dat file... DeleteExtendedCustomTaskSettingsFile(settingsType, index); @@ -1855,6 +1964,7 @@ bool DeleteExtendedCustomTaskSettingsFile(SettingsType::Enum settingsType, int i if (fileExists(fname)) { const bool deleted = tryDeleteFile(fname); // Don't need the extension file anymore, so delete it # ifndef BUILD_NO_DEBUG + if (loglevelActiveFor(LOG_LEVEL_INFO)) { addLog(LOG_LEVEL_INFO, concat(F("CustomTaskSettings: Removing no longer needed file: "), fname)); } @@ -1864,7 +1974,9 @@ bool DeleteExtendedCustomTaskSettingsFile(SettingsType::Enum settingsType, int i } return false; } + #endif // if FEATURE_EXTENDED_CUSTOM_SETTINGS + /********************************************************************************************\ Check file system area settings \*********************************************************************************************/ @@ -1872,7 +1984,7 @@ int SpiffsSectors() { #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("SpiffsSectors")); - #endif + #endif // ifndef BUILD_NO_RAM_TRACKER #if defined(ESP8266) # ifdef CORE_POST_2_6_0 uint32_t _sectorStart = ((uint32_t)&_FS_start - 0x40200000) / SPI_FLASH_SEC_SIZE; @@ -1905,6 +2017,7 @@ size_t SpiffsUsedBytes() { size_t SpiffsTotalBytes() { static size_t result = 1; // Do not output 0, this may be used in divisions. + if (result == 1) { #ifdef ESP32 result = ESPEASY_FS.totalBytes(); @@ -1920,9 +2033,10 @@ size_t SpiffsTotalBytes() { size_t SpiffsBlocksize() { static size_t result = 1; + if (result == 1) { #ifdef ESP32 - result = 8192; // Just assume 8k, since we cannot query it + result = 8192; // Just assume 8k, since we cannot query it #endif // ifdef ESP32 #ifdef ESP8266 fs::FSInfo fs_info; @@ -1935,9 +2049,10 @@ size_t SpiffsBlocksize() { size_t SpiffsPagesize() { static size_t result = 1; + if (result == 1) { #ifdef ESP32 - result = 256; // Just assume 256, since we cannot query it + result = 256; // Just assume 256, since we cannot query it #endif // ifdef ESP32 #ifdef ESP8266 fs::FSInfo fs_info; @@ -1949,7 +2064,7 @@ size_t SpiffsPagesize() { } size_t SpiffsFreeSpace() { - int freeSpace = SpiffsTotalBytes() - SpiffsUsedBytes(); + int freeSpace = SpiffsTotalBytes() - SpiffsUsedBytes(); const size_t blocksize = SpiffsBlocksize(); if (freeSpace < static_cast(2 * blocksize)) { @@ -1965,6 +2080,7 @@ bool SpiffsFull() { } #if FEATURE_RTC_CACHE_STORAGE + /********************************************************************************************\ Handling cached data \*********************************************************************************************/ @@ -1972,16 +2088,16 @@ String createCacheFilename(unsigned int count) { String fname; fname.reserve(16); - #ifdef ESP32 + # ifdef ESP32 fname = '/'; - #endif // ifdef ESP32 + # endif // ifdef ESP32 fname += strformat(F("cache_%d.bin"), count); return fname; } // Match string with an integer between '_' and ".bin" int getCacheFileCountFromFilename(const String& fname) { - if (!isCacheFile(fname)) return -1; + if (!isCacheFile(fname)) { return -1; } int startpos = fname.indexOf('_'); if (startpos < 0) { return -1; } @@ -2008,7 +2124,7 @@ bool getCacheFileCounters(uint16_t& lowest, uint16_t& highest, size_t& filesizeH lowest = 65535; highest = 0; filesizeHighest = 0; -#ifdef ESP8266 +# ifdef ESP8266 fs::Dir dir = ESPEASY_FS.openDir(F("cache")); while (dir.next()) { @@ -2026,8 +2142,8 @@ bool getCacheFileCounters(uint16_t& lowest, uint16_t& highest, size_t& filesizeH } } } -#endif // ESP8266 -#ifdef ESP32 +# endif // ESP8266 +# ifdef ESP32 fs::File root = ESPEASY_FS.open(F("/")); fs::File file = root.openNextFile(); @@ -2035,6 +2151,7 @@ bool getCacheFileCounters(uint16_t& lowest, uint16_t& highest, size_t& filesizeH { if (!file.isDirectory()) { const String fname(file.name()); + if (fname.startsWith(F("/cache")) || fname.startsWith(F("cache"))) { int count = getCacheFileCountFromFilename(fname); @@ -2047,18 +2164,18 @@ bool getCacheFileCounters(uint16_t& lowest, uint16_t& highest, size_t& filesizeH highest = count; filesizeHighest = file.size(); } -#ifndef BUILD_NO_DEBUG +# ifndef BUILD_NO_DEBUG } else { if (loglevelActiveFor(LOG_LEVEL_INFO)) { addLog(LOG_LEVEL_INFO, concat(F("RTC : Cannot get count from: "), fname)); } -#endif +# endif // ifndef BUILD_NO_DEBUG } } } file = root.openNextFile(); } -#endif // ESP32 +# endif // ESP32 if (lowest <= highest) { return true; @@ -2067,7 +2184,8 @@ bool getCacheFileCounters(uint16_t& lowest, uint16_t& highest, size_t& filesizeH highest = 0; return false; } -#endif + +#endif // if FEATURE_RTC_CACHE_STORAGE /********************************************************************************************\ Get partition table information @@ -2102,12 +2220,12 @@ String getPartitionType(uint8_t pType, uint8_t pSubType) { case ESP_PARTITION_SUBTYPE_DATA_COREDUMP: return F("COREDUMP"); case ESP_PARTITION_SUBTYPE_DATA_ESPHTTPD: return F("ESPHTTPD"); case ESP_PARTITION_SUBTYPE_DATA_FAT: return F("FAT"); - case ESP_PARTITION_SUBTYPE_DATA_SPIFFS: - #ifdef USE_LITTLEFS + case ESP_PARTITION_SUBTYPE_DATA_SPIFFS: + # ifdef USE_LITTLEFS return F("LittleFS"); - #else + # else // ifdef USE_LITTLEFS return F("SPIFFS"); - #endif + # endif // ifdef USE_LITTLEFS default: break; } } @@ -2115,8 +2233,10 @@ String getPartitionType(uint8_t pType, uint8_t pSubType) { } String getPartitionTableHeader(const String& itemSep, const String& lineEnd) { + const char *itemSep_str = itemSep.c_str(); + return strformat(F("Address%sSize%sLabel%sPartition Type%sEncrypted%s"), - itemSep.c_str(), itemSep.c_str(), itemSep.c_str(), itemSep.c_str(), lineEnd.c_str()); + itemSep_str, itemSep_str, itemSep_str, itemSep_str, lineEnd.c_str()); } String getPartitionTable(uint8_t pType, const String& itemSep, const String& lineEnd) { @@ -2127,15 +2247,16 @@ String getPartitionTable(uint8_t pType, const String& itemSep, const String& lin if (_mypartiterator) { do { const esp_partition_t *_mypart = esp_partition_get(_mypartiterator); + const char *itemSep_str = itemSep.c_str(); result += strformat(F("%x%s%s%s%s%s%s%s%s%s"), _mypart->address, - itemSep.c_str(), - formatToHex_decimal(_mypart->size, 1024), - itemSep.c_str(), + itemSep_str, + formatToHex_decimal(_mypart->size, 1024).c_str(), + itemSep_str, _mypart->label, - itemSep.c_str(), + itemSep_str, getPartitionType(_mypart->type, _mypart->subtype).c_str(), - itemSep.c_str(), + itemSep_str, String(_mypart->encrypted ? F("Yes") : F("-")).c_str(), lineEnd.c_str()); } while ((_mypartiterator = esp_partition_next(_mypartiterator)) != nullptr); @@ -2155,7 +2276,7 @@ String downloadFileType(const String& url, const String& user, const String& pas } String filename = getFileName(filetype, filenr); - String fullUrl = joinUrlFilename(url, filename); + String fullUrl = joinUrlFilename(url, filename); String error; if (ResetFactoryDefaultPreference.deleteFirst()) { @@ -2169,6 +2290,7 @@ String downloadFileType(const String& url, const String& user, const String& pas } else { if (fileExists(filename)) { const String filename_bak = strformat(F("%s_bak"), filename.c_str()); + if (fileExists(filename_bak)) { if (!ResetFactoryDefaultPreference.delete_Bak_Files() || !tryDeleteFile(filename_bak)) { return F("Could not rename to _bak"); @@ -2176,7 +2298,7 @@ String downloadFileType(const String& url, const String& user, const String& pas } // Must download it to a tmp file. - const String tmpfile = strformat(F("%s_tmp"),filename.c_str()); + const String tmpfile = strformat(F("%s_tmp"), filename.c_str()); if (!downloadFile(fullUrl, tmpfile, user, pass, error)) { return error; @@ -2234,6 +2356,7 @@ String downloadFileType(FileType::Enum filetype, unsigned int filenr) } } String res = downloadFileType(url, user, pass, filetype, filenr); + clearAllCaches(); return res; }