diff --git a/src/_P016_IR.ino b/src/_P016_IR.ino index 9c4ae18271..87f88a945a 100644 --- a/src/_P016_IR.ino +++ b/src/_P016_IR.ino @@ -315,14 +315,7 @@ boolean Plugin_016(uint8_t function, struct EventStruct *event, String& string) 2000); { - // For load and save of the display lines, we must not rely on the data in memory. - // This data in memory can be altered through write commands. - // Therefore we must read the lines from flash in a temporary object. - P016_data_struct *P016_data = new (std::nothrow) P016_data_struct(); - - if (nullptr != P016_data) { - P016_data->loadCommandLines(event); // load saved codes and commands - + { addFormSubHeader(F("Code - command map")); int size = static_cast(decode_type_t::kLastDecodeType) + 1; @@ -366,6 +359,9 @@ boolean Plugin_016(uint8_t function, struct EventStruct *event, String& string) int rowCnt = 0; for (uint8_t varNr = 0; varNr < P16_Nlines; varNr++) { + tCommandLinesV2 line; + P016_data_struct::loadCommandLine(event, line, varNr); + html_TR_TD(); if (varNr < 9) { @@ -375,30 +371,30 @@ boolean Plugin_016(uint8_t function, struct EventStruct *event, String& string) html_TD(); { // Decode type addSelector(getPluginCustomArgName(rowCnt + 0), size, &decodeTypes[0], &decodeTypeOptions[0], NULL, - static_cast(P016_data->CommandLines[varNr].CodeDecodeType), false, true, EMPTY_STRING); + static_cast(line.CodeDecodeType), false, true, EMPTY_STRING); } html_TD(); - addCheckBox(getPluginCustomArgName(rowCnt + 1), bitRead(P016_data->CommandLines[varNr].CodeFlags, P16_FLAGS_REPEAT)); + addCheckBox(getPluginCustomArgName(rowCnt + 1), bitRead(line.CodeFlags, P16_FLAGS_REPEAT)); html_TD(); strCode = EMPTY_STRING; - if (P016_data->CommandLines[varNr].Code > 0) { - strCode = uint64ToString(P016_data->CommandLines[varNr].Code, 16); // convert code to hex for display + if (line.Code > 0) { + strCode = uint64ToString(line.Code, 16); // convert code to hex for display } addTextBox(getPluginCustomArgName(rowCnt + 2), strCode, P16_Cchars - 1, false, false, P016_HEX_INPUT_PATTERN, EMPTY_STRING); html_TD(); { addSelector(getPluginCustomArgName(rowCnt + 3), size, &decodeTypes[0], &decodeTypeOptions[0], NULL, - static_cast(P016_data->CommandLines[varNr].AlternativeCodeDecodeType), false, true, EMPTY_STRING); + static_cast(line.AlternativeCodeDecodeType), false, true, EMPTY_STRING); } html_TD(); - addCheckBox(getPluginCustomArgName(rowCnt + 4), bitRead(P016_data->CommandLines[varNr].AlternativeCodeFlags, P16_FLAGS_REPEAT)); + addCheckBox(getPluginCustomArgName(rowCnt + 4), bitRead(line.AlternativeCodeFlags, P16_FLAGS_REPEAT)); html_TD(); strCode = EMPTY_STRING; - if (P016_data->CommandLines[varNr].AlternativeCode > 0) { - strCode = uint64ToString(P016_data->CommandLines[varNr].AlternativeCode, 16); // convert code to hex for display + if (line.AlternativeCode > 0) { + strCode = uint64ToString(line.AlternativeCode, 16); // convert code to hex for display } addTextBox(getPluginCustomArgName(rowCnt + 5), strCode, P16_Cchars - 1, false, false, P016_HEX_INPUT_PATTERN, EMPTY_STRING); @@ -409,15 +405,12 @@ boolean Plugin_016(uint8_t function, struct EventStruct *event, String& string) addHtmlInt(varNr + 1); addHtml(':'); addHtml(F("")); // Use as much of available width (though limited to 500px by css) - addTextBox(getPluginCustomArgName(rowCnt + 6), String(P016_data->CommandLines[varNr].Command), P16_Nchars - 1); + addTextBox(getPluginCustomArgName(rowCnt + 6), String(line.Command), P16_Nchars - 1); rowCnt += 7; delay(0); } html_end_table(); - - // Need to delete the allocated object here - delete P016_data; } if (P016_SETTINGS_VERSION != P16_SETTINGS_LATEST) { @@ -454,65 +447,58 @@ boolean Plugin_016(uint8_t function, struct EventStruct *event, String& string) PCONFIG_LONG(0) = lSettings; P016_CMDINHIBIT = getFormItemInt(F("p016_cmdinhibit")); - { - // For load and save of the display lines, we must not rely on the data in memory. - // This data in memory can be altered through write commands. - // Therefore we must use a temporary version to store the settings. - P016_data_struct *P016_data = new (std::nothrow) P016_data_struct(); + # ifdef PLUGIN_016_DEBUG + P016_infoLogMemory(F("before save")); + # endif // ifdef PLUGIN_016_DEBUG - if (nullptr != P016_data) { - char strCode[P16_Cchars]; + { String strError; strError.reserve(30); // Length of expected string, needed for strings > 11 chars - String strID; - uint64_t iCode; int rowCnt = 0; - P016_data->CommandLines.clear(); // Start fresh - for (uint8_t varNr = 0; varNr < P16_Nlines; varNr++) { - P016_data->CommandLines.push_back(tCommandLinesV2()); + tCommandLinesV2 line; + strError = EMPTY_STRING; // Normal Code & flags - P016_data->CommandLines[varNr].CodeDecodeType = static_cast(getFormItemInt(getPluginCustomArgName(rowCnt + 0))); - bitWrite(P016_data->CommandLines[varNr].CodeFlags, P16_FLAGS_REPEAT, isFormItemChecked(getPluginCustomArgName(rowCnt + 1))); - iCode = 0; + line.CodeDecodeType = static_cast(getFormItemInt(getPluginCustomArgName(rowCnt + 0))); + bitWrite(line.CodeFlags, P16_FLAGS_REPEAT, isFormItemChecked(getPluginCustomArgName(rowCnt + 1))); + line.Code = 0; + char strCode[P16_Cchars] = {0}; if (!safe_strncpy(strCode, webArg(getPluginCustomArgName(rowCnt + 2)), P16_Cchars)) { strError += F("Code "); strError += (varNr + 1); strError += ' '; } else { - iCode = hexToULL(strCode); // convert string with hexnumbers to uint64_t + line.Code = hexToULL(strCode); // convert string with hexnumbers to uint64_t } - P016_data->CommandLines[varNr].Code = iCode; delay(0); // Alternate Code & flags - P016_data->CommandLines[varNr].AlternativeCodeDecodeType = + line.AlternativeCodeDecodeType = static_cast(getFormItemInt(getPluginCustomArgName(rowCnt + 3))); - bitWrite(P016_data->CommandLines[varNr].AlternativeCodeFlags, P16_FLAGS_REPEAT, + bitWrite(line.AlternativeCodeFlags, P16_FLAGS_REPEAT, isFormItemChecked(getPluginCustomArgName(rowCnt + 4))); - iCode = 0; + line.AlternativeCode = 0; if (!safe_strncpy(strCode, webArg(getPluginCustomArgName(rowCnt + 5)), P16_Cchars)) { strError += F("Alt.Code "); strError += (varNr + 1); strError += ' '; } else { - iCode = hexToULL(strCode); // convert string with hexnumbers to uint64_t + line.AlternativeCode = hexToULL(strCode); // convert string with hexnumbers to uint64_t } - P016_data->CommandLines[varNr].AlternativeCode = iCode; // Command - if (!safe_strncpy(P016_data->CommandLines[varNr].Command, webArg(getPluginCustomArgName(rowCnt + 6)), P16_Nchars)) { + if (!safe_strncpy(line.Command, webArg(getPluginCustomArgName(rowCnt + 6)), P16_Nchars)) { strError += F("Command "); strError += (varNr + 1); } - P016_data->CommandLines[varNr].Command[P16_Nchars - 1] = 0; // Terminate string + line.Command[P16_Nchars - 1] = 0; // Terminate string if (!strError.isEmpty()) { addHtmlError(strError); @@ -520,21 +506,13 @@ boolean Plugin_016(uint8_t function, struct EventStruct *event, String& string) rowCnt += 7; delay(0); - } - - # ifdef PLUGIN_016_DEBUG - P016_infoLogMemory(F("before save")); - # endif // ifdef PLUGIN_016_DEBUG - P016_data->saveCommandLines(event); + P016_data_struct::saveCommandLine(event, line, varNr); + } # ifdef PLUGIN_016_DEBUG P016_infoLogMemory(F("after save")); # endif // ifdef PLUGIN_016_DEBUG - - // Need to delete the allocated object here - delete P016_data; - } } # ifdef PLUGIN_016_DEBUG diff --git a/src/_P022_PCA9685.ino b/src/_P022_PCA9685.ino index 267a5507ee..a2a9c48ebb 100644 --- a/src/_P022_PCA9685.ino +++ b/src/_P022_PCA9685.ino @@ -63,6 +63,7 @@ boolean Plugin_022(uint8_t function, struct EventStruct *event, String& string) Device[deviceCount].ValueCount = 0; Device[deviceCount].Custom = true; Device[deviceCount].TimerOption = false; + Device[deviceCount].ExitTaskBeforeSave = false; break; } diff --git a/src/_P036_FrameOLED.ino b/src/_P036_FrameOLED.ino index 11f1ada852..0609827d55 100644 --- a/src/_P036_FrameOLED.ino +++ b/src/_P036_FrameOLED.ino @@ -461,17 +461,6 @@ boolean Plugin_036(uint8_t function, struct EventStruct *event, String& string) } } - P036_data_struct *P036_data = - static_cast(getPluginTaskData(event->TaskIndex)); - - if (nullptr != P036_data) { - // After saving, make sure the active lines are updated. - P036_data->frameCounter = 0; - P036_data->MaxFramesToDisplay = 0xFF; - P036_data->disp_resolution = static_cast(P036_RESOLUTION); - P036_data->loadDisplayLines(event->TaskIndex, 1); - } - #ifdef PLUGIN_036_DEBUG addLog(LOG_LEVEL_INFO, F("P036_PLUGIN_WEBFORM_SAVE Done")); #endif // PLUGIN_036_DEBUG diff --git a/src/_P052_SenseAir.ino b/src/_P052_SenseAir.ino index 645aabf1cd..9ac2119da0 100644 --- a/src/_P052_SenseAir.ino +++ b/src/_P052_SenseAir.ino @@ -158,6 +158,8 @@ boolean Plugin_052(uint8_t function, struct EventStruct *event, String& string) Device[deviceCount].TimerOption = true; Device[deviceCount].GlobalSyncOption = true; Device[deviceCount].OutputDataType = Output_Data_type_t::Simple; + // FIXME TD-er: Seems to use task data, but not sure if really needed. + Device[deviceCount].ExitTaskBeforeSave = false; break; } diff --git a/src/_P062_MPR121_KeyPad.ino b/src/_P062_MPR121_KeyPad.ino index 9d4431d24f..127e3d2ce2 100644 --- a/src/_P062_MPR121_KeyPad.ino +++ b/src/_P062_MPR121_KeyPad.ino @@ -56,6 +56,7 @@ boolean Plugin_062(uint8_t function, struct EventStruct *event, String& string) Device[deviceCount].TimerOption = true; Device[deviceCount].TimerOptional = true; Device[deviceCount].GlobalSyncOption = true; + Device[deviceCount].ExitTaskBeforeSave = false; break; } diff --git a/src/_P070_NeoPixel_Clock.ino b/src/_P070_NeoPixel_Clock.ino index 2cdab517af..5c657d5f39 100644 --- a/src/_P070_NeoPixel_Clock.ino +++ b/src/_P070_NeoPixel_Clock.ino @@ -166,6 +166,8 @@ boolean Plugin_070(uint8_t function, struct EventStruct *event, String& string) Device[deviceCount].SendDataOption = false; Device[deviceCount].TimerOption = false; Device[deviceCount].GlobalSyncOption = false; + // FIXME TD-er: Not sure if access to any existing task data is needed when saving + Device[deviceCount].ExitTaskBeforeSave = false; break; } diff --git a/src/_P073_7DGT.ino b/src/_P073_7DGT.ino index b0e8ad458c..b6791b8e12 100644 --- a/src/_P073_7DGT.ino +++ b/src/_P073_7DGT.ino @@ -704,6 +704,8 @@ boolean Plugin_073(uint8_t function, struct EventStruct *event, String& string) Device[deviceCount].TimerOption = false; Device[deviceCount].TimerOptional = false; Device[deviceCount].GlobalSyncOption = true; + // FIXME TD-er: Not sure if access to any existing task data is needed when saving + Device[deviceCount].ExitTaskBeforeSave = false; break; } diff --git a/src/_P075_Nextion.ino b/src/_P075_Nextion.ino index 745dae340f..edb4a60790 100644 --- a/src/_P075_Nextion.ino +++ b/src/_P075_Nextion.ino @@ -121,6 +121,9 @@ boolean Plugin_075(uint8_t function, struct EventStruct *event, String& string) Device[deviceCount].TimerOption = true; Device[deviceCount].TimerOptional = true; // Allow user to disable interval function. Device[deviceCount].GlobalSyncOption = true; + // FIXME TD-er: Not sure if access to any existing task data is needed when saving + Device[deviceCount].ExitTaskBeforeSave = false; + break; } diff --git a/src/_P085_AcuDC243.ino b/src/_P085_AcuDC243.ino index af78e24385..535ef046ae 100644 --- a/src/_P085_AcuDC243.ino +++ b/src/_P085_AcuDC243.ino @@ -105,6 +105,7 @@ boolean Plugin_085(uint8_t function, struct EventStruct *event, String& string) Device[deviceCount].SendDataOption = true; Device[deviceCount].TimerOption = true; Device[deviceCount].GlobalSyncOption = true; + Device[deviceCount].ExitTaskBeforeSave = false; break; } diff --git a/src/_P087_SerialProxy.ino b/src/_P087_SerialProxy.ino index 2c4bf7cc92..4287a00e11 100644 --- a/src/_P087_SerialProxy.ino +++ b/src/_P087_SerialProxy.ino @@ -65,6 +65,8 @@ boolean Plugin_087(uint8_t function, struct EventStruct *event, String& string) Device[deviceCount].SendDataOption = true; Device[deviceCount].TimerOption = true; Device[deviceCount].GlobalSyncOption = false; + // FIXME TD-er: Not sure if access to any existing task data is needed when saving + Device[deviceCount].ExitTaskBeforeSave = false; break; } diff --git a/src/_P094_CULReader.ino b/src/_P094_CULReader.ino index 2cffc8feb4..4b156c4497 100644 --- a/src/_P094_CULReader.ino +++ b/src/_P094_CULReader.ino @@ -73,6 +73,8 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) Device[deviceCount].TimerOption = true; Device[deviceCount].GlobalSyncOption = false; // Device[deviceCount].DuplicateDetection = true; + // FIXME TD-er: Not sure if access to any existing task data is needed when saving + Device[deviceCount].ExitTaskBeforeSave = false; break; } diff --git a/src/_P104_max7219_Dotmatrix.ino b/src/_P104_max7219_Dotmatrix.ino index c8ce124262..f1e967d778 100644 --- a/src/_P104_max7219_Dotmatrix.ino +++ b/src/_P104_max7219_Dotmatrix.ino @@ -131,6 +131,7 @@ boolean Plugin_104(uint8_t function, struct EventStruct *event, String& string) Device[deviceCount].TimerOption = false; Device[deviceCount].TimerOptional = false; Device[deviceCount].GlobalSyncOption = true; + Device[deviceCount].ExitTaskBeforeSave = false; break; } diff --git a/src/src/DataStructs/DeviceStruct.cpp b/src/src/DataStructs/DeviceStruct.cpp index f6a1f83c1a..ee853a171c 100644 --- a/src/src/DataStructs/DeviceStruct.cpp +++ b/src/src/DataStructs/DeviceStruct.cpp @@ -5,7 +5,8 @@ DeviceStruct::DeviceStruct() : OutputDataType(Output_Data_type_t::Default), PullUpOption(false), InverseLogicOption(false), FormulaOption(false), Custom(false), SendDataOption(false), GlobalSyncOption(false), - TimerOption(false), TimerOptional(false), DecimalsOnly(false) {} + TimerOption(false), TimerOptional(false), DecimalsOnly(false), + ExitTaskBeforeSave(true) {} bool DeviceStruct::connectedToGPIOpins() const { switch(Type) { diff --git a/src/src/DataStructs/DeviceStruct.h b/src/src/DataStructs/DeviceStruct.h index fc47572b74..579701a077 100644 --- a/src/src/DataStructs/DeviceStruct.h +++ b/src/src/DataStructs/DeviceStruct.h @@ -93,6 +93,7 @@ struct DeviceStruct bool TimerOption : 1; // Allow to set the "Interval" timer for the plugin. bool TimerOptional : 1; // When taskdevice timer is not set and not optional, use default "Interval" delay (Settings.Delay) bool DecimalsOnly : 1; // Allow to set the number of decimals (otherwise treated a 0 decimals) + bool ExitTaskBeforeSave : 1; // Optimization in memory usage, Do not exit when task data is needed during save. }; typedef std::vector DeviceVector; diff --git a/src/src/DataTypes/ControllerIndex.cpp b/src/src/DataTypes/ControllerIndex.cpp index ada9588cd6..ff5d61e1ed 100644 --- a/src/src/DataTypes/ControllerIndex.cpp +++ b/src/src/DataTypes/ControllerIndex.cpp @@ -1,4 +1,4 @@ -#include "ControllerIndex.h" +#include "../DataTypes/ControllerIndex.h" #include "../CustomBuild/ESPEasyLimits.h" diff --git a/src/src/PluginStructs/P016_data_struct.cpp b/src/src/PluginStructs/P016_data_struct.cpp index 6c118e71a5..fa7adf9793 100644 --- a/src/src/PluginStructs/P016_data_struct.cpp +++ b/src/src/PluginStructs/P016_data_struct.cpp @@ -7,13 +7,10 @@ # include # ifdef P16_SETTINGS_V1 -tCommandLinesV2::tCommandLinesV2() {} // Default constructor // Conversion constructor -tCommandLinesV2::tCommandLinesV2(const String& command, - uint32_t oldCode, - uint32_t oldAlternativeCode, - uint8_t i) { +tCommandLinesV2::tCommandLinesV2(const tCommandLinesV1& lineV1, uint8_t i) +{ String log; if (loglevelActiveFor(LOG_LEVEL_INFO)) { @@ -30,9 +27,8 @@ tCommandLinesV2::tCommandLinesV2(const String& command, log += ':'; # endif // ifdef PLUGIN_016_DEBUG - if (command.length() > 0) { - safe_strncpy(Command, command, P16_Nchars); - } + memcpy(Command, lineV1.Command, P16_Nchars); + const uint32_t oldCode = lineV1.Code; if (oldCode > 0) { CodeDecodeType = static_cast((oldCode >> 24)); // decode_type @@ -49,6 +45,8 @@ tCommandLinesV2::tCommandLinesV2(const String& command, # endif // ifdef PLUGIN_016_DEBUG } + const uint32_t oldAlternativeCode = lineV1.AlternativeCode; + if (oldAlternativeCode > 0) { AlternativeCodeDecodeType = static_cast((oldAlternativeCode >> 24)); // decode_type bitWrite(AlternativeCodeFlags, P16_FLAGS_REPEAT, oldAlternativeCode & (0x1 << P16_CMDBIT_REPEAT)); // Repeat flag @@ -77,98 +75,75 @@ void P016_data_struct::init(struct EventStruct *event, uint16_t CmdInhibitTime) iLastCmdTime = 0; } -# ifdef P16_SETTINGS_V1 -void P016_data_struct::convertCommandLines(struct EventStruct *event) { - String log; - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - # ifndef PLUGIN_016_DEBUG - log.reserve(20); // less space needed - # else // ifndef PLUGIN_016_DEBUG - log.reserve(80); +void P016_data_struct::loadCommandLines(struct EventStruct *event) { + # ifdef P16_SETTINGS_V1 - log = F("P016: struct size: "); - log += sizeof(tCommandLinesV2); - log += '/'; - log += sizeof(tCommandLines); - log += F(" enum: "); - log += sizeof(decode_type_t); - log += F(" p016: "); - log += sizeof(P016_data_struct); - addLog(LOG_LEVEL_INFO, log); - # endif // ifdef PLUGIN_016_DEBUG + // Convert the settings if both versions are defined and PCONFIG(7) != latest version + if (PCONFIG(7) != P16_SETTINGS_LATEST) { + addLog(LOG_LEVEL_ERROR, F("P016 IR: Settings conversion, save task settings to store in new format.")); } - - // read V1 data && convert - CommandLinesV1.clear(); // Start fresh - int loadOffset = 0; + # endif // ifdef P16_SETTINGS_V1 + CommandLines.clear(); // Start fresh for (uint8_t i = 0; i < P16_Nlines; i++) { - CommandLinesV1.push_back(tCommandLines()); - LoadFromFile(SettingsType::Enum::CustomTaskSettings_Type, - event->TaskIndex, - reinterpret_cast(&(CommandLinesV1[i])), - sizeof(tCommandLines), - loadOffset); - loadOffset += sizeof(tCommandLines); + CommandLines.push_back(tCommandLinesV2()); + loadCommandLine(event, CommandLines[i], i); } +} - CommandLines.clear(); // Start fresh - - for (int i = 0; i < P16_Nlines; ++i) { - CommandLines.push_back(tCommandLinesV2(String(CommandLinesV1[i].Command), CommandLinesV1[i].Code, CommandLinesV1[i].AlternativeCode, i)); - - delay(0); +void P016_data_struct::saveCommandLines(struct EventStruct *event) { + for (uint8_t i = 0; i < P16_Nlines; i++) { + saveCommandLine(event, CommandLines[i], i); } - CommandLinesV1.clear(); // clean up after conversion } -# endif // ifdef P16_SETTINGS_V1 - -void P016_data_struct::loadCommandLines(struct EventStruct *event) { +void P016_data_struct::loadCommandLine(struct EventStruct *event, tCommandLinesV2& line, uint8_t lineNr) +{ # ifdef P16_SETTINGS_V1 - // Convert the settings if both versions are defined and PCONFIG(7) != latest version if (PCONFIG(7) != P16_SETTINGS_LATEST) { - addLog(LOG_LEVEL_ERROR, F("P016 IR: Settings conversion, save task settings to store in new format.")); - - convertCommandLines(event); + loadCommandLinev1(event, line, lineNr); + return; } - else # endif // ifdef P16_SETTINGS_V1 - { - // read V2 settings data - - CommandLines.clear(); // Start fresh - int loadOffset = 0; - - for (uint8_t i = 0; i < P16_Nlines; i++) { - CommandLines.push_back(tCommandLinesV2()); - LoadFromFile(SettingsType::Enum::CustomTaskSettings_Type, - event->TaskIndex, - reinterpret_cast(&(CommandLines[i])), - sizeof(tCommandLinesV2), - loadOffset); - loadOffset += sizeof(tCommandLinesV2); - } - } - for (int i = 0; i < P16_Nlines; ++i) { - CommandLines[i].Command[P16_Nchars - 1] = 0; // Terminate in case of uninitalized data - } + const int loadOffset = lineNr * sizeof(tCommandLinesV2); + LoadFromFile(SettingsType::Enum::CustomTaskSettings_Type, + event->TaskIndex, + reinterpret_cast(&line), + sizeof(tCommandLinesV2), + loadOffset); + line.Command[P16_Nchars - 1] = 0; // Terminate in case of uninitalized data } -void P016_data_struct::saveCommandLines(struct EventStruct *event) { - int saveOffset = 0; +# ifdef P16_SETTINGS_V1 +void P016_data_struct::loadCommandLinev1(struct EventStruct *event, tCommandLinesV2& line, uint8_t lineNr) +{ + tCommandLinesV1 lineV1; - for (uint8_t i = 0; i < P16_Nlines; i++) { - SaveToFile(SettingsType::Enum::CustomTaskSettings_Type, - event->TaskIndex, - reinterpret_cast(&(CommandLines[i])), - sizeof(tCommandLinesV2), - saveOffset); - saveOffset += sizeof(tCommandLinesV2); + { + const int loadOffsetV1 = lineNr * sizeof(tCommandLinesV1); + LoadFromFile(SettingsType::Enum::CustomTaskSettings_Type, + event->TaskIndex, + reinterpret_cast(&lineV1), + sizeof(tCommandLinesV2), + loadOffsetV1); } + line = tCommandLinesV2(lineV1, lineNr); + line.Command[P16_Nchars - 1] = 0; +} + +# endif // ifdef P16_SETTINGS_V1 + +void P016_data_struct::saveCommandLine(struct EventStruct *event, const tCommandLinesV2& line, uint8_t lineNr) +{ + const int saveOffset = lineNr * sizeof(tCommandLinesV2); + + SaveToFile(SettingsType::Enum::CustomTaskSettings_Type, + event->TaskIndex, + reinterpret_cast(&line), + sizeof(tCommandLinesV2), + saveOffset); } void P016_data_struct::AddCode(uint64_t Code, decode_type_t DecodeType, uint16_t CodeFlags) { @@ -266,21 +241,22 @@ void P016_data_struct::ExecuteCode(uint64_t Code, decode_type_t DecodeType, uint return; } # ifdef PLUGIN_016_DEBUG + if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log; - log.reserve(128); // estimated - log = F("[P36] ValidateCode failed: "); - log += typeToString(DecodeType, bitRead(CodeFlags, P16_FLAGS_REPEAT)); - log += F(" Code: 0x"); - log += uint64ToString(Code, 16); - log += F(" / ["); - log += (i + 1); - log += F("] = {"); - log += typeToString(CommandLines[i].CodeDecodeType, bitRead(CommandLines[i].CodeFlags, P16_FLAGS_REPEAT)); - log += F(" Code: 0x"); - log += uint64ToString(CommandLines[i].Code, 16); - log += '}'; - addLog(LOG_LEVEL_INFO, log); + String log; + log.reserve(128); // estimated + log = F("[P36] ValidateCode failed: "); + log += typeToString(DecodeType, bitRead(CodeFlags, P16_FLAGS_REPEAT)); + log += F(" Code: 0x"); + log += uint64ToString(Code, 16); + log += F(" / ["); + log += (i + 1); + log += F("] = {"); + log += typeToString(CommandLines[i].CodeDecodeType, bitRead(CommandLines[i].CodeFlags, P16_FLAGS_REPEAT)); + log += F(" Code: 0x"); + log += uint64ToString(CommandLines[i].Code, 16); + log += '}'; + addLog(LOG_LEVEL_INFO, log); } # endif // PLUGIN_016_DEBUG } diff --git a/src/src/PluginStructs/P016_data_struct.h b/src/src/PluginStructs/P016_data_struct.h index 689b1b4d92..7d9b106aba 100644 --- a/src/src/PluginStructs/P016_data_struct.h +++ b/src/src/PluginStructs/P016_data_struct.h @@ -6,18 +6,19 @@ # include -# define PLUGIN_016_DEBUG // additional debug messages in the log +# define PLUGIN_016_DEBUG // additional debug messages in the log // bit definition in PCONFIG_LONG(0) -# define P016_BitAddNewCode 0 // Add automatically new code into Code of the command structure -# define P016_BitExecuteCmd 1 // Execute command if received code matches Code or AlternativeCode of the command structure -# define P016_BitAcceptUnknownType 2 // Accept unknown DecodeType as valid IR code (will be set to RAW before calling AddCode() or ExecuteCode()) +# define P016_BitAddNewCode 0 // Add automatically new code into Code of the command structure +# define P016_BitExecuteCmd 1 // Execute command if received code matches Code or AlternativeCode of the command structure +# define P016_BitAcceptUnknownType 2 // Accept unknown DecodeType as valid IR code (will be set to RAW before calling AddCode() or + // ExecuteCode()) -# define P16_Nlines 10 // The number of different lines which can be displayed - each line is 64 chars max -# define P16_Nchars 64 // max chars per command line -# define P16_Cchars 20 // max chars per code +# define P16_Nlines 10 // The number of different lines which can be displayed - each line is 64 chars max +# define P16_Nchars 64 // max chars per command line +# define P16_Cchars 20 // max chars per code -# define P16_SETTINGS_V1 // Settings v1 original settings when enabled, settings conversion is also enabled +# define P16_SETTINGS_V1 // Settings v1 original settings when enabled, settings conversion is also enabled // Settings v2 includes 64 bit codes and some separated flags # ifdef P16_SETTINGS_V1 @@ -30,13 +31,19 @@ # define P16_FLAGS_REPEAT 0 // Repeat code // # define P16_FLAGS_HASH 1 // Code is a Hash +# ifdef P16_SETTINGS_V1 +typedef struct { + char Command[P16_Nchars] = { 0 }; + uint32_t Code = 0; // received code (can be added automatically) + uint32_t AlternativeCode = 0; // alternative code fpr the same command +} tCommandLinesV1; +# endif // ifdef P16_SETTINGS_V1 + struct tCommandLinesV2 { # ifdef P16_SETTINGS_V1 - tCommandLinesV2(); - tCommandLinesV2(const String& command, - uint32_t oldCode, - uint32_t oldAlternativeCode, - uint8_t i); + tCommandLinesV2() = default; + tCommandLinesV2(const tCommandLinesV1& lineV1, + uint8_t i); # endif // ifdef P16_SETTINGS_V1 char Command[P16_Nchars] = { 0 }; @@ -48,13 +55,6 @@ struct tCommandLinesV2 { uint16_t AlternativeCodeFlags = 0; }; -# ifdef P16_SETTINGS_V1 -typedef struct { - char Command[P16_Nchars] = { 0 }; - uint32_t Code = 0; // received code (can be added automatically) - uint32_t AlternativeCode = 0; // alternative code fpr the same command -} tCommandLines; -# endif // ifdef P16_SETTINGS_V1 extern String uint64ToString(uint64_t input, uint8_t base); @@ -64,10 +64,23 @@ struct P016_data_struct : public PluginTaskData_base { P016_data_struct(); - void init(struct EventStruct *event, - uint16_t CmdInhibitTime); - void loadCommandLines(struct EventStruct *event); - void saveCommandLines(struct EventStruct *event); + void init(struct EventStruct *event, + uint16_t CmdInhibitTime); + void loadCommandLines(struct EventStruct *event); + void saveCommandLines(struct EventStruct *event); + + static void loadCommandLine(struct EventStruct *event, + tCommandLinesV2 & line, + uint8_t lineNr); + # ifdef P16_SETTINGS_V1 + static void loadCommandLinev1(struct EventStruct *event, + tCommandLinesV2 & line, + uint8_t lineNr); + # endif // ifdef P16_SETTINGS_V1 + static void saveCommandLine(struct EventStruct *event, + const tCommandLinesV2& line, + uint8_t lineNr); + void AddCode(uint64_t Code, decode_type_t DecodeType = decode_type_t::UNKNOWN, uint16_t CodeFlags = 0u); @@ -86,16 +99,12 @@ struct P016_data_struct : public PluginTaskData_base { uint64_t Code, decode_type_t DecodeType, uint16_t CodeFlags); - void convertCommandLines(struct EventStruct *event); - # ifdef P16_SETTINGS_V1 - std::vectorCommandLinesV1; // holds the CustomTaskSettings V1, allocated when needed for conversion - # endif // ifdef P16_SETTINGS_V1 - uint64_t iLastCmd = 0; // last command send - uint32_t iLastCmdTime = 0; // time while last command was send - decode_type_t iLastDecodeType = decode_type_t::UNKNOWN; // last decode_type sent - uint16_t iCmdInhibitTime = 0; // inhibit time for sending the same command again - uint16_t iLastCodeFlags = 0; // last flags sent + uint64_t iLastCmd = 0; // last command send + uint32_t iLastCmdTime = 0; // time while last command was send + decode_type_t iLastDecodeType = decode_type_t::UNKNOWN; // last decode_type sent + uint16_t iCmdInhibitTime = 0; // inhibit time for sending the same command again + uint16_t iLastCodeFlags = 0; // last flags sent }; #endif // ifdef USES_P016 diff --git a/src/src/WebServer/CustomPage.cpp b/src/src/WebServer/CustomPage.cpp index b7114b2432..4f77ed7c8e 100644 --- a/src/src/WebServer/CustomPage.cpp +++ b/src/src/WebServer/CustomPage.cpp @@ -142,7 +142,7 @@ bool handle_custom(const String& path) { line.reserve(128); while (available > 0) { uint32_t chunksize = 64; - if (available < chunksize) { + if (available < static_cast(chunksize)) { chunksize = available; } uint8_t buf[64] = {0}; diff --git a/src/src/WebServer/DevicesPage.cpp b/src/src/WebServer/DevicesPage.cpp index 41a6fe057d..15534eeb9c 100644 --- a/src/src/WebServer/DevicesPage.cpp +++ b/src/src/WebServer/DevicesPage.cpp @@ -374,7 +374,16 @@ void handle_devices_CopySubmittedSettings(taskIndex_t taskIndex, pluginID_t task // allow the plugin to save plugin-specific form settings. { String dummy; + if (Device[DeviceIndex].ExitTaskBeforeSave) { + PluginCall(PLUGIN_EXIT, &TempEvent, dummy); + } + PluginCall(PLUGIN_WEBFORM_SAVE, &TempEvent, dummy); + + // Make sure the task needs to reload using the new settings. + if (!Device[DeviceIndex].ExitTaskBeforeSave) { + PluginCall(PLUGIN_EXIT, &TempEvent, dummy); + } } // notify controllers: CPlugin::Function::CPLUGIN_TASK_CHANGE_NOTIFICATION diff --git a/src/src/WebServer/LoadFromFS.cpp b/src/src/WebServer/LoadFromFS.cpp index 8ff857fb64..6781e9959b 100644 --- a/src/src/WebServer/LoadFromFS.cpp +++ b/src/src/WebServer/LoadFromFS.cpp @@ -156,7 +156,7 @@ size_t streamFromFS(String path, bool htmlEscape) { String escaped; while (available > 0) { uint32_t chunksize = 64; - if (available < chunksize) { + if (available < static_cast(chunksize)) { chunksize = available; } uint8_t buf[64] = {0}; diff --git a/src/src/WebServer/WebServer.cpp b/src/src/WebServer/WebServer.cpp index 68244c3ff6..1a921b287b 100644 --- a/src/src/WebServer/WebServer.cpp +++ b/src/src/WebServer/WebServer.cpp @@ -36,6 +36,8 @@ #include "../WebServer/UploadPage.h" #include "../WebServer/WiFiScanner.h" +#include "../WebServer/WebTemplateParser.h" + #include "../../ESPEasy-Globals.h" #include "../../_Plugin_Helper.h" @@ -66,45 +68,6 @@ #include "../Static/WebStaticData.h" -// Determine what pages should be visible -#ifndef MENU_INDEX_MAIN_VISIBLE - # define MENU_INDEX_MAIN_VISIBLE true -#endif // ifndef MENU_INDEX_MAIN_VISIBLE - -#ifndef MENU_INDEX_CONFIG_VISIBLE - # define MENU_INDEX_CONFIG_VISIBLE true -#endif // ifndef MENU_INDEX_CONFIG_VISIBLE - -#ifndef MENU_INDEX_CONTROLLERS_VISIBLE - # define MENU_INDEX_CONTROLLERS_VISIBLE true -#endif // ifndef MENU_INDEX_CONTROLLERS_VISIBLE - -#ifndef MENU_INDEX_HARDWARE_VISIBLE - # define MENU_INDEX_HARDWARE_VISIBLE true -#endif // ifndef MENU_INDEX_HARDWARE_VISIBLE - -#ifndef MENU_INDEX_DEVICES_VISIBLE - # define MENU_INDEX_DEVICES_VISIBLE true -#endif // ifndef MENU_INDEX_DEVICES_VISIBLE - -#ifndef MENU_INDEX_RULES_VISIBLE - # define MENU_INDEX_RULES_VISIBLE true -#endif // ifndef MENU_INDEX_RULES_VISIBLE - -#ifndef MENU_INDEX_NOTIFICATIONS_VISIBLE - # define MENU_INDEX_NOTIFICATIONS_VISIBLE true -#endif // ifndef MENU_INDEX_NOTIFICATIONS_VISIBLE - -#ifndef MENU_INDEX_TOOLS_VISIBLE - # define MENU_INDEX_TOOLS_VISIBLE true -#endif // ifndef MENU_INDEX_TOOLS_VISIBLE - - -#if defined(NOTIFIER_SET_NONE) && defined(MENU_INDEX_NOTIFICATIONS_VISIBLE) - #undef MENU_INDEX_NOTIFICATIONS_VISIBLE - #define MENU_INDEX_NOTIFICATIONS_VISIBLE false -#endif - void safe_strncpy_webserver_arg(char *dest, const String& arg, size_t max_size) { @@ -125,20 +88,20 @@ void sendHeadandTail(const String& tmplName, boolean Tail, boolean rebooting) { } #endif // ifdef USES_TIMING_STATS { - String pageTemplate; String fileName = tmplName; fileName += F(".htm"); fs::File f = tryOpenFile(fileName, "r"); + WebTemplateParser templateParser(Tail, rebooting); if (f) { - pageTemplate.reserve(f.size()); - - while (f.available()) { pageTemplate += (char)f.read(); } + bool success = true; + while (f.available() && success) { + success = templateParser.process((char)f.read()); + } f.close(); } else { - // TODO TD-er: Should send data directly to TXBuffer instead of using large strings. - getWebPageTemplateDefault(tmplName, pageTemplate); + getWebPageTemplateDefault(tmplName, templateParser); } #ifndef BUILD_NO_RAM_TRACKER checkRAM(F("sendWebPage")); @@ -146,55 +109,6 @@ void sendHeadandTail(const String& tmplName, boolean Tail, boolean rebooting) { // web activity timer lastWeb = millis(); - - if (Tail) { - int pos = pageTemplate.indexOf(F("{{content}}")); - if (pos >= 0) { - pos += 11; // Size of "{{content}}" - const int length = pageTemplate.length(); - // Prevent copy'ing the string, just stream directly to the buffer. - for (int i = pos; i < length; ++i) { - addHtml(pageTemplate[i]); - } - } - } else { - int indexStart = 0; - int indexEnd = 0; - int readPos = 0; // Position of data sent to TXBuffer - String varName; // , varValue; - - while ((indexStart = pageTemplate.indexOf(F("{{"), indexStart)) >= 0) { - for (int i = readPos; i < indexStart; ++i) { - addHtml(pageTemplate[i]); - } - readPos = indexStart; - - if ((indexEnd = pageTemplate.indexOf(F("}}"), indexStart)) > 0) { - varName = pageTemplate.substring(indexStart + 2, indexEnd); - indexStart = indexEnd + 2; - readPos = indexEnd + 2; - varName.toLowerCase(); - - if (varName == F("content")) { // is var == page content? - break; // send first part of result only - } else if (varName == F("error")) { - getErrorNotifications(); - } - else if (varName == F("meta")) { - if (rebooting) { - addHtml(F("")); - } - } - else { - getWebPageTemplateVar(varName); - } - } else { // no closing "}}" - // eat "{{" - readPos += 2; - indexStart += 2; - } - } - } } if (shouldReboot) { @@ -432,95 +346,72 @@ void setWebserverRunning(bool state) { CheckRunningServices(); // Uses webserverRunning state. } -void getWebPageTemplateDefault(const String& tmplName, String& tmpl) +void getWebPageTemplateDefault(const String& tmplName, WebTemplateParser& parser) { const bool addJS = true; const bool addMeta = true; if (tmplName == F("TmplAP")) { - static size_t expectedSize = 200; - tmpl.reserve(expectedSize); - getWebPageTemplateDefaultHead(tmpl, !addMeta, !addJS); + getWebPageTemplateDefaultHead(parser, !addMeta, !addJS); #ifndef WEBPAGE_TEMPLATE_AP_HEADER - tmpl += F("
" - "

Welcome to ESP Easy Mega AP

"); + parser.process(F("
" + "

Welcome to ESP Easy Mega AP

")); #else - tmpl += F(WEBPAGE_TEMPLATE_AP_HEADER); + parser.process(F(WEBPAGE_TEMPLATE_AP_HEADER)); #endif - tmpl += F("
"); - getWebPageTemplateDefaultContentSection(tmpl); - getWebPageTemplateDefaultFooter(tmpl); - if (tmpl.length() > expectedSize) { - expectedSize = tmpl.length(); - } + parser.process(F("
")); + getWebPageTemplateDefaultContentSection(parser); + getWebPageTemplateDefaultFooter(parser); } else if (tmplName == F("TmplMsg")) { - static size_t expectedSize = 200; - - tmpl.reserve(expectedSize); - getWebPageTemplateDefaultHead(tmpl, !addMeta, !addJS); - tmpl += F(""); - getWebPageTemplateDefaultHeader(tmpl, F("{{name}}"), false); - getWebPageTemplateDefaultContentSection(tmpl); - getWebPageTemplateDefaultFooter(tmpl); - if (tmpl.length() > expectedSize) { - expectedSize = tmpl.length(); - } + getWebPageTemplateDefaultHead(parser, !addMeta, !addJS); + parser.process(F("")); + getWebPageTemplateDefaultHeader(parser, F("{{name}}"), false); + getWebPageTemplateDefaultContentSection(parser); + getWebPageTemplateDefaultFooter(parser); } else if (tmplName == F("TmplDsh")) { - static size_t expectedSize = 200; - - tmpl.reserve(expectedSize); - getWebPageTemplateDefaultHead(tmpl, !addMeta, addJS); - tmpl += F( + getWebPageTemplateDefaultHead(parser, !addMeta, addJS); + parser.process(F( "" "{{content}}" "" - ); - if (tmpl.length() > expectedSize) { - expectedSize = tmpl.length(); - } + )); } else // all other template names e.g. TmplStd { - static size_t expectedSize = 200; - - tmpl.reserve(expectedSize); - getWebPageTemplateDefaultHead(tmpl, addMeta, addJS); - tmpl += F("" - ""); - getWebPageTemplateDefaultHeader(tmpl, F("{{name}} {{logo}}"), true); - getWebPageTemplateDefaultContentSection(tmpl); - getWebPageTemplateDefaultFooter(tmpl); - if (tmpl.length() > expectedSize) { - expectedSize = tmpl.length(); - } + getWebPageTemplateDefaultHead(parser, addMeta, addJS); + parser.process(F("" + "")); + getWebPageTemplateDefaultHeader(parser, F("{{name}} {{logo}}"), true); + getWebPageTemplateDefaultContentSection(parser); + getWebPageTemplateDefaultFooter(parser); } // addLog(LOG_LEVEL_INFO, String(F("tmpl.length(): ")) + String(tmpl.length())); } -void getWebPageTemplateDefaultHead(String& tmpl, bool addMeta, bool addJS) { - tmpl += F("" +void getWebPageTemplateDefaultHead(WebTemplateParser& parser, bool addMeta, bool addJS) { + parser.process(F("" "" "" "" - "{{name}}"); + "{{name}}")); - if (addMeta) { tmpl += F("{{meta}}"); } + if (addMeta) { parser.process(F("{{meta}}")); } - if (addJS) { tmpl += F("{{js}}"); } + if (addJS) { parser.process(F("{{js}}")); } - tmpl += F("{{css}}" - " "); + parser.process(F("{{css}}" + " ")); } -void getWebPageTemplateDefaultHeader(String& tmpl, const String& title, bool addMenu) { +void getWebPageTemplateDefaultHeader(WebTemplateParser& parser, const String& title, bool addMenu) { { String tmp; #ifndef WEBPAGE_TEMPLATE_DEFAULT_HEADER @@ -538,26 +429,26 @@ void getWebPageTemplateDefaultHeader(String& tmpl, const String& title, bool add #if BUILD_IN_WEBHEADER tmp.replace(F("{{date}}"), get_build_date()); #endif // #if BUILD_IN_WEBHEADER - tmpl += tmp; + parser.process(tmp); } - if (addMenu) { tmpl += F("{{menu}}"); } - tmpl += F(""); + if (addMenu) { parser.process(F("{{menu}}")); } + parser.process(F("")); } -void getWebPageTemplateDefaultContentSection(String& tmpl) { - tmpl += F("
" +void getWebPageTemplateDefaultContentSection(WebTemplateParser& parser) { + parser.process(F("
" "" "{{error}}" "" "{{content}}" "
" - ); + )); } -void getWebPageTemplateDefaultFooter(String& tmpl) { +void getWebPageTemplateDefaultFooter(WebTemplateParser& parser) { #ifndef WEBPAGE_TEMPLATE_DEFAULT_FOOTER - tmpl += F("