From e9b7320d1ce0b21170741c1c7fc3143bf0d5b824 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 14 Jul 2024 11:38:29 -0400 Subject: [PATCH 01/24] Add preliminary web stress test script --- tools/stress_test.sh | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 tools/stress_test.sh diff --git a/tools/stress_test.sh b/tools/stress_test.sh new file mode 100644 index 000000000..c107f789a --- /dev/null +++ b/tools/stress_test.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# Some web server stress tests +# +# Perform a large number of parallel requests, stress testing the web server +# TODO: some kind of performance metrics + + +TARGET=$1 + +JSON_TARGETS=('json/state' 'json/info' 'json/si', 'json/palettes' 'json/fxdata' 'settings/s.js?p=2') +FILE_TARGETS=('' 'iro.js' 'rangetouch.js' 'settings' 'settings/wifi') +CURL_ARGS="--compressed --parallel --parallel-immediate --parallel-max 2" + +# TODO: argument parsing + +# Test static file targets +TARGETS=(${JSON_TARGETS[@]}) +#TARGETS=(${FILE_TARGETS[@]}) + +# Expand target URLS to full arguments for curl +FULL_OPTIONS=$(printf "http://${TARGET}/%s -o /dev/null " "${TARGETS[@]}") + +#echo ${FULL_OPTIONS} +time curl ${CURL_ARGS} ${FULL_OPTIONS} From 91efcb910bc3d648044b655241ec094b19cb175e Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 14 Jul 2024 11:38:29 -0400 Subject: [PATCH 02/24] stress_test: Add a larger JSON target --- tools/stress_test.sh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tools/stress_test.sh b/tools/stress_test.sh index c107f789a..c3bdfd14d 100644 --- a/tools/stress_test.sh +++ b/tools/stress_test.sh @@ -7,15 +7,24 @@ TARGET=$1 +CURL_ARGS="--compressed --parallel --parallel-immediate --parallel-max 50" + JSON_TARGETS=('json/state' 'json/info' 'json/si', 'json/palettes' 'json/fxdata' 'settings/s.js?p=2') FILE_TARGETS=('' 'iro.js' 'rangetouch.js' 'settings' 'settings/wifi') -CURL_ARGS="--compressed --parallel --parallel-immediate --parallel-max 2" + +# Replicate one target many times +function replicate() { + printf "${1}?%d " {1..8} +} +read -a JSON_LARGE_TARGETS <<< $(replicate "json/si") +read -a JSON_LARGER_TARGETS <<< $(replicate "json/fxdata") # TODO: argument parsing # Test static file targets -TARGETS=(${JSON_TARGETS[@]}) +#TARGETS=(${JSON_TARGETS[@]}) #TARGETS=(${FILE_TARGETS[@]}) +TARGETS=(${JSON_LARGER_TARGETS[@]}) # Expand target URLS to full arguments for curl FULL_OPTIONS=$(printf "http://${TARGET}/%s -o /dev/null " "${TARGETS[@]}") From abcd2a2d01146c84ceb5ffd485d4d0cd80d41543 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 14 Jul 2024 11:38:29 -0400 Subject: [PATCH 03/24] tools/stress_test: Allow command line target spec --- tools/stress_test.sh | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/tools/stress_test.sh b/tools/stress_test.sh index c3bdfd14d..31a0469f9 100644 --- a/tools/stress_test.sh +++ b/tools/stress_test.sh @@ -4,14 +4,16 @@ # Perform a large number of parallel requests, stress testing the web server # TODO: some kind of performance metrics - -TARGET=$1 +# Accepts two command line arguments: +# - first argument - mandatory - IP or hostname of target server +# - second argument - targert type +HOST=$1 +declare -n TARGET_STR="${2:-JSON_LARGER}_TARGETS" CURL_ARGS="--compressed --parallel --parallel-immediate --parallel-max 50" JSON_TARGETS=('json/state' 'json/info' 'json/si', 'json/palettes' 'json/fxdata' 'settings/s.js?p=2') FILE_TARGETS=('' 'iro.js' 'rangetouch.js' 'settings' 'settings/wifi') - # Replicate one target many times function replicate() { printf "${1}?%d " {1..8} @@ -19,15 +21,10 @@ function replicate() { read -a JSON_LARGE_TARGETS <<< $(replicate "json/si") read -a JSON_LARGER_TARGETS <<< $(replicate "json/fxdata") -# TODO: argument parsing - -# Test static file targets -#TARGETS=(${JSON_TARGETS[@]}) -#TARGETS=(${FILE_TARGETS[@]}) -TARGETS=(${JSON_LARGER_TARGETS[@]}) - # Expand target URLS to full arguments for curl -FULL_OPTIONS=$(printf "http://${TARGET}/%s -o /dev/null " "${TARGETS[@]}") +TARGETS=(${TARGET_STR[@]}) +#echo "${TARGETS[@]}" +FULL_TGT_OPTIONS=$(printf "http://${HOST}/%s -o /dev/null " "${TARGETS[@]}") +#echo ${FULL_TGT_OPTIONS} -#echo ${FULL_OPTIONS} -time curl ${CURL_ARGS} ${FULL_OPTIONS} +time curl ${CURL_ARGS} ${FULL_TGT_OPTIONS} From 0191af412bf1fa1f827646665d9bee33530f34c6 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 14 Jul 2024 11:38:29 -0400 Subject: [PATCH 04/24] stress_test: Add small JSON target Good for measuring quick response performance --- tools/stress_test.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/stress_test.sh b/tools/stress_test.sh index 31a0469f9..4ea672405 100644 --- a/tools/stress_test.sh +++ b/tools/stress_test.sh @@ -10,7 +10,9 @@ HOST=$1 declare -n TARGET_STR="${2:-JSON_LARGER}_TARGETS" -CURL_ARGS="--compressed --parallel --parallel-immediate --parallel-max 50" +PARALLEL_MAX=${PARALLEL_MAX:-50} + +CURL_ARGS="--compressed --parallel --parallel-immediate --parallel-max ${PARALLEL_MAX}" JSON_TARGETS=('json/state' 'json/info' 'json/si', 'json/palettes' 'json/fxdata' 'settings/s.js?p=2') FILE_TARGETS=('' 'iro.js' 'rangetouch.js' 'settings' 'settings/wifi') @@ -18,6 +20,7 @@ FILE_TARGETS=('' 'iro.js' 'rangetouch.js' 'settings' 'settings/wifi') function replicate() { printf "${1}?%d " {1..8} } +read -a JSON_SMALL_TARGETS <<< $(replicate "json/info") read -a JSON_LARGE_TARGETS <<< $(replicate "json/si") read -a JSON_LARGER_TARGETS <<< $(replicate "json/fxdata") From 541d3f286afab91b21c1468f82471883f45315ac Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 14 Jul 2024 11:38:29 -0400 Subject: [PATCH 05/24] stress_test: Make it worse Read 40 copies! --- tools/stress_test.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/stress_test.sh b/tools/stress_test.sh index 4ea672405..0a11c4332 100644 --- a/tools/stress_test.sh +++ b/tools/stress_test.sh @@ -18,8 +18,9 @@ JSON_TARGETS=('json/state' 'json/info' 'json/si', 'json/palettes' 'json/fxdata' FILE_TARGETS=('' 'iro.js' 'rangetouch.js' 'settings' 'settings/wifi') # Replicate one target many times function replicate() { - printf "${1}?%d " {1..8} + printf "${1}?%d " {1..40} } +read -a JSON_TINY_TARGETS <<< $(replicate "json/nodes") read -a JSON_SMALL_TARGETS <<< $(replicate "json/info") read -a JSON_LARGE_TARGETS <<< $(replicate "json/si") read -a JSON_LARGER_TARGETS <<< $(replicate "json/fxdata") From 5a6ebd665787b66e94719dacf2e82d07f2c0ce6e Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 14 Jul 2024 11:38:29 -0400 Subject: [PATCH 06/24] stress_test: Allow replication argument --- tools/stress_test.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/stress_test.sh b/tools/stress_test.sh index 0a11c4332..fe25f3b4e 100644 --- a/tools/stress_test.sh +++ b/tools/stress_test.sh @@ -4,11 +4,13 @@ # Perform a large number of parallel requests, stress testing the web server # TODO: some kind of performance metrics -# Accepts two command line arguments: +# Accepts three command line arguments: # - first argument - mandatory - IP or hostname of target server -# - second argument - targert type +# - second argument - target type (optional) +# - third argument - xfer count (for replicated targets) (optional) HOST=$1 declare -n TARGET_STR="${2:-JSON_LARGER}_TARGETS" +REPLICATE_COUNT=$(("${3:-10}")) PARALLEL_MAX=${PARALLEL_MAX:-50} @@ -18,7 +20,7 @@ JSON_TARGETS=('json/state' 'json/info' 'json/si', 'json/palettes' 'json/fxdata' FILE_TARGETS=('' 'iro.js' 'rangetouch.js' 'settings' 'settings/wifi') # Replicate one target many times function replicate() { - printf "${1}?%d " {1..40} + printf "${1}?%d " $(seq 1 ${REPLICATE_COUNT}) } read -a JSON_TINY_TARGETS <<< $(replicate "json/nodes") read -a JSON_SMALL_TARGETS <<< $(replicate "json/info") From 509cbdf476c258aa2eb5900310ea899f886ce025 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 14 Jul 2024 11:38:29 -0400 Subject: [PATCH 07/24] Add UDP test code Courtesy of @_tvk_ on Discord --- tools/udp_test.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tools/udp_test.py diff --git a/tools/udp_test.py b/tools/udp_test.py new file mode 100644 index 000000000..c4c9129cf --- /dev/null +++ b/tools/udp_test.py @@ -0,0 +1,46 @@ +import numpy as np +import socket + +class WledRealtimeClient: + def __init__(self, wled_controller_ip, num_pixels, udp_port=21324, max_pixels_per_packet=126): + self.wled_controller_ip = wled_controller_ip + self.num_pixels = num_pixels + self.udp_port = udp_port + self.max_pixels_per_packet = max_pixels_per_packet + self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self._prev_pixels = np.full((3, self.num_pixels), 253, dtype=np.uint8) + self.pixels = np.full((3, self.num_pixels), 1, dtype=np.uint8) + + def update(self): + # Truncate values and cast to integer + self.pixels = np.clip(self.pixels, 0, 255).astype(np.uint8) + p = np.copy(self.pixels) + + idx = np.where(~np.all(p == self._prev_pixels, axis=0))[0] + num_pixels = len(idx) + n_packets = (num_pixels + self.max_pixels_per_packet - 1) // self.max_pixels_per_packet + idx_split = np.array_split(idx, n_packets) + + header = bytes([1, 2]) # WARLS protocol header + for packet_indices in idx_split: + data = bytearray(header) + for i in packet_indices: + data.extend([i, *p[:, i]]) # Index and RGB values + self._sock.sendto(bytes(data), (self.wled_controller_ip, self.udp_port)) + + self._prev_pixels = np.copy(p) + + + +################################## LED blink test ################################## +if __name__ == "__main__": + WLED_CONTROLLER_IP = "192.168.1.153" + NUM_PIXELS = 255 # Amount of LEDs on your strip + import time + wled = WledRealtimeClient(WLED_CONTROLLER_IP, NUM_PIXELS) + print('Starting LED blink test') + while True: + for i in range(NUM_PIXELS): + wled.pixels[1, i] = 255 if wled.pixels[1, i] == 0 else 0 + wled.update() + time.sleep(.01) From 5582bbac6068b03d6ec68c94c6e7035a6a35f72c Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 14 Jul 2024 11:38:29 -0400 Subject: [PATCH 08/24] stress_test: Add code for logging responses --- tools/stress_test.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/stress_test.sh b/tools/stress_test.sh index fe25f3b4e..d7c344c58 100644 --- a/tools/stress_test.sh +++ b/tools/stress_test.sh @@ -15,6 +15,7 @@ REPLICATE_COUNT=$(("${3:-10}")) PARALLEL_MAX=${PARALLEL_MAX:-50} CURL_ARGS="--compressed --parallel --parallel-immediate --parallel-max ${PARALLEL_MAX}" +CURL_PRINT_RESPONSE_ARGS="-w %{http_code}\n" JSON_TARGETS=('json/state' 'json/info' 'json/si', 'json/palettes' 'json/fxdata' 'settings/s.js?p=2') FILE_TARGETS=('' 'iro.js' 'rangetouch.js' 'settings' 'settings/wifi') From 6f01896d0443d3cb4029fc4b8c7167bd66d2c3b4 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 4 Aug 2024 14:02:05 -0400 Subject: [PATCH 09/24] requestJSONBufferLock: Fix locking implementation On ESP8266, it isn't permissible to call delay() in system context; ensure this is legal before waiting. On ESP32, use an operating system mutex to ensure consistent variable state in a multicore environment, and manage the wait without needing to loop. --- wled00/util.cpp | 27 +++++++++++++++++++++++---- wled00/wled.h | 1 + 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/wled00/util.cpp b/wled00/util.cpp index 6bc02234b..d2302a085 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -213,15 +213,31 @@ bool requestJSONBufferLock(uint8_t module) DEBUG_PRINTLN(F("ERROR: JSON buffer not allocated!")); return false; } - unsigned long now = millis(); - - while (jsonBufferLock && millis()-now < 250) delay(1); // wait for fraction for buffer lock +#if defined(ARDUINO_ARCH_ESP32) + // Use a recursive mutex type in case our task is the one holding the JSON buffer. + // This can happen during large JSON web transactions. In this case, we continue immediately + // and then will return out below if the lock is still held. + if (xSemaphoreTakeRecursive(jsonBufferLockMutex, 250) == pdFALSE) return false; // timed out waiting +#elif defined(ARDUINO_ARCH_ESP8266) + // If we're in system context, delay() won't return control to the user context, so there's + // no point in waiting. + if (can_yield()) { + unsigned long now = millis(); + while (jsonBufferLock && (millis()-now < 250)) delay(1); // wait for fraction for buffer lock + } +#else + #error Unsupported task framework - fix requestJSONBufferLock +#endif + // If the lock is still held - by us, or by another task if (jsonBufferLock) { DEBUG_PRINT(F("ERROR: Locking JSON buffer failed! (still locked by ")); DEBUG_PRINT(jsonBufferLock); DEBUG_PRINTLN(")"); - return false; // waiting time-outed +#ifdef ARDUINO_ARCH_ESP32 + xSemaphoreGiveRecursive(jsonBufferLockMutex); +#endif + return false; } jsonBufferLock = module ? module : 255; @@ -239,6 +255,9 @@ void releaseJSONBufferLock() DEBUG_PRINT(jsonBufferLock); DEBUG_PRINTLN(")"); jsonBufferLock = 0; +#ifdef ARDUINO_ARCH_ESP32 + xSemaphoreGiveRecursive(jsonBufferLockMutex); +#endif } diff --git a/wled00/wled.h b/wled00/wled.h index f761b970d..d6915e7fb 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -810,6 +810,7 @@ WLED_GLOBAL int8_t spi_sclk _INIT(SPISCLKPIN); // global ArduinoJson buffer #if defined(ARDUINO_ARCH_ESP32) WLED_GLOBAL JsonDocument *pDoc _INIT(nullptr); +WLED_GLOBAL SemaphoreHandle_t jsonBufferLockMutex _INIT(xSemaphoreCreateRecursiveMutex()); #else WLED_GLOBAL StaticJsonDocument gDoc; WLED_GLOBAL JsonDocument *pDoc _INIT(&gDoc); From e701b5b5ebddb62e565b74ea2c45da7bc8ef8cc2 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 4 Aug 2024 14:02:05 -0400 Subject: [PATCH 10/24] util: Print locking module when JSON lock fails For debugging, also log who was trying to lock when it was contended. --- wled00/util.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wled00/util.cpp b/wled00/util.cpp index d2302a085..5d4428be4 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -231,7 +231,9 @@ bool requestJSONBufferLock(uint8_t module) #endif // If the lock is still held - by us, or by another task if (jsonBufferLock) { - DEBUG_PRINT(F("ERROR: Locking JSON buffer failed! (still locked by ")); + DEBUG_PRINT(F("ERROR: Locking JSON buffer (")); + DEBUG_PRINT(module); + DEBUG_PRINT(F(") failed! (still locked by ")); DEBUG_PRINT(jsonBufferLock); DEBUG_PRINTLN(")"); #ifdef ARDUINO_ARCH_ESP32 From 113dbbdf94f9f5b7bc0d007bb4cd7fe7af9b5c2d Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 4 Aug 2024 15:08:46 -0400 Subject: [PATCH 11/24] Use DEBUG_PRINTF_P for jsonBufferLock Tiny code space usage reduction. --- wled00/util.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/wled00/util.cpp b/wled00/util.cpp index 5d4428be4..86ba5b486 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -231,11 +231,7 @@ bool requestJSONBufferLock(uint8_t module) #endif // If the lock is still held - by us, or by another task if (jsonBufferLock) { - DEBUG_PRINT(F("ERROR: Locking JSON buffer (")); - DEBUG_PRINT(module); - DEBUG_PRINT(F(") failed! (still locked by ")); - DEBUG_PRINT(jsonBufferLock); - DEBUG_PRINTLN(")"); + DEBUG_PRINTF_P(PSTR("ERROR: Locking JSON buffer (%d) failed! (still locked by %d)\n"), module, jsonBufferLock); #ifdef ARDUINO_ARCH_ESP32 xSemaphoreGiveRecursive(jsonBufferLockMutex); #endif @@ -243,9 +239,7 @@ bool requestJSONBufferLock(uint8_t module) } jsonBufferLock = module ? module : 255; - DEBUG_PRINT(F("JSON buffer locked. (")); - DEBUG_PRINT(jsonBufferLock); - DEBUG_PRINTLN(")"); + DEBUG_PRINTF_P(PSTR("JSON buffer locked. (%d)\n"), jsonBufferLock); pDoc->clear(); return true; } @@ -253,9 +247,7 @@ bool requestJSONBufferLock(uint8_t module) void releaseJSONBufferLock() { - DEBUG_PRINT(F("JSON buffer released. (")); - DEBUG_PRINT(jsonBufferLock); - DEBUG_PRINTLN(")"); + DEBUG_PRINTF_P(PSTR("JSON buffer released. (%d)\n"), jsonBufferLock); jsonBufferLock = 0; #ifdef ARDUINO_ARCH_ESP32 xSemaphoreGiveRecursive(jsonBufferLockMutex); From 1d27aa2f18fb11c1eb811b703a920408524d8248 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 14 Jul 2024 11:38:29 -0400 Subject: [PATCH 12/24] 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 13/24] 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 14/24] 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 15/24] 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 bcf862044a22113207fc72a3dfe82eecf4e46dac Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 13 Aug 2024 22:21:21 +0200 Subject: [PATCH 16/24] 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 17/24] 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 18/24] 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 19/24] 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 20/24] 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 21/24] 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 22/24] 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 23/24] #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 24/24] 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