From 1d27aa2f18fb11c1eb811b703a920408524d8248 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 14 Jul 2024 11:38:29 -0400 Subject: [PATCH 01/16] Move .ino to .cpp This fixes platformio continually recompiling this file. --- wled00/{wled00.ino => wled00.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename wled00/{wled00.ino => wled00.cpp} (100%) diff --git a/wled00/wled00.ino b/wled00/wled00.cpp similarity index 100% rename from wled00/wled00.ino rename to wled00/wled00.cpp From d234b4b0f1b96a093e2592cbad131c5923db63dd Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Mon, 5 Aug 2024 20:56:12 +0200 Subject: [PATCH 02/16] SM16825 support - add WW & CW swapping --- wled00/bus_manager.h | 5 +- wled00/bus_wrapper.h | 93 ++++++++++++++++++++++++++++++++--- wled00/const.h | 1 + wled00/data/settings_leds.htm | 12 +++-- 4 files changed, 97 insertions(+), 14 deletions(-) diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index e1bacd555..5e516d2e1 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -157,7 +157,7 @@ class Bus { static bool hasWhite(uint8_t type) { if ((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_SK6812_RGBW || type == TYPE_TM1814 || type == TYPE_UCS8904 || - type == TYPE_FW1906 || type == TYPE_WS2805) return true; // digital types with white channel + type == TYPE_FW1906 || type == TYPE_WS2805 || type == TYPE_SM16825) return true; // digital types with white channel if (type > TYPE_ONOFF && type <= TYPE_ANALOG_5CH && type != TYPE_ANALOG_3CH) return true; // analog types with white channel if (type == TYPE_NET_DDP_RGBW || type == TYPE_NET_ARTNET_RGBW) return true; // network types with white channel return false; @@ -166,7 +166,8 @@ class Bus { static bool hasCCT(uint8_t type) { if (type == TYPE_WS2812_2CH_X3 || type == TYPE_WS2812_WWA || type == TYPE_ANALOG_2CH || type == TYPE_ANALOG_5CH || - type == TYPE_FW1906 || type == TYPE_WS2805 ) return true; + type == TYPE_FW1906 || type == TYPE_WS2805 || + type == TYPE_SM16825) return true; return false; } static inline int16_t getCCT() { return _cct; } diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index d619e85af..d1d4f8941 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -84,6 +84,11 @@ #define I_8266_U1_TM1914_3 100 #define I_8266_DM_TM1914_3 101 #define I_8266_BB_TM1914_3 102 +//SM16825 (RGBCW) +#define I_8266_U0_SM16825_5 103 +#define I_8266_U1_SM16825_5 104 +#define I_8266_DM_SM16825_5 105 +#define I_8266_BB_SM16825_5 106 /*** ESP32 Neopixel methods ***/ //RGB @@ -130,7 +135,10 @@ #define I_32_RN_TM1914_3 96 #define I_32_I0_TM1914_3 97 #define I_32_I1_TM1914_3 98 - +//SM16825 (RGBCW) +#define I_32_RN_SM16825_5 107 +#define I_32_I0_SM16825_5 108 +#define I_32_I1_SM16825_5 109 //APA102 #define I_HS_DOT_3 39 //hardware SPI @@ -213,6 +221,11 @@ #define B_8266_U1_TM1914_3 NeoPixelBusLg #define B_8266_DM_TM1914_3 NeoPixelBusLg #define B_8266_BB_TM1914_3 NeoPixelBusLg +//Sm16825 (RGBWC) +#define B_8266_U0_SM16825_5 NeoPixelBusLg +#define B_8266_U1_SM16825_5 NeoPixelBusLg +#define B_8266_DM_SM16825_5 NeoPixelBusLg +#define B_8266_BB_SM16825_5 NeoPixelBusLg #endif /*** ESP32 Neopixel methods ***/ @@ -272,6 +285,11 @@ #define B_32_I0_TM1914_3 NeoPixelBusLg #define B_32_I1_TM1914_3 NeoPixelBusLg #define B_32_I1_TM1914_3P NeoPixelBusLg // parallel I2S +//Sm16825 (RGBWC) +#define B_32_RN_SM16825_5 NeoPixelBusLg +#define B_32_I0_SM16825_5 NeoPixelBusLg +#define B_32_I1_SM16825_5 NeoPixelBusLg +#define B_32_I1_SM16825_5P NeoPixelBusLg // parallel I2S #endif //APA102 @@ -398,6 +416,10 @@ class PolyBus { case I_8266_U1_TM1914_3: beginTM1914(busPtr); break; case I_8266_DM_TM1914_3: beginTM1914(busPtr); break; case I_8266_BB_TM1914_3: beginTM1914(busPtr); break; + case I_8266_U0_SM16825_5: (static_cast(busPtr))->Begin(); break; + case I_8266_U1_SM16825_5: (static_cast(busPtr))->Begin(); break; + case I_8266_DM_SM16825_5: (static_cast(busPtr))->Begin(); break; + case I_8266_BB_SM16825_5: (static_cast(busPtr))->Begin(); break; #endif #ifdef ARDUINO_ARCH_ESP32 // RMT buses @@ -412,6 +434,7 @@ class PolyBus { case I_32_RN_APA106_3: (static_cast(busPtr))->Begin(); break; case I_32_RN_2805_5: (static_cast(busPtr))->Begin(); break; case I_32_RN_TM1914_3: beginTM1914(busPtr); break; + case I_32_RN_SM16825_5: (static_cast(busPtr))->Begin(); break; // I2S1 bus or parellel buses #ifndef WLED_NO_I2S1_PIXELBUS case I_32_I1_NEO_3: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; @@ -425,6 +448,7 @@ class PolyBus { case I_32_I1_APA106_3: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; case I_32_I1_2805_5: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; case I_32_I1_TM1914_3: if (useParallelI2S) beginTM1914(busPtr); else beginTM1914(busPtr); break; + case I_32_I1_SM16825_5: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; #endif // I2S0 bus #ifndef WLED_NO_I2S0_PIXELBUS @@ -439,6 +463,7 @@ class PolyBus { case I_32_I0_APA106_3: (static_cast(busPtr))->Begin(); break; case I_32_I0_2805_5: (static_cast(busPtr))->Begin(); break; case I_32_I0_TM1914_3: beginTM1914(busPtr); break; + case I_32_I0_SM16825_5: (static_cast(busPtr))->Begin(); break; #endif // ESP32 can (and should, to avoid inadvertantly driving the chip select signal) specify the pins used for SPI, but only in begin() case I_HS_DOT_3: beginDotStar(busPtr, pins[1], -1, pins[0], -1, clock_kHz); break; @@ -510,6 +535,10 @@ class PolyBus { case I_8266_U1_TM1914_3: busPtr = new B_8266_U1_TM1914_3(len, pins[0]); break; case I_8266_DM_TM1914_3: busPtr = new B_8266_DM_TM1914_3(len, pins[0]); break; case I_8266_BB_TM1914_3: busPtr = new B_8266_BB_TM1914_3(len, pins[0]); break; + case I_8266_U0_SM16825_5: busPtr = new B_8266_U0_SM16825_5(len, pins[0]); break; + case I_8266_U1_SM16825_5: busPtr = new B_8266_U1_SM16825_5(len, pins[0]); break; + case I_8266_DM_SM16825_5: busPtr = new B_8266_DM_SM16825_5(len, pins[0]); break; + case I_8266_BB_SM16825_5: busPtr = new B_8266_BB_SM16825_5(len, pins[0]); break; #endif #ifdef ARDUINO_ARCH_ESP32 // RMT buses @@ -524,6 +553,7 @@ class PolyBus { case I_32_RN_FW6_5: busPtr = new B_32_RN_FW6_5(len, pins[0], (NeoBusChannel)channel); break; case I_32_RN_2805_5: busPtr = new B_32_RN_2805_5(len, pins[0], (NeoBusChannel)channel); break; case I_32_RN_TM1914_3: busPtr = new B_32_RN_TM1914_3(len, pins[0], (NeoBusChannel)channel); break; + case I_32_RN_SM16825_5: busPtr = new B_32_RN_SM16825_5(len, pins[0], (NeoBusChannel)channel); break; // I2S1 bus or paralell buses #ifndef WLED_NO_I2S1_PIXELBUS case I_32_I1_NEO_3: if (useParallelI2S) busPtr = new B_32_I1_NEO_3P(len, pins[0]); else busPtr = new B_32_I1_NEO_3(len, pins[0]); break; @@ -537,6 +567,7 @@ class PolyBus { case I_32_I1_FW6_5: if (useParallelI2S) busPtr = new B_32_I1_FW6_5P(len, pins[0]); else busPtr = new B_32_I1_FW6_5(len, pins[0]); break; case I_32_I1_2805_5: if (useParallelI2S) busPtr = new B_32_I1_2805_5P(len, pins[0]); else busPtr = new B_32_I1_2805_5(len, pins[0]); break; case I_32_I1_TM1914_3: if (useParallelI2S) busPtr = new B_32_I1_TM1914_3P(len, pins[0]); else busPtr = new B_32_I1_TM1914_3(len, pins[0]); break; + case I_32_I1_SM16825_5: if (useParallelI2S) busPtr = new B_32_I1_SM16825_5P(len, pins[0]); else busPtr = new B_32_I1_SM16825_5(len, pins[0]); break; #endif // I2S0 bus #ifndef WLED_NO_I2S0_PIXELBUS @@ -551,6 +582,7 @@ class PolyBus { case I_32_I0_FW6_5: busPtr = new B_32_I0_FW6_5(len, pins[0]); break; case I_32_I0_2805_5: busPtr = new B_32_I0_2805_5(len, pins[0]); break; case I_32_I0_TM1914_3: busPtr = new B_32_I0_TM1914_3(len, pins[0]); break; + case I_32_I0_SM16825_5: busPtr = new B_32_I0_SM16825_5(len, pins[0]); break; #endif #endif // for 2-wire: pins[1] is clk, pins[0] is dat. begin expects (len, clk, dat) @@ -617,6 +649,10 @@ class PolyBus { case I_8266_U1_TM1914_3: (static_cast(busPtr))->Show(consistent); break; case I_8266_DM_TM1914_3: (static_cast(busPtr))->Show(consistent); break; case I_8266_BB_TM1914_3: (static_cast(busPtr))->Show(consistent); break; + case I_8266_U0_SM16825_5: (static_cast(busPtr))->Show(consistent); break; + case I_8266_U1_SM16825_5: (static_cast(busPtr))->Show(consistent); break; + case I_8266_DM_SM16825_5: (static_cast(busPtr))->Show(consistent); break; + case I_8266_BB_SM16825_5: (static_cast(busPtr))->Show(consistent); break; #endif #ifdef ARDUINO_ARCH_ESP32 // RMT buses @@ -631,6 +667,7 @@ class PolyBus { case I_32_RN_FW6_5: (static_cast(busPtr))->Show(consistent); break; case I_32_RN_2805_5: (static_cast(busPtr))->Show(consistent); break; case I_32_RN_TM1914_3: (static_cast(busPtr))->Show(consistent); break; + case I_32_RN_SM16825_5: (static_cast(busPtr))->Show(consistent); break; // I2S1 bus or paralell buses #ifndef WLED_NO_I2S1_PIXELBUS case I_32_I1_NEO_3: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; @@ -644,6 +681,7 @@ class PolyBus { case I_32_I1_FW6_5: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; case I_32_I1_2805_5: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; case I_32_I1_TM1914_3: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I1_SM16825_5: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; #endif // I2S0 bus #ifndef WLED_NO_I2S0_PIXELBUS @@ -658,6 +696,7 @@ class PolyBus { case I_32_I0_FW6_5: (static_cast(busPtr))->Show(consistent); break; case I_32_I0_2805_5: (static_cast(busPtr))->Show(consistent); break; case I_32_I0_TM1914_3: (static_cast(busPtr))->Show(consistent); break; + case I_32_I0_SM16825_5: (static_cast(busPtr))->Show(consistent); break; #endif #endif case I_HS_DOT_3: (static_cast(busPtr))->Show(consistent); break; @@ -720,6 +759,10 @@ class PolyBus { case I_8266_U1_TM1914_3: return (static_cast(busPtr))->CanShow(); break; case I_8266_DM_TM1914_3: return (static_cast(busPtr))->CanShow(); break; case I_8266_BB_TM1914_3: return (static_cast(busPtr))->CanShow(); break; + case I_8266_U0_SM16825_5: return (static_cast(busPtr))->CanShow(); break; + case I_8266_U1_SM16825_5: return (static_cast(busPtr))->CanShow(); break; + case I_8266_DM_SM16825_5: return (static_cast(busPtr))->CanShow(); break; + case I_8266_BB_SM16825_5: return (static_cast(busPtr))->CanShow(); break; #endif #ifdef ARDUINO_ARCH_ESP32 // RMT buses @@ -734,6 +777,7 @@ class PolyBus { 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; // 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; @@ -747,6 +791,7 @@ class PolyBus { 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; #endif // I2S0 bus #ifndef WLED_NO_I2S0_PIXELBUS @@ -761,6 +806,7 @@ class PolyBus { 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; #endif #endif case I_HS_DOT_3: return (static_cast(busPtr))->CanShow(); break; @@ -800,6 +846,7 @@ class PolyBus { case 1: col.W = col.B; col.B = w; break; // swap W & B case 2: col.W = col.G; col.G = w; break; // swap W & G case 3: col.W = col.R; col.R = w; break; // swap W & R + case 4: std::swap(cctWW, cctCW); break; // swap WW & CW } switch (busType) { @@ -849,6 +896,10 @@ class PolyBus { case I_8266_U1_TM1914_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; case I_8266_DM_TM1914_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; case I_8266_BB_TM1914_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_8266_U0_SM16825_5: (static_cast(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); break; + case I_8266_U1_SM16825_5: (static_cast(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); break; + case I_8266_DM_SM16825_5: (static_cast(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); break; + case I_8266_BB_SM16825_5: (static_cast(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); break; #endif #ifdef ARDUINO_ARCH_ESP32 // RMT buses @@ -863,6 +914,7 @@ class PolyBus { case I_32_RN_FW6_5: (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; case I_32_RN_2805_5: (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; case I_32_RN_TM1914_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_32_RN_SM16825_5: (static_cast(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); break; // I2S1 bus or paralell buses #ifndef WLED_NO_I2S1_PIXELBUS case I_32_I1_NEO_3: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; @@ -873,9 +925,10 @@ class PolyBus { case I_32_I1_UCS_3: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, Rgb48Color(RgbColor(col))); break; case I_32_I1_UCS_4: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break; case I_32_I1_APA106_3: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - case I_32_I1_FW6_5: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; - case I_32_I1_2805_5: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; + case I_32_I1_FW6_5: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); else (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; + case I_32_I1_2805_5: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); else (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; case I_32_I1_TM1914_3: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_32_I1_SM16825_5: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); else (static_cast(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); break; #endif // I2S0 bus #ifndef WLED_NO_I2S0_PIXELBUS @@ -890,6 +943,7 @@ class PolyBus { case I_32_I0_FW6_5: (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; case I_32_I0_2805_5: (static_cast(busPtr))->SetPixelColor(pix, RgbwwColor(col.R, col.G, col.B, cctWW, cctCW)); break; case I_32_I0_TM1914_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_32_I0_SM16825_5: (static_cast(busPtr))->SetPixelColor(pix, Rgbww80Color(col.R*257, col.G*257, col.B*257, cctWW*257, cctCW*257)); break; #endif #endif case I_HS_DOT_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; @@ -953,6 +1007,10 @@ class PolyBus { case I_8266_U1_TM1914_3: (static_cast(busPtr))->SetLuminance(b); break; case I_8266_DM_TM1914_3: (static_cast(busPtr))->SetLuminance(b); break; case I_8266_BB_TM1914_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_U0_SM16825_5: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_U1_SM16825_5: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_DM_SM16825_5: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_BB_SM16825_5: (static_cast(busPtr))->SetLuminance(b); break; #endif #ifdef ARDUINO_ARCH_ESP32 // RMT buses @@ -967,6 +1025,7 @@ class PolyBus { case I_32_RN_FW6_5: (static_cast(busPtr))->SetLuminance(b); break; case I_32_RN_2805_5: (static_cast(busPtr))->SetLuminance(b); break; case I_32_RN_TM1914_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_32_RN_SM16825_5: (static_cast(busPtr))->SetLuminance(b); break; // I2S1 bus or paralell buses #ifndef WLED_NO_I2S1_PIXELBUS case I_32_I1_NEO_3: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; @@ -980,6 +1039,7 @@ class PolyBus { case I_32_I1_FW6_5: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; case I_32_I1_2805_5: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; case I_32_I1_TM1914_3: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I1_SM16825_5: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; #endif // I2S0 bus #ifndef WLED_NO_I2S0_PIXELBUS @@ -994,6 +1054,7 @@ class PolyBus { case I_32_I0_FW6_5: (static_cast(busPtr))->SetLuminance(b); break; case I_32_I0_2805_5: (static_cast(busPtr))->SetLuminance(b); break; case I_32_I0_TM1914_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I0_SM16825_5: (static_cast(busPtr))->SetLuminance(b); break; #endif #endif case I_HS_DOT_3: (static_cast(busPtr))->SetLuminance(b); break; @@ -1058,6 +1119,10 @@ class PolyBus { case I_8266_U1_TM1914_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; case I_8266_DM_TM1914_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; case I_8266_BB_TM1914_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_8266_U0_SM16825_5: { Rgbww80Color c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W + case I_8266_U1_SM16825_5: { Rgbww80Color c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W + case I_8266_DM_SM16825_5: { Rgbww80Color c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W + case I_8266_BB_SM16825_5: { Rgbww80Color c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W #endif #ifdef ARDUINO_ARCH_ESP32 // RMT buses @@ -1072,6 +1137,7 @@ class PolyBus { case I_32_RN_FW6_5: { RgbwwColor c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W case I_32_RN_2805_5: { RgbwwColor c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W case I_32_RN_TM1914_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_RN_SM16825_5: { Rgbww80Color c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,max(c.WW,c.CW)/257); } break; // will not return original W // I2S1 bus or paralell buses #ifndef WLED_NO_I2S1_PIXELBUS case I_32_I1_NEO_3: col = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; @@ -1079,12 +1145,13 @@ class PolyBus { case I_32_I1_400_3: col = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; case I_32_I1_TM1_4: col = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; case I_32_I1_TM2_3: col = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; - case I_32_I1_UCS_3: { Rgb48Color c = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R>>8,c.G>>8,c.B>>8,0); } break; - case I_32_I1_UCS_4: { Rgbw64Color c = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R>>8,c.G>>8,c.B>>8,c.W>>8); } break; + case I_32_I1_UCS_3: { Rgb48Color c = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,0); } break; + case I_32_I1_UCS_4: { Rgbw64Color c = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,c.W/257); } break; case I_32_I1_APA106_3: col = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; case I_32_I1_FW6_5: { RgbwwColor c = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W case I_32_I1_2805_5: { RgbwwColor c = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W case I_32_I1_TM1914_3: col = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I1_SM16825_5: { Rgbww80Color c = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,max(c.WW,c.CW)/257); } break; // will not return original W #endif // I2S0 bus #ifndef WLED_NO_I2S0_PIXELBUS @@ -1093,12 +1160,13 @@ class PolyBus { case I_32_I0_400_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; case I_32_I0_TM1_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; case I_32_I0_TM2_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; - case I_32_I0_UCS_3: { Rgb48Color c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R>>8,c.G>>8,c.B>>8,0); } break; - case I_32_I0_UCS_4: { Rgbw64Color c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R>>8,c.G>>8,c.B>>8,c.W>>8); } break; + case I_32_I0_UCS_3: { Rgb48Color c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,0); } break; + case I_32_I0_UCS_4: { Rgbw64Color c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,c.W/257); } break; case I_32_I0_APA106_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; case I_32_I0_FW6_5: { RgbwwColor c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W case I_32_I0_2805_5: { RgbwwColor c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R,c.G,c.B,max(c.WW,c.CW)); } break; // will not return original W case I_32_I0_TM1914_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I0_SM16825_5: { Rgbww80Color c = (static_cast(busPtr))->GetPixelColor(pix); col = RGBW32(c.R/257,c.G/257,c.B/257,max(c.WW,c.CW)/257); } break; // will not return original W #endif #endif case I_HS_DOT_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; @@ -1181,6 +1249,10 @@ class PolyBus { case I_8266_U1_TM1914_3: delete (static_cast(busPtr)); break; case I_8266_DM_TM1914_3: delete (static_cast(busPtr)); break; case I_8266_BB_TM1914_3: delete (static_cast(busPtr)); break; + case I_8266_U0_SM16825_5: delete (static_cast(busPtr)); break; + case I_8266_U1_SM16825_5: delete (static_cast(busPtr)); break; + case I_8266_DM_SM16825_5: delete (static_cast(busPtr)); break; + case I_8266_BB_SM16825_5: delete (static_cast(busPtr)); break; #endif #ifdef ARDUINO_ARCH_ESP32 // RMT buses @@ -1195,6 +1267,7 @@ class PolyBus { case I_32_RN_FW6_5: delete (static_cast(busPtr)); break; case I_32_RN_2805_5: delete (static_cast(busPtr)); break; case I_32_RN_TM1914_3: delete (static_cast(busPtr)); break; + case I_32_RN_SM16825_5: delete (static_cast(busPtr)); break; // I2S1 bus or paralell buses #ifndef WLED_NO_I2S1_PIXELBUS case I_32_I1_NEO_3: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; @@ -1208,6 +1281,7 @@ class PolyBus { case I_32_I1_FW6_5: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; case I_32_I1_2805_5: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; case I_32_I1_TM1914_3: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I1_SM16825_5: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; #endif // I2S0 bus #ifndef WLED_NO_I2S0_PIXELBUS @@ -1222,6 +1296,7 @@ class PolyBus { case I_32_I0_FW6_5: delete (static_cast(busPtr)); break; case I_32_I0_2805_5: delete (static_cast(busPtr)); break; case I_32_I0_TM1914_3: delete (static_cast(busPtr)); break; + case I_32_I0_SM16825_5: delete (static_cast(busPtr)); break; #endif #endif case I_HS_DOT_3: delete (static_cast(busPtr)); break; @@ -1290,6 +1365,8 @@ class PolyBus { return I_8266_U0_2805_5 + offset; case TYPE_TM1914: return I_8266_U0_TM1914_3 + offset; + case TYPE_SM16825: + return I_8266_U0_SM16825_5 + offset; } #else //ESP32 uint8_t offset = 0; // 0 = RMT (num 1-8), 1 = I2S0 (used by Audioreactive), 2 = I2S1 @@ -1343,6 +1420,8 @@ class PolyBus { return I_32_RN_2805_5 + offset; case TYPE_TM1914: return I_32_RN_TM1914_3 + offset; + case TYPE_SM16825: + return I_32_RN_SM16825_5 + offset; } #endif } diff --git a/wled00/const.h b/wled00/const.h index 0ff70e47d..8a5983213 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -295,6 +295,7 @@ #define TYPE_TM1814 31 #define TYPE_WS2805 32 //RGB + WW + CW #define TYPE_TM1914 33 //RGB +#define TYPE_SM16825 34 //RGB + WW + CW //"Analog" types (40-47) #define TYPE_ONOFF 40 //binary output (relays etc.; NOT PWM) #define TYPE_ANALOG_1CH 41 //single channel PWM. Uses value of brightest RGBW channel diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 1712b360e..b7d2d18a7 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -22,10 +22,10 @@ function isAna(t) { return t == 40 || isPWM(t); } // is analog type function isDig(t) { return (t > 15 && t < 40) || isD2P(t); } // is digital type function isD2P(t) { return t > 47 && t < 64; } // is digital 2 pin type - function is16b(t) { return t == 26 || t == 29 } // is digital 16 bit type + function is16b(t) { return t == 26 || t == 29 || t == 34; } // is digital 16 bit type function isVir(t) { return t >= 80 && t < 96; } // is virtual type - function hasW(t) { return (t >= 18 && t <= 21) || (t >= 28 && t <= 32) || (t >= 44 && t <= 45) || (t >= 88 && t <= 89); } - function hasCCT(t) { return t == 20 || t == 21 || t == 42 || t == 45 || t == 28 || t == 32; } + function hasW(t) { return (t >= 18 && t <= 21) || (t >= 28 && t <= 32) || t == 34 || (t >= 44 && t <= 45) || (t >= 88 && t <= 89); } + function hasCCT(t) { return t == 20 || t == 21 || t == 42 || t == 45 || t == 28 || t == 32 || t == 34; } // https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript function loadJS(FILE_URL, async = true) { let scE = d.createElement("script"); @@ -264,7 +264,8 @@ gId("rf"+n).onclick = (t == 31) ? (()=>{return false}) : (()=>{}); // prevent change for TM1814 gRGBW |= hasW(t); // RGBW checkbox, TYPE_xxxx values from const.h gId("co"+n).style.display = (isVir(t) || isAna(t)) ? "none":"inline"; // hide color order for PWM - gId("dig"+n+"w").style.display = (isDig(t) && hasW(t)) ? "inline":"none"; // show swap channels dropdown + gId("dig"+n+"w").style.display = (isDig(t) && hasW(t)) ? "inline":"none"; // show swap channels dropdown + gId("dig"+n+"w").querySelector("[data-opt=CCT]").disabled = !hasCCT(t); // disable WW/CW swapping if (!(isDig(t) && hasW(t))) d.Sf["WO"+n].value = 0; // reset swapping gId("dig"+n+"c").style.display = (isAna(t)) ? "none":"inline"; // hide count for analog gId("dig"+n+"r").style.display = (isVir(t)) ? "none":"inline"; // hide reversed for virtual @@ -419,6 +420,7 @@ ${i+1}: \ \ \ +\ \ \ \ @@ -459,7 +461,7 @@ mA/LED: - +
Start:   From ea80c1ed830251ae2154e69495dc6fb5d2cda3d1 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Wed, 7 Aug 2024 22:39:31 +0200 Subject: [PATCH 03/16] Swap WW & CW --- wled00/bus_wrapper.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index d1d4f8941..ae39adc14 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -286,10 +286,10 @@ #define B_32_I1_TM1914_3 NeoPixelBusLg #define B_32_I1_TM1914_3P NeoPixelBusLg // parallel I2S //Sm16825 (RGBWC) -#define B_32_RN_SM16825_5 NeoPixelBusLg -#define B_32_I0_SM16825_5 NeoPixelBusLg -#define B_32_I1_SM16825_5 NeoPixelBusLg -#define B_32_I1_SM16825_5P NeoPixelBusLg // parallel I2S +#define B_32_RN_SM16825_5 NeoPixelBusLg +#define B_32_I0_SM16825_5 NeoPixelBusLg +#define B_32_I1_SM16825_5 NeoPixelBusLg +#define B_32_I1_SM16825_5P NeoPixelBusLg // parallel I2S #endif //APA102 From db5e66a9b092954c457900b4a39247875a3e7383 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Fri, 9 Aug 2024 12:53:41 +0200 Subject: [PATCH 04/16] playing with Fire2012 * speedup: add functions to only blur rows or columns (50% faster) * fire2012: tinkering with bur options. Vertical blur only when slider < 64 (faster); extra blur for slider values >192 (bush burn) --- wled00/FX.cpp | 6 ++++-- wled00/FX.h | 10 ++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index bded21060..b0fac6f81 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2098,7 +2098,7 @@ uint16_t mode_fire_2012() { // Step 4. Map from heat cells to LED colors for (int j = 0; j < SEGLEN; j++) { - SEGMENT.setPixelColor(indexToVStrip(j, stripNr), ColorFromPalette(SEGPALETTE, MIN(heat[j],240), 255, NOBLEND)); + SEGMENT.setPixelColor(indexToVStrip(j, stripNr), ColorFromPalette(SEGPALETTE, min(heat[j], byte(240)), 255, NOBLEND)); } } }; @@ -2108,7 +2108,9 @@ uint16_t mode_fire_2012() { if (SEGMENT.is2D()) { uint8_t blurAmount = SEGMENT.custom2 >> 2; - SEGMENT.blur(blurAmount); + if (blurAmount > 48) blurAmount += blurAmount-48; // extra blur when slider > 192 (bush burn) + if (blurAmount < 16) SEGMENT.blurCols(SEGMENT.custom2 >> 1); // no side-burn when slider < 64 (faster) + else SEGMENT.blur(blurAmount); } if (it != SEGENV.step) diff --git a/wled00/FX.h b/wled00/FX.h index 57de5df44..98fdbf1fc 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -602,6 +602,16 @@ typedef struct Segment { uint32_t color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255) const; uint32_t color_wheel(uint8_t pos) const; + // 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); + } + 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); + } + // 2D matrix uint16_t virtualWidth(void) const; // segment width in virtual pixels (accounts for groupping and spacing) uint16_t virtualHeight(void) const; // segment height in virtual pixels (accounts for groupping and spacing) From ed5eb2822827399d9dfeb55db9a5068bb2bec8f9 Mon Sep 17 00:00:00 2001 From: Arthur Suzuki Date: Wed, 22 Nov 2023 02:36:06 +0100 Subject: [PATCH 05/16] Added POV image effect Setup is really easy, after first boot and WiFi/LEDs setup: go to wled.local/edit and upload a couple image to WLed's filesystem. Only PNG is supported right now, further support for GIF is planned. The image should be as wide as the 1D segment you want to apply to. When done, go to the Effect page on the UI, select "POV Image" effect. You could also update the image with a post to the JSON-API like this: curl -X POST http://[wled]/json/state -d '{"seg":{"id":0,"fx":114,"f":"/axel.png"}}' The segment should move at around 120RPM (that's 2revolutions per seconds) for an image to showup. More informations and pictures here : https://lumina.toys --- platformio_override.sample.ini | 4 + usermods/pov_display/usermod_pov_display.h | 85 ++++++++++++++++++++++ wled00/const.h | 1 + wled00/usermods_list.cpp | 8 ++ 4 files changed, 98 insertions(+) create mode 100644 usermods/pov_display/usermod_pov_display.h diff --git a/platformio_override.sample.ini b/platformio_override.sample.ini index be959e46a..7f6524922 100644 --- a/platformio_override.sample.ini +++ b/platformio_override.sample.ini @@ -29,6 +29,8 @@ lib_deps = ${esp8266.lib_deps} ; ;gmag11/QuickESPNow @ ~0.7.0 # will also load QuickDebug ; https://github.com/blazoncek/QuickESPNow.git#optional-debug ;; exludes debug library ; ${esp32.AR_lib_deps} ;; used for USERMOD_AUDIOREACTIVE +; bitbank2/PNGdec@^1.0.1 ;; used for POV display uncomment following + build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp8266.build_flags} ; @@ -152,6 +154,8 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} ; -D TACHO_PIN=33 ; -D PWM_PIN=32 ; +; Use POV Display usermod +; -D USERMOD_POV_DISPLAY ; Use built-in or custom LED as a status indicator (assumes LED is connected to GPIO16) ; -D STATUSLED=16 ; diff --git a/usermods/pov_display/usermod_pov_display.h b/usermods/pov_display/usermod_pov_display.h new file mode 100644 index 000000000..b1fc0dba6 --- /dev/null +++ b/usermods/pov_display/usermod_pov_display.h @@ -0,0 +1,85 @@ +#pragma once +#include "wled.h" +#include + +void * openFile(const char *filename, int32_t *size) { + f = WLED_FS.open(filename); + *size = f.size(); + return &f; +} + +void closeFile(void *handle) { + if (f) f.close(); +} + +int32_t readFile(PNGFILE *pFile, uint8_t *pBuf, int32_t iLen) +{ + int32_t iBytesRead; + iBytesRead = iLen; + File *f = static_cast(pFile->fHandle); + // Note: If you read a file all the way to the last byte, seek() stops working + if ((pFile->iSize - pFile->iPos) < iLen) + iBytesRead = pFile->iSize - pFile->iPos - 1; // <-- ugly work-around + if (iBytesRead <= 0) + return 0; + iBytesRead = (int32_t)f->read(pBuf, iBytesRead); + pFile->iPos = f->position(); + return iBytesRead; +} + +int32_t seekFile(PNGFILE *pFile, int32_t iPosition) +{ + int i = micros(); + File *f = static_cast(pFile->fHandle); + f->seek(iPosition); + pFile->iPos = (int32_t)f->position(); + i = micros() - i; + return pFile->iPos; +} + +void draw(PNGDRAW *pDraw) { + uint16_t usPixels[SEGLEN]; + png.getLineAsRGB565(pDraw, usPixels, PNG_RGB565_LITTLE_ENDIAN, 0xffffffff); + for(int x=0; x < SEGLEN; x++) { + uint16_t color = usPixels[x]; + byte r = ((color >> 11) & 0x1F); + byte g = ((color >> 5) & 0x3F); + byte b = (color & 0x1F); + SEGMENT.setPixelColor(x, RGBW32(r,g,b,0)); + } + strip.show(); +} + +uint16_t mode_pov_image(void) { + const char * filepath = SEGMENT.name; + int rc = png.open(filepath, openFile, closeFile, readFile, seekFile, draw); + if (rc == PNG_SUCCESS) { + rc = png.decode(NULL, 0); + png.close(); + return FRAMETIME; + } + return FRAMETIME; +} + +class PovDisplayUsermod : public Usermod +{ + public: + static const char _data_FX_MODE_POV_IMAGE[] PROGMEM = "POV Image@!;;;1"; + + PNG png; + File f; + + void setup() { + strip.addEffect(255, &mode_pov_image, _data_FX_MODE_POV_IMAGE); + } + + void loop() { + } + + uint16_t getId() + { + return USERMOD_ID_POV_DISPLAY; + } + + void connected() {} +}; diff --git a/wled00/const.h b/wled00/const.h index 0ff70e47d..72e1a3bae 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -200,6 +200,7 @@ #define USERMOD_ID_INA226 50 //Usermod "usermod_ina226.h" #define USERMOD_ID_AHT10 51 //Usermod "usermod_aht10.h" #define USERMOD_ID_LD2410 52 //Usermod "usermod_ld2410.h" +#define USERMOD_ID_POV_DISPLAY 53 //Usermod "usermod_pov_display.h" //Access point behavior #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp index a39aa5f41..be2239d65 100644 --- a/wled00/usermods_list.cpp +++ b/wled00/usermods_list.cpp @@ -210,6 +210,10 @@ #include "../usermods/LDR_Dusk_Dawn_v2/usermod_LDR_Dusk_Dawn_v2.h" #endif +#ifdef USERMOD_POV_DISPLAY + #include "../usermods/pov_display/usermod_pov_display.h" +#endif + #ifdef USERMOD_STAIRCASE_WIPE #include "../usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h" #endif @@ -454,4 +458,8 @@ void registerUsermods() #ifdef USERMOD_LD2410 usermods.add(new LD2410Usermod()); #endif + + #ifdef USERMOD_POV_DISPLAY + usermods.add(new PovDisplayUsermod()); + #endif } From bcf862044a22113207fc72a3dfe82eecf4e46dac Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 13 Aug 2024 22:21:21 +0200 Subject: [PATCH 06/16] Update wled00.cpp * added #include - this is basically what the preprocessing tool (wled.ino -> wled00.ino.cpp) does * added a comment that Arduino IDE is not supported, use platformIO. --- wled00/wled00.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/wled00/wled00.cpp b/wled00/wled00.cpp index 866543ab9..f3f090715 100644 --- a/wled00/wled00.cpp +++ b/wled00/wled00.cpp @@ -1,9 +1,12 @@ +#include /* * WLED Arduino IDE compatibility file. + * (this is the former wled00.ino) * * Where has everything gone? * - * In April 2020, the project's structure underwent a major change. + * In April 2020, the project's structure underwent a major change. + * We now use the platformIO build system, and building WLED in Arduino IDE is not supported any more. * Global variables are now found in file "wled.h" * Global function declarations are found in "fcn_declare.h" * From 2443e2ec7c6800d2053fb05e6820be4a4440741c Mon Sep 17 00:00:00 2001 From: Frank Date: Wed, 14 Aug 2024 11:16:46 +0200 Subject: [PATCH 07/16] wled00 -> wled_main --- wled00/{wled00.cpp => wled_main.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename wled00/{wled00.cpp => wled_main.cpp} (100%) diff --git a/wled00/wled00.cpp b/wled00/wled_main.cpp similarity index 100% rename from wled00/wled00.cpp rename to wled00/wled_main.cpp From cec67d8eff1844fe9917685dd0aa39321a5e07db Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Wed, 14 Aug 2024 22:15:48 +0200 Subject: [PATCH 08/16] Const and 2D box blur - added 2D blur --- wled00/FX.cpp | 37 ++++++----- wled00/FX.h | 75 ++++++++++----------- wled00/FX_2Dfcn.cpp | 156 ++++++++++++++++++++++++++++++++++---------- wled00/FX_fcn.cpp | 50 +++++++------- 4 files changed, 204 insertions(+), 114 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index b0fac6f81..944afe641 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -1226,15 +1226,18 @@ uint16_t mode_fireworks() { } SEGMENT.fade_out(128); - bool valid1 = (SEGENV.aux0 < width*height); - bool valid2 = (SEGENV.aux1 < width*height); uint8_t x = SEGENV.aux0%width, y = SEGENV.aux0/width; // 2D coordinates stored in upper and lower byte - uint32_t sv1 = 0, sv2 = 0; - if (valid1) sv1 = SEGMENT.is2D() ? SEGMENT.getPixelColorXY(x, y) : SEGMENT.getPixelColor(SEGENV.aux0); // get spark color - if (valid2) sv2 = SEGMENT.is2D() ? SEGMENT.getPixelColorXY(x, y) : SEGMENT.getPixelColor(SEGENV.aux1); - if (!SEGENV.step) SEGMENT.blur(16); - if (valid1) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, sv1); else SEGMENT.setPixelColor(SEGENV.aux0, sv1); } // restore spark color after blur - if (valid2) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, sv2); else SEGMENT.setPixelColor(SEGENV.aux1, sv2); } // restore old spark color after blur + if (!SEGENV.step) { + // fireworks mode (blur flares) + bool valid1 = (SEGENV.aux0 < width*height); + bool valid2 = (SEGENV.aux1 < width*height); + uint32_t sv1 = 0, sv2 = 0; + if (valid1) sv1 = SEGMENT.is2D() ? SEGMENT.getPixelColorXY(x, y) : SEGMENT.getPixelColor(SEGENV.aux0); // get spark color + if (valid2) sv2 = SEGMENT.is2D() ? SEGMENT.getPixelColorXY(x, y) : SEGMENT.getPixelColor(SEGENV.aux1); + SEGMENT.blur(16); // used in mode_rain() + if (valid1) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, sv1); else SEGMENT.setPixelColor(SEGENV.aux0, sv1); } // restore spark color after blur + if (valid2) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, sv2); else SEGMENT.setPixelColor(SEGENV.aux1, sv2); } // restore old spark color after blur + } for (int i=0; i> 1)) == 0) { @@ -1261,7 +1264,7 @@ uint16_t mode_rain() { SEGENV.step += FRAMETIME; if (SEGENV.call && SEGENV.step > SPEED_FORMULA_L) { SEGENV.step = 1; - if (strip.isMatrix) { + if (SEGMENT.is2D()) { //uint32_t ctemp[width]; //for (int i = 0; i 100 ? 16 : 0); + if (SEGMENT.check3) SEGMENT.blur(16, cols*rows < 100); return FRAMETIME; } // mode_2DBlackHole() -static const char _data_FX_MODE_2DBLACKHOLE[] PROGMEM = "Black Hole@Fade rate,Outer Y freq.,Outer X freq.,Inner X freq.,Inner Y freq.,Solid;!;!;2;pal=11"; +static const char _data_FX_MODE_2DBLACKHOLE[] PROGMEM = "Black Hole@Fade rate,Outer Y freq.,Outer X freq.,Inner X freq.,Inner Y freq.,Solid,,Blur;!;!;2;pal=11"; //////////////////////////// @@ -5636,7 +5639,7 @@ uint16_t mode_2DPulser(void) { // By: ldirko https://edi int y = map((sin8(a * 5) + sin8(a * 4) + sin8(a * 2)), 0, 765, rows-1, 0); SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, map(y, 0, rows-1, 0, 255), 255, LINEARBLEND)); - SEGMENT.blur(1 + (SEGMENT.intensity>>4)); + SEGMENT.blur(SEGMENT.intensity>>4); return FRAMETIME; } // mode_2DPulser() @@ -6219,7 +6222,7 @@ uint16_t mode_2Ddriftrose(void) { uint32_t y = (CY + (cos_t(angle) * (beatsin8(i, 0, L*2)-L))) * 255.f; SEGMENT.wu_pixel(x, y, CHSV(i * 10, 255, 255)); } - SEGMENT.blur((SEGMENT.intensity>>4)+1); + SEGMENT.blur(SEGMENT.intensity>>4); return FRAMETIME; } @@ -6475,11 +6478,11 @@ uint16_t mode_2DWaverly(void) { SEGMENT.addPixelColorXY((cols - 1) - i, (rows - 1) - j, ColorFromPalette(SEGPALETTE, map(j, 0, thisMax, 250, 0), 255, LINEARBLEND)); } } - SEGMENT.blur(cols*rows > 100 ? 16 : 0); + if (SEGMENT.check3) SEGMENT.blur(16, cols*rows < 100); return FRAMETIME; } // mode_2DWaverly() -static const char _data_FX_MODE_2DWAVERLY[] PROGMEM = "Waverly@Amplification,Sensitivity;;!;2v;ix=64,si=0"; // Beatsin +static const char _data_FX_MODE_2DWAVERLY[] PROGMEM = "Waverly@Amplification,Sensitivity,,,,,Blur;;!;2v;ix=64,si=0"; // Beatsin #endif // WLED_DISABLE_2D diff --git a/wled00/FX.h b/wled00/FX.h index 98fdbf1fc..276a16703 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -636,7 +636,8 @@ typedef struct Segment { 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)); } - void box_blur(uint16_t i, bool vertical, fract8 blur_amount); // 1D box blur (with weight) + 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 moveX(int8_t delta, bool wrap = false); @@ -666,14 +667,15 @@ typedef struct Segment { inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColor(x, RGBW32(r,g,b,w), aa); } inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) { setPixelColor(x, RGBW32(c.r,c.g,c.b,0), aa); } #endif - inline uint32_t getPixelColorXY(uint16_t x, uint16_t y) { return getPixelColor(x); } + 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 fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { fadePixelColor(x, fade); } - inline void box_blur(uint16_t i, bool vertical, fract8 blur_amount) {} + 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 moveX(int8_t delta, bool wrap = false) {} @@ -800,56 +802,55 @@ class WS2812FX { // 96 bytes bool paletteFade, checkSegmentAlignment(void), - hasRGBWBus(void), - hasCCTBus(void), - // return true if the strip is being sent pixel updates - isUpdating(void), + hasRGBWBus(void) const, + hasCCTBus(void) const, + isUpdating(void) const, // return true if the strip is being sent pixel updates deserializeMap(uint8_t n=0); - inline bool isServicing(void) { return _isServicing; } // returns true if strip.service() is executing - inline bool hasWhiteChannel(void) { return _hasWhiteChannel; } // returns true if strip contains separate white chanel - inline bool isOffRefreshRequired(void) { return _isOffRefreshRequired; } // returns true if strip requires regular updates (i.e. TM1814 chipset) - inline bool isSuspended(void) { return _suspend; } // returns true if strip.service() execution is suspended - inline bool needsUpdate(void) { return _triggered; } // returns true if strip received a trigger() request + inline bool isServicing(void) const { return _isServicing; } // returns true if strip.service() is executing + inline bool hasWhiteChannel(void) const { return _hasWhiteChannel; } // returns true if strip contains separate white chanel + inline bool isOffRefreshRequired(void) const { return _isOffRefreshRequired; } // returns true if strip requires regular updates (i.e. TM1814 chipset) + inline bool isSuspended(void) const { return _suspend; } // returns true if strip.service() execution is suspended + inline bool needsUpdate(void) const { return _triggered; } // returns true if strip received a trigger() request uint8_t paletteBlend, cctBlending, - getActiveSegmentsNum(void), - getFirstSelectedSegId(void), - getLastActiveSegmentId(void), - getActiveSegsLightCapabilities(bool selectedOnly = false); + getActiveSegmentsNum(void) const, + getFirstSelectedSegId(void) const, + getLastActiveSegmentId(void) const, + getActiveSegsLightCapabilities(bool selectedOnly = false) const; - inline uint8_t getBrightness(void) { return _brightness; } // returns current strip brightness - inline uint8_t getMaxSegments(void) { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value) - inline uint8_t getSegmentsNum(void) { return _segments.size(); } // returns currently present segments - inline uint8_t getCurrSegmentId(void) { return _segment_index; } // returns current segment index (only valid while strip.isServicing()) - inline uint8_t getMainSegmentId(void) { return _mainSegment; } // returns main segment index - inline uint8_t getPaletteCount() { return 13 + GRADIENT_PALETTE_COUNT + customPalettes.size(); } - inline uint8_t getTargetFps() { return _targetFps; } // returns rough FPS value for las 2s interval - inline uint8_t getModeCount() { return _modeCount; } // returns number of registered modes/effects + inline uint8_t getBrightness(void) const { return _brightness; } // returns current strip brightness + inline uint8_t getMaxSegments(void) const { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value) + inline uint8_t getSegmentsNum(void) const { return _segments.size(); } // returns currently present segments + inline uint8_t getCurrSegmentId(void) const { return _segment_index; } // returns current segment index (only valid while strip.isServicing()) + inline uint8_t getMainSegmentId(void) const { return _mainSegment; } // returns main segment index + inline uint8_t getPaletteCount() const { return 13 + GRADIENT_PALETTE_COUNT + customPalettes.size(); } + inline uint8_t getTargetFps() const { return _targetFps; } // returns rough FPS value for las 2s interval + inline uint8_t getModeCount() const { return _modeCount; } // returns number of registered modes/effects uint16_t - getLengthPhysical(void), - getLengthTotal(void), // will include virtual/nonexistent pixels in matrix - getFps(), - getMappedPixelIndex(uint16_t index); + getLengthPhysical(void) const, + getLengthTotal(void) const, // will include virtual/nonexistent pixels in matrix + getFps() const, + getMappedPixelIndex(uint16_t index) const; - inline uint16_t getFrameTime(void) { return _frametime; } // returns amount of time a frame should take (in ms) - inline uint16_t getMinShowDelay(void) { return MIN_SHOW_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant) - inline uint16_t getLength(void) { return _length; } // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H) - inline uint16_t getTransition(void) { return _transitionDur; } // returns currently set transition time (in ms) + inline uint16_t getFrameTime(void) const { return _frametime; } // returns amount of time a frame should take (in ms) + inline uint16_t getMinShowDelay(void) const { return MIN_SHOW_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant) + inline uint16_t getLength(void) const { return _length; } // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H) + inline uint16_t getTransition(void) const { return _transitionDur; } // returns currently set transition time (in ms) uint32_t now, timebase, - getPixelColor(uint16_t); + getPixelColor(uint16_t) const; - inline uint32_t getLastShow(void) { return _lastShow; } // returns millis() timestamp of last strip.show() call - inline uint32_t segColor(uint8_t i) { return _colors_t[i]; } // returns currently valid color (for slot i) AKA SEGCOLOR(); may be blended between two colors while in transition + inline uint32_t getLastShow(void) 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) { return (id && id<_modeCount) ? _modeData[id] : PSTR("Solid"); } + getModeData(uint8_t id = 0) const { return (id && id<_modeCount) ? _modeData[id] : PSTR("Solid"); } const char ** getModeDataSrc(void) { return &(_modeData[0]); } // vectors use arrays for underlying data @@ -900,7 +901,7 @@ class WS2812FX { // 96 bytes 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 uint32_t getPixelColorXY(uint16_t x, uint16_t y) { return getPixelColor(isMatrix ? y * Segment::maxWidth + x : x);} + inline uint32_t getPixelColorXY(int x, int y) const { return getPixelColor(isMatrix ? y * Segment::maxWidth + x : x); } // end 2D support diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index c135c3dbc..0fd5bb09f 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -184,13 +184,16 @@ void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col) x *= groupLength(); // expand to physical pixels y *= groupLength(); // expand to physical pixels - if (x >= width() || y >= height()) return; // if pixel would fall out of segment just exit + + unsigned W = width(); + unsigned H = height(); + if (x >= W || y >= H) return; // if pixel would fall out of segment just exit uint32_t tmpCol = col; - for (int j = 0; j < grouping; j++) { // groupping vertically - for (int g = 0; g < grouping; g++) { // groupping horizontally + for (unsigned j = 0; j < grouping; j++) { // groupping vertically + for (unsigned g = 0; g < grouping; g++) { // groupping horizontally unsigned xX = (x+g), yY = (y+j); - if (xX >= width() || yY >= height()) continue; // we have reached one dimension's end + if (xX >= W || yY >= H) continue; // we have reached one dimension's end #ifndef WLED_DISABLE_MODE_BLEND // if blending modes, blend with underlying pixel @@ -339,39 +342,126 @@ void Segment::blurCol(uint32_t col, fract8 blur_amount, bool smear) { setPixelColorXY(col, rows - 1, curnew); } -// 1D Box blur (with added weight - blur_amount: [0=no blur, 255=max blur]) -void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) { +void Segment::blur2D(uint8_t blur_amount, bool smear) { if (!isActive() || blur_amount == 0) return; // not active - const int cols = virtualWidth(); - const int rows = virtualHeight(); - const int dim1 = vertical ? rows : cols; - const int dim2 = vertical ? cols : rows; - if (i >= dim2) return; - const float seep = blur_amount/255.f; - const float keep = 3.f - 2.f*seep; - // 1D box blur - uint32_t out[dim1], in[dim1]; - for (int j = 0; j < dim1; j++) { - int x = vertical ? i : j; - int y = vertical ? j : i; - in[j] = getPixelColorXY(x, y); + const unsigned cols = virtualWidth(); + const unsigned rows = virtualHeight(); + + 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, true); + uint32_t prev = color_add(lastnew, part, true); + // 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 } - for (int j = 0; j < dim1; j++) { - uint32_t curr = in[j]; - uint32_t prev = j > 0 ? in[j-1] : BLACK; - uint32_t next = j < dim1-1 ? in[j+1] : BLACK; - uint8_t r, g, b, w; - r = (R(curr)*keep + (R(prev) + R(next))*seep) / 3; - g = (G(curr)*keep + (G(prev) + G(next))*seep) / 3; - b = (B(curr)*keep + (B(prev) + B(next))*seep) / 3; - w = (W(curr)*keep + (W(prev) + W(next))*seep) / 3; - out[j] = RGBW32(r,g,b,w); + 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, true); + uint32_t prev = color_add(lastnew, part, true); + // 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); } - for (int j = 0; j < dim1; j++) { - int x = vertical ? i : j; - int y = vertical ? j : i; - setPixelColorXY(x, y, out[j]); +} + +// 2D Box blur +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(); + uint16_t *tmpRSum = new uint16_t[cols*rows]; + uint16_t *tmpGSum = new uint16_t[cols*rows]; + uint16_t *tmpBSum = new uint16_t[cols*rows]; + uint16_t *tmpWSum = new uint16_t[cols*rows]; + // fill summed-area table (https://en.wikipedia.org/wiki/Summed-area_table) + for (unsigned x = 0; x < cols; x++) { + unsigned rS, gS, bS, wS; + unsigned index; + rS = gS = bS = wS = 0; + for (unsigned y = 0; y < rows; y++) { + index = x * cols + y; + if (x > 0) { + unsigned index2 = (x - 1) * cols + y; + tmpRSum[index] = tmpRSum[index2]; + tmpGSum[index] = tmpGSum[index2]; + tmpBSum[index] = tmpBSum[index2]; + tmpWSum[index] = tmpWSum[index2]; + } else { + tmpRSum[index] = 0; + tmpGSum[index] = 0; + tmpBSum[index] = 0; + tmpWSum[index] = 0; + } + uint32_t c = getPixelColorXY(x, y); + rS += R(c); + gS += G(c); + bS += B(c); + wS += W(c); + tmpRSum[index] += rS; + tmpGSum[index] += gS; + tmpBSum[index] += bS; + tmpWSum[index] += wS; + } } + // do a box blur using pre-calculated sums + for (unsigned x = 0; x < cols; x++) { + for (unsigned y = 0; y < rows; y++) { + // sum = D + A - B - C where k = (x,y) + // +----+-+---- (x) + // | | | + // +----A-B + // | |k| + // +----C-D + // | + //(y) + unsigned x0 = x < radius ? 0 : x - radius; + unsigned y0 = y < radius ? 0 : y - radius; + unsigned x1 = x >= cols - radius ? cols - 1 : x + radius; + unsigned y1 = y >= rows - radius ? rows - 1 : y + radius; + unsigned A = x0 * cols + y0; + unsigned B = x1 * cols + y0; + unsigned C = x0 * cols + y1; + unsigned D = x1 * cols + y1; + unsigned r = tmpRSum[D] + tmpRSum[A] - tmpRSum[C] - tmpRSum[B]; + unsigned g = tmpGSum[D] + tmpGSum[A] - tmpGSum[C] - tmpGSum[B]; + unsigned b = tmpBSum[D] + tmpBSum[A] - tmpBSum[C] - tmpBSum[B]; + unsigned w = tmpWSum[D] + tmpWSum[A] - tmpWSum[C] - tmpWSum[B]; + setPixelColorXY(x, y, RGBW32(r/d, g/d, b/d, w/d)); + } + } + delete[] tmpRSum; + delete[] tmpGSum; + delete[] tmpBSum; + delete[] tmpWSum; } void Segment::moveX(int8_t delta, bool wrap) { diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 758df62fa..80eedc085 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -954,9 +954,9 @@ uint32_t IRAM_ATTR Segment::getPixelColor(int i) const if (reverse) i = virtualLength() - i - 1; i *= groupLength(); i += start; - /* offset/phase */ + // offset/phase i += offset; - if ((i >= stop) && (stop>0)) i -= length(); // avoids negative pixel index (stop = 0 is a possible value) + if (i >= stop) i -= length(); return strip.getPixelColor(i); } @@ -1110,15 +1110,13 @@ void Segment::blur(uint8_t blur_amount, bool smear) { #ifndef WLED_DISABLE_2D if (is2D()) { // compatibility with 2D - const unsigned cols = virtualWidth(); - const unsigned rows = virtualHeight(); - for (unsigned i = 0; i < rows; i++) blurRow(i, blur_amount, smear); // blur all rows - for (unsigned k = 0; k < cols; k++) blurCol(k, blur_amount, smear); // blur all columns + blur2D(blur_amount, smear); + //box_blur(map(blur_amount,1,255,1,3), smear); return; } #endif uint8_t keep = smear ? 255 : 255 - blur_amount; - uint8_t seep = blur_amount >> 1; + uint8_t seep = blur_amount >> (1 + smear); unsigned vlength = virtualLength(); uint32_t carryover = BLACK; uint32_t lastnew; @@ -1129,13 +1127,11 @@ 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); + if (carryover) curnew = color_add(curnew, carryover, true); uint32_t prev = color_add(lastnew, part, true); - if (last != prev) // optimization: only set pixel if color has changed - setPixelColor(i - 1, prev); - } - else // first pixel + // optimization: only set pixel if color has changed + if (last != prev) setPixelColor(i - 1, prev); + } else // first pixel setPixelColor(i, curnew); lastnew = curnew; last = cur; // save original value for comparison on next iteration @@ -1357,7 +1353,7 @@ void IRAM_ATTR WS2812FX::setPixelColor(unsigned i, uint32_t col) { BusManager::setPixelColor(i, col); } -uint32_t IRAM_ATTR WS2812FX::getPixelColor(uint16_t i) { +uint32_t IRAM_ATTR WS2812FX::getPixelColor(uint16_t i) const { i = getMappedPixelIndex(i); if (i >= _length) return 0; return BusManager::getPixelColor(i); @@ -1385,7 +1381,7 @@ void WS2812FX::show(void) { * 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() { +bool WS2812FX::isUpdating() const { return !BusManager::canAllShow(); } @@ -1393,7 +1389,7 @@ bool WS2812FX::isUpdating() { * 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() { +uint16_t WS2812FX::getFps() const { if (millis() - _lastShow > 2000) return 0; return _cumulativeFps +1; } @@ -1452,17 +1448,17 @@ void WS2812FX::setBrightness(uint8_t b, bool direct) { } } -uint8_t WS2812FX::getActiveSegsLightCapabilities(bool selectedOnly) { +uint8_t WS2812FX::getActiveSegsLightCapabilities(bool selectedOnly) const { uint8_t totalLC = 0; - for (segment &seg : _segments) { + for (const segment &seg : _segments) { if (seg.isActive() && (!selectedOnly || seg.isSelected())) totalLC |= seg.getLightCapabilities(); } return totalLC; } -uint8_t WS2812FX::getFirstSelectedSegId(void) { +uint8_t WS2812FX::getFirstSelectedSegId(void) const { size_t i = 0; - for (segment &seg : _segments) { + for (const segment &seg : _segments) { if (seg.isActive() && seg.isSelected()) return i; i++; } @@ -1478,14 +1474,14 @@ void WS2812FX::setMainSegmentId(uint8_t n) { return; } -uint8_t WS2812FX::getLastActiveSegmentId(void) { +uint8_t WS2812FX::getLastActiveSegmentId(void) const { for (size_t i = _segments.size() -1; i > 0; i--) { if (_segments[i].isActive()) return i; } return 0; } -uint8_t WS2812FX::getActiveSegmentsNum(void) { +uint8_t WS2812FX::getActiveSegmentsNum(void) const { uint8_t c = 0; for (size_t i = 0; i < _segments.size(); i++) { if (_segments[i].isActive()) c++; @@ -1493,13 +1489,13 @@ uint8_t WS2812FX::getActiveSegmentsNum(void) { return c; } -uint16_t WS2812FX::getLengthTotal(void) { +uint16_t WS2812FX::getLengthTotal(void) const { unsigned len = Segment::maxWidth * Segment::maxHeight; // will be _length for 1D (see finalizeInit()) but should cover whole matrix for 2D if (isMatrix && _length > len) len = _length; // for 2D with trailing strip return len; } -uint16_t WS2812FX::getLengthPhysical(void) { +uint16_t WS2812FX::getLengthPhysical(void) const { unsigned len = 0; for (size_t b = 0; b < BusManager::getNumBusses(); b++) { Bus *bus = BusManager::getBus(b); @@ -1512,7 +1508,7 @@ uint16_t WS2812FX::getLengthPhysical(void) { //used for JSON API info.leds.rgbw. Little practical use, deprecate with info.leds.rgbw. //returns if there is an RGBW bus (supports RGB and White, not only white) //not influenced by auto-white mode, also true if white slider does not affect output white channel -bool WS2812FX::hasRGBWBus(void) { +bool WS2812FX::hasRGBWBus(void) const { for (size_t b = 0; b < BusManager::getNumBusses(); b++) { Bus *bus = BusManager::getBus(b); if (bus == nullptr || bus->getLength()==0) break; @@ -1521,7 +1517,7 @@ bool WS2812FX::hasRGBWBus(void) { return false; } -bool WS2812FX::hasCCTBus(void) { +bool WS2812FX::hasCCTBus(void) const { if (cctFromRgb && !correctWB) return false; for (size_t b = 0; b < BusManager::getNumBusses(); b++) { Bus *bus = BusManager::getBus(b); @@ -1813,7 +1809,7 @@ bool WS2812FX::deserializeMap(uint8_t n) { return (customMappingSize > 0); } -uint16_t IRAM_ATTR WS2812FX::getMappedPixelIndex(uint16_t index) { +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]; From e68375a71eca592df1420b191eeb39222c4aa565 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Thu, 15 Aug 2024 09:08:57 +0100 Subject: [PATCH 09/16] Remove repeating code to fetch audio data --- wled00/FX.cpp | 162 +++++++----------------------------------- wled00/fcn_declare.h | 1 + wled00/um_manager.cpp | 8 +++ 3 files changed, 36 insertions(+), 135 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index cce3098e1..e51f66bf8 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -6325,11 +6325,7 @@ uint16_t mode_ripplepeak(void) { // * Ripple peak. By Andrew Tuli if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed Ripple* ripples = reinterpret_cast(SEGENV.data); - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); uint8_t samplePeak = *(uint8_t*)um_data->u_data[3]; #ifdef ESP32 float FFT_MajorPeak = *(float*) um_data->u_data[4]; @@ -6416,11 +6412,7 @@ uint16_t mode_2DSwirl(void) { int ni = (cols - 1) - i; int nj = (cols - 1) - j; - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; //ewowi: use instead of sampleAvg??? int volumeRaw = *(int16_t*) um_data->u_data[1]; @@ -6446,11 +6438,7 @@ uint16_t mode_2DWaverly(void) { const int cols = SEGMENT.virtualWidth(); const int rows = SEGMENT.virtualHeight(); - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; SEGMENT.fadeToBlackBy(SEGMENT.speed); @@ -6499,11 +6487,7 @@ uint16_t mode_gravcenter(void) { // Gravcenter. By Andrew Tuline. if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed Gravity* gravcen = reinterpret_cast(SEGENV.data); - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; //SEGMENT.fade_out(240); @@ -6548,11 +6532,7 @@ uint16_t mode_gravcentric(void) { // Gravcentric. By Andrew if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed Gravity* gravcen = reinterpret_cast(SEGENV.data); - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; // printUmData(); @@ -6600,11 +6580,7 @@ uint16_t mode_gravimeter(void) { // Gravmeter. By Andrew Tuline. if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed Gravity* gravcen = reinterpret_cast(SEGENV.data); - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; //SEGMENT.fade_out(240); @@ -6641,11 +6617,7 @@ static const char _data_FX_MODE_GRAVIMETER[] PROGMEM = "Gravimeter@Rate of fall, // * JUGGLES // ////////////////////// uint16_t mode_juggles(void) { // Juggles. By Andrew Tuline. - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; SEGMENT.fade_out(224); // 6.25% @@ -6668,11 +6640,7 @@ uint16_t mode_matripix(void) { // Matripix. By Andrew Tuline. if (SEGLEN == 1) return mode_static(); // even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); int volumeRaw = *(int16_t*)um_data->u_data[1]; if (SEGENV.call == 0) { @@ -6700,11 +6668,7 @@ uint16_t mode_midnoise(void) { // Midnoise. By Andrew Tuline. if (SEGLEN == 1) return mode_static(); // Changing xdist to SEGENV.aux0 and ydist to SEGENV.aux1. - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; SEGMENT.fade_out(SEGMENT.speed); @@ -6739,11 +6703,7 @@ uint16_t mode_noisefire(void) { // Noisefire. By Andrew Tuline. CRGB::DarkOrange, CRGB::DarkOrange, CRGB::Orange, CRGB::Orange, CRGB::Yellow, CRGB::Orange, CRGB::Yellow, CRGB::Yellow); - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; if (SEGENV.call == 0) SEGMENT.fill(BLACK); @@ -6767,11 +6727,7 @@ static const char _data_FX_MODE_NOISEFIRE[] PROGMEM = "Noisefire@!,!;;;01v;m12=2 /////////////////////// uint16_t mode_noisemeter(void) { // Noisemeter. By Andrew Tuline. - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; int volumeRaw = *(int16_t*)um_data->u_data[1]; @@ -6808,11 +6764,7 @@ uint16_t mode_pixelwave(void) { // Pixelwave. By Andrew Tuline. SEGMENT.fill(BLACK); } - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); int volumeRaw = *(int16_t*)um_data->u_data[1]; uint8_t secondHand = micros()/(256-SEGMENT.speed)/500+1 % 16; @@ -6844,11 +6796,7 @@ uint16_t mode_plasmoid(void) { // Plasmoid. By Andrew Tuline. if (!SEGENV.allocateData(sizeof(plasphase))) return mode_static(); //allocation failed Plasphase* plasmoip = reinterpret_cast(SEGENV.data); - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; SEGMENT.fadeToBlackBy(32); @@ -6883,11 +6831,7 @@ uint16_t mode_puddlepeak(void) { // Puddlepeak. By Andrew Tuline. uint8_t fadeVal = map(SEGMENT.speed,0,255, 224, 254); unsigned pos = random16(SEGLEN); // Set a random starting position. - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); uint8_t samplePeak = *(uint8_t*)um_data->u_data[3]; uint8_t *maxVol = (uint8_t*)um_data->u_data[6]; uint8_t *binNum = (uint8_t*)um_data->u_data[7]; @@ -6928,11 +6872,7 @@ uint16_t mode_puddles(void) { // Puddles. By Andrew Tuline. SEGMENT.fade_out(fadeVal); - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); int volumeRaw = *(int16_t*)um_data->u_data[1]; if (volumeRaw > 1) { @@ -6990,11 +6930,7 @@ uint16_t mode_blurz(void) { // Blurz. By Andrew Tuline. if (SEGLEN == 1) return mode_static(); // even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; if (SEGENV.call == 0) { @@ -7027,11 +6963,7 @@ uint16_t mode_DJLight(void) { // Written by ??? Adapted by Wil // No need to prevent from executing on single led strips, only mid will be set (mid = 0) const int mid = SEGLEN / 2; - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; if (SEGENV.call == 0) { @@ -7063,11 +6995,7 @@ uint16_t mode_freqmap(void) { // Map FFT_MajorPeak to SEGLEN. // Start frequency = 60 Hz and log10(60) = 1.78 // End frequency = MAX_FREQUENCY in Hz and lo10(MAX_FREQUENCY) = MAX_FREQ_LOG10 - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); float FFT_MajorPeak = *(float*)um_data->u_data[4]; float my_magnitude = *(float*)um_data->u_data[5] / 4.0f; if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; // log10(0) is "forbidden" (throws exception) @@ -7097,11 +7025,7 @@ static const char _data_FX_MODE_FREQMAP[] PROGMEM = "Freqmap@Fade rate,Starting /////////////////////// uint16_t mode_freqmatrix(void) { // Freqmatrix. By Andreas Pleschung. // No need to prevent from executing on single led strips, we simply change pixel 0 each time and avoid the shift - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); float FFT_MajorPeak = *(float*)um_data->u_data[4]; float volumeSmth = *(float*)um_data->u_data[0]; @@ -7156,11 +7080,7 @@ static const char _data_FX_MODE_FREQMATRIX[] PROGMEM = "Freqmatrix@Speed,Sound e // SEGMENT.speed select faderate // SEGMENT.intensity select colour index uint16_t mode_freqpixels(void) { // Freqpixel. By Andrew Tuline. - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); float FFT_MajorPeak = *(float*)um_data->u_data[4]; float my_magnitude = *(float*)um_data->u_data[5] / 16.0f; if (FFT_MajorPeak < 1) FFT_MajorPeak = 1.0f; // log10(0) is "forbidden" (throws exception) @@ -7203,11 +7123,7 @@ static const char _data_FX_MODE_FREQPIXELS[] PROGMEM = "Freqpixels@Fade rate,Sta // Depending on the music stream you have you might find it useful to change the frequency mapping. uint16_t mode_freqwave(void) { // Freqwave. By Andreas Pleschung. // As before, this effect can also work on single pixels, we just lose the shifting effect - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); float FFT_MajorPeak = *(float*)um_data->u_data[4]; float volumeSmth = *(float*)um_data->u_data[0]; @@ -7262,11 +7178,7 @@ uint16_t mode_gravfreq(void) { // Gravfreq. By Andrew Tuline. if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed Gravity* gravcen = reinterpret_cast(SEGENV.data); - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); float FFT_MajorPeak = *(float*)um_data->u_data[4]; float volumeSmth = *(float*)um_data->u_data[0]; if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; // log10(0) is "forbidden" (throws exception) @@ -7309,11 +7221,7 @@ static const char _data_FX_MODE_GRAVFREQ[] PROGMEM = "Gravfreq@Rate of fall,Sens // ** Noisemove // ////////////////////// uint16_t mode_noisemove(void) { // Noisemove. By: Andrew Tuline - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; int fadeoutDelay = (256 - SEGMENT.speed) / 96; @@ -7336,11 +7244,7 @@ static const char _data_FX_MODE_NOISEMOVE[] PROGMEM = "Noisemove@Speed of perlin // ** Rocktaves // ////////////////////// uint16_t mode_rocktaves(void) { // Rocktaves. Same note from each octave is same colour. By: Andrew Tuline - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); float FFT_MajorPeak = *(float*) um_data->u_data[4]; float my_magnitude = *(float*) um_data->u_data[5] / 16.0f; @@ -7378,11 +7282,7 @@ static const char _data_FX_MODE_ROCKTAVES[] PROGMEM = "Rocktaves@;!,!;!;01f;m12= uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tuline // effect can work on single pixels, we just lose the shifting effect - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); uint8_t samplePeak = *(uint8_t*)um_data->u_data[3]; float FFT_MajorPeak = *(float*) um_data->u_data[4]; uint8_t *maxVol = (uint8_t*)um_data->u_data[6]; @@ -7437,11 +7337,7 @@ uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma. 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 - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } + um_data_t *um_data = usermods.getAudioData(); uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; if (SEGENV.call == 0) for (int i=0; iu_data[2]; if (SEGENV.call == 0) { diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index d95b8ef8e..3f0e63338 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -326,6 +326,7 @@ class UsermodManager { 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 + um_data_t *getAudioData(); void setup(); void connected(); void appendConfigData(); diff --git a/wled00/um_manager.cpp b/wled00/um_manager.cpp index 2db29c3cd..3add18f39 100644 --- a/wled00/um_manager.cpp +++ b/wled00/um_manager.cpp @@ -23,6 +23,14 @@ bool UsermodManager::getUMData(um_data_t **data, uint8_t mod_id) { } return false; } +um_data_t* UsermodManager::getAudioData() { + um_data_t *um_data; + if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { + // add support for no audio + um_data = simulateSound(SEGMENT.soundSim); + } + return um_data; +} void UsermodManager::addToJsonState(JsonObject& obj) { for (unsigned i = 0; i < numMods; i++) ums[i]->addToJsonState(obj); } void UsermodManager::addToJsonInfo(JsonObject& obj) { for (unsigned i = 0; i < numMods; i++) ums[i]->addToJsonInfo(obj); } void UsermodManager::readFromJsonState(JsonObject& obj) { for (unsigned i = 0; i < numMods; i++) ums[i]->readFromJsonState(obj); } From 577fce69e2bf1aea598b398e7bec0c2090a67cf4 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Thu, 15 Aug 2024 16:18:34 +0200 Subject: [PATCH 10/16] MQTT unification and cleanup --- wled00/cfg.cpp | 8 ++++---- wled00/mqtt.cpp | 9 +++++---- wled00/set.cpp | 2 +- wled00/wled.h | 2 +- wled00/xml.cpp | 2 +- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index f9a94e228..a6e919dee 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -537,7 +537,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { CJSON(alexaNumPresets, interfaces["va"]["p"]); -#ifdef WLED_ENABLE_MQTT +#ifndef WLED_DISABLE_MQTT JsonObject if_mqtt = interfaces["mqtt"]; CJSON(mqttEnabled, if_mqtt["en"]); getStringFromJson(mqttServer, if_mqtt[F("broker")], MQTT_MAX_SERVER_LEN+1); @@ -1019,7 +1019,7 @@ void serializeConfig() { if_va["p"] = alexaNumPresets; #endif -#ifdef WLED_ENABLE_MQTT +#ifndef WLED_DISABLE_MQTT JsonObject if_mqtt = interfaces.createNestedObject("mqtt"); if_mqtt["en"] = mqttEnabled; if_mqtt[F("broker")] = mqttServer; @@ -1165,7 +1165,7 @@ bool deserializeConfigSec() { [[maybe_unused]] JsonObject interfaces = root["if"]; -#ifdef WLED_ENABLE_MQTT +#ifndef WLED_DISABLE_MQTT JsonObject if_mqtt = interfaces["mqtt"]; getStringFromJson(mqttPass, if_mqtt["psk"], 65); #endif @@ -1206,7 +1206,7 @@ void serializeConfigSec() { ap["psk"] = apPass; [[maybe_unused]] JsonObject interfaces = root.createNestedObject("if"); -#ifdef WLED_ENABLE_MQTT +#ifndef WLED_DISABLE_MQTT JsonObject if_mqtt = interfaces.createNestedObject("mqtt"); if_mqtt["psk"] = mqttPass; #endif diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp index 5599824ef..775a4fe58 100644 --- a/wled00/mqtt.cpp +++ b/wled00/mqtt.cpp @@ -4,10 +4,10 @@ * MQTT communication protocol for home automation */ -#ifdef WLED_ENABLE_MQTT +#ifndef WLED_DISABLE_MQTT #define MQTT_KEEP_ALIVE_TIME 60 // contact the MQTT broker every 60 seconds -void parseMQTTBriPayload(char* payload) +static void parseMQTTBriPayload(char* payload) { if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) {bri = briLast; stateUpdated(CALL_MODE_DIRECT_CHANGE);} else if (strstr(payload, "T" ) || strstr(payload, "t" )) {toggleOnOff(); stateUpdated(CALL_MODE_DIRECT_CHANGE);} @@ -20,7 +20,7 @@ void parseMQTTBriPayload(char* payload) } -void onMqttConnect(bool sessionPresent) +static void onMqttConnect(bool sessionPresent) { //(re)subscribe to required topics char subuf[38]; @@ -52,7 +52,7 @@ void onMqttConnect(bool sessionPresent) } -void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) { +static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) { static char *payloadStr; DEBUG_PRINT(F("MQTT msg: ")); @@ -166,6 +166,7 @@ bool initMqtt() if (mqtt == nullptr) { mqtt = new AsyncMqttClient(); + if (!mqtt) return false; mqtt->onMessage(onMqttMessage); mqtt->onConnect(onMqttConnect); } diff --git a/wled00/set.cpp b/wled00/set.cpp index 3dd226e00..5eecb5c9a 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -426,7 +426,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) t = request->arg(F("AP")).toInt(); if (t >= 0 && t <= 9) alexaNumPresets = t; - #ifdef WLED_ENABLE_MQTT + #ifndef WLED_DISABLE_MQTT mqttEnabled = request->hasArg(F("MQ")); strlcpy(mqttServer, request->arg(F("MS")).c_str(), MQTT_MAX_SERVER_LEN+1); t = request->arg(F("MQPORT")).toInt(); diff --git a/wled00/wled.h b/wled00/wled.h index d6915e7fb..b381a8a16 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -145,7 +145,7 @@ #endif #include "src/dependencies/e131/ESPAsyncE131.h" -#ifdef WLED_ENABLE_MQTT +#ifndef WLED_DISABLE_MQTT #include "src/dependencies/async-mqtt-client/AsyncMqttClient.h" #endif diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 7da301715..2ae599f5d 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -541,7 +541,7 @@ void getSettingsJS(byte subPage, char* dest) oappend(SET_F("toggle('Alexa');")); // hide Alexa settings #endif - #ifdef WLED_ENABLE_MQTT + #ifndef WLED_DISABLE_MQTT sappend('c',SET_F("MQ"),mqttEnabled); sappends('s',SET_F("MS"),mqttServer); sappend('v',SET_F("MQPORT"),mqttPort); From 9940d2590bae64c7461f45654d72be9400c644f2 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Thu, 15 Aug 2024 17:22:59 +0200 Subject: [PATCH 11/16] Arc expansion getPixelColor fix. --- wled00/FX_fcn.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 80eedc085..0608f6784 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -674,7 +674,7 @@ uint16_t IRAM_ATTR Segment::virtualLength() const { if (is2D()) { unsigned vW = virtualWidth(); unsigned vH = virtualHeight(); - unsigned vLen = vW * vH; // use all pixels from segment + unsigned vLen; switch (map1D2D) { case M12_pBar: vLen = vH; @@ -688,6 +688,9 @@ uint16_t IRAM_ATTR Segment::virtualLength() const { case M12_sPinwheel: vLen = getPinwheelLength(vW, vH); break; + default: + vLen = vW * vH; // use all pixels from segment + break; } return vLen; } @@ -913,6 +916,10 @@ uint32_t IRAM_ATTR Segment::getPixelColor(int i) const else return getPixelColorXY(0, vH - i -1); break; case M12_pArc: + if (i >= vW && i >= vH) { + unsigned vI = sqrt16(i*i/2); + return getPixelColorXY(vI,vI); // use diagonal + } case M12_pCorner: // use longest dimension return vW>vH ? getPixelColorXY(i, 0) : getPixelColorXY(0, i); From 24ecf1a16626870d53a8d6a229d47b7909ee7a2a Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Thu, 15 Aug 2024 17:58:19 +0100 Subject: [PATCH 12/16] Move getAudioData to static --- wled00/FX.cpp | 63 ++++++++++++++++++++++++------------------- wled00/fcn_declare.h | 1 - wled00/um_manager.cpp | 8 ------ 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index e51f66bf8..bca9e58f2 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -73,6 +73,15 @@ int8_t tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec) { return 0; } +static um_data_t* getAudioData() { + um_data_t *um_data; + if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { + // add support for no audio + um_data = simulateSound(SEGMENT.soundSim); + } + return um_data; +} + // effect functions /* @@ -6325,7 +6334,7 @@ uint16_t mode_ripplepeak(void) { // * Ripple peak. By Andrew Tuli if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed Ripple* ripples = reinterpret_cast(SEGENV.data); - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); uint8_t samplePeak = *(uint8_t*)um_data->u_data[3]; #ifdef ESP32 float FFT_MajorPeak = *(float*) um_data->u_data[4]; @@ -6412,7 +6421,7 @@ uint16_t mode_2DSwirl(void) { int ni = (cols - 1) - i; int nj = (cols - 1) - j; - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; //ewowi: use instead of sampleAvg??? int volumeRaw = *(int16_t*) um_data->u_data[1]; @@ -6438,7 +6447,7 @@ uint16_t mode_2DWaverly(void) { const int cols = SEGMENT.virtualWidth(); const int rows = SEGMENT.virtualHeight(); - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; SEGMENT.fadeToBlackBy(SEGMENT.speed); @@ -6487,7 +6496,7 @@ uint16_t mode_gravcenter(void) { // Gravcenter. By Andrew Tuline. if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed Gravity* gravcen = reinterpret_cast(SEGENV.data); - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; //SEGMENT.fade_out(240); @@ -6532,7 +6541,7 @@ uint16_t mode_gravcentric(void) { // Gravcentric. By Andrew if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed Gravity* gravcen = reinterpret_cast(SEGENV.data); - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; // printUmData(); @@ -6580,7 +6589,7 @@ uint16_t mode_gravimeter(void) { // Gravmeter. By Andrew Tuline. if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed Gravity* gravcen = reinterpret_cast(SEGENV.data); - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; //SEGMENT.fade_out(240); @@ -6617,7 +6626,7 @@ static const char _data_FX_MODE_GRAVIMETER[] PROGMEM = "Gravimeter@Rate of fall, // * JUGGLES // ////////////////////// uint16_t mode_juggles(void) { // Juggles. By Andrew Tuline. - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; SEGMENT.fade_out(224); // 6.25% @@ -6640,7 +6649,7 @@ uint16_t mode_matripix(void) { // Matripix. By Andrew Tuline. if (SEGLEN == 1) return mode_static(); // even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); int volumeRaw = *(int16_t*)um_data->u_data[1]; if (SEGENV.call == 0) { @@ -6668,7 +6677,7 @@ uint16_t mode_midnoise(void) { // Midnoise. By Andrew Tuline. if (SEGLEN == 1) return mode_static(); // Changing xdist to SEGENV.aux0 and ydist to SEGENV.aux1. - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; SEGMENT.fade_out(SEGMENT.speed); @@ -6703,7 +6712,7 @@ uint16_t mode_noisefire(void) { // Noisefire. By Andrew Tuline. CRGB::DarkOrange, CRGB::DarkOrange, CRGB::Orange, CRGB::Orange, CRGB::Yellow, CRGB::Orange, CRGB::Yellow, CRGB::Yellow); - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; if (SEGENV.call == 0) SEGMENT.fill(BLACK); @@ -6727,7 +6736,7 @@ static const char _data_FX_MODE_NOISEFIRE[] PROGMEM = "Noisefire@!,!;;;01v;m12=2 /////////////////////// uint16_t mode_noisemeter(void) { // Noisemeter. By Andrew Tuline. - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; int volumeRaw = *(int16_t*)um_data->u_data[1]; @@ -6764,7 +6773,7 @@ uint16_t mode_pixelwave(void) { // Pixelwave. By Andrew Tuline. SEGMENT.fill(BLACK); } - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); int volumeRaw = *(int16_t*)um_data->u_data[1]; uint8_t secondHand = micros()/(256-SEGMENT.speed)/500+1 % 16; @@ -6796,7 +6805,7 @@ uint16_t mode_plasmoid(void) { // Plasmoid. By Andrew Tuline. if (!SEGENV.allocateData(sizeof(plasphase))) return mode_static(); //allocation failed Plasphase* plasmoip = reinterpret_cast(SEGENV.data); - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; SEGMENT.fadeToBlackBy(32); @@ -6831,7 +6840,7 @@ uint16_t mode_puddlepeak(void) { // Puddlepeak. By Andrew Tuline. uint8_t fadeVal = map(SEGMENT.speed,0,255, 224, 254); unsigned pos = random16(SEGLEN); // Set a random starting position. - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); uint8_t samplePeak = *(uint8_t*)um_data->u_data[3]; uint8_t *maxVol = (uint8_t*)um_data->u_data[6]; uint8_t *binNum = (uint8_t*)um_data->u_data[7]; @@ -6872,7 +6881,7 @@ uint16_t mode_puddles(void) { // Puddles. By Andrew Tuline. SEGMENT.fade_out(fadeVal); - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); int volumeRaw = *(int16_t*)um_data->u_data[1]; if (volumeRaw > 1) { @@ -6930,7 +6939,7 @@ uint16_t mode_blurz(void) { // Blurz. By Andrew Tuline. if (SEGLEN == 1) return mode_static(); // even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; if (SEGENV.call == 0) { @@ -6963,7 +6972,7 @@ uint16_t mode_DJLight(void) { // Written by ??? Adapted by Wil // No need to prevent from executing on single led strips, only mid will be set (mid = 0) const int mid = SEGLEN / 2; - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; if (SEGENV.call == 0) { @@ -6995,7 +7004,7 @@ uint16_t mode_freqmap(void) { // Map FFT_MajorPeak to SEGLEN. // Start frequency = 60 Hz and log10(60) = 1.78 // End frequency = MAX_FREQUENCY in Hz and lo10(MAX_FREQUENCY) = MAX_FREQ_LOG10 - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); float FFT_MajorPeak = *(float*)um_data->u_data[4]; float my_magnitude = *(float*)um_data->u_data[5] / 4.0f; if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; // log10(0) is "forbidden" (throws exception) @@ -7025,7 +7034,7 @@ static const char _data_FX_MODE_FREQMAP[] PROGMEM = "Freqmap@Fade rate,Starting /////////////////////// uint16_t mode_freqmatrix(void) { // Freqmatrix. By Andreas Pleschung. // No need to prevent from executing on single led strips, we simply change pixel 0 each time and avoid the shift - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); float FFT_MajorPeak = *(float*)um_data->u_data[4]; float volumeSmth = *(float*)um_data->u_data[0]; @@ -7080,7 +7089,7 @@ static const char _data_FX_MODE_FREQMATRIX[] PROGMEM = "Freqmatrix@Speed,Sound e // SEGMENT.speed select faderate // SEGMENT.intensity select colour index uint16_t mode_freqpixels(void) { // Freqpixel. By Andrew Tuline. - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); float FFT_MajorPeak = *(float*)um_data->u_data[4]; float my_magnitude = *(float*)um_data->u_data[5] / 16.0f; if (FFT_MajorPeak < 1) FFT_MajorPeak = 1.0f; // log10(0) is "forbidden" (throws exception) @@ -7123,7 +7132,7 @@ static const char _data_FX_MODE_FREQPIXELS[] PROGMEM = "Freqpixels@Fade rate,Sta // Depending on the music stream you have you might find it useful to change the frequency mapping. uint16_t mode_freqwave(void) { // Freqwave. By Andreas Pleschung. // As before, this effect can also work on single pixels, we just lose the shifting effect - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); float FFT_MajorPeak = *(float*)um_data->u_data[4]; float volumeSmth = *(float*)um_data->u_data[0]; @@ -7178,7 +7187,7 @@ uint16_t mode_gravfreq(void) { // Gravfreq. By Andrew Tuline. if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed Gravity* gravcen = reinterpret_cast(SEGENV.data); - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); float FFT_MajorPeak = *(float*)um_data->u_data[4]; float volumeSmth = *(float*)um_data->u_data[0]; if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; // log10(0) is "forbidden" (throws exception) @@ -7221,7 +7230,7 @@ static const char _data_FX_MODE_GRAVFREQ[] PROGMEM = "Gravfreq@Rate of fall,Sens // ** Noisemove // ////////////////////// uint16_t mode_noisemove(void) { // Noisemove. By: Andrew Tuline - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; int fadeoutDelay = (256 - SEGMENT.speed) / 96; @@ -7244,7 +7253,7 @@ static const char _data_FX_MODE_NOISEMOVE[] PROGMEM = "Noisemove@Speed of perlin // ** Rocktaves // ////////////////////// uint16_t mode_rocktaves(void) { // Rocktaves. Same note from each octave is same colour. By: Andrew Tuline - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); float FFT_MajorPeak = *(float*) um_data->u_data[4]; float my_magnitude = *(float*) um_data->u_data[5] / 16.0f; @@ -7282,7 +7291,7 @@ static const char _data_FX_MODE_ROCKTAVES[] PROGMEM = "Rocktaves@;!,!;!;01f;m12= uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tuline // effect can work on single pixels, we just lose the shifting effect - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); uint8_t samplePeak = *(uint8_t*)um_data->u_data[3]; float FFT_MajorPeak = *(float*) um_data->u_data[4]; uint8_t *maxVol = (uint8_t*)um_data->u_data[6]; @@ -7337,7 +7346,7 @@ uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma. 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 - um_data_t *um_data = usermods.getAudioData(); + um_data_t *um_data = getAudioData(); uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; if (SEGENV.call == 0) for (int i=0; iu_data[2]; if (SEGENV.call == 0) { diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 3f0e63338..d95b8ef8e 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -326,7 +326,6 @@ class UsermodManager { 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 - um_data_t *getAudioData(); void setup(); void connected(); void appendConfigData(); diff --git a/wled00/um_manager.cpp b/wled00/um_manager.cpp index 3add18f39..2db29c3cd 100644 --- a/wled00/um_manager.cpp +++ b/wled00/um_manager.cpp @@ -23,14 +23,6 @@ bool UsermodManager::getUMData(um_data_t **data, uint8_t mod_id) { } return false; } -um_data_t* UsermodManager::getAudioData() { - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - // add support for no audio - um_data = simulateSound(SEGMENT.soundSim); - } - return um_data; -} void UsermodManager::addToJsonState(JsonObject& obj) { for (unsigned i = 0; i < numMods; i++) ums[i]->addToJsonState(obj); } void UsermodManager::addToJsonInfo(JsonObject& obj) { for (unsigned i = 0; i < numMods; i++) ums[i]->addToJsonInfo(obj); } void UsermodManager::readFromJsonState(JsonObject& obj) { for (unsigned i = 0; i < numMods; i++) ums[i]->readFromJsonState(obj); } From ee1bf1c221d222b225cc85c186e7e4647e2846d0 Mon Sep 17 00:00:00 2001 From: FreakyJ Date: Thu, 15 Aug 2024 20:18:06 +0200 Subject: [PATCH 13/16] #3809 Loxone JSON parser doesn't handle lx=0 correctly --- wled00/json.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/json.cpp b/wled00/json.cpp index 895709680..670a38d13 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -197,11 +197,11 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) // lx parser #ifdef WLED_ENABLE_LOXONE int lx = elem[F("lx")] | -1; - if (lx > 0) { + if (lx >= 0) { parseLxJson(lx, id, false); } int ly = elem[F("ly")] | -1; - if (ly > 0) { + if (ly >= 0) { parseLxJson(ly, id, true); } #endif From 8d00e4d31d49f14b18d7cbe92584ada534c38ccb Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sat, 17 Aug 2024 15:09:41 +0200 Subject: [PATCH 14/16] Save some tiny amounts of RAM - use `-D WLED_SAVE_RAM` --- wled00/FX.h | 9 +++ wled00/FX_fcn.cpp | 6 +- wled00/cfg.cpp | 24 ++++--- wled00/e131.cpp | 8 +-- wled00/json.cpp | 8 +-- wled00/set.cpp | 8 ++- wled00/wled.h | 180 ++++++++++++++++++++++++++++++++++++++-------- wled00/xml.cpp | 9 +-- 8 files changed, 196 insertions(+), 56 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 276a16703..6a1ae1b6b 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -720,6 +720,9 @@ class WS2812FX { // 96 bytes #ifndef WLED_DISABLE_2D panels(1), #endif + autoSegments(false), + correctWB(false), + cctFromRgb(false), // semi-private (just obscured) used in effect functions through macros _colors_t{0,0,0}, _virtualSegmentLength(0), @@ -908,6 +911,12 @@ class WS2812FX { // 96 bytes void loadCustomPalettes(void); // loads custom palettes from JSON std::vector customPalettes; // TODO: move custom palettes out of WS2812FX class + struct { + bool autoSegments : 1; + bool correctWB : 1; + 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) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 0608f6784..c6c0dad4d 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1028,9 +1028,9 @@ void Segment::refreshLightCapabilities() { if (bus->getStart() + bus->getLength() <= segStartIdx) continue; //uint8_t type = bus->getType(); - if (bus->hasRGB() || (cctFromRgb && bus->hasCCT())) capabilities |= SEG_CAPABILITY_RGB; - if (!cctFromRgb && bus->hasCCT()) capabilities |= SEG_CAPABILITY_CCT; - if (correctWB && (bus->hasRGB() || bus->hasCCT())) capabilities |= SEG_CAPABILITY_CCT; //white balance correction (CCT slider) + if (bus->hasRGB() || (strip.cctFromRgb && bus->hasCCT())) capabilities |= SEG_CAPABILITY_RGB; + if (!strip.cctFromRgb && bus->hasCCT()) capabilities |= SEG_CAPABILITY_CCT; + if (strip.correctWB && (bus->hasRGB() || bus->hasCCT())) capabilities |= SEG_CAPABILITY_CCT; //white balance correction (CCT slider) if (bus->hasWhite()) { unsigned aWM = Bus::getGlobalAWMode() == AW_GLOBAL_DISABLED ? bus->getAutoWhiteMode() : Bus::getGlobalAWMode(); bool whiteSlider = (aWM == RGBW_MODE_DUAL || aWM == RGBW_MODE_MANUAL_ONLY); // white slider allowed diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index a6e919dee..6c6e62a25 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -20,17 +20,19 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { //long vid = doc[F("vid")]; // 2010020 - #ifdef WLED_USE_ETHERNET +#ifdef WLED_USE_ETHERNET JsonObject ethernet = doc[F("eth")]; CJSON(ethernetType, ethernet["type"]); // NOTE: Ethernet configuration takes priority over other use of pins WLED::instance().initEthernet(); - #endif +#endif JsonObject id = doc["id"]; getStringFromJson(cmDNS, id[F("mdns")], 33); getStringFromJson(serverDescription, id[F("name")], 33); +#ifndef WLED_DISABLE_ALEXA getStringFromJson(alexaInvocationName, id[F("inv")], 33); +#endif CJSON(simplifiedUI, id[F("sui")]); JsonObject nw = doc["nw"]; @@ -109,8 +111,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { uint16_t ablMilliampsMax = hw_led[F("maxpwr")] | BusManager::ablMilliampsMax(); BusManager::setMilliampsMax(ablMilliampsMax); Bus::setGlobalAWMode(hw_led[F("rgbwm")] | AW_GLOBAL_DISABLED); - CJSON(correctWB, hw_led["cct"]); - CJSON(cctFromRgb, hw_led[F("cr")]); + CJSON(strip.correctWB, hw_led["cct"]); + CJSON(strip.cctFromRgb, hw_led[F("cr")]); CJSON(cctICused, hw_led[F("ic")]); CJSON(strip.cctBlending, hw_led[F("cb")]); Bus::setCCTBlend(strip.cctBlending); @@ -431,7 +433,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { JsonObject light = doc[F("light")]; CJSON(briMultiplier, light[F("scale-bri")]); CJSON(strip.paletteBlend, light[F("pal-mode")]); - CJSON(autoSegments, light[F("aseg")]); + CJSON(strip.autoSegments, light[F("aseg")]); CJSON(gammaCorrectVal, light["gc"]["val"]); // default 2.8 float light_gc_bri = light["gc"]["bri"]; @@ -530,12 +532,12 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { CJSON(arlsDisableGammaCorrection, if_live[F("no-gc")]); // false CJSON(arlsOffset, if_live[F("offset")]); // 0 +#ifndef WLED_DISABLE_ALEXA CJSON(alexaEnabled, interfaces["va"][F("alexa")]); // false - CJSON(macroAlexaOn, interfaces["va"]["macros"][0]); CJSON(macroAlexaOff, interfaces["va"]["macros"][1]); - CJSON(alexaNumPresets, interfaces["va"]["p"]); +#endif #ifndef WLED_DISABLE_MQTT JsonObject if_mqtt = interfaces["mqtt"]; @@ -739,7 +741,9 @@ void serializeConfig() { JsonObject id = root.createNestedObject("id"); id[F("mdns")] = cmDNS; id[F("name")] = serverDescription; +#ifndef WLED_DISABLE_ALEXA id[F("inv")] = alexaInvocationName; +#endif id[F("sui")] = simplifiedUI; JsonObject nw = root.createNestedObject("nw"); @@ -818,8 +822,8 @@ void serializeConfig() { hw_led[F("total")] = strip.getLengthTotal(); //provided for compatibility on downgrade and per-output ABL hw_led[F("maxpwr")] = BusManager::ablMilliampsMax(); hw_led[F("ledma")] = 0; // no longer used - hw_led["cct"] = correctWB; - hw_led[F("cr")] = cctFromRgb; + hw_led["cct"] = strip.correctWB; + hw_led[F("cr")] = strip.cctFromRgb; hw_led[F("ic")] = cctICused; hw_led[F("cb")] = strip.cctBlending; hw_led["fps"] = strip.getTargetFps(); @@ -931,7 +935,7 @@ void serializeConfig() { JsonObject light = root.createNestedObject(F("light")); light[F("scale-bri")] = briMultiplier; light[F("pal-mode")] = strip.paletteBlend; - light[F("aseg")] = autoSegments; + light[F("aseg")] = strip.autoSegments; JsonObject light_gc = light.createNestedObject("gc"); light_gc["bri"] = (gammaCorrectBri) ? gammaCorrectVal : 1.0f; // keep compatibility diff --git a/wled00/e131.cpp b/wled00/e131.cpp index 2d172e072..e28750db3 100644 --- a/wled00/e131.cpp +++ b/wled00/e131.cpp @@ -56,9 +56,9 @@ void handleDDPPacket(e131_packet_t* p) { //E1.31 and Art-Net protocol support void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){ - unsigned uni = 0, dmxChannels = 0; + int uni = 0, dmxChannels = 0; uint8_t* e131_data = nullptr; - unsigned seq = 0, mde = REALTIME_MODE_E131; + int seq = 0, mde = REALTIME_MODE_E131; if (protocol == P_ARTNET) { @@ -179,7 +179,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){ if (uni != e131Universe || availDMXLen < 2) return; // limit max. selectable preset to 250, even though DMX max. val is 255 - unsigned dmxValPreset = (e131_data[dataOffset+1] > 250 ? 250 : e131_data[dataOffset+1]); + int dmxValPreset = (e131_data[dataOffset+1] > 250 ? 250 : e131_data[dataOffset+1]); // only apply preset if value changed if (dmxValPreset != 0 && dmxValPreset != currentPreset && @@ -254,7 +254,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){ // Set segment opacity or global brightness if (isSegmentMode) { if (e131_data[dataOffset] != seg.opacity) seg.setOpacity(e131_data[dataOffset]); - } else if ( id == strip.getSegmentsNum()-1 ) { + } else if ( id == strip.getSegmentsNum()-1U ) { if (bri != e131_data[dataOffset]) { bri = e131_data[dataOffset]; strip.setBrightness(bri, true); diff --git a/wled00/json.cpp b/wled00/json.cpp index 670a38d13..01acc7ba3 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -37,14 +37,14 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) 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); - unsigned start = elem["start"] | seg.start; + int start = elem["start"] | seg.start; if (stop < 0) { int len = elem["len"]; stop = (len > 0) ? start + len : seg.stop; } // 2D segments - unsigned startY = elem["startY"] | seg.startY; - unsigned stopY = elem["stopY"] | seg.stopY; + int startY = elem["startY"] | seg.startY; + int stopY = elem["stopY"] | seg.stopY; //repeat, multiplies segment until all LEDs are used, or max segments reached bool repeat = elem["rpt"] | false; @@ -105,7 +105,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) uint8_t set = elem[F("set")] | seg.set; seg.set = constrain(set, 0, 3); - unsigned len = 1; + int len = 1; if (stop > start) len = stop - start; int offset = elem[F("of")] | INT32_MAX; if (offset != INT32_MAX) { diff --git a/wled00/set.cpp b/wled00/set.cpp index 5eecb5c9a..87323407e 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -130,9 +130,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) unsigned ablMilliampsMax = request->arg(F("MA")).toInt(); BusManager::setMilliampsMax(ablMilliampsMax); - autoSegments = request->hasArg(F("MS")); - correctWB = request->hasArg(F("CCT")); - cctFromRgb = request->hasArg(F("CR")); + strip.autoSegments = request->hasArg(F("MS")); + strip.correctWB = request->hasArg(F("CCT")); + strip.cctFromRgb = request->hasArg(F("CR")); cctICused = request->hasArg(F("IC")); strip.cctBlending = request->arg(F("CB")).toInt(); Bus::setCCTBlend(strip.cctBlending); @@ -421,10 +421,12 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) t = request->arg(F("WO")).toInt(); if (t >= -255 && t <= 255) arlsOffset = t; + #ifndef WLED_DISABLE_ALEXA alexaEnabled = request->hasArg(F("AL")); strlcpy(alexaInvocationName, request->arg(F("AI")).c_str(), 33); t = request->arg(F("AP")).toInt(); if (t >= 0 && t <= 9) alexaNumPresets = t; + #endif #ifndef WLED_DISABLE_MQTT mqttEnabled = request->hasArg(F("MQ")); diff --git a/wled00/wled.h b/wled00/wled.h index b381a8a16..b9e675edc 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -321,19 +321,53 @@ WLED_GLOBAL bool rlyOpenDrain _INIT(RLYODRAIN); 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) -WLED_GLOBAL uint8_t selectedWiFi _INIT(0); WLED_GLOBAL std::vector multiWiFi; WLED_GLOBAL IPAddress dnsAddress _INIT_N((( 8, 8, 8, 8))); // Google's DNS WLED_GLOBAL char cmDNS[33] _INIT(MDNS_NAME); // mDNS address (*.local, replaced by wledXXXXXX if default is used) WLED_GLOBAL char apSSID[33] _INIT(""); // AP off by default (unless setup) +#ifdef WLED_SAVE_RAM +typedef class WiFiOptions { + public: + struct { + uint8_t selectedWiFi : 4; // max 16 SSIDs + uint8_t apChannel : 4; + bool apHide : 1; + uint8_t apBehavior : 3; + bool noWifiSleep : 1; + bool force802_3g : 1; + }; + WiFiOptions(uint8_t s, uint8_t c, bool h, uint8_t b, bool sl, bool g) { + selectedWiFi = s; + apChannel = c; + apHide = h; + apBehavior = b; + noWifiSleep = sl; + force802_3g = g; + } +} __attribute__ ((aligned(1), packed)) wifi_options_t; + #ifdef ARDUINO_ARCH_ESP32 +WLED_GLOBAL wifi_options_t wifiOpt _INIT_N(({0, 1, false, AP_BEHAVIOR_BOOT_NO_CONN, true, false})); + #else +WLED_GLOBAL wifi_options_t wifiOpt _INIT_N(({0, 1, false, AP_BEHAVIOR_BOOT_NO_CONN, false, false})); + #endif +#define selectedWiFi wifiOpt.selectedWiFi +#define apChannel wifiOpt.apChannel +#define apHide wifiOpt.apHide +#define apBehavior wifiOpt.apBehavior +#define noWifiSleep wifiOpt.noWifiSleep +#define force802_3g wifiOpt.force802_3g +#else +WLED_GLOBAL uint8_t selectedWiFi _INIT(0); WLED_GLOBAL byte apChannel _INIT(1); // 2.4GHz WiFi AP channel (1-13) WLED_GLOBAL byte apHide _INIT(0); // hidden AP SSID WLED_GLOBAL byte apBehavior _INIT(AP_BEHAVIOR_BOOT_NO_CONN); // access point opens when no connection after boot by default -#ifdef ARDUINO_ARCH_ESP32 + #ifdef ARDUINO_ARCH_ESP32 WLED_GLOBAL bool noWifiSleep _INIT(true); // disabling modem sleep modes will increase heat output and power usage, but may help with connection issues -#else + #else WLED_GLOBAL bool noWifiSleep _INIT(false); -#endif + #endif +WLED_GLOBAL bool force802_3g _INIT(false); +#endif // WLED_SAVE_RAM #ifdef ARDUINO_ARCH_ESP32 #if defined(LOLIN_WIFI_FIX) && (defined(ARDUINO_ARCH_ESP32C3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32S3)) WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_8_5dBm); @@ -341,7 +375,6 @@ WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_8_5dBm); WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_19_5dBm); #endif #endif -WLED_GLOBAL bool force802_3g _INIT(false); #define WLED_WIFI_CONFIGURED (strlen(multiWiFi[0].clientSSID) >= 1 && strcmp(multiWiFi[0].clientSSID, DEFAULT_CLIENT_SSID) != 0) #ifdef WLED_USE_ETHERNET @@ -359,14 +392,11 @@ WLED_GLOBAL byte bootPreset _INIT(0); // save preset to load //if true, a segment per bus will be created on boot and LED settings save //if false, only one segment spanning the total LEDs is created, //but not on LED settings save if there is more than one segment currently -WLED_GLOBAL bool autoSegments _INIT(false); #ifdef ESP8266 WLED_GLOBAL bool useGlobalLedBuffer _INIT(false); // double buffering disabled on ESP8266 #else WLED_GLOBAL bool useGlobalLedBuffer _INIT(true); // double buffering enabled on ESP32 #endif -WLED_GLOBAL bool correctWB _INIT(false); // CCT color correction of RGB color -WLED_GLOBAL bool cctFromRgb _INIT(false); // CCT is calculated from RGB instead of using seg.cct #ifdef WLED_USE_IC_CCT WLED_GLOBAL bool cctICused _INIT(true); // CCT IC used (Athom 15W bulbs) #else @@ -378,7 +408,6 @@ WLED_GLOBAL float gammaCorrectVal _INIT(2.8f); // gamma correction value WLED_GLOBAL byte col[] _INIT_N(({ 255, 160, 0, 0 })); // current RGB(W) primary color. col[] should be updated if you want to change the color. WLED_GLOBAL byte colSec[] _INIT_N(({ 0, 0, 0, 0 })); // current RGB(W) secondary color -WLED_GLOBAL byte briS _INIT(128); // default brightness WLED_GLOBAL byte nightlightTargetBri _INIT(0); // brightness after nightlight is over WLED_GLOBAL byte nightlightDelayMins _INIT(60); @@ -406,30 +435,14 @@ WLED_GLOBAL byte irEnabled _INIT(IRTYPE); // Infrared receiver #endif WLED_GLOBAL bool irApplyToAllSelected _INIT(true); //apply IR or ESP-NOW to all selected segments -WLED_GLOBAL uint16_t udpPort _INIT(21324); // WLED notifier default port -WLED_GLOBAL uint16_t udpPort2 _INIT(65506); // WLED notifier supplemental port -WLED_GLOBAL uint16_t udpRgbPort _INIT(19446); // Hyperion port - -WLED_GLOBAL uint8_t syncGroups _INIT(0x01); // sync groups this instance syncs (bit mapped) -WLED_GLOBAL uint8_t receiveGroups _INIT(0x01); // sync receive groups this instance belongs to (bit mapped) -WLED_GLOBAL bool receiveNotificationBrightness _INIT(true); // apply brightness from incoming notifications -WLED_GLOBAL bool receiveNotificationColor _INIT(true); // apply color -WLED_GLOBAL bool receiveNotificationEffects _INIT(true); // apply effects setup -WLED_GLOBAL bool receiveSegmentOptions _INIT(false); // apply segment options -WLED_GLOBAL bool receiveSegmentBounds _INIT(false); // apply segment bounds (start, stop, offset) -WLED_GLOBAL bool notifyDirect _INIT(false); // send notification if change via UI or HTTP API -WLED_GLOBAL bool notifyButton _INIT(false); // send if updated by button or infrared remote -WLED_GLOBAL bool notifyAlexa _INIT(false); // send notification if updated via Alexa -WLED_GLOBAL bool notifyHue _INIT(true); // send notification if Hue light changes -WLED_GLOBAL uint8_t udpNumRetries _INIT(0); // Number of times a UDP sync message is retransmitted. Increase to increase reliability - +#ifndef WLED_DISABLE_ALEXA WLED_GLOBAL bool alexaEnabled _INIT(false); // enable device discovery by Amazon Echo WLED_GLOBAL char alexaInvocationName[33] _INIT("Light"); // speech control name of device. Choose something voice-to-text can understand WLED_GLOBAL byte alexaNumPresets _INIT(0); // number of presets to expose to Alexa, starting from preset 1, up to 9 +#endif WLED_GLOBAL uint16_t realtimeTimeoutMs _INIT(2500); // ms timeout of realtime mode before returning to normal mode WLED_GLOBAL int arlsOffset _INIT(0); // realtime LED offset -WLED_GLOBAL bool receiveDirect _INIT(true); // receive UDP/Hyperion realtime WLED_GLOBAL bool arlsDisableGammaCorrection _INIT(true); // activate if gamma correction is handled by the source WLED_GLOBAL bool arlsForceMaxBri _INIT(false); // enable to force max brightness if source has very dark colors that would be black @@ -587,6 +600,7 @@ WLED_GLOBAL byte colNlT[] _INIT_N(({ 0, 0, 0, 0 })); // current nightligh // brightness WLED_GLOBAL unsigned long lastOnTime _INIT(0); WLED_GLOBAL bool offMode _INIT(!turnOnAtBoot); +WLED_GLOBAL byte briS _INIT(128); // default brightness WLED_GLOBAL byte bri _INIT(briS); // global brightness (set) WLED_GLOBAL byte briOld _INIT(0); // global brightness while in transition loop (previous iteration) WLED_GLOBAL byte briT _INIT(0); // global brightness during transition @@ -610,6 +624,77 @@ WLED_GLOBAL bool sendNotificationsRT _INIT(false); // master notifica WLED_GLOBAL unsigned long notificationSentTime _INIT(0); WLED_GLOBAL byte notificationSentCallMode _INIT(CALL_MODE_INIT); WLED_GLOBAL uint8_t notificationCount _INIT(0); +WLED_GLOBAL uint8_t syncGroups _INIT(0x01); // sync send groups this instance syncs to (bit mapped) +WLED_GLOBAL uint8_t receiveGroups _INIT(0x01); // sync receive groups this instance belongs to (bit mapped) +#ifdef WLED_SAVE_RAM +// this will save us 8 bytes of RAM while increasing code by ~400 bytes +typedef class Receive { + public: + union { + uint8_t Options; + struct { + bool Brightness : 1; + bool Color : 1; + bool Effects : 1; + bool SegmentOptions : 1; + bool SegmentBounds : 1; + bool Direct : 1; + uint8_t reserved : 2; + }; + }; + Receive(int i) { Options = i; } + Receive(bool b, bool c, bool e, bool sO, bool sB) { + Brightness = b; + Color = c; + Effects = e; + SegmentOptions = sO; + SegmentBounds = sB; + }; +} __attribute__ ((aligned(1), packed)) receive_notification_t; +typedef class Send { + public: + union { + uint8_t Options; + struct { + bool Direct : 1; + bool Button : 1; + bool Alexa : 1; + bool Hue : 1; + uint8_t reserved : 4; + }; + }; + Send(int o) { Options = o; } + Send(bool d, bool b, bool a, bool h) { + Direct = d; + Button = b; + Alexa = a; + Hue = h; + } +} __attribute__ ((aligned(1), packed)) send_notification_t; +WLED_GLOBAL receive_notification_t receiveN _INIT(0b00100111); +WLED_GLOBAL send_notification_t notifyG _INIT(0b00001111); +#define receiveNotificationBrightness receiveN.Brightness +#define receiveNotificationColor receiveN.Color +#define receiveNotificationEffects receiveN.Effects +#define receiveSegmentOptions receiveN.SegmentOptions +#define receiveSegmentBounds receiveN.SegmentBounds +#define receiveDirect receiveN.Direct +#define notifyDirect notifyG.Direct +#define notifyButton notifyG.Button +#define notifyAlexa notifyG.Alexa +#define notifyHue notifyG.Hue +#else +WLED_GLOBAL bool receiveNotificationBrightness _INIT(true); // apply brightness from incoming notifications +WLED_GLOBAL bool receiveNotificationColor _INIT(true); // apply color +WLED_GLOBAL bool receiveNotificationEffects _INIT(true); // apply effects setup +WLED_GLOBAL bool receiveSegmentOptions _INIT(false); // apply segment options +WLED_GLOBAL bool receiveSegmentBounds _INIT(false); // apply segment bounds (start, stop, offset) +WLED_GLOBAL bool receiveDirect _INIT(true); // receive UDP/Hyperion realtime +WLED_GLOBAL bool notifyDirect _INIT(false); // send notification if change via UI or HTTP API +WLED_GLOBAL bool notifyButton _INIT(false); // send if updated by button or infrared remote +WLED_GLOBAL bool notifyAlexa _INIT(false); // send notification if updated via Alexa +WLED_GLOBAL bool notifyHue _INIT(true); // send notification if Hue light changes +#endif // effects WLED_GLOBAL byte effectCurrent _INIT(0); @@ -619,7 +704,46 @@ WLED_GLOBAL byte effectPalette _INIT(0); WLED_GLOBAL bool stateChanged _INIT(false); // network -WLED_GLOBAL bool udpConnected _INIT(false), udp2Connected _INIT(false), udpRgbConnected _INIT(false); +#ifdef WLED_SAVE_RAM +// this will save us 2 bytes of RAM while increasing code by ~400 bytes +typedef class Udp { + public: + uint16_t Port; + uint16_t Port2; + uint16_t RgbPort; + struct { + uint8_t NumRetries : 5; + bool Connected : 1; + bool Connected2 : 1; + bool RgbConnected : 1; + }; + Udp(int p1, int p2, int p3, int r, bool c1, bool c2, bool c3) { + Port = p1; + Port2 = p2; + RgbPort = p3; + NumRetries = r; + Connected = c1; + Connected2 = c2; + RgbConnected = c3; + } +} __attribute__ ((aligned(1), packed)) udp_port_t; +WLED_GLOBAL udp_port_t udp _INIT_N(({21234, 65506, 19446, 0, false, false, false})); +#define udpPort udp.Port +#define udpPort2 udp.Port2 +#define udpRgbPort udp.RgbPort +#define udpNumRetries udp.NumRetries +#define udpConnected udp.Connected +#define udp2Connected udp.Connected2 +#define udpRgbConnected udp.RgbConnected +#else +WLED_GLOBAL uint16_t udpPort _INIT(21324); // WLED notifier default port +WLED_GLOBAL uint16_t udpPort2 _INIT(65506); // WLED notifier supplemental port +WLED_GLOBAL uint16_t udpRgbPort _INIT(19446); // Hyperion port +WLED_GLOBAL uint8_t udpNumRetries _INIT(0); // Number of times a UDP sync message is retransmitted. Increase to increase reliability +WLED_GLOBAL bool udpConnected _INIT(false); +WLED_GLOBAL bool udp2Connected _INIT(false); +WLED_GLOBAL bool udpRgbConnected _INIT(false); +#endif // ui style WLED_GLOBAL bool showWelcomePage _INIT(false); diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 2ae599f5d..0439b7bdc 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -361,10 +361,10 @@ void getSettingsJS(byte subPage, char* dest) oappend(itoa(WLED_MAX_ANALOG_CHANNELS,nS,10)); oappend(SET_F(");")); - sappend('c',SET_F("MS"),autoSegments); - sappend('c',SET_F("CCT"),correctWB); + 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"),cctFromRgb); + 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()); @@ -533,11 +533,12 @@ void getSettingsJS(byte subPage, char* dest) sappend('c',SET_F("FB"),arlsForceMaxBri); sappend('c',SET_F("RG"),arlsDisableGammaCorrection); sappend('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); - #ifdef WLED_DISABLE_ALEXA + #elese oappend(SET_F("toggle('Alexa');")); // hide Alexa settings #endif From 79b3ce141cf3ab014411860f06380a6aef9581eb Mon Sep 17 00:00:00 2001 From: srg74 <28492985+srg74@users.noreply.github.com> Date: Sat, 17 Aug 2024 14:42:44 -0400 Subject: [PATCH 15/16] correct spelling error xml.cpp --- wled00/xml.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 0439b7bdc..25c0c6298 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -538,7 +538,7 @@ void getSettingsJS(byte subPage, char* dest) sappends('s',SET_F("AI"),alexaInvocationName); sappend('c',SET_F("SA"),notifyAlexa); sappend('v',SET_F("AP"),alexaNumPresets); - #elese + #else oappend(SET_F("toggle('Alexa');")); // hide Alexa settings #endif From f6c47ac19cd9fc2b6b2861289b86f2ef963a329a Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sun, 18 Aug 2024 10:45:16 +0200 Subject: [PATCH 16/16] Fix some compiler warnings --- wled00/FX_2Dfcn.cpp | 10 +++++----- wled00/FX_fcn.cpp | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 0fd5bb09f..44919f925 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -185,14 +185,14 @@ void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col) x *= groupLength(); // expand to physical pixels y *= groupLength(); // expand to physical pixels - unsigned W = width(); - unsigned H = height(); + int W = width(); + int H = height(); if (x >= W || y >= H) return; // if pixel would fall out of segment just exit uint32_t tmpCol = col; - for (unsigned j = 0; j < grouping; j++) { // groupping vertically - for (unsigned g = 0; g < grouping; g++) { // groupping horizontally - unsigned xX = (x+g), yY = (y+j); + 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); if (xX >= W || yY >= H) continue; // we have reached one dimension's end #ifndef WLED_DISABLE_MODE_BLEND diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index c6c0dad4d..bc5c8b051 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -905,8 +905,8 @@ uint32_t IRAM_ATTR Segment::getPixelColor(int i) const #ifndef WLED_DISABLE_2D if (is2D()) { - unsigned vH = virtualHeight(); // segment height in logical pixels - unsigned vW = virtualWidth(); + int vH = virtualHeight(); // segment height in logical pixels + int vW = virtualWidth(); switch (map1D2D) { case M12_Pixels: return getPixelColorXY(i % vW, i / vW);