diff --git a/tasmota/settings.ino b/tasmota/settings.ino index 9656623a5..64efab53c 100644 --- a/tasmota/settings.ino +++ b/tasmota/settings.ino @@ -486,6 +486,8 @@ void SettingsSave(uint8_t rotate) { * stop_flash_rotate 1 = Allow only eeprom flash slot use (SetOption12 1) */ #ifndef FIRMWARE_MINIMAL + XsnsCall(FUNC_SAVE_SETTINGS); + XdrvCall(FUNC_SAVE_SETTINGS); UpdateBackwardCompatibility(); if ((GetSettingsCrc32() != settings_crc32) || rotate) { if (1 == rotate) { // Use eeprom flash slot only and disable flash rotate from now on (upgrade) diff --git a/tasmota/tasmota.h b/tasmota/tasmota.h index 49b3789b1..77853258b 100644 --- a/tasmota/tasmota.h +++ b/tasmota/tasmota.h @@ -270,7 +270,7 @@ enum LightTypes { LT_BASIC, LT_PWM1, LT_PWM2, LT_PWM3, LT_PWM4, LT enum XsnsFunctions {FUNC_SETTINGS_OVERRIDE, FUNC_PIN_STATE, FUNC_MODULE_INIT, FUNC_PRE_INIT, FUNC_INIT, FUNC_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_100_MSECOND, FUNC_EVERY_200_MSECOND, FUNC_EVERY_250_MSECOND, FUNC_EVERY_SECOND, - FUNC_SAVE_AT_MIDNIGHT, FUNC_SAVE_BEFORE_RESTART, + FUNC_SAVE_SETTINGS, FUNC_SAVE_AT_MIDNIGHT, FUNC_SAVE_BEFORE_RESTART, FUNC_AFTER_TELEPERIOD, FUNC_JSON_APPEND, FUNC_WEB_SENSOR, FUNC_COMMAND, FUNC_COMMAND_SENSOR, FUNC_COMMAND_DRIVER, FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, FUNC_MQTT_DATA, FUNC_SET_POWER, FUNC_SET_DEVICE_POWER, FUNC_SHOW_SENSOR, FUNC_ANY_KEY, diff --git a/tasmota/tasmota_globals.h b/tasmota/tasmota_globals.h index cb3f4547b..fe54cad67 100644 --- a/tasmota/tasmota_globals.h +++ b/tasmota/tasmota_globals.h @@ -233,6 +233,8 @@ const uint16_t LOG_BUFFER_SIZE = 4000; // Max number of characters in lo #define TASM_FILE_SETTINGS "/.settings" // Settings binary blob #define TASM_FILE_SETTINGS_LKG "/.settings.lkg" // Last Known Good Settings binary blob +#define TASM_FILE_DRIVER "/.drvset%03d" +#define TASM_FILE_SENSOR "/.snsset%03d" #define TASM_FILE_ZIGBEE "/zb" // Zigbee settings blob as used by CC2530 on ESP32 #ifndef MQTT_MAX_PACKET_SIZE @@ -475,18 +477,18 @@ bool first_device_group_is_local = true; /*********************************************************************************************\ * Macro for SetOption synonyms - * + * * SetOption synonyms come first in the list of commands, right after the prefix. * They don't need any matching function pointer, since they are handled internally. * So don't forget to NOT put pointers in the functions pointers list. - * + * * The additionnal list of unsigned bytes contains the Option numbers of each synonyms * in the same order. The first byte of the list contains the number of synonyms * (not including the number itself). The is the number of names to skip to find the first command. - * + * * As it si cumbersome to calculate the first byte (number of synonyms), we provide the following * macro `SO_SYNONYMS(, )` - * + * * For example: * ``` * SO_SYNONYMS(kLightSynonyms, @@ -494,7 +496,7 @@ bool first_device_group_is_local = true; * 106, * ); * ``` - * + * * is equivalent to: * ``` * const static uint8_t kLightSynonyms[] PROGMEM = { @@ -503,7 +505,7 @@ bool first_device_group_is_local = true; * 106, * }; * ``` - * + * * This comes very handy if you need to adjust the number of synonyms depending on #defines \*********************************************************************************************/ diff --git a/tasmota/xdrv_50_filesystem.ino b/tasmota/xdrv_50_filesystem.ino index 141af6215..aacdf543d 100644 --- a/tasmota/xdrv_50_filesystem.ino +++ b/tasmota/xdrv_50_filesystem.ino @@ -85,10 +85,6 @@ uint8_t ufs_type; uint8_t ffs_type; bool download_busy; - - - - /*********************************************************************************************/ // Init flash file system diff --git a/tasmota/xdrv_98_file_settings_demo.ino b/tasmota/xdrv_98_file_settings_demo.ino new file mode 100644 index 000000000..4dd62ee97 --- /dev/null +++ b/tasmota/xdrv_98_file_settings_demo.ino @@ -0,0 +1,186 @@ +/* + xdrv_98_file_settings_demo.ino - Demo for Tasmota + + Copyright (C) 2021 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +// Enable this define to use this demo +//#define USE_DRV_FILE_DEMO + +#ifdef USE_DRV_FILE_DEMO +/*********************************************************************************************\ + * Settings load and save demo using Tasmota file system + * + * To test this file: + * - Have hardware with at least 2M flash + * - Enable a build.ldscript with at least 256k filesystem in platform_override.ini + * - Enable define USE_UFILESYS in user_config_override.h +\*********************************************************************************************/ +#warning **** USE_DRV_FILE_DEMO is enabled **** + +#define XDRV_98 98 + +#define DRV98_MAX_DRV_TEXT 16 + +const uint32_t DRV98_VERSION = 0x01010101; // Latest driver version (See settings deltas below) + +// Demo command line commands +const char kDrvDemoCommands[] PROGMEM = "Drv|" // Prefix + "Text"; + +void (* const DrvDemoCommand[])(void) PROGMEM = { + &CmndDrvText }; + +// Global structure containing driver saved variables +struct { + uint32_t crc32; // To detect file changes + uint32_t version; // To detect driver function changes + char drv_text[DRV98_MAX_DRV_TEXT -1][10]; +} Drv98Settings; + +// Global structure containing driver non-saved variables +struct { + uint32_t any_value; +} Drv98Global; + +void CmndDrvText(void) { + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= DRV98_MAX_DRV_TEXT)) { + if (!XdrvMailbox.usridx) { + // Command DrvText + for (uint32_t i = 0; i < DRV98_MAX_DRV_TEXT; i++) { + AddLog(LOG_LEVEL_DEBUG, PSTR("DRV: DrvText%02d %s"), i, Drv98Settings.drv_text[i]); + } + ResponseCmndDone(); + } else { + // Command DrvText + uint32_t index = XdrvMailbox.index -1; + if (XdrvMailbox.data_len > 0) { + snprintf_P(Drv98Settings.drv_text[index], sizeof(Drv98Settings.drv_text[index]), XdrvMailbox.data); + } + ResponseCmndIdxChar(Drv98Settings.drv_text[index]); + } + } +} + +/*********************************************************************************************\ + * Driver Settings load and save +\*********************************************************************************************/ + +uint32_t GetDrvDemoSettingsCrc32(void) { + // Use Tasmota CRC calculation function + return GetCfgCrc32((uint8_t*)&Drv98Settings +4, sizeof(Drv98Settings) -4); // Skip crc32 +} + +void DrvDemoPreInit(void) { + // Init default values in case file is not found + memset(&Drv98Settings, 0x00, sizeof(Drv98Settings)); + Drv98Settings.version = DRV98_VERSION; + // Init any other parameter in struct Drv98Settings + snprintf_P(Drv98Settings.drv_text[0], sizeof(Drv98Settings.drv_text[0]), PSTR("Azalea")); + + // Try to load file /drvset098 + char filename[20]; + // Use for sensors: +// snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_SENSOR), XSNS_98); + // Use for drivers: + snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_DRIVER), XDRV_98); + + AddLog(LOG_LEVEL_INFO, PSTR("DRV: About to load settings from file %s"), filename); + +#ifdef USE_UFILESYS + + bool result = TfsLoadFile(filename, (uint8_t*)&Drv98Settings, sizeof(Drv98Settings)); + if (result) { + // Fix possible setting deltas + if (Drv98Settings.version != DRV98_VERSION) { // Fix version dependent changes + + if (Settings.version < 0x01010100) { + AddLog(LOG_LEVEL_INFO, PSTR("DRV: Update oldest version restore")); + + } + if (Settings.version < 0x01010101) { + AddLog(LOG_LEVEL_INFO, PSTR("DRV: Update old version restore")); + + } + + // Set current version and save settings + Drv98Settings.version = DRV98_VERSION; + DrvDemoSettingsSave(); + } + } else { + // File system not ready: No flash space reserved for file system + AddLog(LOG_LEVEL_INFO, PSTR("DRV: ERROR File system not ready or file not found")); + } + +#else + + AddLog(LOG_LEVEL_INFO, PSTR("DRV: ERROR File system not enabled")); + +#endif // USE_UFILESYS + Drv98Settings.crc32 = GetDrvDemoSettingsCrc32(); +} + +void DrvDemoSettingsSave(void) { + if (GetDrvDemoSettingsCrc32() != Drv98Settings.crc32) { + // Try to save file /drvset098 + Drv98Settings.crc32 = GetDrvDemoSettingsCrc32(); + char filename[20]; + // Use for sensors: +// snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_SENSOR), XSNS_98); + // Use for drivers: + snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_DRIVER), XDRV_98); + + AddLog(LOG_LEVEL_INFO, PSTR("DRV: About to save settings to file %s"), filename); + +#ifdef USE_UFILESYS + bool result = TfsSaveFile(filename, (const uint8_t*)&Drv98Settings, sizeof(Drv98Settings)); + if (!result) { + // File system not ready: No flash space reserved for file system + AddLog(LOG_LEVEL_INFO, PSTR("DRV: ERROR File system not ready or unable to save file")); + } +#else + + AddLog(LOG_LEVEL_INFO, PSTR("DRV: ERROR File system not enabled")); + +#endif // USE_UFILESYS + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv98(uint8_t function) { + bool result = false; + + switch (function) { + case FUNC_COMMAND: + result = DecodeCommand(kDrvDemoCommands, DrvDemoCommand); + break; + case FUNC_SAVE_SETTINGS: + DrvDemoSettingsSave(); + break; + case FUNC_PRE_INIT: + DrvDemoPreInit(); + break; + case FUNC_SAVE_BEFORE_RESTART: + // !!! DO NOT USE AS IT'S FUNCTION IS BETTER HANDLED BY FUNC_SAVE_SETTINGS !!! + break; + } + return result; +} + +#endif // USE_DRV_FILE_DEMO \ No newline at end of file