From 02cae2e61ea61a8b6f840a18ef7bacbbfcd0a8d8 Mon Sep 17 00:00:00 2001 From: jdiamond Date: Thu, 25 Jul 2024 04:47:44 +0000 Subject: [PATCH 01/10] Add example runArgs to devcountainer to access serial port. --- .devcontainer/devcontainer.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index f77dc4de4..b367752d9 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -12,6 +12,13 @@ } }, + // To give the container access to a device serial port, you can uncomment one of the following lines. + // You can explicitly forward the port. The docker user needs to be able to access this port, and this will only work + // if the device is plugged in from the start without reconnecting. + // "runArgs": ["--device=/dev/ttyACM0", "--group-add", "dialout"], + // Alternatively, you can give more comprehensive access to the host system. + // "runArgs": ["--privileged", "-v", "/dev/bus/usb:/dev/bus/usb", "--group-add", "dialout"], + // Set *default* container specific settings.json values on container create. "settings": { "terminal.integrated.shell.linux": "/bin/bash", From 343d766ddd6336722d14ab229f80fb03e2685316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Schr=C3=B6ter?= Date: Wed, 7 Feb 2024 17:06:18 +0100 Subject: [PATCH 02/10] 2DGEQ: Getting same sized bar width on 32x32 display before a x=32 (n times of 16) had not equal sized bars, but first was a single pixel and later a bar had 3 pixel width. This solves it to have always 2 pixel sized bars. I have to admit that I did not test with other pixel dimensions. --- wled00/FX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index cce3098e1..9e8c80729 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7456,7 +7456,7 @@ uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma. if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fadeToBlackBy(SEGMENT.speed); for (int x=0; x < cols; x++) { - uint8_t band = map(x, 0, cols-1, 0, NUM_BANDS - 1); + uint8_t band = map(x, 0, cols, 0, NUM_BANDS); if (NUM_BANDS < 16) band = map(band, 0, NUM_BANDS - 1, 0, 15); // always use full range. comment out this line to get the previous behaviour. band = constrain(band, 0, 15); unsigned colorIndex = band * 17; From 0af1ec3bde17de01946653f0e7cef9fd1d475860 Mon Sep 17 00:00:00 2001 From: Alexey Panteleev Date: Sat, 27 Jul 2024 10:44:53 -0700 Subject: [PATCH 03/10] Added a parameter for blur amount in the Fire 2012 effect. --- wled00/FX.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 4b7f9ce36..0bdcb042f 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2106,14 +2106,17 @@ uint16_t mode_fire_2012() { for (unsigned stripNr=0; stripNr> 2; + SEGMENT.blur(blurAmount); + } if (it != SEGENV.step) SEGENV.step = it; return FRAMETIME; } -static const char _data_FX_MODE_FIRE_2012[] PROGMEM = "Fire 2012@Cooling,Spark rate,,,Boost;;!;1;sx=64,ix=160,m12=1"; // bars +static const char _data_FX_MODE_FIRE_2012[] PROGMEM = "Fire 2012@Cooling,Spark rate,,2D Blur,Boost;;!;1;sx=64,ix=160,m12=1,c2=128"; // bars // ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb From 10fdf464102fe1d415040e3604150de9af91da1e Mon Sep 17 00:00:00 2001 From: jdiamond Date: Mon, 29 Jul 2024 17:34:10 +0000 Subject: [PATCH 04/10] Clarify security implicatations. --- .devcontainer/devcontainer.json | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index b367752d9..305236c91 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -13,10 +13,16 @@ }, // To give the container access to a device serial port, you can uncomment one of the following lines. - // You can explicitly forward the port. The docker user needs to be able to access this port, and this will only work - // if the device is plugged in from the start without reconnecting. + // + // You can explicitly just forward the port you want to connect to. Replace `/dev/ttyACM0` with the serial port for + // your device. This will only work if the device is plugged in from the start without reconnecting. Adding the + // `dialout` group is needed if read/write permisions for the port are limitted to the dialout user. // "runArgs": ["--device=/dev/ttyACM0", "--group-add", "dialout"], - // Alternatively, you can give more comprehensive access to the host system. + // + // Alternatively, you can give more comprehensive access to the host system. This will expose all the host devices to + // the container. Adding the `dialout` group is needed if read/write permisions for the port are limitted to the + // dialout user. This could allow the container to modify unrelated serial devices, which would be a similar level of + // risk to running the build directly on the host. // "runArgs": ["--privileged", "-v", "/dev/bus/usb:/dev/bus/usb", "--group-add", "dialout"], // Set *default* container specific settings.json values on container create. From 050f7ebddfae349339f27c475d5e44458bb9da82 Mon Sep 17 00:00:00 2001 From: jdiamond Date: Mon, 29 Jul 2024 18:00:46 +0000 Subject: [PATCH 05/10] Add note for Windows. --- .devcontainer/devcontainer.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 305236c91..2a8e4712d 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -13,6 +13,8 @@ }, // To give the container access to a device serial port, you can uncomment one of the following lines. + // Note: If running on Windows, you will have to do some additional steps: + // https://stackoverflow.com/questions/68527888/how-can-i-use-a-usb-com-port-inside-of-a-vscode-development-container // // You can explicitly just forward the port you want to connect to. Replace `/dev/ttyACM0` with the serial port for // your device. This will only work if the device is plugged in from the start without reconnecting. Adding the From 5c247d283357895a56e51379eff07dc9a97703bf Mon Sep 17 00:00:00 2001 From: PaoloTK Date: Thu, 1 Aug 2024 20:25:18 +0200 Subject: [PATCH 06/10] first implementation --- wled00/bus_manager.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 7aa3351cf..9e16e4458 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -40,6 +40,19 @@ uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, byte #define DEBUG_PRINTF_P(x...) #endif +// ESP8266 has 1 MHz clock +#ifdef ESP8266 + #define CLOCK_FREQUENCY 1e6f +#else + // Use XTAL clock if possible to avoid timer frequency error when setting APB clock < 80 Mhz + // https://github.com/espressif/arduino-esp32/blob/2.0.2/cores/esp32/esp32-hal-ledc.c + #ifdef SOC_LEDC_SUPPORT_XTAL_CLOCK + #define CLOCK_FREQUENCY 40e6f + #else + #define CLOCK_FREQUENCY 80e6f + #endif +#endif + //color mangling macros #define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b)))) #define R(c) (byte((c) >> 16)) @@ -384,12 +397,10 @@ BusPwm::BusPwm(BusConfig &bc) if (!IS_PWM(bc.type)) return; unsigned numPins = NUM_PWM_PINS(bc.type); _frequency = bc.frequency ? bc.frequency : WLED_PWM_FREQ; + // duty cycle resolution (_depth) can be extracted from this formula: CLOCK_FREQUENCY > _frequency * 2^_depth + _depth = uint8_t(log((float)CLOCK_FREQUENCY / (float)_frequency) / log(2.0)); #ifdef ESP8266 - // duty cycle resolution (_depth) can be extracted from this formula: 1MHz > _frequency * 2^_depth - if (_frequency > 1760) _depth = 8; - else if (_frequency > 880) _depth = 9; - else _depth = 10; // WLED_PWM_FREQ <= 880Hz analogWriteRange((1<<_depth)-1); analogWriteFreq(_frequency); #else @@ -397,11 +408,6 @@ BusPwm::BusPwm(BusConfig &bc) if (_ledcStart == 255) { //no more free LEDC channels deallocatePins(); return; } - // duty cycle resolution (_depth) can be extracted from this formula: 80MHz > _frequency * 2^_depth - if (_frequency > 78124) _depth = 9; - else if (_frequency > 39062) _depth = 10; - else if (_frequency > 19531) _depth = 11; - else _depth = 12; // WLED_PWM_FREQ <= 19531Hz #endif for (unsigned i = 0; i < numPins; i++) { @@ -419,7 +425,7 @@ BusPwm::BusPwm(BusConfig &bc) } _data = _pwmdata; // avoid malloc() and use stack _valid = true; - DEBUG_PRINTF_P(PSTR("%successfully inited PWM strip with type %u and pins %u,%u,%u,%u,%u\n"), _valid?"S":"Uns", bc.type, _pins[0], _pins[1], _pins[2], _pins[3], _pins[4]); + DEBUG_PRINTF_P(PSTR("%successfully inited PWM strip with type %u, frequency %u, bit depth %u and pins %u,%u,%u,%u,%u\n"), _valid?"S":"Uns", bc.type, _frequency, _depth, _pins[0], _pins[1], _pins[2], _pins[3], _pins[4]); } void BusPwm::setPixelColor(uint16_t pix, uint32_t c) { From 1123d85fd2f828fdcfe4afc911bd7d0c91ac3249 Mon Sep 17 00:00:00 2001 From: PaoloTK Date: Sat, 3 Aug 2024 15:54:39 +0200 Subject: [PATCH 07/10] removed float math and log(), added max bit width --- wled00/bus_manager.cpp | 15 +-------------- wled00/const.h | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 9e16e4458..e626a2962 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -40,19 +40,6 @@ uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, byte #define DEBUG_PRINTF_P(x...) #endif -// ESP8266 has 1 MHz clock -#ifdef ESP8266 - #define CLOCK_FREQUENCY 1e6f -#else - // Use XTAL clock if possible to avoid timer frequency error when setting APB clock < 80 Mhz - // https://github.com/espressif/arduino-esp32/blob/2.0.2/cores/esp32/esp32-hal-ledc.c - #ifdef SOC_LEDC_SUPPORT_XTAL_CLOCK - #define CLOCK_FREQUENCY 40e6f - #else - #define CLOCK_FREQUENCY 80e6f - #endif -#endif - //color mangling macros #define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b)))) #define R(c) (byte((c) >> 16)) @@ -398,7 +385,7 @@ BusPwm::BusPwm(BusConfig &bc) unsigned numPins = NUM_PWM_PINS(bc.type); _frequency = bc.frequency ? bc.frequency : WLED_PWM_FREQ; // duty cycle resolution (_depth) can be extracted from this formula: CLOCK_FREQUENCY > _frequency * 2^_depth - _depth = uint8_t(log((float)CLOCK_FREQUENCY / (float)_frequency) / log(2.0)); + for (_depth=MAX_BIT_WIDTH; _depth>8; _depth--) if (((uint32_t(CLOCK_FREQUENCY)/_frequency)>>_depth) > 0) break; #ifdef ESP8266 analogWriteRange((1<<_depth)-1); diff --git a/wled00/const.h b/wled00/const.h index 0ff70e47d..110ef9f0d 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -521,6 +521,35 @@ #endif #endif +#ifndef CLOCK_FREQUENCY + #ifdef ESP8266 + // 1 MHz clock + #define CLOCK_FREQUENCY 1e6f + #else + // Use XTAL clock if possible to avoid timer frequency error when setting APB clock < 80 Mhz + // https://github.com/espressif/arduino-esp32/blob/2.0.2/cores/esp32/esp32-hal-ledc.c + #ifdef SOC_LEDC_SUPPORT_XTAL_CLOCK + #define CLOCK_FREQUENCY 40e6f + #else + #define CLOCK_FREQUENCY 80e6f + #endif + #endif +#endif + +#ifndef MAX_BIT_WIDTH + #ifdef ESP8266 + #define MAX_BIT_WIDTH 10 + #else + #ifdef SOC_LEDC_TIMER_BIT_WIDE_NUM + // C6/H2/P4: 20 bit, S2/S3/C2/C3: 14 bit + #define MAX_BIT_WIDTH SOC_LEDC_TIMER_BIT_WIDE_NUM + #else + // ESP32: 32 bit + #define MAX_BIT_WIDTH 20 + #endif + #endif +#endif + #define TOUCH_THRESHOLD 32 // limit to recognize a touch, higher value means more sensitive // Size of buffer for API JSON object (increase for more segments) From 779744bd8e4b8cb851d48dfe4d8164f80ed69af2 Mon Sep 17 00:00:00 2001 From: PaoloTK Date: Sat, 3 Aug 2024 15:56:29 +0200 Subject: [PATCH 08/10] typo in comment --- wled00/const.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/const.h b/wled00/const.h index 110ef9f0d..d792f592a 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -544,7 +544,7 @@ // C6/H2/P4: 20 bit, S2/S3/C2/C3: 14 bit #define MAX_BIT_WIDTH SOC_LEDC_TIMER_BIT_WIDE_NUM #else - // ESP32: 32 bit + // ESP32: 20 bit #define MAX_BIT_WIDTH 20 #endif #endif From 52548542d2f838208a8cbd05dc3c14dc19a13a31 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sun, 4 Aug 2024 17:05:47 +0200 Subject: [PATCH 09/10] Remove clock/max bit overrides Move contants into bus manager --- wled00/bus_manager.cpp | 27 ++++++++++++++++++++++++++- wled00/const.h | 29 ----------------------------- 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index e626a2962..d0e32b211 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -378,6 +378,31 @@ void BusDigital::cleanup() { } +#ifdef ESP8266 + // 1 MHz clock + #define CLOCK_FREQUENCY 1000000UL +#else + // Use XTAL clock if possible to avoid timer frequency error when setting APB clock < 80 Mhz + // https://github.com/espressif/arduino-esp32/blob/2.0.2/cores/esp32/esp32-hal-ledc.c + #ifdef SOC_LEDC_SUPPORT_XTAL_CLOCK + #define CLOCK_FREQUENCY 40000000UL + #else + #define CLOCK_FREQUENCY 80000000UL + #endif +#endif + +#ifdef ESP8266 + #define MAX_BIT_WIDTH 10 +#else + #ifdef SOC_LEDC_TIMER_BIT_WIDE_NUM + // C6/H2/P4: 20 bit, S2/S3/C2/C3: 14 bit + #define MAX_BIT_WIDTH SOC_LEDC_TIMER_BIT_WIDE_NUM + #else + // ESP32: 20 bit (but in reality we would never go beyond 16 bit as the frequency would be to low) + #define MAX_BIT_WIDTH 20 + #endif +#endif + BusPwm::BusPwm(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed) { @@ -385,7 +410,7 @@ BusPwm::BusPwm(BusConfig &bc) unsigned numPins = NUM_PWM_PINS(bc.type); _frequency = bc.frequency ? bc.frequency : WLED_PWM_FREQ; // duty cycle resolution (_depth) can be extracted from this formula: CLOCK_FREQUENCY > _frequency * 2^_depth - for (_depth=MAX_BIT_WIDTH; _depth>8; _depth--) if (((uint32_t(CLOCK_FREQUENCY)/_frequency)>>_depth) > 0) break; + for (_depth = MAX_BIT_WIDTH; _depth > 8; _depth--) if (((CLOCK_FREQUENCY/_frequency) >> _depth) > 0) break; #ifdef ESP8266 analogWriteRange((1<<_depth)-1); diff --git a/wled00/const.h b/wled00/const.h index d792f592a..0ff70e47d 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -521,35 +521,6 @@ #endif #endif -#ifndef CLOCK_FREQUENCY - #ifdef ESP8266 - // 1 MHz clock - #define CLOCK_FREQUENCY 1e6f - #else - // Use XTAL clock if possible to avoid timer frequency error when setting APB clock < 80 Mhz - // https://github.com/espressif/arduino-esp32/blob/2.0.2/cores/esp32/esp32-hal-ledc.c - #ifdef SOC_LEDC_SUPPORT_XTAL_CLOCK - #define CLOCK_FREQUENCY 40e6f - #else - #define CLOCK_FREQUENCY 80e6f - #endif - #endif -#endif - -#ifndef MAX_BIT_WIDTH - #ifdef ESP8266 - #define MAX_BIT_WIDTH 10 - #else - #ifdef SOC_LEDC_TIMER_BIT_WIDE_NUM - // C6/H2/P4: 20 bit, S2/S3/C2/C3: 14 bit - #define MAX_BIT_WIDTH SOC_LEDC_TIMER_BIT_WIDE_NUM - #else - // ESP32: 20 bit - #define MAX_BIT_WIDTH 20 - #endif - #endif -#endif - #define TOUCH_THRESHOLD 32 // limit to recognize a touch, higher value means more sensitive // Size of buffer for API JSON object (increase for more segments) From e82f38e277b6ad3d7b943b8868c3f88cb7c53382 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Mon, 5 Aug 2024 16:42:21 +0200 Subject: [PATCH 10/10] Tuning --- wled00/FX.h | 38 +++++++++--------------------- wled00/FX_2Dfcn.cpp | 6 ++--- wled00/FX_fcn.cpp | 46 ++++++++++++++++++------------------- wled00/colors.cpp | 41 +++++++++++++++------------------ wled00/data/settings_um.htm | 21 +++++++++-------- wled00/set.cpp | 9 ++++---- wled00/util.cpp | 2 +- 7 files changed, 73 insertions(+), 90 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index e4ebd3016..57de5df44 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -563,16 +563,16 @@ typedef struct Segment { // transition functions void startTransition(uint16_t dur); // transition has to start before actual segment values change - void stopTransition(void); // ends transition mode by destroying transition structure - void handleTransition(void); + void stopTransition(void); // ends transition mode by destroying transition structure (does nothing if not in transition) + inline void handleTransition(void) { if (progress() == 0xFFFFU) stopTransition(); } #ifndef WLED_DISABLE_MODE_BLEND void swapSegenv(tmpsegd_t &tmpSegD); // copies segment data into specifed buffer, if buffer is not a transition buffer, segment data is overwritten from transition buffer void restoreSegenv(tmpsegd_t &tmpSegD); // restores segment data from buffer, if buffer is not transition buffer, changed values are copied to transition buffer #endif - uint16_t progress(void); // transition progression between 0-65535 - uint8_t currentBri(bool useCct = false); // current segment brightness/CCT (blended while in transition) - uint8_t currentMode(void); // currently active effect/mode (while in transition) - uint32_t currentColor(uint8_t slot); // currently active segment color (blended while in transition) + uint16_t progress(void) const; // transition progression between 0-65535 + uint8_t currentBri(bool useCct = false) const; // current segment brightness/CCT (blended while in transition) + uint8_t currentMode(void) const; // currently active effect/mode (while in transition) + uint32_t currentColor(uint8_t slot) const; // currently active segment color (blended while in transition) CRGBPalette16 &loadPalette(CRGBPalette16 &tgt, uint8_t pal); void setCurrentPalette(void); @@ -587,7 +587,7 @@ typedef struct Segment { inline void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) { setPixelColor(i, RGBW32(r,g,b,w), aa); } inline void setPixelColor(float i, CRGB c, bool aa = true) { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); } #endif - uint32_t getPixelColor(int i); + uint32_t getPixelColor(int i) const; // 1D support functions (some implement 2D as well) void blur(uint8_t, bool smear = false); void fill(uint32_t c); @@ -599,8 +599,8 @@ typedef struct Segment { inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColor(n, RGBW32(r,g,b,w), fast); } inline void addPixelColor(int n, CRGB c, bool fast = false) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), fast); } inline void fadePixelColor(uint16_t n, uint8_t fade) { setPixelColor(n, color_fade(getPixelColor(n), fade, true)); } - uint32_t color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255); - uint32_t color_wheel(uint8_t pos); + 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 matrix uint16_t virtualWidth(void) const; // segment width in virtual pixels (accounts for groupping and spacing) @@ -618,7 +618,7 @@ typedef struct Segment { inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColorXY(x, y, RGBW32(r,g,b,w), aa); } inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), aa); } #endif - uint32_t getPixelColorXY(int x, int y); + uint32_t getPixelColorXY(int x, int y) const; // 2D support functions inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) { setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend)); } inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), blend); } @@ -729,15 +729,7 @@ class WS2812FX { // 96 bytes customMappingSize(0), _lastShow(0), _segment_index(0), - _mainSegment(0), - _queuedChangesSegId(255), - _qStart(0), - _qStop(0), - _qStartY(0), - _qStopY(0), - _qGrouping(0), - _qSpacing(0), - _qOffset(0) + _mainSegment(0) { WS2812FX::instance = this; _mode.reserve(_modeCount); // allocate memory to prevent initial fragmentation (does not increase size()) @@ -945,14 +937,6 @@ class WS2812FX { // 96 bytes uint8_t _segment_index; uint8_t _mainSegment; - uint8_t _queuedChangesSegId; - uint16_t _qStart, _qStop, _qStartY, _qStopY; - uint8_t _qGrouping, _qSpacing; - uint16_t _qOffset; -/* - void - setUpSegmentFromQueuedChanges(void); -*/ }; extern const char JSON_mode_names[]; diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index b262c157d..c135c3dbc 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -180,7 +180,7 @@ void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col) if (reverse ) x = virtualWidth() - x - 1; if (reverse_y) y = virtualHeight() - y - 1; - if (transpose) { unsigned t = x; x = y; y = t; } // swap X & Y if segment transposed + if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed x *= groupLength(); // expand to physical pixels y *= groupLength(); // expand to physical pixels @@ -261,12 +261,12 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa) #endif // returns RGBW values of pixel -uint32_t IRAM_ATTR Segment::getPixelColorXY(int x, int y) { +uint32_t IRAM_ATTR Segment::getPixelColorXY(int x, int y) const { if (!isActive()) return 0; // not active if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit if (reverse ) x = virtualWidth() - x - 1; if (reverse_y) y = virtualHeight() - y - 1; - if (transpose) { unsigned t = x; x = y; y = t; } // swap X & Y if segment transposed + if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed x *= groupLength(); // expand to physical pixels y *= groupLength(); // expand to physical pixels if (x >= width() || y >= height()) return 0; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 48570b30d..758df62fa 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -327,13 +327,8 @@ void Segment::stopTransition() { } } -void Segment::handleTransition() { - unsigned _progress = progress(); - if (_progress == 0xFFFFU) stopTransition(); -} - // transition progression between 0-65535 -uint16_t IRAM_ATTR Segment::progress() { +uint16_t IRAM_ATTR Segment::progress() const { if (isInTransition()) { unsigned diff = millis() - _t->_start; if (_t->_dur > 0 && diff < _t->_dur) return diff * 0xFFFFU / _t->_dur; @@ -412,7 +407,7 @@ void Segment::restoreSegenv(tmpsegd_t &tmpSeg) { } #endif -uint8_t IRAM_ATTR Segment::currentBri(bool useCct) { +uint8_t IRAM_ATTR Segment::currentBri(bool useCct) const { unsigned prog = progress(); if (prog < 0xFFFFU) { unsigned curBri = (useCct ? cct : (on ? opacity : 0)) * prog; @@ -422,7 +417,7 @@ uint8_t IRAM_ATTR Segment::currentBri(bool useCct) { return (useCct ? cct : (on ? opacity : 0)); } -uint8_t IRAM_ATTR Segment::currentMode() { +uint8_t IRAM_ATTR Segment::currentMode() const { #ifndef WLED_DISABLE_MODE_BLEND unsigned prog = progress(); if (modeBlending && prog < 0xFFFFU) return _t->_modeT; @@ -430,7 +425,7 @@ uint8_t IRAM_ATTR Segment::currentMode() { return mode; } -uint32_t IRAM_ATTR Segment::currentColor(uint8_t slot) { +uint32_t IRAM_ATTR Segment::currentColor(uint8_t slot) const { if (slot >= NUM_COLORS) slot = 0; #ifndef WLED_DISABLE_MODE_BLEND return isInTransition() ? color_blend(_t->_segT._colorT[slot], colors[slot], progress(), true) : colors[slot]; @@ -685,9 +680,11 @@ uint16_t IRAM_ATTR Segment::virtualLength() const { vLen = vH; break; case M12_pCorner: - case M12_pArc: vLen = max(vW,vH); // get the longest dimension break; + case M12_pArc: + vLen = sqrt16(vH*vH + vW*vW); // use diagonal + break; case M12_sPinwheel: vLen = getPinwheelLength(vW, vH); break; @@ -730,12 +727,14 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col) if (i==0) setPixelColorXY(0, 0, col); else { - float step = HALF_PI / (2.85f*i); - for (float rad = 0.0f; rad <= HALF_PI+step/2; rad += step) { - // may want to try float version as well (with or without antialiasing) - int x = roundf(sin_t(rad) * i); - int y = roundf(cos_t(rad) * i); + float r = i; + float step = HALF_PI / (2.8284f * r + 4); // we only need (PI/4)/(r/sqrt(2)+1) steps + for (float rad = 0.0f; rad <= (HALF_PI/2)+step/2; rad += step) { + int x = roundf(sin_t(rad) * r); + int y = roundf(cos_t(rad) * r); + // exploit symmetry setPixelColorXY(x, y, col); + setPixelColorXY(y, x, col); } // Bresenham’s Algorithm (may not fill every pixel) //int d = 3 - (2*i); @@ -893,7 +892,7 @@ void Segment::setPixelColor(float i, uint32_t col, bool aa) } #endif -uint32_t IRAM_ATTR Segment::getPixelColor(int i) +uint32_t IRAM_ATTR Segment::getPixelColor(int i) const { if (!isActive()) return 0; // not active #ifndef WLED_DISABLE_2D @@ -1059,7 +1058,7 @@ void Segment::fade_out(uint8_t rate) { const int rows = virtualHeight(); // will be 1 for 1D rate = (255-rate) >> 1; - float mappedRate = float(rate) +1.1f; + float mappedRate = 1.0f / (float(rate) + 1.1f); uint32_t color = colors[1]; // SEGCOLOR(1); // target color int w2 = W(color); @@ -1069,15 +1068,16 @@ void Segment::fade_out(uint8_t rate) { for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) { color = is2D() ? getPixelColorXY(x, y) : getPixelColor(x); + if (color == colors[1]) continue; // already at target color int w1 = W(color); int r1 = R(color); int g1 = G(color); int b1 = B(color); - int wdelta = (w2 - w1) / mappedRate; - int rdelta = (r2 - r1) / mappedRate; - int gdelta = (g2 - g1) / mappedRate; - int bdelta = (b2 - b1) / mappedRate; + int wdelta = (w2 - w1) * mappedRate; + int rdelta = (r2 - r1) * mappedRate; + int gdelta = (g2 - g1) * mappedRate; + int bdelta = (b2 - b1) * mappedRate; // if fade isn't complete, make sure delta is at least 1 (fixes rounding issues) wdelta += (w2 == w1) ? 0 : (w2 > w1) ? 1 : -1; @@ -1149,7 +1149,7 @@ void Segment::blur(uint8_t blur_amount, bool smear) { * The colours are a transition r -> g -> b -> back to r * Inspired by the Adafruit examples. */ -uint32_t Segment::color_wheel(uint8_t pos) { +uint32_t Segment::color_wheel(uint8_t pos) const { if (palette) return color_from_palette(pos, false, true, 0); // perhaps "strip.paletteBlend < 2" should be better instead of "true" uint8_t w = W(currentColor(0)); pos = 255 - pos; @@ -1173,7 +1173,7 @@ uint32_t Segment::color_wheel(uint8_t pos) { * @param pbri Value to scale the brightness of the returned color by. Default is 255. (no scaling) * @returns Single color from palette */ -uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) { +uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) const { uint32_t color = gamma32(currentColor(mcol)); // default palette or no RGB support on segment diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 82dde47bb..ebea7ea05 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -8,10 +8,10 @@ * color blend function */ uint32_t color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) { - if(blend == 0) return color1; + if (blend == 0) return color1; unsigned blendmax = b16 ? 0xFFFF : 0xFF; - if(blend == blendmax) return color2; - uint8_t shift = b16 ? 16 : 8; + if (blend == blendmax) return color2; + unsigned shift = b16 ? 16 : 8; uint32_t w1 = W(color1); uint32_t r1 = R(color1); @@ -73,22 +73,19 @@ uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) uint32_t g = G(c1); uint32_t b = B(c1); uint32_t w = W(c1); - if (video) { - uint32_t scale = amount; // 32bit for faster calculation - scaledcolor = (((r * scale) >> 8) << 16) + ((r && scale) ? 1 : 0); - scaledcolor |= (((g * scale) >> 8) << 8) + ((g && scale) ? 1 : 0); - scaledcolor |= ((b * scale) >> 8) + ((b && scale) ? 1 : 0); + uint32_t scale = amount + !video; // 32bit for faster calculation + if (video) { + scaledcolor = (((r * scale) >> 8) << 16) + ((r && scale) ? 1 : 0); + scaledcolor |= (((g * scale) >> 8) << 8) + ((g && scale) ? 1 : 0); + scaledcolor |= ((b * scale) >> 8) + ((b && scale) ? 1 : 0); scaledcolor |= (((w * scale) >> 8) << 24) + ((w && scale) ? 1 : 0); - return scaledcolor; - } - else { - uint32_t scale = 1 + amount; - scaledcolor = ((r * scale) >> 8) << 16; + } else { + scaledcolor = ((r * scale) >> 8) << 16; scaledcolor |= ((g * scale) >> 8) << 8; - scaledcolor |= (b * scale) >> 8; + scaledcolor |= (b * scale) >> 8; scaledcolor |= ((w * scale) >> 8) << 24; - return scaledcolor; } + return scaledcolor; } void setRandomColor(byte* rgb) @@ -140,25 +137,25 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) case 1: // triadic harmonics[0] = basehue + 113 + random8(15); harmonics[1] = basehue + 233 + random8(15); - harmonics[2] = basehue -7 + random8(15); + harmonics[2] = basehue - 7 + random8(15); break; case 2: // split-complementary harmonics[0] = basehue + 145 + random8(10); harmonics[1] = basehue + 205 + random8(10); - harmonics[2] = basehue - 5 + random8(10); + harmonics[2] = basehue - 5 + random8(10); break; case 3: // square - harmonics[0] = basehue + 85 + random8(10); + harmonics[0] = basehue + 85 + random8(10); harmonics[1] = basehue + 175 + random8(10); harmonics[2] = basehue + 265 + random8(10); break; case 4: // tetradic - harmonics[0] = basehue + 80 + random8(20); + harmonics[0] = basehue + 80 + random8(20); harmonics[1] = basehue + 170 + random8(20); - harmonics[2] = basehue + random8(30)-15; + harmonics[2] = basehue - 15 + random8(30); break; } @@ -384,13 +381,13 @@ bool colorFromHexString(byte* rgb, const char* in) { return true; } -float minf (float v, float w) +static inline float minf(float v, float w) { if (w > v) return v; return w; } -float maxf (float v, float w) +static inline float maxf(float v, float w) { if (w > v) return w; return v; diff --git a/wled00/data/settings_um.htm b/wled00/data/settings_um.htm index a50fc8269..686c881d9 100644 --- a/wled00/data/settings_um.htm +++ b/wled00/data/settings_um.htm @@ -34,7 +34,7 @@ if (d.um_p[0]==-1) d.um_p.shift(); // remove filler d.Sf.SDA.max = d.Sf.SCL.max = d.Sf.MOSI.max = d.Sf.SCLK.max = d.Sf.MISO.max = d.max_gpio; //for (let i of d.getElementsByTagName("input")) if (i.type === "number" && i.name.replace("[]","").substr(-3) === "pin") i.max = d.max_gpio; - pinDropdowns(); // convert INPUT to SELECT for pins + pinDD(); // convert INPUT to SELECT for pins }); // error event scE.addEventListener("error", (ev) => { @@ -165,25 +165,25 @@ urows += `
`; } } - function pinDropdowns() { + function pinDD() { for (let i of d.Sf.elements) { if (i.type === "number" && (i.name.includes("pin") || ["SDA","SCL","MOSI","MISO","SCLK"].includes(i.name))) { //select all pin select elements let v = parseInt(i.value); - let sel = addDropdown(i.name,0); + let sel = addDD(i.name,0); for (var j = -1; j <= d.max_gpio; j++) { if (d.rsvd.includes(j)) continue; let foundPin = pins.indexOf(j); let txt = (j === -1) ? "unused" : `${j}`; if (foundPin >= 0 && j !== v) txt += ` ${pinO[foundPin]=="if"?"global":pinO[foundPin]}`; // already reserved pin if (d.ro_gpio.includes(j)) txt += " (R/O)"; - let opt = addOption(sel, txt, j); + let opt = addO(sel, txt, j); if (j === v) opt.selected = true; // this is "our" pin else if (pins.includes(j)) opt.disabled = true; // someone else's pin } let um = i.name.split(":")[0]; d.extra.forEach((o)=>{ if (o[um] && o[um].pin) o[um].pin.forEach((e)=>{ - let opt = addOption(sel,e[0],e[1]); + let opt = addO(sel,e[0],e[1]); if (e[1]==v) opt.selected = true; }); }); @@ -219,7 +219,7 @@ } } // https://stackoverflow.com/questions/39729741/javascript-change-input-text-to-select-option - function addDropdown(um,fld) { + function addDD(um,fld) { let sel = d.createElement('select'); if (typeof(fld) === "string") { // parameter from usermod (field name) if (fld.includes("pin")) sel.classList.add("pin"); @@ -255,7 +255,8 @@ } return null; } - function addOption(sel,txt,val) { + var addDropdown = addDD; // backwards compatibility + function addO(sel,txt,val) { if (sel===null) return; // select object missing let opt = d.createElement("option"); opt.value = val; @@ -267,8 +268,9 @@ } return opt; } + var addOption = addO; // backwards compatibility // https://stackoverflow.com/questions/26440494/insert-text-after-this-input-element-with-javascript - function addInfo(name,el,txt, txt2="") { + function addI(name,el,txt, txt2="") { let obj = d.getElementsByName(name); if (!obj.length) return; if (typeof el === "string" && obj[0]) obj[0].placeholder = el; @@ -277,9 +279,10 @@ if (txt2!="") obj[el].insertAdjacentHTML('beforebegin', txt2 + ' '); //add pre texts } } + var addInfo = addI; // backwards compatibility // add Help Button function addHB(um) { - addInfo(um + ':help',0,``); + addI(um + ':help',0,``); } // load settings and insert values into DOM function ldS() { diff --git a/wled00/set.cpp b/wled00/set.cpp index 13295df21..3dd226e00 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -860,20 +860,19 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) uint16_t spcI = selseg.spacing; pos = req.indexOf(F("&S=")); //segment start if (pos > 0) { - startI = getNumVal(&req, pos); + startI = std::abs(getNumVal(&req, pos)); } pos = req.indexOf(F("S2=")); //segment stop if (pos > 0) { - stopI = getNumVal(&req, pos); + stopI = std::abs(getNumVal(&req, pos)); } pos = req.indexOf(F("GP=")); //segment grouping if (pos > 0) { - grpI = getNumVal(&req, pos); - if (grpI == 0) grpI = 1; + grpI = std::max(1,getNumVal(&req, pos)); } pos = req.indexOf(F("SP=")); //segment spacing if (pos > 0) { - spcI = getNumVal(&req, pos); + spcI = std::max(0,getNumVal(&req, pos)); } strip.setSegment(selectedSeg, startI, stopI, grpI, spcI, UINT16_MAX, startY, stopY); diff --git a/wled00/util.cpp b/wled00/util.cpp index 6bc02234b..fc19d60bd 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -148,7 +148,7 @@ void sappends(char stype, const char* key, char* val) bool oappendi(int i) { - char s[11]; + char s[12]; // 32bit signed number can have 10 digits plus - sign sprintf(s, "%d", i); return oappend(s); }