diff --git a/src/ESPEasy/net/Globals/NWPlugins.cpp b/src/ESPEasy/net/Globals/NWPlugins.cpp index 41e7494c1..a8df3ce85 100644 --- a/src/ESPEasy/net/Globals/NWPlugins.cpp +++ b/src/ESPEasy/net/Globals/NWPlugins.cpp @@ -439,7 +439,8 @@ bool NWPluginCall(NWPlugin::Function Function, EventStruct *event, String& str) if (event->kvWriter->summaryValueOnly()) { event->kvWriter->write({ EMPTY_STRING, - concat(F("MAC: "), event->networkInterface->macAddress()) }); + concat(F("MAC: "), event->networkInterface->macAddress()), + KeyValueStruct::Format::PreFormatted }); } else { event->kvWriter->write({ @@ -460,7 +461,7 @@ bool NWPluginCall(NWPlugin::Function Function, EventStruct *event, String& str) static_cast(event->Par1), event->networkInterface, prstr); - event->kvWriter->write({ F("ip"), prstr.getMove() }); + event->kvWriter->write({ F("ip"), prstr.getMove(), KeyValueStruct::Format::PreFormatted }); success = true; } break; diff --git a/src/_P126_74HC595.ino b/src/_P126_74HC595.ino index 3f6703dd8..996d22e60 100644 --- a/src/_P126_74HC595.ino +++ b/src/_P126_74HC595.ino @@ -60,6 +60,28 @@ # include "./src/PluginStructs/P126_data_struct.h" +String P126_formatValue(uint32_t value, struct EventStruct *event, bool showSeparatorDot) +{ + const uint8_t base = +# ifdef P126_SHOW_VALUES + P126_CONFIG_FLAGS_GET_VALUES_DISPLAY ? BIN : +# endif // ifdef P126_SHOW_VALUES + HEX; + + const uint8_t minNrDigits = (base == BIN) ? 32 : 8; + const char separatorChar = showSeparatorDot ? '.' : '\0'; + constexpr bool toUpperCase = true; + + return concat( + (base == BIN) ? F("0b") : F("0x"), + ull2String( + value, + base, + minNrDigits, + separatorChar, + toUpperCase)); +} + boolean Plugin_126(uint8_t function, struct EventStruct *event, String& string) { boolean success = false; @@ -272,18 +294,10 @@ boolean Plugin_126(uint8_t function, struct EventStruct *event, String& string) if ((P126_CONFIG_FLAGS_GET_OUTPUT_SELECTION == P126_OUTPUT_BOTH) || (P126_CONFIG_FLAGS_GET_OUTPUT_SELECTION == P126_OUTPUT_HEXBIN)) { - string += '0'; - string += (P126_CONFIG_FLAGS_GET_VALUES_DISPLAY ? 'b' : 'x'); - - string += ul2stringFixed(UserVar.getUint32(event->TaskIndex, event->idx), - # ifdef P126_SHOW_VALUES - (P126_CONFIG_FLAGS_GET_VALUES_DISPLAY ? BIN : - # endif // ifdef P126_SHOW_VALUES - HEX - # ifdef P126_SHOW_VALUES - ) - # endif // ifdef P126_SHOW_VALUES - , 1 == event->ParN[event->idx]); + string += P126_formatValue( + UserVar.getUint32(event->TaskIndex, event->idx), + event, + (1 == event->ParN[event->idx])); } success = true; break; @@ -302,10 +316,8 @@ boolean Plugin_126(uint8_t function, struct EventStruct *event, String& string) for (uint16_t varNr = 0; varNr < maxVar; ++varNr) { if (P126_CONFIG_FLAGS_GET_VALUES_DISPLAY) { label = F("Bin"); - state = F("0b"); } else { label = F("Hex"); - state = F("0x"); } label += strformat(F(" State_%s "), abcd.substring(varNr, varNr + 1).c_str()); @@ -314,7 +326,10 @@ boolean Plugin_126(uint8_t function, struct EventStruct *event, String& string) label += (P126_CONFIG_SHOW_OFFSET + (4 * varNr) + 1); // 4 = nr of bytes in an uint32_t. if ((P126_CONFIG_SHOW_OFFSET + (4 * varNr) + 4) <= endCheck) { // Only show if still in range - state += ul2stringFixed(UserVar.getUint32(event->TaskIndex, varNr), P126_CONFIG_FLAGS_GET_VALUES_DISPLAY ? BIN : HEX, true); + string += P126_formatValue( + UserVar.getUint32(event->TaskIndex, varNr), + event, + true); pluginWebformShowValue(event->TaskIndex, VARS_PER_TASK + varNr, label, state, true); } } diff --git a/src/_P129_74HC165.ino b/src/_P129_74HC165.ino index bf0b73511..17050839c 100644 --- a/src/_P129_74HC165.ino +++ b/src/_P129_74HC165.ino @@ -44,6 +44,29 @@ # include "./src/PluginStructs/P129_data_struct.h" +String P129_formatValue(uint32_t value, struct EventStruct *event, bool showSeparatorDot) +{ + const uint8_t base = +# ifdef P129_SHOW_VALUES + P129_CONFIG_FLAGS_GET_VALUES_DISPLAY ? BIN : +# endif // ifdef P126_SHOW_VALUES + HEX; + + const uint8_t minNrDigits = (base == BIN) ? 32 : 8; + const char separatorChar = showSeparatorDot ? '.' : '\0'; + constexpr bool toUpperCase = true; + + return concat( + (base == BIN) ? F("0b") : F("0x"), + ull2String( + value, + base, + minNrDigits, + separatorChar, + toUpperCase)); +} + + boolean Plugin_129(uint8_t function, struct EventStruct *event, String& string) { boolean success = false; @@ -232,7 +255,10 @@ boolean Plugin_129(uint8_t function, struct EventStruct *event, String& string) # ifdef P129_DEBUG_LOG if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLog(LOG_LEVEL_INFO, strformat(F("74HC165 Reading from: %d, bits: %s"), i / 4, ul2stringFixed(bits, BIN, false).c_str())); + addLog(LOG_LEVEL_INFO, strformat( + F("74HC165 Reading from: %d, bits: %s"), + i / 4, + ull2String(bits, BIN, 32, '\0', true).c_str())); } # endif // ifdef P129_DEBUG_LOG } @@ -305,7 +331,7 @@ boolean Plugin_129(uint8_t function, struct EventStruct *event, String& string) addLog(LOG_LEVEL_INFO, strformat(F("74HC165 Writing to: %d, offset: %d, bits: %s"), i / 4, off * 8, - ul2stringFixed(bits, BIN, false).c_str())); + ull2String(bits, BIN, 32, '\0', true).c_str())); } # endif // ifdef P129_DEBUG_LOG off++; @@ -378,18 +404,10 @@ boolean Plugin_129(uint8_t function, struct EventStruct *event, String& string) if ((P129_CONFIG_FLAGS_GET_OUTPUT_SELECTION == P129_OUTPUT_BOTH) || (P129_CONFIG_FLAGS_GET_OUTPUT_SELECTION == P129_OUTPUT_HEXBIN)) { - string += '0'; - string += (P129_CONFIG_FLAGS_GET_VALUES_DISPLAY ? 'b' : 'x'); - - string += ul2stringFixed(UserVar.getUint32(event->TaskIndex, event->idx), - # ifdef P129_SHOW_VALUES - (P129_CONFIG_FLAGS_GET_VALUES_DISPLAY ? BIN : - # endif // ifdef P129_SHOW_VALUES - HEX - # ifdef P129_SHOW_VALUES - ) - # endif // ifdef P129_SHOW_VALUES - , 1 == event->ParN[event->idx]); + string += P129_formatValue( + UserVar.getUint32(event->TaskIndex, event->idx), + event, + (1 == event->ParN[event->idx])); } success = true; break; @@ -419,7 +437,10 @@ boolean Plugin_129(uint8_t function, struct EventStruct *event, String& string) label += (P129_CONFIG_SHOW_OFFSET + (4 * varNr) + 1); // 4 = nr of bytes in an uint32_t. if ((P129_CONFIG_SHOW_OFFSET + (4 * varNr) + 4) <= endCheck) { // Only show if still in range - state += ul2stringFixed(UserVar.getUint32(event->TaskIndex, varNr), P129_CONFIG_FLAGS_GET_VALUES_DISPLAY ? BIN : HEX, true); + string += P129_formatValue( + UserVar.getUint32(event->TaskIndex, varNr), + event, + true); pluginWebformShowValue(event->TaskIndex, VARS_PER_TASK + varNr, label, state, true); } } diff --git a/src/src/Helpers/StringConverter_Numerical.cpp b/src/src/Helpers/StringConverter_Numerical.cpp index 53b302f55..8e1cf1bad 100644 --- a/src/src/Helpers/StringConverter_Numerical.cpp +++ b/src/src/Helpers/StringConverter_Numerical.cpp @@ -59,19 +59,38 @@ bool toValidString(String& str, return doubleToValidString(str, value_d, decimalPlaces, trimTrailingZeros); } - -String ull2String(uint64_t value, uint8_t base) { +String ull2String(uint64_t value, + uint8_t base, + uint8_t minNrDigits, + char separatorChar, + bool toUpperCase) +{ String res; - if (value == 0) { - res = '0'; - return res; - } - while (value > 0) { res += String(static_cast(value % base), base); value /= base; } + // String representation is still reversed, so pad instead of prefix + padToMinimumLength(res, minNrDigits, '0'); + + if (separatorChar != '\0') { + // Need to insert separator chars, starting from the 'right' of the string + // However the string is still in reversed order, which makes it rather easy. + const uint32_t byteGroupLength = (base == DEC) ? 3 : (base == HEX) ? 2 : 8; + const auto length = res.length(); + + String tmp; + tmp.reserve(res.length() + (minNrDigits / byteGroupLength) - 1); + + for (uint8_t i = 0; i < length; ++i) { + if (i != 0 && i % byteGroupLength == 0) { + tmp += separatorChar; + } + tmp += res[i]; + } + res = std::move(tmp); + } int endpos = res.length() - 1; int beginpos = 0; @@ -84,52 +103,27 @@ String ull2String(uint64_t value, uint8_t base) { --endpos; } + if (toUpperCase && base == HEX) { + res.toUpperCase(); + } + return res; } -String ll2String(int64_t value, uint8_t base) { - if (value < 0) { - return concat('-', ull2String(value * -1ll, base)); - } else { - return ull2String(value, base); +String ll2String(int64_t value, + uint8_t base, + uint8_t minNrDigits, + char separatorChar, + bool toUpperCase) +{ + if (value >= 0) { + return ull2String(value, base, minNrDigits, separatorChar, toUpperCase); } + return concat( + '-', + ull2String(value * -1ll, base, minNrDigits, separatorChar, toUpperCase)); } -/** - * format an uint32_t with 0-prefixed in the provided base of 2, 16 and insert an optional dot as separator for each byte - * separator only applied for base 2 and 16 - */ -String ul2stringFixed(uint32_t value, uint8_t base, bool dotSeparator) { - // Set bit just left of 32 bits so we will see the leading zeroes - const uint64_t val = static_cast(value) | 0x100000000ull; - - String valStr = ull2String(val, base).substring(1); // Delete leading 1 we added - - if (base == HEX) { - valStr.toUpperCase(); // uppercase hex for readability - } - - if (dotSeparator) { - uint8_t dotInsert{}; - uint8_t dotOffset{}; - - if (BIN == base) { - dotInsert = 10; - dotOffset = 9; - } else - if (HEX == base) { - dotInsert += 4; - dotOffset = 3; - } - - if (dotInsert) { - for (uint8_t i = 0; i < 3; ++i, dotInsert += dotOffset) { // Insert readability separators - valStr = valStr.substring(0, dotInsert) + '.' + valStr.substring(dotInsert); - } - } - } - return valStr; -} String trimTrailingZeros(const String& value) { String res(value); diff --git a/src/src/Helpers/StringConverter_Numerical.h b/src/src/Helpers/StringConverter_Numerical.h index e7f0c3bd1..2572642da 100644 --- a/src/src/Helpers/StringConverter_Numerical.h +++ b/src/src/Helpers/StringConverter_Numerical.h @@ -29,15 +29,22 @@ bool toValidString(String& str, bool trimTrailingZeros = false); +// Create a string from given value represented in 'base' +// For HEX or BIN representation, the separation will be per byte from the right. +// For base 10 (DEC) the separator char will be placed every 3rd position from the right. +// When extending the string to contain minNrDigits, zeroes will be prefixed. String ull2String(uint64_t value, - uint8_t base = 10); + uint8_t base = 10, + uint8_t minNrDigits = 1, + char separatorChar = '\0', + bool toUpperCase = false); -String ll2String(int64_t value, - uint8_t base = 10); -String ul2stringFixed(uint32_t value, - uint8_t base, - bool dotSeparator); +String ll2String(int64_t value, + uint8_t base = 10, + uint8_t minNrDigits = 1, + char separatorChar = '\0', + bool toUpperCase = false); String trimTrailingZeros(const String& value); diff --git a/src/src/PluginStructs/P073_data_struct.cpp b/src/src/PluginStructs/P073_data_struct.cpp index a78e77b14..36faff2d4 100644 --- a/src/src/PluginStructs/P073_data_struct.cpp +++ b/src/src/PluginStructs/P073_data_struct.cpp @@ -554,24 +554,20 @@ void P073_data_struct::setTextToScroll(const String& text) { if (!text.isEmpty()) { const int bufToFill = P073_getDefaultDigits(displayModel, digits); - _textToScroll.reserve(text.length() + bufToFill + (scrollFull ? bufToFill : 0)); - - for (int i = 0; scrollFull && i < bufToFill; ++i) { // Scroll text in from the right, so start with all spaces - _textToScroll += + const char fillChar = # if P073_7DBIN_COMMAND binaryData ? (char)0x00 : # endif // if P073_7DBIN_COMMAND ' '; - } - _textToScroll += text; - for (int i = 0; i < bufToFill; ++i) { // Scroll text off completely before restarting - _textToScroll += - # if P073_7DBIN_COMMAND - binaryData ? (char)0x00 : - # endif // if P073_7DBIN_COMMAND - ' '; + _textToScroll = text; + + if (scrollFull) { + // Scroll text in from the right, so start with all spaces + prefixToMinimumLength(_textToScroll, _textToScroll.length() + bufToFill, fillChar); } + // Scroll text off completely before restarting + padToMinimumLength(_textToScroll, _textToScroll.length() + bufToFill, fillChar); } scrollCount = _scrollSpeed; scrollPos = 0; diff --git a/src/src/WebServer/KeyValueWriter_WebForm.cpp b/src/src/WebServer/KeyValueWriter_WebForm.cpp index 918a6f0e9..4320777fe 100644 --- a/src/src/WebServer/KeyValueWriter_WebForm.cpp +++ b/src/src/WebServer/KeyValueWriter_WebForm.cpp @@ -68,8 +68,7 @@ void KeyValueWriter_WebForm::write(const KeyValueStruct& kv) const size_t nrValues = kv._values.size(); const bool format_pre = !plain_text && - - // !summary_value_only && + !summary_value_only && (nrValues > 1 || kv._format == KeyValueStruct::Format::PreFormatted); const bool format_note =