From ef80abd88509856a0426735743ebc39ceda2952e Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 4 Sep 2024 11:38:03 +0200 Subject: [PATCH 001/234] 8266 compatibility builds for older chips (another attempt t o solve #3690 and #3685) some users have reported that releases after 0.14.0 are not working reliably. So we add a few "compat" for 8266 that try to reproduce the buildenv of 0.14.0 as much as possible. * platform and platform_packages from 0.14.0 * not using PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48 * due to smaller IRAM, we had to move some functions back from IRAM to normal flash (may cause slowdown) --- platformio.ini | 44 +++++++++++++++++++++++++++++++++++++++++++- wled00/FX_2Dfcn.cpp | 4 ++-- wled00/FX_fcn.cpp | 3 ++- wled00/const.h | 8 ++++++++ 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/platformio.ini b/platformio.ini index cbe13c0dd..d19f47764 100644 --- a/platformio.ini +++ b/platformio.ini @@ -11,7 +11,7 @@ # CI binaries ; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth # ESP32 variant builds are temporarily excluded from CI due to toolchain issues on the GitHub Actions Linux environment -default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, esp32dev, esp32_eth, esp32dev_audioreactive, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB, esp32s3dev_8MB_PSRAM_opi +default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, esp32dev, esp32_eth, esp32dev_audioreactive, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB, esp32s3dev_8MB_PSRAM_opi # Release binaries ; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB @@ -226,6 +226,27 @@ lib_deps = ESPAsyncUDP ${env.lib_deps} +;; compatibilty flags - same as 0.14.0 which seems to work better on some 8266 boards. Not using PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48 +build_flags_compat = + -DESP8266 + -DFP_IN_IROM + ;;-Wno-deprecated-declarations + -Wno-misleading-indentation + ;;-Wno-attributes ;; silence warnings about unknown attribute 'maybe_unused' in NeoPixelBus + -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703 + -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH + -DVTABLES_IN_FLASH + -DMIMETYPE_MINIMAL + -DWLED_SAVE_IRAM ;; needed to prevent linker error + +;; this platform version was used for WLED 0.14.0 +platform_compat = espressif8266@4.2.0 +platform_packages_compat = + platformio/toolchain-xtensa @ ~2.100300.220621 #2.40802.200502 + platformio/tool-esptool #@ ~1.413.0 + platformio/tool-esptoolpy #@ ~1.30000.0 + + [esp32] #platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.3/platform-espressif32-2.0.2.3.zip platform = espressif32@3.5.0 @@ -336,6 +357,13 @@ build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP8266 #-DWLED lib_deps = ${esp8266.lib_deps} monitor_filters = esp8266_exception_decoder +[env:nodemcuv2_compat] +extends = env:nodemcuv2 +;; using platform version and build options from WLED 0.14.0 +platform = ${esp8266.platform_compat} +platform_packages = ${esp8266.platform_packages_compat} +build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=ESP8266_compat #-DWLED_DISABLE_2D + [env:nodemcuv2_160] extends = env:nodemcuv2 board_build.f_cpu = 160000000L @@ -350,6 +378,13 @@ build_unflags = ${common.build_unflags} build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP02 lib_deps = ${esp8266.lib_deps} +[env:esp8266_2m_compat] +extends = env:esp8266_2m +;; using platform version and build options from WLED 0.14.0 +platform = ${esp8266.platform_compat} +platform_packages = ${esp8266.platform_packages_compat} +build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=ESP02_compat #-DWLED_DISABLE_2D + [env:esp8266_2m_160] extends = env:esp8266_2m board_build.f_cpu = 160000000L @@ -365,6 +400,13 @@ build_flags = ${common.build_flags_esp8266} -D WLED_RELEASE_NAME=ESP01 -D WLED_D ; -D WLED_USE_UNREAL_MATH ;; may cause wrong sunset/sunrise times, but saves 7064 bytes FLASH and 975 bytes RAM lib_deps = ${esp8266.lib_deps} +[env:esp01_1m_full_compat] +extends = env:esp01_1m_full +;; using platform version and build options from WLED 0.14.0 +platform = ${esp8266.platform_compat} +platform_packages = ${esp8266.platform_packages_compat} +build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=ESP01_compat -D WLED_DISABLE_OTA #-DWLED_DISABLE_2D + [env:esp01_1m_full_160] extends = env:esp01_1m_full board_build.f_cpu = 160000000L diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 5dc9e9ff2..918ce61e2 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -163,14 +163,14 @@ void WS2812FX::setUpMatrix() { #ifndef WLED_DISABLE_2D // XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element) -uint16_t IRAM_ATTR Segment::XY(uint16_t x, uint16_t y) +uint16_t IRAM_ATTR_YN Segment::XY(uint16_t x, uint16_t y) { uint16_t width = virtualWidth(); // segment width in logical pixels (can be 0 if segment is inactive) uint16_t height = virtualHeight(); // segment height in logical pixels (is always >= 1) return isActive() ? (x%width) + (y%height) * width : 0; } -void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col) +void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) { if (!isActive()) return; // not active if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 10847ef57..58e2fdfa5 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -145,6 +145,7 @@ Segment& Segment::operator= (Segment &&orig) noexcept { } bool Segment::allocateData(size_t len) { + if (len == 0) return false; // nothing to do if (data && _dataLen >= len) { // already allocated enough (reduce fragmentation) if (call == 0) memset(data, 0, len); // erase buffer if called during effect initialisation return true; @@ -659,7 +660,7 @@ uint16_t Segment::virtualLength() const { return vLength; } -void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col) +void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) { if (!isActive()) return; // not active #ifndef WLED_DISABLE_2D diff --git a/wled00/const.h b/wled00/const.h index 388b64c82..97bfcff1b 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -540,4 +540,12 @@ #define HW_PIN_MISOSPI MISO #endif +// IRAM_ATTR for 8266 with 32Kb IRAM causes error: section `.text1' will not fit in region `iram1_0_seg' +// this hack removes the IRAM flag for some 1D/2D functions - somewhat slower, but it solves problems with some older 8266 chips +#ifdef WLED_SAVE_IRAM + #define IRAM_ATTR_YN +#else + #define IRAM_ATTR_YN IRAM_ATTR +#endif + #endif From dc90a4ed42702e608b1f1482a541a4adbd1ae1ac Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Wed, 4 Sep 2024 21:17:21 +0200 Subject: [PATCH 002/234] Mirroring bugfix. --- wled00/FX_2Dfcn.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 918ce61e2..1461a1a9e 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -214,7 +214,7 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) else strip.setPixelColorXY(start + xX, startY + height() - yY - 1, tmpCol); } if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel - strip.setPixelColorXY(width() - xX - 1, height() - yY - 1, tmpCol); + strip.setPixelColorXY(start + width() - xX - 1, startY + height() - yY - 1, tmpCol); } } } From 058e66c7fcc8b8ea568c777f7574f1295d82d4e2 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 10 Sep 2024 20:32:40 +0200 Subject: [PATCH 003/234] Update CONTRIBUTING.md - adding a hint to avoid force-pushing --- CONTRIBUTING.md | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 168131160..8ab9bb9f0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,6 +16,20 @@ A good description helps us to review and understand your proposed changes. For Please make all PRs against the `0_15` branch. +### Updating your code +While the PR is open - and under review by maintainers - you may be asked to modify your PR source code. +You can simply update your own branch, and push changes in response to reviewer recommendations. +Github will pick up the changes so your PR stays up-to-date. + +> [!CAUTION] +> Do not use "force-push" while your PR is open! +> It has many subtle and unexpected consequences on our github reposistory. +> For example, we regularly lost review comments when the PR author force-pushes code changes. So, pretty please, do not force-push. + + +You kan find a collection of very usefull tips and tricks here: https://github.com/Aircoookie/WLED/wiki/How-to-properly-submit-a-PR + + ### Code style When in doubt, it is easiest to replicate the code style you find in the files you want to edit :) @@ -37,6 +51,11 @@ if (a == b) { } ``` +```cpp +if (a == b) doStuff(a); +``` + +Acceptable - however the first variant is usually easier to read: ```cpp if (a == b) { @@ -44,9 +63,6 @@ if (a == b) } ``` -```cpp -if (a == b) doStuff(a); -``` There should always be a space between a keyword and its condition and between the condition and brace. Within the condition, no space should be between the paranthesis and variables. From 2cfd2e1410f2ebed85df0e56fef658ee018f6266 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 10 Sep 2024 20:36:18 +0200 Subject: [PATCH 004/234] Update CONTRIBUTING.md - typo --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8ab9bb9f0..9b1affbc3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,7 +27,7 @@ Github will pick up the changes so your PR stays up-to-date. > For example, we regularly lost review comments when the PR author force-pushes code changes. So, pretty please, do not force-push. -You kan find a collection of very usefull tips and tricks here: https://github.com/Aircoookie/WLED/wiki/How-to-properly-submit-a-PR +You can find a collection of very useful tips and tricks here: https://github.com/Aircoookie/WLED/wiki/How-to-properly-submit-a-PR ### Code style From c3f472fbcb0d766f8c6cce1bf8841770b4b15bac Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Wed, 11 Sep 2024 21:41:42 +0200 Subject: [PATCH 005/234] some improvements to consider no real difference in FPS but code is faster. also 160bytes smaller, meaning it is actually faster --- wled00/FX_2Dfcn.cpp | 25 +++++++++--------- wled00/colors.cpp | 62 +++++++++++++++++++++++++++++++++++++------- wled00/fcn_declare.h | 2 ++ 3 files changed, 67 insertions(+), 22 deletions(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 26ec1d608..ae76379ed 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -173,11 +173,6 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) if (!isActive()) return; // not active if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit - uint8_t _bri_t = currentBri(); - if (_bri_t < 255) { - col = color_fade(col, _bri_t); - } - if (reverse ) x = virtualWidth() - x - 1; if (reverse_y) y = virtualHeight() - y - 1; if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed @@ -189,7 +184,11 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) int H = height(); if (x >= W || y >= H) return; // if pixel would fall out of segment just exit - uint32_t tmpCol = col; + uint8_t _bri_t = currentBri(); + if (_bri_t < 255) { + col = color_fade(col, _bri_t); + } + for (int j = 0; j < grouping; j++) { // groupping vertically for (int g = 0; g < grouping; g++) { // groupping horizontally int xX = (x+g), yY = (y+j); @@ -197,21 +196,21 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) #ifndef WLED_DISABLE_MODE_BLEND // if blending modes, blend with underlying pixel - if (_modeBlend) tmpCol = color_blend(strip.getPixelColorXY(start + xX, startY + yY), col, 0xFFFFU - progress(), true); + if (_modeBlend) col = color_blend(strip.getPixelColorXY(start + xX, startY + yY), col, 0xFFFFU - progress(), true); #endif - strip.setPixelColorXY(start + xX, startY + yY, tmpCol); + strip.setPixelColorXY(start + xX, startY + yY, col); if (mirror) { //set the corresponding horizontally mirrored pixel - if (transpose) strip.setPixelColorXY(start + xX, startY + height() - yY - 1, tmpCol); - else strip.setPixelColorXY(start + width() - xX - 1, startY + yY, tmpCol); + if (transpose) strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col); + else strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col); } if (mirror_y) { //set the corresponding vertically mirrored pixel - if (transpose) strip.setPixelColorXY(start + width() - xX - 1, startY + yY, tmpCol); - else strip.setPixelColorXY(start + xX, startY + height() - yY - 1, tmpCol); + if (transpose) strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col); + else strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col); } if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel - strip.setPixelColorXY(start + width() - xX - 1, startY + height() - yY - 1, tmpCol); + strip.setPixelColorXY(start + width() - xX - 1, startY + height() - yY - 1, col); } } } diff --git a/wled00/colors.cpp b/wled00/colors.cpp index ac1dee00a..791aad982 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -72,25 +72,69 @@ uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) { if (c1 == BLACK || amount + video == 0) return BLACK; uint32_t scaledcolor; // color order is: W R G B from MSB to LSB - uint32_t r = R(c1); - uint32_t g = G(c1); - uint32_t b = B(c1); - uint32_t w = W(c1); uint32_t scale = amount; // 32bit for faster calculation if (video) { + uint32_t r = R(c1); + uint32_t g = G(c1); + uint32_t b = B(c1); + uint32_t w = W(c1); scaledcolor = (((r * scale) >> 8) + ((r && scale) ? 1 : 0)) << 16; scaledcolor |= (((g * scale) >> 8) + ((g && scale) ? 1 : 0)) << 8; scaledcolor |= ((b * scale) >> 8) + ((b && scale) ? 1 : 0); scaledcolor |= (((w * scale) >> 8) + ((w && scale) ? 1 : 0)) << 24; - } else { - scaledcolor = ((r * scale) >> 8) << 16; - scaledcolor |= ((g * scale) >> 8) << 8; - scaledcolor |= (b * scale) >> 8; - scaledcolor |= ((w * scale) >> 8) << 24; + } else { // according to compile explorer, this is 15% faster but cannot be used for video (its not faster if the assignments are seperated) + uint32_t r = (((c1&0x00FF0000) * scale) >> 8) & 0x00FF0000; + uint32_t g = (((c1&0x0000FF00) * scale) >> 8) & 0x0000FF00; + uint32_t b = ((c1&0x000000FF) * scale) >> 8; + uint32_t w = (((c1 & 0xFF000000) >> 8) * scale) & 0xFF000000; // Scale w and keep it in position + scaledcolor = r | g | b | w; } return scaledcolor; } +// 1:1 replacement of fastled function optimized for ESP, slightly faster, more accurate and uses less flash (~ -200bytes) +CRGB ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brightness, TBlendType blendType) +{ + if ( blendType == LINEARBLEND_NOWRAP) { + //index = map8(index, 0, 239); + index = (index*240) >> 8; // Blend range is affected by lo4 blend of values, remap to avoid wrapping + } + unsigned hi4 = byte(index) >> 4; + unsigned lo4 = index & 0x0F; + unsigned hi4XsizeofCRGB = hi4 * sizeof(CRGB); + // We then add that to a base array pointer. + const CRGB* entry = (CRGB*)( (uint8_t*)(&(pal[0])) + hi4XsizeofCRGB); + unsigned red1 = entry->red; + unsigned green1 = entry->green; + unsigned blue1 = entry->blue; + if(blendType != NOBLEND) { + if(hi4 == 15) entry = &(pal[0]); + else ++entry; + unsigned red2 = entry->red; + unsigned green2 = entry->green; + unsigned blue2 = entry->blue; + unsigned f2 = (lo4 << 4)+1; // +1 so we scale by 256 as a max value, then result can just be shifted by 8 + unsigned f1 = (257 - f2); // f2 is 1 minimum, so this is 256 max + red1 *= f1; + green1 *= f1; + blue1 *= f1; + red2 *= f2; + green2 *= f2; + blue2 *= f2; + red1 = (red1 + red2) >> 8; + green1 = (green1 + green2) >> 8; + blue1 = (blue1 + blue2) >> 8; + } + if( brightness != 255) { // note: zero checking could be done to return black but that is hardly ever used so it is omitted + uint32_t scale = brightness; + scale++; // adjust for rounding (bitshift) + red1 = (red1 * scale) >> 8; + green1 = (green1 * scale) >> 8; + blue1 = (blue1 * scale) >> 8; + } + return CRGB((uint8_t)red1, (uint8_t)green1, (uint8_t)blue1); +} + void setRandomColor(byte* rgb) { lastRandomIndex = get_random_wheel_index(lastRandomIndex); diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index f8399b1ad..2f9bc44d0 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -66,6 +66,7 @@ typedef struct WiFiConfig { } wifi_config; //colors.cpp +#define ColorFromPalette ColorFromPaletteWLED // override fastled version // similar to NeoPixelBus NeoGammaTableMethod but allows dynamic changes (superseded by NPB::NeoGammaDynamicTableMethod) class NeoGammaWLEDMethod { public: @@ -81,6 +82,7 @@ class NeoGammaWLEDMethod { [[gnu::hot]] uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false); [[gnu::hot]] uint32_t color_add(uint32_t,uint32_t, bool fast=false); [[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); +CRGB ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND); CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette); CRGBPalette16 generateRandomPalette(); inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); } From 934176818f32ffa0ffe359192dbf7d769c3e740f Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 12 Sep 2024 06:43:20 +0200 Subject: [PATCH 006/234] more improvements to color_scale() now even faster. tested and working, also tested video --- wled00/colors.cpp | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 791aad982..c3ac0cb61 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -70,25 +70,22 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool fast) uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) { - if (c1 == BLACK || amount + video == 0) return BLACK; + if (c1 == BLACK || amount == 0) return BLACK; + else if (amount == 255) return c1; + video = true; uint32_t scaledcolor; // color order is: W R G B from MSB to LSB uint32_t scale = amount; // 32bit for faster calculation - if (video) { - uint32_t r = R(c1); - uint32_t g = G(c1); - uint32_t b = B(c1); - uint32_t w = W(c1); - scaledcolor = (((r * scale) >> 8) + ((r && scale) ? 1 : 0)) << 16; - scaledcolor |= (((g * scale) >> 8) + ((g && scale) ? 1 : 0)) << 8; - scaledcolor |= ((b * scale) >> 8) + ((b && scale) ? 1 : 0); - scaledcolor |= (((w * scale) >> 8) + ((w && scale) ? 1 : 0)) << 24; - } else { // according to compile explorer, this is 15% faster but cannot be used for video (its not faster if the assignments are seperated) - uint32_t r = (((c1&0x00FF0000) * scale) >> 8) & 0x00FF0000; - uint32_t g = (((c1&0x0000FF00) * scale) >> 8) & 0x0000FF00; - uint32_t b = ((c1&0x000000FF) * scale) >> 8; - uint32_t w = (((c1 & 0xFF000000) >> 8) * scale) & 0xFF000000; // Scale w and keep it in position - scaledcolor = r | g | b | w; + uint32_t addRemains = 0; + if (!video) amount++; // add one for correct scaling using bitshifts + else { // video scaling: make sure colors do not dim to zero if they started non-zero + addRemains = R(c1) ? 0x00010000 : 0; + addRemains |= G(c1) ? 0x00000100 : 0; + addRemains |= B(c1) ? 0x00000001 : 0; + addRemains |= W(c1) ? 0x01000000 : 0; } + uint32_t rb = (((c1 & 0x00FF00FF) * scale) >> 8) & 0x00FF00FF; // scale red and blue + uint32_t wg = (((c1 & 0xFF00FF00) >> 8) * scale) & 0xFF00FF00; // scale white and green + scaledcolor = (rb | wg) + addRemains; return scaledcolor; } From feac45fd0aed860235aef4e03fe91c5b49f95a89 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 12 Sep 2024 07:45:49 +0200 Subject: [PATCH 007/234] improvement in color_add its not faster but cleaner (and uses less flash) --- wled00/colors.cpp | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index c3ac0cb61..960cef313 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -39,21 +39,17 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool fast) { if (c1 == BLACK) return c2; if (c2 == BLACK) return c1; - if (fast) { - uint8_t r = R(c1); - uint8_t g = G(c1); - uint8_t b = B(c1); - uint8_t w = W(c1); - r = qadd8(r, R(c2)); - g = qadd8(g, G(c2)); - b = qadd8(b, B(c2)); - w = qadd8(w, W(c2)); + uint32_t r = R(c1) + R(c2); + uint32_t g = G(c1) + G(c2); + uint32_t b = B(c1) + B(c2); + uint32_t w = W(c1) + W(c2); + if (fast) { + r = r > 255 ? 255 : r; + g = g > 255 ? 255 : g; + b = b > 255 ? 255 : b; + w = w > 255 ? 255 : w; return RGBW32(r,g,b,w); } else { - uint32_t r = R(c1) + R(c2); - uint32_t g = G(c1) + G(c2); - uint32_t b = B(c1) + B(c2); - uint32_t w = W(c1) + W(c2); unsigned max = r; if (g > max) max = g; if (b > max) max = b; @@ -72,7 +68,6 @@ uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) { if (c1 == BLACK || amount == 0) return BLACK; else if (amount == 255) return c1; - video = true; uint32_t scaledcolor; // color order is: W R G B from MSB to LSB uint32_t scale = amount; // 32bit for faster calculation uint32_t addRemains = 0; From 992d11be105ac00380874a11f6ba33e9acfc24e1 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 12 Sep 2024 08:28:30 +0200 Subject: [PATCH 008/234] Improvements in get/set PixelColor() -calculations for virtual strips are done on each call, which is unnecessary. moved them into the if statement. --- wled00/FX_fcn.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index d3521c90c..4364b9f43 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -705,11 +705,16 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) { if (!isActive()) return; // not active #ifndef WLED_DISABLE_2D - int vStrip = i>>16; // hack to allow running on virtual strips (2D segment columns/rows) + int vStrip; #endif - i &= 0xFFFF; - - if (i >= virtualLength() || i<0) return; // if pixel would fall out of segment just exit + if (i >= virtualLength() || i<0) // pixel would fall out of segment, check if this is a virtual strip NOTE: this is almost always false if not virtual strip, saves the calculation on 'standard' call + { + #ifndef WLED_DISABLE_2D + vStrip = i>>16; // hack to allow running on virtual strips (2D segment columns/rows) + #endif + i &= 0xFFFF; //truncate vstrip index + if (i >= virtualLength() || i<0) return; // if pixel would still fall out of segment just exit + } #ifndef WLED_DISABLE_2D if (is2D()) { @@ -900,8 +905,7 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const if (!isActive()) return 0; // not active #ifndef WLED_DISABLE_2D int vStrip = i>>16; -#endif - i &= 0xFFFF; +#endif #ifndef WLED_DISABLE_2D if (is2D()) { @@ -912,7 +916,7 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const return getPixelColorXY(i % vW, i / vW); break; case M12_pBar: - if (vStrip>0) return getPixelColorXY(vStrip - 1, vH - i -1); + if (vStrip>0) { i &= 0xFFFF; return getPixelColorXY(vStrip - 1, vH - i -1); } else return getPixelColorXY(0, vH - i -1); break; case M12_pArc: From b07658b46060c73c4bd94a9a4e4289d44639c173 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 12 Sep 2024 14:09:09 +0200 Subject: [PATCH 009/234] improved Segment::setPixelColorXY a tiny bit uses less flash so it should be faster (did not notice any FPS difference though) also cleaned code in ColorFromPaletteWLED (it is not faster, same amount of code) --- wled00/FX_2Dfcn.cpp | 30 ++++++++++++++---------------- wled00/colors.cpp | 33 +++++++++++---------------------- 2 files changed, 25 insertions(+), 38 deletions(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index ae76379ed..01410b811 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -173,34 +173,30 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) if (!isActive()) return; // not active if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit - if (reverse ) x = virtualWidth() - x - 1; - if (reverse_y) y = virtualHeight() - y - 1; - if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed - - x *= groupLength(); // expand to physical pixels - y *= groupLength(); // expand to physical pixels - - int W = width(); - int H = height(); - if (x >= W || y >= H) return; // if pixel would fall out of segment just exit - uint8_t _bri_t = currentBri(); if (_bri_t < 255) { col = color_fade(col, _bri_t); } + if (reverse ) x = virtualWidth() - x - 1; + if (reverse_y) y = virtualHeight() - y - 1; + if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed + x *= groupLength(); // expand to physical pixels + y *= groupLength(); // expand to physical pixels + int W = width(); + int H = height(); + + int yY = y; for (int j = 0; j < grouping; j++) { // groupping vertically + if(yY >= H) continue; + int xX = x; for (int g = 0; g < grouping; g++) { // groupping horizontally - int xX = (x+g), yY = (y+j); - if (xX >= W || yY >= H) continue; // we have reached one dimension's end - + if (xX >= W) continue; // we have reached one dimension's end #ifndef WLED_DISABLE_MODE_BLEND // if blending modes, blend with underlying pixel if (_modeBlend) col = color_blend(strip.getPixelColorXY(start + xX, startY + yY), col, 0xFFFFU - progress(), true); #endif - strip.setPixelColorXY(start + xX, startY + yY, col); - if (mirror) { //set the corresponding horizontally mirrored pixel if (transpose) strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col); else strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col); @@ -212,7 +208,9 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel strip.setPixelColorXY(start + width() - xX - 1, startY + height() - yY - 1, col); } + xX++; } + yY++; } } diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 960cef313..b6cb3ac51 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -92,34 +92,23 @@ CRGB ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brig index = (index*240) >> 8; // Blend range is affected by lo4 blend of values, remap to avoid wrapping } unsigned hi4 = byte(index) >> 4; - unsigned lo4 = index & 0x0F; - unsigned hi4XsizeofCRGB = hi4 * sizeof(CRGB); // We then add that to a base array pointer. - const CRGB* entry = (CRGB*)( (uint8_t*)(&(pal[0])) + hi4XsizeofCRGB); - unsigned red1 = entry->red; - unsigned green1 = entry->green; - unsigned blue1 = entry->blue; + const CRGB* entry = (CRGB*)( (uint8_t*)(&(pal[0])) + (hi4 * sizeof(CRGB))); + unsigned red1 = entry->r; + unsigned green1 = entry->g; + unsigned blue1 = entry->b; if(blendType != NOBLEND) { if(hi4 == 15) entry = &(pal[0]); else ++entry; - unsigned red2 = entry->red; - unsigned green2 = entry->green; - unsigned blue2 = entry->blue; - unsigned f2 = (lo4 << 4)+1; // +1 so we scale by 256 as a max value, then result can just be shifted by 8 + // unsigned red2 = entry->red; + unsigned f2 = ((index & 0x0F) << 4) + 1; // +1 so we scale by 256 as a max value, then result can just be shifted by 8 unsigned f1 = (257 - f2); // f2 is 1 minimum, so this is 256 max - red1 *= f1; - green1 *= f1; - blue1 *= f1; - red2 *= f2; - green2 *= f2; - blue2 *= f2; - red1 = (red1 + red2) >> 8; - green1 = (green1 + green2) >> 8; - blue1 = (blue1 + blue2) >> 8; + red1 = (red1 * f1 + (unsigned)entry->r * f2) >> 8; + green1 = (green1 * f1 + (unsigned)entry->g * f2) >> 8; + blue1 = (green1 * f1 + (unsigned)entry->b * f2) >> 8; } - if( brightness != 255) { // note: zero checking could be done to return black but that is hardly ever used so it is omitted - uint32_t scale = brightness; - scale++; // adjust for rounding (bitshift) + if( brightness < 255) { // note: zero checking could be done to return black but that is hardly ever used so it is omitted + uint32_t scale = brightness + 1; // adjust for rounding (bitshift) red1 = (red1 * scale) >> 8; green1 = (green1 * scale) >> 8; blue1 = (blue1 * scale) >> 8; From 09428dcade03aa4544f85f81f2d8a160d144db9c Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 12 Sep 2024 16:34:55 +0200 Subject: [PATCH 010/234] inlined getMappedPixelIndex, improved color_add, bugfix in colorFromPalette inlining getMappedPixelIndex gets rid of function entry instructions (hopefully) so it should be faster. also added the 'multi color math' trick to color_add function (it will not make much difference but code shrinks by a few bytes) --- wled00/FX_fcn.cpp | 2 +- wled00/colors.cpp | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 4364b9f43..cddf1ece7 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1820,7 +1820,7 @@ bool WS2812FX::deserializeMap(uint8_t n) { return (customMappingSize > 0); } -uint16_t IRAM_ATTR WS2812FX::getMappedPixelIndex(uint16_t index) const { +__attribute__ ((always_inline)) inline uint16_t IRAM_ATTR WS2812FX::getMappedPixelIndex(uint16_t index) const { // convert logical address to physical if (index < customMappingSize && (realtimeMode == REALTIME_MODE_INACTIVE || realtimeRespectLedMaps)) index = customMappingTable[index]; diff --git a/wled00/colors.cpp b/wled00/colors.cpp index b6cb3ac51..1f1069655 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -39,10 +39,17 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool fast) { if (c1 == BLACK) return c2; if (c2 == BLACK) return c1; - uint32_t r = R(c1) + R(c2); + /*uint32_t r = R(c1) + R(c2); uint32_t g = G(c1) + G(c2); uint32_t b = B(c1) + B(c2); - uint32_t w = W(c1) + W(c2); + uint32_t w = W(c1) + W(c2);*/ + uint32_t rb = (c1 & 0x00FF00FF) + (c2 & 0x00FF00FF); + uint32_t r = rb >> 16; + uint32_t b = rb & 0xFFFF; + uint32_t wg = ((c1>>8) & 0x00FF00FF) + ((c2>>8) & 0x00FF00FF); + uint32_t w = wg >> 16; + uint32_t g = wg & 0xFFFF; + if (fast) { r = r > 255 ? 255 : r; g = g > 255 ? 255 : g; @@ -105,7 +112,7 @@ CRGB ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brig unsigned f1 = (257 - f2); // f2 is 1 minimum, so this is 256 max red1 = (red1 * f1 + (unsigned)entry->r * f2) >> 8; green1 = (green1 * f1 + (unsigned)entry->g * f2) >> 8; - blue1 = (green1 * f1 + (unsigned)entry->b * f2) >> 8; + blue1 = (blue1 * f1 + (unsigned)entry->b * f2) >> 8; } if( brightness < 255) { // note: zero checking could be done to return black but that is hardly ever used so it is omitted uint32_t scale = brightness + 1; // adjust for rounding (bitshift) From ec938f254cf3fdecf0757a2dee4d9364973d4941 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 12 Sep 2024 21:25:08 +0200 Subject: [PATCH 011/234] removed old code --- wled00/colors.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 1f1069655..ce1d2f2f9 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -39,10 +39,6 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool fast) { if (c1 == BLACK) return c2; if (c2 == BLACK) return c1; - /*uint32_t r = R(c1) + R(c2); - uint32_t g = G(c1) + G(c2); - uint32_t b = B(c1) + B(c2); - uint32_t w = W(c1) + W(c2);*/ uint32_t rb = (c1 & 0x00FF00FF) + (c2 & 0x00FF00FF); uint32_t r = rb >> 16; uint32_t b = rb & 0xFFFF; From d45b4ad1340bccfeb9093b1ff460f1919721a277 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Fri, 13 Sep 2024 19:01:54 +0200 Subject: [PATCH 012/234] fixes and consistency --- wled00/colors.cpp | 8 ++++---- wled00/fcn_declare.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index ce1d2f2f9..7747216f7 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -54,9 +54,9 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool fast) return RGBW32(r,g,b,w); } else { unsigned max = r; - if (g > max) max = g; - if (b > max) max = b; - if (w > max) max = w; + max = g > max ? g : max; + max = b > max ? b : max; + max = w > max ? w : max; if (max < 256) return RGBW32(r, g, b, w); else return RGBW32(r * 255 / max, g * 255 / max, b * 255 / max, w * 255 / max); } @@ -70,7 +70,7 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool fast) uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) { if (c1 == BLACK || amount == 0) return BLACK; - else if (amount == 255) return c1; + if (amount == 255) return c1; uint32_t scaledcolor; // color order is: W R G B from MSB to LSB uint32_t scale = amount; // 32bit for faster calculation uint32_t addRemains = 0; diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 2f9bc44d0..0ebcd64da 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -82,7 +82,7 @@ class NeoGammaWLEDMethod { [[gnu::hot]] uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false); [[gnu::hot]] uint32_t color_add(uint32_t,uint32_t, bool fast=false); [[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); -CRGB ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND); +[[gnu::hot]] CRGB ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND); CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette); CRGBPalette16 generateRandomPalette(); inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); } From 2afff0501401c7161eae841107868884635779ae Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 14 Sep 2024 11:45:27 +0200 Subject: [PATCH 013/234] minor tweak (break instead of continue in setPixelColorXY) --- wled00/FX_2Dfcn.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 01410b811..57ee2e5e3 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -188,7 +188,7 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) int yY = y; for (int j = 0; j < grouping; j++) { // groupping vertically - if(yY >= H) continue; + if(yY >= H) break; int xX = x; for (int g = 0; g < grouping; g++) { // groupping horizontally if (xX >= W) continue; // we have reached one dimension's end From 6a37f25c5d994b914222999fdce441c3427e1fcd Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 14 Sep 2024 14:10:46 +0200 Subject: [PATCH 014/234] memory improvement: dropped static gamma table - there already is a method to calculate the table on the fly, there is no need to store it in flash, it can just be calculated at bootup (or cfg change) --- wled00/cfg.cpp | 11 +++++------ wled00/colors.cpp | 19 ++----------------- wled00/set.cpp | 5 ++--- 3 files changed, 9 insertions(+), 26 deletions(-) diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index a6c3ab74d..978ed6eba 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -440,13 +440,12 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { else gammaCorrectBri = false; if (light_gc_col > 1.0f) gammaCorrectCol = true; else gammaCorrectCol = false; - if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3) { - if (gammaCorrectVal != 2.8f) NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); - } else { - gammaCorrectVal = 1.0f; // no gamma correction - gammaCorrectBri = false; - gammaCorrectCol = false; + if (gammaCorrectVal <= 1.0f || gammaCorrectVal > 3) { + gammaCorrectVal = 1.0f; // no gamma correction + gammaCorrectBri = false; + gammaCorrectCol = false; } + NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table JsonObject light_tr = light["tr"]; CJSON(fadeTransition, light_tr["mode"]); diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 7747216f7..4afe4c0d7 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -481,23 +481,7 @@ uint16_t approximateKelvinFromRGB(uint32_t rgb) { } //gamma 2.8 lookup table used for color correction -uint8_t NeoGammaWLEDMethod::gammaT[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, - 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, - 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, - 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, - 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25, - 25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36, - 37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50, - 51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68, - 69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89, - 90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114, - 115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142, - 144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175, - 177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213, - 215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 }; +uint8_t NeoGammaWLEDMethod::gammaT[256]; // re-calculates & fills gamma table void NeoGammaWLEDMethod::calcGammaTable(float gamma) @@ -505,6 +489,7 @@ void NeoGammaWLEDMethod::calcGammaTable(float gamma) for (size_t i = 0; i < 256; i++) { gammaT[i] = (int)(powf((float)i / 255.0f, gamma) * 255.0f + 0.5f); } + Serial.println("****GAMMA***"); //!!! } uint8_t IRAM_ATTR NeoGammaWLEDMethod::Correct(uint8_t value) diff --git a/wled00/set.cpp b/wled00/set.cpp index 7814e55d9..2fe01a54c 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -319,13 +319,12 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) gammaCorrectBri = request->hasArg(F("GB")); gammaCorrectCol = request->hasArg(F("GC")); gammaCorrectVal = request->arg(F("GV")).toFloat(); - if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3) - NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); - else { + if (gammaCorrectVal <= 1.0f || gammaCorrectVal > 3) { gammaCorrectVal = 1.0f; // no gamma correction gammaCorrectBri = false; gammaCorrectCol = false; } + NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table fadeTransition = request->hasArg(F("TF")); modeBlending = request->hasArg(F("EB")); From 0e5bd4ed7428ab7540393935ced7e8ef4e937fc2 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 14 Sep 2024 14:11:29 +0200 Subject: [PATCH 015/234] remove test printout --- wled00/colors.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 4afe4c0d7..74723471c 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -489,7 +489,6 @@ void NeoGammaWLEDMethod::calcGammaTable(float gamma) for (size_t i = 0; i < 256; i++) { gammaT[i] = (int)(powf((float)i / 255.0f, gamma) * 255.0f + 0.5f); } - Serial.println("****GAMMA***"); //!!! } uint8_t IRAM_ATTR NeoGammaWLEDMethod::Correct(uint8_t value) From f3137eb0a9b8d12759a207b910bc854dc1b36ec3 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 14 Sep 2024 14:49:36 +0200 Subject: [PATCH 016/234] updated Segment::color_from_palette - gamma correction only where needed - paletteIndex should be uint8_t (it is only used as that) note: integrating the new `ColorFromPaletteWLED()` into this would require a whole lot of code rewrite and would result in more color conversions from 32bit to CRGB. It would be really useful only if CRGB is replaced with native 32bit colors. --- wled00/FX_fcn.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index cddf1ece7..7e8bd6471 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1181,18 +1181,21 @@ uint32_t Segment::color_wheel(uint8_t pos) const { * @returns Single color from palette */ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) const { - uint32_t color = gamma32(currentColor(mcol)); - + + uint32_t color = currentColor(mcol); // default palette or no RGB support on segment - if ((palette == 0 && mcol < NUM_COLORS) || !_isRGB) return (pbri == 255) ? color : color_fade(color, pbri, true); + if ((palette == 0 && mcol < NUM_COLORS) || !_isRGB) { + color = gamma32(color); + return (pbri == 255) ? color : color_fade(color, pbri, true); + } - unsigned paletteIndex = i; + uint8_t paletteIndex = i; if (mapping && virtualLength() > 1) paletteIndex = (i*255)/(virtualLength() -1); // paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined) if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end" CRGB fastled_col = ColorFromPalette(_currentPalette, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global - return RGBW32(fastled_col.r, fastled_col.g, fastled_col.b, W(color)); + return RGBW32(fastled_col.r, fastled_col.g, fastled_col.b, gamma8(W(color))); } From 1ff667b7eff07ebad100e48eb871c698eab11a71 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sun, 15 Sep 2024 10:59:50 +0200 Subject: [PATCH 017/234] AWS library fix --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index d19f47764..2ef4ae01b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -180,7 +180,7 @@ lib_deps = fastled/FastLED @ 3.6.0 IRremoteESP8266 @ 2.8.2 makuna/NeoPixelBus @ 2.7.5 - https://github.com/Aircoookie/ESPAsyncWebServer.git @ 2.2.1 + https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.2.1 #For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line #TFT_eSPI #For compatible OLED display uncomment following From 696290527abfd01fcff3d4bd5fbfdc9c53050787 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Wed, 18 Sep 2024 22:10:27 +0200 Subject: [PATCH 018/234] cleanup and improved color_add() - optimized color_add() again: now it is as fast with preserved ratio scaling than the "fast" variant was before (if no scaling is needed, it is even faster). plus it saves 250 bytes of flash - bugfix in `color_fade()` - removed a lot of whitespaces --- wled00/FX.h | 24 +++++++-------- wled00/FX_2Dfcn.cpp | 26 ++++++++-------- wled00/FX_fcn.cpp | 16 +++++----- wled00/colors.cpp | 70 +++++++++++++++++++++----------------------- wled00/fcn_declare.h | 2 +- 5 files changed, 67 insertions(+), 71 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 3c28274d6..bea4dbcb8 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -595,9 +595,9 @@ typedef struct Segment { void fadeToBlackBy(uint8_t fadeBy); inline void blendPixelColor(int n, uint32_t color, uint8_t blend) { setPixelColor(n, color_blend(getPixelColor(n), color, blend)); } inline void blendPixelColor(int n, CRGB c, uint8_t blend) { blendPixelColor(n, RGBW32(c.r,c.g,c.b,0), blend); } - inline void addPixelColor(int n, uint32_t color, bool fast = false) { setPixelColor(n, color_add(getPixelColor(n), color, fast)); } - inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColor(n, RGBW32(r,g,b,w), fast); } - inline void addPixelColor(int n, CRGB c, bool fast = false) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), fast); } + inline void addPixelColor(int n, uint32_t color) { setPixelColor(n, color_add(getPixelColor(n), color)); } + inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0) { addPixelColor(n, RGBW32(r,g,b,w)); } + inline void addPixelColor(int n, CRGB c) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } inline void fadePixelColor(uint16_t n, uint8_t fade) { setPixelColor(n, color_fade(getPixelColor(n), fade, true)); } [[gnu::hot]] uint32_t color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255) const; [[gnu::hot]] uint32_t color_wheel(uint8_t pos) const; @@ -605,11 +605,11 @@ typedef struct Segment { // 2D Blur: shortcuts for bluring columns or rows only (50% faster than full 2D blur) inline void blurCols(fract8 blur_amount, bool smear = false) { // blur all columns const unsigned cols = virtualWidth(); - for (unsigned k = 0; k < cols; k++) blurCol(k, blur_amount, smear); + for (unsigned k = 0; k < cols; k++) blurCol(k, blur_amount, smear); } inline void blurRows(fract8 blur_amount, bool smear = false) { // blur all rows const unsigned rows = virtualHeight(); - for ( unsigned i = 0; i < rows; i++) blurRow(i, blur_amount, smear); + for ( unsigned i = 0; i < rows; i++) blurRow(i, blur_amount, smear); } // 2D matrix @@ -632,10 +632,10 @@ typedef struct Segment { // 2D support functions inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) { setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend)); } inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), blend); } - inline void addPixelColorXY(int x, int y, uint32_t color, bool fast = false) { setPixelColorXY(x, y, color_add(getPixelColorXY(x,y), color, fast)); } - inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColorXY(x, y, RGBW32(r,g,b,w), fast); } - inline void addPixelColorXY(int x, int y, CRGB c, bool fast = false) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), fast); } - inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), fade, true)); } + inline void addPixelColorXY(int x, int y, uint32_t color) { setPixelColorXY(x, y, color_add(getPixelColorXY(x,y), color)); } + inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { addPixelColorXY(x, y, RGBW32(r,g,b,w)); } + inline void addPixelColorXY(int x, int y, CRGB c) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } + inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), fade, true)); } void box_blur(unsigned r = 1U, bool smear = false); // 2D box blur void blur2D(uint8_t blur_amount, bool smear = false); void blurRow(uint32_t row, fract8 blur_amount, bool smear = false); @@ -670,9 +670,9 @@ typedef struct Segment { inline uint32_t getPixelColorXY(int x, int y) { return getPixelColor(x); } inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t c, uint8_t blend) { blendPixelColor(x, c, blend); } inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColor(x, RGBW32(c.r,c.g,c.b,0), blend); } - inline void addPixelColorXY(int x, int y, uint32_t color, bool fast = false) { addPixelColor(x, color, fast); } - inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColor(x, RGBW32(r,g,b,w), fast); } - inline void addPixelColorXY(int x, int y, CRGB c, bool fast = false) { addPixelColor(x, RGBW32(c.r,c.g,c.b,0), fast); } + inline void addPixelColorXY(int x, int y, uint32_t color) { addPixelColor(x, color); } + inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { addPixelColor(x, RGBW32(r,g,b,w)); } + inline void addPixelColorXY(int x, int y, CRGB c) { addPixelColor(x, RGBW32(c.r,c.g,c.b,0)); } inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { fadePixelColor(x, fade); } inline void box_blur(unsigned i, bool vertical, fract8 blur_amount) {} inline void blur2D(uint8_t blur_amount, bool smear = false) {} diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 57ee2e5e3..10b85a82e 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -173,7 +173,7 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) if (!isActive()) return; // not active if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit - uint8_t _bri_t = currentBri(); + uint8_t _bri_t = currentBri(); if (_bri_t < 255) { col = color_fade(col, _bri_t); } @@ -185,11 +185,11 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) y *= groupLength(); // expand to physical pixels int W = width(); int H = height(); - + int yY = y; for (int j = 0; j < grouping; j++) { // groupping vertically if(yY >= H) break; - int xX = x; + int xX = x; for (int g = 0; g < grouping; g++) { // groupping horizontally if (xX >= W) continue; // we have reached one dimension's end #ifndef WLED_DISABLE_MODE_BLEND @@ -293,8 +293,8 @@ void Segment::blurRow(uint32_t row, fract8 blur_amount, bool smear){ curnew = color_fade(cur, keep); if (x > 0) { if (carryover) - curnew = color_add(curnew, carryover, true); - uint32_t prev = color_add(lastnew, part, true); + curnew = color_add(curnew, carryover); + uint32_t prev = color_add(lastnew, part); if (last != prev) // optimization: only set pixel if color has changed setPixelColorXY(x - 1, row, prev); } else // first pixel @@ -326,15 +326,15 @@ void Segment::blurCol(uint32_t col, fract8 blur_amount, bool smear) { curnew = color_fade(cur, keep); if (y > 0) { if (carryover) - curnew = color_add(curnew, carryover, true); - uint32_t prev = color_add(lastnew, part, true); + curnew = color_add(curnew, carryover); + uint32_t prev = color_add(lastnew, part); if (last != prev) // optimization: only set pixel if color has changed setPixelColorXY(col, y - 1, prev); } else // first pixel setPixelColorXY(col, y, curnew); lastnew = curnew; last = cur; //save original value for comparison on next iteration - carryover = part; + carryover = part; } setPixelColorXY(col, rows - 1, curnew); } @@ -356,8 +356,8 @@ void Segment::blur2D(uint8_t blur_amount, bool smear) { uint32_t part = color_fade(cur, seep); curnew = color_fade(cur, keep); if (x > 0) { - if (carryover) curnew = color_add(curnew, carryover, true); - uint32_t prev = color_add(lastnew, part, true); + if (carryover) curnew = color_add(curnew, carryover); + uint32_t prev = color_add(lastnew, part); // optimization: only set pixel if color has changed if (last != prev) setPixelColorXY(x - 1, row, prev); } else setPixelColorXY(x, row, curnew); // first pixel @@ -375,14 +375,14 @@ void Segment::blur2D(uint8_t blur_amount, bool smear) { uint32_t part = color_fade(cur, seep); curnew = color_fade(cur, keep); if (y > 0) { - if (carryover) curnew = color_add(curnew, carryover, true); - uint32_t prev = color_add(lastnew, part, true); + if (carryover) curnew = color_add(curnew, carryover); + uint32_t prev = color_add(lastnew, part); // optimization: only set pixel if color has changed if (last != prev) setPixelColorXY(col, y - 1, prev); } else setPixelColorXY(col, y, curnew); // first pixel lastnew = curnew; last = cur; //save original value for comparison on next iteration - carryover = part; + carryover = part; } setPixelColorXY(col, rows - 1, curnew); } diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 236f7ad4a..66aeaab63 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -712,12 +712,12 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) { if (!isActive()) return; // not active #ifndef WLED_DISABLE_2D - int vStrip; + int vStrip; #endif if (i >= virtualLength() || i<0) // pixel would fall out of segment, check if this is a virtual strip NOTE: this is almost always false if not virtual strip, saves the calculation on 'standard' call { #ifndef WLED_DISABLE_2D - vStrip = i>>16; // hack to allow running on virtual strips (2D segment columns/rows) + vStrip = i>>16; // hack to allow running on virtual strips (2D segment columns/rows) #endif i &= 0xFFFF; //truncate vstrip index if (i >= virtualLength() || i<0) return; // if pixel would still fall out of segment just exit @@ -735,7 +735,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) case M12_pBar: // expand 1D effect vertically or have it play on virtual strips if (vStrip>0) setPixelColorXY(vStrip - 1, vH - i - 1, col); - else for (int x = 0; x < vW; x++) setPixelColorXY(x, vH - i - 1, col); + else for (int x = 0; x < vW; x++) setPixelColorXY(x, vH - i - 1, col); break; case M12_pArc: // expand in circular fashion from center @@ -796,7 +796,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) // Odd rays start further from center if prevRay started at center. static int prevRay = INT_MIN; // previous ray number if ((i % 2 == 1) && (i - 1 == prevRay || i + 1 == prevRay)) { - int jump = min(vW/3, vH/3); // can add 2 if using medium pinwheel + int jump = min(vW/3, vH/3); // can add 2 if using medium pinwheel posx += inc_x * jump; posy += inc_y * jump; } @@ -1145,8 +1145,8 @@ void Segment::blur(uint8_t blur_amount, bool smear) { uint32_t part = color_fade(cur, seep); curnew = color_fade(cur, keep); if (i > 0) { - if (carryover) curnew = color_add(curnew, carryover, true); - uint32_t prev = color_add(lastnew, part, true); + if (carryover) curnew = color_add(curnew, carryover); + uint32_t prev = color_add(lastnew, part); // optimization: only set pixel if color has changed if (last != prev) setPixelColor(i - 1, prev); } else // first pixel @@ -1188,7 +1188,7 @@ uint32_t Segment::color_wheel(uint8_t pos) const { * @returns Single color from palette */ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) const { - + uint32_t color = currentColor(mcol); // default palette or no RGB support on segment if ((palette == 0 && mcol < NUM_COLORS) || !_isRGB) { @@ -1196,7 +1196,7 @@ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_ return (pbri == 255) ? color : color_fade(color, pbri, true); } - uint8_t paletteIndex = i; + unsigned paletteIndex = i; if (mapping && virtualLength() > 1) paletteIndex = (i*255)/(virtualLength() -1); // paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined) if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end" diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 104d25e60..54469ebe0 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -33,33 +33,32 @@ uint32_t color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) /* * color add function that preserves ratio - * idea: https://github.com/Aircoookie/WLED/pull/2465 by https://github.com/Proto-molecule + * original idea: https://github.com/Aircoookie/WLED/pull/2465 by https://github.com/Proto-molecule + * heavily optimized for speed by @dedehai */ -uint32_t color_add(uint32_t c1, uint32_t c2, bool fast) +uint32_t color_add(uint32_t c1, uint32_t c2) { if (c1 == BLACK) return c2; if (c2 == BLACK) return c1; - uint32_t rb = (c1 & 0x00FF00FF) + (c2 & 0x00FF00FF); - uint32_t r = rb >> 16; - uint32_t b = rb & 0xFFFF; - uint32_t wg = ((c1>>8) & 0x00FF00FF) + ((c2>>8) & 0x00FF00FF); + uint32_t rb = (c1 & 0x00FF00FF) + (c2 & 0x00FF00FF); // mask and add two colors at once + uint32_t wg = ((c1>>8) & 0x00FF00FF) + ((c2>>8) & 0x00FF00FF); + uint32_t r = rb >> 16; // extract single color values + uint32_t b = rb & 0xFFFF; uint32_t w = wg >> 16; - uint32_t g = wg & 0xFFFF; + uint32_t g = wg & 0xFFFF; - if (fast) { - r = r > 255 ? 255 : r; - g = g > 255 ? 255 : g; - b = b > 255 ? 255 : b; - w = w > 255 ? 255 : w; - return RGBW32(r,g,b,w); - } else { - unsigned max = r; - max = g > max ? g : max; - max = b > max ? b : max; - max = w > max ? w : max; - if (max < 256) return RGBW32(r, g, b, w); - else return RGBW32(r * 255 / max, g * 255 / max, b * 255 / max, w * 255 / max); + unsigned max = r; // check for overflow note: not checking and just topping out at 255 (formerly 'fast') is not any faster (but even slower if not overflowing) + max = g > max ? g : max; + max = b > max ? b : max; + max = w > max ? w : max; + + if (max > 255) { + uint32_t scale = (uint32_t(255)<<8) / max; // division of two 8bit (shifted) values does not work -> use bit shifts and multiplaction instead + rb = ((rb * scale) >> 8) & 0x00FF00FF; // + wg = (wg * scale) & 0xFF00FF00; } + else wg = wg << 8; //shift white and green back to correct position + return rb | wg; } /* @@ -70,52 +69,49 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool fast) uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) { if (c1 == BLACK || amount == 0) return BLACK; - if (amount == 255) return c1; + if (amount == 255) return c1; uint32_t scaledcolor; // color order is: W R G B from MSB to LSB uint32_t scale = amount; // 32bit for faster calculation uint32_t addRemains = 0; - if (!video) amount++; // add one for correct scaling using bitshifts + if (!video) scale++; // add one for correct scaling using bitshifts else { // video scaling: make sure colors do not dim to zero if they started non-zero - addRemains = R(c1) ? 0x00010000 : 0; + addRemains = R(c1) ? 0x00010000 : 0; addRemains |= G(c1) ? 0x00000100 : 0; addRemains |= B(c1) ? 0x00000001 : 0; addRemains |= W(c1) ? 0x01000000 : 0; } uint32_t rb = (((c1 & 0x00FF00FF) * scale) >> 8) & 0x00FF00FF; // scale red and blue uint32_t wg = (((c1 & 0xFF00FF00) >> 8) * scale) & 0xFF00FF00; // scale white and green - scaledcolor = (rb | wg) + addRemains; + scaledcolor = (rb | wg) + addRemains; return scaledcolor; } // 1:1 replacement of fastled function optimized for ESP, slightly faster, more accurate and uses less flash (~ -200bytes) CRGB ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brightness, TBlendType blendType) { - if ( blendType == LINEARBLEND_NOWRAP) { - //index = map8(index, 0, 239); + if (blendType == LINEARBLEND_NOWRAP) { index = (index*240) >> 8; // Blend range is affected by lo4 blend of values, remap to avoid wrapping } unsigned hi4 = byte(index) >> 4; - // We then add that to a base array pointer. const CRGB* entry = (CRGB*)( (uint8_t*)(&(pal[0])) + (hi4 * sizeof(CRGB))); unsigned red1 = entry->r; unsigned green1 = entry->g; - unsigned blue1 = entry->b; + unsigned blue1 = entry->b; if(blendType != NOBLEND) { if(hi4 == 15) entry = &(pal[0]); else ++entry; - // unsigned red2 = entry->red; unsigned f2 = ((index & 0x0F) << 4) + 1; // +1 so we scale by 256 as a max value, then result can just be shifted by 8 unsigned f1 = (257 - f2); // f2 is 1 minimum, so this is 256 max - red1 = (red1 * f1 + (unsigned)entry->r * f2) >> 8; - green1 = (green1 * f1 + (unsigned)entry->g * f2) >> 8; - blue1 = (blue1 * f1 + (unsigned)entry->b * f2) >> 8; + red1 = (red1 * f1 + (unsigned)entry->r * f2) >> 8; + green1 = (green1 * f1 + (unsigned)entry->g * f2) >> 8; + blue1 = (blue1 * f1 + (unsigned)entry->b * f2) >> 8; } if( brightness < 255) { // note: zero checking could be done to return black but that is hardly ever used so it is omitted - uint32_t scale = brightness + 1; // adjust for rounding (bitshift) + uint32_t scale = brightness + 1; // adjust for rounding (bitshift) red1 = (red1 * scale) >> 8; green1 = (green1 * scale) >> 8; blue1 = (blue1 * scale) >> 8; - } + } return CRGB((uint8_t)red1, (uint8_t)green1, (uint8_t)blue1); } @@ -176,7 +172,7 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) harmonics[1] = basehue + 205 + random8(10); harmonics[2] = basehue - 5 + random8(10); break; - + case 3: // square harmonics[0] = basehue + 85 + random8(10); harmonics[1] = basehue + 175 + random8(10); @@ -213,9 +209,9 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) //apply saturation & gamma correction CRGB RGBpalettecolors[4]; for (int i = 0; i < 4; i++) { - if (makepastelpalette && palettecolors[i].saturation > 180) { + if (makepastelpalette && palettecolors[i].saturation > 180) { palettecolors[i].saturation -= 160; //desaturate all four colors - } + } RGBpalettecolors[i] = (CRGB)palettecolors[i]; //convert to RGB RGBpalettecolors[i] = gamma32(((uint32_t)RGBpalettecolors[i]) & 0x00FFFFFFU); //strip alpha from CRGB } diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index ac941dc97..be7ed4462 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -80,7 +80,7 @@ class NeoGammaWLEDMethod { #define gamma32(c) NeoGammaWLEDMethod::Correct32(c) #define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c) [[gnu::hot]] uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false); -[[gnu::hot]] uint32_t color_add(uint32_t,uint32_t, bool fast=false); +[[gnu::hot]] uint32_t color_add(uint32_t,uint32_t); [[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); [[gnu::hot]] CRGB ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND); CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette); From d4268ba070bc33d52193aafa7f7e1efe904d39dd Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sat, 7 Sep 2024 19:51:23 -0400 Subject: [PATCH 019/234] handleFileRead: Skip duplicate FS check Since we validate the file existence ourselves, no need to have AsyncWebServer do it again. --- wled00/file.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/file.cpp b/wled00/file.cpp index 69e1e692c..bc3467202 100644 --- a/wled00/file.cpp +++ b/wled00/file.cpp @@ -433,7 +433,7 @@ bool handleFileRead(AsyncWebServerRequest* request, String path){ } #endif if(WLED_FS.exists(path) || WLED_FS.exists(path + ".gz")) { - request->send(WLED_FS, path, String(), request->hasArg(F("download"))); + request->send(request->beginResponse(WLED_FS, path, {}, request->hasArg(F("download")), {})); return true; } return false; From 1346eb4f76805fc6210e31949e33a06fa44d813a Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 8 Sep 2024 15:55:50 -0400 Subject: [PATCH 020/234] tools: Add all_xml fetch script Useful for checking that I haven't broken anything. --- tools/all_xml.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tools/all_xml.sh diff --git a/tools/all_xml.sh b/tools/all_xml.sh new file mode 100644 index 000000000..68ed07bbd --- /dev/null +++ b/tools/all_xml.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# Pull all settings pages for comparison +HOST=$1 +TGT_PATH=$2 +CURL_ARGS="--compressed" + +# Replicate one target many times +function replicate() { + for i in {0..10} + do + echo -n " http://${HOST}/settings.js?p=$i -o ${TGT_PATH}/$i.xml" + done +} +read -a TARGETS <<< $(replicate) + +mkdir -p ${TGT_PATH} +curl ${CURL_ARGS} ${TARGETS[@]} From 32f9616b6e078e53da033f1054e747e04e8b30c3 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Thu, 5 Sep 2024 21:13:55 -0400 Subject: [PATCH 021/234] Remove oappend Remove the large stack buffer as we're just going to copy it in to a heap buffer anyways. Later we can refine the length estimation or use a rope-style dynamic data structure like DynamicBufferList. --- wled00/fcn_declare.h | 14 +- wled00/mqtt.cpp | 34 +- wled00/set.cpp | 6 +- wled00/um_manager.cpp | 2 +- wled00/util.cpp | 69 +--- wled00/wled.h | 4 - wled00/wled_server.cpp | 18 +- wled00/xml.cpp | 772 ++++++++++++++++++++--------------------- 8 files changed, 442 insertions(+), 477 deletions(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index a95064a2a..6ce30facf 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -302,7 +302,7 @@ class Usermod { virtual bool handleButton(uint8_t b) { return false; } // button overrides are possible here virtual bool getUMData(um_data_t **data) { if (data) *data = nullptr; return false; }; // usermod data exchange [see examples for audio effects] virtual void connected() {} // called when WiFi is (re)connected - virtual void appendConfigData() {} // helper function called from usermod settings page to add metadata for entry fields + virtual void appendConfigData(Print&) {} // helper function called from usermod settings page to add metadata for entry fields virtual void addToJsonState(JsonObject& obj) {} // add JSON objects for WLED state virtual void addToJsonInfo(JsonObject& obj) {} // add JSON objects for UI Info page virtual void readFromJsonState(JsonObject& obj) {} // process JSON messages received from web server @@ -328,7 +328,7 @@ class UsermodManager { bool getUMData(um_data_t **um_data, uint8_t mod_id = USERMOD_ID_RESERVED); // USERMOD_ID_RESERVED will poll all usermods void setup(); void connected(); - void appendConfigData(); + void appendConfigData(Print&); void addToJsonState(JsonObject& obj); void addToJsonInfo(JsonObject& obj); void readFromJsonState(JsonObject& obj); @@ -362,10 +362,8 @@ void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255); bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255); bool getBoolVal(JsonVariant elem, bool dflt); bool updateVal(const char* req, const char* key, byte* val, byte minv=0, byte maxv=255); -bool oappend(const char* txt); // append new c string to temp buffer efficiently -bool oappendi(int i); // append new number to temp buffer efficiently -void sappend(char stype, const char* key, int val); -void sappends(char stype, const char* key, char* val); +void sappend(Print& dest, char stype, const char* key, int val); +void sappends(Print& dest, char stype, const char* key, char* val); void prepareHostname(char* hostname); bool isAsterisksOnly(const char* str, byte maxLen); bool requestJSONBufferLock(uint8_t module=255); @@ -444,7 +442,7 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp void sendDataWs(AsyncWebSocketClient * client = nullptr); //xml.cpp -void XML_response(AsyncWebServerRequest *request, char* dest = nullptr); -void getSettingsJS(byte subPage, char* dest); +void XML_response(Print& dest); +void getSettingsJS(byte subPage, Print& dest); #endif diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp index 833e6eb7d..6694be07d 100644 --- a/wled00/mqtt.cpp +++ b/wled00/mqtt.cpp @@ -124,6 +124,32 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp payloadStr = nullptr; } +// Print adapter for flat buffers +namespace { +class bufferPrint : public Print { + char* _buf; + size_t _size, _offset; + public: + + bufferPrint(char* buf, size_t size) : _buf(buf), _size(size), _offset(0) {}; + + size_t write(const uint8_t *buffer, size_t size) { + size = std::min(size, _size - _offset); + memcpy(_buf + _offset, buffer, size); + _offset += size; + return size; + } + + size_t write(uint8_t c) { + return this->write(&c, 1); + } + + char* data() const { return _buf; } + size_t size() const { return _offset; } + size_t capacity() const { return _size; } +}; +}; // anonymous namespace + void publishMqtt() { @@ -148,11 +174,13 @@ void publishMqtt() strcat_P(subuf, PSTR("/status")); mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT - char apires[1024]; // allocating 1024 bytes from stack can be risky - XML_response(nullptr, apires); + // TODO: use a DynamicBufferList. Requires a list-read-capable MQTT client API. + DynamicBuffer buf(1024); + bufferPrint pbuf(buf.data(), buf.size()); + XML_response(pbuf); strlcpy(subuf, mqttDeviceTopic, 33); strcat_P(subuf, PSTR("/v")); - mqtt->publish(subuf, 0, retainMqttMsg, apires); // optionally retain message (#2263) + mqtt->publish(subuf, 0, retainMqttMsg, buf.data(), pbuf.size()); // optionally retain message (#2263) #endif } diff --git a/wled00/set.cpp b/wled00/set.cpp index 812bcc52f..05b5b3181 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -1191,7 +1191,11 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) // internal call, does not send XML response pos = req.indexOf(F("IN")); - if (pos < 1) XML_response(request); + if (pos < 1) { + auto response = request->beginResponseStream("text/xml"); + XML_response(*response); + request->send(response); + } return true; } diff --git a/wled00/um_manager.cpp b/wled00/um_manager.cpp index 2db29c3cd..3970e7af4 100644 --- a/wled00/um_manager.cpp +++ b/wled00/um_manager.cpp @@ -8,7 +8,7 @@ void UsermodManager::setup() { for (unsigned i = 0; i < numMods; i++ void UsermodManager::connected() { for (unsigned i = 0; i < numMods; i++) ums[i]->connected(); } void UsermodManager::loop() { for (unsigned i = 0; i < numMods; i++) ums[i]->loop(); } void UsermodManager::handleOverlayDraw() { for (unsigned i = 0; i < numMods; i++) ums[i]->handleOverlayDraw(); } -void UsermodManager::appendConfigData() { for (unsigned i = 0; i < numMods; i++) ums[i]->appendConfigData(); } +void UsermodManager::appendConfigData(Print& dest) { for (unsigned i = 0; i < numMods; i++) ums[i]->appendConfigData(dest); } bool UsermodManager::handleButton(uint8_t b) { bool overrideIO = false; for (unsigned i = 0; i < numMods; i++) { diff --git a/wled00/util.cpp b/wled00/util.cpp index 99a75bdd3..00506ea97 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -89,88 +89,43 @@ bool updateVal(const char* req, const char* key, byte* val, byte minv, byte maxv //append a numeric setting to string buffer -void sappend(char stype, const char* key, int val) +void sappend(Print& dest, char stype, const char* key, int val) { - char ds[] = "d.Sf."; - + const __FlashStringHelper* type_str; switch(stype) { case 'c': //checkbox - oappend(ds); - oappend(key); - oappend(".checked="); - oappendi(val); - oappend(";"); + type_str = F(".checked="); break; case 'v': //numeric - oappend(ds); - oappend(key); - oappend(".value="); - oappendi(val); - oappend(";"); + type_str = F(".value="); break; case 'i': //selectedIndex - oappend(ds); - oappend(key); - oappend(SET_F(".selectedIndex=")); - oappendi(val); - oappend(";"); + type_str = F(".selectedIndex="); break; + default: + return; //??? } + + dest.printf_P(PSTR("d.Sf.%s%s%d;"), key, type_str, val); } //append a string setting to buffer -void sappends(char stype, const char* key, char* val) +void sappends(Print& dest, char stype, const char* key, char* val) { switch(stype) { case 's': {//string (we can interpret val as char*) - String buf = val; - //convert "%" to "%%" to make EspAsyncWebServer happy - //buf.replace("%","%%"); - oappend("d.Sf."); - oappend(key); - oappend(".value=\""); - oappend(buf.c_str()); - oappend("\";"); + dest.printf_P(PSTR("d.Sf.%s.value=\"%s\";"),key,val); break;} case 'm': //message - oappend(SET_F("d.getElementsByClassName")); - oappend(key); - oappend(SET_F(".innerHTML=\"")); - oappend(val); - oappend("\";"); + dest.printf_P(PSTR("d.getElementsByClassName%s.innerHTML=\"%s\";"), key, val); break; } } -bool oappendi(int i) -{ - char s[12]; // 32bit signed number can have 10 digits plus - sign - sprintf(s, "%d", i); - return oappend(s); -} - - -bool oappend(const char* txt) -{ - unsigned len = strlen(txt); - if ((obuf == nullptr) || (olen + len >= SETTINGS_STACK_BUF_SIZE)) { // sanity checks -#ifdef WLED_DEBUG - DEBUG_PRINT(F("oappend() buffer overflow. Cannot append ")); - DEBUG_PRINT(len); DEBUG_PRINT(F(" bytes \t\"")); - DEBUG_PRINT(txt); DEBUG_PRINTLN(F("\"")); -#endif - return false; // buffer full - } - strcpy(obuf + olen, txt); - olen += len; - return true; -} - - void prepareHostname(char* hostname) { sprintf_P(hostname, PSTR("wled-%*s"), 6, escapedMac.c_str() + 6); diff --git a/wled00/wled.h b/wled00/wled.h index 31a612858..052f29b29 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -839,10 +839,6 @@ WLED_GLOBAL time_t sunrise _INIT(0); WLED_GLOBAL time_t sunset _INIT(0); WLED_GLOBAL Toki toki _INIT(Toki()); -// Temp buffer -WLED_GLOBAL char* obuf; -WLED_GLOBAL uint16_t olen _INIT(0); - // General filesystem WLED_GLOBAL size_t fsBytesUsed _INIT(0); WLED_GLOBAL size_t fsBytesTotal _INIT(0); diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index 9d4e4c85b..8fdcb1ebe 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -520,27 +520,23 @@ void serveSettingsJS(AsyncWebServerRequest* request) handleStaticContent(request, FPSTR(_common_js), 200, FPSTR(CONTENT_TYPE_JAVASCRIPT), JS_common, JS_common_length); return; } - char buf[SETTINGS_STACK_BUF_SIZE+37]; - buf[0] = 0; byte subPage = request->arg(F("p")).toInt(); if (subPage > 10) { - strcpy_P(buf, PSTR("alert('Settings for this request are not implemented.');")); - request->send(501, FPSTR(CONTENT_TYPE_JAVASCRIPT), buf); + request->send_P(501, FPSTR(CONTENT_TYPE_JAVASCRIPT), PSTR("alert('Settings for this request are not implemented.');")); return; } if (subPage > 0 && !correctPIN && strlen(settingsPIN)>0) { - strcpy_P(buf, PSTR("alert('PIN incorrect.');")); - request->send(401, FPSTR(CONTENT_TYPE_JAVASCRIPT), buf); + request->send_P(401, FPSTR(CONTENT_TYPE_JAVASCRIPT), PSTR("alert('PIN incorrect.');")); return; } - strcat_P(buf,PSTR("function GetV(){var d=document;")); - getSettingsJS(subPage, buf+strlen(buf)); // this may overflow by 35bytes!!! - strcat_P(buf,PSTR("}")); - AsyncWebServerResponse *response; - response = request->beginResponse(200, FPSTR(CONTENT_TYPE_JAVASCRIPT), buf); + AsyncResponseStream *response = request->beginResponseStream(FPSTR(CONTENT_TYPE_JAVASCRIPT)); response->addHeader(F("Cache-Control"), F("no-store")); response->addHeader(F("Expires"), F("0")); + + response->print(F("function GetV(){var d=document;")); + getSettingsJS(subPage, *response); + response->print(F("}")); request->send(response); } diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 71d66d002..2d63d61f3 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -6,85 +6,80 @@ */ //build XML response to HTTP /win API request -void XML_response(AsyncWebServerRequest *request, char* dest) +void XML_response(Print& dest) { - char sbuf[(dest == nullptr)?1024:1]; //allocate local buffer if none passed - obuf = (dest == nullptr)? sbuf:dest; - - olen = 0; - oappend(SET_F("")); - oappendi((nightlightActive && nightlightMode > NL_MODE_SET) ? briT : bri); - oappend(SET_F("")); + dest.print(F("")); + dest.print((nightlightActive && nightlightMode > NL_MODE_SET) ? briT : bri); + dest.print(F("")); for (int i = 0; i < 3; i++) { - oappend(""); - oappendi(col[i]); - oappend(""); + dest.print(""); + dest.print(col[i]); + dest.print(""); } for (int i = 0; i < 3; i++) { - oappend(""); - oappendi(colSec[i]); - oappend(""); + dest.print(""); + dest.print(colSec[i]); + dest.print(""); } - oappend(SET_F("")); - oappendi(notifyDirect); - oappend(SET_F("")); - oappendi(receiveGroups!=0); - oappend(SET_F("")); - oappendi(nightlightActive); - oappend(SET_F("")); - oappendi(nightlightMode > NL_MODE_SET); - oappend(SET_F("")); - oappendi(nightlightDelayMins); - oappend(SET_F("")); - oappendi(nightlightTargetBri); - oappend(SET_F("")); - oappendi(effectCurrent); - oappend(SET_F("")); - oappendi(effectSpeed); - oappend(SET_F("")); - oappendi(effectIntensity); - oappend(SET_F("")); - oappendi(effectPalette); - oappend(SET_F("")); + dest.print(F("")); + dest.print(notifyDirect); + dest.print(F("")); + dest.print(receiveGroups!=0); + dest.print(F("")); + dest.print(nightlightActive); + dest.print(F("")); + dest.print(nightlightMode > NL_MODE_SET); + dest.print(F("")); + dest.print(nightlightDelayMins); + dest.print(F("")); + dest.print(nightlightTargetBri); + dest.print(F("")); + dest.print(effectCurrent); + dest.print(F("")); + dest.print(effectSpeed); + dest.print(F("")); + dest.print(effectIntensity); + dest.print(F("")); + dest.print(effectPalette); + dest.print(F("")); if (strip.hasWhiteChannel()) { - oappendi(col[3]); + dest.print(col[3]); } else { - oappend("-1"); + dest.print("-1"); } - oappend(SET_F("")); - oappendi(colSec[3]); - oappend(SET_F("")); - oappendi(currentPreset); - oappend(SET_F("")); - oappendi(currentPlaylist >= 0); - oappend(SET_F("")); - oappend(serverDescription); + dest.print(F("")); + dest.print(colSec[3]); + dest.print(F("")); + dest.print(currentPreset); + dest.print(F("")); + dest.print(currentPlaylist >= 0); + dest.print(F("")); + dest.print(serverDescription); if (realtimeMode) { - oappend(SET_F(" (live)")); + dest.print(F(" (live)")); } - oappend(SET_F("")); - oappendi(strip.getFirstSelectedSegId()); - oappend(SET_F("")); - if (request != nullptr) request->send(200, "text/xml", obuf); + dest.print(F("")); + dest.print(strip.getFirstSelectedSegId()); + dest.print(F("")); } -void extractPin(JsonObject &obj, const char *key) { +static void extractPin(Print& dest, JsonObject &obj, const char *key) { if (obj[key].is()) { JsonArray pins = obj[key].as(); for (JsonVariant pv : pins) { - if (pv.as() > -1) { oappend(","); oappendi(pv.as()); } + if (pv.as() > -1) { dest.print(","); dest.print(pv.as()); } } } else { - if (obj[key].as() > -1) { oappend(","); oappendi(obj[key].as()); } + if (obj[key].as() > -1) { dest.print(","); dest.print(obj[key].as()); } } } -// oappend used pins by scanning JsonObject (1 level deep) -void fillUMPins(JsonObject &mods) +// dest.print used pins by scanning JsonObject (1 level deep) +void fillUMPins(Print& dest, JsonObject &mods) { for (JsonPair kv : mods) { // kv.key() is usermod name or subobject key @@ -93,7 +88,7 @@ void fillUMPins(JsonObject &mods) if (!obj.isNull()) { // element is an JsonObject if (!obj["pin"].isNull()) { - extractPin(obj, "pin"); + extractPin(dest, obj, "pin"); } else { // scan keys (just one level deep as is possible with usermods) for (JsonPair so : obj) { @@ -102,7 +97,7 @@ void fillUMPins(JsonObject &mods) // we found a key containing "pin" substring if (strlen(strstr(key, "pin")) == 3) { // and it is at the end, we found another pin - extractPin(obj, key); + extractPin(dest, obj, key); continue; } } @@ -110,7 +105,7 @@ void fillUMPins(JsonObject &mods) JsonObject subObj = obj[so.key()]; if (!subObj["pin"].isNull()) { // get pins from subobject - extractPin(subObj, "pin"); + extractPin(dest, subObj, "pin"); } } } @@ -118,101 +113,99 @@ void fillUMPins(JsonObject &mods) } } -void appendGPIOinfo() { +void appendGPIOinfo(Print& dest) { char nS[8]; // add usermod pins as d.um_p array - oappend(SET_F("d.um_p=[-1")); // has to have 1 element + dest.print(F("d.um_p=[-1")); // has to have 1 element if (i2c_sda > -1 && i2c_scl > -1) { - oappend(","); oappend(itoa(i2c_sda,nS,10)); - oappend(","); oappend(itoa(i2c_scl,nS,10)); + dest.print(","); dest.print(itoa(i2c_sda,nS,10)); + dest.print(","); dest.print(itoa(i2c_scl,nS,10)); } if (spi_mosi > -1 && spi_sclk > -1) { - oappend(","); oappend(itoa(spi_mosi,nS,10)); - oappend(","); oappend(itoa(spi_sclk,nS,10)); + dest.print(","); dest.print(itoa(spi_mosi,nS,10)); + dest.print(","); dest.print(itoa(spi_sclk,nS,10)); } // usermod pin reservations will become unnecessary when settings pages will read cfg.json directly if (requestJSONBufferLock(6)) { // if we can't allocate JSON buffer ignore usermod pins JsonObject mods = pDoc->createNestedObject(F("um")); usermods.addToConfig(mods); - if (!mods.isNull()) fillUMPins(mods); + if (!mods.isNull()) fillUMPins(dest, mods); releaseJSONBufferLock(); } - oappend(SET_F("];")); + dest.print(F("];")); // add reserved (unusable) pins - oappend(SET_F("d.rsvd=[")); + dest.print(SET_F("d.rsvd=[")); for (unsigned i = 0; i < WLED_NUM_PINS; i++) { if (!pinManager.isPinOk(i, false)) { // include readonly pins - oappendi(i); oappend(","); + dest.print(i); dest.print(","); } } #ifdef WLED_ENABLE_DMX - oappend(SET_F("2,")); // DMX hardcoded pin + dest.print(SET_F("2,")); // DMX hardcoded pin #endif #if defined(WLED_DEBUG) && !defined(WLED_DEBUG_HOST) - oappend(itoa(hardwareTX,nS,10)); oappend(","); // debug output (TX) pin + dest.print(itoa(hardwareTX,nS,10)); dest.print(","); // debug output (TX) pin #endif //Note: Using pin 3 (RX) disables Adalight / Serial JSON #ifdef WLED_USE_ETHERNET if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) { - for (unsigned p=0; p=0) { oappend(itoa(ethernetBoards[ethernetType].eth_power,nS,10)); oappend(","); } - if (ethernetBoards[ethernetType].eth_mdc>=0) { oappend(itoa(ethernetBoards[ethernetType].eth_mdc,nS,10)); oappend(","); } - if (ethernetBoards[ethernetType].eth_mdio>=0) { oappend(itoa(ethernetBoards[ethernetType].eth_mdio,nS,10)); oappend(","); } + for (unsigned p=0; p=0) { dest.print(itoa(ethernetBoards[ethernetType].eth_power,nS,10)); dest.print(","); } + if (ethernetBoards[ethernetType].eth_mdc>=0) { dest.print(itoa(ethernetBoards[ethernetType].eth_mdc,nS,10)); dest.print(","); } + if (ethernetBoards[ethernetType].eth_mdio>=0) { dest.print(itoa(ethernetBoards[ethernetType].eth_mdio,nS,10)); dest.print(","); } switch (ethernetBoards[ethernetType].eth_clk_mode) { case ETH_CLOCK_GPIO0_IN: case ETH_CLOCK_GPIO0_OUT: - oappend(SET_F("0")); + dest.print(SET_F("0")); break; case ETH_CLOCK_GPIO16_OUT: - oappend(SET_F("16")); + dest.print(SET_F("16")); break; case ETH_CLOCK_GPIO17_OUT: - oappend(SET_F("17")); + dest.print(SET_F("17")); break; } } #endif - oappend(SET_F("];")); // rsvd + dest.print(SET_F("];")); // rsvd // add info for read-only GPIO - oappend(SET_F("d.ro_gpio=[")); + dest.print(SET_F("d.ro_gpio=[")); bool firstPin = true; for (unsigned i = 0; i < WLED_NUM_PINS; i++) { if (pinManager.isReadOnlyPin(i)) { // No comma before the first pin - if (!firstPin) oappend(SET_F(",")); - oappendi(i); + if (!firstPin) dest.print(SET_F(",")); + dest.print(i); firstPin = false; } } - oappend(SET_F("];")); + dest.print(SET_F("];")); // add info about max. # of pins - oappend(SET_F("d.max_gpio=")); - oappendi(WLED_NUM_PINS); - oappend(SET_F(";")); + dest.print(SET_F("d.max_gpio=")); + dest.print(WLED_NUM_PINS); + dest.print(SET_F(";")); } //get values for settings form in javascript -void getSettingsJS(byte subPage, char* dest) +void getSettingsJS(byte subPage, Print& dest) { //0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec DEBUG_PRINTF_P(PSTR("settings resp %u\n"), (unsigned)subPage); - obuf = dest; - olen = 0; if (subPage <0 || subPage >10) return; if (subPage == SUBPAGE_MENU) { #ifdef WLED_DISABLE_2D // include only if 2D is not compiled in - oappend(PSTR("gId('2dbtn').style.display='none';")); + dest.print(F("gId('2dbtn').style.display='none';")); #endif #ifdef WLED_ENABLE_DMX // include only if DMX is enabled - oappend(PSTR("gId('dmxbtn').style.display='';")); + dest.print(F("gId('dmxbtn').style.display='';")); #endif } @@ -220,65 +213,65 @@ void getSettingsJS(byte subPage, char* dest) { char nS[10]; size_t l; - oappend(SET_F("resetWiFi(")); - oappend(itoa(WLED_MAX_WIFI_COUNT,nS,10)); - oappend(SET_F(");")); + dest.print(F("resetWiFi(")); + dest.print(WLED_MAX_WIFI_COUNT); + dest.print(F(");")); for (size_t n = 0; n < multiWiFi.size(); n++) { l = strlen(multiWiFi[n].clientPass); char fpass[l+1]; //fill password field with *** fpass[l] = 0; memset(fpass,'*',l); - oappend(SET_F("addWiFi(\"")); - oappend(multiWiFi[n].clientSSID); - oappend(SET_F("\",\"")); - oappend(fpass); - oappend(SET_F("\",0x")); - oappend(itoa(multiWiFi[n].staticIP,nS,16)); - oappend(SET_F(",0x")); - oappend(itoa(multiWiFi[n].staticGW,nS,16)); - oappend(SET_F(",0x")); - oappend(itoa(multiWiFi[n].staticSN,nS,16)); - oappend(SET_F(");")); + dest.print(F("addWiFi(\"")); + dest.print(multiWiFi[n].clientSSID); + dest.print(F("\",\"")); + dest.print(fpass); + dest.print(F("\",0x")); + dest.print(itoa(multiWiFi[n].staticIP,nS,16)); + dest.print(F(",0x")); + dest.print(itoa(multiWiFi[n].staticGW,nS,16)); + dest.print(F(",0x")); + dest.print(itoa(multiWiFi[n].staticSN,nS,16)); + dest.print(F(");")); } - sappend('v',SET_F("D0"),dnsAddress[0]); - sappend('v',SET_F("D1"),dnsAddress[1]); - sappend('v',SET_F("D2"),dnsAddress[2]); - sappend('v',SET_F("D3"),dnsAddress[3]); + sappend(dest,'v',SET_F("D0"),dnsAddress[0]); + sappend(dest,'v',SET_F("D1"),dnsAddress[1]); + sappend(dest,'v',SET_F("D2"),dnsAddress[2]); + sappend(dest,'v',SET_F("D3"),dnsAddress[3]); - sappends('s',SET_F("CM"),cmDNS); - sappend('i',SET_F("AB"),apBehavior); - sappends('s',SET_F("AS"),apSSID); - sappend('c',SET_F("AH"),apHide); + sappends(dest,'s',SET_F("CM"),cmDNS); + sappend(dest,'i',SET_F("AB"),apBehavior); + sappends(dest,'s',SET_F("AS"),apSSID); + sappend(dest,'c',SET_F("AH"),apHide); l = strlen(apPass); char fapass[l+1]; //fill password field with *** fapass[l] = 0; memset(fapass,'*',l); - sappends('s',SET_F("AP"),fapass); + sappends(dest,'s',SET_F("AP"),fapass); - sappend('v',SET_F("AC"),apChannel); + sappend(dest,'v',SET_F("AC"),apChannel); #ifdef ARDUINO_ARCH_ESP32 - sappend('v',SET_F("TX"),txPower); + sappend(dest,'v',SET_F("TX"),txPower); #else - oappend(SET_F("gId('tx').style.display='none';")); + dest.print(F("gId('tx').style.display='none';")); #endif - sappend('c',SET_F("FG"),force802_3g); - sappend('c',SET_F("WS"),noWifiSleep); + sappend(dest,'c',SET_F("FG"),force802_3g); + sappend(dest,'c',SET_F("WS"),noWifiSleep); #ifndef WLED_DISABLE_ESPNOW - sappend('c',SET_F("RE"),enableESPNow); - sappends('s',SET_F("RMAC"),linked_remote); + sappend(dest,'c',SET_F("RE"),enableESPNow); + sappends(dest,'s',SET_F("RMAC"),linked_remote); #else //hide remote settings if not compiled - oappend(SET_F("toggle('ESPNOW');")); // hide ESP-NOW setting + dest.print(F("toggle('ESPNOW');")); // hide ESP-NOW setting #endif #ifdef WLED_USE_ETHERNET - sappend('v',SET_F("ETH"),ethernetType); + sappend(dest,'v',SET_F("ETH"),ethernetType); #else //hide ethernet setting if not compiled in - oappend(SET_F("gId('ethd').style.display='none';")); + dest.print(F("gId('ethd').style.display='none';")); #endif if (Network.isConnected()) //is connected @@ -290,10 +283,10 @@ void getSettingsJS(byte subPage, char* dest) #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) if (Network.isEthernet()) strcat_P(s ,SET_F(" (Ethernet)")); #endif - sappends('m',SET_F("(\"sip\")[0]"),s); + sappends(dest,'m',SET_F("(\"sip\")[0]"),s); } else { - sappends('m',SET_F("(\"sip\")[0]"),(char*)F("Not connected")); + sappends(dest,'m',SET_F("(\"sip\")[0]"),(char*)F("Not connected")); } if (WiFi.softAPIP()[0] != 0) //is active @@ -301,19 +294,19 @@ void getSettingsJS(byte subPage, char* dest) char s[16]; IPAddress apIP = WiFi.softAPIP(); sprintf(s, "%d.%d.%d.%d", apIP[0], apIP[1], apIP[2], apIP[3]); - sappends('m',SET_F("(\"sip\")[1]"),s); + sappends(dest,'m',SET_F("(\"sip\")[1]"),s); } else { - sappends('m',SET_F("(\"sip\")[1]"),(char*)F("Not active")); + sappends(dest,'m',SET_F("(\"sip\")[1]"),(char*)F("Not active")); } #ifndef WLED_DISABLE_ESPNOW if (strlen(last_signal_src) > 0) { //Have seen an ESP-NOW Remote - sappends('m',SET_F("(\"rlid\")[0]"),last_signal_src); + sappends(dest,'m',SET_F("(\"rlid\")[0]"),last_signal_src); } else if (!enableESPNow) { - sappends('m',SET_F("(\"rlid\")[0]"),(char*)F("(Enable ESP-NOW to listen)")); + sappends(dest,'m',SET_F("(\"rlid\")[0]"),(char*)F("(Enable ESP-NOW to listen)")); } else { - sappends('m',SET_F("(\"rlid\")[0]"),(char*)F("None")); + sappends(dest,'m',SET_F("(\"rlid\")[0]"),(char*)F("None")); } #endif } @@ -322,30 +315,30 @@ void getSettingsJS(byte subPage, char* dest) { char nS[32]; - appendGPIOinfo(); + appendGPIOinfo(dest); - oappend(SET_F("d.ledTypes=")); oappend(BusManager::getLEDTypesJSONString().c_str()); oappend(";"); + dest.print(SET_F("d.ledTypes=")); dest.print(BusManager::getLEDTypesJSONString().c_str()); dest.print(";"); // set limits - oappend(SET_F("bLimits(")); - oappend(itoa(WLED_MAX_BUSSES,nS,10)); oappend(","); - oappend(itoa(WLED_MIN_VIRTUAL_BUSSES,nS,10)); oappend(","); - oappend(itoa(MAX_LEDS_PER_BUS,nS,10)); oappend(","); - oappend(itoa(MAX_LED_MEMORY,nS,10)); oappend(","); - oappend(itoa(MAX_LEDS,nS,10)); oappend(","); - oappend(itoa(WLED_MAX_COLOR_ORDER_MAPPINGS,nS,10)); oappend(","); - oappend(itoa(WLED_MAX_DIGITAL_CHANNELS,nS,10)); oappend(","); - oappend(itoa(WLED_MAX_ANALOG_CHANNELS,nS,10)); - oappend(SET_F(");")); + dest.print(F("bLimits(")); + dest.print(itoa(WLED_MAX_BUSSES,nS,10)); dest.print(","); + dest.print(itoa(WLED_MIN_VIRTUAL_BUSSES,nS,10)); dest.print(","); + dest.print(itoa(MAX_LEDS_PER_BUS,nS,10)); dest.print(","); + dest.print(itoa(MAX_LED_MEMORY,nS,10)); dest.print(","); + dest.print(itoa(MAX_LEDS,nS,10)); dest.print(","); + dest.print(itoa(WLED_MAX_COLOR_ORDER_MAPPINGS,nS,10)); dest.print(","); + dest.print(itoa(WLED_MAX_DIGITAL_CHANNELS,nS,10)); dest.print(","); + dest.print(itoa(WLED_MAX_ANALOG_CHANNELS,nS,10)); + dest.print(F(");")); - sappend('c',SET_F("MS"),strip.autoSegments); - sappend('c',SET_F("CCT"),strip.correctWB); - sappend('c',SET_F("IC"),cctICused); - sappend('c',SET_F("CR"),strip.cctFromRgb); - sappend('v',SET_F("CB"),strip.cctBlending); - sappend('v',SET_F("FR"),strip.getTargetFps()); - sappend('v',SET_F("AW"),Bus::getGlobalAWMode()); - sappend('c',SET_F("LD"),useGlobalLedBuffer); + sappend(dest,'c',SET_F("MS"),strip.autoSegments); + sappend(dest,'c',SET_F("CCT"),strip.correctWB); + sappend(dest,'c',SET_F("IC"),cctICused); + sappend(dest,'c',SET_F("CR"),strip.cctFromRgb); + sappend(dest,'v',SET_F("CB"),strip.cctBlending); + sappend(dest,'v',SET_F("FR"),strip.getTargetFps()); + sappend(dest,'v',SET_F("AW"),Bus::getGlobalAWMode()); + sappend(dest,'c',SET_F("LD"),useGlobalLedBuffer); unsigned sumMa = 0; for (int s = 0; s < BusManager::getNumBusses(); s++) { @@ -365,22 +358,22 @@ void getSettingsJS(byte subPage, char* dest) char sp[4] = "SP"; sp[2] = offset+s; sp[3] = 0; //bus clock speed char la[4] = "LA"; la[2] = offset+s; la[3] = 0; //LED current char ma[4] = "MA"; ma[2] = offset+s; ma[3] = 0; //max per-port PSU current - oappend(SET_F("addLEDs(1);")); + dest.print(F("addLEDs(1);")); uint8_t pins[5]; int nPins = bus->getPins(pins); for (int i = 0; i < nPins; i++) { lp[1] = offset+i; - if (pinManager.isPinOk(pins[i]) || bus->isVirtual()) sappend('v',lp,pins[i]); + if (pinManager.isPinOk(pins[i]) || bus->isVirtual()) sappend(dest,'v',lp,pins[i]); } - sappend('v',lc,bus->getLength()); - sappend('v',lt,bus->getType()); - sappend('v',co,bus->getColorOrder() & 0x0F); - sappend('v',ls,bus->getStart()); - sappend('c',cv,bus->isReversed()); - sappend('v',sl,bus->skippedLeds()); - sappend('c',rf,bus->isOffRefreshRequired()); - sappend('v',aw,bus->getAutoWhiteMode()); - sappend('v',wo,bus->getColorOrder() >> 4); + sappend(dest,'v',lc,bus->getLength()); + sappend(dest,'v',lt,bus->getType()); + sappend(dest,'v',co,bus->getColorOrder() & 0x0F); + sappend(dest,'v',ls,bus->getStart()); + sappend(dest,'c',cv,bus->isReversed()); + sappend(dest,'v',sl,bus->skippedLeds()); + sappend(dest,'c',rf,bus->isOffRefreshRequired()); + sappend(dest,'v',aw,bus->getAutoWhiteMode()); + sappend(dest,'v',wo,bus->getColorOrder() >> 4); unsigned speed = bus->getFrequency(); if (bus->isPWM()) { switch (speed) { @@ -401,158 +394,158 @@ void getSettingsJS(byte subPage, char* dest) case 20000 : speed = 4; break; } } - sappend('v',sp,speed); - sappend('v',la,bus->getLEDCurrent()); - sappend('v',ma,bus->getMaxCurrent()); + sappend(dest,'v',sp,speed); + sappend(dest,'v',la,bus->getLEDCurrent()); + sappend(dest,'v',ma,bus->getMaxCurrent()); sumMa += bus->getMaxCurrent(); } - sappend('v',SET_F("MA"),BusManager::ablMilliampsMax() ? BusManager::ablMilliampsMax() : sumMa); - sappend('c',SET_F("ABL"),BusManager::ablMilliampsMax() || sumMa > 0); - sappend('c',SET_F("PPL"),!BusManager::ablMilliampsMax() && sumMa > 0); + sappend(dest,'v',SET_F("MA"),BusManager::ablMilliampsMax() ? BusManager::ablMilliampsMax() : sumMa); + sappend(dest,'c',SET_F("ABL"),BusManager::ablMilliampsMax() || sumMa > 0); + sappend(dest,'c',SET_F("PPL"),!BusManager::ablMilliampsMax() && sumMa > 0); - oappend(SET_F("resetCOM(")); - oappend(itoa(WLED_MAX_COLOR_ORDER_MAPPINGS,nS,10)); - oappend(SET_F(");")); + dest.print(F("resetCOM(")); + dest.print(itoa(WLED_MAX_COLOR_ORDER_MAPPINGS,nS,10)); + dest.print(F(");")); const ColorOrderMap& com = BusManager::getColorOrderMap(); for (int s = 0; s < com.count(); s++) { const ColorOrderMapEntry* entry = com.get(s); if (entry == nullptr) break; - oappend(SET_F("addCOM(")); - oappend(itoa(entry->start,nS,10)); oappend(","); - oappend(itoa(entry->len,nS,10)); oappend(","); - oappend(itoa(entry->colorOrder,nS,10)); oappend(");"); + dest.print(F("addCOM(")); + dest.print(itoa(entry->start,nS,10)); dest.print(","); + dest.print(itoa(entry->len,nS,10)); dest.print(","); + dest.print(itoa(entry->colorOrder,nS,10)); dest.print(");"); } - sappend('v',SET_F("CA"),briS); + sappend(dest,'v',SET_F("CA"),briS); - sappend('c',SET_F("BO"),turnOnAtBoot); - sappend('v',SET_F("BP"),bootPreset); + sappend(dest,'c',SET_F("BO"),turnOnAtBoot); + sappend(dest,'v',SET_F("BP"),bootPreset); - sappend('c',SET_F("GB"),gammaCorrectBri); - sappend('c',SET_F("GC"),gammaCorrectCol); - dtostrf(gammaCorrectVal,3,1,nS); sappends('s',SET_F("GV"),nS); - sappend('c',SET_F("TF"),fadeTransition); - sappend('c',SET_F("EB"),modeBlending); - sappend('v',SET_F("TD"),transitionDelayDefault); - sappend('c',SET_F("PF"),strip.paletteFade); - sappend('v',SET_F("TP"),randomPaletteChangeTime); - sappend('c',SET_F("TH"),useHarmonicRandomPalette); - sappend('v',SET_F("BF"),briMultiplier); - sappend('v',SET_F("TB"),nightlightTargetBri); - sappend('v',SET_F("TL"),nightlightDelayMinsDefault); - sappend('v',SET_F("TW"),nightlightMode); - sappend('i',SET_F("PB"),strip.paletteBlend); - sappend('v',SET_F("RL"),rlyPin); - sappend('c',SET_F("RM"),rlyMde); - sappend('c',SET_F("RO"),rlyOpenDrain); + sappend(dest,'c',SET_F("GB"),gammaCorrectBri); + sappend(dest,'c',SET_F("GC"),gammaCorrectCol); + dtostrf(gammaCorrectVal,3,1,nS); sappends(dest,'s',SET_F("GV"),nS); + sappend(dest,'c',SET_F("TF"),fadeTransition); + sappend(dest,'c',SET_F("EB"),modeBlending); + sappend(dest,'v',SET_F("TD"),transitionDelayDefault); + sappend(dest,'c',SET_F("PF"),strip.paletteFade); + sappend(dest,'v',SET_F("TP"),randomPaletteChangeTime); + sappend(dest,'c',SET_F("TH"),useHarmonicRandomPalette); + sappend(dest,'v',SET_F("BF"),briMultiplier); + sappend(dest,'v',SET_F("TB"),nightlightTargetBri); + sappend(dest,'v',SET_F("TL"),nightlightDelayMinsDefault); + sappend(dest,'v',SET_F("TW"),nightlightMode); + sappend(dest,'i',SET_F("PB"),strip.paletteBlend); + sappend(dest,'v',SET_F("RL"),rlyPin); + sappend(dest,'c',SET_F("RM"),rlyMde); + sappend(dest,'c',SET_F("RO"),rlyOpenDrain); for (int i = 0; i < WLED_MAX_BUTTONS; i++) { - oappend(SET_F("addBtn(")); - oappend(itoa(i,nS,10)); oappend(","); - oappend(itoa(btnPin[i],nS,10)); oappend(","); - oappend(itoa(buttonType[i],nS,10)); - oappend(SET_F(");")); + dest.print(F("addBtn(")); + dest.print(itoa(i,nS,10)); dest.print(","); + dest.print(itoa(btnPin[i],nS,10)); dest.print(","); + dest.print(itoa(buttonType[i],nS,10)); + dest.print(F(");")); } - sappend('c',SET_F("IP"),disablePullUp); - sappend('v',SET_F("TT"),touchThreshold); + sappend(dest,'c',SET_F("IP"),disablePullUp); + sappend(dest,'v',SET_F("TT"),touchThreshold); #ifndef WLED_DISABLE_INFRARED - sappend('v',SET_F("IR"),irPin); - sappend('v',SET_F("IT"),irEnabled); + sappend(dest,'v',SET_F("IR"),irPin); + sappend(dest,'v',SET_F("IT"),irEnabled); #endif - sappend('c',SET_F("MSO"),!irApplyToAllSelected); + sappend(dest,'c',SET_F("MSO"),!irApplyToAllSelected); } if (subPage == SUBPAGE_UI) { - sappends('s',SET_F("DS"),serverDescription); - sappend('c',SET_F("SU"),simplifiedUI); + sappends(dest,'s',SET_F("DS"),serverDescription); + sappend(dest,'c',SET_F("SU"),simplifiedUI); } if (subPage == SUBPAGE_SYNC) { [[maybe_unused]] char nS[32]; - sappend('v',SET_F("UP"),udpPort); - sappend('v',SET_F("U2"),udpPort2); + sappend(dest,'v',SET_F("UP"),udpPort); + sappend(dest,'v',SET_F("U2"),udpPort2); #ifndef WLED_DISABLE_ESPNOW - if (enableESPNow) sappend('c',SET_F("EN"),useESPNowSync); - else oappend(SET_F("toggle('ESPNOW');")); // hide ESP-NOW setting + if (enableESPNow) sappend(dest,'c',SET_F("EN"),useESPNowSync); + else dest.print(F("toggle('ESPNOW');")); // hide ESP-NOW setting #else - oappend(SET_F("toggle('ESPNOW');")); // hide ESP-NOW setting + dest.print(F("toggle('ESPNOW');")); // hide ESP-NOW setting #endif - sappend('v',SET_F("GS"),syncGroups); - sappend('v',SET_F("GR"),receiveGroups); + sappend(dest,'v',SET_F("GS"),syncGroups); + sappend(dest,'v',SET_F("GR"),receiveGroups); - sappend('c',SET_F("RB"),receiveNotificationBrightness); - sappend('c',SET_F("RC"),receiveNotificationColor); - sappend('c',SET_F("RX"),receiveNotificationEffects); - sappend('c',SET_F("RP"),receiveNotificationPalette); - sappend('c',SET_F("SO"),receiveSegmentOptions); - sappend('c',SET_F("SG"),receiveSegmentBounds); - sappend('c',SET_F("SS"),sendNotifications); - sappend('c',SET_F("SD"),notifyDirect); - sappend('c',SET_F("SB"),notifyButton); - sappend('c',SET_F("SH"),notifyHue); - sappend('v',SET_F("UR"),udpNumRetries); + sappend(dest,'c',SET_F("RB"),receiveNotificationBrightness); + sappend(dest,'c',SET_F("RC"),receiveNotificationColor); + sappend(dest,'c',SET_F("RX"),receiveNotificationEffects); + sappend(dest,'c',SET_F("RP"),receiveNotificationPalette); + sappend(dest,'c',SET_F("SO"),receiveSegmentOptions); + sappend(dest,'c',SET_F("SG"),receiveSegmentBounds); + sappend(dest,'c',SET_F("SS"),sendNotifications); + sappend(dest,'c',SET_F("SD"),notifyDirect); + sappend(dest,'c',SET_F("SB"),notifyButton); + sappend(dest,'c',SET_F("SH"),notifyHue); + sappend(dest,'v',SET_F("UR"),udpNumRetries); - sappend('c',SET_F("NL"),nodeListEnabled); - sappend('c',SET_F("NB"),nodeBroadcastEnabled); + sappend(dest,'c',SET_F("NL"),nodeListEnabled); + sappend(dest,'c',SET_F("NB"),nodeBroadcastEnabled); - sappend('c',SET_F("RD"),receiveDirect); - sappend('c',SET_F("MO"),useMainSegmentOnly); - sappend('c',SET_F("RLM"),realtimeRespectLedMaps); - sappend('v',SET_F("EP"),e131Port); - sappend('c',SET_F("ES"),e131SkipOutOfSequence); - sappend('c',SET_F("EM"),e131Multicast); - sappend('v',SET_F("EU"),e131Universe); - sappend('v',SET_F("DA"),DMXAddress); - sappend('v',SET_F("XX"),DMXSegmentSpacing); - sappend('v',SET_F("PY"),e131Priority); - sappend('v',SET_F("DM"),DMXMode); - sappend('v',SET_F("ET"),realtimeTimeoutMs); - sappend('c',SET_F("FB"),arlsForceMaxBri); - sappend('c',SET_F("RG"),arlsDisableGammaCorrection); - sappend('v',SET_F("WO"),arlsOffset); + sappend(dest,'c',SET_F("RD"),receiveDirect); + sappend(dest,'c',SET_F("MO"),useMainSegmentOnly); + sappend(dest,'c',SET_F("RLM"),realtimeRespectLedMaps); + sappend(dest,'v',SET_F("EP"),e131Port); + sappend(dest,'c',SET_F("ES"),e131SkipOutOfSequence); + sappend(dest,'c',SET_F("EM"),e131Multicast); + sappend(dest,'v',SET_F("EU"),e131Universe); + sappend(dest,'v',SET_F("DA"),DMXAddress); + sappend(dest,'v',SET_F("XX"),DMXSegmentSpacing); + sappend(dest,'v',SET_F("PY"),e131Priority); + sappend(dest,'v',SET_F("DM"),DMXMode); + sappend(dest,'v',SET_F("ET"),realtimeTimeoutMs); + sappend(dest,'c',SET_F("FB"),arlsForceMaxBri); + sappend(dest,'c',SET_F("RG"),arlsDisableGammaCorrection); + sappend(dest,'v',SET_F("WO"),arlsOffset); #ifndef WLED_DISABLE_ALEXA - sappend('c',SET_F("AL"),alexaEnabled); - sappends('s',SET_F("AI"),alexaInvocationName); - sappend('c',SET_F("SA"),notifyAlexa); - sappend('v',SET_F("AP"),alexaNumPresets); + sappend(dest,'c',SET_F("AL"),alexaEnabled); + sappends(dest,'s',SET_F("AI"),alexaInvocationName); + sappend(dest,'c',SET_F("SA"),notifyAlexa); + sappend(dest,'v',SET_F("AP"),alexaNumPresets); #else - oappend(SET_F("toggle('Alexa');")); // hide Alexa settings + dest.print(F("toggle('Alexa');")); // hide Alexa settings #endif #ifndef WLED_DISABLE_MQTT - sappend('c',SET_F("MQ"),mqttEnabled); - sappends('s',SET_F("MS"),mqttServer); - sappend('v',SET_F("MQPORT"),mqttPort); - sappends('s',SET_F("MQUSER"),mqttUser); + sappend(dest,'c',SET_F("MQ"),mqttEnabled); + sappends(dest,'s',SET_F("MS"),mqttServer); + sappend(dest,'v',SET_F("MQPORT"),mqttPort); + sappends(dest,'s',SET_F("MQUSER"),mqttUser); byte l = strlen(mqttPass); char fpass[l+1]; //fill password field with *** fpass[l] = 0; memset(fpass,'*',l); - sappends('s',SET_F("MQPASS"),fpass); - sappends('s',SET_F("MQCID"),mqttClientID); - sappends('s',"MD",mqttDeviceTopic); - sappends('s',SET_F("MG"),mqttGroupTopic); - sappend('c',SET_F("BM"),buttonPublishMqtt); - sappend('c',SET_F("RT"),retainMqttMsg); - oappend(SET_F("d.Sf.MD.maxlength=")); oappend(itoa(MQTT_MAX_TOPIC_LEN,nS,10)); oappend(SET_F(";")); - oappend(SET_F("d.Sf.MG.maxlength=")); oappend(itoa(MQTT_MAX_TOPIC_LEN,nS,10)); oappend(SET_F(";")); - oappend(SET_F("d.Sf.MS.maxlength=")); oappend(itoa(MQTT_MAX_SERVER_LEN,nS,10)); oappend(SET_F(";")); + sappends(dest,'s',SET_F("MQPASS"),fpass); + sappends(dest,'s',SET_F("MQCID"),mqttClientID); + sappends(dest,'s',"MD",mqttDeviceTopic); + sappends(dest,'s',SET_F("MG"),mqttGroupTopic); + sappend(dest,'c',SET_F("BM"),buttonPublishMqtt); + sappend(dest,'c',SET_F("RT"),retainMqttMsg); + dest.print(F("d.Sf.MD.maxlength=")); dest.print(itoa(MQTT_MAX_TOPIC_LEN,nS,10)); dest.print(F(";")); + dest.print(F("d.Sf.MG.maxlength=")); dest.print(itoa(MQTT_MAX_TOPIC_LEN,nS,10)); dest.print(F(";")); + dest.print(F("d.Sf.MS.maxlength=")); dest.print(itoa(MQTT_MAX_SERVER_LEN,nS,10)); dest.print(F(";")); #else - oappend(SET_F("toggle('MQTT');")); // hide MQTT settings + dest.print(F("toggle('MQTT');")); // hide MQTT settings #endif #ifndef WLED_DISABLE_HUESYNC - sappend('v',SET_F("H0"),hueIP[0]); - sappend('v',SET_F("H1"),hueIP[1]); - sappend('v',SET_F("H2"),hueIP[2]); - sappend('v',SET_F("H3"),hueIP[3]); - sappend('v',SET_F("HL"),huePollLightId); - sappend('v',SET_F("HI"),huePollIntervalMs); - sappend('c',SET_F("HP"),huePollingEnabled); - sappend('c',SET_F("HO"),hueApplyOnOff); - sappend('c',SET_F("HB"),hueApplyBri); - sappend('c',SET_F("HC"),hueApplyColor); + sappend(dest,'v',SET_F("H0"),hueIP[0]); + sappend(dest,'v',SET_F("H1"),hueIP[1]); + sappend(dest,'v',SET_F("H2"),hueIP[2]); + sappend(dest,'v',SET_F("H3"),hueIP[3]); + sappend(dest,'v',SET_F("HL"),huePollLightId); + sappend(dest,'v',SET_F("HI"),huePollIntervalMs); + sappend(dest,'c',SET_F("HP"),huePollingEnabled); + sappend(dest,'c',SET_F("HO"),hueApplyOnOff); + sappend(dest,'c',SET_F("HB"),hueApplyBri); + sappend(dest,'c',SET_F("HC"),hueApplyColor); char hueErrorString[25]; switch (hueError) { @@ -566,61 +559,61 @@ void getSettingsJS(byte subPage, char* dest) default: sprintf_P(hueErrorString,PSTR("Bridge Error %i"),hueError); } - sappends('m',SET_F("(\"sip\")[0]"),hueErrorString); + sappends(dest,'m',SET_F("(\"sip\")[0]"),hueErrorString); #else - oappend(SET_F("toggle('Hue');")); // hide Hue Sync settings + dest.print(F("toggle('Hue');")); // hide Hue Sync settings #endif - sappend('v',SET_F("BD"),serialBaud); + sappend(dest,'v',SET_F("BD"),serialBaud); #ifndef WLED_ENABLE_ADALIGHT - oappend(SET_F("toggle('Serial);")); + dest.print(SET_F("toggle('Serial);")); #endif } if (subPage == SUBPAGE_TIME) { - sappend('c',SET_F("NT"),ntpEnabled); - sappends('s',SET_F("NS"),ntpServerName); - sappend('c',SET_F("CF"),!useAMPM); - sappend('i',SET_F("TZ"),currentTimezone); - sappend('v',SET_F("UO"),utcOffsetSecs); + sappend(dest,'c',SET_F("NT"),ntpEnabled); + sappends(dest,'s',SET_F("NS"),ntpServerName); + sappend(dest,'c',SET_F("CF"),!useAMPM); + sappend(dest,'i',SET_F("TZ"),currentTimezone); + sappend(dest,'v',SET_F("UO"),utcOffsetSecs); char tm[32]; dtostrf(longitude,4,2,tm); - sappends('s',SET_F("LN"),tm); + sappends(dest,'s',SET_F("LN"),tm); dtostrf(latitude,4,2,tm); - sappends('s',SET_F("LT"),tm); + sappends(dest,'s',SET_F("LT"),tm); getTimeString(tm); - sappends('m',SET_F("(\"times\")[0]"),tm); + sappends(dest,'m',SET_F("(\"times\")[0]"),tm); if ((int)(longitude*10.0f) || (int)(latitude*10.0f)) { sprintf_P(tm, PSTR("Sunrise: %02d:%02d Sunset: %02d:%02d"), hour(sunrise), minute(sunrise), hour(sunset), minute(sunset)); - sappends('m',SET_F("(\"times\")[1]"),tm); + sappends(dest,'m',SET_F("(\"times\")[1]"),tm); } - sappend('c',SET_F("OL"),overlayCurrent); - sappend('v',SET_F("O1"),overlayMin); - sappend('v',SET_F("O2"),overlayMax); - sappend('v',SET_F("OM"),analogClock12pixel); - sappend('c',SET_F("OS"),analogClockSecondsTrail); - sappend('c',SET_F("O5"),analogClock5MinuteMarks); - sappend('c',SET_F("OB"),analogClockSolidBlack); + sappend(dest,'c',SET_F("OL"),overlayCurrent); + sappend(dest,'v',SET_F("O1"),overlayMin); + sappend(dest,'v',SET_F("O2"),overlayMax); + sappend(dest,'v',SET_F("OM"),analogClock12pixel); + sappend(dest,'c',SET_F("OS"),analogClockSecondsTrail); + sappend(dest,'c',SET_F("O5"),analogClock5MinuteMarks); + sappend(dest,'c',SET_F("OB"),analogClockSolidBlack); - sappend('c',SET_F("CE"),countdownMode); - sappend('v',SET_F("CY"),countdownYear); - sappend('v',SET_F("CI"),countdownMonth); - sappend('v',SET_F("CD"),countdownDay); - sappend('v',SET_F("CH"),countdownHour); - sappend('v',SET_F("CM"),countdownMin); - sappend('v',SET_F("CS"),countdownSec); + sappend(dest,'c',SET_F("CE"),countdownMode); + sappend(dest,'v',SET_F("CY"),countdownYear); + sappend(dest,'v',SET_F("CI"),countdownMonth); + sappend(dest,'v',SET_F("CD"),countdownDay); + sappend(dest,'v',SET_F("CH"),countdownHour); + sappend(dest,'v',SET_F("CM"),countdownMin); + sappend(dest,'v',SET_F("CS"),countdownSec); - sappend('v',SET_F("A0"),macroAlexaOn); - sappend('v',SET_F("A1"),macroAlexaOff); - sappend('v',SET_F("MC"),macroCountdown); - sappend('v',SET_F("MN"),macroNl); + sappend(dest,'v',SET_F("A0"),macroAlexaOn); + sappend(dest,'v',SET_F("A1"),macroAlexaOff); + sappend(dest,'v',SET_F("MC"),macroCountdown); + sappend(dest,'v',SET_F("MN"),macroNl); for (unsigned i=0; i> 4) & 0x0F); - k[0] = 'P'; sappend('v',k,timerMonth[i] & 0x0F); - k[0] = 'D'; sappend('v',k,timerDay[i]); - k[0] = 'E'; sappend('v',k,timerDayEnd[i]); + k[0] = 'M'; sappend(dest,'v',k,(timerMonth[i] >> 4) & 0x0F); + k[0] = 'P'; sappend(dest,'v',k,timerMonth[i] & 0x0F); + k[0] = 'D'; sappend(dest,'v',k,timerDay[i]); + k[0] = 'E'; sappend(dest,'v',k,timerDayEnd[i]); } } } @@ -647,121 +640,116 @@ void getSettingsJS(byte subPage, char* dest) char fpass[l+1]; //fill PIN field with 0000 fpass[l] = 0; memset(fpass,'0',l); - sappends('s',SET_F("PIN"),fpass); - sappend('c',SET_F("NO"),otaLock); - sappend('c',SET_F("OW"),wifiLock); - sappend('c',SET_F("AO"),aOtaEnabled); - sappends('m',SET_F("(\"sip\")[0]"),(char*)F("WLED ")); - olen -= 2; //delete "; - oappend(versionString); - oappend(SET_F(" (build ")); - oappendi(VERSION); - oappend(SET_F(")\";")); - oappend(SET_F("sd=\"")); - oappend(serverDescription); - oappend(SET_F("\";")); + sappends(dest,'s',SET_F("PIN"),fpass); + sappend(dest,'c',SET_F("NO"),otaLock); + sappend(dest,'c',SET_F("OW"),wifiLock); + sappend(dest,'c',SET_F("AO"),aOtaEnabled); + char tmp_buf[128]; + snprintf_P(tmp_buf,sizeof(tmp_buf),PSTR("WLED %s (build %d)"),versionString,VERSION); + sappends(dest,'m',SET_F("(\"sip\")[0]"),tmp_buf); + dest.print(F("sd=\"")); + dest.print(serverDescription); + dest.print(F("\";")); } #ifdef WLED_ENABLE_DMX // include only if DMX is enabled if (subPage == SUBPAGE_DMX) { - sappend('v',SET_F("PU"),e131ProxyUniverse); + sappend(dest,'v',SET_F("PU"),e131ProxyUniverse); - sappend('v',SET_F("CN"),DMXChannels); - sappend('v',SET_F("CG"),DMXGap); - sappend('v',SET_F("CS"),DMXStart); - sappend('v',SET_F("SL"),DMXStartLED); + sappend(dest,'v',SET_F("CN"),DMXChannels); + sappend(dest,'v',SET_F("CG"),DMXGap); + sappend(dest,'v',SET_F("CS"),DMXStart); + sappend(dest,'v',SET_F("SL"),DMXStartLED); - sappend('i',SET_F("CH1"),DMXFixtureMap[0]); - sappend('i',SET_F("CH2"),DMXFixtureMap[1]); - sappend('i',SET_F("CH3"),DMXFixtureMap[2]); - sappend('i',SET_F("CH4"),DMXFixtureMap[3]); - sappend('i',SET_F("CH5"),DMXFixtureMap[4]); - sappend('i',SET_F("CH6"),DMXFixtureMap[5]); - sappend('i',SET_F("CH7"),DMXFixtureMap[6]); - sappend('i',SET_F("CH8"),DMXFixtureMap[7]); - sappend('i',SET_F("CH9"),DMXFixtureMap[8]); - sappend('i',SET_F("CH10"),DMXFixtureMap[9]); - sappend('i',SET_F("CH11"),DMXFixtureMap[10]); - sappend('i',SET_F("CH12"),DMXFixtureMap[11]); - sappend('i',SET_F("CH13"),DMXFixtureMap[12]); - sappend('i',SET_F("CH14"),DMXFixtureMap[13]); - sappend('i',SET_F("CH15"),DMXFixtureMap[14]); + sappend(dest,'i',SET_F("CH1"),DMXFixtureMap[0]); + sappend(dest,'i',SET_F("CH2"),DMXFixtureMap[1]); + sappend(dest,'i',SET_F("CH3"),DMXFixtureMap[2]); + sappend(dest,'i',SET_F("CH4"),DMXFixtureMap[3]); + sappend(dest,'i',SET_F("CH5"),DMXFixtureMap[4]); + sappend(dest,'i',SET_F("CH6"),DMXFixtureMap[5]); + sappend(dest,'i',SET_F("CH7"),DMXFixtureMap[6]); + sappend(dest,'i',SET_F("CH8"),DMXFixtureMap[7]); + sappend(dest,'i',SET_F("CH9"),DMXFixtureMap[8]); + sappend(dest,'i',SET_F("CH10"),DMXFixtureMap[9]); + sappend(dest,'i',SET_F("CH11"),DMXFixtureMap[10]); + sappend(dest,'i',SET_F("CH12"),DMXFixtureMap[11]); + sappend(dest,'i',SET_F("CH13"),DMXFixtureMap[12]); + sappend(dest,'i',SET_F("CH14"),DMXFixtureMap[13]); + sappend(dest,'i',SET_F("CH15"),DMXFixtureMap[14]); } #endif if (subPage == SUBPAGE_UM) //usermods { - appendGPIOinfo(); - oappend(SET_F("numM=")); - oappendi(usermods.getModCount()); - oappend(";"); - sappend('v',SET_F("SDA"),i2c_sda); - sappend('v',SET_F("SCL"),i2c_scl); - sappend('v',SET_F("MOSI"),spi_mosi); - sappend('v',SET_F("MISO"),spi_miso); - sappend('v',SET_F("SCLK"),spi_sclk); - oappend(SET_F("addInfo('SDA','")); oappendi(HW_PIN_SDA); oappend(SET_F("');")); - oappend(SET_F("addInfo('SCL','")); oappendi(HW_PIN_SCL); oappend(SET_F("');")); - oappend(SET_F("addInfo('MOSI','")); oappendi(HW_PIN_DATASPI); oappend(SET_F("');")); - oappend(SET_F("addInfo('MISO','")); oappendi(HW_PIN_MISOSPI); oappend(SET_F("');")); - oappend(SET_F("addInfo('SCLK','")); oappendi(HW_PIN_CLOCKSPI); oappend(SET_F("');")); - usermods.appendConfigData(); + appendGPIOinfo(dest); + dest.print(F("numM=")); + dest.print(usermods.getModCount()); + dest.print(";"); + sappend(dest,'v',SET_F("SDA"),i2c_sda); + sappend(dest,'v',SET_F("SCL"),i2c_scl); + sappend(dest,'v',SET_F("MOSI"),spi_mosi); + sappend(dest,'v',SET_F("MISO"),spi_miso); + sappend(dest,'v',SET_F("SCLK"),spi_sclk); + dest.print(F("addInfo('SDA','")); dest.print(HW_PIN_SDA); dest.print(F("');")); + dest.print(F("addInfo('SCL','")); dest.print(HW_PIN_SCL); dest.print(F("');")); + dest.print(F("addInfo('MOSI','")); dest.print(HW_PIN_DATASPI); dest.print(F("');")); + dest.print(F("addInfo('MISO','")); dest.print(HW_PIN_MISOSPI); dest.print(F("');")); + dest.print(F("addInfo('SCLK','")); dest.print(HW_PIN_CLOCKSPI); dest.print(F("');")); + usermods.appendConfigData(dest); } if (subPage == SUBPAGE_UPDATE) // update { - sappends('m',SET_F("(\"sip\")[0]"),(char*)F("WLED ")); - olen -= 2; //delete "; - oappend(versionString); - oappend(SET_F("
")); - oappend(releaseString); - oappend(SET_F("
(")); + char tmp_buf[128]; + snprintf_P(tmp_buf,sizeof(tmp_buf),PSTR("WLED %s
%s
(%s build %d)"), + versionString, + releaseString, #if defined(ARDUINO_ARCH_ESP32) - oappend(ESP.getChipModel()); + ESP.getChipModel(), #else - oappend("esp8266"); + F("esp8266"), #endif - oappend(SET_F(" build ")); - oappendi(VERSION); - oappend(SET_F(")\";")); + VERSION); + + sappends(dest,'m',SET_F("(\"sip\")[0]"),tmp_buf); } if (subPage == SUBPAGE_2D) // 2D matrices { - sappend('v',SET_F("SOMP"),strip.isMatrix); + sappend(dest,'v',SET_F("SOMP"),strip.isMatrix); #ifndef WLED_DISABLE_2D - oappend(SET_F("maxPanels=")); oappendi(WLED_MAX_PANELS); oappend(SET_F(";")); - oappend(SET_F("resetPanels();")); + dest.print(F("maxPanels=")); dest.print(WLED_MAX_PANELS); dest.print(F(";")); + dest.print(F("resetPanels();")); if (strip.isMatrix) { if(strip.panels>0){ - sappend('v',SET_F("PW"),strip.panel[0].width); //Set generator Width and Height to first panel size for convenience - sappend('v',SET_F("PH"),strip.panel[0].height); + sappend(dest,'v',SET_F("PW"),strip.panel[0].width); //Set generator Width and Height to first panel size for convenience + sappend(dest,'v',SET_F("PH"),strip.panel[0].height); } - sappend('v',SET_F("MPC"),strip.panels); + sappend(dest,'v',SET_F("MPC"),strip.panels); // panels for (unsigned i=0; i Date: Tue, 17 Sep 2024 18:26:46 -0400 Subject: [PATCH 022/234] Usermod: Implement shim for oappend Use a static Print* to transform old oappend calls to print calls. --- wled00/fcn_declare.h | 12 +++++++++++- wled00/um_manager.cpp | 11 +++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 6ce30facf..8c90e2be1 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -302,7 +302,7 @@ class Usermod { virtual bool handleButton(uint8_t b) { return false; } // button overrides are possible here virtual bool getUMData(um_data_t **data) { if (data) *data = nullptr; return false; }; // usermod data exchange [see examples for audio effects] virtual void connected() {} // called when WiFi is (re)connected - virtual void appendConfigData(Print&) {} // helper function called from usermod settings page to add metadata for entry fields + virtual void appendConfigData(Print&); // helper function called from usermod settings page to add metadata for entry fields virtual void addToJsonState(JsonObject& obj) {} // add JSON objects for WLED state virtual void addToJsonInfo(JsonObject& obj) {} // add JSON objects for UI Info page virtual void readFromJsonState(JsonObject& obj) {} // process JSON messages received from web server @@ -314,6 +314,16 @@ class Usermod { virtual void onUpdateBegin(bool) {} // fired prior to and after unsuccessful firmware update virtual void onStateChange(uint8_t mode) {} // fired upon WLED state change virtual uint16_t getId() {return USERMOD_ID_UNSPECIFIED;} + + // API shims + private: + static Print* oappend_shim; + // old form of appendConfigData; called by default appendConfigData(Print&) with oappend_shim set up + // private so it is not accidentally invoked except via Usermod::appendConfigData(Print&) + virtual void appendConfigData() {} + protected: + // Shim for oappend(), which used to exist in utils.cpp + template static inline void oappend(const T& t) { oappend_shim->print(t); }; }; class UsermodManager { diff --git a/wled00/um_manager.cpp b/wled00/um_manager.cpp index 3970e7af4..5307d26f6 100644 --- a/wled00/um_manager.cpp +++ b/wled00/um_manager.cpp @@ -68,3 +68,14 @@ bool UsermodManager::add(Usermod* um) ums[numMods++] = um; return true; } + + +/* Usermod v2 interface shim for oappend */ +Print* Usermod::oappend_shim = nullptr; + +void Usermod::appendConfigData(Print& p) { + assert(!oappend_shim); + oappend_shim = &p; + this->appendConfigData(); + oappend_shim = nullptr; +} From 4ef583c8445e74eea3f6c0bc5805563728351f17 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sat, 7 Sep 2024 19:52:30 -0400 Subject: [PATCH 023/234] xml: Print optimization Reduce the total number of calls by using printf_P and skipping atoi(). --- wled00/xml.cpp | 171 +++++++++++++++---------------------------------- 1 file changed, 50 insertions(+), 121 deletions(-) diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 2d63d61f3..5ed1109c9 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -8,63 +8,22 @@ //build XML response to HTTP /win API request void XML_response(Print& dest) { - dest.print(F("")); - dest.print((nightlightActive && nightlightMode > NL_MODE_SET) ? briT : bri); - dest.print(F("")); - + dest.printf_P(PSTR("%d"), (nightlightActive && nightlightMode > NL_MODE_SET) ? briT : bri); for (int i = 0; i < 3; i++) { - dest.print(""); - dest.print(col[i]); - dest.print(""); + dest.printf_P(PSTR("%d"), col[i]); } for (int i = 0; i < 3; i++) { - dest.print(""); - dest.print(colSec[i]); - dest.print(""); + dest.printf_P(PSTR("%d"), colSec[i]); } - dest.print(F("")); - dest.print(notifyDirect); - dest.print(F("")); - dest.print(receiveGroups!=0); - dest.print(F("")); - dest.print(nightlightActive); - dest.print(F("")); - dest.print(nightlightMode > NL_MODE_SET); - dest.print(F("")); - dest.print(nightlightDelayMins); - dest.print(F("")); - dest.print(nightlightTargetBri); - dest.print(F("")); - dest.print(effectCurrent); - dest.print(F("")); - dest.print(effectSpeed); - dest.print(F("")); - dest.print(effectIntensity); - dest.print(F("")); - dest.print(effectPalette); - dest.print(F("")); - if (strip.hasWhiteChannel()) { - dest.print(col[3]); - } else { - dest.print("-1"); - } - dest.print(F("")); - dest.print(colSec[3]); - dest.print(F("")); - dest.print(currentPreset); - dest.print(F("")); - dest.print(currentPlaylist >= 0); - dest.print(F("")); - dest.print(serverDescription); - if (realtimeMode) - { - dest.print(F(" (live)")); - } - dest.print(F("")); - dest.print(strip.getFirstSelectedSegId()); - dest.print(F("")); + dest.printf_P(PSTR("%d%d%d%d%d%d%d%d%d%d%d%d%d%d%s%s%d"), + notifyDirect, receiveGroups!=0, nightlightActive, nightlightMode > NL_MODE_SET, nightlightDelayMins, + nightlightTargetBri, effectCurrent, effectSpeed, effectIntensity, effectPalette, + strip.hasWhiteChannel() ? col[3] : -1, colSec[3], currentPreset, currentPlaylist >= 0, + serverDescription, realtimeMode ? PSTR(" (live)") : "", + strip.getFirstSelectedSegId() + ); } static void extractPin(Print& dest, JsonObject &obj, const char *key) { @@ -114,17 +73,12 @@ void fillUMPins(Print& dest, JsonObject &mods) } void appendGPIOinfo(Print& dest) { - char nS[8]; - - // add usermod pins as d.um_p array dest.print(F("d.um_p=[-1")); // has to have 1 element if (i2c_sda > -1 && i2c_scl > -1) { - dest.print(","); dest.print(itoa(i2c_sda,nS,10)); - dest.print(","); dest.print(itoa(i2c_scl,nS,10)); + dest.printf_P(PSTR(",%d,%d"), i2c_sda, i2c_scl); } if (spi_mosi > -1 && spi_sclk > -1) { - dest.print(","); dest.print(itoa(spi_mosi,nS,10)); - dest.print(","); dest.print(itoa(spi_sclk,nS,10)); + dest.printf_P(PSTR(",%d,%d"), spi_mosi, spi_sclk); } // usermod pin reservations will become unnecessary when settings pages will read cfg.json directly if (requestJSONBufferLock(6)) { @@ -147,16 +101,16 @@ void appendGPIOinfo(Print& dest) { dest.print(SET_F("2,")); // DMX hardcoded pin #endif #if defined(WLED_DEBUG) && !defined(WLED_DEBUG_HOST) - dest.print(itoa(hardwareTX,nS,10)); dest.print(","); // debug output (TX) pin + dest.printf_P(PSTR(",%d"),hardwareTX); // debug output (TX) pin #endif //Note: Using pin 3 (RX) disables Adalight / Serial JSON #ifdef WLED_USE_ETHERNET if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) { - for (unsigned p=0; p=0) { dest.print(itoa(ethernetBoards[ethernetType].eth_power,nS,10)); dest.print(","); } - if (ethernetBoards[ethernetType].eth_mdc>=0) { dest.print(itoa(ethernetBoards[ethernetType].eth_mdc,nS,10)); dest.print(","); } - if (ethernetBoards[ethernetType].eth_mdio>=0) { dest.print(itoa(ethernetBoards[ethernetType].eth_mdio,nS,10)); dest.print(","); } - switch (ethernetBoards[ethernetType].eth_clk_mode) { + for (unsigned p=0; p=0) { dest.printf(",%d", ethernetBoards[ethernetType].eth_power); } + if (ethernetBoards[ethernetType].eth_mdc>=0) { dest.printf(",%d", ethernetBoards[ethernetType].eth_mdc); } + if (ethernetBoards[ethernetType].eth_mdio>=0) { dest.printf(",%d", ethernetBoards[ethernetType].eth_mdio); } + switch (ethernetBoards[ethernetType].eth_clk_mode) { case ETH_CLOCK_GPIO0_IN: case ETH_CLOCK_GPIO0_OUT: dest.print(SET_F("0")); @@ -211,27 +165,19 @@ void getSettingsJS(byte subPage, Print& dest) if (subPage == SUBPAGE_WIFI) { - char nS[10]; size_t l; - dest.print(F("resetWiFi(")); - dest.print(WLED_MAX_WIFI_COUNT); - dest.print(F(");")); + dest.printf_P(PSTR("resetWiFi(%d);"), WLED_MAX_WIFI_COUNT); for (size_t n = 0; n < multiWiFi.size(); n++) { l = strlen(multiWiFi[n].clientPass); char fpass[l+1]; //fill password field with *** fpass[l] = 0; memset(fpass,'*',l); - dest.print(F("addWiFi(\"")); - dest.print(multiWiFi[n].clientSSID); - dest.print(F("\",\"")); - dest.print(fpass); - dest.print(F("\",0x")); - dest.print(itoa(multiWiFi[n].staticIP,nS,16)); - dest.print(F(",0x")); - dest.print(itoa(multiWiFi[n].staticGW,nS,16)); - dest.print(F(",0x")); - dest.print(itoa(multiWiFi[n].staticSN,nS,16)); - dest.print(F(");")); + dest.printf_P(PSTR("addWiFi(\"%s\",\",%s\",0x%X,0x%X,0x%X);"), + multiWiFi[n].clientSSID, + fpass, + (uint32_t) multiWiFi[n].staticIP, // explicit cast required as this is a struct + (uint32_t) multiWiFi[n].staticGW, + (uint32_t) multiWiFi[n].staticSN); } sappend(dest,'v',SET_F("D0"),dnsAddress[0]); @@ -320,16 +266,16 @@ void getSettingsJS(byte subPage, Print& dest) dest.print(SET_F("d.ledTypes=")); dest.print(BusManager::getLEDTypesJSONString().c_str()); dest.print(";"); // set limits - dest.print(F("bLimits(")); - dest.print(itoa(WLED_MAX_BUSSES,nS,10)); dest.print(","); - dest.print(itoa(WLED_MIN_VIRTUAL_BUSSES,nS,10)); dest.print(","); - dest.print(itoa(MAX_LEDS_PER_BUS,nS,10)); dest.print(","); - dest.print(itoa(MAX_LED_MEMORY,nS,10)); dest.print(","); - dest.print(itoa(MAX_LEDS,nS,10)); dest.print(","); - dest.print(itoa(WLED_MAX_COLOR_ORDER_MAPPINGS,nS,10)); dest.print(","); - dest.print(itoa(WLED_MAX_DIGITAL_CHANNELS,nS,10)); dest.print(","); - dest.print(itoa(WLED_MAX_ANALOG_CHANNELS,nS,10)); - dest.print(F(");")); + dest.printf_P(PSTR("bLimits(%d,%d,%d,%d,%d,%d,%d,%d);"), + WLED_MAX_BUSSES, + WLED_MIN_VIRTUAL_BUSSES, + MAX_LEDS_PER_BUS, + MAX_LED_MEMORY, + MAX_LEDS, + WLED_MAX_COLOR_ORDER_MAPPINGS, + WLED_MAX_DIGITAL_CHANNELS, + WLED_MAX_ANALOG_CHANNELS + ); sappend(dest,'c',SET_F("MS"),strip.autoSegments); sappend(dest,'c',SET_F("CCT"),strip.correctWB); @@ -403,17 +349,12 @@ void getSettingsJS(byte subPage, Print& dest) sappend(dest,'c',SET_F("ABL"),BusManager::ablMilliampsMax() || sumMa > 0); sappend(dest,'c',SET_F("PPL"),!BusManager::ablMilliampsMax() && sumMa > 0); - dest.print(F("resetCOM(")); - dest.print(itoa(WLED_MAX_COLOR_ORDER_MAPPINGS,nS,10)); - dest.print(F(");")); + dest.printf_P(PSTR("resetCOM(%d);"), WLED_MAX_COLOR_ORDER_MAPPINGS); const ColorOrderMap& com = BusManager::getColorOrderMap(); for (int s = 0; s < com.count(); s++) { const ColorOrderMapEntry* entry = com.get(s); if (entry == nullptr) break; - dest.print(F("addCOM(")); - dest.print(itoa(entry->start,nS,10)); dest.print(","); - dest.print(itoa(entry->len,nS,10)); dest.print(","); - dest.print(itoa(entry->colorOrder,nS,10)); dest.print(");"); + dest.printf_P(PSTR("addCOM(%d,%d,%d);"), entry->start, entry->len, entry->colorOrder); } sappend(dest,'v',SET_F("CA"),briS); @@ -439,11 +380,7 @@ void getSettingsJS(byte subPage, Print& dest) sappend(dest,'c',SET_F("RM"),rlyMde); sappend(dest,'c',SET_F("RO"),rlyOpenDrain); for (int i = 0; i < WLED_MAX_BUTTONS; i++) { - dest.print(F("addBtn(")); - dest.print(itoa(i,nS,10)); dest.print(","); - dest.print(itoa(btnPin[i],nS,10)); dest.print(","); - dest.print(itoa(buttonType[i],nS,10)); - dest.print(F(");")); + dest.printf_P(PSTR("addBtn(%d,%d,%d);"), i, btnPin[i], buttonType[i]); } sappend(dest,'c',SET_F("IP"),disablePullUp); sappend(dest,'v',SET_F("TT"),touchThreshold); @@ -528,9 +465,8 @@ void getSettingsJS(byte subPage, Print& dest) sappends(dest,'s',SET_F("MG"),mqttGroupTopic); sappend(dest,'c',SET_F("BM"),buttonPublishMqtt); sappend(dest,'c',SET_F("RT"),retainMqttMsg); - dest.print(F("d.Sf.MD.maxlength=")); dest.print(itoa(MQTT_MAX_TOPIC_LEN,nS,10)); dest.print(F(";")); - dest.print(F("d.Sf.MG.maxlength=")); dest.print(itoa(MQTT_MAX_TOPIC_LEN,nS,10)); dest.print(F(";")); - dest.print(F("d.Sf.MS.maxlength=")); dest.print(itoa(MQTT_MAX_SERVER_LEN,nS,10)); dest.print(F(";")); + dest.printf_P(PSTR("d.Sf.MD.maxlength=%d;d.Sf.MG.maxlength=%d;d.Sf.MS.maxlength=%d;"), + MQTT_MAX_TOPIC_LEN, MQTT_MAX_TOPIC_LEN, MQTT_MAX_SERVER_LEN); #else dest.print(F("toggle('MQTT');")); // hide MQTT settings #endif @@ -608,12 +544,7 @@ void getSettingsJS(byte subPage, Print& dest) sappend(dest,'v',SET_F("MC"),macroCountdown); sappend(dest,'v',SET_F("MN"),macroNl); for (unsigned i=0; i Date: Mon, 9 Sep 2024 20:00:23 -0400 Subject: [PATCH 024/234] Replace sappend and sappends Use named functions to describe what's being printed. --- wled00/fcn_declare.h | 7 +- wled00/util.cpp | 53 ++---- wled00/xml.cpp | 422 +++++++++++++++++++++---------------------- 3 files changed, 235 insertions(+), 247 deletions(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 8c90e2be1..a36f2dc26 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -372,8 +372,11 @@ void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255); bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255); bool getBoolVal(JsonVariant elem, bool dflt); bool updateVal(const char* req, const char* key, byte* val, byte minv=0, byte maxv=255); -void sappend(Print& dest, char stype, const char* key, int val); -void sappends(Print& dest, char stype, const char* key, char* val); +size_t printSetCheckbox(Print& dest, const char* key, int val); +size_t printSetValue(Print& dest, const char* key, int val); +size_t printSetValue(Print& dest, const char* key, const char* val); +size_t printSetIndex(Print& dest, const char* key, int index); +size_t printSetMessage(Print& dest, const char* key, const char* val); void prepareHostname(char* hostname); bool isAsterisksOnly(const char* str, byte maxLen); bool requestJSONBufferLock(uint8_t module=255); diff --git a/wled00/util.cpp b/wled00/util.cpp index 00506ea97..660877d18 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -87,43 +87,28 @@ bool updateVal(const char* req, const char* key, byte* val, byte minv, byte maxv return true; } - -//append a numeric setting to string buffer -void sappend(Print& dest, char stype, const char* key, int val) -{ - const __FlashStringHelper* type_str; - switch(stype) - { - case 'c': //checkbox - type_str = F(".checked="); - break; - case 'v': //numeric - type_str = F(".value="); - break; - case 'i': //selectedIndex - type_str = F(".selectedIndex="); - break; - default: - return; //??? - } - - dest.printf_P(PSTR("d.Sf.%s%s%d;"), key, type_str, val); +static size_t printSetInt(Print& dest, const char* key, const char* selector, int value) { + return dest.printf_P(PSTR("d.Sf.%s.%s=%d;"), key, selector, value); } - -//append a string setting to buffer -void sappends(Print& dest, char stype, const char* key, char* val) -{ - switch(stype) - { - case 's': {//string (we can interpret val as char*) - dest.printf_P(PSTR("d.Sf.%s.value=\"%s\";"),key,val); - break;} - case 'm': //message - dest.printf_P(PSTR("d.getElementsByClassName%s.innerHTML=\"%s\";"), key, val); - break; - } +size_t printSetCheckbox(Print& dest, const char* key, int val) { + return printSetInt(dest, key, PSTR("checked"), val); } +size_t printSetValue(Print& dest, const char* key, int val) { + return printSetInt(dest, key, PSTR("value"), val); +} +size_t printSetIndex(Print& dest, const char* key, int index) { + return printSetInt(dest, key, PSTR("selectedIndex"), index); +} + +size_t printSetValue(Print& dest, const char* key, const char* val) { + return dest.printf_P(PSTR("d.Sf.%s.value=\"%s\";"),key,val); +} + +size_t printSetMessage(Print& dest, const char* key, const char* val) { + return dest.printf_P(PSTR("d.getElementsByClassName%s.innerHTML=\"%s\";"), key, val); +} + void prepareHostname(char* hostname) diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 5ed1109c9..e8858066c 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -180,41 +180,41 @@ void getSettingsJS(byte subPage, Print& dest) (uint32_t) multiWiFi[n].staticSN); } - sappend(dest,'v',SET_F("D0"),dnsAddress[0]); - sappend(dest,'v',SET_F("D1"),dnsAddress[1]); - sappend(dest,'v',SET_F("D2"),dnsAddress[2]); - sappend(dest,'v',SET_F("D3"),dnsAddress[3]); + printSetValue(dest,PSTR("D0"),dnsAddress[0]); + printSetValue(dest,PSTR("D1"),dnsAddress[1]); + printSetValue(dest,PSTR("D2"),dnsAddress[2]); + printSetValue(dest,PSTR("D3"),dnsAddress[3]); - sappends(dest,'s',SET_F("CM"),cmDNS); - sappend(dest,'i',SET_F("AB"),apBehavior); - sappends(dest,'s',SET_F("AS"),apSSID); - sappend(dest,'c',SET_F("AH"),apHide); + printSetValue(dest,PSTR("CM"),cmDNS); + printSetIndex(dest,PSTR("AB"),apBehavior); + printSetValue(dest,PSTR("AS"),apSSID); + printSetCheckbox(dest,PSTR("AH"),apHide); l = strlen(apPass); char fapass[l+1]; //fill password field with *** fapass[l] = 0; memset(fapass,'*',l); - sappends(dest,'s',SET_F("AP"),fapass); + printSetValue(dest,PSTR("AP"),fapass); - sappend(dest,'v',SET_F("AC"),apChannel); + printSetValue(dest,PSTR("AC"),apChannel); #ifdef ARDUINO_ARCH_ESP32 - sappend(dest,'v',SET_F("TX"),txPower); + printSetValue(dest,PSTR("TX"),txPower); #else dest.print(F("gId('tx').style.display='none';")); #endif - sappend(dest,'c',SET_F("FG"),force802_3g); - sappend(dest,'c',SET_F("WS"),noWifiSleep); + printSetCheckbox(dest,PSTR("FG"),force802_3g); + printSetCheckbox(dest,PSTR("WS"),noWifiSleep); #ifndef WLED_DISABLE_ESPNOW - sappend(dest,'c',SET_F("RE"),enableESPNow); - sappends(dest,'s',SET_F("RMAC"),linked_remote); + printSetCheckbox(dest,PSTR("RE"),enableESPNow); + printSetValue(dest,PSTR("RMAC"),linked_remote); #else //hide remote settings if not compiled dest.print(F("toggle('ESPNOW');")); // hide ESP-NOW setting #endif #ifdef WLED_USE_ETHERNET - sappend(dest,'v',SET_F("ETH"),ethernetType); + printSetValue(dest,PSTR("ETH"),ethernetType); #else //hide ethernet setting if not compiled in dest.print(F("gId('ethd').style.display='none';")); @@ -229,10 +229,10 @@ void getSettingsJS(byte subPage, Print& dest) #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) if (Network.isEthernet()) strcat_P(s ,SET_F(" (Ethernet)")); #endif - sappends(dest,'m',SET_F("(\"sip\")[0]"),s); + printSetMessage(dest,PSTR("(\"sip\")[0]"),s); } else { - sappends(dest,'m',SET_F("(\"sip\")[0]"),(char*)F("Not connected")); + printSetMessage(dest,PSTR("(\"sip\")[0]"),(char*)F("Not connected")); } if (WiFi.softAPIP()[0] != 0) //is active @@ -240,19 +240,19 @@ void getSettingsJS(byte subPage, Print& dest) char s[16]; IPAddress apIP = WiFi.softAPIP(); sprintf(s, "%d.%d.%d.%d", apIP[0], apIP[1], apIP[2], apIP[3]); - sappends(dest,'m',SET_F("(\"sip\")[1]"),s); + printSetMessage(dest,PSTR("(\"sip\")[1]"),s); } else { - sappends(dest,'m',SET_F("(\"sip\")[1]"),(char*)F("Not active")); + printSetMessage(dest,PSTR("(\"sip\")[1]"),(char*)F("Not active")); } #ifndef WLED_DISABLE_ESPNOW if (strlen(last_signal_src) > 0) { //Have seen an ESP-NOW Remote - sappends(dest,'m',SET_F("(\"rlid\")[0]"),last_signal_src); + printSetMessage(dest,PSTR("(\"rlid\")[0]"),last_signal_src); } else if (!enableESPNow) { - sappends(dest,'m',SET_F("(\"rlid\")[0]"),(char*)F("(Enable ESP-NOW to listen)")); + printSetMessage(dest,PSTR("(\"rlid\")[0]"),(char*)F("(Enable ESP-NOW to listen)")); } else { - sappends(dest,'m',SET_F("(\"rlid\")[0]"),(char*)F("None")); + printSetMessage(dest,PSTR("(\"rlid\")[0]"),(char*)F("None")); } #endif } @@ -277,14 +277,14 @@ void getSettingsJS(byte subPage, Print& dest) WLED_MAX_ANALOG_CHANNELS ); - sappend(dest,'c',SET_F("MS"),strip.autoSegments); - sappend(dest,'c',SET_F("CCT"),strip.correctWB); - sappend(dest,'c',SET_F("IC"),cctICused); - sappend(dest,'c',SET_F("CR"),strip.cctFromRgb); - sappend(dest,'v',SET_F("CB"),strip.cctBlending); - sappend(dest,'v',SET_F("FR"),strip.getTargetFps()); - sappend(dest,'v',SET_F("AW"),Bus::getGlobalAWMode()); - sappend(dest,'c',SET_F("LD"),useGlobalLedBuffer); + printSetCheckbox(dest,PSTR("MS"),strip.autoSegments); + printSetCheckbox(dest,PSTR("CCT"),strip.correctWB); + printSetCheckbox(dest,PSTR("IC"),cctICused); + printSetCheckbox(dest,PSTR("CR"),strip.cctFromRgb); + printSetValue(dest,PSTR("CB"),strip.cctBlending); + printSetValue(dest,PSTR("FR"),strip.getTargetFps()); + printSetValue(dest,PSTR("AW"),Bus::getGlobalAWMode()); + printSetCheckbox(dest,PSTR("LD"),useGlobalLedBuffer); unsigned sumMa = 0; for (int s = 0; s < BusManager::getNumBusses(); s++) { @@ -309,17 +309,17 @@ void getSettingsJS(byte subPage, Print& dest) int nPins = bus->getPins(pins); for (int i = 0; i < nPins; i++) { lp[1] = offset+i; - if (pinManager.isPinOk(pins[i]) || bus->isVirtual()) sappend(dest,'v',lp,pins[i]); + if (pinManager.isPinOk(pins[i]) || bus->isVirtual()) printSetValue(dest,lp,pins[i]); } - sappend(dest,'v',lc,bus->getLength()); - sappend(dest,'v',lt,bus->getType()); - sappend(dest,'v',co,bus->getColorOrder() & 0x0F); - sappend(dest,'v',ls,bus->getStart()); - sappend(dest,'c',cv,bus->isReversed()); - sappend(dest,'v',sl,bus->skippedLeds()); - sappend(dest,'c',rf,bus->isOffRefreshRequired()); - sappend(dest,'v',aw,bus->getAutoWhiteMode()); - sappend(dest,'v',wo,bus->getColorOrder() >> 4); + printSetValue(dest,lc,bus->getLength()); + printSetValue(dest,lt,bus->getType()); + printSetValue(dest,co,bus->getColorOrder() & 0x0F); + printSetValue(dest,ls,bus->getStart()); + printSetCheckbox(dest,cv,bus->isReversed()); + printSetValue(dest,sl,bus->skippedLeds()); + printSetCheckbox(dest,rf,bus->isOffRefreshRequired()); + printSetValue(dest,aw,bus->getAutoWhiteMode()); + printSetValue(dest,wo,bus->getColorOrder() >> 4); unsigned speed = bus->getFrequency(); if (bus->isPWM()) { switch (speed) { @@ -340,14 +340,14 @@ void getSettingsJS(byte subPage, Print& dest) case 20000 : speed = 4; break; } } - sappend(dest,'v',sp,speed); - sappend(dest,'v',la,bus->getLEDCurrent()); - sappend(dest,'v',ma,bus->getMaxCurrent()); + printSetValue(dest,sp,speed); + printSetValue(dest,la,bus->getLEDCurrent()); + printSetValue(dest,ma,bus->getMaxCurrent()); sumMa += bus->getMaxCurrent(); } - sappend(dest,'v',SET_F("MA"),BusManager::ablMilliampsMax() ? BusManager::ablMilliampsMax() : sumMa); - sappend(dest,'c',SET_F("ABL"),BusManager::ablMilliampsMax() || sumMa > 0); - sappend(dest,'c',SET_F("PPL"),!BusManager::ablMilliampsMax() && sumMa > 0); + printSetValue(dest,PSTR("MA"),BusManager::ablMilliampsMax() ? BusManager::ablMilliampsMax() : sumMa); + printSetCheckbox(dest,PSTR("ABL"),BusManager::ablMilliampsMax() || sumMa > 0); + printSetCheckbox(dest,PSTR("PPL"),!BusManager::ablMilliampsMax() && sumMa > 0); dest.printf_P(PSTR("resetCOM(%d);"), WLED_MAX_COLOR_ORDER_MAPPINGS); const ColorOrderMap& com = BusManager::getColorOrderMap(); @@ -357,114 +357,114 @@ void getSettingsJS(byte subPage, Print& dest) dest.printf_P(PSTR("addCOM(%d,%d,%d);"), entry->start, entry->len, entry->colorOrder); } - sappend(dest,'v',SET_F("CA"),briS); + printSetValue(dest,PSTR("CA"),briS); - sappend(dest,'c',SET_F("BO"),turnOnAtBoot); - sappend(dest,'v',SET_F("BP"),bootPreset); + printSetCheckbox(dest,PSTR("BO"),turnOnAtBoot); + printSetValue(dest,PSTR("BP"),bootPreset); - sappend(dest,'c',SET_F("GB"),gammaCorrectBri); - sappend(dest,'c',SET_F("GC"),gammaCorrectCol); - dtostrf(gammaCorrectVal,3,1,nS); sappends(dest,'s',SET_F("GV"),nS); - sappend(dest,'c',SET_F("TF"),fadeTransition); - sappend(dest,'c',SET_F("EB"),modeBlending); - sappend(dest,'v',SET_F("TD"),transitionDelayDefault); - sappend(dest,'c',SET_F("PF"),strip.paletteFade); - sappend(dest,'v',SET_F("TP"),randomPaletteChangeTime); - sappend(dest,'c',SET_F("TH"),useHarmonicRandomPalette); - sappend(dest,'v',SET_F("BF"),briMultiplier); - sappend(dest,'v',SET_F("TB"),nightlightTargetBri); - sappend(dest,'v',SET_F("TL"),nightlightDelayMinsDefault); - sappend(dest,'v',SET_F("TW"),nightlightMode); - sappend(dest,'i',SET_F("PB"),strip.paletteBlend); - sappend(dest,'v',SET_F("RL"),rlyPin); - sappend(dest,'c',SET_F("RM"),rlyMde); - sappend(dest,'c',SET_F("RO"),rlyOpenDrain); + printSetCheckbox(dest,PSTR("GB"),gammaCorrectBri); + printSetCheckbox(dest,PSTR("GC"),gammaCorrectCol); + dtostrf(gammaCorrectVal,3,1,nS); printSetValue(dest,PSTR("GV"),nS); + printSetCheckbox(dest,PSTR("TF"),fadeTransition); + printSetCheckbox(dest,PSTR("EB"),modeBlending); + printSetValue(dest,PSTR("TD"),transitionDelayDefault); + printSetCheckbox(dest,PSTR("PF"),strip.paletteFade); + printSetValue(dest,PSTR("TP"),randomPaletteChangeTime); + printSetCheckbox(dest,PSTR("TH"),useHarmonicRandomPalette); + printSetValue(dest,PSTR("BF"),briMultiplier); + printSetValue(dest,PSTR("TB"),nightlightTargetBri); + printSetValue(dest,PSTR("TL"),nightlightDelayMinsDefault); + printSetValue(dest,PSTR("TW"),nightlightMode); + printSetIndex(dest,PSTR("PB"),strip.paletteBlend); + printSetValue(dest,PSTR("RL"),rlyPin); + printSetCheckbox(dest,PSTR("RM"),rlyMde); + printSetCheckbox(dest,PSTR("RO"),rlyOpenDrain); for (int i = 0; i < WLED_MAX_BUTTONS; i++) { dest.printf_P(PSTR("addBtn(%d,%d,%d);"), i, btnPin[i], buttonType[i]); } - sappend(dest,'c',SET_F("IP"),disablePullUp); - sappend(dest,'v',SET_F("TT"),touchThreshold); + printSetCheckbox(dest,PSTR("IP"),disablePullUp); + printSetValue(dest,PSTR("TT"),touchThreshold); #ifndef WLED_DISABLE_INFRARED - sappend(dest,'v',SET_F("IR"),irPin); - sappend(dest,'v',SET_F("IT"),irEnabled); + printSetValue(dest,PSTR("IR"),irPin); + printSetValue(dest,PSTR("IT"),irEnabled); #endif - sappend(dest,'c',SET_F("MSO"),!irApplyToAllSelected); + printSetCheckbox(dest,PSTR("MSO"),!irApplyToAllSelected); } if (subPage == SUBPAGE_UI) { - sappends(dest,'s',SET_F("DS"),serverDescription); - sappend(dest,'c',SET_F("SU"),simplifiedUI); + printSetValue(dest,PSTR("DS"),serverDescription); + printSetCheckbox(dest,PSTR("SU"),simplifiedUI); } if (subPage == SUBPAGE_SYNC) { [[maybe_unused]] char nS[32]; - sappend(dest,'v',SET_F("UP"),udpPort); - sappend(dest,'v',SET_F("U2"),udpPort2); + printSetValue(dest,PSTR("UP"),udpPort); + printSetValue(dest,PSTR("U2"),udpPort2); #ifndef WLED_DISABLE_ESPNOW - if (enableESPNow) sappend(dest,'c',SET_F("EN"),useESPNowSync); + if (enableESPNow) printSetCheckbox(dest,PSTR("EN"),useESPNowSync); else dest.print(F("toggle('ESPNOW');")); // hide ESP-NOW setting #else dest.print(F("toggle('ESPNOW');")); // hide ESP-NOW setting #endif - sappend(dest,'v',SET_F("GS"),syncGroups); - sappend(dest,'v',SET_F("GR"),receiveGroups); + printSetValue(dest,PSTR("GS"),syncGroups); + printSetValue(dest,PSTR("GR"),receiveGroups); - sappend(dest,'c',SET_F("RB"),receiveNotificationBrightness); - sappend(dest,'c',SET_F("RC"),receiveNotificationColor); - sappend(dest,'c',SET_F("RX"),receiveNotificationEffects); - sappend(dest,'c',SET_F("RP"),receiveNotificationPalette); - sappend(dest,'c',SET_F("SO"),receiveSegmentOptions); - sappend(dest,'c',SET_F("SG"),receiveSegmentBounds); - sappend(dest,'c',SET_F("SS"),sendNotifications); - sappend(dest,'c',SET_F("SD"),notifyDirect); - sappend(dest,'c',SET_F("SB"),notifyButton); - sappend(dest,'c',SET_F("SH"),notifyHue); - sappend(dest,'v',SET_F("UR"),udpNumRetries); + printSetCheckbox(dest,PSTR("RB"),receiveNotificationBrightness); + printSetCheckbox(dest,PSTR("RC"),receiveNotificationColor); + printSetCheckbox(dest,PSTR("RX"),receiveNotificationEffects); + printSetCheckbox(dest,PSTR("RP"),receiveNotificationPalette); + printSetCheckbox(dest,PSTR("SO"),receiveSegmentOptions); + printSetCheckbox(dest,PSTR("SG"),receiveSegmentBounds); + printSetCheckbox(dest,PSTR("SS"),sendNotifications); + printSetCheckbox(dest,PSTR("SD"),notifyDirect); + printSetCheckbox(dest,PSTR("SB"),notifyButton); + printSetCheckbox(dest,PSTR("SH"),notifyHue); + printSetValue(dest,PSTR("UR"),udpNumRetries); - sappend(dest,'c',SET_F("NL"),nodeListEnabled); - sappend(dest,'c',SET_F("NB"),nodeBroadcastEnabled); + printSetCheckbox(dest,PSTR("NL"),nodeListEnabled); + printSetCheckbox(dest,PSTR("NB"),nodeBroadcastEnabled); - sappend(dest,'c',SET_F("RD"),receiveDirect); - sappend(dest,'c',SET_F("MO"),useMainSegmentOnly); - sappend(dest,'c',SET_F("RLM"),realtimeRespectLedMaps); - sappend(dest,'v',SET_F("EP"),e131Port); - sappend(dest,'c',SET_F("ES"),e131SkipOutOfSequence); - sappend(dest,'c',SET_F("EM"),e131Multicast); - sappend(dest,'v',SET_F("EU"),e131Universe); - sappend(dest,'v',SET_F("DA"),DMXAddress); - sappend(dest,'v',SET_F("XX"),DMXSegmentSpacing); - sappend(dest,'v',SET_F("PY"),e131Priority); - sappend(dest,'v',SET_F("DM"),DMXMode); - sappend(dest,'v',SET_F("ET"),realtimeTimeoutMs); - sappend(dest,'c',SET_F("FB"),arlsForceMaxBri); - sappend(dest,'c',SET_F("RG"),arlsDisableGammaCorrection); - sappend(dest,'v',SET_F("WO"),arlsOffset); + printSetCheckbox(dest,PSTR("RD"),receiveDirect); + printSetCheckbox(dest,PSTR("MO"),useMainSegmentOnly); + printSetCheckbox(dest,PSTR("RLM"),realtimeRespectLedMaps); + printSetValue(dest,PSTR("EP"),e131Port); + printSetCheckbox(dest,PSTR("ES"),e131SkipOutOfSequence); + printSetCheckbox(dest,PSTR("EM"),e131Multicast); + printSetValue(dest,PSTR("EU"),e131Universe); + printSetValue(dest,PSTR("DA"),DMXAddress); + printSetValue(dest,PSTR("XX"),DMXSegmentSpacing); + printSetValue(dest,PSTR("PY"),e131Priority); + printSetValue(dest,PSTR("DM"),DMXMode); + printSetValue(dest,PSTR("ET"),realtimeTimeoutMs); + printSetCheckbox(dest,PSTR("FB"),arlsForceMaxBri); + printSetCheckbox(dest,PSTR("RG"),arlsDisableGammaCorrection); + printSetValue(dest,PSTR("WO"),arlsOffset); #ifndef WLED_DISABLE_ALEXA - sappend(dest,'c',SET_F("AL"),alexaEnabled); - sappends(dest,'s',SET_F("AI"),alexaInvocationName); - sappend(dest,'c',SET_F("SA"),notifyAlexa); - sappend(dest,'v',SET_F("AP"),alexaNumPresets); + printSetCheckbox(dest,PSTR("AL"),alexaEnabled); + printSetValue(dest,PSTR("AI"),alexaInvocationName); + printSetCheckbox(dest,PSTR("SA"),notifyAlexa); + printSetValue(dest,PSTR("AP"),alexaNumPresets); #else dest.print(F("toggle('Alexa');")); // hide Alexa settings #endif #ifndef WLED_DISABLE_MQTT - sappend(dest,'c',SET_F("MQ"),mqttEnabled); - sappends(dest,'s',SET_F("MS"),mqttServer); - sappend(dest,'v',SET_F("MQPORT"),mqttPort); - sappends(dest,'s',SET_F("MQUSER"),mqttUser); + printSetCheckbox(dest,PSTR("MQ"),mqttEnabled); + printSetValue(dest,PSTR("MS"),mqttServer); + printSetValue(dest,PSTR("MQPORT"),mqttPort); + printSetValue(dest,PSTR("MQUSER"),mqttUser); byte l = strlen(mqttPass); char fpass[l+1]; //fill password field with *** fpass[l] = 0; memset(fpass,'*',l); - sappends(dest,'s',SET_F("MQPASS"),fpass); - sappends(dest,'s',SET_F("MQCID"),mqttClientID); - sappends(dest,'s',"MD",mqttDeviceTopic); - sappends(dest,'s',SET_F("MG"),mqttGroupTopic); - sappend(dest,'c',SET_F("BM"),buttonPublishMqtt); - sappend(dest,'c',SET_F("RT"),retainMqttMsg); + printSetValue(dest,PSTR("MQPASS"),fpass); + printSetValue(dest,PSTR("MQCID"),mqttClientID); + printSetValue(dest,PSTR("MD"),mqttDeviceTopic); + printSetValue(dest,PSTR("MG"),mqttGroupTopic); + printSetCheckbox(dest,PSTR("BM"),buttonPublishMqtt); + printSetCheckbox(dest,PSTR("RT"),retainMqttMsg); dest.printf_P(PSTR("d.Sf.MD.maxlength=%d;d.Sf.MG.maxlength=%d;d.Sf.MS.maxlength=%d;"), MQTT_MAX_TOPIC_LEN, MQTT_MAX_TOPIC_LEN, MQTT_MAX_SERVER_LEN); #else @@ -472,16 +472,16 @@ void getSettingsJS(byte subPage, Print& dest) #endif #ifndef WLED_DISABLE_HUESYNC - sappend(dest,'v',SET_F("H0"),hueIP[0]); - sappend(dest,'v',SET_F("H1"),hueIP[1]); - sappend(dest,'v',SET_F("H2"),hueIP[2]); - sappend(dest,'v',SET_F("H3"),hueIP[3]); - sappend(dest,'v',SET_F("HL"),huePollLightId); - sappend(dest,'v',SET_F("HI"),huePollIntervalMs); - sappend(dest,'c',SET_F("HP"),huePollingEnabled); - sappend(dest,'c',SET_F("HO"),hueApplyOnOff); - sappend(dest,'c',SET_F("HB"),hueApplyBri); - sappend(dest,'c',SET_F("HC"),hueApplyColor); + printSetValue(dest,PSTR("H0"),hueIP[0]); + printSetValue(dest,PSTR("H1"),hueIP[1]); + printSetValue(dest,PSTR("H2"),hueIP[2]); + printSetValue(dest,PSTR("H3"),hueIP[3]); + printSetValue(dest,PSTR("HL"),huePollLightId); + printSetValue(dest,PSTR("HI"),huePollIntervalMs); + printSetCheckbox(dest,PSTR("HP"),huePollingEnabled); + printSetCheckbox(dest,PSTR("HO"),hueApplyOnOff); + printSetCheckbox(dest,PSTR("HB"),hueApplyBri); + printSetCheckbox(dest,PSTR("HC"),hueApplyColor); char hueErrorString[25]; switch (hueError) { @@ -495,11 +495,11 @@ void getSettingsJS(byte subPage, Print& dest) default: sprintf_P(hueErrorString,PSTR("Bridge Error %i"),hueError); } - sappends(dest,'m',SET_F("(\"sip\")[0]"),hueErrorString); + printSetMessage(dest,PSTR("(\"sip\")[0]"),hueErrorString); #else dest.print(F("toggle('Hue');")); // hide Hue Sync settings #endif - sappend(dest,'v',SET_F("BD"),serialBaud); + printSetValue(dest,PSTR("BD"),serialBaud); #ifndef WLED_ENABLE_ADALIGHT dest.print(SET_F("toggle('Serial);")); #endif @@ -507,42 +507,42 @@ void getSettingsJS(byte subPage, Print& dest) if (subPage == SUBPAGE_TIME) { - sappend(dest,'c',SET_F("NT"),ntpEnabled); - sappends(dest,'s',SET_F("NS"),ntpServerName); - sappend(dest,'c',SET_F("CF"),!useAMPM); - sappend(dest,'i',SET_F("TZ"),currentTimezone); - sappend(dest,'v',SET_F("UO"),utcOffsetSecs); + printSetCheckbox(dest,PSTR("NT"),ntpEnabled); + printSetValue(dest,PSTR("NS"),ntpServerName); + printSetCheckbox(dest,PSTR("CF"),!useAMPM); + printSetIndex(dest,PSTR("TZ"),currentTimezone); + printSetValue(dest,PSTR("UO"),utcOffsetSecs); char tm[32]; dtostrf(longitude,4,2,tm); - sappends(dest,'s',SET_F("LN"),tm); + printSetValue(dest,PSTR("LN"),tm); dtostrf(latitude,4,2,tm); - sappends(dest,'s',SET_F("LT"),tm); + printSetValue(dest,PSTR("LT"),tm); getTimeString(tm); - sappends(dest,'m',SET_F("(\"times\")[0]"),tm); + printSetMessage(dest,PSTR("(\"times\")[0]"),tm); if ((int)(longitude*10.0f) || (int)(latitude*10.0f)) { sprintf_P(tm, PSTR("Sunrise: %02d:%02d Sunset: %02d:%02d"), hour(sunrise), minute(sunrise), hour(sunset), minute(sunset)); - sappends(dest,'m',SET_F("(\"times\")[1]"),tm); + printSetMessage(dest,PSTR("(\"times\")[1]"),tm); } - sappend(dest,'c',SET_F("OL"),overlayCurrent); - sappend(dest,'v',SET_F("O1"),overlayMin); - sappend(dest,'v',SET_F("O2"),overlayMax); - sappend(dest,'v',SET_F("OM"),analogClock12pixel); - sappend(dest,'c',SET_F("OS"),analogClockSecondsTrail); - sappend(dest,'c',SET_F("O5"),analogClock5MinuteMarks); - sappend(dest,'c',SET_F("OB"),analogClockSolidBlack); + printSetCheckbox(dest,PSTR("OL"),overlayCurrent); + printSetValue(dest,PSTR("O1"),overlayMin); + printSetValue(dest,PSTR("O2"),overlayMax); + printSetValue(dest,PSTR("OM"),analogClock12pixel); + printSetCheckbox(dest,PSTR("OS"),analogClockSecondsTrail); + printSetCheckbox(dest,PSTR("O5"),analogClock5MinuteMarks); + printSetCheckbox(dest,PSTR("OB"),analogClockSolidBlack); - sappend(dest,'c',SET_F("CE"),countdownMode); - sappend(dest,'v',SET_F("CY"),countdownYear); - sappend(dest,'v',SET_F("CI"),countdownMonth); - sappend(dest,'v',SET_F("CD"),countdownDay); - sappend(dest,'v',SET_F("CH"),countdownHour); - sappend(dest,'v',SET_F("CM"),countdownMin); - sappend(dest,'v',SET_F("CS"),countdownSec); + printSetCheckbox(dest,PSTR("CE"),countdownMode); + printSetValue(dest,PSTR("CY"),countdownYear); + printSetValue(dest,PSTR("CI"),countdownMonth); + printSetValue(dest,PSTR("CD"),countdownDay); + printSetValue(dest,PSTR("CH"),countdownHour); + printSetValue(dest,PSTR("CM"),countdownMin); + printSetValue(dest,PSTR("CS"),countdownSec); - sappend(dest,'v',SET_F("A0"),macroAlexaOn); - sappend(dest,'v',SET_F("A1"),macroAlexaOff); - sappend(dest,'v',SET_F("MC"),macroCountdown); - sappend(dest,'v',SET_F("MN"),macroNl); + printSetValue(dest,PSTR("A0"),macroAlexaOn); + printSetValue(dest,PSTR("A1"),macroAlexaOff); + printSetValue(dest,PSTR("MC"),macroCountdown); + printSetValue(dest,PSTR("MN"),macroNl); for (unsigned i=0; i> 4) & 0x0F); - k[0] = 'P'; sappend(dest,'v',k,timerMonth[i] & 0x0F); - k[0] = 'D'; sappend(dest,'v',k,timerDay[i]); - k[0] = 'E'; sappend(dest,'v',k,timerDayEnd[i]); + k[0] = 'M'; printSetValue(dest,k,(timerMonth[i] >> 4) & 0x0F); + k[0] = 'P'; printSetValue(dest,k,timerMonth[i] & 0x0F); + k[0] = 'D'; printSetValue(dest,k,timerDay[i]); + k[0] = 'E'; printSetValue(dest,k,timerDayEnd[i]); } } } @@ -571,41 +571,41 @@ void getSettingsJS(byte subPage, Print& dest) char fpass[l+1]; //fill PIN field with 0000 fpass[l] = 0; memset(fpass,'0',l); - sappends(dest,'s',SET_F("PIN"),fpass); - sappend(dest,'c',SET_F("NO"),otaLock); - sappend(dest,'c',SET_F("OW"),wifiLock); - sappend(dest,'c',SET_F("AO"),aOtaEnabled); + printSetValue(dest,PSTR("PIN"),fpass); + printSetCheckbox(dest,PSTR("NO"),otaLock); + printSetCheckbox(dest,PSTR("OW"),wifiLock); + printSetCheckbox(dest,PSTR("AO"),aOtaEnabled); char tmp_buf[128]; snprintf_P(tmp_buf,sizeof(tmp_buf),PSTR("WLED %s (build %d)"),versionString,VERSION); - sappends(dest,'m',SET_F("(\"sip\")[0]"),tmp_buf); + printSetMessage(dest,PSTR("(\"sip\")[0]"),tmp_buf); dest.printf_P(PSTR("sd=\"%s\";"), serverDescription); } #ifdef WLED_ENABLE_DMX // include only if DMX is enabled if (subPage == SUBPAGE_DMX) { - sappend(dest,'v',SET_F("PU"),e131ProxyUniverse); + printSetValue(dest,PSTR("PU"),e131ProxyUniverse); - sappend(dest,'v',SET_F("CN"),DMXChannels); - sappend(dest,'v',SET_F("CG"),DMXGap); - sappend(dest,'v',SET_F("CS"),DMXStart); - sappend(dest,'v',SET_F("SL"),DMXStartLED); + printSetValue(dest,PSTR("CN"),DMXChannels); + printSetValue(dest,PSTR("CG"),DMXGap); + printSetValue(dest,PSTR("CS"),DMXStart); + printSetValue(dest,PSTR("SL"),DMXStartLED); - sappend(dest,'i',SET_F("CH1"),DMXFixtureMap[0]); - sappend(dest,'i',SET_F("CH2"),DMXFixtureMap[1]); - sappend(dest,'i',SET_F("CH3"),DMXFixtureMap[2]); - sappend(dest,'i',SET_F("CH4"),DMXFixtureMap[3]); - sappend(dest,'i',SET_F("CH5"),DMXFixtureMap[4]); - sappend(dest,'i',SET_F("CH6"),DMXFixtureMap[5]); - sappend(dest,'i',SET_F("CH7"),DMXFixtureMap[6]); - sappend(dest,'i',SET_F("CH8"),DMXFixtureMap[7]); - sappend(dest,'i',SET_F("CH9"),DMXFixtureMap[8]); - sappend(dest,'i',SET_F("CH10"),DMXFixtureMap[9]); - sappend(dest,'i',SET_F("CH11"),DMXFixtureMap[10]); - sappend(dest,'i',SET_F("CH12"),DMXFixtureMap[11]); - sappend(dest,'i',SET_F("CH13"),DMXFixtureMap[12]); - sappend(dest,'i',SET_F("CH14"),DMXFixtureMap[13]); - sappend(dest,'i',SET_F("CH15"),DMXFixtureMap[14]); + printSetIndex(dest,PSTR("CH1"),DMXFixtureMap[0]); + printSetIndex(dest,PSTR("CH2"),DMXFixtureMap[1]); + printSetIndex(dest,PSTR("CH3"),DMXFixtureMap[2]); + printSetIndex(dest,PSTR("CH4"),DMXFixtureMap[3]); + printSetIndex(dest,PSTR("CH5"),DMXFixtureMap[4]); + printSetIndex(dest,PSTR("CH6"),DMXFixtureMap[5]); + printSetIndex(dest,PSTR("CH7"),DMXFixtureMap[6]); + printSetIndex(dest,PSTR("CH8"),DMXFixtureMap[7]); + printSetIndex(dest,PSTR("CH9"),DMXFixtureMap[8]); + printSetIndex(dest,PSTR("CH10"),DMXFixtureMap[9]); + printSetIndex(dest,PSTR("CH11"),DMXFixtureMap[10]); + printSetIndex(dest,PSTR("CH12"),DMXFixtureMap[11]); + printSetIndex(dest,PSTR("CH13"),DMXFixtureMap[12]); + printSetIndex(dest,PSTR("CH14"),DMXFixtureMap[13]); + printSetIndex(dest,PSTR("CH15"),DMXFixtureMap[14]); } #endif @@ -613,11 +613,11 @@ void getSettingsJS(byte subPage, Print& dest) { appendGPIOinfo(dest); dest.printf_P(PSTR("numM=%d;"), usermods.getModCount()); - sappend(dest,'v',SET_F("SDA"),i2c_sda); - sappend(dest,'v',SET_F("SCL"),i2c_scl); - sappend(dest,'v',SET_F("MOSI"),spi_mosi); - sappend(dest,'v',SET_F("MISO"),spi_miso); - sappend(dest,'v',SET_F("SCLK"),spi_sclk); + printSetValue(dest,PSTR("SDA"),i2c_sda); + printSetValue(dest,PSTR("SCL"),i2c_scl); + printSetValue(dest,PSTR("MOSI"),spi_mosi); + printSetValue(dest,PSTR("MISO"),spi_miso); + printSetValue(dest,PSTR("SCLK"),spi_sclk); dest.printf_P(PSTR("addInfo('SDA','%d');" "addInfo('SCL','%d');" "addInfo('MOSI','%d');" @@ -641,21 +641,21 @@ void getSettingsJS(byte subPage, Print& dest) #endif VERSION); - sappends(dest,'m',SET_F("(\"sip\")[0]"),tmp_buf); + printSetMessage(dest,PSTR("(\"sip\")[0]"),tmp_buf); } if (subPage == SUBPAGE_2D) // 2D matrices { - sappend(dest,'v',SET_F("SOMP"),strip.isMatrix); + printSetValue(dest,PSTR("SOMP"),strip.isMatrix); #ifndef WLED_DISABLE_2D dest.print(F("maxPanels=")); dest.print(WLED_MAX_PANELS); dest.print(F(";")); dest.print(F("resetPanels();")); if (strip.isMatrix) { if(strip.panels>0){ - sappend(dest,'v',SET_F("PW"),strip.panel[0].width); //Set generator Width and Height to first panel size for convenience - sappend(dest,'v',SET_F("PH"),strip.panel[0].height); + printSetValue(dest,PSTR("PW"),strip.panel[0].width); //Set generator Width and Height to first panel size for convenience + printSetValue(dest,PSTR("PH"),strip.panel[0].height); } - sappend(dest,'v',SET_F("MPC"),strip.panels); + printSetValue(dest,PSTR("MPC"),strip.panels); // panels for (unsigned i=0; i Date: Thu, 12 Sep 2024 20:39:13 +0200 Subject: [PATCH 025/234] New names --- wled00/fcn_declare.h | 10 +- wled00/util.cpp | 20 +- wled00/xml.cpp | 424 +++++++++++++++++++++---------------------- 3 files changed, 227 insertions(+), 227 deletions(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index a36f2dc26..29db8ea76 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -372,11 +372,11 @@ void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255); bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255); bool getBoolVal(JsonVariant elem, bool dflt); bool updateVal(const char* req, const char* key, byte* val, byte minv=0, byte maxv=255); -size_t printSetCheckbox(Print& dest, const char* key, int val); -size_t printSetValue(Print& dest, const char* key, int val); -size_t printSetValue(Print& dest, const char* key, const char* val); -size_t printSetIndex(Print& dest, const char* key, int index); -size_t printSetMessage(Print& dest, const char* key, const char* val); +size_t printSetFormCheckbox(Print& dest, const char* key, int val); +size_t printSetFormValue(Print& dest, const char* key, int val); +size_t printSetFormValue(Print& dest, const char* key, const char* val); +size_t printSetFormIndex(Print& dest, const char* key, int index); +size_t printSetClassElementHTML(Print& dest, const char* key, const int index, const char* val); void prepareHostname(char* hostname); bool isAsterisksOnly(const char* str, byte maxLen); bool requestJSONBufferLock(uint8_t module=255); diff --git a/wled00/util.cpp b/wled00/util.cpp index 660877d18..07190e37c 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -87,26 +87,26 @@ bool updateVal(const char* req, const char* key, byte* val, byte minv, byte maxv return true; } -static size_t printSetInt(Print& dest, const char* key, const char* selector, int value) { +static size_t printSetFormInput(Print& dest, const char* key, const char* selector, int value) { return dest.printf_P(PSTR("d.Sf.%s.%s=%d;"), key, selector, value); } -size_t printSetCheckbox(Print& dest, const char* key, int val) { - return printSetInt(dest, key, PSTR("checked"), val); +size_t printSetFormCheckbox(Print& dest, const char* key, int val) { + return printSetFormInput(dest, key, PSTR("checked"), val); } -size_t printSetValue(Print& dest, const char* key, int val) { - return printSetInt(dest, key, PSTR("value"), val); +size_t printSetFormValue(Print& dest, const char* key, int val) { + return printSetFormInput(dest, key, PSTR("value"), val); } -size_t printSetIndex(Print& dest, const char* key, int index) { - return printSetInt(dest, key, PSTR("selectedIndex"), index); +size_t printSetFormIndex(Print& dest, const char* key, int index) { + return printSetFormInput(dest, key, PSTR("selectedIndex"), index); } -size_t printSetValue(Print& dest, const char* key, const char* val) { +size_t printSetFormValue(Print& dest, const char* key, const char* val) { return dest.printf_P(PSTR("d.Sf.%s.value=\"%s\";"),key,val); } -size_t printSetMessage(Print& dest, const char* key, const char* val) { - return dest.printf_P(PSTR("d.getElementsByClassName%s.innerHTML=\"%s\";"), key, val); +size_t printSetClassElementHTML(Print& dest, const char* key, const int index, const char* val) { + return dest.printf_P(PSTR("d.getElementsByClassName(\"%s\")[%d].innerHTML=\"%s\";"), key, index, val); } diff --git a/wled00/xml.cpp b/wled00/xml.cpp index e8858066c..8cbd51cde 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -180,41 +180,41 @@ void getSettingsJS(byte subPage, Print& dest) (uint32_t) multiWiFi[n].staticSN); } - printSetValue(dest,PSTR("D0"),dnsAddress[0]); - printSetValue(dest,PSTR("D1"),dnsAddress[1]); - printSetValue(dest,PSTR("D2"),dnsAddress[2]); - printSetValue(dest,PSTR("D3"),dnsAddress[3]); + printSetFormValue(dest,PSTR("D0"),dnsAddress[0]); + printSetFormValue(dest,PSTR("D1"),dnsAddress[1]); + printSetFormValue(dest,PSTR("D2"),dnsAddress[2]); + printSetFormValue(dest,PSTR("D3"),dnsAddress[3]); - printSetValue(dest,PSTR("CM"),cmDNS); - printSetIndex(dest,PSTR("AB"),apBehavior); - printSetValue(dest,PSTR("AS"),apSSID); - printSetCheckbox(dest,PSTR("AH"),apHide); + printSetFormValue(dest,PSTR("CM"),cmDNS); + printSetFormIndex(dest,PSTR("AB"),apBehavior); + printSetFormValue(dest,PSTR("AS"),apSSID); + printSetFormCheckbox(dest,PSTR("AH"),apHide); l = strlen(apPass); char fapass[l+1]; //fill password field with *** fapass[l] = 0; memset(fapass,'*',l); - printSetValue(dest,PSTR("AP"),fapass); + printSetFormValue(dest,PSTR("AP"),fapass); - printSetValue(dest,PSTR("AC"),apChannel); + printSetFormValue(dest,PSTR("AC"),apChannel); #ifdef ARDUINO_ARCH_ESP32 - printSetValue(dest,PSTR("TX"),txPower); + printSetFormValue(dest,PSTR("TX"),txPower); #else dest.print(F("gId('tx').style.display='none';")); #endif - printSetCheckbox(dest,PSTR("FG"),force802_3g); - printSetCheckbox(dest,PSTR("WS"),noWifiSleep); + printSetFormCheckbox(dest,PSTR("FG"),force802_3g); + printSetFormCheckbox(dest,PSTR("WS"),noWifiSleep); #ifndef WLED_DISABLE_ESPNOW - printSetCheckbox(dest,PSTR("RE"),enableESPNow); - printSetValue(dest,PSTR("RMAC"),linked_remote); + printSetFormCheckbox(dest,PSTR("RE"),enableESPNow); + printSetFormValue(dest,PSTR("RMAC"),linked_remote); #else //hide remote settings if not compiled dest.print(F("toggle('ESPNOW');")); // hide ESP-NOW setting #endif #ifdef WLED_USE_ETHERNET - printSetValue(dest,PSTR("ETH"),ethernetType); + printSetFormValue(dest,PSTR("ETH"),ethernetType); #else //hide ethernet setting if not compiled in dest.print(F("gId('ethd').style.display='none';")); @@ -229,10 +229,10 @@ void getSettingsJS(byte subPage, Print& dest) #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) if (Network.isEthernet()) strcat_P(s ,SET_F(" (Ethernet)")); #endif - printSetMessage(dest,PSTR("(\"sip\")[0]"),s); + printSetClassElementHTML(dest,PSTR("sip"),0,s); } else { - printSetMessage(dest,PSTR("(\"sip\")[0]"),(char*)F("Not connected")); + printSetClassElementHTML(dest,PSTR("sip"),0,(char*)F("Not connected")); } if (WiFi.softAPIP()[0] != 0) //is active @@ -240,19 +240,19 @@ void getSettingsJS(byte subPage, Print& dest) char s[16]; IPAddress apIP = WiFi.softAPIP(); sprintf(s, "%d.%d.%d.%d", apIP[0], apIP[1], apIP[2], apIP[3]); - printSetMessage(dest,PSTR("(\"sip\")[1]"),s); + printSetClassElementHTML(dest,PSTR("sip"),1,s); } else { - printSetMessage(dest,PSTR("(\"sip\")[1]"),(char*)F("Not active")); + printSetClassElementHTML(dest,PSTR("sip"),1,(char*)F("Not active")); } #ifndef WLED_DISABLE_ESPNOW if (strlen(last_signal_src) > 0) { //Have seen an ESP-NOW Remote - printSetMessage(dest,PSTR("(\"rlid\")[0]"),last_signal_src); + printSetClassElementHTML(dest,PSTR("rlid"),0,last_signal_src); } else if (!enableESPNow) { - printSetMessage(dest,PSTR("(\"rlid\")[0]"),(char*)F("(Enable ESP-NOW to listen)")); + printSetClassElementHTML(dest,PSTR("rlid"),0,(char*)F("(Enable ESP-NOW to listen)")); } else { - printSetMessage(dest,PSTR("(\"rlid\")[0]"),(char*)F("None")); + printSetClassElementHTML(dest,PSTR("rlid"),0,(char*)F("None")); } #endif } @@ -277,14 +277,14 @@ void getSettingsJS(byte subPage, Print& dest) WLED_MAX_ANALOG_CHANNELS ); - printSetCheckbox(dest,PSTR("MS"),strip.autoSegments); - printSetCheckbox(dest,PSTR("CCT"),strip.correctWB); - printSetCheckbox(dest,PSTR("IC"),cctICused); - printSetCheckbox(dest,PSTR("CR"),strip.cctFromRgb); - printSetValue(dest,PSTR("CB"),strip.cctBlending); - printSetValue(dest,PSTR("FR"),strip.getTargetFps()); - printSetValue(dest,PSTR("AW"),Bus::getGlobalAWMode()); - printSetCheckbox(dest,PSTR("LD"),useGlobalLedBuffer); + printSetFormCheckbox(dest,PSTR("MS"),strip.autoSegments); + printSetFormCheckbox(dest,PSTR("CCT"),strip.correctWB); + printSetFormCheckbox(dest,PSTR("IC"),cctICused); + printSetFormCheckbox(dest,PSTR("CR"),strip.cctFromRgb); + printSetFormValue(dest,PSTR("CB"),strip.cctBlending); + printSetFormValue(dest,PSTR("FR"),strip.getTargetFps()); + printSetFormValue(dest,PSTR("AW"),Bus::getGlobalAWMode()); + printSetFormCheckbox(dest,PSTR("LD"),useGlobalLedBuffer); unsigned sumMa = 0; for (int s = 0; s < BusManager::getNumBusses(); s++) { @@ -309,17 +309,17 @@ void getSettingsJS(byte subPage, Print& dest) int nPins = bus->getPins(pins); for (int i = 0; i < nPins; i++) { lp[1] = offset+i; - if (pinManager.isPinOk(pins[i]) || bus->isVirtual()) printSetValue(dest,lp,pins[i]); + if (pinManager.isPinOk(pins[i]) || bus->isVirtual()) printSetFormValue(dest,lp,pins[i]); } - printSetValue(dest,lc,bus->getLength()); - printSetValue(dest,lt,bus->getType()); - printSetValue(dest,co,bus->getColorOrder() & 0x0F); - printSetValue(dest,ls,bus->getStart()); - printSetCheckbox(dest,cv,bus->isReversed()); - printSetValue(dest,sl,bus->skippedLeds()); - printSetCheckbox(dest,rf,bus->isOffRefreshRequired()); - printSetValue(dest,aw,bus->getAutoWhiteMode()); - printSetValue(dest,wo,bus->getColorOrder() >> 4); + printSetFormValue(dest,lc,bus->getLength()); + printSetFormValue(dest,lt,bus->getType()); + printSetFormValue(dest,co,bus->getColorOrder() & 0x0F); + printSetFormValue(dest,ls,bus->getStart()); + printSetFormCheckbox(dest,cv,bus->isReversed()); + printSetFormValue(dest,sl,bus->skippedLeds()); + printSetFormCheckbox(dest,rf,bus->isOffRefreshRequired()); + printSetFormValue(dest,aw,bus->getAutoWhiteMode()); + printSetFormValue(dest,wo,bus->getColorOrder() >> 4); unsigned speed = bus->getFrequency(); if (bus->isPWM()) { switch (speed) { @@ -340,14 +340,14 @@ void getSettingsJS(byte subPage, Print& dest) case 20000 : speed = 4; break; } } - printSetValue(dest,sp,speed); - printSetValue(dest,la,bus->getLEDCurrent()); - printSetValue(dest,ma,bus->getMaxCurrent()); + printSetFormValue(dest,sp,speed); + printSetFormValue(dest,la,bus->getLEDCurrent()); + printSetFormValue(dest,ma,bus->getMaxCurrent()); sumMa += bus->getMaxCurrent(); } - printSetValue(dest,PSTR("MA"),BusManager::ablMilliampsMax() ? BusManager::ablMilliampsMax() : sumMa); - printSetCheckbox(dest,PSTR("ABL"),BusManager::ablMilliampsMax() || sumMa > 0); - printSetCheckbox(dest,PSTR("PPL"),!BusManager::ablMilliampsMax() && sumMa > 0); + printSetFormValue(dest,PSTR("MA"),BusManager::ablMilliampsMax() ? BusManager::ablMilliampsMax() : sumMa); + printSetFormCheckbox(dest,PSTR("ABL"),BusManager::ablMilliampsMax() || sumMa > 0); + printSetFormCheckbox(dest,PSTR("PPL"),!BusManager::ablMilliampsMax() && sumMa > 0); dest.printf_P(PSTR("resetCOM(%d);"), WLED_MAX_COLOR_ORDER_MAPPINGS); const ColorOrderMap& com = BusManager::getColorOrderMap(); @@ -357,114 +357,114 @@ void getSettingsJS(byte subPage, Print& dest) dest.printf_P(PSTR("addCOM(%d,%d,%d);"), entry->start, entry->len, entry->colorOrder); } - printSetValue(dest,PSTR("CA"),briS); + printSetFormValue(dest,PSTR("CA"),briS); - printSetCheckbox(dest,PSTR("BO"),turnOnAtBoot); - printSetValue(dest,PSTR("BP"),bootPreset); + printSetFormCheckbox(dest,PSTR("BO"),turnOnAtBoot); + printSetFormValue(dest,PSTR("BP"),bootPreset); - printSetCheckbox(dest,PSTR("GB"),gammaCorrectBri); - printSetCheckbox(dest,PSTR("GC"),gammaCorrectCol); - dtostrf(gammaCorrectVal,3,1,nS); printSetValue(dest,PSTR("GV"),nS); - printSetCheckbox(dest,PSTR("TF"),fadeTransition); - printSetCheckbox(dest,PSTR("EB"),modeBlending); - printSetValue(dest,PSTR("TD"),transitionDelayDefault); - printSetCheckbox(dest,PSTR("PF"),strip.paletteFade); - printSetValue(dest,PSTR("TP"),randomPaletteChangeTime); - printSetCheckbox(dest,PSTR("TH"),useHarmonicRandomPalette); - printSetValue(dest,PSTR("BF"),briMultiplier); - printSetValue(dest,PSTR("TB"),nightlightTargetBri); - printSetValue(dest,PSTR("TL"),nightlightDelayMinsDefault); - printSetValue(dest,PSTR("TW"),nightlightMode); - printSetIndex(dest,PSTR("PB"),strip.paletteBlend); - printSetValue(dest,PSTR("RL"),rlyPin); - printSetCheckbox(dest,PSTR("RM"),rlyMde); - printSetCheckbox(dest,PSTR("RO"),rlyOpenDrain); + printSetFormCheckbox(dest,PSTR("GB"),gammaCorrectBri); + printSetFormCheckbox(dest,PSTR("GC"),gammaCorrectCol); + dtostrf(gammaCorrectVal,3,1,nS); printSetFormValue(dest,PSTR("GV"),nS); + printSetFormCheckbox(dest,PSTR("TF"),fadeTransition); + printSetFormCheckbox(dest,PSTR("EB"),modeBlending); + printSetFormValue(dest,PSTR("TD"),transitionDelayDefault); + printSetFormCheckbox(dest,PSTR("PF"),strip.paletteFade); + printSetFormValue(dest,PSTR("TP"),randomPaletteChangeTime); + printSetFormCheckbox(dest,PSTR("TH"),useHarmonicRandomPalette); + printSetFormValue(dest,PSTR("BF"),briMultiplier); + printSetFormValue(dest,PSTR("TB"),nightlightTargetBri); + printSetFormValue(dest,PSTR("TL"),nightlightDelayMinsDefault); + printSetFormValue(dest,PSTR("TW"),nightlightMode); + printSetFormIndex(dest,PSTR("PB"),strip.paletteBlend); + printSetFormValue(dest,PSTR("RL"),rlyPin); + printSetFormCheckbox(dest,PSTR("RM"),rlyMde); + printSetFormCheckbox(dest,PSTR("RO"),rlyOpenDrain); for (int i = 0; i < WLED_MAX_BUTTONS; i++) { dest.printf_P(PSTR("addBtn(%d,%d,%d);"), i, btnPin[i], buttonType[i]); } - printSetCheckbox(dest,PSTR("IP"),disablePullUp); - printSetValue(dest,PSTR("TT"),touchThreshold); + printSetFormCheckbox(dest,PSTR("IP"),disablePullUp); + printSetFormValue(dest,PSTR("TT"),touchThreshold); #ifndef WLED_DISABLE_INFRARED - printSetValue(dest,PSTR("IR"),irPin); - printSetValue(dest,PSTR("IT"),irEnabled); + printSetFormValue(dest,PSTR("IR"),irPin); + printSetFormValue(dest,PSTR("IT"),irEnabled); #endif - printSetCheckbox(dest,PSTR("MSO"),!irApplyToAllSelected); + printSetFormCheckbox(dest,PSTR("MSO"),!irApplyToAllSelected); } if (subPage == SUBPAGE_UI) { - printSetValue(dest,PSTR("DS"),serverDescription); - printSetCheckbox(dest,PSTR("SU"),simplifiedUI); + printSetFormValue(dest,PSTR("DS"),serverDescription); + printSetFormCheckbox(dest,PSTR("SU"),simplifiedUI); } if (subPage == SUBPAGE_SYNC) { [[maybe_unused]] char nS[32]; - printSetValue(dest,PSTR("UP"),udpPort); - printSetValue(dest,PSTR("U2"),udpPort2); + printSetFormValue(dest,PSTR("UP"),udpPort); + printSetFormValue(dest,PSTR("U2"),udpPort2); #ifndef WLED_DISABLE_ESPNOW - if (enableESPNow) printSetCheckbox(dest,PSTR("EN"),useESPNowSync); + if (enableESPNow) printSetFormCheckbox(dest,PSTR("EN"),useESPNowSync); else dest.print(F("toggle('ESPNOW');")); // hide ESP-NOW setting #else dest.print(F("toggle('ESPNOW');")); // hide ESP-NOW setting #endif - printSetValue(dest,PSTR("GS"),syncGroups); - printSetValue(dest,PSTR("GR"),receiveGroups); + printSetFormValue(dest,PSTR("GS"),syncGroups); + printSetFormValue(dest,PSTR("GR"),receiveGroups); - printSetCheckbox(dest,PSTR("RB"),receiveNotificationBrightness); - printSetCheckbox(dest,PSTR("RC"),receiveNotificationColor); - printSetCheckbox(dest,PSTR("RX"),receiveNotificationEffects); - printSetCheckbox(dest,PSTR("RP"),receiveNotificationPalette); - printSetCheckbox(dest,PSTR("SO"),receiveSegmentOptions); - printSetCheckbox(dest,PSTR("SG"),receiveSegmentBounds); - printSetCheckbox(dest,PSTR("SS"),sendNotifications); - printSetCheckbox(dest,PSTR("SD"),notifyDirect); - printSetCheckbox(dest,PSTR("SB"),notifyButton); - printSetCheckbox(dest,PSTR("SH"),notifyHue); - printSetValue(dest,PSTR("UR"),udpNumRetries); + printSetFormCheckbox(dest,PSTR("RB"),receiveNotificationBrightness); + printSetFormCheckbox(dest,PSTR("RC"),receiveNotificationColor); + printSetFormCheckbox(dest,PSTR("RX"),receiveNotificationEffects); + printSetFormCheckbox(dest,PSTR("RP"),receiveNotificationPalette); + printSetFormCheckbox(dest,PSTR("SO"),receiveSegmentOptions); + printSetFormCheckbox(dest,PSTR("SG"),receiveSegmentBounds); + printSetFormCheckbox(dest,PSTR("SS"),sendNotifications); + printSetFormCheckbox(dest,PSTR("SD"),notifyDirect); + printSetFormCheckbox(dest,PSTR("SB"),notifyButton); + printSetFormCheckbox(dest,PSTR("SH"),notifyHue); + printSetFormValue(dest,PSTR("UR"),udpNumRetries); - printSetCheckbox(dest,PSTR("NL"),nodeListEnabled); - printSetCheckbox(dest,PSTR("NB"),nodeBroadcastEnabled); + printSetFormCheckbox(dest,PSTR("NL"),nodeListEnabled); + printSetFormCheckbox(dest,PSTR("NB"),nodeBroadcastEnabled); - printSetCheckbox(dest,PSTR("RD"),receiveDirect); - printSetCheckbox(dest,PSTR("MO"),useMainSegmentOnly); - printSetCheckbox(dest,PSTR("RLM"),realtimeRespectLedMaps); - printSetValue(dest,PSTR("EP"),e131Port); - printSetCheckbox(dest,PSTR("ES"),e131SkipOutOfSequence); - printSetCheckbox(dest,PSTR("EM"),e131Multicast); - printSetValue(dest,PSTR("EU"),e131Universe); - printSetValue(dest,PSTR("DA"),DMXAddress); - printSetValue(dest,PSTR("XX"),DMXSegmentSpacing); - printSetValue(dest,PSTR("PY"),e131Priority); - printSetValue(dest,PSTR("DM"),DMXMode); - printSetValue(dest,PSTR("ET"),realtimeTimeoutMs); - printSetCheckbox(dest,PSTR("FB"),arlsForceMaxBri); - printSetCheckbox(dest,PSTR("RG"),arlsDisableGammaCorrection); - printSetValue(dest,PSTR("WO"),arlsOffset); + printSetFormCheckbox(dest,PSTR("RD"),receiveDirect); + printSetFormCheckbox(dest,PSTR("MO"),useMainSegmentOnly); + printSetFormCheckbox(dest,PSTR("RLM"),realtimeRespectLedMaps); + printSetFormValue(dest,PSTR("EP"),e131Port); + printSetFormCheckbox(dest,PSTR("ES"),e131SkipOutOfSequence); + printSetFormCheckbox(dest,PSTR("EM"),e131Multicast); + printSetFormValue(dest,PSTR("EU"),e131Universe); + printSetFormValue(dest,PSTR("DA"),DMXAddress); + printSetFormValue(dest,PSTR("XX"),DMXSegmentSpacing); + printSetFormValue(dest,PSTR("PY"),e131Priority); + printSetFormValue(dest,PSTR("DM"),DMXMode); + printSetFormValue(dest,PSTR("ET"),realtimeTimeoutMs); + printSetFormCheckbox(dest,PSTR("FB"),arlsForceMaxBri); + printSetFormCheckbox(dest,PSTR("RG"),arlsDisableGammaCorrection); + printSetFormValue(dest,PSTR("WO"),arlsOffset); #ifndef WLED_DISABLE_ALEXA - printSetCheckbox(dest,PSTR("AL"),alexaEnabled); - printSetValue(dest,PSTR("AI"),alexaInvocationName); - printSetCheckbox(dest,PSTR("SA"),notifyAlexa); - printSetValue(dest,PSTR("AP"),alexaNumPresets); + printSetFormCheckbox(dest,PSTR("AL"),alexaEnabled); + printSetFormValue(dest,PSTR("AI"),alexaInvocationName); + printSetFormCheckbox(dest,PSTR("SA"),notifyAlexa); + printSetFormValue(dest,PSTR("AP"),alexaNumPresets); #else dest.print(F("toggle('Alexa');")); // hide Alexa settings #endif #ifndef WLED_DISABLE_MQTT - printSetCheckbox(dest,PSTR("MQ"),mqttEnabled); - printSetValue(dest,PSTR("MS"),mqttServer); - printSetValue(dest,PSTR("MQPORT"),mqttPort); - printSetValue(dest,PSTR("MQUSER"),mqttUser); + printSetFormCheckbox(dest,PSTR("MQ"),mqttEnabled); + printSetFormValue(dest,PSTR("MS"),mqttServer); + printSetFormValue(dest,PSTR("MQPORT"),mqttPort); + printSetFormValue(dest,PSTR("MQUSER"),mqttUser); byte l = strlen(mqttPass); char fpass[l+1]; //fill password field with *** fpass[l] = 0; memset(fpass,'*',l); - printSetValue(dest,PSTR("MQPASS"),fpass); - printSetValue(dest,PSTR("MQCID"),mqttClientID); - printSetValue(dest,PSTR("MD"),mqttDeviceTopic); - printSetValue(dest,PSTR("MG"),mqttGroupTopic); - printSetCheckbox(dest,PSTR("BM"),buttonPublishMqtt); - printSetCheckbox(dest,PSTR("RT"),retainMqttMsg); + printSetFormValue(dest,PSTR("MQPASS"),fpass); + printSetFormValue(dest,PSTR("MQCID"),mqttClientID); + printSetFormValue(dest,PSTR("MD"),mqttDeviceTopic); + printSetFormValue(dest,PSTR("MG"),mqttGroupTopic); + printSetFormCheckbox(dest,PSTR("BM"),buttonPublishMqtt); + printSetFormCheckbox(dest,PSTR("RT"),retainMqttMsg); dest.printf_P(PSTR("d.Sf.MD.maxlength=%d;d.Sf.MG.maxlength=%d;d.Sf.MS.maxlength=%d;"), MQTT_MAX_TOPIC_LEN, MQTT_MAX_TOPIC_LEN, MQTT_MAX_SERVER_LEN); #else @@ -472,16 +472,16 @@ void getSettingsJS(byte subPage, Print& dest) #endif #ifndef WLED_DISABLE_HUESYNC - printSetValue(dest,PSTR("H0"),hueIP[0]); - printSetValue(dest,PSTR("H1"),hueIP[1]); - printSetValue(dest,PSTR("H2"),hueIP[2]); - printSetValue(dest,PSTR("H3"),hueIP[3]); - printSetValue(dest,PSTR("HL"),huePollLightId); - printSetValue(dest,PSTR("HI"),huePollIntervalMs); - printSetCheckbox(dest,PSTR("HP"),huePollingEnabled); - printSetCheckbox(dest,PSTR("HO"),hueApplyOnOff); - printSetCheckbox(dest,PSTR("HB"),hueApplyBri); - printSetCheckbox(dest,PSTR("HC"),hueApplyColor); + printSetFormValue(dest,PSTR("H0"),hueIP[0]); + printSetFormValue(dest,PSTR("H1"),hueIP[1]); + printSetFormValue(dest,PSTR("H2"),hueIP[2]); + printSetFormValue(dest,PSTR("H3"),hueIP[3]); + printSetFormValue(dest,PSTR("HL"),huePollLightId); + printSetFormValue(dest,PSTR("HI"),huePollIntervalMs); + printSetFormCheckbox(dest,PSTR("HP"),huePollingEnabled); + printSetFormCheckbox(dest,PSTR("HO"),hueApplyOnOff); + printSetFormCheckbox(dest,PSTR("HB"),hueApplyBri); + printSetFormCheckbox(dest,PSTR("HC"),hueApplyColor); char hueErrorString[25]; switch (hueError) { @@ -495,11 +495,11 @@ void getSettingsJS(byte subPage, Print& dest) default: sprintf_P(hueErrorString,PSTR("Bridge Error %i"),hueError); } - printSetMessage(dest,PSTR("(\"sip\")[0]"),hueErrorString); + printSetClassElementHTML(dest,PSTR("sip"),0,hueErrorString); #else dest.print(F("toggle('Hue');")); // hide Hue Sync settings #endif - printSetValue(dest,PSTR("BD"),serialBaud); + printSetFormValue(dest,PSTR("BD"),serialBaud); #ifndef WLED_ENABLE_ADALIGHT dest.print(SET_F("toggle('Serial);")); #endif @@ -507,42 +507,42 @@ void getSettingsJS(byte subPage, Print& dest) if (subPage == SUBPAGE_TIME) { - printSetCheckbox(dest,PSTR("NT"),ntpEnabled); - printSetValue(dest,PSTR("NS"),ntpServerName); - printSetCheckbox(dest,PSTR("CF"),!useAMPM); - printSetIndex(dest,PSTR("TZ"),currentTimezone); - printSetValue(dest,PSTR("UO"),utcOffsetSecs); + printSetFormCheckbox(dest,PSTR("NT"),ntpEnabled); + printSetFormValue(dest,PSTR("NS"),ntpServerName); + printSetFormCheckbox(dest,PSTR("CF"),!useAMPM); + printSetFormIndex(dest,PSTR("TZ"),currentTimezone); + printSetFormValue(dest,PSTR("UO"),utcOffsetSecs); char tm[32]; dtostrf(longitude,4,2,tm); - printSetValue(dest,PSTR("LN"),tm); + printSetFormValue(dest,PSTR("LN"),tm); dtostrf(latitude,4,2,tm); - printSetValue(dest,PSTR("LT"),tm); + printSetFormValue(dest,PSTR("LT"),tm); getTimeString(tm); - printSetMessage(dest,PSTR("(\"times\")[0]"),tm); + printSetClassElementHTML(dest,PSTR("times"),0,tm); if ((int)(longitude*10.0f) || (int)(latitude*10.0f)) { sprintf_P(tm, PSTR("Sunrise: %02d:%02d Sunset: %02d:%02d"), hour(sunrise), minute(sunrise), hour(sunset), minute(sunset)); - printSetMessage(dest,PSTR("(\"times\")[1]"),tm); + printSetClassElementHTML(dest,PSTR("times"),1,tm); } - printSetCheckbox(dest,PSTR("OL"),overlayCurrent); - printSetValue(dest,PSTR("O1"),overlayMin); - printSetValue(dest,PSTR("O2"),overlayMax); - printSetValue(dest,PSTR("OM"),analogClock12pixel); - printSetCheckbox(dest,PSTR("OS"),analogClockSecondsTrail); - printSetCheckbox(dest,PSTR("O5"),analogClock5MinuteMarks); - printSetCheckbox(dest,PSTR("OB"),analogClockSolidBlack); + printSetFormCheckbox(dest,PSTR("OL"),overlayCurrent); + printSetFormValue(dest,PSTR("O1"),overlayMin); + printSetFormValue(dest,PSTR("O2"),overlayMax); + printSetFormValue(dest,PSTR("OM"),analogClock12pixel); + printSetFormCheckbox(dest,PSTR("OS"),analogClockSecondsTrail); + printSetFormCheckbox(dest,PSTR("O5"),analogClock5MinuteMarks); + printSetFormCheckbox(dest,PSTR("OB"),analogClockSolidBlack); - printSetCheckbox(dest,PSTR("CE"),countdownMode); - printSetValue(dest,PSTR("CY"),countdownYear); - printSetValue(dest,PSTR("CI"),countdownMonth); - printSetValue(dest,PSTR("CD"),countdownDay); - printSetValue(dest,PSTR("CH"),countdownHour); - printSetValue(dest,PSTR("CM"),countdownMin); - printSetValue(dest,PSTR("CS"),countdownSec); + printSetFormCheckbox(dest,PSTR("CE"),countdownMode); + printSetFormValue(dest,PSTR("CY"),countdownYear); + printSetFormValue(dest,PSTR("CI"),countdownMonth); + printSetFormValue(dest,PSTR("CD"),countdownDay); + printSetFormValue(dest,PSTR("CH"),countdownHour); + printSetFormValue(dest,PSTR("CM"),countdownMin); + printSetFormValue(dest,PSTR("CS"),countdownSec); - printSetValue(dest,PSTR("A0"),macroAlexaOn); - printSetValue(dest,PSTR("A1"),macroAlexaOff); - printSetValue(dest,PSTR("MC"),macroCountdown); - printSetValue(dest,PSTR("MN"),macroNl); + printSetFormValue(dest,PSTR("A0"),macroAlexaOn); + printSetFormValue(dest,PSTR("A1"),macroAlexaOff); + printSetFormValue(dest,PSTR("MC"),macroCountdown); + printSetFormValue(dest,PSTR("MN"),macroNl); for (unsigned i=0; i> 4) & 0x0F); - k[0] = 'P'; printSetValue(dest,k,timerMonth[i] & 0x0F); - k[0] = 'D'; printSetValue(dest,k,timerDay[i]); - k[0] = 'E'; printSetValue(dest,k,timerDayEnd[i]); + k[0] = 'M'; printSetFormValue(dest,k,(timerMonth[i] >> 4) & 0x0F); + k[0] = 'P'; printSetFormValue(dest,k,timerMonth[i] & 0x0F); + k[0] = 'D'; printSetFormValue(dest,k,timerDay[i]); + k[0] = 'E'; printSetFormValue(dest,k,timerDayEnd[i]); } } } @@ -571,41 +571,41 @@ void getSettingsJS(byte subPage, Print& dest) char fpass[l+1]; //fill PIN field with 0000 fpass[l] = 0; memset(fpass,'0',l); - printSetValue(dest,PSTR("PIN"),fpass); - printSetCheckbox(dest,PSTR("NO"),otaLock); - printSetCheckbox(dest,PSTR("OW"),wifiLock); - printSetCheckbox(dest,PSTR("AO"),aOtaEnabled); + printSetFormValue(dest,PSTR("PIN"),fpass); + printSetFormCheckbox(dest,PSTR("NO"),otaLock); + printSetFormCheckbox(dest,PSTR("OW"),wifiLock); + printSetFormCheckbox(dest,PSTR("AO"),aOtaEnabled); char tmp_buf[128]; snprintf_P(tmp_buf,sizeof(tmp_buf),PSTR("WLED %s (build %d)"),versionString,VERSION); - printSetMessage(dest,PSTR("(\"sip\")[0]"),tmp_buf); + printSetClassElementHTML(dest,PSTR("sip"),0,tmp_buf); dest.printf_P(PSTR("sd=\"%s\";"), serverDescription); } #ifdef WLED_ENABLE_DMX // include only if DMX is enabled if (subPage == SUBPAGE_DMX) { - printSetValue(dest,PSTR("PU"),e131ProxyUniverse); + printSetFormValue(dest,PSTR("PU"),e131ProxyUniverse); - printSetValue(dest,PSTR("CN"),DMXChannels); - printSetValue(dest,PSTR("CG"),DMXGap); - printSetValue(dest,PSTR("CS"),DMXStart); - printSetValue(dest,PSTR("SL"),DMXStartLED); + printSetFormValue(dest,PSTR("CN"),DMXChannels); + printSetFormValue(dest,PSTR("CG"),DMXGap); + printSetFormValue(dest,PSTR("CS"),DMXStart); + printSetFormValue(dest,PSTR("SL"),DMXStartLED); - printSetIndex(dest,PSTR("CH1"),DMXFixtureMap[0]); - printSetIndex(dest,PSTR("CH2"),DMXFixtureMap[1]); - printSetIndex(dest,PSTR("CH3"),DMXFixtureMap[2]); - printSetIndex(dest,PSTR("CH4"),DMXFixtureMap[3]); - printSetIndex(dest,PSTR("CH5"),DMXFixtureMap[4]); - printSetIndex(dest,PSTR("CH6"),DMXFixtureMap[5]); - printSetIndex(dest,PSTR("CH7"),DMXFixtureMap[6]); - printSetIndex(dest,PSTR("CH8"),DMXFixtureMap[7]); - printSetIndex(dest,PSTR("CH9"),DMXFixtureMap[8]); - printSetIndex(dest,PSTR("CH10"),DMXFixtureMap[9]); - printSetIndex(dest,PSTR("CH11"),DMXFixtureMap[10]); - printSetIndex(dest,PSTR("CH12"),DMXFixtureMap[11]); - printSetIndex(dest,PSTR("CH13"),DMXFixtureMap[12]); - printSetIndex(dest,PSTR("CH14"),DMXFixtureMap[13]); - printSetIndex(dest,PSTR("CH15"),DMXFixtureMap[14]); + printSetFormIndex(dest,PSTR("CH1"),DMXFixtureMap[0]); + printSetFormIndex(dest,PSTR("CH2"),DMXFixtureMap[1]); + printSetFormIndex(dest,PSTR("CH3"),DMXFixtureMap[2]); + printSetFormIndex(dest,PSTR("CH4"),DMXFixtureMap[3]); + printSetFormIndex(dest,PSTR("CH5"),DMXFixtureMap[4]); + printSetFormIndex(dest,PSTR("CH6"),DMXFixtureMap[5]); + printSetFormIndex(dest,PSTR("CH7"),DMXFixtureMap[6]); + printSetFormIndex(dest,PSTR("CH8"),DMXFixtureMap[7]); + printSetFormIndex(dest,PSTR("CH9"),DMXFixtureMap[8]); + printSetFormIndex(dest,PSTR("CH10"),DMXFixtureMap[9]); + printSetFormIndex(dest,PSTR("CH11"),DMXFixtureMap[10]); + printSetFormIndex(dest,PSTR("CH12"),DMXFixtureMap[11]); + printSetFormIndex(dest,PSTR("CH13"),DMXFixtureMap[12]); + printSetFormIndex(dest,PSTR("CH14"),DMXFixtureMap[13]); + printSetFormIndex(dest,PSTR("CH15"),DMXFixtureMap[14]); } #endif @@ -613,11 +613,11 @@ void getSettingsJS(byte subPage, Print& dest) { appendGPIOinfo(dest); dest.printf_P(PSTR("numM=%d;"), usermods.getModCount()); - printSetValue(dest,PSTR("SDA"),i2c_sda); - printSetValue(dest,PSTR("SCL"),i2c_scl); - printSetValue(dest,PSTR("MOSI"),spi_mosi); - printSetValue(dest,PSTR("MISO"),spi_miso); - printSetValue(dest,PSTR("SCLK"),spi_sclk); + printSetFormValue(dest,PSTR("SDA"),i2c_sda); + printSetFormValue(dest,PSTR("SCL"),i2c_scl); + printSetFormValue(dest,PSTR("MOSI"),spi_mosi); + printSetFormValue(dest,PSTR("MISO"),spi_miso); + printSetFormValue(dest,PSTR("SCLK"),spi_sclk); dest.printf_P(PSTR("addInfo('SDA','%d');" "addInfo('SCL','%d');" "addInfo('MOSI','%d');" @@ -641,21 +641,21 @@ void getSettingsJS(byte subPage, Print& dest) #endif VERSION); - printSetMessage(dest,PSTR("(\"sip\")[0]"),tmp_buf); + printSetClassElementHTML(dest,PSTR("sip"),0,tmp_buf); } if (subPage == SUBPAGE_2D) // 2D matrices { - printSetValue(dest,PSTR("SOMP"),strip.isMatrix); + printSetFormValue(dest,PSTR("SOMP"),strip.isMatrix); #ifndef WLED_DISABLE_2D - dest.print(F("maxPanels=")); dest.print(WLED_MAX_PANELS); dest.print(F(";")); + dest.printf_P(PSTR("maxPanels=%d;"),WLED_MAX_PANELS); dest.print(F("resetPanels();")); if (strip.isMatrix) { if(strip.panels>0){ - printSetValue(dest,PSTR("PW"),strip.panel[0].width); //Set generator Width and Height to first panel size for convenience - printSetValue(dest,PSTR("PH"),strip.panel[0].height); + printSetFormValue(dest,PSTR("PW"),strip.panel[0].width); //Set generator Width and Height to first panel size for convenience + printSetFormValue(dest,PSTR("PH"),strip.panel[0].height); } - printSetValue(dest,PSTR("MPC"),strip.panels); + printSetFormValue(dest,PSTR("MPC"),strip.panels); // panels for (unsigned i=0; i Date: Wed, 18 Sep 2024 19:19:40 -0400 Subject: [PATCH 026/234] Rename destination for getSettingsJS Use a name that makes it a bit clearer what the output is. The new name is applied consistently through most uses. Usermods are not yet updated. --- wled00/fcn_declare.h | 12 +- wled00/um_manager.cpp | 4 +- wled00/util.cpp | 24 +- wled00/xml.cpp | 556 +++++++++++++++++++++--------------------- 4 files changed, 298 insertions(+), 298 deletions(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 29db8ea76..5712c7f8d 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -302,7 +302,7 @@ class Usermod { virtual bool handleButton(uint8_t b) { return false; } // button overrides are possible here virtual bool getUMData(um_data_t **data) { if (data) *data = nullptr; return false; }; // usermod data exchange [see examples for audio effects] virtual void connected() {} // called when WiFi is (re)connected - virtual void appendConfigData(Print&); // helper function called from usermod settings page to add metadata for entry fields + virtual void appendConfigData(Print& settingsScript); // helper function called from usermod settings page to add metadata for entry fields virtual void addToJsonState(JsonObject& obj) {} // add JSON objects for WLED state virtual void addToJsonInfo(JsonObject& obj) {} // add JSON objects for UI Info page virtual void readFromJsonState(JsonObject& obj) {} // process JSON messages received from web server @@ -372,11 +372,11 @@ void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255); bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255); bool getBoolVal(JsonVariant elem, bool dflt); bool updateVal(const char* req, const char* key, byte* val, byte minv=0, byte maxv=255); -size_t printSetFormCheckbox(Print& dest, const char* key, int val); -size_t printSetFormValue(Print& dest, const char* key, int val); -size_t printSetFormValue(Print& dest, const char* key, const char* val); -size_t printSetFormIndex(Print& dest, const char* key, int index); -size_t printSetClassElementHTML(Print& dest, const char* key, const int index, const char* val); +size_t printSetFormCheckbox(Print& settingsScript, const char* key, int val); +size_t printSetFormValue(Print& settingsScript, const char* key, int val); +size_t printSetFormValue(Print& settingsScript, const char* key, const char* val); +size_t printSetFormIndex(Print& settingsScript, const char* key, int index); +size_t printSetClassElementHTML(Print& settingsScript, const char* key, const int index, const char* val); void prepareHostname(char* hostname); bool isAsterisksOnly(const char* str, byte maxLen); bool requestJSONBufferLock(uint8_t module=255); diff --git a/wled00/um_manager.cpp b/wled00/um_manager.cpp index 5307d26f6..ff3b62789 100644 --- a/wled00/um_manager.cpp +++ b/wled00/um_manager.cpp @@ -73,9 +73,9 @@ bool UsermodManager::add(Usermod* um) /* Usermod v2 interface shim for oappend */ Print* Usermod::oappend_shim = nullptr; -void Usermod::appendConfigData(Print& p) { +void Usermod::appendConfigData(Print& settingsScript) { assert(!oappend_shim); - oappend_shim = &p; + oappend_shim = &settingsScript; this->appendConfigData(); oappend_shim = nullptr; } diff --git a/wled00/util.cpp b/wled00/util.cpp index 07190e37c..0b78a4646 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -87,26 +87,26 @@ bool updateVal(const char* req, const char* key, byte* val, byte minv, byte maxv return true; } -static size_t printSetFormInput(Print& dest, const char* key, const char* selector, int value) { - return dest.printf_P(PSTR("d.Sf.%s.%s=%d;"), key, selector, value); +static size_t printSetFormInput(Print& settingsScript, const char* key, const char* selector, int value) { + return settingsScript.printf_P(PSTR("d.Sf.%s.%s=%d;"), key, selector, value); } -size_t printSetFormCheckbox(Print& dest, const char* key, int val) { - return printSetFormInput(dest, key, PSTR("checked"), val); +size_t printSetFormCheckbox(Print& settingsScript, const char* key, int val) { + return printSetFormInput(settingsScript, key, PSTR("checked"), val); } -size_t printSetFormValue(Print& dest, const char* key, int val) { - return printSetFormInput(dest, key, PSTR("value"), val); +size_t printSetFormValue(Print& settingsScript, const char* key, int val) { + return printSetFormInput(settingsScript, key, PSTR("value"), val); } -size_t printSetFormIndex(Print& dest, const char* key, int index) { - return printSetFormInput(dest, key, PSTR("selectedIndex"), index); +size_t printSetFormIndex(Print& settingsScript, const char* key, int index) { + return printSetFormInput(settingsScript, key, PSTR("selectedIndex"), index); } -size_t printSetFormValue(Print& dest, const char* key, const char* val) { - return dest.printf_P(PSTR("d.Sf.%s.value=\"%s\";"),key,val); +size_t printSetFormValue(Print& settingsScript, const char* key, const char* val) { + return settingsScript.printf_P(PSTR("d.Sf.%s.value=\"%s\";"),key,val); } -size_t printSetClassElementHTML(Print& dest, const char* key, const int index, const char* val) { - return dest.printf_P(PSTR("d.getElementsByClassName(\"%s\")[%d].innerHTML=\"%s\";"), key, index, val); +size_t printSetClassElementHTML(Print& settingsScript, const char* key, const int index, const char* val) { + return settingsScript.printf_P(PSTR("d.getElementsByClassName(\"%s\")[%d].innerHTML=\"%s\";"), key, index, val); } diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 8cbd51cde..5619a0ee3 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -26,19 +26,19 @@ void XML_response(Print& dest) ); } -static void extractPin(Print& dest, JsonObject &obj, const char *key) { +static void extractPin(Print& settingsScript, JsonObject &obj, const char *key) { if (obj[key].is()) { JsonArray pins = obj[key].as(); for (JsonVariant pv : pins) { - if (pv.as() > -1) { dest.print(","); dest.print(pv.as()); } + if (pv.as() > -1) { settingsScript.print(","); settingsScript.print(pv.as()); } } } else { - if (obj[key].as() > -1) { dest.print(","); dest.print(obj[key].as()); } + if (obj[key].as() > -1) { settingsScript.print(","); settingsScript.print(obj[key].as()); } } } -// dest.print used pins by scanning JsonObject (1 level deep) -void fillUMPins(Print& dest, JsonObject &mods) +// print used pins by scanning JsonObject (1 level deep) +static void fillUMPins(Print& settingsScript, JsonObject &mods) { for (JsonPair kv : mods) { // kv.key() is usermod name or subobject key @@ -47,7 +47,7 @@ void fillUMPins(Print& dest, JsonObject &mods) if (!obj.isNull()) { // element is an JsonObject if (!obj["pin"].isNull()) { - extractPin(dest, obj, "pin"); + extractPin(settingsScript, obj, "pin"); } else { // scan keys (just one level deep as is possible with usermods) for (JsonPair so : obj) { @@ -56,7 +56,7 @@ void fillUMPins(Print& dest, JsonObject &mods) // we found a key containing "pin" substring if (strlen(strstr(key, "pin")) == 3) { // and it is at the end, we found another pin - extractPin(dest, obj, key); + extractPin(settingsScript, obj, key); continue; } } @@ -64,7 +64,7 @@ void fillUMPins(Print& dest, JsonObject &mods) JsonObject subObj = obj[so.key()]; if (!subObj["pin"].isNull()) { // get pins from subobject - extractPin(dest, subObj, "pin"); + extractPin(settingsScript, subObj, "pin"); } } } @@ -72,81 +72,81 @@ void fillUMPins(Print& dest, JsonObject &mods) } } -void appendGPIOinfo(Print& dest) { - dest.print(F("d.um_p=[-1")); // has to have 1 element +void appendGPIOinfo(Print& settingsScript) { + settingsScript.print(F("d.um_p=[-1")); // has to have 1 element if (i2c_sda > -1 && i2c_scl > -1) { - dest.printf_P(PSTR(",%d,%d"), i2c_sda, i2c_scl); + settingsScript.printf_P(PSTR(",%d,%d"), i2c_sda, i2c_scl); } if (spi_mosi > -1 && spi_sclk > -1) { - dest.printf_P(PSTR(",%d,%d"), spi_mosi, spi_sclk); + settingsScript.printf_P(PSTR(",%d,%d"), spi_mosi, spi_sclk); } // usermod pin reservations will become unnecessary when settings pages will read cfg.json directly if (requestJSONBufferLock(6)) { // if we can't allocate JSON buffer ignore usermod pins JsonObject mods = pDoc->createNestedObject(F("um")); usermods.addToConfig(mods); - if (!mods.isNull()) fillUMPins(dest, mods); + if (!mods.isNull()) fillUMPins(settingsScript, mods); releaseJSONBufferLock(); } - dest.print(F("];")); + settingsScript.print(F("];")); // add reserved (unusable) pins - dest.print(SET_F("d.rsvd=[")); + settingsScript.print(SET_F("d.rsvd=[")); for (unsigned i = 0; i < WLED_NUM_PINS; i++) { if (!pinManager.isPinOk(i, false)) { // include readonly pins - dest.print(i); dest.print(","); + settingsScript.print(i); settingsScript.print(","); } } #ifdef WLED_ENABLE_DMX - dest.print(SET_F("2,")); // DMX hardcoded pin + settingsScript.print(SET_F("2,")); // DMX hardcoded pin #endif #if defined(WLED_DEBUG) && !defined(WLED_DEBUG_HOST) - dest.printf_P(PSTR(",%d"),hardwareTX); // debug output (TX) pin + settingsScript.printf_P(PSTR(",%d"),hardwareTX); // debug output (TX) pin #endif //Note: Using pin 3 (RX) disables Adalight / Serial JSON #ifdef WLED_USE_ETHERNET if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) { - for (unsigned p=0; p=0) { dest.printf(",%d", ethernetBoards[ethernetType].eth_power); } - if (ethernetBoards[ethernetType].eth_mdc>=0) { dest.printf(",%d", ethernetBoards[ethernetType].eth_mdc); } - if (ethernetBoards[ethernetType].eth_mdio>=0) { dest.printf(",%d", ethernetBoards[ethernetType].eth_mdio); } + for (unsigned p=0; p=0) { settingsScript.printf(",%d", ethernetBoards[ethernetType].eth_power); } + if (ethernetBoards[ethernetType].eth_mdc>=0) { settingsScript.printf(",%d", ethernetBoards[ethernetType].eth_mdc); } + if (ethernetBoards[ethernetType].eth_mdio>=0) { settingsScript.printf(",%d", ethernetBoards[ethernetType].eth_mdio); } switch (ethernetBoards[ethernetType].eth_clk_mode) { case ETH_CLOCK_GPIO0_IN: case ETH_CLOCK_GPIO0_OUT: - dest.print(SET_F("0")); + settingsScript.print(SET_F("0")); break; case ETH_CLOCK_GPIO16_OUT: - dest.print(SET_F("16")); + settingsScript.print(SET_F("16")); break; case ETH_CLOCK_GPIO17_OUT: - dest.print(SET_F("17")); + settingsScript.print(SET_F("17")); break; } } #endif - dest.print(SET_F("];")); // rsvd + settingsScript.print(SET_F("];")); // rsvd // add info for read-only GPIO - dest.print(SET_F("d.ro_gpio=[")); + settingsScript.print(SET_F("d.ro_gpio=[")); bool firstPin = true; for (unsigned i = 0; i < WLED_NUM_PINS; i++) { if (pinManager.isReadOnlyPin(i)) { // No comma before the first pin - if (!firstPin) dest.print(SET_F(",")); - dest.print(i); + if (!firstPin) settingsScript.print(SET_F(",")); + settingsScript.print(i); firstPin = false; } } - dest.print(SET_F("];")); + settingsScript.print(SET_F("];")); // add info about max. # of pins - dest.print(SET_F("d.max_gpio=")); - dest.print(WLED_NUM_PINS); - dest.print(SET_F(";")); + settingsScript.print(SET_F("d.max_gpio=")); + settingsScript.print(WLED_NUM_PINS); + settingsScript.print(SET_F(";")); } //get values for settings form in javascript -void getSettingsJS(byte subPage, Print& dest) +void getSettingsJS(byte subPage, Print& settingsScript) { //0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec DEBUG_PRINTF_P(PSTR("settings resp %u\n"), (unsigned)subPage); @@ -156,23 +156,23 @@ void getSettingsJS(byte subPage, Print& dest) if (subPage == SUBPAGE_MENU) { #ifdef WLED_DISABLE_2D // include only if 2D is not compiled in - dest.print(F("gId('2dbtn').style.display='none';")); + settingsScript.print(F("gId('2dbtn').style.display='none';")); #endif #ifdef WLED_ENABLE_DMX // include only if DMX is enabled - dest.print(F("gId('dmxbtn').style.display='';")); + settingsScript.print(F("gId('dmxbtn').style.display='';")); #endif } if (subPage == SUBPAGE_WIFI) { size_t l; - dest.printf_P(PSTR("resetWiFi(%d);"), WLED_MAX_WIFI_COUNT); + settingsScript.printf_P(PSTR("resetWiFi(%d);"), WLED_MAX_WIFI_COUNT); for (size_t n = 0; n < multiWiFi.size(); n++) { l = strlen(multiWiFi[n].clientPass); char fpass[l+1]; //fill password field with *** fpass[l] = 0; memset(fpass,'*',l); - dest.printf_P(PSTR("addWiFi(\"%s\",\",%s\",0x%X,0x%X,0x%X);"), + settingsScript.printf_P(PSTR("addWiFi(\"%s\",\",%s\",0x%X,0x%X,0x%X);"), multiWiFi[n].clientSSID, fpass, (uint32_t) multiWiFi[n].staticIP, // explicit cast required as this is a struct @@ -180,44 +180,44 @@ void getSettingsJS(byte subPage, Print& dest) (uint32_t) multiWiFi[n].staticSN); } - printSetFormValue(dest,PSTR("D0"),dnsAddress[0]); - printSetFormValue(dest,PSTR("D1"),dnsAddress[1]); - printSetFormValue(dest,PSTR("D2"),dnsAddress[2]); - printSetFormValue(dest,PSTR("D3"),dnsAddress[3]); + printSetFormValue(settingsScript,PSTR("D0"),dnsAddress[0]); + printSetFormValue(settingsScript,PSTR("D1"),dnsAddress[1]); + printSetFormValue(settingsScript,PSTR("D2"),dnsAddress[2]); + printSetFormValue(settingsScript,PSTR("D3"),dnsAddress[3]); - printSetFormValue(dest,PSTR("CM"),cmDNS); - printSetFormIndex(dest,PSTR("AB"),apBehavior); - printSetFormValue(dest,PSTR("AS"),apSSID); - printSetFormCheckbox(dest,PSTR("AH"),apHide); + printSetFormValue(settingsScript,PSTR("CM"),cmDNS); + printSetFormIndex(settingsScript,PSTR("AB"),apBehavior); + printSetFormValue(settingsScript,PSTR("AS"),apSSID); + printSetFormCheckbox(settingsScript,PSTR("AH"),apHide); l = strlen(apPass); char fapass[l+1]; //fill password field with *** fapass[l] = 0; memset(fapass,'*',l); - printSetFormValue(dest,PSTR("AP"),fapass); + printSetFormValue(settingsScript,PSTR("AP"),fapass); - printSetFormValue(dest,PSTR("AC"),apChannel); + printSetFormValue(settingsScript,PSTR("AC"),apChannel); #ifdef ARDUINO_ARCH_ESP32 - printSetFormValue(dest,PSTR("TX"),txPower); + printSetFormValue(settingsScript,PSTR("TX"),txPower); #else - dest.print(F("gId('tx').style.display='none';")); + settingsScript.print(F("gId('tx').style.display='none';")); #endif - printSetFormCheckbox(dest,PSTR("FG"),force802_3g); - printSetFormCheckbox(dest,PSTR("WS"),noWifiSleep); + printSetFormCheckbox(settingsScript,PSTR("FG"),force802_3g); + printSetFormCheckbox(settingsScript,PSTR("WS"),noWifiSleep); #ifndef WLED_DISABLE_ESPNOW - printSetFormCheckbox(dest,PSTR("RE"),enableESPNow); - printSetFormValue(dest,PSTR("RMAC"),linked_remote); + printSetFormCheckbox(settingsScript,PSTR("RE"),enableESPNow); + printSetFormValue(settingsScript,PSTR("RMAC"),linked_remote); #else //hide remote settings if not compiled - dest.print(F("toggle('ESPNOW');")); // hide ESP-NOW setting + settingsScript.print(F("toggle('ESPNOW');")); // hide ESP-NOW setting #endif #ifdef WLED_USE_ETHERNET - printSetFormValue(dest,PSTR("ETH"),ethernetType); + printSetFormValue(settingsScript,PSTR("ETH"),ethernetType); #else //hide ethernet setting if not compiled in - dest.print(F("gId('ethd').style.display='none';")); + settingsScript.print(F("gId('ethd').style.display='none';")); #endif if (Network.isConnected()) //is connected @@ -229,10 +229,10 @@ void getSettingsJS(byte subPage, Print& dest) #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) if (Network.isEthernet()) strcat_P(s ,SET_F(" (Ethernet)")); #endif - printSetClassElementHTML(dest,PSTR("sip"),0,s); + printSetClassElementHTML(settingsScript,PSTR("sip"),0,s); } else { - printSetClassElementHTML(dest,PSTR("sip"),0,(char*)F("Not connected")); + printSetClassElementHTML(settingsScript,PSTR("sip"),0,(char*)F("Not connected")); } if (WiFi.softAPIP()[0] != 0) //is active @@ -240,19 +240,19 @@ void getSettingsJS(byte subPage, Print& dest) char s[16]; IPAddress apIP = WiFi.softAPIP(); sprintf(s, "%d.%d.%d.%d", apIP[0], apIP[1], apIP[2], apIP[3]); - printSetClassElementHTML(dest,PSTR("sip"),1,s); + printSetClassElementHTML(settingsScript,PSTR("sip"),1,s); } else { - printSetClassElementHTML(dest,PSTR("sip"),1,(char*)F("Not active")); + printSetClassElementHTML(settingsScript,PSTR("sip"),1,(char*)F("Not active")); } #ifndef WLED_DISABLE_ESPNOW if (strlen(last_signal_src) > 0) { //Have seen an ESP-NOW Remote - printSetClassElementHTML(dest,PSTR("rlid"),0,last_signal_src); + printSetClassElementHTML(settingsScript,PSTR("rlid"),0,last_signal_src); } else if (!enableESPNow) { - printSetClassElementHTML(dest,PSTR("rlid"),0,(char*)F("(Enable ESP-NOW to listen)")); + printSetClassElementHTML(settingsScript,PSTR("rlid"),0,(char*)F("(Enable ESP-NOW to listen)")); } else { - printSetClassElementHTML(dest,PSTR("rlid"),0,(char*)F("None")); + printSetClassElementHTML(settingsScript,PSTR("rlid"),0,(char*)F("None")); } #endif } @@ -261,12 +261,12 @@ void getSettingsJS(byte subPage, Print& dest) { char nS[32]; - appendGPIOinfo(dest); + appendGPIOinfo(settingsScript); - dest.print(SET_F("d.ledTypes=")); dest.print(BusManager::getLEDTypesJSONString().c_str()); dest.print(";"); + settingsScript.print(SET_F("d.ledTypes=")); settingsScript.print(BusManager::getLEDTypesJSONString().c_str()); settingsScript.print(";"); // set limits - dest.printf_P(PSTR("bLimits(%d,%d,%d,%d,%d,%d,%d,%d);"), + settingsScript.printf_P(PSTR("bLimits(%d,%d,%d,%d,%d,%d,%d,%d);"), WLED_MAX_BUSSES, WLED_MIN_VIRTUAL_BUSSES, MAX_LEDS_PER_BUS, @@ -277,14 +277,14 @@ void getSettingsJS(byte subPage, Print& dest) WLED_MAX_ANALOG_CHANNELS ); - printSetFormCheckbox(dest,PSTR("MS"),strip.autoSegments); - printSetFormCheckbox(dest,PSTR("CCT"),strip.correctWB); - printSetFormCheckbox(dest,PSTR("IC"),cctICused); - printSetFormCheckbox(dest,PSTR("CR"),strip.cctFromRgb); - printSetFormValue(dest,PSTR("CB"),strip.cctBlending); - printSetFormValue(dest,PSTR("FR"),strip.getTargetFps()); - printSetFormValue(dest,PSTR("AW"),Bus::getGlobalAWMode()); - printSetFormCheckbox(dest,PSTR("LD"),useGlobalLedBuffer); + printSetFormCheckbox(settingsScript,PSTR("MS"),strip.autoSegments); + printSetFormCheckbox(settingsScript,PSTR("CCT"),strip.correctWB); + printSetFormCheckbox(settingsScript,PSTR("IC"),cctICused); + printSetFormCheckbox(settingsScript,PSTR("CR"),strip.cctFromRgb); + printSetFormValue(settingsScript,PSTR("CB"),strip.cctBlending); + printSetFormValue(settingsScript,PSTR("FR"),strip.getTargetFps()); + printSetFormValue(settingsScript,PSTR("AW"),Bus::getGlobalAWMode()); + printSetFormCheckbox(settingsScript,PSTR("LD"),useGlobalLedBuffer); unsigned sumMa = 0; for (int s = 0; s < BusManager::getNumBusses(); s++) { @@ -304,22 +304,22 @@ void getSettingsJS(byte subPage, Print& dest) char sp[4] = "SP"; sp[2] = offset+s; sp[3] = 0; //bus clock speed char la[4] = "LA"; la[2] = offset+s; la[3] = 0; //LED current char ma[4] = "MA"; ma[2] = offset+s; ma[3] = 0; //max per-port PSU current - dest.print(F("addLEDs(1);")); + settingsScript.print(F("addLEDs(1);")); uint8_t pins[5]; int nPins = bus->getPins(pins); for (int i = 0; i < nPins; i++) { lp[1] = offset+i; - if (pinManager.isPinOk(pins[i]) || bus->isVirtual()) printSetFormValue(dest,lp,pins[i]); + if (pinManager.isPinOk(pins[i]) || bus->isVirtual()) printSetFormValue(settingsScript,lp,pins[i]); } - printSetFormValue(dest,lc,bus->getLength()); - printSetFormValue(dest,lt,bus->getType()); - printSetFormValue(dest,co,bus->getColorOrder() & 0x0F); - printSetFormValue(dest,ls,bus->getStart()); - printSetFormCheckbox(dest,cv,bus->isReversed()); - printSetFormValue(dest,sl,bus->skippedLeds()); - printSetFormCheckbox(dest,rf,bus->isOffRefreshRequired()); - printSetFormValue(dest,aw,bus->getAutoWhiteMode()); - printSetFormValue(dest,wo,bus->getColorOrder() >> 4); + printSetFormValue(settingsScript,lc,bus->getLength()); + printSetFormValue(settingsScript,lt,bus->getType()); + printSetFormValue(settingsScript,co,bus->getColorOrder() & 0x0F); + printSetFormValue(settingsScript,ls,bus->getStart()); + printSetFormCheckbox(settingsScript,cv,bus->isReversed()); + printSetFormValue(settingsScript,sl,bus->skippedLeds()); + printSetFormCheckbox(settingsScript,rf,bus->isOffRefreshRequired()); + printSetFormValue(settingsScript,aw,bus->getAutoWhiteMode()); + printSetFormValue(settingsScript,wo,bus->getColorOrder() >> 4); unsigned speed = bus->getFrequency(); if (bus->isPWM()) { switch (speed) { @@ -340,148 +340,148 @@ void getSettingsJS(byte subPage, Print& dest) case 20000 : speed = 4; break; } } - printSetFormValue(dest,sp,speed); - printSetFormValue(dest,la,bus->getLEDCurrent()); - printSetFormValue(dest,ma,bus->getMaxCurrent()); + printSetFormValue(settingsScript,sp,speed); + printSetFormValue(settingsScript,la,bus->getLEDCurrent()); + printSetFormValue(settingsScript,ma,bus->getMaxCurrent()); sumMa += bus->getMaxCurrent(); } - printSetFormValue(dest,PSTR("MA"),BusManager::ablMilliampsMax() ? BusManager::ablMilliampsMax() : sumMa); - printSetFormCheckbox(dest,PSTR("ABL"),BusManager::ablMilliampsMax() || sumMa > 0); - printSetFormCheckbox(dest,PSTR("PPL"),!BusManager::ablMilliampsMax() && sumMa > 0); + printSetFormValue(settingsScript,PSTR("MA"),BusManager::ablMilliampsMax() ? BusManager::ablMilliampsMax() : sumMa); + printSetFormCheckbox(settingsScript,PSTR("ABL"),BusManager::ablMilliampsMax() || sumMa > 0); + printSetFormCheckbox(settingsScript,PSTR("PPL"),!BusManager::ablMilliampsMax() && sumMa > 0); - dest.printf_P(PSTR("resetCOM(%d);"), WLED_MAX_COLOR_ORDER_MAPPINGS); + settingsScript.printf_P(PSTR("resetCOM(%d);"), WLED_MAX_COLOR_ORDER_MAPPINGS); const ColorOrderMap& com = BusManager::getColorOrderMap(); for (int s = 0; s < com.count(); s++) { const ColorOrderMapEntry* entry = com.get(s); if (entry == nullptr) break; - dest.printf_P(PSTR("addCOM(%d,%d,%d);"), entry->start, entry->len, entry->colorOrder); + settingsScript.printf_P(PSTR("addCOM(%d,%d,%d);"), entry->start, entry->len, entry->colorOrder); } - printSetFormValue(dest,PSTR("CA"),briS); + printSetFormValue(settingsScript,PSTR("CA"),briS); - printSetFormCheckbox(dest,PSTR("BO"),turnOnAtBoot); - printSetFormValue(dest,PSTR("BP"),bootPreset); + printSetFormCheckbox(settingsScript,PSTR("BO"),turnOnAtBoot); + printSetFormValue(settingsScript,PSTR("BP"),bootPreset); - printSetFormCheckbox(dest,PSTR("GB"),gammaCorrectBri); - printSetFormCheckbox(dest,PSTR("GC"),gammaCorrectCol); - dtostrf(gammaCorrectVal,3,1,nS); printSetFormValue(dest,PSTR("GV"),nS); - printSetFormCheckbox(dest,PSTR("TF"),fadeTransition); - printSetFormCheckbox(dest,PSTR("EB"),modeBlending); - printSetFormValue(dest,PSTR("TD"),transitionDelayDefault); - printSetFormCheckbox(dest,PSTR("PF"),strip.paletteFade); - printSetFormValue(dest,PSTR("TP"),randomPaletteChangeTime); - printSetFormCheckbox(dest,PSTR("TH"),useHarmonicRandomPalette); - printSetFormValue(dest,PSTR("BF"),briMultiplier); - printSetFormValue(dest,PSTR("TB"),nightlightTargetBri); - printSetFormValue(dest,PSTR("TL"),nightlightDelayMinsDefault); - printSetFormValue(dest,PSTR("TW"),nightlightMode); - printSetFormIndex(dest,PSTR("PB"),strip.paletteBlend); - printSetFormValue(dest,PSTR("RL"),rlyPin); - printSetFormCheckbox(dest,PSTR("RM"),rlyMde); - printSetFormCheckbox(dest,PSTR("RO"),rlyOpenDrain); + printSetFormCheckbox(settingsScript,PSTR("GB"),gammaCorrectBri); + printSetFormCheckbox(settingsScript,PSTR("GC"),gammaCorrectCol); + dtostrf(gammaCorrectVal,3,1,nS); printSetFormValue(settingsScript,PSTR("GV"),nS); + printSetFormCheckbox(settingsScript,PSTR("TF"),fadeTransition); + printSetFormCheckbox(settingsScript,PSTR("EB"),modeBlending); + printSetFormValue(settingsScript,PSTR("TD"),transitionDelayDefault); + printSetFormCheckbox(settingsScript,PSTR("PF"),strip.paletteFade); + printSetFormValue(settingsScript,PSTR("TP"),randomPaletteChangeTime); + printSetFormCheckbox(settingsScript,PSTR("TH"),useHarmonicRandomPalette); + printSetFormValue(settingsScript,PSTR("BF"),briMultiplier); + printSetFormValue(settingsScript,PSTR("TB"),nightlightTargetBri); + printSetFormValue(settingsScript,PSTR("TL"),nightlightDelayMinsDefault); + printSetFormValue(settingsScript,PSTR("TW"),nightlightMode); + printSetFormIndex(settingsScript,PSTR("PB"),strip.paletteBlend); + printSetFormValue(settingsScript,PSTR("RL"),rlyPin); + printSetFormCheckbox(settingsScript,PSTR("RM"),rlyMde); + printSetFormCheckbox(settingsScript,PSTR("RO"),rlyOpenDrain); for (int i = 0; i < WLED_MAX_BUTTONS; i++) { - dest.printf_P(PSTR("addBtn(%d,%d,%d);"), i, btnPin[i], buttonType[i]); + settingsScript.printf_P(PSTR("addBtn(%d,%d,%d);"), i, btnPin[i], buttonType[i]); } - printSetFormCheckbox(dest,PSTR("IP"),disablePullUp); - printSetFormValue(dest,PSTR("TT"),touchThreshold); + printSetFormCheckbox(settingsScript,PSTR("IP"),disablePullUp); + printSetFormValue(settingsScript,PSTR("TT"),touchThreshold); #ifndef WLED_DISABLE_INFRARED - printSetFormValue(dest,PSTR("IR"),irPin); - printSetFormValue(dest,PSTR("IT"),irEnabled); + printSetFormValue(settingsScript,PSTR("IR"),irPin); + printSetFormValue(settingsScript,PSTR("IT"),irEnabled); #endif - printSetFormCheckbox(dest,PSTR("MSO"),!irApplyToAllSelected); + printSetFormCheckbox(settingsScript,PSTR("MSO"),!irApplyToAllSelected); } if (subPage == SUBPAGE_UI) { - printSetFormValue(dest,PSTR("DS"),serverDescription); - printSetFormCheckbox(dest,PSTR("SU"),simplifiedUI); + printSetFormValue(settingsScript,PSTR("DS"),serverDescription); + printSetFormCheckbox(settingsScript,PSTR("SU"),simplifiedUI); } if (subPage == SUBPAGE_SYNC) { [[maybe_unused]] char nS[32]; - printSetFormValue(dest,PSTR("UP"),udpPort); - printSetFormValue(dest,PSTR("U2"),udpPort2); + printSetFormValue(settingsScript,PSTR("UP"),udpPort); + printSetFormValue(settingsScript,PSTR("U2"),udpPort2); #ifndef WLED_DISABLE_ESPNOW - if (enableESPNow) printSetFormCheckbox(dest,PSTR("EN"),useESPNowSync); - else dest.print(F("toggle('ESPNOW');")); // hide ESP-NOW setting + if (enableESPNow) printSetFormCheckbox(settingsScript,PSTR("EN"),useESPNowSync); + else settingsScript.print(F("toggle('ESPNOW');")); // hide ESP-NOW setting #else - dest.print(F("toggle('ESPNOW');")); // hide ESP-NOW setting + settingsScript.print(F("toggle('ESPNOW');")); // hide ESP-NOW setting #endif - printSetFormValue(dest,PSTR("GS"),syncGroups); - printSetFormValue(dest,PSTR("GR"),receiveGroups); + printSetFormValue(settingsScript,PSTR("GS"),syncGroups); + printSetFormValue(settingsScript,PSTR("GR"),receiveGroups); - printSetFormCheckbox(dest,PSTR("RB"),receiveNotificationBrightness); - printSetFormCheckbox(dest,PSTR("RC"),receiveNotificationColor); - printSetFormCheckbox(dest,PSTR("RX"),receiveNotificationEffects); - printSetFormCheckbox(dest,PSTR("RP"),receiveNotificationPalette); - printSetFormCheckbox(dest,PSTR("SO"),receiveSegmentOptions); - printSetFormCheckbox(dest,PSTR("SG"),receiveSegmentBounds); - printSetFormCheckbox(dest,PSTR("SS"),sendNotifications); - printSetFormCheckbox(dest,PSTR("SD"),notifyDirect); - printSetFormCheckbox(dest,PSTR("SB"),notifyButton); - printSetFormCheckbox(dest,PSTR("SH"),notifyHue); - printSetFormValue(dest,PSTR("UR"),udpNumRetries); + printSetFormCheckbox(settingsScript,PSTR("RB"),receiveNotificationBrightness); + printSetFormCheckbox(settingsScript,PSTR("RC"),receiveNotificationColor); + printSetFormCheckbox(settingsScript,PSTR("RX"),receiveNotificationEffects); + printSetFormCheckbox(settingsScript,PSTR("RP"),receiveNotificationPalette); + printSetFormCheckbox(settingsScript,PSTR("SO"),receiveSegmentOptions); + printSetFormCheckbox(settingsScript,PSTR("SG"),receiveSegmentBounds); + printSetFormCheckbox(settingsScript,PSTR("SS"),sendNotifications); + printSetFormCheckbox(settingsScript,PSTR("SD"),notifyDirect); + printSetFormCheckbox(settingsScript,PSTR("SB"),notifyButton); + printSetFormCheckbox(settingsScript,PSTR("SH"),notifyHue); + printSetFormValue(settingsScript,PSTR("UR"),udpNumRetries); - printSetFormCheckbox(dest,PSTR("NL"),nodeListEnabled); - printSetFormCheckbox(dest,PSTR("NB"),nodeBroadcastEnabled); + printSetFormCheckbox(settingsScript,PSTR("NL"),nodeListEnabled); + printSetFormCheckbox(settingsScript,PSTR("NB"),nodeBroadcastEnabled); - printSetFormCheckbox(dest,PSTR("RD"),receiveDirect); - printSetFormCheckbox(dest,PSTR("MO"),useMainSegmentOnly); - printSetFormCheckbox(dest,PSTR("RLM"),realtimeRespectLedMaps); - printSetFormValue(dest,PSTR("EP"),e131Port); - printSetFormCheckbox(dest,PSTR("ES"),e131SkipOutOfSequence); - printSetFormCheckbox(dest,PSTR("EM"),e131Multicast); - printSetFormValue(dest,PSTR("EU"),e131Universe); - printSetFormValue(dest,PSTR("DA"),DMXAddress); - printSetFormValue(dest,PSTR("XX"),DMXSegmentSpacing); - printSetFormValue(dest,PSTR("PY"),e131Priority); - printSetFormValue(dest,PSTR("DM"),DMXMode); - printSetFormValue(dest,PSTR("ET"),realtimeTimeoutMs); - printSetFormCheckbox(dest,PSTR("FB"),arlsForceMaxBri); - printSetFormCheckbox(dest,PSTR("RG"),arlsDisableGammaCorrection); - printSetFormValue(dest,PSTR("WO"),arlsOffset); + printSetFormCheckbox(settingsScript,PSTR("RD"),receiveDirect); + printSetFormCheckbox(settingsScript,PSTR("MO"),useMainSegmentOnly); + printSetFormCheckbox(settingsScript,PSTR("RLM"),realtimeRespectLedMaps); + printSetFormValue(settingsScript,PSTR("EP"),e131Port); + printSetFormCheckbox(settingsScript,PSTR("ES"),e131SkipOutOfSequence); + printSetFormCheckbox(settingsScript,PSTR("EM"),e131Multicast); + printSetFormValue(settingsScript,PSTR("EU"),e131Universe); + printSetFormValue(settingsScript,PSTR("DA"),DMXAddress); + printSetFormValue(settingsScript,PSTR("XX"),DMXSegmentSpacing); + printSetFormValue(settingsScript,PSTR("PY"),e131Priority); + printSetFormValue(settingsScript,PSTR("DM"),DMXMode); + printSetFormValue(settingsScript,PSTR("ET"),realtimeTimeoutMs); + printSetFormCheckbox(settingsScript,PSTR("FB"),arlsForceMaxBri); + printSetFormCheckbox(settingsScript,PSTR("RG"),arlsDisableGammaCorrection); + printSetFormValue(settingsScript,PSTR("WO"),arlsOffset); #ifndef WLED_DISABLE_ALEXA - printSetFormCheckbox(dest,PSTR("AL"),alexaEnabled); - printSetFormValue(dest,PSTR("AI"),alexaInvocationName); - printSetFormCheckbox(dest,PSTR("SA"),notifyAlexa); - printSetFormValue(dest,PSTR("AP"),alexaNumPresets); + printSetFormCheckbox(settingsScript,PSTR("AL"),alexaEnabled); + printSetFormValue(settingsScript,PSTR("AI"),alexaInvocationName); + printSetFormCheckbox(settingsScript,PSTR("SA"),notifyAlexa); + printSetFormValue(settingsScript,PSTR("AP"),alexaNumPresets); #else - dest.print(F("toggle('Alexa');")); // hide Alexa settings + settingsScript.print(F("toggle('Alexa');")); // hide Alexa settings #endif #ifndef WLED_DISABLE_MQTT - printSetFormCheckbox(dest,PSTR("MQ"),mqttEnabled); - printSetFormValue(dest,PSTR("MS"),mqttServer); - printSetFormValue(dest,PSTR("MQPORT"),mqttPort); - printSetFormValue(dest,PSTR("MQUSER"),mqttUser); + printSetFormCheckbox(settingsScript,PSTR("MQ"),mqttEnabled); + printSetFormValue(settingsScript,PSTR("MS"),mqttServer); + printSetFormValue(settingsScript,PSTR("MQPORT"),mqttPort); + printSetFormValue(settingsScript,PSTR("MQUSER"),mqttUser); byte l = strlen(mqttPass); char fpass[l+1]; //fill password field with *** fpass[l] = 0; memset(fpass,'*',l); - printSetFormValue(dest,PSTR("MQPASS"),fpass); - printSetFormValue(dest,PSTR("MQCID"),mqttClientID); - printSetFormValue(dest,PSTR("MD"),mqttDeviceTopic); - printSetFormValue(dest,PSTR("MG"),mqttGroupTopic); - printSetFormCheckbox(dest,PSTR("BM"),buttonPublishMqtt); - printSetFormCheckbox(dest,PSTR("RT"),retainMqttMsg); - dest.printf_P(PSTR("d.Sf.MD.maxlength=%d;d.Sf.MG.maxlength=%d;d.Sf.MS.maxlength=%d;"), + printSetFormValue(settingsScript,PSTR("MQPASS"),fpass); + printSetFormValue(settingsScript,PSTR("MQCID"),mqttClientID); + printSetFormValue(settingsScript,PSTR("MD"),mqttDeviceTopic); + printSetFormValue(settingsScript,PSTR("MG"),mqttGroupTopic); + printSetFormCheckbox(settingsScript,PSTR("BM"),buttonPublishMqtt); + printSetFormCheckbox(settingsScript,PSTR("RT"),retainMqttMsg); + settingsScript.printf_P(PSTR("d.Sf.MD.maxlength=%d;d.Sf.MG.maxlength=%d;d.Sf.MS.maxlength=%d;"), MQTT_MAX_TOPIC_LEN, MQTT_MAX_TOPIC_LEN, MQTT_MAX_SERVER_LEN); #else - dest.print(F("toggle('MQTT');")); // hide MQTT settings + settingsScript.print(F("toggle('MQTT');")); // hide MQTT settings #endif #ifndef WLED_DISABLE_HUESYNC - printSetFormValue(dest,PSTR("H0"),hueIP[0]); - printSetFormValue(dest,PSTR("H1"),hueIP[1]); - printSetFormValue(dest,PSTR("H2"),hueIP[2]); - printSetFormValue(dest,PSTR("H3"),hueIP[3]); - printSetFormValue(dest,PSTR("HL"),huePollLightId); - printSetFormValue(dest,PSTR("HI"),huePollIntervalMs); - printSetFormCheckbox(dest,PSTR("HP"),huePollingEnabled); - printSetFormCheckbox(dest,PSTR("HO"),hueApplyOnOff); - printSetFormCheckbox(dest,PSTR("HB"),hueApplyBri); - printSetFormCheckbox(dest,PSTR("HC"),hueApplyColor); + printSetFormValue(settingsScript,PSTR("H0"),hueIP[0]); + printSetFormValue(settingsScript,PSTR("H1"),hueIP[1]); + printSetFormValue(settingsScript,PSTR("H2"),hueIP[2]); + printSetFormValue(settingsScript,PSTR("H3"),hueIP[3]); + printSetFormValue(settingsScript,PSTR("HL"),huePollLightId); + printSetFormValue(settingsScript,PSTR("HI"),huePollIntervalMs); + printSetFormCheckbox(settingsScript,PSTR("HP"),huePollingEnabled); + printSetFormCheckbox(settingsScript,PSTR("HO"),hueApplyOnOff); + printSetFormCheckbox(settingsScript,PSTR("HB"),hueApplyBri); + printSetFormCheckbox(settingsScript,PSTR("HC"),hueApplyColor); char hueErrorString[25]; switch (hueError) { @@ -495,56 +495,56 @@ void getSettingsJS(byte subPage, Print& dest) default: sprintf_P(hueErrorString,PSTR("Bridge Error %i"),hueError); } - printSetClassElementHTML(dest,PSTR("sip"),0,hueErrorString); + printSetClassElementHTML(settingsScript,PSTR("sip"),0,hueErrorString); #else - dest.print(F("toggle('Hue');")); // hide Hue Sync settings + settingsScript.print(F("toggle('Hue');")); // hide Hue Sync settings #endif - printSetFormValue(dest,PSTR("BD"),serialBaud); + printSetFormValue(settingsScript,PSTR("BD"),serialBaud); #ifndef WLED_ENABLE_ADALIGHT - dest.print(SET_F("toggle('Serial);")); + settingsScript.print(SET_F("toggle('Serial);")); #endif } if (subPage == SUBPAGE_TIME) { - printSetFormCheckbox(dest,PSTR("NT"),ntpEnabled); - printSetFormValue(dest,PSTR("NS"),ntpServerName); - printSetFormCheckbox(dest,PSTR("CF"),!useAMPM); - printSetFormIndex(dest,PSTR("TZ"),currentTimezone); - printSetFormValue(dest,PSTR("UO"),utcOffsetSecs); + printSetFormCheckbox(settingsScript,PSTR("NT"),ntpEnabled); + printSetFormValue(settingsScript,PSTR("NS"),ntpServerName); + printSetFormCheckbox(settingsScript,PSTR("CF"),!useAMPM); + printSetFormIndex(settingsScript,PSTR("TZ"),currentTimezone); + printSetFormValue(settingsScript,PSTR("UO"),utcOffsetSecs); char tm[32]; dtostrf(longitude,4,2,tm); - printSetFormValue(dest,PSTR("LN"),tm); + printSetFormValue(settingsScript,PSTR("LN"),tm); dtostrf(latitude,4,2,tm); - printSetFormValue(dest,PSTR("LT"),tm); + printSetFormValue(settingsScript,PSTR("LT"),tm); getTimeString(tm); - printSetClassElementHTML(dest,PSTR("times"),0,tm); + printSetClassElementHTML(settingsScript,PSTR("times"),0,tm); if ((int)(longitude*10.0f) || (int)(latitude*10.0f)) { sprintf_P(tm, PSTR("Sunrise: %02d:%02d Sunset: %02d:%02d"), hour(sunrise), minute(sunrise), hour(sunset), minute(sunset)); - printSetClassElementHTML(dest,PSTR("times"),1,tm); + printSetClassElementHTML(settingsScript,PSTR("times"),1,tm); } - printSetFormCheckbox(dest,PSTR("OL"),overlayCurrent); - printSetFormValue(dest,PSTR("O1"),overlayMin); - printSetFormValue(dest,PSTR("O2"),overlayMax); - printSetFormValue(dest,PSTR("OM"),analogClock12pixel); - printSetFormCheckbox(dest,PSTR("OS"),analogClockSecondsTrail); - printSetFormCheckbox(dest,PSTR("O5"),analogClock5MinuteMarks); - printSetFormCheckbox(dest,PSTR("OB"),analogClockSolidBlack); + printSetFormCheckbox(settingsScript,PSTR("OL"),overlayCurrent); + printSetFormValue(settingsScript,PSTR("O1"),overlayMin); + printSetFormValue(settingsScript,PSTR("O2"),overlayMax); + printSetFormValue(settingsScript,PSTR("OM"),analogClock12pixel); + printSetFormCheckbox(settingsScript,PSTR("OS"),analogClockSecondsTrail); + printSetFormCheckbox(settingsScript,PSTR("O5"),analogClock5MinuteMarks); + printSetFormCheckbox(settingsScript,PSTR("OB"),analogClockSolidBlack); - printSetFormCheckbox(dest,PSTR("CE"),countdownMode); - printSetFormValue(dest,PSTR("CY"),countdownYear); - printSetFormValue(dest,PSTR("CI"),countdownMonth); - printSetFormValue(dest,PSTR("CD"),countdownDay); - printSetFormValue(dest,PSTR("CH"),countdownHour); - printSetFormValue(dest,PSTR("CM"),countdownMin); - printSetFormValue(dest,PSTR("CS"),countdownSec); + printSetFormCheckbox(settingsScript,PSTR("CE"),countdownMode); + printSetFormValue(settingsScript,PSTR("CY"),countdownYear); + printSetFormValue(settingsScript,PSTR("CI"),countdownMonth); + printSetFormValue(settingsScript,PSTR("CD"),countdownDay); + printSetFormValue(settingsScript,PSTR("CH"),countdownHour); + printSetFormValue(settingsScript,PSTR("CM"),countdownMin); + printSetFormValue(settingsScript,PSTR("CS"),countdownSec); - printSetFormValue(dest,PSTR("A0"),macroAlexaOn); - printSetFormValue(dest,PSTR("A1"),macroAlexaOff); - printSetFormValue(dest,PSTR("MC"),macroCountdown); - printSetFormValue(dest,PSTR("MN"),macroNl); + printSetFormValue(settingsScript,PSTR("A0"),macroAlexaOn); + printSetFormValue(settingsScript,PSTR("A1"),macroAlexaOff); + printSetFormValue(settingsScript,PSTR("MC"),macroCountdown); + printSetFormValue(settingsScript,PSTR("MN"),macroNl); for (unsigned i=0; i> 4) & 0x0F); - k[0] = 'P'; printSetFormValue(dest,k,timerMonth[i] & 0x0F); - k[0] = 'D'; printSetFormValue(dest,k,timerDay[i]); - k[0] = 'E'; printSetFormValue(dest,k,timerDayEnd[i]); + k[0] = 'M'; printSetFormValue(settingsScript,k,(timerMonth[i] >> 4) & 0x0F); + k[0] = 'P'; printSetFormValue(settingsScript,k,timerMonth[i] & 0x0F); + k[0] = 'D'; printSetFormValue(settingsScript,k,timerDay[i]); + k[0] = 'E'; printSetFormValue(settingsScript,k,timerDayEnd[i]); } } } @@ -571,61 +571,61 @@ void getSettingsJS(byte subPage, Print& dest) char fpass[l+1]; //fill PIN field with 0000 fpass[l] = 0; memset(fpass,'0',l); - printSetFormValue(dest,PSTR("PIN"),fpass); - printSetFormCheckbox(dest,PSTR("NO"),otaLock); - printSetFormCheckbox(dest,PSTR("OW"),wifiLock); - printSetFormCheckbox(dest,PSTR("AO"),aOtaEnabled); + printSetFormValue(settingsScript,PSTR("PIN"),fpass); + printSetFormCheckbox(settingsScript,PSTR("NO"),otaLock); + printSetFormCheckbox(settingsScript,PSTR("OW"),wifiLock); + printSetFormCheckbox(settingsScript,PSTR("AO"),aOtaEnabled); char tmp_buf[128]; snprintf_P(tmp_buf,sizeof(tmp_buf),PSTR("WLED %s (build %d)"),versionString,VERSION); - printSetClassElementHTML(dest,PSTR("sip"),0,tmp_buf); - dest.printf_P(PSTR("sd=\"%s\";"), serverDescription); + printSetClassElementHTML(settingsScript,PSTR("sip"),0,tmp_buf); + settingsScript.printf_P(PSTR("sd=\"%s\";"), serverDescription); } #ifdef WLED_ENABLE_DMX // include only if DMX is enabled if (subPage == SUBPAGE_DMX) { - printSetFormValue(dest,PSTR("PU"),e131ProxyUniverse); + printSetFormValue(settingsScript,PSTR("PU"),e131ProxyUniverse); - printSetFormValue(dest,PSTR("CN"),DMXChannels); - printSetFormValue(dest,PSTR("CG"),DMXGap); - printSetFormValue(dest,PSTR("CS"),DMXStart); - printSetFormValue(dest,PSTR("SL"),DMXStartLED); + printSetFormValue(settingsScript,PSTR("CN"),DMXChannels); + printSetFormValue(settingsScript,PSTR("CG"),DMXGap); + printSetFormValue(settingsScript,PSTR("CS"),DMXStart); + printSetFormValue(settingsScript,PSTR("SL"),DMXStartLED); - printSetFormIndex(dest,PSTR("CH1"),DMXFixtureMap[0]); - printSetFormIndex(dest,PSTR("CH2"),DMXFixtureMap[1]); - printSetFormIndex(dest,PSTR("CH3"),DMXFixtureMap[2]); - printSetFormIndex(dest,PSTR("CH4"),DMXFixtureMap[3]); - printSetFormIndex(dest,PSTR("CH5"),DMXFixtureMap[4]); - printSetFormIndex(dest,PSTR("CH6"),DMXFixtureMap[5]); - printSetFormIndex(dest,PSTR("CH7"),DMXFixtureMap[6]); - printSetFormIndex(dest,PSTR("CH8"),DMXFixtureMap[7]); - printSetFormIndex(dest,PSTR("CH9"),DMXFixtureMap[8]); - printSetFormIndex(dest,PSTR("CH10"),DMXFixtureMap[9]); - printSetFormIndex(dest,PSTR("CH11"),DMXFixtureMap[10]); - printSetFormIndex(dest,PSTR("CH12"),DMXFixtureMap[11]); - printSetFormIndex(dest,PSTR("CH13"),DMXFixtureMap[12]); - printSetFormIndex(dest,PSTR("CH14"),DMXFixtureMap[13]); - printSetFormIndex(dest,PSTR("CH15"),DMXFixtureMap[14]); + printSetFormIndex(settingsScript,PSTR("CH1"),DMXFixtureMap[0]); + printSetFormIndex(settingsScript,PSTR("CH2"),DMXFixtureMap[1]); + printSetFormIndex(settingsScript,PSTR("CH3"),DMXFixtureMap[2]); + printSetFormIndex(settingsScript,PSTR("CH4"),DMXFixtureMap[3]); + printSetFormIndex(settingsScript,PSTR("CH5"),DMXFixtureMap[4]); + printSetFormIndex(settingsScript,PSTR("CH6"),DMXFixtureMap[5]); + printSetFormIndex(settingsScript,PSTR("CH7"),DMXFixtureMap[6]); + printSetFormIndex(settingsScript,PSTR("CH8"),DMXFixtureMap[7]); + printSetFormIndex(settingsScript,PSTR("CH9"),DMXFixtureMap[8]); + printSetFormIndex(settingsScript,PSTR("CH10"),DMXFixtureMap[9]); + printSetFormIndex(settingsScript,PSTR("CH11"),DMXFixtureMap[10]); + printSetFormIndex(settingsScript,PSTR("CH12"),DMXFixtureMap[11]); + printSetFormIndex(settingsScript,PSTR("CH13"),DMXFixtureMap[12]); + printSetFormIndex(settingsScript,PSTR("CH14"),DMXFixtureMap[13]); + printSetFormIndex(settingsScript,PSTR("CH15"),DMXFixtureMap[14]); } #endif if (subPage == SUBPAGE_UM) //usermods { - appendGPIOinfo(dest); - dest.printf_P(PSTR("numM=%d;"), usermods.getModCount()); - printSetFormValue(dest,PSTR("SDA"),i2c_sda); - printSetFormValue(dest,PSTR("SCL"),i2c_scl); - printSetFormValue(dest,PSTR("MOSI"),spi_mosi); - printSetFormValue(dest,PSTR("MISO"),spi_miso); - printSetFormValue(dest,PSTR("SCLK"),spi_sclk); - dest.printf_P(PSTR("addInfo('SDA','%d');" + appendGPIOinfo(settingsScript); + settingsScript.printf_P(PSTR("numM=%d;"), usermods.getModCount()); + printSetFormValue(settingsScript,PSTR("SDA"),i2c_sda); + printSetFormValue(settingsScript,PSTR("SCL"),i2c_scl); + printSetFormValue(settingsScript,PSTR("MOSI"),spi_mosi); + printSetFormValue(settingsScript,PSTR("MISO"),spi_miso); + printSetFormValue(settingsScript,PSTR("SCLK"),spi_sclk); + settingsScript.printf_P(PSTR("addInfo('SDA','%d');" "addInfo('SCL','%d');" "addInfo('MOSI','%d');" "addInfo('MISO','%d');" "addInfo('SCLK','%d');"), HW_PIN_SDA, HW_PIN_SCL, HW_PIN_DATASPI, HW_PIN_MISOSPI, HW_PIN_CLOCKSPI ); - usermods.appendConfigData(dest); + usermods.appendConfigData(settingsScript); } if (subPage == SUBPAGE_UPDATE) // update @@ -641,44 +641,44 @@ void getSettingsJS(byte subPage, Print& dest) #endif VERSION); - printSetClassElementHTML(dest,PSTR("sip"),0,tmp_buf); + printSetClassElementHTML(settingsScript,PSTR("sip"),0,tmp_buf); } if (subPage == SUBPAGE_2D) // 2D matrices { - printSetFormValue(dest,PSTR("SOMP"),strip.isMatrix); + printSetFormValue(settingsScript,PSTR("SOMP"),strip.isMatrix); #ifndef WLED_DISABLE_2D - dest.printf_P(PSTR("maxPanels=%d;"),WLED_MAX_PANELS); - dest.print(F("resetPanels();")); + settingsScript.printf_P(PSTR("maxPanels=%d;"),WLED_MAX_PANELS); + settingsScript.print(F("resetPanels();")); if (strip.isMatrix) { if(strip.panels>0){ - printSetFormValue(dest,PSTR("PW"),strip.panel[0].width); //Set generator Width and Height to first panel size for convenience - printSetFormValue(dest,PSTR("PH"),strip.panel[0].height); + printSetFormValue(settingsScript,PSTR("PW"),strip.panel[0].width); //Set generator Width and Height to first panel size for convenience + printSetFormValue(settingsScript,PSTR("PH"),strip.panel[0].height); } - printSetFormValue(dest,PSTR("MPC"),strip.panels); + printSetFormValue(settingsScript,PSTR("MPC"),strip.panels); // panels for (unsigned i=0; i Date: Thu, 19 Sep 2024 08:49:18 +0200 Subject: [PATCH 027/234] revert removal of adding with saturation, renamed 'fast' to 'saturate' - blurring now uses desaturated adding: it is faster most of the times and blurring adds scaled colors so should rarely (ever?) saturate, I saw no visual difference in tests. - formatting --- wled00/FX.h | 18 +++++++++--------- wled00/FX_2Dfcn.cpp | 2 +- wled00/FX_fcn.cpp | 2 +- wled00/colors.cpp | 31 ++++++++++++++++++++----------- wled00/fcn_declare.h | 4 ++-- 5 files changed, 33 insertions(+), 24 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index bea4dbcb8..50bcd6624 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -595,9 +595,9 @@ typedef struct Segment { void fadeToBlackBy(uint8_t fadeBy); inline void blendPixelColor(int n, uint32_t color, uint8_t blend) { setPixelColor(n, color_blend(getPixelColor(n), color, blend)); } inline void blendPixelColor(int n, CRGB c, uint8_t blend) { blendPixelColor(n, RGBW32(c.r,c.g,c.b,0), blend); } - inline void addPixelColor(int n, uint32_t color) { setPixelColor(n, color_add(getPixelColor(n), color)); } - inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0) { addPixelColor(n, RGBW32(r,g,b,w)); } - inline void addPixelColor(int n, CRGB c) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } + inline void addPixelColor(int n, uint32_t color, bool saturate = false) { setPixelColor(n, color_add(getPixelColor(n), color, saturate)); } + inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool saturate = false) { addPixelColor(n, RGBW32(r,g,b,w), saturate); } + inline void addPixelColor(int n, CRGB c, bool saturate = false) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), saturate); } inline void fadePixelColor(uint16_t n, uint8_t fade) { setPixelColor(n, color_fade(getPixelColor(n), fade, true)); } [[gnu::hot]] uint32_t color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255) const; [[gnu::hot]] uint32_t color_wheel(uint8_t pos) const; @@ -632,9 +632,9 @@ typedef struct Segment { // 2D support functions inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) { setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend)); } inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), blend); } - inline void addPixelColorXY(int x, int y, uint32_t color) { setPixelColorXY(x, y, color_add(getPixelColorXY(x,y), color)); } - inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { addPixelColorXY(x, y, RGBW32(r,g,b,w)); } - inline void addPixelColorXY(int x, int y, CRGB c) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } + inline void addPixelColorXY(int x, int y, uint32_t color, bool saturate = false) { setPixelColorXY(x, y, color_add(getPixelColorXY(x,y), color, saturate)); } + inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool saturate = false) { addPixelColorXY(x, y, RGBW32(r,g,b,w), saturate); } + inline void addPixelColorXY(int x, int y, CRGB c, bool saturate = false) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), saturate); } inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), fade, true)); } void box_blur(unsigned r = 1U, bool smear = false); // 2D box blur void blur2D(uint8_t blur_amount, bool smear = false); @@ -670,9 +670,9 @@ typedef struct Segment { inline uint32_t getPixelColorXY(int x, int y) { return getPixelColor(x); } inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t c, uint8_t blend) { blendPixelColor(x, c, blend); } inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColor(x, RGBW32(c.r,c.g,c.b,0), blend); } - inline void addPixelColorXY(int x, int y, uint32_t color) { addPixelColor(x, color); } - inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { addPixelColor(x, RGBW32(r,g,b,w)); } - inline void addPixelColorXY(int x, int y, CRGB c) { addPixelColor(x, RGBW32(c.r,c.g,c.b,0)); } + inline void addPixelColorXY(int x, int y, uint32_t color, bool saturate = false) { addPixelColor(x, color, saturate); } + inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool saturate = false) { addPixelColor(x, RGBW32(r,g,b,w), saturate); } + inline void addPixelColorXY(int x, int y, CRGB c, bool saturate = false) { addPixelColor(x, RGBW32(c.r,c.g,c.b,0), saturate); } inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { fadePixelColor(x, fade); } inline void box_blur(unsigned i, bool vertical, fract8 blur_amount) {} inline void blur2D(uint8_t blur_amount, bool smear = false) {} diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 10b85a82e..63595d930 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -188,7 +188,7 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) int yY = y; for (int j = 0; j < grouping; j++) { // groupping vertically - if(yY >= H) break; + if (yY >= H) break; int xX = x; for (int g = 0; g < grouping; g++) { // groupping horizontally if (xX >= W) continue; // we have reached one dimension's end diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 66aeaab63..7159d21c7 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1169,7 +1169,7 @@ uint32_t Segment::color_wheel(uint8_t pos) const { pos = 255 - pos; if (pos < 85) { return RGBW32((255 - pos * 3), 0, (pos * 3), w); - } else if(pos < 170) { + } else if (pos < 170) { pos -= 85; return RGBW32(0, (pos * 3), (255 - pos * 3), w); } else { diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 54469ebe0..13405be6e 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -36,7 +36,7 @@ uint32_t color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) * original idea: https://github.com/Aircoookie/WLED/pull/2465 by https://github.com/Proto-molecule * heavily optimized for speed by @dedehai */ -uint32_t color_add(uint32_t c1, uint32_t c2) +uint32_t color_add(uint32_t c1, uint32_t c2, bool desat) { if (c1 == BLACK) return c2; if (c2 == BLACK) return c1; @@ -47,18 +47,27 @@ uint32_t color_add(uint32_t c1, uint32_t c2) uint32_t w = wg >> 16; uint32_t g = wg & 0xFFFF; - unsigned max = r; // check for overflow note: not checking and just topping out at 255 (formerly 'fast') is not any faster (but even slower if not overflowing) - max = g > max ? g : max; - max = b > max ? b : max; - max = w > max ? w : max; + if(desat) { // desaturate + unsigned max = r; // check for overflow note + max = g > max ? g : max; + max = b > max ? b : max; + max = w > max ? w : max; - if (max > 255) { - uint32_t scale = (uint32_t(255)<<8) / max; // division of two 8bit (shifted) values does not work -> use bit shifts and multiplaction instead - rb = ((rb * scale) >> 8) & 0x00FF00FF; // - wg = (wg * scale) & 0xFF00FF00; + if (max > 255) { + uint32_t scale = (uint32_t(255)<<8) / max; // division of two 8bit (shifted) values does not work -> use bit shifts and multiplaction instead + rb = ((rb * scale) >> 8) & 0x00FF00FF; // + wg = (wg * scale) & 0xFF00FF00; + } + else wg = wg << 8; //shift white and green back to correct position + return rb | wg; + } + else { + r = r > 255 ? 255 : r; + g = g > 255 ? 255 : g; + b = b > 255 ? 255 : b; + w = w > 255 ? 255 : w; + return RGBW32(r,g,b,w); } - else wg = wg << 8; //shift white and green back to correct position - return rb | wg; } /* diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index be7ed4462..d32356d7b 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -79,8 +79,8 @@ class NeoGammaWLEDMethod { }; #define gamma32(c) NeoGammaWLEDMethod::Correct32(c) #define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c) -[[gnu::hot]] uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false); -[[gnu::hot]] uint32_t color_add(uint32_t,uint32_t); +[[gnu::hot]] uint32_t color_blend(uint32_t, uint32_t, uint16_t, bool b16=false); +[[gnu::hot]] uint32_t color_add(uint32_t, uint32_t, bool desat = false); [[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); [[gnu::hot]] CRGB ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND); CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette); From 17d59d333710264a6e0772b3e9d29c8a59c1e189 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 22 Sep 2024 09:02:42 +0200 Subject: [PATCH 028/234] adding initialization to vStrip, added comment on padding bytes --- wled00/FX.h | 1 + wled00/FX_fcn.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/wled00/FX.h b/wled00/FX.h index 50bcd6624..49277ba11 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -368,6 +368,7 @@ typedef struct Segment { }; uint8_t startY; // start Y coodrinate 2D (top); there should be no more than 255 rows uint8_t stopY; // stop Y coordinate 2D (bottom); there should be no more than 255 rows + //note: here are 3 free bytes of padding char *name; // runtime data diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 7159d21c7..e78608a14 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -712,7 +712,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) { if (!isActive()) return; // not active #ifndef WLED_DISABLE_2D - int vStrip; + int vStrip = 0; #endif if (i >= virtualLength() || i<0) // pixel would fall out of segment, check if this is a virtual strip NOTE: this is almost always false if not virtual strip, saves the calculation on 'standard' call { From 0a5400263be34b6a9b45e7d11acefce584f17614 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 22 Sep 2024 13:52:56 +0200 Subject: [PATCH 029/234] removed IRAM_ATTR from inlined function when the function is inlined into a IRAM_ATTR function, it will also reside in IRAM. Forced inlining is recommended by Espressif if I understand this correctly: https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/hardware-abstraction.html --- wled00/FX_fcn.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index e78608a14..9fd78e314 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1884,7 +1884,7 @@ bool WS2812FX::deserializeMap(uint8_t n) { return (customMappingSize > 0); } -__attribute__ ((always_inline)) inline uint16_t IRAM_ATTR WS2812FX::getMappedPixelIndex(uint16_t index) const { +__attribute__ ((always_inline)) inline uint16_t WS2812FX::getMappedPixelIndex(uint16_t index) const { // convert logical address to physical if (index < customMappingSize && (realtimeMode == REALTIME_MODE_INACTIVE || realtimeRespectLedMaps)) index = customMappingTable[index]; From 33cf82a9822a427d941107eba76e562a446a72ab Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Mon, 23 Sep 2024 18:03:17 +0200 Subject: [PATCH 030/234] Indentations and a few optimisations Restore addPixelColor() behaviour. --- wled00/FX.h | 22 ++++++++++++------- wled00/FX_2Dfcn.cpp | 16 ++++++-------- wled00/FX_fcn.cpp | 48 +++++++++++++++------------------------- wled00/cfg.cpp | 6 ++--- wled00/colors.cpp | 52 ++++++++++++++++++++++---------------------- wled00/fcn_declare.h | 2 +- 6 files changed, 69 insertions(+), 77 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 49277ba11..989dfbe33 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -56,6 +56,9 @@ #define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b)))) #endif +extern bool realtimeRespectLedMaps; // used in getMappedPixelIndex() +extern byte realtimeMode; // used in getMappedPixelIndex() + /* Not used in all effects yet */ #define WLED_FPS 42 #define FRAMETIME_FIXED (1000/WLED_FPS) @@ -596,9 +599,9 @@ typedef struct Segment { void fadeToBlackBy(uint8_t fadeBy); inline void blendPixelColor(int n, uint32_t color, uint8_t blend) { setPixelColor(n, color_blend(getPixelColor(n), color, blend)); } inline void blendPixelColor(int n, CRGB c, uint8_t blend) { blendPixelColor(n, RGBW32(c.r,c.g,c.b,0), blend); } - inline void addPixelColor(int n, uint32_t color, bool saturate = false) { setPixelColor(n, color_add(getPixelColor(n), color, saturate)); } - inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool saturate = false) { addPixelColor(n, RGBW32(r,g,b,w), saturate); } - inline void addPixelColor(int n, CRGB c, bool saturate = false) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), saturate); } + inline void addPixelColor(int n, uint32_t color, bool preserveCR = true) { setPixelColor(n, color_add(getPixelColor(n), color, preserveCR)); } + inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool preserveCR = true) { addPixelColor(n, RGBW32(r,g,b,w), preserveCR); } + inline void addPixelColor(int n, CRGB c, bool preserveCR = true) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), preserveCR); } inline void fadePixelColor(uint16_t n, uint8_t fade) { setPixelColor(n, color_fade(getPixelColor(n), fade, true)); } [[gnu::hot]] uint32_t color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255) const; [[gnu::hot]] uint32_t color_wheel(uint8_t pos) const; @@ -633,9 +636,9 @@ typedef struct Segment { // 2D support functions inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) { setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend)); } inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), blend); } - inline void addPixelColorXY(int x, int y, uint32_t color, bool saturate = false) { setPixelColorXY(x, y, color_add(getPixelColorXY(x,y), color, saturate)); } - inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool saturate = false) { addPixelColorXY(x, y, RGBW32(r,g,b,w), saturate); } - inline void addPixelColorXY(int x, int y, CRGB c, bool saturate = false) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), saturate); } + inline void addPixelColorXY(int x, int y, uint32_t color, bool preserveCR = true) { setPixelColorXY(x, y, color_add(getPixelColorXY(x,y), color, preserveCR)); } + inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool preserveCR = true) { addPixelColorXY(x, y, RGBW32(r,g,b,w), preserveCR); } + inline void addPixelColorXY(int x, int y, CRGB c, bool preserveCR = true) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), preserveCR); } inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), fade, true)); } void box_blur(unsigned r = 1U, bool smear = false); // 2D box blur void blur2D(uint8_t blur_amount, bool smear = false); @@ -837,13 +840,16 @@ class WS2812FX { // 96 bytes uint16_t getLengthPhysical() const, getLengthTotal() const, // will include virtual/nonexistent pixels in matrix - getFps() const, - getMappedPixelIndex(uint16_t index) const; + getFps() const; inline uint16_t getFrameTime() const { return _frametime; } // returns amount of time a frame should take (in ms) inline uint16_t getMinShowDelay() const { return MIN_SHOW_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant) inline uint16_t getLength() const { return _length; } // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H) inline uint16_t getTransition() const { return _transitionDur; } // returns currently set transition time (in ms) + inline uint16_t getMappedPixelIndex(uint16_t index) const { // convert logical address to physical + if (index < customMappingSize && (realtimeMode == REALTIME_MODE_INACTIVE || realtimeRespectLedMaps)) index = customMappingTable[index]; + return index; + }; uint32_t now, diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 63595d930..ca28a9586 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -191,7 +191,7 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) if (yY >= H) break; int xX = x; for (int g = 0; g < grouping; g++) { // groupping horizontally - if (xX >= W) continue; // we have reached one dimension's end + if (xX >= W) break; // we have reached X dimension's end #ifndef WLED_DISABLE_MODE_BLEND // if blending modes, blend with underlying pixel if (_modeBlend) col = color_blend(strip.getPixelColorXY(start + xX, startY + yY), col, 0xFFFFU - progress(), true); @@ -292,11 +292,10 @@ void Segment::blurRow(uint32_t row, fract8 blur_amount, bool smear){ uint32_t part = color_fade(cur, seep); curnew = color_fade(cur, keep); if (x > 0) { - if (carryover) - curnew = color_add(curnew, carryover); + if (carryover) curnew = color_add(curnew, carryover); uint32_t prev = color_add(lastnew, part); - if (last != prev) // optimization: only set pixel if color has changed - setPixelColorXY(x - 1, row, prev); + // optimization: only set pixel if color has changed + if (last != prev) setPixelColorXY(x - 1, row, prev); } else // first pixel setPixelColorXY(x, row, curnew); lastnew = curnew; @@ -325,11 +324,10 @@ void Segment::blurCol(uint32_t col, fract8 blur_amount, bool smear) { uint32_t part = color_fade(cur, seep); curnew = color_fade(cur, keep); if (y > 0) { - if (carryover) - curnew = color_add(curnew, carryover); + if (carryover) curnew = color_add(curnew, carryover); uint32_t prev = color_add(lastnew, part); - if (last != prev) // optimization: only set pixel if color has changed - setPixelColorXY(col, y - 1, prev); + // optimization: only set pixel if color has changed + if (last != prev) setPixelColorXY(col, y - 1, prev); } else // first pixel setPixelColorXY(col, y, curnew); lastnew = curnew; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 9fd78e314..545c92f25 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -628,13 +628,7 @@ uint16_t IRAM_ATTR Segment::virtualHeight() const { uint16_t IRAM_ATTR_YN Segment::nrOfVStrips() const { unsigned vLen = 1; #ifndef WLED_DISABLE_2D - if (is2D()) { - switch (map1D2D) { - case M12_pBar: - vLen = virtualWidth(); - break; - } - } + if (is2D() && map1D2D == M12_pBar) vLen = virtualWidth(); #endif return vLen; } @@ -710,17 +704,21 @@ uint16_t IRAM_ATTR Segment::virtualLength() const { void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) { - if (!isActive()) return; // not active + if (!isActive() || i < 0) return; // not active or invalid index #ifndef WLED_DISABLE_2D int vStrip = 0; #endif - if (i >= virtualLength() || i<0) // pixel would fall out of segment, check if this is a virtual strip NOTE: this is almost always false if not virtual strip, saves the calculation on 'standard' call - { + // if the 1D effect is using virtual strips "i" will have virtual strip id stored in upper 16 bits + // in such case "i" will be > virtualLength() + if (i >= virtualLength()) { + // check if this is a virtual strip #ifndef WLED_DISABLE_2D vStrip = i>>16; // hack to allow running on virtual strips (2D segment columns/rows) + i &= 0xFFFF; //truncate vstrip index + if (i >= virtualLength()) return; // if pixel would still fall out of segment just exit + #else + return; #endif - i &= 0xFFFF; //truncate vstrip index - if (i >= virtualLength() || i<0) return; // if pixel would still fall out of segment just exit } #ifndef WLED_DISABLE_2D @@ -734,12 +732,12 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) break; case M12_pBar: // expand 1D effect vertically or have it play on virtual strips - if (vStrip>0) setPixelColorXY(vStrip - 1, vH - i - 1, col); - else for (int x = 0; x < vW; x++) setPixelColorXY(x, vH - i - 1, col); + if (vStrip > 0) setPixelColorXY(vStrip - 1, vH - i - 1, col); + else for (int x = 0; x < vW; x++) setPixelColorXY(x, vH - i - 1, col); break; case M12_pArc: // expand in circular fashion from center - if (i==0) + if (i == 0) setPixelColorXY(0, 0, col); else { float r = i; @@ -910,9 +908,6 @@ void Segment::setPixelColor(float i, uint32_t col, bool aa) uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const { if (!isActive()) return 0; // not active -#ifndef WLED_DISABLE_2D - int vStrip = i>>16; -#endif #ifndef WLED_DISABLE_2D if (is2D()) { @@ -922,10 +917,11 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const case M12_Pixels: return getPixelColorXY(i % vW, i / vW); break; - case M12_pBar: - if (vStrip>0) { i &= 0xFFFF; return getPixelColorXY(vStrip - 1, vH - i -1); } - else return getPixelColorXY(0, vH - i -1); - break; + case M12_pBar: { + int vStrip = i>>16; // virtual strips are only relevant in Bar expansion mode + if (vStrip > 0) return getPixelColorXY(vStrip - 1, vH - (i & 0xFFFF) -1); + else return getPixelColorXY(0, vH - i -1); + break; } case M12_pArc: if (i >= vW && i >= vH) { unsigned vI = sqrt16(i*i/2); @@ -1884,14 +1880,6 @@ bool WS2812FX::deserializeMap(uint8_t n) { return (customMappingSize > 0); } -__attribute__ ((always_inline)) inline uint16_t WS2812FX::getMappedPixelIndex(uint16_t index) const { - // convert logical address to physical - if (index < customMappingSize - && (realtimeMode == REALTIME_MODE_INACTIVE || realtimeRespectLedMaps)) index = customMappingTable[index]; - - return index; -} - WS2812FX* WS2812FX::instance = nullptr; diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 8983da65b..00e219138 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -437,9 +437,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { if (light_gc_col > 1.0f) gammaCorrectCol = true; else gammaCorrectCol = false; if (gammaCorrectVal <= 1.0f || gammaCorrectVal > 3) { - gammaCorrectVal = 1.0f; // no gamma correction - gammaCorrectBri = false; - gammaCorrectCol = false; + gammaCorrectVal = 1.0f; // no gamma correction + gammaCorrectBri = false; + gammaCorrectCol = false; } NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 13405be6e..233d3d116 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -34,9 +34,9 @@ uint32_t color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) /* * color add function that preserves ratio * original idea: https://github.com/Aircoookie/WLED/pull/2465 by https://github.com/Proto-molecule - * heavily optimized for speed by @dedehai + * speed optimisations by @dedehai */ -uint32_t color_add(uint32_t c1, uint32_t c2, bool desat) +uint32_t color_add(uint32_t c1, uint32_t c2, bool preserveCR) { if (c1 == BLACK) return c2; if (c2 == BLACK) return c1; @@ -47,21 +47,21 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool desat) uint32_t w = wg >> 16; uint32_t g = wg & 0xFFFF; - if(desat) { // desaturate - unsigned max = r; // check for overflow note - max = g > max ? g : max; - max = b > max ? b : max; - max = w > max ? w : max; - + if (preserveCR) { // preserve color ratios + unsigned max = std::max(r,g); // check for overflow note + max = std::max(max,b); + max = std::max(max,w); + //unsigned max = r; // check for overflow note + //max = g > max ? g : max; + //max = b > max ? b : max; + //max = w > max ? w : max; if (max > 255) { uint32_t scale = (uint32_t(255)<<8) / max; // division of two 8bit (shifted) values does not work -> use bit shifts and multiplaction instead rb = ((rb * scale) >> 8) & 0x00FF00FF; // wg = (wg * scale) & 0xFF00FF00; - } - else wg = wg << 8; //shift white and green back to correct position + } else wg = wg << 8; //shift white and green back to correct position return rb | wg; - } - else { + } else { r = r > 255 ? 255 : r; g = g > 255 ? 255 : g; b = b > 255 ? 255 : b; @@ -106,20 +106,20 @@ CRGB ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brig unsigned red1 = entry->r; unsigned green1 = entry->g; unsigned blue1 = entry->b; - if(blendType != NOBLEND) { - if(hi4 == 15) entry = &(pal[0]); - else ++entry; - unsigned f2 = ((index & 0x0F) << 4) + 1; // +1 so we scale by 256 as a max value, then result can just be shifted by 8 - unsigned f1 = (257 - f2); // f2 is 1 minimum, so this is 256 max - red1 = (red1 * f1 + (unsigned)entry->r * f2) >> 8; - green1 = (green1 * f1 + (unsigned)entry->g * f2) >> 8; - blue1 = (blue1 * f1 + (unsigned)entry->b * f2) >> 8; + if (blendType != NOBLEND) { + if (hi4 == 15) entry = &(pal[0]); + else ++entry; + unsigned f2 = ((index & 0x0F) << 4) + 1; // +1 so we scale by 256 as a max value, then result can just be shifted by 8 + unsigned f1 = (257 - f2); // f2 is 1 minimum, so this is 256 max + red1 = (red1 * f1 + (unsigned)entry->r * f2) >> 8; + green1 = (green1 * f1 + (unsigned)entry->g * f2) >> 8; + blue1 = (blue1 * f1 + (unsigned)entry->b * f2) >> 8; } - if( brightness < 255) { // note: zero checking could be done to return black but that is hardly ever used so it is omitted - uint32_t scale = brightness + 1; // adjust for rounding (bitshift) - red1 = (red1 * scale) >> 8; - green1 = (green1 * scale) >> 8; - blue1 = (blue1 * scale) >> 8; + if (brightness < 255) { // note: zero checking could be done to return black but that is hardly ever used so it is omitted + uint32_t scale = brightness + 1; // adjust for rounding (bitshift) + red1 = (red1 * scale) >> 8; + green1 = (green1 * scale) >> 8; + blue1 = (blue1 * scale) >> 8; } return CRGB((uint8_t)red1, (uint8_t)green1, (uint8_t)blue1); } @@ -485,7 +485,7 @@ uint16_t approximateKelvinFromRGB(uint32_t rgb) { } } -//gamma 2.8 lookup table used for color correction +// gamma lookup table used for color correction (filled on 1st use (cfg.cpp & set.cpp)) uint8_t NeoGammaWLEDMethod::gammaT[256]; // re-calculates & fills gamma table diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index d32356d7b..741e1eefd 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -80,7 +80,7 @@ class NeoGammaWLEDMethod { #define gamma32(c) NeoGammaWLEDMethod::Correct32(c) #define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c) [[gnu::hot]] uint32_t color_blend(uint32_t, uint32_t, uint16_t, bool b16=false); -[[gnu::hot]] uint32_t color_add(uint32_t, uint32_t, bool desat = false); +[[gnu::hot]] uint32_t color_add(uint32_t, uint32_t, bool preserveCR = false); [[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); [[gnu::hot]] CRGB ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND); CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette); From 3ccc5babc13cc16ed1f141115f83c236b1d3c2ba Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Mon, 23 Sep 2024 20:39:16 +0200 Subject: [PATCH 031/234] Remov superfluous #if --- wled00/udp.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/wled00/udp.cpp b/wled00/udp.cpp index 09e1440ef..60774d701 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -974,10 +974,8 @@ void espNowReceiveCB(uint8_t* address, uint8_t* data, uint8_t len, signed int rs DEBUG_PRINTLN(); #endif -#ifndef WLED_DISABLE_ESPNOW // usermods hook can override processing if (UsermodManager::onEspNowMessage(address, data, len)) return; -#endif // handle WiZ Mote data if (data[0] == 0x91 || data[0] == 0x81 || data[0] == 0x80) { From c600c6da63f2a818814595ea9cf6d8dd5d8e0b47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Wed, 25 Sep 2024 09:33:16 +0200 Subject: [PATCH 032/234] Bus length fix --- wled00/FX_fcn.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 737d5f7a4..1bbfa365b 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1290,7 +1290,7 @@ void WS2812FX::finalizeInit() { // if we have less counts than pins and they do not align, use last known count to set current count unsigned count = defCounts[(i < defNumCounts) ? i : defNumCounts -1]; // analog always has length 1 - if (Bus::isPWM(dataType)) count = 1; + if (Bus::isPWM(dataType) || Bus::isOnOff(dataType)) count = 1; prevLen += count; BusConfig defCfg = BusConfig(dataType, defPin, start, count, DEFAULT_LED_COLOR_ORDER, false, 0, RGBW_MODE_MANUAL_ONLY, 0, useGlobalLedBuffer); if (BusManager::add(defCfg) == -1) break; From 906f8fc2e72cc901be7136fe533a40a27a97fd2d Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Wed, 25 Sep 2024 18:49:10 +0200 Subject: [PATCH 033/234] Fix C3 compiler issue. --- wled00/colors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 233d3d116..00f184601 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -48,7 +48,7 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool preserveCR) uint32_t g = wg & 0xFFFF; if (preserveCR) { // preserve color ratios - unsigned max = std::max(r,g); // check for overflow note + uint32_t max = std::max(r,g); // check for overflow note max = std::max(max,b); max = std::max(max,w); //unsigned max = r; // check for overflow note From bef1ac2668eb17312549e637f81c3954ac3052cd Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Wed, 25 Sep 2024 19:36:20 +0200 Subject: [PATCH 034/234] Added HSV2RGB and RGB2HSV functions for higher accuracy conversions - also added a struct to handle HSV with 16bit hue better (including some conversions, can be extended easily) - the functions are optimized for speed and flash use. They are faster and more accurate than what fastled offers (and use much less flash). - replaced colorHStoRGB() with a call to the new hsv2rgb() function, saving even more flash (new function is untested!) - the 16bit hue calculations result in an almost perfect conversion from RGB to HSV and back, the maximum error was 1/255 in the cases I tested. --- wled00/colors.cpp | 74 +++++++++++++++++++++++++++++++++----------- wled00/fcn_declare.h | 29 ++++++++++++++++- wled00/ir.cpp | 4 +-- 3 files changed, 86 insertions(+), 21 deletions(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 00f184601..163429f7f 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -239,26 +239,64 @@ CRGBPalette16 generateRandomPalette() //generate fully random palette CHSV(random8(), random8(160, 255), random8(128, 255))); } -void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb +void hsv2rgb(const CHSV32& hsv, uint32_t& rgb) // convert HSV (16bit hue) to RGB (32bit with white = 0) { - float h = ((float)hue)/10922.5f; // hue*6/65535 - float s = ((float)sat)/255.0f; - int i = int(h); - float f = h - i; - int p = int(255.0f * (1.0f-s)); - int q = int(255.0f * (1.0f-s*f)); - int t = int(255.0f * (1.0f-s*(1.0f-f))); - p = constrain(p, 0, 255); - q = constrain(q, 0, 255); - t = constrain(t, 0, 255); - switch (i%6) { - case 0: rgb[0]=255,rgb[1]=t, rgb[2]=p; break; - case 1: rgb[0]=q, rgb[1]=255,rgb[2]=p; break; - case 2: rgb[0]=p, rgb[1]=255,rgb[2]=t; break; - case 3: rgb[0]=p, rgb[1]=q, rgb[2]=255;break; - case 4: rgb[0]=t, rgb[1]=p, rgb[2]=255;break; - case 5: rgb[0]=255,rgb[1]=p, rgb[2]=q; break; + unsigned int remainder, region, p, q, t; + unsigned int h = hsv.h; + unsigned int s = hsv.s; + unsigned int v = hsv.v; + if (s == 0) { + rgb = v << 16 | v << 8 | v; + return; } + region = h / 10923; // 65536 / 6 = 10923 + remainder = (h - (region * 10923)) * 6; + p = (v * (256 - s)) >> 8; + q = (v * (255 - ((s * remainder) >> 16))) >> 8; + t = (v * (255 - ((s * (65535 - remainder)) >> 16))) >> 8; + switch (region) { + case 0: + rgb = v << 16 | t << 8 | p; break; + case 1: + rgb = q << 16 | v << 8 | p; break; + case 2: + rgb = p << 16 | v << 8 | t; break; + case 3: + rgb = p << 16 | q << 8 | v; break; + case 4: + rgb = t << 16 | p << 8 | v; break; + default: + rgb = v << 16 | p << 8 | q; break; + } +} + +void rgb2hsv(const uint32_t rgb, CHSV32& hsv) // convert RGB to HSV (16bit hue), much more accurate and faster than fastled version +{ + hsv.raw = 0; + int32_t r = (rgb>>16)&0xFF; + int32_t g = (rgb>>8)&0xFF; + int32_t b = rgb&0xFF; + int32_t minval, maxval, delta; + minval = min(r, g); + minval = min(minval, b); + maxval = max(r, g); + maxval = max(maxval, b); + if (maxval == 0) return; // black + hsv.v = maxval; + delta = maxval - minval; + hsv.s = (255 * delta) / maxval; + if (hsv.s == 0) return; // gray value + if (maxval == r) hsv.h = (10923 * (g - b)) / delta; + else if (maxval == g) hsv.h = 21845 + (10923 * (b - r)) / delta; + else hsv.h = 43690 + (10923 * (r - g)) / delta; +} + +void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) { //hue, sat to rgb + uint32_t crgb; + hsv2rgb(CHSV32(hue, sat, 255), crgb); + rgb[0] = byte((crgb) >> 16); + rgb[1] = byte((crgb) >> 8); + rgb[2] = byte(crgb); } //get RGB values from color temperature in K (https://tannerhelland.com/2012/09/18/convert-temperature-rgb-algorithm-code.html) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 741e1eefd..b5bd1c28e 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -67,6 +67,30 @@ typedef struct WiFiConfig { //colors.cpp #define ColorFromPalette ColorFromPaletteWLED // override fastled version + +struct CHSV32 { // 32bit HSV color with 16bit hue for more accurate conversions + union { + struct { + uint16_t h; // hue + uint8_t s; // saturation + uint8_t v; // value + }; + uint32_t raw; // 32bit access + }; + inline CHSV32() __attribute__((always_inline)) = default; // default constructor + + /// Allow construction from hue, saturation, and value + /// @param ih input hue + /// @param is input saturation + /// @param iv input value + inline CHSV32(uint16_t ih, uint8_t is, uint8_t iv) __attribute__((always_inline)) // constructor from 16bit h, s, v + : h(ih), s(is), v(iv) {} + inline CHSV32(uint8_t ih, uint8_t is, uint8_t iv) __attribute__((always_inline)) // constructor from 8bit h, s, v + : h((uint16_t)ih << 8), s(is), v(iv) {} + inline CHSV32(const CHSV& chsv) __attribute__((always_inline)) // constructor from CHSV + : h((uint16_t)chsv.h << 8), s(chsv.s), v(chsv.v) {} + inline operator CHSV() const { return CHSV((uint8_t)(h >> 8), s, v); } // typecast to CHSV +}; // similar to NeoPixelBus NeoGammaTableMethod but allows dynamic changes (superseded by NPB::NeoGammaDynamicTableMethod) class NeoGammaWLEDMethod { public: @@ -86,7 +110,10 @@ class NeoGammaWLEDMethod { CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette); CRGBPalette16 generateRandomPalette(); inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); } -void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb +void hsv2rgb(const CHSV32& hsv, uint32_t& rgb); +void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); +void rgb2hsv(const uint32_t rgb, CHSV32& hsv); +inline CHSV rgb2hsv(const CRGB c) { CHSV32 hsv; rgb2hsv((uint32_t((byte(c.r) << 16) | (byte(c.g) << 8) | (byte(c.b)))), hsv); return CHSV(hsv); } // CRGB to hsv void colorKtoRGB(uint16_t kelvin, byte* rgb); void colorCTtoRGB(uint16_t mired, byte* rgb); //white spectrum to rgb void colorXYtoRGB(float x, float y, byte* rgb); // only defined if huesync disabled TODO diff --git a/wled00/ir.cpp b/wled00/ir.cpp index e4541cd90..f094d3b87 100644 --- a/wled00/ir.cpp +++ b/wled00/ir.cpp @@ -129,7 +129,7 @@ static void changeEffectSpeed(int8_t amount) } else { // if Effect == "solid Color", change the hue of the primary color Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment(); CRGB fastled_col = CRGB(sseg.colors[0]); - CHSV prim_hsv = rgb2hsv_approximate(fastled_col); + CHSV prim_hsv = rgb2hsv(fastled_col); int16_t new_val = (int16_t)prim_hsv.h + amount; if (new_val > 255) new_val -= 255; // roll-over if bigger than 255 if (new_val < 0) new_val += 255; // roll-over if smaller than 0 @@ -173,7 +173,7 @@ static void changeEffectIntensity(int8_t amount) } else { // if Effect == "solid Color", change the saturation of the primary color Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment(); CRGB fastled_col = CRGB(sseg.colors[0]); - CHSV prim_hsv = rgb2hsv_approximate(fastled_col); + CHSV prim_hsv = rgb2hsv(fastled_col); int16_t new_val = (int16_t) prim_hsv.s + amount; prim_hsv.s = (byte)constrain(new_val,0,255); // constrain to 0-255 hsv2rgb_rainbow(prim_hsv, fastled_col); From b40445836931f769dce87168ff80c0ec489afc2c Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 26 Sep 2024 18:29:31 +0200 Subject: [PATCH 035/234] fixed one forgotten replacement of rgb2hsv_approximate --- wled00/colors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 163429f7f..d705b9a7f 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -138,7 +138,7 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) { CHSV palettecolors[4]; //array of colors for the new palette uint8_t keepcolorposition = random8(4); //color position of current random palette to keep - palettecolors[keepcolorposition] = rgb2hsv_approximate(basepalette.entries[keepcolorposition*5]); //read one of the base colors of the current palette + palettecolors[keepcolorposition] = rgb2hsv(basepalette.entries[keepcolorposition*5]); //read one of the base colors of the current palette palettecolors[keepcolorposition].hue += random8(10)-5; // +/- 5 randomness of base color //generate 4 saturation and brightness value numbers //only one saturation is allowed to be below 200 creating mostly vibrant colors From a76a895f1d86f9405b94fca5dc91a6649bdf48dd Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Fri, 27 Sep 2024 06:17:26 +0200 Subject: [PATCH 036/234] bugfix --- wled00/colors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index d705b9a7f..1b6a6f8d9 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -251,7 +251,7 @@ void hsv2rgb(const CHSV32& hsv, uint32_t& rgb) // convert HSV (16bit hue) to RGB } region = h / 10923; // 65536 / 6 = 10923 remainder = (h - (region * 10923)) * 6; - p = (v * (256 - s)) >> 8; + p = (v * (255 - s)) >> 8; q = (v * (255 - ((s * remainder) >> 16))) >> 8; t = (v * (255 - ((s * (65535 - remainder)) >> 16))) >> 8; switch (region) { From 8180f2c7422557e4753d97a2d06cfda57a979f1e Mon Sep 17 00:00:00 2001 From: Christian Schwinne Date: Fri, 27 Sep 2024 13:46:01 +0200 Subject: [PATCH 037/234] Bump build tool dependencies --- package-lock.json | 119 ++++++++++++++++------------------------------ package.json | 2 +- requirements.txt | 34 ++++++------- 3 files changed, 56 insertions(+), 99 deletions(-) diff --git a/package-lock.json b/package-lock.json index ce2e7a464..415d88151 100644 --- a/package-lock.json +++ b/package-lock.json @@ -54,9 +54,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", @@ -67,15 +67,10 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "bin": { "acorn": "bin/acorn" }, @@ -190,9 +185,9 @@ } }, "node_modules/aws4": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", - "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==" + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", + "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==" }, "node_modules/balanced-match": { "version": "1.0.2", @@ -233,11 +228,11 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -701,9 +696,9 @@ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -1281,17 +1276,6 @@ "node": ">=0.10.0" } }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -1375,9 +1359,9 @@ } }, "node_modules/nodemon": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.0.tgz", - "integrity": "sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.7.tgz", + "integrity": "sha512-hLj7fuMow6f0lbB0cD14Lz2xNjwsyruH251Pk4t/yIitCFJbmY1myuLlHm/q06aST4jg6EgAh74PIBBrRqpVAQ==", "dependencies": { "chokidar": "^3.5.2", "debug": "^4", @@ -1402,11 +1386,11 @@ } }, "node_modules/nodemon/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -1418,9 +1402,9 @@ } }, "node_modules/nodemon/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/nodemon/node_modules/supports-color": { "version": "5.5.0", @@ -1433,20 +1417,6 @@ "node": ">=4" } }, - "node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "*" - } - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -1507,6 +1477,7 @@ "version": "0.1.5", "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "deprecated": "This package is no longer supported.", "dependencies": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" @@ -1620,6 +1591,7 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", "engines": { "node": ">=0.6.0", "teleport": ">=0.2.0" @@ -1826,12 +1798,9 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -1993,9 +1962,9 @@ } }, "node_modules/terser": { - "version": "5.29.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.2.tgz", - "integrity": "sha512-ZiGkhUBIM+7LwkNjXYJq8svgkd+QK3UUr0wJqY4MieaezBSAIPgbSPZyIx0idM6XWK5CMzSWa8MJIzmRcB8Caw==", + "version": "5.34.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.34.0.tgz", + "integrity": "sha512-y5NUX+U9HhVsK/zihZwoq4r9dICLyV2jXGOriDAVOeKhq3LKVjgJbGO90FisozXLlJfvjHqgckGmJFBb9KYoWQ==", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -2042,12 +2011,9 @@ } }, "node_modules/touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "dependencies": { - "nopt": "~1.0.10" - }, + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", "bin": { "nodetouch": "bin/nodetouch.js" } @@ -2065,9 +2031,9 @@ } }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" }, "node_modules/tunnel-agent": { "version": "0.6.0", @@ -2229,11 +2195,6 @@ "node": ">=0.10.0" } }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/yargs": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", diff --git a/package.json b/package.json index e47a46b26..721455bff 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,6 @@ "clean-css": "^5.3.3", "html-minifier-terser": "^7.2.0", "inliner": "^1.13.1", - "nodemon": "^3.0.2" + "nodemon": "^3.1.7" } } diff --git a/requirements.txt b/requirements.txt index c4ce9445f..666122aa2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,19 +4,17 @@ # # pip-compile # -aiofiles==22.1.0 - # via platformio ajsonrpc==1.2.0 # via platformio -anyio==3.6.2 +anyio==4.6.0 # via starlette -bottle==0.12.25 +bottle==0.13.1 # via platformio -certifi==2023.7.22 +certifi==2024.8.30 # via requests -charset-normalizer==3.1.0 +charset-normalizer==3.3.2 # via requests -click==8.1.3 +click==8.1.7 # via # platformio # uvicorn @@ -28,35 +26,33 @@ h11==0.14.0 # via # uvicorn # wsproto -idna==3.7 +idna==3.10 # via # anyio # requests -marshmallow==3.19.0 +marshmallow==3.22.0 # via platformio -packaging==23.1 +packaging==24.1 # via marshmallow -platformio==6.1.14 +platformio==6.1.16 # via -r requirements.in -pyelftools==0.29 +pyelftools==0.31 # via platformio pyserial==3.5 # via platformio -requests==2.32.0 +requests==2.32.3 # via platformio semantic-version==2.10.0 # via platformio -sniffio==1.3.0 +sniffio==1.3.1 # via anyio -starlette==0.23.1 +starlette==0.39.1 # via platformio tabulate==0.9.0 # via platformio -typing-extensions==4.11.0 - # via starlette -urllib3==1.26.19 +urllib3==2.2.3 # via requests -uvicorn==0.20.0 +uvicorn==0.30.6 # via platformio wsproto==1.2.0 # via platformio From 9a4b56db6e6a8fa06bbcafdb3334ab4ce4414c18 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Fri, 27 Sep 2024 21:05:28 -0400 Subject: [PATCH 038/234] Fix incorrect F-strings A merge issue with end-oappend: some strings did not get correctly converted from SET_F() to F(), which can cause crashes. --- wled00/xml.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 68a26036b..424842a1d 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -91,14 +91,14 @@ void appendGPIOinfo(Print& settingsScript) { settingsScript.print(F("];")); // add reserved (unusable) pins - settingsScript.print(SET_F("d.rsvd=[")); + settingsScript.print(F("d.rsvd=[")); for (unsigned i = 0; i < WLED_NUM_PINS; i++) { if (!PinManager::isPinOk(i, false)) { // include readonly pins settingsScript.print(i); settingsScript.print(","); } } #ifdef WLED_ENABLE_DMX - settingsScript.print(SET_F("2,")); // DMX hardcoded pin + settingsScript.print(F("2,")); // DMX hardcoded pin #endif #if defined(WLED_DEBUG) && !defined(WLED_DEBUG_HOST) settingsScript.printf_P(PSTR(",%d"),hardwareTX); // debug output (TX) pin @@ -113,36 +113,36 @@ void appendGPIOinfo(Print& settingsScript) { switch (ethernetBoards[ethernetType].eth_clk_mode) { case ETH_CLOCK_GPIO0_IN: case ETH_CLOCK_GPIO0_OUT: - settingsScript.print(SET_F("0")); + settingsScript.print(F("0")); break; case ETH_CLOCK_GPIO16_OUT: - settingsScript.print(SET_F("16")); + settingsScript.print(F("16")); break; case ETH_CLOCK_GPIO17_OUT: - settingsScript.print(SET_F("17")); + settingsScript.print(F("17")); break; } } #endif - settingsScript.print(SET_F("];")); // rsvd + settingsScript.print(F("];")); // rsvd // add info for read-only GPIO - settingsScript.print(SET_F("d.ro_gpio=[")); + settingsScript.print(F("d.ro_gpio=[")); bool firstPin = true; for (unsigned i = 0; i < WLED_NUM_PINS; i++) { if (PinManager::isReadOnlyPin(i)) { // No comma before the first pin - if (!firstPin) settingsScript.print(SET_F(",")); + if (!firstPin) settingsScript.print(F(",")); settingsScript.print(i); firstPin = false; } } - settingsScript.print(SET_F("];")); + settingsScript.print(F("];")); // add info about max. # of pins - settingsScript.print(SET_F("d.max_gpio=")); + settingsScript.print(F("d.max_gpio=")); settingsScript.print(WLED_NUM_PINS); - settingsScript.print(SET_F(";")); + settingsScript.print(F(";")); } //get values for settings form in javascript @@ -263,7 +263,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) appendGPIOinfo(settingsScript); - settingsScript.print(SET_F("d.ledTypes=")); settingsScript.print(BusManager::getLEDTypesJSONString().c_str()); settingsScript.print(";"); + settingsScript.print(F("d.ledTypes=")); settingsScript.print(BusManager::getLEDTypesJSONString().c_str()); settingsScript.print(";"); // set limits settingsScript.printf_P(PSTR("bLimits(%d,%d,%d,%d,%d,%d,%d,%d);"), @@ -501,7 +501,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) #endif printSetFormValue(settingsScript,PSTR("BD"),serialBaud); #ifndef WLED_ENABLE_ADALIGHT - settingsScript.print(SET_F("toggle('Serial);")); + settingsScript.print(F("toggle('Serial);")); #endif } From 7c0fe1285aa21e20b16c1185e93fc5e65cd32b3c Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 28 Sep 2024 15:26:14 +0200 Subject: [PATCH 039/234] updated setPixelColor() and getPixelColor() functions uint16_t to unsigned to make it consisten throughout the hand-down. colorFromPaletteWLED now returns uint32_t which saves the conversion to CRGB and back to uint32_t (in most uses at least). also added (preliminary) CRGBW struct. I tried to use it in place of uint32_t colors but it adds a lot of overhead when passing the struct so reverted to uint32_t in most places. updated a few FX to use the CRGBW struct and also cleaned some code to improve flash useage. --- wled00/FX.cpp | 92 ++++++++++++++++++------------------------ wled00/FX.h | 6 +-- wled00/FX_2Dfcn.cpp | 2 +- wled00/FX_fcn.cpp | 7 ++-- wled00/bus_manager.cpp | 20 ++++----- wled00/bus_manager.h | 24 +++++------ wled00/colors.cpp | 4 +- wled00/fcn_declare.h | 60 ++++++++++++++++++++++++++- 8 files changed, 129 insertions(+), 86 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index ad843f0f9..3df91547d 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -1937,7 +1937,7 @@ uint16_t mode_juggle(void) { for (int i = 0; i < 8; i++) { int index = 0 + beatsin88((16 + SEGMENT.speed)*(i + 7), 0, SEGLEN -1); fastled_col = CRGB(SEGMENT.getPixelColor(index)); - fastled_col |= (SEGMENT.palette==0)?CHSV(dothue, 220, 255):ColorFromPalette(SEGPALETTE, dothue, 255); + fastled_col |= (SEGMENT.palette==0)?CHSV(dothue, 220, 255):CRGB(ColorFromPalette(SEGPALETTE, dothue, 255)); SEGMENT.setPixelColor(index, fastled_col); dothue += 32; } @@ -2282,33 +2282,33 @@ uint16_t mode_colortwinkle() { unsigned dataSize = (SEGLEN+7) >> 3; //1 bit per LED if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed - CRGB fastled_col, prev; + CRGBW col, prev; fract8 fadeUpAmount = strip.getBrightness()>28 ? 8 + (SEGMENT.speed>>2) : 68-strip.getBrightness(); fract8 fadeDownAmount = strip.getBrightness()>28 ? 8 + (SEGMENT.speed>>3) : 68-strip.getBrightness(); for (int i = 0; i < SEGLEN; i++) { - fastled_col = SEGMENT.getPixelColor(i); - prev = fastled_col; + CRGBW cur = SEGMENT.getPixelColor(i); + prev = cur; unsigned index = i >> 3; unsigned bitNum = i & 0x07; bool fadeUp = bitRead(SEGENV.data[index], bitNum); if (fadeUp) { - CRGB incrementalColor = fastled_col; - incrementalColor.nscale8_video(fadeUpAmount); - fastled_col += incrementalColor; + CRGBW incrementalColor = color_fade(col, fadeUpAmount, true); + col = color_add(cur, incrementalColor); - if (fastled_col.red == 255 || fastled_col.green == 255 || fastled_col.blue == 255) { + if (col.r == 255 || col.g == 255 || col.b == 255) { bitWrite(SEGENV.data[index], bitNum, false); } - SEGMENT.setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); - if (SEGMENT.getPixelColor(i) == RGBW32(prev.r, prev.g, prev.b, 0)) { //fix "stuck" pixels - fastled_col += fastled_col; - SEGMENT.setPixelColor(i, fastled_col); + if (cur == prev) { //fix "stuck" pixels + color_add(col, col); + SEGMENT.setPixelColor(i, col); } - } else { - fastled_col.nscale8(255 - fadeDownAmount); - SEGMENT.setPixelColor(i, fastled_col); + else SEGMENT.setPixelColor(i, col); + } + else { + col = color_fade(cur, 255 - fadeDownAmount); + SEGMENT.setPixelColor(i, col); } } @@ -2317,11 +2317,10 @@ uint16_t mode_colortwinkle() { for (unsigned times = 0; times < 5; times++) { //attempt to spawn a new pixel 5 times int i = random16(SEGLEN); if (SEGMENT.getPixelColor(i) == 0) { - fastled_col = ColorFromPalette(SEGPALETTE, random8(), 64, NOBLEND); unsigned index = i >> 3; unsigned bitNum = i & 0x07; bitWrite(SEGENV.data[index], bitNum, true); - SEGMENT.setPixelColor(i, fastled_col); + SEGMENT.setPixelColor(i, ColorFromPalette(SEGPALETTE, random8(), 64, NOBLEND)); break; //only spawn 1 new pixel per frame per 50 LEDs } } @@ -2378,8 +2377,7 @@ uint16_t mode_meteor() { index = map(i,0,SEGLEN,0,max); bri = trail[i]; } - uint32_t col = SEGMENT.color_from_palette(index, false, false, idx, bri); // full brightness for Fire - SEGMENT.setPixelColor(i, col); + SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, false, idx, bri)); // full brightness for Fire } } @@ -2392,8 +2390,7 @@ uint16_t mode_meteor() { i = map(index,0,SEGLEN,0,max); idx = 0; } - uint32_t col = SEGMENT.color_from_palette(i, false, false, idx, 255); // full brightness - SEGMENT.setPixelColor(index, col); + SEGMENT.setPixelColor(index, SEGMENT.color_from_palette(i, false, false, idx, 255)); // full brightness } return FRAMETIME; @@ -2419,8 +2416,7 @@ uint16_t mode_meteor_smooth() { if (/*trail[i] != 0 &&*/ random8() <= 255 - SEGMENT.intensity) { int change = trail[i] + 4 - random8(24); //change each time between -20 and +4 trail[i] = constrain(change, 0, max); - uint32_t col = SEGMENT.check1 ? SEGMENT.color_from_palette(i, true, false, 0, trail[i]) : SEGMENT.color_from_palette(trail[i], false, true, 255); - SEGMENT.setPixelColor(i, col); + SEGMENT.setPixelColor(i, SEGMENT.check1 ? SEGMENT.color_from_palette(i, true, false, 0, trail[i]) : SEGMENT.color_from_palette(trail[i], false, true, 255)); } } @@ -2431,8 +2427,7 @@ uint16_t mode_meteor_smooth() { index -= SEGLEN; } trail[index] = max; - uint32_t col = SEGMENT.check1 ? SEGMENT.color_from_palette(index, true, false, 0, trail[index]) : SEGMENT.color_from_palette(trail[index], false, true, 255); - SEGMENT.setPixelColor(index, col); + SEGMENT.setPixelColor(index, SEGMENT.check1 ? SEGMENT.color_from_palette(index, true, false, 0, trail[index]) : SEGMENT.color_from_palette(trail[index], false, true, 255)); } SEGENV.step += SEGMENT.speed +1; @@ -2680,7 +2675,7 @@ static uint16_t twinklefox_base(bool cat) if (deltabright >= 32 || (!bg)) { // If the new pixel is significantly brighter than the background color, // use the new color. - SEGMENT.setPixelColor(i, c.red, c.green, c.blue); + SEGMENT.setPixelColor(i, c); } else if (deltabright > 0) { // If the new pixel is just slightly brighter than the background color, // mix a blend of the new color and the background color @@ -2688,7 +2683,7 @@ static uint16_t twinklefox_base(bool cat) } else { // if the new pixel is not at all brighter than the background color, // just use the background color. - SEGMENT.setPixelColor(i, bg.r, bg.g, bg.b); + SEGMENT.setPixelColor(i, bg); } } return FRAMETIME; @@ -3532,7 +3527,7 @@ uint16_t mode_starburst(void) { if (start == end) end++; if (end > SEGLEN) end = SEGLEN; for (int p = start; p < end; p++) { - SEGMENT.setPixelColor(p, c.r, c.g, c.b); + SEGMENT.setPixelColor(p, c); } } } @@ -3650,17 +3645,17 @@ uint16_t mode_exploding_fireworks(void) if (SEGMENT.is2D() && !(sparks[i].posX >= 0 && sparks[i].posX < cols)) continue; unsigned prog = sparks[i].col; uint32_t spColor = (SEGMENT.palette) ? SEGMENT.color_wheel(sparks[i].colIndex) : SEGCOLOR(0); - CRGB c = CRGB::Black; //HeatColor(sparks[i].col); + CRGBW c = BLACK; //HeatColor(sparks[i].col); if (prog > 300) { //fade from white to spark color - c = CRGB(color_blend(spColor, WHITE, (prog - 300)*5)); + c = color_blend(spColor, WHITE, (prog - 300)*5); } else if (prog > 45) { //fade from spark color to black - c = CRGB(color_blend(BLACK, spColor, prog - 45)); + c = color_blend(BLACK, spColor, prog - 45); unsigned cooling = (300 - prog) >> 5; c.g = qsub8(c.g, cooling); c.b = qsub8(c.b, cooling * 2); } - if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(int(sparks[i].posX), rows - int(sparks[i].pos) - 1, c.red, c.green, c.blue); - else SEGMENT.setPixelColor(int(sparks[i].posX) ? rows - int(sparks[i].pos) - 1 : int(sparks[i].pos), c.red, c.green, c.blue); + if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(int(sparks[i].posX), rows - int(sparks[i].pos) - 1, c); + else SEGMENT.setPixelColor(int(sparks[i].posX) ? rows - int(sparks[i].pos) - 1 : int(sparks[i].pos), c); } } if (SEGMENT.check3) SEGMENT.blur(16); @@ -4006,7 +4001,7 @@ static CRGB pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, u ci += (cs * i); unsigned sindex16 = sin16(ci) + 32768; unsigned sindex8 = scale16(sindex16, 240); - return ColorFromPalette(p, sindex8, bri, LINEARBLEND); + return CRGB(ColorFromPalette(p, sindex8, bri, LINEARBLEND)); } uint16_t mode_pacifica() @@ -4077,7 +4072,7 @@ uint16_t mode_pacifica() c.green = scale8(c.green, 200); c |= CRGB( 2, 5, 7); - SEGMENT.setPixelColor(i, c.red, c.green, c.blue); + SEGMENT.setPixelColor(i, c); } strip.now = nowOld; @@ -4119,13 +4114,10 @@ uint16_t mode_sunrise() { for (int i = 0; i <= SEGLEN/2; i++) { - //default palette is Fire - uint32_t c = SEGMENT.color_from_palette(0, false, true, 255); //background - + //default palette is Fire unsigned wave = triwave16((i * stage) / SEGLEN); - wave = (wave >> 8) + ((wave * SEGMENT.intensity) >> 15); - + uint32_t c; if (wave > 240) { //clipped, full white sun c = SEGMENT.color_from_palette( 240, false, true, 255); } else { //transition @@ -4217,8 +4209,6 @@ uint16_t mode_noisepal(void) { // Slow noise palettes[1] = CRGBPalette16(CHSV(baseI+random8(64), 255, random8(128,255)), CHSV(baseI+128, 255, random8(128,255)), CHSV(baseI+random8(92), 192, random8(128,255)), CHSV(baseI+random8(92), 255, random8(128,255))); } - CRGB color; - //EVERY_N_MILLIS(10) { //(don't have to time this, effect function is only called every 24ms) nblendPaletteTowardPalette(palettes[0], palettes[1], 48); // Blend towards the target palette over 48 iterations. @@ -4226,8 +4216,7 @@ uint16_t mode_noisepal(void) { // Slow noise for (int i = 0; i < SEGLEN; i++) { unsigned index = inoise8(i*scale, SEGENV.aux0+i*scale); // Get a value from the noise function. I'm using both x and y axis. - color = ColorFromPalette(palettes[0], index, 255, LINEARBLEND); // Use the my own palette. - SEGMENT.setPixelColor(i, color.red, color.green, color.blue); + SEGMENT.setPixelColor(i, ColorFromPalette(palettes[0], index, 255, LINEARBLEND)); // Use my own palette. } SEGENV.aux0 += beatsin8(10,1,4); // Moving along the distance. Vary it a bit with a sine wave. @@ -4314,9 +4303,8 @@ uint16_t mode_chunchun(void) counter -= span; unsigned megumin = sin16(counter) + 0x8000; unsigned bird = uint32_t(megumin * SEGLEN) >> 16; - uint32_t c = SEGMENT.color_from_palette((i * 255)/ numBirds, false, false, 0); // no palette wrapping bird = constrain(bird, 0U, SEGLEN-1U); - SEGMENT.setPixelColor(bird, c); + SEGMENT.setPixelColor(bird, SEGMENT.color_from_palette((i * 255)/ numBirds, false, false, 0)); // no palette wrapping } return FRAMETIME; } @@ -4934,7 +4922,7 @@ uint16_t mode_2DColoredBursts() { // By: ldirko https://editor.so byte x2 = beatsin8(1 + SEGMENT.speed/16, 0, (cols - 1)); byte y1 = beatsin8(5 + SEGMENT.speed/16, 0, (rows - 1), 0, i * 24); byte y2 = beatsin8(3 + SEGMENT.speed/16, 0, (rows - 1), 0, i * 48 + 64); - CRGB color = ColorFromPalette(SEGPALETTE, i * 255 / numLines + (SEGENV.aux0&0xFF), 255, LINEARBLEND); + uint32_t color = ColorFromPalette(SEGPALETTE, i * 255 / numLines + (SEGENV.aux0&0xFF), 255, LINEARBLEND); byte xsteps = abs8(x1 - y1) + 1; byte ysteps = abs8(x2 - y2) + 1; @@ -5831,7 +5819,7 @@ uint16_t mode_2Dspaceships(void) { //// Space ships by stepko (c)05.02.21 [ht for (size_t i = 0; i < 8; i++) { int x = beatsin8(12 + i, 2, cols - 3); int y = beatsin8(15 + i, 2, rows - 3); - CRGB color = ColorFromPalette(SEGPALETTE, beatsin8(12 + i, 0, 255), 255); + uint32_t color = ColorFromPalette(SEGPALETTE, beatsin8(12 + i, 0, 255), 255); SEGMENT.addPixelColorXY(x, y, color); if (cols > 24 || rows > 24) { SEGMENT.addPixelColorXY(x+1, y, color); @@ -6725,8 +6713,7 @@ uint16_t mode_noisefire(void) { // Noisefire. By Andrew Tuline. index = (255 - i*256/SEGLEN) * index/(256-SEGMENT.intensity); // Now we need to scale index so that it gets blacker as we get close to one of the ends. // This is a simple y=mx+b equation that's been scaled. index/128 is another scaling. - CRGB color = ColorFromPalette(myPal, index, volumeSmth*2, LINEARBLEND); // Use the my own palette. - SEGMENT.setPixelColor(i, color); + SEGMENT.setPixelColor(i, ColorFromPalette(myPal, index, volumeSmth*2, LINEARBLEND)); // Use my own palette. } return FRAMETIME; @@ -7532,7 +7519,7 @@ uint16_t mode_2DAkemi(void) { unsigned band = x * cols/8; band = constrain(band, 0, 15); int barHeight = map(fftResult[band], 0, 255, 0, 17*rows/32); - CRGB color = CRGB(SEGMENT.color_from_palette((band * 35), false, PALETTE_SOLID_WRAP, 0)); + uint32_t color = SEGMENT.color_from_palette((band * 35), false, PALETTE_SOLID_WRAP, 0); for (int y=0; y < barHeight; y++) { SEGMENT.setPixelColorXY(x, rows/2-y, color); @@ -7760,8 +7747,7 @@ uint16_t mode_2Doctopus() { //CRGB c = CHSV(SEGENV.step / 2 - radius, 255, sin8(sin8((angle * 4 - radius) / 4 + SEGENV.step) + radius - SEGENV.step * 2 + angle * (SEGMENT.custom3/3+1))); unsigned intensity = sin8(sin8((angle * 4 - radius) / 4 + SEGENV.step/2) + radius - SEGENV.step + angle * (SEGMENT.custom3/4+1)); intensity = map((intensity*intensity) & 0xFFFF, 0, 65535, 0, 255); // add a bit of non-linearity for cleaner display - CRGB c = ColorFromPalette(SEGPALETTE, SEGENV.step / 2 - radius, intensity); - SEGMENT.setPixelColorXY(x, y, c); + SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, SEGENV.step / 2 - radius, intensity)); } } return FRAMETIME; diff --git a/wled00/FX.h b/wled00/FX.h index 989dfbe33..825c722e7 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -851,10 +851,8 @@ class WS2812FX { // 96 bytes return index; }; - uint32_t - now, - timebase, - getPixelColor(uint16_t) const; + uint32_t now, timebase; + uint32_t getPixelColor(unsigned) const; inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call inline uint32_t segColor(uint8_t i) const { return _colors_t[i]; } // returns currently valid color (for slot i) AKA SEGCOLOR(); may be blended between two colors while in transition diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index ca28a9586..41fd67319 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -671,7 +671,7 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, case 60: bits = pgm_read_byte_near(&console_font_5x12[(chr * h) + i]); break; // 5x12 font default: return; } - col = ColorFromPalette(grad, (i+1)*255/h, 255, NOBLEND); + uint32_t col = ColorFromPaletteWLED(grad, (i+1)*255/h, 255, NOBLEND); for (int j = 0; j 1) paletteIndex = (i*255)/(virtualLength() -1); // paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined) if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end" - CRGB fastled_col = ColorFromPalette(_currentPalette, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global + CRGBW palcol = ColorFromPalette(_currentPalette, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global + palcol.w = gamma8(W(color)); - return RGBW32(fastled_col.r, fastled_col.g, fastled_col.b, gamma8(W(color))); + return palcol.color32; } @@ -1419,7 +1420,7 @@ void IRAM_ATTR WS2812FX::setPixelColor(unsigned i, uint32_t col) { BusManager::setPixelColor(i, col); } -uint32_t IRAM_ATTR WS2812FX::getPixelColor(uint16_t i) const { +uint32_t IRAM_ATTR WS2812FX::getPixelColor(unsigned i) const { i = getMappedPixelIndex(i); if (i >= _length) return 0; return BusManager::getPixelColor(i); diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 5b948b9c4..404c33449 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -306,7 +306,7 @@ void BusDigital::setStatusPixel(uint32_t c) { } } -void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) { +void IRAM_ATTR BusDigital::setPixelColor(unsigned pix, uint32_t c) { if (!_valid) return; uint8_t cctWW = 0, cctCW = 0; if (hasWhite()) c = autoWhiteCalc(c); @@ -342,7 +342,7 @@ void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) { } // returns original color if global buffering is enabled, else returns lossly restored color from bus -uint32_t IRAM_ATTR BusDigital::getPixelColor(uint16_t pix) const { +uint32_t IRAM_ATTR BusDigital::getPixelColor(unsigned pix) const { if (!_valid) return 0; if (_data) { size_t offset = pix * getNumberOfChannels(); @@ -501,7 +501,7 @@ BusPwm::BusPwm(BusConfig &bc) DEBUG_PRINTF_P(PSTR("%successfully inited PWM strip with type %u, frequency %u, bit depth %u and pins %u,%u,%u,%u,%u\n"), _valid?"S":"Uns", bc.type, _frequency, _depth, _pins[0], _pins[1], _pins[2], _pins[3], _pins[4]); } -void BusPwm::setPixelColor(uint16_t pix, uint32_t c) { +void BusPwm::setPixelColor(unsigned pix, uint32_t c) { if (pix != 0 || !_valid) return; //only react to first pixel if (_type != TYPE_ANALOG_3CH) c = autoWhiteCalc(c); if (Bus::_cct >= 1900 && (_type == TYPE_ANALOG_3CH || _type == TYPE_ANALOG_4CH)) { @@ -538,7 +538,7 @@ void BusPwm::setPixelColor(uint16_t pix, uint32_t c) { } //does no index check -uint32_t BusPwm::getPixelColor(uint16_t pix) const { +uint32_t BusPwm::getPixelColor(unsigned pix) const { if (!_valid) return 0; // TODO getting the reverse from CCT is involved (a quick approximation when CCT blending is ste to 0 implemented) switch (_type) { @@ -674,7 +674,7 @@ BusOnOff::BusOnOff(BusConfig &bc) DEBUG_PRINTF_P(PSTR("%successfully inited On/Off strip with pin %u\n"), _valid?"S":"Uns", _pin); } -void BusOnOff::setPixelColor(uint16_t pix, uint32_t c) { +void BusOnOff::setPixelColor(unsigned pix, uint32_t c) { if (pix != 0 || !_valid) return; //only react to first pixel c = autoWhiteCalc(c); uint8_t r = R(c); @@ -684,7 +684,7 @@ void BusOnOff::setPixelColor(uint16_t pix, uint32_t c) { _data[0] = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0; } -uint32_t BusOnOff::getPixelColor(uint16_t pix) const { +uint32_t BusOnOff::getPixelColor(unsigned pix) const { if (!_valid) return 0; return RGBW32(_data[0], _data[0], _data[0], _data[0]); } @@ -734,7 +734,7 @@ BusNetwork::BusNetwork(BusConfig &bc) DEBUG_PRINTF_P(PSTR("%successfully inited virtual strip with type %u and IP %u.%u.%u.%u\n"), _valid?"S":"Uns", bc.type, bc.pins[0], bc.pins[1], bc.pins[2], bc.pins[3]); } -void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) { +void BusNetwork::setPixelColor(unsigned pix, uint32_t c) { if (!_valid || pix >= _len) return; if (_hasWhite) c = autoWhiteCalc(c); if (Bus::_cct >= 1900) c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT @@ -745,7 +745,7 @@ void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) { if (_hasWhite) _data[offset+3] = W(c); } -uint32_t BusNetwork::getPixelColor(uint16_t pix) const { +uint32_t BusNetwork::getPixelColor(unsigned pix) const { if (!_valid || pix >= _len) return 0; unsigned offset = pix * _UDPchannels; return RGBW32(_data[offset], _data[offset+1], _data[offset+2], (hasWhite() ? _data[offset+3] : 0)); @@ -952,7 +952,7 @@ void BusManager::setStatusPixel(uint32_t c) { } } -void IRAM_ATTR BusManager::setPixelColor(uint16_t pix, uint32_t c) { +void IRAM_ATTR BusManager::setPixelColor(unsigned pix, uint32_t c) { for (unsigned i = 0; i < numBusses; i++) { unsigned bstart = busses[i]->getStart(); if (pix < bstart || pix >= bstart + busses[i]->getLength()) continue; @@ -975,7 +975,7 @@ void BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) { Bus::setCCT(cct); } -uint32_t BusManager::getPixelColor(uint16_t pix) { +uint32_t BusManager::getPixelColor(unsigned pix) { for (unsigned i = 0; i < numBusses; i++) { unsigned bstart = busses[i]->getStart(); if (!busses[i]->containsPixel(pix)) continue; diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index e96b9de71..1b324d713 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -82,10 +82,10 @@ class Bus { virtual void show() = 0; virtual bool canShow() const { return true; } virtual void setStatusPixel(uint32_t c) {} - virtual void setPixelColor(uint16_t pix, uint32_t c) = 0; + virtual void setPixelColor(unsigned pix, uint32_t c) = 0; virtual void setBrightness(uint8_t b) { _bri = b; }; virtual void setColorOrder(uint8_t co) {} - virtual uint32_t getPixelColor(uint16_t pix) const { return 0; } + virtual uint32_t getPixelColor(unsigned pix) const { return 0; } virtual uint8_t getPins(uint8_t* pinArray = nullptr) const { return 0; } virtual uint16_t getLength() const { return isOk() ? _len : 0; } virtual uint8_t getColorOrder() const { return COL_ORDER_RGB; } @@ -203,9 +203,9 @@ class BusDigital : public Bus { bool canShow() const override; void setBrightness(uint8_t b) override; void setStatusPixel(uint32_t c) override; - [[gnu::hot]] void setPixelColor(uint16_t pix, uint32_t c) override; + [[gnu::hot]] void setPixelColor(unsigned pix, uint32_t c) override; void setColorOrder(uint8_t colorOrder) override; - [[gnu::hot]] uint32_t getPixelColor(uint16_t pix) const override; + [[gnu::hot]] uint32_t getPixelColor(unsigned pix) const override; uint8_t getColorOrder() const override { return _colorOrder; } uint8_t getPins(uint8_t* pinArray = nullptr) const override; uint8_t skippedLeds() const override { return _skip; } @@ -251,8 +251,8 @@ class BusPwm : public Bus { BusPwm(BusConfig &bc); ~BusPwm() { cleanup(); } - void setPixelColor(uint16_t pix, uint32_t c) override; - uint32_t getPixelColor(uint16_t pix) const override; //does no index check + void setPixelColor(unsigned pix, uint32_t c) override; + uint32_t getPixelColor(unsigned pix) const override; //does no index check uint8_t getPins(uint8_t* pinArray = nullptr) const override; uint16_t getFrequency() const override { return _frequency; } void show() override; @@ -278,8 +278,8 @@ class BusOnOff : public Bus { BusOnOff(BusConfig &bc); ~BusOnOff() { cleanup(); } - void setPixelColor(uint16_t pix, uint32_t c) override; - uint32_t getPixelColor(uint16_t pix) const override; + void setPixelColor(unsigned pix, uint32_t c) override; + uint32_t getPixelColor(unsigned pix) const override; uint8_t getPins(uint8_t* pinArray) const override; void show() override; void cleanup() { PinManager::deallocatePin(_pin, PinOwner::BusOnOff); } @@ -298,8 +298,8 @@ class BusNetwork : public Bus { ~BusNetwork() { cleanup(); } bool canShow() const override { return !_broadcastLock; } // this should be a return value from UDP routine if it is still sending data out - void setPixelColor(uint16_t pix, uint32_t c) override; - uint32_t getPixelColor(uint16_t pix) const override; + void setPixelColor(unsigned pix, uint32_t c) override; + uint32_t getPixelColor(unsigned pix) const override; uint8_t getPins(uint8_t* pinArray = nullptr) const override; void show() override; void cleanup(); @@ -384,13 +384,13 @@ class BusManager { static void show(); static bool canAllShow(); static void setStatusPixel(uint32_t c); - [[gnu::hot]] static void setPixelColor(uint16_t pix, uint32_t c); + [[gnu::hot]] static void setPixelColor(unsigned pix, uint32_t c); static void setBrightness(uint8_t b); // for setSegmentCCT(), cct can only be in [-1,255] range; allowWBCorrection will convert it to K // WARNING: setSegmentCCT() is a misleading name!!! much better would be setGlobalCCT() or just setCCT() static void setSegmentCCT(int16_t cct, bool allowWBCorrection = false); static inline void setMilliampsMax(uint16_t max) { _milliAmpsMax = max;} - static uint32_t getPixelColor(uint16_t pix); + [[gnu::hot]] static uint32_t getPixelColor(unsigned pix); static inline int16_t getSegmentCCT() { return Bus::getCCT(); } static Bus* getBus(uint8_t busNr); diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 1b6a6f8d9..1c4844371 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -96,7 +96,7 @@ uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) } // 1:1 replacement of fastled function optimized for ESP, slightly faster, more accurate and uses less flash (~ -200bytes) -CRGB ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brightness, TBlendType blendType) +uint32_t ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brightness, TBlendType blendType) { if (blendType == LINEARBLEND_NOWRAP) { index = (index*240) >> 8; // Blend range is affected by lo4 blend of values, remap to avoid wrapping @@ -121,7 +121,7 @@ CRGB ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brig green1 = (green1 * scale) >> 8; blue1 = (blue1 * scale) >> 8; } - return CRGB((uint8_t)red1, (uint8_t)green1, (uint8_t)blue1); + return RGBW32(red1,green1,blue1,0); } void setRandomColor(byte* rgb) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index ff96cf749..6568304f8 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -68,6 +68,64 @@ typedef struct WiFiConfig { //colors.cpp #define ColorFromPalette ColorFromPaletteWLED // override fastled version +// CRGBW can be used to manipulate 32bit colors faster. However: if it is passed to functions, it adds overhead compared to a uint32_t color +// use with caution and pay attention to flash size. Usually converting a uint32_t to CRGBW to extract r, g, b, w values is slower than using bitshifts +// it can be useful to avoid back and forth conversions between uint32_t and fastled CRGB +struct CRGBW { + union { + uint32_t color32; // Access as a 32-bit value (0xWWRRGGBB) + uint8_t raw[4]; // Access as an array in the order B, G, R, W + struct { + uint8_t b; + uint8_t g; + uint8_t r; + uint8_t w; + }; + }; + + // Default constructor + inline CRGBW() __attribute__((always_inline)) = default; + + // Constructor from a 32-bit color (0xWWRRGGBB) + constexpr CRGBW(uint32_t color) __attribute__((always_inline)) : color32(color) {} + + // Constructor with r, g, b, w values + constexpr CRGBW(uint8_t red, uint8_t green, uint8_t blue, uint8_t white = 0) __attribute__((always_inline)) : r(red), g(green), b(blue), w(white) {} + + // Constructor from CRGB + constexpr CRGBW(CRGB rgb) __attribute__((always_inline)) : r(rgb.r), g(rgb.g), b(rgb.b), w(0) {} + + // Access as an array + inline const uint8_t& operator[] (uint8_t x) const __attribute__((always_inline)) { return raw[x]; } + + // Assignment from 32-bit color + inline CRGBW& operator=(uint32_t color) __attribute__((always_inline)) { color32 = color; return *this; } + + // Assignment from r, g, b, w + inline CRGBW& operator=(const CRGB& rgb) __attribute__((always_inline)) { r = rgb.r; g = rgb.g; b = rgb.b; w = 0; return *this; } + + // Conversion operator to uint32_t + inline operator uint32_t() const __attribute__((always_inline)) { + return color32; + } + /* + // Conversion operator to CRGB + inline operator CRGB() const __attribute__((always_inline)) { + return CRGB(r, g, b); + } + + CRGBW& scale32 (uint8_t scaledown) // 32bit math + { + if (color32 == 0) return *this; // 2 extra instructions, worth it if called a lot on black (which probably is true) adding check if scaledown is zero adds much more overhead as its 8bit + uint32_t scale = scaledown + 1; + uint32_t rb = (((color32 & 0x00FF00FF) * scale) >> 8) & 0x00FF00FF; // scale red and blue + uint32_t wg = (((color32 & 0xFF00FF00) >> 8) * scale) & 0xFF00FF00; // scale white and green + color32 = rb | wg; + return *this; + }*/ + +}; + struct CHSV32 { // 32bit HSV color with 16bit hue for more accurate conversions union { struct { @@ -106,7 +164,7 @@ class NeoGammaWLEDMethod { [[gnu::hot]] uint32_t color_blend(uint32_t, uint32_t, uint16_t, bool b16=false); [[gnu::hot]] uint32_t color_add(uint32_t, uint32_t, bool preserveCR = false); [[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); -[[gnu::hot]] CRGB ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND); +[[gnu::hot]] uint32_t ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND); CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette); CRGBPalette16 generateRandomPalette(); inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); } From 202901b09f2a8c6da3a453b0d3ed8c8140ea5557 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 28 Sep 2024 15:38:41 +0200 Subject: [PATCH 040/234] bugfix, ESP32 compiler requires the color order to be identical --- wled00/fcn_declare.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 6568304f8..704fae852 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -74,13 +74,13 @@ typedef struct WiFiConfig { struct CRGBW { union { uint32_t color32; // Access as a 32-bit value (0xWWRRGGBB) - uint8_t raw[4]; // Access as an array in the order B, G, R, W struct { uint8_t b; uint8_t g; uint8_t r; uint8_t w; }; + uint8_t raw[4]; // Access as an array in the order B, G, R, W }; // Default constructor @@ -90,10 +90,10 @@ struct CRGBW { constexpr CRGBW(uint32_t color) __attribute__((always_inline)) : color32(color) {} // Constructor with r, g, b, w values - constexpr CRGBW(uint8_t red, uint8_t green, uint8_t blue, uint8_t white = 0) __attribute__((always_inline)) : r(red), g(green), b(blue), w(white) {} + constexpr CRGBW(uint8_t red, uint8_t green, uint8_t blue, uint8_t white = 0) __attribute__((always_inline)) : b(blue), g(green), r(red), w(white) {} // Constructor from CRGB - constexpr CRGBW(CRGB rgb) __attribute__((always_inline)) : r(rgb.r), g(rgb.g), b(rgb.b), w(0) {} + constexpr CRGBW(CRGB rgb) __attribute__((always_inline)) : b(rgb.b), g(rgb.g), r(rgb.r), w(0) {} // Access as an array inline const uint8_t& operator[] (uint8_t x) const __attribute__((always_inline)) { return raw[x]; } @@ -102,7 +102,7 @@ struct CRGBW { inline CRGBW& operator=(uint32_t color) __attribute__((always_inline)) { color32 = color; return *this; } // Assignment from r, g, b, w - inline CRGBW& operator=(const CRGB& rgb) __attribute__((always_inline)) { r = rgb.r; g = rgb.g; b = rgb.b; w = 0; return *this; } + inline CRGBW& operator=(const CRGB& rgb) __attribute__((always_inline)) { b = rgb.b; g = rgb.g; r = rgb.r; w = 0; return *this; } // Conversion operator to uint32_t inline operator uint32_t() const __attribute__((always_inline)) { From c842994df5d5e9120c069c84cba97ba8c686ab0d Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sat, 28 Sep 2024 18:14:43 +0200 Subject: [PATCH 041/234] Pre-calculate virtual - move SEGCOLOR() to Segment class - add SEG_H, SEG_W macros - try to speed up virtualXxxxx() - compile warning fixes --- wled00/FX.cpp | 347 ++++++++++++++++++++++---------------------- wled00/FX.h | 64 ++++---- wled00/FX_2Dfcn.cpp | 146 ++++++++++--------- wled00/FX_fcn.cpp | 123 +++++++++------- wled00/udp.cpp | 54 +++---- wled00/xml.cpp | 4 +- 6 files changed, 367 insertions(+), 371 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 3df91547d..2ec31014f 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -118,7 +118,7 @@ uint16_t blink(uint32_t color1, uint32_t color2, bool strobe, bool do_palette) { uint32_t color = on ? color1 : color2; if (color == color1 && do_palette) { - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); } } else SEGMENT.fill(color); @@ -300,25 +300,25 @@ uint16_t mode_dynamic(void) { if(SEGENV.call == 0) { //SEGMENT.fill(BLACK); - for (int i = 0; i < SEGLEN; i++) SEGENV.data[i] = random8(); + for (unsigned i = 0; i < SEGLEN; i++) SEGENV.data[i] = random8(); } uint32_t cycleTime = 50 + (255 - SEGMENT.speed)*15; uint32_t it = strip.now / cycleTime; if (it != SEGENV.step && SEGMENT.speed != 0) //new color { - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { if (random8() <= SEGMENT.intensity) SEGENV.data[i] = random8(); // random color index } SEGENV.step = it; } if (SEGMENT.check1) { - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.blendPixelColor(i, SEGMENT.color_wheel(SEGENV.data[i]), 16); } } else { - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_wheel(SEGENV.data[i])); } } @@ -353,7 +353,7 @@ uint16_t mode_breath(void) { } unsigned lum = 30 + var; - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), lum)); } @@ -369,7 +369,7 @@ uint16_t mode_fade(void) { unsigned counter = (strip.now * ((SEGMENT.speed >> 3) +10)); unsigned lum = triwave16(counter) >> 8; - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), lum)); } @@ -452,7 +452,7 @@ uint16_t mode_rainbow_cycle(void) { unsigned counter = (strip.now * ((SEGMENT.speed >> 2) +2)) & 0xFFFF; counter = counter >> 8; - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { //intensity/29 = 0 (1/16) 1 (1/8) 2 (1/4) 3 (1/2) 4 (1) 5 (2) 6 (4) 7 (8) 8 (16) uint8_t index = (i * (16 << (SEGMENT.intensity /29)) / SEGLEN) + counter; SEGMENT.setPixelColor(i, SEGMENT.color_wheel(index)); @@ -472,7 +472,7 @@ static uint16_t running(uint32_t color1, uint32_t color2, bool theatre = false) uint32_t it = strip.now / cycleTime; bool usePalette = color1 == SEGCOLOR(0); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { uint32_t col = color2; if (usePalette) color1 = SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0); if (theatre) { @@ -519,7 +519,7 @@ static uint16_t running_base(bool saw, bool dual=false) { unsigned x_scale = SEGMENT.intensity >> 2; uint32_t counter = (strip.now * SEGMENT.speed) >> 9; - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { unsigned a = i*x_scale - counter; if (saw) { a &= 0xFF; @@ -622,7 +622,7 @@ uint16_t dissolve(uint32_t color) { SEGENV.aux0 = 1; } - for (int j = 0; j <= SEGLEN / 15; j++) { + for (unsigned j = 0; j <= SEGLEN / 15; j++) { if (random8() <= SEGMENT.intensity) { for (size_t times = 0; times < 10; times++) { //attempt to spawn a new pixel 10 times unsigned i = random16(SEGLEN); @@ -684,7 +684,7 @@ static const char _data_FX_MODE_DISSOLVE_RANDOM[] PROGMEM = "Dissolve Rnd@Repeat * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ */ uint16_t mode_sparkle(void) { - if (!SEGMENT.check2) for(int i = 0; i < SEGLEN; i++) { + if (!SEGMENT.check2) for(unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); } uint32_t cycleTime = 10 + (255 - SEGMENT.speed)*2; @@ -706,7 +706,7 @@ static const char _data_FX_MODE_SPARKLE[] PROGMEM = "Sparkle@!,,,,,,Overlay;!,!; * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ */ uint16_t mode_flash_sparkle(void) { - if (!SEGMENT.check2) for (int i = 0; i < SEGLEN; i++) { + if (!SEGMENT.check2) for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); } @@ -727,13 +727,14 @@ static const char _data_FX_MODE_FLASH_SPARKLE[] PROGMEM = "Sparkle Dark@!,!,,,,, * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ */ uint16_t mode_hyper_sparkle(void) { - if (!SEGMENT.check2) for (int i = 0; i < SEGLEN; i++) { + if (!SEGMENT.check2) for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); } if (strip.now - SEGENV.aux0 > SEGENV.step) { if (random8((255-SEGMENT.intensity) >> 4) == 0) { - for (int i = 0; i < max(1, SEGLEN/3); i++) { + int len = max(1, (int)SEGLEN/3); + for (int i = 0; i < len; i++) { SEGMENT.setPixelColor(random16(SEGLEN), SEGCOLOR(1)); } } @@ -749,7 +750,7 @@ static const char _data_FX_MODE_HYPER_SPARKLE[] PROGMEM = "Sparkle+@!,!,,,,,Over * Strobe effect with different strobe count and pause, controlled by speed. */ uint16_t mode_multi_strobe(void) { - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); } @@ -780,7 +781,7 @@ static const char _data_FX_MODE_MULTI_STROBE[] PROGMEM = "Strobe Mega@!,!;!,!;!; */ uint16_t mode_android(void) { - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); } @@ -995,10 +996,10 @@ static const char _data_FX_MODE_COLORFUL[] PROGMEM = "Colorful@!,Saturation;1,2, */ uint16_t mode_traffic_light(void) { if (SEGLEN == 1) return mode_static(); - for (int i=0; i < SEGLEN; i++) + for (unsigned i=0; i < SEGLEN; i++) SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); uint32_t mdelay = 500; - for (int i = 0; i < SEGLEN-2 ; i+=3) + for (unsigned i = 0; i < SEGLEN-2 ; i+=3) { switch (SEGENV.aux0) { @@ -1030,7 +1031,7 @@ uint16_t mode_chase_flash(void) { if (SEGLEN == 1) return mode_static(); unsigned flash_step = SEGENV.call % ((FLASH_COUNT * 2) + 1); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); } @@ -1226,8 +1227,8 @@ static const char _data_FX_MODE_COMET[] PROGMEM = "Lighthouse@!,Fade rate;!,!;!" */ uint16_t mode_fireworks() { if (SEGLEN == 1) return mode_static(); - const uint16_t width = SEGMENT.is2D() ? SEGMENT.virtualWidth() : SEGMENT.virtualLength(); - const uint16_t height = SEGMENT.virtualHeight(); + const uint16_t width = SEGMENT.is2D() ? SEG_W : SEGLEN; + const uint16_t height = SEG_H; if (SEGENV.call == 0) { SEGENV.aux0 = UINT16_MAX; @@ -1268,8 +1269,8 @@ static const char _data_FX_MODE_FIREWORKS[] PROGMEM = "Fireworks@,Frequency;!,!; //Twinkling LEDs running. Inspired by https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/Rain.h uint16_t mode_rain() { if (SEGLEN == 1) return mode_static(); - const unsigned width = SEGMENT.virtualWidth(); - const unsigned height = SEGMENT.virtualHeight(); + const unsigned width = SEG_W; + const unsigned height = SEG_H; SEGENV.step += FRAMETIME; if (SEGENV.call && SEGENV.step > SPEED_FORMULA_L) { SEGENV.step = 1; @@ -1283,7 +1284,7 @@ uint16_t mode_rain() { } else { //shift all leds left uint32_t ctemp = SEGMENT.getPixelColor(0); - for (int i = 0; i < SEGLEN - 1; i++) { + for (unsigned i = 0; i < SEGLEN - 1; i++) { SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); } SEGMENT.setPixelColor(SEGLEN -1, ctemp); // wrap around @@ -1314,7 +1315,7 @@ uint16_t mode_fire_flicker(void) { byte b = (SEGCOLOR(0) ); byte lum = (SEGMENT.palette == 0) ? MAX(w, MAX(r, MAX(g, b))) : 255; lum /= (((256-SEGMENT.intensity)/16)+1); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { byte flicker = random8(lum); if (SEGMENT.palette == 0) { SEGMENT.setPixelColor(i, MAX(r - flicker, 0), MAX(g - flicker, 0), MAX(b - flicker, 0), MAX(w - flicker, 0)); @@ -1343,7 +1344,7 @@ uint16_t gradient_base(bool loading) { int p1 = pp-SEGLEN; int p2 = pp+SEGLEN; - for (int i = 0; i < SEGLEN; i++) { + for (int i = 0; i < (int)SEGLEN; i++) { if (loading) { val = abs(((i>pp) ? p2:pp) - i); } else { @@ -1428,7 +1429,7 @@ typedef struct Flasher { uint16_t mode_fairy() { //set every pixel to a 'random' color from palette (using seed so it doesn't change between frames) uint16_t PRNG16 = 5100 + strip.getCurrSegmentId(); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; //next 'random' number SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(PRNG16 >> 8, false, false, 0)); } @@ -1513,7 +1514,7 @@ uint16_t mode_fairytwinkle() { unsigned riseFallTime = 400 + (255-SEGMENT.speed)*3; unsigned maxDur = riseFallTime/100 + ((255 - SEGMENT.intensity) >> 2) + 13 + ((255 - SEGMENT.intensity) >> 1); - for (int f = 0; f < SEGLEN; f++) { + for (unsigned f = 0; f < SEGLEN; f++) { unsigned stateTime = now16 - flashers[f].stateStart; //random on/off time reached, switch state if (stateTime > flashers[f].stateDur * 100) { @@ -1558,7 +1559,7 @@ uint16_t tricolor_chase(uint32_t color1, uint32_t color2) { unsigned width = (1 + (SEGMENT.intensity>>4)); // value of 1-16 for each colour unsigned index = it % (width*3); - for (int i = 0; i < SEGLEN; i++, index++) { + for (unsigned i = 0; i < SEGLEN; i++, index++) { if (index > (width*3)-1) index = 0; uint32_t color = color1; @@ -1631,7 +1632,7 @@ uint16_t mode_tricolor_wipe(void) { unsigned ledIndex = (prog * SEGLEN * 3) >> 16; unsigned ledOffset = ledIndex; - for (int i = 0; i < SEGLEN; i++) + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 2)); } @@ -1970,8 +1971,8 @@ uint16_t mode_palette() { constexpr float (*cosFunction)(float) = &cos_t; #endif const bool isMatrix = strip.isMatrix; - const int cols = SEGMENT.virtualWidth(); - const int rows = isMatrix ? SEGMENT.virtualHeight() : strip.getActiveSegmentsNum(); + const int cols = SEG_W; + const int rows = isMatrix ? SEG_H : strip.getActiveSegmentsNum(); const int inputShift = SEGMENT.speed; const int inputSize = SEGMENT.intensity; @@ -2084,10 +2085,10 @@ uint16_t mode_fire_2012() { struct virtualStrip { static void runStrip(uint16_t stripNr, byte* heat, uint32_t it) { - const uint8_t ignition = max(3,SEGLEN/10); // ignition area: 10% of segment length or minimum 3 pixels + const uint8_t ignition = MAX(3,SEGLEN/10); // ignition area: 10% of segment length or minimum 3 pixels // Step 1. Cool down every cell a little - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { uint8_t cool = (it != SEGENV.step) ? random8((((20 + SEGMENT.speed/3) * 16) / SEGLEN)+2) : random8(4); uint8_t minTemp = (i> 8; unsigned h16_128 = hue16 >> 7; @@ -2183,7 +2184,7 @@ static const char _data_FX_MODE_COLORWAVES[] PROGMEM = "Colorwaves@!,Hue;!;!"; uint16_t mode_bpm() { uint32_t stp = (strip.now / 20) & 0xFF; uint8_t beat = beatsin8(SEGMENT.speed, 64, 255); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(stp + (i * 2), false, PALETTE_SOLID_WRAP, 0, beat - stp + (i * 10))); } @@ -2194,7 +2195,7 @@ static const char _data_FX_MODE_BPM[] PROGMEM = "Bpm@!;!;!;;sx=64"; uint16_t mode_fillnoise8() { if (SEGENV.call == 0) SEGENV.step = random16(12345); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { unsigned index = inoise8(i * SEGLEN, SEGENV.step + i * SEGLEN); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); } @@ -2209,7 +2210,7 @@ uint16_t mode_noise16_1() { unsigned scale = 320; // the "zoom factor" for the noise SEGENV.step += (1 + SEGMENT.speed/16); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { unsigned shift_x = beatsin8(11); // the x position of the noise field swings @ 17 bpm unsigned shift_y = SEGENV.step/42; // the y position becomes slowly incremented unsigned real_x = (i + shift_x) * scale; // the x position of the noise field swings @ 17 bpm @@ -2230,7 +2231,7 @@ uint16_t mode_noise16_2() { unsigned scale = 1000; // the "zoom factor" for the noise SEGENV.step += (1 + (SEGMENT.speed >> 1)); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { unsigned shift_x = SEGENV.step >> 6; // x as a function of time uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field unsigned noise = inoise16(real_x, 0, 4223) >> 8; // get the noise data and scale it down @@ -2248,7 +2249,7 @@ uint16_t mode_noise16_3() { unsigned scale = 800; // the "zoom factor" for the noise SEGENV.step += (1 + SEGMENT.speed); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { unsigned shift_x = 4223; // no movement along x and y unsigned shift_y = 1234; uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field @@ -2268,7 +2269,7 @@ static const char _data_FX_MODE_NOISE16_3[] PROGMEM = "Noise 3@!;!;!"; //https://github.com/aykevl/ledstrip-spark/blob/master/ledstrip.ino uint16_t mode_noise16_4() { uint32_t stp = (strip.now * SEGMENT.speed) >> 7; - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { int index = inoise16(uint32_t(i) << 12, stp); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); } @@ -2285,7 +2286,7 @@ uint16_t mode_colortwinkle() { CRGBW col, prev; fract8 fadeUpAmount = strip.getBrightness()>28 ? 8 + (SEGMENT.speed>>2) : 68-strip.getBrightness(); fract8 fadeDownAmount = strip.getBrightness()>28 ? 8 + (SEGMENT.speed>>3) : 68-strip.getBrightness(); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { CRGBW cur = SEGMENT.getPixelColor(i); prev = cur; unsigned index = i >> 3; @@ -2338,7 +2339,7 @@ uint16_t mode_lake() { int wave2 = beatsin8(sp +1, -64,64); int wave3 = beatsin8(sp +2, 0,80); - for (int i = 0; i < SEGLEN; i++) + for (unsigned i = 0; i < SEGLEN; i++) { int index = cos8((i*15)+ wave1)/2 + cubicwave8((i*23)+ wave2)/2; uint8_t lum = (index > wave3) ? index - wave3 : 0; @@ -2365,7 +2366,7 @@ uint16_t mode_meteor() { const int max = SEGMENT.palette==5 ? 239 : 255; // "* Colors only" palette blends end with start // fade all leds to colors[1] in LEDs one step - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { if (random8() <= 255 - SEGMENT.intensity) { int meteorTrailDecay = 128 + random8(127); trail[i] = scale8(trail[i], meteorTrailDecay); @@ -2454,7 +2455,7 @@ uint16_t mode_railway() { if (p0 < 255) pos = p0; } if (SEGENV.aux0) pos = 255 - pos; - for (int i = 0; i < SEGLEN; i += 2) + for (unsigned i = 0; i < SEGLEN; i += 2) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(255 - pos, false, false, 255)); // do not use color 1 or 2, always use palette if (i < SEGLEN -1) @@ -2485,7 +2486,7 @@ typedef struct Ripple { #define MAX_RIPPLES 100 #endif static uint16_t ripple_base() { - unsigned maxRipples = min(1 + (SEGLEN >> 2), MAX_RIPPLES); // 56 max for 16 segment ESP8266 + unsigned maxRipples = min(1 + (int)(SEGLEN >> 2), MAX_RIPPLES); // 56 max for 16 segment ESP8266 unsigned dataSize = sizeof(ripple) * maxRipples; if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed @@ -2655,7 +2656,7 @@ static uint16_t twinklefox_base(bool cat) unsigned backgroundBrightness = bg.getAverageLight(); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number unsigned myclockoffset16= PRNG16; // use that number as clock offset @@ -2727,8 +2728,8 @@ uint16_t mode_halloween_eyes() }; if (SEGLEN == 1) return mode_static(); - const unsigned maxWidth = strip.isMatrix ? SEGMENT.virtualWidth() : SEGLEN; - const unsigned HALLOWEEN_EYE_SPACE = MAX(2, strip.isMatrix ? SEGMENT.virtualWidth()>>4: SEGLEN>>5); + const unsigned maxWidth = strip.isMatrix ? SEG_W : SEGLEN; + const unsigned HALLOWEEN_EYE_SPACE = MAX(2, strip.isMatrix ? SEG_W>>4: SEGLEN>>5); const unsigned HALLOWEEN_EYE_WIDTH = HALLOWEEN_EYE_SPACE/2; unsigned eyeLength = (2*HALLOWEEN_EYE_WIDTH) + HALLOWEEN_EYE_SPACE; if (eyeLength >= maxWidth) return mode_static(); //bail if segment too short @@ -2751,7 +2752,7 @@ uint16_t mode_halloween_eyes() data.startPos = random16(0, maxWidth - eyeLength - 1); data.color = random8(); - if (strip.isMatrix) SEGMENT.offset = random16(SEGMENT.virtualHeight()-1); // a hack: reuse offset since it is not used in matrices + if (strip.isMatrix) SEGMENT.offset = random16(SEG_H-1); // a hack: reuse offset since it is not used in matrices duration = 128u + random16(SEGMENT.intensity*64u); data.duration = duration; data.state = eyeState::on; @@ -2869,7 +2870,7 @@ uint16_t mode_static_pattern() bool drawingLit = true; unsigned cnt = 0; - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, (drawingLit) ? SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0) : SEGCOLOR(1)); cnt++; if (cnt >= ((drawingLit) ? lit : unlit)) { @@ -2889,7 +2890,7 @@ uint16_t mode_tri_static_pattern() unsigned currSeg = 0; unsigned currSegCount = 0; - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { if ( currSeg % 3 == 0 ) { SEGMENT.setPixelColor(i, SEGCOLOR(0)); } else if( currSeg % 3 == 1) { @@ -3319,7 +3320,7 @@ uint16_t candle(bool multi) { if (multi && SEGLEN > 1) { //allocate segment data - unsigned dataSize = max(1, SEGLEN -1) *3; //max. 1365 pixels (ESP8266) + unsigned dataSize = max(1, (int)SEGLEN -1) *3; //max. 1365 pixels (ESP8266) if (!SEGENV.allocateData(dataSize)) return candle(false); //allocation failed } @@ -3378,7 +3379,7 @@ uint16_t candle(bool multi) SEGENV.data[d] = s; SEGENV.data[d+1] = s_target; SEGENV.data[d+2] = fadeStep; } else { - for (int j = 0; j < SEGLEN; j++) { + for (unsigned j = 0; j < SEGLEN; j++) { SEGMENT.setPixelColor(j, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(j, true, PALETTE_SOLID_WRAP, 0), s)); } @@ -3521,12 +3522,12 @@ uint16_t mode_starburst(void) { if (stars[j].fragment[i] > 0) { float loc = stars[j].fragment[i]; if (mirrored) loc -= (loc-stars[j].pos)*2; - int start = loc - particleSize; - int end = loc + particleSize; + unsigned start = loc - particleSize; + unsigned end = loc + particleSize; if (start < 0) start = 0; if (start == end) end++; if (end > SEGLEN) end = SEGLEN; - for (int p = start; p < end; p++) { + for (unsigned p = start; p < end; p++) { SEGMENT.setPixelColor(p, c); } } @@ -3546,8 +3547,8 @@ static const char _data_FX_MODE_STARBURST[] PROGMEM = "Fireworks Starburst@Chanc uint16_t mode_exploding_fireworks(void) { if (SEGLEN == 1) return mode_static(); - const int cols = SEGMENT.is2D() ? SEGMENT.virtualWidth() : 1; - const int rows = SEGMENT.is2D() ? SEGMENT.virtualHeight() : SEGMENT.virtualLength(); + const int cols = SEGMENT.is2D() ? SEG_W : 1; + const int rows = SEGMENT.is2D() ? SEG_H : SEGLEN; //allocate segment data unsigned maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640 @@ -3698,7 +3699,7 @@ uint16_t mode_drip(void) unsigned numDrops = 1 + (SEGMENT.intensity >> 6); // 255>>6 = 3 float gravity = -0.0005f - (SEGMENT.speed/50000.0f); - gravity *= max(1, SEGLEN-1); + gravity *= max(1, (int)SEGLEN-1); int sourcedrop = 12; for (unsigned j=0;j= SEGLEN occasionally + unsigned pos = constrain(unsigned(drops[j].pos) +i, 0, SEGLEN-1); //this is BAD, returns a pos >= SEGLEN occasionally SEGMENT.setPixelColor(indexToVStrip(pos, stripNr), color_blend(BLACK,SEGCOLOR(0),drops[j].col/i)); //spread pixel with fade while falling } @@ -3821,8 +3822,8 @@ uint16_t mode_tetrix(void) { if (drop->pos > drop->stack) { // fall until top of stack drop->pos -= drop->speed; // may add gravity as: speed += gravity if (int(drop->pos) < int(drop->stack)) drop->pos = drop->stack; - for (int i = int(drop->pos); i < SEGLEN; i++) { - uint32_t col = ipos)+drop->brick ? SEGMENT.color_from_palette(drop->col, false, false, 0) : SEGCOLOR(1); + for (unsigned i = unsigned(drop->pos); i < SEGLEN; i++) { + uint32_t col = i < unsigned(drop->pos)+drop->brick ? SEGMENT.color_from_palette(drop->col, false, false, 0) : SEGCOLOR(1); SEGMENT.setPixelColor(indexToVStrip(i, stripNr), col); } } else { // we hit bottom @@ -3836,7 +3837,7 @@ uint16_t mode_tetrix(void) { drop->brick = 0; // reset brick size (no more growing) if (drop->step > strip.now) { // allow fading of virtual strip - for (int i = 0; i < SEGLEN; i++) SEGMENT.blendPixelColor(indexToVStrip(i, stripNr), SEGCOLOR(1), 25); // 10% blend + for (unsigned i = 0; i < SEGLEN; i++) SEGMENT.blendPixelColor(indexToVStrip(i, stripNr), SEGCOLOR(1), 25); // 10% blend } else { drop->stack = 0; // reset brick stack size drop->step = 0; // proceed with next brick @@ -3893,7 +3894,7 @@ uint16_t mode_percent(void) { if (SEGMENT.speed == 255) size = 255; if (percent <= 100) { - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { if (i < SEGENV.aux1) { if (SEGMENT.check1) SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(map(percent,0,100,0,255), false, false, 0)); @@ -3905,7 +3906,7 @@ uint16_t mode_percent(void) { } } } else { - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { if (i < (SEGLEN - SEGENV.aux1)) { SEGMENT.setPixelColor(i, SEGCOLOR(1)); } @@ -3955,7 +3956,7 @@ uint16_t mode_heartbeat(void) { SEGENV.step = strip.now; } - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, color_blend(SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), SEGCOLOR(1), 255 - (SEGENV.aux1 >> 8))); } @@ -4049,7 +4050,7 @@ uint16_t mode_pacifica() unsigned basethreshold = beatsin8( 9, 55, 65); unsigned wave = beat8( 7 ); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { CRGB c = CRGB(2, 6, 10); // Render each of four layers, with different scales and speeds, that vary over time c += pacifica_one_layer(i, pacifica_palette_1, sCIStart1, beatsin16(3, 11 * 256, 14 * 256), beatsin8(10, 70, 130), 0-beat16(301)); @@ -4112,7 +4113,7 @@ uint16_t mode_sunrise() { if (SEGMENT.speed > 60) stage = 0xFFFF - stage; //sunset } - for (int i = 0; i <= SEGLEN/2; i++) + for (unsigned i = 0; i <= SEGLEN/2; i++) { //default palette is Fire unsigned wave = triwave16((i * stage) / SEGLEN); @@ -4145,7 +4146,7 @@ static uint16_t phased_base(uint8_t moder) { // We're making si unsigned index = strip.now/64; // Set color rotation speed *phase += SEGMENT.speed/32.0; // You can change the speed of the wave. AKA SPEED (was .4) - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { if (moder == 1) modVal = (inoise8(i*10 + i*10) /16); // Let's randomize our mod length with some Perlin noise. unsigned val = (i+1) * allfreq; // This sets the frequency of the waves. The +1 makes sure that led 0 is used. if (modVal == 0) modVal = 1; @@ -4177,7 +4178,7 @@ uint16_t mode_twinkleup(void) { // A very short twinkle routine unsigned prevSeed = random16_get_seed(); // save seed so we can restore it at the end of the function random16_set_seed(535); // The randomizer needs to be re-set each time through the loop in order for the same 'random' numbers to be the same each time through. - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { unsigned ranstart = random8(); // The starting value (aka brightness) for each pixel. Must be consistent each time through the loop for this to work. unsigned pixBri = sin8(ranstart + 16 * strip.now/(256-SEGMENT.speed)); if (random8() > SEGMENT.intensity) pixBri = 0; @@ -4214,7 +4215,7 @@ uint16_t mode_noisepal(void) { // Slow noise if (SEGMENT.palette > 0) palettes[0] = SEGPALETTE; - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { unsigned index = inoise8(i*scale, SEGENV.aux0+i*scale); // Get a value from the noise function. I'm using both x and y axis. SEGMENT.setPixelColor(i, ColorFromPalette(palettes[0], index, 255, LINEARBLEND)); // Use my own palette. } @@ -4237,7 +4238,7 @@ uint16_t mode_sinewave(void) { // Adjustable sinewave. By Andrew Tul SEGENV.step += SEGMENT.speed/16; // Speed of animation. unsigned freq = SEGMENT.intensity/4;//SEGMENT.fft2/8; // Frequency of the signal. - for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows: + for (unsigned i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows: int pixBri = cubicwave8((i*freq)+SEGENV.step);//qsuba(cubicwave8((i*freq)+SEGENV.step), (255-SEGMENT.intensity)); // qsub sets a minimum value called thiscutoff. If < thiscutoff, then bright = 0. Otherwise, bright = 128 (as defined in qsub).. //setPixCol(i, i*colorIndex/255, pixBri); SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i*colorIndex/255, false, PALETTE_SOLID_WRAP, 0), pixBri)); @@ -4368,7 +4369,7 @@ uint16_t mode_dancing_shadows(void) spotlights[i].lastUpdateTime = time; } - respawn = (spotlights[i].speed > 0.0 && spotlights[i].position > (SEGLEN + 2)) + respawn = (spotlights[i].speed > 0.0 && spotlights[i].position > (int)(SEGLEN + 2)) || (spotlights[i].speed < 0.0 && spotlights[i].position < -(spotlights[i].width + 2)); } @@ -4398,7 +4399,7 @@ uint16_t mode_dancing_shadows(void) int start = spotlights[i].position; if (spotlights[i].width <= 1) { - if (start >= 0 && start < SEGLEN) { + if (start >= 0 && start < (int)SEGLEN) { SEGMENT.blendPixelColor(start, color, 128); } } else { @@ -4468,7 +4469,7 @@ uint16_t mode_washing_machine(void) { SEGENV.step += (speed * 2048) / (512 - SEGMENT.speed); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { uint8_t col = sin8(((SEGMENT.intensity / 25 + 1) * 255 * i / SEGLEN) + (SEGENV.step >> 7)); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(col, false, PALETTE_SOLID_WRAP, 3)); } @@ -4618,7 +4619,7 @@ uint16_t mode_tv_simulator(void) { } // set strip color - for (i = 0; i < SEGLEN; i++) { + for (i = 0; i < (int)SEGLEN; i++) { SEGMENT.setPixelColor(i, r >> 8, g >> 8, b >> 8); // Quantize to 8-bit } @@ -4777,7 +4778,7 @@ uint16_t mode_aurora(void) { if (SEGCOLOR(1)) backlight++; if (SEGCOLOR(2)) backlight++; //Loop through LEDs to determine color - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { CRGB mixedRgb = CRGB(backlight, backlight, backlight); //For each LED we must check each wave if it is "active" at this position. @@ -4824,7 +4825,7 @@ static const char _data_FX_MODE_PERLINMOVE[] PROGMEM = "Perlin Move@!,# of pixel // Uses beatsin8() + phase shifting. By: Andrew Tuline uint16_t mode_wavesins(void) { - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { uint8_t bri = sin8(strip.now/4 + i * SEGMENT.intensity); uint8_t index = beatsin8(SEGMENT.speed, SEGMENT.custom1, SEGMENT.custom1+SEGMENT.custom2, 0, i * (SEGMENT.custom3<<3)); // custom3 is reduced resolution slider //SEGMENT.setPixelColor(i, ColorFromPalette(SEGPALETTE, index, bri, LINEARBLEND)); @@ -4846,8 +4847,8 @@ uint16_t mode_FlowStripe(void) { uint8_t hue = strip.now / (SEGMENT.speed+1); uint32_t t = strip.now / (SEGMENT.intensity/8+1); - for (int i = 0; i < SEGLEN; i++) { - int c = (abs(i - hl) / hl) * 127; + for (unsigned i = 0; i < SEGLEN; i++) { + int c = (abs((int)i - hl) / hl) * 127; c = sin8(c); c = sin8(c / 2 + t); byte b = sin8(c + t/8); @@ -4869,8 +4870,8 @@ static const char _data_FX_MODE_FLOWSTRIPE[] PROGMEM = "Flow Stripe@Hue speed,Ef uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulmatelights.com/gallery/1012 , Modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; int x, y; SEGMENT.fadeToBlackBy(16 + (SEGMENT.speed>>3)); // create fading trails @@ -4903,8 +4904,8 @@ static const char _data_FX_MODE_2DBLACKHOLE[] PROGMEM = "Black Hole@Fade rate,Ou uint16_t mode_2DColoredBursts() { // By: ldirko https://editor.soulmatelights.com/gallery/819-colored-bursts , modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; if (SEGENV.call == 0) { SEGENV.aux0 = 0; // start with red hue @@ -4955,8 +4956,8 @@ static const char _data_FX_MODE_2DCOLOREDBURSTS[] PROGMEM = "Colored Bursts@Spee uint16_t mode_2Ddna(void) { // dna originally by by ldirko at https://pastebin.com/pCkkkzcs. Updated by Preyy. WLED conversion by Andrew Tuline. if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; SEGMENT.fadeToBlackBy(64); for (int i = 0; i < cols; i++) { @@ -4976,8 +4977,8 @@ static const char _data_FX_MODE_2DDNA[] PROGMEM = "DNA@Scroll speed,Blur;;!;2"; uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulmatelights.com/gallery/512-dna-spiral-variation , modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; if (SEGENV.call == 0) { SEGMENT.fill(BLACK); @@ -5021,8 +5022,8 @@ static const char _data_FX_MODE_2DDNASPIRAL[] PROGMEM = "DNA Spiral@Scroll speed uint16_t mode_2DDrift() { // By: Stepko https://editor.soulmatelights.com/gallery/884-drift , Modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; const int colsCenter = (cols>>1) + (cols%2); const int rowsCenter = (rows>>1) + (rows%2); @@ -5051,8 +5052,8 @@ static const char _data_FX_MODE_2DDRIFT[] PROGMEM = "Drift@Rotation speed,Blur a uint16_t mode_2Dfirenoise(void) { // firenoise2d. By Andrew Tuline. Yet another short routine. if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; if (SEGENV.call == 0) { SEGMENT.fill(BLACK); @@ -5085,8 +5086,8 @@ static const char _data_FX_MODE_2DFIRENOISE[] PROGMEM = "Firenoise@X scale,Y sca uint16_t mode_2DFrizzles(void) { // By: Stepko https://editor.soulmatelights.com/gallery/640-color-frizzles , Modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; SEGMENT.fadeToBlackBy(16); for (size_t i = 8; i > 0; i--) { @@ -5112,8 +5113,8 @@ typedef struct ColorCount { uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https://natureofcode.com/book/chapter-7-cellular-automata/ and https://github.com/DougHaber/nlife-color if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; const unsigned dataSize = sizeof(CRGB) * SEGMENT.length(); // using width*height prevents reallocation if mirroring is enabled const int crcBufferLen = 2; //(SEGMENT.width() + SEGMENT.height())*71/100; // roughly sqrt(2)/2 for better repetition detection (Ewowi) @@ -5218,8 +5219,8 @@ static const char _data_FX_MODE_2DGAMEOFLIFE[] PROGMEM = "Game Of Life@!;!,!;!;2 uint16_t mode_2DHiphotic() { // By: ldirko https://editor.soulmatelights.com/gallery/810 , Modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; const uint32_t a = strip.now / ((SEGMENT.custom3>>1)+1); for (int x = 0; x < cols; x++) { @@ -5250,8 +5251,8 @@ typedef struct Julia { uint16_t mode_2DJulia(void) { // An animated Julia set by Andrew Tuline. if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; if (!SEGENV.allocateData(sizeof(julia))) return mode_static(); Julia* julias = reinterpret_cast(SEGENV.data); @@ -5356,8 +5357,8 @@ static const char _data_FX_MODE_2DJULIA[] PROGMEM = "Julia@,Max iterations per p uint16_t mode_2DLissajous(void) { // By: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; SEGMENT.fadeToBlackBy(SEGMENT.intensity); uint_fast16_t phase = (strip.now * (1 + SEGENV.custom3)) /32; // allow user to control rotation speed @@ -5384,8 +5385,8 @@ static const char _data_FX_MODE_2DLISSAJOUS[] PROGMEM = "Lissajous@X frequency,F uint16_t mode_2Dmatrix(void) { // Matrix2D. By Jeremy Williams. Adapted by Andrew Tuline & improved by merkisoft and ewowi, and softhack007. if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; unsigned dataSize = (SEGMENT.length()+7) >> 3; //1 bit per LED for trails if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed @@ -5454,8 +5455,8 @@ static const char _data_FX_MODE_2DMATRIX[] PROGMEM = "Matrix@!,Spawning rate,Tra uint16_t mode_2Dmetaballs(void) { // Metaballs by Stefan Petrick. Cannot have one of the dimensions be 2 or less. Adapted by Andrew Tuline. if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; float speed = 0.25f * (1+(SEGMENT.speed>>6)); @@ -5513,8 +5514,8 @@ static const char _data_FX_MODE_2DMETABALLS[] PROGMEM = "Metaballs@!;;!;2"; uint16_t mode_2Dnoise(void) { // By Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; const unsigned scale = SEGMENT.intensity+2; @@ -5536,8 +5537,8 @@ static const char _data_FX_MODE_2DNOISE[] PROGMEM = "Noise2D@!,Scale;;!;2"; uint16_t mode_2DPlasmaball(void) { // By: Stepko https://editor.soulmatelights.com/gallery/659-plasm-ball , Modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; SEGMENT.fadeToBlackBy(SEGMENT.custom1>>2); uint_fast32_t t = (strip.now * 8) / (256 - SEGMENT.speed); // optimized to avoid float @@ -5576,8 +5577,8 @@ static const char _data_FX_MODE_2DPLASMABALL[] PROGMEM = "Plasma Ball@Speed,,Fad uint16_t mode_2DPolarLights(void) { // By: Kostyantyn Matviyevskyy https://editor.soulmatelights.com/gallery/762-polar-lights , Modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; CRGBPalette16 auroraPalette = {0x000000, 0x003300, 0x006600, 0x009900, 0x00cc00, 0x00ff00, 0x33ff00, 0x66ff00, 0x99ff00, 0xccff00, 0xffff00, 0xffcc00, 0xff9900, 0xff6600, 0xff3300, 0xff0000}; @@ -5627,8 +5628,8 @@ static const char _data_FX_MODE_2DPOLARLIGHTS[] PROGMEM = "Polar Lights@!,Scale; uint16_t mode_2DPulser(void) { // By: ldirko https://editor.soulmatelights.com/gallery/878-pulse-test , modifed by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; SEGMENT.fadeToBlackBy(8 - (SEGMENT.intensity>>5)); uint32_t a = strip.now / (18 - SEGMENT.speed / 16); @@ -5649,8 +5650,8 @@ static const char _data_FX_MODE_2DPULSER[] PROGMEM = "Pulser@!,Blur;;!;2"; uint16_t mode_2DSindots(void) { // By: ldirko https://editor.soulmatelights.com/gallery/597-sin-dots , modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; if (SEGENV.call == 0) { SEGMENT.fill(BLACK); @@ -5680,8 +5681,8 @@ uint16_t mode_2Dsquaredswirl(void) { // By: Mark Kriegsman. https://g // Modifed by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; const uint8_t kBorderWidth = 2; @@ -5711,8 +5712,8 @@ static const char _data_FX_MODE_2DSQUAREDSWIRL[] PROGMEM = "Squared Swirl@,,,,Bl uint16_t mode_2DSunradiation(void) { // By: ldirko https://editor.soulmatelights.com/gallery/599-sun-radiation , modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; if (!SEGENV.allocateData(sizeof(byte)*(cols+2)*(rows+2))) return mode_static(); //allocation failed byte *bump = reinterpret_cast(SEGENV.data); @@ -5761,8 +5762,8 @@ static const char _data_FX_MODE_2DSUNRADIATION[] PROGMEM = "Sun Radiation@Varian uint16_t mode_2Dtartan(void) { // By: Elliott Kember https://editor.soulmatelights.com/gallery/3-tartan , Modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; if (SEGENV.call == 0) { SEGMENT.fill(BLACK); @@ -5800,8 +5801,8 @@ static const char _data_FX_MODE_2DTARTAN[] PROGMEM = "Tartan@X scale,Y scale,,,S uint16_t mode_2Dspaceships(void) { //// Space ships by stepko (c)05.02.21 [https://editor.soulmatelights.com/gallery/639-space-ships], adapted by Blaz Kristan (AKA blazoncek) if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; uint32_t tb = strip.now >> 12; // every ~4s if (tb > SEGENV.step) { @@ -5843,8 +5844,8 @@ static const char _data_FX_MODE_2DSPACESHIPS[] PROGMEM = "Spaceships@!,Blur;;!;2 uint16_t mode_2Dcrazybees(void) { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; byte n = MIN(MAX_BEES, (rows * cols) / 256 + 1); @@ -5916,8 +5917,8 @@ static const char _data_FX_MODE_2DCRAZYBEES[] PROGMEM = "Crazy Bees@!,Blur;;;2"; uint16_t mode_2Dghostrider(void) { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; typedef struct Lighter { int16_t gPosX; @@ -6006,8 +6007,8 @@ static const char _data_FX_MODE_2DGHOSTRIDER[] PROGMEM = "Ghost Rider@Fade rate, uint16_t mode_2Dfloatingblobs(void) { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; typedef struct Blob { float x[MAX_BLOBS], y[MAX_BLOBS]; @@ -6104,8 +6105,8 @@ static const char _data_FX_MODE_2DBLOBS[] PROGMEM = "Blobs@!,# blobs,Blur,Trail; uint16_t mode_2Dscrollingtext(void) { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; unsigned letterWidth, rotLW; unsigned letterHeight, rotLH; @@ -6205,8 +6206,8 @@ static const char _data_FX_MODE_2DSCROLLTEXT[] PROGMEM = "Scrolling Text@!,Y Off uint16_t mode_2Ddriftrose(void) { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; const float CX = (cols-cols%2)/2.f - .5f; const float CY = (rows-rows%2)/2.f - .5f; @@ -6232,8 +6233,8 @@ static const char _data_FX_MODE_2DDRIFTROSE[] PROGMEM = "Drift Rose@Fade,Blur;;; uint16_t mode_2Dplasmarotozoom() { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; unsigned dataSize = SEGMENT.length() + sizeof(float); if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed @@ -6401,8 +6402,8 @@ static const char _data_FX_MODE_RIPPLEPEAK[] PROGMEM = "Ripple Peak@Fade rate,Ma uint16_t mode_2DSwirl(void) { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; if (SEGENV.call == 0) { SEGMENT.fill(BLACK); @@ -6440,8 +6441,8 @@ static const char _data_FX_MODE_2DSWIRL[] PROGMEM = "Swirl@!,Sensitivity,Blur;,B uint16_t mode_2DWaverly(void) { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; um_data_t *um_data = getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; @@ -6652,7 +6653,7 @@ uint16_t mode_matripix(void) { // Matripix. By Andrew Tuline. SEGENV.aux0 = secondHand; int pixBri = volumeRaw * SEGMENT.intensity / 64; - for (int i = 0; i < SEGLEN-1; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // shift left + for (unsigned i = 0; i < SEGLEN-1; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // shift left SEGMENT.setPixelColor(SEGLEN-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0), pixBri)); } @@ -6677,10 +6678,10 @@ uint16_t mode_midnoise(void) { // Midnoise. By Andrew Tuline. float tmpSound2 = volumeSmth * (float)SEGMENT.intensity / 256.0; // Too sensitive. tmpSound2 *= (float)SEGMENT.intensity / 128.0; // Reduce sensitivity/length. - int maxLen = mapf(tmpSound2, 0, 127, 0, SEGLEN/2); + unsigned maxLen = mapf(tmpSound2, 0, 127, 0, SEGLEN/2); if (maxLen >SEGLEN/2) maxLen = SEGLEN/2; - for (int i=(SEGLEN/2-maxLen); i<(SEGLEN/2+maxLen); i++) { + for (unsigned i=(SEGLEN/2-maxLen); i<(SEGLEN/2+maxLen); i++) { uint8_t index = inoise8(i*volumeSmth+SEGENV.aux0, SEGENV.aux1+i*volumeSmth); // Get a value from the noise function. I'm using both x and y axis. SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); } @@ -6708,7 +6709,7 @@ uint16_t mode_noisefire(void) { // Noisefire. By Andrew Tuline. if (SEGENV.call == 0) SEGMENT.fill(BLACK); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { unsigned index = inoise8(i*SEGMENT.speed/64,strip.now*SEGMENT.speed/64*SEGLEN/255); // X location is constant, but we move along the Y at the rate of millis(). By Andrew Tuline. index = (255 - i*256/SEGLEN) * index/(256-SEGMENT.intensity); // Now we need to scale index so that it gets blacker as we get close to one of the ends. // This is a simple y=mx+b equation that's been scaled. index/128 is another scaling. @@ -6735,11 +6736,11 @@ uint16_t mode_noisemeter(void) { // Noisemeter. By Andrew Tuline. SEGMENT.fade_out(fadeRate); float tmpSound2 = volumeRaw * 2.0 * (float)SEGMENT.intensity / 255.0; - int maxLen = mapf(tmpSound2, 0, 255, 0, SEGLEN); // map to pixels availeable in current segment // Still a bit too sensitive. - if (maxLen <0) maxLen = 0; - if (maxLen >SEGLEN) maxLen = SEGLEN; + unsigned maxLen = mapf(tmpSound2, 0, 255, 0, SEGLEN); // map to pixels availeable in current segment // Still a bit too sensitive. + if (maxLen < 0) maxLen = 0; + if (maxLen > SEGLEN) maxLen = SEGLEN; - for (int i=0; i SEGLEN/2; i--) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i-1)); //move to the left - for (int i = 0; i < SEGLEN/2; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // move to the right + for (unsigned i = SEGLEN - 1; i > SEGLEN/2; i--) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i-1)); //move to the left + for (unsigned i = 0; i < SEGLEN/2; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // move to the right } return FRAMETIME; @@ -6803,7 +6804,7 @@ uint16_t mode_plasmoid(void) { // Plasmoid. By Andrew Tuline. plasmoip->thisphase += beatsin8(6,-4,4); // You can change direction and speed individually. plasmoip->thatphase += beatsin8(7,-4,4); // Two phase values to make a complex pattern. By Andrew Tuline. - for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows. + for (unsigned i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows. // updated, similar to "plasma" effect - softhack007 uint8_t thisbright = cubicwave8(((i*(1 + (3*SEGMENT.speed/32)))+plasmoip->thisphase) & 0xFF)/2; thisbright += cos8(((i*(97 +(5*SEGMENT.speed/32)))+plasmoip->thatphase) & 0xFF)/2; // Let's munge the brightness a bit and animate it all with the phases. @@ -6943,7 +6944,7 @@ uint16_t mode_blurz(void) { // Blurz. By Andrew Tuline. SEGENV.step += FRAMETIME; if (SEGENV.step > SPEED_FORMULA_L) { unsigned segLoc = random16(SEGLEN); - SEGMENT.setPixelColor(segLoc, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(2*fftResult[SEGENV.aux0%16]*240/max(1, SEGLEN-1), false, PALETTE_SOLID_WRAP, 0), 2*fftResult[SEGENV.aux0%16])); + SEGMENT.setPixelColor(segLoc, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(2*fftResult[SEGENV.aux0%16]*240/max(1, (int)SEGLEN-1), false, PALETTE_SOLID_WRAP, 0), 2*fftResult[SEGENV.aux0%16])); ++(SEGENV.aux0) %= 16; // make sure it doesn't cross 16 SEGENV.step = 1; @@ -7006,7 +7007,7 @@ uint16_t mode_freqmap(void) { // Map FFT_MajorPeak to SEGLEN. int locn = (log10f((float)FFT_MajorPeak) - 1.78f) * (float)SEGLEN/(MAX_FREQ_LOG10 - 1.78f); // log10 frequency range is from 1.78 to 3.71. Let's scale to SEGLEN. if (locn < 1) locn = 0; // avoid underflow - if (locn >=SEGLEN) locn = SEGLEN-1; + if (locn >= (int)SEGLEN) locn = SEGLEN-1; unsigned pixCol = (log10f(FFT_MajorPeak) - 1.78f) * 255.0f/(MAX_FREQ_LOG10 - 1.78f); // Scale log10 of frequency values to the 255 colour index. if (FFT_MajorPeak < 61.0f) pixCol = 0; // handle underflow @@ -7159,8 +7160,8 @@ uint16_t mode_freqwave(void) { // Freqwave. By Andreas Pleschun // shift the pixels one pixel outwards // if SEGLEN equals 1 these loops won't execute - for (int i = SEGLEN - 1; i > SEGLEN/2; i--) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i-1)); //move to the left - for (int i = 0; i < SEGLEN/2; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // move to the right + for (unsigned i = SEGLEN - 1; i > SEGLEN/2; i--) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i-1)); //move to the left + for (unsigned i = 0; i < SEGLEN/2; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // move to the right } return FRAMETIME; @@ -7314,7 +7315,7 @@ uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tulin SEGMENT.setPixelColor(SEGLEN-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(pixCol+SEGMENT.intensity, false, PALETTE_SOLID_WRAP, 0), (int)my_magnitude)); } // loop will not execute if SEGLEN equals 1 - for (int i = 0; i < SEGLEN-1; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // shift left + for (unsigned i = 0; i < SEGLEN-1; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // shift left } return FRAMETIME; @@ -7330,8 +7331,8 @@ uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma. if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up const int NUM_BANDS = map(SEGMENT.custom1, 0, 255, 1, 16); - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; if (!SEGENV.allocateData(cols*sizeof(uint16_t))) return mode_static(); //allocation failed uint16_t *previousBarHeight = reinterpret_cast(SEGENV.data); //array of previous bar heights per frequency band @@ -7383,8 +7384,8 @@ static const char _data_FX_MODE_2DGEQ[] PROGMEM = "GEQ@Fade speed,Ripple decay,# uint16_t mode_2DFunkyPlank(void) { // Written by ??? Adapted by Will Tatam. if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; int NUMB_BANDS = map(SEGMENT.custom1, 0, 255, 1, 16); int barWidth = (cols / NUMB_BANDS); @@ -7471,8 +7472,8 @@ static uint8_t akemi[] PROGMEM = { uint16_t mode_2DAkemi(void) { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; unsigned counter = (strip.now * ((SEGMENT.speed >> 2) +2)) & 0xFFFF; counter = counter >> 8; @@ -7539,8 +7540,8 @@ static const char _data_FX_MODE_2DAKEMI[] PROGMEM = "Akemi@Color speed,Dance;Hea uint16_t mode_2Ddistortionwaves() { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; uint8_t speed = SEGMENT.speed/32; uint8_t scale = SEGMENT.intensity/32; @@ -7594,8 +7595,8 @@ static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@ uint16_t mode_2Dsoap() { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; const size_t dataSize = SEGMENT.width() * SEGMENT.height() * sizeof(uint8_t); // prevent reallocation if mirrored or grouped if (!SEGENV.allocateData(dataSize + sizeof(uint32_t)*3)) return mode_static(); //allocation failed @@ -7706,8 +7707,8 @@ static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness;;!;2"; uint16_t mode_2Doctopus() { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; const uint8_t mapp = 180 / MAX(cols,rows); typedef struct { @@ -7761,8 +7762,8 @@ static const char _data_FX_MODE_2DOCTOPUS[] PROGMEM = "Octopus@!,,Offset X,Offse uint16_t mode_2Dwavingcell() { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; uint32_t t = strip.now/(257-SEGMENT.speed); uint8_t aX = SEGMENT.custom1/16 + 9; diff --git a/wled00/FX.h b/wled00/FX.h index 825c722e7..98082c8d8 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -90,11 +90,11 @@ extern byte realtimeMode; // used in getMappedPixelIndex() #define NUM_COLORS 3 /* number of colors per segment */ #define SEGMENT strip._segments[strip.getCurrSegmentId()] #define SEGENV strip._segments[strip.getCurrSegmentId()] -//#define SEGCOLOR(x) strip._segments[strip.getCurrSegmentId()].currentColor(x, strip._segments[strip.getCurrSegmentId()].colors[x]) -//#define SEGLEN strip._segments[strip.getCurrSegmentId()].virtualLength() -#define SEGCOLOR(x) strip.segColor(x) /* saves us a few kbytes of code */ +#define SEGCOLOR(x) Segment::getCurrentColor(x) #define SEGPALETTE Segment::getCurrentPalette() -#define SEGLEN strip._virtualSegmentLength /* saves us a few kbytes of code */ +#define SEGLEN Segment::vLength() +#define SEG_W Segment::vWidth() +#define SEG_H Segment::vHeight() #define SPEED_FORMULA_L (5U + (50U*(255U - SEGMENT.speed))/SEGLEN) // some common colors @@ -421,7 +421,9 @@ typedef struct Segment { uint16_t _dataLen; static uint16_t _usedSegmentData; - // perhaps this should be per segment, not static + static unsigned _vLength; // 1D dimension used for current effect + static unsigned _vWidth, _vHeight; // 2D dimensions used for current effect + static uint32_t _currentColors[NUM_COLORS]; // colors used for current effect static CRGBPalette16 _currentPalette; // palette used for current effect (includes transition, used in color_from_palette()) static CRGBPalette16 _randomPalette; // actual random palette static CRGBPalette16 _newRandomPalette; // target random palette @@ -534,14 +536,20 @@ typedef struct Segment { inline uint16_t groupLength() const { return grouping + spacing; } inline uint8_t getLightCapabilities() const { return _capabilities; } - inline static uint16_t getUsedSegmentData() { return _usedSegmentData; } - inline static void addUsedSegmentData(int len) { _usedSegmentData += len; } + inline static uint16_t getUsedSegmentData() { return Segment::_usedSegmentData; } + inline static void addUsedSegmentData(int len) { Segment::_usedSegmentData += len; } #ifndef WLED_DISABLE_MODE_BLEND - inline static void modeBlend(bool blend) { _modeBlend = blend; } + inline static void modeBlend(bool blend) { _modeBlend = blend; } #endif - static void handleRandomPalette(); + inline static unsigned vLength() { return Segment::_vLength; } + inline static unsigned vWidth() { return Segment::_vWidth; } + inline static unsigned vHeight() { return Segment::_vHeight; } + inline static uint32_t getCurrentColor(unsigned i) { return Segment::_currentColors[i]; } // { return i < 3 ? Segment::_currentColors[i] : 0; } inline static const CRGBPalette16 &getCurrentPalette() { return Segment::_currentPalette; } + static void handleRandomPalette(); + + void beginDraw(); // set up parameters for current effect void setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1); bool setColor(uint8_t slot, uint32_t c); //returns true if changed void setCCT(uint16_t k); @@ -578,14 +586,13 @@ typedef struct Segment { uint8_t currentMode() const; // currently active effect/mode (while in transition) [[gnu::hot]] uint32_t currentColor(uint8_t slot) const; // currently active segment color (blended while in transition) CRGBPalette16 &loadPalette(CRGBPalette16 &tgt, uint8_t pal); - void setCurrentPalette(); // 1D strip [[gnu::hot]] uint16_t virtualLength() const; - [[gnu::hot]] void setPixelColor(int n, uint32_t c); // set relative pixel within segment with color - inline void setPixelColor(unsigned n, uint32_t c) { setPixelColor(int(n), c); } - inline void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } - inline void setPixelColor(int n, CRGB c) { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } + [[gnu::hot]] void setPixelColor(int n, uint32_t c, bool unScaled = true); // set relative pixel within segment with color + inline void setPixelColor(unsigned n, uint32_t c, bool unScaled = true) { setPixelColor(int(n), c, unScaled); } + inline void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } + inline void setPixelColor(int n, CRGB c) { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } #ifdef WLED_USE_AA_PIXELS void setPixelColor(float i, uint32_t c, bool aa = true); inline void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) { setPixelColor(i, RGBW32(r,g,b,w), aa); } @@ -622,8 +629,8 @@ typedef struct Segment { uint16_t nrOfVStrips() const; // returns number of virtual vertical strips in 2D matrix (used to expand 1D effects into 2D) #ifndef WLED_DISABLE_2D [[gnu::hot]] uint16_t XY(int x, int y); // support function to get relative index within segment - [[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color - inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColorXY(int(x), int(y), c); } + [[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c, bool unScaled = true); // set relative pixel within segment with color + inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c, bool unScaled = true) { setPixelColorXY(int(x), int(y), c, unScaled); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColorXY(int(x), int(y), RGBW32(c.r,c.g,c.b,0)); } @@ -642,8 +649,8 @@ typedef struct Segment { inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), fade, true)); } void box_blur(unsigned r = 1U, bool smear = false); // 2D box blur void blur2D(uint8_t blur_amount, bool smear = false); - void blurRow(uint32_t row, fract8 blur_amount, bool smear = false); - void blurCol(uint32_t col, fract8 blur_amount, bool smear = false); + void blurRow(int row, fract8 blur_amount, bool smear = false); + void blurCol(int col, fract8 blur_amount, bool smear = false); void moveX(int8_t delta, bool wrap = false); void moveY(int8_t delta, bool wrap = false); void move(uint8_t dir, uint8_t delta, bool wrap = false); @@ -660,9 +667,9 @@ typedef struct Segment { inline void blur2d(fract8 blur_amount) { blur(blur_amount); } inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); } #else - inline uint16_t XY(uint16_t x, uint16_t y) { return x; } - inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(x, c); } - inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColor(int(x), c); } + inline uint16_t XY(int x, int y) { return x; } + inline void setPixelColorXY(int x, int y, uint32_t c, bool unScaled = true) { setPixelColor(x, c, unScaled); } + inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c, bool unScaled = true) { setPixelColor(int(x), c, unScaled); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColor(x, RGBW32(r,g,b,w)); } inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColor(x, RGBW32(c.r,c.g,c.b,0)); } inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColor(int(x), RGBW32(c.r,c.g,c.b,0)); } @@ -680,8 +687,8 @@ typedef struct Segment { inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { fadePixelColor(x, fade); } inline void box_blur(unsigned i, bool vertical, fract8 blur_amount) {} inline void blur2D(uint8_t blur_amount, bool smear = false) {} - inline void blurRow(uint32_t row, fract8 blur_amount, bool smear = false) {} - inline void blurCol(uint32_t col, fract8 blur_amount, bool smear = false) {} + inline void blurRow(int row, fract8 blur_amount, bool smear = false) {} + inline void blurCol(int col, fract8 blur_amount, bool smear = false) {} inline void moveX(int8_t delta, bool wrap = false) {} inline void moveY(int8_t delta, bool wrap = false) {} inline void move(uint8_t dir, uint8_t delta, bool wrap = false) {} @@ -727,9 +734,6 @@ class WS2812FX { // 96 bytes autoSegments(false), correctWB(false), cctFromRgb(false), - // semi-private (just obscured) used in effect functions through macros - _colors_t{0,0,0}, - _virtualSegmentLength(0), // true private variables _suspend(false), _length(DEFAULT_LED_COUNT), @@ -829,7 +833,7 @@ class WS2812FX { // 96 bytes addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name); // add effect to the list; defined in FX.cpp; inline uint8_t getBrightness() const { return _brightness; } // returns current strip brightness - inline uint8_t getMaxSegments() const { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value) + inline constexpr unsigned getMaxSegments() { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value) inline uint8_t getSegmentsNum() const { return _segments.size(); } // returns currently present segments inline uint8_t getCurrSegmentId() const { return _segment_index; } // returns current segment index (only valid while strip.isServicing()) inline uint8_t getMainSegmentId() const { return _mainSegment; } // returns main segment index @@ -855,7 +859,6 @@ class WS2812FX { // 96 bytes uint32_t getPixelColor(unsigned) const; inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call - inline uint32_t segColor(uint8_t i) const { return _colors_t[i]; } // returns currently valid color (for slot i) AKA SEGCOLOR(); may be blended between two colors while in transition const char * getModeData(uint8_t id = 0) const { return (id && id<_modeCount) ? _modeData[id] : PSTR("Solid"); } @@ -922,11 +925,6 @@ class WS2812FX { // 96 bytes bool cctFromRgb : 1; }; - // using public variables to reduce code size increase due to inline function getSegment() (with bounds checking) - // and color transitions - uint32_t _colors_t[3]; // color used for effect (includes transition) - uint16_t _virtualSegmentLength; - std::vector _segments; friend class Segment; diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 41fd67319..5f61b0094 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -163,23 +163,24 @@ void WS2812FX::setUpMatrix() { // XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element) uint16_t IRAM_ATTR_YN Segment::XY(int x, int y) { - unsigned width = virtualWidth(); // segment width in logical pixels (can be 0 if segment is inactive) - unsigned height = virtualHeight(); // segment height in logical pixels (is always >= 1) - return isActive() ? (x%width) + (y%height) * width : 0; + const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) + const int vH = vHeight(); // segment height in logical pixels (is always >= 1) + return isActive() ? (x%vW) + (y%vH) * vW : 0; } -void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) +void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col, bool unScaled) { if (!isActive()) return; // not active - if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit + + const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) + const int vH = vHeight(); // segment height in logical pixels (is always >= 1) + if (x >= vW|| y >= vH || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit - uint8_t _bri_t = currentBri(); - if (_bri_t < 255) { - col = color_fade(col, _bri_t); - } + // if color is unscaled + if (unScaled) col = color_fade(col, currentBri()); - if (reverse ) x = virtualWidth() - x - 1; - if (reverse_y) y = virtualHeight() - y - 1; + if (reverse ) x = vW - x - 1; + if (reverse_y) y = vH - y - 1; if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed x *= groupLength(); // expand to physical pixels y *= groupLength(); // expand to physical pixels @@ -221,11 +222,8 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa) if (!isActive()) return; // not active if (x<0.0f || x>1.0f || y<0.0f || y>1.0f) return; // not normalized - const unsigned cols = virtualWidth(); - const unsigned rows = virtualHeight(); - - float fX = x * (cols-1); - float fY = y * (rows-1); + float fX = x * (vWidth()-1); + float fY = y * (vHeight()-1); if (aa) { unsigned xL = roundf(fX-0.49f); unsigned xR = roundf(fX+0.49f); @@ -263,9 +261,11 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa) // returns RGBW values of pixel uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const { if (!isActive()) return 0; // not active - if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit - if (reverse ) x = virtualWidth() - x - 1; - if (reverse_y) y = virtualHeight() - y - 1; + int vW = vWidth(); + int vH = vHeight(); + if (x >= vW || y >= vH || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit + if (reverse ) x = vW - x - 1; + if (reverse_y) y = vH - y - 1; if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed x *= groupLength(); // expand to physical pixels y *= groupLength(); // expand to physical pixels @@ -274,10 +274,10 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const { } // blurRow: perform a blur on a row of a rectangular matrix -void Segment::blurRow(uint32_t row, fract8 blur_amount, bool smear){ +void Segment::blurRow(int row, fract8 blur_amount, bool smear){ if (!isActive() || blur_amount == 0) return; // not active - const unsigned cols = virtualWidth(); - const unsigned rows = virtualHeight(); + const int cols = vWidth(); + const int rows = vHeight(); if (row >= rows) return; // blur one row @@ -287,7 +287,7 @@ void Segment::blurRow(uint32_t row, fract8 blur_amount, bool smear){ uint32_t lastnew; uint32_t last; uint32_t curnew = BLACK; - for (unsigned x = 0; x < cols; x++) { + for (int x = 0; x < cols; x++) { uint32_t cur = getPixelColorXY(x, row); uint32_t part = color_fade(cur, seep); curnew = color_fade(cur, keep); @@ -306,10 +306,10 @@ void Segment::blurRow(uint32_t row, fract8 blur_amount, bool smear){ } // blurCol: perform a blur on a column of a rectangular matrix -void Segment::blurCol(uint32_t col, fract8 blur_amount, bool smear) { +void Segment::blurCol(int col, fract8 blur_amount, bool smear) { if (!isActive() || blur_amount == 0) return; // not active - const unsigned cols = virtualWidth(); - const unsigned rows = virtualHeight(); + const int cols = vWidth(); + const int rows = vHeight(); if (col >= cols) return; // blur one column @@ -319,7 +319,7 @@ void Segment::blurCol(uint32_t col, fract8 blur_amount, bool smear) { uint32_t lastnew; uint32_t last; uint32_t curnew = BLACK; - for (unsigned y = 0; y < rows; y++) { + for (int y = 0; y < rows; y++) { uint32_t cur = getPixelColorXY(col, y); uint32_t part = color_fade(cur, seep); curnew = color_fade(cur, keep); @@ -339,8 +339,8 @@ void Segment::blurCol(uint32_t col, fract8 blur_amount, bool smear) { void Segment::blur2D(uint8_t blur_amount, bool smear) { if (!isActive() || blur_amount == 0) return; // not active - const unsigned cols = virtualWidth(); - const unsigned rows = virtualHeight(); + const unsigned cols = vWidth(); + const unsigned rows = vHeight(); const uint8_t keep = smear ? 255 : 255 - blur_amount; const uint8_t seep = blur_amount >> (1 + smear); @@ -391,8 +391,8 @@ void Segment::box_blur(unsigned radius, bool smear) { if (!isActive() || radius == 0) return; // not active if (radius > 3) radius = 3; const unsigned d = (1 + 2*radius) * (1 + 2*radius); // averaging divisor - const unsigned cols = virtualWidth(); - const unsigned rows = virtualHeight(); + const unsigned cols = vWidth(); + const unsigned rows = vHeight(); uint16_t *tmpRSum = new uint16_t[cols*rows]; uint16_t *tmpGSum = new uint16_t[cols*rows]; uint16_t *tmpBSum = new uint16_t[cols*rows]; @@ -461,37 +461,37 @@ void Segment::box_blur(unsigned radius, bool smear) { void Segment::moveX(int8_t delta, bool wrap) { if (!isActive()) return; // not active - const int cols = virtualWidth(); - const int rows = virtualHeight(); - if (!delta || abs(delta) >= cols) return; - uint32_t newPxCol[cols]; - for (int y = 0; y < rows; y++) { + const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) + const int vH = vHeight(); // segment height in logical pixels (is always >= 1) + if (!delta || abs(delta) >= vW) return; + uint32_t newPxCol[vW]; + for (int y = 0; y < vH; y++) { if (delta > 0) { - for (int x = 0; x < cols-delta; x++) newPxCol[x] = getPixelColorXY((x + delta), y); - for (int x = cols-delta; x < cols; x++) newPxCol[x] = getPixelColorXY(wrap ? (x + delta) - cols : x, y); + for (int x = 0; x < vW-delta; x++) newPxCol[x] = getPixelColorXY((x + delta), y); + for (int x = vW-delta; x < vW; x++) newPxCol[x] = getPixelColorXY(wrap ? (x + delta) - vW : x, y); } else { - for (int x = cols-1; x >= -delta; x--) newPxCol[x] = getPixelColorXY((x + delta), y); - for (int x = -delta-1; x >= 0; x--) newPxCol[x] = getPixelColorXY(wrap ? (x + delta) + cols : x, y); + for (int x = vW-1; x >= -delta; x--) newPxCol[x] = getPixelColorXY((x + delta), y); + for (int x = -delta-1; x >= 0; x--) newPxCol[x] = getPixelColorXY(wrap ? (x + delta) + vW : x, y); } - for (int x = 0; x < cols; x++) setPixelColorXY(x, y, newPxCol[x]); + for (int x = 0; x < vW; x++) setPixelColorXY(x, y, newPxCol[x]); } } void Segment::moveY(int8_t delta, bool wrap) { if (!isActive()) return; // not active - const int cols = virtualWidth(); - const int rows = virtualHeight(); - if (!delta || abs(delta) >= rows) return; - uint32_t newPxCol[rows]; - for (int x = 0; x < cols; x++) { + const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) + const int vH = vHeight(); // segment height in logical pixels (is always >= 1) + if (!delta || abs(delta) >= vH) return; + uint32_t newPxCol[vH]; + for (int x = 0; x < vW; x++) { if (delta > 0) { - for (int y = 0; y < rows-delta; y++) newPxCol[y] = getPixelColorXY(x, (y + delta)); - for (int y = rows-delta; y < rows; y++) newPxCol[y] = getPixelColorXY(x, wrap ? (y + delta) - rows : y); + for (int y = 0; y < vH-delta; y++) newPxCol[y] = getPixelColorXY(x, (y + delta)); + for (int y = vH-delta; y < vH; y++) newPxCol[y] = getPixelColorXY(x, wrap ? (y + delta) - vH : y); } else { - for (int y = rows-1; y >= -delta; y--) newPxCol[y] = getPixelColorXY(x, (y + delta)); - for (int y = -delta-1; y >= 0; y--) newPxCol[y] = getPixelColorXY(x, wrap ? (y + delta) + rows : y); + for (int y = vH-1; y >= -delta; y--) newPxCol[y] = getPixelColorXY(x, (y + delta)); + for (int y = -delta-1; y >= 0; y--) newPxCol[y] = getPixelColorXY(x, wrap ? (y + delta) + vH : y); } - for (int y = 0; y < rows; y++) setPixelColorXY(x, y, newPxCol[y]); + for (int y = 0; y < vH; y++) setPixelColorXY(x, y, newPxCol[y]); } } @@ -545,18 +545,20 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, x++; } } else { + // pre-scale color for all pixels + col = color_fade(col, currentBri()); // Bresenham’s Algorithm int d = 3 - (2*radius); int y = radius, x = 0; while (y >= x) { - setPixelColorXY(cx+x, cy+y, col); - setPixelColorXY(cx-x, cy+y, col); - setPixelColorXY(cx+x, cy-y, col); - setPixelColorXY(cx-x, cy-y, col); - setPixelColorXY(cx+y, cy+x, col); - setPixelColorXY(cx-y, cy+x, col); - setPixelColorXY(cx+y, cy-x, col); - setPixelColorXY(cx-y, cy-x, col); + setPixelColorXY(cx+x, cy+y, col, false); + setPixelColorXY(cx-x, cy+y, col, false); + setPixelColorXY(cx+x, cy-y, col, false); + setPixelColorXY(cx-x, cy-y, col, false); + setPixelColorXY(cx+y, cy+x, col, false); + setPixelColorXY(cx-y, cy+x, col, false); + setPixelColorXY(cx+y, cy-x, col, false); + setPixelColorXY(cx-y, cy-x, col, false); x++; if (d > 0) { y--; @@ -571,17 +573,19 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, // by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs void Segment::fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, bool soft) { if (!isActive() || radius == 0) return; // not active + const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) + const int vH = vHeight(); // segment height in logical pixels (is always >= 1) // draw soft bounding circle if (soft) drawCircle(cx, cy, radius, col, soft); + // pre-scale color for all pixels + col = color_fade(col, currentBri()); // fill it - const int cols = virtualWidth(); - const int rows = virtualHeight(); for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius && - int(cx)+x>=0 && int(cy)+y>=0 && - int(cx)+x= 0 && int(cy)+y >= 0 && + int(cx)+x < vW && int(cy)+y < vH) + setPixelColorXY(cx + x, cy + y, col, false); } } } @@ -589,9 +593,9 @@ void Segment::fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, //line function void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft) { if (!isActive()) return; // not active - const int cols = virtualWidth(); - const int rows = virtualHeight(); - if (x0 >= cols || x1 >= cols || y0 >= rows || y1 >= rows) return; + const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) + const int vH = vHeight(); // segment height in logical pixels (is always >= 1) + if (x0 >= vW || x1 >= vW || y0 >= vH || y1 >= vH) return; const int dx = abs(x1-x0), sx = x0dy ? dx : -dy)/2; // error direction for (;;) { - setPixelColorXY(x0, y0, c); + setPixelColorXY(x0, y0, c, false); if (x0==x1 && y0==y1) break; int e2 = err; if (e2 >-dx) { err -= dy; x0 += sx; } @@ -653,8 +659,6 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, if (!isActive()) return; // not active if (chr < 32 || chr > 126) return; // only ASCII 32-126 supported chr -= 32; // align with font table entries - const int cols = virtualWidth(); - const int rows = virtualHeight(); const int font = w*h; CRGB col = CRGB(color); @@ -681,7 +685,7 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, case 1: x0 = x + i; y0 = y + j; break; // +90 deg default: x0 = x + (w-1) - j; y0 = y + i; break; // no rotation } - if (x0 < 0 || x0 >= cols || y0 < 0 || y0 >= rows) continue; // drawing off-screen + if (x0 < 0 || x0 >= (int)vWidth() || y0 < 0 || y0 >= (int)vHeight()) continue; // drawing off-screen if (((bits>>(j+(8-w))) & 0x01)) { // bit set setPixelColorXY(x0, y0, col); } diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index a98755425..a47a7edc9 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -80,15 +80,18 @@ static constexpr bool validatePinsAndTypes(const unsigned* types, unsigned numTy /////////////////////////////////////////////////////////////////////////////// // Segment class implementation /////////////////////////////////////////////////////////////////////////////// -uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for their data[] -uint16_t Segment::maxWidth = DEFAULT_LED_COUNT; -uint16_t Segment::maxHeight = 1; - +uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for their data[] +uint16_t Segment::maxWidth = DEFAULT_LED_COUNT; +uint16_t Segment::maxHeight = 1; +unsigned Segment::_vLength = 0; +unsigned Segment::_vWidth = 0; +unsigned Segment::_vHeight = 0; +uint32_t Segment::_currentColors[NUM_COLORS] = {0,0,0}; CRGBPalette16 Segment::_currentPalette = CRGBPalette16(CRGB::Black); CRGBPalette16 Segment::_randomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR); CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR); uint16_t Segment::_lastPaletteChange = 0; // perhaps it should be per segment -uint16_t Segment::_lastPaletteBlend = 0; //in millis (lowest 16 bits only) +uint16_t Segment::_lastPaletteBlend = 0; // in millis (lowest 16 bits only) #ifndef WLED_DISABLE_MODE_BLEND bool Segment::_modeBlend = false; @@ -437,7 +440,21 @@ uint32_t IRAM_ATTR_YN Segment::currentColor(uint8_t slot) const { #endif } -void Segment::setCurrentPalette() { +// pre-calculate drawing parameters for faster access +void Segment::beginDraw() { + _vWidth = virtualWidth(); + _vHeight = virtualHeight(); + _vLength = virtualLength(); + // adjust gamma for effects + for (unsigned i = 0; i < NUM_COLORS; i++) { + #ifndef WLED_DISABLE_MODE_BLEND + uint32_t col = isInTransition() ? color_blend(_t->_segT._colorT[i], colors[i], progress(), true) : colors[i]; + #else + uint32_t col = isInTransition() ? color_blend(_t->_colorT[i], colors[i], progress(), true) : colors[i]; + #endif + _currentColors[i] = gamma32(col); + } + // load palette into _currentPalette loadPalette(_currentPalette, palette); unsigned prog = progress(); if (strip.paletteFade && prog < 0xFFFFU) { @@ -698,20 +715,21 @@ uint16_t IRAM_ATTR Segment::virtualLength() const { return vLength; } -void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) +void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col, bool unScaled) { if (!isActive() || i < 0) return; // not active or invalid index #ifndef WLED_DISABLE_2D int vStrip = 0; #endif + int vL = vLength(); // if the 1D effect is using virtual strips "i" will have virtual strip id stored in upper 16 bits // in such case "i" will be > virtualLength() - if (i >= virtualLength()) { + if (i >= vL) { // check if this is a virtual strip #ifndef WLED_DISABLE_2D vStrip = i>>16; // hack to allow running on virtual strips (2D segment columns/rows) i &= 0xFFFF; //truncate vstrip index - if (i >= virtualLength()) return; // if pixel would still fall out of segment just exit + if (i >= vL) return; // if pixel would still fall out of segment just exit #else return; #endif @@ -719,22 +737,24 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) #ifndef WLED_DISABLE_2D if (is2D()) { - int vH = virtualHeight(); // segment height in logical pixels - int vW = virtualWidth(); + const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) + const int vH = vHeight(); // segment height in logical pixels (is always >= 1) + // pre-scale color for all pixels + col = color_fade(col, currentBri()); switch (map1D2D) { case M12_Pixels: // use all available pixels as a long strip - setPixelColorXY(i % vW, i / vW, col); + setPixelColorXY(i % vW, i / vW, col, false); break; case M12_pBar: // expand 1D effect vertically or have it play on virtual strips - if (vStrip > 0) setPixelColorXY(vStrip - 1, vH - i - 1, col); - else for (int x = 0; x < vW; x++) setPixelColorXY(x, vH - i - 1, col); + if (vStrip > 0) setPixelColorXY(vStrip - 1, vH - i - 1, col, false); + else for (int x = 0; x < vW; x++) setPixelColorXY(x, vH - i - 1, col, false); break; case M12_pArc: // expand in circular fashion from center if (i == 0) - setPixelColorXY(0, 0, col); + setPixelColorXY(0, 0, col, false); else { float r = i; float step = HALF_PI / (2.8284f * r + 4); // we only need (PI/4)/(r/sqrt(2)+1) steps @@ -742,8 +762,8 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) int x = roundf(sin_t(rad) * r); int y = roundf(cos_t(rad) * r); // exploit symmetry - setPixelColorXY(x, y, col); - setPixelColorXY(y, x, col); + setPixelColorXY(x, y, col, false); + setPixelColorXY(y, x, col, false); } // Bresenham’s Algorithm (may not fill every pixel) //int d = 3 - (2*i); @@ -762,8 +782,8 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) } break; case M12_pCorner: - for (int x = 0; x <= i; x++) setPixelColorXY(x, i, col); - for (int y = 0; y < i; y++) setPixelColorXY(i, y, col); + for (int x = 0; x <= i; x++) setPixelColorXY(x, i, col, false); + for (int y = 0; y < i; y++) setPixelColorXY(i, y, col, false); break; case M12_sPinwheel: { // i = angle --> 0 - 296 (Big), 0 - 192 (Medium), 0 - 72 (Small) @@ -802,7 +822,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) int x = posx / Fixed_Scale; int y = posy / Fixed_Scale; // set pixel - if (x != lastX || y != lastY) setPixelColorXY(x, y, col); // only paint if pixel position is different + if (x != lastX || y != lastY) setPixelColorXY(x, y, col, false); // only paint if pixel position is different lastX = x; lastY = y; // advance to next position @@ -813,12 +833,12 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) } } return; - } else if (Segment::maxHeight!=1 && (width()==1 || height()==1)) { + } else if (Segment::maxHeight != 1 && (width() == 1 || height() == 1)) { if (start < Segment::maxWidth*Segment::maxHeight) { // we have a vertical or horizontal 1D segment (WARNING: virtual...() may be transposed) int x = 0, y = 0; - if (virtualHeight()>1) y = i; - if (virtualWidth() >1) x = i; + if (vHeight() > 1) y = i; + if (vWidth() > 1) x = i; setPixelColorXY(x, y, col); return; } @@ -826,10 +846,8 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) #endif unsigned len = length(); - uint8_t _bri_t = currentBri(); - if (_bri_t < 255) { - col = color_fade(col, _bri_t); - } + // if color is unscaled + if (unScaled) col = color_fade(col, currentBri()); // expand pixel (taking into account start, grouping, spacing [and offset]) i = i * groupLength(); @@ -907,8 +925,8 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const #ifndef WLED_DISABLE_2D if (is2D()) { - int vH = virtualHeight(); // segment height in logical pixels - int vW = virtualWidth(); + const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) + const int vH = vHeight(); // segment height in logical pixels (is always >= 1) switch (map1D2D) { case M12_Pixels: return getPixelColorXY(i % vW, i / vW); @@ -961,7 +979,7 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const } #endif - if (reverse) i = virtualLength() - i - 1; + if (reverse) i = vLength() - i - 1; i *= groupLength(); i += start; // offset/phase @@ -1050,11 +1068,13 @@ void Segment::refreshLightCapabilities() { */ void Segment::fill(uint32_t c) { if (!isActive()) return; // not active - const int cols = is2D() ? virtualWidth() : virtualLength(); - const int rows = virtualHeight(); // will be 1 for 1D + const int cols = is2D() ? vWidth() : vLength(); + const int rows = vHeight(); // will be 1 for 1D + // pre-scale color for all pixels + c = color_fade(c, currentBri()); for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) { - if (is2D()) setPixelColorXY(x, y, c); - else setPixelColor(x, c); + if (is2D()) setPixelColorXY(x, y, c, false); + else setPixelColor(x, c, false); } } @@ -1063,8 +1083,8 @@ void Segment::fill(uint32_t c) { */ void Segment::fade_out(uint8_t rate) { if (!isActive()) return; // not active - const int cols = is2D() ? virtualWidth() : virtualLength(); - const int rows = virtualHeight(); // will be 1 for 1D + const int cols = is2D() ? vWidth() : vLength(); + const int rows = vHeight(); // will be 1 for 1D rate = (255-rate) >> 1; float mappedRate = 1.0f / (float(rate) + 1.1f); @@ -1102,8 +1122,8 @@ void Segment::fade_out(uint8_t rate) { // fades all pixels to black using nscale8() void Segment::fadeToBlackBy(uint8_t fadeBy) { if (!isActive() || fadeBy == 0) return; // optimization - no scaling to apply - const int cols = is2D() ? virtualWidth() : virtualLength(); - const int rows = virtualHeight(); // will be 1 for 1D + const int cols = is2D() ? vWidth() : vLength(); + const int rows = vHeight(); // will be 1 for 1D for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) { if (is2D()) setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), 255-fadeBy)); @@ -1126,7 +1146,7 @@ void Segment::blur(uint8_t blur_amount, bool smear) { #endif uint8_t keep = smear ? 255 : 255 - blur_amount; uint8_t seep = blur_amount >> (1 + smear); - unsigned vlength = virtualLength(); + unsigned vlength = vLength(); uint32_t carryover = BLACK; uint32_t lastnew; uint32_t last; @@ -1140,8 +1160,7 @@ void Segment::blur(uint8_t blur_amount, bool smear) { uint32_t prev = color_add(lastnew, part); // optimization: only set pixel if color has changed if (last != prev) setPixelColor(i - 1, prev); - } else // first pixel - setPixelColor(i, curnew); + } else setPixelColor(i, curnew); // first pixel lastnew = curnew; last = cur; // save original value for comparison on next iteration carryover = part; @@ -1156,7 +1175,7 @@ void Segment::blur(uint8_t blur_amount, bool smear) { */ uint32_t Segment::color_wheel(uint8_t pos) const { if (palette) return color_from_palette(pos, false, true, 0); // perhaps "strip.paletteBlend < 2" should be better instead of "true" - uint8_t w = W(currentColor(0)); + uint8_t w = W(getCurrentColor(0)); pos = 255 - pos; if (pos < 85) { return RGBW32((255 - pos * 3), 0, (pos * 3), w); @@ -1179,20 +1198,19 @@ uint32_t Segment::color_wheel(uint8_t pos) const { * @returns Single color from palette */ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) const { - - uint32_t color = currentColor(mcol); + uint32_t color = getCurrentColor(mcol < NUM_COLORS ? mcol : 0); // default palette or no RGB support on segment if ((palette == 0 && mcol < NUM_COLORS) || !_isRGB) { - color = gamma32(color); - return (pbri == 255) ? color : color_fade(color, pbri, true); + return color_fade(color, pbri, true); } + const int vL = vLength(); unsigned paletteIndex = i; - if (mapping && virtualLength() > 1) paletteIndex = (i*255)/(virtualLength() -1); + if (mapping && vL > 1) paletteIndex = (i*255)/(vL -1); // paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined) if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end" CRGBW palcol = ColorFromPalette(_currentPalette, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global - palcol.w = gamma8(W(color)); + palcol.w = W(color); return palcol.color32; } @@ -1359,11 +1377,6 @@ void WS2812FX::service() { if (!seg.freeze) { //only run effect function if not frozen int oldCCT = BusManager::getSegmentCCT(); // store original CCT value (actually it is not Segment based) - _virtualSegmentLength = seg.virtualLength(); //SEGLEN - _colors_t[0] = gamma32(seg.currentColor(0)); - _colors_t[1] = gamma32(seg.currentColor(1)); - _colors_t[2] = gamma32(seg.currentColor(2)); - seg.setCurrentPalette(); // load actual palette // when correctWB is true we need to correct/adjust RGB value according to desired CCT value, but it will also affect actual WW/CW ratio // when cctFromRgb is true we implicitly calculate WW and CW from RGB values if (cctFromRgb) BusManager::setSegmentCCT(-1); @@ -1375,13 +1388,14 @@ void WS2812FX::service() { // overwritten by later effect. To enable seamless blending for every effect, additional LED buffer // would need to be allocated for each effect and then blended together for each pixel. [[maybe_unused]] uint8_t tmpMode = seg.currentMode(); // this will return old mode while in transition + seg.beginDraw(); // set up parameters for get/setPixelColor() delay = (*_mode[seg.mode])(); // run new/current mode #ifndef WLED_DISABLE_MODE_BLEND if (modeBlending && seg.mode != tmpMode) { Segment::tmpsegd_t _tmpSegData; Segment::modeBlend(true); // set semaphore seg.swapSegenv(_tmpSegData); // temporarily store new mode state (and swap it with transitional state) - _virtualSegmentLength = seg.virtualLength(); // update SEGLEN (mapping may have changed) + seg.beginDraw(); // set up parameters for get/setPixelColor() unsigned d2 = (*_mode[tmpMode])(); // run old mode seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state) delay = MIN(delay,d2); // use shortest delay @@ -1397,7 +1411,6 @@ void WS2812FX::service() { } _segment_index++; } - _virtualSegmentLength = 0; _isServicing = false; _triggered = false; diff --git a/wled00/udp.cpp b/wled00/udp.cpp index 60774d701..a615cefcb 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -416,18 +416,18 @@ void realtimeLock(uint32_t timeoutMs, byte md) start = mainseg.start; stop = mainseg.stop; mainseg.freeze = true; + // if WLED was off and using main segment only, freeze non-main segments so they stay off + if (bri == 0) { + for (size_t s = 0; s < strip.getSegmentsNum(); s++) { + strip.getSegment(s).freeze = true; + } + } } else { start = 0; stop = strip.getLengthTotal(); } // clear strip/segment for (size_t i = start; i < stop; i++) strip.setPixelColor(i,BLACK); - // if WLED was off and using main segment only, freeze non-main segments so they stay off - if (useMainSegmentOnly && bri == 0) { - for (size_t s=0; s < strip.getSegmentsNum(); s++) { - strip.getSegment(s).freeze = true; - } - } } // if strip is off (bri==0) and not already in RTM if (briT == 0 && !realtimeMode && !realtimeOverride) { @@ -510,12 +510,10 @@ void handleNotifications() rgbUdp.read(lbuf, packetSize); realtimeLock(realtimeTimeoutMs, REALTIME_MODE_HYPERION); if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return; - unsigned id = 0; unsigned totalLen = strip.getLengthTotal(); - for (size_t i = 0; i < packetSize -2; i += 3) - { + if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); // set up parameters for get/setPixelColor() + for (size_t i = 0, id = 0; i < packetSize -2 && id < totalLen; i += 3, id++) { setRealtimePixel(id, lbuf[i], lbuf[i+1], lbuf[i+2], 0); - id++; if (id >= totalLen) break; } if (!(realtimeMode && useMainSegmentOnly)) strip.show(); return; @@ -595,17 +593,11 @@ void handleNotifications() unsigned id = (tpmPayloadFrameSize/3)*(packetNum-1); //start LED unsigned totalLen = strip.getLengthTotal(); - for (size_t i = 6; i < tpmPayloadFrameSize + 4U; i += 3) - { - if (id < totalLen) - { - setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0); - id++; - } - else break; + if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); // set up parameters for get/setPixelColor() + for (size_t i = 6; i < tpmPayloadFrameSize + 4U && id < totalLen; i += 3, id++) { + setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0); } - if (tpmPacketCount == numPackets) //reset packet count and show if all packets were received - { + if (tpmPacketCount == numPackets) { //reset packet count and show if all packets were received tpmPacketCount = 0; strip.show(); } @@ -629,6 +621,7 @@ void handleNotifications() if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return; unsigned totalLen = strip.getLengthTotal(); + if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); // set up parameters for get/setPixelColor() if (udpIn[0] == 1 && packetSize > 5) //warls { for (size_t i = 2; i < packetSize -3; i += 4) @@ -637,39 +630,29 @@ void handleNotifications() } } else if (udpIn[0] == 2 && packetSize > 4) //drgb { - unsigned id = 0; - for (size_t i = 2; i < packetSize -2; i += 3) + for (size_t i = 2, id = 0; i < packetSize -2 && id < totalLen; i += 3, id++) { setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0); - - id++; if (id >= totalLen) break; } } else if (udpIn[0] == 3 && packetSize > 6) //drgbw { - unsigned id = 0; - for (size_t i = 2; i < packetSize -3; i += 4) + for (size_t i = 2, id = 0; i < packetSize -3 && id < totalLen; i += 4, id++) { setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]); - - id++; if (id >= totalLen) break; } } else if (udpIn[0] == 4 && packetSize > 7) //dnrgb { unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00); - for (size_t i = 4; i < packetSize -2; i += 3) + for (size_t i = 4; i < packetSize -2 && id < totalLen; i += 3, id++) { - if (id >= totalLen) break; setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0); - id++; } } else if (udpIn[0] == 5 && packetSize > 8) //dnrgbw { unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00); - for (size_t i = 4; i < packetSize -2; i += 4) + for (size_t i = 4; i < packetSize -2 && id < totalLen; i += 4, id++) { - if (id >= totalLen) break; setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]); - id++; } } strip.show(); @@ -705,8 +688,7 @@ void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w) w = gamma8(w); } if (useMainSegmentOnly) { - Segment &seg = strip.getMainSegment(); - if (pix10) return; + char nS[32]; if (subPage == SUBPAGE_MENU) { @@ -259,8 +260,6 @@ void getSettingsJS(byte subPage, Print& settingsScript) if (subPage == SUBPAGE_LEDS) { - char nS[32]; - appendGPIOinfo(settingsScript); settingsScript.print(SET_F("d.ledTypes=")); settingsScript.print(BusManager::getLEDTypesJSONString().c_str()); settingsScript.print(";"); @@ -399,7 +398,6 @@ void getSettingsJS(byte subPage, Print& settingsScript) if (subPage == SUBPAGE_SYNC) { - [[maybe_unused]] char nS[32]; printSetFormValue(settingsScript,PSTR("UP"),udpPort); printSetFormValue(settingsScript,PSTR("U2"),udpPort2); #ifndef WLED_DISABLE_ESPNOW From 6f221852a262d9f2ba6f6817b1284990d8f4f54d Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sat, 28 Sep 2024 18:25:16 +0200 Subject: [PATCH 042/234] partition file for 512Kb Filesystem, 1.7MB Program the missing link between 256KB (very small FS) and 700KB (only 100KB extra program) --- tools/WLED_ESP32_4MB_512KB_FS.csv | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tools/WLED_ESP32_4MB_512KB_FS.csv diff --git a/tools/WLED_ESP32_4MB_512KB_FS.csv b/tools/WLED_ESP32_4MB_512KB_FS.csv new file mode 100644 index 000000000..5281a6124 --- /dev/null +++ b/tools/WLED_ESP32_4MB_512KB_FS.csv @@ -0,0 +1,7 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, 0xe000, 0x2000, +app0, app, ota_0, 0x10000, 0x1B0000, +app1, app, ota_1, 0x1C0000,0x1B0000, +spiffs, data, spiffs, 0x370000,0x80000, +coredump, data, coredump,,64K \ No newline at end of file From 9114867578477e4cf5fa652769ea0690503c5f10 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sat, 28 Sep 2024 18:48:43 +0200 Subject: [PATCH 043/234] Fix compiler error --- wled00/FX.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.h b/wled00/FX.h index 98082c8d8..b4aaf3c48 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -833,7 +833,7 @@ class WS2812FX { // 96 bytes addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name); // add effect to the list; defined in FX.cpp; inline uint8_t getBrightness() const { return _brightness; } // returns current strip brightness - inline constexpr unsigned getMaxSegments() { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value) + inline static constexpr unsigned getMaxSegments() { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value) inline uint8_t getSegmentsNum() const { return _segments.size(); } // returns currently present segments inline uint8_t getCurrSegmentId() const { return _segment_index; } // returns current segment index (only valid while strip.isServicing()) inline uint8_t getMainSegmentId() const { return _mainSegment; } // returns main segment index From 10d8cfde8555bb3b817ede0e7dbeb45d02a38517 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sun, 29 Sep 2024 13:00:07 +0200 Subject: [PATCH 044/234] Fix FX filter bug --- wled00/data/index.css | 15 ++++++++++----- wled00/data/index.js | 32 ++++++++++++++++++++++---------- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/wled00/data/index.css b/wled00/data/index.css index 0952cca21..c4e85f73f 100644 --- a/wled00/data/index.css +++ b/wled00/data/index.css @@ -35,6 +35,7 @@ --sgp: "block"; --bmt: 0; --sti: 42px; + --stp: 42px; } html { @@ -468,7 +469,7 @@ button { padding: 4px 2px; position: relative; opacity: 1; - transition: opacity .5s linear, height .25s, transform .25s; + transition: opacity .25s linear, height .2s, transform .2s; } .filter { @@ -1335,10 +1336,12 @@ TD .checkmark, TD .radiomark { top: 42px; } -#fxlist .lstI.selected, -#pallist .lstI.selected { +#fxlist .lstI.selected { top: calc(var(--sti) + 42px); } +#pallist .lstI.selected { + top: calc(var(--stp) + 42px); +} dialog::backdrop { backdrop-filter: blur(10px); @@ -1353,10 +1356,12 @@ dialog { color: var(--c-f); } -#fxlist .lstI.sticky, -#pallist .lstI.sticky { +#fxlist .lstI.sticky { top: var(--sti); } +#pallist .lstI.sticky { + top: var(--stp); +} /* list item content */ .lstIcontent { diff --git a/wled00/data/index.js b/wled00/data/index.js index 25ade1163..d9c64bdfb 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -2828,7 +2828,12 @@ function search(field, listId = null) { // restore default preset sorting if no search term is entered if (!search) { if (listId === 'pcont') { populatePresets(); return; } - if (listId === 'pallist') { populatePalettes(); return; } + if (listId === 'pallist') { + let id = parseInt(d.querySelector('#pallist input[name="palette"]:checked').value); // preserve selected palette + populatePalettes(); + updateSelectedPalette(id); + return; + } } // clear filter if searching in fxlist @@ -2887,18 +2892,25 @@ function initFilters() { function filterFocus(e) { const f = gId("filters"); - if (e.type === "focus") f.classList.remove('fade'); // immediately show (still has transition) - // compute sticky top (with delay for transition) - setTimeout(() => { - const sti = parseInt(getComputedStyle(d.documentElement).getPropertyValue('--sti')) + (e.type === "focus" ? 1 : -1) * f.offsetHeight; - sCol('--sti', sti + "px"); - }, 252); + const c = !!f.querySelectorAll("input[type=checkbox]:checked").length; + const h = f.offsetHeight; + const sti = parseInt(getComputedStyle(d.documentElement).getPropertyValue('--sti')); + if (e.type === "focus") { + // compute sticky top (with delay for transition) + if (!h) setTimeout(() => { + sCol('--sti', (sti+f.offsetHeight) + "px"); // has an unpleasant consequence on palette offset + }, 255); + f.classList.remove('fade'); // immediately show (still has transition) + } if (e.type === "blur") { setTimeout(() => { if (e.target === document.activeElement && document.hasFocus()) return; // do not hide if filter is active - if (gId("filters").querySelectorAll("input[type=checkbox]:checked").length) return; - f.classList.add('fade'); + if (!c) { + // compute sticky top + sCol('--sti', (sti-h) + "px"); // has an unpleasant consequence on palette offset + f.classList.add('fade'); + } }, 255); // wait with hiding } } @@ -2911,7 +2923,7 @@ function filterFx() { gId("fxlist").querySelectorAll('.lstI').forEach((listItem,i) => { const listItemName = listItem.querySelector('.lstIname').innerText; let hide = false; - gId("filters").querySelectorAll("input[type=checkbox]").forEach((e) => { if (e.checked && !listItemName.includes(e.dataset.flt)) hide = true; }); + gId("filters").querySelectorAll("input[type=checkbox]").forEach((e) => { if (e.checked && !listItemName.includes(e.dataset.flt)) hide = i>0 /*true*/; }); listItem.style.display = hide ? 'none' : ''; }); } From ffbc8c5f709461f96c557e5dc9162c8f3e5c6004 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 29 Sep 2024 13:55:00 +0200 Subject: [PATCH 045/234] Reverting addition of `bool unScale`, added new improvements and fixes - Added pre-calculation for segment brightness: stored in _segBri. The impact on FPS is not huge but measurable (~1-2FPS in my test conditions) - Removed `bool unScaled` from `setPixelColor()` function again (it has no/minimal impact on speed but huge impact on flash usage: +850 bytes) - Removed negative checking in `setPixelColorXY()` and replaced it with a local typecast to unsigned, saves a few instructions (tested and working) - Changed int8_t to int in `moveX()` and `moveY()` - Removed a few functions from IRAM as they are now not called for every pixel but only once per segment update - Removed a `virtualWidth()` call from `ripple_base()` - Bugfix in `mode_colortwinkle()` --- wled00/FX.cpp | 4 ++-- wled00/FX.h | 26 ++++++++++++------------- wled00/FX_2Dfcn.cpp | 40 ++++++++++++++++---------------------- wled00/FX_fcn.cpp | 47 ++++++++++++++++++++++----------------------- 4 files changed, 55 insertions(+), 62 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 2ec31014f..77167b02d 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2294,7 +2294,7 @@ uint16_t mode_colortwinkle() { bool fadeUp = bitRead(SEGENV.data[index], bitNum); if (fadeUp) { - CRGBW incrementalColor = color_fade(col, fadeUpAmount, true); + CRGBW incrementalColor = color_fade(cur, fadeUpAmount, true); col = color_add(cur, incrementalColor); if (col.r == 255 || col.g == 255 || col.b == 255) { @@ -2528,7 +2528,7 @@ static uint16_t ripple_base() { } else {//randomly create new wave if (random16(IBN + 10000) <= (SEGMENT.intensity >> (SEGMENT.is2D()*3))) { ripples[i].state = 1; - ripples[i].pos = SEGMENT.is2D() ? ((random8(SEGENV.virtualWidth())<<8) | (random8(SEGENV.virtualHeight()))) : random16(SEGLEN); + ripples[i].pos = SEGMENT.is2D() ? ((random8(SEG_W)<<8) | (random8(SEG_H))) : random16(SEGLEN); ripples[i].color = random8(); //color } } diff --git a/wled00/FX.h b/wled00/FX.h index b4aaf3c48..8a452cfcb 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -420,8 +420,8 @@ typedef struct Segment { }; uint16_t _dataLen; static uint16_t _usedSegmentData; - - static unsigned _vLength; // 1D dimension used for current effect + static uint8_t _segBri; // Current brightness of segment + static unsigned _vLength; // 1D dimension used for current effect static unsigned _vWidth, _vHeight; // 2D dimensions used for current effect static uint32_t _currentColors[NUM_COLORS]; // colors used for current effect static CRGBPalette16 _currentPalette; // palette used for current effect (includes transition, used in color_from_palette()) @@ -546,7 +546,7 @@ typedef struct Segment { inline static unsigned vHeight() { return Segment::_vHeight; } inline static uint32_t getCurrentColor(unsigned i) { return Segment::_currentColors[i]; } // { return i < 3 ? Segment::_currentColors[i] : 0; } inline static const CRGBPalette16 &getCurrentPalette() { return Segment::_currentPalette; } - + inline static uint8_t getCurrentBrightness() { return Segment::_segBri; } static void handleRandomPalette(); void beginDraw(); // set up parameters for current effect @@ -589,8 +589,8 @@ typedef struct Segment { // 1D strip [[gnu::hot]] uint16_t virtualLength() const; - [[gnu::hot]] void setPixelColor(int n, uint32_t c, bool unScaled = true); // set relative pixel within segment with color - inline void setPixelColor(unsigned n, uint32_t c, bool unScaled = true) { setPixelColor(int(n), c, unScaled); } + [[gnu::hot]] void setPixelColor(int n, uint32_t c); // set relative pixel within segment with color + inline void setPixelColor(unsigned n, uint32_t c) { setPixelColor(int(n), c); } inline void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } inline void setPixelColor(int n, CRGB c) { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } #ifdef WLED_USE_AA_PIXELS @@ -629,8 +629,8 @@ typedef struct Segment { uint16_t nrOfVStrips() const; // returns number of virtual vertical strips in 2D matrix (used to expand 1D effects into 2D) #ifndef WLED_DISABLE_2D [[gnu::hot]] uint16_t XY(int x, int y); // support function to get relative index within segment - [[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c, bool unScaled = true); // set relative pixel within segment with color - inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c, bool unScaled = true) { setPixelColorXY(int(x), int(y), c, unScaled); } + [[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color + inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColorXY(int(x), int(y), c); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColorXY(int(x), int(y), RGBW32(c.r,c.g,c.b,0)); } @@ -651,8 +651,8 @@ typedef struct Segment { void blur2D(uint8_t blur_amount, bool smear = false); void blurRow(int row, fract8 blur_amount, bool smear = false); void blurCol(int col, fract8 blur_amount, bool smear = false); - void moveX(int8_t delta, bool wrap = false); - void moveY(int8_t delta, bool wrap = false); + void moveX(int delta, bool wrap = false); + void moveY(int delta, bool wrap = false); void move(uint8_t dir, uint8_t delta, bool wrap = false); void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false); inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) { drawCircle(cx, cy, radius, RGBW32(c.r,c.g,c.b,0), soft); } @@ -668,8 +668,8 @@ typedef struct Segment { inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); } #else inline uint16_t XY(int x, int y) { return x; } - inline void setPixelColorXY(int x, int y, uint32_t c, bool unScaled = true) { setPixelColor(x, c, unScaled); } - inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c, bool unScaled = true) { setPixelColor(int(x), c, unScaled); } + inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(x, c); } + inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColor(int(x), c); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColor(x, RGBW32(r,g,b,w)); } inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColor(x, RGBW32(c.r,c.g,c.b,0)); } inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColor(int(x), RGBW32(c.r,c.g,c.b,0)); } @@ -689,8 +689,8 @@ typedef struct Segment { inline void blur2D(uint8_t blur_amount, bool smear = false) {} inline void blurRow(int row, fract8 blur_amount, bool smear = false) {} inline void blurCol(int col, fract8 blur_amount, bool smear = false) {} - inline void moveX(int8_t delta, bool wrap = false) {} - inline void moveY(int8_t delta, bool wrap = false) {} + inline void moveX(int delta, bool wrap = false) {} + inline void moveY(int delta, bool wrap = false) {} inline void move(uint8_t dir, uint8_t delta, bool wrap = false) {} inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false) {} inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) {} diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 5f61b0094..bee317597 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -168,16 +168,16 @@ uint16_t IRAM_ATTR_YN Segment::XY(int x, int y) return isActive() ? (x%vW) + (y%vH) * vW : 0; } -void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col, bool unScaled) +void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) { if (!isActive()) return; // not active - + const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) const int vH = vHeight(); // segment height in logical pixels (is always >= 1) - if (x >= vW|| y >= vH || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit + if (unsigned(x) >= vW || unsigned(y) >= vH) return; // if pixel would fall out of virtual segment just exit - // if color is unscaled - if (unScaled) col = color_fade(col, currentBri()); + if(getCurrentBrightness() < 255) + col = color_fade(col, getCurrentBrightness()); // scale brightness if (reverse ) x = vW - x - 1; if (reverse_y) y = vH - y - 1; @@ -459,7 +459,7 @@ void Segment::box_blur(unsigned radius, bool smear) { delete[] tmpWSum; } -void Segment::moveX(int8_t delta, bool wrap) { +void Segment::moveX(int delta, bool wrap) { if (!isActive()) return; // not active const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) const int vH = vHeight(); // segment height in logical pixels (is always >= 1) @@ -477,7 +477,7 @@ void Segment::moveX(int8_t delta, bool wrap) { } } -void Segment::moveY(int8_t delta, bool wrap) { +void Segment::moveY(int delta, bool wrap) { if (!isActive()) return; // not active const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) const int vH = vHeight(); // segment height in logical pixels (is always >= 1) @@ -545,20 +545,18 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, x++; } } else { - // pre-scale color for all pixels - col = color_fade(col, currentBri()); // Bresenham’s Algorithm int d = 3 - (2*radius); int y = radius, x = 0; while (y >= x) { - setPixelColorXY(cx+x, cy+y, col, false); - setPixelColorXY(cx-x, cy+y, col, false); - setPixelColorXY(cx+x, cy-y, col, false); - setPixelColorXY(cx-x, cy-y, col, false); - setPixelColorXY(cx+y, cy+x, col, false); - setPixelColorXY(cx-y, cy+x, col, false); - setPixelColorXY(cx+y, cy-x, col, false); - setPixelColorXY(cx-y, cy-x, col, false); + setPixelColorXY(cx+x, cy+y, col); + setPixelColorXY(cx-x, cy+y, col); + setPixelColorXY(cx+x, cy-y, col); + setPixelColorXY(cx-x, cy-y, col); + setPixelColorXY(cx+y, cy+x, col); + setPixelColorXY(cx-y, cy+x, col); + setPixelColorXY(cx+y, cy-x, col); + setPixelColorXY(cx-y, cy-x, col); x++; if (d > 0) { y--; @@ -577,15 +575,13 @@ void Segment::fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, const int vH = vHeight(); // segment height in logical pixels (is always >= 1) // draw soft bounding circle if (soft) drawCircle(cx, cy, radius, col, soft); - // pre-scale color for all pixels - col = color_fade(col, currentBri()); // fill it for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius && int(cx)+x >= 0 && int(cy)+y >= 0 && int(cx)+x < vW && int(cy)+y < vH) - setPixelColorXY(cx + x, cy + y, col, false); + setPixelColorXY(cx + x, cy + y, col); } } } @@ -633,12 +629,10 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3 if (steep) std::swap(x,y); // restore if steep } } else { - // pre-scale color for all pixels - c = color_fade(c, currentBri()); // Bresenham's algorithm int err = (dx>dy ? dx : -dy)/2; // error direction for (;;) { - setPixelColorXY(x0, y0, c, false); + setPixelColorXY(x0, y0, c); if (x0==x1 && y0==y1) break; int e2 = err; if (e2 >-dx) { err -= dy; x0 += sx; } diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index a47a7edc9..9edd7a282 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -86,6 +86,9 @@ uint16_t Segment::maxHeight = 1; unsigned Segment::_vLength = 0; unsigned Segment::_vWidth = 0; unsigned Segment::_vHeight = 0; +uint8_t Segment::_segBri = 0; +//uint8_t Segment::_currentBrightness2 = 0; +//uint8_t Segment::_currentBrightness3 = 0; uint32_t Segment::_currentColors[NUM_COLORS] = {0,0,0}; CRGBPalette16 Segment::_currentPalette = CRGBPalette16(CRGB::Black); CRGBPalette16 Segment::_randomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR); @@ -413,7 +416,7 @@ void Segment::restoreSegenv(tmpsegd_t &tmpSeg) { } #endif -uint8_t IRAM_ATTR Segment::currentBri(bool useCct) const { +uint8_t Segment::currentBri(bool useCct) const { unsigned prog = progress(); if (prog < 0xFFFFU) { unsigned curBri = (useCct ? cct : (on ? opacity : 0)) * prog; @@ -445,6 +448,7 @@ void Segment::beginDraw() { _vWidth = virtualWidth(); _vHeight = virtualHeight(); _vLength = virtualLength(); + _segBri = currentBri(); // adjust gamma for effects for (unsigned i = 0; i < NUM_COLORS; i++) { #ifndef WLED_DISABLE_MODE_BLEND @@ -624,21 +628,21 @@ void Segment::setPalette(uint8_t pal) { } // 2D matrix -uint16_t IRAM_ATTR Segment::virtualWidth() const { +uint16_t Segment::virtualWidth() const { unsigned groupLen = groupLength(); unsigned vWidth = ((transpose ? height() : width()) + groupLen - 1) / groupLen; if (mirror) vWidth = (vWidth + 1) /2; // divide by 2 if mirror, leave at least a single LED return vWidth; } -uint16_t IRAM_ATTR Segment::virtualHeight() const { +uint16_t Segment::virtualHeight() const { unsigned groupLen = groupLength(); unsigned vHeight = ((transpose ? width() : height()) + groupLen - 1) / groupLen; if (mirror_y) vHeight = (vHeight + 1) /2; // divide by 2 if mirror, leave at least a single LED return vHeight; } -uint16_t IRAM_ATTR_YN Segment::nrOfVStrips() const { +uint16_t Segment::nrOfVStrips() const { unsigned vLen = 1; #ifndef WLED_DISABLE_2D if (is2D() && map1D2D == M12_pBar) vLen = virtualWidth(); @@ -683,7 +687,7 @@ static int getPinwheelLength(int vW, int vH) { #endif // 1D strip -uint16_t IRAM_ATTR Segment::virtualLength() const { +uint16_t Segment::virtualLength() const { #ifndef WLED_DISABLE_2D if (is2D()) { unsigned vW = virtualWidth(); @@ -715,7 +719,7 @@ uint16_t IRAM_ATTR Segment::virtualLength() const { return vLength; } -void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col, bool unScaled) +void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) { if (!isActive() || i < 0) return; // not active or invalid index #ifndef WLED_DISABLE_2D @@ -739,22 +743,20 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col, bool unScaled) if (is2D()) { const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) const int vH = vHeight(); // segment height in logical pixels (is always >= 1) - // pre-scale color for all pixels - col = color_fade(col, currentBri()); switch (map1D2D) { case M12_Pixels: // use all available pixels as a long strip - setPixelColorXY(i % vW, i / vW, col, false); + setPixelColorXY(i % vW, i / vW, col); break; case M12_pBar: // expand 1D effect vertically or have it play on virtual strips - if (vStrip > 0) setPixelColorXY(vStrip - 1, vH - i - 1, col, false); - else for (int x = 0; x < vW; x++) setPixelColorXY(x, vH - i - 1, col, false); + if (vStrip > 0) setPixelColorXY(vStrip - 1, vH - i - 1, col); + else for (int x = 0; x < vW; x++) setPixelColorXY(x, vH - i - 1, col); break; case M12_pArc: // expand in circular fashion from center if (i == 0) - setPixelColorXY(0, 0, col, false); + setPixelColorXY(0, 0, col); else { float r = i; float step = HALF_PI / (2.8284f * r + 4); // we only need (PI/4)/(r/sqrt(2)+1) steps @@ -762,8 +764,8 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col, bool unScaled) int x = roundf(sin_t(rad) * r); int y = roundf(cos_t(rad) * r); // exploit symmetry - setPixelColorXY(x, y, col, false); - setPixelColorXY(y, x, col, false); + setPixelColorXY(x, y, col); + setPixelColorXY(y, x, col); } // Bresenham’s Algorithm (may not fill every pixel) //int d = 3 - (2*i); @@ -782,8 +784,8 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col, bool unScaled) } break; case M12_pCorner: - for (int x = 0; x <= i; x++) setPixelColorXY(x, i, col, false); - for (int y = 0; y < i; y++) setPixelColorXY(i, y, col, false); + for (int x = 0; x <= i; x++) setPixelColorXY(x, i, col); + for (int y = 0; y < i; y++) setPixelColorXY(i, y, col); break; case M12_sPinwheel: { // i = angle --> 0 - 296 (Big), 0 - 192 (Medium), 0 - 72 (Small) @@ -822,7 +824,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col, bool unScaled) int x = posx / Fixed_Scale; int y = posy / Fixed_Scale; // set pixel - if (x != lastX || y != lastY) setPixelColorXY(x, y, col, false); // only paint if pixel position is different + if (x != lastX || y != lastY) setPixelColorXY(x, y, col); // only paint if pixel position is different lastX = x; lastY = y; // advance to next position @@ -846,9 +848,8 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col, bool unScaled) #endif unsigned len = length(); - // if color is unscaled - if (unScaled) col = color_fade(col, currentBri()); - + if(getCurrentBrightness() < 255) //!!! test without this if + col = color_fade(col, getCurrentBrightness()); // scale brightness // expand pixel (taking into account start, grouping, spacing [and offset]) i = i * groupLength(); if (reverse) { // is segment reversed? @@ -1070,11 +1071,9 @@ void Segment::fill(uint32_t c) { if (!isActive()) return; // not active const int cols = is2D() ? vWidth() : vLength(); const int rows = vHeight(); // will be 1 for 1D - // pre-scale color for all pixels - c = color_fade(c, currentBri()); for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) { - if (is2D()) setPixelColorXY(x, y, c, false); - else setPixelColor(x, c, false); + if (is2D()) setPixelColorXY(x, y, c); + else setPixelColor(x, c); } } From 336da25463ff13485da9bd2b1d825f1647368221 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sun, 29 Sep 2024 14:14:07 +0200 Subject: [PATCH 046/234] Private global _colorScaled --- wled00/FX.h | 15 ++++++++------- wled00/FX_2Dfcn.cpp | 20 ++++++++++++++++++-- wled00/FX_fcn.cpp | 18 +++++++++++++----- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 8a452cfcb..763dc2639 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -420,10 +420,11 @@ typedef struct Segment { }; uint16_t _dataLen; static uint16_t _usedSegmentData; - static uint8_t _segBri; // Current brightness of segment + static uint8_t _segBri; // brightness of segment for current effect static unsigned _vLength; // 1D dimension used for current effect static unsigned _vWidth, _vHeight; // 2D dimensions used for current effect static uint32_t _currentColors[NUM_COLORS]; // colors used for current effect + static bool _colorScaled; // color has been scaled prior to setPixelColor() call static CRGBPalette16 _currentPalette; // palette used for current effect (includes transition, used in color_from_palette()) static CRGBPalette16 _randomPalette; // actual random palette static CRGBPalette16 _newRandomPalette; // target random palette @@ -590,9 +591,9 @@ typedef struct Segment { // 1D strip [[gnu::hot]] uint16_t virtualLength() const; [[gnu::hot]] void setPixelColor(int n, uint32_t c); // set relative pixel within segment with color - inline void setPixelColor(unsigned n, uint32_t c) { setPixelColor(int(n), c); } - inline void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } - inline void setPixelColor(int n, CRGB c) { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } + inline void setPixelColor(unsigned n, uint32_t c) { setPixelColor(int(n), c); } + inline void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } + inline void setPixelColor(int n, CRGB c) { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } #ifdef WLED_USE_AA_PIXELS void setPixelColor(float i, uint32_t c, bool aa = true); inline void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) { setPixelColor(i, RGBW32(r,g,b,w), aa); } @@ -630,7 +631,7 @@ typedef struct Segment { #ifndef WLED_DISABLE_2D [[gnu::hot]] uint16_t XY(int x, int y); // support function to get relative index within segment [[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color - inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColorXY(int(x), int(y), c); } + inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColorXY(int(x), int(y), c); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColorXY(int(x), int(y), RGBW32(c.r,c.g,c.b,0)); } @@ -668,8 +669,8 @@ typedef struct Segment { inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); } #else inline uint16_t XY(int x, int y) { return x; } - inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(x, c); } - inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColor(int(x), c); } + inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(x, c); } + inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColor(int(x), c); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColor(x, RGBW32(r,g,b,w)); } inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColor(x, RGBW32(c.r,c.g,c.b,0)); } inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColor(int(x), RGBW32(c.r,c.g,c.b,0)); } diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index bee317597..8804cdbb6 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -176,8 +176,8 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) const int vH = vHeight(); // segment height in logical pixels (is always >= 1) if (unsigned(x) >= vW || unsigned(y) >= vH) return; // if pixel would fall out of virtual segment just exit - if(getCurrentBrightness() < 255) - col = color_fade(col, getCurrentBrightness()); // scale brightness + // if color is unscaled + if (!_colorScaled) col = color_fade(col, _segBri); if (reverse ) x = vW - x - 1; if (reverse_y) y = vH - y - 1; @@ -545,6 +545,9 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, x++; } } else { + // pre-scale color for all pixels + col = color_fade(col, _segBri); + _colorScaled = true; // Bresenham’s Algorithm int d = 3 - (2*radius); int y = radius, x = 0; @@ -565,6 +568,7 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, d += 4 * x + 6; } } + _colorScaled = false; } } @@ -575,6 +579,9 @@ void Segment::fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, const int vH = vHeight(); // segment height in logical pixels (is always >= 1) // draw soft bounding circle if (soft) drawCircle(cx, cy, radius, col, soft); + // pre-scale color for all pixels + col = color_fade(col, _segBri); + _colorScaled = true; // fill it for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { @@ -584,6 +591,7 @@ void Segment::fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, setPixelColorXY(cx + x, cy + y, col); } } + _colorScaled = false; } //line function @@ -629,6 +637,9 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3 if (steep) std::swap(x,y); // restore if steep } } else { + // pre-scale color for all pixels + c = color_fade(c, _segBri); + _colorScaled = true; // Bresenham's algorithm int err = (dx>dy ? dx : -dy)/2; // error direction for (;;) { @@ -638,6 +649,7 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3 if (e2 >-dx) { err -= dy; x0 += sx; } if (e2 < dy) { err += dx; y0 += sy; } } + _colorScaled = false; } } @@ -670,6 +682,9 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, default: return; } uint32_t col = ColorFromPaletteWLED(grad, (i+1)*255/h, 255, NOBLEND); + // pre-scale color for all pixels + col = color_fade(col, _segBri); + _colorScaled = true; for (int j = 0; j= 1) + // pre-scale color for all pixels + col = color_fade(col, _segBri); + _colorScaled = true; switch (map1D2D) { case M12_Pixels: // use all available pixels as a long strip @@ -834,6 +836,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) break; } } + _colorScaled = false; return; } else if (Segment::maxHeight != 1 && (width() == 1 || height() == 1)) { if (start < Segment::maxWidth*Segment::maxHeight) { @@ -848,8 +851,9 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) #endif unsigned len = length(); - if(getCurrentBrightness() < 255) //!!! test without this if - col = color_fade(col, getCurrentBrightness()); // scale brightness + // if color is unscaled + if (!_colorScaled) col = color_fade(col, _segBri); + // expand pixel (taking into account start, grouping, spacing [and offset]) i = i * groupLength(); if (reverse) { // is segment reversed? @@ -1071,10 +1075,14 @@ void Segment::fill(uint32_t c) { if (!isActive()) return; // not active const int cols = is2D() ? vWidth() : vLength(); const int rows = vHeight(); // will be 1 for 1D + // pre-scale color for all pixels + c = color_fade(c, _segBri); + _colorScaled = true; for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) { if (is2D()) setPixelColorXY(x, y, c); else setPixelColor(x, c); } + _colorScaled = false; } /* From 0ae73296cffaff3089893734c2621174347de7ad Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sun, 29 Sep 2024 15:19:37 +0200 Subject: [PATCH 047/234] Update comment --- wled00/FX_fcn.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 86f190ad5..232994e73 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -442,7 +442,7 @@ uint32_t IRAM_ATTR_YN Segment::currentColor(uint8_t slot) const { #endif } -// pre-calculate drawing parameters for faster access +// pre-calculate drawing parameters for faster access (based on the idea from @softhack007 from MM fork) void Segment::beginDraw() { _vWidth = virtualWidth(); _vHeight = virtualHeight(); From d3c401ed4e59ab19cc79be7d3bb1ed53de5e56ae Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sun, 29 Sep 2024 18:37:18 +0200 Subject: [PATCH 048/234] wu_pixel small optimization 5% faster --- wled00/FX_2Dfcn.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 26ec1d608..0f6690549 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -704,11 +704,14 @@ void Segment::wu_pixel(uint32_t x, uint32_t y, CRGB c) { //awesome wu_pixel WU_WEIGHT(ix, yy), WU_WEIGHT(xx, yy)}; // multiply the intensities by the colour, and saturating-add them to the pixels for (int i = 0; i < 4; i++) { - CRGB led = getPixelColorXY((x >> 8) + (i & 1), (y >> 8) + ((i >> 1) & 1)); + int wu_x = (x >> 8) + (i & 1); // precalculate x + int wu_y = (y >> 8) + ((i >> 1) & 1); // precalculate y + CRGB led = getPixelColorXY(wu_x, wu_y); + CRGB oldLed = led; led.r = qadd8(led.r, c.r * wu[i] >> 8); led.g = qadd8(led.g, c.g * wu[i] >> 8); led.b = qadd8(led.b, c.b * wu[i] >> 8); - setPixelColorXY(int((x >> 8) + (i & 1)), int((y >> 8) + ((i >> 1) & 1)), led); + if (led != oldLed) setPixelColorXY(wu_x, wu_y, led); // don't repaint if same color } } #undef WU_WEIGHT From 7fa25ca7aec7ad3969011ecfeba63197cb43190e Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:25:58 +0200 Subject: [PATCH 049/234] pio update - flash size of non-standard boards * adding missing flash size flags that were lost between 0.14 and 0.15 (necessary if you don't flash using esptool) * adding env:esp32dev_16M for 16MB flash (serg74 esp32-16M, twilightlord esp32 16M) --- platformio.ini | 21 +++++++++++++++++++++ platformio_override.sample.ini | 2 ++ 2 files changed, 23 insertions(+) diff --git a/platformio.ini b/platformio.ini index 4d30be322..3005ba220 100644 --- a/platformio.ini +++ b/platformio.ini @@ -430,7 +430,26 @@ lib_deps = ${esp32_idf_V4.lib_deps} ${esp32.AR_lib_deps} monitor_filters = esp32_exception_decoder board_build.partitions = ${esp32.large_partitions} +board_upload.flash_size = 8MB +board_upload.maximum_size = 8388608 ; board_build.f_flash = 80000000L +; board_build.flash_mode = qio + +[env:esp32dev_16M] +board = esp32dev +platform = ${esp32_idf_V4.platform} +platform_packages = ${esp32_idf_V4.platform_packages} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=ESP32_16M #-D WLED_DISABLE_BROWNOUT_DET + ${esp32.AR_build_flags} +lib_deps = ${esp32_idf_V4.lib_deps} + ${esp32.AR_lib_deps} +monitor_filters = esp32_exception_decoder +board_build.partitions = ${esp32.extreme_partitions} +board_upload.flash_size = 16MB +board_upload.maximum_size = 16777216 +board_build.f_flash = 80000000L +board_build.flash_mode = dio ;[env:esp32dev_audioreactive] ;board = esp32dev @@ -508,6 +527,8 @@ build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME= lib_deps = ${esp32s3.lib_deps} ${esp32.AR_lib_deps} board_build.partitions = ${esp32.extreme_partitions} +board_upload.flash_size = 16MB +board_upload.maximum_size = 16777216 board_build.f_flash = 80000000L board_build.flash_mode = qio monitor_filters = esp32_exception_decoder diff --git a/platformio_override.sample.ini b/platformio_override.sample.ini index dedc8edf5..8e5fdf003 100644 --- a/platformio_override.sample.ini +++ b/platformio_override.sample.ini @@ -359,6 +359,8 @@ upload_speed = 115200 lib_deps = ${esp32c3.lib_deps} board_build.partitions = tools/WLED_ESP32_2MB_noOTA.csv board_build.flash_mode = dio +board_upload.flash_size = 2MB +board_upload.maximum_size = 2097152 [env:wemos_shield_esp32] board = esp32dev From ee380c5377b1f73e2a8da2247bb77288b9670899 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Mon, 30 Sep 2024 16:35:40 +0200 Subject: [PATCH 050/234] Replace uint16_t with unsigned for segment data swap if statements in color_fade --- wled00/FX.h | 8 ++++---- wled00/FX_fcn.cpp | 4 ++-- wled00/colors.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 763dc2639..065daa86d 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -400,7 +400,7 @@ typedef struct Segment { uint32_t _stepT; uint32_t _callT; uint8_t *_dataT; - uint16_t _dataLenT; + unsigned _dataLenT; TemporarySegmentData() : _dataT(nullptr) // just in case... , _dataLenT(0) @@ -418,8 +418,8 @@ typedef struct Segment { uint8_t _reserved : 4; }; }; - uint16_t _dataLen; - static uint16_t _usedSegmentData; + unsigned _dataLen; + static unsigned _usedSegmentData; static uint8_t _segBri; // brightness of segment for current effect static unsigned _vLength; // 1D dimension used for current effect static unsigned _vWidth, _vHeight; // 2D dimensions used for current effect @@ -537,7 +537,7 @@ typedef struct Segment { inline uint16_t groupLength() const { return grouping + spacing; } inline uint8_t getLightCapabilities() const { return _capabilities; } - inline static uint16_t getUsedSegmentData() { return Segment::_usedSegmentData; } + inline static unsigned getUsedSegmentData() { return Segment::_usedSegmentData; } inline static void addUsedSegmentData(int len) { Segment::_usedSegmentData += len; } #ifndef WLED_DISABLE_MODE_BLEND inline static void modeBlend(bool blend) { _modeBlend = blend; } diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 232994e73..13e9e73bb 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -80,7 +80,7 @@ static constexpr bool validatePinsAndTypes(const unsigned* types, unsigned numTy /////////////////////////////////////////////////////////////////////////////// // Segment class implementation /////////////////////////////////////////////////////////////////////////////// -uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for their data[] +unsigned Segment::_usedSegmentData = 0U; // amount of RAM all segments use for their data[] uint16_t Segment::maxWidth = DEFAULT_LED_COUNT; uint16_t Segment::maxHeight = 1; unsigned Segment::_vLength = 0; @@ -433,7 +433,7 @@ uint8_t Segment::currentMode() const { return mode; } -uint32_t IRAM_ATTR_YN Segment::currentColor(uint8_t slot) const { +uint32_t Segment::currentColor(uint8_t slot) const { if (slot >= NUM_COLORS) slot = 0; #ifndef WLED_DISABLE_MODE_BLEND return isInTransition() ? color_blend(_t->_segT._colorT[slot], colors[slot], progress(), true) : colors[slot]; diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 1c4844371..c059ea9db 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -77,8 +77,8 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool preserveCR) uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) { - if (c1 == BLACK || amount == 0) return BLACK; if (amount == 255) return c1; + if (c1 == BLACK || amount == 0) return BLACK; uint32_t scaledcolor; // color order is: W R G B from MSB to LSB uint32_t scale = amount; // 32bit for faster calculation uint32_t addRemains = 0; From 4ed8ded502fa77396303a5241b643cb7fc406dce Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:44:38 +0200 Subject: [PATCH 051/234] Akemi bugfix for panel width > 32 due to a math accident, Akemi did not show proper GEQ bands in its hands when width>32 --- wled00/FX.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index ad843f0f9..40db1a3df 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7528,8 +7528,9 @@ uint16_t mode_2DAkemi(void) { //add geq left and right if (um_data && fftResult) { - for (int x=0; x < cols/8; x++) { - unsigned band = x * cols/8; + int xMax = cols/8; + for (int x=0; x < xMax; x++) { + unsigned band = map2(x, 0, max(xMax,4), 0, 15); // map 0..cols/8 to 16 GEQ bands band = constrain(band, 0, 15); int barHeight = map(fftResult[band], 0, 255, 0, 17*rows/32); CRGB color = CRGB(SEGMENT.color_from_palette((band * 35), false, PALETTE_SOLID_WRAP, 0)); From 3765d558b6ebfb4e9d90074bf545580d4475dcbd Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 30 Sep 2024 18:26:00 +0200 Subject: [PATCH 052/234] akemi bugfix fix map2 --> map --- wled00/FX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 40db1a3df..2ac773099 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7530,7 +7530,7 @@ uint16_t mode_2DAkemi(void) { if (um_data && fftResult) { int xMax = cols/8; for (int x=0; x < xMax; x++) { - unsigned band = map2(x, 0, max(xMax,4), 0, 15); // map 0..cols/8 to 16 GEQ bands + unsigned band = map(x, 0, max(xMax,4), 0, 15); // map 0..cols/8 to 16 GEQ bands band = constrain(band, 0, 15); int barHeight = map(fftResult[band], 0, 255, 0, 17*rows/32); CRGB color = CRGB(SEGMENT.color_from_palette((band * 35), false, PALETTE_SOLID_WRAP, 0)); From 262af0678f3c2ce367b244dc99acc4764c76c723 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 30 Sep 2024 18:35:14 +0200 Subject: [PATCH 053/234] colored burst effect bugfix (swapped XY dimensions) fixing a bug where width and height got swapped (visible on non-square panels) --- wled00/FX.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 2ac773099..a3cd32e8e 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -4931,8 +4931,8 @@ uint16_t mode_2DColoredBursts() { // By: ldirko https://editor.so SEGMENT.fadeToBlackBy(40); for (size_t i = 0; i < numLines; i++) { byte x1 = beatsin8(2 + SEGMENT.speed/16, 0, (cols - 1)); - byte x2 = beatsin8(1 + SEGMENT.speed/16, 0, (cols - 1)); - byte y1 = beatsin8(5 + SEGMENT.speed/16, 0, (rows - 1), 0, i * 24); + byte x2 = beatsin8(1 + SEGMENT.speed/16, 0, (rows - 1)); + byte y1 = beatsin8(5 + SEGMENT.speed/16, 0, (cols - 1), 0, i * 24); byte y2 = beatsin8(3 + SEGMENT.speed/16, 0, (rows - 1), 0, i * 48 + 64); CRGB color = ColorFromPalette(SEGPALETTE, i * 255 / numLines + (SEGENV.aux0&0xFF), 255, LINEARBLEND); From 402fba734ad4dbade8aef23382d77a856d497bb7 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 2 Oct 2024 16:34:36 +0200 Subject: [PATCH 054/234] bugfix for holes in 2D DNA Spiral Holes were visible at height > 32. Root cause: "lerp8x8" seems to be inaccurate --> replaced by a simple linear calculation. --- wled00/FX.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index a3cd32e8e..f3e82275c 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -5010,9 +5010,11 @@ uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulma // draw a gradient line between x and x1 x = x / 2; x1 = x1 / 2; unsigned steps = abs8(x - x1) + 1; + bool positive = (x1 >= x); // direction of drawing for (size_t k = 1; k <= steps; k++) { unsigned rate = k * 255 / steps; - unsigned dx = lerp8by8(x, x1, rate); + //unsigned dx = lerp8by8(x, x1, rate); + unsigned dx = positive? (x + k-1) : (x - k+1); // behaves the same as "lerp8by8" but does not create holes //SEGMENT.setPixelColorXY(dx, i, ColorFromPalette(SEGPALETTE, hue, 255, LINEARBLEND).nscale8_video(rate)); SEGMENT.addPixelColorXY(dx, i, ColorFromPalette(SEGPALETTE, hue, 255, LINEARBLEND)); // use setPixelColorXY for different look SEGMENT.fadePixelColorXY(dx, i, rate); From ba3a61f6236f316e3b03e3cf3bd92c79b0a1ce8f Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Wed, 2 Oct 2024 20:14:25 +0200 Subject: [PATCH 055/234] Reduced code size by: - removing WS2812FX::setMode() - removing WS2812FX::setColor() - removing floating point in transition - color handling modification in set.cpp - replaced uint8_t with unsigned in function parameters - inlined WS2812FX::isUpdating() - (MAY BE BREAKING) alexa & smartnest update --- usermods/smartnest/usermod_smartnest.h | 2 +- wled00/FX.h | 29 +++++++--------- wled00/FX_2Dfcn.cpp | 2 +- wled00/FX_fcn.cpp | 46 +++----------------------- wled00/alexa.cpp | 4 +-- wled00/bus_manager.h | 1 + wled00/led.cpp | 21 ++++++------ wled00/set.cpp | 45 ++++++++++++------------- wled00/udp.cpp | 6 ++-- wled00/wled.cpp | 10 +++--- wled00/wled.h | 1 - 11 files changed, 61 insertions(+), 106 deletions(-) diff --git a/usermods/smartnest/usermod_smartnest.h b/usermods/smartnest/usermod_smartnest.h index 92d524c88..9d21ef2e7 100644 --- a/usermods/smartnest/usermod_smartnest.h +++ b/usermods/smartnest/usermod_smartnest.h @@ -49,7 +49,7 @@ private: void setColor(int r, int g, int b) { - strip.setColor(0, r, g, b); + strip.getMainSegment().setColor(0, RGBW32(r, g, b, 0)); stateUpdated(CALL_MODE_DIRECT_CHANGE); char msg[18] {}; sprintf(msg, "rgb(%d,%d,%d)", r, g, b); diff --git a/wled00/FX.h b/wled00/FX.h index 065daa86d..14c268162 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -30,6 +30,7 @@ #include #include "const.h" +#include "bus_manager.h" #define FASTLED_INTERNAL //remove annoying pragma messages #define USE_GET_MILLISECOND_TIMER @@ -654,7 +655,7 @@ typedef struct Segment { void blurCol(int col, fract8 blur_amount, bool smear = false); void moveX(int delta, bool wrap = false); void moveY(int delta, bool wrap = false); - void move(uint8_t dir, uint8_t delta, bool wrap = false); + void move(unsigned dir, unsigned delta, bool wrap = false); void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false); inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) { drawCircle(cx, cy, radius, RGBW32(c.r,c.g,c.b,0), soft); } void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false); @@ -781,25 +782,22 @@ class WS2812FX { // 96 bytes #endif finalizeInit(), // initialises strip components service(), // executes effect functions when due and calls strip.show() - setMode(uint8_t segid, uint8_t m), // sets effect/mode for given segment (high level API) - setColor(uint8_t slot, uint32_t c), // sets color (in slot) for given segment (high level API) setCCT(uint16_t k), // sets global CCT (either in relative 0-255 value or in K) setBrightness(uint8_t b, bool direct = false), // sets strip brightness setRange(uint16_t i, uint16_t i2, uint32_t col), // used for clock overlay purgeSegments(), // removes inactive segments from RAM (may incure penalty and memory fragmentation but reduces vector footprint) setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 1, uint8_t spacing = 0, uint16_t offset = UINT16_MAX, uint16_t startY=0, uint16_t stopY=1), - setMainSegmentId(uint8_t n), + setMainSegmentId(unsigned n = 0), resetSegments(), // marks all segments for reset makeAutoSegments(bool forceReset = false), // will create segments based on configured outputs fixInvalidSegments(), // fixes incorrect segment configuration setPixelColor(unsigned n, uint32_t c), // paints absolute strip pixel with index n and color c show(), // initiates LED output - setTargetFps(uint8_t fps), + setTargetFps(unsigned fps), setupEffectData(); // add default effects to the list; defined in FX.cpp inline void restartRuntime() { for (Segment &seg : _segments) seg.markForReset(); } inline void setTransitionMode(bool t) { for (Segment &seg : _segments) seg.startTransition(t ? _transitionDur : 0); } - inline void setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setColor(slot, RGBW32(r,g,b,w)); } inline void setPixelColor(unsigned n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } inline void setPixelColor(unsigned n, CRGB c) { setPixelColor(n, c.red, c.green, c.blue); } inline void fill(uint32_t c) { for (unsigned i = 0; i < getLengthTotal(); i++) setPixelColor(i, c); } // fill whole strip with color (inline) @@ -815,9 +813,9 @@ class WS2812FX { // 96 bytes checkSegmentAlignment(), hasRGBWBus() const, hasCCTBus() const, - isUpdating() const, // return true if the strip is being sent pixel updates - deserializeMap(uint8_t n=0); + deserializeMap(unsigned n = 0); + inline bool isUpdating() const { return !BusManager::canAllShow(); } // return true if the strip is being sent pixel updates inline bool isServicing() const { return _isServicing; } // returns true if strip.service() is executing inline bool hasWhiteChannel() const { return _hasWhiteChannel; } // returns true if strip contains separate white chanel inline bool isOffRefreshRequired() const { return _isOffRefreshRequired; } // returns true if strip requires regular updates (i.e. TM1814 chipset) @@ -844,9 +842,9 @@ class WS2812FX { // 96 bytes uint16_t getLengthPhysical() const, - getLengthTotal() const, // will include virtual/nonexistent pixels in matrix - getFps() const; + getLengthTotal() const; // will include virtual/nonexistent pixels in matrix + inline uint16_t getFps() const { return (millis() - _lastShow > 2000) ? 0 : _cumulativeFps +1; } // Returns the refresh rate of the LED strip inline uint16_t getFrameTime() const { return _frametime; } // returns amount of time a frame should take (in ms) inline uint16_t getMinShowDelay() const { return MIN_SHOW_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant) inline uint16_t getLength() const { return _length; } // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H) @@ -859,15 +857,12 @@ class WS2812FX { // 96 bytes uint32_t now, timebase; uint32_t getPixelColor(unsigned) const; - inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call + inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call - const char * - getModeData(uint8_t id = 0) const { return (id && id<_modeCount) ? _modeData[id] : PSTR("Solid"); } + const char *getModeData(unsigned id = 0) const { return (id && id < _modeCount) ? _modeData[id] : PSTR("Solid"); } + inline const char **getModeDataSrc() { return &(_modeData[0]); } // vectors use arrays for underlying data - const char ** - getModeDataSrc() { return &(_modeData[0]); } // vectors use arrays for underlying data - - Segment& getSegment(uint8_t id); + Segment& getSegment(unsigned id); inline Segment& getFirstSelectedSeg() { return _segments[getFirstSelectedSegId()]; } // returns reference to first segment that is "selected" inline Segment& getMainSegment() { return _segments[getMainSegmentId()]; } // returns reference to main segment inline Segment* getSegments() { return &(_segments[0]); } // returns pointer to segment vector structure (warning: use carefully) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 8804cdbb6..9b39b4c8f 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -499,7 +499,7 @@ void Segment::moveY(int delta, bool wrap) { // @param dir direction: 0=left, 1=left-up, 2=up, 3=right-up, 4=right, 5=right-down, 6=down, 7=left-down // @param delta number of pixels to move // @param wrap around -void Segment::move(uint8_t dir, uint8_t delta, bool wrap) { +void Segment::move(unsigned dir, unsigned delta, bool wrap) { if (delta==0) return; switch (dir) { case 0: moveX( delta, wrap); break; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 13e9e73bb..7927269ed 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1464,49 +1464,11 @@ void WS2812FX::show() { _lastShow = showNow; } -/** - * Returns a true value if any of the strips are still being updated. - * On some hardware (ESP32), strip updates are done asynchronously. - */ -bool WS2812FX::isUpdating() const { - return !BusManager::canAllShow(); -} - -/** - * Returns the refresh rate of the LED strip. Useful for finding out whether a given setup is fast enough. - * Only updates on show() or is set to 0 fps if last show is more than 2 secs ago, so accuracy varies - */ -uint16_t WS2812FX::getFps() const { - if (millis() - _lastShow > 2000) return 0; - return _cumulativeFps +1; -} - -void WS2812FX::setTargetFps(uint8_t fps) { +void WS2812FX::setTargetFps(unsigned fps) { if (fps > 0 && fps <= 120) _targetFps = fps; _frametime = 1000 / _targetFps; } -void WS2812FX::setMode(uint8_t segid, uint8_t m) { - if (segid >= _segments.size()) return; - - if (m >= getModeCount()) m = getModeCount() - 1; - - if (_segments[segid].mode != m) { - _segments[segid].setMode(m); // do not load defaults - } -} - -//applies to all active and selected segments -void WS2812FX::setColor(uint8_t slot, uint32_t c) { - if (slot >= NUM_COLORS) return; - - for (segment &seg : _segments) { - if (seg.isActive() && seg.isSelected()) { - seg.setColor(slot, c); - } - } -} - void WS2812FX::setCCT(uint16_t k) { for (segment &seg : _segments) { if (seg.isActive() && seg.isSelected()) { @@ -1553,7 +1515,7 @@ uint8_t WS2812FX::getFirstSelectedSegId() const { return getMainSegmentId(); } -void WS2812FX::setMainSegmentId(uint8_t n) { +void WS2812FX::setMainSegmentId(unsigned n) { _mainSegment = 0; if (n < _segments.size()) { _mainSegment = n; @@ -1629,7 +1591,7 @@ void WS2812FX::purgeSegments() { } } -Segment& WS2812FX::getSegment(uint8_t id) { +Segment& WS2812FX::getSegment(unsigned id) { return _segments[id >= _segments.size() ? getMainSegmentId() : id]; // vectors } @@ -1844,7 +1806,7 @@ void WS2812FX::loadCustomPalettes() { } //load custom mapping table from JSON file (called from finalizeInit() or deserializeState()) -bool WS2812FX::deserializeMap(uint8_t n) { +bool WS2812FX::deserializeMap(unsigned n) { // 2D support creates its own ledmap (on the fly) if a ledmap.json exists it will overwrite built one. char fileName[32]; diff --git a/wled00/alexa.cpp b/wled00/alexa.cpp index b108f294b..81b9ec346 100644 --- a/wled00/alexa.cpp +++ b/wled00/alexa.cpp @@ -126,10 +126,10 @@ void onAlexaChange(EspalexaDevice* dev) } else { colorKtoRGB(k, rgbw); } - strip.setColor(0, RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3])); + strip.getMainSegment().setColor(0, RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3])); } else { uint32_t color = dev->getRGB(); - strip.setColor(0, color); + strip.getMainSegment().setColor(0, color); } stateUpdated(CALL_MODE_ALEXA); } diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 1b324d713..e25a06849 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -6,6 +6,7 @@ */ #include "const.h" +#include "pin_manager.h" #include //colors.cpp diff --git a/wled00/led.cpp b/wled00/led.cpp index 9de0495b4..5439fbb68 100644 --- a/wled00/led.cpp +++ b/wled00/led.cpp @@ -80,6 +80,7 @@ byte scaledBri(byte in) void applyBri() { if (!realtimeMode || !arlsForceMaxBri) { + //DEBUG_PRINTF_P(PSTR("Applying strip brightness: %d (%d,%d)\n"), (int)briT, (int)bri, (int)briOld); strip.setBrightness(scaledBri(briT)); } } @@ -144,7 +145,6 @@ void stateUpdated(byte callMode) { if (transitionActive) { briOld = briT; - tperLast = 0; } else strip.setTransitionMode(true); // force all segments to transition mode transitionActive = true; @@ -184,22 +184,21 @@ void handleTransitions() updateInterfaces(interfaceUpdateCallMode); if (transitionActive && strip.getTransition() > 0) { - float tper = (millis() - transitionStartTime)/(float)strip.getTransition(); - if (tper >= 1.0f) { + int ti = millis() - transitionStartTime; + int tr = strip.getTransition(); + if (ti/tr) { strip.setTransitionMode(false); // stop all transitions // restore (global) transition time if not called from UDP notifier or single/temporary transition from JSON (also playlist) if (jsonTransitionOnce) strip.setTransition(transitionDelay); transitionActive = false; jsonTransitionOnce = false; - tperLast = 0; applyFinalBri(); return; } - if (tper - tperLast < 0.004f) return; // less than 1 bit change (1/255) - tperLast = tper; - briT = briOld + ((bri - briOld) * tper); - - applyBri(); + byte briTO = briT; + int deltaBri = (int)bri - (int)briOld; + briT = briOld + (deltaBri * ti / tr); + if (briTO != briT) applyBri(); } } @@ -234,8 +233,8 @@ void handleNightlight() colNlT[1] = effectSpeed; colNlT[2] = effectPalette; - strip.setMode(strip.getFirstSelectedSegId(), FX_MODE_STATIC); // make sure seg runtime is reset if it was in sunrise mode - effectCurrent = FX_MODE_SUNRISE; + strip.getFirstSelectedSeg().setMode(FX_MODE_STATIC); // make sure seg runtime is reset if it was in sunrise mode + effectCurrent = FX_MODE_SUNRISE; // colorUpdated() will take care of assigning that to all selected segments effectSpeed = nightlightDelayMins; effectPalette = 0; if (effectSpeed > 60) effectSpeed = 60; //currently limited to 60 minutes diff --git a/wled00/set.cpp b/wled00/set.cpp index 9b7aa92a5..cf3a07dd0 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -837,8 +837,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) } // temporary values, write directly to segments, globals are updated by setValuesFromFirstSelectedSeg() - uint32_t col0 = selseg.colors[0]; - uint32_t col1 = selseg.colors[1]; + uint32_t col0 = selseg.colors[0]; + uint32_t col1 = selseg.colors[1]; + uint32_t col2 = selseg.colors[2]; byte colIn[4] = {R(col0), G(col0), B(col0), W(col0)}; byte colInSec[4] = {R(col1), G(col1), B(col1), W(col1)}; byte effectIn = selseg.mode; @@ -919,7 +920,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) //set brightness updateVal(req.c_str(), "&A=", &bri); - bool col0Changed = false, col1Changed = false; + bool col0Changed = false, col1Changed = false, col2Changed = false; //set colors col0Changed |= updateVal(req.c_str(), "&R=", &colIn[0]); col0Changed |= updateVal(req.c_str(), "&G=", &colIn[1]); @@ -976,7 +977,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) } //set color from HEX or 32bit DEC - byte tmpCol[4]; pos = req.indexOf(F("CL=")); if (pos > 0) { colorFromDecOrHexString(colIn, (char*)req.substring(pos + 3).c_str()); @@ -989,10 +989,11 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) } pos = req.indexOf(F("C3=")); if (pos > 0) { + byte tmpCol[4]; colorFromDecOrHexString(tmpCol, (char*)req.substring(pos + 3).c_str()); - uint32_t col2 = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]); + col2 = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]); selseg.setColor(2, col2); // defined above (SS= or main) - if (!singleSegment) strip.setColor(2, col2); // will set color to all active & selected segments + col2Changed = true; } //set to random hue SR=0->1st SR=1->2nd @@ -1003,29 +1004,22 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) col0Changed |= (!sec); col1Changed |= sec; } - //swap 2nd & 1st - pos = req.indexOf(F("SC")); - if (pos > 0) { - byte temp; - for (unsigned i=0; i<4; i++) { - temp = colIn[i]; - colIn[i] = colInSec[i]; - colInSec[i] = temp; - } - col0Changed = col1Changed = true; - } - // apply colors to selected segment, and all selected segments if applicable if (col0Changed) { - uint32_t colIn0 = RGBW32(colIn[0], colIn[1], colIn[2], colIn[3]); - selseg.setColor(0, colIn0); - if (!singleSegment) strip.setColor(0, colIn0); // will set color to all active & selected segments + col0 = RGBW32(colIn[0], colIn[1], colIn[2], colIn[3]); + selseg.setColor(0, col0); } if (col1Changed) { - uint32_t colIn1 = RGBW32(colInSec[0], colInSec[1], colInSec[2], colInSec[3]); - selseg.setColor(1, colIn1); - if (!singleSegment) strip.setColor(1, colIn1); // will set color to all active & selected segments + col1 = RGBW32(colInSec[0], colInSec[1], colInSec[2], colInSec[3]); + selseg.setColor(1, col1); + } + + //swap 2nd & 1st + pos = req.indexOf(F("SC")); + if (pos > 0) { + std::swap(col0,col1); + col0Changed = col1Changed = true; } bool fxModeChanged = false, speedChanged = false, intensityChanged = false, paletteChanged = false; @@ -1055,6 +1049,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) if (speedChanged) seg.speed = speedIn; if (intensityChanged) seg.intensity = intensityIn; if (paletteChanged) seg.setPalette(paletteIn); + if (col0Changed) seg.setColor(0, col0); + if (col1Changed) seg.setColor(1, col1); + if (col2Changed) seg.setColor(2, col2); if (custom1Changed) seg.custom1 = custom1In; if (custom2Changed) seg.custom2 = custom2In; if (custom3Changed) seg.custom3 = custom3In; diff --git a/wled00/udp.cpp b/wled00/udp.cpp index a615cefcb..0ff39f110 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -234,12 +234,12 @@ void parseNotifyPacket(uint8_t *udpIn) { //apply colors from notification to main segment, only if not syncing full segments if ((receiveNotificationColor || !someSel) && (version < 11 || !receiveSegmentOptions)) { // primary color, only apply white if intented (version > 0) - strip.setColor(0, RGBW32(udpIn[3], udpIn[4], udpIn[5], (version > 0) ? udpIn[10] : 0)); + strip.getMainSegment().setColor(0, RGBW32(udpIn[3], udpIn[4], udpIn[5], (version > 0) ? udpIn[10] : 0)); if (version > 1) { - strip.setColor(1, RGBW32(udpIn[12], udpIn[13], udpIn[14], udpIn[15])); // secondary color + strip.getMainSegment().setColor(1, RGBW32(udpIn[12], udpIn[13], udpIn[14], udpIn[15])); // secondary color } if (version > 6) { - strip.setColor(2, RGBW32(udpIn[20], udpIn[21], udpIn[22], udpIn[23])); // tertiary color + strip.getMainSegment().setColor(2, RGBW32(udpIn[20], udpIn[21], udpIn[22], udpIn[23])); // tertiary color if (version > 9 && udpIn[37] < 255) { // valid CCT/Kelvin value unsigned cct = udpIn[38]; if (udpIn[37] > 0) { //Kelvin diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 39e0d250b..a80808a78 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -221,6 +221,7 @@ void WLED::loop() strip.finalizeInit(); // also loads default ledmap if present if (aligned) strip.makeAutoSegments(); else strip.fixInvalidSegments(); + BusManager::setBrightness(bri); // fix re-initialised bus' brightness doSerializeConfig = true; } if (loadLedmap >= 0) { @@ -571,10 +572,11 @@ void WLED::beginStrip() } else { // fix for #3196 if (bootPreset > 0) { - bool oldTransition = fadeTransition; // workaround if transitions are enabled - fadeTransition = false; // ignore transitions temporarily - strip.setColor(0, BLACK); // set all segments black - fadeTransition = oldTransition; // restore transitions + // set all segments black (no transition) + for (unsigned i = 0; i < strip.getSegmentsNum(); i++) { + Segment &seg = strip.getSegment(i); + if (seg.isActive()) seg.colors[0] = BLACK; + } col[0] = col[1] = col[2] = col[3] = 0; // needed for colorUpdated() } briLast = briS; bri = 0; diff --git a/wled00/wled.h b/wled00/wled.h index 052f29b29..f8021e92b 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -584,7 +584,6 @@ WLED_GLOBAL bool transitionActive _INIT(false); WLED_GLOBAL uint16_t transitionDelay _INIT(750); // global transition duration WLED_GLOBAL uint16_t transitionDelayDefault _INIT(750); // default transition time (stored in cfg.json) WLED_GLOBAL unsigned long transitionStartTime; -WLED_GLOBAL float tperLast _INIT(0.0f); // crossfade transition progress, 0.0f - 1.0f WLED_GLOBAL bool jsonTransitionOnce _INIT(false); // flag to override transitionDelay (playlist, JSON API: "live" & "seg":{"i"} & "tt") WLED_GLOBAL uint8_t randomPaletteChangeTime _INIT(5); // amount of time [s] between random palette changes (min: 1s, max: 255s) WLED_GLOBAL bool useHarmonicRandomPalette _INIT(true); // use *harmonic* random palette generation (nicer looking) or truly random From a4c49aa35e93d158033844f6d433fae56def8514 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Wed, 2 Oct 2024 20:15:58 +0200 Subject: [PATCH 056/234] Fix for #4005 --- wled00/wled.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 39e0d250b..13d43218a 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -219,6 +219,7 @@ void WLED::loop() busConfigs[i] = nullptr; } strip.finalizeInit(); // also loads default ledmap if present + BusManager::setBrightness(bri); // fix re-initialised bus' brightness #4005 if (aligned) strip.makeAutoSegments(); else strip.fixInvalidSegments(); doSerializeConfig = true; From dd27504d30e021e038a70ba5900ce47079a09f96 Mon Sep 17 00:00:00 2001 From: Nicolas Saugnier Date: Thu, 3 Oct 2024 11:04:47 +0200 Subject: [PATCH 057/234] Fixed Improv rejecting all properly formatted packets. --- wled00/improv.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/wled00/improv.cpp b/wled00/improv.cpp index abfd463c6..66f14aec6 100644 --- a/wled00/improv.cpp +++ b/wled00/improv.cpp @@ -123,6 +123,7 @@ void handleImprovPacket() { } checksum += next; + checksum &= 0xFF; packetByte++; } } From ae1b6af0d43b79557ff10a4feb4d709722bd69f8 Mon Sep 17 00:00:00 2001 From: Nicolas Saugnier Date: Thu, 3 Oct 2024 11:07:58 +0200 Subject: [PATCH 058/234] Indent formatting... --- wled00/improv.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/improv.cpp b/wled00/improv.cpp index 66f14aec6..31547f86c 100644 --- a/wled00/improv.cpp +++ b/wled00/improv.cpp @@ -123,7 +123,7 @@ void handleImprovPacket() { } checksum += next; - checksum &= 0xFF; + checksum &= 0xFF; packetByte++; } } From 949b9fb10ea7a841f6b9f2ccc49da4347cc84e36 Mon Sep 17 00:00:00 2001 From: Nicolas Saugnier Date: Thu, 3 Oct 2024 15:21:39 +0200 Subject: [PATCH 059/234] Fixed Polybus.canShow always returning true on ESP32 --- wled00/bus_wrapper.h | 72 ++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index bf2d30c0e..84c32f46b 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -766,47 +766,47 @@ class PolyBus { #endif #ifdef ARDUINO_ARCH_ESP32 // RMT buses - case I_32_RN_NEO_3: (static_cast(busPtr))->CanShow(); break; - case I_32_RN_NEO_4: (static_cast(busPtr))->CanShow(); break; - case I_32_RN_400_3: (static_cast(busPtr))->CanShow(); break; - case I_32_RN_TM1_4: (static_cast(busPtr))->CanShow(); break; - case I_32_RN_TM2_3: (static_cast(busPtr))->CanShow(); break; - case I_32_RN_UCS_3: (static_cast(busPtr))->CanShow(); break; - case I_32_RN_UCS_4: (static_cast(busPtr))->CanShow(); break; - case I_32_RN_APA106_3: (static_cast(busPtr))->CanShow(); break; - case I_32_RN_FW6_5: (static_cast(busPtr))->CanShow(); break; - case I_32_RN_2805_5: (static_cast(busPtr))->CanShow(); break; - case I_32_RN_TM1914_3: (static_cast(busPtr))->CanShow(); break; - case I_32_RN_SM16825_5: (static_cast(busPtr))->CanShow(); break; + case I_32_RN_NEO_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_RN_NEO_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_RN_400_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_RN_TM1_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_RN_TM2_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_RN_UCS_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_RN_UCS_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_RN_APA106_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_RN_FW6_5: return (static_cast(busPtr))->CanShow(); break; + case I_32_RN_2805_5: return (static_cast(busPtr))->CanShow(); break; + case I_32_RN_TM1914_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_RN_SM16825_5: return (static_cast(busPtr))->CanShow(); break; // I2S1 bus or paralell buses #ifndef WLED_NO_I2S1_PIXELBUS - case I_32_I1_NEO_3: if (useParallelI2S) (static_cast(busPtr))->CanShow(); else (static_cast(busPtr))->CanShow(); break; - case I_32_I1_NEO_4: if (useParallelI2S) (static_cast(busPtr))->CanShow(); else (static_cast(busPtr))->CanShow(); break; - case I_32_I1_400_3: if (useParallelI2S) (static_cast(busPtr))->CanShow(); else (static_cast(busPtr))->CanShow(); break; - case I_32_I1_TM1_4: if (useParallelI2S) (static_cast(busPtr))->CanShow(); else (static_cast(busPtr))->CanShow(); break; - case I_32_I1_TM2_3: if (useParallelI2S) (static_cast(busPtr))->CanShow(); else (static_cast(busPtr))->CanShow(); break; - case I_32_I1_UCS_3: if (useParallelI2S) (static_cast(busPtr))->CanShow(); else (static_cast(busPtr))->CanShow(); break; - case I_32_I1_UCS_4: if (useParallelI2S) (static_cast(busPtr))->CanShow(); else (static_cast(busPtr))->CanShow(); break; - case I_32_I1_APA106_3: if (useParallelI2S) (static_cast(busPtr))->CanShow(); else (static_cast(busPtr))->CanShow(); break; - case I_32_I1_FW6_5: if (useParallelI2S) (static_cast(busPtr))->CanShow(); else (static_cast(busPtr))->CanShow(); break; - case I_32_I1_2805_5: if (useParallelI2S) (static_cast(busPtr))->CanShow(); else (static_cast(busPtr))->CanShow(); break; - case I_32_I1_TM1914_3: if (useParallelI2S) (static_cast(busPtr))->CanShow(); else (static_cast(busPtr))->CanShow(); break; - case I_32_I1_SM16825_5: if (useParallelI2S) (static_cast(busPtr))->CanShow(); else (static_cast(busPtr))->CanShow(); break; + case I_32_I1_NEO_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I1_NEO_4: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I1_400_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I1_TM1_4: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I1_TM2_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I1_UCS_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I1_UCS_4: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I1_APA106_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I1_FW6_5: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I1_2805_5: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I1_TM1914_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I1_SM16825_5: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; #endif // I2S0 bus #ifndef WLED_NO_I2S0_PIXELBUS - case I_32_I0_NEO_3: (static_cast(busPtr))->CanShow(); break; - case I_32_I0_NEO_4: (static_cast(busPtr))->CanShow(); break; - case I_32_I0_400_3: (static_cast(busPtr))->CanShow(); break; - case I_32_I0_TM1_4: (static_cast(busPtr))->CanShow(); break; - case I_32_I0_TM2_3: (static_cast(busPtr))->CanShow(); break; - case I_32_I0_UCS_3: (static_cast(busPtr))->CanShow(); break; - case I_32_I0_UCS_4: (static_cast(busPtr))->CanShow(); break; - case I_32_I0_APA106_3: (static_cast(busPtr))->CanShow(); break; - case I_32_I0_FW6_5: (static_cast(busPtr))->CanShow(); break; - case I_32_I0_2805_5: (static_cast(busPtr))->CanShow(); break; - case I_32_I0_TM1914_3: (static_cast(busPtr))->CanShow(); break; - case I_32_I0_SM16825_5: (static_cast(busPtr))->CanShow(); break; + case I_32_I0_NEO_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_I0_NEO_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_I0_400_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_I0_TM1_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_I0_TM2_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_I0_UCS_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_I0_UCS_4: return (static_cast(busPtr))->CanShow(); break; + case I_32_I0_APA106_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_I0_FW6_5: return (static_cast(busPtr))->CanShow(); break; + case I_32_I0_2805_5: return (static_cast(busPtr))->CanShow(); break; + case I_32_I0_TM1914_3: return (static_cast(busPtr))->CanShow(); break; + case I_32_I0_SM16825_5: return (static_cast(busPtr))->CanShow(); break; #endif #endif case I_HS_DOT_3: return (static_cast(busPtr))->CanShow(); break; From a15c391e6c00dd1b81f4e3116aa87a81628a17e8 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 3 Oct 2024 21:19:34 +0200 Subject: [PATCH 060/234] Improvement to `setPixelColorXY` and some flash optimisations - changes to `setPixelColorXY` give an extra FPS, some checks and the loops are only done when needed, additional function call is still faster (force inlining it gives negligible speed boost but eats more flash) - commented out the unused `boxBlur` function - code size improvemnts (also faster) in `moveX()` and `moveY()` by only copying whats required and avoiding code duplications - consolidated the `blur()` functions by enabling asymmetrical blur2D() to replace `blurRow` and `blurCol` - compiler warning fixes (explicit unsigned casts) --- wled00/FX.h | 19 ++- wled00/FX_2Dfcn.cpp | 284 +++++++++++++++++++++----------------------- wled00/FX_fcn.cpp | 2 +- 3 files changed, 142 insertions(+), 163 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 14c268162..c06332c76 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -457,6 +457,8 @@ typedef struct Segment { {} } *_t; + [[gnu::hot]] void _setPixelColorXY_raw(int& x, int& y, uint32_t& col); // set pixel without mapping (internal use only) + public: Segment(uint16_t sStart=0, uint16_t sStop=30) : @@ -617,12 +619,10 @@ typedef struct Segment { // 2D Blur: shortcuts for bluring columns or rows only (50% faster than full 2D blur) inline void blurCols(fract8 blur_amount, bool smear = false) { // blur all columns - const unsigned cols = virtualWidth(); - for (unsigned k = 0; k < cols; k++) blurCol(k, blur_amount, smear); + blur2D(0, blur_amount, smear); } inline void blurRows(fract8 blur_amount, bool smear = false) { // blur all rows - const unsigned rows = virtualHeight(); - for ( unsigned i = 0; i < rows; i++) blurRow(i, blur_amount, smear); + blur2D(blur_amount, 0, smear); } // 2D matrix @@ -649,10 +649,8 @@ typedef struct Segment { inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool preserveCR = true) { addPixelColorXY(x, y, RGBW32(r,g,b,w), preserveCR); } inline void addPixelColorXY(int x, int y, CRGB c, bool preserveCR = true) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), preserveCR); } inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), fade, true)); } - void box_blur(unsigned r = 1U, bool smear = false); // 2D box blur - void blur2D(uint8_t blur_amount, bool smear = false); - void blurRow(int row, fract8 blur_amount, bool smear = false); - void blurCol(int col, fract8 blur_amount, bool smear = false); + //void box_blur(unsigned r = 1U, bool smear = false); // 2D box blur + void blur2D(uint8_t blur_x, uint8_t blur_y, bool smear = false); void moveX(int delta, bool wrap = false); void moveY(int delta, bool wrap = false); void move(unsigned dir, unsigned delta, bool wrap = false); @@ -666,7 +664,6 @@ typedef struct Segment { inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0)); } // automatic inline inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, int8_t rotate = 0) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0), rotate); } // automatic inline void wu_pixel(uint32_t x, uint32_t y, CRGB c); - inline void blur2d(fract8 blur_amount) { blur(blur_amount); } inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); } #else inline uint16_t XY(int x, int y) { return x; } @@ -687,8 +684,8 @@ typedef struct Segment { inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool saturate = false) { addPixelColor(x, RGBW32(r,g,b,w), saturate); } inline void addPixelColorXY(int x, int y, CRGB c, bool saturate = false) { addPixelColor(x, RGBW32(c.r,c.g,c.b,0), saturate); } inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { fadePixelColor(x, fade); } - inline void box_blur(unsigned i, bool vertical, fract8 blur_amount) {} - inline void blur2D(uint8_t blur_amount, bool smear = false) {} + //inline void box_blur(unsigned i, bool vertical, fract8 blur_amount) {} + inline void blur2D(uint8_t blur_x, uint8_t blur_y, bool smear = false) {} inline void blurRow(int row, fract8 blur_amount, bool smear = false) {} inline void blurCol(int col, fract8 blur_amount, bool smear = false) {} inline void moveX(int delta, bool wrap = false) {} diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 9b39b4c8f..3ad061a8c 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -168,13 +168,34 @@ uint16_t IRAM_ATTR_YN Segment::XY(int x, int y) return isActive() ? (x%vW) + (y%vH) * vW : 0; } +// raw setColor function without checks (checks are done in setPixelColorXY()) +void IRAM_ATTR_YN Segment::_setPixelColorXY_raw(int& x, int& y, uint32_t& col) +{ +#ifndef WLED_DISABLE_MODE_BLEND + // if blending modes, blend with underlying pixel + if (_modeBlend) col = color_blend(strip.getPixelColorXY(start + x, startY + y), col, 0xFFFFU - progress(), true); +#endif + strip.setPixelColorXY(start + x, startY + y, col); + if (mirror) { //set the corresponding horizontally mirrored pixel + if (transpose) strip.setPixelColorXY(start + x, startY + height() - y - 1, col); + else strip.setPixelColorXY(start + width() - x - 1, startY + y, col); + } + if (mirror_y) { //set the corresponding vertically mirrored pixel + if (transpose) strip.setPixelColorXY(start + width() - x - 1, startY + y, col); + else strip.setPixelColorXY(start + x, startY + height() - y - 1, col); + } + if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel + strip.setPixelColorXY(start + width() - x - 1, startY + height() - y - 1, col); + } +} + void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) { if (!isActive()) return; // not active const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) const int vH = vHeight(); // segment height in logical pixels (is always >= 1) - if (unsigned(x) >= vW || unsigned(y) >= vH) return; // if pixel would fall out of virtual segment just exit + if (unsigned(x) >= unsigned(vW) || unsigned(y) >= unsigned(vH)) return; // if pixel would fall out of virtual segment just exit // if color is unscaled if (!_colorScaled) col = color_fade(col, _segBri); @@ -182,36 +203,28 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) if (reverse ) x = vW - x - 1; if (reverse_y) y = vH - y - 1; if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed - x *= groupLength(); // expand to physical pixels - y *= groupLength(); // expand to physical pixels - int W = width(); - int H = height(); + unsigned groupLen = groupLength(); - int yY = y; - for (int j = 0; j < grouping; j++) { // groupping vertically - if (yY >= H) break; - int xX = x; - for (int g = 0; g < grouping; g++) { // groupping horizontally - if (xX >= W) break; // we have reached X dimension's end -#ifndef WLED_DISABLE_MODE_BLEND - // if blending modes, blend with underlying pixel - if (_modeBlend) col = color_blend(strip.getPixelColorXY(start + xX, startY + yY), col, 0xFFFFU - progress(), true); -#endif - strip.setPixelColorXY(start + xX, startY + yY, col); - if (mirror) { //set the corresponding horizontally mirrored pixel - if (transpose) strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col); - else strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col); + if(groupLen > 1) + { + int W = width(); + int H = height(); + x *= groupLen; // expand to physical pixels + y *= groupLen; // expand to physical pixels + int yY = y; + for (int j = 0; j < grouping; j++) { // groupping vertically + if (yY >= H) break; + int xX = x; + for (int g = 0; g < grouping; g++) { // groupping horizontally + if (xX >= W) break; // we have reached X dimension's end + _setPixelColorXY_raw(xX, yY, col); + xX++; } - if (mirror_y) { //set the corresponding vertically mirrored pixel - if (transpose) strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col); - else strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col); - } - if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel - strip.setPixelColorXY(start + width() - xX - 1, startY + height() - yY - 1, col); - } - xX++; + yY++; } - yY++; + } + else { + _setPixelColorXY_raw(x, y, col); } } @@ -263,7 +276,7 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const { if (!isActive()) return 0; // not active int vW = vWidth(); int vH = vHeight(); - if (x >= vW || y >= vH || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit + if (unsigned(x) >= unsigned(vW) || unsigned(y) >= unsigned(vH)) return 0; // if pixel would fall out of virtual segment just exit if (reverse ) x = vW - x - 1; if (reverse_y) y = vH - y - 1; if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed @@ -273,119 +286,62 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const { return strip.getPixelColorXY(start + x, startY + y); } -// blurRow: perform a blur on a row of a rectangular matrix -void Segment::blurRow(int row, fract8 blur_amount, bool smear){ - if (!isActive() || blur_amount == 0) return; // not active - const int cols = vWidth(); - const int rows = vHeight(); - - if (row >= rows) return; - // blur one row - uint8_t keep = smear ? 255 : 255 - blur_amount; - uint8_t seep = blur_amount >> 1; - uint32_t carryover = BLACK; - uint32_t lastnew; - uint32_t last; - uint32_t curnew = BLACK; - for (int x = 0; x < cols; x++) { - uint32_t cur = getPixelColorXY(x, row); - uint32_t part = color_fade(cur, seep); - curnew = color_fade(cur, keep); - if (x > 0) { - if (carryover) curnew = color_add(curnew, carryover); - uint32_t prev = color_add(lastnew, part); - // optimization: only set pixel if color has changed - if (last != prev) setPixelColorXY(x - 1, row, prev); - } else // first pixel - setPixelColorXY(x, row, curnew); - lastnew = curnew; - last = cur; // save original value for comparison on next iteration - carryover = part; - } - setPixelColorXY(cols-1, row, curnew); // set last pixel -} - -// blurCol: perform a blur on a column of a rectangular matrix -void Segment::blurCol(int col, fract8 blur_amount, bool smear) { - if (!isActive() || blur_amount == 0) return; // not active - const int cols = vWidth(); - const int rows = vHeight(); - - if (col >= cols) return; - // blur one column - uint8_t keep = smear ? 255 : 255 - blur_amount; - uint8_t seep = blur_amount >> 1; - uint32_t carryover = BLACK; - uint32_t lastnew; - uint32_t last; - uint32_t curnew = BLACK; - for (int y = 0; y < rows; y++) { - uint32_t cur = getPixelColorXY(col, y); - uint32_t part = color_fade(cur, seep); - curnew = color_fade(cur, keep); - if (y > 0) { - if (carryover) curnew = color_add(curnew, carryover); - uint32_t prev = color_add(lastnew, part); - // optimization: only set pixel if color has changed - if (last != prev) setPixelColorXY(col, y - 1, prev); - } else // first pixel - setPixelColorXY(col, y, curnew); - lastnew = curnew; - last = cur; //save original value for comparison on next iteration - carryover = part; - } - setPixelColorXY(col, rows - 1, curnew); -} - -void Segment::blur2D(uint8_t blur_amount, bool smear) { - if (!isActive() || blur_amount == 0) return; // not active +// 2D blurring, can be asymmetrical +void Segment::blur2D(uint8_t blur_x, uint8_t blur_y, bool smear) { + if (!isActive()) return; // not active const unsigned cols = vWidth(); const unsigned rows = vHeight(); - - const uint8_t keep = smear ? 255 : 255 - blur_amount; - const uint8_t seep = blur_amount >> (1 + smear); uint32_t lastnew; uint32_t last; - for (unsigned row = 0; row < rows; row++) { - uint32_t carryover = BLACK; - uint32_t curnew = BLACK; - for (unsigned x = 0; x < cols; x++) { - uint32_t cur = getPixelColorXY(x, row); - uint32_t part = color_fade(cur, seep); - curnew = color_fade(cur, keep); - if (x > 0) { - if (carryover) curnew = color_add(curnew, carryover); - uint32_t prev = color_add(lastnew, part); - // optimization: only set pixel if color has changed - if (last != prev) setPixelColorXY(x - 1, row, prev); - } else setPixelColorXY(x, row, curnew); // first pixel - lastnew = curnew; - last = cur; // save original value for comparison on next iteration - carryover = part; + if(blur_x) { + const uint8_t keepx = smear ? 255 : 255 - blur_x; + const uint8_t seepx = blur_x >> (1 + smear); + for (unsigned row = 0; row < rows; row++) { // blur rows (x direction) + uint32_t carryover = BLACK; + uint32_t curnew = BLACK; + for (unsigned x = 0; x < cols; x++) { + uint32_t cur = getPixelColorXY(x, row); + uint32_t part = color_fade(cur, seepx); + curnew = color_fade(cur, keepx); + if (x > 0) { + if (carryover) curnew = color_add(curnew, carryover); + uint32_t prev = color_add(lastnew, part); + // optimization: only set pixel if color has changed + if (last != prev) setPixelColorXY(x - 1, row, prev); + } else setPixelColorXY(x, row, curnew); // first pixel + lastnew = curnew; + last = cur; // save original value for comparison on next iteration + carryover = part; + } + setPixelColorXY(cols-1, row, curnew); // set last pixel } - setPixelColorXY(cols-1, row, curnew); // set last pixel } - for (unsigned col = 0; col < cols; col++) { - uint32_t carryover = BLACK; - uint32_t curnew = BLACK; - for (unsigned y = 0; y < rows; y++) { - uint32_t cur = getPixelColorXY(col, y); - uint32_t part = color_fade(cur, seep); - curnew = color_fade(cur, keep); - if (y > 0) { - if (carryover) curnew = color_add(curnew, carryover); - uint32_t prev = color_add(lastnew, part); - // optimization: only set pixel if color has changed - if (last != prev) setPixelColorXY(col, y - 1, prev); - } else setPixelColorXY(col, y, curnew); // first pixel - lastnew = curnew; - last = cur; //save original value for comparison on next iteration - carryover = part; + if(blur_y) { + const uint8_t keepy = smear ? 255 : 255 - blur_y; + const uint8_t seepy = blur_y >> (1 + smear); + for (unsigned col = 0; col < cols; col++) { + uint32_t carryover = BLACK; + uint32_t curnew = BLACK; + for (unsigned y = 0; y < rows; y++) { + uint32_t cur = getPixelColorXY(col, y); + uint32_t part = color_fade(cur, seepy); + curnew = color_fade(cur, keepy); + if (y > 0) { + if (carryover) curnew = color_add(curnew, carryover); + uint32_t prev = color_add(lastnew, part); + // optimization: only set pixel if color has changed + if (last != prev) setPixelColorXY(col, y - 1, prev); + } else setPixelColorXY(col, y, curnew); // first pixel + lastnew = curnew; + last = cur; //save original value for comparison on next iteration + carryover = part; + } + setPixelColorXY(col, rows - 1, curnew); } - setPixelColorXY(col, rows - 1, curnew); } } +/* // 2D Box blur void Segment::box_blur(unsigned radius, bool smear) { if (!isActive() || radius == 0) return; // not active @@ -458,43 +414,69 @@ void Segment::box_blur(unsigned radius, bool smear) { delete[] tmpBSum; delete[] tmpWSum; } - +*/ void Segment::moveX(int delta, bool wrap) { - if (!isActive()) return; // not active + if (!isActive() || !delta) return; // not active const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) const int vH = vHeight(); // segment height in logical pixels (is always >= 1) - if (!delta || abs(delta) >= vW) return; + int absDelta = abs(delta); + if (absDelta >= vW) return; uint32_t newPxCol[vW]; + int newDelta; + int stop = vW; + int start = 0; + if(wrap) newDelta = (delta + vW) % vW; // +cols in case delta < 0 + else { + if(delta < 0) start = -delta; + stop = vW - absDelta; + newDelta = delta > 0 ? delta : 0; + } for (int y = 0; y < vH; y++) { - if (delta > 0) { - for (int x = 0; x < vW-delta; x++) newPxCol[x] = getPixelColorXY((x + delta), y); - for (int x = vW-delta; x < vW; x++) newPxCol[x] = getPixelColorXY(wrap ? (x + delta) - vW : x, y); - } else { - for (int x = vW-1; x >= -delta; x--) newPxCol[x] = getPixelColorXY((x + delta), y); - for (int x = -delta-1; x >= 0; x--) newPxCol[x] = getPixelColorXY(wrap ? (x + delta) + vW : x, y); + for (int x = 0; x < stop; x++) { + int srcX; + if (wrap) { + srcX = (x + newDelta) % vW; // Wrap using modulo when `wrap` is true + } else { + srcX = x + newDelta; + } + newPxCol[x] = getPixelColorXY(srcX, y); } - for (int x = 0; x < vW; x++) setPixelColorXY(x, y, newPxCol[x]); + for (int x = 0; x < stop; x++) setPixelColorXY(x + start, y, newPxCol[x]); } } void Segment::moveY(int delta, bool wrap) { - if (!isActive()) return; // not active + if (!isActive() || !delta) return; // not active const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) const int vH = vHeight(); // segment height in logical pixels (is always >= 1) - if (!delta || abs(delta) >= vH) return; + int absDelta = abs(delta); + if (absDelta >= vH) return; uint32_t newPxCol[vH]; + int newDelta; + int stop = vH; + int start = 0; + if(wrap) newDelta = (delta + vH) % vH; // +rows in case delta < 0 + else { + if(delta < 0) start = -delta; + stop = vH - absDelta; + newDelta = delta > 0 ? delta : 0; + } for (int x = 0; x < vW; x++) { - if (delta > 0) { - for (int y = 0; y < vH-delta; y++) newPxCol[y] = getPixelColorXY(x, (y + delta)); - for (int y = vH-delta; y < vH; y++) newPxCol[y] = getPixelColorXY(x, wrap ? (y + delta) - vH : y); - } else { - for (int y = vH-1; y >= -delta; y--) newPxCol[y] = getPixelColorXY(x, (y + delta)); - for (int y = -delta-1; y >= 0; y--) newPxCol[y] = getPixelColorXY(x, wrap ? (y + delta) + vH : y); + for (int y = 0; y < stop; y++) { + int srcY; + if (wrap) { + srcY = (y + newDelta) % vH; // Wrap using modulo when `wrap` is true + } else { + srcY = y + newDelta; + } + newPxCol[y] = getPixelColorXY(x, srcY); } - for (int y = 0; y < vH; y++) setPixelColorXY(x, y, newPxCol[y]); + for (int y = 0; y < stop; y++) setPixelColorXY(x, y + start, newPxCol[y]); } } +// TODO: check if it works, used in FX rain and 2D spaceships + // move() - move all pixels in desired direction delta number of pixels // @param dir direction: 0=left, 1=left-up, 2=up, 3=right-up, 4=right, 5=right-down, 6=down, 7=left-down // @param delta number of pixels to move diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 7927269ed..613b41fad 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1146,7 +1146,7 @@ void Segment::blur(uint8_t blur_amount, bool smear) { #ifndef WLED_DISABLE_2D if (is2D()) { // compatibility with 2D - blur2D(blur_amount, smear); + blur2D(blur_amount, blur_amount, smear); // symmetrical 2D blur //box_blur(map(blur_amount,1,255,1,3), smear); return; } From ca062140f3c17eb64928a5b47566bb7599828cb1 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 3 Oct 2024 19:39:39 +0000 Subject: [PATCH 061/234] removed todo. --- wled00/FX_2Dfcn.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 3ad061a8c..6b3e6ef11 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -475,8 +475,6 @@ void Segment::moveY(int delta, bool wrap) { } } -// TODO: check if it works, used in FX rain and 2D spaceships - // move() - move all pixels in desired direction delta number of pixels // @param dir direction: 0=left, 1=left-up, 2=up, 3=right-up, 4=right, 5=right-down, 6=down, 7=left-down // @param delta number of pixels to move From 7b855c851d7824596557d4444796c2c3aec6356c Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 5 Oct 2024 12:29:31 +0200 Subject: [PATCH 062/234] Added integer based `sin()/cos()` functions, changed all trig functions to wled_math - `sin16_t() / cos16_t()` are faster and more accurate than fastled versions - `sin_approx() / cos_approx()` are float wrappers for `sin16_t() / cos16_t()` and are accurate enough to replace `sinf()/cosf()` - `atan2()` is used only in octopus to calculate center offset, new approximated version saves flash - `tan(), atan(), asin(), acos(), floor(), fmod()` are used only for sunrise/sunset calculation, using wled_math version saves flash - `beatsinx()` replacements are to make use of new `sin16_t()/sin8_t()` functions to reduce flash size - Extensively tested surnise/sunset calculation: deviation is 1min. max - Tested some of the relevant FX and found no visual difference: Julia, 2D Drift, Drift Rose, Ghost rider, Rotozoomer, Palette, Arc 1D expansion - total flash savings: 7.4k --- usermods/Analog_Clock/Analog_Clock.h | 4 +- wled00/FX.cpp | 258 +++++++++++++-------------- wled00/fcn_declare.h | 53 +++--- wled00/util.cpp | 41 ++++- wled00/wled_math.cpp | 89 ++++++++- 5 files changed, 288 insertions(+), 157 deletions(-) diff --git a/usermods/Analog_Clock/Analog_Clock.h b/usermods/Analog_Clock/Analog_Clock.h index 596f0acb3..9d82f7670 100644 --- a/usermods/Analog_Clock/Analog_Clock.h +++ b/usermods/Analog_Clock/Analog_Clock.h @@ -102,9 +102,9 @@ private: void secondsEffectSineFade(int16_t secondLed, Toki::Time const& time) { uint32_t ms = time.ms % 1000; - uint8_t b0 = (cos8(ms * 64 / 1000) - 128) * 2; + uint8_t b0 = (cos8_t(ms * 64 / 1000) - 128) * 2; setPixelColor(secondLed, gamma32(scale32(secondColor, b0))); - uint8_t b1 = (sin8(ms * 64 / 1000) - 128) * 2; + uint8_t b1 = (sin8_t(ms * 64 / 1000) - 128) * 2; setPixelColor(inc(secondLed, 1, secondsSegment), gamma32(scale32(secondColor, b1))); } diff --git a/wled00/FX.cpp b/wled00/FX.cpp index f3e82275c..338dd2df9 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -39,7 +39,7 @@ // effect utility functions uint8_t sin_gap(uint16_t in) { if (in & 0x100) return 0; - return sin8(in + 192); // correct phase shift of sine so that it starts and stops at 0 + return sin8_t(in + 192); // correct phase shift of sine so that it starts and stops at 0 } uint16_t triwave16(uint16_t in) { @@ -349,7 +349,7 @@ uint16_t mode_breath(void) { counter = (counter >> 2) + (counter >> 4); //0-16384 + 0-2048 if (counter < 16384) { if (counter > 8192) counter = 8192 - (counter - 8192); - var = sin16(counter) / 103; //close to parabolic in range 0-8192, max val. 23170 + var = sin16_t(counter) / 103; //close to parabolic in range 0-8192, max val. 23170 } unsigned lum = 30 + var; @@ -531,7 +531,7 @@ static uint16_t running_base(bool saw, bool dual=false) { } a = 255 - a; } - uint8_t s = dual ? sin_gap(a) : sin8(a); + uint8_t s = dual ? sin_gap(a) : sin8_t(a); uint32_t ca = color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), s); if (dual) { unsigned b = (SEGLEN-1-i)*x_scale - counter; @@ -1893,16 +1893,16 @@ uint16_t mode_pride_2015(void) { unsigned sPseudotime = SEGENV.step; unsigned sHue16 = SEGENV.aux0; - uint8_t sat8 = beatsin88( 87, 220, 250); - uint8_t brightdepth = beatsin88( 341, 96, 224); - unsigned brightnessthetainc16 = beatsin88( 203, (25 * 256), (40 * 256)); - unsigned msmultiplier = beatsin88(147, 23, 60); + uint8_t sat8 = beatsin88_t( 87, 220, 250); + uint8_t brightdepth = beatsin88_t( 341, 96, 224); + unsigned brightnessthetainc16 = beatsin88_t( 203, (25 * 256), (40 * 256)); + unsigned msmultiplier = beatsin88_t(147, 23, 60); unsigned hue16 = sHue16;//gHue * 256; - unsigned hueinc16 = beatsin88(113, 1, 3000); + unsigned hueinc16 = beatsin88_t(113, 1, 3000); sPseudotime += duration * msmultiplier; - sHue16 += duration * beatsin88( 400, 5,9); + sHue16 += duration * beatsin88_t( 400, 5,9); unsigned brightnesstheta16 = sPseudotime; for (unsigned i = 0 ; i < SEGLEN; i++) { @@ -1910,7 +1910,7 @@ uint16_t mode_pride_2015(void) { uint8_t hue8 = hue16 >> 8; brightnesstheta16 += brightnessthetainc16; - unsigned b16 = sin16( brightnesstheta16 ) + 32768; + unsigned b16 = sin16_t( brightnesstheta16 ) + 32768; unsigned bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536; uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536; @@ -1935,7 +1935,7 @@ uint16_t mode_juggle(void) { CRGB fastled_col; byte dothue = 0; for (int i = 0; i < 8; i++) { - int index = 0 + beatsin88((16 + SEGMENT.speed)*(i + 7), 0, SEGLEN -1); + int index = 0 + beatsin88_t((16 + SEGMENT.speed)*(i + 7), 0, SEGLEN -1); fastled_col = CRGB(SEGMENT.getPixelColor(index)); fastled_col |= (SEGMENT.palette==0)?CHSV(dothue, 220, 255):ColorFromPalette(SEGPALETTE, dothue, 255); SEGMENT.setPixelColor(index, fastled_col); @@ -1956,8 +1956,8 @@ uint16_t mode_palette() { constexpr mathType maxAngle = 0x8000; constexpr mathType staticRotationScale = 256; constexpr mathType animatedRotationScale = 1; - constexpr int16_t (*sinFunction)(uint16_t) = &sin16; - constexpr int16_t (*cosFunction)(uint16_t) = &cos16; + constexpr int16_t (*sinFunction)(uint16_t) = &sin16_t; + constexpr int16_t (*cosFunction)(uint16_t) = &cos16_t; #else using mathType = float; using wideMathType = float; @@ -2141,15 +2141,15 @@ uint16_t mode_colorwaves() { unsigned sPseudotime = SEGENV.step; unsigned sHue16 = SEGENV.aux0; - unsigned brightdepth = beatsin88(341, 96, 224); - unsigned brightnessthetainc16 = beatsin88( 203, (25 * 256), (40 * 256)); - unsigned msmultiplier = beatsin88(147, 23, 60); + unsigned brightdepth = beatsin88_t(341, 96, 224); + unsigned brightnessthetainc16 = beatsin88_t( 203, (25 * 256), (40 * 256)); + unsigned msmultiplier = beatsin88_t(147, 23, 60); unsigned hue16 = sHue16;//gHue * 256; - unsigned hueinc16 = beatsin88(113, 60, 300)*SEGMENT.intensity*10/255; // Use the Intensity Slider for the hues + unsigned hueinc16 = beatsin88_t(113, 60, 300)*SEGMENT.intensity*10/255; // Use the Intensity Slider for the hues sPseudotime += duration * msmultiplier; - sHue16 += duration * beatsin88(400, 5, 9); + sHue16 += duration * beatsin88_t(400, 5, 9); unsigned brightnesstheta16 = sPseudotime; for (int i = 0 ; i < SEGLEN; i++) { @@ -2163,7 +2163,7 @@ uint16_t mode_colorwaves() { } brightnesstheta16 += brightnessthetainc16; - unsigned b16 = sin16(brightnesstheta16) + 32768; + unsigned b16 = sin16_t(brightnesstheta16) + 32768; unsigned bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536; uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536; @@ -2182,7 +2182,7 @@ static const char _data_FX_MODE_COLORWAVES[] PROGMEM = "Colorwaves@!,Hue;!;!"; // colored stripes pulsing at a defined Beats-Per-Minute (BPM) uint16_t mode_bpm() { uint32_t stp = (strip.now / 20) & 0xFF; - uint8_t beat = beatsin8(SEGMENT.speed, 64, 255); + uint8_t beat = beatsin8_t(SEGMENT.speed, 64, 255); for (int i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(stp + (i * 2), false, PALETTE_SOLID_WRAP, 0, beat - stp + (i * 10))); } @@ -2198,7 +2198,7 @@ uint16_t mode_fillnoise8() { unsigned index = inoise8(i * SEGLEN, SEGENV.step + i * SEGLEN); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); } - SEGENV.step += beatsin8(SEGMENT.speed, 1, 6); //10,1,4 + SEGENV.step += beatsin8_t(SEGMENT.speed, 1, 6); //10,1,4 return FRAMETIME; } @@ -2210,13 +2210,13 @@ uint16_t mode_noise16_1() { SEGENV.step += (1 + SEGMENT.speed/16); for (int i = 0; i < SEGLEN; i++) { - unsigned shift_x = beatsin8(11); // the x position of the noise field swings @ 17 bpm + unsigned shift_x = beatsin8_t(11); // the x position of the noise field swings @ 17 bpm unsigned shift_y = SEGENV.step/42; // the y position becomes slowly incremented unsigned real_x = (i + shift_x) * scale; // the x position of the noise field swings @ 17 bpm unsigned real_y = (i + shift_y) * scale; // the y position becomes slowly incremented uint32_t real_z = SEGENV.step; // the z position becomes quickly incremented unsigned noise = inoise16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down - unsigned index = sin8(noise * 3); // map LED color based on noise data + unsigned index = sin8_t(noise * 3); // map LED color based on noise data SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); } @@ -2234,7 +2234,7 @@ uint16_t mode_noise16_2() { unsigned shift_x = SEGENV.step >> 6; // x as a function of time uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field unsigned noise = inoise16(real_x, 0, 4223) >> 8; // get the noise data and scale it down - unsigned index = sin8(noise * 3); // map led color based on noise data + unsigned index = sin8_t(noise * 3); // map led color based on noise data SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0, noise)); } @@ -2255,7 +2255,7 @@ uint16_t mode_noise16_3() { uint32_t real_y = (i + shift_y) * scale; // based on the precalculated positions uint32_t real_z = SEGENV.step*8; unsigned noise = inoise16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down - unsigned index = sin8(noise * 3); // map led color based on noise data + unsigned index = sin8_t(noise * 3); // map led color based on noise data SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0, noise)); } @@ -2335,13 +2335,13 @@ static const char _data_FX_MODE_COLORTWINKLE[] PROGMEM = "Colortwinkles@Fade spe //Calm effect, like a lake at night uint16_t mode_lake() { unsigned sp = SEGMENT.speed/10; - int wave1 = beatsin8(sp +2, -64,64); - int wave2 = beatsin8(sp +1, -64,64); - int wave3 = beatsin8(sp +2, 0,80); + int wave1 = beatsin8_t(sp +2, -64,64); + int wave2 = beatsin8_t(sp +1, -64,64); + int wave3 = beatsin8_t(sp +2, 0,80); for (int i = 0; i < SEGLEN; i++) { - int index = cos8((i*15)+ wave1)/2 + cubicwave8((i*23)+ wave2)/2; + int index = cos8_t((i*15)+ wave1)/2 + cubicwave8((i*23)+ wave2)/2; uint8_t lum = (index > wave3) ? index - wave3 : 0; SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, false, 0, lum)); } @@ -2514,7 +2514,7 @@ static uint16_t ripple_base() { propI /= 2; unsigned cx = rippleorigin >> 8; unsigned cy = rippleorigin & 0xFF; - unsigned mag = scale8(sin8((propF>>2)), amp); + unsigned mag = scale8(sin8_t((propF>>2)), amp); if (propI > 0) SEGMENT.drawCircle(cx, cy, propI, color_blend(SEGMENT.getPixelColorXY(cx + propI, cy), col, mag), true); } else #endif @@ -2581,7 +2581,7 @@ static CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat) unsigned ticks = ms / SEGENV.aux0; unsigned fastcycle8 = ticks; unsigned slowcycle16 = (ticks >> 8) + salt; - slowcycle16 += sin8(slowcycle16); + slowcycle16 += sin8_t(slowcycle16); slowcycle16 = (slowcycle16 * 2053) + 1384; unsigned slowcycle8 = (slowcycle16 & 0xFF) + (slowcycle16 >> 8); @@ -3152,7 +3152,7 @@ static const char _data_FX_MODE_ROLLINGBALLS[] PROGMEM = "Rolling Balls@!,# of b static uint16_t sinelon_base(bool dual, bool rainbow=false) { if (SEGLEN == 1) return mode_static(); SEGMENT.fade_out(SEGMENT.intensity); - unsigned pos = beatsin16(SEGMENT.speed/10,0,SEGLEN-1); + unsigned pos = beatsin16_t(SEGMENT.speed/10,0,SEGLEN-1); if (SEGENV.call == 0) SEGENV.aux0 = pos; uint32_t color1 = SEGMENT.color_from_palette(pos, true, false, 0); uint32_t color2 = SEGCOLOR(2); @@ -3868,13 +3868,13 @@ uint16_t mode_plasma(void) { if (SEGENV.call == 0) { SEGENV.aux0 = random8(0,2); // add a bit of randomness } - unsigned thisPhase = beatsin8(6+SEGENV.aux0,-64,64); - unsigned thatPhase = beatsin8(7+SEGENV.aux0,-64,64); + unsigned thisPhase = beatsin8_t(6+SEGENV.aux0,-64,64); + unsigned thatPhase = beatsin8_t(7+SEGENV.aux0,-64,64); for (unsigned i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set color & brightness based on a wave as follows: unsigned colorIndex = cubicwave8((i*(2+ 3*(SEGMENT.speed >> 5))+thisPhase) & 0xFF)/2 // factor=23 // Create a wave and add a phase change and add another wave with its own phase change. - + cos8((i*(1+ 2*(SEGMENT.speed >> 5))+thatPhase) & 0xFF)/2; // factor=15 // Hey, you can even change the frequencies if you wish. - unsigned thisBright = qsub8(colorIndex, beatsin8(7,0, (128 - (SEGMENT.intensity>>1)))); + + cos8_t((i*(1+ 2*(SEGMENT.speed >> 5))+thatPhase) & 0xFF)/2; // factor=15 // Hey, you can even change the frequencies if you wish. + unsigned thisBright = qsub8(colorIndex, beatsin8_t(7,0, (128 - (SEGMENT.intensity>>1)))); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(colorIndex, false, PALETTE_SOLID_WRAP, 0, thisBright)); } @@ -4001,10 +4001,10 @@ static CRGB pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, u unsigned wavescale_half = (wavescale >> 1) + 20; waveangle += ((120 + SEGMENT.intensity) * i); //original 250 * i - unsigned s16 = sin16(waveangle) + 32768; + unsigned s16 = sin16_t(waveangle) + 32768; unsigned cs = scale16(s16, wavescale_half) + wavescale_half; ci += (cs * i); - unsigned sindex16 = sin16(ci) + 32768; + unsigned sindex16 = sin16_t(ci) + 32768; unsigned sindex8 = scale16(sindex16, 240); return ColorFromPalette(p, sindex8, bri, LINEARBLEND); } @@ -4036,34 +4036,34 @@ uint16_t mode_pacifica() uint64_t deltat = (strip.now >> 2) + ((strip.now * SEGMENT.speed) >> 7); strip.now = deltat; - unsigned speedfactor1 = beatsin16(3, 179, 269); - unsigned speedfactor2 = beatsin16(4, 179, 269); + unsigned speedfactor1 = beatsin16_t(3, 179, 269); + unsigned speedfactor2 = beatsin16_t(4, 179, 269); uint32_t deltams1 = (deltams * speedfactor1) / 256; uint32_t deltams2 = (deltams * speedfactor2) / 256; uint32_t deltams21 = (deltams1 + deltams2) / 2; - sCIStart1 += (deltams1 * beatsin88(1011,10,13)); - sCIStart2 -= (deltams21 * beatsin88(777,8,11)); - sCIStart3 -= (deltams1 * beatsin88(501,5,7)); - sCIStart4 -= (deltams2 * beatsin88(257,4,6)); + sCIStart1 += (deltams1 * beatsin88_t(1011,10,13)); + sCIStart2 -= (deltams21 * beatsin88_t(777,8,11)); + sCIStart3 -= (deltams1 * beatsin88_t(501,5,7)); + sCIStart4 -= (deltams2 * beatsin88_t(257,4,6)); SEGENV.aux0 = sCIStart1; SEGENV.aux1 = sCIStart2; SEGENV.step = sCIStart4; SEGENV.step = (SEGENV.step << 16) + sCIStart3; // Clear out the LED array to a dim background blue-green //SEGMENT.fill(132618); - unsigned basethreshold = beatsin8( 9, 55, 65); + unsigned basethreshold = beatsin8_t( 9, 55, 65); unsigned wave = beat8( 7 ); for (int i = 0; i < SEGLEN; i++) { CRGB c = CRGB(2, 6, 10); // Render each of four layers, with different scales and speeds, that vary over time - c += pacifica_one_layer(i, pacifica_palette_1, sCIStart1, beatsin16(3, 11 * 256, 14 * 256), beatsin8(10, 70, 130), 0-beat16(301)); - c += pacifica_one_layer(i, pacifica_palette_2, sCIStart2, beatsin16(4, 6 * 256, 9 * 256), beatsin8(17, 40, 80), beat16(401)); - c += pacifica_one_layer(i, pacifica_palette_3, sCIStart3, 6 * 256 , beatsin8(9, 10,38) , 0-beat16(503)); - c += pacifica_one_layer(i, pacifica_palette_3, sCIStart4, 5 * 256 , beatsin8(8, 10,28) , beat16(601)); + c += pacifica_one_layer(i, pacifica_palette_1, sCIStart1, beatsin16_t(3, 11 * 256, 14 * 256), beatsin8_t(10, 70, 130), 0-beat16(301)); + c += pacifica_one_layer(i, pacifica_palette_2, sCIStart2, beatsin16_t(4, 6 * 256, 9 * 256), beatsin8_t(17, 40, 80), beat16(401)); + c += pacifica_one_layer(i, pacifica_palette_3, sCIStart3, 6 * 256 , beatsin8_t(9, 10,38) , 0-beat16(503)); + c += pacifica_one_layer(i, pacifica_palette_3, sCIStart4, 5 * 256 , beatsin8_t(8, 10,28) , beat16(601)); // Add extra 'white' to areas where the four layers of light have lined up brightly - unsigned threshold = scale8( sin8( wave), 20) + basethreshold; + unsigned threshold = scale8( sin8_t( wave), 20) + basethreshold; wave += 7; unsigned l = c.getAverageLight(); if (l > threshold) { @@ -4187,7 +4187,7 @@ uint16_t mode_twinkleup(void) { // A very short twinkle routine for (int i = 0; i < SEGLEN; i++) { unsigned ranstart = random8(); // The starting value (aka brightness) for each pixel. Must be consistent each time through the loop for this to work. - unsigned pixBri = sin8(ranstart + 16 * strip.now/(256-SEGMENT.speed)); + unsigned pixBri = sin8_t(ranstart + 16 * strip.now/(256-SEGMENT.speed)); if (random8() > SEGMENT.intensity) pixBri = 0; SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(random8()+strip.now/100, false, PALETTE_SOLID_WRAP, 0), pixBri)); } @@ -4230,7 +4230,7 @@ uint16_t mode_noisepal(void) { // Slow noise SEGMENT.setPixelColor(i, color.red, color.green, color.blue); } - SEGENV.aux0 += beatsin8(10,1,4); // Moving along the distance. Vary it a bit with a sine wave. + SEGENV.aux0 += beatsin8_t(10,1,4); // Moving along the distance. Vary it a bit with a sine wave. return FRAMETIME; } @@ -4312,7 +4312,7 @@ uint16_t mode_chunchun(void) for (unsigned i = 0; i < numBirds; i++) { counter -= span; - unsigned megumin = sin16(counter) + 0x8000; + unsigned megumin = sin16_t(counter) + 0x8000; unsigned bird = uint32_t(megumin * SEGLEN) >> 16; uint32_t c = SEGMENT.color_from_palette((i * 255)/ numBirds, false, false, 0); // no palette wrapping bird = constrain(bird, 0U, SEGLEN-1U); @@ -4481,7 +4481,7 @@ uint16_t mode_washing_machine(void) { SEGENV.step += (speed * 2048) / (512 - SEGMENT.speed); for (int i = 0; i < SEGLEN; i++) { - uint8_t col = sin8(((SEGMENT.intensity / 25 + 1) * 255 * i / SEGLEN) + (SEGENV.step >> 7)); + uint8_t col = sin8_t(((SEGMENT.intensity / 25 + 1) * 255 * i / SEGLEN) + (SEGENV.step >> 7)); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(col, false, PALETTE_SOLID_WRAP, 3)); } @@ -4837,8 +4837,8 @@ static const char _data_FX_MODE_PERLINMOVE[] PROGMEM = "Perlin Move@!,# of pixel uint16_t mode_wavesins(void) { for (int i = 0; i < SEGLEN; i++) { - uint8_t bri = sin8(strip.now/4 + i * SEGMENT.intensity); - uint8_t index = beatsin8(SEGMENT.speed, SEGMENT.custom1, SEGMENT.custom1+SEGMENT.custom2, 0, i * (SEGMENT.custom3<<3)); // custom3 is reduced resolution slider + uint8_t bri = sin8_t(strip.now/4 + i * SEGMENT.intensity); + uint8_t index = beatsin8_t(SEGMENT.speed, SEGMENT.custom1, SEGMENT.custom1+SEGMENT.custom2, 0, i * (SEGMENT.custom3<<3)); // custom3 is reduced resolution slider //SEGMENT.setPixelColor(i, ColorFromPalette(SEGPALETTE, index, bri, LINEARBLEND)); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0, bri)); } @@ -4860,9 +4860,9 @@ uint16_t mode_FlowStripe(void) { for (int i = 0; i < SEGLEN; i++) { int c = (abs(i - hl) / hl) * 127; - c = sin8(c); - c = sin8(c / 2 + t); - byte b = sin8(c + t/8); + c = sin8_t(c); + c = sin8_t(c / 2 + t); + byte b = sin8_t(c + t/8); SEGMENT.setPixelColor(i, CHSV(b + hue, 255, 255)); } @@ -4889,14 +4889,14 @@ uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulma unsigned long t = strip.now/128; // timebase // outer stars for (size_t i = 0; i < 8; i++) { - x = beatsin8(SEGMENT.custom1>>3, 0, cols - 1, 0, ((i % 2) ? 128 : 0) + t * i); - y = beatsin8(SEGMENT.intensity>>3, 0, rows - 1, 0, ((i % 2) ? 192 : 64) + t * i); + x = beatsin8_t(SEGMENT.custom1>>3, 0, cols - 1, 0, ((i % 2) ? 128 : 0) + t * i); + y = beatsin8_t(SEGMENT.intensity>>3, 0, rows - 1, 0, ((i % 2) ? 192 : 64) + t * i); SEGMENT.addPixelColorXY(x, y, SEGMENT.color_from_palette(i*32, false, PALETTE_SOLID_WRAP, SEGMENT.check1?0:255)); } // inner stars for (size_t i = 0; i < 4; i++) { - x = beatsin8(SEGMENT.custom2>>3, cols/4, cols - 1 - cols/4, 0, ((i % 2) ? 128 : 0) + t * i); - y = beatsin8(SEGMENT.custom3 , rows/4, rows - 1 - rows/4, 0, ((i % 2) ? 192 : 64) + t * i); + x = beatsin8_t(SEGMENT.custom2>>3, cols/4, cols - 1 - cols/4, 0, ((i % 2) ? 128 : 0) + t * i); + y = beatsin8_t(SEGMENT.custom3 , rows/4, rows - 1 - rows/4, 0, ((i % 2) ? 192 : 64) + t * i); SEGMENT.addPixelColorXY(x, y, SEGMENT.color_from_palette(255-i*64, false, PALETTE_SOLID_WRAP, SEGMENT.check1?0:255)); } // central white dot @@ -4930,10 +4930,10 @@ uint16_t mode_2DColoredBursts() { // By: ldirko https://editor.so SEGENV.aux0++; // hue SEGMENT.fadeToBlackBy(40); for (size_t i = 0; i < numLines; i++) { - byte x1 = beatsin8(2 + SEGMENT.speed/16, 0, (cols - 1)); - byte x2 = beatsin8(1 + SEGMENT.speed/16, 0, (rows - 1)); - byte y1 = beatsin8(5 + SEGMENT.speed/16, 0, (cols - 1), 0, i * 24); - byte y2 = beatsin8(3 + SEGMENT.speed/16, 0, (rows - 1), 0, i * 48 + 64); + byte x1 = beatsin8_t(2 + SEGMENT.speed/16, 0, (cols - 1)); + byte x2 = beatsin8_t(1 + SEGMENT.speed/16, 0, (rows - 1)); + byte y1 = beatsin8_t(5 + SEGMENT.speed/16, 0, (cols - 1), 0, i * 24); + byte y2 = beatsin8_t(3 + SEGMENT.speed/16, 0, (rows - 1), 0, i * 48 + 64); CRGB color = ColorFromPalette(SEGPALETTE, i * 255 / numLines + (SEGENV.aux0&0xFF), 255, LINEARBLEND); byte xsteps = abs8(x1 - y1) + 1; @@ -4972,8 +4972,8 @@ uint16_t mode_2Ddna(void) { // dna originally by by ldirko at https://pa SEGMENT.fadeToBlackBy(64); for (int i = 0; i < cols; i++) { - SEGMENT.setPixelColorXY(i, beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4 ), ColorFromPalette(SEGPALETTE, i*5+strip.now/17, beatsin8(5, 55, 255, 0, i*10), LINEARBLEND)); - SEGMENT.setPixelColorXY(i, beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4+128), ColorFromPalette(SEGPALETTE, i*5+128+strip.now/17, beatsin8(5, 55, 255, 0, i*10+128), LINEARBLEND)); + SEGMENT.setPixelColorXY(i, beatsin8_t(SEGMENT.speed/8, 0, rows-1, 0, i*4 ), ColorFromPalette(SEGPALETTE, i*5+strip.now/17, beatsin8_t(5, 55, 255, 0, i*10), LINEARBLEND)); + SEGMENT.setPixelColorXY(i, beatsin8_t(SEGMENT.speed/8, 0, rows-1, 0, i*4+128), ColorFromPalette(SEGPALETTE, i*5+128+strip.now/17, beatsin8_t(5, 55, 255, 0, i*10+128), LINEARBLEND)); } SEGMENT.blur(SEGMENT.intensity>>3); @@ -5002,8 +5002,8 @@ uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulma SEGMENT.fadeToBlackBy(135); for (int i = 0; i < rows; i++) { - int x = beatsin8(speeds, 0, cols - 1, 0, i * freq) + beatsin8(speeds - 7, 0, cols - 1, 0, i * freq + 128); - int x1 = beatsin8(speeds, 0, cols - 1, 0, 128 + i * freq) + beatsin8(speeds - 7, 0, cols - 1, 0, 128 + 64 + i * freq); + int x = beatsin8_t(speeds, 0, cols - 1, 0, i * freq) + beatsin8_t(speeds - 7, 0, cols - 1, 0, i * freq + 128); + int x1 = beatsin8_t(speeds, 0, cols - 1, 0, 128 + i * freq) + beatsin8_t(speeds - 7, 0, cols - 1, 0, 128 + 64 + i * freq); unsigned hue = (i * 128 / rows) + ms; // skip every 4th row every now and then (fade it more) if ((i + ms / 8) & 3) { @@ -5104,9 +5104,9 @@ uint16_t mode_2DFrizzles(void) { // By: Stepko https://editor.so SEGMENT.fadeToBlackBy(16); for (size_t i = 8; i > 0; i--) { - SEGMENT.addPixelColorXY(beatsin8(SEGMENT.speed/8 + i, 0, cols - 1), - beatsin8(SEGMENT.intensity/8 - i, 0, rows - 1), - ColorFromPalette(SEGPALETTE, beatsin8(12, 0, 255), 255, LINEARBLEND)); + SEGMENT.addPixelColorXY(beatsin8_t(SEGMENT.speed/8 + i, 0, cols - 1), + beatsin8_t(SEGMENT.intensity/8 - i, 0, rows - 1), + ColorFromPalette(SEGPALETTE, beatsin8_t(12, 0, 255), 255, LINEARBLEND)); } SEGMENT.blur(SEGMENT.custom1>>3); @@ -5238,7 +5238,7 @@ uint16_t mode_2DHiphotic() { // By: ldirko https://edit for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) { - SEGMENT.setPixelColorXY(x, y, SEGMENT.color_from_palette(sin8(cos8(x * SEGMENT.speed/16 + a / 3) + sin8(y * SEGMENT.intensity/16 + a / 4) + a), false, PALETTE_SOLID_WRAP, 0)); + SEGMENT.setPixelColorXY(x, y, SEGMENT.color_from_palette(sin8_t(cos8_t(x * SEGMENT.speed/16 + a / 3) + sin8_t(y * SEGMENT.intensity/16 + a / 4) + a), false, PALETTE_SOLID_WRAP, 0)); } } @@ -5378,10 +5378,10 @@ uint16_t mode_2DLissajous(void) { // By: Andrew Tuline //for (int i=0; i < 4*(cols+rows); i ++) { for (int i=0; i < 256; i ++) { - //float xlocn = float(sin8(now/4+i*(SEGMENT.speed>>5))) / 255.0f; - //float ylocn = float(cos8(now/4+i*2)) / 255.0f; - uint_fast8_t xlocn = sin8(phase/2 + (i*SEGMENT.speed)/32); - uint_fast8_t ylocn = cos8(phase/2 + i*2); + //float xlocn = float(sin8_t(now/4+i*(SEGMENT.speed>>5))) / 255.0f; + //float ylocn = float(cos8_t(now/4+i*2)) / 255.0f; + uint_fast8_t xlocn = sin8_t(phase/2 + (i*SEGMENT.speed)/32); + uint_fast8_t ylocn = cos8_t(phase/2 + i*2); xlocn = (cols < 2) ? 1 : (map(2*xlocn, 0,511, 0,2*(cols-1)) +1) /2; // softhack007: "(2* ..... +1) /2" for proper rounding ylocn = (rows < 2) ? 1 : (map(2*ylocn, 0,511, 0,2*(rows-1)) +1) /2; // "rows > 1" is needed to avoid div/0 in map() SEGMENT.setPixelColorXY((uint8_t)xlocn, (uint8_t)ylocn, SEGMENT.color_from_palette(strip.now/100+i, false, PALETTE_SOLID_WRAP, 0)); @@ -5481,8 +5481,8 @@ uint16_t mode_2Dmetaballs(void) { // Metaballs by Stefan Petrick. Cannot have int y3 = map(inoise8(strip.now * speed, 25355, 22685), 0, 255, 0, rows-1); // and one Lissajou function - int x1 = beatsin8(23 * speed, 0, cols-1); - int y1 = beatsin8(28 * speed, 0, rows-1); + int x1 = beatsin8_t(23 * speed, 0, cols-1); + int y1 = beatsin8_t(28 * speed, 0, rows-1); for (int y = 0; y < rows; y++) { for (int x = 0; x < cols; x++) { @@ -5647,7 +5647,7 @@ uint16_t mode_2DPulser(void) { // By: ldirko https://edi SEGMENT.fadeToBlackBy(8 - (SEGMENT.intensity>>5)); uint32_t a = strip.now / (18 - SEGMENT.speed / 16); int x = (a / 14) % cols; - int y = map((sin8(a * 5) + sin8(a * 4) + sin8(a * 2)), 0, 765, rows-1, 0); + int y = map((sin8_t(a * 5) + sin8_t(a * 4) + sin8_t(a * 2)), 0, 765, rows-1, 0); SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, map(y, 0, rows-1, 0, 255), 255, LINEARBLEND)); SEGMENT.blur(SEGMENT.intensity>>4); @@ -5673,10 +5673,10 @@ uint16_t mode_2DSindots(void) { // By: ldirko http SEGMENT.fadeToBlackBy(SEGMENT.custom1>>3); byte t1 = strip.now / (257 - SEGMENT.speed); // 20; - byte t2 = sin8(t1) / 4 * 2; + byte t2 = sin8_t(t1) / 4 * 2; for (int i = 0; i < 13; i++) { - int x = sin8(t1 + i * SEGMENT.intensity/8)*(cols-1)/255; // max index now 255x15/255=15! - int y = sin8(t2 + i * SEGMENT.intensity/8)*(rows-1)/255; // max index now 255x15/255=15! + int x = sin8_t(t1 + i * SEGMENT.intensity/8)*(cols-1)/255; // max index now 255x15/255=15! + int y = sin8_t(t2 + i * SEGMENT.intensity/8)*(rows-1)/255; // max index now 255x15/255=15! SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, i * 255 / 13, 255, LINEARBLEND)); } SEGMENT.blur(SEGMENT.custom2>>3); @@ -5703,12 +5703,12 @@ uint16_t mode_2Dsquaredswirl(void) { // By: Mark Kriegsman. https://g SEGMENT.blur(SEGMENT.custom3>>1); // Use two out-of-sync sine waves - int i = beatsin8(19, kBorderWidth, cols-kBorderWidth); - int j = beatsin8(22, kBorderWidth, cols-kBorderWidth); - int k = beatsin8(17, kBorderWidth, cols-kBorderWidth); - int m = beatsin8(18, kBorderWidth, rows-kBorderWidth); - int n = beatsin8(15, kBorderWidth, rows-kBorderWidth); - int p = beatsin8(20, kBorderWidth, rows-kBorderWidth); + int i = beatsin8_t(19, kBorderWidth, cols-kBorderWidth); + int j = beatsin8_t(22, kBorderWidth, cols-kBorderWidth); + int k = beatsin8_t(17, kBorderWidth, cols-kBorderWidth); + int m = beatsin8_t(18, kBorderWidth, rows-kBorderWidth); + int n = beatsin8_t(15, kBorderWidth, rows-kBorderWidth); + int p = beatsin8_t(20, kBorderWidth, rows-kBorderWidth); SEGMENT.addPixelColorXY(i, m, ColorFromPalette(SEGPALETTE, strip.now/29, 255, LINEARBLEND)); SEGMENT.addPixelColorXY(j, n, ColorFromPalette(SEGPALETTE, strip.now/41, 255, LINEARBLEND)); @@ -5784,19 +5784,19 @@ uint16_t mode_2Dtartan(void) { // By: Elliott Kember https://editor.so uint8_t hue, bri; size_t intensity; - int offsetX = beatsin16(3, -360, 360); - int offsetY = beatsin16(2, -360, 360); + int offsetX = beatsin16_t(3, -360, 360); + int offsetY = beatsin16_t(2, -360, 360); int sharpness = SEGMENT.custom3 / 8; // 0-3 for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) { - hue = x * beatsin16(10, 1, 10) + offsetY; - intensity = bri = sin8(x * SEGMENT.speed/2 + offsetX); + hue = x * beatsin16_t(10, 1, 10) + offsetY; + intensity = bri = sin8_t(x * SEGMENT.speed/2 + offsetX); for (int i=0; i>= 8*sharpness; SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, hue, intensity, LINEARBLEND)); hue = y * 3 + offsetX; - intensity = bri = sin8(y * SEGMENT.intensity/2 + offsetY); + intensity = bri = sin8_t(y * SEGMENT.intensity/2 + offsetY); for (int i=0; i>= 8*sharpness; SEGMENT.addPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, hue, intensity, LINEARBLEND)); @@ -5831,9 +5831,9 @@ uint16_t mode_2Dspaceships(void) { //// Space ships by stepko (c)05.02.21 [ht SEGMENT.move(SEGENV.aux0, 1); for (size_t i = 0; i < 8; i++) { - int x = beatsin8(12 + i, 2, cols - 3); - int y = beatsin8(15 + i, 2, rows - 3); - CRGB color = ColorFromPalette(SEGPALETTE, beatsin8(12 + i, 0, 255), 255); + int x = beatsin8_t(12 + i, 2, cols - 3); + int y = beatsin8_t(15 + i, 2, rows - 3); + CRGB color = ColorFromPalette(SEGPALETTE, beatsin8_t(12 + i, 0, 255), 255); SEGMENT.addPixelColorXY(x, y, color); if (cols > 24 || rows > 24) { SEGMENT.addPixelColorXY(x+1, y, color); @@ -6229,8 +6229,8 @@ uint16_t mode_2Ddriftrose(void) { SEGMENT.fadeToBlackBy(32+(SEGMENT.speed>>3)); for (size_t i = 1; i < 37; i++) { float angle = radians(i * 10); - uint32_t x = (CX + (sin_t(angle) * (beatsin8(i, 0, L*2)-L))) * 255.f; - uint32_t y = (CY + (cos_t(angle) * (beatsin8(i, 0, L*2)-L))) * 255.f; + uint32_t x = (CX + (sin_t(angle) * (beatsin8_t(i, 0, L*2)-L))) * 255.f; + uint32_t y = (CY + (cos_t(angle) * (beatsin8_t(i, 0, L*2)-L))) * 255.f; SEGMENT.wu_pixel(x, y, CHSV(i * 10, 255, 255)); } SEGMENT.blur(SEGMENT.intensity>>4); @@ -6426,8 +6426,8 @@ uint16_t mode_2DSwirl(void) { SEGMENT.blur(SEGMENT.custom1); - int i = beatsin8( 27*SEGMENT.speed/255, borderWidth, cols - borderWidth); - int j = beatsin8( 41*SEGMENT.speed/255, borderWidth, rows - borderWidth); + int i = beatsin8_t( 27*SEGMENT.speed/255, borderWidth, cols - borderWidth); + int j = beatsin8_t( 41*SEGMENT.speed/255, borderWidth, rows - borderWidth); int ni = (cols - 1) - i; int nj = (cols - 1) - j; @@ -6639,7 +6639,7 @@ uint16_t mode_juggles(void) { // Juggles. By Andrew Tuline. for (size_t i=0; ithisphase += beatsin8(6,-4,4); // You can change direction and speed individually. - plasmoip->thatphase += beatsin8(7,-4,4); // Two phase values to make a complex pattern. By Andrew Tuline. + plasmoip->thisphase += beatsin8_t(6,-4,4); // You can change direction and speed individually. + plasmoip->thatphase += beatsin8_t(7,-4,4); // Two phase values to make a complex pattern. By Andrew Tuline. for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows. // updated, similar to "plasma" effect - softhack007 uint8_t thisbright = cubicwave8(((i*(1 + (3*SEGMENT.speed/32)))+plasmoip->thisphase) & 0xFF)/2; - thisbright += cos8(((i*(97 +(5*SEGMENT.speed/32)))+plasmoip->thatphase) & 0xFF)/2; // Let's munge the brightness a bit and animate it all with the phases. + thisbright += cos8_t(((i*(97 +(5*SEGMENT.speed/32)))+plasmoip->thatphase) & 0xFF)/2; // Let's munge the brightness a bit and animate it all with the phases. uint8_t colorIndex=thisbright; if (volumeSmth * SEGMENT.intensity / 64 < thisbright) {thisbright = 0;} @@ -7280,7 +7280,7 @@ uint16_t mode_rocktaves(void) { // Rocktaves. Same note from eac frTemp -= 132.0f; // This should give us a base musical note of C3 frTemp = fabsf(frTemp * 2.1f); // Fudge factors to compress octave range starting at 0 and going to 255; - unsigned i = map(beatsin8(8+octCount*4, 0, 255, 0, octCount*8), 0, 255, 0, SEGLEN-1); + unsigned i = map(beatsin8_t(8+octCount*4, 0, 255, 0, octCount*8), 0, 255, 0, SEGLEN-1); i = constrain(i, 0U, SEGLEN-1U); SEGMENT.addPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette((uint8_t)frTemp, false, PALETTE_SOLID_WRAP, 0), volTemp)); @@ -7567,12 +7567,12 @@ uint16_t mode_2Ddistortionwaves() { unsigned a2 = a/2; unsigned a3 = a/3; - unsigned cx = beatsin8(10-speed,0,cols-1)*scale; - unsigned cy = beatsin8(12-speed,0,rows-1)*scale; - unsigned cx1 = beatsin8(13-speed,0,cols-1)*scale; - unsigned cy1 = beatsin8(15-speed,0,rows-1)*scale; - unsigned cx2 = beatsin8(17-speed,0,cols-1)*scale; - unsigned cy2 = beatsin8(14-speed,0,rows-1)*scale; + unsigned cx = beatsin8_t(10-speed,0,cols-1)*scale; + unsigned cy = beatsin8_t(12-speed,0,rows-1)*scale; + unsigned cx1 = beatsin8_t(13-speed,0,cols-1)*scale; + unsigned cy1 = beatsin8_t(15-speed,0,rows-1)*scale; + unsigned cx2 = beatsin8_t(17-speed,0,cols-1)*scale; + unsigned cy2 = beatsin8_t(14-speed,0,rows-1)*scale; unsigned xoffs = 0; for (int x = 0; x < cols; x++) { @@ -7582,17 +7582,17 @@ uint16_t mode_2Ddistortionwaves() { for (int y = 0; y < rows; y++) { yoffs += scale; - byte rdistort = cos8((cos8(((x<<3)+a )&255)+cos8(((y<<3)-a2)&255)+a3 )&255)>>1; - byte gdistort = cos8((cos8(((x<<3)-a2)&255)+cos8(((y<<3)+a3)&255)+a+32 )&255)>>1; - byte bdistort = cos8((cos8(((x<<3)+a3)&255)+cos8(((y<<3)-a) &255)+a2+64)&255)>>1; + byte rdistort = cos8_t((cos8_t(((x<<3)+a )&255)+cos8_t(((y<<3)-a2)&255)+a3 )&255)>>1; + byte gdistort = cos8_t((cos8_t(((x<<3)-a2)&255)+cos8_t(((y<<3)+a3)&255)+a+32 )&255)>>1; + byte bdistort = cos8_t((cos8_t(((x<<3)+a3)&255)+cos8_t(((y<<3)-a) &255)+a2+64)&255)>>1; byte valueR = rdistort+ w* (a- ( ((xoffs - cx) * (xoffs - cx) + (yoffs - cy) * (yoffs - cy))>>7 )); byte valueG = gdistort+ w* (a2-( ((xoffs - cx1) * (xoffs - cx1) + (yoffs - cy1) * (yoffs - cy1))>>7 )); byte valueB = bdistort+ w* (a3-( ((xoffs - cx2) * (xoffs - cx2) + (yoffs - cy2) * (yoffs - cy2))>>7 )); - valueR = gamma8(cos8(valueR)); - valueG = gamma8(cos8(valueG)); - valueB = gamma8(cos8(valueB)); + valueR = gamma8(cos8_t(valueR)); + valueG = gamma8(cos8_t(valueG)); + valueB = gamma8(cos8_t(valueB)); SEGMENT.setPixelColorXY(x, y, RGBW32(valueR, valueG, valueB, 0)); } @@ -7749,7 +7749,7 @@ uint16_t mode_2Doctopus() { const int C_Y = (rows / 2) + ((SEGMENT.custom2 - 128)*rows)/255; for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) { - rMap[XY(x, y)].angle = 40.7436f * atan2f((y - C_Y), (x - C_X)); // avoid 128*atan2()/PI + rMap[XY(x, y)].angle = 40.7436f * atan2_t((y - C_Y), (x - C_X)); // avoid 128*atan2()/PI rMap[XY(x, y)].radius = hypotf((x - C_X), (y - C_Y)) * mapp; //thanks Sutaburosu } } @@ -7760,8 +7760,8 @@ uint16_t mode_2Doctopus() { for (int y = 0; y < rows; y++) { byte angle = rMap[XY(x,y)].angle; byte radius = rMap[XY(x,y)].radius; - //CRGB c = CHSV(SEGENV.step / 2 - radius, 255, sin8(sin8((angle * 4 - radius) / 4 + SEGENV.step) + radius - SEGENV.step * 2 + angle * (SEGMENT.custom3/3+1))); - unsigned intensity = sin8(sin8((angle * 4 - radius) / 4 + SEGENV.step/2) + radius - SEGENV.step + angle * (SEGMENT.custom3/4+1)); + //CRGB c = CHSV(SEGENV.step / 2 - radius, 255, sin8_t(sin8_t((angle * 4 - radius) / 4 + SEGENV.step) + radius - SEGENV.step * 2 + angle * (SEGMENT.custom3/3+1))); + unsigned intensity = sin8_t(sin8_t((angle * 4 - radius) / 4 + SEGENV.step/2) + radius - SEGENV.step + angle * (SEGMENT.custom3/4+1)); intensity = map((intensity*intensity) & 0xFFFF, 0, 65535, 0, 255); // add a bit of non-linearity for cleaner display CRGB c = ColorFromPalette(SEGPALETTE, SEGENV.step / 2 - radius, intensity); SEGMENT.setPixelColorXY(x, y, c); @@ -7769,7 +7769,7 @@ uint16_t mode_2Doctopus() { } return FRAMETIME; } -static const char _data_FX_MODE_2DOCTOPUS[] PROGMEM = "Octopus@!,,Offset X,Offset Y,Legs;;!;2;"; +static const char _data_FX_MODE_2DOCTOPUS[] PROGMEM = "Octopus@!,,Offset X,Offset Y,Legs,fasttan;;!;2;"; //Waving Cell @@ -7786,7 +7786,7 @@ uint16_t mode_2Dwavingcell() { uint8_t aY = SEGMENT.custom2/16 + 1; uint8_t aZ = SEGMENT.custom3 + 1; for (int x = 0; x < cols; x++) for (int y = 0; y T atan_t(T x); - float cos_t(float phi); - float sin_t(float x); - float tan_t(float x); - float acos_t(float x); - float asin_t(float x); - float floor_t(float x); - float fmod_t(float num, float denom); -#else - #include - #define sin_t sinf - #define cos_t cosf - #define tan_t tanf - #define asin_t asinf - #define acos_t acosf - #define atan_t atanf - #define fmod_t fmodf - #define floor_t floorf -#endif +//float cos_t(float phi); // use float math +//float sin_t(float phi); +//float tan_t(float x); +int16_t sin16_t(uint16_t theta); +int16_t cos16_t(uint16_t theta); +uint8_t sin8_t(uint8_t theta); +uint8_t cos8_t(uint8_t theta); +float sin_approx(float theta); // uses integer math (converted to float), accuracy +/-0.0015 (compared to sinf()) +float cos_approx(float theta); +float tan_approx(float x); +float atan2_t(float y, float x); +float acos_t(float x); +float asin_t(float x); +template T atan_t(T x); +float floor_t(float x); +float fmod_t(float num, float denom); +#define sin_t sin_approx +#define cos_t cos_approx +#define tan_t tan_approx +/* +#include // standard math functions. use a lot of flash +#define sin_t sinf +#define cos_t cosf +#define tan_t tanf +#define asin_t asinf +#define acos_t acosf +#define atan_t atanf +#define fmod_t fmodf +#define floor_t floorf +*/ //wled_serial.cpp void handleSerial(); void updateBaudRate(uint32_t rate); diff --git a/wled00/util.cpp b/wled00/util.cpp index 0b78a4646..c43fdeabf 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -372,6 +372,39 @@ uint16_t crc16(const unsigned char* data_p, size_t length) { return crc; } +// fastled beatsin: 1:1 replacements to remove the use of fastled sin16() +// Generates a 16-bit sine wave at a given BPM that oscillates within a given range. see fastled for details. +uint16_t beatsin88_t(accum88 beats_per_minute_88, uint16_t lowest, uint16_t highest, uint32_t timebase, uint16_t phase_offset) +{ + uint16_t beat = beat88( beats_per_minute_88, timebase); + uint16_t beatsin (sin16_t( beat + phase_offset) + 32768); + uint16_t rangewidth = highest - lowest; + uint16_t scaledbeat = scale16( beatsin, rangewidth); + uint16_t result = lowest + scaledbeat; + return result; +} + +// Generates a 16-bit sine wave at a given BPM that oscillates within a given range. see fastled for details. +uint16_t beatsin16_t(accum88 beats_per_minute, uint16_t lowest, uint16_t highest, uint32_t timebase, uint16_t phase_offset) +{ + uint16_t beat = beat16( beats_per_minute, timebase); + uint16_t beatsin = (sin16_t( beat + phase_offset) + 32768); + uint16_t rangewidth = highest - lowest; + uint16_t scaledbeat = scale16( beatsin, rangewidth); + uint16_t result = lowest + scaledbeat; + return result; +} + +// Generates an 8-bit sine wave at a given BPM that oscillates within a given range. see fastled for details. +uint8_t beatsin8_t(accum88 beats_per_minute, uint8_t lowest, uint8_t highest, uint32_t timebase, uint8_t phase_offset) +{ + uint8_t beat = beat8( beats_per_minute, timebase); + uint8_t beatsin = sin8_t( beat + phase_offset); + uint8_t rangewidth = highest - lowest; + uint8_t scaledbeat = scale8( beatsin, rangewidth); + uint8_t result = lowest + scaledbeat; + return result; +} /////////////////////////////////////////////////////////////////////////////// // Begin simulateSound (to enable audio enhanced effects to display something) @@ -431,8 +464,8 @@ um_data_t* simulateSound(uint8_t simulationId) default: case UMS_BeatSin: for (int i = 0; i<16; i++) - fftResult[i] = beatsin8(120 / (i+1), 0, 255); - // fftResult[i] = (beatsin8(120, 0, 255) + (256/16 * i)) % 256; + fftResult[i] = beatsin8_t(120 / (i+1), 0, 255); + // fftResult[i] = (beatsin8_t(120, 0, 255) + (256/16 * i)) % 256; volumeSmth = fftResult[8]; break; case UMS_WeWillRockYou: @@ -469,12 +502,12 @@ um_data_t* simulateSound(uint8_t simulationId) break; case UMS_10_13: for (int i = 0; i<16; i++) - fftResult[i] = inoise8(beatsin8(90 / (i+1), 0, 200)*15 + (ms>>10), ms>>3); + fftResult[i] = inoise8(beatsin8_t(90 / (i+1), 0, 200)*15 + (ms>>10), ms>>3); volumeSmth = fftResult[8]; break; case UMS_14_3: for (int i = 0; i<16; i++) - fftResult[i] = inoise8(beatsin8(120 / (i+1), 10, 30)*10 + (ms>>14), ms>>3); + fftResult[i] = inoise8(beatsin8_t(120 / (i+1), 10, 30)*10 + (ms>>14), ms>>3); volumeSmth = fftResult[8]; break; } diff --git a/wled00/wled_math.cpp b/wled00/wled_math.cpp index a4c9fc123..401446a23 100644 --- a/wled00/wled_math.cpp +++ b/wled00/wled_math.cpp @@ -12,6 +12,12 @@ #define modd(x, y) ((x) - (int)((x) / (y)) * (y)) +// Note: cos_t, sin_t and tan_t are very accurate but may be slow +// the math.h functions use several kB of flash and are to be avoided if possible +// sin16_t / cos16_t are faster and much more accurate than the fastled variants +// sin_approx and cos_approx are float wrappers for sin16_t/cos16_t and have an accuracy of +/-0.0015 compared to sinf() +// sin8_t / cos8_t are fastled replacements and use sin16_t / cos16_t. Slightly slower than fastled version but very accurate + float cos_t(float phi) { float x = modd(phi, TWO_PI); @@ -31,8 +37,8 @@ float cos_t(float phi) return res; } -float sin_t(float x) { - float res = cos_t(HALF_PI - x); +float sin_t(float phi) { + float res = cos_t(HALF_PI - phi); #ifdef WLED_DEBUG_MATH Serial.printf("sin: %f,%f,%f,(%f)\n",x,res,sin(x),res-sin(x)); #endif @@ -49,6 +55,85 @@ float tan_t(float x) { return res; } +// 16-bit, integer based Bhaskara I's sine approximation: 16*x*(pi - x) / (5*pi^2 - 4*x*(pi - x)) +// input is 16bit unsigned (0-65535), output is 16bit signed (-32767 to +32767) +// optimized integer implementation by @dedehai +int16_t sin16_t(uint16_t theta) { + int scale = 1; + if (theta > 0x7FFF) { + theta = 0xFFFF - theta; + scale = -1; // second half of the sine function is negative (pi - 2*pi) + } + uint32_t precal = theta * (0x7FFF - theta); + uint64_t numerator = (uint64_t)precal * (4 * 0x7FFF); // 64bit required + int32_t denominator = 1342095361 - precal; // 1342095361 is 5 * 0x7FFF^2 / 4 + int16_t result = numerator / denominator; + return result * scale; +} + +int16_t cos16_t(uint16_t theta) { + return sin16_t(theta + 16384); //cos(x) = sin(x+pi/2) +} + +uint8_t sin8_t(uint8_t theta) { + int32_t sin16 = sin16_t((uint16_t)theta * 257); // 255 * 257 = 0xFFFF + sin16 += 0x7FFF; //shift result to range 0-0xFFFF + return sin16 >> 8; +} + +uint8_t cos8_t(uint8_t theta) { + return sin8_t(theta + 64); //cos(x) = sin(x+pi/2) +} + +float sin_approx(float theta) +{ + theta = modd(theta, TWO_PI); // modulo: bring to -2pi to 2pi range + if(theta < 0) theta += M_TWOPI; // 0-2pi range + uint16_t scaled_theta = (uint16_t)(theta * (0xFFFF / M_TWOPI)); + int32_t result = sin16_t(scaled_theta); + float sin = float(result) / 0x7FFF; + return sin; +} + +float cos_approx(float theta) +{ + return sin_approx(theta + M_PI_2); +} + +float tan_approx(float x) { + float c = cos_approx(x); + if (c==0.0f) return 0; + float res = sin_approx(x) / c; + return res; +} + +#define ATAN2_CONST_A 0.1963f +#define ATAN2_CONST_B 0.9817f + +// fast atan2() approximation source: public domain +float atan2_t(float y, float x) { + if (x == 0.0f) return (y > 0.0f) ? M_PI_2 : (y < 0.0f) ? -M_PI_2 : 0.0f; + + float abs_y = (y < 0.0f) ? -y : y + 1e-10f; // make sure y is not zero to prevent division by 0 + float z = abs_y / x; + float atan_approx; + + if (z < 1.0f) { + atan_approx = z / (1.0f + ATAN2_CONST_A * z * z); + if (x < 0.0f) { + return (y >= 0.0f) ? atan_approx + PI : atan_approx - PI; + } + } + else { + z = x / abs_y; + atan_approx = M_PI_2 - z / (1.0f + ATAN2_CONST_A * z * z); + if (y < 0.0f) { + return -atan_approx; + } + } + return atan_approx; +} + //https://stackoverflow.com/questions/3380628 // Absolute error <= 6.7e-5 float acos_t(float x) { From 1b0ce9a123617abbe6580cca0f0548f1f9760fb5 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sat, 5 Oct 2024 15:00:58 +0200 Subject: [PATCH 063/234] Fix for #4179 --- wled00/FX.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index f3e82275c..e7429d19f 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -4031,7 +4031,7 @@ uint16_t mode_pacifica() // Increment the four "color index start" counters, one for each wave layer. // Each is incremented at a different speed, and the speeds vary over time. - unsigned sCIStart1 = SEGENV.aux0, sCIStart2 = SEGENV.aux1, sCIStart3 = SEGENV.step, sCIStart4 = SEGENV.step >> 16; + unsigned sCIStart1 = SEGENV.aux0, sCIStart2 = SEGENV.aux1, sCIStart3 = SEGENV.step & 0xFFFF, sCIStart4 = (SEGENV.step >> 16); uint32_t deltams = (FRAMETIME >> 2) + ((FRAMETIME * SEGMENT.speed) >> 7); uint64_t deltat = (strip.now >> 2) + ((strip.now * SEGMENT.speed) >> 7); strip.now = deltat; @@ -4046,7 +4046,7 @@ uint16_t mode_pacifica() sCIStart3 -= (deltams1 * beatsin88(501,5,7)); sCIStart4 -= (deltams2 * beatsin88(257,4,6)); SEGENV.aux0 = sCIStart1; SEGENV.aux1 = sCIStart2; - SEGENV.step = sCIStart4; SEGENV.step = (SEGENV.step << 16) + sCIStart3; + SEGENV.step = (sCIStart4 << 16) | (sCIStart3 & 0xFFFF); // Clear out the LED array to a dim background blue-green //SEGMENT.fill(132618); @@ -4077,7 +4077,7 @@ uint16_t mode_pacifica() c.green = scale8(c.green, 200); c |= CRGB( 2, 5, 7); - SEGMENT.setPixelColor(i, c.red, c.green, c.blue); + SEGMENT.setPixelColor(i, c); } strip.now = nowOld; From eb5ad232a0e8dd5623051bc8d03c399fba318291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sat, 5 Oct 2024 23:31:31 +0200 Subject: [PATCH 064/234] Minor tweaks and whitespace --- wled00/FX_2Dfcn.cpp | 35 +++++++++++++---------------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 6b3e6ef11..0e31083df 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -195,6 +195,7 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) const int vH = vHeight(); // segment height in logical pixels (is always >= 1) + // negative values of x & y cast into unsigend will become very large values and will therefore be greater than vW/vH if (unsigned(x) >= unsigned(vW) || unsigned(y) >= unsigned(vH)) return; // if pixel would fall out of virtual segment just exit // if color is unscaled @@ -205,8 +206,7 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed unsigned groupLen = groupLength(); - if(groupLen > 1) - { + if (groupLen > 1) { int W = width(); int H = height(); x *= groupLen; // expand to physical pixels @@ -222,8 +222,7 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) } yY++; } - } - else { + } else { _setPixelColorXY_raw(x, y, col); } } @@ -293,7 +292,7 @@ void Segment::blur2D(uint8_t blur_x, uint8_t blur_y, bool smear) { const unsigned rows = vHeight(); uint32_t lastnew; uint32_t last; - if(blur_x) { + if (blur_x) { const uint8_t keepx = smear ? 255 : 255 - blur_x; const uint8_t seepx = blur_x >> (1 + smear); for (unsigned row = 0; row < rows; row++) { // blur rows (x direction) @@ -316,7 +315,7 @@ void Segment::blur2D(uint8_t blur_x, uint8_t blur_y, bool smear) { setPixelColorXY(cols-1, row, curnew); // set last pixel } } - if(blur_y) { + if (blur_y) { const uint8_t keepy = smear ? 255 : 255 - blur_y; const uint8_t seepy = blur_y >> (1 + smear); for (unsigned col = 0; col < cols; col++) { @@ -425,20 +424,16 @@ void Segment::moveX(int delta, bool wrap) { int newDelta; int stop = vW; int start = 0; - if(wrap) newDelta = (delta + vW) % vW; // +cols in case delta < 0 + if (wrap) newDelta = (delta + vW) % vW; // +cols in case delta < 0 else { - if(delta < 0) start = -delta; + if (delta < 0) start = absDelta; stop = vW - absDelta; newDelta = delta > 0 ? delta : 0; } for (int y = 0; y < vH; y++) { for (int x = 0; x < stop; x++) { - int srcX; - if (wrap) { - srcX = (x + newDelta) % vW; // Wrap using modulo when `wrap` is true - } else { - srcX = x + newDelta; - } + int srcX = x + newDelta; + if (wrap) srcX %= vW; // Wrap using modulo when `wrap` is true newPxCol[x] = getPixelColorXY(srcX, y); } for (int x = 0; x < stop; x++) setPixelColorXY(x + start, y, newPxCol[x]); @@ -455,20 +450,16 @@ void Segment::moveY(int delta, bool wrap) { int newDelta; int stop = vH; int start = 0; - if(wrap) newDelta = (delta + vH) % vH; // +rows in case delta < 0 + if (wrap) newDelta = (delta + vH) % vH; // +rows in case delta < 0 else { - if(delta < 0) start = -delta; + if (delta < 0) start = absDelta; stop = vH - absDelta; newDelta = delta > 0 ? delta : 0; } for (int x = 0; x < vW; x++) { for (int y = 0; y < stop; y++) { - int srcY; - if (wrap) { - srcY = (y + newDelta) % vH; // Wrap using modulo when `wrap` is true - } else { - srcY = y + newDelta; - } + int srcY = y + newDelta; + if (wrap) srcY %= vH; // Wrap using modulo when `wrap` is true newPxCol[y] = getPixelColorXY(x, srcY); } for (int y = 0; y < stop; y++) setPixelColorXY(x, y + start, newPxCol[y]); From 407477dc6816b98ef2b8091dcb59628013ef2ba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sun, 6 Oct 2024 15:42:58 +0200 Subject: [PATCH 065/234] Fix for #4168 - set min value to 0 for disabled ABL --- wled00/data/settings_leds.htm | 58 ++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index dd0e8ee8b..6be5becd1 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -119,7 +119,12 @@ var en = d.Sf.ABL.checked; gId('abl').style.display = (en) ? 'inline':'none'; gId('psu2').style.display = (en) ? 'inline':'none'; - if (!en) d.Sf.PPL.checked = false; + if (!en) { + // limiter disabled + d.Sf.PPL.checked = false; +// d.Sf.querySelectorAll("#mLC select[name^=LAsel]").forEach((e)=>{e.selectedIndex = 0;}); // select default LED mA +// d.Sf.querySelectorAll("#mLC input[name^=LA]").forEach((e)=>{e.min = 0; e.value = 0;}); // set min & value to 0 + } UI(); } // enable per port limiter and calculate current @@ -132,46 +137,51 @@ d.Sf.MA.min = abl && !ppl ? 250 : 0; gId("psuMA").style.display = ppl ? 'none' : 'inline'; gId("ppldis").style.display = ppl ? 'inline' : 'none'; - // set PPL minimum value and clear actual PPL limit if ABL disabled + // set PPL minimum value and clear actual PPL limit if ABL is disabled d.Sf.querySelectorAll("#mLC input[name^=MA]").forEach((i,x)=>{ var n = String.fromCharCode((x<10?48:55)+x); gId("PSU"+n).style.display = ppl ? "inline" : "none"; const t = parseInt(d.Sf["LT"+n].value); // LED type SELECT const c = parseInt(d.Sf["LC"+n].value); //get LED count - i.min = ppl && !(isVir(t) || isAna(t)) ? 250 : 0; - if (!abl || isVir(t) || isAna(t)) i.value = 0; + i.min = ppl && isDig(t) ? 250 : 0; + if (!abl || !isDig(t)) i.value = 0; else if (ppl) sumMA += parseInt(i.value,10); else if (sDI) i.value = Math.round(parseInt(d.Sf.MA.value,10)*c/sDI); }); if (ppl) d.Sf.MA.value = sumMA; // populate UI ABL value if PPL used } + // enable and update LED Amps function enLA(s,n) { + const abl = d.Sf.ABL.checked; const t = parseInt(d.Sf["LT"+n].value); // LED type SELECT - gId('LAdis'+n).style.display = s.selectedIndex==5 ? "inline" : "none"; - if (s.value!=="0") d.Sf["LA"+n].value = s.value; - d.Sf["LA"+n].min = (isVir(t) || isAna(t)) ? 0 : 1; + gId('LAdis'+n).style.display = s.selectedIndex==5 ? "inline" : "none"; // show/hide custom mA field + if (s.value!=="0") d.Sf["LA"+n].value = s.value; // set value from select object + d.Sf["LA"+n].min = (!isDig(t) || !abl) ? 0 : 1; // set minimum value for validation } function setABL() { - d.Sf.ABL.checked = parseInt(d.Sf.MA.value) > 0; + let en = parseInt(d.Sf.MA.value) > 0; // check if ABL is enabled (max mA entered per output) d.Sf.querySelectorAll("#mLC input[name^=MA]").forEach((i,n)=>{ - if (parseInt(i.value) > 0) d.Sf.ABL.checked = true; + if (parseInt(i.value) > 0) en = true; }); + d.Sf.ABL.checked = en; // select appropriate LED current d.Sf.querySelectorAll("#mLC select[name^=LAsel]").forEach((sel,x)=>{ sel.value = 0; // set custom var n = String.fromCharCode((x<10?48:55)+x); - switch (parseInt(d.Sf["LA"+n].value)) { - case 0: break; // disable ABL - case 15: sel.value = 15; break; - case 30: sel.value = 30; break; - case 35: sel.value = 35; break; - case 55: sel.value = 55; break; - case 255: sel.value = 255; break; - } - enLA(sel,n); + if (en) + switch (parseInt(d.Sf["LA"+n].value)) { + case 0: break; // disable ABL + case 15: sel.value = 15; break; + case 30: sel.value = 30; break; + case 35: sel.value = 35; break; + case 55: sel.value = 55; break; + case 255: sel.value = 255; break; + } + else sel.value = 0; + enLA(sel,n); // configure individual limiter }); enABL(); gId('m1').innerHTML = maxM; @@ -202,7 +212,7 @@ let gRGBW = false, memu = 0; let busMA = 0; let sLC = 0, sPC = 0, sDI = 0, maxLC = 0; - const ablEN = d.Sf.ABL.checked; + const abl = d.Sf.ABL.checked; maxB = oMaxB; // TODO make sure we start with all possible buses let setPinConfig = (n,t) => { let p0d = "GPIO:"; @@ -249,12 +259,12 @@ var t = parseInt(s.value); memu += getMem(t, n); // calc memory setPinConfig(n,t); - gId("abl"+n).style.display = (!ablEN || isVir(t) || isAna(t)) ? "none" : "inline"; - if (change) { + gId("abl"+n).style.display = (!abl || !isDig(t)) ? "none" : "inline"; // show/hide individual ABL settings + if (change) { // did we change LED type? gId("rf"+n).checked = (gId("rf"+n).checked || t == 31); // LEDs require data in off state (mandatory for TM1814) if (isAna(t)) d.Sf["LC"+n].value = 1; // for sanity change analog count just to 1 LED - d.Sf["LA"+n].min = (isVir(t) || isAna(t)) ? 0 : 1; - d.Sf["MA"+n].min = (isVir(t) || isAna(t)) ? 0 : 250; + d.Sf["LA"+n].min = (!isDig(t) || !abl) ? 0 : 1; // set minimum value for LED mA + d.Sf["MA"+n].min = (!isDig(t)) ? 0 : 250; // set minimum value for PSU mA } gId("rf"+n).onclick = mustR(t) ? (()=>{return false}) : (()=>{}); // prevent change change of "Refresh" checkmark when mandatory gRGBW |= hasW(t); // RGBW checkbox @@ -294,7 +304,7 @@ if (s+c > sLC) sLC = s+c; //update total count if (c > maxLC) maxLC = c; //max per output if (!isVir(t)) sPC += c; //virtual out busses do not count towards physical LEDs - if (!(isVir(t) || isAna(t))) { + if (isDig(t)) { sDI += c; // summarize digital LED count let maPL = parseInt(d.Sf["LA"+n].value); if (maPL == 255) maPL = 12; From f301296f1e1c9ba9ceeb49aead1f89fc3cd94ba6 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 6 Oct 2024 21:27:58 +0200 Subject: [PATCH 066/234] added rounding to sin8_t thx to @softhack007 --- wled00/wled_math.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/wled_math.cpp b/wled00/wled_math.cpp index 401446a23..080cc9425 100644 --- a/wled00/wled_math.cpp +++ b/wled00/wled_math.cpp @@ -77,8 +77,8 @@ int16_t cos16_t(uint16_t theta) { uint8_t sin8_t(uint8_t theta) { int32_t sin16 = sin16_t((uint16_t)theta * 257); // 255 * 257 = 0xFFFF - sin16 += 0x7FFF; //shift result to range 0-0xFFFF - return sin16 >> 8; + sin16 += 0x7FFF + 128; //shift result to range 0-0xFFFF, +128 for rounding + return min(sin16, int32_t(0xFFFF)) >> 8; // min performs saturation, and prevents overflow } uint8_t cos8_t(uint8_t theta) { From 5975b9125f9e5b993a1e13b97bf2972bd0137079 Mon Sep 17 00:00:00 2001 From: PaoloTK Date: Sun, 6 Oct 2024 22:56:30 +0200 Subject: [PATCH 067/234] add autosegment outputs compile flag --- wled00/FX.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wled00/FX.h b/wled00/FX.h index 3c28274d6..1d3ce1f93 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -720,7 +720,11 @@ class WS2812FX { // 96 bytes #ifndef WLED_DISABLE_2D panels(1), #endif +#ifdef WLED_AUTOSEGMENT_OUTPUTS + autoSegments(true), +#else autoSegments(false), +#endif correctWB(false), cctFromRgb(false), // semi-private (just obscured) used in effect functions through macros From 488974dd3e969fd8a723aa709b5944fc2308c0ea Mon Sep 17 00:00:00 2001 From: PaoloTK Date: Mon, 7 Oct 2024 10:39:45 +0200 Subject: [PATCH 068/234] change flag --- wled00/FX.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.h b/wled00/FX.h index 1d3ce1f93..f16f07924 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -720,7 +720,7 @@ class WS2812FX { // 96 bytes #ifndef WLED_DISABLE_2D panels(1), #endif -#ifdef WLED_AUTOSEGMENT_OUTPUTS +#ifdef WLED_AUTOSEGMENTS autoSegments(true), #else autoSegments(false), From be64930ebb97b554e3e03c6c178269cec791053a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Mon, 7 Oct 2024 16:50:51 +0200 Subject: [PATCH 069/234] Indentation and shadowed variable. --- wled00/FX_2Dfcn.cpp | 6 +++--- wled00/colors.cpp | 48 ++++++++++++++++++++++----------------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 0e31083df..5a7dc76d3 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -652,9 +652,9 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, case 60: bits = pgm_read_byte_near(&console_font_5x12[(chr * h) + i]); break; // 5x12 font default: return; } - uint32_t col = ColorFromPaletteWLED(grad, (i+1)*255/h, 255, NOBLEND); + uint32_t c = ColorFromPaletteWLED(grad, (i+1)*255/h, 255, NOBLEND); // pre-scale color for all pixels - col = color_fade(col, _segBri); + c = color_fade(c, _segBri); _colorScaled = true; for (int j = 0; j= (int)vWidth() || y0 < 0 || y0 >= (int)vHeight()) continue; // drawing off-screen if (((bits>>(j+(8-w))) & 0x01)) { // bit set - setPixelColorXY(x0, y0, col); + setPixelColorXY(x0, y0, c); } } _colorScaled = false; diff --git a/wled00/colors.cpp b/wled00/colors.cpp index c059ea9db..27c9c8289 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -98,30 +98,30 @@ uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) // 1:1 replacement of fastled function optimized for ESP, slightly faster, more accurate and uses less flash (~ -200bytes) uint32_t ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brightness, TBlendType blendType) { - if (blendType == LINEARBLEND_NOWRAP) { - index = (index*240) >> 8; // Blend range is affected by lo4 blend of values, remap to avoid wrapping - } - unsigned hi4 = byte(index) >> 4; - const CRGB* entry = (CRGB*)( (uint8_t*)(&(pal[0])) + (hi4 * sizeof(CRGB))); - unsigned red1 = entry->r; - unsigned green1 = entry->g; - unsigned blue1 = entry->b; - if (blendType != NOBLEND) { - if (hi4 == 15) entry = &(pal[0]); - else ++entry; - unsigned f2 = ((index & 0x0F) << 4) + 1; // +1 so we scale by 256 as a max value, then result can just be shifted by 8 - unsigned f1 = (257 - f2); // f2 is 1 minimum, so this is 256 max - red1 = (red1 * f1 + (unsigned)entry->r * f2) >> 8; - green1 = (green1 * f1 + (unsigned)entry->g * f2) >> 8; - blue1 = (blue1 * f1 + (unsigned)entry->b * f2) >> 8; - } - if (brightness < 255) { // note: zero checking could be done to return black but that is hardly ever used so it is omitted - uint32_t scale = brightness + 1; // adjust for rounding (bitshift) - red1 = (red1 * scale) >> 8; - green1 = (green1 * scale) >> 8; - blue1 = (blue1 * scale) >> 8; - } - return RGBW32(red1,green1,blue1,0); + if (blendType == LINEARBLEND_NOWRAP) { + index = (index*240) >> 8; // Blend range is affected by lo4 blend of values, remap to avoid wrapping + } + unsigned hi4 = byte(index) >> 4; + const CRGB* entry = (CRGB*)((uint8_t*)(&(pal[0])) + (hi4 * sizeof(CRGB))); + unsigned red1 = entry->r; + unsigned green1 = entry->g; + unsigned blue1 = entry->b; + if (blendType != NOBLEND) { + if (hi4 == 15) entry = &(pal[0]); + else ++entry; + unsigned f2 = ((index & 0x0F) << 4) + 1; // +1 so we scale by 256 as a max value, then result can just be shifted by 8 + unsigned f1 = (257 - f2); // f2 is 1 minimum, so this is 256 max + red1 = (red1 * f1 + (unsigned)entry->r * f2) >> 8; + green1 = (green1 * f1 + (unsigned)entry->g * f2) >> 8; + blue1 = (blue1 * f1 + (unsigned)entry->b * f2) >> 8; + } + if (brightness < 255) { // note: zero checking could be done to return black but that is hardly ever used so it is omitted + uint32_t scale = brightness + 1; // adjust for rounding (bitshift) + red1 = (red1 * scale) >> 8; + green1 = (green1 * scale) >> 8; + blue1 = (blue1 * scale) >> 8; + } + return RGBW32(red1,green1,blue1,0); } void setRandomColor(byte* rgb) From 5e9a46d54d86c2f08b65b2152cab194794030553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Mon, 7 Oct 2024 17:15:35 +0200 Subject: [PATCH 070/234] Fix for #4154 --- wled00/json.cpp | 1 - wled00/presets.cpp | 4 ++-- wled00/wled.h | 2 -- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/wled00/json.cpp b/wled00/json.cpp index 0df7294c8..c877d1f3b 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -465,7 +465,6 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) ps = presetCycCurr; if (root["win"].isNull() && getVal(root["ps"], &ps, 0, 0) && ps > 0 && ps < 251 && ps != currentPreset) { // b) preset ID only or preset that does not change state (use embedded cycling limits if they exist in getVal()) - presetCycCurr = ps; applyPreset(ps, callMode); // async load from file system (only preset ID was specified) return stateResponse; } diff --git a/wled00/presets.cpp b/wled00/presets.cpp index 20edfd91e..2749d4677 100644 --- a/wled00/presets.cpp +++ b/wled00/presets.cpp @@ -118,7 +118,7 @@ void initPresetsFile() bool applyPresetFromPlaylist(byte index) { DEBUG_PRINTF_P(PSTR("Request to apply preset: %d\n"), index); - presetToApply = index; + presetToApply = presetCycCurr = index; callModeToApply = CALL_MODE_DIRECT_CHANGE; return true; } @@ -127,7 +127,7 @@ bool applyPreset(byte index, byte callMode) { unloadPlaylist(); // applying a preset unloads the playlist (#3827) DEBUG_PRINTF_P(PSTR("Request to apply preset: %u\n"), index); - presetToApply = index; + presetToApply = presetCycCurr = index; callModeToApply = callMode; return true; } diff --git a/wled00/wled.h b/wled00/wled.h index 052f29b29..173bd6554 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -316,8 +316,6 @@ WLED_GLOBAL bool rlyOpenDrain _INIT(RLYODRAIN); constexpr uint8_t hardwareTX = 1; #endif -//WLED_GLOBAL byte presetToApply _INIT(0); - WLED_GLOBAL char ntpServerName[33] _INIT("0.wled.pool.ntp.org"); // NTP server to use // WiFi CONFIG (all these can be changed via web UI, no need to set them here) From 7deea9eb75e651b19c04217c5fabde3f544c542b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Mon, 7 Oct 2024 17:52:36 +0200 Subject: [PATCH 071/234] Minor button & rover CSS tweak. --- wled00/data/index.css | 12 ++++++++---- wled00/data/index.htm | 14 +++++++------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/wled00/data/index.css b/wled00/data/index.css index c4e85f73f..6f465e407 100644 --- a/wled00/data/index.css +++ b/wled00/data/index.css @@ -144,7 +144,7 @@ button { } .huge { - font-size: 42px; + font-size: 60px !important; } .segt, .plentry TABLE { @@ -584,6 +584,10 @@ button { z-index: 3; } +#rover .ibtn { + margin: 5px; +} + #ndlt { margin: 12px 0; } @@ -624,7 +628,7 @@ button { padding-bottom: 8px; } -.infobtn { +#info .ibtn { margin: 5px; } @@ -848,7 +852,7 @@ input[type=range]::-moz-range-thumb { width: 135px; } -#nodes .infobtn { +#nodes .ibtn { margin: 0; } @@ -1524,7 +1528,7 @@ dialog { #info table .btn, #nodes table .btn { width: 200px; } - #info .infobtn, #nodes .infobtn { + #info .ibtn, #nodes .ibtn { width: 145px; } #info div, #nodes div, #nodes a.btn { diff --git a/wled00/data/index.htm b/wled00/data/index.htm index 86b3b1879..e74ea0076 100644 --- a/wled00/data/index.htm +++ b/wled00/data/index.htm @@ -304,10 +304,10 @@
Loading...

- - - - + + + +

Made with ❤︎ by Aircoookie and the WLED community @@ -318,7 +318,7 @@
WLED instances
Loading...
- +
@@ -331,8 +331,8 @@
?


To use built-in effects, use an override button below.
You can return to realtime mode by pressing the star in the top left corner.
- -
+ +
For best performance, it is recommended to turn off the streaming source when not in use. From 210191b251f0ebdca0d5d12f21278b03fe404755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Mon, 7 Oct 2024 20:19:07 +0200 Subject: [PATCH 072/234] Fix for realtime drawing on main segment --- wled00/e131.cpp | 4 ++++ wled00/udp.cpp | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/wled00/e131.cpp b/wled00/e131.cpp index 7c074759e..bc26a0639 100644 --- a/wled00/e131.cpp +++ b/wled00/e131.cpp @@ -39,6 +39,7 @@ void handleDDPPacket(e131_packet_t* p) { realtimeLock(realtimeTimeoutMs, REALTIME_MODE_DDP); if (!realtimeOverride || (realtimeMode && useMainSegmentOnly)) { + if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); for (unsigned i = start; i < stop; i++, c += ddpChannelsPerLed) { setRealtimePixel(i, data[c], data[c+1], data[c+2], ddpChannelsPerLed >3 ? data[c+3] : 0); } @@ -147,6 +148,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){ if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return; wChannel = (availDMXLen > 3) ? e131_data[dataOffset+3] : 0; + if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); for (unsigned i = 0; i < totalLen; i++) setRealtimePixel(i, e131_data[dataOffset+0], e131_data[dataOffset+1], e131_data[dataOffset+2], wChannel); break; @@ -164,6 +166,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){ strip.setBrightness(bri, true); } + if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); for (unsigned i = 0; i < totalLen; i++) setRealtimePixel(i, e131_data[dataOffset+1], e131_data[dataOffset+2], e131_data[dataOffset+3], wChannel); break; @@ -308,6 +311,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){ } } + if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); if (!is4Chan) { for (unsigned i = previousLeds; i < ledsTotal; i++) { setRealtimePixel(i, e131_data[dmxOffset], e131_data[dmxOffset+1], e131_data[dmxOffset+2], 0); diff --git a/wled00/udp.cpp b/wled00/udp.cpp index 0ff39f110..a6a0f6aa2 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -687,10 +687,11 @@ void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w) b = gamma8(b); w = gamma8(w); } + uint32_t col = RGBW32(r,g,b,w); if (useMainSegmentOnly) { - strip.getMainSegment().setPixelColor(pix, r, g, b, w); // this expects that strip.getMainSegment().beginDraw() has been called in handleNotification() + strip.getMainSegment().setPixelColor(pix, col); // this expects that strip.getMainSegment().beginDraw() has been called in handleNotification() } else { - strip.setPixelColor(pix, r, g, b, w); + strip.setPixelColor(pix, col); } } } From a60231ba59f285617086e501c27546beb5e998eb Mon Sep 17 00:00:00 2001 From: maxi4329 <84231420+maxi4329@users.noreply.github.com> Date: Wed, 9 Oct 2024 22:10:59 +0200 Subject: [PATCH 073/234] Fixed the positioning of the "Download the latest binary" button (#4184) * fixed the positioning of the download button * fixed space after "Download the latest binary:" disapering after building * fixed typo --------- Co-authored-by: maxi4329 --- wled00/data/update.htm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wled00/data/update.htm b/wled00/data/update.htm index f157f98d8..b68645a52 100644 --- a/wled00/data/update.htm +++ b/wled00/data/update.htm @@ -17,7 +17,8 @@

WLED Software Update

Installed version: ##VERSION##
- Download the latest binary: + Download the latest binary: 


From 37f32ab197dac8399e2f2b302992344071094e7c Mon Sep 17 00:00:00 2001 From: Luis <84397555+LuisFadini@users.noreply.github.com> Date: Sat, 12 Oct 2024 10:56:40 -0300 Subject: [PATCH 074/234] Added BRT timezone --- wled00/data/settings_time.htm | 1 + wled00/ntp.cpp | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/wled00/data/settings_time.htm b/wled00/data/settings_time.htm index 52f79eb7d..df054f417 100644 --- a/wled00/data/settings_time.htm +++ b/wled00/data/settings_time.htm @@ -156,6 +156,7 @@ +
UTC offset: seconds (max. 18 hours)
Current local time is unknown.
diff --git a/wled00/ntp.cpp b/wled00/ntp.cpp index 7b7dac96e..8d44e634e 100644 --- a/wled00/ntp.cpp +++ b/wled00/ntp.cpp @@ -36,8 +36,9 @@ Timezone* tz; #define TZ_ANCHORAGE 20 #define TZ_MX_CENTRAL 21 #define TZ_PAKISTAN 22 +#define TZ_BRASILIA 23 -#define TZ_COUNT 23 +#define TZ_COUNT 24 #define TZ_INIT 255 byte tzCurrent = TZ_INIT; //uninitialized @@ -135,6 +136,10 @@ static const std::pair TZ_TABLE[] PROGMEM = { /* TZ_PAKISTAN */ { {Last, Sun, Mar, 1, 300}, //Pakistan Standard Time = UTC + 5 hours {Last, Sun, Mar, 1, 300} + }, + /* TZ_BRASILIA */ { + {Last, Sun, Mar, 1, -180}, //Brasília Standard Time = UTC - 3 hours + {Last, Sun, Mar, 1, -180} } }; From 49f044ecde8119d03d78fe167f375e71eabf6150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sun, 13 Oct 2024 10:43:56 +0200 Subject: [PATCH 075/234] Better fix for #4154 --- wled00/json.cpp | 19 ++++++++++++------- wled00/presets.cpp | 4 ++-- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/wled00/json.cpp b/wled00/json.cpp index c877d1f3b..06eb3015e 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -454,20 +454,25 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) handleSet(nullptr, apireq, false); // may set stateChanged } - // applying preset (2 cases: a) API call includes all preset values ("pd"), b) API only specifies preset ID ("ps")) + // Applying preset from JSON API has 2 cases: a) "pd" AKA "preset direct" and b) "ps" AKA "preset select" + // a) "preset direct" can only be an integer value representing preset ID. "preset direct" assumes JSON API contains the rest of preset content (i.e. from UI call) + // "preset direct" JSON can contain "ps" API (i.e. call from UI to cycle presets) in such case stateChanged has to be false (i.e. no "win" or "seg" API) + // b) "preset select" can be cycling ("1~5~""), random ("r" or "1~5r"), ID, etc. value allowed from JSON API. This type of call assumes no state changing content in API call byte presetToRestore = 0; - // a) already applied preset content (requires "seg" or "win" but will ignore the rest) if (!root[F("pd")].isNull() && stateChanged) { + // a) already applied preset content (requires "seg" or "win" but will ignore the rest) currentPreset = root[F("pd")] | currentPreset; - if (root["win"].isNull()) presetCycCurr = currentPreset; // otherwise it was set in handleSet() [set.cpp] + if (root["win"].isNull()) presetCycCurr = currentPreset; // otherwise presetCycCurr was set in handleSet() [set.cpp] presetToRestore = currentPreset; // stateUpdated() will clear the preset, so we need to restore it after + DEBUG_PRINTF_P(PSTR("Preset direct: %d\n"), currentPreset); } else if (!root["ps"].isNull()) { - ps = presetCycCurr; - if (root["win"].isNull() && getVal(root["ps"], &ps, 0, 0) && ps > 0 && ps < 251 && ps != currentPreset) { + // we have "ps" call (i.e. from button or external API call) or "pd" that includes "ps" (i.e. from UI call) + if (root["win"].isNull() && getVal(root["ps"], &presetCycCurr, 0, 0) && presetCycCurr > 0 && presetCycCurr < 251 && presetCycCurr != currentPreset) { + DEBUG_PRINTF_P(PSTR("Preset select: %d\n"), presetCycCurr); // b) preset ID only or preset that does not change state (use embedded cycling limits if they exist in getVal()) - applyPreset(ps, callMode); // async load from file system (only preset ID was specified) + applyPreset(presetCycCurr, callMode); // async load from file system (only preset ID was specified) return stateResponse; - } + } else presetCycCurr = currentPreset; // restore presetCycCurr } JsonObject playlist = root[F("playlist")]; diff --git a/wled00/presets.cpp b/wled00/presets.cpp index 2749d4677..20edfd91e 100644 --- a/wled00/presets.cpp +++ b/wled00/presets.cpp @@ -118,7 +118,7 @@ void initPresetsFile() bool applyPresetFromPlaylist(byte index) { DEBUG_PRINTF_P(PSTR("Request to apply preset: %d\n"), index); - presetToApply = presetCycCurr = index; + presetToApply = index; callModeToApply = CALL_MODE_DIRECT_CHANGE; return true; } @@ -127,7 +127,7 @@ bool applyPreset(byte index, byte callMode) { unloadPlaylist(); // applying a preset unloads the playlist (#3827) DEBUG_PRINTF_P(PSTR("Request to apply preset: %u\n"), index); - presetToApply = presetCycCurr = index; + presetToApply = index; callModeToApply = callMode; return true; } From 01e07ca0bc0157bcb279f7715c33916e39d7e0be Mon Sep 17 00:00:00 2001 From: AlDIY <87589371+dosipod@users.noreply.github.com> Date: Sun, 13 Oct 2024 20:34:18 +0300 Subject: [PATCH 076/234] Update xml.cpp --- wled00/xml.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 424842a1d..1ac22c9ce 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -172,7 +172,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) char fpass[l+1]; //fill password field with *** fpass[l] = 0; memset(fpass,'*',l); - settingsScript.printf_P(PSTR("addWiFi(\"%s\",\",%s\",0x%X,0x%X,0x%X);"), + settingsScript.printf_P(PSTR("addWiFi(\"%s\",\"%s\",0x%X,0x%X,0x%X);"), multiWiFi[n].clientSSID, fpass, (uint32_t) multiWiFi[n].staticIP, // explicit cast required as this is a struct From a0e81da8c5327e2083d616c5b7d45031b09a27d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Mon, 14 Oct 2024 20:13:59 +0200 Subject: [PATCH 077/234] WLED 0.15.0-b6 release (#4180) * modified Improv chip & version handling * Update build and changelog --- CHANGELOG.md | 17 +++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- wled00/improv.cpp | 30 ++++++++++++++---------------- wled00/wled.h | 4 ++-- 5 files changed, 36 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e377418e3..4dad83d9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,26 @@ ## WLED changelog +#### Build 2410140 +- WLED 0.15.0-b6 release +- Added BRT timezone (#4188 by @LuisFadini) +- Fixed the positioning of the "Download the latest binary" button (#4184 by @maxi4329) +- Add WLED_AUTOSEGMENTS compile flag (#4183 by @PaoloTK) +- New 512kB FS parition map for 4MB devices +- Internal API change: Static PinManager & UsermodManager +- Change in Improv chip ID and version generation +- Various optimisations, bugfixes and enhancements (#4005, #4174 & #4175 by @Xevel, #4180, #4168, #4154, #4189 by @dosipod) + +#### Build 2409170 +- UI: Introduce common.js in settings pages (size optimisation) +- Add the ability to toggle the reception of palette synchronizations (#4137 by @felddy) +- Usermod/FX: Temperature usermod added Temperature effect (example usermod effect by @blazoncek) +- Fix AsyncWebServer version pin + #### Build 2409140 - Configure different kinds of busses at compile (#4107 by @PaoloTK) - BREAKING: removes LEDPIN and DEFAULT_LED_TYPE compile overrides - Fetch LED types from Bus classes (dynamic UI) (#4129 by @netmindz, @blazoncek, @dedehai) +- Temperature usermod: update OneWire to 2.3.8 (#4131 by @iammattcoleman) #### Build 2409100 - WLED 0.15.0-b5 release diff --git a/package-lock.json b/package-lock.json index 415d88151..85ee1df0f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "wled", - "version": "0.15.0-b5", + "version": "0.15.0-b6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "wled", - "version": "0.15.0-b5", + "version": "0.15.0-b6", "license": "ISC", "dependencies": { "clean-css": "^5.3.3", diff --git a/package.json b/package.json index 721455bff..d76d87687 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wled", - "version": "0.15.0-b5", + "version": "0.15.0-b6", "description": "Tools for WLED project", "main": "tools/cdata.js", "directories": { diff --git a/wled00/improv.cpp b/wled00/improv.cpp index 31547f86c..197148b2b 100644 --- a/wled00/improv.cpp +++ b/wled00/improv.cpp @@ -194,24 +194,22 @@ void sendImprovIPRPCResult(ImprovRPCType type) { } void sendImprovInfoResponse() { - const char* bString = - #ifdef ESP8266 - "esp8266" - #elif CONFIG_IDF_TARGET_ESP32C3 - "esp32-c3" - #elif CONFIG_IDF_TARGET_ESP32S2 - "esp32-s2" - #elif CONFIG_IDF_TARGET_ESP32S3 - "esp32-s3"; - #else // ESP32 - "esp32"; - #endif - ; - + char bString[32]; + #ifdef ESP8266 + strcpy(bString, "esp8266"); + #else // ESP32 + strncpy(bString, ESP.getChipModel(), 31); + #if CONFIG_IDF_TARGET_ESP32 + bString[5] = '\0'; // disregard chip revision for classic ESP32 + #else + bString[31] = '\0'; // just in case + #endif + strlwr(bString); + #endif //Use serverDescription if it has been changed from the default "WLED", else mDNS name bool useMdnsName = (strcmp(serverDescription, "WLED") == 0 && strlen(cmDNS) > 0); - char vString[20]; - sprintf_P(vString, PSTR("0.15.0-b5/%i"), VERSION); + char vString[32]; + sprintf_P(vString, PSTR("%s/%i"), versionString, VERSION); const char *str[4] = {"WLED", vString, bString, useMdnsName ? cmDNS : serverDescription}; sendImprovRPCResult(ImprovRPCType::Request_Info, 4, str); diff --git a/wled00/wled.h b/wled00/wled.h index 173bd6554..bc525cd6f 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -3,12 +3,12 @@ /* Main sketch, global variable declarations @title WLED project sketch - @version 0.15.0-b5 + @version 0.15.0-b6 @author Christian Schwinne */ // version code in format yymmddb (b = daily build) -#define VERSION 2409170 +#define VERSION 2410140 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG From 44e28f96e0af0c78cb1b902a45b6332dcacd10e0 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Tue, 15 Oct 2024 13:16:18 +0200 Subject: [PATCH 078/234] Fix for Octopus on ESP32 C3 Apparently the C3 can not convert negative floats to uint8_t directly, casting it into an int first fixes it. --- wled00/FX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index e7429d19f..c6c8222be 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7749,7 +7749,7 @@ uint16_t mode_2Doctopus() { const int C_Y = (rows / 2) + ((SEGMENT.custom2 - 128)*rows)/255; for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) { - rMap[XY(x, y)].angle = 40.7436f * atan2f((y - C_Y), (x - C_X)); // avoid 128*atan2()/PI + rMap[XY(x, y)].angle = int(40.7436f * atan2f((y - C_Y), (x - C_X))); // avoid 128*atan2()/PI rMap[XY(x, y)].radius = hypotf((x - C_X), (y - C_Y)) * mapp; //thanks Sutaburosu } } From 5e29f2c1b7844492c5ccaf194f524fe810947c3f Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Tue, 15 Oct 2024 20:11:33 +0200 Subject: [PATCH 079/234] fixed atan2_t approximation was incorrect, now doing it right. also removed hypotf() from octopus, saving a little flash. --- wled00/FX.cpp | 6 ++++-- wled00/wled_math.cpp | 39 +++++++++++++++++---------------------- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 338dd2df9..5b4513dc7 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7749,8 +7749,10 @@ uint16_t mode_2Doctopus() { const int C_Y = (rows / 2) + ((SEGMENT.custom2 - 128)*rows)/255; for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) { - rMap[XY(x, y)].angle = 40.7436f * atan2_t((y - C_Y), (x - C_X)); // avoid 128*atan2()/PI - rMap[XY(x, y)].radius = hypotf((x - C_X), (y - C_Y)) * mapp; //thanks Sutaburosu + rMap[XY(x, y)].angle = int(40.7436f * atan2_t((y - C_Y), (x - C_X))); // avoid 128*atan2()/PI + int dx = (x - C_X); + int dy = (y - C_Y); + rMap[XY(x, y)].radius = sqrtf(dx * dx + dy * dy) * mapp; //thanks Sutaburosu } } } diff --git a/wled00/wled_math.cpp b/wled00/wled_math.cpp index 080cc9425..1825ab198 100644 --- a/wled00/wled_math.cpp +++ b/wled00/wled_math.cpp @@ -88,8 +88,8 @@ uint8_t cos8_t(uint8_t theta) { float sin_approx(float theta) { theta = modd(theta, TWO_PI); // modulo: bring to -2pi to 2pi range - if(theta < 0) theta += M_TWOPI; // 0-2pi range - uint16_t scaled_theta = (uint16_t)(theta * (0xFFFF / M_TWOPI)); + if(theta < 0) theta += TWO_PI; // 0-2pi range + uint16_t scaled_theta = (uint16_t)(theta * (0xFFFF / TWO_PI)); int32_t result = sin16_t(scaled_theta); float sin = float(result) / 0x7FFF; return sin; @@ -110,28 +110,23 @@ float tan_approx(float x) { #define ATAN2_CONST_A 0.1963f #define ATAN2_CONST_B 0.9817f -// fast atan2() approximation source: public domain +// atan2_t approximation, with the idea from https://gist.github.com/volkansalma/2972237?permalink_comment_id=3872525#gistcomment-3872525 float atan2_t(float y, float x) { - if (x == 0.0f) return (y > 0.0f) ? M_PI_2 : (y < 0.0f) ? -M_PI_2 : 0.0f; - - float abs_y = (y < 0.0f) ? -y : y + 1e-10f; // make sure y is not zero to prevent division by 0 - float z = abs_y / x; - float atan_approx; - - if (z < 1.0f) { - atan_approx = z / (1.0f + ATAN2_CONST_A * z * z); - if (x < 0.0f) { - return (y >= 0.0f) ? atan_approx + PI : atan_approx - PI; - } + float abs_y = fabs(y); + float abs_x = fabs(x); + float r = (abs_x - abs_y) / (abs_y + abs_x + 1e-10f); // avoid division by zero by adding a small nubmer + float angle; + if(x < 0) { + r = -r; + angle = M_PI/2.0f + M_PI/4.f; } - else { - z = x / abs_y; - atan_approx = M_PI_2 - z / (1.0f + ATAN2_CONST_A * z * z); - if (y < 0.0f) { - return -atan_approx; - } - } - return atan_approx; + else + angle = M_PI/2.0f - M_PI/4.f; + + float add = (ATAN2_CONST_A * (r * r) - ATAN2_CONST_B) * r; + angle += add; + angle = y < 0 ? -angle : angle; + return angle; } //https://stackoverflow.com/questions/3380628 From e9d2182390d43d7dd25492f6555d082280e79b3b Mon Sep 17 00:00:00 2001 From: Christian Schwinne Date: Wed, 16 Oct 2024 00:07:19 +0200 Subject: [PATCH 080/234] Re-license the WLED project from MIT to EUPL (#4194) --- LICENSE | 307 +++++++++++++++++++++++++++++++++-- readme.md | 4 +- wled00/FX.cpp | 20 +-- wled00/FX.h | 20 +-- wled00/FX_2Dfcn.cpp | 19 +-- wled00/FX_fcn.cpp | 20 +-- wled00/data/settings_sec.htm | 2 +- 7 files changed, 304 insertions(+), 88 deletions(-) diff --git a/LICENSE b/LICENSE index 69325d21c..cca21c008 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,294 @@ -MIT License +Copyright (c) 2016-present Christian Schwinne and individual WLED contributors +Licensed under the EUPL v. 1.2 or later -Copyright (c) 2016 Christian Schwinne + EUROPEAN UNION PUBLIC LICENCE v. 1.2 + EUPL © the European Union 2007, 2016 -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +This European Union Public Licence (the ‘EUPL’) applies to the Work (as +defined below) which is provided under the terms of this Licence. Any use of +the Work, other than as authorised under this Licence is prohibited (to the +extent such use is covered by a right of the copyright holder of the Work). -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +The Work is provided under the terms of this Licence when the Licensor (as +defined below) has placed the following notice immediately following the +copyright notice for the Work: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file + Licensed under the EUPL + +or has expressed by any other means his willingness to license under the EUPL. + +1. Definitions + +In this Licence, the following terms have the following meaning: + +- ‘The Licence’: this Licence. + +- ‘The Original Work’: the work or software distributed or communicated by the + Licensor under this Licence, available as Source Code and also as Executable + Code as the case may be. + +- ‘Derivative Works’: the works or software that could be created by the + Licensee, based upon the Original Work or modifications thereof. This + Licence does not define the extent of modification or dependence on the + Original Work required in order to classify a work as a Derivative Work; + this extent is determined by copyright law applicable in the country + mentioned in Article 15. + +- ‘The Work’: the Original Work or its Derivative Works. + +- ‘The Source Code’: the human-readable form of the Work which is the most + convenient for people to study and modify. + +- ‘The Executable Code’: any code which has generally been compiled and which + is meant to be interpreted by a computer as a program. + +- ‘The Licensor’: the natural or legal person that distributes or communicates + the Work under the Licence. + +- ‘Contributor(s)’: any natural or legal person who modifies the Work under + the Licence, or otherwise contributes to the creation of a Derivative Work. + +- ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of + the Work under the terms of the Licence. + +- ‘Distribution’ or ‘Communication’: any act of selling, giving, lending, + renting, distributing, communicating, transmitting, or otherwise making + available, online or offline, copies of the Work or providing access to its + essential functionalities at the disposal of any other natural or legal + person. + +2. Scope of the rights granted by the Licence + +The Licensor hereby grants You a worldwide, royalty-free, non-exclusive, +sublicensable licence to do the following, for the duration of copyright +vested in the Original Work: + +- use the Work in any circumstance and for all usage, +- reproduce the Work, +- modify the Work, and make Derivative Works based upon the Work, +- communicate to the public, including the right to make available or display + the Work or copies thereof to the public and perform publicly, as the case + may be, the Work, +- distribute the Work or copies thereof, +- lend and rent the Work or copies thereof, +- sublicense rights in the Work or copies thereof. + +Those rights can be exercised on any media, supports and formats, whether now +known or later invented, as far as the applicable law permits so. + +In the countries where moral rights apply, the Licensor waives his right to +exercise his moral right to the extent allowed by law in order to make +effective the licence of the economic rights here above listed. + +The Licensor grants to the Licensee royalty-free, non-exclusive usage rights +to any patents held by the Licensor, to the extent necessary to make use of +the rights granted on the Work under this Licence. + +3. Communication of the Source Code + +The Licensor may provide the Work either in its Source Code form, or as +Executable Code. If the Work is provided as Executable Code, the Licensor +provides in addition a machine-readable copy of the Source Code of the Work +along with each copy of the Work that the Licensor distributes or indicates, +in a notice following the copyright notice attached to the Work, a repository +where the Source Code is easily and freely accessible for as long as the +Licensor continues to distribute or communicate the Work. + +4. Limitations on copyright + +Nothing in this Licence is intended to deprive the Licensee of the benefits +from any exception or limitation to the exclusive rights of the rights owners +in the Work, of the exhaustion of those rights or of other applicable +limitations thereto. + +5. Obligations of the Licensee + +The grant of the rights mentioned above is subject to some restrictions and +obligations imposed on the Licensee. Those obligations are the following: + +Attribution right: The Licensee shall keep intact all copyright, patent or +trademarks notices and all notices that refer to the Licence and to the +disclaimer of warranties. The Licensee must include a copy of such notices and +a copy of the Licence with every copy of the Work he/she distributes or +communicates. The Licensee must cause any Derivative Work to carry prominent +notices stating that the Work has been modified and the date of modification. + +Copyleft clause: If the Licensee distributes or communicates copies of the +Original Works or Derivative Works, this Distribution or Communication will be +done under the terms of this Licence or of a later version of this Licence +unless the Original Work is expressly distributed only under this version of +the Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee +(becoming Licensor) cannot offer or impose any additional terms or conditions +on the Work or Derivative Work that alter or restrict the terms of the +Licence. + +Compatibility clause: If the Licensee Distributes or Communicates Derivative +Works or copies thereof based upon both the Work and another work licensed +under a Compatible Licence, this Distribution or Communication can be done +under the terms of this Compatible Licence. For the sake of this clause, +‘Compatible Licence’ refers to the licences listed in the appendix attached to +this Licence. Should the Licensee's obligations under the Compatible Licence +conflict with his/her obligations under this Licence, the obligations of the +Compatible Licence shall prevail. + +Provision of Source Code: When distributing or communicating copies of the +Work, the Licensee will provide a machine-readable copy of the Source Code or +indicate a repository where this Source will be easily and freely available +for as long as the Licensee continues to distribute or communicate the Work. + +Legal Protection: This Licence does not grant permission to use the trade +names, trademarks, service marks, or names of the Licensor, except as required +for reasonable and customary use in describing the origin of the Work and +reproducing the content of the copyright notice. + +6. Chain of Authorship + +The original Licensor warrants that the copyright in the Original Work granted +hereunder is owned by him/her or licensed to him/her and that he/she has the +power and authority to grant the Licence. + +Each Contributor warrants that the copyright in the modifications he/she +brings to the Work are owned by him/her or licensed to him/her and that he/she +has the power and authority to grant the Licence. + +Each time You accept the Licence, the original Licensor and subsequent +Contributors grant You a licence to their contributions to the Work, under the +terms of this Licence. + +7. Disclaimer of Warranty + +The Work is a work in progress, which is continuously improved by numerous +Contributors. It is not a finished work and may therefore contain defects or +‘bugs’ inherent to this type of development. + +For the above reason, the Work is provided under the Licence on an ‘as is’ +basis and without warranties of any kind concerning the Work, including +without limitation merchantability, fitness for a particular purpose, absence +of defects or errors, accuracy, non-infringement of intellectual property +rights other than copyright as stated in Article 6 of this Licence. + +This disclaimer of warranty is an essential part of the Licence and a +condition for the grant of any rights to the Work. + +8. Disclaimer of Liability + +Except in the cases of wilful misconduct or damages directly caused to natural +persons, the Licensor will in no event be liable for any direct or indirect, +material or moral, damages of any kind, arising out of the Licence or of the +use of the Work, including without limitation, damages for loss of goodwill, +work stoppage, computer failure or malfunction, loss of data or any commercial +damage, even if the Licensor has been advised of the possibility of such +damage. However, the Licensor will be liable under statutory product liability +laws as far such laws apply to the Work. + +9. Additional agreements + +While distributing the Work, You may choose to conclude an additional +agreement, defining obligations or services consistent with this Licence. +However, if accepting obligations, You may act only on your own behalf and on +your sole responsibility, not on behalf of the original Licensor or any other +Contributor, and only if You agree to indemnify, defend, and hold each +Contributor harmless for any liability incurred by, or claims asserted against +such Contributor by the fact You have accepted any warranty or additional +liability. + +10. Acceptance of the Licence + +The provisions of this Licence can be accepted by clicking on an icon ‘I +agree’ placed under the bottom of a window displaying the text of this Licence +or by affirming consent in any other similar way, in accordance with the rules +of applicable law. Clicking on that icon indicates your clear and irrevocable +acceptance of this Licence and all of its terms and conditions. + +Similarly, you irrevocably accept this Licence and all of its terms and +conditions by exercising any rights granted to You by Article 2 of this +Licence, such as the use of the Work, the creation by You of a Derivative Work +or the Distribution or Communication by You of the Work or copies thereof. + +11. Information to the public + +In case of any Distribution or Communication of the Work by means of +electronic communication by You (for example, by offering to download the Work +from a remote location) the distribution channel or media (for example, a +website) must at least provide to the public the information requested by the +applicable law regarding the Licensor, the Licence and the way it may be +accessible, concluded, stored and reproduced by the Licensee. + +12. Termination of the Licence + +The Licence and the rights granted hereunder will terminate automatically upon +any breach by the Licensee of the terms of the Licence. + +Such a termination will not terminate the licences of any person who has +received the Work from the Licensee under the Licence, provided such persons +remain in full compliance with the Licence. + +13. Miscellaneous + +Without prejudice of Article 9 above, the Licence represents the complete +agreement between the Parties as to the Work. + +If any provision of the Licence is invalid or unenforceable under applicable +law, this will not affect the validity or enforceability of the Licence as a +whole. Such provision will be construed or reformed so as necessary to make it +valid and enforceable. + +The European Commission may publish other linguistic versions or new versions +of this Licence or updated versions of the Appendix, so far this is required +and reasonable, without reducing the scope of the rights granted by the +Licence. New versions of the Licence will be published with a unique version +number. + +All linguistic versions of this Licence, approved by the European Commission, +have identical value. Parties can take advantage of the linguistic version of +their choice. + +14. Jurisdiction + +Without prejudice to specific agreement between parties, + +- any litigation resulting from the interpretation of this License, arising + between the European Union institutions, bodies, offices or agencies, as a + Licensor, and any Licensee, will be subject to the jurisdiction of the Court + of Justice of the European Union, as laid down in article 272 of the Treaty + on the Functioning of the European Union, + +- any litigation arising between other parties and resulting from the + interpretation of this License, will be subject to the exclusive + jurisdiction of the competent court where the Licensor resides or conducts + its primary business. + +15. Applicable Law + +Without prejudice to specific agreement between parties, + +- this Licence shall be governed by the law of the European Union Member State + where the Licensor has his seat, resides or has his registered office, + +- this licence shall be governed by Belgian law if the Licensor has no seat, + residence or registered office inside a European Union Member State. + +Appendix + +‘Compatible Licences’ according to Article 5 EUPL are: + +- GNU General Public License (GPL) v. 2, v. 3 +- GNU Affero General Public License (AGPL) v. 3 +- Open Software License (OSL) v. 2.1, v. 3.0 +- Eclipse Public License (EPL) v. 1.0 +- CeCILL v. 2.0, v. 2.1 +- Mozilla Public Licence (MPL) v. 2 +- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3 +- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for + works other than software +- European Union Public Licence (EUPL) v. 1.1, v. 1.2 +- Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong + Reciprocity (LiLiQ-R+). + +The European Commission may update this Appendix to later versions of the +above licences without producing a new version of the EUPL, as long as they +provide the rights granted in Article 2 of this Licence and protect the +covered Source Code from exclusive appropriation. + +All other changes or additions to this Appendix require the production of a +new EUPL version. \ No newline at end of file diff --git a/readme.md b/readme.md index 11c1733f8..80256560a 100644 --- a/readme.md +++ b/readme.md @@ -61,7 +61,7 @@ See [here](https://kno.wled.ge/basics/compatible-hardware)! ## ✌️ Other -Licensed under the MIT license +Licensed under the EUPL v1.2 license Credits [here](https://kno.wled.ge/about/contributors/)! Join the Discord server to discuss everything about WLED! @@ -80,5 +80,5 @@ If WLED really brightens up your day, you can [![](https://img.shields.io/badge/ If you are prone to photosensitive epilepsy, we recommended you do **not** use this software. If you still want to try, don't use strobe, lighting or noise modes or high effect speed settings. -As per the MIT license, I assume no liability for any damage to you or any other person or equipment. +As per the EUPL license, I assume no liability for any damage to you or any other person or equipment. diff --git a/wled00/FX.cpp b/wled00/FX.cpp index c6c8222be..d4b83de6c 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2,24 +2,10 @@ WS2812FX.cpp contains all effect methods Harm Aldick - 2016 www.aldick.org - LICENSE - The MIT License (MIT) + Copyright (c) 2016 Harm Aldick - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. + Licensed under the EUPL v. 1.2 or later + Adapted from code originally licensed under the MIT license Modified heavily for WLED */ diff --git a/wled00/FX.h b/wled00/FX.h index f16f07924..385c52476 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -2,24 +2,10 @@ WS2812FX.h - Library for WS2812 LED effects. Harm Aldick - 2016 www.aldick.org - LICENSE - The MIT License (MIT) + Copyright (c) 2016 Harm Aldick - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. + Licensed under the EUPL v. 1.2 or later + Adapted from code originally licensed under the MIT license Modified for WLED */ diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 0f6690549..e38602ebc 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -1,24 +1,9 @@ /* FX_2Dfcn.cpp contains all 2D utility functions - LICENSE - The MIT License (MIT) Copyright (c) 2022 Blaz Kristan (https://blaz.at/home) - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. + Licensed under the EUPL v. 1.2 or later + Adapted from code originally licensed under the MIT license Parts of the code adapted from WLED Sound Reactive */ diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 1bbfa365b..79189ef57 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -2,24 +2,10 @@ WS2812FX_fcn.cpp contains all utility functions Harm Aldick - 2016 www.aldick.org - LICENSE - The MIT License (MIT) + Copyright (c) 2016 Harm Aldick - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. + Licensed under the EUPL v. 1.2 or later + Adapted from code originally licensed under the MIT license Modified heavily for WLED */ diff --git a/wled00/data/settings_sec.htm b/wled00/data/settings_sec.htm index ce9bd8aa3..fa75882c0 100644 --- a/wled00/data/settings_sec.htm +++ b/wled00/data/settings_sec.htm @@ -72,7 +72,7 @@ Contributors, dependencies and special thanks
A huge thank you to everyone who helped me create WLED!

(c) 2016-2024 Christian Schwinne
- Licensed under the MIT license

+ Licensed under the EUPL v1.2 license

Server message: Response error!
From 98a6907976bfa3142545467359e876bd6d0ddc22 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Wed, 16 Oct 2024 19:53:58 +0200 Subject: [PATCH 081/234] cleanup and improvement to sin_appros() -replaced all PI references with M_PI version -there is no need to do the angle-modulo in float, casting it to an integer does the same BUT it has to be cast to an `int` first, see comment. --- wled00/wled_math.cpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/wled00/wled_math.cpp b/wled00/wled_math.cpp index 1825ab198..a191968e1 100644 --- a/wled00/wled_math.cpp +++ b/wled00/wled_math.cpp @@ -15,17 +15,17 @@ // Note: cos_t, sin_t and tan_t are very accurate but may be slow // the math.h functions use several kB of flash and are to be avoided if possible // sin16_t / cos16_t are faster and much more accurate than the fastled variants -// sin_approx and cos_approx are float wrappers for sin16_t/cos16_t and have an accuracy of +/-0.0015 compared to sinf() +// sin_approx and cos_approx are float wrappers for sin16_t/cos16_t and have an accuracy better than +/-0.0015 compared to sinf() // sin8_t / cos8_t are fastled replacements and use sin16_t / cos16_t. Slightly slower than fastled version but very accurate float cos_t(float phi) { - float x = modd(phi, TWO_PI); + float x = modd(phi, M_TWOPI); if (x < 0) x = -1 * x; int8_t sign = 1; - if (x > PI) + if (x > M_PI) { - x -= PI; + x -= M_PI; sign = -1; } float xx = x * x; @@ -38,7 +38,7 @@ float cos_t(float phi) } float sin_t(float phi) { - float res = cos_t(HALF_PI - phi); + float res = cos_t(M_PI_2 - phi); #ifdef WLED_DEBUG_MATH Serial.printf("sin: %f,%f,%f,(%f)\n",x,res,sin(x),res-sin(x)); #endif @@ -87,9 +87,7 @@ uint8_t cos8_t(uint8_t theta) { float sin_approx(float theta) { - theta = modd(theta, TWO_PI); // modulo: bring to -2pi to 2pi range - if(theta < 0) theta += TWO_PI; // 0-2pi range - uint16_t scaled_theta = (uint16_t)(theta * (0xFFFF / TWO_PI)); + uint16_t scaled_theta = (int)(theta * (0xFFFF / M_TWOPI)); // note: do not cast negative float to uint! cast to int first (undefined on C3) int32_t result = sin16_t(scaled_theta); float sin = float(result) / 0x7FFF; return sin; @@ -118,10 +116,10 @@ float atan2_t(float y, float x) { float angle; if(x < 0) { r = -r; - angle = M_PI/2.0f + M_PI/4.f; + angle = M_PI_2 + M_PI_4; } else - angle = M_PI/2.0f - M_PI/4.f; + angle = M_PI_2 - M_PI_4; float add = (ATAN2_CONST_A * (r * r) - ATAN2_CONST_B) * r; angle += add; @@ -140,10 +138,10 @@ float acos_t(float x) { ret = ret * xabs; ret = ret - 0.2121144f; ret = ret * xabs; - ret = ret + HALF_PI; + ret = ret + M_PI_2; ret = ret * sqrt(1.0f-xabs); ret = ret - 2 * negate * ret; - float res = negate * PI + ret; + float res = negate * M_PI + ret; #ifdef WLED_DEBUG_MATH Serial.printf("acos: %f,%f,%f,(%f)\n",x,res,acos(x),res-acos(x)); #endif @@ -151,7 +149,7 @@ float acos_t(float x) { } float asin_t(float x) { - float res = HALF_PI - acos_t(x); + float res = M_PI_2 - acos_t(x); #ifdef WLED_DEBUG_MATH Serial.printf("asin: %f,%f,%f,(%f)\n",x,res,asin(x),res-asin(x)); #endif @@ -167,7 +165,7 @@ float atan_t(float x) { //For A/B/C, see https://stackoverflow.com/a/42542593 static const double A { 0.0776509570923569 }; static const double B { -0.287434475393028 }; - static const double C { ((HALF_PI/2) - A - B) }; + static const double C { ((M_PI_4) - A - B) }; // polynominal factors for approximation between 1 and 5 static const float C0 { 0.089494f }; static const float C1 { 0.974207f }; @@ -182,7 +180,7 @@ float atan_t(float x) { x = std::abs(x); float res; if (x > 5.0f) { // atan(x) converges to pi/2 - (1/x) for large values - res = HALF_PI - (1.0f/x); + res = M_PI_2 - (1.0f/x); } else if (x > 1.0f) { //1 < x < 5 float xx = x * x; res = (C4*xx*xx)+(C3*xx*x)+(C2*xx)+(C1*x)+C0; From bd68b977d512e28b072cfeb1d3c146e4af221e31 Mon Sep 17 00:00:00 2001 From: maxi4329 Date: Thu, 17 Oct 2024 18:07:01 +0200 Subject: [PATCH 082/234] minor webui enhancements --- wled00/data/index.css | 20 +++++++++++++++++--- wled00/data/index.htm | 2 +- wled00/data/settings_2D.htm | 12 ++++++------ wled00/data/settings_leds.htm | 8 ++++---- wled00/data/settings_pin.htm | 11 ++++++++++- wled00/data/settings_sec.htm | 4 ++-- wled00/data/settings_sync.htm | 10 +++++----- wled00/data/settings_time.htm | 6 +++--- wled00/data/settings_um.htm | 10 +++++----- wled00/data/settings_wifi.htm | 8 ++++---- wled00/data/update.htm | 2 +- 11 files changed, 58 insertions(+), 35 deletions(-) diff --git a/wled00/data/index.css b/wled00/data/index.css index 6f465e407..2ae17ffe5 100644 --- a/wled00/data/index.css +++ b/wled00/data/index.css @@ -97,6 +97,7 @@ button { .labels { margin: 0; padding: 8px 0 2px 0; + font-size: 19px; } #namelabel { @@ -890,12 +891,12 @@ a.btn { line-height: 28px; } -/* Quick color select Black button (has white border) */ -.qcsb { +/* Quick color select Black and White button (has white/black border, depending on the theme) */ +.qcsb, .qcsw { width: 26px; height: 26px; line-height: 26px; - border: 1px solid #fff; + border: 1px solid var(--c-f); } /* Hex color input wrapper div */ @@ -1299,6 +1300,14 @@ TD .checkmark, TD .radiomark { width: 100%; } +#segutil { + margin-bottom: 12px; +} + +#segcont > div:first-child, #fxFind { + margin-top: 4px; +} + /* Simplify segments */ .simplified #segcont .lstI { margin-top: 4px; @@ -1433,6 +1442,11 @@ dialog { position: relative; } +.presin { + width: 100%; + box-sizing: border-box; +} + .btn-s, .btn-n { border: 1px solid var(--c-2); diff --git a/wled00/data/index.htm b/wled00/data/index.htm index e74ea0076..8adec791f 100644 --- a/wled00/data/index.htm +++ b/wled00/data/index.htm @@ -106,7 +106,7 @@
-
+

diff --git a/wled00/data/settings_2D.htm b/wled00/data/settings_2D.htm index a70ca76be..2aec03682 100644 --- a/wled00/data/settings_2D.htm +++ b/wled00/data/settings_2D.htm @@ -54,8 +54,8 @@ Orientation:
Serpentine:
Dimensions (WxH): x
-Offset X: -Y:
(offset from top-left corner in # LEDs) +Offset X: +Y:
(offset from top-left corner in # LEDs) `; p.insertAdjacentHTML("beforeend", b); } @@ -246,7 +246,7 @@ Y:

2D setup

- Strip or panel: + Strip or panel:  Panel dimensions (WxH): x
Horizontal panels: Vertical panels:
- 1st panel:
- Orientation:
@@ -286,7 +286,7 @@ Y:
Gap file:
- Note: Gap file is a .json file containing an array with number of elements equal to the matrix size.
+ Note: Gap file is a .json file containing an array with number of elements equal to the matrix size.
A value of -1 means that pixel at that position is missing, a value of 0 means never paint that pixel, and 1 means regular pixel.

diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 6be5becd1..0a28fda3f 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -747,7 +747,7 @@ Swap:

- LED memory usage: 0 / ? B
+ LED memory usage: 0 / ? B

Advanced

- Palette wrapping: + Palette wrapping:  +
diff --git a/wled00/data/settings_sec.htm b/wled00/data/settings_sec.htm index fa75882c0..6cc03e9eb 100644 --- a/wled00/data/settings_sec.htm +++ b/wled00/data/settings_sec.htm @@ -72,8 +72,8 @@ Contributors, dependencies and special thanks
A huge thank you to everyone who helped me create WLED!

(c) 2016-2024 Christian Schwinne
- Licensed under the EUPL v1.2 license

- Server message: Response error!
+ Licensed under the EUPL v1.2 license

+ Server message:  Response error!
diff --git a/wled00/data/settings_sync.htm b/wled00/data/settings_sync.htm index 34b9fc6cd..754605bf0 100644 --- a/wled00/data/settings_sync.htm +++ b/wled00/data/settings_sync.htm @@ -118,7 +118,7 @@ Receive UDP realtime:
Use main segment only:
Respect LED Maps:

Network DMX input
-Type: +Type: 
Multicast:
Start universe:
-Reboot required. Check out LedFx!
+Reboot required. Check out LedFx!
Skip out-of-sequence packets:
DMX start address:
DMX segment spacing:
E1.31 port priority:
-DMX mode: +DMX mode: 
Group Topic:
Publish on button press:
Retain brightness & color messages:
-Reboot required to apply changes. MQTT info +Reboot required to apply changes. MQTT info

Philips Hue

@@ -209,7 +209,7 @@ Hue status: Disabled in this build This firmware build does not support Serial interface.
-Baud rate: +Baud rate: 

Use 24h format:
- Time zone: + Time zone: 
UTC offset: seconds (max. 18 hours)
Current local time is unknown.
- Latitude:
- Longitude:
+ Latitude: 
+ Longitude: 
(opens new tab, only works in browser)
diff --git a/wled00/data/settings_um.htm b/wled00/data/settings_um.htm index c2f0ffbf2..9c53d560d 100644 --- a/wled00/data/settings_um.htm +++ b/wled00/data/settings_um.htm @@ -283,14 +283,14 @@

Usermod Setup

Global I2C GPIOs (HW)
(change requires reboot!)
- SDA: - SCL: + SDA:  + SCL: 
Global SPI GPIOs (HW)
(only changable on ESP32, change requires reboot!)
- MOSI: - MISO: - SCLK: + MOSI:  + MISO:  + SCLK: 
Reboot after save?
Loading settings...
diff --git a/wled00/data/settings_wifi.htm b/wled00/data/settings_wifi.htm index 30b6600ae..3b840f509 100644 --- a/wled00/data/settings_wifi.htm +++ b/wled00/data/settings_wifi.htm @@ -166,7 +166,7 @@ Static subnet mask:
Hide AP name:
AP password (leave empty for open):

Access Point WiFi channel:
- AP opens: + AP opens: 
- AP IP: Not active
+ AP IP:  Not active

Experimental

Force 802.11g mode (ESP8266 only):
Disable WiFi sleep:
Can help with connectivity issues and Audioreactive sync.
Disabling WiFi sleep increases power consumption.

-
TX power: @@ -205,7 +205,7 @@ Static subnet mask:
Listen for events over ESP-NOW
Keep disabled if not using a remote or wireless sync, increases power consumption.
Paired Remote MAC:
- Last device seen: None
+ Last device seen: None
diff --git a/wled00/data/update.htm b/wled00/data/update.htm index b68645a52..791a76f6b 100644 --- a/wled00/data/update.htm +++ b/wled00/data/update.htm @@ -16,7 +16,7 @@

WLED Software Update

- Installed version: ##VERSION##
+ Installed version: ##VERSION##
Download the latest binary: 
From caa997fff1750bd08e7d815674c3ff7728a14029 Mon Sep 17 00:00:00 2001 From: maxi4329 Date: Fri, 18 Oct 2024 18:43:41 +0200 Subject: [PATCH 083/234] removed onkeydown tried to find a replacement for the nbsp --- package-lock.json | 2 +- wled00/data/settings_2D.htm | 8 ++++---- wled00/data/settings_leds.htm | 8 ++++---- wled00/data/settings_pin.htm | 11 +---------- wled00/data/settings_sec.htm | 4 ++-- wled00/data/settings_sync.htm | 10 +++++----- wled00/data/settings_time.htm | 6 +++--- wled00/data/settings_um.htm | 10 +++++----- wled00/data/settings_wifi.htm | 8 ++++---- wled00/data/style.css | 3 +++ wled00/data/update.htm | 2 +- 11 files changed, 33 insertions(+), 39 deletions(-) diff --git a/package-lock.json b/package-lock.json index 85ee1df0f..e85857017 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "clean-css": "^5.3.3", "html-minifier-terser": "^7.2.0", "inliner": "^1.13.1", - "nodemon": "^3.0.2" + "nodemon": "^3.1.7" } }, "node_modules/@jridgewell/gen-mapping": { diff --git a/wled00/data/settings_2D.htm b/wled00/data/settings_2D.htm index 2aec03682..e372b3e21 100644 --- a/wled00/data/settings_2D.htm +++ b/wled00/data/settings_2D.htm @@ -246,7 +246,7 @@ Y: Back

2D setup

- Strip or panel:  + Strip or panel: x
Horizontal panels: Vertical panels:
- 1st panel: 
- Orientation: 
@@ -286,7 +286,7 @@ Y:
Gap file:
- Note: Gap file is a .json file containing an array with number of elements equal to the matrix size.
+ Note: Gap file is a .json file containing an array with number of elements equal to the matrix size.
A value of -1 means that pixel at that position is missing, a value of 0 means never paint that pixel, and 1 means regular pixel.

diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 0a28fda3f..6be5becd1 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -747,7 +747,7 @@ Swap:

- LED memory usage: 0 / ? B
+ LED memory usage: 0 / ? B

Advanced

- Palette wrapping:  + Palette wrapping: +
diff --git a/wled00/data/settings_sec.htm b/wled00/data/settings_sec.htm index 6cc03e9eb..fa75882c0 100644 --- a/wled00/data/settings_sec.htm +++ b/wled00/data/settings_sec.htm @@ -72,8 +72,8 @@ Contributors, dependencies and special thanks
A huge thank you to everyone who helped me create WLED!

(c) 2016-2024 Christian Schwinne
- Licensed under the EUPL v1.2 license

- Server message:  Response error!
+ Licensed under the EUPL v1.2 license

+ Server message: Response error!
diff --git a/wled00/data/settings_sync.htm b/wled00/data/settings_sync.htm index 754605bf0..34b9fc6cd 100644 --- a/wled00/data/settings_sync.htm +++ b/wled00/data/settings_sync.htm @@ -118,7 +118,7 @@ Receive UDP realtime:
Use main segment only:
Respect LED Maps:

Network DMX input
-Type:  +Type:
Multicast:
Start universe:
-Reboot required. Check out LedFx!
+Reboot required. Check out LedFx!
Skip out-of-sequence packets:
DMX start address:
DMX segment spacing:
E1.31 port priority:
-DMX mode:  +DMX mode:
Group Topic:
Publish on button press:
Retain brightness & color messages:
-Reboot required to apply changes. MQTT info +Reboot required to apply changes. MQTT info

Philips Hue

@@ -209,7 +209,7 @@ Hue status: Disabled in this build This firmware build does not support Serial interface.
-Baud rate:  +Baud rate:

Use 24h format:
- Time zone:  + Time zone:
UTC offset: seconds (max. 18 hours)
Current local time is unknown.
- Latitude: 
- Longitude: 
+ Latitude:
+ Longitude:
(opens new tab, only works in browser)
diff --git a/wled00/data/settings_um.htm b/wled00/data/settings_um.htm index 9c53d560d..c2f0ffbf2 100644 --- a/wled00/data/settings_um.htm +++ b/wled00/data/settings_um.htm @@ -283,14 +283,14 @@

Usermod Setup

Global I2C GPIOs (HW)
(change requires reboot!)
- SDA:  - SCL:  + SDA: + SCL:
Global SPI GPIOs (HW)
(only changable on ESP32, change requires reboot!)
- MOSI:  - MISO:  - SCLK:  + MOSI: + MISO: + SCLK:
Reboot after save?
Loading settings...
diff --git a/wled00/data/settings_wifi.htm b/wled00/data/settings_wifi.htm index 3b840f509..30b6600ae 100644 --- a/wled00/data/settings_wifi.htm +++ b/wled00/data/settings_wifi.htm @@ -166,7 +166,7 @@ Static subnet mask:
Hide AP name:
AP password (leave empty for open):

Access Point WiFi channel:
- AP opens:  + AP opens:
- AP IP:  Not active
+ AP IP: Not active

Experimental

Force 802.11g mode (ESP8266 only):
Disable WiFi sleep:
Can help with connectivity issues and Audioreactive sync.
Disabling WiFi sleep increases power consumption.

-
TX power:  @@ -205,7 +205,7 @@ Static subnet mask:
Listen for events over ESP-NOW
Keep disabled if not using a remote or wireless sync, increases power consumption.
Paired Remote MAC:
- Last device seen: None
+ Last device seen: None
diff --git a/wled00/data/style.css b/wled00/data/style.css index b6cb0f9e6..42e49d304 100644 --- a/wled00/data/style.css +++ b/wled00/data/style.css @@ -44,6 +44,9 @@ button.sml { min-width: 40px; margin: 0 0 0 10px; } +span:before, b:before, b:after, i:after{ + content: "\00A0"; +} #scan { margin-top: -10px; } diff --git a/wled00/data/update.htm b/wled00/data/update.htm index 791a76f6b..b68645a52 100644 --- a/wled00/data/update.htm +++ b/wled00/data/update.htm @@ -16,7 +16,7 @@

WLED Software Update

- Installed version: ##VERSION##
+ Installed version: ##VERSION##
Download the latest binary: 
From 4fa8a3898a8771c6680bf84eaa5ab5101dd82b5b Mon Sep 17 00:00:00 2001 From: 1Prototype1 Date: Sat, 19 Oct 2024 00:30:24 +0530 Subject: [PATCH 084/234] Added Distribute for cpal Added a button to distribute the color markers in palette equally --- wled00/data/cpal/cpal.htm | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/wled00/data/cpal/cpal.htm b/wled00/data/cpal/cpal.htm index b58c0987a..8fa715bc8 100644 --- a/wled00/data/cpal/cpal.htm +++ b/wled00/data/cpal/cpal.htm @@ -167,9 +167,10 @@
-
- Currently in use custom palettes -
+
+
+ Currently in use custom palettes +
@@ -187,7 +188,7 @@ Available static palettes
- + @@ -204,6 +205,13 @@ var paletteName = []; // Holds the names of the palettes after load. var svgSave = '' var svgEdit = '' + var svgDist = '' + var svgTrash = '' + + const distDiv = gId("distDiv"); + distDiv.addEventListener('click', distribute); + distDiv.setAttribute('title', 'Distribute colors equally'); + distDiv.innerHTML = svgDist; function recOf() { rect = gradientBox.getBoundingClientRect(); @@ -433,7 +441,7 @@ renderY = e.srcElement.getBoundingClientRect().y + 13; trash.id = "trash"; - trash.innerHTML = ''; + trash.innerHTML = svgTrash; trash.style.position = "absolute"; trash.style.left = (renderX) + "px"; trash.style.top = (renderY) + "px"; @@ -712,9 +720,27 @@ } } + function distribute() { + let colorMarkers = [...gradientBox.querySelectorAll('.color-marker')]; + colorMarkers.sort((a, b) => a.getAttribute('data-truepos') - b.getAttribute('data-truepos')); + colorMarkers = colorMarkers.slice(1, -1); + const spacing = Math.round(256 / (colorMarkers.length + 1)); + + colorMarkers.forEach((e, i) => { + const markerId = e.id.match(/\d+/)[0]; + const trueCol = e.getAttribute("data-truecol"); + gradientBox.removeChild(e); + gradientBox.removeChild(gId(`colorPicker${markerId}`)); + gradientBox.removeChild(gId(`colorPickerMarker${markerId}`)); + gradientBox.removeChild(gId(`deleteMarker${markerId}`)); + addC(spacing * (i + 1), trueCol); + }); + } + function rgbToHex(r, g, b) { const hex = ((r << 16) | (g << 8) | b).toString(16); return "#" + "0".repeat(6 - hex.length) + hex; } + From 0a97e28aab766ada3a7cf0fc2c9eb63a5f6afdf3 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sat, 19 Oct 2024 18:43:10 +0200 Subject: [PATCH 085/234] bugfix: prevent preset loading from resetting other errors without this fix, any not-yet reported error - like filesystem problems at startup, or out-of-memory - was rest by successfully loading a preset. --- wled00/presets.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/wled00/presets.cpp b/wled00/presets.cpp index 20edfd91e..04474113d 100644 --- a/wled00/presets.cpp +++ b/wled00/presets.cpp @@ -143,6 +143,7 @@ void applyPresetWithFallback(uint8_t index, uint8_t callMode, uint8_t effectID, void handlePresets() { + byte presetErrFlag = ERR_NONE; if (presetToSave) { strip.suspend(); doSaveState(); @@ -166,14 +167,16 @@ void handlePresets() #ifdef ARDUINO_ARCH_ESP32 if (tmpPreset==255 && tmpRAMbuffer!=nullptr) { deserializeJson(*pDoc,tmpRAMbuffer); - errorFlag = ERR_NONE; } else #endif { - errorFlag = readObjectFromFileUsingId(getPresetsFileName(tmpPreset < 255), tmpPreset, pDoc) ? ERR_NONE : ERR_FS_PLOAD; + presetErrFlag = readObjectFromFileUsingId(getPresetsFileName(tmpPreset < 255), tmpPreset, pDoc) ? ERR_NONE : ERR_FS_PLOAD; } fdo = pDoc->as(); + // only reset errorflag if previous error was preset-related + if ((errorFlag == ERR_NONE) || (errorFlag == ERR_FS_PLOAD)) errorFlag = presetErrFlag; + //HTTP API commands const char* httpwin = fdo["win"]; if (httpwin) { From 95b4bde918c00c2d3191a0f71a391965d69b3d34 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 20 Oct 2024 10:42:02 -0400 Subject: [PATCH 086/234] UsermodManager: Make into namespace Namespaces are the C++ language construct for grouping global functions. --- wled00/fcn_declare.h | 47 ++++++++++++++++++++----------------------- wled00/um_manager.cpp | 5 +++-- wled00/wled.h | 3 --- 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 71b00599c..78655b271 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -326,36 +326,33 @@ class Usermod { template static inline void oappend(const T& t) { oappend_shim->print(t); }; }; -class UsermodManager { - private: - static Usermod* ums[WLED_MAX_USERMODS]; - static byte numMods; +namespace UsermodManager { + extern byte numMods; - public: - static void loop(); - static void handleOverlayDraw(); - static bool handleButton(uint8_t b); - static bool getUMData(um_data_t **um_data, uint8_t mod_id = USERMOD_ID_RESERVED); // USERMOD_ID_RESERVED will poll all usermods - static void setup(); - static void connected(); - static void appendConfigData(Print&); - static void addToJsonState(JsonObject& obj); - static void addToJsonInfo(JsonObject& obj); - static void readFromJsonState(JsonObject& obj); - static void addToConfig(JsonObject& obj); - static bool readFromConfig(JsonObject& obj); + void loop(); + void handleOverlayDraw(); + bool handleButton(uint8_t b); + bool getUMData(um_data_t **um_data, uint8_t mod_id = USERMOD_ID_RESERVED); // USERMOD_ID_RESERVED will poll all usermods + void setup(); + void connected(); + void appendConfigData(Print&); + void addToJsonState(JsonObject& obj); + void addToJsonInfo(JsonObject& obj); + void readFromJsonState(JsonObject& obj); + void addToConfig(JsonObject& obj); + bool readFromConfig(JsonObject& obj); #ifndef WLED_DISABLE_MQTT - static void onMqttConnect(bool sessionPresent); - static bool onMqttMessage(char* topic, char* payload); + void onMqttConnect(bool sessionPresent); + bool onMqttMessage(char* topic, char* payload); #endif #ifndef WLED_DISABLE_ESPNOW - static bool onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t len); + bool onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t len); #endif - static void onUpdateBegin(bool); - static void onStateChange(uint8_t); - static bool add(Usermod* um); - static Usermod* lookup(uint16_t mod_id); - static inline byte getModCount() {return numMods;}; + void onUpdateBegin(bool); + void onStateChange(uint8_t); + bool add(Usermod* um); + Usermod* lookup(uint16_t mod_id); + inline byte getModCount() {return numMods;}; }; //usermods_list.cpp diff --git a/wled00/um_manager.cpp b/wled00/um_manager.cpp index 46fdf5b3b..1fdb6d688 100644 --- a/wled00/um_manager.cpp +++ b/wled00/um_manager.cpp @@ -3,6 +3,9 @@ * Registration and management utility for v2 usermods */ +static Usermod* ums[WLED_MAX_USERMODS] = {nullptr}; +byte UsermodManager::numMods = 0; + //Usermod Manager internals void UsermodManager::setup() { for (unsigned i = 0; i < numMods; i++) ums[i]->setup(); } void UsermodManager::connected() { for (unsigned i = 0; i < numMods; i++) ums[i]->connected(); } @@ -69,8 +72,6 @@ bool UsermodManager::add(Usermod* um) return true; } -Usermod* UsermodManager::ums[WLED_MAX_USERMODS] = {nullptr}; -byte UsermodManager::numMods = 0; /* Usermod v2 interface shim for oappend */ Print* Usermod::oappend_shim = nullptr; diff --git a/wled00/wled.h b/wled00/wled.h index bc525cd6f..5f1952bec 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -896,9 +896,6 @@ WLED_GLOBAL uint32_t ledMaps _INIT(0); // bitfield representation of available l WLED_GLOBAL uint16_t ledMaps _INIT(0); // bitfield representation of available ledmaps #endif -// Usermod manager -WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager()); - // global I2C SDA pin (used for usermods) #ifndef I2CSDAPIN WLED_GLOBAL int8_t i2c_sda _INIT(-1); From 32eee3365ac06858b5d6821931c39c020af233bc Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 20 Oct 2024 10:48:31 -0400 Subject: [PATCH 087/234] PinManager: Make in to namespace Namespaces are the C++ language construct for grouping global functions. --- wled00/pin_manager.cpp | 20 +++++------ wled00/pin_manager.h | 78 +++++++++++++++++++----------------------- 2 files changed, 45 insertions(+), 53 deletions(-) diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index 793b5440c..14209977a 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -13,6 +13,16 @@ #endif #endif +// Pin management state variables +#ifdef ESP8266 +static uint32_t pinAlloc = 0UL; // 1 bit per pin, we use first 17bits +#else +static uint64_t pinAlloc = 0ULL; // 1 bit per pin, we use 50 bits on ESP32-S3 +static uint16_t ledcAlloc = 0; // up to 16 LEDC channels (WLED_MAX_ANALOG_CHANNELS) +#endif +static uint8_t i2cAllocCount = 0; // allow multiple allocation of I2C bus pins but keep track of allocations +static uint8_t spiAllocCount = 0; // allow multiple allocation of SPI bus pins but keep track of allocations +static PinOwner ownerTag[WLED_NUM_PINS] = { PinOwner::None }; /// Actual allocation/deallocation routines bool PinManager::deallocatePin(byte gpio, PinOwner tag) @@ -273,13 +283,3 @@ void PinManager::deallocateLedc(byte pos, byte channels) } } #endif - -#ifdef ESP8266 -uint32_t PinManager::pinAlloc = 0UL; -#else -uint64_t PinManager::pinAlloc = 0ULL; -uint16_t PinManager::ledcAlloc = 0; -#endif -uint8_t PinManager::i2cAllocCount = 0; -uint8_t PinManager::spiAllocCount = 0; -PinOwner PinManager::ownerTag[WLED_NUM_PINS] = { PinOwner::None }; diff --git a/wled00/pin_manager.h b/wled00/pin_manager.h index 73a4a3656..c8fb165ce 100644 --- a/wled00/pin_manager.h +++ b/wled00/pin_manager.h @@ -9,6 +9,12 @@ #endif #include "const.h" // for USERMOD_* values +#ifdef ESP8266 +#define WLED_NUM_PINS (GPIO_PIN_COUNT+1) // somehow they forgot GPIO 16 (0-16==17) +#else +#define WLED_NUM_PINS (GPIO_PIN_COUNT) +#endif + typedef struct PinManagerPinType { int8_t pin; bool isOutput; @@ -70,53 +76,39 @@ enum struct PinOwner : uint8_t { }; static_assert(0u == static_cast(PinOwner::None), "PinOwner::None must be zero, so default array initialization works as expected"); -class PinManager { - private: - #ifdef ESP8266 - #define WLED_NUM_PINS (GPIO_PIN_COUNT+1) // somehow they forgot GPIO 16 (0-16==17) - static uint32_t pinAlloc; // 1 bit per pin, we use first 17bits - #else - #define WLED_NUM_PINS (GPIO_PIN_COUNT) - static uint64_t pinAlloc; // 1 bit per pin, we use 50 bits on ESP32-S3 - static uint16_t ledcAlloc; // up to 16 LEDC channels (WLED_MAX_ANALOG_CHANNELS) - #endif - static uint8_t i2cAllocCount; // allow multiple allocation of I2C bus pins but keep track of allocations - static uint8_t spiAllocCount; // allow multiple allocation of SPI bus pins but keep track of allocations - static PinOwner ownerTag[WLED_NUM_PINS]; +namespace PinManager { + // De-allocates a single pin + bool deallocatePin(byte gpio, PinOwner tag); + // De-allocates multiple pins but only if all can be deallocated (PinOwner has to be specified) + bool deallocateMultiplePins(const uint8_t *pinArray, byte arrayElementCount, PinOwner tag); + bool deallocateMultiplePins(const managed_pin_type *pinArray, byte arrayElementCount, PinOwner tag); + // Allocates a single pin, with an owner tag. + // De-allocation requires the same owner tag (or override) + bool allocatePin(byte gpio, bool output, PinOwner tag); + // Allocates all the pins, or allocates none of the pins, with owner tag. + // Provided to simplify error condition handling in clients + // using more than one pin, such as I2C, SPI, rotary encoders, + // ethernet, etc.. + bool allocateMultiplePins(const managed_pin_type * mptArray, byte arrayElementCount, PinOwner tag ); - public: - // De-allocates a single pin - static bool deallocatePin(byte gpio, PinOwner tag); - // De-allocates multiple pins but only if all can be deallocated (PinOwner has to be specified) - static bool deallocateMultiplePins(const uint8_t *pinArray, byte arrayElementCount, PinOwner tag); - static bool deallocateMultiplePins(const managed_pin_type *pinArray, byte arrayElementCount, PinOwner tag); - // Allocates a single pin, with an owner tag. - // De-allocation requires the same owner tag (or override) - static bool allocatePin(byte gpio, bool output, PinOwner tag); - // Allocates all the pins, or allocates none of the pins, with owner tag. - // Provided to simplify error condition handling in clients - // using more than one pin, such as I2C, SPI, rotary encoders, - // ethernet, etc.. - static bool allocateMultiplePins(const managed_pin_type * mptArray, byte arrayElementCount, PinOwner tag ); + [[deprecated("Replaced by three-parameter allocatePin(gpio, output, ownerTag), for improved debugging")]] + inline bool allocatePin(byte gpio, bool output = true) { return allocatePin(gpio, output, PinOwner::None); } + [[deprecated("Replaced by two-parameter deallocatePin(gpio, ownerTag), for improved debugging")]] + inline void deallocatePin(byte gpio) { deallocatePin(gpio, PinOwner::None); } - [[deprecated("Replaced by three-parameter allocatePin(gpio, output, ownerTag), for improved debugging")]] - static inline bool allocatePin(byte gpio, bool output = true) { return allocatePin(gpio, output, PinOwner::None); } - [[deprecated("Replaced by two-parameter deallocatePin(gpio, ownerTag), for improved debugging")]] - static inline void deallocatePin(byte gpio) { deallocatePin(gpio, PinOwner::None); } + // will return true for reserved pins + bool isPinAllocated(byte gpio, PinOwner tag = PinOwner::None); + // will return false for reserved pins + bool isPinOk(byte gpio, bool output = true); + + bool isReadOnlyPin(byte gpio); - // will return true for reserved pins - static bool isPinAllocated(byte gpio, PinOwner tag = PinOwner::None); - // will return false for reserved pins - static bool isPinOk(byte gpio, bool output = true); - - static bool isReadOnlyPin(byte gpio); + PinOwner getPinOwner(byte gpio); - static PinOwner getPinOwner(byte gpio); - - #ifdef ARDUINO_ARCH_ESP32 - static byte allocateLedc(byte channels); - static void deallocateLedc(byte pos, byte channels); - #endif + #ifdef ARDUINO_ARCH_ESP32 + byte allocateLedc(byte channels); + void deallocateLedc(byte pos, byte channels); + #endif }; //extern PinManager pinManager; From 7db198909398feeab431031c0ae3f21e47266bd3 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 22 Oct 2024 14:42:48 +0200 Subject: [PATCH 088/234] fix major performance regression in ArduinoFFT since v2.0.0, we cannot override the internal sqrt function by #define --> moved to build_flags. Average FFT time on esp32 : 4.5ms --> 1.8ms --- platformio.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 3005ba220..b130b687c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -259,7 +259,8 @@ lib_deps = https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 ${env.lib_deps} # additional build flags for audioreactive -AR_build_flags = -D USERMOD_AUDIOREACTIVE +AR_build_flags = -D USERMOD_AUDIOREACTIVE + -D sqrt_internal=sqrtf ;; -fsingle-precision-constant ;; forces ArduinoFFT to use float math (2x faster) AR_lib_deps = kosme/arduinoFFT @ 2.0.1 [esp32_idf_V4] From 01d43c69fb5d9fa616bc276039fc00c33742bad0 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 22 Oct 2024 14:45:32 +0200 Subject: [PATCH 089/234] AR memory optimization - part 1 allocating FFT buffers late makes up to 16Kb heap available when audioreactive is not enabled. Already tested in MM fork. --- usermods/audioreactive/audio_reactive.h | 30 +++++++++++++++---------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index fde7afded..1a91c333f 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -191,8 +191,8 @@ constexpr uint16_t samplesFFT_2 = 256; // meaningfull part of FFT resul #define LOG_256 5.54517744f // log(256) // These are the input and output vectors. Input vectors receive computed results from FFT. -static float vReal[samplesFFT] = {0.0f}; // FFT sample inputs / freq output - these are our raw result bins -static float vImag[samplesFFT] = {0.0f}; // imaginary parts +static float* vReal = nullptr; // FFT sample inputs / freq output - these are our raw result bins +static float* vImag = nullptr; // imaginary parts // Create FFT object // lib_deps += https://github.com/kosme/arduinoFFT#develop @ 1.9.2 @@ -200,14 +200,9 @@ static float vImag[samplesFFT] = {0.0f}; // imaginary parts // #define FFT_SPEED_OVER_PRECISION // enables use of reciprocals (1/x etc) - not faster on ESP32 // #define FFT_SQRT_APPROXIMATION // enables "quake3" style inverse sqrt - slower on ESP32 // Below options are forcing ArduinoFFT to use sqrtf() instead of sqrt() -#define sqrt(x) sqrtf(x) // little hack that reduces FFT time by 10-50% on ESP32 -#define sqrt_internal sqrtf // see https://github.com/kosme/arduinoFFT/pull/83 - -#include - -/* Create FFT object with weighing factor storage */ -static ArduinoFFT FFT = ArduinoFFT( vReal, vImag, samplesFFT, SAMPLE_RATE, true); +// #define sqrt_internal sqrtf // see https://github.com/kosme/arduinoFFT/pull/83 - since v2.0.0 this must be done in build_flags +#include // FFT object is created in FFTcode // Helper functions // compute average of several FFT result bins @@ -226,6 +221,18 @@ void FFTcode(void * parameter) { DEBUGSR_PRINT("FFT started on core: "); DEBUGSR_PRINTLN(xPortGetCoreID()); + // allocate FFT buffers on first call + if (vReal == nullptr) vReal = (float*) calloc(sizeof(float), samplesFFT); + if (vImag == nullptr) vImag = (float*) calloc(sizeof(float), samplesFFT); + if ((vReal == nullptr) || (vImag == nullptr)) { + // something went wrong + if (vReal) free(vReal); vReal = nullptr; + if (vImag) free(vImag); vImag = nullptr; + return; + } + // Create FFT object with weighing factor storage + ArduinoFFT FFT = ArduinoFFT( vReal, vImag, samplesFFT, SAMPLE_RATE, true); + // see https://www.freertos.org/vtaskdelayuntil.html const TickType_t xFrequency = FFT_MIN_CYCLE * portTICK_PERIOD_MS; @@ -247,6 +254,7 @@ void FFTcode(void * parameter) // get a fresh batch of samples from I2S if (audioSource) audioSource->getSamples(vReal, samplesFFT); + memset(vImag, 0, samplesFFT * sizeof(float)); // set imaginary parts to 0 #if defined(WLED_DEBUG) || defined(SR_DEBUG) if (start < esp_timer_get_time()) { // filter out overflows @@ -265,8 +273,6 @@ void FFTcode(void * parameter) // find highest sample in the batch float maxSample = 0.0f; // max sample from FFT batch for (int i=0; i < samplesFFT; i++) { - // set imaginary parts to 0 - vImag[i] = 0; // pick our our current mic sample - we take the max value from all samples that go into FFT if ((vReal[i] <= (INT16_MAX - 1024)) && (vReal[i] >= (INT16_MIN + 1024))) //skip extreme values - normally these are artefacts if (fabsf((float)vReal[i]) > maxSample) maxSample = fabsf((float)vReal[i]); @@ -297,7 +303,7 @@ void FFTcode(void * parameter) #endif } else { // noise gate closed - only clear results as FFT was skipped. MIC samples are still valid when we do this. - memset(vReal, 0, sizeof(vReal)); + memset(vReal, 0, samplesFFT * sizeof(float)); FFT_MajorPeak = 1; FFT_Magnitude = 0.001; } From 26a47537f98f06dc9645e7eaf16016d349c2b297 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 22 Oct 2024 15:15:14 +0200 Subject: [PATCH 090/234] AR memory optimization - part 2 shorten strings in UI script - saves a few hundred bytes on RAM --- usermods/audioreactive/audio_reactive.h | 74 +++++++++++++------------ 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index 1a91c333f..ad449fc83 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -1885,57 +1885,59 @@ class AudioReactive : public Usermod { } - void appendConfigData() override + void appendConfigData(Print& uiScript) override { -#ifdef ARDUINO_ARCH_ESP32 - oappend(SET_F("dd=addDropdown('AudioReactive','digitalmic:type');")); + uiScript.print(F("ux='AudioReactive';")); // ux = shortcut for Audioreactive - fingers crossed that "ux" isn't already used as JS var, html post parameter or css style +#ifdef ARDUINO_ARCH_ESP32 + uiScript.print(F("uxp=ux+':digitalmic:pin[]';")); // uxp = shortcut for AudioReactive:digitalmic:pin[] + uiScript.print(F("dd=addDropdown(ux,'digitalmic:type');")); #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) - oappend(SET_F("addOption(dd,'Generic Analog',0);")); + uiScript.print(F("addOption(dd,'Generic Analog',0);")); #endif - oappend(SET_F("addOption(dd,'Generic I2S',1);")); - oappend(SET_F("addOption(dd,'ES7243',2);")); - oappend(SET_F("addOption(dd,'SPH0654',3);")); - oappend(SET_F("addOption(dd,'Generic I2S with Mclk',4);")); + uiScript.print(F("addOption(dd,'Generic I2S',1);")); + uiScript.print(F("addOption(dd,'ES7243',2);")); + uiScript.print(F("addOption(dd,'SPH0654',3);")); + uiScript.print(F("addOption(dd,'Generic I2S with Mclk',4);")); #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) - oappend(SET_F("addOption(dd,'Generic I2S PDM',5);")); + uiScript.print(F("addOption(dd,'Generic I2S PDM',5);")); #endif - oappend(SET_F("addOption(dd,'ES8388',6);")); + uiScript.print(F("addOption(dd,'ES8388',6);")); - oappend(SET_F("dd=addDropdown('AudioReactive','config:AGC');")); - oappend(SET_F("addOption(dd,'Off',0);")); - oappend(SET_F("addOption(dd,'Normal',1);")); - oappend(SET_F("addOption(dd,'Vivid',2);")); - oappend(SET_F("addOption(dd,'Lazy',3);")); + uiScript.print(F("dd=addDropdown(ux,'config:AGC');")); + uiScript.print(F("addOption(dd,'Off',0);")); + uiScript.print(F("addOption(dd,'Normal',1);")); + uiScript.print(F("addOption(dd,'Vivid',2);")); + uiScript.print(F("addOption(dd,'Lazy',3);")); - oappend(SET_F("dd=addDropdown('AudioReactive','dynamics:limiter');")); - oappend(SET_F("addOption(dd,'Off',0);")); - oappend(SET_F("addOption(dd,'On',1);")); - oappend(SET_F("addInfo('AudioReactive:dynamics:limiter',0,' On ');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('AudioReactive:dynamics:rise',1,'ms (♪ effects only)');")); - oappend(SET_F("addInfo('AudioReactive:dynamics:fall',1,'ms (♪ effects only)');")); + uiScript.print(F("dd=addDropdown(ux,'dynamics:limiter');")); + uiScript.print(F("addOption(dd,'Off',0);")); + uiScript.print(F("addOption(dd,'On',1);")); + uiScript.print(F("addInfo(ux+':dynamics:limiter',0,' On ');")); // 0 is field type, 1 is actual field + uiScript.print(F("addInfo(ux+':dynamics:rise',1,'ms (♪ effects only)');")); + uiScript.print(F("addInfo(ux+':dynamics:fall',1,'ms (♪ effects only)');")); - oappend(SET_F("dd=addDropdown('AudioReactive','frequency:scale');")); - oappend(SET_F("addOption(dd,'None',0);")); - oappend(SET_F("addOption(dd,'Linear (Amplitude)',2);")); - oappend(SET_F("addOption(dd,'Square Root (Energy)',3);")); - oappend(SET_F("addOption(dd,'Logarithmic (Loudness)',1);")); + uiScript.print(F("dd=addDropdown(ux,'frequency:scale');")); + uiScript.print(F("addOption(dd,'None',0);")); + uiScript.print(F("addOption(dd,'Linear (Amplitude)',2);")); + uiScript.print(F("addOption(dd,'Square Root (Energy)',3);")); + uiScript.print(F("addOption(dd,'Logarithmic (Loudness)',1);")); #endif - oappend(SET_F("dd=addDropdown('AudioReactive','sync:mode');")); - oappend(SET_F("addOption(dd,'Off',0);")); + uiScript.print(F("dd=addDropdown(ux,'sync:mode');")); + uiScript.print(F("addOption(dd,'Off',0);")); #ifdef ARDUINO_ARCH_ESP32 - oappend(SET_F("addOption(dd,'Send',1);")); + uiScript.print(F("addOption(dd,'Send',1);")); #endif - oappend(SET_F("addOption(dd,'Receive',2);")); + uiScript.print(F("addOption(dd,'Receive',2);")); #ifdef ARDUINO_ARCH_ESP32 - oappend(SET_F("addInfo('AudioReactive:digitalmic:type',1,'requires reboot!');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',0,'sd/data/dout','I2S SD');")); - oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',1,'ws/clk/lrck','I2S WS');")); - oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',2,'sck/bclk','I2S SCK');")); + uiScript.print(F("addInfo(ux+':digitalmic:type',1,'requires reboot!');")); // 0 is field type, 1 is actual field + uiScript.print(F("addInfo(uxp,0,'sd/data/dout','I2S SD');")); + uiScript.print(F("addInfo(uxp,1,'ws/clk/lrck','I2S WS');")); + uiScript.print(F("addInfo(uxp,2,'sck/bclk','I2S SCK');")); #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) - oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',3,'only use -1, 0, 1 or 3','I2S MCLK');")); + uiScript.print(F("addInfo(uxp,3,'only use -1, 0, 1 or 3','I2S MCLK');")); #else - oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',3,'master clock','I2S MCLK');")); + uiScript.print(F("addInfo(uxp,3,'master clock','I2S MCLK');")); #endif #endif } From 6d1126b8aa123ebf351bb73b2618ccfcb9199682 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 22 Oct 2024 16:19:46 +0200 Subject: [PATCH 091/234] Update audioreactive readme.md added `-D sqrt_internal=sqrtf` -> needed for good performance --- usermods/audioreactive/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usermods/audioreactive/readme.md b/usermods/audioreactive/readme.md index 4668ca881..aad269c67 100644 --- a/usermods/audioreactive/readme.md +++ b/usermods/audioreactive/readme.md @@ -30,7 +30,7 @@ There are however plans to create a lightweight audioreactive for the 8266, with ### using latest _arduinoFFT_ library version 2.x The latest arduinoFFT release version should be used for audioreactive. -* `build_flags` = `-D USERMOD_AUDIOREACTIVE` +* `build_flags` = `-D USERMOD_AUDIOREACTIVE -D sqrt_internal=sqrtf` * `lib_deps`= `kosme/arduinoFFT @ 2.0.1` ## Configuration From 2a094883ad7b8d59630d88733c0df1ee43969811 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Fri, 27 Sep 2024 22:33:20 -0400 Subject: [PATCH 092/234] Better oappend shim on ESP8266 Detect IRAM pointers if we can't be sure. --- wled00/fcn_declare.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 71b00599c..d44ed43a0 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -324,6 +324,10 @@ class Usermod { protected: // Shim for oappend(), which used to exist in utils.cpp template static inline void oappend(const T& t) { oappend_shim->print(t); }; +#ifdef ESP8266 + // Handle print(PSTR()) without crashing by detecting PROGMEM strings + static void oappend(const char* c) { if ((intptr_t) c >= 0x40000000) oappend_shim->print(FPSTR(c)); else oappend_shim->print(c); }; +#endif }; class UsermodManager { From 2bb2caf2d2ae2d06d7dd45be6e898e3b731fbcf7 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Wed, 23 Oct 2024 19:47:44 -0400 Subject: [PATCH 093/234] Enable NON32XFER_HANDLER on ESP8266 This is a platform feature that asks forgiveness for PROGMEM misuse: it adds a handler such that incorrectly used PROGMEM will work without crashing, just really, *really* inefficiently. Given that most of our real-world use cases for PROGMEM strings are relatively infrequent text calls, we can err on the side of developer convenience and address performance problems if and when they arise. --- platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio.ini b/platformio.ini index b130b687c..9628722aa 100644 --- a/platformio.ini +++ b/platformio.ini @@ -197,6 +197,7 @@ build_flags = ; decrease code cache size and increase IRAM to fit all pixel functions -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48 ;; in case of linker errors like "section `.text1' will not fit in region `iram1_0_seg'" ; -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED ;; (experimental) adds some extra heap, but may cause slowdown + -D NON32XFER_HANDLER ;; ask forgiveness for PROGMEM misuse lib_deps = #https://github.com/lorol/LITTLEFS.git From b3b326738c14808ed2cac069a70bf9ea18bccd20 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Wed, 23 Oct 2024 19:58:52 -0400 Subject: [PATCH 094/234] Fix incorrect SET_F calls Replace with F() or PSTR() as appropriate. --- wled00/wled_server.cpp | 8 ++++---- wled00/xml.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index 958b51330..e8cbb41ae 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -193,12 +193,12 @@ void createEditHandler(bool enable) { editHandler = &server.addHandler(new SPIFFSEditor("","",WLED_FS));//http_username,http_password)); #endif #else - editHandler = &server.on(SET_F("/edit"), HTTP_GET, [](AsyncWebServerRequest *request){ + editHandler = &server.on(F("/edit"), HTTP_GET, [](AsyncWebServerRequest *request){ serveMessage(request, 501, FPSTR(s_notimplemented), F("The FS editor is disabled in this build."), 254); }); #endif } else { - editHandler = &server.on(SET_F("/edit"), HTTP_ANY, [](AsyncWebServerRequest *request){ + editHandler = &server.on(F("/edit"), HTTP_ANY, [](AsyncWebServerRequest *request){ serveMessage(request, 401, FPSTR(s_accessdenied), FPSTR(s_unlock_cfg), 254); }); } @@ -427,11 +427,11 @@ void initServer() #ifdef WLED_ENABLE_DMX - server.on(SET_F("/dmxmap"), HTTP_GET, [](AsyncWebServerRequest *request){ + server.on(F("/dmxmap"), HTTP_GET, [](AsyncWebServerRequest *request){ request->send_P(200, FPSTR(CONTENT_TYPE_HTML), PAGE_dmxmap , dmxProcessor); }); #else - server.on(SET_F("/dmxmap"), HTTP_GET, [](AsyncWebServerRequest *request){ + server.on(F("/dmxmap"), HTTP_GET, [](AsyncWebServerRequest *request){ serveMessage(request, 501, FPSTR(s_notimplemented), F("DMX support is not enabled in this build."), 254); }); #endif diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 1ac22c9ce..6d1ff2f86 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -227,7 +227,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]); #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) - if (Network.isEthernet()) strcat_P(s ,SET_F(" (Ethernet)")); + if (Network.isEthernet()) strcat_P(s ,PSTR(" (Ethernet)")); #endif printSetClassElementHTML(settingsScript,PSTR("sip"),0,s); } else From 7d067d8c305c3c6f397b6863f6849659a0aadd24 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Wed, 23 Oct 2024 20:00:22 -0400 Subject: [PATCH 095/234] Replace SET_F with F in usermods Since oappend() is now strongly typed, pass the correct type. This is a step towards removing the extra shim logic on ESP8266. --- .../Animated_Staircase/Animated_Staircase.h | 8 ++--- usermods/BME68X_v2/usermod_bme68x.h | 20 +++++------ usermods/Battery/usermod_v2_Battery.h | 34 +++++++++---------- usermods/EXAMPLE_v2/usermod_v2_example.h | 10 +++--- .../usermod_internal_temperature.h | 6 ++-- .../usermod_PIR_sensor_switch.h | 4 +-- usermods/ST7789_display/ST7789_display.h | 8 ++--- usermods/Temperature/usermod_temperature.h | 8 ++--- usermods/boblight/boblight.h | 16 ++++----- usermods/multi_relay/usermod_multi_relay.h | 10 +++--- usermods/pixels_dice_tray/pixels_dice_tray.h | 22 ++++++------ usermods/sht/usermod_sht.h | 24 ++++++------- .../usermod_v2_four_line_display_ALT.h | 30 ++++++++-------- .../usermod_v2_rotary_encoder_ui_ALT.h | 4 +-- .../usermod_v2_word_clock.h | 4 +-- usermods/wireguard/wireguard.h | 14 ++++---- 16 files changed, 111 insertions(+), 111 deletions(-) diff --git a/usermods/Animated_Staircase/Animated_Staircase.h b/usermods/Animated_Staircase/Animated_Staircase.h index d1ec9bb7f..54a9b3331 100644 --- a/usermods/Animated_Staircase/Animated_Staircase.h +++ b/usermods/Animated_Staircase/Animated_Staircase.h @@ -425,10 +425,10 @@ class Animated_Staircase : public Usermod { } void appendConfigData() { - //oappend(SET_F("dd=addDropdown('staircase','selectfield');")); - //oappend(SET_F("addOption(dd,'1st value',0);")); - //oappend(SET_F("addOption(dd,'2nd value',1);")); - //oappend(SET_F("addInfo('staircase:selectfield',1,'additional info');")); // 0 is field type, 1 is actual field + //oappend(F("dd=addDropdown('staircase','selectfield');")); + //oappend(F("addOption(dd,'1st value',0);")); + //oappend(F("addOption(dd,'2nd value',1);")); + //oappend(F("addInfo('staircase:selectfield',1,'additional info');")); // 0 is field type, 1 is actual field } diff --git a/usermods/BME68X_v2/usermod_bme68x.h b/usermods/BME68X_v2/usermod_bme68x.h index 8e360515a..aca24d0a2 100644 --- a/usermods/BME68X_v2/usermod_bme68x.h +++ b/usermods/BME68X_v2/usermod_bme68x.h @@ -767,22 +767,22 @@ void UsermodBME68X::appendConfigData() { // snprintf_P(charbuffer, 127, PSTR("addInfo('%s:%s',1,'*) Set to minus to deactivate (all sensors)');"), UMOD_NAME, _nameTemp); oappend(charbuffer); /* Dropdown for Celsius/Fahrenheit*/ - oappend(SET_F("dd=addDropdown('")); + oappend(F("dd=addDropdown('")); oappend(UMOD_NAME); - oappend(SET_F("','")); + oappend(F("','")); oappend(_nameTempScale); - oappend(SET_F("');")); - oappend(SET_F("addOption(dd,'Celsius',0);")); - oappend(SET_F("addOption(dd,'Fahrenheit',1);")); + oappend(F("');")); + oappend(F("addOption(dd,'Celsius',0);")); + oappend(F("addOption(dd,'Fahrenheit',1);")); /* i²C Address*/ - oappend(SET_F("dd=addDropdown('")); + oappend(F("dd=addDropdown('")); oappend(UMOD_NAME); - oappend(SET_F("','")); + oappend(F("','")); oappend(_nameI2CAdr); - oappend(SET_F("');")); - oappend(SET_F("addOption(dd,'0x76',0x76);")); - oappend(SET_F("addOption(dd,'0x77',0x77);")); + oappend(F("');")); + oappend(F("addOption(dd,'0x76',0x76);")); + oappend(F("addOption(dd,'0x77',0x77);")); } /** diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index e91de850c..b36c5f4d6 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -478,29 +478,29 @@ class UsermodBattery : public Usermod void appendConfigData() { // Total: 462 Bytes - oappend(SET_F("td=addDropdown('Battery','type');")); // 34 Bytes - oappend(SET_F("addOption(td,'Unkown','0');")); // 28 Bytes - oappend(SET_F("addOption(td,'LiPo','1');")); // 26 Bytes - oappend(SET_F("addOption(td,'LiOn','2');")); // 26 Bytes - oappend(SET_F("addInfo('Battery:type',1,'requires reboot');")); // 81 Bytes - oappend(SET_F("addInfo('Battery:min-voltage',1,'v');")); // 38 Bytes - oappend(SET_F("addInfo('Battery:max-voltage',1,'v');")); // 38 Bytes - oappend(SET_F("addInfo('Battery:interval',1,'ms');")); // 36 Bytes - oappend(SET_F("addInfo('Battery:HA-discovery',1,'');")); // 38 Bytes - oappend(SET_F("addInfo('Battery:auto-off:threshold',1,'%');")); // 45 Bytes - oappend(SET_F("addInfo('Battery:indicator:threshold',1,'%');")); // 46 Bytes - oappend(SET_F("addInfo('Battery:indicator:duration',1,'s');")); // 45 Bytes + oappend(F("td=addDropdown('Battery','type');")); // 34 Bytes + oappend(F("addOption(td,'Unkown','0');")); // 28 Bytes + oappend(F("addOption(td,'LiPo','1');")); // 26 Bytes + oappend(F("addOption(td,'LiOn','2');")); // 26 Bytes + oappend(F("addInfo('Battery:type',1,'requires reboot');")); // 81 Bytes + oappend(F("addInfo('Battery:min-voltage',1,'v');")); // 38 Bytes + oappend(F("addInfo('Battery:max-voltage',1,'v');")); // 38 Bytes + oappend(F("addInfo('Battery:interval',1,'ms');")); // 36 Bytes + oappend(F("addInfo('Battery:HA-discovery',1,'');")); // 38 Bytes + oappend(F("addInfo('Battery:auto-off:threshold',1,'%');")); // 45 Bytes + oappend(F("addInfo('Battery:indicator:threshold',1,'%');")); // 46 Bytes + oappend(F("addInfo('Battery:indicator:duration',1,'s');")); // 45 Bytes // this option list would exeed the oappend() buffer // a list of all presets to select one from - // oappend(SET_F("bd=addDropdown('Battery:low-power-indicator', 'preset');")); - // the loop generates: oappend(SET_F("addOption(bd, 'preset name', preset id);")); + // oappend(F("bd=addDropdown('Battery:low-power-indicator', 'preset');")); + // the loop generates: oappend(F("addOption(bd, 'preset name', preset id);")); // for(int8_t i=1; i < 42; i++) { - // oappend(SET_F("addOption(bd, 'Preset#")); + // oappend(F("addOption(bd, 'Preset#")); // oappendi(i); - // oappend(SET_F("',")); + // oappend(F("',")); // oappendi(i); - // oappend(SET_F(");")); + // oappend(F(");")); // } } diff --git a/usermods/EXAMPLE_v2/usermod_v2_example.h b/usermods/EXAMPLE_v2/usermod_v2_example.h index 3d562b585..df05f3e3d 100644 --- a/usermods/EXAMPLE_v2/usermod_v2_example.h +++ b/usermods/EXAMPLE_v2/usermod_v2_example.h @@ -287,11 +287,11 @@ class MyExampleUsermod : public Usermod { */ void appendConfigData() override { - oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":great")); oappend(SET_F("',1,'(this is a great config value)');")); - oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":testString")); oappend(SET_F("',1,'enter any string you want');")); - oappend(SET_F("dd=addDropdown('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F("','testInt');")); - oappend(SET_F("addOption(dd,'Nothing',0);")); - oappend(SET_F("addOption(dd,'Everything',42);")); + oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":great")); oappend(F("',1,'(this is a great config value)');")); + oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":testString")); oappend(F("',1,'enter any string you want');")); + oappend(F("dd=addDropdown('")); oappend(String(FPSTR(_name)).c_str()); oappend(F("','testInt');")); + oappend(F("addOption(dd,'Nothing',0);")); + oappend(F("addOption(dd,'Everything',42);")); } diff --git a/usermods/Internal_Temperature_v2/usermod_internal_temperature.h b/usermods/Internal_Temperature_v2/usermod_internal_temperature.h index 2236bfeab..c24b4c628 100644 --- a/usermods/Internal_Temperature_v2/usermod_internal_temperature.h +++ b/usermods/Internal_Temperature_v2/usermod_internal_temperature.h @@ -149,11 +149,11 @@ public: void appendConfigData() { // Display 'ms' next to the 'Loop Interval' setting - oappend(SET_F("addInfo('Internal Temperature:Loop Interval', 1, 'ms');")); + oappend(F("addInfo('Internal Temperature:Loop Interval', 1, 'ms');")); // Display '°C' next to the 'Activation Threshold' setting - oappend(SET_F("addInfo('Internal Temperature:Activation Threshold', 1, '°C');")); + oappend(F("addInfo('Internal Temperature:Activation Threshold', 1, '°C');")); // Display '0 = Disabled' next to the 'Preset To Activate' setting - oappend(SET_F("addInfo('Internal Temperature:Preset To Activate', 1, '0 = unused');")); + oappend(F("addInfo('Internal Temperature:Preset To Activate', 1, '0 = unused');")); } bool readFromConfig(JsonObject &root) diff --git a/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h b/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h index 29070cf84..0deda181c 100644 --- a/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h +++ b/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h @@ -511,8 +511,8 @@ void PIRsensorSwitch::addToConfig(JsonObject &root) void PIRsensorSwitch::appendConfigData() { - oappend(SET_F("addInfo('PIRsensorSwitch:HA-discovery',1,'HA=Home Assistant');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('PIRsensorSwitch:override',1,'Cancel timer on change');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('PIRsensorSwitch:HA-discovery',1,'HA=Home Assistant');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('PIRsensorSwitch:override',1,'Cancel timer on change');")); // 0 is field type, 1 is actual field for (int i = 0; i < PIR_SENSOR_MAX_SENSORS; i++) { char str[128]; sprintf_P(str, PSTR("addInfo('PIRsensorSwitch:pin[]',%d,'','#%d');"), i, i); diff --git a/usermods/ST7789_display/ST7789_display.h b/usermods/ST7789_display/ST7789_display.h index 0dbada382..65f4cae5d 100644 --- a/usermods/ST7789_display/ST7789_display.h +++ b/usermods/ST7789_display/ST7789_display.h @@ -377,10 +377,10 @@ class St7789DisplayUsermod : public Usermod { void appendConfigData() override { - oappend(SET_F("addInfo('ST7789:pin[]',0,'','SPI CS');")); - oappend(SET_F("addInfo('ST7789:pin[]',1,'','SPI DC');")); - oappend(SET_F("addInfo('ST7789:pin[]',2,'','SPI RST');")); - oappend(SET_F("addInfo('ST7789:pin[]',3,'','SPI BL');")); + oappend(F("addInfo('ST7789:pin[]',0,'','SPI CS');")); + oappend(F("addInfo('ST7789:pin[]',1,'','SPI DC');")); + oappend(F("addInfo('ST7789:pin[]',2,'','SPI RST');")); + oappend(F("addInfo('ST7789:pin[]',3,'','SPI BL');")); } /* diff --git a/usermods/Temperature/usermod_temperature.h b/usermods/Temperature/usermod_temperature.h index ad755eaee..178bc05a0 100644 --- a/usermods/Temperature/usermod_temperature.h +++ b/usermods/Temperature/usermod_temperature.h @@ -435,10 +435,10 @@ bool UsermodTemperature::readFromConfig(JsonObject &root) { } void UsermodTemperature::appendConfigData() { - oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_parasite)).c_str()); - oappend(SET_F("',1,'(if no Vcc connected)');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_parasitePin)).c_str()); - oappend(SET_F("',1,'(for external MOSFET)');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":")); oappend(String(FPSTR(_parasite)).c_str()); + oappend(F("',1,'(if no Vcc connected)');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":")); oappend(String(FPSTR(_parasitePin)).c_str()); + oappend(F("',1,'(for external MOSFET)');")); // 0 is field type, 1 is actual field } float UsermodTemperature::getTemperature() { diff --git a/usermods/boblight/boblight.h b/usermods/boblight/boblight.h index 916f7da98..b04b78fac 100644 --- a/usermods/boblight/boblight.h +++ b/usermods/boblight/boblight.h @@ -305,14 +305,14 @@ class BobLightUsermod : public Usermod { } void appendConfigData() override { - //oappend(SET_F("dd=addDropdown('usermod','selectfield');")); - //oappend(SET_F("addOption(dd,'1st value',0);")); - //oappend(SET_F("addOption(dd,'2nd value',1);")); - oappend(SET_F("addInfo('BobLight:top',1,'LEDs');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('BobLight:bottom',1,'LEDs');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('BobLight:left',1,'LEDs');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('BobLight:right',1,'LEDs');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('BobLight:pct',1,'Depth of scan [%]');")); // 0 is field type, 1 is actual field + //oappend(F("dd=addDropdown('usermod','selectfield');")); + //oappend(F("addOption(dd,'1st value',0);")); + //oappend(F("addOption(dd,'2nd value',1);")); + oappend(F("addInfo('BobLight:top',1,'LEDs');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('BobLight:bottom',1,'LEDs');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('BobLight:left',1,'LEDs');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('BobLight:right',1,'LEDs');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('BobLight:pct',1,'Depth of scan [%]');")); // 0 is field type, 1 is actual field } void addToConfig(JsonObject& root) override { diff --git a/usermods/multi_relay/usermod_multi_relay.h b/usermods/multi_relay/usermod_multi_relay.h index 33a6cf85e..c4446c7a2 100644 --- a/usermods/multi_relay/usermod_multi_relay.h +++ b/usermods/multi_relay/usermod_multi_relay.h @@ -264,7 +264,7 @@ void MultiRelay::handleOffTimer() { void MultiRelay::InitHtmlAPIHandle() { // https://github.com/me-no-dev/ESPAsyncWebServer DEBUG_PRINTLN(F("Relays: Initialize HTML API")); - server.on(SET_F("/relays"), HTTP_GET, [this](AsyncWebServerRequest *request) { + server.on(F("/relays"), HTTP_GET, [this](AsyncWebServerRequest *request) { DEBUG_PRINTLN(F("Relays: HTML API")); String janswer; String error = ""; @@ -765,10 +765,10 @@ void MultiRelay::addToConfig(JsonObject &root) { } void MultiRelay::appendConfigData() { - oappend(SET_F("addInfo('MultiRelay:PCF8574-address',1,'(not hex!)');")); - oappend(SET_F("addInfo('MultiRelay:broadcast-sec',1,'(MQTT message)');")); - //oappend(SET_F("addInfo('MultiRelay:relay-0:pin',1,'(use -1 for PCF8574)');")); - oappend(SET_F("d.extra.push({'MultiRelay':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});")); + oappend(F("addInfo('MultiRelay:PCF8574-address',1,'(not hex!)');")); + oappend(F("addInfo('MultiRelay:broadcast-sec',1,'(MQTT message)');")); + //oappend(F("addInfo('MultiRelay:relay-0:pin',1,'(use -1 for PCF8574)');")); + oappend(F("d.extra.push({'MultiRelay':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});")); } /** diff --git a/usermods/pixels_dice_tray/pixels_dice_tray.h b/usermods/pixels_dice_tray/pixels_dice_tray.h index a1e45ba33..61348ebb8 100644 --- a/usermods/pixels_dice_tray/pixels_dice_tray.h +++ b/usermods/pixels_dice_tray/pixels_dice_tray.h @@ -387,23 +387,23 @@ class PixelsDiceTrayUsermod : public Usermod { // To work around this, add info text to the end of the preceding item. // // See addInfo in wled00/data/settings_um.htm for details on what this function does. - oappend(SET_F( + oappend(F( "addInfo('DiceTray:ble_scan_duration',1,'

Set to \"*\" to " "connect to any die.
Leave Blank to disable.

Saving will replace \"*\" with die names.','');")); #if USING_TFT_DISPLAY - oappend(SET_F("ddr=addDropdown('DiceTray','rotation');")); - oappend(SET_F("addOption(ddr,'0 deg',0);")); - oappend(SET_F("addOption(ddr,'90 deg',1);")); - oappend(SET_F("addOption(ddr,'180 deg',2);")); - oappend(SET_F("addOption(ddr,'270 deg',3);")); - oappend(SET_F( + oappend(F("ddr=addDropdown('DiceTray','rotation');")); + oappend(F("addOption(ddr,'0 deg',0);")); + oappend(F("addOption(ddr,'90 deg',1);")); + oappend(F("addOption(ddr,'180 deg',2);")); + oappend(F("addOption(ddr,'270 deg',3);")); + oappend(F( "addInfo('DiceTray:rotation',1,'
DO NOT CHANGE " "SPI PINS.
CHANGES ARE IGNORED.','');")); - oappend(SET_F("addInfo('TFT:pin[]',0,'','SPI CS');")); - oappend(SET_F("addInfo('TFT:pin[]',1,'','SPI DC');")); - oappend(SET_F("addInfo('TFT:pin[]',2,'','SPI RST');")); - oappend(SET_F("addInfo('TFT:pin[]',3,'','SPI BL');")); + oappend(F("addInfo('TFT:pin[]',0,'','SPI CS');")); + oappend(F("addInfo('TFT:pin[]',1,'','SPI DC');")); + oappend(F("addInfo('TFT:pin[]',2,'','SPI RST');")); + oappend(F("addInfo('TFT:pin[]',3,'','SPI BL');")); #endif } diff --git a/usermods/sht/usermod_sht.h b/usermods/sht/usermod_sht.h index c6e17221b..f10c78a25 100644 --- a/usermods/sht/usermod_sht.h +++ b/usermods/sht/usermod_sht.h @@ -310,22 +310,22 @@ void ShtUsermod::onMqttConnect(bool sessionPresent) { * @return void */ void ShtUsermod::appendConfigData() { - oappend(SET_F("dd=addDropdown('")); + oappend(F("dd=addDropdown('")); oappend(_name); - oappend(SET_F("','")); + oappend(F("','")); oappend(_shtType); - oappend(SET_F("');")); - oappend(SET_F("addOption(dd,'SHT30',0);")); - oappend(SET_F("addOption(dd,'SHT31',1);")); - oappend(SET_F("addOption(dd,'SHT35',2);")); - oappend(SET_F("addOption(dd,'SHT85',3);")); - oappend(SET_F("dd=addDropdown('")); + oappend(F("');")); + oappend(F("addOption(dd,'SHT30',0);")); + oappend(F("addOption(dd,'SHT31',1);")); + oappend(F("addOption(dd,'SHT35',2);")); + oappend(F("addOption(dd,'SHT85',3);")); + oappend(F("dd=addDropdown('")); oappend(_name); - oappend(SET_F("','")); + oappend(F("','")); oappend(_unitOfTemp); - oappend(SET_F("');")); - oappend(SET_F("addOption(dd,'Celsius',0);")); - oappend(SET_F("addOption(dd,'Fahrenheit',1);")); + oappend(F("');")); + oappend(F("addOption(dd,'Celsius',0);")); + oappend(F("addOption(dd,'Fahrenheit',1);")); } /** diff --git a/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h b/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h index dfab7e6ff..684dd86e4 100644 --- a/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h +++ b/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h @@ -1202,21 +1202,21 @@ void FourLineDisplayUsermod::onUpdateBegin(bool init) { //} void FourLineDisplayUsermod::appendConfigData() { - oappend(SET_F("dd=addDropdown('4LineDisplay','type');")); - oappend(SET_F("addOption(dd,'None',0);")); - oappend(SET_F("addOption(dd,'SSD1306',1);")); - oappend(SET_F("addOption(dd,'SH1106',2);")); - oappend(SET_F("addOption(dd,'SSD1306 128x64',3);")); - oappend(SET_F("addOption(dd,'SSD1305',4);")); - oappend(SET_F("addOption(dd,'SSD1305 128x64',5);")); - oappend(SET_F("addOption(dd,'SSD1309 128x64',9);")); - oappend(SET_F("addOption(dd,'SSD1306 SPI',6);")); - oappend(SET_F("addOption(dd,'SSD1306 SPI 128x64',7);")); - oappend(SET_F("addOption(dd,'SSD1309 SPI 128x64',8);")); - oappend(SET_F("addInfo('4LineDisplay:type',1,'
Change may require reboot','');")); - oappend(SET_F("addInfo('4LineDisplay:pin[]',0,'','SPI CS');")); - oappend(SET_F("addInfo('4LineDisplay:pin[]',1,'','SPI DC');")); - oappend(SET_F("addInfo('4LineDisplay:pin[]',2,'','SPI RST');")); + oappend(F("dd=addDropdown('4LineDisplay','type');")); + oappend(F("addOption(dd,'None',0);")); + oappend(F("addOption(dd,'SSD1306',1);")); + oappend(F("addOption(dd,'SH1106',2);")); + oappend(F("addOption(dd,'SSD1306 128x64',3);")); + oappend(F("addOption(dd,'SSD1305',4);")); + oappend(F("addOption(dd,'SSD1305 128x64',5);")); + oappend(F("addOption(dd,'SSD1309 128x64',9);")); + oappend(F("addOption(dd,'SSD1306 SPI',6);")); + oappend(F("addOption(dd,'SSD1306 SPI 128x64',7);")); + oappend(F("addOption(dd,'SSD1309 SPI 128x64',8);")); + oappend(F("addInfo('4LineDisplay:type',1,'
Change may require reboot','');")); + oappend(F("addInfo('4LineDisplay:pin[]',0,'','SPI CS');")); + oappend(F("addInfo('4LineDisplay:pin[]',1,'','SPI DC');")); + oappend(F("addInfo('4LineDisplay:pin[]',2,'','SPI RST');")); } /* diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h index 55715b7c7..383c1193e 100644 --- a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h @@ -1090,8 +1090,8 @@ void RotaryEncoderUIUsermod::addToConfig(JsonObject &root) { } void RotaryEncoderUIUsermod::appendConfigData() { - oappend(SET_F("addInfo('Rotary-Encoder:PCF8574-address',1,'(not hex!)');")); - oappend(SET_F("d.extra.push({'Rotary-Encoder':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});")); + oappend(F("addInfo('Rotary-Encoder:PCF8574-address',1,'(not hex!)');")); + oappend(F("d.extra.push({'Rotary-Encoder':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});")); } /** diff --git a/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h b/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h index b66be290a..7ecec08e5 100644 --- a/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h +++ b/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h @@ -433,8 +433,8 @@ class WordClockUsermod : public Usermod void appendConfigData() { - oappend(SET_F("addInfo('WordClockUsermod:ledOffset', 1, 'Number of LEDs before the letters');")); - oappend(SET_F("addInfo('WordClockUsermod:Norddeutsch', 1, 'Viertel vor instead of Dreiviertel');")); + oappend(F("addInfo('WordClockUsermod:ledOffset', 1, 'Number of LEDs before the letters');")); + oappend(F("addInfo('WordClockUsermod:Norddeutsch', 1, 'Viertel vor instead of Dreiviertel');")); } /* diff --git a/usermods/wireguard/wireguard.h b/usermods/wireguard/wireguard.h index 8c88d0001..8656a704a 100644 --- a/usermods/wireguard/wireguard.h +++ b/usermods/wireguard/wireguard.h @@ -54,13 +54,13 @@ class WireguardUsermod : public Usermod { } void appendConfigData() { - oappend(SET_F("addInfo('WireGuard:host',1,'Server Hostname');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('WireGuard:port',1,'Server Port');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('WireGuard:ip',1,'Device IP');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('WireGuard:psk',1,'Pre Shared Key (optional)');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('WireGuard:pem',1,'Private Key');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('WireGuard:pub',1,'Public Key');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('WireGuard:tz',1,'POSIX timezone string');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('WireGuard:host',1,'Server Hostname');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('WireGuard:port',1,'Server Port');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('WireGuard:ip',1,'Device IP');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('WireGuard:psk',1,'Pre Shared Key (optional)');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('WireGuard:pem',1,'Private Key');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('WireGuard:pub',1,'Public Key');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('WireGuard:tz',1,'POSIX timezone string');")); // 0 is field type, 1 is actual field } void addToConfig(JsonObject& root) { From 2e01fe0b5bf853f068fc255896994b324a56c2d8 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Wed, 23 Oct 2024 21:34:35 -0400 Subject: [PATCH 096/234] Revert "Replace SET_F with F in usermods" This reverts commit 7d067d8c305c3c6f397b6863f6849659a0aadd24. --- .../Animated_Staircase/Animated_Staircase.h | 8 ++--- usermods/BME68X_v2/usermod_bme68x.h | 20 +++++------ usermods/Battery/usermod_v2_Battery.h | 34 +++++++++---------- usermods/EXAMPLE_v2/usermod_v2_example.h | 10 +++--- .../usermod_internal_temperature.h | 6 ++-- .../usermod_PIR_sensor_switch.h | 4 +-- usermods/ST7789_display/ST7789_display.h | 8 ++--- usermods/Temperature/usermod_temperature.h | 8 ++--- usermods/boblight/boblight.h | 16 ++++----- usermods/multi_relay/usermod_multi_relay.h | 10 +++--- usermods/pixels_dice_tray/pixels_dice_tray.h | 22 ++++++------ usermods/sht/usermod_sht.h | 24 ++++++------- .../usermod_v2_four_line_display_ALT.h | 30 ++++++++-------- .../usermod_v2_rotary_encoder_ui_ALT.h | 4 +-- .../usermod_v2_word_clock.h | 4 +-- usermods/wireguard/wireguard.h | 14 ++++---- 16 files changed, 111 insertions(+), 111 deletions(-) diff --git a/usermods/Animated_Staircase/Animated_Staircase.h b/usermods/Animated_Staircase/Animated_Staircase.h index 54a9b3331..d1ec9bb7f 100644 --- a/usermods/Animated_Staircase/Animated_Staircase.h +++ b/usermods/Animated_Staircase/Animated_Staircase.h @@ -425,10 +425,10 @@ class Animated_Staircase : public Usermod { } void appendConfigData() { - //oappend(F("dd=addDropdown('staircase','selectfield');")); - //oappend(F("addOption(dd,'1st value',0);")); - //oappend(F("addOption(dd,'2nd value',1);")); - //oappend(F("addInfo('staircase:selectfield',1,'additional info');")); // 0 is field type, 1 is actual field + //oappend(SET_F("dd=addDropdown('staircase','selectfield');")); + //oappend(SET_F("addOption(dd,'1st value',0);")); + //oappend(SET_F("addOption(dd,'2nd value',1);")); + //oappend(SET_F("addInfo('staircase:selectfield',1,'additional info');")); // 0 is field type, 1 is actual field } diff --git a/usermods/BME68X_v2/usermod_bme68x.h b/usermods/BME68X_v2/usermod_bme68x.h index aca24d0a2..8e360515a 100644 --- a/usermods/BME68X_v2/usermod_bme68x.h +++ b/usermods/BME68X_v2/usermod_bme68x.h @@ -767,22 +767,22 @@ void UsermodBME68X::appendConfigData() { // snprintf_P(charbuffer, 127, PSTR("addInfo('%s:%s',1,'*) Set to minus to deactivate (all sensors)');"), UMOD_NAME, _nameTemp); oappend(charbuffer); /* Dropdown for Celsius/Fahrenheit*/ - oappend(F("dd=addDropdown('")); + oappend(SET_F("dd=addDropdown('")); oappend(UMOD_NAME); - oappend(F("','")); + oappend(SET_F("','")); oappend(_nameTempScale); - oappend(F("');")); - oappend(F("addOption(dd,'Celsius',0);")); - oappend(F("addOption(dd,'Fahrenheit',1);")); + oappend(SET_F("');")); + oappend(SET_F("addOption(dd,'Celsius',0);")); + oappend(SET_F("addOption(dd,'Fahrenheit',1);")); /* i²C Address*/ - oappend(F("dd=addDropdown('")); + oappend(SET_F("dd=addDropdown('")); oappend(UMOD_NAME); - oappend(F("','")); + oappend(SET_F("','")); oappend(_nameI2CAdr); - oappend(F("');")); - oappend(F("addOption(dd,'0x76',0x76);")); - oappend(F("addOption(dd,'0x77',0x77);")); + oappend(SET_F("');")); + oappend(SET_F("addOption(dd,'0x76',0x76);")); + oappend(SET_F("addOption(dd,'0x77',0x77);")); } /** diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index b36c5f4d6..e91de850c 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -478,29 +478,29 @@ class UsermodBattery : public Usermod void appendConfigData() { // Total: 462 Bytes - oappend(F("td=addDropdown('Battery','type');")); // 34 Bytes - oappend(F("addOption(td,'Unkown','0');")); // 28 Bytes - oappend(F("addOption(td,'LiPo','1');")); // 26 Bytes - oappend(F("addOption(td,'LiOn','2');")); // 26 Bytes - oappend(F("addInfo('Battery:type',1,'requires reboot');")); // 81 Bytes - oappend(F("addInfo('Battery:min-voltage',1,'v');")); // 38 Bytes - oappend(F("addInfo('Battery:max-voltage',1,'v');")); // 38 Bytes - oappend(F("addInfo('Battery:interval',1,'ms');")); // 36 Bytes - oappend(F("addInfo('Battery:HA-discovery',1,'');")); // 38 Bytes - oappend(F("addInfo('Battery:auto-off:threshold',1,'%');")); // 45 Bytes - oappend(F("addInfo('Battery:indicator:threshold',1,'%');")); // 46 Bytes - oappend(F("addInfo('Battery:indicator:duration',1,'s');")); // 45 Bytes + oappend(SET_F("td=addDropdown('Battery','type');")); // 34 Bytes + oappend(SET_F("addOption(td,'Unkown','0');")); // 28 Bytes + oappend(SET_F("addOption(td,'LiPo','1');")); // 26 Bytes + oappend(SET_F("addOption(td,'LiOn','2');")); // 26 Bytes + oappend(SET_F("addInfo('Battery:type',1,'requires reboot');")); // 81 Bytes + oappend(SET_F("addInfo('Battery:min-voltage',1,'v');")); // 38 Bytes + oappend(SET_F("addInfo('Battery:max-voltage',1,'v');")); // 38 Bytes + oappend(SET_F("addInfo('Battery:interval',1,'ms');")); // 36 Bytes + oappend(SET_F("addInfo('Battery:HA-discovery',1,'');")); // 38 Bytes + oappend(SET_F("addInfo('Battery:auto-off:threshold',1,'%');")); // 45 Bytes + oappend(SET_F("addInfo('Battery:indicator:threshold',1,'%');")); // 46 Bytes + oappend(SET_F("addInfo('Battery:indicator:duration',1,'s');")); // 45 Bytes // this option list would exeed the oappend() buffer // a list of all presets to select one from - // oappend(F("bd=addDropdown('Battery:low-power-indicator', 'preset');")); - // the loop generates: oappend(F("addOption(bd, 'preset name', preset id);")); + // oappend(SET_F("bd=addDropdown('Battery:low-power-indicator', 'preset');")); + // the loop generates: oappend(SET_F("addOption(bd, 'preset name', preset id);")); // for(int8_t i=1; i < 42; i++) { - // oappend(F("addOption(bd, 'Preset#")); + // oappend(SET_F("addOption(bd, 'Preset#")); // oappendi(i); - // oappend(F("',")); + // oappend(SET_F("',")); // oappendi(i); - // oappend(F(");")); + // oappend(SET_F(");")); // } } diff --git a/usermods/EXAMPLE_v2/usermod_v2_example.h b/usermods/EXAMPLE_v2/usermod_v2_example.h index df05f3e3d..3d562b585 100644 --- a/usermods/EXAMPLE_v2/usermod_v2_example.h +++ b/usermods/EXAMPLE_v2/usermod_v2_example.h @@ -287,11 +287,11 @@ class MyExampleUsermod : public Usermod { */ void appendConfigData() override { - oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":great")); oappend(F("',1,'(this is a great config value)');")); - oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":testString")); oappend(F("',1,'enter any string you want');")); - oappend(F("dd=addDropdown('")); oappend(String(FPSTR(_name)).c_str()); oappend(F("','testInt');")); - oappend(F("addOption(dd,'Nothing',0);")); - oappend(F("addOption(dd,'Everything',42);")); + oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":great")); oappend(SET_F("',1,'(this is a great config value)');")); + oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":testString")); oappend(SET_F("',1,'enter any string you want');")); + oappend(SET_F("dd=addDropdown('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F("','testInt');")); + oappend(SET_F("addOption(dd,'Nothing',0);")); + oappend(SET_F("addOption(dd,'Everything',42);")); } diff --git a/usermods/Internal_Temperature_v2/usermod_internal_temperature.h b/usermods/Internal_Temperature_v2/usermod_internal_temperature.h index c24b4c628..2236bfeab 100644 --- a/usermods/Internal_Temperature_v2/usermod_internal_temperature.h +++ b/usermods/Internal_Temperature_v2/usermod_internal_temperature.h @@ -149,11 +149,11 @@ public: void appendConfigData() { // Display 'ms' next to the 'Loop Interval' setting - oappend(F("addInfo('Internal Temperature:Loop Interval', 1, 'ms');")); + oappend(SET_F("addInfo('Internal Temperature:Loop Interval', 1, 'ms');")); // Display '°C' next to the 'Activation Threshold' setting - oappend(F("addInfo('Internal Temperature:Activation Threshold', 1, '°C');")); + oappend(SET_F("addInfo('Internal Temperature:Activation Threshold', 1, '°C');")); // Display '0 = Disabled' next to the 'Preset To Activate' setting - oappend(F("addInfo('Internal Temperature:Preset To Activate', 1, '0 = unused');")); + oappend(SET_F("addInfo('Internal Temperature:Preset To Activate', 1, '0 = unused');")); } bool readFromConfig(JsonObject &root) diff --git a/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h b/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h index 0deda181c..29070cf84 100644 --- a/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h +++ b/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h @@ -511,8 +511,8 @@ void PIRsensorSwitch::addToConfig(JsonObject &root) void PIRsensorSwitch::appendConfigData() { - oappend(F("addInfo('PIRsensorSwitch:HA-discovery',1,'HA=Home Assistant');")); // 0 is field type, 1 is actual field - oappend(F("addInfo('PIRsensorSwitch:override',1,'Cancel timer on change');")); // 0 is field type, 1 is actual field + oappend(SET_F("addInfo('PIRsensorSwitch:HA-discovery',1,'HA=Home Assistant');")); // 0 is field type, 1 is actual field + oappend(SET_F("addInfo('PIRsensorSwitch:override',1,'Cancel timer on change');")); // 0 is field type, 1 is actual field for (int i = 0; i < PIR_SENSOR_MAX_SENSORS; i++) { char str[128]; sprintf_P(str, PSTR("addInfo('PIRsensorSwitch:pin[]',%d,'','#%d');"), i, i); diff --git a/usermods/ST7789_display/ST7789_display.h b/usermods/ST7789_display/ST7789_display.h index 65f4cae5d..0dbada382 100644 --- a/usermods/ST7789_display/ST7789_display.h +++ b/usermods/ST7789_display/ST7789_display.h @@ -377,10 +377,10 @@ class St7789DisplayUsermod : public Usermod { void appendConfigData() override { - oappend(F("addInfo('ST7789:pin[]',0,'','SPI CS');")); - oappend(F("addInfo('ST7789:pin[]',1,'','SPI DC');")); - oappend(F("addInfo('ST7789:pin[]',2,'','SPI RST');")); - oappend(F("addInfo('ST7789:pin[]',3,'','SPI BL');")); + oappend(SET_F("addInfo('ST7789:pin[]',0,'','SPI CS');")); + oappend(SET_F("addInfo('ST7789:pin[]',1,'','SPI DC');")); + oappend(SET_F("addInfo('ST7789:pin[]',2,'','SPI RST');")); + oappend(SET_F("addInfo('ST7789:pin[]',3,'','SPI BL');")); } /* diff --git a/usermods/Temperature/usermod_temperature.h b/usermods/Temperature/usermod_temperature.h index 178bc05a0..ad755eaee 100644 --- a/usermods/Temperature/usermod_temperature.h +++ b/usermods/Temperature/usermod_temperature.h @@ -435,10 +435,10 @@ bool UsermodTemperature::readFromConfig(JsonObject &root) { } void UsermodTemperature::appendConfigData() { - oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":")); oappend(String(FPSTR(_parasite)).c_str()); - oappend(F("',1,'(if no Vcc connected)');")); // 0 is field type, 1 is actual field - oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":")); oappend(String(FPSTR(_parasitePin)).c_str()); - oappend(F("',1,'(for external MOSFET)');")); // 0 is field type, 1 is actual field + oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_parasite)).c_str()); + oappend(SET_F("',1,'(if no Vcc connected)');")); // 0 is field type, 1 is actual field + oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_parasitePin)).c_str()); + oappend(SET_F("',1,'(for external MOSFET)');")); // 0 is field type, 1 is actual field } float UsermodTemperature::getTemperature() { diff --git a/usermods/boblight/boblight.h b/usermods/boblight/boblight.h index b04b78fac..916f7da98 100644 --- a/usermods/boblight/boblight.h +++ b/usermods/boblight/boblight.h @@ -305,14 +305,14 @@ class BobLightUsermod : public Usermod { } void appendConfigData() override { - //oappend(F("dd=addDropdown('usermod','selectfield');")); - //oappend(F("addOption(dd,'1st value',0);")); - //oappend(F("addOption(dd,'2nd value',1);")); - oappend(F("addInfo('BobLight:top',1,'LEDs');")); // 0 is field type, 1 is actual field - oappend(F("addInfo('BobLight:bottom',1,'LEDs');")); // 0 is field type, 1 is actual field - oappend(F("addInfo('BobLight:left',1,'LEDs');")); // 0 is field type, 1 is actual field - oappend(F("addInfo('BobLight:right',1,'LEDs');")); // 0 is field type, 1 is actual field - oappend(F("addInfo('BobLight:pct',1,'Depth of scan [%]');")); // 0 is field type, 1 is actual field + //oappend(SET_F("dd=addDropdown('usermod','selectfield');")); + //oappend(SET_F("addOption(dd,'1st value',0);")); + //oappend(SET_F("addOption(dd,'2nd value',1);")); + oappend(SET_F("addInfo('BobLight:top',1,'LEDs');")); // 0 is field type, 1 is actual field + oappend(SET_F("addInfo('BobLight:bottom',1,'LEDs');")); // 0 is field type, 1 is actual field + oappend(SET_F("addInfo('BobLight:left',1,'LEDs');")); // 0 is field type, 1 is actual field + oappend(SET_F("addInfo('BobLight:right',1,'LEDs');")); // 0 is field type, 1 is actual field + oappend(SET_F("addInfo('BobLight:pct',1,'Depth of scan [%]');")); // 0 is field type, 1 is actual field } void addToConfig(JsonObject& root) override { diff --git a/usermods/multi_relay/usermod_multi_relay.h b/usermods/multi_relay/usermod_multi_relay.h index c4446c7a2..33a6cf85e 100644 --- a/usermods/multi_relay/usermod_multi_relay.h +++ b/usermods/multi_relay/usermod_multi_relay.h @@ -264,7 +264,7 @@ void MultiRelay::handleOffTimer() { void MultiRelay::InitHtmlAPIHandle() { // https://github.com/me-no-dev/ESPAsyncWebServer DEBUG_PRINTLN(F("Relays: Initialize HTML API")); - server.on(F("/relays"), HTTP_GET, [this](AsyncWebServerRequest *request) { + server.on(SET_F("/relays"), HTTP_GET, [this](AsyncWebServerRequest *request) { DEBUG_PRINTLN(F("Relays: HTML API")); String janswer; String error = ""; @@ -765,10 +765,10 @@ void MultiRelay::addToConfig(JsonObject &root) { } void MultiRelay::appendConfigData() { - oappend(F("addInfo('MultiRelay:PCF8574-address',1,'(not hex!)');")); - oappend(F("addInfo('MultiRelay:broadcast-sec',1,'(MQTT message)');")); - //oappend(F("addInfo('MultiRelay:relay-0:pin',1,'(use -1 for PCF8574)');")); - oappend(F("d.extra.push({'MultiRelay':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});")); + oappend(SET_F("addInfo('MultiRelay:PCF8574-address',1,'(not hex!)');")); + oappend(SET_F("addInfo('MultiRelay:broadcast-sec',1,'(MQTT message)');")); + //oappend(SET_F("addInfo('MultiRelay:relay-0:pin',1,'(use -1 for PCF8574)');")); + oappend(SET_F("d.extra.push({'MultiRelay':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});")); } /** diff --git a/usermods/pixels_dice_tray/pixels_dice_tray.h b/usermods/pixels_dice_tray/pixels_dice_tray.h index 61348ebb8..a1e45ba33 100644 --- a/usermods/pixels_dice_tray/pixels_dice_tray.h +++ b/usermods/pixels_dice_tray/pixels_dice_tray.h @@ -387,23 +387,23 @@ class PixelsDiceTrayUsermod : public Usermod { // To work around this, add info text to the end of the preceding item. // // See addInfo in wled00/data/settings_um.htm for details on what this function does. - oappend(F( + oappend(SET_F( "addInfo('DiceTray:ble_scan_duration',1,'

Set to \"*\" to " "connect to any die.
Leave Blank to disable.

Saving will replace \"*\" with die names.','');")); #if USING_TFT_DISPLAY - oappend(F("ddr=addDropdown('DiceTray','rotation');")); - oappend(F("addOption(ddr,'0 deg',0);")); - oappend(F("addOption(ddr,'90 deg',1);")); - oappend(F("addOption(ddr,'180 deg',2);")); - oappend(F("addOption(ddr,'270 deg',3);")); - oappend(F( + oappend(SET_F("ddr=addDropdown('DiceTray','rotation');")); + oappend(SET_F("addOption(ddr,'0 deg',0);")); + oappend(SET_F("addOption(ddr,'90 deg',1);")); + oappend(SET_F("addOption(ddr,'180 deg',2);")); + oappend(SET_F("addOption(ddr,'270 deg',3);")); + oappend(SET_F( "addInfo('DiceTray:rotation',1,'
DO NOT CHANGE " "SPI PINS.
CHANGES ARE IGNORED.','');")); - oappend(F("addInfo('TFT:pin[]',0,'','SPI CS');")); - oappend(F("addInfo('TFT:pin[]',1,'','SPI DC');")); - oappend(F("addInfo('TFT:pin[]',2,'','SPI RST');")); - oappend(F("addInfo('TFT:pin[]',3,'','SPI BL');")); + oappend(SET_F("addInfo('TFT:pin[]',0,'','SPI CS');")); + oappend(SET_F("addInfo('TFT:pin[]',1,'','SPI DC');")); + oappend(SET_F("addInfo('TFT:pin[]',2,'','SPI RST');")); + oappend(SET_F("addInfo('TFT:pin[]',3,'','SPI BL');")); #endif } diff --git a/usermods/sht/usermod_sht.h b/usermods/sht/usermod_sht.h index f10c78a25..c6e17221b 100644 --- a/usermods/sht/usermod_sht.h +++ b/usermods/sht/usermod_sht.h @@ -310,22 +310,22 @@ void ShtUsermod::onMqttConnect(bool sessionPresent) { * @return void */ void ShtUsermod::appendConfigData() { - oappend(F("dd=addDropdown('")); + oappend(SET_F("dd=addDropdown('")); oappend(_name); - oappend(F("','")); + oappend(SET_F("','")); oappend(_shtType); - oappend(F("');")); - oappend(F("addOption(dd,'SHT30',0);")); - oappend(F("addOption(dd,'SHT31',1);")); - oappend(F("addOption(dd,'SHT35',2);")); - oappend(F("addOption(dd,'SHT85',3);")); - oappend(F("dd=addDropdown('")); + oappend(SET_F("');")); + oappend(SET_F("addOption(dd,'SHT30',0);")); + oappend(SET_F("addOption(dd,'SHT31',1);")); + oappend(SET_F("addOption(dd,'SHT35',2);")); + oappend(SET_F("addOption(dd,'SHT85',3);")); + oappend(SET_F("dd=addDropdown('")); oappend(_name); - oappend(F("','")); + oappend(SET_F("','")); oappend(_unitOfTemp); - oappend(F("');")); - oappend(F("addOption(dd,'Celsius',0);")); - oappend(F("addOption(dd,'Fahrenheit',1);")); + oappend(SET_F("');")); + oappend(SET_F("addOption(dd,'Celsius',0);")); + oappend(SET_F("addOption(dd,'Fahrenheit',1);")); } /** diff --git a/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h b/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h index 684dd86e4..dfab7e6ff 100644 --- a/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h +++ b/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h @@ -1202,21 +1202,21 @@ void FourLineDisplayUsermod::onUpdateBegin(bool init) { //} void FourLineDisplayUsermod::appendConfigData() { - oappend(F("dd=addDropdown('4LineDisplay','type');")); - oappend(F("addOption(dd,'None',0);")); - oappend(F("addOption(dd,'SSD1306',1);")); - oappend(F("addOption(dd,'SH1106',2);")); - oappend(F("addOption(dd,'SSD1306 128x64',3);")); - oappend(F("addOption(dd,'SSD1305',4);")); - oappend(F("addOption(dd,'SSD1305 128x64',5);")); - oappend(F("addOption(dd,'SSD1309 128x64',9);")); - oappend(F("addOption(dd,'SSD1306 SPI',6);")); - oappend(F("addOption(dd,'SSD1306 SPI 128x64',7);")); - oappend(F("addOption(dd,'SSD1309 SPI 128x64',8);")); - oappend(F("addInfo('4LineDisplay:type',1,'
Change may require reboot','');")); - oappend(F("addInfo('4LineDisplay:pin[]',0,'','SPI CS');")); - oappend(F("addInfo('4LineDisplay:pin[]',1,'','SPI DC');")); - oappend(F("addInfo('4LineDisplay:pin[]',2,'','SPI RST');")); + oappend(SET_F("dd=addDropdown('4LineDisplay','type');")); + oappend(SET_F("addOption(dd,'None',0);")); + oappend(SET_F("addOption(dd,'SSD1306',1);")); + oappend(SET_F("addOption(dd,'SH1106',2);")); + oappend(SET_F("addOption(dd,'SSD1306 128x64',3);")); + oappend(SET_F("addOption(dd,'SSD1305',4);")); + oappend(SET_F("addOption(dd,'SSD1305 128x64',5);")); + oappend(SET_F("addOption(dd,'SSD1309 128x64',9);")); + oappend(SET_F("addOption(dd,'SSD1306 SPI',6);")); + oappend(SET_F("addOption(dd,'SSD1306 SPI 128x64',7);")); + oappend(SET_F("addOption(dd,'SSD1309 SPI 128x64',8);")); + oappend(SET_F("addInfo('4LineDisplay:type',1,'
Change may require reboot','');")); + oappend(SET_F("addInfo('4LineDisplay:pin[]',0,'','SPI CS');")); + oappend(SET_F("addInfo('4LineDisplay:pin[]',1,'','SPI DC');")); + oappend(SET_F("addInfo('4LineDisplay:pin[]',2,'','SPI RST');")); } /* diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h index 383c1193e..55715b7c7 100644 --- a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h @@ -1090,8 +1090,8 @@ void RotaryEncoderUIUsermod::addToConfig(JsonObject &root) { } void RotaryEncoderUIUsermod::appendConfigData() { - oappend(F("addInfo('Rotary-Encoder:PCF8574-address',1,'(not hex!)');")); - oappend(F("d.extra.push({'Rotary-Encoder':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});")); + oappend(SET_F("addInfo('Rotary-Encoder:PCF8574-address',1,'(not hex!)');")); + oappend(SET_F("d.extra.push({'Rotary-Encoder':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});")); } /** diff --git a/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h b/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h index 7ecec08e5..b66be290a 100644 --- a/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h +++ b/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h @@ -433,8 +433,8 @@ class WordClockUsermod : public Usermod void appendConfigData() { - oappend(F("addInfo('WordClockUsermod:ledOffset', 1, 'Number of LEDs before the letters');")); - oappend(F("addInfo('WordClockUsermod:Norddeutsch', 1, 'Viertel vor instead of Dreiviertel');")); + oappend(SET_F("addInfo('WordClockUsermod:ledOffset', 1, 'Number of LEDs before the letters');")); + oappend(SET_F("addInfo('WordClockUsermod:Norddeutsch', 1, 'Viertel vor instead of Dreiviertel');")); } /* diff --git a/usermods/wireguard/wireguard.h b/usermods/wireguard/wireguard.h index 8656a704a..8c88d0001 100644 --- a/usermods/wireguard/wireguard.h +++ b/usermods/wireguard/wireguard.h @@ -54,13 +54,13 @@ class WireguardUsermod : public Usermod { } void appendConfigData() { - oappend(F("addInfo('WireGuard:host',1,'Server Hostname');")); // 0 is field type, 1 is actual field - oappend(F("addInfo('WireGuard:port',1,'Server Port');")); // 0 is field type, 1 is actual field - oappend(F("addInfo('WireGuard:ip',1,'Device IP');")); // 0 is field type, 1 is actual field - oappend(F("addInfo('WireGuard:psk',1,'Pre Shared Key (optional)');")); // 0 is field type, 1 is actual field - oappend(F("addInfo('WireGuard:pem',1,'Private Key');")); // 0 is field type, 1 is actual field - oappend(F("addInfo('WireGuard:pub',1,'Public Key');")); // 0 is field type, 1 is actual field - oappend(F("addInfo('WireGuard:tz',1,'POSIX timezone string');")); // 0 is field type, 1 is actual field + oappend(SET_F("addInfo('WireGuard:host',1,'Server Hostname');")); // 0 is field type, 1 is actual field + oappend(SET_F("addInfo('WireGuard:port',1,'Server Port');")); // 0 is field type, 1 is actual field + oappend(SET_F("addInfo('WireGuard:ip',1,'Device IP');")); // 0 is field type, 1 is actual field + oappend(SET_F("addInfo('WireGuard:psk',1,'Pre Shared Key (optional)');")); // 0 is field type, 1 is actual field + oappend(SET_F("addInfo('WireGuard:pem',1,'Private Key');")); // 0 is field type, 1 is actual field + oappend(SET_F("addInfo('WireGuard:pub',1,'Public Key');")); // 0 is field type, 1 is actual field + oappend(SET_F("addInfo('WireGuard:tz',1,'POSIX timezone string');")); // 0 is field type, 1 is actual field } void addToConfig(JsonObject& root) { From 4f48ddfaec8a4d3d5dfe548204e3fde90baf8e9f Mon Sep 17 00:00:00 2001 From: Will Miles Date: Wed, 23 Oct 2024 20:00:22 -0400 Subject: [PATCH 097/234] Replace SET_F with F in usermods Since oappend() is now strongly typed, pass the correct type. This is a step towards removing the extra shim logic on ESP8266. --- .../Animated_Staircase/Animated_Staircase.h | 8 ++--- usermods/BME68X_v2/usermod_bme68x.h | 20 +++++------ usermods/Battery/usermod_v2_Battery.h | 34 +++++++++---------- usermods/EXAMPLE_v2/usermod_v2_example.h | 10 +++--- .../usermod_internal_temperature.h | 6 ++-- .../usermod_PIR_sensor_switch.h | 4 +-- usermods/ST7789_display/ST7789_display.h | 8 ++--- usermods/Temperature/usermod_temperature.h | 8 ++--- usermods/boblight/boblight.h | 16 ++++----- usermods/multi_relay/usermod_multi_relay.h | 10 +++--- usermods/pixels_dice_tray/pixels_dice_tray.h | 22 ++++++------ usermods/sht/usermod_sht.h | 24 ++++++------- .../usermod_v2_four_line_display_ALT.h | 30 ++++++++-------- .../usermod_v2_rotary_encoder_ui_ALT.h | 4 +-- .../usermod_v2_word_clock.h | 4 +-- usermods/wireguard/wireguard.h | 14 ++++---- 16 files changed, 111 insertions(+), 111 deletions(-) diff --git a/usermods/Animated_Staircase/Animated_Staircase.h b/usermods/Animated_Staircase/Animated_Staircase.h index d1ec9bb7f..54a9b3331 100644 --- a/usermods/Animated_Staircase/Animated_Staircase.h +++ b/usermods/Animated_Staircase/Animated_Staircase.h @@ -425,10 +425,10 @@ class Animated_Staircase : public Usermod { } void appendConfigData() { - //oappend(SET_F("dd=addDropdown('staircase','selectfield');")); - //oappend(SET_F("addOption(dd,'1st value',0);")); - //oappend(SET_F("addOption(dd,'2nd value',1);")); - //oappend(SET_F("addInfo('staircase:selectfield',1,'additional info');")); // 0 is field type, 1 is actual field + //oappend(F("dd=addDropdown('staircase','selectfield');")); + //oappend(F("addOption(dd,'1st value',0);")); + //oappend(F("addOption(dd,'2nd value',1);")); + //oappend(F("addInfo('staircase:selectfield',1,'additional info');")); // 0 is field type, 1 is actual field } diff --git a/usermods/BME68X_v2/usermod_bme68x.h b/usermods/BME68X_v2/usermod_bme68x.h index 8e360515a..aca24d0a2 100644 --- a/usermods/BME68X_v2/usermod_bme68x.h +++ b/usermods/BME68X_v2/usermod_bme68x.h @@ -767,22 +767,22 @@ void UsermodBME68X::appendConfigData() { // snprintf_P(charbuffer, 127, PSTR("addInfo('%s:%s',1,'*) Set to minus to deactivate (all sensors)');"), UMOD_NAME, _nameTemp); oappend(charbuffer); /* Dropdown for Celsius/Fahrenheit*/ - oappend(SET_F("dd=addDropdown('")); + oappend(F("dd=addDropdown('")); oappend(UMOD_NAME); - oappend(SET_F("','")); + oappend(F("','")); oappend(_nameTempScale); - oappend(SET_F("');")); - oappend(SET_F("addOption(dd,'Celsius',0);")); - oappend(SET_F("addOption(dd,'Fahrenheit',1);")); + oappend(F("');")); + oappend(F("addOption(dd,'Celsius',0);")); + oappend(F("addOption(dd,'Fahrenheit',1);")); /* i²C Address*/ - oappend(SET_F("dd=addDropdown('")); + oappend(F("dd=addDropdown('")); oappend(UMOD_NAME); - oappend(SET_F("','")); + oappend(F("','")); oappend(_nameI2CAdr); - oappend(SET_F("');")); - oappend(SET_F("addOption(dd,'0x76',0x76);")); - oappend(SET_F("addOption(dd,'0x77',0x77);")); + oappend(F("');")); + oappend(F("addOption(dd,'0x76',0x76);")); + oappend(F("addOption(dd,'0x77',0x77);")); } /** diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h index e91de850c..b36c5f4d6 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/usermod_v2_Battery.h @@ -478,29 +478,29 @@ class UsermodBattery : public Usermod void appendConfigData() { // Total: 462 Bytes - oappend(SET_F("td=addDropdown('Battery','type');")); // 34 Bytes - oappend(SET_F("addOption(td,'Unkown','0');")); // 28 Bytes - oappend(SET_F("addOption(td,'LiPo','1');")); // 26 Bytes - oappend(SET_F("addOption(td,'LiOn','2');")); // 26 Bytes - oappend(SET_F("addInfo('Battery:type',1,'requires reboot');")); // 81 Bytes - oappend(SET_F("addInfo('Battery:min-voltage',1,'v');")); // 38 Bytes - oappend(SET_F("addInfo('Battery:max-voltage',1,'v');")); // 38 Bytes - oappend(SET_F("addInfo('Battery:interval',1,'ms');")); // 36 Bytes - oappend(SET_F("addInfo('Battery:HA-discovery',1,'');")); // 38 Bytes - oappend(SET_F("addInfo('Battery:auto-off:threshold',1,'%');")); // 45 Bytes - oappend(SET_F("addInfo('Battery:indicator:threshold',1,'%');")); // 46 Bytes - oappend(SET_F("addInfo('Battery:indicator:duration',1,'s');")); // 45 Bytes + oappend(F("td=addDropdown('Battery','type');")); // 34 Bytes + oappend(F("addOption(td,'Unkown','0');")); // 28 Bytes + oappend(F("addOption(td,'LiPo','1');")); // 26 Bytes + oappend(F("addOption(td,'LiOn','2');")); // 26 Bytes + oappend(F("addInfo('Battery:type',1,'requires reboot');")); // 81 Bytes + oappend(F("addInfo('Battery:min-voltage',1,'v');")); // 38 Bytes + oappend(F("addInfo('Battery:max-voltage',1,'v');")); // 38 Bytes + oappend(F("addInfo('Battery:interval',1,'ms');")); // 36 Bytes + oappend(F("addInfo('Battery:HA-discovery',1,'');")); // 38 Bytes + oappend(F("addInfo('Battery:auto-off:threshold',1,'%');")); // 45 Bytes + oappend(F("addInfo('Battery:indicator:threshold',1,'%');")); // 46 Bytes + oappend(F("addInfo('Battery:indicator:duration',1,'s');")); // 45 Bytes // this option list would exeed the oappend() buffer // a list of all presets to select one from - // oappend(SET_F("bd=addDropdown('Battery:low-power-indicator', 'preset');")); - // the loop generates: oappend(SET_F("addOption(bd, 'preset name', preset id);")); + // oappend(F("bd=addDropdown('Battery:low-power-indicator', 'preset');")); + // the loop generates: oappend(F("addOption(bd, 'preset name', preset id);")); // for(int8_t i=1; i < 42; i++) { - // oappend(SET_F("addOption(bd, 'Preset#")); + // oappend(F("addOption(bd, 'Preset#")); // oappendi(i); - // oappend(SET_F("',")); + // oappend(F("',")); // oappendi(i); - // oappend(SET_F(");")); + // oappend(F(");")); // } } diff --git a/usermods/EXAMPLE_v2/usermod_v2_example.h b/usermods/EXAMPLE_v2/usermod_v2_example.h index 3d562b585..df05f3e3d 100644 --- a/usermods/EXAMPLE_v2/usermod_v2_example.h +++ b/usermods/EXAMPLE_v2/usermod_v2_example.h @@ -287,11 +287,11 @@ class MyExampleUsermod : public Usermod { */ void appendConfigData() override { - oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":great")); oappend(SET_F("',1,'(this is a great config value)');")); - oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":testString")); oappend(SET_F("',1,'enter any string you want');")); - oappend(SET_F("dd=addDropdown('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F("','testInt');")); - oappend(SET_F("addOption(dd,'Nothing',0);")); - oappend(SET_F("addOption(dd,'Everything',42);")); + oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":great")); oappend(F("',1,'(this is a great config value)');")); + oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":testString")); oappend(F("',1,'enter any string you want');")); + oappend(F("dd=addDropdown('")); oappend(String(FPSTR(_name)).c_str()); oappend(F("','testInt');")); + oappend(F("addOption(dd,'Nothing',0);")); + oappend(F("addOption(dd,'Everything',42);")); } diff --git a/usermods/Internal_Temperature_v2/usermod_internal_temperature.h b/usermods/Internal_Temperature_v2/usermod_internal_temperature.h index 2236bfeab..c24b4c628 100644 --- a/usermods/Internal_Temperature_v2/usermod_internal_temperature.h +++ b/usermods/Internal_Temperature_v2/usermod_internal_temperature.h @@ -149,11 +149,11 @@ public: void appendConfigData() { // Display 'ms' next to the 'Loop Interval' setting - oappend(SET_F("addInfo('Internal Temperature:Loop Interval', 1, 'ms');")); + oappend(F("addInfo('Internal Temperature:Loop Interval', 1, 'ms');")); // Display '°C' next to the 'Activation Threshold' setting - oappend(SET_F("addInfo('Internal Temperature:Activation Threshold', 1, '°C');")); + oappend(F("addInfo('Internal Temperature:Activation Threshold', 1, '°C');")); // Display '0 = Disabled' next to the 'Preset To Activate' setting - oappend(SET_F("addInfo('Internal Temperature:Preset To Activate', 1, '0 = unused');")); + oappend(F("addInfo('Internal Temperature:Preset To Activate', 1, '0 = unused');")); } bool readFromConfig(JsonObject &root) diff --git a/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h b/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h index 29070cf84..0deda181c 100644 --- a/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h +++ b/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h @@ -511,8 +511,8 @@ void PIRsensorSwitch::addToConfig(JsonObject &root) void PIRsensorSwitch::appendConfigData() { - oappend(SET_F("addInfo('PIRsensorSwitch:HA-discovery',1,'HA=Home Assistant');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('PIRsensorSwitch:override',1,'Cancel timer on change');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('PIRsensorSwitch:HA-discovery',1,'HA=Home Assistant');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('PIRsensorSwitch:override',1,'Cancel timer on change');")); // 0 is field type, 1 is actual field for (int i = 0; i < PIR_SENSOR_MAX_SENSORS; i++) { char str[128]; sprintf_P(str, PSTR("addInfo('PIRsensorSwitch:pin[]',%d,'','#%d');"), i, i); diff --git a/usermods/ST7789_display/ST7789_display.h b/usermods/ST7789_display/ST7789_display.h index 0dbada382..65f4cae5d 100644 --- a/usermods/ST7789_display/ST7789_display.h +++ b/usermods/ST7789_display/ST7789_display.h @@ -377,10 +377,10 @@ class St7789DisplayUsermod : public Usermod { void appendConfigData() override { - oappend(SET_F("addInfo('ST7789:pin[]',0,'','SPI CS');")); - oappend(SET_F("addInfo('ST7789:pin[]',1,'','SPI DC');")); - oappend(SET_F("addInfo('ST7789:pin[]',2,'','SPI RST');")); - oappend(SET_F("addInfo('ST7789:pin[]',3,'','SPI BL');")); + oappend(F("addInfo('ST7789:pin[]',0,'','SPI CS');")); + oappend(F("addInfo('ST7789:pin[]',1,'','SPI DC');")); + oappend(F("addInfo('ST7789:pin[]',2,'','SPI RST');")); + oappend(F("addInfo('ST7789:pin[]',3,'','SPI BL');")); } /* diff --git a/usermods/Temperature/usermod_temperature.h b/usermods/Temperature/usermod_temperature.h index ad755eaee..178bc05a0 100644 --- a/usermods/Temperature/usermod_temperature.h +++ b/usermods/Temperature/usermod_temperature.h @@ -435,10 +435,10 @@ bool UsermodTemperature::readFromConfig(JsonObject &root) { } void UsermodTemperature::appendConfigData() { - oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_parasite)).c_str()); - oappend(SET_F("',1,'(if no Vcc connected)');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(SET_F(":")); oappend(String(FPSTR(_parasitePin)).c_str()); - oappend(SET_F("',1,'(for external MOSFET)');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":")); oappend(String(FPSTR(_parasite)).c_str()); + oappend(F("',1,'(if no Vcc connected)');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('")); oappend(String(FPSTR(_name)).c_str()); oappend(F(":")); oappend(String(FPSTR(_parasitePin)).c_str()); + oappend(F("',1,'(for external MOSFET)');")); // 0 is field type, 1 is actual field } float UsermodTemperature::getTemperature() { diff --git a/usermods/boblight/boblight.h b/usermods/boblight/boblight.h index 916f7da98..b04b78fac 100644 --- a/usermods/boblight/boblight.h +++ b/usermods/boblight/boblight.h @@ -305,14 +305,14 @@ class BobLightUsermod : public Usermod { } void appendConfigData() override { - //oappend(SET_F("dd=addDropdown('usermod','selectfield');")); - //oappend(SET_F("addOption(dd,'1st value',0);")); - //oappend(SET_F("addOption(dd,'2nd value',1);")); - oappend(SET_F("addInfo('BobLight:top',1,'LEDs');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('BobLight:bottom',1,'LEDs');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('BobLight:left',1,'LEDs');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('BobLight:right',1,'LEDs');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('BobLight:pct',1,'Depth of scan [%]');")); // 0 is field type, 1 is actual field + //oappend(F("dd=addDropdown('usermod','selectfield');")); + //oappend(F("addOption(dd,'1st value',0);")); + //oappend(F("addOption(dd,'2nd value',1);")); + oappend(F("addInfo('BobLight:top',1,'LEDs');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('BobLight:bottom',1,'LEDs');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('BobLight:left',1,'LEDs');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('BobLight:right',1,'LEDs');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('BobLight:pct',1,'Depth of scan [%]');")); // 0 is field type, 1 is actual field } void addToConfig(JsonObject& root) override { diff --git a/usermods/multi_relay/usermod_multi_relay.h b/usermods/multi_relay/usermod_multi_relay.h index 33a6cf85e..c4446c7a2 100644 --- a/usermods/multi_relay/usermod_multi_relay.h +++ b/usermods/multi_relay/usermod_multi_relay.h @@ -264,7 +264,7 @@ void MultiRelay::handleOffTimer() { void MultiRelay::InitHtmlAPIHandle() { // https://github.com/me-no-dev/ESPAsyncWebServer DEBUG_PRINTLN(F("Relays: Initialize HTML API")); - server.on(SET_F("/relays"), HTTP_GET, [this](AsyncWebServerRequest *request) { + server.on(F("/relays"), HTTP_GET, [this](AsyncWebServerRequest *request) { DEBUG_PRINTLN(F("Relays: HTML API")); String janswer; String error = ""; @@ -765,10 +765,10 @@ void MultiRelay::addToConfig(JsonObject &root) { } void MultiRelay::appendConfigData() { - oappend(SET_F("addInfo('MultiRelay:PCF8574-address',1,'(not hex!)');")); - oappend(SET_F("addInfo('MultiRelay:broadcast-sec',1,'(MQTT message)');")); - //oappend(SET_F("addInfo('MultiRelay:relay-0:pin',1,'(use -1 for PCF8574)');")); - oappend(SET_F("d.extra.push({'MultiRelay':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});")); + oappend(F("addInfo('MultiRelay:PCF8574-address',1,'(not hex!)');")); + oappend(F("addInfo('MultiRelay:broadcast-sec',1,'(MQTT message)');")); + //oappend(F("addInfo('MultiRelay:relay-0:pin',1,'(use -1 for PCF8574)');")); + oappend(F("d.extra.push({'MultiRelay':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});")); } /** diff --git a/usermods/pixels_dice_tray/pixels_dice_tray.h b/usermods/pixels_dice_tray/pixels_dice_tray.h index a1e45ba33..61348ebb8 100644 --- a/usermods/pixels_dice_tray/pixels_dice_tray.h +++ b/usermods/pixels_dice_tray/pixels_dice_tray.h @@ -387,23 +387,23 @@ class PixelsDiceTrayUsermod : public Usermod { // To work around this, add info text to the end of the preceding item. // // See addInfo in wled00/data/settings_um.htm for details on what this function does. - oappend(SET_F( + oappend(F( "addInfo('DiceTray:ble_scan_duration',1,'

Set to \"*\" to " "connect to any die.
Leave Blank to disable.

Saving will replace \"*\" with die names.','');")); #if USING_TFT_DISPLAY - oappend(SET_F("ddr=addDropdown('DiceTray','rotation');")); - oappend(SET_F("addOption(ddr,'0 deg',0);")); - oappend(SET_F("addOption(ddr,'90 deg',1);")); - oappend(SET_F("addOption(ddr,'180 deg',2);")); - oappend(SET_F("addOption(ddr,'270 deg',3);")); - oappend(SET_F( + oappend(F("ddr=addDropdown('DiceTray','rotation');")); + oappend(F("addOption(ddr,'0 deg',0);")); + oappend(F("addOption(ddr,'90 deg',1);")); + oappend(F("addOption(ddr,'180 deg',2);")); + oappend(F("addOption(ddr,'270 deg',3);")); + oappend(F( "addInfo('DiceTray:rotation',1,'
DO NOT CHANGE " "SPI PINS.
CHANGES ARE IGNORED.','');")); - oappend(SET_F("addInfo('TFT:pin[]',0,'','SPI CS');")); - oappend(SET_F("addInfo('TFT:pin[]',1,'','SPI DC');")); - oappend(SET_F("addInfo('TFT:pin[]',2,'','SPI RST');")); - oappend(SET_F("addInfo('TFT:pin[]',3,'','SPI BL');")); + oappend(F("addInfo('TFT:pin[]',0,'','SPI CS');")); + oappend(F("addInfo('TFT:pin[]',1,'','SPI DC');")); + oappend(F("addInfo('TFT:pin[]',2,'','SPI RST');")); + oappend(F("addInfo('TFT:pin[]',3,'','SPI BL');")); #endif } diff --git a/usermods/sht/usermod_sht.h b/usermods/sht/usermod_sht.h index c6e17221b..f10c78a25 100644 --- a/usermods/sht/usermod_sht.h +++ b/usermods/sht/usermod_sht.h @@ -310,22 +310,22 @@ void ShtUsermod::onMqttConnect(bool sessionPresent) { * @return void */ void ShtUsermod::appendConfigData() { - oappend(SET_F("dd=addDropdown('")); + oappend(F("dd=addDropdown('")); oappend(_name); - oappend(SET_F("','")); + oappend(F("','")); oappend(_shtType); - oappend(SET_F("');")); - oappend(SET_F("addOption(dd,'SHT30',0);")); - oappend(SET_F("addOption(dd,'SHT31',1);")); - oappend(SET_F("addOption(dd,'SHT35',2);")); - oappend(SET_F("addOption(dd,'SHT85',3);")); - oappend(SET_F("dd=addDropdown('")); + oappend(F("');")); + oappend(F("addOption(dd,'SHT30',0);")); + oappend(F("addOption(dd,'SHT31',1);")); + oappend(F("addOption(dd,'SHT35',2);")); + oappend(F("addOption(dd,'SHT85',3);")); + oappend(F("dd=addDropdown('")); oappend(_name); - oappend(SET_F("','")); + oappend(F("','")); oappend(_unitOfTemp); - oappend(SET_F("');")); - oappend(SET_F("addOption(dd,'Celsius',0);")); - oappend(SET_F("addOption(dd,'Fahrenheit',1);")); + oappend(F("');")); + oappend(F("addOption(dd,'Celsius',0);")); + oappend(F("addOption(dd,'Fahrenheit',1);")); } /** diff --git a/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h b/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h index dfab7e6ff..684dd86e4 100644 --- a/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h +++ b/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h @@ -1202,21 +1202,21 @@ void FourLineDisplayUsermod::onUpdateBegin(bool init) { //} void FourLineDisplayUsermod::appendConfigData() { - oappend(SET_F("dd=addDropdown('4LineDisplay','type');")); - oappend(SET_F("addOption(dd,'None',0);")); - oappend(SET_F("addOption(dd,'SSD1306',1);")); - oappend(SET_F("addOption(dd,'SH1106',2);")); - oappend(SET_F("addOption(dd,'SSD1306 128x64',3);")); - oappend(SET_F("addOption(dd,'SSD1305',4);")); - oappend(SET_F("addOption(dd,'SSD1305 128x64',5);")); - oappend(SET_F("addOption(dd,'SSD1309 128x64',9);")); - oappend(SET_F("addOption(dd,'SSD1306 SPI',6);")); - oappend(SET_F("addOption(dd,'SSD1306 SPI 128x64',7);")); - oappend(SET_F("addOption(dd,'SSD1309 SPI 128x64',8);")); - oappend(SET_F("addInfo('4LineDisplay:type',1,'
Change may require reboot','');")); - oappend(SET_F("addInfo('4LineDisplay:pin[]',0,'','SPI CS');")); - oappend(SET_F("addInfo('4LineDisplay:pin[]',1,'','SPI DC');")); - oappend(SET_F("addInfo('4LineDisplay:pin[]',2,'','SPI RST');")); + oappend(F("dd=addDropdown('4LineDisplay','type');")); + oappend(F("addOption(dd,'None',0);")); + oappend(F("addOption(dd,'SSD1306',1);")); + oappend(F("addOption(dd,'SH1106',2);")); + oappend(F("addOption(dd,'SSD1306 128x64',3);")); + oappend(F("addOption(dd,'SSD1305',4);")); + oappend(F("addOption(dd,'SSD1305 128x64',5);")); + oappend(F("addOption(dd,'SSD1309 128x64',9);")); + oappend(F("addOption(dd,'SSD1306 SPI',6);")); + oappend(F("addOption(dd,'SSD1306 SPI 128x64',7);")); + oappend(F("addOption(dd,'SSD1309 SPI 128x64',8);")); + oappend(F("addInfo('4LineDisplay:type',1,'
Change may require reboot','');")); + oappend(F("addInfo('4LineDisplay:pin[]',0,'','SPI CS');")); + oappend(F("addInfo('4LineDisplay:pin[]',1,'','SPI DC');")); + oappend(F("addInfo('4LineDisplay:pin[]',2,'','SPI RST');")); } /* diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h index 55715b7c7..383c1193e 100644 --- a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h @@ -1090,8 +1090,8 @@ void RotaryEncoderUIUsermod::addToConfig(JsonObject &root) { } void RotaryEncoderUIUsermod::appendConfigData() { - oappend(SET_F("addInfo('Rotary-Encoder:PCF8574-address',1,'(not hex!)');")); - oappend(SET_F("d.extra.push({'Rotary-Encoder':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});")); + oappend(F("addInfo('Rotary-Encoder:PCF8574-address',1,'(not hex!)');")); + oappend(F("d.extra.push({'Rotary-Encoder':{pin:[['P0',100],['P1',101],['P2',102],['P3',103],['P4',104],['P5',105],['P6',106],['P7',107]]}});")); } /** diff --git a/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h b/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h index b66be290a..7ecec08e5 100644 --- a/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h +++ b/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h @@ -433,8 +433,8 @@ class WordClockUsermod : public Usermod void appendConfigData() { - oappend(SET_F("addInfo('WordClockUsermod:ledOffset', 1, 'Number of LEDs before the letters');")); - oappend(SET_F("addInfo('WordClockUsermod:Norddeutsch', 1, 'Viertel vor instead of Dreiviertel');")); + oappend(F("addInfo('WordClockUsermod:ledOffset', 1, 'Number of LEDs before the letters');")); + oappend(F("addInfo('WordClockUsermod:Norddeutsch', 1, 'Viertel vor instead of Dreiviertel');")); } /* diff --git a/usermods/wireguard/wireguard.h b/usermods/wireguard/wireguard.h index 8c88d0001..8656a704a 100644 --- a/usermods/wireguard/wireguard.h +++ b/usermods/wireguard/wireguard.h @@ -54,13 +54,13 @@ class WireguardUsermod : public Usermod { } void appendConfigData() { - oappend(SET_F("addInfo('WireGuard:host',1,'Server Hostname');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('WireGuard:port',1,'Server Port');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('WireGuard:ip',1,'Device IP');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('WireGuard:psk',1,'Pre Shared Key (optional)');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('WireGuard:pem',1,'Private Key');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('WireGuard:pub',1,'Public Key');")); // 0 is field type, 1 is actual field - oappend(SET_F("addInfo('WireGuard:tz',1,'POSIX timezone string');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('WireGuard:host',1,'Server Hostname');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('WireGuard:port',1,'Server Port');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('WireGuard:ip',1,'Device IP');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('WireGuard:psk',1,'Pre Shared Key (optional)');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('WireGuard:pem',1,'Private Key');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('WireGuard:pub',1,'Public Key');")); // 0 is field type, 1 is actual field + oappend(F("addInfo('WireGuard:tz',1,'POSIX timezone string');")); // 0 is field type, 1 is actual field } void addToConfig(JsonObject& root) { From 832599b8c51ba7df3a565901ddf338b18d82f8a4 Mon Sep 17 00:00:00 2001 From: Svennte <105973347+Svennte@users.noreply.github.com> Date: Fri, 25 Oct 2024 09:33:05 +0200 Subject: [PATCH 098/234] Fix alexa devices invisible/uncontrollable (#4214) Fix for LED and Scenes uncontrollable using Alexa. Weird behavior regarding to the device names and shared scenes fixed with this. Seen in issue Aircoookie/Espalexa#228 and fixed from @ams-hh Tested by myself and works just fine. Created second pull request here because the library seems to be a bit different from the official Espalexa repo. --------- Co-authored-by: Frank <91616163+softhack007@users.noreply.github.com> Co-authored-by: Blaz Kristan --- wled00/src/dependencies/espalexa/Espalexa.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/wled00/src/dependencies/espalexa/Espalexa.h b/wled00/src/dependencies/espalexa/Espalexa.h index 5c780e248..ae761e9fa 100644 --- a/wled00/src/dependencies/espalexa/Espalexa.h +++ b/wled00/src/dependencies/espalexa/Espalexa.h @@ -120,10 +120,8 @@ private: void encodeLightId(uint8_t idx, char* out) { - uint8_t mac[6]; - WiFi.macAddress(mac); - - sprintf_P(out, PSTR("%02X:%02X:%02X:%02X:%02X:%02X:00:11-%02X"), mac[0],mac[1],mac[2],mac[3],mac[4],mac[5], idx); + String mymac = WiFi.macAddress(); + sprintf_P(out, PSTR("%02X:%s:AB-%02X"), idx, mymac.c_str(), idx); } // construct 'globally unique' Json dict key fitting into signed int From dcfdca63515f2d3f80674d05c6ee7186f9458354 Mon Sep 17 00:00:00 2001 From: ingDIY <10012263+ingDIY@users.noreply.github.com> Date: Fri, 25 Oct 2024 12:14:37 +0200 Subject: [PATCH 099/234] cleaned up old references to USE_ALT_DISPlAY that aren't used anymore in the code/source files; fixed readme.md documents and updated instructions; removed referencies to old usermods; fixed invalid filenames; removed referencies to old usermods; checked cycle options; splitted and fixed platformio_override.sample.ini; --- platformio_override.sample.ini | 2 -- .../platformio_override.sample.ini} | 11 +++---- .../readme.md | 30 +++++-------------- .../platformio_override.sample.ini | 14 +++++++++ .../readme.md | 22 ++++---------- 5 files changed, 32 insertions(+), 47 deletions(-) rename usermods/{usermod_v2_rotary_encoder_ui_ALT/platformio–override.sample.ini => usermod_v2_four_line_display_ALT/platformio_override.sample.ini} (54%) create mode 100644 usermods/usermod_v2_rotary_encoder_ui_ALT/platformio_override.sample.ini diff --git a/platformio_override.sample.ini b/platformio_override.sample.ini index 8e5fdf003..c445cd32e 100644 --- a/platformio_override.sample.ini +++ b/platformio_override.sample.ini @@ -111,7 +111,6 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} ; ; Use 4 Line Display usermod with SPI display ; -D USERMOD_FOUR_LINE_DISPLAY -; -D USE_ALT_DISPlAY # mandatory ; -DFLD_SPI_DEFAULT ; -D FLD_TYPE=SSD1306_SPI64 ; -D FLD_PIN_CLOCKSPI=14 @@ -377,7 +376,6 @@ build_flags = ${common.build_flags} ${esp32.build_flags} -D USERMOD_DALLASTEMPERATURE -D USERMOD_FOUR_LINE_DISPLAY -D TEMPERATURE_PIN=23 - -D USE_ALT_DISPlAY ; new versions of USERMOD_FOUR_LINE_DISPLAY and USERMOD_ROTARY_ENCODER_UI -D USERMOD_AUDIOREACTIVE lib_deps = ${esp32.lib_deps} OneWire@~2.3.5 diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/platformio–override.sample.ini b/usermods/usermod_v2_four_line_display_ALT/platformio_override.sample.ini similarity index 54% rename from usermods/usermod_v2_rotary_encoder_ui_ALT/platformio–override.sample.ini rename to usermods/usermod_v2_four_line_display_ALT/platformio_override.sample.ini index 6b32c71fb..9010648b3 100644 --- a/usermods/usermod_v2_rotary_encoder_ui_ALT/platformio–override.sample.ini +++ b/usermods/usermod_v2_four_line_display_ALT/platformio_override.sample.ini @@ -7,11 +7,12 @@ platform = ${esp32.platform} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags_esp32} - -D USERMOD_FOUR_LINE_DISPLAY -D USE_ALT_DISPlAY - -D USERMOD_ROTARY_ENCODER_UI -D ENCODER_DT_PIN=18 -D ENCODER_CLK_PIN=5 -D ENCODER_SW_PIN=19 -upload_speed = 460800 + -D USERMOD_FOUR_LINE_DISPLAY + -D FLD_TYPE=SH1106 + -D I2CSCLPIN=27 + -D I2CSDAPIN=26 + lib_deps = ${esp32.lib_deps} - U8g2@~2.34.4 + U8g2 Wire - diff --git a/usermods/usermod_v2_four_line_display_ALT/readme.md b/usermods/usermod_v2_four_line_display_ALT/readme.md index a8f386dac..39bb5d28e 100644 --- a/usermods/usermod_v2_four_line_display_ALT/readme.md +++ b/usermods/usermod_v2_four_line_display_ALT/readme.md @@ -1,16 +1,8 @@ # I2C/SPI 4 Line Display Usermod ALT -Thank you to the authors of the original version of these usermods. It would not have been possible without them! -"usermod_v2_four_line_display" -"usermod_v2_rotary_encoder_ui" +This usermod could be used in compination with `usermod_v2_rotary_encoder_ui_ALT`. -The core of these usermods are a copy of the originals. The main changes are to the FourLineDisplay usermod. -The display usermod UI has been completely changed. - - -The changes made to the RotaryEncoder usermod were made to support the new UI in the display usermod. -Without the display, it functions identical to the original. -The original "usermod_v2_auto_save" will not work with the display just yet. +## Functionalities Press the encoder to cycle through the options: * Brightness @@ -18,26 +10,18 @@ Press the encoder to cycle through the options: * Intensity * Palette * Effect -* Main Color (only if display is used) -* Saturation (only if display is used) +* Main Color +* Saturation -Press and hold the encoder to display Network Info. If AP is active, it will display AP, SSID and password +Press and hold the encoder to display Network Info. If AP is active, it will display the AP, SSID and Password -Also shows if the timer is enabled +Also shows if the timer is enabled. [See the pair of usermods in action](https://www.youtube.com/watch?v=ulZnBt9z3TI) ## Installation -Please refer to the original `usermod_v2_rotary_encoder_ui` readme for the main instructions. - -Copy the example `platformio_override.sample.ini` from the usermod_v2_rotary_encoder_ui_ALT folder to the root directory of your particular build and rename it to `platformio_override.ini`. - -This file should be placed in the same directory as `platformio.ini`. - -Then, to activate this alternative usermod, add `#define USE_ALT_DISPlAY` (NOTE: CASE SENSITIVE) to the `usermods_list.cpp` file, - or add `-D USE_ALT_DISPlAY` to the original `platformio_override.ini.sample` file - +Copy the example `platformio_override.sample.ini` to the root directory of your particular build. ## Configuration diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/platformio_override.sample.ini b/usermods/usermod_v2_rotary_encoder_ui_ALT/platformio_override.sample.ini new file mode 100644 index 000000000..8a88fd6b5 --- /dev/null +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/platformio_override.sample.ini @@ -0,0 +1,14 @@ +[platformio] +default_envs = esp32dev + +[env:esp32dev] +board = esp32dev +platform = ${esp32.platform} +build_unflags = ${common.build_unflags} +build_flags = + ${common.build_flags_esp32} + -D USERMOD_ROTARY_ENCODER_UI + -D USERMOD_ROTARY_ENCODER_GPIO=INPUT + -D ENCODER_DT_PIN=21 + -D ENCODER_CLK_PIN=23 + -D ENCODER_SW_PIN=0 diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/readme.md b/usermods/usermod_v2_rotary_encoder_ui_ALT/readme.md index 10db879fb..c46e87663 100644 --- a/usermods/usermod_v2_rotary_encoder_ui_ALT/readme.md +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/readme.md @@ -1,16 +1,8 @@ # Rotary Encoder UI Usermod ALT -Thank you to the authors of the original version of these usermods. It would not have been possible without them! -"usermod_v2_four_line_display" -"usermod_v2_rotary_encoder_ui" +This usermod supports the UI of the `usermod_v2_rotary_encoder_ui_ALT`. -The core of these usermods are a copy of the originals. The main changes are to the FourLineDisplay usermod. -The display usermod UI has been completely changed. - - -The changes made to the RotaryEncoder usermod were made to support the new UI in the display usermod. -Without the display, it functions identical to the original. -The original "usermod_v2_auto_save" will not work with the display just yet. +## Functionalities Press the encoder to cycle through the options: * Brightness @@ -21,8 +13,7 @@ Press the encoder to cycle through the options: * Main Color (only if display is used) * Saturation (only if display is used) -Press and hold the encoder to display Network Info - if AP is active, it will display the AP, SSID and Password +Press and hold the encoder to display Network Info. If AP is active, it will display the AP, SSID and Password Also shows if the timer is enabled. @@ -30,9 +21,7 @@ Also shows if the timer is enabled. ## Installation -Copy the example `platformio_override.sample.ini` to the root directory of your particular build and rename it to `platformio_override.ini`. - -To activate this alternative usermod, add `#define USE_ALT_DISPlAY` (NOTE: CASE SENSITIVE) to the `usermods_list.cpp` file, or add `-D USE_ALT_DISPlAY` to your `platformio_override.ini` file +Copy the example `platformio_override.sample.ini` to the root directory of your particular build. ### Define Your Options @@ -40,7 +29,6 @@ To activate this alternative usermod, add `#define USE_ALT_DISPlAY` (NOTE: CASE * `USERMOD_FOUR_LINE_DISPLAY` - define this to have this the Four Line Display mod included wled00\usermods_list.cpp also tells this usermod that the display is available (see the Four Line Display usermod `readme.md` for more details) -* `USE_ALT_DISPlAY` - Mandatory to use Four Line Display * `ENCODER_DT_PIN` - defaults to 18 * `ENCODER_CLK_PIN` - defaults to 5 * `ENCODER_SW_PIN` - defaults to 19 @@ -50,7 +38,7 @@ To activate this alternative usermod, add `#define USE_ALT_DISPlAY` (NOTE: CASE ### PlatformIO requirements -Note: the Four Line Display usermod requires the libraries `U8g2` and `Wire`. +No special requirements. ## Change Log From 4cc2cc4ad40b4611124587f7496f1554abd9ef07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sat, 26 Oct 2024 15:16:11 +0200 Subject: [PATCH 100/234] Multiple fixes - increase WLED_MAX_BUSSES for C3 (fixes #4215) - fix for #4228 - fix for very long running effect (strip.now, strip.timebase) - C++ API change to allow `seg.setColor().setOpacity()` --- .../stairway-wipe-usermod-v2.h | 2 +- .../stairway_wipe_basic/wled06_usermod.ino | 2 +- wled00/FX.h | 35 ++++++---- wled00/FX_2Dfcn.cpp | 4 +- wled00/FX_fcn.cpp | 70 ++++++++----------- wled00/button.cpp | 1 + wled00/const.h | 2 +- wled00/fcn_declare.h | 1 - wled00/json.cpp | 4 +- wled00/led.cpp | 9 +-- wled00/wled.h | 2 +- 11 files changed, 62 insertions(+), 70 deletions(-) diff --git a/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h b/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h index f712316b8..707479df1 100644 --- a/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h +++ b/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h @@ -96,7 +96,7 @@ void setup() { jsonTransitionOnce = true; strip.setTransition(0); //no transition effectCurrent = FX_MODE_COLOR_WIPE; - resetTimebase(); //make sure wipe starts from beginning + strip.resetTimebase(); //make sure wipe starts from beginning //set wipe direction Segment& seg = strip.getSegment(0); diff --git a/usermods/stairway_wipe_basic/wled06_usermod.ino b/usermods/stairway_wipe_basic/wled06_usermod.ino index c1264ebfb..dc2159ee9 100644 --- a/usermods/stairway_wipe_basic/wled06_usermod.ino +++ b/usermods/stairway_wipe_basic/wled06_usermod.ino @@ -86,7 +86,7 @@ void startWipe() bri = briLast; //turn on transitionDelayTemp = 0; //no transition effectCurrent = FX_MODE_COLOR_WIPE; - resetTimebase(); //make sure wipe starts from beginning + strip.resetTimebase(); //make sure wipe starts from beginning //set wipe direction Segment& seg = strip.getSegment(0); diff --git a/wled00/FX.h b/wled00/FX.h index 385c52476..ad39a7c06 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -525,12 +525,12 @@ typedef struct Segment { inline static const CRGBPalette16 &getCurrentPalette() { return Segment::_currentPalette; } void setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1); - bool setColor(uint8_t slot, uint32_t c); //returns true if changed - void setCCT(uint16_t k); - void setOpacity(uint8_t o); - void setOption(uint8_t n, bool val); - void setMode(uint8_t fx, bool loadDefaults = false); - void setPalette(uint8_t pal); + Segment &setColor(uint8_t slot, uint32_t c); + Segment &setCCT(uint16_t k); + Segment &setOpacity(uint8_t o); + Segment &setOption(uint8_t n, bool val); + Segment &setMode(uint8_t fx, bool loadDefaults = false); + Segment &setPalette(uint8_t pal); uint8_t differs(Segment& b) const; void refreshLightCapabilities(); @@ -545,7 +545,7 @@ typedef struct Segment { * Call resetIfRequired before calling the next effect function. * Safe to call from interrupts and network requests. */ - inline void markForReset() { reset = true; } // setOption(SEG_OPTION_RESET, true) + inline Segment &markForReset() { reset = true; return *this; } // setOption(SEG_OPTION_RESET, true) // transition functions void startTransition(uint16_t dur); // transition has to start before actual segment values change @@ -599,9 +599,15 @@ typedef struct Segment { } // 2D matrix - [[gnu::hot]] uint16_t virtualWidth() const; // segment width in virtual pixels (accounts for groupping and spacing) - [[gnu::hot]] uint16_t virtualHeight() const; // segment height in virtual pixels (accounts for groupping and spacing) - uint16_t nrOfVStrips() const; // returns number of virtual vertical strips in 2D matrix (used to expand 1D effects into 2D) + [[gnu::hot]] unsigned virtualWidth() const; // segment width in virtual pixels (accounts for groupping and spacing) + [[gnu::hot]] unsigned virtualHeight() const; // segment height in virtual pixels (accounts for groupping and spacing) + inline unsigned nrOfVStrips() const { // returns number of virtual vertical strips in 2D matrix (used to expand 1D effects into 2D) + #ifndef WLED_DISABLE_2D + return (is2D() && map1D2D == M12_pBar) ? virtualWidth() : 1; + #else + return 1; + #endif + } #ifndef WLED_DISABLE_2D [[gnu::hot]] uint16_t XY(int x, int y); // support function to get relative index within segment [[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color @@ -778,7 +784,8 @@ class WS2812FX { // 96 bytes setTargetFps(uint8_t fps), setupEffectData(); // add default effects to the list; defined in FX.cpp - inline void restartRuntime() { for (Segment &seg : _segments) seg.markForReset(); } + inline void resetTimebase() { timebase = 0UL - millis(); } + inline void restartRuntime() { for (Segment &seg : _segments) { seg.markForReset().resetIfRequired(); } } inline void setTransitionMode(bool t) { for (Segment &seg : _segments) seg.startTransition(t ? _transitionDur : 0); } inline void setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setColor(slot, RGBW32(r,g,b,w)); } inline void setPixelColor(unsigned n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } @@ -834,10 +841,8 @@ class WS2812FX { // 96 bytes inline uint16_t getLength() const { return _length; } // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H) inline uint16_t getTransition() const { return _transitionDur; } // returns currently set transition time (in ms) - uint32_t - now, - timebase, - getPixelColor(uint16_t) const; + unsigned long now, timebase; + uint32_t getPixelColor(unsigned) const; inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call inline uint32_t segColor(uint8_t i) const { return _colors_t[i]; } // returns currently valid color (for slot i) AKA SEGCOLOR(); may be blended between two colors while in transition diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index e38602ebc..7c1ae366b 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -156,7 +156,7 @@ uint16_t IRAM_ATTR_YN Segment::XY(int x, int y) void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) { if (!isActive()) return; // not active - if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit + if ((unsigned)x >= virtualWidth() || (unsigned)y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit uint8_t _bri_t = currentBri(); if (_bri_t < 255) { @@ -251,7 +251,7 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa) // returns RGBW values of pixel uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const { if (!isActive()) return 0; // not active - if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit + if ((unsigned)x >= virtualWidth() || (unsigned)y >= virtualHeight() || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit if (reverse ) x = virtualWidth() - x - 1; if (reverse_y) y = virtualHeight() - y - 1; if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 79189ef57..949b6a932 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -509,46 +509,53 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t } -bool Segment::setColor(uint8_t slot, uint32_t c) { //returns true if changed - if (slot >= NUM_COLORS || c == colors[slot]) return false; +Segment &Segment::setColor(uint8_t slot, uint32_t c) { + if (slot >= NUM_COLORS || c == colors[slot]) return *this; if (!_isRGB && !_hasW) { - if (slot == 0 && c == BLACK) return false; // on/off segment cannot have primary color black - if (slot == 1 && c != BLACK) return false; // on/off segment cannot have secondary color non black + if (slot == 0 && c == BLACK) return *this; // on/off segment cannot have primary color black + if (slot == 1 && c != BLACK) return *this; // on/off segment cannot have secondary color non black } if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change colors[slot] = c; stateChanged = true; // send UDP/WS broadcast - return true; + return *this; } -void Segment::setCCT(uint16_t k) { +Segment &Segment::setCCT(uint16_t k) { if (k > 255) { //kelvin value, convert to 0-255 if (k < 1900) k = 1900; if (k > 10091) k = 10091; k = (k - 1900) >> 5; } - if (cct == k) return; - if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change - cct = k; - stateChanged = true; // send UDP/WS broadcast + if (cct != k) { + //DEBUGFX_PRINTF_P(PSTR("- Starting CCT transition: %d\n"), k); + startTransition(strip.getTransition()); // start transition prior to change + cct = k; + stateChanged = true; // send UDP/WS broadcast + } + return *this; } -void Segment::setOpacity(uint8_t o) { - if (opacity == o) return; - if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change - opacity = o; - stateChanged = true; // send UDP/WS broadcast +Segment &Segment::setOpacity(uint8_t o) { + if (opacity != o) { + //DEBUGFX_PRINTF_P(PSTR("- Starting opacity transition: %d\n"), o); + startTransition(strip.getTransition()); // start transition prior to change + opacity = o; + stateChanged = true; // send UDP/WS broadcast + } + return *this; } -void Segment::setOption(uint8_t n, bool val) { +Segment &Segment::setOption(uint8_t n, bool val) { bool prevOn = on; if (fadeTransition && n == SEG_OPTION_ON && val != prevOn) startTransition(strip.getTransition()); // start transition prior to change if (val) options |= 0x01 << n; else options &= ~(0x01 << n); if (!(n == SEG_OPTION_SELECTED || n == SEG_OPTION_RESET)) stateChanged = true; // send UDP/WS broadcast + return *this; } -void Segment::setMode(uint8_t fx, bool loadDefaults) { +Segment &Segment::setMode(uint8_t fx, bool loadDefaults) { // skip reserved while (fx < strip.getModeCount() && strncmp_P("RSVD", strip.getModeData(fx), 4) == 0) fx++; if (fx >= strip.getModeCount()) fx = 0; // set solid mode @@ -580,9 +587,10 @@ void Segment::setMode(uint8_t fx, bool loadDefaults) { markForReset(); stateChanged = true; // send UDP/WS broadcast } + return *this; } -void Segment::setPalette(uint8_t pal) { +Segment &Segment::setPalette(uint8_t pal) { if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0; // built in palettes if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0; // custom palettes if (pal != palette) { @@ -590,37 +598,24 @@ void Segment::setPalette(uint8_t pal) { palette = pal; stateChanged = true; // send UDP/WS broadcast } + return *this; } // 2D matrix -uint16_t IRAM_ATTR Segment::virtualWidth() const { +unsigned IRAM_ATTR Segment::virtualWidth() const { unsigned groupLen = groupLength(); unsigned vWidth = ((transpose ? height() : width()) + groupLen - 1) / groupLen; if (mirror) vWidth = (vWidth + 1) /2; // divide by 2 if mirror, leave at least a single LED return vWidth; } -uint16_t IRAM_ATTR Segment::virtualHeight() const { +unsigned IRAM_ATTR Segment::virtualHeight() const { unsigned groupLen = groupLength(); unsigned vHeight = ((transpose ? width() : height()) + groupLen - 1) / groupLen; if (mirror_y) vHeight = (vHeight + 1) /2; // divide by 2 if mirror, leave at least a single LED return vHeight; } -uint16_t IRAM_ATTR_YN Segment::nrOfVStrips() const { - unsigned vLen = 1; -#ifndef WLED_DISABLE_2D - if (is2D()) { - switch (map1D2D) { - case M12_pBar: - vLen = virtualWidth(); - break; - } - } -#endif - return vLen; -} - // Constants for mapping mode "Pinwheel" #ifndef WLED_DISABLE_2D constexpr int Pinwheel_Steps_Small = 72; // no holes up to 16x16 @@ -1187,10 +1182,7 @@ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_ //do not call this method from system context (network callback) void WS2812FX::finalizeInit() { //reset segment runtimes - for (segment &seg : _segments) { - seg.markForReset(); - seg.resetIfRequired(); - } + restartRuntime(); // for the lack of better place enumerate ledmaps here // if we do it in json.cpp (serializeInfo()) we are getting flashes on LEDs @@ -1402,7 +1394,7 @@ void IRAM_ATTR WS2812FX::setPixelColor(unsigned i, uint32_t col) { BusManager::setPixelColor(i, col); } -uint32_t IRAM_ATTR WS2812FX::getPixelColor(uint16_t i) const { +uint32_t IRAM_ATTR WS2812FX::getPixelColor(unsigned i) const { i = getMappedPixelIndex(i); if (i >= _length) return 0; return BusManager::getPixelColor(i); diff --git a/wled00/button.cpp b/wled00/button.cpp index f02ed3d6d..4d6f954f6 100644 --- a/wled00/button.cpp +++ b/wled00/button.cpp @@ -215,6 +215,7 @@ void handleAnalog(uint8_t b) briLast = bri; bri = 0; } else { + if (bri == 0) strip.restartRuntime(); bri = aRead; } } else if (macroDoublePress[b] == 249) { diff --git a/wled00/const.h b/wled00/const.h index 14ec23b58..07873deca 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -53,7 +53,7 @@ #else #define WLED_MAX_ANALOG_CHANNELS (LEDC_CHANNEL_MAX*LEDC_SPEED_MODE_MAX) #if defined(CONFIG_IDF_TARGET_ESP32C3) // 2 RMT, 6 LEDC, only has 1 I2S but NPB does not support it ATM - #define WLED_MAX_BUSSES 4 // will allow 2 digital & 2 analog RGB + #define WLED_MAX_BUSSES 6 // will allow 2 digital & 2 analog RGB or 6 PWM white #define WLED_MAX_DIGITAL_CHANNELS 2 //#define WLED_MAX_ANALOG_CHANNELS 6 #define WLED_MIN_VIRTUAL_BUSSES 3 diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index d44ed43a0..1855a8b63 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -169,7 +169,6 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0); void setValuesFromSegment(uint8_t s); void setValuesFromMainSeg(); void setValuesFromFirstSelectedSeg(); -void resetTimebase(); void toggleOnOff(); void applyBri(); void applyFinalBri(); diff --git a/wled00/json.cpp b/wled00/json.cpp index 06eb3015e..288059653 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -346,7 +346,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) } } - int tr = -1; + long tr = -1; if (!presetId || currentPlaylist < 0) { //do not apply transition time from preset if playlist active, as it would override playlist transition times tr = root[F("transition")] | -1; if (tr >= 0) { @@ -363,7 +363,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) } tr = root[F("tb")] | -1; - if (tr >= 0) strip.timebase = ((uint32_t)tr) - millis(); + if (tr >= 0) strip.timebase = (unsigned long)tr - millis(); JsonObject nl = root["nl"]; nightlightActive = getBoolVal(nl["on"], nightlightActive); diff --git a/wled00/led.cpp b/wled00/led.cpp index 9de0495b4..9b97091e6 100644 --- a/wled00/led.cpp +++ b/wled00/led.cpp @@ -47,17 +47,12 @@ void applyValuesToSelectedSegs() } -void resetTimebase() -{ - strip.timebase = 0 - millis(); -} - - void toggleOnOff() { if (bri == 0) { bri = briLast; + strip.restartRuntime(); } else { briLast = bri; @@ -122,7 +117,7 @@ void stateUpdated(byte callMode) { nightlightStartTime = millis(); } if (briT == 0) { - if (callMode != CALL_MODE_NOTIFICATION) resetTimebase(); //effect start from beginning + if (callMode != CALL_MODE_NOTIFICATION) strip.resetTimebase(); //effect start from beginning } if (bri > 0) briLast = bri; diff --git a/wled00/wled.h b/wled00/wled.h index bc525cd6f..912e0b3c0 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2410140 +#define VERSION 2410260 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG From 798c398f23f9ea2c6e826acafa5a4a81ce35945a Mon Sep 17 00:00:00 2001 From: maxi4329 Date: Sat, 26 Oct 2024 20:33:38 +0200 Subject: [PATCH 101/234] specified required nodejs ver --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index d76d87687..0c016329b 100644 --- a/package.json +++ b/package.json @@ -27,5 +27,8 @@ "html-minifier-terser": "^7.2.0", "inliner": "^1.13.1", "nodemon": "^3.1.7" + }, + "engines": { + "node": ">=20.0.0" } } From 7c6bc5c4211c5c45342b2b833bf3d04991ee76ea Mon Sep 17 00:00:00 2001 From: maxi4329 Date: Sat, 26 Oct 2024 21:07:17 +0200 Subject: [PATCH 102/234] indened formating --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0c016329b..35fda6002 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,6 @@ "nodemon": "^3.1.7" }, "engines": { - "node": ">=20.0.0" + "node": ">=21.0.0" } } From d05c358fd23d86697ec343b9c46c231d30346fcb Mon Sep 17 00:00:00 2001 From: maxi4329 Date: Sun, 27 Oct 2024 11:13:56 +0100 Subject: [PATCH 103/234] version changed to 20 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 35fda6002..0c016329b 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,6 @@ "nodemon": "^3.1.7" }, "engines": { - "node": ">=21.0.0" + "node": ">=20.0.0" } } From 2703c9899afd6a9c6f3f41eccce03b6b11208a0a Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 27 Oct 2024 15:08:25 +0100 Subject: [PATCH 104/234] Bugfix in FX `ripple_base()` --- wled00/FX.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index d4b83de6c..2f24f745a 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2506,9 +2506,9 @@ static uint16_t ripple_base() { #endif { int left = rippleorigin - propI -1; - int right = rippleorigin + propI +3; + int right = rippleorigin + propI +2; for (int v = 0; v < 4; v++) { - unsigned mag = scale8(cubicwave8((propF>>2)+(v-left)*64), amp); + unsigned mag = scale8(cubicwave8((propF>>2) + v * 64), amp); SEGMENT.setPixelColor(left + v, color_blend(SEGMENT.getPixelColor(left + v), col, mag)); // TODO SEGMENT.setPixelColor(right - v, color_blend(SEGMENT.getPixelColor(right - v), col, mag)); // TODO } From 6e89346f00e8b240915313f9d99a9121cbc60190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sun, 27 Oct 2024 18:47:10 +0100 Subject: [PATCH 105/234] WLED 0.15.0-b7 release - fix for #4172 - fix for #4230 - /json/live enabled when WS disabled --- CHANGELOG.md | 6 ++++++ package-lock.json | 4 ++-- package.json | 2 +- wled00/data/index.css | 7 ++++++- wled00/wled.h | 7 ++++--- wled00/xml.cpp | 2 +- 6 files changed, 20 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dad83d9b..452e02b25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ ## WLED changelog +#### Build 2410270 +- WLED 0.15.0-b7 release +- Add visual expand button on hover (#4172) +- `/json/live` (JSON live data/peek) only enabled when WebSockets are disabled +- Bugfixes: #4179, #4215, #4219, #4224, #4228, #4230 + #### Build 2410140 - WLED 0.15.0-b6 release - Added BRT timezone (#4188 by @LuisFadini) diff --git a/package-lock.json b/package-lock.json index 85ee1df0f..0f73bff0c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "wled", - "version": "0.15.0-b6", + "version": "0.15.0-b7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "wled", - "version": "0.15.0-b6", + "version": "0.15.0-b7", "license": "ISC", "dependencies": { "clean-css": "^5.3.3", diff --git a/package.json b/package.json index d76d87687..9d095c82c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wled", - "version": "0.15.0-b6", + "version": "0.15.0-b7", "description": "Tools for WLED project", "main": "tools/cdata.js", "directories": { diff --git a/wled00/data/index.css b/wled00/data/index.css index 6f465e407..0e36ff08c 100644 --- a/wled00/data/index.css +++ b/wled00/data/index.css @@ -1040,7 +1040,7 @@ textarea { .segname .flr, .pname .flr { transform: rotate(0deg); - right: -6px; + /*right: -6px;*/ } /* segment power wrapper */ @@ -1335,6 +1335,11 @@ TD .checkmark, TD .radiomark { box-shadow: 0 0 10px 4px var(--c-1); } +.lstI .flr:hover { + background: var(--c-6); + border-radius: 100%; +} + #pcont .selected:not([class*="expanded"]) { bottom: 52px; top: 42px; diff --git a/wled00/wled.h b/wled00/wled.h index 912e0b3c0..2b3a77d24 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -3,12 +3,12 @@ /* Main sketch, global variable declarations @title WLED project sketch - @version 0.15.0-b6 + @version 0.15.0-b7 @author Christian Schwinne */ // version code in format yymmddb (b = daily build) -#define VERSION 2410260 +#define VERSION 2410270 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG @@ -36,12 +36,13 @@ #undef WLED_ENABLE_ADALIGHT // disable has priority over enable #endif //#define WLED_ENABLE_DMX // uses 3.5kb -//#define WLED_ENABLE_JSONLIVE // peek LED output via /json/live (WS binary peek is always enabled) #ifndef WLED_DISABLE_LOXONE #define WLED_ENABLE_LOXONE // uses 1.2kb #endif #ifndef WLED_DISABLE_WEBSOCKETS #define WLED_ENABLE_WEBSOCKETS +#else + #define WLED_ENABLE_JSONLIVE // peek LED output via /json/live (WS binary peek is always enabled) #endif //#define WLED_DISABLE_ESPNOW // Removes dependence on esp now diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 6d1ff2f86..dc2673271 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -501,7 +501,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) #endif printSetFormValue(settingsScript,PSTR("BD"),serialBaud); #ifndef WLED_ENABLE_ADALIGHT - settingsScript.print(F("toggle('Serial);")); + settingsScript.print(F("toggle('Serial');")); #endif } From 4588219e3134481a9f3dc66077811bf5d16f7f88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Mon, 28 Oct 2024 12:42:53 +0100 Subject: [PATCH 106/234] Update changelog --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 452e02b25..c570ac1f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,12 @@ #### Build 2410270 - WLED 0.15.0-b7 release +- Re-license the WLED project from MIT to EUPL (#4194 by @Aircoookie) +- Fix alexa devices invisible/uncontrollable (#4214 by @Svennte) - Add visual expand button on hover (#4172) +- Usermod: Audioreactive tuning and performance enhancements (by @softhack007) - `/json/live` (JSON live data/peek) only enabled when WebSockets are disabled -- Bugfixes: #4179, #4215, #4219, #4224, #4228, #4230 +- Various bugfixes and optimisations: #4179, #4215, #4219, #4222, #4223, #4224, #4228, #4230 #### Build 2410140 - WLED 0.15.0-b6 release From fa053b7e60effbbb76dc49822003ea5acb4b4dcf Mon Sep 17 00:00:00 2001 From: ingDIY <10012263+ingDIY@users.noreply.github.com> Date: Tue, 29 Oct 2024 01:14:02 +0100 Subject: [PATCH 107/234] Update platformio_override.sample.ini fixed back U8g2 version --- .../platformio_override.sample.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usermods/usermod_v2_four_line_display_ALT/platformio_override.sample.ini b/usermods/usermod_v2_four_line_display_ALT/platformio_override.sample.ini index 9010648b3..e59637453 100644 --- a/usermods/usermod_v2_four_line_display_ALT/platformio_override.sample.ini +++ b/usermods/usermod_v2_four_line_display_ALT/platformio_override.sample.ini @@ -14,5 +14,5 @@ build_flags = lib_deps = ${esp32.lib_deps} - U8g2 + U8g2@~2.34.4 Wire From 1898be2fe1c9c3e9c05b5b41d2a2d9b597930156 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Fri, 1 Nov 2024 21:13:43 +0100 Subject: [PATCH 108/234] S3 WROOM-2 buildenv this chip has 16MB or 32MB flash, and requires .memory_type = opi_opi --- platformio.ini | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/platformio.ini b/platformio.ini index 9628722aa..48731f39b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -556,6 +556,32 @@ board_build.f_flash = 80000000L board_build.flash_mode = qio monitor_filters = esp32_exception_decoder +[env:esp32S3_wroom2] +;; For ESP32-S3 WROOM-2, a.k.a. ESP32-S3 DevKitC-1 v1.1 +;; with >= 16MB FLASH and >= 8MB PSRAM (memory_type: opi_opi) +platform = ${esp32s3.platform} +platform_packages = ${esp32s3.platform_packages} +board = esp32s3camlcd ;; this is the only standard board with "opi_opi" +board_build.arduino.memory_type = opi_opi +upload_speed = 921600 +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=ESP32-S3_WROOM-2 + -D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0 + -D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip + ;; -D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB") + -DBOARD_HAS_PSRAM + -D LEDPIN=38 ;; buildin LED + -D BTNPIN=0 -D RLYPIN=16 -D IRPIN=17 -D AUDIOPIN=-1 + ${esp32.AR_build_flags} + -D SR_DMTYPE=1 -D I2S_SDPIN=13 -D I2S_CKPIN=14 -D I2S_WSPIN=15 -D MCLK_PIN=4 ;; I2S mic +lib_deps = ${esp32s3.lib_deps} + ${esp32.AR_lib_deps} + +board_build.partitions = ${esp32.extreme_partitions} +board_upload.flash_size = 16MB +board_upload.maximum_size = 16777216 +monitor_filters = esp32_exception_decoder + [env:esp32s3_4M_qspi] ;; ESP32-S3, with 4MB FLASH and <= 4MB PSRAM (memory_type: qio_qspi) board = lolin_s3_mini ;; -S3 mini, 4MB flash 2MB PSRAM From 749d34cd30a76e7c17be04f71016960d2331a4de Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Fri, 1 Nov 2024 21:31:57 +0100 Subject: [PATCH 109/234] pinmanager support for S3 WROOM-2 (pin 33-37 reserved for flash) --- wled00/pin_manager.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index 793b5440c..0d4c2ad5c 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -201,7 +201,12 @@ bool PinManager::isPinOk(byte gpio, bool output) if (gpio > 18 && gpio < 21) return false; // 19 + 20 = USB-JTAG. Not recommended for other uses. #endif if (gpio > 21 && gpio < 33) return false; // 22 to 32: not connected + SPI FLASH - if (gpio > 32 && gpio < 38) return !psramFound(); // 33 to 37: not available if using _octal_ SPI Flash or _octal_ PSRAM + #if CONFIG_ESPTOOLPY_FLASHMODE_OPI // 33-37: never available if using _octal_ Flash (opi_opi) + if (gpio > 32 && gpio < 38) return false; + #endif + #if CONFIG_SPIRAM_MODE_OCT // 33-37: not available if using _octal_ PSRAM (qio_opi), but free to use on _quad_ PSRAM (qio_qspi) + if (gpio > 32 && gpio < 38) return !psramFound(); + #endif // 38 to 48 are for general use. Be careful about straping pins GPIO45 and GPIO46 - these may be pull-up or pulled-down on your board. #elif defined(CONFIG_IDF_TARGET_ESP32S2) // strapping pins: 0, 45 & 46 From 3c2c5bedc50845c168f7e0881e3a1d6aa973e7d5 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Fri, 1 Nov 2024 21:42:54 +0100 Subject: [PATCH 110/234] LEDPIN --> DATA_PINS --- platformio.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 48731f39b..6d4aa1dc1 100644 --- a/platformio.ini +++ b/platformio.ini @@ -570,8 +570,9 @@ build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME= -D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip ;; -D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB") -DBOARD_HAS_PSRAM - -D LEDPIN=38 ;; buildin LED + -D LEDPIN=38 -D DATA_PINS=38 ;; buildin WS2812b LED -D BTNPIN=0 -D RLYPIN=16 -D IRPIN=17 -D AUDIOPIN=-1 + -D WLED_DEBUG ${esp32.AR_build_flags} -D SR_DMTYPE=1 -D I2S_SDPIN=13 -D I2S_CKPIN=14 -D I2S_WSPIN=15 -D MCLK_PIN=4 ;; I2S mic lib_deps = ${esp32s3.lib_deps} From d98ca9a202795f9851bbeca7e895cb790abd2727 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Fri, 1 Nov 2024 21:51:46 +0100 Subject: [PATCH 111/234] show correct flash mode in WLED_DEBUG --- wled00/wled.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 13d43218a..d6a39a399 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -380,6 +380,12 @@ void WLED::setup() case FM_QOUT: DEBUG_PRINT(F("(QOUT)"));break; case FM_DIO: DEBUG_PRINT(F("(DIO)")); break; case FM_DOUT: DEBUG_PRINT(F("(DOUT)"));break; + #if defined(CONFIG_IDF_TARGET_ESP32S3) && CONFIG_ESPTOOLPY_FLASHMODE_OPI + case FM_FAST_READ: DEBUG_PRINT(F("(OPI)")); break; + #else + case FM_FAST_READ: DEBUG_PRINT(F("(fast_read)")); break; + #endif + case FM_SLOW_READ: DEBUG_PRINT(F("(slow_read)")); break; default: break; } #endif From 451cd4c74aff2faff9ab11f746f9e454ab10bd2e Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Fri, 1 Nov 2024 23:19:38 +0100 Subject: [PATCH 112/234] Improved framerate control in strip.show(), strip.service() * separate fps calculation (strip.show) from framerate control (strio.service) * improved condition for early exit in strip.show * make MIN_SHOW_DELAY depend on target fps * strip.show consideres complete time for effect calculation + show; old code wrongly used the time between completion of last show and start of next effect drawing, causing unexpected slowdown * add "unlimited FPS mode" for testing * increase warning limits for "slow strip" and "slow effects" --- wled00/FX.h | 22 +++++++++++++++++----- wled00/FX_fcn.cpp | 37 +++++++++++++++++++++++++++---------- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index ad39a7c06..acdb62c81 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -44,8 +44,20 @@ /* Not used in all effects yet */ #define WLED_FPS 42 -#define FRAMETIME_FIXED (1000/WLED_FPS) #define FRAMETIME strip.getFrameTime() +#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) // all ESP32 except -C3(very slow, untested) + #define FRAMETIME_FIXED (strip.getFrameTime() < 10 ? 12 : 24) // allow faster FRAMETIME_FIXED when target FPS >= 100 + #define MIN_SHOW_DELAY (max(2, (_frametime*5)/8)) // supports higher framerates and better animation control -- 5/8 = 62% + // used to initialize for strip attributes: + #define WLED_FPS_SLOW 42 + #define FRAMETIME_FIXED_SLOW (24) // 1000/42 = 24ms +#else + #define FRAMETIME_FIXED (1000/WLED_FPS) + #define MIN_SHOW_DELAY (_frametime < 16 ? 8 : 15) // legacy MIN_SHOW_DELAY - creates more idle loops, but reduces framerates + #define WLED_FPS_SLOW WLED_FPS + #define FRAMETIME_FIXED_SLOW FRAMETIME_FIXED +#endif +#define FPS_UNLIMITED 119 /* each segment uses 82 bytes of SRAM memory, so if you're application fails because of insufficient memory, decreasing MAX_NUM_SEGMENTS may help */ @@ -68,8 +80,6 @@ assuming each segment uses the same amount of data. 256 for ESP8266, 640 for ESP32. */ #define FAIR_DATA_PER_SEG (MAX_SEGMENT_DATA / strip.getMaxSegments()) -#define MIN_SHOW_DELAY (_frametime < 16 ? 8 : 15) - #define NUM_COLORS 3 /* number of colors per segment */ #define SEGMENT strip._segments[strip.getCurrSegmentId()] #define SEGENV strip._segments[strip.getCurrSegmentId()] @@ -727,8 +737,8 @@ class WS2812FX { // 96 bytes _length(DEFAULT_LED_COUNT), _brightness(DEFAULT_BRIGHTNESS), _transitionDur(750), - _targetFps(WLED_FPS), - _frametime(FRAMETIME_FIXED), + _targetFps(WLED_FPS_SLOW), + _frametime(FRAMETIME_FIXED_SLOW), _cumulativeFps(2), _isServicing(false), _isOffRefreshRequired(false), @@ -739,6 +749,7 @@ class WS2812FX { // 96 bytes customMappingTable(nullptr), customMappingSize(0), _lastShow(0), + _lastServiceShow(0), _segment_index(0), _mainSegment(0) { @@ -949,6 +960,7 @@ class WS2812FX { // 96 bytes uint16_t customMappingSize; unsigned long _lastShow; + unsigned long _lastServiceShow; uint8_t _segment_index; uint8_t _mainSegment; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 949b6a932..5856ad786 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1309,11 +1309,23 @@ void WS2812FX::finalizeInit() { void WS2812FX::service() { unsigned long nowUp = millis(); // Be aware, millis() rolls over every 49 days now = nowUp + timebase; - if (nowUp - _lastShow < MIN_SHOW_DELAY || _suspend) return; + if (_suspend) return; + unsigned long elapsed = nowUp - _lastServiceShow; + + #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) + if (elapsed < 2) return; // keep wifi alive + if ( !_triggered && (_targetFps < FPS_UNLIMITED) && (_targetFps > 0)) { + if (elapsed < MIN_SHOW_DELAY) return; // WLEDMM too early for service + } + #else // legacy + if (nowUp - _lastShow < MIN_SHOW_DELAY) return; + #endif + bool doShow = false; _isServicing = true; _segment_index = 0; + unsigned speedLimit = (_targetFps < FPS_UNLIMITED) ? (0.85f * FRAMETIME) : 1; // lower limit for effect frametime for (segment &seg : _segments) { if (_suspend) return; // immediately stop processing segments if suspend requested during service() @@ -1326,10 +1338,10 @@ void WS2812FX::service() { if (!seg.isActive()) continue; // last condition ensures all solid segments are updated at the same time - if (nowUp > seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC)) + if (nowUp >= seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC)) { doShow = true; - unsigned delay = FRAMETIME; + unsigned frameDelay = FRAMETIME; if (!seg.freeze) { //only run effect function if not frozen int oldCCT = BusManager::getSegmentCCT(); // store original CCT value (actually it is not Segment based) @@ -1349,7 +1361,8 @@ void WS2812FX::service() { // overwritten by later effect. To enable seamless blending for every effect, additional LED buffer // would need to be allocated for each effect and then blended together for each pixel. [[maybe_unused]] uint8_t tmpMode = seg.currentMode(); // this will return old mode while in transition - delay = (*_mode[seg.mode])(); // run new/current mode + frameDelay = (*_mode[seg.mode])(); // run new/current mode + if (frameDelay < speedLimit) frameDelay = FRAMETIME; // limit effects that want to go faster than target FPS #ifndef WLED_DISABLE_MODE_BLEND if (modeBlending && seg.mode != tmpMode) { Segment::tmpsegd_t _tmpSegData; @@ -1358,16 +1371,16 @@ void WS2812FX::service() { _virtualSegmentLength = seg.virtualLength(); // update SEGLEN (mapping may have changed) unsigned d2 = (*_mode[tmpMode])(); // run old mode seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state) - delay = MIN(delay,d2); // use shortest delay + frameDelay = min(frameDelay,d2); // use shortest delay Segment::modeBlend(false); // unset semaphore } #endif seg.call++; - if (seg.isInTransition() && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition + if (seg.isInTransition() && frameDelay > FRAMETIME) frameDelay = FRAMETIME; // force faster updates during transition BusManager::setSegmentCCT(oldCCT); // restore old CCT for ABL adjustments } - seg.next_time = nowUp + delay; + seg.next_time = nowUp + frameDelay; } _segment_index++; } @@ -1376,15 +1389,16 @@ void WS2812FX::service() { _triggered = false; #ifdef WLED_DEBUG - if (millis() - nowUp > _frametime) DEBUG_PRINTF_P(PSTR("Slow effects %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime); + if (millis() - nowUp > _frametime*2) DEBUG_PRINTF_P(PSTR("Slow effects %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime); #endif if (doShow) { yield(); Segment::handleRandomPalette(); // slowly transition random palette; move it into for loop when each segment has individual random palette show(); + _lastServiceShow = nowUp; // correct timestamp, for better FPS control } #ifdef WLED_DEBUG - if (millis() - nowUp > _frametime) DEBUG_PRINTF_P(PSTR("Slow strip %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime); + if (millis() - nowUp > _frametime*2) DEBUG_PRINTF_P(PSTR("Slow strip %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime); #endif } @@ -1404,18 +1418,19 @@ void WS2812FX::show() { // avoid race condition, capture _callback value show_callback callback = _callback; if (callback) callback(); + unsigned long showNow = millis(); // some buses send asynchronously and this method will return before // all of the data has been sent. // See https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods BusManager::show(); - unsigned long showNow = millis(); size_t diff = showNow - _lastShow; size_t fpsCurr = 200; if (diff > 0) fpsCurr = 1000 / diff; _cumulativeFps = (3 * _cumulativeFps + fpsCurr +2) >> 2; // "+2" for proper rounding (2/4 = 0.5) _lastShow = showNow; + _lastServiceShow = showNow; } /** @@ -1438,6 +1453,8 @@ uint16_t WS2812FX::getFps() const { void WS2812FX::setTargetFps(uint8_t fps) { if (fps > 0 && fps <= 120) _targetFps = fps; _frametime = 1000 / _targetFps; + if (_frametime < 1) _frametime = 1; // better safe than sorry + if (fps >= FPS_UNLIMITED) _frametime = 3; // unlimited mode } void WS2812FX::setMode(uint8_t segid, uint8_t m) { From 70323b947745e81644b955d3d16cc2bd24059636 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sat, 2 Nov 2024 17:50:30 +0100 Subject: [PATCH 113/234] rename delay -> frameDelay Avoiding name collisions with the 'delay' function. --- wled00/FX_fcn.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 949b6a932..f45256f0f 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1329,7 +1329,7 @@ void WS2812FX::service() { if (nowUp > seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC)) { doShow = true; - unsigned delay = FRAMETIME; + unsigned frameDelay = FRAMETIME; if (!seg.freeze) { //only run effect function if not frozen int oldCCT = BusManager::getSegmentCCT(); // store original CCT value (actually it is not Segment based) @@ -1349,7 +1349,7 @@ void WS2812FX::service() { // overwritten by later effect. To enable seamless blending for every effect, additional LED buffer // would need to be allocated for each effect and then blended together for each pixel. [[maybe_unused]] uint8_t tmpMode = seg.currentMode(); // this will return old mode while in transition - delay = (*_mode[seg.mode])(); // run new/current mode + frameDelay = (*_mode[seg.mode])(); // run new/current mode #ifndef WLED_DISABLE_MODE_BLEND if (modeBlending && seg.mode != tmpMode) { Segment::tmpsegd_t _tmpSegData; @@ -1358,16 +1358,16 @@ void WS2812FX::service() { _virtualSegmentLength = seg.virtualLength(); // update SEGLEN (mapping may have changed) unsigned d2 = (*_mode[tmpMode])(); // run old mode seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state) - delay = MIN(delay,d2); // use shortest delay + frameDelay = min(frameDelay,d2); // use shortest delay Segment::modeBlend(false); // unset semaphore } #endif seg.call++; - if (seg.isInTransition() && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition + if (seg.isInTransition() && frameDelay > FRAMETIME) frameDelay = FRAMETIME; // force faster updates during transition BusManager::setSegmentCCT(oldCCT); // restore old CCT for ABL adjustments } - seg.next_time = nowUp + delay; + seg.next_time = nowUp + frameDelay; } _segment_index++; } From 50934e6840995154109ab7d532dbb61af0377f90 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sat, 2 Nov 2024 18:16:51 +0100 Subject: [PATCH 114/234] adressing some review comments * keep FRAMETIME_FIXED as a fixed value * remove WLED_FPS_SLOW and FRAMETIME_FIXED_SLOW * explicit test "(_targetFps != FPS_UNLIMITED)" for debug messages * don't modify _lastServiceShow in show() * test for "fps == FPS_UNLIMITED" explicitly, so we could pick a different magic number later --- wled00/FX.h | 13 ++++--------- wled00/FX_fcn.cpp | 12 +++++------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index acdb62c81..1f0df9da3 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -44,20 +44,15 @@ /* Not used in all effects yet */ #define WLED_FPS 42 +#define FRAMETIME_FIXED (1000/WLED_FPS) #define FRAMETIME strip.getFrameTime() #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) // all ESP32 except -C3(very slow, untested) - #define FRAMETIME_FIXED (strip.getFrameTime() < 10 ? 12 : 24) // allow faster FRAMETIME_FIXED when target FPS >= 100 #define MIN_SHOW_DELAY (max(2, (_frametime*5)/8)) // supports higher framerates and better animation control -- 5/8 = 62% // used to initialize for strip attributes: - #define WLED_FPS_SLOW 42 - #define FRAMETIME_FIXED_SLOW (24) // 1000/42 = 24ms #else - #define FRAMETIME_FIXED (1000/WLED_FPS) #define MIN_SHOW_DELAY (_frametime < 16 ? 8 : 15) // legacy MIN_SHOW_DELAY - creates more idle loops, but reduces framerates - #define WLED_FPS_SLOW WLED_FPS - #define FRAMETIME_FIXED_SLOW FRAMETIME_FIXED #endif -#define FPS_UNLIMITED 119 +#define FPS_UNLIMITED 120 /* each segment uses 82 bytes of SRAM memory, so if you're application fails because of insufficient memory, decreasing MAX_NUM_SEGMENTS may help */ @@ -737,8 +732,8 @@ class WS2812FX { // 96 bytes _length(DEFAULT_LED_COUNT), _brightness(DEFAULT_BRIGHTNESS), _transitionDur(750), - _targetFps(WLED_FPS_SLOW), - _frametime(FRAMETIME_FIXED_SLOW), + _targetFps(WLED_FPS), + _frametime(FRAMETIME_FIXED), _cumulativeFps(2), _isServicing(false), _isOffRefreshRequired(false), diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 5856ad786..3972dad2c 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1314,7 +1314,7 @@ void WS2812FX::service() { #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) if (elapsed < 2) return; // keep wifi alive - if ( !_triggered && (_targetFps < FPS_UNLIMITED) && (_targetFps > 0)) { + if ( !_triggered && (_targetFps != FPS_UNLIMITED) && (_targetFps > 0)) { if (elapsed < MIN_SHOW_DELAY) return; // WLEDMM too early for service } #else // legacy @@ -1325,7 +1325,7 @@ void WS2812FX::service() { _isServicing = true; _segment_index = 0; - unsigned speedLimit = (_targetFps < FPS_UNLIMITED) ? (0.85f * FRAMETIME) : 1; // lower limit for effect frametime + unsigned speedLimit = (_targetFps != FPS_UNLIMITED) ? (0.85f * FRAMETIME) : 1; // lower limit for effect frametime for (segment &seg : _segments) { if (_suspend) return; // immediately stop processing segments if suspend requested during service() @@ -1389,7 +1389,7 @@ void WS2812FX::service() { _triggered = false; #ifdef WLED_DEBUG - if (millis() - nowUp > _frametime*2) DEBUG_PRINTF_P(PSTR("Slow effects %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime); + if ((_targetFps != FPS_UNLIMITED) && (millis() - nowUp > _frametime)) DEBUG_PRINTF_P(PSTR("Slow effects %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime); #endif if (doShow) { yield(); @@ -1398,7 +1398,7 @@ void WS2812FX::service() { _lastServiceShow = nowUp; // correct timestamp, for better FPS control } #ifdef WLED_DEBUG - if (millis() - nowUp > _frametime*2) DEBUG_PRINTF_P(PSTR("Slow strip %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime); + if ((_targetFps != FPS_UNLIMITED) && (millis() - nowUp > _frametime)) DEBUG_PRINTF_P(PSTR("Slow strip %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime); #endif } @@ -1430,7 +1430,6 @@ void WS2812FX::show() { if (diff > 0) fpsCurr = 1000 / diff; _cumulativeFps = (3 * _cumulativeFps + fpsCurr +2) >> 2; // "+2" for proper rounding (2/4 = 0.5) _lastShow = showNow; - _lastServiceShow = showNow; } /** @@ -1453,8 +1452,7 @@ uint16_t WS2812FX::getFps() const { void WS2812FX::setTargetFps(uint8_t fps) { if (fps > 0 && fps <= 120) _targetFps = fps; _frametime = 1000 / _targetFps; - if (_frametime < 1) _frametime = 1; // better safe than sorry - if (fps >= FPS_UNLIMITED) _frametime = 3; // unlimited mode + if (fps == FPS_UNLIMITED) _frametime = 3; // unlimited mode } void WS2812FX::setMode(uint8_t segid, uint8_t m) { From bf37ac53a3dd5c666027932027502c72e69b6996 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 4 Nov 2024 08:10:05 +0100 Subject: [PATCH 115/234] improved FPS calc resolution, added averaging & multiplier compileflags Fixed point calculation for improved accuracy, dithering in debug builds only. Averaging and optional multiplier can be set as compile flags, example for speed testing with long averaging and a 10x multiplier: -D FPS_CALC_AVG=200 -D FPS_MULTIPLIER=10 The calculation resolution is limited (9.7bit fixed point) so values larger than 200 can hit resolution limit and get stuck before reaching the final value. If WLED_DEBUG is defined, dithering is added to the returned value so sub-frame accuracy is possible in post-processingwithout enabling the multiplier. --- wled00/FX.h | 10 +++++++++- wled00/FX_fcn.cpp | 16 +++++++++++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index ad39a7c06..1579a5bcb 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -47,6 +47,14 @@ #define FRAMETIME_FIXED (1000/WLED_FPS) #define FRAMETIME strip.getFrameTime() +// FPS calculation (can be defined as compile flag for debugging) +#ifndef FPS_CALC_AVG +#define FPS_CALC_AVG 7 // average FPS calculation over this many frames (moving average) +#endif +#ifndef FPS_MULTIPLIER +#define FPS_MULTIPLIER 1 // dev option: multiplier to get sub-frame FPS without floats +#endif + /* each segment uses 82 bytes of SRAM memory, so if you're application fails because of insufficient memory, decreasing MAX_NUM_SEGMENTS may help */ #ifdef ESP8266 @@ -729,7 +737,7 @@ class WS2812FX { // 96 bytes _transitionDur(750), _targetFps(WLED_FPS), _frametime(FRAMETIME_FIXED), - _cumulativeFps(2), + _cumulativeFps(50<<6), _isServicing(false), _isOffRefreshRequired(false), _hasWhiteChannel(false), diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index f45256f0f..395451466 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1412,10 +1412,12 @@ void WS2812FX::show() { unsigned long showNow = millis(); size_t diff = showNow - _lastShow; - size_t fpsCurr = 200; - if (diff > 0) fpsCurr = 1000 / diff; - _cumulativeFps = (3 * _cumulativeFps + fpsCurr +2) >> 2; // "+2" for proper rounding (2/4 = 0.5) - _lastShow = showNow; + + if (diff > 0) { // skip calculation if no time has passed + size_t fpsCurr = (1000<<7) / diff; // fixed point 9.7 bit + _cumulativeFps = (FPS_CALC_AVG * _cumulativeFps + fpsCurr + FPS_CALC_AVG / 2) / (FPS_CALC_AVG + 1); // "+FPS_CALC_AVG/2" for proper rounding + _lastShow = showNow; + } } /** @@ -1432,7 +1434,11 @@ bool WS2812FX::isUpdating() const { */ uint16_t WS2812FX::getFps() const { if (millis() - _lastShow > 2000) return 0; - return _cumulativeFps +1; + #ifdef WLED_DEBUG + return (FPS_MULTIPLIER * (_cumulativeFps + (random16() & 63))) >> 7; // + random("0.5") for dithering + #else + return (FPS_MULTIPLIER * _cumulativeFps) >> 7; // _cumulativeFps is stored in fixed point 9.7 bit + #endif } void WS2812FX::setTargetFps(uint8_t fps) { From 3733715184df2a684820a54f0d7caf61ab1dc0ac Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 4 Nov 2024 17:38:45 +0100 Subject: [PATCH 116/234] bugfix bitshift was still set from testing, forgot to update --- wled00/FX.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.h b/wled00/FX.h index 1579a5bcb..e5b7a0e95 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -737,7 +737,7 @@ class WS2812FX { // 96 bytes _transitionDur(750), _targetFps(WLED_FPS), _frametime(FRAMETIME_FIXED), - _cumulativeFps(50<<6), + _cumulativeFps(50<<7), _isServicing(false), _isOffRefreshRequired(false), _hasWhiteChannel(false), From 4634ace74e9e7295ff1518b449112146475df349 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 4 Nov 2024 19:33:42 +0100 Subject: [PATCH 117/234] Added define for bitshift, removed dithering dithering is not really needed, the FPS_MULTIPLIER is a much better option. --- wled00/FX.h | 3 ++- wled00/FX_fcn.cpp | 8 ++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index e5b7a0e95..545161546 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -54,6 +54,7 @@ #ifndef FPS_MULTIPLIER #define FPS_MULTIPLIER 1 // dev option: multiplier to get sub-frame FPS without floats #endif +#define FPS_CALC_SHIFT 7 // bit shift for fixed point math /* each segment uses 82 bytes of SRAM memory, so if you're application fails because of insufficient memory, decreasing MAX_NUM_SEGMENTS may help */ @@ -737,7 +738,7 @@ class WS2812FX { // 96 bytes _transitionDur(750), _targetFps(WLED_FPS), _frametime(FRAMETIME_FIXED), - _cumulativeFps(50<<7), + _cumulativeFps(50 << FPS_CALC_SHIFT), _isServicing(false), _isOffRefreshRequired(false), _hasWhiteChannel(false), diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 395451466..e706f2b43 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1414,7 +1414,7 @@ void WS2812FX::show() { size_t diff = showNow - _lastShow; if (diff > 0) { // skip calculation if no time has passed - size_t fpsCurr = (1000<<7) / diff; // fixed point 9.7 bit + size_t fpsCurr = (1000 << FPS_CALC_SHIFT) / diff; // fixed point math _cumulativeFps = (FPS_CALC_AVG * _cumulativeFps + fpsCurr + FPS_CALC_AVG / 2) / (FPS_CALC_AVG + 1); // "+FPS_CALC_AVG/2" for proper rounding _lastShow = showNow; } @@ -1434,11 +1434,7 @@ bool WS2812FX::isUpdating() const { */ uint16_t WS2812FX::getFps() const { if (millis() - _lastShow > 2000) return 0; - #ifdef WLED_DEBUG - return (FPS_MULTIPLIER * (_cumulativeFps + (random16() & 63))) >> 7; // + random("0.5") for dithering - #else - return (FPS_MULTIPLIER * _cumulativeFps) >> 7; // _cumulativeFps is stored in fixed point 9.7 bit - #endif + return (FPS_MULTIPLIER * _cumulativeFps) >> FPS_CALC_SHIFT; // _cumulativeFps is stored in fixed point } void WS2812FX::setTargetFps(uint8_t fps) { From cf1630a94a3de7b59e2dd21562a607627c9fa2d2 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 4 Nov 2024 19:49:43 +0100 Subject: [PATCH 118/234] 0 FPS = unlimited --- wled00/FX.h | 2 +- wled00/FX_fcn.cpp | 8 ++++---- wled00/data/settings_leds.htm | 8 +++++++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 1f0df9da3..5c80686d6 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -52,7 +52,7 @@ #else #define MIN_SHOW_DELAY (_frametime < 16 ? 8 : 15) // legacy MIN_SHOW_DELAY - creates more idle loops, but reduces framerates #endif -#define FPS_UNLIMITED 120 +#define FPS_UNLIMITED 0 /* each segment uses 82 bytes of SRAM memory, so if you're application fails because of insufficient memory, decreasing MAX_NUM_SEGMENTS may help */ diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 3972dad2c..30882c4e7 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1314,7 +1314,7 @@ void WS2812FX::service() { #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) if (elapsed < 2) return; // keep wifi alive - if ( !_triggered && (_targetFps != FPS_UNLIMITED) && (_targetFps > 0)) { + if ( !_triggered && (_targetFps != FPS_UNLIMITED)) { if (elapsed < MIN_SHOW_DELAY) return; // WLEDMM too early for service } #else // legacy @@ -1450,9 +1450,9 @@ uint16_t WS2812FX::getFps() const { } void WS2812FX::setTargetFps(uint8_t fps) { - if (fps > 0 && fps <= 120) _targetFps = fps; - _frametime = 1000 / _targetFps; - if (fps == FPS_UNLIMITED) _frametime = 3; // unlimited mode + if (fps <= 120) _targetFps = fps; + if (_targetFps > 0) _frametime = 1000 / _targetFps; + else _frametime = 3; // unlimited mode } void WS2812FX::setMode(uint8_t segid, uint8_t m) { diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 6be5becd1..35bbbd312 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -380,6 +380,10 @@ gId('psu').innerHTML = s; gId('psu2').innerHTML = s2; gId("json").style.display = d.Sf.IT.value==8 ? "" : "none"; + + // show/hide unlimited FPS message + gId('fpsNone').style.display = (d.Sf.FR.value == 0) ? 'block':'none'; + gId('fpsHelp').style.display = (d.Sf.FR.value == 0)? 'none':'block'; } function lastEnd(i) { if (i-- < 1) return 0; @@ -870,7 +874,9 @@ Swap:
- Target refresh rate: FPS + Target refresh rate: FPS +
use 0 for unlimited
+
Config template:

From 029293a08621df71ed0546ed5bf3c0e4cc9d49c7 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 4 Nov 2024 20:11:10 +0100 Subject: [PATCH 119/234] simplify sheduler logic * _frametime ensures that effects are not serviced too often * MIN_SHOW_DELAY is the minimum allowed FRAMETIME that can be requested by effects --- wled00/FX.h | 3 +-- wled00/FX_fcn.cpp | 13 ++++--------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 5c80686d6..d749d7796 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -47,8 +47,7 @@ #define FRAMETIME_FIXED (1000/WLED_FPS) #define FRAMETIME strip.getFrameTime() #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) // all ESP32 except -C3(very slow, untested) - #define MIN_SHOW_DELAY (max(2, (_frametime*5)/8)) // supports higher framerates and better animation control -- 5/8 = 62% - // used to initialize for strip attributes: + #define MIN_SHOW_DELAY 3 // supports higher framerates and better animation control #else #define MIN_SHOW_DELAY (_frametime < 16 ? 8 : 15) // legacy MIN_SHOW_DELAY - creates more idle loops, but reduces framerates #endif diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 30882c4e7..6bc61d10d 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1312,20 +1312,15 @@ void WS2812FX::service() { if (_suspend) return; unsigned long elapsed = nowUp - _lastServiceShow; - #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) - if (elapsed < 2) return; // keep wifi alive - if ( !_triggered && (_targetFps != FPS_UNLIMITED)) { - if (elapsed < MIN_SHOW_DELAY) return; // WLEDMM too early for service + if (elapsed < 2) return; // keep wifi alive - no matter if triggered or unlimited + if ( !_triggered && (_targetFps != FPS_UNLIMITED)) { // unlimited mode = no frametime + if (elapsed < _frametime) return; // too early for service } - #else // legacy - if (nowUp - _lastShow < MIN_SHOW_DELAY) return; - #endif bool doShow = false; _isServicing = true; _segment_index = 0; - unsigned speedLimit = (_targetFps != FPS_UNLIMITED) ? (0.85f * FRAMETIME) : 1; // lower limit for effect frametime for (segment &seg : _segments) { if (_suspend) return; // immediately stop processing segments if suspend requested during service() @@ -1362,7 +1357,6 @@ void WS2812FX::service() { // would need to be allocated for each effect and then blended together for each pixel. [[maybe_unused]] uint8_t tmpMode = seg.currentMode(); // this will return old mode while in transition frameDelay = (*_mode[seg.mode])(); // run new/current mode - if (frameDelay < speedLimit) frameDelay = FRAMETIME; // limit effects that want to go faster than target FPS #ifndef WLED_DISABLE_MODE_BLEND if (modeBlending && seg.mode != tmpMode) { Segment::tmpsegd_t _tmpSegData; @@ -1375,6 +1369,7 @@ void WS2812FX::service() { Segment::modeBlend(false); // unset semaphore } #endif + frameDelay = max(frameDelay, unsigned(MIN_SHOW_DELAY)); // limit effects that want to go faster than target FPS seg.call++; if (seg.isInTransition() && frameDelay > FRAMETIME) frameDelay = FRAMETIME; // force faster updates during transition BusManager::setSegmentCCT(oldCCT); // restore old CCT for ABL adjustments From ab7b2d729e68099b140473079dc22ea9b186d7b5 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 5 Nov 2024 12:24:20 +0100 Subject: [PATCH 120/234] use class="warn" for unlimited mode message --- wled00/data/settings_leds.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 35bbbd312..caeaacea9 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -876,7 +876,7 @@ Swap:
Target refresh rate: FPS
use 0 for unlimited
- +
Config template:

From 1e761c31bdd53850aca805c9400ef24b10f3afda Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 6 Nov 2024 22:09:33 +0100 Subject: [PATCH 121/234] simpler hight FPS warning * removed "use 0 for unlimited" * added "high FPS mode is experimental" warning * added "backup first!" warning * added anchor #backup to sec page --- wled00/data/settings_leds.htm | 10 ++++++---- wled00/data/settings_sec.htm | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index caeaacea9..55f8122e8 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -381,9 +381,10 @@ gId('psu2').innerHTML = s2; gId("json").style.display = d.Sf.IT.value==8 ? "" : "none"; - // show/hide unlimited FPS message + // show/hide FPS warning messages gId('fpsNone').style.display = (d.Sf.FR.value == 0) ? 'block':'none'; - gId('fpsHelp').style.display = (d.Sf.FR.value == 0)? 'none':'block'; + gId('fpsWarn').style.display = (d.Sf.FR.value == 0) || (d.Sf.FR.value >= 80) ? 'block':'none'; + gId('fpsHigh').style.display = (d.Sf.FR.value >= 80) ? 'block':'none'; } function lastEnd(i) { if (i-- < 1) return 0; @@ -875,8 +876,9 @@ Swap:
Target refresh rate: FPS -
use 0 for unlimited
- + + +
Config template:

diff --git a/wled00/data/settings_sec.htm b/wled00/data/settings_sec.htm index fa75882c0..5181858d5 100644 --- a/wled00/data/settings_sec.htm +++ b/wled00/data/settings_sec.htm @@ -57,7 +57,7 @@

Software Update


Enable ArduinoOTA: -
+

Backup & Restore

⚠ Restoring presets/configuration will OVERWRITE your current presets/configuration.
Incorrect upload or configuration may require a factory reset or re-flashing of your ESP.
From 6ff5c88ebf0525f8101c49f19702c0ee0cec0e65 Mon Sep 17 00:00:00 2001 From: netmindz Date: Thu, 7 Nov 2024 08:17:08 +0000 Subject: [PATCH 122/234] List ESP32 first --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 11c1733f8..595b9ee0b 100644 --- a/readme.md +++ b/readme.md @@ -12,7 +12,7 @@ # Welcome to my project WLED! ✨ -A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B, WS2811, SK6812) LEDs or also SPI based chipsets like the WS2801 and APA102! +A fast and feature-rich implementation of an ESP32 and ESP8266 webserver to control NeoPixel (WS2812B, WS2811, SK6812) LEDs or also SPI based chipsets like the WS2801 and APA102! ## ⚙️ Features - WS2812FX library with more than 100 special effects From 0404ec988137acca997e620384cf446b19dce350 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 7 Nov 2024 23:15:39 +0100 Subject: [PATCH 123/234] changes in response to feedback from @willmmiles * MIN_SHOW_DELAY -> MIN_FRAME_DELAY * allow up to 250 for target FPS * minor cleanup * added specific MIN_FRAME_DELAY for -S2 --- wled00/FX.h | 10 ++++++---- wled00/FX_fcn.cpp | 11 +++++------ wled00/data/settings_leds.htm | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index d749d7796..56a0c9bd0 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -46,10 +46,12 @@ #define WLED_FPS 42 #define FRAMETIME_FIXED (1000/WLED_FPS) #define FRAMETIME strip.getFrameTime() -#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) // all ESP32 except -C3(very slow, untested) - #define MIN_SHOW_DELAY 3 // supports higher framerates and better animation control +#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S2) + #define MIN_FRAME_DELAY 2 // minimum wait between repaints, to keep other functions like WiFi alive +#elif defined(CONFIG_IDF_TARGET_ESP32S2) + #define MIN_FRAME_DELAY 4 // S2 is slower than normal esp32, and only has one core #else - #define MIN_SHOW_DELAY (_frametime < 16 ? 8 : 15) // legacy MIN_SHOW_DELAY - creates more idle loops, but reduces framerates + #define MIN_FRAME_DELAY 8 // 8266 legacy MIN_SHOW_DELAY #endif #define FPS_UNLIMITED 0 @@ -842,7 +844,7 @@ class WS2812FX { // 96 bytes getMappedPixelIndex(uint16_t index) const; inline uint16_t getFrameTime() const { return _frametime; } // returns amount of time a frame should take (in ms) - inline uint16_t getMinShowDelay() const { return MIN_SHOW_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant) + inline uint16_t getMinShowDelay() const { return MIN_FRAME_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant) inline uint16_t getLength() const { return _length; } // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H) inline uint16_t getTransition() const { return _transitionDur; } // returns currently set transition time (in ms) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 6bc61d10d..f4b46dade 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1312,7 +1312,7 @@ void WS2812FX::service() { if (_suspend) return; unsigned long elapsed = nowUp - _lastServiceShow; - if (elapsed < 2) return; // keep wifi alive - no matter if triggered or unlimited + if (elapsed <= MIN_FRAME_DELAY) return; // keep wifi alive - no matter if triggered or unlimited if ( !_triggered && (_targetFps != FPS_UNLIMITED)) { // unlimited mode = no frametime if (elapsed < _frametime) return; // too early for service } @@ -1369,7 +1369,6 @@ void WS2812FX::service() { Segment::modeBlend(false); // unset semaphore } #endif - frameDelay = max(frameDelay, unsigned(MIN_SHOW_DELAY)); // limit effects that want to go faster than target FPS seg.call++; if (seg.isInTransition() && frameDelay > FRAMETIME) frameDelay = FRAMETIME; // force faster updates during transition BusManager::setSegmentCCT(oldCCT); // restore old CCT for ABL adjustments @@ -1390,7 +1389,7 @@ void WS2812FX::service() { yield(); Segment::handleRandomPalette(); // slowly transition random palette; move it into for loop when each segment has individual random palette show(); - _lastServiceShow = nowUp; // correct timestamp, for better FPS control + _lastServiceShow = nowUp; // update timestamp, for precise FPS control } #ifdef WLED_DEBUG if ((_targetFps != FPS_UNLIMITED) && (millis() - nowUp > _frametime)) DEBUG_PRINTF_P(PSTR("Slow strip %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime); @@ -1445,9 +1444,9 @@ uint16_t WS2812FX::getFps() const { } void WS2812FX::setTargetFps(uint8_t fps) { - if (fps <= 120) _targetFps = fps; + if (fps <= 250) _targetFps = fps; if (_targetFps > 0) _frametime = 1000 / _targetFps; - else _frametime = 3; // unlimited mode + else _frametime = MIN_FRAME_DELAY; // unlimited mode } void WS2812FX::setMode(uint8_t segid, uint8_t m) { @@ -1495,7 +1494,7 @@ void WS2812FX::setBrightness(uint8_t b, bool direct) { BusManager::setBrightness(b); if (!direct) { unsigned long t = millis(); - if (_segments[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) trigger(); //apply brightness change immediately if no refresh soon + if (_segments[0].next_time > t + 22 && t - _lastShow > MIN_FRAME_DELAY) trigger(); //apply brightness change immediately if no refresh soon } } diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 55f8122e8..b467d5b9b 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -875,7 +875,7 @@ Swap:
- Target refresh rate: FPS + Target refresh rate: FPS From 001e2ad2875742b51861ba826baa9a9727698ea0 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Fri, 8 Nov 2024 19:35:42 +0100 Subject: [PATCH 124/234] adjust audioreactive for the new FRAME_DELAY logic minor --- usermods/audioreactive/audio_reactive.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index ad449fc83..9c463e0a1 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -75,7 +75,7 @@ static uint8_t soundAgc = 0; // Automagic gain control: 0 - n //static float volumeSmth = 0.0f; // either sampleAvg or sampleAgc depending on soundAgc; smoothed sample static float FFT_MajorPeak = 1.0f; // FFT: strongest (peak) frequency static float FFT_Magnitude = 0.0f; // FFT: volume (magnitude) of peak frequency -static bool samplePeak = false; // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getMinShowDelay() +static bool samplePeak = false; // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getFrameTime() static bool udpSamplePeak = false; // Boolean flag for peak. Set at the same time as samplePeak, but reset by transmitAudioData static unsigned long timeOfPeak = 0; // time of last sample peak detection. static uint8_t fftResult[NUM_GEQ_CHANNELS]= {0};// Our calculated freq. channel result table to be used by effects @@ -536,8 +536,8 @@ static void detectSamplePeak(void) { #endif static void autoResetPeak(void) { - uint16_t MinShowDelay = MAX(50, strip.getMinShowDelay()); // Fixes private class variable compiler error. Unsure if this is the correct way of fixing the root problem. -THATDONFC - if (millis() - timeOfPeak > MinShowDelay) { // Auto-reset of samplePeak after a complete frame has passed. + uint16_t peakDelay = max(uint16_t(50), strip.getFrameTime()); + if (millis() - timeOfPeak > peakDelay) { // Auto-reset of samplePeak after at least one complete frame has passed. samplePeak = false; if (audioSyncEnabled == 0) udpSamplePeak = false; // this is normally reset by transmitAudioData } From ef1e24cec26cdb05b7a342e7a432f03692ca521e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sat, 9 Nov 2024 10:42:49 +0100 Subject: [PATCH 125/234] Bugfix & code reduction - correctly clear segment spacing change - renamed Segment::setUp() to Segment::setGeometry() - removed WS2812FX::setSegment() - removed obsolete/unfunctional word clock usermod .cpp file --- .../usermod_word_clock_matrix.h | 128 ++++---- .../word-clock-matrix/word-clock-matrix.cpp | 305 ------------------ wled00/FX.h | 6 +- wled00/FX_fcn.cpp | 34 +- wled00/json.cpp | 16 +- wled00/set.cpp | 4 +- wled00/udp.cpp | 15 +- 7 files changed, 99 insertions(+), 409 deletions(-) delete mode 100644 usermods/word-clock-matrix/word-clock-matrix.cpp diff --git a/usermods/word-clock-matrix/usermod_word_clock_matrix.h b/usermods/word-clock-matrix/usermod_word_clock_matrix.h index 506c1275e..82499c0ce 100644 --- a/usermods/word-clock-matrix/usermod_word_clock_matrix.h +++ b/usermods/word-clock-matrix/usermod_word_clock_matrix.h @@ -31,14 +31,14 @@ public: //strip.getSegment(1).setOption(SEG_OPTION_SELECTED, true); //select first two segments (background color + FX settable) - WS2812FX::Segment &seg = strip.getSegment(0); + Segment &seg = strip.getSegment(0); seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((0 & 0xFF) << 8) | ((0 & 0xFF))); strip.getSegment(0).setOption(0, false); strip.getSegment(0).setOption(2, false); //other segments are text for (int i = 1; i < 10; i++) { - WS2812FX::Segment &seg = strip.getSegment(i); + Segment &seg = strip.getSegment(i); seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((190 & 0xFF) << 8) | ((180 & 0xFF))); strip.getSegment(i).setOption(0, true); strip.setBrightness(64); @@ -80,61 +80,61 @@ public: void displayTime(byte hour, byte minute) { bool isToHour = false; //true if minute > 30 - strip.setSegment(0, 0, 64); // background - strip.setSegment(1, 0, 2); //It is + strip.getSegment(0).setGeometry(0, 64); // background + strip.getSegment(1).setGeometry(0, 2); //It is - strip.setSegment(2, 0, 0); - strip.setSegment(3, 0, 0); //disable minutes - strip.setSegment(4, 0, 0); //past - strip.setSegment(6, 0, 0); //to - strip.setSegment(8, 0, 0); //disable o'clock + strip.getSegment(2).setGeometry(0, 0); + strip.getSegment(3).setGeometry(0, 0); //disable minutes + strip.getSegment(4).setGeometry(0, 0); //past + strip.getSegment(6).setGeometry(0, 0); //to + strip.getSegment(8).setGeometry(0, 0); //disable o'clock if (hour < 24) //valid time, display { if (minute == 30) { - strip.setSegment(2, 3, 6); //half - strip.setSegment(3, 0, 0); //minutes + strip.getSegment(2).setGeometry(3, 6); //half + strip.getSegment(3).setGeometry(0, 0); //minutes } else if (minute == 15 || minute == 45) { - strip.setSegment(3, 0, 0); //minutes + strip.getSegment(3).setGeometry(0, 0); //minutes } else if (minute == 10) { - //strip.setSegment(5, 6, 8); //ten + //strip.getSegment(5).setGeometry(6, 8); //ten } else if (minute == 5) { - //strip.setSegment(5, 16, 18); //five + //strip.getSegment(5).setGeometry(16, 18); //five } else if (minute == 0) { - strip.setSegment(3, 0, 0); //minutes + strip.getSegment(3).setGeometry(0, 0); //minutes //hourChime(); } else { - strip.setSegment(3, 18, 22); //minutes + strip.getSegment(3).setGeometry(18, 22); //minutes } //past or to? if (minute == 0) { //full hour - strip.setSegment(3, 0, 0); //disable minutes - strip.setSegment(4, 0, 0); //disable past - strip.setSegment(6, 0, 0); //disable to - strip.setSegment(8, 60, 64); //o'clock + strip.getSegment(3).setGeometry(0, 0); //disable minutes + strip.getSegment(4).setGeometry(0, 0); //disable past + strip.getSegment(6).setGeometry(0, 0); //disable to + strip.getSegment(8).setGeometry(60, 64); //o'clock } else if (minute > 34) { - //strip.setSegment(6, 22, 24); //to + //strip.getSegment(6).setGeometry(22, 24); //to //minute = 60 - minute; isToHour = true; } else { - //strip.setSegment(4, 24, 27); //past + //strip.getSegment(4).setGeometry(24, 27); //past //isToHour = false; } } @@ -143,68 +143,68 @@ public: if (minute <= 4) { - strip.setSegment(3, 0, 0); //nothing - strip.setSegment(5, 0, 0); //nothing - strip.setSegment(6, 0, 0); //nothing - strip.setSegment(8, 60, 64); //o'clock + strip.getSegment(3).setGeometry(0, 0); //nothing + strip.getSegment(5).setGeometry(0, 0); //nothing + strip.getSegment(6).setGeometry(0, 0); //nothing + strip.getSegment(8).setGeometry(60, 64); //o'clock } else if (minute <= 9) { - strip.setSegment(5, 16, 18); // five past - strip.setSegment(4, 24, 27); //past + strip.getSegment(5).setGeometry(16, 18); // five past + strip.getSegment(4).setGeometry(24, 27); //past } else if (minute <= 14) { - strip.setSegment(5, 6, 8); // ten past - strip.setSegment(4, 24, 27); //past + strip.getSegment(5).setGeometry(6, 8); // ten past + strip.getSegment(4).setGeometry(24, 27); //past } else if (minute <= 19) { - strip.setSegment(5, 8, 12); // quarter past - strip.setSegment(3, 0, 0); //minutes - strip.setSegment(4, 24, 27); //past + strip.getSegment(5).setGeometry(8, 12); // quarter past + strip.getSegment(3).setGeometry(0, 0); //minutes + strip.getSegment(4).setGeometry(24, 27); //past } else if (minute <= 24) { - strip.setSegment(5, 12, 16); // twenty past - strip.setSegment(4, 24, 27); //past + strip.getSegment(5).setGeometry(12, 16); // twenty past + strip.getSegment(4).setGeometry(24, 27); //past } else if (minute <= 29) { - strip.setSegment(5, 12, 18); // twenty-five past - strip.setSegment(4, 24, 27); //past + strip.getSegment(5).setGeometry(12, 18); // twenty-five past + strip.getSegment(4).setGeometry(24, 27); //past } else if (minute <= 34) { - strip.setSegment(5, 3, 6); // half past - strip.setSegment(3, 0, 0); //minutes - strip.setSegment(4, 24, 27); //past + strip.getSegment(5).setGeometry(3, 6); // half past + strip.getSegment(3).setGeometry(0, 0); //minutes + strip.getSegment(4).setGeometry(24, 27); //past } else if (minute <= 39) { - strip.setSegment(5, 12, 18); // twenty-five to - strip.setSegment(6, 22, 24); //to + strip.getSegment(5).setGeometry(12, 18); // twenty-five to + strip.getSegment(6).setGeometry(22, 24); //to } else if (minute <= 44) { - strip.setSegment(5, 12, 16); // twenty to - strip.setSegment(6, 22, 24); //to + strip.getSegment(5).setGeometry(12, 16); // twenty to + strip.getSegment(6).setGeometry(22, 24); //to } else if (minute <= 49) { - strip.setSegment(5, 8, 12); // quarter to - strip.setSegment(3, 0, 0); //minutes - strip.setSegment(6, 22, 24); //to + strip.getSegment(5).setGeometry(8, 12); // quarter to + strip.getSegment(3).setGeometry(0, 0); //minutes + strip.getSegment(6).setGeometry(22, 24); //to } else if (minute <= 54) { - strip.setSegment(5, 6, 8); // ten to - strip.setSegment(6, 22, 24); //to + strip.getSegment(5).setGeometry(6, 8); // ten to + strip.getSegment(6).setGeometry(22, 24); //to } else if (minute <= 59) { - strip.setSegment(5, 16, 18); // five to - strip.setSegment(6, 22, 24); //to + strip.getSegment(5).setGeometry(16, 18); // five to + strip.getSegment(6).setGeometry(22, 24); //to } //hours @@ -220,45 +220,45 @@ public: switch (hour) { case 1: - strip.setSegment(7, 27, 29); + strip.getSegment(7).setGeometry(27, 29); break; //one case 2: - strip.setSegment(7, 35, 37); + strip.getSegment(7).setGeometry(35, 37); break; //two case 3: - strip.setSegment(7, 29, 32); + strip.getSegment(7).setGeometry(29, 32); break; //three case 4: - strip.setSegment(7, 32, 35); + strip.getSegment(7).setGeometry(32, 35); break; //four case 5: - strip.setSegment(7, 37, 40); + strip.getSegment(7).setGeometry(37, 40); break; //five case 6: - strip.setSegment(7, 43, 45); + strip.getSegment(7).setGeometry(43, 45); break; //six case 7: - strip.setSegment(7, 40, 43); + strip.getSegment(7).setGeometry(40, 43); break; //seven case 8: - strip.setSegment(7, 45, 48); + strip.getSegment(7).setGeometry(45, 48); break; //eight case 9: - strip.setSegment(7, 48, 50); + strip.getSegment(7).setGeometry(48, 50); break; //nine case 10: - strip.setSegment(7, 54, 56); + strip.getSegment(7).setGeometry(54, 56); break; //ten case 11: - strip.setSegment(7, 50, 54); + strip.getSegment(7).setGeometry(50, 54); break; //eleven case 12: - strip.setSegment(7, 56, 60); + strip.getSegment(7).setGeometry(56, 60); break; //twelve } selectWordSegments(true); - applyMacro(1); + applyPreset(1); } void timeOfDay() diff --git a/usermods/word-clock-matrix/word-clock-matrix.cpp b/usermods/word-clock-matrix/word-clock-matrix.cpp deleted file mode 100644 index 67c5b1e47..000000000 --- a/usermods/word-clock-matrix/word-clock-matrix.cpp +++ /dev/null @@ -1,305 +0,0 @@ -#include "wled.h" -/* - * This v1 usermod file allows you to add own functionality to WLED more easily - * See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality - * EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h) - * If you just need 8 bytes, use 2551-2559 (you do not need to increase EEPSIZE) - * - * Consider the v2 usermod API if you need a more advanced feature set! - */ - - -uint8_t minuteLast = 99; -int dayBrightness = 128; -int nightBrightness = 16; - -//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t) - -//gets called once at boot. Do all initialization that doesn't depend on network here -void userSetup() -{ -saveMacro(14, "A=128", false); -saveMacro(15, "A=64", false); -saveMacro(16, "A=16", false); - -saveMacro(1, "&FX=0&R=255&G=255&B=255", false); - -//strip.getSegment(1).setOption(SEG_OPTION_SELECTED, true); - - //select first two segments (background color + FX settable) - Segment &seg = strip.getSegment(0); - seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((0 & 0xFF) << 8) | ((0 & 0xFF))); - strip.getSegment(0).setOption(0, false); - strip.getSegment(0).setOption(2, false); - //other segments are text - for (int i = 1; i < 10; i++) - { - Segment &seg = strip.getSegment(i); - seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((190 & 0xFF) << 8) | ((180 & 0xFF))); - strip.getSegment(i).setOption(0, true); - strip.setBrightness(128); - } -} - -//gets called every time WiFi is (re-)connected. Initialize own network interfaces here -void userConnected() -{ -} - -void selectWordSegments(bool state) -{ - for (int i = 1; i < 10; i++) - { - //Segment &seg = strip.getSegment(i); - strip.getSegment(i).setOption(0, state); - // strip.getSegment(1).setOption(SEG_OPTION_SELECTED, true); - //seg.mode = 12; - //seg.palette = 1; - //strip.setBrightness(255); - } - strip.getSegment(0).setOption(0, !state); -} - -void hourChime() -{ - //strip.resetSegments(); - selectWordSegments(true); - colorUpdated(CALL_MODE_FX_CHANGED); - //savePreset(255); - selectWordSegments(false); - //strip.getSegment(0).setOption(0, true); - strip.getSegment(0).setOption(2, true); - applyPreset(12); - colorUpdated(CALL_MODE_FX_CHANGED); -} - -void displayTime(byte hour, byte minute) -{ - bool isToHour = false; //true if minute > 30 - strip.setSegment(0, 0, 64); // background - strip.setSegment(1, 0, 2); //It is - - strip.setSegment(2, 0, 0); - strip.setSegment(3, 0, 0); //disable minutes - strip.setSegment(4, 0, 0); //past - strip.setSegment(6, 0, 0); //to - strip.setSegment(8, 0, 0); //disable o'clock - - if (hour < 24) //valid time, display - { - if (minute == 30) - { - strip.setSegment(2, 3, 6); //half - strip.setSegment(3, 0, 0); //minutes - } - else if (minute == 15 || minute == 45) - { - strip.setSegment(3, 0, 0); //minutes - } - else if (minute == 10) - { - //strip.setSegment(5, 6, 8); //ten - } - else if (minute == 5) - { - //strip.setSegment(5, 16, 18); //five - } - else if (minute == 0) - { - strip.setSegment(3, 0, 0); //minutes - //hourChime(); - } - else - { - strip.setSegment(3, 18, 22); //minutes - } - - //past or to? - if (minute == 0) - { //full hour - strip.setSegment(3, 0, 0); //disable minutes - strip.setSegment(4, 0, 0); //disable past - strip.setSegment(6, 0, 0); //disable to - strip.setSegment(8, 60, 64); //o'clock - } - else if (minute > 34) - { - //strip.setSegment(6, 22, 24); //to - //minute = 60 - minute; - isToHour = true; - } - else - { - //strip.setSegment(4, 24, 27); //past - //isToHour = false; - } - } - else - { //temperature display - } - - //byte minuteRem = minute %10; - - if (minute <= 4) - { - strip.setSegment(3, 0, 0); //nothing - strip.setSegment(5, 0, 0); //nothing - strip.setSegment(6, 0, 0); //nothing - strip.setSegment(8, 60, 64); //o'clock - } - else if (minute <= 9) - { - strip.setSegment(5, 16, 18); // five past - strip.setSegment(4, 24, 27); //past - } - else if (minute <= 14) - { - strip.setSegment(5, 6, 8); // ten past - strip.setSegment(4, 24, 27); //past - } - else if (minute <= 19) - { - strip.setSegment(5, 8, 12); // quarter past - strip.setSegment(3, 0, 0); //minutes - strip.setSegment(4, 24, 27); //past - } - else if (minute <= 24) - { - strip.setSegment(5, 12, 16); // twenty past - strip.setSegment(4, 24, 27); //past - } - else if (minute <= 29) - { - strip.setSegment(5, 12, 18); // twenty-five past - strip.setSegment(4, 24, 27); //past - } - else if (minute <= 34) - { - strip.setSegment(5, 3, 6); // half past - strip.setSegment(3, 0, 0); //minutes - strip.setSegment(4, 24, 27); //past - } - else if (minute <= 39) - { - strip.setSegment(5, 12, 18); // twenty-five to - strip.setSegment(6, 22, 24); //to - } - else if (minute <= 44) - { - strip.setSegment(5, 12, 16); // twenty to - strip.setSegment(6, 22, 24); //to - } - else if (minute <= 49) - { - strip.setSegment(5, 8, 12); // quarter to - strip.setSegment(3, 0, 0); //minutes - strip.setSegment(6, 22, 24); //to - } - else if (minute <= 54) - { - strip.setSegment(5, 6, 8); // ten to - strip.setSegment(6, 22, 24); //to - } - else if (minute <= 59) - { - strip.setSegment(5, 16, 18); // five to - strip.setSegment(6, 22, 24); //to - } - - //hours - if (hour > 23) - return; - if (isToHour) - hour++; - if (hour > 12) - hour -= 12; - if (hour == 0) - hour = 12; - - switch (hour) - { - case 1: - strip.setSegment(7, 27, 29); - break; //one - case 2: - strip.setSegment(7, 35, 37); - break; //two - case 3: - strip.setSegment(7, 29, 32); - break; //three - case 4: - strip.setSegment(7, 32, 35); - break; //four - case 5: - strip.setSegment(7, 37, 40); - break; //five - case 6: - strip.setSegment(7, 43, 45); - break; //six - case 7: - strip.setSegment(7, 40, 43); - break; //seven - case 8: - strip.setSegment(7, 45, 48); - break; //eight - case 9: - strip.setSegment(7, 48, 50); - break; //nine - case 10: - strip.setSegment(7, 54, 56); - break; //ten - case 11: - strip.setSegment(7, 50, 54); - break; //eleven - case 12: - strip.setSegment(7, 56, 60); - break; //twelve - } - -selectWordSegments(true); -applyMacro(1); -} - -void timeOfDay() { -// NOT USED: use timed macros instead - //Used to set brightness dependant of time of day - lights dimmed at night - - //monday to thursday and sunday - - if ((weekday(localTime) == 6) | (weekday(localTime) == 7)) { - if (hour(localTime) > 0 | hour(localTime) < 8) { - strip.setBrightness(nightBrightness); - } - else { - strip.setBrightness(dayBrightness); - } - } - else { - if (hour(localTime) < 6 | hour(localTime) >= 22) { - strip.setBrightness(nightBrightness); - } - else { - strip.setBrightness(dayBrightness); - } - } -} - -//loop. You can use "if (WLED_CONNECTED)" to check for successful connection -void userLoop() -{ - if (minute(localTime) != minuteLast) - { - updateLocalTime(); - //timeOfDay(); - minuteLast = minute(localTime); - displayTime(hour(localTime), minute(localTime)); - if (minute(localTime) == 0){ - hourChime(); - } - if (minute(localTime) == 1){ - //turn off background segment; - strip.getSegment(0).setOption(2, false); - //applyPreset(255); - } - } -} diff --git a/wled00/FX.h b/wled00/FX.h index c06332c76..d56c0fa99 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -539,6 +539,7 @@ typedef struct Segment { inline uint16_t length() const { return width() * height(); } // segment length (count) in physical pixels inline uint16_t groupLength() const { return grouping + spacing; } inline uint8_t getLightCapabilities() const { return _capabilities; } + inline void deactivate() { setGeometry(0,0); } inline static unsigned getUsedSegmentData() { return Segment::_usedSegmentData; } inline static void addUsedSegmentData(int len) { Segment::_usedSegmentData += len; } @@ -554,14 +555,14 @@ typedef struct Segment { static void handleRandomPalette(); void beginDraw(); // set up parameters for current effect - void setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1); + void setGeometry(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1, uint8_t m12=0); bool setColor(uint8_t slot, uint32_t c); //returns true if changed void setCCT(uint16_t k); void setOpacity(uint8_t o); void setOption(uint8_t n, bool val); void setMode(uint8_t fx, bool loadDefaults = false); void setPalette(uint8_t pal); - uint8_t differs(Segment& b) const; + uint8_t differs(const Segment& b) const; void refreshLightCapabilities(); // runtime data functions @@ -783,7 +784,6 @@ class WS2812FX { // 96 bytes setBrightness(uint8_t b, bool direct = false), // sets strip brightness setRange(uint16_t i, uint16_t i2, uint32_t col), // used for clock overlay purgeSegments(), // removes inactive segments from RAM (may incure penalty and memory fragmentation but reduces vector footprint) - setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 1, uint8_t spacing = 0, uint16_t offset = UINT16_MAX, uint16_t startY=0, uint16_t stopY=1), setMainSegmentId(unsigned n = 0), resetSegments(), // marks all segments for reset makeAutoSegments(bool forceReset = false), // will create segments based on configured outputs diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 613b41fad..69b0c028a 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -489,8 +489,10 @@ void Segment::handleRandomPalette() { nblendPaletteTowardPalette(_randomPalette, _newRandomPalette, 48); } -// segId is given when called from network callback, changes are queued if that segment is currently in its effect function -void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y) { +// sets Segment geometry (length or width/height and grouping, spacing and offset as well as 2D mapping) +// strip must be suspended (strip.suspend()) before calling this function +// this function may call fill() to clear pixels if spacing or mapping changed (which requires setting _vWidth, _vHeight, _vLength or beginDraw()) +void Segment::setGeometry(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y, uint8_t m12) { // return if neither bounds nor grouping have changed bool boundsUnchanged = (start == i1 && stop == i2); #ifndef WLED_DISABLE_2D @@ -498,11 +500,19 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t #endif if (boundsUnchanged && (!grp || (grouping == grp && spacing == spc)) - && (ofs == UINT16_MAX || ofs == offset)) return; + && (ofs == UINT16_MAX || ofs == offset) + && (m12 == map1D2D) + ) return; stateChanged = true; // send UDP/WS broadcast - if (stop) fill(BLACK); // turn old segment range off (clears pixels if changing spacing) + if (stop || spc != spacing || m12 != map1D2D) { + _vWidth = virtualWidth(); + _vHeight = virtualHeight(); + _vLength = virtualLength(); + _segBri = currentBri(); + fill(BLACK); // turn old segment range off or clears pixels if changing spacing (requires _vWidth/_vHeight/_vLength/_segBri) + } if (grp) { // prevent assignment of 0 grouping = grp; spacing = spc; @@ -511,6 +521,7 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t spacing = 0; } if (ofs < UINT16_MAX) offset = ofs; + map1D2D = constrain(m12, 0, 7); DEBUG_PRINT(F("setUp segment: ")); DEBUG_PRINT(i1); DEBUG_PRINT(','); DEBUG_PRINT(i2); @@ -993,7 +1004,7 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const return strip.getPixelColor(i); } -uint8_t Segment::differs(Segment& b) const { +uint8_t Segment::differs(const Segment& b) const { uint8_t d = 0; if (start != b.start) d |= SEG_DIFFERS_BOUNDS; if (stop != b.stop) d |= SEG_DIFFERS_BOUNDS; @@ -1595,19 +1606,6 @@ Segment& WS2812FX::getSegment(unsigned id) { return _segments[id >= _segments.size() ? getMainSegmentId() : id]; // vectors } -// sets new segment bounds, queues if that segment is currently running -void WS2812FX::setSegment(uint8_t segId, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing, uint16_t offset, uint16_t startY, uint16_t stopY) { - if (segId >= getSegmentsNum()) { - if (i2 <= i1) return; // do not append empty/inactive segments - appendSegment(Segment(0, strip.getLengthTotal())); - segId = getSegmentsNum()-1; // segments are added at the end of list - } - suspend(); - _segments[segId].setUp(i1, i2, grouping, spacing, offset, startY, stopY); - resume(); - if (segId > 0 && segId == getSegmentsNum()-1 && i2 <= i1) _segments.pop_back(); // if last segment was deleted remove it from vector -} - void WS2812FX::resetSegments() { _segments.clear(); // destructs all Segment as part of clearing #ifndef WLED_DISABLE_2D diff --git a/wled00/json.cpp b/wled00/json.cpp index 0df7294c8..64b9ddd8d 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -34,7 +34,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) //DEBUG_PRINTLN(F("-- JSON deserialize segment.")); Segment& seg = strip.getSegment(id); //DEBUG_PRINTF_P(PSTR("-- Original segment: %p (%p)\n"), &seg, seg.data); - Segment prev = seg; //make a backup so we can tell if something changed (calling copy constructor) + const Segment prev = seg; //make a backup so we can tell if something changed (calling copy constructor) //DEBUG_PRINTF_P(PSTR("-- Duplicate segment: %p (%p)\n"), &prev, prev.data); int start = elem["start"] | seg.start; @@ -96,17 +96,11 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) uint16_t of = seg.offset; uint8_t soundSim = elem["si"] | seg.soundSim; uint8_t map1D2D = elem["m12"] | seg.map1D2D; - - if ((spc>0 && spc!=seg.spacing) || seg.map1D2D!=map1D2D) seg.fill(BLACK); // clear spacing gaps - - seg.map1D2D = constrain(map1D2D, 0, 7); + uint8_t set = elem[F("set")] | seg.set; + seg.set = constrain(set, 0, 3); seg.soundSim = constrain(soundSim, 0, 3); - uint8_t set = elem[F("set")] | seg.set; - seg.set = constrain(set, 0, 3); - - int len = 1; - if (stop > start) len = stop - start; + int len = (stop > start) ? stop - start : 1; int offset = elem[F("of")] | INT32_MAX; if (offset != INT32_MAX) { int offsetAbs = abs(offset); @@ -117,7 +111,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) if (stop > start && of > len -1) of = len -1; // update segment (delete if necessary) - seg.setUp(start, stop, grp, spc, of, startY, stopY); // strip needs to be suspended for this to work without issues + seg.setGeometry(start, stop, grp, spc, of, startY, stopY, map1D2D); // strip needs to be suspended for this to work without issues if (newSeg) seg.refreshLightCapabilities(); // fix for #3403 diff --git a/wled00/set.cpp b/wled00/set.cpp index cf3a07dd0..15981d30d 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -874,7 +874,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) if (pos > 0) { spcI = std::max(0,getNumVal(&req, pos)); } - strip.setSegment(selectedSeg, startI, stopI, grpI, spcI, UINT16_MAX, startY, stopY); + strip.suspend(); // must suspend strip operations before changing geometry + selseg.setGeometry(startI, stopI, grpI, spcI, UINT16_MAX, startY, stopY, selseg.map1D2D); + strip.resume(); pos = req.indexOf(F("RV=")); //Segment reverse if (pos > 0) selseg.reverse = req.charAt(pos+3) != '0'; diff --git a/wled00/udp.cpp b/wled00/udp.cpp index a6a0f6aa2..47398bc8a 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -260,11 +260,12 @@ void parseNotifyPacket(uint8_t *udpIn) { // are we syncing bounds and slave has more active segments than master? if (receiveSegmentBounds && numSrcSegs < strip.getActiveSegmentsNum()) { DEBUG_PRINTLN(F("Removing excessive segments.")); - for (size_t i=strip.getSegmentsNum(); i>numSrcSegs; i--) { - if (strip.getSegment(i).isActive()) { - strip.setSegment(i-1,0,0); // delete segment - } + strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case" + for (size_t i=strip.getSegmentsNum(); i>numSrcSegs && i>0; i--) { + Segment &seg = strip.getSegment(i-1); + if (seg.isActive()) seg.deactivate(); // delete segment } + strip.resume(); } size_t inactiveSegs = 0; for (size_t i = 0; i < numSrcSegs && i < strip.getMaxSegments(); i++) { @@ -300,7 +301,7 @@ void parseNotifyPacket(uint8_t *udpIn) { if (!receiveSegmentOptions) { DEBUG_PRINTF_P(PSTR("Set segment w/o options: %d [%d,%d;%d,%d]\n"), id, (int)start, (int)stop, (int)startY, (int)stopY); strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case" - selseg.setUp(start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY); + selseg.setGeometry(start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY, selseg.map1D2D); strip.resume(); continue; // we do receive bounds, but not options } @@ -342,12 +343,12 @@ void parseNotifyPacket(uint8_t *udpIn) { if (receiveSegmentBounds) { DEBUG_PRINTF_P(PSTR("Set segment w/ options: %d [%d,%d;%d,%d]\n"), id, (int)start, (int)stop, (int)startY, (int)stopY); strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case" - selseg.setUp(start, stop, udpIn[5+ofs], udpIn[6+ofs], offset, startY, stopY); + selseg.setGeometry(start, stop, udpIn[5+ofs], udpIn[6+ofs], offset, startY, stopY, selseg.map1D2D); strip.resume(); } else { DEBUG_PRINTF_P(PSTR("Set segment grouping: %d [%d,%d]\n"), id, (int)udpIn[5+ofs], (int)udpIn[6+ofs]); strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case" - selseg.setUp(selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], selseg.offset, selseg.startY, selseg.stopY); + selseg.setGeometry(selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], selseg.offset, selseg.startY, selseg.stopY, selseg.map1D2D); strip.resume(); } } From 536444f9d1fae4c092a6cfd2f3d944e31cf30055 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 9 Nov 2024 16:38:18 +0100 Subject: [PATCH 126/234] fixed palette FX to more closely match original 1D version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - rotation scale is now exactly 180° (divide slider input by 255 instead of 256) - removed shift offset: offset is now zero at slider 0, to hit 128 on touch input devices is really hard - added a 90° shift to input rotation, enabling to rotate from 0 to 180° instead of +90 to -90 (which is not useful in 1D) - changed default settings values to more closely match the old 1D effect --- wled00/FX.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 2f24f745a..47200655d 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -1940,7 +1940,7 @@ uint16_t mode_palette() { using angleType = unsigned; constexpr mathType sInt16Scale = 0x7FFF; constexpr mathType maxAngle = 0x8000; - constexpr mathType staticRotationScale = 256; + constexpr mathType staticRotationScale = 255; constexpr mathType animatedRotationScale = 1; constexpr int16_t (*sinFunction)(uint16_t) = &sin16; constexpr int16_t (*cosFunction)(uint16_t) = &cos16; @@ -1949,7 +1949,7 @@ uint16_t mode_palette() { using wideMathType = float; using angleType = float; constexpr mathType sInt16Scale = 1.0f; - constexpr mathType maxAngle = M_PI / 256.0; + constexpr mathType maxAngle = M_PI / 255.0; constexpr mathType staticRotationScale = 1.0f; constexpr mathType animatedRotationScale = M_TWOPI / double(0xFFFF); constexpr float (*sinFunction)(float) = &sin_t; @@ -1961,7 +1961,7 @@ uint16_t mode_palette() { const int inputShift = SEGMENT.speed; const int inputSize = SEGMENT.intensity; - const int inputRotation = SEGMENT.custom1; + const int inputRotation = SEGMENT.custom1 + 128; const bool inputAnimateShift = SEGMENT.check1; const bool inputAnimateRotation = SEGMENT.check2; const bool inputAssumeSquare = SEGMENT.check3; @@ -1985,7 +1985,7 @@ uint16_t mode_palette() { // So the rectangle needs to have exactly the right size. That size depends on the rotation. // This scale computation here only considers one dimension. You can think of it like the rectangle is always scaled so that // the left and right most points always match the left and right side of the display. - const mathType scale = std::abs(sinTheta) + (std::abs(cosTheta) * maxYOut / maxXOut); + const mathType scale = std::abs(sinTheta) + (std::abs(cosTheta) * maxYOut / maxXOut); // 2D simulation: // If we are dealing with a 1D setup, we assume that each segment represents one line on a 2-dimensional display. // The function is called once per segments, so we need to handle one line at a time. @@ -2016,7 +2016,7 @@ uint16_t mode_palette() { colorIndex = ((inputSize - 112) * colorIndex) / 16; } // Finally, shift the palette a bit. - const int paletteOffset = (!inputAnimateShift) ? (inputShift-128) : (((strip.now * ((inputShift >> 3) +1)) & 0xFFFF) >> 8); + const int paletteOffset = (!inputAnimateShift) ? (inputShift) : (((strip.now * ((inputShift >> 3) +1)) & 0xFFFF) >> 8); colorIndex += paletteOffset; const uint32_t color = SEGMENT.color_wheel((uint8_t)colorIndex); if (isMatrix) { @@ -2028,7 +2028,7 @@ uint16_t mode_palette() { } return FRAMETIME; } -static const char _data_FX_MODE_PALETTE[] PROGMEM = "Palette@Shift,Size,Rotation,,,Animate Shift,Animate Rotation,Anamorphic;;!;12;c1=128,c2=128,c3=128,o1=1,o2=1,o3=0"; +static const char _data_FX_MODE_PALETTE[] PROGMEM = "Palette@Shift,Size,Rotation,,,Animate Shift,Animate Rotation,Anamorphic;;!;12;ix=112,c1=0,o1=1,o2=0,o3=1"; // WLED limitation: Analog Clock overlay will NOT work when Fire2012 is active From 5de86d3d9166e1d629d5fdcd128008360378dccd Mon Sep 17 00:00:00 2001 From: Woody <27882680+w00000dy@users.noreply.github.com> Date: Sat, 9 Nov 2024 23:55:09 +0100 Subject: [PATCH 127/234] fix problem with spaces --- tools/cdata.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/cdata.js b/tools/cdata.js index d65573a8e..c5d3c6aa5 100644 --- a/tools/cdata.js +++ b/tools/cdata.js @@ -101,6 +101,7 @@ function adoptVersionAndRepo(html) { async function minify(str, type = "plain") { const options = { collapseWhitespace: true, + conservativeCollapse: true, // preserve spaces in text collapseBooleanAttributes: true, collapseInlineTagWhitespace: true, minifyCSS: true, From 9a564ee20457664e09f2d12aeceac874d1edef53 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sun, 10 Nov 2024 14:45:55 +0100 Subject: [PATCH 128/234] readme.md - link to multi-strip KB page --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 595b9ee0b..0a02826af 100644 --- a/readme.md +++ b/readme.md @@ -21,7 +21,7 @@ A fast and feature-rich implementation of an ESP32 and ESP8266 webserver to cont - Segments to set different effects and colors to user defined parts of the LED string - Settings page - configuration via the network - Access Point and station mode - automatic failsafe AP -- Up to 10 LED outputs per instance +- [Up to 10 LED outputs](https://kno.wled.ge/features/multi-strip/#esp32) per instance - Support for RGBW strips - Up to 250 user presets to save and load colors/effects easily, supports cycling through them. - Presets can be used to automatically execute API calls From d437027f2630c88ea660fa4e4ad199f537b1abea Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 10 Nov 2024 22:39:52 +0100 Subject: [PATCH 129/234] Replaced single palette cases with an array to consolidate code - all palettes are defined in palettes.h - access to fastled palettes as an array to remove the switch cases - palette createn in json.cpp in a loop instead of repeaded calls to save flash --- wled00/FX_fcn.cpp | 16 ++------------- wled00/json.cpp | 52 ++++++++--------------------------------------- wled00/palettes.h | 11 ++++++++++ 3 files changed, 21 insertions(+), 58 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index e706f2b43..d666513ae 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -236,23 +236,11 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) { targetPalette = CRGBPalette16(prim,prim,prim,prim,prim,prim,prim,prim,sec,sec,sec,sec,sec,sec,sec,sec); } break;} - case 6: //Party colors - targetPalette = PartyColors_p; break; - case 7: //Cloud colors - targetPalette = CloudColors_p; break; - case 8: //Lava colors - targetPalette = LavaColors_p; break; - case 9: //Ocean colors - targetPalette = OceanColors_p; break; - case 10: //Forest colors - targetPalette = ForestColors_p; break; - case 11: //Rainbow colors - targetPalette = RainbowColors_p; break; - case 12: //Rainbow stripe colors - targetPalette = RainbowStripeColors_p; break; default: //progmem palettes if (pal>245) { targetPalette = strip.customPalettes[255-pal]; // we checked bounds above + } else if (pal < 13) { // palette 6 - 12, fastled palettes + targetPalette = *fastledPalettes[pal-6]; } else { byte tcp[72]; memcpy_P(tcp, (byte*)pgm_read_dword(&(gGradientPalettes[pal-13])), 72); diff --git a/wled00/json.cpp b/wled00/json.cpp index 288059653..c74bf6a8d 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -902,10 +902,7 @@ void serializePalettes(JsonObject root, int page) setPaletteColors(curPalette, PartyColors_p); break; case 1: //random - curPalette.add("r"); - curPalette.add("r"); - curPalette.add("r"); - curPalette.add("r"); + for (int j = 0; j < 4; j++) curPalette.add("r"); break; case 2: //primary color only curPalette.add("c1"); @@ -922,53 +919,20 @@ void serializePalettes(JsonObject root, int page) curPalette.add("c1"); break; case 5: //primary + secondary (+tertiary if not off), more distinct + for (int j = 0; j < 5; j++) curPalette.add("c1"); + for (int j = 0; j < 5; j++) curPalette.add("c2"); + for (int j = 0; j < 5; j++) curPalette.add("c3"); curPalette.add("c1"); - curPalette.add("c1"); - curPalette.add("c1"); - curPalette.add("c1"); - curPalette.add("c1"); - curPalette.add("c2"); - curPalette.add("c2"); - curPalette.add("c2"); - curPalette.add("c2"); - curPalette.add("c2"); - curPalette.add("c3"); - curPalette.add("c3"); - curPalette.add("c3"); - curPalette.add("c3"); - curPalette.add("c3"); - curPalette.add("c1"); - break; - case 6: //Party colors - setPaletteColors(curPalette, PartyColors_p); - break; - case 7: //Cloud colors - setPaletteColors(curPalette, CloudColors_p); - break; - case 8: //Lava colors - setPaletteColors(curPalette, LavaColors_p); - break; - case 9: //Ocean colors - setPaletteColors(curPalette, OceanColors_p); - break; - case 10: //Forest colors - setPaletteColors(curPalette, ForestColors_p); - break; - case 11: //Rainbow colors - setPaletteColors(curPalette, RainbowColors_p); - break; - case 12: //Rainbow stripe colors - setPaletteColors(curPalette, RainbowStripeColors_p); break; default: - { - if (i>=palettesCount) { + if (i >= palettesCount) setPaletteColors(curPalette, strip.customPalettes[i - palettesCount]); - } else { + else if (i < 13) // palette 6 - 12, fastled palettes + setPaletteColors(curPalette, *fastledPalettes[i-6]); + else { memcpy_P(tcp, (byte*)pgm_read_dword(&(gGradientPalettes[i - 13])), 72); setPaletteColors(curPalette, tcp); } - } break; } } diff --git a/wled00/palettes.h b/wled00/palettes.h index 41dfbbc16..1ead342bb 100644 --- a/wled00/palettes.h +++ b/wled00/palettes.h @@ -844,6 +844,17 @@ const byte candy2_gp[] PROGMEM = { 211, 39, 33, 34, 255, 1, 1, 1}; +// array of fastled palettes (palette 6 - 12) +const TProgmemRGBPalette16 *const fastledPalettes[] PROGMEM = { + &PartyColors_p, //06-00 Party + &CloudColors_p, //07-01 Cloud + &LavaColors_p, //08-02 Lava + &OceanColors_p, //09-03 Ocean + &ForestColors_p, //10-04 Forest + &RainbowColors_p, //11-05 Rainbow + &RainbowStripeColors_p //12-06 Rainbow Bands +}; + // Single array of defined cpt-city color palettes. // This will let us programmatically choose one based on // a number, rather than having to activate each explicitly From 223b97b8848d8f44c891ea511dadc20e40270cf7 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 10 Nov 2024 18:04:07 -0500 Subject: [PATCH 130/234] handleSet: Fix incorrect response generation Don't generate a response if there's no HTTP request. Fixes #4269 --- wled00/set.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/set.cpp b/wled00/set.cpp index c446a2eff..712e5f254 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -1191,7 +1191,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) // internal call, does not send XML response pos = req.indexOf(F("IN")); - if (pos < 1) { + if ((request != nullptr) && (pos < 1)) { auto response = request->beginResponseStream("text/xml"); XML_response(*response); request->send(response); From 8c5e0cd4e94ebc4a2d59c24fce620f6e3540c903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Fri, 15 Nov 2024 16:01:58 +0100 Subject: [PATCH 131/234] Keep selected FX while searching --- wled00/data/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/data/index.js b/wled00/data/index.js index d9c64bdfb..cbc389391 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -2850,7 +2850,7 @@ function search(field, listId = null) { if (listId!=='pcont' && i===0) return; const listItemName = listItem.querySelector('.lstIname').innerText.toUpperCase(); const searchIndex = listItemName.indexOf(field.value.toUpperCase()); - listItem.style.display = (searchIndex < 0) ? 'none' : ''; + listItem.style.display = (searchIndex < 0) && !listItem.classList.contains("selected") ? 'none' : ''; listItem.dataset.searchIndex = searchIndex; }); @@ -2924,7 +2924,7 @@ function filterFx() { const listItemName = listItem.querySelector('.lstIname').innerText; let hide = false; gId("filters").querySelectorAll("input[type=checkbox]").forEach((e) => { if (e.checked && !listItemName.includes(e.dataset.flt)) hide = i>0 /*true*/; }); - listItem.style.display = hide ? 'none' : ''; + listItem.style.display = hide && !listItem.classList.contains("selected") ? 'none' : ''; }); } From 86be5df475468824cee3654efc6175170d3dbf83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Fri, 15 Nov 2024 19:03:46 +0100 Subject: [PATCH 132/234] xml comma bugfix + few optimisations --- wled00/xml.cpp | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/wled00/xml.cpp b/wled00/xml.cpp index dc2673271..a4a72abea 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -83,7 +83,7 @@ void appendGPIOinfo(Print& settingsScript) { // usermod pin reservations will become unnecessary when settings pages will read cfg.json directly if (requestJSONBufferLock(6)) { // if we can't allocate JSON buffer ignore usermod pins - JsonObject mods = pDoc->createNestedObject(F("um")); + JsonObject mods = pDoc->createNestedObject("um"); UsermodManager::addToConfig(mods); if (!mods.isNull()) fillUMPins(settingsScript, mods); releaseJSONBufferLock(); @@ -91,35 +91,42 @@ void appendGPIOinfo(Print& settingsScript) { settingsScript.print(F("];")); // add reserved (unusable) pins + bool firstPin = true; settingsScript.print(F("d.rsvd=[")); for (unsigned i = 0; i < WLED_NUM_PINS; i++) { if (!PinManager::isPinOk(i, false)) { // include readonly pins - settingsScript.print(i); settingsScript.print(","); + if (!firstPin) settingsScript.print(','); + settingsScript.print(i); + firstPin = false; } } #ifdef WLED_ENABLE_DMX - settingsScript.print(F("2,")); // DMX hardcoded pin + if (!firstPin) settingsScript.print(','); + settingsScript.print(2); // DMX hardcoded pin + firstPin = false; #endif #if defined(WLED_DEBUG) && !defined(WLED_DEBUG_HOST) - settingsScript.printf_P(PSTR(",%d"),hardwareTX); // debug output (TX) pin + if (!firstPin) settingsScript.print(','); + settingsScript.print(hardwareTX); // debug output (TX) pin + firstPin = false; #endif - //Note: Using pin 3 (RX) disables Adalight / Serial JSON #ifdef WLED_USE_ETHERNET if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) { - for (unsigned p=0; p=0) { settingsScript.printf(",%d", ethernetBoards[ethernetType].eth_power); } - if (ethernetBoards[ethernetType].eth_mdc>=0) { settingsScript.printf(",%d", ethernetBoards[ethernetType].eth_mdc); } - if (ethernetBoards[ethernetType].eth_mdio>=0) { settingsScript.printf(",%d", ethernetBoards[ethernetType].eth_mdio); } - switch (ethernetBoards[ethernetType].eth_clk_mode) { + if (!firstPin) settingsScript.print(','); + for (unsigned p=0; p= 0) { settingsScript.printf("%d,",ethernetBoards[ethernetType].eth_power); } + if (ethernetBoards[ethernetType].eth_mdc >= 0) { settingsScript.printf("%d,",ethernetBoards[ethernetType].eth_mdc); } + if (ethernetBoards[ethernetType].eth_mdio >= 0) { settingsScript.printf("%d,",ethernetBoards[ethernetType].eth_mdio); } + switch (ethernetBoards[ethernetType].eth_clk_mode) { case ETH_CLOCK_GPIO0_IN: case ETH_CLOCK_GPIO0_OUT: - settingsScript.print(F("0")); + settingsScript.print(0); break; case ETH_CLOCK_GPIO16_OUT: - settingsScript.print(F("16")); + settingsScript.print(16); break; case ETH_CLOCK_GPIO17_OUT: - settingsScript.print(F("17")); + settingsScript.print(17); break; } } @@ -128,11 +135,11 @@ void appendGPIOinfo(Print& settingsScript) { // add info for read-only GPIO settingsScript.print(F("d.ro_gpio=[")); - bool firstPin = true; + firstPin = true; for (unsigned i = 0; i < WLED_NUM_PINS; i++) { if (PinManager::isReadOnlyPin(i)) { // No comma before the first pin - if (!firstPin) settingsScript.print(F(",")); + if (!firstPin) settingsScript.print(','); settingsScript.print(i); firstPin = false; } @@ -142,7 +149,7 @@ void appendGPIOinfo(Print& settingsScript) { // add info about max. # of pins settingsScript.print(F("d.max_gpio=")); settingsScript.print(WLED_NUM_PINS); - settingsScript.print(F(";")); + settingsScript.print(';'); } //get values for settings form in javascript @@ -152,6 +159,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) DEBUG_PRINTF_P(PSTR("settings resp %u\n"), (unsigned)subPage); if (subPage <0 || subPage >10) return; + char nS[32]; if (subPage == SUBPAGE_MENU) { @@ -259,8 +267,6 @@ void getSettingsJS(byte subPage, Print& settingsScript) if (subPage == SUBPAGE_LEDS) { - char nS[32]; - appendGPIOinfo(settingsScript); settingsScript.print(F("d.ledTypes=")); settingsScript.print(BusManager::getLEDTypesJSONString().c_str()); settingsScript.print(";"); @@ -399,7 +405,6 @@ void getSettingsJS(byte subPage, Print& settingsScript) if (subPage == SUBPAGE_SYNC) { - [[maybe_unused]] char nS[32]; printSetFormValue(settingsScript,PSTR("UP"),udpPort); printSetFormValue(settingsScript,PSTR("U2"),udpPort2); #ifndef WLED_DISABLE_ESPNOW @@ -637,7 +642,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) #if defined(ARDUINO_ARCH_ESP32) ESP.getChipModel(), #else - F("esp8266"), + "esp8266", #endif VERSION); From 7f69a0bc5ec42c507f3923b456257c517b65e1ef Mon Sep 17 00:00:00 2001 From: maxi4329 Date: Sat, 16 Nov 2024 12:37:24 +0100 Subject: [PATCH 133/234] removed obsolete code as of #4267 --- wled00/data/style.css | 3 --- wled00/data/update.htm | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/wled00/data/style.css b/wled00/data/style.css index 42e49d304..b6cb0f9e6 100644 --- a/wled00/data/style.css +++ b/wled00/data/style.css @@ -44,9 +44,6 @@ button.sml { min-width: 40px; margin: 0 0 0 10px; } -span:before, b:before, b:after, i:after{ - content: "\00A0"; -} #scan { margin-top: -10px; } diff --git a/wled00/data/update.htm b/wled00/data/update.htm index b68645a52..23a6a866e 100644 --- a/wled00/data/update.htm +++ b/wled00/data/update.htm @@ -17,7 +17,7 @@

WLED Software Update

Installed version: ##VERSION##
- Download the latest binary: 

From 6fe2024542b12fc17af98fa6402ca5f557a6d958 Mon Sep 17 00:00:00 2001 From: Woody <27882680+w00000dy@users.noreply.github.com> Date: Sat, 16 Nov 2024 19:53:10 +0100 Subject: [PATCH 134/234] move selected to the bottom in search result --- wled00/data/index.js | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/wled00/data/index.js b/wled00/data/index.js index cbc389391..f93511aaf 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -2827,7 +2827,7 @@ function search(field, listId = null) { // restore default preset sorting if no search term is entered if (!search) { - if (listId === 'pcont') { populatePresets(); return; } + if (listId === 'pcont') { populatePresets(); return; } if (listId === 'pallist') { let id = parseInt(d.querySelector('#pallist input[name="palette"]:checked').value); // preserve selected palette populatePalettes(); @@ -2846,12 +2846,17 @@ function search(field, listId = null) { // filter list items but leave (Default & Solid) always visible const listItems = gId(listId).querySelectorAll('.lstI'); - listItems.forEach((listItem,i)=>{ - if (listId!=='pcont' && i===0) return; + listItems.forEach((listItem, i) => { const listItemName = listItem.querySelector('.lstIname').innerText.toUpperCase(); const searchIndex = listItemName.indexOf(field.value.toUpperCase()); - listItem.style.display = (searchIndex < 0) && !listItem.classList.contains("selected") ? 'none' : ''; - listItem.dataset.searchIndex = searchIndex; + if (searchIndex < 0) { + listItem.dataset.searchIndex = Number.MAX_SAFE_INTEGER; + } else { + listItem.dataset.searchIndex = searchIndex; + } + + if ((listId !== 'pcont' && i === 0) || listItem.classList.contains("selected")) return; + listItem.style.display = (searchIndex < 0) ? 'none' : ''; }); // sort list items by search index and name @@ -2920,10 +2925,10 @@ function filterFx() { inputField.value = ''; inputField.focus(); clean(inputField.nextElementSibling); - gId("fxlist").querySelectorAll('.lstI').forEach((listItem,i) => { + gId("fxlist").querySelectorAll('.lstI').forEach((listItem, i) => { const listItemName = listItem.querySelector('.lstIname').innerText; let hide = false; - gId("filters").querySelectorAll("input[type=checkbox]").forEach((e) => { if (e.checked && !listItemName.includes(e.dataset.flt)) hide = i>0 /*true*/; }); + gId("filters").querySelectorAll("input[type=checkbox]").forEach((e) => { if (e.checked && !listItemName.includes(e.dataset.flt)) hide = i > 0 /*true*/; }); listItem.style.display = hide && !listItem.classList.contains("selected") ? 'none' : ''; }); } From 4d3df5d98fb283e936db9eb7f19406a3a5a38b24 Mon Sep 17 00:00:00 2001 From: Woody <27882680+w00000dy@users.noreply.github.com> Date: Sat, 16 Nov 2024 20:12:29 +0100 Subject: [PATCH 135/234] Fix default/solid not being first --- wled00/data/index.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/wled00/data/index.js b/wled00/data/index.js index f93511aaf..1482c27b5 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -2847,6 +2847,7 @@ function search(field, listId = null) { // filter list items but leave (Default & Solid) always visible const listItems = gId(listId).querySelectorAll('.lstI'); listItems.forEach((listItem, i) => { + if (listId !== 'pcont' && i === 0) return; const listItemName = listItem.querySelector('.lstIname').innerText.toUpperCase(); const searchIndex = listItemName.indexOf(field.value.toUpperCase()); if (searchIndex < 0) { @@ -2854,9 +2855,7 @@ function search(field, listId = null) { } else { listItem.dataset.searchIndex = searchIndex; } - - if ((listId !== 'pcont' && i === 0) || listItem.classList.contains("selected")) return; - listItem.style.display = (searchIndex < 0) ? 'none' : ''; + listItem.style.display = (searchIndex < 0) && !listItem.classList.contains("selected") ? 'none' : ''; }); // sort list items by search index and name From a765903a41d3272c166ff5351da5c0338947c183 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sat, 16 Nov 2024 17:10:08 -0500 Subject: [PATCH 136/234] Fix array overflow in exploding_fireworks Attempt to allocate enough room for the "minimum" sparks; and ensure that we never overrun the allocated array size. Fixes #4120 --- wled00/FX.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 2f24f745a..947788fee 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -3547,7 +3547,7 @@ uint16_t mode_exploding_fireworks(void) if (segs <= (strip.getMaxSegments() /4)) maxData *= 2; //ESP8266: 1024 if <= 4 segs ESP32: 2560 if <= 8 segs int maxSparks = maxData / sizeof(spark); //ESP8266: max. 21/42/85 sparks/seg, ESP32: max. 53/106/213 sparks/seg - unsigned numSparks = min(2 + ((rows*cols) >> 1), maxSparks); + unsigned numSparks = min(5 + ((rows*cols) >> 1), maxSparks); unsigned dataSize = sizeof(spark) * numSparks; if (!SEGENV.allocateData(dataSize + sizeof(float))) return mode_static(); //allocation failed float *dying_gravity = reinterpret_cast(SEGENV.data + dataSize); @@ -3602,7 +3602,8 @@ uint16_t mode_exploding_fireworks(void) * Size is proportional to the height. */ unsigned nSparks = flare->pos + random8(4); - nSparks = constrain(nSparks, 4, numSparks); + nSparks = std::max(nSparks, 4U); // This is not a standard constrain; numSparks is not guaranteed to be at least 4 + nSparks = std::min(nSparks, numSparks); // initialize sparks if (SEGENV.aux0 == 2) { From 84dd26c1b7d90b2f4466253bc9e6b9faa545451a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sun, 17 Nov 2024 10:47:09 +0100 Subject: [PATCH 137/234] Some more optimisations. --- wled00/xml.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/wled00/xml.cpp b/wled00/xml.cpp index a4a72abea..df52b6248 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -147,9 +147,7 @@ void appendGPIOinfo(Print& settingsScript) { settingsScript.print(F("];")); // add info about max. # of pins - settingsScript.print(F("d.max_gpio=")); - settingsScript.print(WLED_NUM_PINS); - settingsScript.print(';'); + settingsScript.printf_P(PSTR("d.max_gpio=%d;"),WLED_NUM_PINS); } //get values for settings form in javascript @@ -269,7 +267,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) { appendGPIOinfo(settingsScript); - settingsScript.print(F("d.ledTypes=")); settingsScript.print(BusManager::getLEDTypesJSONString().c_str()); settingsScript.print(";"); + settingsScript.printf_P(PSTR("d.ledTypes=%s;"), BusManager::getLEDTypesJSONString().c_str()); // set limits settingsScript.printf_P(PSTR("bLimits(%d,%d,%d,%d,%d,%d,%d,%d);"), @@ -653,8 +651,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) { printSetFormValue(settingsScript,PSTR("SOMP"),strip.isMatrix); #ifndef WLED_DISABLE_2D - settingsScript.printf_P(PSTR("maxPanels=%d;"),WLED_MAX_PANELS); - settingsScript.print(F("resetPanels();")); + settingsScript.printf_P(PSTR("maxPanels=%d;resetPanels();"),WLED_MAX_PANELS); if (strip.isMatrix) { if(strip.panels>0){ printSetFormValue(settingsScript,PSTR("PW"),strip.panel[0].width); //Set generator Width and Height to first panel size for convenience @@ -664,11 +661,9 @@ void getSettingsJS(byte subPage, Print& settingsScript) // panels for (unsigned i=0; i Date: Sun, 17 Nov 2024 14:31:23 +0100 Subject: [PATCH 138/234] Bugfix --- wled00/xml.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wled00/xml.cpp b/wled00/xml.cpp index df52b6248..597db73f2 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -660,8 +660,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) printSetFormValue(settingsScript,PSTR("MPC"),strip.panels); // panels for (unsigned i=0; i Date: Wed, 20 Nov 2024 12:39:39 +0100 Subject: [PATCH 139/234] Use MQTT_MAX_TOPIC_LEN in places where it was not used before to avoid buffer overflows when value is increased --- wled00/button.cpp | 8 ++++---- wled00/mqtt.cpp | 22 +++++++++++----------- wled00/wled.h | 8 ++++---- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/wled00/button.cpp b/wled00/button.cpp index 4d6f954f6..6f9c84560 100644 --- a/wled00/button.cpp +++ b/wled00/button.cpp @@ -29,7 +29,7 @@ void shortPressAction(uint8_t b) #ifndef WLED_DISABLE_MQTT // publish MQTT message if (buttonPublishMqtt && WLED_MQTT_CONNECTED) { - char subuf[64]; + char subuf[MQTT_MAX_TOPIC_LEN + 32]; sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b); mqtt->publish(subuf, 0, false, "short"); } @@ -62,7 +62,7 @@ void longPressAction(uint8_t b) #ifndef WLED_DISABLE_MQTT // publish MQTT message if (buttonPublishMqtt && WLED_MQTT_CONNECTED) { - char subuf[64]; + char subuf[MQTT_MAX_TOPIC_LEN + 32]; sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b); mqtt->publish(subuf, 0, false, "long"); } @@ -83,7 +83,7 @@ void doublePressAction(uint8_t b) #ifndef WLED_DISABLE_MQTT // publish MQTT message if (buttonPublishMqtt && WLED_MQTT_CONNECTED) { - char subuf[64]; + char subuf[MQTT_MAX_TOPIC_LEN + 32]; sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b); mqtt->publish(subuf, 0, false, "double"); } @@ -151,7 +151,7 @@ void handleSwitch(uint8_t b) #ifndef WLED_DISABLE_MQTT // publish MQTT message if (buttonPublishMqtt && WLED_MQTT_CONNECTED) { - char subuf[64]; + char subuf[MQTT_MAX_TOPIC_LEN + 32]; if (buttonType[b] == BTN_TYPE_PIR_SENSOR) sprintf_P(subuf, PSTR("%s/motion/%d"), mqttDeviceTopic, (int)b); else sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b); mqtt->publish(subuf, 0, false, !buttonPressedBefore[b] ? "off" : "on"); diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp index a476db87a..d909494ee 100644 --- a/wled00/mqtt.cpp +++ b/wled00/mqtt.cpp @@ -23,24 +23,24 @@ static void parseMQTTBriPayload(char* payload) static void onMqttConnect(bool sessionPresent) { //(re)subscribe to required topics - char subuf[38]; + char subuf[MQTT_MAX_TOPIC_LEN + 6]; if (mqttDeviceTopic[0] != 0) { - strlcpy(subuf, mqttDeviceTopic, 33); + strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); mqtt->subscribe(subuf, 0); strcat_P(subuf, PSTR("/col")); mqtt->subscribe(subuf, 0); - strlcpy(subuf, mqttDeviceTopic, 33); + strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); strcat_P(subuf, PSTR("/api")); mqtt->subscribe(subuf, 0); } if (mqttGroupTopic[0] != 0) { - strlcpy(subuf, mqttGroupTopic, 33); + strlcpy(subuf, mqttGroupTopic, MQTT_MAX_TOPIC_LEN + 1); mqtt->subscribe(subuf, 0); strcat_P(subuf, PSTR("/col")); mqtt->subscribe(subuf, 0); - strlcpy(subuf, mqttGroupTopic, 33); + strlcpy(subuf, mqttGroupTopic, MQTT_MAX_TOPIC_LEN + 1); strcat_P(subuf, PSTR("/api")); mqtt->subscribe(subuf, 0); } @@ -158,19 +158,19 @@ void publishMqtt() #ifndef USERMOD_SMARTNEST char s[10]; - char subuf[48]; + char subuf[MQTT_MAX_TOPIC_LEN + 16]; sprintf_P(s, PSTR("%u"), bri); - strlcpy(subuf, mqttDeviceTopic, 33); + strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); strcat_P(subuf, PSTR("/g")); mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263) sprintf_P(s, PSTR("#%06X"), (col[3] << 24) | (col[0] << 16) | (col[1] << 8) | (col[2])); - strlcpy(subuf, mqttDeviceTopic, 33); + strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); strcat_P(subuf, PSTR("/c")); mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263) - strlcpy(subuf, mqttDeviceTopic, 33); + strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); strcat_P(subuf, PSTR("/status")); mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT @@ -178,7 +178,7 @@ void publishMqtt() DynamicBuffer buf(1024); bufferPrint pbuf(buf.data(), buf.size()); XML_response(pbuf); - strlcpy(subuf, mqttDeviceTopic, 33); + strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); strcat_P(subuf, PSTR("/v")); mqtt->publish(subuf, 0, retainMqttMsg, buf.data(), pbuf.size()); // optionally retain message (#2263) #endif @@ -211,7 +211,7 @@ bool initMqtt() if (mqttUser[0] && mqttPass[0]) mqtt->setCredentials(mqttUser, mqttPass); #ifndef USERMOD_SMARTNEST - strlcpy(mqttStatusTopic, mqttDeviceTopic, 33); + strlcpy(mqttStatusTopic, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); strcat_P(mqttStatusTopic, PSTR("/status")); mqtt->setWill(mqttStatusTopic, 0, true, "offline"); // LWT message #endif diff --git a/wled00/wled.h b/wled00/wled.h index 2b3a77d24..29b43753a 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -483,10 +483,10 @@ WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0); // used for other #endif WLED_GLOBAL AsyncMqttClient *mqtt _INIT(NULL); WLED_GLOBAL bool mqttEnabled _INIT(false); -WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers -WLED_GLOBAL char mqttDeviceTopic[MQTT_MAX_TOPIC_LEN+1] _INIT(""); // main MQTT topic (individual per device, default is wled/mac) -WLED_GLOBAL char mqttGroupTopic[MQTT_MAX_TOPIC_LEN+1] _INIT("wled/all"); // second MQTT topic (for example to group devices) -WLED_GLOBAL char mqttServer[MQTT_MAX_SERVER_LEN+1] _INIT(""); // both domains and IPs should work (no SSL) +WLED_GLOBAL char mqttStatusTopic[MQTT_MAX_TOPIC_LEN + 8] _INIT(""); // this must be global because of async handlers +WLED_GLOBAL char mqttDeviceTopic[MQTT_MAX_TOPIC_LEN + 1] _INIT(""); // main MQTT topic (individual per device, default is wled/mac) +WLED_GLOBAL char mqttGroupTopic[MQTT_MAX_TOPIC_LEN + 1] _INIT("wled/all"); // second MQTT topic (for example to group devices) +WLED_GLOBAL char mqttServer[MQTT_MAX_SERVER_LEN + 1] _INIT(""); // both domains and IPs should work (no SSL) WLED_GLOBAL char mqttUser[41] _INIT(""); // optional: username for MQTT auth WLED_GLOBAL char mqttPass[65] _INIT(""); // optional: password for MQTT auth WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID From cec89788865bf29aae0799f03ba0c8c43638d297 Mon Sep 17 00:00:00 2001 From: Wouter Gritter Date: Wed, 20 Nov 2024 12:45:39 +0100 Subject: [PATCH 140/234] Fix comment alignment --- wled00/wled.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/wled.h b/wled00/wled.h index 29b43753a..3630170f9 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -483,7 +483,7 @@ WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0); // used for other #endif WLED_GLOBAL AsyncMqttClient *mqtt _INIT(NULL); WLED_GLOBAL bool mqttEnabled _INIT(false); -WLED_GLOBAL char mqttStatusTopic[MQTT_MAX_TOPIC_LEN + 8] _INIT(""); // this must be global because of async handlers +WLED_GLOBAL char mqttStatusTopic[MQTT_MAX_TOPIC_LEN + 8] _INIT(""); // this must be global because of async handlers WLED_GLOBAL char mqttDeviceTopic[MQTT_MAX_TOPIC_LEN + 1] _INIT(""); // main MQTT topic (individual per device, default is wled/mac) WLED_GLOBAL char mqttGroupTopic[MQTT_MAX_TOPIC_LEN + 1] _INIT("wled/all"); // second MQTT topic (for example to group devices) WLED_GLOBAL char mqttServer[MQTT_MAX_SERVER_LEN + 1] _INIT(""); // both domains and IPs should work (no SSL) From 0db47a8586526541b0cdd810b466923c64b80cd6 Mon Sep 17 00:00:00 2001 From: Wouter Gritter Date: Thu, 21 Nov 2024 09:51:13 +0100 Subject: [PATCH 141/234] Add comment warning about modification of MQTT_MAX_TOPIC_LEN --- wled00/wled.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/wled.h b/wled00/wled.h index 3630170f9..5dbc013d9 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -476,7 +476,7 @@ WLED_GLOBAL uint16_t pollReplyCount _INIT(0); // count numbe WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0); // used for other periodic tasks too #ifndef WLED_DISABLE_MQTT #ifndef MQTT_MAX_TOPIC_LEN - #define MQTT_MAX_TOPIC_LEN 32 + #define MQTT_MAX_TOPIC_LEN 32 // should not be less than 32. might cause trouble when increased with usermods active that do not handle this correctly. #endif #ifndef MQTT_MAX_SERVER_LEN #define MQTT_MAX_SERVER_LEN 32 From 49fb16e2c6528ddc98cccc352cc8f0d4a5f62a13 Mon Sep 17 00:00:00 2001 From: Wouter Gritter Date: Thu, 21 Nov 2024 10:52:22 +0100 Subject: [PATCH 142/234] Introduce printSetInputMaxlength to properly set an inputs maxlength variable --- wled00/fcn_declare.h | 1 + wled00/util.cpp | 4 ++++ wled00/xml.cpp | 5 +++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 1855a8b63..91176160f 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -380,6 +380,7 @@ size_t printSetFormValue(Print& settingsScript, const char* key, int val); size_t printSetFormValue(Print& settingsScript, const char* key, const char* val); size_t printSetFormIndex(Print& settingsScript, const char* key, int index); size_t printSetClassElementHTML(Print& settingsScript, const char* key, const int index, const char* val); +size_t printSetInputMaxLength(Print& settingsScript, const char* key, int val); void prepareHostname(char* hostname); bool isAsterisksOnly(const char* str, byte maxLen); bool requestJSONBufferLock(uint8_t module=255); diff --git a/wled00/util.cpp b/wled00/util.cpp index 0b78a4646..1c1282eda 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -109,6 +109,10 @@ size_t printSetClassElementHTML(Print& settingsScript, const char* key, const in return settingsScript.printf_P(PSTR("d.getElementsByClassName(\"%s\")[%d].innerHTML=\"%s\";"), key, index, val); } +size_t printSetInputMaxLength(Print& settingsScript, const char* key, int val) { + return settingsScript.printf_P(PSTR("d.Sf.%s.setAttribute(\"maxlength\", %d);"),key,val); +} + void prepareHostname(char* hostname) diff --git a/wled00/xml.cpp b/wled00/xml.cpp index dc2673271..6f837a9b6 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -465,8 +465,9 @@ void getSettingsJS(byte subPage, Print& settingsScript) printSetFormValue(settingsScript,PSTR("MG"),mqttGroupTopic); printSetFormCheckbox(settingsScript,PSTR("BM"),buttonPublishMqtt); printSetFormCheckbox(settingsScript,PSTR("RT"),retainMqttMsg); - settingsScript.printf_P(PSTR("d.Sf.MD.maxlength=%d;d.Sf.MG.maxlength=%d;d.Sf.MS.maxlength=%d;"), - MQTT_MAX_TOPIC_LEN, MQTT_MAX_TOPIC_LEN, MQTT_MAX_SERVER_LEN); + printSetInputMaxLength(settingsScript, PSTR("MD"), MQTT_MAX_TOPIC_LEN); + printSetInputMaxLength(settingsScript, PSTR("MG"), MQTT_MAX_TOPIC_LEN); + printSetInputMaxLength(settingsScript, PSTR("MS"), MQTT_MAX_SERVER_LEN); #else settingsScript.print(F("toggle('MQTT');")); // hide MQTT settings #endif From 8f8afd98a5dc5982271babbcce84ffff28c32fab Mon Sep 17 00:00:00 2001 From: Wouter Gritter Date: Thu, 21 Nov 2024 11:20:42 +0100 Subject: [PATCH 143/234] Replace comment with compile-time error and warning --- wled00/mqtt.cpp | 4 ++++ wled00/wled.h | 2 +- wled00/wled_eeprom.cpp | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) mode change 100755 => 100644 wled00/wled_eeprom.cpp diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp index d909494ee..38afeffe3 100644 --- a/wled00/mqtt.cpp +++ b/wled00/mqtt.cpp @@ -7,6 +7,10 @@ #ifndef WLED_DISABLE_MQTT #define MQTT_KEEP_ALIVE_TIME 60 // contact the MQTT broker every 60 seconds +#if MQTT_MAX_TOPIC_LEN > 32 +#warning "MQTT topics length > 32 is not recommended for compatibility with usermods!" +#endif + static void parseMQTTBriPayload(char* payload) { if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) {bri = briLast; stateUpdated(CALL_MODE_DIRECT_CHANGE);} diff --git a/wled00/wled.h b/wled00/wled.h index 5dbc013d9..3630170f9 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -476,7 +476,7 @@ WLED_GLOBAL uint16_t pollReplyCount _INIT(0); // count numbe WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0); // used for other periodic tasks too #ifndef WLED_DISABLE_MQTT #ifndef MQTT_MAX_TOPIC_LEN - #define MQTT_MAX_TOPIC_LEN 32 // should not be less than 32. might cause trouble when increased with usermods active that do not handle this correctly. + #define MQTT_MAX_TOPIC_LEN 32 #endif #ifndef MQTT_MAX_SERVER_LEN #define MQTT_MAX_SERVER_LEN 32 diff --git a/wled00/wled_eeprom.cpp b/wled00/wled_eeprom.cpp old mode 100755 new mode 100644 index 4f2c14d47..8582b49df --- a/wled00/wled_eeprom.cpp +++ b/wled00/wled_eeprom.cpp @@ -2,6 +2,10 @@ #include #include "wled.h" +#if defined(WLED_ENABLE_MQTT) && MQTT_MAX_TOPIC_LEN < 32 +#error "MQTT topics length < 32 is not supported by the EEPROM module!" +#endif + /* * DEPRECATED, do not use for new settings * Only used to restore config from pre-0.11 installations using the deEEP() methods From 5ac8ba9bae80688ab9c9151e8775447d8e86cbf1 Mon Sep 17 00:00:00 2001 From: Wouter Gritter Date: Thu, 21 Nov 2024 12:02:55 +0100 Subject: [PATCH 144/234] Revert "Introduce printSetInputMaxlength to properly set an inputs maxlength variable" This reverts commit 49fb16e2c6528ddc98cccc352cc8f0d4a5f62a13. --- wled00/fcn_declare.h | 1 - wled00/util.cpp | 4 ---- wled00/xml.cpp | 5 ++--- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 91176160f..1855a8b63 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -380,7 +380,6 @@ size_t printSetFormValue(Print& settingsScript, const char* key, int val); size_t printSetFormValue(Print& settingsScript, const char* key, const char* val); size_t printSetFormIndex(Print& settingsScript, const char* key, int index); size_t printSetClassElementHTML(Print& settingsScript, const char* key, const int index, const char* val); -size_t printSetInputMaxLength(Print& settingsScript, const char* key, int val); void prepareHostname(char* hostname); bool isAsterisksOnly(const char* str, byte maxLen); bool requestJSONBufferLock(uint8_t module=255); diff --git a/wled00/util.cpp b/wled00/util.cpp index 1c1282eda..0b78a4646 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -109,10 +109,6 @@ size_t printSetClassElementHTML(Print& settingsScript, const char* key, const in return settingsScript.printf_P(PSTR("d.getElementsByClassName(\"%s\")[%d].innerHTML=\"%s\";"), key, index, val); } -size_t printSetInputMaxLength(Print& settingsScript, const char* key, int val) { - return settingsScript.printf_P(PSTR("d.Sf.%s.setAttribute(\"maxlength\", %d);"),key,val); -} - void prepareHostname(char* hostname) diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 6f837a9b6..dc2673271 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -465,9 +465,8 @@ void getSettingsJS(byte subPage, Print& settingsScript) printSetFormValue(settingsScript,PSTR("MG"),mqttGroupTopic); printSetFormCheckbox(settingsScript,PSTR("BM"),buttonPublishMqtt); printSetFormCheckbox(settingsScript,PSTR("RT"),retainMqttMsg); - printSetInputMaxLength(settingsScript, PSTR("MD"), MQTT_MAX_TOPIC_LEN); - printSetInputMaxLength(settingsScript, PSTR("MG"), MQTT_MAX_TOPIC_LEN); - printSetInputMaxLength(settingsScript, PSTR("MS"), MQTT_MAX_SERVER_LEN); + settingsScript.printf_P(PSTR("d.Sf.MD.maxlength=%d;d.Sf.MG.maxlength=%d;d.Sf.MS.maxlength=%d;"), + MQTT_MAX_TOPIC_LEN, MQTT_MAX_TOPIC_LEN, MQTT_MAX_SERVER_LEN); #else settingsScript.print(F("toggle('MQTT');")); // hide MQTT settings #endif From 5c8b2ebf7a015983890daecabe0db1cfcc7628d0 Mon Sep 17 00:00:00 2001 From: Wouter Gritter Date: Thu, 21 Nov 2024 12:04:01 +0100 Subject: [PATCH 145/234] maxlength -> maxLength to fix this attribute not being modified correctly --- wled00/xml.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/xml.cpp b/wled00/xml.cpp index dc2673271..0893e5d25 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -465,7 +465,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) printSetFormValue(settingsScript,PSTR("MG"),mqttGroupTopic); printSetFormCheckbox(settingsScript,PSTR("BM"),buttonPublishMqtt); printSetFormCheckbox(settingsScript,PSTR("RT"),retainMqttMsg); - settingsScript.printf_P(PSTR("d.Sf.MD.maxlength=%d;d.Sf.MG.maxlength=%d;d.Sf.MS.maxlength=%d;"), + settingsScript.printf_P(PSTR("d.Sf.MD.maxLength=%d;d.Sf.MG.maxLength=%d;d.Sf.MS.maxLength=%d;"), MQTT_MAX_TOPIC_LEN, MQTT_MAX_TOPIC_LEN, MQTT_MAX_SERVER_LEN); #else settingsScript.print(F("toggle('MQTT');")); // hide MQTT settings From 6790f8af084a4f4fe04672d82c6f55744d6d095d Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 21 Nov 2024 22:16:03 +0100 Subject: [PATCH 146/234] Same MIN_FRAME_DELAY=3 for -C3 and -S2 --- wled00/FX.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 56a0c9bd0..c15500aa3 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -48,8 +48,8 @@ #define FRAMETIME strip.getFrameTime() #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S2) #define MIN_FRAME_DELAY 2 // minimum wait between repaints, to keep other functions like WiFi alive -#elif defined(CONFIG_IDF_TARGET_ESP32S2) - #define MIN_FRAME_DELAY 4 // S2 is slower than normal esp32, and only has one core +#elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) + #define MIN_FRAME_DELAY 3 // S2/C3 are slower than normal esp32, and only have one core #else #define MIN_FRAME_DELAY 8 // 8266 legacy MIN_SHOW_DELAY #endif From 548736f432d5c1484b85045816ce1cfbafaa4e46 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 21 Nov 2024 22:50:55 +0100 Subject: [PATCH 147/234] SparkFunDMX fix for possible array bounds violation in DMX.write Align with code in espdmx.cpp --- wled00/src/dependencies/dmx/SparkFunDMX.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/src/dependencies/dmx/SparkFunDMX.cpp b/wled00/src/dependencies/dmx/SparkFunDMX.cpp index dbc9b1590..064b9ff62 100644 --- a/wled00/src/dependencies/dmx/SparkFunDMX.cpp +++ b/wled00/src/dependencies/dmx/SparkFunDMX.cpp @@ -34,8 +34,8 @@ static const int enablePin = -1; // disable the enable pin because it is not ne static const int rxPin = -1; // disable the receiving pin because it is not needed - softhack007: Pin=-1 means "use default" not "disable" static const int txPin = 2; // transmit DMX data over this pin (default is pin 2) -//DMX value array and size. Entry 0 will hold startbyte -static uint8_t dmxData[dmxMaxChannel] = { 0 }; +//DMX value array and size. Entry 0 will hold startbyte, so we need 512+1 elements +static uint8_t dmxData[dmxMaxChannel+1] = { 0 }; static int chanSize = 0; #if !defined(DMX_SEND_ONLY) static int currentChannel = 0; From 32dc54ce7239c9947260db272750fb5c5cfacb19 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Fri, 22 Nov 2024 08:43:45 +0100 Subject: [PATCH 148/234] reverted rotation scale, offset only on static rotation, inverted shift direction - inverting the shift direction in signed int is computationally safe as it is cast into an uint8_t and it matches the original FX in 1D --- wled00/FX.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 47200655d..1463121eb 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -1940,7 +1940,7 @@ uint16_t mode_palette() { using angleType = unsigned; constexpr mathType sInt16Scale = 0x7FFF; constexpr mathType maxAngle = 0x8000; - constexpr mathType staticRotationScale = 255; + constexpr mathType staticRotationScale = 256; constexpr mathType animatedRotationScale = 1; constexpr int16_t (*sinFunction)(uint16_t) = &sin16; constexpr int16_t (*cosFunction)(uint16_t) = &cos16; @@ -1949,7 +1949,7 @@ uint16_t mode_palette() { using wideMathType = float; using angleType = float; constexpr mathType sInt16Scale = 1.0f; - constexpr mathType maxAngle = M_PI / 255.0; + constexpr mathType maxAngle = M_PI / 256.0; constexpr mathType staticRotationScale = 1.0f; constexpr mathType animatedRotationScale = M_TWOPI / double(0xFFFF); constexpr float (*sinFunction)(float) = &sin_t; @@ -1961,12 +1961,12 @@ uint16_t mode_palette() { const int inputShift = SEGMENT.speed; const int inputSize = SEGMENT.intensity; - const int inputRotation = SEGMENT.custom1 + 128; + const int inputRotation = SEGMENT.custom1; const bool inputAnimateShift = SEGMENT.check1; const bool inputAnimateRotation = SEGMENT.check2; const bool inputAssumeSquare = SEGMENT.check3; - const angleType theta = (!inputAnimateRotation) ? (inputRotation * maxAngle / staticRotationScale) : (((strip.now * ((inputRotation >> 4) +1)) & 0xFFFF) * animatedRotationScale); + const angleType theta = (!inputAnimateRotation) ? ((inputRotation + 128) * maxAngle / staticRotationScale) : (((strip.now * ((inputRotation >> 4) +1)) & 0xFFFF) * animatedRotationScale); const mathType sinTheta = sinFunction(theta); const mathType cosTheta = cosFunction(theta); @@ -2017,7 +2017,7 @@ uint16_t mode_palette() { } // Finally, shift the palette a bit. const int paletteOffset = (!inputAnimateShift) ? (inputShift) : (((strip.now * ((inputShift >> 3) +1)) & 0xFFFF) >> 8); - colorIndex += paletteOffset; + colorIndex -= paletteOffset; const uint32_t color = SEGMENT.color_wheel((uint8_t)colorIndex); if (isMatrix) { SEGMENT.setPixelColorXY(x, y, color); From 6aef0e145c234cabb1129feed4068830de45a409 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sat, 23 Nov 2024 16:31:07 +0000 Subject: [PATCH 149/234] Remove TOSTRING for releaseString and add quotes to WLED_RELEASE_NAME --- platformio.ini | 42 +++++++++++++++++++++--------------------- wled00/wled.h | 2 +- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/platformio.ini b/platformio.ini index 6d4aa1dc1..fe02213ff 100644 --- a/platformio.ini +++ b/platformio.ini @@ -345,7 +345,7 @@ platform = ${common.platform_wled_default} platform_packages = ${common.platform_packages} board_build.ldscript = ${common.ldscript_4m1m} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP8266 #-DWLED_DISABLE_2D +build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP8266\" #-DWLED_DISABLE_2D lib_deps = ${esp8266.lib_deps} monitor_filters = esp8266_exception_decoder @@ -354,13 +354,13 @@ extends = env:nodemcuv2 ;; using platform version and build options from WLED 0.14.0 platform = ${esp8266.platform_compat} platform_packages = ${esp8266.platform_packages_compat} -build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=ESP8266_compat #-DWLED_DISABLE_2D +build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=\"ESP8266_compat\" #-DWLED_DISABLE_2D ;; lib_deps = ${esp8266.lib_deps_compat} ;; experimental - use older NeoPixelBus 2.7.9 [env:nodemcuv2_160] extends = env:nodemcuv2 board_build.f_cpu = 160000000L -build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP8266_160 #-DWLED_DISABLE_2D +build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP8266_160\" #-DWLED_DISABLE_2D -D USERMOD_AUDIOREACTIVE [env:esp8266_2m] @@ -369,7 +369,7 @@ platform = ${common.platform_wled_default} platform_packages = ${common.platform_packages} board_build.ldscript = ${common.ldscript_2m512k} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP02 +build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP02\" lib_deps = ${esp8266.lib_deps} [env:esp8266_2m_compat] @@ -377,12 +377,12 @@ extends = env:esp8266_2m ;; using platform version and build options from WLED 0.14.0 platform = ${esp8266.platform_compat} platform_packages = ${esp8266.platform_packages_compat} -build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=ESP02_compat #-DWLED_DISABLE_2D +build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=\"ESP02_compat\" #-DWLED_DISABLE_2D [env:esp8266_2m_160] extends = env:esp8266_2m board_build.f_cpu = 160000000L -build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP02_160 +build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP02_160\" -D USERMOD_AUDIOREACTIVE [env:esp01_1m_full] @@ -391,7 +391,7 @@ platform = ${common.platform_wled_default} platform_packages = ${common.platform_packages} board_build.ldscript = ${common.ldscript_1m128k} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP01 -D WLED_DISABLE_OTA +build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP01\" -D WLED_DISABLE_OTA ; -D WLED_USE_REAL_MATH ;; may fix wrong sunset/sunrise times, at the cost of 7064 bytes FLASH and 975 bytes RAM lib_deps = ${esp8266.lib_deps} @@ -400,12 +400,12 @@ extends = env:esp01_1m_full ;; using platform version and build options from WLED 0.14.0 platform = ${esp8266.platform_compat} platform_packages = ${esp8266.platform_packages_compat} -build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=ESP01_compat -D WLED_DISABLE_OTA #-DWLED_DISABLE_2D +build_flags = ${common.build_flags} ${esp8266.build_flags_compat} -D WLED_RELEASE_NAME=\"ESP01_compat\" -D WLED_DISABLE_OTA #-DWLED_DISABLE_2D [env:esp01_1m_full_160] extends = env:esp01_1m_full board_build.f_cpu = 160000000L -build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=ESP01_160 -D WLED_DISABLE_OTA +build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP01_160\" -D WLED_DISABLE_OTA -D USERMOD_AUDIOREACTIVE ; -D WLED_USE_REAL_MATH ;; may fix wrong sunset/sunrise times, at the cost of 7064 bytes FLASH and 975 bytes RAM @@ -414,7 +414,7 @@ board = esp32dev platform = ${esp32.platform} platform_packages = ${esp32.platform_packages} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=ESP32 #-D WLED_DISABLE_BROWNOUT_DET +build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32\" #-D WLED_DISABLE_BROWNOUT_DET ${esp32.AR_build_flags} lib_deps = ${esp32.lib_deps} ${esp32.AR_lib_deps} @@ -426,7 +426,7 @@ board = esp32dev platform = ${esp32_idf_V4.platform} platform_packages = ${esp32_idf_V4.platform_packages} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=ESP32_8M #-D WLED_DISABLE_BROWNOUT_DET +build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_8M\" #-D WLED_DISABLE_BROWNOUT_DET ${esp32.AR_build_flags} lib_deps = ${esp32_idf_V4.lib_deps} ${esp32.AR_lib_deps} @@ -442,7 +442,7 @@ board = esp32dev platform = ${esp32_idf_V4.platform} platform_packages = ${esp32_idf_V4.platform_packages} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=ESP32_16M #-D WLED_DISABLE_BROWNOUT_DET +build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_16M\" #-D WLED_DISABLE_BROWNOUT_DET ${esp32.AR_build_flags} lib_deps = ${esp32_idf_V4.lib_deps} ${esp32.AR_lib_deps} @@ -458,7 +458,7 @@ board_build.flash_mode = dio ;platform = ${esp32.platform} ;platform_packages = ${esp32.platform_packages} ;build_unflags = ${common.build_unflags} -;build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=ESP32_audioreactive #-D WLED_DISABLE_BROWNOUT_DET +;build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32_audioreactive\" #-D WLED_DISABLE_BROWNOUT_DET ; ${esp32.AR_build_flags} ;lib_deps = ${esp32.lib_deps} ; ${esp32.AR_lib_deps} @@ -473,7 +473,7 @@ platform = ${esp32.platform} platform_packages = ${esp32.platform_packages} upload_speed = 921600 build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=ESP32_Ethernet -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1 +build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32_Ethernet\" -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1 ; -D WLED_DISABLE_ESPNOW ;; ESP-NOW requires wifi, may crash with ethernet only ${esp32.AR_build_flags} lib_deps = ${esp32.lib_deps} @@ -489,7 +489,7 @@ board_build.f_flash = 80000000L board_build.flash_mode = qio board_build.partitions = ${esp32.extended_partitions} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=ESP32_WROVER +build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_WROVER\" -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue ;; Older ESP32 (rev.<3) need a PSRAM fix (increases static RAM used) https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/external-ram.html -D DATA_PINS=25 ${esp32.AR_build_flags} @@ -503,7 +503,7 @@ platform_packages = ${esp32c3.platform_packages} framework = arduino board = esp32-c3-devkitm-1 board_build.partitions = ${esp32.default_partitions} -build_flags = ${common.build_flags} ${esp32c3.build_flags} -D WLED_RELEASE_NAME=ESP32-C3 +build_flags = ${common.build_flags} ${esp32c3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-C3\" -D WLED_WATCHDOG_TIMEOUT=0 -DLOLIN_WIFI_FIX ; seems to work much better with this -DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB @@ -520,7 +520,7 @@ platform = ${esp32s3.platform} platform_packages = ${esp32s3.platform_packages} upload_speed = 921600 build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=ESP32-S3_16MB_opi +build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_16MB_opi\" -D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0 ;-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip -D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB") @@ -543,7 +543,7 @@ platform = ${esp32s3.platform} platform_packages = ${esp32s3.platform_packages} upload_speed = 921600 build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=ESP32-S3_8MB_opi +build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_8MB_opi\" -D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0 ;-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip -D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB") @@ -565,7 +565,7 @@ board = esp32s3camlcd ;; this is the only standard board with "opi_opi" board_build.arduino.memory_type = opi_opi upload_speed = 921600 build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=ESP32-S3_WROOM-2 +build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_WROOM-2\" -D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0 -D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip ;; -D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB") @@ -590,7 +590,7 @@ platform = ${esp32s3.platform} platform_packages = ${esp32s3.platform_packages} upload_speed = 921600 build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=ESP32-S3_4M_qspi +build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_4M_qspi\" -DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB") -DBOARD_HAS_PSRAM -DLOLIN_WIFI_FIX ; seems to work much better with this @@ -611,7 +611,7 @@ board_build.partitions = ${esp32.default_partitions} board_build.flash_mode = qio board_build.f_flash = 80000000L build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=ESP32-S2 +build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S2\" -DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 diff --git a/wled00/wled.h b/wled00/wled.h index 2b3a77d24..163ce6b04 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -269,7 +269,7 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument; // Global Variable definitions WLED_GLOBAL char versionString[] _INIT(TOSTRING(WLED_VERSION)); -WLED_GLOBAL char releaseString[] _INIT(TOSTRING(WLED_RELEASE_NAME)); // somehow this will not work if using "const char releaseString[] +WLED_GLOBAL char releaseString[] _INIT(WLED_RELEASE_NAME); // somehow this will not work if using "const char releaseString[] #define WLED_CODENAME "Kōsen" // AP and OTA default passwords (for maximum security change them!) From 0be1df7ee89d01a53b0043dd4c4b66c0e741ccd4 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sat, 23 Nov 2024 16:46:41 +0000 Subject: [PATCH 150/234] Stip \" from WLED_RELEASE_NAME --- pio-scripts/output_bins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pio-scripts/output_bins.py b/pio-scripts/output_bins.py index 633654008..bdd6fc941 100644 --- a/pio-scripts/output_bins.py +++ b/pio-scripts/output_bins.py @@ -19,7 +19,7 @@ def _create_dirs(dirs=["map", "release", "firmware"]): os.makedirs(os.path.join(OUTPUT_DIR, d), exist_ok=True) def create_release(source): - release_name = _get_cpp_define_value(env, "WLED_RELEASE_NAME") + release_name = _get_cpp_define_value(env, "WLED_RELEASE_NAME").replace("\\\"", "") if release_name: version = _get_cpp_define_value(env, "WLED_VERSION") release_file = os.path.join(OUTPUT_DIR, "release", f"WLED_{version}_{release_name}.bin") From d53d7aa2e2d22085979e0134fb7ce1c5dd6684df Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sat, 23 Nov 2024 12:29:46 -0500 Subject: [PATCH 151/234] Defer calling begin() on digital buses NeoPixelBus requires that all parallel I2S bus members be constructed before any of them call Begin(). Implement this by deferring the call to the end of bus construction. Fixes #4301. --- wled00/FX_fcn.cpp | 11 +++-------- wled00/bus_manager.cpp | 4 ++-- wled00/bus_manager.h | 3 ++- wled00/bus_wrapper.h | 2 +- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index e706f2b43..7177ca89e 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1286,14 +1286,9 @@ void WS2812FX::finalizeInit() { _isOffRefreshRequired |= bus->isOffRefreshRequired() && !bus->isPWM(); // use refresh bit for phase shift with analog unsigned busEnd = bus->getStart() + bus->getLength(); if (busEnd > _length) _length = busEnd; - #ifdef ESP8266 - // why do we need to reinitialise GPIO3??? - //if (!bus->isDigital() || bus->is2Pin()) continue; - //uint8_t pins[5]; - //if (!bus->getPins(pins)) continue; - //BusDigital* bd = static_cast(bus); - //if (pins[0] == 3) bd->reinit(); - #endif + + // This must be done after all buses have been created, as some kinds (parallel I2S) interact + bus->begin(); } Segment::maxWidth = _length; diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 5b948b9c4..8281211c1 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -410,7 +410,7 @@ std::vector BusDigital::getLEDTypes() { }; } -void BusDigital::reinit() { +void BusDigital::begin() { if (!_valid) return; PolyBus::begin(_busPtr, _iType, _pins); } @@ -910,7 +910,7 @@ void BusManager::on() { if (busses[i]->isDigital() && busses[i]->getPins(pins)) { if (pins[0] == LED_BUILTIN || pins[1] == LED_BUILTIN) { BusDigital *bus = static_cast(busses[i]); - bus->reinit(); + bus->begin(); break; } } diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index e96b9de71..ecebc120e 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -79,6 +79,7 @@ class Bus { virtual ~Bus() {} //throw the bus under the bus + virtual void begin() {}; virtual void show() = 0; virtual bool canShow() const { return true; } virtual void setStatusPixel(uint32_t c) {} @@ -213,7 +214,7 @@ class BusDigital : public Bus { uint16_t getLEDCurrent() const override { return _milliAmpsPerLed; } uint16_t getUsedCurrent() const override { return _milliAmpsTotal; } uint16_t getMaxCurrent() const override { return _milliAmpsMax; } - void reinit(); + void begin() override; void cleanup(); static std::vector getLEDTypes(); diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index 84c32f46b..7e6e74d85 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -597,7 +597,7 @@ class PolyBus { case I_HS_P98_3: busPtr = new B_HS_P98_3(len, pins[1], pins[0]); break; case I_SS_P98_3: busPtr = new B_SS_P98_3(len, pins[1], pins[0]); break; } - begin(busPtr, busType, pins, clock_kHz); + return busPtr; } From 0c77dbb7ea63c0b228d5d0f576d6eb0dcb7daeb1 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sun, 24 Nov 2024 13:55:23 +0000 Subject: [PATCH 152/234] cleanup WLED_RELEASE_NAME only if present --- pio-scripts/output_bins.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pio-scripts/output_bins.py b/pio-scripts/output_bins.py index bdd6fc941..4d1594d84 100644 --- a/pio-scripts/output_bins.py +++ b/pio-scripts/output_bins.py @@ -19,8 +19,9 @@ def _create_dirs(dirs=["map", "release", "firmware"]): os.makedirs(os.path.join(OUTPUT_DIR, d), exist_ok=True) def create_release(source): - release_name = _get_cpp_define_value(env, "WLED_RELEASE_NAME").replace("\\\"", "") - if release_name: + release_name_def = _get_cpp_define_value(env, "WLED_RELEASE_NAME") + if release_name_def: + release_name = release_name_def.replace("\\\"", "") version = _get_cpp_define_value(env, "WLED_VERSION") release_file = os.path.join(OUTPUT_DIR, "release", f"WLED_{version}_{release_name}.bin") release_gz_file = release_file + ".gz" From 20f8d3c8a9cc0812261089714baaf08538aabb19 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sun, 24 Nov 2024 15:26:30 +0000 Subject: [PATCH 153/234] Builds without WLED_RELEASE_NAME should be called Custom --- wled00/wled.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/wled.h b/wled00/wled.h index 163ce6b04..bb647340b 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -264,7 +264,7 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument; #define WLED_VERSION dev #endif #ifndef WLED_RELEASE_NAME - #define WLED_RELEASE_NAME dev_release + #define WLED_RELEASE_NAME "Custom" #endif // Global Variable definitions From 5b989adebc666f5d6314e0ece81c1141a0ae454f Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 25 Nov 2024 15:27:53 +0100 Subject: [PATCH 154/234] Allow TV Simulator on single LED segments I've checked the code - nothing preventing the effect to run with SEGLEN=1 --- wled00/FX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 947788fee..80be13c62 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -4631,7 +4631,7 @@ uint16_t mode_tv_simulator(void) { return FRAMETIME; } -static const char _data_FX_MODE_TV_SIMULATOR[] PROGMEM = "TV Simulator@!,!;;"; +static const char _data_FX_MODE_TV_SIMULATOR[] PROGMEM = "TV Simulator@!,!;;!;01"; /* From dd533a9ab4f37c8bc271f4a7cdbd7c0fe51456a3 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Mon, 25 Nov 2024 23:00:31 +0000 Subject: [PATCH 155/234] Update sample WLED_RELEASE_NAME --- platformio_override.sample.ini | 2 +- wled00/wled.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio_override.sample.ini b/platformio_override.sample.ini index 8e5fdf003..a4dea6677 100644 --- a/platformio_override.sample.ini +++ b/platformio_override.sample.ini @@ -37,7 +37,7 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} ; *** To use the below defines/overrides, copy and paste each onto it's own line just below build_flags in the section above. ; ; Set a release name that may be used to distinguish required binary for flashing -; -D WLED_RELEASE_NAME=ESP32_MULTI_USREMODS +; -D WLED_RELEASE_NAME=\"ESP32_MULTI_USREMODS\" ; ; disable specific features ; -D WLED_DISABLE_OTA diff --git a/wled00/wled.h b/wled00/wled.h index bb647340b..fcbc11978 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -269,7 +269,7 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument; // Global Variable definitions WLED_GLOBAL char versionString[] _INIT(TOSTRING(WLED_VERSION)); -WLED_GLOBAL char releaseString[] _INIT(WLED_RELEASE_NAME); // somehow this will not work if using "const char releaseString[] +WLED_GLOBAL char releaseString[] _INIT(WLED_RELEASE_NAME); // must include the quotes when defining, e.g -D WLED_RELEASE_NAME=\"ESP32_MULTI_USREMODS\" #define WLED_CODENAME "Kōsen" // AP and OTA default passwords (for maximum security change them!) From d87c5035dd0ac1c908c6a4680640999ab52bbddd Mon Sep 17 00:00:00 2001 From: AlDIY <87589371+dosipod@users.noreply.github.com> Date: Tue, 26 Nov 2024 19:33:22 +0300 Subject: [PATCH 156/234] Update settings_sec.htm --- wled00/data/settings_sec.htm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wled00/data/settings_sec.htm b/wled00/data/settings_sec.htm index fa75882c0..7fe0fe62e 100644 --- a/wled00/data/settings_sec.htm +++ b/wled00/data/settings_sec.htm @@ -60,8 +60,8 @@

Backup & Restore

⚠ Restoring presets/configuration will OVERWRITE your current presets/configuration.
- Incorrect upload or configuration may require a factory reset or re-flashing of your ESP.
- For security reasons, passwords are not backed up. + Incorrect upload or configuration may require a factory reset or re-flashing of your ESP.
+ For security reasons, passwords are not backed up. Backup presets
Restore presets


Backup configuration
@@ -78,4 +78,4 @@ - \ No newline at end of file + From cd1c13b4b1e242e736cad086abcb7a9dcc727b2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Tue, 26 Nov 2024 19:35:15 +0100 Subject: [PATCH 157/234] Fix for #4300 --- wled00/set.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/wled00/set.cpp b/wled00/set.cpp index 712e5f254..2a6fdd3fb 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -215,6 +215,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) //doInitBusses = busesChanged; // we will do that below to ensure all input data is processed // we will not bother with pre-allocating ColorOrderMappings vector + BusManager::getColorOrderMap().reset(); for (int s = 0; s < WLED_MAX_COLOR_ORDER_MAPPINGS; s++) { int offset = s < 10 ? 48 : 55; char xs[4] = "XS"; xs[2] = offset+s; xs[3] = 0; //start LED From 1a8aaa3b26feba106259b6842ad9f8998fb3233d Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Tue, 26 Nov 2024 20:32:39 +0100 Subject: [PATCH 158/234] Speed improvements, commented legacy _t trig functions - speed improvement: by default M_TWOPI is treated as a double float - directly calling sin16_t in cos_approx() saves a lot of overhead --- wled00/wled_math.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/wled00/wled_math.cpp b/wled00/wled_math.cpp index a191968e1..583381d66 100644 --- a/wled00/wled_math.cpp +++ b/wled00/wled_math.cpp @@ -10,14 +10,17 @@ //#define WLED_DEBUG_MATH -#define modd(x, y) ((x) - (int)((x) / (y)) * (y)) - -// Note: cos_t, sin_t and tan_t are very accurate but may be slow +// Note: cos_t, sin_t and tan_t are very accurate but slow // the math.h functions use several kB of flash and are to be avoided if possible // sin16_t / cos16_t are faster and much more accurate than the fastled variants // sin_approx and cos_approx are float wrappers for sin16_t/cos16_t and have an accuracy better than +/-0.0015 compared to sinf() // sin8_t / cos8_t are fastled replacements and use sin16_t / cos16_t. Slightly slower than fastled version but very accurate + +// Taylor series approximations, replaced with Bhaskara I's approximation +/* +#define modd(x, y) ((x) - (int)((x) / (y)) * (y)) + float cos_t(float phi) { float x = modd(phi, M_TWOPI); @@ -54,6 +57,7 @@ float tan_t(float x) { #endif return res; } +*/ // 16-bit, integer based Bhaskara I's sine approximation: 16*x*(pi - x) / (5*pi^2 - 4*x*(pi - x)) // input is 16bit unsigned (0-65535), output is 16bit signed (-32767 to +32767) @@ -85,17 +89,18 @@ uint8_t cos8_t(uint8_t theta) { return sin8_t(theta + 64); //cos(x) = sin(x+pi/2) } -float sin_approx(float theta) -{ - uint16_t scaled_theta = (int)(theta * (0xFFFF / M_TWOPI)); // note: do not cast negative float to uint! cast to int first (undefined on C3) +float sin_approx(float theta) { + uint16_t scaled_theta = (int)(theta * (float)(0xFFFF / M_TWOPI)); // note: do not cast negative float to uint! cast to int first (undefined on C3) int32_t result = sin16_t(scaled_theta); float sin = float(result) / 0x7FFF; return sin; } -float cos_approx(float theta) -{ - return sin_approx(theta + M_PI_2); +float cos_approx(float theta) { + uint16_t scaled_theta = (int)(theta * (float)(0xFFFF / M_TWOPI)); // note: do not cast negative float to uint! cast to int first (undefined on C3) + int32_t result = sin16_t(scaled_theta + 16384); + float cos = float(result) / 0x7FFF; + return cos; } float tan_approx(float x) { From 0a05611e1d5a8dcccf515ba616042692197258f6 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Tue, 26 Nov 2024 20:59:36 +0100 Subject: [PATCH 159/234] more improvements to setPixelColor - code is a bit cleaner and faster as well - chaning array access to pointer access in bus_manager makes it a few instructions faster - changed getNumberOfPins and getNumberOfChannels to return 32bit values, saving the unnecessary 8bit conversion --- wled00/FX_2Dfcn.cpp | 41 +++++++++++++++++++++-------------------- wled00/bus_manager.cpp | 26 ++++++++++++++++---------- wled00/bus_manager.h | 6 +++--- 3 files changed, 40 insertions(+), 33 deletions(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index adb9f8bca..ba0c69322 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -156,21 +156,26 @@ uint16_t IRAM_ATTR_YN Segment::XY(int x, int y) // raw setColor function without checks (checks are done in setPixelColorXY()) void IRAM_ATTR_YN Segment::_setPixelColorXY_raw(int& x, int& y, uint32_t& col) { + const int baseX = start + x; + const int baseY = startY + y; #ifndef WLED_DISABLE_MODE_BLEND // if blending modes, blend with underlying pixel - if (_modeBlend) col = color_blend(strip.getPixelColorXY(start + x, startY + y), col, 0xFFFFU - progress(), true); + if (_modeBlend) col = color_blend(strip.getPixelColorXY(baseX, baseY), col, 0xFFFFU - progress(), true); #endif - strip.setPixelColorXY(start + x, startY + y, col); - if (mirror) { //set the corresponding horizontally mirrored pixel - if (transpose) strip.setPixelColorXY(start + x, startY + height() - y - 1, col); - else strip.setPixelColorXY(start + width() - x - 1, startY + y, col); - } - if (mirror_y) { //set the corresponding vertically mirrored pixel - if (transpose) strip.setPixelColorXY(start + width() - x - 1, startY + y, col); - else strip.setPixelColorXY(start + x, startY + height() - y - 1, col); - } - if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel - strip.setPixelColorXY(start + width() - x - 1, startY + height() - y - 1, col); + strip.setPixelColorXY(baseX, baseY, col); + + // Apply mirroring + if (mirror || mirror_y) { + auto setMirroredPixel = [&](int mx, int my) { + strip.setPixelColorXY(mx, my, col); + }; + + const int mirrorX = start + width() - x - 1; + const int mirrorY = startY + height() - y - 1; + + if (mirror) setMirroredPixel(transpose ? baseX : mirrorX, transpose ? mirrorY : baseY); + if (mirror_y) setMirroredPixel(transpose ? mirrorX : baseX, transpose ? baseY : mirrorY); + if (mirror && mirror_y) setMirroredPixel(mirrorX, mirrorY); } } @@ -196,16 +201,12 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) int H = height(); x *= groupLen; // expand to physical pixels y *= groupLen; // expand to physical pixels - int yY = y; - for (int j = 0; j < grouping; j++) { // groupping vertically - if (yY >= H) break; - int xX = x; - for (int g = 0; g < grouping; g++) { // groupping horizontally - if (xX >= W) break; // we have reached X dimension's end + const int maxY = std::min(y + grouping, H); + const int maxX = std::min(x + grouping, W); + for (int yY = y; yY < maxY; yY++) { + for (int xX = x; xX < maxX; xX++) { _setPixelColorXY_raw(xX, yY, col); - xX++; } - yY++; } } else { _setPixelColorXY_raw(x, y, col); diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 404c33449..941135497 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -308,20 +308,20 @@ void BusDigital::setStatusPixel(uint32_t c) { void IRAM_ATTR BusDigital::setPixelColor(unsigned pix, uint32_t c) { if (!_valid) return; - uint8_t cctWW = 0, cctCW = 0; if (hasWhite()) c = autoWhiteCalc(c); if (Bus::_cct >= 1900) c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT if (_data) { size_t offset = pix * getNumberOfChannels(); + uint8_t* dataptr = _data + offset; if (hasRGB()) { - _data[offset++] = R(c); - _data[offset++] = G(c); - _data[offset++] = B(c); + *dataptr++ = R(c); + *dataptr++ = G(c); + *dataptr++ = B(c); } - if (hasWhite()) _data[offset++] = W(c); + if (hasWhite()) *dataptr++ = W(c); // unfortunately as a segment may span multiple buses or a bus may contain multiple segments and each segment may have different CCT // we need to store CCT value for each pixel (if there is a color correction in play, convert K in CCT ratio) - if (hasCCT()) _data[offset] = Bus::_cct >= 1900 ? (Bus::_cct - 1900) >> 5 : (Bus::_cct < 0 ? 127 : Bus::_cct); // TODO: if _cct == -1 we simply ignore it + if (hasCCT()) *dataptr = Bus::_cct >= 1900 ? (Bus::_cct - 1900) >> 5 : (Bus::_cct < 0 ? 127 : Bus::_cct); // TODO: if _cct == -1 we simply ignore it } else { if (_reversed) pix = _len - pix -1; pix += _skip; @@ -336,8 +336,14 @@ void IRAM_ATTR BusDigital::setPixelColor(unsigned pix, uint32_t c) { case 2: c = RGBW32(R(cOld), G(cOld), W(c) , 0); break; } } - if (hasCCT()) Bus::calculateCCT(c, cctWW, cctCW); - PolyBus::setPixelColor(_busPtr, _iType, pix, c, co, (cctCW<<8) | cctWW); + uint16_t wwcw = 0; + if (hasCCT()) { + uint8_t cctWW = 0, cctCW = 0; + Bus::calculateCCT(c, cctWW, cctCW); + wwcw = (cctCW<<8) | cctWW; + } + + PolyBus::setPixelColor(_busPtr, _iType, pix, c, co, wwcw); } } @@ -345,7 +351,7 @@ void IRAM_ATTR BusDigital::setPixelColor(unsigned pix, uint32_t c) { uint32_t IRAM_ATTR BusDigital::getPixelColor(unsigned pix) const { if (!_valid) return 0; if (_data) { - size_t offset = pix * getNumberOfChannels(); + const size_t offset = pix * getNumberOfChannels(); uint32_t c; if (!hasRGB()) { c = RGBW32(_data[offset], _data[offset], _data[offset], _data[offset]); @@ -356,7 +362,7 @@ uint32_t IRAM_ATTR BusDigital::getPixelColor(unsigned pix) const { } else { if (_reversed) pix = _len - pix -1; pix += _skip; - unsigned co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder); + const unsigned co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder); uint32_t c = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, (_type==TYPE_WS2812_1CH_X3) ? IC_INDEX_WS2812_1CH_3X(pix) : pix, co),_bri); if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs unsigned r = R(c); diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index e25a06849..49077f27c 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -110,7 +110,7 @@ class Bus { inline void setStart(uint16_t start) { _start = start; } inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; } inline uint8_t getAutoWhiteMode() const { return _autoWhiteMode; } - inline uint8_t getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); } + inline uint32_t getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); } inline uint16_t getStart() const { return _start; } inline uint8_t getType() const { return _type; } inline bool isOk() const { return _valid; } @@ -119,8 +119,8 @@ class Bus { inline bool containsPixel(uint16_t pix) const { return pix >= _start && pix < _start + _len; } static inline std::vector getLEDTypes() { return {{TYPE_NONE, "", PSTR("None")}}; } // not used. just for reference for derived classes - static constexpr uint8_t getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK - static constexpr uint8_t getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); } + static constexpr uint32_t getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK + static constexpr uint32_t getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); } static constexpr bool hasRGB(uint8_t type) { return !((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_ANALOG_1CH || type == TYPE_ANALOG_2CH || type == TYPE_ONOFF); } From ca176c7549f92ae6ba611b9b6f9e9edbf13bad15 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 27 Nov 2024 10:31:41 +0000 Subject: [PATCH 160/234] rename workflow ready for workflow refactor --- .github/workflows/{wled-ci.yml => build.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{wled-ci.yml => build.yml} (100%) diff --git a/.github/workflows/wled-ci.yml b/.github/workflows/build.yml similarity index 100% rename from .github/workflows/wled-ci.yml rename to .github/workflows/build.yml From feab27295db32f9ad367ec3a68d3d7ad9b3779eb Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 27 Nov 2024 10:33:44 +0000 Subject: [PATCH 161/234] workflow refactor to used shared build file --- .github/workflows/build.yml | 8 +++++--- .github/workflows/wled-ci.yml | 11 +++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/wled-ci.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1dcab26ab..80fce38c3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,7 +1,9 @@ -name: WLED CI - -on: [push, pull_request] +name: WLED Build +# Only included into other workflows +on: + workflow_call: + jobs: get_default_envs: diff --git a/.github/workflows/wled-ci.yml b/.github/workflows/wled-ci.yml new file mode 100644 index 000000000..3c862c185 --- /dev/null +++ b/.github/workflows/wled-ci.yml @@ -0,0 +1,11 @@ +name: WLED CI + +on: + push: + branches: + - '*' + pull_request: + +jobs: + wled_build: + uses: ./.github/workflows/build.yml From 95718ab6ecb830b57f74d7cbed0b142d70b33c63 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 27 Nov 2024 10:35:04 +0000 Subject: [PATCH 162/234] Dedicated release workflow --- .github/workflows/build.yml | 16 ---------------- .github/workflows/release.yml | 28 ++++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 80fce38c3..e5fdfc5a3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -64,22 +64,6 @@ jobs: path: | build_output/release/*.bin build_output/release/*_ESP02*.bin.gz - release: - name: Create Release - runs-on: ubuntu-latest - needs: build - if: startsWith(github.ref, 'refs/tags/') - steps: - - uses: actions/download-artifact@v4 - with: - merge-multiple: true - - name: Create draft release - uses: softprops/action-gh-release@v1 - with: - draft: True - files: | - *.bin - *.bin.gz testCdata: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..27beec99c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,28 @@ +name: WLED Release CI + +on: + push: + tags: + - '*' + +jobs: + + wled_build: + uses: ./.github/workflows/build.yml + + release: + name: Create Release + runs-on: ubuntu-latest + needs: wled_build + steps: + - uses: actions/download-artifact@v4 + with: + merge-multiple: true + - name: Create draft release + uses: softprops/action-gh-release@v1 + with: + draft: True + files: | + *.bin + *.bin.gz + From cc55f6015dfff436cb4ff3f595ae53695393f8b3 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 27 Nov 2024 10:56:53 +0000 Subject: [PATCH 163/234] Cache always misses for tags, so save space and do not save back --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e5fdfc5a3..ac1db6445 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -42,6 +42,7 @@ jobs: - run: npm ci - name: Cache PlatformIO uses: actions/cache@v4 + if: !startsWith(github.ref, 'refs/tags/') with: path: | ~/.platformio/.cache From 6cbdd825eb6cea9c2cc5c6219f4fd7db567cd8ff Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 27 Nov 2024 10:59:23 +0000 Subject: [PATCH 164/234] Revert "Cache always misses for tags, so save space and do not save back" This reverts commit cc55f6015dfff436cb4ff3f595ae53695393f8b3. --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ac1db6445..e5fdfc5a3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -42,7 +42,6 @@ jobs: - run: npm ci - name: Cache PlatformIO uses: actions/cache@v4 - if: !startsWith(github.ref, 'refs/tags/') with: path: | ~/.platformio/.cache From acc8b9cdbc22086762d5c05e6d2ff419c96fc074 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Wed, 27 Nov 2024 09:00:25 -0500 Subject: [PATCH 165/234] BusDigital::begin: Pass clock rate argument Fixes bug introduced by #4312. --- wled00/bus_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 8281211c1..715470800 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -412,7 +412,7 @@ std::vector BusDigital::getLEDTypes() { void BusDigital::begin() { if (!_valid) return; - PolyBus::begin(_busPtr, _iType, _pins); + PolyBus::begin(_busPtr, _iType, _pins, _frequencykHz); } void BusDigital::cleanup() { From dcba1aad109c29b9594973d99270f62006dd0289 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Wed, 27 Nov 2024 09:05:10 -0500 Subject: [PATCH 166/234] PolyBus: Clarify use of clock_kHz While not used by most bus types, it's not an optional parameter. --- wled00/bus_manager.cpp | 2 +- wled00/bus_wrapper.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 715470800..5b031bebb 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -150,7 +150,7 @@ BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) //_buffering = bc.doubleBuffer; uint16_t lenToCreate = bc.count; if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(bc.count); // only needs a third of "RGB" LEDs for NeoPixelBus - _busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr, _frequencykHz); + _busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr); _valid = (_busPtr != nullptr); DEBUG_PRINTF_P(PSTR("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u). mA=%d/%d\n"), _valid?"S":"Uns", nr, bc.count, bc.type, _pins[0], is2Pin(bc.type)?_pins[1]:255, _iType, _milliAmpsPerLed, _milliAmpsMax); } diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index 7e6e74d85..d2a18c9d8 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -336,7 +336,7 @@ class PolyBus { // initialize SPI bus speed for DotStar methods template - static void beginDotStar(void* busPtr, int8_t sck, int8_t miso, int8_t mosi, int8_t ss, uint16_t clock_kHz = 0U) { + static void beginDotStar(void* busPtr, int8_t sck, int8_t miso, int8_t mosi, int8_t ss, uint16_t clock_kHz /* 0 == use default */) { T dotStar_strip = static_cast(busPtr); #ifdef ESP8266 dotStar_strip->Begin(); @@ -363,7 +363,7 @@ class PolyBus { tm1914_strip->SetPixelSettings(NeoTm1914Settings()); //NeoTm1914_Mode_DinFdinAutoSwitch, NeoTm1914_Mode_DinOnly, NeoTm1914_Mode_FdinOnly } - static void begin(void* busPtr, uint8_t busType, uint8_t* pins, uint16_t clock_kHz = 0U) { + static void begin(void* busPtr, uint8_t busType, uint8_t* pins, uint16_t clock_kHz /* only used by DotStar */) { switch (busType) { case I_NONE: break; #ifdef ESP8266 @@ -480,7 +480,7 @@ class PolyBus { } } - static void* create(uint8_t busType, uint8_t* pins, uint16_t len, uint8_t channel, uint16_t clock_kHz = 0U) { + static void* create(uint8_t busType, uint8_t* pins, uint16_t len, uint8_t channel) { #if defined(ARDUINO_ARCH_ESP32) && !(defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3)) // NOTE: "channel" is only used on ESP32 (and its variants) for RMT channel allocation // since 0.15.0-b3 I2S1 is favoured for classic ESP32 and moved to position 0 (channel 0) so we need to subtract 1 for correct RMT allocation From b1dd27b516fa93919edd967c85bd8b287b9b914d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Wed, 27 Nov 2024 16:08:10 +0100 Subject: [PATCH 167/234] Fix for #4321 --- wled00/data/settings_leds.htm | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 6be5becd1..baf80a5d7 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -42,15 +42,14 @@ if (loc) d.Sf.action = getURL('/settings/leds'); } function bLimits(b,v,p,m,l,o=5,d=2,a=6) { - // maxB - max buses (can be changed if using ESP32 parallel I2S) - // maxD - max digital channels (can be changed if using ESP32 parallel I2S) - // maxA - max analog channels - // maxV - min virtual buses - // maxPB - max LEDs per bus - // maxM - max LED memory - // maxL - max LEDs (will serve to determine ESP >1664 == ESP32) - // maxCO - max Color Order mappings - oMaxB = maxB = b; maxD = d, maxA = a, maxV = v; maxM = m; maxPB = p; maxL = l; maxCO = o; + oMaxB = maxB = b; // maxB - max buses (can be changed if using ESP32 parallel I2S) + maxD = d; // maxD - max digital channels (can be changed if using ESP32 parallel I2S) + maxA = a; // maxA - max analog channels + maxV = v; // maxV - min virtual buses + maxPB = p; // maxPB - max LEDs per bus + maxM = m; // maxM - max LED memory + maxL = l; // maxL - max LEDs (will serve to determine ESP >1664 == ESP32) + maxCO = o; // maxCO - max Color Order mappings } function pinsOK() { var ok = true; From 4cd0563a9398812f65f8dbbe22d0ab48799f4de8 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Wed, 27 Nov 2024 21:53:32 +0100 Subject: [PATCH 168/234] =?UTF-8?q?changed=2090=C2=B0=20offset=20to=20hex,?= =?UTF-8?q?=20fixed=20potential=20bug=20in=20FX=20using=20sin/cos=20with?= =?UTF-8?q?=20incrementing=20number?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - sin/cos calls with incrementing numbers can lead to bad outcomes, the functions (_approx or original sinf/cosf) return bad values for very large float inputs --- wled00/FX.cpp | 5 +++-- wled00/wled_math.cpp | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 5b4513dc7..da2967a3c 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -5314,8 +5314,8 @@ uint16_t mode_2DJulia(void) { // An animated Julia set reAl = -0.94299f; // PixelBlaze example imAg = 0.3162f; - reAl += sin_t((float)strip.now/305.f)/20.f; - imAg += sin_t((float)strip.now/405.f)/20.f; + reAl += (float)sin16_t(strip.now * 34) / 655340.f; + imAg += (float)sin16_t(strip.now * 26) / 655340.f; dx = (xmax - xmin) / (cols); // Scale the delta x and y values to our matrix size. dy = (ymax - ymin) / (rows); @@ -6279,6 +6279,7 @@ uint16_t mode_2Dplasmarotozoom() { } } *a -= 0.03f + float(SEGENV.speed-128)*0.0002f; // rotation speed + if(*a < -6283.18530718f) *a += 6283.18530718f; // 1000*2*PI, protect sin/cos from very large input float values (will give wrong results) return FRAMETIME; } diff --git a/wled00/wled_math.cpp b/wled00/wled_math.cpp index 583381d66..a8ec55400 100644 --- a/wled00/wled_math.cpp +++ b/wled00/wled_math.cpp @@ -76,7 +76,7 @@ int16_t sin16_t(uint16_t theta) { } int16_t cos16_t(uint16_t theta) { - return sin16_t(theta + 16384); //cos(x) = sin(x+pi/2) + return sin16_t(theta + 0x4000); //cos(x) = sin(x+pi/2) } uint8_t sin8_t(uint8_t theta) { @@ -98,7 +98,7 @@ float sin_approx(float theta) { float cos_approx(float theta) { uint16_t scaled_theta = (int)(theta * (float)(0xFFFF / M_TWOPI)); // note: do not cast negative float to uint! cast to int first (undefined on C3) - int32_t result = sin16_t(scaled_theta + 16384); + int32_t result = sin16_t(scaled_theta + 0x4000); float cos = float(result) / 0x7FFF; return cos; } From fa4c23b76ec7843aff6a8f3e5b9bc7a46a41858e Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Wed, 27 Nov 2024 22:23:48 +0100 Subject: [PATCH 169/234] minor improvement --- wled00/FX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index a2ceb591a..a0d080818 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7737,9 +7737,9 @@ uint16_t mode_2Doctopus() { const int C_Y = (rows / 2) + ((SEGMENT.custom2 - 128)*rows)/255; for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) { - rMap[XY(x, y)].angle = int(40.7436f * atan2_t((y - C_Y), (x - C_X))); // avoid 128*atan2()/PI int dx = (x - C_X); int dy = (y - C_Y); + rMap[XY(x, y)].angle = int(40.7436f * atan2_t(dy, dx)); // avoid 128*atan2()/PI rMap[XY(x, y)].radius = sqrtf(dx * dx + dy * dy) * mapp; //thanks Sutaburosu } } From 8b1d712e1e04a696086b7e5b9df06a4dff97b289 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 1 Dec 2024 13:00:37 -0500 Subject: [PATCH 170/234] settings_leds: Initialize current limiter field When adding a new bus, the numeric current limit field was not being initialized; this was causing it to save 0 when saved instead of the default 55mA value. --- wled00/data/settings_leds.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index baf80a5d7..ff5087aed 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -422,7 +422,7 @@ mA/LED:
- +
PSU: mA
Color Order: From ae8c3b02d04064cb809af2f3f10413563fae2dd7 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 2 Dec 2024 21:35:48 +0100 Subject: [PATCH 171/234] blends FX - hotfix for black pixels fixing an off-by-one error to solve #4335 --- wled00/FX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index a0d080818..61d7a66a8 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -4497,7 +4497,7 @@ uint16_t mode_blends(void) { unsigned offset = 0; for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, pixels[offset++]); - if (offset > pixelLen) offset = 0; + if (offset >= pixelLen) offset = 0; } return FRAMETIME; From 8db8ecfef3cbbf8cd70862d856742874e2a9306f Mon Sep 17 00:00:00 2001 From: Will Miles Date: Mon, 2 Dec 2024 21:50:29 +0000 Subject: [PATCH 172/234] settings_leds: Fix quotes on LA value --- wled00/data/settings_leds.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index ff5087aed..ce9c8ceed 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -422,7 +422,7 @@ mA/LED:
- +
PSU: mA
Color Order: From d620930f10f06bce563d95c94e6513739959a012 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Mon, 2 Dec 2024 21:52:41 +0000 Subject: [PATCH 173/234] settings_leds: Remove unused variables Remove a couple of leftover variables from previous revisions. --- wled00/data/settings_leds.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index ce9c8ceed..71fec2798 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -6,7 +6,7 @@ LED Settings