From cc81cc27b033b8358b4acc1f4155d51f31b83f5d Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 28 Jun 2025 09:42:52 +0200 Subject: [PATCH] enhancement & bugfixes in scrolling text (#4742) * enhancement & bugfixes in scrolling text - function now evaluates full string: allows custom text plus multiple tokens in any order - fixed evaluation order to prevent early exit(s) - fixed day strings (argument must be weekday() ) --- wled00/FX.cpp | 77 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 22 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 4a364ea65..8bc6d8a1b 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -6091,9 +6091,7 @@ uint16_t mode_2Dscrollingtext(void) { } char text[WLED_MAX_SEGNAME_LEN+1] = {'\0'}; - if (SEGMENT.name) for (size_t i=0,j=0; i31 && SEGMENT.name[i]<128) text[j++] = SEGMENT.name[i]; - const bool zero = strchr(text, '0') != nullptr; - + size_t result_pos = 0; char sec[5]; int AmPmHour = hour(localTime); bool isitAM = true; @@ -6105,27 +6103,62 @@ uint16_t mode_2Dscrollingtext(void) { sprintf_P(sec, PSTR(":%02d"), second(localTime)); } - if (!strlen(text)) { // fallback if empty segment name: display date and time + size_t len = 0; + if (SEGMENT.name) len = strlen(SEGMENT.name); // note: SEGMENT.name is limited to WLED_MAX_SEGNAME_LEN + if (len == 0) { // fallback if empty segment name: display date and time sprintf_P(text, PSTR("%s %d, %d %d:%02d%s"), monthShortStr(month(localTime)), day(localTime), year(localTime), AmPmHour, minute(localTime), sec); } else { - if (text[0] == '#') for (auto &c : text) c = std::toupper(c); - if (!strncmp_P(text,PSTR("#DATE"),5)) sprintf_P(text, zero?PSTR("%02d.%02d.%04d"):PSTR("%d.%d.%d"), day(localTime), month(localTime), year(localTime)); - else if (!strncmp_P(text,PSTR("#DDMM"),5)) sprintf_P(text, zero?PSTR("%02d.%02d") :PSTR("%d.%d"), day(localTime), month(localTime)); - else if (!strncmp_P(text,PSTR("#MMDD"),5)) sprintf_P(text, zero?PSTR("%02d/%02d") :PSTR("%d/%d"), month(localTime), day(localTime)); - else if (!strncmp_P(text,PSTR("#TIME"),5)) sprintf_P(text, zero?PSTR("%02d:%02d%s") :PSTR("%2d:%02d%s"), AmPmHour, minute(localTime), sec); - else if (!strncmp_P(text,PSTR("#HHMM"),5)) sprintf_P(text, zero?PSTR("%02d:%02d") :PSTR("%d:%02d"), AmPmHour, minute(localTime)); - else if (!strncmp_P(text,PSTR("#HH"),3)) sprintf (text, zero? ("%02d") : ("%d"), AmPmHour); - else if (!strncmp_P(text,PSTR("#MM"),3)) sprintf (text, zero? ("%02d") : ("%d"), minute(localTime)); - else if (!strncmp_P(text,PSTR("#SS"),3)) sprintf (text, ("%02d") , second(localTime)); - else if (!strncmp_P(text,PSTR("#DD"),3)) sprintf (text, zero? ("%02d") : ("%d"), day(localTime)); - else if (!strncmp_P(text,PSTR("#DAY"),4)) sprintf (text, ("%s") , dayShortStr(day(localTime))); - else if (!strncmp_P(text,PSTR("#DDDD"),5)) sprintf (text, ("%s") , dayStr(day(localTime))); - else if (!strncmp_P(text,PSTR("#DAYL"),5)) sprintf (text, ("%s") , dayStr(day(localTime))); - else if (!strncmp_P(text,PSTR("#MO"),3)) sprintf (text, zero? ("%02d") : ("%d"), month(localTime)); - else if (!strncmp_P(text,PSTR("#MON"),4)) sprintf (text, ("%s") , monthShortStr(month(localTime))); - else if (!strncmp_P(text,PSTR("#MMMM"),5)) sprintf (text, ("%s") , monthStr(month(localTime))); - else if (!strncmp_P(text,PSTR("#YY"),3)) sprintf (text, ("%02d") , year(localTime)%100); - else if (!strncmp_P(text,PSTR("#YYYY"),5)) sprintf_P(text, zero?PSTR("%04d") : ("%d"), year(localTime)); + size_t i = 0; + while (i < len) { + if (SEGMENT.name[i] == '#') { + char token[7]; // copy up to 6 chars + null terminator + bool zero = false; // a 0 suffix means display leading zeros + size_t j = 0; + while (j < 6 && i + j < len) { + token[j] = std::toupper(SEGMENT.name[i + j]); + if(token[j] == '0') + zero = true; // 0 suffix found. Note: there is an edge case where a '0' could be part of a trailing text and not the token, handling it is not worth the effort + j++; + } + token[j] = '\0'; + int advance = 5; // number of chars to advance in 'text' after processing the token + + // Process token + char temp[32]; + if (!strncmp_P(token,PSTR("#DATE"),5)) sprintf_P(temp, zero?PSTR("%02d.%02d.%04d"):PSTR("%d.%d.%d"), day(localTime), month(localTime), year(localTime)); + else if (!strncmp_P(token,PSTR("#DDMM"),5)) sprintf_P(temp, zero?PSTR("%02d.%02d") :PSTR("%d.%d"), day(localTime), month(localTime)); + else if (!strncmp_P(token,PSTR("#MMDD"),5)) sprintf_P(temp, zero?PSTR("%02d/%02d") :PSTR("%d/%d"), month(localTime), day(localTime)); + else if (!strncmp_P(token,PSTR("#TIME"),5)) sprintf_P(temp, zero?PSTR("%02d:%02d%s") :PSTR("%2d:%02d%s"), AmPmHour, minute(localTime), sec); + else if (!strncmp_P(token,PSTR("#HHMM"),5)) sprintf_P(temp, zero?PSTR("%02d:%02d") :PSTR("%d:%02d"), AmPmHour, minute(localTime)); + else if (!strncmp_P(token,PSTR("#YYYY"),5)) sprintf_P(temp, PSTR("%04d") , year(localTime)); + else if (!strncmp_P(token,PSTR("#MONL"),5)) sprintf (temp, ("%s") , monthStr(month(localTime))); + else if (!strncmp_P(token,PSTR("#DDDD"),5)) sprintf (temp, ("%s") , dayStr(weekday(localTime))); + else if (!strncmp_P(token,PSTR("#YY"),3)) { sprintf (temp, ("%02d") , year(localTime)%100); advance = 3; } + else if (!strncmp_P(token,PSTR("#HH"),3)) { sprintf (temp, zero? ("%02d") : ("%d"), AmPmHour); advance = 3; } + else if (!strncmp_P(token,PSTR("#MM"),3)) { sprintf (temp, zero? ("%02d") : ("%d"), minute(localTime)); advance = 3; } + else if (!strncmp_P(token,PSTR("#SS"),3)) { sprintf (temp, zero? ("%02d") : ("%d"), second(localTime)); advance = 3; } + else if (!strncmp_P(token,PSTR("#MON"),4)) { sprintf (temp, ("%s") , monthShortStr(month(localTime))); advance = 4; } + else if (!strncmp_P(token,PSTR("#MO"),3)) { sprintf (temp, zero? ("%02d") : ("%d"), month(localTime)); advance = 3; } + else if (!strncmp_P(token,PSTR("#DAY"),4)) { sprintf (temp, ("%s") , dayShortStr(weekday(localTime))); advance = 4; } + else if (!strncmp_P(token,PSTR("#DD"),3)) { sprintf (temp, zero? ("%02d") : ("%d"), day(localTime)); advance = 3; } + else { temp[0] = '#'; temp[1] = '\0'; zero = false; advance = 1; } // Unknown token, just copy the # + + if(zero) advance++; // skip the '0' suffix + size_t temp_len = strlen(temp); + if (result_pos + temp_len < WLED_MAX_SEGNAME_LEN) { + strcpy(text + result_pos, temp); + result_pos += temp_len; + } + + i += advance; + } + else { + if (result_pos < WLED_MAX_SEGNAME_LEN) { + text[result_pos++] = SEGMENT.name[i++]; // no token, just copy char + } else + break; // buffer full + } + } } const int numberOfLetters = strlen(text);