From 3ad56ea103d794082b3475fd22591a5a7787e63d Mon Sep 17 00:00:00 2001 From: Christian Schwinne Date: Sun, 10 Mar 2024 14:34:15 +0100 Subject: [PATCH 001/463] GIF testing --- wled00/fcn_declare.h | 3 ++- wled00/image_loader.cpp | 58 +++++++++++++++++++++-------------------- 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 59be6762..72918d1a 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -5,7 +5,6 @@ * All globally accessible functions are declared here */ -#include "FX.h" //alexa.cpp #ifndef WLED_DISABLE_ALEXA @@ -127,6 +126,8 @@ void onHueConnect(void* arg, AsyncClient* client); void sendHuePoll(); void onHueData(void* arg, AsyncClient* client, void *data, size_t len); +#include "FX.h" // must be below colors.cpp declarations (potentially due to duplicate declarations of e.g. color_blend) + //image_loader.cpp #ifndef WLED_DISABLE_GIF bool fileSeekCallback(unsigned long position); diff --git a/wled00/image_loader.cpp b/wled00/image_loader.cpp index 500fbc2d..4a805240 100644 --- a/wled00/image_loader.cpp +++ b/wled00/image_loader.cpp @@ -5,7 +5,7 @@ File file; char lastFilename[34] = "/"; -GifDecoder<320,320,12,true>* decoder; +GifDecoder<32,32,12> decoder; bool gifDecodeFailed = false; long lastFrameDisplayTime = 0, currentFrameDelay = 0; @@ -38,7 +38,7 @@ bool openGif(const char *filename) { Segment* activeSeg; uint16_t gifWidth, gifHeight; -uint16_t fillPixX, fillPixY; +//uint16_t fillPixX, fillPixY; void screenClearCallback(void) { activeSeg->fill(0); @@ -66,6 +66,7 @@ void drawPixelCallback(int16_t x, int16_t y, uint8_t red, uint8_t green, uint8_t #define IMAGE_ERROR_DECODER_ALLOC 5 #define IMAGE_ERROR_GIF_DECODE 6 #define IMAGE_ERROR_FRAME_DECODE 7 +#define IMAGE_ERROR_WAITING 254 #define IMAGE_ERROR_PREV 255 // renders an image (.gif only; .bmp and .fseq to be added soon) from FS to a segment @@ -84,47 +85,48 @@ byte renderImageToSegment(Segment &seg) { if (file) file.close(); openGif(lastFilename); if (!file) { gifDecodeFailed = true; return IMAGE_ERROR_FILE_MISSING; } - if (!decoder) decoder = new GifDecoder<320,320,12,true>(); - if (!decoder) { gifDecodeFailed = true; return IMAGE_ERROR_DECODER_ALLOC; } - decoder->setScreenClearCallback(screenClearCallback); - decoder->setUpdateScreenCallback(updateScreenCallback); - decoder->setDrawPixelCallback(drawPixelCallback); - decoder->setFileSeekCallback(fileSeekCallback); - decoder->setFilePositionCallback(filePositionCallback); - decoder->setFileReadCallback(fileReadCallback); - decoder->setFileReadBlockCallback(fileReadBlockCallback); - decoder->setFileSizeCallback(fileSizeCallback); + //if (!decoder) decoder = new GifDecoder<32,32,12>(); + //if (!decoder) { gifDecodeFailed = true; return IMAGE_ERROR_DECODER_ALLOC; } + decoder.setScreenClearCallback(screenClearCallback); + decoder.setUpdateScreenCallback(updateScreenCallback); + decoder.setDrawPixelCallback(drawPixelCallback); + decoder.setFileSeekCallback(fileSeekCallback); + decoder.setFilePositionCallback(filePositionCallback); + decoder.setFileReadCallback(fileReadCallback); + decoder.setFileReadBlockCallback(fileReadBlockCallback); + decoder.setFileSizeCallback(fileSizeCallback); Serial.println("Starting decoding"); - if(decoder->startDecoding() < 0) { gifDecodeFailed = true; return IMAGE_ERROR_GIF_DECODE; } + if(decoder.startDecoding() < 0) { gifDecodeFailed = true; return IMAGE_ERROR_GIF_DECODE; } Serial.println("Decoding started"); } if (gifDecodeFailed) return IMAGE_ERROR_PREV; if (!file) { gifDecodeFailed = true; return IMAGE_ERROR_FILE_MISSING; } - if (!decoder) { gifDecodeFailed = true; return IMAGE_ERROR_DECODER_ALLOC; } + //if (!decoder) { gifDecodeFailed = true; return IMAGE_ERROR_DECODER_ALLOC; } // speed 0 = half speed, 128 = normal, 255 = full FX FPS // TODO: 0 = 4x slow, 64 = 2x slow, 128 = normal, 192 = 2x fast, 255 = 4x fast uint32_t wait = currentFrameDelay * 2 - seg.speed * currentFrameDelay / 128; - if((millis() - lastFrameDisplayTime) >= wait) { - decoder->getSize(&gifWidth, &gifHeight); - fillPixX = (seg.width()+(gifWidth-1)) / gifWidth; - fillPixY = (seg.height()+(gifHeight-1)) / gifHeight; - int result = decoder->decodeFrame(false); - if (result < 0) { gifDecodeFailed = true; return IMAGE_ERROR_FRAME_DECODE; } - long lastFrameDelay = currentFrameDelay; - currentFrameDelay = decoder->getFrameDelay_ms(); - long tooSlowBy = (millis() - lastFrameDisplayTime) - wait; // if last frame was longer than intended, compensate - currentFrameDelay -= tooSlowBy; - lastFrameDisplayTime = millis(); - } - return true; + if((millis() - lastFrameDisplayTime) < wait) return IMAGE_ERROR_WAITING; + + decoder.getSize(&gifWidth, &gifHeight); + //fillPixX = (seg.width()+(gifWidth-1)) / gifWidth; + //fillPixY = (seg.height()+(gifHeight-1)) / gifHeight; + int result = decoder.decodeFrame(false); + if (result < 0) { gifDecodeFailed = true; return IMAGE_ERROR_FRAME_DECODE; } + //long lastFrameDelay = currentFrameDelay; + currentFrameDelay = decoder.getFrameDelay_ms(); + //long tooSlowBy = (millis() - lastFrameDisplayTime) - wait; // if last frame was longer than intended, compensate + //currentFrameDelay -= tooSlowBy; // TODO this is broken + lastFrameDisplayTime = millis(); + + return IMAGE_ERROR_NONE; } void endImagePlayback() { if (file) file.close(); - delete decoder; + //delete decoder; gifDecodeFailed = false; activeSeg = nullptr; lastFilename[0] = '\0'; From b2afac891415a65c5267755a351844903aba8e9d Mon Sep 17 00:00:00 2001 From: Christian Schwinne Date: Sun, 10 Mar 2024 21:36:13 +0100 Subject: [PATCH 002/463] GIFs work again in principle --- platformio.ini | 2 +- wled00/FX.cpp | 11 +++++++---- wled00/FX_fcn.cpp | 1 + wled00/fcn_declare.h | 1 + wled00/image_loader.cpp | 13 +++++++++---- 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/platformio.ini b/platformio.ini index 66bd0995..73d82c3a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -221,7 +221,7 @@ lib_deps = https://github.com/lorol/LITTLEFS.git https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 bitbank2/AnimatedGIF@^1.4.7 - pixelmatix/GifDecoder@^1.1.0 + https://github.com/Aircoookie/GifDecoder#e76f58f ${env.lib_deps} # additional build flags for audioreactive AR_build_flags = -D USERMOD_AUDIOREACTIVE diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 681f3d10..e8c59bab 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -4470,7 +4470,12 @@ static const char _data_FX_MODE_WASHING_MACHINE[] PROGMEM = "Washing Machine@!,! Draws a .gif image from filesystem on the matrix/strip */ uint16_t mode_image(void) { - renderImageToSegment(SEGMENT); + //Serial.println(renderImageToSegment(SEGMENT)); + int status = renderImageToSegment(SEGMENT); + if (status != 0 && status != 254 && status != 255) { + Serial.print("GIF renderer return: "); + Serial.println(status); + } return FRAMETIME; } static const char _data_FX_MODE_IMAGE[] PROGMEM = "Image@!,;;;12;sx=128"; @@ -7973,7 +7978,7 @@ void WS2812FX::setupEffectData() { addEffect(FX_MODE_TWO_DOTS, &mode_two_dots, _data_FX_MODE_TWO_DOTS); addEffect(FX_MODE_FAIRYTWINKLE, &mode_fairytwinkle, _data_FX_MODE_FAIRYTWINKLE); addEffect(FX_MODE_RUNNING_DUAL, &mode_running_dual, _data_FX_MODE_RUNNING_DUAL); - + addEffect(FX_MODE_IMAGE, &mode_image, _data_FX_MODE_IMAGE); addEffect(FX_MODE_TRICOLOR_CHASE, &mode_tricolor_chase, _data_FX_MODE_TRICOLOR_CHASE); addEffect(FX_MODE_TRICOLOR_WIPE, &mode_tricolor_wipe, _data_FX_MODE_TRICOLOR_WIPE); addEffect(FX_MODE_TRICOLOR_FADE, &mode_tricolor_fade, _data_FX_MODE_TRICOLOR_FADE); @@ -8035,8 +8040,6 @@ void WS2812FX::setupEffectData() { addEffect(FX_MODE_DANCING_SHADOWS, &mode_dancing_shadows, _data_FX_MODE_DANCING_SHADOWS); addEffect(FX_MODE_WASHING_MACHINE, &mode_washing_machine, _data_FX_MODE_WASHING_MACHINE); - addEffect(FX_MODE_IMAGE, &mode_image, _data_FX_MODE_IMAGE); - addEffect(FX_MODE_BLENDS, &mode_blends, _data_FX_MODE_BLENDS); addEffect(FX_MODE_TV_SIMULATOR, &mode_tv_simulator, _data_FX_MODE_TV_SIMULATOR); addEffect(FX_MODE_DYNAMIC_SMOOTH, &mode_dynamic_smooth, _data_FX_MODE_DYNAMIC_SMOOTH); diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 42e98452..94fdb300 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -199,6 +199,7 @@ void Segment::resetIfRequired() { if (data && _dataLen > 0) memset(data, 0, _dataLen); // prevent heap fragmentation (just erase buffer instead of deallocateData()) next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0; reset = false; + endImagePlayback(this); } CRGBPalette16 IRAM_ATTR &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) { diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 72918d1a..4619e640 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -136,6 +136,7 @@ int fileReadCallback(void); int fileReadBlockCallback(void * buffer, int numberOfBytes); int fileSizeCallback(void); byte renderImageToSegment(Segment &seg); +void endImagePlayback(Segment* seg); #endif //improv.cpp diff --git a/wled00/image_loader.cpp b/wled00/image_loader.cpp index 4a805240..44fb7f7c 100644 --- a/wled00/image_loader.cpp +++ b/wled00/image_loader.cpp @@ -5,7 +5,7 @@ File file; char lastFilename[34] = "/"; -GifDecoder<32,32,12> decoder; +GifDecoder<32,32,12,true> decoder; bool gifDecodeFailed = false; long lastFrameDisplayTime = 0, currentFrameDelay = 0; @@ -85,7 +85,7 @@ byte renderImageToSegment(Segment &seg) { if (file) file.close(); openGif(lastFilename); if (!file) { gifDecodeFailed = true; return IMAGE_ERROR_FILE_MISSING; } - //if (!decoder) decoder = new GifDecoder<32,32,12>(); + //if (!decoder) decoder = new GifDecoder<32,32,12,true>(); //if (!decoder) { gifDecodeFailed = true; return IMAGE_ERROR_DECODER_ALLOC; } decoder.setScreenClearCallback(screenClearCallback); decoder.setUpdateScreenCallback(updateScreenCallback); @@ -95,6 +95,7 @@ byte renderImageToSegment(Segment &seg) { decoder.setFileReadCallback(fileReadCallback); decoder.setFileReadBlockCallback(fileReadBlockCallback); decoder.setFileSizeCallback(fileSizeCallback); + decoder.alloc(); // TODO only if not already allocated Serial.println("Starting decoding"); if(decoder.startDecoding() < 0) { gifDecodeFailed = true; return IMAGE_ERROR_GIF_DECODE; } Serial.println("Decoding started"); @@ -124,12 +125,16 @@ byte renderImageToSegment(Segment &seg) { return IMAGE_ERROR_NONE; } -void endImagePlayback() { +void endImagePlayback(Segment *seg) { + Serial.println("Image playback end called"); + if (!activeSeg || activeSeg != seg) return; if (file) file.close(); //delete decoder; + decoder.dealloc(); gifDecodeFailed = false; activeSeg = nullptr; - lastFilename[0] = '\0'; + lastFilename[1] = '\0'; + Serial.println("Image playback ended"); } #endif \ No newline at end of file From 3e60d3d96e9ebbea6232fca0b0e10fe714f9b008 Mon Sep 17 00:00:00 2001 From: Christian Schwinne Date: Sun, 17 Mar 2024 22:24:55 +0100 Subject: [PATCH 003/463] Working GIF support --- wled00/FX.cpp | 11 +++++------ wled00/image_loader.cpp | 28 +++++++++++++++------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index e8c59bab..48866224 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -4470,12 +4470,11 @@ static const char _data_FX_MODE_WASHING_MACHINE[] PROGMEM = "Washing Machine@!,! Draws a .gif image from filesystem on the matrix/strip */ uint16_t mode_image(void) { - //Serial.println(renderImageToSegment(SEGMENT)); - int status = renderImageToSegment(SEGMENT); - if (status != 0 && status != 254 && status != 255) { - Serial.print("GIF renderer return: "); - Serial.println(status); - } + renderImageToSegment(SEGMENT); + // if (status != 0 && status != 254 && status != 255) { + // Serial.print("GIF renderer return: "); + // Serial.println(status); + // } return FRAMETIME; } static const char _data_FX_MODE_IMAGE[] PROGMEM = "Image@!,;;;12;sx=128"; diff --git a/wled00/image_loader.cpp b/wled00/image_loader.cpp index 44fb7f7c..9ad4662e 100644 --- a/wled00/image_loader.cpp +++ b/wled00/image_loader.cpp @@ -3,11 +3,15 @@ #include "GifDecoder.h" #include "wled.h" +/* + * Functions to render images from filesystem to segments, used by the "Image" effect + */ + File file; char lastFilename[34] = "/"; -GifDecoder<32,32,12,true> decoder; +GifDecoder<320,320,12,true> decoder; bool gifDecodeFailed = false; -long lastFrameDisplayTime = 0, currentFrameDelay = 0; +unsigned long lastFrameDisplayTime = 0, currentFrameDelay = 0; bool fileSeekCallback(unsigned long position) { return file.seek(position); @@ -38,7 +42,6 @@ bool openGif(const char *filename) { Segment* activeSeg; uint16_t gifWidth, gifHeight; -//uint16_t fillPixX, fillPixY; void screenClearCallback(void) { activeSeg->fill(0); @@ -72,6 +75,8 @@ void drawPixelCallback(int16_t x, int16_t y, uint8_t red, uint8_t green, uint8_t // renders an image (.gif only; .bmp and .fseq to be added soon) from FS to a segment byte renderImageToSegment(Segment &seg) { if (!seg.name) return IMAGE_ERROR_NO_NAME; + // disable during effect transition, causes flickering, multiple allocations and depending on image, part of old FX remaining + if (seg.mode != seg.currentMode()) return IMAGE_ERROR_WAITING; if (activeSeg && activeSeg != &seg) return IMAGE_ERROR_SEG_LIMIT; // only one segment at a time activeSeg = &seg; @@ -85,8 +90,6 @@ byte renderImageToSegment(Segment &seg) { if (file) file.close(); openGif(lastFilename); if (!file) { gifDecodeFailed = true; return IMAGE_ERROR_FILE_MISSING; } - //if (!decoder) decoder = new GifDecoder<32,32,12,true>(); - //if (!decoder) { gifDecodeFailed = true; return IMAGE_ERROR_DECODER_ALLOC; } decoder.setScreenClearCallback(screenClearCallback); decoder.setUpdateScreenCallback(updateScreenCallback); decoder.setDrawPixelCallback(drawPixelCallback); @@ -95,7 +98,7 @@ byte renderImageToSegment(Segment &seg) { decoder.setFileReadCallback(fileReadCallback); decoder.setFileReadBlockCallback(fileReadBlockCallback); decoder.setFileSizeCallback(fileSizeCallback); - decoder.alloc(); // TODO only if not already allocated + decoder.alloc(); Serial.println("Starting decoding"); if(decoder.startDecoding() < 0) { gifDecodeFailed = true; return IMAGE_ERROR_GIF_DECODE; } Serial.println("Decoding started"); @@ -109,17 +112,17 @@ byte renderImageToSegment(Segment &seg) { // TODO: 0 = 4x slow, 64 = 2x slow, 128 = normal, 192 = 2x fast, 255 = 4x fast uint32_t wait = currentFrameDelay * 2 - seg.speed * currentFrameDelay / 128; - if((millis() - lastFrameDisplayTime) < wait) return IMAGE_ERROR_WAITING; + // TODO consider handling this on FX level with a different frametime, but that would cause slow gifs to speed up during transitions + if (millis() - lastFrameDisplayTime < wait) return IMAGE_ERROR_WAITING; decoder.getSize(&gifWidth, &gifHeight); - //fillPixX = (seg.width()+(gifWidth-1)) / gifWidth; - //fillPixY = (seg.height()+(gifHeight-1)) / gifHeight; + int result = decoder.decodeFrame(false); if (result < 0) { gifDecodeFailed = true; return IMAGE_ERROR_FRAME_DECODE; } - //long lastFrameDelay = currentFrameDelay; + currentFrameDelay = decoder.getFrameDelay_ms(); - //long tooSlowBy = (millis() - lastFrameDisplayTime) - wait; // if last frame was longer than intended, compensate - //currentFrameDelay -= tooSlowBy; // TODO this is broken + unsigned long tooSlowBy = (millis() - lastFrameDisplayTime) - wait; // if last frame was longer than intended, compensate + currentFrameDelay = tooSlowBy > currentFrameDelay ? 0 : currentFrameDelay - tooSlowBy; lastFrameDisplayTime = millis(); return IMAGE_ERROR_NONE; @@ -129,7 +132,6 @@ void endImagePlayback(Segment *seg) { Serial.println("Image playback end called"); if (!activeSeg || activeSeg != seg) return; if (file) file.close(); - //delete decoder; decoder.dealloc(); gifDecodeFailed = false; activeSeg = nullptr; From 247de600afd3d06918c7c9873e63a756e970ad2b Mon Sep 17 00:00:00 2001 From: Christian Schwinne Date: Sun, 17 Mar 2024 22:57:15 +0100 Subject: [PATCH 004/463] Fix missing GIF enable macros --- platformio.ini | 2 +- wled00/FX.cpp | 6 +++++- wled00/FX_fcn.cpp | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 73d82c3a..c08c632a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -221,7 +221,7 @@ lib_deps = https://github.com/lorol/LITTLEFS.git https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 bitbank2/AnimatedGIF@^1.4.7 - https://github.com/Aircoookie/GifDecoder#e76f58f + https://github.com/Aircoookie/GifDecoder#bc3af18 ${env.lib_deps} # additional build flags for audioreactive AR_build_flags = -D USERMOD_AUDIOREACTIVE diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 48866224..5543b54b 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -4470,12 +4470,16 @@ static const char _data_FX_MODE_WASHING_MACHINE[] PROGMEM = "Washing Machine@!,! Draws a .gif image from filesystem on the matrix/strip */ uint16_t mode_image(void) { + #ifdef WLED_DISABLE_GIF + return mode_static(); + #else renderImageToSegment(SEGMENT); + return FRAMETIME; + #endif // if (status != 0 && status != 254 && status != 255) { // Serial.print("GIF renderer return: "); // Serial.println(status); // } - return FRAMETIME; } static const char _data_FX_MODE_IMAGE[] PROGMEM = "Image@!,;;;12;sx=128"; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 94fdb300..7a2c0057 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -199,7 +199,9 @@ void Segment::resetIfRequired() { if (data && _dataLen > 0) memset(data, 0, _dataLen); // prevent heap fragmentation (just erase buffer instead of deallocateData()) next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0; reset = false; + #ifndef WLED_DISABLE_GIF endImagePlayback(this); + #endif } CRGBPalette16 IRAM_ATTR &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) { From 0c8d9d5614a2e4f0013604cfcac8552cf1646279 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Wed, 3 Apr 2024 18:38:06 +0200 Subject: [PATCH 005/463] Mode blending styles - alternative to #3669 --- wled00/FX.h | 28 ++++++++++ wled00/FX_2Dfcn.cpp | 33 +++++++++++- wled00/FX_fcn.cpp | 123 +++++++++++++++++++++++++++++++++++++----- wled00/data/index.htm | 20 ++++++- wled00/data/index.js | 4 ++ wled00/fcn_declare.h | 1 + wled00/json.cpp | 8 +++ wled00/util.cpp | 7 +++ wled00/wled.h | 3 +- 9 files changed, 212 insertions(+), 15 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 1089a0b8..44c5e154 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -316,6 +316,25 @@ #define MODE_COUNT 187 + +#define BLEND_STYLE_FADE 0 +#define BLEND_STYLE_FAIRY_DUST 1 +#define BLEND_STYLE_SWIPE_RIGHT 2 +#define BLEND_STYLE_SWIPE_LEFT 3 +#define BLEND_STYLE_PINCH_OUT 4 +#define BLEND_STYLE_INSIDE_OUT 5 +#define BLEND_STYLE_SWIPE_UP 6 +#define BLEND_STYLE_SWIPE_DOWN 7 +#define BLEND_STYLE_OPEN_H 8 +#define BLEND_STYLE_OPEN_V 9 +#define BLEND_STYLE_PUSH_TL 10 +#define BLEND_STYLE_PUSH_TR 11 +#define BLEND_STYLE_PUSH_BR 12 +#define BLEND_STYLE_PUSH_BL 13 + +#define BLEND_STYLE_COUNT 14 + + typedef enum mapping1D2D { M12_Pixels = 0, M12_pBar = 1, @@ -419,6 +438,9 @@ typedef struct Segment { static uint16_t _lastPaletteBlend; // blend palette according to set Transition Delay in millis()%0xFFFF #ifndef WLED_DISABLE_MODE_BLEND static bool _modeBlend; // mode/effect blending semaphore + // clipping + static uint16_t _clipStart, _clipStop; + static uint8_t _clipStartY, _clipStopY; #endif // transition data, valid only if transitional==true, holds values during transition (72 bytes) @@ -578,6 +600,10 @@ typedef struct Segment { void setPixelColor(float i, uint32_t c, bool aa = true); inline void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) { setPixelColor(i, RGBW32(r,g,b,w), aa); } inline void setPixelColor(float i, CRGB c, bool aa = true) { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); } + #ifndef WLED_DISABLE_MODE_BLEND + inline void setClippingRect(int startX, int stopX, int startY = 0, int stopY = 1) { _clipStart = startX; _clipStop = stopX; _clipStartY = startY; _clipStopY = stopY; }; + #endif + bool isPixelClipped(int i); uint32_t getPixelColor(int i); // 1D support functions (some implement 2D as well) void blur(uint8_t); @@ -606,6 +632,7 @@ typedef struct Segment { void setPixelColorXY(float x, float y, uint32_t c, bool aa = true); 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); } + bool isPixelXYClipped(int x, int y); uint32_t getPixelColorXY(uint16_t x, uint16_t y); // 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)); } @@ -640,6 +667,7 @@ typedef struct Segment { inline void setPixelColorXY(float x, float y, uint32_t c, bool aa = true) { setPixelColor(x, c, aa); } 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); } + inline bool isPixelXYClipped(int x, int y) { return isPixelClipped(x); } inline uint32_t getPixelColorXY(uint16_t x, uint16_t 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); } diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 7aecd227..7e141929 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -167,10 +167,41 @@ uint16_t IRAM_ATTR Segment::XY(uint16_t x, uint16_t y) return isActive() ? (x%width) + (y%height) * width : 0; } +// pixel is clipped if it falls outside clipping range (_modeBlend==true) or is inside clipping range (_modeBlend==false) +// if clipping start > stop the clipping range is inverted +// _modeBlend==true -> old effect during transition +// _modeBlend==false -> new effect during transition +bool IRAM_ATTR Segment::isPixelXYClipped(int x, int y) { +#ifndef WLED_DISABLE_MODE_BLEND + if (_clipStart != _clipStop && blendingStyle > BLEND_STYLE_FADE) { + const bool invertX = _clipStart > _clipStop; + const bool invertY = _clipStartY > _clipStopY; + const unsigned startX = invertX ? _clipStop : _clipStart; + const unsigned stopX = invertX ? _clipStart : _clipStop; + const unsigned startY = invertY ? _clipStopY : _clipStartY; + const unsigned stopY = invertY ? _clipStartY : _clipStopY; + if (blendingStyle == BLEND_STYLE_FAIRY_DUST) { + const unsigned width = stopX - startX; // assumes full segment width (faster than virtualWidth()) + const unsigned len = width * (stopY - startY); // assumes full segment height (faster than virtualHeight()) + if (len < 2) return false; + const unsigned shuffled = hashInt(x + y * width) % len; + const unsigned pos = (shuffled * 0xFFFFU) / len; + return progress() <= pos; + } + bool xInside = (x >= startX && x < stopX); if (invertX) xInside = !xInside; + bool yInside = (y >= startY && y < stopY); if (invertY) yInside = !yInside; + const bool clip = (invertX && invertY) ? !_modeBlend : _modeBlend; + if (xInside && yInside) return clip; // covers window & corners (inverted) + return !clip; + } +#endif + return false; +} + void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col) { if (!isActive()) return; // not active - if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit + if (x >= virtualWidth() || y >= virtualHeight() || x < 0 || y < 0 || isPixelXYClipped(x,y)) return; // if pixel would fall out of virtual segment just exit uint8_t _bri_t = currentBri(); if (_bri_t < 255) { diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index f97268f9..989809d0 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -84,6 +84,10 @@ uint16_t Segment::_lastPaletteBlend = 0; //in millis (lowest 16 bits only) #ifndef WLED_DISABLE_MODE_BLEND bool Segment::_modeBlend = false; +uint16_t Segment::_clipStart = 0; +uint16_t Segment::_clipStop = 0; +uint8_t Segment::_clipStartY = 0; +uint8_t Segment::_clipStopY = 1; #endif // copy constructor @@ -413,12 +417,17 @@ void Segment::restoreSegenv(tmpsegd_t &tmpSeg) { uint8_t IRAM_ATTR Segment::currentBri(bool useCct) { uint32_t prog = progress(); + uint32_t curBri = useCct ? cct : (on ? opacity : 0); if (prog < 0xFFFFU) { - uint32_t curBri = (useCct ? cct : (on ? opacity : 0)) * prog; - curBri += (useCct ? _t->_cctT : _t->_briT) * (0xFFFFU - prog); + uint8_t tmpBri = useCct ? _t->_cctT : (_t->_segT._optionsT & 0x0004 ? _t->_briT : 0); +#ifndef WLED_DISABLE_MODE_BLEND + if (blendingStyle > BLEND_STYLE_FADE) return _modeBlend ? tmpBri : curBri; // not fade/blend transition, each effect uses its brightness +#endif + curBri *= prog; + curBri += tmpBri * (0xFFFFU - prog); return curBri / 0xFFFFU; } - return (useCct ? cct : (on ? opacity : 0)); + return curBri; } uint8_t IRAM_ATTR Segment::currentMode() { @@ -431,16 +440,23 @@ uint8_t IRAM_ATTR Segment::currentMode() { uint32_t IRAM_ATTR Segment::currentColor(uint8_t slot) { if (slot >= NUM_COLORS) slot = 0; + uint32_t prog = progress(); + if (prog == 0xFFFFU) return colors[slot]; #ifndef WLED_DISABLE_MODE_BLEND - return isInTransition() ? color_blend(_t->_segT._colorT[slot], colors[slot], progress(), true) : colors[slot]; + if (blendingStyle > BLEND_STYLE_FADE) return _modeBlend ? _t->_segT._colorT[slot] : colors[slot]; // not fade/blend transition, each effect uses its color + return color_blend(_t->_segT._colorT[slot], colors[slot], prog, true); #else - return isInTransition() ? color_blend(_t->_colorT[slot], colors[slot], progress(), true) : colors[slot]; + return color_blend(_t->_colorT[slot], colors[slot], prog, true); #endif } CRGBPalette16 IRAM_ATTR &Segment::currentPalette(CRGBPalette16 &targetPalette, uint8_t pal) { loadPalette(targetPalette, pal); uint16_t prog = progress(); +#ifndef WLED_DISABLE_MODE_BLEND + if (prog < 0xFFFFU && blendingStyle > BLEND_STYLE_FADE && _modeBlend) targetPalette = _t->_palT; // not fade/blend transition, each effect uses its palette + else +#endif if (strip.paletteFade && prog < 0xFFFFU) { // blend palettes // there are about 255 blend passes of 48 "blends" to completely blend two palettes (in _dur time) @@ -456,9 +472,9 @@ CRGBPalette16 IRAM_ATTR &Segment::currentPalette(CRGBPalette16 &targetPalette, u void Segment::handleRandomPalette() { // is it time to generate a new palette? if ((millis()/1000U) - _lastPaletteChange > randomPaletteChangeTime) { - _newRandomPalette = useHarmonicRandomPalette ? generateHarmonicRandomPalette(_randomPalette) : generateRandomPalette(); - _lastPaletteChange = millis()/1000U; - _lastPaletteBlend = (uint16_t)(millis() & 0xFFFF)-512; // starts blending immediately + _newRandomPalette = useHarmonicRandomPalette ? generateHarmonicRandomPalette(_randomPalette) : generateRandomPalette(); + _lastPaletteChange = millis()/1000U; + _lastPaletteBlend = (uint16_t)(millis() & 0xFFFF)-512; // starts blending immediately } // if palette transitions is enabled, blend it according to Transition Time (if longer than minimum given by service calls) @@ -662,6 +678,32 @@ uint16_t IRAM_ATTR Segment::virtualLength() const { return vLength; } +// pixel is clipped if it falls outside clipping range (_modeBlend==true) or is inside clipping range (_modeBlend==false) +// if clipping start > stop the clipping range is inverted +// _modeBlend==true -> old effect during transition +// _modeBlend==false -> new effect during transition +bool IRAM_ATTR Segment::isPixelClipped(int i) { +#ifndef WLED_DISABLE_MODE_BLEND + if (_clipStart != _clipStop && blendingStyle > BLEND_STYLE_FADE) { + bool invert = _clipStart > _clipStop; + unsigned start = invert ? _clipStop : _clipStart; + unsigned stop = invert ? _clipStart : _clipStop; + if (blendingStyle == BLEND_STYLE_FAIRY_DUST) { + unsigned len = stop - start; + if (len < 2) return false; + unsigned shuffled = hashInt(i) % len; + unsigned pos = (shuffled * 0xFFFFU) / len; + return progress() <= pos; + } + const bool iInside = (i >= start && i < stop); + if (!invert && iInside) return _modeBlend; + if ( invert && !iInside) return _modeBlend; + return !_modeBlend; + } +#endif + return false; +} + void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col) { if (!isActive()) return; // not active @@ -732,6 +774,8 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col) } #endif + if (isPixelClipped(i)) return; // handle clipping on 1D + uint16_t len = length(); uint8_t _bri_t = currentBri(); if (_bri_t < 255) { @@ -763,14 +807,16 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col) indexMir += offset; // offset/phase if (indexMir >= stop) indexMir -= len; // wrap #ifndef WLED_DISABLE_MODE_BLEND - if (_modeBlend) tmpCol = color_blend(strip.getPixelColor(indexMir), col, 0xFFFFU - progress(), true); + // _modeBlend==true -> old effect + if (_modeBlend && blendingStyle == BLEND_STYLE_FADE) tmpCol = color_blend(strip.getPixelColor(indexMir), col, 0xFFFFU - progress(), true); #endif strip.setPixelColor(indexMir, tmpCol); } indexSet += offset; // offset/phase if (indexSet >= stop) indexSet -= len; // wrap #ifndef WLED_DISABLE_MODE_BLEND - if (_modeBlend) tmpCol = color_blend(strip.getPixelColor(indexSet), col, 0xFFFFU - progress(), true); + // _modeBlend==true -> old effect + if (_modeBlend && blendingStyle == BLEND_STYLE_FADE) tmpCol = color_blend(strip.getPixelColor(indexSet), col, 0xFFFFU - progress(), true); #endif strip.setPixelColor(indexSet, tmpCol); } @@ -1062,7 +1108,7 @@ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_ // paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined) if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end" CRGBPalette16 curPal; - curPal = currentPalette(curPal, palette); + currentPalette(curPal, palette); CRGB fastled_col = ColorFromPalette(curPal, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global return RGBW32(fastled_col.r, fastled_col.g, fastled_col.b, W(color)); @@ -1185,8 +1231,59 @@ void WS2812FX::service() { // overwritten by later effect. To enable seamless blending for every effect, additional LED buffer // would need to be allocated for each effect and then blended together for each pixel. [[maybe_unused]] uint8_t tmpMode = seg.currentMode(); // this will return old mode while in transition - delay = (*_mode[seg.mode])(); // run new/current mode #ifndef WLED_DISABLE_MODE_BLEND + seg.setClippingRect(0, 0); // disable clipping + if (modeBlending && seg.mode != tmpMode) { + // set clipping rectangle + // new mode is run inside clipping area and old mode outside clipping area + unsigned p = seg.progress(); + unsigned w = seg.is2D() ? seg.virtualWidth() : _virtualSegmentLength; + unsigned h = seg.virtualHeight(); + unsigned dw = p * w / 0xFFFFU + 1; + unsigned dh = p * h / 0xFFFFU + 1; + switch (blendingStyle) { + case BLEND_STYLE_FAIRY_DUST: // fairy dust (must set entire segment, see isPixelXYClipped()) + seg.setClippingRect(0, w, 0, h); + break; + case BLEND_STYLE_SWIPE_RIGHT: // left-to-right + seg.setClippingRect(0, dw, 0, h); + break; + case BLEND_STYLE_SWIPE_LEFT: // right-to-left + seg.setClippingRect(w - dw, w, 0, h); + break; + case BLEND_STYLE_PINCH_OUT: // corners + seg.setClippingRect((w + dw)/2, (w - dw)/2, (h + dh)/2, (h - dh)/2); // inverted!! + break; + case BLEND_STYLE_INSIDE_OUT: // outward + seg.setClippingRect((w - dw)/2, (w + dw)/2, (h - dh)/2, (h + dh)/2); + break; + case BLEND_STYLE_SWIPE_DOWN: // top-to-bottom (2D) + seg.setClippingRect(0, w, 0, dh); + break; + case BLEND_STYLE_SWIPE_UP: // bottom-to-top (2D) + seg.setClippingRect(0, w, h - dh, h); + break; + case BLEND_STYLE_OPEN_H: // horizontal-outward (2D) same look as INSIDE_OUT on 1D + seg.setClippingRect((w - dw)/2, (w + dw)/2, 0, h); + break; + case BLEND_STYLE_OPEN_V: // vertical-outward (2D) + seg.setClippingRect(0, w, (h - dh)/2, (h + dh)/2); + break; + case BLEND_STYLE_PUSH_TL: // TL-to-BR (2D) + seg.setClippingRect(0, dw, 0, dh); + break; + case BLEND_STYLE_PUSH_TR: // TR-to-BL (2D) + seg.setClippingRect(w - dw, w, 0, dh); + break; + case BLEND_STYLE_PUSH_BR: // BR-to-TL (2D) + seg.setClippingRect(w - dw, w, h - dh, h); + break; + case BLEND_STYLE_PUSH_BL: // BL-to-TR (2D) + seg.setClippingRect(0, dw, h - dh, h); + break; + } + } + delay = (*_mode[seg.mode])(); // run new/current mode if (modeBlending && seg.mode != tmpMode) { Segment::tmpsegd_t _tmpSegData; Segment::modeBlend(true); // set semaphore @@ -1197,6 +1294,8 @@ void WS2812FX::service() { delay = MIN(delay,d2); // use shortest delay Segment::modeBlend(false); // unset semaphore } +#else + delay = (*_mode[seg.mode])(); // run effect mode #endif seg.call++; if (seg.isInTransition() && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition diff --git a/wled00/data/index.htm b/wled00/data/index.htm index 4a532abb..dc143176 100644 --- a/wled00/data/index.htm +++ b/wled00/data/index.htm @@ -265,7 +265,25 @@
-

Transition:  s

+

Transition:  s

+

Blend: + +

diff --git a/wled00/data/index.js b/wled00/data/index.js index 4ad2044a..1a50b6a3 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -1426,6 +1426,9 @@ function readState(s,command=false) tr = s.transition; gId('tt').value = tr/10; + gId('bs').value = s.bs || 0; + if (tr===0) gId('bsp').classList.add('hide') + else gId('bsp').classList.remove('hide') populateSegments(s); var selc=0; @@ -1682,6 +1685,7 @@ function requestJson(command=null) var tn = parseInt(t.value*10); if (tn != tr) command.transition = tn; } + //command.bs = parseInt(gId('bs').value); req = JSON.stringify(command); if (req.length > 1340) useWs = false; // do not send very long requests over websocket if (req.length > 500 && lastinfo && lastinfo.arch == "esp8266") useWs = false; // esp8266 can only handle 500 bytes diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index f1b013e9..9a843dbf 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -383,6 +383,7 @@ uint16_t crc16(const unsigned char* data_p, size_t length); um_data_t* simulateSound(uint8_t simulationId); void enumerateLedmaps(); uint8_t get_random_wheel_index(uint8_t pos); +uint32_t hashInt(uint32_t s); // RAII guard class for the JSON Buffer lock // Modeled after std::lock_guard diff --git a/wled00/json.cpp b/wled00/json.cpp index fd1527a2..bde6c36c 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -355,6 +355,11 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) } } +#ifndef WLED_DISABLE_MODE_BLEND + blendingStyle = root[F("bs")] | blendingStyle; + blendingStyle = constrain(blendingStyle, 0, BLEND_STYLE_COUNT-1); +#endif + // temporary transition (applies only once) tr = root[F("tt")] | -1; if (tr >= 0) { @@ -581,6 +586,9 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme root["on"] = (bri > 0); root["bri"] = briLast; root[F("transition")] = transitionDelay/100; //in 100ms +#ifndef WLED_DISABLE_MODE_BLEND + root[F("bs")] = blendingStyle; +#endif } if (!forPreset) { diff --git a/wled00/util.cpp b/wled00/util.cpp index ad7e4b67..eabd3e38 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -599,3 +599,10 @@ uint8_t get_random_wheel_index(uint8_t pos) { } return r; } + +uint32_t hashInt(uint32_t s) { + // borrowed from https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key + s = ((s >> 16) ^ s) * 0x45d9f3b; + s = ((s >> 16) ^ s) * 0x45d9f3b; + return (s >> 16) ^ s; +} diff --git a/wled00/wled.h b/wled00/wled.h index 35b99260..a58e1cea 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2403280 +#define VERSION 2404030 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG @@ -547,6 +547,7 @@ WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random co // transitions WLED_GLOBAL bool fadeTransition _INIT(true); // enable crossfading brightness/color WLED_GLOBAL bool modeBlending _INIT(true); // enable effect blending +WLED_GLOBAL uint8_t blendingStyle _INIT(0); // effect blending/transitionig style WLED_GLOBAL bool transitionActive _INIT(false); WLED_GLOBAL uint16_t transitionDelay _INIT(750); // global transition duration WLED_GLOBAL uint16_t transitionDelayDefault _INIT(750); // default transition time (stored in cfg.json) From f5199d2b73bb3b516b7d98b4fee8b2af2b688c07 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Wed, 3 Apr 2024 20:55:59 +0200 Subject: [PATCH 006/463] Fix compile. --- wled00/FX_fcn.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 989809d0..bd5758e3 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -419,9 +419,11 @@ uint8_t IRAM_ATTR Segment::currentBri(bool useCct) { uint32_t prog = progress(); uint32_t curBri = useCct ? cct : (on ? opacity : 0); if (prog < 0xFFFFU) { - uint8_t tmpBri = useCct ? _t->_cctT : (_t->_segT._optionsT & 0x0004 ? _t->_briT : 0); #ifndef WLED_DISABLE_MODE_BLEND + uint8_t tmpBri = useCct ? _t->_cctT : (_t->_segT._optionsT & 0x0004 ? _t->_briT : 0); if (blendingStyle > BLEND_STYLE_FADE) return _modeBlend ? tmpBri : curBri; // not fade/blend transition, each effect uses its brightness +#else + uint8_t tmpBri = useCct ? _t->_cctT : _t->_briT; #endif curBri *= prog; curBri += tmpBri * (0xFFFFU - prog); From a3a8fa1cef1f54c2d1028a0c3e5a5fcc6ef8235e Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Mon, 8 Apr 2024 16:24:27 +0200 Subject: [PATCH 007/463] Remove conditional fade/blend - transitions always enabled (use delay 0 to disable) - optimisation in on/off fade - fix for palette/color blend when blending style is not fade - various tweaks and optimisations --- CHANGELOG.md | 3 + .../stairway-wipe-usermod-v2.h | 2 +- .../stairway_wipe_basic/wled06_usermod.ino | 111 ------------------ wled00/FX.cpp | 61 +++++----- wled00/FX.h | 7 +- wled00/FX_2Dfcn.cpp | 10 +- wled00/FX_fcn.cpp | 104 ++++++++-------- wled00/bus_manager.cpp | 6 +- wled00/bus_manager.h | 3 +- wled00/cfg.cpp | 14 +-- wled00/data/settings_leds.htm | 7 +- wled00/fcn_declare.h | 1 - wled00/json.cpp | 6 +- wled00/led.cpp | 54 +++------ wled00/playlist.cpp | 2 +- wled00/set.cpp | 9 +- wled00/udp.cpp | 6 +- wled00/wled.cpp | 6 +- wled00/wled.h | 2 - wled00/wled_eeprom.cpp | 2 +- wled00/xml.cpp | 5 +- 21 files changed, 135 insertions(+), 286 deletions(-) delete mode 100644 usermods/stairway_wipe_basic/wled06_usermod.ino diff --git a/CHANGELOG.md b/CHANGELOG.md index 46f6df2d..0d86c8b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## WLED changelog +#### Build 2404050 +- Blending styles (with help from @tkadauke) + #### Build 2403280 - Individual color channel control for JSON API (fixes #3860) - "col":[int|string|object|array, int|string|object|array, int|string|object|array] diff --git a/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h b/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h index f712316b..707479df 100644 --- a/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h +++ b/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h @@ -96,7 +96,7 @@ void setup() { jsonTransitionOnce = true; strip.setTransition(0); //no transition effectCurrent = FX_MODE_COLOR_WIPE; - resetTimebase(); //make sure wipe starts from beginning + strip.resetTimebase(); //make sure wipe starts from beginning //set wipe direction Segment& seg = strip.getSegment(0); diff --git a/usermods/stairway_wipe_basic/wled06_usermod.ino b/usermods/stairway_wipe_basic/wled06_usermod.ino deleted file mode 100644 index c1264ebf..00000000 --- a/usermods/stairway_wipe_basic/wled06_usermod.ino +++ /dev/null @@ -1,111 +0,0 @@ -/* - * This file allows you to add own functionality to WLED more easily - * See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality - * EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in wled_eeprom.h) - * bytes 2400+ are currently ununsed, but might be used for future wled features - */ - -//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t) - -byte wipeState = 0; //0: inactive 1: wiping 2: solid -unsigned long timeStaticStart = 0; -uint16_t previousUserVar0 = 0; - -//comment this out if you want the turn off effect to be just fading out instead of reverse wipe -#define STAIRCASE_WIPE_OFF - -//gets called once at boot. Do all initialization that doesn't depend on network here -void userSetup() -{ - //setup PIR sensor here, if needed -} - -//gets called every time WiFi is (re-)connected. Initialize own network interfaces here -void userConnected() -{ - -} - -//loop. You can use "if (WLED_CONNECTED)" to check for successful connection -void userLoop() -{ - //userVar0 (U0 in HTTP API): - //has to be set to 1 if movement is detected on the PIR that is the same side of the staircase as the ESP8266 - //has to be set to 2 if movement is detected on the PIR that is the opposite side - //can be set to 0 if no movement is detected. Otherwise LEDs will turn off after a configurable timeout (userVar1 seconds) - - if (userVar0 > 0) - { - if ((previousUserVar0 == 1 && userVar0 == 2) || (previousUserVar0 == 2 && userVar0 == 1)) wipeState = 3; //turn off if other PIR triggered - previousUserVar0 = userVar0; - - if (wipeState == 0) { - startWipe(); - wipeState = 1; - } else if (wipeState == 1) { //wiping - uint32_t cycleTime = 360 + (255 - effectSpeed)*75; //this is how long one wipe takes (minus 25 ms to make sure we switch in time) - if (millis() + strip.timebase > (cycleTime - 25)) { //wipe complete - effectCurrent = FX_MODE_STATIC; - timeStaticStart = millis(); - colorUpdated(CALL_MODE_NOTIFICATION); - wipeState = 2; - } - } else if (wipeState == 2) { //static - if (userVar1 > 0) //if U1 is not set, the light will stay on until second PIR or external command is triggered - { - if (millis() - timeStaticStart > userVar1*1000) wipeState = 3; - } - } else if (wipeState == 3) { //switch to wipe off - #ifdef STAIRCASE_WIPE_OFF - effectCurrent = FX_MODE_COLOR_WIPE; - strip.timebase = 360 + (255 - effectSpeed)*75 - millis(); //make sure wipe starts fully lit - colorUpdated(CALL_MODE_NOTIFICATION); - wipeState = 4; - #else - turnOff(); - #endif - } else { //wiping off - if (millis() + strip.timebase > (725 + (255 - effectSpeed)*150)) turnOff(); //wipe complete - } - } else { - wipeState = 0; //reset for next time - if (previousUserVar0) { - #ifdef STAIRCASE_WIPE_OFF - userVar0 = previousUserVar0; - wipeState = 3; - #else - turnOff(); - #endif - } - previousUserVar0 = 0; - } -} - -void startWipe() -{ - bri = briLast; //turn on - transitionDelayTemp = 0; //no transition - effectCurrent = FX_MODE_COLOR_WIPE; - resetTimebase(); //make sure wipe starts from beginning - - //set wipe direction - Segment& seg = strip.getSegment(0); - bool doReverse = (userVar0 == 2); - seg.setOption(1, doReverse); - - colorUpdated(CALL_MODE_NOTIFICATION); -} - -void turnOff() -{ - #ifdef STAIRCASE_WIPE_OFF - transitionDelayTemp = 0; //turn off immediately after wipe completed - #else - transitionDelayTemp = 4000; //fade out slowly - #endif - bri = 0; - stateUpdated(CALL_MODE_NOTIFICATION); - wipeState = 0; - userVar0 = 0; - previousUserVar0 = 0; -} diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 14341f5b..e75e20cd 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -1211,8 +1211,9 @@ static const char _data_FX_MODE_COMET[] PROGMEM = "Lighthouse@!,Fade rate;!,!;!" */ uint16_t mode_fireworks() { if (SEGLEN == 1) return mode_static(); - const uint16_t width = SEGMENT.is2D() ? SEGMENT.virtualWidth() : SEGMENT.virtualLength(); - const uint16_t height = SEGMENT.virtualHeight(); + const unsigned width = SEGMENT.is2D() ? SEGMENT.virtualWidth() : SEGMENT.virtualLength(); + const unsigned height = SEGMENT.virtualHeight(); + const unsigned dimension = width * height; if (SEGENV.call == 0) { SEGENV.aux0 = UINT16_MAX; @@ -1220,19 +1221,19 @@ 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 + bool valid1 = (SEGENV.aux0 < dimension); + bool valid2 = (SEGENV.aux1 < dimension); + unsigned 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 (!SEGENV.step) SEGMENT.blur(dimension > 100 ? 16 : 8); 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) { - uint16_t index = random16(width*height); + unsigned index = random16(dimension); x = index % width; y = index / width; uint32_t col = SEGMENT.color_from_palette(random8(), false, false, 0); @@ -2066,41 +2067,41 @@ uint16_t mode_fire_2012() { struct virtualStrip { static void runStrip(uint16_t stripNr, byte* heat, uint32_t it) { - const uint8_t ignition = max(3,SEGLEN/10); // ignition area: 10% of segment length or minimum 3 pixels + const unsigned ignition = max(3,SEGLEN/10); // ignition area: 10% of segment length or minimum 3 pixels // Step 1. Cool down every cell a little - for (int i = 0; i < SEGLEN; i++) { - uint8_t cool = (it != SEGENV.step) ? random8((((20 + SEGMENT.speed/3) * 16) / SEGLEN)+2) : random8(4); - uint8_t minTemp = (i 1; k--) { + for (unsigned k = SEGLEN -1; k > 1; k--) { heat[k] = (heat[k - 1] + (heat[k - 2]<<1) ) / 3; // heat[k-2] multiplied by 2 } // Step 3. Randomly ignite new 'sparks' of heat near the bottom if (random8() <= SEGMENT.intensity) { - uint8_t y = random8(ignition); - uint8_t boost = (17+SEGMENT.custom3) * (ignition - y/2) / ignition; // integer math! + unsigned y = random8(ignition); + unsigned boost = (17+SEGMENT.custom3) * (ignition - y/2) / ignition; // integer math! heat[y] = qadd8(heat[y], random8(96+2*boost,207+boost)); } } // 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],240), 255, LINEARBLEND_NOWRAP)); } } }; - for (int stripNr=0; stripNr 100 ? 32 : 0); if (it != SEGENV.step) SEGENV.step = it; @@ -4856,9 +4857,9 @@ static const char _data_FX_MODE_FLOWSTRIPE[] PROGMEM = "Flow Stripe@Hue speed,Ef uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulmatelights.com/gallery/1012 , Modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const uint16_t cols = SEGMENT.virtualWidth(); - const uint16_t rows = SEGMENT.virtualHeight(); - uint16_t x, y; + const unsigned cols = SEGMENT.virtualWidth(); + const unsigned rows = SEGMENT.virtualHeight(); + unsigned x, y; SEGMENT.fadeToBlackBy(16 + (SEGMENT.speed>>3)); // create fading trails unsigned long t = strip.now/128; // timebase @@ -4877,7 +4878,7 @@ uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulma // central white dot SEGMENT.setPixelColorXY(cols/2, rows/2, WHITE); // blur everything a bit - SEGMENT.blur(16); + SEGMENT.blur(sqrt16(cols*rows) > 100 ? 16 : 0); return FRAMETIME; } // mode_2DBlackHole() @@ -6436,8 +6437,8 @@ static const char _data_FX_MODE_2DSWIRL[] PROGMEM = "Swirl@!,Sensitivity,Blur;,B uint16_t mode_2DWaverly(void) { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const uint16_t cols = SEGMENT.virtualWidth(); - const uint16_t rows = SEGMENT.virtualHeight(); + const unsigned cols = SEGMENT.virtualWidth(); + const unsigned rows = SEGMENT.virtualHeight(); um_data_t *um_data; if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { @@ -6449,21 +6450,21 @@ uint16_t mode_2DWaverly(void) { SEGMENT.fadeToBlackBy(SEGMENT.speed); long t = strip.now / 2; - for (int i = 0; i < cols; i++) { - uint16_t thisVal = (1 + SEGMENT.intensity/64) * inoise8(i * 45 , t , t)/2; + for (unsigned i = 0; i < cols; i++) { + unsigned thisVal = (1 + SEGMENT.intensity/64) * inoise8(i * 45 , t , t)/2; // use audio if available if (um_data) { thisVal /= 32; // reduce intensity of inoise8() thisVal *= volumeSmth; } - uint16_t thisMax = map(thisVal, 0, 512, 0, rows); + unsigned thisMax = map(thisVal, 0, 512, 0, rows); - for (int j = 0; j < thisMax; j++) { + for (unsigned j = 0; j < thisMax; j++) { SEGMENT.addPixelColorXY(i, j, ColorFromPalette(SEGPALETTE, map(j, 0, thisMax, 250, 0), 255, LINEARBLEND)); SEGMENT.addPixelColorXY((cols - 1) - i, (rows - 1) - j, ColorFromPalette(SEGPALETTE, map(j, 0, thisMax, 250, 0), 255, LINEARBLEND)); } } - SEGMENT.blur(16); + SEGMENT.blur(sqrt16(cols*rows) > 100 ? 16 : 0); return FRAMETIME; } // mode_2DWaverly() diff --git a/wled00/FX.h b/wled00/FX.h index 44c5e154..fd0bb297 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -601,7 +601,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); } #ifndef WLED_DISABLE_MODE_BLEND - inline void setClippingRect(int startX, int stopX, int startY = 0, int stopY = 1) { _clipStart = startX; _clipStop = stopX; _clipStartY = startY; _clipStopY = stopY; }; + static inline void setClippingRect(int startX, int stopX, int startY = 0, int stopY = 1) { _clipStart = startX; _clipStop = stopX; _clipStartY = startY; _clipStopY = stopY; }; #endif bool isPixelClipped(int i); uint32_t getPixelColor(int i); @@ -708,9 +708,7 @@ class WS2812FX { // 96 bytes public: WS2812FX() : - paletteFade(0), paletteBlend(0), - cctBlending(0), now(millis()), timebase(0), isMatrix(false), @@ -792,6 +790,7 @@ class WS2812FX { // 96 bytes addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name), // add effect to the list; defined in FX.cpp setupEffectData(void); // add default effects to the list; defined in FX.cpp + inline void resetTimebase() { timebase = 0U - millis(); } inline void restartRuntime() { for (Segment &seg : _segments) seg.markForReset(); } inline void setTransitionMode(bool t) { for (Segment &seg : _segments) seg.startTransition(t ? _transitionDur : 0); } inline void setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setColor(slot, RGBW32(r,g,b,w)); } @@ -806,7 +805,6 @@ class WS2812FX { // 96 bytes inline void resume(void) { _suspend = false; } // will resume strip.service() execution bool - paletteFade, checkSegmentAlignment(void), hasRGBWBus(void), hasCCTBus(void), @@ -822,7 +820,6 @@ class WS2812FX { // 96 bytes uint8_t paletteBlend, - cctBlending, getActiveSegmentsNum(void), getFirstSelectedSegId(void), getLastActiveSegmentId(void), diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 7e141929..a37e5d11 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -176,10 +176,10 @@ bool IRAM_ATTR Segment::isPixelXYClipped(int x, int y) { if (_clipStart != _clipStop && blendingStyle > BLEND_STYLE_FADE) { const bool invertX = _clipStart > _clipStop; const bool invertY = _clipStartY > _clipStopY; - const unsigned startX = invertX ? _clipStop : _clipStart; - const unsigned stopX = invertX ? _clipStart : _clipStop; - const unsigned startY = invertY ? _clipStopY : _clipStartY; - const unsigned stopY = invertY ? _clipStartY : _clipStopY; + const int startX = invertX ? _clipStop : _clipStart; + const int stopX = invertX ? _clipStart : _clipStop; + const int startY = invertY ? _clipStopY : _clipStartY; + const int stopY = invertY ? _clipStartY : _clipStopY; if (blendingStyle == BLEND_STYLE_FAIRY_DUST) { const unsigned width = stopX - startX; // assumes full segment width (faster than virtualWidth()) const unsigned len = width * (stopY - startY); // assumes full segment height (faster than virtualHeight()) @@ -295,7 +295,7 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa) // returns RGBW values of pixel uint32_t IRAM_ATTR Segment::getPixelColorXY(uint16_t x, uint16_t y) { 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 (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0 || isPixelXYClipped(x,y)) 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) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 00196e38..4ef110e0 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -293,21 +293,17 @@ void Segment::startTransition(uint16_t dur) { _t->_briT = on ? opacity : 0; _t->_cctT = cct; #ifndef WLED_DISABLE_MODE_BLEND - if (modeBlending) { - swapSegenv(_t->_segT); - _t->_modeT = mode; - _t->_segT._dataLenT = 0; - _t->_segT._dataT = nullptr; - if (_dataLen > 0 && data) { - _t->_segT._dataT = (byte *)malloc(_dataLen); - if (_t->_segT._dataT) { - //DEBUG_PRINTF_P(PSTR("-- Allocated duplicate data (%d) for %p: %p\n"), _dataLen, this, _t->_segT._dataT); - memcpy(_t->_segT._dataT, data, _dataLen); - _t->_segT._dataLenT = _dataLen; - } + swapSegenv(_t->_segT); + _t->_modeT = mode; + _t->_segT._dataLenT = 0; + _t->_segT._dataT = nullptr; + if (_dataLen > 0 && data) { + _t->_segT._dataT = (byte *)malloc(_dataLen); + if (_t->_segT._dataT) { + //DEBUG_PRINTF_P(PSTR("-- Allocated duplicate data (%d) for %p: %p\n"), _dataLen, this, _t->_segT._dataT); + memcpy(_t->_segT._dataT, data, _dataLen); + _t->_segT._dataLenT = _dataLen; } - } else { - for (size_t i=0; i_segT._colorT[i] = colors[i]; } #else for (size_t i=0; i_colorT[i] = colors[i]; @@ -435,7 +431,7 @@ uint8_t IRAM_ATTR Segment::currentBri(bool useCct) { uint8_t IRAM_ATTR Segment::currentMode() { #ifndef WLED_DISABLE_MODE_BLEND uint16_t prog = progress(); - if (modeBlending && prog < 0xFFFFU) return _t->_modeT; + if (prog < 0xFFFFU) return _t->_modeT; #endif return mode; } @@ -445,7 +441,7 @@ uint32_t IRAM_ATTR Segment::currentColor(uint8_t slot) { uint32_t prog = progress(); if (prog == 0xFFFFU) return colors[slot]; #ifndef WLED_DISABLE_MODE_BLEND - if (blendingStyle > BLEND_STYLE_FADE) return _modeBlend ? _t->_segT._colorT[slot] : colors[slot]; // not fade/blend transition, each effect uses its color + if (blendingStyle > BLEND_STYLE_FADE && mode != _t->_modeT) return _modeBlend ? _t->_segT._colorT[slot] : colors[slot]; // not fade/blend transition, each effect uses its color return color_blend(_t->_segT._colorT[slot], colors[slot], prog, true); #else return color_blend(_t->_colorT[slot], colors[slot], prog, true); @@ -456,10 +452,10 @@ CRGBPalette16 IRAM_ATTR &Segment::currentPalette(CRGBPalette16 &targetPalette, u loadPalette(targetPalette, pal); uint16_t prog = progress(); #ifndef WLED_DISABLE_MODE_BLEND - if (prog < 0xFFFFU && blendingStyle > BLEND_STYLE_FADE && _modeBlend) targetPalette = _t->_palT; // not fade/blend transition, each effect uses its palette + if (prog < 0xFFFFU && blendingStyle > BLEND_STYLE_FADE && _modeBlend && mode != _t->_modeT) targetPalette = _t->_palT; // not fade/blend transition, each effect uses its palette else #endif - if (strip.paletteFade && prog < 0xFFFFU) { + if (prog < 0xFFFFU) { // blend palettes // there are about 255 blend passes of 48 "blends" to completely blend two palettes (in _dur time) // minimum blend time is 100ms maximum is 65535ms @@ -473,19 +469,16 @@ CRGBPalette16 IRAM_ATTR &Segment::currentPalette(CRGBPalette16 &targetPalette, u // relies on WS2812FX::service() to call it for each frame void Segment::handleRandomPalette() { // is it time to generate a new palette? - if ((uint16_t)(millis() / 1000U) - _lastPaletteChange > randomPaletteChangeTime){ - _newRandomPalette = useHarmonicRandomPalette ? generateHarmonicRandomPalette(_randomPalette) : generateRandomPalette(); - _lastPaletteChange = (uint16_t)(millis() / 1000U); - _lastPaletteBlend = (uint16_t)millis() - 512; // starts blending immediately + if ((uint16_t)(millis()/1000U) - _lastPaletteChange > randomPaletteChangeTime) { + _newRandomPalette = useHarmonicRandomPalette ? generateHarmonicRandomPalette(_randomPalette) : generateRandomPalette(); + _lastPaletteChange = (uint16_t)(millis()/1000U); + _lastPaletteBlend = (uint16_t)(millis())-512; // starts blending immediately } - // if palette transitions is enabled, blend it according to Transition Time (if longer than minimum given by service calls) - if (strip.paletteFade) { - // assumes that 128 updates are sufficient to blend a palette, so shift by 7 (can be more, can be less) - // in reality there need to be 255 blends to fully blend two entirely different palettes - if ((uint16_t)((uint16_t)millis() - _lastPaletteBlend) < strip.getTransition() >> 7) return; // not yet time to fade, delay the update - _lastPaletteBlend = (uint16_t)millis(); - } + // assumes that 128 updates are sufficient to blend a palette, so shift by 7 (can be more, can be less) + // in reality there need to be 255 blends to fully blend two entirely different palettes + if ((uint16_t)millis() - _lastPaletteBlend < strip.getTransition() >> 7) return; // not yet time to fade, delay the update + _lastPaletteBlend = (uint16_t)millis(); nblendPaletteTowardPalette(_randomPalette, _newRandomPalette, 48); } @@ -549,7 +542,7 @@ bool Segment::setColor(uint8_t slot, uint32_t c) { //returns true if changed if (slot == 0 && c == BLACK) return false; // on/off segment cannot have primary color black if (slot == 1 && c != BLACK) return false; // on/off segment cannot have secondary color non black } - if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change + startTransition(strip.getTransition()); // start transition prior to change colors[slot] = c; stateChanged = true; // send UDP/WS broadcast return true; @@ -562,21 +555,21 @@ void Segment::setCCT(uint16_t k) { k = (k - 1900) >> 5; } if (cct == k) return; - if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change + startTransition(strip.getTransition()); // start transition prior to change cct = k; stateChanged = true; // send UDP/WS broadcast } void Segment::setOpacity(uint8_t o) { if (opacity == o) return; - if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change + startTransition(strip.getTransition()); // start transition prior to change opacity = o; stateChanged = true; // send UDP/WS broadcast } void Segment::setOption(uint8_t n, bool val) { bool prevOn = on; - if (fadeTransition && n == SEG_OPTION_ON && val != prevOn) startTransition(strip.getTransition()); // start transition prior to change + if (n == SEG_OPTION_ON && val != prevOn) startTransition(strip.getTransition()); // start transition prior to change if (val) options |= 0x01 << n; else options &= ~(0x01 << n); if (!(n == SEG_OPTION_SELECTED || n == SEG_OPTION_RESET)) stateChanged = true; // send UDP/WS broadcast @@ -589,7 +582,7 @@ void Segment::setMode(uint8_t fx, bool loadDefaults) { // if we have a valid mode & is not reserved if (fx != mode) { #ifndef WLED_DISABLE_MODE_BLEND - if (modeBlending) startTransition(strip.getTransition()); // set effect transitions + startTransition(strip.getTransition()); // set effect transitions #endif mode = fx; // load default values from effect string @@ -620,7 +613,7 @@ void Segment::setPalette(uint8_t pal) { if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0; // built in palettes if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0; // custom palettes if (pal != palette) { - if (strip.paletteFade) startTransition(strip.getTransition()); + startTransition(strip.getTransition()); palette = pal; stateChanged = true; // send UDP/WS broadcast } @@ -688,8 +681,8 @@ bool IRAM_ATTR Segment::isPixelClipped(int i) { #ifndef WLED_DISABLE_MODE_BLEND if (_clipStart != _clipStop && blendingStyle > BLEND_STYLE_FADE) { bool invert = _clipStart > _clipStop; - unsigned start = invert ? _clipStop : _clipStart; - unsigned stop = invert ? _clipStart : _clipStop; + int start = invert ? _clipStop : _clipStart; + int stop = invert ? _clipStart : _clipStop; if (blendingStyle == BLEND_STYLE_FAIRY_DUST) { unsigned len = stop - start; if (len < 2) return false; @@ -888,6 +881,8 @@ uint32_t IRAM_ATTR Segment::getPixelColor(int i) } #endif + if (isPixelClipped(i)) return 0; // handle clipping on 1D + if (reverse) i = virtualLength() - i - 1; i *= groupLength(); i += start; @@ -1234,8 +1229,8 @@ void WS2812FX::service() { // would need to be allocated for each effect and then blended together for each pixel. [[maybe_unused]] uint8_t tmpMode = seg.currentMode(); // this will return old mode while in transition #ifndef WLED_DISABLE_MODE_BLEND - seg.setClippingRect(0, 0); // disable clipping - if (modeBlending && seg.mode != tmpMode) { + Segment::setClippingRect(0, 0); // disable clipping (just in case) + if (seg.mode != tmpMode) { // could try seg.isInTransition() to allow color and palette to follow blending styles // set clipping rectangle // new mode is run inside clipping area and old mode outside clipping area unsigned p = seg.progress(); @@ -1245,48 +1240,48 @@ void WS2812FX::service() { unsigned dh = p * h / 0xFFFFU + 1; switch (blendingStyle) { case BLEND_STYLE_FAIRY_DUST: // fairy dust (must set entire segment, see isPixelXYClipped()) - seg.setClippingRect(0, w, 0, h); + Segment::setClippingRect(0, w, 0, h); break; case BLEND_STYLE_SWIPE_RIGHT: // left-to-right - seg.setClippingRect(0, dw, 0, h); + Segment::setClippingRect(0, dw, 0, h); break; case BLEND_STYLE_SWIPE_LEFT: // right-to-left - seg.setClippingRect(w - dw, w, 0, h); + Segment::setClippingRect(w - dw, w, 0, h); break; case BLEND_STYLE_PINCH_OUT: // corners - seg.setClippingRect((w + dw)/2, (w - dw)/2, (h + dh)/2, (h - dh)/2); // inverted!! + Segment::setClippingRect((w + dw)/2, (w - dw)/2, (h + dh)/2, (h - dh)/2); // inverted!! break; case BLEND_STYLE_INSIDE_OUT: // outward - seg.setClippingRect((w - dw)/2, (w + dw)/2, (h - dh)/2, (h + dh)/2); + Segment::setClippingRect((w - dw)/2, (w + dw)/2, (h - dh)/2, (h + dh)/2); break; case BLEND_STYLE_SWIPE_DOWN: // top-to-bottom (2D) - seg.setClippingRect(0, w, 0, dh); + Segment::setClippingRect(0, w, 0, dh); break; case BLEND_STYLE_SWIPE_UP: // bottom-to-top (2D) - seg.setClippingRect(0, w, h - dh, h); + Segment::setClippingRect(0, w, h - dh, h); break; case BLEND_STYLE_OPEN_H: // horizontal-outward (2D) same look as INSIDE_OUT on 1D - seg.setClippingRect((w - dw)/2, (w + dw)/2, 0, h); + Segment::setClippingRect((w - dw)/2, (w + dw)/2, 0, h); break; case BLEND_STYLE_OPEN_V: // vertical-outward (2D) - seg.setClippingRect(0, w, (h - dh)/2, (h + dh)/2); + Segment::setClippingRect(0, w, (h - dh)/2, (h + dh)/2); break; case BLEND_STYLE_PUSH_TL: // TL-to-BR (2D) - seg.setClippingRect(0, dw, 0, dh); + Segment::setClippingRect(0, dw, 0, dh); break; case BLEND_STYLE_PUSH_TR: // TR-to-BL (2D) - seg.setClippingRect(w - dw, w, 0, dh); + Segment::setClippingRect(w - dw, w, 0, dh); break; case BLEND_STYLE_PUSH_BR: // BR-to-TL (2D) - seg.setClippingRect(w - dw, w, h - dh, h); + Segment::setClippingRect(w - dw, w, h - dh, h); break; case BLEND_STYLE_PUSH_BL: // BL-to-TR (2D) - seg.setClippingRect(0, dw, h - dh, h); + Segment::setClippingRect(0, dw, h - dh, h); break; } } delay = (*_mode[seg.mode])(); // run new/current mode - if (modeBlending && seg.mode != tmpMode) { + if (seg.mode != tmpMode) { // could try seg.isInTransition() to allow color and palette to follow blending styles Segment::tmpsegd_t _tmpSegData; Segment::modeBlend(true); // set semaphore seg.swapSegenv(_tmpSegData); // temporarily store new mode state (and swap it with transitional state) @@ -1301,13 +1296,14 @@ void WS2812FX::service() { #endif seg.call++; if (seg.isInTransition() && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition - BusManager::setSegmentCCT(oldCCT); // restore old CCT for ABL adjustments + BusManager::setSegmentCCT(oldCCT); // restore old CCT for ABL adjustments } seg.next_time = nowUp + delay; } _segment_index++; } + Segment::setClippingRect(0, 0); // disable clipping for overlays _virtualSegmentLength = 0; _isServicing = false; _triggered = false; diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 82e81a38..02a76f69 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -391,14 +391,14 @@ BusPwm::BusPwm(BusConfig &bc) uint8_t numPins = NUM_PWM_PINS(bc.type); _frequency = bc.frequency ? bc.frequency : WLED_PWM_FREQ; - #ifdef ESP8266 +#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 +#else _ledcStart = pinManager.allocateLedc(numPins); if (_ledcStart == 255) { //no more free LEDC channels deallocatePins(); return; @@ -408,7 +408,7 @@ BusPwm::BusPwm(BusConfig &bc) else if (_frequency > 39062) _depth = 10; else if (_frequency > 19531) _depth = 11; else _depth = 12; // WLED_PWM_FREQ <= 19531Hz - #endif +#endif for (unsigned i = 0; i < numPins; i++) { uint8_t currentPin = bc.pins[i]; diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index c128f8c0..cdd1e82f 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -173,10 +173,11 @@ class Bus { type == TYPE_FW1906 || type == TYPE_WS2805 ) return true; return false; } - static int16_t getCCT() { return _cct; } + static inline int16_t getCCT() { return _cct; } static void setCCT(int16_t cct) { _cct = cct; } + static inline uint8_t getCCTBlend() { return _cctBlend; } static void setCCTBlend(uint8_t b) { if (b > 100) b = 100; _cctBlend = (b * 127) / 100; diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 530777ab..01c407f9 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -111,8 +111,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { CJSON(correctWB, hw_led["cct"]); CJSON(cctFromRgb, hw_led[F("cr")]); CJSON(cctICused, hw_led[F("ic")]); - CJSON(strip.cctBlending, hw_led[F("cb")]); - Bus::setCCTBlend(strip.cctBlending); + uint8_t cctBlending = hw_led[F("cb")] | Bus::getCCTBlend(); + Bus::setCCTBlend(cctBlending); strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS CJSON(useGlobalLedBuffer, hw_led[F("ld")]); @@ -408,12 +408,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { } JsonObject light_tr = light["tr"]; - CJSON(fadeTransition, light_tr["mode"]); - CJSON(modeBlending, light_tr["fx"]); int tdd = light_tr["dur"] | -1; if (tdd >= 0) transitionDelay = transitionDelayDefault = tdd * 100; - strip.setTransition(fadeTransition ? transitionDelayDefault : 0); - CJSON(strip.paletteFade, light_tr["pal"]); + strip.setTransition(transitionDelayDefault); CJSON(randomPaletteChangeTime, light_tr[F("rpc")]); CJSON(useHarmonicRandomPalette, light_tr[F("hrp")]); @@ -777,7 +774,7 @@ void serializeConfig() { hw_led["cct"] = correctWB; hw_led[F("cr")] = cctFromRgb; hw_led[F("ic")] = cctICused; - hw_led[F("cb")] = strip.cctBlending; + hw_led[F("cb")] = Bus::getCCTBlend(); hw_led["fps"] = strip.getTargetFps(); hw_led[F("rgbwm")] = Bus::getGlobalAWMode(); // global auto white mode override hw_led[F("ld")] = useGlobalLedBuffer; @@ -894,10 +891,7 @@ void serializeConfig() { light_gc["val"] = gammaCorrectVal; JsonObject light_tr = light.createNestedObject("tr"); - light_tr["mode"] = fadeTransition; - light_tr["fx"] = modeBlending; light_tr["dur"] = transitionDelayDefault / 100; - light_tr["pal"] = strip.paletteFade; light_tr[F("rpc")] = randomPaletteChangeTime; light_tr[F("hrp")] = useHarmonicRandomPalette; diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index dddedd47..2a526782 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -834,12 +834,7 @@ Swap:

Brightness factor: %

Transitions

- Enable transitions:
- - Effect blending:
- Transition Time: ms
- Palette transitions:
-
+ Transition Time: ms
Random Cycle Palette Time: s
Use harmonic Random Cycle Palette:

Timed light

diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 010ad3a5..85893dfa 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -181,7 +181,6 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0); void setValuesFromSegment(uint8_t s); void setValuesFromMainSeg(); void setValuesFromFirstSelectedSeg(); -void resetTimebase(); void toggleOnOff(); void applyBri(); void applyFinalBri(); diff --git a/wled00/json.cpp b/wled00/json.cpp index 269d8a7f..2e00ec09 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -351,7 +351,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) tr = root[F("transition")] | -1; if (tr >= 0) { transitionDelay = tr * 100; - if (fadeTransition) strip.setTransition(transitionDelay); + strip.setTransition(transitionDelay); } } @@ -364,7 +364,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) tr = root[F("tt")] | -1; if (tr >= 0) { jsonTransitionOnce = true; - if (fadeTransition) strip.setTransition(tr * 100); + strip.setTransition(tr * 100); } tr = root[F("tb")] | -1; @@ -779,7 +779,7 @@ void serializeInfo(JsonObject root) root[F("freeheap")] = ESP.getFreeHeap(); #if defined(ARDUINO_ARCH_ESP32) - if (psramSafe && psramFound()) root[F("psram")] = ESP.getFreePsram(); + if (psramFound()) root[F("psram")] = ESP.getFreePsram(); #endif root[F("uptime")] = millis()/1000 + rolloverMillis*4294967; diff --git a/wled00/led.cpp b/wled00/led.cpp index 23c8d03c..acfa3ac3 100644 --- a/wled00/led.cpp +++ b/wled00/led.cpp @@ -47,12 +47,6 @@ void applyValuesToSelectedSegs() } -void resetTimebase() -{ - strip.timebase = 0 - millis(); -} - - void toggleOnOff() { if (bri == 0) @@ -76,7 +70,7 @@ byte scaledBri(byte in) } -//applies global brightness +//applies global temporary brightness (briT) to strip void applyBri() { if (!realtimeMode || !arlsForceMaxBri) { @@ -90,6 +84,7 @@ void applyFinalBri() { briOld = bri; briT = bri; applyBri(); + strip.trigger(); // force one last update } @@ -122,7 +117,7 @@ void stateUpdated(byte callMode) { nightlightStartTime = millis(); } if (briT == 0) { - if (callMode != CALL_MODE_NOTIFICATION) resetTimebase(); //effect start from beginning + if (callMode != CALL_MODE_NOTIFICATION) strip.resetTimebase(); //effect start from beginning } if (bri > 0) briLast = bri; @@ -133,31 +128,24 @@ void stateUpdated(byte callMode) { // notify usermods of state change usermods.onStateChange(callMode); - if (fadeTransition) { - if (strip.getTransition() == 0) { - jsonTransitionOnce = false; - transitionActive = false; - applyFinalBri(); - strip.trigger(); - return; - } - - if (transitionActive) { - briOld = briT; - tperLast = 0; - } else - strip.setTransitionMode(true); // force all segments to transition mode - transitionActive = true; - transitionStartTime = millis(); - } else { + if (strip.getTransition() == 0) { + jsonTransitionOnce = false; + transitionActive = false; applyFinalBri(); - strip.trigger(); + return; } + + if (transitionActive) { + briOld = briT; + tperLast = 0; + } else + strip.setTransitionMode(true); // force all segments to transition mode + transitionActive = true; + transitionStartTime = millis(); } -void updateInterfaces(uint8_t callMode) -{ +void updateInterfaces(uint8_t callMode) { if (!interfaceUpdateCallMode || millis() - lastInterfaceUpdate < INTERFACE_UPDATE_COOLDOWN) return; sendDataWs(); @@ -178,8 +166,7 @@ void updateInterfaces(uint8_t callMode) } -void handleTransitions() -{ +void handleTransitions() { //handle still pending interface update updateInterfaces(interfaceUpdateCallMode); @@ -198,7 +185,6 @@ void handleTransitions() if (tper - tperLast < 0.004f) return; tperLast = tper; briT = briOld + ((bri - briOld) * tper); - applyBri(); } } @@ -211,8 +197,7 @@ void colorUpdated(byte callMode) { } -void handleNightlight() -{ +void handleNightlight() { unsigned long now = millis(); if (now < 100 && lastNlUpdate > 0) lastNlUpdate = 0; // take care of millis() rollover if (now - lastNlUpdate < 100) return; // allow only 10 NL updates per second @@ -292,7 +277,6 @@ void handleNightlight() } //utility for FastLED to use our custom timer -uint32_t get_millisecond_timer() -{ +uint32_t get_millisecond_timer() { return strip.now; } diff --git a/wled00/playlist.cpp b/wled00/playlist.cpp index 67c4f604..225102da 100644 --- a/wled00/playlist.cpp +++ b/wled00/playlist.cpp @@ -146,7 +146,7 @@ void handlePlaylist() { } jsonTransitionOnce = true; - strip.setTransition(fadeTransition ? playlistEntries[playlistIndex].tr * 100 : 0); + strip.setTransition(playlistEntries[playlistIndex].tr * 100); playlistEntryDur = playlistEntries[playlistIndex].dur; applyPresetFromPlaylist(playlistEntries[playlistIndex].preset); } diff --git a/wled00/set.cpp b/wled00/set.cpp index a2e884c8..c5b9f262 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -128,8 +128,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) correctWB = request->hasArg(F("CCT")); cctFromRgb = request->hasArg(F("CR")); cctICused = request->hasArg(F("IC")); - strip.cctBlending = request->arg(F("CB")).toInt(); - Bus::setCCTBlend(strip.cctBlending); + uint8_t cctBlending = request->arg(F("CB")).toInt(); + Bus::setCCTBlend(cctBlending); Bus::setGlobalAWMode(request->arg(F("AW")).toInt()); strip.setTargetFps(request->arg(F("FR")).toInt()); useGlobalLedBuffer = request->hasArg(F("LD")); @@ -313,11 +313,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) gammaCorrectCol = false; } - fadeTransition = request->hasArg(F("TF")); - modeBlending = request->hasArg(F("EB")); t = request->arg(F("TD")).toInt(); if (t >= 0) transitionDelayDefault = t; - strip.paletteFade = request->hasArg(F("PF")); t = request->arg(F("TP")).toInt(); randomPaletteChangeTime = MIN(255,MAX(1,t)); useHarmonicRandomPalette = request->hasArg(F("TH")); @@ -1124,7 +1121,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) pos = req.indexOf(F("TT=")); if (pos > 0) transitionDelay = getNumVal(&req, pos); - if (fadeTransition) strip.setTransition(transitionDelay); + strip.setTransition(transitionDelay); //set time (unix timestamp) pos = req.indexOf(F("ST=")); diff --git a/wled00/udp.cpp b/wled00/udp.cpp index 100ace16..d2f49144 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -225,10 +225,8 @@ void parseNotifyPacket(uint8_t *udpIn) { // set transition time before making any segment changes if (version > 3) { - if (fadeTransition) { - jsonTransitionOnce = true; - strip.setTransition(((udpIn[17] << 0) & 0xFF) + ((udpIn[18] << 8) & 0xFF00)); - } + jsonTransitionOnce = true; + strip.setTransition(((udpIn[17] << 0) & 0xFF) + ((udpIn[18] << 8) & 0xFF00)); } //apply colors from notification to main segment, only if not syncing full segments diff --git a/wled00/wled.cpp b/wled00/wled.cpp index eb786085..8f64a10e 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -538,10 +538,10 @@ void WLED::beginStrip() } else { // fix for #3196 if (bootPreset > 0) { - bool oldTransition = fadeTransition; // workaround if transitions are enabled - fadeTransition = false; // ignore transitions temporarily + uint16_t oldTransition = strip.getTransition(); // workaround if transitions are enabled + strip.setTransition(0); // ignore transitions temporarily strip.setColor(0, BLACK); // set all segments black - fadeTransition = oldTransition; // restore transitions + strip.setTransition(oldTransition); // restore transitions col[0] = col[1] = col[2] = col[3] = 0; // needed for colorUpdated() } briLast = briS; bri = 0; diff --git a/wled00/wled.h b/wled00/wled.h index 5a9b8dcf..8e21343f 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -545,8 +545,6 @@ WLED_GLOBAL bool wasConnected _INIT(false); WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same // transitions -WLED_GLOBAL bool fadeTransition _INIT(true); // enable crossfading brightness/color -WLED_GLOBAL bool modeBlending _INIT(true); // enable effect blending WLED_GLOBAL uint8_t blendingStyle _INIT(0); // effect blending/transitionig style WLED_GLOBAL bool transitionActive _INIT(false); WLED_GLOBAL uint16_t transitionDelay _INIT(750); // global transition duration diff --git a/wled00/wled_eeprom.cpp b/wled00/wled_eeprom.cpp index 4f2c14d4..a43c23e8 100755 --- a/wled00/wled_eeprom.cpp +++ b/wled00/wled_eeprom.cpp @@ -220,7 +220,7 @@ void loadSettingsFromEEPROM() if (lastEEPROMversion > 7) { - strip.paletteFade = EEPROM.read(374); + //strip.paletteFade = EEPROM.read(374); strip.paletteBlend = EEPROM.read(382); for (int i = 0; i < 8; ++i) diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 3915d9b0..e9c1fac4 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -357,7 +357,7 @@ void getSettingsJS(byte subPage, char* dest) sappend('c',SET_F("CCT"),correctWB); sappend('c',SET_F("IC"),cctICused); sappend('c',SET_F("CR"),cctFromRgb); - sappend('v',SET_F("CB"),strip.cctBlending); + sappend('v',SET_F("CB"),Bus::getCCTBlend()); sappend('v',SET_F("FR"),strip.getTargetFps()); sappend('v',SET_F("AW"),Bus::getGlobalAWMode()); sappend('c',SET_F("LD"),useGlobalLedBuffer); @@ -445,10 +445,7 @@ void getSettingsJS(byte subPage, char* dest) sappend('c',SET_F("GB"),gammaCorrectBri); sappend('c',SET_F("GC"),gammaCorrectCol); dtostrf(gammaCorrectVal,3,1,nS); sappends('s',SET_F("GV"),nS); - sappend('c',SET_F("TF"),fadeTransition); - sappend('c',SET_F("EB"),modeBlending); sappend('v',SET_F("TD"),transitionDelayDefault); - sappend('c',SET_F("PF"),strip.paletteFade); sappend('v',SET_F("TP"),randomPaletteChangeTime); sappend('c',SET_F("TH"),useHarmonicRandomPalette); sappend('v',SET_F("BF"),briMultiplier); From ef017fd343bc0329125c52681015fc6b85284be1 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sun, 14 Apr 2024 15:34:59 +0200 Subject: [PATCH 008/463] Revert FX.cpp --- wled00/FX.cpp | 61 +++++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index e75e20cd..14341f5b 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -1211,9 +1211,8 @@ static const char _data_FX_MODE_COMET[] PROGMEM = "Lighthouse@!,Fade rate;!,!;!" */ uint16_t mode_fireworks() { if (SEGLEN == 1) return mode_static(); - const unsigned width = SEGMENT.is2D() ? SEGMENT.virtualWidth() : SEGMENT.virtualLength(); - const unsigned height = SEGMENT.virtualHeight(); - const unsigned dimension = width * height; + const uint16_t width = SEGMENT.is2D() ? SEGMENT.virtualWidth() : SEGMENT.virtualLength(); + const uint16_t height = SEGMENT.virtualHeight(); if (SEGENV.call == 0) { SEGENV.aux0 = UINT16_MAX; @@ -1221,19 +1220,19 @@ uint16_t mode_fireworks() { } SEGMENT.fade_out(128); - bool valid1 = (SEGENV.aux0 < dimension); - bool valid2 = (SEGENV.aux1 < dimension); - unsigned x = SEGENV.aux0%width, y = SEGENV.aux0/width; // 2D coordinates stored in upper and lower byte + 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(dimension > 100 ? 16 : 8); + 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 - for (unsigned i=0; i> 1)) == 0) { - unsigned index = random16(dimension); + uint16_t index = random16(width*height); x = index % width; y = index / width; uint32_t col = SEGMENT.color_from_palette(random8(), false, false, 0); @@ -2067,41 +2066,41 @@ uint16_t mode_fire_2012() { struct virtualStrip { static void runStrip(uint16_t stripNr, byte* heat, uint32_t it) { - const unsigned ignition = max(3,SEGLEN/10); // ignition area: 10% of segment length or minimum 3 pixels + const uint8_t ignition = max(3,SEGLEN/10); // ignition area: 10% of segment length or minimum 3 pixels // Step 1. Cool down every cell a little - for (unsigned i = 0; i < SEGLEN; i++) { - unsigned cool = (it != SEGENV.step) ? random8((((20 + SEGMENT.speed/3) * 16) / SEGLEN)+2) : random8(4); - unsigned minTemp = (i 1; k--) { + for (int k = SEGLEN -1; k > 1; k--) { heat[k] = (heat[k - 1] + (heat[k - 2]<<1) ) / 3; // heat[k-2] multiplied by 2 } // Step 3. Randomly ignite new 'sparks' of heat near the bottom if (random8() <= SEGMENT.intensity) { - unsigned y = random8(ignition); - unsigned boost = (17+SEGMENT.custom3) * (ignition - y/2) / ignition; // integer math! + uint8_t y = random8(ignition); + uint8_t boost = (17+SEGMENT.custom3) * (ignition - y/2) / ignition; // integer math! heat[y] = qadd8(heat[y], random8(96+2*boost,207+boost)); } } // 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, LINEARBLEND_NOWRAP)); + SEGMENT.setPixelColor(indexToVStrip(j, stripNr), ColorFromPalette(SEGPALETTE, MIN(heat[j],240), 255, NOBLEND)); } } }; - for (unsigned stripNr=0; stripNr 100 ? 32 : 0); + if (SEGMENT.is2D()) SEGMENT.blur(32); if (it != SEGENV.step) SEGENV.step = it; @@ -4857,9 +4856,9 @@ static const char _data_FX_MODE_FLOWSTRIPE[] PROGMEM = "Flow Stripe@Hue speed,Ef uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulmatelights.com/gallery/1012 , Modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const unsigned cols = SEGMENT.virtualWidth(); - const unsigned rows = SEGMENT.virtualHeight(); - unsigned x, y; + const uint16_t cols = SEGMENT.virtualWidth(); + const uint16_t rows = SEGMENT.virtualHeight(); + uint16_t x, y; SEGMENT.fadeToBlackBy(16 + (SEGMENT.speed>>3)); // create fading trails unsigned long t = strip.now/128; // timebase @@ -4878,7 +4877,7 @@ uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulma // central white dot SEGMENT.setPixelColorXY(cols/2, rows/2, WHITE); // blur everything a bit - SEGMENT.blur(sqrt16(cols*rows) > 100 ? 16 : 0); + SEGMENT.blur(16); return FRAMETIME; } // mode_2DBlackHole() @@ -6437,8 +6436,8 @@ static const char _data_FX_MODE_2DSWIRL[] PROGMEM = "Swirl@!,Sensitivity,Blur;,B uint16_t mode_2DWaverly(void) { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const unsigned cols = SEGMENT.virtualWidth(); - const unsigned rows = SEGMENT.virtualHeight(); + const uint16_t cols = SEGMENT.virtualWidth(); + const uint16_t rows = SEGMENT.virtualHeight(); um_data_t *um_data; if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { @@ -6450,21 +6449,21 @@ uint16_t mode_2DWaverly(void) { SEGMENT.fadeToBlackBy(SEGMENT.speed); long t = strip.now / 2; - for (unsigned i = 0; i < cols; i++) { - unsigned thisVal = (1 + SEGMENT.intensity/64) * inoise8(i * 45 , t , t)/2; + for (int i = 0; i < cols; i++) { + uint16_t thisVal = (1 + SEGMENT.intensity/64) * inoise8(i * 45 , t , t)/2; // use audio if available if (um_data) { thisVal /= 32; // reduce intensity of inoise8() thisVal *= volumeSmth; } - unsigned thisMax = map(thisVal, 0, 512, 0, rows); + uint16_t thisMax = map(thisVal, 0, 512, 0, rows); - for (unsigned j = 0; j < thisMax; j++) { + for (int j = 0; j < thisMax; j++) { SEGMENT.addPixelColorXY(i, j, ColorFromPalette(SEGPALETTE, map(j, 0, thisMax, 250, 0), 255, LINEARBLEND)); SEGMENT.addPixelColorXY((cols - 1) - i, (rows - 1) - j, ColorFromPalette(SEGPALETTE, map(j, 0, thisMax, 250, 0), 255, LINEARBLEND)); } } - SEGMENT.blur(sqrt16(cols*rows) > 100 ? 16 : 0); + SEGMENT.blur(16); return FRAMETIME; } // mode_2DWaverly() From da484b07f5bda6d0a955e389658971e4b18f18f1 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sun, 2 Jun 2024 21:30:44 +0200 Subject: [PATCH 009/463] Use transition style for palette and color change - as requested by @willmmiles & @tkadauke --- wled00/FX.h | 2 ++ wled00/FX_fcn.cpp | 63 +++++++++++++++++++++++++++++++---------------- 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index cb9cafb2..acca0b20 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -457,6 +457,7 @@ typedef struct Segment { #else uint32_t _colorT[NUM_COLORS]; #endif + uint8_t _palTid; // previous palette uint8_t _briT; // temporary brightness uint8_t _cctT; // temporary CCT CRGBPalette16 _palT; // temporary palette @@ -594,6 +595,7 @@ typedef struct Segment { 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) + uint8_t currentPalette(void); // currently active palette (while in transition) uint32_t currentColor(uint8_t slot); // currently active segment color (blended while in transition) CRGBPalette16 &loadPalette(CRGBPalette16 &tgt, uint8_t pal); void setCurrentPalette(void); diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 29302bfb..df06e56a 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -291,6 +291,7 @@ void Segment::startTransition(uint16_t dur) { //DEBUG_PRINTF_P(PSTR("-- Started transition: %p (%p)\n"), this, _t); loadPalette(_t->_palT, palette); + _t->_palTid = palette; _t->_briT = on ? opacity : 0; _t->_cctT = cct; #ifndef WLED_DISABLE_MODE_BLEND @@ -442,27 +443,43 @@ uint32_t IRAM_ATTR Segment::currentColor(uint8_t slot) { uint32_t prog = progress(); if (prog == 0xFFFFU) return colors[slot]; #ifndef WLED_DISABLE_MODE_BLEND - if (blendingStyle > BLEND_STYLE_FADE && mode != _t->_modeT) return _modeBlend ? _t->_segT._colorT[slot] : colors[slot]; // not fade/blend transition, each effect uses its color + if (blendingStyle > BLEND_STYLE_FADE) return _modeBlend ? _t->_segT._colorT[slot] : colors[slot]; // not fade/blend transition, each effect uses its color return color_blend(_t->_segT._colorT[slot], colors[slot], prog, true); #else return color_blend(_t->_colorT[slot], colors[slot], prog, true); #endif } +uint8_t IRAM_ATTR Segment::currentPalette() { + unsigned prog = progress(); + if (prog < 0xFFFFU) { +#ifndef WLED_DISABLE_MODE_BLEND + if (blendingStyle > BLEND_STYLE_FADE && _modeBlend) return _t->_palTid; +#else + return _t->_palTid; +#endif + } + return palette; +} + void Segment::setCurrentPalette() { loadPalette(_currentPalette, palette); unsigned prog = progress(); -#ifndef WLED_DISABLE_MODE_BLEND - if (prog < 0xFFFFU && blendingStyle > BLEND_STYLE_FADE && _modeBlend && mode != _t->_modeT) _currentPalette = _t->_palT; // not fade/blend transition, each effect uses its palette - else -#endif if (prog < 0xFFFFU) { - // blend palettes - // there are about 255 blend passes of 48 "blends" to completely blend two palettes (in _dur time) - // minimum blend time is 100ms maximum is 65535ms - unsigned noOfBlends = ((255U * prog) / 0xFFFFU) - _t->_prevPaletteBlends; - for (unsigned i = 0; i < noOfBlends; i++, _t->_prevPaletteBlends++) nblendPaletteTowardPalette(_t->_palT, _currentPalette, 48); - _currentPalette = _t->_palT; // copy transitioning/temporary palette +#ifndef WLED_DISABLE_MODE_BLEND + if (blendingStyle > BLEND_STYLE_FADE) { + //if (_modeBlend) loadPalette(_currentPalette, _t->_palTid); // not fade/blend transition, each effect uses its palette + if (_modeBlend) _currentPalette = _t->_palT; // not fade/blend transition, each effect uses its palette + } else +#endif + { + // blend palettes + // there are about 255 blend passes of 48 "blends" to completely blend two palettes (in _dur time) + // minimum blend time is 100ms maximum is 65535ms + unsigned noOfBlends = ((255U * prog) / 0xFFFFU) - _t->_prevPaletteBlends; + for (unsigned i = 0; i < noOfBlends; i++, _t->_prevPaletteBlends++) nblendPaletteTowardPalette(_t->_palT, _currentPalette, 48); + _currentPalette = _t->_palT; // copy transitioning/temporary palette + } } } @@ -719,7 +736,7 @@ uint16_t IRAM_ATTR Segment::virtualLength() const { bool IRAM_ATTR Segment::isPixelClipped(int i) { #ifndef WLED_DISABLE_MODE_BLEND if (_clipStart != _clipStop && blendingStyle > BLEND_STYLE_FADE) { - bool invert = _clipStart > _clipStop; + bool invert = _clipStart > _clipStop; // ineverted start & stop int start = invert ? _clipStop : _clipStart; int stop = invert ? _clipStart : _clipStop; if (blendingStyle == BLEND_STYLE_FAIRY_DUST) { @@ -727,12 +744,13 @@ bool IRAM_ATTR Segment::isPixelClipped(int i) { if (len < 2) return false; unsigned shuffled = hashInt(i) % len; unsigned pos = (shuffled * 0xFFFFU) / len; - return progress() <= pos; + return (progress() <= pos) ^ _modeBlend; } const bool iInside = (i >= start && i < stop); - if (!invert && iInside) return _modeBlend; - if ( invert && !iInside) return _modeBlend; - return !_modeBlend; + //if (!invert && iInside) return _modeBlend; + //if ( invert && !iInside) return _modeBlend; + //return !_modeBlend; + return !iInside ^ invert ^ _modeBlend; // thanks @willmmiles (https://github.com/Aircoookie/WLED/pull/3877#discussion_r1554633876) } #endif return false; @@ -1220,7 +1238,7 @@ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_ uint32_t color = gamma32(currentColor(mcol)); // default palette or no RGB support on segment - if ((palette == 0 && mcol < NUM_COLORS) || !_isRGB) return (pbri == 255) ? color : color_fade(color, pbri, true); + if ((currentPalette() == 0 && mcol < NUM_COLORS) || !_isRGB) return (pbri == 255) ? color : color_fade(color, pbri, true); unsigned paletteIndex = i; if (mapping && virtualLength() > 1) paletteIndex = (i*255)/(virtualLength() -1); @@ -1313,6 +1331,7 @@ void WS2812FX::service() { now = nowUp + timebase; if (nowUp - _lastShow < MIN_SHOW_DELAY || _suspend) return; bool doShow = false; + int pal = -1; // optimise palette loading _isServicing = true; _segment_index = 0; @@ -1339,7 +1358,8 @@ void WS2812FX::service() { _colors_t[0] = gamma32(seg.currentColor(0)); _colors_t[1] = gamma32(seg.currentColor(1)); _colors_t[2] = gamma32(seg.currentColor(2)); - seg.setCurrentPalette(); // load actual palette + if (seg.currentPalette() != pal) seg.setCurrentPalette(); // load actual palette + pal = seg.currentPalette(); // when correctWB is true we need to correct/adjust RGB value according to desired CCT value, but it will also affect actual WW/CW ratio // when cctFromRgb is true we implicitly calculate WW and CW from RGB values if (cctFromRgb) BusManager::setSegmentCCT(-1); @@ -1350,10 +1370,10 @@ void WS2812FX::service() { // The blending will largely depend on the effect behaviour since actual output (LEDs) may be // overwritten by later effect. To enable seamless blending for every effect, additional LED buffer // would need to be allocated for each effect and then blended together for each pixel. - [[maybe_unused]] uint8_t tmpMode = seg.currentMode(); // this will return old mode while in transition #ifndef WLED_DISABLE_MODE_BLEND + uint8_t tmpMode = seg.currentMode(); // this will return old mode while in transition Segment::setClippingRect(0, 0); // disable clipping (just in case) - if (seg.mode != tmpMode) { // could try seg.isInTransition() to allow color and palette to follow blending styles + if (seg.isInTransition()) { // set clipping rectangle // new mode is run inside clipping area and old mode outside clipping area unsigned p = seg.progress(); @@ -1404,11 +1424,12 @@ void WS2812FX::service() { } } delay = (*_mode[seg.mode])(); // run new/current mode - if (seg.mode != tmpMode) { // could try seg.isInTransition() to allow color and palette to follow blending styles + if (seg.isInTransition()) { Segment::tmpsegd_t _tmpSegData; Segment::modeBlend(true); // set semaphore seg.swapSegenv(_tmpSegData); // temporarily store new mode state (and swap it with transitional state) _virtualSegmentLength = seg.virtualLength(); // update SEGLEN (mapping may have changed) + seg.setCurrentPalette(); // load actual palette unsigned d2 = (*_mode[tmpMode])(); // run old mode seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state) delay = MIN(delay,d2); // use shortest delay From b9849da66e9d7c052e314a1d1eda0531a4939ffd Mon Sep 17 00:00:00 2001 From: Brandon502 <105077712+Brandon502@users.noreply.github.com> Date: Sat, 8 Jun 2024 13:16:56 -0400 Subject: [PATCH 010/463] Added Cube Mapping tool --- tools/AutoCubeMap.xlsx | Bin 0 -> 80009 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tools/AutoCubeMap.xlsx diff --git a/tools/AutoCubeMap.xlsx b/tools/AutoCubeMap.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..b3f5cee2ad32ae887d6cc62d6667a05c61a8ac35 GIT binary patch literal 80009 zcmeFXWmFv9x;085Sb*T}?(PsExCVE3cXxujyL)gAuE8}p!67)o-Q^b9@@DUIzH`UE zl{68ARzX1WE0Zx%Ypg=VQZLA%Q ztQ~a}-E55PvwfCBgb-`D?Q21XNCq(K=G0#81927j`F(|C+zq|v^0 zC?VMZOK{f3Zn2uiL|t87AnL^kKoH+DW^X;pxcJ1*UF5=Tp?UTm+UhisgSIsfq{_d> zTRwDd-C$Q8MQj**+b>vR^i7}D%WW}xhUhoHG9KkTvM_e}yvkfT)gY)Wm3~6juv^AY zhKlZ`WCY_aE7T?a-AY`Z^X$(5U%e)e-%NU2MEl z9J^gDSyOV>u#)H)$z&lcK+H8UTIEEX7bmwBF?fs=;WxQ z?sU0Qx*5$TRs-w%Na`*RcSC0)?H#~^8^}P*9)9S~au+fzqSm>!`ZJq7f3$I$$G`5$ zXdRbx?0vxI<3|oU;Bfwtqw+b_-xbYobguJ-O3ipA+Ly)U^8+5dnq#^{1yTz71||0b z_cxa#S{!vwFO>_5r3=DxNA^31OIZ1k!Cy(bE}xAO>Si+s1!4xfsic0uZ6^|oZf0`_ zv3bCyu&y$hc)cKlfV{kbfyn+#EY~YB5MKfgDg}fp3=qpY_C}Tt^mMP||Bd1Q#ew?= z^zyh*GCd5iK__C5!GkxmD=`QHk}mvWt%Qo+pT(Eq>m&0?uva?CaS#--{J}(h+Pxo# zmsUPR?hg`PZ?KeyBcX5;H@H*;CEwdQK~j;~CyCgVulFK4&tA=5r;19rQ8>3pQG^A3vV%Gne$` z7aU&*r_|w8D(awvzR5zR=b$Cw)g6|Sf+?q2wSJa87m=Heq2;#=q4ZAVCr?`Gj6r!K z7NlFIanS+NoGTyoI+nAMOt)Tk=$^8{(;>fb{Nh!hto_#@!S7Qn?gIk>IfVuRfd`mz zwWN2kvA58-v9Wk9cI8S|HX9rW&)!qd!4zxL^P$Lb#g4+Ob&12J`U}_6rHZM&EOHml zQ3}PSPbb{(0|XYbnvRL8Yj`ehF~>L0?slEjC}biU-LxW=JcASimBcf5W_whhc%xZG zmDKsm640Fb`uCYFX2;R9pSg5qAMNDkqThii9;tp0F#Vuq6CaUS$5V!_+%;UgLyF3< z1@FFOD>BVyAe9hkO<;IH`kmUz|L2(k!~QmtjH)WR)(}(7i^r)jBZs)C^D+ z`R937b@^ntk2L2*=;J)ar3s-fce1k?bnl=%B594juUquM6Prfpk*jhomX0E8H(tqS zys7IT^g`hi;p&GJt>)$RpNl1Q7IYfiGGdG$)XofDt^FtGpvsYmj5JD}^Fw!O z)RY=il?V<9=OFMwgA9mqNdyt%gcw!Dy8K$u6YFf1YqOfsxQ470nyEEDtr^TssyXx_ zsOo91j+5F7v6Q&<{pLScyle;`Tfu`L+}Jh4uB~NKFK@9P;jN~GAj$=Mv6a(bZ1N%P zm$5HhXq!M^=zFLKyV&pFV*0ifEx~v|i$;BapjyZ4@CmJe=8wX(u*0~=s(~$L8#Bz~ z^gS`?VO-$|^ZCfId>xnOOteI%ArP$un#!Y|Hg#3)7dyB8i#ig$?#Z;)XByUm&+uDq z`O22%Y{#&``@}0N?ZPYba`XAmIa%<*W!`6OGQtq{c8G7{zb~UF0rz4o2}%1sl76kZ z_tQ+)9dTqmoc9&U5HG(AK)`?qX(A-j3-A!R$1Cjk3|ilzQmTD9wkYRk-Ib#}a=wWF zwbWMTxSL*qCV#PU;2LYmhG#G<`0NL9%G8eJ_iYP?Ll9I1ZHPCRW9KYJvhL2_(nq$ie2dDV7o-wwVFBk8XZsSamZYYa6GtTBtU#Sl{VIb$<4x*dT> zvlKmP$3(?NVOATsuOVM@J1R_f2)jt#{EC40>&NS(%G;X4q&CM`17aeva^Yd^nQZ7Id_rC0ZKE?x$QHeQ*y2a5rfij11> z$`OGc+NpacT+;?taT zrF;~S9i)&a+jo>x%H;hK)%=zkgLo;`Q2na&2K1A0fua%%61>5KXU709&9QU~p^R=O zlNG-kh8$=GOQE?7_|vr$vS9)T{h~a}mq0&W|9qE`n-erqgPTf-)3?wS)TT#X$;>;3 zaOzDHjuRVVM&)RDd`D5uV}2BnvDT_M!U|sk&3}mv9?`-oC`oiL4*CcEh(>^kJXP&1 zQ`#M4p|$BU)4K_#ixF`NnJ*Q&+kGPunsnDw$*OFLed)Ck8nb117Iv1Ek&Jm?r935} zzA3dWNbuTK5>y39IOek7r8F~UP$-^g#yJk!XgIW%6rj0l&U26(9S3MfsWj;r8L2h?us zi%qzIi{6xeYMbX30Gk4i+vc*uXyhq|&}p@PyWAJbyGNS7ezmmrDeJDg$o@8|M+aCI3 zll|(lPdbp6Wb|(@T8%G`*!em=9==1G#3!(=QiK2Uhy55tfH??d2+Q;))o=9U4gpLI z>EJsz%=B+PZZ?LCwU|R_4gwAf2+d!B!xBPs zKX6z9^&)1}f^a_g@@=eQ^BY~r+Xnc>ww>?5%Q?MzVv?KA?z1xnK9u@gDUpSvrz$xQOqagp2!JK;RYg zW)Oh{4AVD)pNv2u26GU{@J;PoHQ#c6HqsJp$D1>cV^nF47~Da;EfD*+oW7UtLi9qG zyLi|w14+jUAAHKT;8j&{~LMH8+-abFc;J?`4%*x<*K3rF>xiOpXoXm7eto=IHLdq(B zz{xhXT^9ym?^gY1e^W21TdA>m{+6hZ;c7;BVO z)wFs>SLt)9N() zL|&L`u!~~IFoZyd_XMIb$YNEZmjYY0r1J07n{T5N{FLdOi3@WQ!&~Pomi=g{^U^h56g$ z_k4RdOiNHC#HN0p8WqZluXXMyQU%8Sjn~WHylMlyQvDKj%E(G+i^x>SLHUzb64@}& z013G`SxQiz7*kH4Dy@mnyCPqw<2oC1!6l$B-1 zh2;ENN~ZPkrO)+~i1S{`9$i54zeM=_vMqWM{=N**bJ z4bI$+r?>$7$Ax@a;_SJ*JZ^~`4}GD!!3pXf=wyPa2n)G70&S@Bd+_sby0QGAFI>$8 z2uQpLA;uaV$cuM30+moxlCFD$IvURbd?EH9mQ|>7N&IfANf!~1Lf;FC<{`(T*e1MK z>a-J};u!L(5!EmpdftlK>&@RyM855*zR*J#7coS)5aG>q7K}xrQr8|Men~Vgc9mXU zmuFTKK|_XITg{Bt`2l;?e-vyIs8WJSMGRTrhL=zZci>hsCZ{}dAYP)**y{Gn?AB*4 zermg>Q@I#ZSkQ@zrEoUFRJx8p9jOB69cvH80M#V;_n6aA*8BxDJJWDgM>~7(&7^%$>6923QTTyPe)JQ3QicjJ_J@PUW zmf*-y?hQn>M#B7GNlC%oq9u$!sLRVEWR+DYn%JIc2Hv=J6jYEi?sGUL>=@Q(T#|_3 zlJnSeT}!)ZK^8f0pQhLN@J?Y(@2NE^wtlM2mU`crdK*7&LUL(m_qh1bFkc(}%t$ z+pn}-%VT^uLfNfuMbf-4ctVZYLPgm^RoV6{NiQ!H?#~p?(eTa27F|K=mTnf@c|4Q8 zdt#16an@OK>!u8dusp?67xyS(W^2_K?nsMpaNJc8xhsR!7tNaUeSVoLWh(^p6xJSQ zT#8U^!xQ28+SN+eg=2S~^TqgP4TYb3Lr=e=#IP*+<{XF@hVQ-;R)wCEZr7~`Iv+iyHR2IBjBW({T1yYyYzYxRzqmbgU?S;l3XGn0w6P8pYbKZ~Q{>7KAX ziVmiV(+mN?2_jd#Y1&s*g>vHKhovf%krHjYD(x98`vN_EO62sBr4>oJ@nZSrFNx7d z0$BKpQWa0@vRET;n< zF^oVy_P=q2L~3r@hC2$m7J|$po(vV+nxNofQ`HB`zn4E8EE|ieF+;ZM8M=?_xE&-@ zm027AdpXd%DaYa%L7v&YD0j}8tAX|PaQosStST-y&Y8k~r;J7S(wZm*(PXSSyZ!x= zelBTuwVruytz^MjlK3+1LL4f+bO6`3Z0O!AuHaHgw$AcqHR6~T&?#7m@_^0CC06oU#o(sm}x z!zxFu_e$|nmF|i5#R+=ufPR9c7+=e@rQc`I9$0(N4wdD)e-1B`)`pu+*Tdur#VXy= zxtnk{FBULAf)6%V-3hJ;a-+$fWyt=JM87U_&`f9$DQ`qZ9C=r6C;2`^jO}FGN zX58@3JxPra({si=MDbq$nwz2&{07L7y>#XnBM0Vu09$bFyl2=%@@z;eS8oCZ4a}!uGVEm{DEN=%cwQfvc6Sy(^(LiZ|C3 zr>(($t}fE6X~|rLP+1W*vJ|?{7AQld$RD!z(rbNPhs_B!H4WZaM_A#x%)!F;MU-Ow(1|0_5)hWQEI)GiT-3p3(i z!$tOI#j&CTYgxerkj@P9#{#A*SwU3BQ11O1*}2_dQF<@RMn$NbDz3ZA+{*E)%^77g z&T=5`uI`*NS|lt)>N6a@I$T=lf=Y#7!7(c8Gq>+=_f?l@I|KS@!_M+q0P=+c^7Yky zogqpc?+(v3FEw%{MHHNUq{d&6hE)=KjXl_r%O-*#Z(%=AQg&=6vH3U~qdN&}c0*}l ziKz67$B)mkk29{`)*nWSYCTE#SPUD4EeMh9MjjUaS#(WvYiPQ3wZY##Q92_?!f|IW z=B|9Jz6ix!Gz!X;DVwmyS?E(w8Q%|5zb(6-=NyMClQ2>Nr)A}qCoI_DIeRbs6r$~Rq&sGmPvjH7Uw-l$PXdxJe54!$tY79M*=RS z%n*_vk)@{om~eD8(mMG=+i(Kh`IEoLg>5*b#l9ME4JF5LrOE#nt_3e8>i!_Fw?%H; zoFTu9^v5p?mgZirqX>~?)uPPFL!^UTEu4dvtSgns-a6GCi3Ef~A+NkQlQ9&;Scs9K zWI_sgn3EZ%{BEDT`_ut^xBjouuekC*tc3fMipV1@iIgS0Rq z*JTwA(L1pm8JF&6Pg7nvhE(vM?|xlG`;7BGU-^ukO7iJX>F1^kDv6OrDN0T&#PAM+ z7(&JQMm)kPjZ6)+4g42}DUFad*s5||Li(#JGj&s#GNsr&m@W=iUmW3^1jtPo-riF{ zd5v&{Fl}ror_*XpTw*i%^-1r3-5qf&%jTnu=#H2uIBBCw|J&XKClT@dEH~&4$C>i% zMHfG;A7vPFEMcCe-4%!@h+(Vy+JU?xK=FZxwjT_I9*&iP}mBcXUL?1MKhkjF#w( zC6;5_=qF#Lk`htxV#k4vhR?H^ytrO3`;;-)t{c%FB_z{gdZrg`NNO} zV-%CW8zOGk02q?AVVSRmDJ|C!=xo=J+K1U$xfXmko2=~HZAmSbVil#BI^$w3XWwNm zRyLYX(7gO9(1vSyxAzWw+*yK!I1QOLBuR)mk9G2kfU>>XLp7R5+1(2Iigda6jc{Y* zVxLudETDX7ZeTg}t#$qn z@x2E}Dc&&r?#XyF^4>BZdWs1{8_y@|p>}i;wQ_VhLVvRnV@QImgFzuv3D1qVs$98g||C z&bSr!wln{Fsn2R}lBsANITr$MsI*X=jtJxDE+qd#h>J;--Q=3_?DYc!DlACG!+yl@ z3rTb^&5Z{~Pmup?0M3IR@v4Y?Gnu~Gpqb-0iqA!!AbVr>V~)FGk9JZ9Fa&QJak&QWqa}d-Jy7v4=)#xlO+Dd_ty67>;?QU14<8;l+-+mRf zbeXbh8Lf04vQYIdy1ugQ`cGTrM8E^Ph9{s^7%`lUZr?f^fq<98=GvnA+wtOy=p{uG zw{qk=g7?|D8q~DpX<1_`wb$UhW0HvPa48Gg<$v9g9gL;O4+|H@+?I8#FS#hQxBSQc z)-zsDM7P0`D|M>z&@O|Y7R800TjzLMTV7b-W}h-vU%!BNHfv{%Y)zs_jVlfeS=qtu z&cYw=i!@x^_c!k~x)g%$vq(ThAw@azMCpS@UF?ItdYIL(Qwv|0yA88f<`+OE$*!U( z`Zm+u*ufn;pP-;CB$zk4#?LBo64`yDYzHZq#ED{er6habi zr-$ko4@(I@$Oco5pEnA&)vkAA`QfRQcd`8blwy>}1a&Km`l0x|^yD#5(SJ5ZIki(a z#(a!ksvcChWJfl}JWA1w#eqDU2}T)49oTz$7U>!7zF1O>o*68+_b>LGi@#8x(?|cT zFNxC0uUJDGwgjG|dJvZAZrS{&Jv9-v@Be0xKZP_+etFL+?Iwi;&3zQ{8b^(HXKfVQ z2-k;q$Rldtp@rgWt>88cR?GpPUgLb96pcJAZa9~qgeA3^S?Q_&AO3`~gN(QI#XU}$ z_ih7DZPs1;R-Fcy&!$xFm|=@;mLe$%9Y%-SeVuyA;?GDU&$sUR9chU*$XAGwEpR=J z5jhl@d)!f;n~wKS`)rHlOQ#f4N#u*_hWNAU zoexn=|J`#=h3*U!%rH8PpoH&)*6g;hw-t7im?H1LYVJ<=lVam3<&TDnDy4k+XFtJ7 zVnn_DF<0=MQ}aEF`#|Y9`#;;mMA6w#%$$cC1#0X{Sze(4%(2 zGp$8l00rqj^50Tlh^Z9If0Ow;%mq;|TQad9ohkap;D$xW(b=tkt{nce(Tf`?o&~y3 zVIJZLcM+Vch>!c2u`|p9B__S{^zXlLG>@uBE+yLz$pjI7{fwmkKQ~eDm=DG~ACFq` zJEYMr3U2O$J+o0Tb5zm`s@=6imdN_JfCZ-@#v0`l#;B=n zsFT4als~4`?~Zep^hab~Xh>g8WjNWteY@l@g}Aay9k|v`%SM=Zq>p&;5xU|(Yi#Wy zemAz(mQZ>O`QKlg(Yh9(8QpM>Hqc6D_9XnFRy*@`@x&{@dBBrCyt_mX06#5dPrwSo@DH9diDsr2xyXXBBic)=~|kG*M1G z3(tY7y8-V1xuxCzVkvM2SlYsfj90_)<4WolT|e{d3U1E-8~}vwq>F!)2mO_lLbjC2 zp8$)jX_|jO132xcaq7)eJz2f>e`9jtdY$?ok-C2cd#w*FK|DmlZz9M}Fs)XZvD!`Q z+{aC?wU>|W$`3*}4q8^X4H@JF68;j047VFV;;3>|NR}<_}S4%seS~J*5|5HbGQ+SpC z@BhjHh`QAoU6HSn<-r|xFdun}w{O8xxQc<7Y`+bBJshYY30Yx$pz(CvY4}{r-7NKCU%ZZm~IlBaf z-mg6IdK%%53yRu$0wIlV$C9cZ>_iJN_YWp%wPvI`-<#9k>SA-OnQHO|k-1{Qvbl!Z zNOP`8?9q3Da#7y4E=;l%W>N@~Wj=T}9qV=y=?MF6qgbUZ%ERARxQ|QNl>B9f^0eqD z>=(O;QxZ9qXY3(OBiS*fTF+;FH(1(OH2mLRr2qTxUDdstv{ckVK+w=Z|4+ZSVEWtd zEtaB|2oQo!sIPDlZr-2SSy7KsnX&D!Dk??Kz1_s^6j{^P%Kw?>d2`$b&P#lM*p3=hWJ)SqfKY~%JRpN=7L)UcLt! zz6Lci#?YwMvK-#h-MP8V^}X8>ljf^FBFTs_%2qf9OzmUO3Xu+KpJ42V&AW262|X3m zskV|+BAR4);fNv69o$R7Q~$dI>?e5%Z=)GjYMC>m+ab1V921xNQF_oijZ+XLknz+prwSOpS=+3 zt*CKi&RIUyKE9{u&&v40&=YbLsdT=3D|0J=g*gE+9)cY4{N_%^5SG)^^j+%nv(HMfE;o+Uc{3M@3Dfs>-2hg$o3p94!>&`?GKQGawFPGjiDrD7T5`(fpQ}>6dw$WVI{;C zXb5OSIu{w_Cgc{l4#0upM6xH^k`kL{aKzkY2!eyR=-FI6{l@m877pHObAYYvxW(nt zA6wAd(O?kX2KMeOl92Bk(}k9 zTy?SW7J`Bs&J3`1K)h`Y2BWQE@74iRI~cbh0aKxXM{i)98vv%p0F(BxcY1)SW56U} zsu(c24@?4fRRfdGZ{eQ)H1+io3@KI|4BQi>Trtk+n%+NO`}X&;^?&)~9uScQXk?IB)0jbZ<=0|)QklfQae&HmvS4&Jke zcg->+(4c+a?dNGCO2=c*1Sz|O0>`7+f~%rPhhUM#giW!{WgTJFt+@Sve&4Q!Pfjt z@Vc)X(ZBOCL%|1;vZmHn$i5sdLvyREzZ=o5n$?yn7P5+V*M7t+{#)x?XQX+_p9H@7 zZ>5nqBy-H5Fp-#udUa|i=@op;L_#|IffN3#?VIvWUVWSGX}%y&XRwxK!Cv9%Tgxaj zUNwWkU47U)#c;xGamFoV(jZT~-WdEHjB_wR&|<(bodH(>)c(o175pLSF$Yll8Vc*) zE}D?<6!2BvpvMW|(gT{rG2v+;`)ENk5LivEWQ}V@6if?uZ9r5s6-LI zh(-{;u!j-8kcZ@|JagH=wlmimn2t~Q<`N5%2aUaj!ww39b-R)XNXT!yr4R^1Y~>fz zx)c@@PKsL0=NId9`p|*%DPZQ8&d&LFOxM`xc)T(6@sd8LN5gd}E%)aP1uw+8vzc#0 z0d(JCGc+{^9KebYTIv{VsqDNuFgWTl&bD_m?!yQD69b9Qb*+AG5y7*eMGg8__$q{c zF!em|Ol7}NZ_yGU- zSabych3jdgO6^MKd-*N;i{$n5=ItEcqlL52^vkK_J)2*K+WN^RG6kYT)Ok;K2&d>> zmt=27zBZ=2!Cq!AuAoQIdstjdE=ET((|HCK!$E3Oq8*%VB{@U~8p<_-9lCp>9ij@+ zqe+4tfx-Ud{JB0&sD*;y>Ck3`T5=dssD+E&jQwzg+7e&lxm6QDv;a%%pMz@UfxZgR zgdU8xTQjrg4$@D;TV2DiPRnMyETyHnTU`SPXbG1gvBkd`PmXqR%@UfzyalNo;zqO3 z)WN%hXOr;jv4aM}b(?*#e#ZQ{iI)$lVuymSB~;lV0Y6=+jB`IRmpy0|bCI#mWbfNV zY%a2(iC++$pkPqjM>6&Aa@vLfu#|P`PyaMD95+HniRl9E0ITGaX16H*=^tD;=_Q6O0NTo*$?TO{rvEbN7HMpq%-7$ zDmF*+pns$sceZYKW!2AZ$GCQx8;#ni*j|I$aRBaM%@5*!~>v!M} znMvd zJ(|ijz<)`->?%3fF2Cl&c(wx-r!W_*Et8$mH~>JH3jlD2ZKC&cka7wgtO$*`gT)q4 z7_XdncSh%*Ve>6k;amf(2lSi6R1?D-}QvQ!yi?zHTMmt+~FxppMYCRfr zr}L~^t#qH_Xs^=vYR6-RsyK(EZS&@Ewg<>3Eu!3w_9Am#f}CNGFu52U4flE{Qgifr zCSnNb<3hC^63}^ttC$tPugROAbkm2?R`yK}EXdZa(IF0FF4{TXmKrB-w4`6g`k9V! zE|SCi;@5N=hma>VF)KooCtE%l6^Og2bAS=2gQcM%;Z%6gC!EzkOh%i^M|e#1RUGN_ ztq){Di0iD0**gFBL!h+xJ3cn_VmOJiEj%ewrLJCthY*gB^Vg7MOeyDQC~%+8<~@#l zAHQ2XwmQE!muh=eZprs2M&lxpA=;DD!MYG_OK4)03ymf=sepSZRJ(vLQO;|3y?^Jd zSRL<|iP@tZ%*L(XhexG4F(tH+*pw5U*3ins!fu&w-nbmF4{!G-vi90`!kMw2DeAq> zoU>ht)V)|{15B=4Z46$3f;U?X6{i_@eGJojq6u1DMnk5CSRlf9U?2&(wGK^zdc@O| zfIA9i4O5JHvvPGq395gXb6<0XvU{y+wac=fSDWd)x zX#OqJHyH0xX^PECk4NF&m6WtD4Lka`G;(LRwZIGMM+3NIT?oxL_fDOh(7oNKME7U3 zLKfo#F9{wmzXp;NxfMakCqm1mtBKj?xmXjT3e2DZ2=~1JVHUgpg4OaDEFAz=VR;*j zTSDKD+526JHD+u1bXkBZVDZ%%xgYfjhqgls11~9<^oKMyj;!HDw0;BDi{ zfR!X!pj*J05xBUii`gIPTM#C0JV!3vTvLgWbOg%7j{~mB8w$^zUu9;;`Pm}aIhhnq zin{3*k|u?>yU>8DV|aa$5miTzzh2-;GVnh6-4#7*7#cMSy>fAQN%hattaPC)KA*u1 z#VtP){Q)WaNIQE+a``BcV`4_-PU9}I}Wv8m@t zy5eY4QkRS!{RbOcGJcn~7 zaMr4vebkwDzhUCa?v)(B%_@c>1--G3Za*4oo}mvuWii|(qYldwch`El2FC#Ep19!; zodfCJUjL4Iu&tI;u}kC~n{u_dUm?>88^H>}#gTU*!G(Qz@dZKUQ(;v>tcMVwvXQnm z(h;!}6TM65tIFxcfg~mgfXbwEw8ms{%arDXiS}j1p(Hn9fSRlZW`sP$D|ry|v?|O$ z(55~fqu0l5nfLz?pfVdMHX&siUxE@uB4|07=Dbn7!Jk7_j(5{^P%-Sl`PObg_Jt<* zV&dfd4c80QQ~$Cj>t}BR>yFZ&KUS98G(3d$J_UBCy$fVTeP=<1@dZypR$WgwU2M1L9G9MOh2i>JTm>Cet?#=!)0`4&yVzeZjUq7(M zl=@CIriPNZ!~*$eqA?JF4}7v$`VBv`;1xdWZ}_AD{L*-K1F1;#xP1d)36S#K0w z+O?7IsWl`<-k{()92-Fg1}o6xGw57EZTI7Nv3`y-i0UZKIkb*?MwEEjdxjDA38-!5 za1pf~!@uC3KMPk0nggkFM5Yqw@%frO(il>ZwW$o0o#orATDgtxiC()ZiRE;^cIx?m zO<@Jv3ofO)fA@9y5*LkZ>zI4zBE=Z@<_8uFc#o1~=F!*mT$21C^B|TvGXhtP7B`b= zf-G+OYvyBV!SSdRi5)&ra^zjm$l{t>J5?$LpZGwtp~plqPc0r@yHJbY)v#5JK{{Gbd28XVWt#g6`yKjM=j6 z?iND2IYfsMue7K6MA95R`>}MJYG6?y&cPV_^^?29A75tQ=2=CxEYkG==cbsK>ym!wYz%8(b?B~C9qR}F>C-kZug*P7%93-( z`^N@a7Pglx?B(~6IvthvjXyrqMKauOb|p)OF9}qdMs*KuHLG8XMh^&#MQoY zr+a@+A!&S&k|N>UwILj$l^Q3DyCr1;e7~VQ)i+_p{G~aNq}88RisbI$n?T&tSQ1%W zc~@hMA!MVI)O|zb1xqq+0Gr(5S|^;jT@PgQh?t8i>~R_2VV1}FjZJq_8!6;=ROrnf zuuitk8|fptutpD--!#K{3KKQCg+b1Kd*Z>Fyv$qE=}hMmx^0E8=LFRjDm@%L9jpK&evOxkDb~D< z$_xm^mk8uGA8rk?TG7!dp*RmE8j^)%Pp`{-`5WM5AJBC?`e)f zLkq&$>nHU7?7Z)(kVB%|r{$z@!D|;4y;FgX^7ew)0Uh`5#unBQ@ElyJSLoXj)g>y%AO!T5dvGozHmO`z?4meEG>lRzkR4ifT5(j;&Rnm5U+ zXcQ|*3}j(cQYcEQOqJCcvU)>J-S(iyJ3o_tey%o*Fk@)@8S%5&ymvOFY`xr^qY7)c z%&r6LeR=;|rO53NEXi@!un2RM&>s{?q$34&hE1O7Blb0Z6@Xany-a5wj(LfyWKl4n ziR!?3ANPBVc^&6m%u|~J1)4Y%MtbemyTdlSjgSp8<7H{4t!ObJyt!>VjpBHIfR@cM z4Yli_#U1|SV2s^btPLdbkmuD9vv2n_Cmh1Q8vQuDP4^WDCH#uI>X_n-G~g3jJxlD? zDm{!i@3Z-eDAnR!tY*v1Cn5V)F^XF@9-7SEGQMSZVm-dqDgTXzM?Bm@=+G%2^)oYP zuM7q-5_xZ%btoH82HP#?_WVHNnGM6AhUeOz4KW4CebWsZoCoz7by_y2dUDY-v4N!F zsCs^|*|O>~qgY;JSc87=QV3weuj>QCbJyOAXa5k_)AvgtBVE6o`xK)=^GFfapV!Cp zgWwpZDIS!r@Y}hHuTeE$ zoNE)B@S|Xm5?X+*1KXvf!hMU8ojd-ZfI z>P!e*u6;wyF03wgZUzR#1Db}a*!dmwI9ePHK`M~`c}$E6w(V=|U;EkYz(ApPXj+oH znW(~0lHY$LH+8@(zw2$dbQ-d?9GwEY@FjQ~bPM3U1)uQ2W{5wP;AC>L>{!$@O$(pA z3I7cI1}!QjjT6`uxY{vYhpOkmg|AtzUMOPiewGW}Jpri++H{^?a9bjZT3>#Xzs1 zoAu@6x{R+t4k+n!ihS^e-TOgK{N2wP|M>9J@{}Iun;;iVDwe9m@NbOem3giO>TQ8auv6yi6L>KN#%FLIKA?n14ChQz&F34f?H z+qb-BQHW&MyZ6Z^9WM#(aTectB|4?VP4fNlTes*aZ705s>BD=D)u+LPHEfRaMJ^1E z+Kp|~pN8^u(!euZIDxDN1#?|A`_=n__{IgEmd5?kP_}FJCXRKX`jvB^hi}iGfTNdM z&f|kgVmX(8zVi_1e2R@u->YM&;gfJFv%SZAKyJ}Mt>yqP7k?A3@U0Z(^`qpQaQ|Ot z4>)M#!8Jp2hw(i-Tl3KVp*pJgQXAi}x+cEiH+$F5e{_pRUiVBfZX5p@#zYfnbSjJ) z7Qw_pJes+#)b+e&>61XFl3a!O>6zkFWkOTEpA!=5(;b(V#36jA=tR!Uv#q9V((f_o zb!@6uczR>e|;|aC~W+A*C1Cdos9JRtcl-E-vTLtw4Tqi zBL}wRX}!r-ujo1$yFIXssh$r9y|UQxD14JkC1*Z+DXkOE^J^a9To2rk%Gpn`;j0D! z$CXk*f1L1QNI0~Z2y6`eAeREzZe?PQu~)Na1WK;(NVh;ZMW*3fV3{`3GlAA?+oz1 z^2+X0OFpave=yJ;szCb9d+i(=z`O9aLMGDnBL0FkOt{W6dv$!v z-t)?D-k%U^jzJ#$)$mnQK?}LSB|P7$CUhs>eyiQ0I2+Q_v$wn()=GrG&(+;WzlQwE zF~+q1A_(&CiyXGsiMgk3H!LeJW}AEvRyOP^rQo(B1byHF^DTY`NaD2O-RRnp@LfkH zELoY(s225dq@PoF!Yw|p4nnTuJ&GeJNIeX$0pc?_y(-$Z;d?3u-jeuU~%Zv;V_S$X@F@}NNGXin5)XZR%$-?Ns z&ft$aU^B)%1W52Eu5`c>Z@dE_y}1A&{bdjmTbN|mN62XyD5rCr+E430UZ8f*l5i5B z&+%~E_kDVc7Ow34UJ!L`ZGH|~9O(WWTujUdni&1Y_&^eBl`$Z_{q%n^yDDFM8Ei?+ z4J4ftTK55(O$~{j7YtSVE41fbhaVr=5`$hCtBXIEDs+3l5PP5kt}gXryE!U7p2 zZ6}n#4Iv9=i;EI3hh7j>Hmsx(W~nC=O{USjNwyv(+_cFlAIF>Ph4>datU!oKu^pfP zhq$)@ifc*3hJ(911a}D@G`PDv1b4TDKyZfugEMGw37(LkA^70#gamg;aOXdhyZ7$h zyL-24>-+2bs;1uQ(=%|opZDpf<@CIrBAc(cWZ1!nI)kFM8h9xZf?Ny*{I9UPppvo= z{sNqh{TtDs>EqdX*q(=_878mqSqo=3lvm0@Uv|&LR%N*Wr0)j0C6n4%bJ^$&+K-*6 z`*Fj|0g>0ULDXa)WZwk*;b5RIUk_UEkxWu+GBK2|=e4n>9#8fIW}gpBjtSE?k>4SlJc~NT!1yS)D(SbGTzMQu*2PNxqYdHn=+eI z3al29^cLM(ltfuGg76KPN5!r~ASjyjZ6Ed(W${ZF>^R_V#-$z_ONJ{h_?37i-49G{ zo&+wS+_@}xdxbl!JPvuO-9Q0$t&hu1aNknv z0Dj3?!|T>O;D~AT0jx6v1IPluYy>({{aip}3OO4#1t@?xu)bYI{9y`-~9!>FBE!5 zDD;(oKtBM5{@riTQ(~e2f*!5x7xY19Q0NtZgWdzlq%=JGVWqb(C+X}mZ%nmW8mtz4 zoDFL&iZI}fnsSBD^o`jVj8*ZXJC@bQHzkNN5>+AEESMY@Ns^jS$K3u(Eq?RToh_YcQ0qpP}N;U z;8bXq!%6?^$}RL15Sbb}n0p07p9OjmhhqevG&+D`T2A9%ywhskS{&iPdFfB(l zFm>9~iw7pTtjo}0&2#9mCZ@)ojjh6j#8AIJpn}9ef5MSp0_lcrK|D?UsRXj0!SN?a zyp-B>85!*y{Bts@rpRi%uDM6ytgM|v%zIqo`IcVMl6kOaf(WSos8f6ROsCB1?OJcg zkUZBp#WRp4z189=#+u%pb-*PdR;Q69NRYqfM1C*CPW%;b9RKGs!S(kr5>$U~Z3Jtk z(|&cLl$CPd43AJ4Se$SPINtO$MENU<9Q9sA`RF|>_S{FBt9+;*b!w^P>UNN6@GT{L zap8)xIppOmf>IjYcKX~`22|0pJtG0$ql0h(t?z!s?4HA+jy~r6wZK#A)3#<>EmZ0s z^}CD%tTzW(e{9bWNIjc5RO(ZqQcuqYmHJeu)DwOLq~1XE%z~Q0;@Z!ix_>t#6pejK3N)wj zFa1T&vw?s4*#o#62_-rxzrFr7lP}MQS}Pa=bkIuMx&^-R=iZaSS>gt2R2m{0o4ap``Rq&F(Psa z(uRm2MOb2s1?4k(kMHO8YX(2yv=N(jW$`FUXT08qN1Tf{Y{aH%>45O5}dW2!#khg-@i+*nvuXB_J z3Aj0C5AjmV#cQ#^u)t*+ zyj43RQ(lq zSS;o9hB)`y`>4WST{IbyGtj11aMNL z#f0En0d{ZkYU@=DPw~%P7Dtakt@W}^wr4_A^KigwuQwYolUk0?Q>N3HKLyZO{5d6! zEB4bCz}|HNV0+X=r)1JoZ4ST-FdTrZsNdIvigt`I5<}pC?5wEu$DnRp}=LDXsJtR!X zmn0c&H*vzWr6*7MY7y(>Q8BkqE=c9KPyn}R(CaXU-(f~&ibuX!TouMu^KDdVkY2|#!RHxhlF@3I9La^>8DFLjm0@=Ba_|K;#YZx^ zA?_`U;59V&fjK2mkiwd%rVy=vsE|~Ia_jNN9aAY6bik~j*D9|EUB-GTf`_0?_w0X+ z-RI4c3cY{=57^vaHeP_;PHHzOgN*$E7~nLO!_lzob`bAX%G9Iwy614I>vmX?ZHwJu zXg%9Fa`+y2GZ}b$n%C7X@cpnQ(5fdv%>Qof;Z5NEL22Ft`u^ZicK5?6bQ2$j7==Mx ztwcf}^G4AgQ|(lJi^NT9pJa7xf(o0#3O85Xy2WsE9KH13e0S2|Q!O&3+xt8N{U+mH z@S^@I#e2>=tHkNpIQmm}dy9UW%+zT5S%$^ZURuBDXZyxUP6Xub>F*Wl^*#u&50*af za)0*j{-!-JIabJZwbo7KKx*|TnEa+fCkdl)%@dc|hkl+5ph@~-hh&o8`MBgjQB1ZI zoB8=DLt5ossQIyq&9qp{1DcIT&*OL?I+?XztujOAlKC{V)wjsUkOkHZhOQQj^%#2N zu*red5Ba_nmLPj})v8oWBfpn4TMmuY`mUTY9p>B#kIMoqLo`~K zF%K*~_roW^SW+a5i9ytNq+Klfkns6+;@~6?er59KZoZ#ae5fzqndLl_+1le}?i8Yq zsm<~D+!o@^g5xfX6IFYNn^1cQ8(*pR(py&l<&KR0OB4E!3igyauQ$C`Ay183%~zv* zdEz}ndeK#geJ!@Z`OH#05u4~wh<(lN`p07OpGuKMd_-^KKJ6V7mJ*IQM<*v1;`XxG z9>R7(SvvA8GaCph>`rbP07+R2s*;?_lAOtsoHLMKyqnxLaW&Z1fk9wYwkkLz#(aVt0%aPG5 zkkKoV(W{WrtC7)b)O`vg>t=}-(#9nSM^N;fhgX^&Z?I^QATRe^WMZ@%8Vk#3jL0R) zFX ztmpFMO^hq!AMO(#t~W;8$*S}UH}CTPw3iEe?)bi?CGh53OCSnbVg_;72L$}d@?tHO z(lphlIfg>hUJg6jcn;C@eM?WLdSU4UBqh1N1_*0sg~lZ>t>Fvc1)P50n3^ar(NZeS zRDF`;&^+uXAoX+O+kHA+a(i7;4M;g&i<>a1-(7J;l3P%<-%y^RkNFi^|GEIZCpGwS z={h@I@>Jv<>tdl$wjE5=a7UXd6?GahcLro(py(^ud8du zYax;=4!950N+|$@xRfP%WtTKTtJ;y$5gBJ$&3#+zu9zTzpvC8--!QY#qV z=(Ut*K@9GB{Pb96YXYkMq2`%L`o3KoYT-zb@VP4RmCH zP^i_yp5bxRTggJQK?u|wVQeS{IQ0xxQji(id8vyHQ#dbhq|aZr#MvMpcRBk^(H(&zK(N_i!egCw=<|upZJ&-*rYD*B$_lWzG1`W_%o#~YAWE0_Me8u@kX{<_e(_I&K zd!yj&CE#9^m?^6ADr)j7>hdZY@+v;(RkYw$v_VfDB4z<|X>(f&Y##9`^UzM`EeaLk zAGmDl2O84NP(~|1+rvGPhVW2pN!o-Bp%`EvOG1)B1k{d_d|^%^N!wV?7XfG*=|!*q z!iW1G=NI`QarjP^X66}McPkgjQaQW8BzZ;ktP}{$m9V6N?Ln1F84wCWD!+9zhJ(AtA#6IvJKauV^meLT8 zU*PdF+lGuq=krK`D3`^Aw1FqCaRhAWo-DvRx_Oz_)d~P<`K^~b(N&^RvlM30F%S*) z7$|K#S`%mhcv^7+f z)`f(dt8PSoqeb^-0oK_fgj4g_4|fZ`e!ctpHSpnbwxy*eu(9POs}JSiOBwx7Ee`^h zXIKxJU%#EUu&DTH7S?g4oiCUe&Z^#t%$k3Kw-|Tpy~6r&n%QoH4H~@B7#)q? zXIeukAQEa%Ny4yJ?0PyY8Av7wgW4#8u0lSGU|CYTG6uh4txQA;DIy*{hggUQUS}PH zT%5}ynE%n7_J^~ zCJ5J05f}~fFW+}JhI|oVUpHg%8#*}VOcVj+52wD*U6Eb#9B_;*grbl63VFUz077A@ zC<)C|kcT`69Fx05U$l=%+NgN=LRfu#W}>%#mZolB!D`i@ZofanHU^B#O>3nJ2>}sF zriE1^8{pMbTkR!EpO?*D0z|5p`wNjo*l8$P=Hxqi0Z|c56$wb-oPw5(_)z=2SwQE! z)ANL_K&OE4owS1P&O%|J7jjR##;9q5Lxc3RL$pvOs<-~#7R`m zB~2VqQ@SF6b=hIO9@$B$AlZ1WW84XOcaUsv1ZoK#1ED-Pi@}B^uDbIqg0jn5!ig>F z2`*ZJG())b-|H#vRbkA^Cv1X2N|^%zhd;K2qf6X3hWM8Kqh6cZ_m?7_>ZR47wNAIv ze-pyLgR!i}p^@ zQdD<>u=)_s%I{RH-9N7sV6V`^m6ZdDJ&hr~r;%KJKwPG^=4@p;P?MsrBrMQ1E6G#! zF@sT1fCk4;9gL5JVx_F0+9(yTm4tW58LvdIo^}v;+|^jsA4gv+V}X(aDFQ+8s7J&8 zM&g3CKR}&_@)zgHQxQ2~5jYi@St6iyWh+v(%MtHt!vY&eU$O+7WU~aXxRbJJ(DQvx zpIbI4*z=4gSEJ|SOr86pz1m?$pBtxPL1q^{oI}torI$fjS<9qJT^*vYtN*y1(^UUg z^76{KNleF&A6{+~$(0tRfy?rHTQ()M)6xn9zk`Ol2@ z)Pe6oN#%qd#`1&OXoBoTHWlHIFDl+-CgqMvZnB`DJ^|`2lOGNUEAt1?>f7))7zE1w znzt-AE}6yAglV6gjV_VZK0fiGn~;=b2z!QetPJ^&YT9i`{5JMS8`tT`SbY9J#dL}n zmG6(9tRVc?-~cTZIyfMFzUuV^{jR~tgyrXt54fXP%$~Q~!z&N9=55ky{q-T&I+q*^ z0V#H9nxdUVqMb+PS4Ex23JBAcoJ#unc=F+ms1*i4p2r|#)Vuu5r)e4vL!>k6!=x1k zYki&=5BgG1iz!&Xu@_kvL@FA~4@+aEHiB}aDOlWVP)myJ3fJul>Ff)w>9Y;_^pVh`SQQ^h>?T@r56iz`b zgWn{z*D?O(mjV%QBaQ9F{y?E3@|X8TetDnbg?lqagiA|Lp_b(3XP6Y1Ak!~)2zmu8 z8qs|UX+9+{qSGko4SiGC4{;PDy^~S*7zk3{hj{4f^Os}mNeHr5W@)>8?e38fbgayp z0y1&*q=01JREBJ2e)iK8&qqD54+6rIga&E*1NQ_Pc~cBV=*$x z5}T6CbL=%q68kdwQgOgMaV)glwuU;g(yFp_JZ;bmUmaOx&nBF%u`@E++stv*xJwyL z+VlR?_i8p&o*)DWt`$N(;(U;k#0x4v5FDhA9*o1a9}r(Y6(w&1ZpQfnW_#(<&At^!Oj%?w`238+*T+U5ZTHn`p6|PX(&Z-? z<&o9_yNPajzAJ~N_pjfgF~gb2lR&cJz@C4kL)|dBjO9@T!JcJk%u>L|Ec_{gkE?91i@<5$e6K|tkT@0P&waO_{O1tERKG_Sc2cmB zMsLouWO+)XsaN76{jvaQJb7D&j@IKxpw--5ZM1paP!rA-5XH)qmYZlWhpcY!6>V>% z?Tq2zbp7)xZ=)xc(<@8)%Z)$EFI4?^53=A)bV#-<2Emg0yQ_U>~bLoKgxeTbwhrxi$=iUNIVekT& zArv9=|qugkAX}ton@tkdmQ#xOq{;XC{ zGb?>IpX(!c3lFU>i{VL2%W+TFx&*4y8zw!R)Qr1up=5Sko_Re@OZ+UCKrApR7 z)(}`Wl^@Jg#o~JGf;ah2Xc3aVqm$!o#eOuslw}UOiA!CdU3z(S@`O^1ob%pE;}|6L z*Wg~ihZ2!JZL@mTPz`iL-T7 z5^V^0(cEtRaPV>diuOcY$$3%f&Y&ED1>XM9*8Tz0Q-Yi5hKGpGvrY<{^y3}wVNfyH zpGfK91KuW6dSrpOsgxdF;B7k0-W>QVF1B+AU#I=)l%D5z7EM%LQ5R$(PK=%H4;=|& zMyGe!Y9M9^x)o;qBZH7i@fj*I(C<-5Yw%Z@ojRx-3o{=qa^~dLNL}bj~~4X zX%#Q(tV!~Jh~cJIXLCx*uko|<43>Xzx(;Ei!~(R zn@BBntKP@dx8023=_He?RO6~0u;CVpqso-_!YjQ@{z^Is%MjJB;*hwW6=Kr7x}HTu zGcM1R>MP>sN;niB*bOl0m2zH88T3i+eUZ%54kOYJYio#SJC(Ec(QcX2-+e=mZ+B=E zjgj)YrJ4Y5=BZ_8^9yDDSrAI>6EMrBRe+1rfN}8VX97n{$cyYhAr1<>1zL z`K)dwU)Z+@h>vuxQg$7xb{xv9XCgkP?K+@T%-DGs4|1jURXH>wwhy$+FI_`*&P1zXjQt^sdM82cPl#(tvV2I(l{Ucu4>_7? zFlP|oY}OruhZxVsgCBu~dp@do*mki;^n4te4Z0<%dwTMe$`d#?=P8wkAzV@qp-K;- zAFnCg@tmr-*aM~qOoYTCKm6Q?e<`e!2F({yaKL&0e@TfsN~haR}Lf<^iy3L-+7%CPn;?jt9TSE>?!u8tlTI6$ld!vlly~$B1dgX^-78n zw!wq#!xQ!}v?^3Ig}SlxCJ^D^k6k(Yx~UkP>oxwpOwLJ4PZL_3Ys+fKUgf}{9E(XH zeQ4oP$Lx9ca}H44`wT#F_pk(a64?0cs>PsW*lXua-{TnaY|n3haVtD+8jE{(_TPHb z`_G>pO4^2OW?0+n zJrCW$m7duHLjA3~4}w+2O@>+1hMDggUR42M3e2mDniOH*@rvv3&?pxF+*Ne!)%^55 zRY>-o)SYXiiP~(In3tr+7A9H_5gT2%q+_R~BAeH8EeKyJhlh>6M{^5}S}dTZ8iD7E zYZjn^7?cL_|-AeOv$&DoIG@7zw<*YFRf%m5AC+D#jd9MdN z8qSLw*z_Fp3+6P>I?$mtF zvu~ll-@g<9w0REC8!jS0o==n>^^^uc7aIWWVh_?cJ#NBboX`m{?<>Yyb&kc_Z(`eT zMjtNM+V2Keu^vvb#QHD;FNoT&i@GF)XLAheWuobC0C1Gp=0}GXm3`7(F3O}ZqVHyp z9!5H3RVE`3GwhSdz!qoVX!{LZxH~}M9HxxnOP})y{f}1 z1IGKqOGS|WBC9$v&tz^QVP1aw%s~}W#82P!JCm+v-K4% z`oQ+FV!q>0c#8h^wFfmbVRKat`WCr2oDwr@+BN4~f@$Sm$56nKw|~ZbLQ^#nz@wKj zB3VE>w!bHL=%CNi(sc9OlKtGqMQq(ltbQ)9=`JIdJads_c;g(6cHVWaCg;2A!E8Zy zfIm0+>EHDf@4o>(#s05vL3@e@(?5C&NC41N+y(vCQw#M8Dgh$QvC4+WTvEOIQ{ zA2Sb5FRahh8&|2gKH-{PfS;{5E>>};AJkc((KD>pG4HCpNgQ;e*H?37>Pl|sMZ3hw z4I_8axkuLGZvJ6xr&t2QZK%0s>Wr5CI%XUZJF;SCP?ut1{x|IgXhVQh`f+~(q|zU} z2uNjC(;X=J4q_1q1>%LB3m}z?M{P#RhzE8r9e@ttd@tGl8QVPh1&^oIe;O&AJGxF? z&U7@X_$Q-52-g1?C)AtX2*20>{afW*q@a~=4*01u`zpo3o?g#t(h|w$)Vp zAYsTqNbmE23=K_;uaq^9Mfr_@|2^dq-8O3We9hohgXznMC_p7Gp(@E&0Ts+OAeqWn zpW3ZsZ)CKSP5L{_dl>(Ip{VKgRdK=z!A3@prZCzg>E7UPlX5`NTr6q-id_>CVUL_iEF2 zS%j99{G$9_>r#OE$aP$ft8iLQ^_^kLT+M%L@#iIBGZq}SQ&GppIC0-3Ah|#{VJ`~-wu-!bAQaz-N{R*zR&4|4N zw*bxk5DjkHwXr6rUG*!_kp2H#bN7Tc_oZLof;M;WKQ(uMpt;}t-rW6vHTN6N6OM~S zZ~A+!!>$_@hXV~qlIoeWTP|6L~u3fn*F1op2VN1jZOsVFuy{NoQkv zUqz1dJtM>Sb+^Au3bB2N07gYL#$>9dXsAa&XOEgWPAEK0kZhJMtM@vG{DyLdOgH9h zW6kTxJdXf!#}Bmu9L3_xH=b3|TL^kE$emocU&G7|B0~gm;Lfe10 zsIb{qQLH;;b)@@7oa=_QYa@aBXi`$sEwk##ze`nj~G z(~Q_SuoB0x^#s|uE8Z2QNZ^mH((S{l{zCf1vuE0f!MnDCdx^ES;Tl&3dGD90ZN zahsbcF;wpLhk2`jYpYrDW*V$Jn?K*$6jpQK&748gz`QUWW$*f!agdw@u`2MU(=F=i z02s5`{WIt-5cxR5?oSaedB*=-SDJp%$pdYdatFN>g`?tfMkasBc2a)RcsKCtn{#P% z0$1Lv)Y%Tbl^qmAY~2MMy_Ip!%nas+47RTKI$f6Uy-Z|AORvVBV&|x`S@oG-aYl_T z=~;Y^wD0OYHMbYn#(z7l2*F_HMz6-esaEMaavzZiQ8mkd}6Tqaj zDeNA~5Fg=P5xn%j(zuY5oG?@z8CBQ<@|M!Co=$A$(&(U|Db-dYf&i*{=s? zl!R|CVs8yX{Sg!~#!{N&jU(jBB9QvG6;JX$0Vht?U7?o1Y={TwOokYuaNB08vjW8< zbD)Q0+e=r$1ItQfslY!XX~4A_`B11E0_hL7Dk0wx-#mUXL{3~%^39DZqV9hK*n=wa z3JUOGFce@+D8PV8F~QvTD2IDEdbrtYf0%72J$kved7S>$vdo)k@#ucDJ@BG^=-ui= zCC%Uu{prh!i*F25?N_dq=vT$cN&_)N;F1&qFpo1cE4MAFmM&1(l1iWoss_L^VQxLJ zGALm!vu-8BJ^2>6con*-i#|E!s*fYJutq)hKk(ZiQR*JbZ)+KV-|WD>VxVRKYEZvr z3@C|iMqqR)|7>`&QCD)ikOq`Rd{J{#8O_dUAln|+SqUiNTW4n1W=?;qD^A;M@nduL zqflc}^NcHuE3-7;XYl_P4)ssLP`wzMu}z}?xj=j6)*E1z!Q8msWvS9nPr0c)4mI;o zvjR0c-l}f|wO;o}3Tg!aX7W)ImS+h99qQxI z$JEdw{Bn+hXVdFWy92W0j_yMrO?8{720&Y?OHT6)_2{jW?vkEoGP=g39!V~CSGXYABdjmCfx?gc-($o6y)-zGcF6**jlX0yj`@|P!*WIef5~nfv!CVeaz-bA z$#ERBzoo;sj8*=U>p12>%iV7oh<3_Iyd?;vlW=kNA-!G_mJ4sW{5iS*^cuLKN+0#J z{3#|tsP;d>!e#k0A`XLxApP~_tCCG96?UQKFe!mVhJPsKIg~&DjV5mUO8_2S**kFk zkxi{w9#^gWG54W`+y8!E#qUenz-bjD(nJNU<8j-nr&PYUZBcZTJTWeFbDUc4{gHXL z4(tHx6;QLwewBgZ)}_2dPss!0l2QIySM=G;lqoB~6C}G0;GQs5fR{|(rUC`V`f$90 z4|sSIDJcQ`XjC6)H>_8SqgS_I>^A=GOp!kxGXN)~jf1x(z3Bh>h-tlRd@0eq{mYkra(F21vM|A#s_MC;|VnNcWR&f8lns(2vlf)Y5o5z zNd86JJg&lib^#nI|G&*t(1Qd<~P;o=$0E{BXZ`o(i>|JP% z(61f_+In_i0p>u#C`|zx9zc+xFwb77zOLM&F=qeUAv^z-s5YJRzW@QW(T#5iXu5!^ z|9LF%D_h(2mvP`lTr< zly-|fK-c5kGO?8Y`uApJVl*E>z`YuMF}aUpg<5B`vEldwGxWRl|!n%R018ZeDdh&UVgyT@Hg5k(4hgYa@oT&)@184Zu&71pI{h=iEBc3Kd z7VIF~B#+xn?{Dh_Nd4Rhf*9q;*b7rHR0cBe2$&9KOJL$yi|btdm z6RT#dYEA}&7L15X*ouRyaH?PrkfOpf{Z5Zq<{Q;AaX)>>{}lNVB}@Z@=0$zl{gM>3 z295ucqvcg~Z>yR{CxW2CYm3)MqSn_BdWwpuj@it2$o)<~Ugz9r50elPO?cn)n->5l zf2W(kw5$KTV3S!xW4#ag>W|0Q^rd;N-kvq~O#t1y1Kx)Q1BCZKUz5`-e5NwA8`GxzvG z5Plx8lZ>{@;oo)6kZTJTJ^U@u_%CLqWI4L7^^$}?#JuCMf5b2YT9t{I6_?Vya7@Lz z(`_W<(0n^bc+NL}f0J8xiCNVp_!Bh>`-oM9!hJJ)WoYH{eq*+@lw)`;y)W`+EAS!U zw=gUH;aNby6{q6Sl9$)Xv>B0d>r=Of@xW`w*S9P8 zpCT!j?hahBER^DyhC(n$=r zzQXUU?f!Ca?PQXpFl(z+jZ)U<;V?yY4E)gjhTHcN&ReK#@-APNUVEFT zO*Jo|+wugsXQNLW!5O%0RK`Ep*ElkKhm*{d#i|@6M1_~xqlaqm3oq7|b2*Ed>d=npm}+mQ!{lb4Rr+ry+J#L#lUX(D%tUu@=>YFG7I)Il^h>>k z6nXL|eA?W9`m*lwXyg@A=vk6X$xj$E6=6cGsLaL{CuuKts#J9=Qu(N^#J?1z^4W=& z>H;glZ?Ccmag3tjhqt^a=c7ly#a>HHB@_f4o9-Aow+zKD#I`6KW4dqMKM*{hL<>gq zzPWmcY1ou56aEK~=x2>FTs~V3X0rUdO_IA5`R2w#>DTbAtfar$i(*b6J5KTbU96 z>{$p}r`srYuqFgqm=TW;JfotIcB(Q2BPFELZNy23^bG`?PZ6O}u-Y2~%Z1=wuruK!(ujF_sMNU_82v{GLTl+c>2ks?u)B%1#$xQtiNkn< zNt|M2+Nr;Am5}bo5a6*HV%(O1%*JDUo!?d4j2n5?a%)wc5*EL5<1pHJqKGRXU-XG7 zZU{$yf7$K0eV43io7;!&Lw*; zOvYckfvVs=)$C^k73nhk6cvSEts5!tb1w<m19jVjrU*^hWg zSVh&&V`b(NOtr8F>i@C`E3s<}`LY1K%~H3%GV)G8qJ0}HM=5_-**DRVbg?uPB(ZP% zhL+z+TNrZph6L+aWE?Z3{R_HoTZjbH9G8?U8vLt#>d=;2acue*$Ti;+D&Roeq})IF z3}4MI-bbJ_GD6I1_oQJ%MM}Rpl=yUYbXofNWz*O4X2;R<=#H#@eAD-OcAfKnO+(C5 ze&o|PrPAqpL5nwKCRFk;agrbdLt0+mDoJeHOhJWFo^Yxi-Y_dZJ!DCB9>%X_gs2k8 z4#;4ea*(ySfPsOxeD`R6pXS88A=lpLbaIuaWIa@f7|TWTuig=_zYWfh_ADia&$m(C zZD^AOC6Y>7da5I@YVj~Ke=ozPdlvy3QKfh_J1VN!b1m4>1?v>>v+R+PDJ5C4PuI%l zXAz5i_92Trhck2c7W|JdJbl0N+|DM*-8sc#k!Bj=G@uOra+GI<0!h$0jE{z^UgFr;eL+2#*OuwC8#wyj~nb zS^~}$ICUpca#bzy;`##SByW%fddO;<$Sj9NUZA8c=m*mdbXFT)UNyhR-?=&!w`y~~ z!Q!^9idx`!-(ty`{^?Yf8j_BYuj)t;vORyRto22iIx2T~lrE@A5?drIPvH?-I2&wI zat2W7Q>V;)zb_S1Gy#XgU__fLVyn@P(e>dt3v5v&*NMlqIz#6eQnT;1&{u6wc+M7{ zQ%B_ukMi;%g;NFai6z6vqe^f)TS^H5%r+6bDSrB*2L)5oTq#cOa!!5CJznW2V%mz! zzKDowt#fZRX&vwRT<7R)j)=mjtq4uPN8}KpDqZOVNjnLtNhWxdPvB(uF&223Pt=bs zS>dlfUV+!2=^?K=pYSx<c0F+nmb1Ga}{GkdnODu>ejZI*7+fr=0?-A;y2L$z4$YP1Y03bj% zyqh*MuA3)M|NeU7%dh(wS!Si#G+0u&h^$>>bG)TKU9Ru?YPr$l1kfe)!QYwFpyf?^ zo=_`$F>;O_QeC18FX>7~^4uX$Z64j`4Fh&7mXi)Gq;+_RZW9djKmGDnp5a4qos5b^ zs0Q#>ZW&V4gA~+>RYG(Yn?LNBiro!ZZOAj-MZY!ip1iU`JfJ%H2%Z-^ZWd^+SeQRw zQ%irZ1*w*^%baJmqQnl+4N!+rQ_-UU%};vS#wKZg4}A1;*qBb=x)h}~7LQ7RKlX(3 z-i*36j_V6r>^?VG757qvR- z!iT)l6o$t|2Y&ROdOb*e2Dw_$w6#1o~r}(W1@4W^t=0ue@sj|kpqWLMtq*9 zT`*1;=$Ys6Hg{{tbKz!YDen452RI^TqqxeClo-ba2$Yt$g80!ASB&m_4tTYZ)tE$6Glo7KkOxO>(A=;lnq z0=wTSDk!+b@ibrsE0<)~44Q%v%x@)|s~;GYd1-Z92l9jS$}Sz5Wp=^|0y~p9IyZ^t z+)O@hTkEU_3KqZm5KS3!Ml%>;oZjeTQSYYUjx6{ajuVKbk+Vum-G@)tR8WZllrW$9i4er^BsnD_|oNb;Crqg!PVdtiDZ65#uaU+Hkj z;>AhN5T)4C-LdW2>G8_WW-rC#P{Wd;Vah%x3(r5AI>(!D8>9AwC+yS-sOM0^CTQD*o+*mi?3~c zDVBM;=+6F`N8<=lMX`!9U7^1Z>KV+~R3E0rP(L z3d*GcH_or(8gN-LL!OQ2DhTPSAb<9&n#6D{&detH)+YNAy&R!`O8jweuu;lyUZ|^{jgAGwDY?2B(_nwqTL{uDOGeo97j+?~3KAql6HIBG?eXeu~uO zMlp?>6{!S3F|c1>EJV&ii!s)tR1Aurrm0rW!8e*wq?NDktuKsc_URbXDfg!uK`+hkXpA!Pd7g8zPVi9{6MOi{xIJM9 zsdbc;3q2SNJ}E&9*A4?_U1T`kr~K#!s!<+UX*9`v(};^)MYvYghC9sM_F4*NJs?BS z5FRObLl(4zmPSmoFf={$!J6C=fmxeXI3|h@t>GF@su@Lt=VK|PNad*|Qp9Np+f<4B z2Z-LlWRXDa1imS@g##8hS+jw;#vI=^cGigv&s3)dk=5jw`d)pLh&Uvz0WPc1N zc)E|!{e0CMM~)Lu#dg+yVFs36%Qm#_yi(l+zm_r%H4;CHwl~lOqpjbd*ny zOG@(fSWRwS+e1Bg{MZ)PNH$?nIm|f@Sn*BMaGt+)y$#tGY*!s^s<9<{RYsyudNVE| zGKl#$K0byTxi9C@)Wj6Jgo`juIiu|aS5X`0&#Bk4ttN2O)EXtb2K?tkmg<7Iy=W~8 z!ew@-YpEf~p$?^%iZz7N#M+YKKVu}`fX^Q_2s-yM|Bwz^nth7rmw(X&1c5rM zq>Ab%FYx_nD3< zt4$lHK1;rul%3QU3c~WWGQ$pq^K~yk=EC+B)fng!oQK#o7BapOW=rJ;7@J=VJ30=g zDrZjY68Wc{l5LUsB$?~y`rS9S7(5>W$4iAPJTN1@DX{n)oPj6Ac-aF@5D4ouO2uF?P*?>Hqj4aYX)0-0x>Ququ``xv_BVn7-bErV^ZE~ zNUd0ZA=2;0qMzg~P#%>MCQ)~An7zSkoMrH-)AA?$b9g-5#-S-oU_rv*|90P5R^3LE z!$igJr7GQ>8);;n_##SN(E*J_RmS&&Ls*h#!QsomSc@U&$!q!ml3=8RC>ynO`*<; z##UU%Id^(~(>4!TDrR5op{LIMtWF_>UBb{r*S24+h5$0*3;$5~beKIGr+cJkg5N(K zW9>;%*9gZGN$Yhgi$3kp5AR!5*D^6OxeUigII_|h|9x(hCG9RN<5avClWb4iDjW&8 zAm7NJRi}J~mDHF%^R-^@C0;m;W|T}{YZed6XHaWh z0p=`}+l(<|3c;}7*z}q6h+R3VmFBS??*rEt5379eh z%dQ^VQ^^whM<0tWtBujv4QT|cXm;_-lU~6pfRCM*5?_FBGxW-DQ~_$ih`KZ@eWk4L zc#swHwuLg-Zu2o7-htqA4P5yzeV}T!AIontQ>0yU{Q^2_7vVJR`v>z!iSGKBFftR5H`!r z#Il0@oQ}a!Vp_b0Vf?F=jU{SUOH+oUMy1H!F!Dd2Qs`l3PnYmLzK9_EaJMS?OMFCp+Vid`X5nKs*NP7gG!7=@;nr@hwrNr zdgM{%CnT=q1pYY{tnu#kzQ;kg1Ros2MhmMo{H<=na&zlxOuKM~ofXqU6MJT`-gZu-?m}e5=LEd0?M??KAobcR|w`uDYvw=c7`bv3}1kNg#0va zLg34u0cI)rc*Yw2Y3n$D(~-o-6m04 z*~yrv!)r*n-QQ-pPd@Hf|KH~{f{zdXD$zc8urc|+{kDbcUrr+zp2Yg*$64$p8RK4? z;I^RBAKFAt3uh2)u!zLa7su+|^vBnro4ux2^0_M9!ymq)!9CY?b`1`k#+lrs2N^77 zle?ZvjXcw)bEG}k)1Nl;kHnl&YpjxrJEsux*7Ck7=hbvM4vl&Euxh(C>J2Y*$?4MAarZ{RHa)oNauRinn zgDs<#u21sn1Wt7+i*_HBX%xSR#|nzX?cDubw0wnoDV!Jc(#hG*$ZlT^IZTd9hE|Jfx%a@{B6fL6=y?ZvR~KHzk1NQJ()F*3+WHY zAfuZ{94S&VVmw&#dFGWSM<7nci5eJ0KFWIVc4;+Jg>^B5VZ}&yiHk|SA=#i@C*--i z^5M#zb{2Vrhh@090jgNfuh^NL*|2Zdi%L|Mb2W>3LSFG(f1i91d7RXq9K2N?srSD1 z0k&yY{x7CKZ8+v!*L1I5c{AH9u<;krbN&i34H@pSdVxQD_4x!*6%nQ&)%xH5muFFm zrR|CoB-Wg{yHmJgn)m$m@s*;8_Z`CL`i!ULc0c20f57(cVw9!jWq=be%|MN|3LBNvORqME_tpIehBxuIWL8s&ELYq=Y6h@ zJ~iqy&&34StS)_bI54O?&)4zPVHT#tON$F0>g`-#T?%$MFs?f<)bZ41ZkEvqU})F8 z>kGeA1N*4W@?71W`S@Js-BrQ8?{@S@sy=C)#N#bjUn{$;E?qesh}WH$>0GNZdo$y; z!~_Sl#Ux4bB&hQwnD8Vx^CbB5B*gLj?P|`@zdpSxO=Ib6xjESLxmZdD6yt+E#h`&DmOQ9c0q%Rdrkn`VNLskm8hv!66z~Rc4x!mo5b# z^wlFB4svxGnefPBf-(C#rB|1h9S&sb&MS31)tQA^@bqJXSw;hy`Xtj<#p+jLjZZm7 zz25|u^_zS-M_9vK%KEuEn&ui@sryt)&zMtt%EzD`$O6myPKM`m(!Nf`)unZZ1Gzd^ z{Eru@bn`r`xzT93@o2e8Xt`-<$3J}%Zi}Flyku@CQ1FoM$D!Ge;crh6rLQx}AMG^C zeRJ-8q4xhk&gp5NN=0;z)Gj_Vl962$;;m;7ob1Q4rf6d$bL+u8oP_w3_EGaV0!Bdd@j ztF9xfmt#8K?PDifU2-e*M{w#4@qOn)oX}v6cIax=8th=}&i_0%wiNhpU7O20os*WT z&1|dMs@|V_G375J=|s3!X>zZ}V$!^Xg^cTR#t5)FewRU*ovh1q$$p~`TrW5kGR z@=7{CNLJDQx$hJfdc)}(JhSZj@WQy%r9%`@VAw3PlBN*@PCp7Qv}o;c7cZT$B9?fp z{ZR~%n&Qj9*_9)Y(&Rn7*;d;Z9(gdomt&S~Te!Sl;J;aLzgeii ziMTwwE3GYIP^%Kvh38uY)bCP)By|&$5ebWXA26IjmuJ$wE^a%FbVZTyEw4i@0yn03 z+d_wn@ffm%LvdAaquy}&i$FS&oS9j!+*GdK{K{(%#T`YpcRbYVsY_1A1hKcCi*yPm zamr0HCvWoj`||V0V)JTWX-b_)!Bll}8M7QLU6$#XzbJ*y6)`JomM0}%PC-4BsTzi_ zU_T1WjdmL~RjQbzd0vmNzZ>_K8Mu>@3w}-t^#YgNcxqEL1RuzP|>mD?<%Tzq) zZF>(vU!;6&o{RHQj%Uuqtc6*lyyWkaf5t6@+&e&OFIzyDGr_H|L^PV{b~b%j{*uR~ z+03<@#G!latM-jSN1b;XZyuG{k60p5ou^@MP40DT3>oC`ovOE0uOe*?MaYB3AUmdV z$E|`JCz=ykb5x@dyYRWp;sm+;T>DnFQ8G+59TNFI^A9VqCi~Az^@I3J$|UK+3bB zl{|aVr(GXB>O56r`~KUNf2@nO+wGEijz`XSFy>7t8vdGDcXv#c*gMXy4ps2z4GoRl z`F83oDPA74TrF+SkJ4c5Bq~qmAsfU}rRj6LZ;gjwd*yP!q1{PqU7Z-lt}pC7&CJZQ zO0&R8<39pSEu4p%-y1h*ND9l!!Dc<(*!?tFRMVowiElog#TLxr@FQ5+N=6kNnQK8f_IY% zidZ+v9megiU`*EaS+1D_j`dmahED*d)46B>%YHM)-3C5^Q~#7xf1nHHR~7dB%Co?6#L}^pE`Od60`a?# zg9<#$q&#WmFF4XL4?iW%V2g2^_X7c1-wier;LqR7l3BC0uPHoqJ-9w=Z zxCjy*W4xNrB`r| z3Vdz1d5-s>i_Ji<|8g|Cn$t)PVc5vmFu_i|!BaL45^cPI=pFHpg${UUo5@u|Vpwso zYUGZ%`&A;Kir5`P6aH#u1+{8Stg@H-@B;}L$7mVYKC|5GC$IiRy#h^PQYgquH#y(x z$q2WNr|vp-l>iZRqJEGDI+YR%!p*k=HB^-KK8h{2aN$3{Tm+Y1$1{_r_I@}ssd!ix^nlobST_JQhq#+LwKC~8 z_-uPgbknP+VdUq}M0RGh(jbiiL?6vi2wl_OVtL`U-9R(le8OQdok;o&M6ogp%rtxU zSJku3N|@rCbn23&=~3ja2cRSRq#>(hqwrwy!L@fcXJhbAa?_*4&}b`NVuzoVYj%TP zz>8dyWlC*$k3_NL6brIkT{OwtGY;lf78v0!LGBm>Akj?LGqc0;TAE#Xhu}YI!oeq- zr7WaF+L`64n^SpLRP-Sw@J>ZcIW>IUQfL}!d_HTvUc879ld^$RQ;CneUi$A102Zen zZaQoIZPqcfV4wa<&t`V#vSunISwZV*>S_T{G+y{u6f|T!dSavk&$Oj_$mM@J7eI(* zIupXzz?DV6wlXeYv>vS*IlXC-95ka)(>3{L$EkrAr;eolNokx$`^)t&k~rv(QRTv_ z+o9{7SD(74DpI+^t3z^{_GG#XuN%kj(J`%#*Jtt-Th?`;rY^lSLPSj$iz^|Vl`dcFFg6-?Dv6S zEKv+IW(TlM^8e3m$$ykfM80^MrjE%UT5Rv@4ozg9x{_NGj)!dgQ7(4*R23&>vr<_P zi6r7Hwi);nnyg+EJRdo_m6)!@*F< zl3Gt_7=P)Cw6VAs^WkpNA^Ph0c_yg1D%e^`Qqthn)HbGIC;U$r&7sEzU9%K-^W^zo zkpVvChLP?tFI~@2E6<99jA8_>YD({3L1}Pl_#S9!c)tN5Jb+Mo# za0=_9>G+NQyXjRcPqT2KW~ky+R~2vy7T|JZQ}rd(vX0I*&CHF$TO%~MdvWRG*jMACE(yj!aN<>hp?MW)zJ&@J6$<+SO0ljM7*uZH&Nm6%XIbgP;Xmm z>~|psR1bBGQ{(}nxeBR9(_+^lh&?fEV)H8XNons;+^(vPH3uPFYmbd5b?I@1buY@i zdk|)SHC-s8Rn_xz^}yuBmx1?@|=Q}o*VLQ`G}IHZ2zD>tx8QS&MBE! zs<>W!6l?4%)JFzHf&M3J8*^#sYiURJ1BU@G!Nvr7LtVKq)#4UUtgPza8wcwFn$_bk zu^L89T5XHzPG)k|giJDjp3DMEV%s3fX0n~g8M9OsSG$Hc=@U^-ng&C~@qV-OpMY1p zGF}?kYXe6z7z{L-mJ4Qho#+_d@|kEB870@}yAe+>x758hm+2=-p~+;&Q5v+0bQj zDlAzD%GYP2(_(AuJ7jyeDDM7Qp2tCfplqmbMq7Sz&m%}FH`~KjP?DC`nn_y`t2d^y z|FI(03)yuu3?WHcRet8vv0;hL7vBsOu?P_sPHeve^PZvPKr0oIM=2srQz_nzZ7Y9K zOlir;w$^bCQX0#-s@8EwzOA*6ThQMRu=hmNx#+2u(+Sp2ROEn+fSwU4g&kz z{<+5BMICw7)GxDVObei5SB2V@9xj}#duo`D z?M<&{de73Nn~m9HPHxfHc>&ClG@;NtZh%tETsq(t05efkWGPqjo-aj_G_u6pD{%TI zLrGoN!gYyGOms6^IWLtWhAy&^1KAcX=DcTbGCl@I=mUI}>NTfwkUXclV)LGbsugSR z>D{-Y^-PG`aQ^qD7JWwB!~UJ5tSI0?*Ln}fsTRLoAqg`rnl7;PwmZdHNCez4jE(OQQ+6p3Y9DE0y z?;fgLGnhYLvn+E{4-y~FHw?-LHB107$`Y&GCwY+Q1_Q0`u{z&lEs@|oev^^T3H4e* za^yb;bo(NDSUVdV2{KJe_yjn5jJw&d>gPL>5;=%GwVt(46%RW{AVv?6?O0CD2aQw; zPL(R*M3)`pdoYa*e836iSG5=`^(t?jQQ!(Row*2l)>#lSo#lavMMw?~M#aQ>@gc8C z=s1BKCxiyrX9*GFTFzKU16g3P0B@!a8qhFuL(3XWR#-P2JAIw^X^bcBOmBgDwbSc82dWadjD z6R;`=R-fz9fmIv2`N~sqn@^Q9pO?(q3cEVW^pXXwNqVq_7=(WgWl%Dn!<+Yk{Z88Za`)B} z$^hIE1zKqhEr8mQ)j3oovj*ptLNBWnaYOmxloh{RnkmHW>5Y;-_K+GqD#awFcoPxg zNCqg_PmMJd=@)D{rU2p$SsGn^z_;=zDK^>+@xg1H+TjG#a>-wm=NVzdzqLt~O>Ly} zHpJcgROb^%XC6!Kw5(@0gCRwDS*J7EEmhQSSuKX-U+5sRz9Z36`2lD{vJ>ZQ5_4^k z>uTgWq01%#SdZC!I)brw&hGmuw^#CNeN{G`W0*@m#gNw)`R50I${bPDwz_O7dXe)b z2{`M?`&(>VQv@ehr`U!1HA}RF;FWziM1S_5av^k+$Qzj+3>fYU*^2k~%3agIL=v{v zlSZm~O(PsA#ef{e3OJ<08!uC@68psV1z&Oi~vQl{WF4cX<$)>GUNez_HKBw7%GI93>D6}L>ff}GUu)ipRVd3>>_*`QeBh!O z+(|7CP<^C>NI=ayouO>2Dw*miSiCifB7E0gKp?wZ&m^-NXXF%|R82<^+Q3bjMKn`w z@WVO!a99vC#B*T`Ei}5}2+#I24&lo|bvmK}RCS{)2CF6tB3*+coW5attF&le(9uIi zX^y_0k#P#-!1CrgwAu2!n+$X{Iy8TC;lrKgeFf|$9_$u@nV*HHwOpJ8V0v69j@#iC z^W$z7gD>p>p?4wXEJ}=!O5Z$Q97no=;NN?t6O4-^QRi8OAv?u^U!;J!nn4w$Q;`cwZTd1zCBPYjH%?PpWWya~Kdh;M)Vh_!6LVup`hC(7_wI zVx-QC-3w(Z#&GLBMp?%SnVizdceF5XBc6rQi2W}cB8Om&rFbeeC_WG(v?Fld`)f;Q znz5L$URy!c)TTO@Kc>bCmN>eORc7enN{4GI>1h4wz9~krzq989P0(7khE)c%$!i^8 zqTf#^@NMlMkp{2{E{;hi^VK*fCtw=Fq>krv9iO3 zhB&ucjzw31c-FEfqe77)Alf{RdS&6p>4E zd@u{Tl$@+Q7^gSRzGw{!agsc(r+BBkxQ;U&r`9t+S?%{&=fF4x)M6`LatY>%&jfWF zI$I8u?|KCNb)D57h_||zYPk*aLIzMs?v-jRgzN}MJcr}et%nweCCuYaCg75^m7r)B z8YEQ{O~w1`mPvI(1{F8$b;yR`(8og_wDEA=q!W7wLKMvbK?X|B^qf9$8z}J`B0U9) z5p?Hm4lCU$_%FzHe4F`GQxw|EVe_1^3-o!HZjORJzSRxrq%Ltw6TcBn$}UUdRIDP~E3!xu5JRX13-YNi*`wUmX3d zEVYfAvyj$8b>6O%@kC4xiTPc|6*)%DYt=|}7kYU`KY&-v_|V!-7CJ7&t@rRjJ_CA2 z_yp<$W{_kjIg2_fn%O7|n;sdS>{KF$5%jae<;wReBebv{0}eF>Ta&Xl z+>)9($(&@L0LC9aYpi55s7xeZ;DaN&`S9)Px# zNs`t{6q}j|`SFj6?z_k6fAR8~Cg#0d9Z3MWs>^8RxdXk_JDAz!ZpT0L1;{Ix>ES@0 z%3~)8v|9Q|@-!fR?XgaYO-wwU%lc=bU>Ibtg*;K((nhM#3??emS9^k% zkuT#=>_STMCR8bGa}Jq>G>m^o_Kl}Y(m=@ZAHiLQZ0F`A^4#sMVB{YS*8a5&ch)Y) z{n9qz0QGoDT(-cu8VgOU}l2jf2QnNMEG^SWZ^;C*5D`bQL}EZa7$BT5hK-W;XRe=aY00L-m@Rf zX20({Kl4;D5ax-Rvv0Ki!MY0y~o5(`0d7o9FPQjEe(l9FY+eiwcK&G;)`!xVoP~grSkkr{Uuos>F z_42Q@MH=#_Xy@g7x}f{eIYSoqkM8k5x=?NZHbXkx8OFN$npUirHmBM<j<*VgN#3HRtsXO&v>uo{^f1Y6 z#?3g$snk=!XQE=HEDyGh8F9Tso4Dy%QntCRjia`CtgWM-_Px3ue@f(5s-h0zbdglA zr}&{88Cx*J;~+i06tK4i;dLLx9<#5G#KM<+&(24Vka6z2bo z0^^@ij3SLfbALlt-v}xM=2V853jw!!S&0<3>pwTv`sc=S_g=wI1inYxb&qx=vHD++ z$8if}CP2nRflT<6AO|f31(}+tIr7Wn;(nR*=0A|iwbtM~xmWJhKjr?f**-zsD;J^7 zYSdDL3#8Mi3jWC8&JJ=yCg$E}0_1uNpT}Q%#5S3$S=5ua7*`C2Do3k|KeL-G;^2|H z3wRPg!0!lgZ7*suDP>PatLVy?k*hI^*B%*Rnp}&k`1V^orL$K;7e?BRfHQ(ia_1S_>vEX8s=Ss){+pDzdeTV{(Pbe?|B>J z(D`CUD(tSvDx<-G4rxDaW=>{JzT-N^JUGgz4$s%0-F#1)9g23s14BUN#ratUb8rD=t-?lr5(7K2QulREM`!> zHYU~!lK6rn0Zgo3COzqKXP5jdH1m1)eJ&u!8?m{*Po#s8iL^b16V;!4_vP{a7dC4Y z0+GZDHVuM<74hSyms;WIHUWstc8ZUkNh*L8q`8XvE+AsQTyuRc^DHUh%{Kd`ktuL9?%E+Zw0b2;+X|<6wewk$mDBef?v>o6O2H5b z=TIiNd4R2Y_<@c0Fy9ShcaUP?dB+R6QUL2GPf3cTif~PFN?V#}-R0e`qWKy_&1Dxx zxlO;}B1!yzU};|8C(|a{HAsc!`e6X<=hwN~SGX#?I;#}&!mot(Vt zeKF2*7WGu^Gwh-y^qTE z4`gt9c7u8jgCv|gSKK7&@9}19Iyy{p9jzhxS^|8T)hS0njq zbpfe{v26X{d$*0V2XgAfC?Mkyk~GUEtO~&f%=e8;x;~_;sW%Thr>+Nx$};lha<1>` zHvXgg6nr0{Sd85yKoDMwUBzo^?Le8*#Q)9lqZGH7BlUml}~KcFRLflM>JbdLVT3^aE4d=A+I{?sS*v#+J%9a=-fR!q znt4E}rQf?*5rL|sv%mnRq!;AU)M$t26aoxeGCp~S_z~KddkVeq0e~)-^CVYd-M{!B zWOq#~oH|VTQu;5ueXf@0?+*LYcB>U#XyUu^?ye0^48W|(vo;#ZGkZ@hF5(Z~lqN!L z5^ro08}8SA_v>jXZ#Swv1=3XSM;te=O%8Wg7R|Hvjw^8)S~D&paLC$dK%QS>srwUe zN)p&h|JXQ+?gLdehgpOd2OfG}As_5QK9)7DFXDCSbu_vsa&vz7|L0SPs@|tM>vaFe zrx3aSJ%y+ZJcan`$2@Y*hieRsnkPzsENqpJ)QhKf|8vfVBni-+2WsYkdaqpN>$mL* zd&veEeOFmqe*`|!gqE1S8Kiy4^pWYLB(uf4lVBbJ?`5qtk?hAv!rXqICYpUJ>1){zhl2fk`73M#~ zOIXW^!0a|dr7#hP0LACQx0uH&_#$a7Gx}nuj>yi3jEPU zu-y<$5wGiv=b73)dhDOTnkw;QQwgI~qUS)d?d!gwWOPi__ad+0KGvafr&N|#@1CxQ zx(ncC_VheC|F54`6{VQlGDyee-UVHGZ`ynXHP^AKvRgf-i+o+Rhluyjo03BRn@=#Y z3xW8EDC)2&?l%+IYC&vTD@%MY=o6>i265Z=e6A2fB6rP~n`dd>*SGMy6Q5>a@JDec z&(`~DUgTz{hD;bX&()_mf1PFFbJ^!|ck81ea(5b^c6WM(2~5mTr{{fnaMh9>im7#b zaz=Ki=5@C-?{j@S-C`Ah+1Cy|+^-k(R3jB;#1uHJ8u;9R3>d^#MF-s zDD7+KSzVlV0@t!9pXhsEuNPiP!@L~N)9#kneQxuO@mY`M8b z#9N*Mld^>C-=3~togCe4!g^L)JheQvh|$+w5S^k|v%k#mz#dq4YD~h%WO!a>R!NvY zm)w2&9LX?6hOSUaZ;hV5!1Qr*1(E8-2ZZ;wcdstWyPanXdTNmhGhn902e9+PE4zP0`^3H1w7?^2s5vf=765du_P3|^PClT_cqCzzTa^r6V z;}q9b-OlR-uT@CBnJ_WG6Ns=b2bjzVqJDRK_4J4mZA}@!cGCrIFy80(Bv0Sx_6%r` z%Ol|N#HE`(|7dEqMW5e?iX!g89sWtH-Ap6p7I=MyZKPC5l`EZlH;1~_1y-^3n3_2y zRdO|JijB$?W> zV$Od~ZEh3vevAnz^Rvy}o95YD4M!g>-}+_N6XmrAI#@a*eF>-O8$a5@O-6{EiyKdm z`~0asF`iZ@)r$>)uP$aC?%TV$s*(!RVW!0e4E46JZzjhSgMJ)LNb%v9%t~+k4n7rs z7v7$O{Opl8I&Sg_BTr9uO&h8qATzDWp-{MyDt))3B^ToF@z$E=fb#gCgBcHb?i>d} zOm#;=i~6ChHMapX*@htt++vexE(gIOy=eIY;-O$zvY*u6clhCrFq+AAYX}*{{-_mm zEs(7Lok)VI_rm6FDdCuLRRCS55%;y#DO=99RrK>t&Fzb(`SuuQH>&9Rq2T$+LCJRG ztok$Zta=UZ!qr8Po2xFVFg+$&d;oASL?7;(^UE4iyZxE(H)5I_pA30MV`-_qdcj+h z*-kGJD)t0<8gMvr{7xm;bn$ z0`~#4u7)AxernFmOYhYJclm?^ryOT4MRmv5giTnfP1OChnHQZF3gTIj9ZNZOLrux}DhGz3^pRO<*oIODP*I z@DYCZV%tgfF#~_^#ALK#{XypYKdDQt|0F2n1fBGw)?F@rU8aZqY?y!eJF*3B{iREv z`{f(%8*$}j47-n2z@Lb5e!Ka?WtuTevEFkzk3U%ATHk zVXAqSw4u^wbim4VQ62bYbxAf?fw^}hMk7Nuf4=2CFO5*~mpQo*=QKF_lGqoroR3?h zpJdM%5+LC>T9vT7%m-Q_u&hIH>w!Q0C{%tsQ1HkwbQ>`SRR`tA1!ePrzFN^;@t+lf zyY%z0dXwpu#?5~&fusq(dN}B4I2OKLNF|0>X^@~kY8WES>o1Uc>YRonuh(f^f#MNg zGQ(`P+qgvuJ)WygQ$`sb({|g>9DP*<5rbf%z_j@CX;}DQM$X|4abzw)+!_P*r6-wZ*w$^n|qZ-Wuf&iV(S$nMxef> zTO!EfAiYotL4!xiMPWCWp^L3p4)fT4r*AVyoX)sXCAE#!2R`nOP&se?Ll0DtfcNgf z6{*NsAkA4IHr>(@tGLFJ6ukn8+DPYF{>H)n#drl#pm} zoNU=@>N-F%uyCq7iJn_O%50}Od8~a)9<+5^OtGrgheFA){yYKnB>?VN_|dtn{mFY9 zeJH(}+$8)Unf_06%<}JF4PM0+B7fz-OcH?3AJ0<8RTXA!V{Z4@r(7ty#`HAPbc1(6 z-I_UPU7gAFnL9T!jF#b+*thTRxf*!uC%pwk*`^`?N)H?b+G?2v^y-tYdbcwURj3e2 zXTo#Q>&zi0C_d}D0sdgg?euqz6jPt{_;rN60?zGw7C52@%3Lmze%5sqLjSj9cRCnP zH!SnEf*6JfG2G35ikF5H`iDs6^7%xR*ZC>bP*sV+nmMYa2m=*3Q!0C3#^xPwFo zMYC}EU%E{^zOy_aj@7?*#BU3^jJ}O-+(wK(Koi4WAAeO#oz<|i9yKqpv>3+g3P|@{ z$hrpe+a`LO)%y)K#*dO>-lh#0nJ&lvP6a%a)~LgEfvyM9JMKT{M&FI7>THv{V-8>R zhm8$%e@Nlx$tF$PRZk7DX?+GxzGxN+%q_OSE>sY(W4@-Dc{1PN zgzmiQwh5xq1Sx*77Fm>8^AG~6Y;i&>U#@rgh%w7b)RvcOm-6?~pDY26APB8IcNfWf z(QL^x_+4YsDYP4CvgKs@#z!Yhsf|HSz0Uegrz?U(1yZHy@RDS_(#%h6yK;M>a01W+ zy%gS0)_eH~C38!RqSL~+*V%lgl}$frH>uUOI@&B6N|W9;Li8xMctC+^h<-(;c2Ubx zfvI8hlBAAFyrfTSC$8VewA8-CH|E+9-ov{rc-BGb@%#1f%6ESjon6#*?_Gr)2~(ph zv>VpWwVi~mr2z{@iA%wkB#6(5vt3G3EFKou^odhI9XDJ zPSb!hlhpX~=v3jf`vxcgoZF~_(VGx<2rW|42t6)RUDeKo5yc>15aoipPh6q&f-j{L z53jKGrU}}+1qx-1gtA`DfA)E;sSTs{{H~y#J$P+z?R$u{1T>+u!e|m0-95?d{!3+Nw0SL&q#*8|6aw)y~NcZG=NHO~}l*t<&;T0j8{(KU*lBRX>|+@~Fj z_t>XT&i|Z06AOX15z0Dvv{bPC5lwpo?-JyfkK)m6(vVOABOEtEpFxVj;A+X+IVTeGQlDA*3-RP}+S{zy0+z{=fL)!(dR!d}rBq`!#8o2IQSVQ}JVAfh%{Lf1p*z1Lk)6sxo}rM1hO?l7Hu2!wJ2DTF0*`*KJU8{@Vg0$=!7|<;zjw za@5k_bU|inrzgC5FUBqJdZIOSO)*6UdQ#Wb7Rk*RCWAGUr|`p(66XWCKHC}=-Kjw> zdQwep^*+br@wA>x1UUL8^l2^H?t!B^Wb*Nhw-28~;TRd^%xOLNX~E^q*J(tUv(qR= zHJpSdsTQS%A74LYOQ5w0v-TnP<`!;k^_!%!tzhn|?^w7lex0AhKMyFrpNx?>Ica|T$%^T^2eO+7Q{S!(gRRwUp|9Sw zkr+$=z(~;`ogp}L(AsP~Ty)N_%=^3px`;D}MduVE+DJ-%IDd*@I9(X5jhEo5`;s@c z!s+X5^4fzRCL>rLTK};lRRIhEP35>(gK$QkE9J2K@7mphMRq1|iFuDTO?48B*4>-&RH-j%Nfyj_62TbmRl zT=(e(lkN4VCQbp|z)X$P(HfBh&k|(m*W46v6ny!?EZU%N)+_{pgi|fn?_g^pxJrM4u>gt zj7y2@3`U2$$QB23QrMiH1uW=2+Q2=pcKR-gkuHBMZ_|*&LloR#rqaTFvK|&z8RqUH zO``=YsD1(z8>tGFq^)NUn)9%WfyK0ev{gf54kywj_I6-?jqt&449#6X6m=%{@maTe zRKeVMDXp)Er&at562fAk+HSyLu(Sc0Cq~!U@ch7#*AZSCti?-EAv|5ch*dyM=iF{1 zsfBCd7noq~Ds8SjQyCzgS`>`|zRah3ab>e>~3Y~^eV(ik8n5lzPLD46q)mQYq z&({ggrgoe+L3n@{=}wn4JCuFD0$vm{i^D8yrbF-iJkQ_%N^aLKt?#9mXPa|_fz>y) zaPQGOHwd}nG|RR+y|$lr{9r+$wiF>~eFpl~t!OW8{`_V#IJM%#>G6^z3&Bqamg`9& z9Qd)4E4m&x8kUCoR*~;cP4uVVqoU(DuUGY4@Og_Wf&ZE8F-wm)e)QG4R6Ag`q)Gz? z*r7ab{^Pqu9h@Yuae;ddHwm+Pxask9I^lKoLLC*gO(H)`CC(;M;YSn7^z+%9Od0GD zb2)^WBBGTA_nU_7Pi$M&wOwFOn+N7xfrIKw$pIdifw*kLqnu_{|Fze1}YMx~t&pKiS6tWRxC)JWM$*Fz&SD4B-4sc*6i z{2eJ^c2;6}^)*fboCvC)`3qAA*}Y=Xah#LsKr|z$X z>kd#aqIb${N;!4N781UTRoHnl2^b6(|0V-bs4d?J>Gw3**)I`0XYt>2Wr?1NR>O-q z#9%!rK&2Qk;iGR>r2+~z<3!~!W0c8_xo=jPR+%Qe6<-P8CaLkgx7J*LY}wH2?7NL& zL}SH*ClA3wck;+wO;vNjboEeK_ma)XqY}sU8`+>AS;fH;fD?S?d62~RUhn%QVFdj1 zT>p_Q!!OSV6Sgm_-+U7iUXlATU|kR-r6um=o(N)8B3GCSG9=A5c(ya^D6^wCu{qF&Gz_!JZa|}3BB%As8w}%`QxL}x(Pt%x-WE> z!_p@n3zVa3C44Oh65jYjxfM!7~cM1XD@Hg$u;{sE-3ihFuV#>oz6% ztts1X(61hsi&`U%vuRx%i8D<~5BL4dfQ1Zyw{X4V1j(hSd*x@w|eZhE5 zMz1Uq7hq7m3JZ2!%YAl=?bdZ8-;uVE-M0v8^x3RUre*g^t61Eq)~co)f6zk3$b*ME z9<%(*s_QDgK;+U}A9%$9S#bE`NvTp?M`1T`JNM0!enO(3>64Aj=bF!TROYk3##T(V z)S?PWTI~|W{@HHr6x8Un-GpB^{46Q#xnBhahEU!!4!a?tUK}h%}B~tJst%sbArL6y{M4py$tgrvA9VTKJZoxGx z;Zqv`&VR${1abR>y2KSJm6v#5ep4h=)E&?`eEbH*5)+|BXZFX#1E>IFjW}~IJYv-k zEjg2awqrmN_O1F3OU&a_fGk`n;1B6I!NDWipWABix-3u&?s6B@)$;g)MvmMTgfi_& zL?2q*w8m`8CGjM@g;)&>HYt7S?(kr-0$b?G%c=<3^KFT6&FmgK7WW_znWVTL*9IXW z(@4sEIyHe|IsbHS7nOWxK%;qT%0g3BvJE_~ zWq`fM&@;87XB{x@*phHJj7$3a4`0VQNo(@hdr3XkkvjR4r6s`N&(d{FlAmiL52;7# zdG%QB$aZAHT8zB_@syIM6*s9X*enUAMEH7@i@|!_>}SITOL4CZ_J!{kUhrNJ#2KZL zA#>-2r{nHJE-bE-UBa(Nnk4xm)v}s5)nW2%g<%9kF9@g|_*7jIqB^vdj@r*Cc<~kEqTjkAH|hh0}czaCBEZS3P%_vHGS9tF9Xi6n0g0^oYXP1w3Etrh=@`~83u(qGbH%OCdDSnKl1{TRU`8ju+WOvtBOKYu0>jD)R03?ud;gfZ z^<|S9X3OUBzqe>??jVdP>9`&Rmc9=Pq?3tVJgPfZX}Y&Kd9W2JIJk9)dSQpHm@m-cI`^) zak47qAE58-2b|rw)iO1ju}1pDtcg$;XX!VTnSBA4)O=jnS2V(vyHIxJry=ka&r{C> z2Hw?#Nv7B~2GvNZS+;cUsDmVc8w=(IA-4nF zh2Vo++=y%S2i58YS4olv-+3J)CHWLcfqwD_CG>ewUb68FekR;wn-T)ak}w)oM}Lv>cj@xoMNA8&|M~)iR}tIaNf!_U zYl%3C6?>y$1EzTM@?d7oO{Ovuw?ed2LDokP*s`z^kX$qHE`}a5gaGTJtOR-Hn(t2V zj&t7;g^ZL_{kmBuq>(CowV%VVfBidf9%G?JEV+3sUbPu_`KF5~UAqB^EMEyZgsDa% zPT<1mD1CF{oOw_RYR)qKd*_%sG%e+y@3@}o;tjkWzd~&MzzjAKjy_76sYuCPTFK*r z(q;a};-RH%nrN`MSRPfcmD5@usb*Ct#rV(FM6jo!@m!b9R49(d>^hrn1IROH8npuS z1kW8XDFlua%;kGoH9W>oF6DD6x1E#n+>}H~5@`Aa49YrXJ}O<8lUoDChn(YbvnZ#| zT<>UfwvtMg!63>` z4JN=sZE5&#&?AVg#4qd zGj6^Z__HA`yJm46v)++HG1c-@cI2I|fhv+-L8(SVhKggD+Ijj~E1moZ8YGxwBopZ_`~!@zH1c%Nooi*`B?KyQNx_5T zPaC`WpFZ+9=RIaXeoRiETnZ!jQ(=J%mkW%u!4m0UV0n@1lq}Qu>R5Dw(_k)Y0jt^_ z^kEiTtXlUvO@+&t)G5kMd9Y7UW)EwM)5Hl@gZ-XRB(I*@Y2bI*rIRMd>hOm_%+o#i`3kRSr0u9nnODWm*Q^ z;;O%-@3&ZAd%X$#aLrMdqce}f*_Jsu zBeL}U_Jk-Nc9AMi$#oemjdExba4@}!;+!Kdzp^eOI#H(hTfr7z{c!%j%zyl60E#zD zOibTB{zVDEA1r`cMDirte3EJgc6WhNz^{zAm^Zi6`F!z3*@KaNlKkYzt|2PWQ@{rrA*-)WxDf-%mK>-Qe{_rFmt-i!w1U1?gdQ1^l7RJ z<3r9eII7P2&qD-eOT>|cu1pu(?oZZdL*)RY8tAgH7?2w9+0?Pm%KfwcN6O)QqHe8{ zt*7Xpi>anPKdNPRv7w#zI(AV8rq2IlA^SQ0H=IfXzy?J&**BkPB2$H8fubac6n2Rl4uaT&KP|Z z`pD`cc9tUUqzZiP8pa&(M_T!uf(X;HPB?O|`Et}6)<2JsT*n-U)FxMVCyL8+ z?(o;nSiVt~on-wl;l-U^_R6YnuXaS`>=?`)5H+lui}xesPTaiymL($zX6jrW0k2mV zDv1d+K8N;wfU6*P_=#fT*m|K}ItW$v{9>P=TngOU&`sVh&|G_SJ>byYAC;$mKmG;s z|Lfve@2l$mvHktTPO({JVx!(-<6wdj=0Av7}a z07J4yHZ&Ox2-@HW*Q3q?1&XQn*7yu zcq9SzpzPJ>FIKOl(I+BrfIlL*SyH%<`_6*U7<8}W{+6JH>UJJE!IrhTla1-0l0a_% z-Kr*^2>~F7)hI^O^{w65&=;th-XZyV(>8~q+)o5)2oSxrnnLfKcX{KJax}p8RZ>Ll zFDSbvd_#oOH*)Yz0+=ODMj2W;%W;0zem{i8+O|4_pB$ms(-SIXtrpGwPL%~ra8xw~ zA|kQO=W3l}i&UnbbQmkkAWO7G1f;Jy6N~)5!XjJVVja)au+d#!yqiD8olhDxzooI3 zV{fdtzV~lT8_G>zF1^_OF*iSxx2rs8r_`91mnS+>%EnC%Z&C92wgmPyvS|G+br>ae z`~_rG%!Oz;`K^n&uY9~-YJ%ru8NlqKig6keA*VNALgKQkqNd+wk*W4JL)9o$iF?C& zv#@~Dy1DENgLoo~HiW2Yz}dxqyfhMe<^i9GrX(QxFJ8C$dmsvU5`u4WpseKl>|$P0 z(s*75afQOBw66AE&o44A;F+o`W zXjYV9lSZ7;B}skF#+*zwhD~nQk+UrAgW0HOjp7P>>-$}_U>JTkQGKDjJAP?t8!DfY`g0S-4oukE|HD<;9x) z<{JcQ8O?$4FHD^qTNu>rKBe>G+s2ZFwYLAz0iE;PjzEKPO&}_aV?2ytTeEbGwDc&J zRZQrJEJpcyDEwT~!E2VEw+`}4T3hkUVQk_Qi5#Z-g@r8g-z&BFR$52uF(R5GN}7Av zwD1uDTQ*yD?x1>qVWt4%g96lN?*q#zVXitDx4X!o)5ojxkS} zjj)6VA9Yy6*rbSKOiP{Eh6=bzYJuMxf$SrrX&QeDF!=cdGFUj9Vn!^7w^_Wg|0E0^ z*0TMkik?waT73!pYvWBbe#IHqUOA-sU9szxBfOmnKy$B-N`NRJd6jRlz6bPuN zbm0^)1hcqJd7W~{e@{0XP$F^Z@59xG^7e@iUAAo5f7yZs2{ zonNPwvdhBBP5Ty|V_sybe;7{H{fmbW_-+iYMX_xYT)WN7ELQoYLi?*pMy;s27cH*_ zbC!FBwHX8_RTrU1i3*(zKP+bOl~R{>)0lJ4bu zx{&dkH1>lfdYTNGo*Nud_XqxChqJU{a=Oka{hG)B6==|MEg0Gf$os>5R(@*`aLV0z)|= z2n#*P^mx7ET3V@`|NFD1;q&nJ>_+4@P4vvDNrj$UM&1uQkGRQ!hr~fi_|IT9g6^*? zdTDl}3C-W9LW)m7DO5JU>ZA}@-+HqCFGs5|z(Bw3-zzwDdfSB^Umg7U|=Z_Y>QPb-Ofg|2W1ifB@4pWE8g{kc-=BJ%=^7LIU--PXNAqJt^y0 zCMz$6(}V6(LlK`2m5-&5Nu_)m>%%*m1{T#49$A$c_1p^%E8+o!#6hYAY#L<(e%2MV zO&lQcPszVD%-&W5HlNw=HP;cO^OQE4%ks#=D&j<3T=q!5e+(~%Zth9vhy&g z|MMTEfD?o`DR)ZVq@`2b9^cn6qoK!d4-Ot9L73)~ z-1ZrSA8cI(-A#R*2P}{JYtuFYsV@(w%u(F=`hC5)^1(L8n;zbaXS1{&?~L#EP`dbz z8hc}d*mFXsc094xEE`wG@H&HNIk+8rxyOn&aQ4n2VWw&#>3RG8DSqfx^xt7)8A6y5 z^@Wp5R4Uc=Fo*upEo%`GrdA4GAds@_B}01D{~&NM_iX!ULmPz(M=xoi+aq#{WX>ls z4lSdy-~pl8`DtgDeWSzm<@)FTtJ~jxEQYLCMEoh^0w$HDRbtsB<5t3#m%-QPYnOxW z*OwJky%$hqvhh>7&&$hP^Tu<6yZVnHD&3d+ay31l>k9^-yB9(|u7+FatfVb89JDam zAu{(-LstPqgmnJY@N~&Ln`B zokpL&hSO~_?pI6%%|M`DYm*_$se-0?Th$Zoq8Ynv$9Q|fb~mS}gRZ1>s9`_Wnq@I% zPAhIreLBu(;^5zVj*pC5gKUbF?x)jkft(B^Ay1wkwm6*ZizJl?ys0OMMHsnuhhg~l zZV;w!H(@i5oo3V>B@o zcedrw(Us&n&klv!?bj$5;w!DKH$39fYDM7A) ztpBvpSy@Ztp1pQ8EHx+DAf~PO?=|Jvb^3e7_!pJv=X6kM@)rF?J3D!#r8G4CF*X#- zQb`D3&3eg*l$MoX{>}Q)*BmU5YewWo09PHFBw8UlwWm53rAHL$fQ~W zn_{uqo|Wxon$7tt{}}R3EN2#V@0gM&sAFt+LvQ+X3|-YENJ!5&I_IMtu*;M2S-+|O}g<_zafn5)Pw zCRt+F0`J>iOZX55X0kerSGH0z3`OMH2&SLu74i2JMd5J2%~r3kE^Ye!$jHNtcDQOB zeM)zPIyb$|cY450$shwkld|L6>Ch%eXGAJKY0PoG$h(z*Mp8Y$_KCcEvb4HH*9hX@ zIF$k(F0y2JgwUzw`{?6+O{o>3-4@(RSNFEC#z3aIZmd0@1k%&6R2NkzHBOfN-Rnn0>tWh4#)lUzuFL2;5*P96t%GDNrbM-LtYl}M zDy>cCQAV>C2mTQ4?5J+T5bcre#BSSZv1`jZv2efss&)^qNOf{S>;yo(L#+w1!TZC^KY z`0=6!BWtGdAgWGpaT0aA*-BVe^1V4w#IAEuH$5L){hL2$Iyh+c6mB`4iT``K*`KybbZcHMDHwOY>mm96ta}W>JLhf--mvPOh^oi~+WtzZIp$w9 zSp`M|t&CskfxA?HCP&##YR4EgvHs*Iq(vFun}kagslm;#oI=LsJq=o0{H9&|BC8ts z$(yp)kuI`Wj~#ntDjagI^CVAwWySl{?6D)Y;Fvd^g3N9lA?f_%W*V)eM8w2lu!&jT zT_E((bByIg1D^TGV+Tc?#ok>i-1Xt5MlX}D8RLpE&onO)waC}!*xF=EDqX)|u)?Lr zUnLJQba%_Oj0poVjVe2Ne2J=KkbHRgM|Q1ogcI&zhnp`0%l6Df3=^HTAL@2>ee{(I%`PF`@AX9}Ei&V70h_4@leBsAm-sy~tAU=uhgiIE5D{9f$+D;ksp z5e8Hr&Qev3Ket_F7?`t5X&`YcXcLbrF#l@?^oy%O>vruKY?6zOc4gQ!X%C_*t)6h6 zWv>Msrn=LZDLMrnEiFYl#ovh~)kWNGyf~0&6S-L*lZdFiWtW)`JUphoc|ozOj5Ae_ z>c^dKXKM1;y@NaanpXda4&ZUO12|o&M)V^h%Ll1f9AtK(PWS$7eX&7KuDbH$hdPb! ztq)LR(|QdEaC6qkf?oy__~2Y#xH-iTYWJ5ZG@GQ8sa_GnU=0cu@mQl{?2ZPhsg;pG z(k+`|I3vzqyKnt?+~E*}RsHa7r6Nkt!mPazHue$xYye9;G&x+en(Mk$V^u{)T3!2t zZkTq`VT|Zo;^KF43b!nMy%A+0C>78*{swFL`R`!NK|D#l1*Sw=ZAK-K)I3YqzGL=5OM;@kD94KZ{zD=GAO+LHs0OkmXye#YfWYF?k_#*W&R$e)Wei)J?F|L3= zy24H4XHQ`exwIYYcRpbmCGE@=xDx6cVr#UIv+!wtmP^d9uej#gi$AUup3p`>a(6X}W{t^sR)l}MMwk8^ zJm}5`^|Kw*Tb3!;a<6>W?pMoLXt&Zl+P3XR?sS9*2<|l;!(JY23R*+isFujBFcUz| zSD}m@CLQz-A+O5*^4#9STR^8!;T$OBb)WbN{(IGJao$fdsTb{4=%n40ZCau*R@up@ zi^1&?34Y#J1x)>4Q(y(3IMV^?P~e0QTH^YV<~z$5t#?5hcMHy(VOKt}n_rtwN%(DXHFUFu4(is-1-HhTsOwC&GhY!jg%bi z&8mY$FfkfR6-nT0ycyIbVQ2>r1}dg0Ls3B2j2 zV>ny#mUHHMvizYQdpUf7v|SP+(Dt=(dIU+&Bp$2=qJ7q7dFfi>`?(_`W_G@Fb@8X~k#lD6rL0IhsB_R`K&e4n z?Dl%=%Qk92;lg=PQ!l2>`%ze1p+_vqP*@dQe|Nlf*1;(h?zgBx+M@0m!SK71SHdo^ zyV?s-f9fp=@L?0-NPGJCZrgw3&TYjc{R_Zb2*94?Ke)Tt*jqT585=t~FzDGETRJfO z`|)qCO8@pdF#1<`?^kruTc{UdSC9DlAS7WW_Af0e`%nfC%kNi`V{Xx(J?im{dvAD4LIgVD*;puo{^k?Y1(x7BzrNRbd)G-ii zgA_=gKlge6UaF0PFOA{bTapZO`wF`Mi917|Mi=Z-oV`YSar;LM&JVhJGw%kGQm4LYQ^+ywyO{= zMT*4o-zZH=90qY#7ITes)iW$a))^n8Ct){x{Df_65Bx|_d(h4ywPQAMxv9)G-xZb) z`{|sFpB|5oHgBiK(##V5M4B#@kUl_EE<{+%#dZ&z!{Zp?00kJv=7egG#+^>(P%SVm z@Xv&lj(ViYOXM=J2jE&wny0Cd3z#M%?co#{IL_PtExJ9y79C?$-p?roJxRu(suT3JHq03(`0uu^gyK>sh+N0JGVKkg2 z)ufB0#3%^NTr~5rr`^vJM3Iw7m5#$C5SYHG-PNMC`^h2qHH^iXP+%(l4Z$CD*d~Y& zX^#>w_uJ=WEV$Zo&ZW4KWOw8d8tMU)O3ei~rA(X|);NBc3uww|96FSQ z`-z^AK(~i8cjVT$YZhmgUosE7;g~-)$>;sBoZ*+p&cXeA^X8Ky!WHHKad7le(%G$k z`ikT;!r{B!NwP*W+&Rl+yo&l9dXA4Ui!cpg?Hb2W=MJ;|sd84wZ5(4$JPla#Dh@fK zqxy;}UPI@dm1r6I+}t$_0Z|aQD`Diwb;JT)eQ>{)c={x_`!mHGn5@NKi(AKE~=gFPu)pur*0d-Rx?Dn-ZOb-h+jWE zx~_AJf!sKHcyaL62yyehO;)Lftv1)i3p~2V`snR*f8tDu@)^fR>~;8jb9$n(tEkFx zh`N6sjXe(u2>mX8PvVZ_%$~rj`wcg@H9{y93^=kcNM5%u*U`Sz^K^Z9SH&(qU2zqjkFYa8%lEBLvc z{{=WfnC)|a0!}7ef8Aj4>3D7KevS6IUjc;g?Ve}$v%9-+?e882QO|rHE+>3mvTeHV zw+FMko*wR_eV$LU^}0~HpB`$ya^J39nF(pUvJZc^)UF*mF`Xgr7zqC?Yn(9Jnv?u zD(V6|e%2{oxJz*-uQF`16LyJe2-Q_2bYxANXguRt^Ld8U1sZ8kx$zc`)je>odfpKj z!-M__q#Iv5wA`PoC6JMhNP)mqR!MUcTStA9m#^*YWj3o2tuXey#2VrD>D%mtFYG@^ zNi7oM7L=B0%d`9N2S)H8Uh&-z@gJt~HJ?yU>|sq#H%#Jxh778YF6Mu1Y6K1a5C|0 z8GC8ndsLsB1!CDqIJ6ZN**6Isv4(-}B^=)Y=_VM@1LYWi%VX9cq|HGjBLK|YG<9Q0UnyLlOU53U^7yrBay@gZLuk7zmk9t&;1_cY z1wY_&}JEX)E!^tW=b#)&MEf{{@sT6DE`zWY0UBmE>oIH_{`cwRp0eV2|!Rj z)s#psXY=C_{BL|e9^X@-t@H&e(Tje%F>A=V4t4G1v)FPpA70+u>-lx~t^$RLZh^u( z1VG`Uf54m^|6JaGvJ61%Vz=~nxacHz6zc+z6u6~{!J2$V+JSfEhvfA0Cy9am;DWj{ zncD8~J3F9}xvtZSf_5DuVfll>Y2RvO61QP`1w?1Aq^@5_jwAp^t|Wn9#w00V0HRxh zp?9T=k_)_T_l={Ni$EK6Gmj@0A!!6`%zOcRnfU^0nfU_XvGjZ#f-32NwHGMUN^n9( zzAafmv9xtJHPx%fU1+aMv%Ym= zaTS20WE22h{u}^Z2B1E4TeJYdq{OWNiiFe3%JMn7ucr-MX8ajz?s$uKF8u$SiF}po zVAa?YfoG8=t2DW5?A~Dl9Y&*mZ#kwVBd1mWN8_vY)9=q>qod{eWbt#B+J77TL>032 zwYPRknB&w+mT}8o0Yo#mfKJ5K2QZSW4=_sF^_vlm&gsc*6xvp?Iy{U_TZB4qzHfgT zLaDGnY!`U6mB`L7T(I=e5UHFQvgBH!&nI-c;4&=Mc;^nxF97nz16JO=0mxVB40MtC zZotaaoRY4np!sCx$lI9JYVBNIj~Y98BUsheBHf%yb^#-eELJ{QR4zrZNnBH4CY5Cn zy4aWKsB>FKsBG;fNG=({djW5-aM1ky25(ZlF7x>rSn+f z1;TaQL|(JSc*%tb6*m3Bg;(uOZ2IWe$I)h}M;q}8lw-8{^E(d1`f7ms|Hw3#4fugf zfXWRI0BXx;Z>a5{?OSD>P{=9TY+KUZ*Cve;SPmJM810nqSdGqTHcU{*vNwza>Kt4G zhOfMY+XzJIxI&T0e^obDUjH!(UPg7Sm+JGJ{AQ>nR zfOgEjIlPm%{&xQFqLfFZ6n^ZJ`#6m)kacoQY4v)ES4n|gWVy1=iR)Ut2#s`z}{OpuI%=P|0ig~ww8=|DDrrD1_R9T&j8J?ESx zaIo+hrUmLO!2Fkue*k*Bf>GQfGztfS4Z(Tla5U~(#S`OgH|lw5kS52l6~S|+&|sz- zX4z%i8M&zmehOxu@SKpNziz1P5@PIq(T7x5gxKq<4;ps}8lWtTn2N6VAat7;q?`93 zBdbYK?ratb%xQl|lVg@hn)aE5&7o5MVq%4a~ctuOWT`J^G-xjLY&i@ISvI+G1W)69-s_~ z8hJ65@s7 z4hX$Zg8&UWy{Wy&lMkRqce*VV)t8T5}2T5d>wK1f$AL_->`AqFnDV$;jB51 z%c!ifIq*)=Z#| zYkT%S0LbYi0Ntg(C*bzpVVnJ-&zMY`{5_}$6z0^9%_s|zC& z5@%oQ6^P&jY5$lkqyW3`IAP4^`@mQB%P}Xj0bASBOUC9ZR2fr zRtr^#ZLCKvN4X`s%uQ|L-PtYZ{SJ!k9_(LFC6-a_%>MV-zT-=y)Z;~pWa*W`lBV_6 z$|z$m`cHq*zWA9iGkFUZM|6>qfZNd`MBA38GB=MiE}Anxj!r1t$gJs<1&+Pnw=B!| z9kZ(;OCPIH<75#|nM&8G#?Fz-OD#c&!I-}9|K-fQ&(+Nl4xMh#>gZi>Gpyk`z|d_t z#cC|#!d7hkj%zSC(Q&v%+ieKK3Ms!D^rFdBr;Y=XAj@y9k8t?AXTM3iO+gaEm-B!k5 zQ$~qSl;WF_Wsy5j^cRRpnG4U}l&M?}eFMhs(@UC5tz3GEDRMN&+&&tbfywu4t3fp?Lyt(~$HdxEzOjp?O~RYIM}^T#xzOz_tMhZjZuMP3!p zj`<0mDT6}IKwK`8``1kVDmgE-ZWp6rA*b@ArW`k=eUeDYy=Q!b5dYxYv0D( z*R1x)V-`#9N?6{bc`UKcRwdAiz|yg#O_d%x_S1ehbzL(o?h=@>o$=}z|C>`5TSv+^ z>Tghpo3h$A(2F~V6Tna4=^R3 zo^u%9ne+u`ZU`gXZAKXL@A`o-InR6#*qnANa2LkalL~*fjjInIsFpA%F}0nlGqqvu zM;KGLaU4?DHo|BpJ1$Kd+hAE8bs0C*F2*7BnI7x(yq1( z>}6GNmK$}1i#oSCM`5gEh%&;VhOv&Y*gND%!Xe7utV1MhO*ZrF)n7cVuz5WND)V$k zr@oZ(`4%Y-YuFXuEJV}lC6lG&a^AQ!vc<_+Or~Fprs&0SS5ZoD1giZ0DMeIU7P`pe*S`QRZD+ zlXB?k1x6lsW)M;mMVhyrGHd@%O(4QA19?-IiOT&CGer9ZA(k~N4h+SNWj-G!zs&h? zb0#;#U2%L>=Kvq|v3uQBp>Eu6VKR3sTQFWCF4AmWNr^!=KUbi7wTRADLux8}Dd}(d zmZ9q1ZmsaGo>Gur(#7~3PFm9ytg7%Yr1N<$grxsvzqDq6`pkGFW6;%!^!;0*NPS$= zZVYsUuEkdE8Hk- zrdPYmCvCJ9OG<*0{P8zpfeK&ZuSFywPu43VPZP|rq^0xLiUZ3K_x=Lve^;#Pv3}Vaa$;$6eBC0;(m6GZ(>)|+T4WFN>BIvt) zsgl?*k#)Z|D*osuepVK(hN65V^`qzR23qp%t|Y&=bOGG@wG^}1i7 z+P^>S_=9f5hfr&XwjhMUG-r&$G!eVs70lFE+l(}HUKLrN0Nh07w4ox2Pq|G>hG;hl^TlmvW$?C*jP;c1aivLmDFuCX&K}Z{j;X z`mf6oEPOUQ!79W$%yOv?pOWE28c%ILV^}im8XMV2??`E7T+dDby$BQ;E;Fz}2kbXF4W8-(=RX(aDW-)KP_04(M zZM};rRcYUw&&i4JQIdY!y?kW9=S5bodaITmXfBy)`_-;fbf%MX;Gp)qTCMbmE8?Yy zRn>76z2O~bl1U(t^xgcZR;EwUg zz5PSHU^>d@ryW|buwHu5bSSR(HxU^$)9EqpkaJ7D2c7g%cgJ)ios6Hv?E6$dF7ZF! zRiz%4>g(yc7=f(xUM%flB&=%<*r0e?PpTc6o|G=TIx^r(?t2f>obOy_R$wmM4yaOo zz;qsNhu)=*uNL785$BKAq>a+M3~LNK;5roRsj#xjq#$qB}$B#Sot5Cg7<1?#^Qg(KVP24QAN9lCjgk5DV+mB*cs!}sI zGT<+Wl1-PX!qqjbI*Ct7O?soT&ml$8b$u0KR&AJ)mJmUOlJ6o29ci@UmvLxt98V*ZN}!Ym4-TNhOvrQ*NylRUdX1_c`wJ? zKerLnTV9}jRO;Qmr#hWcZj47}RBMdTgsBUc34f5mb|PDNV6q0~1Ad+A@Ajyq=dr;_ z22Afo`lp-)wa#~s8V5RmWTEI2N?SZKU*_a;IoxD5Ueh&W&$$w=(Y{qrko22usef;D z6v|!j&8+jzb=PSZUh+>0|Fw`?kuAh{=_#>iBFlKGy_GQac!IC;sQ1)&u6-vseto>B zaey9JJ@X5TX@fSgP3KN<>LMd&wU1ge3oQX?>%Nlf@VBW8OI1Dg+gI6cFrhTkv-MU8 zSIy*mN3%efrNX`sqWzb|^X!IHr#hyg*Jwz>mRliX)2Ijr$;Lb~@X9k-L^cA!tn}TS z@BJ|y6(u@pHUFMRhgRdzVa! zX+--S>K@X+^>>0}8f&6eT)9y)f^51H{TE|tkDvb%-!~gCktof9Lj#U4&JH01`tV3o z5B{C}MOQX%u)U1nvb1Nk1M2 z&GhS69Tv;)@UBP+*oe-7k@5;Nui|jp785iM>Ha7R%V~1Q1xQScw|~nr$}BpmOWT45 z&zdhMCVZM|j#;B>-mr}O(3 zZ=mzD!@+i&{4QriyYAlPAp6+Fgu`ckv=m{&@^;T38*_T(~rki13a?1basKqAr1B*4BwF-7)hR_~UZvZASr zga6*1gydFtyNrE~S(1AjP7rFLGbcsJ0(A8^4KI z=`vj?{8fl6b%q1?V4*s1?qM$UyKJg=@s9spMARnKuvc*zlUv_b6kB+dd0*{)(MmD) zYk+!PyQ{xlVL@PL>d4`UquRBdqBo?l!L+tE>Z5IB4x0zj#r5^{Aa-x6+ztY_{8ElI zp+*c%c6k&pmuWukRUplBJL5>%6}9xsdsVJIo%@v3aX1cpD7j#oV=zWu|0O7O&x8rP zyjpkbr(joF);WdvBQ#}eNrV=h2!|W){Wn^d{=eQ>L$&8Q6&Ko zIMXpnD)ZIda^jLqBt}0`;(?sByg!nWbdL?+*P*?qylfSsGx}cFW~h?jGz?~)U&9_j zdv`CJFnUyHxFMkfJH>Q=s7wi>^i8{Djw0Hp z__$VM>pkEGy2tity^J3sa8mogxKE)3vg^4AP48xGJsHu>TRA&<4|rQXHJ}_n6-21k z#!V6Q0lC+#+dytZ06q2^terR09OeoAS(X&p0`5Kqn2dsA8`hHYbKYO5RBocS=ba~` z!{tOyeo*e|83#Woxa*^|7}%2dA>7GZk)KOV&? za7b^%a#`#;de@zDWiolkMCVC!@|Wh)qj2$S%+xze9X&r2g^x+F8(TI z_tPG5qLbR_hibK?!bKe2>RFAcuN}In(G_2SwD?C&?S1Vr47mZP0lxY*MCVK;!hQ<7 z%-RVNzPfB>YSBYGFGW*c{jCQhjk?7azQu(`=@VVmsy+ALzej+`yY_Eg3hK=#I$4Fn z>5!b{#L|L^!NW)C2^aJ{Z}reGJ?MFy9UuC4DMdUgfk?IVLt_wdM-2G8!CWvszO0(y zXw%8ItD+I%Y3DQ4YT?sp%lq?o>^*Gf(|D-5)&;(XtEf$~Kmo3zK-bQ$c(md+ro)cB z6}p-X2FDv8E+M^T-O*La&Fg@J!14D(?#B-Wqg|EmZ)a*Xq{Ny|g&MkmSwr-Al}>iT zlmpUR#^bkzkSEf-V#JQl#cZ^x8JNT$Yd2d#2kkxA*e){Ta$mxi{yY>!+-Q>JOE8Vg z6)7sG#!WQ~6T5%T`QVk0k!QvnbfC4k^f|gaBT{4sxVcmiAvDK@OO>C`W=dj=&R%46 zmAGSRMC}#%b~5L6Tx|G&=hvdy{z=fmOG52CY@I?THX;Xjkq!66BLt?0A~rUn{CY$~ zC?;4UF4Ow1DcS6dNIMK?wog-%vY-Q&zNI1MI+BD4+4mWd-wM$_0~c|e-nA?keaAXi zT2UWMlRwU!8JQ4!GPfjwz0@PUSC<*hiL0JWoPWt>N}_bAJqw)Ap_y7~#U}7HP7F1Cy!`J70Sb<-oLcQkcOzJextC$SZFCh9rAMaRoq>$R0y!71& z&p70i!zVeFZBekvrX{|$I76%PcS->Cdcaa2nLyQ#Eb5bpWLtbptSkED3$@Gbziiq+9$;92abl8Lf5Y)XY*h zGliL|=jA967Hl)-c?eTu5~Wt`O$q4fZJ*@fMC4ebFxgk5@zRj+K2>j4c)?tDAl+nL z4&`bTi9VmxVWFnIs?cGhVMOE&+6?0CtU6g5)}efl+K6%!s>5GjWZ`7{1ak?!zxbY+ z%)#FrRYmD*v%pEeEy5mF06}Sik@wvHY46Pcp=$d$K9YTllBL_=Df>3b5{7Ig##Y%G z5*pheYxbuR%59Gjk$s6ajAScomdIGf+K^O?M@)>d#C>uW3Opd!N=9V2>ZWT4;L>t@T2; zF(64PT{hh-75T=dA_XQJP!HYHKIJ0o4=&8Acvbr?0g+P-#W~Y z+?HZJPuJX(iVk6aKl6MES(7YgT$qHUaa;)g9J-^BC~a_qRc=Z~<@2feF|;f!c&kVu zk;fo0V57-4ZxaqrV8dq_3B;w3!7Vnq1lFA1|t8t zXR?@36M+q_VsE;(`?-TMi*acA$tW5P6LxG!aBKO$N61b9Xz z*~7)^LS}a-X4W+<;?*}o1tj|PGT2LF2#7-1XdmW^Q+bbIr@paBn~gG&V29@ox;QtX z=Kan%&0~o>raa^V=(=%R4$)~RJGtTg*86Km-?$>fU zDYT&}=~O0x-G{Af8NXwa9b37foh&qNf!L8tc=uz=$rP`-kiXUE3!li3z~S;MF6KO# zn)|*owOw>cb2X`+NjU+VSyhwz!Tkvbc&&GL*UInuYC-6U`i{{hc@KS0bs}zKd->y} zpAH%`H<;6vnjl;&w3ZcJ|AJ3EC!47U+HA{Ty;*hsyD(#jbf3G`&lo;9Ok~aKJ#COE zgL(~J4ER?Rc6}}P-qzHUShV^_Ct;30t|6QA!{Y4!=4oZ_-crL?!$QJvSf@p{huyo| z#oWSObIBoY=GOPV)_1b1`jjqkPRV?~qeEIC+Ql|Rg>LJ#s-VO`A&6okc(bkw>IqjjIJOE&AJ z{4``5b*B?iMd|#xNGzF&@kP##yVH&;&lG50P4vB1@OUHU#uADBjGw+wnUGgadS7he z^o=%>*yNFZ#w2V!+zP!?7Z8jdsS(Ydg&mA$%2`35!7;H0IGWX|~txC*9rJc5C7u zhT>2%E4qu=G5K#;$GL3!cEauX=D?#wQQd@tzbq)`b)MkD67Z^4PTVMb45(Q%1p7wU_l95OD)%CFzgy^p2Mb zCR%oVn#gDp*Z_Q$%b-APo$A6{1{Wi(SLOy>5R667A1s91q`+!XeN9Kn{Hi;s9N}cO z-BsGjVEo%cRI)D1ab}Fr8@6ICrH^qh;$Gc1K!!^}WPhbhys_X~u7cKHPySTmW}L4F z;WktDl0Q>8SJJkpSXKE4sdZ>}>0c0pL(Y%^b3B~DAkxH!?)>5*r*%%1$GT`T3K|@Z z$dy-hc-3@*zsI%DBcB!$V)R1ho};T;e%MT9n-K$7l?iH#yDJcuir~EdR^qZ)BNzSY zQBx&Z*_VMd>U(a#V6GqtgrBAJi%1T(-)TMTTLy|(nuQ^X^9(brJxZHxRIy zDMYB`&Ocqd#xFP_-SvIlZ5A-;s^g-_olGJfLe3N=`}!Q2+Y$ghtz$*$obp&zi;=a6bg2jm3073Rsc6W z$06Y={eJH4cYff8x3>qivm#h+izR?=(*RBR4~gdh`#lhv`}@QP5mY@RRdd3P!QeL$wztnX7O|AasZpv+W~0Xo0-0px@wrIa#GM3zP!q4`}Oew5)NN&;mt zhD_L|-6tHVFsd;bN+4y literal 0 HcmV?d00001 From bee75a450827ad571bc59241386b425a153981d1 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sun, 23 Jun 2024 14:14:26 +0200 Subject: [PATCH 011/463] Hide 2D blending styles on non-2D set-up --- wled00/data/index.htm | 16 ++++++++-------- wled00/data/index.js | 2 ++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/wled00/data/index.htm b/wled00/data/index.htm index e91bc10b..d7ef3707 100644 --- a/wled00/data/index.htm +++ b/wled00/data/index.htm @@ -275,14 +275,14 @@ - - - - - - - - + + + + + + + +

diff --git a/wled00/data/index.js b/wled00/data/index.js index 4cb70796..1f8a9161 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -677,8 +677,10 @@ function parseInfo(i) { isM = mw>0 && mh>0; if (!isM) { gId("filter2D").classList.add('hide'); + gId('bs').querySelectorAll('option[data-type="2D"]').forEach((o,i)=>{o.style.display='none';}); } else { gId("filter2D").classList.remove('hide'); + gId('bs').querySelectorAll('option[data-type="2D"]').forEach((o,i)=>{o.style.display='';}); } // if (i.noaudio) { // gId("filterVol").classList.add("hide"); From 0275bd1d45660ae1630792c835e65fd5a34c40ca Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Fri, 5 Jul 2024 21:23:59 +0200 Subject: [PATCH 012/463] On/Off blending respected --- wled00/FX_fcn.cpp | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 3ebf0c44..af9b3218 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -433,9 +433,17 @@ uint8_t IRAM_ATTR Segment::currentBri(bool useCct) { uint8_t IRAM_ATTR Segment::currentMode() { #ifndef WLED_DISABLE_MODE_BLEND unsigned prog = progress(); - if (prog < 0xFFFFU) return _t->_modeT; -#endif + if (prog == 0xFFFFU) return mode; + if (blendingStyle > BLEND_STYLE_FADE) { + // workaround for on/off transition to respect blending style + uint8_t modeT = (bri != briT) && bri ? FX_MODE_STATIC : _t->_modeT; // On/Off transition active (bri!=briT) and final bri>0 : old mode is STATIC + uint8_t modeS = (bri != briT) && !bri ? FX_MODE_STATIC : mode; // On/Off transition active (bri!=briT) and final bri==0 : new mode is STATIC + return _modeBlend ? modeT : modeS; + } + return _modeBlend ? _t->_modeT : mode; +#else return mode; +#endif } uint32_t IRAM_ATTR Segment::currentColor(uint8_t slot) { @@ -443,7 +451,12 @@ uint32_t IRAM_ATTR Segment::currentColor(uint8_t slot) { uint32_t prog = progress(); if (prog == 0xFFFFU) return colors[slot]; #ifndef WLED_DISABLE_MODE_BLEND - if (blendingStyle > BLEND_STYLE_FADE) return _modeBlend ? _t->_segT._colorT[slot] : colors[slot]; // not fade/blend transition, each effect uses its color + if (blendingStyle > BLEND_STYLE_FADE) { + // workaround for on/off transition to respect blending style + uint32_t colT = (bri != briT) && bri ? BLACK : _t->_segT._colorT[slot]; // On/Off transition active (bri!=briT) and final bri>0 : old color is BLACK + uint32_t colS = (bri != briT) && !bri ? BLACK : colors[slot]; // On/Off transition active (bri!=briT) and final bri==0 : new color is BLACK + return _modeBlend ? colT : colS; + } return color_blend(_t->_segT._colorT[slot], colors[slot], prog, true); #else return color_blend(_t->_colorT[slot], colors[slot], prog, true); @@ -559,6 +572,7 @@ bool Segment::setColor(uint8_t slot, uint32_t c) { //returns true if changed if (slot == 0 && c == BLACK) return false; // on/off segment cannot have primary color black if (slot == 1 && c != BLACK) return false; // on/off segment cannot have secondary color non black } + //DEBUG_PRINTF_P(PSTR("- Starting color transition: %d [0x%X]\n"), slot, c); startTransition(strip.getTransition()); // start transition prior to change colors[slot] = c; stateChanged = true; // send UDP/WS broadcast @@ -572,6 +586,7 @@ void Segment::setCCT(uint16_t k) { k = (k - 1900) >> 5; } if (cct == k) return; + //DEBUG_PRINTF_P(PSTR("- Starting CCT transition: %d\n"), k); startTransition(strip.getTransition()); // start transition prior to change cct = k; stateChanged = true; // send UDP/WS broadcast @@ -579,6 +594,7 @@ void Segment::setCCT(uint16_t k) { void Segment::setOpacity(uint8_t o) { if (opacity == o) return; + //DEBUG_PRINTF_P(PSTR("- Starting opacity transition: %d\n"), o); startTransition(strip.getTransition()); // start transition prior to change opacity = o; stateChanged = true; // send UDP/WS broadcast @@ -599,6 +615,7 @@ void Segment::setMode(uint8_t fx, bool loadDefaults) { // if we have a valid mode & is not reserved if (fx != mode) { #ifndef WLED_DISABLE_MODE_BLEND + //DEBUG_PRINTF_P(PSTR("- Starting effect transition: %d\n"), fx); startTransition(strip.getTransition()); // set effect transitions #endif mode = fx; @@ -630,6 +647,7 @@ void Segment::setPalette(uint8_t pal) { if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0; // built in palettes if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0; // custom palettes if (pal != palette) { + //DEBUG_PRINTF_P(PSTR("- Starting palette transition: %d\n"), pal); startTransition(strip.getTransition()); palette = pal; stateChanged = true; // send UDP/WS broadcast @@ -1373,7 +1391,6 @@ void WS2812FX::service() { // overwritten by later effect. To enable seamless blending for every effect, additional LED buffer // would need to be allocated for each effect and then blended together for each pixel. #ifndef WLED_DISABLE_MODE_BLEND - uint8_t tmpMode = seg.currentMode(); // this will return old mode while in transition Segment::setClippingRect(0, 0); // disable clipping (just in case) if (seg.isInTransition()) { // set clipping rectangle @@ -1425,14 +1442,20 @@ void WS2812FX::service() { break; } } - delay = (*_mode[seg.mode])(); // run new/current mode + delay = (*_mode[seg.currentMode()])(); // run new/current mode if (seg.isInTransition()) { Segment::tmpsegd_t _tmpSegData; Segment::modeBlend(true); // set semaphore seg.swapSegenv(_tmpSegData); // temporarily store new mode state (and swap it with transitional state) _virtualSegmentLength = seg.virtualLength(); // update SEGLEN (mapping may have changed) - seg.setCurrentPalette(); // load actual palette - unsigned d2 = (*_mode[tmpMode])(); // run old mode + _colors_t[0] = gamma32(seg.currentColor(0)); + _colors_t[1] = gamma32(seg.currentColor(1)); + _colors_t[2] = gamma32(seg.currentColor(2)); + if (seg.currentPalette() != pal) { + seg.setCurrentPalette(); // load actual palette + pal = seg.currentPalette(); + } + unsigned d2 = (*_mode[seg.currentMode()])(); // run old mode seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state) delay = MIN(delay,d2); // use shortest delay Segment::modeBlend(false); // unset semaphore From c03422ee3703dd604c909a58997442c0f2c532e4 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Tue, 30 Jul 2024 17:26:50 +0200 Subject: [PATCH 013/463] Push variants --- wled00/FX.h | 26 ++++++++++-------- wled00/FX_2Dfcn.cpp | 61 ++++++++++++++++++++++++++++++++++++++----- wled00/FX_fcn.cpp | 30 ++++++++++++++++++--- wled00/data/index.htm | 28 +++++++++++--------- 4 files changed, 112 insertions(+), 33 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 136f8e18..3dc69e98 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -325,18 +325,22 @@ #define BLEND_STYLE_FAIRY_DUST 1 #define BLEND_STYLE_SWIPE_RIGHT 2 #define BLEND_STYLE_SWIPE_LEFT 3 -#define BLEND_STYLE_PINCH_OUT 4 -#define BLEND_STYLE_INSIDE_OUT 5 -#define BLEND_STYLE_SWIPE_UP 6 -#define BLEND_STYLE_SWIPE_DOWN 7 -#define BLEND_STYLE_OPEN_H 8 -#define BLEND_STYLE_OPEN_V 9 -#define BLEND_STYLE_PUSH_TL 10 -#define BLEND_STYLE_PUSH_TR 11 -#define BLEND_STYLE_PUSH_BR 12 -#define BLEND_STYLE_PUSH_BL 13 +#define BLEND_STYLE_PUSH_RIGHT 4 +#define BLEND_STYLE_PUSH_LEFT 5 +#define BLEND_STYLE_PINCH_OUT 6 +#define BLEND_STYLE_INSIDE_OUT 7 +#define BLEND_STYLE_SWIPE_UP 8 +#define BLEND_STYLE_SWIPE_DOWN 9 +#define BLEND_STYLE_OPEN_H 10 +#define BLEND_STYLE_OPEN_V 11 +#define BLEND_STYLE_PUSH_UP 12 +#define BLEND_STYLE_PUSH_DOWN 13 +#define BLEND_STYLE_PUSH_TL 14 +#define BLEND_STYLE_PUSH_TR 15 +#define BLEND_STYLE_PUSH_BR 16 +#define BLEND_STYLE_PUSH_BL 17 -#define BLEND_STYLE_COUNT 14 +#define BLEND_STYLE_COUNT 18 typedef enum mapping1D2D { diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index a62aa330..846c7867 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -202,15 +202,39 @@ bool IRAM_ATTR Segment::isPixelXYClipped(int x, int y) { void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col) { if (!isActive()) return; // not active - if (x >= virtualWidth() || y >= virtualHeight() || x < 0 || y < 0 || isPixelXYClipped(x,y)) return; // if pixel would fall out of virtual segment just exit + + int vW = virtualWidth(); + int vH = virtualHeight(); + +#ifndef WLED_DISABLE_MODE_BLEND + if (!_modeBlend && + (blendingStyle == BLEND_STYLE_PUSH_RIGHT || + blendingStyle == BLEND_STYLE_PUSH_LEFT || + blendingStyle == BLEND_STYLE_PUSH_UP || + blendingStyle == BLEND_STYLE_PUSH_DOWN || + blendingStyle == BLEND_STYLE_PUSH_TL || + blendingStyle == BLEND_STYLE_PUSH_TR || + blendingStyle == BLEND_STYLE_PUSH_BR || + blendingStyle == BLEND_STYLE_PUSH_BL)) { + unsigned prog = 0xFFFF - progress(); + unsigned dX = (blendingStyle == BLEND_STYLE_PUSH_UP || blendingStyle == BLEND_STYLE_PUSH_DOWN) ? 0 : prog * vW / 0xFFFF; + unsigned dY = (blendingStyle == BLEND_STYLE_PUSH_LEFT || blendingStyle == BLEND_STYLE_PUSH_RIGHT) ? 0 : prog * vH / 0xFFFF; + if (blendingStyle == BLEND_STYLE_PUSH_LEFT || blendingStyle == BLEND_STYLE_PUSH_TL || blendingStyle == BLEND_STYLE_PUSH_BL) x -= dX; + else x += dX; + if (blendingStyle == BLEND_STYLE_PUSH_DOWN || blendingStyle == BLEND_STYLE_PUSH_TL || blendingStyle == BLEND_STYLE_PUSH_TR) y -= dY; + else y += dY; + } +#endif + + if (x >= vW || y >= vH || x < 0 || y < 0 || isPixelXYClipped(x,y)) return; // if pixel would fall out of virtual segment just exit uint8_t _bri_t = currentBri(); if (_bri_t < 255) { col = color_fade(col, _bri_t); } - if (reverse ) x = virtualWidth() - x - 1; - if (reverse_y) y = virtualHeight() - y - 1; + if (reverse ) x = vW - x - 1; + if (reverse_y) y = vH - y - 1; if (transpose) { unsigned t = x; x = y; y = t; } // swap X & Y if segment transposed x *= groupLength(); // expand to physical pixels @@ -294,9 +318,34 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa) // returns RGBW values of pixel uint32_t IRAM_ATTR Segment::getPixelColorXY(int x, int y) { if (!isActive()) return 0; // not active - if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0 || isPixelXYClipped(x,y)) return 0; // if pixel would fall out of virtual segment just exit - if (reverse ) x = virtualWidth() - x - 1; - if (reverse_y) y = virtualHeight() - y - 1; + + int vW = virtualWidth(); + int vH = virtualHeight(); + +#ifndef WLED_DISABLE_MODE_BLEND + if (!_modeBlend && + (blendingStyle == BLEND_STYLE_PUSH_RIGHT || + blendingStyle == BLEND_STYLE_PUSH_LEFT || + blendingStyle == BLEND_STYLE_PUSH_UP || + blendingStyle == BLEND_STYLE_PUSH_DOWN || + blendingStyle == BLEND_STYLE_PUSH_TL || + blendingStyle == BLEND_STYLE_PUSH_TR || + blendingStyle == BLEND_STYLE_PUSH_BR || + blendingStyle == BLEND_STYLE_PUSH_BL)) { + unsigned prog = 0xFFFF - progress(); + unsigned dX = (blendingStyle == BLEND_STYLE_PUSH_UP || blendingStyle == BLEND_STYLE_PUSH_DOWN) ? 0 : prog * vW / 0xFFFF; + unsigned dY = (blendingStyle == BLEND_STYLE_PUSH_LEFT || blendingStyle == BLEND_STYLE_PUSH_RIGHT) ? 0 : prog * vH / 0xFFFF; + if (blendingStyle == BLEND_STYLE_PUSH_LEFT || blendingStyle == BLEND_STYLE_PUSH_TL || blendingStyle == BLEND_STYLE_PUSH_BL) x -= dX; + else x += dX; + if (blendingStyle == BLEND_STYLE_PUSH_DOWN || blendingStyle == BLEND_STYLE_PUSH_TL || blendingStyle == BLEND_STYLE_PUSH_TR) y -= dY; + else y += dY; + } +#endif + + if (x >= vW || y >= vH || x<0 || y<0 || isPixelXYClipped(x,y)) return 0; // if pixel would fall out of virtual segment just exit + + if (reverse ) x = vW - x - 1; + if (reverse_y) y = vH - y - 1; if (transpose) { unsigned t = x; x = y; y = t; } // swap X & Y if segment transposed x *= groupLength(); // expand to physical pixels y *= groupLength(); // expand to physical pixels diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 4af96176..583496de 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -782,7 +782,8 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col) #endif i &= 0xFFFF; - if (i >= virtualLength() || i<0) return; // if pixel would fall out of segment just exit + int vL = virtualLength(); + if (i >= vL || i < 0) return; // if pixel would fall out of segment just exit #ifndef WLED_DISABLE_2D if (is2D()) { @@ -890,7 +891,16 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col) } #endif - if (isPixelClipped(i)) return; // handle clipping on 1D +#ifndef WLED_DISABLE_MODE_BLEND + if (!_modeBlend && (blendingStyle == BLEND_STYLE_PUSH_RIGHT || blendingStyle == BLEND_STYLE_PUSH_LEFT)) { + unsigned prog = 0xFFFF - progress(); + unsigned dI = prog * vL / 0xFFFF; + if (blendingStyle == BLEND_STYLE_PUSH_RIGHT) i -= dI; + else i += dI; + } +#endif + + if (i >= vL || i < 0 || isPixelClipped(i)) return; // handle clipping on 1D unsigned len = length(); uint8_t _bri_t = currentBri(); @@ -978,6 +988,9 @@ uint32_t IRAM_ATTR Segment::getPixelColor(int i) #endif i &= 0xFFFF; + int vL = virtualLength(); + if (i >= vL || i < 0) return 0; + #ifndef WLED_DISABLE_2D if (is2D()) { unsigned vH = virtualHeight(); // segment height in logical pixels @@ -1029,9 +1042,18 @@ uint32_t IRAM_ATTR Segment::getPixelColor(int i) } #endif - if (isPixelClipped(i)) return 0; // handle clipping on 1D +#ifndef WLED_DISABLE_MODE_BLEND + if (!_modeBlend && (blendingStyle == BLEND_STYLE_PUSH_RIGHT || blendingStyle == BLEND_STYLE_PUSH_LEFT)) { + unsigned prog = 0xFFFF - progress(); + unsigned dI = prog * vL / 0xFFFF; + if (blendingStyle == BLEND_STYLE_PUSH_RIGHT) i -= dI; + else i += dI; + } +#endif - if (reverse) i = virtualLength() - i - 1; + if (i >= vL || i < 0 || isPixelClipped(i)) return 0; // handle clipping on 1D + + if (reverse) i = vL - i - 1; i *= groupLength(); i += start; /* offset/phase */ diff --git a/wled00/data/index.htm b/wled00/data/index.htm index d7ef3707..df867d3a 100644 --- a/wled00/data/index.htm +++ b/wled00/data/index.htm @@ -271,18 +271,22 @@

From 365c1987ed8f5f8070081c2619d1b784ff354a7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Thu, 1 Aug 2024 10:24:40 +0200 Subject: [PATCH 014/463] Missing clipping fix - small speed optimisations --- wled00/FX.h | 6 +++--- wled00/FX_2Dfcn.cpp | 22 ++++++++++++---------- wled00/FX_fcn.cpp | 35 ++++++++++++++++++++--------------- 3 files changed, 35 insertions(+), 28 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 3dc69e98..3abc8116 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -351,7 +351,7 @@ typedef enum mapping1D2D { M12_sPinwheel = 4 } mapping1D2D_t; -// segment, 80 bytes +// segment, 68 bytes typedef struct Segment { public: uint16_t start; // start index / start X coordinate 2D (left) @@ -639,7 +639,7 @@ typedef struct Segment { uint16_t virtualHeight(void) const; // segment height in virtual pixels (accounts for groupping and spacing) uint16_t nrOfVStrips(void) const; // returns number of virtual vertical strips in 2D matrix (used to expand 1D effects into 2D) #ifndef WLED_DISABLE_2D - uint16_t XY(uint16_t x, uint16_t y); // support function to get relative index within segment + uint16_t XY(int x, int y); // support function to get relative index within segment void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColorXY(int(x), int(y), c); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } @@ -678,7 +678,7 @@ typedef struct Segment { inline void blur2d(fract8 blur_amount) { blur(blur_amount); } inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); } #else - inline uint16_t XY(uint16_t x, uint16_t y) { return x; } + inline uint16_t XY(int x, int y) { return x; } inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(x, c); } inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColor(int(x), c); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColor(x, RGBW32(r,g,b,w)); } diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 846c7867..493cb896 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -161,8 +161,7 @@ void WS2812FX::setUpMatrix() { #ifndef WLED_DISABLE_2D // XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element) -uint16_t IRAM_ATTR Segment::XY(uint16_t x, uint16_t y) -{ +uint16_t IRAM_ATTR Segment::XY(int x, int y) { unsigned width = virtualWidth(); // segment width in logical pixels (can be 0 if segment is inactive) unsigned height = virtualHeight(); // segment height in logical pixels (is always >= 1) return isActive() ? (x%width) + (y%height) * width : 0; @@ -207,7 +206,7 @@ void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col) int vH = virtualHeight(); #ifndef WLED_DISABLE_MODE_BLEND - if (!_modeBlend && + if (isInTransition() && !_modeBlend && (blendingStyle == BLEND_STYLE_PUSH_RIGHT || blendingStyle == BLEND_STYLE_PUSH_LEFT || blendingStyle == BLEND_STYLE_PUSH_UP || @@ -239,13 +238,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 + + int W = width(); + int H = height(); + if (x >= W || y >= H) return; // if pixel would fall out of segment just exit uint32_t tmpCol = col; for (int j = 0; j < grouping; j++) { // groupping vertically for (int 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 @@ -255,15 +257,15 @@ void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col) strip.setPixelColorXY(start + xX, startY + yY, tmpCol); if (mirror) { //set the corresponding horizontally mirrored pixel - if (transpose) strip.setPixelColorXY(start + xX, startY + height() - yY - 1, tmpCol); - else strip.setPixelColorXY(start + width() - xX - 1, startY + yY, tmpCol); + if (transpose) strip.setPixelColorXY(start + xX, startY + H - yY - 1, tmpCol); + else strip.setPixelColorXY(start + W - xX - 1, startY + yY, tmpCol); } if (mirror_y) { //set the corresponding vertically mirrored pixel - if (transpose) strip.setPixelColorXY(start + width() - xX - 1, startY + yY, tmpCol); - else strip.setPixelColorXY(start + xX, startY + height() - yY - 1, tmpCol); + if (transpose) strip.setPixelColorXY(start + W - xX - 1, startY + yY, tmpCol); + else strip.setPixelColorXY(start + xX, startY + H - yY - 1, tmpCol); } if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel - strip.setPixelColorXY(width() - xX - 1, height() - yY - 1, tmpCol); + strip.setPixelColorXY(W - xX - 1, H - yY - 1, tmpCol); } } } diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 583496de..dbbd24b7 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -754,7 +754,7 @@ uint16_t IRAM_ATTR Segment::virtualLength() const { bool IRAM_ATTR Segment::isPixelClipped(int i) { #ifndef WLED_DISABLE_MODE_BLEND if (_clipStart != _clipStop && blendingStyle > BLEND_STYLE_FADE) { - bool invert = _clipStart > _clipStop; // ineverted start & stop + bool invert = _clipStart > _clipStop; // ineverted start & stop int start = invert ? _clipStop : _clipStart; int stop = invert ? _clipStart : _clipStop; if (blendingStyle == BLEND_STYLE_FAIRY_DUST) { @@ -892,7 +892,8 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col) #endif #ifndef WLED_DISABLE_MODE_BLEND - if (!_modeBlend && (blendingStyle == BLEND_STYLE_PUSH_RIGHT || blendingStyle == BLEND_STYLE_PUSH_LEFT)) { + // if we blend using "push" style we need to "shift" new mode to left or right + if (isInTransition() && !_modeBlend && (blendingStyle == BLEND_STYLE_PUSH_RIGHT || blendingStyle == BLEND_STYLE_PUSH_LEFT)) { unsigned prog = 0xFFFF - progress(); unsigned dI = prog * vL / 0xFFFF; if (blendingStyle == BLEND_STYLE_PUSH_RIGHT) i -= dI; @@ -1043,7 +1044,7 @@ uint32_t IRAM_ATTR Segment::getPixelColor(int i) #endif #ifndef WLED_DISABLE_MODE_BLEND - if (!_modeBlend && (blendingStyle == BLEND_STYLE_PUSH_RIGHT || blendingStyle == BLEND_STYLE_PUSH_LEFT)) { + if (isInTransition() && !_modeBlend && (blendingStyle == BLEND_STYLE_PUSH_RIGHT || blendingStyle == BLEND_STYLE_PUSH_LEFT)) { unsigned prog = 0xFFFF - progress(); unsigned dI = prog * vL / 0xFFFF; if (blendingStyle == BLEND_STYLE_PUSH_RIGHT) i -= dI; @@ -1425,43 +1426,47 @@ void WS2812FX::service() { unsigned dw = p * w / 0xFFFFU + 1; unsigned dh = p * h / 0xFFFFU + 1; switch (blendingStyle) { - case BLEND_STYLE_FAIRY_DUST: // fairy dust (must set entire segment, see isPixelXYClipped()) + case BLEND_STYLE_FAIRY_DUST: // fairy dust (must set entire segment, see isPixelXYClipped()) Segment::setClippingRect(0, w, 0, h); break; case BLEND_STYLE_SWIPE_RIGHT: // left-to-right + case BLEND_STYLE_PUSH_RIGHT: // left-to-right Segment::setClippingRect(0, dw, 0, h); break; - case BLEND_STYLE_SWIPE_LEFT: // right-to-left + case BLEND_STYLE_SWIPE_LEFT: // right-to-left + case BLEND_STYLE_PUSH_LEFT: // right-to-left Segment::setClippingRect(w - dw, w, 0, h); break; - case BLEND_STYLE_PINCH_OUT: // corners + case BLEND_STYLE_PINCH_OUT: // corners Segment::setClippingRect((w + dw)/2, (w - dw)/2, (h + dh)/2, (h - dh)/2); // inverted!! break; - case BLEND_STYLE_INSIDE_OUT: // outward + case BLEND_STYLE_INSIDE_OUT: // outward Segment::setClippingRect((w - dw)/2, (w + dw)/2, (h - dh)/2, (h + dh)/2); break; - case BLEND_STYLE_SWIPE_DOWN: // top-to-bottom (2D) + case BLEND_STYLE_SWIPE_DOWN: // top-to-bottom (2D) + case BLEND_STYLE_PUSH_DOWN: // top-to-bottom (2D) Segment::setClippingRect(0, w, 0, dh); break; - case BLEND_STYLE_SWIPE_UP: // bottom-to-top (2D) + case BLEND_STYLE_SWIPE_UP: // bottom-to-top (2D) + case BLEND_STYLE_PUSH_UP: // bottom-to-top (2D) Segment::setClippingRect(0, w, h - dh, h); break; - case BLEND_STYLE_OPEN_H: // horizontal-outward (2D) same look as INSIDE_OUT on 1D + case BLEND_STYLE_OPEN_H: // horizontal-outward (2D) same look as INSIDE_OUT on 1D Segment::setClippingRect((w - dw)/2, (w + dw)/2, 0, h); break; - case BLEND_STYLE_OPEN_V: // vertical-outward (2D) + case BLEND_STYLE_OPEN_V: // vertical-outward (2D) Segment::setClippingRect(0, w, (h - dh)/2, (h + dh)/2); break; - case BLEND_STYLE_PUSH_TL: // TL-to-BR (2D) + case BLEND_STYLE_PUSH_TL: // TL-to-BR (2D) Segment::setClippingRect(0, dw, 0, dh); break; - case BLEND_STYLE_PUSH_TR: // TR-to-BL (2D) + case BLEND_STYLE_PUSH_TR: // TR-to-BL (2D) Segment::setClippingRect(w - dw, w, 0, dh); break; - case BLEND_STYLE_PUSH_BR: // BR-to-TL (2D) + case BLEND_STYLE_PUSH_BR: // BR-to-TL (2D) Segment::setClippingRect(w - dw, w, h - dh, h); break; - case BLEND_STYLE_PUSH_BL: // BL-to-TR (2D) + case BLEND_STYLE_PUSH_BL: // BL-to-TR (2D) Segment::setClippingRect(0, dw, h - dh, h); break; } From 77723b615f5c482a63053c7a40705b073f072681 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Thu, 8 Aug 2024 21:10:27 +0200 Subject: [PATCH 015/463] Fix compiler warning --- wled00/FX_2Dfcn.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 36d2038b..7aec73ca 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -246,7 +246,7 @@ void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col) uint32_t tmpCol = col; for (int j = 0; j < grouping; j++) { // groupping vertically for (int g = 0; g < grouping; g++) { // groupping horizontally - unsigned xX = (x+g), yY = (y+j); + int xX = (x+g), yY = (y+j); if (xX >= W || yY >= H) continue; // we have reached one dimension's end #ifndef WLED_DISABLE_MODE_BLEND From ebd8a10cefdfa83f289961de8d3d6ef5fa6e6da6 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Tue, 3 Sep 2024 17:20:16 +0200 Subject: [PATCH 016/463] Prevent styles on 1px segments --- wled00/FX_fcn.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index a5e007e8..f825cecd 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1428,6 +1428,8 @@ void WS2812FX::service() { unsigned h = seg.virtualHeight(); unsigned dw = p * w / 0xFFFFU + 1; unsigned dh = p * h / 0xFFFFU + 1; + unsigned orgBS = blendingStyle; + if (w*h == 1) blendingStyle = BLEND_STYLE_FADE; // disable belending for single pixel segments (use fade instead) switch (blendingStyle) { case BLEND_STYLE_FAIRY_DUST: // fairy dust (must set entire segment, see isPixelXYClipped()) Segment::setClippingRect(0, w, 0, h); @@ -1473,9 +1475,8 @@ void WS2812FX::service() { Segment::setClippingRect(0, dw, h - dh, h); break; } - } - delay = (*_mode[seg.currentMode()])(); // run new/current mode - if (seg.isInTransition()) { + delay = (*_mode[seg.currentMode()])(); // run new/current mode + // now run old/previous mode Segment::tmpsegd_t _tmpSegData; Segment::modeBlend(true); // set semaphore seg.swapSegenv(_tmpSegData); // temporarily store new mode state (and swap it with transitional state) @@ -1491,10 +1492,10 @@ void WS2812FX::service() { seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state) delay = MIN(delay,d2); // use shortest delay Segment::modeBlend(false); // unset semaphore - } -#else - delay = (*_mode[seg.mode])(); // run effect mode + blendingStyle = orgBS; // restore blending style if it was modified for single pixel segment + } else #endif + delay = (*_mode[seg.mode])(); // run effect mode (not in transition) seg.call++; if (seg.isInTransition() && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition BusManager::setSegmentCCT(oldCCT); // restore old CCT for ABL adjustments From c3f472fbcb0d766f8c6cce1bf8841770b4b15bac Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Wed, 11 Sep 2024 21:41:42 +0200 Subject: [PATCH 017/463] some improvements to consider no real difference in FPS but code is faster. also 160bytes smaller, meaning it is actually faster --- wled00/FX_2Dfcn.cpp | 25 +++++++++--------- wled00/colors.cpp | 62 +++++++++++++++++++++++++++++++++++++------- wled00/fcn_declare.h | 2 ++ 3 files changed, 67 insertions(+), 22 deletions(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 26ec1d60..ae76379e 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -173,11 +173,6 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) if (!isActive()) return; // not active if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit - uint8_t _bri_t = currentBri(); - if (_bri_t < 255) { - col = color_fade(col, _bri_t); - } - if (reverse ) x = virtualWidth() - x - 1; if (reverse_y) y = virtualHeight() - y - 1; if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed @@ -189,7 +184,11 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) int H = height(); if (x >= W || y >= H) return; // if pixel would fall out of segment just exit - uint32_t tmpCol = col; + uint8_t _bri_t = currentBri(); + if (_bri_t < 255) { + col = color_fade(col, _bri_t); + } + for (int j = 0; j < grouping; j++) { // groupping vertically for (int g = 0; g < grouping; g++) { // groupping horizontally int xX = (x+g), yY = (y+j); @@ -197,21 +196,21 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) #ifndef WLED_DISABLE_MODE_BLEND // if blending modes, blend with underlying pixel - if (_modeBlend) tmpCol = color_blend(strip.getPixelColorXY(start + xX, startY + yY), col, 0xFFFFU - progress(), true); + if (_modeBlend) col = color_blend(strip.getPixelColorXY(start + xX, startY + yY), col, 0xFFFFU - progress(), true); #endif - strip.setPixelColorXY(start + xX, startY + yY, tmpCol); + strip.setPixelColorXY(start + xX, startY + yY, col); if (mirror) { //set the corresponding horizontally mirrored pixel - if (transpose) strip.setPixelColorXY(start + xX, startY + height() - yY - 1, tmpCol); - else strip.setPixelColorXY(start + width() - xX - 1, startY + yY, tmpCol); + if (transpose) strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col); + else strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col); } if (mirror_y) { //set the corresponding vertically mirrored pixel - if (transpose) strip.setPixelColorXY(start + width() - xX - 1, startY + yY, tmpCol); - else strip.setPixelColorXY(start + xX, startY + height() - yY - 1, tmpCol); + if (transpose) strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col); + else strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col); } if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel - strip.setPixelColorXY(start + width() - xX - 1, startY + height() - yY - 1, tmpCol); + strip.setPixelColorXY(start + width() - xX - 1, startY + height() - yY - 1, col); } } } diff --git a/wled00/colors.cpp b/wled00/colors.cpp index ac1dee00..791aad98 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -72,25 +72,69 @@ uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) { if (c1 == BLACK || amount + video == 0) return BLACK; uint32_t scaledcolor; // color order is: W R G B from MSB to LSB - uint32_t r = R(c1); - uint32_t g = G(c1); - uint32_t b = B(c1); - uint32_t w = W(c1); uint32_t scale = amount; // 32bit for faster calculation if (video) { + uint32_t r = R(c1); + uint32_t g = G(c1); + uint32_t b = B(c1); + uint32_t w = W(c1); scaledcolor = (((r * scale) >> 8) + ((r && scale) ? 1 : 0)) << 16; scaledcolor |= (((g * scale) >> 8) + ((g && scale) ? 1 : 0)) << 8; scaledcolor |= ((b * scale) >> 8) + ((b && scale) ? 1 : 0); scaledcolor |= (((w * scale) >> 8) + ((w && scale) ? 1 : 0)) << 24; - } else { - scaledcolor = ((r * scale) >> 8) << 16; - scaledcolor |= ((g * scale) >> 8) << 8; - scaledcolor |= (b * scale) >> 8; - scaledcolor |= ((w * scale) >> 8) << 24; + } else { // according to compile explorer, this is 15% faster but cannot be used for video (its not faster if the assignments are seperated) + uint32_t r = (((c1&0x00FF0000) * scale) >> 8) & 0x00FF0000; + uint32_t g = (((c1&0x0000FF00) * scale) >> 8) & 0x0000FF00; + uint32_t b = ((c1&0x000000FF) * scale) >> 8; + uint32_t w = (((c1 & 0xFF000000) >> 8) * scale) & 0xFF000000; // Scale w and keep it in position + scaledcolor = r | g | b | w; } return scaledcolor; } +// 1:1 replacement of fastled function optimized for ESP, slightly faster, more accurate and uses less flash (~ -200bytes) +CRGB ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brightness, TBlendType blendType) +{ + if ( blendType == LINEARBLEND_NOWRAP) { + //index = map8(index, 0, 239); + index = (index*240) >> 8; // Blend range is affected by lo4 blend of values, remap to avoid wrapping + } + unsigned hi4 = byte(index) >> 4; + unsigned lo4 = index & 0x0F; + unsigned hi4XsizeofCRGB = hi4 * sizeof(CRGB); + // We then add that to a base array pointer. + const CRGB* entry = (CRGB*)( (uint8_t*)(&(pal[0])) + hi4XsizeofCRGB); + unsigned red1 = entry->red; + unsigned green1 = entry->green; + unsigned blue1 = entry->blue; + if(blendType != NOBLEND) { + if(hi4 == 15) entry = &(pal[0]); + else ++entry; + unsigned red2 = entry->red; + unsigned green2 = entry->green; + unsigned blue2 = entry->blue; + unsigned f2 = (lo4 << 4)+1; // +1 so we scale by 256 as a max value, then result can just be shifted by 8 + unsigned f1 = (257 - f2); // f2 is 1 minimum, so this is 256 max + red1 *= f1; + green1 *= f1; + blue1 *= f1; + red2 *= f2; + green2 *= f2; + blue2 *= f2; + red1 = (red1 + red2) >> 8; + green1 = (green1 + green2) >> 8; + blue1 = (blue1 + blue2) >> 8; + } + if( brightness != 255) { // note: zero checking could be done to return black but that is hardly ever used so it is omitted + uint32_t scale = brightness; + scale++; // adjust for rounding (bitshift) + red1 = (red1 * scale) >> 8; + green1 = (green1 * scale) >> 8; + blue1 = (blue1 * scale) >> 8; + } + return CRGB((uint8_t)red1, (uint8_t)green1, (uint8_t)blue1); +} + void setRandomColor(byte* rgb) { lastRandomIndex = get_random_wheel_index(lastRandomIndex); diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index f8399b1a..2f9bc44d 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -66,6 +66,7 @@ typedef struct WiFiConfig { } wifi_config; //colors.cpp +#define ColorFromPalette ColorFromPaletteWLED // override fastled version // similar to NeoPixelBus NeoGammaTableMethod but allows dynamic changes (superseded by NPB::NeoGammaDynamicTableMethod) class NeoGammaWLEDMethod { public: @@ -81,6 +82,7 @@ class NeoGammaWLEDMethod { [[gnu::hot]] uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false); [[gnu::hot]] uint32_t color_add(uint32_t,uint32_t, bool fast=false); [[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); +CRGB ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND); CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette); CRGBPalette16 generateRandomPalette(); inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); } From 934176818f32ffa0ffe359192dbf7d769c3e740f Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 12 Sep 2024 06:43:20 +0200 Subject: [PATCH 018/463] more improvements to color_scale() now even faster. tested and working, also tested video --- wled00/colors.cpp | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 791aad98..c3ac0cb6 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -70,25 +70,22 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool fast) uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) { - if (c1 == BLACK || amount + video == 0) return BLACK; + if (c1 == BLACK || amount == 0) return BLACK; + else if (amount == 255) return c1; + video = true; uint32_t scaledcolor; // color order is: W R G B from MSB to LSB uint32_t scale = amount; // 32bit for faster calculation - if (video) { - uint32_t r = R(c1); - uint32_t g = G(c1); - uint32_t b = B(c1); - uint32_t w = W(c1); - scaledcolor = (((r * scale) >> 8) + ((r && scale) ? 1 : 0)) << 16; - scaledcolor |= (((g * scale) >> 8) + ((g && scale) ? 1 : 0)) << 8; - scaledcolor |= ((b * scale) >> 8) + ((b && scale) ? 1 : 0); - scaledcolor |= (((w * scale) >> 8) + ((w && scale) ? 1 : 0)) << 24; - } else { // according to compile explorer, this is 15% faster but cannot be used for video (its not faster if the assignments are seperated) - uint32_t r = (((c1&0x00FF0000) * scale) >> 8) & 0x00FF0000; - uint32_t g = (((c1&0x0000FF00) * scale) >> 8) & 0x0000FF00; - uint32_t b = ((c1&0x000000FF) * scale) >> 8; - uint32_t w = (((c1 & 0xFF000000) >> 8) * scale) & 0xFF000000; // Scale w and keep it in position - scaledcolor = r | g | b | w; + uint32_t addRemains = 0; + if (!video) amount++; // add one for correct scaling using bitshifts + else { // video scaling: make sure colors do not dim to zero if they started non-zero + addRemains = R(c1) ? 0x00010000 : 0; + addRemains |= G(c1) ? 0x00000100 : 0; + addRemains |= B(c1) ? 0x00000001 : 0; + addRemains |= W(c1) ? 0x01000000 : 0; } + uint32_t rb = (((c1 & 0x00FF00FF) * scale) >> 8) & 0x00FF00FF; // scale red and blue + uint32_t wg = (((c1 & 0xFF00FF00) >> 8) * scale) & 0xFF00FF00; // scale white and green + scaledcolor = (rb | wg) + addRemains; return scaledcolor; } From feac45fd0aed860235aef4e03fe91c5b49f95a89 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 12 Sep 2024 07:45:49 +0200 Subject: [PATCH 019/463] improvement in color_add its not faster but cleaner (and uses less flash) --- wled00/colors.cpp | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index c3ac0cb6..960cef31 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -39,21 +39,17 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool fast) { if (c1 == BLACK) return c2; if (c2 == BLACK) return c1; - if (fast) { - uint8_t r = R(c1); - uint8_t g = G(c1); - uint8_t b = B(c1); - uint8_t w = W(c1); - r = qadd8(r, R(c2)); - g = qadd8(g, G(c2)); - b = qadd8(b, B(c2)); - w = qadd8(w, W(c2)); + uint32_t r = R(c1) + R(c2); + uint32_t g = G(c1) + G(c2); + uint32_t b = B(c1) + B(c2); + uint32_t w = W(c1) + W(c2); + if (fast) { + r = r > 255 ? 255 : r; + g = g > 255 ? 255 : g; + b = b > 255 ? 255 : b; + w = w > 255 ? 255 : w; return RGBW32(r,g,b,w); } else { - uint32_t r = R(c1) + R(c2); - uint32_t g = G(c1) + G(c2); - uint32_t b = B(c1) + B(c2); - uint32_t w = W(c1) + W(c2); unsigned max = r; if (g > max) max = g; if (b > max) max = b; @@ -72,7 +68,6 @@ uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) { if (c1 == BLACK || amount == 0) return BLACK; else if (amount == 255) return c1; - video = true; uint32_t scaledcolor; // color order is: W R G B from MSB to LSB uint32_t scale = amount; // 32bit for faster calculation uint32_t addRemains = 0; From 992d11be105ac00380874a11f6ba33e9acfc24e1 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 12 Sep 2024 08:28:30 +0200 Subject: [PATCH 020/463] Improvements in get/set PixelColor() -calculations for virtual strips are done on each call, which is unnecessary. moved them into the if statement. --- wled00/FX_fcn.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index d3521c90..4364b9f4 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -705,11 +705,16 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) { if (!isActive()) return; // not active #ifndef WLED_DISABLE_2D - int vStrip = i>>16; // hack to allow running on virtual strips (2D segment columns/rows) + int vStrip; #endif - i &= 0xFFFF; - - if (i >= virtualLength() || i<0) return; // if pixel would fall out of segment just exit + if (i >= virtualLength() || i<0) // pixel would fall out of segment, check if this is a virtual strip NOTE: this is almost always false if not virtual strip, saves the calculation on 'standard' call + { + #ifndef WLED_DISABLE_2D + vStrip = i>>16; // hack to allow running on virtual strips (2D segment columns/rows) + #endif + i &= 0xFFFF; //truncate vstrip index + if (i >= virtualLength() || i<0) return; // if pixel would still fall out of segment just exit + } #ifndef WLED_DISABLE_2D if (is2D()) { @@ -900,8 +905,7 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const if (!isActive()) return 0; // not active #ifndef WLED_DISABLE_2D int vStrip = i>>16; -#endif - i &= 0xFFFF; +#endif #ifndef WLED_DISABLE_2D if (is2D()) { @@ -912,7 +916,7 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const return getPixelColorXY(i % vW, i / vW); break; case M12_pBar: - if (vStrip>0) return getPixelColorXY(vStrip - 1, vH - i -1); + if (vStrip>0) { i &= 0xFFFF; return getPixelColorXY(vStrip - 1, vH - i -1); } else return getPixelColorXY(0, vH - i -1); break; case M12_pArc: From b07658b46060c73c4bd94a9a4e4289d44639c173 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 12 Sep 2024 14:09:09 +0200 Subject: [PATCH 021/463] improved Segment::setPixelColorXY a tiny bit uses less flash so it should be faster (did not notice any FPS difference though) also cleaned code in ColorFromPaletteWLED (it is not faster, same amount of code) --- wled00/FX_2Dfcn.cpp | 30 ++++++++++++++---------------- wled00/colors.cpp | 33 +++++++++++---------------------- 2 files changed, 25 insertions(+), 38 deletions(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index ae76379e..01410b81 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -173,34 +173,30 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) if (!isActive()) return; // not active if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit - if (reverse ) x = virtualWidth() - x - 1; - if (reverse_y) y = virtualHeight() - y - 1; - if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed - - x *= groupLength(); // expand to physical pixels - y *= groupLength(); // expand to physical pixels - - int W = width(); - int H = height(); - if (x >= W || y >= H) return; // if pixel would fall out of segment just exit - uint8_t _bri_t = currentBri(); if (_bri_t < 255) { col = color_fade(col, _bri_t); } + if (reverse ) x = virtualWidth() - x - 1; + if (reverse_y) y = virtualHeight() - y - 1; + if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed + x *= groupLength(); // expand to physical pixels + y *= groupLength(); // expand to physical pixels + int W = width(); + int H = height(); + + int yY = y; for (int j = 0; j < grouping; j++) { // groupping vertically + if(yY >= H) continue; + int xX = x; for (int g = 0; g < grouping; g++) { // groupping horizontally - int xX = (x+g), yY = (y+j); - if (xX >= W || yY >= H) continue; // we have reached one dimension's end - + if (xX >= W) continue; // we have reached one dimension's end #ifndef WLED_DISABLE_MODE_BLEND // if blending modes, blend with underlying pixel if (_modeBlend) col = color_blend(strip.getPixelColorXY(start + xX, startY + yY), col, 0xFFFFU - progress(), true); #endif - strip.setPixelColorXY(start + xX, startY + yY, col); - if (mirror) { //set the corresponding horizontally mirrored pixel if (transpose) strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col); else strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col); @@ -212,7 +208,9 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel strip.setPixelColorXY(start + width() - xX - 1, startY + height() - yY - 1, col); } + xX++; } + yY++; } } diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 960cef31..b6cb3ac5 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -92,34 +92,23 @@ CRGB ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brig index = (index*240) >> 8; // Blend range is affected by lo4 blend of values, remap to avoid wrapping } unsigned hi4 = byte(index) >> 4; - unsigned lo4 = index & 0x0F; - unsigned hi4XsizeofCRGB = hi4 * sizeof(CRGB); // We then add that to a base array pointer. - const CRGB* entry = (CRGB*)( (uint8_t*)(&(pal[0])) + hi4XsizeofCRGB); - unsigned red1 = entry->red; - unsigned green1 = entry->green; - unsigned blue1 = entry->blue; + const CRGB* entry = (CRGB*)( (uint8_t*)(&(pal[0])) + (hi4 * sizeof(CRGB))); + unsigned red1 = entry->r; + unsigned green1 = entry->g; + unsigned blue1 = entry->b; if(blendType != NOBLEND) { if(hi4 == 15) entry = &(pal[0]); else ++entry; - unsigned red2 = entry->red; - unsigned green2 = entry->green; - unsigned blue2 = entry->blue; - unsigned f2 = (lo4 << 4)+1; // +1 so we scale by 256 as a max value, then result can just be shifted by 8 + // unsigned red2 = entry->red; + unsigned f2 = ((index & 0x0F) << 4) + 1; // +1 so we scale by 256 as a max value, then result can just be shifted by 8 unsigned f1 = (257 - f2); // f2 is 1 minimum, so this is 256 max - red1 *= f1; - green1 *= f1; - blue1 *= f1; - red2 *= f2; - green2 *= f2; - blue2 *= f2; - red1 = (red1 + red2) >> 8; - green1 = (green1 + green2) >> 8; - blue1 = (blue1 + blue2) >> 8; + red1 = (red1 * f1 + (unsigned)entry->r * f2) >> 8; + green1 = (green1 * f1 + (unsigned)entry->g * f2) >> 8; + blue1 = (green1 * f1 + (unsigned)entry->b * f2) >> 8; } - if( brightness != 255) { // note: zero checking could be done to return black but that is hardly ever used so it is omitted - uint32_t scale = brightness; - scale++; // adjust for rounding (bitshift) + if( brightness < 255) { // note: zero checking could be done to return black but that is hardly ever used so it is omitted + uint32_t scale = brightness + 1; // adjust for rounding (bitshift) red1 = (red1 * scale) >> 8; green1 = (green1 * scale) >> 8; blue1 = (blue1 * scale) >> 8; From 09428dcade03aa4544f85f81f2d8a160d144db9c Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 12 Sep 2024 16:34:55 +0200 Subject: [PATCH 022/463] inlined getMappedPixelIndex, improved color_add, bugfix in colorFromPalette inlining getMappedPixelIndex gets rid of function entry instructions (hopefully) so it should be faster. also added the 'multi color math' trick to color_add function (it will not make much difference but code shrinks by a few bytes) --- wled00/FX_fcn.cpp | 2 +- wled00/colors.cpp | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 4364b9f4..cddf1ece 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1820,7 +1820,7 @@ bool WS2812FX::deserializeMap(uint8_t n) { return (customMappingSize > 0); } -uint16_t IRAM_ATTR WS2812FX::getMappedPixelIndex(uint16_t index) const { +__attribute__ ((always_inline)) inline uint16_t IRAM_ATTR WS2812FX::getMappedPixelIndex(uint16_t index) const { // convert logical address to physical if (index < customMappingSize && (realtimeMode == REALTIME_MODE_INACTIVE || realtimeRespectLedMaps)) index = customMappingTable[index]; diff --git a/wled00/colors.cpp b/wled00/colors.cpp index b6cb3ac5..1f106965 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -39,10 +39,17 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool fast) { if (c1 == BLACK) return c2; if (c2 == BLACK) return c1; - uint32_t r = R(c1) + R(c2); + /*uint32_t r = R(c1) + R(c2); uint32_t g = G(c1) + G(c2); uint32_t b = B(c1) + B(c2); - uint32_t w = W(c1) + W(c2); + uint32_t w = W(c1) + W(c2);*/ + uint32_t rb = (c1 & 0x00FF00FF) + (c2 & 0x00FF00FF); + uint32_t r = rb >> 16; + uint32_t b = rb & 0xFFFF; + uint32_t wg = ((c1>>8) & 0x00FF00FF) + ((c2>>8) & 0x00FF00FF); + uint32_t w = wg >> 16; + uint32_t g = wg & 0xFFFF; + if (fast) { r = r > 255 ? 255 : r; g = g > 255 ? 255 : g; @@ -105,7 +112,7 @@ CRGB ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brig unsigned f1 = (257 - f2); // f2 is 1 minimum, so this is 256 max red1 = (red1 * f1 + (unsigned)entry->r * f2) >> 8; green1 = (green1 * f1 + (unsigned)entry->g * f2) >> 8; - blue1 = (green1 * f1 + (unsigned)entry->b * f2) >> 8; + blue1 = (blue1 * f1 + (unsigned)entry->b * f2) >> 8; } if( brightness < 255) { // note: zero checking could be done to return black but that is hardly ever used so it is omitted uint32_t scale = brightness + 1; // adjust for rounding (bitshift) From ec938f254cf3fdecf0757a2dee4d9364973d4941 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 12 Sep 2024 21:25:08 +0200 Subject: [PATCH 023/463] removed old code --- wled00/colors.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 1f106965..ce1d2f2f 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -39,10 +39,6 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool fast) { if (c1 == BLACK) return c2; if (c2 == BLACK) return c1; - /*uint32_t r = R(c1) + R(c2); - uint32_t g = G(c1) + G(c2); - uint32_t b = B(c1) + B(c2); - uint32_t w = W(c1) + W(c2);*/ uint32_t rb = (c1 & 0x00FF00FF) + (c2 & 0x00FF00FF); uint32_t r = rb >> 16; uint32_t b = rb & 0xFFFF; From d45b4ad1340bccfeb9093b1ff460f1919721a277 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Fri, 13 Sep 2024 19:01:54 +0200 Subject: [PATCH 024/463] fixes and consistency --- wled00/colors.cpp | 8 ++++---- wled00/fcn_declare.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index ce1d2f2f..7747216f 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -54,9 +54,9 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool fast) return RGBW32(r,g,b,w); } else { unsigned max = r; - if (g > max) max = g; - if (b > max) max = b; - if (w > max) max = w; + max = g > max ? g : max; + max = b > max ? b : max; + max = w > max ? w : max; if (max < 256) return RGBW32(r, g, b, w); else return RGBW32(r * 255 / max, g * 255 / max, b * 255 / max, w * 255 / max); } @@ -70,7 +70,7 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool fast) uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) { if (c1 == BLACK || amount == 0) return BLACK; - else if (amount == 255) return c1; + if (amount == 255) return c1; uint32_t scaledcolor; // color order is: W R G B from MSB to LSB uint32_t scale = amount; // 32bit for faster calculation uint32_t addRemains = 0; diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 2f9bc44d..0ebcd64d 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -82,7 +82,7 @@ class NeoGammaWLEDMethod { [[gnu::hot]] uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false); [[gnu::hot]] uint32_t color_add(uint32_t,uint32_t, bool fast=false); [[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); -CRGB ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND); +[[gnu::hot]] CRGB ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND); CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette); CRGBPalette16 generateRandomPalette(); inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); } From 2afff0501401c7161eae841107868884635779ae Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 14 Sep 2024 11:45:27 +0200 Subject: [PATCH 025/463] minor tweak (break instead of continue in setPixelColorXY) --- wled00/FX_2Dfcn.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 01410b81..57ee2e5e 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -188,7 +188,7 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) int yY = y; for (int j = 0; j < grouping; j++) { // groupping vertically - if(yY >= H) continue; + if(yY >= H) break; int xX = x; for (int g = 0; g < grouping; g++) { // groupping horizontally if (xX >= W) continue; // we have reached one dimension's end From 6a37f25c5d994b914222999fdce441c3427e1fcd Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 14 Sep 2024 14:10:46 +0200 Subject: [PATCH 026/463] memory improvement: dropped static gamma table - there already is a method to calculate the table on the fly, there is no need to store it in flash, it can just be calculated at bootup (or cfg change) --- wled00/cfg.cpp | 11 +++++------ wled00/colors.cpp | 19 ++----------------- wled00/set.cpp | 5 ++--- 3 files changed, 9 insertions(+), 26 deletions(-) diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index a6c3ab74..978ed6eb 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -440,13 +440,12 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { else gammaCorrectBri = false; if (light_gc_col > 1.0f) gammaCorrectCol = true; else gammaCorrectCol = false; - if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3) { - if (gammaCorrectVal != 2.8f) NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); - } else { - gammaCorrectVal = 1.0f; // no gamma correction - gammaCorrectBri = false; - gammaCorrectCol = false; + if (gammaCorrectVal <= 1.0f || gammaCorrectVal > 3) { + gammaCorrectVal = 1.0f; // no gamma correction + gammaCorrectBri = false; + gammaCorrectCol = false; } + NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table JsonObject light_tr = light["tr"]; CJSON(fadeTransition, light_tr["mode"]); diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 7747216f..4afe4c0d 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -481,23 +481,7 @@ uint16_t approximateKelvinFromRGB(uint32_t rgb) { } //gamma 2.8 lookup table used for color correction -uint8_t NeoGammaWLEDMethod::gammaT[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, - 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, - 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, - 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, - 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25, - 25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36, - 37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50, - 51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68, - 69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89, - 90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114, - 115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142, - 144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175, - 177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213, - 215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 }; +uint8_t NeoGammaWLEDMethod::gammaT[256]; // re-calculates & fills gamma table void NeoGammaWLEDMethod::calcGammaTable(float gamma) @@ -505,6 +489,7 @@ void NeoGammaWLEDMethod::calcGammaTable(float gamma) for (size_t i = 0; i < 256; i++) { gammaT[i] = (int)(powf((float)i / 255.0f, gamma) * 255.0f + 0.5f); } + Serial.println("****GAMMA***"); //!!! } uint8_t IRAM_ATTR NeoGammaWLEDMethod::Correct(uint8_t value) diff --git a/wled00/set.cpp b/wled00/set.cpp index 7814e55d..2fe01a54 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -319,13 +319,12 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) gammaCorrectBri = request->hasArg(F("GB")); gammaCorrectCol = request->hasArg(F("GC")); gammaCorrectVal = request->arg(F("GV")).toFloat(); - if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3) - NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); - else { + if (gammaCorrectVal <= 1.0f || gammaCorrectVal > 3) { gammaCorrectVal = 1.0f; // no gamma correction gammaCorrectBri = false; gammaCorrectCol = false; } + NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table fadeTransition = request->hasArg(F("TF")); modeBlending = request->hasArg(F("EB")); From 0e5bd4ed7428ab7540393935ced7e8ef4e937fc2 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 14 Sep 2024 14:11:29 +0200 Subject: [PATCH 027/463] remove test printout --- wled00/colors.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 4afe4c0d..74723471 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -489,7 +489,6 @@ void NeoGammaWLEDMethod::calcGammaTable(float gamma) for (size_t i = 0; i < 256; i++) { gammaT[i] = (int)(powf((float)i / 255.0f, gamma) * 255.0f + 0.5f); } - Serial.println("****GAMMA***"); //!!! } uint8_t IRAM_ATTR NeoGammaWLEDMethod::Correct(uint8_t value) From f3137eb0a9b8d12759a207b910bc854dc1b36ec3 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 14 Sep 2024 14:49:36 +0200 Subject: [PATCH 028/463] updated Segment::color_from_palette - gamma correction only where needed - paletteIndex should be uint8_t (it is only used as that) note: integrating the new `ColorFromPaletteWLED()` into this would require a whole lot of code rewrite and would result in more color conversions from 32bit to CRGB. It would be really useful only if CRGB is replaced with native 32bit colors. --- wled00/FX_fcn.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index cddf1ece..7e8bd647 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1181,18 +1181,21 @@ uint32_t Segment::color_wheel(uint8_t pos) const { * @returns Single color from palette */ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) const { - uint32_t color = gamma32(currentColor(mcol)); - + + uint32_t color = currentColor(mcol); // default palette or no RGB support on segment - if ((palette == 0 && mcol < NUM_COLORS) || !_isRGB) return (pbri == 255) ? color : color_fade(color, pbri, true); + if ((palette == 0 && mcol < NUM_COLORS) || !_isRGB) { + color = gamma32(color); + return (pbri == 255) ? color : color_fade(color, pbri, true); + } - unsigned paletteIndex = i; + uint8_t paletteIndex = i; if (mapping && virtualLength() > 1) paletteIndex = (i*255)/(virtualLength() -1); // paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined) if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end" CRGB fastled_col = ColorFromPalette(_currentPalette, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global - return RGBW32(fastled_col.r, fastled_col.g, fastled_col.b, W(color)); + return RGBW32(fastled_col.r, fastled_col.g, fastled_col.b, gamma8(W(color))); } From 696290527abfd01fcff3d4bd5fbfdc9c53050787 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Wed, 18 Sep 2024 22:10:27 +0200 Subject: [PATCH 029/463] cleanup and improved color_add() - optimized color_add() again: now it is as fast with preserved ratio scaling than the "fast" variant was before (if no scaling is needed, it is even faster). plus it saves 250 bytes of flash - bugfix in `color_fade()` - removed a lot of whitespaces --- wled00/FX.h | 24 +++++++-------- wled00/FX_2Dfcn.cpp | 26 ++++++++-------- wled00/FX_fcn.cpp | 16 +++++----- wled00/colors.cpp | 70 +++++++++++++++++++++----------------------- wled00/fcn_declare.h | 2 +- 5 files changed, 67 insertions(+), 71 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 3c28274d..bea4dbcb 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -595,9 +595,9 @@ typedef struct Segment { void fadeToBlackBy(uint8_t fadeBy); inline void blendPixelColor(int n, uint32_t color, uint8_t blend) { setPixelColor(n, color_blend(getPixelColor(n), color, blend)); } inline void blendPixelColor(int n, CRGB c, uint8_t blend) { blendPixelColor(n, RGBW32(c.r,c.g,c.b,0), blend); } - inline void addPixelColor(int n, uint32_t color, bool fast = false) { setPixelColor(n, color_add(getPixelColor(n), color, fast)); } - inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColor(n, RGBW32(r,g,b,w), fast); } - inline void addPixelColor(int n, CRGB c, bool fast = false) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), fast); } + inline void addPixelColor(int n, uint32_t color) { setPixelColor(n, color_add(getPixelColor(n), color)); } + inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0) { addPixelColor(n, RGBW32(r,g,b,w)); } + inline void addPixelColor(int n, CRGB c) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } inline void fadePixelColor(uint16_t n, uint8_t fade) { setPixelColor(n, color_fade(getPixelColor(n), fade, true)); } [[gnu::hot]] uint32_t color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255) const; [[gnu::hot]] uint32_t color_wheel(uint8_t pos) const; @@ -605,11 +605,11 @@ typedef struct Segment { // 2D Blur: shortcuts for bluring columns or rows only (50% faster than full 2D blur) inline void blurCols(fract8 blur_amount, bool smear = false) { // blur all columns const unsigned cols = virtualWidth(); - for (unsigned k = 0; k < cols; k++) blurCol(k, blur_amount, smear); + for (unsigned k = 0; k < cols; k++) blurCol(k, blur_amount, smear); } inline void blurRows(fract8 blur_amount, bool smear = false) { // blur all rows const unsigned rows = virtualHeight(); - for ( unsigned i = 0; i < rows; i++) blurRow(i, blur_amount, smear); + for ( unsigned i = 0; i < rows; i++) blurRow(i, blur_amount, smear); } // 2D matrix @@ -632,10 +632,10 @@ typedef struct Segment { // 2D support functions inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) { setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend)); } inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), blend); } - inline void addPixelColorXY(int x, int y, uint32_t color, bool fast = false) { setPixelColorXY(x, y, color_add(getPixelColorXY(x,y), color, fast)); } - inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColorXY(x, y, RGBW32(r,g,b,w), fast); } - inline void addPixelColorXY(int x, int y, CRGB c, bool fast = false) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), fast); } - inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), fade, true)); } + inline void addPixelColorXY(int x, int y, uint32_t color) { setPixelColorXY(x, y, color_add(getPixelColorXY(x,y), color)); } + inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { addPixelColorXY(x, y, RGBW32(r,g,b,w)); } + inline void addPixelColorXY(int x, int y, CRGB c) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } + inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), fade, true)); } void box_blur(unsigned r = 1U, bool smear = false); // 2D box blur void blur2D(uint8_t blur_amount, bool smear = false); void blurRow(uint32_t row, fract8 blur_amount, bool smear = false); @@ -670,9 +670,9 @@ typedef struct Segment { inline uint32_t getPixelColorXY(int x, int y) { return getPixelColor(x); } inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t c, uint8_t blend) { blendPixelColor(x, c, blend); } inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColor(x, RGBW32(c.r,c.g,c.b,0), blend); } - inline void addPixelColorXY(int x, int y, uint32_t color, bool fast = false) { addPixelColor(x, color, fast); } - inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColor(x, RGBW32(r,g,b,w), fast); } - inline void addPixelColorXY(int x, int y, CRGB c, bool fast = false) { addPixelColor(x, RGBW32(c.r,c.g,c.b,0), fast); } + inline void addPixelColorXY(int x, int y, uint32_t color) { addPixelColor(x, color); } + inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { addPixelColor(x, RGBW32(r,g,b,w)); } + inline void addPixelColorXY(int x, int y, CRGB c) { addPixelColor(x, RGBW32(c.r,c.g,c.b,0)); } inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { fadePixelColor(x, fade); } inline void box_blur(unsigned i, bool vertical, fract8 blur_amount) {} inline void blur2D(uint8_t blur_amount, bool smear = false) {} diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 57ee2e5e..10b85a82 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -173,7 +173,7 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) if (!isActive()) return; // not active if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit - uint8_t _bri_t = currentBri(); + uint8_t _bri_t = currentBri(); if (_bri_t < 255) { col = color_fade(col, _bri_t); } @@ -185,11 +185,11 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) y *= groupLength(); // expand to physical pixels int W = width(); int H = height(); - + int yY = y; for (int j = 0; j < grouping; j++) { // groupping vertically if(yY >= H) break; - int xX = x; + int xX = x; for (int g = 0; g < grouping; g++) { // groupping horizontally if (xX >= W) continue; // we have reached one dimension's end #ifndef WLED_DISABLE_MODE_BLEND @@ -293,8 +293,8 @@ void Segment::blurRow(uint32_t row, fract8 blur_amount, bool smear){ curnew = color_fade(cur, keep); if (x > 0) { if (carryover) - curnew = color_add(curnew, carryover, true); - uint32_t prev = color_add(lastnew, part, true); + curnew = color_add(curnew, carryover); + uint32_t prev = color_add(lastnew, part); if (last != prev) // optimization: only set pixel if color has changed setPixelColorXY(x - 1, row, prev); } else // first pixel @@ -326,15 +326,15 @@ void Segment::blurCol(uint32_t col, fract8 blur_amount, bool smear) { curnew = color_fade(cur, keep); if (y > 0) { if (carryover) - curnew = color_add(curnew, carryover, true); - uint32_t prev = color_add(lastnew, part, true); + curnew = color_add(curnew, carryover); + uint32_t prev = color_add(lastnew, part); if (last != prev) // optimization: only set pixel if color has changed setPixelColorXY(col, y - 1, prev); } else // first pixel setPixelColorXY(col, y, curnew); lastnew = curnew; last = cur; //save original value for comparison on next iteration - carryover = part; + carryover = part; } setPixelColorXY(col, rows - 1, curnew); } @@ -356,8 +356,8 @@ void Segment::blur2D(uint8_t blur_amount, bool smear) { uint32_t part = color_fade(cur, seep); curnew = color_fade(cur, keep); if (x > 0) { - if (carryover) curnew = color_add(curnew, carryover, true); - uint32_t prev = color_add(lastnew, part, true); + if (carryover) curnew = color_add(curnew, carryover); + uint32_t prev = color_add(lastnew, part); // optimization: only set pixel if color has changed if (last != prev) setPixelColorXY(x - 1, row, prev); } else setPixelColorXY(x, row, curnew); // first pixel @@ -375,14 +375,14 @@ void Segment::blur2D(uint8_t blur_amount, bool smear) { uint32_t part = color_fade(cur, seep); curnew = color_fade(cur, keep); if (y > 0) { - if (carryover) curnew = color_add(curnew, carryover, true); - uint32_t prev = color_add(lastnew, part, true); + if (carryover) curnew = color_add(curnew, carryover); + uint32_t prev = color_add(lastnew, part); // optimization: only set pixel if color has changed if (last != prev) setPixelColorXY(col, y - 1, prev); } else setPixelColorXY(col, y, curnew); // first pixel lastnew = curnew; last = cur; //save original value for comparison on next iteration - carryover = part; + carryover = part; } setPixelColorXY(col, rows - 1, curnew); } diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 236f7ad4..66aeaab6 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -712,12 +712,12 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) { if (!isActive()) return; // not active #ifndef WLED_DISABLE_2D - int vStrip; + int vStrip; #endif if (i >= virtualLength() || i<0) // pixel would fall out of segment, check if this is a virtual strip NOTE: this is almost always false if not virtual strip, saves the calculation on 'standard' call { #ifndef WLED_DISABLE_2D - vStrip = i>>16; // hack to allow running on virtual strips (2D segment columns/rows) + vStrip = i>>16; // hack to allow running on virtual strips (2D segment columns/rows) #endif i &= 0xFFFF; //truncate vstrip index if (i >= virtualLength() || i<0) return; // if pixel would still fall out of segment just exit @@ -735,7 +735,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) case M12_pBar: // expand 1D effect vertically or have it play on virtual strips if (vStrip>0) setPixelColorXY(vStrip - 1, vH - i - 1, col); - else for (int x = 0; x < vW; x++) setPixelColorXY(x, vH - i - 1, col); + else for (int x = 0; x < vW; x++) setPixelColorXY(x, vH - i - 1, col); break; case M12_pArc: // expand in circular fashion from center @@ -796,7 +796,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) // Odd rays start further from center if prevRay started at center. static int prevRay = INT_MIN; // previous ray number if ((i % 2 == 1) && (i - 1 == prevRay || i + 1 == prevRay)) { - int jump = min(vW/3, vH/3); // can add 2 if using medium pinwheel + int jump = min(vW/3, vH/3); // can add 2 if using medium pinwheel posx += inc_x * jump; posy += inc_y * jump; } @@ -1145,8 +1145,8 @@ void Segment::blur(uint8_t blur_amount, bool smear) { uint32_t part = color_fade(cur, seep); curnew = color_fade(cur, keep); if (i > 0) { - if (carryover) curnew = color_add(curnew, carryover, true); - uint32_t prev = color_add(lastnew, part, true); + if (carryover) curnew = color_add(curnew, carryover); + uint32_t prev = color_add(lastnew, part); // optimization: only set pixel if color has changed if (last != prev) setPixelColor(i - 1, prev); } else // first pixel @@ -1188,7 +1188,7 @@ uint32_t Segment::color_wheel(uint8_t pos) const { * @returns Single color from palette */ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) const { - + uint32_t color = currentColor(mcol); // default palette or no RGB support on segment if ((palette == 0 && mcol < NUM_COLORS) || !_isRGB) { @@ -1196,7 +1196,7 @@ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_ return (pbri == 255) ? color : color_fade(color, pbri, true); } - uint8_t paletteIndex = i; + unsigned paletteIndex = i; if (mapping && virtualLength() > 1) paletteIndex = (i*255)/(virtualLength() -1); // paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined) if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end" diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 104d25e6..54469ebe 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -33,33 +33,32 @@ uint32_t color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) /* * color add function that preserves ratio - * idea: https://github.com/Aircoookie/WLED/pull/2465 by https://github.com/Proto-molecule + * original idea: https://github.com/Aircoookie/WLED/pull/2465 by https://github.com/Proto-molecule + * heavily optimized for speed by @dedehai */ -uint32_t color_add(uint32_t c1, uint32_t c2, bool fast) +uint32_t color_add(uint32_t c1, uint32_t c2) { if (c1 == BLACK) return c2; if (c2 == BLACK) return c1; - uint32_t rb = (c1 & 0x00FF00FF) + (c2 & 0x00FF00FF); - uint32_t r = rb >> 16; - uint32_t b = rb & 0xFFFF; - uint32_t wg = ((c1>>8) & 0x00FF00FF) + ((c2>>8) & 0x00FF00FF); + uint32_t rb = (c1 & 0x00FF00FF) + (c2 & 0x00FF00FF); // mask and add two colors at once + uint32_t wg = ((c1>>8) & 0x00FF00FF) + ((c2>>8) & 0x00FF00FF); + uint32_t r = rb >> 16; // extract single color values + uint32_t b = rb & 0xFFFF; uint32_t w = wg >> 16; - uint32_t g = wg & 0xFFFF; + uint32_t g = wg & 0xFFFF; - if (fast) { - r = r > 255 ? 255 : r; - g = g > 255 ? 255 : g; - b = b > 255 ? 255 : b; - w = w > 255 ? 255 : w; - return RGBW32(r,g,b,w); - } else { - unsigned max = r; - max = g > max ? g : max; - max = b > max ? b : max; - max = w > max ? w : max; - if (max < 256) return RGBW32(r, g, b, w); - else return RGBW32(r * 255 / max, g * 255 / max, b * 255 / max, w * 255 / max); + unsigned max = r; // check for overflow note: not checking and just topping out at 255 (formerly 'fast') is not any faster (but even slower if not overflowing) + max = g > max ? g : max; + max = b > max ? b : max; + max = w > max ? w : max; + + if (max > 255) { + uint32_t scale = (uint32_t(255)<<8) / max; // division of two 8bit (shifted) values does not work -> use bit shifts and multiplaction instead + rb = ((rb * scale) >> 8) & 0x00FF00FF; // + wg = (wg * scale) & 0xFF00FF00; } + else wg = wg << 8; //shift white and green back to correct position + return rb | wg; } /* @@ -70,52 +69,49 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool fast) uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) { if (c1 == BLACK || amount == 0) return BLACK; - if (amount == 255) return c1; + if (amount == 255) return c1; uint32_t scaledcolor; // color order is: W R G B from MSB to LSB uint32_t scale = amount; // 32bit for faster calculation uint32_t addRemains = 0; - if (!video) amount++; // add one for correct scaling using bitshifts + if (!video) scale++; // add one for correct scaling using bitshifts else { // video scaling: make sure colors do not dim to zero if they started non-zero - addRemains = R(c1) ? 0x00010000 : 0; + addRemains = R(c1) ? 0x00010000 : 0; addRemains |= G(c1) ? 0x00000100 : 0; addRemains |= B(c1) ? 0x00000001 : 0; addRemains |= W(c1) ? 0x01000000 : 0; } uint32_t rb = (((c1 & 0x00FF00FF) * scale) >> 8) & 0x00FF00FF; // scale red and blue uint32_t wg = (((c1 & 0xFF00FF00) >> 8) * scale) & 0xFF00FF00; // scale white and green - scaledcolor = (rb | wg) + addRemains; + scaledcolor = (rb | wg) + addRemains; return scaledcolor; } // 1:1 replacement of fastled function optimized for ESP, slightly faster, more accurate and uses less flash (~ -200bytes) CRGB ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brightness, TBlendType blendType) { - if ( blendType == LINEARBLEND_NOWRAP) { - //index = map8(index, 0, 239); + if (blendType == LINEARBLEND_NOWRAP) { index = (index*240) >> 8; // Blend range is affected by lo4 blend of values, remap to avoid wrapping } unsigned hi4 = byte(index) >> 4; - // We then add that to a base array pointer. const CRGB* entry = (CRGB*)( (uint8_t*)(&(pal[0])) + (hi4 * sizeof(CRGB))); unsigned red1 = entry->r; unsigned green1 = entry->g; - unsigned blue1 = entry->b; + unsigned blue1 = entry->b; if(blendType != NOBLEND) { if(hi4 == 15) entry = &(pal[0]); else ++entry; - // unsigned red2 = entry->red; unsigned f2 = ((index & 0x0F) << 4) + 1; // +1 so we scale by 256 as a max value, then result can just be shifted by 8 unsigned f1 = (257 - f2); // f2 is 1 minimum, so this is 256 max - red1 = (red1 * f1 + (unsigned)entry->r * f2) >> 8; - green1 = (green1 * f1 + (unsigned)entry->g * f2) >> 8; - blue1 = (blue1 * f1 + (unsigned)entry->b * f2) >> 8; + red1 = (red1 * f1 + (unsigned)entry->r * f2) >> 8; + green1 = (green1 * f1 + (unsigned)entry->g * f2) >> 8; + blue1 = (blue1 * f1 + (unsigned)entry->b * f2) >> 8; } if( brightness < 255) { // note: zero checking could be done to return black but that is hardly ever used so it is omitted - uint32_t scale = brightness + 1; // adjust for rounding (bitshift) + uint32_t scale = brightness + 1; // adjust for rounding (bitshift) red1 = (red1 * scale) >> 8; green1 = (green1 * scale) >> 8; blue1 = (blue1 * scale) >> 8; - } + } return CRGB((uint8_t)red1, (uint8_t)green1, (uint8_t)blue1); } @@ -176,7 +172,7 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) harmonics[1] = basehue + 205 + random8(10); harmonics[2] = basehue - 5 + random8(10); break; - + case 3: // square harmonics[0] = basehue + 85 + random8(10); harmonics[1] = basehue + 175 + random8(10); @@ -213,9 +209,9 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) //apply saturation & gamma correction CRGB RGBpalettecolors[4]; for (int i = 0; i < 4; i++) { - if (makepastelpalette && palettecolors[i].saturation > 180) { + if (makepastelpalette && palettecolors[i].saturation > 180) { palettecolors[i].saturation -= 160; //desaturate all four colors - } + } RGBpalettecolors[i] = (CRGB)palettecolors[i]; //convert to RGB RGBpalettecolors[i] = gamma32(((uint32_t)RGBpalettecolors[i]) & 0x00FFFFFFU); //strip alpha from CRGB } diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index ac941dc9..be7ed446 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -80,7 +80,7 @@ class NeoGammaWLEDMethod { #define gamma32(c) NeoGammaWLEDMethod::Correct32(c) #define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c) [[gnu::hot]] uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false); -[[gnu::hot]] uint32_t color_add(uint32_t,uint32_t, bool fast=false); +[[gnu::hot]] uint32_t color_add(uint32_t,uint32_t); [[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); [[gnu::hot]] CRGB ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND); CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette); From a88436c620bed17a66bf7f1563888036c3a4d10f Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 19 Sep 2024 08:49:18 +0200 Subject: [PATCH 030/463] revert removal of adding with saturation, renamed 'fast' to 'saturate' - blurring now uses desaturated adding: it is faster most of the times and blurring adds scaled colors so should rarely (ever?) saturate, I saw no visual difference in tests. - formatting --- wled00/FX.h | 18 +++++++++--------- wled00/FX_2Dfcn.cpp | 2 +- wled00/FX_fcn.cpp | 2 +- wled00/colors.cpp | 31 ++++++++++++++++++++----------- wled00/fcn_declare.h | 4 ++-- 5 files changed, 33 insertions(+), 24 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index bea4dbcb..50bcd662 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -595,9 +595,9 @@ typedef struct Segment { void fadeToBlackBy(uint8_t fadeBy); inline void blendPixelColor(int n, uint32_t color, uint8_t blend) { setPixelColor(n, color_blend(getPixelColor(n), color, blend)); } inline void blendPixelColor(int n, CRGB c, uint8_t blend) { blendPixelColor(n, RGBW32(c.r,c.g,c.b,0), blend); } - inline void addPixelColor(int n, uint32_t color) { setPixelColor(n, color_add(getPixelColor(n), color)); } - inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0) { addPixelColor(n, RGBW32(r,g,b,w)); } - inline void addPixelColor(int n, CRGB c) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } + inline void addPixelColor(int n, uint32_t color, bool saturate = false) { setPixelColor(n, color_add(getPixelColor(n), color, saturate)); } + inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool saturate = false) { addPixelColor(n, RGBW32(r,g,b,w), saturate); } + inline void addPixelColor(int n, CRGB c, bool saturate = false) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), saturate); } inline void fadePixelColor(uint16_t n, uint8_t fade) { setPixelColor(n, color_fade(getPixelColor(n), fade, true)); } [[gnu::hot]] uint32_t color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255) const; [[gnu::hot]] uint32_t color_wheel(uint8_t pos) const; @@ -632,9 +632,9 @@ typedef struct Segment { // 2D support functions inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) { setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend)); } inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), blend); } - inline void addPixelColorXY(int x, int y, uint32_t color) { setPixelColorXY(x, y, color_add(getPixelColorXY(x,y), color)); } - inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { addPixelColorXY(x, y, RGBW32(r,g,b,w)); } - inline void addPixelColorXY(int x, int y, CRGB c) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } + inline void addPixelColorXY(int x, int y, uint32_t color, bool saturate = false) { setPixelColorXY(x, y, color_add(getPixelColorXY(x,y), color, saturate)); } + inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool saturate = false) { addPixelColorXY(x, y, RGBW32(r,g,b,w), saturate); } + inline void addPixelColorXY(int x, int y, CRGB c, bool saturate = false) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), saturate); } inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), fade, true)); } void box_blur(unsigned r = 1U, bool smear = false); // 2D box blur void blur2D(uint8_t blur_amount, bool smear = false); @@ -670,9 +670,9 @@ typedef struct Segment { inline uint32_t getPixelColorXY(int x, int y) { return getPixelColor(x); } inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t c, uint8_t blend) { blendPixelColor(x, c, blend); } inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColor(x, RGBW32(c.r,c.g,c.b,0), blend); } - inline void addPixelColorXY(int x, int y, uint32_t color) { addPixelColor(x, color); } - inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { addPixelColor(x, RGBW32(r,g,b,w)); } - inline void addPixelColorXY(int x, int y, CRGB c) { addPixelColor(x, RGBW32(c.r,c.g,c.b,0)); } + inline void addPixelColorXY(int x, int y, uint32_t color, bool saturate = false) { addPixelColor(x, color, saturate); } + inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool saturate = false) { addPixelColor(x, RGBW32(r,g,b,w), saturate); } + inline void addPixelColorXY(int x, int y, CRGB c, bool saturate = false) { addPixelColor(x, RGBW32(c.r,c.g,c.b,0), saturate); } inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { fadePixelColor(x, fade); } inline void box_blur(unsigned i, bool vertical, fract8 blur_amount) {} inline void blur2D(uint8_t blur_amount, bool smear = false) {} diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 10b85a82..63595d93 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -188,7 +188,7 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) int yY = y; for (int j = 0; j < grouping; j++) { // groupping vertically - if(yY >= H) break; + if (yY >= H) break; int xX = x; for (int g = 0; g < grouping; g++) { // groupping horizontally if (xX >= W) continue; // we have reached one dimension's end diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 66aeaab6..7159d21c 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1169,7 +1169,7 @@ uint32_t Segment::color_wheel(uint8_t pos) const { pos = 255 - pos; if (pos < 85) { return RGBW32((255 - pos * 3), 0, (pos * 3), w); - } else if(pos < 170) { + } else if (pos < 170) { pos -= 85; return RGBW32(0, (pos * 3), (255 - pos * 3), w); } else { diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 54469ebe..13405be6 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -36,7 +36,7 @@ uint32_t color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) * original idea: https://github.com/Aircoookie/WLED/pull/2465 by https://github.com/Proto-molecule * heavily optimized for speed by @dedehai */ -uint32_t color_add(uint32_t c1, uint32_t c2) +uint32_t color_add(uint32_t c1, uint32_t c2, bool desat) { if (c1 == BLACK) return c2; if (c2 == BLACK) return c1; @@ -47,18 +47,27 @@ uint32_t color_add(uint32_t c1, uint32_t c2) uint32_t w = wg >> 16; uint32_t g = wg & 0xFFFF; - unsigned max = r; // check for overflow note: not checking and just topping out at 255 (formerly 'fast') is not any faster (but even slower if not overflowing) - max = g > max ? g : max; - max = b > max ? b : max; - max = w > max ? w : max; + if(desat) { // desaturate + unsigned max = r; // check for overflow note + max = g > max ? g : max; + max = b > max ? b : max; + max = w > max ? w : max; - if (max > 255) { - uint32_t scale = (uint32_t(255)<<8) / max; // division of two 8bit (shifted) values does not work -> use bit shifts and multiplaction instead - rb = ((rb * scale) >> 8) & 0x00FF00FF; // - wg = (wg * scale) & 0xFF00FF00; + if (max > 255) { + uint32_t scale = (uint32_t(255)<<8) / max; // division of two 8bit (shifted) values does not work -> use bit shifts and multiplaction instead + rb = ((rb * scale) >> 8) & 0x00FF00FF; // + wg = (wg * scale) & 0xFF00FF00; + } + else wg = wg << 8; //shift white and green back to correct position + return rb | wg; + } + else { + r = r > 255 ? 255 : r; + g = g > 255 ? 255 : g; + b = b > 255 ? 255 : b; + w = w > 255 ? 255 : w; + return RGBW32(r,g,b,w); } - else wg = wg << 8; //shift white and green back to correct position - return rb | wg; } /* diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index be7ed446..d32356d7 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -79,8 +79,8 @@ class NeoGammaWLEDMethod { }; #define gamma32(c) NeoGammaWLEDMethod::Correct32(c) #define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c) -[[gnu::hot]] uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false); -[[gnu::hot]] uint32_t color_add(uint32_t,uint32_t); +[[gnu::hot]] uint32_t color_blend(uint32_t, uint32_t, uint16_t, bool b16=false); +[[gnu::hot]] uint32_t color_add(uint32_t, uint32_t, bool desat = false); [[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); [[gnu::hot]] CRGB ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND); CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette); From 17d59d333710264a6e0772b3e9d29c8a59c1e189 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 22 Sep 2024 09:02:42 +0200 Subject: [PATCH 031/463] adding initialization to vStrip, added comment on padding bytes --- wled00/FX.h | 1 + wled00/FX_fcn.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/wled00/FX.h b/wled00/FX.h index 50bcd662..49277ba1 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -368,6 +368,7 @@ typedef struct Segment { }; uint8_t startY; // start Y coodrinate 2D (top); there should be no more than 255 rows uint8_t stopY; // stop Y coordinate 2D (bottom); there should be no more than 255 rows + //note: here are 3 free bytes of padding char *name; // runtime data diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 7159d21c..e78608a1 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -712,7 +712,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) { if (!isActive()) return; // not active #ifndef WLED_DISABLE_2D - int vStrip; + int vStrip = 0; #endif if (i >= virtualLength() || i<0) // pixel would fall out of segment, check if this is a virtual strip NOTE: this is almost always false if not virtual strip, saves the calculation on 'standard' call { From 0a5400263be34b6a9b45e7d11acefce584f17614 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 22 Sep 2024 13:52:56 +0200 Subject: [PATCH 032/463] removed IRAM_ATTR from inlined function when the function is inlined into a IRAM_ATTR function, it will also reside in IRAM. Forced inlining is recommended by Espressif if I understand this correctly: https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/hardware-abstraction.html --- wled00/FX_fcn.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index e78608a1..9fd78e31 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1884,7 +1884,7 @@ bool WS2812FX::deserializeMap(uint8_t n) { return (customMappingSize > 0); } -__attribute__ ((always_inline)) inline uint16_t IRAM_ATTR WS2812FX::getMappedPixelIndex(uint16_t index) const { +__attribute__ ((always_inline)) inline uint16_t WS2812FX::getMappedPixelIndex(uint16_t index) const { // convert logical address to physical if (index < customMappingSize && (realtimeMode == REALTIME_MODE_INACTIVE || realtimeRespectLedMaps)) index = customMappingTable[index]; From 33cf82a9822a427d941107eba76e562a446a72ab Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Mon, 23 Sep 2024 18:03:17 +0200 Subject: [PATCH 033/463] Indentations and a few optimisations Restore addPixelColor() behaviour. --- wled00/FX.h | 22 ++++++++++++------- wled00/FX_2Dfcn.cpp | 16 ++++++-------- wled00/FX_fcn.cpp | 48 +++++++++++++++------------------------- wled00/cfg.cpp | 6 ++--- wled00/colors.cpp | 52 ++++++++++++++++++++++---------------------- wled00/fcn_declare.h | 2 +- 6 files changed, 69 insertions(+), 77 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 49277ba1..989dfbe3 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -56,6 +56,9 @@ #define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b)))) #endif +extern bool realtimeRespectLedMaps; // used in getMappedPixelIndex() +extern byte realtimeMode; // used in getMappedPixelIndex() + /* Not used in all effects yet */ #define WLED_FPS 42 #define FRAMETIME_FIXED (1000/WLED_FPS) @@ -596,9 +599,9 @@ typedef struct Segment { void fadeToBlackBy(uint8_t fadeBy); inline void blendPixelColor(int n, uint32_t color, uint8_t blend) { setPixelColor(n, color_blend(getPixelColor(n), color, blend)); } inline void blendPixelColor(int n, CRGB c, uint8_t blend) { blendPixelColor(n, RGBW32(c.r,c.g,c.b,0), blend); } - inline void addPixelColor(int n, uint32_t color, bool saturate = false) { setPixelColor(n, color_add(getPixelColor(n), color, saturate)); } - inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool saturate = false) { addPixelColor(n, RGBW32(r,g,b,w), saturate); } - inline void addPixelColor(int n, CRGB c, bool saturate = false) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), saturate); } + inline void addPixelColor(int n, uint32_t color, bool preserveCR = true) { setPixelColor(n, color_add(getPixelColor(n), color, preserveCR)); } + inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool preserveCR = true) { addPixelColor(n, RGBW32(r,g,b,w), preserveCR); } + inline void addPixelColor(int n, CRGB c, bool preserveCR = true) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), preserveCR); } inline void fadePixelColor(uint16_t n, uint8_t fade) { setPixelColor(n, color_fade(getPixelColor(n), fade, true)); } [[gnu::hot]] uint32_t color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255) const; [[gnu::hot]] uint32_t color_wheel(uint8_t pos) const; @@ -633,9 +636,9 @@ typedef struct Segment { // 2D support functions inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) { setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend)); } inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), blend); } - inline void addPixelColorXY(int x, int y, uint32_t color, bool saturate = false) { setPixelColorXY(x, y, color_add(getPixelColorXY(x,y), color, saturate)); } - inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool saturate = false) { addPixelColorXY(x, y, RGBW32(r,g,b,w), saturate); } - inline void addPixelColorXY(int x, int y, CRGB c, bool saturate = false) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), saturate); } + inline void addPixelColorXY(int x, int y, uint32_t color, bool preserveCR = true) { setPixelColorXY(x, y, color_add(getPixelColorXY(x,y), color, preserveCR)); } + inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool preserveCR = true) { addPixelColorXY(x, y, RGBW32(r,g,b,w), preserveCR); } + inline void addPixelColorXY(int x, int y, CRGB c, bool preserveCR = true) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), preserveCR); } inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), fade, true)); } void box_blur(unsigned r = 1U, bool smear = false); // 2D box blur void blur2D(uint8_t blur_amount, bool smear = false); @@ -837,13 +840,16 @@ class WS2812FX { // 96 bytes uint16_t getLengthPhysical() const, getLengthTotal() const, // will include virtual/nonexistent pixels in matrix - getFps() const, - getMappedPixelIndex(uint16_t index) const; + getFps() const; inline uint16_t getFrameTime() const { return _frametime; } // returns amount of time a frame should take (in ms) inline uint16_t getMinShowDelay() const { return MIN_SHOW_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant) inline uint16_t getLength() const { return _length; } // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H) inline uint16_t getTransition() const { return _transitionDur; } // returns currently set transition time (in ms) + inline uint16_t getMappedPixelIndex(uint16_t index) const { // convert logical address to physical + if (index < customMappingSize && (realtimeMode == REALTIME_MODE_INACTIVE || realtimeRespectLedMaps)) index = customMappingTable[index]; + return index; + }; uint32_t now, diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 63595d93..ca28a958 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -191,7 +191,7 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) if (yY >= H) break; int xX = x; for (int g = 0; g < grouping; g++) { // groupping horizontally - if (xX >= W) continue; // we have reached one dimension's end + if (xX >= W) break; // we have reached X dimension's end #ifndef WLED_DISABLE_MODE_BLEND // if blending modes, blend with underlying pixel if (_modeBlend) col = color_blend(strip.getPixelColorXY(start + xX, startY + yY), col, 0xFFFFU - progress(), true); @@ -292,11 +292,10 @@ void Segment::blurRow(uint32_t row, fract8 blur_amount, bool smear){ uint32_t part = color_fade(cur, seep); curnew = color_fade(cur, keep); if (x > 0) { - if (carryover) - curnew = color_add(curnew, carryover); + if (carryover) curnew = color_add(curnew, carryover); uint32_t prev = color_add(lastnew, part); - if (last != prev) // optimization: only set pixel if color has changed - setPixelColorXY(x - 1, row, prev); + // optimization: only set pixel if color has changed + if (last != prev) setPixelColorXY(x - 1, row, prev); } else // first pixel setPixelColorXY(x, row, curnew); lastnew = curnew; @@ -325,11 +324,10 @@ void Segment::blurCol(uint32_t col, fract8 blur_amount, bool smear) { uint32_t part = color_fade(cur, seep); curnew = color_fade(cur, keep); if (y > 0) { - if (carryover) - curnew = color_add(curnew, carryover); + if (carryover) curnew = color_add(curnew, carryover); uint32_t prev = color_add(lastnew, part); - if (last != prev) // optimization: only set pixel if color has changed - setPixelColorXY(col, y - 1, prev); + // optimization: only set pixel if color has changed + if (last != prev) setPixelColorXY(col, y - 1, prev); } else // first pixel setPixelColorXY(col, y, curnew); lastnew = curnew; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 9fd78e31..545c92f2 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -628,13 +628,7 @@ uint16_t IRAM_ATTR Segment::virtualHeight() const { uint16_t IRAM_ATTR_YN Segment::nrOfVStrips() const { unsigned vLen = 1; #ifndef WLED_DISABLE_2D - if (is2D()) { - switch (map1D2D) { - case M12_pBar: - vLen = virtualWidth(); - break; - } - } + if (is2D() && map1D2D == M12_pBar) vLen = virtualWidth(); #endif return vLen; } @@ -710,17 +704,21 @@ uint16_t IRAM_ATTR Segment::virtualLength() const { void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) { - if (!isActive()) return; // not active + if (!isActive() || i < 0) return; // not active or invalid index #ifndef WLED_DISABLE_2D int vStrip = 0; #endif - if (i >= virtualLength() || i<0) // pixel would fall out of segment, check if this is a virtual strip NOTE: this is almost always false if not virtual strip, saves the calculation on 'standard' call - { + // if the 1D effect is using virtual strips "i" will have virtual strip id stored in upper 16 bits + // in such case "i" will be > virtualLength() + if (i >= virtualLength()) { + // check if this is a virtual strip #ifndef WLED_DISABLE_2D vStrip = i>>16; // hack to allow running on virtual strips (2D segment columns/rows) + i &= 0xFFFF; //truncate vstrip index + if (i >= virtualLength()) return; // if pixel would still fall out of segment just exit + #else + return; #endif - i &= 0xFFFF; //truncate vstrip index - if (i >= virtualLength() || i<0) return; // if pixel would still fall out of segment just exit } #ifndef WLED_DISABLE_2D @@ -734,12 +732,12 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) break; case M12_pBar: // expand 1D effect vertically or have it play on virtual strips - if (vStrip>0) setPixelColorXY(vStrip - 1, vH - i - 1, col); - else for (int x = 0; x < vW; x++) setPixelColorXY(x, vH - i - 1, col); + if (vStrip > 0) setPixelColorXY(vStrip - 1, vH - i - 1, col); + else for (int x = 0; x < vW; x++) setPixelColorXY(x, vH - i - 1, col); break; case M12_pArc: // expand in circular fashion from center - if (i==0) + if (i == 0) setPixelColorXY(0, 0, col); else { float r = i; @@ -910,9 +908,6 @@ void Segment::setPixelColor(float i, uint32_t col, bool aa) uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const { if (!isActive()) return 0; // not active -#ifndef WLED_DISABLE_2D - int vStrip = i>>16; -#endif #ifndef WLED_DISABLE_2D if (is2D()) { @@ -922,10 +917,11 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const case M12_Pixels: return getPixelColorXY(i % vW, i / vW); break; - case M12_pBar: - if (vStrip>0) { i &= 0xFFFF; return getPixelColorXY(vStrip - 1, vH - i -1); } - else return getPixelColorXY(0, vH - i -1); - break; + case M12_pBar: { + int vStrip = i>>16; // virtual strips are only relevant in Bar expansion mode + if (vStrip > 0) return getPixelColorXY(vStrip - 1, vH - (i & 0xFFFF) -1); + else return getPixelColorXY(0, vH - i -1); + break; } case M12_pArc: if (i >= vW && i >= vH) { unsigned vI = sqrt16(i*i/2); @@ -1884,14 +1880,6 @@ bool WS2812FX::deserializeMap(uint8_t n) { return (customMappingSize > 0); } -__attribute__ ((always_inline)) inline uint16_t WS2812FX::getMappedPixelIndex(uint16_t index) const { - // convert logical address to physical - if (index < customMappingSize - && (realtimeMode == REALTIME_MODE_INACTIVE || realtimeRespectLedMaps)) index = customMappingTable[index]; - - return index; -} - WS2812FX* WS2812FX::instance = nullptr; diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 8983da65..00e21913 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -437,9 +437,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { if (light_gc_col > 1.0f) gammaCorrectCol = true; else gammaCorrectCol = false; if (gammaCorrectVal <= 1.0f || gammaCorrectVal > 3) { - gammaCorrectVal = 1.0f; // no gamma correction - gammaCorrectBri = false; - gammaCorrectCol = false; + gammaCorrectVal = 1.0f; // no gamma correction + gammaCorrectBri = false; + gammaCorrectCol = false; } NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 13405be6..233d3d11 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -34,9 +34,9 @@ uint32_t color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) /* * color add function that preserves ratio * original idea: https://github.com/Aircoookie/WLED/pull/2465 by https://github.com/Proto-molecule - * heavily optimized for speed by @dedehai + * speed optimisations by @dedehai */ -uint32_t color_add(uint32_t c1, uint32_t c2, bool desat) +uint32_t color_add(uint32_t c1, uint32_t c2, bool preserveCR) { if (c1 == BLACK) return c2; if (c2 == BLACK) return c1; @@ -47,21 +47,21 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool desat) uint32_t w = wg >> 16; uint32_t g = wg & 0xFFFF; - if(desat) { // desaturate - unsigned max = r; // check for overflow note - max = g > max ? g : max; - max = b > max ? b : max; - max = w > max ? w : max; - + if (preserveCR) { // preserve color ratios + unsigned max = std::max(r,g); // check for overflow note + max = std::max(max,b); + max = std::max(max,w); + //unsigned max = r; // check for overflow note + //max = g > max ? g : max; + //max = b > max ? b : max; + //max = w > max ? w : max; if (max > 255) { uint32_t scale = (uint32_t(255)<<8) / max; // division of two 8bit (shifted) values does not work -> use bit shifts and multiplaction instead rb = ((rb * scale) >> 8) & 0x00FF00FF; // wg = (wg * scale) & 0xFF00FF00; - } - else wg = wg << 8; //shift white and green back to correct position + } else wg = wg << 8; //shift white and green back to correct position return rb | wg; - } - else { + } else { r = r > 255 ? 255 : r; g = g > 255 ? 255 : g; b = b > 255 ? 255 : b; @@ -106,20 +106,20 @@ CRGB ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brig unsigned red1 = entry->r; unsigned green1 = entry->g; unsigned blue1 = entry->b; - if(blendType != NOBLEND) { - if(hi4 == 15) entry = &(pal[0]); - else ++entry; - unsigned f2 = ((index & 0x0F) << 4) + 1; // +1 so we scale by 256 as a max value, then result can just be shifted by 8 - unsigned f1 = (257 - f2); // f2 is 1 minimum, so this is 256 max - red1 = (red1 * f1 + (unsigned)entry->r * f2) >> 8; - green1 = (green1 * f1 + (unsigned)entry->g * f2) >> 8; - blue1 = (blue1 * f1 + (unsigned)entry->b * f2) >> 8; + if (blendType != NOBLEND) { + if (hi4 == 15) entry = &(pal[0]); + else ++entry; + unsigned f2 = ((index & 0x0F) << 4) + 1; // +1 so we scale by 256 as a max value, then result can just be shifted by 8 + unsigned f1 = (257 - f2); // f2 is 1 minimum, so this is 256 max + red1 = (red1 * f1 + (unsigned)entry->r * f2) >> 8; + green1 = (green1 * f1 + (unsigned)entry->g * f2) >> 8; + blue1 = (blue1 * f1 + (unsigned)entry->b * f2) >> 8; } - if( brightness < 255) { // note: zero checking could be done to return black but that is hardly ever used so it is omitted - uint32_t scale = brightness + 1; // adjust for rounding (bitshift) - red1 = (red1 * scale) >> 8; - green1 = (green1 * scale) >> 8; - blue1 = (blue1 * scale) >> 8; + if (brightness < 255) { // note: zero checking could be done to return black but that is hardly ever used so it is omitted + uint32_t scale = brightness + 1; // adjust for rounding (bitshift) + red1 = (red1 * scale) >> 8; + green1 = (green1 * scale) >> 8; + blue1 = (blue1 * scale) >> 8; } return CRGB((uint8_t)red1, (uint8_t)green1, (uint8_t)blue1); } @@ -485,7 +485,7 @@ uint16_t approximateKelvinFromRGB(uint32_t rgb) { } } -//gamma 2.8 lookup table used for color correction +// gamma lookup table used for color correction (filled on 1st use (cfg.cpp & set.cpp)) uint8_t NeoGammaWLEDMethod::gammaT[256]; // re-calculates & fills gamma table diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index d32356d7..741e1eef 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -80,7 +80,7 @@ class NeoGammaWLEDMethod { #define gamma32(c) NeoGammaWLEDMethod::Correct32(c) #define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c) [[gnu::hot]] uint32_t color_blend(uint32_t, uint32_t, uint16_t, bool b16=false); -[[gnu::hot]] uint32_t color_add(uint32_t, uint32_t, bool desat = false); +[[gnu::hot]] uint32_t color_add(uint32_t, uint32_t, bool preserveCR = false); [[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); [[gnu::hot]] CRGB ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND); CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette); From 906f8fc2e72cc901be7136fe533a40a27a97fd2d Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Wed, 25 Sep 2024 18:49:10 +0200 Subject: [PATCH 034/463] Fix C3 compiler issue. --- wled00/colors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 233d3d11..00f18460 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -48,7 +48,7 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool preserveCR) uint32_t g = wg & 0xFFFF; if (preserveCR) { // preserve color ratios - unsigned max = std::max(r,g); // check for overflow note + uint32_t max = std::max(r,g); // check for overflow note max = std::max(max,b); max = std::max(max,w); //unsigned max = r; // check for overflow note From bef1ac2668eb17312549e637f81c3954ac3052cd Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Wed, 25 Sep 2024 19:36:20 +0200 Subject: [PATCH 035/463] Added HSV2RGB and RGB2HSV functions for higher accuracy conversions - also added a struct to handle HSV with 16bit hue better (including some conversions, can be extended easily) - the functions are optimized for speed and flash use. They are faster and more accurate than what fastled offers (and use much less flash). - replaced colorHStoRGB() with a call to the new hsv2rgb() function, saving even more flash (new function is untested!) - the 16bit hue calculations result in an almost perfect conversion from RGB to HSV and back, the maximum error was 1/255 in the cases I tested. --- wled00/colors.cpp | 74 +++++++++++++++++++++++++++++++++----------- wled00/fcn_declare.h | 29 ++++++++++++++++- wled00/ir.cpp | 4 +-- 3 files changed, 86 insertions(+), 21 deletions(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 00f18460..163429f7 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -239,26 +239,64 @@ CRGBPalette16 generateRandomPalette() //generate fully random palette CHSV(random8(), random8(160, 255), random8(128, 255))); } -void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb +void hsv2rgb(const CHSV32& hsv, uint32_t& rgb) // convert HSV (16bit hue) to RGB (32bit with white = 0) { - float h = ((float)hue)/10922.5f; // hue*6/65535 - float s = ((float)sat)/255.0f; - int i = int(h); - float f = h - i; - int p = int(255.0f * (1.0f-s)); - int q = int(255.0f * (1.0f-s*f)); - int t = int(255.0f * (1.0f-s*(1.0f-f))); - p = constrain(p, 0, 255); - q = constrain(q, 0, 255); - t = constrain(t, 0, 255); - switch (i%6) { - case 0: rgb[0]=255,rgb[1]=t, rgb[2]=p; break; - case 1: rgb[0]=q, rgb[1]=255,rgb[2]=p; break; - case 2: rgb[0]=p, rgb[1]=255,rgb[2]=t; break; - case 3: rgb[0]=p, rgb[1]=q, rgb[2]=255;break; - case 4: rgb[0]=t, rgb[1]=p, rgb[2]=255;break; - case 5: rgb[0]=255,rgb[1]=p, rgb[2]=q; break; + unsigned int remainder, region, p, q, t; + unsigned int h = hsv.h; + unsigned int s = hsv.s; + unsigned int v = hsv.v; + if (s == 0) { + rgb = v << 16 | v << 8 | v; + return; } + region = h / 10923; // 65536 / 6 = 10923 + remainder = (h - (region * 10923)) * 6; + p = (v * (256 - s)) >> 8; + q = (v * (255 - ((s * remainder) >> 16))) >> 8; + t = (v * (255 - ((s * (65535 - remainder)) >> 16))) >> 8; + switch (region) { + case 0: + rgb = v << 16 | t << 8 | p; break; + case 1: + rgb = q << 16 | v << 8 | p; break; + case 2: + rgb = p << 16 | v << 8 | t; break; + case 3: + rgb = p << 16 | q << 8 | v; break; + case 4: + rgb = t << 16 | p << 8 | v; break; + default: + rgb = v << 16 | p << 8 | q; break; + } +} + +void rgb2hsv(const uint32_t rgb, CHSV32& hsv) // convert RGB to HSV (16bit hue), much more accurate and faster than fastled version +{ + hsv.raw = 0; + int32_t r = (rgb>>16)&0xFF; + int32_t g = (rgb>>8)&0xFF; + int32_t b = rgb&0xFF; + int32_t minval, maxval, delta; + minval = min(r, g); + minval = min(minval, b); + maxval = max(r, g); + maxval = max(maxval, b); + if (maxval == 0) return; // black + hsv.v = maxval; + delta = maxval - minval; + hsv.s = (255 * delta) / maxval; + if (hsv.s == 0) return; // gray value + if (maxval == r) hsv.h = (10923 * (g - b)) / delta; + else if (maxval == g) hsv.h = 21845 + (10923 * (b - r)) / delta; + else hsv.h = 43690 + (10923 * (r - g)) / delta; +} + +void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) { //hue, sat to rgb + uint32_t crgb; + hsv2rgb(CHSV32(hue, sat, 255), crgb); + rgb[0] = byte((crgb) >> 16); + rgb[1] = byte((crgb) >> 8); + rgb[2] = byte(crgb); } //get RGB values from color temperature in K (https://tannerhelland.com/2012/09/18/convert-temperature-rgb-algorithm-code.html) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 741e1eef..b5bd1c28 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -67,6 +67,30 @@ typedef struct WiFiConfig { //colors.cpp #define ColorFromPalette ColorFromPaletteWLED // override fastled version + +struct CHSV32 { // 32bit HSV color with 16bit hue for more accurate conversions + union { + struct { + uint16_t h; // hue + uint8_t s; // saturation + uint8_t v; // value + }; + uint32_t raw; // 32bit access + }; + inline CHSV32() __attribute__((always_inline)) = default; // default constructor + + /// Allow construction from hue, saturation, and value + /// @param ih input hue + /// @param is input saturation + /// @param iv input value + inline CHSV32(uint16_t ih, uint8_t is, uint8_t iv) __attribute__((always_inline)) // constructor from 16bit h, s, v + : h(ih), s(is), v(iv) {} + inline CHSV32(uint8_t ih, uint8_t is, uint8_t iv) __attribute__((always_inline)) // constructor from 8bit h, s, v + : h((uint16_t)ih << 8), s(is), v(iv) {} + inline CHSV32(const CHSV& chsv) __attribute__((always_inline)) // constructor from CHSV + : h((uint16_t)chsv.h << 8), s(chsv.s), v(chsv.v) {} + inline operator CHSV() const { return CHSV((uint8_t)(h >> 8), s, v); } // typecast to CHSV +}; // similar to NeoPixelBus NeoGammaTableMethod but allows dynamic changes (superseded by NPB::NeoGammaDynamicTableMethod) class NeoGammaWLEDMethod { public: @@ -86,7 +110,10 @@ class NeoGammaWLEDMethod { CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette); CRGBPalette16 generateRandomPalette(); inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); } -void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb +void hsv2rgb(const CHSV32& hsv, uint32_t& rgb); +void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); +void rgb2hsv(const uint32_t rgb, CHSV32& hsv); +inline CHSV rgb2hsv(const CRGB c) { CHSV32 hsv; rgb2hsv((uint32_t((byte(c.r) << 16) | (byte(c.g) << 8) | (byte(c.b)))), hsv); return CHSV(hsv); } // CRGB to hsv void colorKtoRGB(uint16_t kelvin, byte* rgb); void colorCTtoRGB(uint16_t mired, byte* rgb); //white spectrum to rgb void colorXYtoRGB(float x, float y, byte* rgb); // only defined if huesync disabled TODO diff --git a/wled00/ir.cpp b/wled00/ir.cpp index e4541cd9..f094d3b8 100644 --- a/wled00/ir.cpp +++ b/wled00/ir.cpp @@ -129,7 +129,7 @@ static void changeEffectSpeed(int8_t amount) } else { // if Effect == "solid Color", change the hue of the primary color Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment(); CRGB fastled_col = CRGB(sseg.colors[0]); - CHSV prim_hsv = rgb2hsv_approximate(fastled_col); + CHSV prim_hsv = rgb2hsv(fastled_col); int16_t new_val = (int16_t)prim_hsv.h + amount; if (new_val > 255) new_val -= 255; // roll-over if bigger than 255 if (new_val < 0) new_val += 255; // roll-over if smaller than 0 @@ -173,7 +173,7 @@ static void changeEffectIntensity(int8_t amount) } else { // if Effect == "solid Color", change the saturation of the primary color Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment(); CRGB fastled_col = CRGB(sseg.colors[0]); - CHSV prim_hsv = rgb2hsv_approximate(fastled_col); + CHSV prim_hsv = rgb2hsv(fastled_col); int16_t new_val = (int16_t) prim_hsv.s + amount; prim_hsv.s = (byte)constrain(new_val,0,255); // constrain to 0-255 hsv2rgb_rainbow(prim_hsv, fastled_col); From b40445836931f769dce87168ff80c0ec489afc2c Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 26 Sep 2024 18:29:31 +0200 Subject: [PATCH 036/463] fixed one forgotten replacement of rgb2hsv_approximate --- wled00/colors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 163429f7..d705b9a7 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -138,7 +138,7 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) { CHSV palettecolors[4]; //array of colors for the new palette uint8_t keepcolorposition = random8(4); //color position of current random palette to keep - palettecolors[keepcolorposition] = rgb2hsv_approximate(basepalette.entries[keepcolorposition*5]); //read one of the base colors of the current palette + palettecolors[keepcolorposition] = rgb2hsv(basepalette.entries[keepcolorposition*5]); //read one of the base colors of the current palette palettecolors[keepcolorposition].hue += random8(10)-5; // +/- 5 randomness of base color //generate 4 saturation and brightness value numbers //only one saturation is allowed to be below 200 creating mostly vibrant colors From a76a895f1d86f9405b94fca5dc91a6649bdf48dd Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Fri, 27 Sep 2024 06:17:26 +0200 Subject: [PATCH 037/463] bugfix --- wled00/colors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index d705b9a7..1b6a6f8d 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -251,7 +251,7 @@ void hsv2rgb(const CHSV32& hsv, uint32_t& rgb) // convert HSV (16bit hue) to RGB } region = h / 10923; // 65536 / 6 = 10923 remainder = (h - (region * 10923)) * 6; - p = (v * (256 - s)) >> 8; + p = (v * (255 - s)) >> 8; q = (v * (255 - ((s * remainder) >> 16))) >> 8; t = (v * (255 - ((s * (65535 - remainder)) >> 16))) >> 8; switch (region) { From 7c0fe1285aa21e20b16c1185e93fc5e65cd32b3c Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 28 Sep 2024 15:26:14 +0200 Subject: [PATCH 038/463] updated setPixelColor() and getPixelColor() functions uint16_t to unsigned to make it consisten throughout the hand-down. colorFromPaletteWLED now returns uint32_t which saves the conversion to CRGB and back to uint32_t (in most uses at least). also added (preliminary) CRGBW struct. I tried to use it in place of uint32_t colors but it adds a lot of overhead when passing the struct so reverted to uint32_t in most places. updated a few FX to use the CRGBW struct and also cleaned some code to improve flash useage. --- wled00/FX.cpp | 92 ++++++++++++++++++------------------------ wled00/FX.h | 6 +-- wled00/FX_2Dfcn.cpp | 2 +- wled00/FX_fcn.cpp | 7 ++-- wled00/bus_manager.cpp | 20 ++++----- wled00/bus_manager.h | 24 +++++------ wled00/colors.cpp | 4 +- wled00/fcn_declare.h | 60 ++++++++++++++++++++++++++- 8 files changed, 129 insertions(+), 86 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index ad843f0f..3df91547 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -1937,7 +1937,7 @@ uint16_t mode_juggle(void) { for (int i = 0; i < 8; i++) { int index = 0 + beatsin88((16 + SEGMENT.speed)*(i + 7), 0, SEGLEN -1); fastled_col = CRGB(SEGMENT.getPixelColor(index)); - fastled_col |= (SEGMENT.palette==0)?CHSV(dothue, 220, 255):ColorFromPalette(SEGPALETTE, dothue, 255); + fastled_col |= (SEGMENT.palette==0)?CHSV(dothue, 220, 255):CRGB(ColorFromPalette(SEGPALETTE, dothue, 255)); SEGMENT.setPixelColor(index, fastled_col); dothue += 32; } @@ -2282,33 +2282,33 @@ uint16_t mode_colortwinkle() { unsigned dataSize = (SEGLEN+7) >> 3; //1 bit per LED if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed - CRGB fastled_col, prev; + CRGBW col, prev; fract8 fadeUpAmount = strip.getBrightness()>28 ? 8 + (SEGMENT.speed>>2) : 68-strip.getBrightness(); fract8 fadeDownAmount = strip.getBrightness()>28 ? 8 + (SEGMENT.speed>>3) : 68-strip.getBrightness(); for (int i = 0; i < SEGLEN; i++) { - fastled_col = SEGMENT.getPixelColor(i); - prev = fastled_col; + CRGBW cur = SEGMENT.getPixelColor(i); + prev = cur; unsigned index = i >> 3; unsigned bitNum = i & 0x07; bool fadeUp = bitRead(SEGENV.data[index], bitNum); if (fadeUp) { - CRGB incrementalColor = fastled_col; - incrementalColor.nscale8_video(fadeUpAmount); - fastled_col += incrementalColor; + CRGBW incrementalColor = color_fade(col, fadeUpAmount, true); + col = color_add(cur, incrementalColor); - if (fastled_col.red == 255 || fastled_col.green == 255 || fastled_col.blue == 255) { + if (col.r == 255 || col.g == 255 || col.b == 255) { bitWrite(SEGENV.data[index], bitNum, false); } - SEGMENT.setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); - if (SEGMENT.getPixelColor(i) == RGBW32(prev.r, prev.g, prev.b, 0)) { //fix "stuck" pixels - fastled_col += fastled_col; - SEGMENT.setPixelColor(i, fastled_col); + if (cur == prev) { //fix "stuck" pixels + color_add(col, col); + SEGMENT.setPixelColor(i, col); } - } else { - fastled_col.nscale8(255 - fadeDownAmount); - SEGMENT.setPixelColor(i, fastled_col); + else SEGMENT.setPixelColor(i, col); + } + else { + col = color_fade(cur, 255 - fadeDownAmount); + SEGMENT.setPixelColor(i, col); } } @@ -2317,11 +2317,10 @@ uint16_t mode_colortwinkle() { for (unsigned times = 0; times < 5; times++) { //attempt to spawn a new pixel 5 times int i = random16(SEGLEN); if (SEGMENT.getPixelColor(i) == 0) { - fastled_col = ColorFromPalette(SEGPALETTE, random8(), 64, NOBLEND); unsigned index = i >> 3; unsigned bitNum = i & 0x07; bitWrite(SEGENV.data[index], bitNum, true); - SEGMENT.setPixelColor(i, fastled_col); + SEGMENT.setPixelColor(i, ColorFromPalette(SEGPALETTE, random8(), 64, NOBLEND)); break; //only spawn 1 new pixel per frame per 50 LEDs } } @@ -2378,8 +2377,7 @@ uint16_t mode_meteor() { index = map(i,0,SEGLEN,0,max); bri = trail[i]; } - uint32_t col = SEGMENT.color_from_palette(index, false, false, idx, bri); // full brightness for Fire - SEGMENT.setPixelColor(i, col); + SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, false, idx, bri)); // full brightness for Fire } } @@ -2392,8 +2390,7 @@ uint16_t mode_meteor() { i = map(index,0,SEGLEN,0,max); idx = 0; } - uint32_t col = SEGMENT.color_from_palette(i, false, false, idx, 255); // full brightness - SEGMENT.setPixelColor(index, col); + SEGMENT.setPixelColor(index, SEGMENT.color_from_palette(i, false, false, idx, 255)); // full brightness } return FRAMETIME; @@ -2419,8 +2416,7 @@ uint16_t mode_meteor_smooth() { if (/*trail[i] != 0 &&*/ random8() <= 255 - SEGMENT.intensity) { int change = trail[i] + 4 - random8(24); //change each time between -20 and +4 trail[i] = constrain(change, 0, max); - uint32_t col = SEGMENT.check1 ? SEGMENT.color_from_palette(i, true, false, 0, trail[i]) : SEGMENT.color_from_palette(trail[i], false, true, 255); - SEGMENT.setPixelColor(i, col); + SEGMENT.setPixelColor(i, SEGMENT.check1 ? SEGMENT.color_from_palette(i, true, false, 0, trail[i]) : SEGMENT.color_from_palette(trail[i], false, true, 255)); } } @@ -2431,8 +2427,7 @@ uint16_t mode_meteor_smooth() { index -= SEGLEN; } trail[index] = max; - uint32_t col = SEGMENT.check1 ? SEGMENT.color_from_palette(index, true, false, 0, trail[index]) : SEGMENT.color_from_palette(trail[index], false, true, 255); - SEGMENT.setPixelColor(index, col); + SEGMENT.setPixelColor(index, SEGMENT.check1 ? SEGMENT.color_from_palette(index, true, false, 0, trail[index]) : SEGMENT.color_from_palette(trail[index], false, true, 255)); } SEGENV.step += SEGMENT.speed +1; @@ -2680,7 +2675,7 @@ static uint16_t twinklefox_base(bool cat) if (deltabright >= 32 || (!bg)) { // If the new pixel is significantly brighter than the background color, // use the new color. - SEGMENT.setPixelColor(i, c.red, c.green, c.blue); + SEGMENT.setPixelColor(i, c); } else if (deltabright > 0) { // If the new pixel is just slightly brighter than the background color, // mix a blend of the new color and the background color @@ -2688,7 +2683,7 @@ static uint16_t twinklefox_base(bool cat) } else { // if the new pixel is not at all brighter than the background color, // just use the background color. - SEGMENT.setPixelColor(i, bg.r, bg.g, bg.b); + SEGMENT.setPixelColor(i, bg); } } return FRAMETIME; @@ -3532,7 +3527,7 @@ uint16_t mode_starburst(void) { if (start == end) end++; if (end > SEGLEN) end = SEGLEN; for (int p = start; p < end; p++) { - SEGMENT.setPixelColor(p, c.r, c.g, c.b); + SEGMENT.setPixelColor(p, c); } } } @@ -3650,17 +3645,17 @@ uint16_t mode_exploding_fireworks(void) if (SEGMENT.is2D() && !(sparks[i].posX >= 0 && sparks[i].posX < cols)) continue; unsigned prog = sparks[i].col; uint32_t spColor = (SEGMENT.palette) ? SEGMENT.color_wheel(sparks[i].colIndex) : SEGCOLOR(0); - CRGB c = CRGB::Black; //HeatColor(sparks[i].col); + CRGBW c = BLACK; //HeatColor(sparks[i].col); if (prog > 300) { //fade from white to spark color - c = CRGB(color_blend(spColor, WHITE, (prog - 300)*5)); + c = color_blend(spColor, WHITE, (prog - 300)*5); } else if (prog > 45) { //fade from spark color to black - c = CRGB(color_blend(BLACK, spColor, prog - 45)); + c = color_blend(BLACK, spColor, prog - 45); unsigned cooling = (300 - prog) >> 5; c.g = qsub8(c.g, cooling); c.b = qsub8(c.b, cooling * 2); } - if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(int(sparks[i].posX), rows - int(sparks[i].pos) - 1, c.red, c.green, c.blue); - else SEGMENT.setPixelColor(int(sparks[i].posX) ? rows - int(sparks[i].pos) - 1 : int(sparks[i].pos), c.red, c.green, c.blue); + if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(int(sparks[i].posX), rows - int(sparks[i].pos) - 1, c); + else SEGMENT.setPixelColor(int(sparks[i].posX) ? rows - int(sparks[i].pos) - 1 : int(sparks[i].pos), c); } } if (SEGMENT.check3) SEGMENT.blur(16); @@ -4006,7 +4001,7 @@ static CRGB pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, u ci += (cs * i); unsigned sindex16 = sin16(ci) + 32768; unsigned sindex8 = scale16(sindex16, 240); - return ColorFromPalette(p, sindex8, bri, LINEARBLEND); + return CRGB(ColorFromPalette(p, sindex8, bri, LINEARBLEND)); } uint16_t mode_pacifica() @@ -4077,7 +4072,7 @@ uint16_t mode_pacifica() c.green = scale8(c.green, 200); c |= CRGB( 2, 5, 7); - SEGMENT.setPixelColor(i, c.red, c.green, c.blue); + SEGMENT.setPixelColor(i, c); } strip.now = nowOld; @@ -4119,13 +4114,10 @@ uint16_t mode_sunrise() { for (int i = 0; i <= SEGLEN/2; i++) { - //default palette is Fire - uint32_t c = SEGMENT.color_from_palette(0, false, true, 255); //background - + //default palette is Fire unsigned wave = triwave16((i * stage) / SEGLEN); - wave = (wave >> 8) + ((wave * SEGMENT.intensity) >> 15); - + uint32_t c; if (wave > 240) { //clipped, full white sun c = SEGMENT.color_from_palette( 240, false, true, 255); } else { //transition @@ -4217,8 +4209,6 @@ uint16_t mode_noisepal(void) { // Slow noise palettes[1] = CRGBPalette16(CHSV(baseI+random8(64), 255, random8(128,255)), CHSV(baseI+128, 255, random8(128,255)), CHSV(baseI+random8(92), 192, random8(128,255)), CHSV(baseI+random8(92), 255, random8(128,255))); } - CRGB color; - //EVERY_N_MILLIS(10) { //(don't have to time this, effect function is only called every 24ms) nblendPaletteTowardPalette(palettes[0], palettes[1], 48); // Blend towards the target palette over 48 iterations. @@ -4226,8 +4216,7 @@ uint16_t mode_noisepal(void) { // Slow noise for (int i = 0; i < SEGLEN; i++) { unsigned index = inoise8(i*scale, SEGENV.aux0+i*scale); // Get a value from the noise function. I'm using both x and y axis. - color = ColorFromPalette(palettes[0], index, 255, LINEARBLEND); // Use the my own palette. - SEGMENT.setPixelColor(i, color.red, color.green, color.blue); + SEGMENT.setPixelColor(i, ColorFromPalette(palettes[0], index, 255, LINEARBLEND)); // Use my own palette. } SEGENV.aux0 += beatsin8(10,1,4); // Moving along the distance. Vary it a bit with a sine wave. @@ -4314,9 +4303,8 @@ uint16_t mode_chunchun(void) counter -= span; unsigned megumin = sin16(counter) + 0x8000; unsigned bird = uint32_t(megumin * SEGLEN) >> 16; - uint32_t c = SEGMENT.color_from_palette((i * 255)/ numBirds, false, false, 0); // no palette wrapping bird = constrain(bird, 0U, SEGLEN-1U); - SEGMENT.setPixelColor(bird, c); + SEGMENT.setPixelColor(bird, SEGMENT.color_from_palette((i * 255)/ numBirds, false, false, 0)); // no palette wrapping } return FRAMETIME; } @@ -4934,7 +4922,7 @@ uint16_t mode_2DColoredBursts() { // By: ldirko https://editor.so byte x2 = beatsin8(1 + SEGMENT.speed/16, 0, (cols - 1)); byte y1 = beatsin8(5 + SEGMENT.speed/16, 0, (rows - 1), 0, i * 24); byte y2 = beatsin8(3 + SEGMENT.speed/16, 0, (rows - 1), 0, i * 48 + 64); - CRGB color = ColorFromPalette(SEGPALETTE, i * 255 / numLines + (SEGENV.aux0&0xFF), 255, LINEARBLEND); + uint32_t color = ColorFromPalette(SEGPALETTE, i * 255 / numLines + (SEGENV.aux0&0xFF), 255, LINEARBLEND); byte xsteps = abs8(x1 - y1) + 1; byte ysteps = abs8(x2 - y2) + 1; @@ -5831,7 +5819,7 @@ uint16_t mode_2Dspaceships(void) { //// Space ships by stepko (c)05.02.21 [ht for (size_t i = 0; i < 8; i++) { int x = beatsin8(12 + i, 2, cols - 3); int y = beatsin8(15 + i, 2, rows - 3); - CRGB color = ColorFromPalette(SEGPALETTE, beatsin8(12 + i, 0, 255), 255); + uint32_t color = ColorFromPalette(SEGPALETTE, beatsin8(12 + i, 0, 255), 255); SEGMENT.addPixelColorXY(x, y, color); if (cols > 24 || rows > 24) { SEGMENT.addPixelColorXY(x+1, y, color); @@ -6725,8 +6713,7 @@ uint16_t mode_noisefire(void) { // Noisefire. By Andrew Tuline. index = (255 - i*256/SEGLEN) * index/(256-SEGMENT.intensity); // Now we need to scale index so that it gets blacker as we get close to one of the ends. // This is a simple y=mx+b equation that's been scaled. index/128 is another scaling. - CRGB color = ColorFromPalette(myPal, index, volumeSmth*2, LINEARBLEND); // Use the my own palette. - SEGMENT.setPixelColor(i, color); + SEGMENT.setPixelColor(i, ColorFromPalette(myPal, index, volumeSmth*2, LINEARBLEND)); // Use my own palette. } return FRAMETIME; @@ -7532,7 +7519,7 @@ uint16_t mode_2DAkemi(void) { unsigned band = x * cols/8; band = constrain(band, 0, 15); int barHeight = map(fftResult[band], 0, 255, 0, 17*rows/32); - CRGB color = CRGB(SEGMENT.color_from_palette((band * 35), false, PALETTE_SOLID_WRAP, 0)); + uint32_t color = SEGMENT.color_from_palette((band * 35), false, PALETTE_SOLID_WRAP, 0); for (int y=0; y < barHeight; y++) { SEGMENT.setPixelColorXY(x, rows/2-y, color); @@ -7760,8 +7747,7 @@ uint16_t mode_2Doctopus() { //CRGB c = CHSV(SEGENV.step / 2 - radius, 255, sin8(sin8((angle * 4 - radius) / 4 + SEGENV.step) + radius - SEGENV.step * 2 + angle * (SEGMENT.custom3/3+1))); unsigned intensity = sin8(sin8((angle * 4 - radius) / 4 + SEGENV.step/2) + radius - SEGENV.step + angle * (SEGMENT.custom3/4+1)); intensity = map((intensity*intensity) & 0xFFFF, 0, 65535, 0, 255); // add a bit of non-linearity for cleaner display - CRGB c = ColorFromPalette(SEGPALETTE, SEGENV.step / 2 - radius, intensity); - SEGMENT.setPixelColorXY(x, y, c); + SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, SEGENV.step / 2 - radius, intensity)); } } return FRAMETIME; diff --git a/wled00/FX.h b/wled00/FX.h index 989dfbe3..825c722e 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -851,10 +851,8 @@ class WS2812FX { // 96 bytes return index; }; - uint32_t - now, - timebase, - getPixelColor(uint16_t) const; + uint32_t now, timebase; + uint32_t getPixelColor(unsigned) const; inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call inline uint32_t segColor(uint8_t i) const { return _colors_t[i]; } // returns currently valid color (for slot i) AKA SEGCOLOR(); may be blended between two colors while in transition diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index ca28a958..41fd6731 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -671,7 +671,7 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, case 60: bits = pgm_read_byte_near(&console_font_5x12[(chr * h) + i]); break; // 5x12 font default: return; } - col = ColorFromPalette(grad, (i+1)*255/h, 255, NOBLEND); + uint32_t col = ColorFromPaletteWLED(grad, (i+1)*255/h, 255, NOBLEND); for (int j = 0; j 1) paletteIndex = (i*255)/(virtualLength() -1); // paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined) if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end" - CRGB fastled_col = ColorFromPalette(_currentPalette, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global + CRGBW palcol = ColorFromPalette(_currentPalette, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global + palcol.w = gamma8(W(color)); - return RGBW32(fastled_col.r, fastled_col.g, fastled_col.b, gamma8(W(color))); + return palcol.color32; } @@ -1419,7 +1420,7 @@ void IRAM_ATTR WS2812FX::setPixelColor(unsigned i, uint32_t col) { BusManager::setPixelColor(i, col); } -uint32_t IRAM_ATTR WS2812FX::getPixelColor(uint16_t i) const { +uint32_t IRAM_ATTR WS2812FX::getPixelColor(unsigned i) const { i = getMappedPixelIndex(i); if (i >= _length) return 0; return BusManager::getPixelColor(i); diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 5b948b9c..404c3344 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -306,7 +306,7 @@ void BusDigital::setStatusPixel(uint32_t c) { } } -void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) { +void IRAM_ATTR BusDigital::setPixelColor(unsigned pix, uint32_t c) { if (!_valid) return; uint8_t cctWW = 0, cctCW = 0; if (hasWhite()) c = autoWhiteCalc(c); @@ -342,7 +342,7 @@ void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) { } // returns original color if global buffering is enabled, else returns lossly restored color from bus -uint32_t IRAM_ATTR BusDigital::getPixelColor(uint16_t pix) const { +uint32_t IRAM_ATTR BusDigital::getPixelColor(unsigned pix) const { if (!_valid) return 0; if (_data) { size_t offset = pix * getNumberOfChannels(); @@ -501,7 +501,7 @@ BusPwm::BusPwm(BusConfig &bc) DEBUG_PRINTF_P(PSTR("%successfully inited PWM strip with type %u, frequency %u, bit depth %u and pins %u,%u,%u,%u,%u\n"), _valid?"S":"Uns", bc.type, _frequency, _depth, _pins[0], _pins[1], _pins[2], _pins[3], _pins[4]); } -void BusPwm::setPixelColor(uint16_t pix, uint32_t c) { +void BusPwm::setPixelColor(unsigned pix, uint32_t c) { if (pix != 0 || !_valid) return; //only react to first pixel if (_type != TYPE_ANALOG_3CH) c = autoWhiteCalc(c); if (Bus::_cct >= 1900 && (_type == TYPE_ANALOG_3CH || _type == TYPE_ANALOG_4CH)) { @@ -538,7 +538,7 @@ void BusPwm::setPixelColor(uint16_t pix, uint32_t c) { } //does no index check -uint32_t BusPwm::getPixelColor(uint16_t pix) const { +uint32_t BusPwm::getPixelColor(unsigned pix) const { if (!_valid) return 0; // TODO getting the reverse from CCT is involved (a quick approximation when CCT blending is ste to 0 implemented) switch (_type) { @@ -674,7 +674,7 @@ BusOnOff::BusOnOff(BusConfig &bc) DEBUG_PRINTF_P(PSTR("%successfully inited On/Off strip with pin %u\n"), _valid?"S":"Uns", _pin); } -void BusOnOff::setPixelColor(uint16_t pix, uint32_t c) { +void BusOnOff::setPixelColor(unsigned pix, uint32_t c) { if (pix != 0 || !_valid) return; //only react to first pixel c = autoWhiteCalc(c); uint8_t r = R(c); @@ -684,7 +684,7 @@ void BusOnOff::setPixelColor(uint16_t pix, uint32_t c) { _data[0] = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0; } -uint32_t BusOnOff::getPixelColor(uint16_t pix) const { +uint32_t BusOnOff::getPixelColor(unsigned pix) const { if (!_valid) return 0; return RGBW32(_data[0], _data[0], _data[0], _data[0]); } @@ -734,7 +734,7 @@ BusNetwork::BusNetwork(BusConfig &bc) DEBUG_PRINTF_P(PSTR("%successfully inited virtual strip with type %u and IP %u.%u.%u.%u\n"), _valid?"S":"Uns", bc.type, bc.pins[0], bc.pins[1], bc.pins[2], bc.pins[3]); } -void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) { +void BusNetwork::setPixelColor(unsigned pix, uint32_t c) { if (!_valid || pix >= _len) return; if (_hasWhite) c = autoWhiteCalc(c); if (Bus::_cct >= 1900) c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT @@ -745,7 +745,7 @@ void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) { if (_hasWhite) _data[offset+3] = W(c); } -uint32_t BusNetwork::getPixelColor(uint16_t pix) const { +uint32_t BusNetwork::getPixelColor(unsigned pix) const { if (!_valid || pix >= _len) return 0; unsigned offset = pix * _UDPchannels; return RGBW32(_data[offset], _data[offset+1], _data[offset+2], (hasWhite() ? _data[offset+3] : 0)); @@ -952,7 +952,7 @@ void BusManager::setStatusPixel(uint32_t c) { } } -void IRAM_ATTR BusManager::setPixelColor(uint16_t pix, uint32_t c) { +void IRAM_ATTR BusManager::setPixelColor(unsigned pix, uint32_t c) { for (unsigned i = 0; i < numBusses; i++) { unsigned bstart = busses[i]->getStart(); if (pix < bstart || pix >= bstart + busses[i]->getLength()) continue; @@ -975,7 +975,7 @@ void BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) { Bus::setCCT(cct); } -uint32_t BusManager::getPixelColor(uint16_t pix) { +uint32_t BusManager::getPixelColor(unsigned pix) { for (unsigned i = 0; i < numBusses; i++) { unsigned bstart = busses[i]->getStart(); if (!busses[i]->containsPixel(pix)) continue; diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index e96b9de7..1b324d71 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -82,10 +82,10 @@ class Bus { virtual void show() = 0; virtual bool canShow() const { return true; } virtual void setStatusPixel(uint32_t c) {} - virtual void setPixelColor(uint16_t pix, uint32_t c) = 0; + virtual void setPixelColor(unsigned pix, uint32_t c) = 0; virtual void setBrightness(uint8_t b) { _bri = b; }; virtual void setColorOrder(uint8_t co) {} - virtual uint32_t getPixelColor(uint16_t pix) const { return 0; } + virtual uint32_t getPixelColor(unsigned pix) const { return 0; } virtual uint8_t getPins(uint8_t* pinArray = nullptr) const { return 0; } virtual uint16_t getLength() const { return isOk() ? _len : 0; } virtual uint8_t getColorOrder() const { return COL_ORDER_RGB; } @@ -203,9 +203,9 @@ class BusDigital : public Bus { bool canShow() const override; void setBrightness(uint8_t b) override; void setStatusPixel(uint32_t c) override; - [[gnu::hot]] void setPixelColor(uint16_t pix, uint32_t c) override; + [[gnu::hot]] void setPixelColor(unsigned pix, uint32_t c) override; void setColorOrder(uint8_t colorOrder) override; - [[gnu::hot]] uint32_t getPixelColor(uint16_t pix) const override; + [[gnu::hot]] uint32_t getPixelColor(unsigned pix) const override; uint8_t getColorOrder() const override { return _colorOrder; } uint8_t getPins(uint8_t* pinArray = nullptr) const override; uint8_t skippedLeds() const override { return _skip; } @@ -251,8 +251,8 @@ class BusPwm : public Bus { BusPwm(BusConfig &bc); ~BusPwm() { cleanup(); } - void setPixelColor(uint16_t pix, uint32_t c) override; - uint32_t getPixelColor(uint16_t pix) const override; //does no index check + void setPixelColor(unsigned pix, uint32_t c) override; + uint32_t getPixelColor(unsigned pix) const override; //does no index check uint8_t getPins(uint8_t* pinArray = nullptr) const override; uint16_t getFrequency() const override { return _frequency; } void show() override; @@ -278,8 +278,8 @@ class BusOnOff : public Bus { BusOnOff(BusConfig &bc); ~BusOnOff() { cleanup(); } - void setPixelColor(uint16_t pix, uint32_t c) override; - uint32_t getPixelColor(uint16_t pix) const override; + void setPixelColor(unsigned pix, uint32_t c) override; + uint32_t getPixelColor(unsigned pix) const override; uint8_t getPins(uint8_t* pinArray) const override; void show() override; void cleanup() { PinManager::deallocatePin(_pin, PinOwner::BusOnOff); } @@ -298,8 +298,8 @@ class BusNetwork : public Bus { ~BusNetwork() { cleanup(); } bool canShow() const override { return !_broadcastLock; } // this should be a return value from UDP routine if it is still sending data out - void setPixelColor(uint16_t pix, uint32_t c) override; - uint32_t getPixelColor(uint16_t pix) const override; + void setPixelColor(unsigned pix, uint32_t c) override; + uint32_t getPixelColor(unsigned pix) const override; uint8_t getPins(uint8_t* pinArray = nullptr) const override; void show() override; void cleanup(); @@ -384,13 +384,13 @@ class BusManager { static void show(); static bool canAllShow(); static void setStatusPixel(uint32_t c); - [[gnu::hot]] static void setPixelColor(uint16_t pix, uint32_t c); + [[gnu::hot]] static void setPixelColor(unsigned pix, uint32_t c); static void setBrightness(uint8_t b); // for setSegmentCCT(), cct can only be in [-1,255] range; allowWBCorrection will convert it to K // WARNING: setSegmentCCT() is a misleading name!!! much better would be setGlobalCCT() or just setCCT() static void setSegmentCCT(int16_t cct, bool allowWBCorrection = false); static inline void setMilliampsMax(uint16_t max) { _milliAmpsMax = max;} - static uint32_t getPixelColor(uint16_t pix); + [[gnu::hot]] static uint32_t getPixelColor(unsigned pix); static inline int16_t getSegmentCCT() { return Bus::getCCT(); } static Bus* getBus(uint8_t busNr); diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 1b6a6f8d..1c484437 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -96,7 +96,7 @@ uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) } // 1:1 replacement of fastled function optimized for ESP, slightly faster, more accurate and uses less flash (~ -200bytes) -CRGB ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brightness, TBlendType blendType) +uint32_t ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brightness, TBlendType blendType) { if (blendType == LINEARBLEND_NOWRAP) { index = (index*240) >> 8; // Blend range is affected by lo4 blend of values, remap to avoid wrapping @@ -121,7 +121,7 @@ CRGB ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brig green1 = (green1 * scale) >> 8; blue1 = (blue1 * scale) >> 8; } - return CRGB((uint8_t)red1, (uint8_t)green1, (uint8_t)blue1); + return RGBW32(red1,green1,blue1,0); } void setRandomColor(byte* rgb) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index ff96cf74..6568304f 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -68,6 +68,64 @@ typedef struct WiFiConfig { //colors.cpp #define ColorFromPalette ColorFromPaletteWLED // override fastled version +// CRGBW can be used to manipulate 32bit colors faster. However: if it is passed to functions, it adds overhead compared to a uint32_t color +// use with caution and pay attention to flash size. Usually converting a uint32_t to CRGBW to extract r, g, b, w values is slower than using bitshifts +// it can be useful to avoid back and forth conversions between uint32_t and fastled CRGB +struct CRGBW { + union { + uint32_t color32; // Access as a 32-bit value (0xWWRRGGBB) + uint8_t raw[4]; // Access as an array in the order B, G, R, W + struct { + uint8_t b; + uint8_t g; + uint8_t r; + uint8_t w; + }; + }; + + // Default constructor + inline CRGBW() __attribute__((always_inline)) = default; + + // Constructor from a 32-bit color (0xWWRRGGBB) + constexpr CRGBW(uint32_t color) __attribute__((always_inline)) : color32(color) {} + + // Constructor with r, g, b, w values + constexpr CRGBW(uint8_t red, uint8_t green, uint8_t blue, uint8_t white = 0) __attribute__((always_inline)) : r(red), g(green), b(blue), w(white) {} + + // Constructor from CRGB + constexpr CRGBW(CRGB rgb) __attribute__((always_inline)) : r(rgb.r), g(rgb.g), b(rgb.b), w(0) {} + + // Access as an array + inline const uint8_t& operator[] (uint8_t x) const __attribute__((always_inline)) { return raw[x]; } + + // Assignment from 32-bit color + inline CRGBW& operator=(uint32_t color) __attribute__((always_inline)) { color32 = color; return *this; } + + // Assignment from r, g, b, w + inline CRGBW& operator=(const CRGB& rgb) __attribute__((always_inline)) { r = rgb.r; g = rgb.g; b = rgb.b; w = 0; return *this; } + + // Conversion operator to uint32_t + inline operator uint32_t() const __attribute__((always_inline)) { + return color32; + } + /* + // Conversion operator to CRGB + inline operator CRGB() const __attribute__((always_inline)) { + return CRGB(r, g, b); + } + + CRGBW& scale32 (uint8_t scaledown) // 32bit math + { + if (color32 == 0) return *this; // 2 extra instructions, worth it if called a lot on black (which probably is true) adding check if scaledown is zero adds much more overhead as its 8bit + uint32_t scale = scaledown + 1; + uint32_t rb = (((color32 & 0x00FF00FF) * scale) >> 8) & 0x00FF00FF; // scale red and blue + uint32_t wg = (((color32 & 0xFF00FF00) >> 8) * scale) & 0xFF00FF00; // scale white and green + color32 = rb | wg; + return *this; + }*/ + +}; + struct CHSV32 { // 32bit HSV color with 16bit hue for more accurate conversions union { struct { @@ -106,7 +164,7 @@ class NeoGammaWLEDMethod { [[gnu::hot]] uint32_t color_blend(uint32_t, uint32_t, uint16_t, bool b16=false); [[gnu::hot]] uint32_t color_add(uint32_t, uint32_t, bool preserveCR = false); [[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); -[[gnu::hot]] CRGB ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND); +[[gnu::hot]] uint32_t ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND); CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette); CRGBPalette16 generateRandomPalette(); inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); } From 202901b09f2a8c6da3a453b0d3ed8c8140ea5557 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 28 Sep 2024 15:38:41 +0200 Subject: [PATCH 039/463] bugfix, ESP32 compiler requires the color order to be identical --- wled00/fcn_declare.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 6568304f..704fae85 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -74,13 +74,13 @@ typedef struct WiFiConfig { struct CRGBW { union { uint32_t color32; // Access as a 32-bit value (0xWWRRGGBB) - uint8_t raw[4]; // Access as an array in the order B, G, R, W struct { uint8_t b; uint8_t g; uint8_t r; uint8_t w; }; + uint8_t raw[4]; // Access as an array in the order B, G, R, W }; // Default constructor @@ -90,10 +90,10 @@ struct CRGBW { constexpr CRGBW(uint32_t color) __attribute__((always_inline)) : color32(color) {} // Constructor with r, g, b, w values - constexpr CRGBW(uint8_t red, uint8_t green, uint8_t blue, uint8_t white = 0) __attribute__((always_inline)) : r(red), g(green), b(blue), w(white) {} + constexpr CRGBW(uint8_t red, uint8_t green, uint8_t blue, uint8_t white = 0) __attribute__((always_inline)) : b(blue), g(green), r(red), w(white) {} // Constructor from CRGB - constexpr CRGBW(CRGB rgb) __attribute__((always_inline)) : r(rgb.r), g(rgb.g), b(rgb.b), w(0) {} + constexpr CRGBW(CRGB rgb) __attribute__((always_inline)) : b(rgb.b), g(rgb.g), r(rgb.r), w(0) {} // Access as an array inline const uint8_t& operator[] (uint8_t x) const __attribute__((always_inline)) { return raw[x]; } @@ -102,7 +102,7 @@ struct CRGBW { inline CRGBW& operator=(uint32_t color) __attribute__((always_inline)) { color32 = color; return *this; } // Assignment from r, g, b, w - inline CRGBW& operator=(const CRGB& rgb) __attribute__((always_inline)) { r = rgb.r; g = rgb.g; b = rgb.b; w = 0; return *this; } + inline CRGBW& operator=(const CRGB& rgb) __attribute__((always_inline)) { b = rgb.b; g = rgb.g; r = rgb.r; w = 0; return *this; } // Conversion operator to uint32_t inline operator uint32_t() const __attribute__((always_inline)) { From c842994df5d5e9120c069c84cba97ba8c686ab0d Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sat, 28 Sep 2024 18:14:43 +0200 Subject: [PATCH 040/463] Pre-calculate virtual - move SEGCOLOR() to Segment class - add SEG_H, SEG_W macros - try to speed up virtualXxxxx() - compile warning fixes --- wled00/FX.cpp | 347 ++++++++++++++++++++++---------------------- wled00/FX.h | 64 ++++---- wled00/FX_2Dfcn.cpp | 146 ++++++++++--------- wled00/FX_fcn.cpp | 123 +++++++++------- wled00/udp.cpp | 54 +++---- wled00/xml.cpp | 4 +- 6 files changed, 367 insertions(+), 371 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 3df91547..2ec31014 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -118,7 +118,7 @@ uint16_t blink(uint32_t color1, uint32_t color2, bool strobe, bool do_palette) { uint32_t color = on ? color1 : color2; if (color == color1 && do_palette) { - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); } } else SEGMENT.fill(color); @@ -300,25 +300,25 @@ uint16_t mode_dynamic(void) { if(SEGENV.call == 0) { //SEGMENT.fill(BLACK); - for (int i = 0; i < SEGLEN; i++) SEGENV.data[i] = random8(); + for (unsigned i = 0; i < SEGLEN; i++) SEGENV.data[i] = random8(); } uint32_t cycleTime = 50 + (255 - SEGMENT.speed)*15; uint32_t it = strip.now / cycleTime; if (it != SEGENV.step && SEGMENT.speed != 0) //new color { - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { if (random8() <= SEGMENT.intensity) SEGENV.data[i] = random8(); // random color index } SEGENV.step = it; } if (SEGMENT.check1) { - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.blendPixelColor(i, SEGMENT.color_wheel(SEGENV.data[i]), 16); } } else { - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_wheel(SEGENV.data[i])); } } @@ -353,7 +353,7 @@ uint16_t mode_breath(void) { } unsigned lum = 30 + var; - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), lum)); } @@ -369,7 +369,7 @@ uint16_t mode_fade(void) { unsigned counter = (strip.now * ((SEGMENT.speed >> 3) +10)); unsigned lum = triwave16(counter) >> 8; - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), lum)); } @@ -452,7 +452,7 @@ uint16_t mode_rainbow_cycle(void) { unsigned counter = (strip.now * ((SEGMENT.speed >> 2) +2)) & 0xFFFF; counter = counter >> 8; - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { //intensity/29 = 0 (1/16) 1 (1/8) 2 (1/4) 3 (1/2) 4 (1) 5 (2) 6 (4) 7 (8) 8 (16) uint8_t index = (i * (16 << (SEGMENT.intensity /29)) / SEGLEN) + counter; SEGMENT.setPixelColor(i, SEGMENT.color_wheel(index)); @@ -472,7 +472,7 @@ static uint16_t running(uint32_t color1, uint32_t color2, bool theatre = false) uint32_t it = strip.now / cycleTime; bool usePalette = color1 == SEGCOLOR(0); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { uint32_t col = color2; if (usePalette) color1 = SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0); if (theatre) { @@ -519,7 +519,7 @@ static uint16_t running_base(bool saw, bool dual=false) { unsigned x_scale = SEGMENT.intensity >> 2; uint32_t counter = (strip.now * SEGMENT.speed) >> 9; - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { unsigned a = i*x_scale - counter; if (saw) { a &= 0xFF; @@ -622,7 +622,7 @@ uint16_t dissolve(uint32_t color) { SEGENV.aux0 = 1; } - for (int j = 0; j <= SEGLEN / 15; j++) { + for (unsigned j = 0; j <= SEGLEN / 15; j++) { if (random8() <= SEGMENT.intensity) { for (size_t times = 0; times < 10; times++) { //attempt to spawn a new pixel 10 times unsigned i = random16(SEGLEN); @@ -684,7 +684,7 @@ static const char _data_FX_MODE_DISSOLVE_RANDOM[] PROGMEM = "Dissolve Rnd@Repeat * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ */ uint16_t mode_sparkle(void) { - if (!SEGMENT.check2) for(int i = 0; i < SEGLEN; i++) { + if (!SEGMENT.check2) for(unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); } uint32_t cycleTime = 10 + (255 - SEGMENT.speed)*2; @@ -706,7 +706,7 @@ static const char _data_FX_MODE_SPARKLE[] PROGMEM = "Sparkle@!,,,,,,Overlay;!,!; * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ */ uint16_t mode_flash_sparkle(void) { - if (!SEGMENT.check2) for (int i = 0; i < SEGLEN; i++) { + if (!SEGMENT.check2) for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); } @@ -727,13 +727,14 @@ static const char _data_FX_MODE_FLASH_SPARKLE[] PROGMEM = "Sparkle Dark@!,!,,,,, * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ */ uint16_t mode_hyper_sparkle(void) { - if (!SEGMENT.check2) for (int i = 0; i < SEGLEN; i++) { + if (!SEGMENT.check2) for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); } if (strip.now - SEGENV.aux0 > SEGENV.step) { if (random8((255-SEGMENT.intensity) >> 4) == 0) { - for (int i = 0; i < max(1, SEGLEN/3); i++) { + int len = max(1, (int)SEGLEN/3); + for (int i = 0; i < len; i++) { SEGMENT.setPixelColor(random16(SEGLEN), SEGCOLOR(1)); } } @@ -749,7 +750,7 @@ static const char _data_FX_MODE_HYPER_SPARKLE[] PROGMEM = "Sparkle+@!,!,,,,,Over * Strobe effect with different strobe count and pause, controlled by speed. */ uint16_t mode_multi_strobe(void) { - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); } @@ -780,7 +781,7 @@ static const char _data_FX_MODE_MULTI_STROBE[] PROGMEM = "Strobe Mega@!,!;!,!;!; */ uint16_t mode_android(void) { - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); } @@ -995,10 +996,10 @@ static const char _data_FX_MODE_COLORFUL[] PROGMEM = "Colorful@!,Saturation;1,2, */ uint16_t mode_traffic_light(void) { if (SEGLEN == 1) return mode_static(); - for (int i=0; i < SEGLEN; i++) + for (unsigned i=0; i < SEGLEN; i++) SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); uint32_t mdelay = 500; - for (int i = 0; i < SEGLEN-2 ; i+=3) + for (unsigned i = 0; i < SEGLEN-2 ; i+=3) { switch (SEGENV.aux0) { @@ -1030,7 +1031,7 @@ uint16_t mode_chase_flash(void) { if (SEGLEN == 1) return mode_static(); unsigned flash_step = SEGENV.call % ((FLASH_COUNT * 2) + 1); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); } @@ -1226,8 +1227,8 @@ static const char _data_FX_MODE_COMET[] PROGMEM = "Lighthouse@!,Fade rate;!,!;!" */ uint16_t mode_fireworks() { if (SEGLEN == 1) return mode_static(); - const uint16_t width = SEGMENT.is2D() ? SEGMENT.virtualWidth() : SEGMENT.virtualLength(); - const uint16_t height = SEGMENT.virtualHeight(); + const uint16_t width = SEGMENT.is2D() ? SEG_W : SEGLEN; + const uint16_t height = SEG_H; if (SEGENV.call == 0) { SEGENV.aux0 = UINT16_MAX; @@ -1268,8 +1269,8 @@ static const char _data_FX_MODE_FIREWORKS[] PROGMEM = "Fireworks@,Frequency;!,!; //Twinkling LEDs running. Inspired by https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/Rain.h uint16_t mode_rain() { if (SEGLEN == 1) return mode_static(); - const unsigned width = SEGMENT.virtualWidth(); - const unsigned height = SEGMENT.virtualHeight(); + const unsigned width = SEG_W; + const unsigned height = SEG_H; SEGENV.step += FRAMETIME; if (SEGENV.call && SEGENV.step > SPEED_FORMULA_L) { SEGENV.step = 1; @@ -1283,7 +1284,7 @@ uint16_t mode_rain() { } else { //shift all leds left uint32_t ctemp = SEGMENT.getPixelColor(0); - for (int i = 0; i < SEGLEN - 1; i++) { + for (unsigned i = 0; i < SEGLEN - 1; i++) { SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); } SEGMENT.setPixelColor(SEGLEN -1, ctemp); // wrap around @@ -1314,7 +1315,7 @@ uint16_t mode_fire_flicker(void) { byte b = (SEGCOLOR(0) ); byte lum = (SEGMENT.palette == 0) ? MAX(w, MAX(r, MAX(g, b))) : 255; lum /= (((256-SEGMENT.intensity)/16)+1); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { byte flicker = random8(lum); if (SEGMENT.palette == 0) { SEGMENT.setPixelColor(i, MAX(r - flicker, 0), MAX(g - flicker, 0), MAX(b - flicker, 0), MAX(w - flicker, 0)); @@ -1343,7 +1344,7 @@ uint16_t gradient_base(bool loading) { int p1 = pp-SEGLEN; int p2 = pp+SEGLEN; - for (int i = 0; i < SEGLEN; i++) { + for (int i = 0; i < (int)SEGLEN; i++) { if (loading) { val = abs(((i>pp) ? p2:pp) - i); } else { @@ -1428,7 +1429,7 @@ typedef struct Flasher { uint16_t mode_fairy() { //set every pixel to a 'random' color from palette (using seed so it doesn't change between frames) uint16_t PRNG16 = 5100 + strip.getCurrSegmentId(); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; //next 'random' number SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(PRNG16 >> 8, false, false, 0)); } @@ -1513,7 +1514,7 @@ uint16_t mode_fairytwinkle() { unsigned riseFallTime = 400 + (255-SEGMENT.speed)*3; unsigned maxDur = riseFallTime/100 + ((255 - SEGMENT.intensity) >> 2) + 13 + ((255 - SEGMENT.intensity) >> 1); - for (int f = 0; f < SEGLEN; f++) { + for (unsigned f = 0; f < SEGLEN; f++) { unsigned stateTime = now16 - flashers[f].stateStart; //random on/off time reached, switch state if (stateTime > flashers[f].stateDur * 100) { @@ -1558,7 +1559,7 @@ uint16_t tricolor_chase(uint32_t color1, uint32_t color2) { unsigned width = (1 + (SEGMENT.intensity>>4)); // value of 1-16 for each colour unsigned index = it % (width*3); - for (int i = 0; i < SEGLEN; i++, index++) { + for (unsigned i = 0; i < SEGLEN; i++, index++) { if (index > (width*3)-1) index = 0; uint32_t color = color1; @@ -1631,7 +1632,7 @@ uint16_t mode_tricolor_wipe(void) { unsigned ledIndex = (prog * SEGLEN * 3) >> 16; unsigned ledOffset = ledIndex; - for (int i = 0; i < SEGLEN; i++) + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 2)); } @@ -1970,8 +1971,8 @@ uint16_t mode_palette() { constexpr float (*cosFunction)(float) = &cos_t; #endif const bool isMatrix = strip.isMatrix; - const int cols = SEGMENT.virtualWidth(); - const int rows = isMatrix ? SEGMENT.virtualHeight() : strip.getActiveSegmentsNum(); + const int cols = SEG_W; + const int rows = isMatrix ? SEG_H : strip.getActiveSegmentsNum(); const int inputShift = SEGMENT.speed; const int inputSize = SEGMENT.intensity; @@ -2084,10 +2085,10 @@ uint16_t mode_fire_2012() { struct virtualStrip { static void runStrip(uint16_t stripNr, byte* heat, uint32_t it) { - const uint8_t ignition = max(3,SEGLEN/10); // ignition area: 10% of segment length or minimum 3 pixels + const uint8_t ignition = MAX(3,SEGLEN/10); // ignition area: 10% of segment length or minimum 3 pixels // Step 1. Cool down every cell a little - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { uint8_t cool = (it != SEGENV.step) ? random8((((20 + SEGMENT.speed/3) * 16) / SEGLEN)+2) : random8(4); uint8_t minTemp = (i> 8; unsigned h16_128 = hue16 >> 7; @@ -2183,7 +2184,7 @@ static const char _data_FX_MODE_COLORWAVES[] PROGMEM = "Colorwaves@!,Hue;!;!"; uint16_t mode_bpm() { uint32_t stp = (strip.now / 20) & 0xFF; uint8_t beat = beatsin8(SEGMENT.speed, 64, 255); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(stp + (i * 2), false, PALETTE_SOLID_WRAP, 0, beat - stp + (i * 10))); } @@ -2194,7 +2195,7 @@ static const char _data_FX_MODE_BPM[] PROGMEM = "Bpm@!;!;!;;sx=64"; uint16_t mode_fillnoise8() { if (SEGENV.call == 0) SEGENV.step = random16(12345); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { unsigned index = inoise8(i * SEGLEN, SEGENV.step + i * SEGLEN); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); } @@ -2209,7 +2210,7 @@ uint16_t mode_noise16_1() { unsigned scale = 320; // the "zoom factor" for the noise SEGENV.step += (1 + SEGMENT.speed/16); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { unsigned shift_x = beatsin8(11); // the x position of the noise field swings @ 17 bpm unsigned shift_y = SEGENV.step/42; // the y position becomes slowly incremented unsigned real_x = (i + shift_x) * scale; // the x position of the noise field swings @ 17 bpm @@ -2230,7 +2231,7 @@ uint16_t mode_noise16_2() { unsigned scale = 1000; // the "zoom factor" for the noise SEGENV.step += (1 + (SEGMENT.speed >> 1)); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { unsigned shift_x = SEGENV.step >> 6; // x as a function of time uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field unsigned noise = inoise16(real_x, 0, 4223) >> 8; // get the noise data and scale it down @@ -2248,7 +2249,7 @@ uint16_t mode_noise16_3() { unsigned scale = 800; // the "zoom factor" for the noise SEGENV.step += (1 + SEGMENT.speed); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { unsigned shift_x = 4223; // no movement along x and y unsigned shift_y = 1234; uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field @@ -2268,7 +2269,7 @@ static const char _data_FX_MODE_NOISE16_3[] PROGMEM = "Noise 3@!;!;!"; //https://github.com/aykevl/ledstrip-spark/blob/master/ledstrip.ino uint16_t mode_noise16_4() { uint32_t stp = (strip.now * SEGMENT.speed) >> 7; - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { int index = inoise16(uint32_t(i) << 12, stp); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); } @@ -2285,7 +2286,7 @@ uint16_t mode_colortwinkle() { CRGBW col, prev; fract8 fadeUpAmount = strip.getBrightness()>28 ? 8 + (SEGMENT.speed>>2) : 68-strip.getBrightness(); fract8 fadeDownAmount = strip.getBrightness()>28 ? 8 + (SEGMENT.speed>>3) : 68-strip.getBrightness(); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { CRGBW cur = SEGMENT.getPixelColor(i); prev = cur; unsigned index = i >> 3; @@ -2338,7 +2339,7 @@ uint16_t mode_lake() { int wave2 = beatsin8(sp +1, -64,64); int wave3 = beatsin8(sp +2, 0,80); - for (int i = 0; i < SEGLEN; i++) + for (unsigned i = 0; i < SEGLEN; i++) { int index = cos8((i*15)+ wave1)/2 + cubicwave8((i*23)+ wave2)/2; uint8_t lum = (index > wave3) ? index - wave3 : 0; @@ -2365,7 +2366,7 @@ uint16_t mode_meteor() { const int max = SEGMENT.palette==5 ? 239 : 255; // "* Colors only" palette blends end with start // fade all leds to colors[1] in LEDs one step - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { if (random8() <= 255 - SEGMENT.intensity) { int meteorTrailDecay = 128 + random8(127); trail[i] = scale8(trail[i], meteorTrailDecay); @@ -2454,7 +2455,7 @@ uint16_t mode_railway() { if (p0 < 255) pos = p0; } if (SEGENV.aux0) pos = 255 - pos; - for (int i = 0; i < SEGLEN; i += 2) + for (unsigned i = 0; i < SEGLEN; i += 2) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(255 - pos, false, false, 255)); // do not use color 1 or 2, always use palette if (i < SEGLEN -1) @@ -2485,7 +2486,7 @@ typedef struct Ripple { #define MAX_RIPPLES 100 #endif static uint16_t ripple_base() { - unsigned maxRipples = min(1 + (SEGLEN >> 2), MAX_RIPPLES); // 56 max for 16 segment ESP8266 + unsigned maxRipples = min(1 + (int)(SEGLEN >> 2), MAX_RIPPLES); // 56 max for 16 segment ESP8266 unsigned dataSize = sizeof(ripple) * maxRipples; if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed @@ -2655,7 +2656,7 @@ static uint16_t twinklefox_base(bool cat) unsigned backgroundBrightness = bg.getAverageLight(); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number unsigned myclockoffset16= PRNG16; // use that number as clock offset @@ -2727,8 +2728,8 @@ uint16_t mode_halloween_eyes() }; if (SEGLEN == 1) return mode_static(); - const unsigned maxWidth = strip.isMatrix ? SEGMENT.virtualWidth() : SEGLEN; - const unsigned HALLOWEEN_EYE_SPACE = MAX(2, strip.isMatrix ? SEGMENT.virtualWidth()>>4: SEGLEN>>5); + const unsigned maxWidth = strip.isMatrix ? SEG_W : SEGLEN; + const unsigned HALLOWEEN_EYE_SPACE = MAX(2, strip.isMatrix ? SEG_W>>4: SEGLEN>>5); const unsigned HALLOWEEN_EYE_WIDTH = HALLOWEEN_EYE_SPACE/2; unsigned eyeLength = (2*HALLOWEEN_EYE_WIDTH) + HALLOWEEN_EYE_SPACE; if (eyeLength >= maxWidth) return mode_static(); //bail if segment too short @@ -2751,7 +2752,7 @@ uint16_t mode_halloween_eyes() data.startPos = random16(0, maxWidth - eyeLength - 1); data.color = random8(); - if (strip.isMatrix) SEGMENT.offset = random16(SEGMENT.virtualHeight()-1); // a hack: reuse offset since it is not used in matrices + if (strip.isMatrix) SEGMENT.offset = random16(SEG_H-1); // a hack: reuse offset since it is not used in matrices duration = 128u + random16(SEGMENT.intensity*64u); data.duration = duration; data.state = eyeState::on; @@ -2869,7 +2870,7 @@ uint16_t mode_static_pattern() bool drawingLit = true; unsigned cnt = 0; - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, (drawingLit) ? SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0) : SEGCOLOR(1)); cnt++; if (cnt >= ((drawingLit) ? lit : unlit)) { @@ -2889,7 +2890,7 @@ uint16_t mode_tri_static_pattern() unsigned currSeg = 0; unsigned currSegCount = 0; - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { if ( currSeg % 3 == 0 ) { SEGMENT.setPixelColor(i, SEGCOLOR(0)); } else if( currSeg % 3 == 1) { @@ -3319,7 +3320,7 @@ uint16_t candle(bool multi) { if (multi && SEGLEN > 1) { //allocate segment data - unsigned dataSize = max(1, SEGLEN -1) *3; //max. 1365 pixels (ESP8266) + unsigned dataSize = max(1, (int)SEGLEN -1) *3; //max. 1365 pixels (ESP8266) if (!SEGENV.allocateData(dataSize)) return candle(false); //allocation failed } @@ -3378,7 +3379,7 @@ uint16_t candle(bool multi) SEGENV.data[d] = s; SEGENV.data[d+1] = s_target; SEGENV.data[d+2] = fadeStep; } else { - for (int j = 0; j < SEGLEN; j++) { + for (unsigned j = 0; j < SEGLEN; j++) { SEGMENT.setPixelColor(j, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(j, true, PALETTE_SOLID_WRAP, 0), s)); } @@ -3521,12 +3522,12 @@ uint16_t mode_starburst(void) { if (stars[j].fragment[i] > 0) { float loc = stars[j].fragment[i]; if (mirrored) loc -= (loc-stars[j].pos)*2; - int start = loc - particleSize; - int end = loc + particleSize; + unsigned start = loc - particleSize; + unsigned end = loc + particleSize; if (start < 0) start = 0; if (start == end) end++; if (end > SEGLEN) end = SEGLEN; - for (int p = start; p < end; p++) { + for (unsigned p = start; p < end; p++) { SEGMENT.setPixelColor(p, c); } } @@ -3546,8 +3547,8 @@ static const char _data_FX_MODE_STARBURST[] PROGMEM = "Fireworks Starburst@Chanc uint16_t mode_exploding_fireworks(void) { if (SEGLEN == 1) return mode_static(); - const int cols = SEGMENT.is2D() ? SEGMENT.virtualWidth() : 1; - const int rows = SEGMENT.is2D() ? SEGMENT.virtualHeight() : SEGMENT.virtualLength(); + const int cols = SEGMENT.is2D() ? SEG_W : 1; + const int rows = SEGMENT.is2D() ? SEG_H : SEGLEN; //allocate segment data unsigned maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640 @@ -3698,7 +3699,7 @@ uint16_t mode_drip(void) unsigned numDrops = 1 + (SEGMENT.intensity >> 6); // 255>>6 = 3 float gravity = -0.0005f - (SEGMENT.speed/50000.0f); - gravity *= max(1, SEGLEN-1); + gravity *= max(1, (int)SEGLEN-1); int sourcedrop = 12; for (unsigned j=0;j= SEGLEN occasionally + unsigned pos = constrain(unsigned(drops[j].pos) +i, 0, SEGLEN-1); //this is BAD, returns a pos >= SEGLEN occasionally SEGMENT.setPixelColor(indexToVStrip(pos, stripNr), color_blend(BLACK,SEGCOLOR(0),drops[j].col/i)); //spread pixel with fade while falling } @@ -3821,8 +3822,8 @@ uint16_t mode_tetrix(void) { if (drop->pos > drop->stack) { // fall until top of stack drop->pos -= drop->speed; // may add gravity as: speed += gravity if (int(drop->pos) < int(drop->stack)) drop->pos = drop->stack; - for (int i = int(drop->pos); i < SEGLEN; i++) { - uint32_t col = ipos)+drop->brick ? SEGMENT.color_from_palette(drop->col, false, false, 0) : SEGCOLOR(1); + for (unsigned i = unsigned(drop->pos); i < SEGLEN; i++) { + uint32_t col = i < unsigned(drop->pos)+drop->brick ? SEGMENT.color_from_palette(drop->col, false, false, 0) : SEGCOLOR(1); SEGMENT.setPixelColor(indexToVStrip(i, stripNr), col); } } else { // we hit bottom @@ -3836,7 +3837,7 @@ uint16_t mode_tetrix(void) { drop->brick = 0; // reset brick size (no more growing) if (drop->step > strip.now) { // allow fading of virtual strip - for (int i = 0; i < SEGLEN; i++) SEGMENT.blendPixelColor(indexToVStrip(i, stripNr), SEGCOLOR(1), 25); // 10% blend + for (unsigned i = 0; i < SEGLEN; i++) SEGMENT.blendPixelColor(indexToVStrip(i, stripNr), SEGCOLOR(1), 25); // 10% blend } else { drop->stack = 0; // reset brick stack size drop->step = 0; // proceed with next brick @@ -3893,7 +3894,7 @@ uint16_t mode_percent(void) { if (SEGMENT.speed == 255) size = 255; if (percent <= 100) { - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { if (i < SEGENV.aux1) { if (SEGMENT.check1) SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(map(percent,0,100,0,255), false, false, 0)); @@ -3905,7 +3906,7 @@ uint16_t mode_percent(void) { } } } else { - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { if (i < (SEGLEN - SEGENV.aux1)) { SEGMENT.setPixelColor(i, SEGCOLOR(1)); } @@ -3955,7 +3956,7 @@ uint16_t mode_heartbeat(void) { SEGENV.step = strip.now; } - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, color_blend(SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), SEGCOLOR(1), 255 - (SEGENV.aux1 >> 8))); } @@ -4049,7 +4050,7 @@ uint16_t mode_pacifica() unsigned basethreshold = beatsin8( 9, 55, 65); unsigned wave = beat8( 7 ); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { CRGB c = CRGB(2, 6, 10); // Render each of four layers, with different scales and speeds, that vary over time c += pacifica_one_layer(i, pacifica_palette_1, sCIStart1, beatsin16(3, 11 * 256, 14 * 256), beatsin8(10, 70, 130), 0-beat16(301)); @@ -4112,7 +4113,7 @@ uint16_t mode_sunrise() { if (SEGMENT.speed > 60) stage = 0xFFFF - stage; //sunset } - for (int i = 0; i <= SEGLEN/2; i++) + for (unsigned i = 0; i <= SEGLEN/2; i++) { //default palette is Fire unsigned wave = triwave16((i * stage) / SEGLEN); @@ -4145,7 +4146,7 @@ static uint16_t phased_base(uint8_t moder) { // We're making si unsigned index = strip.now/64; // Set color rotation speed *phase += SEGMENT.speed/32.0; // You can change the speed of the wave. AKA SPEED (was .4) - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { if (moder == 1) modVal = (inoise8(i*10 + i*10) /16); // Let's randomize our mod length with some Perlin noise. unsigned val = (i+1) * allfreq; // This sets the frequency of the waves. The +1 makes sure that led 0 is used. if (modVal == 0) modVal = 1; @@ -4177,7 +4178,7 @@ uint16_t mode_twinkleup(void) { // A very short twinkle routine unsigned prevSeed = random16_get_seed(); // save seed so we can restore it at the end of the function random16_set_seed(535); // The randomizer needs to be re-set each time through the loop in order for the same 'random' numbers to be the same each time through. - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { unsigned ranstart = random8(); // The starting value (aka brightness) for each pixel. Must be consistent each time through the loop for this to work. unsigned pixBri = sin8(ranstart + 16 * strip.now/(256-SEGMENT.speed)); if (random8() > SEGMENT.intensity) pixBri = 0; @@ -4214,7 +4215,7 @@ uint16_t mode_noisepal(void) { // Slow noise if (SEGMENT.palette > 0) palettes[0] = SEGPALETTE; - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { unsigned index = inoise8(i*scale, SEGENV.aux0+i*scale); // Get a value from the noise function. I'm using both x and y axis. SEGMENT.setPixelColor(i, ColorFromPalette(palettes[0], index, 255, LINEARBLEND)); // Use my own palette. } @@ -4237,7 +4238,7 @@ uint16_t mode_sinewave(void) { // Adjustable sinewave. By Andrew Tul SEGENV.step += SEGMENT.speed/16; // Speed of animation. unsigned freq = SEGMENT.intensity/4;//SEGMENT.fft2/8; // Frequency of the signal. - for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows: + for (unsigned i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows: int pixBri = cubicwave8((i*freq)+SEGENV.step);//qsuba(cubicwave8((i*freq)+SEGENV.step), (255-SEGMENT.intensity)); // qsub sets a minimum value called thiscutoff. If < thiscutoff, then bright = 0. Otherwise, bright = 128 (as defined in qsub).. //setPixCol(i, i*colorIndex/255, pixBri); SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i*colorIndex/255, false, PALETTE_SOLID_WRAP, 0), pixBri)); @@ -4368,7 +4369,7 @@ uint16_t mode_dancing_shadows(void) spotlights[i].lastUpdateTime = time; } - respawn = (spotlights[i].speed > 0.0 && spotlights[i].position > (SEGLEN + 2)) + respawn = (spotlights[i].speed > 0.0 && spotlights[i].position > (int)(SEGLEN + 2)) || (spotlights[i].speed < 0.0 && spotlights[i].position < -(spotlights[i].width + 2)); } @@ -4398,7 +4399,7 @@ uint16_t mode_dancing_shadows(void) int start = spotlights[i].position; if (spotlights[i].width <= 1) { - if (start >= 0 && start < SEGLEN) { + if (start >= 0 && start < (int)SEGLEN) { SEGMENT.blendPixelColor(start, color, 128); } } else { @@ -4468,7 +4469,7 @@ uint16_t mode_washing_machine(void) { SEGENV.step += (speed * 2048) / (512 - SEGMENT.speed); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { uint8_t col = sin8(((SEGMENT.intensity / 25 + 1) * 255 * i / SEGLEN) + (SEGENV.step >> 7)); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(col, false, PALETTE_SOLID_WRAP, 3)); } @@ -4618,7 +4619,7 @@ uint16_t mode_tv_simulator(void) { } // set strip color - for (i = 0; i < SEGLEN; i++) { + for (i = 0; i < (int)SEGLEN; i++) { SEGMENT.setPixelColor(i, r >> 8, g >> 8, b >> 8); // Quantize to 8-bit } @@ -4777,7 +4778,7 @@ uint16_t mode_aurora(void) { if (SEGCOLOR(1)) backlight++; if (SEGCOLOR(2)) backlight++; //Loop through LEDs to determine color - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { CRGB mixedRgb = CRGB(backlight, backlight, backlight); //For each LED we must check each wave if it is "active" at this position. @@ -4824,7 +4825,7 @@ static const char _data_FX_MODE_PERLINMOVE[] PROGMEM = "Perlin Move@!,# of pixel // Uses beatsin8() + phase shifting. By: Andrew Tuline uint16_t mode_wavesins(void) { - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { uint8_t bri = sin8(strip.now/4 + i * SEGMENT.intensity); uint8_t index = beatsin8(SEGMENT.speed, SEGMENT.custom1, SEGMENT.custom1+SEGMENT.custom2, 0, i * (SEGMENT.custom3<<3)); // custom3 is reduced resolution slider //SEGMENT.setPixelColor(i, ColorFromPalette(SEGPALETTE, index, bri, LINEARBLEND)); @@ -4846,8 +4847,8 @@ uint16_t mode_FlowStripe(void) { uint8_t hue = strip.now / (SEGMENT.speed+1); uint32_t t = strip.now / (SEGMENT.intensity/8+1); - for (int i = 0; i < SEGLEN; i++) { - int c = (abs(i - hl) / hl) * 127; + for (unsigned i = 0; i < SEGLEN; i++) { + int c = (abs((int)i - hl) / hl) * 127; c = sin8(c); c = sin8(c / 2 + t); byte b = sin8(c + t/8); @@ -4869,8 +4870,8 @@ static const char _data_FX_MODE_FLOWSTRIPE[] PROGMEM = "Flow Stripe@Hue speed,Ef uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulmatelights.com/gallery/1012 , Modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; int x, y; SEGMENT.fadeToBlackBy(16 + (SEGMENT.speed>>3)); // create fading trails @@ -4903,8 +4904,8 @@ static const char _data_FX_MODE_2DBLACKHOLE[] PROGMEM = "Black Hole@Fade rate,Ou uint16_t mode_2DColoredBursts() { // By: ldirko https://editor.soulmatelights.com/gallery/819-colored-bursts , modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; if (SEGENV.call == 0) { SEGENV.aux0 = 0; // start with red hue @@ -4955,8 +4956,8 @@ static const char _data_FX_MODE_2DCOLOREDBURSTS[] PROGMEM = "Colored Bursts@Spee uint16_t mode_2Ddna(void) { // dna originally by by ldirko at https://pastebin.com/pCkkkzcs. Updated by Preyy. WLED conversion by Andrew Tuline. if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; SEGMENT.fadeToBlackBy(64); for (int i = 0; i < cols; i++) { @@ -4976,8 +4977,8 @@ static const char _data_FX_MODE_2DDNA[] PROGMEM = "DNA@Scroll speed,Blur;;!;2"; uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulmatelights.com/gallery/512-dna-spiral-variation , modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; if (SEGENV.call == 0) { SEGMENT.fill(BLACK); @@ -5021,8 +5022,8 @@ static const char _data_FX_MODE_2DDNASPIRAL[] PROGMEM = "DNA Spiral@Scroll speed uint16_t mode_2DDrift() { // By: Stepko https://editor.soulmatelights.com/gallery/884-drift , Modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; const int colsCenter = (cols>>1) + (cols%2); const int rowsCenter = (rows>>1) + (rows%2); @@ -5051,8 +5052,8 @@ static const char _data_FX_MODE_2DDRIFT[] PROGMEM = "Drift@Rotation speed,Blur a uint16_t mode_2Dfirenoise(void) { // firenoise2d. By Andrew Tuline. Yet another short routine. if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; if (SEGENV.call == 0) { SEGMENT.fill(BLACK); @@ -5085,8 +5086,8 @@ static const char _data_FX_MODE_2DFIRENOISE[] PROGMEM = "Firenoise@X scale,Y sca uint16_t mode_2DFrizzles(void) { // By: Stepko https://editor.soulmatelights.com/gallery/640-color-frizzles , Modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; SEGMENT.fadeToBlackBy(16); for (size_t i = 8; i > 0; i--) { @@ -5112,8 +5113,8 @@ typedef struct ColorCount { uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https://natureofcode.com/book/chapter-7-cellular-automata/ and https://github.com/DougHaber/nlife-color if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; const unsigned dataSize = sizeof(CRGB) * SEGMENT.length(); // using width*height prevents reallocation if mirroring is enabled const int crcBufferLen = 2; //(SEGMENT.width() + SEGMENT.height())*71/100; // roughly sqrt(2)/2 for better repetition detection (Ewowi) @@ -5218,8 +5219,8 @@ static const char _data_FX_MODE_2DGAMEOFLIFE[] PROGMEM = "Game Of Life@!;!,!;!;2 uint16_t mode_2DHiphotic() { // By: ldirko https://editor.soulmatelights.com/gallery/810 , Modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; const uint32_t a = strip.now / ((SEGMENT.custom3>>1)+1); for (int x = 0; x < cols; x++) { @@ -5250,8 +5251,8 @@ typedef struct Julia { uint16_t mode_2DJulia(void) { // An animated Julia set by Andrew Tuline. if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; if (!SEGENV.allocateData(sizeof(julia))) return mode_static(); Julia* julias = reinterpret_cast(SEGENV.data); @@ -5356,8 +5357,8 @@ static const char _data_FX_MODE_2DJULIA[] PROGMEM = "Julia@,Max iterations per p uint16_t mode_2DLissajous(void) { // By: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; SEGMENT.fadeToBlackBy(SEGMENT.intensity); uint_fast16_t phase = (strip.now * (1 + SEGENV.custom3)) /32; // allow user to control rotation speed @@ -5384,8 +5385,8 @@ static const char _data_FX_MODE_2DLISSAJOUS[] PROGMEM = "Lissajous@X frequency,F uint16_t mode_2Dmatrix(void) { // Matrix2D. By Jeremy Williams. Adapted by Andrew Tuline & improved by merkisoft and ewowi, and softhack007. if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; unsigned dataSize = (SEGMENT.length()+7) >> 3; //1 bit per LED for trails if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed @@ -5454,8 +5455,8 @@ static const char _data_FX_MODE_2DMATRIX[] PROGMEM = "Matrix@!,Spawning rate,Tra uint16_t mode_2Dmetaballs(void) { // Metaballs by Stefan Petrick. Cannot have one of the dimensions be 2 or less. Adapted by Andrew Tuline. if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; float speed = 0.25f * (1+(SEGMENT.speed>>6)); @@ -5513,8 +5514,8 @@ static const char _data_FX_MODE_2DMETABALLS[] PROGMEM = "Metaballs@!;;!;2"; uint16_t mode_2Dnoise(void) { // By Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; const unsigned scale = SEGMENT.intensity+2; @@ -5536,8 +5537,8 @@ static const char _data_FX_MODE_2DNOISE[] PROGMEM = "Noise2D@!,Scale;;!;2"; uint16_t mode_2DPlasmaball(void) { // By: Stepko https://editor.soulmatelights.com/gallery/659-plasm-ball , Modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; SEGMENT.fadeToBlackBy(SEGMENT.custom1>>2); uint_fast32_t t = (strip.now * 8) / (256 - SEGMENT.speed); // optimized to avoid float @@ -5576,8 +5577,8 @@ static const char _data_FX_MODE_2DPLASMABALL[] PROGMEM = "Plasma Ball@Speed,,Fad uint16_t mode_2DPolarLights(void) { // By: Kostyantyn Matviyevskyy https://editor.soulmatelights.com/gallery/762-polar-lights , Modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; CRGBPalette16 auroraPalette = {0x000000, 0x003300, 0x006600, 0x009900, 0x00cc00, 0x00ff00, 0x33ff00, 0x66ff00, 0x99ff00, 0xccff00, 0xffff00, 0xffcc00, 0xff9900, 0xff6600, 0xff3300, 0xff0000}; @@ -5627,8 +5628,8 @@ static const char _data_FX_MODE_2DPOLARLIGHTS[] PROGMEM = "Polar Lights@!,Scale; uint16_t mode_2DPulser(void) { // By: ldirko https://editor.soulmatelights.com/gallery/878-pulse-test , modifed by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; SEGMENT.fadeToBlackBy(8 - (SEGMENT.intensity>>5)); uint32_t a = strip.now / (18 - SEGMENT.speed / 16); @@ -5649,8 +5650,8 @@ static const char _data_FX_MODE_2DPULSER[] PROGMEM = "Pulser@!,Blur;;!;2"; uint16_t mode_2DSindots(void) { // By: ldirko https://editor.soulmatelights.com/gallery/597-sin-dots , modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; if (SEGENV.call == 0) { SEGMENT.fill(BLACK); @@ -5680,8 +5681,8 @@ uint16_t mode_2Dsquaredswirl(void) { // By: Mark Kriegsman. https://g // Modifed by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; const uint8_t kBorderWidth = 2; @@ -5711,8 +5712,8 @@ static const char _data_FX_MODE_2DSQUAREDSWIRL[] PROGMEM = "Squared Swirl@,,,,Bl uint16_t mode_2DSunradiation(void) { // By: ldirko https://editor.soulmatelights.com/gallery/599-sun-radiation , modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; if (!SEGENV.allocateData(sizeof(byte)*(cols+2)*(rows+2))) return mode_static(); //allocation failed byte *bump = reinterpret_cast(SEGENV.data); @@ -5761,8 +5762,8 @@ static const char _data_FX_MODE_2DSUNRADIATION[] PROGMEM = "Sun Radiation@Varian uint16_t mode_2Dtartan(void) { // By: Elliott Kember https://editor.soulmatelights.com/gallery/3-tartan , Modified by: Andrew Tuline if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; if (SEGENV.call == 0) { SEGMENT.fill(BLACK); @@ -5800,8 +5801,8 @@ static const char _data_FX_MODE_2DTARTAN[] PROGMEM = "Tartan@X scale,Y scale,,,S uint16_t mode_2Dspaceships(void) { //// Space ships by stepko (c)05.02.21 [https://editor.soulmatelights.com/gallery/639-space-ships], adapted by Blaz Kristan (AKA blazoncek) if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; uint32_t tb = strip.now >> 12; // every ~4s if (tb > SEGENV.step) { @@ -5843,8 +5844,8 @@ static const char _data_FX_MODE_2DSPACESHIPS[] PROGMEM = "Spaceships@!,Blur;;!;2 uint16_t mode_2Dcrazybees(void) { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; byte n = MIN(MAX_BEES, (rows * cols) / 256 + 1); @@ -5916,8 +5917,8 @@ static const char _data_FX_MODE_2DCRAZYBEES[] PROGMEM = "Crazy Bees@!,Blur;;;2"; uint16_t mode_2Dghostrider(void) { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; typedef struct Lighter { int16_t gPosX; @@ -6006,8 +6007,8 @@ static const char _data_FX_MODE_2DGHOSTRIDER[] PROGMEM = "Ghost Rider@Fade rate, uint16_t mode_2Dfloatingblobs(void) { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; typedef struct Blob { float x[MAX_BLOBS], y[MAX_BLOBS]; @@ -6104,8 +6105,8 @@ static const char _data_FX_MODE_2DBLOBS[] PROGMEM = "Blobs@!,# blobs,Blur,Trail; uint16_t mode_2Dscrollingtext(void) { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; unsigned letterWidth, rotLW; unsigned letterHeight, rotLH; @@ -6205,8 +6206,8 @@ static const char _data_FX_MODE_2DSCROLLTEXT[] PROGMEM = "Scrolling Text@!,Y Off uint16_t mode_2Ddriftrose(void) { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; const float CX = (cols-cols%2)/2.f - .5f; const float CY = (rows-rows%2)/2.f - .5f; @@ -6232,8 +6233,8 @@ static const char _data_FX_MODE_2DDRIFTROSE[] PROGMEM = "Drift Rose@Fade,Blur;;; uint16_t mode_2Dplasmarotozoom() { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; unsigned dataSize = SEGMENT.length() + sizeof(float); if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed @@ -6401,8 +6402,8 @@ static const char _data_FX_MODE_RIPPLEPEAK[] PROGMEM = "Ripple Peak@Fade rate,Ma uint16_t mode_2DSwirl(void) { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; if (SEGENV.call == 0) { SEGMENT.fill(BLACK); @@ -6440,8 +6441,8 @@ static const char _data_FX_MODE_2DSWIRL[] PROGMEM = "Swirl@!,Sensitivity,Blur;,B uint16_t mode_2DWaverly(void) { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; um_data_t *um_data = getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; @@ -6652,7 +6653,7 @@ uint16_t mode_matripix(void) { // Matripix. By Andrew Tuline. SEGENV.aux0 = secondHand; int pixBri = volumeRaw * SEGMENT.intensity / 64; - for (int i = 0; i < SEGLEN-1; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // shift left + for (unsigned i = 0; i < SEGLEN-1; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // shift left SEGMENT.setPixelColor(SEGLEN-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0), pixBri)); } @@ -6677,10 +6678,10 @@ uint16_t mode_midnoise(void) { // Midnoise. By Andrew Tuline. float tmpSound2 = volumeSmth * (float)SEGMENT.intensity / 256.0; // Too sensitive. tmpSound2 *= (float)SEGMENT.intensity / 128.0; // Reduce sensitivity/length. - int maxLen = mapf(tmpSound2, 0, 127, 0, SEGLEN/2); + unsigned maxLen = mapf(tmpSound2, 0, 127, 0, SEGLEN/2); if (maxLen >SEGLEN/2) maxLen = SEGLEN/2; - for (int i=(SEGLEN/2-maxLen); i<(SEGLEN/2+maxLen); i++) { + for (unsigned i=(SEGLEN/2-maxLen); i<(SEGLEN/2+maxLen); i++) { uint8_t index = inoise8(i*volumeSmth+SEGENV.aux0, SEGENV.aux1+i*volumeSmth); // Get a value from the noise function. I'm using both x and y axis. SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); } @@ -6708,7 +6709,7 @@ uint16_t mode_noisefire(void) { // Noisefire. By Andrew Tuline. if (SEGENV.call == 0) SEGMENT.fill(BLACK); - for (int i = 0; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { unsigned index = inoise8(i*SEGMENT.speed/64,strip.now*SEGMENT.speed/64*SEGLEN/255); // X location is constant, but we move along the Y at the rate of millis(). By Andrew Tuline. index = (255 - i*256/SEGLEN) * index/(256-SEGMENT.intensity); // Now we need to scale index so that it gets blacker as we get close to one of the ends. // This is a simple y=mx+b equation that's been scaled. index/128 is another scaling. @@ -6735,11 +6736,11 @@ uint16_t mode_noisemeter(void) { // Noisemeter. By Andrew Tuline. SEGMENT.fade_out(fadeRate); float tmpSound2 = volumeRaw * 2.0 * (float)SEGMENT.intensity / 255.0; - int maxLen = mapf(tmpSound2, 0, 255, 0, SEGLEN); // map to pixels availeable in current segment // Still a bit too sensitive. - if (maxLen <0) maxLen = 0; - if (maxLen >SEGLEN) maxLen = SEGLEN; + unsigned maxLen = mapf(tmpSound2, 0, 255, 0, SEGLEN); // map to pixels availeable in current segment // Still a bit too sensitive. + if (maxLen < 0) maxLen = 0; + if (maxLen > SEGLEN) maxLen = SEGLEN; - for (int i=0; i SEGLEN/2; i--) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i-1)); //move to the left - for (int i = 0; i < SEGLEN/2; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // move to the right + for (unsigned i = SEGLEN - 1; i > SEGLEN/2; i--) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i-1)); //move to the left + for (unsigned i = 0; i < SEGLEN/2; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // move to the right } return FRAMETIME; @@ -6803,7 +6804,7 @@ uint16_t mode_plasmoid(void) { // Plasmoid. By Andrew Tuline. plasmoip->thisphase += beatsin8(6,-4,4); // You can change direction and speed individually. plasmoip->thatphase += beatsin8(7,-4,4); // Two phase values to make a complex pattern. By Andrew Tuline. - for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows. + for (unsigned i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows. // updated, similar to "plasma" effect - softhack007 uint8_t thisbright = cubicwave8(((i*(1 + (3*SEGMENT.speed/32)))+plasmoip->thisphase) & 0xFF)/2; thisbright += cos8(((i*(97 +(5*SEGMENT.speed/32)))+plasmoip->thatphase) & 0xFF)/2; // Let's munge the brightness a bit and animate it all with the phases. @@ -6943,7 +6944,7 @@ uint16_t mode_blurz(void) { // Blurz. By Andrew Tuline. SEGENV.step += FRAMETIME; if (SEGENV.step > SPEED_FORMULA_L) { unsigned segLoc = random16(SEGLEN); - SEGMENT.setPixelColor(segLoc, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(2*fftResult[SEGENV.aux0%16]*240/max(1, SEGLEN-1), false, PALETTE_SOLID_WRAP, 0), 2*fftResult[SEGENV.aux0%16])); + SEGMENT.setPixelColor(segLoc, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(2*fftResult[SEGENV.aux0%16]*240/max(1, (int)SEGLEN-1), false, PALETTE_SOLID_WRAP, 0), 2*fftResult[SEGENV.aux0%16])); ++(SEGENV.aux0) %= 16; // make sure it doesn't cross 16 SEGENV.step = 1; @@ -7006,7 +7007,7 @@ uint16_t mode_freqmap(void) { // Map FFT_MajorPeak to SEGLEN. int locn = (log10f((float)FFT_MajorPeak) - 1.78f) * (float)SEGLEN/(MAX_FREQ_LOG10 - 1.78f); // log10 frequency range is from 1.78 to 3.71. Let's scale to SEGLEN. if (locn < 1) locn = 0; // avoid underflow - if (locn >=SEGLEN) locn = SEGLEN-1; + if (locn >= (int)SEGLEN) locn = SEGLEN-1; unsigned pixCol = (log10f(FFT_MajorPeak) - 1.78f) * 255.0f/(MAX_FREQ_LOG10 - 1.78f); // Scale log10 of frequency values to the 255 colour index. if (FFT_MajorPeak < 61.0f) pixCol = 0; // handle underflow @@ -7159,8 +7160,8 @@ uint16_t mode_freqwave(void) { // Freqwave. By Andreas Pleschun // shift the pixels one pixel outwards // if SEGLEN equals 1 these loops won't execute - for (int i = SEGLEN - 1; i > SEGLEN/2; i--) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i-1)); //move to the left - for (int i = 0; i < SEGLEN/2; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // move to the right + for (unsigned i = SEGLEN - 1; i > SEGLEN/2; i--) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i-1)); //move to the left + for (unsigned i = 0; i < SEGLEN/2; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // move to the right } return FRAMETIME; @@ -7314,7 +7315,7 @@ uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tulin SEGMENT.setPixelColor(SEGLEN-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(pixCol+SEGMENT.intensity, false, PALETTE_SOLID_WRAP, 0), (int)my_magnitude)); } // loop will not execute if SEGLEN equals 1 - for (int i = 0; i < SEGLEN-1; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // shift left + for (unsigned i = 0; i < SEGLEN-1; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // shift left } return FRAMETIME; @@ -7330,8 +7331,8 @@ uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma. if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up const int NUM_BANDS = map(SEGMENT.custom1, 0, 255, 1, 16); - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; if (!SEGENV.allocateData(cols*sizeof(uint16_t))) return mode_static(); //allocation failed uint16_t *previousBarHeight = reinterpret_cast(SEGENV.data); //array of previous bar heights per frequency band @@ -7383,8 +7384,8 @@ static const char _data_FX_MODE_2DGEQ[] PROGMEM = "GEQ@Fade speed,Ripple decay,# uint16_t mode_2DFunkyPlank(void) { // Written by ??? Adapted by Will Tatam. if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; int NUMB_BANDS = map(SEGMENT.custom1, 0, 255, 1, 16); int barWidth = (cols / NUMB_BANDS); @@ -7471,8 +7472,8 @@ static uint8_t akemi[] PROGMEM = { uint16_t mode_2DAkemi(void) { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; unsigned counter = (strip.now * ((SEGMENT.speed >> 2) +2)) & 0xFFFF; counter = counter >> 8; @@ -7539,8 +7540,8 @@ static const char _data_FX_MODE_2DAKEMI[] PROGMEM = "Akemi@Color speed,Dance;Hea uint16_t mode_2Ddistortionwaves() { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; uint8_t speed = SEGMENT.speed/32; uint8_t scale = SEGMENT.intensity/32; @@ -7594,8 +7595,8 @@ static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@ uint16_t mode_2Dsoap() { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; const size_t dataSize = SEGMENT.width() * SEGMENT.height() * sizeof(uint8_t); // prevent reallocation if mirrored or grouped if (!SEGENV.allocateData(dataSize + sizeof(uint32_t)*3)) return mode_static(); //allocation failed @@ -7706,8 +7707,8 @@ static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness;;!;2"; uint16_t mode_2Doctopus() { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; const uint8_t mapp = 180 / MAX(cols,rows); typedef struct { @@ -7761,8 +7762,8 @@ static const char _data_FX_MODE_2DOCTOPUS[] PROGMEM = "Octopus@!,,Offset X,Offse uint16_t mode_2Dwavingcell() { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up - const int cols = SEGMENT.virtualWidth(); - const int rows = SEGMENT.virtualHeight(); + const int cols = SEG_W; + const int rows = SEG_H; uint32_t t = strip.now/(257-SEGMENT.speed); uint8_t aX = SEGMENT.custom1/16 + 9; diff --git a/wled00/FX.h b/wled00/FX.h index 825c722e..98082c8d 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -90,11 +90,11 @@ extern byte realtimeMode; // used in getMappedPixelIndex() #define NUM_COLORS 3 /* number of colors per segment */ #define SEGMENT strip._segments[strip.getCurrSegmentId()] #define SEGENV strip._segments[strip.getCurrSegmentId()] -//#define SEGCOLOR(x) strip._segments[strip.getCurrSegmentId()].currentColor(x, strip._segments[strip.getCurrSegmentId()].colors[x]) -//#define SEGLEN strip._segments[strip.getCurrSegmentId()].virtualLength() -#define SEGCOLOR(x) strip.segColor(x) /* saves us a few kbytes of code */ +#define SEGCOLOR(x) Segment::getCurrentColor(x) #define SEGPALETTE Segment::getCurrentPalette() -#define SEGLEN strip._virtualSegmentLength /* saves us a few kbytes of code */ +#define SEGLEN Segment::vLength() +#define SEG_W Segment::vWidth() +#define SEG_H Segment::vHeight() #define SPEED_FORMULA_L (5U + (50U*(255U - SEGMENT.speed))/SEGLEN) // some common colors @@ -421,7 +421,9 @@ typedef struct Segment { uint16_t _dataLen; static uint16_t _usedSegmentData; - // perhaps this should be per segment, not static + static unsigned _vLength; // 1D dimension used for current effect + static unsigned _vWidth, _vHeight; // 2D dimensions used for current effect + static uint32_t _currentColors[NUM_COLORS]; // colors used for current effect static CRGBPalette16 _currentPalette; // palette used for current effect (includes transition, used in color_from_palette()) static CRGBPalette16 _randomPalette; // actual random palette static CRGBPalette16 _newRandomPalette; // target random palette @@ -534,14 +536,20 @@ typedef struct Segment { inline uint16_t groupLength() const { return grouping + spacing; } inline uint8_t getLightCapabilities() const { return _capabilities; } - inline static uint16_t getUsedSegmentData() { return _usedSegmentData; } - inline static void addUsedSegmentData(int len) { _usedSegmentData += len; } + inline static uint16_t getUsedSegmentData() { return Segment::_usedSegmentData; } + inline static void addUsedSegmentData(int len) { Segment::_usedSegmentData += len; } #ifndef WLED_DISABLE_MODE_BLEND - inline static void modeBlend(bool blend) { _modeBlend = blend; } + inline static void modeBlend(bool blend) { _modeBlend = blend; } #endif - static void handleRandomPalette(); + inline static unsigned vLength() { return Segment::_vLength; } + inline static unsigned vWidth() { return Segment::_vWidth; } + inline static unsigned vHeight() { return Segment::_vHeight; } + inline static uint32_t getCurrentColor(unsigned i) { return Segment::_currentColors[i]; } // { return i < 3 ? Segment::_currentColors[i] : 0; } inline static const CRGBPalette16 &getCurrentPalette() { return Segment::_currentPalette; } + static void handleRandomPalette(); + + void beginDraw(); // set up parameters for current effect void setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1); bool setColor(uint8_t slot, uint32_t c); //returns true if changed void setCCT(uint16_t k); @@ -578,14 +586,13 @@ typedef struct Segment { uint8_t currentMode() const; // currently active effect/mode (while in transition) [[gnu::hot]] uint32_t currentColor(uint8_t slot) const; // currently active segment color (blended while in transition) CRGBPalette16 &loadPalette(CRGBPalette16 &tgt, uint8_t pal); - void setCurrentPalette(); // 1D strip [[gnu::hot]] uint16_t virtualLength() const; - [[gnu::hot]] void setPixelColor(int n, uint32_t c); // set relative pixel within segment with color - inline void setPixelColor(unsigned n, uint32_t c) { setPixelColor(int(n), c); } - inline void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } - inline void setPixelColor(int n, CRGB c) { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } + [[gnu::hot]] void setPixelColor(int n, uint32_t c, bool unScaled = true); // set relative pixel within segment with color + inline void setPixelColor(unsigned n, uint32_t c, bool unScaled = true) { setPixelColor(int(n), c, unScaled); } + inline void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } + inline void setPixelColor(int n, CRGB c) { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } #ifdef WLED_USE_AA_PIXELS void setPixelColor(float i, uint32_t c, bool aa = true); inline void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) { setPixelColor(i, RGBW32(r,g,b,w), aa); } @@ -622,8 +629,8 @@ typedef struct Segment { uint16_t nrOfVStrips() const; // returns number of virtual vertical strips in 2D matrix (used to expand 1D effects into 2D) #ifndef WLED_DISABLE_2D [[gnu::hot]] uint16_t XY(int x, int y); // support function to get relative index within segment - [[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color - inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColorXY(int(x), int(y), c); } + [[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c, bool unScaled = true); // set relative pixel within segment with color + inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c, bool unScaled = true) { setPixelColorXY(int(x), int(y), c, unScaled); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColorXY(int(x), int(y), RGBW32(c.r,c.g,c.b,0)); } @@ -642,8 +649,8 @@ typedef struct Segment { inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), fade, true)); } void box_blur(unsigned r = 1U, bool smear = false); // 2D box blur void blur2D(uint8_t blur_amount, bool smear = false); - void blurRow(uint32_t row, fract8 blur_amount, bool smear = false); - void blurCol(uint32_t col, fract8 blur_amount, bool smear = false); + void blurRow(int row, fract8 blur_amount, bool smear = false); + void blurCol(int col, fract8 blur_amount, bool smear = false); void moveX(int8_t delta, bool wrap = false); void moveY(int8_t delta, bool wrap = false); void move(uint8_t dir, uint8_t delta, bool wrap = false); @@ -660,9 +667,9 @@ typedef struct Segment { inline void blur2d(fract8 blur_amount) { blur(blur_amount); } inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); } #else - inline uint16_t XY(uint16_t x, uint16_t y) { return x; } - inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(x, c); } - inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColor(int(x), c); } + inline uint16_t XY(int x, int y) { return x; } + inline void setPixelColorXY(int x, int y, uint32_t c, bool unScaled = true) { setPixelColor(x, c, unScaled); } + inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c, bool unScaled = true) { setPixelColor(int(x), c, unScaled); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColor(x, RGBW32(r,g,b,w)); } inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColor(x, RGBW32(c.r,c.g,c.b,0)); } inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColor(int(x), RGBW32(c.r,c.g,c.b,0)); } @@ -680,8 +687,8 @@ typedef struct Segment { inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { fadePixelColor(x, fade); } inline void box_blur(unsigned i, bool vertical, fract8 blur_amount) {} inline void blur2D(uint8_t blur_amount, bool smear = false) {} - inline void blurRow(uint32_t row, fract8 blur_amount, bool smear = false) {} - inline void blurCol(uint32_t col, fract8 blur_amount, bool smear = false) {} + inline void blurRow(int row, fract8 blur_amount, bool smear = false) {} + inline void blurCol(int col, fract8 blur_amount, bool smear = false) {} inline void moveX(int8_t delta, bool wrap = false) {} inline void moveY(int8_t delta, bool wrap = false) {} inline void move(uint8_t dir, uint8_t delta, bool wrap = false) {} @@ -727,9 +734,6 @@ class WS2812FX { // 96 bytes autoSegments(false), correctWB(false), cctFromRgb(false), - // semi-private (just obscured) used in effect functions through macros - _colors_t{0,0,0}, - _virtualSegmentLength(0), // true private variables _suspend(false), _length(DEFAULT_LED_COUNT), @@ -829,7 +833,7 @@ class WS2812FX { // 96 bytes addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name); // add effect to the list; defined in FX.cpp; inline uint8_t getBrightness() const { return _brightness; } // returns current strip brightness - inline uint8_t getMaxSegments() const { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value) + inline constexpr unsigned getMaxSegments() { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value) inline uint8_t getSegmentsNum() const { return _segments.size(); } // returns currently present segments inline uint8_t getCurrSegmentId() const { return _segment_index; } // returns current segment index (only valid while strip.isServicing()) inline uint8_t getMainSegmentId() const { return _mainSegment; } // returns main segment index @@ -855,7 +859,6 @@ class WS2812FX { // 96 bytes uint32_t getPixelColor(unsigned) const; inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call - inline uint32_t segColor(uint8_t i) const { return _colors_t[i]; } // returns currently valid color (for slot i) AKA SEGCOLOR(); may be blended between two colors while in transition const char * getModeData(uint8_t id = 0) const { return (id && id<_modeCount) ? _modeData[id] : PSTR("Solid"); } @@ -922,11 +925,6 @@ class WS2812FX { // 96 bytes bool cctFromRgb : 1; }; - // using public variables to reduce code size increase due to inline function getSegment() (with bounds checking) - // and color transitions - uint32_t _colors_t[3]; // color used for effect (includes transition) - uint16_t _virtualSegmentLength; - std::vector _segments; friend class Segment; diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 41fd6731..5f61b009 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -163,23 +163,24 @@ void WS2812FX::setUpMatrix() { // XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element) uint16_t IRAM_ATTR_YN Segment::XY(int x, int y) { - unsigned width = virtualWidth(); // segment width in logical pixels (can be 0 if segment is inactive) - unsigned height = virtualHeight(); // segment height in logical pixels (is always >= 1) - return isActive() ? (x%width) + (y%height) * width : 0; + const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) + const int vH = vHeight(); // segment height in logical pixels (is always >= 1) + return isActive() ? (x%vW) + (y%vH) * vW : 0; } -void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) +void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col, bool unScaled) { if (!isActive()) return; // not active - if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit + + const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) + const int vH = vHeight(); // segment height in logical pixels (is always >= 1) + if (x >= vW|| y >= vH || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit - uint8_t _bri_t = currentBri(); - if (_bri_t < 255) { - col = color_fade(col, _bri_t); - } + // if color is unscaled + if (unScaled) col = color_fade(col, currentBri()); - if (reverse ) x = virtualWidth() - x - 1; - if (reverse_y) y = virtualHeight() - y - 1; + if (reverse ) x = vW - x - 1; + if (reverse_y) y = vH - y - 1; if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed x *= groupLength(); // expand to physical pixels y *= groupLength(); // expand to physical pixels @@ -221,11 +222,8 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa) if (!isActive()) return; // not active if (x<0.0f || x>1.0f || y<0.0f || y>1.0f) return; // not normalized - const unsigned cols = virtualWidth(); - const unsigned rows = virtualHeight(); - - float fX = x * (cols-1); - float fY = y * (rows-1); + float fX = x * (vWidth()-1); + float fY = y * (vHeight()-1); if (aa) { unsigned xL = roundf(fX-0.49f); unsigned xR = roundf(fX+0.49f); @@ -263,9 +261,11 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa) // returns RGBW values of pixel uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const { if (!isActive()) return 0; // not active - if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit - if (reverse ) x = virtualWidth() - x - 1; - if (reverse_y) y = virtualHeight() - y - 1; + int vW = vWidth(); + int vH = vHeight(); + if (x >= vW || y >= vH || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit + if (reverse ) x = vW - x - 1; + if (reverse_y) y = vH - y - 1; if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed x *= groupLength(); // expand to physical pixels y *= groupLength(); // expand to physical pixels @@ -274,10 +274,10 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const { } // blurRow: perform a blur on a row of a rectangular matrix -void Segment::blurRow(uint32_t row, fract8 blur_amount, bool smear){ +void Segment::blurRow(int row, fract8 blur_amount, bool smear){ if (!isActive() || blur_amount == 0) return; // not active - const unsigned cols = virtualWidth(); - const unsigned rows = virtualHeight(); + const int cols = vWidth(); + const int rows = vHeight(); if (row >= rows) return; // blur one row @@ -287,7 +287,7 @@ void Segment::blurRow(uint32_t row, fract8 blur_amount, bool smear){ uint32_t lastnew; uint32_t last; uint32_t curnew = BLACK; - for (unsigned x = 0; x < cols; x++) { + for (int x = 0; x < cols; x++) { uint32_t cur = getPixelColorXY(x, row); uint32_t part = color_fade(cur, seep); curnew = color_fade(cur, keep); @@ -306,10 +306,10 @@ void Segment::blurRow(uint32_t row, fract8 blur_amount, bool smear){ } // blurCol: perform a blur on a column of a rectangular matrix -void Segment::blurCol(uint32_t col, fract8 blur_amount, bool smear) { +void Segment::blurCol(int col, fract8 blur_amount, bool smear) { if (!isActive() || blur_amount == 0) return; // not active - const unsigned cols = virtualWidth(); - const unsigned rows = virtualHeight(); + const int cols = vWidth(); + const int rows = vHeight(); if (col >= cols) return; // blur one column @@ -319,7 +319,7 @@ void Segment::blurCol(uint32_t col, fract8 blur_amount, bool smear) { uint32_t lastnew; uint32_t last; uint32_t curnew = BLACK; - for (unsigned y = 0; y < rows; y++) { + for (int y = 0; y < rows; y++) { uint32_t cur = getPixelColorXY(col, y); uint32_t part = color_fade(cur, seep); curnew = color_fade(cur, keep); @@ -339,8 +339,8 @@ void Segment::blurCol(uint32_t col, fract8 blur_amount, bool smear) { void Segment::blur2D(uint8_t blur_amount, bool smear) { if (!isActive() || blur_amount == 0) return; // not active - const unsigned cols = virtualWidth(); - const unsigned rows = virtualHeight(); + const unsigned cols = vWidth(); + const unsigned rows = vHeight(); const uint8_t keep = smear ? 255 : 255 - blur_amount; const uint8_t seep = blur_amount >> (1 + smear); @@ -391,8 +391,8 @@ void Segment::box_blur(unsigned radius, bool smear) { if (!isActive() || radius == 0) return; // not active if (radius > 3) radius = 3; const unsigned d = (1 + 2*radius) * (1 + 2*radius); // averaging divisor - const unsigned cols = virtualWidth(); - const unsigned rows = virtualHeight(); + const unsigned cols = vWidth(); + const unsigned rows = vHeight(); uint16_t *tmpRSum = new uint16_t[cols*rows]; uint16_t *tmpGSum = new uint16_t[cols*rows]; uint16_t *tmpBSum = new uint16_t[cols*rows]; @@ -461,37 +461,37 @@ void Segment::box_blur(unsigned radius, bool smear) { void Segment::moveX(int8_t delta, bool wrap) { if (!isActive()) return; // not active - const int cols = virtualWidth(); - const int rows = virtualHeight(); - if (!delta || abs(delta) >= cols) return; - uint32_t newPxCol[cols]; - for (int y = 0; y < rows; y++) { + const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) + const int vH = vHeight(); // segment height in logical pixels (is always >= 1) + if (!delta || abs(delta) >= vW) return; + uint32_t newPxCol[vW]; + for (int y = 0; y < vH; y++) { if (delta > 0) { - for (int x = 0; x < cols-delta; x++) newPxCol[x] = getPixelColorXY((x + delta), y); - for (int x = cols-delta; x < cols; x++) newPxCol[x] = getPixelColorXY(wrap ? (x + delta) - cols : x, y); + for (int x = 0; x < vW-delta; x++) newPxCol[x] = getPixelColorXY((x + delta), y); + for (int x = vW-delta; x < vW; x++) newPxCol[x] = getPixelColorXY(wrap ? (x + delta) - vW : x, y); } else { - for (int x = cols-1; x >= -delta; x--) newPxCol[x] = getPixelColorXY((x + delta), y); - for (int x = -delta-1; x >= 0; x--) newPxCol[x] = getPixelColorXY(wrap ? (x + delta) + cols : x, y); + for (int x = vW-1; x >= -delta; x--) newPxCol[x] = getPixelColorXY((x + delta), y); + for (int x = -delta-1; x >= 0; x--) newPxCol[x] = getPixelColorXY(wrap ? (x + delta) + vW : x, y); } - for (int x = 0; x < cols; x++) setPixelColorXY(x, y, newPxCol[x]); + for (int x = 0; x < vW; x++) setPixelColorXY(x, y, newPxCol[x]); } } void Segment::moveY(int8_t delta, bool wrap) { if (!isActive()) return; // not active - const int cols = virtualWidth(); - const int rows = virtualHeight(); - if (!delta || abs(delta) >= rows) return; - uint32_t newPxCol[rows]; - for (int x = 0; x < cols; x++) { + const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) + const int vH = vHeight(); // segment height in logical pixels (is always >= 1) + if (!delta || abs(delta) >= vH) return; + uint32_t newPxCol[vH]; + for (int x = 0; x < vW; x++) { if (delta > 0) { - for (int y = 0; y < rows-delta; y++) newPxCol[y] = getPixelColorXY(x, (y + delta)); - for (int y = rows-delta; y < rows; y++) newPxCol[y] = getPixelColorXY(x, wrap ? (y + delta) - rows : y); + for (int y = 0; y < vH-delta; y++) newPxCol[y] = getPixelColorXY(x, (y + delta)); + for (int y = vH-delta; y < vH; y++) newPxCol[y] = getPixelColorXY(x, wrap ? (y + delta) - vH : y); } else { - for (int y = rows-1; y >= -delta; y--) newPxCol[y] = getPixelColorXY(x, (y + delta)); - for (int y = -delta-1; y >= 0; y--) newPxCol[y] = getPixelColorXY(x, wrap ? (y + delta) + rows : y); + for (int y = vH-1; y >= -delta; y--) newPxCol[y] = getPixelColorXY(x, (y + delta)); + for (int y = -delta-1; y >= 0; y--) newPxCol[y] = getPixelColorXY(x, wrap ? (y + delta) + vH : y); } - for (int y = 0; y < rows; y++) setPixelColorXY(x, y, newPxCol[y]); + for (int y = 0; y < vH; y++) setPixelColorXY(x, y, newPxCol[y]); } } @@ -545,18 +545,20 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, x++; } } else { + // pre-scale color for all pixels + col = color_fade(col, currentBri()); // Bresenham’s Algorithm int d = 3 - (2*radius); int y = radius, x = 0; while (y >= x) { - setPixelColorXY(cx+x, cy+y, col); - setPixelColorXY(cx-x, cy+y, col); - setPixelColorXY(cx+x, cy-y, col); - setPixelColorXY(cx-x, cy-y, col); - setPixelColorXY(cx+y, cy+x, col); - setPixelColorXY(cx-y, cy+x, col); - setPixelColorXY(cx+y, cy-x, col); - setPixelColorXY(cx-y, cy-x, col); + setPixelColorXY(cx+x, cy+y, col, false); + setPixelColorXY(cx-x, cy+y, col, false); + setPixelColorXY(cx+x, cy-y, col, false); + setPixelColorXY(cx-x, cy-y, col, false); + setPixelColorXY(cx+y, cy+x, col, false); + setPixelColorXY(cx-y, cy+x, col, false); + setPixelColorXY(cx+y, cy-x, col, false); + setPixelColorXY(cx-y, cy-x, col, false); x++; if (d > 0) { y--; @@ -571,17 +573,19 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, // by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs void Segment::fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, bool soft) { if (!isActive() || radius == 0) return; // not active + const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) + const int vH = vHeight(); // segment height in logical pixels (is always >= 1) // draw soft bounding circle if (soft) drawCircle(cx, cy, radius, col, soft); + // pre-scale color for all pixels + col = color_fade(col, currentBri()); // fill it - const int cols = virtualWidth(); - const int rows = virtualHeight(); for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius && - int(cx)+x>=0 && int(cy)+y>=0 && - int(cx)+x= 0 && int(cy)+y >= 0 && + int(cx)+x < vW && int(cy)+y < vH) + setPixelColorXY(cx + x, cy + y, col, false); } } } @@ -589,9 +593,9 @@ void Segment::fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, //line function void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft) { if (!isActive()) return; // not active - const int cols = virtualWidth(); - const int rows = virtualHeight(); - if (x0 >= cols || x1 >= cols || y0 >= rows || y1 >= rows) return; + const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) + const int vH = vHeight(); // segment height in logical pixels (is always >= 1) + if (x0 >= vW || x1 >= vW || y0 >= vH || y1 >= vH) return; const int dx = abs(x1-x0), sx = x0dy ? dx : -dy)/2; // error direction for (;;) { - setPixelColorXY(x0, y0, c); + setPixelColorXY(x0, y0, c, false); if (x0==x1 && y0==y1) break; int e2 = err; if (e2 >-dx) { err -= dy; x0 += sx; } @@ -653,8 +659,6 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, if (!isActive()) return; // not active if (chr < 32 || chr > 126) return; // only ASCII 32-126 supported chr -= 32; // align with font table entries - const int cols = virtualWidth(); - const int rows = virtualHeight(); const int font = w*h; CRGB col = CRGB(color); @@ -681,7 +685,7 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, case 1: x0 = x + i; y0 = y + j; break; // +90 deg default: x0 = x + (w-1) - j; y0 = y + i; break; // no rotation } - if (x0 < 0 || x0 >= cols || y0 < 0 || y0 >= rows) continue; // drawing off-screen + if (x0 < 0 || x0 >= (int)vWidth() || y0 < 0 || y0 >= (int)vHeight()) continue; // drawing off-screen if (((bits>>(j+(8-w))) & 0x01)) { // bit set setPixelColorXY(x0, y0, col); } diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index a9875542..a47a7edc 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -80,15 +80,18 @@ static constexpr bool validatePinsAndTypes(const unsigned* types, unsigned numTy /////////////////////////////////////////////////////////////////////////////// // Segment class implementation /////////////////////////////////////////////////////////////////////////////// -uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for their data[] -uint16_t Segment::maxWidth = DEFAULT_LED_COUNT; -uint16_t Segment::maxHeight = 1; - +uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for their data[] +uint16_t Segment::maxWidth = DEFAULT_LED_COUNT; +uint16_t Segment::maxHeight = 1; +unsigned Segment::_vLength = 0; +unsigned Segment::_vWidth = 0; +unsigned Segment::_vHeight = 0; +uint32_t Segment::_currentColors[NUM_COLORS] = {0,0,0}; CRGBPalette16 Segment::_currentPalette = CRGBPalette16(CRGB::Black); CRGBPalette16 Segment::_randomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR); CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR); uint16_t Segment::_lastPaletteChange = 0; // perhaps it should be per segment -uint16_t Segment::_lastPaletteBlend = 0; //in millis (lowest 16 bits only) +uint16_t Segment::_lastPaletteBlend = 0; // in millis (lowest 16 bits only) #ifndef WLED_DISABLE_MODE_BLEND bool Segment::_modeBlend = false; @@ -437,7 +440,21 @@ uint32_t IRAM_ATTR_YN Segment::currentColor(uint8_t slot) const { #endif } -void Segment::setCurrentPalette() { +// pre-calculate drawing parameters for faster access +void Segment::beginDraw() { + _vWidth = virtualWidth(); + _vHeight = virtualHeight(); + _vLength = virtualLength(); + // adjust gamma for effects + for (unsigned i = 0; i < NUM_COLORS; i++) { + #ifndef WLED_DISABLE_MODE_BLEND + uint32_t col = isInTransition() ? color_blend(_t->_segT._colorT[i], colors[i], progress(), true) : colors[i]; + #else + uint32_t col = isInTransition() ? color_blend(_t->_colorT[i], colors[i], progress(), true) : colors[i]; + #endif + _currentColors[i] = gamma32(col); + } + // load palette into _currentPalette loadPalette(_currentPalette, palette); unsigned prog = progress(); if (strip.paletteFade && prog < 0xFFFFU) { @@ -698,20 +715,21 @@ uint16_t IRAM_ATTR Segment::virtualLength() const { return vLength; } -void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) +void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col, bool unScaled) { if (!isActive() || i < 0) return; // not active or invalid index #ifndef WLED_DISABLE_2D int vStrip = 0; #endif + int vL = vLength(); // if the 1D effect is using virtual strips "i" will have virtual strip id stored in upper 16 bits // in such case "i" will be > virtualLength() - if (i >= virtualLength()) { + if (i >= vL) { // check if this is a virtual strip #ifndef WLED_DISABLE_2D vStrip = i>>16; // hack to allow running on virtual strips (2D segment columns/rows) i &= 0xFFFF; //truncate vstrip index - if (i >= virtualLength()) return; // if pixel would still fall out of segment just exit + if (i >= vL) return; // if pixel would still fall out of segment just exit #else return; #endif @@ -719,22 +737,24 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) #ifndef WLED_DISABLE_2D if (is2D()) { - int vH = virtualHeight(); // segment height in logical pixels - int vW = virtualWidth(); + const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) + const int vH = vHeight(); // segment height in logical pixels (is always >= 1) + // pre-scale color for all pixels + col = color_fade(col, currentBri()); switch (map1D2D) { case M12_Pixels: // use all available pixels as a long strip - setPixelColorXY(i % vW, i / vW, col); + setPixelColorXY(i % vW, i / vW, col, false); break; case M12_pBar: // expand 1D effect vertically or have it play on virtual strips - if (vStrip > 0) setPixelColorXY(vStrip - 1, vH - i - 1, col); - else for (int x = 0; x < vW; x++) setPixelColorXY(x, vH - i - 1, col); + if (vStrip > 0) setPixelColorXY(vStrip - 1, vH - i - 1, col, false); + else for (int x = 0; x < vW; x++) setPixelColorXY(x, vH - i - 1, col, false); break; case M12_pArc: // expand in circular fashion from center if (i == 0) - setPixelColorXY(0, 0, col); + setPixelColorXY(0, 0, col, false); else { float r = i; float step = HALF_PI / (2.8284f * r + 4); // we only need (PI/4)/(r/sqrt(2)+1) steps @@ -742,8 +762,8 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) int x = roundf(sin_t(rad) * r); int y = roundf(cos_t(rad) * r); // exploit symmetry - setPixelColorXY(x, y, col); - setPixelColorXY(y, x, col); + setPixelColorXY(x, y, col, false); + setPixelColorXY(y, x, col, false); } // Bresenham’s Algorithm (may not fill every pixel) //int d = 3 - (2*i); @@ -762,8 +782,8 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) } break; case M12_pCorner: - for (int x = 0; x <= i; x++) setPixelColorXY(x, i, col); - for (int y = 0; y < i; y++) setPixelColorXY(i, y, col); + for (int x = 0; x <= i; x++) setPixelColorXY(x, i, col, false); + for (int y = 0; y < i; y++) setPixelColorXY(i, y, col, false); break; case M12_sPinwheel: { // i = angle --> 0 - 296 (Big), 0 - 192 (Medium), 0 - 72 (Small) @@ -802,7 +822,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) int x = posx / Fixed_Scale; int y = posy / Fixed_Scale; // set pixel - if (x != lastX || y != lastY) setPixelColorXY(x, y, col); // only paint if pixel position is different + if (x != lastX || y != lastY) setPixelColorXY(x, y, col, false); // only paint if pixel position is different lastX = x; lastY = y; // advance to next position @@ -813,12 +833,12 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) } } return; - } else if (Segment::maxHeight!=1 && (width()==1 || height()==1)) { + } else if (Segment::maxHeight != 1 && (width() == 1 || height() == 1)) { if (start < Segment::maxWidth*Segment::maxHeight) { // we have a vertical or horizontal 1D segment (WARNING: virtual...() may be transposed) int x = 0, y = 0; - if (virtualHeight()>1) y = i; - if (virtualWidth() >1) x = i; + if (vHeight() > 1) y = i; + if (vWidth() > 1) x = i; setPixelColorXY(x, y, col); return; } @@ -826,10 +846,8 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) #endif unsigned len = length(); - uint8_t _bri_t = currentBri(); - if (_bri_t < 255) { - col = color_fade(col, _bri_t); - } + // if color is unscaled + if (unScaled) col = color_fade(col, currentBri()); // expand pixel (taking into account start, grouping, spacing [and offset]) i = i * groupLength(); @@ -907,8 +925,8 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const #ifndef WLED_DISABLE_2D if (is2D()) { - int vH = virtualHeight(); // segment height in logical pixels - int vW = virtualWidth(); + const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) + const int vH = vHeight(); // segment height in logical pixels (is always >= 1) switch (map1D2D) { case M12_Pixels: return getPixelColorXY(i % vW, i / vW); @@ -961,7 +979,7 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const } #endif - if (reverse) i = virtualLength() - i - 1; + if (reverse) i = vLength() - i - 1; i *= groupLength(); i += start; // offset/phase @@ -1050,11 +1068,13 @@ void Segment::refreshLightCapabilities() { */ void Segment::fill(uint32_t c) { if (!isActive()) return; // not active - const int cols = is2D() ? virtualWidth() : virtualLength(); - const int rows = virtualHeight(); // will be 1 for 1D + const int cols = is2D() ? vWidth() : vLength(); + const int rows = vHeight(); // will be 1 for 1D + // pre-scale color for all pixels + c = color_fade(c, currentBri()); for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) { - if (is2D()) setPixelColorXY(x, y, c); - else setPixelColor(x, c); + if (is2D()) setPixelColorXY(x, y, c, false); + else setPixelColor(x, c, false); } } @@ -1063,8 +1083,8 @@ void Segment::fill(uint32_t c) { */ void Segment::fade_out(uint8_t rate) { if (!isActive()) return; // not active - const int cols = is2D() ? virtualWidth() : virtualLength(); - const int rows = virtualHeight(); // will be 1 for 1D + const int cols = is2D() ? vWidth() : vLength(); + const int rows = vHeight(); // will be 1 for 1D rate = (255-rate) >> 1; float mappedRate = 1.0f / (float(rate) + 1.1f); @@ -1102,8 +1122,8 @@ void Segment::fade_out(uint8_t rate) { // fades all pixels to black using nscale8() void Segment::fadeToBlackBy(uint8_t fadeBy) { if (!isActive() || fadeBy == 0) return; // optimization - no scaling to apply - const int cols = is2D() ? virtualWidth() : virtualLength(); - const int rows = virtualHeight(); // will be 1 for 1D + const int cols = is2D() ? vWidth() : vLength(); + const int rows = vHeight(); // will be 1 for 1D for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) { if (is2D()) setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), 255-fadeBy)); @@ -1126,7 +1146,7 @@ void Segment::blur(uint8_t blur_amount, bool smear) { #endif uint8_t keep = smear ? 255 : 255 - blur_amount; uint8_t seep = blur_amount >> (1 + smear); - unsigned vlength = virtualLength(); + unsigned vlength = vLength(); uint32_t carryover = BLACK; uint32_t lastnew; uint32_t last; @@ -1140,8 +1160,7 @@ void Segment::blur(uint8_t blur_amount, bool smear) { uint32_t prev = color_add(lastnew, part); // optimization: only set pixel if color has changed if (last != prev) setPixelColor(i - 1, prev); - } else // first pixel - setPixelColor(i, curnew); + } else setPixelColor(i, curnew); // first pixel lastnew = curnew; last = cur; // save original value for comparison on next iteration carryover = part; @@ -1156,7 +1175,7 @@ void Segment::blur(uint8_t blur_amount, bool smear) { */ uint32_t Segment::color_wheel(uint8_t pos) const { if (palette) return color_from_palette(pos, false, true, 0); // perhaps "strip.paletteBlend < 2" should be better instead of "true" - uint8_t w = W(currentColor(0)); + uint8_t w = W(getCurrentColor(0)); pos = 255 - pos; if (pos < 85) { return RGBW32((255 - pos * 3), 0, (pos * 3), w); @@ -1179,20 +1198,19 @@ uint32_t Segment::color_wheel(uint8_t pos) const { * @returns Single color from palette */ uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) const { - - uint32_t color = currentColor(mcol); + uint32_t color = getCurrentColor(mcol < NUM_COLORS ? mcol : 0); // default palette or no RGB support on segment if ((palette == 0 && mcol < NUM_COLORS) || !_isRGB) { - color = gamma32(color); - return (pbri == 255) ? color : color_fade(color, pbri, true); + return color_fade(color, pbri, true); } + const int vL = vLength(); unsigned paletteIndex = i; - if (mapping && virtualLength() > 1) paletteIndex = (i*255)/(virtualLength() -1); + if (mapping && vL > 1) paletteIndex = (i*255)/(vL -1); // paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined) if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end" CRGBW palcol = ColorFromPalette(_currentPalette, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global - palcol.w = gamma8(W(color)); + palcol.w = W(color); return palcol.color32; } @@ -1359,11 +1377,6 @@ void WS2812FX::service() { if (!seg.freeze) { //only run effect function if not frozen int oldCCT = BusManager::getSegmentCCT(); // store original CCT value (actually it is not Segment based) - _virtualSegmentLength = seg.virtualLength(); //SEGLEN - _colors_t[0] = gamma32(seg.currentColor(0)); - _colors_t[1] = gamma32(seg.currentColor(1)); - _colors_t[2] = gamma32(seg.currentColor(2)); - seg.setCurrentPalette(); // load actual palette // when correctWB is true we need to correct/adjust RGB value according to desired CCT value, but it will also affect actual WW/CW ratio // when cctFromRgb is true we implicitly calculate WW and CW from RGB values if (cctFromRgb) BusManager::setSegmentCCT(-1); @@ -1375,13 +1388,14 @@ void WS2812FX::service() { // overwritten by later effect. To enable seamless blending for every effect, additional LED buffer // would need to be allocated for each effect and then blended together for each pixel. [[maybe_unused]] uint8_t tmpMode = seg.currentMode(); // this will return old mode while in transition + seg.beginDraw(); // set up parameters for get/setPixelColor() delay = (*_mode[seg.mode])(); // run new/current mode #ifndef WLED_DISABLE_MODE_BLEND if (modeBlending && seg.mode != tmpMode) { Segment::tmpsegd_t _tmpSegData; Segment::modeBlend(true); // set semaphore seg.swapSegenv(_tmpSegData); // temporarily store new mode state (and swap it with transitional state) - _virtualSegmentLength = seg.virtualLength(); // update SEGLEN (mapping may have changed) + seg.beginDraw(); // set up parameters for get/setPixelColor() unsigned d2 = (*_mode[tmpMode])(); // run old mode seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state) delay = MIN(delay,d2); // use shortest delay @@ -1397,7 +1411,6 @@ void WS2812FX::service() { } _segment_index++; } - _virtualSegmentLength = 0; _isServicing = false; _triggered = false; diff --git a/wled00/udp.cpp b/wled00/udp.cpp index 60774d70..a615cefc 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -416,18 +416,18 @@ void realtimeLock(uint32_t timeoutMs, byte md) start = mainseg.start; stop = mainseg.stop; mainseg.freeze = true; + // if WLED was off and using main segment only, freeze non-main segments so they stay off + if (bri == 0) { + for (size_t s = 0; s < strip.getSegmentsNum(); s++) { + strip.getSegment(s).freeze = true; + } + } } else { start = 0; stop = strip.getLengthTotal(); } // clear strip/segment for (size_t i = start; i < stop; i++) strip.setPixelColor(i,BLACK); - // if WLED was off and using main segment only, freeze non-main segments so they stay off - if (useMainSegmentOnly && bri == 0) { - for (size_t s=0; s < strip.getSegmentsNum(); s++) { - strip.getSegment(s).freeze = true; - } - } } // if strip is off (bri==0) and not already in RTM if (briT == 0 && !realtimeMode && !realtimeOverride) { @@ -510,12 +510,10 @@ void handleNotifications() rgbUdp.read(lbuf, packetSize); realtimeLock(realtimeTimeoutMs, REALTIME_MODE_HYPERION); if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return; - unsigned id = 0; unsigned totalLen = strip.getLengthTotal(); - for (size_t i = 0; i < packetSize -2; i += 3) - { + if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); // set up parameters for get/setPixelColor() + for (size_t i = 0, id = 0; i < packetSize -2 && id < totalLen; i += 3, id++) { setRealtimePixel(id, lbuf[i], lbuf[i+1], lbuf[i+2], 0); - id++; if (id >= totalLen) break; } if (!(realtimeMode && useMainSegmentOnly)) strip.show(); return; @@ -595,17 +593,11 @@ void handleNotifications() unsigned id = (tpmPayloadFrameSize/3)*(packetNum-1); //start LED unsigned totalLen = strip.getLengthTotal(); - for (size_t i = 6; i < tpmPayloadFrameSize + 4U; i += 3) - { - if (id < totalLen) - { - setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0); - id++; - } - else break; + if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); // set up parameters for get/setPixelColor() + for (size_t i = 6; i < tpmPayloadFrameSize + 4U && id < totalLen; i += 3, id++) { + setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0); } - if (tpmPacketCount == numPackets) //reset packet count and show if all packets were received - { + if (tpmPacketCount == numPackets) { //reset packet count and show if all packets were received tpmPacketCount = 0; strip.show(); } @@ -629,6 +621,7 @@ void handleNotifications() if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return; unsigned totalLen = strip.getLengthTotal(); + if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); // set up parameters for get/setPixelColor() if (udpIn[0] == 1 && packetSize > 5) //warls { for (size_t i = 2; i < packetSize -3; i += 4) @@ -637,39 +630,29 @@ void handleNotifications() } } else if (udpIn[0] == 2 && packetSize > 4) //drgb { - unsigned id = 0; - for (size_t i = 2; i < packetSize -2; i += 3) + for (size_t i = 2, id = 0; i < packetSize -2 && id < totalLen; i += 3, id++) { setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0); - - id++; if (id >= totalLen) break; } } else if (udpIn[0] == 3 && packetSize > 6) //drgbw { - unsigned id = 0; - for (size_t i = 2; i < packetSize -3; i += 4) + for (size_t i = 2, id = 0; i < packetSize -3 && id < totalLen; i += 4, id++) { setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]); - - id++; if (id >= totalLen) break; } } else if (udpIn[0] == 4 && packetSize > 7) //dnrgb { unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00); - for (size_t i = 4; i < packetSize -2; i += 3) + for (size_t i = 4; i < packetSize -2 && id < totalLen; i += 3, id++) { - if (id >= totalLen) break; setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0); - id++; } } else if (udpIn[0] == 5 && packetSize > 8) //dnrgbw { unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00); - for (size_t i = 4; i < packetSize -2; i += 4) + for (size_t i = 4; i < packetSize -2 && id < totalLen; i += 4, id++) { - if (id >= totalLen) break; setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]); - id++; } } strip.show(); @@ -705,8 +688,7 @@ void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w) w = gamma8(w); } if (useMainSegmentOnly) { - Segment &seg = strip.getMainSegment(); - if (pix10) return; + char nS[32]; if (subPage == SUBPAGE_MENU) { @@ -259,8 +260,6 @@ void getSettingsJS(byte subPage, Print& settingsScript) if (subPage == SUBPAGE_LEDS) { - char nS[32]; - appendGPIOinfo(settingsScript); settingsScript.print(SET_F("d.ledTypes=")); settingsScript.print(BusManager::getLEDTypesJSONString().c_str()); settingsScript.print(";"); @@ -399,7 +398,6 @@ void getSettingsJS(byte subPage, Print& settingsScript) if (subPage == SUBPAGE_SYNC) { - [[maybe_unused]] char nS[32]; printSetFormValue(settingsScript,PSTR("UP"),udpPort); printSetFormValue(settingsScript,PSTR("U2"),udpPort2); #ifndef WLED_DISABLE_ESPNOW From 9114867578477e4cf5fa652769ea0690503c5f10 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sat, 28 Sep 2024 18:48:43 +0200 Subject: [PATCH 041/463] Fix compiler error --- wled00/FX.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.h b/wled00/FX.h index 98082c8d..b4aaf3c4 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -833,7 +833,7 @@ class WS2812FX { // 96 bytes addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name); // add effect to the list; defined in FX.cpp; inline uint8_t getBrightness() const { return _brightness; } // returns current strip brightness - inline constexpr unsigned getMaxSegments() { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value) + inline static constexpr unsigned getMaxSegments() { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value) inline uint8_t getSegmentsNum() const { return _segments.size(); } // returns currently present segments inline uint8_t getCurrSegmentId() const { return _segment_index; } // returns current segment index (only valid while strip.isServicing()) inline uint8_t getMainSegmentId() const { return _mainSegment; } // returns main segment index From cc87b32206e602adc1a3c34f659ca5498fdd269a Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sat, 28 Sep 2024 10:02:05 -0400 Subject: [PATCH 042/463] Support PWM phase shifts on ESP8266 Use the phase-locked soft PWM from the Arduino core to implement the same PWM phase management as ESP32s are using. The soft PWM code is vendored in, as it was previously, to add the NMI workaround from #4035. Completes #4034 --- .../src/core_esp8266_waveform_phase.cpp | 478 ++++++++++++ .../src/core_esp8266_waveform_pwm.cpp | 717 ------------------ wled00/bus_manager.cpp | 46 +- 3 files changed, 507 insertions(+), 734 deletions(-) create mode 100644 lib/ESP8266PWM/src/core_esp8266_waveform_phase.cpp delete mode 100644 lib/ESP8266PWM/src/core_esp8266_waveform_pwm.cpp diff --git a/lib/ESP8266PWM/src/core_esp8266_waveform_phase.cpp b/lib/ESP8266PWM/src/core_esp8266_waveform_phase.cpp new file mode 100644 index 00000000..b846091b --- /dev/null +++ b/lib/ESP8266PWM/src/core_esp8266_waveform_phase.cpp @@ -0,0 +1,478 @@ +/* esp8266_waveform imported from platform source code + Modified for WLED to work around a fault in the NMI handling, + which can result in the system locking up and hard WDT crashes. + + Imported from https://github.com/esp8266/Arduino/blob/7e0d20e2b9034994f573a236364e0aef17fd66de/cores/esp8266/core_esp8266_waveform_phase.cpp +*/ + + +/* + esp8266_waveform - General purpose waveform generation and control, + supporting outputs on all pins in parallel. + + Copyright (c) 2018 Earle F. Philhower, III. All rights reserved. + Copyright (c) 2020 Dirk O. Kaar. + + The core idea is to have a programmable waveform generator with a unique + high and low period (defined in microseconds or CPU clock cycles). TIMER1 is + set to 1-shot mode and is always loaded with the time until the next edge + of any live waveforms. + + Up to one waveform generator per pin supported. + + Each waveform generator is synchronized to the ESP clock cycle counter, not the + timer. This allows for removing interrupt jitter and delay as the counter + always increments once per 80MHz clock. Changes to a waveform are + contiguous and only take effect on the next waveform transition, + allowing for smooth transitions. + + This replaces older tone(), analogWrite(), and the Servo classes. + + Everywhere in the code where "ccy" or "ccys" is used, it means ESP.getCycleCount() + clock cycle time, or an interval measured in clock cycles, but not TIMER1 + cycles (which may be 2 CPU clock cycles @ 160MHz). + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "core_esp8266_waveform.h" +#include +#include "debug.h" +#include "ets_sys.h" +#include + + +// ----- @willmmiles begin patch ----- +// Linker magic +extern "C" void usePWMFixedNMI(void) {}; + +// NMI crash workaround +// Sometimes the NMI fails to return, stalling the CPU. When this happens, +// the next NMI gets a return address /inside the NMI handler function/. +// We work around this by caching the last NMI return address, and restoring +// the epc3 and eps3 registers to the previous values if the observed epc3 +// happens to be pointing to the _NMILevelVector function. +extern "C" void _NMILevelVector(); +extern "C" void _UserExceptionVector_1(); // the next function after _NMILevelVector +static inline IRAM_ATTR void nmiCrashWorkaround() { + static uintptr_t epc3_backup, eps3_backup; + + uintptr_t epc3, eps3; + __asm__ __volatile__("rsr %0,epc3; rsr %1,eps3":"=a"(epc3),"=a" (eps3)); + if ((epc3 < (uintptr_t) &_NMILevelVector) || (epc3 >= (uintptr_t) &_UserExceptionVector_1)) { + // Address is good; save backup + epc3_backup = epc3; + eps3_backup = eps3; + } else { + // Address is inside the NMI handler -- restore from backup + __asm__ __volatile__("wsr %0,epc3; wsr %1,eps3"::"a"(epc3_backup),"a"(eps3_backup)); + } +} +// ----- @willmmiles end patch ----- + + +// No-op calls to override the PWM implementation +extern "C" void _setPWMFreq_weak(uint32_t freq) { (void) freq; } +extern "C" IRAM_ATTR bool _stopPWM_weak(int pin) { (void) pin; return false; } +extern "C" bool _setPWM_weak(int pin, uint32_t val, uint32_t range) { (void) pin; (void) val; (void) range; return false; } + + +// Timer is 80MHz fixed. 160MHz CPU frequency need scaling. +constexpr bool ISCPUFREQ160MHZ = clockCyclesPerMicrosecond() == 160; +// Maximum delay between IRQs, Timer1, <= 2^23 / 80MHz +constexpr int32_t MAXIRQTICKSCCYS = microsecondsToClockCycles(10000); +// Maximum servicing time for any single IRQ +constexpr uint32_t ISRTIMEOUTCCYS = microsecondsToClockCycles(18); +// The latency between in-ISR rearming of the timer and the earliest firing +constexpr int32_t IRQLATENCYCCYS = microsecondsToClockCycles(2); +// The SDK and hardware take some time to actually get to our NMI code +constexpr int32_t DELTAIRQCCYS = ISCPUFREQ160MHZ ? + microsecondsToClockCycles(2) >> 1 : microsecondsToClockCycles(2); + +// for INFINITE, the NMI proceeds on the waveform without expiry deadline. +// for EXPIRES, the NMI expires the waveform automatically on the expiry ccy. +// for UPDATEEXPIRY, the NMI recomputes the exact expiry ccy and transitions to EXPIRES. +// for INIT, the NMI initializes nextPeriodCcy, and if expiryCcy != 0 includes UPDATEEXPIRY. +enum class WaveformMode : uint8_t {INFINITE = 0, EXPIRES = 1, UPDATEEXPIRY = 2, INIT = 3}; + +// Waveform generator can create tones, PWM, and servos +typedef struct { + uint32_t nextPeriodCcy; // ESP clock cycle when a period begins. If WaveformMode::INIT, temporarily holds positive phase offset ccy count + uint32_t endDutyCcy; // ESP clock cycle when going from duty to off + int32_t dutyCcys; // Set next off cycle at low->high to maintain phase + int32_t adjDutyCcys; // Temporary correction for next period + int32_t periodCcys; // Set next phase cycle at low->high to maintain phase + uint32_t expiryCcy; // For time-limited waveform, the CPU clock cycle when this waveform must stop. If WaveformMode::UPDATE, temporarily holds relative ccy count + WaveformMode mode; + int8_t alignPhase; // < 0 no phase alignment, otherwise starts waveform in relative phase offset to given pin + bool autoPwm; // perform PWM duty to idle cycle ratio correction under high load at the expense of precise timings +} Waveform; + +namespace { + + static struct { + Waveform pins[17]; // State of all possible pins + uint32_t states = 0; // Is the pin high or low, updated in NMI so no access outside the NMI code + uint32_t enabled = 0; // Is it actively running, updated in NMI so no access outside the NMI code + + // Enable lock-free by only allowing updates to waveform.states and waveform.enabled from IRQ service routine + int32_t toSetBits = 0; // Message to the NMI handler to start/modify exactly one waveform + int32_t toDisableBits = 0; // Message to the NMI handler to disable exactly one pin from waveform generation + + uint32_t(*timer1CB)() = nullptr; + + bool timer1Running = false; + + uint32_t nextEventCcy; + } waveform; + +} + +// Interrupt on/off control +static IRAM_ATTR void timer1Interrupt(); + +// Non-speed critical bits +#pragma GCC optimize ("Os") + +static void initTimer() { + timer1_disable(); + ETS_FRC_TIMER1_INTR_ATTACH(NULL, NULL); + ETS_FRC_TIMER1_NMI_INTR_ATTACH(timer1Interrupt); + timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE); + waveform.timer1Running = true; + timer1_write(IRQLATENCYCCYS); // Cause an interrupt post-haste +} + +static void IRAM_ATTR deinitTimer() { + ETS_FRC_TIMER1_NMI_INTR_ATTACH(NULL); + timer1_disable(); + timer1_isr_init(); + waveform.timer1Running = false; +} + +extern "C" { + +// Set a callback. Pass in NULL to stop it +void setTimer1Callback_weak(uint32_t (*fn)()) { + waveform.timer1CB = fn; + std::atomic_thread_fence(std::memory_order_acq_rel); + if (!waveform.timer1Running && fn) { + initTimer(); + } else if (waveform.timer1Running && !fn && !waveform.enabled) { + deinitTimer(); + } +} + +// Start up a waveform on a pin, or change the current one. Will change to the new +// waveform smoothly on next low->high transition. For immediate change, stopWaveform() +// first, then it will immediately begin. +int startWaveformClockCycles_weak(uint8_t pin, uint32_t highCcys, uint32_t lowCcys, + uint32_t runTimeCcys, int8_t alignPhase, uint32_t phaseOffsetCcys, bool autoPwm) { + uint32_t periodCcys = highCcys + lowCcys; + if (periodCcys < MAXIRQTICKSCCYS) { + if (!highCcys) { + periodCcys = (MAXIRQTICKSCCYS / periodCcys) * periodCcys; + } + else if (!lowCcys) { + highCcys = periodCcys = (MAXIRQTICKSCCYS / periodCcys) * periodCcys; + } + } + // sanity checks, including mixed signed/unsigned arithmetic safety + if ((pin > 16) || isFlashInterfacePin(pin) || (alignPhase > 16) || + static_cast(periodCcys) <= 0 || + static_cast(highCcys) < 0 || static_cast(lowCcys) < 0) { + return false; + } + Waveform& wave = waveform.pins[pin]; + wave.dutyCcys = highCcys; + wave.adjDutyCcys = 0; + wave.periodCcys = periodCcys; + wave.autoPwm = autoPwm; + + std::atomic_thread_fence(std::memory_order_acquire); + const uint32_t pinBit = 1UL << pin; + if (!(waveform.enabled & pinBit)) { + // wave.nextPeriodCcy and wave.endDutyCcy are initialized by the ISR + wave.nextPeriodCcy = phaseOffsetCcys; + wave.expiryCcy = runTimeCcys; // in WaveformMode::INIT, temporarily hold relative cycle count + wave.mode = WaveformMode::INIT; + wave.alignPhase = (alignPhase < 0) ? -1 : alignPhase; + if (!wave.dutyCcys) { + // If initially at zero duty cycle, force GPIO off + if (pin == 16) { + GP16O = 0; + } + else { + GPOC = pinBit; + } + } + std::atomic_thread_fence(std::memory_order_release); + waveform.toSetBits = 1UL << pin; + std::atomic_thread_fence(std::memory_order_release); + if (!waveform.timer1Running) { + initTimer(); + } + else if (T1V > IRQLATENCYCCYS) { + // Must not interfere if Timer is due shortly + timer1_write(IRQLATENCYCCYS); + } + } + else { + wave.mode = WaveformMode::INFINITE; // turn off possible expiry to make update atomic from NMI + std::atomic_thread_fence(std::memory_order_release); + wave.expiryCcy = runTimeCcys; // in WaveformMode::UPDATEEXPIRY, temporarily hold relative cycle count + if (runTimeCcys) { + wave.mode = WaveformMode::UPDATEEXPIRY; + std::atomic_thread_fence(std::memory_order_release); + waveform.toSetBits = 1UL << pin; + } + } + std::atomic_thread_fence(std::memory_order_acq_rel); + while (waveform.toSetBits) { + esp_yield(); // Wait for waveform to update + std::atomic_thread_fence(std::memory_order_acquire); + } + return true; +} + +// Stops a waveform on a pin +IRAM_ATTR int stopWaveform_weak(uint8_t pin) { + // Can't possibly need to stop anything if there is no timer active + if (!waveform.timer1Running) { + return false; + } + // If user sends in a pin >16 but <32, this will always point to a 0 bit + // If they send >=32, then the shift will result in 0 and it will also return false + std::atomic_thread_fence(std::memory_order_acquire); + const uint32_t pinBit = 1UL << pin; + if (waveform.enabled & pinBit) { + waveform.toDisableBits = 1UL << pin; + std::atomic_thread_fence(std::memory_order_release); + // Must not interfere if Timer is due shortly + if (T1V > IRQLATENCYCCYS) { + timer1_write(IRQLATENCYCCYS); + } + while (waveform.toDisableBits) { + /* no-op */ // Can't delay() since stopWaveform may be called from an IRQ + std::atomic_thread_fence(std::memory_order_acquire); + } + } + if (!waveform.enabled && !waveform.timer1CB) { + deinitTimer(); + } + return true; +} + +}; + +// Speed critical bits +#pragma GCC optimize ("O2") + +// For dynamic CPU clock frequency switch in loop the scaling logic would have to be adapted. +// Using constexpr makes sure that the CPU clock frequency is compile-time fixed. +static inline IRAM_ATTR int32_t scaleCcys(const int32_t ccys, const bool isCPU2X) { + if (ISCPUFREQ160MHZ) { + return isCPU2X ? ccys : (ccys >> 1); + } + else { + return isCPU2X ? (ccys << 1) : ccys; + } +} + +static IRAM_ATTR void timer1Interrupt() { + // ----- @willmmiles begin patch ----- + nmiCrashWorkaround(); + // ----- @willmmiles end patch ----- + + const uint32_t isrStartCcy = ESP.getCycleCount(); + int32_t clockDrift = isrStartCcy - waveform.nextEventCcy; + const bool isCPU2X = CPU2X & 1; + if ((waveform.toSetBits && !(waveform.enabled & waveform.toSetBits)) || waveform.toDisableBits) { + // Handle enable/disable requests from main app. + waveform.enabled = (waveform.enabled & ~waveform.toDisableBits) | waveform.toSetBits; // Set the requested waveforms on/off + // Find the first GPIO being generated by checking GCC's find-first-set (returns 1 + the bit of the first 1 in an int32_t) + waveform.toDisableBits = 0; + } + + if (waveform.toSetBits) { + const int toSetPin = __builtin_ffs(waveform.toSetBits) - 1; + Waveform& wave = waveform.pins[toSetPin]; + switch (wave.mode) { + case WaveformMode::INIT: + waveform.states &= ~waveform.toSetBits; // Clear the state of any just started + if (wave.alignPhase >= 0 && waveform.enabled & (1UL << wave.alignPhase)) { + wave.nextPeriodCcy = waveform.pins[wave.alignPhase].nextPeriodCcy + wave.nextPeriodCcy; + } + else { + wave.nextPeriodCcy = waveform.nextEventCcy; + } + if (!wave.expiryCcy) { + wave.mode = WaveformMode::INFINITE; + break; + } + // fall through + case WaveformMode::UPDATEEXPIRY: + // in WaveformMode::UPDATEEXPIRY, expiryCcy temporarily holds relative CPU cycle count + wave.expiryCcy = wave.nextPeriodCcy + scaleCcys(wave.expiryCcy, isCPU2X); + wave.mode = WaveformMode::EXPIRES; + break; + default: + break; + } + waveform.toSetBits = 0; + } + + // Exit the loop if the next event, if any, is sufficiently distant. + const uint32_t isrTimeoutCcy = isrStartCcy + ISRTIMEOUTCCYS; + uint32_t busyPins = waveform.enabled; + waveform.nextEventCcy = isrStartCcy + MAXIRQTICKSCCYS; + + uint32_t now = ESP.getCycleCount(); + uint32_t isrNextEventCcy = now; + while (busyPins) { + if (static_cast(isrNextEventCcy - now) > IRQLATENCYCCYS) { + waveform.nextEventCcy = isrNextEventCcy; + break; + } + isrNextEventCcy = waveform.nextEventCcy; + uint32_t loopPins = busyPins; + while (loopPins) { + const int pin = __builtin_ffsl(loopPins) - 1; + const uint32_t pinBit = 1UL << pin; + loopPins ^= pinBit; + + Waveform& wave = waveform.pins[pin]; + + if (clockDrift) { + wave.endDutyCcy += clockDrift; + wave.nextPeriodCcy += clockDrift; + wave.expiryCcy += clockDrift; + } + + uint32_t waveNextEventCcy = (waveform.states & pinBit) ? wave.endDutyCcy : wave.nextPeriodCcy; + if (WaveformMode::EXPIRES == wave.mode && + static_cast(waveNextEventCcy - wave.expiryCcy) >= 0 && + static_cast(now - wave.expiryCcy) >= 0) { + // Disable any waveforms that are done + waveform.enabled ^= pinBit; + busyPins ^= pinBit; + } + else { + const int32_t overshootCcys = now - waveNextEventCcy; + if (overshootCcys >= 0) { + const int32_t periodCcys = scaleCcys(wave.periodCcys, isCPU2X); + if (waveform.states & pinBit) { + // active configuration and forward are 100% duty + if (wave.periodCcys == wave.dutyCcys) { + wave.nextPeriodCcy += periodCcys; + wave.endDutyCcy = wave.nextPeriodCcy; + } + else { + if (wave.autoPwm) { + wave.adjDutyCcys += overshootCcys; + } + waveform.states ^= pinBit; + if (16 == pin) { + GP16O = 0; + } + else { + GPOC = pinBit; + } + } + waveNextEventCcy = wave.nextPeriodCcy; + } + else { + wave.nextPeriodCcy += periodCcys; + if (!wave.dutyCcys) { + wave.endDutyCcy = wave.nextPeriodCcy; + } + else { + int32_t dutyCcys = scaleCcys(wave.dutyCcys, isCPU2X); + if (dutyCcys <= wave.adjDutyCcys) { + dutyCcys >>= 1; + wave.adjDutyCcys -= dutyCcys; + } + else if (wave.adjDutyCcys) { + dutyCcys -= wave.adjDutyCcys; + wave.adjDutyCcys = 0; + } + wave.endDutyCcy = now + dutyCcys; + if (static_cast(wave.endDutyCcy - wave.nextPeriodCcy) > 0) { + wave.endDutyCcy = wave.nextPeriodCcy; + } + waveform.states |= pinBit; + if (16 == pin) { + GP16O = 1; + } + else { + GPOS = pinBit; + } + } + waveNextEventCcy = wave.endDutyCcy; + } + + if (WaveformMode::EXPIRES == wave.mode && static_cast(waveNextEventCcy - wave.expiryCcy) > 0) { + waveNextEventCcy = wave.expiryCcy; + } + } + + if (static_cast(waveNextEventCcy - isrTimeoutCcy) >= 0) { + busyPins ^= pinBit; + if (static_cast(waveform.nextEventCcy - waveNextEventCcy) > 0) { + waveform.nextEventCcy = waveNextEventCcy; + } + } + else if (static_cast(isrNextEventCcy - waveNextEventCcy) > 0) { + isrNextEventCcy = waveNextEventCcy; + } + } + now = ESP.getCycleCount(); + } + clockDrift = 0; + } + + int32_t callbackCcys = 0; + if (waveform.timer1CB) { + callbackCcys = scaleCcys(waveform.timer1CB(), isCPU2X); + } + now = ESP.getCycleCount(); + int32_t nextEventCcys = waveform.nextEventCcy - now; + // Account for unknown duration of timer1CB(). + if (waveform.timer1CB && nextEventCcys > callbackCcys) { + waveform.nextEventCcy = now + callbackCcys; + nextEventCcys = callbackCcys; + } + + // Timer is 80MHz fixed. 160MHz CPU frequency need scaling. + int32_t deltaIrqCcys = DELTAIRQCCYS; + int32_t irqLatencyCcys = IRQLATENCYCCYS; + if (isCPU2X) { + nextEventCcys >>= 1; + deltaIrqCcys >>= 1; + irqLatencyCcys >>= 1; + } + + // Firing timer too soon, the NMI occurs before ISR has returned. + if (nextEventCcys < irqLatencyCcys + deltaIrqCcys) { + waveform.nextEventCcy = now + IRQLATENCYCCYS + DELTAIRQCCYS; + nextEventCcys = irqLatencyCcys; + } + else { + nextEventCcys -= deltaIrqCcys; + } + + // Register access is fast and edge IRQ was configured before. + T1L = nextEventCcys; +} diff --git a/lib/ESP8266PWM/src/core_esp8266_waveform_pwm.cpp b/lib/ESP8266PWM/src/core_esp8266_waveform_pwm.cpp deleted file mode 100644 index 78c7160d..00000000 --- a/lib/ESP8266PWM/src/core_esp8266_waveform_pwm.cpp +++ /dev/null @@ -1,717 +0,0 @@ -/* esp8266_waveform imported from platform source code - Modified for WLED to work around a fault in the NMI handling, - which can result in the system locking up and hard WDT crashes. - - Imported from https://github.com/esp8266/Arduino/blob/7e0d20e2b9034994f573a236364e0aef17fd66de/cores/esp8266/core_esp8266_waveform_pwm.cpp -*/ - -/* - esp8266_waveform - General purpose waveform generation and control, - supporting outputs on all pins in parallel. - - Copyright (c) 2018 Earle F. Philhower, III. All rights reserved. - - The core idea is to have a programmable waveform generator with a unique - high and low period (defined in microseconds or CPU clock cycles). TIMER1 - is set to 1-shot mode and is always loaded with the time until the next - edge of any live waveforms. - - Up to one waveform generator per pin supported. - - Each waveform generator is synchronized to the ESP clock cycle counter, not - the timer. This allows for removing interrupt jitter and delay as the - counter always increments once per 80MHz clock. Changes to a waveform are - contiguous and only take effect on the next waveform transition, - allowing for smooth transitions. - - This replaces older tone(), analogWrite(), and the Servo classes. - - Everywhere in the code where "cycles" is used, it means ESP.getCycleCount() - clock cycle count, or an interval measured in CPU clock cycles, but not - TIMER1 cycles (which may be 2 CPU clock cycles @ 160MHz). - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - - -#include -#include -#include "ets_sys.h" -#include "core_esp8266_waveform.h" -#include "user_interface.h" - -extern "C" { - -// Linker magic -void usePWMFixedNMI() {}; - -// Maximum delay between IRQs -#define MAXIRQUS (10000) - -// Waveform generator can create tones, PWM, and servos -typedef struct { - uint32_t nextServiceCycle; // ESP cycle timer when a transition required - uint32_t expiryCycle; // For time-limited waveform, the cycle when this waveform must stop - uint32_t timeHighCycles; // Actual running waveform period (adjusted using desiredCycles) - uint32_t timeLowCycles; // - uint32_t desiredHighCycles; // Ideal waveform period to drive the error signal - uint32_t desiredLowCycles; // - uint32_t lastEdge; // Cycle when this generator last changed -} Waveform; - -class WVFState { -public: - Waveform waveform[17]; // State of all possible pins - uint32_t waveformState = 0; // Is the pin high or low, updated in NMI so no access outside the NMI code - uint32_t waveformEnabled = 0; // Is it actively running, updated in NMI so no access outside the NMI code - - // Enable lock-free by only allowing updates to waveformState and waveformEnabled from IRQ service routine - uint32_t waveformToEnable = 0; // Message to the NMI handler to start a waveform on a inactive pin - uint32_t waveformToDisable = 0; // Message to the NMI handler to disable a pin from waveform generation - - uint32_t waveformToChange = 0; // Mask of pin to change. One bit set in main app, cleared when effected in the NMI - uint32_t waveformNewHigh = 0; - uint32_t waveformNewLow = 0; - - uint32_t (*timer1CB)() = NULL; - - // Optimize the NMI inner loop by keeping track of the min and max GPIO that we - // are generating. In the common case (1 PWM) these may be the same pin and - // we can avoid looking at the other pins. - uint16_t startPin = 0; - uint16_t endPin = 0; -}; -static WVFState wvfState; - - -// Ensure everything is read/written to RAM -#define MEMBARRIER() { __asm__ volatile("" ::: "memory"); } - -// Non-speed critical bits -#pragma GCC optimize ("Os") - -// Interrupt on/off control -static IRAM_ATTR void timer1Interrupt(); -static bool timerRunning = false; - -static __attribute__((noinline)) void initTimer() { - if (!timerRunning) { - timer1_disable(); - ETS_FRC_TIMER1_INTR_ATTACH(NULL, NULL); - ETS_FRC_TIMER1_NMI_INTR_ATTACH(timer1Interrupt); - timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE); - timerRunning = true; - timer1_write(microsecondsToClockCycles(10)); - } -} - -static IRAM_ATTR void forceTimerInterrupt() { - if (T1L > microsecondsToClockCycles(10)) { - T1L = microsecondsToClockCycles(10); - } -} - -// PWM implementation using special purpose state machine -// -// Keep an ordered list of pins with the delta in cycles between each -// element, with a terminal entry making up the remainder of the PWM -// period. With this method sum(all deltas) == PWM period clock cycles. -// -// At t=0 set all pins high and set the timeout for the 1st edge. -// On interrupt, if we're at the last element reset to t=0 state -// Otherwise, clear that pin down and set delay for next element -// and so forth. - -constexpr int maxPWMs = 8; - -// PWM machine state -typedef struct PWMState { - uint32_t mask; // Bitmask of active pins - uint32_t cnt; // How many entries - uint32_t idx; // Where the state machine is along the list - uint8_t pin[maxPWMs + 1]; - uint32_t delta[maxPWMs + 1]; - uint32_t nextServiceCycle; // Clock cycle for next step - struct PWMState *pwmUpdate; // Set by main code, cleared by ISR -} PWMState; - -static PWMState pwmState; -static uint32_t _pwmFreq = 1000; -static uint32_t _pwmPeriod = microsecondsToClockCycles(1000000UL) / _pwmFreq; - - -// If there are no more scheduled activities, shut down Timer 1. -// Otherwise, do nothing. -static IRAM_ATTR void disableIdleTimer() { - if (timerRunning && !wvfState.waveformEnabled && !pwmState.cnt && !wvfState.timer1CB) { - ETS_FRC_TIMER1_NMI_INTR_ATTACH(NULL); - timer1_disable(); - timer1_isr_init(); - timerRunning = false; - } -} - -// Notify the NMI that a new PWM state is available through the mailbox. -// Wait for mailbox to be emptied (either busy or delay() as needed) -static IRAM_ATTR void _notifyPWM(PWMState *p, bool idle) { - p->pwmUpdate = nullptr; - pwmState.pwmUpdate = p; - MEMBARRIER(); - forceTimerInterrupt(); - while (pwmState.pwmUpdate) { - if (idle) { - esp_yield(); - } - MEMBARRIER(); - } -} - -static void _addPWMtoList(PWMState &p, int pin, uint32_t val, uint32_t range); - - -// Called when analogWriteFreq() changed to update the PWM total period -//extern void _setPWMFreq_weak(uint32_t freq) __attribute__((weak)); -void _setPWMFreq_weak(uint32_t freq) { - _pwmFreq = freq; - - // Convert frequency into clock cycles - uint32_t cc = microsecondsToClockCycles(1000000UL) / freq; - - // Simple static adjustment to bring period closer to requested due to overhead - // Empirically determined as a constant PWM delay and a function of the number of PWMs -#if F_CPU == 80000000 - cc -= ((microsecondsToClockCycles(pwmState.cnt) * 13) >> 4) + 110; -#else - cc -= ((microsecondsToClockCycles(pwmState.cnt) * 10) >> 4) + 75; -#endif - - if (cc == _pwmPeriod) { - return; // No change - } - - _pwmPeriod = cc; - - if (pwmState.cnt) { - PWMState p; // The working copy since we can't edit the one in use - p.mask = 0; - p.cnt = 0; - for (uint32_t i = 0; i < pwmState.cnt; i++) { - auto pin = pwmState.pin[i]; - _addPWMtoList(p, pin, wvfState.waveform[pin].desiredHighCycles, wvfState.waveform[pin].desiredLowCycles); - } - // Update and wait for mailbox to be emptied - initTimer(); - _notifyPWM(&p, true); - disableIdleTimer(); - } -} -/* -static void _setPWMFreq_bound(uint32_t freq) __attribute__((weakref("_setPWMFreq_weak"))); -void _setPWMFreq(uint32_t freq) { - _setPWMFreq_bound(freq); -} -*/ - -// Helper routine to remove an entry from the state machine -// and clean up any marked-off entries -static void _cleanAndRemovePWM(PWMState *p, int pin) { - uint32_t leftover = 0; - uint32_t in, out; - for (in = 0, out = 0; in < p->cnt; in++) { - if ((p->pin[in] != pin) && (p->mask & (1<pin[in]))) { - p->pin[out] = p->pin[in]; - p->delta[out] = p->delta[in] + leftover; - leftover = 0; - out++; - } else { - leftover += p->delta[in]; - p->mask &= ~(1<pin[in]); - } - } - p->cnt = out; - // Final pin is never used: p->pin[out] = 0xff; - p->delta[out] = p->delta[in] + leftover; -} - - -// Disable PWM on a specific pin (i.e. when a digitalWrite or analogWrite(0%/100%)) -//extern bool _stopPWM_weak(uint8_t pin) __attribute__((weak)); -IRAM_ATTR bool _stopPWM_weak(uint8_t pin) { - if (!((1<= _pwmPeriod) { - cc = _pwmPeriod - 1; - } - - if (p.cnt == 0) { - // Starting up from scratch, special case 1st element and PWM period - p.pin[0] = pin; - p.delta[0] = cc; - // Final pin is never used: p.pin[1] = 0xff; - p.delta[1] = _pwmPeriod - cc; - } else { - uint32_t ttl = 0; - uint32_t i; - // Skip along until we're at the spot to insert - for (i=0; (i <= p.cnt) && (ttl + p.delta[i] < cc); i++) { - ttl += p.delta[i]; - } - // Shift everything out by one to make space for new edge - for (int32_t j = p.cnt; j >= (int)i; j--) { - p.pin[j + 1] = p.pin[j]; - p.delta[j + 1] = p.delta[j]; - } - int off = cc - ttl; // The delta from the last edge to the one we're inserting - p.pin[i] = pin; - p.delta[i] = off; // Add the delta to this new pin - p.delta[i + 1] -= off; // And subtract it from the follower to keep sum(deltas) constant - } - p.cnt++; - p.mask |= 1<= maxPWMs) { - return false; // No space left - } - - // Sanity check for all-on/off - uint32_t cc = (_pwmPeriod * val) / range; - if ((cc == 0) || (cc >= _pwmPeriod)) { - digitalWrite(pin, cc ? HIGH : LOW); - return true; - } - - _addPWMtoList(p, pin, val, range); - - // Set mailbox and wait for ISR to copy it over - initTimer(); - _notifyPWM(&p, true); - disableIdleTimer(); - - // Potentially recalculate the PWM period if we've added another pin - _setPWMFreq(_pwmFreq); - - return true; -} -/* -static bool _setPWM_bound(int pin, uint32_t val, uint32_t range) __attribute__((weakref("_setPWM_weak"))); -bool _setPWM(int pin, uint32_t val, uint32_t range) { - return _setPWM_bound(pin, val, range); -} -*/ - -// Start up a waveform on a pin, or change the current one. Will change to the new -// waveform smoothly on next low->high transition. For immediate change, stopWaveform() -// first, then it will immediately begin. -//extern int startWaveformClockCycles_weak(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles, int8_t alignPhase, uint32_t phaseOffsetUS, bool autoPwm) __attribute__((weak)); -int startWaveformClockCycles_weak(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles, - int8_t alignPhase, uint32_t phaseOffsetUS, bool autoPwm) { - (void) alignPhase; - (void) phaseOffsetUS; - (void) autoPwm; - - if ((pin > 16) || isFlashInterfacePin(pin) || (timeHighCycles == 0)) { - return false; - } - Waveform *wave = &wvfState.waveform[pin]; - wave->expiryCycle = runTimeCycles ? ESP.getCycleCount() + runTimeCycles : 0; - if (runTimeCycles && !wave->expiryCycle) { - wave->expiryCycle = 1; // expiryCycle==0 means no timeout, so avoid setting it - } - - _stopPWM(pin); // Make sure there's no PWM live here - - uint32_t mask = 1<timeHighCycles = timeHighCycles; - wave->desiredHighCycles = timeHighCycles; - wave->timeLowCycles = timeLowCycles; - wave->desiredLowCycles = timeLowCycles; - wave->lastEdge = 0; - wave->nextServiceCycle = ESP.getCycleCount() + microsecondsToClockCycles(1); - wvfState.waveformToEnable |= mask; - MEMBARRIER(); - initTimer(); - forceTimerInterrupt(); - while (wvfState.waveformToEnable) { - esp_yield(); // Wait for waveform to update - MEMBARRIER(); - } - } - - return true; -} -/* -static int startWaveformClockCycles_bound(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles, int8_t alignPhase, uint32_t phaseOffsetUS, bool autoPwm) __attribute__((weakref("startWaveformClockCycles_weak"))); -int startWaveformClockCycles(uint8_t pin, uint32_t timeHighCycles, uint32_t timeLowCycles, uint32_t runTimeCycles, int8_t alignPhase, uint32_t phaseOffsetUS, bool autoPwm) { - return startWaveformClockCycles_bound(pin, timeHighCycles, timeLowCycles, runTimeCycles, alignPhase, phaseOffsetUS, autoPwm); -} - - -// This version falls-thru to the proper startWaveformClockCycles call and is invariant across waveform generators -int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS, - int8_t alignPhase, uint32_t phaseOffsetUS, bool autoPwm) { - return startWaveformClockCycles_bound(pin, - microsecondsToClockCycles(timeHighUS), microsecondsToClockCycles(timeLowUS), - microsecondsToClockCycles(runTimeUS), alignPhase, microsecondsToClockCycles(phaseOffsetUS), autoPwm); -} -*/ - -// Set a callback. Pass in NULL to stop it -//extern void setTimer1Callback_weak(uint32_t (*fn)()) __attribute__((weak)); -void setTimer1Callback_weak(uint32_t (*fn)()) { - wvfState.timer1CB = fn; - if (fn) { - initTimer(); - forceTimerInterrupt(); - } - disableIdleTimer(); -} -/* -static void setTimer1Callback_bound(uint32_t (*fn)()) __attribute__((weakref("setTimer1Callback_weak"))); -void setTimer1Callback(uint32_t (*fn)()) { - setTimer1Callback_bound(fn); -} -*/ - -// Stops a waveform on a pin -//extern int stopWaveform_weak(uint8_t pin) __attribute__((weak)); -IRAM_ATTR int stopWaveform_weak(uint8_t pin) { - // Can't possibly need to stop anything if there is no timer active - if (!timerRunning) { - return false; - } - // If user sends in a pin >16 but <32, this will always point to a 0 bit - // If they send >=32, then the shift will result in 0 and it will also return false - uint32_t mask = 1<= (uintptr_t) &_UserExceptionVector_1)) { - // Address is good; save backup - epc3_backup = epc3; - eps3_backup = eps3; - } else { - // Address is inside the NMI handler -- restore from backup - __asm__ __volatile__("wsr %0,epc3; wsr %1,eps3"::"a"(epc3_backup),"a"(eps3_backup)); - } -} -// ----- @willmmiles end patch ----- - - -// The SDK and hardware take some time to actually get to our NMI code, so -// decrement the next IRQ's timer value by a bit so we can actually catch the -// real CPU cycle counter we want for the waveforms. - -// The SDK also sometimes is running at a different speed the the Arduino core -// so the ESP cycle counter is actually running at a variable speed. -// adjust(x) takes care of adjusting a delta clock cycle amount accordingly. -#if F_CPU == 80000000 - #define DELTAIRQ (microsecondsToClockCycles(9)/4) - #define adjust(x) ((x) << (turbo ? 1 : 0)) -#else - #define DELTAIRQ (microsecondsToClockCycles(9)/8) - #define adjust(x) ((x) >> 0) -#endif - -// When the time to the next edge is greater than this, RTI and set another IRQ to minimize CPU usage -#define MINIRQTIME microsecondsToClockCycles(6) - -static IRAM_ATTR void timer1Interrupt() { - // ----- @willmmiles begin patch ----- - nmiCrashWorkaround(); - // ----- @willmmiles end patch ----- - - // Flag if the core is at 160 MHz, for use by adjust() - bool turbo = (*(uint32_t*)0x3FF00014) & 1 ? true : false; - - uint32_t nextEventCycle = GetCycleCountIRQ() + microsecondsToClockCycles(MAXIRQUS); - uint32_t timeoutCycle = GetCycleCountIRQ() + microsecondsToClockCycles(14); - - if (wvfState.waveformToEnable || wvfState.waveformToDisable) { - // Handle enable/disable requests from main app - wvfState.waveformEnabled = (wvfState.waveformEnabled & ~wvfState.waveformToDisable) | wvfState.waveformToEnable; // Set the requested waveforms on/off - wvfState.waveformState &= ~wvfState.waveformToEnable; // And clear the state of any just started - wvfState.waveformToEnable = 0; - wvfState.waveformToDisable = 0; - // No mem barrier. Globals must be written to RAM on ISR exit. - // Find the first GPIO being generated by checking GCC's find-first-set (returns 1 + the bit of the first 1 in an int32_t) - wvfState.startPin = __builtin_ffs(wvfState.waveformEnabled) - 1; - // Find the last bit by subtracting off GCC's count-leading-zeros (no offset in this one) - wvfState.endPin = 32 - __builtin_clz(wvfState.waveformEnabled); - } else if (!pwmState.cnt && pwmState.pwmUpdate) { - // Start up the PWM generator by copying from the mailbox - pwmState.cnt = 1; - pwmState.idx = 1; // Ensure copy this cycle, cause it to start at t=0 - pwmState.nextServiceCycle = GetCycleCountIRQ(); // Do it this loop! - // No need for mem barrier here. Global must be written by IRQ exit - } - - bool done = false; - if (wvfState.waveformEnabled || pwmState.cnt) { - do { - nextEventCycle = GetCycleCountIRQ() + microsecondsToClockCycles(MAXIRQUS); - - // PWM state machine implementation - if (pwmState.cnt) { - int32_t cyclesToGo; - do { - cyclesToGo = pwmState.nextServiceCycle - GetCycleCountIRQ(); - if (cyclesToGo < 0) { - if (pwmState.idx == pwmState.cnt) { // Start of pulses, possibly copy new - if (pwmState.pwmUpdate) { - // Do the memory copy from temp to global and clear mailbox - pwmState = *(PWMState*)pwmState.pwmUpdate; - } - GPOS = pwmState.mask; // Set all active pins high - if (pwmState.mask & (1<<16)) { - GP16O = 1; - } - pwmState.idx = 0; - } else { - do { - // Drop the pin at this edge - if (pwmState.mask & (1<expiryCycle) { - int32_t expiryToGo = wave->expiryCycle - now; - if (expiryToGo < 0) { - // Done, remove! - if (i == 16) { - GP16O = 0; - } - GPOC = mask; - wvfState.waveformEnabled &= ~mask; - continue; - } - } - - // Check for toggles - int32_t cyclesToGo = wave->nextServiceCycle - now; - if (cyclesToGo < 0) { - uint32_t nextEdgeCycles; - uint32_t desired = 0; - uint32_t *timeToUpdate; - wvfState.waveformState ^= mask; - if (wvfState.waveformState & mask) { - if (i == 16) { - GP16O = 1; - } - GPOS = mask; - - if (wvfState.waveformToChange & mask) { - // Copy over next full-cycle timings - wave->timeHighCycles = wvfState.waveformNewHigh; - wave->desiredHighCycles = wvfState.waveformNewHigh; - wave->timeLowCycles = wvfState.waveformNewLow; - wave->desiredLowCycles = wvfState.waveformNewLow; - wave->lastEdge = 0; - wvfState.waveformToChange = 0; - } - if (wave->lastEdge) { - desired = wave->desiredLowCycles; - timeToUpdate = &wave->timeLowCycles; - } - nextEdgeCycles = wave->timeHighCycles; - } else { - if (i == 16) { - GP16O = 0; - } - GPOC = mask; - desired = wave->desiredHighCycles; - timeToUpdate = &wave->timeHighCycles; - nextEdgeCycles = wave->timeLowCycles; - } - if (desired) { - desired = adjust(desired); - int32_t err = desired - (now - wave->lastEdge); - if (abs(err) < desired) { // If we've lost > the entire phase, ignore this error signal - err /= 2; - *timeToUpdate += err; - } - } - nextEdgeCycles = adjust(nextEdgeCycles); - wave->nextServiceCycle = now + nextEdgeCycles; - wave->lastEdge = now; - } - nextEventCycle = earliest(nextEventCycle, wave->nextServiceCycle); - } - - // Exit the loop if we've hit the fixed runtime limit or the next event is known to be after that timeout would occur - uint32_t now = GetCycleCountIRQ(); - int32_t cycleDeltaNextEvent = nextEventCycle - now; - int32_t cyclesLeftTimeout = timeoutCycle - now; - done = (cycleDeltaNextEvent > MINIRQTIME) || (cyclesLeftTimeout < 0); - } while (!done); - } // if (wvfState.waveformEnabled) - - if (wvfState.timer1CB) { - nextEventCycle = earliest(nextEventCycle, GetCycleCountIRQ() + wvfState.timer1CB()); - } - - int32_t nextEventCycles = nextEventCycle - GetCycleCountIRQ(); - - if (nextEventCycles < MINIRQTIME) { - nextEventCycles = MINIRQTIME; - } - nextEventCycles -= DELTAIRQ; - - // Do it here instead of global function to save time and because we know it's edge-IRQ - T1L = nextEventCycles >> (turbo ? 1 : 0); -} - -}; diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 5b948b9c..5dcb7f94 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -16,6 +16,9 @@ #define LEDC_MUTEX_UNLOCK() #endif #endif +#ifdef ESP8266 +#include "core_esp8266_waveform.h" +#endif #include "const.h" #include "pin_manager.h" #include "bus_wrapper.h" @@ -466,10 +469,7 @@ BusPwm::BusPwm(BusConfig &bc) for (unsigned i = 0; i < numPins; i++) pins[i] = {(int8_t)bc.pins[i], true}; if (!PinManager::allocateMultiplePins(pins, numPins, PinOwner::BusPwm)) return; -#ifdef ESP8266 - analogWriteRange((1<<_depth)-1); - analogWriteFreq(_frequency); -#else +#ifdef ARDUINO_ARCH_ESP32 // for 2 pin PWM CCT strip pinManager will make sure both LEDC channels are in the same speed group and sharing the same timer _ledcStart = PinManager::allocateLedc(numPins); if (_ledcStart == 255) { //no more free LEDC channels @@ -560,12 +560,23 @@ uint32_t BusPwm::getPixelColor(uint16_t pix) const { void BusPwm::show() { if (!_valid) return; + const unsigned numPins = getPins(); +#ifdef ESP8266 + const unsigned analogPeriod = F_CPU / _frequency; + const unsigned maxBri = analogPeriod; // compute to clock cycle accuracy + constexpr bool dithering = false; + constexpr unsigned bitShift = 7; // 2^7 clocks for dead time +#else // if _needsRefresh is true (UI hack) we are using dithering (credit @dedehai & @zalatnaicsongor) // https://github.com/Aircoookie/WLED/pull/4115 and https://github.com/zalatnaicsongor/WLED/pull/1) const bool dithering = _needsRefresh; // avoid working with bitfield - const unsigned numPins = getPins(); const unsigned maxBri = (1<<_depth); // possible values: 16384 (14), 8192 (13), 4096 (12), 2048 (11), 1024 (10), 512 (9) and 256 (8) - [[maybe_unused]] const unsigned bitShift = dithering * 4; // if dithering, _depth is 12 bit but LEDC channel is set to 8 bit (using 4 fractional bits) + const unsigned bitShift = dithering * 4; // if dithering, _depth is 12 bit but LEDC channel is set to 8 bit (using 4 fractional bits) +#endif + // add dead time between signals (when using dithering, two full 8bit pulses are required) + // this is needed for 2CH, but also adds some slack for ESP8266 which has less precise + // PWM timing. + const int deadTime = (1+dithering) << bitShift; // use CIE brightness formula (cubic) to fit (or approximate linearity of) human eye perceived brightness // the formula is based on 12 bit resolution as there is no need for greater precision @@ -591,19 +602,19 @@ void BusPwm::show() { // also mandatory that both channels use the same timer (pinManager takes care of that). for (unsigned i = 0; i < numPins; i++) { unsigned duty = (_data[i] * pwmBri) / 255; - #ifdef ESP8266 - if (_reversed) duty = maxBri - duty; - analogWrite(_pins[i], duty); - #else - int deadTime = 0; + if (_type == TYPE_ANALOG_2CH && Bus::getCCTBlend() == 0) { - // add dead time between signals (when using dithering, two full 8bit pulses are required) - deadTime = (1+dithering) << bitShift; // we only need to take care of shortening the signal at (almost) full brightness otherwise pulses may overlap - if (_bri >= 254 && duty >= maxBri / 2 && duty < maxBri) duty -= deadTime << 1; // shorten duty of larger signal except if full on - if (_reversed) deadTime = -deadTime; // need to invert dead time to make phaseshift go the opposite way so low signals dont overlap + if (_bri >= 254 && duty >= maxBri / 2 && duty < maxBri) { + duty -= deadTime << 1; // shorten duty of larger signal except if full on + } } if (_reversed) duty = maxBri - duty; + + #ifdef ESP8266 + stopWaveform(_pins[i]); + startWaveformClockCycles(_pins[i], duty, analogPeriod - duty, 0, i ? _pins[0] : -1, hPoint, false); + #else unsigned channel = _ledcStart + i; unsigned gr = channel/8; // high/low speed group unsigned ch = channel%8; // group channel @@ -612,9 +623,10 @@ void BusPwm::show() { LEDC.channel_group[gr].channel[ch].duty.duty = duty << ((!dithering)*4); // lowest 4 bits are used for dithering, shift by 4 bits if not using dithering LEDC.channel_group[gr].channel[ch].hpoint.hpoint = hPoint >> bitShift; // hPoint is at _depth resolution (needs shifting if dithering) ledc_update_duty((ledc_mode_t)gr, (ledc_channel_t)ch); - hPoint += duty + deadTime; // offset to cascade the signals - if (hPoint >= maxBri) hPoint = 0; // offset it out of bounds, reset #endif + + hPoint += duty + (_reversed ? -1 : 1) * deadTime; // offset to cascade the signals + if (hPoint >= maxBri) hPoint -= maxBri; // offset is out of bounds, reset } } From fe4b668107fc5a91a1d66743cefbce185c10b5d2 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sat, 28 Sep 2024 23:12:03 -0400 Subject: [PATCH 043/463] Slightly reduce PWM jankiness --- .../src/core_esp8266_waveform_phase.cpp | 33 +++++++++++++++---- wled00/bus_manager.cpp | 2 +- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/lib/ESP8266PWM/src/core_esp8266_waveform_phase.cpp b/lib/ESP8266PWM/src/core_esp8266_waveform_phase.cpp index b846091b..12a12066 100644 --- a/lib/ESP8266PWM/src/core_esp8266_waveform_phase.cpp +++ b/lib/ESP8266PWM/src/core_esp8266_waveform_phase.cpp @@ -104,18 +104,20 @@ constexpr int32_t DELTAIRQCCYS = ISCPUFREQ160MHZ ? // for INFINITE, the NMI proceeds on the waveform without expiry deadline. // for EXPIRES, the NMI expires the waveform automatically on the expiry ccy. // for UPDATEEXPIRY, the NMI recomputes the exact expiry ccy and transitions to EXPIRES. +// for UPDATEPHASE, the NMI recomputes the target timings // for INIT, the NMI initializes nextPeriodCcy, and if expiryCcy != 0 includes UPDATEEXPIRY. -enum class WaveformMode : uint8_t {INFINITE = 0, EXPIRES = 1, UPDATEEXPIRY = 2, INIT = 3}; +enum class WaveformMode : uint8_t {INFINITE = 0, EXPIRES = 1, UPDATEEXPIRY = 2, UPDATEPHASE = 3, INIT = 4}; // Waveform generator can create tones, PWM, and servos typedef struct { - uint32_t nextPeriodCcy; // ESP clock cycle when a period begins. If WaveformMode::INIT, temporarily holds positive phase offset ccy count + uint32_t nextPeriodCcy; // ESP clock cycle when a period begins. uint32_t endDutyCcy; // ESP clock cycle when going from duty to off int32_t dutyCcys; // Set next off cycle at low->high to maintain phase int32_t adjDutyCcys; // Temporary correction for next period int32_t periodCcys; // Set next phase cycle at low->high to maintain phase uint32_t expiryCcy; // For time-limited waveform, the CPU clock cycle when this waveform must stop. If WaveformMode::UPDATE, temporarily holds relative ccy count WaveformMode mode; + uint32_t phaseCcy; // positive phase offset ccy count int8_t alignPhase; // < 0 no phase alignment, otherwise starts waveform in relative phase offset to given pin bool autoPwm; // perform PWM duty to idle cycle ratio correction under high load at the expense of precise timings } Waveform; @@ -200,15 +202,15 @@ int startWaveformClockCycles_weak(uint8_t pin, uint32_t highCcys, uint32_t lowCc wave.adjDutyCcys = 0; wave.periodCcys = periodCcys; wave.autoPwm = autoPwm; + wave.alignPhase = (alignPhase < 0) ? -1 : alignPhase; + wave.phaseCcy = phaseOffsetCcys; std::atomic_thread_fence(std::memory_order_acquire); const uint32_t pinBit = 1UL << pin; if (!(waveform.enabled & pinBit)) { // wave.nextPeriodCcy and wave.endDutyCcy are initialized by the ISR - wave.nextPeriodCcy = phaseOffsetCcys; wave.expiryCcy = runTimeCcys; // in WaveformMode::INIT, temporarily hold relative cycle count wave.mode = WaveformMode::INIT; - wave.alignPhase = (alignPhase < 0) ? -1 : alignPhase; if (!wave.dutyCcys) { // If initially at zero duty cycle, force GPIO off if (pin == 16) { @@ -232,11 +234,16 @@ int startWaveformClockCycles_weak(uint8_t pin, uint32_t highCcys, uint32_t lowCc else { wave.mode = WaveformMode::INFINITE; // turn off possible expiry to make update atomic from NMI std::atomic_thread_fence(std::memory_order_release); - wave.expiryCcy = runTimeCcys; // in WaveformMode::UPDATEEXPIRY, temporarily hold relative cycle count if (runTimeCcys) { + wave.expiryCcy = runTimeCcys; // in WaveformMode::UPDATEEXPIRY, temporarily hold relative cycle count wave.mode = WaveformMode::UPDATEEXPIRY; std::atomic_thread_fence(std::memory_order_release); waveform.toSetBits = 1UL << pin; + } else if (alignPhase) { + // @willmmiles new feature + wave.mode = WaveformMode::UPDATEPHASE; // recalculate start + std::atomic_thread_fence(std::memory_order_release); + waveform.toSetBits = 1UL << pin; } } std::atomic_thread_fence(std::memory_order_acq_rel); @@ -292,12 +299,13 @@ static inline IRAM_ATTR int32_t scaleCcys(const int32_t ccys, const bool isCPU2X } static IRAM_ATTR void timer1Interrupt() { + const uint32_t isrStartCcy = ESP.getCycleCount(); + int32_t clockDrift = isrStartCcy - waveform.nextEventCcy; + // ----- @willmmiles begin patch ----- nmiCrashWorkaround(); // ----- @willmmiles end patch ----- - const uint32_t isrStartCcy = ESP.getCycleCount(); - int32_t clockDrift = isrStartCcy - waveform.nextEventCcy; const bool isCPU2X = CPU2X & 1; if ((waveform.toSetBits && !(waveform.enabled & waveform.toSetBits)) || waveform.toDisableBits) { // Handle enable/disable requests from main app. @@ -328,6 +336,15 @@ static IRAM_ATTR void timer1Interrupt() { wave.expiryCcy = wave.nextPeriodCcy + scaleCcys(wave.expiryCcy, isCPU2X); wave.mode = WaveformMode::EXPIRES; break; + // @willmmiles new feature + case WaveformMode::UPDATEPHASE: + // in WaveformMode::UPDATEPHASE, we recalculate the targets without adjusting the state + if (wave.alignPhase >= 0 && waveform.enabled & (1UL << wave.alignPhase)) { + auto& align_wave = waveform.pins[wave.alignPhase]; + // Go back one cycle + wave.nextPeriodCcy = align_wave.nextPeriodCcy - scaleCcys(align_wave.periodCcys, isCPU2X) + scaleCcys(wave.phaseCcy, isCPU2X); + wave.endDutyCcy = wave.nextPeriodCcy + scaleCcys(wave.dutyCcys, isCPU2X); + } default: break; } @@ -355,11 +372,13 @@ static IRAM_ATTR void timer1Interrupt() { Waveform& wave = waveform.pins[pin]; +/* @willmmiles - wtf? We don't want to accumulate drift if (clockDrift) { wave.endDutyCcy += clockDrift; wave.nextPeriodCcy += clockDrift; wave.expiryCcy += clockDrift; } +*/ uint32_t waveNextEventCcy = (waveform.states & pinBit) ? wave.endDutyCcy : wave.nextPeriodCcy; if (WaveformMode::EXPIRES == wave.mode && diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 5dcb7f94..e631190d 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -612,7 +612,7 @@ void BusPwm::show() { if (_reversed) duty = maxBri - duty; #ifdef ESP8266 - stopWaveform(_pins[i]); + //stopWaveform(_pins[i]); // can cause the waveform to miss a cycle. instead we risk crossovers. startWaveformClockCycles(_pins[i], duty, analogPeriod - duty, 0, i ? _pins[0] : -1, hPoint, false); #else unsigned channel = _ledcStart + i; From 3c7f83407b64f21fa20262189c215fdd9852a972 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sat, 28 Sep 2024 23:15:20 -0400 Subject: [PATCH 044/463] Save a little RAM --- .../src/core_esp8266_waveform_phase.cpp | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/ESP8266PWM/src/core_esp8266_waveform_phase.cpp b/lib/ESP8266PWM/src/core_esp8266_waveform_phase.cpp index 12a12066..60b9b0eb 100644 --- a/lib/ESP8266PWM/src/core_esp8266_waveform_phase.cpp +++ b/lib/ESP8266PWM/src/core_esp8266_waveform_phase.cpp @@ -117,8 +117,6 @@ typedef struct { int32_t periodCcys; // Set next phase cycle at low->high to maintain phase uint32_t expiryCcy; // For time-limited waveform, the CPU clock cycle when this waveform must stop. If WaveformMode::UPDATE, temporarily holds relative ccy count WaveformMode mode; - uint32_t phaseCcy; // positive phase offset ccy count - int8_t alignPhase; // < 0 no phase alignment, otherwise starts waveform in relative phase offset to given pin bool autoPwm; // perform PWM duty to idle cycle ratio correction under high load at the expense of precise timings } Waveform; @@ -133,6 +131,11 @@ namespace { int32_t toSetBits = 0; // Message to the NMI handler to start/modify exactly one waveform int32_t toDisableBits = 0; // Message to the NMI handler to disable exactly one pin from waveform generation + // toSetBits temporaries + // cheaper than packing them in every Waveform, since we permit only one use at a time + uint32_t phaseCcy; // positive phase offset ccy count + int8_t alignPhase; // < 0 no phase alignment, otherwise starts waveform in relative phase offset to given pin + uint32_t(*timer1CB)() = nullptr; bool timer1Running = false; @@ -202,8 +205,8 @@ int startWaveformClockCycles_weak(uint8_t pin, uint32_t highCcys, uint32_t lowCc wave.adjDutyCcys = 0; wave.periodCcys = periodCcys; wave.autoPwm = autoPwm; - wave.alignPhase = (alignPhase < 0) ? -1 : alignPhase; - wave.phaseCcy = phaseOffsetCcys; + waveform.alignPhase = (alignPhase < 0) ? -1 : alignPhase; + waveform.phaseCcy = phaseOffsetCcys; std::atomic_thread_fence(std::memory_order_acquire); const uint32_t pinBit = 1UL << pin; @@ -320,8 +323,8 @@ static IRAM_ATTR void timer1Interrupt() { switch (wave.mode) { case WaveformMode::INIT: waveform.states &= ~waveform.toSetBits; // Clear the state of any just started - if (wave.alignPhase >= 0 && waveform.enabled & (1UL << wave.alignPhase)) { - wave.nextPeriodCcy = waveform.pins[wave.alignPhase].nextPeriodCcy + wave.nextPeriodCcy; + if (waveform.alignPhase >= 0 && waveform.enabled & (1UL << waveform.alignPhase)) { + wave.nextPeriodCcy = waveform.pins[waveform.alignPhase].nextPeriodCcy + wave.nextPeriodCcy; } else { wave.nextPeriodCcy = waveform.nextEventCcy; @@ -339,10 +342,10 @@ static IRAM_ATTR void timer1Interrupt() { // @willmmiles new feature case WaveformMode::UPDATEPHASE: // in WaveformMode::UPDATEPHASE, we recalculate the targets without adjusting the state - if (wave.alignPhase >= 0 && waveform.enabled & (1UL << wave.alignPhase)) { - auto& align_wave = waveform.pins[wave.alignPhase]; + if (waveform.alignPhase >= 0 && waveform.enabled & (1UL << waveform.alignPhase)) { + auto& align_wave = waveform.pins[waveform.alignPhase]; // Go back one cycle - wave.nextPeriodCcy = align_wave.nextPeriodCcy - scaleCcys(align_wave.periodCcys, isCPU2X) + scaleCcys(wave.phaseCcy, isCPU2X); + wave.nextPeriodCcy = align_wave.nextPeriodCcy - scaleCcys(align_wave.periodCcys, isCPU2X) + scaleCcys(waveform.phaseCcy, isCPU2X); wave.endDutyCcy = wave.nextPeriodCcy + scaleCcys(wave.dutyCcys, isCPU2X); } default: From ffbc8c5f709461f96c557e5dc9162c8f3e5c6004 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 29 Sep 2024 13:55:00 +0200 Subject: [PATCH 045/463] Reverting addition of `bool unScale`, added new improvements and fixes - Added pre-calculation for segment brightness: stored in _segBri. The impact on FPS is not huge but measurable (~1-2FPS in my test conditions) - Removed `bool unScaled` from `setPixelColor()` function again (it has no/minimal impact on speed but huge impact on flash usage: +850 bytes) - Removed negative checking in `setPixelColorXY()` and replaced it with a local typecast to unsigned, saves a few instructions (tested and working) - Changed int8_t to int in `moveX()` and `moveY()` - Removed a few functions from IRAM as they are now not called for every pixel but only once per segment update - Removed a `virtualWidth()` call from `ripple_base()` - Bugfix in `mode_colortwinkle()` --- wled00/FX.cpp | 4 ++-- wled00/FX.h | 26 ++++++++++++------------- wled00/FX_2Dfcn.cpp | 40 ++++++++++++++++---------------------- wled00/FX_fcn.cpp | 47 ++++++++++++++++++++++----------------------- 4 files changed, 55 insertions(+), 62 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 2ec31014..77167b02 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2294,7 +2294,7 @@ uint16_t mode_colortwinkle() { bool fadeUp = bitRead(SEGENV.data[index], bitNum); if (fadeUp) { - CRGBW incrementalColor = color_fade(col, fadeUpAmount, true); + CRGBW incrementalColor = color_fade(cur, fadeUpAmount, true); col = color_add(cur, incrementalColor); if (col.r == 255 || col.g == 255 || col.b == 255) { @@ -2528,7 +2528,7 @@ static uint16_t ripple_base() { } else {//randomly create new wave if (random16(IBN + 10000) <= (SEGMENT.intensity >> (SEGMENT.is2D()*3))) { ripples[i].state = 1; - ripples[i].pos = SEGMENT.is2D() ? ((random8(SEGENV.virtualWidth())<<8) | (random8(SEGENV.virtualHeight()))) : random16(SEGLEN); + ripples[i].pos = SEGMENT.is2D() ? ((random8(SEG_W)<<8) | (random8(SEG_H))) : random16(SEGLEN); ripples[i].color = random8(); //color } } diff --git a/wled00/FX.h b/wled00/FX.h index b4aaf3c4..8a452cfc 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -420,8 +420,8 @@ typedef struct Segment { }; uint16_t _dataLen; static uint16_t _usedSegmentData; - - static unsigned _vLength; // 1D dimension used for current effect + static uint8_t _segBri; // Current brightness of segment + static unsigned _vLength; // 1D dimension used for current effect static unsigned _vWidth, _vHeight; // 2D dimensions used for current effect static uint32_t _currentColors[NUM_COLORS]; // colors used for current effect static CRGBPalette16 _currentPalette; // palette used for current effect (includes transition, used in color_from_palette()) @@ -546,7 +546,7 @@ typedef struct Segment { inline static unsigned vHeight() { return Segment::_vHeight; } inline static uint32_t getCurrentColor(unsigned i) { return Segment::_currentColors[i]; } // { return i < 3 ? Segment::_currentColors[i] : 0; } inline static const CRGBPalette16 &getCurrentPalette() { return Segment::_currentPalette; } - + inline static uint8_t getCurrentBrightness() { return Segment::_segBri; } static void handleRandomPalette(); void beginDraw(); // set up parameters for current effect @@ -589,8 +589,8 @@ typedef struct Segment { // 1D strip [[gnu::hot]] uint16_t virtualLength() const; - [[gnu::hot]] void setPixelColor(int n, uint32_t c, bool unScaled = true); // set relative pixel within segment with color - inline void setPixelColor(unsigned n, uint32_t c, bool unScaled = true) { setPixelColor(int(n), c, unScaled); } + [[gnu::hot]] void setPixelColor(int n, uint32_t c); // set relative pixel within segment with color + inline void setPixelColor(unsigned n, uint32_t c) { setPixelColor(int(n), c); } inline void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } inline void setPixelColor(int n, CRGB c) { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } #ifdef WLED_USE_AA_PIXELS @@ -629,8 +629,8 @@ typedef struct Segment { uint16_t nrOfVStrips() const; // returns number of virtual vertical strips in 2D matrix (used to expand 1D effects into 2D) #ifndef WLED_DISABLE_2D [[gnu::hot]] uint16_t XY(int x, int y); // support function to get relative index within segment - [[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c, bool unScaled = true); // set relative pixel within segment with color - inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c, bool unScaled = true) { setPixelColorXY(int(x), int(y), c, unScaled); } + [[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color + inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColorXY(int(x), int(y), c); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColorXY(int(x), int(y), RGBW32(c.r,c.g,c.b,0)); } @@ -651,8 +651,8 @@ typedef struct Segment { void blur2D(uint8_t blur_amount, bool smear = false); void blurRow(int row, fract8 blur_amount, bool smear = false); void blurCol(int col, fract8 blur_amount, bool smear = false); - void moveX(int8_t delta, bool wrap = false); - void moveY(int8_t delta, bool wrap = false); + void moveX(int delta, bool wrap = false); + void moveY(int delta, bool wrap = false); void move(uint8_t dir, uint8_t delta, bool wrap = false); void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false); inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) { drawCircle(cx, cy, radius, RGBW32(c.r,c.g,c.b,0), soft); } @@ -668,8 +668,8 @@ typedef struct Segment { inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); } #else inline uint16_t XY(int x, int y) { return x; } - inline void setPixelColorXY(int x, int y, uint32_t c, bool unScaled = true) { setPixelColor(x, c, unScaled); } - inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c, bool unScaled = true) { setPixelColor(int(x), c, unScaled); } + inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(x, c); } + inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColor(int(x), c); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColor(x, RGBW32(r,g,b,w)); } inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColor(x, RGBW32(c.r,c.g,c.b,0)); } inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColor(int(x), RGBW32(c.r,c.g,c.b,0)); } @@ -689,8 +689,8 @@ typedef struct Segment { inline void blur2D(uint8_t blur_amount, bool smear = false) {} inline void blurRow(int row, fract8 blur_amount, bool smear = false) {} inline void blurCol(int col, fract8 blur_amount, bool smear = false) {} - inline void moveX(int8_t delta, bool wrap = false) {} - inline void moveY(int8_t delta, bool wrap = false) {} + inline void moveX(int delta, bool wrap = false) {} + inline void moveY(int delta, bool wrap = false) {} inline void move(uint8_t dir, uint8_t delta, bool wrap = false) {} inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false) {} inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) {} diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 5f61b009..bee31759 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -168,16 +168,16 @@ uint16_t IRAM_ATTR_YN Segment::XY(int x, int y) return isActive() ? (x%vW) + (y%vH) * vW : 0; } -void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col, bool unScaled) +void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) { if (!isActive()) return; // not active - + const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) const int vH = vHeight(); // segment height in logical pixels (is always >= 1) - if (x >= vW|| y >= vH || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit + if (unsigned(x) >= vW || unsigned(y) >= vH) return; // if pixel would fall out of virtual segment just exit - // if color is unscaled - if (unScaled) col = color_fade(col, currentBri()); + if(getCurrentBrightness() < 255) + col = color_fade(col, getCurrentBrightness()); // scale brightness if (reverse ) x = vW - x - 1; if (reverse_y) y = vH - y - 1; @@ -459,7 +459,7 @@ void Segment::box_blur(unsigned radius, bool smear) { delete[] tmpWSum; } -void Segment::moveX(int8_t delta, bool wrap) { +void Segment::moveX(int delta, bool wrap) { if (!isActive()) return; // not active const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) const int vH = vHeight(); // segment height in logical pixels (is always >= 1) @@ -477,7 +477,7 @@ void Segment::moveX(int8_t delta, bool wrap) { } } -void Segment::moveY(int8_t delta, bool wrap) { +void Segment::moveY(int delta, bool wrap) { if (!isActive()) return; // not active const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) const int vH = vHeight(); // segment height in logical pixels (is always >= 1) @@ -545,20 +545,18 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, x++; } } else { - // pre-scale color for all pixels - col = color_fade(col, currentBri()); // Bresenham’s Algorithm int d = 3 - (2*radius); int y = radius, x = 0; while (y >= x) { - setPixelColorXY(cx+x, cy+y, col, false); - setPixelColorXY(cx-x, cy+y, col, false); - setPixelColorXY(cx+x, cy-y, col, false); - setPixelColorXY(cx-x, cy-y, col, false); - setPixelColorXY(cx+y, cy+x, col, false); - setPixelColorXY(cx-y, cy+x, col, false); - setPixelColorXY(cx+y, cy-x, col, false); - setPixelColorXY(cx-y, cy-x, col, false); + setPixelColorXY(cx+x, cy+y, col); + setPixelColorXY(cx-x, cy+y, col); + setPixelColorXY(cx+x, cy-y, col); + setPixelColorXY(cx-x, cy-y, col); + setPixelColorXY(cx+y, cy+x, col); + setPixelColorXY(cx-y, cy+x, col); + setPixelColorXY(cx+y, cy-x, col); + setPixelColorXY(cx-y, cy-x, col); x++; if (d > 0) { y--; @@ -577,15 +575,13 @@ void Segment::fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, const int vH = vHeight(); // segment height in logical pixels (is always >= 1) // draw soft bounding circle if (soft) drawCircle(cx, cy, radius, col, soft); - // pre-scale color for all pixels - col = color_fade(col, currentBri()); // fill it for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius && int(cx)+x >= 0 && int(cy)+y >= 0 && int(cx)+x < vW && int(cy)+y < vH) - setPixelColorXY(cx + x, cy + y, col, false); + setPixelColorXY(cx + x, cy + y, col); } } } @@ -633,12 +629,10 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3 if (steep) std::swap(x,y); // restore if steep } } else { - // pre-scale color for all pixels - c = color_fade(c, currentBri()); // Bresenham's algorithm int err = (dx>dy ? dx : -dy)/2; // error direction for (;;) { - setPixelColorXY(x0, y0, c, false); + setPixelColorXY(x0, y0, c); if (x0==x1 && y0==y1) break; int e2 = err; if (e2 >-dx) { err -= dy; x0 += sx; } diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index a47a7edc..9edd7a28 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -86,6 +86,9 @@ uint16_t Segment::maxHeight = 1; unsigned Segment::_vLength = 0; unsigned Segment::_vWidth = 0; unsigned Segment::_vHeight = 0; +uint8_t Segment::_segBri = 0; +//uint8_t Segment::_currentBrightness2 = 0; +//uint8_t Segment::_currentBrightness3 = 0; uint32_t Segment::_currentColors[NUM_COLORS] = {0,0,0}; CRGBPalette16 Segment::_currentPalette = CRGBPalette16(CRGB::Black); CRGBPalette16 Segment::_randomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR); @@ -413,7 +416,7 @@ void Segment::restoreSegenv(tmpsegd_t &tmpSeg) { } #endif -uint8_t IRAM_ATTR Segment::currentBri(bool useCct) const { +uint8_t Segment::currentBri(bool useCct) const { unsigned prog = progress(); if (prog < 0xFFFFU) { unsigned curBri = (useCct ? cct : (on ? opacity : 0)) * prog; @@ -445,6 +448,7 @@ void Segment::beginDraw() { _vWidth = virtualWidth(); _vHeight = virtualHeight(); _vLength = virtualLength(); + _segBri = currentBri(); // adjust gamma for effects for (unsigned i = 0; i < NUM_COLORS; i++) { #ifndef WLED_DISABLE_MODE_BLEND @@ -624,21 +628,21 @@ void Segment::setPalette(uint8_t pal) { } // 2D matrix -uint16_t IRAM_ATTR Segment::virtualWidth() const { +uint16_t Segment::virtualWidth() const { unsigned groupLen = groupLength(); unsigned vWidth = ((transpose ? height() : width()) + groupLen - 1) / groupLen; if (mirror) vWidth = (vWidth + 1) /2; // divide by 2 if mirror, leave at least a single LED return vWidth; } -uint16_t IRAM_ATTR Segment::virtualHeight() const { +uint16_t Segment::virtualHeight() const { unsigned groupLen = groupLength(); unsigned vHeight = ((transpose ? width() : height()) + groupLen - 1) / groupLen; if (mirror_y) vHeight = (vHeight + 1) /2; // divide by 2 if mirror, leave at least a single LED return vHeight; } -uint16_t IRAM_ATTR_YN Segment::nrOfVStrips() const { +uint16_t Segment::nrOfVStrips() const { unsigned vLen = 1; #ifndef WLED_DISABLE_2D if (is2D() && map1D2D == M12_pBar) vLen = virtualWidth(); @@ -683,7 +687,7 @@ static int getPinwheelLength(int vW, int vH) { #endif // 1D strip -uint16_t IRAM_ATTR Segment::virtualLength() const { +uint16_t Segment::virtualLength() const { #ifndef WLED_DISABLE_2D if (is2D()) { unsigned vW = virtualWidth(); @@ -715,7 +719,7 @@ uint16_t IRAM_ATTR Segment::virtualLength() const { return vLength; } -void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col, bool unScaled) +void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) { if (!isActive() || i < 0) return; // not active or invalid index #ifndef WLED_DISABLE_2D @@ -739,22 +743,20 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col, bool unScaled) if (is2D()) { const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) const int vH = vHeight(); // segment height in logical pixels (is always >= 1) - // pre-scale color for all pixels - col = color_fade(col, currentBri()); switch (map1D2D) { case M12_Pixels: // use all available pixels as a long strip - setPixelColorXY(i % vW, i / vW, col, false); + setPixelColorXY(i % vW, i / vW, col); break; case M12_pBar: // expand 1D effect vertically or have it play on virtual strips - if (vStrip > 0) setPixelColorXY(vStrip - 1, vH - i - 1, col, false); - else for (int x = 0; x < vW; x++) setPixelColorXY(x, vH - i - 1, col, false); + if (vStrip > 0) setPixelColorXY(vStrip - 1, vH - i - 1, col); + else for (int x = 0; x < vW; x++) setPixelColorXY(x, vH - i - 1, col); break; case M12_pArc: // expand in circular fashion from center if (i == 0) - setPixelColorXY(0, 0, col, false); + setPixelColorXY(0, 0, col); else { float r = i; float step = HALF_PI / (2.8284f * r + 4); // we only need (PI/4)/(r/sqrt(2)+1) steps @@ -762,8 +764,8 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col, bool unScaled) int x = roundf(sin_t(rad) * r); int y = roundf(cos_t(rad) * r); // exploit symmetry - setPixelColorXY(x, y, col, false); - setPixelColorXY(y, x, col, false); + setPixelColorXY(x, y, col); + setPixelColorXY(y, x, col); } // Bresenham’s Algorithm (may not fill every pixel) //int d = 3 - (2*i); @@ -782,8 +784,8 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col, bool unScaled) } break; case M12_pCorner: - for (int x = 0; x <= i; x++) setPixelColorXY(x, i, col, false); - for (int y = 0; y < i; y++) setPixelColorXY(i, y, col, false); + for (int x = 0; x <= i; x++) setPixelColorXY(x, i, col); + for (int y = 0; y < i; y++) setPixelColorXY(i, y, col); break; case M12_sPinwheel: { // i = angle --> 0 - 296 (Big), 0 - 192 (Medium), 0 - 72 (Small) @@ -822,7 +824,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col, bool unScaled) int x = posx / Fixed_Scale; int y = posy / Fixed_Scale; // set pixel - if (x != lastX || y != lastY) setPixelColorXY(x, y, col, false); // only paint if pixel position is different + if (x != lastX || y != lastY) setPixelColorXY(x, y, col); // only paint if pixel position is different lastX = x; lastY = y; // advance to next position @@ -846,9 +848,8 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col, bool unScaled) #endif unsigned len = length(); - // if color is unscaled - if (unScaled) col = color_fade(col, currentBri()); - + if(getCurrentBrightness() < 255) //!!! test without this if + col = color_fade(col, getCurrentBrightness()); // scale brightness // expand pixel (taking into account start, grouping, spacing [and offset]) i = i * groupLength(); if (reverse) { // is segment reversed? @@ -1070,11 +1071,9 @@ void Segment::fill(uint32_t c) { if (!isActive()) return; // not active const int cols = is2D() ? vWidth() : vLength(); const int rows = vHeight(); // will be 1 for 1D - // pre-scale color for all pixels - c = color_fade(c, currentBri()); for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) { - if (is2D()) setPixelColorXY(x, y, c, false); - else setPixelColor(x, c, false); + if (is2D()) setPixelColorXY(x, y, c); + else setPixelColor(x, c); } } From 336da25463ff13485da9bd2b1d825f1647368221 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sun, 29 Sep 2024 14:14:07 +0200 Subject: [PATCH 046/463] Private global _colorScaled --- wled00/FX.h | 15 ++++++++------- wled00/FX_2Dfcn.cpp | 20 ++++++++++++++++++-- wled00/FX_fcn.cpp | 18 +++++++++++++----- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 8a452cfc..763dc263 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -420,10 +420,11 @@ typedef struct Segment { }; uint16_t _dataLen; static uint16_t _usedSegmentData; - static uint8_t _segBri; // Current brightness of segment + static uint8_t _segBri; // brightness of segment for current effect static unsigned _vLength; // 1D dimension used for current effect static unsigned _vWidth, _vHeight; // 2D dimensions used for current effect static uint32_t _currentColors[NUM_COLORS]; // colors used for current effect + static bool _colorScaled; // color has been scaled prior to setPixelColor() call static CRGBPalette16 _currentPalette; // palette used for current effect (includes transition, used in color_from_palette()) static CRGBPalette16 _randomPalette; // actual random palette static CRGBPalette16 _newRandomPalette; // target random palette @@ -590,9 +591,9 @@ typedef struct Segment { // 1D strip [[gnu::hot]] uint16_t virtualLength() const; [[gnu::hot]] void setPixelColor(int n, uint32_t c); // set relative pixel within segment with color - inline void setPixelColor(unsigned n, uint32_t c) { setPixelColor(int(n), c); } - inline void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } - inline void setPixelColor(int n, CRGB c) { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } + inline void setPixelColor(unsigned n, uint32_t c) { setPixelColor(int(n), c); } + inline void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } + inline void setPixelColor(int n, CRGB c) { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } #ifdef WLED_USE_AA_PIXELS void setPixelColor(float i, uint32_t c, bool aa = true); inline void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) { setPixelColor(i, RGBW32(r,g,b,w), aa); } @@ -630,7 +631,7 @@ typedef struct Segment { #ifndef WLED_DISABLE_2D [[gnu::hot]] uint16_t XY(int x, int y); // support function to get relative index within segment [[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color - inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColorXY(int(x), int(y), c); } + inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColorXY(int(x), int(y), c); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColorXY(int(x), int(y), RGBW32(c.r,c.g,c.b,0)); } @@ -668,8 +669,8 @@ typedef struct Segment { inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); } #else inline uint16_t XY(int x, int y) { return x; } - inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(x, c); } - inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColor(int(x), c); } + inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(x, c); } + inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColor(int(x), c); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColor(x, RGBW32(r,g,b,w)); } inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColor(x, RGBW32(c.r,c.g,c.b,0)); } inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColor(int(x), RGBW32(c.r,c.g,c.b,0)); } diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index bee31759..8804cdbb 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -176,8 +176,8 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) const int vH = vHeight(); // segment height in logical pixels (is always >= 1) if (unsigned(x) >= vW || unsigned(y) >= vH) return; // if pixel would fall out of virtual segment just exit - if(getCurrentBrightness() < 255) - col = color_fade(col, getCurrentBrightness()); // scale brightness + // if color is unscaled + if (!_colorScaled) col = color_fade(col, _segBri); if (reverse ) x = vW - x - 1; if (reverse_y) y = vH - y - 1; @@ -545,6 +545,9 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, x++; } } else { + // pre-scale color for all pixels + col = color_fade(col, _segBri); + _colorScaled = true; // Bresenham’s Algorithm int d = 3 - (2*radius); int y = radius, x = 0; @@ -565,6 +568,7 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, d += 4 * x + 6; } } + _colorScaled = false; } } @@ -575,6 +579,9 @@ void Segment::fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, const int vH = vHeight(); // segment height in logical pixels (is always >= 1) // draw soft bounding circle if (soft) drawCircle(cx, cy, radius, col, soft); + // pre-scale color for all pixels + col = color_fade(col, _segBri); + _colorScaled = true; // fill it for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { @@ -584,6 +591,7 @@ void Segment::fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, setPixelColorXY(cx + x, cy + y, col); } } + _colorScaled = false; } //line function @@ -629,6 +637,9 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3 if (steep) std::swap(x,y); // restore if steep } } else { + // pre-scale color for all pixels + c = color_fade(c, _segBri); + _colorScaled = true; // Bresenham's algorithm int err = (dx>dy ? dx : -dy)/2; // error direction for (;;) { @@ -638,6 +649,7 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3 if (e2 >-dx) { err -= dy; x0 += sx; } if (e2 < dy) { err += dx; y0 += sy; } } + _colorScaled = false; } } @@ -670,6 +682,9 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, default: return; } uint32_t col = ColorFromPaletteWLED(grad, (i+1)*255/h, 255, NOBLEND); + // pre-scale color for all pixels + col = color_fade(col, _segBri); + _colorScaled = true; for (int j = 0; j= 1) + // pre-scale color for all pixels + col = color_fade(col, _segBri); + _colorScaled = true; switch (map1D2D) { case M12_Pixels: // use all available pixels as a long strip @@ -834,6 +836,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) break; } } + _colorScaled = false; return; } else if (Segment::maxHeight != 1 && (width() == 1 || height() == 1)) { if (start < Segment::maxWidth*Segment::maxHeight) { @@ -848,8 +851,9 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) #endif unsigned len = length(); - if(getCurrentBrightness() < 255) //!!! test without this if - col = color_fade(col, getCurrentBrightness()); // scale brightness + // if color is unscaled + if (!_colorScaled) col = color_fade(col, _segBri); + // expand pixel (taking into account start, grouping, spacing [and offset]) i = i * groupLength(); if (reverse) { // is segment reversed? @@ -1071,10 +1075,14 @@ void Segment::fill(uint32_t c) { if (!isActive()) return; // not active const int cols = is2D() ? vWidth() : vLength(); const int rows = vHeight(); // will be 1 for 1D + // pre-scale color for all pixels + c = color_fade(c, _segBri); + _colorScaled = true; for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) { if (is2D()) setPixelColorXY(x, y, c); else setPixelColor(x, c); } + _colorScaled = false; } /* From 0ae73296cffaff3089893734c2621174347de7ad Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sun, 29 Sep 2024 15:19:37 +0200 Subject: [PATCH 047/463] Update comment --- wled00/FX_fcn.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 86f190ad..232994e7 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -442,7 +442,7 @@ uint32_t IRAM_ATTR_YN Segment::currentColor(uint8_t slot) const { #endif } -// pre-calculate drawing parameters for faster access +// pre-calculate drawing parameters for faster access (based on the idea from @softhack007 from MM fork) void Segment::beginDraw() { _vWidth = virtualWidth(); _vHeight = virtualHeight(); From 59deebc961ec86f602504499ca45fda239a04bd6 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 29 Sep 2024 10:00:27 -0400 Subject: [PATCH 048/463] Improve PWM on ESP8266 - Better phase updates without dropping samples - Make second pin duty cycle always after first, even inverted --- .../src/core_esp8266_waveform_phase.cpp | 20 +++++++++++-------- wled00/bus_manager.cpp | 11 ++++++---- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/lib/ESP8266PWM/src/core_esp8266_waveform_phase.cpp b/lib/ESP8266PWM/src/core_esp8266_waveform_phase.cpp index 60b9b0eb..b89ec8bc 100644 --- a/lib/ESP8266PWM/src/core_esp8266_waveform_phase.cpp +++ b/lib/ESP8266PWM/src/core_esp8266_waveform_phase.cpp @@ -242,7 +242,7 @@ int startWaveformClockCycles_weak(uint8_t pin, uint32_t highCcys, uint32_t lowCc wave.mode = WaveformMode::UPDATEEXPIRY; std::atomic_thread_fence(std::memory_order_release); waveform.toSetBits = 1UL << pin; - } else if (alignPhase) { + } else if (alignPhase >= 0) { // @willmmiles new feature wave.mode = WaveformMode::UPDATEPHASE; // recalculate start std::atomic_thread_fence(std::memory_order_release); @@ -303,7 +303,7 @@ static inline IRAM_ATTR int32_t scaleCcys(const int32_t ccys, const bool isCPU2X static IRAM_ATTR void timer1Interrupt() { const uint32_t isrStartCcy = ESP.getCycleCount(); - int32_t clockDrift = isrStartCcy - waveform.nextEventCcy; + //int32_t clockDrift = isrStartCcy - waveform.nextEventCcy; // ----- @willmmiles begin patch ----- nmiCrashWorkaround(); @@ -341,12 +341,16 @@ static IRAM_ATTR void timer1Interrupt() { break; // @willmmiles new feature case WaveformMode::UPDATEPHASE: - // in WaveformMode::UPDATEPHASE, we recalculate the targets without adjusting the state + // in WaveformMode::UPDATEPHASE, we recalculate the targets if (waveform.alignPhase >= 0 && waveform.enabled & (1UL << waveform.alignPhase)) { - auto& align_wave = waveform.pins[waveform.alignPhase]; - // Go back one cycle - wave.nextPeriodCcy = align_wave.nextPeriodCcy - scaleCcys(align_wave.periodCcys, isCPU2X) + scaleCcys(waveform.phaseCcy, isCPU2X); - wave.endDutyCcy = wave.nextPeriodCcy + scaleCcys(wave.dutyCcys, isCPU2X); + // Compute phase shift to realign with target + auto& align_wave = waveform.pins[waveform.alignPhase]; + int32_t shift = static_cast(align_wave.nextPeriodCcy + scaleCcys(waveform.phaseCcy, isCPU2X) - wave.nextPeriodCcy); + const int32_t periodCcys = scaleCcys(wave.periodCcys, isCPU2X); + if (shift > periodCcys/2) shift -= periodCcys; + else if (shift <= -periodCcys/2) shift += periodCcys; + wave.nextPeriodCcy += shift; + wave.endDutyCcy += shift; } default: break; @@ -462,7 +466,7 @@ static IRAM_ATTR void timer1Interrupt() { } now = ESP.getCycleCount(); } - clockDrift = 0; + //clockDrift = 0; } int32_t callbackCcys = 0; diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index e631190d..c3c8a212 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -565,7 +565,7 @@ void BusPwm::show() { const unsigned analogPeriod = F_CPU / _frequency; const unsigned maxBri = analogPeriod; // compute to clock cycle accuracy constexpr bool dithering = false; - constexpr unsigned bitShift = 7; // 2^7 clocks for dead time + constexpr unsigned bitShift = 8; // 256 clocks for dead time, ~3us at 80MHz #else // if _needsRefresh is true (UI hack) we are using dithering (credit @dedehai & @zalatnaicsongor) // https://github.com/Aircoookie/WLED/pull/4115 and https://github.com/zalatnaicsongor/WLED/pull/1) @@ -609,8 +609,10 @@ void BusPwm::show() { duty -= deadTime << 1; // shorten duty of larger signal except if full on } } - if (_reversed) duty = maxBri - duty; - + if (_reversed) { + if (i) hPoint += duty; // align start at time zero + duty = maxBri - duty; + } #ifdef ESP8266 //stopWaveform(_pins[i]); // can cause the waveform to miss a cycle. instead we risk crossovers. startWaveformClockCycles(_pins[i], duty, analogPeriod - duty, 0, i ? _pins[0] : -1, hPoint, false); @@ -625,7 +627,8 @@ void BusPwm::show() { ledc_update_duty((ledc_mode_t)gr, (ledc_channel_t)ch); #endif - hPoint += duty + (_reversed ? -1 : 1) * deadTime; // offset to cascade the signals + if (!_reversed) hPoint += duty; + hPoint += deadTime; // offset to cascade the signals if (hPoint >= maxBri) hPoint -= maxBri; // offset is out of bounds, reset } } From cb8dae1ddbe750527ad5d4f162a6aa1793748ce3 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 29 Sep 2024 10:13:19 -0400 Subject: [PATCH 049/463] PWM: Revert always apply dead time --- wled00/bus_manager.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index c3c8a212..cbcfa4b2 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -573,11 +573,6 @@ void BusPwm::show() { const unsigned maxBri = (1<<_depth); // possible values: 16384 (14), 8192 (13), 4096 (12), 2048 (11), 1024 (10), 512 (9) and 256 (8) const unsigned bitShift = dithering * 4; // if dithering, _depth is 12 bit but LEDC channel is set to 8 bit (using 4 fractional bits) #endif - // add dead time between signals (when using dithering, two full 8bit pulses are required) - // this is needed for 2CH, but also adds some slack for ESP8266 which has less precise - // PWM timing. - const int deadTime = (1+dithering) << bitShift; - // use CIE brightness formula (cubic) to fit (or approximate linearity of) human eye perceived brightness // the formula is based on 12 bit resolution as there is no need for greater precision // see: https://en.wikipedia.org/wiki/Lightness @@ -601,9 +596,12 @@ void BusPwm::show() { // Phase shifting requires that LEDC timers are synchronised (see setup()). For PWM CCT (and H-bridge) it is // also mandatory that both channels use the same timer (pinManager takes care of that). for (unsigned i = 0; i < numPins; i++) { - unsigned duty = (_data[i] * pwmBri) / 255; + unsigned duty = (_data[i] * pwmBri) / 255; + unsigned deadTime = 0; if (_type == TYPE_ANALOG_2CH && Bus::getCCTBlend() == 0) { + // add dead time between signals (when using dithering, two full 8bit pulses are required) + deadTime = (1+dithering) << bitShift; // we only need to take care of shortening the signal at (almost) full brightness otherwise pulses may overlap if (_bri >= 254 && duty >= maxBri / 2 && duty < maxBri) { duty -= deadTime << 1; // shorten duty of larger signal except if full on From ee380c5377b1f73e2a8da2247bb77288b9670899 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Mon, 30 Sep 2024 16:35:40 +0200 Subject: [PATCH 050/463] Replace uint16_t with unsigned for segment data swap if statements in color_fade --- wled00/FX.h | 8 ++++---- wled00/FX_fcn.cpp | 4 ++-- wled00/colors.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 763dc263..065daa86 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -400,7 +400,7 @@ typedef struct Segment { uint32_t _stepT; uint32_t _callT; uint8_t *_dataT; - uint16_t _dataLenT; + unsigned _dataLenT; TemporarySegmentData() : _dataT(nullptr) // just in case... , _dataLenT(0) @@ -418,8 +418,8 @@ typedef struct Segment { uint8_t _reserved : 4; }; }; - uint16_t _dataLen; - static uint16_t _usedSegmentData; + unsigned _dataLen; + static unsigned _usedSegmentData; static uint8_t _segBri; // brightness of segment for current effect static unsigned _vLength; // 1D dimension used for current effect static unsigned _vWidth, _vHeight; // 2D dimensions used for current effect @@ -537,7 +537,7 @@ typedef struct Segment { inline uint16_t groupLength() const { return grouping + spacing; } inline uint8_t getLightCapabilities() const { return _capabilities; } - inline static uint16_t getUsedSegmentData() { return Segment::_usedSegmentData; } + inline static unsigned getUsedSegmentData() { return Segment::_usedSegmentData; } inline static void addUsedSegmentData(int len) { Segment::_usedSegmentData += len; } #ifndef WLED_DISABLE_MODE_BLEND inline static void modeBlend(bool blend) { _modeBlend = blend; } diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 232994e7..13e9e73b 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -80,7 +80,7 @@ static constexpr bool validatePinsAndTypes(const unsigned* types, unsigned numTy /////////////////////////////////////////////////////////////////////////////// // Segment class implementation /////////////////////////////////////////////////////////////////////////////// -uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for their data[] +unsigned Segment::_usedSegmentData = 0U; // amount of RAM all segments use for their data[] uint16_t Segment::maxWidth = DEFAULT_LED_COUNT; uint16_t Segment::maxHeight = 1; unsigned Segment::_vLength = 0; @@ -433,7 +433,7 @@ uint8_t Segment::currentMode() const { return mode; } -uint32_t IRAM_ATTR_YN Segment::currentColor(uint8_t slot) const { +uint32_t Segment::currentColor(uint8_t slot) const { if (slot >= NUM_COLORS) slot = 0; #ifndef WLED_DISABLE_MODE_BLEND return isInTransition() ? color_blend(_t->_segT._colorT[slot], colors[slot], progress(), true) : colors[slot]; diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 1c484437..c059ea9d 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -77,8 +77,8 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool preserveCR) uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) { - if (c1 == BLACK || amount == 0) return BLACK; if (amount == 255) return c1; + if (c1 == BLACK || amount == 0) return BLACK; uint32_t scaledcolor; // color order is: W R G B from MSB to LSB uint32_t scale = amount; // 32bit for faster calculation uint32_t addRemains = 0; From ba3a61f6236f316e3b03e3cf3bd92c79b0a1ce8f Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Wed, 2 Oct 2024 20:14:25 +0200 Subject: [PATCH 051/463] Reduced code size by: - removing WS2812FX::setMode() - removing WS2812FX::setColor() - removing floating point in transition - color handling modification in set.cpp - replaced uint8_t with unsigned in function parameters - inlined WS2812FX::isUpdating() - (MAY BE BREAKING) alexa & smartnest update --- usermods/smartnest/usermod_smartnest.h | 2 +- wled00/FX.h | 29 +++++++--------- wled00/FX_2Dfcn.cpp | 2 +- wled00/FX_fcn.cpp | 46 +++----------------------- wled00/alexa.cpp | 4 +-- wled00/bus_manager.h | 1 + wled00/led.cpp | 21 ++++++------ wled00/set.cpp | 45 ++++++++++++------------- wled00/udp.cpp | 6 ++-- wled00/wled.cpp | 10 +++--- wled00/wled.h | 1 - 11 files changed, 61 insertions(+), 106 deletions(-) diff --git a/usermods/smartnest/usermod_smartnest.h b/usermods/smartnest/usermod_smartnest.h index 92d524c8..9d21ef2e 100644 --- a/usermods/smartnest/usermod_smartnest.h +++ b/usermods/smartnest/usermod_smartnest.h @@ -49,7 +49,7 @@ private: void setColor(int r, int g, int b) { - strip.setColor(0, r, g, b); + strip.getMainSegment().setColor(0, RGBW32(r, g, b, 0)); stateUpdated(CALL_MODE_DIRECT_CHANGE); char msg[18] {}; sprintf(msg, "rgb(%d,%d,%d)", r, g, b); diff --git a/wled00/FX.h b/wled00/FX.h index 065daa86..14c26816 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -30,6 +30,7 @@ #include #include "const.h" +#include "bus_manager.h" #define FASTLED_INTERNAL //remove annoying pragma messages #define USE_GET_MILLISECOND_TIMER @@ -654,7 +655,7 @@ typedef struct Segment { void blurCol(int col, fract8 blur_amount, bool smear = false); void moveX(int delta, bool wrap = false); void moveY(int delta, bool wrap = false); - void move(uint8_t dir, uint8_t delta, bool wrap = false); + void move(unsigned dir, unsigned delta, bool wrap = false); void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false); inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) { drawCircle(cx, cy, radius, RGBW32(c.r,c.g,c.b,0), soft); } void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false); @@ -781,25 +782,22 @@ class WS2812FX { // 96 bytes #endif finalizeInit(), // initialises strip components service(), // executes effect functions when due and calls strip.show() - setMode(uint8_t segid, uint8_t m), // sets effect/mode for given segment (high level API) - setColor(uint8_t slot, uint32_t c), // sets color (in slot) for given segment (high level API) setCCT(uint16_t k), // sets global CCT (either in relative 0-255 value or in K) setBrightness(uint8_t b, bool direct = false), // sets strip brightness setRange(uint16_t i, uint16_t i2, uint32_t col), // used for clock overlay purgeSegments(), // removes inactive segments from RAM (may incure penalty and memory fragmentation but reduces vector footprint) setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 1, uint8_t spacing = 0, uint16_t offset = UINT16_MAX, uint16_t startY=0, uint16_t stopY=1), - setMainSegmentId(uint8_t n), + setMainSegmentId(unsigned n = 0), resetSegments(), // marks all segments for reset makeAutoSegments(bool forceReset = false), // will create segments based on configured outputs fixInvalidSegments(), // fixes incorrect segment configuration setPixelColor(unsigned n, uint32_t c), // paints absolute strip pixel with index n and color c show(), // initiates LED output - setTargetFps(uint8_t fps), + setTargetFps(unsigned fps), setupEffectData(); // add default effects to the list; defined in FX.cpp inline void restartRuntime() { for (Segment &seg : _segments) seg.markForReset(); } inline void setTransitionMode(bool t) { for (Segment &seg : _segments) seg.startTransition(t ? _transitionDur : 0); } - inline void setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setColor(slot, RGBW32(r,g,b,w)); } inline void setPixelColor(unsigned n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } inline void setPixelColor(unsigned n, CRGB c) { setPixelColor(n, c.red, c.green, c.blue); } inline void fill(uint32_t c) { for (unsigned i = 0; i < getLengthTotal(); i++) setPixelColor(i, c); } // fill whole strip with color (inline) @@ -815,9 +813,9 @@ class WS2812FX { // 96 bytes checkSegmentAlignment(), hasRGBWBus() const, hasCCTBus() const, - isUpdating() const, // return true if the strip is being sent pixel updates - deserializeMap(uint8_t n=0); + deserializeMap(unsigned n = 0); + inline bool isUpdating() const { return !BusManager::canAllShow(); } // return true if the strip is being sent pixel updates inline bool isServicing() const { return _isServicing; } // returns true if strip.service() is executing inline bool hasWhiteChannel() const { return _hasWhiteChannel; } // returns true if strip contains separate white chanel inline bool isOffRefreshRequired() const { return _isOffRefreshRequired; } // returns true if strip requires regular updates (i.e. TM1814 chipset) @@ -844,9 +842,9 @@ class WS2812FX { // 96 bytes uint16_t getLengthPhysical() const, - getLengthTotal() const, // will include virtual/nonexistent pixels in matrix - getFps() const; + getLengthTotal() const; // will include virtual/nonexistent pixels in matrix + inline uint16_t getFps() const { return (millis() - _lastShow > 2000) ? 0 : _cumulativeFps +1; } // Returns the refresh rate of the LED strip inline uint16_t getFrameTime() const { return _frametime; } // returns amount of time a frame should take (in ms) inline uint16_t getMinShowDelay() const { return MIN_SHOW_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant) inline uint16_t getLength() const { return _length; } // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H) @@ -859,15 +857,12 @@ class WS2812FX { // 96 bytes uint32_t now, timebase; uint32_t getPixelColor(unsigned) const; - inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call + inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call - const char * - getModeData(uint8_t id = 0) const { return (id && id<_modeCount) ? _modeData[id] : PSTR("Solid"); } + const char *getModeData(unsigned id = 0) const { return (id && id < _modeCount) ? _modeData[id] : PSTR("Solid"); } + inline const char **getModeDataSrc() { return &(_modeData[0]); } // vectors use arrays for underlying data - const char ** - getModeDataSrc() { return &(_modeData[0]); } // vectors use arrays for underlying data - - Segment& getSegment(uint8_t id); + Segment& getSegment(unsigned id); inline Segment& getFirstSelectedSeg() { return _segments[getFirstSelectedSegId()]; } // returns reference to first segment that is "selected" inline Segment& getMainSegment() { return _segments[getMainSegmentId()]; } // returns reference to main segment inline Segment* getSegments() { return &(_segments[0]); } // returns pointer to segment vector structure (warning: use carefully) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 8804cdbb..9b39b4c8 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -499,7 +499,7 @@ void Segment::moveY(int delta, bool wrap) { // @param dir direction: 0=left, 1=left-up, 2=up, 3=right-up, 4=right, 5=right-down, 6=down, 7=left-down // @param delta number of pixels to move // @param wrap around -void Segment::move(uint8_t dir, uint8_t delta, bool wrap) { +void Segment::move(unsigned dir, unsigned delta, bool wrap) { if (delta==0) return; switch (dir) { case 0: moveX( delta, wrap); break; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 13e9e73b..7927269e 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1464,49 +1464,11 @@ void WS2812FX::show() { _lastShow = showNow; } -/** - * Returns a true value if any of the strips are still being updated. - * On some hardware (ESP32), strip updates are done asynchronously. - */ -bool WS2812FX::isUpdating() const { - return !BusManager::canAllShow(); -} - -/** - * Returns the refresh rate of the LED strip. Useful for finding out whether a given setup is fast enough. - * Only updates on show() or is set to 0 fps if last show is more than 2 secs ago, so accuracy varies - */ -uint16_t WS2812FX::getFps() const { - if (millis() - _lastShow > 2000) return 0; - return _cumulativeFps +1; -} - -void WS2812FX::setTargetFps(uint8_t fps) { +void WS2812FX::setTargetFps(unsigned fps) { if (fps > 0 && fps <= 120) _targetFps = fps; _frametime = 1000 / _targetFps; } -void WS2812FX::setMode(uint8_t segid, uint8_t m) { - if (segid >= _segments.size()) return; - - if (m >= getModeCount()) m = getModeCount() - 1; - - if (_segments[segid].mode != m) { - _segments[segid].setMode(m); // do not load defaults - } -} - -//applies to all active and selected segments -void WS2812FX::setColor(uint8_t slot, uint32_t c) { - if (slot >= NUM_COLORS) return; - - for (segment &seg : _segments) { - if (seg.isActive() && seg.isSelected()) { - seg.setColor(slot, c); - } - } -} - void WS2812FX::setCCT(uint16_t k) { for (segment &seg : _segments) { if (seg.isActive() && seg.isSelected()) { @@ -1553,7 +1515,7 @@ uint8_t WS2812FX::getFirstSelectedSegId() const { return getMainSegmentId(); } -void WS2812FX::setMainSegmentId(uint8_t n) { +void WS2812FX::setMainSegmentId(unsigned n) { _mainSegment = 0; if (n < _segments.size()) { _mainSegment = n; @@ -1629,7 +1591,7 @@ void WS2812FX::purgeSegments() { } } -Segment& WS2812FX::getSegment(uint8_t id) { +Segment& WS2812FX::getSegment(unsigned id) { return _segments[id >= _segments.size() ? getMainSegmentId() : id]; // vectors } @@ -1844,7 +1806,7 @@ void WS2812FX::loadCustomPalettes() { } //load custom mapping table from JSON file (called from finalizeInit() or deserializeState()) -bool WS2812FX::deserializeMap(uint8_t n) { +bool WS2812FX::deserializeMap(unsigned n) { // 2D support creates its own ledmap (on the fly) if a ledmap.json exists it will overwrite built one. char fileName[32]; diff --git a/wled00/alexa.cpp b/wled00/alexa.cpp index b108f294..81b9ec34 100644 --- a/wled00/alexa.cpp +++ b/wled00/alexa.cpp @@ -126,10 +126,10 @@ void onAlexaChange(EspalexaDevice* dev) } else { colorKtoRGB(k, rgbw); } - strip.setColor(0, RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3])); + strip.getMainSegment().setColor(0, RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3])); } else { uint32_t color = dev->getRGB(); - strip.setColor(0, color); + strip.getMainSegment().setColor(0, color); } stateUpdated(CALL_MODE_ALEXA); } diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 1b324d71..e25a0684 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -6,6 +6,7 @@ */ #include "const.h" +#include "pin_manager.h" #include //colors.cpp diff --git a/wled00/led.cpp b/wled00/led.cpp index 9de0495b..5439fbb6 100644 --- a/wled00/led.cpp +++ b/wled00/led.cpp @@ -80,6 +80,7 @@ byte scaledBri(byte in) void applyBri() { if (!realtimeMode || !arlsForceMaxBri) { + //DEBUG_PRINTF_P(PSTR("Applying strip brightness: %d (%d,%d)\n"), (int)briT, (int)bri, (int)briOld); strip.setBrightness(scaledBri(briT)); } } @@ -144,7 +145,6 @@ void stateUpdated(byte callMode) { if (transitionActive) { briOld = briT; - tperLast = 0; } else strip.setTransitionMode(true); // force all segments to transition mode transitionActive = true; @@ -184,22 +184,21 @@ void handleTransitions() updateInterfaces(interfaceUpdateCallMode); if (transitionActive && strip.getTransition() > 0) { - float tper = (millis() - transitionStartTime)/(float)strip.getTransition(); - if (tper >= 1.0f) { + int ti = millis() - transitionStartTime; + int tr = strip.getTransition(); + if (ti/tr) { strip.setTransitionMode(false); // stop all transitions // restore (global) transition time if not called from UDP notifier or single/temporary transition from JSON (also playlist) if (jsonTransitionOnce) strip.setTransition(transitionDelay); transitionActive = false; jsonTransitionOnce = false; - tperLast = 0; applyFinalBri(); return; } - if (tper - tperLast < 0.004f) return; // less than 1 bit change (1/255) - tperLast = tper; - briT = briOld + ((bri - briOld) * tper); - - applyBri(); + byte briTO = briT; + int deltaBri = (int)bri - (int)briOld; + briT = briOld + (deltaBri * ti / tr); + if (briTO != briT) applyBri(); } } @@ -234,8 +233,8 @@ void handleNightlight() colNlT[1] = effectSpeed; colNlT[2] = effectPalette; - strip.setMode(strip.getFirstSelectedSegId(), FX_MODE_STATIC); // make sure seg runtime is reset if it was in sunrise mode - effectCurrent = FX_MODE_SUNRISE; + strip.getFirstSelectedSeg().setMode(FX_MODE_STATIC); // make sure seg runtime is reset if it was in sunrise mode + effectCurrent = FX_MODE_SUNRISE; // colorUpdated() will take care of assigning that to all selected segments effectSpeed = nightlightDelayMins; effectPalette = 0; if (effectSpeed > 60) effectSpeed = 60; //currently limited to 60 minutes diff --git a/wled00/set.cpp b/wled00/set.cpp index 9b7aa92a..cf3a07dd 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -837,8 +837,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) } // temporary values, write directly to segments, globals are updated by setValuesFromFirstSelectedSeg() - uint32_t col0 = selseg.colors[0]; - uint32_t col1 = selseg.colors[1]; + uint32_t col0 = selseg.colors[0]; + uint32_t col1 = selseg.colors[1]; + uint32_t col2 = selseg.colors[2]; byte colIn[4] = {R(col0), G(col0), B(col0), W(col0)}; byte colInSec[4] = {R(col1), G(col1), B(col1), W(col1)}; byte effectIn = selseg.mode; @@ -919,7 +920,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) //set brightness updateVal(req.c_str(), "&A=", &bri); - bool col0Changed = false, col1Changed = false; + bool col0Changed = false, col1Changed = false, col2Changed = false; //set colors col0Changed |= updateVal(req.c_str(), "&R=", &colIn[0]); col0Changed |= updateVal(req.c_str(), "&G=", &colIn[1]); @@ -976,7 +977,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) } //set color from HEX or 32bit DEC - byte tmpCol[4]; pos = req.indexOf(F("CL=")); if (pos > 0) { colorFromDecOrHexString(colIn, (char*)req.substring(pos + 3).c_str()); @@ -989,10 +989,11 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) } pos = req.indexOf(F("C3=")); if (pos > 0) { + byte tmpCol[4]; colorFromDecOrHexString(tmpCol, (char*)req.substring(pos + 3).c_str()); - uint32_t col2 = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]); + col2 = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]); selseg.setColor(2, col2); // defined above (SS= or main) - if (!singleSegment) strip.setColor(2, col2); // will set color to all active & selected segments + col2Changed = true; } //set to random hue SR=0->1st SR=1->2nd @@ -1003,29 +1004,22 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) col0Changed |= (!sec); col1Changed |= sec; } - //swap 2nd & 1st - pos = req.indexOf(F("SC")); - if (pos > 0) { - byte temp; - for (unsigned i=0; i<4; i++) { - temp = colIn[i]; - colIn[i] = colInSec[i]; - colInSec[i] = temp; - } - col0Changed = col1Changed = true; - } - // apply colors to selected segment, and all selected segments if applicable if (col0Changed) { - uint32_t colIn0 = RGBW32(colIn[0], colIn[1], colIn[2], colIn[3]); - selseg.setColor(0, colIn0); - if (!singleSegment) strip.setColor(0, colIn0); // will set color to all active & selected segments + col0 = RGBW32(colIn[0], colIn[1], colIn[2], colIn[3]); + selseg.setColor(0, col0); } if (col1Changed) { - uint32_t colIn1 = RGBW32(colInSec[0], colInSec[1], colInSec[2], colInSec[3]); - selseg.setColor(1, colIn1); - if (!singleSegment) strip.setColor(1, colIn1); // will set color to all active & selected segments + col1 = RGBW32(colInSec[0], colInSec[1], colInSec[2], colInSec[3]); + selseg.setColor(1, col1); + } + + //swap 2nd & 1st + pos = req.indexOf(F("SC")); + if (pos > 0) { + std::swap(col0,col1); + col0Changed = col1Changed = true; } bool fxModeChanged = false, speedChanged = false, intensityChanged = false, paletteChanged = false; @@ -1055,6 +1049,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) if (speedChanged) seg.speed = speedIn; if (intensityChanged) seg.intensity = intensityIn; if (paletteChanged) seg.setPalette(paletteIn); + if (col0Changed) seg.setColor(0, col0); + if (col1Changed) seg.setColor(1, col1); + if (col2Changed) seg.setColor(2, col2); if (custom1Changed) seg.custom1 = custom1In; if (custom2Changed) seg.custom2 = custom2In; if (custom3Changed) seg.custom3 = custom3In; diff --git a/wled00/udp.cpp b/wled00/udp.cpp index a615cefc..0ff39f11 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -234,12 +234,12 @@ void parseNotifyPacket(uint8_t *udpIn) { //apply colors from notification to main segment, only if not syncing full segments if ((receiveNotificationColor || !someSel) && (version < 11 || !receiveSegmentOptions)) { // primary color, only apply white if intented (version > 0) - strip.setColor(0, RGBW32(udpIn[3], udpIn[4], udpIn[5], (version > 0) ? udpIn[10] : 0)); + strip.getMainSegment().setColor(0, RGBW32(udpIn[3], udpIn[4], udpIn[5], (version > 0) ? udpIn[10] : 0)); if (version > 1) { - strip.setColor(1, RGBW32(udpIn[12], udpIn[13], udpIn[14], udpIn[15])); // secondary color + strip.getMainSegment().setColor(1, RGBW32(udpIn[12], udpIn[13], udpIn[14], udpIn[15])); // secondary color } if (version > 6) { - strip.setColor(2, RGBW32(udpIn[20], udpIn[21], udpIn[22], udpIn[23])); // tertiary color + strip.getMainSegment().setColor(2, RGBW32(udpIn[20], udpIn[21], udpIn[22], udpIn[23])); // tertiary color if (version > 9 && udpIn[37] < 255) { // valid CCT/Kelvin value unsigned cct = udpIn[38]; if (udpIn[37] > 0) { //Kelvin diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 39e0d250..a80808a7 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -221,6 +221,7 @@ void WLED::loop() strip.finalizeInit(); // also loads default ledmap if present if (aligned) strip.makeAutoSegments(); else strip.fixInvalidSegments(); + BusManager::setBrightness(bri); // fix re-initialised bus' brightness doSerializeConfig = true; } if (loadLedmap >= 0) { @@ -571,10 +572,11 @@ void WLED::beginStrip() } else { // fix for #3196 if (bootPreset > 0) { - bool oldTransition = fadeTransition; // workaround if transitions are enabled - fadeTransition = false; // ignore transitions temporarily - strip.setColor(0, BLACK); // set all segments black - fadeTransition = oldTransition; // restore transitions + // set all segments black (no transition) + for (unsigned i = 0; i < strip.getSegmentsNum(); i++) { + Segment &seg = strip.getSegment(i); + if (seg.isActive()) seg.colors[0] = BLACK; + } col[0] = col[1] = col[2] = col[3] = 0; // needed for colorUpdated() } briLast = briS; bri = 0; diff --git a/wled00/wled.h b/wled00/wled.h index 052f29b2..f8021e92 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -584,7 +584,6 @@ WLED_GLOBAL bool transitionActive _INIT(false); WLED_GLOBAL uint16_t transitionDelay _INIT(750); // global transition duration WLED_GLOBAL uint16_t transitionDelayDefault _INIT(750); // default transition time (stored in cfg.json) WLED_GLOBAL unsigned long transitionStartTime; -WLED_GLOBAL float tperLast _INIT(0.0f); // crossfade transition progress, 0.0f - 1.0f WLED_GLOBAL bool jsonTransitionOnce _INIT(false); // flag to override transitionDelay (playlist, JSON API: "live" & "seg":{"i"} & "tt") WLED_GLOBAL uint8_t randomPaletteChangeTime _INIT(5); // amount of time [s] between random palette changes (min: 1s, max: 255s) WLED_GLOBAL bool useHarmonicRandomPalette _INIT(true); // use *harmonic* random palette generation (nicer looking) or truly random From a15c391e6c00dd1b81f4e3116aa87a81628a17e8 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 3 Oct 2024 21:19:34 +0200 Subject: [PATCH 052/463] Improvement to `setPixelColorXY` and some flash optimisations - changes to `setPixelColorXY` give an extra FPS, some checks and the loops are only done when needed, additional function call is still faster (force inlining it gives negligible speed boost but eats more flash) - commented out the unused `boxBlur` function - code size improvemnts (also faster) in `moveX()` and `moveY()` by only copying whats required and avoiding code duplications - consolidated the `blur()` functions by enabling asymmetrical blur2D() to replace `blurRow` and `blurCol` - compiler warning fixes (explicit unsigned casts) --- wled00/FX.h | 19 ++- wled00/FX_2Dfcn.cpp | 284 +++++++++++++++++++++----------------------- wled00/FX_fcn.cpp | 2 +- 3 files changed, 142 insertions(+), 163 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 14c26816..c06332c7 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -457,6 +457,8 @@ typedef struct Segment { {} } *_t; + [[gnu::hot]] void _setPixelColorXY_raw(int& x, int& y, uint32_t& col); // set pixel without mapping (internal use only) + public: Segment(uint16_t sStart=0, uint16_t sStop=30) : @@ -617,12 +619,10 @@ typedef struct Segment { // 2D Blur: shortcuts for bluring columns or rows only (50% faster than full 2D blur) inline void blurCols(fract8 blur_amount, bool smear = false) { // blur all columns - const unsigned cols = virtualWidth(); - for (unsigned k = 0; k < cols; k++) blurCol(k, blur_amount, smear); + blur2D(0, blur_amount, smear); } inline void blurRows(fract8 blur_amount, bool smear = false) { // blur all rows - const unsigned rows = virtualHeight(); - for ( unsigned i = 0; i < rows; i++) blurRow(i, blur_amount, smear); + blur2D(blur_amount, 0, smear); } // 2D matrix @@ -649,10 +649,8 @@ typedef struct Segment { inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool preserveCR = true) { addPixelColorXY(x, y, RGBW32(r,g,b,w), preserveCR); } inline void addPixelColorXY(int x, int y, CRGB c, bool preserveCR = true) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), preserveCR); } inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), fade, true)); } - void box_blur(unsigned r = 1U, bool smear = false); // 2D box blur - void blur2D(uint8_t blur_amount, bool smear = false); - void blurRow(int row, fract8 blur_amount, bool smear = false); - void blurCol(int col, fract8 blur_amount, bool smear = false); + //void box_blur(unsigned r = 1U, bool smear = false); // 2D box blur + void blur2D(uint8_t blur_x, uint8_t blur_y, bool smear = false); void moveX(int delta, bool wrap = false); void moveY(int delta, bool wrap = false); void move(unsigned dir, unsigned delta, bool wrap = false); @@ -666,7 +664,6 @@ typedef struct Segment { inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0)); } // automatic inline inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, int8_t rotate = 0) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0), rotate); } // automatic inline void wu_pixel(uint32_t x, uint32_t y, CRGB c); - inline void blur2d(fract8 blur_amount) { blur(blur_amount); } inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); } #else inline uint16_t XY(int x, int y) { return x; } @@ -687,8 +684,8 @@ typedef struct Segment { inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool saturate = false) { addPixelColor(x, RGBW32(r,g,b,w), saturate); } inline void addPixelColorXY(int x, int y, CRGB c, bool saturate = false) { addPixelColor(x, RGBW32(c.r,c.g,c.b,0), saturate); } inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { fadePixelColor(x, fade); } - inline void box_blur(unsigned i, bool vertical, fract8 blur_amount) {} - inline void blur2D(uint8_t blur_amount, bool smear = false) {} + //inline void box_blur(unsigned i, bool vertical, fract8 blur_amount) {} + inline void blur2D(uint8_t blur_x, uint8_t blur_y, bool smear = false) {} inline void blurRow(int row, fract8 blur_amount, bool smear = false) {} inline void blurCol(int col, fract8 blur_amount, bool smear = false) {} inline void moveX(int delta, bool wrap = false) {} diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 9b39b4c8..3ad061a8 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -168,13 +168,34 @@ uint16_t IRAM_ATTR_YN Segment::XY(int x, int y) return isActive() ? (x%vW) + (y%vH) * vW : 0; } +// raw setColor function without checks (checks are done in setPixelColorXY()) +void IRAM_ATTR_YN Segment::_setPixelColorXY_raw(int& x, int& y, uint32_t& col) +{ +#ifndef WLED_DISABLE_MODE_BLEND + // if blending modes, blend with underlying pixel + if (_modeBlend) col = color_blend(strip.getPixelColorXY(start + x, startY + y), col, 0xFFFFU - progress(), true); +#endif + strip.setPixelColorXY(start + x, startY + y, col); + if (mirror) { //set the corresponding horizontally mirrored pixel + if (transpose) strip.setPixelColorXY(start + x, startY + height() - y - 1, col); + else strip.setPixelColorXY(start + width() - x - 1, startY + y, col); + } + if (mirror_y) { //set the corresponding vertically mirrored pixel + if (transpose) strip.setPixelColorXY(start + width() - x - 1, startY + y, col); + else strip.setPixelColorXY(start + x, startY + height() - y - 1, col); + } + if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel + strip.setPixelColorXY(start + width() - x - 1, startY + height() - y - 1, col); + } +} + void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) { if (!isActive()) return; // not active const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) const int vH = vHeight(); // segment height in logical pixels (is always >= 1) - if (unsigned(x) >= vW || unsigned(y) >= vH) return; // if pixel would fall out of virtual segment just exit + if (unsigned(x) >= unsigned(vW) || unsigned(y) >= unsigned(vH)) return; // if pixel would fall out of virtual segment just exit // if color is unscaled if (!_colorScaled) col = color_fade(col, _segBri); @@ -182,36 +203,28 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) if (reverse ) x = vW - x - 1; if (reverse_y) y = vH - y - 1; if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed - x *= groupLength(); // expand to physical pixels - y *= groupLength(); // expand to physical pixels - int W = width(); - int H = height(); + unsigned groupLen = groupLength(); - int yY = y; - for (int j = 0; j < grouping; j++) { // groupping vertically - if (yY >= H) break; - int xX = x; - for (int g = 0; g < grouping; g++) { // groupping horizontally - if (xX >= W) break; // we have reached X dimension's end -#ifndef WLED_DISABLE_MODE_BLEND - // if blending modes, blend with underlying pixel - if (_modeBlend) col = color_blend(strip.getPixelColorXY(start + xX, startY + yY), col, 0xFFFFU - progress(), true); -#endif - strip.setPixelColorXY(start + xX, startY + yY, col); - if (mirror) { //set the corresponding horizontally mirrored pixel - if (transpose) strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col); - else strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col); + if(groupLen > 1) + { + int W = width(); + int H = height(); + x *= groupLen; // expand to physical pixels + y *= groupLen; // expand to physical pixels + int yY = y; + for (int j = 0; j < grouping; j++) { // groupping vertically + if (yY >= H) break; + int xX = x; + for (int g = 0; g < grouping; g++) { // groupping horizontally + if (xX >= W) break; // we have reached X dimension's end + _setPixelColorXY_raw(xX, yY, col); + xX++; } - if (mirror_y) { //set the corresponding vertically mirrored pixel - if (transpose) strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col); - else strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col); - } - if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel - strip.setPixelColorXY(start + width() - xX - 1, startY + height() - yY - 1, col); - } - xX++; + yY++; } - yY++; + } + else { + _setPixelColorXY_raw(x, y, col); } } @@ -263,7 +276,7 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const { if (!isActive()) return 0; // not active int vW = vWidth(); int vH = vHeight(); - if (x >= vW || y >= vH || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit + if (unsigned(x) >= unsigned(vW) || unsigned(y) >= unsigned(vH)) return 0; // if pixel would fall out of virtual segment just exit if (reverse ) x = vW - x - 1; if (reverse_y) y = vH - y - 1; if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed @@ -273,119 +286,62 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const { return strip.getPixelColorXY(start + x, startY + y); } -// blurRow: perform a blur on a row of a rectangular matrix -void Segment::blurRow(int row, fract8 blur_amount, bool smear){ - if (!isActive() || blur_amount == 0) return; // not active - const int cols = vWidth(); - const int rows = vHeight(); - - if (row >= rows) return; - // blur one row - uint8_t keep = smear ? 255 : 255 - blur_amount; - uint8_t seep = blur_amount >> 1; - uint32_t carryover = BLACK; - uint32_t lastnew; - uint32_t last; - uint32_t curnew = BLACK; - for (int x = 0; x < cols; x++) { - uint32_t cur = getPixelColorXY(x, row); - uint32_t part = color_fade(cur, seep); - curnew = color_fade(cur, keep); - if (x > 0) { - if (carryover) curnew = color_add(curnew, carryover); - uint32_t prev = color_add(lastnew, part); - // optimization: only set pixel if color has changed - if (last != prev) setPixelColorXY(x - 1, row, prev); - } else // first pixel - setPixelColorXY(x, row, curnew); - lastnew = curnew; - last = cur; // save original value for comparison on next iteration - carryover = part; - } - setPixelColorXY(cols-1, row, curnew); // set last pixel -} - -// blurCol: perform a blur on a column of a rectangular matrix -void Segment::blurCol(int col, fract8 blur_amount, bool smear) { - if (!isActive() || blur_amount == 0) return; // not active - const int cols = vWidth(); - const int rows = vHeight(); - - if (col >= cols) return; - // blur one column - uint8_t keep = smear ? 255 : 255 - blur_amount; - uint8_t seep = blur_amount >> 1; - uint32_t carryover = BLACK; - uint32_t lastnew; - uint32_t last; - uint32_t curnew = BLACK; - for (int y = 0; y < rows; y++) { - uint32_t cur = getPixelColorXY(col, y); - uint32_t part = color_fade(cur, seep); - curnew = color_fade(cur, keep); - if (y > 0) { - if (carryover) curnew = color_add(curnew, carryover); - uint32_t prev = color_add(lastnew, part); - // optimization: only set pixel if color has changed - if (last != prev) setPixelColorXY(col, y - 1, prev); - } else // first pixel - setPixelColorXY(col, y, curnew); - lastnew = curnew; - last = cur; //save original value for comparison on next iteration - carryover = part; - } - setPixelColorXY(col, rows - 1, curnew); -} - -void Segment::blur2D(uint8_t blur_amount, bool smear) { - if (!isActive() || blur_amount == 0) return; // not active +// 2D blurring, can be asymmetrical +void Segment::blur2D(uint8_t blur_x, uint8_t blur_y, bool smear) { + if (!isActive()) return; // not active const unsigned cols = vWidth(); const unsigned rows = vHeight(); - - const uint8_t keep = smear ? 255 : 255 - blur_amount; - const uint8_t seep = blur_amount >> (1 + smear); uint32_t lastnew; uint32_t last; - for (unsigned row = 0; row < rows; row++) { - uint32_t carryover = BLACK; - uint32_t curnew = BLACK; - for (unsigned x = 0; x < cols; x++) { - uint32_t cur = getPixelColorXY(x, row); - uint32_t part = color_fade(cur, seep); - curnew = color_fade(cur, keep); - if (x > 0) { - if (carryover) curnew = color_add(curnew, carryover); - uint32_t prev = color_add(lastnew, part); - // optimization: only set pixel if color has changed - if (last != prev) setPixelColorXY(x - 1, row, prev); - } else setPixelColorXY(x, row, curnew); // first pixel - lastnew = curnew; - last = cur; // save original value for comparison on next iteration - carryover = part; + if(blur_x) { + const uint8_t keepx = smear ? 255 : 255 - blur_x; + const uint8_t seepx = blur_x >> (1 + smear); + for (unsigned row = 0; row < rows; row++) { // blur rows (x direction) + uint32_t carryover = BLACK; + uint32_t curnew = BLACK; + for (unsigned x = 0; x < cols; x++) { + uint32_t cur = getPixelColorXY(x, row); + uint32_t part = color_fade(cur, seepx); + curnew = color_fade(cur, keepx); + if (x > 0) { + if (carryover) curnew = color_add(curnew, carryover); + uint32_t prev = color_add(lastnew, part); + // optimization: only set pixel if color has changed + if (last != prev) setPixelColorXY(x - 1, row, prev); + } else setPixelColorXY(x, row, curnew); // first pixel + lastnew = curnew; + last = cur; // save original value for comparison on next iteration + carryover = part; + } + setPixelColorXY(cols-1, row, curnew); // set last pixel } - setPixelColorXY(cols-1, row, curnew); // set last pixel } - for (unsigned col = 0; col < cols; col++) { - uint32_t carryover = BLACK; - uint32_t curnew = BLACK; - for (unsigned y = 0; y < rows; y++) { - uint32_t cur = getPixelColorXY(col, y); - uint32_t part = color_fade(cur, seep); - curnew = color_fade(cur, keep); - if (y > 0) { - if (carryover) curnew = color_add(curnew, carryover); - uint32_t prev = color_add(lastnew, part); - // optimization: only set pixel if color has changed - if (last != prev) setPixelColorXY(col, y - 1, prev); - } else setPixelColorXY(col, y, curnew); // first pixel - lastnew = curnew; - last = cur; //save original value for comparison on next iteration - carryover = part; + if(blur_y) { + const uint8_t keepy = smear ? 255 : 255 - blur_y; + const uint8_t seepy = blur_y >> (1 + smear); + for (unsigned col = 0; col < cols; col++) { + uint32_t carryover = BLACK; + uint32_t curnew = BLACK; + for (unsigned y = 0; y < rows; y++) { + uint32_t cur = getPixelColorXY(col, y); + uint32_t part = color_fade(cur, seepy); + curnew = color_fade(cur, keepy); + if (y > 0) { + if (carryover) curnew = color_add(curnew, carryover); + uint32_t prev = color_add(lastnew, part); + // optimization: only set pixel if color has changed + if (last != prev) setPixelColorXY(col, y - 1, prev); + } else setPixelColorXY(col, y, curnew); // first pixel + lastnew = curnew; + last = cur; //save original value for comparison on next iteration + carryover = part; + } + setPixelColorXY(col, rows - 1, curnew); } - setPixelColorXY(col, rows - 1, curnew); } } +/* // 2D Box blur void Segment::box_blur(unsigned radius, bool smear) { if (!isActive() || radius == 0) return; // not active @@ -458,43 +414,69 @@ void Segment::box_blur(unsigned radius, bool smear) { delete[] tmpBSum; delete[] tmpWSum; } - +*/ void Segment::moveX(int delta, bool wrap) { - if (!isActive()) return; // not active + if (!isActive() || !delta) return; // not active const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) const int vH = vHeight(); // segment height in logical pixels (is always >= 1) - if (!delta || abs(delta) >= vW) return; + int absDelta = abs(delta); + if (absDelta >= vW) return; uint32_t newPxCol[vW]; + int newDelta; + int stop = vW; + int start = 0; + if(wrap) newDelta = (delta + vW) % vW; // +cols in case delta < 0 + else { + if(delta < 0) start = -delta; + stop = vW - absDelta; + newDelta = delta > 0 ? delta : 0; + } for (int y = 0; y < vH; y++) { - if (delta > 0) { - for (int x = 0; x < vW-delta; x++) newPxCol[x] = getPixelColorXY((x + delta), y); - for (int x = vW-delta; x < vW; x++) newPxCol[x] = getPixelColorXY(wrap ? (x + delta) - vW : x, y); - } else { - for (int x = vW-1; x >= -delta; x--) newPxCol[x] = getPixelColorXY((x + delta), y); - for (int x = -delta-1; x >= 0; x--) newPxCol[x] = getPixelColorXY(wrap ? (x + delta) + vW : x, y); + for (int x = 0; x < stop; x++) { + int srcX; + if (wrap) { + srcX = (x + newDelta) % vW; // Wrap using modulo when `wrap` is true + } else { + srcX = x + newDelta; + } + newPxCol[x] = getPixelColorXY(srcX, y); } - for (int x = 0; x < vW; x++) setPixelColorXY(x, y, newPxCol[x]); + for (int x = 0; x < stop; x++) setPixelColorXY(x + start, y, newPxCol[x]); } } void Segment::moveY(int delta, bool wrap) { - if (!isActive()) return; // not active + if (!isActive() || !delta) return; // not active const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) const int vH = vHeight(); // segment height in logical pixels (is always >= 1) - if (!delta || abs(delta) >= vH) return; + int absDelta = abs(delta); + if (absDelta >= vH) return; uint32_t newPxCol[vH]; + int newDelta; + int stop = vH; + int start = 0; + if(wrap) newDelta = (delta + vH) % vH; // +rows in case delta < 0 + else { + if(delta < 0) start = -delta; + stop = vH - absDelta; + newDelta = delta > 0 ? delta : 0; + } for (int x = 0; x < vW; x++) { - if (delta > 0) { - for (int y = 0; y < vH-delta; y++) newPxCol[y] = getPixelColorXY(x, (y + delta)); - for (int y = vH-delta; y < vH; y++) newPxCol[y] = getPixelColorXY(x, wrap ? (y + delta) - vH : y); - } else { - for (int y = vH-1; y >= -delta; y--) newPxCol[y] = getPixelColorXY(x, (y + delta)); - for (int y = -delta-1; y >= 0; y--) newPxCol[y] = getPixelColorXY(x, wrap ? (y + delta) + vH : y); + for (int y = 0; y < stop; y++) { + int srcY; + if (wrap) { + srcY = (y + newDelta) % vH; // Wrap using modulo when `wrap` is true + } else { + srcY = y + newDelta; + } + newPxCol[y] = getPixelColorXY(x, srcY); } - for (int y = 0; y < vH; y++) setPixelColorXY(x, y, newPxCol[y]); + for (int y = 0; y < stop; y++) setPixelColorXY(x, y + start, newPxCol[y]); } } +// TODO: check if it works, used in FX rain and 2D spaceships + // move() - move all pixels in desired direction delta number of pixels // @param dir direction: 0=left, 1=left-up, 2=up, 3=right-up, 4=right, 5=right-down, 6=down, 7=left-down // @param delta number of pixels to move diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 7927269e..613b41fa 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1146,7 +1146,7 @@ void Segment::blur(uint8_t blur_amount, bool smear) { #ifndef WLED_DISABLE_2D if (is2D()) { // compatibility with 2D - blur2D(blur_amount, smear); + blur2D(blur_amount, blur_amount, smear); // symmetrical 2D blur //box_blur(map(blur_amount,1,255,1,3), smear); return; } From ca062140f3c17eb64928a5b47566bb7599828cb1 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 3 Oct 2024 19:39:39 +0000 Subject: [PATCH 053/463] removed todo. --- wled00/FX_2Dfcn.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 3ad061a8..6b3e6ef1 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -475,8 +475,6 @@ void Segment::moveY(int delta, bool wrap) { } } -// TODO: check if it works, used in FX rain and 2D spaceships - // move() - move all pixels in desired direction delta number of pixels // @param dir direction: 0=left, 1=left-up, 2=up, 3=right-up, 4=right, 5=right-down, 6=down, 7=left-down // @param delta number of pixels to move From eb5ad232a0e8dd5623051bc8d03c399fba318291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sat, 5 Oct 2024 23:31:31 +0200 Subject: [PATCH 054/463] Minor tweaks and whitespace --- wled00/FX_2Dfcn.cpp | 35 +++++++++++++---------------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 6b3e6ef1..0e31083d 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -195,6 +195,7 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) const int vH = vHeight(); // segment height in logical pixels (is always >= 1) + // negative values of x & y cast into unsigend will become very large values and will therefore be greater than vW/vH if (unsigned(x) >= unsigned(vW) || unsigned(y) >= unsigned(vH)) return; // if pixel would fall out of virtual segment just exit // if color is unscaled @@ -205,8 +206,7 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed unsigned groupLen = groupLength(); - if(groupLen > 1) - { + if (groupLen > 1) { int W = width(); int H = height(); x *= groupLen; // expand to physical pixels @@ -222,8 +222,7 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) } yY++; } - } - else { + } else { _setPixelColorXY_raw(x, y, col); } } @@ -293,7 +292,7 @@ void Segment::blur2D(uint8_t blur_x, uint8_t blur_y, bool smear) { const unsigned rows = vHeight(); uint32_t lastnew; uint32_t last; - if(blur_x) { + if (blur_x) { const uint8_t keepx = smear ? 255 : 255 - blur_x; const uint8_t seepx = blur_x >> (1 + smear); for (unsigned row = 0; row < rows; row++) { // blur rows (x direction) @@ -316,7 +315,7 @@ void Segment::blur2D(uint8_t blur_x, uint8_t blur_y, bool smear) { setPixelColorXY(cols-1, row, curnew); // set last pixel } } - if(blur_y) { + if (blur_y) { const uint8_t keepy = smear ? 255 : 255 - blur_y; const uint8_t seepy = blur_y >> (1 + smear); for (unsigned col = 0; col < cols; col++) { @@ -425,20 +424,16 @@ void Segment::moveX(int delta, bool wrap) { int newDelta; int stop = vW; int start = 0; - if(wrap) newDelta = (delta + vW) % vW; // +cols in case delta < 0 + if (wrap) newDelta = (delta + vW) % vW; // +cols in case delta < 0 else { - if(delta < 0) start = -delta; + if (delta < 0) start = absDelta; stop = vW - absDelta; newDelta = delta > 0 ? delta : 0; } for (int y = 0; y < vH; y++) { for (int x = 0; x < stop; x++) { - int srcX; - if (wrap) { - srcX = (x + newDelta) % vW; // Wrap using modulo when `wrap` is true - } else { - srcX = x + newDelta; - } + int srcX = x + newDelta; + if (wrap) srcX %= vW; // Wrap using modulo when `wrap` is true newPxCol[x] = getPixelColorXY(srcX, y); } for (int x = 0; x < stop; x++) setPixelColorXY(x + start, y, newPxCol[x]); @@ -455,20 +450,16 @@ void Segment::moveY(int delta, bool wrap) { int newDelta; int stop = vH; int start = 0; - if(wrap) newDelta = (delta + vH) % vH; // +rows in case delta < 0 + if (wrap) newDelta = (delta + vH) % vH; // +rows in case delta < 0 else { - if(delta < 0) start = -delta; + if (delta < 0) start = absDelta; stop = vH - absDelta; newDelta = delta > 0 ? delta : 0; } for (int x = 0; x < vW; x++) { for (int y = 0; y < stop; y++) { - int srcY; - if (wrap) { - srcY = (y + newDelta) % vH; // Wrap using modulo when `wrap` is true - } else { - srcY = y + newDelta; - } + int srcY = y + newDelta; + if (wrap) srcY %= vH; // Wrap using modulo when `wrap` is true newPxCol[y] = getPixelColorXY(x, srcY); } for (int y = 0; y < stop; y++) setPixelColorXY(x, y + start, newPxCol[y]); From be64930ebb97b554e3e03c6c178269cec791053a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Mon, 7 Oct 2024 16:50:51 +0200 Subject: [PATCH 055/463] Indentation and shadowed variable. --- wled00/FX_2Dfcn.cpp | 6 +++--- wled00/colors.cpp | 48 ++++++++++++++++++++++----------------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 0e31083d..5a7dc76d 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -652,9 +652,9 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, case 60: bits = pgm_read_byte_near(&console_font_5x12[(chr * h) + i]); break; // 5x12 font default: return; } - uint32_t col = ColorFromPaletteWLED(grad, (i+1)*255/h, 255, NOBLEND); + uint32_t c = ColorFromPaletteWLED(grad, (i+1)*255/h, 255, NOBLEND); // pre-scale color for all pixels - col = color_fade(col, _segBri); + c = color_fade(c, _segBri); _colorScaled = true; for (int j = 0; j= (int)vWidth() || y0 < 0 || y0 >= (int)vHeight()) continue; // drawing off-screen if (((bits>>(j+(8-w))) & 0x01)) { // bit set - setPixelColorXY(x0, y0, col); + setPixelColorXY(x0, y0, c); } } _colorScaled = false; diff --git a/wled00/colors.cpp b/wled00/colors.cpp index c059ea9d..27c9c828 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -98,30 +98,30 @@ uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) // 1:1 replacement of fastled function optimized for ESP, slightly faster, more accurate and uses less flash (~ -200bytes) uint32_t ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brightness, TBlendType blendType) { - if (blendType == LINEARBLEND_NOWRAP) { - index = (index*240) >> 8; // Blend range is affected by lo4 blend of values, remap to avoid wrapping - } - unsigned hi4 = byte(index) >> 4; - const CRGB* entry = (CRGB*)( (uint8_t*)(&(pal[0])) + (hi4 * sizeof(CRGB))); - unsigned red1 = entry->r; - unsigned green1 = entry->g; - unsigned blue1 = entry->b; - if (blendType != NOBLEND) { - if (hi4 == 15) entry = &(pal[0]); - else ++entry; - unsigned f2 = ((index & 0x0F) << 4) + 1; // +1 so we scale by 256 as a max value, then result can just be shifted by 8 - unsigned f1 = (257 - f2); // f2 is 1 minimum, so this is 256 max - red1 = (red1 * f1 + (unsigned)entry->r * f2) >> 8; - green1 = (green1 * f1 + (unsigned)entry->g * f2) >> 8; - blue1 = (blue1 * f1 + (unsigned)entry->b * f2) >> 8; - } - if (brightness < 255) { // note: zero checking could be done to return black but that is hardly ever used so it is omitted - uint32_t scale = brightness + 1; // adjust for rounding (bitshift) - red1 = (red1 * scale) >> 8; - green1 = (green1 * scale) >> 8; - blue1 = (blue1 * scale) >> 8; - } - return RGBW32(red1,green1,blue1,0); + if (blendType == LINEARBLEND_NOWRAP) { + index = (index*240) >> 8; // Blend range is affected by lo4 blend of values, remap to avoid wrapping + } + unsigned hi4 = byte(index) >> 4; + const CRGB* entry = (CRGB*)((uint8_t*)(&(pal[0])) + (hi4 * sizeof(CRGB))); + unsigned red1 = entry->r; + unsigned green1 = entry->g; + unsigned blue1 = entry->b; + if (blendType != NOBLEND) { + if (hi4 == 15) entry = &(pal[0]); + else ++entry; + unsigned f2 = ((index & 0x0F) << 4) + 1; // +1 so we scale by 256 as a max value, then result can just be shifted by 8 + unsigned f1 = (257 - f2); // f2 is 1 minimum, so this is 256 max + red1 = (red1 * f1 + (unsigned)entry->r * f2) >> 8; + green1 = (green1 * f1 + (unsigned)entry->g * f2) >> 8; + blue1 = (blue1 * f1 + (unsigned)entry->b * f2) >> 8; + } + if (brightness < 255) { // note: zero checking could be done to return black but that is hardly ever used so it is omitted + uint32_t scale = brightness + 1; // adjust for rounding (bitshift) + red1 = (red1 * scale) >> 8; + green1 = (green1 * scale) >> 8; + blue1 = (blue1 * scale) >> 8; + } + return RGBW32(red1,green1,blue1,0); } void setRandomColor(byte* rgb) From 210191b251f0ebdca0d5d12f21278b03fe404755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Mon, 7 Oct 2024 20:19:07 +0200 Subject: [PATCH 056/463] Fix for realtime drawing on main segment --- wled00/e131.cpp | 4 ++++ wled00/udp.cpp | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/wled00/e131.cpp b/wled00/e131.cpp index 7c074759..bc26a063 100644 --- a/wled00/e131.cpp +++ b/wled00/e131.cpp @@ -39,6 +39,7 @@ void handleDDPPacket(e131_packet_t* p) { realtimeLock(realtimeTimeoutMs, REALTIME_MODE_DDP); if (!realtimeOverride || (realtimeMode && useMainSegmentOnly)) { + if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); for (unsigned i = start; i < stop; i++, c += ddpChannelsPerLed) { setRealtimePixel(i, data[c], data[c+1], data[c+2], ddpChannelsPerLed >3 ? data[c+3] : 0); } @@ -147,6 +148,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){ if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return; wChannel = (availDMXLen > 3) ? e131_data[dataOffset+3] : 0; + if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); for (unsigned i = 0; i < totalLen; i++) setRealtimePixel(i, e131_data[dataOffset+0], e131_data[dataOffset+1], e131_data[dataOffset+2], wChannel); break; @@ -164,6 +166,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){ strip.setBrightness(bri, true); } + if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); for (unsigned i = 0; i < totalLen; i++) setRealtimePixel(i, e131_data[dataOffset+1], e131_data[dataOffset+2], e131_data[dataOffset+3], wChannel); break; @@ -308,6 +311,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){ } } + if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); if (!is4Chan) { for (unsigned i = previousLeds; i < ledsTotal; i++) { setRealtimePixel(i, e131_data[dmxOffset], e131_data[dmxOffset+1], e131_data[dmxOffset+2], 0); diff --git a/wled00/udp.cpp b/wled00/udp.cpp index 0ff39f11..a6a0f6aa 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -687,10 +687,11 @@ void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w) b = gamma8(b); w = gamma8(w); } + uint32_t col = RGBW32(r,g,b,w); if (useMainSegmentOnly) { - strip.getMainSegment().setPixelColor(pix, r, g, b, w); // this expects that strip.getMainSegment().beginDraw() has been called in handleNotification() + strip.getMainSegment().setPixelColor(pix, col); // this expects that strip.getMainSegment().beginDraw() has been called in handleNotification() } else { - strip.setPixelColor(pix, r, g, b, w); + strip.setPixelColor(pix, col); } } } From 95b4bde918c00c2d3191a0f71a391965d69b3d34 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 20 Oct 2024 10:42:02 -0400 Subject: [PATCH 057/463] UsermodManager: Make into namespace Namespaces are the C++ language construct for grouping global functions. --- wled00/fcn_declare.h | 47 ++++++++++++++++++++----------------------- wled00/um_manager.cpp | 5 +++-- wled00/wled.h | 3 --- 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 71b00599..78655b27 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -326,36 +326,33 @@ class Usermod { template static inline void oappend(const T& t) { oappend_shim->print(t); }; }; -class UsermodManager { - private: - static Usermod* ums[WLED_MAX_USERMODS]; - static byte numMods; +namespace UsermodManager { + extern byte numMods; - public: - static void loop(); - static void handleOverlayDraw(); - static bool handleButton(uint8_t b); - static bool getUMData(um_data_t **um_data, uint8_t mod_id = USERMOD_ID_RESERVED); // USERMOD_ID_RESERVED will poll all usermods - static void setup(); - static void connected(); - static void appendConfigData(Print&); - static void addToJsonState(JsonObject& obj); - static void addToJsonInfo(JsonObject& obj); - static void readFromJsonState(JsonObject& obj); - static void addToConfig(JsonObject& obj); - static bool readFromConfig(JsonObject& obj); + void loop(); + void handleOverlayDraw(); + bool handleButton(uint8_t b); + bool getUMData(um_data_t **um_data, uint8_t mod_id = USERMOD_ID_RESERVED); // USERMOD_ID_RESERVED will poll all usermods + void setup(); + void connected(); + void appendConfigData(Print&); + void addToJsonState(JsonObject& obj); + void addToJsonInfo(JsonObject& obj); + void readFromJsonState(JsonObject& obj); + void addToConfig(JsonObject& obj); + bool readFromConfig(JsonObject& obj); #ifndef WLED_DISABLE_MQTT - static void onMqttConnect(bool sessionPresent); - static bool onMqttMessage(char* topic, char* payload); + void onMqttConnect(bool sessionPresent); + bool onMqttMessage(char* topic, char* payload); #endif #ifndef WLED_DISABLE_ESPNOW - static bool onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t len); + bool onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t len); #endif - static void onUpdateBegin(bool); - static void onStateChange(uint8_t); - static bool add(Usermod* um); - static Usermod* lookup(uint16_t mod_id); - static inline byte getModCount() {return numMods;}; + void onUpdateBegin(bool); + void onStateChange(uint8_t); + bool add(Usermod* um); + Usermod* lookup(uint16_t mod_id); + inline byte getModCount() {return numMods;}; }; //usermods_list.cpp diff --git a/wled00/um_manager.cpp b/wled00/um_manager.cpp index 46fdf5b3..1fdb6d68 100644 --- a/wled00/um_manager.cpp +++ b/wled00/um_manager.cpp @@ -3,6 +3,9 @@ * Registration and management utility for v2 usermods */ +static Usermod* ums[WLED_MAX_USERMODS] = {nullptr}; +byte UsermodManager::numMods = 0; + //Usermod Manager internals void UsermodManager::setup() { for (unsigned i = 0; i < numMods; i++) ums[i]->setup(); } void UsermodManager::connected() { for (unsigned i = 0; i < numMods; i++) ums[i]->connected(); } @@ -69,8 +72,6 @@ bool UsermodManager::add(Usermod* um) return true; } -Usermod* UsermodManager::ums[WLED_MAX_USERMODS] = {nullptr}; -byte UsermodManager::numMods = 0; /* Usermod v2 interface shim for oappend */ Print* Usermod::oappend_shim = nullptr; diff --git a/wled00/wled.h b/wled00/wled.h index bc525cd6..5f1952be 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -896,9 +896,6 @@ WLED_GLOBAL uint32_t ledMaps _INIT(0); // bitfield representation of available l WLED_GLOBAL uint16_t ledMaps _INIT(0); // bitfield representation of available ledmaps #endif -// Usermod manager -WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager()); - // global I2C SDA pin (used for usermods) #ifndef I2CSDAPIN WLED_GLOBAL int8_t i2c_sda _INIT(-1); From 32eee3365ac06858b5d6821931c39c020af233bc Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 20 Oct 2024 10:48:31 -0400 Subject: [PATCH 058/463] PinManager: Make in to namespace Namespaces are the C++ language construct for grouping global functions. --- wled00/pin_manager.cpp | 20 +++++------ wled00/pin_manager.h | 78 +++++++++++++++++++----------------------- 2 files changed, 45 insertions(+), 53 deletions(-) diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index 793b5440..14209977 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -13,6 +13,16 @@ #endif #endif +// Pin management state variables +#ifdef ESP8266 +static uint32_t pinAlloc = 0UL; // 1 bit per pin, we use first 17bits +#else +static uint64_t pinAlloc = 0ULL; // 1 bit per pin, we use 50 bits on ESP32-S3 +static uint16_t ledcAlloc = 0; // up to 16 LEDC channels (WLED_MAX_ANALOG_CHANNELS) +#endif +static uint8_t i2cAllocCount = 0; // allow multiple allocation of I2C bus pins but keep track of allocations +static uint8_t spiAllocCount = 0; // allow multiple allocation of SPI bus pins but keep track of allocations +static PinOwner ownerTag[WLED_NUM_PINS] = { PinOwner::None }; /// Actual allocation/deallocation routines bool PinManager::deallocatePin(byte gpio, PinOwner tag) @@ -273,13 +283,3 @@ void PinManager::deallocateLedc(byte pos, byte channels) } } #endif - -#ifdef ESP8266 -uint32_t PinManager::pinAlloc = 0UL; -#else -uint64_t PinManager::pinAlloc = 0ULL; -uint16_t PinManager::ledcAlloc = 0; -#endif -uint8_t PinManager::i2cAllocCount = 0; -uint8_t PinManager::spiAllocCount = 0; -PinOwner PinManager::ownerTag[WLED_NUM_PINS] = { PinOwner::None }; diff --git a/wled00/pin_manager.h b/wled00/pin_manager.h index 73a4a365..c8fb165c 100644 --- a/wled00/pin_manager.h +++ b/wled00/pin_manager.h @@ -9,6 +9,12 @@ #endif #include "const.h" // for USERMOD_* values +#ifdef ESP8266 +#define WLED_NUM_PINS (GPIO_PIN_COUNT+1) // somehow they forgot GPIO 16 (0-16==17) +#else +#define WLED_NUM_PINS (GPIO_PIN_COUNT) +#endif + typedef struct PinManagerPinType { int8_t pin; bool isOutput; @@ -70,53 +76,39 @@ enum struct PinOwner : uint8_t { }; static_assert(0u == static_cast(PinOwner::None), "PinOwner::None must be zero, so default array initialization works as expected"); -class PinManager { - private: - #ifdef ESP8266 - #define WLED_NUM_PINS (GPIO_PIN_COUNT+1) // somehow they forgot GPIO 16 (0-16==17) - static uint32_t pinAlloc; // 1 bit per pin, we use first 17bits - #else - #define WLED_NUM_PINS (GPIO_PIN_COUNT) - static uint64_t pinAlloc; // 1 bit per pin, we use 50 bits on ESP32-S3 - static uint16_t ledcAlloc; // up to 16 LEDC channels (WLED_MAX_ANALOG_CHANNELS) - #endif - static uint8_t i2cAllocCount; // allow multiple allocation of I2C bus pins but keep track of allocations - static uint8_t spiAllocCount; // allow multiple allocation of SPI bus pins but keep track of allocations - static PinOwner ownerTag[WLED_NUM_PINS]; +namespace PinManager { + // De-allocates a single pin + bool deallocatePin(byte gpio, PinOwner tag); + // De-allocates multiple pins but only if all can be deallocated (PinOwner has to be specified) + bool deallocateMultiplePins(const uint8_t *pinArray, byte arrayElementCount, PinOwner tag); + bool deallocateMultiplePins(const managed_pin_type *pinArray, byte arrayElementCount, PinOwner tag); + // Allocates a single pin, with an owner tag. + // De-allocation requires the same owner tag (or override) + bool allocatePin(byte gpio, bool output, PinOwner tag); + // Allocates all the pins, or allocates none of the pins, with owner tag. + // Provided to simplify error condition handling in clients + // using more than one pin, such as I2C, SPI, rotary encoders, + // ethernet, etc.. + bool allocateMultiplePins(const managed_pin_type * mptArray, byte arrayElementCount, PinOwner tag ); - public: - // De-allocates a single pin - static bool deallocatePin(byte gpio, PinOwner tag); - // De-allocates multiple pins but only if all can be deallocated (PinOwner has to be specified) - static bool deallocateMultiplePins(const uint8_t *pinArray, byte arrayElementCount, PinOwner tag); - static bool deallocateMultiplePins(const managed_pin_type *pinArray, byte arrayElementCount, PinOwner tag); - // Allocates a single pin, with an owner tag. - // De-allocation requires the same owner tag (or override) - static bool allocatePin(byte gpio, bool output, PinOwner tag); - // Allocates all the pins, or allocates none of the pins, with owner tag. - // Provided to simplify error condition handling in clients - // using more than one pin, such as I2C, SPI, rotary encoders, - // ethernet, etc.. - static bool allocateMultiplePins(const managed_pin_type * mptArray, byte arrayElementCount, PinOwner tag ); + [[deprecated("Replaced by three-parameter allocatePin(gpio, output, ownerTag), for improved debugging")]] + inline bool allocatePin(byte gpio, bool output = true) { return allocatePin(gpio, output, PinOwner::None); } + [[deprecated("Replaced by two-parameter deallocatePin(gpio, ownerTag), for improved debugging")]] + inline void deallocatePin(byte gpio) { deallocatePin(gpio, PinOwner::None); } - [[deprecated("Replaced by three-parameter allocatePin(gpio, output, ownerTag), for improved debugging")]] - static inline bool allocatePin(byte gpio, bool output = true) { return allocatePin(gpio, output, PinOwner::None); } - [[deprecated("Replaced by two-parameter deallocatePin(gpio, ownerTag), for improved debugging")]] - static inline void deallocatePin(byte gpio) { deallocatePin(gpio, PinOwner::None); } + // will return true for reserved pins + bool isPinAllocated(byte gpio, PinOwner tag = PinOwner::None); + // will return false for reserved pins + bool isPinOk(byte gpio, bool output = true); + + bool isReadOnlyPin(byte gpio); - // will return true for reserved pins - static bool isPinAllocated(byte gpio, PinOwner tag = PinOwner::None); - // will return false for reserved pins - static bool isPinOk(byte gpio, bool output = true); - - static bool isReadOnlyPin(byte gpio); + PinOwner getPinOwner(byte gpio); - static PinOwner getPinOwner(byte gpio); - - #ifdef ARDUINO_ARCH_ESP32 - static byte allocateLedc(byte channels); - static void deallocateLedc(byte pos, byte channels); - #endif + #ifdef ARDUINO_ARCH_ESP32 + byte allocateLedc(byte channels); + void deallocateLedc(byte pos, byte channels); + #endif }; //extern PinManager pinManager; From ef1e24cec26cdb05b7a342e7a432f03692ca521e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sat, 9 Nov 2024 10:42:49 +0100 Subject: [PATCH 059/463] Bugfix & code reduction - correctly clear segment spacing change - renamed Segment::setUp() to Segment::setGeometry() - removed WS2812FX::setSegment() - removed obsolete/unfunctional word clock usermod .cpp file --- .../usermod_word_clock_matrix.h | 128 ++++---- .../word-clock-matrix/word-clock-matrix.cpp | 305 ------------------ wled00/FX.h | 6 +- wled00/FX_fcn.cpp | 34 +- wled00/json.cpp | 16 +- wled00/set.cpp | 4 +- wled00/udp.cpp | 15 +- 7 files changed, 99 insertions(+), 409 deletions(-) delete mode 100644 usermods/word-clock-matrix/word-clock-matrix.cpp diff --git a/usermods/word-clock-matrix/usermod_word_clock_matrix.h b/usermods/word-clock-matrix/usermod_word_clock_matrix.h index 506c1275..82499c0c 100644 --- a/usermods/word-clock-matrix/usermod_word_clock_matrix.h +++ b/usermods/word-clock-matrix/usermod_word_clock_matrix.h @@ -31,14 +31,14 @@ public: //strip.getSegment(1).setOption(SEG_OPTION_SELECTED, true); //select first two segments (background color + FX settable) - WS2812FX::Segment &seg = strip.getSegment(0); + Segment &seg = strip.getSegment(0); seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((0 & 0xFF) << 8) | ((0 & 0xFF))); strip.getSegment(0).setOption(0, false); strip.getSegment(0).setOption(2, false); //other segments are text for (int i = 1; i < 10; i++) { - WS2812FX::Segment &seg = strip.getSegment(i); + Segment &seg = strip.getSegment(i); seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((190 & 0xFF) << 8) | ((180 & 0xFF))); strip.getSegment(i).setOption(0, true); strip.setBrightness(64); @@ -80,61 +80,61 @@ public: void displayTime(byte hour, byte minute) { bool isToHour = false; //true if minute > 30 - strip.setSegment(0, 0, 64); // background - strip.setSegment(1, 0, 2); //It is + strip.getSegment(0).setGeometry(0, 64); // background + strip.getSegment(1).setGeometry(0, 2); //It is - strip.setSegment(2, 0, 0); - strip.setSegment(3, 0, 0); //disable minutes - strip.setSegment(4, 0, 0); //past - strip.setSegment(6, 0, 0); //to - strip.setSegment(8, 0, 0); //disable o'clock + strip.getSegment(2).setGeometry(0, 0); + strip.getSegment(3).setGeometry(0, 0); //disable minutes + strip.getSegment(4).setGeometry(0, 0); //past + strip.getSegment(6).setGeometry(0, 0); //to + strip.getSegment(8).setGeometry(0, 0); //disable o'clock if (hour < 24) //valid time, display { if (minute == 30) { - strip.setSegment(2, 3, 6); //half - strip.setSegment(3, 0, 0); //minutes + strip.getSegment(2).setGeometry(3, 6); //half + strip.getSegment(3).setGeometry(0, 0); //minutes } else if (minute == 15 || minute == 45) { - strip.setSegment(3, 0, 0); //minutes + strip.getSegment(3).setGeometry(0, 0); //minutes } else if (minute == 10) { - //strip.setSegment(5, 6, 8); //ten + //strip.getSegment(5).setGeometry(6, 8); //ten } else if (minute == 5) { - //strip.setSegment(5, 16, 18); //five + //strip.getSegment(5).setGeometry(16, 18); //five } else if (minute == 0) { - strip.setSegment(3, 0, 0); //minutes + strip.getSegment(3).setGeometry(0, 0); //minutes //hourChime(); } else { - strip.setSegment(3, 18, 22); //minutes + strip.getSegment(3).setGeometry(18, 22); //minutes } //past or to? if (minute == 0) { //full hour - strip.setSegment(3, 0, 0); //disable minutes - strip.setSegment(4, 0, 0); //disable past - strip.setSegment(6, 0, 0); //disable to - strip.setSegment(8, 60, 64); //o'clock + strip.getSegment(3).setGeometry(0, 0); //disable minutes + strip.getSegment(4).setGeometry(0, 0); //disable past + strip.getSegment(6).setGeometry(0, 0); //disable to + strip.getSegment(8).setGeometry(60, 64); //o'clock } else if (minute > 34) { - //strip.setSegment(6, 22, 24); //to + //strip.getSegment(6).setGeometry(22, 24); //to //minute = 60 - minute; isToHour = true; } else { - //strip.setSegment(4, 24, 27); //past + //strip.getSegment(4).setGeometry(24, 27); //past //isToHour = false; } } @@ -143,68 +143,68 @@ public: if (minute <= 4) { - strip.setSegment(3, 0, 0); //nothing - strip.setSegment(5, 0, 0); //nothing - strip.setSegment(6, 0, 0); //nothing - strip.setSegment(8, 60, 64); //o'clock + strip.getSegment(3).setGeometry(0, 0); //nothing + strip.getSegment(5).setGeometry(0, 0); //nothing + strip.getSegment(6).setGeometry(0, 0); //nothing + strip.getSegment(8).setGeometry(60, 64); //o'clock } else if (minute <= 9) { - strip.setSegment(5, 16, 18); // five past - strip.setSegment(4, 24, 27); //past + strip.getSegment(5).setGeometry(16, 18); // five past + strip.getSegment(4).setGeometry(24, 27); //past } else if (minute <= 14) { - strip.setSegment(5, 6, 8); // ten past - strip.setSegment(4, 24, 27); //past + strip.getSegment(5).setGeometry(6, 8); // ten past + strip.getSegment(4).setGeometry(24, 27); //past } else if (minute <= 19) { - strip.setSegment(5, 8, 12); // quarter past - strip.setSegment(3, 0, 0); //minutes - strip.setSegment(4, 24, 27); //past + strip.getSegment(5).setGeometry(8, 12); // quarter past + strip.getSegment(3).setGeometry(0, 0); //minutes + strip.getSegment(4).setGeometry(24, 27); //past } else if (minute <= 24) { - strip.setSegment(5, 12, 16); // twenty past - strip.setSegment(4, 24, 27); //past + strip.getSegment(5).setGeometry(12, 16); // twenty past + strip.getSegment(4).setGeometry(24, 27); //past } else if (minute <= 29) { - strip.setSegment(5, 12, 18); // twenty-five past - strip.setSegment(4, 24, 27); //past + strip.getSegment(5).setGeometry(12, 18); // twenty-five past + strip.getSegment(4).setGeometry(24, 27); //past } else if (minute <= 34) { - strip.setSegment(5, 3, 6); // half past - strip.setSegment(3, 0, 0); //minutes - strip.setSegment(4, 24, 27); //past + strip.getSegment(5).setGeometry(3, 6); // half past + strip.getSegment(3).setGeometry(0, 0); //minutes + strip.getSegment(4).setGeometry(24, 27); //past } else if (minute <= 39) { - strip.setSegment(5, 12, 18); // twenty-five to - strip.setSegment(6, 22, 24); //to + strip.getSegment(5).setGeometry(12, 18); // twenty-five to + strip.getSegment(6).setGeometry(22, 24); //to } else if (minute <= 44) { - strip.setSegment(5, 12, 16); // twenty to - strip.setSegment(6, 22, 24); //to + strip.getSegment(5).setGeometry(12, 16); // twenty to + strip.getSegment(6).setGeometry(22, 24); //to } else if (minute <= 49) { - strip.setSegment(5, 8, 12); // quarter to - strip.setSegment(3, 0, 0); //minutes - strip.setSegment(6, 22, 24); //to + strip.getSegment(5).setGeometry(8, 12); // quarter to + strip.getSegment(3).setGeometry(0, 0); //minutes + strip.getSegment(6).setGeometry(22, 24); //to } else if (minute <= 54) { - strip.setSegment(5, 6, 8); // ten to - strip.setSegment(6, 22, 24); //to + strip.getSegment(5).setGeometry(6, 8); // ten to + strip.getSegment(6).setGeometry(22, 24); //to } else if (minute <= 59) { - strip.setSegment(5, 16, 18); // five to - strip.setSegment(6, 22, 24); //to + strip.getSegment(5).setGeometry(16, 18); // five to + strip.getSegment(6).setGeometry(22, 24); //to } //hours @@ -220,45 +220,45 @@ public: switch (hour) { case 1: - strip.setSegment(7, 27, 29); + strip.getSegment(7).setGeometry(27, 29); break; //one case 2: - strip.setSegment(7, 35, 37); + strip.getSegment(7).setGeometry(35, 37); break; //two case 3: - strip.setSegment(7, 29, 32); + strip.getSegment(7).setGeometry(29, 32); break; //three case 4: - strip.setSegment(7, 32, 35); + strip.getSegment(7).setGeometry(32, 35); break; //four case 5: - strip.setSegment(7, 37, 40); + strip.getSegment(7).setGeometry(37, 40); break; //five case 6: - strip.setSegment(7, 43, 45); + strip.getSegment(7).setGeometry(43, 45); break; //six case 7: - strip.setSegment(7, 40, 43); + strip.getSegment(7).setGeometry(40, 43); break; //seven case 8: - strip.setSegment(7, 45, 48); + strip.getSegment(7).setGeometry(45, 48); break; //eight case 9: - strip.setSegment(7, 48, 50); + strip.getSegment(7).setGeometry(48, 50); break; //nine case 10: - strip.setSegment(7, 54, 56); + strip.getSegment(7).setGeometry(54, 56); break; //ten case 11: - strip.setSegment(7, 50, 54); + strip.getSegment(7).setGeometry(50, 54); break; //eleven case 12: - strip.setSegment(7, 56, 60); + strip.getSegment(7).setGeometry(56, 60); break; //twelve } selectWordSegments(true); - applyMacro(1); + applyPreset(1); } void timeOfDay() diff --git a/usermods/word-clock-matrix/word-clock-matrix.cpp b/usermods/word-clock-matrix/word-clock-matrix.cpp deleted file mode 100644 index 67c5b1e4..00000000 --- a/usermods/word-clock-matrix/word-clock-matrix.cpp +++ /dev/null @@ -1,305 +0,0 @@ -#include "wled.h" -/* - * This v1 usermod file allows you to add own functionality to WLED more easily - * See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality - * EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h) - * If you just need 8 bytes, use 2551-2559 (you do not need to increase EEPSIZE) - * - * Consider the v2 usermod API if you need a more advanced feature set! - */ - - -uint8_t minuteLast = 99; -int dayBrightness = 128; -int nightBrightness = 16; - -//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t) - -//gets called once at boot. Do all initialization that doesn't depend on network here -void userSetup() -{ -saveMacro(14, "A=128", false); -saveMacro(15, "A=64", false); -saveMacro(16, "A=16", false); - -saveMacro(1, "&FX=0&R=255&G=255&B=255", false); - -//strip.getSegment(1).setOption(SEG_OPTION_SELECTED, true); - - //select first two segments (background color + FX settable) - Segment &seg = strip.getSegment(0); - seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((0 & 0xFF) << 8) | ((0 & 0xFF))); - strip.getSegment(0).setOption(0, false); - strip.getSegment(0).setOption(2, false); - //other segments are text - for (int i = 1; i < 10; i++) - { - Segment &seg = strip.getSegment(i); - seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((190 & 0xFF) << 8) | ((180 & 0xFF))); - strip.getSegment(i).setOption(0, true); - strip.setBrightness(128); - } -} - -//gets called every time WiFi is (re-)connected. Initialize own network interfaces here -void userConnected() -{ -} - -void selectWordSegments(bool state) -{ - for (int i = 1; i < 10; i++) - { - //Segment &seg = strip.getSegment(i); - strip.getSegment(i).setOption(0, state); - // strip.getSegment(1).setOption(SEG_OPTION_SELECTED, true); - //seg.mode = 12; - //seg.palette = 1; - //strip.setBrightness(255); - } - strip.getSegment(0).setOption(0, !state); -} - -void hourChime() -{ - //strip.resetSegments(); - selectWordSegments(true); - colorUpdated(CALL_MODE_FX_CHANGED); - //savePreset(255); - selectWordSegments(false); - //strip.getSegment(0).setOption(0, true); - strip.getSegment(0).setOption(2, true); - applyPreset(12); - colorUpdated(CALL_MODE_FX_CHANGED); -} - -void displayTime(byte hour, byte minute) -{ - bool isToHour = false; //true if minute > 30 - strip.setSegment(0, 0, 64); // background - strip.setSegment(1, 0, 2); //It is - - strip.setSegment(2, 0, 0); - strip.setSegment(3, 0, 0); //disable minutes - strip.setSegment(4, 0, 0); //past - strip.setSegment(6, 0, 0); //to - strip.setSegment(8, 0, 0); //disable o'clock - - if (hour < 24) //valid time, display - { - if (minute == 30) - { - strip.setSegment(2, 3, 6); //half - strip.setSegment(3, 0, 0); //minutes - } - else if (minute == 15 || minute == 45) - { - strip.setSegment(3, 0, 0); //minutes - } - else if (minute == 10) - { - //strip.setSegment(5, 6, 8); //ten - } - else if (minute == 5) - { - //strip.setSegment(5, 16, 18); //five - } - else if (minute == 0) - { - strip.setSegment(3, 0, 0); //minutes - //hourChime(); - } - else - { - strip.setSegment(3, 18, 22); //minutes - } - - //past or to? - if (minute == 0) - { //full hour - strip.setSegment(3, 0, 0); //disable minutes - strip.setSegment(4, 0, 0); //disable past - strip.setSegment(6, 0, 0); //disable to - strip.setSegment(8, 60, 64); //o'clock - } - else if (minute > 34) - { - //strip.setSegment(6, 22, 24); //to - //minute = 60 - minute; - isToHour = true; - } - else - { - //strip.setSegment(4, 24, 27); //past - //isToHour = false; - } - } - else - { //temperature display - } - - //byte minuteRem = minute %10; - - if (minute <= 4) - { - strip.setSegment(3, 0, 0); //nothing - strip.setSegment(5, 0, 0); //nothing - strip.setSegment(6, 0, 0); //nothing - strip.setSegment(8, 60, 64); //o'clock - } - else if (minute <= 9) - { - strip.setSegment(5, 16, 18); // five past - strip.setSegment(4, 24, 27); //past - } - else if (minute <= 14) - { - strip.setSegment(5, 6, 8); // ten past - strip.setSegment(4, 24, 27); //past - } - else if (minute <= 19) - { - strip.setSegment(5, 8, 12); // quarter past - strip.setSegment(3, 0, 0); //minutes - strip.setSegment(4, 24, 27); //past - } - else if (minute <= 24) - { - strip.setSegment(5, 12, 16); // twenty past - strip.setSegment(4, 24, 27); //past - } - else if (minute <= 29) - { - strip.setSegment(5, 12, 18); // twenty-five past - strip.setSegment(4, 24, 27); //past - } - else if (minute <= 34) - { - strip.setSegment(5, 3, 6); // half past - strip.setSegment(3, 0, 0); //minutes - strip.setSegment(4, 24, 27); //past - } - else if (minute <= 39) - { - strip.setSegment(5, 12, 18); // twenty-five to - strip.setSegment(6, 22, 24); //to - } - else if (minute <= 44) - { - strip.setSegment(5, 12, 16); // twenty to - strip.setSegment(6, 22, 24); //to - } - else if (minute <= 49) - { - strip.setSegment(5, 8, 12); // quarter to - strip.setSegment(3, 0, 0); //minutes - strip.setSegment(6, 22, 24); //to - } - else if (minute <= 54) - { - strip.setSegment(5, 6, 8); // ten to - strip.setSegment(6, 22, 24); //to - } - else if (minute <= 59) - { - strip.setSegment(5, 16, 18); // five to - strip.setSegment(6, 22, 24); //to - } - - //hours - if (hour > 23) - return; - if (isToHour) - hour++; - if (hour > 12) - hour -= 12; - if (hour == 0) - hour = 12; - - switch (hour) - { - case 1: - strip.setSegment(7, 27, 29); - break; //one - case 2: - strip.setSegment(7, 35, 37); - break; //two - case 3: - strip.setSegment(7, 29, 32); - break; //three - case 4: - strip.setSegment(7, 32, 35); - break; //four - case 5: - strip.setSegment(7, 37, 40); - break; //five - case 6: - strip.setSegment(7, 43, 45); - break; //six - case 7: - strip.setSegment(7, 40, 43); - break; //seven - case 8: - strip.setSegment(7, 45, 48); - break; //eight - case 9: - strip.setSegment(7, 48, 50); - break; //nine - case 10: - strip.setSegment(7, 54, 56); - break; //ten - case 11: - strip.setSegment(7, 50, 54); - break; //eleven - case 12: - strip.setSegment(7, 56, 60); - break; //twelve - } - -selectWordSegments(true); -applyMacro(1); -} - -void timeOfDay() { -// NOT USED: use timed macros instead - //Used to set brightness dependant of time of day - lights dimmed at night - - //monday to thursday and sunday - - if ((weekday(localTime) == 6) | (weekday(localTime) == 7)) { - if (hour(localTime) > 0 | hour(localTime) < 8) { - strip.setBrightness(nightBrightness); - } - else { - strip.setBrightness(dayBrightness); - } - } - else { - if (hour(localTime) < 6 | hour(localTime) >= 22) { - strip.setBrightness(nightBrightness); - } - else { - strip.setBrightness(dayBrightness); - } - } -} - -//loop. You can use "if (WLED_CONNECTED)" to check for successful connection -void userLoop() -{ - if (minute(localTime) != minuteLast) - { - updateLocalTime(); - //timeOfDay(); - minuteLast = minute(localTime); - displayTime(hour(localTime), minute(localTime)); - if (minute(localTime) == 0){ - hourChime(); - } - if (minute(localTime) == 1){ - //turn off background segment; - strip.getSegment(0).setOption(2, false); - //applyPreset(255); - } - } -} diff --git a/wled00/FX.h b/wled00/FX.h index c06332c7..d56c0fa9 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -539,6 +539,7 @@ typedef struct Segment { inline uint16_t length() const { return width() * height(); } // segment length (count) in physical pixels inline uint16_t groupLength() const { return grouping + spacing; } inline uint8_t getLightCapabilities() const { return _capabilities; } + inline void deactivate() { setGeometry(0,0); } inline static unsigned getUsedSegmentData() { return Segment::_usedSegmentData; } inline static void addUsedSegmentData(int len) { Segment::_usedSegmentData += len; } @@ -554,14 +555,14 @@ typedef struct Segment { static void handleRandomPalette(); void beginDraw(); // set up parameters for current effect - void setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1); + void setGeometry(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1, uint8_t m12=0); bool setColor(uint8_t slot, uint32_t c); //returns true if changed void setCCT(uint16_t k); void setOpacity(uint8_t o); void setOption(uint8_t n, bool val); void setMode(uint8_t fx, bool loadDefaults = false); void setPalette(uint8_t pal); - uint8_t differs(Segment& b) const; + uint8_t differs(const Segment& b) const; void refreshLightCapabilities(); // runtime data functions @@ -783,7 +784,6 @@ class WS2812FX { // 96 bytes setBrightness(uint8_t b, bool direct = false), // sets strip brightness setRange(uint16_t i, uint16_t i2, uint32_t col), // used for clock overlay purgeSegments(), // removes inactive segments from RAM (may incure penalty and memory fragmentation but reduces vector footprint) - setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 1, uint8_t spacing = 0, uint16_t offset = UINT16_MAX, uint16_t startY=0, uint16_t stopY=1), setMainSegmentId(unsigned n = 0), resetSegments(), // marks all segments for reset makeAutoSegments(bool forceReset = false), // will create segments based on configured outputs diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 613b41fa..69b0c028 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -489,8 +489,10 @@ void Segment::handleRandomPalette() { nblendPaletteTowardPalette(_randomPalette, _newRandomPalette, 48); } -// segId is given when called from network callback, changes are queued if that segment is currently in its effect function -void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y) { +// sets Segment geometry (length or width/height and grouping, spacing and offset as well as 2D mapping) +// strip must be suspended (strip.suspend()) before calling this function +// this function may call fill() to clear pixels if spacing or mapping changed (which requires setting _vWidth, _vHeight, _vLength or beginDraw()) +void Segment::setGeometry(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y, uint8_t m12) { // return if neither bounds nor grouping have changed bool boundsUnchanged = (start == i1 && stop == i2); #ifndef WLED_DISABLE_2D @@ -498,11 +500,19 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t #endif if (boundsUnchanged && (!grp || (grouping == grp && spacing == spc)) - && (ofs == UINT16_MAX || ofs == offset)) return; + && (ofs == UINT16_MAX || ofs == offset) + && (m12 == map1D2D) + ) return; stateChanged = true; // send UDP/WS broadcast - if (stop) fill(BLACK); // turn old segment range off (clears pixels if changing spacing) + if (stop || spc != spacing || m12 != map1D2D) { + _vWidth = virtualWidth(); + _vHeight = virtualHeight(); + _vLength = virtualLength(); + _segBri = currentBri(); + fill(BLACK); // turn old segment range off or clears pixels if changing spacing (requires _vWidth/_vHeight/_vLength/_segBri) + } if (grp) { // prevent assignment of 0 grouping = grp; spacing = spc; @@ -511,6 +521,7 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t spacing = 0; } if (ofs < UINT16_MAX) offset = ofs; + map1D2D = constrain(m12, 0, 7); DEBUG_PRINT(F("setUp segment: ")); DEBUG_PRINT(i1); DEBUG_PRINT(','); DEBUG_PRINT(i2); @@ -993,7 +1004,7 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const return strip.getPixelColor(i); } -uint8_t Segment::differs(Segment& b) const { +uint8_t Segment::differs(const Segment& b) const { uint8_t d = 0; if (start != b.start) d |= SEG_DIFFERS_BOUNDS; if (stop != b.stop) d |= SEG_DIFFERS_BOUNDS; @@ -1595,19 +1606,6 @@ Segment& WS2812FX::getSegment(unsigned id) { return _segments[id >= _segments.size() ? getMainSegmentId() : id]; // vectors } -// sets new segment bounds, queues if that segment is currently running -void WS2812FX::setSegment(uint8_t segId, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing, uint16_t offset, uint16_t startY, uint16_t stopY) { - if (segId >= getSegmentsNum()) { - if (i2 <= i1) return; // do not append empty/inactive segments - appendSegment(Segment(0, strip.getLengthTotal())); - segId = getSegmentsNum()-1; // segments are added at the end of list - } - suspend(); - _segments[segId].setUp(i1, i2, grouping, spacing, offset, startY, stopY); - resume(); - if (segId > 0 && segId == getSegmentsNum()-1 && i2 <= i1) _segments.pop_back(); // if last segment was deleted remove it from vector -} - void WS2812FX::resetSegments() { _segments.clear(); // destructs all Segment as part of clearing #ifndef WLED_DISABLE_2D diff --git a/wled00/json.cpp b/wled00/json.cpp index 0df7294c..64b9ddd8 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -34,7 +34,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) //DEBUG_PRINTLN(F("-- JSON deserialize segment.")); Segment& seg = strip.getSegment(id); //DEBUG_PRINTF_P(PSTR("-- Original segment: %p (%p)\n"), &seg, seg.data); - Segment prev = seg; //make a backup so we can tell if something changed (calling copy constructor) + const Segment prev = seg; //make a backup so we can tell if something changed (calling copy constructor) //DEBUG_PRINTF_P(PSTR("-- Duplicate segment: %p (%p)\n"), &prev, prev.data); int start = elem["start"] | seg.start; @@ -96,17 +96,11 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) uint16_t of = seg.offset; uint8_t soundSim = elem["si"] | seg.soundSim; uint8_t map1D2D = elem["m12"] | seg.map1D2D; - - if ((spc>0 && spc!=seg.spacing) || seg.map1D2D!=map1D2D) seg.fill(BLACK); // clear spacing gaps - - seg.map1D2D = constrain(map1D2D, 0, 7); + uint8_t set = elem[F("set")] | seg.set; + seg.set = constrain(set, 0, 3); seg.soundSim = constrain(soundSim, 0, 3); - uint8_t set = elem[F("set")] | seg.set; - seg.set = constrain(set, 0, 3); - - int len = 1; - if (stop > start) len = stop - start; + int len = (stop > start) ? stop - start : 1; int offset = elem[F("of")] | INT32_MAX; if (offset != INT32_MAX) { int offsetAbs = abs(offset); @@ -117,7 +111,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) if (stop > start && of > len -1) of = len -1; // update segment (delete if necessary) - seg.setUp(start, stop, grp, spc, of, startY, stopY); // strip needs to be suspended for this to work without issues + seg.setGeometry(start, stop, grp, spc, of, startY, stopY, map1D2D); // strip needs to be suspended for this to work without issues if (newSeg) seg.refreshLightCapabilities(); // fix for #3403 diff --git a/wled00/set.cpp b/wled00/set.cpp index cf3a07dd..15981d30 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -874,7 +874,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) if (pos > 0) { spcI = std::max(0,getNumVal(&req, pos)); } - strip.setSegment(selectedSeg, startI, stopI, grpI, spcI, UINT16_MAX, startY, stopY); + strip.suspend(); // must suspend strip operations before changing geometry + selseg.setGeometry(startI, stopI, grpI, spcI, UINT16_MAX, startY, stopY, selseg.map1D2D); + strip.resume(); pos = req.indexOf(F("RV=")); //Segment reverse if (pos > 0) selseg.reverse = req.charAt(pos+3) != '0'; diff --git a/wled00/udp.cpp b/wled00/udp.cpp index a6a0f6aa..47398bc8 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -260,11 +260,12 @@ void parseNotifyPacket(uint8_t *udpIn) { // are we syncing bounds and slave has more active segments than master? if (receiveSegmentBounds && numSrcSegs < strip.getActiveSegmentsNum()) { DEBUG_PRINTLN(F("Removing excessive segments.")); - for (size_t i=strip.getSegmentsNum(); i>numSrcSegs; i--) { - if (strip.getSegment(i).isActive()) { - strip.setSegment(i-1,0,0); // delete segment - } + strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case" + for (size_t i=strip.getSegmentsNum(); i>numSrcSegs && i>0; i--) { + Segment &seg = strip.getSegment(i-1); + if (seg.isActive()) seg.deactivate(); // delete segment } + strip.resume(); } size_t inactiveSegs = 0; for (size_t i = 0; i < numSrcSegs && i < strip.getMaxSegments(); i++) { @@ -300,7 +301,7 @@ void parseNotifyPacket(uint8_t *udpIn) { if (!receiveSegmentOptions) { DEBUG_PRINTF_P(PSTR("Set segment w/o options: %d [%d,%d;%d,%d]\n"), id, (int)start, (int)stop, (int)startY, (int)stopY); strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case" - selseg.setUp(start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY); + selseg.setGeometry(start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY, selseg.map1D2D); strip.resume(); continue; // we do receive bounds, but not options } @@ -342,12 +343,12 @@ void parseNotifyPacket(uint8_t *udpIn) { if (receiveSegmentBounds) { DEBUG_PRINTF_P(PSTR("Set segment w/ options: %d [%d,%d;%d,%d]\n"), id, (int)start, (int)stop, (int)startY, (int)stopY); strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case" - selseg.setUp(start, stop, udpIn[5+ofs], udpIn[6+ofs], offset, startY, stopY); + selseg.setGeometry(start, stop, udpIn[5+ofs], udpIn[6+ofs], offset, startY, stopY, selseg.map1D2D); strip.resume(); } else { DEBUG_PRINTF_P(PSTR("Set segment grouping: %d [%d,%d]\n"), id, (int)udpIn[5+ofs], (int)udpIn[6+ofs]); strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case" - selseg.setUp(selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], selseg.offset, selseg.startY, selseg.stopY); + selseg.setGeometry(selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], selseg.offset, selseg.startY, selseg.stopY, selseg.map1D2D); strip.resume(); } } From 9fa53ccf058b9e687d17d5350e4993a9dd72d1e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sat, 9 Nov 2024 11:22:38 +0100 Subject: [PATCH 060/463] Large ledmap support - add filtering support for readObjectFromFile() --- wled00/FX_fcn.cpp | 44 +++++++++++++++++++++++++++++++++++++++++++- wled00/fcn_declare.h | 8 ++++---- wled00/file.cpp | 9 +++++---- 3 files changed, 52 insertions(+), 9 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index e706f2b4..12e9a80d 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1820,12 +1820,18 @@ bool WS2812FX::deserializeMap(uint8_t n) { if (!isFile || !requestJSONBufferLock(7)) return false; - if (!readObjectFromFile(fileName, nullptr, pDoc)) { + StaticJsonDocument<64> filter; + filter[F("width")] = true; + filter[F("height")] = true; + filter[F("name")] = true; + if (!readObjectFromFile(fileName, nullptr, pDoc, &filter)) { DEBUG_PRINT(F("ERROR Invalid ledmap in ")); DEBUG_PRINTLN(fileName); releaseJSONBufferLock(); return false; // if file does not load properly then exit } + suspend(); + JsonObject root = pDoc->as(); // if we are loading default ledmap (at boot) set matrix width and height from the ledmap (compatible with WLED MM ledmaps) if (isMatrix && n == 0 && (!root[F("width")].isNull() || !root[F("height")].isNull())) { @@ -1838,16 +1844,52 @@ bool WS2812FX::deserializeMap(uint8_t n) { if (customMappingTable) { DEBUG_PRINT(F("Reading LED map from ")); DEBUG_PRINTLN(fileName); + File f = WLED_FS.open(fileName, "r"); + f.find("\"map\":["); + while (f.available()) { // f.position() < f.size() - 1 + char number[32]; + size_t numRead = f.readBytesUntil(',', number, sizeof(number)-1); // read a single number (may include array terminating "]" but not number separator ',') + number[numRead] = 0; + if (numRead > 0) { + char *end = strchr(number,']'); // we encountered end of array so stop processing if no digit found + bool foundDigit = (end == nullptr); + int i = 0; + if (end != nullptr) do { + if (number[i] >= '0' && number[i] <= '9') foundDigit = true; + if (foundDigit || &number[i++] == end) break; + } while (i < 32); + if (!foundDigit) break; + int index = atoi(number); + if (index < 0 || index > 16384) index = 0xFFFF; + customMappingTable[customMappingSize++] = index; + if (customMappingSize > getLengthTotal()) break; + } else break; // there was nothing to read, stop + } + currentLedmap = n; + f.close(); + + #ifdef WLED_DEBUG + DEBUG_PRINT(F("Loaded ledmap:")); + for (unsigned i=0; i 0); } diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 1855a8b6..311f71ef 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -109,14 +109,14 @@ void sendArtnetPollReply(ArtPollReply* reply, IPAddress ipAddress, uint16_t port bool handleFileRead(AsyncWebServerRequest*, String path); bool writeObjectToFileUsingId(const char* file, uint16_t id, JsonDocument* content); bool writeObjectToFile(const char* file, const char* key, JsonDocument* content); -bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest); -bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest); +bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest, JsonDocument* filter = nullptr); +bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest, JsonDocument* filter = nullptr); void updateFSInfo(); void closeFile(); inline bool writeObjectToFileUsingId(const String &file, uint16_t id, JsonDocument* content) { return writeObjectToFileUsingId(file.c_str(), id, content); }; inline bool writeObjectToFile(const String &file, const char* key, JsonDocument* content) { return writeObjectToFile(file.c_str(), key, content); }; -inline bool readObjectFromFileUsingId(const String &file, uint16_t id, JsonDocument* dest) { return readObjectFromFileUsingId(file.c_str(), id, dest); }; -inline bool readObjectFromFile(const String &file, const char* key, JsonDocument* dest) { return readObjectFromFile(file.c_str(), key, dest); }; +inline bool readObjectFromFileUsingId(const String &file, uint16_t id, JsonDocument* dest, JsonDocument* filter = nullptr) { return readObjectFromFileUsingId(file.c_str(), id, dest); }; +inline bool readObjectFromFile(const String &file, const char* key, JsonDocument* dest, JsonDocument* filter = nullptr) { return readObjectFromFile(file.c_str(), key, dest); }; //hue.cpp void handleHue(); diff --git a/wled00/file.cpp b/wled00/file.cpp index bc346720..f390bcc0 100644 --- a/wled00/file.cpp +++ b/wled00/file.cpp @@ -325,15 +325,15 @@ bool writeObjectToFile(const char* file, const char* key, JsonDocument* content) return true; } -bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest) +bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest, JsonDocument* filter) { char objKey[10]; sprintf(objKey, "\"%d\":", id); - return readObjectFromFile(file, objKey, dest); + return readObjectFromFile(file, objKey, dest, filter); } //if the key is a nullptr, deserialize entire object -bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest) +bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest, JsonDocument* filter) { if (doCloseFile) closeFile(); #ifdef WLED_DEBUG_FS @@ -352,7 +352,8 @@ bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest) return false; } - deserializeJson(*dest, f); + if (filter) deserializeJson(*dest, f, DeserializationOption::Filter(*filter)); + else deserializeJson(*dest, f); f.close(); DEBUGFS_PRINTF("Read, took %d ms\n", millis() - s); From ba5ec57e4d784f19ff50ec74ce6b1aeb62b68998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sat, 9 Nov 2024 11:33:10 +0100 Subject: [PATCH 061/463] Enumeration support. --- wled00/FX_fcn.cpp | 1 - wled00/util.cpp | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 12e9a80d..e213740a 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1823,7 +1823,6 @@ bool WS2812FX::deserializeMap(uint8_t n) { StaticJsonDocument<64> filter; filter[F("width")] = true; filter[F("height")] = true; - filter[F("name")] = true; if (!readObjectFromFile(fileName, nullptr, pDoc, &filter)) { DEBUG_PRINT(F("ERROR Invalid ledmap in ")); DEBUG_PRINTLN(fileName); releaseJSONBufferLock(); diff --git a/wled00/util.cpp b/wled00/util.cpp index 0b78a464..d58084e8 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -493,6 +493,8 @@ um_data_t* simulateSound(uint8_t simulationId) static const char s_ledmap_tmpl[] PROGMEM = "ledmap%d.json"; // enumerate all ledmapX.json files on FS and extract ledmap names if existing void enumerateLedmaps() { + StaticJsonDocument<64> filter; + filter["n"] = true; ledMaps = 1; for (size_t i=1; ias(); if (!root["n"].isNull()) { From 4b6041302e03b0379629be2329c436113d395363 Mon Sep 17 00:00:00 2001 From: Woody Date: Sat, 9 Nov 2024 21:37:42 +0100 Subject: [PATCH 062/463] fix #4166 --- package-lock.json | 1877 ++++++--------------------------------------- package.json | 2 +- tools/cdata.js | 35 +- 3 files changed, 247 insertions(+), 1667 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0f73bff0..a7beb9c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,14 +11,15 @@ "dependencies": { "clean-css": "^5.3.3", "html-minifier-terser": "^7.2.0", - "inliner": "^1.13.1", - "nodemon": "^3.0.2" + "nodemon": "^3.1.7", + "web-resource-inliner": "^7.0.0" } }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -32,6 +33,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -40,6 +42,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -48,6 +51,7 @@ "version": "0.3.6", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" @@ -56,21 +60,24 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -78,62 +85,20 @@ "node": ">=0.4.0" } }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha512-GrTZLRpmp6wIC2ztrWW9MjjTgSKccffgFagbNDOX95/dcjEcYZibYTeaOntySQLcdw1ztBoFkviiUvTMbb9MYg==", - "dependencies": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" - }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "license": "MIT", "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ansi-escapes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", - "integrity": "sha512-wiXutNjDUlNEDWHcYH3jtZUhd3c4/VojassD8zHdHCY13xbZy2XbW+NKQwA0tWGBVzDA9qEzYwfoSsWmviidhw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -142,70 +107,17 @@ "node": ">= 8" } }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", - "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==" - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dependencies": { - "tweetnacl": "^0.14.3" - } + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", "engines": { "node": ">=8" }, @@ -213,15 +125,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -231,6 +139,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, @@ -241,89 +150,24 @@ "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" }, "node_modules/camel-case": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "license": "MIT", "dependencies": { "pascal-case": "^3.1.2", "tslib": "^2.0.3" } }, - "node_modules/camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha512-wzLkDa4K/mzI1OSITC+DUyjgIl/ETNHE9QvYgy6J6Jvqyyz4C0Xfd+lQhb19sX2jMpZV4IssUn0VDVmglV+s4g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" - }, - "node_modules/center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha512-Baz3aNe2gd2LP2qk5U+sDk/m4oSuwSDcBfayTCTBoWpfIGO5XFxPmjILQII4NGiZjD6DoDI6kf7gKaxkf7s3VQ==", - "dependencies": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/charset": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/charset/-/charset-1.0.1.tgz", - "integrity": "sha512-6dVyOOYjpfFcL1Y4qChrAoQLRHvj2ziyhcm0QJlhOcAhykL/k1kTUPbeo+87MNRTRdk2OIIsIXbuF3x2wi5EXg==", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/cheerio": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.19.0.tgz", - "integrity": "sha512-Fwcm3zkR37STnPC8FepSHeSYJM5Rd596TZOcfDUdojR4Q735aK1Xn+M+ISagNneuCwMjK28w4kX+ETILGNT/UQ==", - "dependencies": { - "css-select": "~1.0.0", - "dom-serializer": "~0.1.0", - "entities": "~1.1.1", - "htmlparser2": "~3.8.1", - "lodash": "^3.2.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cheerio/node_modules/entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" - }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -343,21 +187,11 @@ "fsevents": "~2.3.2" } }, - "node_modules/clap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz", - "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==", - "dependencies": { - "chalk": "^1.1.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/clean-css": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "license": "MIT", "dependencies": { "source-map": "~0.6.0" }, @@ -365,50 +199,11 @@ "node": ">= 10.0" } }, - "node_modules/cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha512-GIOYRizG+TGoc7Wgc1LiOTLare95R3mzKgoln+Q/lE4ceiYH19gUpl0l0Ffq4lJDEf3FxujMe6IBfOCs7pfqNA==", - "dependencies": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" - } - }, - "node_modules/coa": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz", - "integrity": "sha512-KAGck/eNAmCL0dcT3BiuYwLbExK6lduR8DxM3C1TyDzaXhZHyZ8ooX5I5+na2e3dPFuibfxrGdorr0/Lr7RYCQ==", - "dependencies": { - "q": "^1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/colors": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", - "integrity": "sha512-ENwblkFQpqqia6b++zLD/KUWafYlVY/UNnAp7oz7LY7E924wmpye416wBOmvv/HMWzl8gL1kJlfvId/1Dg176w==", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/commander": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "license": "MIT", "engines": { "node": ">=14" } @@ -416,230 +211,135 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "node_modules/configstore": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-1.4.0.tgz", - "integrity": "sha512-Zcx2SVdZC06IuRHd2MhkVYFNJBkZBj166LGdsJXRcqNC8Gs5Bwh8mosStNeCBBmtIm4wNii2uarD50qztjKOjw==", - "dependencies": { - "graceful-fs": "^4.1.2", - "mkdirp": "^0.5.0", - "object-assign": "^4.0.1", - "os-tmpdir": "^1.0.0", - "osenv": "^0.1.0", - "uuid": "^2.0.1", - "write-file-atomic": "^1.1.2", - "xdg-basedir": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/configstore/node_modules/uuid": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", - "integrity": "sha512-FULf7fayPdpASncVy4DLh3xydlXEJJpvIELjYjNeQWYUZ9pclcpvCZSr2gkmN2FrrGcI7G/cJsIEwk5/8vfXpg==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details." - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, - "node_modules/css-select": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.0.0.tgz", - "integrity": "sha512-/xPlD7betkfd7ChGkLGGWx5HWyiHDOSn7aACLzdH0nwucPvB0EAm8hMBm7Xn7vGfAeRRN7KZ8wumGm8NoNcMRw==", - "dependencies": { - "boolbase": "~1.0.0", - "css-what": "1.0", - "domutils": "1.4", - "nth-check": "~1.0.0" - } - }, - "node_modules/css-what": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-1.0.0.tgz", - "integrity": "sha512-60SUMPBreXrLXgvpM8kYpO0AOyMRhdRlXFX5BMQbZq1SIJCyNE56nqFQhmvREQdUJpedbGRYZ5wOyq3/F6q5Zw==", - "engines": { - "node": "*" - } - }, - "node_modules/csso": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-2.0.0.tgz", - "integrity": "sha512-tckZA0LhyEnToPoQDmncCA+TUS3aoIVl/MsSaoipR52Sfa+H83fJvIHRVOHMFn9zW6kIV1L0D7tUDFFjvN28lg==", - "dependencies": { - "clap": "^1.0.9", - "source-map": "^0.5.3" - }, - "bin": { - "csso": "bin/csso" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/csso/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" }, "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "ms": "^2.1.3" + }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/dom-serializer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", - "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "license": "MIT", "dependencies": { - "domelementtype": "^1.3.0", - "entities": "^1.1.1" + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-serializer/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" } }, "node_modules/dom-serializer/node_modules/entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } }, "node_modules/domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" }, "node_modules/domhandler": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", - "integrity": "sha512-q9bUwjfp7Eif8jWxxxPSykdRZAb6GkguBGSgvvCrhI9wB71W2K/Kvv4E61CF/mcCfnVJDeDWx/Vb/uAqbDj6UQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", + "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", + "license": "BSD-2-Clause", "dependencies": { - "domelementtype": "1" + "domelementtype": "^2.0.1" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" } }, "node_modules/domutils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.4.3.tgz", - "integrity": "sha512-ZkVgS/PpxjyJMb+S2iVHHEZjVnOUtjGp0/zstqKGTE9lrZtNHlNQmLwP/lhLMEApYbzc08BKMx9IFpKhaSbW1w==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "license": "BSD-2-Clause", "dependencies": { - "domelementtype": "1" + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/domutils/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" } }, "node_modules/dot-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "license": "MIT", "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" } }, - "node_modules/duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "dependencies": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "node_modules/duplexify/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/duplexify/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/duplexify/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/duplexify/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dependencies": { - "once": "^1.4.0" - } - }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", "engines": { "node": ">=0.12" }, @@ -647,58 +347,23 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/es6-promise": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-2.3.0.tgz", - "integrity": "sha512-oyOjMhyKMLEjOOtvkwg0G4pAzLQ9WdbbeX7WdqKzvYXu+UFgD0Zo/Brq5Q49zNmnGPPzV5rmYvrr0jz1zWx8Iw==" - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "node_modules/escape-goat": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-3.0.0.tgz", + "integrity": "sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==", + "license": "MIT", "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/esprima": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "node": ">=10" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -706,32 +371,12 @@ "node": ">=8" } }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -740,18 +385,11 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dependencies": { - "assert-plus": "^1.0.0" - } - }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -759,75 +397,11 @@ "node": ">= 6" } }, - "node_modules/got": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/got/-/got-3.3.1.tgz", - "integrity": "sha512-7chPlc0pWHjvq7B6dEEXz4GphoDupOvBSSl6AwRsAJX7GPTZ+bturaZiIigX4Dp6KrAP67nvzuKkNc0SLA0DKg==", - "dependencies": { - "duplexify": "^3.2.0", - "infinity-agent": "^2.0.0", - "is-redirect": "^1.0.0", - "is-stream": "^1.0.0", - "lowercase-keys": "^1.0.0", - "nested-error-stacks": "^1.0.0", - "object-assign": "^3.0.0", - "prepend-http": "^1.0.0", - "read-all-stream": "^3.0.0", - "timed-out": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/got/node_modules/object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha512-jHP15vXVGeVh1HuaA2wY6lxk+whK/x4KBG88VXeRma7CCun7iGD5qPc4eYykQ9sdQvg8jkwFKsSxHln2ybW3xQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" - }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", "engines": { "node": ">=4" } @@ -836,6 +410,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", + "license": "MIT", "dependencies": { "camel-case": "^4.1.2", "clean-css": "~5.3.2", @@ -853,117 +428,40 @@ } }, "node_modules/htmlparser2": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", - "integrity": "sha512-hBxEg3CYXe+rPIua8ETe7tmG3XDn9B0edOE/e9wH2nLczxzgdu0m0aNHY+5wFZiviLWLdANPJTssa92dMcXQ5Q==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-5.0.1.tgz", + "integrity": "sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ==", + "license": "MIT", "dependencies": { - "domelementtype": "1", - "domhandler": "2.3", - "domutils": "1.5", - "entities": "1.0", - "readable-stream": "1.1" - } - }, - "node_modules/htmlparser2/node_modules/domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==", - "dependencies": { - "dom-serializer": "0", - "domelementtype": "1" + "domelementtype": "^2.0.1", + "domhandler": "^3.3.0", + "domutils": "^2.4.2", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/fb55/htmlparser2?sponsor=1" } }, "node_modules/htmlparser2/node_modules/entities": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", - "integrity": "sha512-LbLqfXgJMmy81t+7c14mnulFHJ170cM6E+0vMXR9k/ZiZwgX8i5pNgjTCX3SO4VeUsFLV+8InixoretwU+MjBQ==" - }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, "node_modules/ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==" - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/infinity-agent": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/infinity-agent/-/infinity-agent-2.0.3.tgz", - "integrity": "sha512-CnfUJe5o2S9aAQWXGMhDZI4UL39MAJV3guOTfHHIdos4tuVHkl1j/J+1XLQn+CLIvqcpgQR/p+xXYXzcrhCe5w==" - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "node_modules/inliner": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/inliner/-/inliner-1.13.1.tgz", - "integrity": "sha512-yoS+56puOu+Ug8FBRtxtTFnEn2NHqFs8BNQgSOvzh3J0ommbwNw8VKiaVNYjWK6fgPuByq95KyV0LC+qV9IwLw==", - "dependencies": { - "ansi-escapes": "^1.4.0", - "ansi-styles": "^2.2.1", - "chalk": "^1.1.3", - "charset": "^1.0.0", - "cheerio": "^0.19.0", - "debug": "^2.2.0", - "es6-promise": "^2.3.0", - "iconv-lite": "^0.4.11", - "jschardet": "^1.3.0", - "lodash.assign": "^3.2.0", - "lodash.defaults": "^3.1.2", - "lodash.foreach": "^3.0.3", - "mime": "^1.3.4", - "minimist": "^1.1.3", - "request": "^2.74.0", - "svgo": "^0.6.6", - "then-fs": "^2.0.0", - "uglify-js": "^2.8.0", - "update-notifier": "^0.5.0" - }, - "bin": { - "inliner": "cli/index.js" - } + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "license": "ISC" }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -971,34 +469,20 @@ "node": ">=8" } }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/is-finite": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", - "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -1006,310 +490,41 @@ "node": ">=0.10.0" } }, - "node_modules/is-npm": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", - "integrity": "sha512-9r39FIr3d+KD9SbX0sfMsHzb5PP3uimOiwr3YupUaUFG4W0l1U57Rx3utpttV7qz5U3jmrO5auUa04LU9pyHsg==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", "engines": { "node": ">=0.12.0" } }, - "node_modules/is-redirect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha512-cr/SlUEe5zOGmzvj9bUyC4LVvkNVAXu4GytXLNMr1pny+a65MpQ9IJzFHD5vi7FyJgb4qt27+eS3TuQnqB+RQw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" - }, - "node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" - }, - "node_modules/js-yaml": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.6.1.tgz", - "integrity": "sha512-BLv3oxhfET+w5fjPwq3PsAsxzi9i3qzU//HMpWVz0A6KplF86HdR9x2TGnv9DXhSUrO7LO8czUiTd3yb3mLSvg==", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^2.6.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" - }, - "node_modules/jschardet": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.6.0.tgz", - "integrity": "sha512-xYuhvQ7I9PDJIGBWev9xm0+SMSed3ZDBAmvVjbFR1ZRLAF+vlXcQu6cRI9uAlj81rzikElRVteehwV7DuX2ZmQ==", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" - }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/latest-version": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-1.0.1.tgz", - "integrity": "sha512-HERbxp4SBlmI380+eM0B0u4nxjfTaPeydIMzl9+9UQ4nSu3xMWKlX9WoT34e4wy7VWe67c53Nv9qPVjS8fHKgg==", - "dependencies": { - "package-json": "^1.0.0" - }, - "bin": { - "latest-version": "cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lodash": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "integrity": "sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ==" - }, - "node_modules/lodash._arrayeach": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz", - "integrity": "sha512-Mn7HidOVcl3mkQtbPsuKR0Fj0N6Q6DQB77CtYncZcJc0bx5qv2q4Gl6a0LC1AN+GSxpnBDNnK3CKEm9XNA4zqQ==" - }, - "node_modules/lodash._baseassign": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", - "integrity": "sha512-t3N26QR2IdSN+gqSy9Ds9pBu/J1EAFEshKlUHpJG3rvyJOYgcELIxcIeKKfZk7sjOz11cFfzJRsyFry/JyabJQ==", - "dependencies": { - "lodash._basecopy": "^3.0.0", - "lodash.keys": "^3.0.0" - } - }, - "node_modules/lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha512-rFR6Vpm4HeCK1WPGvjZSJ+7yik8d8PVUdCJx5rT2pogG4Ve/2ZS7kfmO5l5T2o5V2mqlNIfSF5MZlr1+xOoYQQ==" - }, - "node_modules/lodash._baseeach": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash._baseeach/-/lodash._baseeach-3.0.4.tgz", - "integrity": "sha512-IqUZ9MQo2UT1XPGuBntInqTOlc+oV+bCo0kMp+yuKGsfvRSNgUW0YjWVZUrG/gs+8z/Eyuc0jkJjOBESt9BXxg==", - "dependencies": { - "lodash.keys": "^3.0.0" - } - }, - "node_modules/lodash._bindcallback": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", - "integrity": "sha512-2wlI0JRAGX8WEf4Gm1p/mv/SZ+jLijpj0jyaE/AXeuQphzCgD8ZQW4oSpoN8JAopujOFGU3KMuq7qfHBWlGpjQ==" - }, - "node_modules/lodash._createassigner": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz", - "integrity": "sha512-LziVL7IDnJjQeeV95Wvhw6G28Z8Q6da87LWKOPWmzBLv4u6FAT/x5v00pyGW0u38UoogNF2JnD3bGgZZDaNEBw==", - "dependencies": { - "lodash._bindcallback": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", - "lodash.restparam": "^3.0.0" - } - }, - "node_modules/lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA==" - }, - "node_modules/lodash._isiterateecall": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha512-De+ZbrMu6eThFti/CSzhRvTKMgQToLxbij58LMfM8JnYDNSOjkjTCIaa8ixglOeGh2nyPlakbt5bJWJ7gvpYlQ==" - }, - "node_modules/lodash.assign": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz", - "integrity": "sha512-/VVxzgGBmbphasTg51FrztxQJ/VgAUpol6zmJuSVSGcNg4g7FA4z7rQV8Ovr9V3vFBNWZhvKWHfpAytjTVUfFA==", - "dependencies": { - "lodash._baseassign": "^3.0.0", - "lodash._createassigner": "^3.0.0", - "lodash.keys": "^3.0.0" - } - }, - "node_modules/lodash.defaults": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-3.1.2.tgz", - "integrity": "sha512-X7135IXFQt5JDFnYxOVAzVz+kFvwDn3N8DJYf+nrz/mMWEuSu7+OL6rWqsk3+VR1T4TejFCSu5isBJOLSID2bg==", - "dependencies": { - "lodash.assign": "^3.0.0", - "lodash.restparam": "^3.0.0" - } - }, - "node_modules/lodash.foreach": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-3.0.3.tgz", - "integrity": "sha512-PA7Lp7pe2HMJBoB1vELegEIF3waUFnM0fWDKJVYolwZ4zHh6WTmnq0xmzfQksD66gx2quhDNyBdyaE2T8/DP3Q==", - "dependencies": { - "lodash._arrayeach": "^3.0.0", - "lodash._baseeach": "^3.0.0", - "lodash._bindcallback": "^3.0.0", - "lodash.isarray": "^3.0.0" - } - }, - "node_modules/lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" - }, - "node_modules/lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ==" - }, - "node_modules/lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha512-CuBsapFjcubOGMn3VD+24HOAPxM79tH+V6ivJL3CHYjtrawauDJHUk//Yew9Hvc6e9rbCrURGk8z6PC+8WJBfQ==", - "dependencies": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" - } - }, - "node_modules/lodash.restparam": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha512-L4/arjjuq4noiUJpt3yS6KIKDtJwNe2fIYgMqyYYKoeIfV1iEqvPwhCx23o+R9dzouGihDAPN1dTIRWa7zk8tw==" - }, - "node_modules/longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha512-k+yt5n3l48JU4k8ftnKG6V7u32wyH2NfKzeMto9F/QRE0amxy/LayxwlvjjkZEIzqR+19IrtFO8p5kB9QaYUFg==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/lower-case": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "license": "MIT", "dependencies": { "tslib": "^2.0.3" } }, - "node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "license": "MIT", "bin": { "mime": "cli.js" }, "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" + "node": ">=4.0.0" } }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -1317,42 +532,17 @@ "node": "*" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/nested-error-stacks": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-1.0.2.tgz", - "integrity": "sha512-o32anp9JA7oezPOFSfG2BBXSdHepOm5FpJvwxHWDtfJ3Bg3xdi68S6ijPlEOfUg6quxZWyvJM+8fHk1yMDKspA==", - "dependencies": { - "inherits": "~2.0.1" - } + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "license": "MIT", "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" @@ -1362,6 +552,7 @@ "version": "3.1.7", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.7.tgz", "integrity": "sha512-hLj7fuMow6f0lbB0cD14Lz2xNjwsyruH251Pk4t/yIitCFJbmY1myuLlHm/q06aST4jg6EgAh74PIBBrRqpVAQ==", + "license": "MIT", "dependencies": { "chokidar": "^3.5.2", "debug": "^4", @@ -1385,112 +576,11 @@ "url": "https://opencollective.com/nodemon" } }, - "node_modules/nodemon/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/nodemon/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/nodemon/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "dependencies": { - "boolbase": "~1.0.0" - } - }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "engines": { - "node": "*" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "deprecated": "This package is no longer supported.", - "dependencies": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "node_modules/package-json": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-1.2.0.tgz", - "integrity": "sha512-knDtirWWqKVJrLY3gEBLflVvueTMpyjbAwX/9j/EKi2DsjNemp5voS8cyKyGh57SNaMJNhNRZbIaWdneOcLU1g==", - "dependencies": { - "got": "^3.2.0", - "registry-url": "^3.0.0" - }, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -1499,6 +589,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "license": "MIT", "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" @@ -1508,20 +599,17 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "license": "MIT", "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" } }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" - }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -1529,155 +617,17 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", - "dependencies": { - "pinkie": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "node_modules/promise": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "dependencies": { - "asap": "~2.0.3" - } - }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" - }, "node_modules/pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, - "node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/read-all-stream": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz", - "integrity": "sha512-DI1drPHbmBcUDWrJ7ull/F2Qb8HkwBncVx8/RpKYFSIACYaVRQReISYPdZz/mt1y1+qMCOrfReTopERmaxtP6w==", - "dependencies": { - "pinkie-promise": "^2.0.0", - "readable-stream": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-all-stream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/read-all-stream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/read-all-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/read-all-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "license": "MIT" }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -1685,122 +635,20 @@ "node": ">=8.10.0" } }, - "node_modules/registry-url": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", - "integrity": "sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA==", - "dependencies": { - "rc": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/relateurl": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "license": "MIT", "engines": { "node": ">= 0.10" } }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/repeating": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz", - "integrity": "sha512-Nh30JLeMHdoI+AsQ5eblhZ7YlTsM9wiJQe/AHIunlK3KWzvXhXb36IJ7K1IOeRjIOtzMjdUHjwXUFxKJoPTSOg==", - "dependencies": { - "is-finite": "^1.0.0" - }, - "bin": { - "repeating": "cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/right-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha512-yqINtL/G7vs2v+dFIZmFUDbnVyFUJFKd6gK22Kgo6R4jfJGFtisKyncWDDULgjfqf4ASQuIQyjJ7XZ+3aWpsAg==", - "dependencies": { - "align-text": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -1808,29 +656,11 @@ "node": ">=10" } }, - "node_modules/semver-diff": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", - "integrity": "sha512-gL8F8L4ORwsS0+iQ34yCYv///jsOq0ZL7WP55d1HnJ32o7tyFYEFQZQA22mrLIacZdU6xecaBBZ+uEiffGNyXw==", - "dependencies": { - "semver": "^5.0.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/semver-diff/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/simple-update-notifier": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "license": "MIT", "dependencies": { "semver": "^7.5.3" }, @@ -1838,18 +668,11 @@ "node": ">=10" } }, - "node_modules/slide": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==", - "engines": { - "node": "*" - } - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -1858,113 +681,29 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" - }, - "node_modules/sshpk": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", - "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stream-shift": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", - "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==" - }, - "node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==" - }, - "node_modules/string-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz", - "integrity": "sha512-MNCACnufWUf3pQ57O5WTBMkKhzYIaKEcUioO0XHrTMafrbBaNk4IyDOLHBv5xbXO0jLLdsYWeFjpjG2hVHRDtw==", - "dependencies": { - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/svgo": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.6.6.tgz", - "integrity": "sha512-C5A1r5SjFesNoKsmc+kWBxmB04iBGH2D/nFy8HJaME9+SyZKcmqcN8QG+GwxIc7D2+JWhaaW7uaM9+XwfplTEQ==", - "deprecated": "This SVGO version is no longer supported. Upgrade to v2.x.x.", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", "dependencies": { - "coa": "~1.0.1", - "colors": "~1.1.2", - "csso": "~2.0.0", - "js-yaml": "~3.6.0", - "mkdirp": "~0.5.1", - "sax": "~1.2.1", - "whet.extend": "~0.9.9" - }, - "bin": { - "svgo": "bin/svgo" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, "node_modules/terser": { - "version": "5.34.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.34.0.tgz", - "integrity": "sha512-y5NUX+U9HhVsK/zihZwoq4r9dICLyV2jXGOriDAVOeKhq3LKVjgJbGO90FisozXLlJfvjHqgckGmJFBb9KYoWQ==", + "version": "5.36.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", + "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", + "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -1981,28 +720,14 @@ "node_modules/terser/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "node_modules/then-fs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/then-fs/-/then-fs-2.0.0.tgz", - "integrity": "sha512-5ffcBcU+vFUCYDNi/o507IqjqrTkuGsLVZ1Fp50hwgZRY7ufVFa9jFfTy5uZ2QnSKacKigWKeaXkOqLa4DsjLw==", - "dependencies": { - "promise": ">=3.2 <8" - } - }, - "node_modules/timed-out": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz", - "integrity": "sha512-pqqJOi1rF5zNs/ps4vmbE4SFCrM4iR7LW+GHAsHqO/EumqbIWceioevYLM5xZRgQSH6gFgL9J/uB7EcJhQ9niQ==", - "engines": { - "node": ">=0.10.0" - } + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -2014,196 +739,46 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "license": "ISC", "bin": { "nodetouch": "bin/nodetouch.js" } }, - "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" - }, - "node_modules/uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha512-qLq/4y2pjcU3vhlhseXGGJ7VbFO4pBANu0kwl8VCa9KEI0V8VfZIx2Fy3w01iSTA/pGwKZSmu/+I4etLNDdt5w==", - "dependencies": { - "source-map": "~0.5.1", - "yargs": "~3.10.0" - }, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - }, - "optionalDependencies": { - "uglify-to-browserify": "~1.0.0" - } - }, - "node_modules/uglify-js/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha512-vb2s1lYx2xBtUgy+ta+b2J/GLVUR+wmpINwHePmPRhOsIVCG2wDzKJ0n14GslH1BifsqVzSOwQhRaCAsZ/nI4Q==", - "optional": true + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "license": "MIT" }, - "node_modules/update-notifier": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-0.5.0.tgz", - "integrity": "sha512-zOGOlUKDAgDlLHLv7Oiszz3pSj8fKlSJ3i0u49sEakjXUEVJ6DMjo/Mh/B6mg2eOALvRTJkd0kbChcipQoYCng==", + "node_modules/valid-data-url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-3.0.1.tgz", + "integrity": "sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/web-resource-inliner": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-7.0.0.tgz", + "integrity": "sha512-NlfnGF8MY9ZUwFjyq3vOUBx7KwF8bmE+ywR781SB0nWB6MoMxN4BA8gtgP1KGTZo/O/AyWJz7HZpR704eaj4mg==", + "license": "MIT", "dependencies": { - "chalk": "^1.0.0", - "configstore": "^1.0.0", - "is-npm": "^1.0.0", - "latest-version": "^1.0.0", - "repeating": "^1.1.2", - "semver-diff": "^2.0.0", - "string-length": "^1.0.0" + "ansi-colors": "^4.1.1", + "escape-goat": "^3.0.0", + "htmlparser2": "^5.0.0", + "mime": "^2.4.6", + "valid-data-url": "^3.0.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/verror/node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" - }, - "node_modules/whet.extend": { - "version": "0.9.9", - "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz", - "integrity": "sha512-mmIPAft2vTgEILgPeZFqE/wWh24SEsR/k+N9fJ3Jxrz44iDFy9aemCxdksfURSHYFCLmvs/d/7Iso5XjPpNfrA==", - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha512-1pTPQDKTdd61ozlKGNCjhNRd+KPmgLSGa3mZTHoOliaGcESD8G1PXhh7c1fgiPjVbNVfgy2Faw4BI8/m0cC8Mg==", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha512-xSBsCeh+g+dinoBv3GAOWM4LcVVO68wLXRanibtBSdUvkGWQRGeE9P7IwU9EmDDi4jA6L44lz15CGMwdw9N5+Q==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/write-file-atomic": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", - "integrity": "sha512-SdrHoC/yVBPpV0Xq/mUZQIpW2sWXAShb/V4pomcJXh92RuaO+f3UTWItiR3Px+pLnV2PvC2/bfn5cwr5X6Vfxw==", - "dependencies": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "slide": "^1.1.5" - } - }, - "node_modules/xdg-basedir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-2.0.0.tgz", - "integrity": "sha512-NF1pPn594TaRSUO/HARoB4jK8I+rWgcpVlpQCK6/6o5PHyLUt2CSiDrpUZbQ6rROck+W2EwF8mBJcTs+W98J9w==", - "dependencies": { - "os-homedir": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha512-QFzUah88GAGy9lyDKGBqZdkYApt63rCXYBGYnEP4xDJPXNqXXnBDACnbrXnViV6jRSqAePwrATi2i8mfYm4L1A==", - "dependencies": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" + "node": ">=10.0.0" } } } diff --git a/package.json b/package.json index 9d095c82..eb05066e 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "dependencies": { "clean-css": "^5.3.3", "html-minifier-terser": "^7.2.0", - "inliner": "^1.13.1", + "web-resource-inliner": "^7.0.0", "nodemon": "^3.1.7" } } diff --git a/tools/cdata.js b/tools/cdata.js index d65573a8..014609f0 100644 --- a/tools/cdata.js +++ b/tools/cdata.js @@ -17,7 +17,7 @@ const fs = require("node:fs"); const path = require("path"); -const inliner = require("inliner"); +const inline = require("web-resource-inliner"); const zlib = require("node:zlib"); const CleanCSS = require("clean-css"); const minifyHtml = require("html-minifier-terser").minify; @@ -127,21 +127,26 @@ async function minify(str, type = "plain") { async function writeHtmlGzipped(sourceFile, resultFile, page) { console.info("Reading " + sourceFile); - new inliner(sourceFile, async function (error, html) { - if (error) throw error; + inline.html({ + fileContent: fs.readFileSync(sourceFile, "utf8"), + relativeTo: path.dirname(sourceFile), + strict: true, + }, + async function (error, html) { + if (error) throw error; - html = adoptVersionAndRepo(html); - const originalLength = html.length; - html = await minify(html, "html-minify"); - const result = zlib.gzipSync(html, { level: zlib.constants.Z_BEST_COMPRESSION }); - console.info("Minified and compressed " + sourceFile + " from " + originalLength + " to " + result.length + " bytes"); - const array = hexdump(result); - let src = singleHeader; - src += `const uint16_t PAGE_${page}_L = ${result.length};\n`; - src += `const uint8_t PAGE_${page}[] PROGMEM = {\n${array}\n};\n\n`; - console.info("Writing " + resultFile); - fs.writeFileSync(resultFile, src); - }); + html = adoptVersionAndRepo(html); + const originalLength = html.length; + html = await minify(html, "html-minify"); + const result = zlib.gzipSync(html, { level: zlib.constants.Z_BEST_COMPRESSION }); + console.info("Minified and compressed " + sourceFile + " from " + originalLength + " to " + result.length + " bytes"); + const array = hexdump(result); + let src = singleHeader; + src += `const uint16_t PAGE_${page}_L = ${result.length};\n`; + src += `const uint8_t PAGE_${page}[] PROGMEM = {\n${array}\n};\n\n`; + console.info("Writing " + resultFile); + fs.writeFileSync(resultFile, src); + }); } async function specToChunk(srcDir, s) { From d37ee89e845ef83b75b1ad42345f73ad82c71629 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sat, 9 Nov 2024 19:53:47 -0500 Subject: [PATCH 063/463] ESP8266PWM: Fix phase shift glitches In some cases it was possible for the computed phase shift to skip a cycle. Update the shift calculation logic to prevent this. --- .../src/core_esp8266_waveform_phase.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/ESP8266PWM/src/core_esp8266_waveform_phase.cpp b/lib/ESP8266PWM/src/core_esp8266_waveform_phase.cpp index b89ec8bc..68cb9010 100644 --- a/lib/ESP8266PWM/src/core_esp8266_waveform_phase.cpp +++ b/lib/ESP8266PWM/src/core_esp8266_waveform_phase.cpp @@ -324,7 +324,7 @@ static IRAM_ATTR void timer1Interrupt() { case WaveformMode::INIT: waveform.states &= ~waveform.toSetBits; // Clear the state of any just started if (waveform.alignPhase >= 0 && waveform.enabled & (1UL << waveform.alignPhase)) { - wave.nextPeriodCcy = waveform.pins[waveform.alignPhase].nextPeriodCcy + wave.nextPeriodCcy; + wave.nextPeriodCcy = waveform.pins[waveform.alignPhase].nextPeriodCcy + scaleCcys(waveform.phaseCcy, isCPU2X); } else { wave.nextPeriodCcy = waveform.nextEventCcy; @@ -342,15 +342,15 @@ static IRAM_ATTR void timer1Interrupt() { // @willmmiles new feature case WaveformMode::UPDATEPHASE: // in WaveformMode::UPDATEPHASE, we recalculate the targets - if (waveform.alignPhase >= 0 && waveform.enabled & (1UL << waveform.alignPhase)) { + if ((waveform.alignPhase >= 0) && (waveform.enabled & (1UL << waveform.alignPhase))) { // Compute phase shift to realign with target - auto& align_wave = waveform.pins[waveform.alignPhase]; - int32_t shift = static_cast(align_wave.nextPeriodCcy + scaleCcys(waveform.phaseCcy, isCPU2X) - wave.nextPeriodCcy); - const int32_t periodCcys = scaleCcys(wave.periodCcys, isCPU2X); - if (shift > periodCcys/2) shift -= periodCcys; - else if (shift <= -periodCcys/2) shift += periodCcys; - wave.nextPeriodCcy += shift; - wave.endDutyCcy += shift; + auto const newPeriodCcy = waveform.pins[waveform.alignPhase].nextPeriodCcy + scaleCcys(waveform.phaseCcy, isCPU2X); + auto const period = scaleCcys(wave.periodCcys, isCPU2X); + auto shift = ((static_cast (newPeriodCcy - wave.nextPeriodCcy) + period/2) % period) - (period/2); + wave.nextPeriodCcy += static_cast(shift); + if (static_cast(wave.endDutyCcy - wave.nextPeriodCcy) > 0) { + wave.endDutyCcy = wave.nextPeriodCcy; + } } default: break; From 0160e3fa87d08cee401bebfe82c0c42e2bd6935d Mon Sep 17 00:00:00 2001 From: Wouter Gritter Date: Wed, 20 Nov 2024 12:39:39 +0100 Subject: [PATCH 064/463] Use MQTT_MAX_TOPIC_LEN in places where it was not used before to avoid buffer overflows when value is increased --- wled00/button.cpp | 8 ++++---- wled00/mqtt.cpp | 22 +++++++++++----------- wled00/wled.h | 8 ++++---- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/wled00/button.cpp b/wled00/button.cpp index 4d6f954f..6f9c8456 100644 --- a/wled00/button.cpp +++ b/wled00/button.cpp @@ -29,7 +29,7 @@ void shortPressAction(uint8_t b) #ifndef WLED_DISABLE_MQTT // publish MQTT message if (buttonPublishMqtt && WLED_MQTT_CONNECTED) { - char subuf[64]; + char subuf[MQTT_MAX_TOPIC_LEN + 32]; sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b); mqtt->publish(subuf, 0, false, "short"); } @@ -62,7 +62,7 @@ void longPressAction(uint8_t b) #ifndef WLED_DISABLE_MQTT // publish MQTT message if (buttonPublishMqtt && WLED_MQTT_CONNECTED) { - char subuf[64]; + char subuf[MQTT_MAX_TOPIC_LEN + 32]; sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b); mqtt->publish(subuf, 0, false, "long"); } @@ -83,7 +83,7 @@ void doublePressAction(uint8_t b) #ifndef WLED_DISABLE_MQTT // publish MQTT message if (buttonPublishMqtt && WLED_MQTT_CONNECTED) { - char subuf[64]; + char subuf[MQTT_MAX_TOPIC_LEN + 32]; sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b); mqtt->publish(subuf, 0, false, "double"); } @@ -151,7 +151,7 @@ void handleSwitch(uint8_t b) #ifndef WLED_DISABLE_MQTT // publish MQTT message if (buttonPublishMqtt && WLED_MQTT_CONNECTED) { - char subuf[64]; + char subuf[MQTT_MAX_TOPIC_LEN + 32]; if (buttonType[b] == BTN_TYPE_PIR_SENSOR) sprintf_P(subuf, PSTR("%s/motion/%d"), mqttDeviceTopic, (int)b); else sprintf_P(subuf, _mqtt_topic_button, mqttDeviceTopic, (int)b); mqtt->publish(subuf, 0, false, !buttonPressedBefore[b] ? "off" : "on"); diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp index a476db87..d909494e 100644 --- a/wled00/mqtt.cpp +++ b/wled00/mqtt.cpp @@ -23,24 +23,24 @@ static void parseMQTTBriPayload(char* payload) static void onMqttConnect(bool sessionPresent) { //(re)subscribe to required topics - char subuf[38]; + char subuf[MQTT_MAX_TOPIC_LEN + 6]; if (mqttDeviceTopic[0] != 0) { - strlcpy(subuf, mqttDeviceTopic, 33); + strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); mqtt->subscribe(subuf, 0); strcat_P(subuf, PSTR("/col")); mqtt->subscribe(subuf, 0); - strlcpy(subuf, mqttDeviceTopic, 33); + strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); strcat_P(subuf, PSTR("/api")); mqtt->subscribe(subuf, 0); } if (mqttGroupTopic[0] != 0) { - strlcpy(subuf, mqttGroupTopic, 33); + strlcpy(subuf, mqttGroupTopic, MQTT_MAX_TOPIC_LEN + 1); mqtt->subscribe(subuf, 0); strcat_P(subuf, PSTR("/col")); mqtt->subscribe(subuf, 0); - strlcpy(subuf, mqttGroupTopic, 33); + strlcpy(subuf, mqttGroupTopic, MQTT_MAX_TOPIC_LEN + 1); strcat_P(subuf, PSTR("/api")); mqtt->subscribe(subuf, 0); } @@ -158,19 +158,19 @@ void publishMqtt() #ifndef USERMOD_SMARTNEST char s[10]; - char subuf[48]; + char subuf[MQTT_MAX_TOPIC_LEN + 16]; sprintf_P(s, PSTR("%u"), bri); - strlcpy(subuf, mqttDeviceTopic, 33); + strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); strcat_P(subuf, PSTR("/g")); mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263) sprintf_P(s, PSTR("#%06X"), (col[3] << 24) | (col[0] << 16) | (col[1] << 8) | (col[2])); - strlcpy(subuf, mqttDeviceTopic, 33); + strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); strcat_P(subuf, PSTR("/c")); mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263) - strlcpy(subuf, mqttDeviceTopic, 33); + strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); strcat_P(subuf, PSTR("/status")); mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT @@ -178,7 +178,7 @@ void publishMqtt() DynamicBuffer buf(1024); bufferPrint pbuf(buf.data(), buf.size()); XML_response(pbuf); - strlcpy(subuf, mqttDeviceTopic, 33); + strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); strcat_P(subuf, PSTR("/v")); mqtt->publish(subuf, 0, retainMqttMsg, buf.data(), pbuf.size()); // optionally retain message (#2263) #endif @@ -211,7 +211,7 @@ bool initMqtt() if (mqttUser[0] && mqttPass[0]) mqtt->setCredentials(mqttUser, mqttPass); #ifndef USERMOD_SMARTNEST - strlcpy(mqttStatusTopic, mqttDeviceTopic, 33); + strlcpy(mqttStatusTopic, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); strcat_P(mqttStatusTopic, PSTR("/status")); mqtt->setWill(mqttStatusTopic, 0, true, "offline"); // LWT message #endif diff --git a/wled00/wled.h b/wled00/wled.h index 2b3a77d2..29b43753 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -483,10 +483,10 @@ WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0); // used for other #endif WLED_GLOBAL AsyncMqttClient *mqtt _INIT(NULL); WLED_GLOBAL bool mqttEnabled _INIT(false); -WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers -WLED_GLOBAL char mqttDeviceTopic[MQTT_MAX_TOPIC_LEN+1] _INIT(""); // main MQTT topic (individual per device, default is wled/mac) -WLED_GLOBAL char mqttGroupTopic[MQTT_MAX_TOPIC_LEN+1] _INIT("wled/all"); // second MQTT topic (for example to group devices) -WLED_GLOBAL char mqttServer[MQTT_MAX_SERVER_LEN+1] _INIT(""); // both domains and IPs should work (no SSL) +WLED_GLOBAL char mqttStatusTopic[MQTT_MAX_TOPIC_LEN + 8] _INIT(""); // this must be global because of async handlers +WLED_GLOBAL char mqttDeviceTopic[MQTT_MAX_TOPIC_LEN + 1] _INIT(""); // main MQTT topic (individual per device, default is wled/mac) +WLED_GLOBAL char mqttGroupTopic[MQTT_MAX_TOPIC_LEN + 1] _INIT("wled/all"); // second MQTT topic (for example to group devices) +WLED_GLOBAL char mqttServer[MQTT_MAX_SERVER_LEN + 1] _INIT(""); // both domains and IPs should work (no SSL) WLED_GLOBAL char mqttUser[41] _INIT(""); // optional: username for MQTT auth WLED_GLOBAL char mqttPass[65] _INIT(""); // optional: password for MQTT auth WLED_GLOBAL char mqttClientID[41] _INIT(""); // override the client ID From cec89788865bf29aae0799f03ba0c8c43638d297 Mon Sep 17 00:00:00 2001 From: Wouter Gritter Date: Wed, 20 Nov 2024 12:45:39 +0100 Subject: [PATCH 065/463] Fix comment alignment --- wled00/wled.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/wled.h b/wled00/wled.h index 29b43753..3630170f 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -483,7 +483,7 @@ WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0); // used for other #endif WLED_GLOBAL AsyncMqttClient *mqtt _INIT(NULL); WLED_GLOBAL bool mqttEnabled _INIT(false); -WLED_GLOBAL char mqttStatusTopic[MQTT_MAX_TOPIC_LEN + 8] _INIT(""); // this must be global because of async handlers +WLED_GLOBAL char mqttStatusTopic[MQTT_MAX_TOPIC_LEN + 8] _INIT(""); // this must be global because of async handlers WLED_GLOBAL char mqttDeviceTopic[MQTT_MAX_TOPIC_LEN + 1] _INIT(""); // main MQTT topic (individual per device, default is wled/mac) WLED_GLOBAL char mqttGroupTopic[MQTT_MAX_TOPIC_LEN + 1] _INIT("wled/all"); // second MQTT topic (for example to group devices) WLED_GLOBAL char mqttServer[MQTT_MAX_SERVER_LEN + 1] _INIT(""); // both domains and IPs should work (no SSL) From 0db47a8586526541b0cdd810b466923c64b80cd6 Mon Sep 17 00:00:00 2001 From: Wouter Gritter Date: Thu, 21 Nov 2024 09:51:13 +0100 Subject: [PATCH 066/463] Add comment warning about modification of MQTT_MAX_TOPIC_LEN --- wled00/wled.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/wled.h b/wled00/wled.h index 3630170f..5dbc013d 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -476,7 +476,7 @@ WLED_GLOBAL uint16_t pollReplyCount _INIT(0); // count numbe WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0); // used for other periodic tasks too #ifndef WLED_DISABLE_MQTT #ifndef MQTT_MAX_TOPIC_LEN - #define MQTT_MAX_TOPIC_LEN 32 + #define MQTT_MAX_TOPIC_LEN 32 // should not be less than 32. might cause trouble when increased with usermods active that do not handle this correctly. #endif #ifndef MQTT_MAX_SERVER_LEN #define MQTT_MAX_SERVER_LEN 32 From 8f8afd98a5dc5982271babbcce84ffff28c32fab Mon Sep 17 00:00:00 2001 From: Wouter Gritter Date: Thu, 21 Nov 2024 11:20:42 +0100 Subject: [PATCH 067/463] Replace comment with compile-time error and warning --- wled00/mqtt.cpp | 4 ++++ wled00/wled.h | 2 +- wled00/wled_eeprom.cpp | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) mode change 100755 => 100644 wled00/wled_eeprom.cpp diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp index d909494e..38afeffe 100644 --- a/wled00/mqtt.cpp +++ b/wled00/mqtt.cpp @@ -7,6 +7,10 @@ #ifndef WLED_DISABLE_MQTT #define MQTT_KEEP_ALIVE_TIME 60 // contact the MQTT broker every 60 seconds +#if MQTT_MAX_TOPIC_LEN > 32 +#warning "MQTT topics length > 32 is not recommended for compatibility with usermods!" +#endif + static void parseMQTTBriPayload(char* payload) { if (strstr(payload, "ON") || strstr(payload, "on") || strstr(payload, "true")) {bri = briLast; stateUpdated(CALL_MODE_DIRECT_CHANGE);} diff --git a/wled00/wled.h b/wled00/wled.h index 5dbc013d..3630170f 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -476,7 +476,7 @@ WLED_GLOBAL uint16_t pollReplyCount _INIT(0); // count numbe WLED_GLOBAL unsigned long lastMqttReconnectAttempt _INIT(0); // used for other periodic tasks too #ifndef WLED_DISABLE_MQTT #ifndef MQTT_MAX_TOPIC_LEN - #define MQTT_MAX_TOPIC_LEN 32 // should not be less than 32. might cause trouble when increased with usermods active that do not handle this correctly. + #define MQTT_MAX_TOPIC_LEN 32 #endif #ifndef MQTT_MAX_SERVER_LEN #define MQTT_MAX_SERVER_LEN 32 diff --git a/wled00/wled_eeprom.cpp b/wled00/wled_eeprom.cpp old mode 100755 new mode 100644 index 4f2c14d4..8582b49d --- a/wled00/wled_eeprom.cpp +++ b/wled00/wled_eeprom.cpp @@ -2,6 +2,10 @@ #include #include "wled.h" +#if defined(WLED_ENABLE_MQTT) && MQTT_MAX_TOPIC_LEN < 32 +#error "MQTT topics length < 32 is not supported by the EEPROM module!" +#endif + /* * DEPRECATED, do not use for new settings * Only used to restore config from pre-0.11 installations using the deEEP() methods From 4f1965fbaa6690d2de477d4d2de2512f77d10e2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sat, 23 Nov 2024 11:24:03 +0100 Subject: [PATCH 068/463] Add ability to configure settings PIN at compile time --- wled00/wled.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/wled00/wled.h b/wled00/wled.h index 2b3a77d2..45d9dd5d 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -214,6 +214,10 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument; #define WLED_AP_PASS DEFAULT_AP_PASS #endif +#ifndef WLED_PIN + #define WLED_PIN "" +#endif + #ifndef SPIFFS_EDITOR_AIRCOOOKIE #error You are not using the Aircoookie fork of the ESPAsyncWebserver library.\ Using upstream puts your WiFi password at risk of being served by the filesystem.\ @@ -556,10 +560,10 @@ WLED_GLOBAL byte macroLongPress[WLED_MAX_BUTTONS] _INIT({0}); WLED_GLOBAL byte macroDoublePress[WLED_MAX_BUTTONS] _INIT({0}); // Security CONFIG -WLED_GLOBAL bool otaLock _INIT(false); // prevents OTA firmware updates without password. ALWAYS enable if system exposed to any public networks -WLED_GLOBAL bool wifiLock _INIT(false); // prevents access to WiFi settings when OTA lock is enabled -WLED_GLOBAL bool aOtaEnabled _INIT(true); // ArduinoOTA allows easy updates directly from the IDE. Careful, it does not auto-disable when OTA lock is on -WLED_GLOBAL char settingsPIN[5] _INIT(""); // PIN for settings pages +WLED_GLOBAL bool otaLock _INIT(false); // prevents OTA firmware updates without password. ALWAYS enable if system exposed to any public networks +WLED_GLOBAL bool wifiLock _INIT(false); // prevents access to WiFi settings when OTA lock is enabled +WLED_GLOBAL bool aOtaEnabled _INIT(true); // ArduinoOTA allows easy updates directly from the IDE. Careful, it does not auto-disable when OTA lock is on +WLED_GLOBAL char settingsPIN[5] _INIT(WLED_PIN); // PIN for settings pages WLED_GLOBAL bool correctPIN _INIT(true); WLED_GLOBAL unsigned long lastEditTime _INIT(0); From 855e6061631df03ee297eba900d60230bbbc6e9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sun, 24 Nov 2024 17:17:17 +0100 Subject: [PATCH 069/463] Fix 1st use --- wled00/wled.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/wled.h b/wled00/wled.h index 45d9dd5d..62c3a3f0 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -564,7 +564,7 @@ WLED_GLOBAL bool otaLock _INIT(false); // prevents OTA firmware updat WLED_GLOBAL bool wifiLock _INIT(false); // prevents access to WiFi settings when OTA lock is enabled WLED_GLOBAL bool aOtaEnabled _INIT(true); // ArduinoOTA allows easy updates directly from the IDE. Careful, it does not auto-disable when OTA lock is on WLED_GLOBAL char settingsPIN[5] _INIT(WLED_PIN); // PIN for settings pages -WLED_GLOBAL bool correctPIN _INIT(true); +WLED_GLOBAL bool correctPIN _INIT(!strlen(settingsPIN)); WLED_GLOBAL unsigned long lastEditTime _INIT(0); WLED_GLOBAL uint16_t userVar0 _INIT(0), userVar1 _INIT(0); //available for use in usermod From 2c583c3071926a15411efa1349e1a3916e6572fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Mon, 25 Nov 2024 22:56:22 +0100 Subject: [PATCH 070/463] Allow editing WiFi settings --- wled00/wled_server.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index e8cbb41a..6dac16ab 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -567,13 +567,14 @@ void serveSettings(AsyncWebServerRequest* request, bool post) { //else if (url.indexOf("/edit") >= 0) subPage = 10; else subPage = SUBPAGE_WELCOME; - if (!correctPIN && strlen(settingsPIN) > 0 && (subPage > 0 && subPage < 11)) { + bool pinRequired = !correctPIN && strlen(settingsPIN) > 0 && (subPage > (WLED_WIFI_CONFIGURED ? SUBPAGE_MENU : SUBPAGE_WIFI) && subPage < SUBPAGE_LOCK); + if (pinRequired) { originalSubPage = subPage; subPage = SUBPAGE_PINREQ; // require PIN } // if OTA locked or too frequent PIN entry requests fail hard - if ((subPage == SUBPAGE_WIFI && wifiLock && otaLock) || (post && !correctPIN && millis()-lastEditTime < PIN_RETRY_COOLDOWN)) + if ((subPage == SUBPAGE_WIFI && wifiLock && otaLock) || (post && pinRequired && millis()-lastEditTime < PIN_RETRY_COOLDOWN)) { serveMessage(request, 401, FPSTR(s_accessdenied), FPSTR(s_unlock_ota), 254); return; } @@ -609,7 +610,7 @@ void serveSettings(AsyncWebServerRequest* request, bool post) { if (!s2[0]) strcpy_P(s2, s_redirecting); bool redirectAfter9s = (subPage == SUBPAGE_WIFI || ((subPage == SUBPAGE_SEC || subPage == SUBPAGE_UM) && doReboot)); - serveMessage(request, (correctPIN ? 200 : 401), s, s2, redirectAfter9s ? 129 : (correctPIN ? 1 : 3)); + serveMessage(request, (!pinRequired ? 200 : 401), s, s2, redirectAfter9s ? 129 : (!pinRequired ? 1 : 3)); return; } } From 7236589037a9c987cf75874398507cdcb2f2050e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Mon, 25 Nov 2024 22:57:21 +0100 Subject: [PATCH 071/463] Allow pre-compiled OTA password --- wled00/wled.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/wled00/wled.h b/wled00/wled.h index 62c3a3f0..74719a6f 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -278,7 +278,11 @@ WLED_GLOBAL char releaseString[] _INIT(TOSTRING(WLED_RELEASE_NAME)); // somehow // AP and OTA default passwords (for maximum security change them!) WLED_GLOBAL char apPass[65] _INIT(WLED_AP_PASS); +#ifdef WLED_OTA_PASS +WLED_GLOBAL char otaPass[33] _INIT(WLED_OTA_PASS); +#else WLED_GLOBAL char otaPass[33] _INIT(DEFAULT_OTA_PASS); +#endif // Hardware and pin config #ifndef BTNPIN @@ -560,7 +564,11 @@ WLED_GLOBAL byte macroLongPress[WLED_MAX_BUTTONS] _INIT({0}); WLED_GLOBAL byte macroDoublePress[WLED_MAX_BUTTONS] _INIT({0}); // Security CONFIG +#ifdef WLED_OTA_PASS +WLED_GLOBAL bool otaLock _INIT(true); // prevents OTA firmware updates without password. ALWAYS enable if system exposed to any public networks +#else WLED_GLOBAL bool otaLock _INIT(false); // prevents OTA firmware updates without password. ALWAYS enable if system exposed to any public networks +#endif WLED_GLOBAL bool wifiLock _INIT(false); // prevents access to WiFi settings when OTA lock is enabled WLED_GLOBAL bool aOtaEnabled _INIT(true); // ArduinoOTA allows easy updates directly from the IDE. Careful, it does not auto-disable when OTA lock is on WLED_GLOBAL char settingsPIN[5] _INIT(WLED_PIN); // PIN for settings pages From 0a05611e1d5a8dcccf515ba616042692197258f6 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Tue, 26 Nov 2024 20:59:36 +0100 Subject: [PATCH 072/463] more improvements to setPixelColor - code is a bit cleaner and faster as well - chaning array access to pointer access in bus_manager makes it a few instructions faster - changed getNumberOfPins and getNumberOfChannels to return 32bit values, saving the unnecessary 8bit conversion --- wled00/FX_2Dfcn.cpp | 41 +++++++++++++++++++++-------------------- wled00/bus_manager.cpp | 26 ++++++++++++++++---------- wled00/bus_manager.h | 6 +++--- 3 files changed, 40 insertions(+), 33 deletions(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index adb9f8bc..ba0c6932 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -156,21 +156,26 @@ uint16_t IRAM_ATTR_YN Segment::XY(int x, int y) // raw setColor function without checks (checks are done in setPixelColorXY()) void IRAM_ATTR_YN Segment::_setPixelColorXY_raw(int& x, int& y, uint32_t& col) { + const int baseX = start + x; + const int baseY = startY + y; #ifndef WLED_DISABLE_MODE_BLEND // if blending modes, blend with underlying pixel - if (_modeBlend) col = color_blend(strip.getPixelColorXY(start + x, startY + y), col, 0xFFFFU - progress(), true); + if (_modeBlend) col = color_blend(strip.getPixelColorXY(baseX, baseY), col, 0xFFFFU - progress(), true); #endif - strip.setPixelColorXY(start + x, startY + y, col); - if (mirror) { //set the corresponding horizontally mirrored pixel - if (transpose) strip.setPixelColorXY(start + x, startY + height() - y - 1, col); - else strip.setPixelColorXY(start + width() - x - 1, startY + y, col); - } - if (mirror_y) { //set the corresponding vertically mirrored pixel - if (transpose) strip.setPixelColorXY(start + width() - x - 1, startY + y, col); - else strip.setPixelColorXY(start + x, startY + height() - y - 1, col); - } - if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel - strip.setPixelColorXY(start + width() - x - 1, startY + height() - y - 1, col); + strip.setPixelColorXY(baseX, baseY, col); + + // Apply mirroring + if (mirror || mirror_y) { + auto setMirroredPixel = [&](int mx, int my) { + strip.setPixelColorXY(mx, my, col); + }; + + const int mirrorX = start + width() - x - 1; + const int mirrorY = startY + height() - y - 1; + + if (mirror) setMirroredPixel(transpose ? baseX : mirrorX, transpose ? mirrorY : baseY); + if (mirror_y) setMirroredPixel(transpose ? mirrorX : baseX, transpose ? baseY : mirrorY); + if (mirror && mirror_y) setMirroredPixel(mirrorX, mirrorY); } } @@ -196,16 +201,12 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) int H = height(); x *= groupLen; // expand to physical pixels y *= groupLen; // expand to physical pixels - int yY = y; - for (int j = 0; j < grouping; j++) { // groupping vertically - if (yY >= H) break; - int xX = x; - for (int g = 0; g < grouping; g++) { // groupping horizontally - if (xX >= W) break; // we have reached X dimension's end + const int maxY = std::min(y + grouping, H); + const int maxX = std::min(x + grouping, W); + for (int yY = y; yY < maxY; yY++) { + for (int xX = x; xX < maxX; xX++) { _setPixelColorXY_raw(xX, yY, col); - xX++; } - yY++; } } else { _setPixelColorXY_raw(x, y, col); diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 404c3344..94113549 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -308,20 +308,20 @@ void BusDigital::setStatusPixel(uint32_t c) { void IRAM_ATTR BusDigital::setPixelColor(unsigned pix, uint32_t c) { if (!_valid) return; - uint8_t cctWW = 0, cctCW = 0; if (hasWhite()) c = autoWhiteCalc(c); if (Bus::_cct >= 1900) c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT if (_data) { size_t offset = pix * getNumberOfChannels(); + uint8_t* dataptr = _data + offset; if (hasRGB()) { - _data[offset++] = R(c); - _data[offset++] = G(c); - _data[offset++] = B(c); + *dataptr++ = R(c); + *dataptr++ = G(c); + *dataptr++ = B(c); } - if (hasWhite()) _data[offset++] = W(c); + if (hasWhite()) *dataptr++ = W(c); // unfortunately as a segment may span multiple buses or a bus may contain multiple segments and each segment may have different CCT // we need to store CCT value for each pixel (if there is a color correction in play, convert K in CCT ratio) - if (hasCCT()) _data[offset] = Bus::_cct >= 1900 ? (Bus::_cct - 1900) >> 5 : (Bus::_cct < 0 ? 127 : Bus::_cct); // TODO: if _cct == -1 we simply ignore it + if (hasCCT()) *dataptr = Bus::_cct >= 1900 ? (Bus::_cct - 1900) >> 5 : (Bus::_cct < 0 ? 127 : Bus::_cct); // TODO: if _cct == -1 we simply ignore it } else { if (_reversed) pix = _len - pix -1; pix += _skip; @@ -336,8 +336,14 @@ void IRAM_ATTR BusDigital::setPixelColor(unsigned pix, uint32_t c) { case 2: c = RGBW32(R(cOld), G(cOld), W(c) , 0); break; } } - if (hasCCT()) Bus::calculateCCT(c, cctWW, cctCW); - PolyBus::setPixelColor(_busPtr, _iType, pix, c, co, (cctCW<<8) | cctWW); + uint16_t wwcw = 0; + if (hasCCT()) { + uint8_t cctWW = 0, cctCW = 0; + Bus::calculateCCT(c, cctWW, cctCW); + wwcw = (cctCW<<8) | cctWW; + } + + PolyBus::setPixelColor(_busPtr, _iType, pix, c, co, wwcw); } } @@ -345,7 +351,7 @@ void IRAM_ATTR BusDigital::setPixelColor(unsigned pix, uint32_t c) { uint32_t IRAM_ATTR BusDigital::getPixelColor(unsigned pix) const { if (!_valid) return 0; if (_data) { - size_t offset = pix * getNumberOfChannels(); + const size_t offset = pix * getNumberOfChannels(); uint32_t c; if (!hasRGB()) { c = RGBW32(_data[offset], _data[offset], _data[offset], _data[offset]); @@ -356,7 +362,7 @@ uint32_t IRAM_ATTR BusDigital::getPixelColor(unsigned pix) const { } else { if (_reversed) pix = _len - pix -1; pix += _skip; - unsigned co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder); + const unsigned co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder); uint32_t c = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, (_type==TYPE_WS2812_1CH_X3) ? IC_INDEX_WS2812_1CH_3X(pix) : pix, co),_bri); if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs unsigned r = R(c); diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index e25a0684..49077f27 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -110,7 +110,7 @@ class Bus { inline void setStart(uint16_t start) { _start = start; } inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; } inline uint8_t getAutoWhiteMode() const { return _autoWhiteMode; } - inline uint8_t getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); } + inline uint32_t getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); } inline uint16_t getStart() const { return _start; } inline uint8_t getType() const { return _type; } inline bool isOk() const { return _valid; } @@ -119,8 +119,8 @@ class Bus { inline bool containsPixel(uint16_t pix) const { return pix >= _start && pix < _start + _len; } static inline std::vector getLEDTypes() { return {{TYPE_NONE, "", PSTR("None")}}; } // not used. just for reference for derived classes - static constexpr uint8_t getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK - static constexpr uint8_t getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); } + static constexpr uint32_t getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK + static constexpr uint32_t getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); } static constexpr bool hasRGB(uint8_t type) { return !((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_ANALOG_1CH || type == TYPE_ANALOG_2CH || type == TYPE_ONOFF); } From e16d3bf040a20d104c29fe870639d04e018a7b8d Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Fri, 13 Dec 2024 07:40:04 +0100 Subject: [PATCH 073/463] Fix: output-glitching on ESPNow remote command reception Processing of received button command is no longer processed in the callback, instead the value is saved to a variable and processed in the main loop. The actual fix is to not access the file system while data is being sent out: even just trying to open a non-existing file causes glitches on the C3. Waiting for the bus to finish fixes this BUT it causes a frame-delay which is the lesser evil than random color flashes. --- wled00/fcn_declare.h | 1 + wled00/remote.cpp | 19 ++++++++++++++++--- wled00/wled.cpp | 3 +++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 3d8c27ac..e883c5fb 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -231,6 +231,7 @@ bool getPresetName(byte index, String& name); //remote.cpp void handleRemote(uint8_t *data, size_t len); +void processESPNowButton(); //set.cpp bool isAsterisksOnly(const char* str, byte maxLen); diff --git a/wled00/remote.cpp b/wled00/remote.cpp index 9bc5430c..de386932 100644 --- a/wled00/remote.cpp +++ b/wled00/remote.cpp @@ -1,6 +1,8 @@ #include "wled.h" #ifndef WLED_DISABLE_ESPNOW +#define ESPNOW_BUSWAIT_TIMEOUT 30 // timeout in ms to wait for bus to finish updating + #define NIGHT_MODE_DEACTIVATED -1 #define NIGHT_MODE_BRIGHTNESS 5 @@ -38,6 +40,7 @@ typedef struct WizMoteMessageStructure { static uint32_t last_seq = UINT32_MAX; static int brightnessBeforeNightMode = NIGHT_MODE_DEACTIVATED; +static uint8_t ESPNowButton = 0; // set in callback if new button value is received // Pulled from the IR Remote logic but reduced to 10 steps with a constant of 3 static const byte brightnessSteps[] = { @@ -121,6 +124,9 @@ static bool remoteJson(int button) sprintf_P(objKey, PSTR("\"%d\":"), button); + unsigned long start = millis(); + while (strip.isUpdating() && millis()-start < ESPNOW_BUSWAIT_TIMEOUT) yield(); // wait for strip to finish updating, accessing FS during sendout causes glitches + // attempt to read command from remote.json readObjectFromFile(PSTR("/remote.json"), objKey, pDoc); JsonObject fdo = pDoc->as(); @@ -202,8 +208,14 @@ void handleRemote(uint8_t *incomingData, size_t len) { DEBUG_PRINT(F("] button: ")); DEBUG_PRINTLN(incoming->button); - if (!remoteJson(incoming->button)) - switch (incoming->button) { + ESPNowButton = incoming->button; // save state, do not process in callback (can cause glitches) + last_seq = cur_seq; +} + +void processESPNowButton() { + if(ESPNowButton > 0) { + if (!remoteJson(ESPNowButton)) + switch (ESPNowButton) { case WIZMOTE_BUTTON_ON : setOn(); break; case WIZMOTE_BUTTON_OFF : setOff(); break; case WIZMOTE_BUTTON_ONE : presetWithFallback(1, FX_MODE_STATIC, 0); break; @@ -219,7 +231,8 @@ void handleRemote(uint8_t *incomingData, size_t len) { case WIZ_SMART_BUTTON_BRIGHT_DOWN : brightnessDown(); break; default: break; } - last_seq = cur_seq; + } + ESPNowButton = 0; } #else diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 394da678..229d363b 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -84,6 +84,9 @@ void WLED::loop() #ifndef WLED_DISABLE_INFRARED handleIR(); #endif + #ifndef WLED_DISABLE_ESPNOW + processESPNowButton(); + #endif #ifndef WLED_DISABLE_ALEXA handleAlexa(); #endif From 3c11c8441f8c34ff882661b34bf093599dbb22d8 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sun, 15 Dec 2024 20:54:16 +0100 Subject: [PATCH 074/463] fix errors in pltformio_override.ini (solves #4395) * WLED_tasmota_1M not existing * always use ${esp32.default_partitions} * fix build error in wemos_shield_esp32 --- platformio_override.sample.ini | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/platformio_override.sample.ini b/platformio_override.sample.ini index dd3630d8..bc1656c9 100644 --- a/platformio_override.sample.ini +++ b/platformio_override.sample.ini @@ -5,7 +5,7 @@ # Please visit documentation: https://docs.platformio.org/page/projectconf.html [platformio] -default_envs = WLED_tasmota_1M # define as many as you need +default_envs = WLED_generic8266_1M, esp32dev_V4_dio80 # put the name(s) of your own build environment here. You can define as many as you need #---------- # SAMPLE @@ -258,7 +258,7 @@ build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} #-D WLED_DISABLE_BROWNOUT_DET lib_deps = ${esp32_idf_V4.lib_deps} monitor_filters = esp32_exception_decoder -board_build.partitions = ${esp32_idf_V4.default_partitions} +board_build.partitions = ${esp32.default_partitions} board_build.f_flash = 80000000L board_build.flash_mode = dio @@ -368,6 +368,7 @@ platform_packages = ${esp32.platform_packages} upload_speed = 460800 build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32.build_flags} + -D WLED_RELEASE_NAME=\"ESP32_wemos_shield\" -D DATA_PINS=16 -D RLYPIN=19 -D BTNPIN=17 @@ -376,11 +377,11 @@ build_flags = ${common.build_flags} ${esp32.build_flags} -D USERMOD_DALLASTEMPERATURE -D USERMOD_FOUR_LINE_DISPLAY -D TEMPERATURE_PIN=23 - -D USERMOD_AUDIOREACTIVE + ${esp32.AR_build_flags} ;; includes USERMOD_AUDIOREACTIVE lib_deps = ${esp32.lib_deps} - OneWire@~2.3.5 - olikraus/U8g2 @ ^2.28.8 - https://github.com/blazoncek/arduinoFFT.git + OneWire@~2.3.5 ;; needed for USERMOD_DALLASTEMPERATURE + olikraus/U8g2 @ ^2.28.8 ;; needed for USERMOD_FOUR_LINE_DISPLAY + ${esp32.AR_lib_deps} ;; needed for USERMOD_AUDIOREACTIVE board_build.partitions = ${esp32.default_partitions} [env:m5atom] From c6fd4c51cf6327a45b91e58f81fa70f44d8d87b0 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sun, 15 Dec 2024 21:02:45 +0100 Subject: [PATCH 075/463] fix outdated build options * DEFAULT_LED_PIN --> DATA_PINS * DEFAULT_LED_COUNT --> PIXEL_COUNTS * DEFAULT_LED_TYPE --> LED_TYPES * USERMOD_AUDIOREACTIVE --> ${esp32.AR_build_flags} --- platformio_override.sample.ini | 35 ++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/platformio_override.sample.ini b/platformio_override.sample.ini index bc1656c9..cf7706d1 100644 --- a/platformio_override.sample.ini +++ b/platformio_override.sample.ini @@ -28,8 +28,8 @@ lib_deps = ${esp8266.lib_deps} ; robtillaart/SHT85@~0.3.3 ; ;gmag11/QuickESPNow @ ~0.7.0 # will also load QuickDebug ; https://github.com/blazoncek/QuickESPNow.git#optional-debug ;; exludes debug library -; ${esp32.AR_lib_deps} ;; used for USERMOD_AUDIOREACTIVE ; bitbank2/PNGdec@^1.0.1 ;; used for POV display uncomment following +; ${esp32.AR_lib_deps} ;; needed for USERMOD_AUDIOREACTIVE build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp8266.build_flags} @@ -141,7 +141,8 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} ; -D PIR_SENSOR_MAX_SENSORS=2 # max allowable sensors (uses OR logic for triggering) ; ; Use Audioreactive usermod and configure I2S microphone -; -D USERMOD_AUDIOREACTIVE +; ${esp32.AR_build_flags} ;; default flags required to propery configure ArduinoFFT +; ;; don't forget to add ArduinoFFT to your libs_deps: ${esp32.AR_lib_deps} ; -D AUDIOPIN=-1 ; -D DMTYPE=1 # 0-analog/disabled, 1-I2S generic, 2-ES7243, 3-SPH0645, 4-I2S+mclk, 5-I2S PDM ; -D I2S_SDPIN=36 @@ -157,17 +158,22 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} ; -D USERMOD_POV_DISPLAY ; Use built-in or custom LED as a status indicator (assumes LED is connected to GPIO16) ; -D STATUSLED=16 -; +; ; set the name of the module - make sure there is a quote-backslash-quote before the name and a backslash-quote-quote after the name ; -D SERVERNAME="\"WLED\"" -; +; ; set the number of LEDs -; -D DEFAULT_LED_COUNT=30 +; -D PIXEL_COUNTS=30 ; or this for multiple outputs ; -D PIXEL_COUNTS=30,30 ; ; set the default LED type -; -D DEFAULT_LED_TYPE=22 # see const.h (TYPE_xxxx) +; -D LED_TYPES=22 # see const.h (TYPE_xxxx) +; or this for multiple outputs +; -D LED_TYPES=TYPE_SK6812_RGBW,TYPE_WS2812_RGB +; +; set default color order of your led strip +; -D DEFAULT_LED_COLOR_ORDER=COL_ORDER_GRB ; ; set milliampere limit when using ESP power pin (or inadequate PSU) to power LEDs ; -D ABL_MILLIAMPS_DEFAULT=850 @@ -176,9 +182,6 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} ; enable IR by setting remote type ; -D IRTYPE=0 # 0 Remote disabled | 1 24-key RGB | 2 24-key with CT | 3 40-key blue | 4 40-key RGB | 5 21-key RGB | 6 6-key black | 7 9-key red | 8 JSON remote ; -; set default color order of your led strip -; -D DEFAULT_LED_COLOR_ORDER=COL_ORDER_GRB -; ; use PSRAM on classic ESP32 rev.1 (rev.3 or above has no issues) ; -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue # needed only for classic ESP32 rev.1 ; @@ -241,7 +244,9 @@ platform = ${esp32.platform} platform_packages = ${esp32.platform_packages} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32.build_flags} #-D WLED_DISABLE_BROWNOUT_DET + ${esp32.AR_build_flags} ;; optional - includes USERMOD_AUDIOREACTIVE lib_deps = ${esp32.lib_deps} + ${esp32.AR_lib_deps} ;; needed for USERMOD_AUDIOREACTIVE monitor_filters = esp32_exception_decoder board_build.partitions = ${esp32.default_partitions} board_build.f_flash = 80000000L @@ -256,7 +261,9 @@ platform = ${esp32_idf_V4.platform} platform_packages = ${esp32_idf_V4.platform_packages} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} #-D WLED_DISABLE_BROWNOUT_DET + ${esp32.AR_build_flags} ;; includes USERMOD_AUDIOREACTIVE lib_deps = ${esp32_idf_V4.lib_deps} + ${esp32.AR_lib_deps} ;; needed for USERMOD_AUDIOREACTIVE monitor_filters = esp32_exception_decoder board_build.partitions = ${esp32.default_partitions} board_build.f_flash = 80000000L @@ -307,7 +314,7 @@ platform = ${common.platform_wled_default} platform_packages = ${common.platform_packages} board_build.ldscript = ${common.ldscript_4m1m} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_USE_SHOJO_PCB +build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_USE_SHOJO_PCB ;; NB: WLED_USE_SHOJO_PCB is not used anywhere in the source code. Not sure why its needed. lib_deps = ${esp8266.lib_deps} [env:d1_mini_debug] @@ -373,7 +380,7 @@ build_flags = ${common.build_flags} ${esp32.build_flags} -D RLYPIN=19 -D BTNPIN=17 -D IRPIN=18 - -D UWLED_USE_MY_CONFIG + -UWLED_USE_MY_CONFIG -D USERMOD_DALLASTEMPERATURE -D USERMOD_FOUR_LINE_DISPLAY -D TEMPERATURE_PIN=23 @@ -414,7 +421,7 @@ platform_packages = ${common.platform_packages} board_build.ldscript = ${common.ldscript_2m512k} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=-1 -D RLYPIN=-1 -D DATA_PINS=4,12,14,13,5 - -D DEFAULT_LED_TYPE=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0 + -D LED_TYPES=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0 lib_deps = ${esp8266.lib_deps} [env:Athom_15w_RGBCW] ;15w bulb @@ -424,7 +431,7 @@ platform_packages = ${common.platform_packages} board_build.ldscript = ${common.ldscript_2m512k} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp8266.build_flags} -D BTNPIN=-1 -D RLYPIN=-1 -D DATA_PINS=4,12,14,5,13 - -D DEFAULT_LED_TYPE=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0 -D WLED_USE_IC_CCT + -D LED_TYPES=TYPE_ANALOG_5CH -D WLED_DISABLE_INFRARED -D WLED_MAX_CCT_BLEND=0 -D WLED_USE_IC_CCT lib_deps = ${esp8266.lib_deps} [env:Athom_3Pin_Controller] ;small controller with only data @@ -500,7 +507,7 @@ build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_DISABLE_BROWNOU -D DATA_PINS=12 -D RLYPIN=27 -D BTNPIN=34 - -D DEFAULT_LED_COUNT=6 + -D PIXEL_COUNTS=6 # Display config -D ST7789_DRIVER -D TFT_WIDTH=135 From 65f98c1f30a83ba2c1e586e7c9d6a4cb06c9cf53 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sun, 15 Dec 2024 21:07:01 +0100 Subject: [PATCH 076/463] esp32: use "extends" directly inherits default platform from esp32 --- platformio_override.sample.ini | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/platformio_override.sample.ini b/platformio_override.sample.ini index cf7706d1..4a6617a3 100644 --- a/platformio_override.sample.ini +++ b/platformio_override.sample.ini @@ -239,9 +239,8 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} -D DATA_PINS=1 -D WLE lib_deps = ${esp8266.lib_deps} [env:esp32dev_qio80] +extends = env:esp32dev # ww want to extend the existing esp32dev environment (and define only updated options) board = esp32dev -platform = ${esp32.platform} -platform_packages = ${esp32.platform_packages} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32.build_flags} #-D WLED_DISABLE_BROWNOUT_DET ${esp32.AR_build_flags} ;; optional - includes USERMOD_AUDIOREACTIVE @@ -256,9 +255,8 @@ board_build.flash_mode = qio ;; experimental ESP32 env using ESP-IDF V4.4.x ;; Warning: this build environment is not stable!! ;; please erase your device before installing. +extends = esp32_idf_V4 # based on newer "esp-idf V4" platform environment board = esp32dev -platform = ${esp32_idf_V4.platform} -platform_packages = ${esp32_idf_V4.platform_packages} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} #-D WLED_DISABLE_BROWNOUT_DET ${esp32.AR_build_flags} ;; includes USERMOD_AUDIOREACTIVE @@ -270,6 +268,7 @@ board_build.f_flash = 80000000L board_build.flash_mode = dio [env:esp32s2_saola] +extends = esp32s2 board = esp32-s2-saola-1 platform = ${esp32s2.platform} platform_packages = ${esp32s2.platform_packages} @@ -369,9 +368,8 @@ board_upload.flash_size = 2MB board_upload.maximum_size = 2097152 [env:wemos_shield_esp32] +extends = esp32 ;; use default esp32 platform board = esp32dev -platform = ${esp32.platform} -platform_packages = ${esp32.platform_packages} upload_speed = 460800 build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32.build_flags} From b72695f01ae1fca24ba4ef179fc3d0b51466f43c Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sun, 15 Dec 2024 21:22:19 +0100 Subject: [PATCH 077/463] added example environment for pico-D4 boards this one is actually for https://github.com/srg74/WLED-ESP32-pico Its a simple example how to configure WLED for a custom board with build-in microphone and special purpose pins. --- platformio_override.sample.ini | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/platformio_override.sample.ini b/platformio_override.sample.ini index 4a6617a3..27bbfe15 100644 --- a/platformio_override.sample.ini +++ b/platformio_override.sample.ini @@ -389,6 +389,26 @@ lib_deps = ${esp32.lib_deps} ${esp32.AR_lib_deps} ;; needed for USERMOD_AUDIOREACTIVE board_build.partitions = ${esp32.default_partitions} +[env:esp32_pico-D4] +extends = esp32 ;; use default esp32 platform +board = pico32 ;; pico32-D4 is different from the standard esp32dev + ;; hardware details from https://github.com/srg74/WLED-ESP32-pico +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} ${esp32.build_flags} + -D WLED_RELEASE_NAME=\"pico32-D4\" -D SERVERNAME='"WLED-pico32"' + -D WLED_DISABLE_ADALIGHT ;; no serial-to-USB chip on this board - better to disable serial protocols + -D DATA_PINS=2,18 ;; LED pins + -D RLYPIN=19 -D BTNPIN=0 -D IRPIN=-1 ;; no default pin for IR + ${esp32.AR_build_flags} ;; include USERMOD_AUDIOREACTIVE + -D UM_AUDIOREACTIVE_ENABLE ;; enable AR by default + ;; Audioreactive settings for on-board microphone (ICS-43432) + -D SR_DMTYPE=1 -D I2S_SDPIN=25 -D I2S_WSPIN=15 -D I2S_CKPIN=14 + -D SR_SQUELCH=5 -D SR_GAIN=30 +lib_deps = ${esp32.lib_deps} + ${esp32.AR_lib_deps} ;; needed for USERMOD_AUDIOREACTIVE +board_build.partitions = ${esp32.default_partitions} +board_build.f_flash = 80000000L + [env:m5atom] board = esp32dev build_unflags = ${common.build_unflags} From 6668e72351333c5df9357e6a540a55ab758d533e Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sun, 15 Dec 2024 21:35:13 +0100 Subject: [PATCH 078/463] fix typo --- platformio_override.sample.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio_override.sample.ini b/platformio_override.sample.ini index 27bbfe15..bf06a4a6 100644 --- a/platformio_override.sample.ini +++ b/platformio_override.sample.ini @@ -141,7 +141,7 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} ; -D PIR_SENSOR_MAX_SENSORS=2 # max allowable sensors (uses OR logic for triggering) ; ; Use Audioreactive usermod and configure I2S microphone -; ${esp32.AR_build_flags} ;; default flags required to propery configure ArduinoFFT +; ${esp32.AR_build_flags} ;; default flags required to properly configure ArduinoFFT ; ;; don't forget to add ArduinoFFT to your libs_deps: ${esp32.AR_lib_deps} ; -D AUDIOPIN=-1 ; -D DMTYPE=1 # 0-analog/disabled, 1-I2S generic, 2-ES7243, 3-SPH0645, 4-I2S+mclk, 5-I2S PDM @@ -239,7 +239,7 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} -D DATA_PINS=1 -D WLE lib_deps = ${esp8266.lib_deps} [env:esp32dev_qio80] -extends = env:esp32dev # ww want to extend the existing esp32dev environment (and define only updated options) +extends = env:esp32dev # we want to extend the existing esp32dev environment (and define only updated options) board = esp32dev build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32.build_flags} #-D WLED_DISABLE_BROWNOUT_DET From 3d3c475d1bbd1a6973bd876e2fb7a82afe1f14fb Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sun, 15 Dec 2024 22:20:52 +0100 Subject: [PATCH 079/463] define board_build.partitions and build_unflags in standard envs to ensure that build_unflags and board_build.partitions are always having a useful default value. Values can be overridden in custom buildenvs. saves us a few lines lin platformio_override.sample.ini. --- platformio.ini | 11 +++++++++++ platformio_override.sample.ini | 20 +++----------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/platformio.ini b/platformio.ini index fe02213f..0870cde9 100644 --- a/platformio.ini +++ b/platformio.ini @@ -176,6 +176,7 @@ lib_deps = extra_scripts = ${scripts_defaults.extra_scripts} [esp8266] +build_unflags = ${common.build_unflags} build_flags = -DESP8266 -DFP_IN_IROM @@ -242,6 +243,7 @@ lib_deps_compat = #platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.3/platform-espressif32-2.0.2.3.zip platform = espressif32@3.5.0 platform_packages = framework-arduinoespressif32 @ https://github.com/Aircoookie/arduino-esp32.git#1.0.6.4 +build_unflags = ${common.build_unflags} build_flags = -g -DARDUINO_ARCH_ESP32 #-DCONFIG_LITTLEFS_FOR_IDF_3_2 @@ -263,6 +265,7 @@ lib_deps = AR_build_flags = -D USERMOD_AUDIOREACTIVE -D sqrt_internal=sqrtf ;; -fsingle-precision-constant ;; forces ArduinoFFT to use float math (2x faster) AR_lib_deps = kosme/arduinoFFT @ 2.0.1 +board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs [esp32_idf_V4] ;; experimental build environment for ESP32 using ESP-IDF 4.4.x / arduino-esp32 v2.0.5 @@ -272,6 +275,7 @@ AR_lib_deps = kosme/arduinoFFT @ 2.0.1 ;; You need to completely erase your device (esptool erase_flash) first, then install the "V4" build from VSCode+platformio. platform = espressif32@ ~6.3.2 platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them) +build_unflags = ${common.build_unflags} build_flags = -g -Wshadow=compatible-local ;; emit warning in case a local variable "shadows" another local one -DARDUINO_ARCH_ESP32 -DESP32 @@ -280,11 +284,13 @@ build_flags = -g lib_deps = https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 ${env.lib_deps} +board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs [esp32s2] ;; generic definitions for all ESP32-S2 boards platform = espressif32@ ~6.3.2 platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them) +build_unflags = ${common.build_unflags} build_flags = -g -DARDUINO_ARCH_ESP32 -DARDUINO_ARCH_ESP32S2 @@ -298,11 +304,13 @@ build_flags = -g lib_deps = https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 ${env.lib_deps} +board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs [esp32c3] ;; generic definitions for all ESP32-C3 boards platform = espressif32@ ~6.3.2 platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them) +build_unflags = ${common.build_unflags} build_flags = -g -DARDUINO_ARCH_ESP32 -DARDUINO_ARCH_ESP32C3 @@ -315,11 +323,13 @@ build_flags = -g lib_deps = https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 ${env.lib_deps} +board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs [esp32s3] ;; generic definitions for all ESP32-S3 boards platform = espressif32@ ~6.3.2 platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them) +build_unflags = ${common.build_unflags} build_flags = -g -DESP32 -DARDUINO_ARCH_ESP32 @@ -333,6 +343,7 @@ build_flags = -g lib_deps = https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 ${env.lib_deps} +board_build.partitions = ${esp32.large_partitions} ;; default partioning for 8MB flash - can be overridden in build envs # ------------------------------------------------------------------------------ diff --git a/platformio_override.sample.ini b/platformio_override.sample.ini index bf06a4a6..d945bd91 100644 --- a/platformio_override.sample.ini +++ b/platformio_override.sample.ini @@ -241,13 +241,11 @@ lib_deps = ${esp8266.lib_deps} [env:esp32dev_qio80] extends = env:esp32dev # we want to extend the existing esp32dev environment (and define only updated options) board = esp32dev -build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32.build_flags} #-D WLED_DISABLE_BROWNOUT_DET ${esp32.AR_build_flags} ;; optional - includes USERMOD_AUDIOREACTIVE lib_deps = ${esp32.lib_deps} ${esp32.AR_lib_deps} ;; needed for USERMOD_AUDIOREACTIVE monitor_filters = esp32_exception_decoder -board_build.partitions = ${esp32.default_partitions} board_build.f_flash = 80000000L board_build.flash_mode = qio @@ -257,13 +255,12 @@ board_build.flash_mode = qio ;; please erase your device before installing. extends = esp32_idf_V4 # based on newer "esp-idf V4" platform environment board = esp32dev -build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} #-D WLED_DISABLE_BROWNOUT_DET ${esp32.AR_build_flags} ;; includes USERMOD_AUDIOREACTIVE lib_deps = ${esp32_idf_V4.lib_deps} ${esp32.AR_lib_deps} ;; needed for USERMOD_AUDIOREACTIVE monitor_filters = esp32_exception_decoder -board_build.partitions = ${esp32.default_partitions} +board_build.partitions = ${esp32.default_partitions} ;; if you get errors about "out of program space", change this to ${esp32.extended_partitions} or even ${esp32.big_partitions} board_build.f_flash = 80000000L board_build.flash_mode = dio @@ -273,10 +270,8 @@ board = esp32-s2-saola-1 platform = ${esp32s2.platform} platform_packages = ${esp32s2.platform_packages} framework = arduino -board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv board_build.flash_mode = qio upload_speed = 460800 -build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32s2.build_flags} ;-DLOLIN_WIFI_FIX ;; try this in case Wifi does not work -DARDUINO_USB_CDC_ON_BOOT=1 @@ -371,7 +366,6 @@ board_upload.maximum_size = 2097152 extends = esp32 ;; use default esp32 platform board = esp32dev upload_speed = 460800 -build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32_wemos_shield\" -D DATA_PINS=16 @@ -393,7 +387,6 @@ board_build.partitions = ${esp32.default_partitions} extends = esp32 ;; use default esp32 platform board = pico32 ;; pico32-D4 is different from the standard esp32dev ;; hardware details from https://github.com/srg74/WLED-ESP32-pico -build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"pico32-D4\" -D SERVERNAME='"WLED-pico32"' -D WLED_DISABLE_ADALIGHT ;; no serial-to-USB chip on this board - better to disable serial protocols @@ -410,13 +403,8 @@ board_build.partitions = ${esp32.default_partitions} board_build.f_flash = 80000000L [env:m5atom] -board = esp32dev -build_unflags = ${common.build_unflags} +extends = env:esp32dev # we want to extend the existing esp32dev environment (and define only updated options) build_flags = ${common.build_flags} ${esp32.build_flags} -D DATA_PINS=27 -D BTNPIN=39 -lib_deps = ${esp32.lib_deps} -platform = ${esp32.platform} -platform_packages = ${esp32.platform_packages} -board_build.partitions = ${esp32.default_partitions} [env:sp501e] board = esp_wroom_02 @@ -515,9 +503,8 @@ lib_deps = ${esp8266.lib_deps} # EleksTube-IPS # ------------------------------------------------------------------------------ [env:elekstube_ips] +extends = esp32 ;; use default esp32 platform board = esp32dev -platform = ${esp32.platform} -platform_packages = ${esp32.platform_packages} upload_speed = 921600 build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_DISABLE_BROWNOUT_DET -D WLED_DISABLE_INFRARED -D USERMOD_RTC @@ -542,4 +529,3 @@ monitor_filters = esp32_exception_decoder lib_deps = ${esp32.lib_deps} TFT_eSPI @ ^2.3.70 -board_build.partitions = ${esp32.default_partitions} From 18e0ec9a554c4c01063d93169b4cc8c1755a5414 Mon Sep 17 00:00:00 2001 From: netmindz Date: Mon, 16 Dec 2024 13:21:07 +0000 Subject: [PATCH 080/463] PRs to main now --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 06c221fc..670b5561 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,7 +14,7 @@ A good description helps us to review and understand your proposed changes. For ### Target branch for pull requests -Please make all PRs against the `0_15` branch. +Please make all PRs against the `main` branch. ### Updating your code While the PR is open - and under review by maintainers - you may be asked to modify your PR source code. @@ -105,4 +105,4 @@ Good: There is no hard character limit for a comment within a line, though as a rule of thumb consider wrapping after 120 characters. -Inline comments are OK if they describe that line only and are not exceedingly wide. \ No newline at end of file +Inline comments are OK if they describe that line only and are not exceedingly wide. From b8a96d9a772fae6b9a1d188237f38019342c57b0 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 16 Dec 2024 15:46:59 +0100 Subject: [PATCH 081/463] workaround for elekstube_ips compile error the trick is to pin TFT_eSPI version 2.5.33 --- platformio_override.sample.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio_override.sample.ini b/platformio_override.sample.ini index d945bd91..cb5b43e7 100644 --- a/platformio_override.sample.ini +++ b/platformio_override.sample.ini @@ -528,4 +528,4 @@ build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_DISABLE_BROWNOU monitor_filters = esp32_exception_decoder lib_deps = ${esp32.lib_deps} - TFT_eSPI @ ^2.3.70 + TFT_eSPI @ 2.5.33 ;; this is the last version that compiles with the WLED default framework - newer versions require platform = espressif32 @ ^6.3.2 From b4aa8376deae9d0b66ae9268ba85665de07d43f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Tue, 17 Dec 2024 18:59:53 +0100 Subject: [PATCH 082/463] Idle current bugfix (#4402) --- wled00/bus_manager.cpp | 11 ----------- wled00/bus_manager.h | 12 +++++++++++- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 5b031beb..fa78b480 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -155,16 +155,6 @@ BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) DEBUG_PRINTF_P(PSTR("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u). mA=%d/%d\n"), _valid?"S":"Uns", nr, bc.count, bc.type, _pins[0], is2Pin(bc.type)?_pins[1]:255, _iType, _milliAmpsPerLed, _milliAmpsMax); } -//fine tune power estimation constants for your setup -//you can set it to 0 if the ESP is powered by USB and the LEDs by external -#ifndef MA_FOR_ESP - #ifdef ESP8266 - #define MA_FOR_ESP 80 //how much mA does the ESP use (Wemos D1 about 80mA) - #else - #define MA_FOR_ESP 120 //how much mA does the ESP use (ESP32 about 120mA) - #endif -#endif - //DISCLAIMER //The following function attemps to calculate the current LED power usage, //and will limit the brightness to stay below a set amperage threshold. @@ -943,7 +933,6 @@ void BusManager::show() { busses[i]->show(); _milliAmpsUsed += busses[i]->getUsedCurrent(); } - if (_milliAmpsUsed) _milliAmpsUsed += MA_FOR_ESP; } void BusManager::setStatusPixel(uint32_t c) { diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index ecebc120..89307af2 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -363,6 +363,16 @@ struct BusConfig { }; +//fine tune power estimation constants for your setup +//you can set it to 0 if the ESP is powered by USB and the LEDs by external +#ifndef MA_FOR_ESP + #ifdef ESP8266 + #define MA_FOR_ESP 80 //how much mA does the ESP use (Wemos D1 about 80mA) + #else + #define MA_FOR_ESP 120 //how much mA does the ESP use (ESP32 about 120mA) + #endif +#endif + class BusManager { public: BusManager() {}; @@ -370,7 +380,7 @@ class BusManager { //utility to get the approx. memory usage of a given BusConfig static uint32_t memUsage(BusConfig &bc); static uint32_t memUsage(unsigned channels, unsigned count, unsigned buses = 1); - static uint16_t currentMilliamps() { return _milliAmpsUsed; } + static uint16_t currentMilliamps() { return _milliAmpsUsed + MA_FOR_ESP; } static uint16_t ablMilliampsMax() { return _milliAmpsMax; } static int add(BusConfig &bc); From e57c701837ca3bcc65b9f2036baeace19b55c011 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 19 Dec 2024 09:21:57 +0100 Subject: [PATCH 083/463] fix for repeating glitch glitch appeared every 65s due to missing uint16_t overflow. --- wled00/FX.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index fd2118fd..7b2839f3 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -1441,7 +1441,7 @@ uint16_t mode_fairy() { if (z == zones-1) flashersInZone = numFlashers-(flashersInZone*(zones-1)); for (unsigned f = firstFlasher; f < firstFlasher + flashersInZone; f++) { - unsigned stateTime = now16 - flashers[f].stateStart; + unsigned stateTime = uint16_t(now16 - flashers[f].stateStart); //random on/off time reached, switch state if (stateTime > flashers[f].stateDur * 10) { flashers[f].stateOn = !flashers[f].stateOn; @@ -1500,7 +1500,7 @@ uint16_t mode_fairytwinkle() { unsigned maxDur = riseFallTime/100 + ((255 - SEGMENT.intensity) >> 2) + 13 + ((255 - SEGMENT.intensity) >> 1); for (int f = 0; f < SEGLEN; f++) { - unsigned stateTime = now16 - flashers[f].stateStart; + uint16_t stateTime = now16 - flashers[f].stateStart; //random on/off time reached, switch state if (stateTime > flashers[f].stateDur * 100) { flashers[f].stateOn = !flashers[f].stateOn; From fd3b47908b8eab700391a759a99d3987f536586f Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 19 Dec 2024 17:41:44 +0100 Subject: [PATCH 084/463] renamed functions, changed timeout to 24ms --- wled00/fcn_declare.h | 4 ++-- wled00/remote.cpp | 9 +++++---- wled00/udp.cpp | 2 +- wled00/wled.cpp | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index e883c5fb..2e965a9a 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -230,8 +230,8 @@ void deletePreset(byte index); bool getPresetName(byte index, String& name); //remote.cpp -void handleRemote(uint8_t *data, size_t len); -void processESPNowButton(); +void handleWiZdata(uint8_t *incomingData, size_t len); +void handleRemote(); //set.cpp bool isAsterisksOnly(const char* str, byte maxLen); diff --git a/wled00/remote.cpp b/wled00/remote.cpp index de386932..8787369c 100644 --- a/wled00/remote.cpp +++ b/wled00/remote.cpp @@ -1,7 +1,7 @@ #include "wled.h" #ifndef WLED_DISABLE_ESPNOW -#define ESPNOW_BUSWAIT_TIMEOUT 30 // timeout in ms to wait for bus to finish updating +#define ESPNOW_BUSWAIT_TIMEOUT 24 // one frame timeout to wait for bus to finish updating #define NIGHT_MODE_DEACTIVATED -1 #define NIGHT_MODE_BRIGHTNESS 5 @@ -182,7 +182,7 @@ static bool remoteJson(int button) } // Callback function that will be executed when data is received -void handleRemote(uint8_t *incomingData, size_t len) { +void handleWiZdata(uint8_t *incomingData, size_t len) { message_structure_t *incoming = reinterpret_cast(incomingData); if (strcmp(last_signal_src, linked_remote) != 0) { @@ -212,7 +212,8 @@ void handleRemote(uint8_t *incomingData, size_t len) { last_seq = cur_seq; } -void processESPNowButton() { +// process ESPNow button data (acesses FS, should not be called while update to avoid glitches) +void handleRemote() { if(ESPNowButton > 0) { if (!remoteJson(ESPNowButton)) switch (ESPNowButton) { @@ -236,5 +237,5 @@ void processESPNowButton() { } #else -void handleRemote(uint8_t *incomingData, size_t len) {} +void handleRemote() {} #endif diff --git a/wled00/udp.cpp b/wled00/udp.cpp index 60774d70..5173842a 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -979,7 +979,7 @@ void espNowReceiveCB(uint8_t* address, uint8_t* data, uint8_t len, signed int rs // handle WiZ Mote data if (data[0] == 0x91 || data[0] == 0x81 || data[0] == 0x80) { - handleRemote(data, len); + handleWiZdata(data, len); return; } diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 229d363b..b7f4ad7d 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -85,7 +85,7 @@ void WLED::loop() handleIR(); #endif #ifndef WLED_DISABLE_ESPNOW - processESPNowButton(); + handleRemote(); #endif #ifndef WLED_DISABLE_ALEXA handleAlexa(); From dcfebcb9732e3ffae63d8e2b8566f70397b6c745 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 19 Dec 2024 17:46:39 +0100 Subject: [PATCH 085/463] allow for 0 value button code --- wled00/remote.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wled00/remote.cpp b/wled00/remote.cpp index 8787369c..c3325ab9 100644 --- a/wled00/remote.cpp +++ b/wled00/remote.cpp @@ -40,7 +40,7 @@ typedef struct WizMoteMessageStructure { static uint32_t last_seq = UINT32_MAX; static int brightnessBeforeNightMode = NIGHT_MODE_DEACTIVATED; -static uint8_t ESPNowButton = 0; // set in callback if new button value is received +static int16_t ESPNowButton = -1; // set in callback if new button value is received // Pulled from the IR Remote logic but reduced to 10 steps with a constant of 3 static const byte brightnessSteps[] = { @@ -214,7 +214,7 @@ void handleWiZdata(uint8_t *incomingData, size_t len) { // process ESPNow button data (acesses FS, should not be called while update to avoid glitches) void handleRemote() { - if(ESPNowButton > 0) { + if(ESPNowButton >= 0) { if (!remoteJson(ESPNowButton)) switch (ESPNowButton) { case WIZMOTE_BUTTON_ON : setOn(); break; @@ -233,7 +233,7 @@ void handleRemote() { default: break; } } - ESPNowButton = 0; + ESPNowButton = -1; } #else From 26397ee8ad675ef6c19cb4c2be70009166926c76 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 19 Dec 2024 18:20:56 +0100 Subject: [PATCH 086/463] Optimization: color_blend() (#4245) Removing the bool saves on code size and makes the function a tiny bit faster. Also this is a cleaner solution IMHO. -updated blend function to optimized 8bit calculation - efficient color blend calculation in fews operations possible - omitting min / max checks makes it faster on average - using 8bit for "blend" variable does not significantly influence the resulting color, just transition points are slightly shifted but yield very good results (and better than the original 16bit version using the old fastled math with improper rounding) - updated drawCircle and drawLine to use 8bit directly instead of 16bit with a shift --- wled00/FX.cpp | 98 ++++++++++++++++++++++---------------------- wled00/FX_2Dfcn.cpp | 44 ++++++++++---------- wled00/FX_fcn.cpp | 9 ++-- wled00/colors.cpp | 34 +++++---------- wled00/fcn_declare.h | 3 +- 5 files changed, 88 insertions(+), 100 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 7b2839f3..ae69be10 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -200,7 +200,7 @@ uint16_t color_wipe(bool rev, bool useRandomColors) { } else { SEGMENT.setPixelColor(index, back? col0 : col1); - if (i == ledIndex) SEGMENT.setPixelColor(index, color_blend(back? col0 : col1, back? col1 : col0, rem)); + if (i == ledIndex) SEGMENT.setPixelColor(index, color_blend(back? col0 : col1, back? col1 : col0, uint8_t(rem))); } } return FRAMETIME; @@ -271,7 +271,7 @@ uint16_t mode_random_color(void) { SEGENV.step = it; } - SEGMENT.fill(color_blend(SEGMENT.color_wheel(SEGENV.aux1), SEGMENT.color_wheel(SEGENV.aux0), fade)); + SEGMENT.fill(color_blend(SEGMENT.color_wheel(SEGENV.aux1), SEGMENT.color_wheel(SEGENV.aux0), uint8_t(fade))); return FRAMETIME; } static const char _data_FX_MODE_RANDOM_COLOR[] PROGMEM = "Random Colors@!,Fade time;;!;01"; @@ -338,7 +338,7 @@ uint16_t mode_breath(void) { var = sin16_t(counter) / 103; //close to parabolic in range 0-8192, max val. 23170 } - unsigned lum = 30 + var; + uint8_t lum = 30 + var; for (int i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), lum)); } @@ -353,7 +353,7 @@ static const char _data_FX_MODE_BREATH[] PROGMEM = "Breathe@!;!,!;!;01"; */ uint16_t mode_fade(void) { unsigned counter = (strip.now * ((SEGMENT.speed >> 3) +10)); - unsigned lum = triwave16(counter) >> 8; + uint8_t lum = triwave16(counter) >> 8; for (int i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), lum)); @@ -421,7 +421,7 @@ uint16_t mode_rainbow(void) { counter = counter >> 8; if (SEGMENT.intensity < 128){ - SEGMENT.fill(color_blend(SEGMENT.color_wheel(counter),WHITE,128-SEGMENT.intensity)); + SEGMENT.fill(color_blend(SEGMENT.color_wheel(counter),WHITE,uint8_t(128-SEGMENT.intensity))); } else { SEGMENT.fill(SEGMENT.color_wheel(counter)); } @@ -523,7 +523,7 @@ static uint16_t running_base(bool saw, bool dual=false) { unsigned b = (SEGLEN-1-i)*x_scale - counter; uint8_t t = sin_gap(b); uint32_t cb = color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 2), t); - ca = color_blend(ca, cb, 127); + ca = color_blend(ca, cb, uint8_t(127)); } SEGMENT.setPixelColor(i, ca); } @@ -1336,7 +1336,7 @@ uint16_t gradient_base(bool loading) { val = min(abs(pp-i),min(abs(p1-i),abs(p2-i))); } val = (brd > val) ? (val * 255) / brd : 255; - SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(0), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1), val)); + SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(0), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1), uint8_t(val))); } return FRAMETIME; @@ -1470,7 +1470,7 @@ uint16_t mode_fairy() { unsigned globalPeakBri = 255 - ((avgFlasherBri * MAX_SHIMMER) >> 8); //183-255, suitable for 1/5th of LEDs flashers for (unsigned f = firstFlasher; f < firstFlasher + flashersInZone; f++) { - unsigned bri = (flasherBri[f - firstFlasher] * globalPeakBri) / 255; + uint8_t bri = (flasherBri[f - firstFlasher] * globalPeakBri) / 255; PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; //next 'random' number unsigned flasherPos = f*flasherDistance; SEGMENT.setPixelColor(flasherPos, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(PRNG16 >> 8, false, false, 0), bri)); @@ -1521,7 +1521,7 @@ uint16_t mode_fairytwinkle() { if (flashers[f].stateOn && flashers[f].stateDur > maxDur) flashers[f].stateDur = maxDur; //react more quickly on intensity change if (stateTime > riseFallTime) stateTime = riseFallTime; //for flasher brightness calculation, fades in first 255 ms of state unsigned fadeprog = 255 - ((stateTime * 255) / riseFallTime); - unsigned flasherBri = (flashers[f].stateOn) ? 255-gamma8(fadeprog) : gamma8(fadeprog); + uint8_t flasherBri = (flashers[f].stateOn) ? 255-gamma8(fadeprog) : gamma8(fadeprog); unsigned lastR = PRNG16; unsigned diff = 0; while (diff < 0x4000) { //make sure colors of two adjacent LEDs differ enough @@ -1815,7 +1815,7 @@ uint16_t mode_oscillate(void) { uint32_t color = BLACK; for (unsigned j = 0; j < numOscillators; j++) { if(i >= (unsigned)oscillators[j].pos - oscillators[j].size && i <= oscillators[j].pos + oscillators[j].size) { - color = (color == BLACK) ? SEGCOLOR(j) : color_blend(color, SEGCOLOR(j), 128); + color = (color == BLACK) ? SEGCOLOR(j) : color_blend(color, SEGCOLOR(j), uint8_t(128)); } } SEGMENT.setPixelColor(i, color); @@ -2508,7 +2508,7 @@ static uint16_t ripple_base() { int left = rippleorigin - propI -1; int right = rippleorigin + propI +2; for (int v = 0; v < 4; v++) { - unsigned mag = scale8(cubicwave8((propF>>2) + v * 64), amp); + uint8_t mag = scale8(cubicwave8((propF>>2) + v * 64), amp); SEGMENT.setPixelColor(left + v, color_blend(SEGMENT.getPixelColor(left + v), col, mag)); // TODO SEGMENT.setPixelColor(right - v, color_blend(SEGMENT.getPixelColor(right - v), col, mag)); // TODO } @@ -2551,7 +2551,7 @@ uint16_t mode_ripple_rainbow(void) { } else { SEGENV.aux0--; } - SEGMENT.fill(color_blend(SEGMENT.color_wheel(SEGENV.aux0),BLACK,235)); + SEGMENT.fill(color_blend(SEGMENT.color_wheel(SEGENV.aux0),BLACK,uint8_t(235))); return ripple_base(); } static const char _data_FX_MODE_RIPPLE_RAINBOW[] PROGMEM = "Ripple Rainbow@!,Wave #;;!;12"; @@ -2670,7 +2670,7 @@ static uint16_t twinklefox_base(bool cat) } else if (deltabright > 0) { // If the new pixel is just slightly brighter than the background color, // mix a blend of the new color and the background color - SEGMENT.setPixelColor(i, color_blend(RGBW32(bg.r,bg.g,bg.b,0), RGBW32(c.r,c.g,c.b,0), deltabright * 8)); + SEGMENT.setPixelColor(i, color_blend(RGBW32(bg.r,bg.g,bg.b,0), RGBW32(c.r,c.g,c.b,0), uint8_t(deltabright * 8))); } else { // if the new pixel is not at all brighter than the background color, // just use the background color. @@ -2766,7 +2766,7 @@ uint16_t mode_halloween_eyes() const uint32_t eyeColor = SEGMENT.color_from_palette(data.color, false, false, 0); uint32_t c = eyeColor; if (fadeInAnimationState < 256u) { - c = color_blend(backgroundColor, eyeColor, fadeInAnimationState); + c = color_blend(backgroundColor, eyeColor, uint8_t(fadeInAnimationState)); } else if (elapsedTime > minimumOnTimeBegin) { const uint32_t remainingTime = (elapsedTime >= duration) ? 0u : (duration - elapsedTime); if (remainingTime > minimumOnTimeEnd) { @@ -2919,7 +2919,7 @@ static uint16_t spots_base(uint16_t threshold) if (wave > threshold) { unsigned index = 0 + pos + i; unsigned s = (wave - threshold)*255 / (0xFFFF - threshold); - SEGMENT.setPixelColor(index, color_blend(SEGMENT.color_from_palette(index, true, PALETTE_SOLID_WRAP, 0), SEGCOLOR(1), 255-s)); + SEGMENT.setPixelColor(index, color_blend(SEGMENT.color_from_palette(index, true, PALETTE_SOLID_WRAP, 0), SEGCOLOR(1), uint8_t(255-s))); } } } @@ -3365,12 +3365,12 @@ uint16_t candle(bool multi) } if (i > 0) { - SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), s)); + SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), uint8_t(s))); SEGENV.data[d] = s; SEGENV.data[d+1] = s_target; SEGENV.data[d+2] = fadeStep; } else { for (int j = 0; j < SEGLEN; j++) { - SEGMENT.setPixelColor(j, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(j, true, PALETTE_SOLID_WRAP, 0), s)); + SEGMENT.setPixelColor(j, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(j, true, PALETTE_SOLID_WRAP, 0), uint8_t(s))); } SEGENV.aux0 = s; SEGENV.aux1 = s_target; SEGENV.step = fadeStep; @@ -3488,7 +3488,7 @@ uint16_t mode_starburst(void) { float age = it-stars[j].birth; if (age < particleIgnition) { - c = CRGB(color_blend(WHITE, RGBW32(c.r,c.g,c.b,0), 254.5f*((age / particleIgnition)))); + c = CRGB(color_blend(WHITE, RGBW32(c.r,c.g,c.b,0), uint8_t(254.5f*((age / particleIgnition))))); } else { // Figure out how much to fade and shrink the star based on // its age relative to its lifetime @@ -3499,8 +3499,7 @@ uint16_t mode_starburst(void) { } else { age -= particleIgnition; fade = (age / particleFadeTime); // Fading star - byte f = 254.5f*fade; - c = CRGB(color_blend(RGBW32(c.r,c.g,c.b,0), SEGCOLOR(1), f)); + c = CRGB(color_blend(RGBW32(c.r,c.g,c.b,0), SEGCOLOR(1), uint8_t(254.5f*fade))); } } @@ -3639,9 +3638,9 @@ uint16_t mode_exploding_fireworks(void) uint32_t spColor = (SEGMENT.palette) ? SEGMENT.color_wheel(sparks[i].colIndex) : SEGCOLOR(0); CRGB c = CRGB::Black; //HeatColor(sparks[i].col); if (prog > 300) { //fade from white to spark color - c = CRGB(color_blend(spColor, WHITE, (prog - 300)*5)); + c = CRGB(color_blend(spColor, WHITE, uint8_t((prog - 300)*5))); } else if (prog > 45) { //fade from spark color to black - c = CRGB(color_blend(BLACK, spColor, prog - 45)); + c = CRGB(color_blend(BLACK, spColor, uint8_t(prog - 45))); unsigned cooling = (300 - prog) >> 5; c.g = qsub8(c.g, cooling); c.b = qsub8(c.b, cooling * 2); @@ -3701,10 +3700,10 @@ uint16_t mode_drip(void) drops[j].colIndex = 1; // drop state (0 init, 1 forming, 2 falling, 5 bouncing) } - SEGMENT.setPixelColor(indexToVStrip(SEGLEN-1, stripNr), color_blend(BLACK,SEGCOLOR(0), sourcedrop));// water source + SEGMENT.setPixelColor(indexToVStrip(SEGLEN-1, stripNr), color_blend(BLACK,SEGCOLOR(0), uint8_t(sourcedrop)));// water source if (drops[j].colIndex==1) { if (drops[j].col>255) drops[j].col=255; - SEGMENT.setPixelColor(indexToVStrip(uint16_t(drops[j].pos), stripNr), color_blend(BLACK,SEGCOLOR(0),drops[j].col)); + SEGMENT.setPixelColor(indexToVStrip(uint16_t(drops[j].pos), stripNr), color_blend(BLACK,SEGCOLOR(0),uint8_t(drops[j].col))); drops[j].col += map(SEGMENT.speed, 0, 255, 1, 6); // swelling @@ -3721,11 +3720,11 @@ uint16_t mode_drip(void) for (int i=1;i<7-drops[j].colIndex;i++) { // some minor math so we don't expand bouncing droplets unsigned pos = constrain(uint16_t(drops[j].pos) +i, 0, SEGLEN-1); //this is BAD, returns a pos >= SEGLEN occasionally - SEGMENT.setPixelColor(indexToVStrip(pos, stripNr), color_blend(BLACK,SEGCOLOR(0),drops[j].col/i)); //spread pixel with fade while falling + SEGMENT.setPixelColor(indexToVStrip(pos, stripNr), color_blend(BLACK,SEGCOLOR(0),uint8_t(drops[j].col/i))); //spread pixel with fade while falling } if (drops[j].colIndex > 2) { // during bounce, some water is on the floor - SEGMENT.setPixelColor(indexToVStrip(0, stripNr), color_blend(SEGCOLOR(0),BLACK,drops[j].col)); + SEGMENT.setPixelColor(indexToVStrip(0, stripNr), color_blend(SEGCOLOR(0),BLACK,uint8_t(drops[j].col))); } } else { // we hit bottom if (drops[j].colIndex > 2) { // already hit once, so back to forming @@ -3948,7 +3947,7 @@ uint16_t mode_heartbeat(void) { } for (int i = 0; i < SEGLEN; i++) { - SEGMENT.setPixelColor(i, color_blend(SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), SEGCOLOR(1), 255 - (SEGENV.aux1 >> 8))); + SEGMENT.setPixelColor(i, color_blend(SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), SEGCOLOR(1), uint8_t(255 - (SEGENV.aux1 >> 8)))); } return FRAMETIME; @@ -4147,7 +4146,7 @@ static uint16_t phased_base(uint8_t moder) { // We're making si val += *phase * (i % modVal +1) /2; // This sets the varying phase change of the waves. By Andrew Tuline. unsigned b = cubicwave8(val); // Now we make an 8 bit sinewave. b = (b > cutOff) ? (b - cutOff) : 0; // A ternary operator to cutoff the light. - SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(index, false, false, 0), b)); + SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(index, false, false, 0), uint8_t(b))); index += 256 / SEGLEN; if (SEGLEN > 256) index ++; // Correction for segments longer than 256 LEDs } @@ -4236,7 +4235,7 @@ uint16_t mode_sinewave(void) { // Adjustable sinewave. By Andrew Tul unsigned freq = SEGMENT.intensity/4;//SEGMENT.fft2/8; // Frequency of the signal. for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows: - int pixBri = cubicwave8((i*freq)+SEGENV.step);//qsuba(cubicwave8((i*freq)+SEGENV.step), (255-SEGMENT.intensity)); // qsub sets a minimum value called thiscutoff. If < thiscutoff, then bright = 0. Otherwise, bright = 128 (as defined in qsub).. + uint8_t pixBri = cubicwave8((i*freq)+SEGENV.step);//qsuba(cubicwave8((i*freq)+SEGENV.step), (255-SEGMENT.intensity)); // qsub sets a minimum value called thiscutoff. If < thiscutoff, then bright = 0. Otherwise, bright = 128 (as defined in qsub).. //setPixCol(i, i*colorIndex/255, pixBri); SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i*colorIndex/255, false, PALETTE_SOLID_WRAP, 0), pixBri)); } @@ -4486,7 +4485,7 @@ uint16_t mode_blends(void) { unsigned dataSize = sizeof(uint32_t) * (pixelLen + 1); // max segment length of 56 pixels on 16 segment ESP8266 if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed uint32_t* pixels = reinterpret_cast(SEGENV.data); - unsigned blendSpeed = map(SEGMENT.intensity, 0, UINT8_MAX, 10, 128); + uint8_t blendSpeed = map(SEGMENT.intensity, 0, UINT8_MAX, 10, 128); unsigned shift = (strip.now * ((SEGMENT.speed >> 3) +1)) >> 8; for (unsigned i = 0; i < pixelLen; i++) { @@ -6325,7 +6324,7 @@ static const char _data_FX_MODE_2DPLASMAROTOZOOM[] PROGMEM = "Rotozoomer@!,Scale ///////////////////////////////// uint16_t mode_ripplepeak(void) { // * Ripple peak. By Andrew Tuline. // This currently has no controls. - #define maxsteps 16 // Case statement wouldn't allow a variable. + #define MAXSTEPS 16 // Case statement wouldn't allow a variable. unsigned maxRipples = 16; unsigned dataSize = sizeof(Ripple) * maxRipples; @@ -6343,7 +6342,6 @@ uint16_t mode_ripplepeak(void) { // * Ripple peak. By Andrew Tuli // printUmData(); if (SEGENV.call == 0) { - SEGENV.aux0 = 255; SEGMENT.custom1 = *binNum; SEGMENT.custom2 = *maxVol * 2; } @@ -6374,17 +6372,17 @@ uint16_t mode_ripplepeak(void) { // * Ripple peak. By Andrew Tuli break; case 0: - SEGMENT.setPixelColor(ripples[i].pos, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(ripples[i].color, false, PALETTE_SOLID_WRAP, 0), SEGENV.aux0)); + SEGMENT.setPixelColor(ripples[i].pos, SEGMENT.color_from_palette(ripples[i].color, false, PALETTE_SOLID_WRAP, 0)); ripples[i].state++; break; - case maxsteps: // At the end of the ripples. 254 is an inactive mode. + case MAXSTEPS: // At the end of the ripples. 254 is an inactive mode. ripples[i].state = 254; break; default: // Middle of the ripples. - SEGMENT.setPixelColor((ripples[i].pos + ripples[i].state + SEGLEN) % SEGLEN, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(ripples[i].color, false, PALETTE_SOLID_WRAP, 0), SEGENV.aux0/ripples[i].state*2)); - SEGMENT.setPixelColor((ripples[i].pos - ripples[i].state + SEGLEN) % SEGLEN, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(ripples[i].color, false, PALETTE_SOLID_WRAP, 0), SEGENV.aux0/ripples[i].state*2)); + SEGMENT.setPixelColor((ripples[i].pos + ripples[i].state + SEGLEN) % SEGLEN, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(ripples[i].color, false, PALETTE_SOLID_WRAP, 0), uint8_t(2*255/ripples[i].state))); + SEGMENT.setPixelColor((ripples[i].pos - ripples[i].state + SEGLEN) % SEGLEN, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(ripples[i].color, false, PALETTE_SOLID_WRAP, 0), uint8_t(2*255/ripples[i].state))); ripples[i].state++; // Next step. break; } // switch step @@ -6504,8 +6502,8 @@ uint16_t mode_gravcenter(void) { // Gravcenter. By Andrew Tuline. for (int i=0; i= gravcen->topLED) @@ -6597,7 +6595,7 @@ uint16_t mode_gravimeter(void) { // Gravmeter. By Andrew Tuline. for (int i=0; i= gravcen->topLED) @@ -6623,7 +6621,7 @@ uint16_t mode_juggles(void) { // Juggles. By Andrew Tuline. float volumeSmth = *(float*) um_data->u_data[0]; SEGMENT.fade_out(224); // 6.25% - unsigned my_sampleAgc = fmax(fmin(volumeSmth, 255.0), 0); + uint8_t my_sampleAgc = fmax(fmin(volumeSmth, 255.0), 0); for (size_t i=0; i SEGLEN/2; i--) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i-1)); //move to the left @@ -6912,7 +6910,7 @@ uint16_t mode_pixels(void) { // Pixels. By Andrew Tuline. for (int i=0; i SPEED_FORMULA_L) { unsigned segLoc = random16(SEGLEN); - SEGMENT.setPixelColor(segLoc, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(2*fftResult[SEGENV.aux0%16]*240/max(1, SEGLEN-1), false, PALETTE_SOLID_WRAP, 0), 2*fftResult[SEGENV.aux0%16])); + SEGMENT.setPixelColor(segLoc, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(2*fftResult[SEGENV.aux0%16]*240/max(1, SEGLEN-1), false, PALETTE_SOLID_WRAP, 0), uint8_t(2*fftResult[SEGENV.aux0%16]))); ++(SEGENV.aux0) %= 16; // make sure it doesn't cross 16 SEGENV.step = 1; - SEGMENT.blur(SEGMENT.intensity); + SEGMENT.blur(SEGMENT.intensity); // note: blur > 210 results in a alternating pattern, this could be fixed by mapping but some may like it (very old bug) } return FRAMETIME; @@ -7013,7 +7011,7 @@ uint16_t mode_freqmap(void) { // Map FFT_MajorPeak to SEGLEN. unsigned pixCol = (log10f(FFT_MajorPeak) - 1.78f) * 255.0f/(MAX_FREQ_LOG10 - 1.78f); // Scale log10 of frequency values to the 255 colour index. if (FFT_MajorPeak < 61.0f) pixCol = 0; // handle underflow - unsigned bright = (int)my_magnitude; + uint8_t bright = (uint8_t)my_magnitude; SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(SEGMENT.intensity+pixCol, false, PALETTE_SOLID_WRAP, 0), bright)); @@ -7100,7 +7098,7 @@ uint16_t mode_freqpixels(void) { // Freqpixel. By Andrew Tuline. if (FFT_MajorPeak < 61.0f) pixCol = 0; // handle underflow for (int i=0; i < SEGMENT.intensity/32+1; i++) { unsigned locn = random16(0,SEGLEN); - SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(SEGMENT.intensity+pixCol, false, PALETTE_SOLID_WRAP, 0), (int)my_magnitude)); + SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(SEGMENT.intensity+pixCol, false, PALETTE_SOLID_WRAP, 0), (uint8_t)my_magnitude)); } return FRAMETIME; @@ -7234,12 +7232,12 @@ uint16_t mode_noisemove(void) { // Noisemove. By: Andrew Tuli unsigned locn = inoise16(strip.now*SEGMENT.speed+i*50000, strip.now*SEGMENT.speed); // Get a new pixel location from moving noise. // if SEGLEN equals 1 locn will be always 0, hence we set the first pixel only locn = map(locn, 7500, 58000, 0, SEGLEN-1); // Map that to the length of the strand, and ensure we don't go over. - SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i*64, false, PALETTE_SOLID_WRAP, 0), fftResult[i % 16]*4)); + SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i*64, false, PALETTE_SOLID_WRAP, 0), uint8_t(fftResult[i % 16]*4))); } return FRAMETIME; } // mode_noisemove() -static const char _data_FX_MODE_NOISEMOVE[] PROGMEM = "Noisemove@Speed of perlin movement,Fade rate;!,!;!;01f;m12=0,si=0"; // Pixels, Beatsin +static const char _data_FX_MODE_NOISEMOVE[] PROGMEM = "Noisemove@Move speed,Fade rate;!,!;!;01f;m12=0,si=0"; // Pixels, Beatsin ////////////////////// @@ -7314,7 +7312,7 @@ uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tulin if (samplePeak) { SEGMENT.setPixelColor(SEGLEN-1, CHSV(92,92,92)); } else { - SEGMENT.setPixelColor(SEGLEN-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(pixCol+SEGMENT.intensity, false, PALETTE_SOLID_WRAP, 0), (int)my_magnitude)); + SEGMENT.setPixelColor(SEGLEN-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(pixCol+SEGMENT.intensity, false, PALETTE_SOLID_WRAP, 0), (uint8_t)my_magnitude)); } // loop will not execute if SEGLEN equals 1 for (int i = 0; i < SEGLEN-1; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // shift left diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 7c1ae366..1d54ef4a 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -182,7 +182,7 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) #ifndef WLED_DISABLE_MODE_BLEND // if blending modes, blend with underlying pixel - if (_modeBlend) tmpCol = color_blend(strip.getPixelColorXY(start + xX, startY + yY), col, 0xFFFFU - progress(), true); + if (_modeBlend) tmpCol = color_blend16(strip.getPixelColorXY(start + xX, startY + yY), col, uint16_t(0xFFFFU - progress())); #endif strip.setPixelColorXY(start + xX, startY + yY, tmpCol); @@ -513,25 +513,25 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, unsigned oldFade = 0; while (x < y) { float yf = sqrtf(float(rsq - x*x)); // needs to be floating point - unsigned fade = float(0xFFFF) * (ceilf(yf) - yf); // how much color to keep + uint16_t fade = float(0xFF) * (ceilf(yf) - yf); // how much color to keep if (oldFade > fade) y--; oldFade = fade; - setPixelColorXY(cx+x, cy+y, color_blend(col, getPixelColorXY(cx+x, cy+y), fade, true)); - setPixelColorXY(cx-x, cy+y, color_blend(col, getPixelColorXY(cx-x, cy+y), fade, true)); - setPixelColorXY(cx+x, cy-y, color_blend(col, getPixelColorXY(cx+x, cy-y), fade, true)); - setPixelColorXY(cx-x, cy-y, color_blend(col, getPixelColorXY(cx-x, cy-y), fade, true)); - setPixelColorXY(cx+y, cy+x, color_blend(col, getPixelColorXY(cx+y, cy+x), fade, true)); - setPixelColorXY(cx-y, cy+x, color_blend(col, getPixelColorXY(cx-y, cy+x), fade, true)); - setPixelColorXY(cx+y, cy-x, color_blend(col, getPixelColorXY(cx+y, cy-x), fade, true)); - setPixelColorXY(cx-y, cy-x, color_blend(col, getPixelColorXY(cx-y, cy-x), fade, true)); - setPixelColorXY(cx+x, cy+y-1, color_blend(getPixelColorXY(cx+x, cy+y-1), col, fade, true)); - setPixelColorXY(cx-x, cy+y-1, color_blend(getPixelColorXY(cx-x, cy+y-1), col, fade, true)); - setPixelColorXY(cx+x, cy-y+1, color_blend(getPixelColorXY(cx+x, cy-y+1), col, fade, true)); - setPixelColorXY(cx-x, cy-y+1, color_blend(getPixelColorXY(cx-x, cy-y+1), col, fade, true)); - setPixelColorXY(cx+y-1, cy+x, color_blend(getPixelColorXY(cx+y-1, cy+x), col, fade, true)); - setPixelColorXY(cx-y+1, cy+x, color_blend(getPixelColorXY(cx-y+1, cy+x), col, fade, true)); - setPixelColorXY(cx+y-1, cy-x, color_blend(getPixelColorXY(cx+y-1, cy-x), col, fade, true)); - setPixelColorXY(cx-y+1, cy-x, color_blend(getPixelColorXY(cx-y+1, cy-x), col, fade, true)); + setPixelColorXY(cx+x, cy+y, color_blend(col, getPixelColorXY(cx+x, cy+y), fade)); + setPixelColorXY(cx-x, cy+y, color_blend(col, getPixelColorXY(cx-x, cy+y), fade)); + setPixelColorXY(cx+x, cy-y, color_blend(col, getPixelColorXY(cx+x, cy-y), fade)); + setPixelColorXY(cx-x, cy-y, color_blend(col, getPixelColorXY(cx-x, cy-y), fade)); + setPixelColorXY(cx+y, cy+x, color_blend(col, getPixelColorXY(cx+y, cy+x), fade)); + setPixelColorXY(cx-y, cy+x, color_blend(col, getPixelColorXY(cx-y, cy+x), fade)); + setPixelColorXY(cx+y, cy-x, color_blend(col, getPixelColorXY(cx+y, cy-x), fade)); + setPixelColorXY(cx-y, cy-x, color_blend(col, getPixelColorXY(cx-y, cy-x), fade)); + setPixelColorXY(cx+x, cy+y-1, color_blend(getPixelColorXY(cx+x, cy+y-1), col, fade)); + setPixelColorXY(cx-x, cy+y-1, color_blend(getPixelColorXY(cx-x, cy+y-1), col, fade)); + setPixelColorXY(cx+x, cy-y+1, color_blend(getPixelColorXY(cx+x, cy-y+1), col, fade)); + setPixelColorXY(cx-x, cy-y+1, color_blend(getPixelColorXY(cx-x, cy-y+1), col, fade)); + setPixelColorXY(cx+y-1, cy+x, color_blend(getPixelColorXY(cx+y-1, cy+x), col, fade)); + setPixelColorXY(cx-y+1, cy+x, color_blend(getPixelColorXY(cx-y+1, cy+x), col, fade)); + setPixelColorXY(cx+y-1, cy-x, color_blend(getPixelColorXY(cx+y-1, cy-x), col, fade)); + setPixelColorXY(cx-y+1, cy-x, color_blend(getPixelColorXY(cx-y+1, cy-x), col, fade)); x++; } } else { @@ -608,13 +608,13 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3 float gradient = x1-x0 == 0 ? 1.0f : float(y1-y0) / float(x1-x0); float intersectY = y0; for (int x = x0; x <= x1; x++) { - unsigned keep = float(0xFFFF) * (intersectY-int(intersectY)); // how much color to keep - unsigned seep = 0xFFFF - keep; // how much background to keep + uint8_t keep = float(0xFF) * (intersectY-int(intersectY)); // how much color to keep + uint8_t seep = 0xFF - keep; // how much background to keep int y = int(intersectY); if (steep) std::swap(x,y); // temporaryly swap if steep // pixel coverage is determined by fractional part of y co-ordinate - setPixelColorXY(x, y, color_blend(c, getPixelColorXY(x, y), keep, true)); - setPixelColorXY(x+int(steep), y+int(!steep), color_blend(c, getPixelColorXY(x+int(steep), y+int(!steep)), seep, true)); + setPixelColorXY(x, y, color_blend(c, getPixelColorXY(x, y), keep)); + setPixelColorXY(x+int(steep), y+int(!steep), color_blend(c, getPixelColorXY(x+int(steep), y+int(!steep)), seep)); intersectY += gradient; if (steep) std::swap(x,y); // restore if steep } diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 88fec3d8..ac9de8d7 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -406,9 +406,9 @@ uint8_t Segment::currentMode() const { uint32_t IRAM_ATTR_YN 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]; + return isInTransition() ? color_blend16(_t->_segT._colorT[slot], colors[slot], progress()) : colors[slot]; #else - return isInTransition() ? color_blend(_t->_colorT[slot], colors[slot], progress(), true) : colors[slot]; + return isInTransition() ? color_blend16(_t->_colorT[slot], colors[slot], progress()) : colors[slot]; #endif } @@ -819,14 +819,14 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) indexMir += offset; // offset/phase if (indexMir >= stop) indexMir -= len; // wrap #ifndef WLED_DISABLE_MODE_BLEND - if (_modeBlend) tmpCol = color_blend(strip.getPixelColor(indexMir), col, 0xFFFFU - progress(), true); + if (_modeBlend) tmpCol = color_blend16(strip.getPixelColor(indexMir), col, uint16_t(0xFFFFU - progress())); #endif strip.setPixelColor(indexMir, tmpCol); } indexSet += offset; // offset/phase if (indexSet >= stop) indexSet -= len; // wrap #ifndef WLED_DISABLE_MODE_BLEND - if (_modeBlend) tmpCol = color_blend(strip.getPixelColor(indexSet), col, 0xFFFFU - progress(), true); + if (_modeBlend) tmpCol = color_blend16(strip.getPixelColor(indexSet), col, uint16_t(0xFFFFU - progress())); #endif strip.setPixelColor(indexSet, tmpCol); } @@ -1083,6 +1083,7 @@ void Segment::fadeToBlackBy(uint8_t fadeBy) { /* * blurs segment content, source: FastLED colorutils.cpp + * Note: for blur_amount > 215 this function does not work properly (creates alternating pattern) */ void Segment::blur(uint8_t blur_amount, bool smear) { if (!isActive() || blur_amount == 0) return; // optimization: 0 means "don't blur" diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 478a0a27..8393d9b8 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -5,30 +5,18 @@ */ /* - * color blend function + * color blend function, based on FastLED blend function + * the calculation for each color is: result = (A*(amountOfA) + A + B*(amountOfB) + B) / 256 with amountOfA = 255 - amountOfB */ -uint32_t color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) { - if (blend == 0) return color1; - unsigned blendmax = b16 ? 0xFFFF : 0xFF; - if (blend == blendmax) return color2; - unsigned shift = b16 ? 16 : 8; - - uint32_t w1 = W(color1); - uint32_t r1 = R(color1); - uint32_t g1 = G(color1); - uint32_t b1 = B(color1); - - uint32_t w2 = W(color2); - uint32_t r2 = R(color2); - uint32_t g2 = G(color2); - uint32_t b2 = B(color2); - - uint32_t w3 = ((w2 * blend) + (w1 * (blendmax - blend))) >> shift; - uint32_t r3 = ((r2 * blend) + (r1 * (blendmax - blend))) >> shift; - uint32_t g3 = ((g2 * blend) + (g1 * (blendmax - blend))) >> shift; - uint32_t b3 = ((b2 * blend) + (b1 * (blendmax - blend))) >> shift; - - return RGBW32(r3, g3, b3, w3); +uint32_t color_blend(uint32_t color1, uint32_t color2, uint8_t blend) { + // min / max blend checking is omitted: calls with 0 or 255 are rare, checking lowers overall performance + uint32_t rb1 = color1 & 0x00FF00FF; + uint32_t wg1 = (color1>>8) & 0x00FF00FF; + uint32_t rb2 = color2 & 0x00FF00FF; + uint32_t wg2 = (color2>>8) & 0x00FF00FF; + uint32_t rb3 = ((((rb1 << 8) | rb2) + (rb2 * blend) - (rb1 * blend)) >> 8) & 0x00FF00FF; + uint32_t wg3 = ((((wg1 << 8) | wg2) + (wg2 * blend) - (wg1 * blend))) & 0xFF00FF00; + return rb3 | wg3; } /* diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 3d8c27ac..de5975da 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -78,7 +78,8 @@ class NeoGammaWLEDMethod { }; #define gamma32(c) NeoGammaWLEDMethod::Correct32(c) #define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c) -[[gnu::hot]] uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false); +[[gnu::hot]] uint32_t color_blend(uint32_t c1, uint32_t c2 , uint8_t blend); +inline uint32_t color_blend16(uint32_t c1, uint32_t c2, uint16_t b) { return color_blend(c1, c2, b >> 8); }; [[gnu::hot]] uint32_t color_add(uint32_t,uint32_t, bool fast=false); [[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette); From 83da7569f5c82cbabdeff7b1c8a8945afb64abd7 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 19 Dec 2024 20:19:42 +0100 Subject: [PATCH 087/463] code consolidation in drawCircle() (#4302) - saves about 600bytes of flash - speed tradoff: drawing is now a tiny bit slower but insignificant in my tests --- wled00/FX_2Dfcn.cpp | 52 ++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 1d54ef4a..0ba70adb 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -507,31 +507,33 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, if (!isActive() || radius == 0) return; // not active if (soft) { // Xiaolin Wu’s algorithm - int rsq = radius*radius; + const int rsq = radius*radius; int x = 0; int y = radius; unsigned oldFade = 0; while (x < y) { float yf = sqrtf(float(rsq - x*x)); // needs to be floating point - uint16_t fade = float(0xFF) * (ceilf(yf) - yf); // how much color to keep + uint8_t fade = float(0xFF) * (ceilf(yf) - yf); // how much color to keep if (oldFade > fade) y--; oldFade = fade; - setPixelColorXY(cx+x, cy+y, color_blend(col, getPixelColorXY(cx+x, cy+y), fade)); - setPixelColorXY(cx-x, cy+y, color_blend(col, getPixelColorXY(cx-x, cy+y), fade)); - setPixelColorXY(cx+x, cy-y, color_blend(col, getPixelColorXY(cx+x, cy-y), fade)); - setPixelColorXY(cx-x, cy-y, color_blend(col, getPixelColorXY(cx-x, cy-y), fade)); - setPixelColorXY(cx+y, cy+x, color_blend(col, getPixelColorXY(cx+y, cy+x), fade)); - setPixelColorXY(cx-y, cy+x, color_blend(col, getPixelColorXY(cx-y, cy+x), fade)); - setPixelColorXY(cx+y, cy-x, color_blend(col, getPixelColorXY(cx+y, cy-x), fade)); - setPixelColorXY(cx-y, cy-x, color_blend(col, getPixelColorXY(cx-y, cy-x), fade)); - setPixelColorXY(cx+x, cy+y-1, color_blend(getPixelColorXY(cx+x, cy+y-1), col, fade)); - setPixelColorXY(cx-x, cy+y-1, color_blend(getPixelColorXY(cx-x, cy+y-1), col, fade)); - setPixelColorXY(cx+x, cy-y+1, color_blend(getPixelColorXY(cx+x, cy-y+1), col, fade)); - setPixelColorXY(cx-x, cy-y+1, color_blend(getPixelColorXY(cx-x, cy-y+1), col, fade)); - setPixelColorXY(cx+y-1, cy+x, color_blend(getPixelColorXY(cx+y-1, cy+x), col, fade)); - setPixelColorXY(cx-y+1, cy+x, color_blend(getPixelColorXY(cx-y+1, cy+x), col, fade)); - setPixelColorXY(cx+y-1, cy-x, color_blend(getPixelColorXY(cx+y-1, cy-x), col, fade)); - setPixelColorXY(cx-y+1, cy-x, color_blend(getPixelColorXY(cx-y+1, cy-x), col, fade)); + int px, py; + for (uint8_t i = 0; i < 16; i++) { + int swaps = (i & 0x4 ? 1 : 0); // 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1 + int adj = (i < 8) ? 0 : 1; // 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 + int dx = (i & 1) ? -1 : 1; // 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1 + int dy = (i & 2) ? -1 : 1; // 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1 + if (swaps) { + px = cx + (y - adj) * dx; + py = cy + x * dy; + } else { + px = cx + x * dx; + py = cy + (y - adj) * dy; + } + uint32_t pixCol = getPixelColorXY(px, py); + setPixelColorXY(px, py, adj ? + color_blend(pixCol, col, fade) : + color_blend(col, pixCol, fade)); + } x++; } } else { @@ -539,14 +541,12 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, int d = 3 - (2*radius); int y = radius, x = 0; while (y >= x) { - setPixelColorXY(cx+x, cy+y, col); - setPixelColorXY(cx-x, cy+y, col); - setPixelColorXY(cx+x, cy-y, col); - setPixelColorXY(cx-x, cy-y, col); - setPixelColorXY(cx+y, cy+x, col); - setPixelColorXY(cx-y, cy+x, col); - setPixelColorXY(cx+y, cy-x, col); - setPixelColorXY(cx-y, cy-x, col); + for (int i = 0; i < 4; i++) { + int dx = (i & 1) ? -x : x; + int dy = (i & 2) ? -y : y; + setPixelColorXY(cx + dx, cy + dy, col); + setPixelColorXY(cx + dy, cy + dx, col); + } x++; if (d > 0) { y--; From 7b9b3f1ee2b895d266c089629b4e02a8772c88df Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Fri, 20 Dec 2024 09:12:20 +0100 Subject: [PATCH 088/463] merge fix --- wled00/FX_fcn.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index b3f765af..d1a6e30b 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -426,9 +426,9 @@ void Segment::beginDraw() { // adjust gamma for effects for (unsigned i = 0; i < NUM_COLORS; i++) { #ifndef WLED_DISABLE_MODE_BLEND - uint32_t col = isInTransition() ? color_blend(_t->_segT._colorT[i], colors[i], progress(), true) : colors[i]; + uint32_t col = isInTransition() ? color_blend16(_t->_segT._colorT[i], colors[i], progress()) : colors[i]; #else - uint32_t col = isInTransition() ? color_blend(_t->_colorT[i], colors[i], progress(), true) : colors[i]; + uint32_t col = isInTransition() ? color_blend16(_t->_colorT[i], colors[i], progress()) : colors[i]; #endif _currentColors[i] = gamma32(col); } From 3323d2ed375483dd4236ba4c8a49e2f4f6f7112f Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Fri, 20 Dec 2024 09:37:41 +0100 Subject: [PATCH 089/463] another merge fix --- wled00/FX_fcn.cpp | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index d1a6e30b..74e315d4 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1454,23 +1454,6 @@ void WS2812FX::show() { } } -/** - * Returns a true value if any of the strips are still being updated. - * On some hardware (ESP32), strip updates are done asynchronously. - */ -bool WS2812FX::isUpdating() const { - return !BusManager::canAllShow(); -} - -/** - * Returns the refresh rate of the LED strip. Useful for finding out whether a given setup is fast enough. - * Only updates on show() or is set to 0 fps if last show is more than 2 secs ago, so accuracy varies - */ -uint16_t WS2812FX::getFps() const { - if (millis() - _lastShow > 2000) return 0; - return (FPS_MULTIPLIER * _cumulativeFps) >> FPS_CALC_SHIFT; // _cumulativeFps is stored in fixed point -} - void WS2812FX::setTargetFps(unsigned fps) { if (fps <= 250) _targetFps = fps; if (_targetFps > 0) _frametime = 1000 / _targetFps; From 07cc3aa5c074c1e3f87bd3e704e5cd9b2077843b Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Fri, 20 Dec 2024 14:13:53 +0100 Subject: [PATCH 090/463] FX improvements and cleanup (#4145) Improvements & merges of FX - Scrolling Text: Gradient Palette support added - Waving Cell: Improved with higher temporal resolution (smoother at lower speeds) and added additional mode setting and optional blurring - Julia: added blur option - Squared Swirl: added fade option - Added smearing option to: - DNA - DNA Spiral - Drift - Drift Rose - Crazy Bees - Ripple - Colored Bursts - Frizzles - Lissajous - Sindots - Spaceships - Added palette support to: - Crazy Bees - Polar Lights - Drift Rose - Changed default palette handling (no more special treatment for some FX) - Merged puddles and puddlepeak - Merged Gravcenter, Gravcentric, Gravfreq and Gravimeter (saves 1.2k of flash) - Merged meteor and meteor smooth - Renamed police_base into mode_two_dots as that was just an alias - Added 'Traffic Light' palette (originally defined in Polar Lights FX) - Firenoise: removed local palette, use fire palette -> slight change in looks (+bugfix) - Some code cleanup (removed unused / commented stuff) - Moved dev info for AR to the top so ist easier to find as a reference, also added link to KB there --- wled00/FX.cpp | 735 ++++++++++++++++++-------------------------- wled00/FX.h | 12 +- wled00/FX_2Dfcn.cpp | 7 +- wled00/FX_fcn.cpp | 23 +- wled00/const.h | 2 +- wled00/ir.cpp | 2 +- wled00/palettes.h | 10 +- 7 files changed, 335 insertions(+), 456 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 3805d38f..b6d26532 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -14,14 +14,56 @@ #include "FX.h" #include "fcn_declare.h" -#define IBN 5100 + ////////////// + // DEV INFO // + ////////////// +/* + information for FX metadata strings: https://kno.wled.ge/interfaces/json-api/#effect-metadata + + Audio Reactive: use the following code to pass usermod variables to effect + + uint8_t *binNum = (uint8_t*)&SEGENV.aux1, *maxVol = (uint8_t*)(&SEGENV.aux1+1); // just in case assignment + bool samplePeak = false; + float FFT_MajorPeak = 1.0; + uint8_t *fftResult = nullptr; + float *fftBin = nullptr; + um_data_t *um_data; + if (usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { + volumeSmth = *(float*) um_data->u_data[0]; + volumeRaw = *(float*) um_data->u_data[1]; + fftResult = (uint8_t*) um_data->u_data[2]; + samplePeak = *(uint8_t*) um_data->u_data[3]; + FFT_MajorPeak = *(float*) um_data->u_data[4]; + my_magnitude = *(float*) um_data->u_data[5]; + maxVol = (uint8_t*) um_data->u_data[6]; // requires UI element (SEGMENT.customX?), changes source element + binNum = (uint8_t*) um_data->u_data[7]; // requires UI element (SEGMENT.customX?), changes source element + fftBin = (float*) um_data->u_data[8]; + } else { + // add support for no audio data + um_data = simulateSound(SEGMENT.soundSim); + } +*/ + + +#define IBN 5100 // paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined) #define PALETTE_SOLID_WRAP (strip.paletteBlend == 1 || strip.paletteBlend == 3) #define PALETTE_MOVING_WRAP !(strip.paletteBlend == 2 || (strip.paletteBlend == 0 && SEGMENT.speed == 0)) #define indexToVStrip(index, stripNr) ((index) | (int((stripNr)+1)<<16)) +// a few constants needed for AudioReactive effects +// for 22Khz sampling +#define MAX_FREQUENCY 11025 // sample frequency / 2 (as per Nyquist criterion) +#define MAX_FREQ_LOG10 4.04238f // log10(MAX_FREQUENCY) +// for 20Khz sampling +//#define MAX_FREQUENCY 10240 +//#define MAX_FREQ_LOG10 4.0103f +// for 10Khz sampling +//#define MAX_FREQUENCY 5120 +//#define MAX_FREQ_LOG10 3.71f + // effect utility functions uint8_t sin_gap(uint16_t in) { if (in & 0x100) return 0; @@ -1361,16 +1403,19 @@ uint16_t mode_loading(void) { } static const char _data_FX_MODE_LOADING[] PROGMEM = "Loading@!,Fade;!,!;!;;ix=16"; - -//American Police Light with all LEDs Red and Blue -uint16_t police_base(uint32_t color1, uint32_t color2) { - if (SEGLEN == 1) return mode_static(); +/* + * Two dots running + */ +uint16_t mode_two_dots() { + if (SEGLEN == 1) return mode_static(); unsigned delay = 1 + (FRAMETIME<<3) / SEGLEN; // longer segments should change faster uint32_t it = strip.now / map(SEGMENT.speed, 0, 255, delay<<4, delay); unsigned offset = it % SEGLEN; - unsigned width = ((SEGLEN*(SEGMENT.intensity+1))>>9); //max width is half the strip if (!width) width = 1; + if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(2)); + const uint32_t color1 = SEGCOLOR(0); + const uint32_t color2 = (SEGCOLOR(1) == SEGCOLOR(2)) ? color1 : SEGCOLOR(1); for (unsigned i = 0; i < width; i++) { unsigned indexR = (offset + i) % SEGLEN; unsigned indexB = (offset + i + (SEGLEN>>1)) % SEGLEN; @@ -1379,23 +1424,6 @@ uint16_t police_base(uint32_t color1, uint32_t color2) { } return FRAMETIME; } - - -//Police Lights Red and Blue -//uint16_t mode_police() -//{ -// SEGMENT.fill(SEGCOLOR(1)); -// return police_base(RED, BLUE); -//} -//static const char _data_FX_MODE_POLICE[] PROGMEM = "Police@!,Width;,Bg;0"; - - -//Police Lights with custom colors -uint16_t mode_two_dots() { - if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(2)); - uint32_t color2 = (SEGCOLOR(1) == SEGCOLOR(2)) ? SEGCOLOR(0) : SEGCOLOR(1); - return police_base(SEGCOLOR(0), color2); -} static const char _data_FX_MODE_TWO_DOTS[] PROGMEM = "Two Dots@!,Dot size,,,,,Overlay;1,2,Bg;!"; @@ -2117,7 +2145,7 @@ uint16_t mode_fire_2012() { return FRAMETIME; } -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 +static const char _data_FX_MODE_FIRE_2012[] PROGMEM = "Fire 2012@Cooling,Spark rate,,2D Blur,Boost;;!;1;pal=35,sx=64,ix=160,m12=1,c2=128"; // bars // ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb @@ -2163,7 +2191,7 @@ uint16_t mode_colorwaves() { return FRAMETIME; } -static const char _data_FX_MODE_COLORWAVES[] PROGMEM = "Colorwaves@!,Hue;!;!"; +static const char _data_FX_MODE_COLORWAVES[] PROGMEM = "Colorwaves@!,Hue;!;!;;pal=26"; // colored stripes pulsing at a defined Beats-Per-Minute (BPM) @@ -2210,7 +2238,7 @@ uint16_t mode_noise16_1() { return FRAMETIME; } -static const char _data_FX_MODE_NOISE16_1[] PROGMEM = "Noise 1@!;!;!"; +static const char _data_FX_MODE_NOISE16_1[] PROGMEM = "Noise 1@!;!;!;;pal=20"; uint16_t mode_noise16_2() { @@ -2228,7 +2256,7 @@ uint16_t mode_noise16_2() { return FRAMETIME; } -static const char _data_FX_MODE_NOISE16_2[] PROGMEM = "Noise 2@!;!;!"; +static const char _data_FX_MODE_NOISE16_2[] PROGMEM = "Noise 2@!;!;!;;pal=43"; uint16_t mode_noise16_3() { @@ -2249,7 +2277,7 @@ uint16_t mode_noise16_3() { return FRAMETIME; } -static const char _data_FX_MODE_NOISE16_3[] PROGMEM = "Noise 3@!;!;!"; +static const char _data_FX_MODE_NOISE16_3[] PROGMEM = "Noise 3@!;!;!;;pal=35"; //https://github.com/aykevl/ledstrip-spark/blob/master/ledstrip.ino @@ -2261,7 +2289,7 @@ uint16_t mode_noise16_4() { } return FRAMETIME; } -static const char _data_FX_MODE_NOISE16_4[] PROGMEM = "Noise 4@!;!;!"; +static const char _data_FX_MODE_NOISE16_4[] PROGMEM = "Noise 4@!;!;!;;pal=26"; //based on https://gist.github.com/kriegsman/5408ecd397744ba0393e @@ -2337,90 +2365,73 @@ uint16_t mode_lake() { static const char _data_FX_MODE_LAKE[] PROGMEM = "Lake@!;Fx;!"; -// meteor effect +// meteor effect & meteor smooth (merged by @dedehai) // send a meteor from begining to to the end of the strip with a trail that randomly decays. // adapted from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectMeteorRain uint16_t mode_meteor() { if (SEGLEN == 1) return mode_static(); if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed - + const bool meteorSmooth = SEGMENT.check3; byte* trail = SEGENV.data; const unsigned meteorSize = 1 + SEGLEN / 20; // 5% - unsigned counter = strip.now * ((SEGMENT.speed >> 2) +8); - uint16_t in = counter * SEGLEN >> 16; - - const int max = SEGMENT.palette==5 ? 239 : 255; // "* Colors only" palette blends end with start - // fade all leds to colors[1] in LEDs one step - for (unsigned i = 0; i < SEGLEN; i++) { - if (random8() <= 255 - SEGMENT.intensity) { - int meteorTrailDecay = 128 + random8(127); - trail[i] = scale8(trail[i], meteorTrailDecay); - int index = trail[i]; - int idx = 255; - int bri = SEGMENT.palette==35 || SEGMENT.palette==36 ? 255 : trail[i]; - if (!SEGMENT.check1) { - idx = 0; - index = map(i,0,SEGLEN,0,max); - bri = trail[i]; - } - SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, false, idx, bri)); // full brightness for Fire - } + uint16_t meteorstart; + if(meteorSmooth) meteorstart = map((SEGENV.step >> 6 & 0xFF), 0, 255, 0, SEGLEN -1); + else { + unsigned counter = strip.now * ((SEGMENT.speed >> 2) + 8); + meteorstart = (counter * SEGLEN) >> 16; } - // draw meteor - for (unsigned j = 0; j < meteorSize; j++) { - int index = (in + j) % SEGLEN; - int idx = 255; - int i = trail[index] = max; - if (!SEGMENT.check1) { - i = map(index,0,SEGLEN,0,max); - idx = 0; - } - SEGMENT.setPixelColor(index, SEGMENT.color_from_palette(i, false, false, idx, 255)); // full brightness - } - - return FRAMETIME; -} -static const char _data_FX_MODE_METEOR[] PROGMEM = "Meteor@!,Trail,,,,Gradient;!;!;1"; - - -// smooth meteor effect -// send a meteor from begining to to the end of the strip with a trail that randomly decays. -// adapted from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectMeteorRain -uint16_t mode_meteor_smooth() { - if (SEGLEN == 1) return mode_static(); - if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed - - byte* trail = SEGENV.data; - - const unsigned meteorSize = 1+ SEGLEN / 20; // 5% - uint16_t in = map((SEGENV.step >> 6 & 0xFF), 0, 255, 0, SEGLEN -1); - const int max = SEGMENT.palette==5 || !SEGMENT.check1 ? 240 : 255; // fade all leds to colors[1] in LEDs one step for (unsigned i = 0; i < SEGLEN; i++) { - if (/*trail[i] != 0 &&*/ random8() <= 255 - SEGMENT.intensity) { - int change = trail[i] + 4 - random8(24); //change each time between -20 and +4 - trail[i] = constrain(change, 0, max); - SEGMENT.setPixelColor(i, SEGMENT.check1 ? SEGMENT.color_from_palette(i, true, false, 0, trail[i]) : SEGMENT.color_from_palette(trail[i], false, true, 255)); + uint32_t col; + if (random8() <= 255 - SEGMENT.intensity) { + if(meteorSmooth) { + int change = trail[i] + 4 - random8(24); //change each time between -20 and +4 + trail[i] = constrain(change, 0, max); + col = SEGMENT.check1 ? SEGMENT.color_from_palette(i, true, false, 0, trail[i]) : SEGMENT.color_from_palette(trail[i], false, true, 255); + } + else { + trail[i] = scale8(trail[i], 128 + random8(127)); + int index = trail[i]; + int idx = 255; + int bri = SEGMENT.palette==35 || SEGMENT.palette==36 ? 255 : trail[i]; + if (!SEGMENT.check1) { + idx = 0; + index = map(i,0,SEGLEN,0,max); + bri = trail[i]; + } + col = SEGMENT.color_from_palette(index, false, false, idx, bri); // full brightness for Fire + } + SEGMENT.setPixelColor(i, col); } } // draw meteor for (unsigned j = 0; j < meteorSize; j++) { - unsigned index = in + j; - if (index >= SEGLEN) { - index -= SEGLEN; + unsigned index = (meteorstart + j) % SEGLEN; + if(meteorSmooth) { + trail[index] = max; + uint32_t col = SEGMENT.check1 ? SEGMENT.color_from_palette(index, true, false, 0, trail[index]) : SEGMENT.color_from_palette(trail[index], false, true, 255); + SEGMENT.setPixelColor(index, col); + } + else{ + int idx = 255; + int i = trail[index] = max; + if (!SEGMENT.check1) { + i = map(index,0,SEGLEN,0,max); + idx = 0; + } + uint32_t col = SEGMENT.color_from_palette(i, false, false, idx, 255); // full brightness + SEGMENT.setPixelColor(index, col); } - trail[index] = max; - SEGMENT.setPixelColor(index, SEGMENT.check1 ? SEGMENT.color_from_palette(index, true, false, 0, trail[index]) : SEGMENT.color_from_palette(trail[index], false, true, 255)); } SEGENV.step += SEGMENT.speed +1; return FRAMETIME; } -static const char _data_FX_MODE_METEOR_SMOOTH[] PROGMEM = "Meteor Smooth@!,Trail,,,,Gradient;;!;1"; +static const char _data_FX_MODE_METEOR[] PROGMEM = "Meteor@!,Trail,,,,Gradient,,Smooth;;!;1"; //Railway Crossing / Christmas Fairy lights @@ -2452,7 +2463,7 @@ uint16_t mode_railway() { SEGENV.step += FRAMETIME; return FRAMETIME; } -static const char _data_FX_MODE_RAILWAY[] PROGMEM = "Railway@!,Smoothness;1,2;!"; +static const char _data_FX_MODE_RAILWAY[] PROGMEM = "Railway@!,Smoothness;1,2;!;;pal=3"; //Water ripple @@ -2471,7 +2482,7 @@ typedef struct Ripple { #else #define MAX_RIPPLES 100 #endif -static uint16_t ripple_base() { +static uint16_t ripple_base(uint8_t blurAmount = 0) { unsigned maxRipples = min(1 + (int)(SEGLEN >> 2), MAX_RIPPLES); // 56 max for 16 segment ESP8266 unsigned dataSize = sizeof(ripple) * maxRipples; @@ -2519,7 +2530,7 @@ static uint16_t ripple_base() { } } } - + SEGMENT.blur(blurAmount); return FRAMETIME; } #undef MAX_RIPPLES @@ -2527,11 +2538,14 @@ static uint16_t ripple_base() { uint16_t mode_ripple(void) { if (SEGLEN == 1) return mode_static(); - if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); - else SEGMENT.fade_out(250); - return ripple_base(); + if(SEGMENT.custom1 || SEGMENT.check2) // blur or overlay + SEGMENT.fade_out(250); + else + SEGMENT.fill(SEGCOLOR(1)); + + return ripple_base(SEGMENT.custom1>>1); } -static const char _data_FX_MODE_RIPPLE[] PROGMEM = "Ripple@!,Wave #,,,,,Overlay;,!;!;12"; +static const char _data_FX_MODE_RIPPLE[] PROGMEM = "Ripple@!,Wave #,Blur,,,,Overlay;,!;!;12;c1=0"; uint16_t mode_ripple_rainbow(void) { @@ -3209,7 +3223,7 @@ uint16_t mode_glitter() glitter_base(SEGMENT.intensity, SEGCOLOR(2) ? SEGCOLOR(2) : ULTRAWHITE); return FRAMETIME; } -static const char _data_FX_MODE_GLITTER[] PROGMEM = "Glitter@!,!,,,,,Overlay;,,Glitter color;!;;pal=0,m12=0"; //pixels +static const char _data_FX_MODE_GLITTER[] PROGMEM = "Glitter@!,!,,,,,Overlay;,,Glitter color;!;;pal=11,m12=0"; //pixels //Solid colour background with glitter (can be replaced by Glitter) @@ -4116,7 +4130,7 @@ uint16_t mode_sunrise() { return FRAMETIME; } -static const char _data_FX_MODE_SUNRISE[] PROGMEM = "Sunrise@Time [min],Width;;!;;sx=60"; +static const char _data_FX_MODE_SUNRISE[] PROGMEM = "Sunrise@Time [min],Width;;!;;pal=35,sx=60"; /* @@ -4903,7 +4917,7 @@ uint16_t mode_2DColoredBursts() { // By: ldirko https://editor.so byte numLines = SEGMENT.intensity/16 + 1; SEGENV.aux0++; // hue - SEGMENT.fadeToBlackBy(40); + SEGMENT.fadeToBlackBy(40 - SEGMENT.check2 * 8); for (size_t i = 0; i < numLines; i++) { byte x1 = beatsin8_t(2 + SEGMENT.speed/16, 0, (cols - 1)); byte x2 = beatsin8_t(1 + SEGMENT.speed/16, 0, (rows - 1)); @@ -4929,11 +4943,11 @@ uint16_t mode_2DColoredBursts() { // By: ldirko https://editor.so SEGMENT.setPixelColorXY(y1, y2, DARKSLATEGRAY); } } - if (SEGMENT.custom3) SEGMENT.blur(SEGMENT.custom3/2); + SEGMENT.blur(SEGMENT.custom3>>1, SEGMENT.check2); return FRAMETIME; } // mode_2DColoredBursts() -static const char _data_FX_MODE_2DCOLOREDBURSTS[] PROGMEM = "Colored Bursts@Speed,# of lines,,,Blur,Gradient,,Dots;;!;2;c3=16"; +static const char _data_FX_MODE_2DCOLOREDBURSTS[] PROGMEM = "Colored Bursts@Speed,# of lines,,,Blur,Gradient,Smear,Dots;;!;2;c3=16"; ///////////////////// @@ -4950,12 +4964,11 @@ uint16_t mode_2Ddna(void) { // dna originally by by ldirko at https://pa SEGMENT.setPixelColorXY(i, beatsin8_t(SEGMENT.speed/8, 0, rows-1, 0, i*4 ), ColorFromPalette(SEGPALETTE, i*5+strip.now/17, beatsin8_t(5, 55, 255, 0, i*10), LINEARBLEND)); SEGMENT.setPixelColorXY(i, beatsin8_t(SEGMENT.speed/8, 0, rows-1, 0, i*4+128), ColorFromPalette(SEGPALETTE, i*5+128+strip.now/17, beatsin8_t(5, 55, 255, 0, i*10+128), LINEARBLEND)); } - SEGMENT.blur(SEGMENT.intensity>>3); + SEGMENT.blur(SEGMENT.intensity / (8 - (SEGMENT.check1 * 2)), SEGMENT.check1); return FRAMETIME; } // mode_2Ddna() -static const char _data_FX_MODE_2DDNA[] PROGMEM = "DNA@Scroll speed,Blur;;!;2"; - +static const char _data_FX_MODE_2DDNA[] PROGMEM = "DNA@Scroll speed,Blur,,,,Smear;;!;2;ix=0"; ///////////////////////// // 2D DNA Spiral // @@ -4998,10 +5011,11 @@ uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulma SEGMENT.setPixelColorXY(x1, i, WHITE); } } + SEGMENT.blur(((uint16_t)SEGMENT.custom1 * 3) / (6 + SEGMENT.check1), SEGMENT.check1); return FRAMETIME; } // mode_2DDNASpiral() -static const char _data_FX_MODE_2DDNASPIRAL[] PROGMEM = "DNA Spiral@Scroll speed,Y frequency;;!;2"; +static const char _data_FX_MODE_2DDNASPIRAL[] PROGMEM = "DNA Spiral@Scroll speed,Y frequency,Blur,,,Smear;;!;2;c1=0"; ///////////////////////// @@ -5027,11 +5041,11 @@ uint16_t mode_2DDrift() { // By: Stepko https://editor.soulmateli SEGMENT.setPixelColorXY(colsCenter + mySin, rowsCenter + myCos, ColorFromPalette(SEGPALETTE, (i * 20) + t_20, 255, LINEARBLEND)); if (SEGMENT.check1) SEGMENT.setPixelColorXY(colsCenter + myCos, rowsCenter + mySin, ColorFromPalette(SEGPALETTE, (i * 20) + t_20, 255, LINEARBLEND)); } - SEGMENT.blur(SEGMENT.intensity>>3); + SEGMENT.blur(SEGMENT.intensity>>(3 - SEGMENT.check2), SEGMENT.check2); return FRAMETIME; } // mode_2DDrift() -static const char _data_FX_MODE_2DDRIFT[] PROGMEM = "Drift@Rotation speed,Blur amount,,,,Twin;;!;2"; +static const char _data_FX_MODE_2DDRIFT[] PROGMEM = "Drift@Rotation speed,Blur,,,,Twin,Smear;;!;2;ix=0"; ////////////////////////// @@ -5051,15 +5065,11 @@ uint16_t mode_2Dfirenoise(void) { // firenoise2d. By Andrew Tuline unsigned yscale = SEGMENT.speed*8; unsigned indexx = 0; - CRGBPalette16 pal = SEGMENT.check1 ? SEGPALETTE : CRGBPalette16(CRGB::Black, CRGB::Black, CRGB::Black, CRGB::Black, - CRGB::Red, CRGB::Red, CRGB::Red, CRGB::DarkOrange, - CRGB::DarkOrange,CRGB::DarkOrange, CRGB::Orange, CRGB::Orange, - CRGB::Yellow, CRGB::Orange, CRGB::Yellow, CRGB::Yellow); - + CRGBPalette16 pal = SEGMENT.check1 ? SEGPALETTE : SEGMENT.loadPalette(pal, 35); for (int j=0; j < cols; j++) { for (int i=0; i < rows; i++) { indexx = inoise8(j*yscale*rows/255, i*xscale+strip.now/4); // We're moving along our Perlin map. - SEGMENT.setPixelColorXY(j, i, ColorFromPalette(pal, min(i*(indexx)>>4, 255U), i*255/cols, LINEARBLEND)); // With that value, look up the 8 bit colour palette value and assign it to the current LED. + SEGMENT.setPixelColorXY(j, i, ColorFromPalette(pal, min(i*indexx/11, 225U), i*255/rows, LINEARBLEND)); // With that value, look up the 8 bit colour palette value and assign it to the current LED. } // for i } // for j @@ -5077,17 +5087,16 @@ uint16_t mode_2DFrizzles(void) { // By: Stepko https://editor.so const int cols = SEG_W; const int rows = SEG_H; - SEGMENT.fadeToBlackBy(16); + SEGMENT.fadeToBlackBy(16 + SEGMENT.check1 * 10); for (size_t i = 8; i > 0; i--) { SEGMENT.addPixelColorXY(beatsin8_t(SEGMENT.speed/8 + i, 0, cols - 1), beatsin8_t(SEGMENT.intensity/8 - i, 0, rows - 1), ColorFromPalette(SEGPALETTE, beatsin8_t(12, 0, 255), 255, LINEARBLEND)); } - SEGMENT.blur(SEGMENT.custom1>>3); - + SEGMENT.blur(SEGMENT.custom1 >> (3 + SEGMENT.check1), SEGMENT.check1); return FRAMETIME; } // mode_2DFrizzles() -static const char _data_FX_MODE_2DFRIZZLES[] PROGMEM = "Frizzles@X frequency,Y frequency,Blur;;!;2"; +static const char _data_FX_MODE_2DFRIZZLES[] PROGMEM = "Frizzles@X frequency,Y frequency,Blur,,,Smear;;!;2"; /////////////////////////////////////////// @@ -5332,11 +5341,12 @@ uint16_t mode_2DJulia(void) { // An animated Julia set } y += dy; } -// SEGMENT.blur(64); + if(SEGMENT.check1) + SEGMENT.blur(100, true); return FRAMETIME; } // mode_2DJulia() -static const char _data_FX_MODE_2DJULIA[] PROGMEM = "Julia@,Max iterations per pixel,X center,Y center,Area size;!;!;2;ix=24,c1=128,c2=128,c3=16"; +static const char _data_FX_MODE_2DJULIA[] PROGMEM = "Julia@,Max iterations per pixel,X center,Y center,Area size, Blur;!;!;2;ix=24,c1=128,c2=128,c3=16"; ////////////////////////////// @@ -5361,10 +5371,11 @@ uint16_t mode_2DLissajous(void) { // By: Andrew Tuline ylocn = (rows < 2) ? 1 : (map(2*ylocn, 0,511, 0,2*(rows-1)) +1) /2; // "rows > 1" is needed to avoid div/0 in map() SEGMENT.setPixelColorXY((uint8_t)xlocn, (uint8_t)ylocn, SEGMENT.color_from_palette(strip.now/100+i, false, PALETTE_SOLID_WRAP, 0)); } + SEGMENT.blur(SEGMENT.custom1 >> (1 + SEGMENT.check1 * 3), SEGMENT.check1); return FRAMETIME; } // mode_2DLissajous() -static const char _data_FX_MODE_2DLISSAJOUS[] PROGMEM = "Lissajous@X frequency,Fade rate,,,Speed;!;!;2;c3=15"; +static const char _data_FX_MODE_2DLISSAJOUS[] PROGMEM = "Lissajous@X frequency,Fade rate,Blur,,Speed,Smear;!;!;2;c1=0"; /////////////////////// @@ -5559,17 +5570,13 @@ static const char _data_FX_MODE_2DPLASMABALL[] PROGMEM = "Plasma Ball@Speed,,Fad //////////////////////////////// // 2D Polar Lights // //////////////////////////////// -//static float fmap(const float x, const float in_min, const float in_max, const float out_min, const float out_max) { -// return (out_max - out_min) * (x - in_min) / (in_max - in_min) + out_min; -//} -uint16_t mode_2DPolarLights(void) { // By: Kostyantyn Matviyevskyy https://editor.soulmatelights.com/gallery/762-polar-lights , Modified by: Andrew Tuline + +uint16_t mode_2DPolarLights(void) { // By: Kostyantyn Matviyevskyy https://editor.soulmatelights.com/gallery/762-polar-lights , Modified by: Andrew Tuline & @dedehai (palette support) if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up const int cols = SEG_W; const int rows = SEG_H; - CRGBPalette16 auroraPalette = {0x000000, 0x003300, 0x006600, 0x009900, 0x00cc00, 0x00ff00, 0x33ff00, 0x66ff00, 0x99ff00, 0xccff00, 0xffff00, 0xffcc00, 0xff9900, 0xff6600, 0xff3300, 0xff0000}; - if (SEGENV.call == 0) { SEGMENT.fill(BLACK); SEGENV.step = 0; @@ -5577,37 +5584,22 @@ uint16_t mode_2DPolarLights(void) { // By: Kostyantyn Matviyevskyy https float adjustHeight = (float)map(rows, 8, 32, 28, 12); // maybe use mapf() ??? unsigned adjScale = map(cols, 8, 64, 310, 63); -/* - if (SEGENV.aux1 != SEGMENT.custom1/12) { // Hacky palette rotation. We need that black. - SEGENV.aux1 = SEGMENT.custom1/12; - for (int i = 0; i < 16; i++) { - long ilk; - ilk = (long)currentPalette[i].r << 16; - ilk += (long)currentPalette[i].g << 8; - ilk += (long)currentPalette[i].b; - ilk = (ilk << SEGENV.aux1) | (ilk >> (24 - SEGENV.aux1)); - currentPalette[i].r = ilk >> 16; - currentPalette[i].g = ilk >> 8; - currentPalette[i].b = ilk; - } - } -*/ unsigned _scale = map(SEGMENT.intensity, 0, 255, 30, adjScale); int _speed = map(SEGMENT.speed, 0, 255, 128, 16); for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) { SEGENV.step++; - SEGMENT.setPixelColorXY(x, y, ColorFromPalette(auroraPalette, - qsub8( - inoise8((SEGENV.step%2) + x * _scale, y * 16 + SEGENV.step % 16, SEGENV.step / _speed), - fabsf((float)rows / 2.0f - (float)y) * adjustHeight))); + uint8_t palindex = qsub8(inoise8((SEGENV.step%2) + x * _scale, y * 16 + SEGENV.step % 16, SEGENV.step / _speed), fabsf((float)rows / 2.0f - (float)y) * adjustHeight); + uint8_t palbrightness = palindex; + if(SEGMENT.check1) palindex = 255 - palindex; //flip palette + SEGMENT.setPixelColorXY(x, y, SEGMENT.color_from_palette(palindex, false, false, 255, palbrightness)); } } return FRAMETIME; } // mode_2DPolarLights() -static const char _data_FX_MODE_2DPOLARLIGHTS[] PROGMEM = "Polar Lights@!,Scale;;;2"; +static const char _data_FX_MODE_2DPOLARLIGHTS[] PROGMEM = "Polar Lights@!,Scale,,,,Flip Palette;;!;2;pal=71"; ///////////////////////// @@ -5645,7 +5637,7 @@ uint16_t mode_2DSindots(void) { // By: ldirko http SEGMENT.fill(BLACK); } - SEGMENT.fadeToBlackBy(SEGMENT.custom1>>3); + SEGMENT.fadeToBlackBy((SEGMENT.custom1>>3) + (SEGMENT.check1 * 24)); byte t1 = strip.now / (257 - SEGMENT.speed); // 20; byte t2 = sin8_t(t1) / 4 * 2; @@ -5654,11 +5646,11 @@ uint16_t mode_2DSindots(void) { // By: ldirko http int y = sin8_t(t2 + i * SEGMENT.intensity/8)*(rows-1)/255; // max index now 255x15/255=15! SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, i * 255 / 13, 255, LINEARBLEND)); } - SEGMENT.blur(SEGMENT.custom2>>3); + SEGMENT.blur(SEGMENT.custom2 >> (3 + SEGMENT.check1), SEGMENT.check1); return FRAMETIME; } // mode_2DSindots() -static const char _data_FX_MODE_2DSINDOTS[] PROGMEM = "Sindots@!,Dot distance,Fade rate,Blur;;!;2"; +static const char _data_FX_MODE_2DSINDOTS[] PROGMEM = "Sindots@!,Dot distance,Fade rate,Blur,,Smear;;!;2;"; ////////////////////////////// @@ -5674,7 +5666,7 @@ uint16_t mode_2Dsquaredswirl(void) { // By: Mark Kriegsman. https://g const uint8_t kBorderWidth = 2; - SEGMENT.fadeToBlackBy(24); + SEGMENT.fadeToBlackBy(1 + SEGMENT.intensity / 5); SEGMENT.blur(SEGMENT.custom3>>1); // Use two out-of-sync sine waves @@ -5691,7 +5683,7 @@ uint16_t mode_2Dsquaredswirl(void) { // By: Mark Kriegsman. https://g return FRAMETIME; } // mode_2Dsquaredswirl() -static const char _data_FX_MODE_2DSQUAREDSWIRL[] PROGMEM = "Squared Swirl@,,,,Blur;;!;2"; +static const char _data_FX_MODE_2DSQUAREDSWIRL[] PROGMEM = "Squared Swirl@,Fade,,,Blur;;!;2"; ////////////////////////////// @@ -5817,17 +5809,17 @@ uint16_t mode_2Dspaceships(void) { //// Space ships by stepko (c)05.02.21 [ht SEGMENT.addPixelColorXY(x, y-1, color); } } - SEGMENT.blur(SEGMENT.intensity>>3); + SEGMENT.blur(SEGMENT.intensity >> 3, SEGMENT.check1); return FRAMETIME; } -static const char _data_FX_MODE_2DSPACESHIPS[] PROGMEM = "Spaceships@!,Blur;;!;2"; +static const char _data_FX_MODE_2DSPACESHIPS[] PROGMEM = "Spaceships@!,Blur,,,,Smear;;!;2"; ///////////////////////// // 2D Crazy Bees // ///////////////////////// -//// Crazy bees by stepko (c)12.02.21 [https://editor.soulmatelights.com/gallery/651-crazy-bees], adapted by Blaz Kristan (AKA blazoncek) +//// Crazy bees by stepko (c)12.02.21 [https://editor.soulmatelights.com/gallery/651-crazy-bees], adapted by Blaz Kristan (AKA blazoncek), improved by @dedehai #define MAX_BEES 5 uint16_t mode_2Dcrazybees(void) { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up @@ -5867,14 +5859,14 @@ uint16_t mode_2Dcrazybees(void) { if (strip.now > SEGENV.step) { SEGENV.step = strip.now + (FRAMETIME * 16 / ((SEGMENT.speed>>4)+1)); - - SEGMENT.fadeToBlackBy(32); - + SEGMENT.fadeToBlackBy(32 + ((SEGMENT.check1*SEGMENT.intensity) / 25)); + SEGMENT.blur(SEGMENT.intensity / (2 + SEGMENT.check1 * 9), SEGMENT.check1); for (size_t i = 0; i < n; i++) { - SEGMENT.addPixelColorXY(bee[i].aimX + 1, bee[i].aimY, CHSV(bee[i].hue, 255, 255)); - SEGMENT.addPixelColorXY(bee[i].aimX, bee[i].aimY + 1, CHSV(bee[i].hue, 255, 255)); - SEGMENT.addPixelColorXY(bee[i].aimX - 1, bee[i].aimY, CHSV(bee[i].hue, 255, 255)); - SEGMENT.addPixelColorXY(bee[i].aimX, bee[i].aimY - 1, CHSV(bee[i].hue, 255, 255)); + uint32_t flowerCcolor = SEGMENT.color_from_palette(bee[i].hue, false, true, 255); + SEGMENT.addPixelColorXY(bee[i].aimX + 1, bee[i].aimY, flowerCcolor); + SEGMENT.addPixelColorXY(bee[i].aimX, bee[i].aimY + 1, flowerCcolor); + SEGMENT.addPixelColorXY(bee[i].aimX - 1, bee[i].aimY, flowerCcolor); + SEGMENT.addPixelColorXY(bee[i].aimX, bee[i].aimY - 1, flowerCcolor); if (bee[i].posX != bee[i].aimX || bee[i].posY != bee[i].aimY) { SEGMENT.setPixelColorXY(bee[i].posX, bee[i].posY, CRGB(CHSV(bee[i].hue, 60, 255))); int error2 = bee[i].error * 2; @@ -5890,13 +5882,13 @@ uint16_t mode_2Dcrazybees(void) { bee[i].aimed(cols, rows); } } - SEGMENT.blur(SEGMENT.intensity>>4); } return FRAMETIME; } -static const char _data_FX_MODE_2DCRAZYBEES[] PROGMEM = "Crazy Bees@!,Blur;;;2"; +static const char _data_FX_MODE_2DCRAZYBEES[] PROGMEM = "Crazy Bees@!,Blur,,,,Smear;;!;2;pal=11,ix=0"; #undef MAX_BEES + ///////////////////////// // 2D Ghost Rider // ///////////////////////// @@ -6169,17 +6161,21 @@ uint16_t mode_2Dscrollingtext(void) { } if (!SEGMENT.check2) SEGMENT.fade_out(255 - (SEGMENT.custom1>>4)); // trail + bool usePaletteGradient = false; + uint32_t col1 = SEGMENT.color_from_palette(SEGENV.aux1, false, PALETTE_SOLID_WRAP, 0); + uint32_t col2 = BLACK; + if (SEGMENT.check1) { // use gradient + if(SEGMENT.palette == 0) { // use colors for gradient + col1 = SEGCOLOR(0); + col2 = SEGCOLOR(2); + } + else usePaletteGradient = true; + } for (int i = 0; i < numberOfLetters; i++) { int xoffset = int(cols) - int(SEGENV.aux0) + rotLW*i; if (xoffset + rotLW < 0) continue; // don't draw characters off-screen - uint32_t col1 = SEGMENT.color_from_palette(SEGENV.aux1, false, PALETTE_SOLID_WRAP, 0); - uint32_t col2 = BLACK; - if (SEGMENT.check1 && SEGMENT.palette == 0) { - col1 = SEGCOLOR(0); - col2 = SEGCOLOR(2); - } - SEGMENT.drawCharacter(text[i], xoffset, yoffset, letterWidth, letterHeight, col1, col2, map(SEGMENT.custom3, 0, 31, -2, 2)); + SEGMENT.drawCharacter(text[i], xoffset, yoffset, letterWidth, letterHeight, col1, col2, map(SEGMENT.custom3, 0, 31, -2, 2), usePaletteGradient); } return FRAMETIME; @@ -6190,7 +6186,7 @@ static const char _data_FX_MODE_2DSCROLLTEXT[] PROGMEM = "Scrolling Text@!,Y Off //////////////////////////// // 2D Drift Rose // //////////////////////////// -//// Drift Rose by stepko (c)2021 [https://editor.soulmatelights.com/gallery/1369-drift-rose-pattern], adapted by Blaz Kristan (AKA blazoncek) +//// Drift Rose by stepko (c)2021 [https://editor.soulmatelights.com/gallery/1369-drift-rose-pattern], adapted by Blaz Kristan (AKA blazoncek) improved by @dedehai uint16_t mode_2Ddriftrose(void) { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up @@ -6206,13 +6202,14 @@ uint16_t mode_2Ddriftrose(void) { float angle = radians(i * 10); uint32_t x = (CX + (sin_t(angle) * (beatsin8_t(i, 0, L*2)-L))) * 255.f; uint32_t y = (CY + (cos_t(angle) * (beatsin8_t(i, 0, L*2)-L))) * 255.f; - SEGMENT.wu_pixel(x, y, CHSV(i * 10, 255, 255)); + if(SEGMENT.palette == 0) SEGMENT.wu_pixel(x, y, CHSV(i * 10, 255, 255)); + else SEGMENT.wu_pixel(x, y, ColorFromPalette(SEGPALETTE, i * 10)); } - SEGMENT.blur(SEGMENT.intensity>>4); + SEGMENT.blur(SEGMENT.intensity >> 4, SEGMENT.check1); return FRAMETIME; } -static const char _data_FX_MODE_2DDRIFTROSE[] PROGMEM = "Drift Rose@Fade,Blur;;;2"; +static const char _data_FX_MODE_2DDRIFTROSE[] PROGMEM = "Drift Rose@Fade,Blur,,,,Smear;;!;2;pal=11"; ///////////////////////////// // 2D PLASMA ROTOZOOMER // @@ -6268,46 +6265,6 @@ static const char _data_FX_MODE_2DPLASMAROTOZOOM[] PROGMEM = "Rotozoomer@!,Scale /////////////////////////////////////////////////////////////////////////////// -/* use the following code to pass AudioReactive usermod variables to effect - - uint8_t *binNum = (uint8_t*)&SEGENV.aux1, *maxVol = (uint8_t*)(&SEGENV.aux1+1); // just in case assignment - bool samplePeak = false; - float FFT_MajorPeak = 1.0; - uint8_t *fftResult = nullptr; - float *fftBin = nullptr; - um_data_t *um_data; - if (UsermodManager::getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) { - volumeSmth = *(float*) um_data->u_data[0]; - volumeRaw = *(float*) um_data->u_data[1]; - fftResult = (uint8_t*) um_data->u_data[2]; - samplePeak = *(uint8_t*) um_data->u_data[3]; - FFT_MajorPeak = *(float*) um_data->u_data[4]; - my_magnitude = *(float*) um_data->u_data[5]; - maxVol = (uint8_t*) um_data->u_data[6]; // requires UI element (SEGMENT.customX?), changes source element - binNum = (uint8_t*) um_data->u_data[7]; // requires UI element (SEGMENT.customX?), changes source element - fftBin = (float*) um_data->u_data[8]; - } else { - // add support for no audio data - um_data = simulateSound(SEGMENT.soundSim); - } -*/ - - -// a few constants needed for AudioReactive effects - -// for 22Khz sampling -#define MAX_FREQUENCY 11025 // sample frequency / 2 (as per Nyquist criterion) -#define MAX_FREQ_LOG10 4.04238f // log10(MAX_FREQUENCY) - -// for 20Khz sampling -//#define MAX_FREQUENCY 10240 -//#define MAX_FREQ_LOG10 4.0103f - -// for 10Khz sampling -//#define MAX_FREQUENCY 5120 -//#define MAX_FREQ_LOG10 3.71f - - ///////////////////////////////// // * Ripple Peak // ///////////////////////////////// @@ -6469,7 +6426,10 @@ typedef struct Gravity { /////////////////////// // * GRAVCENTER // /////////////////////// -uint16_t mode_gravcenter(void) { // Gravcenter. By Andrew Tuline. +// Gravcenter effects By Andrew Tuline. +// Gravcenter base function for Gravcenter (0), Gravcentric (1), Gravimeter (2), Gravfreq (3) (merged by @dedehai) + +uint16_t mode_gravcenter_base(unsigned mode) { if (SEGLEN == 1) return mode_static(); const unsigned dataSize = sizeof(gravity); @@ -6479,83 +6439,92 @@ uint16_t mode_gravcenter(void) { // Gravcenter. By Andrew Tuline. um_data_t *um_data = getAudioData(); float volumeSmth = *(float*) um_data->u_data[0]; - //SEGMENT.fade_out(240); - SEGMENT.fade_out(251); // 30% + if(mode == 1) SEGMENT.fade_out(253); // //Gravcentric + else if(mode == 2) SEGMENT.fade_out(249); // Gravimeter + else if(mode == 3) SEGMENT.fade_out(250); // Gravfreq + else SEGMENT.fade_out(251); // Gravcenter + float mySampleAvg; + int tempsamp; float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0f; - segmentSampleAvg *= 0.125; // divide by 8, to compensate for later "sensitivity" upscaling - float mySampleAvg = mapf(segmentSampleAvg*2.0, 0, 32, 0, (float)SEGLEN/2.0f); // map to pixels available in current segment - int tempsamp = constrain(mySampleAvg, 0, SEGLEN/2); // Keep the sample from overflowing. + if(mode == 2) { //Gravimeter + segmentSampleAvg *= 0.25; // divide by 4, to compensate for later "sensitivity" upscaling + mySampleAvg = mapf(segmentSampleAvg*2.0, 0, 64, 0, (SEGLEN-1)); // map to pixels availeable in current segment + tempsamp = constrain(mySampleAvg,0,SEGLEN-1); // Keep the sample from overflowing. + } + else { // Gravcenter or Gravcentric or Gravfreq + segmentSampleAvg *= 0.125f; // divide by 8, to compensate for later "sensitivity" upscaling + mySampleAvg = mapf(segmentSampleAvg*2.0, 0.0f, 32.0f, 0.0f, (float)SEGLEN/2.0f); // map to pixels availeable in current segment + tempsamp = constrain(mySampleAvg, 0, SEGLEN/2); // Keep the sample from overflowing. + } + uint8_t gravity = 8 - SEGMENT.speed/32; - - for (int i=0; i= gravcen->topLED) gravcen->topLED = tempsamp-offset; + else if (gravcen->gravityCounter % gravity == 0) gravcen->topLED--; + + if(mode == 1) { //Gravcentric + for (int i=0; itopLED >= 0) { + SEGMENT.setPixelColor(gravcen->topLED+SEGLEN/2, CRGB::Gray); + SEGMENT.setPixelColor(SEGLEN/2-1-gravcen->topLED, CRGB::Gray); + } } - - if (tempsamp >= gravcen->topLED) - gravcen->topLED = tempsamp-1; - else if (gravcen->gravityCounter % gravity == 0) - gravcen->topLED--; - - if (gravcen->topLED >= 0) { - SEGMENT.setPixelColor(gravcen->topLED+SEGLEN/2, SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0)); - SEGMENT.setPixelColor(SEGLEN/2-1-gravcen->topLED, SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0)); + else if(mode == 2) { //Gravimeter + for (int i=0; itopLED > 0) { + SEGMENT.setPixelColor(gravcen->topLED, SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0)); + } } + else if(mode == 3) { //Gravfreq + for (int i=0; iu_data[4]; // used in mode 3: Gravfreq + if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; + uint8_t index = (log10f(FFT_MajorPeak) - (MAX_FREQ_LOG10 - 1.78f)) * 255; + SEGMENT.setPixelColor(i+SEGLEN/2, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); + SEGMENT.setPixelColor(SEGLEN/2-i-1, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); + } + if (gravcen->topLED >= 0) { + SEGMENT.setPixelColor(gravcen->topLED+SEGLEN/2, CRGB::Gray); + SEGMENT.setPixelColor(SEGLEN/2-1-gravcen->topLED, CRGB::Gray); + } + } + else { //Gravcenter + for (int i=0; itopLED >= 0) { + SEGMENT.setPixelColor(gravcen->topLED+SEGLEN/2, SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0)); + SEGMENT.setPixelColor(SEGLEN/2-1-gravcen->topLED, SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0)); + } + } gravcen->gravityCounter = (gravcen->gravityCounter + 1) % gravity; return FRAMETIME; -} // mode_gravcenter() -static const char _data_FX_MODE_GRAVCENTER[] PROGMEM = "Gravcenter@Rate of fall,Sensitivity;!,!;!;1v;ix=128,m12=2,si=0"; // Circle, Beatsin +} +uint16_t mode_gravcenter(void) { // Gravcenter. By Andrew Tuline. + return mode_gravcenter_base(0); +} +static const char _data_FX_MODE_GRAVCENTER[] PROGMEM = "Gravcenter@Rate of fall,Sensitivity;!,!;!;1v;ix=128,m12=2,si=0"; // Circle, Beatsin /////////////////////// // * GRAVCENTRIC // /////////////////////// -uint16_t mode_gravcentric(void) { // Gravcentric. By Andrew Tuline. - if (SEGLEN == 1) return mode_static(); - - unsigned dataSize = sizeof(gravity); - if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed - Gravity* gravcen = reinterpret_cast(SEGENV.data); - - um_data_t *um_data = getAudioData(); - float volumeSmth = *(float*) um_data->u_data[0]; - - // printUmData(); - - //SEGMENT.fade_out(240); - //SEGMENT.fade_out(240); // twice? really? - SEGMENT.fade_out(253); // 50% - - float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0f; - segmentSampleAvg *= 0.125f; // divide by 8, to compensate for later "sensitivity" upscaling - - float mySampleAvg = mapf(segmentSampleAvg*2.0, 0.0f, 32.0f, 0.0f, (float)SEGLEN/2.0f); // map to pixels availeable in current segment - int tempsamp = constrain(mySampleAvg, 0, SEGLEN/2); // Keep the sample from overflowing. - uint8_t gravity = 8 - SEGMENT.speed/32; - - for (int i=0; i= gravcen->topLED) - gravcen->topLED = tempsamp-1; - else if (gravcen->gravityCounter % gravity == 0) - gravcen->topLED--; - - if (gravcen->topLED >= 0) { - SEGMENT.setPixelColor(gravcen->topLED+SEGLEN/2, CRGB::Gray); - SEGMENT.setPixelColor(SEGLEN/2-1-gravcen->topLED, CRGB::Gray); - } - gravcen->gravityCounter = (gravcen->gravityCounter + 1) % gravity; - - return FRAMETIME; -} // mode_gravcentric() +uint16_t mode_gravcentric(void) { // Gravcentric. By Andrew Tuline. + return mode_gravcenter_base(1); +} static const char _data_FX_MODE_GRAVCENTRIC[] PROGMEM = "Gravcentric@Rate of fall,Sensitivity;!,!;!;1v;ix=128,m12=3,si=0"; // Corner, Beatsin @@ -6563,45 +6532,20 @@ static const char _data_FX_MODE_GRAVCENTRIC[] PROGMEM = "Gravcentric@Rate of fal // * GRAVIMETER // /////////////////////// uint16_t mode_gravimeter(void) { // Gravmeter. By Andrew Tuline. - if (SEGLEN == 1) return mode_static(); - - unsigned dataSize = sizeof(gravity); - if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed - Gravity* gravcen = reinterpret_cast(SEGENV.data); - - um_data_t *um_data = getAudioData(); - float volumeSmth = *(float*) um_data->u_data[0]; - - //SEGMENT.fade_out(240); - SEGMENT.fade_out(249); // 25% - - float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0; - segmentSampleAvg *= 0.25; // divide by 4, to compensate for later "sensitivity" upscaling - - float mySampleAvg = mapf(segmentSampleAvg*2.0, 0, 64, 0, (SEGLEN-1)); // map to pixels availeable in current segment - int tempsamp = constrain(mySampleAvg,0,SEGLEN-1); // Keep the sample from overflowing. - uint8_t gravity = 8 - SEGMENT.speed/32; - - for (int i=0; i= gravcen->topLED) - gravcen->topLED = tempsamp; - else if (gravcen->gravityCounter % gravity == 0) - gravcen->topLED--; - - if (gravcen->topLED > 0) { - SEGMENT.setPixelColor(gravcen->topLED, SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0)); - } - gravcen->gravityCounter = (gravcen->gravityCounter + 1) % gravity; - - return FRAMETIME; -} // mode_gravimeter() + return mode_gravcenter_base(2); +} static const char _data_FX_MODE_GRAVIMETER[] PROGMEM = "Gravimeter@Rate of fall,Sensitivity;!,!;!;1v;ix=128,m12=2,si=0"; // Circle, Beatsin +/////////////////////// +// ** Gravfreq // +/////////////////////// +uint16_t mode_gravfreq(void) { // Gravfreq. By Andrew Tuline. + return mode_gravcenter_base(3); +} +static const char _data_FX_MODE_GRAVFREQ[] PROGMEM = "Gravfreq@Rate of fall,Sensitivity;!,!;!;1f;ix=128,m12=0,si=0"; // Pixels, Beatsin + + ////////////////////// // * JUGGLES // ////////////////////// @@ -6808,72 +6752,54 @@ uint16_t mode_plasmoid(void) { // Plasmoid. By Andrew Tuline. static const char _data_FX_MODE_PLASMOID[] PROGMEM = "Plasmoid@Phase,# of pixels;!,!;!;01v;sx=128,ix=128,m12=0,si=0"; // Pixels, Beatsin -/////////////////////// -// * PUDDLEPEAK // -/////////////////////// -// Andrew's crappy peak detector. If I were 40+ years younger, I'd learn signal processing. -uint16_t mode_puddlepeak(void) { // Puddlepeak. By Andrew Tuline. +////////////////////// +// * PUDDLES // +////////////////////// +// Puddles/Puddlepeak By Andrew Tuline. Merged by @dedehai +uint16_t mode_puddles_base(bool peakdetect) { if (SEGLEN == 1) return mode_static(); - unsigned size = 0; - uint8_t fadeVal = map(SEGMENT.speed,0,255, 224, 254); - unsigned pos = random16(SEGLEN); // Set a random starting position. + uint8_t fadeVal = map(SEGMENT.speed, 0, 255, 224, 254); + unsigned pos = random16(SEGLEN); // Set a random starting position. + SEGMENT.fade_out(fadeVal); um_data_t *um_data = getAudioData(); + int volumeRaw = *(int16_t*)um_data->u_data[1]; 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]; float volumeSmth = *(float*) um_data->u_data[0]; - if (SEGENV.call == 0) { - SEGMENT.custom1 = *binNum; - SEGMENT.custom2 = *maxVol * 2; + if(peakdetect) { // puddles peak + *binNum = SEGMENT.custom1; // Select a bin. + *maxVol = SEGMENT.custom2 / 2; // Our volume comparator. + if (samplePeak == 1) { + size = volumeSmth * SEGMENT.intensity /256 /4 + 1; // Determine size of the flash based on the volume. + if (pos+size>= SEGLEN) size = SEGLEN - pos; + } } - - *binNum = SEGMENT.custom1; // Select a bin. - *maxVol = SEGMENT.custom2 / 2; // Our volume comparator. - - SEGMENT.fade_out(fadeVal); - - if (samplePeak == 1) { - size = volumeSmth * SEGMENT.intensity /256 /4 + 1; // Determine size of the flash based on the volume. - if (pos+size>= SEGLEN) size = SEGLEN - pos; + else { // puddles + if (volumeRaw > 1) { + size = volumeRaw * SEGMENT.intensity /256 /8 + 1; // Determine size of the flash based on the volume. + if (pos+size >= SEGLEN) size = SEGLEN - pos; + } } - - for (unsigned i=0; iu_data[1]; - - if (volumeRaw > 1) { - size = volumeRaw * SEGMENT.intensity /256 /8 + 1; // Determine size of the flash based on the volume. - if (pos+size >= SEGLEN) size = SEGLEN - pos; - } - + for (unsigned i=0; i(SEGENV.data); - - 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) - - SEGMENT.fade_out(250); - - float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0f; - segmentSampleAvg *= 0.125f; // divide by 8, to compensate for later "sensitivity" upscaling - - float mySampleAvg = mapf(segmentSampleAvg*2.0f, 0,32, 0, (float)SEGLEN/2.0f); // map to pixels availeable in current segment - int tempsamp = constrain(mySampleAvg,0,SEGLEN/2); // Keep the sample from overflowing. - uint8_t gravity = 8 - SEGMENT.speed/32; - - for (int i=0; i= gravcen->topLED) - gravcen->topLED = tempsamp-1; - else if (gravcen->gravityCounter % gravity == 0) - gravcen->topLED--; - - if (gravcen->topLED >= 0) { - SEGMENT.setPixelColor(gravcen->topLED+SEGLEN/2, CRGB::Gray); - SEGMENT.setPixelColor(SEGLEN/2-1-gravcen->topLED, CRGB::Gray); - } - gravcen->gravityCounter = (gravcen->gravityCounter + 1) % gravity; - - return FRAMETIME; -} // mode_gravfreq() -static const char _data_FX_MODE_GRAVFREQ[] PROGMEM = "Gravfreq@Rate of fall,Sensitivity;!,!;!;1f;ix=128,m12=0,si=0"; // Pixels, Beatsin - - ////////////////////// // ** Noisemove // ////////////////////// @@ -7686,7 +7558,7 @@ uint16_t mode_2Dsoap() { return FRAMETIME; } -static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness;;!;2"; +static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness;;!;2;pal=11"; //Idea from https://www.youtube.com/watch?v=HsA-6KIbgto&ab_channel=GreatScott%21 @@ -7749,23 +7621,28 @@ static const char _data_FX_MODE_2DOCTOPUS[] PROGMEM = "Octopus@!,,Offset X,Offse //Waving Cell //@Stepko (https://editor.soulmatelights.com/gallery/1704-wavingcells) -// adapted for WLED by @blazoncek +// adapted for WLED by @blazoncek, improvements by @dedehai uint16_t mode_2Dwavingcell() { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up const int cols = SEG_W; const int rows = SEG_H; - uint32_t t = strip.now/(257-SEGMENT.speed); - uint8_t aX = SEGMENT.custom1/16 + 9; - uint8_t aY = SEGMENT.custom2/16 + 1; - uint8_t aZ = SEGMENT.custom3 + 1; - for (int x = 0; x < cols; x++) for (int y = 0; y >3; + uint32_t aX = SEGMENT.custom1/16 + 9; + uint32_t aY = SEGMENT.custom2/16 + 1; + uint32_t aZ = SEGMENT.custom3 + 1; + for (int x = 0; x < cols; x++) { + for (int y = 0; y < rows; y++) { + uint32_t wave = sin8_t((x * aX) + sin8_t((((y<<8) + t) * aY)>>8)) + cos8_t(y * aZ); // bit shifts to increase temporal resolution + uint8_t colorIndex = wave + (t>>(8-(SEGMENT.check2*3))); + SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, colorIndex)); + } + } + SEGMENT.blur(SEGMENT.intensity); return FRAMETIME; } -static const char _data_FX_MODE_2DWAVINGCELL[] PROGMEM = "Waving Cell@!,,Amplitude 1,Amplitude 2,Amplitude 3;;!;2"; +static const char _data_FX_MODE_2DWAVINGCELL[] PROGMEM = "Waving Cell@!,Blur,Amplitude 1,Amplitude 2,Amplitude 3,,Flow;;!;2;ix=0"; #endif // WLED_DISABLE_2D @@ -7886,7 +7763,7 @@ void WS2812FX::setupEffectData() { addEffect(FX_MODE_COLORTWINKLE, &mode_colortwinkle, _data_FX_MODE_COLORTWINKLE); addEffect(FX_MODE_LAKE, &mode_lake, _data_FX_MODE_LAKE); addEffect(FX_MODE_METEOR, &mode_meteor, _data_FX_MODE_METEOR); - addEffect(FX_MODE_METEOR_SMOOTH, &mode_meteor_smooth, _data_FX_MODE_METEOR_SMOOTH); + //addEffect(FX_MODE_METEOR_SMOOTH, &mode_meteor_smooth, _data_FX_MODE_METEOR_SMOOTH); // merged with mode_meteor addEffect(FX_MODE_RAILWAY, &mode_railway, _data_FX_MODE_RAILWAY); addEffect(FX_MODE_RIPPLE, &mode_ripple, _data_FX_MODE_RIPPLE); addEffect(FX_MODE_TWINKLEFOX, &mode_twinklefox, _data_FX_MODE_TWINKLEFOX); diff --git a/wled00/FX.h b/wled00/FX.h index 6b31d8d2..57df5854 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -208,7 +208,7 @@ extern byte realtimeMode; // used in getMappedPixelIndex() #define FX_MODE_COLORTWINKLE 74 #define FX_MODE_LAKE 75 #define FX_MODE_METEOR 76 -#define FX_MODE_METEOR_SMOOTH 77 +//#define FX_MODE_METEOR_SMOOTH 77 // merged with meteor #define FX_MODE_RAILWAY 78 #define FX_MODE_RIPPLE 79 #define FX_MODE_TWINKLEFOX 80 @@ -420,6 +420,7 @@ typedef struct Segment { uint8_t _reserved : 4; }; }; + uint8_t _default_palette; // palette number that gets assigned to pal0 unsigned _dataLen; static unsigned _usedSegmentData; static uint8_t _segBri; // brightness of segment for current effect @@ -493,6 +494,7 @@ typedef struct Segment { aux1(0), data(nullptr), _capabilities(0), + _default_palette(0), _dataLen(0), _t(nullptr) { @@ -670,9 +672,9 @@ typedef struct Segment { inline void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) { fillCircle(cx, cy, radius, RGBW32(c.r,c.g,c.b,0), soft); } void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft = false); inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, bool soft = false) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0), soft); } // automatic inline - void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0, int8_t rotate = 0); + void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0, int8_t rotate = 0, bool usePalGrad = false); inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0)); } // automatic inline - inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, int8_t rotate = 0) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0), rotate); } // automatic inline + inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, int8_t rotate = 0, bool usePalGrad = false) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0), rotate, usePalGrad); } // automatic inline void wu_pixel(uint32_t x, uint32_t y, CRGB c); inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); } #else @@ -707,9 +709,9 @@ typedef struct Segment { inline void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) {} inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft = false) {} inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, bool soft = false) {} - inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t = 0, int8_t = 0) {} + inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t = 0, int8_t = 0, bool = false) {} inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB color) {} - inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, int8_t rotate = 0) {} + inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, int8_t rotate = 0, bool usePalGrad = false) {} inline void wu_pixel(uint32_t x, uint32_t y, CRGB c) {} #endif } segment; diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index eee81163..f00e7147 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -280,7 +280,7 @@ void Segment::blur2D(uint8_t blur_x, uint8_t blur_y, bool smear) { uint32_t last; if (blur_x) { const uint8_t keepx = smear ? 255 : 255 - blur_x; - const uint8_t seepx = blur_x >> (1 + smear); + const uint8_t seepx = blur_x >> 1; for (unsigned row = 0; row < rows; row++) { // blur rows (x direction) uint32_t carryover = BLACK; uint32_t curnew = BLACK; @@ -303,7 +303,7 @@ void Segment::blur2D(uint8_t blur_x, uint8_t blur_y, bool smear) { } if (blur_y) { const uint8_t keepy = smear ? 255 : 255 - blur_y; - const uint8_t seepy = blur_y >> (1 + smear); + const uint8_t seepy = blur_y >> 1; for (unsigned col = 0; col < cols; col++) { uint32_t carryover = BLACK; uint32_t curnew = BLACK; @@ -618,7 +618,7 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3 // draws a raster font character on canvas // only supports: 4x6=24, 5x8=40, 5x12=60, 6x8=48 and 7x9=63 fonts ATM -void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2, int8_t rotate) { +void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2, int8_t rotate, bool usePalGrad) { if (!isActive()) return; // not active if (chr < 32 || chr > 126) return; // only ASCII 32-126 supported chr -= 32; // align with font table entries @@ -626,6 +626,7 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, CRGB col = CRGB(color); CRGBPalette16 grad = CRGBPalette16(col, col2 ? CRGB(col2) : col); + if(usePalGrad) grad = SEGPALETTE; // selected palette as gradient //if (w<5 || w>6 || h!=8) return; for (int i = 0; i GRADIENT_PALETTE_COUNT+13) pal = 0; if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0; // TODO remove strip dependency by moving customPalettes out of strip //default palette. Differs depending on effect - if (pal == 0) switch (mode) { - case FX_MODE_FIRE_2012 : pal = 35; break; // heat palette - case FX_MODE_COLORWAVES : pal = 26; break; // landscape 33 - case FX_MODE_FILLNOISE8 : pal = 9; break; // ocean colors - case FX_MODE_NOISE16_1 : pal = 20; break; // Drywet - case FX_MODE_NOISE16_2 : pal = 43; break; // Blue cyan yellow - case FX_MODE_NOISE16_3 : pal = 35; break; // heat palette - case FX_MODE_NOISE16_4 : pal = 26; break; // landscape 33 - case FX_MODE_GLITTER : pal = 11; break; // rainbow colors - case FX_MODE_SUNRISE : pal = 35; break; // heat palette - case FX_MODE_RAILWAY : pal = 3; break; // prim + sec - case FX_MODE_2DSOAP : pal = 11; break; // rainbow colors - } + if (pal == 0) pal = _default_palette; //load default palette set in FX _data, party colors as default switch (pal) { case 0: //default palette. Exceptions for specific effects above targetPalette = PartyColors_p; break; @@ -585,9 +573,9 @@ Segment &Segment::setMode(uint8_t fx, bool loadDefaults) { if (modeBlending) startTransition(strip.getTransition()); // set effect transitions #endif mode = fx; + int sOpt; // load default values from effect string if (loadDefaults) { - int sOpt; sOpt = extractModeDefaults(fx, "sx"); speed = (sOpt >= 0) ? sOpt : DEFAULT_SPEED; sOpt = extractModeDefaults(fx, "ix"); intensity = (sOpt >= 0) ? sOpt : DEFAULT_INTENSITY; sOpt = extractModeDefaults(fx, "c1"); custom1 = (sOpt >= 0) ? sOpt : DEFAULT_C1; @@ -604,6 +592,9 @@ Segment &Segment::setMode(uint8_t fx, bool loadDefaults) { sOpt = extractModeDefaults(fx, "mY"); if (sOpt >= 0) mirror_y = (bool)sOpt; // NOTE: setting this option is a risky business sOpt = extractModeDefaults(fx, "pal"); if (sOpt >= 0) setPalette(sOpt); //else setPalette(0); } + sOpt = extractModeDefaults(fx, "pal"); // always extract 'pal' to set _default_palette + if(sOpt <= 0) sOpt = 6; // partycolors if zero or not set + _default_palette = sOpt; // _deault_palette is loaded into pal0 in loadPalette() (if selected) markForReset(); stateChanged = true; // send UDP/WS broadcast } @@ -1140,7 +1131,7 @@ void Segment::blur(uint8_t blur_amount, bool smear) { } #endif uint8_t keep = smear ? 255 : 255 - blur_amount; - uint8_t seep = blur_amount >> (1 + smear); + uint8_t seep = blur_amount >> 1; unsigned vlength = vLength(); uint32_t carryover = BLACK; uint32_t lastnew; @@ -1848,5 +1839,5 @@ const char JSON_palette_names[] PROGMEM = R"=====([ "Magenta","Magred","Yelmag","Yelblu","Orange & Teal","Tiamat","April Night","Orangery","C9","Sakura", "Aurora","Atlantica","C9 2","C9 New","Temperature","Aurora 2","Retro Clown","Candy","Toxy Reaf","Fairy Reaf", "Semi Blue","Pink Candy","Red Reaf","Aqua Flash","Yelblu Hot","Lite Light","Red Flash","Blink Red","Red Shift","Red Tide", -"Candy2" +"Candy2","Traffic Light" ])====="; diff --git a/wled00/const.h b/wled00/const.h index 07873dec..928b150d 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -5,7 +5,7 @@ * Readability defines and their associated numerical values + compile-time constants */ -#define GRADIENT_PALETTE_COUNT 58 +#define GRADIENT_PALETTE_COUNT 59 // You can define custom product info from build flags. // This is useful to allow API consumer to identify what type of WLED version diff --git a/wled00/ir.cpp b/wled00/ir.cpp index f094d3b8..48061238 100644 --- a/wled00/ir.cpp +++ b/wled00/ir.cpp @@ -435,7 +435,7 @@ static void decodeIR44(uint32_t code) case IR44_DIY2 : presetFallback(2, FX_MODE_BREATH, 0); break; case IR44_DIY3 : presetFallback(3, FX_MODE_FIRE_FLICKER, 0); break; case IR44_DIY4 : presetFallback(4, FX_MODE_RAINBOW, 0); break; - case IR44_DIY5 : presetFallback(5, FX_MODE_METEOR_SMOOTH, 0); break; + case IR44_DIY5 : presetFallback(5, FX_MODE_METEOR, 0); break; case IR44_DIY6 : presetFallback(6, FX_MODE_RAIN, 0); break; case IR44_AUTO : changeEffect(FX_MODE_STATIC); break; case IR44_FLASH : changeEffect(FX_MODE_PALETTE); break; diff --git a/wled00/palettes.h b/wled00/palettes.h index 1ead342b..c84c1fb9 100644 --- a/wled00/palettes.h +++ b/wled00/palettes.h @@ -1,5 +1,6 @@ /* * Color palettes for FastLED effects (65-73). + * 4 bytes per color: index, red, green, blue */ // From ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb @@ -844,6 +845,12 @@ const byte candy2_gp[] PROGMEM = { 211, 39, 33, 34, 255, 1, 1, 1}; +const byte trafficlight_gp[] PROGMEM = { + 0, 0, 0, 0, //black + 85, 0, 255, 0, //green + 170, 255, 255, 0, //yellow + 255, 255, 0, 0}; //red + // array of fastled palettes (palette 6 - 12) const TProgmemRGBPalette16 *const fastledPalettes[] PROGMEM = { &PartyColors_p, //06-00 Party @@ -917,7 +924,8 @@ const byte* const gGradientPalettes[] PROGMEM = { blink_red_gp, //67-54 Blink Red red_shift_gp, //68-55 Red Shift red_tide_gp, //69-56 Red Tide - candy2_gp //70-57 Candy2 + candy2_gp, //70-57 Candy2 + trafficlight_gp //71-58 Traffic Light }; #endif From 5f77478841acfa105803dbb192f95b2a6de1ec6b Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Fri, 20 Dec 2024 19:12:29 +0100 Subject: [PATCH 091/463] Replace PRNG with hardware RNG (#4225) Both ESP8266 and ESP32 have a hardware random register. This update makes use of that. It is slightly faster than the fastled variants but mostly it is truly random, even when the timing limitations stated in the datasheet are disregarded. Also saves a bit on code size. - Replaced all random8() and random16() calls with new hw_random() versions - Not replaced in FX where PRNG is required --- wled00/FX.cpp | 320 +++++++++++++++++++++---------------------- wled00/colors.cpp | 92 ++++++------- wled00/fcn_declare.h | 23 ++++ wled00/ir.cpp | 2 +- wled00/remote.cpp | 2 +- wled00/util.cpp | 33 +++-- wled00/wled.cpp | 10 +- 7 files changed, 256 insertions(+), 226 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index b6d26532..5e43430a 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -211,7 +211,7 @@ uint16_t color_wipe(bool rev, bool useRandomColors) { if (useRandomColors) { if (SEGENV.call == 0) { - SEGENV.aux0 = random8(); + SEGENV.aux0 = hw_random8(); SEGENV.step = 3; } if (SEGENV.step == 1) { //if flag set, change to new random color @@ -303,7 +303,7 @@ uint16_t mode_random_color(void) { } if (SEGENV.call == 0) { - SEGENV.aux0 = random8(); + SEGENV.aux0 = hw_random8(); SEGENV.step = 2; } if (it != SEGENV.step) //new color @@ -328,7 +328,7 @@ uint16_t mode_dynamic(void) { if(SEGENV.call == 0) { //SEGMENT.fill(BLACK); - for (unsigned i = 0; i < SEGLEN; i++) SEGENV.data[i] = random8(); + for (unsigned i = 0; i < SEGLEN; i++) SEGENV.data[i] = hw_random8(); } uint32_t cycleTime = 50 + (255 - SEGMENT.speed)*15; @@ -336,7 +336,7 @@ uint16_t mode_dynamic(void) { if (it != SEGENV.step && SEGMENT.speed != 0) //new color { for (unsigned i = 0; i < SEGLEN; i++) { - if (random8() <= SEGMENT.intensity) SEGENV.data[i] = random8(); // random color index + if (hw_random8() <= SEGMENT.intensity) SEGENV.data[i] = hw_random8(); // random color index } SEGENV.step = it; } @@ -617,7 +617,7 @@ uint16_t mode_twinkle(void) { if (SEGENV.aux0 >= maxOn) { SEGENV.aux0 = 0; - SEGENV.aux1 = random16(); //new seed for our PRNG + SEGENV.aux1 = hw_random(); //new seed for our PRNG } SEGENV.aux0++; SEGENV.step = it; @@ -651,9 +651,9 @@ uint16_t dissolve(uint32_t color) { } for (unsigned j = 0; j <= SEGLEN / 15; j++) { - if (random8() <= SEGMENT.intensity) { + if (hw_random8() <= SEGMENT.intensity) { for (size_t times = 0; times < 10; times++) { //attempt to spawn a new pixel 10 times - unsigned i = random16(SEGLEN); + unsigned i = hw_random16(SEGLEN); unsigned index = i >> 3; unsigned bitNum = i & 0x07; bool fadeUp = bitRead(SEGENV.data[index], bitNum); @@ -693,7 +693,7 @@ uint16_t dissolve(uint32_t color) { * Blink several LEDs on and then off */ uint16_t mode_dissolve(void) { - return dissolve(SEGMENT.check1 ? SEGMENT.color_wheel(random8()) : SEGCOLOR(0)); + return dissolve(SEGMENT.check1 ? SEGMENT.color_wheel(hw_random8()) : SEGCOLOR(0)); } static const char _data_FX_MODE_DISSOLVE[] PROGMEM = "Dissolve@Repeat speed,Dissolve speed,,,,Random;!,!;!"; @@ -702,7 +702,7 @@ static const char _data_FX_MODE_DISSOLVE[] PROGMEM = "Dissolve@Repeat speed,Diss * Blink several LEDs on and then off in random colors */ uint16_t mode_dissolve_random(void) { - return dissolve(SEGMENT.color_wheel(random8())); + return dissolve(SEGMENT.color_wheel(hw_random8())); } static const char _data_FX_MODE_DISSOLVE_RANDOM[] PROGMEM = "Dissolve Rnd@Repeat speed,Dissolve speed;,!;!"; @@ -719,7 +719,7 @@ uint16_t mode_sparkle(void) { uint32_t it = strip.now / cycleTime; if (it != SEGENV.step) { - SEGENV.aux0 = random16(SEGLEN); // aux0 stores the random led index + SEGENV.aux0 = hw_random16(SEGLEN); // aux0 stores the random led index SEGENV.step = it; } @@ -739,8 +739,8 @@ uint16_t mode_flash_sparkle(void) { } if (strip.now - SEGENV.aux0 > SEGENV.step) { - if(random8((255-SEGMENT.intensity) >> 4) == 0) { - SEGMENT.setPixelColor(random16(SEGLEN), SEGCOLOR(1)); //flash + if(hw_random8((255-SEGMENT.intensity) >> 4) == 0) { + SEGMENT.setPixelColor(hw_random16(SEGLEN), SEGCOLOR(1)); //flash } SEGENV.step = strip.now; SEGENV.aux0 = 255-SEGMENT.speed; @@ -760,10 +760,10 @@ uint16_t mode_hyper_sparkle(void) { } if (strip.now - SEGENV.aux0 > SEGENV.step) { - if (random8((255-SEGMENT.intensity) >> 4) == 0) { + if (hw_random8((255-SEGMENT.intensity) >> 4) == 0) { int len = max(1, (int)SEGLEN/3); for (int i = 0; i < len; i++) { - SEGMENT.setPixelColor(random16(SEGLEN), SEGCOLOR(1)); + SEGMENT.setPixelColor(hw_random16(SEGLEN), SEGCOLOR(1)); } } SEGENV.step = strip.now; @@ -1133,7 +1133,7 @@ static const char _data_FX_MODE_RUNNING_COLOR[] PROGMEM = "Chase 2@!,Width;!,!;! uint16_t mode_running_random(void) { uint32_t cycleTime = 25 + (3 * (uint32_t)(255 - SEGMENT.speed)); uint32_t it = strip.now / cycleTime; - if (SEGENV.call == 0) SEGENV.aux0 = random16(); // random seed for PRNG on start + if (SEGENV.call == 0) SEGENV.aux0 = hw_random(); // random seed for PRNG on start unsigned zoneSize = ((255-SEGMENT.intensity) >> 4) +1; uint16_t PRNG16 = SEGENV.aux0; @@ -1278,11 +1278,11 @@ uint16_t mode_fireworks() { } for (int i=0; i> 1)) == 0) { - uint16_t index = random16(width*height); + if (hw_random8(129 - (SEGMENT.intensity >> 1)) == 0) { + uint16_t index = hw_random16(width*height); x = index % width; y = index / width; - uint32_t col = SEGMENT.color_from_palette(random8(), false, false, 0); + uint32_t col = SEGMENT.color_from_palette(hw_random8(), false, false, 0); if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, col); else SEGMENT.setPixelColor(index, col); SEGENV.aux1 = SEGENV.aux0; // old spark @@ -1344,7 +1344,7 @@ uint16_t mode_fire_flicker(void) { byte lum = (SEGMENT.palette == 0) ? MAX(w, MAX(r, MAX(g, b))) : 255; lum /= (((256-SEGMENT.intensity)/16)+1); for (unsigned i = 0; i < SEGLEN; i++) { - byte flicker = random8(lum); + byte flicker = hw_random8(lum); if (SEGMENT.palette == 0) { SEGMENT.setPixelColor(i, MAX(r - flicker, 0), MAX(g - flicker, 0), MAX(b - flicker, 0), MAX(w - flicker, 0)); } else { @@ -1475,11 +1475,11 @@ uint16_t mode_fairy() { if (stateTime > flashers[f].stateDur * 10) { flashers[f].stateOn = !flashers[f].stateOn; if (flashers[f].stateOn) { - flashers[f].stateDur = 12 + random8(12 + ((255 - SEGMENT.speed) >> 2)); //*10, 250ms to 1250ms + flashers[f].stateDur = 12 + hw_random8(12 + ((255 - SEGMENT.speed) >> 2)); //*10, 250ms to 1250ms } else { - flashers[f].stateDur = 20 + random8(6 + ((255 - SEGMENT.speed) >> 2)); //*10, 250ms to 1250ms + flashers[f].stateDur = 20 + hw_random8(6 + ((255 - SEGMENT.speed) >> 2)); //*10, 250ms to 1250ms } - //flashers[f].stateDur = 51 + random8(2 + ((255 - SEGMENT.speed) >> 1)); + //flashers[f].stateDur = 51 + hw_random8(2 + ((255 - SEGMENT.speed) >> 1)); flashers[f].stateStart = now16; if (stateTime < 255) { flashers[f].stateStart -= 255 -stateTime; //start early to get correct bri @@ -1535,15 +1535,15 @@ uint16_t mode_fairytwinkle() { flashers[f].stateOn = !flashers[f].stateOn; bool init = !flashers[f].stateDur; if (flashers[f].stateOn) { - flashers[f].stateDur = riseFallTime/100 + ((255 - SEGMENT.intensity) >> 2) + random8(12 + ((255 - SEGMENT.intensity) >> 1)) +1; + flashers[f].stateDur = riseFallTime/100 + ((255 - SEGMENT.intensity) >> 2) + hw_random8(12 + ((255 - SEGMENT.intensity) >> 1)) +1; } else { - flashers[f].stateDur = riseFallTime/100 + random8(3 + ((255 - SEGMENT.speed) >> 6)) +1; + flashers[f].stateDur = riseFallTime/100 + hw_random8(3 + ((255 - SEGMENT.speed) >> 6)) +1; } flashers[f].stateStart = now16; stateTime = 0; if (init) { flashers[f].stateStart -= riseFallTime; //start lit - flashers[f].stateDur = riseFallTime/100 + random8(12 + ((255 - SEGMENT.intensity) >> 1)) +5; //fire up a little quicker + flashers[f].stateDur = riseFallTime/100 + hw_random8(12 + ((255 - SEGMENT.intensity) >> 1)) +5; //fire up a little quicker stateTime = riseFallTime; } } @@ -1611,13 +1611,13 @@ uint16_t mode_icu(void) { SEGMENT.setPixelColor(dest + SEGLEN/space, col); if(SEGENV.aux0 == dest) { // pause between eye movements - if(random8(6) == 0) { // blink once in a while + if(hw_random8(6) == 0) { // blink once in a while SEGMENT.setPixelColor(dest, SEGCOLOR(1)); SEGMENT.setPixelColor(dest + SEGLEN/space, SEGCOLOR(1)); return 200; } - SEGENV.aux0 = random16(SEGLEN-SEGLEN/space); - return 1000 + random16(2000); + SEGENV.aux0 = hw_random16(SEGLEN-SEGLEN/space); + return 1000 + hw_random16(2000); } if(SEGENV.aux0 > SEGENV.step) { @@ -1747,7 +1747,7 @@ uint16_t mode_multi_comet(void) { } comets[i]++; } else { - if(!random16(SEGLEN)) { + if(!hw_random16(SEGLEN)) { comets[i] = 0; } } @@ -1831,12 +1831,12 @@ uint16_t mode_oscillate(void) { oscillators[i].pos = 0; oscillators[i].dir = 1; // make bigger steps for faster speeds - oscillators[i].speed = SEGMENT.speed > 100 ? random8(2, 4):random8(1, 3); + oscillators[i].speed = SEGMENT.speed > 100 ? hw_random8(2, 4):hw_random8(1, 3); } if((oscillators[i].dir == 1) && (oscillators[i].pos >= (SEGLEN - 1))) { oscillators[i].pos = SEGLEN - 1; oscillators[i].dir = -1; - oscillators[i].speed = SEGMENT.speed > 100 ? random8(2, 4):random8(1, 3); + oscillators[i].speed = SEGMENT.speed > 100 ? hw_random8(2, 4):hw_random8(1, 3); } } @@ -1859,13 +1859,13 @@ static const char _data_FX_MODE_OSCILLATE[] PROGMEM = "Oscillate"; //TODO uint16_t mode_lightning(void) { if (SEGLEN == 1) return mode_static(); - unsigned ledstart = random16(SEGLEN); // Determine starting location of flash - unsigned ledlen = 1 + random16(SEGLEN -ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1) - uint8_t bri = 255/random8(1, 3); + unsigned ledstart = hw_random16(SEGLEN); // Determine starting location of flash + unsigned ledlen = 1 + hw_random16(SEGLEN -ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1) + uint8_t bri = 255/hw_random8(1, 3); if (SEGENV.aux1 == 0) //init, leader flash { - SEGENV.aux1 = random8(4, 4 + SEGMENT.intensity/20); //number of flashes + SEGENV.aux1 = hw_random8(4, 4 + SEGMENT.intensity/20); //number of flashes SEGENV.aux1 *= 2; bri = 52; //leader has lower brightness @@ -1882,15 +1882,15 @@ uint16_t mode_lightning(void) { SEGENV.aux1--; SEGENV.step = strip.now; - //return random8(4, 10); // each flash only lasts one frame/every 24ms... originally 4-10 milliseconds + //return hw_random8(4, 10); // each flash only lasts one frame/every 24ms... originally 4-10 milliseconds } else { if (strip.now - SEGENV.step > SEGENV.aux0) { SEGENV.aux1--; if (SEGENV.aux1 < 2) SEGENV.aux1 = 0; - SEGENV.aux0 = (50 + random8(100)); //delay between flashes + SEGENV.aux0 = (50 + hw_random8(100)); //delay between flashes if (SEGENV.aux1 == 2) { - SEGENV.aux0 = (random8(255 - SEGMENT.speed) * 100); // delay between strikes + SEGENV.aux0 = (hw_random8(255 - SEGMENT.speed) * 100); // delay between strikes } SEGENV.step = strip.now; } @@ -2103,7 +2103,7 @@ uint16_t mode_fire_2012() { // Step 1. Cool down every cell a little for (unsigned i = 0; i < SEGLEN; i++) { - uint8_t cool = (it != SEGENV.step) ? random8((((20 + SEGMENT.speed/3) * 16) / SEGLEN)+2) : random8(4); + uint8_t cool = (it != SEGENV.step) ? hw_random8((((20 + SEGMENT.speed/3) * 16) / SEGLEN)+2) : hw_random8(4); uint8_t minTemp = (i> 3; unsigned bitNum = i & 0x07; bitWrite(SEGENV.data[index], bitNum, true); - SEGMENT.setPixelColor(i, ColorFromPalette(SEGPALETTE, random8(), 64, NOBLEND)); + SEGMENT.setPixelColor(i, ColorFromPalette(SEGPALETTE, hw_random8(), 64, NOBLEND)); break; //only spawn 1 new pixel per frame per 50 LEDs } } @@ -2386,14 +2386,14 @@ uint16_t mode_meteor() { // fade all leds to colors[1] in LEDs one step for (unsigned i = 0; i < SEGLEN; i++) { uint32_t col; - if (random8() <= 255 - SEGMENT.intensity) { + if (hw_random8() <= 255 - SEGMENT.intensity) { if(meteorSmooth) { - int change = trail[i] + 4 - random8(24); //change each time between -20 and +4 + int change = trail[i] + 4 - hw_random8(24); //change each time between -20 and +4 trail[i] = constrain(change, 0, max); col = SEGMENT.check1 ? SEGMENT.color_from_palette(i, true, false, 0, trail[i]) : SEGMENT.color_from_palette(trail[i], false, true, 255); } else { - trail[i] = scale8(trail[i], 128 + random8(127)); + trail[i] = scale8(trail[i], 128 + hw_random8(127)); int index = trail[i]; int idx = 255; int bri = SEGMENT.palette==35 || SEGMENT.palette==36 ? 255 : trail[i]; @@ -2410,8 +2410,8 @@ uint16_t mode_meteor() { // draw meteor for (unsigned j = 0; j < meteorSize; j++) { - unsigned index = (meteorstart + j) % SEGLEN; - if(meteorSmooth) { + unsigned index = (meteorstart + j) % SEGLEN; + if(meteorSmooth) { trail[index] = max; uint32_t col = SEGMENT.check1 ? SEGMENT.color_from_palette(index, true, false, 0, trail[index]) : SEGMENT.color_from_palette(trail[index], false, true, 255); SEGMENT.setPixelColor(index, col); @@ -2422,7 +2422,7 @@ uint16_t mode_meteor() { if (!SEGMENT.check1) { i = map(index,0,SEGLEN,0,max); idx = 0; - } + } uint32_t col = SEGMENT.color_from_palette(i, false, false, idx, 255); // full brightness SEGMENT.setPixelColor(index, col); } @@ -2523,10 +2523,10 @@ static uint16_t ripple_base(uint8_t blurAmount = 0) { ripplestate += rippledecay; ripples[i].state = (ripplestate > 254) ? 0 : ripplestate; } else {//randomly create new wave - if (random16(IBN + 10000) <= (SEGMENT.intensity >> (SEGMENT.is2D()*3))) { + if (hw_random16(IBN + 10000) <= (SEGMENT.intensity >> (SEGMENT.is2D()*3))) { ripples[i].state = 1; - ripples[i].pos = SEGMENT.is2D() ? ((random8(SEG_W)<<8) | (random8(SEG_H))) : random16(SEGLEN); - ripples[i].color = random8(); //color + ripples[i].pos = SEGMENT.is2D() ? ((hw_random8(SEG_W)<<8) | (hw_random8(SEG_H))) : hw_random16(SEGLEN); + ripples[i].color = hw_random8(); //color } } } @@ -2551,11 +2551,11 @@ static const char _data_FX_MODE_RIPPLE[] PROGMEM = "Ripple@!,Wave #,Blur,,,,Over uint16_t mode_ripple_rainbow(void) { if (SEGLEN == 1) return mode_static(); if (SEGENV.call ==0) { - SEGENV.aux0 = random8(); - SEGENV.aux1 = random8(); + SEGENV.aux0 = hw_random8(); + SEGENV.aux1 = hw_random8(); } if (SEGENV.aux0 == SEGENV.aux1) { - SEGENV.aux1 = random8(); + SEGENV.aux1 = hw_random8(); } else if (SEGENV.aux1 > SEGENV.aux0) { SEGENV.aux0++; } else { @@ -2750,10 +2750,10 @@ uint16_t mode_halloween_eyes() // - select a duration // - immediately switch to eyes on state. - data.startPos = random16(0, maxWidth - eyeLength - 1); - data.color = random8(); - if (strip.isMatrix) SEGMENT.offset = random16(SEG_H-1); // a hack: reuse offset since it is not used in matrices - duration = 128u + random16(SEGMENT.intensity*64u); + data.startPos = hw_random16(0, maxWidth - eyeLength - 1); + data.color = hw_random8(); + if (strip.isMatrix) SEGMENT.offset = hw_random16(SEG_H-1); // a hack: reuse offset since it is not used in matrices + duration = 128u + hw_random16(SEGMENT.intensity*64u); data.duration = duration; data.state = eyeState::on; [[fallthrough]]; @@ -2780,11 +2780,11 @@ uint16_t mode_halloween_eyes() } else if (elapsedTime > minimumOnTimeBegin) { const uint32_t remainingTime = (elapsedTime >= duration) ? 0u : (duration - elapsedTime); if (remainingTime > minimumOnTimeEnd) { - if (random8() < 4u) + if (hw_random8() < 4u) { c = backgroundColor; data.state = eyeState::blink; - data.blinkEndTime = strip.now + random8(8, 128); + data.blinkEndTime = strip.now + hw_random8(8, 128); } } } @@ -2818,7 +2818,7 @@ uint16_t mode_halloween_eyes() // - immediately switch to eyes-off state const unsigned eyeOffTimeBase = SEGMENT.speed*128u; - duration = eyeOffTimeBase + random16(eyeOffTimeBase); + duration = eyeOffTimeBase + hw_random16(eyeOffTimeBase); data.duration = duration; data.state = eyeState::off; [[fallthrough]]; @@ -3008,7 +3008,7 @@ uint16_t mode_bouncing_balls(void) { balls[i].lastBounceTime = time; if (balls[i].impactVelocity < 0.015f) { - float impactVelocityStart = sqrtf(-2.0f * gravity) * random8(5,11)/10.0f; // randomize impact velocity + float impactVelocityStart = sqrtf(-2.0f * gravity) * hw_random8(5,11)/10.0f; // randomize impact velocity balls[i].impactVelocity = impactVelocityStart; } } else if (balls[i].height > 1.0f) { @@ -3071,10 +3071,10 @@ static uint16_t rolling_balls(void) { SEGMENT.fill(hasCol2 ? BLACK : SEGCOLOR(1)); // start clean for (unsigned i = 0; i < maxNumBalls; i++) { balls[i].lastBounceUpdate = strip.now; - balls[i].velocity = 20.0f * float(random16(1000, 10000))/10000.0f; // number from 1 to 10 - if (random8()<128) balls[i].velocity = -balls[i].velocity; // 50% chance of reverse direction - balls[i].height = (float(random16(0, 10000)) / 10000.0f); // from 0. to 1. - balls[i].mass = (float(random16(1000, 10000)) / 10000.0f); // from .1 to 1. + balls[i].velocity = 20.0f * float(hw_random16(1000, 10000))/10000.0f; // number from 1 to 10 + if (hw_random8()<128) balls[i].velocity = -balls[i].velocity; // 50% chance of reverse direction + balls[i].height = (float(hw_random16(0, 10000)) / 10000.0f); // from 0. to 1. + balls[i].mass = (float(hw_random16(1000, 10000)) / 10000.0f); // from .1 to 1. } } @@ -3090,7 +3090,7 @@ static uint16_t rolling_balls(void) { float thisHeight = balls[i].height + balls[i].velocity * timeSinceLastUpdate; // this method keeps higher resolution // test if intensity level was increased and some balls are way off the track then put them back if (thisHeight < -0.5f || thisHeight > 1.5f) { - thisHeight = balls[i].height = (float(random16(0, 10000)) / 10000.0f); // from 0. to 1. + thisHeight = balls[i].height = (float(hw_random16(0, 10000)) / 10000.0f); // from 0. to 1. balls[i].lastBounceUpdate = strip.now; } // check if reached ends of the strip @@ -3200,7 +3200,7 @@ static const char _data_FX_MODE_SINELON_RAINBOW[] PROGMEM = "Sinelon Rainbow@!,T // utility function that will add random glitter to SEGMENT void glitter_base(uint8_t intensity, uint32_t col = ULTRAWHITE) { - if (intensity > random8()) SEGMENT.setPixelColor(random16(SEGLEN), col); + if (intensity > hw_random8()) SEGMENT.setPixelColor(hw_random16(SEGLEN), col); } //Glitter with palette background, inspired by https://gist.github.com/kriegsman/062e10f7f07ba8518af6 @@ -3277,18 +3277,18 @@ uint16_t mode_popcorn(void) { popcorn[i].pos += popcorn[i].vel; popcorn[i].vel += gravity; } else { // if kernel is inactive, randomly pop it - if (random8() < 2) { // POP!!! + if (hw_random8() < 2) { // POP!!! popcorn[i].pos = 0.01f; - unsigned peakHeight = 128 + random8(128); //0-255 + unsigned peakHeight = 128 + hw_random8(128); //0-255 peakHeight = (peakHeight * (SEGLEN -1)) >> 8; popcorn[i].vel = sqrtf(-2.0f * gravity * peakHeight); if (SEGMENT.palette) { - popcorn[i].colIndex = random8(); + popcorn[i].colIndex = hw_random8(); } else { - byte col = random8(0, NUM_COLORS); + byte col = hw_random8(0, NUM_COLORS); if (!SEGCOLOR(2) || !SEGCOLOR(col)) col = 0; popcorn[i].colIndex = col; } @@ -3350,7 +3350,7 @@ uint16_t candle(bool multi) s = SEGENV.data[d]; s_target = SEGENV.data[d+1]; fadeStep = SEGENV.data[d+2]; } if (fadeStep == 0) { //init vals - s = 128; s_target = 130 + random8(4); fadeStep = 1; + s = 128; s_target = 130 + hw_random8(4); fadeStep = 1; } bool newTarget = false; @@ -3363,8 +3363,8 @@ uint16_t candle(bool multi) } if (newTarget) { - s_target = random8(rndval) + random8(rndval); //between 0 and rndval*2 -2 = 252 - if (s_target < (rndval >> 1)) s_target = (rndval >> 1) + random8(rndval); + s_target = hw_random8(rndval) + hw_random8(rndval); //between 0 and rndval*2 -2 = 252 + if (s_target < (rndval >> 1)) s_target = (rndval >> 1) + hw_random8(rndval); unsigned offset = (255 - valrange); s_target += offset; @@ -3450,19 +3450,19 @@ uint16_t mode_starburst(void) { for (unsigned j = 0; j < numStars; j++) { // speed to adjust chance of a burst, max is nearly always. - if (random8((144-(SEGMENT.speed >> 1))) == 0 && stars[j].birth == 0) + if (hw_random8((144-(SEGMENT.speed >> 1))) == 0 && stars[j].birth == 0) { // Pick a random color and location. - unsigned startPos = random16(SEGLEN-1); - float multiplier = (float)(random8())/255.0f * 1.0f; + unsigned startPos = hw_random16(SEGLEN-1); + float multiplier = (float)(hw_random8())/255.0f * 1.0f; - stars[j].color = CRGB(SEGMENT.color_wheel(random8())); + stars[j].color = CRGB(SEGMENT.color_wheel(hw_random8())); stars[j].pos = startPos; - stars[j].vel = maxSpeed * (float)(random8())/255.0f * multiplier; + stars[j].vel = maxSpeed * (float)(hw_random8())/255.0f * multiplier; stars[j].birth = it; stars[j].last = it; // more fragments means larger burst effect - int num = random8(3,6 + (SEGMENT.intensity >> 5)); + int num = hw_random8(3,6 + (SEGMENT.intensity >> 5)); for (int i=0; i < STARBURST_MAX_FRAG; i++) { if (i < num) stars[j].fragment[i] = startPos; @@ -3578,11 +3578,11 @@ uint16_t mode_exploding_fireworks(void) if (SEGENV.aux0 < 2) { //FLARE if (SEGENV.aux0 == 0) { //init flare flare->pos = 0; - flare->posX = SEGMENT.is2D() ? random16(2,cols-3) : (SEGMENT.intensity > random8()); // will enable random firing side on 1D - unsigned peakHeight = 75 + random8(180); //0-255 + flare->posX = SEGMENT.is2D() ? hw_random16(2,cols-3) : (SEGMENT.intensity > hw_random8()); // will enable random firing side on 1D + unsigned peakHeight = 75 + hw_random8(180); //0-255 peakHeight = (peakHeight * (rows -1)) >> 8; flare->vel = sqrtf(-2.0f * gravity * peakHeight); - flare->velX = SEGMENT.is2D() ? (random8(9)-4)/64.0f : 0; // no X velocity on 1D + flare->velX = SEGMENT.is2D() ? (hw_random8(9)-4)/64.0f : 0; // no X velocity on 1D flare->col = 255; //brightness SEGENV.aux0 = 1; } @@ -3610,7 +3610,7 @@ uint16_t mode_exploding_fireworks(void) * Explosion happens where the flare ended. * Size is proportional to the height. */ - unsigned nSparks = flare->pos + random8(4); + unsigned nSparks = flare->pos + hw_random8(4); nSparks = std::max(nSparks, 4U); // This is not a standard constrain; numSparks is not guaranteed to be at least 4 nSparks = std::min(nSparks, numSparks); @@ -3619,12 +3619,12 @@ uint16_t mode_exploding_fireworks(void) for (unsigned i = 1; i < nSparks; i++) { sparks[i].pos = flare->pos; sparks[i].posX = flare->posX; - sparks[i].vel = (float(random16(20001)) / 10000.0f) - 0.9f; // from -0.9 to 1.1 + sparks[i].vel = (float(hw_random16(20001)) / 10000.0f) - 0.9f; // from -0.9 to 1.1 sparks[i].vel *= rows<32 ? 0.5f : 1; // reduce velocity for smaller strips - sparks[i].velX = SEGMENT.is2D() ? (float(random16(20001)) / 10000.0f) - 1.0f : 0; // from -1 to 1 + sparks[i].velX = SEGMENT.is2D() ? (float(hw_random16(20001)) / 10000.0f) - 1.0f : 0; // from -1 to 1 sparks[i].col = 345;//abs(sparks[i].vel * 750.0); // set colors before scaling velocity to keep them bright //sparks[i].col = constrain(sparks[i].col, 0, 345); - sparks[i].colIndex = random8(); + sparks[i].colIndex = hw_random8(); sparks[i].vel *= flare->pos/rows; // proportional to height sparks[i].velX *= SEGMENT.is2D() ? flare->posX/cols : 0; // proportional to width sparks[i].vel *= -gravity *50; @@ -3662,7 +3662,7 @@ uint16_t mode_exploding_fireworks(void) if (SEGMENT.check3) SEGMENT.blur(16); *dying_gravity *= .8f; // as sparks burn out they fall slower } else { - SEGENV.aux0 = 6 + random8(10); //wait for this many frames + SEGENV.aux0 = 6 + hw_random8(10); //wait for this many frames } } else { SEGENV.aux0--; @@ -3717,7 +3717,7 @@ uint16_t mode_drip(void) drops[j].col += map(SEGMENT.speed, 0, 255, 1, 6); // swelling - if (random8() < drops[j].col/10) { // random drop + if (hw_random8() < drops[j].col/10) { // random drop drops[j].colIndex=2; //fall drops[j].col=255; } @@ -3803,17 +3803,17 @@ uint16_t mode_tetrix(void) { // speed calculation: a single brick should reach bottom of strip in X seconds // if the speed is set to 1 this should take 5s and at 255 it should take 0.25s // as this is dependant on SEGLEN it should be taken into account and the fact that effect runs every FRAMETIME s - int speed = SEGMENT.speed ? SEGMENT.speed : random8(1,255); + int speed = SEGMENT.speed ? SEGMENT.speed : hw_random8(1,255); speed = map(speed, 1, 255, 5000, 250); // time taken for full (SEGLEN) drop drop->speed = float(SEGLEN * FRAMETIME) / float(speed); // set speed drop->pos = SEGLEN; // start at end of segment (no need to subtract 1) - if (!SEGMENT.check1) drop->col = random8(0,15)<<4; // limit color choices so there is enough HUE gap + if (!SEGMENT.check1) drop->col = hw_random8(0,15)<<4; // limit color choices so there is enough HUE gap drop->step = 1; // drop state (0 init, 1 forming, 2 falling) - drop->brick = (SEGMENT.intensity ? (SEGMENT.intensity>>5)+1 : random8(1,5)) * (1+(SEGLEN>>6)); // size of brick + drop->brick = (SEGMENT.intensity ? (SEGMENT.intensity>>5)+1 : hw_random8(1,5)) * (1+(SEGLEN>>6)); // size of brick } if (drop->step == 1) { // forming - if (random8()>>6) { // random drop + if (hw_random8()>>6) { // random drop drop->step = 2; // fall } } @@ -3862,7 +3862,7 @@ static const char _data_FX_MODE_TETRIX[] PROGMEM = "Tetrix@!,Width,,,,One color; uint16_t mode_plasma(void) { // initialize phases on start if (SEGENV.call == 0) { - SEGENV.aux0 = random8(0,2); // add a bit of randomness + SEGENV.aux0 = hw_random8(0,2); // add a bit of randomness } unsigned thisPhase = beatsin8_t(6+SEGENV.aux0,-64,64); unsigned thatPhase = beatsin8_t(7+SEGENV.aux0,-64,64); @@ -4206,8 +4206,8 @@ uint16_t mode_noisepal(void) { // Slow noise { SEGENV.step = strip.now; - unsigned baseI = random8(); - palettes[1] = CRGBPalette16(CHSV(baseI+random8(64), 255, random8(128,255)), CHSV(baseI+128, 255, random8(128,255)), CHSV(baseI+random8(92), 192, random8(128,255)), CHSV(baseI+random8(92), 255, random8(128,255))); + unsigned baseI = hw_random8(); + palettes[1] = CRGBPalette16(CHSV(baseI+hw_random8(64), 255, hw_random8(128,255)), CHSV(baseI+128, 255, hw_random8(128,255)), CHSV(baseI+hw_random8(92), 192, hw_random8(128,255)), CHSV(baseI+hw_random8(92), 255, hw_random8(128,255))); } //EVERY_N_MILLIS(10) { //(don't have to time this, effect function is only called every 24ms) @@ -4374,16 +4374,16 @@ uint16_t mode_dancing_shadows(void) } if (initialize || respawn) { - spotlights[i].colorIdx = random8(); - spotlights[i].width = random8(1, 10); + spotlights[i].colorIdx = hw_random8(); + spotlights[i].width = hw_random8(1, 10); - spotlights[i].speed = 1.0/random8(4, 50); + spotlights[i].speed = 1.0/hw_random8(4, 50); if (initialize) { - spotlights[i].position = random16(SEGLEN); - spotlights[i].speed *= random8(2) ? 1.0 : -1.0; + spotlights[i].position = hw_random16(SEGLEN); + spotlights[i].speed *= hw_random8(2) ? 1.0 : -1.0; } else { - if (random8(2)) { + if (hw_random8(2)) { spotlights[i].position = SEGLEN + spotlights[i].width; spotlights[i].speed *= -1.0; }else { @@ -4392,7 +4392,7 @@ uint16_t mode_dancing_shadows(void) } spotlights[i].lastUpdateTime = time; - spotlights[i].type = random8(SPOT_TYPES_COUNT); + spotlights[i].type = hw_random8(SPOT_TYPES_COUNT); } uint32_t color = SEGMENT.color_from_palette(spotlights[i].colorIdx, false, false, 255); @@ -4551,10 +4551,10 @@ uint16_t mode_tv_simulator(void) { // create a new sceene if (((strip.now - tvSimulator->sceeneStart) >= tvSimulator->sceeneDuration) || SEGENV.aux1 == 0) { tvSimulator->sceeneStart = strip.now; // remember the start of the new sceene - tvSimulator->sceeneDuration = random16(60* 250* colorSpeed, 60* 750 * colorSpeed); // duration of a "movie sceene" which has similar colors (5 to 15 minutes with max speed slider) - tvSimulator->sceeneColorHue = random16( 0, 768); // random start color-tone for the sceene - tvSimulator->sceeneColorSat = random8 ( 100, 130 + colorIntensity); // random start color-saturation for the sceene - tvSimulator->sceeneColorBri = random8 ( 200, 240); // random start color-brightness for the sceene + tvSimulator->sceeneDuration = hw_random16(60* 250* colorSpeed, 60* 750 * colorSpeed); // duration of a "movie sceene" which has similar colors (5 to 15 minutes with max speed slider) + tvSimulator->sceeneColorHue = hw_random16( 0, 768); // random start color-tone for the sceene + tvSimulator->sceeneColorSat = hw_random8 ( 100, 130 + colorIntensity); // random start color-saturation for the sceene + tvSimulator->sceeneColorBri = hw_random8 ( 200, 240); // random start color-brightness for the sceene SEGENV.aux1 = 1; SEGENV.aux0 = 0; } @@ -4562,16 +4562,16 @@ uint16_t mode_tv_simulator(void) { // slightly change the color-tone in this sceene if (SEGENV.aux0 == 0) { // hue change in both directions - j = random8(4 * colorIntensity); - hue = (random8() < 128) ? ((j < tvSimulator->sceeneColorHue) ? tvSimulator->sceeneColorHue - j : 767 - tvSimulator->sceeneColorHue - j) : // negative + j = hw_random8(4 * colorIntensity); + hue = (hw_random8() < 128) ? ((j < tvSimulator->sceeneColorHue) ? tvSimulator->sceeneColorHue - j : 767 - tvSimulator->sceeneColorHue - j) : // negative ((j + tvSimulator->sceeneColorHue) < 767 ? tvSimulator->sceeneColorHue + j : tvSimulator->sceeneColorHue + j - 767) ; // positive // saturation - j = random8(2 * colorIntensity); + j = hw_random8(2 * colorIntensity); sat = (tvSimulator->sceeneColorSat - j) < 0 ? 0 : tvSimulator->sceeneColorSat - j; // brightness - j = random8(100); + j = hw_random8(100); bri = (tvSimulator->sceeneColorBri - j) < 0 ? 0 : tvSimulator->sceeneColorBri - j; // calculate R,G,B from HSV @@ -4597,9 +4597,9 @@ uint16_t mode_tv_simulator(void) { SEGENV.aux0 = 1; // randomize total duration and fade duration for the actual color - tvSimulator->totalTime = random16(250, 2500); // Semi-random pixel-to-pixel time - tvSimulator->fadeTime = random16(0, tvSimulator->totalTime); // Pixel-to-pixel transition time - if (random8(10) < 3) tvSimulator->fadeTime = 0; // Force scene cut 30% of time + tvSimulator->totalTime = hw_random16(250, 2500); // Semi-random pixel-to-pixel time + tvSimulator->fadeTime = hw_random16(0, tvSimulator->totalTime); // Pixel-to-pixel transition time + if (hw_random8(10) < 3) tvSimulator->fadeTime = 0; // Force scene cut 30% of time tvSimulator->startTime = strip.now; } // end of initialization @@ -4664,15 +4664,15 @@ class AuroraWave { public: void init(uint32_t segment_length, CRGB color) { - ttl = random16(500, 1501); + ttl = hw_random16(500, 1501); basecolor = color; - basealpha = random8(60, 101) / (float)100; + basealpha = hw_random8(60, 101) / (float)100; age = 0; - width = random16(segment_length / 20, segment_length / W_WIDTH_FACTOR); //half of width to make math easier + width = hw_random16(segment_length / 20, segment_length / W_WIDTH_FACTOR); //half of width to make math easier if (!width) width = 1; - center = random8(101) / (float)100 * segment_length; - goingleft = random8(0, 2) == 0; - speed_factor = (random8(10, 31) / (float)100 * W_MAX_SPEED / 255); + center = hw_random8(101) / (float)100 * segment_length; + goingleft = hw_random8(0, 2) == 0; + speed_factor = (hw_random8(10, 31) / (float)100 * W_MAX_SPEED / 255); alive = true; } @@ -4757,7 +4757,7 @@ uint16_t mode_aurora(void) { waves = reinterpret_cast(SEGENV.data); for (int i = 0; i < SEGENV.aux1; i++) { - waves[i].init(SEGLEN, CRGB(SEGMENT.color_from_palette(random8(), false, false, random8(0, 3)))); + waves[i].init(SEGLEN, CRGB(SEGMENT.color_from_palette(hw_random8(), false, false, hw_random8(0, 3)))); } } else { waves = reinterpret_cast(SEGENV.data); @@ -4769,7 +4769,7 @@ uint16_t mode_aurora(void) { if(!(waves[i].stillAlive())) { //If a wave dies, reinitialize it starts over. - waves[i].init(SEGLEN, CRGB(SEGMENT.color_from_palette(random8(), false, false, random8(0, 3)))); + waves[i].init(SEGLEN, CRGB(SEGMENT.color_from_palette(hw_random8(), false, false, hw_random8(0, 3)))); } } @@ -5124,15 +5124,14 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https: if (SEGENV.call == 0 || strip.now - SEGMENT.step > 3000) { SEGENV.step = strip.now; SEGENV.aux0 = 0; - //random16_set_seed(millis()>>2); //seed the random generator //give the leds random state and colors (based on intensity, colors from palette or all posible colors are chosen) for (int x = 0; x < cols; x++) for (int y = 0; y < rows; y++) { - unsigned state = random8()%2; + unsigned state = hw_random8()%2; if (state == 0) SEGMENT.setPixelColorXY(x,y, backgroundColor); else - SEGMENT.setPixelColorXY(x,y, SEGMENT.color_from_palette(random8(), false, PALETTE_SOLID_WRAP, 255)); + SEGMENT.setPixelColorXY(x,y, SEGMENT.color_from_palette(hw_random8(), false, PALETTE_SOLID_WRAP, 255)); } for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) prevLeds[XY(x,y)] = CRGB::Black; @@ -5187,9 +5186,9 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https: for (int i=0; i<9 && colorsCount[i].count != 0; i++) if (colorsCount[i].count > dominantColorCount.count) dominantColorCount = colorsCount[i]; // assign the dominant color w/ a bit of randomness to avoid "gliders" - if (dominantColorCount.count > 0 && random8(128)) SEGMENT.setPixelColorXY(x,y, dominantColorCount.color); - } else if ((col == bgc) && (neighbors == 2) && !random8(128)) { // Mutation - SEGMENT.setPixelColorXY(x,y, SEGMENT.color_from_palette(random8(), false, PALETTE_SOLID_WRAP, 255)); + if (dominantColorCount.count > 0 && hw_random8(128)) SEGMENT.setPixelColorXY(x,y, dominantColorCount.color); + } else if ((col == bgc) && (neighbors == 2) && !hw_random8(128)) { // Mutation + SEGMENT.setPixelColorXY(x,y, SEGMENT.color_from_palette(hw_random8(), false, PALETTE_SOLID_WRAP, 255)); } // else do nothing! } //x,y @@ -5433,8 +5432,8 @@ uint16_t mode_2Dmatrix(void) { // Matrix2D. By Jeremy Williams. } // spawn new falling code - if (random8() <= SEGMENT.intensity || emptyScreen) { - uint8_t spawnX = random8(cols); + if (hw_random8() <= SEGMENT.intensity || emptyScreen) { + uint8_t spawnX = hw_random8(cols); SEGMENT.setPixelColorXY(spawnX, 0, spawnColor); // update hint for next run unsigned index = XY(spawnX, 0) >> 3; @@ -5787,11 +5786,11 @@ uint16_t mode_2Dspaceships(void) { //// Space ships by stepko (c)05.02.21 [ht uint32_t tb = strip.now >> 12; // every ~4s if (tb > SEGENV.step) { int dir = ++SEGENV.aux0; - dir += (int)random8(3)-1; + dir += (int)hw_random8(3)-1; if (dir > 7) SEGENV.aux0 = 0; else if (dir < 0) SEGENV.aux0 = 7; else SEGENV.aux0 = dir; - SEGENV.step = tb + random8(4); + SEGENV.step = tb + hw_random8(4); } SEGMENT.fadeToBlackBy(map(SEGMENT.speed, 0, 255, 248, 16)); @@ -5921,9 +5920,8 @@ uint16_t mode_2Dghostrider(void) { if (SEGENV.aux0 != cols || SEGENV.aux1 != rows) { SEGENV.aux0 = cols; SEGENV.aux1 = rows; - //random16_set_seed(strip.now); - lighter->angleSpeed = random8(0,20) - 10; - lighter->gAngle = random16(); + lighter->angleSpeed = hw_random8(0,20) - 10; + lighter->gAngle = hw_random16(); lighter->Vspeed = 5; lighter->gPosX = (cols/2) * 10; lighter->gPosY = (rows/2) * 10; @@ -5951,7 +5949,7 @@ uint16_t mode_2Dghostrider(void) { if (lighter->gPosY < 0) lighter->gPosY = (rows - 1) * 10; if (lighter->gPosY > (rows - 1) * 10) lighter->gPosY = 0; for (size_t i = 0; i < maxLighters; i++) { - lighter->time[i] += random8(5, 20); + lighter->time[i] += hw_random8(5, 20); if (lighter->time[i] >= 255 || (lighter->lightersPosX[i] <= 0) || (lighter->lightersPosX[i] >= (cols - 1) * 10) || @@ -5962,7 +5960,7 @@ uint16_t mode_2Dghostrider(void) { if (lighter->reg[i]) { lighter->lightersPosY[i] = lighter->gPosY; lighter->lightersPosX[i] = lighter->gPosX; - lighter->Angle[i] = lighter->gAngle + ((int)random8(20) - 10); + lighter->Angle[i] = lighter->gAngle + ((int)hw_random8(20) - 10); lighter->time[i] = 0; lighter->reg[i] = false; } else { @@ -6008,12 +6006,12 @@ uint16_t mode_2Dfloatingblobs(void) { SEGENV.aux1 = rows; //SEGMENT.fill(BLACK); for (size_t i = 0; i < MAX_BLOBS; i++) { - blob->r[i] = random8(1, cols>8 ? (cols/4) : 2); - blob->sX[i] = (float) random8(3, cols) / (float)(256 - SEGMENT.speed); // speed x - blob->sY[i] = (float) random8(3, rows) / (float)(256 - SEGMENT.speed); // speed y - blob->x[i] = random8(0, cols-1); - blob->y[i] = random8(0, rows-1); - blob->color[i] = random8(); + blob->r[i] = hw_random8(1, cols>8 ? (cols/4) : 2); + blob->sX[i] = (float) hw_random8(3, cols) / (float)(256 - SEGMENT.speed); // speed x + blob->sY[i] = (float) hw_random8(3, rows) / (float)(256 - SEGMENT.speed); // speed y + blob->x[i] = hw_random8(0, cols-1); + blob->y[i] = hw_random8(0, rows-1); + blob->color[i] = hw_random8(); blob->grow[i] = (blob->r[i] < 1.f); if (blob->sX[i] == 0) blob->sX[i] = 1; if (blob->sY[i] == 0) blob->sY[i] = 1; @@ -6052,19 +6050,19 @@ uint16_t mode_2Dfloatingblobs(void) { else blob->y[i] += blob->sY[i]; // bounce x if (blob->x[i] < 0.01f) { - blob->sX[i] = (float)random8(3, cols) / (256 - SEGMENT.speed); + blob->sX[i] = (float)hw_random8(3, cols) / (256 - SEGMENT.speed); blob->x[i] = 0.01f; } else if (blob->x[i] > (float)cols - 1.01f) { - blob->sX[i] = (float)random8(3, cols) / (256 - SEGMENT.speed); + blob->sX[i] = (float)hw_random8(3, cols) / (256 - SEGMENT.speed); blob->sX[i] = -blob->sX[i]; blob->x[i] = (float)cols - 1.01f; } // bounce y if (blob->y[i] < 0.01f) { - blob->sY[i] = (float)random8(3, rows) / (256 - SEGMENT.speed); + blob->sY[i] = (float)hw_random8(3, rows) / (256 - SEGMENT.speed); blob->y[i] = 0.01f; } else if (blob->y[i] > (float)rows - 1.01f) { - blob->sY[i] = (float)random8(3, rows) / (256 - SEGMENT.speed); + blob->sY[i] = (float)hw_random8(3, rows) / (256 - SEGMENT.speed); blob->sY[i] = -blob->sY[i]; blob->y[i] = (float)rows - 1.01f; } @@ -6306,13 +6304,13 @@ uint16_t mode_ripplepeak(void) { // * Ripple peak. By Andrew Tuli break; case 255: // Initialize ripple variables. - ripples[i].pos = random16(SEGLEN); + ripples[i].pos = hw_random16(SEGLEN); #ifdef ESP32 if (FFT_MajorPeak > 1) // log10(0) is "forbidden" (throws exception) ripples[i].color = (int)(log10f(FFT_MajorPeak)*128); else ripples[i].color = 0; #else - ripples[i].color = random8(); + ripples[i].color = hw_random8(); #endif ripples[i].state = 0; break; @@ -6760,7 +6758,7 @@ uint16_t mode_puddles_base(bool peakdetect) { if (SEGLEN == 1) return mode_static(); unsigned size = 0; uint8_t fadeVal = map(SEGMENT.speed, 0, 255, 224, 254); - unsigned pos = random16(SEGLEN); // Set a random starting position. + unsigned pos = hw_random16(SEGLEN); // Set a random starting position. SEGMENT.fade_out(fadeVal); um_data_t *um_data = getAudioData(); @@ -6823,7 +6821,7 @@ uint16_t mode_pixels(void) { // Pixels. By Andrew Tuline. SEGMENT.fade_out(64+(SEGMENT.speed>>1)); for (int i=0; i SPEED_FORMULA_L) { - unsigned segLoc = random16(SEGLEN); + unsigned segLoc = hw_random16(SEGLEN); SEGMENT.setPixelColor(segLoc, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(2*fftResult[SEGENV.aux0%16]*240/max(1, (int)SEGLEN-1), false, PALETTE_SOLID_WRAP, 0), uint8_t(2*fftResult[SEGENV.aux0%16]))); ++(SEGENV.aux0) %= 16; // make sure it doesn't cross 16 @@ -7005,7 +7003,7 @@ uint16_t mode_freqpixels(void) { // Freqpixel. By Andrew Tuline. uint8_t pixCol = (log10f(FFT_MajorPeak) - 1.78f) * 255.0f/(MAX_FREQ_LOG10 - 1.78f); // Scale log10 of frequency values to the 255 colour index. if (FFT_MajorPeak < 61.0f) pixCol = 0; // handle underflow for (int i=0; i < SEGMENT.intensity/32+1; i++) { - unsigned locn = random16(0,SEGLEN); + unsigned locn = hw_random16(0,SEGLEN); SEGMENT.setPixelColor(locn, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(SEGMENT.intensity+pixCol, false, PALETTE_SOLID_WRAP, 0), (uint8_t)my_magnitude)); } @@ -7473,9 +7471,9 @@ uint16_t mode_2Dsoap() { // init if (SEGENV.call == 0) { - *noise32_x = random16(); - *noise32_y = random16(); - *noise32_z = random16(); + *noise32_x = hw_random(); + *noise32_y = hw_random(); + *noise32_z = hw_random(); } else { *noise32_x += mov; *noise32_y += mov; diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 5c4b9ac4..e64cf675 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -124,86 +124,86 @@ void setRandomColor(byte* rgb) */ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) { - CHSV palettecolors[4]; //array of colors for the new palette - uint8_t keepcolorposition = random8(4); //color position of current random palette to keep - palettecolors[keepcolorposition] = rgb2hsv(basepalette.entries[keepcolorposition*5]); //read one of the base colors of the current palette - palettecolors[keepcolorposition].hue += random8(10)-5; // +/- 5 randomness of base color - //generate 4 saturation and brightness value numbers - //only one saturation is allowed to be below 200 creating mostly vibrant colors - //only one brightness value number is allowed below 200, creating mostly bright palettes + CHSV palettecolors[4]; // array of colors for the new palette + uint8_t keepcolorposition = hw_random8(4); // color position of current random palette to keep + palettecolors[keepcolorposition] = rgb2hsv(basepalette.entries[keepcolorposition*5]); // read one of the base colors of the current palette + palettecolors[keepcolorposition].hue += hw_random8(10)-5; // +/- 5 randomness of base color + // generate 4 saturation and brightness value numbers + // only one saturation is allowed to be below 200 creating mostly vibrant colors + // only one brightness value number is allowed below 200, creating mostly bright palettes - for (int i = 0; i < 3; i++) { //generate three high values - palettecolors[i].saturation = random8(200,255); - palettecolors[i].value = random8(220,255); + for (int i = 0; i < 3; i++) { // generate three high values + palettecolors[i].saturation = hw_random8(200,255); + palettecolors[i].value = hw_random8(220,255); } - //allow one to be lower - palettecolors[3].saturation = random8(20,255); - palettecolors[3].value = random8(80,255); + // allow one to be lower + palettecolors[3].saturation = hw_random8(20,255); + palettecolors[3].value = hw_random8(80,255); - //shuffle the arrays + // shuffle the arrays for (int i = 3; i > 0; i--) { - std::swap(palettecolors[i].saturation, palettecolors[random8(i + 1)].saturation); - std::swap(palettecolors[i].value, palettecolors[random8(i + 1)].value); + std::swap(palettecolors[i].saturation, palettecolors[hw_random8(i + 1)].saturation); + std::swap(palettecolors[i].value, palettecolors[hw_random8(i + 1)].value); } - //now generate three new hues based off of the hue of the chosen current color + // now generate three new hues based off of the hue of the chosen current color uint8_t basehue = palettecolors[keepcolorposition].hue; - uint8_t harmonics[3]; //hues that are harmonic but still a little random - uint8_t type = random8(5); //choose a harmony type + uint8_t harmonics[3]; // hues that are harmonic but still a little random + uint8_t type = hw_random8(5); // choose a harmony type switch (type) { case 0: // analogous - harmonics[0] = basehue + random8(30, 50); - harmonics[1] = basehue + random8(10, 30); - harmonics[2] = basehue - random8(10, 30); + harmonics[0] = basehue + hw_random8(30, 50); + harmonics[1] = basehue + hw_random8(10, 30); + harmonics[2] = basehue - hw_random8(10, 30); break; case 1: // triadic - harmonics[0] = basehue + 113 + random8(15); - harmonics[1] = basehue + 233 + random8(15); - harmonics[2] = basehue - 7 + random8(15); + harmonics[0] = basehue + 113 + hw_random8(15); + harmonics[1] = basehue + 233 + hw_random8(15); + harmonics[2] = basehue - 7 + hw_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[0] = basehue + 145 + hw_random8(10); + harmonics[1] = basehue + 205 + hw_random8(10); + harmonics[2] = basehue - 5 + hw_random8(10); break; case 3: // square - harmonics[0] = basehue + 85 + random8(10); - harmonics[1] = basehue + 175 + random8(10); - harmonics[2] = basehue + 265 + random8(10); + harmonics[0] = basehue + 85 + hw_random8(10); + harmonics[1] = basehue + 175 + hw_random8(10); + harmonics[2] = basehue + 265 + hw_random8(10); break; case 4: // tetradic - harmonics[0] = basehue + 80 + random8(20); - harmonics[1] = basehue + 170 + random8(20); - harmonics[2] = basehue - 15 + random8(30); + harmonics[0] = basehue + 80 + hw_random8(20); + harmonics[1] = basehue + 170 + hw_random8(20); + harmonics[2] = basehue - 15 + hw_random8(30); break; } - if (random8() < 128) { - //50:50 chance of shuffling hues or keep the color order + if (hw_random8() < 128) { + // 50:50 chance of shuffling hues or keep the color order for (int i = 2; i > 0; i--) { - std::swap(harmonics[i], harmonics[random8(i + 1)]); + std::swap(harmonics[i], harmonics[hw_random8(i + 1)]); } } - //now set the hues + // now set the hues int j = 0; for (int i = 0; i < 4; i++) { - if (i==keepcolorposition) continue; //skip the base color + if (i==keepcolorposition) continue; // skip the base color palettecolors[i].hue = harmonics[j]; j++; } bool makepastelpalette = false; - if (random8() < 25) { //~10% chance of desaturated 'pastel' colors + if (hw_random8() < 25) { // ~10% chance of desaturated 'pastel' colors makepastelpalette = true; } - //apply saturation & gamma correction + // apply saturation & gamma correction CRGB RGBpalettecolors[4]; for (int i = 0; i < 4; i++) { if (makepastelpalette && palettecolors[i].saturation > 180) { @@ -219,12 +219,12 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) RGBpalettecolors[3]); } -CRGBPalette16 generateRandomPalette() //generate fully random palette +CRGBPalette16 generateRandomPalette() // generate fully random palette { - return CRGBPalette16(CHSV(random8(), random8(160, 255), random8(128, 255)), - CHSV(random8(), random8(160, 255), random8(128, 255)), - CHSV(random8(), random8(160, 255), random8(128, 255)), - CHSV(random8(), random8(160, 255), random8(128, 255))); + return CRGBPalette16(CHSV(hw_random8(), hw_random8(160, 255), hw_random8(128, 255)), + CHSV(hw_random8(), hw_random8(160, 255), hw_random8(128, 255)), + CHSV(hw_random8(), hw_random8(160, 255), hw_random8(128, 255)), + CHSV(hw_random8(), hw_random8(160, 255), hw_random8(128, 255))); } void hsv2rgb(const CHSV32& hsv, uint32_t& rgb) // convert HSV (16bit hue) to RGB (32bit with white = 0) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index c98eef5c..bc5206b7 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -458,6 +458,12 @@ void userConnected(); void userLoop(); //util.cpp +#ifdef ESP8266 +#define HW_RND_REGISTER RANDOM_REG32 +#else // ESP32 family +#include "soc/wdev_reg.h" +#define HW_RND_REGISTER REG_READ(WDEV_RND_REG) +#endif int getNumVal(const String* req, uint16_t pos); void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255); bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255); // getVal supports inc/decrementing and random ("X~Y(r|~[w][-][Z])" form) @@ -485,6 +491,23 @@ void enumerateLedmaps(); uint8_t get_random_wheel_index(uint8_t pos); float mapf(float x, float in_min, float in_max, float out_min, float out_max); +// fast (true) random numbers using hardware RNG, all functions return values in the range lowerlimit to upperlimit-1 +// note: for true random numbers with high entropy, do not call faster than every 200ns (5MHz) +// tests show it is still highly random reading it quickly in a loop (better than fastled PRNG) +// for 8bit and 16bit random functions: no limit check is done for best speed +// 32bit inputs are used for speed and code size, limits don't work if inverted or out of range +// inlining does save code size except for random(a,b) and 32bit random with limits +#define random hw_random // replace arduino random() +inline uint32_t hw_random() { return HW_RND_REGISTER; }; +uint32_t hw_random(uint32_t upperlimit); // not inlined for code size +int32_t hw_random(int32_t lowerlimit, int32_t upperlimit); +inline uint16_t hw_random16() { return HW_RND_REGISTER; }; +inline uint16_t hw_random16(uint32_t upperlimit) { return (hw_random16() * upperlimit) >> 16; }; // input range 0-65535 (uint16_t) +inline int16_t hw_random16(int32_t lowerlimit, int32_t upperlimit) { int32_t range = upperlimit - lowerlimit; return lowerlimit + hw_random16(range); }; // signed limits, use int16_t ranges +inline uint8_t hw_random8() { return HW_RND_REGISTER; }; +inline uint8_t hw_random8(uint32_t upperlimit) { return (hw_random8() * upperlimit) >> 8; }; // input range 0-255 +inline uint8_t hw_random8(uint32_t lowerlimit, uint32_t upperlimit) { uint32_t range = upperlimit - lowerlimit; return lowerlimit + hw_random8(range); }; // input range 0-255 + // RAII guard class for the JSON Buffer lock // Modeled after std::lock_guard class JSONBufferGuard { diff --git a/wled00/ir.cpp b/wled00/ir.cpp index 48061238..f01e2c32 100644 --- a/wled00/ir.cpp +++ b/wled00/ir.cpp @@ -593,7 +593,7 @@ static void decodeIRJson(uint32_t code) decBrightness(); } else if (cmdStr.startsWith(F("!presetF"))) { //!presetFallback uint8_t p1 = fdo["PL"] | 1; - uint8_t p2 = fdo["FX"] | random8(strip.getModeCount() -1); + uint8_t p2 = fdo["FX"] | hw_random8(strip.getModeCount() -1); uint8_t p3 = fdo["FP"] | 0; presetFallback(p1, p2, p3); } diff --git a/wled00/remote.cpp b/wled00/remote.cpp index 9bc5430c..eb19cc1f 100644 --- a/wled00/remote.cpp +++ b/wled00/remote.cpp @@ -146,7 +146,7 @@ static bool remoteJson(int button) parsed = true; } else if (cmdStr.startsWith(F("!presetF"))) { //!presetFallback uint8_t p1 = fdo["PL"] | 1; - uint8_t p2 = fdo["FX"] | random8(strip.getModeCount() -1); + uint8_t p2 = fdo["FX"] | hw_random8(strip.getModeCount() -1); uint8_t p3 = fdo["FP"] | 0; presetWithFallback(p1, p2, p3); parsed = true; diff --git a/wled00/util.cpp b/wled00/util.cpp index 41e3d6c2..d9f1c00b 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -14,7 +14,7 @@ int getNumVal(const String* req, uint16_t pos) void parseNumber(const char* str, byte* val, byte minv, byte maxv) { if (str == nullptr || str[0] == '\0') return; - if (str[0] == 'r') {*val = random8(minv,maxv?maxv:255); return;} // maxv for random cannot be 0 + if (str[0] == 'r') {*val = hw_random8(minv,maxv?maxv:255); return;} // maxv for random cannot be 0 bool wrap = false; if (str[0] == 'w' && strlen(str) > 1) {str++; wrap = true;} if (str[0] == '~') { @@ -474,9 +474,9 @@ um_data_t* simulateSound(uint8_t simulationId) break; case UMS_WeWillRockYou: if (ms%2000 < 200) { - volumeSmth = random8(255); + volumeSmth = hw_random8(); for (int i = 0; i<5; i++) - fftResult[i] = random8(255); + fftResult[i] = hw_random8(); } else if (ms%2000 < 400) { volumeSmth = 0; @@ -484,9 +484,9 @@ um_data_t* simulateSound(uint8_t simulationId) fftResult[i] = 0; } else if (ms%2000 < 600) { - volumeSmth = random8(255); + volumeSmth = hw_random8(); for (int i = 5; i<11; i++) - fftResult[i] = random8(255); + fftResult[i] = hw_random8(); } else if (ms%2000 < 800) { volumeSmth = 0; @@ -494,9 +494,9 @@ um_data_t* simulateSound(uint8_t simulationId) fftResult[i] = 0; } else if (ms%2000 < 1000) { - volumeSmth = random8(255); + volumeSmth = hw_random8(); for (int i = 11; i<16; i++) - fftResult[i] = random8(255); + fftResult[i] = hw_random8(); } else { volumeSmth = 0; @@ -516,7 +516,7 @@ um_data_t* simulateSound(uint8_t simulationId) break; } - samplePeak = random8() > 250; + samplePeak = hw_random8() > 250; FFT_MajorPeak = 21 + (volumeSmth*volumeSmth) / 8.0f; // walk thru full range of 21hz...8200hz maxVol = 31; // this gets feedback fro UI binNum = 8; // this gets feedback fro UI @@ -582,7 +582,7 @@ void enumerateLedmaps() { uint8_t get_random_wheel_index(uint8_t pos) { uint8_t r = 0, x = 0, y = 0, d = 0; while (d < 42) { - r = random8(); + r = hw_random8(); x = abs(pos - r); y = 255 - x; d = MIN(x, y); @@ -594,3 +594,18 @@ uint8_t get_random_wheel_index(uint8_t pos) { float mapf(float x, float in_min, float in_max, float out_min, float out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } + +// 32 bit random number generator, inlining uses more code, use hw_random16() if speed is critical (see fcn_declare.h) +uint32_t hw_random(uint32_t upperlimit) { + uint32_t rnd = hw_random(); + uint64_t scaled = uint64_t(rnd) * uint64_t(upperlimit); + return scaled >> 32; +} + +int32_t hw_random(int32_t lowerlimit, int32_t upperlimit) { + if(lowerlimit >= upperlimit) { + return lowerlimit; + } + uint32_t diff = upperlimit - lowerlimit; + return hw_random(diff) + lowerlimit; +} \ No newline at end of file diff --git a/wled00/wled.cpp b/wled00/wled.cpp index afed485e..1f978a39 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -544,14 +544,8 @@ void WLED::setup() #endif // Seed FastLED random functions with an esp random value, which already works properly at this point. -#if defined(ARDUINO_ARCH_ESP32) - const uint32_t seed32 = esp_random(); -#elif defined(ARDUINO_ARCH_ESP8266) - const uint32_t seed32 = RANDOM_REG32; -#else - const uint32_t seed32 = random(std::numeric_limits::max()); -#endif - random16_set_seed((uint16_t)((seed32 & 0xFFFF) ^ (seed32 >> 16))); + const uint32_t seed32 = hw_random(); + random16_set_seed((uint16_t)seed32); #if WLED_WATCHDOG_TIMEOUT > 0 enableWatchdog(); From 099d3f7b414d48ca264a3fcb6a208a50fb7ef6d1 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 20 Dec 2024 18:14:30 +0000 Subject: [PATCH 092/463] version bump --- package-lock.json | 7 +++++-- package.json | 2 +- wled00/wled.h | 1 - 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index db709485..0afeeaaf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,21 @@ { "name": "wled", - "version": "0.15.0-b7", + "version": "0.16.0-dev", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "wled", - "version": "0.15.0-b7", + "version": "0.16.0-dev", "license": "ISC", "dependencies": { "clean-css": "^5.3.3", "html-minifier-terser": "^7.2.0", "inliner": "^1.13.1", "nodemon": "^3.1.7" + }, + "engines": { + "node": ">=20.0.0" } }, "node_modules/@jridgewell/gen-mapping": { diff --git a/package.json b/package.json index fbcb8ed8..91e2a615 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wled", - "version": "0.15.0-dev", + "version": "0.16.0-dev", "description": "Tools for WLED project", "main": "tools/cdata.js", "directories": { diff --git a/wled00/wled.h b/wled00/wled.h index 94d52a8d..d0cee80d 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -3,7 +3,6 @@ /* Main sketch, global variable declarations @title WLED project sketch - @version 0.15.0-dev @author Christian Schwinne */ From 1711286ef010490ce4dd884949206de72dde10fb Mon Sep 17 00:00:00 2001 From: wled-install <96419931+wled-install@users.noreply.github.com> Date: Sat, 21 Dec 2024 23:05:13 +0100 Subject: [PATCH 093/463] Update usermods_list.cpp --- wled00/usermods_list.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp index 36bd122a..3283e013 100644 --- a/wled00/usermods_list.cpp +++ b/wled00/usermods_list.cpp @@ -45,7 +45,7 @@ #endif #ifdef USERMOD_BH1750 - #include "../usermods/BH1750_v2/usermod_BH1750.h" + #include "../usermods/BH1750_v2/usermod_bh1750.h" #endif // BME280 v2 usermod. Define "USERMOD_BME280" in my_config.h From 97bbe6f3050e3101ba15fa3b0c6daad23f036946 Mon Sep 17 00:00:00 2001 From: shafingazi <34550119+shafingazi@users.noreply.github.com> Date: Sat, 21 Dec 2024 21:18:57 -0800 Subject: [PATCH 094/463] fixed typo in LED Preferences Changed "poweing" to "powering" within a text block of LED Preferences. --- wled00/data/settings_leds.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index d06e8d3c..956cf7d9 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -761,7 +761,7 @@ Swap:
Automatically limits brightness to stay close to the limit.
- Keep at <1A if poweing LEDs directly from the ESP 5V pin!
+ Keep at <1A if powering LEDs directly from the ESP 5V pin!
If using multiple outputs it is recommended to use per-output limiter.
Analog (PWM) and virtual LEDs cannot use automatic brightness limiter.
Maximum PSU Current: mA
From 0ad65f474898c94227917634e86f7236ade80760 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 23 Dec 2024 14:57:22 +0100 Subject: [PATCH 095/463] fixed CIE brightness calculation for PWM outputs --- wled00/bus_manager.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index d19cb519..2c0ba41a 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -563,19 +563,15 @@ void BusPwm::show() { const unsigned maxBri = (1<<_depth); // possible values: 16384 (14), 8192 (13), 4096 (12), 2048 (11), 1024 (10), 512 (9) and 256 (8) [[maybe_unused]] const unsigned bitShift = dithering * 4; // if dithering, _depth is 12 bit but LEDC channel is set to 8 bit (using 4 fractional bits) - // use CIE brightness formula (cubic) to fit (or approximate linearity of) human eye perceived brightness - // the formula is based on 12 bit resolution as there is no need for greater precision + // use CIE brightness formula (linear + cubic) to approximate human eye perceived brightness // see: https://en.wikipedia.org/wiki/Lightness - unsigned pwmBri = (unsigned)_bri * 100; // enlarge to use integer math for linear response - if (pwmBri < 2040) { - // linear response for values [0-20] - pwmBri = ((pwmBri << 12) + 115043) / 230087; //adding '0.5' before division for correct rounding - } else { - // cubic response for values [21-255] - pwmBri += 4080; - float temp = (float)pwmBri / 29580.0f; - temp = temp * temp * temp * (float)maxBri; - pwmBri = (unsigned)temp; // pwmBri is in range [0-maxBri] + unsigned pwmBri = _bri; + if (pwmBri < 21) { // linear response for values [0-20] + pwmBri = (pwmBri * maxBri + 2300 / 2) / 2300 ; // adding '0.5' before division for correct rounding, 2300 gives a good match to CIE curve + } else { // cubic response for values [21-255] + float temp = float(pwmBri + 41) / float(255 + 41); // 41 is to match offset & slope to linear part + temp = temp * temp * temp * (float)maxBri; + pwmBri = (unsigned)temp; // pwmBri is in range [0-maxBri] C } [[maybe_unused]] unsigned hPoint = 0; // phase shift (0 - maxBri) From 97e8382a4179cbdde56f25b95de791a59e8cc4dd Mon Sep 17 00:00:00 2001 From: Malachi Soord Date: Tue, 24 Dec 2024 11:01:14 +0100 Subject: [PATCH 096/463] Use consistent node version --- .github/workflows/build.yml | 3 ++- .nvmrc | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 .nvmrc diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e5fdfc5a..2bac314f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,6 +38,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: + node-version-file: '.nvmrc' cache: 'npm' - run: npm ci - name: Cache PlatformIO @@ -74,7 +75,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v4 with: - node-version: '20.x' + node-version-file: '.nvmrc' cache: 'npm' - run: npm ci - run: npm test diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..d4b7699d --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +20.18.1 From a2d84886c0569f52768f11cc09ca6cfeb32ef3cc Mon Sep 17 00:00:00 2001 From: Malachi Soord Date: Tue, 24 Dec 2024 13:55:10 +0100 Subject: [PATCH 097/463] Update .nvmrc --- .nvmrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nvmrc b/.nvmrc index d4b7699d..10fef252 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -20.18.1 +20.18 From 1a82a3bf7b5ed515c86838fa60a17dfcea033be5 Mon Sep 17 00:00:00 2001 From: Malachi Soord Date: Tue, 24 Dec 2024 20:30:54 +0000 Subject: [PATCH 098/463] Fix devcontainer --- .devcontainer/Dockerfile | 7 +------ .devcontainer/devcontainer.json | 7 ++----- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index d09c8a60..1340da91 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -2,12 +2,7 @@ # [Choice] Python version: 3, 3.9, 3.8, 3.7, 3.6 ARG VARIANT="3" -FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT} - -# [Option] Install Node.js -ARG INSTALL_NODE="true" -ARG NODE_VERSION="lts/*" -RUN if [ "${INSTALL_NODE}" = "true" ]; then su vscode -c "source /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi +FROM mcr.microsoft.com/devcontainers/python:0-${VARIANT} # [Optional] If your pip requirements rarely change, uncomment this section to add them to the image. # COPY requirements.txt /tmp/pip-tmp/ diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 2a8e4712..241acd79 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -5,10 +5,7 @@ "context": "..", "args": { // Update 'VARIANT' to pick a Python version: 3, 3.6, 3.7, 3.8, 3.9 - "VARIANT": "3", - // Options - "INSTALL_NODE": "true", - "NODE_VERSION": "lts/*" + "VARIANT": "3" } }, @@ -54,7 +51,7 @@ // "forwardPorts": [], // Use 'postCreateCommand' to run commands after the container is created. - "postCreateCommand": "npm install", + "postCreateCommand": "bash -i -c 'nvm install && npm ci'", // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. "remoteUser": "vscode" From 0ac627dfbb21a153a218009f3ed1374ea2bd9330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Wed, 25 Dec 2024 10:40:16 +0100 Subject: [PATCH 099/463] FX: Waterfall and Matripix fix - for Arc expansion - or gaps - or ledmaps with missing pixels --- wled00/FX.cpp | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index fd2118fd..295f2e9a 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -6639,14 +6639,16 @@ static const char _data_FX_MODE_JUGGLES[] PROGMEM = "Juggles@!,# of balls;!,!;!; // * MATRIPIX // ////////////////////// 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 + // effect can work on single pixels, we just lose the shifting effect + unsigned dataSize = sizeof(uint32_t) * SEGLEN; + if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed + uint32_t* pixels = reinterpret_cast(SEGENV.data); um_data_t *um_data = getAudioData(); int volumeRaw = *(int16_t*)um_data->u_data[1]; if (SEGENV.call == 0) { - SEGMENT.fill(BLACK); + for (int i = 0; i < SEGLEN; i++) pixels[i] = BLACK; // may not be needed as resetIfRequired() clears buffer } uint8_t secondHand = micros()/(256-SEGMENT.speed)/500 % 16; @@ -6654,8 +6656,14 @@ uint16_t mode_matripix(void) { // Matripix. By Andrew Tuline. SEGENV.aux0 = secondHand; int pixBri = volumeRaw * SEGMENT.intensity / 64; - for (int i = 0; i < SEGLEN-1; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // shift left - SEGMENT.setPixelColor(SEGLEN-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0), pixBri)); + unsigned k = SEGLEN-1; + // loop will not execute if SEGLEN equals 1 + for (unsigned i = 0; i < k; i++) { + pixels[i] = pixels[i+1]; // shift left + SEGMENT.setPixelColor(i, pixels[i]); + } + pixels[k] = color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(strip.now, false, PALETTE_SOLID_WRAP, 0), pixBri); + SEGMENT.setPixelColor(k, pixels[k]); } return FRAMETIME; @@ -7283,8 +7291,11 @@ static const char _data_FX_MODE_ROCKTAVES[] PROGMEM = "Rocktaves@;!,!;!;01f;m12= // Combines peak detection with FFT_MajorPeak and FFT_Magnitude. 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 = getAudioData(); + unsigned dataSize = sizeof(uint32_t) * SEGLEN; + if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed + uint32_t* pixels = reinterpret_cast(SEGENV.data); + + 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]; @@ -7294,7 +7305,7 @@ uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tulin if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; // log10(0) is "forbidden" (throws exception) if (SEGENV.call == 0) { - SEGMENT.fill(BLACK); + for (int i = 0; i < SEGLEN; i++) pixels[i] = BLACK; // may not be needed as resetIfRequired() clears buffer SEGENV.aux0 = 255; SEGMENT.custom1 = *binNum; SEGMENT.custom2 = *maxVol * 2; @@ -7311,13 +7322,18 @@ uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tulin uint8_t pixCol = (log10f(FFT_MajorPeak) - 2.26f) * 150; // 22Khz sampling - log10 frequency range is from 2.26 (182hz) to 3.967 (9260hz). Let's scale accordingly. if (FFT_MajorPeak < 182.0f) pixCol = 0; // handle underflow + int k = SEGLEN-1; if (samplePeak) { - SEGMENT.setPixelColor(SEGLEN-1, CHSV(92,92,92)); + pixels[k] = (uint32_t)CRGB(CHSV(92,92,92)); } else { - SEGMENT.setPixelColor(SEGLEN-1, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(pixCol+SEGMENT.intensity, false, PALETTE_SOLID_WRAP, 0), (int)my_magnitude)); + pixels[k] = color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(pixCol+SEGMENT.intensity, false, PALETTE_SOLID_WRAP, 0), (int)my_magnitude); } + SEGMENT.setPixelColor(k, pixels[k]); // loop will not execute if SEGLEN equals 1 - for (int i = 0; i < SEGLEN-1; i++) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i+1)); // shift left + for (unsigned i = 0; i < k; i++) { + pixels[i] = pixels[i+1]; // shift left + SEGMENT.setPixelColor(i, pixels[i]); + } } return FRAMETIME; From 0441ede2299bc286dadf23383c3d1613c5ce8823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Wed, 25 Dec 2024 15:18:34 +0100 Subject: [PATCH 100/463] Fix for #4401 --- wled00/FX.cpp | 32 +++++++++++++------------------- wled00/led.cpp | 5 ++--- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 394b5df0..da7b0c4b 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -642,11 +642,12 @@ static const char _data_FX_MODE_TWINKLE[] PROGMEM = "Twinkle@!,!;!,!;!;;m12=0"; * Dissolve function */ uint16_t dissolve(uint32_t color) { - unsigned dataSize = (SEGLEN+7) >> 3; //1 bit per LED + unsigned dataSize = sizeof(uint32_t) * SEGLEN; if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed + uint32_t* pixels = reinterpret_cast(SEGENV.data); if (SEGENV.call == 0) { - memset(SEGMENT.data, 0xFF, dataSize); // start by fading pixels up + for (unsigned i = 0; i < SEGLEN; i++) pixels[i] = SEGCOLOR(1); SEGENV.aux0 = 1; } @@ -654,33 +655,26 @@ uint16_t dissolve(uint32_t color) { if (hw_random8() <= SEGMENT.intensity) { for (size_t times = 0; times < 10; times++) { //attempt to spawn a new pixel 10 times unsigned i = hw_random16(SEGLEN); - unsigned index = i >> 3; - unsigned bitNum = i & 0x07; - bool fadeUp = bitRead(SEGENV.data[index], bitNum); if (SEGENV.aux0) { //dissolve to primary/palette - if (fadeUp) { - if (color == SEGCOLOR(0)) { - SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); - } else { - SEGMENT.setPixelColor(i, color); - } - bitWrite(SEGENV.data[index], bitNum, false); + if (pixels[i] == SEGCOLOR(1)) { + pixels[i] = color == SEGCOLOR(0) ? SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0) : color; break; //only spawn 1 new pixel per frame per 50 LEDs } } else { //dissolve to secondary - if (!fadeUp) { - SEGMENT.setPixelColor(i, SEGCOLOR(1)); break; - bitWrite(SEGENV.data[index], bitNum, true); + if (pixels[i] != SEGCOLOR(1)) { + pixels[i] = SEGCOLOR(1); + break; } } } } } + // fix for #4401 + for (unsigned i = 0; i < SEGLEN; i++) SEGMENT.setPixelColor(i, pixels[i]); if (SEGENV.step > (255 - SEGMENT.speed) + 15U) { SEGENV.aux0 = !SEGENV.aux0; SEGENV.step = 0; - memset(SEGMENT.data, (SEGENV.aux0 ? 0xFF : 0), dataSize); // switch fading } else { SEGENV.step++; } @@ -6577,7 +6571,7 @@ uint16_t mode_matripix(void) { // Matripix. By Andrew Tuline. int volumeRaw = *(int16_t*)um_data->u_data[1]; if (SEGENV.call == 0) { - for (int i = 0; i < SEGLEN; i++) pixels[i] = BLACK; // may not be needed as resetIfRequired() clears buffer + for (unsigned i = 0; i < SEGLEN; i++) pixels[i] = BLACK; // may not be needed as resetIfRequired() clears buffer } uint8_t secondHand = micros()/(256-SEGMENT.speed)/500 % 16; @@ -7161,7 +7155,7 @@ uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tulin if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; // log10(0) is "forbidden" (throws exception) if (SEGENV.call == 0) { - for (int i = 0; i < SEGLEN; i++) pixels[i] = BLACK; // may not be needed as resetIfRequired() clears buffer + for (unsigned i = 0; i < SEGLEN; i++) pixels[i] = BLACK; // may not be needed as resetIfRequired() clears buffer SEGENV.aux0 = 255; SEGMENT.custom1 = *binNum; SEGMENT.custom2 = *maxVol * 2; @@ -7178,7 +7172,7 @@ uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tulin uint8_t pixCol = (log10f(FFT_MajorPeak) - 2.26f) * 150; // 22Khz sampling - log10 frequency range is from 2.26 (182hz) to 3.967 (9260hz). Let's scale accordingly. if (FFT_MajorPeak < 182.0f) pixCol = 0; // handle underflow - int k = SEGLEN-1; + unsigned k = SEGLEN-1; if (samplePeak) { pixels[k] = (uint32_t)CRGB(CHSV(92,92,92)); } else { diff --git a/wled00/led.cpp b/wled00/led.cpp index 68169509..8b34bbf0 100644 --- a/wled00/led.cpp +++ b/wled00/led.cpp @@ -73,8 +73,7 @@ byte scaledBri(byte in) //applies global brightness void applyBri() { - if (!realtimeMode || !arlsForceMaxBri) - { + if (!(realtimeMode && arlsForceMaxBri)) { //DEBUG_PRINTF_P(PSTR("Applying strip brightness: %d (%d,%d)\n"), (int)briT, (int)bri, (int)briOld); strip.setBrightness(scaledBri(briT)); } @@ -86,6 +85,7 @@ void applyFinalBri() { briOld = bri; briT = bri; applyBri(); + strip.trigger(); } @@ -146,7 +146,6 @@ void stateUpdated(byte callMode) { transitionStartTime = millis(); } else { applyFinalBri(); - strip.trigger(); } } From 272129f66c78035c766b93b95bc3cec035a04ef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sat, 21 Dec 2024 19:02:24 +0100 Subject: [PATCH 101/463] Add ability to enter desired BSSID - add event handling (debug) - fixes #2151 --- wled00/cfg.cpp | 16 ++- wled00/data/settings_wifi.htm | 3 +- wled00/fcn_declare.h | 10 +- wled00/network.cpp | 236 ++++++++++++++++++++++++++++++++-- wled00/set.cpp | 6 +- wled00/wled.cpp | 140 -------------------- wled00/wled.h | 9 +- wled00/xml.cpp | 9 +- 8 files changed, 261 insertions(+), 168 deletions(-) diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 38e804ed..eaea1e92 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -20,11 +20,11 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { //long vid = doc[F("vid")]; // 2010020 -#ifdef WLED_USE_ETHERNET +#if defined(ARDUINO_ARCH_ESP32) && defined(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(); + initEthernet(); #endif JsonObject id = doc["id"]; @@ -53,9 +53,11 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { JsonArray sn = wifi["sn"]; char ssid[33] = ""; char pass[65] = ""; + char bssid[13] = ""; IPAddress nIP = (uint32_t)0U, nGW = (uint32_t)0U, nSN = (uint32_t)0x00FFFFFF; // little endian getStringFromJson(ssid, wifi[F("ssid")], 33); getStringFromJson(pass, wifi["psk"], 65); // password is not normally present but if it is, use it + getStringFromJson(bssid, wifi[F("bssid")], 13); for (size_t i = 0; i < 4; i++) { CJSON(nIP[i], ip[i]); CJSON(nGW[i], gw[i]); @@ -63,6 +65,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { } if (strlen(ssid) > 0) strlcpy(multiWiFi[n].clientSSID, ssid, 33); // this will keep old SSID intact if not present in JSON if (strlen(pass) > 0) strlcpy(multiWiFi[n].clientPass, pass, 65); // this will keep old password intact if not present in JSON + if (strlen(bssid) > 0) fillStr2MAC(multiWiFi[n].bssid, bssid); multiWiFi[n].staticIP = nIP; multiWiFi[n].staticGW = nGW; multiWiFi[n].staticSN = nSN; @@ -702,8 +705,8 @@ void deserializeConfigFromFS() { UsermodManager::readFromConfig(empty); serializeConfig(); // init Ethernet (in case default type is set at compile time) - #ifdef WLED_USE_ETHERNET - WLED::instance().initEthernet(); + #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) + initEthernet(); #endif return; } @@ -751,6 +754,9 @@ void serializeConfig() { JsonObject wifi = nw_ins.createNestedObject(); wifi[F("ssid")] = multiWiFi[n].clientSSID; wifi[F("pskl")] = strlen(multiWiFi[n].clientPass); + char bssid[13]; + fillMAC2Str(bssid, multiWiFi[n].bssid); + wifi[F("bssid")] = bssid; JsonArray wifi_ip = wifi.createNestedArray("ip"); JsonArray wifi_gw = wifi.createNestedArray("gw"); JsonArray wifi_sn = wifi.createNestedArray("sn"); @@ -786,7 +792,7 @@ void serializeConfig() { wifi[F("txpwr")] = txPower; #endif -#ifdef WLED_USE_ETHERNET +#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) JsonObject ethernet = root.createNestedObject("eth"); ethernet["type"] = ethernetType; if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) { diff --git a/wled00/data/settings_wifi.htm b/wled00/data/settings_wifi.htm index 30b6600a..d944d938 100644 --- a/wled00/data/settings_wifi.htm +++ b/wled00/data/settings_wifi.htm @@ -109,12 +109,13 @@ gId("wifi_add").style.display = (i1) ? "inline":"none"; } - function addWiFi(ssid="",pass="",ip=0,gw=0,sn=0x00ffffff) { // little endian + function addWiFi(ssid="",pass="",bssid="",ip=0,gw=0,sn=0x00ffffff) { // little endian var i = gId("wifi_entries").childNodes.length; if (i >= maxNetworks) return; var b = `

Network name (SSID${i==0?", empty to not connect":""}):
0?"required":""}>
Network password:

+BSSID (optional):

Static IP (leave at 0.0.0.0 for DHCP)${i==0?"
Also used by Ethernet":""}:
...
Static gateway:
diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index bc5206b7..1f9972a4 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -52,6 +52,7 @@ bool getJsonValue(const JsonVariant& element, DestType& destination, const Defau typedef struct WiFiConfig { char clientSSID[33]; char clientPass[65]; + uint8_t bssid[6]; IPAddress staticIP; IPAddress staticGW; IPAddress staticSN; @@ -62,6 +63,7 @@ typedef struct WiFiConfig { { strncpy(clientSSID, ssid, 32); clientSSID[32] = 0; strncpy(clientPass, pass, 64); clientPass[64] = 0; + memset(bssid, 0, sizeof(bssid)); } } wifi_config; @@ -340,7 +342,12 @@ void espNowReceiveCB(uint8_t* address, uint8_t* data, uint8_t len, signed int rs #endif //network.cpp -int getSignalQuality(int rssi); +bool initEthernet(); // result is informational +int getSignalQuality(int rssi); +void fillMAC2Str(char *str, const uint8_t *mac); +void fillStr2MAC(uint8_t *mac, const char *str); +int findWiFi(bool doScan = false); +bool isWiFiConfigured(); void WiFiEvent(WiFiEvent_t event); //um_manager.cpp @@ -464,6 +471,7 @@ void userLoop(); #include "soc/wdev_reg.h" #define HW_RND_REGISTER REG_READ(WDEV_RND_REG) #endif +#define hex2int(a) (((a)>='0' && (a)<='9') ? (a)-'0' : ((a)>='A' && (a)<='F') ? (a)-'A'+10 : ((a)>='a' && (a)<='f') ? (a)-'a'+10 : 0) int getNumVal(const String* req, uint16_t pos); void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255); bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255); // getVal supports inc/decrementing and random ("X~Y(r|~[w][-][Z])" form) diff --git a/wled00/network.cpp b/wled00/network.cpp index 3bd589f9..79209ff5 100644 --- a/wled00/network.cpp +++ b/wled00/network.cpp @@ -3,7 +3,7 @@ #include "wled_ethernet.h" -#ifdef WLED_USE_ETHERNET +#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) // The following six pins are neither configurable nor // can they be re-assigned through IOMUX / GPIO matrix. // See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/esp32/get-started-ethernet-kit-v1.1.html#ip101gri-phy-interface @@ -146,6 +146,101 @@ const ethernet_settings ethernetBoards[] = { ETH_CLOCK_GPIO0_OUT // eth_clk_mode } }; + +bool initEthernet() +{ + static bool successfullyConfiguredEthernet = false; + + if (successfullyConfiguredEthernet) { + // DEBUG_PRINTLN(F("initE: ETH already successfully configured, ignoring")); + return false; + } + if (ethernetType == WLED_ETH_NONE) { + return false; + } + if (ethernetType >= WLED_NUM_ETH_TYPES) { + DEBUG_PRINTF_P(PSTR("initE: Ignoring attempt for invalid ethernetType (%d)\n"), ethernetType); + return false; + } + + DEBUG_PRINTF_P(PSTR("initE: Attempting ETH config: %d\n"), ethernetType); + + // Ethernet initialization should only succeed once -- else reboot required + ethernet_settings es = ethernetBoards[ethernetType]; + managed_pin_type pinsToAllocate[10] = { + // first six pins are non-configurable + esp32_nonconfigurable_ethernet_pins[0], + esp32_nonconfigurable_ethernet_pins[1], + esp32_nonconfigurable_ethernet_pins[2], + esp32_nonconfigurable_ethernet_pins[3], + esp32_nonconfigurable_ethernet_pins[4], + esp32_nonconfigurable_ethernet_pins[5], + { (int8_t)es.eth_mdc, true }, // [6] = MDC is output and mandatory + { (int8_t)es.eth_mdio, true }, // [7] = MDIO is bidirectional and mandatory + { (int8_t)es.eth_power, true }, // [8] = optional pin, not all boards use + { ((int8_t)0xFE), false }, // [9] = replaced with eth_clk_mode, mandatory + }; + // update the clock pin.... + if (es.eth_clk_mode == ETH_CLOCK_GPIO0_IN) { + pinsToAllocate[9].pin = 0; + pinsToAllocate[9].isOutput = false; + } else if (es.eth_clk_mode == ETH_CLOCK_GPIO0_OUT) { + pinsToAllocate[9].pin = 0; + pinsToAllocate[9].isOutput = true; + } else if (es.eth_clk_mode == ETH_CLOCK_GPIO16_OUT) { + pinsToAllocate[9].pin = 16; + pinsToAllocate[9].isOutput = true; + } else if (es.eth_clk_mode == ETH_CLOCK_GPIO17_OUT) { + pinsToAllocate[9].pin = 17; + pinsToAllocate[9].isOutput = true; + } else { + DEBUG_PRINTF_P(PSTR("initE: Failing due to invalid eth_clk_mode (%d)\n"), es.eth_clk_mode); + return false; + } + + if (!PinManager::allocateMultiplePins(pinsToAllocate, 10, PinOwner::Ethernet)) { + DEBUG_PRINTLN(F("initE: Failed to allocate ethernet pins")); + return false; + } + + /* + For LAN8720 the most correct way is to perform clean reset each time before init + applying LOW to power or nRST pin for at least 100 us (please refer to datasheet, page 59) + ESP_IDF > V4 implements it (150 us, lan87xx_reset_hw(esp_eth_phy_t *phy) function in + /components/esp_eth/src/esp_eth_phy_lan87xx.c, line 280) + but ESP_IDF < V4 does not. Lets do it: + [not always needed, might be relevant in some EMI situations at startup and for hot resets] + */ + #if ESP_IDF_VERSION_MAJOR==3 + if(es.eth_power>0 && es.eth_type==ETH_PHY_LAN8720) { + pinMode(es.eth_power, OUTPUT); + digitalWrite(es.eth_power, 0); + delayMicroseconds(150); + digitalWrite(es.eth_power, 1); + delayMicroseconds(10); + } + #endif + + if (!ETH.begin( + (uint8_t) es.eth_address, + (int) es.eth_power, + (int) es.eth_mdc, + (int) es.eth_mdio, + (eth_phy_type_t) es.eth_type, + (eth_clock_mode_t) es.eth_clk_mode + )) { + DEBUG_PRINTLN(F("initC: ETH.begin() failed")); + // de-allocate the allocated pins + for (managed_pin_type mpt : pinsToAllocate) { + PinManager::deallocatePin(mpt.pin, PinOwner::Ethernet); + } + return false; + } + + successfullyConfiguredEthernet = true; + DEBUG_PRINTLN(F("initC: *** Ethernet successfully configured! ***")); + return true; +} #endif @@ -170,19 +265,136 @@ int getSignalQuality(int rssi) } +void fillMAC2Str(char *str, const uint8_t *mac) { + sprintf_P(str, PSTR("%02x%02x%02x%02x%02x%02x"), MAC2STR(mac)); + byte nul = 0; + for (int i = 0; i < 6; i++) nul |= *mac++; // do we have 0 + if (!nul) str[0] = '\0'; // empty string +} + +void fillStr2MAC(uint8_t *mac, const char *str) { + for (int i = 0; i < 6; i++) *mac++ = 0; // clear + if (!str) return; // null string + uint64_t MAC = strtoull(str, nullptr, 16); + for (int i = 0; i < 6; i++) { *--mac = MAC & 0xFF; MAC >>= 8; } +} + + +// performs asynchronous scan for available networks (which may take couple of seconds to finish) +// returns configured WiFi ID with the strongest signal (or default if no configured networks available) +int findWiFi(bool doScan) { + if (multiWiFi.size() <= 1) { + DEBUG_PRINTF_P(PSTR("WiFi: Defaulf SSID (%s) used.\n"), multiWiFi[0].clientSSID); + return 0; + } + + int status = WiFi.scanComplete(); // complete scan may take as much as several seconds (usually <6s with not very crowded air) + + if (doScan || status == WIFI_SCAN_FAILED) { + DEBUG_PRINTF_P(PSTR("WiFi: Scan started. @ %lus\n"), millis()/1000); + WiFi.scanNetworks(true); // start scanning in asynchronous mode (will delete old scan) + } else if (status >= 0) { // status contains number of found networks (including duplicate SSIDs with different BSSID) + DEBUG_PRINTF_P(PSTR("WiFi: Found %d SSIDs. @ %lus\n"), status, millis()/1000); + int rssi = -9999; + int selected = selectedWiFi; + for (int o = 0; o < status; o++) { + DEBUG_PRINTF_P(PSTR(" SSID: %s (BSSID: %s) RSSI: %ddB\n"), WiFi.SSID(o).c_str(), WiFi.BSSIDstr(o).c_str(), WiFi.RSSI(o)); + for (unsigned n = 0; n < multiWiFi.size(); n++) + if (!strcmp(WiFi.SSID(o).c_str(), multiWiFi[n].clientSSID)) { + bool foundBSSID = memcmp(multiWiFi[n].bssid, WiFi.BSSID(o), 6) == 0; + // find the WiFi with the strongest signal (but keep priority of entry if signal difference is not big) + if (foundBSSID || (n < selected && WiFi.RSSI(o) > rssi-10) || WiFi.RSSI(o) > rssi) { + rssi = foundBSSID ? 0 : WiFi.RSSI(o); // RSSI is only ever negative + selected = n; + } + break; + } + } + DEBUG_PRINTF_P(PSTR("WiFi: Selected SSID: %s RSSI: %ddB\n"), multiWiFi[selected].clientSSID, rssi); + return selected; + } + //DEBUG_PRINT(F("WiFi scan running.")); + return status; // scan is still running or there was an error +} + + +bool isWiFiConfigured() { + return multiWiFi.size() > 1 || (strlen(multiWiFi[0].clientSSID) >= 1 && strcmp_P(multiWiFi[0].clientSSID, PSTR(DEFAULT_CLIENT_SSID)) != 0); +} + +#if defined(ESP8266) + #define ARDUINO_EVENT_WIFI_AP_STADISCONNECTED WIFI_EVENT_SOFTAPMODE_STADISCONNECTED + #define ARDUINO_EVENT_WIFI_AP_STACONNECTED WIFI_EVENT_SOFTAPMODE_STACONNECTED + #define ARDUINO_EVENT_WIFI_STA_GOT_IP WIFI_EVENT_STAMODE_GOT_IP + #define ARDUINO_EVENT_WIFI_STA_CONNECTED WIFI_EVENT_STAMODE_CONNECTED + #define ARDUINO_EVENT_WIFI_STA_DISCONNECTED WIFI_EVENT_STAMODE_DISCONNECTED +#elif defined(ARDUINO_ARCH_ESP32) && !defined(ESP_ARDUINO_VERSION_MAJOR) //ESP_IDF_VERSION_MAJOR==3 + // not strictly IDF v3 but Arduino core related + #define ARDUINO_EVENT_WIFI_AP_STADISCONNECTED SYSTEM_EVENT_AP_STADISCONNECTED + #define ARDUINO_EVENT_WIFI_AP_STACONNECTED SYSTEM_EVENT_AP_STACONNECTED + #define ARDUINO_EVENT_WIFI_STA_GOT_IP SYSTEM_EVENT_STA_GOT_IP + #define ARDUINO_EVENT_WIFI_STA_CONNECTED SYSTEM_EVENT_STA_CONNECTED + #define ARDUINO_EVENT_WIFI_STA_DISCONNECTED SYSTEM_EVENT_STA_DISCONNECTED + #define ARDUINO_EVENT_WIFI_AP_START SYSTEM_EVENT_AP_START + #define ARDUINO_EVENT_WIFI_AP_STOP SYSTEM_EVENT_AP_STOP + #define ARDUINO_EVENT_WIFI_SCAN_DONE SYSTEM_EVENT_SCAN_DONE + #define ARDUINO_EVENT_ETH_START SYSTEM_EVENT_ETH_START + #define ARDUINO_EVENT_ETH_CONNECTED SYSTEM_EVENT_ETH_CONNECTED + #define ARDUINO_EVENT_ETH_DISCONNECTED SYSTEM_EVENT_ETH_DISCONNECTED +#endif + //handle Ethernet connection event void WiFiEvent(WiFiEvent_t event) { switch (event) { -#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) - case SYSTEM_EVENT_ETH_START: - DEBUG_PRINTLN(F("ETH Started")); + case ARDUINO_EVENT_WIFI_AP_STADISCONNECTED: + // AP client disconnected + if (--apClients == 0 && isWiFiConfigured()) forceReconnect = true; // no clients reconnect WiFi if awailable + DEBUG_PRINTF_P(PSTR("WiFi-E: AP Client Disconnected (%d) @ %lus.\n"), (int)apClients, millis()/1000); break; - case SYSTEM_EVENT_ETH_CONNECTED: + case ARDUINO_EVENT_WIFI_AP_STACONNECTED: + // AP client connected + apClients++; + DEBUG_PRINTF_P(PSTR("WiFi-E: AP Client Connected (%d) @ %lus.\n"), (int)apClients, millis()/1000); + break; + case ARDUINO_EVENT_WIFI_STA_GOT_IP: + DEBUG_PRINT(F("WiFi-E: IP address: ")); DEBUG_PRINTLN(Network.localIP()); + break; + case ARDUINO_EVENT_WIFI_STA_CONNECTED: + // followed by IDLE and SCAN_DONE + DEBUG_PRINTF_P(PSTR("WiFi-E: Connected! @ %lus\n"), millis()/1000); + wasConnected = true; + break; + case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: + if (wasConnected && interfacesInited) { + DEBUG_PRINTF_P(PSTR("WiFi-E: Disconnected! @ %lus\n"), millis()/1000); + if (interfacesInited && multiWiFi.size() > 1 && WiFi.scanComplete() >= 0) { + findWiFi(true); // reinit WiFi scan + forceReconnect = true; + } + interfacesInited = false; + } + break; + #ifdef ARDUINO_ARCH_ESP32 + case ARDUINO_EVENT_WIFI_SCAN_DONE: + // also triggered when connected to selected SSID + DEBUG_PRINTLN(F("WiFi-E: SSID scan completed.")); + break; + case ARDUINO_EVENT_WIFI_AP_START: + DEBUG_PRINTLN(F("WiFi-E: AP Started")); + break; + case ARDUINO_EVENT_WIFI_AP_STOP: + DEBUG_PRINTLN(F("WiFi-E: AP Stopped")); + break; + #if defined(WLED_USE_ETHERNET) + case ARDUINO_EVENT_ETH_START: + DEBUG_PRINTLN(F("ETH-E: Started")); + break; + case ARDUINO_EVENT_ETH_CONNECTED: { - DEBUG_PRINTLN(F("ETH Connected")); + DEBUG_PRINTLN(F("ETH-E: Connected")); if (!apActive) { - WiFi.disconnect(true); + WiFi.disconnect(true); // disable WiFi entirely } if (multiWiFi[0].staticIP != (uint32_t)0x00000000 && multiWiFi[0].staticGW != (uint32_t)0x00000000) { ETH.config(multiWiFi[0].staticIP, multiWiFi[0].staticGW, multiWiFi[0].staticSN, dnsAddress); @@ -196,18 +408,20 @@ void WiFiEvent(WiFiEvent_t event) showWelcomePage = false; break; } - case SYSTEM_EVENT_ETH_DISCONNECTED: - DEBUG_PRINTLN(F("ETH Disconnected")); + case ARDUINO_EVENT_ETH_DISCONNECTED: + DEBUG_PRINTLN(F("ETH-E: Disconnected")); // This doesn't really affect ethernet per se, // as it's only configured once. Rather, it // may be necessary to reconnect the WiFi when // ethernet disconnects, as a way to provide // alternative access to the device. + if (interfacesInited && WiFi.scanComplete() >= 0) findWiFi(true); // reinit WiFi scan forceReconnect = true; break; -#endif + #endif + #endif default: - DEBUG_PRINTF_P(PSTR("Network event: %d\n"), (int)event); + DEBUG_PRINTF_P(PSTR("WiFi-E: Event %d\n"), (int)event); break; } } diff --git a/wled00/set.cpp b/wled00/set.cpp index 160eb48f..6152ba0b 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -23,6 +23,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) for (size_t n = 0; n < WLED_MAX_WIFI_COUNT; n++) { char cs[4] = "CS"; cs[2] = 48+n; cs[3] = 0; //client SSID char pw[4] = "PW"; pw[2] = 48+n; pw[3] = 0; //client password + char bs[4] = "BS"; bs[2] = 48+n; bs[3] = 0; //BSSID char ip[5] = "IP"; ip[2] = 48+n; ip[4] = 0; //IP address char gw[5] = "GW"; gw[2] = 48+n; gw[4] = 0; //GW address char sn[5] = "SN"; sn[2] = 48+n; sn[4] = 0; //subnet mask @@ -39,6 +40,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) strlcpy(multiWiFi[n].clientPass, request->arg(pw).c_str(), 65); forceReconnect = true; } + fillStr2MAC(multiWiFi[n].bssid, request->arg(bs).c_str()); for (size_t i = 0; i < 4; i++) { ip[3] = 48+i; gw[3] = 48+i; @@ -93,9 +95,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) strlwr(linked_remote); //Normalize MAC format to lowercase #endif - #ifdef WLED_USE_ETHERNET + #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) ethernetType = request->arg(F("ETH")).toInt(); - WLED::instance().initEthernet(); + initEthernet(); #endif } diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 1f978a39..d4da106a 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -632,146 +632,6 @@ void WLED::initAP(bool resetAP) apActive = true; } -bool WLED::initEthernet() -{ -#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) - - static bool successfullyConfiguredEthernet = false; - - if (successfullyConfiguredEthernet) { - // DEBUG_PRINTLN(F("initE: ETH already successfully configured, ignoring")); - return false; - } - if (ethernetType == WLED_ETH_NONE) { - return false; - } - if (ethernetType >= WLED_NUM_ETH_TYPES) { - DEBUG_PRINTF_P(PSTR("initE: Ignoring attempt for invalid ethernetType (%d)\n"), ethernetType); - return false; - } - - DEBUG_PRINTF_P(PSTR("initE: Attempting ETH config: %d\n"), ethernetType); - - // Ethernet initialization should only succeed once -- else reboot required - ethernet_settings es = ethernetBoards[ethernetType]; - managed_pin_type pinsToAllocate[10] = { - // first six pins are non-configurable - esp32_nonconfigurable_ethernet_pins[0], - esp32_nonconfigurable_ethernet_pins[1], - esp32_nonconfigurable_ethernet_pins[2], - esp32_nonconfigurable_ethernet_pins[3], - esp32_nonconfigurable_ethernet_pins[4], - esp32_nonconfigurable_ethernet_pins[5], - { (int8_t)es.eth_mdc, true }, // [6] = MDC is output and mandatory - { (int8_t)es.eth_mdio, true }, // [7] = MDIO is bidirectional and mandatory - { (int8_t)es.eth_power, true }, // [8] = optional pin, not all boards use - { ((int8_t)0xFE), false }, // [9] = replaced with eth_clk_mode, mandatory - }; - // update the clock pin.... - if (es.eth_clk_mode == ETH_CLOCK_GPIO0_IN) { - pinsToAllocate[9].pin = 0; - pinsToAllocate[9].isOutput = false; - } else if (es.eth_clk_mode == ETH_CLOCK_GPIO0_OUT) { - pinsToAllocate[9].pin = 0; - pinsToAllocate[9].isOutput = true; - } else if (es.eth_clk_mode == ETH_CLOCK_GPIO16_OUT) { - pinsToAllocate[9].pin = 16; - pinsToAllocate[9].isOutput = true; - } else if (es.eth_clk_mode == ETH_CLOCK_GPIO17_OUT) { - pinsToAllocate[9].pin = 17; - pinsToAllocate[9].isOutput = true; - } else { - DEBUG_PRINTF_P(PSTR("initE: Failing due to invalid eth_clk_mode (%d)\n"), es.eth_clk_mode); - return false; - } - - if (!PinManager::allocateMultiplePins(pinsToAllocate, 10, PinOwner::Ethernet)) { - DEBUG_PRINTLN(F("initE: Failed to allocate ethernet pins")); - return false; - } - - /* - For LAN8720 the most correct way is to perform clean reset each time before init - applying LOW to power or nRST pin for at least 100 us (please refer to datasheet, page 59) - ESP_IDF > V4 implements it (150 us, lan87xx_reset_hw(esp_eth_phy_t *phy) function in - /components/esp_eth/src/esp_eth_phy_lan87xx.c, line 280) - but ESP_IDF < V4 does not. Lets do it: - [not always needed, might be relevant in some EMI situations at startup and for hot resets] - */ - #if ESP_IDF_VERSION_MAJOR==3 - if(es.eth_power>0 && es.eth_type==ETH_PHY_LAN8720) { - pinMode(es.eth_power, OUTPUT); - digitalWrite(es.eth_power, 0); - delayMicroseconds(150); - digitalWrite(es.eth_power, 1); - delayMicroseconds(10); - } - #endif - - if (!ETH.begin( - (uint8_t) es.eth_address, - (int) es.eth_power, - (int) es.eth_mdc, - (int) es.eth_mdio, - (eth_phy_type_t) es.eth_type, - (eth_clock_mode_t) es.eth_clk_mode - )) { - DEBUG_PRINTLN(F("initC: ETH.begin() failed")); - // de-allocate the allocated pins - for (managed_pin_type mpt : pinsToAllocate) { - PinManager::deallocatePin(mpt.pin, PinOwner::Ethernet); - } - return false; - } - - successfullyConfiguredEthernet = true; - DEBUG_PRINTLN(F("initC: *** Ethernet successfully configured! ***")); - return true; -#else - return false; // Ethernet not enabled for build -#endif -} - -// performs asynchronous scan for available networks (which may take couple of seconds to finish) -// returns configured WiFi ID with the strongest signal (or default if no configured networks available) -int8_t WLED::findWiFi(bool doScan) { - if (multiWiFi.size() <= 1) { - DEBUG_PRINTLN(F("Defaulf WiFi used.")); - return 0; - } - - if (doScan) WiFi.scanDelete(); // restart scan - - int status = WiFi.scanComplete(); // complete scan may take as much as several seconds (usually <3s with not very crowded air) - - if (status == WIFI_SCAN_FAILED) { - DEBUG_PRINTLN(F("WiFi scan started.")); - WiFi.scanNetworks(true); // start scanning in asynchronous mode - } else if (status >= 0) { // status contains number of found networks - DEBUG_PRINT(F("WiFi scan completed: ")); DEBUG_PRINTLN(status); - int rssi = -9999; - unsigned selected = selectedWiFi; - for (int o = 0; o < status; o++) { - DEBUG_PRINT(F(" WiFi available: ")); DEBUG_PRINT(WiFi.SSID(o)); - DEBUG_PRINT(F(" RSSI: ")); DEBUG_PRINT(WiFi.RSSI(o)); DEBUG_PRINTLN(F("dB")); - for (unsigned n = 0; n < multiWiFi.size(); n++) - if (!strcmp(WiFi.SSID(o).c_str(), multiWiFi[n].clientSSID)) { - // find the WiFi with the strongest signal (but keep priority of entry if signal difference is not big) - if ((n < selected && WiFi.RSSI(o) > rssi-10) || WiFi.RSSI(o) > rssi) { - rssi = WiFi.RSSI(o); - selected = n; - } - break; - } - } - DEBUG_PRINT(F("Selected: ")); DEBUG_PRINT(multiWiFi[selected].clientSSID); - DEBUG_PRINT(F(" RSSI: ")); DEBUG_PRINT(rssi); DEBUG_PRINTLN(F("dB")); - return selected; - } - //DEBUG_PRINT(F("WiFi scan running.")); - return status; // scan is still running or there was an error -} - void WLED::initConnection() { DEBUG_PRINTF_P(PSTR("initConnection() called @ %lus.\n"), millis()/1000); diff --git a/wled00/wled.h b/wled00/wled.h index d0cee80d..84781010 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -355,7 +355,7 @@ WLED_GLOBAL wifi_options_t wifiOpt _INIT_N(({0, 1, false, AP_BEHAVIOR_BOOT_NO_CO #define noWifiSleep wifiOpt.noWifiSleep #define force802_3g wifiOpt.force802_3g #else -WLED_GLOBAL uint8_t selectedWiFi _INIT(0); +WLED_GLOBAL int8_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 @@ -373,9 +373,9 @@ WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_8_5dBm); WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_19_5dBm); #endif #endif -#define WLED_WIFI_CONFIGURED (strlen(multiWiFi[0].clientSSID) >= 1 && strcmp(multiWiFi[0].clientSSID, DEFAULT_CLIENT_SSID) != 0) +#define WLED_WIFI_CONFIGURED isWiFiConfigured() -#ifdef WLED_USE_ETHERNET +#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) #ifdef WLED_ETH_DEFAULT // default ethernet board type if specified WLED_GLOBAL int ethernetType _INIT(WLED_ETH_DEFAULT); // ethernet board type #else @@ -567,6 +567,7 @@ WLED_GLOBAL uint16_t userVar0 _INIT(0), userVar1 _INIT(0); //available for use i // internal global variable declarations // wifi WLED_GLOBAL bool apActive _INIT(false); +WLED_GLOBAL byte apClients _INIT(0); WLED_GLOBAL bool forceReconnect _INIT(false); WLED_GLOBAL unsigned long lastReconnectAttempt _INIT(0); WLED_GLOBAL bool interfacesInited _INIT(false); @@ -1038,11 +1039,9 @@ public: void beginStrip(); void handleConnection(); - bool initEthernet(); // result is informational void initAP(bool resetAP = false); void initConnection(); void initInterfaces(); - int8_t findWiFi(bool doScan = false); #if defined(STATUSLED) void handleStatusLED(); #endif diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 2a19cdfa..4898858d 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -110,7 +110,7 @@ void appendGPIOinfo(Print& settingsScript) { settingsScript.print(hardwareTX); // debug output (TX) pin firstPin = false; #endif - #ifdef WLED_USE_ETHERNET + #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) { if (!firstPin) settingsScript.print(','); for (unsigned p=0; p Date: Fri, 27 Dec 2024 11:19:24 +0100 Subject: [PATCH 102/463] palette effect overflow fix --- wled00/FX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 5e43430a..7bf05458 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2032,7 +2032,7 @@ uint16_t mode_palette() { const mathType sourceX = xtSinTheta + ytCosTheta + centerX; // The computation was scaled just right so that the result should always be in range [0, maxXOut], but enforce this anyway // to account for imprecision. Then scale it so that the range is [0, 255], which we can use with the palette. - int colorIndex = (std::min(std::max(sourceX, mathType(0)), maxXOut * sInt16Scale) * 255) / (sInt16Scale * maxXOut); + int colorIndex = (std::min(std::max(sourceX, mathType(0)), maxXOut * sInt16Scale) * wideMathType(255)) / (sInt16Scale * maxXOut); // inputSize determines by how much we want to scale the palette: // values < 128 display a fraction of a palette, // values > 128 display multiple palettes. From 3fc8c7d560b949eec8e2c55ffa7f0a014fd72a3f Mon Sep 17 00:00:00 2001 From: AlDIY <87589371+dosipod@users.noreply.github.com> Date: Sun, 29 Dec 2024 15:46:49 +0300 Subject: [PATCH 103/463] Update readme.md Updated the readme to use lennarthennigs/ESP Rotary@^2.1.1 as the old lib fail to compile --- usermods/rgb-rotary-encoder/readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/usermods/rgb-rotary-encoder/readme.md b/usermods/rgb-rotary-encoder/readme.md index ba5aad4d..65317917 100644 --- a/usermods/rgb-rotary-encoder/readme.md +++ b/usermods/rgb-rotary-encoder/readme.md @@ -9,7 +9,7 @@ The actual / original code that controls the LED modes is from Adam Zeloof. I ta It was quite a bit more work than I hoped, but I got there eventually :) ## Requirements -* "ESP Rotary" by Lennart Hennigs, v1.5.0 or higher: https://github.com/LennartHennigs/ESPRotary +* "ESP Rotary" by Lennart Hennigs, v2.1.1 or higher: https://github.com/LennartHennigs/ESPRotary ## Usermod installation Simply copy the below block (build task) to your `platformio_override.ini` and compile WLED using this new build task. Or use an existing one and add the buildflag `-D RGB_ROTARY_ENCODER`. @@ -20,7 +20,7 @@ ESP32: extends = env:esp32dev build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32 -D RGB_ROTARY_ENCODER lib_deps = ${esp32.lib_deps} - lennarthennigs/ESP Rotary@^1.5.0 + lennarthennigs/ESP Rotary@^2.1.1 ``` ESP8266 / D1 Mini: @@ -29,7 +29,7 @@ ESP8266 / D1 Mini: extends = env:d1_mini build_flags = ${common.build_flags_esp8266} -D RGB_ROTARY_ENCODER lib_deps = ${esp8266.lib_deps} - lennarthennigs/ESP Rotary@^1.5.0 + lennarthennigs/ESP Rotary@^2.1.1 ``` ## How to connect the board to your ESP From 6a1d3de75b0705549469608afad353605d479da8 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 30 Dec 2024 12:58:38 +0100 Subject: [PATCH 104/463] Fix output glitches when playlist changes preset (#4442) same issue as with https://github.com/Aircoookie/WLED/pull/4386 waiting on bus to finish updating before file access fixes the glitches. this issue is only present on S2 and C3, not on ESP8266 or dual-core ESPs, the fix is only applied for these two. --- wled00/presets.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/wled00/presets.cpp b/wled00/presets.cpp index 04474113..fb09d48a 100644 --- a/wled00/presets.cpp +++ b/wled00/presets.cpp @@ -164,6 +164,11 @@ void handlePresets() DEBUG_PRINTF_P(PSTR("Applying preset: %u\n"), (unsigned)tmpPreset); + #if defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32C3) + unsigned long start = millis(); + while (strip.isUpdating() && millis() - start < FRAMETIME_FIXED) yield(); // wait for strip to finish updating, accessing FS during sendout causes glitches + #endif + #ifdef ARDUINO_ARCH_ESP32 if (tmpPreset==255 && tmpRAMbuffer!=nullptr) { deserializeJson(*pDoc,tmpRAMbuffer); From 54264efb20fa54950113924281a42166f676339d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Mon, 30 Dec 2024 15:03:45 +0100 Subject: [PATCH 105/463] Fill SSID fix --- wled00/data/settings_wifi.htm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/data/settings_wifi.htm b/wled00/data/settings_wifi.htm index d944d938..1531d161 100644 --- a/wled00/data/settings_wifi.htm +++ b/wled00/data/settings_wifi.htm @@ -47,7 +47,7 @@ scanLoops = 0; if (networks.length > 0) { - let cs = d.querySelectorAll("#wifi_entries input[type=text]"); + let cs = d.querySelectorAll("#wifi_entries input[type=text][name^=CS]"); for (let input of (cs||[])) { let found = false; let select = cE("select"); @@ -64,7 +64,7 @@ const option = cE("option"); option.setAttribute("value", networks[i].ssid); - option.textContent = `${networks[i].ssid} (${networks[i].rssi} dBm)`; + option.textContent = `${networks[i].ssid} (${networks[i].rssi} dBm)`; // [${networks[i].bssid.replaceAll(':','')}] if (networks[i].ssid === input.value) { option.setAttribute("selected", "selected"); From 0937064e18c771c1930c61af6c27c0ac1ee5473b Mon Sep 17 00:00:00 2001 From: ladyada Date: Tue, 31 Dec 2024 16:40:11 -0500 Subject: [PATCH 106/463] fix pin availability calculations for ESP32-mini modules --- wled00/pin_manager.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index 0d4c2ad5..1dc14fbc 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -214,7 +214,18 @@ bool PinManager::isPinOk(byte gpio, bool output) // JTAG: GPIO39-42 are usually used for inline debugging // GPIO46 is input only and pulled down #else - if (gpio > 5 && gpio < 12) return false; //SPI flash pins + + if (strncmp_P(PSTR("ESP32-U4WDH"), ESP.getChipModel(), 11) == 0) { + // this chip has 4 MB of internal Flash and different packaging, so available pins are different! + if ((gpio == 1) || (gpio == 3) || ((gpio >= 6) && (gpio =< 8)) || + (gpio == 11) || (gpio == 16) || (gpio == 17) || (gpio == 20) || + (gpio == 24) || ((gpio >= 28) && (gpio <= 31))) + return false; + } else { + // for classic ESP32 (non-mini) modules, these are the SPI flash pins + if (gpio > 5 && gpio < 12) return false; //SPI flash pins + } + if (strncmp_P(PSTR("ESP32-PICO"), ESP.getChipModel(), 10) == 0 && (gpio == 16 || gpio == 17)) return false; // PICO-D4: gpio16+17 are in use for onboard SPI FLASH if (gpio == 16 || gpio == 17) return !psramFound(); //PSRAM pins on ESP32 (these are IO) #endif From d637260dc3d729d50d256b21564c8c8ea486a087 Mon Sep 17 00:00:00 2001 From: ladyada Date: Tue, 31 Dec 2024 16:42:49 -0500 Subject: [PATCH 107/463] typo fix --- wled00/pin_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index 1dc14fbc..1110ae0e 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -217,7 +217,7 @@ bool PinManager::isPinOk(byte gpio, bool output) if (strncmp_P(PSTR("ESP32-U4WDH"), ESP.getChipModel(), 11) == 0) { // this chip has 4 MB of internal Flash and different packaging, so available pins are different! - if ((gpio == 1) || (gpio == 3) || ((gpio >= 6) && (gpio =< 8)) || + if ((gpio == 1) || (gpio == 3) || ((gpio >= 6) && (gpio <= 8)) || (gpio == 11) || (gpio == 16) || (gpio == 17) || (gpio == 20) || (gpio == 24) || ((gpio >= 28) && (gpio <= 31))) return false; From 12db60885f7e82d6b4b194a70f7e398b7cf39dfe Mon Sep 17 00:00:00 2001 From: ladyada Date: Tue, 31 Dec 2024 17:02:52 -0500 Subject: [PATCH 108/463] try debug --- wled00/pin_manager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index 1110ae0e..7ee1076b 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -215,7 +215,9 @@ bool PinManager::isPinOk(byte gpio, bool output) // GPIO46 is input only and pulled down #else + Serial.printf("GPIO TEST %d\n\r", gpio); if (strncmp_P(PSTR("ESP32-U4WDH"), ESP.getChipModel(), 11) == 0) { + Serial.println("U4WDH"); // this chip has 4 MB of internal Flash and different packaging, so available pins are different! if ((gpio == 1) || (gpio == 3) || ((gpio >= 6) && (gpio <= 8)) || (gpio == 11) || (gpio == 16) || (gpio == 17) || (gpio == 20) || From 35d92f43c050c0c5afd8fd4cc41270da99b283f7 Mon Sep 17 00:00:00 2001 From: ladyada Date: Thu, 2 Jan 2025 20:54:19 -0500 Subject: [PATCH 109/463] >sigh< https://github.com/espressif/arduino-esp32/issues/10683 --- wled00/pin_manager.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index 7ee1076b..aa2dcf06 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -215,9 +215,8 @@ bool PinManager::isPinOk(byte gpio, bool output) // GPIO46 is input only and pulled down #else - Serial.printf("GPIO TEST %d\n\r", gpio); - if (strncmp_P(PSTR("ESP32-U4WDH"), ESP.getChipModel(), 11) == 0) { - Serial.println("U4WDH"); + if ((strncmp_P(PSTR("ESP32-U4WDH"), ESP.getChipModel(), 11) == 0) || // this is the correct identifier, but.... + (strncmp_P(PSTR("ESP32-PICO-D2"), ESP.getChipModel(), 13) == 0)) { // https://github.com/espressif/arduino-esp32/issues/10683 // this chip has 4 MB of internal Flash and different packaging, so available pins are different! if ((gpio == 1) || (gpio == 3) || ((gpio >= 6) && (gpio <= 8)) || (gpio == 11) || (gpio == 16) || (gpio == 17) || (gpio == 20) || From dcf89e0dbd428c6cb658e94854edd2969590f4ee Mon Sep 17 00:00:00 2001 From: ladyada Date: Fri, 3 Jan 2025 16:37:26 -0500 Subject: [PATCH 110/463] simplify logic --- wled00/pin_manager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index aa2dcf06..c37b1936 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -218,16 +218,16 @@ bool PinManager::isPinOk(byte gpio, bool output) if ((strncmp_P(PSTR("ESP32-U4WDH"), ESP.getChipModel(), 11) == 0) || // this is the correct identifier, but.... (strncmp_P(PSTR("ESP32-PICO-D2"), ESP.getChipModel(), 13) == 0)) { // https://github.com/espressif/arduino-esp32/issues/10683 // this chip has 4 MB of internal Flash and different packaging, so available pins are different! - if ((gpio == 1) || (gpio == 3) || ((gpio >= 6) && (gpio <= 8)) || - (gpio == 11) || (gpio == 16) || (gpio == 17) || (gpio == 20) || - (gpio == 24) || ((gpio >= 28) && (gpio <= 31))) + if (((gpio > 5) && (gpio < 9)) || (gpio == 11)) return false; } else { // for classic ESP32 (non-mini) modules, these are the SPI flash pins if (gpio > 5 && gpio < 12) return false; //SPI flash pins } - if (strncmp_P(PSTR("ESP32-PICO"), ESP.getChipModel(), 10) == 0 && (gpio == 16 || gpio == 17)) return false; // PICO-D4: gpio16+17 are in use for onboard SPI FLASH + if (((strncmp_P(PSTR("ESP32-PICO"), ESP.getChipModel(), 10) == 0) || + (strncmp_P(PSTR("ESP32-U4WDH"), ESP.getChipModel(), 11) == 0)) + && (gpio == 16 || gpio == 17)) return false; // PICO-D4/U4WDH: gpio16+17 are in use for onboard SPI FLASH if (gpio == 16 || gpio == 17) return !psramFound(); //PSRAM pins on ESP32 (these are IO) #endif if (output) return digitalPinCanOutput(gpio); From ae4de2782a10a1db6cb007558af9ec81f339366c Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 4 Jan 2025 08:07:11 +0100 Subject: [PATCH 111/463] DeepSleep usermod (#4190) * DeepSleep Usermod - sleep delay is now 1 by default, disabling sleep at powerup - renamed bootup variable to powerup - using delay counter for proper bootup - changed power-up and bootup logic - added fallback to always power-on at boot except at powerup - fixed bug in settings page --- usermods/deep_sleep/readme.md | 84 +++++++++ usermods/deep_sleep/usermod_deep_sleep.h | 227 +++++++++++++++++++++++ wled00/const.h | 1 + wled00/usermods_list.cpp | 9 + 4 files changed, 321 insertions(+) create mode 100644 usermods/deep_sleep/readme.md create mode 100644 usermods/deep_sleep/usermod_deep_sleep.h diff --git a/usermods/deep_sleep/readme.md b/usermods/deep_sleep/readme.md new file mode 100644 index 00000000..006aa31f --- /dev/null +++ b/usermods/deep_sleep/readme.md @@ -0,0 +1,84 @@ +# Deep Sleep usermod + +This usermod unleashes the low power capabilities of th ESP: when you power off your LEDs (using the UI power button or a macro) the ESP will be put into deep sleep mode, reducing power consumption to a minimum. +During deep sleep the ESP is shut down completely: no WiFi, no CPU, no outputs. The only way to wake it up is to use an external signal or a button. Once it wakes from deep sleep it reboots so ***make sure to use a boot-up preset.*** + +# A word of warning + +When you disable the WLED option 'Turn LEDs on after power up/reset' and 'DelaySleep' is set to zero the ESP will go into deep sleep directly after power-up and only start WLED after it has been woken up. +If the ESP can not be awoken from deep sleep due to a wrong configuration it has to be factory reset, disabling sleep at power-up. There is no other way to wake it up. + +# Power Consumption in deep sleep + +The current drawn by the ESP in deep sleep mode depends on the type and is in the range of 5uA-20uA (as in micro Amperes): +- ESP32: 10uA +- ESP32 S3: 8uA +- ESP32 S2: 20uA +- ESP32 C3: 5uA +- ESP8266: 20uA (not supported in this usermod) + +However, there is usually additional components on a controller that increase the value: +- Power LED: the power LED on a ESP board draws 500uA - 1mA +- LDO: the voltage regulator also draws idle current. Depending on the type used this can be around 50uA up to 10mA (LM1117). Special low power LDOs with very low idle currents do exist +- Digital LEDs: WS2812 for example draw a current of about 1mA per LED. To make good use of this usermod it is required to power them off using MOSFETs or a Relay + +For lowest power consumption, remove the Power LED and make sure your board does not use an LM1117. On a ESP32 C3 Supermini with the power LED removed (no other modifications) powered through the 5V pin I measured a current draw of 50uA in deep sleep. + +# Useable GPIOs + +The GPIOs that can be used to wake the ESP from deep sleep are limited. Only pins connected to the internal RTC unit can be used: + +- ESP32: GPIO 0, 2, 4, 12-15, 25-39 +- ESP32 S3: GPIO 0-21 +- ESP32 S2: GPIO 0-21 +- ESP32 C3: GPIO 0-5 +- ESP8266 is not supported in this usermod + +You can however use the selected wake-up pin normally in WLED, it only gets activated as a wake-up pin when your LEDs are powered down. + +# Limitations + +To keep this usermod simple and easy to use, it is a very basic implementation of the low-power capabilities provided by the ESP. If you need more advanced control you are welcome to implement your own version based on this usermod. + +## Usermod installation + +Use `#define USERMOD_DEEP_SLEEP` in wled.h or `-D USERMOD_DEEP_SLEEP` in your platformio.ini. Settings can be changed in the usermod config UI. + +### Define Settings + +There are five parameters you can set: + +- GPIO: the pin to use for wake-up +- WakeWhen High/Low: the pin state that triggers the wake-up +- Pull-up/down disable: enable or disable the internal pullup resistors during sleep (does not affect normal use while running) +- Wake after: if set larger than 0, ESP will automatically wake-up after this many seconds (Turn LEDs on after power up/reset is overriden, it will always turn on) +- Delay sleep: if set larger than 0, ESP will not go to sleep for this many seconds after you power it off. Timer is reset when switched back on during this time. + +To override the default settings, place the `#define` in wled.h or add `-D DEEPSLEEP_xxx` to your platformio_override.ini build flags + +* `DEEPSLEEP_WAKEUPPIN x` - define the pin to be used for wake-up, see list of useable pins above. The pin can be used normally as a button pin in WLED. +* `DEEPSLEEP_WAKEWHENHIGH` - if defined, wakes up when pin goes high (default is low) +* `DEEPSLEEP_DISABLEPULL` - if defined, internal pullup/pulldown is disabled in deep sleep (default is ebnabled) +* `DEEPSLEEP_WAKEUPINTERVAL` - number of seconds after which a wake-up happens automatically, sooner if button is pressed. 0 = never. accuracy is about 2% +* `DEEPSLEEP_DELAY` - delay between power-off and sleep + +example for env build flags: + `-D USERMOD_DEEP_SLEEP` + `-D DEEPSLEEP_WAKEUPPIN=4` + `-D DEEPSLEEP_DISABLEPULL=0` ;enable pull-up/down resistors by default + `-D DEEPSLEEP_WAKEUPINTERVAL=43200` ;wake up after 12 hours (or when button is pressed) + +### Hardware Setup + +To wake from deep-sleep an external trigger signal on the configured GPIO is required. When using timed-only wake-up, use a GPIO that has an on-board pull-up resistor (GPIO0 on most boards). When using push-buttons it is highly recommended to use an external pull-up resistor: not all IO's on all devices have properly working internal resistors. + +Using sensors like PIR, IR, touch sensors or any other sensor with a digital output can be used instead of a button. + +now go on and save some power +@dedehai + +## Change log +2024-09 +* Initial version +2024-10 +* Changed from #define configuration to UI configuration \ No newline at end of file diff --git a/usermods/deep_sleep/usermod_deep_sleep.h b/usermods/deep_sleep/usermod_deep_sleep.h new file mode 100644 index 00000000..7f4efd5c --- /dev/null +++ b/usermods/deep_sleep/usermod_deep_sleep.h @@ -0,0 +1,227 @@ +#pragma once + +#include "wled.h" +#include "driver/rtc_io.h" + +#ifdef ESP8266 +#error The "Deep Sleep" usermod does not support ESP8266 +#endif + +#ifndef DEEPSLEEP_WAKEUPPIN +#define DEEPSLEEP_WAKEUPPIN 0 +#endif +#ifndef DEEPSLEEP_WAKEWHENHIGH +#define DEEPSLEEP_WAKEWHENHIGH 0 +#endif +#ifndef DEEPSLEEP_DISABLEPULL +#define DEEPSLEEP_DISABLEPULL 1 +#endif +#ifndef DEEPSLEEP_WAKEUPINTERVAL +#define DEEPSLEEP_WAKEUPINTERVAL 0 +#endif +#ifndef DEEPSLEEP_DELAY +#define DEEPSLEEP_DELAY 1 +#endif + +RTC_DATA_ATTR bool powerup = true; // variable in RTC data persists on a reboot + +class DeepSleepUsermod : public Usermod { + + private: + + bool enabled = true; + bool initDone = false; + uint8_t wakeupPin = DEEPSLEEP_WAKEUPPIN; + uint8_t wakeWhenHigh = DEEPSLEEP_WAKEWHENHIGH; // wake up when pin goes high if 1, triggers on low if 0 + bool noPull = true; // use pullup/pulldown resistor + int wakeupAfter = DEEPSLEEP_WAKEUPINTERVAL; // in seconds, <=0: button only + int sleepDelay = DEEPSLEEP_DELAY; // in seconds, 0 = immediate + int delaycounter = 5; // delay deep sleep at bootup until preset settings are applied + uint32_t lastLoopTime = 0; + // string that are used multiple time (this will save some flash memory) + static const char _name[]; + static const char _enabled[]; + + bool pin_is_valid(uint8_t wakePin) { + #ifdef CONFIG_IDF_TARGET_ESP32 //ESP32: GPIOs 0,2,4, 12-15, 25-39 can be used for wake-up + if (wakePin == 0 || wakePin == 2 || wakePin == 4 || (wakePin >= 12 && wakePin <= 15) || (wakePin >= 25 && wakePin <= 27) || (wakePin >= 32 && wakePin <= 39)) { + return true; + } + #endif + #if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32S2) //ESP32 S3 & S3: GPIOs 0-21 can be used for wake-up + if (wakePin <= 21) { + return true; + } + #endif + #ifdef CONFIG_IDF_TARGET_ESP32C3 // ESP32 C3: GPIOs 0-5 can be used for wake-up + if (wakePin <= 5) { + return true; + } + #endif + DEBUG_PRINTLN(F("Error: unsupported deep sleep wake-up pin")); + return false; + } + + public: + + inline void enable(bool enable) { enabled = enable; } // Enable/Disable the usermod + inline bool isEnabled() { return enabled; } //Get usermod enabled/disabled state + + // setup is called at boot (or in this case after every exit of sleep mode) + void setup() { + //TODO: if the de-init of RTC pins is required to do it could be done here + //rtc_gpio_deinit(wakeupPin); + initDone = true; + } + + void loop() { + if (!enabled || !offMode) { // disabled or LEDs are on + lastLoopTime = 0; // reset timer + return; + } + + if (sleepDelay > 0) { + if(lastLoopTime == 0) lastLoopTime = millis(); // initialize + if (millis() - lastLoopTime < sleepDelay * 1000) { + return; // wait until delay is over + } + } + + if(powerup == false && delaycounter) { // delay sleep in case a preset is being loaded and turnOnAtBoot is disabled (handleIO() does enable offMode temporarily in this case) + delaycounter--; + if(delaycounter == 2 && offMode) { // force turn on, no matter the settings (device is bricked if user set sleepDelay=0, no bootup preset and turnOnAtBoot=false) + if (briS == 0) bri = 10; // turn on at low brightness + else bri = briS; + strip.setBrightness(bri); // needed to make handleIO() not turn off LEDs (really? does not help in bootup preset) + offMode = false; + applyPresetWithFallback(0, CALL_MODE_INIT, FX_MODE_STATIC, 0); // try to apply preset 0, fallback to static + if (rlyPin >= 0) { + digitalWrite(rlyPin, (rlyMde ? HIGH : LOW)); // turn relay on TODO: this should be done by wled, what function to call? + } + } + return; + } + + DEBUG_PRINTLN(F("DeepSleep UM: entering deep sleep...")); + powerup = false; // turn leds on in all subsequent bootups (overrides Turn LEDs on after power up/reset' at reboot) + if(!pin_is_valid(wakeupPin)) return; + esp_err_t halerror = ESP_OK; + pinMode(wakeupPin, INPUT); // make sure GPIO is input with pullup/pulldown disabled + esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL); //disable all wake-up sources (just in case) + + if(wakeupAfter) + esp_sleep_enable_timer_wakeup((uint64_t)wakeupAfter * (uint64_t)1e6); //sleep for x seconds + + #if defined(CONFIG_IDF_TARGET_ESP32C3) // ESP32 C3 + if(noPull) + gpio_sleep_set_pull_mode((gpio_num_t)wakeupPin, GPIO_FLOATING); + else { // enable pullup/pulldown resistor + if(wakeWhenHigh) + gpio_sleep_set_pull_mode((gpio_num_t)wakeupPin, GPIO_PULLDOWN_ONLY); + else + gpio_sleep_set_pull_mode((gpio_num_t)wakeupPin, GPIO_PULLUP_ONLY); + } + if(wakeWhenHigh) + halerror = esp_deep_sleep_enable_gpio_wakeup(1<(0 = never)');")); + oappend(SET_F("addInfo('DeepSleep:delaySleep',1,'seconds (0 = sleep at powerup)');")); // first string is suffix, second string is prefix + } + + /* + * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). + * This could be used in the future for the system to determine whether your usermod is installed. + */ + uint16_t getId() { + return USERMOD_ID_DEEP_SLEEP; + } + +}; + +// add more strings here to reduce flash memory usage +const char DeepSleepUsermod::_name[] PROGMEM = "DeepSleep"; +const char DeepSleepUsermod::_enabled[] PROGMEM = "enabled"; \ No newline at end of file diff --git a/wled00/const.h b/wled00/const.h index 928b150d..bdd20beb 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -203,6 +203,7 @@ #define USERMOD_ID_LD2410 52 //Usermod "usermod_ld2410.h" #define USERMOD_ID_POV_DISPLAY 53 //Usermod "usermod_pov_display.h" #define USERMOD_ID_PIXELS_DICE_TRAY 54 //Usermod "pixels_dice_tray.h" +#define USERMOD_ID_DEEP_SLEEP 55 //Usermod "usermod_deep_sleep.h" //Access point behavior #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp index 3283e013..627fa630 100644 --- a/wled00/usermods_list.cpp +++ b/wled00/usermods_list.cpp @@ -242,6 +242,11 @@ #include "../usermods/LD2410_v2/usermod_ld2410.h" #endif + +#ifdef USERMOD_DEEP_SLEEP + #include "../usermods/deep_sleep/usermod_deep_sleep.h" +#endif + void registerUsermods() { /* @@ -470,4 +475,8 @@ void registerUsermods() #ifdef USERMOD_POV_DISPLAY UsermodManager::add(new PovDisplayUsermod()); #endif + + #ifdef USERMOD_DEEP_SLEEP + usermods.add(new DeepSleepUsermod()); + #endif } From 27e98147ef481d6cef7d9cdbc153b40402c43104 Mon Sep 17 00:00:00 2001 From: netmindz Date: Sun, 5 Jan 2025 18:49:51 +0000 Subject: [PATCH 112/463] Swap from dev to alpha for our current work in progress builds whilst working towards the next version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 91e2a615..68260982 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wled", - "version": "0.16.0-dev", + "version": "0.16.0-alpha", "description": "Tools for WLED project", "main": "tools/cdata.js", "directories": { From 3adcbb7904ffca360e00caf2b0ebf42dac90089b Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 6 Jan 2025 22:24:28 +0100 Subject: [PATCH 113/463] Playlist output glitchfix update: found it also happens on S3 (#4462) * Fix output glitches when playlist changes preset update: glitches also happen on S3 --- wled00/presets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/presets.cpp b/wled00/presets.cpp index fb09d48a..1abcb52b 100644 --- a/wled00/presets.cpp +++ b/wled00/presets.cpp @@ -164,7 +164,7 @@ void handlePresets() DEBUG_PRINTF_P(PSTR("Applying preset: %u\n"), (unsigned)tmpPreset); - #if defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32C3) + #if defined(ARDUINO_ARCH_ESP32S3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32C3) unsigned long start = millis(); while (strip.isUpdating() && millis() - start < FRAMETIME_FIXED) yield(); // wait for strip to finish updating, accessing FS during sendout causes glitches #endif From 50d505b8963b053e612f8e82d99a4d0fbf065659 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 8 Jan 2025 08:50:33 +0000 Subject: [PATCH 114/463] Nightly release --- .github/workflows/nightly.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/nightly.yml diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml new file mode 100644 index 00000000..58e31472 --- /dev/null +++ b/.github/workflows/nightly.yml @@ -0,0 +1,31 @@ + +name: Deploy Nightly +on: + # This can be used to automatically publish nightlies at UTC nighttime + schedule: + - cron: '0 2 * * *' # run at 2 AM UTC + # This can be used to allow manually triggering nightlies from the web interface + workflow_dispatch: + +jobs: + wled_build: + uses: ./.github/workflows/build.yml + nightly: + name: Deploy nightly + runs-on: ubuntu-latest + needs: wled_build + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + merge-multiple: true + + - name: Deploy release + uses: WebFreak001/deploy-nightly@v3.2.0 + with: + upload_url: https://uploads.github.com/repos/Aircoookie/WLED/releases/190052071/assets{?name,label} + release_id: 190052071 + asset_path: ./WLED_*_ESP32.bin + asset_name: WLED_$$_ESP32.bin + asset_content_type: application/octet-stream + max_releases: 7 From 7d29edf6f46fe6b9bdffb482b55f18e6765ace2a Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 8 Jan 2025 09:01:15 +0000 Subject: [PATCH 115/463] Nightly release - fix filename --- .github/workflows/nightly.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 58e31472..d3c20d65 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -19,13 +19,14 @@ jobs: uses: actions/download-artifact@v4 with: merge-multiple: true - + - name: Show Files + run: ls -la - name: Deploy release uses: WebFreak001/deploy-nightly@v3.2.0 with: upload_url: https://uploads.github.com/repos/Aircoookie/WLED/releases/190052071/assets{?name,label} release_id: 190052071 - asset_path: ./WLED_*_ESP32.bin - asset_name: WLED_$$_ESP32.bin + asset_path: firmware-esp32dev.zip + asset_name: WLED_$$_ESP32.zip asset_content_type: application/octet-stream max_releases: 7 From 438c5d9909a7f1a676d13d3840aedb08a5e680d4 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 8 Jan 2025 09:05:28 +0000 Subject: [PATCH 116/463] Nightly release - fix filename --- .github/workflows/nightly.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index d3c20d65..f350085b 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -26,7 +26,7 @@ jobs: with: upload_url: https://uploads.github.com/repos/Aircoookie/WLED/releases/190052071/assets{?name,label} release_id: 190052071 - asset_path: firmware-esp32dev.zip - asset_name: WLED_$$_ESP32.zip + asset_path: WLED_0.16.0-alpha_ESP32.bin + asset_name: WLED_$$_ESP32.bin asset_content_type: application/octet-stream max_releases: 7 From 0c431d9746e92aea36caf354880060fe5f172f26 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 8 Jan 2025 09:22:00 +0000 Subject: [PATCH 117/463] Nightly release - fix release --- .github/workflows/nightly.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index f350085b..8d15a7f2 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -24,8 +24,8 @@ jobs: - name: Deploy release uses: WebFreak001/deploy-nightly@v3.2.0 with: - upload_url: https://uploads.github.com/repos/Aircoookie/WLED/releases/190052071/assets{?name,label} - release_id: 190052071 + upload_url: https://uploads.github.com/repos/Aircoookie/WLED/releases/193651519/assets{?name,label} + release_id: 193651519 asset_path: WLED_0.16.0-alpha_ESP32.bin asset_name: WLED_$$_ESP32.bin asset_content_type: application/octet-stream From 5e3b4c3a110bddadfbf2fedf7ae9f30b9e8ea4f5 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 8 Jan 2025 09:32:12 +0000 Subject: [PATCH 118/463] Nightly release - swap action --- .github/workflows/nightly.yml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 8d15a7f2..918e2ab0 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -21,12 +21,14 @@ jobs: merge-multiple: true - name: Show Files run: ls -la - - name: Deploy release - uses: WebFreak001/deploy-nightly@v3.2.0 + - name: Update Nightly Release + uses: andelf/nightly-release@main + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - upload_url: https://uploads.github.com/repos/Aircoookie/WLED/releases/193651519/assets{?name,label} - release_id: 193651519 - asset_path: WLED_0.16.0-alpha_ESP32.bin - asset_name: WLED_$$_ESP32.bin - asset_content_type: application/octet-stream - max_releases: 7 + tag_name: nightly + name: 'Nightly Release $$' + prerelease: true + body: 'Nightly build' + files: | + ./*.bin \ No newline at end of file From 1750512477fb009b552807a01390be7add7c535e Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 8 Jan 2025 09:50:54 +0000 Subject: [PATCH 119/463] Nightly release - add changelog --- .github/workflows/nightly.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 918e2ab0..d67706dd 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -21,6 +21,12 @@ jobs: merge-multiple: true - name: Show Files run: ls -la + - name: "✏️ Generate release changelog" + id: changelog + uses: janheinrichmerker/action-github-changelog-generator@v2.3 + with: + token: ${{ secrets.GITHUB_TOKEN }} + sinceTag: nightly - name: Update Nightly Release uses: andelf/nightly-release@main env: @@ -29,6 +35,6 @@ jobs: tag_name: nightly name: 'Nightly Release $$' prerelease: true - body: 'Nightly build' + body: ${{ steps.changelog.outputs.changelog }} files: | ./*.bin \ No newline at end of file From d0e99923fdc9af8f5c32888514e9b8bf559ffbca Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 8 Jan 2025 09:55:41 +0000 Subject: [PATCH 120/463] Nightly release - add changelog --- .github/workflows/build.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e5fdfc5a..af523074 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,5 +1,3 @@ -name: WLED Build - # Only included into other workflows on: workflow_call: From 08b263bf4e8b9443aeaab0d00810ce522a1391d4 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 8 Jan 2025 09:55:52 +0000 Subject: [PATCH 121/463] Nightly release - add changelog --- .github/workflows/nightly.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index d67706dd..4503d63b 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -27,6 +27,7 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} sinceTag: nightly + onlyLastTag: true - name: Update Nightly Release uses: andelf/nightly-release@main env: From f626dfb7b7d636127b29698f24a98afe79dd7f85 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 8 Jan 2025 10:00:39 +0000 Subject: [PATCH 122/463] Nightly release - add changelog since last release --- .github/workflows/build.yml | 2 ++ .github/workflows/nightly.yml | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index af523074..e5fdfc5a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,3 +1,5 @@ +name: WLED Build + # Only included into other workflows on: workflow_call: diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 4503d63b..13873005 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -26,8 +26,7 @@ jobs: uses: janheinrichmerker/action-github-changelog-generator@v2.3 with: token: ${{ secrets.GITHUB_TOKEN }} - sinceTag: nightly - onlyLastTag: true + sinceTag: v0.15.0 - name: Update Nightly Release uses: andelf/nightly-release@main env: From bb0c0af1893e774f8401515083097caf0429c381 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 9 Jan 2025 22:41:45 +0100 Subject: [PATCH 123/463] added a delay after switching relay (#4474) - helps to stabilize power on the LEDs before sending data --- wled00/button.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/wled00/button.cpp b/wled00/button.cpp index 6f9c8456..4e063c12 100644 --- a/wled00/button.cpp +++ b/wled00/button.cpp @@ -375,6 +375,7 @@ void handleIO() if (rlyPin>=0) { pinMode(rlyPin, rlyOpenDrain ? OUTPUT_OPEN_DRAIN : OUTPUT); digitalWrite(rlyPin, rlyMde); + delay(50); // wait for relay to switch and power to stabilize } offMode = false; } From ec7a7f4c2522f9958636ceca802b9f6ed24ff64a Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 10 Jan 2025 16:49:15 +0000 Subject: [PATCH 124/463] Set build version during nightly build --- .github/workflows/nightly.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 13873005..acf974ff 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -8,7 +8,15 @@ on: workflow_dispatch: jobs: + prep: + runs-on: ubuntu-latest + steps: + - name: Set Version + run: | + VERSION=`date +%y%m%d0` + sed -i -r -e "s/#define VERSION .+/#define VERSION $VERSION/" wled00/wled.h wled_build: + needs: prep uses: ./.github/workflows/build.yml nightly: name: Deploy nightly From 471bd83eb2dd9fa3636d89b884378cb6a65e62ad Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 10 Jan 2025 16:53:20 +0000 Subject: [PATCH 125/463] Revert "Set build version during nightly build" - doesn't work as source files not yet checked out This reverts commit ec7a7f4c2522f9958636ceca802b9f6ed24ff64a. --- .github/workflows/nightly.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index acf974ff..13873005 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -8,15 +8,7 @@ on: workflow_dispatch: jobs: - prep: - runs-on: ubuntu-latest - steps: - - name: Set Version - run: | - VERSION=`date +%y%m%d0` - sed -i -r -e "s/#define VERSION .+/#define VERSION $VERSION/" wled00/wled.h wled_build: - needs: prep uses: ./.github/workflows/build.yml nightly: name: Deploy nightly From 2aab617c2e2d3f49ba786532b0e44508659f1fae Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 10 Jan 2025 16:56:07 +0000 Subject: [PATCH 126/463] Reapply "Set build version during nightly build" - doesn't work as source This reverts commit 471bd83eb2dd9fa3636d89b884378cb6a65e62ad. --- .github/workflows/nightly.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 13873005..acf974ff 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -8,7 +8,15 @@ on: workflow_dispatch: jobs: + prep: + runs-on: ubuntu-latest + steps: + - name: Set Version + run: | + VERSION=`date +%y%m%d0` + sed -i -r -e "s/#define VERSION .+/#define VERSION $VERSION/" wled00/wled.h wled_build: + needs: prep uses: ./.github/workflows/build.yml nightly: name: Deploy nightly From 4a56c92e7b87703166e0ef6dfa3b54f68ffeb237 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 10 Jan 2025 16:59:08 +0000 Subject: [PATCH 127/463] Set build version during nightly build --- .github/workflows/build.yml | 2 ++ .github/workflows/nightly.yml | 1 + 2 files changed, 3 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2bac314f..5a25bb4d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,6 +11,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + clean: false - uses: actions/setup-python@v5 with: python-version: '3.12' diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index acf974ff..6bc57750 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -11,6 +11,7 @@ jobs: prep: runs-on: ubuntu-latest steps: + - uses: actions/checkout@v4 - name: Set Version run: | VERSION=`date +%y%m%d0` From 3502a391811df0e309cb83063dddd77de2e056ef Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 10 Jan 2025 17:09:11 +0000 Subject: [PATCH 128/463] Revert "Set build version during nightly build" This reverts commit 4a56c92e7b87703166e0ef6dfa3b54f68ffeb237. --- .github/workflows/build.yml | 2 -- .github/workflows/nightly.yml | 1 - 2 files changed, 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5a25bb4d..2bac314f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,8 +11,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - with: - clean: false - uses: actions/setup-python@v5 with: python-version: '3.12' diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 6bc57750..acf974ff 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -11,7 +11,6 @@ jobs: prep: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - name: Set Version run: | VERSION=`date +%y%m%d0` From c4e697d797e1d7eef72f39de72be3268c9a14535 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Fri, 10 Jan 2025 17:09:25 +0000 Subject: [PATCH 129/463] Revert "Reapply "Set build version during nightly build" - doesn't work as source" This reverts commit 2aab617c2e2d3f49ba786532b0e44508659f1fae. --- .github/workflows/nightly.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index acf974ff..13873005 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -8,15 +8,7 @@ on: workflow_dispatch: jobs: - prep: - runs-on: ubuntu-latest - steps: - - name: Set Version - run: | - VERSION=`date +%y%m%d0` - sed -i -r -e "s/#define VERSION .+/#define VERSION $VERSION/" wled00/wled.h wled_build: - needs: prep uses: ./.github/workflows/build.yml nightly: name: Deploy nightly From b8685f2c39b78286dddd1ad03e19284c9978dde4 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sat, 14 Sep 2024 15:09:47 -0400 Subject: [PATCH 130/463] Convert usermods to static libraries Redesign the usermod system so that usermods are implemented as PlatformIO libraries instead of headers. This permits them to call for dependencies, and eliminates the compiler flags for enabling each one, allowing the build cache to behave better. The usermod list is built using some linker magic to construct a static list in ROM memory. This eliminates the need for wasting SRAM on something fixed at build time. --- pio-scripts/load_usermods.py | 9 + platformio.ini | 35 +- .../{audio_reactive.h => audio_reactive.cpp} | 4 +- usermods/audioreactive/library.json | 17 + usermods/usermod_v2_auto_save/library.json | 8 + ...2_auto_save.h => usermod_v2_auto_save.cpp} | 3 + wled00/fcn_declare.h | 11 +- wled00/um_manager.cpp | 72 +-- wled00/usermod_v2_empty.h | 18 - wled00/usermods_list.cpp | 482 ------------------ wled00/wled.cpp | 3 - 11 files changed, 100 insertions(+), 562 deletions(-) create mode 100644 pio-scripts/load_usermods.py rename usermods/audioreactive/{audio_reactive.h => audio_reactive.cpp} (99%) create mode 100644 usermods/audioreactive/library.json create mode 100644 usermods/usermod_v2_auto_save/library.json rename usermods/usermod_v2_auto_save/{usermod_v2_auto_save.h => usermod_v2_auto_save.cpp} (99%) delete mode 100644 wled00/usermod_v2_empty.h delete mode 100644 wled00/usermods_list.cpp diff --git a/pio-scripts/load_usermods.py b/pio-scripts/load_usermods.py new file mode 100644 index 00000000..ac761131 --- /dev/null +++ b/pio-scripts/load_usermods.py @@ -0,0 +1,9 @@ +Import('env') +usermods = env.GetProjectOption("custom_usermods","") +if usermods: + proj = env.GetProjectConfig() + deps = env.GetProjectOption('lib_deps') + src_dir = proj.get("platformio", "src_dir") + src_dir = src_dir.replace('\\','/') + usermods = [f"{mod} = symlink://{src_dir}/../usermods/{mod}" for mod in usermods.split(" ")] + proj.set("env:" + env['PIOENV'], 'lib_deps', deps + usermods) diff --git a/platformio.ini b/platformio.ini index 0870cde9..1597343d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -114,6 +114,7 @@ extra_scripts = post:pio-scripts/output_bins.py post:pio-scripts/strip-floats.py pre:pio-scripts/user_config_copy.py + pre:pio-scripts/load_usermods.py pre:pio-scripts/build_ui.py ; post:pio-scripts/obj-dump.py ;; convenience script to create a disassembly dump of the firmware (hardcore debugging) @@ -170,8 +171,6 @@ lib_deps = ;https://github.com/netmindz/animartrix.git#18bf17389e57c69f11bc8d04ebe1d215422c7fb7 # SHT85 ;robtillaart/SHT85@~0.3.3 - # Audioreactive usermod - ;kosme/arduinoFFT @ 2.0.1 extra_scripts = ${scripts_defaults.extra_scripts} @@ -261,11 +260,11 @@ lib_deps = https://github.com/lorol/LITTLEFS.git https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 ${env.lib_deps} -# additional build flags for audioreactive -AR_build_flags = -D USERMOD_AUDIOREACTIVE - -D sqrt_internal=sqrtf ;; -fsingle-precision-constant ;; forces ArduinoFFT to use float math (2x faster) -AR_lib_deps = kosme/arduinoFFT @ 2.0.1 board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs +# additional build flags for audioreactive - must be applied globally +AR_build_flags = -D sqrt_internal=sqrtf ;; -fsingle-precision-constant ;; forces ArduinoFFT to use float math (2x faster) +AR_lib_deps = kosme/arduinoFFT @ 2.0.1 ;; for pre-usermod-library platformio_override compatibility + [esp32_idf_V4] ;; experimental build environment for ESP32 using ESP-IDF 4.4.x / arduino-esp32 v2.0.5 @@ -424,11 +423,11 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME= board = esp32dev platform = ${esp32.platform} platform_packages = ${esp32.platform_packages} +custom_usermods = audioreactive build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32\" #-D WLED_DISABLE_BROWNOUT_DET ${esp32.AR_build_flags} lib_deps = ${esp32.lib_deps} - ${esp32.AR_lib_deps} monitor_filters = esp32_exception_decoder board_build.partitions = ${esp32.default_partitions} @@ -436,11 +435,11 @@ board_build.partitions = ${esp32.default_partitions} board = esp32dev platform = ${esp32_idf_V4.platform} platform_packages = ${esp32_idf_V4.platform_packages} +custom_usermods = audioreactive build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_8M\" #-D WLED_DISABLE_BROWNOUT_DET ${esp32.AR_build_flags} lib_deps = ${esp32_idf_V4.lib_deps} - ${esp32.AR_lib_deps} monitor_filters = esp32_exception_decoder board_build.partitions = ${esp32.large_partitions} board_upload.flash_size = 8MB @@ -452,11 +451,11 @@ board_upload.maximum_size = 8388608 board = esp32dev platform = ${esp32_idf_V4.platform} platform_packages = ${esp32_idf_V4.platform_packages} +custom_usermods = audioreactive build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_16M\" #-D WLED_DISABLE_BROWNOUT_DET ${esp32.AR_build_flags} lib_deps = ${esp32_idf_V4.lib_deps} - ${esp32.AR_lib_deps} monitor_filters = esp32_exception_decoder board_build.partitions = ${esp32.extreme_partitions} board_upload.flash_size = 16MB @@ -468,11 +467,11 @@ board_build.flash_mode = dio ;board = esp32dev ;platform = ${esp32.platform} ;platform_packages = ${esp32.platform_packages} +;custom_usermods = audioreactive ;build_unflags = ${common.build_unflags} ;build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32_audioreactive\" #-D WLED_DISABLE_BROWNOUT_DET ; ${esp32.AR_build_flags} ;lib_deps = ${esp32.lib_deps} -; ${esp32.AR_lib_deps} ;monitor_filters = esp32_exception_decoder ;board_build.partitions = ${esp32.default_partitions} ;; board_build.f_flash = 80000000L @@ -483,12 +482,12 @@ board = esp32-poe platform = ${esp32.platform} platform_packages = ${esp32.platform_packages} upload_speed = 921600 +custom_usermods = audioreactive build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32_Ethernet\" -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1 ; -D WLED_DISABLE_ESPNOW ;; ESP-NOW requires wifi, may crash with ethernet only ${esp32.AR_build_flags} lib_deps = ${esp32.lib_deps} - ${esp32.AR_lib_deps} board_build.partitions = ${esp32.default_partitions} [env:esp32_wrover] @@ -499,14 +498,14 @@ board = ttgo-t7-v14-mini32 board_build.f_flash = 80000000L board_build.flash_mode = qio board_build.partitions = ${esp32.extended_partitions} +custom_usermods = audioreactive build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_WROVER\" -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue ;; Older ESP32 (rev.<3) need a PSRAM fix (increases static RAM used) https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/external-ram.html -D DATA_PINS=25 ${esp32.AR_build_flags} lib_deps = ${esp32_idf_V4.lib_deps} - ${esp32.AR_lib_deps} - + [env:esp32c3dev] extends = esp32c3 platform = ${esp32c3.platform} @@ -530,6 +529,7 @@ board_build.arduino.memory_type = qio_opi ;; use with PSRAM: 8MB or 16MB platform = ${esp32s3.platform} platform_packages = ${esp32s3.platform_packages} upload_speed = 921600 +custom_usermods = audioreactive build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_16MB_opi\" -D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0 @@ -538,7 +538,6 @@ build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME= -DBOARD_HAS_PSRAM ${esp32.AR_build_flags} lib_deps = ${esp32s3.lib_deps} - ${esp32.AR_lib_deps} board_build.partitions = ${esp32.extreme_partitions} board_upload.flash_size = 16MB board_upload.maximum_size = 16777216 @@ -553,6 +552,7 @@ board_build.arduino.memory_type = qio_opi ;; use with PSRAM: 8MB or 16MB platform = ${esp32s3.platform} platform_packages = ${esp32s3.platform_packages} upload_speed = 921600 +custom_usermods = audioreactive build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_8MB_opi\" -D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0 @@ -561,7 +561,6 @@ build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME= -DBOARD_HAS_PSRAM ${esp32.AR_build_flags} lib_deps = ${esp32s3.lib_deps} - ${esp32.AR_lib_deps} board_build.partitions = ${esp32.large_partitions} board_build.f_flash = 80000000L board_build.flash_mode = qio @@ -575,6 +574,7 @@ platform_packages = ${esp32s3.platform_packages} board = esp32s3camlcd ;; this is the only standard board with "opi_opi" board_build.arduino.memory_type = opi_opi upload_speed = 921600 +custom_usermods = audioreactive build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_WROOM-2\" -D CONFIG_LITTLEFS_FOR_IDF_3_2 -D WLED_WATCHDOG_TIMEOUT=0 @@ -587,7 +587,6 @@ build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME= ${esp32.AR_build_flags} -D SR_DMTYPE=1 -D I2S_SDPIN=13 -D I2S_CKPIN=14 -D I2S_WSPIN=15 -D MCLK_PIN=4 ;; I2S mic lib_deps = ${esp32s3.lib_deps} - ${esp32.AR_lib_deps} board_build.partitions = ${esp32.extreme_partitions} board_upload.flash_size = 16MB @@ -600,6 +599,7 @@ board = lolin_s3_mini ;; -S3 mini, 4MB flash 2MB PSRAM platform = ${esp32s3.platform} platform_packages = ${esp32s3.platform_packages} upload_speed = 921600 +custom_usermods = audioreactive build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_4M_qspi\" -DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB") @@ -608,7 +608,6 @@ build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME= -D WLED_WATCHDOG_TIMEOUT=0 ${esp32.AR_build_flags} lib_deps = ${esp32s3.lib_deps} - ${esp32.AR_lib_deps} board_build.partitions = ${esp32.default_partitions} board_build.f_flash = 80000000L board_build.flash_mode = qio @@ -621,6 +620,7 @@ board = lolin_s2_mini board_build.partitions = ${esp32.default_partitions} board_build.flash_mode = qio board_build.f_flash = 80000000L +custom_usermods = audioreactive build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S2\" -DARDUINO_USB_CDC_ON_BOOT=1 @@ -639,4 +639,3 @@ build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME= ; -D STATUSLED=15 ${esp32.AR_build_flags} lib_deps = ${esp32s2.lib_deps} - ${esp32.AR_lib_deps} diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.cpp similarity index 99% rename from usermods/audioreactive/audio_reactive.h rename to usermods/audioreactive/audio_reactive.cpp index 9c463e0a..a5bf782a 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.cpp @@ -1,4 +1,3 @@ -#pragma once #include "wled.h" @@ -2064,3 +2063,6 @@ const char AudioReactive::_digitalmic[] PROGMEM = "digitalmic"; const char AudioReactive::_addPalettes[] PROGMEM = "add-palettes"; const char AudioReactive::UDP_SYNC_HEADER[] PROGMEM = "00002"; // new sync header version, as format no longer compatible with previous structure const char AudioReactive::UDP_SYNC_HEADER_v1[] PROGMEM = "00001"; // old sync header version - need to add backwards-compatibility feature + +static AudioReactive ar_module; +REGISTER_USERMOD(ar_module); diff --git a/usermods/audioreactive/library.json b/usermods/audioreactive/library.json new file mode 100644 index 00000000..658bf943 --- /dev/null +++ b/usermods/audioreactive/library.json @@ -0,0 +1,17 @@ +{ + "name": "audioreactive", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + }, + "dependencies": [ + { + "owner": "kosme", + "name": "arduinoFFT", + "version": "2.0.1", + "platforms": "espressif32" + } + ] +} \ No newline at end of file diff --git a/usermods/usermod_v2_auto_save/library.json b/usermods/usermod_v2_auto_save/library.json new file mode 100644 index 00000000..40676ed5 --- /dev/null +++ b/usermods/usermod_v2_auto_save/library.json @@ -0,0 +1,8 @@ +{ + "name": "auto_save", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+" + } +} \ No newline at end of file diff --git a/usermods/usermod_v2_auto_save/usermod_v2_auto_save.h b/usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp similarity index 99% rename from usermods/usermod_v2_auto_save/usermod_v2_auto_save.h rename to usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp index a257413b..2dae867d 100644 --- a/usermods/usermod_v2_auto_save/usermod_v2_auto_save.h +++ b/usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp @@ -275,3 +275,6 @@ const char AutoSaveUsermod::_autoSaveEnabled[] PROGMEM = "enabled"; const char AutoSaveUsermod::_autoSaveAfterSec[] PROGMEM = "autoSaveAfterSec"; const char AutoSaveUsermod::_autoSavePreset[] PROGMEM = "autoSavePreset"; const char AutoSaveUsermod::_autoSaveApplyOnBoot[] PROGMEM = "autoSaveApplyOnBoot"; + +static AutoSaveUsermod autosave; +REGISTER_USERMOD(autosave); diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index cb21e8c2..cfb18c25 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -381,7 +381,7 @@ class Usermod { protected: um_data_t *um_data; // um_data should be allocated using new in (derived) Usermod's setup() or constructor public: - Usermod() { um_data = nullptr; } + Usermod() : um_data(nullptr) {}; virtual ~Usermod() { if (um_data) delete um_data; } virtual void setup() = 0; // pure virtual, has to be overriden virtual void loop() = 0; // pure virtual, has to be overriden @@ -418,8 +418,6 @@ class Usermod { }; namespace UsermodManager { - extern byte numMods; - void loop(); void handleOverlayDraw(); bool handleButton(uint8_t b); @@ -441,13 +439,12 @@ namespace UsermodManager { #endif void onUpdateBegin(bool); void onStateChange(uint8_t); - bool add(Usermod* um); Usermod* lookup(uint16_t mod_id); - inline byte getModCount() {return numMods;}; + size_t getModCount(); }; -//usermods_list.cpp -void registerUsermods(); +// Register usermods by building a static list via a linker section +#define REGISTER_USERMOD(x) Usermod* const um_##x __attribute__((__section__(".dtors.tbl.usermods.1"), used)) = &x //usermod.cpp void userSetup(); diff --git a/wled00/um_manager.cpp b/wled00/um_manager.cpp index 1fdb6d68..9bfb7e73 100644 --- a/wled00/um_manager.cpp +++ b/wled00/um_manager.cpp @@ -3,75 +3,81 @@ * Registration and management utility for v2 usermods */ -static Usermod* ums[WLED_MAX_USERMODS] = {nullptr}; -byte UsermodManager::numMods = 0; +// Global usermod instance list +// Table begin and end references +// Zero-length arrays -- so they'll get assigned addresses, but consume no flash +// The numeric suffix ensures they're put in the right place; the linker script will sort them +// We stick them in the '.dtors' segment because it's always included by the linker scripts +// even though it never gets called. Who calls exit() in an embedded program anyways? +// If someone ever does, though, it'll explode as these aren't function pointers. +static Usermod * const _usermod_table_begin[0] __attribute__((__section__(".dtors.tbl.usermods.0"), unused)) = {}; +static Usermod * const _usermod_table_end[0] __attribute__((__section__(".dtors.tbl.usermods.99"), unused)) = {}; + +static size_t getCount() { + return &_usermod_table_end[0] - &_usermod_table_begin[0]; +} + //Usermod Manager internals -void UsermodManager::setup() { for (unsigned i = 0; i < numMods; i++) ums[i]->setup(); } -void UsermodManager::connected() { for (unsigned i = 0; i < numMods; i++) ums[i]->connected(); } -void UsermodManager::loop() { for (unsigned i = 0; i < numMods; i++) ums[i]->loop(); } -void UsermodManager::handleOverlayDraw() { for (unsigned i = 0; i < numMods; i++) ums[i]->handleOverlayDraw(); } -void UsermodManager::appendConfigData(Print& dest) { for (unsigned i = 0; i < numMods; i++) ums[i]->appendConfigData(dest); } +void UsermodManager::setup() { for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) (*mod)->setup(); } +void UsermodManager::connected() { for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) (*mod)->connected(); } +void UsermodManager::loop() { for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) (*mod)->loop(); } +void UsermodManager::handleOverlayDraw() { for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) (*mod)->handleOverlayDraw(); } +void UsermodManager::appendConfigData(Print& dest) { for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) (*mod)->appendConfigData(dest); } bool UsermodManager::handleButton(uint8_t b) { bool overrideIO = false; - for (unsigned i = 0; i < numMods; i++) { - if (ums[i]->handleButton(b)) overrideIO = true; + for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) { + if ((*mod)->handleButton(b)) overrideIO = true; } return overrideIO; } bool UsermodManager::getUMData(um_data_t **data, uint8_t mod_id) { - for (unsigned i = 0; i < numMods; i++) { - if (mod_id > 0 && ums[i]->getId() != mod_id) continue; // only get data form requested usermod if provided - if (ums[i]->getUMData(data)) return true; // if usermod does provide data return immediately (only one usermod can provide data at one time) + for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) { + if (mod_id > 0 && (*mod)->getId() != mod_id) continue; // only get data form requested usermod if provided + if ((*mod)->getUMData(data)) return true; // if usermod does provide data return immediately (only one usermod can provide data at one time) } return false; } -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); } -void UsermodManager::addToConfig(JsonObject& obj) { for (unsigned i = 0; i < numMods; i++) ums[i]->addToConfig(obj); } +void UsermodManager::addToJsonState(JsonObject& obj) { for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) (*mod)->addToJsonState(obj); } +void UsermodManager::addToJsonInfo(JsonObject& obj) { for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) (*mod)->addToJsonInfo(obj); } +void UsermodManager::readFromJsonState(JsonObject& obj) { for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) (*mod)->readFromJsonState(obj); } +void UsermodManager::addToConfig(JsonObject& obj) { for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) (*mod)->addToConfig(obj); } bool UsermodManager::readFromConfig(JsonObject& obj) { bool allComplete = true; - for (unsigned i = 0; i < numMods; i++) { - if (!ums[i]->readFromConfig(obj)) allComplete = false; + for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) { + if (!(*mod)->readFromConfig(obj)) allComplete = false; } return allComplete; } #ifndef WLED_DISABLE_MQTT -void UsermodManager::onMqttConnect(bool sessionPresent) { for (unsigned i = 0; i < numMods; i++) ums[i]->onMqttConnect(sessionPresent); } +void UsermodManager::onMqttConnect(bool sessionPresent) { for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) (*mod)->onMqttConnect(sessionPresent); } bool UsermodManager::onMqttMessage(char* topic, char* payload) { - for (unsigned i = 0; i < numMods; i++) if (ums[i]->onMqttMessage(topic, payload)) return true; + for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) if ((*mod)->onMqttMessage(topic, payload)) return true; return false; } #endif #ifndef WLED_DISABLE_ESPNOW bool UsermodManager::onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t len) { - for (unsigned i = 0; i < numMods; i++) if (ums[i]->onEspNowMessage(sender, payload, len)) return true; + for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) if ((*mod)->onEspNowMessage(sender, payload, len)) return true; return false; } #endif -void UsermodManager::onUpdateBegin(bool init) { for (unsigned i = 0; i < numMods; i++) ums[i]->onUpdateBegin(init); } // notify usermods that update is to begin -void UsermodManager::onStateChange(uint8_t mode) { for (unsigned i = 0; i < numMods; i++) ums[i]->onStateChange(mode); } // notify usermods that WLED state changed +void UsermodManager::onUpdateBegin(bool init) { for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) (*mod)->onUpdateBegin(init); } // notify usermods that update is to begin +void UsermodManager::onStateChange(uint8_t mode) { for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) (*mod)->onStateChange(mode); } // notify usermods that WLED state changed /* * Enables usermods to lookup another Usermod. */ Usermod* UsermodManager::lookup(uint16_t mod_id) { - for (unsigned i = 0; i < numMods; i++) { - if (ums[i]->getId() == mod_id) { - return ums[i]; + for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) { + if ((*mod)->getId() == mod_id) { + return *mod; } } return nullptr; } -bool UsermodManager::add(Usermod* um) -{ - if (numMods >= WLED_MAX_USERMODS || um == nullptr) return false; - ums[numMods++] = um; - return true; -} - +size_t UsermodManager::getModCount() { return getCount(); }; /* Usermod v2 interface shim for oappend */ Print* Usermod::oappend_shim = nullptr; diff --git a/wled00/usermod_v2_empty.h b/wled00/usermod_v2_empty.h deleted file mode 100644 index 6537b56b..00000000 --- a/wled00/usermod_v2_empty.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "wled.h" - -//This is an empty v2 usermod template. Please see the file usermod_v2_example.h in the EXAMPLE_v2 usermod folder for documentation on the functions you can use! - -class UsermodRenameMe : public Usermod { - private: - - public: - void setup() { - - } - - void loop() { - - } -}; \ No newline at end of file diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp deleted file mode 100644 index 627fa630..00000000 --- a/wled00/usermods_list.cpp +++ /dev/null @@ -1,482 +0,0 @@ -#include "wled.h" -/* - * Register your v2 usermods here! - * (for v1 usermods using just usermod.cpp, you can ignore this file) - */ - -/* - * Add/uncomment your usermod filename here (and once more below) - * || || || - * \/ \/ \/ - */ -//#include "../usermods/EXAMPLE_v2/usermod_v2_example.h" - -#ifdef USERMOD_BATTERY - #include "../usermods/Battery/usermod_v2_Battery.h" -#endif - -#ifdef USERMOD_DALLASTEMPERATURE - #include "../usermods/Temperature/usermod_temperature.h" -#endif - -#ifdef USERMOD_SHT -#include "../usermods/sht/usermod_sht.h" -#endif - -#ifdef USERMOD_SN_PHOTORESISTOR - #include "../usermods/SN_Photoresistor/usermod_sn_photoresistor.h" -#endif - -#ifdef USERMOD_PWM_FAN - // requires DALLASTEMPERATURE or SHT included before it - #include "../usermods/PWM_fan/usermod_PWM_fan.h" -#endif - -#ifdef USERMOD_BUZZER - #include "../usermods/buzzer/usermod_v2_buzzer.h" -#endif - -#ifdef USERMOD_SENSORSTOMQTT - #include "../usermods/sensors_to_mqtt/usermod_v2_SensorsToMqtt.h" -#endif - -#ifdef USERMOD_PIRSWITCH - #include "../usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h" -#endif - -#ifdef USERMOD_BH1750 - #include "../usermods/BH1750_v2/usermod_bh1750.h" -#endif - -// BME280 v2 usermod. Define "USERMOD_BME280" in my_config.h -#ifdef USERMOD_BME280 - #include "../usermods/BME280_v2/usermod_bme280.h" -#endif - -#ifdef USERMOD_BME68X - #include "../usermods/BME68X_v2/usermod_bme68x.h" -#endif - - -#ifdef USERMOD_FOUR_LINE_DISPLAY - #include "../usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h" -#endif - -#ifdef USERMOD_ROTARY_ENCODER_UI - #include "../usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h" -#endif - -#ifdef USERMOD_AUTO_SAVE - #include "../usermods/usermod_v2_auto_save/usermod_v2_auto_save.h" -#endif - -#ifdef USERMOD_DHT - #include "../usermods/DHT/usermod_dht.h" -#endif - -#ifdef USERMOD_VL53L0X_GESTURES - #include "../usermods/VL53L0X_gestures/usermod_vl53l0x_gestures.h" -#endif - -#ifdef USERMOD_ANIMATED_STAIRCASE - #include "../usermods/Animated_Staircase/Animated_Staircase.h" -#endif - -#ifdef USERMOD_MULTI_RELAY - #include "../usermods/multi_relay/usermod_multi_relay.h" -#endif - -#ifdef USERMOD_RTC - #include "../usermods/RTC/usermod_rtc.h" -#endif - -#ifdef USERMOD_ELEKSTUBE_IPS - #include "../usermods/EleksTube_IPS/usermod_elekstube_ips.h" -#endif - -#ifdef USERMOD_ROTARY_ENCODER_BRIGHTNESS_COLOR - #include "../usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.h" -#endif - -#ifdef RGB_ROTARY_ENCODER - #include "../usermods/rgb-rotary-encoder/rgb-rotary-encoder.h" -#endif - -#ifdef USERMOD_ST7789_DISPLAY - #include "../usermods/ST7789_display/ST7789_Display.h" -#endif - -#ifdef USERMOD_PIXELS_DICE_TRAY - #include "../usermods/pixels_dice_tray/pixels_dice_tray.h" -#endif - -#ifdef USERMOD_SEVEN_SEGMENT - #include "../usermods/seven_segment_display/usermod_v2_seven_segment_display.h" -#endif - -#ifdef USERMOD_SSDR - #include "../usermods/seven_segment_display_reloaded/usermod_seven_segment_reloaded.h" -#endif - -#ifdef USERMOD_CRONIXIE - #include "../usermods/Cronixie/usermod_cronixie.h" -#endif - -#ifdef QUINLED_AN_PENTA - #include "../usermods/quinled-an-penta/quinled-an-penta.h" -#endif - -#ifdef USERMOD_WIZLIGHTS - #include "../usermods/wizlights/wizlights.h" -#endif - -#ifdef USERMOD_WIREGUARD - #include "../usermods/wireguard/wireguard.h" -#endif - -#ifdef USERMOD_WORDCLOCK - #include "../usermods/usermod_v2_word_clock/usermod_v2_word_clock.h" -#endif - -#ifdef USERMOD_MY9291 - #include "../usermods/MY9291/usermode_MY9291.h" -#endif - -#ifdef USERMOD_SI7021_MQTT_HA - #include "../usermods/Si7021_MQTT_HA/usermod_si7021_mqtt_ha.h" -#endif - -#ifdef USERMOD_SMARTNEST - #include "../usermods/smartnest/usermod_smartnest.h" -#endif - -#ifdef USERMOD_AUDIOREACTIVE - #include "../usermods/audioreactive/audio_reactive.h" -#endif - -#ifdef USERMOD_ANALOG_CLOCK - #include "../usermods/Analog_Clock/Analog_Clock.h" -#endif - -#ifdef USERMOD_PING_PONG_CLOCK - #include "../usermods/usermod_v2_ping_pong_clock/usermod_v2_ping_pong_clock.h" -#endif - -#ifdef USERMOD_ADS1115 - #include "../usermods/ADS1115_v2/usermod_ads1115.h" -#endif - -#ifdef USERMOD_KLIPPER_PERCENTAGE - #include "../usermods/usermod_v2_klipper_percentage/usermod_v2_klipper_percentage.h" -#endif - -#ifdef USERMOD_BOBLIGHT - #include "../usermods/boblight/boblight.h" -#endif - -#ifdef USERMOD_ANIMARTRIX - #include "../usermods/usermod_v2_animartrix/usermod_v2_animartrix.h" -#endif - -#ifdef USERMOD_INTERNAL_TEMPERATURE - #include "../usermods/Internal_Temperature_v2/usermod_internal_temperature.h" -#endif - -#if defined(WLED_USE_SD_MMC) || defined(WLED_USE_SD_SPI) -// This include of SD.h and SD_MMC.h must happen here, else they won't be -// resolved correctly (when included in mod's header only) - #ifdef WLED_USE_SD_MMC - #include "SD_MMC.h" - #elif defined(WLED_USE_SD_SPI) - #include "SD.h" - #include "SPI.h" - #endif - #include "../usermods/sd_card/usermod_sd_card.h" -#endif - -#ifdef USERMOD_PWM_OUTPUTS - #include "../usermods/pwm_outputs/usermod_pwm_outputs.h" -#endif - -#ifdef USERMOD_HTTP_PULL_LIGHT_CONTROL - #include "../usermods/usermod_v2_HttpPullLightControl/usermod_v2_HttpPullLightControl.h" -#endif - -#ifdef USERMOD_MPU6050_IMU - #include "../usermods/mpu6050_imu/usermod_mpu6050_imu.h" -#endif - -#ifdef USERMOD_MPU6050_IMU - #include "../usermods/mpu6050_imu/usermod_gyro_surge.h" -#endif - -#ifdef USERMOD_LDR_DUSK_DAWN - #include "../usermods/LDR_Dusk_Dawn_v2/usermod_LDR_Dusk_Dawn_v2.h" -#endif - -#ifdef USERMOD_POV_DISPLAY - #include "../usermods/pov_display/usermod_pov_display.h" -#endif - -#ifdef USERMOD_STAIRCASE_WIPE - #include "../usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h" -#endif - -#ifdef USERMOD_MAX17048 - #include "../usermods/MAX17048_v2/usermod_max17048.h" -#endif - -#ifdef USERMOD_TETRISAI - #include "../usermods/TetrisAI_v2/usermod_v2_tetrisai.h" -#endif - -#ifdef USERMOD_AHT10 - #include "../usermods/AHT10_v2/usermod_aht10.h" -#endif - -#ifdef USERMOD_INA226 - #include "../usermods/INA226_v2/usermod_ina226.h" -#endif - -#ifdef USERMOD_LD2410 -#include "../usermods/LD2410_v2/usermod_ld2410.h" -#endif - - -#ifdef USERMOD_DEEP_SLEEP - #include "../usermods/deep_sleep/usermod_deep_sleep.h" -#endif - -void registerUsermods() -{ -/* - * Add your usermod class name here - * || || || - * \/ \/ \/ - */ - //UsermodManager::add(new MyExampleUsermod()); - - #ifdef USERMOD_BATTERY - UsermodManager::add(new UsermodBattery()); - #endif - - #ifdef USERMOD_DALLASTEMPERATURE - UsermodManager::add(new UsermodTemperature()); - #endif - - #ifdef USERMOD_SN_PHOTORESISTOR - UsermodManager::add(new Usermod_SN_Photoresistor()); - #endif - - #ifdef USERMOD_PWM_FAN - UsermodManager::add(new PWMFanUsermod()); - #endif - - #ifdef USERMOD_BUZZER - UsermodManager::add(new BuzzerUsermod()); - #endif - - #ifdef USERMOD_BH1750 - UsermodManager::add(new Usermod_BH1750()); - #endif - - #ifdef USERMOD_BME280 - UsermodManager::add(new UsermodBME280()); - #endif - - #ifdef USERMOD_BME68X - UsermodManager::add(new UsermodBME68X()); - #endif - - #ifdef USERMOD_SENSORSTOMQTT - UsermodManager::add(new UserMod_SensorsToMQTT()); - #endif - - #ifdef USERMOD_PIRSWITCH - UsermodManager::add(new PIRsensorSwitch()); - #endif - - #ifdef USERMOD_FOUR_LINE_DISPLAY - UsermodManager::add(new FourLineDisplayUsermod()); - #endif - - #ifdef USERMOD_ROTARY_ENCODER_UI - UsermodManager::add(new RotaryEncoderUIUsermod()); // can use USERMOD_FOUR_LINE_DISPLAY - #endif - - #ifdef USERMOD_AUTO_SAVE - UsermodManager::add(new AutoSaveUsermod()); // can use USERMOD_FOUR_LINE_DISPLAY - #endif - - #ifdef USERMOD_DHT - UsermodManager::add(new UsermodDHT()); - #endif - - #ifdef USERMOD_VL53L0X_GESTURES - UsermodManager::add(new UsermodVL53L0XGestures()); - #endif - - #ifdef USERMOD_ANIMATED_STAIRCASE - UsermodManager::add(new Animated_Staircase()); - #endif - - #ifdef USERMOD_MULTI_RELAY - UsermodManager::add(new MultiRelay()); - #endif - - #ifdef USERMOD_RTC - UsermodManager::add(new RTCUsermod()); - #endif - - #ifdef USERMOD_ELEKSTUBE_IPS - UsermodManager::add(new ElekstubeIPSUsermod()); - #endif - - #ifdef USERMOD_ROTARY_ENCODER_BRIGHTNESS_COLOR - UsermodManager::add(new RotaryEncoderBrightnessColor()); - #endif - - #ifdef RGB_ROTARY_ENCODER - UsermodManager::add(new RgbRotaryEncoderUsermod()); - #endif - - #ifdef USERMOD_ST7789_DISPLAY - UsermodManager::add(new St7789DisplayUsermod()); - #endif - - #ifdef USERMOD_PIXELS_DICE_TRAY - UsermodManager::add(new PixelsDiceTrayUsermod()); - #endif - - #ifdef USERMOD_SEVEN_SEGMENT - UsermodManager::add(new SevenSegmentDisplay()); - #endif - - #ifdef USERMOD_SSDR - UsermodManager::add(new UsermodSSDR()); - #endif - - #ifdef USERMOD_CRONIXIE - UsermodManager::add(new UsermodCronixie()); - #endif - - #ifdef QUINLED_AN_PENTA - UsermodManager::add(new QuinLEDAnPentaUsermod()); - #endif - - #ifdef USERMOD_WIZLIGHTS - UsermodManager::add(new WizLightsUsermod()); - #endif - - #ifdef USERMOD_WIREGUARD - UsermodManager::add(new WireguardUsermod()); - #endif - - #ifdef USERMOD_WORDCLOCK - UsermodManager::add(new WordClockUsermod()); - #endif - - #ifdef USERMOD_MY9291 - UsermodManager::add(new MY9291Usermod()); - #endif - - #ifdef USERMOD_SI7021_MQTT_HA - UsermodManager::add(new Si7021_MQTT_HA()); - #endif - - #ifdef USERMOD_SMARTNEST - UsermodManager::add(new Smartnest()); - #endif - - #ifdef USERMOD_AUDIOREACTIVE - UsermodManager::add(new AudioReactive()); - #endif - - #ifdef USERMOD_ANALOG_CLOCK - UsermodManager::add(new AnalogClockUsermod()); - #endif - - #ifdef USERMOD_PING_PONG_CLOCK - UsermodManager::add(new PingPongClockUsermod()); - #endif - - #ifdef USERMOD_ADS1115 - UsermodManager::add(new ADS1115Usermod()); - #endif - - #ifdef USERMOD_KLIPPER_PERCENTAGE - UsermodManager::add(new klipper_percentage()); - #endif - - #ifdef USERMOD_BOBLIGHT - UsermodManager::add(new BobLightUsermod()); - #endif - - #ifdef SD_ADAPTER - UsermodManager::add(new UsermodSdCard()); - #endif - - #ifdef USERMOD_PWM_OUTPUTS - UsermodManager::add(new PwmOutputsUsermod()); - #endif - - #ifdef USERMOD_SHT - UsermodManager::add(new ShtUsermod()); - #endif - - #ifdef USERMOD_ANIMARTRIX - UsermodManager::add(new AnimartrixUsermod("Animartrix", false)); - #endif - - #ifdef USERMOD_INTERNAL_TEMPERATURE - UsermodManager::add(new InternalTemperatureUsermod()); - #endif - - #ifdef USERMOD_HTTP_PULL_LIGHT_CONTROL - UsermodManager::add(new HttpPullLightControl()); - #endif - - #ifdef USERMOD_MPU6050_IMU - static MPU6050Driver mpu6050; UsermodManager::add(&mpu6050); - #endif - - #ifdef USERMOD_GYRO_SURGE - static GyroSurge gyro_surge; UsermodManager::add(&gyro_surge); - #endif - - #ifdef USERMOD_LDR_DUSK_DAWN - UsermodManager::add(new LDR_Dusk_Dawn_v2()); - #endif - - #ifdef USERMOD_STAIRCASE_WIPE - UsermodManager::add(new StairwayWipeUsermod()); - #endif - - #ifdef USERMOD_MAX17048 - UsermodManager::add(new Usermod_MAX17048()); - #endif - - #ifdef USERMOD_TETRISAI - UsermodManager::add(new TetrisAIUsermod()); - #endif - - #ifdef USERMOD_AHT10 - UsermodManager::add(new UsermodAHT10()); - #endif - - #ifdef USERMOD_INA226 - UsermodManager::add(new UsermodINA226()); - #endif - - #ifdef USERMOD_LD2410 - UsermodManager::add(new LD2410Usermod()); - #endif - - #ifdef USERMOD_POV_DISPLAY - UsermodManager::add(new PovDisplayUsermod()); - #endif - - #ifdef USERMOD_DEEP_SLEEP - usermods.add(new DeepSleepUsermod()); - #endif -} diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 1f978a39..3b8c6009 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -424,9 +424,6 @@ void WLED::setup() PinManager::allocatePin(2, true, PinOwner::DMX); #endif - DEBUG_PRINTLN(F("Registering usermods ...")); - registerUsermods(); - DEBUG_PRINTF_P(PSTR("heap %u\n"), ESP.getFreeHeap()); bool fsinit = false; From 4d5e0ca7a3a1b9914621813f6cb8827dd33a5c32 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sat, 11 Jan 2025 13:31:20 -0500 Subject: [PATCH 131/463] load_usermods: Expand name search Look for 'usermod_v2_x' as well. This could be removed later if we clean up the folder names. --- pio-scripts/load_usermods.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/pio-scripts/load_usermods.py b/pio-scripts/load_usermods.py index ac761131..55b9c4b1 100644 --- a/pio-scripts/load_usermods.py +++ b/pio-scripts/load_usermods.py @@ -1,9 +1,26 @@ Import('env') +import os + +def find_usermod(mod_dir: str, mod: str): + """Locate this library in the usermods folder. + We do this to avoid needing to rename a bunch of folders; + this could be removed later + """ + # Check name match + mp = f"{mod_dir}/{mod}" + if os.path.exists(mp): + return mp + mp = f"{mod_dir}/usermod_v2_{mod}" + if os.path.exists(mp): + return mp + raise RuntimeError(f"Couldn't locate module {mod} in usermods directory!") + usermods = env.GetProjectOption("custom_usermods","") if usermods: proj = env.GetProjectConfig() deps = env.GetProjectOption('lib_deps') src_dir = proj.get("platformio", "src_dir") src_dir = src_dir.replace('\\','/') - usermods = [f"{mod} = symlink://{src_dir}/../usermods/{mod}" for mod in usermods.split(" ")] + mod_paths = {mod: find_usermod(f"{src_dir}/../usermods", mod) for mod in usermods.split(" ")} + usermods = [f"{mod} = symlink://{path}" for mod, path in mod_paths.items()] proj.set("env:" + env['PIOENV'], 'lib_deps', deps + usermods) From 71b0e8e93745bb906d0f1f6eb9d161c4a1499e3d Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sat, 11 Jan 2025 13:32:28 -0500 Subject: [PATCH 132/463] Convert AnimARTrix usermod to library Borrowed library definition from @netmindz's work on #4476. --- platformio.ini | 3 --- usermods/usermod_v2_animartrix/library.json | 12 ++++++++++++ usermods/usermod_v2_animartrix/readme.md | 6 +----- ...mod_v2_animartrix.h => usermod_v2_animartrix.cpp} | 5 ++--- 4 files changed, 15 insertions(+), 11 deletions(-) create mode 100644 usermods/usermod_v2_animartrix/library.json rename usermods/usermod_v2_animartrix/{usermod_v2_animartrix.h => usermod_v2_animartrix.cpp} (99%) diff --git a/platformio.ini b/platformio.ini index 1597343d..4832978a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -166,9 +166,6 @@ lib_deps = ; https://github.com/adafruit/Adafruit_MAX1704X @ 1.0.2 #For MPU6050 IMU uncomment follwoing ;electroniccats/MPU6050 @1.0.1 - # For -D USERMOD_ANIMARTRIX - # CC BY-NC 3.0 licensed effects by Stefan Petrick, include this usermod only if you accept the terms! - ;https://github.com/netmindz/animartrix.git#18bf17389e57c69f11bc8d04ebe1d215422c7fb7 # SHT85 ;robtillaart/SHT85@~0.3.3 diff --git a/usermods/usermod_v2_animartrix/library.json b/usermods/usermod_v2_animartrix/library.json new file mode 100644 index 00000000..f176e72e --- /dev/null +++ b/usermods/usermod_v2_animartrix/library.json @@ -0,0 +1,12 @@ +{ + "name": "animartrix", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + }, + "dependencies": { + "Animartrix": "https://github.com/netmindz/animartrix.git#b172586" + } +} diff --git a/usermods/usermod_v2_animartrix/readme.md b/usermods/usermod_v2_animartrix/readme.md index 42d463c5..f0ff60a7 100644 --- a/usermods/usermod_v2_animartrix/readme.md +++ b/usermods/usermod_v2_animartrix/readme.md @@ -6,9 +6,5 @@ CC BY-NC 3.0 licensed effects by Stefan Petrick, include this usermod only if yo ## Installation -Please uncomment the two references to ANIMartRIX in your platform.ini - -lib_dep to a version of https://github.com/netmindz/animartrix.git -and the build_flags -D USERMOD_ANIMARTRIX - +Add 'animartrix' to 'custom_usermods' in your platformio_override.ini. diff --git a/usermods/usermod_v2_animartrix/usermod_v2_animartrix.h b/usermods/usermod_v2_animartrix/usermod_v2_animartrix.cpp similarity index 99% rename from usermods/usermod_v2_animartrix/usermod_v2_animartrix.h rename to usermods/usermod_v2_animartrix/usermod_v2_animartrix.cpp index d91cf6c9..d2968f2f 100644 --- a/usermods/usermod_v2_animartrix/usermod_v2_animartrix.h +++ b/usermods/usermod_v2_animartrix/usermod_v2_animartrix.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" #include @@ -452,5 +450,6 @@ class AnimartrixUsermod : public Usermod { }; - +static AnimartrixUsermod animartrix_module("Animartrix", false); +REGISTER_USERMOD(animartrix_module); From 90b18158fc636f420a091893ea71075e86af72e5 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sat, 11 Jan 2025 21:14:20 +0000 Subject: [PATCH 133/463] Convert usermods from header to library --- .../Analog_Clock/{Analog_Clock.h => Analog_Clock.cpp} | 4 ++++ usermods/Analog_Clock/library.json | 9 +++++++++ .../{Animated_Staircase.h => Animated_Staircase.cpp} | 4 ++++ usermods/Animated_Staircase/library.json | 9 +++++++++ usermods/Battery/{usermod_v2_Battery.h => Battery.cpp} | 4 ++++ usermods/Battery/library.json | 9 +++++++++ usermods/Cronixie/{usermod_cronixie.h => Cronixie.cpp} | 5 ++++- usermods/Cronixie/library.json | 9 +++++++++ usermods/DHT/{usermod_dht.h => DHT.cpp} | 4 ++++ usermods/DHT/library.json | 9 +++++++++ .../{usermod_elekstube_ips.h => EleksTube_IPS.cpp} | 4 ++++ usermods/EleksTube_IPS/library.json | 9 +++++++++ .../{usermod_LDR_Dusk_Dawn_v2.h => LDR_Dusk_Dawn_v2.cpp} | 4 ++++ usermods/LDR_Dusk_Dawn_v2/library.json | 9 +++++++++ ...usermod_PIR_sensor_switch.h => PIR_sensor_switch.cpp} | 4 ++++ usermods/PIR_sensor_switch/library.json | 9 +++++++++ usermods/PWM_fan/{usermod_PWM_fan.h => PWM_fan.cpp} | 4 ++++ usermods/PWM_fan/library.json | 9 +++++++++ usermods/RTC/{usermod_rtc.h => RTC.cpp} | 5 ++++- usermods/RTC/library.json | 9 +++++++++ .../{usermod_sn_photoresistor.h => SN_Photoresistor.cpp} | 4 ++++ usermods/SN_Photoresistor/library.json | 9 +++++++++ .../{ST7789_display.h => ST7789_display.cpp} | 5 ++++- usermods/ST7789_display/library.json | 9 +++++++++ .../{usermod_si7021_mqtt_ha.h => Si7021_MQTT_HA.cpp} | 4 ++++ usermods/Si7021_MQTT_HA/library.json | 9 +++++++++ .../{usermod_temperature.h => Temperature.cpp} | 4 ++++ usermods/Temperature/library.json | 9 +++++++++ .../{usermod_vl53l0x_gestures.h => VL53L0X_gestures.cpp} | 5 ++++- usermods/VL53L0X_gestures/library.json | 9 +++++++++ usermods/boblight/{boblight.h => boblight.cpp} | 4 ++++ usermods/boblight/library.json | 9 +++++++++ usermods/buzzer/{usermod_v2_buzzer.h => buzzer.cpp} | 5 ++++- usermods/buzzer/library.json | 9 +++++++++ .../deep_sleep/{usermod_deep_sleep.h => deep_sleep.cpp} | 5 ++++- usermods/deep_sleep/library.json | 9 +++++++++ usermods/mpu6050_imu/library.json | 9 +++++++++ .../{usermod_mpu6050_imu.h => mpu6050_imu.cpp} | 4 ++++ usermods/multi_relay/library.json | 9 +++++++++ .../{usermod_multi_relay.h => multi_relay.cpp} | 4 ++++ usermods/pixels_dice_tray/library.json | 9 +++++++++ .../{pixels_dice_tray.h => pixels_dice_tray.cpp} | 4 ++++ usermods/pov_display/library.json | 9 +++++++++ .../{usermod_pov_display.h => pov_display.cpp} | 4 ++++ usermods/pwm_outputs/library.json | 9 +++++++++ .../{usermod_pwm_outputs.h => pwm_outputs.cpp} | 4 ++++ usermods/quinled-an-penta/library.json | 9 +++++++++ .../{quinled-an-penta.h => quinled-an-penta.cpp} | 5 ++++- usermods/rgb-rotary-encoder/library.json | 9 +++++++++ .../{rgb-rotary-encoder.h => rgb-rotary-encoder.cpp} | 5 ++++- usermods/sd_card/library.json | 9 +++++++++ usermods/sd_card/{usermod_sd_card.h => sd_card.cpp} | 5 ++++- usermods/seven_segment_display/library.json | 9 +++++++++ ...seven_segment_display.h => seven_segment_display.cpp} | 5 ++++- usermods/sht/library.json | 9 +++++++++ usermods/sht/{usermod_sht.h => sht.cpp} | 5 ++++- usermods/smartnest/library.json | 9 +++++++++ .../smartnest/{usermod_smartnest.h => smartnest.cpp} | 4 ++++ usermods/usermod_rotary_brightness_color/library.json | 9 +++++++++ ...tness_color.h => usermod_rotary_brightness_color.cpp} | 4 ++++ usermods/usermod_v2_HttpPullLightControl/library.json | 9 +++++++++ usermods/usermod_v2_four_line_display_ALT/library.json | 9 +++++++++ ...isplay_ALT.h => usermod_v2_four_line_display_ALT.cpp} | 4 ++++ usermods/usermod_v2_klipper_percentage/library.json | 9 +++++++++ ...er_percentage.h => usermod_v2_klipper_percentage.cpp} | 5 ++++- usermods/usermod_v2_ping_pong_clock/library.json | 9 +++++++++ ..._ping_pong_clock.h => usermod_v2_ping_pong_clock.cpp} | 4 ++++ usermods/usermod_v2_rotary_encoder_ui_ALT/library.json | 9 +++++++++ ...der_ui_ALT.h => usermod_v2_rotary_encoder_ui_ALT.cpp} | 4 ++++ usermods/usermod_v2_word_clock/library.json | 9 +++++++++ ...usermod_v2_word_clock.h => usermod_v2_word_clock.cpp} | 5 ++++- usermods/wireguard/library.json | 9 +++++++++ usermods/wireguard/{wireguard.h => wireguard.cpp} | 5 ++++- usermods/wizlights/library.json | 9 +++++++++ usermods/wizlights/{wizlights.h => wizlights.cpp} | 4 ++++ 75 files changed, 490 insertions(+), 14 deletions(-) rename usermods/Analog_Clock/{Analog_Clock.h => Analog_Clock.cpp} (99%) create mode 100644 usermods/Analog_Clock/library.json rename usermods/Animated_Staircase/{Animated_Staircase.h => Animated_Staircase.cpp} (99%) create mode 100644 usermods/Animated_Staircase/library.json rename usermods/Battery/{usermod_v2_Battery.h => Battery.cpp} (99%) create mode 100644 usermods/Battery/library.json rename usermods/Cronixie/{usermod_cronixie.h => Cronixie.cpp} (99%) create mode 100644 usermods/Cronixie/library.json rename usermods/DHT/{usermod_dht.h => DHT.cpp} (99%) create mode 100644 usermods/DHT/library.json rename usermods/EleksTube_IPS/{usermod_elekstube_ips.h => EleksTube_IPS.cpp} (98%) create mode 100644 usermods/EleksTube_IPS/library.json rename usermods/LDR_Dusk_Dawn_v2/{usermod_LDR_Dusk_Dawn_v2.h => LDR_Dusk_Dawn_v2.cpp} (98%) create mode 100644 usermods/LDR_Dusk_Dawn_v2/library.json rename usermods/PIR_sensor_switch/{usermod_PIR_sensor_switch.h => PIR_sensor_switch.cpp} (96%) create mode 100644 usermods/PIR_sensor_switch/library.json rename usermods/PWM_fan/{usermod_PWM_fan.h => PWM_fan.cpp} (99%) create mode 100644 usermods/PWM_fan/library.json rename usermods/RTC/{usermod_rtc.h => RTC.cpp} (96%) create mode 100644 usermods/RTC/library.json rename usermods/SN_Photoresistor/{usermod_sn_photoresistor.h => SN_Photoresistor.cpp} (98%) create mode 100644 usermods/SN_Photoresistor/library.json rename usermods/ST7789_display/{ST7789_display.h => ST7789_display.cpp} (99%) create mode 100644 usermods/ST7789_display/library.json rename usermods/Si7021_MQTT_HA/{usermod_si7021_mqtt_ha.h => Si7021_MQTT_HA.cpp} (99%) create mode 100644 usermods/Si7021_MQTT_HA/library.json rename usermods/Temperature/{usermod_temperature.h => Temperature.cpp} (99%) create mode 100644 usermods/Temperature/library.json rename usermods/VL53L0X_gestures/{usermod_vl53l0x_gestures.h => VL53L0X_gestures.cpp} (98%) create mode 100644 usermods/VL53L0X_gestures/library.json rename usermods/boblight/{boblight.h => boblight.cpp} (99%) create mode 100644 usermods/boblight/library.json rename usermods/buzzer/{usermod_v2_buzzer.h => buzzer.cpp} (97%) create mode 100644 usermods/buzzer/library.json rename usermods/deep_sleep/{usermod_deep_sleep.h => deep_sleep.cpp} (98%) create mode 100644 usermods/deep_sleep/library.json create mode 100644 usermods/mpu6050_imu/library.json rename usermods/mpu6050_imu/{usermod_mpu6050_imu.h => mpu6050_imu.cpp} (99%) create mode 100644 usermods/multi_relay/library.json rename usermods/multi_relay/{usermod_multi_relay.h => multi_relay.cpp} (99%) create mode 100644 usermods/pixels_dice_tray/library.json rename usermods/pixels_dice_tray/{pixels_dice_tray.h => pixels_dice_tray.cpp} (99%) create mode 100644 usermods/pov_display/library.json rename usermods/pov_display/{usermod_pov_display.h => pov_display.cpp} (96%) create mode 100644 usermods/pwm_outputs/library.json rename usermods/pwm_outputs/{usermod_pwm_outputs.h => pwm_outputs.cpp} (98%) create mode 100644 usermods/quinled-an-penta/library.json rename usermods/quinled-an-penta/{quinled-an-penta.h => quinled-an-penta.cpp} (99%) create mode 100644 usermods/rgb-rotary-encoder/library.json rename usermods/rgb-rotary-encoder/{rgb-rotary-encoder.h => rgb-rotary-encoder.cpp} (99%) create mode 100644 usermods/sd_card/library.json rename usermods/sd_card/{usermod_sd_card.h => sd_card.cpp} (99%) create mode 100644 usermods/seven_segment_display/library.json rename usermods/seven_segment_display/{usermod_v2_seven_segment_display.h => seven_segment_display.cpp} (99%) create mode 100644 usermods/sht/library.json rename usermods/sht/{usermod_sht.h => sht.cpp} (99%) create mode 100644 usermods/smartnest/library.json rename usermods/smartnest/{usermod_smartnest.h => smartnest.cpp} (98%) create mode 100644 usermods/usermod_rotary_brightness_color/library.json rename usermods/usermod_rotary_brightness_color/{usermod_rotary_brightness_color.h => usermod_rotary_brightness_color.cpp} (98%) create mode 100644 usermods/usermod_v2_HttpPullLightControl/library.json create mode 100644 usermods/usermod_v2_four_line_display_ALT/library.json rename usermods/usermod_v2_four_line_display_ALT/{usermod_v2_four_line_display_ALT.h => usermod_v2_four_line_display_ALT.cpp} (99%) create mode 100644 usermods/usermod_v2_klipper_percentage/library.json rename usermods/usermod_v2_klipper_percentage/{usermod_v2_klipper_percentage.h => usermod_v2_klipper_percentage.cpp} (97%) create mode 100644 usermods/usermod_v2_ping_pong_clock/library.json rename usermods/usermod_v2_ping_pong_clock/{usermod_v2_ping_pong_clock.h => usermod_v2_ping_pong_clock.cpp} (97%) create mode 100644 usermods/usermod_v2_rotary_encoder_ui_ALT/library.json rename usermods/usermod_v2_rotary_encoder_ui_ALT/{usermod_v2_rotary_encoder_ui_ALT.h => usermod_v2_rotary_encoder_ui_ALT.cpp} (99%) create mode 100644 usermods/usermod_v2_word_clock/library.json rename usermods/usermod_v2_word_clock/{usermod_v2_word_clock.h => usermod_v2_word_clock.cpp} (99%) create mode 100644 usermods/wireguard/library.json rename usermods/wireguard/{wireguard.h => wireguard.cpp} (98%) create mode 100644 usermods/wizlights/library.json rename usermods/wizlights/{wizlights.h => wizlights.cpp} (98%) diff --git a/usermods/Analog_Clock/Analog_Clock.h b/usermods/Analog_Clock/Analog_Clock.cpp similarity index 99% rename from usermods/Analog_Clock/Analog_Clock.h rename to usermods/Analog_Clock/Analog_Clock.cpp index 9d82f767..8a4c048a 100644 --- a/usermods/Analog_Clock/Analog_Clock.h +++ b/usermods/Analog_Clock/Analog_Clock.cpp @@ -254,3 +254,7 @@ public: return USERMOD_ID_ANALOG_CLOCK; } }; + + +static AnalogClockUsermod analog_clock; +REGISTER_USERMOD(analog_clock); \ No newline at end of file diff --git a/usermods/Analog_Clock/library.json b/usermods/Analog_Clock/library.json new file mode 100644 index 00000000..ddba3a76 --- /dev/null +++ b/usermods/Analog_Clock/library.json @@ -0,0 +1,9 @@ +{ + "name:": "Analog_Clock", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/Animated_Staircase/Animated_Staircase.h b/usermods/Animated_Staircase/Animated_Staircase.cpp similarity index 99% rename from usermods/Animated_Staircase/Animated_Staircase.h rename to usermods/Animated_Staircase/Animated_Staircase.cpp index 54a9b333..43d9db6b 100644 --- a/usermods/Animated_Staircase/Animated_Staircase.h +++ b/usermods/Animated_Staircase/Animated_Staircase.cpp @@ -562,3 +562,7 @@ const char Animated_Staircase::_bottomEcho_pin[] PROGMEM = "bottomEch const char Animated_Staircase::_topEchoCm[] PROGMEM = "top-dist-cm"; const char Animated_Staircase::_bottomEchoCm[] PROGMEM = "bottom-dist-cm"; const char Animated_Staircase::_togglePower[] PROGMEM = "toggle-on-off"; + + +static Animated_Staircase animated_staircase; +REGISTER_USERMOD(animated_staircase); \ No newline at end of file diff --git a/usermods/Animated_Staircase/library.json b/usermods/Animated_Staircase/library.json new file mode 100644 index 00000000..e37df311 --- /dev/null +++ b/usermods/Animated_Staircase/library.json @@ -0,0 +1,9 @@ +{ + "name:": "Animated_Staircase", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/Battery.cpp similarity index 99% rename from usermods/Battery/usermod_v2_Battery.h rename to usermods/Battery/Battery.cpp index b36c5f4d..4646a238 100644 --- a/usermods/Battery/usermod_v2_Battery.h +++ b/usermods/Battery/Battery.cpp @@ -857,3 +857,7 @@ const char UsermodBattery::_preset[] PROGMEM = "preset"; const char UsermodBattery::_duration[] PROGMEM = "duration"; const char UsermodBattery::_init[] PROGMEM = "init"; const char UsermodBattery::_haDiscovery[] PROGMEM = "HA-discovery"; + + +static UsermodBattery battery; +REGISTER_USERMOD(battery); \ No newline at end of file diff --git a/usermods/Battery/library.json b/usermods/Battery/library.json new file mode 100644 index 00000000..bc0d97a1 --- /dev/null +++ b/usermods/Battery/library.json @@ -0,0 +1,9 @@ +{ + "name:": "Battery", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/Cronixie/usermod_cronixie.h b/usermods/Cronixie/Cronixie.cpp similarity index 99% rename from usermods/Cronixie/usermod_cronixie.h rename to usermods/Cronixie/Cronixie.cpp index 671c5d13..09e7e25a 100644 --- a/usermods/Cronixie/usermod_cronixie.h +++ b/usermods/Cronixie/Cronixie.cpp @@ -299,4 +299,7 @@ class UsermodCronixie : public Usermod { { return USERMOD_ID_CRONIXIE; } -}; \ No newline at end of file +}; + +static UsermodCronixie cronixie; +REGISTER_USERMOD(cronixie); \ No newline at end of file diff --git a/usermods/Cronixie/library.json b/usermods/Cronixie/library.json new file mode 100644 index 00000000..f0d39d00 --- /dev/null +++ b/usermods/Cronixie/library.json @@ -0,0 +1,9 @@ +{ + "name:": "Cronixie", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/DHT/usermod_dht.h b/usermods/DHT/DHT.cpp similarity index 99% rename from usermods/DHT/usermod_dht.h rename to usermods/DHT/DHT.cpp index 05a7267b..fad6dad5 100644 --- a/usermods/DHT/usermod_dht.h +++ b/usermods/DHT/DHT.cpp @@ -245,3 +245,7 @@ class UsermodDHT : public Usermod { } }; + + +static UsermodDHT dht; +REGISTER_USERMOD(dht); \ No newline at end of file diff --git a/usermods/DHT/library.json b/usermods/DHT/library.json new file mode 100644 index 00000000..bb677361 --- /dev/null +++ b/usermods/DHT/library.json @@ -0,0 +1,9 @@ +{ + "name:": "DHT", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/EleksTube_IPS/usermod_elekstube_ips.h b/usermods/EleksTube_IPS/EleksTube_IPS.cpp similarity index 98% rename from usermods/EleksTube_IPS/usermod_elekstube_ips.h rename to usermods/EleksTube_IPS/EleksTube_IPS.cpp index 0f7d92e7..48fbb2b4 100644 --- a/usermods/EleksTube_IPS/usermod_elekstube_ips.h +++ b/usermods/EleksTube_IPS/EleksTube_IPS.cpp @@ -156,3 +156,7 @@ class ElekstubeIPSUsermod : public Usermod { const char ElekstubeIPSUsermod::_name[] PROGMEM = "EleksTubeIPS"; const char ElekstubeIPSUsermod::_tubeSeg[] PROGMEM = "tubeSegment"; const char ElekstubeIPSUsermod::_digitOffset[] PROGMEM = "digitOffset"; + + +static ElekstubeIPSUsermod elekstube_ips; +REGISTER_USERMOD(elekstube_ips); \ No newline at end of file diff --git a/usermods/EleksTube_IPS/library.json b/usermods/EleksTube_IPS/library.json new file mode 100644 index 00000000..d025fc78 --- /dev/null +++ b/usermods/EleksTube_IPS/library.json @@ -0,0 +1,9 @@ +{ + "name:": "EleksTube_IPS", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/LDR_Dusk_Dawn_v2/usermod_LDR_Dusk_Dawn_v2.h b/usermods/LDR_Dusk_Dawn_v2/LDR_Dusk_Dawn_v2.cpp similarity index 98% rename from usermods/LDR_Dusk_Dawn_v2/usermod_LDR_Dusk_Dawn_v2.h rename to usermods/LDR_Dusk_Dawn_v2/LDR_Dusk_Dawn_v2.cpp index 03f4c078..6104fcab 100644 --- a/usermods/LDR_Dusk_Dawn_v2/usermod_LDR_Dusk_Dawn_v2.h +++ b/usermods/LDR_Dusk_Dawn_v2/LDR_Dusk_Dawn_v2.cpp @@ -151,3 +151,7 @@ class LDR_Dusk_Dawn_v2 : public Usermod { }; const char LDR_Dusk_Dawn_v2::_name[] PROGMEM = "LDR_Dusk_Dawn_v2"; + + +static LDR_Dusk_Dawn_v2 ldr_dusk_dawn_v2; +REGISTER_USERMOD(ldr_dusk_dawn_v2); \ No newline at end of file diff --git a/usermods/LDR_Dusk_Dawn_v2/library.json b/usermods/LDR_Dusk_Dawn_v2/library.json new file mode 100644 index 00000000..6a08c9cc --- /dev/null +++ b/usermods/LDR_Dusk_Dawn_v2/library.json @@ -0,0 +1,9 @@ +{ + "name:": "LDR_Dusk_Dawn_v2", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h b/usermods/PIR_sensor_switch/PIR_sensor_switch.cpp similarity index 96% rename from usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h rename to usermods/PIR_sensor_switch/PIR_sensor_switch.cpp index 0deda181..1cc31a08 100644 --- a/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h +++ b/usermods/PIR_sensor_switch/PIR_sensor_switch.cpp @@ -571,3 +571,7 @@ bool PIRsensorSwitch::readFromConfig(JsonObject &root) // use "return !top["newestParameter"].isNull();" when updating Usermod with new features return !(pins.isNull() || pins.size() != PIR_SENSOR_MAX_SENSORS); } + + +static PIRsensorSwitch pir_sensor_switch; +REGISTER_USERMOD(pir_sensor_switch); \ No newline at end of file diff --git a/usermods/PIR_sensor_switch/library.json b/usermods/PIR_sensor_switch/library.json new file mode 100644 index 00000000..152946e4 --- /dev/null +++ b/usermods/PIR_sensor_switch/library.json @@ -0,0 +1,9 @@ +{ + "name:": "PIR_sensor_switch", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/PWM_fan/usermod_PWM_fan.h b/usermods/PWM_fan/PWM_fan.cpp similarity index 99% rename from usermods/PWM_fan/usermod_PWM_fan.h rename to usermods/PWM_fan/PWM_fan.cpp index c3ef24fe..9df37304 100644 --- a/usermods/PWM_fan/usermod_PWM_fan.h +++ b/usermods/PWM_fan/PWM_fan.cpp @@ -397,3 +397,7 @@ const char PWMFanUsermod::_maxPWMValuePct[] PROGMEM = "max-PWM-percent"; const char PWMFanUsermod::_IRQperRotation[] PROGMEM = "IRQs-per-rotation"; const char PWMFanUsermod::_speed[] PROGMEM = "speed"; const char PWMFanUsermod::_lock[] PROGMEM = "lock"; + + +static PWMFanUsermod pwm_fan; +REGISTER_USERMOD(pwm_fan); \ No newline at end of file diff --git a/usermods/PWM_fan/library.json b/usermods/PWM_fan/library.json new file mode 100644 index 00000000..a6d5ea64 --- /dev/null +++ b/usermods/PWM_fan/library.json @@ -0,0 +1,9 @@ +{ + "name:": "PWM_fan", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/RTC/usermod_rtc.h b/usermods/RTC/RTC.cpp similarity index 96% rename from usermods/RTC/usermod_rtc.h rename to usermods/RTC/RTC.cpp index 42965e3a..f9dbe3cf 100644 --- a/usermods/RTC/usermod_rtc.h +++ b/usermods/RTC/RTC.cpp @@ -48,4 +48,7 @@ class RTCUsermod : public Usermod { { return USERMOD_ID_RTC; } -}; \ No newline at end of file +}; + +static RTCUsermod rtc; +REGISTER_USERMOD(rtc); \ No newline at end of file diff --git a/usermods/RTC/library.json b/usermods/RTC/library.json new file mode 100644 index 00000000..96aa095b --- /dev/null +++ b/usermods/RTC/library.json @@ -0,0 +1,9 @@ +{ + "name:": "RTC", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/SN_Photoresistor/usermod_sn_photoresistor.h b/usermods/SN_Photoresistor/SN_Photoresistor.cpp similarity index 98% rename from usermods/SN_Photoresistor/usermod_sn_photoresistor.h rename to usermods/SN_Photoresistor/SN_Photoresistor.cpp index 45cdb66a..5e50ab7a 100644 --- a/usermods/SN_Photoresistor/usermod_sn_photoresistor.h +++ b/usermods/SN_Photoresistor/SN_Photoresistor.cpp @@ -210,3 +210,7 @@ const char Usermod_SN_Photoresistor::_referenceVoltage[] PROGMEM = "supplied-vol const char Usermod_SN_Photoresistor::_resistorValue[] PROGMEM = "resistor-value"; const char Usermod_SN_Photoresistor::_adcPrecision[] PROGMEM = "adc-precision"; const char Usermod_SN_Photoresistor::_offset[] PROGMEM = "offset"; + + +static Usermod_SN_Photoresistor sn_photoresistor; +REGISTER_USERMOD(sn_photoresistor); \ No newline at end of file diff --git a/usermods/SN_Photoresistor/library.json b/usermods/SN_Photoresistor/library.json new file mode 100644 index 00000000..fe5173be --- /dev/null +++ b/usermods/SN_Photoresistor/library.json @@ -0,0 +1,9 @@ +{ + "name:": "SN_Photoresistor", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/ST7789_display/ST7789_display.h b/usermods/ST7789_display/ST7789_display.cpp similarity index 99% rename from usermods/ST7789_display/ST7789_display.h rename to usermods/ST7789_display/ST7789_display.cpp index 65f4cae5..e81c53ba 100644 --- a/usermods/ST7789_display/ST7789_display.h +++ b/usermods/ST7789_display/ST7789_display.cpp @@ -410,4 +410,7 @@ class St7789DisplayUsermod : public Usermod { //More methods can be added in the future, this example will then be extended. //Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class! -}; \ No newline at end of file +}; + +static name. st7789_display; +REGISTER_USERMOD(st7789_display); \ No newline at end of file diff --git a/usermods/ST7789_display/library.json b/usermods/ST7789_display/library.json new file mode 100644 index 00000000..88f4efe7 --- /dev/null +++ b/usermods/ST7789_display/library.json @@ -0,0 +1,9 @@ +{ + "name:": "ST7789_display", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/Si7021_MQTT_HA/usermod_si7021_mqtt_ha.h b/usermods/Si7021_MQTT_HA/Si7021_MQTT_HA.cpp similarity index 99% rename from usermods/Si7021_MQTT_HA/usermod_si7021_mqtt_ha.h rename to usermods/Si7021_MQTT_HA/Si7021_MQTT_HA.cpp index 9f027382..04f6d750 100644 --- a/usermods/Si7021_MQTT_HA/usermod_si7021_mqtt_ha.h +++ b/usermods/Si7021_MQTT_HA/Si7021_MQTT_HA.cpp @@ -229,3 +229,7 @@ const char Si7021_MQTT_HA::_name[] PROGMEM = "Si7021 MQTT (Hom const char Si7021_MQTT_HA::_enabled[] PROGMEM = "enabled"; const char Si7021_MQTT_HA::_sendAdditionalSensors[] PROGMEM = "Send Dew Point, Abs. Humidity and Heat Index"; const char Si7021_MQTT_HA::_haAutoDiscovery[] PROGMEM = "Home Assistant MQTT Auto-Discovery"; + + +static Si7021_MQTT_HA si7021_mqtt_ha; +REGISTER_USERMOD(si7021_mqtt_ha); \ No newline at end of file diff --git a/usermods/Si7021_MQTT_HA/library.json b/usermods/Si7021_MQTT_HA/library.json new file mode 100644 index 00000000..2c18375f --- /dev/null +++ b/usermods/Si7021_MQTT_HA/library.json @@ -0,0 +1,9 @@ +{ + "name:": "Si7021_MQTT_HA", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/Temperature/usermod_temperature.h b/usermods/Temperature/Temperature.cpp similarity index 99% rename from usermods/Temperature/usermod_temperature.h rename to usermods/Temperature/Temperature.cpp index 178bc05a..a17bd2d9 100644 --- a/usermods/Temperature/usermod_temperature.h +++ b/usermods/Temperature/Temperature.cpp @@ -471,3 +471,7 @@ static uint16_t mode_temperature() { SEGMENT.fill(SEGMENT.color_from_palette(i, false, false, 255)); return FRAMETIME; } + + +static UsermodTemperature temperature; +REGISTER_USERMOD(temperature); \ No newline at end of file diff --git a/usermods/Temperature/library.json b/usermods/Temperature/library.json new file mode 100644 index 00000000..56371db4 --- /dev/null +++ b/usermods/Temperature/library.json @@ -0,0 +1,9 @@ +{ + "name:": "Temperature", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/VL53L0X_gestures/usermod_vl53l0x_gestures.h b/usermods/VL53L0X_gestures/VL53L0X_gestures.cpp similarity index 98% rename from usermods/VL53L0X_gestures/usermod_vl53l0x_gestures.h rename to usermods/VL53L0X_gestures/VL53L0X_gestures.cpp index fe6b958f..759c31c7 100644 --- a/usermods/VL53L0X_gestures/usermod_vl53l0x_gestures.h +++ b/usermods/VL53L0X_gestures/VL53L0X_gestures.cpp @@ -126,4 +126,7 @@ class UsermodVL53L0XGestures : public Usermod { { return USERMOD_ID_VL53L0X; } -}; \ No newline at end of file +}; + +static UsermodVL53L0XGestures vl53l0x_gestures; +REGISTER_USERMOD(vl53l0x_gestures); \ No newline at end of file diff --git a/usermods/VL53L0X_gestures/library.json b/usermods/VL53L0X_gestures/library.json new file mode 100644 index 00000000..77521d6f --- /dev/null +++ b/usermods/VL53L0X_gestures/library.json @@ -0,0 +1,9 @@ +{ + "name:": "VL53L0X_gestures", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/boblight/boblight.h b/usermods/boblight/boblight.cpp similarity index 99% rename from usermods/boblight/boblight.h rename to usermods/boblight/boblight.cpp index b04b78fa..2a52fc15 100644 --- a/usermods/boblight/boblight.h +++ b/usermods/boblight/boblight.cpp @@ -457,3 +457,7 @@ void BobLightUsermod::pollBob() { } } } + + +static BobLightUsermod boblight; +REGISTER_USERMOD(boblight); \ No newline at end of file diff --git a/usermods/boblight/library.json b/usermods/boblight/library.json new file mode 100644 index 00000000..0b63b224 --- /dev/null +++ b/usermods/boblight/library.json @@ -0,0 +1,9 @@ +{ + "name:": "boblight", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/buzzer/usermod_v2_buzzer.h b/usermods/buzzer/buzzer.cpp similarity index 97% rename from usermods/buzzer/usermod_v2_buzzer.h rename to usermods/buzzer/buzzer.cpp index ebd8dcb1..e421a239 100644 --- a/usermods/buzzer/usermod_v2_buzzer.h +++ b/usermods/buzzer/buzzer.cpp @@ -78,4 +78,7 @@ class BuzzerUsermod : public Usermod { { return USERMOD_ID_BUZZER; } -}; \ No newline at end of file +}; + +static BuzzerUsermod buzzer; +REGISTER_USERMOD(buzzer); \ No newline at end of file diff --git a/usermods/buzzer/library.json b/usermods/buzzer/library.json new file mode 100644 index 00000000..78ba4152 --- /dev/null +++ b/usermods/buzzer/library.json @@ -0,0 +1,9 @@ +{ + "name:": "buzzer", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/deep_sleep/usermod_deep_sleep.h b/usermods/deep_sleep/deep_sleep.cpp similarity index 98% rename from usermods/deep_sleep/usermod_deep_sleep.h rename to usermods/deep_sleep/deep_sleep.cpp index 7f4efd5c..741b618f 100644 --- a/usermods/deep_sleep/usermod_deep_sleep.h +++ b/usermods/deep_sleep/deep_sleep.cpp @@ -224,4 +224,7 @@ void addToConfig(JsonObject& root) override // add more strings here to reduce flash memory usage const char DeepSleepUsermod::_name[] PROGMEM = "DeepSleep"; -const char DeepSleepUsermod::_enabled[] PROGMEM = "enabled"; \ No newline at end of file +const char DeepSleepUsermod::_enabled[] PROGMEM = "enabled"; + +static DeepSleepUsermod deep_sleep; +REGISTER_USERMOD(deep_sleep); \ No newline at end of file diff --git a/usermods/deep_sleep/library.json b/usermods/deep_sleep/library.json new file mode 100644 index 00000000..c15e8d57 --- /dev/null +++ b/usermods/deep_sleep/library.json @@ -0,0 +1,9 @@ +{ + "name:": "deep_sleep", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/mpu6050_imu/library.json b/usermods/mpu6050_imu/library.json new file mode 100644 index 00000000..bf86aed6 --- /dev/null +++ b/usermods/mpu6050_imu/library.json @@ -0,0 +1,9 @@ +{ + "name:": "mpu6050_imu", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/mpu6050_imu/usermod_mpu6050_imu.h b/usermods/mpu6050_imu/mpu6050_imu.cpp similarity index 99% rename from usermods/mpu6050_imu/usermod_mpu6050_imu.h rename to usermods/mpu6050_imu/mpu6050_imu.cpp index f04578fe..2f8166cd 100644 --- a/usermods/mpu6050_imu/usermod_mpu6050_imu.h +++ b/usermods/mpu6050_imu/mpu6050_imu.cpp @@ -446,3 +446,7 @@ const char MPU6050Driver::_z_acc_bias[] PROGMEM = "z_acc_bias"; const char MPU6050Driver::_x_gyro_bias[] PROGMEM = "x_gyro_bias"; const char MPU6050Driver::_y_gyro_bias[] PROGMEM = "y_gyro_bias"; const char MPU6050Driver::_z_gyro_bias[] PROGMEM = "z_gyro_bias"; + + +static MPU6050Driver mpu6050_imu; +REGISTER_USERMOD(mpu6050_imu); \ No newline at end of file diff --git a/usermods/multi_relay/library.json b/usermods/multi_relay/library.json new file mode 100644 index 00000000..47505d0b --- /dev/null +++ b/usermods/multi_relay/library.json @@ -0,0 +1,9 @@ +{ + "name:": "multi_relay", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/multi_relay/usermod_multi_relay.h b/usermods/multi_relay/multi_relay.cpp similarity index 99% rename from usermods/multi_relay/usermod_multi_relay.h rename to usermods/multi_relay/multi_relay.cpp index c4446c7a..ea07e281 100644 --- a/usermods/multi_relay/usermod_multi_relay.h +++ b/usermods/multi_relay/multi_relay.cpp @@ -842,3 +842,7 @@ const char MultiRelay::_pcfAddress[] PROGMEM = "PCF8574-address"; const char MultiRelay::_switch[] PROGMEM = "switch"; const char MultiRelay::_toggle[] PROGMEM = "toggle"; const char MultiRelay::_Command[] PROGMEM = "/command"; + + +static MultiRelay multi_relay; +REGISTER_USERMOD(multi_relay); \ No newline at end of file diff --git a/usermods/pixels_dice_tray/library.json b/usermods/pixels_dice_tray/library.json new file mode 100644 index 00000000..01776ffe --- /dev/null +++ b/usermods/pixels_dice_tray/library.json @@ -0,0 +1,9 @@ +{ + "name:": "pixels_dice_tray", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/pixels_dice_tray/pixels_dice_tray.h b/usermods/pixels_dice_tray/pixels_dice_tray.cpp similarity index 99% rename from usermods/pixels_dice_tray/pixels_dice_tray.h rename to usermods/pixels_dice_tray/pixels_dice_tray.cpp index 61348ebb..07fd3d59 100644 --- a/usermods/pixels_dice_tray/pixels_dice_tray.h +++ b/usermods/pixels_dice_tray/pixels_dice_tray.cpp @@ -533,3 +533,7 @@ class PixelsDiceTrayUsermod : public Usermod { // extended. Your usermod will remain compatible as it does not need to // implement all methods from the Usermod base class! }; + + +static PixelsDiceTrayUsermod pixels_dice_tray; +REGISTER_USERMOD(pixels_dice_tray); \ No newline at end of file diff --git a/usermods/pov_display/library.json b/usermods/pov_display/library.json new file mode 100644 index 00000000..5998377b --- /dev/null +++ b/usermods/pov_display/library.json @@ -0,0 +1,9 @@ +{ + "name:": "pov_display", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/pov_display/usermod_pov_display.h b/usermods/pov_display/pov_display.cpp similarity index 96% rename from usermods/pov_display/usermod_pov_display.h rename to usermods/pov_display/pov_display.cpp index b1fc0dba..c1bd143a 100644 --- a/usermods/pov_display/usermod_pov_display.h +++ b/usermods/pov_display/pov_display.cpp @@ -83,3 +83,7 @@ class PovDisplayUsermod : public Usermod void connected() {} }; + + +static PovDisplayUsermod pov_display; +REGISTER_USERMOD(pov_display); \ No newline at end of file diff --git a/usermods/pwm_outputs/library.json b/usermods/pwm_outputs/library.json new file mode 100644 index 00000000..18ce7d88 --- /dev/null +++ b/usermods/pwm_outputs/library.json @@ -0,0 +1,9 @@ +{ + "name:": "pwm_outputs", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/pwm_outputs/usermod_pwm_outputs.h b/usermods/pwm_outputs/pwm_outputs.cpp similarity index 98% rename from usermods/pwm_outputs/usermod_pwm_outputs.h rename to usermods/pwm_outputs/pwm_outputs.cpp index 09232f04..72a78475 100644 --- a/usermods/pwm_outputs/usermod_pwm_outputs.h +++ b/usermods/pwm_outputs/pwm_outputs.cpp @@ -219,3 +219,7 @@ class PwmOutputsUsermod : public Usermod { const char PwmOutputsUsermod::USERMOD_NAME[] PROGMEM = "PwmOutputs"; const char PwmOutputsUsermod::PWM_STATE_NAME[] PROGMEM = "pwm"; + + +static PwmOutputsUsermod pwm_outputs; +REGISTER_USERMOD(pwm_outputs); \ No newline at end of file diff --git a/usermods/quinled-an-penta/library.json b/usermods/quinled-an-penta/library.json new file mode 100644 index 00000000..274020d9 --- /dev/null +++ b/usermods/quinled-an-penta/library.json @@ -0,0 +1,9 @@ +{ + "name:": "quinled-an-penta", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/quinled-an-penta/quinled-an-penta.h b/usermods/quinled-an-penta/quinled-an-penta.cpp similarity index 99% rename from usermods/quinled-an-penta/quinled-an-penta.h rename to usermods/quinled-an-penta/quinled-an-penta.cpp index e4467203..612ade03 100644 --- a/usermods/quinled-an-penta/quinled-an-penta.h +++ b/usermods/quinled-an-penta/quinled-an-penta.cpp @@ -752,4 +752,7 @@ const unsigned char QuinLEDAnPentaUsermod::quinLedLogo[] PROGMEM = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -}; \ No newline at end of file +}; + +static QuinLEDAnPentaUsermod quinled-an-penta; +REGISTER_USERMOD(quinled-an-penta); \ No newline at end of file diff --git a/usermods/rgb-rotary-encoder/library.json b/usermods/rgb-rotary-encoder/library.json new file mode 100644 index 00000000..c23606c0 --- /dev/null +++ b/usermods/rgb-rotary-encoder/library.json @@ -0,0 +1,9 @@ +{ + "name:": "rgb-rotary-encoder", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/rgb-rotary-encoder/rgb-rotary-encoder.h b/usermods/rgb-rotary-encoder/rgb-rotary-encoder.cpp similarity index 99% rename from usermods/rgb-rotary-encoder/rgb-rotary-encoder.h rename to usermods/rgb-rotary-encoder/rgb-rotary-encoder.cpp index 00fc2272..3e7b96bb 100644 --- a/usermods/rgb-rotary-encoder/rgb-rotary-encoder.h +++ b/usermods/rgb-rotary-encoder/rgb-rotary-encoder.cpp @@ -340,4 +340,7 @@ const char RgbRotaryEncoderUsermod::_ebIo[] PROGMEM = "eb-pin"; const char RgbRotaryEncoderUsermod::_ledMode[] PROGMEM = "LED-Mode"; const char RgbRotaryEncoderUsermod::_ledBrightness[] PROGMEM = "LED-Brightness"; const char RgbRotaryEncoderUsermod::_stepsPerClick[] PROGMEM = "Steps-per-Click"; -const char RgbRotaryEncoderUsermod::_incrementPerClick[] PROGMEM = "Increment-per-Click"; \ No newline at end of file +const char RgbRotaryEncoderUsermod::_incrementPerClick[] PROGMEM = "Increment-per-Click"; + +static RgbRotaryEncoderUsermod rgb-rotary-encoder; +REGISTER_USERMOD(rgb-rotary-encoder); \ No newline at end of file diff --git a/usermods/sd_card/library.json b/usermods/sd_card/library.json new file mode 100644 index 00000000..777c6264 --- /dev/null +++ b/usermods/sd_card/library.json @@ -0,0 +1,9 @@ +{ + "name:": "sd_card", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/sd_card/usermod_sd_card.h b/usermods/sd_card/sd_card.cpp similarity index 99% rename from usermods/sd_card/usermod_sd_card.h rename to usermods/sd_card/sd_card.cpp index da1999d9..e33a643f 100644 --- a/usermods/sd_card/usermod_sd_card.h +++ b/usermods/sd_card/sd_card.cpp @@ -240,4 +240,7 @@ void listDir( const char * dirname, uint8_t levels){ } } -#endif \ No newline at end of file +#endif + +static UsermodSdCard sd_card; +REGISTER_USERMOD(sd_card); \ No newline at end of file diff --git a/usermods/seven_segment_display/library.json b/usermods/seven_segment_display/library.json new file mode 100644 index 00000000..c10bd084 --- /dev/null +++ b/usermods/seven_segment_display/library.json @@ -0,0 +1,9 @@ +{ + "name:": "seven_segment_display", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/seven_segment_display/usermod_v2_seven_segment_display.h b/usermods/seven_segment_display/seven_segment_display.cpp similarity index 99% rename from usermods/seven_segment_display/usermod_v2_seven_segment_display.h rename to usermods/seven_segment_display/seven_segment_display.cpp index 20fef15d..d3aa5737 100644 --- a/usermods/seven_segment_display/usermod_v2_seven_segment_display.h +++ b/usermods/seven_segment_display/seven_segment_display.cpp @@ -498,4 +498,7 @@ const char SevenSegmentDisplay::_str_timeEnabled[] PROGMEM = "timeEnabled"; const char SevenSegmentDisplay::_str_scrollSpd[] PROGMEM = "scrollSpd"; const char SevenSegmentDisplay::_str_displayMask[] PROGMEM = "displayMask"; const char SevenSegmentDisplay::_str_displayMsg[] PROGMEM = "displayMsg"; -const char SevenSegmentDisplay::_str_sevenSeg[] PROGMEM = "sevenSeg"; \ No newline at end of file +const char SevenSegmentDisplay::_str_sevenSeg[] PROGMEM = "sevenSeg"; + +static SevenSegmentDisplay seven_segment_display; +REGISTER_USERMOD(seven_segment_display); \ No newline at end of file diff --git a/usermods/sht/library.json b/usermods/sht/library.json new file mode 100644 index 00000000..2cb0003a --- /dev/null +++ b/usermods/sht/library.json @@ -0,0 +1,9 @@ +{ + "name:": "sht", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/sht/usermod_sht.h b/usermods/sht/sht.cpp similarity index 99% rename from usermods/sht/usermod_sht.h rename to usermods/sht/sht.cpp index f10c78a2..7641bbc2 100644 --- a/usermods/sht/usermod_sht.h +++ b/usermods/sht/sht.cpp @@ -477,4 +477,7 @@ float ShtUsermod::getTemperature() { */ const char* ShtUsermod::getUnitString() { return unitOfTemp ? "°F" : "°C"; -} \ No newline at end of file +} + +static ShtUsermod sht; +REGISTER_USERMOD(sht); \ No newline at end of file diff --git a/usermods/smartnest/library.json b/usermods/smartnest/library.json new file mode 100644 index 00000000..4e776ad7 --- /dev/null +++ b/usermods/smartnest/library.json @@ -0,0 +1,9 @@ +{ + "name:": "smartnest", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/smartnest/usermod_smartnest.h b/usermods/smartnest/smartnest.cpp similarity index 98% rename from usermods/smartnest/usermod_smartnest.h rename to usermods/smartnest/smartnest.cpp index 9d21ef2e..be7710ab 100644 --- a/usermods/smartnest/usermod_smartnest.h +++ b/usermods/smartnest/smartnest.cpp @@ -203,3 +203,7 @@ public: } } }; + + +static Smartnest smartnest; +REGISTER_USERMOD(smartnest); \ No newline at end of file diff --git a/usermods/usermod_rotary_brightness_color/library.json b/usermods/usermod_rotary_brightness_color/library.json new file mode 100644 index 00000000..8d368082 --- /dev/null +++ b/usermods/usermod_rotary_brightness_color/library.json @@ -0,0 +1,9 @@ +{ + "name:": "usermod_rotary_brightness_color", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.h b/usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.cpp similarity index 98% rename from usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.h rename to usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.cpp index 85a9a160..076e91f7 100644 --- a/usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.h +++ b/usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.cpp @@ -187,3 +187,7 @@ public: return configComplete; } }; + + +static RotaryEncoderBrightnessColor usermod_rotary_brightness_color; +REGISTER_USERMOD(usermod_rotary_brightness_color); \ No newline at end of file diff --git a/usermods/usermod_v2_HttpPullLightControl/library.json b/usermods/usermod_v2_HttpPullLightControl/library.json new file mode 100644 index 00000000..68b93708 --- /dev/null +++ b/usermods/usermod_v2_HttpPullLightControl/library.json @@ -0,0 +1,9 @@ +{ + "name:": "usermod_v2_HttpPullLightControl", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/usermod_v2_four_line_display_ALT/library.json b/usermods/usermod_v2_four_line_display_ALT/library.json new file mode 100644 index 00000000..6dccb4a9 --- /dev/null +++ b/usermods/usermod_v2_four_line_display_ALT/library.json @@ -0,0 +1,9 @@ +{ + "name:": "usermod_v2_four_line_display_ALT", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h b/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.cpp similarity index 99% rename from usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h rename to usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.cpp index 684dd86e..851e378e 100644 --- a/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h +++ b/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.cpp @@ -1386,3 +1386,7 @@ bool FourLineDisplayUsermod::readFromConfig(JsonObject& root) { // use "return !top["newestParameter"].isNull();" when updating Usermod with new features return !top[FPSTR(_contrastFix)].isNull(); } + + +static FourLineDisplayUsermod usermod_v2_four_line_display_alt; +REGISTER_USERMOD(usermod_v2_four_line_display_alt); \ No newline at end of file diff --git a/usermods/usermod_v2_klipper_percentage/library.json b/usermods/usermod_v2_klipper_percentage/library.json new file mode 100644 index 00000000..afd96163 --- /dev/null +++ b/usermods/usermod_v2_klipper_percentage/library.json @@ -0,0 +1,9 @@ +{ + "name:": "usermod_v2_klipper_percentage", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/usermod_v2_klipper_percentage/usermod_v2_klipper_percentage.h b/usermods/usermod_v2_klipper_percentage/usermod_v2_klipper_percentage.cpp similarity index 97% rename from usermods/usermod_v2_klipper_percentage/usermod_v2_klipper_percentage.h rename to usermods/usermod_v2_klipper_percentage/usermod_v2_klipper_percentage.cpp index bd4170dd..55132b84 100644 --- a/usermods/usermod_v2_klipper_percentage/usermod_v2_klipper_percentage.h +++ b/usermods/usermod_v2_klipper_percentage/usermod_v2_klipper_percentage.cpp @@ -219,4 +219,7 @@ public: } }; const char klipper_percentage::_name[] PROGMEM = "Klipper_Percentage"; -const char klipper_percentage::_enabled[] PROGMEM = "enabled"; \ No newline at end of file +const char klipper_percentage::_enabled[] PROGMEM = "enabled"; + +static klipper_percentage usermod_v2_klipper_percentage; +REGISTER_USERMOD(usermod_v2_klipper_percentage); \ No newline at end of file diff --git a/usermods/usermod_v2_ping_pong_clock/library.json b/usermods/usermod_v2_ping_pong_clock/library.json new file mode 100644 index 00000000..19708611 --- /dev/null +++ b/usermods/usermod_v2_ping_pong_clock/library.json @@ -0,0 +1,9 @@ +{ + "name:": "usermod_v2_ping_pong_clock", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/usermod_v2_ping_pong_clock/usermod_v2_ping_pong_clock.h b/usermods/usermod_v2_ping_pong_clock/usermod_v2_ping_pong_clock.cpp similarity index 97% rename from usermods/usermod_v2_ping_pong_clock/usermod_v2_ping_pong_clock.h rename to usermods/usermod_v2_ping_pong_clock/usermod_v2_ping_pong_clock.cpp index 40ff675c..8212947a 100644 --- a/usermods/usermod_v2_ping_pong_clock/usermod_v2_ping_pong_clock.h +++ b/usermods/usermod_v2_ping_pong_clock/usermod_v2_ping_pong_clock.cpp @@ -117,3 +117,7 @@ public: } }; + + +static PingPongClockUsermod usermod_v2_ping_pong_clock; +REGISTER_USERMOD(usermod_v2_ping_pong_clock); \ No newline at end of file diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/library.json b/usermods/usermod_v2_rotary_encoder_ui_ALT/library.json new file mode 100644 index 00000000..f7c60ecd --- /dev/null +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/library.json @@ -0,0 +1,9 @@ +{ + "name:": "usermod_v2_rotary_encoder_ui_ALT", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.cpp similarity index 99% rename from usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h rename to usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.cpp index 383c1193..ac2cc3c4 100644 --- a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.cpp @@ -1175,3 +1175,7 @@ const char RotaryEncoderUIUsermod::_applyToAll[] PROGMEM = "apply-2-all-seg"; const char RotaryEncoderUIUsermod::_pcf8574[] PROGMEM = "use-PCF8574"; const char RotaryEncoderUIUsermod::_pcfAddress[] PROGMEM = "PCF8574-address"; const char RotaryEncoderUIUsermod::_pcfINTpin[] PROGMEM = "PCF8574-INT-pin"; + + +static RotaryEncoderUIUsermod usermod_v2_rotary_encoder_ui_alt; +REGISTER_USERMOD(usermod_v2_rotary_encoder_ui_alt); \ No newline at end of file diff --git a/usermods/usermod_v2_word_clock/library.json b/usermods/usermod_v2_word_clock/library.json new file mode 100644 index 00000000..74a3d903 --- /dev/null +++ b/usermods/usermod_v2_word_clock/library.json @@ -0,0 +1,9 @@ +{ + "name:": "usermod_v2_word_clock", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h b/usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp similarity index 99% rename from usermods/usermod_v2_word_clock/usermod_v2_word_clock.h rename to usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp index 7ecec08e..781dd7d8 100644 --- a/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h +++ b/usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp @@ -504,4 +504,7 @@ class WordClockUsermod : public Usermod //More methods can be added in the future, this example will then be extended. //Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class! -}; \ No newline at end of file +}; + +static WordClockUsermod usermod_v2_word_clock; +REGISTER_USERMOD(usermod_v2_word_clock); \ No newline at end of file diff --git a/usermods/wireguard/library.json b/usermods/wireguard/library.json new file mode 100644 index 00000000..290f2794 --- /dev/null +++ b/usermods/wireguard/library.json @@ -0,0 +1,9 @@ +{ + "name:": "wireguard", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/wireguard/wireguard.h b/usermods/wireguard/wireguard.cpp similarity index 98% rename from usermods/wireguard/wireguard.h rename to usermods/wireguard/wireguard.cpp index 8656a704..77cc952f 100644 --- a/usermods/wireguard/wireguard.h +++ b/usermods/wireguard/wireguard.cpp @@ -124,4 +124,7 @@ class WireguardUsermod : public Usermod { int endpoint_port = 0; bool is_enabled = false; unsigned long lastTime = 0; -}; \ No newline at end of file +}; + +static WireguardUsermod wireguard; +REGISTER_USERMOD(wireguard); \ No newline at end of file diff --git a/usermods/wizlights/library.json b/usermods/wizlights/library.json new file mode 100644 index 00000000..a82dd7fc --- /dev/null +++ b/usermods/wizlights/library.json @@ -0,0 +1,9 @@ +{ + "name:": "wizlights", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/wizlights/wizlights.h b/usermods/wizlights/wizlights.cpp similarity index 98% rename from usermods/wizlights/wizlights.h rename to usermods/wizlights/wizlights.cpp index 08d20493..67c0effd 100644 --- a/usermods/wizlights/wizlights.h +++ b/usermods/wizlights/wizlights.cpp @@ -156,3 +156,7 @@ class WizLightsUsermod : public Usermod { uint16_t getId(){return USERMOD_ID_WIZLIGHTS;} }; + + +static WizLightsUsermod wizlights; +REGISTER_USERMOD(wizlights); \ No newline at end of file From a5575bc3a037b50f0f4be6be8ad1c28f0b5e1ca7 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sat, 11 Jan 2025 21:41:21 +0000 Subject: [PATCH 134/463] Fix naming of usermod files to match library name --- usermods/ADS1115_v2/{usermod_ads1115.h => ADS1115_v2.h} | 0 usermods/AHT10_v2/{usermod_aht10.h => AHT10_v2.h} | 0 usermods/BH1750_v2/{usermod_bh1750.h => BH1750_v2.h} | 0 usermods/BME280_v2/{usermod_bme280.h => BME280_v2.h} | 0 usermods/BME68X_v2/{usermod_bme68x.h => BME68X_v2.h} | 0 usermods/INA226_v2/{usermod_ina226.h => INA226_v2.h} | 0 .../{usermod_internal_temperature.h => Internal_Temperature_v2.h} | 0 usermods/LD2410_v2/{usermod_ld2410.h => LD2410_v2.h} | 0 usermods/MAX17048_v2/{usermod_max17048.h => MAX17048_v2.h} | 0 usermods/MY9291/{usermode_MY9291.h => MY9291.h} | 0 usermods/TetrisAI_v2/{usermod_v2_tetrisai.h => TetrisAI_v2.h} | 0 .../mqtt_switch_v2/{usermod_mqtt_switch.h => mqtt_switch_v2.h} | 0 .../{usermod_v2_SensorsToMqtt.h => sensors_to_mqtt.h} | 0 ..._seven_segment_reloaded.h => seven_segment_display_reloaded.h} | 0 .../{stairway-wipe-usermod-v2.h => stairway_wipe_basic.h} | 0 .../{usermod_word_clock_matrix.h => word-clock-matrix.h} | 0 16 files changed, 0 insertions(+), 0 deletions(-) rename usermods/ADS1115_v2/{usermod_ads1115.h => ADS1115_v2.h} (100%) rename usermods/AHT10_v2/{usermod_aht10.h => AHT10_v2.h} (100%) rename usermods/BH1750_v2/{usermod_bh1750.h => BH1750_v2.h} (100%) rename usermods/BME280_v2/{usermod_bme280.h => BME280_v2.h} (100%) rename usermods/BME68X_v2/{usermod_bme68x.h => BME68X_v2.h} (100%) rename usermods/INA226_v2/{usermod_ina226.h => INA226_v2.h} (100%) rename usermods/Internal_Temperature_v2/{usermod_internal_temperature.h => Internal_Temperature_v2.h} (100%) rename usermods/LD2410_v2/{usermod_ld2410.h => LD2410_v2.h} (100%) rename usermods/MAX17048_v2/{usermod_max17048.h => MAX17048_v2.h} (100%) rename usermods/MY9291/{usermode_MY9291.h => MY9291.h} (100%) rename usermods/TetrisAI_v2/{usermod_v2_tetrisai.h => TetrisAI_v2.h} (100%) rename usermods/mqtt_switch_v2/{usermod_mqtt_switch.h => mqtt_switch_v2.h} (100%) rename usermods/sensors_to_mqtt/{usermod_v2_SensorsToMqtt.h => sensors_to_mqtt.h} (100%) rename usermods/seven_segment_display_reloaded/{usermod_seven_segment_reloaded.h => seven_segment_display_reloaded.h} (100%) rename usermods/stairway_wipe_basic/{stairway-wipe-usermod-v2.h => stairway_wipe_basic.h} (100%) rename usermods/word-clock-matrix/{usermod_word_clock_matrix.h => word-clock-matrix.h} (100%) diff --git a/usermods/ADS1115_v2/usermod_ads1115.h b/usermods/ADS1115_v2/ADS1115_v2.h similarity index 100% rename from usermods/ADS1115_v2/usermod_ads1115.h rename to usermods/ADS1115_v2/ADS1115_v2.h diff --git a/usermods/AHT10_v2/usermod_aht10.h b/usermods/AHT10_v2/AHT10_v2.h similarity index 100% rename from usermods/AHT10_v2/usermod_aht10.h rename to usermods/AHT10_v2/AHT10_v2.h diff --git a/usermods/BH1750_v2/usermod_bh1750.h b/usermods/BH1750_v2/BH1750_v2.h similarity index 100% rename from usermods/BH1750_v2/usermod_bh1750.h rename to usermods/BH1750_v2/BH1750_v2.h diff --git a/usermods/BME280_v2/usermod_bme280.h b/usermods/BME280_v2/BME280_v2.h similarity index 100% rename from usermods/BME280_v2/usermod_bme280.h rename to usermods/BME280_v2/BME280_v2.h diff --git a/usermods/BME68X_v2/usermod_bme68x.h b/usermods/BME68X_v2/BME68X_v2.h similarity index 100% rename from usermods/BME68X_v2/usermod_bme68x.h rename to usermods/BME68X_v2/BME68X_v2.h diff --git a/usermods/INA226_v2/usermod_ina226.h b/usermods/INA226_v2/INA226_v2.h similarity index 100% rename from usermods/INA226_v2/usermod_ina226.h rename to usermods/INA226_v2/INA226_v2.h diff --git a/usermods/Internal_Temperature_v2/usermod_internal_temperature.h b/usermods/Internal_Temperature_v2/Internal_Temperature_v2.h similarity index 100% rename from usermods/Internal_Temperature_v2/usermod_internal_temperature.h rename to usermods/Internal_Temperature_v2/Internal_Temperature_v2.h diff --git a/usermods/LD2410_v2/usermod_ld2410.h b/usermods/LD2410_v2/LD2410_v2.h similarity index 100% rename from usermods/LD2410_v2/usermod_ld2410.h rename to usermods/LD2410_v2/LD2410_v2.h diff --git a/usermods/MAX17048_v2/usermod_max17048.h b/usermods/MAX17048_v2/MAX17048_v2.h similarity index 100% rename from usermods/MAX17048_v2/usermod_max17048.h rename to usermods/MAX17048_v2/MAX17048_v2.h diff --git a/usermods/MY9291/usermode_MY9291.h b/usermods/MY9291/MY9291.h similarity index 100% rename from usermods/MY9291/usermode_MY9291.h rename to usermods/MY9291/MY9291.h diff --git a/usermods/TetrisAI_v2/usermod_v2_tetrisai.h b/usermods/TetrisAI_v2/TetrisAI_v2.h similarity index 100% rename from usermods/TetrisAI_v2/usermod_v2_tetrisai.h rename to usermods/TetrisAI_v2/TetrisAI_v2.h diff --git a/usermods/mqtt_switch_v2/usermod_mqtt_switch.h b/usermods/mqtt_switch_v2/mqtt_switch_v2.h similarity index 100% rename from usermods/mqtt_switch_v2/usermod_mqtt_switch.h rename to usermods/mqtt_switch_v2/mqtt_switch_v2.h diff --git a/usermods/sensors_to_mqtt/usermod_v2_SensorsToMqtt.h b/usermods/sensors_to_mqtt/sensors_to_mqtt.h similarity index 100% rename from usermods/sensors_to_mqtt/usermod_v2_SensorsToMqtt.h rename to usermods/sensors_to_mqtt/sensors_to_mqtt.h diff --git a/usermods/seven_segment_display_reloaded/usermod_seven_segment_reloaded.h b/usermods/seven_segment_display_reloaded/seven_segment_display_reloaded.h similarity index 100% rename from usermods/seven_segment_display_reloaded/usermod_seven_segment_reloaded.h rename to usermods/seven_segment_display_reloaded/seven_segment_display_reloaded.h diff --git a/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h b/usermods/stairway_wipe_basic/stairway_wipe_basic.h similarity index 100% rename from usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h rename to usermods/stairway_wipe_basic/stairway_wipe_basic.h diff --git a/usermods/word-clock-matrix/usermod_word_clock_matrix.h b/usermods/word-clock-matrix/word-clock-matrix.h similarity index 100% rename from usermods/word-clock-matrix/usermod_word_clock_matrix.h rename to usermods/word-clock-matrix/word-clock-matrix.h From 6e76a72d78659200f369316351c3ea939592f274 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sat, 11 Jan 2025 21:42:41 +0000 Subject: [PATCH 135/463] Convert usermods from header to library --- usermods/ADS1115_v2/{ADS1115_v2.h => ADS1115_v2.cpp} | 5 ++++- usermods/ADS1115_v2/library.json | 9 +++++++++ usermods/AHT10_v2/{AHT10_v2.h => AHT10_v2.cpp} | 5 ++++- usermods/AHT10_v2/library.json | 9 +++++++++ usermods/BH1750_v2/{BH1750_v2.h => BH1750_v2.cpp} | 4 ++++ usermods/BH1750_v2/library.json | 9 +++++++++ usermods/BME280_v2/{BME280_v2.h => BME280_v2.cpp} | 4 ++++ usermods/BME280_v2/library.json | 9 +++++++++ usermods/BME68X_v2/{BME68X_v2.h => BME68X_v2.cpp} | 4 ++++ usermods/BME68X_v2/library.json | 9 +++++++++ usermods/INA226_v2/{INA226_v2.h => INA226_v2.cpp} | 4 ++++ usermods/INA226_v2/library.json | 9 +++++++++ ...rnal_Temperature_v2.h => Internal_Temperature_v2.cpp} | 5 ++++- usermods/Internal_Temperature_v2/library.json | 9 +++++++++ usermods/LD2410_v2/{LD2410_v2.h => LD2410_v2.cpp} | 4 ++++ usermods/LD2410_v2/library.json | 9 +++++++++ usermods/MAX17048_v2/{MAX17048_v2.h => MAX17048_v2.cpp} | 4 ++++ usermods/MAX17048_v2/library.json | 9 +++++++++ usermods/MY9291/{MY9291.h => MY9291.cpp} | 5 ++++- usermods/MY9291/library.json | 9 +++++++++ usermods/TetrisAI_v2/{TetrisAI_v2.h => TetrisAI_v2.cpp} | 4 ++++ usermods/TetrisAI_v2/library.json | 9 +++++++++ usermods/mqtt_switch_v2/library.json | 9 +++++++++ .../{mqtt_switch_v2.h => mqtt_switch_v2.cpp} | 4 ++++ usermods/sensors_to_mqtt/library.json | 9 +++++++++ .../{sensors_to_mqtt.h => sensors_to_mqtt.cpp} | 4 ++++ usermods/seven_segment_display_reloaded/library.json | 9 +++++++++ ...lay_reloaded.h => seven_segment_display_reloaded.cpp} | 4 ++++ usermods/stairway_wipe_basic/library.json | 9 +++++++++ .../{stairway_wipe_basic.h => stairway_wipe_basic.cpp} | 4 ++++ usermods/word-clock-matrix/library.json | 9 +++++++++ .../{word-clock-matrix.h => word-clock-matrix.cpp} | 4 ++++ 32 files changed, 208 insertions(+), 4 deletions(-) rename usermods/ADS1115_v2/{ADS1115_v2.h => ADS1115_v2.cpp} (98%) create mode 100644 usermods/ADS1115_v2/library.json rename usermods/AHT10_v2/{AHT10_v2.h => AHT10_v2.cpp} (98%) create mode 100644 usermods/AHT10_v2/library.json rename usermods/BH1750_v2/{BH1750_v2.h => BH1750_v2.cpp} (99%) create mode 100644 usermods/BH1750_v2/library.json rename usermods/BME280_v2/{BME280_v2.h => BME280_v2.cpp} (99%) create mode 100644 usermods/BME280_v2/library.json rename usermods/BME68X_v2/{BME68X_v2.h => BME68X_v2.cpp} (99%) create mode 100644 usermods/BME68X_v2/library.json rename usermods/INA226_v2/{INA226_v2.h => INA226_v2.cpp} (99%) create mode 100644 usermods/INA226_v2/library.json rename usermods/Internal_Temperature_v2/{Internal_Temperature_v2.h => Internal_Temperature_v2.cpp} (98%) create mode 100644 usermods/Internal_Temperature_v2/library.json rename usermods/LD2410_v2/{LD2410_v2.h => LD2410_v2.cpp} (99%) create mode 100644 usermods/LD2410_v2/library.json rename usermods/MAX17048_v2/{MAX17048_v2.h => MAX17048_v2.cpp} (99%) create mode 100644 usermods/MAX17048_v2/library.json rename usermods/MY9291/{MY9291.h => MY9291.cpp} (94%) create mode 100644 usermods/MY9291/library.json rename usermods/TetrisAI_v2/{TetrisAI_v2.h => TetrisAI_v2.cpp} (99%) create mode 100644 usermods/TetrisAI_v2/library.json create mode 100644 usermods/mqtt_switch_v2/library.json rename usermods/mqtt_switch_v2/{mqtt_switch_v2.h => mqtt_switch_v2.cpp} (98%) create mode 100644 usermods/sensors_to_mqtt/library.json rename usermods/sensors_to_mqtt/{sensors_to_mqtt.h => sensors_to_mqtt.cpp} (98%) create mode 100644 usermods/seven_segment_display_reloaded/library.json rename usermods/seven_segment_display_reloaded/{seven_segment_display_reloaded.h => seven_segment_display_reloaded.cpp} (99%) create mode 100644 usermods/stairway_wipe_basic/library.json rename usermods/stairway_wipe_basic/{stairway_wipe_basic.h => stairway_wipe_basic.cpp} (97%) create mode 100644 usermods/word-clock-matrix/library.json rename usermods/word-clock-matrix/{word-clock-matrix.h => word-clock-matrix.cpp} (99%) diff --git a/usermods/ADS1115_v2/ADS1115_v2.h b/usermods/ADS1115_v2/ADS1115_v2.cpp similarity index 98% rename from usermods/ADS1115_v2/ADS1115_v2.h rename to usermods/ADS1115_v2/ADS1115_v2.cpp index 5e2b4b27..48f91733 100644 --- a/usermods/ADS1115_v2/ADS1115_v2.h +++ b/usermods/ADS1115_v2/ADS1115_v2.cpp @@ -252,4 +252,7 @@ class ADS1115Usermod : public Usermod { int16_t results = ads.getLastConversionResults(); readings[activeChannel] = ads.computeVolts(results); } -}; \ No newline at end of file +}; + +static ADS1115Usermod ads1115_v2; +REGISTER_USERMOD(ads1115_v2); \ No newline at end of file diff --git a/usermods/ADS1115_v2/library.json b/usermods/ADS1115_v2/library.json new file mode 100644 index 00000000..e4b448a0 --- /dev/null +++ b/usermods/ADS1115_v2/library.json @@ -0,0 +1,9 @@ +{ + "name:": "ADS1115_v2", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/AHT10_v2/AHT10_v2.h b/usermods/AHT10_v2/AHT10_v2.cpp similarity index 98% rename from usermods/AHT10_v2/AHT10_v2.h rename to usermods/AHT10_v2/AHT10_v2.cpp index b5dc1841..171e1575 100644 --- a/usermods/AHT10_v2/AHT10_v2.h +++ b/usermods/AHT10_v2/AHT10_v2.cpp @@ -324,4 +324,7 @@ public: } }; -const char UsermodAHT10::_name[] PROGMEM = "AHTxx"; \ No newline at end of file +const char UsermodAHT10::_name[] PROGMEM = "AHTxx"; + +static UsermodAHT10 aht10_v2; +REGISTER_USERMOD(aht10_v2); \ No newline at end of file diff --git a/usermods/AHT10_v2/library.json b/usermods/AHT10_v2/library.json new file mode 100644 index 00000000..209e97af --- /dev/null +++ b/usermods/AHT10_v2/library.json @@ -0,0 +1,9 @@ +{ + "name:": "AHT10_v2", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/BH1750_v2/BH1750_v2.h b/usermods/BH1750_v2/BH1750_v2.cpp similarity index 99% rename from usermods/BH1750_v2/BH1750_v2.h rename to usermods/BH1750_v2/BH1750_v2.cpp index 2a2bd463..5bd47624 100644 --- a/usermods/BH1750_v2/BH1750_v2.h +++ b/usermods/BH1750_v2/BH1750_v2.cpp @@ -250,3 +250,7 @@ const char Usermod_BH1750::_maxReadInterval[] PROGMEM = "max-read-interval-ms"; const char Usermod_BH1750::_minReadInterval[] PROGMEM = "min-read-interval-ms"; const char Usermod_BH1750::_HomeAssistantDiscovery[] PROGMEM = "HomeAssistantDiscoveryLux"; const char Usermod_BH1750::_offset[] PROGMEM = "offset-lx"; + + +static Usermod_BH1750 bh1750_v2; +REGISTER_USERMOD(bh1750_v2); \ No newline at end of file diff --git a/usermods/BH1750_v2/library.json b/usermods/BH1750_v2/library.json new file mode 100644 index 00000000..662ca354 --- /dev/null +++ b/usermods/BH1750_v2/library.json @@ -0,0 +1,9 @@ +{ + "name:": "BH1750_v2", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/BME280_v2/BME280_v2.h b/usermods/BME280_v2/BME280_v2.cpp similarity index 99% rename from usermods/BME280_v2/BME280_v2.h rename to usermods/BME280_v2/BME280_v2.cpp index 9168f422..d29451ee 100644 --- a/usermods/BME280_v2/BME280_v2.h +++ b/usermods/BME280_v2/BME280_v2.cpp @@ -479,3 +479,7 @@ public: const char UsermodBME280::_name[] PROGMEM = "BME280/BMP280"; const char UsermodBME280::_enabled[] PROGMEM = "enabled"; + + +static UsermodBME280 bme280_v2; +REGISTER_USERMOD(bme280_v2); \ No newline at end of file diff --git a/usermods/BME280_v2/library.json b/usermods/BME280_v2/library.json new file mode 100644 index 00000000..57d41fb3 --- /dev/null +++ b/usermods/BME280_v2/library.json @@ -0,0 +1,9 @@ +{ + "name:": "BME280_v2", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/BME68X_v2/BME68X_v2.h b/usermods/BME68X_v2/BME68X_v2.cpp similarity index 99% rename from usermods/BME68X_v2/BME68X_v2.h rename to usermods/BME68X_v2/BME68X_v2.cpp index aca24d0a..5814506b 100644 --- a/usermods/BME68X_v2/BME68X_v2.h +++ b/usermods/BME68X_v2/BME68X_v2.cpp @@ -1112,3 +1112,7 @@ void UsermodBME68X::saveState() { if (WLED_MQTT_CONNECTED) mqtt->publish(charbuffer, 0, false, contbuffer); } } + + +static UsermodBME68X bme68x_v2; +REGISTER_USERMOD(bme68x_v2); \ No newline at end of file diff --git a/usermods/BME68X_v2/library.json b/usermods/BME68X_v2/library.json new file mode 100644 index 00000000..1a8a1f0f --- /dev/null +++ b/usermods/BME68X_v2/library.json @@ -0,0 +1,9 @@ +{ + "name:": "BME68X_v2", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/INA226_v2/INA226_v2.h b/usermods/INA226_v2/INA226_v2.cpp similarity index 99% rename from usermods/INA226_v2/INA226_v2.h rename to usermods/INA226_v2/INA226_v2.cpp index 52bc3d83..3c79f05b 100644 --- a/usermods/INA226_v2/INA226_v2.h +++ b/usermods/INA226_v2/INA226_v2.cpp @@ -554,3 +554,7 @@ public: }; const char UsermodINA226::_name[] PROGMEM = "INA226"; + + +static UsermodINA226 ina226_v2; +REGISTER_USERMOD(ina226_v2); \ No newline at end of file diff --git a/usermods/INA226_v2/library.json b/usermods/INA226_v2/library.json new file mode 100644 index 00000000..2596b86a --- /dev/null +++ b/usermods/INA226_v2/library.json @@ -0,0 +1,9 @@ +{ + "name:": "INA226_v2", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/Internal_Temperature_v2/Internal_Temperature_v2.h b/usermods/Internal_Temperature_v2/Internal_Temperature_v2.cpp similarity index 98% rename from usermods/Internal_Temperature_v2/Internal_Temperature_v2.h rename to usermods/Internal_Temperature_v2/Internal_Temperature_v2.cpp index 6d4d4577..ab7f907e 100644 --- a/usermods/Internal_Temperature_v2/Internal_Temperature_v2.h +++ b/usermods/Internal_Temperature_v2/Internal_Temperature_v2.cpp @@ -193,4 +193,7 @@ void InternalTemperatureUsermod::publishMqtt(const char *state, bool retain) mqtt->publish(subuf, 0, retain, state); } #endif -} \ No newline at end of file +} + +static InternalTemperatureUsermod internal_temperature_v2; +REGISTER_USERMOD(internal_temperature_v2); \ No newline at end of file diff --git a/usermods/Internal_Temperature_v2/library.json b/usermods/Internal_Temperature_v2/library.json new file mode 100644 index 00000000..38b560da --- /dev/null +++ b/usermods/Internal_Temperature_v2/library.json @@ -0,0 +1,9 @@ +{ + "name:": "Internal_Temperature_v2", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/LD2410_v2/LD2410_v2.h b/usermods/LD2410_v2/LD2410_v2.cpp similarity index 99% rename from usermods/LD2410_v2/LD2410_v2.h rename to usermods/LD2410_v2/LD2410_v2.cpp index 4d96b32f..51c887fa 100644 --- a/usermods/LD2410_v2/LD2410_v2.h +++ b/usermods/LD2410_v2/LD2410_v2.cpp @@ -235,3 +235,7 @@ void LD2410Usermod::publishMqtt(const char* topic, const char* state, bool retai } #endif } + + +static LD2410Usermod ld2410_v2; +REGISTER_USERMOD(ld2410_v2); \ No newline at end of file diff --git a/usermods/LD2410_v2/library.json b/usermods/LD2410_v2/library.json new file mode 100644 index 00000000..3480cd79 --- /dev/null +++ b/usermods/LD2410_v2/library.json @@ -0,0 +1,9 @@ +{ + "name:": "LD2410_v2", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/MAX17048_v2/MAX17048_v2.h b/usermods/MAX17048_v2/MAX17048_v2.cpp similarity index 99% rename from usermods/MAX17048_v2/MAX17048_v2.h rename to usermods/MAX17048_v2/MAX17048_v2.cpp index c3a2664a..1a1108cf 100644 --- a/usermods/MAX17048_v2/MAX17048_v2.h +++ b/usermods/MAX17048_v2/MAX17048_v2.cpp @@ -279,3 +279,7 @@ const char Usermod_MAX17048::_enabled[] PROGMEM = "enabled"; const char Usermod_MAX17048::_maxReadInterval[] PROGMEM = "max-read-interval-ms"; const char Usermod_MAX17048::_minReadInterval[] PROGMEM = "min-read-interval-ms"; const char Usermod_MAX17048::_HomeAssistantDiscovery[] PROGMEM = "HomeAssistantDiscovery"; + + +static Usermod_MAX17048 max17048_v2; +REGISTER_USERMOD(max17048_v2); \ No newline at end of file diff --git a/usermods/MAX17048_v2/library.json b/usermods/MAX17048_v2/library.json new file mode 100644 index 00000000..72ac0e61 --- /dev/null +++ b/usermods/MAX17048_v2/library.json @@ -0,0 +1,9 @@ +{ + "name:": "MAX17048_v2", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/MY9291/MY9291.h b/usermods/MY9291/MY9291.cpp similarity index 94% rename from usermods/MY9291/MY9291.h rename to usermods/MY9291/MY9291.cpp index 66bbc34c..ce8d0f00 100644 --- a/usermods/MY9291/MY9291.h +++ b/usermods/MY9291/MY9291.cpp @@ -42,4 +42,7 @@ class MY9291Usermod : public Usermod { uint16_t getId() { return USERMOD_ID_MY9291; } -}; \ No newline at end of file +}; + +static MY9291Usermod my9291; +REGISTER_USERMOD(my9291); \ No newline at end of file diff --git a/usermods/MY9291/library.json b/usermods/MY9291/library.json new file mode 100644 index 00000000..d965f4c3 --- /dev/null +++ b/usermods/MY9291/library.json @@ -0,0 +1,9 @@ +{ + "name:": "MY9291", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/TetrisAI_v2/TetrisAI_v2.h b/usermods/TetrisAI_v2/TetrisAI_v2.cpp similarity index 99% rename from usermods/TetrisAI_v2/TetrisAI_v2.h rename to usermods/TetrisAI_v2/TetrisAI_v2.cpp index 0f7039da..78cdfd22 100644 --- a/usermods/TetrisAI_v2/TetrisAI_v2.h +++ b/usermods/TetrisAI_v2/TetrisAI_v2.cpp @@ -250,3 +250,7 @@ public: return USERMOD_ID_TETRISAI; } }; + + +static TetrisAIUsermod tetrisai_v2; +REGISTER_USERMOD(tetrisai_v2); \ No newline at end of file diff --git a/usermods/TetrisAI_v2/library.json b/usermods/TetrisAI_v2/library.json new file mode 100644 index 00000000..199e5c43 --- /dev/null +++ b/usermods/TetrisAI_v2/library.json @@ -0,0 +1,9 @@ +{ + "name:": "TetrisAI_v2", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/mqtt_switch_v2/library.json b/usermods/mqtt_switch_v2/library.json new file mode 100644 index 00000000..96695a9c --- /dev/null +++ b/usermods/mqtt_switch_v2/library.json @@ -0,0 +1,9 @@ +{ + "name:": "mqtt_switch_v2", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/mqtt_switch_v2/mqtt_switch_v2.h b/usermods/mqtt_switch_v2/mqtt_switch_v2.cpp similarity index 98% rename from usermods/mqtt_switch_v2/mqtt_switch_v2.h rename to usermods/mqtt_switch_v2/mqtt_switch_v2.cpp index 67dfc9cc..d4d823f3 100644 --- a/usermods/mqtt_switch_v2/mqtt_switch_v2.h +++ b/usermods/mqtt_switch_v2/mqtt_switch_v2.cpp @@ -157,3 +157,7 @@ inline void UsermodMqttSwitch::updateState(uint8_t pinNr) mqtt->publish(buf, 0, false, "OFF"); } } + + +static UsermodMqttSwitc mqtt_switch_v2; +REGISTER_USERMOD(mqtt_switch_v2); \ No newline at end of file diff --git a/usermods/sensors_to_mqtt/library.json b/usermods/sensors_to_mqtt/library.json new file mode 100644 index 00000000..dd9a4f3a --- /dev/null +++ b/usermods/sensors_to_mqtt/library.json @@ -0,0 +1,9 @@ +{ + "name:": "sensors_to_mqtt", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/sensors_to_mqtt/sensors_to_mqtt.h b/usermods/sensors_to_mqtt/sensors_to_mqtt.cpp similarity index 98% rename from usermods/sensors_to_mqtt/sensors_to_mqtt.h rename to usermods/sensors_to_mqtt/sensors_to_mqtt.cpp index 9b5bd8c8..02f8e8d2 100644 --- a/usermods/sensors_to_mqtt/sensors_to_mqtt.h +++ b/usermods/sensors_to_mqtt/sensors_to_mqtt.cpp @@ -276,3 +276,7 @@ public: } } }; + + +static UserMod_SensorsToMQTT sensors_to_mqtt; +REGISTER_USERMOD(sensors_to_mqtt); \ No newline at end of file diff --git a/usermods/seven_segment_display_reloaded/library.json b/usermods/seven_segment_display_reloaded/library.json new file mode 100644 index 00000000..485aa4fd --- /dev/null +++ b/usermods/seven_segment_display_reloaded/library.json @@ -0,0 +1,9 @@ +{ + "name:": "seven_segment_display_reloaded", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/seven_segment_display_reloaded/seven_segment_display_reloaded.h b/usermods/seven_segment_display_reloaded/seven_segment_display_reloaded.cpp similarity index 99% rename from usermods/seven_segment_display_reloaded/seven_segment_display_reloaded.h rename to usermods/seven_segment_display_reloaded/seven_segment_display_reloaded.cpp index 1436f8fc..812065d8 100644 --- a/usermods/seven_segment_display_reloaded/seven_segment_display_reloaded.h +++ b/usermods/seven_segment_display_reloaded/seven_segment_display_reloaded.cpp @@ -571,3 +571,7 @@ const char UsermodSSDR::_str_years[] PROGMEM = "LED-Numbers-Year"; const char UsermodSSDR::_str_ldrEnabled[] PROGMEM = "enable-auto-brightness"; const char UsermodSSDR::_str_minBrightness[] PROGMEM = "auto-brightness-min"; const char UsermodSSDR::_str_maxBrightness[] PROGMEM = "auto-brightness-max"; + + +static UsermodSSDR seven_segment_display_reloaded; +REGISTER_USERMOD(seven_segment_display_reloaded); \ No newline at end of file diff --git a/usermods/stairway_wipe_basic/library.json b/usermods/stairway_wipe_basic/library.json new file mode 100644 index 00000000..6b3a5236 --- /dev/null +++ b/usermods/stairway_wipe_basic/library.json @@ -0,0 +1,9 @@ +{ + "name:": "stairway_wipe_basic", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/stairway_wipe_basic/stairway_wipe_basic.h b/usermods/stairway_wipe_basic/stairway_wipe_basic.cpp similarity index 97% rename from usermods/stairway_wipe_basic/stairway_wipe_basic.h rename to usermods/stairway_wipe_basic/stairway_wipe_basic.cpp index 707479df..cdb7cd66 100644 --- a/usermods/stairway_wipe_basic/stairway_wipe_basic.h +++ b/usermods/stairway_wipe_basic/stairway_wipe_basic.cpp @@ -126,3 +126,7 @@ void setup() { //More methods can be added in the future, this example will then be extended. //Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class! }; + + +static StairwayWipeUsermod stairway_wipe_basic; +REGISTER_USERMOD(stairway_wipe_basic); \ No newline at end of file diff --git a/usermods/word-clock-matrix/library.json b/usermods/word-clock-matrix/library.json new file mode 100644 index 00000000..ed29ae08 --- /dev/null +++ b/usermods/word-clock-matrix/library.json @@ -0,0 +1,9 @@ +{ + "name:": "word-clock-matrix", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "libLDFMode": "chain+", + "libArchive": false + } +} \ No newline at end of file diff --git a/usermods/word-clock-matrix/word-clock-matrix.h b/usermods/word-clock-matrix/word-clock-matrix.cpp similarity index 99% rename from usermods/word-clock-matrix/word-clock-matrix.h rename to usermods/word-clock-matrix/word-clock-matrix.cpp index 82499c0c..c8606003 100644 --- a/usermods/word-clock-matrix/word-clock-matrix.h +++ b/usermods/word-clock-matrix/word-clock-matrix.cpp @@ -336,3 +336,7 @@ public: }; + + +static WordClockMatrix word-clock-matrix; +REGISTER_USERMOD(word-clock-matrix); \ No newline at end of file From 67022beca0aee5edcc45918987217660d0362892 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sat, 11 Jan 2025 22:07:03 +0000 Subject: [PATCH 136/463] Build all usermods --- .github/workflows/build.yml | 7 ++++++- usermods/platformio_override.usermods.ini | 9 +++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 usermods/platformio_override.usermods.ini diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2bac314f..e1b05b5a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -32,7 +32,7 @@ jobs: strategy: fail-fast: false matrix: - environment: ${{ fromJSON(needs.get_default_envs.outputs.environments) }} + environment: ${{ fromJSON(needs.get_default_envs.outputs.environments) }} usermods steps: - uses: actions/checkout@v4 - name: Set up Node.js @@ -57,6 +57,11 @@ jobs: cache: 'pip' - name: Install PlatformIO run: pip install -r requirements.txt + - name: Add usermods environment + run: | + cp -v usermods/platformio_override.usermods.ini platformio_override.ini + find usermods/ -name library.json | xargs dirname | xargs -n 1 basename | xargs echo >> platformio_override.ini + - name: Build firmware run: pio run -e ${{ matrix.environment }} - uses: actions/upload-artifact@v4 diff --git a/usermods/platformio_override.usermods.ini b/usermods/platformio_override.usermods.ini new file mode 100644 index 00000000..568b2025 --- /dev/null +++ b/usermods/platformio_override.usermods.ini @@ -0,0 +1,9 @@ +[env:usermods] +board = esp32dev +platform = ${esp32.platform} +platform_packages = ${esp32.platform_packages} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"USERMODS\" + ${esp32.AR_build_flags} +lib_deps = ${esp32.lib_deps} +board_build.partitions = ${esp32.default_partitions} From cbed841414c0c6e388c3abac71f3063a5c472323 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sat, 11 Jan 2025 22:12:36 +0000 Subject: [PATCH 137/463] Include basic usermods in CI --- .github/workflows/build.yml | 3 ++- platformio.ini | 12 +++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e1b05b5a..efdb3f7a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -32,7 +32,7 @@ jobs: strategy: fail-fast: false matrix: - environment: ${{ fromJSON(needs.get_default_envs.outputs.environments) }} usermods + environment: ${{ fromJSON(needs.get_default_envs.outputs.environments) }} steps: - uses: actions/checkout@v4 - name: Set up Node.js @@ -60,6 +60,7 @@ jobs: - name: Add usermods environment run: | cp -v usermods/platformio_override.usermods.ini platformio_override.ini + echo -n "custom_usermods = " >> platformio_override.ini find usermods/ -name library.json | xargs dirname | xargs -n 1 basename | xargs echo >> platformio_override.ini - name: Build firmware diff --git a/platformio.ini b/platformio.ini index 4832978a..156feb06 100644 --- a/platformio.ini +++ b/platformio.ini @@ -10,7 +10,7 @@ # ------------------------------------------------------------------------------ # CI/release binaries -default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover +default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover, usermods src_dir = ./wled00 data_dir = ./wled00/data @@ -636,3 +636,13 @@ build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME= ; -D STATUSLED=15 ${esp32.AR_build_flags} lib_deps = ${esp32s2.lib_deps} + + +[env:usermods] +board = esp32dev +platform = ${esp32.platform} +platform_packages = ${esp32.platform_packages} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"USERMODS\" + ${esp32.AR_build_flags} +lib_deps = ${esp32.lib_deps} From c16d83fab00c6a3bb8510bc269f46d2082b41cef Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sat, 11 Jan 2025 22:36:06 +0000 Subject: [PATCH 138/463] Build custom_usermods = audioreactive auto_save animartrix --- platformio.ini | 2 +- wled00/wled.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 156feb06..7eef1775 100644 --- a/platformio.ini +++ b/platformio.ini @@ -420,7 +420,7 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME= board = esp32dev platform = ${esp32.platform} platform_packages = ${esp32.platform_packages} -custom_usermods = audioreactive +custom_usermods = audioreactive auto_save usermod_v2_animartrix build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32\" #-D WLED_DISABLE_BROWNOUT_DET ${esp32.AR_build_flags} diff --git a/wled00/wled.h b/wled00/wled.h index ae93d954..5a1a9ff8 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -1,3 +1,6 @@ +// TODO: HACK!! - do not merge +#define LOROL_LITTLEFS 1 + #ifndef WLED_H #define WLED_H /* From d64cedd3fc94080277524942f3170a7c06d8e1bf Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sat, 11 Jan 2025 22:38:57 +0000 Subject: [PATCH 139/463] Build custom_usermods = audioreactive auto_save animartrix --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 7eef1775..00ddd815 100644 --- a/platformio.ini +++ b/platformio.ini @@ -420,7 +420,7 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME= board = esp32dev platform = ${esp32.platform} platform_packages = ${esp32.platform_packages} -custom_usermods = audioreactive auto_save usermod_v2_animartrix +custom_usermods = audioreactive auto_save animartrix build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32\" #-D WLED_DISABLE_BROWNOUT_DET ${esp32.AR_build_flags} From 2381e323c1dcb13c176d691bbf9871d7e5282fcd Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sat, 11 Jan 2025 22:54:28 +0000 Subject: [PATCH 140/463] Define dependencies for ADS1115 usermod --- platformio.ini | 3 --- usermods/ADS1115_v2/library.json | 6 +++++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/platformio.ini b/platformio.ini index 00ddd815..e52afb3b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -158,9 +158,6 @@ lib_deps = ;adafruit/Adafruit BMP280 Library @ 2.1.0 ;adafruit/Adafruit CCS811 Library @ 1.0.4 ;adafruit/Adafruit Si7021 Library @ 1.4.0 - #For ADS1115 sensor uncomment following - ;adafruit/Adafruit BusIO @ 1.13.2 - ;adafruit/Adafruit ADS1X15 @ 2.4.0 #For MAX1704x Lipo Monitor / Fuel Gauge uncomment following ; https://github.com/adafruit/Adafruit_BusIO @ 1.14.5 ; https://github.com/adafruit/Adafruit_MAX1704X @ 1.0.2 diff --git a/usermods/ADS1115_v2/library.json b/usermods/ADS1115_v2/library.json index e4b448a0..179a56e5 100644 --- a/usermods/ADS1115_v2/library.json +++ b/usermods/ADS1115_v2/library.json @@ -5,5 +5,9 @@ "includeDir": "../../wled00", "libLDFMode": "chain+", "libArchive": false + }, + "dependencies": { + "Adafruit BusIO": "https://github.com/adafruit/Adafruit_BusIO#1.13.2", + "Adafruit ADS1X15": "https://github.com/adafruit/Adafruit_ADS1X15#2.4.0" } -} \ No newline at end of file +} From 79bac912aa7164b18efddf676397e0b8755e4fca Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sat, 11 Jan 2025 23:25:05 +0000 Subject: [PATCH 141/463] use bigger partitions for usermods env --- usermods/AHT10_v2/library.json | 5 ++++- usermods/AHT10_v2/platformio_override.ini | 4 ---- usermods/BH1750_v2/library.json | 5 ++++- usermods/BH1750_v2/readme.md | 11 ----------- usermods/Temperature/library.json | 5 ++++- usermods/Temperature/platformio_override.ini | 6 +----- usermods/platformio_override.usermods.ini | 2 +- 7 files changed, 14 insertions(+), 24 deletions(-) diff --git a/usermods/AHT10_v2/library.json b/usermods/AHT10_v2/library.json index 209e97af..28bac435 100644 --- a/usermods/AHT10_v2/library.json +++ b/usermods/AHT10_v2/library.json @@ -5,5 +5,8 @@ "includeDir": "../../wled00", "libLDFMode": "chain+", "libArchive": false + }, + "dependencies": { + "enjoyneering/AHT10":"~1.1.0" } -} \ No newline at end of file +} diff --git a/usermods/AHT10_v2/platformio_override.ini b/usermods/AHT10_v2/platformio_override.ini index 30240f22..74dcd659 100644 --- a/usermods/AHT10_v2/platformio_override.ini +++ b/usermods/AHT10_v2/platformio_override.ini @@ -2,8 +2,4 @@ extends = env:esp32dev build_flags = ${common.build_flags} ${esp32.build_flags} - -D USERMOD_AHT10 ; -D USERMOD_AHT10_DEBUG ; -- add a debug status to the info modal -lib_deps = - ${esp32.lib_deps} - enjoyneering/AHT10@~1.1.0 \ No newline at end of file diff --git a/usermods/BH1750_v2/library.json b/usermods/BH1750_v2/library.json index 662ca354..0211bc88 100644 --- a/usermods/BH1750_v2/library.json +++ b/usermods/BH1750_v2/library.json @@ -5,5 +5,8 @@ "includeDir": "../../wled00", "libLDFMode": "chain+", "libArchive": false + }, + "dependencies": { + "claws/BH1750":"^1.2.0" } -} \ No newline at end of file +} diff --git a/usermods/BH1750_v2/readme.md b/usermods/BH1750_v2/readme.md index 6e6c693d..c4aa8cb4 100644 --- a/usermods/BH1750_v2/readme.md +++ b/usermods/BH1750_v2/readme.md @@ -6,22 +6,11 @@ The luminance is displayed in both the Info section of the web UI, as well as pu ## Dependencies - Libraries - `claws/BH1750 @^1.2.0` - - This must be added under `lib_deps` in your `platformio.ini` (or `platformio_override.ini`). - Data is published over MQTT - make sure you've enabled the MQTT sync interface. ## Compilation To enable, compile with `USERMOD_BH1750` defined (e.g. in `platformio_override.ini`) -```ini -[env:usermod_BH1750_d1_mini] -extends = env:d1_mini -build_flags = - ${common.build_flags_esp8266} - -D USERMOD_BH1750 -lib_deps = - ${esp8266.lib_deps} - claws/BH1750 @ ^1.2.0 -``` ### Configuration Options The following settings can be set at compile-time but are configurable on the usermod menu (except First Measurement time): diff --git a/usermods/Temperature/library.json b/usermods/Temperature/library.json index 56371db4..24de7982 100644 --- a/usermods/Temperature/library.json +++ b/usermods/Temperature/library.json @@ -5,5 +5,8 @@ "includeDir": "../../wled00", "libLDFMode": "chain+", "libArchive": false + }, + "dependencies": { + "paulstoffregen/OneWire":"~2.3.8" } -} \ No newline at end of file +} diff --git a/usermods/Temperature/platformio_override.ini b/usermods/Temperature/platformio_override.ini index cc86367f..ed35b7d4 100644 --- a/usermods/Temperature/platformio_override.ini +++ b/usermods/Temperature/platformio_override.ini @@ -3,8 +3,4 @@ ; USERMOD_DALLASTEMPERATURE - define this to have this user mod included wled00\usermods_list.cpp ; USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL - the number of milliseconds between measurements, defaults to 60 seconds ; -[env:d1_mini_usermod_dallas_temperature_C] -extends = env:d1_mini -build_flags = ${common.build_flags_esp8266} -D USERMOD_DALLASTEMPERATURE -lib_deps = ${env.lib_deps} - paulstoffregen/OneWire@~2.3.8 \ No newline at end of file + diff --git a/usermods/platformio_override.usermods.ini b/usermods/platformio_override.usermods.ini index 568b2025..0035ac59 100644 --- a/usermods/platformio_override.usermods.ini +++ b/usermods/platformio_override.usermods.ini @@ -6,4 +6,4 @@ build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"USERMODS\" ${esp32.AR_build_flags} lib_deps = ${esp32.lib_deps} -board_build.partitions = ${esp32.default_partitions} +board_build.partitions = ${esp32.big_partitions} \ No newline at end of file From d3eec72e45e4bfae7ada12e45c637058d552a0a8 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sun, 12 Jan 2025 00:09:31 +0000 Subject: [PATCH 142/463] Defining more usermod dependencies --- usermods/BME68X_v2/README.md | 17 ----------------- usermods/BME68X_v2/library.json | 5 ++++- usermods/pixels_dice_tray/library.json | 5 ++++- usermods/pov_display/library.json | 5 ++++- usermods/sensors_to_mqtt/library.json | 8 ++++++-- usermods/sensors_to_mqtt/readme.md | 19 ------------------- usermods/wireguard/library.json | 5 ++++- usermods/wireguard/platformio_override.ini | 22 ---------------------- 8 files changed, 22 insertions(+), 64 deletions(-) delete mode 100644 usermods/wireguard/platformio_override.ini diff --git a/usermods/BME68X_v2/README.md b/usermods/BME68X_v2/README.md index 72ae25a5..7e7a1511 100644 --- a/usermods/BME68X_v2/README.md +++ b/usermods/BME68X_v2/README.md @@ -118,23 +118,6 @@ Methods also exist to read the read/calculated values from other WLED modules th - getStabStatus(); - getRunInStatus(); - -## Compiling - -To enable, compile with `USERMOD_BME68X` defined (e.g. in `platformio_override.ini`) and add the `BSEC Software Library` to the lib_deps. - -``` -[env:esp32-BME680] -board = esp32dev -platform = ${esp32.platform} -platform_packages = ${esp32.platform_packages} -lib_deps = ${esp32.lib_deps} - boschsensortec/BSEC Software Library @ ^1.8.1492 ; USERMOD: BME680 -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp32} - -D USERMOD_BME68X ; USERMOD: BME680 -``` - ## Revision History ### Version 1.0.0 - First version of the BME68X_v user module diff --git a/usermods/BME68X_v2/library.json b/usermods/BME68X_v2/library.json index 1a8a1f0f..ccfac0d9 100644 --- a/usermods/BME68X_v2/library.json +++ b/usermods/BME68X_v2/library.json @@ -5,5 +5,8 @@ "includeDir": "../../wled00", "libLDFMode": "chain+", "libArchive": false + }, + "dependencies": { + "boschsensortec/BSEC Software Library":"^1.8.1492" } -} \ No newline at end of file +} diff --git a/usermods/pixels_dice_tray/library.json b/usermods/pixels_dice_tray/library.json index 01776ffe..4634c407 100644 --- a/usermods/pixels_dice_tray/library.json +++ b/usermods/pixels_dice_tray/library.json @@ -5,5 +5,8 @@ "includeDir": "../../wled00", "libLDFMode": "chain+", "libArchive": false + }, + "dependencies": { + "arduino-pixels-dice":"https://github.com/axlan/arduino-pixels-dice.git" } -} \ No newline at end of file +} diff --git a/usermods/pov_display/library.json b/usermods/pov_display/library.json index 5998377b..a3885417 100644 --- a/usermods/pov_display/library.json +++ b/usermods/pov_display/library.json @@ -5,5 +5,8 @@ "includeDir": "../../wled00", "libLDFMode": "chain+", "libArchive": false + }, + "dependencies": { + "bitbank2/PNGdec":"^1.0.3" } -} \ No newline at end of file +} diff --git a/usermods/sensors_to_mqtt/library.json b/usermods/sensors_to_mqtt/library.json index dd9a4f3a..c1bb6ec8 100644 --- a/usermods/sensors_to_mqtt/library.json +++ b/usermods/sensors_to_mqtt/library.json @@ -5,5 +5,9 @@ "includeDir": "../../wled00", "libLDFMode": "chain+", "libArchive": false - } -} \ No newline at end of file + }, + "dependencies": { + "adafruit/Adafruit BMP280 Library":"2.1.0", + "adafruit/Adafruit CCS811 Library":"1.0.4", + "adafruit/Adafruit Si7021 Library":"1.4.0 +} diff --git a/usermods/sensors_to_mqtt/readme.md b/usermods/sensors_to_mqtt/readme.md index d427d3e1..06162793 100644 --- a/usermods/sensors_to_mqtt/readme.md +++ b/usermods/sensors_to_mqtt/readme.md @@ -60,25 +60,6 @@ SCL_PIN = 5; SDA_PIN = 4; ``` -## Enable in WLED - -1. Copy `usermod_v2_SensorsToMqtt.h` into the `wled00` directory. -2. Add to `build_flags` in platformio.ini: - -``` - -D USERMOD_SENSORSTOMQTT -``` - -3. And add to `lib_deps` in platformio.ini: - -``` - adafruit/Adafruit BMP280 Library @ 2.1.0 - adafruit/Adafruit CCS811 Library @ 1.0.4 - adafruit/Adafruit Si7021 Library @ 1.4.0 -``` - -The #ifdefs in `usermods_list.cpp` should do the rest - # Credits - Aircoookie for making WLED diff --git a/usermods/wireguard/library.json b/usermods/wireguard/library.json index 290f2794..99648400 100644 --- a/usermods/wireguard/library.json +++ b/usermods/wireguard/library.json @@ -5,5 +5,8 @@ "includeDir": "../../wled00", "libLDFMode": "chain+", "libArchive": false + }, + "dependencies": { + "WireGuard-ESP32-Arduino":"https://github.com/kienvu58/WireGuard-ESP32-Arduino.git" } -} \ No newline at end of file +} diff --git a/usermods/wireguard/platformio_override.ini b/usermods/wireguard/platformio_override.ini deleted file mode 100644 index fc0ae5fc..00000000 --- a/usermods/wireguard/platformio_override.ini +++ /dev/null @@ -1,22 +0,0 @@ -# Example PlatformIO Project Configuration Override for WireGuard -# ------------------------------------------------------------------------------ -# Copy to platformio_override.ini to activate. -# ------------------------------------------------------------------------------ -# Please visit documentation: https://docs.platformio.org/page/projectconf.html - -[platformio] -default_envs = WLED_ESP32-WireGuard - -[env:WLED_ESP32-WireGuard] -board = esp32dev -platform = ${esp32.platform} -platform_packages = ${esp32.platform_packages} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp32} - -D WLED_RELEASE_NAME=ESP32-WireGuard - -D USERMOD_WIREGUARD -lib_deps = ${esp32.lib_deps} - https://github.com/kienvu58/WireGuard-ESP32-Arduino.git -monitor_filters = esp32_exception_decoder -board_build.partitions = ${esp32.default_partitions} -upload_speed = 921600 \ No newline at end of file From 3521732597fb838d5fda5d696c9225a415c991f0 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sun, 12 Jan 2025 00:22:22 +0000 Subject: [PATCH 143/463] fix env:userods --- usermods/platformio_override.usermods.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usermods/platformio_override.usermods.ini b/usermods/platformio_override.usermods.ini index 0035ac59..3b3e6696 100644 --- a/usermods/platformio_override.usermods.ini +++ b/usermods/platformio_override.usermods.ini @@ -6,4 +6,4 @@ build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"USERMODS\" ${esp32.AR_build_flags} lib_deps = ${esp32.lib_deps} -board_build.partitions = ${esp32.big_partitions} \ No newline at end of file +board_build.partitions = ${esp32.big_partitions} From 52b784e0e50c316acb6fdcafb53ec41283386af6 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sun, 12 Jan 2025 00:22:22 +0000 Subject: [PATCH 144/463] fix env:usermods --- usermods/platformio_override.usermods.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usermods/platformio_override.usermods.ini b/usermods/platformio_override.usermods.ini index 0035ac59..3b3e6696 100644 --- a/usermods/platformio_override.usermods.ini +++ b/usermods/platformio_override.usermods.ini @@ -6,4 +6,4 @@ build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"USERMODS\" ${esp32.AR_build_flags} lib_deps = ${esp32.lib_deps} -board_build.partitions = ${esp32.big_partitions} \ No newline at end of file +board_build.partitions = ${esp32.big_partitions} From 52bee88ad2d3c690f57c25140dbf082a6d13745e Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sun, 12 Jan 2025 00:36:08 +0000 Subject: [PATCH 145/463] fix word_clock_matrix naming --- usermods/word-clock-matrix/word-clock-matrix.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/usermods/word-clock-matrix/word-clock-matrix.cpp b/usermods/word-clock-matrix/word-clock-matrix.cpp index c8606003..6643d293 100644 --- a/usermods/word-clock-matrix/word-clock-matrix.cpp +++ b/usermods/word-clock-matrix/word-clock-matrix.cpp @@ -338,5 +338,5 @@ public: }; -static WordClockMatrix word-clock-matrix; -REGISTER_USERMOD(word-clock-matrix); \ No newline at end of file +static WordClockMatrix word_clock_matrix; +REGISTER_USERMOD(word_clock_matrix); \ No newline at end of file From 075fd4da2d9ddc71f6a755a5a2edddad25fbc4d2 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sun, 12 Jan 2025 01:38:48 +0000 Subject: [PATCH 146/463] Defining more usermod dependencies --- usermods/DHT/library.json | 5 +++- usermods/INA226_v2/library.json | 5 +++- usermods/MAX17048_v2/library.json | 5 +++- usermods/ST7789_display/README.md | 13 ---------- usermods/VL53L0X_gestures/library.json | 5 +++- usermods/VL53L0X_gestures/readme.md | 16 ------------- usermods/mpu6050_imu/library.json | 5 +++- usermods/quinled-an-penta/library.json | 6 ++++- .../quinled-an-penta/quinled-an-penta.cpp | 4 ++-- usermods/quinled-an-penta/readme.md | 23 ------------------ usermods/rgb-rotary-encoder/library.json | 5 +++- usermods/rgb-rotary-encoder/readme.md | 24 ------------------- .../rgb-rotary-encoder/rgb-rotary-encoder.cpp | 4 ++-- 13 files changed, 33 insertions(+), 87 deletions(-) diff --git a/usermods/DHT/library.json b/usermods/DHT/library.json index bb677361..ec7158d2 100644 --- a/usermods/DHT/library.json +++ b/usermods/DHT/library.json @@ -5,5 +5,8 @@ "includeDir": "../../wled00", "libLDFMode": "chain+", "libArchive": false + }, + "dependencies": { + "DHT_nonblocking":"https://github.com/alwynallan/DHT_nonblocking" } -} \ No newline at end of file +} diff --git a/usermods/INA226_v2/library.json b/usermods/INA226_v2/library.json index 2596b86a..be6987e2 100644 --- a/usermods/INA226_v2/library.json +++ b/usermods/INA226_v2/library.json @@ -5,5 +5,8 @@ "includeDir": "../../wled00", "libLDFMode": "chain+", "libArchive": false + }, + "dependencies": { + "wollewald/INA226_WE":"~1.2.9" } -} \ No newline at end of file +} diff --git a/usermods/MAX17048_v2/library.json b/usermods/MAX17048_v2/library.json index 72ac0e61..f85b33cf 100644 --- a/usermods/MAX17048_v2/library.json +++ b/usermods/MAX17048_v2/library.json @@ -5,5 +5,8 @@ "includeDir": "../../wled00", "libLDFMode": "chain+", "libArchive": false + }, + "dependencies": { + "Adafruit_MAX1704X":"https://github.com/adafruit/Adafruit_MAX1704X#1.0.2" } -} \ No newline at end of file +} diff --git a/usermods/ST7789_display/README.md b/usermods/ST7789_display/README.md index ebaae492..7dd3b599 100644 --- a/usermods/ST7789_display/README.md +++ b/usermods/ST7789_display/README.md @@ -27,19 +27,6 @@ This usermod enables display of the following: ### Platformio.ini changes -In the `platformio.ini` file, uncomment the `TFT_eSPI` line within the [common] section, under `lib_deps`: - -```ini -# platformio.ini -... -[common] -... -lib_deps = - ... - #For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line - #TFT_eSPI -... -``` In the `platformio.ini` file, you must change the environment setup to build for just the esp32dev platform as follows: diff --git a/usermods/VL53L0X_gestures/library.json b/usermods/VL53L0X_gestures/library.json index 77521d6f..6dfe4c4d 100644 --- a/usermods/VL53L0X_gestures/library.json +++ b/usermods/VL53L0X_gestures/library.json @@ -5,5 +5,8 @@ "includeDir": "../../wled00", "libLDFMode": "chain+", "libArchive": false + }, + "dependencies": { + "pololu/VL53L0X" : "^1.3.0" } -} \ No newline at end of file +} diff --git a/usermods/VL53L0X_gestures/readme.md b/usermods/VL53L0X_gestures/readme.md index a230b1a6..04c4a4aa 100644 --- a/usermods/VL53L0X_gestures/readme.md +++ b/usermods/VL53L0X_gestures/readme.md @@ -10,20 +10,4 @@ Useful for controlling strips when you want to avoid touching anything. 1. Attach VL53L0X sensor to i2c pins according to default pins for your board. 2. Add `-D USERMOD_VL53L0X_GESTURES` to your build flags at platformio.ini (plaformio_override.ini) for needed environment. -In my case, for example: `build_flags = ${env.build_flags} -D USERMOD_VL53L0X_GESTURES` -3. Add "pololu/VL53L0X" dependency below to `lib_deps` like this: -```ini -lib_deps = ${env.lib_deps} - pololu/VL53L0X @ ^1.3.0 -``` -My entire `platformio_override.ini` for example (for nodemcu board): -```ini -[platformio] -default_envs = nodemcuv2 - -[env:nodemcuv2] -build_flags = ${env.build_flags} -D USERMOD_VL53L0X_GESTURES -lib_deps = ${env.lib_deps} - pololu/VL53L0X @ ^1.3.0 -``` diff --git a/usermods/mpu6050_imu/library.json b/usermods/mpu6050_imu/library.json index bf86aed6..68db4d2f 100644 --- a/usermods/mpu6050_imu/library.json +++ b/usermods/mpu6050_imu/library.json @@ -5,5 +5,8 @@ "includeDir": "../../wled00", "libLDFMode": "chain+", "libArchive": false + }, + "dependencies": { + "electroniccats/MPU6050":"1.0.1" } -} \ No newline at end of file +} diff --git a/usermods/quinled-an-penta/library.json b/usermods/quinled-an-penta/library.json index 274020d9..2fe3e11a 100644 --- a/usermods/quinled-an-penta/library.json +++ b/usermods/quinled-an-penta/library.json @@ -5,5 +5,9 @@ "includeDir": "../../wled00", "libLDFMode": "chain+", "libArchive": false + }, + "dependencies": { + "olikraus/U8g2":"~2.28.8", + "robtillaart/SHT85":"~0.3.3" } -} \ No newline at end of file +} diff --git a/usermods/quinled-an-penta/quinled-an-penta.cpp b/usermods/quinled-an-penta/quinled-an-penta.cpp index 612ade03..1fbfd807 100644 --- a/usermods/quinled-an-penta/quinled-an-penta.cpp +++ b/usermods/quinled-an-penta/quinled-an-penta.cpp @@ -754,5 +754,5 @@ const unsigned char QuinLEDAnPentaUsermod::quinLedLogo[] PROGMEM = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }; -static QuinLEDAnPentaUsermod quinled-an-penta; -REGISTER_USERMOD(quinled-an-penta); \ No newline at end of file +static QuinLEDAnPentaUsermod quinled_an_penta; +REGISTER_USERMOD(quinled_an_penta); \ No newline at end of file diff --git a/usermods/quinled-an-penta/readme.md b/usermods/quinled-an-penta/readme.md index c1260d91..db1f72c4 100644 --- a/usermods/quinled-an-penta/readme.md +++ b/usermods/quinled-an-penta/readme.md @@ -5,29 +5,6 @@ The (un)official usermod to get the best out of the QuinLED-An-Penta (https://qu * "u8g2" by olikraus, v2.28 or higher: https://github.com/olikraus/u8g2 * "SHT85" by Rob Tillaart, v0.2 or higher: https://github.com/RobTillaart/SHT85 -## Usermod installation -Simply copy the below block (build task) to your `platformio_override.ini` and compile WLED using this new build task. Or use an existing one, add the buildflag `-D QUINLED_AN_PENTA` and the below library dependencies. - -ESP32 (**without** ethernet): -``` -[env:custom_esp32dev_usermod_quinled_an_penta] -extends = env:esp32dev -build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32 -D QUINLED_AN_PENTA -lib_deps = ${esp32.lib_deps} - olikraus/U8g2@~2.28.8 - robtillaart/SHT85@~0.2.0 -``` - -ESP32 (**with** ethernet): -``` -[env:custom_esp32dev_usermod_quinled_an_penta] -extends = env:esp32dev -build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_Ethernet -D WLED_USE_ETHERNET -D QUINLED_AN_PENTA -lib_deps = ${esp32.lib_deps} - olikraus/U8g2@~2.28.8 - robtillaart/SHT85@~0.2.0 -``` - ## Some words about the (optional) OLED This mod has been optimized for an SSD1306 driven 128x64 OLED. Using a smaller OLED or an OLED using a different driver will result in unexpected results. I highly recommend using these "two color monochromatic OLEDs", which have the first 16 pixels in a different color than the other 48, e.g. a yellow/blue OLED. diff --git a/usermods/rgb-rotary-encoder/library.json b/usermods/rgb-rotary-encoder/library.json index c23606c0..dd6169a3 100644 --- a/usermods/rgb-rotary-encoder/library.json +++ b/usermods/rgb-rotary-encoder/library.json @@ -5,5 +5,8 @@ "includeDir": "../../wled00", "libLDFMode": "chain+", "libArchive": false + }, + "dependencies": { + "lennarthennigs/ESP Rotary":"^2.1.1" } -} \ No newline at end of file +} diff --git a/usermods/rgb-rotary-encoder/readme.md b/usermods/rgb-rotary-encoder/readme.md index 65317917..abd8a812 100644 --- a/usermods/rgb-rotary-encoder/readme.md +++ b/usermods/rgb-rotary-encoder/readme.md @@ -8,30 +8,6 @@ https://user-images.githubusercontent.com/3090131/124680599-0180ab80-dec7-11eb-9 The actual / original code that controls the LED modes is from Adam Zeloof. I take no credit for it. I ported it to WLED, which involved replacing the LED library he used, (because WLED already has one, so no need to add another one) plus the rotary encoder library because it was not compatible with ESP, only Arduino. It was quite a bit more work than I hoped, but I got there eventually :) -## Requirements -* "ESP Rotary" by Lennart Hennigs, v2.1.1 or higher: https://github.com/LennartHennigs/ESPRotary - -## Usermod installation -Simply copy the below block (build task) to your `platformio_override.ini` and compile WLED using this new build task. Or use an existing one and add the buildflag `-D RGB_ROTARY_ENCODER`. - -ESP32: -``` -[env:custom_esp32dev_usermod_rgb_encoder_board] -extends = env:esp32dev -build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32 -D RGB_ROTARY_ENCODER -lib_deps = ${esp32.lib_deps} - lennarthennigs/ESP Rotary@^2.1.1 -``` - -ESP8266 / D1 Mini: -``` -[env:custom_d1_mini_usermod_rgb_encoder_board] -extends = env:d1_mini -build_flags = ${common.build_flags_esp8266} -D RGB_ROTARY_ENCODER -lib_deps = ${esp8266.lib_deps} - lennarthennigs/ESP Rotary@^2.1.1 -``` - ## How to connect the board to your ESP We'll need (minimum) three or (maximum) four GPIOs for the board: * "ea": reports the encoder direction diff --git a/usermods/rgb-rotary-encoder/rgb-rotary-encoder.cpp b/usermods/rgb-rotary-encoder/rgb-rotary-encoder.cpp index 3e7b96bb..5b4e7315 100644 --- a/usermods/rgb-rotary-encoder/rgb-rotary-encoder.cpp +++ b/usermods/rgb-rotary-encoder/rgb-rotary-encoder.cpp @@ -342,5 +342,5 @@ const char RgbRotaryEncoderUsermod::_ledBrightness[] PROGMEM = "LED-Brightne const char RgbRotaryEncoderUsermod::_stepsPerClick[] PROGMEM = "Steps-per-Click"; const char RgbRotaryEncoderUsermod::_incrementPerClick[] PROGMEM = "Increment-per-Click"; -static RgbRotaryEncoderUsermod rgb-rotary-encoder; -REGISTER_USERMOD(rgb-rotary-encoder); \ No newline at end of file +static RgbRotaryEncoderUsermod rgb_rotary_encoder; +REGISTER_USERMOD(rgb_rotary_encoder); \ No newline at end of file From 8527d231e1624244c68ea78cebc996eee61736e0 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 12 Jan 2025 13:12:12 +0000 Subject: [PATCH 147/463] audioreactive: Move flags to library Use a PlatformIO script to move the last of AR_buildflags in to the module itself. --- usermods/audioreactive/library.json | 31 ++++++++++++------------- usermods/audioreactive/override_sqrt.py | 5 ++++ 2 files changed, 20 insertions(+), 16 deletions(-) create mode 100644 usermods/audioreactive/override_sqrt.py diff --git a/usermods/audioreactive/library.json b/usermods/audioreactive/library.json index 658bf943..2ce60ec6 100644 --- a/usermods/audioreactive/library.json +++ b/usermods/audioreactive/library.json @@ -1,17 +1,16 @@ -{ - "name": "audioreactive", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - }, - "dependencies": [ - { - "owner": "kosme", - "name": "arduinoFFT", - "version": "2.0.1", - "platforms": "espressif32" - } - ] +{ + "name": "audioreactive", + "build": { + "srcDir": ".", + "includeDir": "../../wled00", + "extraScript": "override_sqrt.py" + }, + "dependencies": [ + { + "owner": "kosme", + "name": "arduinoFFT", + "version": "2.0.1", + "platforms": "espressif32" + } + ] } \ No newline at end of file diff --git a/usermods/audioreactive/override_sqrt.py b/usermods/audioreactive/override_sqrt.py new file mode 100644 index 00000000..36aa79df --- /dev/null +++ b/usermods/audioreactive/override_sqrt.py @@ -0,0 +1,5 @@ +Import('env') + +for lb in env.GetLibBuilders(): + if lb.name == "arduinoFFT": + lb.env.Append(CPPDEFINES=[("sqrt_internal", "sqrtf")]) From adead9b578ad1abc8d941fbdc8d94d892767dd9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sun, 12 Jan 2025 15:17:22 +0100 Subject: [PATCH 148/463] Bus wrapper modifications - NeoPixelBus update 2.8.3 - automatic selection of appropriate I2S bus (`X1xxxxxxMethod`) - removed I2S0 on ESP32 (used by AudioReactive) - renumbered internal bus numbers (iType) - added buffer size reporting Bus modifications - WWA strip support - bus initialisation rewrite - optional parallel I2S (ESP32, S2 & S3) --- platformio.ini | 2 +- wled00/FX_fcn.cpp | 47 +++ wled00/bus_manager.cpp | 73 ++-- wled00/bus_manager.h | 104 ++--- wled00/bus_wrapper.h | 719 +++++++++++++++++----------------- wled00/cfg.cpp | 54 +-- wled00/const.h | 14 +- wled00/data/settings_leds.htm | 25 +- wled00/set.cpp | 3 + wled00/wled.cpp | 42 +- wled00/wled.h | 5 +- wled00/xml.cpp | 1 + 12 files changed, 546 insertions(+), 543 deletions(-) diff --git a/platformio.ini b/platformio.ini index 0870cde9..62c8ca51 100644 --- a/platformio.ini +++ b/platformio.ini @@ -138,7 +138,7 @@ lib_compat_mode = strict lib_deps = fastled/FastLED @ 3.6.0 IRremoteESP8266 @ 2.8.2 - makuna/NeoPixelBus @ 2.8.0 + makuna/NeoPixelBus @ 2.8.3 #https://github.com/makuna/NeoPixelBus.git#CoreShaderBeta https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.2.1 # for I2C interface diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index b9a62bb2..589fa67e 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1219,6 +1219,50 @@ void WS2812FX::finalizeInit() { _hasWhiteChannel = _isOffRefreshRequired = false; + #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) + // determine if it is sensible to use parallel I2S outputs on ESP32 (i.e. more than 5 outputs = 1 I2S + 4 RMT) + unsigned digitalCount = 0; + unsigned maxLedsOnBus = 0; + //unsigned maxChannels = 0; + for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { + if (busConfigs[i] == nullptr) break; + if (Bus::isDigital(busConfigs[i]->type) && !Bus::is2Pin(busConfigs[i]->type)) { + digitalCount++; + if (busConfigs[i]->count > maxLedsOnBus) maxLedsOnBus = busConfigs[i]->count; + //unsigned channels = Bus::getNumberOfChannels(busConfigs[i]->type); + //if (channels > maxChannels) maxChannels = channels; + } + } + DEBUG_PRINTF_P(PSTR("Maximum LEDs on a bus: %u\nDigital buses: %u\n"), maxLedsOnBus, digitalCount); + // we may remove 300 LEDs per bus limit when NeoPixelBus is updated beyond 2.9.0 + if (maxLedsOnBus <= 300 && useParallelI2S) BusManager::useParallelOutput(); // must call before creating buses + else useParallelI2S = false; // enforce single I2S + #endif + + // create buses/outputs + unsigned mem = 0; + for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { + if (busConfigs[i] == nullptr) break; + #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) + #if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32S2) + // TODO: once I2S memory is larger than RMT it will ignore RMT + if (BusManager::hasParallelOutput() && i > 3) { // will use RMT and then x8 I2S + unsigned memT = BusManager::memUsage(*busConfigs[i]); // includes x8 memory allocation for parallel I2S + if (memT > mem) mem = memT; // if we have unequal LED count use the largest + } else + #else // classic ESP32 + if (BusManager::hasParallelOutput() && i < 8) { // 1-8 are RMT if using x1 I2S + unsigned memT = BusManager::memUsage(*busConfigs[i]); // includes x8 memory allocation for parallel I2S + if (memT > mem) mem = memT; // if we have unequal LED count use the largest + } else + #endif + #endif + mem += BusManager::memUsage(*busConfigs[i]); // includes global buffer + if (mem <= MAX_LED_MEMORY) BusManager::add(*busConfigs[i]); + delete busConfigs[i]; + busConfigs[i] = nullptr; + } + //if busses failed to load, add default (fresh install, FS issue, ...) if (BusManager::getNumBusses() == 0) { DEBUG_PRINTLN(F("No busses, init default")); @@ -1298,9 +1342,11 @@ void WS2812FX::finalizeInit() { if (Bus::isPWM(dataType) || Bus::isOnOff(dataType)) count = 1; prevLen += count; BusConfig defCfg = BusConfig(dataType, defPin, start, count, DEFAULT_LED_COLOR_ORDER, false, 0, RGBW_MODE_MANUAL_ONLY, 0, useGlobalLedBuffer); + mem += BusManager::memUsage(defCfg); if (BusManager::add(defCfg) == -1) break; } } + DEBUG_PRINTF_P(PSTR("LED buffer size: %uB/%uB\n"), mem, BusManager::getTotalBuffers()); _length = 0; for (int i=0; ibegin(); } + DEBUG_PRINTF_P(PSTR("Heap after buses: %d\n"), ESP.getFreeHeap()); Segment::maxWidth = _length; Segment::maxHeight = 1; diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 2c0ba41a..44b841ac 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -18,10 +18,11 @@ #endif #include "const.h" #include "pin_manager.h" -#include "bus_wrapper.h" #include "bus_manager.h" +#include "bus_wrapper.h" extern bool cctICused; +extern bool useParallelI2S; //colors.cpp uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb); @@ -121,7 +122,7 @@ uint8_t *Bus::allocateData(size_t size) { } -BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) +BusDigital::BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com) : Bus(bc.type, bc.start, bc.autoWhite, bc.count, bc.reversed, (bc.refreshReq || bc.type == TYPE_TM1814)) , _skip(bc.skipAmount) //sacrificial pixels , _colorOrder(bc.colorOrder) @@ -220,7 +221,7 @@ void BusDigital::show() { if (!_valid) return; uint8_t cctWW = 0, cctCW = 0; - unsigned newBri = estimateCurrentAndLimitBri(); // will fill _milliAmpsTotal + unsigned newBri = estimateCurrentAndLimitBri(); // will fill _milliAmpsTotal (TODO: could use PolyBus::CalcTotalMilliAmpere()) if (newBri < _bri) PolyBus::setBrightness(_busPtr, _iType, newBri); // limit brightness to stay within current limits if (_data) { @@ -246,6 +247,7 @@ void BusDigital::show() { // TODO: there is an issue if CCT is calculated from RGB value (_cct==-1), we cannot do that with double buffer Bus::_cct = _data[offset+channels-1]; Bus::calculateCCT(c, cctWW, cctCW); + if (_type == TYPE_WS2812_WWA) c = RGBW32(cctWW, cctCW, 0, W(c)); // may need swapping } unsigned pix = i; if (_reversed) pix = _len - pix -1; @@ -331,8 +333,8 @@ void IRAM_ATTR BusDigital::setPixelColor(unsigned pix, uint32_t c) { uint8_t cctWW = 0, cctCW = 0; Bus::calculateCCT(c, cctWW, cctCW); wwcw = (cctCW<<8) | cctWW; + if (_type == TYPE_WS2812_WWA) c = RGBW32(cctWW, cctCW, 0, W(c)); // may need swapping } - PolyBus::setPixelColor(_busPtr, _iType, pix, c, co, wwcw); } } @@ -364,16 +366,24 @@ uint32_t IRAM_ATTR BusDigital::getPixelColor(unsigned pix) const { case 2: c = RGBW32(b, b, b, b); break; } } + if (_type == TYPE_WS2812_WWA) { + uint8_t w = R(c) | G(c); + c = RGBW32(w, w, 0, w); + } return c; } } -uint8_t BusDigital::getPins(uint8_t* pinArray) const { +unsigned BusDigital::getPins(uint8_t* pinArray) const { unsigned numPins = is2Pin(_type) + 1; if (pinArray) for (unsigned i = 0; i < numPins; i++) pinArray[i] = _pins[i]; return numPins; } +unsigned BusDigital::getBufferSize() const { + return isOk() ? PolyBus::getDataSize(_busPtr, _iType) : 0; +} + void BusDigital::setColorOrder(uint8_t colorOrder) { // upper nibble contains W swap information if ((colorOrder & 0x0F) > 5) return; @@ -397,7 +407,7 @@ std::vector BusDigital::getLEDTypes() { {TYPE_SM16825, "D", PSTR("SM16825 RGBCW")}, {TYPE_WS2812_1CH_X3, "D", PSTR("WS2811 White")}, //{TYPE_WS2812_2CH_X3, "D", PSTR("WS2811 CCT")}, // not implemented - //{TYPE_WS2812_WWA, "D", PSTR("WS2811 WWA")}, // not implemented + {TYPE_WS2812_WWA, "D", PSTR("WS2811 WWA")}, // amber ignored {TYPE_WS2801, "2P", PSTR("WS2801")}, {TYPE_APA102, "2P", PSTR("APA102")}, {TYPE_LPD8806, "2P", PSTR("LPD8806")}, @@ -418,8 +428,9 @@ void BusDigital::cleanup() { _valid = false; _busPtr = nullptr; if (_data != nullptr) freeData(); - PinManager::deallocatePin(_pins[1], PinOwner::BusDigital); - PinManager::deallocatePin(_pins[0], PinOwner::BusDigital); + PinManager::deallocateMultiplePins(_pins, 2, PinOwner::BusDigital); + //PinManager::deallocatePin(_pins[1], PinOwner::BusDigital); + //PinManager::deallocatePin(_pins[0], PinOwner::BusDigital); } @@ -448,7 +459,7 @@ void BusDigital::cleanup() { #endif #endif -BusPwm::BusPwm(BusConfig &bc) +BusPwm::BusPwm(const BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed, bc.refreshReq) // hijack Off refresh flag to indicate usage of dithering { if (!isPWM(bc.type)) return; @@ -610,7 +621,7 @@ void BusPwm::show() { } } -uint8_t BusPwm::getPins(uint8_t* pinArray) const { +unsigned BusPwm::getPins(uint8_t* pinArray) const { if (!_valid) return 0; unsigned numPins = numPWMPins(_type); if (pinArray) for (unsigned i = 0; i < numPins; i++) pinArray[i] = _pins[i]; @@ -646,7 +657,7 @@ void BusPwm::deallocatePins() { } -BusOnOff::BusOnOff(BusConfig &bc) +BusOnOff::BusOnOff(const BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed) , _onoffdata(0) { @@ -686,7 +697,7 @@ void BusOnOff::show() { digitalWrite(_pin, _reversed ? !(bool)_data[0] : (bool)_data[0]); } -uint8_t BusOnOff::getPins(uint8_t* pinArray) const { +unsigned BusOnOff::getPins(uint8_t* pinArray) const { if (!_valid) return 0; if (pinArray) pinArray[0] = _pin; return 1; @@ -699,7 +710,7 @@ std::vector BusOnOff::getLEDTypes() { }; } -BusNetwork::BusNetwork(BusConfig &bc) +BusNetwork::BusNetwork(const BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite, bc.count) , _broadcastLock(false) { @@ -750,7 +761,7 @@ void BusNetwork::show() { _broadcastLock = false; } -uint8_t BusNetwork::getPins(uint8_t* pinArray) const { +unsigned BusNetwork::getPins(uint8_t* pinArray) const { if (pinArray) for (unsigned i = 0; i < 4; i++) pinArray[i] = _client[i]; return 4; } @@ -778,7 +789,7 @@ void BusNetwork::cleanup() { //utility to get the approx. memory usage of a given BusConfig -uint32_t BusManager::memUsage(BusConfig &bc) { +uint32_t BusManager::memUsage(const BusConfig &bc) { if (Bus::isOnOff(bc.type) || Bus::isPWM(bc.type)) return OUTPUT_MAX_PINS; unsigned len = bc.count + bc.skipAmount; @@ -791,19 +802,23 @@ uint32_t BusManager::memUsage(BusConfig &bc) { multiplier = 5; } #else //ESP32 RMT uses double buffer, parallel I2S uses 8x buffer (3 times) - multiplier = PolyBus::isParallelI2S1Output() ? 24 : 2; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + multiplier = useParallelI2S ? 24 : 2; + #else + multiplier = 2; + #endif #endif } return (len * multiplier + bc.doubleBuffer * (bc.count + bc.skipAmount)) * channels; } -uint32_t BusManager::memUsage(unsigned maxChannels, unsigned maxCount, unsigned minBuses) { - //ESP32 RMT uses double buffer, parallel I2S uses 8x buffer (3 times) - unsigned multiplier = PolyBus::isParallelI2S1Output() ? 3 : 2; - return (maxChannels * maxCount * minBuses * multiplier); +unsigned BusManager::getTotalBuffers() { + unsigned size = 0; + for (unsigned i=0; igetBufferSize(); + return size; } -int BusManager::add(BusConfig &bc) { +int BusManager::add(const BusConfig &bc) { if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1; if (Bus::isVirtual(bc.type)) { busses[numBusses] = new BusNetwork(bc); @@ -843,10 +858,13 @@ String BusManager::getLEDTypesJSONString() { } void BusManager::useParallelOutput() { - _parallelOutputs = 8; // hardcoded since we use NPB I2S x8 methods PolyBus::setParallelI2S1Output(); } +bool BusManager::hasParallelOutput() { + return PolyBus::isParallelI2S1Output(); +} + //do not call this method from system context (network callback) void BusManager::removeAll() { DEBUG_PRINTLN(F("Removing all.")); @@ -854,7 +872,6 @@ void BusManager::removeAll() { while (!canAllShow()) yield(); for (unsigned i = 0; i < numBusses; i++) delete busses[i]; numBusses = 0; - _parallelOutputs = 1; PolyBus::setParallelI2S1Output(false); } @@ -876,9 +893,10 @@ void BusManager::esp32RMTInvertIdle() { if (u > 3) return; rmt = u; #else - if (u < _parallelOutputs) continue; - if (u >= _parallelOutputs + 8) return; // only 8 RMT channels - rmt = u - _parallelOutputs; + unsigned numI2S = 1 + PolyBus::isParallelI2S1Output()*7; + if (u < numI2S) continue; + if (u >= numI2S + 8) return; // only 8 RMT channels + rmt = u - numI2S; #endif if (busses[u]->getLength()==0 || !busses[u]->isDigital() || busses[u]->is2Pin()) continue; //assumes that bus number to rmt channel mapping stays 1:1 @@ -994,7 +1012,7 @@ uint16_t BusManager::getTotalLength() { return len; } -bool PolyBus::useParallelI2S = false; +bool PolyBus::_useParallelI2S = false; // Bus static member definition int16_t Bus::_cct = -1; @@ -1008,4 +1026,3 @@ Bus* BusManager::busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES]; ColorOrderMap BusManager::colorOrderMap = {}; uint16_t BusManager::_milliAmpsUsed = 0; uint16_t BusManager::_milliAmpsMax = ABL_MILLIAMPS_DEFAULT; -uint8_t BusManager::_parallelOutputs = 1; diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index d90a6615..5f582971 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -82,46 +82,47 @@ class Bus { virtual void begin() {}; virtual void show() = 0; - virtual bool canShow() const { return true; } - virtual void setStatusPixel(uint32_t c) {} + virtual bool canShow() const { return true; } + virtual void setStatusPixel(uint32_t c) {} virtual void setPixelColor(unsigned pix, uint32_t c) = 0; - virtual void setBrightness(uint8_t b) { _bri = b; }; - virtual void setColorOrder(uint8_t co) {} - virtual uint32_t getPixelColor(unsigned pix) const { return 0; } - virtual uint8_t getPins(uint8_t* pinArray = nullptr) const { return 0; } - virtual uint16_t getLength() const { return isOk() ? _len : 0; } - virtual uint8_t getColorOrder() const { return COL_ORDER_RGB; } - virtual uint8_t skippedLeds() const { return 0; } - virtual uint16_t getFrequency() const { return 0U; } - virtual uint16_t getLEDCurrent() const { return 0; } - virtual uint16_t getUsedCurrent() const { return 0; } - virtual uint16_t getMaxCurrent() const { return 0; } + virtual void setBrightness(uint8_t b) { _bri = b; }; + virtual void setColorOrder(uint8_t co) {} + virtual uint32_t getPixelColor(unsigned pix) const { return 0; } + virtual unsigned getPins(uint8_t* pinArray = nullptr) const { return 0; } + virtual uint16_t getLength() const { return isOk() ? _len : 0; } + virtual uint8_t getColorOrder() const { return COL_ORDER_RGB; } + virtual unsigned skippedLeds() const { return 0; } + virtual uint16_t getFrequency() const { return 0U; } + virtual uint16_t getLEDCurrent() const { return 0; } + virtual uint16_t getUsedCurrent() const { return 0; } + virtual uint16_t getMaxCurrent() const { return 0; } + virtual unsigned getBufferSize() const { return 1; } - inline bool hasRGB() const { return _hasRgb; } - inline bool hasWhite() const { return _hasWhite; } - inline bool hasCCT() const { return _hasCCT; } - inline bool isDigital() const { return isDigital(_type); } - inline bool is2Pin() const { return is2Pin(_type); } - inline bool isOnOff() const { return isOnOff(_type); } - inline bool isPWM() const { return isPWM(_type); } - inline bool isVirtual() const { return isVirtual(_type); } - inline bool is16bit() const { return is16bit(_type); } - inline bool mustRefresh() const { return mustRefresh(_type); } - inline void setReversed(bool reversed) { _reversed = reversed; } - inline void setStart(uint16_t start) { _start = start; } - inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; } - inline uint8_t getAutoWhiteMode() const { return _autoWhiteMode; } - inline uint32_t getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); } - inline uint16_t getStart() const { return _start; } - inline uint8_t getType() const { return _type; } - inline bool isOk() const { return _valid; } - inline bool isReversed() const { return _reversed; } - inline bool isOffRefreshRequired() const { return _needsRefresh; } - inline bool containsPixel(uint16_t pix) const { return pix >= _start && pix < _start + _len; } + inline bool hasRGB() const { return _hasRgb; } + inline bool hasWhite() const { return _hasWhite; } + inline bool hasCCT() const { return _hasCCT; } + inline bool isDigital() const { return isDigital(_type); } + inline bool is2Pin() const { return is2Pin(_type); } + inline bool isOnOff() const { return isOnOff(_type); } + inline bool isPWM() const { return isPWM(_type); } + inline bool isVirtual() const { return isVirtual(_type); } + inline bool is16bit() const { return is16bit(_type); } + inline bool mustRefresh() const { return mustRefresh(_type); } + inline void setReversed(bool reversed) { _reversed = reversed; } + inline void setStart(uint16_t start) { _start = start; } + inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; } + inline uint8_t getAutoWhiteMode() const { return _autoWhiteMode; } + inline unsigned getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); } + inline uint16_t getStart() const { return _start; } + inline uint8_t getType() const { return _type; } + inline bool isOk() const { return _valid; } + inline bool isReversed() const { return _reversed; } + inline bool isOffRefreshRequired() const { return _needsRefresh; } + inline bool containsPixel(uint16_t pix) const { return pix >= _start && pix < _start + _len; } - static inline std::vector getLEDTypes() { return {{TYPE_NONE, "", PSTR("None")}}; } // not used. just for reference for derived classes - static constexpr uint32_t getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK - static constexpr uint32_t getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); } + static inline std::vector getLEDTypes() { return {{TYPE_NONE, "", PSTR("None")}}; } // not used. just for reference for derived classes + static constexpr uint8_t getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK + static constexpr uint8_t getNumberOfChannels(uint8_t type) { return (type == TYPE_WS2812_WWA) ? 3 : hasWhite(type) + 3*hasRGB(type) + hasCCT(type); } static constexpr bool hasRGB(uint8_t type) { return !((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_ANALOG_1CH || type == TYPE_ANALOG_2CH || type == TYPE_ONOFF); } @@ -198,7 +199,7 @@ class Bus { class BusDigital : public Bus { public: - BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com); + BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com); ~BusDigital() { cleanup(); } void show() override; @@ -209,12 +210,13 @@ class BusDigital : public Bus { void setColorOrder(uint8_t colorOrder) override; [[gnu::hot]] uint32_t getPixelColor(unsigned pix) const override; uint8_t getColorOrder() const override { return _colorOrder; } - uint8_t getPins(uint8_t* pinArray = nullptr) const override; - uint8_t skippedLeds() const override { return _skip; } + unsigned getPins(uint8_t* pinArray = nullptr) const override; + unsigned skippedLeds() const override { return _skip; } uint16_t getFrequency() const override { return _frequencykHz; } uint16_t getLEDCurrent() const override { return _milliAmpsPerLed; } uint16_t getUsedCurrent() const override { return _milliAmpsTotal; } uint16_t getMaxCurrent() const override { return _milliAmpsMax; } + unsigned getBufferSize() const override; void begin() override; void cleanup(); @@ -250,13 +252,14 @@ class BusDigital : public Bus { class BusPwm : public Bus { public: - BusPwm(BusConfig &bc); + BusPwm(const BusConfig &bc); ~BusPwm() { cleanup(); } void setPixelColor(unsigned pix, uint32_t c) override; uint32_t getPixelColor(unsigned pix) const override; //does no index check - uint8_t getPins(uint8_t* pinArray = nullptr) const override; + unsigned getPins(uint8_t* pinArray = nullptr) const override; uint16_t getFrequency() const override { return _frequency; } + unsigned getBufferSize() const override { return OUTPUT_MAX_PINS; } void show() override; void cleanup() { deallocatePins(); } @@ -277,12 +280,12 @@ class BusPwm : public Bus { class BusOnOff : public Bus { public: - BusOnOff(BusConfig &bc); + BusOnOff(const BusConfig &bc); ~BusOnOff() { cleanup(); } void setPixelColor(unsigned pix, uint32_t c) override; uint32_t getPixelColor(unsigned pix) const override; - uint8_t getPins(uint8_t* pinArray) const override; + unsigned getPins(uint8_t* pinArray) const override; void show() override; void cleanup() { PinManager::deallocatePin(_pin, PinOwner::BusOnOff); } @@ -296,13 +299,14 @@ class BusOnOff : public Bus { class BusNetwork : public Bus { public: - BusNetwork(BusConfig &bc); + BusNetwork(const BusConfig &bc); ~BusNetwork() { cleanup(); } bool canShow() const override { return !_broadcastLock; } // this should be a return value from UDP routine if it is still sending data out void setPixelColor(unsigned pix, uint32_t c) override; uint32_t getPixelColor(unsigned pix) const override; - uint8_t getPins(uint8_t* pinArray = nullptr) const override; + unsigned getPins(uint8_t* pinArray = nullptr) const override; + unsigned getBufferSize() const override { return isOk() ? _len * _UDPchannels : 0; } void show() override; void cleanup(); @@ -379,13 +383,14 @@ class BusManager { BusManager() {}; //utility to get the approx. memory usage of a given BusConfig - static uint32_t memUsage(BusConfig &bc); - static uint32_t memUsage(unsigned channels, unsigned count, unsigned buses = 1); + static uint32_t memUsage(const BusConfig &bc); + static unsigned getTotalBuffers(); static uint16_t currentMilliamps() { return _milliAmpsUsed + MA_FOR_ESP; } static uint16_t ablMilliampsMax() { return _milliAmpsMax; } - static int add(BusConfig &bc); + static int add(const BusConfig &bc); static void useParallelOutput(); // workaround for inaccessible PolyBus + static bool hasParallelOutput(); // workaround for inaccessible PolyBus //do not call this method from system context (network callback) static void removeAll(); @@ -420,7 +425,6 @@ class BusManager { static ColorOrderMap colorOrderMap; static uint16_t _milliAmpsUsed; static uint16_t _milliAmpsMax; - static uint8_t _parallelOutputs; #ifdef ESP32_DATA_IDLE_HIGH static void esp32RMTInvertIdle() ; diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index d2a18c9d..943a0b81 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -1,23 +1,8 @@ #ifndef BusWrapper_h #define BusWrapper_h +//#define NPB_CONF_4STEP_CADENCE #include "NeoPixelBusLg.h" -#include "bus_manager.h" - -// temporary - these defines should actually be set in platformio.ini -// C3: I2S0 and I2S1 methods not supported (has one I2S bus) -// S2: I2S1 methods not supported (has one I2S bus) -// S3: I2S0 and I2S1 methods not supported yet (has two I2S buses) -// https://github.com/Makuna/NeoPixelBus/blob/b32f719e95ef3c35c46da5c99538017ef925c026/src/internal/Esp32_i2s.h#L4 -// https://github.com/Makuna/NeoPixelBus/blob/b32f719e95ef3c35c46da5c99538017ef925c026/src/internal/NeoEsp32RmtMethod.h#L857 - -#if !defined(WLED_NO_I2S0_PIXELBUS) && (defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3)) -#define WLED_NO_I2S0_PIXELBUS -#endif -#if !defined(WLED_NO_I2S1_PIXELBUS) && (defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2)) -#define WLED_NO_I2S1_PIXELBUS -#endif -// temporary end //Hardware SPI Pins #define P_8266_HS_MOSI 13 @@ -55,110 +40,98 @@ #define I_8266_DM_TM2_3 19 #define I_8266_BB_TM2_3 20 //UCS8903 (RGB) -#define I_8266_U0_UCS_3 49 -#define I_8266_U1_UCS_3 50 -#define I_8266_DM_UCS_3 51 -#define I_8266_BB_UCS_3 52 +#define I_8266_U0_UCS_3 21 +#define I_8266_U1_UCS_3 22 +#define I_8266_DM_UCS_3 23 +#define I_8266_BB_UCS_3 24 //UCS8904 (RGBW) -#define I_8266_U0_UCS_4 53 -#define I_8266_U1_UCS_4 54 -#define I_8266_DM_UCS_4 55 -#define I_8266_BB_UCS_4 56 +#define I_8266_U0_UCS_4 25 +#define I_8266_U1_UCS_4 26 +#define I_8266_DM_UCS_4 27 +#define I_8266_BB_UCS_4 28 //FW1906 GRBCW -#define I_8266_U0_FW6_5 66 -#define I_8266_U1_FW6_5 67 -#define I_8266_DM_FW6_5 68 -#define I_8266_BB_FW6_5 69 +#define I_8266_U0_FW6_5 29 +#define I_8266_U1_FW6_5 30 +#define I_8266_DM_FW6_5 31 +#define I_8266_BB_FW6_5 32 //ESP8266 APA106 -#define I_8266_U0_APA106_3 81 -#define I_8266_U1_APA106_3 82 -#define I_8266_DM_APA106_3 83 -#define I_8266_BB_APA106_3 84 +#define I_8266_U0_APA106_3 33 +#define I_8266_U1_APA106_3 34 +#define I_8266_DM_APA106_3 35 +#define I_8266_BB_APA106_3 36 //WS2805 (RGBCW) -#define I_8266_U0_2805_5 89 -#define I_8266_U1_2805_5 90 -#define I_8266_DM_2805_5 91 -#define I_8266_BB_2805_5 92 +#define I_8266_U0_2805_5 37 +#define I_8266_U1_2805_5 38 +#define I_8266_DM_2805_5 39 +#define I_8266_BB_2805_5 40 //TM1914 (RGB) -#define I_8266_U0_TM1914_3 99 -#define I_8266_U1_TM1914_3 100 -#define I_8266_DM_TM1914_3 101 -#define I_8266_BB_TM1914_3 102 +#define I_8266_U0_TM1914_3 41 +#define I_8266_U1_TM1914_3 42 +#define I_8266_DM_TM1914_3 43 +#define I_8266_BB_TM1914_3 44 //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 +#define I_8266_U0_SM16825_5 45 +#define I_8266_U1_SM16825_5 46 +#define I_8266_DM_SM16825_5 47 +#define I_8266_BB_SM16825_5 48 /*** ESP32 Neopixel methods ***/ //RGB -#define I_32_RN_NEO_3 21 -#define I_32_I0_NEO_3 22 -#define I_32_I1_NEO_3 23 +#define I_32_RN_NEO_3 1 +#define I_32_I2_NEO_3 2 //RGBW -#define I_32_RN_NEO_4 25 -#define I_32_I0_NEO_4 26 -#define I_32_I1_NEO_4 27 +#define I_32_RN_NEO_4 5 +#define I_32_I2_NEO_4 6 //400Kbps -#define I_32_RN_400_3 29 -#define I_32_I0_400_3 30 -#define I_32_I1_400_3 31 +#define I_32_RN_400_3 9 +#define I_32_I2_400_3 10 //TM1814 (RGBW) -#define I_32_RN_TM1_4 33 -#define I_32_I0_TM1_4 34 -#define I_32_I1_TM1_4 35 +#define I_32_RN_TM1_4 13 +#define I_32_I2_TM1_4 14 //TM1829 (RGB) -#define I_32_RN_TM2_3 36 -#define I_32_I0_TM2_3 37 -#define I_32_I1_TM2_3 38 +#define I_32_RN_TM2_3 17 +#define I_32_I2_TM2_3 18 //UCS8903 (RGB) -#define I_32_RN_UCS_3 57 -#define I_32_I0_UCS_3 58 -#define I_32_I1_UCS_3 59 +#define I_32_RN_UCS_3 21 +#define I_32_I2_UCS_3 22 //UCS8904 (RGBW) -#define I_32_RN_UCS_4 60 -#define I_32_I0_UCS_4 61 -#define I_32_I1_UCS_4 62 +#define I_32_RN_UCS_4 25 +#define I_32_I2_UCS_4 26 //FW1906 GRBCW -#define I_32_RN_FW6_5 63 -#define I_32_I0_FW6_5 64 -#define I_32_I1_FW6_5 65 +#define I_32_RN_FW6_5 29 +#define I_32_I2_FW6_5 30 //APA106 -#define I_32_RN_APA106_3 85 -#define I_32_I0_APA106_3 86 -#define I_32_I1_APA106_3 87 +#define I_32_RN_APA106_3 33 +#define I_32_I2_APA106_3 34 //WS2805 (RGBCW) -#define I_32_RN_2805_5 93 -#define I_32_I0_2805_5 94 -#define I_32_I1_2805_5 95 +#define I_32_RN_2805_5 37 +#define I_32_I2_2805_5 38 //TM1914 (RGB) -#define I_32_RN_TM1914_3 96 -#define I_32_I0_TM1914_3 97 -#define I_32_I1_TM1914_3 98 +#define I_32_RN_TM1914_3 41 +#define I_32_I2_TM1914_3 42 //SM16825 (RGBCW) -#define I_32_RN_SM16825_5 107 -#define I_32_I0_SM16825_5 108 -#define I_32_I1_SM16825_5 109 +#define I_32_RN_SM16825_5 45 +#define I_32_I2_SM16825_5 46 //APA102 -#define I_HS_DOT_3 39 //hardware SPI -#define I_SS_DOT_3 40 //soft SPI +#define I_HS_DOT_3 101 //hardware SPI +#define I_SS_DOT_3 102 //soft SPI //LPD8806 -#define I_HS_LPD_3 41 -#define I_SS_LPD_3 42 +#define I_HS_LPD_3 103 +#define I_SS_LPD_3 104 //WS2801 -#define I_HS_WS1_3 43 -#define I_SS_WS1_3 44 +#define I_HS_WS1_3 105 +#define I_SS_WS1_3 106 //P9813 -#define I_HS_P98_3 45 -#define I_SS_P98_3 46 +#define I_HS_P98_3 107 +#define I_SS_P98_3 108 //LPD6803 -#define I_HS_LPO_3 47 -#define I_SS_LPO_3 48 +#define I_HS_LPO_3 109 +#define I_SS_LPO_3 110 // In the following NeoGammaNullMethod can be replaced with NeoGammaWLEDMethod to perform Gamma correction implicitly @@ -230,66 +203,95 @@ /*** ESP32 Neopixel methods ***/ #ifdef ARDUINO_ARCH_ESP32 +// C3: I2S0 and I2S1 methods not supported (has one I2S bus) +// S2: I2S0 methods supported (single & parallel), I2S1 methods not supported (has one I2S bus) +// S3: I2S0 methods not supported, I2S1 supports LCD parallel methods (has two I2S buses) +// https://github.com/Makuna/NeoPixelBus/blob/b32f719e95ef3c35c46da5c99538017ef925c026/src/internal/Esp32_i2s.h#L4 +// https://github.com/Makuna/NeoPixelBus/blob/b32f719e95ef3c35c46da5c99538017ef925c026/src/internal/NeoEsp32RmtMethod.h#L857 +#if defined(CONFIG_IDF_TARGET_ESP32S3) + // S3 will always use LCD parallel output + typedef X8Ws2812xMethod X1Ws2812xMethod; + typedef X8Sk6812Method X1Sk6812Method; + typedef X8400KbpsMethod X1400KbpsMethod; + typedef X8800KbpsMethod X1800KbpsMethod; + typedef X8Tm1814Method X1Tm1814Method; + typedef X8Tm1829Method X1Tm1829Method; + typedef X8Apa106Method X1Apa106Method; + typedef X8Ws2805Method X1Ws2805Method; + typedef X8Tm1914Method X1Tm1914Method; +#elif defined(CONFIG_IDF_TARGET_ESP32S2) + // S2 will use I2S0 + typedef NeoEsp32I2s0Ws2812xMethod X1Ws2812xMethod; + typedef NeoEsp32I2s0Sk6812Method X1Sk6812Method; + typedef NeoEsp32I2s0400KbpsMethod X1400KbpsMethod; + typedef NeoEsp32I2s0800KbpsMethod X1800KbpsMethod; + typedef NeoEsp32I2s0Tm1814Method X1Tm1814Method; + typedef NeoEsp32I2s0Tm1829Method X1Tm1829Method; + typedef NeoEsp32I2s0Apa106Method X1Apa106Method; + typedef NeoEsp32I2s0Ws2805Method X1Ws2805Method; + typedef NeoEsp32I2s0Tm1914Method X1Tm1914Method; +#elif !defined(CONFIG_IDF_TARGET_ESP32C3) + // regular ESP32 will use I2S1 + typedef NeoEsp32I2s1Ws2812xMethod X1Ws2812xMethod; + typedef NeoEsp32I2s1Sk6812Method X1Sk6812Method; + typedef NeoEsp32I2s1400KbpsMethod X1400KbpsMethod; + typedef NeoEsp32I2s1800KbpsMethod X1800KbpsMethod; + typedef NeoEsp32I2s1Tm1814Method X1Tm1814Method; + typedef NeoEsp32I2s1Tm1829Method X1Tm1829Method; + typedef NeoEsp32I2s1Apa106Method X1Apa106Method; + typedef NeoEsp32I2s1Ws2805Method X1Ws2805Method; + typedef NeoEsp32I2s1Tm1914Method X1Tm1914Method; +#endif + //RGB -#define B_32_RN_NEO_3 NeoPixelBusLg -#define B_32_I0_NEO_3 NeoPixelBusLg -#define B_32_I1_NEO_3 NeoPixelBusLg -#define B_32_I1_NEO_3P NeoPixelBusLg // parallel I2S +#define B_32_RN_NEO_3 NeoPixelBusLg // ESP32, S2, S3, C3 +//#define B_32_IN_NEO_3 NeoPixelBusLg // ESP32 (dynamic I2S selection) +#define B_32_I2_NEO_3 NeoPixelBusLg // ESP32, S2, S3 (automatic I2S selection, see typedef above) +#define B_32_IP_NEO_3 NeoPixelBusLg // parallel I2S (ESP32, S2, S3) //RGBW #define B_32_RN_NEO_4 NeoPixelBusLg -#define B_32_I0_NEO_4 NeoPixelBusLg -#define B_32_I1_NEO_4 NeoPixelBusLg -#define B_32_I1_NEO_4P NeoPixelBusLg // parallel I2S +#define B_32_I2_NEO_4 NeoPixelBusLg +#define B_32_IP_NEO_4 NeoPixelBusLg // parallel I2S //400Kbps #define B_32_RN_400_3 NeoPixelBusLg -#define B_32_I0_400_3 NeoPixelBusLg -#define B_32_I1_400_3 NeoPixelBusLg -#define B_32_I1_400_3P NeoPixelBusLg // parallel I2S +#define B_32_I2_400_3 NeoPixelBusLg +#define B_32_IP_400_3 NeoPixelBusLg // parallel I2S //TM1814 (RGBW) #define B_32_RN_TM1_4 NeoPixelBusLg -#define B_32_I0_TM1_4 NeoPixelBusLg -#define B_32_I1_TM1_4 NeoPixelBusLg -#define B_32_I1_TM1_4P NeoPixelBusLg // parallel I2S +#define B_32_I2_TM1_4 NeoPixelBusLg +#define B_32_IP_TM1_4 NeoPixelBusLg // parallel I2S //TM1829 (RGB) #define B_32_RN_TM2_3 NeoPixelBusLg -#define B_32_I0_TM2_3 NeoPixelBusLg -#define B_32_I1_TM2_3 NeoPixelBusLg -#define B_32_I1_TM2_3P NeoPixelBusLg // parallel I2S +#define B_32_I2_TM2_3 NeoPixelBusLg +#define B_32_IP_TM2_3 NeoPixelBusLg // parallel I2S //UCS8903 #define B_32_RN_UCS_3 NeoPixelBusLg -#define B_32_I0_UCS_3 NeoPixelBusLg -#define B_32_I1_UCS_3 NeoPixelBusLg -#define B_32_I1_UCS_3P NeoPixelBusLg // parallel I2S +#define B_32_I2_UCS_3 NeoPixelBusLg +#define B_32_IP_UCS_3 NeoPixelBusLg // parallel I2S //UCS8904 #define B_32_RN_UCS_4 NeoPixelBusLg -#define B_32_I0_UCS_4 NeoPixelBusLg -#define B_32_I1_UCS_4 NeoPixelBusLg -#define B_32_I1_UCS_4P NeoPixelBusLg// parallel I2S +#define B_32_I2_UCS_4 NeoPixelBusLg +#define B_32_IP_UCS_4 NeoPixelBusLg// parallel I2S //APA106 #define B_32_RN_APA106_3 NeoPixelBusLg -#define B_32_I0_APA106_3 NeoPixelBusLg -#define B_32_I1_APA106_3 NeoPixelBusLg -#define B_32_I1_APA106_3P NeoPixelBusLg // parallel I2S +#define B_32_I2_APA106_3 NeoPixelBusLg +#define B_32_IP_APA106_3 NeoPixelBusLg // parallel I2S //FW1906 GRBCW #define B_32_RN_FW6_5 NeoPixelBusLg -#define B_32_I0_FW6_5 NeoPixelBusLg -#define B_32_I1_FW6_5 NeoPixelBusLg -#define B_32_I1_FW6_5P NeoPixelBusLg // parallel I2S +#define B_32_I2_FW6_5 NeoPixelBusLg +#define B_32_IP_FW6_5 NeoPixelBusLg // parallel I2S //WS2805 RGBWC #define B_32_RN_2805_5 NeoPixelBusLg -#define B_32_I0_2805_5 NeoPixelBusLg -#define B_32_I1_2805_5 NeoPixelBusLg -#define B_32_I1_2805_5P NeoPixelBusLg // parallel I2S +#define B_32_I2_2805_5 NeoPixelBusLg +#define B_32_IP_2805_5 NeoPixelBusLg // parallel I2S //TM1914 (RGB) #define B_32_RN_TM1914_3 NeoPixelBusLg -#define B_32_I0_TM1914_3 NeoPixelBusLg -#define B_32_I1_TM1914_3 NeoPixelBusLg -#define B_32_I1_TM1914_3P NeoPixelBusLg // parallel I2S +#define B_32_I2_TM1914_3 NeoPixelBusLg +#define B_32_IP_TM1914_3 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_I2_SM16825_5 NeoPixelBusLg +#define B_32_IP_SM16825_5 NeoPixelBusLg // parallel I2S #endif //APA102 @@ -328,11 +330,11 @@ //handles pointer type conversion for all possible bus types class PolyBus { private: - static bool useParallelI2S; + static bool _useParallelI2S; public: - static inline void setParallelI2S1Output(bool b = true) { useParallelI2S = b; } - static inline bool isParallelI2S1Output(void) { return useParallelI2S; } + static inline void setParallelI2S1Output(bool b = true) { _useParallelI2S = b; } + static inline bool isParallelI2S1Output(void) { return _useParallelI2S; } // initialize SPI bus speed for DotStar methods template @@ -436,34 +438,19 @@ class PolyBus { 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; - case I_32_I1_NEO_4: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; - case I_32_I1_400_3: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; - case I_32_I1_TM1_4: if (useParallelI2S) beginTM1814(busPtr); else beginTM1814(busPtr); break; - case I_32_I1_TM2_3: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; - case I_32_I1_UCS_3: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; - case I_32_I1_UCS_4: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; - case I_32_I1_FW6_5: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; - 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 - case I_32_I0_NEO_3: (static_cast(busPtr))->Begin(); break; - case I_32_I0_NEO_4: (static_cast(busPtr))->Begin(); break; - case I_32_I0_400_3: (static_cast(busPtr))->Begin(); break; - case I_32_I0_TM1_4: beginTM1814(busPtr); break; - case I_32_I0_TM2_3: (static_cast(busPtr))->Begin(); break; - case I_32_I0_UCS_3: (static_cast(busPtr))->Begin(); break; - case I_32_I0_UCS_4: (static_cast(busPtr))->Begin(); break; - case I_32_I0_FW6_5: (static_cast(busPtr))->Begin(); break; - 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; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_NEO_4: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_400_3: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_TM1_4: if (_useParallelI2S) beginTM1814(busPtr); else beginTM1814(busPtr); break; + case I_32_I2_TM2_3: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_UCS_3: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_UCS_4: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_FW6_5: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_APA106_3: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_2805_5: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_TM1914_3: if (_useParallelI2S) beginTM1914(busPtr); else beginTM1914(busPtr); break; + case I_32_I2_SM16825_5: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (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; @@ -484,7 +471,7 @@ class PolyBus { #if defined(ARDUINO_ARCH_ESP32) && !(defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3)) // NOTE: "channel" is only used on ESP32 (and its variants) for RMT channel allocation // since 0.15.0-b3 I2S1 is favoured for classic ESP32 and moved to position 0 (channel 0) so we need to subtract 1 for correct RMT allocation - if (useParallelI2S && channel > 7) channel -= 8; // accommodate parallel I2S1 which is used 1st on classic ESP32 + if (_useParallelI2S && channel > 7) channel -= 8; // accommodate parallel I2S1 which is used 1st on classic ESP32 else if (channel > 0) channel--; // accommodate I2S1 which is used as 1st bus on classic ESP32 #endif void* busPtr = nullptr; @@ -555,34 +542,19 @@ class PolyBus { 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; - case I_32_I1_NEO_4: if (useParallelI2S) busPtr = new B_32_I1_NEO_4P(len, pins[0]); else busPtr = new B_32_I1_NEO_4(len, pins[0]); break; - case I_32_I1_400_3: if (useParallelI2S) busPtr = new B_32_I1_400_3P(len, pins[0]); else busPtr = new B_32_I1_400_3(len, pins[0]); break; - case I_32_I1_TM1_4: if (useParallelI2S) busPtr = new B_32_I1_TM1_4P(len, pins[0]); else busPtr = new B_32_I1_TM1_4(len, pins[0]); break; - case I_32_I1_TM2_3: if (useParallelI2S) busPtr = new B_32_I1_TM2_3P(len, pins[0]); else busPtr = new B_32_I1_TM2_3(len, pins[0]); break; - case I_32_I1_UCS_3: if (useParallelI2S) busPtr = new B_32_I1_UCS_3P(len, pins[0]); else busPtr = new B_32_I1_UCS_3(len, pins[0]); break; - case I_32_I1_UCS_4: if (useParallelI2S) busPtr = new B_32_I1_UCS_4P(len, pins[0]); else busPtr = new B_32_I1_UCS_4(len, pins[0]); break; - case I_32_I1_APA106_3: if (useParallelI2S) busPtr = new B_32_I1_APA106_3P(len, pins[0]); else busPtr = new B_32_I1_APA106_3(len, pins[0]); break; - 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 - case I_32_I0_NEO_3: busPtr = new B_32_I0_NEO_3(len, pins[0]); break; - case I_32_I0_NEO_4: busPtr = new B_32_I0_NEO_4(len, pins[0]); break; - case I_32_I0_400_3: busPtr = new B_32_I0_400_3(len, pins[0]); break; - case I_32_I0_TM1_4: busPtr = new B_32_I0_TM1_4(len, pins[0]); break; - case I_32_I0_TM2_3: busPtr = new B_32_I0_TM2_3(len, pins[0]); break; - case I_32_I0_UCS_3: busPtr = new B_32_I0_UCS_3(len, pins[0]); break; - case I_32_I0_UCS_4: busPtr = new B_32_I0_UCS_4(len, pins[0]); break; - case I_32_I0_APA106_3: busPtr = new B_32_I0_APA106_3(len, pins[0]); break; - 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; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: if (_useParallelI2S) busPtr = new B_32_IP_NEO_3(len, pins[0]); else busPtr = new B_32_I2_NEO_3(len, pins[0]); break; + case I_32_I2_NEO_4: if (_useParallelI2S) busPtr = new B_32_IP_NEO_4(len, pins[0]); else busPtr = new B_32_I2_NEO_4(len, pins[0]); break; + case I_32_I2_400_3: if (_useParallelI2S) busPtr = new B_32_IP_400_3(len, pins[0]); else busPtr = new B_32_I2_400_3(len, pins[0]); break; + case I_32_I2_TM1_4: if (_useParallelI2S) busPtr = new B_32_IP_TM1_4(len, pins[0]); else busPtr = new B_32_I2_TM1_4(len, pins[0]); break; + case I_32_I2_TM2_3: if (_useParallelI2S) busPtr = new B_32_IP_TM2_3(len, pins[0]); else busPtr = new B_32_I2_TM2_3(len, pins[0]); break; + case I_32_I2_UCS_3: if (_useParallelI2S) busPtr = new B_32_IP_UCS_3(len, pins[0]); else busPtr = new B_32_I2_UCS_3(len, pins[0]); break; + case I_32_I2_UCS_4: if (_useParallelI2S) busPtr = new B_32_IP_UCS_4(len, pins[0]); else busPtr = new B_32_I2_UCS_4(len, pins[0]); break; + case I_32_I2_APA106_3: if (_useParallelI2S) busPtr = new B_32_IP_APA106_3(len, pins[0]); else busPtr = new B_32_I2_APA106_3(len, pins[0]); break; + case I_32_I2_FW6_5: if (_useParallelI2S) busPtr = new B_32_IP_FW6_5(len, pins[0]); else busPtr = new B_32_I2_FW6_5(len, pins[0]); break; + case I_32_I2_2805_5: if (_useParallelI2S) busPtr = new B_32_IP_2805_5(len, pins[0]); else busPtr = new B_32_I2_2805_5(len, pins[0]); break; + case I_32_I2_TM1914_3: if (_useParallelI2S) busPtr = new B_32_IP_TM1914_3(len, pins[0]); else busPtr = new B_32_I2_TM1914_3(len, pins[0]); break; + case I_32_I2_SM16825_5: if (_useParallelI2S) busPtr = new B_32_IP_SM16825_5(len, pins[0]); else busPtr = new B_32_I2_SM16825_5(len, pins[0]); break; #endif #endif // for 2-wire: pins[1] is clk, pins[0] is dat. begin expects (len, clk, dat) @@ -669,34 +641,19 @@ class PolyBus { 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; - case I_32_I1_NEO_4: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_400_3: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_TM1_4: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_TM2_3: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_UCS_3: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_UCS_4: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_APA106_3: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - 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 - case I_32_I0_NEO_3: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_NEO_4: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_400_3: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_TM1_4: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_TM2_3: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_UCS_3: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_UCS_4: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_APA106_3: (static_cast(busPtr))->Show(consistent); break; - 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; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_NEO_4: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_400_3: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_TM1_4: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_TM2_3: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_UCS_3: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_UCS_4: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_APA106_3: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_FW6_5: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_2805_5: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_TM1914_3: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_SM16825_5: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; #endif #endif case I_HS_DOT_3: (static_cast(busPtr))->Show(consistent); break; @@ -779,34 +736,19 @@ class PolyBus { case I_32_RN_TM1914_3: return (static_cast(busPtr))->CanShow(); break; case I_32_RN_SM16825_5: return (static_cast(busPtr))->CanShow(); break; // I2S1 bus or paralell buses - #ifndef WLED_NO_I2S1_PIXELBUS - case I_32_I1_NEO_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_NEO_4: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_400_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_TM1_4: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_TM2_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_UCS_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_UCS_4: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_APA106_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_FW6_5: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_2805_5: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_TM1914_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_SM16825_5: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - #endif - // I2S0 bus - #ifndef WLED_NO_I2S0_PIXELBUS - case I_32_I0_NEO_3: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_NEO_4: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_400_3: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_TM1_4: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_TM2_3: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_UCS_3: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_UCS_4: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_APA106_3: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_FW6_5: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_2805_5: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_TM1914_3: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_SM16825_5: return (static_cast(busPtr))->CanShow(); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_NEO_4: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_400_3: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_TM1_4: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_TM2_3: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_UCS_3: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_UCS_4: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_APA106_3: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_FW6_5: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_2805_5: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_TM1914_3: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_SM16825_5: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; #endif #endif case I_HS_DOT_3: return (static_cast(busPtr))->CanShow(); break; @@ -916,34 +858,19 @@ class PolyBus { 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; - case I_32_I1_NEO_4: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, col); break; - case I_32_I1_400_3: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - case I_32_I1_TM1_4: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, col); break; - case I_32_I1_TM2_3: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - 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, 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 - case I_32_I0_NEO_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - case I_32_I0_NEO_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; - case I_32_I0_400_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - case I_32_I0_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; - case I_32_I0_TM2_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - case I_32_I0_UCS_3: (static_cast(busPtr))->SetPixelColor(pix, Rgb48Color(RgbColor(col))); break; - case I_32_I0_UCS_4: (static_cast(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break; - case I_32_I0_APA106_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - 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; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_32_I2_NEO_4: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_I2_400_3: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_32_I2_TM1_4: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_I2_TM2_3: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_32_I2_UCS_3: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, Rgb48Color(RgbColor(col))); break; + case I_32_I2_UCS_4: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break; + case I_32_I2_APA106_3: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_32_I2_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_I2_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_I2_TM1914_3: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_32_I2_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 #endif case I_HS_DOT_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; @@ -1027,34 +954,19 @@ class PolyBus { 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; - case I_32_I1_NEO_4: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_400_3: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_TM1_4: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_TM2_3: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_UCS_3: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_UCS_4: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_APA106_3: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - 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 - case I_32_I0_NEO_3: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_NEO_4: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_400_3: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_TM1_4: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_TM2_3: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_UCS_3: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_UCS_4: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_APA106_3: (static_cast(busPtr))->SetLuminance(b); break; - 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; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_NEO_4: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_400_3: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_TM1_4: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_TM2_3: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_UCS_3: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_UCS_4: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_APA106_3: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_FW6_5: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_2805_5: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_TM1914_3: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_SM16825_5: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; #endif #endif case I_HS_DOT_3: (static_cast(busPtr))->SetLuminance(b); break; @@ -1139,34 +1051,19 @@ class PolyBus { 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; - case I_32_I1_NEO_4: col = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; - 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/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 - case I_32_I0_NEO_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; - case I_32_I0_NEO_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; - 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/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 + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: col = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I2_NEO_4: col = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I2_400_3: col = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I2_TM1_4: col = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I2_TM2_3: col = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I2_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_I2_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_I2_APA106_3: col = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I2_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_I2_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_I2_TM1914_3: col = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I2_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 #endif case I_HS_DOT_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; @@ -1269,34 +1166,19 @@ class PolyBus { 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; - case I_32_I1_NEO_4: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_400_3: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_TM1_4: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_TM2_3: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_UCS_3: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_UCS_4: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_APA106_3: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - 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 - case I_32_I0_NEO_3: delete (static_cast(busPtr)); break; - case I_32_I0_NEO_4: delete (static_cast(busPtr)); break; - case I_32_I0_400_3: delete (static_cast(busPtr)); break; - case I_32_I0_TM1_4: delete (static_cast(busPtr)); break; - case I_32_I0_TM2_3: delete (static_cast(busPtr)); break; - case I_32_I0_UCS_3: delete (static_cast(busPtr)); break; - case I_32_I0_UCS_4: delete (static_cast(busPtr)); break; - case I_32_I0_APA106_3: delete (static_cast(busPtr)); break; - 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; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_NEO_4: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_400_3: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_TM1_4: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_TM2_3: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_UCS_3: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_UCS_4: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_APA106_3: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_FW6_5: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_2805_5: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_TM1914_3: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_SM16825_5: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; #endif #endif case I_HS_DOT_3: delete (static_cast(busPtr)); break; @@ -1312,6 +1194,104 @@ class PolyBus { } } + static unsigned getDataSize(void* busPtr, uint8_t busType) { + unsigned size = 0; + switch (busType) { + case I_NONE: break; + #ifdef ESP8266 + case I_8266_U0_NEO_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_NEO_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_NEO_3: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_NEO_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U0_NEO_4: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_NEO_4: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_NEO_4: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_NEO_4: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U0_400_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_400_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_400_3: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_400_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U0_TM1_4: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_TM1_4: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_TM1_4: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_TM1_4: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U0_TM2_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_TM2_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_TM2_3: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_TM2_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U0_UCS_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_UCS_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_UCS_3: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_UCS_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U0_UCS_4: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_UCS_4: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_UCS_4: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_UCS_4: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U0_APA106_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_APA106_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_APA106_3: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_APA106_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U0_FW6_5: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_FW6_5: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_FW6_5: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_FW6_5: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U0_2805_5: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_2805_5: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_2805_5: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_2805_5: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U0_TM1914_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_TM1914_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_TM1914_3: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_TM1914_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U0_SM16825_5: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_U1_SM16825_5: size = (static_cast(busPtr))->PixelsSize(); break; + case I_8266_DM_SM16825_5: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_SM16825_5: size = (static_cast(busPtr))->PixelsSize(); break; + #endif + #ifdef ARDUINO_ARCH_ESP32 + // RMT buses + case I_32_RN_NEO_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_NEO_4: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_400_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_TM1_4: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_TM2_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_UCS_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_UCS_4: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_APA106_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_FW6_5: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_2805_5: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_TM1914_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_SM16825_5: size = (static_cast(busPtr))->PixelsSize()*2; break; + // I2S1 bus or paralell buses + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + case I_32_I2_NEO_4: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + case I_32_I2_400_3: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + case I_32_I2_TM1_4: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + case I_32_I2_TM2_3: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + case I_32_I2_UCS_3: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + case I_32_I2_UCS_4: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + case I_32_I2_APA106_3: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + case I_32_I2_FW6_5: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + case I_32_I2_2805_5: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + case I_32_I2_TM1914_3: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + case I_32_I2_SM16825_5: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*16 : (static_cast(busPtr))->PixelsSize()*8; break; + #endif + #endif + case I_HS_DOT_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_SS_DOT_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_HS_LPD_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_SS_LPD_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_HS_LPO_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_SS_LPO_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_HS_WS1_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_SS_WS1_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_HS_P98_3: size = (static_cast(busPtr))->PixelsSize(); break; + case I_SS_P98_3: size = (static_cast(busPtr))->PixelsSize(); break; + } + return size; + } + //gives back the internal type index (I_XX_XXX_X above) for the input static uint8_t getI(uint8_t busType, uint8_t* pins, uint8_t num = 0) { if (!Bus::isDigital(busType)) return I_NONE; @@ -1372,26 +1352,33 @@ class PolyBus { uint8_t offset = 0; // 0 = RMT (num 1-8), 1 = I2S0 (used by Audioreactive), 2 = I2S1 #if defined(CONFIG_IDF_TARGET_ESP32S2) // ESP32-S2 only has 4 RMT channels - if (num > 4) return I_NONE; - if (num > 3) offset = 1; // only one I2S (use last to allow Audioreactive) + if (_useParallelI2S) { + if (num > 11) return I_NONE; + if (num > 3) offset = 1; // use x8 parallel I2S0 channels (use last to allow Audioreactive) + } else { + if (num > 4) return I_NONE; + if (num > 3) offset = 1; // only one I2S0 (use last to allow Audioreactive) + } #elif defined(CONFIG_IDF_TARGET_ESP32C3) // On ESP32-C3 only the first 2 RMT channels are usable for transmitting if (num > 1) return I_NONE; //if (num > 1) offset = 1; // I2S not supported yet (only 1 I2S) #elif defined(CONFIG_IDF_TARGET_ESP32S3) // On ESP32-S3 only the first 4 RMT channels are usable for transmitting - if (num > 3) return I_NONE; - //if (num > 3) offset = num -4; // I2S not supported yet + if (_useParallelI2S) { + if (num > 11) return I_NONE; + if (num > 3) offset = 1; // use x8 parallel I2S LCD channels + } else { + if (num > 3) return I_NONE; // do not use single I2S (as it is not supported) + } #else - // standard ESP32 has 8 RMT and 2 I2S channels - if (useParallelI2S) { - if (num > 16) return I_NONE; - if (num < 8) offset = 2; // prefer 8 parallel I2S1 channels - if (num == 16) offset = 1; + // standard ESP32 has 8 RMT and x1/x8 I2S1 channels + if (_useParallelI2S) { + if (num > 15) return I_NONE; + if (num < 8) offset = 1; // prefer 8 parallel I2S1 channels } else { if (num > 9) return I_NONE; - if (num > 8) offset = 1; - if (num == 0) offset = 2; // prefer I2S1 for 1st bus (less flickering but more RAM needed) + if (num == 0) offset = 1; // prefer I2S1 for 1st bus (less flickering but more RAM needed) } #endif switch (busType) { diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 38e804ed..e4536156 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -118,6 +118,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { Bus::setCCTBlend(strip.cctBlending); strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS CJSON(useGlobalLedBuffer, hw_led[F("ld")]); + #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) + CJSON(useParallelI2S, hw_led[F("prl")]); + #endif #ifndef WLED_DISABLE_2D // 2D Matrix Settings @@ -162,34 +165,6 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { DEBUG_PRINTF_P(PSTR("Heap before buses: %d\n"), ESP.getFreeHeap()); int s = 0; // bus iterator if (fromFS) BusManager::removeAll(); // can't safely manipulate busses directly in network callback - unsigned mem = 0; - - // determine if it is sensible to use parallel I2S outputs on ESP32 (i.e. more than 5 outputs = 1 I2S + 4 RMT) - bool useParallel = false; - #if defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ARCH_ESP32S2) && !defined(ARDUINO_ARCH_ESP32S3) && !defined(ARDUINO_ARCH_ESP32C3) - unsigned digitalCount = 0; - unsigned maxLedsOnBus = 0; - unsigned maxChannels = 0; - for (JsonObject elm : ins) { - unsigned type = elm["type"] | TYPE_WS2812_RGB; - unsigned len = elm["len"] | DEFAULT_LED_COUNT; - if (!Bus::isDigital(type)) continue; - if (!Bus::is2Pin(type)) { - digitalCount++; - unsigned channels = Bus::getNumberOfChannels(type); - if (len > maxLedsOnBus) maxLedsOnBus = len; - if (channels > maxChannels) maxChannels = channels; - } - } - DEBUG_PRINTF_P(PSTR("Maximum LEDs on a bus: %u\nDigital buses: %u\n"), maxLedsOnBus, digitalCount); - // we may remove 300 LEDs per bus limit when NeoPixelBus is updated beyond 2.9.0 - if (maxLedsOnBus <= 300 && digitalCount > 5) { - DEBUG_PRINTLN(F("Switching to parallel I2S.")); - useParallel = true; - BusManager::useParallelOutput(); - mem = BusManager::memUsage(maxChannels, maxLedsOnBus, 8); // use alternate memory calculation - } - #endif for (JsonObject elm : ins) { if (s >= WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES) break; @@ -220,24 +195,12 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { maMax = 0; } ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh - if (fromFS) { - BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax); - if (useParallel && s < 8) { - // if for some unexplained reason the above pre-calculation was wrong, update - unsigned memT = BusManager::memUsage(bc); // includes x8 memory allocation for parallel I2S - if (memT > mem) mem = memT; // if we have unequal LED count use the largest - } else - mem += BusManager::memUsage(bc); // includes global buffer - if (mem <= MAX_LED_MEMORY) if (BusManager::add(bc) == -1) break; // finalization will be done in WLED::beginStrip() - } else { - if (busConfigs[s] != nullptr) delete busConfigs[s]; - busConfigs[s] = new BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax); - doInitBusses = true; // finalization done in beginStrip() - } + + if (busConfigs[s] != nullptr) delete busConfigs[s]; + busConfigs[s] = new BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax); + doInitBusses = true; // finalization done in beginStrip() s++; } - DEBUG_PRINTF_P(PSTR("LED buffer size: %uB\n"), mem); - DEBUG_PRINTF_P(PSTR("Heap after buses: %d\n"), ESP.getFreeHeap()); } if (hw_led["rev"]) BusManager::getBus(0)->setReversed(true); //set 0.11 global reversed setting for first bus @@ -823,6 +786,9 @@ void serializeConfig() { hw_led["fps"] = strip.getTargetFps(); hw_led[F("rgbwm")] = Bus::getGlobalAWMode(); // global auto white mode override hw_led[F("ld")] = useGlobalLedBuffer; + #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) + hw_led[F("prl")] = BusManager::hasParallelOutput(); + #endif #ifndef WLED_DISABLE_2D // 2D Matrix Settings diff --git a/wled00/const.h b/wled00/const.h index 928b150d..640d2d8f 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -59,19 +59,19 @@ #define WLED_MIN_VIRTUAL_BUSSES 3 #elif defined(CONFIG_IDF_TARGET_ESP32S2) // 4 RMT, 8 LEDC, only has 1 I2S bus, supported in NPB // the 5th bus (I2S) will prevent Audioreactive usermod from functioning (it is last used though) - #define WLED_MAX_BUSSES 7 // will allow 5 digital & 2 analog RGB - #define WLED_MAX_DIGITAL_CHANNELS 5 + #define WLED_MAX_BUSSES 14 // will allow 12 digital & 2 analog RGB + #define WLED_MAX_DIGITAL_CHANNELS 12 // x4 RMT + x1/x8 I2S0 //#define WLED_MAX_ANALOG_CHANNELS 8 #define WLED_MIN_VIRTUAL_BUSSES 3 - #elif defined(CONFIG_IDF_TARGET_ESP32S3) // 4 RMT, 8 LEDC, has 2 I2S but NPB does not support them ATM - #define WLED_MAX_BUSSES 6 // will allow 4 digital & 2 analog RGB - #define WLED_MAX_DIGITAL_CHANNELS 4 + #elif defined(CONFIG_IDF_TARGET_ESP32S3) // 4 RMT, 8 LEDC, has 2 I2S but NPB supports parallel x8 LCD on I2S1 + #define WLED_MAX_BUSSES 14 // will allow 12 digital & 2 analog RGB + #define WLED_MAX_DIGITAL_CHANNELS 12 // x4 RMT + x8 I2S-LCD //#define WLED_MAX_ANALOG_CHANNELS 8 #define WLED_MIN_VIRTUAL_BUSSES 4 #else // the last digital bus (I2S0) will prevent Audioreactive usermod from functioning - #define WLED_MAX_BUSSES 20 // will allow 17 digital & 3 analog RGB - #define WLED_MAX_DIGITAL_CHANNELS 17 + #define WLED_MAX_BUSSES 19 // will allow 16 digital & 3 analog RGB + #define WLED_MAX_DIGITAL_CHANNELS 16 // x1/x8 I2S1 + x8 RMT //#define WLED_MAX_ANALOG_CHANNELS 16 #define WLED_MIN_VIRTUAL_BUSSES 4 #endif diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 956cf7d9..86a15cde 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -42,10 +42,10 @@ if (loc) d.Sf.action = getURL('/settings/leds'); } function bLimits(b,v,p,m,l,o=5,d=2,a=6) { - oMaxB = maxB = b; // maxB - max buses (can be changed if using ESP32 parallel I2S) - maxD = d; // maxD - max digital channels (can be changed if using ESP32 parallel I2S) - maxA = a; // maxA - max analog channels - maxV = v; // maxV - min virtual buses + oMaxB = maxB = b; // maxB - max buses (can be changed if using ESP32 parallel I2S): 20 - ESP32, 14 - S3/S2, 6 - C3, 4 - 8266 + maxD = d; // maxD - max digital channels (can be changed if using ESP32 parallel I2S): 17 - ESP32, 12 - S3/S2, 2 - C3, 3 - 8266 + maxA = a; // maxA - max analog channels: 16 - ESP32, 8 - S3/S2, 6 - C3, 5 - 8266 + maxV = v; // maxV - min virtual buses: 4 - ESP32/S3, 3 - S2/C3, 2 - ESP8266 maxPB = p; // maxPB - max LEDs per bus maxM = m; // maxM - max LED memory maxL = l; // maxL - max LEDs (will serve to determine ESP >1664 == ESP32) @@ -250,6 +250,7 @@ } // enable/disable LED fields + let dC = 0; // count of digital buses (for parallel I2S) let LTs = d.Sf.querySelectorAll("#mLC select[name^=LT]"); LTs.forEach((s,i)=>{ if (i < LTs.length-1) s.disabled = true; // prevent changing type (as we can't update options) @@ -257,6 +258,7 @@ var n = s.name.substring(2); var t = parseInt(s.value); memu += getMem(t, n); // calc memory + dC += (isDig(t) && !isD2P(t)); setPinConfig(n,t); gId("abl"+n).style.display = (!abl || !isDig(t)) ? "none" : "inline"; // show/hide individual ABL settings if (change) { // did we change LED type? @@ -295,8 +297,7 @@ // do we have a led count field if (nm=="LC") { let c = parseInt(LC.value,10); //get LED count - if (c > 300 && i < 8) maxB = oMaxB - Math.max(maxD-7,0); //TODO: hard limit for buses when using ESP32 parallel I2S - if (!customStarts || !startsDirty[n]) gId("ls"+n).value=sLC; //update start value + if (!customStarts || !startsDirty[n]) gId("ls"+n).value = sLC; //update start value gId("ls"+n).disabled = !customStarts; //enable/disable field editing if (c) { let s = parseInt(gId("ls"+n).value); //start value @@ -350,6 +351,17 @@ else LC.style.color = d.ro_gpio.some((e)=>e==parseInt(LC.value)) ? "orange" : "#fff"; } }); + const S2 = (oMaxB == 14) && (maxV == 3); + const S3 = (oMaxB == 14) && (maxV == 4); + if (oMaxB == 19 || S2 || S3) { // TODO: crude ESP32 & S2/S3 detection + if (maxLC > 300 || dC <= 2) { + d.Sf["PR"].checked = false; + gId("prl").classList.add("hide"); + } else + gId("prl").classList.remove("hide"); + maxD = (S2 || S3 ? 4 : 8) + (d.Sf["PR"].checked ? 8 : S2); // TODO: use bLimits() : 4/8RMT + (x1/x8 parallel) I2S1 + maxB = oMaxB - (d.Sf["PR"].checked ? 0 : 7 + S3); // S2 (maxV==3) does support single I2S + } // distribute ABL current if not using PPL enPPL(sDI); @@ -789,6 +801,7 @@ Swap:
Make a segment for each output:
Custom bus start indices:
Use global LED buffer:
diff --git a/wled00/set.cpp b/wled00/set.cpp index 160eb48f..d4b6f547 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -139,6 +139,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) Bus::setGlobalAWMode(request->arg(F("AW")).toInt()); strip.setTargetFps(request->arg(F("FR")).toInt()); useGlobalLedBuffer = request->hasArg(F("LD")); + #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) + useParallelI2S = request->hasArg(F("PR")); + #endif bool busesChanged = false; for (int s = 0; s < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; s++) { diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 1f978a39..2967c067 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -179,46 +179,7 @@ void WLED::loop() DEBUG_PRINTLN(F("Re-init busses.")); bool aligned = strip.checkSegmentAlignment(); //see if old segments match old bus(ses) BusManager::removeAll(); - unsigned mem = 0; - // determine if it is sensible to use parallel I2S outputs on ESP32 (i.e. more than 5 outputs = 1 I2S + 4 RMT) - bool useParallel = false; - #if defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ARCH_ESP32S2) && !defined(ARDUINO_ARCH_ESP32S3) && !defined(ARDUINO_ARCH_ESP32C3) - unsigned digitalCount = 0; - unsigned maxLedsOnBus = 0; - unsigned maxChannels = 0; - for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { - if (busConfigs[i] == nullptr) break; - if (!Bus::isDigital(busConfigs[i]->type)) continue; - if (!Bus::is2Pin(busConfigs[i]->type)) { - digitalCount++; - unsigned channels = Bus::getNumberOfChannels(busConfigs[i]->type); - if (busConfigs[i]->count > maxLedsOnBus) maxLedsOnBus = busConfigs[i]->count; - if (channels > maxChannels) maxChannels = channels; - } - } - DEBUG_PRINTF_P(PSTR("Maximum LEDs on a bus: %u\nDigital buses: %u\n"), maxLedsOnBus, digitalCount); - // we may remove 300 LEDs per bus limit when NeoPixelBus is updated beyond 2.9.0 - if (maxLedsOnBus <= 300 && digitalCount > 5) { - DEBUG_PRINTF_P(PSTR("Switching to parallel I2S.")); - useParallel = true; - BusManager::useParallelOutput(); - mem = BusManager::memUsage(maxChannels, maxLedsOnBus, 8); // use alternate memory calculation (hse to be used *after* useParallelOutput()) - } - #endif - // create buses/outputs - for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { - if (busConfigs[i] == nullptr || (!useParallel && i > 10)) break; - if (useParallel && i < 8) { - // if for some unexplained reason the above pre-calculation was wrong, update - unsigned memT = BusManager::memUsage(*busConfigs[i]); // includes x8 memory allocation for parallel I2S - if (memT > mem) mem = memT; // if we have unequal LED count use the largest - } else - mem += BusManager::memUsage(*busConfigs[i]); // includes global buffer - if (mem <= MAX_LED_MEMORY) BusManager::add(*busConfigs[i]); - delete busConfigs[i]; - busConfigs[i] = nullptr; - } - strip.finalizeInit(); // also loads default ledmap if present + strip.finalizeInit(); // will create buses and also load default ledmap if present BusManager::setBrightness(bri); // fix re-initialised bus' brightness #4005 if (aligned) strip.makeAutoSegments(); else strip.fixInvalidSegments(); @@ -563,6 +524,7 @@ void WLED::beginStrip() strip.makeAutoSegments(); strip.setBrightness(0); strip.setShowCallback(handleOverlayDraw); + doInitBusses = false; if (turnOnAtBoot) { if (briS > 0) bri = briS; diff --git a/wled00/wled.h b/wled00/wled.h index d0cee80d..4459fe6d 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -367,7 +367,7 @@ WLED_GLOBAL bool noWifiSleep _INIT(false); 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)) + #if defined(LOLIN_WIFI_FIX) && (defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)) WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_8_5dBm); #else WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_19_5dBm); @@ -394,6 +394,9 @@ WLED_GLOBAL byte bootPreset _INIT(0); // save preset to load WLED_GLOBAL bool useGlobalLedBuffer _INIT(false); // double buffering disabled on ESP8266 #else WLED_GLOBAL bool useGlobalLedBuffer _INIT(true); // double buffering enabled on ESP32 + #ifndef CONFIG_IDF_TARGET_ESP32C3 +WLED_GLOBAL bool useParallelI2S _INIT(false); // parallel I2S for ESP32 + #endif #endif #ifdef WLED_USE_IC_CCT WLED_GLOBAL bool cctICused _INIT(true); // CCT IC used (Athom 15W bulbs) diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 2a19cdfa..79ebf678 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -289,6 +289,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) printSetFormValue(settingsScript,PSTR("FR"),strip.getTargetFps()); printSetFormValue(settingsScript,PSTR("AW"),Bus::getGlobalAWMode()); printSetFormCheckbox(settingsScript,PSTR("LD"),useGlobalLedBuffer); + printSetFormCheckbox(settingsScript,PSTR("PR"),BusManager::hasParallelOutput()); // get it from bus manager not global variable unsigned sumMa = 0; for (int s = 0; s < BusManager::getNumBusses(); s++) { From cc9e9b109cb7a9b85531c707ec4bfb086d1faefb Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 12 Jan 2025 17:07:36 +0000 Subject: [PATCH 149/463] Fix usermod library builds Manage include folders via a second platformio script, fixing builds and removing all the extra boilerplate from usermod library.json files. --- pio-scripts/fixup_usermods.py | 17 +++++++++++++++++ platformio.ini | 1 + usermods/audioreactive/library.json | 2 -- usermods/usermod_v2_animartrix/library.json | 6 ------ usermods/usermod_v2_auto_save/library.json | 7 +------ 5 files changed, 19 insertions(+), 14 deletions(-) create mode 100644 pio-scripts/fixup_usermods.py diff --git a/pio-scripts/fixup_usermods.py b/pio-scripts/fixup_usermods.py new file mode 100644 index 00000000..5b8cddf3 --- /dev/null +++ b/pio-scripts/fixup_usermods.py @@ -0,0 +1,17 @@ +Import('env') + +# Patch up each usermod's include folders to include anything referenced by wled +# This is because usermods need to include wled.h +lib_builders = env.GetLibBuilders() +um_deps = [dep for dep in lib_builders if "/usermods" in dep.src_dir] +other_deps = [dep for dep in lib_builders if "/usermods" not in dep.src_dir] + +for um in um_deps: + # Add include paths for all non-usermod dependencies + for dep in other_deps: + for dir in dep.get_include_dirs(): + um.env.PrependUnique(CPPPATH=dir) + # Add the wled folder to the include path + um.env.PrependUnique(CPPPATH=env["PROJECT_SRC_DIR"]) + +#raise RuntimeError("debug") diff --git a/platformio.ini b/platformio.ini index 4832978a..f8366da0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -115,6 +115,7 @@ extra_scripts = post:pio-scripts/strip-floats.py pre:pio-scripts/user_config_copy.py pre:pio-scripts/load_usermods.py + post:pio-scripts/fixup_usermods.py pre:pio-scripts/build_ui.py ; post:pio-scripts/obj-dump.py ;; convenience script to create a disassembly dump of the firmware (hardcore debugging) diff --git a/usermods/audioreactive/library.json b/usermods/audioreactive/library.json index 2ce60ec6..77f30d2c 100644 --- a/usermods/audioreactive/library.json +++ b/usermods/audioreactive/library.json @@ -1,8 +1,6 @@ { "name": "audioreactive", "build": { - "srcDir": ".", - "includeDir": "../../wled00", "extraScript": "override_sqrt.py" }, "dependencies": [ diff --git a/usermods/usermod_v2_animartrix/library.json b/usermods/usermod_v2_animartrix/library.json index f176e72e..4552be33 100644 --- a/usermods/usermod_v2_animartrix/library.json +++ b/usermods/usermod_v2_animartrix/library.json @@ -1,11 +1,5 @@ { "name": "animartrix", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - }, "dependencies": { "Animartrix": "https://github.com/netmindz/animartrix.git#b172586" } diff --git a/usermods/usermod_v2_auto_save/library.json b/usermods/usermod_v2_auto_save/library.json index 40676ed5..9d81aa68 100644 --- a/usermods/usermod_v2_auto_save/library.json +++ b/usermods/usermod_v2_auto_save/library.json @@ -1,8 +1,3 @@ { - "name": "auto_save", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+" - } + "name": "auto_save" } \ No newline at end of file From f2626b0fc0e355f013ed8483445b430cc5214846 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 12 Jan 2025 17:09:33 +0000 Subject: [PATCH 150/463] Remove now-obsolete AR_build_flags --- platformio.ini | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/platformio.ini b/platformio.ini index f8366da0..7094b7d2 100644 --- a/platformio.ini +++ b/platformio.ini @@ -260,8 +260,8 @@ lib_deps = ${env.lib_deps} board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs # additional build flags for audioreactive - must be applied globally -AR_build_flags = -D sqrt_internal=sqrtf ;; -fsingle-precision-constant ;; forces ArduinoFFT to use float math (2x faster) -AR_lib_deps = kosme/arduinoFFT @ 2.0.1 ;; for pre-usermod-library platformio_override compatibility +AR_build_flags = ;; -fsingle-precision-constant ;; forces ArduinoFFT to use float math (2x faster) +AR_lib_deps = ;; for pre-usermod-library platformio_override compatibility [esp32_idf_V4] @@ -424,7 +424,6 @@ platform_packages = ${esp32.platform_packages} custom_usermods = audioreactive build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32\" #-D WLED_DISABLE_BROWNOUT_DET - ${esp32.AR_build_flags} lib_deps = ${esp32.lib_deps} monitor_filters = esp32_exception_decoder board_build.partitions = ${esp32.default_partitions} @@ -436,7 +435,6 @@ platform_packages = ${esp32_idf_V4.platform_packages} custom_usermods = audioreactive build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_8M\" #-D WLED_DISABLE_BROWNOUT_DET - ${esp32.AR_build_flags} lib_deps = ${esp32_idf_V4.lib_deps} monitor_filters = esp32_exception_decoder board_build.partitions = ${esp32.large_partitions} @@ -452,7 +450,6 @@ platform_packages = ${esp32_idf_V4.platform_packages} custom_usermods = audioreactive build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_16M\" #-D WLED_DISABLE_BROWNOUT_DET - ${esp32.AR_build_flags} lib_deps = ${esp32_idf_V4.lib_deps} monitor_filters = esp32_exception_decoder board_build.partitions = ${esp32.extreme_partitions} @@ -468,7 +465,6 @@ board_build.flash_mode = dio ;custom_usermods = audioreactive ;build_unflags = ${common.build_unflags} ;build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32_audioreactive\" #-D WLED_DISABLE_BROWNOUT_DET -; ${esp32.AR_build_flags} ;lib_deps = ${esp32.lib_deps} ;monitor_filters = esp32_exception_decoder ;board_build.partitions = ${esp32.default_partitions} @@ -484,7 +480,6 @@ custom_usermods = audioreactive build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32_Ethernet\" -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1 ; -D WLED_DISABLE_ESPNOW ;; ESP-NOW requires wifi, may crash with ethernet only - ${esp32.AR_build_flags} lib_deps = ${esp32.lib_deps} board_build.partitions = ${esp32.default_partitions} @@ -501,7 +496,6 @@ build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_WROVER\" -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue ;; Older ESP32 (rev.<3) need a PSRAM fix (increases static RAM used) https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/external-ram.html -D DATA_PINS=25 - ${esp32.AR_build_flags} lib_deps = ${esp32_idf_V4.lib_deps} [env:esp32c3dev] @@ -534,7 +528,6 @@ build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME= ;-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip -D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB") -DBOARD_HAS_PSRAM - ${esp32.AR_build_flags} lib_deps = ${esp32s3.lib_deps} board_build.partitions = ${esp32.extreme_partitions} board_upload.flash_size = 16MB @@ -557,7 +550,6 @@ build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME= ;-D ARDUINO_USB_CDC_ON_BOOT=0 ;; -D ARDUINO_USB_MODE=1 ;; for boards with serial-to-USB chip -D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB") -DBOARD_HAS_PSRAM - ${esp32.AR_build_flags} lib_deps = ${esp32s3.lib_deps} board_build.partitions = ${esp32.large_partitions} board_build.f_flash = 80000000L @@ -582,7 +574,6 @@ build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME= -D LEDPIN=38 -D DATA_PINS=38 ;; buildin WS2812b LED -D BTNPIN=0 -D RLYPIN=16 -D IRPIN=17 -D AUDIOPIN=-1 -D WLED_DEBUG - ${esp32.AR_build_flags} -D SR_DMTYPE=1 -D I2S_SDPIN=13 -D I2S_CKPIN=14 -D I2S_WSPIN=15 -D MCLK_PIN=4 ;; I2S mic lib_deps = ${esp32s3.lib_deps} @@ -604,7 +595,6 @@ build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME= -DBOARD_HAS_PSRAM -DLOLIN_WIFI_FIX ; seems to work much better with this -D WLED_WATCHDOG_TIMEOUT=0 - ${esp32.AR_build_flags} lib_deps = ${esp32s3.lib_deps} board_build.partitions = ${esp32.default_partitions} board_build.f_flash = 80000000L @@ -635,5 +625,4 @@ build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME= -D HW_PIN_DATASPI=11 -D HW_PIN_MISOSPI=9 ; -D STATUSLED=15 - ${esp32.AR_build_flags} lib_deps = ${esp32s2.lib_deps} From 24accf96a859c0e4023a5db925d7ecc3898aebf7 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Mon, 13 Jan 2025 10:53:24 +0000 Subject: [PATCH 151/463] Remove now redundant build section from library.json --- usermods/ADS1115_v2/library.json | 6 ------ usermods/AHT10_v2/library.json | 6 ------ usermods/Analog_Clock/library.json | 8 +------- usermods/Animated_Staircase/library.json | 8 +------- usermods/BH1750_v2/library.json | 6 ------ usermods/BME280_v2/library.json | 8 +------- usermods/BME68X_v2/library.json | 6 ------ usermods/Battery/library.json | 8 +------- usermods/Cronixie/library.json | 8 +------- usermods/DHT/library.json | 6 ------ usermods/EleksTube_IPS/library.json | 8 +------- usermods/INA226_v2/library.json | 6 ------ usermods/Internal_Temperature_v2/library.json | 8 +------- usermods/LD2410_v2/library.json | 8 +------- usermods/LDR_Dusk_Dawn_v2/library.json | 8 +------- usermods/MAX17048_v2/library.json | 6 ------ usermods/MY9291/library.json | 8 +------- usermods/PIR_sensor_switch/library.json | 8 +------- usermods/PWM_fan/library.json | 8 +------- usermods/RTC/library.json | 8 +------- usermods/SN_Photoresistor/library.json | 8 +------- usermods/ST7789_display/library.json | 8 +------- usermods/Si7021_MQTT_HA/library.json | 8 +------- usermods/Temperature/library.json | 6 ------ usermods/TetrisAI_v2/library.json | 8 +------- usermods/VL53L0X_gestures/library.json | 6 ------ usermods/audioreactive/library.json | 8 +------- usermods/boblight/library.json | 8 +------- usermods/buzzer/library.json | 8 +------- usermods/deep_sleep/library.json | 8 +------- usermods/mpu6050_imu/library.json | 6 ------ usermods/mqtt_switch_v2/library.json | 8 +------- usermods/multi_relay/library.json | 8 +------- usermods/pixels_dice_tray/library.json | 6 ------ usermods/pov_display/library.json | 6 ------ usermods/pwm_outputs/library.json | 8 +------- usermods/quinled-an-penta/library.json | 6 ------ usermods/rgb-rotary-encoder/library.json | 6 ------ usermods/sd_card/library.json | 8 +------- usermods/sensors_to_mqtt/library.json | 6 ------ usermods/seven_segment_display/library.json | 8 +------- usermods/seven_segment_display_reloaded/library.json | 8 +------- usermods/sht/library.json | 8 +------- usermods/smartnest/library.json | 8 +------- usermods/stairway_wipe_basic/library.json | 8 +------- usermods/usermod_rotary_brightness_color/library.json | 8 +------- usermods/usermod_v2_HttpPullLightControl/library.json | 8 +------- usermods/usermod_v2_animartrix/library.json | 6 ------ usermods/usermod_v2_auto_save/library.json | 9 ++------- usermods/usermod_v2_four_line_display_ALT/library.json | 8 +------- usermods/usermod_v2_klipper_percentage/library.json | 8 +------- usermods/usermod_v2_ping_pong_clock/library.json | 8 +------- usermods/usermod_v2_rotary_encoder_ui_ALT/library.json | 8 +------- usermods/usermod_v2_word_clock/library.json | 8 +------- usermods/wireguard/library.json | 6 ------ usermods/wizlights/library.json | 8 +------- usermods/word-clock-matrix/library.json | 8 +------- 57 files changed, 41 insertions(+), 382 deletions(-) diff --git a/usermods/ADS1115_v2/library.json b/usermods/ADS1115_v2/library.json index 179a56e5..0b93c935 100644 --- a/usermods/ADS1115_v2/library.json +++ b/usermods/ADS1115_v2/library.json @@ -1,11 +1,5 @@ { "name:": "ADS1115_v2", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - }, "dependencies": { "Adafruit BusIO": "https://github.com/adafruit/Adafruit_BusIO#1.13.2", "Adafruit ADS1X15": "https://github.com/adafruit/Adafruit_ADS1X15#2.4.0" diff --git a/usermods/AHT10_v2/library.json b/usermods/AHT10_v2/library.json index 28bac435..94a206c5 100644 --- a/usermods/AHT10_v2/library.json +++ b/usermods/AHT10_v2/library.json @@ -1,11 +1,5 @@ { "name:": "AHT10_v2", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - }, "dependencies": { "enjoyneering/AHT10":"~1.1.0" } diff --git a/usermods/Analog_Clock/library.json b/usermods/Analog_Clock/library.json index ddba3a76..4936950e 100644 --- a/usermods/Analog_Clock/library.json +++ b/usermods/Analog_Clock/library.json @@ -1,9 +1,3 @@ { - "name:": "Analog_Clock", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "Analog_Clock" } \ No newline at end of file diff --git a/usermods/Animated_Staircase/library.json b/usermods/Animated_Staircase/library.json index e37df311..626baa49 100644 --- a/usermods/Animated_Staircase/library.json +++ b/usermods/Animated_Staircase/library.json @@ -1,9 +1,3 @@ { - "name:": "Animated_Staircase", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "Animated_Staircase" } \ No newline at end of file diff --git a/usermods/BH1750_v2/library.json b/usermods/BH1750_v2/library.json index 0211bc88..b7f006cc 100644 --- a/usermods/BH1750_v2/library.json +++ b/usermods/BH1750_v2/library.json @@ -1,11 +1,5 @@ { "name:": "BH1750_v2", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - }, "dependencies": { "claws/BH1750":"^1.2.0" } diff --git a/usermods/BME280_v2/library.json b/usermods/BME280_v2/library.json index 57d41fb3..126cb362 100644 --- a/usermods/BME280_v2/library.json +++ b/usermods/BME280_v2/library.json @@ -1,9 +1,3 @@ { - "name:": "BME280_v2", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "BME280_v2" } \ No newline at end of file diff --git a/usermods/BME68X_v2/library.json b/usermods/BME68X_v2/library.json index ccfac0d9..3a0e4948 100644 --- a/usermods/BME68X_v2/library.json +++ b/usermods/BME68X_v2/library.json @@ -1,11 +1,5 @@ { "name:": "BME68X_v2", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - }, "dependencies": { "boschsensortec/BSEC Software Library":"^1.8.1492" } diff --git a/usermods/Battery/library.json b/usermods/Battery/library.json index bc0d97a1..3f4774b8 100644 --- a/usermods/Battery/library.json +++ b/usermods/Battery/library.json @@ -1,9 +1,3 @@ { - "name:": "Battery", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "Battery" } \ No newline at end of file diff --git a/usermods/Cronixie/library.json b/usermods/Cronixie/library.json index f0d39d00..d4832764 100644 --- a/usermods/Cronixie/library.json +++ b/usermods/Cronixie/library.json @@ -1,9 +1,3 @@ { - "name:": "Cronixie", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "Cronixie" } \ No newline at end of file diff --git a/usermods/DHT/library.json b/usermods/DHT/library.json index ec7158d2..5f2d27f0 100644 --- a/usermods/DHT/library.json +++ b/usermods/DHT/library.json @@ -1,11 +1,5 @@ { "name:": "DHT", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - }, "dependencies": { "DHT_nonblocking":"https://github.com/alwynallan/DHT_nonblocking" } diff --git a/usermods/EleksTube_IPS/library.json b/usermods/EleksTube_IPS/library.json index d025fc78..27d71861 100644 --- a/usermods/EleksTube_IPS/library.json +++ b/usermods/EleksTube_IPS/library.json @@ -1,9 +1,3 @@ { - "name:": "EleksTube_IPS", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "EleksTube_IPS" } \ No newline at end of file diff --git a/usermods/INA226_v2/library.json b/usermods/INA226_v2/library.json index be6987e2..91a735fe 100644 --- a/usermods/INA226_v2/library.json +++ b/usermods/INA226_v2/library.json @@ -1,11 +1,5 @@ { "name:": "INA226_v2", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - }, "dependencies": { "wollewald/INA226_WE":"~1.2.9" } diff --git a/usermods/Internal_Temperature_v2/library.json b/usermods/Internal_Temperature_v2/library.json index 38b560da..6c165238 100644 --- a/usermods/Internal_Temperature_v2/library.json +++ b/usermods/Internal_Temperature_v2/library.json @@ -1,9 +1,3 @@ { - "name:": "Internal_Temperature_v2", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "Internal_Temperature_v2" } \ No newline at end of file diff --git a/usermods/LD2410_v2/library.json b/usermods/LD2410_v2/library.json index 3480cd79..6fcded02 100644 --- a/usermods/LD2410_v2/library.json +++ b/usermods/LD2410_v2/library.json @@ -1,9 +1,3 @@ { - "name:": "LD2410_v2", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "LD2410_v2" } \ No newline at end of file diff --git a/usermods/LDR_Dusk_Dawn_v2/library.json b/usermods/LDR_Dusk_Dawn_v2/library.json index 6a08c9cc..bb57dbd2 100644 --- a/usermods/LDR_Dusk_Dawn_v2/library.json +++ b/usermods/LDR_Dusk_Dawn_v2/library.json @@ -1,9 +1,3 @@ { - "name:": "LDR_Dusk_Dawn_v2", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "LDR_Dusk_Dawn_v2" } \ No newline at end of file diff --git a/usermods/MAX17048_v2/library.json b/usermods/MAX17048_v2/library.json index f85b33cf..14633345 100644 --- a/usermods/MAX17048_v2/library.json +++ b/usermods/MAX17048_v2/library.json @@ -1,11 +1,5 @@ { "name:": "MAX17048_v2", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - }, "dependencies": { "Adafruit_MAX1704X":"https://github.com/adafruit/Adafruit_MAX1704X#1.0.2" } diff --git a/usermods/MY9291/library.json b/usermods/MY9291/library.json index d965f4c3..9324e4a0 100644 --- a/usermods/MY9291/library.json +++ b/usermods/MY9291/library.json @@ -1,9 +1,3 @@ { - "name:": "MY9291", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "MY9291" } \ No newline at end of file diff --git a/usermods/PIR_sensor_switch/library.json b/usermods/PIR_sensor_switch/library.json index 152946e4..0ee7e18b 100644 --- a/usermods/PIR_sensor_switch/library.json +++ b/usermods/PIR_sensor_switch/library.json @@ -1,9 +1,3 @@ { - "name:": "PIR_sensor_switch", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "PIR_sensor_switch" } \ No newline at end of file diff --git a/usermods/PWM_fan/library.json b/usermods/PWM_fan/library.json index a6d5ea64..904d7723 100644 --- a/usermods/PWM_fan/library.json +++ b/usermods/PWM_fan/library.json @@ -1,9 +1,3 @@ { - "name:": "PWM_fan", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "PWM_fan" } \ No newline at end of file diff --git a/usermods/RTC/library.json b/usermods/RTC/library.json index 96aa095b..e0c527d2 100644 --- a/usermods/RTC/library.json +++ b/usermods/RTC/library.json @@ -1,9 +1,3 @@ { - "name:": "RTC", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "RTC" } \ No newline at end of file diff --git a/usermods/SN_Photoresistor/library.json b/usermods/SN_Photoresistor/library.json index fe5173be..7cac93f8 100644 --- a/usermods/SN_Photoresistor/library.json +++ b/usermods/SN_Photoresistor/library.json @@ -1,9 +1,3 @@ { - "name:": "SN_Photoresistor", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "SN_Photoresistor" } \ No newline at end of file diff --git a/usermods/ST7789_display/library.json b/usermods/ST7789_display/library.json index 88f4efe7..abcd4635 100644 --- a/usermods/ST7789_display/library.json +++ b/usermods/ST7789_display/library.json @@ -1,9 +1,3 @@ { - "name:": "ST7789_display", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "ST7789_display" } \ No newline at end of file diff --git a/usermods/Si7021_MQTT_HA/library.json b/usermods/Si7021_MQTT_HA/library.json index 2c18375f..004f9f99 100644 --- a/usermods/Si7021_MQTT_HA/library.json +++ b/usermods/Si7021_MQTT_HA/library.json @@ -1,9 +1,3 @@ { - "name:": "Si7021_MQTT_HA", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "Si7021_MQTT_HA" } \ No newline at end of file diff --git a/usermods/Temperature/library.json b/usermods/Temperature/library.json index 24de7982..6a20a7d3 100644 --- a/usermods/Temperature/library.json +++ b/usermods/Temperature/library.json @@ -1,11 +1,5 @@ { "name:": "Temperature", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - }, "dependencies": { "paulstoffregen/OneWire":"~2.3.8" } diff --git a/usermods/TetrisAI_v2/library.json b/usermods/TetrisAI_v2/library.json index 199e5c43..7163dadb 100644 --- a/usermods/TetrisAI_v2/library.json +++ b/usermods/TetrisAI_v2/library.json @@ -1,9 +1,3 @@ { - "name:": "TetrisAI_v2", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "TetrisAI_v2" } \ No newline at end of file diff --git a/usermods/VL53L0X_gestures/library.json b/usermods/VL53L0X_gestures/library.json index 6dfe4c4d..50ff9cb4 100644 --- a/usermods/VL53L0X_gestures/library.json +++ b/usermods/VL53L0X_gestures/library.json @@ -1,11 +1,5 @@ { "name:": "VL53L0X_gestures", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - }, "dependencies": { "pololu/VL53L0X" : "^1.3.0" } diff --git a/usermods/audioreactive/library.json b/usermods/audioreactive/library.json index 658bf943..70484d0a 100644 --- a/usermods/audioreactive/library.json +++ b/usermods/audioreactive/library.json @@ -1,11 +1,5 @@ { "name": "audioreactive", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - }, "dependencies": [ { "owner": "kosme", @@ -14,4 +8,4 @@ "platforms": "espressif32" } ] -} \ No newline at end of file +} diff --git a/usermods/boblight/library.json b/usermods/boblight/library.json index 0b63b224..741d4cb1 100644 --- a/usermods/boblight/library.json +++ b/usermods/boblight/library.json @@ -1,9 +1,3 @@ { - "name:": "boblight", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "boblight" } \ No newline at end of file diff --git a/usermods/buzzer/library.json b/usermods/buzzer/library.json index 78ba4152..6bbcdcc3 100644 --- a/usermods/buzzer/library.json +++ b/usermods/buzzer/library.json @@ -1,9 +1,3 @@ { - "name:": "buzzer", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "buzzer" } \ No newline at end of file diff --git a/usermods/deep_sleep/library.json b/usermods/deep_sleep/library.json index c15e8d57..c8f66de1 100644 --- a/usermods/deep_sleep/library.json +++ b/usermods/deep_sleep/library.json @@ -1,9 +1,3 @@ { - "name:": "deep_sleep", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "deep_sleep" } \ No newline at end of file diff --git a/usermods/mpu6050_imu/library.json b/usermods/mpu6050_imu/library.json index 68db4d2f..29562393 100644 --- a/usermods/mpu6050_imu/library.json +++ b/usermods/mpu6050_imu/library.json @@ -1,11 +1,5 @@ { "name:": "mpu6050_imu", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - }, "dependencies": { "electroniccats/MPU6050":"1.0.1" } diff --git a/usermods/mqtt_switch_v2/library.json b/usermods/mqtt_switch_v2/library.json index 96695a9c..cf9abefd 100644 --- a/usermods/mqtt_switch_v2/library.json +++ b/usermods/mqtt_switch_v2/library.json @@ -1,9 +1,3 @@ { - "name:": "mqtt_switch_v2", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "mqtt_switch_v2" } \ No newline at end of file diff --git a/usermods/multi_relay/library.json b/usermods/multi_relay/library.json index 47505d0b..7aa76439 100644 --- a/usermods/multi_relay/library.json +++ b/usermods/multi_relay/library.json @@ -1,9 +1,3 @@ { - "name:": "multi_relay", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "multi_relay" } \ No newline at end of file diff --git a/usermods/pixels_dice_tray/library.json b/usermods/pixels_dice_tray/library.json index 4634c407..fd6a53a5 100644 --- a/usermods/pixels_dice_tray/library.json +++ b/usermods/pixels_dice_tray/library.json @@ -1,11 +1,5 @@ { "name:": "pixels_dice_tray", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - }, "dependencies": { "arduino-pixels-dice":"https://github.com/axlan/arduino-pixels-dice.git" } diff --git a/usermods/pov_display/library.json b/usermods/pov_display/library.json index a3885417..298739b5 100644 --- a/usermods/pov_display/library.json +++ b/usermods/pov_display/library.json @@ -1,11 +1,5 @@ { "name:": "pov_display", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - }, "dependencies": { "bitbank2/PNGdec":"^1.0.3" } diff --git a/usermods/pwm_outputs/library.json b/usermods/pwm_outputs/library.json index 18ce7d88..4bf07777 100644 --- a/usermods/pwm_outputs/library.json +++ b/usermods/pwm_outputs/library.json @@ -1,9 +1,3 @@ { - "name:": "pwm_outputs", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "pwm_outputs" } \ No newline at end of file diff --git a/usermods/quinled-an-penta/library.json b/usermods/quinled-an-penta/library.json index 2fe3e11a..e89dc002 100644 --- a/usermods/quinled-an-penta/library.json +++ b/usermods/quinled-an-penta/library.json @@ -1,11 +1,5 @@ { "name:": "quinled-an-penta", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - }, "dependencies": { "olikraus/U8g2":"~2.28.8", "robtillaart/SHT85":"~0.3.3" diff --git a/usermods/rgb-rotary-encoder/library.json b/usermods/rgb-rotary-encoder/library.json index dd6169a3..25572e11 100644 --- a/usermods/rgb-rotary-encoder/library.json +++ b/usermods/rgb-rotary-encoder/library.json @@ -1,11 +1,5 @@ { "name:": "rgb-rotary-encoder", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - }, "dependencies": { "lennarthennigs/ESP Rotary":"^2.1.1" } diff --git a/usermods/sd_card/library.json b/usermods/sd_card/library.json index 777c6264..1f123ead 100644 --- a/usermods/sd_card/library.json +++ b/usermods/sd_card/library.json @@ -1,9 +1,3 @@ { - "name:": "sd_card", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "sd_card" } \ No newline at end of file diff --git a/usermods/sensors_to_mqtt/library.json b/usermods/sensors_to_mqtt/library.json index c1bb6ec8..6594152c 100644 --- a/usermods/sensors_to_mqtt/library.json +++ b/usermods/sensors_to_mqtt/library.json @@ -1,11 +1,5 @@ { "name:": "sensors_to_mqtt", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - }, "dependencies": { "adafruit/Adafruit BMP280 Library":"2.1.0", "adafruit/Adafruit CCS811 Library":"1.0.4", diff --git a/usermods/seven_segment_display/library.json b/usermods/seven_segment_display/library.json index c10bd084..8764e92b 100644 --- a/usermods/seven_segment_display/library.json +++ b/usermods/seven_segment_display/library.json @@ -1,9 +1,3 @@ { - "name:": "seven_segment_display", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "seven_segment_display" } \ No newline at end of file diff --git a/usermods/seven_segment_display_reloaded/library.json b/usermods/seven_segment_display_reloaded/library.json index 485aa4fd..fdce8b53 100644 --- a/usermods/seven_segment_display_reloaded/library.json +++ b/usermods/seven_segment_display_reloaded/library.json @@ -1,9 +1,3 @@ { - "name:": "seven_segment_display_reloaded", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "seven_segment_display_reloaded" } \ No newline at end of file diff --git a/usermods/sht/library.json b/usermods/sht/library.json index 2cb0003a..330093bd 100644 --- a/usermods/sht/library.json +++ b/usermods/sht/library.json @@ -1,9 +1,3 @@ { - "name:": "sht", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "sht" } \ No newline at end of file diff --git a/usermods/smartnest/library.json b/usermods/smartnest/library.json index 4e776ad7..e2c6ab35 100644 --- a/usermods/smartnest/library.json +++ b/usermods/smartnest/library.json @@ -1,9 +1,3 @@ { - "name:": "smartnest", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "smartnest" } \ No newline at end of file diff --git a/usermods/stairway_wipe_basic/library.json b/usermods/stairway_wipe_basic/library.json index 6b3a5236..59cb5da9 100644 --- a/usermods/stairway_wipe_basic/library.json +++ b/usermods/stairway_wipe_basic/library.json @@ -1,9 +1,3 @@ { - "name:": "stairway_wipe_basic", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "stairway_wipe_basic" } \ No newline at end of file diff --git a/usermods/usermod_rotary_brightness_color/library.json b/usermods/usermod_rotary_brightness_color/library.json index 8d368082..777ec19c 100644 --- a/usermods/usermod_rotary_brightness_color/library.json +++ b/usermods/usermod_rotary_brightness_color/library.json @@ -1,9 +1,3 @@ { - "name:": "usermod_rotary_brightness_color", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "usermod_rotary_brightness_color" } \ No newline at end of file diff --git a/usermods/usermod_v2_HttpPullLightControl/library.json b/usermods/usermod_v2_HttpPullLightControl/library.json index 68b93708..0f66710b 100644 --- a/usermods/usermod_v2_HttpPullLightControl/library.json +++ b/usermods/usermod_v2_HttpPullLightControl/library.json @@ -1,9 +1,3 @@ { - "name:": "usermod_v2_HttpPullLightControl", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "usermod_v2_HttpPullLightControl" } \ No newline at end of file diff --git a/usermods/usermod_v2_animartrix/library.json b/usermods/usermod_v2_animartrix/library.json index f176e72e..4552be33 100644 --- a/usermods/usermod_v2_animartrix/library.json +++ b/usermods/usermod_v2_animartrix/library.json @@ -1,11 +1,5 @@ { "name": "animartrix", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - }, "dependencies": { "Animartrix": "https://github.com/netmindz/animartrix.git#b172586" } diff --git a/usermods/usermod_v2_auto_save/library.json b/usermods/usermod_v2_auto_save/library.json index 40676ed5..67b29ca6 100644 --- a/usermods/usermod_v2_auto_save/library.json +++ b/usermods/usermod_v2_auto_save/library.json @@ -1,8 +1,3 @@ -{ - "name": "auto_save", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+" - } +{ + "name:": "usermod_v2_auto_save" } \ No newline at end of file diff --git a/usermods/usermod_v2_four_line_display_ALT/library.json b/usermods/usermod_v2_four_line_display_ALT/library.json index 6dccb4a9..56612c96 100644 --- a/usermods/usermod_v2_four_line_display_ALT/library.json +++ b/usermods/usermod_v2_four_line_display_ALT/library.json @@ -1,9 +1,3 @@ { - "name:": "usermod_v2_four_line_display_ALT", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "usermod_v2_four_line_display_ALT" } \ No newline at end of file diff --git a/usermods/usermod_v2_klipper_percentage/library.json b/usermods/usermod_v2_klipper_percentage/library.json index afd96163..b31fb1ad 100644 --- a/usermods/usermod_v2_klipper_percentage/library.json +++ b/usermods/usermod_v2_klipper_percentage/library.json @@ -1,9 +1,3 @@ { - "name:": "usermod_v2_klipper_percentage", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "usermod_v2_klipper_percentage" } \ No newline at end of file diff --git a/usermods/usermod_v2_ping_pong_clock/library.json b/usermods/usermod_v2_ping_pong_clock/library.json index 19708611..fe23cd91 100644 --- a/usermods/usermod_v2_ping_pong_clock/library.json +++ b/usermods/usermod_v2_ping_pong_clock/library.json @@ -1,9 +1,3 @@ { - "name:": "usermod_v2_ping_pong_clock", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "usermod_v2_ping_pong_clock" } \ No newline at end of file diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/library.json b/usermods/usermod_v2_rotary_encoder_ui_ALT/library.json index f7c60ecd..5f857218 100644 --- a/usermods/usermod_v2_rotary_encoder_ui_ALT/library.json +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/library.json @@ -1,9 +1,3 @@ { - "name:": "usermod_v2_rotary_encoder_ui_ALT", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "usermod_v2_rotary_encoder_ui_ALT" } \ No newline at end of file diff --git a/usermods/usermod_v2_word_clock/library.json b/usermods/usermod_v2_word_clock/library.json index 74a3d903..83c14dc7 100644 --- a/usermods/usermod_v2_word_clock/library.json +++ b/usermods/usermod_v2_word_clock/library.json @@ -1,9 +1,3 @@ { - "name:": "usermod_v2_word_clock", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "usermod_v2_word_clock" } \ No newline at end of file diff --git a/usermods/wireguard/library.json b/usermods/wireguard/library.json index 99648400..0ebace8b 100644 --- a/usermods/wireguard/library.json +++ b/usermods/wireguard/library.json @@ -1,11 +1,5 @@ { "name:": "wireguard", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - }, "dependencies": { "WireGuard-ESP32-Arduino":"https://github.com/kienvu58/WireGuard-ESP32-Arduino.git" } diff --git a/usermods/wizlights/library.json b/usermods/wizlights/library.json index a82dd7fc..687fba0f 100644 --- a/usermods/wizlights/library.json +++ b/usermods/wizlights/library.json @@ -1,9 +1,3 @@ { - "name:": "wizlights", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "wizlights" } \ No newline at end of file diff --git a/usermods/word-clock-matrix/library.json b/usermods/word-clock-matrix/library.json index ed29ae08..d971dfff 100644 --- a/usermods/word-clock-matrix/library.json +++ b/usermods/word-clock-matrix/library.json @@ -1,9 +1,3 @@ { - "name:": "word-clock-matrix", - "build": { - "srcDir": ".", - "includeDir": "../../wled00", - "libLDFMode": "chain+", - "libArchive": false - } + "name:": "word-clock-matrix" } \ No newline at end of file From 3c19692312df2eda362db394faeae5f92bb5f747 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Mon, 13 Jan 2025 10:58:32 +0000 Subject: [PATCH 152/463] Cleanup copy-paste of platform and platform_packages - use the proper common esp32_idf_V4 --- platformio.ini | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/platformio.ini b/platformio.ini index 0870cde9..9a72b75d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -288,8 +288,8 @@ board_build.partitions = ${esp32.default_partitions} ;; default partioning for [esp32s2] ;; generic definitions for all ESP32-S2 boards -platform = espressif32@ ~6.3.2 -platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them) +platform = ${esp32_idf_V4.platform} +platform_packages = ${esp32_idf_V4.platform_packages} build_unflags = ${common.build_unflags} build_flags = -g -DARDUINO_ARCH_ESP32 @@ -308,8 +308,8 @@ board_build.partitions = ${esp32.default_partitions} ;; default partioning for [esp32c3] ;; generic definitions for all ESP32-C3 boards -platform = espressif32@ ~6.3.2 -platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them) +platform = ${esp32_idf_V4.platform} +platform_packages = ${esp32_idf_V4.platform_packages} build_unflags = ${common.build_unflags} build_flags = -g -DARDUINO_ARCH_ESP32 @@ -327,8 +327,8 @@ board_build.partitions = ${esp32.default_partitions} ;; default partioning for [esp32s3] ;; generic definitions for all ESP32-S3 boards -platform = espressif32@ ~6.3.2 -platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them) +platform = ${esp32_idf_V4.platform} +platform_packages = ${esp32_idf_V4.platform_packages} build_unflags = ${common.build_unflags} build_flags = -g -DESP32 From 5b5e4157e3dbf170416f9e7b18fe7398798d15b3 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Mon, 13 Jan 2025 11:12:14 +0000 Subject: [PATCH 153/463] Add esp32dev_v4 env --- platformio.ini | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 9a72b75d..b7395dde 100644 --- a/platformio.ini +++ b/platformio.ini @@ -10,7 +10,7 @@ # ------------------------------------------------------------------------------ # CI/release binaries -default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover +default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev_V4, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover src_dir = ./wled00 data_dir = ./wled00/data @@ -432,6 +432,18 @@ lib_deps = ${esp32.lib_deps} monitor_filters = esp32_exception_decoder board_build.partitions = ${esp32.default_partitions} +[env:esp32dev_V4] +board = esp32dev +platform = ${esp32_idf_V4.platform} +platform_packages = ${esp32_idf_V4.platform_packages} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_V4\" #-D WLED_DISABLE_BROWNOUT_DET + ${esp32.AR_build_flags} +lib_deps = ${esp32_idf_V4.lib_deps} + ${esp32.AR_lib_deps} +monitor_filters = esp32_exception_decoder +board_build.partitions = ${esp32.default_partitions} + [env:esp32dev_8M] board = esp32dev platform = ${esp32_idf_V4.platform} From 29ee551b068e12f353079bb4fb8b5bdd4c93709f Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Mon, 13 Jan 2025 15:38:25 +0000 Subject: [PATCH 154/463] Swap to tasmota/platform-espressif32 --- platformio.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index b7395dde..f3e11ce3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -273,7 +273,7 @@ board_build.partitions = ${esp32.default_partitions} ;; default partioning for ;; ;; please note that you can NOT update existing ESP32 installs with a "V4" build. Also updating by OTA will not work properly. ;; You need to completely erase your device (esptool erase_flash) first, then install the "V4" build from VSCode+platformio. -platform = espressif32@ ~6.3.2 +platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.06.02/platform-espressif32.zip ;; Tasmota Arduino Core 2.0.9 with IPv6 support, based on IDF 4.4.4 platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them) build_unflags = ${common.build_unflags} build_flags = -g @@ -435,7 +435,7 @@ board_build.partitions = ${esp32.default_partitions} [env:esp32dev_V4] board = esp32dev platform = ${esp32_idf_V4.platform} -platform_packages = ${esp32_idf_V4.platform_packages} +; platform_packages = ${esp32_idf_V4.platform_packages} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_V4\" #-D WLED_DISABLE_BROWNOUT_DET ${esp32.AR_build_flags} From cc011e39cea849b52b6e88e25769c9650b0ccae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Mon, 13 Jan 2025 17:22:11 +0100 Subject: [PATCH 155/463] Bus creation bugfix - speed improvements in ABL - verbose debugging --- wled00/FX_fcn.cpp | 1 + wled00/bus_manager.cpp | 51 ++++++++++++++++++++++++++---------------- wled00/cfg.cpp | 11 +++++++++ 3 files changed, 44 insertions(+), 19 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 589fa67e..7be0eace 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1259,6 +1259,7 @@ void WS2812FX::finalizeInit() { #endif mem += BusManager::memUsage(*busConfigs[i]); // includes global buffer if (mem <= MAX_LED_MEMORY) BusManager::add(*busConfigs[i]); + else DEBUG_PRINTF_P(PSTR("Out of LED memory! Bus #%u not created."), i); delete busConfigs[i]; busConfigs[i] = nullptr; } diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 44b841ac..81ef2cb0 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -130,30 +130,41 @@ BusDigital::BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com , _milliAmpsMax(bc.milliAmpsMax) , _colorOrderMap(com) { - if (!isDigital(bc.type) || !bc.count) return; - if (!PinManager::allocatePin(bc.pins[0], true, PinOwner::BusDigital)) return; + DEBUG_PRINTLN(F("Bus: Creating digital bus.")); + if (!isDigital(bc.type) || !bc.count) { DEBUG_PRINTLN(F("Not digial or empty bus!")); return; } + if (!PinManager::allocatePin(bc.pins[0], true, PinOwner::BusDigital)) { DEBUG_PRINTLN(F("Pin 0 allocated!")); return; } _frequencykHz = 0U; _pins[0] = bc.pins[0]; if (is2Pin(bc.type)) { if (!PinManager::allocatePin(bc.pins[1], true, PinOwner::BusDigital)) { cleanup(); + DEBUG_PRINTLN(F("Pin 1 allocated!")); return; } _pins[1] = bc.pins[1]; _frequencykHz = bc.frequency ? bc.frequency : 2000U; // 2MHz clock if undefined } _iType = PolyBus::getI(bc.type, _pins, nr); - if (_iType == I_NONE) return; + if (_iType == I_NONE) { DEBUG_PRINTLN(F("Incorrect iType!")); return; } _hasRgb = hasRGB(bc.type); _hasWhite = hasWhite(bc.type); _hasCCT = hasCCT(bc.type); - if (bc.doubleBuffer && !allocateData(bc.count * Bus::getNumberOfChannels(bc.type))) return; + if (bc.doubleBuffer && !allocateData(bc.count * Bus::getNumberOfChannels(bc.type))) { DEBUG_PRINTLN(F("Buffer allocation failed!")); return; } //_buffering = bc.doubleBuffer; uint16_t lenToCreate = bc.count; if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(bc.count); // only needs a third of "RGB" LEDs for NeoPixelBus _busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr); _valid = (_busPtr != nullptr); - DEBUG_PRINTF_P(PSTR("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u). mA=%d/%d\n"), _valid?"S":"Uns", nr, bc.count, bc.type, _pins[0], is2Pin(bc.type)?_pins[1]:255, _iType, _milliAmpsPerLed, _milliAmpsMax); + DEBUG_PRINTF_P(PSTR("Bus: %successfully inited #%u (len:%u, type:%u (RGB:%d, W:%d, CCT:%d), pins:%u,%u [itype:%u] mA=%d/%d)\n"), + _valid?"S":"Uns", + (int)nr, + (int)bc.count, + (int)bc.type, + (int)_hasRgb, (int)_hasWhite, (int)_hasCCT, + (unsigned)_pins[0], is2Pin(bc.type)?(unsigned)_pins[1]:255U, + (unsigned)_iType, + (int)_milliAmpsPerLed, (int)_milliAmpsMax + ); } //DISCLAIMER @@ -177,7 +188,7 @@ uint8_t BusDigital::estimateCurrentAndLimitBri() { actualMilliampsPerLed = 12; // from testing an actual strip } - size_t powerBudget = (_milliAmpsMax - MA_FOR_ESP/BusManager::getNumBusses()); //80/120mA for ESP power + unsigned powerBudget = (_milliAmpsMax - MA_FOR_ESP/BusManager::getNumBusses()); //80/120mA for ESP power if (powerBudget > getLength()) { //each LED uses about 1mA in standby, exclude that from power budget powerBudget -= getLength(); } else { @@ -202,16 +213,15 @@ uint8_t BusDigital::estimateCurrentAndLimitBri() { } // powerSum has all the values of channels summed (max would be getLength()*765 as white is excluded) so convert to milliAmps - busPowerSum = (busPowerSum * actualMilliampsPerLed) / 765; - _milliAmpsTotal = busPowerSum * _bri / 255; + _milliAmpsTotal = (busPowerSum * actualMilliampsPerLed * _bri) / (765*255); uint8_t newBri = _bri; - if (busPowerSum * _bri / 255 > powerBudget) { //scale brightness down to stay in current limit - float scale = (float)(powerBudget * 255) / (float)(busPowerSum * _bri); - if (scale >= 1.0f) return _bri; - _milliAmpsTotal = ceilf((float)_milliAmpsTotal * scale); - uint8_t scaleB = min((int)(scale * 255), 255); - newBri = unsigned(_bri * scaleB) / 256 + 1; + if (_milliAmpsTotal > powerBudget) { + //scale brightness down to stay in current limit + unsigned scaleB = powerBudget * 255 / _milliAmpsTotal; + newBri = (_bri * scaleB) / 256 + 1; + _milliAmpsTotal = powerBudget; + //_milliAmpsTotal = (busPowerSum * actualMilliampsPerLed * newBri) / (765*255); } return newBri; } @@ -406,8 +416,8 @@ std::vector BusDigital::getLEDTypes() { {TYPE_WS2805, "D", PSTR("WS2805 RGBCW")}, {TYPE_SM16825, "D", PSTR("SM16825 RGBCW")}, {TYPE_WS2812_1CH_X3, "D", PSTR("WS2811 White")}, - //{TYPE_WS2812_2CH_X3, "D", PSTR("WS2811 CCT")}, // not implemented - {TYPE_WS2812_WWA, "D", PSTR("WS2811 WWA")}, // amber ignored + //{TYPE_WS2812_2CH_X3, "D", PSTR("WS281x CCT")}, // not implemented + {TYPE_WS2812_WWA, "D", PSTR("WS281x WWA")}, // amber ignored {TYPE_WS2801, "2P", PSTR("WS2801")}, {TYPE_APA102, "2P", PSTR("APA102")}, {TYPE_LPD8806, "2P", PSTR("LPD8806")}, @@ -428,9 +438,9 @@ void BusDigital::cleanup() { _valid = false; _busPtr = nullptr; if (_data != nullptr) freeData(); - PinManager::deallocateMultiplePins(_pins, 2, PinOwner::BusDigital); - //PinManager::deallocatePin(_pins[1], PinOwner::BusDigital); - //PinManager::deallocatePin(_pins[0], PinOwner::BusDigital); + //PinManager::deallocateMultiplePins(_pins, 2, PinOwner::BusDigital); + PinManager::deallocatePin(_pins[1], PinOwner::BusDigital); + PinManager::deallocatePin(_pins[0], PinOwner::BusDigital); } @@ -782,6 +792,7 @@ std::vector BusNetwork::getLEDTypes() { } void BusNetwork::cleanup() { + DEBUG_PRINTLN(F("Virtual Cleanup.")); _type = I_NONE; _valid = false; freeData(); @@ -819,6 +830,7 @@ unsigned BusManager::getTotalBuffers() { } int BusManager::add(const BusConfig &bc) { + DEBUG_PRINTF_P(PSTR("Bus: Adding bus #%d (%d - %d >= %d)\n"), numBusses, getNumBusses(), getNumVirtualBusses(), WLED_MAX_BUSSES); if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1; if (Bus::isVirtual(bc.type)) { busses[numBusses] = new BusNetwork(bc); @@ -858,6 +870,7 @@ String BusManager::getLEDTypesJSONString() { } void BusManager::useParallelOutput() { + DEBUG_PRINTLN(F("Bus: Enabling parallel I2S.")); PolyBus::setParallelI2S1Output(); } diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index e4536156..1bbe3bcf 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -813,8 +813,19 @@ void serializeConfig() { JsonArray hw_led_ins = hw_led.createNestedArray("ins"); for (size_t s = 0; s < BusManager::getNumBusses(); s++) { + DEBUG_PRINTF_P(PSTR("Cfg: Saving bus #%u\n"), s); Bus *bus = BusManager::getBus(s); if (!bus || bus->getLength()==0) break; + DEBUG_PRINTF_P(PSTR(" (%d-%d, type:%d, CO:%d, rev:%d, skip:%d, AW:%d kHz:%d, mA:%d/%d)\n"), + (int)bus->getStart(), (int)(bus->getStart()+bus->getLength()), + (int)(bus->getType() & 0x7F), + (int)bus->getColorOrder(), + (int)bus->isReversed(), + (int)bus->skippedLeds(), + (int)bus->getAutoWhiteMode(), + (int)bus->getFrequency(), + (int)bus->getLEDCurrent(), (int)bus->getMaxCurrent() + ); JsonObject ins = hw_led_ins.createNestedObject(); ins["start"] = bus->getStart(); ins["len"] = bus->getLength(); From 5bd0a261260f0130550cb431da24fe7935c53b09 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Mon, 13 Jan 2025 16:39:58 +0000 Subject: [PATCH 156/463] Remove platform_package override --- platformio.ini | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/platformio.ini b/platformio.ini index f3e11ce3..6fdaef32 100644 --- a/platformio.ini +++ b/platformio.ini @@ -273,8 +273,9 @@ board_build.partitions = ${esp32.default_partitions} ;; default partioning for ;; ;; please note that you can NOT update existing ESP32 installs with a "V4" build. Also updating by OTA will not work properly. ;; You need to completely erase your device (esptool erase_flash) first, then install the "V4" build from VSCode+platformio. + +;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them) platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.06.02/platform-espressif32.zip ;; Tasmota Arduino Core 2.0.9 with IPv6 support, based on IDF 4.4.4 -platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them) build_unflags = ${common.build_unflags} build_flags = -g -Wshadow=compatible-local ;; emit warning in case a local variable "shadows" another local one @@ -289,7 +290,6 @@ board_build.partitions = ${esp32.default_partitions} ;; default partioning for [esp32s2] ;; generic definitions for all ESP32-S2 boards platform = ${esp32_idf_V4.platform} -platform_packages = ${esp32_idf_V4.platform_packages} build_unflags = ${common.build_unflags} build_flags = -g -DARDUINO_ARCH_ESP32 @@ -309,7 +309,6 @@ board_build.partitions = ${esp32.default_partitions} ;; default partioning for [esp32c3] ;; generic definitions for all ESP32-C3 boards platform = ${esp32_idf_V4.platform} -platform_packages = ${esp32_idf_V4.platform_packages} build_unflags = ${common.build_unflags} build_flags = -g -DARDUINO_ARCH_ESP32 @@ -328,7 +327,6 @@ board_build.partitions = ${esp32.default_partitions} ;; default partioning for [esp32s3] ;; generic definitions for all ESP32-S3 boards platform = ${esp32_idf_V4.platform} -platform_packages = ${esp32_idf_V4.platform_packages} build_unflags = ${common.build_unflags} build_flags = -g -DESP32 @@ -435,7 +433,6 @@ board_build.partitions = ${esp32.default_partitions} [env:esp32dev_V4] board = esp32dev platform = ${esp32_idf_V4.platform} -; platform_packages = ${esp32_idf_V4.platform_packages} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_V4\" #-D WLED_DISABLE_BROWNOUT_DET ${esp32.AR_build_flags} @@ -447,7 +444,6 @@ board_build.partitions = ${esp32.default_partitions} [env:esp32dev_8M] board = esp32dev platform = ${esp32_idf_V4.platform} -platform_packages = ${esp32_idf_V4.platform_packages} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_8M\" #-D WLED_DISABLE_BROWNOUT_DET ${esp32.AR_build_flags} @@ -463,7 +459,6 @@ board_upload.maximum_size = 8388608 [env:esp32dev_16M] board = esp32dev platform = ${esp32_idf_V4.platform} -platform_packages = ${esp32_idf_V4.platform_packages} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_16M\" #-D WLED_DISABLE_BROWNOUT_DET ${esp32.AR_build_flags} @@ -506,7 +501,6 @@ board_build.partitions = ${esp32.default_partitions} [env:esp32_wrover] extends = esp32_idf_V4 platform = ${esp32_idf_V4.platform} -platform_packages = ${esp32_idf_V4.platform_packages} board = ttgo-t7-v14-mini32 board_build.f_flash = 80000000L board_build.flash_mode = qio From f240a33935ce168608dfa007ecdc331ff97efc98 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Mon, 13 Jan 2025 18:33:30 +0000 Subject: [PATCH 157/463] Remove platform_package override --- platformio.ini | 6 ------ 1 file changed, 6 deletions(-) diff --git a/platformio.ini b/platformio.ini index 6fdaef32..73a76f05 100644 --- a/platformio.ini +++ b/platformio.ini @@ -516,7 +516,6 @@ lib_deps = ${esp32_idf_V4.lib_deps} [env:esp32c3dev] extends = esp32c3 platform = ${esp32c3.platform} -platform_packages = ${esp32c3.platform_packages} framework = arduino board = esp32-c3-devkitm-1 board_build.partitions = ${esp32.default_partitions} @@ -534,7 +533,6 @@ lib_deps = ${esp32c3.lib_deps} board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support board_build.arduino.memory_type = qio_opi ;; use with PSRAM: 8MB or 16MB platform = ${esp32s3.platform} -platform_packages = ${esp32s3.platform_packages} upload_speed = 921600 build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_16MB_opi\" @@ -557,7 +555,6 @@ monitor_filters = esp32_exception_decoder board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support board_build.arduino.memory_type = qio_opi ;; use with PSRAM: 8MB or 16MB platform = ${esp32s3.platform} -platform_packages = ${esp32s3.platform_packages} upload_speed = 921600 build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_8MB_opi\" @@ -577,7 +574,6 @@ monitor_filters = esp32_exception_decoder ;; For ESP32-S3 WROOM-2, a.k.a. ESP32-S3 DevKitC-1 v1.1 ;; with >= 16MB FLASH and >= 8MB PSRAM (memory_type: opi_opi) platform = ${esp32s3.platform} -platform_packages = ${esp32s3.platform_packages} board = esp32s3camlcd ;; this is the only standard board with "opi_opi" board_build.arduino.memory_type = opi_opi upload_speed = 921600 @@ -604,7 +600,6 @@ monitor_filters = esp32_exception_decoder ;; ESP32-S3, with 4MB FLASH and <= 4MB PSRAM (memory_type: qio_qspi) board = lolin_s3_mini ;; -S3 mini, 4MB flash 2MB PSRAM platform = ${esp32s3.platform} -platform_packages = ${esp32s3.platform_packages} upload_speed = 921600 build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=\"ESP32-S3_4M_qspi\" @@ -622,7 +617,6 @@ monitor_filters = esp32_exception_decoder [env:lolin_s2_mini] platform = ${esp32s2.platform} -platform_packages = ${esp32s2.platform_packages} board = lolin_s2_mini board_build.partitions = ${esp32.default_partitions} board_build.flash_mode = qio From 7e9f7d410139b6b625610713a4be2e0945f3c50c Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Mon, 13 Jan 2025 18:39:21 +0000 Subject: [PATCH 158/463] set board_build.flash_mode to fix missing sdkconfig.h --- platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio.ini b/platformio.ini index 73a76f05..d6788a0f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -440,6 +440,7 @@ lib_deps = ${esp32_idf_V4.lib_deps} ${esp32.AR_lib_deps} monitor_filters = esp32_exception_decoder board_build.partitions = ${esp32.default_partitions} +board_build.flash_mode = qio ;; TODO: is this the correct flash mode? [env:esp32dev_8M] board = esp32dev From 1ed82426a1c23745a81541e0f3e7a7d83e6a5636 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Mon, 13 Jan 2025 19:30:35 +0000 Subject: [PATCH 159/463] Add esp32dev back to default_envs --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index b7395dde..63433ca7 100644 --- a/platformio.ini +++ b/platformio.ini @@ -10,7 +10,7 @@ # ------------------------------------------------------------------------------ # CI/release binaries -default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev_V4, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover +default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev, esp32dev_V4, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover src_dir = ./wled00 data_dir = ./wled00/data From ca80d0489b552a35be309d47ee3eb7ed5b4f5ad3 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Mon, 13 Jan 2025 20:30:10 +0000 Subject: [PATCH 160/463] Add env:esp8266_2m_tasmota --- platformio.ini | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index d6788a0f..b27525ab 100644 --- a/platformio.ini +++ b/platformio.ini @@ -10,7 +10,7 @@ # ------------------------------------------------------------------------------ # CI/release binaries -default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev_V4, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover +default_envs = nodemcuv2, esp8266_2m, esp8266_2m_tasmota, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev_V4, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover src_dir = ./wled00 data_dir = ./wled00/data @@ -381,6 +381,14 @@ build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP02\" lib_deps = ${esp8266.lib_deps} +[env:esp8266_2m_tasmota] +board = esp_wroom_02 +platform = https://github.com/tasmota/platform-espressif8266#2024.09.00 ;; TODO: not sure this is the correct version +board_build.ldscript = ${common.ldscript_2m512k} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP02_Tasmota\" +lib_deps = ${esp8266.lib_deps} + [env:esp8266_2m_compat] extends = env:esp8266_2m ;; using platform version and build options from WLED 0.14.0 From b421f7ae87aa0c76da34b12ba49dd6fc493e26b1 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Mon, 13 Jan 2025 20:56:48 +0000 Subject: [PATCH 161/463] Update to Tasmota Arduino Core 2.0.18 --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index b27525ab..6db26b2e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -275,7 +275,7 @@ board_build.partitions = ${esp32.default_partitions} ;; default partioning for ;; You need to completely erase your device (esptool erase_flash) first, then install the "V4" build from VSCode+platformio. ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them) -platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.06.02/platform-espressif32.zip ;; Tasmota Arduino Core 2.0.9 with IPv6 support, based on IDF 4.4.4 +platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.06.00/platform-espressif32.zip ;; Tasmota Arduino Core 2.0.18 with IPv6 support, based on IDF 4.4.8 build_unflags = ${common.build_unflags} build_flags = -g -Wshadow=compatible-local ;; emit warning in case a local variable "shadows" another local one From 4e4f823141224435a220412f0c52d54fb64103e2 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Mon, 13 Jan 2025 20:57:49 +0000 Subject: [PATCH 162/463] Update comment --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 6db26b2e..9e221724 100644 --- a/platformio.ini +++ b/platformio.ini @@ -274,7 +274,7 @@ board_build.partitions = ${esp32.default_partitions} ;; default partioning for ;; please note that you can NOT update existing ESP32 installs with a "V4" build. Also updating by OTA will not work properly. ;; You need to completely erase your device (esptool erase_flash) first, then install the "V4" build from VSCode+platformio. -;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them) +;; arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.06.00/platform-espressif32.zip ;; Tasmota Arduino Core 2.0.18 with IPv6 support, based on IDF 4.4.8 build_unflags = ${common.build_unflags} build_flags = -g From f920fdecfe7c67cbc700bacc9f81a4a8a315da5c Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Mon, 13 Jan 2025 21:02:28 +0000 Subject: [PATCH 163/463] Add esp32dev back to default_envs --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 9e221724..701c90d7 100644 --- a/platformio.ini +++ b/platformio.ini @@ -10,7 +10,7 @@ # ------------------------------------------------------------------------------ # CI/release binaries -default_envs = nodemcuv2, esp8266_2m, esp8266_2m_tasmota, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev_V4, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover +default_envs = nodemcuv2, esp8266_2m, esp8266_2m_tasmota, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev, esp32dev_V4, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover src_dir = ./wled00 data_dir = ./wled00/data From 650853c17741323cc46be3652740f6b4877e54d9 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Mon, 13 Jan 2025 21:09:05 +0000 Subject: [PATCH 164/463] Use flash_mode = dio --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 701c90d7..59709eb1 100644 --- a/platformio.ini +++ b/platformio.ini @@ -448,7 +448,7 @@ lib_deps = ${esp32_idf_V4.lib_deps} ${esp32.AR_lib_deps} monitor_filters = esp32_exception_decoder board_build.partitions = ${esp32.default_partitions} -board_build.flash_mode = qio ;; TODO: is this the correct flash mode? +board_build.flash_mode = dio [env:esp32dev_8M] board = esp32dev From b380d5e2c7df29820b91b4d7aa4be7350b8d9a9d Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Tue, 14 Jan 2025 00:10:55 +0000 Subject: [PATCH 165/463] reinstate libArchive:false --- usermods/ADS1115_v2/library.json | 1 + usermods/AHT10_v2/library.json | 1 + usermods/Analog_Clock/library.json | 3 ++- usermods/Animated_Staircase/library.json | 3 ++- usermods/BH1750_v2/library.json | 1 + usermods/BME280_v2/library.json | 3 ++- usermods/BME68X_v2/library.json | 1 + usermods/Battery/library.json | 3 ++- usermods/Cronixie/library.json | 3 ++- usermods/DHT/library.json | 1 + usermods/EleksTube_IPS/library.json | 3 ++- usermods/INA226_v2/library.json | 1 + usermods/Internal_Temperature_v2/library.json | 3 ++- usermods/LD2410_v2/library.json | 3 ++- usermods/LDR_Dusk_Dawn_v2/library.json | 3 ++- usermods/MAX17048_v2/library.json | 1 + usermods/MY9291/library.json | 3 ++- usermods/PIR_sensor_switch/library.json | 3 ++- usermods/PWM_fan/library.json | 3 ++- usermods/RTC/library.json | 3 ++- usermods/SN_Photoresistor/library.json | 3 ++- usermods/ST7789_display/library.json | 3 ++- usermods/Si7021_MQTT_HA/library.json | 3 ++- usermods/Temperature/library.json | 1 + usermods/TetrisAI_v2/library.json | 3 ++- usermods/VL53L0X_gestures/library.json | 1 + usermods/audioreactive/library.json | 1 + usermods/boblight/library.json | 3 ++- usermods/buzzer/library.json | 3 ++- usermods/deep_sleep/library.json | 3 ++- usermods/mpu6050_imu/library.json | 1 + usermods/mqtt_switch_v2/library.json | 3 ++- usermods/multi_relay/library.json | 3 ++- usermods/pixels_dice_tray/library.json | 1 + usermods/pov_display/library.json | 1 + usermods/pwm_outputs/library.json | 3 ++- usermods/quinled-an-penta/library.json | 1 + usermods/rgb-rotary-encoder/library.json | 1 + usermods/sd_card/library.json | 3 ++- usermods/sensors_to_mqtt/library.json | 1 + usermods/seven_segment_display/library.json | 3 ++- usermods/seven_segment_display_reloaded/library.json | 3 ++- usermods/sht/library.json | 3 ++- usermods/smartnest/library.json | 3 ++- usermods/stairway_wipe_basic/library.json | 3 ++- usermods/usermod_rotary_brightness_color/library.json | 3 ++- usermods/usermod_v2_HttpPullLightControl/library.json | 3 ++- usermods/usermod_v2_animartrix/library.json | 1 + usermods/usermod_v2_auto_save/library.json | 3 ++- usermods/usermod_v2_four_line_display_ALT/library.json | 3 ++- usermods/usermod_v2_klipper_percentage/library.json | 3 ++- usermods/usermod_v2_ping_pong_clock/library.json | 3 ++- usermods/usermod_v2_rotary_encoder_ui_ALT/library.json | 3 ++- usermods/usermod_v2_word_clock/library.json | 3 ++- usermods/wireguard/library.json | 1 + usermods/wizlights/library.json | 3 ++- usermods/word-clock-matrix/library.json | 3 ++- 57 files changed, 96 insertions(+), 39 deletions(-) diff --git a/usermods/ADS1115_v2/library.json b/usermods/ADS1115_v2/library.json index 0b93c935..0ce2039f 100644 --- a/usermods/ADS1115_v2/library.json +++ b/usermods/ADS1115_v2/library.json @@ -1,5 +1,6 @@ { "name:": "ADS1115_v2", + "build": { "libArchive": false }, "dependencies": { "Adafruit BusIO": "https://github.com/adafruit/Adafruit_BusIO#1.13.2", "Adafruit ADS1X15": "https://github.com/adafruit/Adafruit_ADS1X15#2.4.0" diff --git a/usermods/AHT10_v2/library.json b/usermods/AHT10_v2/library.json index 94a206c5..b4501ed7 100644 --- a/usermods/AHT10_v2/library.json +++ b/usermods/AHT10_v2/library.json @@ -1,5 +1,6 @@ { "name:": "AHT10_v2", + "build": { "libArchive": false }, "dependencies": { "enjoyneering/AHT10":"~1.1.0" } diff --git a/usermods/Analog_Clock/library.json b/usermods/Analog_Clock/library.json index 4936950e..7a2fc50d 100644 --- a/usermods/Analog_Clock/library.json +++ b/usermods/Analog_Clock/library.json @@ -1,3 +1,4 @@ { - "name:": "Analog_Clock" + "name:": "Analog_Clock", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/Animated_Staircase/library.json b/usermods/Animated_Staircase/library.json index 626baa49..73dc3f1b 100644 --- a/usermods/Animated_Staircase/library.json +++ b/usermods/Animated_Staircase/library.json @@ -1,3 +1,4 @@ { - "name:": "Animated_Staircase" + "name:": "Animated_Staircase", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/BH1750_v2/library.json b/usermods/BH1750_v2/library.json index b7f006cc..2ce4054f 100644 --- a/usermods/BH1750_v2/library.json +++ b/usermods/BH1750_v2/library.json @@ -1,5 +1,6 @@ { "name:": "BH1750_v2", + "build": { "libArchive": false }, "dependencies": { "claws/BH1750":"^1.2.0" } diff --git a/usermods/BME280_v2/library.json b/usermods/BME280_v2/library.json index 126cb362..faae0f34 100644 --- a/usermods/BME280_v2/library.json +++ b/usermods/BME280_v2/library.json @@ -1,3 +1,4 @@ { - "name:": "BME280_v2" + "name:": "BME280_v2", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/BME68X_v2/library.json b/usermods/BME68X_v2/library.json index 3a0e4948..6bd0bb9b 100644 --- a/usermods/BME68X_v2/library.json +++ b/usermods/BME68X_v2/library.json @@ -1,5 +1,6 @@ { "name:": "BME68X_v2", + "build": { "libArchive": false}, "dependencies": { "boschsensortec/BSEC Software Library":"^1.8.1492" } diff --git a/usermods/Battery/library.json b/usermods/Battery/library.json index 3f4774b8..85be8542 100644 --- a/usermods/Battery/library.json +++ b/usermods/Battery/library.json @@ -1,3 +1,4 @@ { - "name:": "Battery" + "name:": "Battery", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/Cronixie/library.json b/usermods/Cronixie/library.json index d4832764..d22bfa45 100644 --- a/usermods/Cronixie/library.json +++ b/usermods/Cronixie/library.json @@ -1,3 +1,4 @@ { - "name:": "Cronixie" + "name:": "Cronixie", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/DHT/library.json b/usermods/DHT/library.json index 5f2d27f0..d61634e9 100644 --- a/usermods/DHT/library.json +++ b/usermods/DHT/library.json @@ -1,5 +1,6 @@ { "name:": "DHT", + "build": { "libArchive": false}, "dependencies": { "DHT_nonblocking":"https://github.com/alwynallan/DHT_nonblocking" } diff --git a/usermods/EleksTube_IPS/library.json b/usermods/EleksTube_IPS/library.json index 27d71861..e5ed6219 100644 --- a/usermods/EleksTube_IPS/library.json +++ b/usermods/EleksTube_IPS/library.json @@ -1,3 +1,4 @@ { - "name:": "EleksTube_IPS" + "name:": "EleksTube_IPS", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/INA226_v2/library.json b/usermods/INA226_v2/library.json index 91a735fe..3633c3a7 100644 --- a/usermods/INA226_v2/library.json +++ b/usermods/INA226_v2/library.json @@ -1,5 +1,6 @@ { "name:": "INA226_v2", + "build": { "libArchive": false}, "dependencies": { "wollewald/INA226_WE":"~1.2.9" } diff --git a/usermods/Internal_Temperature_v2/library.json b/usermods/Internal_Temperature_v2/library.json index 6c165238..dc0ae30a 100644 --- a/usermods/Internal_Temperature_v2/library.json +++ b/usermods/Internal_Temperature_v2/library.json @@ -1,3 +1,4 @@ { - "name:": "Internal_Temperature_v2" + "name:": "Internal_Temperature_v2", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/LD2410_v2/library.json b/usermods/LD2410_v2/library.json index 6fcded02..faef37d4 100644 --- a/usermods/LD2410_v2/library.json +++ b/usermods/LD2410_v2/library.json @@ -1,3 +1,4 @@ { - "name:": "LD2410_v2" + "name:": "LD2410_v2", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/LDR_Dusk_Dawn_v2/library.json b/usermods/LDR_Dusk_Dawn_v2/library.json index bb57dbd2..c5e98620 100644 --- a/usermods/LDR_Dusk_Dawn_v2/library.json +++ b/usermods/LDR_Dusk_Dawn_v2/library.json @@ -1,3 +1,4 @@ { - "name:": "LDR_Dusk_Dawn_v2" + "name:": "LDR_Dusk_Dawn_v2", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/MAX17048_v2/library.json b/usermods/MAX17048_v2/library.json index 14633345..03b9acd9 100644 --- a/usermods/MAX17048_v2/library.json +++ b/usermods/MAX17048_v2/library.json @@ -1,5 +1,6 @@ { "name:": "MAX17048_v2", + "build": { "libArchive": false}, "dependencies": { "Adafruit_MAX1704X":"https://github.com/adafruit/Adafruit_MAX1704X#1.0.2" } diff --git a/usermods/MY9291/library.json b/usermods/MY9291/library.json index 9324e4a0..ddf7aa09 100644 --- a/usermods/MY9291/library.json +++ b/usermods/MY9291/library.json @@ -1,3 +1,4 @@ { - "name:": "MY9291" + "name:": "MY9291", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/PIR_sensor_switch/library.json b/usermods/PIR_sensor_switch/library.json index 0ee7e18b..1c08ccc1 100644 --- a/usermods/PIR_sensor_switch/library.json +++ b/usermods/PIR_sensor_switch/library.json @@ -1,3 +1,4 @@ { - "name:": "PIR_sensor_switch" + "name:": "PIR_sensor_switch", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/PWM_fan/library.json b/usermods/PWM_fan/library.json index 904d7723..67f02620 100644 --- a/usermods/PWM_fan/library.json +++ b/usermods/PWM_fan/library.json @@ -1,3 +1,4 @@ { - "name:": "PWM_fan" + "name:": "PWM_fan", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/RTC/library.json b/usermods/RTC/library.json index e0c527d2..17bc0d53 100644 --- a/usermods/RTC/library.json +++ b/usermods/RTC/library.json @@ -1,3 +1,4 @@ { - "name:": "RTC" + "name:": "RTC", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/SN_Photoresistor/library.json b/usermods/SN_Photoresistor/library.json index 7cac93f8..8e34ed3b 100644 --- a/usermods/SN_Photoresistor/library.json +++ b/usermods/SN_Photoresistor/library.json @@ -1,3 +1,4 @@ { - "name:": "SN_Photoresistor" + "name:": "SN_Photoresistor", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/ST7789_display/library.json b/usermods/ST7789_display/library.json index abcd4635..725e20a6 100644 --- a/usermods/ST7789_display/library.json +++ b/usermods/ST7789_display/library.json @@ -1,3 +1,4 @@ { - "name:": "ST7789_display" + "name:": "ST7789_display", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/Si7021_MQTT_HA/library.json b/usermods/Si7021_MQTT_HA/library.json index 004f9f99..60991a3e 100644 --- a/usermods/Si7021_MQTT_HA/library.json +++ b/usermods/Si7021_MQTT_HA/library.json @@ -1,3 +1,4 @@ { - "name:": "Si7021_MQTT_HA" + "name:": "Si7021_MQTT_HA", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/Temperature/library.json b/usermods/Temperature/library.json index 6a20a7d3..0d9f55cc 100644 --- a/usermods/Temperature/library.json +++ b/usermods/Temperature/library.json @@ -1,5 +1,6 @@ { "name:": "Temperature", + "build": { "libArchive": false}, "dependencies": { "paulstoffregen/OneWire":"~2.3.8" } diff --git a/usermods/TetrisAI_v2/library.json b/usermods/TetrisAI_v2/library.json index 7163dadb..b3282288 100644 --- a/usermods/TetrisAI_v2/library.json +++ b/usermods/TetrisAI_v2/library.json @@ -1,3 +1,4 @@ { - "name:": "TetrisAI_v2" + "name:": "TetrisAI_v2", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/VL53L0X_gestures/library.json b/usermods/VL53L0X_gestures/library.json index 50ff9cb4..db24abd0 100644 --- a/usermods/VL53L0X_gestures/library.json +++ b/usermods/VL53L0X_gestures/library.json @@ -1,5 +1,6 @@ { "name:": "VL53L0X_gestures", + "build": { "libArchive": false}, "dependencies": { "pololu/VL53L0X" : "^1.3.0" } diff --git a/usermods/audioreactive/library.json b/usermods/audioreactive/library.json index 70484d0a..4984a3bc 100644 --- a/usermods/audioreactive/library.json +++ b/usermods/audioreactive/library.json @@ -1,5 +1,6 @@ { "name": "audioreactive", + "build": { "libArchive": false }, "dependencies": [ { "owner": "kosme", diff --git a/usermods/boblight/library.json b/usermods/boblight/library.json index 741d4cb1..34de5c8f 100644 --- a/usermods/boblight/library.json +++ b/usermods/boblight/library.json @@ -1,3 +1,4 @@ { - "name:": "boblight" + "name:": "boblight", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/buzzer/library.json b/usermods/buzzer/library.json index 6bbcdcc3..6208090c 100644 --- a/usermods/buzzer/library.json +++ b/usermods/buzzer/library.json @@ -1,3 +1,4 @@ { - "name:": "buzzer" + "name:": "buzzer", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/deep_sleep/library.json b/usermods/deep_sleep/library.json index c8f66de1..3f4687ef 100644 --- a/usermods/deep_sleep/library.json +++ b/usermods/deep_sleep/library.json @@ -1,3 +1,4 @@ { - "name:": "deep_sleep" + "name:": "deep_sleep", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/mpu6050_imu/library.json b/usermods/mpu6050_imu/library.json index 29562393..3c39de45 100644 --- a/usermods/mpu6050_imu/library.json +++ b/usermods/mpu6050_imu/library.json @@ -1,5 +1,6 @@ { "name:": "mpu6050_imu", + "build": { "libArchive": false}, "dependencies": { "electroniccats/MPU6050":"1.0.1" } diff --git a/usermods/mqtt_switch_v2/library.json b/usermods/mqtt_switch_v2/library.json index cf9abefd..d6032257 100644 --- a/usermods/mqtt_switch_v2/library.json +++ b/usermods/mqtt_switch_v2/library.json @@ -1,3 +1,4 @@ { - "name:": "mqtt_switch_v2" + "name:": "mqtt_switch_v2", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/multi_relay/library.json b/usermods/multi_relay/library.json index 7aa76439..cb9437e6 100644 --- a/usermods/multi_relay/library.json +++ b/usermods/multi_relay/library.json @@ -1,3 +1,4 @@ { - "name:": "multi_relay" + "name:": "multi_relay", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/pixels_dice_tray/library.json b/usermods/pixels_dice_tray/library.json index fd6a53a5..ce08b801 100644 --- a/usermods/pixels_dice_tray/library.json +++ b/usermods/pixels_dice_tray/library.json @@ -1,5 +1,6 @@ { "name:": "pixels_dice_tray", + "build": { "libArchive": false}, "dependencies": { "arduino-pixels-dice":"https://github.com/axlan/arduino-pixels-dice.git" } diff --git a/usermods/pov_display/library.json b/usermods/pov_display/library.json index 298739b5..2dd944a8 100644 --- a/usermods/pov_display/library.json +++ b/usermods/pov_display/library.json @@ -1,5 +1,6 @@ { "name:": "pov_display", + "build": { "libArchive": false}, "dependencies": { "bitbank2/PNGdec":"^1.0.3" } diff --git a/usermods/pwm_outputs/library.json b/usermods/pwm_outputs/library.json index 4bf07777..bdb9937e 100644 --- a/usermods/pwm_outputs/library.json +++ b/usermods/pwm_outputs/library.json @@ -1,3 +1,4 @@ { - "name:": "pwm_outputs" + "name:": "pwm_outputs", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/quinled-an-penta/library.json b/usermods/quinled-an-penta/library.json index e89dc002..9a1f4e0e 100644 --- a/usermods/quinled-an-penta/library.json +++ b/usermods/quinled-an-penta/library.json @@ -1,5 +1,6 @@ { "name:": "quinled-an-penta", + "build": { "libArchive": false}, "dependencies": { "olikraus/U8g2":"~2.28.8", "robtillaart/SHT85":"~0.3.3" diff --git a/usermods/rgb-rotary-encoder/library.json b/usermods/rgb-rotary-encoder/library.json index 25572e11..b1394ba2 100644 --- a/usermods/rgb-rotary-encoder/library.json +++ b/usermods/rgb-rotary-encoder/library.json @@ -1,5 +1,6 @@ { "name:": "rgb-rotary-encoder", + "build": { "libArchive": false}, "dependencies": { "lennarthennigs/ESP Rotary":"^2.1.1" } diff --git a/usermods/sd_card/library.json b/usermods/sd_card/library.json index 1f123ead..5b8faf16 100644 --- a/usermods/sd_card/library.json +++ b/usermods/sd_card/library.json @@ -1,3 +1,4 @@ { - "name:": "sd_card" + "name:": "sd_card", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/sensors_to_mqtt/library.json b/usermods/sensors_to_mqtt/library.json index 6594152c..29addddc 100644 --- a/usermods/sensors_to_mqtt/library.json +++ b/usermods/sensors_to_mqtt/library.json @@ -1,5 +1,6 @@ { "name:": "sensors_to_mqtt", + "build": { "libArchive": false}, "dependencies": { "adafruit/Adafruit BMP280 Library":"2.1.0", "adafruit/Adafruit CCS811 Library":"1.0.4", diff --git a/usermods/seven_segment_display/library.json b/usermods/seven_segment_display/library.json index 8764e92b..6a306119 100644 --- a/usermods/seven_segment_display/library.json +++ b/usermods/seven_segment_display/library.json @@ -1,3 +1,4 @@ { - "name:": "seven_segment_display" + "name:": "seven_segment_display", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/seven_segment_display_reloaded/library.json b/usermods/seven_segment_display_reloaded/library.json index fdce8b53..5fa5037f 100644 --- a/usermods/seven_segment_display_reloaded/library.json +++ b/usermods/seven_segment_display_reloaded/library.json @@ -1,3 +1,4 @@ { - "name:": "seven_segment_display_reloaded" + "name:": "seven_segment_display_reloaded", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/sht/library.json b/usermods/sht/library.json index 330093bd..2788c34a 100644 --- a/usermods/sht/library.json +++ b/usermods/sht/library.json @@ -1,3 +1,4 @@ { - "name:": "sht" + "name:": "sht", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/smartnest/library.json b/usermods/smartnest/library.json index e2c6ab35..7a9d95dd 100644 --- a/usermods/smartnest/library.json +++ b/usermods/smartnest/library.json @@ -1,3 +1,4 @@ { - "name:": "smartnest" + "name:": "smartnest", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/stairway_wipe_basic/library.json b/usermods/stairway_wipe_basic/library.json index 59cb5da9..801846ea 100644 --- a/usermods/stairway_wipe_basic/library.json +++ b/usermods/stairway_wipe_basic/library.json @@ -1,3 +1,4 @@ { - "name:": "stairway_wipe_basic" + "name:": "stairway_wipe_basic", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/usermod_rotary_brightness_color/library.json b/usermods/usermod_rotary_brightness_color/library.json index 777ec19c..5e669169 100644 --- a/usermods/usermod_rotary_brightness_color/library.json +++ b/usermods/usermod_rotary_brightness_color/library.json @@ -1,3 +1,4 @@ { - "name:": "usermod_rotary_brightness_color" + "name:": "usermod_rotary_brightness_color", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/usermod_v2_HttpPullLightControl/library.json b/usermods/usermod_v2_HttpPullLightControl/library.json index 0f66710b..91735b8c 100644 --- a/usermods/usermod_v2_HttpPullLightControl/library.json +++ b/usermods/usermod_v2_HttpPullLightControl/library.json @@ -1,3 +1,4 @@ { - "name:": "usermod_v2_HttpPullLightControl" + "name:": "usermod_v2_HttpPullLightControl", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/usermod_v2_animartrix/library.json b/usermods/usermod_v2_animartrix/library.json index 4552be33..c9c98c39 100644 --- a/usermods/usermod_v2_animartrix/library.json +++ b/usermods/usermod_v2_animartrix/library.json @@ -1,5 +1,6 @@ { "name": "animartrix", + "build": { "libArchive": false}, "dependencies": { "Animartrix": "https://github.com/netmindz/animartrix.git#b172586" } diff --git a/usermods/usermod_v2_auto_save/library.json b/usermods/usermod_v2_auto_save/library.json index 67b29ca6..b9c39d71 100644 --- a/usermods/usermod_v2_auto_save/library.json +++ b/usermods/usermod_v2_auto_save/library.json @@ -1,3 +1,4 @@ { - "name:": "usermod_v2_auto_save" + "name:": "usermod_v2_auto_save", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/usermod_v2_four_line_display_ALT/library.json b/usermods/usermod_v2_four_line_display_ALT/library.json index 56612c96..33c277bd 100644 --- a/usermods/usermod_v2_four_line_display_ALT/library.json +++ b/usermods/usermod_v2_four_line_display_ALT/library.json @@ -1,3 +1,4 @@ { - "name:": "usermod_v2_four_line_display_ALT" + "name:": "usermod_v2_four_line_display_ALT", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/usermod_v2_klipper_percentage/library.json b/usermods/usermod_v2_klipper_percentage/library.json index b31fb1ad..99e0546c 100644 --- a/usermods/usermod_v2_klipper_percentage/library.json +++ b/usermods/usermod_v2_klipper_percentage/library.json @@ -1,3 +1,4 @@ { - "name:": "usermod_v2_klipper_percentage" + "name:": "usermod_v2_klipper_percentage", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/usermod_v2_ping_pong_clock/library.json b/usermods/usermod_v2_ping_pong_clock/library.json index fe23cd91..b3417b98 100644 --- a/usermods/usermod_v2_ping_pong_clock/library.json +++ b/usermods/usermod_v2_ping_pong_clock/library.json @@ -1,3 +1,4 @@ { - "name:": "usermod_v2_ping_pong_clock" + "name:": "usermod_v2_ping_pong_clock", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/library.json b/usermods/usermod_v2_rotary_encoder_ui_ALT/library.json index 5f857218..065c67d9 100644 --- a/usermods/usermod_v2_rotary_encoder_ui_ALT/library.json +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/library.json @@ -1,3 +1,4 @@ { - "name:": "usermod_v2_rotary_encoder_ui_ALT" + "name:": "usermod_v2_rotary_encoder_ui_ALT", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/usermod_v2_word_clock/library.json b/usermods/usermod_v2_word_clock/library.json index 83c14dc7..9e6a339d 100644 --- a/usermods/usermod_v2_word_clock/library.json +++ b/usermods/usermod_v2_word_clock/library.json @@ -1,3 +1,4 @@ { - "name:": "usermod_v2_word_clock" + "name:": "usermod_v2_word_clock", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/wireguard/library.json b/usermods/wireguard/library.json index 0ebace8b..7c7b17ef 100644 --- a/usermods/wireguard/library.json +++ b/usermods/wireguard/library.json @@ -1,5 +1,6 @@ { "name:": "wireguard", + "build": { "libArchive": false}, "dependencies": { "WireGuard-ESP32-Arduino":"https://github.com/kienvu58/WireGuard-ESP32-Arduino.git" } diff --git a/usermods/wizlights/library.json b/usermods/wizlights/library.json index 687fba0f..38ea759f 100644 --- a/usermods/wizlights/library.json +++ b/usermods/wizlights/library.json @@ -1,3 +1,4 @@ { - "name:": "wizlights" + "name:": "wizlights", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/word-clock-matrix/library.json b/usermods/word-clock-matrix/library.json index d971dfff..12a8bd7f 100644 --- a/usermods/word-clock-matrix/library.json +++ b/usermods/word-clock-matrix/library.json @@ -1,3 +1,4 @@ { - "name:": "word-clock-matrix" + "name:": "word-clock-matrix", + "build": { "libArchive": false } } \ No newline at end of file From 022e4986ee26c80f5fe60f71dc90ef88171c5950 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Tue, 14 Jan 2025 00:24:37 +0000 Subject: [PATCH 166/463] Revert "Update to Tasmota Arduino Core 2.0.18" - Frank says to stay on 2.0.9 This reverts commit b421f7ae87aa0c76da34b12ba49dd6fc493e26b1. --- platformio.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 59709eb1..76783dba 100644 --- a/platformio.ini +++ b/platformio.ini @@ -274,8 +274,8 @@ board_build.partitions = ${esp32.default_partitions} ;; default partioning for ;; please note that you can NOT update existing ESP32 installs with a "V4" build. Also updating by OTA will not work properly. ;; You need to completely erase your device (esptool erase_flash) first, then install the "V4" build from VSCode+platformio. -;; arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them -platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.06.00/platform-espressif32.zip ;; Tasmota Arduino Core 2.0.18 with IPv6 support, based on IDF 4.4.8 +;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them) +platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.06.02/platform-espressif32.zip ;; Tasmota Arduino Core 2.0.9 with IPv6 support, based on IDF 4.4.4 build_unflags = ${common.build_unflags} build_flags = -g -Wshadow=compatible-local ;; emit warning in case a local variable "shadows" another local one From 1dbd7066decf914398d30a092e34625c4cc8b178 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Tue, 14 Jan 2025 00:27:54 +0000 Subject: [PATCH 167/463] Revert LOROL_LITTLEFS hack --- wled00/wled.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/wled00/wled.h b/wled00/wled.h index 5a1a9ff8..ae93d954 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -1,6 +1,3 @@ -// TODO: HACK!! - do not merge -#define LOROL_LITTLEFS 1 - #ifndef WLED_H #define WLED_H /* From e4714870a406674fbe18280a2306a27fc793d00b Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Tue, 14 Jan 2025 00:39:04 +0000 Subject: [PATCH 168/463] typo in usermods/sensors_to_mqtt/library.json --- usermods/sensors_to_mqtt/library.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usermods/sensors_to_mqtt/library.json b/usermods/sensors_to_mqtt/library.json index 29addddc..91118c23 100644 --- a/usermods/sensors_to_mqtt/library.json +++ b/usermods/sensors_to_mqtt/library.json @@ -4,5 +4,5 @@ "dependencies": { "adafruit/Adafruit BMP280 Library":"2.1.0", "adafruit/Adafruit CCS811 Library":"1.0.4", - "adafruit/Adafruit Si7021 Library":"1.4.0 + "adafruit/Adafruit Si7021 Library":"1.4.0" } From 869e275e48e3bb1bd0fce020c9cfcdbd8d5535b3 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Tue, 14 Jan 2025 00:43:59 +0000 Subject: [PATCH 169/463] typo in usermods/sensors_to_mqtt/library.json --- usermods/sensors_to_mqtt/library.json | 1 + 1 file changed, 1 insertion(+) diff --git a/usermods/sensors_to_mqtt/library.json b/usermods/sensors_to_mqtt/library.json index 91118c23..9ce4424e 100644 --- a/usermods/sensors_to_mqtt/library.json +++ b/usermods/sensors_to_mqtt/library.json @@ -5,4 +5,5 @@ "adafruit/Adafruit BMP280 Library":"2.1.0", "adafruit/Adafruit CCS811 Library":"1.0.4", "adafruit/Adafruit Si7021 Library":"1.4.0" + } } From 0b8721c25e635e2b6149455ef63d3d54c20be0d3 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Mon, 13 Jan 2025 21:26:15 -0500 Subject: [PATCH 170/463] Fix usermod libArchive setting Monkey-patch PlatformIO to intercept the build process after library dependencies are loaded, but before the build is fully analyzed. This lets us enforce libArchive=False for usermods without making that setting global across all libraries. The rest of the fixup code is integrated at the same call site for simplicity. --- pio-scripts/fixup_usermods.py | 17 -------------- pio-scripts/load_usermods.py | 44 +++++++++++++++++++++++++++++------ platformio.ini | 1 - 3 files changed, 37 insertions(+), 25 deletions(-) delete mode 100644 pio-scripts/fixup_usermods.py diff --git a/pio-scripts/fixup_usermods.py b/pio-scripts/fixup_usermods.py deleted file mode 100644 index 5b8cddf3..00000000 --- a/pio-scripts/fixup_usermods.py +++ /dev/null @@ -1,17 +0,0 @@ -Import('env') - -# Patch up each usermod's include folders to include anything referenced by wled -# This is because usermods need to include wled.h -lib_builders = env.GetLibBuilders() -um_deps = [dep for dep in lib_builders if "/usermods" in dep.src_dir] -other_deps = [dep for dep in lib_builders if "/usermods" not in dep.src_dir] - -for um in um_deps: - # Add include paths for all non-usermod dependencies - for dep in other_deps: - for dir in dep.get_include_dirs(): - um.env.PrependUnique(CPPPATH=dir) - # Add the wled folder to the include path - um.env.PrependUnique(CPPPATH=env["PROJECT_SRC_DIR"]) - -#raise RuntimeError("debug") diff --git a/pio-scripts/load_usermods.py b/pio-scripts/load_usermods.py index 55b9c4b1..f5307820 100644 --- a/pio-scripts/load_usermods.py +++ b/pio-scripts/load_usermods.py @@ -1,17 +1,19 @@ Import('env') -import os +from pathlib import Path # For OS-agnostic path manipulation -def find_usermod(mod_dir: str, mod: str): +usermod_dir = Path(env["PROJECT_DIR"]) / "usermods" + +def find_usermod(mod: str): """Locate this library in the usermods folder. We do this to avoid needing to rename a bunch of folders; this could be removed later """ # Check name match - mp = f"{mod_dir}/{mod}" - if os.path.exists(mp): + mp = usermod_dir / mod + if mp.exists(): return mp - mp = f"{mod_dir}/usermod_v2_{mod}" - if os.path.exists(mp): + mp = usermod_dir / f"usermod_v2_{mod}" + if mp.exists(): return mp raise RuntimeError(f"Couldn't locate module {mod} in usermods directory!") @@ -21,6 +23,34 @@ if usermods: deps = env.GetProjectOption('lib_deps') src_dir = proj.get("platformio", "src_dir") src_dir = src_dir.replace('\\','/') - mod_paths = {mod: find_usermod(f"{src_dir}/../usermods", mod) for mod in usermods.split(" ")} + mod_paths = {mod: find_usermod(mod) for mod in usermods.split(" ")} usermods = [f"{mod} = symlink://{path}" for mod, path in mod_paths.items()] proj.set("env:" + env['PIOENV'], 'lib_deps', deps + usermods) + + +# Monkey-patch ConfigureProjectLibBuilder to mark up the dependencies +# Save the old value +cpl = env.ConfigureProjectLibBuilder +# Our new wrapper +def cpl_wrapper(env): + result = cpl.clone(env)() + # Update usermod properties + lib_builders = env.GetLibBuilders() + um_deps = [dep for dep in lib_builders if usermod_dir in Path(dep.src_dir).parents] + other_deps = [dep for dep in lib_builders if usermod_dir not in Path(dep.src_dir).parents] + for um in um_deps: + # Add include paths for all non-usermod dependencies + for dep in other_deps: + for dir in dep.get_include_dirs(): + um.env.PrependUnique(CPPPATH=dir) + # Add the wled folder to the include path + um.env.PrependUnique(CPPPATH=env["PROJECT_SRC_DIR"]) + # Make sure we link directly, not through an archive + # Archives drop the .dtor table section we need + build = um._manifest.get("build", {}) + build["libArchive"] = False + um._manifest["build"] = build + return result + +# Replace the old one with ours +env.AddMethod(cpl_wrapper, "ConfigureProjectLibBuilder") diff --git a/platformio.ini b/platformio.ini index a64295e5..93219d2f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -115,7 +115,6 @@ extra_scripts = post:pio-scripts/strip-floats.py pre:pio-scripts/user_config_copy.py pre:pio-scripts/load_usermods.py - post:pio-scripts/fixup_usermods.py pre:pio-scripts/build_ui.py ; post:pio-scripts/obj-dump.py ;; convenience script to create a disassembly dump of the firmware (hardcore debugging) From 4f4476b79f46791a4c146eaad0df80a23871447e Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Tue, 14 Jan 2025 11:53:10 +0000 Subject: [PATCH 171/463] Set new codename --- wled00/wled.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/wled.h b/wled00/wled.h index ae93d954..533b1206 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -269,7 +269,7 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument; // Global Variable definitions WLED_GLOBAL char versionString[] _INIT(TOSTRING(WLED_VERSION)); WLED_GLOBAL char releaseString[] _INIT(WLED_RELEASE_NAME); // must include the quotes when defining, e.g -D WLED_RELEASE_NAME=\"ESP32_MULTI_USREMODS\" -#define WLED_CODENAME "Kōsen" +#define WLED_CODENAME "Niji" // AP and OTA default passwords (for maximum security change them!) WLED_GLOBAL char apPass[65] _INIT(WLED_AP_PASS); From bd00d012e22796a5a3580328f4cb3ace93de9230 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Tue, 14 Jan 2025 12:29:03 +0000 Subject: [PATCH 172/463] Remove esp8266_2m_tasmota as not a V4 change and no suitable tasmota build using the currently used Arduino Core version of 3.1.2 --- platformio.ini | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/platformio.ini b/platformio.ini index 59709eb1..069d9c53 100644 --- a/platformio.ini +++ b/platformio.ini @@ -10,7 +10,7 @@ # ------------------------------------------------------------------------------ # CI/release binaries -default_envs = nodemcuv2, esp8266_2m, esp8266_2m_tasmota, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev, esp32dev_V4, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover +default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev, esp32dev_V4, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover src_dir = ./wled00 data_dir = ./wled00/data @@ -381,14 +381,6 @@ build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP02\" lib_deps = ${esp8266.lib_deps} -[env:esp8266_2m_tasmota] -board = esp_wroom_02 -platform = https://github.com/tasmota/platform-espressif8266#2024.09.00 ;; TODO: not sure this is the correct version -board_build.ldscript = ${common.ldscript_2m512k} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME=\"ESP02_Tasmota\" -lib_deps = ${esp8266.lib_deps} - [env:esp8266_2m_compat] extends = env:esp8266_2m ;; using platform version and build options from WLED 0.14.0 From bba5188594364f8e141288f708e7dfaf2b6b5c08 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Tue, 14 Jan 2025 12:43:06 +0000 Subject: [PATCH 173/463] Add the safe option of flash_mode for esp32c3dev, qio also possible --- platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio.ini b/platformio.ini index 48b8c152..33e14799 100644 --- a/platformio.ini +++ b/platformio.ini @@ -528,6 +528,7 @@ build_flags = ${common.build_flags} ${esp32c3.build_flags} -D WLED_RELEASE_NAME= upload_speed = 460800 build_unflags = ${common.build_unflags} lib_deps = ${esp32c3.lib_deps} +board_build.flash_mode = dio [env:esp32s3dev_16MB_opi] ;; ESP32-S3 development board, with 16MB FLASH and >= 8MB PSRAM (memory_type: qio_opi) From a37b953e7293a3af9a327fdc539829cab3b878ff Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Tue, 14 Jan 2025 12:44:40 +0000 Subject: [PATCH 174/463] Set flash_mode to qio for esp32c3dev to maintain current behaviour --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 33e14799..9b9b693f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -528,7 +528,7 @@ build_flags = ${common.build_flags} ${esp32c3.build_flags} -D WLED_RELEASE_NAME= upload_speed = 460800 build_unflags = ${common.build_unflags} lib_deps = ${esp32c3.lib_deps} -board_build.flash_mode = dio +board_build.flash_mode = qio [env:esp32s3dev_16MB_opi] ;; ESP32-S3 development board, with 16MB FLASH and >= 8MB PSRAM (memory_type: qio_opi) From 881da25e8c6642c9df347b03f8d0253a1c1aee9d Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Tue, 14 Jan 2025 18:06:51 +0000 Subject: [PATCH 175/463] Add local defintion of lolin_s3_mini as missing from Tasmota platform --- boards/lolin_s3_mini.json | 47 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 boards/lolin_s3_mini.json diff --git a/boards/lolin_s3_mini.json b/boards/lolin_s3_mini.json new file mode 100644 index 00000000..7f55f0bd --- /dev/null +++ b/boards/lolin_s3_mini.json @@ -0,0 +1,47 @@ +{ + "build": { + "arduino": { + "ldscript": "esp32s3_out.ld", + "memory_type": "qio_qspi" + }, + "core": "esp32", + "extra_flags": [ + "-DBOARD_HAS_PSRAM", + "-DARDUINO_LOLIN_S3_MINI", + "-DARDUINO_USB_MODE=1" + ], + "f_cpu": "240000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "hwids": [ + [ + "0x303A", + "0x8167" + ] + ], + "mcu": "esp32s3", + "variant": "lolin_s3_mini" + }, + "connectivity": [ + "bluetooth", + "wifi" + ], + "debug": { + "openocd_target": "esp32s3.cfg" + }, + "frameworks": [ + "arduino", + "espidf" + ], + "name": "WEMOS LOLIN S3 Mini", + "upload": { + "flash_size": "4MB", + "maximum_ram_size": 327680, + "maximum_size": 4194304, + "require_upload_port": true, + "speed": 460800 + }, + "url": "https://www.wemos.cc/en/latest/s3/index.html", + "vendor": "WEMOS" +} + \ No newline at end of file From d4ba603cf745de2f88a39e7cf13a8967073ab64b Mon Sep 17 00:00:00 2001 From: Christian Schwinne Date: Tue, 19 Mar 2024 22:39:33 +0100 Subject: [PATCH 176/463] Update pio version --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 666122aa..ee70cd68 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.12 +# This file is autogenerated by pip-compile with Python 3.11 # by the following command: # # pip-compile From 7c03f716a8eb2b167ae337e3263ed088827c7661 Mon Sep 17 00:00:00 2001 From: Christian Schwinne Date: Tue, 19 Mar 2024 22:53:43 +0100 Subject: [PATCH 177/463] Include gif library for all esp32 variants --- platformio.ini | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/platformio.ini b/platformio.ini index 2c7d1442..00df6666 100644 --- a/platformio.ini +++ b/platformio.ini @@ -238,6 +238,11 @@ lib_deps_compat = https://github.com/blazoncek/QuickESPNow.git#optional-debug https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.2.1 +[esp32_all_variants] +lib_deps = + https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 + bitbank2/AnimatedGIF@^1.4.7 + https://github.com/Aircoookie/GifDecoder#bc3af18 [esp32] #platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.3/platform-espressif32-2.0.2.3.zip @@ -259,9 +264,7 @@ large_partitions = tools/WLED_ESP32_8MB.csv extreme_partitions = tools/WLED_ESP32_16MB_9MB_FS.csv lib_deps = https://github.com/lorol/LITTLEFS.git - https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 - bitbank2/AnimatedGIF@^1.4.7 - https://github.com/Aircoookie/GifDecoder#bc3af18 + ${esp32_all_variants.lib_deps} ${env.lib_deps} # additional build flags for audioreactive AR_build_flags = -D USERMOD_AUDIOREACTIVE @@ -284,7 +287,7 @@ build_flags = -g -D CONFIG_ASYNC_TCP_USE_WDT=0 -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3 lib_deps = - https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 + ${esp32_all_variants.lib_deps} ${env.lib_deps} board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs @@ -304,7 +307,7 @@ build_flags = -g ;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry: ;; ARDUINO_USB_CDC_ON_BOOT lib_deps = - https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 + ${esp32_all_variants.lib_deps} ${env.lib_deps} board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs @@ -323,7 +326,7 @@ build_flags = -g ;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry: ;; ARDUINO_USB_CDC_ON_BOOT lib_deps = - https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 + ${esp32_all_variants.lib_deps} ${env.lib_deps} board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs @@ -343,7 +346,7 @@ build_flags = -g ;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry: ;; ARDUINO_USB_MODE, ARDUINO_USB_CDC_ON_BOOT lib_deps = - https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 + ${esp32_all_variants.lib_deps} ${env.lib_deps} board_build.partitions = ${esp32.large_partitions} ;; default partioning for 8MB flash - can be overridden in build envs From e852df3179641ef9fe411608d69090aa1c2a5f4a Mon Sep 17 00:00:00 2001 From: Christian Schwinne Date: Sat, 13 Apr 2024 20:06:33 +0200 Subject: [PATCH 178/463] Proper debug statements --- wled00/image_loader.cpp | 144 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 wled00/image_loader.cpp diff --git a/wled00/image_loader.cpp b/wled00/image_loader.cpp new file mode 100644 index 00000000..31a84e66 --- /dev/null +++ b/wled00/image_loader.cpp @@ -0,0 +1,144 @@ +#include "wled.h" + +#ifndef WLED_DISABLE_GIF + +#include "GifDecoder.h" + + +/* + * Functions to render images from filesystem to segments, used by the "Image" effect + */ + +File file; +char lastFilename[34] = "/"; +GifDecoder<320,320,12,true> decoder; +bool gifDecodeFailed = false; +unsigned long lastFrameDisplayTime = 0, currentFrameDelay = 0; + +bool fileSeekCallback(unsigned long position) { + return file.seek(position); +} + +unsigned long filePositionCallback(void) { + return file.position(); +} + +int fileReadCallback(void) { + return file.read(); +} + +int fileReadBlockCallback(void * buffer, int numberOfBytes) { + return file.read((uint8_t*)buffer, numberOfBytes); +} + +int fileSizeCallback(void) { + return file.size(); +} + +bool openGif(const char *filename) { + file = WLED_FS.open(filename, "r"); + + if (!file) return false; + return true; +} + +Segment* activeSeg; +uint16_t gifWidth, gifHeight; + +void screenClearCallback(void) { + activeSeg->fill(0); +} + +void updateScreenCallback(void) {} + +void drawPixelCallback(int16_t x, int16_t y, uint8_t red, uint8_t green, uint8_t blue) { + // simple nearest-neighbor scaling + int16_t outY = y * activeSeg->height() / gifHeight; + int16_t outX = x * activeSeg->width() / gifWidth; + // set multiple pixels if upscaling + for (int16_t i = 0; i < (activeSeg->width()+(gifWidth-1)) / gifWidth; i++) { + for (int16_t j = 0; j < (activeSeg->height()+(gifHeight-1)) / gifHeight; j++) { + activeSeg->setPixelColorXY(outX + i, outY + j, gamma8(red), gamma8(green), gamma8(blue)); + } + } +} + +#define IMAGE_ERROR_NONE 0 +#define IMAGE_ERROR_NO_NAME 1 +#define IMAGE_ERROR_SEG_LIMIT 2 +#define IMAGE_ERROR_UNSUPPORTED_FORMAT 3 +#define IMAGE_ERROR_FILE_MISSING 4 +#define IMAGE_ERROR_DECODER_ALLOC 5 +#define IMAGE_ERROR_GIF_DECODE 6 +#define IMAGE_ERROR_FRAME_DECODE 7 +#define IMAGE_ERROR_WAITING 254 +#define IMAGE_ERROR_PREV 255 + +// renders an image (.gif only; .bmp and .fseq to be added soon) from FS to a segment +byte renderImageToSegment(Segment &seg) { + if (!seg.name) return IMAGE_ERROR_NO_NAME; + // disable during effect transition, causes flickering, multiple allocations and depending on image, part of old FX remaining + if (seg.mode != seg.currentMode()) return IMAGE_ERROR_WAITING; + if (activeSeg && activeSeg != &seg) return IMAGE_ERROR_SEG_LIMIT; // only one segment at a time + activeSeg = &seg; + + if (strncmp(lastFilename +1, seg.name, 32) != 0) { // segment name changed, load new image + strncpy(lastFilename +1, seg.name, 32); + gifDecodeFailed = false; + if (strcmp(lastFilename + strlen(lastFilename) - 4, ".gif") != 0) { + gifDecodeFailed = true; + return IMAGE_ERROR_UNSUPPORTED_FORMAT; + } + if (file) file.close(); + openGif(lastFilename); + if (!file) { gifDecodeFailed = true; return IMAGE_ERROR_FILE_MISSING; } + decoder.setScreenClearCallback(screenClearCallback); + decoder.setUpdateScreenCallback(updateScreenCallback); + decoder.setDrawPixelCallback(drawPixelCallback); + decoder.setFileSeekCallback(fileSeekCallback); + decoder.setFilePositionCallback(filePositionCallback); + decoder.setFileReadCallback(fileReadCallback); + decoder.setFileReadBlockCallback(fileReadBlockCallback); + decoder.setFileSizeCallback(fileSizeCallback); + decoder.alloc(); + DEBUG_PRINTLN(F("Starting decoding")); + if(decoder.startDecoding() < 0) { gifDecodeFailed = true; return IMAGE_ERROR_GIF_DECODE; } + DEBUG_PRINTLN(F("Decoding started")); + } + + if (gifDecodeFailed) return IMAGE_ERROR_PREV; + if (!file) { gifDecodeFailed = true; return IMAGE_ERROR_FILE_MISSING; } + //if (!decoder) { gifDecodeFailed = true; return IMAGE_ERROR_DECODER_ALLOC; } + + // speed 0 = half speed, 128 = normal, 255 = full FX FPS + // TODO: 0 = 4x slow, 64 = 2x slow, 128 = normal, 192 = 2x fast, 255 = 4x fast + uint32_t wait = currentFrameDelay * 2 - seg.speed * currentFrameDelay / 128; + + // TODO consider handling this on FX level with a different frametime, but that would cause slow gifs to speed up during transitions + if (millis() - lastFrameDisplayTime < wait) return IMAGE_ERROR_WAITING; + + decoder.getSize(&gifWidth, &gifHeight); + + int result = decoder.decodeFrame(false); + if (result < 0) { gifDecodeFailed = true; return IMAGE_ERROR_FRAME_DECODE; } + + currentFrameDelay = decoder.getFrameDelay_ms(); + unsigned long tooSlowBy = (millis() - lastFrameDisplayTime) - wait; // if last frame was longer than intended, compensate + currentFrameDelay = tooSlowBy > currentFrameDelay ? 0 : currentFrameDelay - tooSlowBy; + lastFrameDisplayTime = millis(); + + return IMAGE_ERROR_NONE; +} + +void endImagePlayback(Segment *seg) { + DEBUG_PRINTLN(F("Image playback end called")); + if (!activeSeg || activeSeg != seg) return; + if (file) file.close(); + decoder.dealloc(); + gifDecodeFailed = false; + activeSeg = nullptr; + lastFilename[1] = '\0'; + DEBUG_PRINTLN(F("Image playback ended")); +} + +#endif \ No newline at end of file From 56b8af86d70b1de414794e70c4875028fdc71967 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Tue, 14 Jan 2025 18:40:41 +0000 Subject: [PATCH 179/463] Swap to WLED_ENABLE_GIF --- wled00/FX.cpp | 4 +++- wled00/FX_fcn.cpp | 2 +- wled00/fcn_declare.h | 2 +- wled00/image_loader.cpp | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 081009f4..22c33356 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -4484,7 +4484,7 @@ static const char _data_FX_MODE_WASHING_MACHINE[] PROGMEM = "Washing Machine@!,! Draws a .gif image from filesystem on the matrix/strip */ uint16_t mode_image(void) { - #ifdef WLED_DISABLE_GIF + #ifndef WLED_ENABLE_GIF return mode_static(); #else renderImageToSegment(SEGMENT); @@ -7755,7 +7755,9 @@ void WS2812FX::setupEffectData() { addEffect(FX_MODE_TWO_DOTS, &mode_two_dots, _data_FX_MODE_TWO_DOTS); addEffect(FX_MODE_FAIRYTWINKLE, &mode_fairytwinkle, _data_FX_MODE_FAIRYTWINKLE); addEffect(FX_MODE_RUNNING_DUAL, &mode_running_dual, _data_FX_MODE_RUNNING_DUAL); + #ifdef WLED_ENABLE_GIF addEffect(FX_MODE_IMAGE, &mode_image, _data_FX_MODE_IMAGE); + #endif addEffect(FX_MODE_TRICOLOR_CHASE, &mode_tricolor_chase, _data_FX_MODE_TRICOLOR_CHASE); addEffect(FX_MODE_TRICOLOR_WIPE, &mode_tricolor_wipe, _data_FX_MODE_TRICOLOR_WIPE); addEffect(FX_MODE_TRICOLOR_FADE, &mode_tricolor_fade, _data_FX_MODE_TRICOLOR_FADE); diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index af277718..97bb99c9 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -195,7 +195,7 @@ void Segment::resetIfRequired() { if (data && _dataLen > 0) memset(data, 0, _dataLen); // prevent heap fragmentation (just erase buffer instead of deallocateData()) next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0; reset = false; - #ifndef WLED_DISABLE_GIF + #ifdef WLED_ENABLE_GIF endImagePlayback(this); #endif } diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index bd45a2f3..cab5941e 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -217,7 +217,7 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len); #include "FX.h" // must be below colors.cpp declarations (potentially due to duplicate declarations of e.g. color_blend) //image_loader.cpp -#ifndef WLED_DISABLE_GIF +#ifdef WLED_ENABLE_GIF bool fileSeekCallback(unsigned long position); unsigned long filePositionCallback(void); int fileReadCallback(void); diff --git a/wled00/image_loader.cpp b/wled00/image_loader.cpp index 31a84e66..96650579 100644 --- a/wled00/image_loader.cpp +++ b/wled00/image_loader.cpp @@ -1,6 +1,6 @@ #include "wled.h" -#ifndef WLED_DISABLE_GIF +#ifdef WLED_ENABLE_GIF #include "GifDecoder.h" From 53c1856038a273906fe5d3b253600f3cf2596250 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Tue, 14 Jan 2025 18:47:06 +0000 Subject: [PATCH 180/463] Enable GIF support for all esp32 builds --- platformio.ini | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/platformio.ini b/platformio.ini index 00df6666..b11343b1 100644 --- a/platformio.ini +++ b/platformio.ini @@ -243,6 +243,8 @@ lib_deps = https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 bitbank2/AnimatedGIF@^1.4.7 https://github.com/Aircoookie/GifDecoder#bc3af18 +build_flags = + -D WLED_ENABLE_GIF [esp32] #platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.3/platform-espressif32-2.0.2.3.zip @@ -256,6 +258,8 @@ build_flags = -g #use LITTLEFS library by lorol in ESP32 core 1.x.x instead of built-in in 2.x.x -D LOROL_LITTLEFS ; -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3 + ${esp32_all_variants.build_flags} + tiny_partitions = tools/WLED_ESP32_2MB_noOTA.csv default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv extended_partitions = tools/WLED_ESP32_4MB_700k_FS.csv @@ -286,6 +290,7 @@ build_flags = -g -DARDUINO_ARCH_ESP32 -DESP32 -D CONFIG_ASYNC_TCP_USE_WDT=0 -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3 + ${esp32_all_variants.build_flags} lib_deps = ${esp32_all_variants.lib_deps} ${env.lib_deps} @@ -306,6 +311,7 @@ build_flags = -g -DARDUINO_USB_MODE=0 ;; this flag is mandatory for ESP32-S2 ! ;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry: ;; ARDUINO_USB_CDC_ON_BOOT + ${esp32_all_variants.build_flags} lib_deps = ${esp32_all_variants.lib_deps} ${env.lib_deps} @@ -325,6 +331,7 @@ build_flags = -g -DARDUINO_USB_MODE=1 ;; this flag is mandatory for ESP32-C3 ;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry: ;; ARDUINO_USB_CDC_ON_BOOT + ${esp32_all_variants.build_flags} lib_deps = ${esp32_all_variants.lib_deps} ${env.lib_deps} @@ -345,6 +352,7 @@ build_flags = -g -DCO ;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry: ;; ARDUINO_USB_MODE, ARDUINO_USB_CDC_ON_BOOT + ${esp32_all_variants.build_flags} lib_deps = ${esp32_all_variants.lib_deps} ${env.lib_deps} From 270d75afe2b7ee624f10546f32877fbe0a062a18 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Tue, 14 Jan 2025 22:16:55 +0000 Subject: [PATCH 181/463] Update usermod deps earlier When processing usermods, update their include path properties before the LDF runs, so it can see through wled.h. --- pio-scripts/load_usermods.py | 112 +++++++++++++++++------------------ 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/pio-scripts/load_usermods.py b/pio-scripts/load_usermods.py index f5307820..81cbc7bf 100644 --- a/pio-scripts/load_usermods.py +++ b/pio-scripts/load_usermods.py @@ -1,56 +1,56 @@ -Import('env') -from pathlib import Path # For OS-agnostic path manipulation - -usermod_dir = Path(env["PROJECT_DIR"]) / "usermods" - -def find_usermod(mod: str): - """Locate this library in the usermods folder. - We do this to avoid needing to rename a bunch of folders; - this could be removed later - """ - # Check name match - mp = usermod_dir / mod - if mp.exists(): - return mp - mp = usermod_dir / f"usermod_v2_{mod}" - if mp.exists(): - return mp - raise RuntimeError(f"Couldn't locate module {mod} in usermods directory!") - -usermods = env.GetProjectOption("custom_usermods","") -if usermods: - proj = env.GetProjectConfig() - deps = env.GetProjectOption('lib_deps') - src_dir = proj.get("platformio", "src_dir") - src_dir = src_dir.replace('\\','/') - mod_paths = {mod: find_usermod(mod) for mod in usermods.split(" ")} - usermods = [f"{mod} = symlink://{path}" for mod, path in mod_paths.items()] - proj.set("env:" + env['PIOENV'], 'lib_deps', deps + usermods) - - -# Monkey-patch ConfigureProjectLibBuilder to mark up the dependencies -# Save the old value -cpl = env.ConfigureProjectLibBuilder -# Our new wrapper -def cpl_wrapper(env): - result = cpl.clone(env)() - # Update usermod properties - lib_builders = env.GetLibBuilders() - um_deps = [dep for dep in lib_builders if usermod_dir in Path(dep.src_dir).parents] - other_deps = [dep for dep in lib_builders if usermod_dir not in Path(dep.src_dir).parents] - for um in um_deps: - # Add include paths for all non-usermod dependencies - for dep in other_deps: - for dir in dep.get_include_dirs(): - um.env.PrependUnique(CPPPATH=dir) - # Add the wled folder to the include path - um.env.PrependUnique(CPPPATH=env["PROJECT_SRC_DIR"]) - # Make sure we link directly, not through an archive - # Archives drop the .dtor table section we need - build = um._manifest.get("build", {}) - build["libArchive"] = False - um._manifest["build"] = build - return result - -# Replace the old one with ours -env.AddMethod(cpl_wrapper, "ConfigureProjectLibBuilder") +Import('env') +from pathlib import Path # For OS-agnostic path manipulation + +usermod_dir = Path(env["PROJECT_DIR"]) / "usermods" + +def find_usermod(mod: str): + """Locate this library in the usermods folder. + We do this to avoid needing to rename a bunch of folders; + this could be removed later + """ + # Check name match + mp = usermod_dir / mod + if mp.exists(): + return mp + mp = usermod_dir / f"usermod_v2_{mod}" + if mp.exists(): + return mp + raise RuntimeError(f"Couldn't locate module {mod} in usermods directory!") + +usermods = env.GetProjectOption("custom_usermods","") +if usermods: + proj = env.GetProjectConfig() + deps = env.GetProjectOption('lib_deps') + src_dir = proj.get("platformio", "src_dir") + src_dir = src_dir.replace('\\','/') + mod_paths = {mod: find_usermod(mod) for mod in usermods.split(" ")} + usermods = [f"{mod} = symlink://{path}" for mod, path in mod_paths.items()] + proj.set("env:" + env['PIOENV'], 'lib_deps', deps + usermods) + + +# Monkey-patch ConfigureProjectLibBuilder to mark up the dependencies +# Save the old value +cpl = env.ConfigureProjectLibBuilder +# Our new wrapper +def cpl_wrapper(env): + # Update usermod properties + lib_builders = env.GetLibBuilders() + um_deps = [dep for dep in lib_builders if usermod_dir in Path(dep.src_dir).parents] + other_deps = [dep for dep in lib_builders if usermod_dir not in Path(dep.src_dir).parents] + for um in um_deps: + # Add include paths for all non-usermod dependencies + for dep in other_deps: + for dir in dep.get_include_dirs(): + um.env.PrependUnique(CPPPATH=dir) + # Add the wled folder to the include path + um.env.PrependUnique(CPPPATH=env["PROJECT_SRC_DIR"]) + # Make sure we link directly, not through an archive + # Archives drop the .dtor table section we need + build = um._manifest.get("build", {}) + build["libArchive"] = False + um._manifest["build"] = build + return cpl.clone(env)() + + +# Replace the old one with ours +env.AddMethod(cpl_wrapper, "ConfigureProjectLibBuilder") From 8fd905215f4734616d31c8ba0755ada097b91d99 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Tue, 14 Jan 2025 22:21:26 +0000 Subject: [PATCH 182/463] Integrate usermods environment Move the "all usermods" logic in to the platformio script, so the 'usermods' environment can be built in any checkout without extra setup commands. --- .github/workflows/build.yml | 5 ----- pio-scripts/load_usermods.py | 5 +++++ platformio.ini | 1 + usermods/platformio_override.usermods.ini | 9 --------- 4 files changed, 6 insertions(+), 14 deletions(-) delete mode 100644 usermods/platformio_override.usermods.ini diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index efdb3f7a..3de08ff7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -57,11 +57,6 @@ jobs: cache: 'pip' - name: Install PlatformIO run: pip install -r requirements.txt - - name: Add usermods environment - run: | - cp -v usermods/platformio_override.usermods.ini platformio_override.ini - echo -n "custom_usermods = " >> platformio_override.ini - find usermods/ -name library.json | xargs dirname | xargs -n 1 basename | xargs echo >> platformio_override.ini - name: Build firmware run: pio run -e ${{ matrix.environment }} diff --git a/pio-scripts/load_usermods.py b/pio-scripts/load_usermods.py index 81cbc7bf..76359a7a 100644 --- a/pio-scripts/load_usermods.py +++ b/pio-scripts/load_usermods.py @@ -2,6 +2,11 @@ Import('env') from pathlib import Path # For OS-agnostic path manipulation usermod_dir = Path(env["PROJECT_DIR"]) / "usermods" +all_usermods = [f for f in usermod_dir.iterdir() if f.is_dir() and f.joinpath('library.json').exists()] + +if env['PIOENV'] == "usermods": + # Add all usermods + env.GetProjectConfig().set(f"env:usermods", 'custom_usermods', " ".join([f.name for f in all_usermods])) def find_usermod(mod: str): """Locate this library in the usermods folder. diff --git a/platformio.ini b/platformio.ini index 93219d2f..57919e2d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -632,3 +632,4 @@ build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"USERMODS\" ${esp32.AR_build_flags} lib_deps = ${esp32.lib_deps} +board_build.partitions = ${esp32.big_partitions} diff --git a/usermods/platformio_override.usermods.ini b/usermods/platformio_override.usermods.ini deleted file mode 100644 index 3b3e6696..00000000 --- a/usermods/platformio_override.usermods.ini +++ /dev/null @@ -1,9 +0,0 @@ -[env:usermods] -board = esp32dev -platform = ${esp32.platform} -platform_packages = ${esp32.platform_packages} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"USERMODS\" - ${esp32.AR_build_flags} -lib_deps = ${esp32.lib_deps} -board_build.partitions = ${esp32.big_partitions} From 30559cd2d3a1478708f998de257ccb29d5eeb3d1 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Tue, 14 Jan 2025 22:21:41 +0000 Subject: [PATCH 183/463] Fix dependency for EleksTube_IPS usermod --- usermods/EleksTube_IPS/library.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/usermods/EleksTube_IPS/library.json b/usermods/EleksTube_IPS/library.json index e5ed6219..0fc259af 100644 --- a/usermods/EleksTube_IPS/library.json +++ b/usermods/EleksTube_IPS/library.json @@ -1,4 +1,7 @@ { "name:": "EleksTube_IPS", - "build": { "libArchive": false } -} \ No newline at end of file + "build": { "libArchive": false }, + "dependencies": { + "TFT_eSPI" : "2.5.33" + } +} From 32607ee74c280d741f2d0a56b96c3f31df7c7c0e Mon Sep 17 00:00:00 2001 From: Will Miles Date: Wed, 15 Jan 2025 02:26:26 +0000 Subject: [PATCH 184/463] Revert incorrect testing platformio.ini --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 57919e2d..8d8e7647 100644 --- a/platformio.ini +++ b/platformio.ini @@ -417,7 +417,7 @@ build_flags = ${common.build_flags} ${esp8266.build_flags} -D WLED_RELEASE_NAME= board = esp32dev platform = ${esp32.platform} platform_packages = ${esp32.platform_packages} -custom_usermods = audioreactive auto_save animartrix +custom_usermods = audioreactive build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"ESP32\" #-D WLED_DISABLE_BROWNOUT_DET lib_deps = ${esp32.lib_deps} From 2adf745d06e031b763fcf9505ed42ef540d0db24 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 15 Jan 2025 11:22:33 +0000 Subject: [PATCH 185/463] Update env:usermods to use V4 --- platformio.ini | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/platformio.ini b/platformio.ini index dad7007f..5cddbbf9 100644 --- a/platformio.ini +++ b/platformio.ini @@ -427,7 +427,6 @@ board = esp32dev platform = ${esp32_idf_V4.platform} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_V4\" #-D WLED_DISABLE_BROWNOUT_DET - ${esp32.AR_build_flags} lib_deps = ${esp32_idf_V4.lib_deps} ${esp32.AR_lib_deps} monitor_filters = esp32_exception_decoder @@ -628,10 +627,10 @@ lib_deps = ${esp32s2.lib_deps} [env:usermods] board = esp32dev -platform = ${esp32.platform} -platform_packages = ${esp32.platform_packages} +platform = ${esp32_idf_V4.platform} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=\"USERMODS\" - ${esp32.AR_build_flags} -lib_deps = ${esp32.lib_deps} +build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=\"ESP32_USERMODS\" +lib_deps = ${esp32_idf_V4.lib_deps} +monitor_filters = esp32_exception_decoder +board_build.flash_mode = dio board_build.partitions = ${esp32.big_partitions} From 5da380e1b0cda1d44e2d246e097eff4838ed67d5 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 15 Jan 2025 11:28:38 +0000 Subject: [PATCH 186/463] Update dependencies for sensors_to_mqtt --- usermods/sensors_to_mqtt/library.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/usermods/sensors_to_mqtt/library.json b/usermods/sensors_to_mqtt/library.json index 9ce4424e..731f57b2 100644 --- a/usermods/sensors_to_mqtt/library.json +++ b/usermods/sensors_to_mqtt/library.json @@ -2,8 +2,8 @@ "name:": "sensors_to_mqtt", "build": { "libArchive": false}, "dependencies": { - "adafruit/Adafruit BMP280 Library":"2.1.0", - "adafruit/Adafruit CCS811 Library":"1.0.4", - "adafruit/Adafruit Si7021 Library":"1.4.0" + "adafruit/Adafruit BMP280 Library":"2.6.8", + "adafruit/Adafruit CCS811 Library":"1.1.3", + "adafruit/Adafruit Si7021 Library":"1.5.3" } } From 59a79a30da2dd32b261242046db85debd5fac4b6 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 15 Jan 2025 11:34:51 +0000 Subject: [PATCH 187/463] Add deps for usermods/BME280_v2 --- usermods/BME280_v2/library.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/usermods/BME280_v2/library.json b/usermods/BME280_v2/library.json index faae0f34..1cb805d3 100644 --- a/usermods/BME280_v2/library.json +++ b/usermods/BME280_v2/library.json @@ -1,4 +1,7 @@ { "name:": "BME280_v2", - "build": { "libArchive": false } + "build": { "libArchive": false }, + "dependencies": { + "finitespace/BME280":"~3.0.0" + } } \ No newline at end of file From 0afd2fe720c5981cd38b9d90d4bb7187ab8fcdb0 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 15 Jan 2025 12:46:06 +0000 Subject: [PATCH 188/463] Destructor must be public --- usermods/AHT10_v2/AHT10_v2.cpp | 12 ++++++------ usermods/INA226_v2/INA226_v2.cpp | 13 +++++++------ usermods/mqtt_switch_v2/mqtt_switch_v2.cpp | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/usermods/AHT10_v2/AHT10_v2.cpp b/usermods/AHT10_v2/AHT10_v2.cpp index 171e1575..a5d30c0e 100644 --- a/usermods/AHT10_v2/AHT10_v2.cpp +++ b/usermods/AHT10_v2/AHT10_v2.cpp @@ -54,12 +54,6 @@ private: _lastTemperature = 0; } - ~UsermodAHT10() - { - delete _aht; - _aht = nullptr; - } - #ifndef WLED_DISABLE_MQTT void mqttInitialize() { @@ -322,6 +316,12 @@ public: _initDone = true; return configComplete; } + + ~UsermodAHT10() + { + delete _aht; + _aht = nullptr; + } }; const char UsermodAHT10::_name[] PROGMEM = "AHTxx"; diff --git a/usermods/INA226_v2/INA226_v2.cpp b/usermods/INA226_v2/INA226_v2.cpp index 3c79f05b..0284a6fa 100644 --- a/usermods/INA226_v2/INA226_v2.cpp +++ b/usermods/INA226_v2/INA226_v2.cpp @@ -210,12 +210,6 @@ private: } } - ~UsermodINA226() - { - delete _ina226; - _ina226 = nullptr; - } - #ifndef WLED_DISABLE_MQTT void mqttInitialize() { @@ -551,6 +545,13 @@ public: _initDone = true; return configComplete; } + + ~UsermodINA226() + { + delete _ina226; + _ina226 = nullptr; + } + }; const char UsermodINA226::_name[] PROGMEM = "INA226"; diff --git a/usermods/mqtt_switch_v2/mqtt_switch_v2.cpp b/usermods/mqtt_switch_v2/mqtt_switch_v2.cpp index d4d823f3..9c8dd5f0 100644 --- a/usermods/mqtt_switch_v2/mqtt_switch_v2.cpp +++ b/usermods/mqtt_switch_v2/mqtt_switch_v2.cpp @@ -159,5 +159,5 @@ inline void UsermodMqttSwitch::updateState(uint8_t pinNr) } -static UsermodMqttSwitc mqtt_switch_v2; +static UsermodMqttSwitch mqtt_switch_v2; REGISTER_USERMOD(mqtt_switch_v2); \ No newline at end of file From 5d05d7936c238a446ff2b9c76e3f0aa1cf089936 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 15 Jan 2025 12:46:48 +0000 Subject: [PATCH 189/463] Add usermod dependencies --- usermods/LD2410_v2/library.json | 5 ++++- usermods/Si7021_MQTT_HA/library.json | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/usermods/LD2410_v2/library.json b/usermods/LD2410_v2/library.json index faef37d4..60d493ad 100644 --- a/usermods/LD2410_v2/library.json +++ b/usermods/LD2410_v2/library.json @@ -1,4 +1,7 @@ { "name:": "LD2410_v2", - "build": { "libArchive": false } + "build": { "libArchive": false }, + "dependencies": { + "ncmreynolds/ld2410":"^0.1.3" + } } \ No newline at end of file diff --git a/usermods/Si7021_MQTT_HA/library.json b/usermods/Si7021_MQTT_HA/library.json index 60991a3e..8294c126 100644 --- a/usermods/Si7021_MQTT_HA/library.json +++ b/usermods/Si7021_MQTT_HA/library.json @@ -1,4 +1,7 @@ { "name:": "Si7021_MQTT_HA", - "build": { "libArchive": false } + "build": { "libArchive": false }, + "dependencies": { + "finitespace/BME280":"3.0.0" + } } \ No newline at end of file From 8487dd7cfd48eda4450ac3bfa54405e0a964bd17 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 15 Jan 2025 12:49:40 +0000 Subject: [PATCH 190/463] Disable build of usermods that are broken at the moment --- usermods/BME280_v2/{library.json => library.json.disabled} | 0 usermods/BME68X_v2/{library.json => library.json.disabled} | 0 usermods/MAX17048_v2/{library.json => library.json.disabled} | 0 usermods/MY9291/{library.json => library.json.disabled} | 0 usermods/RTC/{library.json => library.json.disabled} | 0 usermods/ST7789_display/{library.json => library.json.disabled} | 0 usermods/pov_display/{library.json => library.json.disabled} | 0 .../rgb-rotary-encoder/{library.json => library.json.disabled} | 0 usermods/sht/{library.json => library.json.disabled} | 0 .../{library.json => library.json.disabled} | 0 .../{library.json => library.json.disabled} | 0 .../word-clock-matrix/{library.json => library.json.disabled} | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename usermods/BME280_v2/{library.json => library.json.disabled} (100%) rename usermods/BME68X_v2/{library.json => library.json.disabled} (100%) rename usermods/MAX17048_v2/{library.json => library.json.disabled} (100%) rename usermods/MY9291/{library.json => library.json.disabled} (100%) rename usermods/RTC/{library.json => library.json.disabled} (100%) rename usermods/ST7789_display/{library.json => library.json.disabled} (100%) rename usermods/pov_display/{library.json => library.json.disabled} (100%) rename usermods/rgb-rotary-encoder/{library.json => library.json.disabled} (100%) rename usermods/sht/{library.json => library.json.disabled} (100%) rename usermods/usermod_v2_HttpPullLightControl/{library.json => library.json.disabled} (100%) rename usermods/usermod_v2_four_line_display_ALT/{library.json => library.json.disabled} (100%) rename usermods/word-clock-matrix/{library.json => library.json.disabled} (100%) diff --git a/usermods/BME280_v2/library.json b/usermods/BME280_v2/library.json.disabled similarity index 100% rename from usermods/BME280_v2/library.json rename to usermods/BME280_v2/library.json.disabled diff --git a/usermods/BME68X_v2/library.json b/usermods/BME68X_v2/library.json.disabled similarity index 100% rename from usermods/BME68X_v2/library.json rename to usermods/BME68X_v2/library.json.disabled diff --git a/usermods/MAX17048_v2/library.json b/usermods/MAX17048_v2/library.json.disabled similarity index 100% rename from usermods/MAX17048_v2/library.json rename to usermods/MAX17048_v2/library.json.disabled diff --git a/usermods/MY9291/library.json b/usermods/MY9291/library.json.disabled similarity index 100% rename from usermods/MY9291/library.json rename to usermods/MY9291/library.json.disabled diff --git a/usermods/RTC/library.json b/usermods/RTC/library.json.disabled similarity index 100% rename from usermods/RTC/library.json rename to usermods/RTC/library.json.disabled diff --git a/usermods/ST7789_display/library.json b/usermods/ST7789_display/library.json.disabled similarity index 100% rename from usermods/ST7789_display/library.json rename to usermods/ST7789_display/library.json.disabled diff --git a/usermods/pov_display/library.json b/usermods/pov_display/library.json.disabled similarity index 100% rename from usermods/pov_display/library.json rename to usermods/pov_display/library.json.disabled diff --git a/usermods/rgb-rotary-encoder/library.json b/usermods/rgb-rotary-encoder/library.json.disabled similarity index 100% rename from usermods/rgb-rotary-encoder/library.json rename to usermods/rgb-rotary-encoder/library.json.disabled diff --git a/usermods/sht/library.json b/usermods/sht/library.json.disabled similarity index 100% rename from usermods/sht/library.json rename to usermods/sht/library.json.disabled diff --git a/usermods/usermod_v2_HttpPullLightControl/library.json b/usermods/usermod_v2_HttpPullLightControl/library.json.disabled similarity index 100% rename from usermods/usermod_v2_HttpPullLightControl/library.json rename to usermods/usermod_v2_HttpPullLightControl/library.json.disabled diff --git a/usermods/usermod_v2_four_line_display_ALT/library.json b/usermods/usermod_v2_four_line_display_ALT/library.json.disabled similarity index 100% rename from usermods/usermod_v2_four_line_display_ALT/library.json rename to usermods/usermod_v2_four_line_display_ALT/library.json.disabled diff --git a/usermods/word-clock-matrix/library.json b/usermods/word-clock-matrix/library.json.disabled similarity index 100% rename from usermods/word-clock-matrix/library.json rename to usermods/word-clock-matrix/library.json.disabled From 39b3e7e5079791e2da00eaa638a65079e1a15a4e Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Wed, 15 Jan 2025 15:17:56 +0100 Subject: [PATCH 191/463] BUGFIX in oscillate FX (#4494) effect was changed from int to uint but it relied on negative numbers. fixed by checking overflow and a cast. --- wled00/FX.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 7bf05458..dba59a5c 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -1827,7 +1827,7 @@ uint16_t mode_oscillate(void) { // if the counter has increased, move the oscillator by the random step if (it != SEGENV.step) oscillators[i].pos += oscillators[i].dir * oscillators[i].speed; oscillators[i].size = SEGLEN/(3+SEGMENT.intensity/8); - if((oscillators[i].dir == -1) && (oscillators[i].pos <= 0)) { + if((oscillators[i].dir == -1) && (oscillators[i].pos > SEGLEN << 1)) { // use integer overflow oscillators[i].pos = 0; oscillators[i].dir = 1; // make bigger steps for faster speeds @@ -1843,7 +1843,7 @@ uint16_t mode_oscillate(void) { for (unsigned i = 0; i < SEGLEN; i++) { uint32_t color = BLACK; for (unsigned j = 0; j < numOscillators; j++) { - if(i >= (unsigned)oscillators[j].pos - oscillators[j].size && i <= oscillators[j].pos + oscillators[j].size) { + if((int)i >= (int)oscillators[j].pos - oscillators[j].size && i <= oscillators[j].pos + oscillators[j].size) { color = (color == BLACK) ? SEGCOLOR(j) : color_blend(color, SEGCOLOR(j), uint8_t(128)); } } From 278d204d1c04766e1313a5b5d8c91bff74079431 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Wed, 15 Jan 2025 20:36:53 +0100 Subject: [PATCH 192/463] merge fix for Deep-Sleep UM --- wled00/usermods_list.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp index 627fa630..3430e337 100644 --- a/wled00/usermods_list.cpp +++ b/wled00/usermods_list.cpp @@ -477,6 +477,6 @@ void registerUsermods() #endif #ifdef USERMOD_DEEP_SLEEP - usermods.add(new DeepSleepUsermod()); + UsermodManager::add(new DeepSleepUsermod()); #endif } From 15edfcd0881de91db4e4c07bee4bdbf9bd37bc45 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Thu, 16 Jan 2025 01:05:12 +0000 Subject: [PATCH 193/463] Fix usermod platformio integration Should now work for new *and* old versions of PlatformIO! --- pio-scripts/load_usermods.py | 72 ++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/pio-scripts/load_usermods.py b/pio-scripts/load_usermods.py index 76359a7a..7aa6c4d8 100644 --- a/pio-scripts/load_usermods.py +++ b/pio-scripts/load_usermods.py @@ -1,5 +1,7 @@ Import('env') +import os.path from pathlib import Path # For OS-agnostic path manipulation +from platformio.package.manager.library import LibraryPackageManager usermod_dir = Path(env["PROJECT_DIR"]) / "usermods" all_usermods = [f for f in usermod_dir.iterdir() if f.is_dir() and f.joinpath('library.json').exists()] @@ -24,38 +26,70 @@ def find_usermod(mod: str): usermods = env.GetProjectOption("custom_usermods","") if usermods: + # Inject usermods in to project lib_deps proj = env.GetProjectConfig() - deps = env.GetProjectOption('lib_deps') + deps = env.GetProjectOption('lib_deps') src_dir = proj.get("platformio", "src_dir") src_dir = src_dir.replace('\\','/') mod_paths = {mod: find_usermod(mod) for mod in usermods.split(" ")} usermods = [f"{mod} = symlink://{path}" for mod, path in mod_paths.items()] - proj.set("env:" + env['PIOENV'], 'lib_deps', deps + usermods) + proj.set("env:" + env['PIOENV'], 'lib_deps', deps + usermods) + # Force usermods to be installed in to the environment build state before the LDF runs + # Otherwise we won't be able to see them until it's too late to change their paths for LDF + # Logic is largely borrowed from PlaformIO internals + not_found_specs = [] + for spec in usermods: + found = False + for storage_dir in env.GetLibSourceDirs(): + #print(f"Checking {storage_dir} for {spec}") + lm = LibraryPackageManager(storage_dir) + if lm.get_package(spec): + #print("Found!") + found = True + break + if not found: + #print("Missing!") + not_found_specs.append(spec) + if not_found_specs: + lm = LibraryPackageManager( + env.subst(os.path.join("$PROJECT_LIBDEPS_DIR", "$PIOENV")) + ) + for spec in not_found_specs: + #print(f"LU: forcing install of {spec}") + lm.install(spec) # Monkey-patch ConfigureProjectLibBuilder to mark up the dependencies # Save the old value -cpl = env.ConfigureProjectLibBuilder +old_ConfigureProjectLibBuilder = env.ConfigureProjectLibBuilder + # Our new wrapper -def cpl_wrapper(env): +def wrapped_ConfigureProjectLibBuilder(xenv): # Update usermod properties - lib_builders = env.GetLibBuilders() - um_deps = [dep for dep in lib_builders if usermod_dir in Path(dep.src_dir).parents] - other_deps = [dep for dep in lib_builders if usermod_dir not in Path(dep.src_dir).parents] - for um in um_deps: - # Add include paths for all non-usermod dependencies - for dep in other_deps: - for dir in dep.get_include_dirs(): - um.env.PrependUnique(CPPPATH=dir) - # Add the wled folder to the include path - um.env.PrependUnique(CPPPATH=env["PROJECT_SRC_DIR"]) - # Make sure we link directly, not through an archive - # Archives drop the .dtor table section we need + # Set libArchive before build actions are added + for um in (um for um in xenv.GetLibBuilders() if usermod_dir in Path(um.src_dir).parents): build = um._manifest.get("build", {}) build["libArchive"] = False um._manifest["build"] = build - return cpl.clone(env)() + # Call the wrapped function + result = old_ConfigureProjectLibBuilder.clone(xenv)() -# Replace the old one with ours -env.AddMethod(cpl_wrapper, "ConfigureProjectLibBuilder") + # Fix up include paths + # In PlatformIO >=6.1.17, this could be done prior to ConfigureProjectLibBuilder + wled_dir = xenv["PROJECT_SRC_DIR"] + lib_builders = xenv.GetLibBuilders() + um_deps = [dep for dep in lib_builders if usermod_dir in Path(dep.src_dir).parents] + other_deps = [dep for dep in lib_builders if usermod_dir not in Path(dep.src_dir).parents] + for um in um_deps: + # Add the wled folder to the include path + um.env.PrependUnique(CPPPATH=wled_dir) + # Add WLED's own dependencies + for dep in other_deps: + for dir in dep.get_include_dirs(): + um.env.PrependUnique(CPPPATH=dir) + + return result + +# Apply the wrapper +env.AddMethod(wrapped_ConfigureProjectLibBuilder, "ConfigureProjectLibBuilder") From 7fcc4a5283b6314d5750a39514479856ae6e0534 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 16 Jan 2025 12:07:52 +0100 Subject: [PATCH 194/463] fix for existing C3 overrides From 356a0d72c33413f65dab759f04d72911e708666d Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 16 Jan 2025 12:11:38 +0100 Subject: [PATCH 195/463] proper fix for existing C3 override envs --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 9b9b693f..6d959fe1 100644 --- a/platformio.ini +++ b/platformio.ini @@ -323,6 +323,7 @@ lib_deps = https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 ${env.lib_deps} board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs +board_build.flash_mode = qio [esp32s3] ;; generic definitions for all ESP32-S3 boards @@ -528,7 +529,6 @@ build_flags = ${common.build_flags} ${esp32c3.build_flags} -D WLED_RELEASE_NAME= upload_speed = 460800 build_unflags = ${common.build_unflags} lib_deps = ${esp32c3.lib_deps} -board_build.flash_mode = qio [env:esp32s3dev_16MB_opi] ;; ESP32-S3 development board, with 16MB FLASH and >= 8MB PSRAM (memory_type: qio_opi) From 702d0851176e73762fce651ad7ff32b357c9f4ee Mon Sep 17 00:00:00 2001 From: Arne Date: Mon, 14 Aug 2023 13:28:34 +0200 Subject: [PATCH 196/463] rename global dmx... variables to dmxInput... This is the first step in supporting both dmx input and dmx output on different pins. --- wled00/cfg.cpp | 12 +++++++++ wled00/dmx.cpp | 67 +++++++++++++++++++++++++++++++++++++++++++++++++ wled00/set.cpp | 6 +++++ wled00/wled.cpp | 5 ++++ wled00/wled.h | 8 +++++- wled00/xml.cpp | 11 ++++++++ 6 files changed, 108 insertions(+), 1 deletion(-) diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 38e804ed..1105077c 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -522,6 +522,13 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { tdd = if_live[F("timeout")] | -1; if (tdd >= 0) realtimeTimeoutMs = tdd * 100; + + #ifdef WLED_ENABLE_DMX_INPUT + CJSON(dmxInputTransmitPin, if_live_dmx[F("inputRxPin")]); + CJSON(dmxInputReceivePin, if_live_dmx[F("inputTxPin")]); + CJSON(dmxInputEnablePin, if_live_dmx[F("enablePin")]); + #endif + CJSON(arlsForceMaxBri, if_live[F("maxbri")]); CJSON(arlsDisableGammaCorrection, if_live[F("no-gc")]); // false CJSON(arlsOffset, if_live[F("offset")]); // 0 @@ -1001,6 +1008,11 @@ void serializeConfig() { if_live_dmx[F("addr")] = DMXAddress; if_live_dmx[F("dss")] = DMXSegmentSpacing; if_live_dmx["mode"] = DMXMode; + #ifdef WLED_ENABLE_DMX_INPUT + if_live_dmx[F("rxPin")] = dmxInputTransmitPin; + if_live_dmx[F("txPin")] = dmxInputReceivePin; + if_live_dmx[F("enablePin")] = dmxInputEnablePin; + #endif if_live[F("timeout")] = realtimeTimeoutMs / 100; if_live[F("maxbri")] = arlsForceMaxBri; diff --git a/wled00/dmx.cpp b/wled00/dmx.cpp index dbe70f2a..305d5130 100644 --- a/wled00/dmx.cpp +++ b/wled00/dmx.cpp @@ -76,3 +76,70 @@ void initDMX() { #endif } #endif + + +#ifdef WLED_ENABLE_DMX_INPUT + +#include + + +dmx_port_t dmxPort = 2; +void initDMX() { +/* Set the DMX hardware pins to the pins that we want to use. */ + if(dmxInputReceivePin > 0) { + USER_PRINTF("Listening for DMX on pin %u\n", dmxInputReceivePin); + dmx_set_pin(dmxPort, dmxInputTransmitPin, dmxInputReceivePin, dmxInputEnablePin); + } + else { + USER_PRINTLN("DMX input disabled due to dmxReceivePin not being set"); + return; + } + + /* Now we can install the DMX driver! We'll tell it which DMX port to use and + which interrupt priority it should have. If you aren't sure which interrupt + priority to use, you can use the macro `DMX_DEFAULT_INTR_FLAG` to set the + interrupt to its default settings.*/ + dmx_driver_install(dmxPort, ESP_INTR_FLAG_LEVEL3); +} + +bool dmxIsConnected = false; +unsigned long dmxLastUpdate = 0; + +void handleDMXInput() { + if(dmxInputReceivePin < 1) { + return; + } + byte dmxdata[DMX_PACKET_SIZE]; + dmx_packet_t packet; + unsigned long now = millis(); + if (dmx_receive(dmxPort, &packet, 0)) { + + /* We should check to make sure that there weren't any DMX errors. */ + if (!packet.err) { + /* If this is the first DMX data we've received, lets log it! */ + if (!dmxIsConnected) { + USER_PRINTLN("DMX is connected!"); + dmxIsConnected = true; + } + + dmx_read(dmxPort, dmxdata, packet.size); + handleDMXData(1, 512, dmxdata, REALTIME_MODE_DMX, 0); + dmxLastUpdate = now; + + } else { + /* Oops! A DMX error occurred! Don't worry, this can happen when you first + connect or disconnect your DMX devices. If you are consistently getting + DMX errors, then something may have gone wrong with your code or + something is seriously wrong with your DMX transmitter. */ + DEBUG_PRINT("A DMX error occurred - "); + DEBUG_PRINTLN(packet.err); + } + } + else if (dmxIsConnected && (now - dmxLastUpdate > 5000)) { + dmxIsConnected = false; + USER_PRINTLN("DMX was disconnected."); + } +} +#else +void initDMX(); +#endif diff --git a/wled00/set.cpp b/wled00/set.cpp index 160eb48f..9a12cdc2 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -420,6 +420,12 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) t = request->arg(F("WO")).toInt(); if (t >= -255 && t <= 255) arlsOffset = t; +#ifdef WLED_ENABLE_DMX_INPUT + dmxInputTransmitPin = request->arg(F("IDMT")).toInt(); + dmxInputReceivePin = request->arg(F("IDMR")).toInt(); + dmxInputEnablePin= request->arg(F("IDME")).toInt(); +#endif + #ifndef WLED_DISABLE_ALEXA alexaEnabled = request->hasArg(F("AL")); strlcpy(alexaInvocationName, request->arg(F("AI")).c_str(), 33); diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 1f978a39..8144b0cd 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -423,6 +423,11 @@ void WLED::setup() #ifdef WLED_ENABLE_DMX //reserve GPIO2 as hardcoded DMX pin PinManager::allocatePin(2, true, PinOwner::DMX); #endif +#ifdef WLED_ENABLE_DMX_INPUT + if(dmxInputTransmitPin > 0) PinManager::allocatePin(dmxInputTransmitPin, true, PinOwner::DMX); + if(dmxInputReceivePin > 0) PinManager::allocatePin(dmxInputReceivePin, true, PinOwner::DMX); + if(dmxInputEnablePin > 0) PinManager::allocatePin(dmxInputEnablePin, true, PinOwner::DMX); +#endif DEBUG_PRINTLN(F("Registering usermods ...")); registerUsermods(); diff --git a/wled00/wled.h b/wled00/wled.h index 533b1206..8adbd1ba 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -459,7 +459,13 @@ WLED_GLOBAL bool arlsForceMaxBri _INIT(false); // enable to f WLED_GLOBAL uint16_t DMXStart _INIT(10); // start address of the first fixture WLED_GLOBAL uint16_t DMXStartLED _INIT(0); // LED from which DMX fixtures start #endif -WLED_GLOBAL uint16_t e131Universe _INIT(1); // settings for E1.31 (sACN) protocol (only DMX_MODE_MULTIPLE_* can span over consecutive universes) +#ifdef WLED_ENABLE_DMX_INPUT + WLED_GLOBAL int dmxInputTransmitPin _INIT(0); + WLED_GLOBAL int dmxInputReceivePin _INIT(0); + WLED_GLOBAL int dmxInputEnablePin _INIT(0); +#endif + +WLED_GLOBAL uint16_t e131Universe _INIT(1); // settings for E1.31 (sACN) protocol (only DMX_MODE_MULTIPLE_* can span over consequtive universes) WLED_GLOBAL uint16_t e131Port _INIT(5568); // DMX in port. E1.31 default is 5568, Art-Net is 6454 WLED_GLOBAL byte e131Priority _INIT(0); // E1.31 port priority (if != 0 priority handling is active) WLED_GLOBAL E131Priority highPriority _INIT(3); // E1.31 highest priority tracking, init = timeout in seconds diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 2a19cdfa..62de5342 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -436,6 +436,17 @@ void getSettingsJS(byte subPage, Print& settingsScript) printSetFormCheckbox(settingsScript,PSTR("ES"),e131SkipOutOfSequence); printSetFormCheckbox(settingsScript,PSTR("EM"),e131Multicast); printSetFormValue(settingsScript,PSTR("EU"),e131Universe); +#ifdef WLED_ENABLE_DMX + oappend(SET_F("hideNoDMX();")); // WLEDMM hide "not compiled in" message +#endif +#ifndef WLED_ENABLE_DMX_INPUT + oappend(SET_F("hideDMXInput();")); // WLEDMM hide "dmx input" settings +#else + oappend(SET_F("hideNoDMXInput();")); // WLEDMM hide "not compiled in" message + sappend('v',SET_F("IDMT"),dmxInputTransmitPin); + sappend('v',SET_F("IDMR"),dmxInputReceivePin); + sappend('v',SET_F("IDME"),dmxInputEnablePin); +#endif printSetFormValue(settingsScript,PSTR("DA"),DMXAddress); printSetFormValue(settingsScript,PSTR("XX"),DMXSegmentSpacing); printSetFormValue(settingsScript,PSTR("PY"),e131Priority); From 9e2268bd74bb35c2695d22668ca191f2242b041d Mon Sep 17 00:00:00 2001 From: Arne Date: Mon, 14 Aug 2023 13:38:04 +0200 Subject: [PATCH 197/463] Adapt to new api of esp_dmx v3.1 --- wled00/dmx.cpp | 55 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/wled00/dmx.cpp b/wled00/dmx.cpp index 305d5130..1bb1b250 100644 --- a/wled00/dmx.cpp +++ b/wled00/dmx.cpp @@ -1,7 +1,7 @@ #include "wled.h" /* - * Support for DMX Output via MAX485. + * Support for DMX input and output via MAX485. * Change the output pin in src/dependencies/ESPDMX.cpp, if needed (ESP8266) * Change the output pin in src/dependencies/SparkFunDMX.cpp, if needed (ESP32) * ESP8266 Library from: @@ -83,36 +83,61 @@ void initDMX() { #include -dmx_port_t dmxPort = 2; +static dmx_port_t dmxInputPort = 2; //TODO make this configurable +bool dmxInputInitialized = false; //true once initDmx finished successfully + void initDMX() { -/* Set the DMX hardware pins to the pins that we want to use. */ - if(dmxInputReceivePin > 0) { + + + if(dmxInputReceivePin > 0 && dmxInputEnablePin > 0 && dmxInputTransmitPin > 0) + { + dmx_config_t config{ + 255, /*alloc_size*/ + 0, /*model_id*/ + RDM_PRODUCT_CATEGORY_FIXTURE, /*product_category*/ + VERSION, /*software_version_id*/ + "undefined", /*software_version_label*/ + 1, /*current_personality*/ + {{15, "WLED Effect Mode"}}, /*personalities*/ + 1, /*personality_count*/ + 1, /*dmx_start_address*/ + }; + const std::string versionString = "WLED_V" + std::to_string(VERSION); + strncpy(config.software_version_label, versionString.c_str(), 32); + config.software_version_label[32] = '\0';//zero termination in case our string was longer than 32 chars + + if(!dmx_driver_install(dmxInputPort, &config, DMX_INTR_FLAGS_DEFAULT)) + { + USER_PRINTF("Error: Failed to install dmx driver\n"); + return; + } + USER_PRINTF("Listening for DMX on pin %u\n", dmxInputReceivePin); - dmx_set_pin(dmxPort, dmxInputTransmitPin, dmxInputReceivePin, dmxInputEnablePin); + USER_PRINTF("Sending DMX on pin %u\n", dmxInputTransmitPin); + USER_PRINTF("DMX enable pin is: %u\n", dmxInputEnablePin); + dmx_set_pin(dmxInputPort, dmxInputTransmitPin, dmxInputReceivePin, dmxInputEnablePin); + + dmxInputInitialized = true; } - else { - USER_PRINTLN("DMX input disabled due to dmxReceivePin not being set"); + else + { + USER_PRINTLN("DMX input disabled due to dmxInputReceivePin, dmxInputEnablePin or dmxInputTransmitPin not set"); return; } - /* Now we can install the DMX driver! We'll tell it which DMX port to use and - which interrupt priority it should have. If you aren't sure which interrupt - priority to use, you can use the macro `DMX_DEFAULT_INTR_FLAG` to set the - interrupt to its default settings.*/ - dmx_driver_install(dmxPort, ESP_INTR_FLAG_LEVEL3); } bool dmxIsConnected = false; unsigned long dmxLastUpdate = 0; void handleDMXInput() { - if(dmxInputReceivePin < 1) { + if(!dmxInputInitialized) { return; } byte dmxdata[DMX_PACKET_SIZE]; dmx_packet_t packet; unsigned long now = millis(); - if (dmx_receive(dmxPort, &packet, 0)) { + if (dmx_receive(dmxInputPort, &packet, 0)) { /* We should check to make sure that there weren't any DMX errors. */ if (!packet.err) { @@ -122,7 +147,7 @@ void handleDMXInput() { dmxIsConnected = true; } - dmx_read(dmxPort, dmxdata, packet.size); + dmx_read(dmxInputPort, dmxdata, packet.size); handleDMXData(1, 512, dmxdata, REALTIME_MODE_DMX, 0); dmxLastUpdate = now; From a0ca243955d6ccefb68be3d6b99c83f7f3400593 Mon Sep 17 00:00:00 2001 From: Arne Date: Mon, 14 Aug 2023 13:58:22 +0200 Subject: [PATCH 198/463] Move dmx_input pin allocations from wled.cpp to dmx.cpp --- wled00/dmx.cpp | 18 +++++++++++++++++- wled00/pin_manager.cpp | 4 +++- wled00/pin_manager.h | 19 ++++++++++--------- wled00/wled.cpp | 3 +++ wled00/xml.cpp | 6 +++--- 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/wled00/dmx.cpp b/wled00/dmx.cpp index 1bb1b250..f2f7d503 100644 --- a/wled00/dmx.cpp +++ b/wled00/dmx.cpp @@ -88,9 +88,25 @@ bool dmxInputInitialized = false; //true once initDmx finished successfully void initDMX() { - if(dmxInputReceivePin > 0 && dmxInputEnablePin > 0 && dmxInputTransmitPin > 0) { + + const managed_pin_type pins[] = { + {dmxInputTransmitPin, false}, //these are not used as gpio pins, this isOutput is always false. + {dmxInputReceivePin, false}, + {dmxInputEnablePin, false} + }; + const bool pinsAllocated = pinManager.allocateMultiplePins(pins, 3, PinOwner::DMX_INPUT); + if(!pinsAllocated) + { + USER_PRINTF("Error: Failed to allocate pins for DMX_INPUT. Pins already in use:\n"); + USER_PRINTF("rx in use by: %s\n", pinManager.getPinOwnerText(dmxInputReceivePin).c_str()); + USER_PRINTF("tx in use by: %s\n", pinManager.getPinOwnerText(dmxInputTransmitPin).c_str()); + USER_PRINTF("en in use by: %s\n", pinManager.getPinOwnerText(dmxInputEnablePin).c_str()); + return; + } + + dmx_config_t config{ 255, /*alloc_size*/ 0, /*model_id*/ diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index 37ebd41e..6f165230 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -141,7 +141,9 @@ bool PinManager::allocateMultiplePins(const managed_pin_type * mptArray, byte ar bool PinManager::allocatePin(byte gpio, bool output, PinOwner tag) { // HW I2C & SPI pins have to be allocated using allocateMultiplePins variant since there is always SCL/SDA pair - if (!isPinOk(gpio, output) || (gpio >= WLED_NUM_PINS) || tag==PinOwner::HW_I2C || tag==PinOwner::HW_SPI) { + // DMX_INPUT pins have to be allocated using allocateMultiplePins variant since there is always RX/TX/EN triple + if (!isPinOk(gpio, output) || (gpio >= WLED_NUM_PINS) || tag==PinOwner::HW_I2C || tag==PinOwner::HW_SPI + || tag==PinOwner::DMX_INPUT) { #ifdef WLED_DEBUG if (gpio < 255) { // 255 (-1) is the "not defined GPIO" if (!isPinOk(gpio, output)) { diff --git a/wled00/pin_manager.h b/wled00/pin_manager.h index c8fb165c..b285b6ee 100644 --- a/wled00/pin_manager.h +++ b/wled00/pin_manager.h @@ -35,15 +35,16 @@ enum struct PinOwner : uint8_t { Ethernet = 0x81, BusDigital = 0x82, BusOnOff = 0x83, - BusPwm = 0x84, // 'BusP' == PWM output using BusPwm - Button = 0x85, // 'Butn' == button from configuration - IR = 0x86, // 'IR' == IR receiver pin from configuration - Relay = 0x87, // 'Rly' == Relay pin from configuration - SPI_RAM = 0x88, // 'SpiR' == SPI RAM - DebugOut = 0x89, // 'Dbg' == debug output always IO1 - DMX = 0x8A, // 'DMX' == hard-coded to IO2 - HW_I2C = 0x8B, // 'I2C' == hardware I2C pins (4&5 on ESP8266, 21&22 on ESP32) - HW_SPI = 0x8C, // 'SPI' == hardware (V)SPI pins (13,14&15 on ESP8266, 5,18&23 on ESP32) + BusPwm = 0x84, // 'BusP' == PWM output using BusPwm + Button = 0x85, // 'Butn' == button from configuration + IR = 0x86, // 'IR' == IR receiver pin from configuration + Relay = 0x87, // 'Rly' == Relay pin from configuration + SPI_RAM = 0x88, // 'SpiR' == SPI RAM + DebugOut = 0x89, // 'Dbg' == debug output always IO1 + DMX = 0x8A, // 'DMX' == hard-coded to IO2 + HW_I2C = 0x8B, // 'I2C' == hardware I2C pins (4&5 on ESP8266, 21&22 on ESP32) + HW_SPI = 0x8C, // 'SPI' == hardware (V)SPI pins (13,14&15 on ESP8266, 5,18&23 on ESP32) + DMX_INPUT = 0x8D, // 'DMX_INPUT' == DMX input via serial // Use UserMod IDs from const.h here UM_Unspecified = USERMOD_ID_UNSPECIFIED, // 0x01 UM_Example = USERMOD_ID_EXAMPLE, // 0x02 // Usermod "usermod_v2_example.h" diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 8144b0cd..a8748162 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -423,11 +423,14 @@ void WLED::setup() #ifdef WLED_ENABLE_DMX //reserve GPIO2 as hardcoded DMX pin PinManager::allocatePin(2, true, PinOwner::DMX); #endif +<<<<<<< HEAD #ifdef WLED_ENABLE_DMX_INPUT if(dmxInputTransmitPin > 0) PinManager::allocatePin(dmxInputTransmitPin, true, PinOwner::DMX); if(dmxInputReceivePin > 0) PinManager::allocatePin(dmxInputReceivePin, true, PinOwner::DMX); if(dmxInputEnablePin > 0) PinManager::allocatePin(dmxInputEnablePin, true, PinOwner::DMX); #endif +======= +>>>>>>> a516a7b8 (Move dmx_input pin allocations from wled.cpp to dmx.cpp) DEBUG_PRINTLN(F("Registering usermods ...")); registerUsermods(); diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 62de5342..5caa7159 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -437,12 +437,12 @@ void getSettingsJS(byte subPage, Print& settingsScript) printSetFormCheckbox(settingsScript,PSTR("EM"),e131Multicast); printSetFormValue(settingsScript,PSTR("EU"),e131Universe); #ifdef WLED_ENABLE_DMX - oappend(SET_F("hideNoDMX();")); // WLEDMM hide "not compiled in" message + settingsScript.print(SET_F("hideNoDMX();")); // hide "not compiled in" message #endif #ifndef WLED_ENABLE_DMX_INPUT - oappend(SET_F("hideDMXInput();")); // WLEDMM hide "dmx input" settings + settingsScript.print(SET_F("hideDMXInput();")); // hide "dmx input" settings #else - oappend(SET_F("hideNoDMXInput();")); // WLEDMM hide "not compiled in" message + settingsScript.print(SET_F("hideNoDMXInput();")); //hide "not comp iled in" message sappend('v',SET_F("IDMT"),dmxInputTransmitPin); sappend('v',SET_F("IDMR"),dmxInputReceivePin); sappend('v',SET_F("IDME"),dmxInputEnablePin); From f06a1e8b49697bdca84e9228c51fafda78b7cbae Mon Sep 17 00:00:00 2001 From: Arne Date: Mon, 14 Aug 2023 14:12:08 +0200 Subject: [PATCH 199/463] Extract dmx_input from dmx.cpp into dmx_input.cpp. This greatly improves readability because it gets rid of most of the ifdefs. --- wled00/dmx.cpp | 111 ++------------------------------------ wled00/dmx_input.cpp | 124 +++++++++++++++++++++++++++++++++++++++++++ wled00/fcn_declare.h | 7 +++ wled00/wled.cpp | 3 ++ 4 files changed, 137 insertions(+), 108 deletions(-) create mode 100644 wled00/dmx_input.cpp diff --git a/wled00/dmx.cpp b/wled00/dmx.cpp index f2f7d503..aa05c011 100644 --- a/wled00/dmx.cpp +++ b/wled00/dmx.cpp @@ -1,7 +1,7 @@ #include "wled.h" /* - * Support for DMX input and output via MAX485. + * Support for DMX input and output via serial (e.g. MAX485). * Change the output pin in src/dependencies/ESPDMX.cpp, if needed (ESP8266) * Change the output pin in src/dependencies/SparkFunDMX.cpp, if needed (ESP32) * ESP8266 Library from: @@ -75,112 +75,7 @@ void initDMX() { dmx.initWrite(512); // initialize with bus length #endif } -#endif - - -#ifdef WLED_ENABLE_DMX_INPUT - -#include - - -static dmx_port_t dmxInputPort = 2; //TODO make this configurable -bool dmxInputInitialized = false; //true once initDmx finished successfully - -void initDMX() { - - if(dmxInputReceivePin > 0 && dmxInputEnablePin > 0 && dmxInputTransmitPin > 0) - { - - const managed_pin_type pins[] = { - {dmxInputTransmitPin, false}, //these are not used as gpio pins, this isOutput is always false. - {dmxInputReceivePin, false}, - {dmxInputEnablePin, false} - }; - const bool pinsAllocated = pinManager.allocateMultiplePins(pins, 3, PinOwner::DMX_INPUT); - if(!pinsAllocated) - { - USER_PRINTF("Error: Failed to allocate pins for DMX_INPUT. Pins already in use:\n"); - USER_PRINTF("rx in use by: %s\n", pinManager.getPinOwnerText(dmxInputReceivePin).c_str()); - USER_PRINTF("tx in use by: %s\n", pinManager.getPinOwnerText(dmxInputTransmitPin).c_str()); - USER_PRINTF("en in use by: %s\n", pinManager.getPinOwnerText(dmxInputEnablePin).c_str()); - return; - } - - - dmx_config_t config{ - 255, /*alloc_size*/ - 0, /*model_id*/ - RDM_PRODUCT_CATEGORY_FIXTURE, /*product_category*/ - VERSION, /*software_version_id*/ - "undefined", /*software_version_label*/ - 1, /*current_personality*/ - {{15, "WLED Effect Mode"}}, /*personalities*/ - 1, /*personality_count*/ - 1, /*dmx_start_address*/ - }; - const std::string versionString = "WLED_V" + std::to_string(VERSION); - strncpy(config.software_version_label, versionString.c_str(), 32); - config.software_version_label[32] = '\0';//zero termination in case our string was longer than 32 chars - - if(!dmx_driver_install(dmxInputPort, &config, DMX_INTR_FLAGS_DEFAULT)) - { - USER_PRINTF("Error: Failed to install dmx driver\n"); - return; - } - - USER_PRINTF("Listening for DMX on pin %u\n", dmxInputReceivePin); - USER_PRINTF("Sending DMX on pin %u\n", dmxInputTransmitPin); - USER_PRINTF("DMX enable pin is: %u\n", dmxInputEnablePin); - dmx_set_pin(dmxInputPort, dmxInputTransmitPin, dmxInputReceivePin, dmxInputEnablePin); - - dmxInputInitialized = true; - } - else - { - USER_PRINTLN("DMX input disabled due to dmxInputReceivePin, dmxInputEnablePin or dmxInputTransmitPin not set"); - return; - } - -} - -bool dmxIsConnected = false; -unsigned long dmxLastUpdate = 0; - -void handleDMXInput() { - if(!dmxInputInitialized) { - return; - } - byte dmxdata[DMX_PACKET_SIZE]; - dmx_packet_t packet; - unsigned long now = millis(); - if (dmx_receive(dmxInputPort, &packet, 0)) { - - /* We should check to make sure that there weren't any DMX errors. */ - if (!packet.err) { - /* If this is the first DMX data we've received, lets log it! */ - if (!dmxIsConnected) { - USER_PRINTLN("DMX is connected!"); - dmxIsConnected = true; - } - - dmx_read(dmxInputPort, dmxdata, packet.size); - handleDMXData(1, 512, dmxdata, REALTIME_MODE_DMX, 0); - dmxLastUpdate = now; - - } else { - /* Oops! A DMX error occurred! Don't worry, this can happen when you first - connect or disconnect your DMX devices. If you are consistently getting - DMX errors, then something may have gone wrong with your code or - something is seriously wrong with your DMX transmitter. */ - DEBUG_PRINT("A DMX error occurred - "); - DEBUG_PRINTLN(packet.err); - } - } - else if (dmxIsConnected && (now - dmxLastUpdate > 5000)) { - dmxIsConnected = false; - USER_PRINTLN("DMX was disconnected."); - } -} #else -void initDMX(); +void initDMX(){} +void handleDMX() {} #endif diff --git a/wled00/dmx_input.cpp b/wled00/dmx_input.cpp new file mode 100644 index 00000000..8ed1d7ac --- /dev/null +++ b/wled00/dmx_input.cpp @@ -0,0 +1,124 @@ +#include "wled.h" + +#ifdef WLED_ENABLE_DMX_INPUT +#include +/* + * Support for DMX/RDM input via serial (e.g. max485) on ESP32 + * ESP32 Library from: + * https://github.com/sparkfun/SparkFunDMX + */ + +static dmx_port_t dmxInputPort = 2; //TODO make this configurable +bool dmxInputInitialized = false; //true once initDmx finished successfully + +void initDMXInput() { + + /** + * TODOS: + * - add personalities for all supported dmx input modes + * - select the personality that is stored in flash on startup + * - attach callback for personality change and store in flash if changed + * - attach callback for address change and store in flash + * - load dmx address from flash and set in config on startup + * - attach callback to rdm identify and flash leds when on + */ + if(dmxInputReceivePin > 0 && dmxInputEnablePin > 0 && dmxInputTransmitPin > 0) + { + + const managed_pin_type pins[] = { + {(int8_t)dmxInputTransmitPin, false}, //these are not used as gpio pins, this isOutput is always false. + {(int8_t)dmxInputReceivePin, false}, + {(int8_t)dmxInputEnablePin, false} + }; + const bool pinsAllocated = pinManager.allocateMultiplePins(pins, 3, PinOwner::DMX_INPUT); + if(!pinsAllocated) + { + USER_PRINTF("Error: Failed to allocate pins for DMX_INPUT. Pins already in use:\n"); + USER_PRINTF("rx in use by: %s\n", pinManager.getPinOwnerText(dmxInputReceivePin).c_str()); + USER_PRINTF("tx in use by: %s\n", pinManager.getPinOwnerText(dmxInputTransmitPin).c_str()); + USER_PRINTF("en in use by: %s\n", pinManager.getPinOwnerText(dmxInputEnablePin).c_str()); + return; + } + + + dmx_config_t config{ + 255, /*alloc_size*/ + 0, /*model_id*/ + RDM_PRODUCT_CATEGORY_FIXTURE, /*product_category*/ + VERSION, /*software_version_id*/ + "undefined", /*software_version_label*/ + 1, /*current_personality*/ + {{15, "WLED Effect Mode"}}, /*personalities*/ + 1, /*personality_count*/ + 1, /*dmx_start_address*/ + }; + const std::string versionString = "WLED_V" + std::to_string(VERSION); + strncpy(config.software_version_label, versionString.c_str(), 32); + config.software_version_label[32] = '\0';//zero termination in case our string was longer than 32 chars + + if(!dmx_driver_install(dmxInputPort, &config, DMX_INTR_FLAGS_DEFAULT)) + { + USER_PRINTF("Error: Failed to install dmx driver\n"); + return; + } + + USER_PRINTF("Listening for DMX on pin %u\n", dmxInputReceivePin); + USER_PRINTF("Sending DMX on pin %u\n", dmxInputTransmitPin); + USER_PRINTF("DMX enable pin is: %u\n", dmxInputEnablePin); + dmx_set_pin(dmxInputPort, dmxInputTransmitPin, dmxInputReceivePin, dmxInputEnablePin); + + dmxInputInitialized = true; + } + else + { + USER_PRINTLN("DMX input disabled due to dmxInputReceivePin, dmxInputEnablePin or dmxInputTransmitPin not set"); + return; + } + +} + +static bool dmxIsConnected = false; +static unsigned long dmxLastUpdate = 0; + +void handleDMXInput() { + if(!dmxInputInitialized) { + return; + } + byte dmxdata[DMX_PACKET_SIZE]; + dmx_packet_t packet; + unsigned long now = millis(); + if (dmx_receive(dmxInputPort, &packet, 0)) { + + /* We should check to make sure that there weren't any DMX errors. */ + if (!packet.err) { + /* If this is the first DMX data we've received, lets log it! */ + if (!dmxIsConnected) { + USER_PRINTLN("DMX is connected!"); + dmxIsConnected = true; + } + + dmx_read(dmxInputPort, dmxdata, packet.size); + handleDMXData(1, 512, dmxdata, REALTIME_MODE_DMX, 0); + dmxLastUpdate = now; + + } else { + /* Oops! A DMX error occurred! Don't worry, this can happen when you first + connect or disconnect your DMX devices. If you are consistently getting + DMX errors, then something may have gone wrong with your code or + something is seriously wrong with your DMX transmitter. */ + DEBUG_PRINT("A DMX error occurred - "); + DEBUG_PRINTLN(packet.err); + } + } + else if (dmxIsConnected && (now - dmxLastUpdate > 5000)) { + dmxIsConnected = false; + USER_PRINTLN("DMX was disconnected."); + } +} + + +#else +void initDMXInput(){} +void handleDMXInput(){} + +#endif \ No newline at end of file diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index cb21e8c2..c3ada1a5 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -186,6 +186,13 @@ void setRandomColor(byte* rgb); //dmx.cpp void initDMX(); void handleDMX(); +<<<<<<< HEAD +======= + +//dmx_input.cpp +void initDMXInput(); +void handleDMXInput(); +>>>>>>> b4bbf0a5 (Extract dmx_input from dmx.cpp into dmx_input.cpp.) //e131.cpp void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol); diff --git a/wled00/wled.cpp b/wled00/wled.cpp index a8748162..5e153947 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -534,6 +534,9 @@ void WLED::setup() #ifdef WLED_ENABLE_DMX initDMX(); #endif +#ifdef WLED_ENABLE_DMX_INPUT + initDMXInput(); +#endif #ifdef WLED_ENABLE_ADALIGHT if (serialCanRX && Serial.available() > 0 && Serial.peek() == 'I') handleImprovPacket(); From 789d68e80d12a4be2d3e98cd75e6e6b0f9e4da2d Mon Sep 17 00:00:00 2001 From: Arne Date: Mon, 14 Aug 2023 14:14:33 +0200 Subject: [PATCH 200/463] Move globals to top of file and change scope to compile unit only. Some minor cleanup changes --- wled00/dmx_input.cpp | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/wled00/dmx_input.cpp b/wled00/dmx_input.cpp index 8ed1d7ac..009112b7 100644 --- a/wled00/dmx_input.cpp +++ b/wled00/dmx_input.cpp @@ -9,7 +9,9 @@ */ static dmx_port_t dmxInputPort = 2; //TODO make this configurable -bool dmxInputInitialized = false; //true once initDmx finished successfully +static bool dmxInputInitialized = false; //true once initDmx finished successfully +static bool dmxIsConnected = false; +static unsigned long dmxLastUpdate = 0; void initDMXInput() { @@ -21,6 +23,8 @@ void initDMXInput() { * - attach callback for address change and store in flash * - load dmx address from flash and set in config on startup * - attach callback to rdm identify and flash leds when on + * - Turn this into a class + * - Make all important config variables available via rdm */ if(dmxInputReceivePin > 0 && dmxInputEnablePin > 0 && dmxInputTransmitPin > 0) { @@ -40,7 +44,6 @@ void initDMXInput() { return; } - dmx_config_t config{ 255, /*alloc_size*/ 0, /*model_id*/ @@ -54,7 +57,7 @@ void initDMXInput() { }; const std::string versionString = "WLED_V" + std::to_string(VERSION); strncpy(config.software_version_label, versionString.c_str(), 32); - config.software_version_label[32] = '\0';//zero termination in case our string was longer than 32 chars + config.software_version_label[32] = '\0';//zero termination in case versionString string was longer than 32 chars if(!dmx_driver_install(dmxInputPort, &config, DMX_INTR_FLAGS_DEFAULT)) { @@ -74,12 +77,8 @@ void initDMXInput() { USER_PRINTLN("DMX input disabled due to dmxInputReceivePin, dmxInputEnablePin or dmxInputTransmitPin not set"); return; } - } -static bool dmxIsConnected = false; -static unsigned long dmxLastUpdate = 0; - void handleDMXInput() { if(!dmxInputInitialized) { return; @@ -88,10 +87,7 @@ void handleDMXInput() { dmx_packet_t packet; unsigned long now = millis(); if (dmx_receive(dmxInputPort, &packet, 0)) { - - /* We should check to make sure that there weren't any DMX errors. */ if (!packet.err) { - /* If this is the first DMX data we've received, lets log it! */ if (!dmxIsConnected) { USER_PRINTLN("DMX is connected!"); dmxIsConnected = true; @@ -102,12 +98,10 @@ void handleDMXInput() { dmxLastUpdate = now; } else { - /* Oops! A DMX error occurred! Don't worry, this can happen when you first - connect or disconnect your DMX devices. If you are consistently getting - DMX errors, then something may have gone wrong with your code or - something is seriously wrong with your DMX transmitter. */ + /*This can happen when you first connect or disconnect your DMX devices. + If you are consistently getting DMX errors, then something may have gone wrong. */ DEBUG_PRINT("A DMX error occurred - "); - DEBUG_PRINTLN(packet.err); + DEBUG_PRINTLN(packet.err); //TODO translate err code to string for output } } else if (dmxIsConnected && (now - dmxLastUpdate > 5000)) { From 0ad31c90f62961de6a03533d94ab7aeb6fa81067 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Thu, 16 Jan 2025 11:26:42 +0000 Subject: [PATCH 201/463] fix merge error --- wled00/wled.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 5e153947..7b49b8b5 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -423,14 +423,6 @@ void WLED::setup() #ifdef WLED_ENABLE_DMX //reserve GPIO2 as hardcoded DMX pin PinManager::allocatePin(2, true, PinOwner::DMX); #endif -<<<<<<< HEAD -#ifdef WLED_ENABLE_DMX_INPUT - if(dmxInputTransmitPin > 0) PinManager::allocatePin(dmxInputTransmitPin, true, PinOwner::DMX); - if(dmxInputReceivePin > 0) PinManager::allocatePin(dmxInputReceivePin, true, PinOwner::DMX); - if(dmxInputEnablePin > 0) PinManager::allocatePin(dmxInputEnablePin, true, PinOwner::DMX); -#endif -======= ->>>>>>> a516a7b8 (Move dmx_input pin allocations from wled.cpp to dmx.cpp) DEBUG_PRINTLN(F("Registering usermods ...")); registerUsermods(); From a3bcf92ea5496e3ce56a9bed1eb74d06e0d03ec6 Mon Sep 17 00:00:00 2001 From: Arne Date: Mon, 14 Aug 2023 15:18:54 +0200 Subject: [PATCH 202/463] Turn dmx_into into class with state. This is much nicer to read and in the future more state will be added to support all the rdm stuff. --- wled00/dmx_input.cpp | 147 +++++++++++++++++++++++-------------------- wled00/dmx_input.h | 23 +++++++ wled00/wled.cpp | 6 +- wled00/wled.h | 5 ++ 4 files changed, 111 insertions(+), 70 deletions(-) create mode 100644 wled00/dmx_input.h diff --git a/wled00/dmx_input.cpp b/wled00/dmx_input.cpp index 009112b7..dcb04781 100644 --- a/wled00/dmx_input.cpp +++ b/wled00/dmx_input.cpp @@ -1,118 +1,127 @@ #include "wled.h" #ifdef WLED_ENABLE_DMX_INPUT +#include "dmx_input.h" #include -/* - * Support for DMX/RDM input via serial (e.g. max485) on ESP32 - * ESP32 Library from: - * https://github.com/sparkfun/SparkFunDMX - */ -static dmx_port_t dmxInputPort = 2; //TODO make this configurable -static bool dmxInputInitialized = false; //true once initDmx finished successfully -static bool dmxIsConnected = false; -static unsigned long dmxLastUpdate = 0; +#ifdef ESP8266 +#error DMX input is only supported on ESP32 +#endif -void initDMXInput() { +void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPortNum) +{ - /** - * TODOS: - * - add personalities for all supported dmx input modes - * - select the personality that is stored in flash on startup - * - attach callback for personality change and store in flash if changed - * - attach callback for address change and store in flash - * - load dmx address from flash and set in config on startup - * - attach callback to rdm identify and flash leds when on - * - Turn this into a class - * - Make all important config variables available via rdm - */ - if(dmxInputReceivePin > 0 && dmxInputEnablePin > 0 && dmxInputTransmitPin > 0) + if (inputPortNum < 3 && inputPortNum > 0) + { + this->inputPortNum = inputPortNum; + } + else + { + USER_PRINTF("DMXInput: Error: invalid inputPortNum: %d\n", inputPortNum); + return; + } + + /** + * TODOS: + * - add personalities for all supported dmx input modes + * - select the personality that is stored in flash on startup + * - attach callback for personality change and store in flash if changed + * - attach callback for address change and store in flash + * - load dmx address from flash and set in config on startup + * - attach callback to rdm identify and flash leds when on + * - Make all important config variables available via rdm + */ + if (rxPin > 0 && enPin > 0 && txPin > 0) { const managed_pin_type pins[] = { - {(int8_t)dmxInputTransmitPin, false}, //these are not used as gpio pins, this isOutput is always false. - {(int8_t)dmxInputReceivePin, false}, - {(int8_t)dmxInputEnablePin, false} - }; + {(int8_t)txPin, false}, // these are not used as gpio pins, this isOutput is always false. + {(int8_t)rxPin, false}, + {(int8_t)enPin, false}}; const bool pinsAllocated = pinManager.allocateMultiplePins(pins, 3, PinOwner::DMX_INPUT); - if(!pinsAllocated) + if (!pinsAllocated) { - USER_PRINTF("Error: Failed to allocate pins for DMX_INPUT. Pins already in use:\n"); - USER_PRINTF("rx in use by: %s\n", pinManager.getPinOwnerText(dmxInputReceivePin).c_str()); - USER_PRINTF("tx in use by: %s\n", pinManager.getPinOwnerText(dmxInputTransmitPin).c_str()); - USER_PRINTF("en in use by: %s\n", pinManager.getPinOwnerText(dmxInputEnablePin).c_str()); + USER_PRINTF("DMXInput: Error: Failed to allocate pins for DMX_INPUT. Pins already in use:\n"); + USER_PRINTF("rx in use by: %s\n", pinManager.getPinOwnerText(rxPin).c_str()); + USER_PRINTF("tx in use by: %s\n", pinManager.getPinOwnerText(txPin).c_str()); + USER_PRINTF("en in use by: %s\n", pinManager.getPinOwnerText(enPin).c_str()); return; } - dmx_config_t config{ - 255, /*alloc_size*/ - 0, /*model_id*/ - RDM_PRODUCT_CATEGORY_FIXTURE, /*product_category*/ - VERSION, /*software_version_id*/ - "undefined", /*software_version_label*/ - 1, /*current_personality*/ - {{15, "WLED Effect Mode"}}, /*personalities*/ - 1, /*personality_count*/ - 1, /*dmx_start_address*/ + dmx_config_t config{ + 255, /*alloc_size*/ + 0, /*model_id*/ + RDM_PRODUCT_CATEGORY_FIXTURE, /*product_category*/ + VERSION, /*software_version_id*/ + "undefined", /*software_version_label*/ + 1, /*current_personality*/ + {{15, "WLED Effect Mode"}}, /*personalities*/ + 1, /*personality_count*/ + 1, /*dmx_start_address*/ }; const std::string versionString = "WLED_V" + std::to_string(VERSION); strncpy(config.software_version_label, versionString.c_str(), 32); - config.software_version_label[32] = '\0';//zero termination in case versionString string was longer than 32 chars + config.software_version_label[32] = '\0'; // zero termination in case versionString string was longer than 32 chars - if(!dmx_driver_install(dmxInputPort, &config, DMX_INTR_FLAGS_DEFAULT)) + if (!dmx_driver_install(inputPortNum, &config, DMX_INTR_FLAGS_DEFAULT)) { USER_PRINTF("Error: Failed to install dmx driver\n"); return; } - - USER_PRINTF("Listening for DMX on pin %u\n", dmxInputReceivePin); - USER_PRINTF("Sending DMX on pin %u\n", dmxInputTransmitPin); - USER_PRINTF("DMX enable pin is: %u\n", dmxInputEnablePin); - dmx_set_pin(dmxInputPort, dmxInputTransmitPin, dmxInputReceivePin, dmxInputEnablePin); - dmxInputInitialized = true; + USER_PRINTF("Listening for DMX on pin %u\n", rxPin); + USER_PRINTF("Sending DMX on pin %u\n", txPin); + USER_PRINTF("DMX enable pin is: %u\n", enPin); + dmx_set_pin(inputPortNum, txPin, rxPin, enPin); + + initialized = true; } - else + else { - USER_PRINTLN("DMX input disabled due to dmxInputReceivePin, dmxInputEnablePin or dmxInputTransmitPin not set"); + USER_PRINTLN("DMX input disabled due to rxPin, enPin or txPin not set"); return; } } -void handleDMXInput() { - if(!dmxInputInitialized) { +void DMXInput::update() +{ + if (!initialized) + { return; } byte dmxdata[DMX_PACKET_SIZE]; dmx_packet_t packet; unsigned long now = millis(); - if (dmx_receive(dmxInputPort, &packet, 0)) { - if (!packet.err) { - if (!dmxIsConnected) { + if (dmx_receive(inputPortNum, &packet, 0)) + { + if (!packet.err) + { + if (!connected) + { USER_PRINTLN("DMX is connected!"); - dmxIsConnected = true; + connected = true; } - dmx_read(dmxInputPort, dmxdata, packet.size); + dmx_read(inputPortNum, dmxdata, packet.size); handleDMXData(1, 512, dmxdata, REALTIME_MODE_DMX, 0); - dmxLastUpdate = now; - - } else { + lastUpdate = now; + } + else + { /*This can happen when you first connect or disconnect your DMX devices. If you are consistently getting DMX errors, then something may have gone wrong. */ - DEBUG_PRINT("A DMX error occurred - "); - DEBUG_PRINTLN(packet.err); //TODO translate err code to string for output + DEBUG_PRINT("A DMX error occurred - "); + DEBUG_PRINTLN(packet.err); // TODO translate err code to string for output } } - else if (dmxIsConnected && (now - dmxLastUpdate > 5000)) { - dmxIsConnected = false; + else if (connected && (now - lastUpdate > 5000)) + { + connected = false; USER_PRINTLN("DMX was disconnected."); } } - #else -void initDMXInput(){} -void handleDMXInput(){} - +void DMXInput::init(uint8_t, uint8_t, uint8_t, uint8_t) {} +void DMXInput::update() {} #endif \ No newline at end of file diff --git a/wled00/dmx_input.h b/wled00/dmx_input.h new file mode 100644 index 00000000..ac67bc20 --- /dev/null +++ b/wled00/dmx_input.h @@ -0,0 +1,23 @@ +#pragma once +#include + +/* + * Support for DMX/RDM input via serial (e.g. max485) on ESP32 + * ESP32 Library from: + * https://github.com/sparkfun/SparkFunDMX + */ +class DMXInput +{ +public: + void init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPortNum); + void update(); + +private: + uint8_t inputPortNum = 255; // TODO make this configurable + /// True once the dmx input has been initialized successfully + bool initialized = false; // true once init finished successfully + /// True if dmx is currently connected + bool connected = false; + /// Timestamp of the last time a dmx frame was received + unsigned long lastUpdate = 0; +}; diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 7b49b8b5..f9dfa55f 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -67,6 +67,9 @@ void WLED::loop() #ifdef WLED_ENABLE_DMX handleDMX(); #endif + #ifdef WLED_ENABLE_DMX_INPUT + dmxInput.update(); + #endif #ifdef WLED_DEBUG unsigned long usermodMillis = millis(); @@ -527,7 +530,8 @@ void WLED::setup() initDMX(); #endif #ifdef WLED_ENABLE_DMX_INPUT - initDMXInput(); + const uint8_t dmxInputPortNumber = 2; //TODO turn into config variable?! + dmxInput.init(dmxInputReceivePin, dmxInputTransmitPin, dmxInputEnablePin, dmxInputPortNumber); #endif #ifdef WLED_ENABLE_ADALIGHT diff --git a/wled00/wled.h b/wled00/wled.h index 8adbd1ba..b366e82a 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -144,6 +144,10 @@ #endif #endif +#ifdef WLED_ENABLE_DMX_INPUT + #include "dmx_input.h" +#endif + #include "src/dependencies/e131/ESPAsyncE131.h" #ifndef WLED_DISABLE_MQTT #include "src/dependencies/async-mqtt-client/AsyncMqttClient.h" @@ -463,6 +467,7 @@ WLED_GLOBAL bool arlsForceMaxBri _INIT(false); // enable to f WLED_GLOBAL int dmxInputTransmitPin _INIT(0); WLED_GLOBAL int dmxInputReceivePin _INIT(0); WLED_GLOBAL int dmxInputEnablePin _INIT(0); + WLED_GLOBAL DMXInput dmxInput; #endif WLED_GLOBAL uint16_t e131Universe _INIT(1); // settings for E1.31 (sACN) protocol (only DMX_MODE_MULTIPLE_* can span over consequtive universes) From 5a5661f136417eea1e19ce82541e034b8ca79228 Mon Sep 17 00:00:00 2001 From: Arne Date: Mon, 14 Aug 2023 15:54:19 +0200 Subject: [PATCH 203/463] handle dmx rdm identify --- wled00/dmx_input.cpp | 37 ++++++++++++++++++++++++++++++------- wled00/dmx_input.h | 8 ++++++-- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/wled00/dmx_input.cpp b/wled00/dmx_input.cpp index dcb04781..28c33725 100644 --- a/wled00/dmx_input.cpp +++ b/wled00/dmx_input.cpp @@ -1,13 +1,14 @@ #include "wled.h" #ifdef WLED_ENABLE_DMX_INPUT -#include "dmx_input.h" -#include #ifdef ESP8266 #error DMX input is only supported on ESP32 #endif +#include "dmx_input.h" +#include + void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPortNum) { @@ -102,8 +103,21 @@ void DMXInput::update() connected = true; } - dmx_read(inputPortNum, dmxdata, packet.size); - handleDMXData(1, 512, dmxdata, REALTIME_MODE_DMX, 0); + uint8_t identify = 0; + const bool gotIdentify = rdm_get_identify_device(inputPortNum, &identify); + // gotIdentify should never be false because it is a default parameter in rdm but just in case we check for it anyway + if (identify && gotIdentify) + { + turnOnAllLeds(); + } + else + { + if (!packet.is_rdm) + { + dmx_read(inputPortNum, dmxdata, packet.size); + handleDMXData(1, 512, dmxdata, REALTIME_MODE_DMX, 0); + } + } lastUpdate = now; } else @@ -121,7 +135,16 @@ void DMXInput::update() } } -#else -void DMXInput::init(uint8_t, uint8_t, uint8_t, uint8_t) {} -void DMXInput::update() {} +void DMXInput::turnOnAllLeds() +{ + // TODO not sure if this is the correct way? + const uint16_t numPixels = strip.getLengthTotal(); + for (uint16_t i = 0; i < numPixels; ++i) + { + strip.setPixelColor(i, 255, 255, 255, 255); + } + strip.setBrightness(255, true); + strip.show(); +} + #endif \ No newline at end of file diff --git a/wled00/dmx_input.h b/wled00/dmx_input.h index ac67bc20..b33c2a16 100644 --- a/wled00/dmx_input.h +++ b/wled00/dmx_input.h @@ -1,6 +1,6 @@ #pragma once #include - +#include /* * Support for DMX/RDM input via serial (e.g. max485) on ESP32 * ESP32 Library from: @@ -10,9 +10,13 @@ class DMXInput { public: void init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPortNum); - void update(); + void update(); private: + + /// overrides everything and turns on all leds + void turnOnAllLeds(); + uint8_t inputPortNum = 255; // TODO make this configurable /// True once the dmx input has been initialized successfully bool initialized = false; // true once init finished successfully From aed03cd03baca7100f7eef713905bc3bae6b55ce Mon Sep 17 00:00:00 2001 From: Arne Date: Thu, 17 Aug 2023 16:52:25 +0200 Subject: [PATCH 204/463] hack: disable dmx receiver while wifi is being activated This fixes a crash in the dmx receiver. The dmx receiver cannot work while cache is disabled. For some reason activating wifi disables the cache. In theory, the driver is placed in iram and should work, but it doesn't. This might be a bug in the driver. --- wled00/wled.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/wled00/wled.cpp b/wled00/wled.cpp index f9dfa55f..376cb6b2 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -783,6 +783,9 @@ void WLED::initConnection() { DEBUG_PRINTF_P(PSTR("initConnection() called @ %lus.\n"), millis()/1000); + #ifdef WLED_ENABLE_DMX_INPUT + dmxInput.disable(); + #endif #ifdef WLED_ENABLE_WEBSOCKETS ws.onEvent(wsEvent); #endif @@ -811,6 +814,11 @@ void WLED::initConnection() if (!WLED_WIFI_CONFIGURED) { DEBUG_PRINTLN(F("No connection configured.")); if (!apActive) initAP(); // instantly go to ap mode + + #ifdef WLED_ENABLE_DMX_INPUT + dmxInput.enable(); + #endif + return; } else if (!apActive) { if (apBehavior == AP_BEHAVIOR_ALWAYS) { DEBUG_PRINTLN(F("Access point ALWAYS enabled.")); @@ -860,6 +868,10 @@ void WLED::initConnection() statusESPNow = espNowOK ? ESP_NOW_STATE_ON : ESP_NOW_STATE_ERROR; } #endif + + #ifdef WLED_ENABLE_DMX_INPUT + dmxInput.enable(); + #endif } void WLED::initInterfaces() From 5525a216969ab2150ffecef1659135887422fd24 Mon Sep 17 00:00:00 2001 From: Arne Date: Thu, 17 Aug 2023 16:53:02 +0200 Subject: [PATCH 205/463] rename settings --- wled00/cfg.cpp | 8 ++++---- wled00/data/settings_sync.htm | 12 ++++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 1105077c..d3a8a0c6 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -526,7 +526,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { #ifdef WLED_ENABLE_DMX_INPUT CJSON(dmxInputTransmitPin, if_live_dmx[F("inputRxPin")]); CJSON(dmxInputReceivePin, if_live_dmx[F("inputTxPin")]); - CJSON(dmxInputEnablePin, if_live_dmx[F("enablePin")]); + CJSON(dmxInputEnablePin, if_live_dmx[F("inputEnablePin")]); #endif CJSON(arlsForceMaxBri, if_live[F("maxbri")]); @@ -1009,9 +1009,9 @@ void serializeConfig() { if_live_dmx[F("dss")] = DMXSegmentSpacing; if_live_dmx["mode"] = DMXMode; #ifdef WLED_ENABLE_DMX_INPUT - if_live_dmx[F("rxPin")] = dmxInputTransmitPin; - if_live_dmx[F("txPin")] = dmxInputReceivePin; - if_live_dmx[F("enablePin")] = dmxInputEnablePin; + if_live_dmx[F("inputRxPin")] = dmxInputTransmitPin; + if_live_dmx[F("inputTxPin")] = dmxInputReceivePin; + if_live_dmx[F("inputEnablePin")] = dmxInputEnablePin; #endif if_live[F("timeout")] = realtimeTimeoutMs / 100; diff --git a/wled00/data/settings_sync.htm b/wled00/data/settings_sync.htm index 34b9fc6c..16bd3f7f 100644 --- a/wled00/data/settings_sync.htm +++ b/wled00/data/settings_sync.htm @@ -151,6 +151,18 @@ Timeout: ms
Force max brightness:
Disable realtime gamma correction:
Realtime LED offset: +
+ DMX Input Pins
+ DMX RX:
+ DMX TX:
+ DMX Enable:
+
+
+
This firmware build does not include DMX Input support.
+
+
+
This firmware build does not include DMX output support.
+

Alexa Voice Assistant

From 033c7abe62198052a53e8c29f04ec9b56a66ecf3 Mon Sep 17 00:00:00 2001 From: Arne Date: Thu, 17 Aug 2023 16:53:48 +0200 Subject: [PATCH 206/463] add enable/disable methods for dmxInput --- wled00/dmx_input.cpp | 15 +++++++++++++++ wled00/dmx_input.h | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/wled00/dmx_input.cpp b/wled00/dmx_input.cpp index 28c33725..a150fa78 100644 --- a/wled00/dmx_input.cpp +++ b/wled00/dmx_input.cpp @@ -147,4 +147,19 @@ void DMXInput::turnOnAllLeds() strip.show(); } +void DMXInput::disable() +{ + if (initialized) + { + dmx_driver_disable(inputPortNum); + } +} +void DMXInput::enable() +{ + if(initialized) + { + dmx_driver_enable(inputPortNum); + } +} + #endif \ No newline at end of file diff --git a/wled00/dmx_input.h b/wled00/dmx_input.h index b33c2a16..b96077c1 100644 --- a/wled00/dmx_input.h +++ b/wled00/dmx_input.h @@ -12,6 +12,10 @@ public: void init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPortNum); void update(); + /**disable dmx receiver (do this before disabling the cache)*/ + void disable(); + void enable(); + private: /// overrides everything and turns on all leds From 9d8fdd0b20e407948b975d847cd1eecbd062f0cf Mon Sep 17 00:00:00 2001 From: Arne Date: Fri, 18 Aug 2023 15:43:14 +0200 Subject: [PATCH 207/463] extract test for rdm identify into own method --- wled00/dmx_input.cpp | 15 +++++++++++---- wled00/dmx_input.h | 2 ++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/wled00/dmx_input.cpp b/wled00/dmx_input.cpp index a150fa78..d46e3beb 100644 --- a/wled00/dmx_input.cpp +++ b/wled00/dmx_input.cpp @@ -103,11 +103,9 @@ void DMXInput::update() connected = true; } - uint8_t identify = 0; - const bool gotIdentify = rdm_get_identify_device(inputPortNum, &identify); - // gotIdentify should never be false because it is a default parameter in rdm but just in case we check for it anyway - if (identify && gotIdentify) + if (isIdentifyOn()) { + DEBUG_PRINTLN("RDM Identify active"); turnOnAllLeds(); } else @@ -162,4 +160,13 @@ void DMXInput::enable() } } +bool DMXInput::isIdentifyOn() const +{ + + uint8_t identify = 0; + const bool gotIdentify = rdm_get_identify_device(inputPortNum, &identify); + // gotIdentify should never be false because it is a default parameter in rdm + // but just in case we check for it anyway + return bool(identify) && gotIdentify; +} #endif \ No newline at end of file diff --git a/wled00/dmx_input.h b/wled00/dmx_input.h index b96077c1..27425d0d 100644 --- a/wled00/dmx_input.h +++ b/wled00/dmx_input.h @@ -17,6 +17,8 @@ public: void enable(); private: + /// @return true if rdm identify is active + bool isIdentifyOn() const; /// overrides everything and turns on all leds void turnOnAllLeds(); From be3e331afba624182625d3d8dceddb4b550bc79e Mon Sep 17 00:00:00 2001 From: Arne Date: Fri, 18 Aug 2023 15:44:27 +0200 Subject: [PATCH 208/463] Monitor dmx personality and dmx start address for change and update rdm --- wled00/dmx_input.cpp | 28 ++++++++++++++++++++++++++++ wled00/dmx_input.h | 5 +++++ 2 files changed, 33 insertions(+) diff --git a/wled00/dmx_input.cpp b/wled00/dmx_input.cpp index d46e3beb..e60be420 100644 --- a/wled00/dmx_input.cpp +++ b/wled00/dmx_input.cpp @@ -90,6 +90,9 @@ void DMXInput::update() { return; } + + checkAndUpdateConfig(); + byte dmxdata[DMX_PACKET_SIZE]; dmx_packet_t packet; unsigned long now = millis(); @@ -169,4 +172,29 @@ bool DMXInput::isIdentifyOn() const // but just in case we check for it anyway return bool(identify) && gotIdentify; } + +void DMXInput::checkAndUpdateConfig() +{ + + /** + * The global configuration variables are modified by the web interface. + * If they differ from the driver configuration, we have to update the driver + * configuration. + */ + + const uint8_t currentPersonality = dmx_get_current_personality(inputPortNum); + if (currentPersonality != DMXMode) + { + DEBUG_PRINTF("DMX personality has changed from %d to %d\n", currentPersonality, DMXMode); + dmx_set_current_personality(inputPortNum, DMXMode); + } + + const uint16_t currentAddr = dmx_get_start_address(inputPortNum); + if (currentAddr != DMXAddress) + { + DEBUG_PRINTF("DMX address has changed from %d to %d\n", currentAddr, DMXAddress); + dmx_set_start_address(inputPortNum, DMXAddress); + } +} + #endif \ No newline at end of file diff --git a/wled00/dmx_input.h b/wled00/dmx_input.h index 27425d0d..1871176e 100644 --- a/wled00/dmx_input.h +++ b/wled00/dmx_input.h @@ -20,6 +20,11 @@ private: /// @return true if rdm identify is active bool isIdentifyOn() const; + /** + * Checks if the global dmx config has changed and updates the changes in rdm + */ + void checkAndUpdateConfig(); + /// overrides everything and turns on all leds void turnOnAllLeds(); From 50b56c64f5af3be65395682949d05439f92a5b8a Mon Sep 17 00:00:00 2001 From: Arne Date: Fri, 18 Aug 2023 15:46:18 +0200 Subject: [PATCH 209/463] extract creation of dmx config into own method --- wled00/dmx_input.cpp | 59 +++++++++++++++++++++++++++++++++----------- wled00/dmx_input.h | 1 + 2 files changed, 45 insertions(+), 15 deletions(-) diff --git a/wled00/dmx_input.cpp b/wled00/dmx_input.cpp index e60be420..b60f56cd 100644 --- a/wled00/dmx_input.cpp +++ b/wled00/dmx_input.cpp @@ -9,6 +9,49 @@ #include "dmx_input.h" #include + +dmx_config_t DMXInput::createConfig() const +{ + + dmx_config_t config; + config.pd_size = 255; + config.dmx_start_address = DMXAddress; // TODO split between input and output address + config.model_id = 0; + config.product_category = RDM_PRODUCT_CATEGORY_FIXTURE; + config.software_version_id = VERSION; + + const std::string versionString = "WLED_V" + std::to_string(VERSION); + strncpy(config.software_version_label, versionString.c_str(), 32); + config.software_version_label[32] = '\0'; // zero termination in case versionString string was longer than 32 chars + + config.personalities[0].description = "SINGLE_RGB"; + config.personalities[0].footprint = 3; + config.personalities[1].description = "SINGLE_DRGB"; + config.personalities[1].footprint = 4; + config.personalities[2].description = "EFFECT"; + config.personalities[2].footprint = 15; + config.personalities[3].description = "MULTIPLE_RGB"; + config.personalities[3].footprint = std::min(512, int(strip.getLengthTotal()) * 3); + config.personalities[4].description = "MULTIPLE_DRGB"; + config.personalities[4].footprint = std::min(512, int(strip.getLengthTotal()) * 3 + 1); + config.personalities[5].description = "MULTIPLE_RGBW"; + config.personalities[5].footprint = std::min(512, int(strip.getLengthTotal()) * 4); + config.personalities[6].description = "EFFECT_W"; + config.personalities[6].footprint = 18; + config.personalities[7].description = "EFFECT_SEGMENT"; + config.personalities[7].footprint = std::min(512, strip.getSegmentsNum() * 15); + config.personalities[8].description = "EFFECT_SEGMENT_W"; + config.personalities[8].footprint = std::min(512, strip.getSegmentsNum() * 18); + config.personalities[9].description = "PRESET"; + config.personalities[9].footprint = 1; + + config.personality_count = 10; + // rdm personalities are numbered from 1, thus we can just set the DMXMode directly. + config.current_personality = DMXMode; + + return config; +} + void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPortNum) { @@ -49,21 +92,7 @@ void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPo return; } - dmx_config_t config{ - 255, /*alloc_size*/ - 0, /*model_id*/ - RDM_PRODUCT_CATEGORY_FIXTURE, /*product_category*/ - VERSION, /*software_version_id*/ - "undefined", /*software_version_label*/ - 1, /*current_personality*/ - {{15, "WLED Effect Mode"}}, /*personalities*/ - 1, /*personality_count*/ - 1, /*dmx_start_address*/ - }; - const std::string versionString = "WLED_V" + std::to_string(VERSION); - strncpy(config.software_version_label, versionString.c_str(), 32); - config.software_version_label[32] = '\0'; // zero termination in case versionString string was longer than 32 chars - + const auto config = createConfig(); if (!dmx_driver_install(inputPortNum, &config, DMX_INTR_FLAGS_DEFAULT)) { USER_PRINTF("Error: Failed to install dmx driver\n"); diff --git a/wled00/dmx_input.h b/wled00/dmx_input.h index 1871176e..88b1755c 100644 --- a/wled00/dmx_input.h +++ b/wled00/dmx_input.h @@ -28,6 +28,7 @@ private: /// overrides everything and turns on all leds void turnOnAllLeds(); + dmx_config_t createConfig() const; uint8_t inputPortNum = 255; // TODO make this configurable /// True once the dmx input has been initialized successfully bool initialized = false; // true once init finished successfully From 2989155f0567df45f9eca6cf644b7b2523f9fcbd Mon Sep 17 00:00:00 2001 From: Arne Date: Fri, 18 Aug 2023 15:47:01 +0200 Subject: [PATCH 210/463] handle rdm dmx address changes --- wled00/dmx_input.cpp | 19 +++++++++++++++++++ wled00/dmx_input.h | 5 +++++ 2 files changed, 24 insertions(+) diff --git a/wled00/dmx_input.cpp b/wled00/dmx_input.cpp index b60f56cd..3cb9090b 100644 --- a/wled00/dmx_input.cpp +++ b/wled00/dmx_input.cpp @@ -9,6 +9,24 @@ #include "dmx_input.h" #include +void rdmAddressChangedCb(dmx_port_t dmxPort, const rdm_header_t *header, + void *context) +{ + DMXInput *dmx = static_cast(context); + + if (!dmx) + { + USER_PRINTLN("DMX: Error: no context in rdmAddressChangedCb"); + return; + } + + if (header->cc == RDM_CC_SET_COMMAND_RESPONSE) + { + const uint16_t addr = dmx_get_start_address(dmx->inputPortNum); + DMXAddress = std::min(512, int(addr)); + USER_PRINTF("DMX start addr changed to: %d\n", DMXAddress); + } +} dmx_config_t DMXInput::createConfig() const { @@ -104,6 +122,7 @@ void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPo USER_PRINTF("DMX enable pin is: %u\n", enPin); dmx_set_pin(inputPortNum, txPin, rxPin, enPin); + rdm_register_dmx_start_address(inputPortNum, rdmAddressChangedCb, this); initialized = true; } else diff --git a/wled00/dmx_input.h b/wled00/dmx_input.h index 88b1755c..df6c31d6 100644 --- a/wled00/dmx_input.h +++ b/wled00/dmx_input.h @@ -29,6 +29,11 @@ private: void turnOnAllLeds(); dmx_config_t createConfig() const; + + //is invoked whenver the dmx start address is changed via rdm + friend void rdmAddressChangedCb(dmx_port_t dmxPort, const rdm_header_t *header, + void *context); + uint8_t inputPortNum = 255; // TODO make this configurable /// True once the dmx input has been initialized successfully bool initialized = false; // true once init finished successfully From 9a3b208ac5ed1a0bf12c6e1cefc73172d9bf3757 Mon Sep 17 00:00:00 2001 From: Arne Date: Fri, 18 Aug 2023 15:47:43 +0200 Subject: [PATCH 211/463] comments and cleanup --- wled00/dmx_input.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/wled00/dmx_input.cpp b/wled00/dmx_input.cpp index 3cb9090b..4294a348 100644 --- a/wled00/dmx_input.cpp +++ b/wled00/dmx_input.cpp @@ -85,19 +85,22 @@ void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPo /** * TODOS: - * - add personalities for all supported dmx input modes - * - select the personality that is stored in flash on startup * - attach callback for personality change and store in flash if changed * - attach callback for address change and store in flash * - load dmx address from flash and set in config on startup * - attach callback to rdm identify and flash leds when on * - Make all important config variables available via rdm + * - RDM_PID_DEVICE_LABEL does not seem to be supported, yet? Implement in esp_dmx and create PR + * - implement changing personality in rdm. (not yet implemented in esp_dmx?) + * - This is more complicated because get personality requests two bytes but + * set personality only contains one byte. Thus the default parameter callback will + * not work. Need to think about this :D */ if (rxPin > 0 && enPin > 0 && txPin > 0) { const managed_pin_type pins[] = { - {(int8_t)txPin, false}, // these are not used as gpio pins, this isOutput is always false. + {(int8_t)txPin, false}, // these are not used as gpio pins, thus isOutput is always false. {(int8_t)rxPin, false}, {(int8_t)enPin, false}}; const bool pinsAllocated = pinManager.allocateMultiplePins(pins, 3, PinOwner::DMX_INPUT); @@ -159,14 +162,12 @@ void DMXInput::update() DEBUG_PRINTLN("RDM Identify active"); turnOnAllLeds(); } - else + else if (!packet.is_rdm) { - if (!packet.is_rdm) - { - dmx_read(inputPortNum, dmxdata, packet.size); - handleDMXData(1, 512, dmxdata, REALTIME_MODE_DMX, 0); - } + dmx_read(inputPortNum, dmxdata, packet.size); + handleDMXData(1, 512, dmxdata, REALTIME_MODE_DMX, 0); } + lastUpdate = now; } else @@ -205,7 +206,7 @@ void DMXInput::disable() } void DMXInput::enable() { - if(initialized) + if (initialized) { dmx_driver_enable(inputPortNum); } From b178c082714ce8c34b2eda92aab38a000e7e5811 Mon Sep 17 00:00:00 2001 From: Arne Date: Tue, 22 Aug 2023 22:09:21 +0200 Subject: [PATCH 212/463] Support dmx rdm personality change --- wled00/dmx_input.cpp | 35 ++++++++++++++++++++++------------- wled00/dmx_input.h | 6 +++++- wled00/wled.cpp | 11 +++++++++++ 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/wled00/dmx_input.cpp b/wled00/dmx_input.cpp index 4294a348..0de1337e 100644 --- a/wled00/dmx_input.cpp +++ b/wled00/dmx_input.cpp @@ -9,6 +9,25 @@ #include "dmx_input.h" #include +void rdmPersonalityChangedCb(dmx_port_t dmxPort, const rdm_header_t *header, + void *context) +{ + DMXInput *dmx = static_cast(context); + + if (!dmx) + { + USER_PRINTLN("DMX: Error: no context in rdmPersonalityChangedCb"); + return; + } + + if (header->cc == RDM_CC_SET_COMMAND_RESPONSE) + { + const uint8_t personality = dmx_get_current_personality(dmx->inputPortNum); + DMXMode = std::min(DMX_MODE_PRESET, std::max(DMX_MODE_SINGLE_RGB, int(personality))); + doSerializeConfig = true; + USER_PRINTF("DMX personality changed to to: %d\n", DMXMode); + } +} void rdmAddressChangedCb(dmx_port_t dmxPort, const rdm_header_t *header, void *context) { @@ -24,6 +43,7 @@ void rdmAddressChangedCb(dmx_port_t dmxPort, const rdm_header_t *header, { const uint16_t addr = dmx_get_start_address(dmx->inputPortNum); DMXAddress = std::min(512, int(addr)); + doSerializeConfig = true; USER_PRINTF("DMX start addr changed to: %d\n", DMXAddress); } } @@ -37,6 +57,7 @@ dmx_config_t DMXInput::createConfig() const config.model_id = 0; config.product_category = RDM_PRODUCT_CATEGORY_FIXTURE; config.software_version_id = VERSION; + strcpy(config.device_label, "WLED_MM"); const std::string versionString = "WLED_V" + std::to_string(VERSION); strncpy(config.software_version_label, versionString.c_str(), 32); @@ -83,19 +104,6 @@ void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPo return; } - /** - * TODOS: - * - attach callback for personality change and store in flash if changed - * - attach callback for address change and store in flash - * - load dmx address from flash and set in config on startup - * - attach callback to rdm identify and flash leds when on - * - Make all important config variables available via rdm - * - RDM_PID_DEVICE_LABEL does not seem to be supported, yet? Implement in esp_dmx and create PR - * - implement changing personality in rdm. (not yet implemented in esp_dmx?) - * - This is more complicated because get personality requests two bytes but - * set personality only contains one byte. Thus the default parameter callback will - * not work. Need to think about this :D - */ if (rxPin > 0 && enPin > 0 && txPin > 0) { @@ -126,6 +134,7 @@ void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPo dmx_set_pin(inputPortNum, txPin, rxPin, enPin); rdm_register_dmx_start_address(inputPortNum, rdmAddressChangedCb, this); + rdm_register_dmx_personality(inputPortNum, rdmPersonalityChangedCb, this); initialized = true; } else diff --git a/wled00/dmx_input.h b/wled00/dmx_input.h index df6c31d6..b762e59b 100644 --- a/wled00/dmx_input.h +++ b/wled00/dmx_input.h @@ -30,10 +30,14 @@ private: dmx_config_t createConfig() const; - //is invoked whenver the dmx start address is changed via rdm + // is invoked whenver the dmx start address is changed via rdm friend void rdmAddressChangedCb(dmx_port_t dmxPort, const rdm_header_t *header, void *context); + // is invoked whenever the personality is changed via rdm + friend void rdmPersonalityChangedCb(dmx_port_t dmxPort, const rdm_header_t *header, + void *context); + uint8_t inputPortNum = 255; // TODO make this configurable /// True once the dmx input has been initialized successfully bool initialized = false; // true once init finished successfully diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 376cb6b2..8b2b3376 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -256,6 +256,17 @@ void WLED::loop() } #endif +if (doSerializeConfig) + { + #ifdef WLED_ENABLE_DMX_INPUT + dmxInput.disable(); + #endif + + #ifdef WLED_ENABLE_DMX_INPUT + dmxInput.enable(); + #endif + } + if (doReboot && (!doInitBusses || !doSerializeConfig)) // if busses have to be inited & saved, wait until next iteration reset(); From 2cc5a29b8633dcb04e0bd2b68b54756e57cb63d6 Mon Sep 17 00:00:00 2001 From: Arne Date: Tue, 22 Aug 2023 22:24:31 +0200 Subject: [PATCH 213/463] keep dmx rdm identify on if dmx disconnects. Some rdm testers disconnect after setting it. --- wled00/dmx_input.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/wled00/dmx_input.cpp b/wled00/dmx_input.cpp index 0de1337e..f90515fd 100644 --- a/wled00/dmx_input.cpp +++ b/wled00/dmx_input.cpp @@ -165,12 +165,6 @@ void DMXInput::update() USER_PRINTLN("DMX is connected!"); connected = true; } - - if (isIdentifyOn()) - { - DEBUG_PRINTLN("RDM Identify active"); - turnOnAllLeds(); - } else if (!packet.is_rdm) { dmx_read(inputPortNum, dmxdata, packet.size); @@ -192,6 +186,12 @@ void DMXInput::update() connected = false; USER_PRINTLN("DMX was disconnected."); } + + if (isIdentifyOn()) + { + DEBUG_PRINTLN("RDM Identify active"); + turnOnAllLeds(); + } } void DMXInput::turnOnAllLeds() From 84eb6fd460cbbb87712e67d789a079c9fb60e48a Mon Sep 17 00:00:00 2001 From: Arne Date: Wed, 23 Aug 2023 14:33:12 +0200 Subject: [PATCH 214/463] Add dmx input port to configuration --- wled00/data/settings_sync.htm | 1 + wled00/set.cpp | 4 +++- wled00/wled.cpp | 3 +-- wled00/wled.h | 1 + wled00/xml.cpp | 1 + 5 files changed, 7 insertions(+), 3 deletions(-) diff --git a/wled00/data/settings_sync.htm b/wled00/data/settings_sync.htm index 16bd3f7f..8e142dc9 100644 --- a/wled00/data/settings_sync.htm +++ b/wled00/data/settings_sync.htm @@ -156,6 +156,7 @@ Realtime LED offset:
DMX TX:
DMX Enable:
+ DMX Port:

This firmware build does not include DMX Input support.
diff --git a/wled00/set.cpp b/wled00/set.cpp index 9a12cdc2..08a0180a 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -423,7 +423,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) #ifdef WLED_ENABLE_DMX_INPUT dmxInputTransmitPin = request->arg(F("IDMT")).toInt(); dmxInputReceivePin = request->arg(F("IDMR")).toInt(); - dmxInputEnablePin= request->arg(F("IDME")).toInt(); + dmxInputEnablePin = request->arg(F("IDME")).toInt(); + dmxInputPort = request->arg(F("IDMP")).toInt(); + if(dmxInputPort <= 0 || dmxInputPort > 2) dmxInputPort = 2; #endif #ifndef WLED_DISABLE_ALEXA diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 8b2b3376..341036ab 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -541,8 +541,7 @@ void WLED::setup() initDMX(); #endif #ifdef WLED_ENABLE_DMX_INPUT - const uint8_t dmxInputPortNumber = 2; //TODO turn into config variable?! - dmxInput.init(dmxInputReceivePin, dmxInputTransmitPin, dmxInputEnablePin, dmxInputPortNumber); + dmxInput.init(dmxInputReceivePin, dmxInputTransmitPin, dmxInputEnablePin, dmxInputPort); #endif #ifdef WLED_ENABLE_ADALIGHT diff --git a/wled00/wled.h b/wled00/wled.h index b366e82a..b7f1ae71 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -467,6 +467,7 @@ WLED_GLOBAL bool arlsForceMaxBri _INIT(false); // enable to f WLED_GLOBAL int dmxInputTransmitPin _INIT(0); WLED_GLOBAL int dmxInputReceivePin _INIT(0); WLED_GLOBAL int dmxInputEnablePin _INIT(0); + WLED_GLOBAL int dmxInputPort _INIT(2); WLED_GLOBAL DMXInput dmxInput; #endif diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 5caa7159..aa49de02 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -446,6 +446,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) sappend('v',SET_F("IDMT"),dmxInputTransmitPin); sappend('v',SET_F("IDMR"),dmxInputReceivePin); sappend('v',SET_F("IDME"),dmxInputEnablePin); + sappend('v',SET_F("IDMP"),dmxInputPort); #endif printSetFormValue(settingsScript,PSTR("DA"),DMXAddress); printSetFormValue(settingsScript,PSTR("XX"),DMXSegmentSpacing); From 7f9cc6751875dd4882f91bf58adcb820d76cab8c Mon Sep 17 00:00:00 2001 From: Arne Date: Wed, 23 Aug 2023 14:50:22 +0200 Subject: [PATCH 215/463] Rename WLED_ENABLE_DMX to WLED_ENABLE_DMX_OUTPUT --- tools/cdata.js | 2 +- wled00/cfg.cpp | 6 +++--- wled00/const.h | 7 +++++++ wled00/dmx.cpp | 2 +- wled00/e131.cpp | 2 +- wled00/set.cpp | 2 +- wled00/wled.cpp | 6 +++--- wled00/wled.h | 7 ++++--- wled00/wled_eeprom.cpp | 4 ++-- wled00/wled_server.cpp | 10 +++++----- wled00/xml.cpp | 8 ++++---- 11 files changed, 32 insertions(+), 24 deletions(-) diff --git a/tools/cdata.js b/tools/cdata.js index c5d3c6aa..b9f29694 100644 --- a/tools/cdata.js +++ b/tools/cdata.js @@ -358,7 +358,7 @@ writeChunks( method: "plaintext", filter: "html-minify", mangle: (str) => ` -#ifdef WLED_ENABLE_DMX +#ifdef WLED_ENABLE_DMX_OUTPUT ${str.replace(/function FM\(\)[ ]?\{/gms, "function FM() {%DMXVARS%\n")} #else const char PAGE_dmxmap[] PROGMEM = R"=====()====="; diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index d3a8a0c6..4d8918db 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -651,7 +651,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { getStringFromJson(otaPass, pwd, 33); //normally not present due to security } - #ifdef WLED_ENABLE_DMX + #ifdef WLED_ENABLE_DMX_OUTPUT JsonObject dmx = doc["dmx"]; CJSON(DMXChannels, dmx[F("chan")]); CJSON(DMXGap,dmx[F("gap")]); @@ -1116,8 +1116,8 @@ void serializeConfig() { ota[F("pskl")] = strlen(otaPass); ota[F("aota")] = aOtaEnabled; - #ifdef WLED_ENABLE_DMX - JsonObject dmx = root.createNestedObject("dmx"); + #ifdef WLED_ENABLE_DMX_OUTPUT + JsonObject dmx = doc.createNestedObject("dmx"); dmx[F("chan")] = DMXChannels; dmx[F("gap")] = DMXGap; dmx["start"] = DMXStart; diff --git a/wled00/const.h b/wled00/const.h index bdd20beb..e0e4916d 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -583,6 +583,13 @@ #define DEFAULT_LED_COUNT 30 #define INTERFACE_UPDATE_COOLDOWN 1000 // time in ms to wait between websockets, alexa, and MQTT updates +#ifdef WLED_ENABLE_DMX_OUTPUT +#if (LEDPIN == 2) + #undef LEDPIN + #define LEDPIN 1 + #warning "Pin conflict compiling with DMX and LEDs on pin 2. The default LED pin has been changed to pin 1." +#endif +#endif #define PIN_RETRY_COOLDOWN 3000 // time in ms after an incorrect attempt PIN and OTA pass will be rejected even if correct #define PIN_TIMEOUT 900000 // time in ms after which the PIN will be required again, 15 minutes diff --git a/wled00/dmx.cpp b/wled00/dmx.cpp index aa05c011..efdd902e 100644 --- a/wled00/dmx.cpp +++ b/wled00/dmx.cpp @@ -10,7 +10,7 @@ * https://github.com/sparkfun/SparkFunDMX */ -#ifdef WLED_ENABLE_DMX +#ifdef WLED_ENABLE_DMX_OUTPUT void handleDMX() { diff --git a/wled00/e131.cpp b/wled00/e131.cpp index bc26a063..98ba5dfd 100644 --- a/wled00/e131.cpp +++ b/wled00/e131.cpp @@ -93,7 +93,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){ return; } - #ifdef WLED_ENABLE_DMX + #ifdef WLED_ENABLE_DMX_OUTPUT // does not act on out-of-order packets yet if (e131ProxyUniverse > 0 && uni == e131ProxyUniverse) { for (uint16_t i = 1; i <= dmxChannels; i++) diff --git a/wled00/set.cpp b/wled00/set.cpp index 08a0180a..7ffd8065 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -598,7 +598,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) } } - #ifdef WLED_ENABLE_DMX // include only if DMX is enabled + #ifdef WLED_ENABLE_DMX_OUTPUT // include only if DMX is enabled if (subPage == SUBPAGE_DMX) { int t = request->arg(F("PU")).toInt(); diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 341036ab..e19361a1 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -64,7 +64,7 @@ void WLED::loop() handleImprovWifiScan(); handleNotifications(); handleTransitions(); - #ifdef WLED_ENABLE_DMX + #ifdef WLED_ENABLE_DMX_OUTPUT handleDMX(); #endif #ifdef WLED_ENABLE_DMX_INPUT @@ -434,7 +434,7 @@ void WLED::setup() #if defined(WLED_DEBUG) && !defined(WLED_DEBUG_HOST) PinManager::allocatePin(hardwareTX, true, PinOwner::DebugOut); // TX (GPIO1 on ESP32) reserved for debug output #endif -#ifdef WLED_ENABLE_DMX //reserve GPIO2 as hardcoded DMX pin +#ifdef WLED_ENABLE_DMX_OUTPUT //reserve GPIO2 as hardcoded DMX pin PinManager::allocatePin(2, true, PinOwner::DMX); #endif @@ -537,7 +537,7 @@ void WLED::setup() ArduinoOTA.setHostname(cmDNS); } #endif -#ifdef WLED_ENABLE_DMX +#ifdef WLED_ENABLE_DMX_OUTPUT initDMX(); #endif #ifdef WLED_ENABLE_DMX_INPUT diff --git a/wled00/wled.h b/wled00/wled.h index b7f1ae71..af4a0a84 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -34,7 +34,8 @@ #else #undef WLED_ENABLE_ADALIGHT // disable has priority over enable #endif -//#define WLED_ENABLE_DMX // uses 3.5kb +//#define WLED_ENABLE_DMX_OUTPUT // uses 3.5kb (use LEDPIN other than 2) +//#define WLED_ENABLE_DMX_INPUT // Listen for DMX over Serial #ifndef WLED_DISABLE_LOXONE #define WLED_ENABLE_LOXONE // uses 1.2kb #endif @@ -136,7 +137,7 @@ #include "src/dependencies/espalexa/EspalexaDevice.h" #endif -#ifdef WLED_ENABLE_DMX +#ifdef WLED_ENABLE_DMX_OUTPUT #if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) #include "src/dependencies/dmx/ESPDMX.h" #else //ESP32 @@ -448,7 +449,7 @@ WLED_GLOBAL int arlsOffset _INIT(0); // realtime LE 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 -#ifdef WLED_ENABLE_DMX +#ifdef WLED_ENABLE_DMX_OUTPUT #if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) WLED_GLOBAL DMXESPSerial dmx; #else //ESP32 diff --git a/wled00/wled_eeprom.cpp b/wled00/wled_eeprom.cpp index 8582b49d..99995deb 100644 --- a/wled00/wled_eeprom.cpp +++ b/wled00/wled_eeprom.cpp @@ -313,7 +313,7 @@ void loadSettingsFromEEPROM() e131Port = EEPROM.read(2187) + ((EEPROM.read(2188) << 8) & 0xFF00); } - #ifdef WLED_ENABLE_DMX + #ifdef WLED_ENABLE_DMX_OUTPUT if (lastEEPROMversion > 19) { e131ProxyUniverse = EEPROM.read(2185) + ((EEPROM.read(2186) << 8) & 0xFF00); @@ -342,7 +342,7 @@ void loadSettingsFromEEPROM() //custom macro memory (16 slots/ each 64byte) //1024-2047 reserved - #ifdef WLED_ENABLE_DMX + #ifdef WLED_ENABLE_DMX_OUTPUT // DMX (2530 - 2549)2535 DMXChannels = EEPROM.read(2530); DMXGap = EEPROM.read(2531) + ((EEPROM.read(2532) << 8) & 0xFF00); diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index e8cbb41a..327cff2c 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -96,7 +96,7 @@ static void handleStaticContent(AsyncWebServerRequest *request, const String &pa request->send(response); } -#ifdef WLED_ENABLE_DMX +#ifdef WLED_ENABLE_DMX_OUTPUT static String dmxProcessor(const String& var) { String mapJS; @@ -426,7 +426,7 @@ void initServer() #endif -#ifdef WLED_ENABLE_DMX +#ifdef WLED_ENABLE_DMX_OUTPUT server.on(F("/dmxmap"), HTTP_GET, [](AsyncWebServerRequest *request){ request->send_P(200, FPSTR(CONTENT_TYPE_HTML), PAGE_dmxmap , dmxProcessor); }); @@ -554,7 +554,7 @@ void serveSettings(AsyncWebServerRequest* request, bool post) { else if (url.indexOf( "sync") > 0) subPage = SUBPAGE_SYNC; else if (url.indexOf( "time") > 0) subPage = SUBPAGE_TIME; else if (url.indexOf(F("sec")) > 0) subPage = SUBPAGE_SEC; -#ifdef WLED_ENABLE_DMX +#ifdef WLED_ENABLE_DMX_OUTPUT else if (url.indexOf( "dmx") > 0) subPage = SUBPAGE_DMX; #endif else if (url.indexOf( "um") > 0) subPage = SUBPAGE_UM; @@ -591,7 +591,7 @@ void serveSettings(AsyncWebServerRequest* request, bool post) { case SUBPAGE_SYNC : strcpy_P(s, PSTR("Sync")); break; case SUBPAGE_TIME : strcpy_P(s, PSTR("Time")); break; case SUBPAGE_SEC : strcpy_P(s, PSTR("Security")); if (doReboot) strcpy_P(s2, PSTR("Rebooting, please wait ~10 seconds...")); break; -#ifdef WLED_ENABLE_DMX +#ifdef WLED_ENABLE_DMX_OUTPUT case SUBPAGE_DMX : strcpy_P(s, PSTR("DMX")); break; #endif case SUBPAGE_UM : strcpy_P(s, PSTR("Usermods")); break; @@ -626,7 +626,7 @@ void serveSettings(AsyncWebServerRequest* request, bool post) { case SUBPAGE_SYNC : content = PAGE_settings_sync; len = PAGE_settings_sync_length; break; case SUBPAGE_TIME : content = PAGE_settings_time; len = PAGE_settings_time_length; break; case SUBPAGE_SEC : content = PAGE_settings_sec; len = PAGE_settings_sec_length; break; -#ifdef WLED_ENABLE_DMX +#ifdef WLED_ENABLE_DMX_OUTPUT case SUBPAGE_DMX : content = PAGE_settings_dmx; len = PAGE_settings_dmx_length; break; #endif case SUBPAGE_UM : content = PAGE_settings_um; len = PAGE_settings_um_length; break; diff --git a/wled00/xml.cpp b/wled00/xml.cpp index aa49de02..b3ba4a0e 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -100,7 +100,7 @@ void appendGPIOinfo(Print& settingsScript) { firstPin = false; } } - #ifdef WLED_ENABLE_DMX + #ifdef WLED_ENABLE_DMX_OUTPUT if (!firstPin) settingsScript.print(','); settingsScript.print(2); // DMX hardcoded pin firstPin = false; @@ -164,7 +164,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) #ifdef WLED_DISABLE_2D // include only if 2D is not compiled in settingsScript.print(F("gId('2dbtn').style.display='none';")); #endif - #ifdef WLED_ENABLE_DMX // include only if DMX is enabled + #ifdef WLED_ENABLE_DMX_OUTPUT // include only if DMX is enabled settingsScript.print(F("gId('dmxbtn').style.display='';")); #endif } @@ -436,7 +436,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) printSetFormCheckbox(settingsScript,PSTR("ES"),e131SkipOutOfSequence); printSetFormCheckbox(settingsScript,PSTR("EM"),e131Multicast); printSetFormValue(settingsScript,PSTR("EU"),e131Universe); -#ifdef WLED_ENABLE_DMX +#ifdef WLED_ENABLE_DMX_OUTPUT settingsScript.print(SET_F("hideNoDMX();")); // hide "not compiled in" message #endif #ifndef WLED_ENABLE_DMX_INPUT @@ -596,7 +596,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) settingsScript.printf_P(PSTR("sd=\"%s\";"), serverDescription); } - #ifdef WLED_ENABLE_DMX // include only if DMX is enabled + #ifdef WLED_ENABLE_DMX_OUTPUT // include only if DMX is enabled if (subPage == SUBPAGE_DMX) { printSetFormValue(settingsScript,PSTR("PU"),e131ProxyUniverse); From fa80c62b2862352ac073e8a3067900e0541d4a4d Mon Sep 17 00:00:00 2001 From: Arne Date: Wed, 23 Aug 2023 14:50:53 +0200 Subject: [PATCH 216/463] rename dmx.cpp -> dmx_output.cpp --- wled00/{dmx.cpp => dmx_output.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename wled00/{dmx.cpp => dmx_output.cpp} (100%) diff --git a/wled00/dmx.cpp b/wled00/dmx_output.cpp similarity index 100% rename from wled00/dmx.cpp rename to wled00/dmx_output.cpp From 11b48bc3745a7dd1b20857486c9d2c43e8ce294e Mon Sep 17 00:00:00 2001 From: Arne Date: Wed, 23 Aug 2023 14:52:57 +0200 Subject: [PATCH 217/463] rename handleDMX() handleDMXOutput() --- wled00/dmx_output.cpp | 4 ++-- wled00/fcn_declare.h | 5 +---- wled00/wled.cpp | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/wled00/dmx_output.cpp b/wled00/dmx_output.cpp index efdd902e..1c883c15 100644 --- a/wled00/dmx_output.cpp +++ b/wled00/dmx_output.cpp @@ -12,7 +12,7 @@ #ifdef WLED_ENABLE_DMX_OUTPUT -void handleDMX() +void handleDMXOutput() { // don't act, when in DMX Proxy mode if (e131ProxyUniverse != 0) return; @@ -77,5 +77,5 @@ void initDMX() { } #else void initDMX(){} -void handleDMX() {} +void handleDMXOutput() {} #endif diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index c3ada1a5..831cc68f 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -185,14 +185,11 @@ void setRandomColor(byte* rgb); //dmx.cpp void initDMX(); -void handleDMX(); -<<<<<<< HEAD -======= +void handleDMXOutput(); //dmx_input.cpp void initDMXInput(); void handleDMXInput(); ->>>>>>> b4bbf0a5 (Extract dmx_input from dmx.cpp into dmx_input.cpp.) //e131.cpp void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol); diff --git a/wled00/wled.cpp b/wled00/wled.cpp index e19361a1..27f74af0 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -65,7 +65,7 @@ void WLED::loop() handleNotifications(); handleTransitions(); #ifdef WLED_ENABLE_DMX_OUTPUT - handleDMX(); + handleDMXOutput(); #endif #ifdef WLED_ENABLE_DMX_INPUT dmxInput.update(); From 67e8a00b6dfd7673076d3617c339a8d41e59e51f Mon Sep 17 00:00:00 2001 From: Arne Date: Wed, 23 Aug 2023 15:04:28 +0200 Subject: [PATCH 218/463] rename initDmx() -> initDmxOutput() --- wled00/dmx_output.cpp | 4 ++-- wled00/fcn_declare.h | 4 ++-- wled00/wled.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/wled00/dmx_output.cpp b/wled00/dmx_output.cpp index 1c883c15..12095965 100644 --- a/wled00/dmx_output.cpp +++ b/wled00/dmx_output.cpp @@ -68,7 +68,7 @@ void handleDMXOutput() dmx.update(); // update the DMX bus } -void initDMX() { +void initDMXOutput() { #if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) dmx.init(512); // initialize with bus length #else @@ -76,6 +76,6 @@ void initDMX() { #endif } #else -void initDMX(){} +void initDMXOutput(){} void handleDMXOutput() {} #endif diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 831cc68f..db6c6b87 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -183,8 +183,8 @@ uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb); uint16_t approximateKelvinFromRGB(uint32_t rgb); void setRandomColor(byte* rgb); -//dmx.cpp -void initDMX(); +//dmx_output.cpp +void initDMXOutput(); void handleDMXOutput(); //dmx_input.cpp diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 27f74af0..44e2faf5 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -538,7 +538,7 @@ void WLED::setup() } #endif #ifdef WLED_ENABLE_DMX_OUTPUT - initDMX(); + initDMXOutput(); #endif #ifdef WLED_ENABLE_DMX_INPUT dmxInput.init(dmxInputReceivePin, dmxInputTransmitPin, dmxInputEnablePin, dmxInputPort); From 68e9d701dea5620a4daa503ee8672e8707e7cbe7 Mon Sep 17 00:00:00 2001 From: Arne Date: Fri, 25 Aug 2023 20:59:03 +0200 Subject: [PATCH 219/463] Do no longer disable dmx_input when cache is disabled. No longer needed because missing ISR_ATTR have been added to esp_dmx. --- wled00/wled.cpp | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 44e2faf5..46d156e7 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -256,17 +256,6 @@ void WLED::loop() } #endif -if (doSerializeConfig) - { - #ifdef WLED_ENABLE_DMX_INPUT - dmxInput.disable(); - #endif - - #ifdef WLED_ENABLE_DMX_INPUT - dmxInput.enable(); - #endif - } - if (doReboot && (!doInitBusses || !doSerializeConfig)) // if busses have to be inited & saved, wait until next iteration reset(); @@ -792,10 +781,6 @@ int8_t WLED::findWiFi(bool doScan) { void WLED::initConnection() { DEBUG_PRINTF_P(PSTR("initConnection() called @ %lus.\n"), millis()/1000); - - #ifdef WLED_ENABLE_DMX_INPUT - dmxInput.disable(); - #endif #ifdef WLED_ENABLE_WEBSOCKETS ws.onEvent(wsEvent); #endif @@ -824,10 +809,6 @@ void WLED::initConnection() if (!WLED_WIFI_CONFIGURED) { DEBUG_PRINTLN(F("No connection configured.")); if (!apActive) initAP(); // instantly go to ap mode - - #ifdef WLED_ENABLE_DMX_INPUT - dmxInput.enable(); - #endif return; } else if (!apActive) { if (apBehavior == AP_BEHAVIOR_ALWAYS) { @@ -878,10 +859,6 @@ void WLED::initConnection() statusESPNow = espNowOK ? ESP_NOW_STATE_ON : ESP_NOW_STATE_ERROR; } #endif - - #ifdef WLED_ENABLE_DMX_INPUT - dmxInput.enable(); - #endif } void WLED::initInterfaces() From 8f398dfd08e44497b17ed16f0432995858a0c363 Mon Sep 17 00:00:00 2001 From: Arne Date: Fri, 25 Aug 2023 20:59:46 +0200 Subject: [PATCH 220/463] Move dmx_input into its own task on core 0. This was necessary because otherwise it is not able to respond to rdm in time. --- wled00/dmx_input.cpp | 110 +++++++++++++++++++++++++++++-------------- wled00/dmx_input.h | 31 ++++++++++-- 2 files changed, 103 insertions(+), 38 deletions(-) diff --git a/wled00/dmx_input.cpp b/wled00/dmx_input.cpp index f90515fd..4ccfbab7 100644 --- a/wled00/dmx_input.cpp +++ b/wled00/dmx_input.cpp @@ -28,6 +28,7 @@ void rdmPersonalityChangedCb(dmx_port_t dmxPort, const rdm_header_t *header, USER_PRINTF("DMX personality changed to to: %d\n", DMXMode); } } + void rdmAddressChangedCb(dmx_port_t dmxPort, const rdm_header_t *header, void *context) { @@ -48,9 +49,8 @@ void rdmAddressChangedCb(dmx_port_t dmxPort, const rdm_header_t *header, } } -dmx_config_t DMXInput::createConfig() const +static dmx_config_t createConfig() { - dmx_config_t config; config.pd_size = 255; config.dmx_start_address = DMXAddress; // TODO split between input and output address @@ -91,9 +91,55 @@ dmx_config_t DMXInput::createConfig() const return config; } +void dmxReceiverTask(void *context) +{ + DMXInput *instance = static_cast(context); + if (instance == nullptr) + { + return; + } + + if (instance->installDriver()) + { + while (true) + { + instance->updateInternal(); + } + } +} + +bool DMXInput::installDriver() +{ + + const auto config = createConfig(); + if (!dmx_driver_install(inputPortNum, &config, DMX_INTR_FLAGS_DEFAULT)) + { + USER_PRINTF("Error: Failed to install dmx driver\n"); + return false; + } + + USER_PRINTF("Listening for DMX on pin %u\n", rxPin); + USER_PRINTF("Sending DMX on pin %u\n", txPin); + USER_PRINTF("DMX enable pin is: %u\n", enPin); + dmx_set_pin(inputPortNum, txPin, rxPin, enPin); + + rdm_register_dmx_start_address(inputPortNum, rdmAddressChangedCb, this); + rdm_register_dmx_personality(inputPortNum, rdmPersonalityChangedCb, this); + initialized = true; + return true; +} + void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPortNum) { +#ifdef WLED_ENABLE_DMX_OUTPUT + if(inputPortNum == dmxOutputPort) + { + USER_PRINTF("DMXInput: Error: Input port == output port"); + return; + } +#endif + if (inputPortNum < 3 && inputPortNum > 0) { this->inputPortNum = inputPortNum; @@ -121,21 +167,17 @@ void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPo return; } - const auto config = createConfig(); - if (!dmx_driver_install(inputPortNum, &config, DMX_INTR_FLAGS_DEFAULT)) + this->rxPin = rxPin; + this->txPin = txPin; + this->enPin = enPin; + + // put dmx receiver into seperate task because it should not be blocked + // pin to core 0 because wled is running on core 1 + xTaskCreatePinnedToCore(dmxReceiverTask, "DMX_RCV_TASK", 10240, this, 2, &task, 0); + if (!task) { - USER_PRINTF("Error: Failed to install dmx driver\n"); - return; + USER_PRINTF("Error: Failed to create dmx rcv task"); } - - USER_PRINTF("Listening for DMX on pin %u\n", rxPin); - USER_PRINTF("Sending DMX on pin %u\n", txPin); - USER_PRINTF("DMX enable pin is: %u\n", enPin); - dmx_set_pin(inputPortNum, txPin, rxPin, enPin); - - rdm_register_dmx_start_address(inputPortNum, rdmAddressChangedCb, this); - rdm_register_dmx_personality(inputPortNum, rdmPersonalityChangedCb, this); - initialized = true; } else { @@ -144,7 +186,7 @@ void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPo } } -void DMXInput::update() +void DMXInput::updateInternal() { if (!initialized) { @@ -153,45 +195,43 @@ void DMXInput::update() checkAndUpdateConfig(); - byte dmxdata[DMX_PACKET_SIZE]; dmx_packet_t packet; unsigned long now = millis(); - if (dmx_receive(inputPortNum, &packet, 0)) + if (dmx_receive(inputPortNum, &packet, DMX_TIMEOUT_TICK)) { if (!packet.err) { - if (!connected) - { - USER_PRINTLN("DMX is connected!"); - connected = true; - } - else if (!packet.is_rdm) + connected = true; + identify = isIdentifyOn(); + if (!packet.is_rdm) { + const std::lock_guard lock(dmxDataLock); dmx_read(inputPortNum, dmxdata, packet.size); - handleDMXData(1, 512, dmxdata, REALTIME_MODE_DMX, 0); } - - lastUpdate = now; } else { - /*This can happen when you first connect or disconnect your DMX devices. - If you are consistently getting DMX errors, then something may have gone wrong. */ - DEBUG_PRINT("A DMX error occurred - "); - DEBUG_PRINTLN(packet.err); // TODO translate err code to string for output + connected = false; } } - else if (connected && (now - lastUpdate > 5000)) + else { connected = false; - USER_PRINTLN("DMX was disconnected."); } +} - if (isIdentifyOn()) + +void DMXInput::update() +{ + if (identify) { - DEBUG_PRINTLN("RDM Identify active"); turnOnAllLeds(); } + else if (connected) + { + const std::lock_guard lock(dmxDataLock); + handleDMXData(1, 512, dmxdata, REALTIME_MODE_DMX, 0); + } } void DMXInput::turnOnAllLeds() diff --git a/wled00/dmx_input.h b/wled00/dmx_input.h index b762e59b..7a6266c5 100644 --- a/wled00/dmx_input.h +++ b/wled00/dmx_input.h @@ -1,6 +1,9 @@ #pragma once #include #include +#include +#include + /* * Support for DMX/RDM input via serial (e.g. max485) on ESP32 * ESP32 Library from: @@ -28,7 +31,12 @@ private: /// overrides everything and turns on all leds void turnOnAllLeds(); - dmx_config_t createConfig() const; + /// installs the dmx driver + /// @return false on fail + bool installDriver(); + + /// is called by the dmx receive task regularly to receive new dmx data + void updateInternal(); // is invoked whenver the dmx start address is changed via rdm friend void rdmAddressChangedCb(dmx_port_t dmxPort, const rdm_header_t *header, @@ -38,11 +46,28 @@ private: friend void rdmPersonalityChangedCb(dmx_port_t dmxPort, const rdm_header_t *header, void *context); - uint8_t inputPortNum = 255; // TODO make this configurable + /// The internal dmx task. + /// This is the main loop of the dmx receiver. It never returns. + friend void dmxReceiverTask(void * context); + + uint8_t inputPortNum = 255; + uint8_t rxPin = 255; + uint8_t txPin = 255; + uint8_t enPin = 255; + + /// is written to by the dmx receive task. + byte dmxdata[DMX_PACKET_SIZE]; //TODO add locking somehow? maybe double buffer? /// True once the dmx input has been initialized successfully bool initialized = false; // true once init finished successfully /// True if dmx is currently connected - bool connected = false; + std::atomic connected{false}; + std::atomic identify{false}; /// Timestamp of the last time a dmx frame was received unsigned long lastUpdate = 0; + + /// Taskhandle of the dmx task that is running in the background + TaskHandle_t task; + /// Guards access to dmxData + std::mutex dmxDataLock; + }; From 6598265f9bf6d2c0de6cea38c4091eb8bafa5167 Mon Sep 17 00:00:00 2001 From: Arne Date: Sun, 3 Sep 2023 16:37:19 +0200 Subject: [PATCH 221/463] make compile after rebase --- wled00/dmx_input.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/wled00/dmx_input.cpp b/wled00/dmx_input.cpp index 4ccfbab7..902303bb 100644 --- a/wled00/dmx_input.cpp +++ b/wled00/dmx_input.cpp @@ -133,11 +133,12 @@ void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPo { #ifdef WLED_ENABLE_DMX_OUTPUT - if(inputPortNum == dmxOutputPort) - { - USER_PRINTF("DMXInput: Error: Input port == output port"); - return; - } + //TODO add again once dmx output has been merged + // if(inputPortNum == dmxOutputPort) + // { + // USER_PRINTF("DMXInput: Error: Input port == output port"); + // return; + // } #endif if (inputPortNum < 3 && inputPortNum > 0) From 8570922dccc3c3cf2ffa27130c3a500b9ebacd0a Mon Sep 17 00:00:00 2001 From: Arne Date: Sun, 22 Oct 2023 20:32:46 +0200 Subject: [PATCH 222/463] chore: adapt code style --- wled00/dmx_input.cpp | 80 +++++++++++++++----------------------------- 1 file changed, 27 insertions(+), 53 deletions(-) diff --git a/wled00/dmx_input.cpp b/wled00/dmx_input.cpp index 902303bb..af0bb679 100644 --- a/wled00/dmx_input.cpp +++ b/wled00/dmx_input.cpp @@ -14,14 +14,12 @@ void rdmPersonalityChangedCb(dmx_port_t dmxPort, const rdm_header_t *header, { DMXInput *dmx = static_cast(context); - if (!dmx) - { + if (!dmx) { USER_PRINTLN("DMX: Error: no context in rdmPersonalityChangedCb"); return; } - if (header->cc == RDM_CC_SET_COMMAND_RESPONSE) - { + if (header->cc == RDM_CC_SET_COMMAND_RESPONSE) { const uint8_t personality = dmx_get_current_personality(dmx->inputPortNum); DMXMode = std::min(DMX_MODE_PRESET, std::max(DMX_MODE_SINGLE_RGB, int(personality))); doSerializeConfig = true; @@ -34,14 +32,12 @@ void rdmAddressChangedCb(dmx_port_t dmxPort, const rdm_header_t *header, { DMXInput *dmx = static_cast(context); - if (!dmx) - { + if (!dmx) { USER_PRINTLN("DMX: Error: no context in rdmAddressChangedCb"); return; } - if (header->cc == RDM_CC_SET_COMMAND_RESPONSE) - { + if (header->cc == RDM_CC_SET_COMMAND_RESPONSE) { const uint16_t addr = dmx_get_start_address(dmx->inputPortNum); DMXAddress = std::min(512, int(addr)); doSerializeConfig = true; @@ -53,7 +49,7 @@ static dmx_config_t createConfig() { dmx_config_t config; config.pd_size = 255; - config.dmx_start_address = DMXAddress; // TODO split between input and output address + config.dmx_start_address = DMXAddress; config.model_id = 0; config.product_category = RDM_PRODUCT_CATEGORY_FIXTURE; config.software_version_id = VERSION; @@ -94,15 +90,12 @@ static dmx_config_t createConfig() void dmxReceiverTask(void *context) { DMXInput *instance = static_cast(context); - if (instance == nullptr) - { + if (instance == nullptr) { return; } - if (instance->installDriver()) - { - while (true) - { + if (instance->installDriver()) { + while (true) { instance->updateInternal(); } } @@ -112,8 +105,7 @@ bool DMXInput::installDriver() { const auto config = createConfig(); - if (!dmx_driver_install(inputPortNum, &config, DMX_INTR_FLAGS_DEFAULT)) - { + if (!dmx_driver_install(inputPortNum, &config, DMX_INTR_FLAGS_DEFAULT)) { USER_PRINTF("Error: Failed to install dmx driver\n"); return false; } @@ -141,26 +133,22 @@ void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPo // } #endif - if (inputPortNum < 3 && inputPortNum > 0) - { + if (inputPortNum < 3 && inputPortNum > 0) { this->inputPortNum = inputPortNum; } - else - { + else { USER_PRINTF("DMXInput: Error: invalid inputPortNum: %d\n", inputPortNum); return; } - if (rxPin > 0 && enPin > 0 && txPin > 0) - { + if (rxPin > 0 && enPin > 0 && txPin > 0) { const managed_pin_type pins[] = { {(int8_t)txPin, false}, // these are not used as gpio pins, thus isOutput is always false. {(int8_t)rxPin, false}, {(int8_t)enPin, false}}; const bool pinsAllocated = pinManager.allocateMultiplePins(pins, 3, PinOwner::DMX_INPUT); - if (!pinsAllocated) - { + if (!pinsAllocated) { USER_PRINTF("DMXInput: Error: Failed to allocate pins for DMX_INPUT. Pins already in use:\n"); USER_PRINTF("rx in use by: %s\n", pinManager.getPinOwnerText(rxPin).c_str()); USER_PRINTF("tx in use by: %s\n", pinManager.getPinOwnerText(txPin).c_str()); @@ -175,13 +163,11 @@ void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPo // put dmx receiver into seperate task because it should not be blocked // pin to core 0 because wled is running on core 1 xTaskCreatePinnedToCore(dmxReceiverTask, "DMX_RCV_TASK", 10240, this, 2, &task, 0); - if (!task) - { + if (!task) { USER_PRINTF("Error: Failed to create dmx rcv task"); } } - else - { + else { USER_PRINTLN("DMX input disabled due to rxPin, enPin or txPin not set"); return; } @@ -189,8 +175,7 @@ void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPo void DMXInput::updateInternal() { - if (!initialized) - { + if (!initialized) { return; } @@ -198,25 +183,20 @@ void DMXInput::updateInternal() dmx_packet_t packet; unsigned long now = millis(); - if (dmx_receive(inputPortNum, &packet, DMX_TIMEOUT_TICK)) - { - if (!packet.err) - { + if (dmx_receive(inputPortNum, &packet, DMX_TIMEOUT_TICK)) { + if (!packet.err) { connected = true; identify = isIdentifyOn(); - if (!packet.is_rdm) - { + if (!packet.is_rdm) { const std::lock_guard lock(dmxDataLock); dmx_read(inputPortNum, dmxdata, packet.size); } } - else - { + else { connected = false; } } - else - { + else { connected = false; } } @@ -224,12 +204,10 @@ void DMXInput::updateInternal() void DMXInput::update() { - if (identify) - { + if (identify) { turnOnAllLeds(); } - else if (connected) - { + else if (connected) { const std::lock_guard lock(dmxDataLock); handleDMXData(1, 512, dmxdata, REALTIME_MODE_DMX, 0); } @@ -249,15 +227,13 @@ void DMXInput::turnOnAllLeds() void DMXInput::disable() { - if (initialized) - { + if (initialized) { dmx_driver_disable(inputPortNum); } } void DMXInput::enable() { - if (initialized) - { + if (initialized) { dmx_driver_enable(inputPortNum); } } @@ -282,15 +258,13 @@ void DMXInput::checkAndUpdateConfig() */ const uint8_t currentPersonality = dmx_get_current_personality(inputPortNum); - if (currentPersonality != DMXMode) - { + if (currentPersonality != DMXMode) { DEBUG_PRINTF("DMX personality has changed from %d to %d\n", currentPersonality, DMXMode); dmx_set_current_personality(inputPortNum, DMXMode); } const uint16_t currentAddr = dmx_get_start_address(inputPortNum); - if (currentAddr != DMXAddress) - { + if (currentAddr != DMXAddress) { DEBUG_PRINTF("DMX address has changed from %d to %d\n", currentAddr, DMXAddress); dmx_set_start_address(inputPortNum, DMXAddress); } From d637524bfccdc1ed7b7d6b340225aab64667543d Mon Sep 17 00:00:00 2001 From: Arne Date: Sun, 22 Oct 2023 20:45:58 +0200 Subject: [PATCH 223/463] chore: remove outdated comments --- wled00/dmx_input.h | 2 +- wled00/dmx_output.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/dmx_input.h b/wled00/dmx_input.h index 7a6266c5..0a02f2d1 100644 --- a/wled00/dmx_input.h +++ b/wled00/dmx_input.h @@ -56,7 +56,7 @@ private: uint8_t enPin = 255; /// is written to by the dmx receive task. - byte dmxdata[DMX_PACKET_SIZE]; //TODO add locking somehow? maybe double buffer? + byte dmxdata[DMX_PACKET_SIZE]; /// True once the dmx input has been initialized successfully bool initialized = false; // true once init finished successfully /// True if dmx is currently connected diff --git a/wled00/dmx_output.cpp b/wled00/dmx_output.cpp index 12095965..a868c789 100644 --- a/wled00/dmx_output.cpp +++ b/wled00/dmx_output.cpp @@ -1,7 +1,7 @@ #include "wled.h" /* - * Support for DMX input and output via serial (e.g. MAX485). + * Support for DMX output via serial (e.g. MAX485). * Change the output pin in src/dependencies/ESPDMX.cpp, if needed (ESP8266) * Change the output pin in src/dependencies/SparkFunDMX.cpp, if needed (ESP32) * ESP8266 Library from: From 3996f02dea6d41b70251a814470ad1e0b428c5ed Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Thu, 16 Jan 2025 12:19:25 +0000 Subject: [PATCH 224/463] Revert "Rename WLED_ENABLE_DMX to WLED_ENABLE_DMX_OUTPUT" This reverts commit 7f9cc6751875dd4882f91bf58adcb820d76cab8c. --- tools/cdata.js | 2 +- wled00/cfg.cpp | 6 +++--- wled00/const.h | 7 ------- wled00/dmx_output.cpp | 2 +- wled00/e131.cpp | 2 +- wled00/set.cpp | 2 +- wled00/wled.cpp | 6 +++--- wled00/wled.h | 7 +++---- wled00/wled_eeprom.cpp | 4 ++-- wled00/wled_server.cpp | 10 +++++----- wled00/xml.cpp | 8 ++++---- 11 files changed, 24 insertions(+), 32 deletions(-) diff --git a/tools/cdata.js b/tools/cdata.js index b9f29694..c5d3c6aa 100644 --- a/tools/cdata.js +++ b/tools/cdata.js @@ -358,7 +358,7 @@ writeChunks( method: "plaintext", filter: "html-minify", mangle: (str) => ` -#ifdef WLED_ENABLE_DMX_OUTPUT +#ifdef WLED_ENABLE_DMX ${str.replace(/function FM\(\)[ ]?\{/gms, "function FM() {%DMXVARS%\n")} #else const char PAGE_dmxmap[] PROGMEM = R"=====()====="; diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 4d8918db..d3a8a0c6 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -651,7 +651,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { getStringFromJson(otaPass, pwd, 33); //normally not present due to security } - #ifdef WLED_ENABLE_DMX_OUTPUT + #ifdef WLED_ENABLE_DMX JsonObject dmx = doc["dmx"]; CJSON(DMXChannels, dmx[F("chan")]); CJSON(DMXGap,dmx[F("gap")]); @@ -1116,8 +1116,8 @@ void serializeConfig() { ota[F("pskl")] = strlen(otaPass); ota[F("aota")] = aOtaEnabled; - #ifdef WLED_ENABLE_DMX_OUTPUT - JsonObject dmx = doc.createNestedObject("dmx"); + #ifdef WLED_ENABLE_DMX + JsonObject dmx = root.createNestedObject("dmx"); dmx[F("chan")] = DMXChannels; dmx[F("gap")] = DMXGap; dmx["start"] = DMXStart; diff --git a/wled00/const.h b/wled00/const.h index e0e4916d..bdd20beb 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -583,13 +583,6 @@ #define DEFAULT_LED_COUNT 30 #define INTERFACE_UPDATE_COOLDOWN 1000 // time in ms to wait between websockets, alexa, and MQTT updates -#ifdef WLED_ENABLE_DMX_OUTPUT -#if (LEDPIN == 2) - #undef LEDPIN - #define LEDPIN 1 - #warning "Pin conflict compiling with DMX and LEDs on pin 2. The default LED pin has been changed to pin 1." -#endif -#endif #define PIN_RETRY_COOLDOWN 3000 // time in ms after an incorrect attempt PIN and OTA pass will be rejected even if correct #define PIN_TIMEOUT 900000 // time in ms after which the PIN will be required again, 15 minutes diff --git a/wled00/dmx_output.cpp b/wled00/dmx_output.cpp index a868c789..eace2145 100644 --- a/wled00/dmx_output.cpp +++ b/wled00/dmx_output.cpp @@ -10,7 +10,7 @@ * https://github.com/sparkfun/SparkFunDMX */ -#ifdef WLED_ENABLE_DMX_OUTPUT +#ifdef WLED_ENABLE_DMX void handleDMXOutput() { diff --git a/wled00/e131.cpp b/wled00/e131.cpp index 98ba5dfd..bc26a063 100644 --- a/wled00/e131.cpp +++ b/wled00/e131.cpp @@ -93,7 +93,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){ return; } - #ifdef WLED_ENABLE_DMX_OUTPUT + #ifdef WLED_ENABLE_DMX // does not act on out-of-order packets yet if (e131ProxyUniverse > 0 && uni == e131ProxyUniverse) { for (uint16_t i = 1; i <= dmxChannels; i++) diff --git a/wled00/set.cpp b/wled00/set.cpp index 7ffd8065..08a0180a 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -598,7 +598,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) } } - #ifdef WLED_ENABLE_DMX_OUTPUT // include only if DMX is enabled + #ifdef WLED_ENABLE_DMX // include only if DMX is enabled if (subPage == SUBPAGE_DMX) { int t = request->arg(F("PU")).toInt(); diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 46d156e7..564f3e8c 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -64,7 +64,7 @@ void WLED::loop() handleImprovWifiScan(); handleNotifications(); handleTransitions(); - #ifdef WLED_ENABLE_DMX_OUTPUT + #ifdef WLED_ENABLE_DMX handleDMXOutput(); #endif #ifdef WLED_ENABLE_DMX_INPUT @@ -423,7 +423,7 @@ void WLED::setup() #if defined(WLED_DEBUG) && !defined(WLED_DEBUG_HOST) PinManager::allocatePin(hardwareTX, true, PinOwner::DebugOut); // TX (GPIO1 on ESP32) reserved for debug output #endif -#ifdef WLED_ENABLE_DMX_OUTPUT //reserve GPIO2 as hardcoded DMX pin +#ifdef WLED_ENABLE_DMX //reserve GPIO2 as hardcoded DMX pin PinManager::allocatePin(2, true, PinOwner::DMX); #endif @@ -526,7 +526,7 @@ void WLED::setup() ArduinoOTA.setHostname(cmDNS); } #endif -#ifdef WLED_ENABLE_DMX_OUTPUT +#ifdef WLED_ENABLE_DMX initDMXOutput(); #endif #ifdef WLED_ENABLE_DMX_INPUT diff --git a/wled00/wled.h b/wled00/wled.h index af4a0a84..b7f1ae71 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -34,8 +34,7 @@ #else #undef WLED_ENABLE_ADALIGHT // disable has priority over enable #endif -//#define WLED_ENABLE_DMX_OUTPUT // uses 3.5kb (use LEDPIN other than 2) -//#define WLED_ENABLE_DMX_INPUT // Listen for DMX over Serial +//#define WLED_ENABLE_DMX // uses 3.5kb #ifndef WLED_DISABLE_LOXONE #define WLED_ENABLE_LOXONE // uses 1.2kb #endif @@ -137,7 +136,7 @@ #include "src/dependencies/espalexa/EspalexaDevice.h" #endif -#ifdef WLED_ENABLE_DMX_OUTPUT +#ifdef WLED_ENABLE_DMX #if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) #include "src/dependencies/dmx/ESPDMX.h" #else //ESP32 @@ -449,7 +448,7 @@ WLED_GLOBAL int arlsOffset _INIT(0); // realtime LE 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 -#ifdef WLED_ENABLE_DMX_OUTPUT +#ifdef WLED_ENABLE_DMX #if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) WLED_GLOBAL DMXESPSerial dmx; #else //ESP32 diff --git a/wled00/wled_eeprom.cpp b/wled00/wled_eeprom.cpp index 99995deb..8582b49d 100644 --- a/wled00/wled_eeprom.cpp +++ b/wled00/wled_eeprom.cpp @@ -313,7 +313,7 @@ void loadSettingsFromEEPROM() e131Port = EEPROM.read(2187) + ((EEPROM.read(2188) << 8) & 0xFF00); } - #ifdef WLED_ENABLE_DMX_OUTPUT + #ifdef WLED_ENABLE_DMX if (lastEEPROMversion > 19) { e131ProxyUniverse = EEPROM.read(2185) + ((EEPROM.read(2186) << 8) & 0xFF00); @@ -342,7 +342,7 @@ void loadSettingsFromEEPROM() //custom macro memory (16 slots/ each 64byte) //1024-2047 reserved - #ifdef WLED_ENABLE_DMX_OUTPUT + #ifdef WLED_ENABLE_DMX // DMX (2530 - 2549)2535 DMXChannels = EEPROM.read(2530); DMXGap = EEPROM.read(2531) + ((EEPROM.read(2532) << 8) & 0xFF00); diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index 327cff2c..e8cbb41a 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -96,7 +96,7 @@ static void handleStaticContent(AsyncWebServerRequest *request, const String &pa request->send(response); } -#ifdef WLED_ENABLE_DMX_OUTPUT +#ifdef WLED_ENABLE_DMX static String dmxProcessor(const String& var) { String mapJS; @@ -426,7 +426,7 @@ void initServer() #endif -#ifdef WLED_ENABLE_DMX_OUTPUT +#ifdef WLED_ENABLE_DMX server.on(F("/dmxmap"), HTTP_GET, [](AsyncWebServerRequest *request){ request->send_P(200, FPSTR(CONTENT_TYPE_HTML), PAGE_dmxmap , dmxProcessor); }); @@ -554,7 +554,7 @@ void serveSettings(AsyncWebServerRequest* request, bool post) { else if (url.indexOf( "sync") > 0) subPage = SUBPAGE_SYNC; else if (url.indexOf( "time") > 0) subPage = SUBPAGE_TIME; else if (url.indexOf(F("sec")) > 0) subPage = SUBPAGE_SEC; -#ifdef WLED_ENABLE_DMX_OUTPUT +#ifdef WLED_ENABLE_DMX else if (url.indexOf( "dmx") > 0) subPage = SUBPAGE_DMX; #endif else if (url.indexOf( "um") > 0) subPage = SUBPAGE_UM; @@ -591,7 +591,7 @@ void serveSettings(AsyncWebServerRequest* request, bool post) { case SUBPAGE_SYNC : strcpy_P(s, PSTR("Sync")); break; case SUBPAGE_TIME : strcpy_P(s, PSTR("Time")); break; case SUBPAGE_SEC : strcpy_P(s, PSTR("Security")); if (doReboot) strcpy_P(s2, PSTR("Rebooting, please wait ~10 seconds...")); break; -#ifdef WLED_ENABLE_DMX_OUTPUT +#ifdef WLED_ENABLE_DMX case SUBPAGE_DMX : strcpy_P(s, PSTR("DMX")); break; #endif case SUBPAGE_UM : strcpy_P(s, PSTR("Usermods")); break; @@ -626,7 +626,7 @@ void serveSettings(AsyncWebServerRequest* request, bool post) { case SUBPAGE_SYNC : content = PAGE_settings_sync; len = PAGE_settings_sync_length; break; case SUBPAGE_TIME : content = PAGE_settings_time; len = PAGE_settings_time_length; break; case SUBPAGE_SEC : content = PAGE_settings_sec; len = PAGE_settings_sec_length; break; -#ifdef WLED_ENABLE_DMX_OUTPUT +#ifdef WLED_ENABLE_DMX case SUBPAGE_DMX : content = PAGE_settings_dmx; len = PAGE_settings_dmx_length; break; #endif case SUBPAGE_UM : content = PAGE_settings_um; len = PAGE_settings_um_length; break; diff --git a/wled00/xml.cpp b/wled00/xml.cpp index b3ba4a0e..aa49de02 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -100,7 +100,7 @@ void appendGPIOinfo(Print& settingsScript) { firstPin = false; } } - #ifdef WLED_ENABLE_DMX_OUTPUT + #ifdef WLED_ENABLE_DMX if (!firstPin) settingsScript.print(','); settingsScript.print(2); // DMX hardcoded pin firstPin = false; @@ -164,7 +164,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) #ifdef WLED_DISABLE_2D // include only if 2D is not compiled in settingsScript.print(F("gId('2dbtn').style.display='none';")); #endif - #ifdef WLED_ENABLE_DMX_OUTPUT // include only if DMX is enabled + #ifdef WLED_ENABLE_DMX // include only if DMX is enabled settingsScript.print(F("gId('dmxbtn').style.display='';")); #endif } @@ -436,7 +436,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) printSetFormCheckbox(settingsScript,PSTR("ES"),e131SkipOutOfSequence); printSetFormCheckbox(settingsScript,PSTR("EM"),e131Multicast); printSetFormValue(settingsScript,PSTR("EU"),e131Universe); -#ifdef WLED_ENABLE_DMX_OUTPUT +#ifdef WLED_ENABLE_DMX settingsScript.print(SET_F("hideNoDMX();")); // hide "not compiled in" message #endif #ifndef WLED_ENABLE_DMX_INPUT @@ -596,7 +596,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) settingsScript.printf_P(PSTR("sd=\"%s\";"), serverDescription); } - #ifdef WLED_ENABLE_DMX_OUTPUT // include only if DMX is enabled + #ifdef WLED_ENABLE_DMX // include only if DMX is enabled if (subPage == SUBPAGE_DMX) { printSetFormValue(settingsScript,PSTR("PU"),e131ProxyUniverse); From ebfc438bd4f7a18918de2a8b07fd467ab1a1d82d Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Tue, 16 Jan 2024 20:13:52 +0000 Subject: [PATCH 225/463] Tweak DMX settings UI --- wled00/data/settings_sync.htm | 8 ++++---- wled00/dmx_input.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/wled00/data/settings_sync.htm b/wled00/data/settings_sync.htm index 8e142dc9..55028848 100644 --- a/wled00/data/settings_sync.htm +++ b/wled00/data/settings_sync.htm @@ -152,10 +152,10 @@ Force max brightness:
Disable realtime gamma correction:
Realtime LED offset:
- DMX Input Pins
- DMX RX:
- DMX TX:
- DMX Enable:
+

Wired DMX Input Pins

+ DMX RX: RO
+ DMX TX: DI
+ DMX Enable: RE+DE
DMX Port:
diff --git a/wled00/dmx_input.h b/wled00/dmx_input.h index 0a02f2d1..7845778d 100644 --- a/wled00/dmx_input.h +++ b/wled00/dmx_input.h @@ -7,7 +7,7 @@ /* * Support for DMX/RDM input via serial (e.g. max485) on ESP32 * ESP32 Library from: - * https://github.com/sparkfun/SparkFunDMX + * https://github.com/someweisguy/esp_dmx */ class DMXInput { From a56014bb668d4871f997971d571be330b6f39952 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 17 Jan 2024 18:03:16 +0000 Subject: [PATCH 226/463] Hide DMX port as just confusing to users --- wled00/data/settings_sync.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/data/settings_sync.htm b/wled00/data/settings_sync.htm index 55028848..fabb2d5d 100644 --- a/wled00/data/settings_sync.htm +++ b/wled00/data/settings_sync.htm @@ -156,7 +156,7 @@ Realtime LED offset: RO
DMX TX: DI
DMX Enable: RE+DE
- DMX Port:
+
DMX Port:

This firmware build does not include DMX Input support.
From fc4e7a2deeb5e4db10ee3e05f113131bf19d7d73 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Thu, 7 Mar 2024 10:44:07 +0000 Subject: [PATCH 227/463] Swap DMX port to 1, persist user choice of port, validate port vs UART count --- wled00/cfg.cpp | 2 ++ wled00/data/settings_sync.htm | 2 +- wled00/dmx_input.cpp | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index d3a8a0c6..443f16c7 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -527,6 +527,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { CJSON(dmxInputTransmitPin, if_live_dmx[F("inputRxPin")]); CJSON(dmxInputReceivePin, if_live_dmx[F("inputTxPin")]); CJSON(dmxInputEnablePin, if_live_dmx[F("inputEnablePin")]); + CJSON(dmxInputPort, if_live_dmx[F("dmxInputPort")]); #endif CJSON(arlsForceMaxBri, if_live[F("maxbri")]); @@ -1012,6 +1013,7 @@ void serializeConfig() { if_live_dmx[F("inputRxPin")] = dmxInputTransmitPin; if_live_dmx[F("inputTxPin")] = dmxInputReceivePin; if_live_dmx[F("inputEnablePin")] = dmxInputEnablePin; + if_live_dmx[F("dmxInputPort")] = dmxInputPort; #endif if_live[F("timeout")] = realtimeTimeoutMs / 100; diff --git a/wled00/data/settings_sync.htm b/wled00/data/settings_sync.htm index fabb2d5d..55028848 100644 --- a/wled00/data/settings_sync.htm +++ b/wled00/data/settings_sync.htm @@ -156,7 +156,7 @@ Realtime LED offset: RO
DMX TX: DI
DMX Enable: RE+DE
-
DMX Port:
+ DMX Port:

This firmware build does not include DMX Input support.
diff --git a/wled00/dmx_input.cpp b/wled00/dmx_input.cpp index af0bb679..facafe17 100644 --- a/wled00/dmx_input.cpp +++ b/wled00/dmx_input.cpp @@ -105,6 +105,7 @@ bool DMXInput::installDriver() { const auto config = createConfig(); + USER_PRINTF("DMX port: %u\n", inputPortNum); if (!dmx_driver_install(inputPortNum, &config, DMX_INTR_FLAGS_DEFAULT)) { USER_PRINTF("Error: Failed to install dmx driver\n"); return false; @@ -133,7 +134,7 @@ void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPo // } #endif - if (inputPortNum < 3 && inputPortNum > 0) { + if (inputPortNum <= (SOC_UART_NUM - 1) && inputPortNum > 0) { this->inputPortNum = inputPortNum; } else { From 9a6e91d3e5039f252b347c314a2a69526c8cc34a Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Tue, 30 Jul 2024 19:15:08 +0100 Subject: [PATCH 228/463] DMX Input - reinstate loggers for connection state change --- wled00/dmx_input.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/wled00/dmx_input.cpp b/wled00/dmx_input.cpp index facafe17..ffdea632 100644 --- a/wled00/dmx_input.cpp +++ b/wled00/dmx_input.cpp @@ -186,6 +186,9 @@ void DMXInput::updateInternal() unsigned long now = millis(); if (dmx_receive(inputPortNum, &packet, DMX_TIMEOUT_TICK)) { if (!packet.err) { + if(!connected) { + USER_PRINTLN("DMX Input - connected"); + } connected = true; identify = isIdentifyOn(); if (!packet.is_rdm) { @@ -198,6 +201,9 @@ void DMXInput::updateInternal() } } else { + if(connected) { + USER_PRINTLN("DMX Input - disconnected"); + } connected = false; } } From 953e994c88abf5e6b62f5026730635c96a0d8278 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Thu, 16 Jan 2025 12:24:42 +0000 Subject: [PATCH 229/463] Add DMX Input support to builds --- platformio.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/platformio.ini b/platformio.ini index 9b9b693f..18a2db8a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -282,8 +282,10 @@ build_flags = -g -DARDUINO_ARCH_ESP32 -DESP32 -D CONFIG_ASYNC_TCP_USE_WDT=0 -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3 + -D WLED_ENABLE_DMX_INPUT lib_deps = https://github.com/pbolduc/AsyncTCP.git @ 1.2.0 + https://github.com/someweisguy/esp_dmx.git#47db25d ${env.lib_deps} board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs From a58278665568eff509df0b721bc8ce23cc04e412 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Thu, 16 Jan 2025 12:48:36 +0000 Subject: [PATCH 230/463] Port over remaining WLEDMM part of DMX Input and adapt for AC --- wled00/const.h | 1 + wled00/data/settings_sync.htm | 6 +++--- wled00/dmx_input.cpp | 40 +++++++++++++++++------------------ wled00/e131.cpp | 11 +++++++--- wled00/fcn_declare.h | 1 + wled00/xml.cpp | 10 ++++----- 6 files changed, 38 insertions(+), 31 deletions(-) diff --git a/wled00/const.h b/wled00/const.h index bdd20beb..b5eb20f8 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -249,6 +249,7 @@ #define REALTIME_MODE_ARTNET 6 #define REALTIME_MODE_TPM2NET 7 #define REALTIME_MODE_DDP 8 +#define REALTIME_MODE_DMX 9 //realtime override modes #define REALTIME_OVERRIDE_NONE 0 diff --git a/wled00/data/settings_sync.htm b/wled00/data/settings_sync.htm index 55028848..775f87a9 100644 --- a/wled00/data/settings_sync.htm +++ b/wled00/data/settings_sync.htm @@ -151,17 +151,17 @@ Timeout: ms
Force max brightness:
Disable realtime gamma correction:
Realtime LED offset: -
+

Wired DMX Input Pins

DMX RX: RO
DMX TX: DI
DMX Enable: RE+DE
DMX Port:
-
+

This firmware build does not include DMX Input support.
-
+

This firmware build does not include DMX output support.

diff --git a/wled00/dmx_input.cpp b/wled00/dmx_input.cpp index ffdea632..afbc9f0d 100644 --- a/wled00/dmx_input.cpp +++ b/wled00/dmx_input.cpp @@ -15,7 +15,7 @@ void rdmPersonalityChangedCb(dmx_port_t dmxPort, const rdm_header_t *header, DMXInput *dmx = static_cast(context); if (!dmx) { - USER_PRINTLN("DMX: Error: no context in rdmPersonalityChangedCb"); + DEBUG_PRINTLN("DMX: Error: no context in rdmPersonalityChangedCb"); return; } @@ -23,7 +23,7 @@ void rdmPersonalityChangedCb(dmx_port_t dmxPort, const rdm_header_t *header, const uint8_t personality = dmx_get_current_personality(dmx->inputPortNum); DMXMode = std::min(DMX_MODE_PRESET, std::max(DMX_MODE_SINGLE_RGB, int(personality))); doSerializeConfig = true; - USER_PRINTF("DMX personality changed to to: %d\n", DMXMode); + DEBUG_PRINTF("DMX personality changed to to: %d\n", DMXMode); } } @@ -33,7 +33,7 @@ void rdmAddressChangedCb(dmx_port_t dmxPort, const rdm_header_t *header, DMXInput *dmx = static_cast(context); if (!dmx) { - USER_PRINTLN("DMX: Error: no context in rdmAddressChangedCb"); + DEBUG_PRINTLN("DMX: Error: no context in rdmAddressChangedCb"); return; } @@ -41,7 +41,7 @@ void rdmAddressChangedCb(dmx_port_t dmxPort, const rdm_header_t *header, const uint16_t addr = dmx_get_start_address(dmx->inputPortNum); DMXAddress = std::min(512, int(addr)); doSerializeConfig = true; - USER_PRINTF("DMX start addr changed to: %d\n", DMXAddress); + DEBUG_PRINTF("DMX start addr changed to: %d\n", DMXAddress); } } @@ -105,15 +105,15 @@ bool DMXInput::installDriver() { const auto config = createConfig(); - USER_PRINTF("DMX port: %u\n", inputPortNum); + DEBUG_PRINTF("DMX port: %u\n", inputPortNum); if (!dmx_driver_install(inputPortNum, &config, DMX_INTR_FLAGS_DEFAULT)) { - USER_PRINTF("Error: Failed to install dmx driver\n"); + DEBUG_PRINTF("Error: Failed to install dmx driver\n"); return false; } - USER_PRINTF("Listening for DMX on pin %u\n", rxPin); - USER_PRINTF("Sending DMX on pin %u\n", txPin); - USER_PRINTF("DMX enable pin is: %u\n", enPin); + DEBUG_PRINTF("Listening for DMX on pin %u\n", rxPin); + DEBUG_PRINTF("Sending DMX on pin %u\n", txPin); + DEBUG_PRINTF("DMX enable pin is: %u\n", enPin); dmx_set_pin(inputPortNum, txPin, rxPin, enPin); rdm_register_dmx_start_address(inputPortNum, rdmAddressChangedCb, this); @@ -129,7 +129,7 @@ void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPo //TODO add again once dmx output has been merged // if(inputPortNum == dmxOutputPort) // { - // USER_PRINTF("DMXInput: Error: Input port == output port"); + // DEBUG_PRINTF("DMXInput: Error: Input port == output port"); // return; // } #endif @@ -138,7 +138,7 @@ void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPo this->inputPortNum = inputPortNum; } else { - USER_PRINTF("DMXInput: Error: invalid inputPortNum: %d\n", inputPortNum); + DEBUG_PRINTF("DMXInput: Error: invalid inputPortNum: %d\n", inputPortNum); return; } @@ -148,12 +148,12 @@ void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPo {(int8_t)txPin, false}, // these are not used as gpio pins, thus isOutput is always false. {(int8_t)rxPin, false}, {(int8_t)enPin, false}}; - const bool pinsAllocated = pinManager.allocateMultiplePins(pins, 3, PinOwner::DMX_INPUT); + const bool pinsAllocated = PinManager::allocateMultiplePins(pins, 3, PinOwner::DMX_INPUT); if (!pinsAllocated) { - USER_PRINTF("DMXInput: Error: Failed to allocate pins for DMX_INPUT. Pins already in use:\n"); - USER_PRINTF("rx in use by: %s\n", pinManager.getPinOwnerText(rxPin).c_str()); - USER_PRINTF("tx in use by: %s\n", pinManager.getPinOwnerText(txPin).c_str()); - USER_PRINTF("en in use by: %s\n", pinManager.getPinOwnerText(enPin).c_str()); + DEBUG_PRINTF("DMXInput: Error: Failed to allocate pins for DMX_INPUT. Pins already in use:\n"); + DEBUG_PRINTF("rx in use by: %s\n", pinManager.getPinOwnerText(rxPin).c_str()); + DEBUG_PRINTF("tx in use by: %s\n", pinManager.getPinOwnerText(txPin).c_str()); + DEBUG_PRINTF("en in use by: %s\n", pinManager.getPinOwnerText(enPin).c_str()); return; } @@ -165,11 +165,11 @@ void DMXInput::init(uint8_t rxPin, uint8_t txPin, uint8_t enPin, uint8_t inputPo // pin to core 0 because wled is running on core 1 xTaskCreatePinnedToCore(dmxReceiverTask, "DMX_RCV_TASK", 10240, this, 2, &task, 0); if (!task) { - USER_PRINTF("Error: Failed to create dmx rcv task"); + DEBUG_PRINTF("Error: Failed to create dmx rcv task"); } } else { - USER_PRINTLN("DMX input disabled due to rxPin, enPin or txPin not set"); + DEBUG_PRINTLN("DMX input disabled due to rxPin, enPin or txPin not set"); return; } } @@ -187,7 +187,7 @@ void DMXInput::updateInternal() if (dmx_receive(inputPortNum, &packet, DMX_TIMEOUT_TICK)) { if (!packet.err) { if(!connected) { - USER_PRINTLN("DMX Input - connected"); + DEBUG_PRINTLN("DMX Input - connected"); } connected = true; identify = isIdentifyOn(); @@ -202,7 +202,7 @@ void DMXInput::updateInternal() } else { if(connected) { - USER_PRINTLN("DMX Input - disconnected"); + DEBUG_PRINTLN("DMX Input - disconnected"); } connected = false; } diff --git a/wled00/e131.cpp b/wled00/e131.cpp index bc26a063..c16ed933 100644 --- a/wled00/e131.cpp +++ b/wled00/e131.cpp @@ -116,6 +116,11 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){ // update status info realtimeIP = clientIP; + + handleDMXData(uni, dmxChannels, e131_data, mde, previousUniverses); +} + +void handleDMXData(uint16_t uni, uint16_t dmxChannels, uint8_t* e131_data, uint8_t mde, uint8_t previousUniverses) { byte wChannel = 0; unsigned totalLen = strip.getLengthTotal(); unsigned availDMXLen = 0; @@ -130,7 +135,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){ } // DMX data in Art-Net packet starts at index 0, for E1.31 at index 1 - if (protocol == P_ARTNET && dataOffset > 0) { + if (mde == REALTIME_MODE_ARTNET && dataOffset > 0) { dataOffset--; } @@ -211,7 +216,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){ else dataOffset = DMXAddress; // Modify address for Art-Net data - if (protocol == P_ARTNET && dataOffset > 0) + if (mde == REALTIME_MODE_ARTNET && dataOffset > 0) dataOffset--; // Skip out of universe addresses if (dataOffset > dmxChannels - dmxEffectChannels + 1) @@ -285,7 +290,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){ } } else { // All subsequent universes start at the first channel. - dmxOffset = (protocol == P_ARTNET) ? 0 : 1; + dmxOffset = (mde == REALTIME_MODE_ARTNET) ? 0 : 1; const unsigned dimmerOffset = (DMXMode == DMX_MODE_MULTIPLE_DRGB) ? 1 : 0; unsigned ledsInFirstUniverse = (((MAX_CHANNELS_PER_UNIVERSE - DMXAddress) + dmxLenOffset) - dimmerOffset) / dmxChannelsPerLed; previousLeds = ledsInFirstUniverse + (previousUniverses - 1) * ledsPerUniverse; diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index db6c6b87..c7fa9daa 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -193,6 +193,7 @@ void handleDMXInput(); //e131.cpp void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol); +void handleDMXData(uint16_t uni, uint16_t dmxChannels, uint8_t* e131_data, uint8_t mde, uint8_t previousUniverses); void handleArtnetPollReply(IPAddress ipAddress); void prepareArtnetPollReply(ArtPollReply* reply); void sendArtnetPollReply(ArtPollReply* reply, IPAddress ipAddress, uint16_t portAddress); diff --git a/wled00/xml.cpp b/wled00/xml.cpp index aa49de02..0ed32c04 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -442,11 +442,11 @@ void getSettingsJS(byte subPage, Print& settingsScript) #ifndef WLED_ENABLE_DMX_INPUT settingsScript.print(SET_F("hideDMXInput();")); // hide "dmx input" settings #else - settingsScript.print(SET_F("hideNoDMXInput();")); //hide "not comp iled in" message - sappend('v',SET_F("IDMT"),dmxInputTransmitPin); - sappend('v',SET_F("IDMR"),dmxInputReceivePin); - sappend('v',SET_F("IDME"),dmxInputEnablePin); - sappend('v',SET_F("IDMP"),dmxInputPort); + settingsScript.print(SET_F("hideNoDMXInput();")); //hide "not compiled in" message + printSetFormValue(settingsScript,SET_F("IDMT"),dmxInputTransmitPin); + printSetFormValue(settingsScript,SET_F("IDMR"),dmxInputReceivePin); + printSetFormValue(settingsScript,SET_F("IDME"),dmxInputEnablePin); + printSetFormValue(settingsScript,SET_F("IDMP"),dmxInputPort); #endif printSetFormValue(settingsScript,PSTR("DA"),DMXAddress); printSetFormValue(settingsScript,PSTR("XX"),DMXSegmentSpacing); From 193926c795961bf30de3c5f44d19ffeb13c4c9d9 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Fri, 17 Jan 2025 00:50:02 +0000 Subject: [PATCH 231/463] usermods: Remove #pragma once from cpps --- usermods/ADS1115_v2/ADS1115_v2.cpp | 2 -- usermods/AHT10_v2/AHT10_v2.cpp | 2 -- usermods/Analog_Clock/Analog_Clock.cpp | 1 - usermods/Animated_Staircase/Animated_Staircase.cpp | 1 - usermods/BH1750_v2/BH1750_v2.cpp | 2 -- usermods/BME280_v2/BME280_v2.cpp | 2 -- usermods/BME68X_v2/BME68X_v2.cpp | 1 - usermods/Battery/Battery.cpp | 2 -- usermods/Cronixie/Cronixie.cpp | 2 -- usermods/DHT/DHT.cpp | 2 -- usermods/EleksTube_IPS/EleksTube_IPS.cpp | 1 - usermods/INA226_v2/INA226_v2.cpp | 2 -- .../Internal_Temperature_v2/Internal_Temperature_v2.cpp | 2 -- usermods/LD2410_v2/LD2410_v2.cpp | 2 -- usermods/LDR_Dusk_Dawn_v2/LDR_Dusk_Dawn_v2.cpp | 1 - usermods/MAX17048_v2/MAX17048_v2.cpp | 2 -- usermods/MY9291/MY9291.cpp | 2 -- usermods/PIR_sensor_switch/PIR_sensor_switch.cpp | 8 +++----- usermods/PWM_fan/PWM_fan.cpp | 2 -- usermods/RTC/RTC.cpp | 2 -- usermods/SN_Photoresistor/SN_Photoresistor.cpp | 2 -- usermods/ST7789_display/ST7789_display.cpp | 2 -- usermods/Si7021_MQTT_HA/Si7021_MQTT_HA.cpp | 2 -- usermods/Temperature/Temperature.cpp | 2 -- usermods/TetrisAI_v2/TetrisAI_v2.cpp | 2 -- usermods/VL53L0X_gestures/VL53L0X_gestures.cpp | 2 -- usermods/boblight/boblight.cpp | 2 -- usermods/buzzer/buzzer.cpp | 2 -- usermods/deep_sleep/deep_sleep.cpp | 2 -- usermods/mpu6050_imu/mpu6050_imu.cpp | 2 -- usermods/mqtt_switch_v2/mqtt_switch_v2.cpp | 2 -- usermods/multi_relay/multi_relay.cpp | 2 -- usermods/pixels_dice_tray/pixels_dice_tray.cpp | 2 -- usermods/pov_display/pov_display.cpp | 1 - usermods/pwm_outputs/pwm_outputs.cpp | 1 - usermods/quinled-an-penta/quinled-an-penta.cpp | 2 -- usermods/rgb-rotary-encoder/rgb-rotary-encoder.cpp | 2 -- usermods/sd_card/sd_card.cpp | 2 -- usermods/sensors_to_mqtt/sensors_to_mqtt.cpp | 2 -- usermods/seven_segment_display/seven_segment_display.cpp | 2 -- .../seven_segment_display_reloaded.cpp | 2 -- usermods/sht/sht.cpp | 2 -- usermods/smartnest/smartnest.cpp | 2 -- .../usermod_rotary_brightness_color.cpp | 2 -- usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp | 2 -- .../usermod_v2_four_line_display_ALT.cpp | 2 -- .../usermod_v2_klipper_percentage.cpp | 2 -- .../usermod_v2_ping_pong_clock.cpp | 2 -- .../usermod_v2_rotary_encoder_ui_ALT.cpp | 2 -- usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp | 2 -- usermods/wireguard/wireguard.cpp | 2 -- usermods/wizlights/wizlights.cpp | 2 -- usermods/word-clock-matrix/word-clock-matrix.cpp | 2 -- 53 files changed, 3 insertions(+), 102 deletions(-) diff --git a/usermods/ADS1115_v2/ADS1115_v2.cpp b/usermods/ADS1115_v2/ADS1115_v2.cpp index 48f91733..bbf457f4 100644 --- a/usermods/ADS1115_v2/ADS1115_v2.cpp +++ b/usermods/ADS1115_v2/ADS1115_v2.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" #include #include diff --git a/usermods/AHT10_v2/AHT10_v2.cpp b/usermods/AHT10_v2/AHT10_v2.cpp index a5d30c0e..f88bee1d 100644 --- a/usermods/AHT10_v2/AHT10_v2.cpp +++ b/usermods/AHT10_v2/AHT10_v2.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" #include diff --git a/usermods/Analog_Clock/Analog_Clock.cpp b/usermods/Analog_Clock/Analog_Clock.cpp index 8a4c048a..970ba722 100644 --- a/usermods/Analog_Clock/Analog_Clock.cpp +++ b/usermods/Analog_Clock/Analog_Clock.cpp @@ -1,4 +1,3 @@ -#pragma once #include "wled.h" /* diff --git a/usermods/Animated_Staircase/Animated_Staircase.cpp b/usermods/Animated_Staircase/Animated_Staircase.cpp index 43d9db6b..2d2d27cf 100644 --- a/usermods/Animated_Staircase/Animated_Staircase.cpp +++ b/usermods/Animated_Staircase/Animated_Staircase.cpp @@ -7,7 +7,6 @@ * * See the accompanying README.md file for more info. */ -#pragma once #include "wled.h" class Animated_Staircase : public Usermod { diff --git a/usermods/BH1750_v2/BH1750_v2.cpp b/usermods/BH1750_v2/BH1750_v2.cpp index 5bd47624..ec29f5b9 100644 --- a/usermods/BH1750_v2/BH1750_v2.cpp +++ b/usermods/BH1750_v2/BH1750_v2.cpp @@ -5,8 +5,6 @@ #error "This user mod requires MQTT to be enabled." #endif -#pragma once - #include "wled.h" #include diff --git a/usermods/BME280_v2/BME280_v2.cpp b/usermods/BME280_v2/BME280_v2.cpp index d29451ee..8cc986aa 100644 --- a/usermods/BME280_v2/BME280_v2.cpp +++ b/usermods/BME280_v2/BME280_v2.cpp @@ -5,8 +5,6 @@ #error "This user mod requires MQTT to be enabled." #endif -#pragma once - #include "wled.h" #include #include // BME280 sensor diff --git a/usermods/BME68X_v2/BME68X_v2.cpp b/usermods/BME68X_v2/BME68X_v2.cpp index 5814506b..081d03ff 100644 --- a/usermods/BME68X_v2/BME68X_v2.cpp +++ b/usermods/BME68X_v2/BME68X_v2.cpp @@ -6,7 +6,6 @@ * @date 19 Feb 2024 */ -#pragma once #warning ********************Included USERMOD_BME68X ******************** #define UMOD_DEVICE "ESP32" // NOTE - Set your hardware here diff --git a/usermods/Battery/Battery.cpp b/usermods/Battery/Battery.cpp index 4646a238..5572f550 100644 --- a/usermods/Battery/Battery.cpp +++ b/usermods/Battery/Battery.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" #include "battery_defaults.h" #include "UMBattery.h" diff --git a/usermods/Cronixie/Cronixie.cpp b/usermods/Cronixie/Cronixie.cpp index 09e7e25a..05557de0 100644 --- a/usermods/Cronixie/Cronixie.cpp +++ b/usermods/Cronixie/Cronixie.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" class UsermodCronixie : public Usermod { diff --git a/usermods/DHT/DHT.cpp b/usermods/DHT/DHT.cpp index fad6dad5..0b481064 100644 --- a/usermods/DHT/DHT.cpp +++ b/usermods/DHT/DHT.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" #ifndef WLED_ENABLE_MQTT #error "This user mod requires MQTT to be enabled." diff --git a/usermods/EleksTube_IPS/EleksTube_IPS.cpp b/usermods/EleksTube_IPS/EleksTube_IPS.cpp index 48fbb2b4..e8637b0f 100644 --- a/usermods/EleksTube_IPS/EleksTube_IPS.cpp +++ b/usermods/EleksTube_IPS/EleksTube_IPS.cpp @@ -1,4 +1,3 @@ -#pragma once #include "TFTs.h" #include "wled.h" diff --git a/usermods/INA226_v2/INA226_v2.cpp b/usermods/INA226_v2/INA226_v2.cpp index 0284a6fa..26f92f49 100644 --- a/usermods/INA226_v2/INA226_v2.cpp +++ b/usermods/INA226_v2/INA226_v2.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" #include diff --git a/usermods/Internal_Temperature_v2/Internal_Temperature_v2.cpp b/usermods/Internal_Temperature_v2/Internal_Temperature_v2.cpp index ab7f907e..7c30985e 100644 --- a/usermods/Internal_Temperature_v2/Internal_Temperature_v2.cpp +++ b/usermods/Internal_Temperature_v2/Internal_Temperature_v2.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" class InternalTemperatureUsermod : public Usermod diff --git a/usermods/LD2410_v2/LD2410_v2.cpp b/usermods/LD2410_v2/LD2410_v2.cpp index 51c887fa..7c1c3674 100644 --- a/usermods/LD2410_v2/LD2410_v2.cpp +++ b/usermods/LD2410_v2/LD2410_v2.cpp @@ -4,8 +4,6 @@ #error "This user mod requires MQTT to be enabled." #endif -#pragma once - #include "wled.h" #include diff --git a/usermods/LDR_Dusk_Dawn_v2/LDR_Dusk_Dawn_v2.cpp b/usermods/LDR_Dusk_Dawn_v2/LDR_Dusk_Dawn_v2.cpp index 6104fcab..9c5c835e 100644 --- a/usermods/LDR_Dusk_Dawn_v2/LDR_Dusk_Dawn_v2.cpp +++ b/usermods/LDR_Dusk_Dawn_v2/LDR_Dusk_Dawn_v2.cpp @@ -1,4 +1,3 @@ -#pragma once #include "wled.h" #ifndef ARDUINO_ARCH_ESP32 diff --git a/usermods/MAX17048_v2/MAX17048_v2.cpp b/usermods/MAX17048_v2/MAX17048_v2.cpp index 1a1108cf..c284bca7 100644 --- a/usermods/MAX17048_v2/MAX17048_v2.cpp +++ b/usermods/MAX17048_v2/MAX17048_v2.cpp @@ -1,8 +1,6 @@ // force the compiler to show a warning to confirm that this file is included #warning **** Included USERMOD_MAX17048 V2.0 **** -#pragma once - #include "wled.h" #include "Adafruit_MAX1704X.h" diff --git a/usermods/MY9291/MY9291.cpp b/usermods/MY9291/MY9291.cpp index ce8d0f00..3881ffd0 100644 --- a/usermods/MY9291/MY9291.cpp +++ b/usermods/MY9291/MY9291.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" #include "MY92xx.h" diff --git a/usermods/PIR_sensor_switch/PIR_sensor_switch.cpp b/usermods/PIR_sensor_switch/PIR_sensor_switch.cpp index 1cc31a08..20e4bc14 100644 --- a/usermods/PIR_sensor_switch/PIR_sensor_switch.cpp +++ b/usermods/PIR_sensor_switch/PIR_sensor_switch.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" #ifndef PIR_SENSOR_PIN @@ -571,7 +569,7 @@ bool PIRsensorSwitch::readFromConfig(JsonObject &root) // use "return !top["newestParameter"].isNull();" when updating Usermod with new features return !(pins.isNull() || pins.size() != PIR_SENSOR_MAX_SENSORS); } - - -static PIRsensorSwitch pir_sensor_switch; + + +static PIRsensorSwitch pir_sensor_switch; REGISTER_USERMOD(pir_sensor_switch); \ No newline at end of file diff --git a/usermods/PWM_fan/PWM_fan.cpp b/usermods/PWM_fan/PWM_fan.cpp index 9df37304..a89a1f32 100644 --- a/usermods/PWM_fan/PWM_fan.cpp +++ b/usermods/PWM_fan/PWM_fan.cpp @@ -1,5 +1,3 @@ -#pragma once - #if !defined(USERMOD_DALLASTEMPERATURE) && !defined(USERMOD_SHT) #error The "PWM fan" usermod requires "Dallas Temeprature" or "SHT" usermod to function properly. #endif diff --git a/usermods/RTC/RTC.cpp b/usermods/RTC/RTC.cpp index f9dbe3cf..2b9c3b4f 100644 --- a/usermods/RTC/RTC.cpp +++ b/usermods/RTC/RTC.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "src/dependencies/time/DS1307RTC.h" #include "wled.h" diff --git a/usermods/SN_Photoresistor/SN_Photoresistor.cpp b/usermods/SN_Photoresistor/SN_Photoresistor.cpp index 5e50ab7a..97f865a9 100644 --- a/usermods/SN_Photoresistor/SN_Photoresistor.cpp +++ b/usermods/SN_Photoresistor/SN_Photoresistor.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" //Pin defaults for QuinLed Dig-Uno (A0) diff --git a/usermods/ST7789_display/ST7789_display.cpp b/usermods/ST7789_display/ST7789_display.cpp index e81c53ba..c596baec 100644 --- a/usermods/ST7789_display/ST7789_display.cpp +++ b/usermods/ST7789_display/ST7789_display.cpp @@ -1,8 +1,6 @@ // Credits to @mrVanboy, @gwaland and my dearest friend @westward // Also for @spiff72 for usermod TTGO-T-Display // 210217 -#pragma once - #include "wled.h" #include #include diff --git a/usermods/Si7021_MQTT_HA/Si7021_MQTT_HA.cpp b/usermods/Si7021_MQTT_HA/Si7021_MQTT_HA.cpp index 04f6d750..8640ceb8 100644 --- a/usermods/Si7021_MQTT_HA/Si7021_MQTT_HA.cpp +++ b/usermods/Si7021_MQTT_HA/Si7021_MQTT_HA.cpp @@ -2,8 +2,6 @@ #error "This user mod requires MQTT to be enabled." #endif -#pragma once - // this is remixed from usermod_v2_SensorsToMqtt.h (sensors_to_mqtt usermod) // and usermod_multi_relay.h (multi_relay usermod) diff --git a/usermods/Temperature/Temperature.cpp b/usermods/Temperature/Temperature.cpp index a17bd2d9..8c925eb1 100644 --- a/usermods/Temperature/Temperature.cpp +++ b/usermods/Temperature/Temperature.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" #include "OneWire.h" diff --git a/usermods/TetrisAI_v2/TetrisAI_v2.cpp b/usermods/TetrisAI_v2/TetrisAI_v2.cpp index 78cdfd22..b51250b2 100644 --- a/usermods/TetrisAI_v2/TetrisAI_v2.cpp +++ b/usermods/TetrisAI_v2/TetrisAI_v2.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" #include "FX.h" #include "fcn_declare.h" diff --git a/usermods/VL53L0X_gestures/VL53L0X_gestures.cpp b/usermods/VL53L0X_gestures/VL53L0X_gestures.cpp index 759c31c7..af3220b3 100644 --- a/usermods/VL53L0X_gestures/VL53L0X_gestures.cpp +++ b/usermods/VL53L0X_gestures/VL53L0X_gestures.cpp @@ -13,8 +13,6 @@ * lib_deps = ${env.lib_deps} * pololu/VL53L0X @ ^1.3.0 */ -#pragma once - #include "wled.h" #include diff --git a/usermods/boblight/boblight.cpp b/usermods/boblight/boblight.cpp index 2a52fc15..5980443d 100644 --- a/usermods/boblight/boblight.cpp +++ b/usermods/boblight/boblight.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" /* diff --git a/usermods/buzzer/buzzer.cpp b/usermods/buzzer/buzzer.cpp index e421a239..e5a071e6 100644 --- a/usermods/buzzer/buzzer.cpp +++ b/usermods/buzzer/buzzer.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" #include "Arduino.h" diff --git a/usermods/deep_sleep/deep_sleep.cpp b/usermods/deep_sleep/deep_sleep.cpp index 741b618f..f6f3604f 100644 --- a/usermods/deep_sleep/deep_sleep.cpp +++ b/usermods/deep_sleep/deep_sleep.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" #include "driver/rtc_io.h" diff --git a/usermods/mpu6050_imu/mpu6050_imu.cpp b/usermods/mpu6050_imu/mpu6050_imu.cpp index 2f8166cd..529d5dde 100644 --- a/usermods/mpu6050_imu/mpu6050_imu.cpp +++ b/usermods/mpu6050_imu/mpu6050_imu.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" /* This driver reads quaternion data from the MPU6060 and adds it to the JSON diff --git a/usermods/mqtt_switch_v2/mqtt_switch_v2.cpp b/usermods/mqtt_switch_v2/mqtt_switch_v2.cpp index 9c8dd5f0..36e2adaa 100644 --- a/usermods/mqtt_switch_v2/mqtt_switch_v2.cpp +++ b/usermods/mqtt_switch_v2/mqtt_switch_v2.cpp @@ -1,5 +1,3 @@ -#pragma once - #warning "This usermod is deprecated and no longer maintained. It will be removed in a future WLED release. Please use usermod multi_relay which has more features." #include "wled.h" diff --git a/usermods/multi_relay/multi_relay.cpp b/usermods/multi_relay/multi_relay.cpp index ea07e281..f8b1f566 100644 --- a/usermods/multi_relay/multi_relay.cpp +++ b/usermods/multi_relay/multi_relay.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" #define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) diff --git a/usermods/pixels_dice_tray/pixels_dice_tray.cpp b/usermods/pixels_dice_tray/pixels_dice_tray.cpp index 07fd3d59..73457c67 100644 --- a/usermods/pixels_dice_tray/pixels_dice_tray.cpp +++ b/usermods/pixels_dice_tray/pixels_dice_tray.cpp @@ -1,5 +1,3 @@ -#pragma once - #include // https://github.com/axlan/arduino-pixels-dice #include "wled.h" diff --git a/usermods/pov_display/pov_display.cpp b/usermods/pov_display/pov_display.cpp index c1bd143a..b2b91f7d 100644 --- a/usermods/pov_display/pov_display.cpp +++ b/usermods/pov_display/pov_display.cpp @@ -1,4 +1,3 @@ -#pragma once #include "wled.h" #include diff --git a/usermods/pwm_outputs/pwm_outputs.cpp b/usermods/pwm_outputs/pwm_outputs.cpp index 72a78475..d94f1d84 100644 --- a/usermods/pwm_outputs/pwm_outputs.cpp +++ b/usermods/pwm_outputs/pwm_outputs.cpp @@ -1,4 +1,3 @@ -#pragma once #include "wled.h" #ifndef ESP32 diff --git a/usermods/quinled-an-penta/quinled-an-penta.cpp b/usermods/quinled-an-penta/quinled-an-penta.cpp index 1fbfd807..a3b452bf 100644 --- a/usermods/quinled-an-penta/quinled-an-penta.cpp +++ b/usermods/quinled-an-penta/quinled-an-penta.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "U8g2lib.h" #include "SHT85.h" #include "Wire.h" diff --git a/usermods/rgb-rotary-encoder/rgb-rotary-encoder.cpp b/usermods/rgb-rotary-encoder/rgb-rotary-encoder.cpp index 5b4e7315..1514e230 100644 --- a/usermods/rgb-rotary-encoder/rgb-rotary-encoder.cpp +++ b/usermods/rgb-rotary-encoder/rgb-rotary-encoder.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "ESPRotary.h" #include #include "wled.h" diff --git a/usermods/sd_card/sd_card.cpp b/usermods/sd_card/sd_card.cpp index e33a643f..4e68b97a 100644 --- a/usermods/sd_card/sd_card.cpp +++ b/usermods/sd_card/sd_card.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" // SD connected via MMC / SPI diff --git a/usermods/sensors_to_mqtt/sensors_to_mqtt.cpp b/usermods/sensors_to_mqtt/sensors_to_mqtt.cpp index 02f8e8d2..c203d4ee 100644 --- a/usermods/sensors_to_mqtt/sensors_to_mqtt.cpp +++ b/usermods/sensors_to_mqtt/sensors_to_mqtt.cpp @@ -2,8 +2,6 @@ #error "This user mod requires MQTT to be enabled." #endif -#pragma once - #include "wled.h" #include #include diff --git a/usermods/seven_segment_display/seven_segment_display.cpp b/usermods/seven_segment_display/seven_segment_display.cpp index d3aa5737..de5719b2 100644 --- a/usermods/seven_segment_display/seven_segment_display.cpp +++ b/usermods/seven_segment_display/seven_segment_display.cpp @@ -2,8 +2,6 @@ #error "This user mod requires MQTT to be enabled." #endif -#pragma once - #include "wled.h" class SevenSegmentDisplay : public Usermod diff --git a/usermods/seven_segment_display_reloaded/seven_segment_display_reloaded.cpp b/usermods/seven_segment_display_reloaded/seven_segment_display_reloaded.cpp index 812065d8..418e53b2 100644 --- a/usermods/seven_segment_display_reloaded/seven_segment_display_reloaded.cpp +++ b/usermods/seven_segment_display_reloaded/seven_segment_display_reloaded.cpp @@ -2,8 +2,6 @@ #error "This user mod requires MQTT to be enabled." #endif -#pragma once - #include "wled.h" class UsermodSSDR : public Usermod { diff --git a/usermods/sht/sht.cpp b/usermods/sht/sht.cpp index 7641bbc2..b269433e 100644 --- a/usermods/sht/sht.cpp +++ b/usermods/sht/sht.cpp @@ -2,8 +2,6 @@ #error "This user mod requires MQTT to be enabled." #endif -#pragma once - #include "SHT85.h" #define USERMOD_SHT_TYPE_SHT30 0 diff --git a/usermods/smartnest/smartnest.cpp b/usermods/smartnest/smartnest.cpp index be7710ab..2ff13b36 100644 --- a/usermods/smartnest/smartnest.cpp +++ b/usermods/smartnest/smartnest.cpp @@ -2,8 +2,6 @@ #error "This user mod requires MQTT to be enabled." #endif -#pragma once - #include "wled.h" class Smartnest : public Usermod diff --git a/usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.cpp b/usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.cpp index 076e91f7..84c11afc 100644 --- a/usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.cpp +++ b/usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" //v2 usermod that allows to change brightness and color using a rotary encoder, diff --git a/usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp b/usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp index 2dae867d..1b97ea94 100644 --- a/usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp +++ b/usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" // v2 Usermod to automatically save settings diff --git a/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.cpp b/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.cpp index 851e378e..93c4110c 100644 --- a/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.cpp +++ b/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" #undef U8X8_NO_HW_I2C // borrowed from WLEDMM: we do want I2C hardware drivers - if possible #include // from https://github.com/olikraus/u8g2/ diff --git a/usermods/usermod_v2_klipper_percentage/usermod_v2_klipper_percentage.cpp b/usermods/usermod_v2_klipper_percentage/usermod_v2_klipper_percentage.cpp index 55132b84..71c5c45f 100644 --- a/usermods/usermod_v2_klipper_percentage/usermod_v2_klipper_percentage.cpp +++ b/usermods/usermod_v2_klipper_percentage/usermod_v2_klipper_percentage.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" class klipper_percentage : public Usermod diff --git a/usermods/usermod_v2_ping_pong_clock/usermod_v2_ping_pong_clock.cpp b/usermods/usermod_v2_ping_pong_clock/usermod_v2_ping_pong_clock.cpp index 8212947a..c6632b53 100644 --- a/usermods/usermod_v2_ping_pong_clock/usermod_v2_ping_pong_clock.cpp +++ b/usermods/usermod_v2_ping_pong_clock/usermod_v2_ping_pong_clock.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" class PingPongClockUsermod : public Usermod diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.cpp b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.cpp index ac2cc3c4..9d112984 100644 --- a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.cpp +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" // diff --git a/usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp b/usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp index 781dd7d8..78929238 100644 --- a/usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp +++ b/usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" /* diff --git a/usermods/wireguard/wireguard.cpp b/usermods/wireguard/wireguard.cpp index 77cc952f..f88bfeb3 100644 --- a/usermods/wireguard/wireguard.cpp +++ b/usermods/wireguard/wireguard.cpp @@ -1,5 +1,3 @@ -#pragma once - #include #include "wled.h" diff --git a/usermods/wizlights/wizlights.cpp b/usermods/wizlights/wizlights.cpp index 67c0effd..3ac756b1 100644 --- a/usermods/wizlights/wizlights.cpp +++ b/usermods/wizlights/wizlights.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" #include diff --git a/usermods/word-clock-matrix/word-clock-matrix.cpp b/usermods/word-clock-matrix/word-clock-matrix.cpp index 6643d293..cd8f78c3 100644 --- a/usermods/word-clock-matrix/word-clock-matrix.cpp +++ b/usermods/word-clock-matrix/word-clock-matrix.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "wled.h" /* From b9aeb19834aae58fc51f3bff873839a802c0f1ed Mon Sep 17 00:00:00 2001 From: Kilrah Date: Fri, 17 Jan 2025 08:01:17 +0100 Subject: [PATCH 232/463] RF433 json usermod (#4234) * RF433 remote usermod --------- Co-authored-by: Kilrah --- platformio_override.sample.ini | 11 ++ usermods/usermod_v2_RF433/readme.md | 18 ++ usermods/usermod_v2_RF433/remote433.json | 34 ++++ usermods/usermod_v2_RF433/usermod_v2_RF433.h | 183 +++++++++++++++++++ wled00/const.h | 1 + wled00/usermods_list.cpp | 9 +- 6 files changed, 255 insertions(+), 1 deletion(-) create mode 100644 usermods/usermod_v2_RF433/readme.md create mode 100644 usermods/usermod_v2_RF433/remote433.json create mode 100644 usermods/usermod_v2_RF433/usermod_v2_RF433.h diff --git a/platformio_override.sample.ini b/platformio_override.sample.ini index cb5b43e7..19b8c273 100644 --- a/platformio_override.sample.ini +++ b/platformio_override.sample.ini @@ -529,3 +529,14 @@ monitor_filters = esp32_exception_decoder lib_deps = ${esp32.lib_deps} TFT_eSPI @ 2.5.33 ;; this is the last version that compiles with the WLED default framework - newer versions require platform = espressif32 @ ^6.3.2 + +# ------------------------------------------------------------------------------ +# Usermod examples +# ------------------------------------------------------------------------------ + +# 433MHz RF remote example for esp32dev +[env:esp32dev_usermod_RF433] +extends = env:esp32dev +build_flags = ${env:esp32dev.build_flags} -D USERMOD_RF433 +lib_deps = ${env:esp32dev.lib_deps} + sui77/rc-switch @ 2.6.4 diff --git a/usermods/usermod_v2_RF433/readme.md b/usermods/usermod_v2_RF433/readme.md new file mode 100644 index 00000000..43919f11 --- /dev/null +++ b/usermods/usermod_v2_RF433/readme.md @@ -0,0 +1,18 @@ +# RF433 remote usermod + +Usermod for controlling WLED using a generic 433 / 315MHz remote and simple 3-pin receiver +See for compatibility details + +## Build + +- Create a `platformio_override.ini` file at the root of the wled source directory if not already present +- Copy the `433MHz RF remote example for esp32dev` section from `platformio_override.sample.ini` into it +- Duplicate/adjust for other boards + +## Usage + +- Connect receiver to a free pin +- Set pin in Config->Usermods +- Info pane will show the last received button code +- Upload the remote433.json sample file in this folder to the ESP with the file editor at [http://\[wled-ip\]/edit](http://ip/edit) +- Edit as necessary, the key is the button number retrieved from the info pane, and the "cmd" can be either an [HTTP API](https://kno.wled.ge/interfaces/http-api/) or a [JSON API](https://kno.wled.ge/interfaces/json-api/) command. \ No newline at end of file diff --git a/usermods/usermod_v2_RF433/remote433.json b/usermods/usermod_v2_RF433/remote433.json new file mode 100644 index 00000000..d5d930a8 --- /dev/null +++ b/usermods/usermod_v2_RF433/remote433.json @@ -0,0 +1,34 @@ +{ + "13985576": { + "cmnt": "Toggle Power using HTTP API", + "cmd": "T=2" + }, + "3670817": { + "cmnt": "Force Power ON using HTTP API", + "cmd": "T=1" + }, + "13985572": { + "cmnt": "Set brightness to 200 using JSON API", + "cmd": {"bri":200} + }, + "3670818": { + "cmnt": "Run Preset 1 using JSON API", + "cmd": {"ps":1} + }, + "13985570": { + "cmnt": "Increase brightness by 40 using HTTP API", + "cmd": "A=~40" + }, + "13985569": { + "cmnt": "Decrease brightness by 40 using HTTP API", + "cmd": "A=~-40" + }, + "7608836": { + "cmnt": "Start 1min timer using JSON API", + "cmd": {"nl":{"on":true,"dur":1,"mode":0}} + }, + "7608840": { + "cmnt": "Select random effect on all segments using JSON API", + "cmd": {"seg":{"fx":"r"}} + } +} \ No newline at end of file diff --git a/usermods/usermod_v2_RF433/usermod_v2_RF433.h b/usermods/usermod_v2_RF433/usermod_v2_RF433.h new file mode 100644 index 00000000..ebaf433f --- /dev/null +++ b/usermods/usermod_v2_RF433/usermod_v2_RF433.h @@ -0,0 +1,183 @@ +#pragma once + +#include "wled.h" +#include "Arduino.h" +#include + +#define RF433_BUSWAIT_TIMEOUT 24 + +class RF433Usermod : public Usermod +{ +private: + RCSwitch mySwitch = RCSwitch(); + unsigned long lastCommand = 0; + unsigned long lastTime = 0; + + bool modEnabled = true; + int8_t receivePin = -1; + + static const char _modName[]; + static const char _modEnabled[]; + static const char _receivePin[]; + + bool initDone = false; + +public: + + void setup() + { + mySwitch.disableReceive(); + if (modEnabled) + { + mySwitch.enableReceive(receivePin); + } + initDone = true; + } + + /* + * connected() is called every time the WiFi is (re)connected + * Use it to initialize network interfaces + */ + void connected() + { + } + + void loop() + { + if (!modEnabled || strip.isUpdating()) + return; + + if (mySwitch.available()) + { + unsigned long receivedCommand = mySwitch.getReceivedValue(); + mySwitch.resetAvailable(); + + // Discard duplicates, limit long press repeat + if (lastCommand == receivedCommand && millis() - lastTime < 800) + return; + + lastCommand = receivedCommand; + lastTime = millis(); + + DEBUG_PRINT(F("RF433 Receive: ")); + DEBUG_PRINTLN(receivedCommand); + + if(!remoteJson433(receivedCommand)) + DEBUG_PRINTLN(F("RF433: unknown button")); + } + } + + // Add last received button to info pane + void addToJsonInfo(JsonObject &root) + { + if (!initDone) + return; // prevent crash on boot applyPreset() + JsonObject user = root["u"]; + if (user.isNull()) + user = root.createNestedObject("u"); + + JsonArray switchArr = user.createNestedArray("RF433 Last Received"); // name + switchArr.add(lastCommand); + } + + void addToConfig(JsonObject &root) + { + JsonObject top = root.createNestedObject(FPSTR(_modName)); // usermodname + top[FPSTR(_modEnabled)] = modEnabled; + JsonArray pinArray = top.createNestedArray("pin"); + pinArray.add(receivePin); + + DEBUG_PRINTLN(F(" config saved.")); + } + + bool readFromConfig(JsonObject &root) + { + JsonObject top = root[FPSTR(_modName)]; + if (top.isNull()) + { + DEBUG_PRINT(FPSTR(_modName)); + DEBUG_PRINTLN(F(": No config found. (Using defaults.)")); + return false; + } + getJsonValue(top[FPSTR(_modEnabled)], modEnabled); + getJsonValue(top["pin"][0], receivePin); + + DEBUG_PRINTLN(F("config (re)loaded.")); + + // Redo init on update + if(initDone) + setup(); + + return true; + } + + /* + * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). + * This could be used in the future for the system to determine whether your usermod is installed. + */ + uint16_t getId() + { + return USERMOD_ID_RF433; + } + + // this function follows the same principle as decodeIRJson() / remoteJson() + bool remoteJson433(int button) + { + char objKey[14]; + bool parsed = false; + + if (!requestJSONBufferLock(22)) return false; + + sprintf_P(objKey, PSTR("\"%d\":"), button); + + unsigned long start = millis(); + while (strip.isUpdating() && millis()-start < RF433_BUSWAIT_TIMEOUT) yield(); // wait for strip to finish updating, accessing FS during sendout causes glitches + + // attempt to read command from remote.json + readObjectFromFile(PSTR("/remote433.json"), objKey, pDoc); + JsonObject fdo = pDoc->as(); + if (fdo.isNull()) { + // the received button does not exist + releaseJSONBufferLock(); + return parsed; + } + + String cmdStr = fdo["cmd"].as(); + JsonObject jsonCmdObj = fdo["cmd"]; //object + + if (jsonCmdObj.isNull()) // we could also use: fdo["cmd"].is() + { + // HTTP API command + String apireq = "win"; apireq += '&'; // reduce flash string usage + if (!cmdStr.startsWith(apireq)) cmdStr = apireq + cmdStr; // if no "win&" prefix + if (!irApplyToAllSelected && cmdStr.indexOf(F("SS="))<0) { + char tmp[10]; + sprintf_P(tmp, PSTR("&SS=%d"), strip.getMainSegmentId()); + cmdStr += tmp; + } + fdo.clear(); // clear JSON buffer (it is no longer needed) + handleSet(nullptr, cmdStr, false); // no stateUpdated() call here + stateUpdated(CALL_MODE_BUTTON); + parsed = true; + } else { + // command is JSON object + if (jsonCmdObj[F("psave")].isNull()) + deserializeState(jsonCmdObj, CALL_MODE_BUTTON_PRESET); + else { + uint8_t psave = jsonCmdObj[F("psave")].as(); + char pname[33]; + sprintf_P(pname, PSTR("IR Preset %d"), psave); + fdo.clear(); + if (psave > 0 && psave < 251) savePreset(psave, pname, fdo); + } + parsed = true; + } + releaseJSONBufferLock(); + return parsed; + } +}; + +const char RF433Usermod::_modName[] PROGMEM = "RF433 Remote"; +const char RF433Usermod::_modEnabled[] PROGMEM = "Enabled"; +const char RF433Usermod::_receivePin[] PROGMEM = "RX Pin"; + diff --git a/wled00/const.h b/wled00/const.h index bdd20beb..6a023fad 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -204,6 +204,7 @@ #define USERMOD_ID_POV_DISPLAY 53 //Usermod "usermod_pov_display.h" #define USERMOD_ID_PIXELS_DICE_TRAY 54 //Usermod "pixels_dice_tray.h" #define USERMOD_ID_DEEP_SLEEP 55 //Usermod "usermod_deep_sleep.h" +#define USERMOD_ID_RF433 56 //Usermod "usermod_v2_RF433.h" //Access point behavior #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp index 3430e337..15ded987 100644 --- a/wled00/usermods_list.cpp +++ b/wled00/usermods_list.cpp @@ -242,11 +242,14 @@ #include "../usermods/LD2410_v2/usermod_ld2410.h" #endif - #ifdef USERMOD_DEEP_SLEEP #include "../usermods/deep_sleep/usermod_deep_sleep.h" #endif +#ifdef USERMOD_RF433 + #include "../usermods/usermod_v2_RF433/usermod_v2_RF433.h" +#endif + void registerUsermods() { /* @@ -479,4 +482,8 @@ void registerUsermods() #ifdef USERMOD_DEEP_SLEEP UsermodManager::add(new DeepSleepUsermod()); #endif + + #ifdef USERMOD_RF433 + UsermodManager::add(new RF433Usermod()); + #endif } From c92dbb10ac79058c96d8bfd7863b83bc63249f78 Mon Sep 17 00:00:00 2001 From: Malachi Soord Date: Wed, 25 Dec 2024 21:31:47 +0100 Subject: [PATCH 233/463] Use proper devcontainers schema for vscode customisations --- .devcontainer/devcontainer.json | 43 +++++++++++++++++---------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 241acd79..58864182 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -24,29 +24,30 @@ // 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. - "settings": { - "terminal.integrated.shell.linux": "/bin/bash", - "python.pythonPath": "/usr/local/bin/python", - "python.linting.enabled": true, - "python.linting.pylintEnabled": true, - "python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8", - "python.formatting.blackPath": "/usr/local/py-utils/bin/black", - "python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf", - "python.linting.banditPath": "/usr/local/py-utils/bin/bandit", - "python.linting.flake8Path": "/usr/local/py-utils/bin/flake8", - "python.linting.mypyPath": "/usr/local/py-utils/bin/mypy", - "python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle", - "python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle", - "python.linting.pylintPath": "/usr/local/py-utils/bin/pylint" + "customizations": { + "vscode": { + "settings": { + "terminal.integrated.shell.linux": "/bin/bash", + "python.pythonPath": "/usr/local/bin/python", + "python.linting.enabled": true, + "python.linting.pylintEnabled": true, + "python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8", + "python.formatting.blackPath": "/usr/local/py-utils/bin/black", + "python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf", + "python.linting.banditPath": "/usr/local/py-utils/bin/bandit", + "python.linting.flake8Path": "/usr/local/py-utils/bin/flake8", + "python.linting.mypyPath": "/usr/local/py-utils/bin/mypy", + "python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle", + "python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle", + "python.linting.pylintPath": "/usr/local/py-utils/bin/pylint" + }, + "extensions": [ + "ms-python.python", + "platformio.platformio-ide" + ] + } }, - // Add the IDs of extensions you want installed when the container is created. - "extensions": [ - "ms-python.python", - "platformio.platformio-ide" - ], - // Use 'forwardPorts' to make a list of ports inside the container available locally. // "forwardPorts": [], From 703f84e5e1070a8006281e198ae354e3435d8e94 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 7 Jan 2025 15:09:29 +0100 Subject: [PATCH 234/463] code robustness improvements plus minor speedup * make XY() and _setPixelColorXY_raw() const (minor speedup) * segment is a struct not a class: friend class Segment --> friend struct Segment * fix missing braces around two macros * use non-throwing "new" where possible * improve robustness of transition code --- wled00/FX.h | 10 +++++----- wled00/FX_2Dfcn.cpp | 8 ++++---- wled00/FX_fcn.cpp | 12 ++++++------ wled00/json.cpp | 2 +- wled00/playlist.cpp | 2 +- wled00/presets.cpp | 4 ++-- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 57df5854..f80ffb36 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -79,9 +79,9 @@ extern byte realtimeMode; // used in getMappedPixelIndex() #define MAX_NUM_SEGMENTS 32 #endif #if defined(ARDUINO_ARCH_ESP32S2) - #define MAX_SEGMENT_DATA MAX_NUM_SEGMENTS*768 // 24k by default (S2 is short on free RAM) + #define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*768) // 24k by default (S2 is short on free RAM) #else - #define MAX_SEGMENT_DATA MAX_NUM_SEGMENTS*1280 // 40k by default + #define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*1280) // 40k by default #endif #endif @@ -460,7 +460,7 @@ typedef struct Segment { {} } *_t; - [[gnu::hot]] void _setPixelColorXY_raw(int& x, int& y, uint32_t& col); // set pixel without mapping (internal use only) + [[gnu::hot]] void _setPixelColorXY_raw(int& x, int& y, uint32_t& col) const; // set pixel without mapping (internal use only) public: @@ -642,7 +642,7 @@ typedef struct Segment { #endif } #ifndef WLED_DISABLE_2D - [[gnu::hot]] uint16_t XY(int x, int y); // support function to get relative index within segment + [[gnu::hot]] uint16_t XY(int x, int y) const; // support function to get relative index within segment [[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColorXY(int(x), int(y), c); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } @@ -936,7 +936,7 @@ class WS2812FX { // 96 bytes }; std::vector _segments; - friend class Segment; + friend struct Segment; private: volatile bool _suspend; diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index f00e7147..2e4cdd51 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -51,7 +51,7 @@ void WS2812FX::setUpMatrix() { customMappingSize = 0; // prevent use of mapping if anything goes wrong if (customMappingTable) delete[] customMappingTable; - customMappingTable = new uint16_t[getLengthTotal()]; + customMappingTable = new(std::nothrow) uint16_t[getLengthTotal()]; if (customMappingTable) { customMappingSize = getLengthTotal(); @@ -85,7 +85,7 @@ void WS2812FX::setUpMatrix() { JsonArray map = pDoc->as(); gapSize = map.size(); if (!map.isNull() && gapSize >= matrixSize) { // not an empty map - gapTable = new int8_t[gapSize]; + gapTable = new(std::nothrow) int8_t[gapSize]; if (gapTable) for (size_t i = 0; i < gapSize; i++) { gapTable[i] = constrain(map[i], -1, 1); } @@ -146,7 +146,7 @@ void WS2812FX::setUpMatrix() { #ifndef WLED_DISABLE_2D // XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element) -uint16_t IRAM_ATTR_YN Segment::XY(int x, int y) +uint16_t IRAM_ATTR_YN Segment::XY(int x, int y) const { const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) const int vH = vHeight(); // segment height in logical pixels (is always >= 1) @@ -154,7 +154,7 @@ uint16_t IRAM_ATTR_YN Segment::XY(int x, int y) } // raw setColor function without checks (checks are done in setPixelColorXY()) -void IRAM_ATTR_YN Segment::_setPixelColorXY_raw(int& x, int& y, uint32_t& col) +void IRAM_ATTR_YN Segment::_setPixelColorXY_raw(int& x, int& y, uint32_t& col) const { const int baseX = start + x; const int baseY = startY + y; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index b9a62bb2..90520d3d 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -94,7 +94,7 @@ Segment::Segment(const Segment &orig) { name = nullptr; data = nullptr; _dataLen = 0; - if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); } + if (orig.name) { name = new(std::nothrow) char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); } if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); } } @@ -122,7 +122,7 @@ Segment& Segment::operator= (const Segment &orig) { data = nullptr; _dataLen = 0; // copy source data - if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); } + if (orig.name) { name = new(std::nothrow) char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); } if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); } } return *this; @@ -253,7 +253,7 @@ void Segment::startTransition(uint16_t dur) { if (isInTransition()) return; // already in transition no need to store anything // starting a transition has to occur before change so we get current values 1st - _t = new Transition(dur); // no previous transition running + _t = new(std::nothrow) Transition(dur); // no previous transition running if (!_t) return; // failed to allocate data //DEBUG_PRINTF_P(PSTR("-- Started transition: %p (%p)\n"), this, _t); @@ -380,7 +380,7 @@ void Segment::restoreSegenv(tmpsegd_t &tmpSeg) { uint8_t Segment::currentBri(bool useCct) const { unsigned prog = progress(); - if (prog < 0xFFFFU) { + if (prog < 0xFFFFU && _t) { unsigned curBri = (useCct ? cct : (on ? opacity : 0)) * prog; curBri += (useCct ? _t->_cctT : _t->_briT) * (0xFFFFU - prog); return curBri / 0xFFFFU; @@ -391,7 +391,7 @@ uint8_t Segment::currentBri(bool useCct) const { uint8_t Segment::currentMode() const { #ifndef WLED_DISABLE_MODE_BLEND unsigned prog = progress(); - if (modeBlending && prog < 0xFFFFU) return _t->_modeT; + if (modeBlending && prog < 0xFFFFU && _t) return _t->_modeT; #endif return mode; } @@ -1809,7 +1809,7 @@ bool WS2812FX::deserializeMap(unsigned n) { } if (customMappingTable) delete[] customMappingTable; - customMappingTable = new uint16_t[getLengthTotal()]; + customMappingTable = new(std::nothrow) uint16_t[getLengthTotal()]; if (customMappingTable) { DEBUG_PRINT(F("Reading LED map from ")); DEBUG_PRINTLN(fileName); diff --git a/wled00/json.cpp b/wled00/json.cpp index cc25d5f8..f284a953 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -77,7 +77,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) if (name != nullptr) len = strlen(name); if (len > 0) { if (len > WLED_MAX_SEGNAME_LEN) len = WLED_MAX_SEGNAME_LEN; - seg.name = new char[len+1]; + seg.name = new(std::nothrow) char[len+1]; if (seg.name) strlcpy(seg.name, name, WLED_MAX_SEGNAME_LEN+1); } else { // but is empty (already deleted above) diff --git a/wled00/playlist.cpp b/wled00/playlist.cpp index 36235ab9..7f11e2bf 100644 --- a/wled00/playlist.cpp +++ b/wled00/playlist.cpp @@ -61,7 +61,7 @@ int16_t loadPlaylist(JsonObject playlistObj, byte presetId) { if (playlistLen == 0) return -1; if (playlistLen > 100) playlistLen = 100; - playlistEntries = new PlaylistEntry[playlistLen]; + playlistEntries = new(std::nothrow) PlaylistEntry[playlistLen]; if (playlistEntries == nullptr) return -1; byte it = 0; diff --git a/wled00/presets.cpp b/wled00/presets.cpp index 1abcb52b..4aaa121f 100644 --- a/wled00/presets.cpp +++ b/wled00/presets.cpp @@ -216,8 +216,8 @@ void handlePresets() //called from handleSet(PS=) [network callback (sObj is empty), IR (irrational), deserializeState, UDP] and deserializeState() [network callback (filedoc!=nullptr)] void savePreset(byte index, const char* pname, JsonObject sObj) { - if (!saveName) saveName = new char[33]; - if (!quickLoad) quickLoad = new char[9]; + if (!saveName) saveName = new(std::nothrow) char[33]; + if (!quickLoad) quickLoad = new(std::nothrow) char[9]; if (!saveName || !quickLoad) return; if (index == 0 || (index > 250 && index < 255)) return; From 7be868db12524835aa087ed27176a790a0ace93b Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 7 Jan 2025 20:18:42 +0100 Subject: [PATCH 235/463] bugfix: indexOf() returns -1 if string not found ... so we must use `int` instead of `unsigned` --- wled00/util.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wled00/util.cpp b/wled00/util.cpp index d9f1c00b..9a918a01 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -265,16 +265,16 @@ uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxL if (mode < strip.getModeCount()) { String lineBuffer = FPSTR(strip.getModeData(mode)); if (lineBuffer.length() > 0) { - unsigned start = lineBuffer.indexOf('@'); - unsigned stop = lineBuffer.indexOf(';', start); + int start = lineBuffer.indexOf('@'); // String::indexOf() returns an int, not an unsigned; -1 means "not found" + int stop = lineBuffer.indexOf(';', start); if (start>0 && stop>0) { String names = lineBuffer.substring(start, stop); // include @ - unsigned nameBegin = 1, nameEnd, nameDefault; + int nameBegin = 1, nameEnd, nameDefault; if (slider < 10) { for (size_t i=0; i<=slider; i++) { const char *tmpstr; dest[0] = '\0'; //clear dest buffer - if (nameBegin == 0) break; // there are no more names + if (nameBegin <= 0) break; // there are no more names nameEnd = names.indexOf(',', nameBegin); if (i == slider) { nameDefault = names.indexOf('=', nameBegin); // find default value From 90c2955a717cd6c0c216bb1ac3ffc31b8a9d0e42 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 7 Jan 2025 20:22:52 +0100 Subject: [PATCH 236/463] avoid using keywords for variables: module, final these are reserved names and future compilers may reject them. --- wled00/fcn_declare.h | 2 +- wled00/util.cpp | 10 +++++----- wled00/wled_server.cpp | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index a1e36291..e9e8df6a 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -479,7 +479,7 @@ size_t printSetFormIndex(Print& settingsScript, const char* key, int index); size_t printSetClassElementHTML(Print& settingsScript, const char* key, const int index, const char* val); void prepareHostname(char* hostname); bool isAsterisksOnly(const char* str, byte maxLen); -bool requestJSONBufferLock(uint8_t module=255); +bool requestJSONBufferLock(uint8_t moduleID=255); void releaseJSONBufferLock(); uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen); uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxLen, uint8_t *var = nullptr); diff --git a/wled00/util.cpp b/wled00/util.cpp index 9a918a01..e15247f9 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -151,7 +151,7 @@ bool isAsterisksOnly(const char* str, byte maxLen) //threading/network callback details: https://github.com/Aircoookie/WLED/pull/2336#discussion_r762276994 -bool requestJSONBufferLock(uint8_t module) +bool requestJSONBufferLock(uint8_t moduleID) { if (pDoc == nullptr) { DEBUG_PRINTLN(F("ERROR: JSON buffer not allocated!")); @@ -175,14 +175,14 @@ bool requestJSONBufferLock(uint8_t module) #endif // If the lock is still held - by us, or by another task if (jsonBufferLock) { - DEBUG_PRINTF_P(PSTR("ERROR: Locking JSON buffer (%d) failed! (still locked by %d)\n"), module, jsonBufferLock); + DEBUG_PRINTF_P(PSTR("ERROR: Locking JSON buffer (%d) failed! (still locked by %d)\n"), moduleID, jsonBufferLock); #ifdef ARDUINO_ARCH_ESP32 xSemaphoreGiveRecursive(jsonBufferLockMutex); #endif return false; } - jsonBufferLock = module ? module : 255; + jsonBufferLock = moduleID ? moduleID : 255; DEBUG_PRINTF_P(PSTR("JSON buffer locked. (%d)\n"), jsonBufferLock); pDoc->clear(); return true; @@ -470,7 +470,7 @@ um_data_t* simulateSound(uint8_t simulationId) for (int i = 0; i<16; i++) fftResult[i] = beatsin8_t(120 / (i+1), 0, 255); // fftResult[i] = (beatsin8_t(120, 0, 255) + (256/16 * i)) % 256; - volumeSmth = fftResult[8]; + volumeSmth = fftResult[8]; break; case UMS_WeWillRockYou: if (ms%2000 < 200) { @@ -507,7 +507,7 @@ um_data_t* simulateSound(uint8_t simulationId) case UMS_10_13: for (int i = 0; i<16; i++) fftResult[i] = inoise8(beatsin8_t(90 / (i+1), 0, 200)*15 + (ms>>10), ms>>3); - volumeSmth = fftResult[8]; + volumeSmth = fftResult[8]; break; case UMS_14_3: for (int i = 0; i<16; i++) diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index e8cbb41a..96f2a705 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -152,9 +152,9 @@ static String msgProcessor(const String& var) return String(); } -static void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) { +static void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool isFinal) { if (!correctPIN) { - if (final) request->send(401, FPSTR(CONTENT_TYPE_PLAIN), FPSTR(s_unlock_cfg)); + if (isFinal) request->send(401, FPSTR(CONTENT_TYPE_PLAIN), FPSTR(s_unlock_cfg)); return; } if (!index) { @@ -170,7 +170,7 @@ static void handleUpload(AsyncWebServerRequest *request, const String& filename, if (len) { request->_tempFile.write(data,len); } - if (final) { + if (isFinal) { request->_tempFile.close(); if (filename.indexOf(F("cfg.json")) >= 0) { // check for filename with or without slash doReboot = true; @@ -359,7 +359,7 @@ void initServer() server.on(F("/upload"), HTTP_POST, [](AsyncWebServerRequest *request) {}, [](AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, - size_t len, bool final) {handleUpload(request, filename, index, data, len, final);} + size_t len, bool isFinal) {handleUpload(request, filename, index, data, len, isFinal);} ); createEditHandler(correctPIN); @@ -389,7 +389,7 @@ void initServer() serveMessage(request, 200, F("Update successful!"), F("Rebooting..."), 131); doReboot = true; } - },[](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){ + },[](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool isFinal){ if (!correctPIN || otaLock) return; if(!index){ DEBUG_PRINTLN(F("OTA Update Start")); @@ -406,7 +406,7 @@ void initServer() Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000); } if(!Update.hasError()) Update.write(data, len); - if(final){ + if(isFinal){ if(Update.end(true)){ DEBUG_PRINTLN(F("Update Success")); } else { From 013684b5ca62052f79df27ab72974cf3425e6a89 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 7 Jan 2025 20:33:10 +0100 Subject: [PATCH 237/463] making some parameters `const`, plus minor improvements * changed some parameters to "pointer to const", so compiler can better optimize code size and performance - because data behind a const pointer will never be modified by the called function. * made setPixelColor `const` * fixed a few potentially uninitialized local vars (the may have random values if not initialized) * avoid shadowing "state" in handleSerial() * plus a few very minor improvements --- wled00/FX.cpp | 8 ++++---- wled00/FX.h | 14 +++++++------- wled00/FX_2Dfcn.cpp | 8 ++++---- wled00/FX_fcn.cpp | 6 +++--- wled00/bus_manager.cpp | 14 +++++++------- wled00/bus_manager.h | 12 ++++++------ wled00/colors.cpp | 6 +++--- wled00/fcn_declare.h | 16 ++++++++-------- wled00/file.cpp | 6 +++--- wled00/json.cpp | 2 +- wled00/ntp.cpp | 2 +- wled00/set.cpp | 6 +++--- wled00/udp.cpp | 4 ++-- wled00/wled_serial.cpp | 4 ++-- wled00/wled_server.cpp | 2 +- wled00/xml.cpp | 4 ++-- 16 files changed, 57 insertions(+), 57 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index dc39df81..4e7c832b 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2363,7 +2363,7 @@ static const char _data_FX_MODE_LAKE[] PROGMEM = "Lake@!;Fx;!"; // send a meteor from begining to to the end of the strip with a trail that randomly decays. // adapted from https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#LEDStripEffectMeteorRain uint16_t mode_meteor() { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); if (!SEGENV.allocateData(SEGLEN)) return mode_static(); //allocation failed const bool meteorSmooth = SEGMENT.check3; byte* trail = SEGENV.data; @@ -2531,7 +2531,7 @@ static uint16_t ripple_base(uint8_t blurAmount = 0) { uint16_t mode_ripple(void) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); if(SEGMENT.custom1 || SEGMENT.check2) // blur or overlay SEGMENT.fade_out(250); else @@ -2543,7 +2543,7 @@ static const char _data_FX_MODE_RIPPLE[] PROGMEM = "Ripple@!,Wave #,Blur,,,,Over uint16_t mode_ripple_rainbow(void) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); if (SEGENV.call ==0) { SEGENV.aux0 = hw_random8(); SEGENV.aux1 = hw_random8(); @@ -3984,7 +3984,7 @@ static const char _data_FX_MODE_HEARTBEAT[] PROGMEM = "Heartbeat@!,!;!,!;!;01;m1 // Modified for WLED, based on https://github.com/FastLED/FastLED/blob/master/examples/Pacifica/Pacifica.ino // // Add one layer of waves into the led array -static CRGB pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff) +static CRGB pacifica_one_layer(uint16_t i, const CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff) { unsigned ci = cistart; unsigned waveangle = ioff; diff --git a/wled00/FX.h b/wled00/FX.h index f80ffb36..7b06963b 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -460,7 +460,7 @@ typedef struct Segment { {} } *_t; - [[gnu::hot]] void _setPixelColorXY_raw(int& x, int& y, uint32_t& col) const; // set pixel without mapping (internal use only) + [[gnu::hot]] void _setPixelColorXY_raw(const int& x, const int& y, uint32_t& col) const; // set pixel without mapping (internal use only) public: @@ -588,7 +588,7 @@ typedef struct Segment { inline void handleTransition() { updateTransitionProgress(); 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 + void restoreSegenv(const tmpsegd_t &tmpSegD); // restores segment data from buffer, if buffer is not transition buffer, changed values are copied to transition buffer #endif [[gnu::hot]] void updateTransitionProgress(); // set current progression of transition inline uint16_t progress() const { return _transitionprogress; }; // transition progression between 0-65535 @@ -643,11 +643,11 @@ typedef struct Segment { } #ifndef WLED_DISABLE_2D [[gnu::hot]] uint16_t XY(int x, int y) const; // support function to get relative index within segment - [[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color - inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColorXY(int(x), int(y), c); } - inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } - inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } - inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColorXY(int(x), int(y), RGBW32(c.r,c.g,c.b,0)); } + [[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c) const; // set relative pixel within segment with color + inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) const { setPixelColorXY(int(x), int(y), c); } + inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) const { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } + inline void setPixelColorXY(int x, int y, CRGB c) const { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } + inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) const { setPixelColorXY(int(x), int(y), RGBW32(c.r,c.g,c.b,0)); } #ifdef WLED_USE_AA_PIXELS void setPixelColorXY(float x, float y, uint32_t c, bool aa = true); 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); } diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 2e4cdd51..a72cfde2 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -154,7 +154,7 @@ uint16_t IRAM_ATTR_YN Segment::XY(int x, int y) const } // raw setColor function without checks (checks are done in setPixelColorXY()) -void IRAM_ATTR_YN Segment::_setPixelColorXY_raw(int& x, int& y, uint32_t& col) const +void IRAM_ATTR_YN Segment::_setPixelColorXY_raw(const int& x, const int& y, uint32_t& col) const { const int baseX = start + x; const int baseY = startY + y; @@ -179,7 +179,7 @@ void IRAM_ATTR_YN Segment::_setPixelColorXY_raw(int& x, int& y, uint32_t& col) c } } -void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) +void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) const { if (!isActive()) return; // not active @@ -276,8 +276,8 @@ void Segment::blur2D(uint8_t blur_x, uint8_t blur_y, bool smear) { if (!isActive()) return; // not active const unsigned cols = vWidth(); const unsigned rows = vHeight(); - uint32_t lastnew; - uint32_t last; + uint32_t lastnew = BLACK; + uint32_t last = BLACK; if (blur_x) { const uint8_t keepx = smear ? 255 : 255 - blur_x; const uint8_t seepx = blur_x >> 1; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 90520d3d..0a2b88ac 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -347,7 +347,7 @@ void Segment::swapSegenv(tmpsegd_t &tmpSeg) { } } -void Segment::restoreSegenv(tmpsegd_t &tmpSeg) { +void Segment::restoreSegenv(const tmpsegd_t &tmpSeg) { //DEBUG_PRINTF_P(PSTR("-- Restoring temp seg: %p->(%p) [%d->%p]\n"), &tmpSeg, this, _dataLen, data); if (_t && &(_t->_segT) != &tmpSeg) { // update possibly changed variables to keep old effect running correctly @@ -1134,8 +1134,8 @@ void Segment::blur(uint8_t blur_amount, bool smear) { uint8_t seep = blur_amount >> 1; unsigned vlength = vLength(); uint32_t carryover = BLACK; - uint32_t lastnew; - uint32_t last; + uint32_t lastnew = BLACK; + uint32_t last = BLACK; uint32_t curnew = BLACK; for (unsigned i = 0; i < vlength; i++) { uint32_t cur = getPixelColor(i); diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 2c0ba41a..6e159a82 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -27,7 +27,7 @@ extern bool cctICused; uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb); //udp.cpp -uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, byte *buffer, uint8_t bri=255, bool isRGBW=false); +uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, const uint8_t* buffer, uint8_t bri=255, bool isRGBW=false); // enable additional debug output #if defined(WLED_DEBUG_HOST) @@ -121,7 +121,7 @@ uint8_t *Bus::allocateData(size_t size) { } -BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) +BusDigital::BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com) : Bus(bc.type, bc.start, bc.autoWhite, bc.count, bc.reversed, (bc.refreshReq || bc.type == TYPE_TM1814)) , _skip(bc.skipAmount) //sacrificial pixels , _colorOrder(bc.colorOrder) @@ -448,7 +448,7 @@ void BusDigital::cleanup() { #endif #endif -BusPwm::BusPwm(BusConfig &bc) +BusPwm::BusPwm(const BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed, bc.refreshReq) // hijack Off refresh flag to indicate usage of dithering { if (!isPWM(bc.type)) return; @@ -646,7 +646,7 @@ void BusPwm::deallocatePins() { } -BusOnOff::BusOnOff(BusConfig &bc) +BusOnOff::BusOnOff(const BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed) , _onoffdata(0) { @@ -699,7 +699,7 @@ std::vector BusOnOff::getLEDTypes() { }; } -BusNetwork::BusNetwork(BusConfig &bc) +BusNetwork::BusNetwork(const BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite, bc.count) , _broadcastLock(false) { @@ -778,7 +778,7 @@ void BusNetwork::cleanup() { //utility to get the approx. memory usage of a given BusConfig -uint32_t BusManager::memUsage(BusConfig &bc) { +uint32_t BusManager::memUsage(const BusConfig &bc) { if (Bus::isOnOff(bc.type) || Bus::isPWM(bc.type)) return OUTPUT_MAX_PINS; unsigned len = bc.count + bc.skipAmount; @@ -803,7 +803,7 @@ uint32_t BusManager::memUsage(unsigned maxChannels, unsigned maxCount, unsigned return (maxChannels * maxCount * minBuses * multiplier); } -int BusManager::add(BusConfig &bc) { +int BusManager::add(const BusConfig &bc) { if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1; if (Bus::isVirtual(bc.type)) { busses[numBusses] = new BusNetwork(bc); diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index d90a6615..9aed0130 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -198,7 +198,7 @@ class Bus { class BusDigital : public Bus { public: - BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com); + BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com); ~BusDigital() { cleanup(); } void show() override; @@ -250,7 +250,7 @@ class BusDigital : public Bus { class BusPwm : public Bus { public: - BusPwm(BusConfig &bc); + BusPwm(const BusConfig &bc); ~BusPwm() { cleanup(); } void setPixelColor(unsigned pix, uint32_t c) override; @@ -277,7 +277,7 @@ class BusPwm : public Bus { class BusOnOff : public Bus { public: - BusOnOff(BusConfig &bc); + BusOnOff(const BusConfig &bc); ~BusOnOff() { cleanup(); } void setPixelColor(unsigned pix, uint32_t c) override; @@ -296,7 +296,7 @@ class BusOnOff : public Bus { class BusNetwork : public Bus { public: - BusNetwork(BusConfig &bc); + BusNetwork(const BusConfig &bc); ~BusNetwork() { cleanup(); } bool canShow() const override { return !_broadcastLock; } // this should be a return value from UDP routine if it is still sending data out @@ -379,12 +379,12 @@ class BusManager { BusManager() {}; //utility to get the approx. memory usage of a given BusConfig - static uint32_t memUsage(BusConfig &bc); + static uint32_t memUsage(const BusConfig &bc); static uint32_t memUsage(unsigned channels, unsigned count, unsigned buses = 1); static uint16_t currentMilliamps() { return _milliAmpsUsed + MA_FOR_ESP; } static uint16_t ablMilliampsMax() { return _milliAmpsMax; } - static int add(BusConfig &bc); + static int add(const BusConfig &bc); static void useParallelOutput(); // workaround for inaccessible PolyBus //do not call this method from system context (network callback) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index e64cf675..f154a1ae 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -122,7 +122,7 @@ void setRandomColor(byte* rgb) * generates a random palette based on harmonic color theory * takes a base palette as the input, it will choose one color of the base palette and keep it */ -CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) +CRGBPalette16 generateHarmonicRandomPalette(const CRGBPalette16 &basepalette) { CHSV palettecolors[4]; // array of colors for the new palette uint8_t keepcolorposition = hw_random8(4); // color position of current random palette to keep @@ -391,7 +391,7 @@ void colorXYtoRGB(float x, float y, byte* rgb) //coordinates to rgb (https://www rgb[2] = byte(255.0f*b); } -void colorRGBtoXY(byte* rgb, float* xy) //rgb to coordinates (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy) +void colorRGBtoXY(const byte* rgb, float* xy) //rgb to coordinates (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy) { float X = rgb[0] * 0.664511f + rgb[1] * 0.154324f + rgb[2] * 0.162028f; float Y = rgb[0] * 0.283881f + rgb[1] * 0.668433f + rgb[2] * 0.047685f; @@ -402,7 +402,7 @@ void colorRGBtoXY(byte* rgb, float* xy) //rgb to coordinates (https://www.develo #endif // WLED_DISABLE_HUESYNC //RRGGBB / WWRRGGBB order for hex -void colorFromDecOrHexString(byte* rgb, char* in) +void colorFromDecOrHexString(byte* rgb, const char* in) { if (in[0] == 0) return; char first = in[0]; diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index e9e8df6a..48aad4d8 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -166,7 +166,7 @@ inline uint32_t color_blend16(uint32_t c1, uint32_t c2, uint16_t b) { return col [[gnu::hot]] uint32_t color_add(uint32_t, uint32_t, bool preserveCR = false); [[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); [[gnu::hot]] uint32_t ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND); -CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette); +CRGBPalette16 generateHarmonicRandomPalette(const CRGBPalette16 &basepalette); CRGBPalette16 generateRandomPalette(); inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); } void hsv2rgb(const CHSV32& hsv, uint32_t& rgb); @@ -177,7 +177,7 @@ void colorKtoRGB(uint16_t kelvin, byte* rgb); void colorCTtoRGB(uint16_t mired, byte* rgb); //white spectrum to rgb void colorXYtoRGB(float x, float y, byte* rgb); // only defined if huesync disabled TODO void colorRGBtoXY(byte* rgb, float* xy); // only defined if huesync disabled TODO -void colorFromDecOrHexString(byte* rgb, char* in); +void colorFromDecOrHexString(byte* rgb, const char* in); bool colorFromHexString(byte* rgb, const char* in); uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb); uint16_t approximateKelvinFromRGB(uint32_t rgb); @@ -200,14 +200,14 @@ void sendArtnetPollReply(ArtPollReply* reply, IPAddress ipAddress, uint16_t port //file.cpp bool handleFileRead(AsyncWebServerRequest*, String path); -bool writeObjectToFileUsingId(const char* file, uint16_t id, JsonDocument* content); -bool writeObjectToFile(const char* file, const char* key, JsonDocument* content); +bool writeObjectToFileUsingId(const char* file, uint16_t id, const JsonDocument* content); +bool writeObjectToFile(const char* file, const char* key, const JsonDocument* content); bool readObjectFromFileUsingId(const char* file, uint16_t id, JsonDocument* dest); bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest); void updateFSInfo(); void closeFile(); -inline bool writeObjectToFileUsingId(const String &file, uint16_t id, JsonDocument* content) { return writeObjectToFileUsingId(file.c_str(), id, content); }; -inline bool writeObjectToFile(const String &file, const char* key, JsonDocument* content) { return writeObjectToFile(file.c_str(), key, content); }; +inline bool writeObjectToFileUsingId(const String &file, uint16_t id, const JsonDocument* content) { return writeObjectToFileUsingId(file.c_str(), id, content); }; +inline bool writeObjectToFile(const String &file, const char* key, const JsonDocument* content) { return writeObjectToFile(file.c_str(), key, content); }; inline bool readObjectFromFileUsingId(const String &file, uint16_t id, JsonDocument* dest) { return readObjectFromFileUsingId(file.c_str(), id, dest); }; inline bool readObjectFromFile(const String &file, const char* key, JsonDocument* dest) { return readObjectFromFile(file.c_str(), key, dest); }; @@ -248,7 +248,7 @@ void handleIR(); bool deserializeSegment(JsonObject elem, byte it, byte presetId = 0); bool deserializeState(JsonObject root, byte callMode = CALL_MODE_DIRECT_CHANGE, byte presetId = 0); -void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true); +void serializeSegment(const JsonObject& root, const Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true); void serializeState(JsonObject root, bool forPreset = false, bool includeBri = true, bool segmentBounds = true, bool selectedSegmentsOnly = false); void serializeInfo(JsonObject root); void serializeModeNames(JsonArray root); @@ -333,7 +333,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply=tru //udp.cpp void notify(byte callMode, bool followUp=false); -uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, uint8_t *buffer, uint8_t bri=255, bool isRGBW=false); +uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, const uint8_t* buffer, uint8_t bri=255, bool isRGBW=false); void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC); void exitRealtime(); void handleNotifications(); diff --git a/wled00/file.cpp b/wled00/file.cpp index bc346720..c48a300b 100644 --- a/wled00/file.cpp +++ b/wled00/file.cpp @@ -176,7 +176,7 @@ static void writeSpace(size_t l) if (knownLargestSpace < l) knownLargestSpace = l; } -bool appendObjectToFile(const char* key, JsonDocument* content, uint32_t s, uint32_t contentLen = 0) +bool appendObjectToFile(const char* key, const JsonDocument* content, uint32_t s, uint32_t contentLen = 0) { #ifdef WLED_DEBUG_FS DEBUGFS_PRINTLN(F("Append")); @@ -255,14 +255,14 @@ bool appendObjectToFile(const char* key, JsonDocument* content, uint32_t s, uint return true; } -bool writeObjectToFileUsingId(const char* file, uint16_t id, JsonDocument* content) +bool writeObjectToFileUsingId(const char* file, uint16_t id, const JsonDocument* content) { char objKey[10]; sprintf(objKey, "\"%d\":", id); return writeObjectToFile(file, objKey, content); } -bool writeObjectToFile(const char* file, const char* key, JsonDocument* content) +bool writeObjectToFile(const char* file, const char* key, const JsonDocument* content) { uint32_t s = 0; //timing #ifdef WLED_DEBUG_FS diff --git a/wled00/json.cpp b/wled00/json.cpp index f284a953..ad0e96ed 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -493,7 +493,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) return stateResponse; } -void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset, bool segmentBounds) +void serializeSegment(const JsonObject& root, const Segment& seg, byte id, bool forPreset, bool segmentBounds) { root["id"] = id; if (segmentBounds) { diff --git a/wled00/ntp.cpp b/wled00/ntp.cpp index 8d44e634..12b698f4 100644 --- a/wled00/ntp.cpp +++ b/wled00/ntp.cpp @@ -224,7 +224,7 @@ void sendNTPPacket() ntpUdp.endPacket(); } -static bool isValidNtpResponse(byte * ntpPacket) { +static bool isValidNtpResponse(const byte* ntpPacket) { // Perform a few validity checks on the packet // based on https://github.com/taranais/NTPClient/blob/master/NTPClient.cpp if((ntpPacket[0] & 0b11000000) == 0b11000000) return false; //reject LI=UNSYNC diff --git a/wled00/set.cpp b/wled00/set.cpp index 08a0180a..a750072a 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -990,18 +990,18 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) //set color from HEX or 32bit DEC pos = req.indexOf(F("CL=")); if (pos > 0) { - colorFromDecOrHexString(colIn, (char*)req.substring(pos + 3).c_str()); + colorFromDecOrHexString(colIn, (const char*)req.substring(pos + 3).c_str()); col0Changed = true; } pos = req.indexOf(F("C2=")); if (pos > 0) { - colorFromDecOrHexString(colInSec, (char*)req.substring(pos + 3).c_str()); + colorFromDecOrHexString(colInSec, (const char*)req.substring(pos + 3).c_str()); col1Changed = true; } pos = req.indexOf(F("C3=")); if (pos > 0) { byte tmpCol[4]; - colorFromDecOrHexString(tmpCol, (char*)req.substring(pos + 3).c_str()); + colorFromDecOrHexString(tmpCol, (const char*)req.substring(pos + 3).c_str()); col2 = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]); selseg.setColor(2, col2); // defined above (SS= or main) col2Changed = true; diff --git a/wled00/udp.cpp b/wled00/udp.cpp index 8ba9a1a7..e76ef664 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -206,7 +206,7 @@ void notify(byte callMode, bool followUp) notificationCount = followUp ? notificationCount + 1 : 0; } -void parseNotifyPacket(uint8_t *udpIn) { +void parseNotifyPacket(const uint8_t *udpIn) { //ignore notification if received within a second after sending a notification ourselves if (millis() - notificationSentTime < 1000) return; if (udpIn[1] > 199) return; //do not receive custom versions @@ -810,7 +810,7 @@ static size_t sequenceNumber = 0; // this needs to be shared across all ou static const size_t ART_NET_HEADER_SIZE = 12; static const byte ART_NET_HEADER[] PROGMEM = {0x41,0x72,0x74,0x2d,0x4e,0x65,0x74,0x00,0x00,0x50,0x00,0x0e}; -uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, uint8_t *buffer, uint8_t bri, bool isRGBW) { +uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, const uint8_t* buffer, uint8_t bri, bool isRGBW) { if (!(apActive || interfacesInited) || !client[0] || !length) return 1; // network not initialised or dummy/unset IP address 031522 ajn added check for ap WiFiUDP ddpUdp; diff --git a/wled00/wled_serial.cpp b/wled00/wled_serial.cpp index ad9bb141..a0e59c53 100644 --- a/wled00/wled_serial.cpp +++ b/wled00/wled_serial.cpp @@ -113,8 +113,8 @@ void handleSerial() //only send response if TX pin is unused for other purposes if (verboseResponse && serialCanTX) { pDoc->clear(); - JsonObject state = pDoc->createNestedObject("state"); - serializeState(state); + JsonObject stateDoc = pDoc->createNestedObject("state"); + serializeState(stateDoc); JsonObject info = pDoc->createNestedObject("info"); serializeInfo(info); diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index 96f2a705..a17a7ec3 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -21,7 +21,7 @@ static const char s_accessdenied[] PROGMEM = "Access Denied"; static const char _common_js[] PROGMEM = "/common.js"; //Is this an IP? -static bool isIp(String str) { +static bool isIp(const String str) { for (size_t i = 0; i < str.length(); i++) { int c = str.charAt(i); if (c != '.' && (c < '0' || c > '9')) { diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 0ed32c04..957ccebd 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -26,7 +26,7 @@ void XML_response(Print& dest) ); } -static void extractPin(Print& settingsScript, JsonObject &obj, const char *key) { +static void extractPin(Print& settingsScript, const JsonObject &obj, const char *key) { if (obj[key].is()) { JsonArray pins = obj[key].as(); for (JsonVariant pv : pins) { @@ -38,7 +38,7 @@ static void extractPin(Print& settingsScript, JsonObject &obj, const char *key) } // print used pins by scanning JsonObject (1 level deep) -static void fillUMPins(Print& settingsScript, JsonObject &mods) +static void fillUMPins(Print& settingsScript, const JsonObject &mods) { for (JsonPair kv : mods) { // kv.key() is usermod name or subobject key From b6f74287d07a7a572318ec78ee90e48399b32081 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 9 Jan 2025 12:12:53 +0100 Subject: [PATCH 238/463] implement recommendations from reviewers * simplified transition bugfix * removed cast same type * isIp parameter changed to pass-by-reference, to avoid copy constructor --- wled00/FX.h | 2 +- wled00/FX_fcn.cpp | 6 +++--- wled00/set.cpp | 6 +++--- wled00/wled_server.cpp | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 7b06963b..fa9ebe1c 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -591,7 +591,7 @@ typedef struct Segment { void restoreSegenv(const tmpsegd_t &tmpSegD); // restores segment data from buffer, if buffer is not transition buffer, changed values are copied to transition buffer #endif [[gnu::hot]] void updateTransitionProgress(); // set current progression of transition - inline uint16_t progress() const { return _transitionprogress; }; // transition progression between 0-65535 + inline uint16_t progress() const { return _t ? Segment::_transitionprogress : 0xFFFFU; } // transition progression between 0-65535 [[gnu::hot]] uint8_t currentBri(bool useCct = false) const; // current segment brightness/CCT (blended while in transition) uint8_t currentMode() const; // currently active effect/mode (while in transition) [[gnu::hot]] uint32_t currentColor(uint8_t slot) const; // currently active segment color (blended while in transition) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 0a2b88ac..b2f3035e 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -380,7 +380,7 @@ void Segment::restoreSegenv(const tmpsegd_t &tmpSeg) { uint8_t Segment::currentBri(bool useCct) const { unsigned prog = progress(); - if (prog < 0xFFFFU && _t) { + if (prog < 0xFFFFU) { // progress() < 0xFFFF inplies that _t is a valid pointer unsigned curBri = (useCct ? cct : (on ? opacity : 0)) * prog; curBri += (useCct ? _t->_cctT : _t->_briT) * (0xFFFFU - prog); return curBri / 0xFFFFU; @@ -390,8 +390,8 @@ uint8_t Segment::currentBri(bool useCct) const { uint8_t Segment::currentMode() const { #ifndef WLED_DISABLE_MODE_BLEND - unsigned prog = progress(); - if (modeBlending && prog < 0xFFFFU && _t) return _t->_modeT; + unsigned prog = progress(); // progress() < 0xFFFF inplies that _t is a valid pointer + if (modeBlending && prog < 0xFFFFU) return _t->_modeT; #endif return mode; } diff --git a/wled00/set.cpp b/wled00/set.cpp index a750072a..7a88699c 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -990,18 +990,18 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) //set color from HEX or 32bit DEC pos = req.indexOf(F("CL=")); if (pos > 0) { - colorFromDecOrHexString(colIn, (const char*)req.substring(pos + 3).c_str()); + colorFromDecOrHexString(colIn, req.substring(pos + 3).c_str()); col0Changed = true; } pos = req.indexOf(F("C2=")); if (pos > 0) { - colorFromDecOrHexString(colInSec, (const char*)req.substring(pos + 3).c_str()); + colorFromDecOrHexString(colInSec, req.substring(pos + 3).c_str()); col1Changed = true; } pos = req.indexOf(F("C3=")); if (pos > 0) { byte tmpCol[4]; - colorFromDecOrHexString(tmpCol, (const char*)req.substring(pos + 3).c_str()); + colorFromDecOrHexString(tmpCol, req.substring(pos + 3).c_str()); col2 = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]); selseg.setColor(2, col2); // defined above (SS= or main) col2Changed = true; diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index a17a7ec3..8768b2b4 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -21,7 +21,7 @@ static const char s_accessdenied[] PROGMEM = "Access Denied"; static const char _common_js[] PROGMEM = "/common.js"; //Is this an IP? -static bool isIp(const String str) { +static bool isIp(const String &str) { for (size_t i = 0; i < str.length(); i++) { int c = str.charAt(i); if (c != '.' && (c < '0' || c > '9')) { From 872465df400e8304c7a20cdb58c43d87d0d9f96a Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 9 Jan 2025 12:21:56 +0100 Subject: [PATCH 239/463] typo in comments --- wled00/FX_fcn.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index b2f3035e..bd0ece16 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -380,7 +380,7 @@ void Segment::restoreSegenv(const tmpsegd_t &tmpSeg) { uint8_t Segment::currentBri(bool useCct) const { unsigned prog = progress(); - if (prog < 0xFFFFU) { // progress() < 0xFFFF inplies that _t is a valid pointer + if (prog < 0xFFFFU) { // progress() < 0xFFFF implies that _t is a valid pointer unsigned curBri = (useCct ? cct : (on ? opacity : 0)) * prog; curBri += (useCct ? _t->_cctT : _t->_briT) * (0xFFFFU - prog); return curBri / 0xFFFFU; @@ -390,8 +390,8 @@ uint8_t Segment::currentBri(bool useCct) const { uint8_t Segment::currentMode() const { #ifndef WLED_DISABLE_MODE_BLEND - unsigned prog = progress(); // progress() < 0xFFFF inplies that _t is a valid pointer - if (modeBlending && prog < 0xFFFFU) return _t->_modeT; + unsigned prog = progress(); + if (modeBlending && prog < 0xFFFFU) return _t->_modeT; // progress() < 0xFFFF implies that _t is a valid pointer #endif return mode; } From 01c463c8e8bd687a439222ffeafca9d1799914f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Thu, 9 Jan 2025 13:29:06 +0100 Subject: [PATCH 240/463] More tuning - replaced POD new/delete with malloc/free - some more SEGLEN <= 1 - some gnu::pure - more const attributes - some static attributes --- wled00/FX.cpp | 70 ++++++++++++++++++++++---------------------- wled00/FX.h | 51 ++++++++++++++++---------------- wled00/FX_2Dfcn.cpp | 14 ++++----- wled00/FX_fcn.cpp | 20 ++++++------- wled00/fcn_declare.h | 22 +++++++------- wled00/file.cpp | 2 +- wled00/json.cpp | 6 ++-- wled00/mqtt.cpp | 8 ++--- wled00/presets.cpp | 12 ++++---- wled00/set.cpp | 2 +- wled00/udp.cpp | 2 +- wled00/util.cpp | 8 ++--- 12 files changed, 109 insertions(+), 108 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 4e7c832b..9fc9dbff 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -197,7 +197,7 @@ static const char _data_FX_MODE_STROBE_RAINBOW[] PROGMEM = "Strobe Rainbow@!;,!; * if (bool rev == true) then LEDs are turned off in reverse order */ uint16_t color_wipe(bool rev, bool useRandomColors) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); uint32_t cycleTime = 750 + (255 - SEGMENT.speed)*150; uint32_t perc = strip.now % cycleTime; unsigned prog = (perc * 65535) / cycleTime; @@ -410,7 +410,7 @@ static const char _data_FX_MODE_FADE[] PROGMEM = "Fade@!;!,!;!;01"; * Scan mode parent function */ uint16_t scan(bool dual) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); uint32_t cycleTime = 750 + (255 - SEGMENT.speed)*150; uint32_t perc = strip.now % cycleTime; int prog = (perc * 65535) / cycleTime; @@ -1017,7 +1017,7 @@ static const char _data_FX_MODE_COLORFUL[] PROGMEM = "Colorful@!,Saturation;1,2, * Emulates a traffic light. */ uint16_t mode_traffic_light(void) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); for (unsigned i=0; i < SEGLEN; i++) SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); uint32_t mdelay = 500; @@ -1050,7 +1050,7 @@ static const char _data_FX_MODE_TRAFFIC_LIGHT[] PROGMEM = "Traffic Light@!,US st */ #define FLASH_COUNT 4 uint16_t mode_chase_flash(void) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); unsigned flash_step = SEGENV.call % ((FLASH_COUNT * 2) + 1); for (unsigned i = 0; i < SEGLEN; i++) { @@ -1080,7 +1080,7 @@ static const char _data_FX_MODE_CHASE_FLASH[] PROGMEM = "Chase Flash@!;Bg,Fx;!"; * Prim flashes running, followed by random color. */ uint16_t mode_chase_flash_random(void) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); unsigned flash_step = SEGENV.call % ((FLASH_COUNT * 2) + 1); for (int i = 0; i < SEGENV.aux1; i++) { @@ -1162,7 +1162,7 @@ static const char _data_FX_MODE_RUNNING_RANDOM[] PROGMEM = "Stream@!,Zone size;; * K.I.T.T. */ uint16_t mode_larson_scanner(void) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); const unsigned speed = FRAMETIME * map(SEGMENT.speed, 0, 255, 96, 2); // map into useful range const unsigned pixels = SEGLEN / speed; // how many pixels to advance per frame @@ -1220,7 +1220,7 @@ static const char _data_FX_MODE_DUAL_LARSON_SCANNER[] PROGMEM = "Scanner Dual@!, * Firing comets from one end. "Lighthouse" */ uint16_t mode_comet(void) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); unsigned counter = (strip.now * ((SEGMENT.speed >>2) +1)) & 0xFFFF; unsigned index = (counter * SEGLEN) >> 16; if (SEGENV.call == 0) SEGENV.aux0 = index; @@ -1248,7 +1248,7 @@ static const char _data_FX_MODE_COMET[] PROGMEM = "Lighthouse@!,Fade rate;!,!;!" * Fireworks function. */ uint16_t mode_fireworks() { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); const uint16_t width = SEGMENT.is2D() ? SEG_W : SEGLEN; const uint16_t height = SEG_H; @@ -1290,7 +1290,7 @@ static const char _data_FX_MODE_FIREWORKS[] PROGMEM = "Fireworks@,Frequency;!,!; //Twinkling LEDs running. Inspired by https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/Rain.h uint16_t mode_rain() { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); const unsigned width = SEG_W; const unsigned height = SEG_H; SEGENV.step += FRAMETIME; @@ -1356,7 +1356,7 @@ static const char _data_FX_MODE_FIRE_FLICKER[] PROGMEM = "Fire Flicker@!,!;!;!;0 * Gradient run base function */ uint16_t gradient_base(bool loading) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); uint16_t counter = strip.now * ((SEGMENT.speed >> 2) + 1); uint16_t pp = (counter * SEGLEN) >> 16; if (SEGENV.call == 0) pp = 0; @@ -1401,7 +1401,7 @@ static const char _data_FX_MODE_LOADING[] PROGMEM = "Loading@!,Fade;!,!;!;;ix=16 * Two dots running */ uint16_t mode_two_dots() { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); unsigned delay = 1 + (FRAMETIME<<3) / SEGLEN; // longer segments should change faster uint32_t it = strip.now / map(SEGMENT.speed, 0, 255, delay<<4, delay); unsigned offset = it % SEGLEN; @@ -1852,7 +1852,7 @@ static const char _data_FX_MODE_OSCILLATE[] PROGMEM = "Oscillate"; //TODO uint16_t mode_lightning(void) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); unsigned ledstart = hw_random16(SEGLEN); // Determine starting location of flash unsigned ledlen = 1 + hw_random16(SEGLEN -ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1) uint8_t bri = 255/hw_random8(1, 3); @@ -1938,7 +1938,7 @@ static const char _data_FX_MODE_PRIDE_2015[] PROGMEM = "Pride 2015@!;;"; //eight colored dots, weaving in and out of sync with each other uint16_t mode_juggle(void) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); SEGMENT.fadeToBlackBy(192 - (3*SEGMENT.intensity/4)); CRGB fastled_col; @@ -2083,7 +2083,7 @@ static const char _data_FX_MODE_PALETTE[] PROGMEM = "Palette@Shift,Size,Rotation // feel of your fire: COOLING (used in step 1 above) (Speed = COOLING), and SPARKING (used // in step 3 above) (Effect Intensity = Sparking). uint16_t mode_fire_2012() { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); const unsigned strips = SEGMENT.nrOfVStrips(); if (!SEGENV.allocateData(strips * SEGLEN)) return mode_static(); //allocation failed byte* heat = SEGENV.data; @@ -2430,7 +2430,7 @@ static const char _data_FX_MODE_METEOR[] PROGMEM = "Meteor@!,Trail,,,,Gradient,, //Railway Crossing / Christmas Fairy lights uint16_t mode_railway() { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); unsigned dur = (256 - SEGMENT.speed) * 40; uint16_t rampdur = (dur * SEGMENT.intensity) >> 8; if (SEGENV.step > dur) @@ -2721,7 +2721,7 @@ uint16_t mode_halloween_eyes() uint32_t blinkEndTime; }; - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); const unsigned maxWidth = strip.isMatrix ? SEG_W : SEGLEN; const unsigned HALLOWEEN_EYE_SPACE = MAX(2, strip.isMatrix ? SEG_W>>4: SEGLEN>>5); const unsigned HALLOWEEN_EYE_WIDTH = HALLOWEEN_EYE_SPACE/2; @@ -2906,7 +2906,7 @@ static const char _data_FX_MODE_TRI_STATIC_PATTERN[] PROGMEM = "Solid Pattern Tr static uint16_t spots_base(uint16_t threshold) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); unsigned maxZones = SEGLEN >> 2; @@ -2962,7 +2962,7 @@ typedef struct Ball { * Bouncing Balls Effect */ uint16_t mode_bouncing_balls(void) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); //allocate segment data const unsigned strips = SEGMENT.nrOfVStrips(); // adapt for 2D const size_t maxNumBalls = 16; @@ -3140,7 +3140,7 @@ static const char _data_FX_MODE_ROLLINGBALLS[] PROGMEM = "Rolling Balls@!,# of b * Sinelon stolen from FASTLED examples */ static uint16_t sinelon_base(bool dual, bool rainbow=false) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); SEGMENT.fade_out(SEGMENT.intensity); unsigned pos = beatsin16_t(SEGMENT.speed/10,0,SEGLEN-1); if (SEGENV.call == 0) SEGENV.aux0 = pos; @@ -3245,7 +3245,7 @@ typedef struct Spark { * modified from https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/Popcorn.h */ uint16_t mode_popcorn(void) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); //allocate segment data unsigned strips = SEGMENT.nrOfVStrips(); unsigned usablePopcorns = maxNumPopcorn; @@ -3420,7 +3420,7 @@ typedef struct particle { } star; uint16_t mode_starburst(void) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); unsigned maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640 unsigned segs = strip.getActiveSegmentsNum(); if (segs <= (strip.getMaxSegments() /2)) maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs @@ -3539,7 +3539,7 @@ static const char _data_FX_MODE_STARBURST[] PROGMEM = "Fireworks Starburst@Chanc */ uint16_t mode_exploding_fireworks(void) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); const int cols = SEGMENT.is2D() ? SEG_W : 1; const int rows = SEGMENT.is2D() ? SEG_H : SEGLEN; @@ -3677,7 +3677,7 @@ static const char _data_FX_MODE_EXPLODING_FIREWORKS[] PROGMEM = "Fireworks 1D@Gr */ uint16_t mode_drip(void) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); //allocate segment data unsigned strips = SEGMENT.nrOfVStrips(); const int maxNumDrops = 4; @@ -3773,7 +3773,7 @@ typedef struct Tetris { } tetris; uint16_t mode_tetrix(void) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); unsigned strips = SEGMENT.nrOfVStrips(); // allow running on virtual strips (columns in 2D segment) unsigned dataSize = sizeof(tetris); if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed @@ -4080,7 +4080,7 @@ static const char _data_FX_MODE_PACIFICA[] PROGMEM = "Pacifica@!,Angle;;!;;pal=5 * Mode simulates a gradual sunrise */ uint16_t mode_sunrise() { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); //speed 0 - static sun //speed 1 - 60: sunrise time in minutes //speed 60 - 120 : sunset time in minutes - 60; @@ -4287,7 +4287,7 @@ static const char _data_FX_MODE_FLOW[] PROGMEM = "Flow@!,Zones;;!;;m12=1"; //ver */ uint16_t mode_chunchun(void) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); SEGMENT.fade_out(254); // add a bit of trail unsigned counter = strip.now * (6 + (SEGMENT.speed >> 4)); unsigned numBirds = 2 + (SEGLEN >> 3); // 2 + 1/8 of a segment @@ -4338,7 +4338,7 @@ typedef struct Spotlight { */ uint16_t mode_dancing_shadows(void) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); unsigned numSpotlights = map(SEGMENT.intensity, 0, 255, 2, SPOT_MAX_COUNT); // 49 on 32 segment ESP32, 17 on 16 segment ESP8266 bool initialize = SEGENV.aux0 != numSpotlights; SEGENV.aux0 = numSpotlights; @@ -4800,7 +4800,7 @@ static const char _data_FX_MODE_AURORA[] PROGMEM = "Aurora@!,!;1,2,3;!;;sx=24,pa // 16 bit perlinmove. Use Perlin Noise instead of sinewaves for movement. By Andrew Tuline. // Controls are speed, # of pixels, faderate. uint16_t mode_perlinmove(void) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); SEGMENT.fade_out(255-SEGMENT.custom1); for (int i = 0; i < SEGMENT.intensity/16 + 1; i++) { unsigned locn = inoise16(strip.now*128/(260-SEGMENT.speed)+i*15000, strip.now*128/(260-SEGMENT.speed)); // Get a new pixel location from moving noise. @@ -4836,7 +4836,7 @@ static const char _data_FX_MODE_WAVESINS[] PROGMEM = "Wavesins@!,Brightness vari ////////////////////////////// // By: ldirko https://editor.soulmatelights.com/gallery/392-flow-led-stripe , modifed by: Andrew Tuline uint16_t mode_FlowStripe(void) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); const int hl = SEGLEN * 10 / 13; uint8_t hue = strip.now / (SEGMENT.speed+1); uint32_t t = strip.now / (SEGMENT.intensity/8+1); @@ -6598,7 +6598,7 @@ static const char _data_FX_MODE_MATRIPIX[] PROGMEM = "Matripix@!,Brightness;!,!; // * MIDNOISE // ////////////////////// uint16_t mode_midnoise(void) { // Midnoise. By Andrew Tuline. - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); // Changing xdist to SEGENV.aux0 and ydist to SEGENV.aux1. um_data_t *um_data = getAudioData(); @@ -6689,7 +6689,7 @@ static const char _data_FX_MODE_NOISEMETER[] PROGMEM = "Noisemeter@Fade rate,Wid // * PIXELWAVE // ////////////////////// uint16_t mode_pixelwave(void) { // Pixelwave. By Andrew Tuline. - if (SEGLEN == 1) return mode_static(); + 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 if (SEGENV.call == 0) { @@ -6757,7 +6757,7 @@ static const char _data_FX_MODE_PLASMOID[] PROGMEM = "Plasmoid@Phase,# of pixels ////////////////////// // Puddles/Puddlepeak By Andrew Tuline. Merged by @dedehai uint16_t mode_puddles_base(bool peakdetect) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); unsigned size = 0; uint8_t fadeVal = map(SEGMENT.speed, 0, 255, 224, 254); unsigned pos = hw_random16(SEGLEN); // Set a random starting position. @@ -6807,7 +6807,7 @@ static const char _data_FX_MODE_PUDDLES[] PROGMEM = "Puddles@Fade rate,Puddle si // * PIXELS // ////////////////////// uint16_t mode_pixels(void) { // Pixels. By Andrew Tuline. - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); if (!SEGENV.allocateData(32*sizeof(uint8_t))) return mode_static(); //allocation failed uint8_t *myVals = reinterpret_cast(SEGENV.data); // Used to store a pile of samples because WLED frame rate and WLED sample rate are not synchronized. Frame rate is too low. @@ -6835,7 +6835,7 @@ static const char _data_FX_MODE_PIXELS[] PROGMEM = "Pixels@Fade rate,# of pixels // ** Blurz // ////////////////////// uint16_t mode_blurz(void) { // Blurz. By Andrew Tuline. - if (SEGLEN == 1) return mode_static(); + 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 = getAudioData(); @@ -6899,7 +6899,7 @@ static const char _data_FX_MODE_DJLIGHT[] PROGMEM = "DJ Light@Speed;;;01f;m12=2, // ** Freqmap // //////////////////// uint16_t mode_freqmap(void) { // Map FFT_MajorPeak to SEGLEN. Would be better if a higher framerate. - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); // Start frequency = 60 Hz and log10(60) = 1.78 // End frequency = MAX_FREQUENCY in Hz and lo10(MAX_FREQUENCY) = MAX_FREQ_LOG10 diff --git a/wled00/FX.h b/wled00/FX.h index fa9ebe1c..289896d2 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -79,7 +79,7 @@ extern byte realtimeMode; // used in getMappedPixelIndex() #define MAX_NUM_SEGMENTS 32 #endif #if defined(ARDUINO_ARCH_ESP32S2) - #define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*768) // 24k by default (S2 is short on free RAM) + #define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*768) // 24k by default (S2 is short on free RAM) #else #define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*1280) // 40k by default #endif @@ -518,7 +518,7 @@ typedef struct Segment { //if (data) Serial.printf(" %d->(%p)", (int)_dataLen, data); //Serial.println(); #endif - if (name) { delete[] name; name = nullptr; } + if (name) { free(name); name = nullptr; } stopTransition(); deallocateData(); } @@ -534,7 +534,6 @@ typedef struct Segment { inline bool isSelected() const { return selected; } inline bool isInTransition() const { return _t != nullptr; } inline bool isActive() const { return stop > start; } - inline bool is2D() const { return (width()>1 && height()>1); } inline bool hasRGB() const { return _isRGB; } inline bool hasWhite() const { return _hasW; } inline bool isCCT() const { return _isCCT; } @@ -599,14 +598,14 @@ typedef struct Segment { // 1D strip [[gnu::hot]] uint16_t virtualLength() const; - [[gnu::hot]] void setPixelColor(int n, uint32_t c); // set relative pixel within segment with color - inline void setPixelColor(unsigned n, uint32_t c) { setPixelColor(int(n), c); } - inline void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } - inline void setPixelColor(int n, CRGB c) { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } + [[gnu::hot]] void setPixelColor(int n, uint32_t c) const; // set relative pixel within segment with color + inline void setPixelColor(unsigned n, uint32_t c) const { setPixelColor(int(n), c); } + inline void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) const { setPixelColor(n, RGBW32(r,g,b,w)); } + inline void setPixelColor(int n, CRGB c) const { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } #ifdef WLED_USE_AA_PIXELS - void setPixelColor(float i, uint32_t c, bool aa = true); - inline void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) { setPixelColor(i, RGBW32(r,g,b,w), aa); } - inline void setPixelColor(float i, CRGB c, bool aa = true) { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); } + void setPixelColor(float i, uint32_t c, bool aa = true) const; + inline void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) const { setPixelColor(i, RGBW32(r,g,b,w), aa); } + inline void setPixelColor(float i, CRGB c, bool aa = true) const { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); } #endif [[gnu::hot]] uint32_t getPixelColor(int i) const; // 1D support functions (some implement 2D as well) @@ -642,16 +641,17 @@ typedef struct Segment { #endif } #ifndef WLED_DISABLE_2D - [[gnu::hot]] uint16_t XY(int x, int y) const; // support function to get relative index within segment + inline bool is2D() const { return (width()>1 && height()>1); } + [[gnu::hot]] int XY(int x, int y) const; // support function to get relative index within segment [[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c) const; // set relative pixel within segment with color inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) const { setPixelColorXY(int(x), int(y), c); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) const { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } inline void setPixelColorXY(int x, int y, CRGB c) const { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) const { setPixelColorXY(int(x), int(y), RGBW32(c.r,c.g,c.b,0)); } #ifdef WLED_USE_AA_PIXELS - void setPixelColorXY(float x, float y, uint32_t c, bool aa = true); - 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); } + void setPixelColorXY(float x, float y, uint32_t c, bool aa = true) const; + inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) const { setPixelColorXY(x, y, RGBW32(r,g,b,w), aa); } + inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) const { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), aa); } #endif [[gnu::hot]] uint32_t getPixelColorXY(int x, int y) const; // 2D support functions @@ -678,7 +678,8 @@ typedef struct Segment { void wu_pixel(uint32_t x, uint32_t y, CRGB c); inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); } #else - inline uint16_t XY(int x, int y) { return x; } + inline constexpr bool is2D() const { return false; } + inline int XY(int x, int y) const { return x; } inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(x, c); } inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColor(int(x), c); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColor(x, RGBW32(r,g,b,w)); } @@ -778,7 +779,7 @@ class WS2812FX { // 96 bytes } ~WS2812FX() { - if (customMappingTable) delete[] customMappingTable; + if (customMappingTable) free(customMappingTable); _mode.clear(); _modeData.clear(); _segments.clear(); @@ -804,7 +805,7 @@ class WS2812FX { // 96 bytes resetSegments(), // marks all segments for reset makeAutoSegments(bool forceReset = false), // will create segments based on configured outputs fixInvalidSegments(), // fixes incorrect segment configuration - setPixelColor(unsigned n, uint32_t c), // paints absolute strip pixel with index n and color c + setPixelColor(unsigned n, uint32_t c) const, // paints absolute strip pixel with index n and color c show(), // initiates LED output setTargetFps(unsigned fps), setupEffectData(); // add default effects to the list; defined in FX.cpp @@ -812,9 +813,9 @@ class WS2812FX { // 96 bytes inline void resetTimebase() { timebase = 0UL - millis(); } inline void restartRuntime() { for (Segment &seg : _segments) { seg.markForReset().resetIfRequired(); } } inline void setTransitionMode(bool t) { for (Segment &seg : _segments) seg.startTransition(t ? _transitionDur : 0); } - inline void setPixelColor(unsigned n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } - inline void setPixelColor(unsigned n, CRGB c) { setPixelColor(n, c.red, c.green, c.blue); } - inline void fill(uint32_t c) { for (unsigned i = 0; i < getLengthTotal(); i++) setPixelColor(i, c); } // fill whole strip with color (inline) + inline void setPixelColor(unsigned n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) const { setPixelColor(n, RGBW32(r,g,b,w)); } + inline void setPixelColor(unsigned n, CRGB c) const { setPixelColor(n, c.red, c.green, c.blue); } + inline void fill(uint32_t c) const { for (unsigned i = 0; i < getLengthTotal(); i++) setPixelColor(i, c); } // fill whole strip with color (inline) inline void trigger() { _triggered = true; } // Forces the next frame to be computed on all active segments. inline void setShowCallback(show_callback cb) { _callback = cb; } inline void setTransition(uint16_t t) { _transitionDur = t; } // sets transition time (in ms) @@ -824,7 +825,7 @@ class WS2812FX { // 96 bytes bool paletteFade, - checkSegmentAlignment(), + checkSegmentAlignment() const, hasRGBWBus() const, hasCCTBus() const, deserializeMap(unsigned n = 0); @@ -918,11 +919,11 @@ class WS2812FX { // 96 bytes void setUpMatrix(); // sets up automatic matrix ledmap from panel configuration // outsmart the compiler :) by correctly overloading - inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor((unsigned)(y * Segment::maxWidth + x), c); } - inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } - inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } + inline void setPixelColorXY(int x, int y, uint32_t c) const { setPixelColor((unsigned)(y * Segment::maxWidth + x), c); } + inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) const { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } + inline void setPixelColorXY(int x, int y, CRGB c) const { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } - inline uint32_t getPixelColorXY(int x, int y) const { 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 a72cfde2..ffaf53bb 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -50,8 +50,8 @@ void WS2812FX::setUpMatrix() { customMappingSize = 0; // prevent use of mapping if anything goes wrong - if (customMappingTable) delete[] customMappingTable; - customMappingTable = new(std::nothrow) uint16_t[getLengthTotal()]; + if (customMappingTable) free(customMappingTable); + customMappingTable = static_cast(malloc(sizeof(uint16_t)*getLengthTotal())); if (customMappingTable) { customMappingSize = getLengthTotal(); @@ -68,7 +68,7 @@ void WS2812FX::setUpMatrix() { // content of the file is just raw JSON array in the form of [val1,val2,val3,...] // there are no other "key":"value" pairs in it // allowed values are: -1 (missing pixel/no LED attached), 0 (inactive/unused pixel), 1 (active/used pixel) - char fileName[32]; strcpy_P(fileName, PSTR("/2d-gaps.json")); // reduce flash footprint + char fileName[32]; strcpy_P(fileName, PSTR("/2d-gaps.json")); bool isFile = WLED_FS.exists(fileName); size_t gapSize = 0; int8_t *gapTable = nullptr; @@ -85,7 +85,7 @@ void WS2812FX::setUpMatrix() { JsonArray map = pDoc->as(); gapSize = map.size(); if (!map.isNull() && gapSize >= matrixSize) { // not an empty map - gapTable = new(std::nothrow) int8_t[gapSize]; + gapTable = static_cast(malloc(gapSize)); if (gapTable) for (size_t i = 0; i < gapSize; i++) { gapTable[i] = constrain(map[i], -1, 1); } @@ -113,7 +113,7 @@ void WS2812FX::setUpMatrix() { } // delete gap array as we no longer need it - if (gapTable) delete[] gapTable; + if (gapTable) free(gapTable); #ifdef WLED_DEBUG DEBUG_PRINT(F("Matrix ledmap:")); @@ -146,7 +146,7 @@ void WS2812FX::setUpMatrix() { #ifndef WLED_DISABLE_2D // XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element) -uint16_t IRAM_ATTR_YN Segment::XY(int x, int y) const +int IRAM_ATTR_YN Segment::XY(int x, int y) const { const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) const int vH = vHeight(); // segment height in logical pixels (is always >= 1) @@ -215,7 +215,7 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) const #ifdef WLED_USE_AA_PIXELS // anti-aliased version of setPixelColorXY() -void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa) +void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa) const { if (!isActive()) return; // not active if (x<0.0f || x>1.0f || y<0.0f || y>1.0f) return; // not normalized diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index bd0ece16..433c828a 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -94,7 +94,7 @@ Segment::Segment(const Segment &orig) { name = nullptr; data = nullptr; _dataLen = 0; - if (orig.name) { name = new(std::nothrow) char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); } + if (orig.name) { name = static_cast(malloc(strlen(orig.name)+1)); if (name) strcpy(name, orig.name); } if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); } } @@ -113,7 +113,7 @@ Segment& Segment::operator= (const Segment &orig) { //DEBUG_PRINTF_P(PSTR("-- Copying segment: %p -> %p\n"), &orig, this); if (this != &orig) { // clean destination - if (name) { delete[] name; name = nullptr; } + if (name) { free(name); name = nullptr; } stopTransition(); deallocateData(); // copy source @@ -122,7 +122,7 @@ Segment& Segment::operator= (const Segment &orig) { data = nullptr; _dataLen = 0; // copy source data - if (orig.name) { name = new(std::nothrow) char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); } + if (orig.name) { name = static_cast(malloc(strlen(orig.name)+1)); if (name) strcpy(name, orig.name); } if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); } } return *this; @@ -132,7 +132,7 @@ Segment& Segment::operator= (const Segment &orig) { Segment& Segment::operator= (Segment &&orig) noexcept { //DEBUG_PRINTF_P(PSTR("-- Moving segment: %p -> %p\n"), &orig, this); if (this != &orig) { - if (name) { delete[] name; name = nullptr; } // free old name + if (name) { free(name); name = nullptr; } // free old name stopTransition(); deallocateData(); // free old runtime data memcpy((void*)this, (void*)&orig, sizeof(Segment)); @@ -869,7 +869,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) #ifdef WLED_USE_AA_PIXELS // anti-aliased normalized version of setPixelColor() -void Segment::setPixelColor(float i, uint32_t col, bool aa) +void Segment::setPixelColor(float i, uint32_t col, bool aa) const { if (!isActive()) return; // not active int vStrip = int(i/10.0f); // hack to allow running on virtual strips (2D segment columns/rows) @@ -1413,7 +1413,7 @@ void WS2812FX::service() { #endif } -void IRAM_ATTR WS2812FX::setPixelColor(unsigned i, uint32_t col) { +void IRAM_ATTR WS2812FX::setPixelColor(unsigned i, uint32_t col) const { i = getMappedPixelIndex(i); if (i >= _length) return; BusManager::setPixelColor(i, col); @@ -1694,9 +1694,9 @@ void WS2812FX::fixInvalidSegments() { //true if all segments align with a bus, or if a segment covers the total length //irrelevant in 2D set-up -bool WS2812FX::checkSegmentAlignment() { +bool WS2812FX::checkSegmentAlignment() const { bool aligned = false; - for (segment &seg : _segments) { + for (const segment &seg : _segments) { for (unsigned b = 0; bgetStart() && seg.stop == bus->getStart() + bus->getLength()) aligned = true; @@ -1808,8 +1808,8 @@ bool WS2812FX::deserializeMap(unsigned n) { Segment::maxHeight = min(max(root[F("height")].as(), 1), 128); } - if (customMappingTable) delete[] customMappingTable; - customMappingTable = new(std::nothrow) uint16_t[getLengthTotal()]; + if (customMappingTable) free(customMappingTable); + customMappingTable = static_cast(malloc(sizeof(uint16_t)*getLengthTotal())); if (customMappingTable) { DEBUG_PRINT(F("Reading LED map from ")); DEBUG_PRINTLN(fileName); diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 48aad4d8..d30230f2 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -161,11 +161,11 @@ class NeoGammaWLEDMethod { }; #define gamma32(c) NeoGammaWLEDMethod::Correct32(c) #define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c) -[[gnu::hot]] uint32_t color_blend(uint32_t c1, uint32_t c2 , uint8_t blend); +[[gnu::hot, gnu::pure]] uint32_t color_blend(uint32_t c1, uint32_t c2 , uint8_t blend); inline uint32_t color_blend16(uint32_t c1, uint32_t c2, uint16_t b) { return color_blend(c1, c2, b >> 8); }; -[[gnu::hot]] uint32_t color_add(uint32_t, uint32_t, bool preserveCR = false); -[[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); -[[gnu::hot]] uint32_t ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND); +[[gnu::hot, gnu::pure]] uint32_t color_add(uint32_t, uint32_t, bool preserveCR = false); +[[gnu::hot, gnu::pure]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); +[[gnu::hot, gnu::pure]] uint32_t ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND); CRGBPalette16 generateHarmonicRandomPalette(const CRGBPalette16 &basepalette); CRGBPalette16 generateRandomPalette(); inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); } @@ -176,7 +176,7 @@ inline CHSV rgb2hsv(const CRGB c) { CHSV32 hsv; rgb2hsv((uint32_t((byte(c.r) << void colorKtoRGB(uint16_t kelvin, byte* rgb); void colorCTtoRGB(uint16_t mired, byte* rgb); //white spectrum to rgb void colorXYtoRGB(float x, float y, byte* rgb); // only defined if huesync disabled TODO -void colorRGBtoXY(byte* rgb, float* xy); // only defined if huesync disabled TODO +void colorRGBtoXY(const byte* rgb, float* xy); // only defined if huesync disabled TODO void colorFromDecOrHexString(byte* rgb, const char* in); bool colorFromHexString(byte* rgb, const char* in); uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb); @@ -467,10 +467,10 @@ void userLoop(); #include "soc/wdev_reg.h" #define HW_RND_REGISTER REG_READ(WDEV_RND_REG) #endif -int getNumVal(const String* req, uint16_t pos); +[[gnu::pure]] int getNumVal(const String* req, uint16_t pos); void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255); -bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255); // getVal supports inc/decrementing and random ("X~Y(r|~[w][-][Z])" form) -bool getBoolVal(JsonVariant elem, bool dflt); +bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255); // getVal supports inc/decrementing and random ("X~Y(r|[w]~[-][Z])" form) +[[gnu::pure]] bool getBoolVal(const JsonVariant &elem, bool dflt); bool updateVal(const char* req, const char* key, byte* val, byte minv=0, byte maxv=255); size_t printSetFormCheckbox(Print& settingsScript, const char* key, int val); size_t printSetFormValue(Print& settingsScript, const char* key, int val); @@ -478,7 +478,7 @@ size_t printSetFormValue(Print& settingsScript, const char* key, const char* val size_t printSetFormIndex(Print& settingsScript, const char* key, int index); size_t printSetClassElementHTML(Print& settingsScript, const char* key, const int index, const char* val); void prepareHostname(char* hostname); -bool isAsterisksOnly(const char* str, byte maxLen); +[[gnu::pure]] bool isAsterisksOnly(const char* str, byte maxLen); bool requestJSONBufferLock(uint8_t moduleID=255); void releaseJSONBufferLock(); uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen); @@ -491,8 +491,8 @@ uint16_t beatsin16_t(accum88 beats_per_minute, uint16_t lowest = 0, uint16_t hig uint8_t beatsin8_t(accum88 beats_per_minute, uint8_t lowest = 0, uint8_t highest = 255, uint32_t timebase = 0, uint8_t phase_offset = 0); um_data_t* simulateSound(uint8_t simulationId); void enumerateLedmaps(); -uint8_t get_random_wheel_index(uint8_t pos); -float mapf(float x, float in_min, float in_max, float out_min, float out_max); +[[gnu::hot]] uint8_t get_random_wheel_index(uint8_t pos); +[[gnu::hot, gnu::pure]] float mapf(float x, float in_min, float in_max, float out_min, float out_max); // fast (true) random numbers using hardware RNG, all functions return values in the range lowerlimit to upperlimit-1 // note: for true random numbers with high entropy, do not call faster than every 200ns (5MHz) diff --git a/wled00/file.cpp b/wled00/file.cpp index c48a300b..46df8d38 100644 --- a/wled00/file.cpp +++ b/wled00/file.cpp @@ -176,7 +176,7 @@ static void writeSpace(size_t l) if (knownLargestSpace < l) knownLargestSpace = l; } -bool appendObjectToFile(const char* key, const JsonDocument* content, uint32_t s, uint32_t contentLen = 0) +static bool appendObjectToFile(const char* key, const JsonDocument* content, uint32_t s, uint32_t contentLen = 0) { #ifdef WLED_DEBUG_FS DEBUGFS_PRINTLN(F("Append")); diff --git a/wled00/json.cpp b/wled00/json.cpp index ad0e96ed..c63da085 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -68,7 +68,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) if (elem["n"]) { // name field exists if (seg.name) { //clear old name - delete[] seg.name; + free(seg.name); seg.name = nullptr; } @@ -77,7 +77,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) if (name != nullptr) len = strlen(name); if (len > 0) { if (len > WLED_MAX_SEGNAME_LEN) len = WLED_MAX_SEGNAME_LEN; - seg.name = new(std::nothrow) char[len+1]; + seg.name = static_cast(malloc(len+1)); if (seg.name) strlcpy(seg.name, name, WLED_MAX_SEGNAME_LEN+1); } else { // but is empty (already deleted above) @@ -86,7 +86,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) } else if (start != seg.start || stop != seg.stop) { // clearing or setting segment without name field if (seg.name) { - delete[] seg.name; + free(seg.name); seg.name = nullptr; } } diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp index 38afeffe..8cbe7909 100644 --- a/wled00/mqtt.cpp +++ b/wled00/mqtt.cpp @@ -68,8 +68,8 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp } if (index == 0) { // start (1st partial packet or the only packet) - if (payloadStr) delete[] payloadStr; // fail-safe: release buffer - payloadStr = new char[total+1]; // allocate new buffer + if (payloadStr) free(payloadStr); // fail-safe: release buffer + payloadStr = static_cast(malloc(total+1)); // allocate new buffer } if (payloadStr == nullptr) return; // buffer not allocated @@ -94,7 +94,7 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp } else { // Non-Wled Topic used here. Probably a usermod subscribed to this topic. UsermodManager::onMqttMessage(topic, payloadStr); - delete[] payloadStr; + free(payloadStr); payloadStr = nullptr; return; } @@ -124,7 +124,7 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp // topmost topic (just wled/MAC) parseMQTTBriPayload(payloadStr); } - delete[] payloadStr; + free(payloadStr); payloadStr = nullptr; } diff --git a/wled00/presets.cpp b/wled00/presets.cpp index 4aaa121f..15eed3e4 100644 --- a/wled00/presets.cpp +++ b/wled00/presets.cpp @@ -76,8 +76,8 @@ static void doSaveState() { // clean up saveLedmap = -1; presetToSave = 0; - delete[] saveName; - delete[] quickLoad; + free(saveName); + free(quickLoad); saveName = nullptr; quickLoad = nullptr; playlistSave = false; @@ -216,8 +216,8 @@ void handlePresets() //called from handleSet(PS=) [network callback (sObj is empty), IR (irrational), deserializeState, UDP] and deserializeState() [network callback (filedoc!=nullptr)] void savePreset(byte index, const char* pname, JsonObject sObj) { - if (!saveName) saveName = new(std::nothrow) char[33]; - if (!quickLoad) quickLoad = new(std::nothrow) char[9]; + if (!saveName) saveName = static_cast(malloc(33)); + if (!quickLoad) quickLoad = static_cast(malloc(9)); if (!saveName || !quickLoad) return; if (index == 0 || (index > 250 && index < 255)) return; @@ -263,8 +263,8 @@ void savePreset(byte index, const char* pname, JsonObject sObj) presetsModifiedTime = toki.second(); //unix time updateFSInfo(); } - delete[] saveName; - delete[] quickLoad; + free(saveName); + free(quickLoad); saveName = nullptr; quickLoad = nullptr; } else { diff --git a/wled00/set.cpp b/wled00/set.cpp index 7a88699c..27ac6b80 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -209,7 +209,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) // actual finalization is done in WLED::loop() (removing old busses and adding new) // this may happen even before this loop is finished so we do "doInitBusses" after the loop if (busConfigs[s] != nullptr) delete busConfigs[s]; - busConfigs[s] = new BusConfig(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freq, useGlobalLedBuffer, maPerLed, maMax); + busConfigs[s] = new(std::nothrow) BusConfig(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freq, useGlobalLedBuffer, maPerLed, maMax); busesChanged = true; } //doInitBusses = busesChanged; // we will do that below to ensure all input data is processed diff --git a/wled00/udp.cpp b/wled00/udp.cpp index e76ef664..b7be591e 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -206,7 +206,7 @@ void notify(byte callMode, bool followUp) notificationCount = followUp ? notificationCount + 1 : 0; } -void parseNotifyPacket(const uint8_t *udpIn) { +static void parseNotifyPacket(const uint8_t *udpIn) { //ignore notification if received within a second after sending a notification ourselves if (millis() - notificationSentTime < 1000) return; if (udpIn[1] > 199) return; //do not receive custom versions diff --git a/wled00/util.cpp b/wled00/util.cpp index e15247f9..ed38ae18 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -73,7 +73,7 @@ bool getVal(JsonVariant elem, byte* val, byte vmin, byte vmax) { } -bool getBoolVal(JsonVariant elem, bool dflt) { +bool getBoolVal(const JsonVariant &elem, bool dflt) { if (elem.is() && elem.as()[0] == 't') { return !dflt; } else { @@ -538,7 +538,7 @@ void enumerateLedmaps() { #ifndef ESP8266 if (ledmapNames[i-1]) { //clear old name - delete[] ledmapNames[i-1]; + free(ledmapNames[i-1]); ledmapNames[i-1] = nullptr; } #endif @@ -556,7 +556,7 @@ void enumerateLedmaps() { const char *name = root["n"].as(); if (name != nullptr) len = strlen(name); if (len > 0 && len < 33) { - ledmapNames[i-1] = new char[len+1]; + ledmapNames[i-1] = static_cast(malloc(len+1)); if (ledmapNames[i-1]) strlcpy(ledmapNames[i-1], name, 33); } } @@ -564,7 +564,7 @@ void enumerateLedmaps() { char tmp[33]; snprintf_P(tmp, 32, s_ledmap_tmpl, i); len = strlen(tmp); - ledmapNames[i-1] = new char[len+1]; + ledmapNames[i-1] = static_cast(malloc(len+1)); if (ledmapNames[i-1]) strlcpy(ledmapNames[i-1], tmp, 33); } } From ed3ec66d33e9579f670f1539ade4501a982afaf3 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 9 Jan 2025 14:36:02 +0100 Subject: [PATCH 241/463] fix compile error "const" was missing in the function implementation --- wled00/FX_fcn.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 433c828a..0c493f23 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -696,7 +696,7 @@ uint16_t Segment::virtualLength() const { return vLength; } -void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) +void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) const { if (!isActive() || i < 0) return; // not active or invalid index #ifndef WLED_DISABLE_2D From cd52d7bcf6723f4b48e67e6176a78fb89b624295 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 9 Jan 2025 14:39:54 +0100 Subject: [PATCH 242/463] align some function declariations with their implementation This is purely a "clean code" thing, no impact on function - it helps to avoid confusion when reading the code. C++ allows declaration and implementation to use different variable names. --- wled00/FX.h | 6 +++--- wled00/button.cpp | 10 +++++----- wled00/fcn_declare.h | 6 +++--- wled00/lx_parser.cpp | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 289896d2..2f42614a 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -598,7 +598,7 @@ typedef struct Segment { // 1D strip [[gnu::hot]] uint16_t virtualLength() const; - [[gnu::hot]] void setPixelColor(int n, uint32_t c) const; // set relative pixel within segment with color + [[gnu::hot]] void setPixelColor(int i, uint32_t c) const; // set relative pixel within segment with color inline void setPixelColor(unsigned n, uint32_t c) const { setPixelColor(int(n), c); } inline void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) const { setPixelColor(n, RGBW32(r,g,b,w)); } inline void setPixelColor(int n, CRGB c) const { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } @@ -805,7 +805,7 @@ class WS2812FX { // 96 bytes resetSegments(), // marks all segments for reset makeAutoSegments(bool forceReset = false), // will create segments based on configured outputs fixInvalidSegments(), // fixes incorrect segment configuration - setPixelColor(unsigned n, uint32_t c) const, // paints absolute strip pixel with index n and color c + setPixelColor(unsigned i, uint32_t c) const, // paints absolute strip pixel with index n and color c show(), // initiates LED output setTargetFps(unsigned fps), setupEffectData(); // add default effects to the list; defined in FX.cpp @@ -870,7 +870,7 @@ class WS2812FX { // 96 bytes }; unsigned long now, timebase; - uint32_t getPixelColor(unsigned) const; + uint32_t getPixelColor(unsigned i) const; inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call diff --git a/wled00/button.cpp b/wled00/button.cpp index 4e063c12..5144f09f 100644 --- a/wled00/button.cpp +++ b/wled00/button.cpp @@ -90,12 +90,12 @@ void doublePressAction(uint8_t b) #endif } -bool isButtonPressed(uint8_t i) +bool isButtonPressed(uint8_t b) { - if (btnPin[i]<0) return false; - unsigned pin = btnPin[i]; + if (btnPin[b]<0) return false; + unsigned pin = btnPin[b]; - switch (buttonType[i]) { + switch (buttonType[b]) { case BTN_TYPE_NONE: case BTN_TYPE_RESERVED: break; @@ -113,7 +113,7 @@ bool isButtonPressed(uint8_t i) #ifdef SOC_TOUCH_VERSION_2 //ESP32 S2 and S3 provide a function to check touch state (state is updated in interrupt) if (touchInterruptGetLastStatus(pin)) return true; #else - if (digitalPinToTouchChannel(btnPin[i]) >= 0 && touchRead(pin) <= touchThreshold) return true; + if (digitalPinToTouchChannel(btnPin[b]) >= 0 && touchRead(pin) <= touchThreshold) return true; #endif #endif break; diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index d30230f2..fcfa1bdc 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -251,8 +251,8 @@ bool deserializeState(JsonObject root, byte callMode = CALL_MODE_DIRECT_CHANGE, void serializeSegment(const JsonObject& root, const Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true); void serializeState(JsonObject root, bool forPreset = false, bool includeBri = true, bool segmentBounds = true, bool selectedSegmentsOnly = false); void serializeInfo(JsonObject root); -void serializeModeNames(JsonArray root); -void serializeModeData(JsonArray root); +void serializeModeNames(JsonArray arr); +void serializeModeData(JsonArray fxdata); void serveJson(AsyncWebServerRequest* request); #ifdef WLED_ENABLE_JSONLIVE bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0); @@ -469,7 +469,7 @@ void userLoop(); #endif [[gnu::pure]] int getNumVal(const String* req, uint16_t pos); void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255); -bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255); // getVal supports inc/decrementing and random ("X~Y(r|[w]~[-][Z])" form) +bool getVal(JsonVariant elem, byte* val, byte vmin=0, byte vmax=255); // getVal supports inc/decrementing and random ("X~Y(r|[w]~[-][Z])" form) [[gnu::pure]] bool getBoolVal(const JsonVariant &elem, bool dflt); bool updateVal(const char* req, const char* key, byte* val, byte minv=0, byte maxv=255); size_t printSetFormCheckbox(Print& settingsScript, const char* key, int val); diff --git a/wled00/lx_parser.cpp b/wled00/lx_parser.cpp index 7fd91ea0..1318686c 100644 --- a/wled00/lx_parser.cpp +++ b/wled00/lx_parser.cpp @@ -22,7 +22,7 @@ bool parseLx(int lxValue, byte* rgbw) } else if ((lxValue >= 200000000) && (lxValue <= 201006500)) { // Loxone Lumitech ok = true; - float tmpBri = floor((lxValue - 200000000) / 10000); ; + float tmpBri = floor((lxValue - 200000000) / 10000); uint16_t ct = (lxValue - 200000000) - (((uint8_t)tmpBri) * 10000); tmpBri *= 2.55f; From 566c5057f961524376e45ec7dad7d5550b16d303 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 16 Jan 2025 17:56:11 +0100 Subject: [PATCH 243/463] optimizations as per reviewer recommendations * removed unneeded initializations in blur() and blur2D() * remove check for _t in progress() * code readability: if (_t) --> if(isInTransition()) * add `isInTransition()` checks to currentBri() and currentMode() * added missing `_transitionprogress = 0xFFFFU` in stopTransition() --- wled00/FX.h | 2 +- wled00/FX_2Dfcn.cpp | 4 ++-- wled00/FX_fcn.cpp | 19 ++++++++++--------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 2f42614a..f54b3ba5 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -590,7 +590,7 @@ typedef struct Segment { void restoreSegenv(const tmpsegd_t &tmpSegD); // restores segment data from buffer, if buffer is not transition buffer, changed values are copied to transition buffer #endif [[gnu::hot]] void updateTransitionProgress(); // set current progression of transition - inline uint16_t progress() const { return _t ? Segment::_transitionprogress : 0xFFFFU; } // transition progression between 0-65535 + inline uint16_t progress() const { return Segment::_transitionprogress; } // transition progression between 0-65535 [[gnu::hot]] uint8_t currentBri(bool useCct = false) const; // current segment brightness/CCT (blended while in transition) uint8_t currentMode() const; // currently active effect/mode (while in transition) [[gnu::hot]] uint32_t currentColor(uint8_t slot) const; // currently active segment color (blended while in transition) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index ffaf53bb..0d38578a 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -276,8 +276,8 @@ void Segment::blur2D(uint8_t blur_x, uint8_t blur_y, bool smear) { if (!isActive()) return; // not active const unsigned cols = vWidth(); const unsigned rows = vHeight(); - uint32_t lastnew = BLACK; - uint32_t last = BLACK; + uint32_t lastnew; // not necessary to initialize lastnew and last, as both will be initialized by the first loop iteration + uint32_t last; if (blur_x) { const uint8_t keepx = smear ? 255 : 255 - blur_x; const uint8_t seepx = blur_x >> 1; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 0c493f23..5ad2314d 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -296,6 +296,7 @@ void Segment::stopTransition() { delete _t; _t = nullptr; } + _transitionprogress = 0xFFFFU; // stop means stop - transition has ended } // transition progression between 0-65535 @@ -326,7 +327,7 @@ void Segment::swapSegenv(tmpsegd_t &tmpSeg) { tmpSeg._callT = call; tmpSeg._dataT = data; tmpSeg._dataLenT = _dataLen; - if (_t && &tmpSeg != &(_t->_segT)) { + if (isInTransition() && &tmpSeg != &(_t->_segT)) { // swap SEGENV with transitional data options = _t->_segT._optionsT; for (size_t i=0; i_segT._colorT[i]; @@ -349,7 +350,7 @@ void Segment::swapSegenv(tmpsegd_t &tmpSeg) { void Segment::restoreSegenv(const tmpsegd_t &tmpSeg) { //DEBUG_PRINTF_P(PSTR("-- Restoring temp seg: %p->(%p) [%d->%p]\n"), &tmpSeg, this, _dataLen, data); - if (_t && &(_t->_segT) != &tmpSeg) { + if (isInTransition() && &(_t->_segT) != &tmpSeg) { // update possibly changed variables to keep old effect running correctly _t->_segT._aux0T = aux0; _t->_segT._aux1T = aux1; @@ -379,7 +380,7 @@ void Segment::restoreSegenv(const tmpsegd_t &tmpSeg) { #endif uint8_t Segment::currentBri(bool useCct) const { - unsigned prog = progress(); + unsigned prog = isInTransition() ? progress() : 0xFFFFU; if (prog < 0xFFFFU) { // progress() < 0xFFFF implies that _t is a valid pointer unsigned curBri = (useCct ? cct : (on ? opacity : 0)) * prog; curBri += (useCct ? _t->_cctT : _t->_briT) * (0xFFFFU - prog); @@ -390,7 +391,7 @@ uint8_t Segment::currentBri(bool useCct) const { uint8_t Segment::currentMode() const { #ifndef WLED_DISABLE_MODE_BLEND - unsigned prog = progress(); + unsigned prog = isInTransition() ? progress() : 0xFFFFU; if (modeBlending && prog < 0xFFFFU) return _t->_modeT; // progress() < 0xFFFF implies that _t is a valid pointer #endif return mode; @@ -411,18 +412,18 @@ void Segment::beginDraw() { _vHeight = virtualHeight(); _vLength = virtualLength(); _segBri = currentBri(); + unsigned prog = isInTransition() ? progress() : 0xFFFFU; // transition progress; 0xFFFFU = no transition active // adjust gamma for effects for (unsigned i = 0; i < NUM_COLORS; i++) { #ifndef WLED_DISABLE_MODE_BLEND - uint32_t col = isInTransition() ? color_blend16(_t->_segT._colorT[i], colors[i], progress()) : colors[i]; + uint32_t col = isInTransition() ? color_blend16(_t->_segT._colorT[i], colors[i], prog) : colors[i]; #else - uint32_t col = isInTransition() ? color_blend16(_t->_colorT[i], colors[i], progress()) : colors[i]; + uint32_t col = isInTransition() ? color_blend16(_t->_colorT[i], colors[i], prog) : colors[i]; #endif _currentColors[i] = gamma32(col); } // load palette into _currentPalette loadPalette(_currentPalette, palette); - unsigned prog = progress(); if (strip.paletteFade && prog < 0xFFFFU) { // blend palettes // there are about 255 blend passes of 48 "blends" to completely blend two palettes (in _dur time) @@ -1134,8 +1135,8 @@ void Segment::blur(uint8_t blur_amount, bool smear) { uint8_t seep = blur_amount >> 1; unsigned vlength = vLength(); uint32_t carryover = BLACK; - uint32_t lastnew = BLACK; - uint32_t last = BLACK; + uint32_t lastnew; // not necessary to initialize lastnew and last, as both will be initialized by the first loop iteration + uint32_t last; uint32_t curnew = BLACK; for (unsigned i = 0; i < vlength; i++) { uint32_t cur = getPixelColor(i); From aab29cb0abf2047fef8205910a17c9a2472aa452 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 19 Jan 2025 09:03:14 +0100 Subject: [PATCH 244/463] consolidated colorwaves and pride into one base function the two FX are almost identical in code with just a few lines difference. --- wled00/FX.cpp | 105 ++++++++++++++++++++------------------------------ 1 file changed, 41 insertions(+), 64 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 9fc9dbff..2655d7da 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -1893,48 +1893,72 @@ uint16_t mode_lightning(void) { } static const char _data_FX_MODE_LIGHTNING[] PROGMEM = "Lightning@!,!,,,,,Overlay;!,!;!"; - -// Pride2015 -// Animated, ever-changing rainbows. -// by Mark Kriegsman: https://gist.github.com/kriegsman/964de772d64c502760e5 -uint16_t mode_pride_2015(void) { +// combined function from original pride and colorwaves +uint16_t mode_colorwaves_pride_base(bool isPride2015) { unsigned duration = 10 + SEGMENT.speed; unsigned sPseudotime = SEGENV.step; unsigned sHue16 = SEGENV.aux0; - uint8_t sat8 = beatsin88_t( 87, 220, 250); - uint8_t brightdepth = beatsin88_t( 341, 96, 224); - unsigned brightnessthetainc16 = beatsin88_t( 203, (25 * 256), (40 * 256)); + uint8_t sat8 = isPride2015 ? beatsin88_t(87, 220, 250) : 255; + unsigned brightdepth = beatsin88_t(341, 96, 224); + unsigned brightnessthetainc16 = beatsin88_t(203, (25 * 256), (40 * 256)); unsigned msmultiplier = beatsin88_t(147, 23, 60); - unsigned hue16 = sHue16;//gHue * 256; - unsigned hueinc16 = beatsin88_t(113, 1, 3000); + unsigned hue16 = sHue16; + unsigned hueinc16 = isPride2015 ? beatsin88_t(113, 1, 3000) : + beatsin88_t(113, 60, 300) * SEGMENT.intensity * 10 / 255; sPseudotime += duration * msmultiplier; - sHue16 += duration * beatsin88_t( 400, 5,9); + sHue16 += duration * beatsin88_t(400, 5, 9); unsigned brightnesstheta16 = sPseudotime; - for (unsigned i = 0 ; i < SEGLEN; i++) { + for (unsigned i = 0; i < SEGLEN; i++) { hue16 += hueinc16; - uint8_t hue8 = hue16 >> 8; + uint8_t hue8; - brightnesstheta16 += brightnessthetainc16; - unsigned b16 = sin16_t( brightnesstheta16 ) + 32768; + if (isPride2015) { + hue8 = hue16 >> 8; + } else { + unsigned h16_128 = hue16 >> 7; + hue8 = (h16_128 & 0x100) ? (255 - (h16_128 >> 1)) : (h16_128 >> 1); + } + brightnesstheta16 += brightnessthetainc16; + unsigned b16 = sin16_t(brightnesstheta16) + 32768; unsigned bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536; uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536; bri8 += (255 - brightdepth); - CRGB newcolor = CHSV(hue8, sat8, bri8); - SEGMENT.blendPixelColor(i, newcolor, 64); + if (isPride2015) { + CRGB newcolor = CHSV(hue8, sat8, bri8); + SEGMENT.blendPixelColor(i, newcolor, 64); + } else { + SEGMENT.blendPixelColor(i, SEGMENT.color_from_palette(hue8, false, PALETTE_SOLID_WRAP, 0, bri8), 128); + } } + SEGENV.step = sPseudotime; SEGENV.aux0 = sHue16; return FRAMETIME; } + +// Pride2015 +// Animated, ever-changing rainbows. +// by Mark Kriegsman: https://gist.github.com/kriegsman/964de772d64c502760e5 +uint16_t mode_pride_2015(void) { + return mode_colorwaves_pride_base(true); +} static const char _data_FX_MODE_PRIDE_2015[] PROGMEM = "Pride 2015@!;;"; +// ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb +// This function draws color waves with an ever-changing, +// widely-varying set of parameters, using a color palette. +uint16_t mode_colorwaves() { + return mode_colorwaves_pride_base(false); +} +static const char _data_FX_MODE_COLORWAVES[] PROGMEM = "Colorwaves@!,Hue;!;!;;pal=26"; + //eight colored dots, weaving in and out of sync with each other uint16_t mode_juggle(void) { @@ -2141,53 +2165,6 @@ uint16_t mode_fire_2012() { } static const char _data_FX_MODE_FIRE_2012[] PROGMEM = "Fire 2012@Cooling,Spark rate,,2D Blur,Boost;;!;1;pal=35,sx=64,ix=160,m12=1,c2=128"; // bars - -// ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb -// This function draws color waves with an ever-changing, -// widely-varying set of parameters, using a color palette. -uint16_t mode_colorwaves() { - unsigned duration = 10 + SEGMENT.speed; - unsigned sPseudotime = SEGENV.step; - unsigned sHue16 = SEGENV.aux0; - - unsigned brightdepth = beatsin88_t(341, 96, 224); - unsigned brightnessthetainc16 = beatsin88_t( 203, (25 * 256), (40 * 256)); - unsigned msmultiplier = beatsin88_t(147, 23, 60); - - unsigned hue16 = sHue16;//gHue * 256; - unsigned hueinc16 = beatsin88_t(113, 60, 300)*SEGMENT.intensity*10/255; // Use the Intensity Slider for the hues - - sPseudotime += duration * msmultiplier; - sHue16 += duration * beatsin88_t(400, 5, 9); - unsigned brightnesstheta16 = sPseudotime; - - for (unsigned i = 0 ; i < SEGLEN; i++) { - hue16 += hueinc16; - uint8_t hue8 = hue16 >> 8; - unsigned h16_128 = hue16 >> 7; - if ( h16_128 & 0x100) { - hue8 = 255 - (h16_128 >> 1); - } else { - hue8 = h16_128 >> 1; - } - - brightnesstheta16 += brightnessthetainc16; - unsigned b16 = sin16_t(brightnesstheta16) + 32768; - - unsigned bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536; - uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536; - bri8 += (255 - brightdepth); - - SEGMENT.blendPixelColor(i, SEGMENT.color_from_palette(hue8, false, PALETTE_SOLID_WRAP, 0, bri8), 128); // 50/50 mix - } - SEGENV.step = sPseudotime; - SEGENV.aux0 = sHue16; - - return FRAMETIME; -} -static const char _data_FX_MODE_COLORWAVES[] PROGMEM = "Colorwaves@!,Hue;!;!;;pal=26"; - - // colored stripes pulsing at a defined Beats-Per-Minute (BPM) uint16_t mode_bpm() { uint32_t stp = (strip.now / 20) & 0xFF; From 0c84235a95bb29dde2237cb8e6a0a0437770d27d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sun, 19 Jan 2025 10:17:33 +0100 Subject: [PATCH 245/463] Bus rework - Implement vector in bus manager - Memory calculation according to explanation from @Makuna - Prefer 8 RMT before 8 I2S on ESP32 (fixes #4380) - speed improvements in ABL - verbose debugging - get bus size from NPB (prototype) - Parallel I2S output bugfix - automatic selection of appropriate I2S bus (`X1xxxxxxMethod`) - removed I2S0 on ESP32 (used by AudioReactive) - renumbered internal bus numbers (iType) - added buffer size reporting --- wled00/FX_fcn.cpp | 30 ++ wled00/bus_manager.cpp | 184 ++++---- wled00/bus_manager.h | 116 ++--- wled00/bus_wrapper.h | 790 ++++++++++++++++++---------------- wled00/cfg.cpp | 28 +- wled00/const.h | 20 +- wled00/data/settings_leds.htm | 12 + wled00/fcn_declare.h | 1 + wled00/set.cpp | 6 +- wled00/wled.h | 3 + wled00/xml.cpp | 1 + 11 files changed, 676 insertions(+), 515 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 5ad2314d..10bb208c 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1220,6 +1220,33 @@ void WS2812FX::finalizeInit() { _hasWhiteChannel = _isOffRefreshRequired = false; + unsigned digitalCount = 0; + #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) + // determine if it is sensible to use parallel I2S outputs on ESP32 (i.e. more than 5 outputs = 1 I2S + 4 RMT) + unsigned maxLedsOnBus = 0; + for (const auto &bus : busConfigs) { + if (Bus::isDigital(bus.type) && !Bus::is2Pin(bus.type)) { + digitalCount++; + if (bus.count > maxLedsOnBus) maxLedsOnBus = bus.count; + } + } + DEBUG_PRINTF_P(PSTR("Maximum LEDs on a bus: %u\nDigital buses: %u\n"), maxLedsOnBus, digitalCount); + // we may remove 300 LEDs per bus limit when NeoPixelBus is updated beyond 2.9.0 + if (maxLedsOnBus <= 300 && useParallelI2S) BusManager::useParallelOutput(); // must call before creating buses + else useParallelI2S = false; // enforce single I2S + #endif + + // create buses/outputs + unsigned mem = 0; + digitalCount = 0; + for (const auto &bus : busConfigs) { + mem += bus.memUsage(Bus::isDigital(bus.type) && !Bus::is2Pin(bus.type) ? digitalCount++ : 0); // includes global buffer + if (mem <= MAX_LED_MEMORY) BusManager::add(bus); + else DEBUG_PRINTF_P(PSTR("Out of LED memory! Bus %d (%d) #%u not created."), (int)bus.type, (int)bus.count, digitalCount); + } + busConfigs.clear(); + busConfigs.shrink_to_fit(); + //if busses failed to load, add default (fresh install, FS issue, ...) if (BusManager::getNumBusses() == 0) { DEBUG_PRINTLN(F("No busses, init default")); @@ -1235,6 +1262,7 @@ void WS2812FX::finalizeInit() { unsigned prevLen = 0; unsigned pinsIndex = 0; + digitalCount = 0; for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { uint8_t defPin[OUTPUT_MAX_PINS]; // if we have less types than requested outputs and they do not align, use last known type to set current type @@ -1299,9 +1327,11 @@ void WS2812FX::finalizeInit() { if (Bus::isPWM(dataType) || Bus::isOnOff(dataType)) count = 1; prevLen += count; BusConfig defCfg = BusConfig(dataType, defPin, start, count, DEFAULT_LED_COLOR_ORDER, false, 0, RGBW_MODE_MANUAL_ONLY, 0, useGlobalLedBuffer); + mem += defCfg.memUsage(Bus::isDigital(dataType) && !Bus::is2Pin(dataType) ? digitalCount++ : 0); if (BusManager::add(defCfg) == -1) break; } } + DEBUG_PRINTF_P(PSTR("LED buffer size: %uB/%uB\n"), mem, BusManager::memUsage()); _length = 0; for (int i=0; i0 ? calloc(size, sizeof(uint8_t)) : nullptr); } +void Bus::freeData() { + if (_data) free(_data); + _data = nullptr; +} + BusDigital::BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com) : Bus(bc.type, bc.start, bc.autoWhite, bc.count, bc.reversed, (bc.refreshReq || bc.type == TYPE_TM1814)) @@ -129,30 +134,41 @@ BusDigital::BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com , _milliAmpsMax(bc.milliAmpsMax) , _colorOrderMap(com) { - if (!isDigital(bc.type) || !bc.count) return; - if (!PinManager::allocatePin(bc.pins[0], true, PinOwner::BusDigital)) return; + DEBUG_PRINTLN(F("Bus: Creating digital bus.")); + if (!isDigital(bc.type) || !bc.count) { DEBUG_PRINTLN(F("Not digial or empty bus!")); return; } + if (!PinManager::allocatePin(bc.pins[0], true, PinOwner::BusDigital)) { DEBUG_PRINTLN(F("Pin 0 allocated!")); return; } _frequencykHz = 0U; _pins[0] = bc.pins[0]; if (is2Pin(bc.type)) { if (!PinManager::allocatePin(bc.pins[1], true, PinOwner::BusDigital)) { cleanup(); + DEBUG_PRINTLN(F("Pin 1 allocated!")); return; } _pins[1] = bc.pins[1]; _frequencykHz = bc.frequency ? bc.frequency : 2000U; // 2MHz clock if undefined } _iType = PolyBus::getI(bc.type, _pins, nr); - if (_iType == I_NONE) return; + if (_iType == I_NONE) { DEBUG_PRINTLN(F("Incorrect iType!")); return; } _hasRgb = hasRGB(bc.type); _hasWhite = hasWhite(bc.type); _hasCCT = hasCCT(bc.type); - if (bc.doubleBuffer && !allocateData(bc.count * Bus::getNumberOfChannels(bc.type))) return; + if (bc.doubleBuffer && !allocateData(bc.count * Bus::getNumberOfChannels(bc.type))) { DEBUG_PRINTLN(F("Buffer allocation failed!")); return; } //_buffering = bc.doubleBuffer; uint16_t lenToCreate = bc.count; if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(bc.count); // only needs a third of "RGB" LEDs for NeoPixelBus _busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr); _valid = (_busPtr != nullptr); - DEBUG_PRINTF_P(PSTR("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u). mA=%d/%d\n"), _valid?"S":"Uns", nr, bc.count, bc.type, _pins[0], is2Pin(bc.type)?_pins[1]:255, _iType, _milliAmpsPerLed, _milliAmpsMax); + DEBUG_PRINTF_P(PSTR("Bus: %successfully inited #%u (len:%u, type:%u (RGB:%d, W:%d, CCT:%d), pins:%u,%u [itype:%u] mA=%d/%d)\n"), + _valid?"S":"Uns", + (int)nr, + (int)bc.count, + (int)bc.type, + (int)_hasRgb, (int)_hasWhite, (int)_hasCCT, + (unsigned)_pins[0], is2Pin(bc.type)?(unsigned)_pins[1]:255U, + (unsigned)_iType, + (int)_milliAmpsPerLed, (int)_milliAmpsMax + ); } //DISCLAIMER @@ -163,7 +179,7 @@ BusDigital::BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com //I am NOT to be held liable for burned down garages or houses! // To disable brightness limiter we either set output max current to 0 or single LED current to 0 -uint8_t BusDigital::estimateCurrentAndLimitBri() { +uint8_t BusDigital::estimateCurrentAndLimitBri() const { bool useWackyWS2815PowerModel = false; byte actualMilliampsPerLed = _milliAmpsPerLed; @@ -176,7 +192,7 @@ uint8_t BusDigital::estimateCurrentAndLimitBri() { actualMilliampsPerLed = 12; // from testing an actual strip } - size_t powerBudget = (_milliAmpsMax - MA_FOR_ESP/BusManager::getNumBusses()); //80/120mA for ESP power + unsigned powerBudget = (_milliAmpsMax - MA_FOR_ESP/BusManager::getNumBusses()); //80/120mA for ESP power if (powerBudget > getLength()) { //each LED uses about 1mA in standby, exclude that from power budget powerBudget -= getLength(); } else { @@ -201,26 +217,25 @@ uint8_t BusDigital::estimateCurrentAndLimitBri() { } // powerSum has all the values of channels summed (max would be getLength()*765 as white is excluded) so convert to milliAmps - busPowerSum = (busPowerSum * actualMilliampsPerLed) / 765; - _milliAmpsTotal = busPowerSum * _bri / 255; + BusDigital::_milliAmpsTotal = (busPowerSum * actualMilliampsPerLed * _bri) / (765*255); uint8_t newBri = _bri; - if (busPowerSum * _bri / 255 > powerBudget) { //scale brightness down to stay in current limit - float scale = (float)(powerBudget * 255) / (float)(busPowerSum * _bri); - if (scale >= 1.0f) return _bri; - _milliAmpsTotal = ceilf((float)_milliAmpsTotal * scale); - uint8_t scaleB = min((int)(scale * 255), 255); - newBri = unsigned(_bri * scaleB) / 256 + 1; + if (BusDigital::_milliAmpsTotal > powerBudget) { + //scale brightness down to stay in current limit + unsigned scaleB = powerBudget * 255 / BusDigital::_milliAmpsTotal; + newBri = (_bri * scaleB) / 256 + 1; + BusDigital::_milliAmpsTotal = powerBudget; + //_milliAmpsTotal = (busPowerSum * actualMilliampsPerLed * newBri) / (765*255); } return newBri; } void BusDigital::show() { - _milliAmpsTotal = 0; + BusDigital::_milliAmpsTotal = 0; if (!_valid) return; uint8_t cctWW = 0, cctCW = 0; - unsigned newBri = estimateCurrentAndLimitBri(); // will fill _milliAmpsTotal + unsigned newBri = estimateCurrentAndLimitBri(); // will fill _milliAmpsTotal (TODO: could use PolyBus::CalcTotalMilliAmpere()) if (newBri < _bri) PolyBus::setBrightness(_busPtr, _iType, newBri); // limit brightness to stay within current limits if (_data) { @@ -374,6 +389,10 @@ uint8_t BusDigital::getPins(uint8_t* pinArray) const { return numPins; } +unsigned BusDigital::getBusSize() const { + return sizeof(BusDigital) + (isOk() ? PolyBus::getDataSize(_busPtr, _iType) + (_data ? _len * getNumberOfChannels() : 0) : 0); +} + void BusDigital::setColorOrder(uint8_t colorOrder) { // upper nibble contains W swap information if ((colorOrder & 0x0F) > 5) return; @@ -396,8 +415,8 @@ std::vector BusDigital::getLEDTypes() { {TYPE_WS2805, "D", PSTR("WS2805 RGBCW")}, {TYPE_SM16825, "D", PSTR("SM16825 RGBCW")}, {TYPE_WS2812_1CH_X3, "D", PSTR("WS2811 White")}, - //{TYPE_WS2812_2CH_X3, "D", PSTR("WS2811 CCT")}, // not implemented - //{TYPE_WS2812_WWA, "D", PSTR("WS2811 WWA")}, // not implemented + //{TYPE_WS2812_2CH_X3, "D", PSTR("WS281x CCT")}, // not implemented + {TYPE_WS2812_WWA, "D", PSTR("WS281x WWA")}, // amber ignored {TYPE_WS2801, "2P", PSTR("WS2801")}, {TYPE_APA102, "2P", PSTR("APA102")}, {TYPE_LPD8806, "2P", PSTR("LPD8806")}, @@ -417,7 +436,8 @@ void BusDigital::cleanup() { _iType = I_NONE; _valid = false; _busPtr = nullptr; - if (_data != nullptr) freeData(); + freeData(); + //PinManager::deallocateMultiplePins(_pins, 2, PinOwner::BusDigital); PinManager::deallocatePin(_pins[1], PinOwner::BusDigital); PinManager::deallocatePin(_pins[0], PinOwner::BusDigital); } @@ -492,7 +512,7 @@ BusPwm::BusPwm(const BusConfig &bc) _hasRgb = hasRGB(bc.type); _hasWhite = hasWhite(bc.type); _hasCCT = hasCCT(bc.type); - _data = _pwmdata; // avoid malloc() and use stack + _data = _pwmdata; // avoid malloc() and use already allocated memory _valid = true; 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]); } @@ -771,6 +791,7 @@ std::vector BusNetwork::getLEDTypes() { } void BusNetwork::cleanup() { + DEBUG_PRINTLN(F("Virtual Cleanup.")); _type = I_NONE; _valid = false; freeData(); @@ -778,41 +799,59 @@ void BusNetwork::cleanup() { //utility to get the approx. memory usage of a given BusConfig -uint32_t BusManager::memUsage(const BusConfig &bc) { - if (Bus::isOnOff(bc.type) || Bus::isPWM(bc.type)) return OUTPUT_MAX_PINS; - - unsigned len = bc.count + bc.skipAmount; - unsigned channels = Bus::getNumberOfChannels(bc.type); - unsigned multiplier = 1; - if (Bus::isDigital(bc.type)) { // digital types - if (Bus::is16bit(bc.type)) len *= 2; // 16-bit LEDs - #ifdef ESP8266 - if (bc.pins[0] == 3) { //8266 DMA uses 5x the mem - multiplier = 5; - } - #else //ESP32 RMT uses double buffer, parallel I2S uses 8x buffer (3 times) - multiplier = PolyBus::isParallelI2S1Output() ? 24 : 2; - #endif +unsigned BusConfig::memUsage(unsigned nr) const { + if (Bus::isVirtual(type)) { + return sizeof(BusNetwork) + (count * Bus::getNumberOfChannels(type)); + } else if (Bus::isDigital(type)) { + return sizeof(BusDigital) + PolyBus::memUsage(count + skipAmount, PolyBus::getI(type, pins, nr)) + doubleBuffer * (count + skipAmount) * Bus::getNumberOfChannels(type); + } else if (Bus::isOnOff(type)) { + return sizeof(BusOnOff); + } else { + return sizeof(BusPwm); } - return (len * multiplier + bc.doubleBuffer * (bc.count + bc.skipAmount)) * channels; } -uint32_t BusManager::memUsage(unsigned maxChannels, unsigned maxCount, unsigned minBuses) { - //ESP32 RMT uses double buffer, parallel I2S uses 8x buffer (3 times) - unsigned multiplier = PolyBus::isParallelI2S1Output() ? 3 : 2; - return (maxChannels * maxCount * minBuses * multiplier); + +unsigned BusManager::memUsage() { + // when ESP32, S2 & S3 use parallel I2S only the largest bus determines the total memory requirements for back buffers + // front buffers are always allocated per bus + unsigned size = 0; + unsigned maxI2S = 0; + #if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(ESP8266) + unsigned digitalCount = 0; + #if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) + #define MAX_RMT 4 + #else + #define MAX_RMT 8 + #endif + #endif + for (const auto &bus : busses) { + //for (unsigned i=0; igetBusSize(); + #if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(ESP8266) + if (bus->isDigital() && !bus->is2Pin()) digitalCount++; + if (PolyBus::isParallelI2S1Output() && digitalCount > MAX_RMT) { + unsigned i2sCommonSize = 3 * bus->getLength() * bus->getNumberOfChannels() * (bus->is16bit()+1); + if (i2sCommonSize > maxI2S) maxI2S = i2sCommonSize; + busSize -= i2sCommonSize; + } + #endif + size += busSize; + } + return size + maxI2S; } int BusManager::add(const BusConfig &bc) { + DEBUG_PRINTF_P(PSTR("Bus: Adding bus #%d (%d - %d >= %d)\n"), numBusses, getNumBusses(), getNumVirtualBusses(), WLED_MAX_BUSSES); if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1; if (Bus::isVirtual(bc.type)) { - busses[numBusses] = new BusNetwork(bc); + busses.push_back(new BusNetwork(bc)); } else if (Bus::isDigital(bc.type)) { - busses[numBusses] = new BusDigital(bc, numBusses, colorOrderMap); + busses.push_back(new BusDigital(bc, numBusses, colorOrderMap)); } else if (Bus::isOnOff(bc.type)) { - busses[numBusses] = new BusOnOff(bc); + busses.push_back(new BusOnOff(bc)); } else { - busses[numBusses] = new BusPwm(bc); + busses.push_back(new BusPwm(bc)); } return numBusses++; } @@ -843,7 +882,7 @@ String BusManager::getLEDTypesJSONString() { } void BusManager::useParallelOutput() { - _parallelOutputs = 8; // hardcoded since we use NPB I2S x8 methods + DEBUG_PRINTLN(F("Bus: Enabling parallel I2S.")); PolyBus::setParallelI2S1Output(); } @@ -852,7 +891,8 @@ void BusManager::removeAll() { DEBUG_PRINTLN(F("Removing all.")); //prevents crashes due to deleting busses while in use. while (!canAllShow()) yield(); - for (unsigned i = 0; i < numBusses; i++) delete busses[i]; + for (auto &bus : busses) delete bus; + busses.clear(); numBusses = 0; _parallelOutputs = 1; PolyBus::setParallelI2S1Output(false); @@ -897,12 +937,12 @@ void BusManager::on() { #ifdef ESP8266 //Fix for turning off onboard LED breaking bus if (PinManager::getPinOwner(LED_BUILTIN) == PinOwner::BusDigital) { - for (unsigned i = 0; i < numBusses; i++) { + for (auto &bus : busses) { uint8_t pins[2] = {255,255}; - if (busses[i]->isDigital() && busses[i]->getPins(pins)) { + if (bus->isDigital() && bus->getPins(pins)) { if (pins[0] == LED_BUILTIN || pins[1] == LED_BUILTIN) { - BusDigital *bus = static_cast(busses[i]); - bus->begin(); + BusDigital *b = static_cast(bus); + b->begin(); break; } } @@ -919,7 +959,7 @@ void BusManager::off() { // turn off built-in LED if strip is turned off // this will break digital bus so will need to be re-initialised on On if (PinManager::getPinOwner(LED_BUILTIN) == PinOwner::BusDigital) { - for (unsigned i = 0; i < numBusses; i++) if (busses[i]->isOffRefreshRequired()) return; + for (const auto &bus : busses) if (bus->isOffRefreshRequired()) return; pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); } @@ -931,30 +971,26 @@ void BusManager::off() { void BusManager::show() { _milliAmpsUsed = 0; - for (unsigned i = 0; i < numBusses; i++) { - busses[i]->show(); - _milliAmpsUsed += busses[i]->getUsedCurrent(); + for (auto &bus : busses) { + bus->show(); + _milliAmpsUsed += bus->getUsedCurrent(); } } void BusManager::setStatusPixel(uint32_t c) { - for (unsigned i = 0; i < numBusses; i++) { - busses[i]->setStatusPixel(c); - } + for (auto &bus : busses) bus->setStatusPixel(c); } void IRAM_ATTR BusManager::setPixelColor(unsigned pix, uint32_t c) { - for (unsigned i = 0; i < numBusses; i++) { - unsigned bstart = busses[i]->getStart(); - if (pix < bstart || pix >= bstart + busses[i]->getLength()) continue; - busses[i]->setPixelColor(pix - bstart, c); + for (auto &bus : busses) { + unsigned bstart = bus->getStart(); + if (pix < bstart || pix >= bstart + bus->getLength()) continue; + bus->setPixelColor(pix - bstart, c); } } void BusManager::setBrightness(uint8_t b) { - for (unsigned i = 0; i < numBusses; i++) { - busses[i]->setBrightness(b); - } + for (auto &bus : busses) bus->setBrightness(b); } void BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) { @@ -967,30 +1003,28 @@ void BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) { } uint32_t BusManager::getPixelColor(unsigned pix) { - for (unsigned i = 0; i < numBusses; i++) { - unsigned bstart = busses[i]->getStart(); - if (!busses[i]->containsPixel(pix)) continue; - return busses[i]->getPixelColor(pix - bstart); + for (auto &bus : busses) { + unsigned bstart = bus->getStart(); + if (!bus->containsPixel(pix)) continue; + return bus->getPixelColor(pix - bstart); } return 0; } bool BusManager::canAllShow() { - for (unsigned i = 0; i < numBusses; i++) { - if (!busses[i]->canShow()) return false; - } + for (const auto &bus : busses) if (!bus->canShow()) return false; return true; } Bus* BusManager::getBus(uint8_t busNr) { - if (busNr >= numBusses) return nullptr; + if (busNr >= busses.size()) return nullptr; return busses[busNr]; } //semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit()) uint16_t BusManager::getTotalLength() { unsigned len = 0; - for (unsigned i=0; igetLength(); + for (const auto &bus : busses) len += bus->getLength(); return len; } @@ -1004,7 +1038,7 @@ uint8_t Bus::_gAWM = 255; uint16_t BusDigital::_milliAmpsTotal = 0; uint8_t BusManager::numBusses = 0; -Bus* BusManager::busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES]; +std::vector BusManager::busses; ColorOrderMap BusManager::colorOrderMap = {}; uint16_t BusManager::_milliAmpsUsed = 0; uint16_t BusManager::_milliAmpsMax = ABL_MILLIAMPS_DEFAULT; diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 9aed0130..3692751c 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -1,3 +1,4 @@ +#pragma once #ifndef BusManager_h #define BusManager_h @@ -78,48 +79,49 @@ class Bus { _autoWhiteMode = Bus::hasWhite(type) ? aw : RGBW_MODE_MANUAL_ONLY; }; - virtual ~Bus() {} //throw the bus under the bus + virtual ~Bus() {} //throw the bus under the bus (derived class needs to freeData()) - virtual void begin() {}; + virtual void begin() {}; virtual void show() = 0; - virtual bool canShow() const { return true; } - virtual void setStatusPixel(uint32_t c) {} + virtual bool canShow() const { return true; } + virtual void setStatusPixel(uint32_t c) {} virtual void setPixelColor(unsigned pix, uint32_t c) = 0; - virtual void setBrightness(uint8_t b) { _bri = b; }; - virtual void setColorOrder(uint8_t co) {} - virtual uint32_t getPixelColor(unsigned pix) const { return 0; } - virtual uint8_t getPins(uint8_t* pinArray = nullptr) const { return 0; } - virtual uint16_t getLength() const { return isOk() ? _len : 0; } - virtual uint8_t getColorOrder() const { return COL_ORDER_RGB; } - virtual uint8_t skippedLeds() const { return 0; } - virtual uint16_t getFrequency() const { return 0U; } - virtual uint16_t getLEDCurrent() const { return 0; } - virtual uint16_t getUsedCurrent() const { return 0; } - virtual uint16_t getMaxCurrent() const { return 0; } + virtual void setBrightness(uint8_t b) { _bri = b; }; + virtual void setColorOrder(uint8_t co) {} + virtual uint32_t getPixelColor(unsigned pix) const { return 0; } + virtual unsigned getPins(uint8_t* pinArray = nullptr) const { return 0; } + virtual uint16_t getLength() const { return isOk() ? _len : 0; } + virtual uint8_t getColorOrder() const { return COL_ORDER_RGB; } + virtual unsigned skippedLeds() const { return 0; } + virtual uint16_t getFrequency() const { return 0U; } + virtual uint16_t getLEDCurrent() const { return 0; } + virtual uint16_t getUsedCurrent() const { return 0; } + virtual uint16_t getMaxCurrent() const { return 0; } + virtual unsigned getBusSize() const { return sizeof(Bus); } - inline bool hasRGB() const { return _hasRgb; } - inline bool hasWhite() const { return _hasWhite; } - inline bool hasCCT() const { return _hasCCT; } - inline bool isDigital() const { return isDigital(_type); } - inline bool is2Pin() const { return is2Pin(_type); } - inline bool isOnOff() const { return isOnOff(_type); } - inline bool isPWM() const { return isPWM(_type); } - inline bool isVirtual() const { return isVirtual(_type); } - inline bool is16bit() const { return is16bit(_type); } - inline bool mustRefresh() const { return mustRefresh(_type); } - inline void setReversed(bool reversed) { _reversed = reversed; } - inline void setStart(uint16_t start) { _start = start; } - inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; } - inline uint8_t getAutoWhiteMode() const { return _autoWhiteMode; } - inline uint32_t getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); } - inline uint16_t getStart() const { return _start; } - inline uint8_t getType() const { return _type; } - inline bool isOk() const { return _valid; } - inline bool isReversed() const { return _reversed; } - inline bool isOffRefreshRequired() const { return _needsRefresh; } - inline bool containsPixel(uint16_t pix) const { return pix >= _start && pix < _start + _len; } + inline bool hasRGB() const { return _hasRgb; } + inline bool hasWhite() const { return _hasWhite; } + inline bool hasCCT() const { return _hasCCT; } + inline bool isDigital() const { return isDigital(_type); } + inline bool is2Pin() const { return is2Pin(_type); } + inline bool isOnOff() const { return isOnOff(_type); } + inline bool isPWM() const { return isPWM(_type); } + inline bool isVirtual() const { return isVirtual(_type); } + inline bool is16bit() const { return is16bit(_type); } + inline bool mustRefresh() const { return mustRefresh(_type); } + inline void setReversed(bool reversed) { _reversed = reversed; } + inline void setStart(uint16_t start) { _start = start; } + inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; } + inline uint8_t getAutoWhiteMode() const { return _autoWhiteMode; } + inline uint32_t getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); } + inline uint16_t getStart() const { return _start; } + inline uint8_t getType() const { return _type; } + inline bool isOk() const { return _valid; } + inline bool isReversed() const { return _reversed; } + inline bool isOffRefreshRequired() const { return _needsRefresh; } + inline bool containsPixel(uint16_t pix) const { return pix >= _start && pix < _start + _len; } - static inline std::vector getLEDTypes() { return {{TYPE_NONE, "", PSTR("None")}}; } // not used. just for reference for derived classes + static inline std::vector getLEDTypes() { return {{TYPE_NONE, "", PSTR("None")}}; } // not used. just for reference for derived classes static constexpr uint32_t getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK static constexpr uint32_t getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); } static constexpr bool hasRGB(uint8_t type) { @@ -192,7 +194,7 @@ class Bus { uint32_t autoWhiteCalc(uint32_t c) const; uint8_t *allocateData(size_t size = 1); - void freeData() { if (_data != nullptr) free(_data); _data = nullptr; } + void freeData(); }; @@ -215,6 +217,7 @@ class BusDigital : public Bus { uint16_t getLEDCurrent() const override { return _milliAmpsPerLed; } uint16_t getUsedCurrent() const override { return _milliAmpsTotal; } uint16_t getMaxCurrent() const override { return _milliAmpsMax; } + unsigned getBusSize() const override; void begin() override; void cleanup(); @@ -244,7 +247,7 @@ class BusDigital : public Bus { return c; } - uint8_t estimateCurrentAndLimitBri(); + uint8_t estimateCurrentAndLimitBri() const; }; @@ -257,8 +260,9 @@ class BusPwm : public Bus { uint32_t getPixelColor(unsigned pix) const override; //does no index check uint8_t getPins(uint8_t* pinArray = nullptr) const override; uint16_t getFrequency() const override { return _frequency; } + unsigned getBusSize() const override { return sizeof(BusPwm); } void show() override; - void cleanup() { deallocatePins(); } + inline void cleanup() { deallocatePins(); _data = nullptr; } static std::vector getLEDTypes(); @@ -282,9 +286,10 @@ class BusOnOff : public Bus { void setPixelColor(unsigned pix, uint32_t c) override; uint32_t getPixelColor(unsigned pix) const override; - uint8_t getPins(uint8_t* pinArray) const override; + unsigned getPins(uint8_t* pinArray) const override; + unsigned getBusSize() const override { return sizeof(BusOnOff); } void show() override; - void cleanup() { PinManager::deallocatePin(_pin, PinOwner::BusOnOff); } + inline void cleanup() { PinManager::deallocatePin(_pin, PinOwner::BusOnOff); _data = nullptr; } static std::vector getLEDTypes(); @@ -300,9 +305,10 @@ class BusNetwork : public Bus { ~BusNetwork() { cleanup(); } bool canShow() const override { return !_broadcastLock; } // this should be a return value from UDP routine if it is still sending data out - void setPixelColor(unsigned pix, uint32_t c) override; - uint32_t getPixelColor(unsigned pix) const override; - uint8_t getPins(uint8_t* pinArray = nullptr) const override; + [[gnu::hot]] void setPixelColor(unsigned pix, uint32_t c) override; + [[gnu::hot]] uint32_t getPixelColor(unsigned pix) const override; + unsigned getPins(uint8_t* pinArray = nullptr) const override; + unsigned getBusSize() const override { return sizeof(BusNetwork) + (isOk() ? _len * _UDPchannels : 0); } void show() override; void cleanup(); @@ -348,6 +354,16 @@ struct BusConfig { type = busType & 0x7F; // bit 7 may be/is hacked to include refresh info (1=refresh in off state, 0=no refresh) size_t nPins = Bus::getNumberOfPins(type); for (size_t i = 0; i < nPins; i++) pins[i] = ppins[i]; + DEBUG_PRINTF_P(PSTR("Bus: Config (%d-%d, type:%d, CO:%d, rev:%d, skip:%d, AW:%d kHz:%d, mA:%d/%d)\n"), + (int)start, (int)(start+len), + (int)type, + (int)colorOrder, + (int)reversed, + (int)skipAmount, + (int)autoWhite, + (int)frequency, + (int)milliAmpsPerLed, (int)milliAmpsMax + ); } //validates start and length and extends total if needed @@ -361,6 +377,8 @@ struct BusConfig { if (start + count > total) total = start + count; return true; } + + unsigned memUsage(unsigned nr = 0) const; }; @@ -378,9 +396,7 @@ class BusManager { public: BusManager() {}; - //utility to get the approx. memory usage of a given BusConfig - static uint32_t memUsage(const BusConfig &bc); - static uint32_t memUsage(unsigned channels, unsigned count, unsigned buses = 1); + static unsigned memUsage(); static uint16_t currentMilliamps() { return _milliAmpsUsed + MA_FOR_ESP; } static uint16_t ablMilliampsMax() { return _milliAmpsMax; } @@ -416,7 +432,7 @@ class BusManager { private: static uint8_t numBusses; - static Bus* busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES]; + static std::vector busses; static ColorOrderMap colorOrderMap; static uint16_t _milliAmpsUsed; static uint16_t _milliAmpsMax; @@ -427,7 +443,7 @@ class BusManager { #endif static uint8_t getNumVirtualBusses() { int j = 0; - for (int i=0; iisVirtual()) j++; + for (const auto &bus : busses) j += bus->isVirtual(); return j; } }; diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index d2a18c9d..24ffe9c5 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -1,24 +1,11 @@ +#pragma once #ifndef BusWrapper_h #define BusWrapper_h +//#define NPB_CONF_4STEP_CADENCE #include "NeoPixelBusLg.h" #include "bus_manager.h" -// temporary - these defines should actually be set in platformio.ini -// C3: I2S0 and I2S1 methods not supported (has one I2S bus) -// S2: I2S1 methods not supported (has one I2S bus) -// S3: I2S0 and I2S1 methods not supported yet (has two I2S buses) -// https://github.com/Makuna/NeoPixelBus/blob/b32f719e95ef3c35c46da5c99538017ef925c026/src/internal/Esp32_i2s.h#L4 -// https://github.com/Makuna/NeoPixelBus/blob/b32f719e95ef3c35c46da5c99538017ef925c026/src/internal/NeoEsp32RmtMethod.h#L857 - -#if !defined(WLED_NO_I2S0_PIXELBUS) && (defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3)) -#define WLED_NO_I2S0_PIXELBUS -#endif -#if !defined(WLED_NO_I2S1_PIXELBUS) && (defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2)) -#define WLED_NO_I2S1_PIXELBUS -#endif -// temporary end - //Hardware SPI Pins #define P_8266_HS_MOSI 13 #define P_8266_HS_CLK 14 @@ -55,110 +42,98 @@ #define I_8266_DM_TM2_3 19 #define I_8266_BB_TM2_3 20 //UCS8903 (RGB) -#define I_8266_U0_UCS_3 49 -#define I_8266_U1_UCS_3 50 -#define I_8266_DM_UCS_3 51 -#define I_8266_BB_UCS_3 52 +#define I_8266_U0_UCS_3 21 +#define I_8266_U1_UCS_3 22 +#define I_8266_DM_UCS_3 23 +#define I_8266_BB_UCS_3 24 //UCS8904 (RGBW) -#define I_8266_U0_UCS_4 53 -#define I_8266_U1_UCS_4 54 -#define I_8266_DM_UCS_4 55 -#define I_8266_BB_UCS_4 56 +#define I_8266_U0_UCS_4 25 +#define I_8266_U1_UCS_4 26 +#define I_8266_DM_UCS_4 27 +#define I_8266_BB_UCS_4 28 //FW1906 GRBCW -#define I_8266_U0_FW6_5 66 -#define I_8266_U1_FW6_5 67 -#define I_8266_DM_FW6_5 68 -#define I_8266_BB_FW6_5 69 +#define I_8266_U0_FW6_5 29 +#define I_8266_U1_FW6_5 30 +#define I_8266_DM_FW6_5 31 +#define I_8266_BB_FW6_5 32 //ESP8266 APA106 -#define I_8266_U0_APA106_3 81 -#define I_8266_U1_APA106_3 82 -#define I_8266_DM_APA106_3 83 -#define I_8266_BB_APA106_3 84 +#define I_8266_U0_APA106_3 33 +#define I_8266_U1_APA106_3 34 +#define I_8266_DM_APA106_3 35 +#define I_8266_BB_APA106_3 36 //WS2805 (RGBCW) -#define I_8266_U0_2805_5 89 -#define I_8266_U1_2805_5 90 -#define I_8266_DM_2805_5 91 -#define I_8266_BB_2805_5 92 +#define I_8266_U0_2805_5 37 +#define I_8266_U1_2805_5 38 +#define I_8266_DM_2805_5 39 +#define I_8266_BB_2805_5 40 //TM1914 (RGB) -#define I_8266_U0_TM1914_3 99 -#define I_8266_U1_TM1914_3 100 -#define I_8266_DM_TM1914_3 101 -#define I_8266_BB_TM1914_3 102 +#define I_8266_U0_TM1914_3 41 +#define I_8266_U1_TM1914_3 42 +#define I_8266_DM_TM1914_3 43 +#define I_8266_BB_TM1914_3 44 //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 +#define I_8266_U0_SM16825_5 45 +#define I_8266_U1_SM16825_5 46 +#define I_8266_DM_SM16825_5 47 +#define I_8266_BB_SM16825_5 48 /*** ESP32 Neopixel methods ***/ //RGB -#define I_32_RN_NEO_3 21 -#define I_32_I0_NEO_3 22 -#define I_32_I1_NEO_3 23 +#define I_32_RN_NEO_3 1 +#define I_32_I2_NEO_3 2 //RGBW -#define I_32_RN_NEO_4 25 -#define I_32_I0_NEO_4 26 -#define I_32_I1_NEO_4 27 +#define I_32_RN_NEO_4 5 +#define I_32_I2_NEO_4 6 //400Kbps -#define I_32_RN_400_3 29 -#define I_32_I0_400_3 30 -#define I_32_I1_400_3 31 +#define I_32_RN_400_3 9 +#define I_32_I2_400_3 10 //TM1814 (RGBW) -#define I_32_RN_TM1_4 33 -#define I_32_I0_TM1_4 34 -#define I_32_I1_TM1_4 35 +#define I_32_RN_TM1_4 13 +#define I_32_I2_TM1_4 14 //TM1829 (RGB) -#define I_32_RN_TM2_3 36 -#define I_32_I0_TM2_3 37 -#define I_32_I1_TM2_3 38 +#define I_32_RN_TM2_3 17 +#define I_32_I2_TM2_3 18 //UCS8903 (RGB) -#define I_32_RN_UCS_3 57 -#define I_32_I0_UCS_3 58 -#define I_32_I1_UCS_3 59 +#define I_32_RN_UCS_3 21 +#define I_32_I2_UCS_3 22 //UCS8904 (RGBW) -#define I_32_RN_UCS_4 60 -#define I_32_I0_UCS_4 61 -#define I_32_I1_UCS_4 62 +#define I_32_RN_UCS_4 25 +#define I_32_I2_UCS_4 26 //FW1906 GRBCW -#define I_32_RN_FW6_5 63 -#define I_32_I0_FW6_5 64 -#define I_32_I1_FW6_5 65 +#define I_32_RN_FW6_5 29 +#define I_32_I2_FW6_5 30 //APA106 -#define I_32_RN_APA106_3 85 -#define I_32_I0_APA106_3 86 -#define I_32_I1_APA106_3 87 +#define I_32_RN_APA106_3 33 +#define I_32_I2_APA106_3 34 //WS2805 (RGBCW) -#define I_32_RN_2805_5 93 -#define I_32_I0_2805_5 94 -#define I_32_I1_2805_5 95 +#define I_32_RN_2805_5 37 +#define I_32_I2_2805_5 38 //TM1914 (RGB) -#define I_32_RN_TM1914_3 96 -#define I_32_I0_TM1914_3 97 -#define I_32_I1_TM1914_3 98 +#define I_32_RN_TM1914_3 41 +#define I_32_I2_TM1914_3 42 //SM16825 (RGBCW) -#define I_32_RN_SM16825_5 107 -#define I_32_I0_SM16825_5 108 -#define I_32_I1_SM16825_5 109 +#define I_32_RN_SM16825_5 45 +#define I_32_I2_SM16825_5 46 //APA102 -#define I_HS_DOT_3 39 //hardware SPI -#define I_SS_DOT_3 40 //soft SPI +#define I_HS_DOT_3 101 //hardware SPI +#define I_SS_DOT_3 102 //soft SPI //LPD8806 -#define I_HS_LPD_3 41 -#define I_SS_LPD_3 42 +#define I_HS_LPD_3 103 +#define I_SS_LPD_3 104 //WS2801 -#define I_HS_WS1_3 43 -#define I_SS_WS1_3 44 +#define I_HS_WS1_3 105 +#define I_SS_WS1_3 106 //P9813 -#define I_HS_P98_3 45 -#define I_SS_P98_3 46 +#define I_HS_P98_3 107 +#define I_SS_P98_3 108 //LPD6803 -#define I_HS_LPO_3 47 -#define I_SS_LPO_3 48 +#define I_HS_LPO_3 109 +#define I_SS_LPO_3 110 // In the following NeoGammaNullMethod can be replaced with NeoGammaWLEDMethod to perform Gamma correction implicitly @@ -230,66 +205,95 @@ /*** ESP32 Neopixel methods ***/ #ifdef ARDUINO_ARCH_ESP32 +// C3: I2S0 and I2S1 methods not supported (has one I2S bus) +// S2: I2S0 methods supported (single & parallel), I2S1 methods not supported (has one I2S bus) +// S3: I2S0 methods not supported, I2S1 supports LCD parallel methods (has two I2S buses) +// https://github.com/Makuna/NeoPixelBus/blob/b32f719e95ef3c35c46da5c99538017ef925c026/src/internal/Esp32_i2s.h#L4 +// https://github.com/Makuna/NeoPixelBus/blob/b32f719e95ef3c35c46da5c99538017ef925c026/src/internal/NeoEsp32RmtMethod.h#L857 +#if defined(CONFIG_IDF_TARGET_ESP32S3) + // S3 will always use LCD parallel output + typedef X8Ws2812xMethod X1Ws2812xMethod; + typedef X8Sk6812Method X1Sk6812Method; + typedef X8400KbpsMethod X1400KbpsMethod; + typedef X8800KbpsMethod X1800KbpsMethod; + typedef X8Tm1814Method X1Tm1814Method; + typedef X8Tm1829Method X1Tm1829Method; + typedef X8Apa106Method X1Apa106Method; + typedef X8Ws2805Method X1Ws2805Method; + typedef X8Tm1914Method X1Tm1914Method; +#elif defined(CONFIG_IDF_TARGET_ESP32S2) + // S2 will use I2S0 + typedef NeoEsp32I2s0Ws2812xMethod X1Ws2812xMethod; + typedef NeoEsp32I2s0Sk6812Method X1Sk6812Method; + typedef NeoEsp32I2s0400KbpsMethod X1400KbpsMethod; + typedef NeoEsp32I2s0800KbpsMethod X1800KbpsMethod; + typedef NeoEsp32I2s0Tm1814Method X1Tm1814Method; + typedef NeoEsp32I2s0Tm1829Method X1Tm1829Method; + typedef NeoEsp32I2s0Apa106Method X1Apa106Method; + typedef NeoEsp32I2s0Ws2805Method X1Ws2805Method; + typedef NeoEsp32I2s0Tm1914Method X1Tm1914Method; +#elif !defined(CONFIG_IDF_TARGET_ESP32C3) + // regular ESP32 will use I2S1 + typedef NeoEsp32I2s1Ws2812xMethod X1Ws2812xMethod; + typedef NeoEsp32I2s1Sk6812Method X1Sk6812Method; + typedef NeoEsp32I2s1400KbpsMethod X1400KbpsMethod; + typedef NeoEsp32I2s1800KbpsMethod X1800KbpsMethod; + typedef NeoEsp32I2s1Tm1814Method X1Tm1814Method; + typedef NeoEsp32I2s1Tm1829Method X1Tm1829Method; + typedef NeoEsp32I2s1Apa106Method X1Apa106Method; + typedef NeoEsp32I2s1Ws2805Method X1Ws2805Method; + typedef NeoEsp32I2s1Tm1914Method X1Tm1914Method; +#endif + //RGB -#define B_32_RN_NEO_3 NeoPixelBusLg -#define B_32_I0_NEO_3 NeoPixelBusLg -#define B_32_I1_NEO_3 NeoPixelBusLg -#define B_32_I1_NEO_3P NeoPixelBusLg // parallel I2S +#define B_32_RN_NEO_3 NeoPixelBusLg // ESP32, S2, S3, C3 +//#define B_32_IN_NEO_3 NeoPixelBusLg // ESP32 (dynamic I2S selection) +#define B_32_I2_NEO_3 NeoPixelBusLg // ESP32, S2, S3 (automatic I2S selection, see typedef above) +#define B_32_IP_NEO_3 NeoPixelBusLg // parallel I2S (ESP32, S2, S3) //RGBW #define B_32_RN_NEO_4 NeoPixelBusLg -#define B_32_I0_NEO_4 NeoPixelBusLg -#define B_32_I1_NEO_4 NeoPixelBusLg -#define B_32_I1_NEO_4P NeoPixelBusLg // parallel I2S +#define B_32_I2_NEO_4 NeoPixelBusLg +#define B_32_IP_NEO_4 NeoPixelBusLg // parallel I2S //400Kbps #define B_32_RN_400_3 NeoPixelBusLg -#define B_32_I0_400_3 NeoPixelBusLg -#define B_32_I1_400_3 NeoPixelBusLg -#define B_32_I1_400_3P NeoPixelBusLg // parallel I2S +#define B_32_I2_400_3 NeoPixelBusLg +#define B_32_IP_400_3 NeoPixelBusLg // parallel I2S //TM1814 (RGBW) #define B_32_RN_TM1_4 NeoPixelBusLg -#define B_32_I0_TM1_4 NeoPixelBusLg -#define B_32_I1_TM1_4 NeoPixelBusLg -#define B_32_I1_TM1_4P NeoPixelBusLg // parallel I2S +#define B_32_I2_TM1_4 NeoPixelBusLg +#define B_32_IP_TM1_4 NeoPixelBusLg // parallel I2S //TM1829 (RGB) #define B_32_RN_TM2_3 NeoPixelBusLg -#define B_32_I0_TM2_3 NeoPixelBusLg -#define B_32_I1_TM2_3 NeoPixelBusLg -#define B_32_I1_TM2_3P NeoPixelBusLg // parallel I2S +#define B_32_I2_TM2_3 NeoPixelBusLg +#define B_32_IP_TM2_3 NeoPixelBusLg // parallel I2S //UCS8903 #define B_32_RN_UCS_3 NeoPixelBusLg -#define B_32_I0_UCS_3 NeoPixelBusLg -#define B_32_I1_UCS_3 NeoPixelBusLg -#define B_32_I1_UCS_3P NeoPixelBusLg // parallel I2S +#define B_32_I2_UCS_3 NeoPixelBusLg +#define B_32_IP_UCS_3 NeoPixelBusLg // parallel I2S //UCS8904 #define B_32_RN_UCS_4 NeoPixelBusLg -#define B_32_I0_UCS_4 NeoPixelBusLg -#define B_32_I1_UCS_4 NeoPixelBusLg -#define B_32_I1_UCS_4P NeoPixelBusLg// parallel I2S +#define B_32_I2_UCS_4 NeoPixelBusLg +#define B_32_IP_UCS_4 NeoPixelBusLg// parallel I2S //APA106 #define B_32_RN_APA106_3 NeoPixelBusLg -#define B_32_I0_APA106_3 NeoPixelBusLg -#define B_32_I1_APA106_3 NeoPixelBusLg -#define B_32_I1_APA106_3P NeoPixelBusLg // parallel I2S +#define B_32_I2_APA106_3 NeoPixelBusLg +#define B_32_IP_APA106_3 NeoPixelBusLg // parallel I2S //FW1906 GRBCW #define B_32_RN_FW6_5 NeoPixelBusLg -#define B_32_I0_FW6_5 NeoPixelBusLg -#define B_32_I1_FW6_5 NeoPixelBusLg -#define B_32_I1_FW6_5P NeoPixelBusLg // parallel I2S +#define B_32_I2_FW6_5 NeoPixelBusLg +#define B_32_IP_FW6_5 NeoPixelBusLg // parallel I2S //WS2805 RGBWC #define B_32_RN_2805_5 NeoPixelBusLg -#define B_32_I0_2805_5 NeoPixelBusLg -#define B_32_I1_2805_5 NeoPixelBusLg -#define B_32_I1_2805_5P NeoPixelBusLg // parallel I2S +#define B_32_I2_2805_5 NeoPixelBusLg +#define B_32_IP_2805_5 NeoPixelBusLg // parallel I2S //TM1914 (RGB) #define B_32_RN_TM1914_3 NeoPixelBusLg -#define B_32_I0_TM1914_3 NeoPixelBusLg -#define B_32_I1_TM1914_3 NeoPixelBusLg -#define B_32_I1_TM1914_3P NeoPixelBusLg // parallel I2S +#define B_32_I2_TM1914_3 NeoPixelBusLg +#define B_32_IP_TM1914_3 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_I2_SM16825_5 NeoPixelBusLg +#define B_32_IP_SM16825_5 NeoPixelBusLg // parallel I2S #endif //APA102 @@ -436,34 +440,19 @@ class PolyBus { 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; - case I_32_I1_NEO_4: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; - case I_32_I1_400_3: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; - case I_32_I1_TM1_4: if (useParallelI2S) beginTM1814(busPtr); else beginTM1814(busPtr); break; - case I_32_I1_TM2_3: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; - case I_32_I1_UCS_3: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; - case I_32_I1_UCS_4: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; - case I_32_I1_FW6_5: if (useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; - 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 - case I_32_I0_NEO_3: (static_cast(busPtr))->Begin(); break; - case I_32_I0_NEO_4: (static_cast(busPtr))->Begin(); break; - case I_32_I0_400_3: (static_cast(busPtr))->Begin(); break; - case I_32_I0_TM1_4: beginTM1814(busPtr); break; - case I_32_I0_TM2_3: (static_cast(busPtr))->Begin(); break; - case I_32_I0_UCS_3: (static_cast(busPtr))->Begin(); break; - case I_32_I0_UCS_4: (static_cast(busPtr))->Begin(); break; - case I_32_I0_FW6_5: (static_cast(busPtr))->Begin(); break; - 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; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_NEO_4: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_400_3: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_TM1_4: if (_useParallelI2S) beginTM1814(busPtr); else beginTM1814(busPtr); break; + case I_32_I2_TM2_3: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_UCS_3: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_UCS_4: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_FW6_5: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_APA106_3: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_2805_5: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (static_cast(busPtr))->Begin(); break; + case I_32_I2_TM1914_3: if (_useParallelI2S) beginTM1914(busPtr); else beginTM1914(busPtr); break; + case I_32_I2_SM16825_5: if (_useParallelI2S) (static_cast(busPtr))->Begin(); else (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; @@ -484,8 +473,8 @@ class PolyBus { #if defined(ARDUINO_ARCH_ESP32) && !(defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3)) // NOTE: "channel" is only used on ESP32 (and its variants) for RMT channel allocation // since 0.15.0-b3 I2S1 is favoured for classic ESP32 and moved to position 0 (channel 0) so we need to subtract 1 for correct RMT allocation - if (useParallelI2S && channel > 7) channel -= 8; // accommodate parallel I2S1 which is used 1st on classic ESP32 - else if (channel > 0) channel--; // accommodate I2S1 which is used as 1st bus on classic ESP32 + if (!_useParallelI2S && channel > 0) channel--; // accommodate I2S1 which is used as 1st bus on classic ESP32 + // if user selected parallel I2S, RMT is used 1st (8 channels) followed by parallel I2S (8 channels) #endif void* busPtr = nullptr; switch (busType) { @@ -555,34 +544,19 @@ class PolyBus { 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; - case I_32_I1_NEO_4: if (useParallelI2S) busPtr = new B_32_I1_NEO_4P(len, pins[0]); else busPtr = new B_32_I1_NEO_4(len, pins[0]); break; - case I_32_I1_400_3: if (useParallelI2S) busPtr = new B_32_I1_400_3P(len, pins[0]); else busPtr = new B_32_I1_400_3(len, pins[0]); break; - case I_32_I1_TM1_4: if (useParallelI2S) busPtr = new B_32_I1_TM1_4P(len, pins[0]); else busPtr = new B_32_I1_TM1_4(len, pins[0]); break; - case I_32_I1_TM2_3: if (useParallelI2S) busPtr = new B_32_I1_TM2_3P(len, pins[0]); else busPtr = new B_32_I1_TM2_3(len, pins[0]); break; - case I_32_I1_UCS_3: if (useParallelI2S) busPtr = new B_32_I1_UCS_3P(len, pins[0]); else busPtr = new B_32_I1_UCS_3(len, pins[0]); break; - case I_32_I1_UCS_4: if (useParallelI2S) busPtr = new B_32_I1_UCS_4P(len, pins[0]); else busPtr = new B_32_I1_UCS_4(len, pins[0]); break; - case I_32_I1_APA106_3: if (useParallelI2S) busPtr = new B_32_I1_APA106_3P(len, pins[0]); else busPtr = new B_32_I1_APA106_3(len, pins[0]); break; - 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 - case I_32_I0_NEO_3: busPtr = new B_32_I0_NEO_3(len, pins[0]); break; - case I_32_I0_NEO_4: busPtr = new B_32_I0_NEO_4(len, pins[0]); break; - case I_32_I0_400_3: busPtr = new B_32_I0_400_3(len, pins[0]); break; - case I_32_I0_TM1_4: busPtr = new B_32_I0_TM1_4(len, pins[0]); break; - case I_32_I0_TM2_3: busPtr = new B_32_I0_TM2_3(len, pins[0]); break; - case I_32_I0_UCS_3: busPtr = new B_32_I0_UCS_3(len, pins[0]); break; - case I_32_I0_UCS_4: busPtr = new B_32_I0_UCS_4(len, pins[0]); break; - case I_32_I0_APA106_3: busPtr = new B_32_I0_APA106_3(len, pins[0]); break; - 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; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: if (_useParallelI2S) busPtr = new B_32_IP_NEO_3(len, pins[0]); else busPtr = new B_32_I2_NEO_3(len, pins[0]); break; + case I_32_I2_NEO_4: if (_useParallelI2S) busPtr = new B_32_IP_NEO_4(len, pins[0]); else busPtr = new B_32_I2_NEO_4(len, pins[0]); break; + case I_32_I2_400_3: if (_useParallelI2S) busPtr = new B_32_IP_400_3(len, pins[0]); else busPtr = new B_32_I2_400_3(len, pins[0]); break; + case I_32_I2_TM1_4: if (_useParallelI2S) busPtr = new B_32_IP_TM1_4(len, pins[0]); else busPtr = new B_32_I2_TM1_4(len, pins[0]); break; + case I_32_I2_TM2_3: if (_useParallelI2S) busPtr = new B_32_IP_TM2_3(len, pins[0]); else busPtr = new B_32_I2_TM2_3(len, pins[0]); break; + case I_32_I2_UCS_3: if (_useParallelI2S) busPtr = new B_32_IP_UCS_3(len, pins[0]); else busPtr = new B_32_I2_UCS_3(len, pins[0]); break; + case I_32_I2_UCS_4: if (_useParallelI2S) busPtr = new B_32_IP_UCS_4(len, pins[0]); else busPtr = new B_32_I2_UCS_4(len, pins[0]); break; + case I_32_I2_APA106_3: if (_useParallelI2S) busPtr = new B_32_IP_APA106_3(len, pins[0]); else busPtr = new B_32_I2_APA106_3(len, pins[0]); break; + case I_32_I2_FW6_5: if (_useParallelI2S) busPtr = new B_32_IP_FW6_5(len, pins[0]); else busPtr = new B_32_I2_FW6_5(len, pins[0]); break; + case I_32_I2_2805_5: if (_useParallelI2S) busPtr = new B_32_IP_2805_5(len, pins[0]); else busPtr = new B_32_I2_2805_5(len, pins[0]); break; + case I_32_I2_TM1914_3: if (_useParallelI2S) busPtr = new B_32_IP_TM1914_3(len, pins[0]); else busPtr = new B_32_I2_TM1914_3(len, pins[0]); break; + case I_32_I2_SM16825_5: if (_useParallelI2S) busPtr = new B_32_IP_SM16825_5(len, pins[0]); else busPtr = new B_32_I2_SM16825_5(len, pins[0]); break; #endif #endif // for 2-wire: pins[1] is clk, pins[0] is dat. begin expects (len, clk, dat) @@ -669,34 +643,19 @@ class PolyBus { 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; - case I_32_I1_NEO_4: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_400_3: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_TM1_4: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_TM2_3: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_UCS_3: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_UCS_4: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - case I_32_I1_APA106_3: if (useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; - 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 - case I_32_I0_NEO_3: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_NEO_4: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_400_3: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_TM1_4: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_TM2_3: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_UCS_3: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_UCS_4: (static_cast(busPtr))->Show(consistent); break; - case I_32_I0_APA106_3: (static_cast(busPtr))->Show(consistent); break; - 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; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_NEO_4: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_400_3: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_TM1_4: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_TM2_3: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_UCS_3: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_UCS_4: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_APA106_3: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_FW6_5: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_2805_5: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_TM1914_3: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; + case I_32_I2_SM16825_5: if (_useParallelI2S) (static_cast(busPtr))->Show(consistent); else (static_cast(busPtr))->Show(consistent); break; #endif #endif case I_HS_DOT_3: (static_cast(busPtr))->Show(consistent); break; @@ -743,6 +702,7 @@ class PolyBus { case I_8266_U0_UCS_4: return (static_cast(busPtr))->CanShow(); break; case I_8266_U1_UCS_4: return (static_cast(busPtr))->CanShow(); break; case I_8266_DM_UCS_4: return (static_cast(busPtr))->CanShow(); break; + case I_8266_BB_UCS_4: return (static_cast(busPtr))->CanShow(); break; case I_8266_U0_APA106_3: return (static_cast(busPtr))->CanShow(); break; case I_8266_U1_APA106_3: return (static_cast(busPtr))->CanShow(); break; case I_8266_DM_APA106_3: return (static_cast(busPtr))->CanShow(); break; @@ -779,34 +739,19 @@ class PolyBus { case I_32_RN_TM1914_3: return (static_cast(busPtr))->CanShow(); break; case I_32_RN_SM16825_5: return (static_cast(busPtr))->CanShow(); break; // I2S1 bus or paralell buses - #ifndef WLED_NO_I2S1_PIXELBUS - case I_32_I1_NEO_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_NEO_4: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_400_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_TM1_4: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_TM2_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_UCS_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_UCS_4: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_APA106_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_FW6_5: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_2805_5: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_TM1914_3: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - case I_32_I1_SM16825_5: if (useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; - #endif - // I2S0 bus - #ifndef WLED_NO_I2S0_PIXELBUS - case I_32_I0_NEO_3: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_NEO_4: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_400_3: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_TM1_4: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_TM2_3: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_UCS_3: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_UCS_4: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_APA106_3: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_FW6_5: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_2805_5: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_TM1914_3: return (static_cast(busPtr))->CanShow(); break; - case I_32_I0_SM16825_5: return (static_cast(busPtr))->CanShow(); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_NEO_4: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_400_3: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_TM1_4: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_TM2_3: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_UCS_3: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_UCS_4: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_APA106_3: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_FW6_5: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_2805_5: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_TM1914_3: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; + case I_32_I2_SM16825_5: if (_useParallelI2S) return (static_cast(busPtr))->CanShow(); else return (static_cast(busPtr))->CanShow(); break; #endif #endif case I_HS_DOT_3: return (static_cast(busPtr))->CanShow(); break; @@ -916,34 +861,19 @@ class PolyBus { 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; - case I_32_I1_NEO_4: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, col); break; - case I_32_I1_400_3: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - case I_32_I1_TM1_4: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, col); break; - case I_32_I1_TM2_3: if (useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - 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, 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 - case I_32_I0_NEO_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - case I_32_I0_NEO_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; - case I_32_I0_400_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - case I_32_I0_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; - case I_32_I0_TM2_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - case I_32_I0_UCS_3: (static_cast(busPtr))->SetPixelColor(pix, Rgb48Color(RgbColor(col))); break; - case I_32_I0_UCS_4: (static_cast(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break; - case I_32_I0_APA106_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; - 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; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_32_I2_NEO_4: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_I2_400_3: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_32_I2_TM1_4: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, col); break; + case I_32_I2_TM2_3: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_32_I2_UCS_3: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, Rgb48Color(RgbColor(col))); break; + case I_32_I2_UCS_4: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, Rgbw64Color(col)); break; + case I_32_I2_APA106_3: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_32_I2_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_I2_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_I2_TM1914_3: if (_useParallelI2S) (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); else (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; + case I_32_I2_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 #endif case I_HS_DOT_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; @@ -1027,34 +957,19 @@ class PolyBus { 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; - case I_32_I1_NEO_4: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_400_3: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_TM1_4: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_TM2_3: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_UCS_3: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_UCS_4: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I1_APA106_3: if (useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; - 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 - case I_32_I0_NEO_3: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_NEO_4: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_400_3: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_TM1_4: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_TM2_3: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_UCS_3: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_UCS_4: (static_cast(busPtr))->SetLuminance(b); break; - case I_32_I0_APA106_3: (static_cast(busPtr))->SetLuminance(b); break; - 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; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_NEO_4: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_400_3: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_TM1_4: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_TM2_3: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_UCS_3: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_UCS_4: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_APA106_3: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_FW6_5: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_2805_5: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_TM1914_3: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I2_SM16825_5: if (_useParallelI2S) (static_cast(busPtr))->SetLuminance(b); else (static_cast(busPtr))->SetLuminance(b); break; #endif #endif case I_HS_DOT_3: (static_cast(busPtr))->SetLuminance(b); break; @@ -1139,34 +1054,19 @@ class PolyBus { 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; - case I_32_I1_NEO_4: col = (useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; - 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/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 - case I_32_I0_NEO_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; - case I_32_I0_NEO_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; - 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/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 + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: col = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I2_NEO_4: col = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I2_400_3: col = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I2_TM1_4: col = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I2_TM2_3: col = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I2_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_I2_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_I2_APA106_3: col = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I2_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_I2_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_I2_TM1914_3: col = (_useParallelI2S) ? (static_cast(busPtr))->GetPixelColor(pix) : (static_cast(busPtr))->GetPixelColor(pix); break; + case I_32_I2_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 #endif case I_HS_DOT_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; @@ -1269,34 +1169,19 @@ class PolyBus { 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; - case I_32_I1_NEO_4: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_400_3: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_TM1_4: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_TM2_3: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_UCS_3: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_UCS_4: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - case I_32_I1_APA106_3: if (useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; - 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 - case I_32_I0_NEO_3: delete (static_cast(busPtr)); break; - case I_32_I0_NEO_4: delete (static_cast(busPtr)); break; - case I_32_I0_400_3: delete (static_cast(busPtr)); break; - case I_32_I0_TM1_4: delete (static_cast(busPtr)); break; - case I_32_I0_TM2_3: delete (static_cast(busPtr)); break; - case I_32_I0_UCS_3: delete (static_cast(busPtr)); break; - case I_32_I0_UCS_4: delete (static_cast(busPtr)); break; - case I_32_I0_APA106_3: delete (static_cast(busPtr)); break; - 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; + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_NEO_4: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_400_3: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_TM1_4: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_TM2_3: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_UCS_3: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_UCS_4: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_APA106_3: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_FW6_5: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_2805_5: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_TM1914_3: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; + case I_32_I2_SM16825_5: if (_useParallelI2S) delete (static_cast(busPtr)); else delete (static_cast(busPtr)); break; #endif #endif case I_HS_DOT_3: delete (static_cast(busPtr)); break; @@ -1312,8 +1197,178 @@ class PolyBus { } } + static unsigned getDataSize(void* busPtr, uint8_t busType) { + unsigned size = 0; + switch (busType) { + case I_NONE: break; + #ifdef ESP8266 + case I_8266_U0_NEO_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U1_NEO_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_DM_NEO_3: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_NEO_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U0_NEO_4: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U1_NEO_4: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_DM_NEO_4: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_NEO_4: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U0_400_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U1_400_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_DM_400_3: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_400_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U0_TM1_4: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U1_TM1_4: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_DM_TM1_4: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_TM1_4: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U0_TM2_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U1_TM2_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_DM_TM2_3: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_TM2_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U0_UCS_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U1_UCS_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_DM_UCS_3: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_UCS_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U0_UCS_4: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U1_UCS_4: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_DM_UCS_4: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_UCS_4: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U0_APA106_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U1_APA106_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_DM_APA106_3: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_APA106_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U0_FW6_5: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U1_FW6_5: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_DM_FW6_5: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_FW6_5: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U0_2805_5: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U1_2805_5: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_DM_2805_5: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_2805_5: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U0_TM1914_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U1_TM1914_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_DM_TM1914_3: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_TM1914_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U0_SM16825_5: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_U1_SM16825_5: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_8266_DM_SM16825_5: size = (static_cast(busPtr))->PixelsSize()*5; break; + case I_8266_BB_SM16825_5: size = (static_cast(busPtr))->PixelsSize()*2; break; + #endif + #ifdef ARDUINO_ARCH_ESP32 + // RMT buses (front + back + small system managed RMT) + case I_32_RN_NEO_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_NEO_4: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_400_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_TM1_4: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_TM2_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_UCS_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_UCS_4: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_APA106_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_FW6_5: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_2805_5: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_TM1914_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_32_RN_SM16825_5: size = (static_cast(busPtr))->PixelsSize()*2; break; + // I2S1 bus or paralell buses (front + DMA; DMA = front * cadence, aligned to 4 bytes) + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*4 : (static_cast(busPtr))->PixelsSize()*4; break; + case I_32_I2_NEO_4: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*4 : (static_cast(busPtr))->PixelsSize()*4; break; + case I_32_I2_400_3: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*4 : (static_cast(busPtr))->PixelsSize()*4; break; + case I_32_I2_TM1_4: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*4 : (static_cast(busPtr))->PixelsSize()*4; break; + case I_32_I2_TM2_3: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*4 : (static_cast(busPtr))->PixelsSize()*4; break; + case I_32_I2_UCS_3: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*4 : (static_cast(busPtr))->PixelsSize()*4; break; + case I_32_I2_UCS_4: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*4 : (static_cast(busPtr))->PixelsSize()*4; break; + case I_32_I2_APA106_3: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*4 : (static_cast(busPtr))->PixelsSize()*4; break; + case I_32_I2_FW6_5: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*4 : (static_cast(busPtr))->PixelsSize()*4; break; + case I_32_I2_2805_5: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*4 : (static_cast(busPtr))->PixelsSize()*4; break; + case I_32_I2_TM1914_3: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*4 : (static_cast(busPtr))->PixelsSize()*4; break; + case I_32_I2_SM16825_5: size = (_useParallelI2S) ? (static_cast(busPtr))->PixelsSize()*4 : (static_cast(busPtr))->PixelsSize()*4; break; + #endif + #endif + case I_HS_DOT_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_SS_DOT_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_HS_LPD_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_SS_LPD_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_HS_LPO_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_SS_LPO_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_HS_WS1_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_SS_WS1_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_HS_P98_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + case I_SS_P98_3: size = (static_cast(busPtr))->PixelsSize()*2; break; + } + return size; + } + + static unsigned memUsage(unsigned count, unsigned busType) { + unsigned size = count*3; // let's assume 3 channels, we will add count or 2*count below for 4 channels or 5 channels + switch (busType) { + case I_NONE: size = 0; break; + #ifdef ESP8266 + // UART methods have front + back buffers + small UART + case I_8266_U0_NEO_4: size = (size + count)*2; break; // 4 channels + case I_8266_U1_NEO_4: size = (size + count)*2; break; // 4 channels + case I_8266_BB_NEO_4: size = (size + count)*2; break; // 4 channels + case I_8266_U0_TM1_4: size = (size + count)*2; break; // 4 channels + case I_8266_U1_TM1_4: size = (size + count)*2; break; // 4 channels + case I_8266_BB_TM1_4: size = (size + count)*2; break; // 4 channels + case I_8266_U0_UCS_3: size *= 4; break; // 16 bit + case I_8266_U1_UCS_3: size *= 4; break; // 16 bit + case I_8266_BB_UCS_3: size *= 4; break; // 16 bit + case I_8266_U0_UCS_4: size = (size + count)*2*2; break; // 16 bit 4 channels + case I_8266_U1_UCS_4: size = (size + count)*2*2; break; // 16 bit 4 channels + case I_8266_BB_UCS_4: size = (size + count)*2*2; break; // 16 bit 4 channels + case I_8266_U0_FW6_5: size = (size + 2*count)*2; break; // 5 channels + case I_8266_U1_FW6_5: size = (size + 2*count)*2; break; // 5channels + case I_8266_BB_FW6_5: size = (size + 2*count)*2; break; // 5 channels + case I_8266_U0_2805_5: size = (size + 2*count)*2; break; // 5 channels + case I_8266_U1_2805_5: size = (size + 2*count)*2; break; // 5 channels + case I_8266_BB_2805_5: size = (size + 2*count)*2; break; // 5 channels + case I_8266_U0_SM16825_5: size = (size + 2*count)*2*2; break; // 16 bit 5 channels + case I_8266_U1_SM16825_5: size = (size + 2*count)*2*2; break; // 16 bit 5 channels + case I_8266_BB_SM16825_5: size = (size + 2*count)*2*2; break; // 16 bit 5 channels + // DMA methods have front + DMA buffer = ((1+(3+1)) * channels) + case I_8266_DM_NEO_3: size *= 5; break; + case I_8266_DM_NEO_4: size = (size + count)*5; break; + case I_8266_DM_400_3: size *= 5; break; + case I_8266_DM_TM1_4: size = (size + count)*5; break; + case I_8266_DM_TM2_3: size *= 5; break; + case I_8266_DM_UCS_3: size *= 2*5; break; + case I_8266_DM_UCS_4: size = (size + count)*2*5; break; + case I_8266_DM_APA106_3: size *= 5; break; + case I_8266_DM_FW6_5: size = (size + 2*count)*5; break; + case I_8266_DM_2805_5: size = (size + 2*count)*5; break; + case I_8266_DM_TM1914_3: size *= 5; break; + case I_8266_DM_SM16825_5: size = (size + 2*count)*2*5; break; + #endif + #ifdef ARDUINO_ARCH_ESP32 + // RMT buses (1x front and 1x back buffer) + case I_32_RN_NEO_4: size = (size + count)*2; break; + case I_32_RN_TM1_4: size = (size + count)*2; break; + case I_32_RN_UCS_3: size *= 2*2; break; + case I_32_RN_UCS_4: size = (size + count)*2*2; break; + case I_32_RN_FW6_5: size = (size + 2*count)*2; break; + case I_32_RN_2805_5: size = (size + 2*count)*2; break; + case I_32_RN_SM16825_5: size = (size + 2*count)*2*2; break; + // I2S1 bus or paralell buses (individual 1x front and 1 DMA (3x or 4x pixel count) or common back DMA buffers) + #ifndef CONFIG_IDF_TARGET_ESP32C3 + case I_32_I2_NEO_3: size *= 4; break; + case I_32_I2_NEO_4: size = (size + count)*4; break; + case I_32_I2_400_3: size *= 4; break; + case I_32_I2_TM1_4: size = (size + count)*4; break; + case I_32_I2_TM2_3: size *= 4; break; + case I_32_I2_UCS_3: size *= 2*4; break; + case I_32_I2_UCS_4: size = (size + count)*2*4; break; + case I_32_I2_APA106_3: size *= 4; break; + case I_32_I2_FW6_5: size = (size + 2*count)*4; break; + case I_32_I2_2805_5: size = (size + 2*count)*4; break; + case I_32_I2_TM1914_3: size *= 4; break; + case I_32_I2_SM16825_5: size = (size + 2*count)*2*4; break; + #endif + #endif + // everything else uses 2 buffers + default: size *= 2; break; + } + return size; + } + //gives back the internal type index (I_XX_XXX_X above) for the input - static uint8_t getI(uint8_t busType, uint8_t* pins, uint8_t num = 0) { + static uint8_t getI(uint8_t busType, const uint8_t* pins, uint8_t num = 0) { if (!Bus::isDigital(busType)) return I_NONE; if (Bus::is2Pin(busType)) { //SPI LED chips bool isHSPI = false; @@ -1372,26 +1427,33 @@ class PolyBus { uint8_t offset = 0; // 0 = RMT (num 1-8), 1 = I2S0 (used by Audioreactive), 2 = I2S1 #if defined(CONFIG_IDF_TARGET_ESP32S2) // ESP32-S2 only has 4 RMT channels - if (num > 4) return I_NONE; - if (num > 3) offset = 1; // only one I2S (use last to allow Audioreactive) + if (_useParallelI2S) { + if (num > 11) return I_NONE; + if (num > 3) offset = 1; // use x8 parallel I2S0 channels (use last to allow Audioreactive) + } else { + if (num > 4) return I_NONE; + if (num > 3) offset = 1; // only one I2S0 (use last to allow Audioreactive) + } #elif defined(CONFIG_IDF_TARGET_ESP32C3) // On ESP32-C3 only the first 2 RMT channels are usable for transmitting if (num > 1) return I_NONE; //if (num > 1) offset = 1; // I2S not supported yet (only 1 I2S) #elif defined(CONFIG_IDF_TARGET_ESP32S3) // On ESP32-S3 only the first 4 RMT channels are usable for transmitting - if (num > 3) return I_NONE; - //if (num > 3) offset = num -4; // I2S not supported yet + if (_useParallelI2S) { + if (num > 11) return I_NONE; + if (num > 3) offset = 1; // use x8 parallel I2S LCD channels + } else { + if (num > 3) return I_NONE; // do not use single I2S (as it is not supported) + } #else - // standard ESP32 has 8 RMT and 2 I2S channels - if (useParallelI2S) { - if (num > 16) return I_NONE; - if (num < 8) offset = 2; // prefer 8 parallel I2S1 channels - if (num == 16) offset = 1; + // standard ESP32 has 8 RMT and x1/x8 I2S1 channels + if (_useParallelI2S) { + if (num > 15) return I_NONE; + if (num > 7) offset = 1; // 8 RMT followed by 8 I2S } else { if (num > 9) return I_NONE; - if (num > 8) offset = 1; - if (num == 0) offset = 2; // prefer I2S1 for 1st bus (less flickering but more RAM needed) + if (num == 0) offset = 1; // prefer I2S1 for 1st bus (less flickering but more RAM needed) } #endif switch (busType) { diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 443f16c7..5fd06986 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -220,20 +220,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { maMax = 0; } ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh - if (fromFS) { - BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax); - if (useParallel && s < 8) { - // if for some unexplained reason the above pre-calculation was wrong, update - unsigned memT = BusManager::memUsage(bc); // includes x8 memory allocation for parallel I2S - if (memT > mem) mem = memT; // if we have unequal LED count use the largest - } else - mem += BusManager::memUsage(bc); // includes global buffer - if (mem <= MAX_LED_MEMORY) if (BusManager::add(bc) == -1) break; // finalization will be done in WLED::beginStrip() - } else { - if (busConfigs[s] != nullptr) delete busConfigs[s]; - busConfigs[s] = new BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax); - doInitBusses = true; // finalization done in beginStrip() - } + + busConfigs.push_back(std::move(BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax))); + doInitBusses = true; // finalization done in beginStrip() s++; } DEBUG_PRINTF_P(PSTR("LED buffer size: %uB\n"), mem); @@ -855,8 +844,19 @@ void serializeConfig() { JsonArray hw_led_ins = hw_led.createNestedArray("ins"); for (size_t s = 0; s < BusManager::getNumBusses(); s++) { + DEBUG_PRINTF_P(PSTR("Cfg: Saving bus #%u\n"), s); Bus *bus = BusManager::getBus(s); if (!bus || bus->getLength()==0) break; + DEBUG_PRINTF_P(PSTR(" (%d-%d, type:%d, CO:%d, rev:%d, skip:%d, AW:%d kHz:%d, mA:%d/%d)\n"), + (int)bus->getStart(), (int)(bus->getStart()+bus->getLength()), + (int)(bus->getType() & 0x7F), + (int)bus->getColorOrder(), + (int)bus->isReversed(), + (int)bus->skippedLeds(), + (int)bus->getAutoWhiteMode(), + (int)bus->getFrequency(), + (int)bus->getLEDCurrent(), (int)bus->getMaxCurrent() + ); JsonObject ins = hw_led_ins.createNestedObject(); ins["start"] = bus->getStart(); ins["len"] = bus->getLength(); diff --git a/wled00/const.h b/wled00/const.h index 3f82219d..bb4c49d7 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -49,31 +49,31 @@ #define WLED_MAX_DIGITAL_CHANNELS 3 #define WLED_MAX_ANALOG_CHANNELS 5 #define WLED_MAX_BUSSES 4 // will allow 3 digital & 1 analog RGB - #define WLED_MIN_VIRTUAL_BUSSES 2 + #define WLED_MIN_VIRTUAL_BUSSES 3 #else #define WLED_MAX_ANALOG_CHANNELS (LEDC_CHANNEL_MAX*LEDC_SPEED_MODE_MAX) #if defined(CONFIG_IDF_TARGET_ESP32C3) // 2 RMT, 6 LEDC, only has 1 I2S but NPB does not support it ATM #define WLED_MAX_BUSSES 6 // will allow 2 digital & 2 analog RGB or 6 PWM white #define WLED_MAX_DIGITAL_CHANNELS 2 //#define WLED_MAX_ANALOG_CHANNELS 6 - #define WLED_MIN_VIRTUAL_BUSSES 3 + #define WLED_MIN_VIRTUAL_BUSSES 4 #elif defined(CONFIG_IDF_TARGET_ESP32S2) // 4 RMT, 8 LEDC, only has 1 I2S bus, supported in NPB // the 5th bus (I2S) will prevent Audioreactive usermod from functioning (it is last used though) #define WLED_MAX_BUSSES 7 // will allow 5 digital & 2 analog RGB #define WLED_MAX_DIGITAL_CHANNELS 5 //#define WLED_MAX_ANALOG_CHANNELS 8 - #define WLED_MIN_VIRTUAL_BUSSES 3 - #elif defined(CONFIG_IDF_TARGET_ESP32S3) // 4 RMT, 8 LEDC, has 2 I2S but NPB does not support them ATM - #define WLED_MAX_BUSSES 6 // will allow 4 digital & 2 analog RGB - #define WLED_MAX_DIGITAL_CHANNELS 4 - //#define WLED_MAX_ANALOG_CHANNELS 8 #define WLED_MIN_VIRTUAL_BUSSES 4 + #elif defined(CONFIG_IDF_TARGET_ESP32S3) // 4 RMT, 8 LEDC, has 2 I2S but NPB supports parallel x8 LCD on I2S1 + #define WLED_MAX_BUSSES 14 // will allow 12 digital & 2 analog RGB + #define WLED_MAX_DIGITAL_CHANNELS 12 // x4 RMT + x8 I2S-LCD + //#define WLED_MAX_ANALOG_CHANNELS 8 + #define WLED_MIN_VIRTUAL_BUSSES 6 #else // the last digital bus (I2S0) will prevent Audioreactive usermod from functioning - #define WLED_MAX_BUSSES 20 // will allow 17 digital & 3 analog RGB - #define WLED_MAX_DIGITAL_CHANNELS 17 + #define WLED_MAX_BUSSES 19 // will allow 16 digital & 3 analog RGB + #define WLED_MAX_DIGITAL_CHANNELS 16 // x1/x8 I2S1 + x8 RMT //#define WLED_MAX_ANALOG_CHANNELS 16 - #define WLED_MIN_VIRTUAL_BUSSES 4 + #define WLED_MIN_VIRTUAL_BUSSES 6 #endif #endif #else diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 956cf7d9..fb0d636b 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -350,6 +350,17 @@ else LC.style.color = d.ro_gpio.some((e)=>e==parseInt(LC.value)) ? "orange" : "#fff"; } }); + const S2 = (oMaxB == 14) && (maxV == 4); + const S3 = (oMaxB == 14) && (maxV == 6); + if (oMaxB == 19 || S2 || S3) { // TODO: crude ESP32 & S2/S3 detection + if (maxLC > 300 || dC <= 2) { + d.Sf["PR"].checked = false; + gId("prl").classList.add("hide"); + } else + gId("prl").classList.remove("hide"); + maxD = (S2 || S3 ? 4 : 8) + (d.Sf["PR"].checked ? 8 : S2); // TODO: use bLimits() : 4/8RMT + (x1/x8 parallel) I2S1 + maxB = oMaxB - (d.Sf["PR"].checked ? 0 : 7 + S3); // S2 (maxV==3) does support single I2S + } // distribute ABL current if not using PPL enPPL(sDI); @@ -789,6 +800,7 @@ Swap:
Make a segment for each output:
Custom bus start indices:
Use global LED buffer:
diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index fcfa1bdc..44b09352 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -1,3 +1,4 @@ +#pragma once #ifndef WLED_FCN_DECLARE_H #define WLED_FCN_DECLARE_H diff --git a/wled00/set.cpp b/wled00/set.cpp index 27ac6b80..f81e6d70 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -139,6 +139,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) Bus::setGlobalAWMode(request->arg(F("AW")).toInt()); strip.setTargetFps(request->arg(F("FR")).toInt()); useGlobalLedBuffer = request->hasArg(F("LD")); + #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) + useParallelI2S = request->hasArg(F("PR")); + #endif bool busesChanged = false; for (int s = 0; s < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; s++) { @@ -208,8 +211,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) type |= request->hasArg(rf) << 7; // off refresh override // actual finalization is done in WLED::loop() (removing old busses and adding new) // this may happen even before this loop is finished so we do "doInitBusses" after the loop - if (busConfigs[s] != nullptr) delete busConfigs[s]; - busConfigs[s] = new(std::nothrow) BusConfig(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freq, useGlobalLedBuffer, maPerLed, maMax); + busConfigs.push_back(std::move(BusConfig(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freq, useGlobalLedBuffer, maPerLed, maMax))); busesChanged = true; } //doInitBusses = busesChanged; // we will do that below to ensure all input data is processed diff --git a/wled00/wled.h b/wled00/wled.h index b7f1ae71..fc40025d 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -398,6 +398,9 @@ WLED_GLOBAL byte bootPreset _INIT(0); // save preset to load WLED_GLOBAL bool useGlobalLedBuffer _INIT(false); // double buffering disabled on ESP8266 #else WLED_GLOBAL bool useGlobalLedBuffer _INIT(true); // double buffering enabled on ESP32 + #ifndef CONFIG_IDF_TARGET_ESP32C3 +WLED_GLOBAL bool useParallelI2S _INIT(false); // parallel I2S for ESP32 + #endif #endif #ifdef WLED_USE_IC_CCT WLED_GLOBAL bool cctICused _INIT(true); // CCT IC used (Athom 15W bulbs) diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 957ccebd..d31119d6 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -289,6 +289,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) printSetFormValue(settingsScript,PSTR("FR"),strip.getTargetFps()); printSetFormValue(settingsScript,PSTR("AW"),Bus::getGlobalAWMode()); printSetFormCheckbox(settingsScript,PSTR("LD"),useGlobalLedBuffer); + printSetFormCheckbox(settingsScript,PSTR("PR"),BusManager::hasParallelOutput()); // get it from bus manager not global variable unsigned sumMa = 0; for (int s = 0; s < BusManager::getNumBusses(); s++) { From 7daea189071098855dbc2513d9fad11fef0ff8e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sun, 19 Jan 2025 11:37:57 +0100 Subject: [PATCH 246/463] Merge fixes & updates - Segment::setName() - S2 limits - bus debug macros - remove cctBlending from strip --- wled00/FX.h | 24 +++++---- wled00/FX_fcn.cpp | 13 +++++ wled00/bus_manager.cpp | 97 +++++++++++++++-------------------- wled00/bus_manager.h | 44 ++++++++++++---- wled00/bus_wrapper.h | 11 ++-- wled00/cfg.cpp | 35 ++----------- wled00/const.h | 16 +++--- wled00/data/settings_leds.htm | 16 +++--- wled00/set.cpp | 3 +- wled00/xml.cpp | 2 +- 10 files changed, 129 insertions(+), 132 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index f54b3ba5..ab5f7f6d 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -1,3 +1,4 @@ +#pragma once /* WS2812FX.h - Library for WS2812 LED effects. Harm Aldick - 2016 @@ -8,12 +9,15 @@ Adapted from code originally licensed under the MIT license Modified for WLED + + Segment class/struct (c) 2022 Blaz Kristan (@blazoncek) */ #ifndef WS2812FX_h #define WS2812FX_h #include +#include "wled.h" #include "const.h" #include "bus_manager.h" @@ -71,18 +75,15 @@ extern byte realtimeMode; // used in getMappedPixelIndex() /* each segment uses 82 bytes of SRAM memory, so if you're application fails because of insufficient memory, decreasing MAX_NUM_SEGMENTS may help */ #ifdef ESP8266 - #define MAX_NUM_SEGMENTS 16 + #define MAX_NUM_SEGMENTS 16 /* How much data bytes all segments combined may allocate */ #define MAX_SEGMENT_DATA 5120 +#elif defined(CONFIG_IDF_TARGET_ESP32S2) + #define MAX_NUM_SEGMENTS 20 + #define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*512) // 10k by default (S2 is short on free RAM) #else - #ifndef MAX_NUM_SEGMENTS - #define MAX_NUM_SEGMENTS 32 - #endif - #if defined(ARDUINO_ARCH_ESP32S2) - #define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*768) // 24k by default (S2 is short on free RAM) - #else - #define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*1280) // 40k by default - #endif + #define MAX_NUM_SEGMENTS 32 // warning: going beyond 32 may consume too much RAM for stable operation + #define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*1280) // 40k by default #endif /* How much data bytes each segment should max allocate to leave enough space for other segments, @@ -543,6 +544,8 @@ typedef struct Segment { inline uint16_t groupLength() const { return grouping + spacing; } inline uint8_t getLightCapabilities() const { return _capabilities; } inline void deactivate() { setGeometry(0,0); } + inline Segment &clearName() { if (name) free(name); name = nullptr; return *this; } + inline Segment &setName(const String &name) { return setName(name.c_str()); } inline static unsigned getUsedSegmentData() { return Segment::_usedSegmentData; } inline static void addUsedSegmentData(int len) { Segment::_usedSegmentData += len; } @@ -565,6 +568,7 @@ typedef struct Segment { Segment &setOption(uint8_t n, bool val); Segment &setMode(uint8_t fx, bool loadDefaults = false); Segment &setPalette(uint8_t pal); + Segment &setName(const char* name); uint8_t differs(const Segment& b) const; void refreshLightCapabilities(); @@ -736,7 +740,6 @@ class WS2812FX { // 96 bytes WS2812FX() : paletteFade(0), paletteBlend(0), - cctBlending(0), now(millis()), timebase(0), isMatrix(false), @@ -839,7 +842,6 @@ class WS2812FX { // 96 bytes uint8_t paletteBlend, - cctBlending, getActiveSegmentsNum() const, getFirstSelectedSegId() const, getLastActiveSegmentId() const, diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 10bb208c..f7c1b398 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -613,6 +613,19 @@ Segment &Segment::setPalette(uint8_t pal) { return *this; } +Segment &Segment::setName(const char *newName) { + if (newName) { + const int newLen = min(strlen(newName), (size_t)WLED_MAX_SEGNAME_LEN); + if (newLen) { + if (name) name = static_cast(realloc(name, newLen+1)); + else name = static_cast(malloc(newLen+1)); + if (name) strlcpy(name, newName, newLen); + return *this; + } + } + return clearName(); +} + // 2D matrix unsigned Segment::virtualWidth() const { unsigned groupLen = groupLength(); diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index c63ff779..6fcb5562 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -18,10 +18,11 @@ #endif #include "const.h" #include "pin_manager.h" -#include "bus_wrapper.h" #include "bus_manager.h" +#include "bus_wrapper.h" extern bool cctICused; +extern bool useParallelI2S; //colors.cpp uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb); @@ -29,28 +30,6 @@ uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb); //udp.cpp uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, const uint8_t* buffer, uint8_t bri=255, bool isRGBW=false); -// enable additional debug output -#if defined(WLED_DEBUG_HOST) - #include "net_debug.h" - #define DEBUGOUT NetDebug -#else - #define DEBUGOUT Serial -#endif - -#ifdef WLED_DEBUG - #ifndef ESP8266 - #include - #endif - #define DEBUG_PRINT(x) DEBUGOUT.print(x) - #define DEBUG_PRINTLN(x) DEBUGOUT.println(x) - #define DEBUG_PRINTF(x...) DEBUGOUT.printf(x) - #define DEBUG_PRINTF_P(x...) DEBUGOUT.printf_P(x) -#else - #define DEBUG_PRINT(x) - #define DEBUG_PRINTLN(x) - #define DEBUG_PRINTF(x...) - #define DEBUG_PRINTF_P(x...) -#endif //color mangling macros #define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b)))) @@ -63,6 +42,7 @@ uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, const bool ColorOrderMap::add(uint16_t start, uint16_t len, uint8_t colorOrder) { if (count() >= WLED_MAX_COLOR_ORDER_MAPPINGS || len == 0 || (colorOrder & 0x0F) > COL_ORDER_MAX) return false; // upper nibble contains W swap information _mappings.push_back({start,len,colorOrder}); + DEBUGBUS_PRINTF_P(PSTR("Bus: Add COM (%d,%d,%d)\n"), (int)start, (int)len, (int)colorOrder); return true; } @@ -116,7 +96,7 @@ uint32_t Bus::autoWhiteCalc(uint32_t c) const { } uint8_t *Bus::allocateData(size_t size) { - if (_data) free(_data); // should not happen, but for safety + freeData(); // should not happen, but for safety return _data = (uint8_t *)(size>0 ? calloc(size, sizeof(uint8_t)) : nullptr); } @@ -134,32 +114,32 @@ BusDigital::BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com , _milliAmpsMax(bc.milliAmpsMax) , _colorOrderMap(com) { - DEBUG_PRINTLN(F("Bus: Creating digital bus.")); - if (!isDigital(bc.type) || !bc.count) { DEBUG_PRINTLN(F("Not digial or empty bus!")); return; } - if (!PinManager::allocatePin(bc.pins[0], true, PinOwner::BusDigital)) { DEBUG_PRINTLN(F("Pin 0 allocated!")); return; } + DEBUGBUS_PRINTLN(F("Bus: Creating digital bus.")); + if (!isDigital(bc.type) || !bc.count) { DEBUGBUS_PRINTLN(F("Not digial or empty bus!")); return; } + if (!PinManager::allocatePin(bc.pins[0], true, PinOwner::BusDigital)) { DEBUGBUS_PRINTLN(F("Pin 0 allocated!")); return; } _frequencykHz = 0U; _pins[0] = bc.pins[0]; if (is2Pin(bc.type)) { if (!PinManager::allocatePin(bc.pins[1], true, PinOwner::BusDigital)) { cleanup(); - DEBUG_PRINTLN(F("Pin 1 allocated!")); + DEBUGBUS_PRINTLN(F("Pin 1 allocated!")); return; } _pins[1] = bc.pins[1]; _frequencykHz = bc.frequency ? bc.frequency : 2000U; // 2MHz clock if undefined } _iType = PolyBus::getI(bc.type, _pins, nr); - if (_iType == I_NONE) { DEBUG_PRINTLN(F("Incorrect iType!")); return; } + if (_iType == I_NONE) { DEBUGBUS_PRINTLN(F("Incorrect iType!")); return; } _hasRgb = hasRGB(bc.type); _hasWhite = hasWhite(bc.type); _hasCCT = hasCCT(bc.type); - if (bc.doubleBuffer && !allocateData(bc.count * Bus::getNumberOfChannels(bc.type))) { DEBUG_PRINTLN(F("Buffer allocation failed!")); return; } + if (bc.doubleBuffer && !allocateData(bc.count * Bus::getNumberOfChannels(bc.type))) { DEBUGBUS_PRINTLN(F("Buffer allocation failed!")); return; } //_buffering = bc.doubleBuffer; uint16_t lenToCreate = bc.count; if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(bc.count); // only needs a third of "RGB" LEDs for NeoPixelBus _busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr); _valid = (_busPtr != nullptr); - DEBUG_PRINTF_P(PSTR("Bus: %successfully inited #%u (len:%u, type:%u (RGB:%d, W:%d, CCT:%d), pins:%u,%u [itype:%u] mA=%d/%d)\n"), + DEBUGBUS_PRINTF_P(PSTR("Bus: %successfully inited #%u (len:%u, type:%u (RGB:%d, W:%d, CCT:%d), pins:%u,%u [itype:%u] mA=%d/%d)\n"), _valid?"S":"Uns", (int)nr, (int)bc.count, @@ -261,6 +241,7 @@ void BusDigital::show() { // TODO: there is an issue if CCT is calculated from RGB value (_cct==-1), we cannot do that with double buffer Bus::_cct = _data[offset+channels-1]; Bus::calculateCCT(c, cctWW, cctCW); + if (_type == TYPE_WS2812_WWA) c = RGBW32(cctWW, cctCW, 0, W(c)); } unsigned pix = i; if (_reversed) pix = _len - pix -1; @@ -346,8 +327,8 @@ void IRAM_ATTR BusDigital::setPixelColor(unsigned pix, uint32_t c) { uint8_t cctWW = 0, cctCW = 0; Bus::calculateCCT(c, cctWW, cctCW); wwcw = (cctCW<<8) | cctWW; + if (_type == TYPE_WS2812_WWA) c = RGBW32(cctWW, cctCW, 0, W(c)); } - PolyBus::setPixelColor(_busPtr, _iType, pix, c, co, wwcw); } } @@ -379,11 +360,15 @@ uint32_t IRAM_ATTR BusDigital::getPixelColor(unsigned pix) const { case 2: c = RGBW32(b, b, b, b); break; } } + if (_type == TYPE_WS2812_WWA) { + uint8_t w = R(c) | G(c); + c = RGBW32(w, w, 0, w); + } return c; } } -uint8_t BusDigital::getPins(uint8_t* pinArray) const { +unsigned BusDigital::getPins(uint8_t* pinArray) const { unsigned numPins = is2Pin(_type) + 1; if (pinArray) for (unsigned i = 0; i < numPins; i++) pinArray[i] = _pins[i]; return numPins; @@ -431,7 +416,7 @@ void BusDigital::begin() { } void BusDigital::cleanup() { - DEBUG_PRINTLN(F("Digital Cleanup.")); + DEBUGBUS_PRINTLN(F("Digital Cleanup.")); PolyBus::cleanup(_busPtr, _iType); _iType = I_NONE; _valid = false; @@ -514,7 +499,7 @@ BusPwm::BusPwm(const BusConfig &bc) _hasCCT = hasCCT(bc.type); _data = _pwmdata; // avoid malloc() and use already allocated memory _valid = true; - 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]); + DEBUGBUS_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(unsigned pix, uint32_t c) { @@ -630,7 +615,7 @@ void BusPwm::show() { } } -uint8_t BusPwm::getPins(uint8_t* pinArray) const { +unsigned BusPwm::getPins(uint8_t* pinArray) const { if (!_valid) return 0; unsigned numPins = numPWMPins(_type); if (pinArray) for (unsigned i = 0; i < numPins; i++) pinArray[i] = _pins[i]; @@ -683,7 +668,7 @@ BusOnOff::BusOnOff(const BusConfig &bc) _hasCCT = false; _data = &_onoffdata; // avoid malloc() and use stack _valid = true; - DEBUG_PRINTF_P(PSTR("%successfully inited On/Off strip with pin %u\n"), _valid?"S":"Uns", _pin); + DEBUGBUS_PRINTF_P(PSTR("%successfully inited On/Off strip with pin %u\n"), _valid?"S":"Uns", _pin); } void BusOnOff::setPixelColor(unsigned pix, uint32_t c) { @@ -706,7 +691,7 @@ void BusOnOff::show() { digitalWrite(_pin, _reversed ? !(bool)_data[0] : (bool)_data[0]); } -uint8_t BusOnOff::getPins(uint8_t* pinArray) const { +unsigned BusOnOff::getPins(uint8_t* pinArray) const { if (!_valid) return 0; if (pinArray) pinArray[0] = _pin; return 1; @@ -743,7 +728,7 @@ BusNetwork::BusNetwork(const BusConfig &bc) _UDPchannels = _hasWhite + 3; _client = IPAddress(bc.pins[0],bc.pins[1],bc.pins[2],bc.pins[3]); _valid = (allocateData(_len * _UDPchannels) != nullptr); - DEBUG_PRINTF_P(PSTR("%successfully inited virtual strip with type %u and IP %u.%u.%u.%u\n"), _valid?"S":"Uns", bc.type, bc.pins[0], bc.pins[1], bc.pins[2], bc.pins[3]); + DEBUGBUS_PRINTF_P(PSTR("%successfully inited virtual strip with type %u and IP %u.%u.%u.%u\n"), _valid?"S":"Uns", bc.type, bc.pins[0], bc.pins[1], bc.pins[2], bc.pins[3]); } void BusNetwork::setPixelColor(unsigned pix, uint32_t c) { @@ -770,7 +755,7 @@ void BusNetwork::show() { _broadcastLock = false; } -uint8_t BusNetwork::getPins(uint8_t* pinArray) const { +unsigned BusNetwork::getPins(uint8_t* pinArray) const { if (pinArray) for (unsigned i = 0; i < 4; i++) pinArray[i] = _client[i]; return 4; } @@ -791,7 +776,7 @@ std::vector BusNetwork::getLEDTypes() { } void BusNetwork::cleanup() { - DEBUG_PRINTLN(F("Virtual Cleanup.")); + DEBUGBUS_PRINTLN(F("Virtual Cleanup.")); _type = I_NONE; _valid = false; freeData(); @@ -826,7 +811,6 @@ unsigned BusManager::memUsage() { #endif #endif for (const auto &bus : busses) { - //for (unsigned i=0; igetBusSize(); #if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(ESP8266) if (bus->isDigital() && !bus->is2Pin()) digitalCount++; @@ -842,18 +826,18 @@ unsigned BusManager::memUsage() { } int BusManager::add(const BusConfig &bc) { - DEBUG_PRINTF_P(PSTR("Bus: Adding bus #%d (%d - %d >= %d)\n"), numBusses, getNumBusses(), getNumVirtualBusses(), WLED_MAX_BUSSES); + DEBUGBUS_PRINTF_P(PSTR("Bus: Adding bus #%d (%d - %d >= %d)\n"), busses.size(), getNumBusses(), getNumVirtualBusses(), WLED_MAX_BUSSES); if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1; if (Bus::isVirtual(bc.type)) { busses.push_back(new BusNetwork(bc)); } else if (Bus::isDigital(bc.type)) { - busses.push_back(new BusDigital(bc, numBusses, colorOrderMap)); + busses.push_back(new BusDigital(bc, busses.size(), colorOrderMap)); } else if (Bus::isOnOff(bc.type)) { busses.push_back(new BusOnOff(bc)); } else { busses.push_back(new BusPwm(bc)); } - return numBusses++; + return busses.size(); } // credit @willmmiles @@ -882,19 +866,21 @@ String BusManager::getLEDTypesJSONString() { } void BusManager::useParallelOutput() { - DEBUG_PRINTLN(F("Bus: Enabling parallel I2S.")); + DEBUGBUS_PRINTLN(F("Bus: Enabling parallel I2S.")); PolyBus::setParallelI2S1Output(); } +bool BusManager::hasParallelOutput() { + return PolyBus::isParallelI2S1Output(); +} + //do not call this method from system context (network callback) void BusManager::removeAll() { - DEBUG_PRINTLN(F("Removing all.")); + DEBUGBUS_PRINTLN(F("Removing all.")); //prevents crashes due to deleting busses while in use. while (!canAllShow()) yield(); for (auto &bus : busses) delete bus; busses.clear(); - numBusses = 0; - _parallelOutputs = 1; PolyBus::setParallelI2S1Output(false); } @@ -905,7 +891,7 @@ void BusManager::removeAll() { void BusManager::esp32RMTInvertIdle() { bool idle_out; unsigned rmt = 0; - for (unsigned u = 0; u < numBusses(); u++) { + for (unsigned u = 0; u < busses.size(); u++) { #if defined(CONFIG_IDF_TARGET_ESP32C3) // 2 RMT, only has 1 I2S but NPB does not support it ATM if (u > 1) return; rmt = u; @@ -916,9 +902,10 @@ void BusManager::esp32RMTInvertIdle() { if (u > 3) return; rmt = u; #else - if (u < _parallelOutputs) continue; - if (u >= _parallelOutputs + 8) return; // only 8 RMT channels - rmt = u - _parallelOutputs; + unsigned numI2S = 1 + PolyBus::isParallelI2S1Output()*7; + if (u < numI2S) continue; + if (u >= numI2S + 8) return; // only 8 RMT channels + rmt = u - numI2S; #endif if (busses[u]->getLength()==0 || !busses[u]->isDigital() || busses[u]->is2Pin()) continue; //assumes that bus number to rmt channel mapping stays 1:1 @@ -1028,7 +1015,7 @@ uint16_t BusManager::getTotalLength() { return len; } -bool PolyBus::useParallelI2S = false; +bool PolyBus::_useParallelI2S = false; // Bus static member definition int16_t Bus::_cct = -1; @@ -1037,9 +1024,7 @@ uint8_t Bus::_gAWM = 255; uint16_t BusDigital::_milliAmpsTotal = 0; -uint8_t BusManager::numBusses = 0; std::vector BusManager::busses; ColorOrderMap BusManager::colorOrderMap = {}; uint16_t BusManager::_milliAmpsUsed = 0; uint16_t BusManager::_milliAmpsMax = ABL_MILLIAMPS_DEFAULT; -uint8_t BusManager::_parallelOutputs = 1; diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 3692751c..162fefe2 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -10,6 +10,29 @@ #include "pin_manager.h" #include +// enable additional debug output +#if defined(WLED_DEBUG_HOST) + #include "net_debug.h" + #define DEBUGOUT NetDebug +#else + #define DEBUGOUT Serial +#endif + +#ifdef WLED_DEBUG_BUS + #ifndef ESP8266 + #include + #endif + #define DEBUGBUS_PRINT(x) DEBUGOUT.print(x) + #define DEBUGBUS_PRINTLN(x) DEBUGOUT.println(x) + #define DEBUGBUS_PRINTF(x...) DEBUGOUT.printf(x) + #define DEBUGBUS_PRINTF_P(x...) DEBUGOUT.printf_P(x) +#else + #define DEBUGBUS_PRINT(x) + #define DEBUGBUS_PRINTLN(x) + #define DEBUGBUS_PRINTF(x...) + #define DEBUGBUS_PRINTF_P(x...) +#endif + //colors.cpp uint16_t approximateKelvinFromRGB(uint32_t rgb); @@ -113,7 +136,7 @@ class Bus { inline void setStart(uint16_t start) { _start = start; } inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; } inline uint8_t getAutoWhiteMode() const { return _autoWhiteMode; } - inline uint32_t getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); } + inline unsigned getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); } inline uint16_t getStart() const { return _start; } inline uint8_t getType() const { return _type; } inline bool isOk() const { return _valid; } @@ -122,8 +145,8 @@ class Bus { inline bool containsPixel(uint16_t pix) const { return pix >= _start && pix < _start + _len; } static inline std::vector getLEDTypes() { return {{TYPE_NONE, "", PSTR("None")}}; } // not used. just for reference for derived classes - static constexpr uint32_t getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK - static constexpr uint32_t getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); } + static constexpr unsigned getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK + static constexpr unsigned getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); } static constexpr bool hasRGB(uint8_t type) { return !((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_ANALOG_1CH || type == TYPE_ANALOG_2CH || type == TYPE_ONOFF); } @@ -155,7 +178,7 @@ class Bus { static inline uint8_t getGlobalAWMode() { return _gAWM; } static inline void setCCT(int16_t cct) { _cct = cct; } static inline uint8_t getCCTBlend() { return _cctBlend; } - static inline void setCCTBlend(uint8_t b) { + static inline void setCCTBlend(uint8_t b) { _cctBlend = (std::min((int)b,100) * 127) / 100; //compile-time limiter for hardware that can't power both white channels at max #ifdef WLED_MAX_CCT_BLEND @@ -211,8 +234,8 @@ class BusDigital : public Bus { void setColorOrder(uint8_t colorOrder) override; [[gnu::hot]] uint32_t getPixelColor(unsigned pix) const override; uint8_t getColorOrder() const override { return _colorOrder; } - uint8_t getPins(uint8_t* pinArray = nullptr) const override; - uint8_t skippedLeds() const override { return _skip; } + unsigned getPins(uint8_t* pinArray = nullptr) const override; + unsigned skippedLeds() const override { return _skip; } uint16_t getFrequency() const override { return _frequencykHz; } uint16_t getLEDCurrent() const override { return _milliAmpsPerLed; } uint16_t getUsedCurrent() const override { return _milliAmpsTotal; } @@ -258,7 +281,7 @@ class BusPwm : public Bus { void setPixelColor(unsigned pix, uint32_t c) override; uint32_t getPixelColor(unsigned pix) const override; //does no index check - uint8_t getPins(uint8_t* pinArray = nullptr) const override; + unsigned getPins(uint8_t* pinArray = nullptr) const override; uint16_t getFrequency() const override { return _frequency; } unsigned getBusSize() const override { return sizeof(BusPwm); } void show() override; @@ -354,7 +377,7 @@ struct BusConfig { type = busType & 0x7F; // bit 7 may be/is hacked to include refresh info (1=refresh in off state, 0=no refresh) size_t nPins = Bus::getNumberOfPins(type); for (size_t i = 0; i < nPins; i++) pins[i] = ppins[i]; - DEBUG_PRINTF_P(PSTR("Bus: Config (%d-%d, type:%d, CO:%d, rev:%d, skip:%d, AW:%d kHz:%d, mA:%d/%d)\n"), + DEBUGBUS_PRINTF_P(PSTR("Bus: Config (%d-%d, type:%d, CO:%d, rev:%d, skip:%d, AW:%d kHz:%d, mA:%d/%d)\n"), (int)start, (int)(start+len), (int)type, (int)colorOrder, @@ -402,6 +425,7 @@ class BusManager { static int add(const BusConfig &bc); static void useParallelOutput(); // workaround for inaccessible PolyBus + static bool hasParallelOutput(); // workaround for inaccessible PolyBus //do not call this method from system context (network callback) static void removeAll(); @@ -425,18 +449,16 @@ class BusManager { //semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit()) static uint16_t getTotalLength(); - static inline uint8_t getNumBusses() { return numBusses; } + static inline uint8_t getNumBusses() { return busses.size(); } static String getLEDTypesJSONString(); static inline ColorOrderMap& getColorOrderMap() { return colorOrderMap; } private: - static uint8_t numBusses; static std::vector busses; static ColorOrderMap colorOrderMap; static uint16_t _milliAmpsUsed; static uint16_t _milliAmpsMax; - static uint8_t _parallelOutputs; #ifdef ESP32_DATA_IDLE_HIGH static void esp32RMTInvertIdle() ; diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index 24ffe9c5..577aaeb8 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -4,7 +4,6 @@ //#define NPB_CONF_4STEP_CADENCE #include "NeoPixelBusLg.h" -#include "bus_manager.h" //Hardware SPI Pins #define P_8266_HS_MOSI 13 @@ -332,11 +331,11 @@ //handles pointer type conversion for all possible bus types class PolyBus { private: - static bool useParallelI2S; + static bool _useParallelI2S; public: - static inline void setParallelI2S1Output(bool b = true) { useParallelI2S = b; } - static inline bool isParallelI2S1Output(void) { return useParallelI2S; } + static inline void setParallelI2S1Output(bool b = true) { _useParallelI2S = b; } + static inline bool isParallelI2S1Output(void) { return _useParallelI2S; } // initialize SPI bus speed for DotStar methods template @@ -768,7 +767,7 @@ class PolyBus { return true; } - static void setPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint32_t c, uint8_t co, uint16_t wwcw = 0) { + [[gnu::hot]] static void setPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint32_t c, uint8_t co, uint16_t wwcw = 0) { uint8_t r = c >> 16; uint8_t g = c >> 8; uint8_t b = c >> 0; @@ -985,7 +984,7 @@ class PolyBus { } } - static uint32_t getPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint8_t co) { + [[gnu::hot]] static uint32_t getPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint8_t co) { RgbwColor col(0,0,0,0); switch (busType) { case I_NONE: break; diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 5fd06986..b973e361 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -114,8 +114,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { 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); + int cctBlending = 0; + CJSON(cctBlending, hw_led[F("cb")]); + Bus::setCCTBlend(cctBlending); strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS CJSON(useGlobalLedBuffer, hw_led[F("ld")]); @@ -162,34 +163,6 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { DEBUG_PRINTF_P(PSTR("Heap before buses: %d\n"), ESP.getFreeHeap()); int s = 0; // bus iterator if (fromFS) BusManager::removeAll(); // can't safely manipulate busses directly in network callback - unsigned mem = 0; - - // determine if it is sensible to use parallel I2S outputs on ESP32 (i.e. more than 5 outputs = 1 I2S + 4 RMT) - bool useParallel = false; - #if defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ARCH_ESP32S2) && !defined(ARDUINO_ARCH_ESP32S3) && !defined(ARDUINO_ARCH_ESP32C3) - unsigned digitalCount = 0; - unsigned maxLedsOnBus = 0; - unsigned maxChannels = 0; - for (JsonObject elm : ins) { - unsigned type = elm["type"] | TYPE_WS2812_RGB; - unsigned len = elm["len"] | DEFAULT_LED_COUNT; - if (!Bus::isDigital(type)) continue; - if (!Bus::is2Pin(type)) { - digitalCount++; - unsigned channels = Bus::getNumberOfChannels(type); - if (len > maxLedsOnBus) maxLedsOnBus = len; - if (channels > maxChannels) maxChannels = channels; - } - } - DEBUG_PRINTF_P(PSTR("Maximum LEDs on a bus: %u\nDigital buses: %u\n"), maxLedsOnBus, digitalCount); - // we may remove 300 LEDs per bus limit when NeoPixelBus is updated beyond 2.9.0 - if (maxLedsOnBus <= 300 && digitalCount > 5) { - DEBUG_PRINTLN(F("Switching to parallel I2S.")); - useParallel = true; - BusManager::useParallelOutput(); - mem = BusManager::memUsage(maxChannels, maxLedsOnBus, 8); // use alternate memory calculation - } - #endif for (JsonObject elm : ins) { if (s >= WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES) break; @@ -816,7 +789,7 @@ void serializeConfig() { hw_led["cct"] = strip.correctWB; hw_led[F("cr")] = strip.cctFromRgb; hw_led[F("ic")] = cctICused; - hw_led[F("cb")] = strip.cctBlending; + hw_led[F("cb")] = Bus::getCCTBlend(); hw_led["fps"] = strip.getTargetFps(); hw_led[F("rgbwm")] = Bus::getGlobalAWMode(); // global auto white mode override hw_led[F("ld")] = useGlobalLedBuffer; diff --git a/wled00/const.h b/wled00/const.h index bb4c49d7..1b419d4b 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -37,7 +37,7 @@ #endif #ifndef WLED_MAX_USERMODS - #ifdef ESP8266 + #if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32S2) #define WLED_MAX_USERMODS 4 #else #define WLED_MAX_USERMODS 6 @@ -59,8 +59,8 @@ #define WLED_MIN_VIRTUAL_BUSSES 4 #elif defined(CONFIG_IDF_TARGET_ESP32S2) // 4 RMT, 8 LEDC, only has 1 I2S bus, supported in NPB // the 5th bus (I2S) will prevent Audioreactive usermod from functioning (it is last used though) - #define WLED_MAX_BUSSES 7 // will allow 5 digital & 2 analog RGB - #define WLED_MAX_DIGITAL_CHANNELS 5 + #define WLED_MAX_BUSSES 14 // will allow 12 digital & 2 analog RGB + #define WLED_MAX_DIGITAL_CHANNELS 12 // x4 RMT + x1/x8 I2S0 //#define WLED_MAX_ANALOG_CHANNELS 8 #define WLED_MIN_VIRTUAL_BUSSES 4 #elif defined(CONFIG_IDF_TARGET_ESP32S3) // 4 RMT, 8 LEDC, has 2 I2S but NPB supports parallel x8 LCD on I2S1 @@ -115,7 +115,7 @@ #endif #endif -#ifdef ESP8266 +#if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32S2) #define WLED_MAX_COLOR_ORDER_MAPPINGS 5 #else #define WLED_MAX_COLOR_ORDER_MAPPINGS 10 @@ -125,7 +125,7 @@ #undef WLED_MAX_LEDMAPS #endif #ifndef WLED_MAX_LEDMAPS - #ifdef ESP8266 + #if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32S2) #define WLED_MAX_LEDMAPS 10 #else #define WLED_MAX_LEDMAPS 16 @@ -476,6 +476,8 @@ #ifndef MAX_LEDS #ifdef ESP8266 #define MAX_LEDS 1664 //can't rely on memory limit to limit this to 1600 LEDs +#elif defined(CONFIG_IDF_TARGET_ESP32S2) +#define MAX_LEDS 2048 //due to memory constraints #else #define MAX_LEDS 8192 #endif @@ -485,7 +487,9 @@ #ifdef ESP8266 #define MAX_LED_MEMORY 4000 #else - #if defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32C3) + #if defined(ARDUINO_ARCH_ESP32S2) + #define MAX_LED_MEMORY 16000 + #elif defined(ARDUINO_ARCH_ESP32C3) #define MAX_LED_MEMORY 32000 #else #define MAX_LED_MEMORY 64000 diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index fb0d636b..5301c8e1 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -42,10 +42,10 @@ if (loc) d.Sf.action = getURL('/settings/leds'); } function bLimits(b,v,p,m,l,o=5,d=2,a=6) { - oMaxB = maxB = b; // maxB - max buses (can be changed if using ESP32 parallel I2S) - maxD = d; // maxD - max digital channels (can be changed if using ESP32 parallel I2S) - maxA = a; // maxA - max analog channels - maxV = v; // maxV - min virtual buses + oMaxB = maxB = b; // maxB - max buses (can be changed if using ESP32 parallel I2S): 19 - ESP32, 14 - S3/S2, 6 - C3, 4 - 8266 + maxD = d; // maxD - max digital channels (can be changed if using ESP32 parallel I2S): 16 - ESP32, 12 - S3/S2, 2 - C3, 3 - 8266 + maxA = a; // maxA - max analog channels: 16 - ESP32, 8 - S3/S2, 6 - C3, 5 - 8266 + maxV = v; // maxV - min virtual buses: 4 - ESP32/S3, 3 - S2/C3, 2 - ESP8266 maxPB = p; // maxPB - max LEDs per bus maxM = m; // maxM - max LED memory maxL = l; // maxL - max LEDs (will serve to determine ESP >1664 == ESP32) @@ -250,6 +250,7 @@ } // enable/disable LED fields + let dC = 0; // count of digital buses (for parallel I2S) let LTs = d.Sf.querySelectorAll("#mLC select[name^=LT]"); LTs.forEach((s,i)=>{ if (i < LTs.length-1) s.disabled = true; // prevent changing type (as we can't update options) @@ -257,6 +258,7 @@ var n = s.name.substring(2); var t = parseInt(s.value); memu += getMem(t, n); // calc memory + dC += (isDig(t) && !isD2P(t)); setPinConfig(n,t); gId("abl"+n).style.display = (!abl || !isDig(t)) ? "none" : "inline"; // show/hide individual ABL settings if (change) { // did we change LED type? @@ -295,8 +297,7 @@ // do we have a led count field if (nm=="LC") { let c = parseInt(LC.value,10); //get LED count - if (c > 300 && i < 8) maxB = oMaxB - Math.max(maxD-7,0); //TODO: hard limit for buses when using ESP32 parallel I2S - if (!customStarts || !startsDirty[n]) gId("ls"+n).value=sLC; //update start value + if (!customStarts || !startsDirty[n]) gId("ls"+n).value = sLC; //update start value gId("ls"+n).disabled = !customStarts; //enable/disable field editing if (c) { let s = parseInt(gId("ls"+n).value); //start value @@ -481,14 +482,13 @@ mA/LED:

From a778ff01f613a92974ba04447adaa0e2490d7e6b Mon Sep 17 00:00:00 2001 From: "Christian W. Zuckschwerdt" Date: Fri, 24 Jan 2025 23:17:01 +0100 Subject: [PATCH 268/463] Nightly release - Add bin.gz artifacts --- .github/workflows/nightly.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 13873005..a5c80f22 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -37,4 +37,5 @@ jobs: prerelease: true body: ${{ steps.changelog.outputs.changelog }} files: | - ./*.bin \ No newline at end of file + *.bin + *.bin.gz From e27fa882fab85320feec437047a66918dd1bb488 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sun, 26 Jan 2025 16:12:08 +0000 Subject: [PATCH 269/463] Move CONFIG_ASYNC_TCP_USE_WDT=0 to new esp32_all_variants --- platformio.ini | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/platformio.ini b/platformio.ini index 56dd2537..e775c61f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -244,6 +244,7 @@ lib_deps = bitbank2/AnimatedGIF@^1.4.7 https://github.com/Aircoookie/GifDecoder#bc3af18 build_flags = + -D CONFIG_ASYNC_TCP_USE_WDT=0 -D WLED_ENABLE_GIF [esp32] @@ -254,7 +255,6 @@ build_unflags = ${common.build_unflags} build_flags = -g -DARDUINO_ARCH_ESP32 #-DCONFIG_LITTLEFS_FOR_IDF_3_2 - -D CONFIG_ASYNC_TCP_USE_WDT=0 #use LITTLEFS library by lorol in ESP32 core 1.x.x instead of built-in in 2.x.x -D LOROL_LITTLEFS ; -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3 @@ -289,7 +289,6 @@ build_unflags = ${common.build_unflags} build_flags = -g -Wshadow=compatible-local ;; emit warning in case a local variable "shadows" another local one -DARDUINO_ARCH_ESP32 -DESP32 - -D CONFIG_ASYNC_TCP_USE_WDT=0 -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3 ${esp32_all_variants.build_flags} -D WLED_ENABLE_DMX_INPUT @@ -307,7 +306,6 @@ build_flags = -g -DARDUINO_ARCH_ESP32 -DARDUINO_ARCH_ESP32S2 -DCONFIG_IDF_TARGET_ESP32S2=1 - -D CONFIG_ASYNC_TCP_USE_WDT=0 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 -DCO -DARDUINO_USB_MODE=0 ;; this flag is mandatory for ESP32-S2 ! @@ -327,7 +325,6 @@ build_flags = -g -DARDUINO_ARCH_ESP32 -DARDUINO_ARCH_ESP32C3 -DCONFIG_IDF_TARGET_ESP32C3=1 - -D CONFIG_ASYNC_TCP_USE_WDT=0 -DCO -DARDUINO_USB_MODE=1 ;; this flag is mandatory for ESP32-C3 ;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry: @@ -348,7 +345,6 @@ build_flags = -g -DARDUINO_ARCH_ESP32 -DARDUINO_ARCH_ESP32S3 -DCONFIG_IDF_TARGET_ESP32S3=1 - -D CONFIG_ASYNC_TCP_USE_WDT=0 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_DFU_ON_BOOT=0 -DCO ;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry: @@ -646,7 +642,6 @@ build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME= -DBOARD_HAS_PSRAM -DLOLIN_WIFI_FIX ; seems to work much better with this -D WLED_WATCHDOG_TIMEOUT=0 - -D CONFIG_ASYNC_TCP_USE_WDT=0 -D DATA_PINS=16 -D HW_PIN_SCL=35 -D HW_PIN_SDA=33 From 1e1ba9afa31642bebd742238ee3f118a44a2b52f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Mon, 27 Jan 2025 21:19:22 +0100 Subject: [PATCH 270/463] Fix for aircoookie/WLED#4519 - added JSON handling for irApplyToAllSelected --- wled00/ir.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/wled00/ir.cpp b/wled00/ir.cpp index f01e2c32..5e633d08 100644 --- a/wled00/ir.cpp +++ b/wled00/ir.cpp @@ -611,9 +611,15 @@ static void decodeIRJson(uint32_t code) handleSet(nullptr, cmdStr, false); // no stateUpdated() call here } } else { - // command is JSON object (TODO: currently will not handle irApplyToAllSelected correctly) - if (jsonCmdObj[F("psave")].isNull()) deserializeState(jsonCmdObj, CALL_MODE_BUTTON_PRESET); - else { + // command is JSON object + if (jsonCmdObj[F("psave")].isNull()) { + if (irApplyToAllSelected && jsonCmdObj["seg"].is()) { + JsonObject seg = jsonCmdObj["seg"][0]; // take 1st segment from array and use it to apply to all selected segments + seg.remove("id"); // remove segment ID if it exists + jsonCmdObj["seg"] = seg; // replace array with object + } + deserializeState(jsonCmdObj, CALL_MODE_BUTTON_PRESET); // **will call stateUpdated() with correct CALL_MODE** + } else { uint8_t psave = jsonCmdObj[F("psave")].as(); char pname[33]; sprintf_P(pname, PSTR("IR Preset %d"), psave); @@ -628,6 +634,7 @@ static void applyRepeatActions() { if (irEnabled == 8) { decodeIRJson(lastValidCode); + stateUpdated(CALL_MODE_BUTTON_PRESET); return; } else switch (lastRepeatableAction) { case ACTION_BRIGHT_UP : incBrightness(); stateUpdated(CALL_MODE_BUTTON); return; @@ -664,7 +671,7 @@ static void decodeIR(uint32_t code) if (irEnabled == 8) { // any remote configurable with ir.json file decodeIRJson(code); - stateUpdated(CALL_MODE_BUTTON); + stateUpdated(CALL_MODE_BUTTON_PRESET); return; } if (code > 0xFFFFFF) return; //invalid code From ee7ec20f29e1dd7fc3e525314b66101634b28974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Tue, 21 Jan 2025 17:50:36 +0100 Subject: [PATCH 271/463] Convert BusManager class to namespace - use unique_ptr/make_unique for busses --- wled00/bus_manager.cpp | 67 ++++++++++--------------- wled00/bus_manager.h | 110 ++++++++++++++++++++++------------------- wled00/cfg.cpp | 3 +- wled00/set.cpp | 3 +- wled00/wled.h | 11 ++--- wled00/xml.cpp | 2 +- 6 files changed, 94 insertions(+), 102 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 3abf6141..669111bf 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -63,6 +63,8 @@ uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, const #define W(c) (byte((c) >> 24)) +static ColorOrderMap _colorOrderMap = {}; + bool ColorOrderMap::add(uint16_t start, uint16_t len, uint8_t colorOrder) { if (count() >= WLED_MAX_COLOR_ORDER_MAPPINGS || len == 0 || (colorOrder & 0x0F) > COL_ORDER_MAX) return false; // upper nibble contains W swap information _mappings.push_back({start,len,colorOrder}); @@ -72,10 +74,8 @@ bool ColorOrderMap::add(uint16_t start, uint16_t len, uint8_t colorOrder) { uint8_t IRAM_ATTR ColorOrderMap::getPixelColorOrder(uint16_t pix, uint8_t defaultColorOrder) const { // upper nibble contains W swap information // when ColorOrderMap's upper nibble contains value >0 then swap information is used from it, otherwise global swap is used - for (unsigned i = 0; i < count(); i++) { - if (pix >= _mappings[i].start && pix < (_mappings[i].start + _mappings[i].len)) { - return _mappings[i].colorOrder | ((_mappings[i].colorOrder >> 4) ? 0 : (defaultColorOrder & 0xF0)); - } + for (const auto& map : _mappings) { + if (pix >= map.start && pix < (map.start + map.len)) return map.colorOrder | ((map.colorOrder >> 4) ? 0 : (defaultColorOrder & 0xF0)); } return defaultColorOrder; } @@ -124,13 +124,12 @@ uint8_t *Bus::allocateData(size_t size) { } -BusDigital::BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com) +BusDigital::BusDigital(const BusConfig &bc, uint8_t nr) : Bus(bc.type, bc.start, bc.autoWhite, bc.count, bc.reversed, (bc.refreshReq || bc.type == TYPE_TM1814)) , _skip(bc.skipAmount) //sacrificial pixels , _colorOrder(bc.colorOrder) , _milliAmpsPerLed(bc.milliAmpsPerLed) , _milliAmpsMax(bc.milliAmpsMax) -, _colorOrderMap(com) { if (!isDigital(bc.type) || !bc.count) return; if (!PinManager::allocatePin(bc.pins[0], true, PinOwner::BusDigital)) return; @@ -819,13 +818,17 @@ uint32_t BusManager::memUsage(unsigned maxChannels, unsigned maxCount, unsigned int BusManager::add(const BusConfig &bc) { if (getNumBusses() - getNumVirtualBusses() >= WLED_MAX_BUSSES) return -1; if (Bus::isVirtual(bc.type)) { - busses[numBusses] = new BusNetwork(bc); + busses.push_back(make_unique(bc)); + //busses.push_back(new BusNetwork(bc)); } else if (Bus::isDigital(bc.type)) { - busses[numBusses] = new BusDigital(bc, numBusses, colorOrderMap); + busses.push_back(make_unique(bc, numDigital)); + //busses.push_back(new BusDigital(bc, numDigital)); } else if (Bus::isOnOff(bc.type)) { - busses[numBusses] = new BusOnOff(bc); + busses.push_back(make_unique(bc)); + //busses.push_back(new BusOnOff(bc)); } else { - busses[numBusses] = new BusPwm(bc); + busses.push_back(make_unique(bc)); + //busses.push_back(new BusPwm(bc)); } return numBusses++; } @@ -865,9 +868,8 @@ void BusManager::removeAll() { DEBUG_PRINTLN(F("Removing all.")); //prevents crashes due to deleting busses while in use. while (!canAllShow()) yield(); - for (unsigned i = 0; i < numBusses; i++) delete busses[i]; - numBusses = 0; - _parallelOutputs = 1; + //for (auto &bus : busses) delete bus; // needed when not using std::unique_ptr C++ >11 + busses.clear(); PolyBus::setParallelI2S1Output(false); } @@ -914,8 +916,8 @@ void BusManager::on() { uint8_t pins[2] = {255,255}; if (busses[i]->isDigital() && busses[i]->getPins(pins)) { if (pins[0] == LED_BUILTIN || pins[1] == LED_BUILTIN) { - BusDigital *bus = static_cast(busses[i]); - bus->begin(); + BusDigital &b = static_cast(*bus); + b.begin(); break; } } @@ -943,16 +945,10 @@ void BusManager::off() { } void BusManager::show() { - _milliAmpsUsed = 0; - for (unsigned i = 0; i < numBusses; i++) { - busses[i]->show(); - _milliAmpsUsed += busses[i]->getUsedCurrent(); - } -} - -void BusManager::setStatusPixel(uint32_t c) { - for (unsigned i = 0; i < numBusses; i++) { - busses[i]->setStatusPixel(c); + _gMilliAmpsUsed = 0; + for (auto &bus : busses) { + bus->show(); + _gMilliAmpsUsed += bus->getUsedCurrent(); } } @@ -995,17 +991,8 @@ bool BusManager::canAllShow() { return true; } -Bus* BusManager::getBus(uint8_t busNr) { - if (busNr >= numBusses) return nullptr; - return busses[busNr]; -} +ColorOrderMap& BusManager::getColorOrderMap() { return _colorOrderMap; } -//semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit()) -uint16_t BusManager::getTotalLength() { - unsigned len = 0; - for (unsigned i=0; igetLength(); - return len; -} bool PolyBus::useParallelI2S = false; @@ -1016,9 +1003,7 @@ uint8_t Bus::_gAWM = 255; uint16_t BusDigital::_milliAmpsTotal = 0; -uint8_t BusManager::numBusses = 0; -Bus* BusManager::busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES]; -ColorOrderMap BusManager::colorOrderMap = {}; -uint16_t BusManager::_milliAmpsUsed = 0; -uint16_t BusManager::_milliAmpsMax = ABL_MILLIAMPS_DEFAULT; -uint8_t BusManager::_parallelOutputs = 1; +std::vector> BusManager::busses; +//std::vector BusManager::busses; +uint16_t BusManager::_gMilliAmpsUsed = 0; +uint16_t BusManager::_gMilliAmpsMax = ABL_MILLIAMPS_DEFAULT; diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 9aed0130..16a708d4 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -8,6 +8,20 @@ #include "const.h" #include "pin_manager.h" #include +#include +#include + +#if __cplusplus >= 201402L +using std::make_unique; +#else +// Really simple C++11 shim for non-array case; implementation from cppreference.com +template +std::unique_ptr +make_unique(Args&&... args) +{ + return std::unique_ptr(new T(std::forward(args)...)); +} +#endif //colors.cpp uint16_t approximateKelvinFromRGB(uint32_t rgb); @@ -198,7 +212,7 @@ class Bus { class BusDigital : public Bus { public: - BusDigital(const BusConfig &bc, uint8_t nr, const ColorOrderMap &com); + BusDigital(const BusConfig &bc, uint8_t nr); ~BusDigital() { cleanup(); } void show() override; @@ -229,7 +243,6 @@ class BusDigital : public Bus { uint8_t _milliAmpsPerLed; uint16_t _milliAmpsMax; void * _busPtr; - const ColorOrderMap &_colorOrderMap; static uint16_t _milliAmpsTotal; // is overwitten/recalculated on each show() @@ -374,61 +387,58 @@ struct BusConfig { #endif #endif -class BusManager { - public: - BusManager() {}; +namespace BusManager { - //utility to get the approx. memory usage of a given BusConfig - static uint32_t memUsage(const BusConfig &bc); - static uint32_t memUsage(unsigned channels, unsigned count, unsigned buses = 1); - static uint16_t currentMilliamps() { return _milliAmpsUsed + MA_FOR_ESP; } - static uint16_t ablMilliampsMax() { return _milliAmpsMax; } + extern std::vector> busses; + //extern std::vector busses; + extern uint16_t _gMilliAmpsUsed; + extern uint16_t _gMilliAmpsMax; - static int add(const BusConfig &bc); - static void useParallelOutput(); // workaround for inaccessible PolyBus + #ifdef ESP32_DATA_IDLE_HIGH + void esp32RMTInvertIdle() ; + #endif + inline uint8_t getNumVirtualBusses() { + int j = 0; + for (const auto &bus : busses) j += bus->isVirtual(); + return j; + } - //do not call this method from system context (network callback) - static void removeAll(); + unsigned memUsage(); + inline uint16_t currentMilliamps() { return _gMilliAmpsUsed + MA_FOR_ESP; } + //inline uint16_t ablMilliampsMax() { unsigned sum = 0; for (auto &bus : busses) sum += bus->getMaxCurrent(); return sum; } + inline uint16_t ablMilliampsMax() { return _gMilliAmpsMax; } // used for compatibility reasons (and enabling virtual global ABL) + inline void setMilliampsMax(uint16_t max) { _gMilliAmpsMax = max;} - static void on(); - static void off(); + void useParallelOutput(); // workaround for inaccessible PolyBus + bool hasParallelOutput(); // workaround for inaccessible PolyBus - static void show(); - static bool canAllShow(); - static void setStatusPixel(uint32_t c); - [[gnu::hot]] static void setPixelColor(unsigned pix, uint32_t c); - static void setBrightness(uint8_t b); - // for setSegmentCCT(), cct can only be in [-1,255] range; allowWBCorrection will convert it to K - // WARNING: setSegmentCCT() is a misleading name!!! much better would be setGlobalCCT() or just setCCT() - static void setSegmentCCT(int16_t cct, bool allowWBCorrection = false); - static inline void setMilliampsMax(uint16_t max) { _milliAmpsMax = max;} - [[gnu::hot]] static uint32_t getPixelColor(unsigned pix); - static inline int16_t getSegmentCCT() { return Bus::getCCT(); } + //do not call this method from system context (network callback) + void removeAll(); + int add(const BusConfig &bc); - static Bus* getBus(uint8_t busNr); + void on(); + void off(); - //semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit()) - static uint16_t getTotalLength(); - static inline uint8_t getNumBusses() { return numBusses; } - static String getLEDTypesJSONString(); + [[gnu::hot]] void setPixelColor(unsigned pix, uint32_t c); + [[gnu::hot]] uint32_t getPixelColor(unsigned pix); + void show(); + bool canAllShow(); + inline void setStatusPixel(uint32_t c) { for (auto &bus : busses) bus->setStatusPixel(c);} + inline void setBrightness(uint8_t b) { for (auto &bus : busses) bus->setBrightness(b); } + // for setSegmentCCT(), cct can only be in [-1,255] range; allowWBCorrection will convert it to K + // WARNING: setSegmentCCT() is a misleading name!!! much better would be setGlobalCCT() or just setCCT() + void setSegmentCCT(int16_t cct, bool allowWBCorrection = false); + inline int16_t getSegmentCCT() { return Bus::getCCT(); } + inline Bus& getBus(uint8_t busNr) { return *busses[std::min((size_t)busNr, busses.size()-1)]; } + inline uint8_t getNumBusses() { return busses.size(); } - static inline ColorOrderMap& getColorOrderMap() { return colorOrderMap; } - - private: - static uint8_t numBusses; - static Bus* busses[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES]; - static ColorOrderMap colorOrderMap; - static uint16_t _milliAmpsUsed; - static uint16_t _milliAmpsMax; - static uint8_t _parallelOutputs; - - #ifdef ESP32_DATA_IDLE_HIGH - static void esp32RMTInvertIdle() ; - #endif - static uint8_t getNumVirtualBusses() { - int j = 0; - for (int i=0; iisVirtual()) j++; - return j; - } + //semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit()) + inline uint16_t getTotalLength(bool onlyPhysical = false) { + unsigned len = 0; + for (const auto &bus : busses) if (!(bus->isVirtual() && onlyPhysical)) len += bus->getLength(); + return len; + } + String getLEDTypesJSONString(); + ColorOrderMap& getColorOrderMap(); }; #endif diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 00cfc60d..352b6c77 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -876,8 +876,7 @@ void serializeConfig() { const ColorOrderMap& com = BusManager::getColorOrderMap(); for (size_t s = 0; s < com.count(); s++) { const ColorOrderMapEntry *entry = com.get(s); - if (!entry) break; - + if (!entry || !entry->len) break; JsonObject co = hw_com.createNestedObject(); co["start"] = entry->start; co["len"] = entry->len; diff --git a/wled00/set.cpp b/wled00/set.cpp index c0977f26..f7be16e0 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -208,8 +208,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) type |= request->hasArg(rf) << 7; // off refresh override // actual finalization is done in WLED::loop() (removing old busses and adding new) // this may happen even before this loop is finished so we do "doInitBusses" after the loop - if (busConfigs[s] != nullptr) delete busConfigs[s]; - busConfigs[s] = new(std::nothrow) BusConfig(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freq, useGlobalLedBuffer, maPerLed, maMax); + busConfigs.emplace_back(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freq, useGlobalLedBuffer, maPerLed, maMax); busesChanged = true; } //doInitBusses = busesChanged; // we will do that below to ensure all input data is processed diff --git a/wled00/wled.h b/wled00/wled.h index a1819944..80d31985 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -891,12 +891,11 @@ WLED_GLOBAL ESPAsyncE131 ddp _INIT_N(((handleE131Packet))); WLED_GLOBAL bool e131NewData _INIT(false); // led fx library object -WLED_GLOBAL BusManager busses _INIT(BusManager()); -WLED_GLOBAL WS2812FX strip _INIT(WS2812FX()); -WLED_GLOBAL BusConfig* busConfigs[WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES] _INIT({nullptr}); //temporary, to remember values from network callback until after -WLED_GLOBAL bool doInitBusses _INIT(false); -WLED_GLOBAL int8_t loadLedmap _INIT(-1); -WLED_GLOBAL uint8_t currentLedmap _INIT(0); +WLED_GLOBAL WS2812FX strip _INIT(WS2812FX()); +WLED_GLOBAL std::vector busConfigs; //temporary, to remember values from network callback until after +WLED_GLOBAL bool doInitBusses _INIT(false); +WLED_GLOBAL int8_t loadLedmap _INIT(-1); +WLED_GLOBAL uint8_t currentLedmap _INIT(0); #ifndef ESP8266 WLED_GLOBAL char *ledmapNames[WLED_MAX_LEDMAPS-1] _INIT_N(({nullptr})); #endif diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 78d2d7d5..b53958c4 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -357,7 +357,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) const ColorOrderMap& com = BusManager::getColorOrderMap(); for (int s = 0; s < com.count(); s++) { const ColorOrderMapEntry* entry = com.get(s); - if (entry == nullptr) break; + if (!entry || !entry->len) break; settingsScript.printf_P(PSTR("addCOM(%d,%d,%d);"), entry->start, entry->len, entry->colorOrder); } From bf69d37cbe6bc4430093d275a6200e3780cb941e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Tue, 21 Jan 2025 20:14:20 +0100 Subject: [PATCH 272/463] Revert getBus() changes --- wled00/FX_fcn.cpp | 31 +++++++++++++++---------------- wled00/bus_manager.cpp | 15 ++++++++++++--- wled00/bus_manager.h | 2 +- wled00/cfg.cpp | 35 +++++++++++++++++++++++------------ wled00/xml.cpp | 6 +++--- 5 files changed, 54 insertions(+), 35 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index cf37a46c..03138142 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1117,12 +1117,9 @@ void Segment::refreshLightCapabilities() { } for (unsigned b = 0; b < BusManager::getNumBusses(); b++) { - Bus *bus = BusManager::getBus(b); - if (bus == nullptr || bus->getLength()==0) break; - if (!bus->isOk()) continue; - if (bus->getStart() >= segStopIdx) continue; - if (bus->getStart() + bus->getLength() <= segStartIdx) continue; - + const Bus *bus = BusManager::getBus(b); + if (!bus || !bus->isOk()) break; + if (bus->getStart() >= segStopIdx || bus->getStart() + bus->getLength() <= segStartIdx) continue; 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) @@ -1397,8 +1394,7 @@ void WS2812FX::finalizeInit() { _length = 0; for (int i=0; igetStart() + bus->getLength() > MAX_LEDS) break; + if (!bus || !bus->isOk() || bus->getStart() + bus->getLength() > MAX_LEDS) break; //RGBW mode is enabled if at least one of the strips is RGBW _hasWhiteChannel |= bus->hasWhite(); //refresh is required to remain off if at least one of the strips requires the refresh. @@ -1408,6 +1404,7 @@ void WS2812FX::finalizeInit() { // This must be done after all buses have been created, as some kinds (parallel I2S) interact bus->begin(); + bus->setBrightness(bri); } Segment::maxWidth = _length; @@ -1691,8 +1688,8 @@ uint16_t WS2812FX::getLengthPhysical() const { //not influenced by auto-white mode, also true if white slider does not affect output white channel bool WS2812FX::hasRGBWBus() const { for (size_t b = 0; b < BusManager::getNumBusses(); b++) { - Bus *bus = BusManager::getBus(b); - if (bus == nullptr || bus->getLength()==0) break; + const Bus *bus = BusManager::getBus(b); + if (!bus || !bus->isOk()) break; if (bus->hasRGB() && bus->hasWhite()) return true; } return false; @@ -1701,8 +1698,8 @@ bool WS2812FX::hasRGBWBus() const { bool WS2812FX::hasCCTBus() const { if (cctFromRgb && !correctWB) return false; for (size_t b = 0; b < BusManager::getNumBusses(); b++) { - Bus *bus = BusManager::getBus(b); - if (bus == nullptr || bus->getLength()==0) break; + const Bus *bus = BusManager::getBus(b); + if (!bus || !bus->isOk()) break; if (bus->hasCCT()) return true; } return false; @@ -1755,10 +1752,11 @@ void WS2812FX::makeAutoSegments(bool forceReset) { #endif for (size_t i = s; i < BusManager::getNumBusses(); i++) { - Bus* b = BusManager::getBus(i); + const Bus *bus = BusManager::getBus(i); + if (!bus || !bus->isOk()) break; - segStarts[s] = b->getStart(); - segStops[s] = segStarts[s] + b->getLength(); + segStarts[s] = bus->getStart(); + segStops[s] = segStarts[s] + bus->getLength(); #ifndef WLED_DISABLE_2D if (isMatrix && segStops[s] <= Segment::maxWidth*Segment::maxHeight) continue; // ignore buses comprising matrix @@ -1848,7 +1846,8 @@ bool WS2812FX::checkSegmentAlignment() const { bool aligned = false; for (const segment &seg : _segments) { for (unsigned b = 0; bisOk()) break; if (seg.start == bus->getStart() && seg.stop == bus->getStart() + bus->getLength()) aligned = true; } if (seg.start == 0 && seg.stop == _length) aligned = true; diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 669111bf..6807f438 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -153,8 +153,17 @@ BusDigital::BusDigital(const BusConfig &bc, uint8_t nr) uint16_t lenToCreate = bc.count; if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(bc.count); // only needs a third of "RGB" LEDs for NeoPixelBus _busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr); - _valid = (_busPtr != nullptr); - DEBUG_PRINTF_P(PSTR("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u). mA=%d/%d\n"), _valid?"S":"Uns", nr, bc.count, bc.type, _pins[0], is2Pin(bc.type)?_pins[1]:255, _iType, _milliAmpsPerLed, _milliAmpsMax); + _valid = (_busPtr != nullptr) && bc.count > 0; + DEBUG_PRINTF_P(PSTR("Bus: %successfully inited #%u (len:%u, type:%u (RGB:%d, W:%d, CCT:%d), pins:%u,%u [itype:%u] mA=%d/%d)\n"), + _valid?"S":"Uns", + (int)nr, + (int)bc.count, + (int)bc.type, + (int)_hasRgb, (int)_hasWhite, (int)_hasCCT, + (unsigned)_pins[0], is2Pin(bc.type)?(unsigned)_pins[1]:255U, + (unsigned)_iType, + (int)_milliAmpsPerLed, (int)_milliAmpsMax + ); } //DISCLAIMER @@ -734,7 +743,7 @@ BusNetwork::BusNetwork(const BusConfig &bc) _hasCCT = false; _UDPchannels = _hasWhite + 3; _client = IPAddress(bc.pins[0],bc.pins[1],bc.pins[2],bc.pins[3]); - _valid = (allocateData(_len * _UDPchannels) != nullptr); + _valid = (allocateData(_len * _UDPchannels) != nullptr) && bc.count > 0; DEBUG_PRINTF_P(PSTR("%successfully inited virtual strip with type %u and IP %u.%u.%u.%u\n"), _valid?"S":"Uns", bc.type, bc.pins[0], bc.pins[1], bc.pins[2], bc.pins[3]); } diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 16a708d4..8f4906ea 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -429,7 +429,7 @@ namespace BusManager { // WARNING: setSegmentCCT() is a misleading name!!! much better would be setGlobalCCT() or just setCCT() void setSegmentCCT(int16_t cct, bool allowWBCorrection = false); inline int16_t getSegmentCCT() { return Bus::getCCT(); } - inline Bus& getBus(uint8_t busNr) { return *busses[std::min((size_t)busNr, busses.size()-1)]; } + inline Bus* getBus(size_t busNr) { return busNr < busses.size() ? busses[busNr].get() : nullptr; } inline uint8_t getNumBusses() { return busses.size(); } //semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit()) diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 352b6c77..0d3165e0 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -239,7 +239,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { DEBUG_PRINTF_P(PSTR("LED buffer size: %uB\n"), mem); DEBUG_PRINTF_P(PSTR("Heap after buses: %d\n"), ESP.getFreeHeap()); } - if (hw_led["rev"]) BusManager::getBus(0)->setReversed(true); //set 0.11 global reversed setting for first bus + if (hw_led["rev"] && BusManager::getNumBusses()) BusManager::getBus(0)->setReversed(true); //set 0.11 global reversed setting for first bus // read color order map configuration JsonArray hw_com = hw[F("com")]; @@ -852,24 +852,35 @@ void serializeConfig() { JsonArray hw_led_ins = hw_led.createNestedArray("ins"); for (size_t s = 0; s < BusManager::getNumBusses(); s++) { - Bus *bus = BusManager::getBus(s); - if (!bus || bus->getLength()==0) break; + DEBUG_PRINTF_P(PSTR("Cfg: Saving bus #%u\n"), s); + const Bus *bus = BusManager::getBus(s); + if (!bus || !bus->isOk()) break; + DEBUG_PRINTF_P(PSTR(" (%d-%d, type:%d, CO:%d, rev:%d, skip:%d, AW:%d kHz:%d, mA:%d/%d)\n"), + (int)bus->getStart(), (int)(bus->getStart()+bus->getLength()), + (int)(bus->getType() & 0x7F), + (int)bus->getColorOrder(), + (int)bus->isReversed(), + (int)bus->skippedLeds(), + (int)bus->getAutoWhiteMode(), + (int)bus->getFrequency(), + (int)bus->getLEDCurrent(), (int)bus->getMaxCurrent() + ); JsonObject ins = hw_led_ins.createNestedObject(); ins["start"] = bus->getStart(); - ins["len"] = bus->getLength(); + ins["len"] = bus->getLength(); JsonArray ins_pin = ins.createNestedArray("pin"); uint8_t pins[5]; uint8_t nPins = bus->getPins(pins); for (int i = 0; i < nPins; i++) ins_pin.add(pins[i]); - ins[F("order")] = bus->getColorOrder(); - ins["rev"] = bus->isReversed(); - ins[F("skip")] = bus->skippedLeds(); - ins["type"] = bus->getType() & 0x7F; - ins["ref"] = bus->isOffRefreshRequired(); - ins[F("rgbwm")] = bus->getAutoWhiteMode(); - ins[F("freq")] = bus->getFrequency(); + ins[F("order")] = bus->getColorOrder(); + ins["rev"] = bus->isReversed(); + ins[F("skip")] = bus->skippedLeds(); + ins["type"] = bus->getType() & 0x7F; + ins["ref"] = bus->isOffRefreshRequired(); + ins[F("rgbwm")] = bus->getAutoWhiteMode(); + ins[F("freq")] = bus->getFrequency(); ins[F("maxpwr")] = bus->getMaxCurrent(); - ins[F("ledma")] = bus->getLEDCurrent(); + ins[F("ledma")] = bus->getLEDCurrent(); } JsonArray hw_com = hw.createNestedArray(F("com")); diff --git a/wled00/xml.cpp b/wled00/xml.cpp index b53958c4..a31b1307 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -292,8 +292,8 @@ void getSettingsJS(byte subPage, Print& settingsScript) unsigned sumMa = 0; for (int s = 0; s < BusManager::getNumBusses(); s++) { - Bus* bus = BusManager::getBus(s); - if (bus == nullptr) continue; + const Bus *bus = BusManager::getBus(s); + if (!bus || !bus->isOk()) break; // should not happen but for safety int offset = s < 10 ? 48 : 55; char lp[4] = "L0"; lp[2] = offset+s; lp[3] = 0; //ascii 0-9 //strip data pin char lc[4] = "LC"; lc[2] = offset+s; lc[3] = 0; //strip length @@ -312,7 +312,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) uint8_t pins[5]; int nPins = bus->getPins(pins); for (int i = 0; i < nPins; i++) { - lp[1] = offset+i; + lp[1] = '0'+i; if (PinManager::isPinOk(pins[i]) || bus->isVirtual()) printSetFormValue(settingsScript,lp,pins[i]); } printSetFormValue(settingsScript,lc,bus->getLength()); From 70042db2dea8ff7a1b4b00430b250a60c30f3ef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Wed, 22 Jan 2025 20:33:56 +0100 Subject: [PATCH 273/463] Allow "unlimited" virtual buses - added config upload options - number of buses it limited to 36 (0-9+A-Z identifiers) - WRNING web server may not support that many variables --- wled00/cfg.cpp | 22 +++------- wled00/const.h | 24 ++++++----- wled00/data/settings_leds.htm | 76 ++++++++++++++++++++++++----------- wled00/set.cpp | 4 +- wled00/xml.cpp | 2 +- 5 files changed, 75 insertions(+), 53 deletions(-) diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 0d3165e0..3e8782a9 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -192,7 +192,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { #endif for (JsonObject elm : ins) { - if (s >= WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES) break; + if (s >= WLED_MAX_BUSSES) break; uint8_t pins[5] = {255, 255, 255, 255, 255}; JsonArray pinArr = elm["pin"]; if (pinArr.size() == 0) continue; @@ -220,21 +220,11 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { maMax = 0; } ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh - if (fromFS) { - BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax); - if (useParallel && s < 8) { - // if for some unexplained reason the above pre-calculation was wrong, update - unsigned memT = BusManager::memUsage(bc); // includes x8 memory allocation for parallel I2S - if (memT > mem) mem = memT; // if we have unequal LED count use the largest - } else - mem += BusManager::memUsage(bc); // includes global buffer - if (mem <= MAX_LED_MEMORY) if (BusManager::add(bc) == -1) break; // finalization will be done in WLED::beginStrip() - } else { - if (busConfigs[s] != nullptr) delete busConfigs[s]; - busConfigs[s] = new BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax); - doInitBusses = true; // finalization done in beginStrip() - } - s++; + + //busConfigs.push_back(std::move(BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax))); + busConfigs.emplace_back(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax); + doInitBusses = true; // finalization done in beginStrip() + if (!Bus::isVirtual(ledType)) s++; // have as many virtual buses as you want } DEBUG_PRINTF_P(PSTR("LED buffer size: %uB\n"), mem); DEBUG_PRINTF_P(PSTR("Heap after buses: %d\n"), ESP.getFreeHeap()); diff --git a/wled00/const.h b/wled00/const.h index 1ebcb939..0f0fc4f9 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -49,31 +49,31 @@ #define WLED_MAX_DIGITAL_CHANNELS 3 #define WLED_MAX_ANALOG_CHANNELS 5 #define WLED_MAX_BUSSES 4 // will allow 3 digital & 1 analog RGB - #define WLED_MIN_VIRTUAL_BUSSES 2 + #define WLED_MIN_VIRTUAL_BUSSES 3 // no longer used for bus creation but used to distinguish S2/S3 in UI #else #define WLED_MAX_ANALOG_CHANNELS (LEDC_CHANNEL_MAX*LEDC_SPEED_MODE_MAX) #if defined(CONFIG_IDF_TARGET_ESP32C3) // 2 RMT, 6 LEDC, only has 1 I2S but NPB does not support it ATM #define WLED_MAX_BUSSES 6 // will allow 2 digital & 2 analog RGB or 6 PWM white #define WLED_MAX_DIGITAL_CHANNELS 2 //#define WLED_MAX_ANALOG_CHANNELS 6 - #define WLED_MIN_VIRTUAL_BUSSES 3 + #define WLED_MIN_VIRTUAL_BUSSES 4 // no longer used for bus creation but used to distinguish S2/S3 in UI #elif defined(CONFIG_IDF_TARGET_ESP32S2) // 4 RMT, 8 LEDC, only has 1 I2S bus, supported in NPB // the 5th bus (I2S) will prevent Audioreactive usermod from functioning (it is last used though) #define WLED_MAX_BUSSES 7 // will allow 5 digital & 2 analog RGB #define WLED_MAX_DIGITAL_CHANNELS 5 //#define WLED_MAX_ANALOG_CHANNELS 8 - #define WLED_MIN_VIRTUAL_BUSSES 3 - #elif defined(CONFIG_IDF_TARGET_ESP32S3) // 4 RMT, 8 LEDC, has 2 I2S but NPB does not support them ATM - #define WLED_MAX_BUSSES 6 // will allow 4 digital & 2 analog RGB - #define WLED_MAX_DIGITAL_CHANNELS 4 + #define WLED_MIN_VIRTUAL_BUSSES 4 // no longer used for bus creation but used to distinguish S2/S3 in UI + #elif defined(CONFIG_IDF_TARGET_ESP32S3) // 4 RMT, 8 LEDC, has 2 I2S but NPB supports parallel x8 LCD on I2S1 + #define WLED_MAX_BUSSES 14 // will allow 12 digital & 2 analog RGB + #define WLED_MAX_DIGITAL_CHANNELS 12 // x4 RMT + x8 I2S-LCD //#define WLED_MAX_ANALOG_CHANNELS 8 - #define WLED_MIN_VIRTUAL_BUSSES 4 + #define WLED_MIN_VIRTUAL_BUSSES 6 // no longer used for bus creation but used to distinguish S2/S3 in UI #else // the last digital bus (I2S0) will prevent Audioreactive usermod from functioning #define WLED_MAX_BUSSES 20 // will allow 17 digital & 3 analog RGB #define WLED_MAX_DIGITAL_CHANNELS 17 //#define WLED_MAX_ANALOG_CHANNELS 16 - #define WLED_MIN_VIRTUAL_BUSSES 4 + #define WLED_MIN_VIRTUAL_BUSSES 6 // no longer used for bus creation but used to distinguish S2/S3 in UI #endif #endif #else @@ -87,7 +87,7 @@ #ifndef WLED_MAX_DIGITAL_CHANNELS #error You must also define WLED_MAX_DIGITAL_CHANNELS. #endif - #define WLED_MIN_VIRTUAL_BUSSES (5-WLED_MAX_BUSSES) + #define WLED_MIN_VIRTUAL_BUSSES 3 #else #if WLED_MAX_BUSSES > 20 #error Maximum number of buses is 20. @@ -98,7 +98,11 @@ #ifndef WLED_MAX_DIGITAL_CHANNELS #error You must also define WLED_MAX_DIGITAL_CHANNELS. #endif - #define WLED_MIN_VIRTUAL_BUSSES (20-WLED_MAX_BUSSES) + #if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) + #define WLED_MIN_VIRTUAL_BUSSES 4 + #else + #define WLED_MIN_VIRTUAL_BUSSES 6 + #endif #endif #endif diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 02ebb6ed..87e76e9b 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -42,10 +42,10 @@ if (loc) d.Sf.action = getURL('/settings/leds'); } function bLimits(b,v,p,m,l,o=5,d=2,a=6) { - oMaxB = maxB = b; // maxB - max buses (can be changed if using ESP32 parallel I2S) - maxD = d; // maxD - max digital channels (can be changed if using ESP32 parallel I2S) - maxA = a; // maxA - max analog channels - maxV = v; // maxV - min virtual buses + oMaxB = maxB = b; // maxB - max buses (can be changed if using ESP32 parallel I2S): 20 - ESP32, 14 - S3/S2, 6 - C3, 4 - 8266 + maxD = d; // maxD - max digital channels (can be changed if using ESP32 parallel I2S): 17 - ESP32, 12 - S3/S2, 2 - C3, 3 - 8266 + maxA = a; // maxA - max analog channels: 16 - ESP32, 8 - S3/S2, 6 - C3, 5 - 8266 + maxV = v; // maxV - min virtual buses: 6 - ESP32/S3, 4 - S2/C3, 3 - ESP8266 (only used to distinguish S2/S3) maxPB = p; // maxPB - max LEDs per bus maxM = m; // maxM - max LED memory maxL = l; // maxL - max LEDs (will serve to determine ESP >1664 == ESP32) @@ -350,6 +350,18 @@ else LC.style.color = d.ro_gpio.some((e)=>e==parseInt(LC.value)) ? "orange" : "#fff"; } }); + const S2 = (oMaxB == 14) && (maxV == 4); + const S3 = (oMaxB == 14) && (maxV == 6); + if (oMaxB == 19 || S2 || S3) { // TODO: crude ESP32 & S2/S3 detection + if (maxLC > 300 || dC <= 2) { + d.Sf["PR"].checked = false; + gId("prl").classList.add("hide"); + } else + gId("prl").classList.remove("hide"); + // S2 supports mono I2S as well as parallel so we need to take that into account; S3 only supports parallel + maxD = (S2 || S3 ? 4 : 8) + (d.Sf["PR"].checked ? 8 : S2); // TODO: use bLimits() : 4/8RMT + (x1/x8 parallel) I2S1 + maxB = oMaxB - (d.Sf["PR"].checked ? 0 : 7 + S3); // S2 (maxV==4) does support mono I2S + } // distribute ABL current if not using PPL enPPL(sDI); @@ -409,8 +421,8 @@ if (isVir(t)) virtB++; }); - if ((n==1 && i>=maxB+maxV) || (n==-1 && i==0)) return; - var s = String.fromCharCode((i<10?48:55)+i); + if ((n==1 && i>=36) || (n==-1 && i==0)) return; // used to be i>=maxB+maxV when virtual buses were limited (now :"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") + var s = chrID(i); if (n==1) { // npm run build has trouble minimizing spaces inside string @@ -484,7 +496,7 @@ mA/LED: function receivedText(e) { let lines = e.target.result; - var c = JSON.parse(lines); + let c = JSON.parse(lines); if (c.hw) { if (c.hw.led) { - for (var i=0; i<10; i++) addLEDs(-1); - var l = c.hw.led; + // remove all existing outputs + for (const i=0; i<36; i++) addLEDs(-1); // was i{ addLEDs(1); for (var j=0; j>4) & 0x0F; + d.getElementsByName("SP"+i)[0].value = v.freq; + d.getElementsByName("LA"+i)[0].value = v.ledma; + d.getElementsByName("MA"+i)[0].value = v.maxpwr; }); + d.getElementsByName("PR")[0].checked = l.prl | 0; + d.getElementsByName("LD")[0].checked = l.ld; + d.getElementsByName("MA")[0].value = l.maxpwr; + d.getElementsByName("ABL")[0].checked = l.maxpwr > 0; } if(c.hw.com) { resetCOM(); @@ -626,22 +648,28 @@ Swap: or a video demo . -## Adding Dependencies - -I2Cdev and MPU6050 must be installed. - -To install them, add electroniccats/MPU6050@1.0.1 to lib_deps in the platformio.ini file. - -For example: - -``` -lib_deps = - FastLED@3.3.2 - NeoPixelBus@2.5.7 - ESPAsyncTCP@1.2.0 - ESPAsyncUDP@697c75a025 - AsyncTCP@1.0.3 - Esp Async WebServer@1.2.0 - IRremoteESP8266@2.7.3 - electroniccats/MPU6050@1.0.1 -``` - ## Wiring The connections needed to the MPU6050 are as follows: @@ -74,18 +54,13 @@ to the info object ## Usermod installation -1. Copy the file `usermod_mpu6050_imu.h` to the `wled00` directory. -2. Register the usermod by adding `#include "usermod_mpu6050_imu.h"` in the top and `registerUsermod(new MPU6050Driver());` in the bottom of `usermods_list.cpp`. +Add `mpu6050_imu` to `custom_usermods` in your platformio_override.ini. -Example **usermods_list.cpp**: +Example **platformio_override.ini**: -```cpp -#include "wled.h" - -#include "usermod_mpu6050_imu.h" - -void registerUsermods() -{ - UsermodManager::add(new MPU6050Driver()); -} +```ini +[env:usermod_mpu6050_imu_esp32dev] +extends = env:esp32dev +custom_usermods = ${env:esp32dev.custom_usermods} + mpu6050_imu ``` diff --git a/usermods/multi_relay/readme.md b/usermods/multi_relay/readme.md index eaa069ae..543809d8 100644 --- a/usermods/multi_relay/readme.md +++ b/usermods/multi_relay/readme.md @@ -41,9 +41,7 @@ When a relay is switched, a message is published: ## Usermod installation -1. Register the usermod by adding `#include "../usermods/multi_relay/usermod_multi_relay.h"` at the top and `UsermodManager::add(new MultiRelay());` at the bottom of `usermods_list.cpp`. -or -2. Use `#define USERMOD_MULTI_RELAY` in wled.h or `-D USERMOD_MULTI_RELAY` in your platformio.ini +Add `multi_relay` to the `custom_usermods` of your platformio.ini environment. You can override the default maximum number of relays (which is 4) by defining MULTI_RELAY_MAX_RELAYS. @@ -65,38 +63,6 @@ The following definitions should be a list of values (maximum number of entries ``` These can be set via your `platformio_override.ini` file or as `#define` in your `my_config.h` (remember to set `WLED_USE_MY_CONFIG` in your `platformio_override.ini`) -Example **usermods_list.cpp**: - -```cpp -#include "wled.h" -/* - * Register your v2 usermods here! - * (for v1 usermods using just usermod.cpp, you can ignore this file) - */ - -/* - * Add/uncomment your usermod filename here (and once more below) - * || || || - * \/ \/ \/ - */ -//#include "usermod_v2_example.h" -//#include "usermod_temperature.h" -#include "../usermods/usermod_multi_relay.h" - -void registerUsermods() -{ - /* - * Add your usermod class name here - * || || || - * \/ \/ \/ - */ - //UsermodManager::add(new MyExampleUsermod()); - //UsermodManager::add(new UsermodTemperature()); - UsermodManager::add(new MultiRelay()); - -} -``` - ## Configuration Usermod can be configured via the Usermods settings page. From b64cd36468384bf4f293a72602cbb2b860b25146 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Fri, 31 Jan 2025 14:10:03 +0100 Subject: [PATCH 282/463] fixes trail flickering randomly. thx @blazoncek for discovering --- wled00/FX.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 59482264..b9ead141 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2358,12 +2358,14 @@ uint16_t mode_meteor() { for (unsigned i = 0; i < SEGLEN; i++) { uint32_t col; if (hw_random8() <= 255 - SEGMENT.intensity) { - if(meteorSmooth) { - int change = trail[i] + 4 - hw_random8(24); //change each time between -20 and +4 - trail[i] = constrain(change, 0, max); - col = SEGMENT.check1 ? SEGMENT.color_from_palette(i, true, false, 0, trail[i]) : SEGMENT.color_from_palette(trail[i], false, true, 255); + if(meteorSmooth) { + if (trail[i] > 0) { + int change = trail[i] + 4 - hw_random8(24); //change each time between -20 and +4 + trail[i] = constrain(change, 0, max); } - else { + col = SEGMENT.check1 ? SEGMENT.color_from_palette(i, true, false, 0, trail[i]) : SEGMENT.color_from_palette(trail[i], false, true, 255); + } + else { trail[i] = scale8(trail[i], 128 + hw_random8(127)); int index = trail[i]; int idx = 255; From 7a40ef74c6f721258ff200208ff0bab1724e32df Mon Sep 17 00:00:00 2001 From: Will Miles Date: Fri, 31 Jan 2025 23:59:37 +0000 Subject: [PATCH 283/463] Fix up PWM_fan Use a custom setup script to check for the dependencies and pass along the required compile flags to the module; also split the object definitions for the target modules from their source so as to allow #including them. --- usermods/PWM_fan/PWM_fan.cpp | 10 +- usermods/PWM_fan/library.json | 6 ++ usermods/PWM_fan/library.json.disabled | 3 - usermods/PWM_fan/readme.md | 4 +- usermods/PWM_fan/setup_deps.py | 12 +++ usermods/Temperature/Temperature.cpp | 107 +----------------- usermods/Temperature/UsermodTemperature.h | 108 +++++++++++++++++++ usermods/Temperature/platformio_override.ini | 1 - usermods/sht/ShtUsermod.h | 71 ++++++++++++ usermods/sht/library.json | 6 ++ usermods/sht/library.json.disabled | 3 - usermods/sht/readme.md | 13 +-- usermods/sht/sht.cpp | 71 +----------- 13 files changed, 220 insertions(+), 195 deletions(-) create mode 100644 usermods/PWM_fan/library.json delete mode 100644 usermods/PWM_fan/library.json.disabled create mode 100644 usermods/PWM_fan/setup_deps.py create mode 100644 usermods/Temperature/UsermodTemperature.h create mode 100644 usermods/sht/ShtUsermod.h create mode 100644 usermods/sht/library.json delete mode 100644 usermods/sht/library.json.disabled diff --git a/usermods/PWM_fan/PWM_fan.cpp b/usermods/PWM_fan/PWM_fan.cpp index a89a1f32..a0939f08 100644 --- a/usermods/PWM_fan/PWM_fan.cpp +++ b/usermods/PWM_fan/PWM_fan.cpp @@ -1,8 +1,14 @@ -#if !defined(USERMOD_DALLASTEMPERATURE) && !defined(USERMOD_SHT) +#include "wled.h" + +#if defined(USERMOD_DALLASTEMPERATURE) +#include "UsermodTemperature.h" +#elif defined(USERMOD_SHT) +#include "ShtUsermod.h" +#else #error The "PWM fan" usermod requires "Dallas Temeprature" or "SHT" usermod to function properly. #endif -#include "wled.h" + // PWM & tacho code curtesy of @KlausMu // https://github.com/KlausMu/esp32-fan-controller/tree/main/src diff --git a/usermods/PWM_fan/library.json b/usermods/PWM_fan/library.json new file mode 100644 index 00000000..a0e53b21 --- /dev/null +++ b/usermods/PWM_fan/library.json @@ -0,0 +1,6 @@ +{ + "name:": "PWM_fan", + "build": { + "extraScript": "setup_deps.py" + } +} \ No newline at end of file diff --git a/usermods/PWM_fan/library.json.disabled b/usermods/PWM_fan/library.json.disabled deleted file mode 100644 index 904d7723..00000000 --- a/usermods/PWM_fan/library.json.disabled +++ /dev/null @@ -1,3 +0,0 @@ -{ - "name:": "PWM_fan" -} \ No newline at end of file diff --git a/usermods/PWM_fan/readme.md b/usermods/PWM_fan/readme.md index 6a44acf3..9fecaabf 100644 --- a/usermods/PWM_fan/readme.md +++ b/usermods/PWM_fan/readme.md @@ -11,8 +11,8 @@ If the _tachometer_ is supported, the current speed (in RPM) will be displayed o ## Installation -Add the compile-time option `-D USERMOD_PWM_FAN` to your `platformio.ini` (or `platformio_override.ini`) or use `#define USERMOD_PWM_FAN` in `myconfig.h`. -You will also need `-D USERMOD_DALLASTEMPERATURE`. +Add the `PWM_fan` to `custom_usermods` in your `platformio.ini` (or `platformio_override.ini`) +You will also need `Temperature` or `sht`. ### Define Your Options diff --git a/usermods/PWM_fan/setup_deps.py b/usermods/PWM_fan/setup_deps.py new file mode 100644 index 00000000..dd29e464 --- /dev/null +++ b/usermods/PWM_fan/setup_deps.py @@ -0,0 +1,12 @@ +Import('env') + + +usermods = env.GetProjectOption("custom_usermods","").split(" ") +# Check for dependencies +if "Temperature" in usermods: + env.Append(CPPDEFINES=[("USERMOD_DALLASTEMPERATURE")]) +elif "sht" in usermods: + env.Append(CPPDEFINES=[("USERMOD_SHT")]) +else: + raise RuntimeError("PWM_fan usermod requires Temperature or sht to be enabled") + diff --git a/usermods/Temperature/Temperature.cpp b/usermods/Temperature/Temperature.cpp index 8c925eb1..a2e0ea91 100644 --- a/usermods/Temperature/Temperature.cpp +++ b/usermods/Temperature/Temperature.cpp @@ -1,112 +1,7 @@ -#include "wled.h" -#include "OneWire.h" - -//Pin defaults for QuinLed Dig-Uno if not overriden -#ifndef TEMPERATURE_PIN - #ifdef ARDUINO_ARCH_ESP32 - #define TEMPERATURE_PIN 18 - #else //ESP8266 boards - #define TEMPERATURE_PIN 14 - #endif -#endif - -// the frequency to check temperature, 1 minute -#ifndef USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL -#define USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL 60000 -#endif +#include "UsermodTemperature.h" static uint16_t mode_temperature(); -class UsermodTemperature : public Usermod { - - private: - - bool initDone = false; - OneWire *oneWire; - // GPIO pin used for sensor (with a default compile-time fallback) - int8_t temperaturePin = TEMPERATURE_PIN; - // measurement unit (true==°C, false==°F) - bool degC = true; - // using parasite power on the sensor - bool parasite = false; - int8_t parasitePin = -1; - // how often do we read from sensor? - unsigned long readingInterval = USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL; - // set last reading as "40 sec before boot", so first reading is taken after 20 sec - unsigned long lastMeasurement = UINT32_MAX - USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL; - // last time requestTemperatures was called - // used to determine when we can read the sensors temperature - // we have to wait at least 93.75 ms after requestTemperatures() is called - unsigned long lastTemperaturesRequest; - float temperature; - // indicates requestTemperatures has been called but the sensor measurement is not complete - bool waitingForConversion = false; - // flag set at startup if DS18B20 sensor not found, avoids trying to keep getting - // temperature if flashed to a board without a sensor attached - byte sensorFound; - - bool enabled = true; - - bool HApublished = false; - int16_t idx = -1; // Domoticz virtual sensor idx - - // strings to reduce flash memory usage (used more than twice) - static const char _name[]; - static const char _enabled[]; - static const char _readInterval[]; - static const char _parasite[]; - static const char _parasitePin[]; - static const char _domoticzIDX[]; - static const char _sensor[]; - static const char _temperature[]; - static const char _Temperature[]; - static const char _data_fx[]; - - //Dallas sensor quick (& dirty) reading. Credit to - Author: Peter Scargill, August 17th, 2013 - float readDallas(); - void requestTemperatures(); - void readTemperature(); - bool findSensor(); -#ifndef WLED_DISABLE_MQTT - void publishHomeAssistantAutodiscovery(); -#endif - - static UsermodTemperature* _instance; // to overcome nonstatic getTemperatureC() method and avoid UsermodManager::lookup(USERMOD_ID_TEMPERATURE); - - public: - - UsermodTemperature() { _instance = this; } - static UsermodTemperature *getInstance() { return UsermodTemperature::_instance; } - - /* - * API calls te enable data exchange between WLED modules - */ - inline float getTemperatureC() { return temperature; } - inline float getTemperatureF() { return temperature * 1.8f + 32.0f; } - float getTemperature(); - const char *getTemperatureUnit(); - uint16_t getId() override { return USERMOD_ID_TEMPERATURE; } - - void setup() override; - void loop() override; - //void connected() override; -#ifndef WLED_DISABLE_MQTT - void onMqttConnect(bool sessionPresent) override; -#endif - //void onUpdateBegin(bool init) override; - - //bool handleButton(uint8_t b) override; - //void handleOverlayDraw() override; - - void addToJsonInfo(JsonObject& root) override; - //void addToJsonState(JsonObject &root) override; - //void readFromJsonState(JsonObject &root) override; - void addToConfig(JsonObject &root) override; - bool readFromConfig(JsonObject &root) override; - - void appendConfigData() override; -}; - //Dallas sensor quick (& dirty) reading. Credit to - Author: Peter Scargill, August 17th, 2013 float UsermodTemperature::readDallas() { byte data[9]; diff --git a/usermods/Temperature/UsermodTemperature.h b/usermods/Temperature/UsermodTemperature.h new file mode 100644 index 00000000..2517a2b8 --- /dev/null +++ b/usermods/Temperature/UsermodTemperature.h @@ -0,0 +1,108 @@ +#pragma once +#include "wled.h" +#include "OneWire.h" + +//Pin defaults for QuinLed Dig-Uno if not overriden +#ifndef TEMPERATURE_PIN + #ifdef ARDUINO_ARCH_ESP32 + #define TEMPERATURE_PIN 18 + #else //ESP8266 boards + #define TEMPERATURE_PIN 14 + #endif +#endif + +// the frequency to check temperature, 1 minute +#ifndef USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL +#define USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL 60000 +#endif + +class UsermodTemperature : public Usermod { + + private: + + bool initDone = false; + OneWire *oneWire; + // GPIO pin used for sensor (with a default compile-time fallback) + int8_t temperaturePin = TEMPERATURE_PIN; + // measurement unit (true==°C, false==°F) + bool degC = true; + // using parasite power on the sensor + bool parasite = false; + int8_t parasitePin = -1; + // how often do we read from sensor? + unsigned long readingInterval = USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL; + // set last reading as "40 sec before boot", so first reading is taken after 20 sec + unsigned long lastMeasurement = UINT32_MAX - USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL; + // last time requestTemperatures was called + // used to determine when we can read the sensors temperature + // we have to wait at least 93.75 ms after requestTemperatures() is called + unsigned long lastTemperaturesRequest; + float temperature; + // indicates requestTemperatures has been called but the sensor measurement is not complete + bool waitingForConversion = false; + // flag set at startup if DS18B20 sensor not found, avoids trying to keep getting + // temperature if flashed to a board without a sensor attached + byte sensorFound; + + bool enabled = true; + + bool HApublished = false; + int16_t idx = -1; // Domoticz virtual sensor idx + + // strings to reduce flash memory usage (used more than twice) + static const char _name[]; + static const char _enabled[]; + static const char _readInterval[]; + static const char _parasite[]; + static const char _parasitePin[]; + static const char _domoticzIDX[]; + static const char _sensor[]; + static const char _temperature[]; + static const char _Temperature[]; + static const char _data_fx[]; + + //Dallas sensor quick (& dirty) reading. Credit to - Author: Peter Scargill, August 17th, 2013 + float readDallas(); + void requestTemperatures(); + void readTemperature(); + bool findSensor(); +#ifndef WLED_DISABLE_MQTT + void publishHomeAssistantAutodiscovery(); +#endif + + static UsermodTemperature* _instance; // to overcome nonstatic getTemperatureC() method and avoid UsermodManager::lookup(USERMOD_ID_TEMPERATURE); + + public: + + UsermodTemperature() { _instance = this; } + static UsermodTemperature *getInstance() { return UsermodTemperature::_instance; } + + /* + * API calls te enable data exchange between WLED modules + */ + inline float getTemperatureC() { return temperature; } + inline float getTemperatureF() { return temperature * 1.8f + 32.0f; } + float getTemperature(); + const char *getTemperatureUnit(); + uint16_t getId() override { return USERMOD_ID_TEMPERATURE; } + + void setup() override; + void loop() override; + //void connected() override; +#ifndef WLED_DISABLE_MQTT + void onMqttConnect(bool sessionPresent) override; +#endif + //void onUpdateBegin(bool init) override; + + //bool handleButton(uint8_t b) override; + //void handleOverlayDraw() override; + + void addToJsonInfo(JsonObject& root) override; + //void addToJsonState(JsonObject &root) override; + //void readFromJsonState(JsonObject &root) override; + void addToConfig(JsonObject &root) override; + bool readFromConfig(JsonObject &root) override; + + void appendConfigData() override; +}; + diff --git a/usermods/Temperature/platformio_override.ini b/usermods/Temperature/platformio_override.ini index ed35b7d4..a53b5974 100644 --- a/usermods/Temperature/platformio_override.ini +++ b/usermods/Temperature/platformio_override.ini @@ -1,6 +1,5 @@ ; Options ; ------- -; USERMOD_DALLASTEMPERATURE - define this to have this user mod included wled00\usermods_list.cpp ; USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL - the number of milliseconds between measurements, defaults to 60 seconds ; diff --git a/usermods/sht/ShtUsermod.h b/usermods/sht/ShtUsermod.h new file mode 100644 index 00000000..5dd83f46 --- /dev/null +++ b/usermods/sht/ShtUsermod.h @@ -0,0 +1,71 @@ +#pragma once +#include "wled.h" + +#ifdef WLED_DISABLE_MQTT +#error "This user mod requires MQTT to be enabled." +#endif + +#define USERMOD_SHT_TYPE_SHT30 0 +#define USERMOD_SHT_TYPE_SHT31 1 +#define USERMOD_SHT_TYPE_SHT35 2 +#define USERMOD_SHT_TYPE_SHT85 3 + +class SHT; + +class ShtUsermod : public Usermod +{ + private: + bool enabled = false; // Is usermod enabled or not + bool firstRunDone = false; // Remembers if the first config load run had been done + bool initDone = false; // Remembers if the mod has been completely initialised + bool haMqttDiscovery = false; // Is MQTT discovery enabled or not + bool haMqttDiscoveryDone = false; // Remembers if we already published the HA discovery topics + + // SHT vars + SHT *shtTempHumidSensor = nullptr; // Instance of SHT lib + byte shtType = 0; // SHT sensor type to be used. Default: SHT30 + byte unitOfTemp = 0; // Temperature unit to be used. Default: Celsius (0 = Celsius, 1 = Fahrenheit) + bool shtInitDone = false; // Remembers if SHT sensor has been initialised + bool shtReadDataSuccess = false; // Did we have a successful data read and is a valid temperature and humidity available? + const byte shtI2cAddress = 0x44; // i2c address of the sensor. 0x44 is the default for all SHT sensors. Change this, if needed + unsigned long shtLastTimeUpdated = 0; // Remembers when we read data the last time + bool shtDataRequested = false; // Reading data is done async. This remembers if we asked the sensor to read data + float shtCurrentTempC = 0.0f; // Last read temperature in Celsius + float shtCurrentHumidity = 0.0f; // Last read humidity in RH% + + + void initShtTempHumiditySensor(); + void cleanupShtTempHumiditySensor(); + void cleanup(); + inline bool isShtReady() { return shtInitDone; } // Checks if the SHT sensor has been initialised. + + void publishTemperatureAndHumidityViaMqtt(); + void publishHomeAssistantAutodiscovery(); + void appendDeviceToMqttDiscoveryMessage(JsonDocument& root); + + public: + // Strings to reduce flash memory usage (used more than twice) + static const char _name[]; + static const char _enabled[]; + static const char _shtType[]; + static const char _unitOfTemp[]; + static const char _haMqttDiscovery[]; + + void setup(); + void loop(); + void onMqttConnect(bool sessionPresent); + void appendConfigData(); + void addToConfig(JsonObject &root); + bool readFromConfig(JsonObject &root); + void addToJsonInfo(JsonObject& root); + + bool isEnabled() { return enabled; } + + float getTemperature(); + float getTemperatureC() { return roundf(shtCurrentTempC * 10.0f) / 10.0f; } + float getTemperatureF() { return (getTemperatureC() * 1.8f) + 32.0f; } + float getHumidity() { return roundf(shtCurrentHumidity * 10.0f) / 10.0f; } + const char* getUnitString(); + + uint16_t getId() { return USERMOD_ID_SHT; } +}; diff --git a/usermods/sht/library.json b/usermods/sht/library.json new file mode 100644 index 00000000..fc62941a --- /dev/null +++ b/usermods/sht/library.json @@ -0,0 +1,6 @@ +{ + "name:": "sht", + "dependencies": { + "robtillaart/SHT85": "~0.3.3" + } +} \ No newline at end of file diff --git a/usermods/sht/library.json.disabled b/usermods/sht/library.json.disabled deleted file mode 100644 index 330093bd..00000000 --- a/usermods/sht/library.json.disabled +++ /dev/null @@ -1,3 +0,0 @@ -{ - "name:": "sht" -} \ No newline at end of file diff --git a/usermods/sht/readme.md b/usermods/sht/readme.md index 0337805b..c2cc5a1f 100644 --- a/usermods/sht/readme.md +++ b/usermods/sht/readme.md @@ -5,26 +5,21 @@ Usermod to support various SHT i2c sensors like the SHT30, SHT31, SHT35 and SHT8 * "SHT85" by Rob Tillaart, v0.2 or higher: https://github.com/RobTillaart/SHT85 ## Usermod installation -Simply copy the below block (build task) to your `platformio_override.ini` and compile WLED using this new build task. Or use an existing one, add the buildflag `-D USERMOD_SHT` and the below library dependencies. + +Simply copy the below block (build task) to your `platformio_override.ini` and compile WLED using this new build task. Or use an existing one, add the custom_usermod `sht`. ESP32: ``` [env:custom_esp32dev_usermod_sht] extends = env:esp32dev -build_flags = ${common.build_flags_esp32} - -D USERMOD_SHT -lib_deps = ${esp32.lib_deps} - robtillaart/SHT85@~0.3.3 +custom_usermods = ${env:esp32dev.custom_usermods} sht ``` ESP8266: ``` [env:custom_d1_mini_usermod_sht] extends = env:d1_mini -build_flags = ${common.build_flags_esp8266} - -D USERMOD_SHT -lib_deps = ${esp8266.lib_deps} - robtillaart/SHT85@~0.3.3 +custom_usermods = ${env:d1_mini.custom_usermods} sht ``` ## MQTT Discovery for Home Assistant diff --git a/usermods/sht/sht.cpp b/usermods/sht/sht.cpp index 6a0e1ec4..e1eb9e88 100644 --- a/usermods/sht/sht.cpp +++ b/usermods/sht/sht.cpp @@ -1,73 +1,6 @@ -#include "wled.h" +#include "ShtUsermod.h" #include "SHT85.h" -#ifdef WLED_DISABLE_MQTT -#error "This user mod requires MQTT to be enabled." -#endif - -#define USERMOD_SHT_TYPE_SHT30 0 -#define USERMOD_SHT_TYPE_SHT31 1 -#define USERMOD_SHT_TYPE_SHT35 2 -#define USERMOD_SHT_TYPE_SHT85 3 - -class ShtUsermod : public Usermod -{ - private: - bool enabled = false; // Is usermod enabled or not - bool firstRunDone = false; // Remembers if the first config load run had been done - bool initDone = false; // Remembers if the mod has been completely initialised - bool haMqttDiscovery = false; // Is MQTT discovery enabled or not - bool haMqttDiscoveryDone = false; // Remembers if we already published the HA discovery topics - - // SHT vars - SHT *shtTempHumidSensor = nullptr; // Instance of SHT lib - byte shtType = 0; // SHT sensor type to be used. Default: SHT30 - byte unitOfTemp = 0; // Temperature unit to be used. Default: Celsius (0 = Celsius, 1 = Fahrenheit) - bool shtInitDone = false; // Remembers if SHT sensor has been initialised - bool shtReadDataSuccess = false; // Did we have a successful data read and is a valid temperature and humidity available? - const byte shtI2cAddress = 0x44; // i2c address of the sensor. 0x44 is the default for all SHT sensors. Change this, if needed - unsigned long shtLastTimeUpdated = 0; // Remembers when we read data the last time - bool shtDataRequested = false; // Reading data is done async. This remembers if we asked the sensor to read data - float shtCurrentTempC = 0.0f; // Last read temperature in Celsius - float shtCurrentHumidity = 0.0f; // Last read humidity in RH% - - - void initShtTempHumiditySensor(); - void cleanupShtTempHumiditySensor(); - void cleanup(); - inline bool isShtReady() { return shtInitDone; } // Checks if the SHT sensor has been initialised. - - void publishTemperatureAndHumidityViaMqtt(); - void publishHomeAssistantAutodiscovery(); - void appendDeviceToMqttDiscoveryMessage(JsonDocument& root); - - public: - // Strings to reduce flash memory usage (used more than twice) - static const char _name[]; - static const char _enabled[]; - static const char _shtType[]; - static const char _unitOfTemp[]; - static const char _haMqttDiscovery[]; - - void setup(); - void loop(); - void onMqttConnect(bool sessionPresent); - void appendConfigData(); - void addToConfig(JsonObject &root); - bool readFromConfig(JsonObject &root); - void addToJsonInfo(JsonObject& root); - - bool isEnabled() { return enabled; } - - float getTemperature(); - float getTemperatureC() { return roundf(shtCurrentTempC * 10.0f) / 10.0f; } - float getTemperatureF() { return (getTemperatureC() * 1.8f) + 32.0f; } - float getHumidity() { return roundf(shtCurrentHumidity * 10.0f) / 10.0f; } - const char* getUnitString(); - - uint16_t getId() { return USERMOD_ID_SHT; } -}; - // Strings to reduce flash memory usage (used more than twice) const char ShtUsermod::_name[] PROGMEM = "SHT-Sensor"; const char ShtUsermod::_enabled[] PROGMEM = "Enabled"; @@ -479,4 +412,4 @@ const char* ShtUsermod::getUnitString() { } static ShtUsermod sht; -REGISTER_USERMOD(sht); \ No newline at end of file +REGISTER_USERMOD(sht); From 1db3359b84ce25129729bbcf35ed5425e9bb12c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sat, 1 Feb 2025 12:04:24 +0100 Subject: [PATCH 284/463] Replace unsigned with size_t --- wled00/bus_manager.cpp | 18 +++++++++--------- wled00/bus_manager.h | 41 ++++++++++++++++++++--------------------- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index f7661c22..69cc63be 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -384,13 +384,13 @@ uint32_t IRAM_ATTR BusDigital::getPixelColor(unsigned pix) const { } } -unsigned BusDigital::getPins(uint8_t* pinArray) const { +size_t BusDigital::getPins(uint8_t* pinArray) const { unsigned numPins = is2Pin(_type) + 1; if (pinArray) for (unsigned i = 0; i < numPins; i++) pinArray[i] = _pins[i]; return numPins; } -unsigned BusDigital::getBusSize() const { +size_t BusDigital::getBusSize() const { return sizeof(BusDigital) + (isOk() ? PolyBus::getDataSize(_busPtr, _iType) + (_data ? _len * getNumberOfChannels() : 0) : 0); } @@ -573,7 +573,7 @@ uint32_t BusPwm::getPixelColor(unsigned pix) const { void BusPwm::show() { if (!_valid) return; - const unsigned numPins = getPins(); + const size_t numPins = getPins(); #ifdef ESP8266 const unsigned analogPeriod = F_CPU / _frequency; const unsigned maxBri = analogPeriod; // compute to clock cycle accuracy @@ -640,7 +640,7 @@ void BusPwm::show() { } } -unsigned BusPwm::getPins(uint8_t* pinArray) const { +size_t BusPwm::getPins(uint8_t* pinArray) const { if (!_valid) return 0; unsigned numPins = numPWMPins(_type); if (pinArray) for (unsigned i = 0; i < numPins; i++) pinArray[i] = _pins[i]; @@ -660,7 +660,7 @@ std::vector BusPwm::getLEDTypes() { } void BusPwm::deallocatePins() { - unsigned numPins = getPins(); + size_t numPins = getPins(); for (unsigned i = 0; i < numPins; i++) { PinManager::deallocatePin(_pins[i], PinOwner::BusPwm); if (!PinManager::isPinOk(_pins[i])) continue; @@ -716,7 +716,7 @@ void BusOnOff::show() { digitalWrite(_pin, _reversed ? !(bool)_data[0] : (bool)_data[0]); } -unsigned BusOnOff::getPins(uint8_t* pinArray) const { +size_t BusOnOff::getPins(uint8_t* pinArray) const { if (!_valid) return 0; if (pinArray) pinArray[0] = _pin; return 1; @@ -780,7 +780,7 @@ void BusNetwork::show() { _broadcastLock = false; } -unsigned BusNetwork::getPins(uint8_t* pinArray) const { +size_t BusNetwork::getPins(uint8_t* pinArray) const { if (pinArray) for (unsigned i = 0; i < 4; i++) pinArray[i] = _client[i]; return 4; } @@ -808,7 +808,7 @@ void BusNetwork::cleanup() { //utility to get the approx. memory usage of a given BusConfig -unsigned BusConfig::memUsage(unsigned nr) const { +size_t BusConfig::memUsage(unsigned nr) const { if (Bus::isVirtual(type)) { return sizeof(BusNetwork) + (count * Bus::getNumberOfChannels(type)); } else if (Bus::isDigital(type)) { @@ -821,7 +821,7 @@ unsigned BusConfig::memUsage(unsigned nr) const { } -unsigned BusManager::memUsage() { +size_t BusManager::memUsage() { // when ESP32, S2 & S3 use parallel I2S only the largest bus determines the total memory requirements for back buffers // front buffers are always allocated per bus unsigned size = 0; diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 74dfd4cf..65724003 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -10,7 +10,6 @@ #include "pin_manager.h" #include #include -#include #if __cplusplus >= 201402L using std::make_unique; @@ -103,7 +102,7 @@ class Bus { virtual void setBrightness(uint8_t b) { _bri = b; }; virtual void setColorOrder(uint8_t co) {} virtual uint32_t getPixelColor(unsigned pix) const { return 0; } - virtual unsigned getPins(uint8_t* pinArray = nullptr) const { return 0; } + virtual size_t getPins(uint8_t* pinArray = nullptr) const { return 0; } virtual uint16_t getLength() const { return isOk() ? _len : 0; } virtual uint8_t getColorOrder() const { return COL_ORDER_RGB; } virtual unsigned skippedLeds() const { return 0; } @@ -111,7 +110,7 @@ class Bus { virtual uint16_t getLEDCurrent() const { return 0; } virtual uint16_t getUsedCurrent() const { return 0; } virtual uint16_t getMaxCurrent() const { return 0; } - virtual unsigned getBusSize() const { return sizeof(Bus); } + virtual size_t getBusSize() const { return sizeof(Bus); } inline bool hasRGB() const { return _hasRgb; } inline bool hasWhite() const { return _hasWhite; } @@ -127,7 +126,7 @@ class Bus { inline void setStart(uint16_t start) { _start = start; } inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; } inline uint8_t getAutoWhiteMode() const { return _autoWhiteMode; } - inline unsigned getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); } + inline size_t getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); } inline uint16_t getStart() const { return _start; } inline uint8_t getType() const { return _type; } inline bool isOk() const { return _valid; } @@ -136,8 +135,8 @@ class Bus { inline bool containsPixel(uint16_t pix) const { return pix >= _start && pix < _start + _len; } static inline std::vector getLEDTypes() { return {{TYPE_NONE, "", PSTR("None")}}; } // not used. just for reference for derived classes - static constexpr unsigned getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK - static constexpr unsigned getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); } + static constexpr size_t getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK + static constexpr size_t getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); } static constexpr bool hasRGB(uint8_t type) { return !((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_ANALOG_1CH || type == TYPE_ANALOG_2CH || type == TYPE_ONOFF); } @@ -225,13 +224,13 @@ class BusDigital : public Bus { void setColorOrder(uint8_t colorOrder) override; [[gnu::hot]] uint32_t getPixelColor(unsigned pix) const override; uint8_t getColorOrder() const override { return _colorOrder; } - unsigned getPins(uint8_t* pinArray = nullptr) const override; + size_t getPins(uint8_t* pinArray = nullptr) const override; unsigned skippedLeds() const override { return _skip; } uint16_t getFrequency() const override { return _frequencykHz; } uint16_t getLEDCurrent() const override { return _milliAmpsPerLed; } uint16_t getUsedCurrent() const override { return _milliAmpsTotal; } uint16_t getMaxCurrent() const override { return _milliAmpsMax; } - unsigned getBusSize() const override; + size_t getBusSize() const override; void begin() override; void cleanup(); @@ -271,9 +270,9 @@ class BusPwm : public Bus { void setPixelColor(unsigned pix, uint32_t c) override; uint32_t getPixelColor(unsigned pix) const override; //does no index check - unsigned getPins(uint8_t* pinArray = nullptr) const override; + size_t getPins(uint8_t* pinArray = nullptr) const override; uint16_t getFrequency() const override { return _frequency; } - unsigned getBusSize() const override { return sizeof(BusPwm); } + size_t getBusSize() const override { return sizeof(BusPwm); } void show() override; inline void cleanup() { deallocatePins(); _data = nullptr; } @@ -299,8 +298,8 @@ class BusOnOff : public Bus { void setPixelColor(unsigned pix, uint32_t c) override; uint32_t getPixelColor(unsigned pix) const override; - unsigned getPins(uint8_t* pinArray) const override; - unsigned getBusSize() const override { return sizeof(BusOnOff); } + size_t getPins(uint8_t* pinArray) const override; + size_t getBusSize() const override { return sizeof(BusOnOff); } void show() override; inline void cleanup() { PinManager::deallocatePin(_pin, PinOwner::BusOnOff); _data = nullptr; } @@ -320,10 +319,10 @@ class BusNetwork : public Bus { bool canShow() const override { return !_broadcastLock; } // this should be a return value from UDP routine if it is still sending data out [[gnu::hot]] void setPixelColor(unsigned pix, uint32_t c) override; [[gnu::hot]] uint32_t getPixelColor(unsigned pix) const override; - unsigned getPins(uint8_t* pinArray = nullptr) const override; - unsigned getBusSize() const override { return sizeof(BusNetwork) + (isOk() ? _len * _UDPchannels : 0); } - void show() override; - void cleanup(); + size_t getPins(uint8_t* pinArray = nullptr) const override; + size_t getBusSize() const override { return sizeof(BusNetwork) + (isOk() ? _len * _UDPchannels : 0); } + void show() override; + void cleanup(); static std::vector getLEDTypes(); @@ -381,7 +380,7 @@ struct BusConfig { return true; } - unsigned memUsage(unsigned nr = 0) const; + size_t memUsage(unsigned nr = 0) const; }; @@ -405,13 +404,13 @@ namespace BusManager { #ifdef ESP32_DATA_IDLE_HIGH void esp32RMTInvertIdle() ; #endif - inline uint8_t getNumVirtualBusses() { - int j = 0; + inline size_t getNumVirtualBusses() { + size_t j = 0; for (const auto &bus : busses) j += bus->isVirtual(); return j; } - unsigned memUsage(); + size_t memUsage(); inline uint16_t currentMilliamps() { return _gMilliAmpsUsed + MA_FOR_ESP; } //inline uint16_t ablMilliampsMax() { unsigned sum = 0; for (auto &bus : busses) sum += bus->getMaxCurrent(); return sum; } inline uint16_t ablMilliampsMax() { return _gMilliAmpsMax; } // used for compatibility reasons (and enabling virtual global ABL) @@ -438,7 +437,7 @@ namespace BusManager { void setSegmentCCT(int16_t cct, bool allowWBCorrection = false); inline int16_t getSegmentCCT() { return Bus::getCCT(); } inline Bus* getBus(size_t busNr) { return busNr < busses.size() ? busses[busNr].get() : nullptr; } - inline uint8_t getNumBusses() { return busses.size(); } + inline size_t getNumBusses() { return busses.size(); } //semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit()) inline uint16_t getTotalLength(bool onlyPhysical = false) { From d56ded8c18a5f46a4e9e9067a1b50b58fd5b07e5 Mon Sep 17 00:00:00 2001 From: Woody <27882680+w00000dy@users.noreply.github.com> Date: Sat, 1 Feb 2025 22:52:31 +0100 Subject: [PATCH 285/463] npm update --- package-lock.json | 32 ++++++++++++++++---------------- package.json | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index a7beb9c4..4630280d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,14 +11,14 @@ "dependencies": { "clean-css": "^5.3.3", "html-minifier-terser": "^7.2.0", - "nodemon": "^3.1.7", + "nodemon": "^3.1.9", "web-resource-inliner": "^7.0.0" } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", @@ -215,9 +215,9 @@ "license": "MIT" }, "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -549,9 +549,9 @@ } }, "node_modules/nodemon": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.7.tgz", - "integrity": "sha512-hLj7fuMow6f0lbB0cD14Lz2xNjwsyruH251Pk4t/yIitCFJbmY1myuLlHm/q06aST4jg6EgAh74PIBBrRqpVAQ==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz", + "integrity": "sha512-hdr1oIb2p6ZSxu3PB2JWWYS7ZQ0qvaZsc3hK8DR8f02kRzc8rjYmxAIvdz+aYC+8F2IjNaB7HMcSDg8nQpJxyg==", "license": "MIT", "dependencies": { "chokidar": "^3.5.2", @@ -645,9 +645,9 @@ } }, "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.0.tgz", + "integrity": "sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -700,9 +700,9 @@ } }, "node_modules/terser": { - "version": "5.36.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", - "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz", + "integrity": "sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==", "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", diff --git a/package.json b/package.json index eb05066e..78bd4036 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,6 @@ "clean-css": "^5.3.3", "html-minifier-terser": "^7.2.0", "web-resource-inliner": "^7.0.0", - "nodemon": "^3.1.7" + "nodemon": "^3.1.9" } } From 58962f84707e53f3d87e8bd66343d0cf73997adc Mon Sep 17 00:00:00 2001 From: Woody <27882680+w00000dy@users.noreply.github.com> Date: Sat, 1 Feb 2025 22:56:06 +0100 Subject: [PATCH 286/463] npm update --- package-lock.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8ebc6a99..b5e14158 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "wled", - "version": "0.16.0-dev", + "version": "0.16.0-alpha", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "wled", - "version": "0.16.0-dev", + "version": "0.16.0-alpha", "license": "ISC", "dependencies": { "clean-css": "^5.3.3", From 2eff6b7a3a202638ac96b33121cea8b5ee3b1fd9 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Mon, 3 Feb 2025 17:57:09 +0000 Subject: [PATCH 287/463] usermod/sensors_to_mqtt: Add explicit dep This mod includes a header from the Adafruit Unified Sensor library inherited by its target sensor libraries. This isn't reliably picked up by PlatformIO's dependency finder. Add an explicit dep to ensure build stability. --- usermods/sensors_to_mqtt/library.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/usermods/sensors_to_mqtt/library.json b/usermods/sensors_to_mqtt/library.json index 731f57b2..d38c794e 100644 --- a/usermods/sensors_to_mqtt/library.json +++ b/usermods/sensors_to_mqtt/library.json @@ -4,6 +4,7 @@ "dependencies": { "adafruit/Adafruit BMP280 Library":"2.6.8", "adafruit/Adafruit CCS811 Library":"1.1.3", - "adafruit/Adafruit Si7021 Library":"1.5.3" + "adafruit/Adafruit Si7021 Library":"1.5.3", + "adafruit/Adafruit Unified Sensor":"^1.1.15" } } From 1688546519a4bcc130a3d1936dfe09109e576450 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Mon, 3 Feb 2025 18:48:07 +0000 Subject: [PATCH 288/463] Fix RTC usermod --- usermods/RTC/{library.json.disabled => library.json} | 0 wled00/src/dependencies/time/DS1307RTC.h | 1 + 2 files changed, 1 insertion(+) rename usermods/RTC/{library.json.disabled => library.json} (100%) diff --git a/usermods/RTC/library.json.disabled b/usermods/RTC/library.json similarity index 100% rename from usermods/RTC/library.json.disabled rename to usermods/RTC/library.json diff --git a/wled00/src/dependencies/time/DS1307RTC.h b/wled00/src/dependencies/time/DS1307RTC.h index 551ae996..bc272701 100644 --- a/wled00/src/dependencies/time/DS1307RTC.h +++ b/wled00/src/dependencies/time/DS1307RTC.h @@ -7,6 +7,7 @@ #define DS1307RTC_h #include "TimeLib.h" +#include "Wire.h" // library interface description class DS1307RTC From f72b5d04e8318fb43505217d6ce3d168a1a540a1 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Mon, 3 Feb 2025 19:35:12 +0000 Subject: [PATCH 289/463] usermod/pixels_dice_try: Add missing dep The "arduino-pixels-dice" library needs the ESP32 BLE subsystem, but doesn't explicitly depend on it. --- usermods/pixels_dice_tray/library.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/usermods/pixels_dice_tray/library.json b/usermods/pixels_dice_tray/library.json index ce08b801..e052fd60 100644 --- a/usermods/pixels_dice_tray/library.json +++ b/usermods/pixels_dice_tray/library.json @@ -2,6 +2,7 @@ "name:": "pixels_dice_tray", "build": { "libArchive": false}, "dependencies": { - "arduino-pixels-dice":"https://github.com/axlan/arduino-pixels-dice.git" + "arduino-pixels-dice":"https://github.com/axlan/arduino-pixels-dice.git", + "ESP32 BLE Arduino":"*" } } From 64a02b705aae8d9ef6f7ed5e33af3046ed947075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Tue, 4 Feb 2025 18:42:38 +0100 Subject: [PATCH 290/463] Blending style bugfix (wrong limit) SoundSim bugfix (missing options) --- wled00/data/index.js | 2 ++ wled00/json.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/wled00/data/index.js b/wled00/data/index.js index dc94cf42..8237e691 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -807,6 +807,8 @@ function populateSegments(s) `
`+ `
`; cn += `
`+ diff --git a/wled00/json.cpp b/wled00/json.cpp index d4f0d777..20030746 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -338,7 +338,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) #ifndef WLED_DISABLE_MODE_BLEND blendingStyle = root[F("bs")] | blendingStyle; - blendingStyle = constrain(blendingStyle, 0, BLEND_STYLE_COUNT-1); + blendingStyle &= 0x1F; #endif // temporary transition (applies only once) From 373f4cfefdee720173043072e35af5e3208c4005 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 6 Feb 2025 06:41:02 +0100 Subject: [PATCH 291/463] removed unnecessary lambda function performance is the same, the function just makes it a bit confusing. --- wled00/FX_2Dfcn.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 67624bac..b8f845bb 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -166,16 +166,11 @@ void IRAM_ATTR_YN Segment::_setPixelColorXY_raw(const int& x, const int& y, uint // Apply mirroring if (mirror || mirror_y) { - auto setMirroredPixel = [&](int mx, int my) { - strip.setPixelColorXY(mx, my, col); - }; - const int mirrorX = start + width() - x - 1; const int mirrorY = startY + height() - y - 1; - - if (mirror) setMirroredPixel(transpose ? baseX : mirrorX, transpose ? mirrorY : baseY); - if (mirror_y) setMirroredPixel(transpose ? mirrorX : baseX, transpose ? baseY : mirrorY); - if (mirror && mirror_y) setMirroredPixel(mirrorX, mirrorY); + if (mirror) strip.setPixelColorXY(transpose ? baseX : mirrorX, transpose ? mirrorY : baseY, col); + if (mirror_y) strip.setPixelColorXY(transpose ? mirrorX : baseX, transpose ? baseY : mirrorY, col); + if (mirror && mirror_y) strip.setPixelColorXY(mirrorX, mirrorY, col); } } From 3baa4f8223de256b2c6f8d1e46da8ddc51101237 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 27 Jan 2025 19:15:04 +0100 Subject: [PATCH 292/463] improved speed and fixed issue - fixed issue: blending was also done when color was on a key-index-color which is now skipped - speed improvement: conversion is skipped if color is key-color --- wled00/colors.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index f154a1ae..d88cfe97 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -87,29 +87,31 @@ uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) uint32_t ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brightness, TBlendType blendType) { if (blendType == LINEARBLEND_NOWRAP) { - index = (index*240) >> 8; // Blend range is affected by lo4 blend of values, remap to avoid wrapping + index = (index * 0xF0) >> 8; // Blend range is affected by lo4 blend of values, remap to avoid wrapping } + uint32_t clr32; unsigned hi4 = byte(index) >> 4; - const CRGB* entry = (CRGB*)((uint8_t*)(&(pal[0])) + (hi4 * sizeof(CRGB))); - unsigned red1 = entry->r; - unsigned green1 = entry->g; - unsigned blue1 = entry->b; - if (blendType != NOBLEND) { + unsigned lo4 = (index & 0x0F); + const CRGB* entry = (CRGB*)&(pal[0]) + hi4; + if(lo4 && blendType != NOBLEND) { + unsigned red1 = entry->r; + unsigned green1 = entry->g; + unsigned blue1 = entry->b; if (hi4 == 15) entry = &(pal[0]); else ++entry; - unsigned f2 = ((index & 0x0F) << 4) + 1; // +1 so we scale by 256 as a max value, then result can just be shifted by 8 - unsigned f1 = (257 - f2); // f2 is 1 minimum, so this is 256 max - red1 = (red1 * f1 + (unsigned)entry->r * f2) >> 8; + unsigned f2 = (lo4 << 4); + unsigned f1 = 256 - f2; + red1 = (red1 * f1 + (unsigned)entry->r * f2) >> 8; // note: using color_blend() is 20% slower green1 = (green1 * f1 + (unsigned)entry->g * f2) >> 8; blue1 = (blue1 * f1 + (unsigned)entry->b * f2) >> 8; + clr32 = RGBW32(red1, green1, blue1, 0); } + else + clr32 = RGBW32(entry->r, entry->g, entry->b, 0); if (brightness < 255) { // note: zero checking could be done to return black but that is hardly ever used so it is omitted - uint32_t scale = brightness + 1; // adjust for rounding (bitshift) - red1 = (red1 * scale) >> 8; - green1 = (green1 * scale) >> 8; - blue1 = (blue1 * scale) >> 8; + clr32 = color_fade(clr32, brightness); } - return RGBW32(red1,green1,blue1,0); + return clr32; } void setRandomColor(byte* rgb) From b363b6151c8105e5f227fa936556b6b61340be28 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Tue, 28 Jan 2025 11:26:44 +0100 Subject: [PATCH 293/463] revert using color_fade() as it is slower - ran a few more tests, it is 30% faster like it was originally so reverting. The conversion to 32bit color appears to be wasteful in resources. --- wled00/colors.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index d88cfe97..ae60caca 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -86,6 +86,7 @@ uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) // 1:1 replacement of fastled function optimized for ESP, slightly faster, more accurate and uses less flash (~ -200bytes) uint32_t ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brightness, TBlendType blendType) { + if (blendType == LINEARBLEND_NOWRAP) { index = (index * 0xF0) >> 8; // Blend range is affected by lo4 blend of values, remap to avoid wrapping } @@ -93,25 +94,25 @@ uint32_t ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t unsigned hi4 = byte(index) >> 4; unsigned lo4 = (index & 0x0F); const CRGB* entry = (CRGB*)&(pal[0]) + hi4; + unsigned red1 = entry->r; + unsigned green1 = entry->g; + unsigned blue1 = entry->b; if(lo4 && blendType != NOBLEND) { - unsigned red1 = entry->r; - unsigned green1 = entry->g; - unsigned blue1 = entry->b; if (hi4 == 15) entry = &(pal[0]); else ++entry; unsigned f2 = (lo4 << 4); unsigned f1 = 256 - f2; - red1 = (red1 * f1 + (unsigned)entry->r * f2) >> 8; // note: using color_blend() is 20% slower + red1 = (red1 * f1 + (unsigned)entry->r * f2) >> 8; // note: using color_blend() is 20% slower green1 = (green1 * f1 + (unsigned)entry->g * f2) >> 8; blue1 = (blue1 * f1 + (unsigned)entry->b * f2) >> 8; - clr32 = RGBW32(red1, green1, blue1, 0); } - else - clr32 = RGBW32(entry->r, entry->g, entry->b, 0); if (brightness < 255) { // note: zero checking could be done to return black but that is hardly ever used so it is omitted - clr32 = color_fade(clr32, brightness); + uint32_t scale = brightness + 1; // adjust for rounding (bitshift) + red1 = (red1 * scale) >> 8; // note: using color_fade() is 30% slower + green1 = (green1 * scale) >> 8; + blue1 = (blue1 * scale) >> 8; } - return clr32; + return RGBW32(red1,green1,blue1,0); } void setRandomColor(byte* rgb) From e088f4654ab6cdf8c0ed8c82bb072bda6c7e377c Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Tue, 28 Jan 2025 11:30:07 +0100 Subject: [PATCH 294/463] removed unnecessary changes --- wled00/colors.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index ae60caca..500687b2 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -86,11 +86,9 @@ uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) // 1:1 replacement of fastled function optimized for ESP, slightly faster, more accurate and uses less flash (~ -200bytes) uint32_t ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brightness, TBlendType blendType) { - if (blendType == LINEARBLEND_NOWRAP) { index = (index * 0xF0) >> 8; // Blend range is affected by lo4 blend of values, remap to avoid wrapping } - uint32_t clr32; unsigned hi4 = byte(index) >> 4; unsigned lo4 = (index & 0x0F); const CRGB* entry = (CRGB*)&(pal[0]) + hi4; From 8c717537c489aae54c0f03091efc44fd6db0965e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Thu, 6 Feb 2025 15:12:04 +0100 Subject: [PATCH 295/463] Lambda XY() --- wled00/FX.cpp | 5 ++++- wled00/FX.h | 2 -- wled00/FX_2Dfcn.cpp | 8 -------- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index b9ead141..216cd7a3 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -4854,7 +4854,6 @@ static const char _data_FX_MODE_FLOWSTRIPE[] PROGMEM = "Flow Stripe@Hue speed,Ef #ifndef WLED_DISABLE_2D /////////////////////////////////////////////////////////////////////////////// //*************************** 2D routines *********************************** -#define XY(x,y) SEGMENT.XY(x,y) // Black hole @@ -5103,6 +5102,7 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https: const int cols = SEG_W; const int rows = SEG_H; + const auto XY = [&](int x, int y) { return (x%cols) + (y%rows) * cols; }; const unsigned dataSize = sizeof(CRGB) * SEGMENT.length(); // using width*height prevents reallocation if mirroring is enabled const int crcBufferLen = 2; //(SEGMENT.width() + SEGMENT.height())*71/100; // roughly sqrt(2)/2 for better repetition detection (Ewowi) @@ -5376,6 +5376,7 @@ uint16_t mode_2Dmatrix(void) { // Matrix2D. By Jeremy Williams. const int cols = SEG_W; const int rows = SEG_H; + const auto XY = [&](int x, int y) { return (x%cols) + (y%rows) * cols; }; unsigned dataSize = (SEGMENT.length()+7) >> 3; //1 bit per LED for trails if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed @@ -7473,6 +7474,7 @@ uint16_t mode_2Dsoap() { const int cols = SEG_W; const int rows = SEG_H; + const auto XY = [&](int x, int y) { return (x%cols) + (y%rows) * cols; }; const size_t dataSize = SEGMENT.width() * SEGMENT.height() * sizeof(uint8_t); // prevent reallocation if mirrored or grouped if (!SEGENV.allocateData(dataSize + sizeof(uint32_t)*3)) return mode_static(); //allocation failed @@ -7585,6 +7587,7 @@ uint16_t mode_2Doctopus() { const int cols = SEG_W; const int rows = SEG_H; + const auto XY = [&](int x, int y) { return (x%cols) + (y%rows) * cols; }; const uint8_t mapp = 180 / MAX(cols,rows); typedef struct { diff --git a/wled00/FX.h b/wled00/FX.h index 3b1f8f8f..1a52ad95 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -674,7 +674,6 @@ typedef struct Segment { } #ifndef WLED_DISABLE_2D inline bool is2D() const { return (width()>1 && height()>1); } - [[gnu::hot]] int XY(int x, int y) const; // support function to get relative index within segment [[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c) const; // set relative pixel within segment with color inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) const { setPixelColorXY(int(x), int(y), c); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) const { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } @@ -712,7 +711,6 @@ typedef struct Segment { inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); } #else inline constexpr bool is2D() const { return false; } - inline int XY(int x, int y) const { return x; } inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(x, c); } inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColor(int(x), c); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColor(x, RGBW32(r,g,b,w)); } diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index b8f845bb..89312333 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -145,14 +145,6 @@ void WS2812FX::setUpMatrix() { #ifndef WLED_DISABLE_2D -// XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element) -int IRAM_ATTR_YN Segment::XY(int x, int y) const -{ - const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive) - const int vH = vHeight(); // segment height in logical pixels (is always >= 1) - return isActive() ? (x%vW) + (y%vH) * vW : 0; -} - // raw setColor function without checks (checks are done in setPixelColorXY()) void IRAM_ATTR_YN Segment::_setPixelColorXY_raw(const int& x, const int& y, uint32_t& col) const { From 2431f2058b14c1cbcbb0e1212e83a485a48e571e Mon Sep 17 00:00:00 2001 From: Will Miles Date: Thu, 6 Feb 2025 22:23:12 -0500 Subject: [PATCH 296/463] load_usermods: Split on any whitespace This allows the common newline syntax in platformio --- pio-scripts/load_usermods.py | 2 +- usermods/PWM_fan/setup_deps.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pio-scripts/load_usermods.py b/pio-scripts/load_usermods.py index 4ac57ba3..ab3c6476 100644 --- a/pio-scripts/load_usermods.py +++ b/pio-scripts/load_usermods.py @@ -35,7 +35,7 @@ if usermods: deps = env.GetProjectOption('lib_deps') src_dir = proj.get("platformio", "src_dir") src_dir = src_dir.replace('\\','/') - mod_paths = {mod: find_usermod(mod) for mod in usermods.split(" ")} + mod_paths = {mod: find_usermod(mod) for mod in usermods.split()} usermods = [f"{mod} = symlink://{path}" for mod, path in mod_paths.items()] proj.set("env:" + env['PIOENV'], 'lib_deps', deps + usermods) # Force usermods to be installed in to the environment build state before the LDF runs diff --git a/usermods/PWM_fan/setup_deps.py b/usermods/PWM_fan/setup_deps.py index dd29e464..2f76ba85 100644 --- a/usermods/PWM_fan/setup_deps.py +++ b/usermods/PWM_fan/setup_deps.py @@ -1,7 +1,7 @@ Import('env') -usermods = env.GetProjectOption("custom_usermods","").split(" ") +usermods = env.GetProjectOption("custom_usermods","").split() # Check for dependencies if "Temperature" in usermods: env.Append(CPPDEFINES=[("USERMOD_DALLASTEMPERATURE")]) From d0b599781df00bc3ef2b6e24181116bb818361a9 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Thu, 6 Feb 2025 22:24:53 -0500 Subject: [PATCH 297/463] Fix up BME280_v2 usermod Minor compile correctness tweak --- usermods/BME280_v2/BME280_v2.cpp | 10 +++++----- usermods/BME280_v2/README.md | 11 ++--------- .../BME280_v2/{library.json.disabled => library.json} | 0 3 files changed, 7 insertions(+), 14 deletions(-) rename usermods/BME280_v2/{library.json.disabled => library.json} (100%) diff --git a/usermods/BME280_v2/BME280_v2.cpp b/usermods/BME280_v2/BME280_v2.cpp index 05aeca55..dd585904 100644 --- a/usermods/BME280_v2/BME280_v2.cpp +++ b/usermods/BME280_v2/BME280_v2.cpp @@ -239,7 +239,7 @@ public: // from the UI and values read from sensor, then publish to broker if (temperature != lastTemperature || PublishAlways) { - publishMqtt("temperature", String(temperature, TemperatureDecimals).c_str()); + publishMqtt("temperature", String(temperature, (unsigned) TemperatureDecimals).c_str()); } lastTemperature = temperature; // Update last sensor temperature for next loop @@ -252,17 +252,17 @@ public: if (humidity != lastHumidity || PublishAlways) { - publishMqtt("humidity", String(humidity, HumidityDecimals).c_str()); + publishMqtt("humidity", String(humidity, (unsigned) HumidityDecimals).c_str()); } if (heatIndex != lastHeatIndex || PublishAlways) { - publishMqtt("heat_index", String(heatIndex, TemperatureDecimals).c_str()); + publishMqtt("heat_index", String(heatIndex, (unsigned) TemperatureDecimals).c_str()); } if (dewPoint != lastDewPoint || PublishAlways) { - publishMqtt("dew_point", String(dewPoint, TemperatureDecimals).c_str()); + publishMqtt("dew_point", String(dewPoint, (unsigned) TemperatureDecimals).c_str()); } lastHumidity = humidity; @@ -279,7 +279,7 @@ public: if (pressure != lastPressure || PublishAlways) { - publishMqtt("pressure", String(pressure, PressureDecimals).c_str()); + publishMqtt("pressure", String(pressure, (unsigned) PressureDecimals).c_str()); } lastPressure = pressure; diff --git a/usermods/BME280_v2/README.md b/usermods/BME280_v2/README.md index a4fc229a..0daea582 100644 --- a/usermods/BME280_v2/README.md +++ b/usermods/BME280_v2/README.md @@ -22,7 +22,6 @@ Dependencies - Libraries - `BME280@~3.0.0` (by [finitespace](https://github.com/finitespace/BME280)) - `Wire` - - These must be added under `lib_deps` in your `platform.ini` (or `platform_override.ini`). - Data is published over MQTT - make sure you've enabled the MQTT sync interface. - This usermod also writes to serial (GPIO1 on ESP8266). Please make sure nothing else is listening to the serial TX pin or your board will get confused by log messages! @@ -40,17 +39,11 @@ Methods also exist to read the read/calculated values from other WLED modules th # Compiling -To enable, compile with `USERMOD_BME280` defined (e.g. in `platformio_override.ini`) +To enable, add `BME280_v2` to your `custom_usermods` (e.g. in `platformio_override.ini`) ```ini [env:usermod_bme280_d1_mini] extends = env:d1_mini -build_flags = - ${common.build_flags_esp8266} - -D USERMOD_BME280 -lib_deps = - ${esp8266.lib_deps} - BME280@~3.0.0 - Wire +custom_usermods = ${env:d1_mini.custom_usermods} BME280_v2 ``` diff --git a/usermods/BME280_v2/library.json.disabled b/usermods/BME280_v2/library.json similarity index 100% rename from usermods/BME280_v2/library.json.disabled rename to usermods/BME280_v2/library.json From e6910f732f645512425ded8dfd2d757ea9082c14 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Thu, 6 Feb 2025 22:25:39 -0500 Subject: [PATCH 298/463] Disable EleksTube_IPS usermod For some reason, building it seems to consume 300kb of SRAM?? Probably there's still something wrong with the configuration. --- usermods/EleksTube_IPS/{library.json => library.json.disabled} | 1 + 1 file changed, 1 insertion(+) rename usermods/EleksTube_IPS/{library.json => library.json.disabled} (63%) diff --git a/usermods/EleksTube_IPS/library.json b/usermods/EleksTube_IPS/library.json.disabled similarity index 63% rename from usermods/EleksTube_IPS/library.json rename to usermods/EleksTube_IPS/library.json.disabled index 2cd1de6f..eddd12b8 100644 --- a/usermods/EleksTube_IPS/library.json +++ b/usermods/EleksTube_IPS/library.json.disabled @@ -4,3 +4,4 @@ "TFT_eSPI" : "2.5.33" } } +# Seems to add 300kb to the RAM requirement??? From c57be770397c3d974b54e8bb8974af361a41c403 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Thu, 6 Feb 2025 22:26:45 -0500 Subject: [PATCH 299/463] Fix sensor usermod globals These can be static locals instead; allows these usermods to build and link together. --- usermods/Si7021_MQTT_HA/Si7021_MQTT_HA.cpp | 2 +- usermods/Si7021_MQTT_HA/library.json | 3 ++- usermods/sensors_to_mqtt/sensors_to_mqtt.cpp | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/usermods/Si7021_MQTT_HA/Si7021_MQTT_HA.cpp b/usermods/Si7021_MQTT_HA/Si7021_MQTT_HA.cpp index 44218d59..7845658a 100644 --- a/usermods/Si7021_MQTT_HA/Si7021_MQTT_HA.cpp +++ b/usermods/Si7021_MQTT_HA/Si7021_MQTT_HA.cpp @@ -9,7 +9,7 @@ #error "This user mod requires MQTT to be enabled." #endif -Adafruit_Si7021 si7021; +static Adafruit_Si7021 si7021; class Si7021_MQTT_HA : public Usermod { diff --git a/usermods/Si7021_MQTT_HA/library.json b/usermods/Si7021_MQTT_HA/library.json index 7b9ac4d7..5d7aa300 100644 --- a/usermods/Si7021_MQTT_HA/library.json +++ b/usermods/Si7021_MQTT_HA/library.json @@ -1,6 +1,7 @@ { "name:": "Si7021_MQTT_HA", "dependencies": { - "finitespace/BME280":"3.0.0" + "finitespace/BME280":"3.0.0", + "adafruit/Adafruit Si7021 Library" : "1.5.3" } } \ No newline at end of file diff --git a/usermods/sensors_to_mqtt/sensors_to_mqtt.cpp b/usermods/sensors_to_mqtt/sensors_to_mqtt.cpp index 343fd08b..5f7da97a 100644 --- a/usermods/sensors_to_mqtt/sensors_to_mqtt.cpp +++ b/usermods/sensors_to_mqtt/sensors_to_mqtt.cpp @@ -9,9 +9,9 @@ #error "This user mod requires MQTT to be enabled." #endif -Adafruit_BMP280 bmp; -Adafruit_Si7021 si7021; -Adafruit_CCS811 ccs811; +static Adafruit_BMP280 bmp; +static Adafruit_Si7021 si7021; +static Adafruit_CCS811 ccs811; class UserMod_SensorsToMQTT : public Usermod { From 078a054dbdb173f447e0c9eadb174b4898178b5d Mon Sep 17 00:00:00 2001 From: Will Miles Date: Fri, 7 Feb 2025 04:12:07 +0000 Subject: [PATCH 300/463] usermods/pixels_dice_tray: Fix BLE dependency --- usermods/pixels_dice_tray/library.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usermods/pixels_dice_tray/library.json b/usermods/pixels_dice_tray/library.json index e052fd60..5043c0cf 100644 --- a/usermods/pixels_dice_tray/library.json +++ b/usermods/pixels_dice_tray/library.json @@ -3,6 +3,6 @@ "build": { "libArchive": false}, "dependencies": { "arduino-pixels-dice":"https://github.com/axlan/arduino-pixels-dice.git", - "ESP32 BLE Arduino":"*" + "BLE":"*" } } From 2fe809f15acd0eb75f65bc59bb9d30c7ce836fb4 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Fri, 7 Feb 2025 09:46:06 +0100 Subject: [PATCH 301/463] consolidated double loops into function - saves ~500 bytes of flash - slight speed improvement --- wled00/FX.cpp | 78 +++++++++++++++++++++------------------------------ 1 file changed, 32 insertions(+), 46 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 216cd7a3..51726215 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7468,7 +7468,36 @@ static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@ //Soap //@Stepko //Idea from https://www.youtube.com/watch?v=DiHBgITrZck&ab_channel=StefanPetrick -// adapted for WLED by @blazoncek +// adapted for WLED by @blazoncek, optimization by @dedehai +void soapProcessPixels(bool isRow, int size1, int size2, uint8_t* noise3d, int amplitude, int shift, CRGB* ledsbuff) { + for (int i = 0; i < size1; i++) { + int amount = ((int)noise3d[isRow ? XY(0, i) : XY(i, 0)] - 128) * 2 * amplitude + 256 * shift; + int delta = abs(amount) >> 8; + int fraction = abs(amount) & 255; + for (int j = 0; j < size2; j++) { + int zD, zF; + if (amount < 0) { + zD = j - delta; + zF = zD - 1; + } else { + zD = j + delta; + zF = zD + 1; + } + CRGB PixelA = CRGB::Black; + if ((zD >= 0) && (zD < size2)) PixelA = isRow ? SEGMENT.getPixelColorXY(zD, i) : SEGMENT.getPixelColorXY(i, zD); + else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? XY(abs(zD), i) : XY(i, abs(zD))] * 3); + CRGB PixelB = CRGB::Black; + if ((zF >= 0) && (zF < size2)) PixelB = isRow ? SEGMENT.getPixelColorXY(zF, i) : SEGMENT.getPixelColorXY(i, zF); + else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? XY(abs(zF), i) : XY(i, abs(zF))] * 3); + ledsbuff[j] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction))); + } + for (int j = 0; j < size2; j++) { + if (isRow) SEGMENT.setPixelColorXY(j, i, ledsbuff[j]); + else SEGMENT.setPixelColorXY(i, j, ledsbuff[j]); + } + } +} + uint16_t mode_2Dsoap() { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up @@ -7526,52 +7555,9 @@ uint16_t mode_2Dsoap() { CRGB ledsbuff[MAX(cols,rows)]; amplitude = (cols >= 16) ? (cols-8)/8 : 1; - for (int y = 0; y < rows; y++) { - int amount = ((int)noise3d[XY(0,y)] - 128) * 2 * amplitude + 256*shiftX; - int delta = abs(amount) >> 8; - int fraction = abs(amount) & 255; - for (int x = 0; x < cols; x++) { - if (amount < 0) { - zD = x - delta; - zF = zD - 1; - } else { - zD = x + delta; - zF = zD + 1; - } - CRGB PixelA = CRGB::Black; - if ((zD >= 0) && (zD < cols)) PixelA = SEGMENT.getPixelColorXY(zD, y); - else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[XY(abs(zD),y)]*3); - CRGB PixelB = CRGB::Black; - if ((zF >= 0) && (zF < cols)) PixelB = SEGMENT.getPixelColorXY(zF, y); - else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[XY(abs(zF),y)]*3); - ledsbuff[x] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction))); - } - for (int x = 0; x < cols; x++) SEGMENT.setPixelColorXY(x, y, ledsbuff[x]); - } - + soapProcessPixels(true, rows, cols, noise3d, amplitude, shiftX, ledsbuff); // rows 1166192 vs 1165634 amplitude = (rows >= 16) ? (rows-8)/8 : 1; - for (int x = 0; x < cols; x++) { - int amount = ((int)noise3d[XY(x,0)] - 128) * 2 * amplitude + 256*shiftY; - int delta = abs(amount) >> 8; - int fraction = abs(amount) & 255; - for (int y = 0; y < rows; y++) { - if (amount < 0) { - zD = y - delta; - zF = zD - 1; - } else { - zD = y + delta; - zF = zD + 1; - } - CRGB PixelA = CRGB::Black; - if ((zD >= 0) && (zD < rows)) PixelA = SEGMENT.getPixelColorXY(x, zD); - else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[XY(x,abs(zD))]*3); - CRGB PixelB = CRGB::Black; - if ((zF >= 0) && (zF < rows)) PixelB = SEGMENT.getPixelColorXY(x, zF); - else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[XY(x,abs(zF))]*3); - ledsbuff[y] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction))); - } - for (int y = 0; y < rows; y++) SEGMENT.setPixelColorXY(x, y, ledsbuff[y]); - } + soapProcessPixels(false, cols, rows, noise3d, amplitude, shiftY, ledsbuff); // cols return FRAMETIME; } From b9ceacb43d8cd019cbe3a343dc8250fcaa069a46 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Fri, 7 Feb 2025 11:14:13 +0100 Subject: [PATCH 302/463] more optimizations and better readability --- wled00/FX.cpp | 62 ++++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 51726215..50406aa9 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7469,33 +7469,39 @@ static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@ //@Stepko //Idea from https://www.youtube.com/watch?v=DiHBgITrZck&ab_channel=StefanPetrick // adapted for WLED by @blazoncek, optimization by @dedehai -void soapProcessPixels(bool isRow, int size1, int size2, uint8_t* noise3d, int amplitude, int shift, CRGB* ledsbuff) { - for (int i = 0; i < size1; i++) { - int amount = ((int)noise3d[isRow ? XY(0, i) : XY(i, 0)] - 128) * 2 * amplitude + 256 * shift; - int delta = abs(amount) >> 8; - int fraction = abs(amount) & 255; - for (int j = 0; j < size2; j++) { - int zD, zF; - if (amount < 0) { - zD = j - delta; - zF = zD - 1; - } else { - zD = j + delta; - zF = zD + 1; - } - CRGB PixelA = CRGB::Black; - if ((zD >= 0) && (zD < size2)) PixelA = isRow ? SEGMENT.getPixelColorXY(zD, i) : SEGMENT.getPixelColorXY(i, zD); - else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? XY(abs(zD), i) : XY(i, abs(zD))] * 3); - CRGB PixelB = CRGB::Black; - if ((zF >= 0) && (zF < size2)) PixelB = isRow ? SEGMENT.getPixelColorXY(zF, i) : SEGMENT.getPixelColorXY(i, zF); - else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? XY(abs(zF), i) : XY(i, abs(zF))] * 3); - ledsbuff[j] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction))); - } - for (int j = 0; j < size2; j++) { - if (isRow) SEGMENT.setPixelColorXY(j, i, ledsbuff[j]); - else SEGMENT.setPixelColorXY(i, j, ledsbuff[j]); - } +void soapProcessPixels(bool isRow, uint8_t* noise3d, int amplitude, int shift, CRGB* ledsbuff) { //1153477-1152873 + const int cols = SEG_W; + const int rows = SEG_H; + int rowcol, colrow; + rowcol = isRow ? rows : cols; + colrow = isRow ? cols : rows; + + for (int i = 0; i < rowcol; i++) { + int amount = ((int)noise3d[isRow ? i * cols : i] - 128) * 2 * amplitude + 256 * shift; + int delta = abs(amount) >> 8; + int fraction = abs(amount) & 255; + for (int j = 0; j < colrow; j++) { + int zD, zF; + if (amount < 0) { + zD = j - delta; + zF = zD - 1; + } else { + zD = j + delta; + zF = zD + 1; + } + CRGB PixelA = CRGB::Black; + if ((zD >= 0) && (zD < colrow)) PixelA = isRow ? SEGMENT.getPixelColorXY(zD, i) : SEGMENT.getPixelColorXY(i, zD); + else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? (abs(zD)%cols) + i*cols : i + (abs(zD)%rows)*cols] * 3); + CRGB PixelB = CRGB::Black; + if ((zF >= 0) && (zF < colrow)) PixelB = isRow ? SEGMENT.getPixelColorXY(zF, i) : SEGMENT.getPixelColorXY(i, zF); + else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? (abs(zF)%cols) + i*cols : i + (abs(zF)%rows)*cols] * 3); + ledsbuff[j] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction))); } + for (int j = 0; j < colrow; j++) { + if (isRow) SEGMENT.setPixelColorXY(j, i, ledsbuff[j]); + else SEGMENT.setPixelColorXY(i, j, ledsbuff[j]); + } + } } uint16_t mode_2Dsoap() { @@ -7555,9 +7561,9 @@ uint16_t mode_2Dsoap() { CRGB ledsbuff[MAX(cols,rows)]; amplitude = (cols >= 16) ? (cols-8)/8 : 1; - soapProcessPixels(true, rows, cols, noise3d, amplitude, shiftX, ledsbuff); // rows 1166192 vs 1165634 + soapProcessPixels(true, noise3d, amplitude, shiftX, ledsbuff); // rows amplitude = (rows >= 16) ? (rows-8)/8 : 1; - soapProcessPixels(false, cols, rows, noise3d, amplitude, shiftY, ledsbuff); // cols + soapProcessPixels(false, noise3d, amplitude, shiftY, ledsbuff); // cols return FRAMETIME; } From d92e60ee5f9e5dbf96d4952e3b50a863ff9f17ef Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Fri, 7 Feb 2025 15:23:44 +0100 Subject: [PATCH 303/463] adding XY() lambda function back in - slight increase in code size, speed is the same but better readability. --- wled00/FX.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 50406aa9..9066e960 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7472,6 +7472,7 @@ static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@ void soapProcessPixels(bool isRow, uint8_t* noise3d, int amplitude, int shift, CRGB* ledsbuff) { //1153477-1152873 const int cols = SEG_W; const int rows = SEG_H; + const auto XY = [&](int x, int y) { return (x%cols) + (y%rows) * cols; }; int rowcol, colrow; rowcol = isRow ? rows : cols; colrow = isRow ? cols : rows; @@ -7491,10 +7492,10 @@ void soapProcessPixels(bool isRow, uint8_t* noise3d, int amplitude, int shift, C } CRGB PixelA = CRGB::Black; if ((zD >= 0) && (zD < colrow)) PixelA = isRow ? SEGMENT.getPixelColorXY(zD, i) : SEGMENT.getPixelColorXY(i, zD); - else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? (abs(zD)%cols) + i*cols : i + (abs(zD)%rows)*cols] * 3); + else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? XY(abs(zD), i) : XY(i, abs(zD))] * 3); CRGB PixelB = CRGB::Black; if ((zF >= 0) && (zF < colrow)) PixelB = isRow ? SEGMENT.getPixelColorXY(zF, i) : SEGMENT.getPixelColorXY(i, zF); - else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? (abs(zF)%cols) + i*cols : i + (abs(zF)%rows)*cols] * 3); + else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? XY(abs(zF), i) : XY(i, abs(zF))] * 3); ledsbuff[j] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction))); } for (int j = 0; j < colrow; j++) { From c43d09c8b18f02a5a9142f000b6449948c9335bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Fri, 7 Feb 2025 15:02:27 +0100 Subject: [PATCH 304/463] Move _data and allocation to derived class - as suggested by @TripleWhy - minimum length guard Conflicts: wled00/bus_manager.cpp wled00/bus_manager.h --- wled00/bus_manager.cpp | 46 ++++++++++++++++++------------------------ wled00/bus_manager.h | 34 +++++++++++++++---------------- 2 files changed, 36 insertions(+), 44 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 69cc63be..68a58d5a 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -91,7 +91,7 @@ void Bus::calculateCCT(uint32_t c, uint8_t &ww, uint8_t &cw) { } else { cct = (approximateKelvinFromRGB(c) - 1900) >> 5; // convert K (from RGB value) to relative format } - + //0 - linear (CCT 127 = 50% warm, 50% cold), 127 - additive CCT blending (CCT 127 = 100% warm, 100% cold) if (cct < _cctBlend) ww = 255; else ww = ((255-cct) * 255) / (255 - _cctBlend); @@ -118,16 +118,6 @@ uint32_t Bus::autoWhiteCalc(uint32_t c) const { return RGBW32(r, g, b, w); } -uint8_t *Bus::allocateData(size_t size) { - freeData(); // should not happen, but for safety - return _data = (uint8_t *)(size>0 ? calloc(size, sizeof(uint8_t)) : nullptr); -} - -void Bus::freeData() { - if (_data) free(_data); - _data = nullptr; -} - BusDigital::BusDigital(const BusConfig &bc, uint8_t nr) : Bus(bc.type, bc.start, bc.autoWhite, bc.count, bc.reversed, (bc.refreshReq || bc.type == TYPE_TM1814)) @@ -153,8 +143,10 @@ BusDigital::BusDigital(const BusConfig &bc, uint8_t nr) _hasRgb = hasRGB(bc.type); _hasWhite = hasWhite(bc.type); _hasCCT = hasCCT(bc.type); - if (bc.doubleBuffer && !allocateData(bc.count * Bus::getNumberOfChannels(bc.type))) return; - //_buffering = bc.doubleBuffer; + if (bc.doubleBuffer) { + _data = (uint8_t*)d_calloc(_len, Bus::getNumberOfChannels(_type)); + if (!_data) DEBUG_PRINTLN(F("Bus: Buffer allocation failed!")); + } uint16_t lenToCreate = bc.count; if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(bc.count); // only needs a third of "RGB" LEDs for NeoPixelBus _busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr); @@ -285,7 +277,7 @@ void BusDigital::show() { } } } - PolyBus::show(_busPtr, _iType, !_data); // faster if buffer consistency is not important (use !_buffering this causes 20% FPS drop) + PolyBus::show(_busPtr, _iType, !_data); // faster if buffer consistency is not important // restore bus brightness to its original value // this is done right after show, so this is only OK if LED updates are completed before show() returns // or async show has a separate buffer (ESP32 RMT and I2S are ok) @@ -434,10 +426,11 @@ void BusDigital::begin() { void BusDigital::cleanup() { DEBUG_PRINTLN(F("Digital Cleanup.")); PolyBus::cleanup(_busPtr, _iType); + free(_data); + _data = nullptr; _iType = I_NONE; _valid = false; _busPtr = nullptr; - if (_data != nullptr) freeData(); PinManager::deallocatePin(_pins[1], PinOwner::BusDigital); PinManager::deallocatePin(_pins[0], PinOwner::BusDigital); } @@ -461,7 +454,7 @@ void BusDigital::cleanup() { #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 + #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 14 @@ -509,7 +502,6 @@ BusPwm::BusPwm(const BusConfig &bc) _hasRgb = hasRGB(bc.type); _hasWhite = hasWhite(bc.type); _hasCCT = hasCCT(bc.type); - _data = _pwmdata; // avoid malloc() and use stack _valid = true; 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]); } @@ -583,7 +575,7 @@ void BusPwm::show() { // if _needsRefresh is true (UI hack) we are using dithering (credit @dedehai & @zalatnaicsongor) // https://github.com/Aircoookie/WLED/pull/4115 and https://github.com/zalatnaicsongor/WLED/pull/1) const bool dithering = _needsRefresh; // avoid working with bitfield - const unsigned maxBri = (1<<_depth); // possible values: 16384 (14), 8192 (13), 4096 (12), 2048 (11), 1024 (10), 512 (9) and 256 (8) + const unsigned maxBri = (1<<_depth); // possible values: 16384 (14), 8192 (13), 4096 (12), 2048 (11), 1024 (10), 512 (9) and 256 (8) const unsigned bitShift = dithering * 4; // if dithering, _depth is 12 bit but LEDC channel is set to 8 bit (using 4 fractional bits) #endif // use CIE brightness formula (linear + cubic) to approximate human eye perceived brightness @@ -599,7 +591,7 @@ void BusPwm::show() { [[maybe_unused]] unsigned hPoint = 0; // phase shift (0 - maxBri) // we will be phase shifting every channel by previous pulse length (plus dead time if required) - // phase shifting is only mandatory when using H-bridge to drive reverse-polarity PWM CCT (2 wire) LED type + // phase shifting is only mandatory when using H-bridge to drive reverse-polarity PWM CCT (2 wire) LED type // CCT additive blending must be 0 (WW & CW will not overlap) otherwise signals *will* overlap // for all other cases it will just try to "spread" the load on PSU // Phase shifting requires that LEDC timers are synchronised (see setup()). For PWM CCT (and H-bridge) it is @@ -678,7 +670,7 @@ void BusPwm::deallocatePins() { BusOnOff::BusOnOff(const BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite, 1, bc.reversed) -, _onoffdata(0) +, _data(0) { if (!Bus::isOnOff(bc.type)) return; @@ -691,7 +683,6 @@ BusOnOff::BusOnOff(const BusConfig &bc) _hasRgb = false; _hasWhite = false; _hasCCT = false; - _data = &_onoffdata; // avoid malloc() and use stack _valid = true; DEBUG_PRINTF_P(PSTR("%successfully inited On/Off strip with pin %u\n"), _valid?"S":"Uns", _pin); } @@ -703,17 +694,17 @@ void BusOnOff::setPixelColor(unsigned pix, uint32_t c) { uint8_t g = G(c); uint8_t b = B(c); uint8_t w = W(c); - _data[0] = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0; + _data = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0; } uint32_t BusOnOff::getPixelColor(unsigned pix) const { if (!_valid) return 0; - return RGBW32(_data[0], _data[0], _data[0], _data[0]); + return RGBW32(_data, _data, _data, _data); } void BusOnOff::show() { if (!_valid) return; - digitalWrite(_pin, _reversed ? !(bool)_data[0] : (bool)_data[0]); + digitalWrite(_pin, _reversed ? !(bool)_data : (bool)_data); } size_t BusOnOff::getPins(uint8_t* pinArray) const { @@ -752,7 +743,8 @@ BusNetwork::BusNetwork(const BusConfig &bc) _hasCCT = false; _UDPchannels = _hasWhite + 3; _client = IPAddress(bc.pins[0],bc.pins[1],bc.pins[2],bc.pins[3]); - _valid = (allocateData(_len * _UDPchannels) != nullptr) && bc.count > 0; + _data = (uint8_t*)d_calloc(_len, _UDPchannels); + _valid = (_data != nullptr); DEBUG_PRINTF_P(PSTR("%successfully inited virtual strip with type %u and IP %u.%u.%u.%u\n"), _valid?"S":"Uns", bc.type, bc.pins[0], bc.pins[1], bc.pins[2], bc.pins[3]); } @@ -801,9 +793,11 @@ std::vector BusNetwork::getLEDTypes() { } void BusNetwork::cleanup() { + DEBUG_PRINTLN(F("Virtual Cleanup.")); + free(_data); + _data = nullptr; _type = I_NONE; _valid = false; - freeData(); } diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 65724003..60b96048 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -83,20 +83,19 @@ class Bus { : _type(type) , _bri(255) , _start(start) - , _len(len) + , _len(std::max(len,(uint16_t)1)) , _reversed(reversed) , _valid(false) , _needsRefresh(refresh) - , _data(nullptr) // keep data access consistent across all types of buses { _autoWhiteMode = Bus::hasWhite(type) ? aw : RGBW_MODE_MANUAL_ONLY; }; - virtual ~Bus() {} //throw the bus under the bus (derived class needs to freeData()) + virtual ~Bus() {} //throw the bus under the bus virtual void begin() {}; virtual void show() = 0; - virtual bool canShow() const { return true; } + virtual bool canShow() const { return true; } virtual void setStatusPixel(uint32_t c) {} virtual void setPixelColor(unsigned pix, uint32_t c) = 0; virtual void setBrightness(uint8_t b) { _bri = b; }; @@ -191,7 +190,6 @@ class Bus { bool _hasCCT;// : 1; //} __attribute__ ((packed)); uint8_t _autoWhiteMode; - uint8_t *_data; // global Auto White Calculation override static uint8_t _gAWM; // _cct has the following menaings (see calculateCCT() & BusManager::setSegmentCCT()): @@ -206,8 +204,6 @@ class Bus { static uint8_t _cctBlend; uint32_t autoWhiteCalc(uint32_t c) const; - uint8_t *allocateData(size_t size = 1); - void freeData(); }; @@ -237,14 +233,15 @@ class BusDigital : public Bus { static std::vector getLEDTypes(); private: - uint8_t _skip; - uint8_t _colorOrder; - uint8_t _pins[2]; - uint8_t _iType; + uint8_t _skip; + uint8_t _colorOrder; + uint8_t _pins[2]; + uint8_t _iType; uint16_t _frequencykHz; - uint8_t _milliAmpsPerLed; + uint8_t _milliAmpsPerLed; uint16_t _milliAmpsMax; - void * _busPtr; + uint8_t *_data; + void *_busPtr; static uint16_t _milliAmpsTotal; // is overwitten/recalculated on each show() @@ -274,13 +271,13 @@ class BusPwm : public Bus { uint16_t getFrequency() const override { return _frequency; } size_t getBusSize() const override { return sizeof(BusPwm); } void show() override; - inline void cleanup() { deallocatePins(); _data = nullptr; } + inline void cleanup() { deallocatePins(); } static std::vector getLEDTypes(); private: uint8_t _pins[OUTPUT_MAX_PINS]; - uint8_t _pwmdata[OUTPUT_MAX_PINS]; + uint8_t _data[OUTPUT_MAX_PINS]; #ifdef ARDUINO_ARCH_ESP32 uint8_t _ledcStart; #endif @@ -301,13 +298,13 @@ class BusOnOff : public Bus { size_t getPins(uint8_t* pinArray) const override; size_t getBusSize() const override { return sizeof(BusOnOff); } void show() override; - inline void cleanup() { PinManager::deallocatePin(_pin, PinOwner::BusOnOff); _data = nullptr; } + inline void cleanup() { PinManager::deallocatePin(_pin, PinOwner::BusOnOff); } static std::vector getLEDTypes(); private: uint8_t _pin; - uint8_t _onoffdata; + uint8_t _data; }; @@ -331,6 +328,7 @@ class BusNetwork : public Bus { uint8_t _UDPtype; uint8_t _UDPchannels; bool _broadcastLock; + uint8_t *_data; }; @@ -351,7 +349,7 @@ struct BusConfig { uint16_t milliAmpsMax; BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false, uint8_t skip = 0, byte aw=RGBW_MODE_MANUAL_ONLY, uint16_t clock_kHz=0U, bool dblBfr=false, uint8_t maPerLed=LED_MILLIAMPS_DEFAULT, uint16_t maMax=ABL_MILLIAMPS_DEFAULT) - : count(len) + : count(std::max(len,(uint16_t)1)) , start(pstart) , colorOrder(pcolorOrder) , reversed(rev) From 77d7082ffc83010464f6ab389213a5b43c34e60e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Fri, 7 Feb 2025 12:26:33 +0100 Subject: [PATCH 305/463] Bugfix - correct string length in strlcpy() --- wled00/FX_fcn.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 8c820280..82760242 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -652,7 +652,8 @@ Segment &Segment::setName(const char *newName) { if (newLen) { if (name) name = static_cast(realloc(name, newLen+1)); else name = static_cast(malloc(newLen+1)); - if (name) strlcpy(name, newName, newLen); + if (name) strlcpy(name, newName, newLen+1); + name[newLen] = 0; return *this; } } From 95a10c692ceb602d2a3206e2ea1741790ae02279 Mon Sep 17 00:00:00 2001 From: scourge411 <86616124+scourge411@users.noreply.github.com> Date: Sat, 8 Feb 2025 00:44:46 -0700 Subject: [PATCH 306/463] constexpr is invalid on is2D() (#4540) * constexpr is invalid on is2D() (it does work on _V4 builds though) --- wled00/FX.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.h b/wled00/FX.h index 1a52ad95..c3629289 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -710,7 +710,7 @@ typedef struct Segment { void wu_pixel(uint32_t x, uint32_t y, CRGB c); inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); } #else - inline constexpr bool is2D() const { return false; } + inline bool is2D() const { return false; } inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(x, c); } inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColor(int(x), c); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColor(x, RGBW32(r,g,b,w)); } From 8e7d6d5dad09a326b09e2334127b6863c1b61857 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 8 Feb 2025 10:06:29 +0100 Subject: [PATCH 307/463] cleanup and added Density slider - moved local variables into function - made coordinates an array - amplitude can now be changed by user (default setting is a slight increase to original which cannot be avoided without complicated logic or default slider setting) --- wled00/FX.cpp | 49 ++++++++++++++++++------------------------------- 1 file changed, 18 insertions(+), 31 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 9066e960..d4288676 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7469,16 +7469,18 @@ static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@ //@Stepko //Idea from https://www.youtube.com/watch?v=DiHBgITrZck&ab_channel=StefanPetrick // adapted for WLED by @blazoncek, optimization by @dedehai -void soapProcessPixels(bool isRow, uint8_t* noise3d, int amplitude, int shift, CRGB* ledsbuff) { //1153477-1152873 +void soapProcessPixels(bool isRow, uint8_t* noise3d) { const int cols = SEG_W; const int rows = SEG_H; const auto XY = [&](int x, int y) { return (x%cols) + (y%rows) * cols; }; - int rowcol, colrow; - rowcol = isRow ? rows : cols; - colrow = isRow ? cols : rows; + CRGB ledsbuff[MAX(cols,rows)]; + const int rowcol = isRow ? rows : cols; + const int colrow = isRow ? cols : rows; + int amplitude = isRow ? (cols-8) >> 3 : (rows-8) >> 3; + amplitude = 2 * max(1, amplitude * (1 + SEGMENT.custom1) >> 6); for (int i = 0; i < rowcol; i++) { - int amount = ((int)noise3d[isRow ? i * cols : i] - 128) * 2 * amplitude + 256 * shift; + int amount = ((int)noise3d[isRow ? i * cols : i] - 128) * amplitude; int delta = abs(amount) >> 8; int fraction = abs(amount) & 255; for (int j = 0; j < colrow; j++) { @@ -7515,31 +7517,25 @@ uint16_t mode_2Dsoap() { const size_t dataSize = SEGMENT.width() * SEGMENT.height() * sizeof(uint8_t); // prevent reallocation if mirrored or grouped if (!SEGENV.allocateData(dataSize + sizeof(uint32_t)*3)) return mode_static(); //allocation failed - uint8_t *noise3d = reinterpret_cast(SEGENV.data); - uint32_t *noise32_x = reinterpret_cast(SEGENV.data + dataSize); - uint32_t *noise32_y = reinterpret_cast(SEGENV.data + dataSize + sizeof(uint32_t)); - uint32_t *noise32_z = reinterpret_cast(SEGENV.data + dataSize + sizeof(uint32_t)*2); + uint8_t *noise3d = reinterpret_cast(SEGENV.data); + uint32_t *noisecoord = reinterpret_cast(SEGENV.data + dataSize); // x, y, z coordinates const uint32_t scale32_x = 160000U/cols; const uint32_t scale32_y = 160000U/rows; const uint32_t mov = MIN(cols,rows)*(SEGMENT.speed+2)/2; const uint8_t smoothness = MIN(250,SEGMENT.intensity); // limit as >250 produces very little changes - // init - if (SEGENV.call == 0) { - *noise32_x = hw_random(); - *noise32_y = hw_random(); - *noise32_z = hw_random(); - } else { - *noise32_x += mov; - *noise32_y += mov; - *noise32_z += mov; + for (int i = 0; i < 3; i++) { + if (SEGENV.call == 0) + noisecoord[i] = hw_random(); // init + else + noisecoord[i] += mov; } for (int i = 0; i < cols; i++) { int32_t ioffset = scale32_x * (i - cols / 2); for (int j = 0; j < rows; j++) { int32_t joffset = scale32_y * (j - rows / 2); - uint8_t data = inoise16(*noise32_x + ioffset, *noise32_y + joffset, *noise32_z) >> 8; + uint8_t data = inoise16(noisecoord[0] + ioffset, noisecoord[1] + joffset, noisecoord[2]) >> 8; noise3d[XY(i,j)] = scale8(noise3d[XY(i,j)], smoothness) + scale8(data, 255 - smoothness); } } @@ -7554,21 +7550,12 @@ uint16_t mode_2Dsoap() { } } - int zD; - int zF; - int amplitude; - int shiftX = 0; //(SEGMENT.custom1 - 128) / 4; - int shiftY = 0; //(SEGMENT.custom2 - 128) / 4; - CRGB ledsbuff[MAX(cols,rows)]; - - amplitude = (cols >= 16) ? (cols-8)/8 : 1; - soapProcessPixels(true, noise3d, amplitude, shiftX, ledsbuff); // rows - amplitude = (rows >= 16) ? (rows-8)/8 : 1; - soapProcessPixels(false, noise3d, amplitude, shiftY, ledsbuff); // cols + soapProcessPixels(true, noise3d); // rows + soapProcessPixels(false, noise3d); // cols return FRAMETIME; } -static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness;;!;2;pal=11"; +static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness,Density;;!;2;pal=11"; //Idea from https://www.youtube.com/watch?v=HsA-6KIbgto&ab_channel=GreatScott%21 From 35f87365c9c7476a1e11b03e373d914f8905e1cd Mon Sep 17 00:00:00 2001 From: yangminglong Date: Sat, 8 Feb 2025 17:11:14 +0800 Subject: [PATCH 308/463] Brightness follow sun (#4485) * add usermod : Brightness Follow Sun --- .../README.md | 35 +++++ .../usermod_v2_brightness_follow_sun.h | 130 ++++++++++++++++++ wled00/const.h | 1 + wled00/usermods_list.cpp | 8 ++ 4 files changed, 174 insertions(+) create mode 100644 usermods/usermod_v2_brightness_follow_sun/README.md create mode 100644 usermods/usermod_v2_brightness_follow_sun/usermod_v2_brightness_follow_sun.h diff --git a/usermods/usermod_v2_brightness_follow_sun/README.md b/usermods/usermod_v2_brightness_follow_sun/README.md new file mode 100644 index 00000000..25daf0ba --- /dev/null +++ b/usermods/usermod_v2_brightness_follow_sun/README.md @@ -0,0 +1,35 @@ +# Update Brightness Follow Sun + +This UserMod can set brightness by mapping [minimum-maximum-minimum] from [sunrise-suntop-sunset], I use this UserMod to adjust the brightness of my plant growth light (pwm led), and I think it will make my plants happy. + +This UserMod will adjust brightness from sunrise to sunset, reaching maximum brightness at the zenith of the sun. It can also maintain the lowest brightness within 0-6 hours before sunrise and after sunset according to the settings. + +## Installation + +define `USERMOD_BRIGHTNESS_FOLLOW_SUN` e.g. `#define USERMOD_BRIGHTNESS_FOLLOW_SUN` in my_config.h + +or add `-D USERMOD_BRIGHTNESS_FOLLOW_SUN` to `build_flags` in platformio_override.ini + + +### Options +Open Usermod Settings in WLED to change settings: + +`Enable` - When checked `Enable`, turn on the `Brightness Follow Sun` Usermod, which will automatically turn on the lights, adjust the brightness, and turn off the lights. If you need to completely turn off the lights, please unchecked `Enable`. + +`Update Interval Sec` - The unit is seconds, and the brightness will be automatically refreshed according to the set parameters. + +`Min Brightness` - set brightness by map of min-max-min : sunrise-suntop-sunset + +`Max Brightness` - It needs to be set to a value greater than `Min Brightness`, otherwise it will always remain at `Min Brightness`. + +`Relax Hour` - The unit is in hours, with an effective range of 0-6. According to the settings, maintain the lowest brightness for 0-6 hours before sunrise and after sunset. + + +### PlatformIO requirements + +No special requirements. + +## Change Log + +2025-01-02 +* init diff --git a/usermods/usermod_v2_brightness_follow_sun/usermod_v2_brightness_follow_sun.h b/usermods/usermod_v2_brightness_follow_sun/usermod_v2_brightness_follow_sun.h new file mode 100644 index 00000000..99f646b2 --- /dev/null +++ b/usermods/usermod_v2_brightness_follow_sun/usermod_v2_brightness_follow_sun.h @@ -0,0 +1,130 @@ +#pragma once + +#include "wled.h" + +//v2 usermod that allows to change brightness and color using a rotary encoder, +//change between modes by pressing a button (many encoders have one included) +class UsermodBrightnessFollowSun : public Usermod +{ +private: + static const char _name[]; + static const char _enabled[]; + static const char _update_interval[]; + static const char _min_bri[]; + static const char _max_bri[]; + static const char _relax_hour[]; + +private: + bool enabled = false; //WLEDMM + unsigned long update_interval = 60; + unsigned long update_interval_ms = 60000; + int min_bri = 1; + int max_bri = 255; + float relax_hour = 0; + int relaxSec = 0; + unsigned long lastUMRun = 0; +public: + + void setup() {}; + + float mapFloat(float inputValue, float inMin, float inMax, float outMin, float outMax) { + if (inMax == inMin) + return outMin; + + inputValue = constrain(inputValue, inMin, inMax); + + return ((inputValue - inMin) * (outMax - outMin) / (inMax - inMin)) + outMin; + } + + uint16_t getId() override + { + return USERMOD_ID_BRIGHTNESS_FOLLOW_SUN; + } + + void update() + { + if (sunrise == 0 || sunset == 0 || localTime == 0) + return; + + int curSec = elapsedSecsToday(localTime); + int sunriseSec = elapsedSecsToday(sunrise); + int sunsetSec = elapsedSecsToday(sunset); + int sunMiddleSec = sunriseSec + (sunsetSec-sunriseSec)/2; + + int relaxSecH = sunriseSec-relaxSec; + int relaxSecE = sunsetSec+relaxSec; + + int briSet = 0; + if (curSec >= relaxSecH && curSec <= relaxSecE) { + float timeMapToAngle = curSec < sunMiddleSec ? + mapFloat(curSec, sunriseSec, sunMiddleSec, 0, M_PI/2.0) : + mapFloat(curSec, sunMiddleSec, sunsetSec, M_PI/2.0, M_PI); + float sinValue = sin_t(timeMapToAngle); + briSet = min_bri + (max_bri-min_bri)*sinValue; + } + + bri = briSet; + stateUpdated(CALL_MODE_DIRECT_CHANGE); +} + + void loop() override + { + if (!enabled || strip.isUpdating()) + return; + + if (millis() - lastUMRun < update_interval_ms) + return; + lastUMRun = millis(); + + update(); + } + + void addToConfig(JsonObject& root) + { + JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname + + top[FPSTR(_enabled)] = enabled; + top[FPSTR(_update_interval)] = update_interval; + top[FPSTR(_min_bri)] = min_bri; + top[FPSTR(_max_bri)] = max_bri; + top[FPSTR(_relax_hour)] = relax_hour; + } + + bool readFromConfig(JsonObject& root) + { + JsonObject top = root[FPSTR(_name)]; + if (top.isNull()) { + DEBUG_PRINTF("[%s] No config found. (Using defaults.)\n", _name); + return false; + } + + bool configComplete = true; + + configComplete &= getJsonValue(top[FPSTR(_enabled)], enabled, false); + configComplete &= getJsonValue(top[FPSTR(_update_interval)], update_interval, 60); + configComplete &= getJsonValue(top[FPSTR(_min_bri)], min_bri, 1); + configComplete &= getJsonValue(top[FPSTR(_max_bri)], max_bri, 255); + configComplete &= getJsonValue(top[FPSTR(_relax_hour)], relax_hour, 0); + + update_interval = constrain(update_interval, 1, SECS_PER_HOUR); + min_bri = constrain(min_bri, 1, 255); + max_bri = constrain(max_bri, 1, 255); + relax_hour = constrain(relax_hour, 0, 6); + + update_interval_ms = update_interval*1000; + relaxSec = SECS_PER_HOUR*relax_hour; + + lastUMRun = 0; + update(); + + return configComplete; + } +}; + + +const char UsermodBrightnessFollowSun::_name[] PROGMEM = "Brightness Follow Sun"; +const char UsermodBrightnessFollowSun::_enabled[] PROGMEM = "Enabled"; +const char UsermodBrightnessFollowSun::_update_interval[] PROGMEM = "Update Interval Sec"; +const char UsermodBrightnessFollowSun::_min_bri[] PROGMEM = "Min Brightness"; +const char UsermodBrightnessFollowSun::_max_bri[] PROGMEM = "Max Brightness"; +const char UsermodBrightnessFollowSun::_relax_hour[] PROGMEM = "Relax Hour"; diff --git a/wled00/const.h b/wled00/const.h index 1ebcb939..112bc6eb 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -205,6 +205,7 @@ #define USERMOD_ID_PIXELS_DICE_TRAY 54 //Usermod "pixels_dice_tray.h" #define USERMOD_ID_DEEP_SLEEP 55 //Usermod "usermod_deep_sleep.h" #define USERMOD_ID_RF433 56 //Usermod "usermod_v2_RF433.h" +#define USERMOD_ID_BRIGHTNESS_FOLLOW_SUN 57 //Usermod "usermod_v2_brightness_follow_sun.h" //Access point behavior #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp index 15ded987..df4715d1 100644 --- a/wled00/usermods_list.cpp +++ b/wled00/usermods_list.cpp @@ -250,6 +250,10 @@ #include "../usermods/usermod_v2_RF433/usermod_v2_RF433.h" #endif +#ifdef USERMOD_BRIGHTNESS_FOLLOW_SUN + #include "../usermods/usermod_v2_brightness_follow_sun/usermod_v2_brightness_follow_sun.h" +#endif + void registerUsermods() { /* @@ -486,4 +490,8 @@ void registerUsermods() #ifdef USERMOD_RF433 UsermodManager::add(new RF433Usermod()); #endif + + #ifdef USERMOD_BRIGHTNESS_FOLLOW_SUN + UsermodManager::add(new UsermodBrightnessFollowSun()); + #endif } From 4d53e0adde054519e84b5bc1b637452980ff9975 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 8 Feb 2025 16:45:33 +0100 Subject: [PATCH 309/463] Fixes first pixel not being set in Stream FX (#4542) * Fixes first pixel not being set * added fix to Stream 2 as well --- wled00/FX.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 216cd7a3..e8a674b4 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -1134,7 +1134,7 @@ uint16_t mode_running_random(void) { unsigned z = it % zoneSize; bool nzone = (!z && it != SEGENV.aux1); - for (unsigned i=SEGLEN-1; i > 0; i--) { + for (int i=SEGLEN-1; i >= 0; i--) { if (nzone || z >= zoneSize) { unsigned lastrand = PRNG16 >> 8; int16_t diff = 0; @@ -1768,7 +1768,7 @@ uint16_t mode_random_chase(void) { uint32_t color = SEGENV.step; random16_set_seed(SEGENV.aux0); - for (unsigned i = SEGLEN -1; i > 0; i--) { + for (int i = SEGLEN -1; i >= 0; i--) { uint8_t r = random8(6) != 0 ? (color >> 16 & 0xFF) : random8(); uint8_t g = random8(6) != 0 ? (color >> 8 & 0xFF) : random8(); uint8_t b = random8(6) != 0 ? (color & 0xFF) : random8(); From ed91c54654e7bd4ecf40b121a3900180836796b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sun, 9 Feb 2025 18:13:55 +0100 Subject: [PATCH 310/463] Uninitialised _data bugfix --- wled00/bus_manager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 68a58d5a..2a7dce4f 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -125,6 +125,7 @@ BusDigital::BusDigital(const BusConfig &bc, uint8_t nr) , _colorOrder(bc.colorOrder) , _milliAmpsPerLed(bc.milliAmpsPerLed) , _milliAmpsMax(bc.milliAmpsMax) +, _data(nullptr) { if (!isDigital(bc.type) || !bc.count) return; if (!PinManager::allocatePin(bc.pins[0], true, PinOwner::BusDigital)) return; From 2473065b986ceea25eda5139a6920b5e584a5fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sun, 9 Feb 2025 18:23:53 +0100 Subject: [PATCH 311/463] Soap gap bugfix & aditional size tuning --- wled00/FX.cpp | 86 +++++++++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 37 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index d4288676..44366bbc 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7469,40 +7469,54 @@ static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@ //@Stepko //Idea from https://www.youtube.com/watch?v=DiHBgITrZck&ab_channel=StefanPetrick // adapted for WLED by @blazoncek, optimization by @dedehai -void soapProcessPixels(bool isRow, uint8_t* noise3d) { - const int cols = SEG_W; - const int rows = SEG_H; - const auto XY = [&](int x, int y) { return (x%cols) + (y%rows) * cols; }; - CRGB ledsbuff[MAX(cols,rows)]; - const int rowcol = isRow ? rows : cols; - const int colrow = isRow ? cols : rows; - int amplitude = isRow ? (cols-8) >> 3 : (rows-8) >> 3; - amplitude = 2 * max(1, amplitude * (1 + SEGMENT.custom1) >> 6); +static void soapPixels(bool isRow, uint8_t *noise3d, CRGB *pixels) { + const int cols = SEG_W; + const int rows = SEG_H; + const auto XY = [&](int x, int y) { return x + y * cols; }; + const auto abs = [](int x) { return x<0 ? -x : x; }; + const int tRC = isRow ? rows : cols; // transpose if isRow + const int tCR = isRow ? cols : rows; // transpose if isRow + const int amplitude = 2 * ((tCR >= 16) ? (tCR-8) : 8) / (1 + ((255 - SEGMENT.custom1) >> 5)); + const int shift = 0; //(128 - SEGMENT.custom2)*2; - for (int i = 0; i < rowcol; i++) { - int amount = ((int)noise3d[isRow ? i * cols : i] - 128) * amplitude; - int delta = abs(amount) >> 8; + CRGB ledsbuff[tCR]; + + for (int i = 0; i < tRC; i++) { + int amount = ((int)noise3d[isRow ? i*cols : i] - 128) * amplitude + shift; // use first row/column: XY(0,i)/XY(i,0) + int delta = abs(amount) >> 8; int fraction = abs(amount) & 255; - for (int j = 0; j < colrow; j++) { + for (int j = 0; j < tCR; j++) { int zD, zF; if (amount < 0) { - zD = j - delta; - zF = zD - 1; + zD = j - delta; + zF = zD - 1; } else { - zD = j + delta; - zF = zD + 1; + zD = j + delta; + zF = zD + 1; } - CRGB PixelA = CRGB::Black; - if ((zD >= 0) && (zD < colrow)) PixelA = isRow ? SEGMENT.getPixelColorXY(zD, i) : SEGMENT.getPixelColorXY(i, zD); - else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? XY(abs(zD), i) : XY(i, abs(zD))] * 3); - CRGB PixelB = CRGB::Black; - if ((zF >= 0) && (zF < colrow)) PixelB = isRow ? SEGMENT.getPixelColorXY(zF, i) : SEGMENT.getPixelColorXY(i, zF); - else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[isRow ? XY(abs(zF), i) : XY(i, abs(zF))] * 3); + int yA = abs(zD); + int yB = abs(zF); + int xA = i; + int xB = i; + if (isRow) { + std::swap(xA,yA); + std::swap(xB,yB); + } + const int indxA = XY(xA,yA); + const int indxB = XY(xB,yB); + CRGB PixelA; + CRGB PixelB; + if ((zD >= 0) && (zD < tCR)) PixelA = pixels[indxA]; + else PixelA = ColorFromPalette(SEGPALETTE, ~noise3d[indxA]*3); + if ((zF >= 0) && (zF < tCR)) PixelB = pixels[indxB]; + else PixelB = ColorFromPalette(SEGPALETTE, ~noise3d[indxB]*3); ledsbuff[j] = (PixelA.nscale8(ease8InOutApprox(255 - fraction))) + (PixelB.nscale8(ease8InOutApprox(fraction))); } - for (int j = 0; j < colrow; j++) { - if (isRow) SEGMENT.setPixelColorXY(j, i, ledsbuff[j]); - else SEGMENT.setPixelColorXY(i, j, ledsbuff[j]); + for (int j = 0; j < tCR; j++) { + CRGB c = ledsbuff[j]; + if (isRow) std::swap(j,i); + SEGMENT.setPixelColorXY(i, j, pixels[XY(i,j)] = c); + if (isRow) std::swap(j,i); } } } @@ -7512,24 +7526,22 @@ uint16_t mode_2Dsoap() { const int cols = SEG_W; const int rows = SEG_H; - const auto XY = [&](int x, int y) { return (x%cols) + (y%rows) * cols; }; + const auto XY = [&](int x, int y) { return x + y * cols; }; - const size_t dataSize = SEGMENT.width() * SEGMENT.height() * sizeof(uint8_t); // prevent reallocation if mirrored or grouped + const size_t segSize = SEGMENT.width() * SEGMENT.height(); // prevent reallocation if mirrored or grouped + const size_t dataSize = segSize * (sizeof(uint8_t) + sizeof(CRGB)); // pixels and noise if (!SEGENV.allocateData(dataSize + sizeof(uint32_t)*3)) return mode_static(); //allocation failed uint8_t *noise3d = reinterpret_cast(SEGENV.data); + CRGB *pixels = reinterpret_cast(SEGENV.data + segSize * sizeof(uint8_t)); uint32_t *noisecoord = reinterpret_cast(SEGENV.data + dataSize); // x, y, z coordinates const uint32_t scale32_x = 160000U/cols; const uint32_t scale32_y = 160000U/rows; const uint32_t mov = MIN(cols,rows)*(SEGMENT.speed+2)/2; const uint8_t smoothness = MIN(250,SEGMENT.intensity); // limit as >250 produces very little changes - for (int i = 0; i < 3; i++) { - if (SEGENV.call == 0) - noisecoord[i] = hw_random(); // init - else - noisecoord[i] += mov; - } + if (SEGENV.call == 0) for (int i = 0; i < 3; i++) noisecoord[i] = hw_random(); // init + else for (int i = 0; i < 3; i++) noisecoord[i] += mov; for (int i = 0; i < cols; i++) { int32_t ioffset = scale32_x * (i - cols / 2); @@ -7550,12 +7562,12 @@ uint16_t mode_2Dsoap() { } } - soapProcessPixels(true, noise3d); // rows - soapProcessPixels(false, noise3d); // cols + soapPixels(true, noise3d, pixels); // rows + soapPixels(false, noise3d, pixels); // cols return FRAMETIME; } -static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness,Density;;!;2;pal=11"; +static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness,Density;;!;2;pal=11,c1=0"; //Idea from https://www.youtube.com/watch?v=HsA-6KIbgto&ab_channel=GreatScott%21 From f3de45c6ad7f8a64788ea320212ee4ca933120db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sun, 9 Feb 2025 21:43:35 +0100 Subject: [PATCH 312/463] Remove reference to custom allocators --- wled00/bus_manager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 2a7dce4f..cdb00b0b 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -145,7 +145,7 @@ BusDigital::BusDigital(const BusConfig &bc, uint8_t nr) _hasWhite = hasWhite(bc.type); _hasCCT = hasCCT(bc.type); if (bc.doubleBuffer) { - _data = (uint8_t*)d_calloc(_len, Bus::getNumberOfChannels(_type)); + _data = (uint8_t*)calloc(_len, Bus::getNumberOfChannels(_type)); if (!_data) DEBUG_PRINTLN(F("Bus: Buffer allocation failed!")); } uint16_t lenToCreate = bc.count; @@ -744,7 +744,7 @@ BusNetwork::BusNetwork(const BusConfig &bc) _hasCCT = false; _UDPchannels = _hasWhite + 3; _client = IPAddress(bc.pins[0],bc.pins[1],bc.pins[2],bc.pins[3]); - _data = (uint8_t*)d_calloc(_len, _UDPchannels); + _data = (uint8_t*)calloc(_len, _UDPchannels); _valid = (_data != nullptr); DEBUG_PRINTF_P(PSTR("%successfully inited virtual strip with type %u and IP %u.%u.%u.%u\n"), _valid?"S":"Uns", bc.type, bc.pins[0], bc.pins[1], bc.pins[2], bc.pins[3]); } From 2cc73660bfb09cc851a8529b53c30a4343b01165 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 10 Feb 2025 08:30:36 +0100 Subject: [PATCH 313/463] bugfix (XY needs the modulo for zF/zD), updated amplitude for better range --- wled00/FX.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 44366bbc..26b7779d 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7472,11 +7472,11 @@ static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@ static void soapPixels(bool isRow, uint8_t *noise3d, CRGB *pixels) { const int cols = SEG_W; const int rows = SEG_H; - const auto XY = [&](int x, int y) { return x + y * cols; }; + const auto XY = [&](int x, int y) { return (x%cols) + (y%rows) * cols; }; const auto abs = [](int x) { return x<0 ? -x : x; }; const int tRC = isRow ? rows : cols; // transpose if isRow const int tCR = isRow ? cols : rows; // transpose if isRow - const int amplitude = 2 * ((tCR >= 16) ? (tCR-8) : 8) / (1 + ((255 - SEGMENT.custom1) >> 5)); + const int amplitude = max(1, (tCR - 8) >> 3) * (1 + (SEGMENT.custom1 >> 5)); const int shift = 0; //(128 - SEGMENT.custom2)*2; CRGB ledsbuff[tCR]; From bdec873fed0617ffaf3271c36a396cee1d4b505b Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 10 Feb 2025 08:42:22 +0100 Subject: [PATCH 314/463] removed slider default --- wled00/FX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 26b7779d..82fc9996 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7567,7 +7567,7 @@ uint16_t mode_2Dsoap() { return FRAMETIME; } -static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness,Density;;!;2;pal=11,c1=0"; +static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness,Density;;!;2;pal=11"; //Idea from https://www.youtube.com/watch?v=HsA-6KIbgto&ab_channel=GreatScott%21 From aba736cb965f9dde78780883dd6d1e533e8e1f5d Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 10 Feb 2025 20:26:34 +0100 Subject: [PATCH 315/463] moved modulo --- wled00/FX.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 82fc9996..95cf3a7e 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7472,7 +7472,7 @@ static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@ static void soapPixels(bool isRow, uint8_t *noise3d, CRGB *pixels) { const int cols = SEG_W; const int rows = SEG_H; - const auto XY = [&](int x, int y) { return (x%cols) + (y%rows) * cols; }; + const auto XY = [&](int x, int y) { return x + y * cols; }; const auto abs = [](int x) { return x<0 ? -x : x; }; const int tRC = isRow ? rows : cols; // transpose if isRow const int tCR = isRow ? cols : rows; // transpose if isRow @@ -7494,8 +7494,8 @@ static void soapPixels(bool isRow, uint8_t *noise3d, CRGB *pixels) { zD = j + delta; zF = zD + 1; } - int yA = abs(zD); - int yB = abs(zF); + int yA = abs(zD)%tCR; + int yB = abs(zF)%tCR; int xA = i; int xB = i; if (isRow) { From e7e0eb0f3203d3979d803338faa3cc5ce8c52a24 Mon Sep 17 00:00:00 2001 From: Brandon502 <105077712+Brandon502@users.noreply.github.com> Date: Thu, 13 Feb 2025 19:01:10 -0500 Subject: [PATCH 316/463] Pinwheel Rework Optimized pinwheel algorithm. Math and memory optimizations by @DedeHai --- wled00/FX_fcn.cpp | 222 +++++++++++++++++++++++++--------------------- 1 file changed, 122 insertions(+), 100 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 42046024..9c40113d 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -680,37 +680,25 @@ unsigned Segment::virtualHeight() const { // Constants for mapping mode "Pinwheel" #ifndef WLED_DISABLE_2D -constexpr int Pinwheel_Steps_Small = 72; // no holes up to 16x16 -constexpr int Pinwheel_Size_Small = 16; // larger than this -> use "Medium" -constexpr int Pinwheel_Steps_Medium = 192; // no holes up to 32x32 -constexpr int Pinwheel_Size_Medium = 32; // larger than this -> use "Big" -constexpr int Pinwheel_Steps_Big = 304; // no holes up to 50x50 -constexpr int Pinwheel_Size_Big = 50; // larger than this -> use "XL" -constexpr int Pinwheel_Steps_XL = 368; -constexpr float Int_to_Rad_Small = (DEG_TO_RAD * 360) / Pinwheel_Steps_Small; // conversion: from 0...72 to Radians -constexpr float Int_to_Rad_Med = (DEG_TO_RAD * 360) / Pinwheel_Steps_Medium; // conversion: from 0...192 to Radians -constexpr float Int_to_Rad_Big = (DEG_TO_RAD * 360) / Pinwheel_Steps_Big; // conversion: from 0...304 to Radians -constexpr float Int_to_Rad_XL = (DEG_TO_RAD * 360) / Pinwheel_Steps_XL; // conversion: from 0...368 to Radians - -constexpr int Fixed_Scale = 512; // fixpoint scaling factor (9bit for fraction) - -// Pinwheel helper function: pixel index to radians -static float getPinwheelAngle(int i, int vW, int vH) { - int maxXY = max(vW, vH); - if (maxXY <= Pinwheel_Size_Small) return float(i) * Int_to_Rad_Small; - if (maxXY <= Pinwheel_Size_Medium) return float(i) * Int_to_Rad_Med; - if (maxXY <= Pinwheel_Size_Big) return float(i) * Int_to_Rad_Big; - // else - return float(i) * Int_to_Rad_XL; -} +constexpr int Fixed_Scale = 16384; // fixpoint scaling factor (14bit for fraction) // Pinwheel helper function: matrix dimensions to number of rays static int getPinwheelLength(int vW, int vH) { - int maxXY = max(vW, vH); - if (maxXY <= Pinwheel_Size_Small) return Pinwheel_Steps_Small; - if (maxXY <= Pinwheel_Size_Medium) return Pinwheel_Steps_Medium; - if (maxXY <= Pinwheel_Size_Big) return Pinwheel_Steps_Big; - // else - return Pinwheel_Steps_XL; + // Returns multiple of 8, prevents over drawing + return (max(vW, vH) + 15) & ~7; +} +static void setPinwheelParameters(int i, int vW, int vH, int& startx, int& starty, int* cosVal, int* sinVal, bool getPixel = false) { + int steps = getPinwheelLength(vW, vH); + int baseAngle = ((0xFFFF + steps / 2) / steps); // 360° / steps, in 16 bit scale round to nearest integer + int rotate = 0; + if (getPixel) rotate = baseAngle / 2; // rotate by half a ray width when reading pixel color + for (int k = 0; k < 2; k++) // angular steps for two consecutive rays + { + int angle = (i + k) * baseAngle + rotate; + cosVal[k] = (cos16(angle) * Fixed_Scale) >> 15; // step per pixel in fixed point, cos16 output is -0x7FFF to +0x7FFF + sinVal[k] = (sin16(angle) * Fixed_Scale) >> 15; // using explicit bit shifts as dividing negative numbers is not equivalent (rounding error is acceptable) + } + startx = (vW * Fixed_Scale) / 2; // + cosVal[0] / 4; // starting position = center + 1/4 pixel (in fixed point) + starty = (vH * Fixed_Scale) / 2; // + sinVal[0] / 4; } #endif @@ -845,55 +833,103 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) const for (int x = 0; x <= i; x++) setPixelColorXY(x, i, col); for (int y = 0; y < i; y++) setPixelColorXY(i, y, col); break; - case M12_sPinwheel: { - // i = angle --> 0 - 296 (Big), 0 - 192 (Medium), 0 - 72 (Small) - float centerX = roundf((vW-1) / 2.0f); - float centerY = roundf((vH-1) / 2.0f); - float angleRad = getPinwheelAngle(i, vW, vH); // angle in radians - float cosVal = cos_t(angleRad); - float sinVal = sin_t(angleRad); - - // avoid re-painting the same pixel - int lastX = INT_MIN; // impossible position - int lastY = INT_MIN; // impossible position - // draw line at angle, starting at center and ending at the segment edge - // we use fixed point math for better speed. Starting distance is 0.5 for better rounding - // int_fast16_t and int_fast32_t types changed to int, minimum bits commented - int posx = (centerX + 0.5f * cosVal) * Fixed_Scale; // X starting position in fixed point 18 bit - int posy = (centerY + 0.5f * sinVal) * Fixed_Scale; // Y starting position in fixed point 18 bit - int inc_x = cosVal * Fixed_Scale; // X increment per step (fixed point) 10 bit - int inc_y = sinVal * Fixed_Scale; // Y increment per step (fixed point) 10 bit - - int32_t maxX = vW * Fixed_Scale; // X edge in fixedpoint - int32_t maxY = vH * Fixed_Scale; // Y edge in fixedpoint - - // Odd rays start further from center if prevRay started at center. - static int prevRay = INT_MIN; // previous ray number - if ((i % 2 == 1) && (i - 1 == prevRay || i + 1 == prevRay)) { - int jump = min(vW/3, vH/3); // can add 2 if using medium pinwheel - posx += inc_x * jump; - posy += inc_y * jump; + case M12_sPinwheel: { + // Uses Bresenham's algorithm to place coordinates of two lines in arrays then draws between them + int startX, startY, cosVal[2], sinVal[2]; // in fixed point scale + setPinwheelParameters(i, vW, vH, startX, startY, cosVal, sinVal); + + unsigned maxLineLength = max(vW, vH) + 2; // pixels drawn is always smaller than dx or dy, +1 pair for rounding errors + uint16_t lineCoords[2][maxLineLength]; // uint16_t to save ram + int lineLength[2] = {0}; + + static int prevRays[2] = {INT_MAX, INT_MAX}; // previous two ray numbers + int closestEdgeIdx = INT_MAX; // index of the closest edge pixel + + for (int lineNr = 0; lineNr < 2; lineNr++) { + int x0 = startX; // x, y coordinates in fixed scale + int y0 = startY; + int x1 = (startX + (cosVal[lineNr] << 9)); // outside of grid + int y1 = (startY + (sinVal[lineNr] << 9)); // outside of grid + const int dx = abs(x1-x0), sx = x0= vW || unsigned(y0) >= vH) { + closestEdgeIdx = min(closestEdgeIdx, idx-2); + break; // stop if outside of grid (exploit unsigned int overflow) + } + coordinates[idx++] = x0; + coordinates[idx++] = y0; + (*length)++; + // note: since endpoint is out of grid, no need to check if endpoint is reached + int e2 = 2 * err; + if (e2 >= dy) { err += dy; x0 += sx; } + if (e2 <= dx) { err += dx; y0 += sy; } + } + } + + // fill up the shorter line with missing coordinates, so block filling works correctly and efficiently + int diff = lineLength[0] - lineLength[1]; + int longLineIdx = (diff > 0) ? 0 : 1; + int shortLineIdx = longLineIdx ? 0 : 1; + if (diff != 0) { + int idx = (lineLength[shortLineIdx] - 1) * 2; // last valid coordinate index + int lastX = lineCoords[shortLineIdx][idx++]; + int lastY = lineCoords[shortLineIdx][idx++]; + bool keepX = lastX == 0 || lastX == vW - 1; + for (int d = 0; d < abs(diff); d++) { + lineCoords[shortLineIdx][idx] = keepX ? lastX :lineCoords[longLineIdx][idx]; + idx++; + lineCoords[shortLineIdx][idx] = keepX ? lineCoords[longLineIdx][idx] : lastY; + idx++; + } + } + + // draw and block-fill the line coordinates. Note: block filling only efficient if angle between lines is small + closestEdgeIdx += 2; + int max_i = getPinwheelLength(vW, vH) - 1; + bool drawFirst = !(prevRays[0] == i - 1 || (i == 0 && prevRays[0] == max_i)); // draw first line if previous ray was not adjacent including wrap + bool drawLast = !(prevRays[0] == i + 1 || (i == max_i && prevRays[0] == 0)); // same as above for last line + for (int idx = 0; idx < lineLength[longLineIdx] * 2;) { //!! should be long line idx! + int x1 = lineCoords[0][idx]; + int x2 = lineCoords[1][idx++]; + int y1 = lineCoords[0][idx]; + int y2 = lineCoords[1][idx++]; + int minX, maxX, minY, maxY; + (x1 < x2) ? (minX = x1, maxX = x2) : (minX = x2, maxX = x1); + (y1 < y2) ? (minY = y1, maxY = y2) : (minY = y2, maxY = y1); + + // fill the block between the two x,y points + bool alwaysDraw = (drawFirst && drawLast) || // No adjacent rays, draw all pixels + (idx > closestEdgeIdx) || // Edge pixels on uneven lines are always drawn + (i == 0 && idx == 2) || // Center pixel special case + (i == prevRays[1]); // Effect drawing twice in 1 frame + for (int x = minX; x <= maxX; x++) { + for (int y = minY; y <= maxY; y++) { + bool onLine1 = x == x1 && y == y1; + bool onLine2 = x == x2 && y == y2; + if ((alwaysDraw) || + (!onLine1 && (!onLine2 || drawLast)) || // Middle pixels and line2 if drawLast + (!onLine2 && (!onLine1 || drawFirst)) // Middle pixels and line1 if drawFirst + ) { + setPixelColorXY(x, y, col); + } + } + } + } + prevRays[1] = prevRays[0]; + prevRays[0] = i; + break; } - prevRay = i; - - // draw ray until we hit any edge - while ((posx >= 0) && (posy >= 0) && (posx < maxX) && (posy < maxY)) { - // scale down to integer (compiler will replace division with appropriate bitshift) - int x = posx / Fixed_Scale; - int y = posy / Fixed_Scale; - // set pixel - if (x != lastX || y != lastY) setPixelColorXY(x, y, col); // only paint if pixel position is different - lastX = x; - lastY = y; - // advance to next position - posx += inc_x; - posy += inc_y; - } - break; } - } - _colorScaled = false; - return; + return; } else if (Segment::maxHeight != 1 && (width() == 1 || height() == 1)) { if (start < Segment::maxWidth*Segment::maxHeight) { // we have a vertical or horizontal 1D segment (WARNING: virtual...() may be transposed) @@ -1025,31 +1061,17 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const break; case M12_sPinwheel: // not 100% accurate, returns pixel at outer edge - // i = angle --> 0 - 296 (Big), 0 - 192 (Medium), 0 - 72 (Small) - float centerX = roundf((vW-1) / 2.0f); - float centerY = roundf((vH-1) / 2.0f); - float angleRad = getPinwheelAngle(i, vW, vH); // angle in radians - float cosVal = cos_t(angleRad); - float sinVal = sin_t(angleRad); - - int posx = (centerX + 0.5f * cosVal) * Fixed_Scale; // X starting position in fixed point 18 bit - int posy = (centerY + 0.5f * sinVal) * Fixed_Scale; // Y starting position in fixed point 18 bit - int inc_x = cosVal * Fixed_Scale; // X increment per step (fixed point) 10 bit - int inc_y = sinVal * Fixed_Scale; // Y increment per step (fixed point) 10 bit - int32_t maxX = vW * Fixed_Scale; // X edge in fixedpoint - int32_t maxY = vH * Fixed_Scale; // Y edge in fixedpoint - - // trace ray from center until we hit any edge - to avoid rounding problems, we use the same method as in setPixelColor - int x = INT_MIN; - int y = INT_MIN; - while ((posx >= 0) && (posy >= 0) && (posx < maxX) && (posy < maxY)) { - // scale down to integer (compiler will replace division with appropriate bitshift) - x = posx / Fixed_Scale; - y = posy / Fixed_Scale; - // advance to next position - posx += inc_x; - posy += inc_y; + int x, y, cosVal[2], sinVal[2]; + setPinwheelParameters(i, vW, vH, x, y, cosVal, sinVal, true); + int maxX = (vW-1) * Fixed_Scale; + int maxY = (vH-1) * Fixed_Scale; + // trace ray from center until we hit any edge - to avoid rounding problems, we use fixed point coordinates + while ((x < maxX) && (y < maxY) && (x > Fixed_Scale) && (y > Fixed_Scale)) { + x += cosVal[0]; // advance to next position + y += sinVal[0]; } + x /= Fixed_Scale; + y /= Fixed_Scale; return getPixelColorXY(x, y); break; } From 778cecb5124a0e637876c137a4cd031a36d7e048 Mon Sep 17 00:00:00 2001 From: SpiroC Date: Sat, 15 Feb 2025 14:43:08 +1100 Subject: [PATCH 317/463] Check if Node.js is installed and present in PATH --- pio-scripts/build_ui.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/pio-scripts/build_ui.py b/pio-scripts/build_ui.py index f3688a5d..047fac44 100644 --- a/pio-scripts/build_ui.py +++ b/pio-scripts/build_ui.py @@ -1,3 +1,21 @@ -Import('env') +Import("env") +import shutil -env.Execute("npm run build") \ No newline at end of file +node_ex = shutil.which("node") +# Check if Node.js is installed and present in PATH if it failed, abort the build +if node_ex is None: + print('\x1b[0;31;43m' + 'Node.js is not installed or missing from PATH html css js will not be processed check https://kno.wled.ge/advanced/compiling-wled/' + '\x1b[0m') + exitCode = env.Execute("null") + exit(exitCode) +else: + # Install the necessary node packages for the pre-build asset bundling script + print('\x1b[6;33;42m' + 'Installing node packages' + '\x1b[0m') + env.Execute("npm install") + + # Call the bundling script + exitCode = env.Execute("npm run build") + + # If it failed, abort the build + if (exitCode): + print('\x1b[0;31;43m' + 'npm run build fails check https://kno.wled.ge/advanced/compiling-wled/' + '\x1b[0m') + exit(exitCode) \ No newline at end of file From b34d65fce051db93d72a6fdde93da45b12014083 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 15 Feb 2025 10:34:44 +0100 Subject: [PATCH 318/463] fix for incorrect hardware timing --- wled00/wled.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/wled00/wled.cpp b/wled00/wled.cpp index c9cd9479..2a5902d1 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -760,6 +760,7 @@ void WLED::initConnection() #endif WiFi.disconnect(true); // close old connections + delay(5); // wait for hardware to be ready #ifdef ESP8266 WiFi.setPhyMode(force802_3g ? WIFI_PHY_MODE_11G : WIFI_PHY_MODE_11N); #endif From 7f24269511642d02f1b5398370b9f021ba835828 Mon Sep 17 00:00:00 2001 From: maxi4329 <84231420+maxi4329@users.noreply.github.com> Date: Sat, 15 Feb 2025 15:14:52 +0100 Subject: [PATCH 319/463] Fix for #4153 (#4253) * fix for #4153 * only load touch/mouse events for touch/mouse devices * undid formating changes * undid more formating changes * undid all formating changes * use pointerover and pointerout eventlisteners --- wled00/data/common.js | 4 ++-- wled00/data/index.js | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/wled00/data/common.js b/wled00/data/common.js index 9378ef07..eddaf654 100644 --- a/wled00/data/common.js +++ b/wled00/data/common.js @@ -16,7 +16,7 @@ function isI(n) { return n === +n && n === (n|0); } // isInteger function toggle(el) { gId(el).classList.toggle("hide"); gId('No'+el).classList.toggle("hide"); } function tooltip(cont=null) { d.querySelectorAll((cont?cont+" ":"")+"[title]").forEach((element)=>{ - element.addEventListener("mouseover", ()=>{ + element.addEventListener("pointerover", ()=>{ // save title element.setAttribute("data-title", element.getAttribute("title")); const tooltip = d.createElement("span"); @@ -41,7 +41,7 @@ function tooltip(cont=null) { tooltip.classList.add("visible"); }); - element.addEventListener("mouseout", ()=>{ + element.addEventListener("pointerout", ()=>{ d.querySelectorAll('.tooltip').forEach((tooltip)=>{ tooltip.classList.remove("visible"); d.body.removeChild(tooltip); diff --git a/wled00/data/index.js b/wled00/data/index.js index 8237e691..94bdb4ad 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -3122,10 +3122,9 @@ function mergeDeep(target, ...sources) return mergeDeep(target, ...sources); } -function tooltip(cont=null) -{ +function tooltip(cont=null) { d.querySelectorAll((cont?cont+" ":"")+"[title]").forEach((element)=>{ - element.addEventListener("mouseover", ()=>{ + element.addEventListener("pointerover", ()=>{ // save title element.setAttribute("data-title", element.getAttribute("title")); const tooltip = d.createElement("span"); @@ -3150,7 +3149,7 @@ function tooltip(cont=null) tooltip.classList.add("visible"); }); - element.addEventListener("mouseout", ()=>{ + element.addEventListener("pointerout", ()=>{ d.querySelectorAll('.tooltip').forEach((tooltip)=>{ tooltip.classList.remove("visible"); d.body.removeChild(tooltip); From aa3fb7d165ad9a846f0eb3f2460d361238de1791 Mon Sep 17 00:00:00 2001 From: maxi4329 Date: Sat, 15 Feb 2025 20:07:41 +0100 Subject: [PATCH 320/463] update links to point to the new repo --- .github/ISSUE_TEMPLATE/bug.yml | 2 +- CONTRIBUTING.md | 2 +- package.json | 6 +++--- platformio_override.sample.ini | 2 +- readme.md | 6 +++--- tools/cdata.js | 2 +- usermods/EXAMPLE_v2/usermod_v2_example.h | 2 +- .../usermod_Fix_unreachable_netservices.h | 2 +- usermods/PIR_sensor_switch/PIR_Highlight_Standby | 2 +- usermods/PIR_sensor_switch/readme.md | 2 +- .../PIR_sensor_switch/usermod_PIR_sensor_switch.h | 2 +- usermods/TTGO-T-Display/usermod.cpp | 2 +- usermods/TetrisAI_v2/readme.md | 2 +- usermods/audioreactive/audio_reactive.h | 2 +- usermods/buzzer/usermod_v2_buzzer.h | 2 +- usermods/photoresistor_sensor_mqtt_v1/usermod.cpp | 2 +- .../platformio_override.ini.sample | 2 +- .../stairway_wipe_basic/stairway-wipe-usermod-v2.h | 2 +- .../usermod_v2_word_clock/usermod_v2_word_clock.h | 2 +- wled00/FX.cpp | 2 +- wled00/FX_fcn.cpp | 2 +- wled00/bus_manager.cpp | 14 +++++++------- wled00/colors.cpp | 2 +- wled00/data/common.js | 2 +- wled00/data/index.htm | 2 +- wled00/data/index.js | 4 ++-- wled00/data/settings_dmx.htm | 2 +- wled00/data/settings_sec.htm | 6 +++--- wled00/data/update.htm | 4 ++-- wled00/ir.cpp | 2 +- wled00/usermod.cpp | 2 +- wled00/util.cpp | 2 +- wled00/wled.h | 2 +- wled00/wled_eeprom.cpp | 2 +- 34 files changed, 48 insertions(+), 48 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 285ad419..6f010aa6 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -80,7 +80,7 @@ body: id: terms attributes: label: Code of Conduct - description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/Aircoookie/WLED/blob/master/CODE_OF_CONDUCT.md) + description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/wled-dev/WLED/blob/main/CODE_OF_CONDUCT.md) options: - label: I agree to follow this project's Code of Conduct required: true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 670b5561..e2078df7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,7 +27,7 @@ Github will pick up the changes so your PR stays up-to-date. > For example, we regularly lost review comments when the PR author force-pushes code changes. So, pretty please, do not force-push. -You can find a collection of very useful tips and tricks here: https://github.com/Aircoookie/WLED/wiki/How-to-properly-submit-a-PR +You can find a collection of very useful tips and tricks here: https://github.com/wled-dev/WLED/wiki/How-to-properly-submit-a-PR ### Code style diff --git a/package.json b/package.json index 68260982..26d24127 100644 --- a/package.json +++ b/package.json @@ -14,14 +14,14 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/Aircoookie/WLED.git" + "url": "git+https://github.com/wled-dev/WLED.git" }, "author": "", "license": "ISC", "bugs": { - "url": "https://github.com/Aircoookie/WLED/issues" + "url": "https://github.com/wled-dev/WLED/issues" }, - "homepage": "https://github.com/Aircoookie/WLED#readme", + "homepage": "https://github.com/wled-dev/WLED#readme", "dependencies": { "clean-css": "^5.3.3", "html-minifier-terser": "^7.2.0", diff --git a/platformio_override.sample.ini b/platformio_override.sample.ini index 19b8c273..36cc4d67 100644 --- a/platformio_override.sample.ini +++ b/platformio_override.sample.ini @@ -280,7 +280,7 @@ lib_deps = ${esp32s2.lib_deps} [env:esp32s3dev_8MB_PSRAM_qspi] ;; ESP32-TinyS3 development board, with 8MB FLASH and PSRAM (memory_type: qio_qspi) extends = env:esp32s3dev_8MB_PSRAM_opi -;board = um_tinys3 ; -> needs workaround from https://github.com/Aircoookie/WLED/pull/2905#issuecomment-1328049860 +;board = um_tinys3 ; -> needs workaround from https://github.com/wled-dev/WLED/pull/2905#issuecomment-1328049860 board = esp32-s3-devkitc-1 ;; generic dev board; the next line adds PSRAM support board_build.arduino.memory_type = qio_qspi ;; use with PSRAM: 2MB or 4MB diff --git a/readme.md b/readme.md index 8c9a0880..c0d24cff 100644 --- a/readme.md +++ b/readme.md @@ -1,12 +1,12 @@

- - + + - +

diff --git a/tools/cdata.js b/tools/cdata.js index c5d3c6aa..b2feffee 100644 --- a/tools/cdata.js +++ b/tools/cdata.js @@ -89,7 +89,7 @@ function adoptVersionAndRepo(html) { repoUrl = repoUrl.replace(/^git\+/, ""); repoUrl = repoUrl.replace(/\.git$/, ""); html = html.replaceAll("https://github.com/atuline/WLED", repoUrl); - html = html.replaceAll("https://github.com/Aircoookie/WLED", repoUrl); + html = html.replaceAll("https://github.com/wled-dev/WLED", repoUrl); } let version = packageJson.version; if (version) { diff --git a/usermods/EXAMPLE_v2/usermod_v2_example.h b/usermods/EXAMPLE_v2/usermod_v2_example.h index df05f3e3..4c07ad17 100644 --- a/usermods/EXAMPLE_v2/usermod_v2_example.h +++ b/usermods/EXAMPLE_v2/usermod_v2_example.h @@ -4,7 +4,7 @@ /* * Usermods allow you to add own functionality to WLED more easily - * See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality + * See: https://github.com/wled-dev/WLED/wiki/Add-own-functionality * * This is an example for a v2 usermod. * v2 usermods are class inheritance based and can (but don't have to) implement more functions, each of them is shown in this example. diff --git a/usermods/Fix_unreachable_netservices_v2/usermod_Fix_unreachable_netservices.h b/usermods/Fix_unreachable_netservices_v2/usermod_Fix_unreachable_netservices.h index 3d441e59..d3a00ac6 100644 --- a/usermods/Fix_unreachable_netservices_v2/usermod_Fix_unreachable_netservices.h +++ b/usermods/Fix_unreachable_netservices_v2/usermod_Fix_unreachable_netservices.h @@ -16,7 +16,7 @@ class FixUnreachableNetServices : public Usermod * By this procedure the net services of WLED remains accessible in some problematic WLAN environments. * * Usermods allow you to add own functionality to WLED more easily - * See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality + * See: https://github.com/wled-dev/WLED/wiki/Add-own-functionality * * v2 usermods are class inheritance based and can (but don't have to) implement more functions, each of them is shown in this example. * Multiple v2 usermods can be added to one compilation easily. diff --git a/usermods/PIR_sensor_switch/PIR_Highlight_Standby b/usermods/PIR_sensor_switch/PIR_Highlight_Standby index 152388e8..4ca32bf4 100644 --- a/usermods/PIR_sensor_switch/PIR_Highlight_Standby +++ b/usermods/PIR_sensor_switch/PIR_Highlight_Standby @@ -42,7 +42,7 @@ * * * Usermods allow you to add own functionality to WLED more easily - * See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality + * See: https://github.com/wled-dev/WLED/wiki/Add-own-functionality * * v2 usermods are class inheritance based and can (but don't have to) implement more functions, each of them is shown in this example. * Multiple v2 usermods can be added to one compilation easily. diff --git a/usermods/PIR_sensor_switch/readme.md b/usermods/PIR_sensor_switch/readme.md index fac5419f..be55406d 100644 --- a/usermods/PIR_sensor_switch/readme.md +++ b/usermods/PIR_sensor_switch/readme.md @@ -5,7 +5,7 @@ This usermod-v2 modification allows the connection of a PIR sensor to switch on _Story:_ I use the PIR Sensor to automatically turn on the WLED analog clock in my home office room when I am there. -The LED strip is switched [using a relay](https://github.com/Aircoookie/WLED/wiki/Control-a-relay-with-WLED) to keep the power consumption low when it is switched off. +The LED strip is switched [using a relay](https://kno.wled.ge/features/relay-control/) to keep the power consumption low when it is switched off. ## Web interface diff --git a/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h b/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h index 0deda181..a61d05f3 100644 --- a/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h +++ b/usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h @@ -26,7 +26,7 @@ * Maintained by: @blazoncek * * Usermods allow you to add own functionality to WLED more easily - * See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality + * See: https://github.com/wled-dev/WLED/wiki/Add-own-functionality * * v2 usermods are class inheritance based and can (but don't have to) implement more functions, each of them is shown in this example. * Multiple v2 usermods can be added to one compilation easily. diff --git a/usermods/TTGO-T-Display/usermod.cpp b/usermods/TTGO-T-Display/usermod.cpp index cbba0777..d8dcb299 100644 --- a/usermods/TTGO-T-Display/usermod.cpp +++ b/usermods/TTGO-T-Display/usermod.cpp @@ -1,7 +1,7 @@ /* * This file allows you to add own functionality to WLED more easily - * See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality + * See: https://github.com/wled-dev/WLED/wiki/Add-own-functionality * EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h) * bytes 2400+ are currently unused, but might be used for future wled features */ diff --git a/usermods/TetrisAI_v2/readme.md b/usermods/TetrisAI_v2/readme.md index b56f801a..5ac80289 100644 --- a/usermods/TetrisAI_v2/readme.md +++ b/usermods/TetrisAI_v2/readme.md @@ -6,7 +6,7 @@ Version 1.0 ## Installation -Just activate the usermod with `-D USERMOD_TETRISAI` and the effect will become available under the name 'Tetris AI'. If you are running out of flash memory, use a different memory layout (e.g. [WLED_ESP32_4MB_256KB_FS.csv](https://github.com/Aircoookie/WLED/blob/main/tools/WLED_ESP32_4MB_256KB_FS.csv)). +Just activate the usermod with `-D USERMOD_TETRISAI` and the effect will become available under the name 'Tetris AI'. If you are running out of flash memory, use a different memory layout (e.g. [WLED_ESP32_4MB_256KB_FS.csv](https://github.com/wled-dev/WLED/blob/main/tools/WLED_ESP32_4MB_256KB_FS.csv)). If needed simply add to `platformio_override.ini` (or `platformio_override.ini`): diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index 9c463e0a..e6b62009 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -19,7 +19,7 @@ /* * Usermods allow you to add own functionality to WLED more easily - * See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality + * See: https://github.com/wled-dev/WLED/wiki/Add-own-functionality * * This is an audioreactive v2 usermod. * .... diff --git a/usermods/buzzer/usermod_v2_buzzer.h b/usermods/buzzer/usermod_v2_buzzer.h index ebd8dcb1..c6c2a47a 100644 --- a/usermods/buzzer/usermod_v2_buzzer.h +++ b/usermods/buzzer/usermod_v2_buzzer.h @@ -12,7 +12,7 @@ /* * Usermods allow you to add own functionality to WLED more easily - * See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality + * See: https://github.com/wled-dev/WLED/wiki/Add-own-functionality * * Using a usermod: * 1. Copy the usermod into the sketch folder (same folder as wled00.ino) diff --git a/usermods/photoresistor_sensor_mqtt_v1/usermod.cpp b/usermods/photoresistor_sensor_mqtt_v1/usermod.cpp index fff7118f..bbbefc10 100644 --- a/usermods/photoresistor_sensor_mqtt_v1/usermod.cpp +++ b/usermods/photoresistor_sensor_mqtt_v1/usermod.cpp @@ -1,7 +1,7 @@ #include "wled.h" /* * This v1 usermod file allows you to add own functionality to WLED more easily - * See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality + * See: https://github.com/wled-dev/WLED/wiki/Add-own-functionality * EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h) * If you just need 8 bytes, use 2551-2559 (you do not need to increase EEPSIZE) * diff --git a/usermods/pixels_dice_tray/platformio_override.ini.sample b/usermods/pixels_dice_tray/platformio_override.ini.sample index b712f8b2..6b4fa776 100644 --- a/usermods/pixels_dice_tray/platformio_override.ini.sample +++ b/usermods/pixels_dice_tray/platformio_override.ini.sample @@ -102,7 +102,7 @@ lib_deps = ${esp32s3.lib_deps} # parallel. Also not clear exactly what difference between the ESP32 and the # ESP32S3 would be causing this, though they do run different BLE versions. # May be related to some of the issues discussed in: -# https://github.com/Aircoookie/WLED/issues/1382 +# https://github.com/wled-dev/WLED/issues/1382 ; [env:esp32dev_dice] ; extends = env:esp32dev ; build_flags = ${common.build_flags} ${esp32.build_flags} -D WLED_RELEASE_NAME=ESP32 diff --git a/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h b/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h index 707479df..f603ed6f 100644 --- a/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h +++ b/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h @@ -2,7 +2,7 @@ /* * Usermods allow you to add own functionality to WLED more easily - * See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality + * See: https://github.com/wled-dev/WLED/wiki/Add-own-functionality * * This is Stairway-Wipe as a v2 usermod. * diff --git a/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h b/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h index 7ecec08e..1fe1a1a2 100644 --- a/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h +++ b/usermods/usermod_v2_word_clock/usermod_v2_word_clock.h @@ -4,7 +4,7 @@ /* * Usermods allow you to add own functionality to WLED more easily - * See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality + * See: https://github.com/wled-dev/WLED/wiki/Add-own-functionality * * This usermod can be used to drive a wordclock with a 11x10 pixel matrix with WLED. There are also 4 additional dots for the minutes. * The visualisation is described in 4 mask with LED numbers (single dots for minutes, minutes, hours and "clock/Uhr"). diff --git a/wled00/FX.cpp b/wled00/FX.cpp index e8a674b4..0b9429ca 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -3017,7 +3017,7 @@ static const char _data_FX_MODE_BOUNCINGBALLS[] PROGMEM = "Bouncing Balls@Gravit /* * bouncing balls on a track track Effect modified from Aircoookie's bouncing balls * Courtesy of pjhatch (https://github.com/pjhatch) - * https://github.com/Aircoookie/WLED/pull/1039 + * https://github.com/wled-dev/WLED/pull/1039 */ // modified for balltrack mode typedef struct RollingBall { diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 42046024..2e1c8441 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -768,7 +768,7 @@ bool IRAM_ATTR_YN Segment::isPixelClipped(int i) const { //if (!invert && iInside) return _modeBlend; //if ( invert && !iInside) return _modeBlend; //return !_modeBlend; - return !iInside ^ invert ^ _modeBlend; // thanks @willmmiles (https://github.com/Aircoookie/WLED/pull/3877#discussion_r1554633876) + return !iInside ^ invert ^ _modeBlend; // thanks @willmmiles (https://github.com/wled-dev/WLED/pull/3877#discussion_r1554633876) } #endif return false; diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 5ab11150..6423a436 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -387,7 +387,7 @@ void BusDigital::setColorOrder(uint8_t colorOrder) { _colorOrder = colorOrder; } -// credit @willmmiles & @netmindz https://github.com/Aircoookie/WLED/pull/4056 +// credit @willmmiles & @netmindz https://github.com/wled-dev/WLED/pull/4056 std::vector BusDigital::getLEDTypes() { return { {TYPE_WS2812_RGB, "D", PSTR("WS281x")}, @@ -569,7 +569,7 @@ void BusPwm::show() { constexpr unsigned bitShift = 8; // 256 clocks for dead time, ~3us at 80MHz #else // if _needsRefresh is true (UI hack) we are using dithering (credit @dedehai & @zalatnaicsongor) - // https://github.com/Aircoookie/WLED/pull/4115 and https://github.com/zalatnaicsongor/WLED/pull/1) + // https://github.com/wled-dev/WLED/pull/4115 and https://github.com/zalatnaicsongor/WLED/pull/1) const bool dithering = _needsRefresh; // avoid working with bitfield const unsigned maxBri = (1<<_depth); // possible values: 16384 (14), 8192 (13), 4096 (12), 2048 (11), 1024 (10), 512 (9) and 256 (8) const unsigned bitShift = dithering * 4; // if dithering, _depth is 12 bit but LEDC channel is set to 8 bit (using 4 fractional bits) @@ -635,7 +635,7 @@ unsigned BusPwm::getPins(uint8_t* pinArray) const { return numPins; } -// credit @willmmiles & @netmindz https://github.com/Aircoookie/WLED/pull/4056 +// credit @willmmiles & @netmindz https://github.com/wled-dev/WLED/pull/4056 std::vector BusPwm::getLEDTypes() { return { {TYPE_ANALOG_1CH, "A", PSTR("PWM White")}, @@ -710,7 +710,7 @@ unsigned BusOnOff::getPins(uint8_t* pinArray) const { return 1; } -// credit @willmmiles & @netmindz https://github.com/Aircoookie/WLED/pull/4056 +// credit @willmmiles & @netmindz https://github.com/wled-dev/WLED/pull/4056 std::vector BusOnOff::getLEDTypes() { return { {TYPE_ONOFF, "", PSTR("On/Off")}, @@ -773,7 +773,7 @@ unsigned BusNetwork::getPins(uint8_t* pinArray) const { return 4; } -// credit @willmmiles & @netmindz https://github.com/Aircoookie/WLED/pull/4056 +// credit @willmmiles & @netmindz https://github.com/wled-dev/WLED/pull/4056 std::vector BusNetwork::getLEDTypes() { return { {TYPE_NET_DDP_RGB, "N", PSTR("DDP RGB (network)")}, // should be "NNNN" to determine 4 "pin" fields @@ -784,7 +784,7 @@ std::vector BusNetwork::getLEDTypes() { //{TYPE_VIRTUAL_I2C_W, "V", PSTR("I2C White (virtual)")}, // allows setting I2C address in _pin[0] //{TYPE_VIRTUAL_I2C_CCT, "V", PSTR("I2C CCT (virtual)")}, // allows setting I2C address in _pin[0] //{TYPE_VIRTUAL_I2C_RGB, "VVV", PSTR("I2C RGB (virtual)")}, // allows setting I2C address in _pin[0] and 2 additional values in _pin[1] & _pin[2] - //{TYPE_USERMOD, "VVVVV", PSTR("Usermod (virtual)")}, // 5 data fields (see https://github.com/Aircoookie/WLED/pull/4123) + //{TYPE_USERMOD, "VVVVV", PSTR("Usermod (virtual)")}, // 5 data fields (see https://github.com/wled-dev/WLED/pull/4123) }; } @@ -872,7 +872,7 @@ static String LEDTypesToJson(const std::vector& types) { return json; } -// credit @willmmiles & @netmindz https://github.com/Aircoookie/WLED/pull/4056 +// credit @willmmiles & @netmindz https://github.com/wled-dev/WLED/pull/4056 String BusManager::getLEDTypesJSONString() { String json = "["; json += LEDTypesToJson(BusDigital::getLEDTypes()); diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 500687b2..7bfd71c2 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -21,7 +21,7 @@ uint32_t color_blend(uint32_t color1, uint32_t color2, uint8_t blend) { /* * color add function that preserves ratio - * original idea: https://github.com/Aircoookie/WLED/pull/2465 by https://github.com/Proto-molecule + * original idea: https://github.com/wled-dev/WLED/pull/2465 by https://github.com/Proto-molecule * speed optimisations by @dedehai */ uint32_t color_add(uint32_t c1, uint32_t c2, bool preserveCR) diff --git a/wled00/data/common.js b/wled00/data/common.js index eddaf654..658346e7 100644 --- a/wled00/data/common.js +++ b/wled00/data/common.js @@ -2,7 +2,7 @@ var d=document; var loc = false, locip, locproto = "http:"; function H(pg="") { window.open("https://kno.wled.ge/"+pg); } -function GH() { window.open("https://github.com/Aircoookie/WLED"); } +function GH() { window.open("https://github.com/wled-dev/WLED"); } function gId(c) { return d.getElementById(c); } // getElementById function cE(e) { return d.createElement(e); } // createElement function gEBCN(c) { return d.getElementsByClassName(c); } // getElementsByClassName diff --git a/wled00/data/index.htm b/wled00/data/index.htm index aa06b512..3d3e4431 100644 --- a/wled00/data/index.htm +++ b/wled00/data/index.htm @@ -362,7 +362,7 @@ diff --git a/wled00/data/index.js b/wled00/data/index.js index 94bdb4ad..f3648d3b 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -1418,7 +1418,7 @@ function makeWS() { ws = null; } ws.onopen = (e)=>{ - //ws.send("{'v':true}"); // unnecessary (https://github.com/Aircoookie/WLED/blob/master/wled00/ws.cpp#L18) + //ws.send("{'v':true}"); // unnecessary (https://github.com/wled-dev/WLED/blob/main/wled00/ws.cpp#L18) wsRpt = 0; reqsLegal = true; } @@ -2729,7 +2729,7 @@ setInterval(()=>{ gId('heart').style.color = `hsl(${hc}, 100%, 50%)`; }, 910); -function openGH() { window.open("https://github.com/Aircoookie/WLED/wiki"); } +function openGH() { window.open("https://github.com/wled-dev/WLED/wiki"); } var cnfr = false; function cnfReset() diff --git a/wled00/data/settings_dmx.htm b/wled00/data/settings_dmx.htm index e800be6e..7458ec9f 100644 --- a/wled00/data/settings_dmx.htm +++ b/wled00/data/settings_dmx.htm @@ -6,7 +6,7 @@ DMX Settings diff --git a/wled00/data/index.js b/wled00/data/index.js index 147abf38..295a3403 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -35,9 +35,10 @@ var cfg = { // [year, month (0 -> January, 11 -> December), day, duration in days, image url] var hol = [ [0, 11, 24, 4, "https://aircoookie.github.io/xmas.png"], // christmas - [0, 2, 17, 1, "https://images.alphacoders.com/491/491123.jpg"], // st. Patrick's day - [2025, 3, 20, 2, "https://aircoookie.github.io/easter.png"], // easter 2025 - [2024, 2, 31, 2, "https://aircoookie.github.io/easter.png"], // easter 2024 + [0, 2, 17, 1, "https://images.alphacoders.com/491/491123.jpg"], // st. Patrick's day + [2026, 3, 5, 2, "https://aircoookie.github.io/easter.png"], // easter 2026 + [2027, 2, 28, 2, "https://aircoookie.github.io/easter.png"], // easter 2027 + //[2028, 3, 16, 2, "https://aircoookie.github.io/easter.png"], // easter 2028 [0, 6, 4, 1, "https://images.alphacoders.com/516/516792.jpg"], // 4th of July [0, 0, 1, 1, "https://images.alphacoders.com/119/1198800.jpg"] // new year ]; @@ -57,7 +58,7 @@ function handleVisibilityChange() {if (!d.hidden && new Date () - lastUpdate > 3 function sCol(na, col) {d.documentElement.style.setProperty(na, col);} function gId(c) {return d.getElementById(c);} function gEBCN(c) {return d.getElementsByClassName(c);} -function isEmpty(o) {return Object.keys(o).length === 0;} +function isEmpty(o) {for (const i in o) return false; return true;} function isObj(i) {return (i && typeof i === 'object' && !Array.isArray(i));} function isNumeric(n) {return !isNaN(parseFloat(n)) && isFinite(n);} @@ -805,6 +806,26 @@ function populateSegments(s) ``+ `
`+ `
`; + let blend = `
Blend mode
`+ + `
`+ + `
`; let sndSim = `
Sound sim
`+ `
d.getElementsByName("MA"+i)[0].value = v.maxpwr; }); d.getElementsByName("PR")[0].checked = l.prl | 0; - d.getElementsByName("LD")[0].checked = l.ld; d.getElementsByName("MA")[0].value = l.maxpwr; d.getElementsByName("ABL")[0].checked = l.maxpwr > 0; } @@ -823,7 +821,6 @@ Swap:
Make a segment for each output:
Custom bus start indices:
- Use global LED buffer:

Color Order Override: @@ -866,7 +863,6 @@ Swap: ms
Random Cycle Palette Time: s
- Use harmonic Random Cycle Palette:

Timed light

Default duration: min
Default target brightness:
@@ -903,8 +899,10 @@ Swap:
+ Use harmonic Random Cycle palette:
+ Use "rainbow" color wheel:
Target refresh rate: FPS - +
diff --git a/wled00/e131.cpp b/wled00/e131.cpp index c16ed933..98cfe28f 100644 --- a/wled00/e131.cpp +++ b/wled00/e131.cpp @@ -38,8 +38,7 @@ void handleDDPPacket(e131_packet_t* p) { if (realtimeMode != REALTIME_MODE_DDP) ddpSeenPush = false; // just starting, no push yet realtimeLock(realtimeTimeoutMs, REALTIME_MODE_DDP); - if (!realtimeOverride || (realtimeMode && useMainSegmentOnly)) { - if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); + if (!realtimeOverride) { for (unsigned i = start; i < stop; i++, c += ddpChannelsPerLed) { setRealtimePixel(i, data[c], data[c+1], data[c+2], ddpChannelsPerLed >3 ? data[c+3] : 0); } @@ -150,10 +149,9 @@ void handleDMXData(uint16_t uni, uint16_t dmxChannels, uint8_t* e131_data, uint8 realtimeLock(realtimeTimeoutMs, mde); - if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return; + if (realtimeOverride) return; wChannel = (availDMXLen > 3) ? e131_data[dataOffset+3] : 0; - if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); for (unsigned i = 0; i < totalLen; i++) setRealtimePixel(i, e131_data[dataOffset+0], e131_data[dataOffset+1], e131_data[dataOffset+2], wChannel); break; @@ -163,7 +161,7 @@ void handleDMXData(uint16_t uni, uint16_t dmxChannels, uint8_t* e131_data, uint8 if (availDMXLen < 4) return; realtimeLock(realtimeTimeoutMs, mde); - if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return; + if (realtimeOverride) return; wChannel = (availDMXLen > 4) ? e131_data[dataOffset+4] : 0; if (bri != e131_data[dataOffset+0]) { @@ -171,7 +169,6 @@ void handleDMXData(uint16_t uni, uint16_t dmxChannels, uint8_t* e131_data, uint8 strip.setBrightness(bri, true); } - if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); for (unsigned i = 0; i < totalLen; i++) setRealtimePixel(i, e131_data[dataOffset+1], e131_data[dataOffset+2], e131_data[dataOffset+3], wChannel); break; @@ -228,16 +225,16 @@ void handleDMXData(uint16_t uni, uint16_t dmxChannels, uint8_t* e131_data, uint8 if (e131_data[dataOffset+3] != seg.intensity) seg.intensity = e131_data[dataOffset+3]; if (e131_data[dataOffset+4] != seg.palette) seg.setPalette(e131_data[dataOffset+4]); - if ((e131_data[dataOffset+5] & 0b00000010) != seg.reverse_y) { seg.setOption(SEG_OPTION_REVERSED_Y, e131_data[dataOffset+5] & 0b00000010); } - if ((e131_data[dataOffset+5] & 0b00000100) != seg.mirror_y) { seg.setOption(SEG_OPTION_MIRROR_Y, e131_data[dataOffset+5] & 0b00000100); } - if ((e131_data[dataOffset+5] & 0b00001000) != seg.transpose) { seg.setOption(SEG_OPTION_TRANSPOSED, e131_data[dataOffset+5] & 0b00001000); } - if ((e131_data[dataOffset+5] & 0b00110000) / 8 != seg.map1D2D) { - seg.map1D2D = (e131_data[dataOffset+5] & 0b00110000) / 8; + if (bool(e131_data[dataOffset+5] & 0b00000010) != seg.reverse_y) { seg.reverse_y = bool(e131_data[dataOffset+5] & 0b00000010); } + if (bool(e131_data[dataOffset+5] & 0b00000100) != seg.mirror_y) { seg.mirror_y = bool(e131_data[dataOffset+5] & 0b00000100); } + if (bool(e131_data[dataOffset+5] & 0b00001000) != seg.transpose) { seg.transpose = bool(e131_data[dataOffset+5] & 0b00001000); } + if ((e131_data[dataOffset+5] & 0b00110000) >> 4 != seg.map1D2D) { + seg.map1D2D = (e131_data[dataOffset+5] & 0b00110000) >> 4; } // To maintain backwards compatibility with prior e1.31 values, reverse is fixed to mask 0x01000000 - if ((e131_data[dataOffset+5] & 0b01000000) != seg.reverse) { seg.setOption(SEG_OPTION_REVERSED, e131_data[dataOffset+5] & 0b01000000); } + if ((e131_data[dataOffset+5] & 0b01000000) != seg.reverse) { seg.reverse = bool(e131_data[dataOffset+5] & 0b01000000); } // To maintain backwards compatibility with prior e1.31 values, mirror is fixed to mask 0x10000000 - if ((e131_data[dataOffset+5] & 0b10000000) != seg.mirror) { seg.setOption(SEG_OPTION_MIRROR, e131_data[dataOffset+5] & 0b10000000); } + if ((e131_data[dataOffset+5] & 0b10000000) != seg.mirror) { seg.mirror = bool(e131_data[dataOffset+5] & 0b10000000); } uint32_t colors[3]; byte whites[3] = {0,0,0}; @@ -271,7 +268,7 @@ void handleDMXData(uint16_t uni, uint16_t dmxChannels, uint8_t* e131_data, uint8 case DMX_MODE_MULTIPLE_RGB: case DMX_MODE_MULTIPLE_RGBW: { - bool is4Chan = (DMXMode == DMX_MODE_MULTIPLE_RGBW); + const bool is4Chan = (DMXMode == DMX_MODE_MULTIPLE_RGBW); const unsigned dmxChannelsPerLed = is4Chan ? 4 : 3; const unsigned ledsPerUniverse = is4Chan ? MAX_4_CH_LEDS_PER_UNIVERSE : MAX_3_CH_LEDS_PER_UNIVERSE; uint8_t stripBrightness = bri; @@ -303,7 +300,7 @@ void handleDMXData(uint16_t uni, uint16_t dmxChannels, uint8_t* e131_data, uint8 } realtimeLock(realtimeTimeoutMs, mde); - if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return; + if (realtimeOverride) return; if (ledsTotal > totalLen) { ledsTotal = totalLen; @@ -316,17 +313,9 @@ void handleDMXData(uint16_t uni, uint16_t dmxChannels, uint8_t* e131_data, uint8 } } - if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); - if (!is4Chan) { - for (unsigned i = previousLeds; i < ledsTotal; i++) { - setRealtimePixel(i, e131_data[dmxOffset], e131_data[dmxOffset+1], e131_data[dmxOffset+2], 0); - dmxOffset+=3; - } - } else { - for (unsigned i = previousLeds; i < ledsTotal; i++) { - setRealtimePixel(i, e131_data[dmxOffset], e131_data[dmxOffset+1], e131_data[dmxOffset+2], e131_data[dmxOffset+3]); - dmxOffset+=4; - } + for (unsigned i = previousLeds; i < ledsTotal; i++) { + setRealtimePixel(i, e131_data[dmxOffset], e131_data[dmxOffset+1], e131_data[dmxOffset+2], is4Chan ? e131_data[dmxOffset+3] : 0); + dmxOffset += dmxChannelsPerLed; } break; } @@ -529,7 +518,7 @@ void sendArtnetPollReply(ArtPollReply *reply, IPAddress ipAddress, uint16_t port reply->reply_sub_sw = (uint8_t)((portAddress >> 4) & 0x000F); reply->reply_sw_out[0] = (uint8_t)(portAddress & 0x000F); - snprintf_P((char *)reply->reply_node_report, sizeof(reply->reply_node_report)-1, PSTR("#0001 [%04u] OK - WLED v" TOSTRING(WLED_VERSION)), pollReplyCount); + snprintf_P((char *)reply->reply_node_report, sizeof(reply->reply_node_report)-1, PSTR("#0001 [%04u] OK - WLED v%s"), pollReplyCount, versionString); if (pollReplyCount < 9999) { pollReplyCount++; diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index ff244364..2846c380 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -172,6 +172,8 @@ inline uint32_t color_blend16(uint32_t c1, uint32_t c2, uint16_t b) { return col [[gnu::hot, gnu::pure]] uint32_t ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND); CRGBPalette16 generateHarmonicRandomPalette(const CRGBPalette16 &basepalette); CRGBPalette16 generateRandomPalette(); +void loadCustomPalettes(); +#define getPaletteCount() (13 + GRADIENT_PALETTE_COUNT + customPalettes.size()) inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); } void hsv2rgb(const CHSV32& hsv, uint32_t& rgb); void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); @@ -490,11 +492,11 @@ void userLoop(); #define inoise8 perlin8 // fastled legacy alias #define inoise16 perlin16 // fastled legacy alias #define hex2int(a) (((a)>='0' && (a)<='9') ? (a)-'0' : ((a)>='A' && (a)<='F') ? (a)-'A'+10 : ((a)>='a' && (a)<='f') ? (a)-'a'+10 : 0) -[[gnu::pure]] int getNumVal(const String* req, uint16_t pos); -void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255); -bool getVal(JsonVariant elem, byte* val, byte vmin=0, byte vmax=255); // getVal supports inc/decrementing and random ("X~Y(r|[w]~[-][Z])" form) +[[gnu::pure]] int getNumVal(const String &req, uint16_t pos); +void parseNumber(const char* str, byte &val, byte minv=0, byte maxv=255); +bool getVal(JsonVariant elem, byte &val, byte vmin=0, byte vmax=255); // getVal supports inc/decrementing and random ("X~Y(r|[w]~[-][Z])" form) [[gnu::pure]] bool getBoolVal(const JsonVariant &elem, bool dflt); -bool updateVal(const char* req, const char* key, byte* val, byte minv=0, byte maxv=255); +bool updateVal(const char* req, const char* key, byte &val, byte minv=0, byte maxv=255); size_t printSetFormCheckbox(Print& settingsScript, const char* key, int val); size_t printSetFormValue(Print& settingsScript, const char* key, int val); size_t printSetFormValue(Print& settingsScript, const char* key, const char* val); @@ -544,6 +546,27 @@ inline uint8_t hw_random8() { return HW_RND_REGISTER; }; inline uint8_t hw_random8(uint32_t upperlimit) { return (hw_random8() * upperlimit) >> 8; }; // input range 0-255 inline uint8_t hw_random8(uint32_t lowerlimit, uint32_t upperlimit) { uint32_t range = upperlimit - lowerlimit; return lowerlimit + hw_random8(range); }; // input range 0-255 +// PSRAM allocation wrappers +#ifndef ESP8266 +void *w_malloc(size_t); // prefer PSRAM over DRAM +void *w_calloc(size_t, size_t); // prefer PSRAM over DRAM +void *w_realloc(void *, size_t); // prefer PSRAM over DRAM +inline void w_free(void *ptr) { heap_caps_free(ptr); } +void *d_malloc(size_t); // prefer DRAM over PSRAM +void *d_calloc(size_t, size_t); // prefer DRAM over PSRAM +void *d_realloc(void *, size_t); // prefer DRAM over PSRAM +inline void d_free(void *ptr) { heap_caps_free(ptr); } +#else +#define w_malloc malloc +#define w_calloc calloc +#define w_realloc realloc +#define w_free free +#define d_malloc malloc +#define d_calloc calloc +#define d_realloc realloc +#define d_free free +#endif + // RAII guard class for the JSON Buffer lock // Modeled after std::lock_guard class JSONBufferGuard { diff --git a/wled00/file.cpp b/wled00/file.cpp index d390207d..4df33199 100644 --- a/wled00/file.cpp +++ b/wled00/file.cpp @@ -39,7 +39,7 @@ void closeFile() { uint32_t s = millis(); #endif f.close(); - DEBUGFS_PRINTF("took %d ms\n", millis() - s); + DEBUGFS_PRINTF("took %lu ms\n", millis() - s); doCloseFile = false; } @@ -69,14 +69,14 @@ static bool bufferedFind(const char *target, bool fromStart = true) { if(buf[count] == target[index]) { if(++index >= targetLen) { // return true if all chars in the target match f.seek((f.position() - bufsize) + count +1); - DEBUGFS_PRINTF("Found at pos %d, took %d ms", f.position(), millis() - s); + DEBUGFS_PRINTF("Found at pos %d, took %lu ms", f.position(), millis() - s); return true; } } count++; } } - DEBUGFS_PRINTF("No match, took %d ms\n", millis() - s); + DEBUGFS_PRINTF("No match, took %lu ms\n", millis() - s); return false; } @@ -111,7 +111,7 @@ static bool bufferedFindSpace(size_t targetLen, bool fromStart = true) { f.seek((f.position() - bufsize) + count +1 - targetLen); knownLargestSpace = MAX_SPACE; //there may be larger spaces after, so we don't know } - DEBUGFS_PRINTF("Found at pos %d, took %d ms", f.position(), millis() - s); + DEBUGFS_PRINTF("Found at pos %d, took %lu ms", f.position(), millis() - s); return true; } } else { @@ -125,7 +125,7 @@ static bool bufferedFindSpace(size_t targetLen, bool fromStart = true) { count++; } } - DEBUGFS_PRINTF("No match, took %d ms\n", millis() - s); + DEBUGFS_PRINTF("No match, took %lu ms\n", millis() - s); return false; } @@ -151,13 +151,13 @@ static bool bufferedFindObjectEnd() { if (buf[count] == '}') objDepth--; if (objDepth == 0) { f.seek((f.position() - bufsize) + count +1); - DEBUGFS_PRINTF("} at pos %d, took %d ms", f.position(), millis() - s); + DEBUGFS_PRINTF("} at pos %d, took %lu ms", f.position(), millis() - s); return true; } count++; } } - DEBUGFS_PRINTF("No match, took %d ms\n", millis() - s); + DEBUGFS_PRINTF("No match, took %lu ms\n", millis() - s); return false; } @@ -203,7 +203,7 @@ static bool appendObjectToFile(const char* key, const JsonDocument* content, uin if (f.position() > 2) f.write(','); //add comma if not first object f.print(key); serializeJson(*content, f); - DEBUGFS_PRINTF("Inserted, took %d ms (total %d)", millis() - s1, millis() - s); + DEBUGFS_PRINTF("Inserted, took %lu ms (total %lu)", millis() - s1, millis() - s); doCloseFile = true; return true; } @@ -251,7 +251,7 @@ static bool appendObjectToFile(const char* key, const JsonDocument* content, uin f.write('}'); doCloseFile = true; - DEBUGFS_PRINTF("Appended, took %d ms (total %d)", millis() - s1, millis() - s); + DEBUGFS_PRINTF("Appended, took %lu ms (total %lu)", millis() - s1, millis() - s); return true; } @@ -321,7 +321,7 @@ bool writeObjectToFile(const char* file, const char* key, const JsonDocument* co } doCloseFile = true; - DEBUGFS_PRINTF("Replaced/deleted, took %d ms\n", millis() - s); + DEBUGFS_PRINTF("Replaced/deleted, took %lu ms\n", millis() - s); return true; } @@ -356,7 +356,7 @@ bool readObjectFromFile(const char* file, const char* key, JsonDocument* dest, c else deserializeJson(*dest, f); f.close(); - DEBUGFS_PRINTF("Read, took %d ms\n", millis() - s); + DEBUGFS_PRINTF("Read, took %lu ms\n", millis() - s); return true; } @@ -392,7 +392,7 @@ static const uint8_t *getPresetCache(size_t &size) { if ((presetsModifiedTime != presetsCachedTime) || (presetsCachedValidate != cacheInvalidate)) { if (presetsCached) { - free(presetsCached); + w_free(presetsCached); presetsCached = nullptr; } } @@ -403,7 +403,7 @@ static const uint8_t *getPresetCache(size_t &size) { presetsCachedTime = presetsModifiedTime; presetsCachedValidate = cacheInvalidate; presetsCachedSize = 0; - presetsCached = (uint8_t*)ps_malloc(file.size() + 1); + presetsCached = (uint8_t*)w_malloc(file.size() + 1); if (presetsCached) { presetsCachedSize = file.size(); file.read(presetsCached, presetsCachedSize); @@ -419,7 +419,7 @@ static const uint8_t *getPresetCache(size_t &size) { #endif bool handleFileRead(AsyncWebServerRequest* request, String path){ - DEBUG_PRINT(F("WS FileRead: ")); DEBUG_PRINTLN(path); + DEBUGFS_PRINT(F("WS FileRead: ")); DEBUGFS_PRINTLN(path); if(path.endsWith("/")) path += "index.htm"; if(path.indexOf(F("sec")) > -1) return false; #ifdef ARDUINO_ARCH_ESP32 diff --git a/wled00/ir.cpp b/wled00/ir.cpp index 9f7950a2..b2fec76f 100644 --- a/wled00/ir.cpp +++ b/wled00/ir.cpp @@ -425,8 +425,8 @@ static void decodeIR44(uint32_t code) case IR44_COLDWHITE2 : changeColor(COLOR_COLDWHITE2, 255); changeEffect(FX_MODE_STATIC); break; case IR44_REDPLUS : changeEffect(relativeChange(effectCurrent, 1, 0, strip.getModeCount() -1)); break; case IR44_REDMINUS : changeEffect(relativeChange(effectCurrent, -1, 0, strip.getModeCount() -1)); break; - case IR44_GREENPLUS : changePalette(relativeChange(effectPalette, 1, 0, strip.getPaletteCount() -1)); break; - case IR44_GREENMINUS : changePalette(relativeChange(effectPalette, -1, 0, strip.getPaletteCount() -1)); break; + case IR44_GREENPLUS : changePalette(relativeChange(effectPalette, 1, 0, getPaletteCount() -1)); break; + case IR44_GREENMINUS : changePalette(relativeChange(effectPalette, -1, 0, getPaletteCount() -1)); break; case IR44_BLUEPLUS : changeEffectIntensity( 16); break; case IR44_BLUEMINUS : changeEffectIntensity(-16); break; case IR44_QUICK : changeEffectSpeed( 16); break; @@ -435,7 +435,7 @@ static void decodeIR44(uint32_t code) case IR44_DIY2 : presetFallback(2, FX_MODE_BREATH, 0); break; case IR44_DIY3 : presetFallback(3, FX_MODE_FIRE_FLICKER, 0); break; case IR44_DIY4 : presetFallback(4, FX_MODE_RAINBOW, 0); break; - case IR44_DIY5 : presetFallback(5, FX_MODE_METEOR, 0); break; + case IR44_DIY5 : presetFallback(5, FX_MODE_METEOR, 0); break; case IR44_DIY6 : presetFallback(6, FX_MODE_RAIN, 0); break; case IR44_AUTO : changeEffect(FX_MODE_STATIC); break; case IR44_FLASH : changeEffect(FX_MODE_PALETTE); break; @@ -484,7 +484,7 @@ static void decodeIR6(uint32_t code) case IR6_CHANNEL_UP: incBrightness(); break; case IR6_CHANNEL_DOWN: decBrightness(); break; case IR6_VOLUME_UP: changeEffect(relativeChange(effectCurrent, 1, 0, strip.getModeCount() -1)); break; - case IR6_VOLUME_DOWN: changePalette(relativeChange(effectPalette, 1, 0, strip.getPaletteCount() -1)); + case IR6_VOLUME_DOWN: changePalette(relativeChange(effectPalette, 1, 0, getPaletteCount() -1)); switch(lastIR6ColourIdx) { case 0: changeColor(COLOR_RED); break; case 1: changeColor(COLOR_REDDISH); break; @@ -530,7 +530,7 @@ static void decodeIR9(uint32_t code) /* This allows users to customize IR actions without the need to edit C code and compile. -From the https://github.com/wled-dev/WLED/wiki/Infrared-Control page, download the starter +From the https://github.com/wled/WLED/wiki/Infrared-Control page, download the starter ir.json file that corresponds to the number of buttons on your remote. Many of the remotes with the same number of buttons emit the same codes, but will have different labels or colors. Once you edit the ir.json file, upload it to your controller diff --git a/wled00/json.cpp b/wled00/json.cpp index c09b543f..03f38825 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -2,14 +2,74 @@ #include "palettes.h" +#define JSON_PATH_STATE 1 +#define JSON_PATH_INFO 2 +#define JSON_PATH_STATE_INFO 3 +#define JSON_PATH_NODES 4 +#define JSON_PATH_PALETTES 5 +#define JSON_PATH_FXDATA 6 +#define JSON_PATH_NETWORKS 7 +#define JSON_PATH_EFFECTS 8 + /* * JSON API (De)serialization */ +namespace { + typedef struct { + uint32_t colors[NUM_COLORS]; + uint16_t start; + uint16_t stop; + uint16_t offset; + uint16_t grouping; + uint16_t spacing; + uint16_t startY; + uint16_t stopY; + uint16_t options; + uint8_t mode; + uint8_t palette; + uint8_t opacity; + uint8_t speed; + uint8_t intensity; + uint8_t custom1; + uint8_t custom2; + uint8_t custom3; + bool check1; + bool check2; + bool check3; + } SegmentCopy; -bool deserializeSegment(JsonObject elem, byte it, byte presetId) + uint8_t differs(const Segment& b, const SegmentCopy& a) { + uint8_t d = 0; + if (a.start != b.start) d |= SEG_DIFFERS_BOUNDS; + if (a.stop != b.stop) d |= SEG_DIFFERS_BOUNDS; + if (a.offset != b.offset) d |= SEG_DIFFERS_GSO; + if (a.grouping != b.grouping) d |= SEG_DIFFERS_GSO; + if (a.spacing != b.spacing) d |= SEG_DIFFERS_GSO; + if (a.opacity != b.opacity) d |= SEG_DIFFERS_BRI; + if (a.mode != b.mode) d |= SEG_DIFFERS_FX; + if (a.speed != b.speed) d |= SEG_DIFFERS_FX; + if (a.intensity != b.intensity) d |= SEG_DIFFERS_FX; + if (a.palette != b.palette) d |= SEG_DIFFERS_FX; + if (a.custom1 != b.custom1) d |= SEG_DIFFERS_FX; + if (a.custom2 != b.custom2) d |= SEG_DIFFERS_FX; + if (a.custom3 != b.custom3) d |= SEG_DIFFERS_FX; + if (a.startY != b.startY) d |= SEG_DIFFERS_BOUNDS; + if (a.stopY != b.stopY) d |= SEG_DIFFERS_BOUNDS; + + //bit pattern: (msb first) + // set:2, sound:2, mapping:3, transposed, mirrorY, reverseY, [reset,] paused, mirrored, on, reverse, [selected] + if ((a.options & 0b1111111111011110U) != (b.options & 0b1111111111011110U)) d |= SEG_DIFFERS_OPT; + if ((a.options & 0x0001U) != (b.options & 0x0001U)) d |= SEG_DIFFERS_SEL; + for (unsigned i = 0; i < NUM_COLORS; i++) if (a.colors[i] != b.colors[i]) d |= SEG_DIFFERS_COL; + + return d; + } +} + +static bool deserializeSegment(JsonObject elem, byte it, byte presetId) { byte id = elem["id"] | it; - if (id >= strip.getMaxSegments()) return false; + if (id >= WS2812FX::getMaxSegments()) return false; bool newSeg = false; int stop = elem["stop"] | -1; @@ -17,16 +77,37 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) // append segment if (id >= strip.getSegmentsNum()) { if (stop <= 0) return false; // ignore empty/inactive segments - strip.appendSegment(Segment(0, strip.getLengthTotal())); + strip.appendSegment(0, strip.getLengthTotal()); id = strip.getSegmentsNum()-1; // segments are added at the end of list newSeg = true; } //DEBUG_PRINTLN(F("-- JSON deserialize segment.")); Segment& seg = strip.getSegment(id); - //DEBUG_PRINTF_P(PSTR("-- Original segment: %p (%p)\n"), &seg, seg.data); - const Segment prev = seg; //make a backup so we can tell if something changed (calling copy constructor) - //DEBUG_PRINTF_P(PSTR("-- Duplicate segment: %p (%p)\n"), &prev, prev.data); + // we do not want to make segment copy as it may use a lot of RAM (effect data and pixel buffer) + // so we will create a copy of segment options and compare it with original segment when done processing + SegmentCopy prev = { + {seg.colors[0], seg.colors[1], seg.colors[2]}, + seg.start, + seg.stop, + seg.offset, + seg.grouping, + seg.spacing, + seg.startY, + seg.stopY, + seg.options, + seg.mode, + seg.palette, + seg.opacity, + seg.speed, + seg.intensity, + seg.custom1, + seg.custom2, + seg.custom3, + seg.check1, + seg.check2, + seg.check3 + }; int start = elem["start"] | seg.start; if (stop < 0) { @@ -44,7 +125,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) elem.remove("rpt"); // remove for recursive call elem.remove("n"); // remove for recursive call unsigned len = stop - start; - for (size_t i=id+1; i= strip.getLengthTotal()) break; //TODO: add support for 2D @@ -58,28 +139,11 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) if (elem["n"]) { // name field exists - if (seg.name) { //clear old name - free(seg.name); - seg.name = nullptr; - } - const char * name = elem["n"].as(); - size_t len = 0; - if (name != nullptr) len = strlen(name); - if (len > 0) { - if (len > WLED_MAX_SEGNAME_LEN) len = WLED_MAX_SEGNAME_LEN; - seg.name = static_cast(malloc(len+1)); - if (seg.name) strlcpy(seg.name, name, WLED_MAX_SEGNAME_LEN+1); - } else { - // but is empty (already deleted above) - elem.remove("n"); - } + seg.setName(name); // will resolve empty and null correctly } else if (start != seg.start || stop != seg.stop) { // clearing or setting segment without name field - if (seg.name) { - free(seg.name); - seg.name = nullptr; - } + seg.clearName(); } uint16_t grp = elem["grp"] | seg.grouping; @@ -97,6 +161,12 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) bool transpose = getBoolVal(elem[F("tp")], seg.transpose); #endif + // if segment's virtual dimensions change we need to restart effect (segment blending and PS rely on dimensions) + if (seg.mirror != mirror) seg.markForReset(); + #ifndef WLED_DISABLE_2D + if (seg.mirror_y != mirror_y || seg.transpose != transpose) seg.markForReset(); + #endif + int len = (stop > start) ? stop - start : 1; int offset = elem[F("of")] | INT32_MAX; if (offset != INT32_MAX) { @@ -118,8 +188,8 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) } byte segbri = seg.opacity; - if (getVal(elem["bri"], &segbri)) { - if (segbri > 0) seg.setOpacity(segbri); + if (getVal(elem["bri"], segbri)) { + if (segbri > 0) seg.setOpacity(segbri); // use transition seg.setOption(SEG_OPTION_ON, segbri); // use transition } @@ -175,13 +245,13 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) if (!colValid) continue; - seg.setColor(i, RGBW32(rgbw[0],rgbw[1],rgbw[2],rgbw[3])); + seg.setColor(i, RGBW32(rgbw[0],rgbw[1],rgbw[2],rgbw[3])); // use transition if (seg.mode == FX_MODE_STATIC) strip.trigger(); //instant refresh } } else { // non RGB & non White segment (usually On/Off bus) - seg.setColor(0, ULTRAWHITE); - seg.setColor(1, BLACK); + seg.setColor(0, ULTRAWHITE); // use transition + seg.setColor(1, BLACK); // use transition } } @@ -197,7 +267,6 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) } #endif - //seg.map1D2D = constrain(map1D2D, 0, 7); // done in setGeometry() seg.set = constrain(set, 0, 3); seg.soundSim = constrain(soundSim, 0, 3); seg.selected = selected; @@ -210,57 +279,58 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) #endif byte fx = seg.mode; - if (getVal(elem["fx"], &fx, 0, strip.getModeCount())) { + if (getVal(elem["fx"], fx, 0, strip.getModeCount())) { if (!presetId && currentPlaylist>=0) unloadPlaylist(); - if (fx != seg.mode) seg.setMode(fx, elem[F("fxdef")]); + if (fx != seg.mode) seg.setMode(fx, elem[F("fxdef")]); // use transition (WARNING: may change map1D2D causing geometry change) } - getVal(elem["sx"], &seg.speed); - getVal(elem["ix"], &seg.intensity); + getVal(elem["sx"], seg.speed); + getVal(elem["ix"], seg.intensity); uint8_t pal = seg.palette; if (seg.getLightCapabilities() & 1) { // ignore palette for White and On/Off segments - if (getVal(elem["pal"], &pal, 0, strip.getPaletteCount())) seg.setPalette(pal); + if (getVal(elem["pal"], pal, 0, getPaletteCount())) seg.setPalette(pal); } - getVal(elem["c1"], &seg.custom1); - getVal(elem["c2"], &seg.custom2); + getVal(elem["c1"], seg.custom1); + getVal(elem["c2"], seg.custom2); uint8_t cust3 = seg.custom3; - getVal(elem["c3"], &cust3, 0, 31); // we can't pass reference to bitfield + getVal(elem["c3"], cust3, 0, 31); // we can't pass reference to bitfield seg.custom3 = constrain(cust3, 0, 31); seg.check1 = getBoolVal(elem["o1"], seg.check1); seg.check2 = getBoolVal(elem["o2"], seg.check2); seg.check3 = getBoolVal(elem["o3"], seg.check3); + uint8_t blend = seg.blendMode; + getVal(elem["bm"], blend, 0, 15); // we can't pass reference to bitfield + seg.blendMode = constrain(blend, 0, 15); + JsonArray iarr = elem[F("i")]; //set individual LEDs if (!iarr.isNull()) { - uint8_t oldMap1D2D = seg.map1D2D; - seg.map1D2D = M12_Pixels; // no mapping - // set brightness immediately and disable transition jsonTransitionOnce = true; - seg.stopTransition(); + if (seg.isInTransition()) seg.startTransition(0); // setting transition time to 0 will stop transition in next frame strip.setTransition(0); strip.setBrightness(scaledBri(bri), true); // freeze and init to black if (!seg.freeze) { seg.freeze = true; - seg.fill(BLACK); + seg.clear(); } - start = 0, stop = 0; - set = 0; //0 nothing set, 1 start set, 2 range set + unsigned iStart = 0, iStop = 0; + unsigned iSet = 0; //0 nothing set, 1 start set, 2 range set for (size_t i = 0; i < iarr.size(); i++) { - if(iarr[i].is()) { - if (!set) { - start = abs(iarr[i].as()); - set++; + if (iarr[i].is()) { + if (!iSet) { + iStart = abs(iarr[i].as()); + iSet++; } else { - stop = abs(iarr[i].as()); - set++; + iStop = abs(iarr[i].as()); + iSet++; } } else { //color uint8_t rgbw[] = {0,0,0,0}; @@ -276,17 +346,16 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) } } - if (set < 2 || stop <= start) stop = start + 1; - uint32_t c = gamma32(RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3])); - while (start < stop) seg.setPixelColor(start++, c); - set = 0; + if (iSet < 2 || iStop <= iStart) iStop = iStart + 1; + uint32_t c = RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3]); + while (iStart < iStop) seg.setRawPixelColor(iStart++, c); // sets pixel color without 1D->2D expansion, grouping or spacing + iSet = 0; } } - seg.map1D2D = oldMap1D2D; // restore mapping strip.trigger(); // force segment update } // send UDP/WS if segment options changed (except selection; will also deselect current preset) - if (seg.differs(prev) & 0x7F) stateChanged = true; + if (differs(seg, prev) & ~SEG_DIFFERS_SEL) stateChanged = true; return true; } @@ -302,7 +371,8 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) #endif bool onBefore = bri; - getVal(root["bri"], &bri); + getVal(root["bri"], bri); + if (bri != briOld) stateChanged = true; bool on = root["on"] | (bri > 0); if (!on != !bri) toggleOnOff(); @@ -329,10 +399,8 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) } } -#ifndef WLED_DISABLE_MODE_BLEND blendingStyle = root[F("bs")] | blendingStyle; blendingStyle &= 0x1F; -#endif // temporary transition (applies only once) tr = root[F("tt")] | -1; @@ -345,6 +413,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) if (tr >= 0) strip.timebase = (unsigned long)tr - millis(); JsonObject nl = root["nl"]; + if (!nl.isNull()) stateChanged = true; nightlightActive = getBoolVal(nl["on"], nightlightActive); nightlightDelayMins = nl["dur"] | nightlightDelayMins; nightlightMode = nl["mode"] | nightlightMode; @@ -371,6 +440,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) if (realtimeOverride > 2) realtimeOverride = REALTIME_OVERRIDE_ALWAYS; if (realtimeMode && useMainSegmentOnly) { strip.getMainSegment().freeze = !realtimeOverride; + realtimeOverride = REALTIME_OVERRIDE_NONE; // ignore request for override if using main segment only } if (root.containsKey("live")) { @@ -388,18 +458,14 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) if (!segVar.isNull()) { // we may be called during strip.service() so we must not modify segments while effects are executing strip.suspend(); - const unsigned long start = millis(); - while (strip.isServicing() && millis() - start < strip.getFrameTime()) yield(); // wait until frame is over - #ifdef WLED_DEBUG - if (millis() - start > 0) DEBUG_PRINTLN(F("JSON: Waited for strip to finish servicing.")); - #endif + strip.waitForIt(); if (segVar.is()) { int id = segVar["id"] | -1; //if "seg" is not an array and ID not specified, apply to all selected/checked segments if (id < 0) { //apply all selected segments for (size_t s = 0; s < strip.getSegmentsNum(); s++) { - Segment &sg = strip.getSegment(s); + const Segment &sg = strip.getSegment(s); if (sg.isActive() && sg.isSelected()) { deserializeSegment(segVar, s, presetId); } @@ -449,7 +515,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) DEBUG_PRINTF_P(PSTR("Preset direct: %d\n"), currentPreset); } else if (!root["ps"].isNull()) { // we have "ps" call (i.e. from button or external API call) or "pd" that includes "ps" (i.e. from UI call) - if (root["win"].isNull() && getVal(root["ps"], &presetCycCurr, 1, 250) && presetCycCurr > 0 && presetCycCurr < 251 && presetCycCurr != currentPreset) { + if (root["win"].isNull() && getVal(root["ps"], presetCycCurr, 1, 250) && presetCycCurr > 0 && presetCycCurr < 251 && presetCycCurr != currentPreset) { DEBUG_PRINTF_P(PSTR("Preset select: %d\n"), presetCycCurr); // b) preset ID only or preset that does not change state (use embedded cycling limits if they exist in getVal()) applyPreset(presetCycCurr, callMode); // async load from file system (only preset ID was specified) @@ -465,11 +531,11 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) } if (root.containsKey(F("rmcpal")) && root[F("rmcpal")].as()) { - if (strip.customPalettes.size()) { + if (customPalettes.size()) { char fileName[32]; - sprintf_P(fileName, PSTR("/palette%d.json"), strip.customPalettes.size()-1); + sprintf_P(fileName, PSTR("/palette%d.json"), customPalettes.size()-1); if (WLED_FS.exists(fileName)) WLED_FS.remove(fileName); - strip.loadCustomPalettes(); + loadCustomPalettes(); } } @@ -488,13 +554,13 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) //if (restart) forceReconnect = true; } - stateUpdated(callMode); + if (stateChanged) stateUpdated(callMode); if (presetToRestore) currentPreset = presetToRestore; return stateResponse; } -void serializeSegment(const JsonObject& root, const Segment& seg, byte id, bool forPreset, bool segmentBounds) +static void serializeSegment(JsonObject& root, const Segment& seg, byte id, bool forPreset, bool segmentBounds) { root["id"] = id; if (segmentBounds) { @@ -517,6 +583,7 @@ void serializeSegment(const JsonObject& root, const Segment& seg, byte id, bool root["bri"] = (segbri) ? segbri : 255; root["cct"] = seg.cct; root[F("set")] = seg.set; + root["lc"] = seg.getLightCapabilities(); if (seg.name != nullptr) root["n"] = reinterpret_cast(seg.name); //not good practice, but decreases required JSON buffer else if (forPreset) root["n"] = ""; @@ -561,6 +628,7 @@ void serializeSegment(const JsonObject& root, const Segment& seg, byte id, bool root["o3"] = seg.check3; root["si"] = seg.soundSim; root["m12"] = seg.map1D2D; + root["bm"] = seg.blendMode; } void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segmentBounds, bool selectedSegmentsOnly) @@ -569,9 +637,7 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme root["on"] = (bri > 0); root["bri"] = briLast; root[F("transition")] = transitionDelay/100; //in 100ms -#ifndef WLED_DISABLE_MODE_BLEND root[F("bs")] = blendingStyle; -#endif } if (!forPreset) { @@ -602,7 +668,7 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme root[F("mainseg")] = strip.getMainSegmentId(); JsonArray seg = root.createNestedArray("seg"); - for (size_t s = 0; s < strip.getMaxSegments(); s++) { + for (size_t s = 0; s < WS2812FX::getMaxSegments(); s++) { if (s >= strip.getSegmentsNum()) { if (forPreset && segmentBounds && !selectedSegmentsOnly) { //disable segments not part of preset JsonObject seg0 = seg.createNestedObject(); @@ -611,7 +677,7 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme } else break; } - Segment &sg = strip.getSegment(s); + const Segment &sg = strip.getSegment(s); if (forPreset && selectedSegmentsOnly && !sg.isSelected()) continue; if (sg.isActive()) { JsonObject seg0 = seg.createNestedObject(); @@ -635,7 +701,7 @@ void serializeInfo(JsonObject root) leds[F("pwr")] = BusManager::currentMilliamps(); leds["fps"] = strip.getFps(); leds[F("maxpwr")] = BusManager::currentMilliamps()>0 ? BusManager::ablMilliampsMax() : 0; - leds[F("maxseg")] = strip.getMaxSegments(); + leds[F("maxseg")] = WS2812FX::getMaxSegments(); //leds[F("actseg")] = strip.getActiveSegmentsNum(); //leds[F("seglock")] = false; //might be used in the future to prevent modifications to segment config leds[F("bootps")] = bootPreset; @@ -649,13 +715,13 @@ void serializeInfo(JsonObject root) #endif unsigned totalLC = 0; - JsonArray lcarr = leds.createNestedArray(F("seglc")); + JsonArray lcarr = leds.createNestedArray(F("seglc")); // deprecated, use state.seg[].lc size_t nSegs = strip.getSegmentsNum(); for (size_t s = 0; s < nSegs; s++) { if (!strip.getSegment(s).isActive()) continue; unsigned lc = strip.getSegment(s).getLightCapabilities(); totalLC |= lc; - lcarr.add(lc); + lcarr.add(lc); // deprecated, use state.seg[].lc } leds["lc"] = totalLC; @@ -703,8 +769,8 @@ void serializeInfo(JsonObject root) #endif root[F("fxcount")] = strip.getModeCount(); - root[F("palcount")] = strip.getPaletteCount(); - root[F("cpalcount")] = strip.customPalettes.size(); //number of custom palettes + root[F("palcount")] = getPaletteCount(); + root[F("cpalcount")] = customPalettes.size(); //number of custom palettes JsonArray ledmaps = root.createNestedArray(F("maps")); for (size_t i=0; i maxPage) page = maxPage; int start = itemPerPage * page; int end = start + itemPerPage; - if (end > palettesCount + customPalettes) end = palettesCount + customPalettes; + if (end > palettesCount + customPalettesCount) end = palettesCount + customPalettesCount; root[F("m")] = maxPage; // inform caller how many pages there are JsonObject palettes = root.createNestedObject("p"); @@ -911,7 +977,7 @@ void serializePalettes(JsonObject root, int page) break; default: if (i >= palettesCount) - setPaletteColors(curPalette, strip.customPalettes[i - palettesCount]); + setPaletteColors(curPalette, customPalettes[i - palettesCount]); else if (i < 13) // palette 6 - 12, fastled palettes setPaletteColors(curPalette, *fastledPalettes[i-6]); else { diff --git a/wled00/led.cpp b/wled00/led.cpp index 2d2f5b6f..43771f9d 100644 --- a/wled00/led.cpp +++ b/wled00/led.cpp @@ -4,11 +4,9 @@ * LED methods */ -void setValuesFromMainSeg() { setValuesFromSegment(strip.getMainSegmentId()); } -void setValuesFromFirstSelectedSeg() { setValuesFromSegment(strip.getFirstSelectedSegId()); } -void setValuesFromSegment(uint8_t s) -{ - Segment& seg = strip.getSegment(s); + // applies chosen setment properties to legacy values +void setValuesFromSegment(uint8_t s) { + const Segment& seg = strip.getSegment(s); colPri[0] = R(seg.colors[0]); colPri[1] = G(seg.colors[0]); colPri[2] = B(seg.colors[0]); @@ -24,25 +22,19 @@ void setValuesFromSegment(uint8_t s) } -// applies global legacy values (col, colSec, effectCurrent...) -// problem: if the first selected segment already has the value to be set, other selected segments are not updated -void applyValuesToSelectedSegs() -{ - // copy of first selected segment to tell if value was updated - unsigned firstSel = strip.getFirstSelectedSegId(); - Segment selsegPrev = strip.getSegment(firstSel); +// applies global legacy values (colPri, colSec, effectCurrent...) to each selected segment +void applyValuesToSelectedSegs() { for (unsigned i = 0; i < strip.getSegmentsNum(); i++) { Segment& seg = strip.getSegment(i); - if (i != firstSel && (!seg.isActive() || !seg.isSelected())) continue; - - if (effectSpeed != selsegPrev.speed) {seg.speed = effectSpeed; stateChanged = true;} - if (effectIntensity != selsegPrev.intensity) {seg.intensity = effectIntensity; stateChanged = true;} - if (effectPalette != selsegPrev.palette) {seg.setPalette(effectPalette);} - if (effectCurrent != selsegPrev.mode) {seg.setMode(effectCurrent);} + if (!(seg.isActive() && seg.isSelected())) continue; + if (effectSpeed != seg.speed) {seg.speed = effectSpeed; stateChanged = true;} + if (effectIntensity != seg.intensity) {seg.intensity = effectIntensity; stateChanged = true;} + if (effectPalette != seg.palette) {seg.setPalette(effectPalette);} + if (effectCurrent != seg.mode) {seg.setMode(effectCurrent);} uint32_t col0 = RGBW32(colPri[0], colPri[1], colPri[2], colPri[3]); uint32_t col1 = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]); - if (col0 != selsegPrev.colors[0]) {seg.setColor(0, col0);} - if (col1 != selsegPrev.colors[1]) {seg.setColor(1, col1);} + if (col0 != seg.colors[0]) {seg.setColor(0, col0);} + if (col1 != seg.colors[1]) {seg.setColor(1, col1);} } } @@ -73,7 +65,8 @@ byte scaledBri(byte in) //applies global temporary brightness (briT) to strip void applyBri() { - if (!(realtimeMode && arlsForceMaxBri)) { + if (realtimeOverride || !(realtimeMode && arlsForceMaxBri)) + { //DEBUG_PRINTF_P(PSTR("Applying strip brightness: %d (%d,%d)\n"), (int)briT, (int)bri, (int)briOld); strip.setBrightness(scaledBri(briT)); } @@ -94,7 +87,7 @@ void applyFinalBri() { void stateUpdated(byte callMode) { //call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification) // 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa 11: ws send only 12: button preset - setValuesFromFirstSelectedSeg(); + setValuesFromFirstSelectedSeg(); // a much better approach would be to use main segment: setValuesFromMainSeg() if (bri != briOld || stateChanged) { if (stateChanged) currentPreset = 0; //something changed, so we are no longer in the preset @@ -104,7 +97,6 @@ void stateUpdated(byte callMode) { //set flag to update ws and mqtt interfaceUpdateCallMode = callMode; - stateChanged = false; } else { if (nightlightActive && !nightlightActiveOld && callMode != CALL_MODE_NOTIFICATION && callMode != CALL_MODE_NO_NOTIFY) { notify(CALL_MODE_NIGHTLIGHT); @@ -134,15 +126,16 @@ void stateUpdated(byte callMode) { jsonTransitionOnce = false; transitionActive = false; applyFinalBri(); - return; + strip.trigger(); + } else { + if (transitionActive) { + briOld = briT; + } else if (bri != briOld || stateChanged) + strip.setTransitionMode(true); // force all segments to transition mode + transitionActive = true; + transitionStartTime = now; } - - if (transitionActive) { - briOld = briT; - } else - strip.setTransitionMode(true); // force all segments to transition mode - transitionActive = true; - transitionStartTime = now; + stateChanged = false; } diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp index a462881e..a1f65951 100644 --- a/wled00/mqtt.cpp +++ b/wled00/mqtt.cpp @@ -68,8 +68,8 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp } if (index == 0) { // start (1st partial packet or the only packet) - if (payloadStr) free(payloadStr); // fail-safe: release buffer - payloadStr = static_cast(malloc(total+1)); // allocate new buffer + w_free(payloadStr); // release buffer if it exists + payloadStr = static_cast(w_malloc(total+1)); // allocate new buffer } if (payloadStr == nullptr) return; // buffer not allocated @@ -94,7 +94,7 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp } else { // Non-Wled Topic used here. Probably a usermod subscribed to this topic. UsermodManager::onMqttMessage(topic, payloadStr); - free(payloadStr); + w_free(payloadStr); payloadStr = nullptr; return; } @@ -124,7 +124,7 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp // topmost topic (just wled/MAC) parseMQTTBriPayload(payloadStr); } - free(payloadStr); + w_free(payloadStr); payloadStr = nullptr; } @@ -196,7 +196,8 @@ bool initMqtt() if (!mqttEnabled || mqttServer[0] == 0 || !WLED_CONNECTED) return false; if (mqtt == nullptr) { - mqtt = new AsyncMqttClient(); + void *ptr = w_malloc(sizeof(AsyncMqttClient)); + mqtt = new (ptr) AsyncMqttClient(); // use placement new (into PSRAM), client will never be deleted if (!mqtt) return false; mqtt->onMessage(onMqttMessage); mqtt->onConnect(onMqttConnect); diff --git a/wled00/overlay.cpp b/wled00/overlay.cpp index fcd0a40c..3f6e6312 100644 --- a/wled00/overlay.cpp +++ b/wled00/overlay.cpp @@ -90,9 +90,8 @@ void _overlayAnalogCountdown() void handleOverlayDraw() { UsermodManager::handleOverlayDraw(); if (analogClockSolidBlack) { - const Segment* segments = strip.getSegments(); for (unsigned i = 0; i < strip.getSegmentsNum(); i++) { - const Segment& segment = segments[i]; + const Segment& segment = strip.getSegment(i); if (!segment.isActive()) continue; if (segment.mode > 0 || segment.colors[0] > 0) { return; diff --git a/wled00/palettes.h b/wled00/palettes.h old mode 100644 new mode 100755 index c84c1fb9..70cf8418 --- a/wled00/palettes.h +++ b/wled00/palettes.h @@ -1,500 +1,371 @@ +#ifndef PalettesWLED_h +#define PalettesWLED_h + /* * Color palettes for FastLED effects (65-73). - * 4 bytes per color: index, red, green, blue */ // From ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb // Unfortunately, these are stored in RAM! // Gradient palette "ib_jul01_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ing/xmas/tn/ib_jul01.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 16 bytes of program space. - -#ifndef PalettesWLED_h -#define PalettesWLED_h - -const byte ib_jul01_gp[] PROGMEM = { - 0, 194, 1, 1, - 94, 1, 29, 18, - 132, 57,131, 28, - 255, 113, 1, 1}; +// http://seaviewsensing.com/pub/cpt-city/ing/xmas/ib_jul01.c3g +const uint8_t ib_jul01_gp[] PROGMEM = { + 0, 230, 6, 17, + 94, 37, 96, 90, + 132, 144, 189, 106, + 255, 187, 3, 13}; // Gradient palette "es_vintage_57_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/vintage/tn/es_vintage_57.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 20 bytes of program space. - -const byte es_vintage_57_gp[] PROGMEM = { - 0, 2, 1, 1, - 53, 18, 1, 0, - 104, 69, 29, 1, - 153, 167,135, 10, - 255, 46, 56, 4}; - +// http://seaviewsensing.com/pub/cpt-city/es/vintage/es_vintage_57.c3g +const uint8_t es_vintage_57_gp[] PROGMEM = { + 0, 41, 8, 5, + 53, 92, 1, 0, + 104, 155, 96, 36, + 153, 217, 191, 72, + 255, 132, 129, 52}; // Gradient palette "es_vintage_01_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/vintage/tn/es_vintage_01.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 32 bytes of program space. - -const byte es_vintage_01_gp[] PROGMEM = { - 0, 4, 1, 1, - 51, 16, 0, 1, - 76, 97,104, 3, - 101, 255,131, 19, - 127, 67, 9, 4, - 153, 16, 0, 1, - 229, 4, 1, 1, - 255, 4, 1, 1}; - +// http://seaviewsensing.com/pub/cpt-city/es/vintage/es_vintage_01.c3g +const uint8_t es_vintage_01_gp[] PROGMEM = { + 0, 54, 18, 32, + 51, 89, 0, 30, + 76, 176, 170, 48, + 101, 255, 189, 92, + 127, 153, 56, 50, + 153, 89, 0, 30, + 229, 54, 18, 32, + 255, 54, 18, 32}; // Gradient palette "es_rivendell_15_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/rivendell/tn/es_rivendell_15.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 20 bytes of program space. - -const byte es_rivendell_15_gp[] PROGMEM = { - 0, 1, 14, 5, - 101, 16, 36, 14, - 165, 56, 68, 30, - 242, 150,156, 99, - 255, 150,156, 99}; - +// http://seaviewsensing.com/pub/cpt-city/es/rivendell/es_rivendell_15.c3g +const uint8_t es_rivendell_15_gp[] PROGMEM = { + 0, 35, 69, 54, + 101, 88, 105, 82, + 165, 143, 140, 109, + 242, 208, 204, 175, + 255, 208, 204, 175}; // Gradient palette "rgi_15_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ds/rgi/tn/rgi_15.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 36 bytes of program space. -// Edited to be brighter - -const byte rgi_15_gp[] PROGMEM = { - 0, 4, 1, 70, - 31, 55, 1, 30, - 63, 255, 4, 7, - 95, 59, 2, 29, - 127, 11, 3, 50, - 159, 39, 8, 60, - 191, 112, 19, 40, - 223, 78, 11, 39, - 255, 29, 8, 59}; - +// http://seaviewsensing.com/pub/cpt-city/ds/rgi/rgi_15.c3g +const uint8_t rgi_15_gp[] PROGMEM = { + 0, 54, 14, 111, + 31, 142, 24, 86, + 63, 231, 34, 61, + 95, 146, 31, 88, + 127, 61, 29, 114, + 159, 124, 47, 113, + 191, 186, 66, 112, + 223, 143, 57, 116, + 255, 100, 48, 120}; // Gradient palette "retro2_16_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ma/retro2/tn/retro2_16.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 8 bytes of program space. - -const byte retro2_16_gp[] PROGMEM = { - 0, 188,135, 1, - 255, 46, 7, 1}; - +// http://seaviewsensing.com/pub/cpt-city/ma/retro2/retro2_16.c3g +const uint8_t retro2_16_gp[] PROGMEM = { + 0, 227, 191, 12, + 255, 132, 52, 2}; // Gradient palette "Analogous_1_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/red/tn/Analogous_1.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 20 bytes of program space. - -const byte Analogous_1_gp[] PROGMEM = { - 0, 3, 0,255, - 63, 23, 0,255, - 127, 67, 0,255, - 191, 142, 0, 45, - 255, 255, 0, 0}; - +// http://seaviewsensing.com/pub/cpt-city/nd/red/Analogous_1.c3g +const uint8_t Analogous_1_gp[] PROGMEM = { + 0, 51, 0, 255, + 63, 102, 0, 255, + 127, 153, 0, 255, + 191, 204, 0, 128, + 255, 255, 0, 0}; // Gradient palette "es_pinksplash_08_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/pink_splash/tn/es_pinksplash_08.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 20 bytes of program space. - -const byte es_pinksplash_08_gp[] PROGMEM = { - 0, 126, 11,255, - 127, 197, 1, 22, - 175, 210,157,172, - 221, 157, 3,112, - 255, 157, 3,112}; - +// http://seaviewsensing.com/pub/cpt-city/es/pink_splash/es_pinksplash_08.c3g +const uint8_t es_pinksplash_08_gp[] PROGMEM = { + 0, 195, 63, 255, + 127, 231, 9, 97, + 175, 237, 205, 218, + 221, 212, 38, 184, + 255, 212, 38, 184}; // Gradient palette "es_ocean_breeze_036_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/ocean_breeze/tn/es_ocean_breeze_036.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 16 bytes of program space. - -const byte es_ocean_breeze_036_gp[] PROGMEM = { - 0, 1, 6, 7, - 89, 1, 99,111, - 153, 144,209,255, - 255, 0, 73, 82}; - +// http://seaviewsensing.com/pub/cpt-city/es/ocean_breeze/es_ocean_breeze_036.c3g +const uint8_t es_ocean_breeze_036_gp[] PROGMEM = { + 0, 25, 48, 62, + 89, 38, 166, 183, + 153, 205, 233, 255, + 255, 0, 145, 162}; // Gradient palette "departure_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/mjf/tn/departure.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 88 bytes of program space. - -const byte departure_gp[] PROGMEM = { - 0, 8, 3, 0, - 42, 23, 7, 0, - 63, 75, 38, 6, - 84, 169, 99, 38, - 106, 213,169,119, - 116, 255,255,255, - 138, 135,255,138, - 148, 22,255, 24, - 170, 0,255, 0, - 191, 0,136, 0, - 212, 0, 55, 0, - 255, 0, 55, 0}; - +// http://seaviewsensing.com/pub/cpt-city/mjf/departure.c3g +const uint8_t departure_gp[] PROGMEM = { + 0, 68, 34, 0, + 42, 102, 51, 0, + 63, 160, 108, 60, + 84, 218, 166, 120, + 106, 238, 212, 188, + 116, 255, 255, 255, + 138, 200, 255, 200, + 148, 100, 255, 100, + 170, 0, 255, 0, + 191, 0, 192, 0, + 212, 0, 128, 0, + 255, 0, 128, 0}; // Gradient palette "es_landscape_64_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/landscape/tn/es_landscape_64.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 36 bytes of program space. - -const byte es_landscape_64_gp[] PROGMEM = { - 0, 0, 0, 0, - 37, 2, 25, 1, - 76, 15,115, 5, - 127, 79,213, 1, - 128, 126,211, 47, - 130, 188,209,247, - 153, 144,182,205, - 204, 59,117,250, - 255, 1, 37,192}; - +// http://seaviewsensing.com/pub/cpt-city/es/landscape/es_landscape_64.c3g +const uint8_t es_landscape_64_gp[] PROGMEM = { + 0, 0, 0, 0, + 37, 43, 89, 26, + 76, 87, 178, 53, + 127, 163, 235, 8, + 128, 195, 234, 130, + 130, 227, 233, 252, + 153, 205, 219, 234, + 204, 146, 179, 253, + 255, 39, 107, 228}; // Gradient palette "es_landscape_33_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/landscape/tn/es_landscape_33.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 24 bytes of program space. - -const byte es_landscape_33_gp[] PROGMEM = { - 0, 1, 5, 0, - 19, 32, 23, 1, - 38, 161, 55, 1, - 63, 229,144, 1, - 66, 39,142, 74, - 255, 1, 4, 1}; - +// http://seaviewsensing.com/pub/cpt-city/es/landscape/es_landscape_33.c3g +const uint8_t es_landscape_33_gp[] PROGMEM = { + 0, 19, 45, 0, + 19, 116, 86, 3, + 38, 214, 128, 7, + 63, 245, 197, 25, + 66, 124, 196, 156, + 255, 9, 39, 11}; // Gradient palette "rainbowsherbet_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ma/icecream/tn/rainbowsherbet.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 28 bytes of program space. - -const byte rainbowsherbet_gp[] PROGMEM = { - 0, 255, 33, 4, - 43, 255, 68, 25, - 86, 255, 7, 25, - 127, 255, 82,103, - 170, 255,255,242, - 209, 42,255, 22, - 255, 87,255, 65}; - +// http://seaviewsensing.com/pub/cpt-city/ma/icecream/rainbowsherbet.c3g +const uint8_t rainbowsherbet_gp[] PROGMEM = { + 0, 255, 102, 51, + 43, 255, 140, 102, + 86, 255, 51, 102, + 127, 255, 153, 178, + 170, 255, 255, 250, + 209, 128, 255, 97, + 255, 169, 255, 148}; // Gradient palette "gr65_hult_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/hult/tn/gr65_hult.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 24 bytes of program space. - -const byte gr65_hult_gp[] PROGMEM = { - 0, 247,176,247, - 48, 255,136,255, - 89, 220, 29,226, - 160, 7, 82,178, - 216, 1,124,109, - 255, 1,124,109}; - +// http://seaviewsensing.com/pub/cpt-city/hult/gr65_hult.c3g +const uint8_t gr65_hult_gp[] PROGMEM = { + 0, 252, 216, 252, + 48, 255, 192, 255, + 89, 241, 95, 243, + 160, 65, 153, 221, + 216, 34, 184, 182, + 255, 34, 184, 182}; // Gradient palette "gr64_hult_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/hult/tn/gr64_hult.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 32 bytes of program space. - -const byte gr64_hult_gp[] PROGMEM = { - 0, 1,124,109, - 66, 1, 93, 79, - 104, 52, 65, 1, - 130, 115,127, 1, - 150, 52, 65, 1, - 201, 1, 86, 72, - 239, 0, 55, 45, - 255, 0, 55, 45}; - +// http://seaviewsensing.com/pub/cpt-city/hult/gr64_hult.c3g +const uint8_t gr64_hult_gp[] PROGMEM = { + 0, 34, 184, 182, + 66, 14, 162, 160, + 104, 139, 137, 11, + 130, 188, 186, 30, + 150, 139, 137, 11, + 201, 10, 156, 154, + 239, 0, 128, 128, + 255, 0, 128, 128}; // Gradient palette "GMT_drywet_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/gmt/tn/GMT_drywet.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 28 bytes of program space. - -const byte GMT_drywet_gp[] PROGMEM = { - 0, 47, 30, 2, - 42, 213,147, 24, - 84, 103,219, 52, - 127, 3,219,207, - 170, 1, 48,214, - 212, 1, 1,111, - 255, 1, 7, 33}; - +// http://seaviewsensing.com/pub/cpt-city/gmt/GMT_drywet.c3g +const uint8_t GMT_drywet_gp[] PROGMEM = { + 0, 134, 97, 42, + 42, 238, 199, 100, + 84, 180, 238, 135, + 127, 50, 238, 235, + 170, 12, 120, 238, + 212, 38, 1, 183, + 255, 8, 51, 113}; // Gradient palette "ib15_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ing/general/tn/ib15.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 24 bytes of program space. - -const byte ib15_gp[] PROGMEM = { - 0, 113, 91,147, - 72, 157, 88, 78, - 89, 208, 85, 33, - 107, 255, 29, 11, - 141, 137, 31, 39, - 255, 59, 33, 89}; - +// http://seaviewsensing.com/pub/cpt-city/ing/general/ib15.c3g +const uint8_t ib15_gp[] PROGMEM = { + 0, 187, 160, 205, + 72, 212, 158, 159, + 89, 236, 155, 113, + 107, 255, 95, 74, + 141, 201, 98, 121, + 255, 146, 101, 168}; // Gradient palette "Tertiary_01_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/vermillion/tn/Tertiary_01.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 20 bytes of program space. - -const byte Tertiary_01_gp[] PROGMEM = { - 0, 0, 1,255, - 63, 3, 68, 45, - 127, 23,255, 0, - 191, 100, 68, 1, - 255, 255, 1, 4}; - +// http://seaviewsensing.com/pub/cpt-city/nd/vermillion/Tertiary_01.c3g +const uint8_t Tertiary_01_gp[] PROGMEM = { + 0, 0, 25, 255, + 63, 51, 140, 128, + 127, 102, 255, 0, + 191, 178, 140, 26, + 255, 255, 25, 51}; // Gradient palette "lava_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/neota/elem/tn/lava.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 52 bytes of program space. - -const byte lava_gp[] PROGMEM = { - 0, 0, 0, 0, - 46, 18, 0, 0, - 96, 113, 0, 0, - 108, 142, 3, 1, - 119, 175, 17, 1, - 146, 213, 44, 2, - 174, 255, 82, 4, - 188, 255,115, 4, - 202, 255,156, 4, - 218, 255,203, 4, - 234, 255,255, 4, - 244, 255,255, 71, - 255, 255,255,255}; - - -// Gradient palette "fierce_ice_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/neota/elem/tn/fierce-ice.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 28 bytes of program space. - -const byte fierce_ice_gp[] PROGMEM = { - 0, 0, 0, 0, - 59, 0, 9, 45, - 119, 0, 38,255, - 149, 3,100,255, - 180, 23,199,255, - 217, 100,235,255, - 255, 255,255,255}; +// http://seaviewsensing.com/pub/cpt-city/neota/elem/lava.c3g +const uint8_t lava_gp[] PROGMEM = { + 0, 0, 0, 0, + 46, 93, 0, 0, + 96, 187, 0, 0, + 108, 204, 38, 13, + 119, 221, 76, 26, + 146, 238, 115, 38, + 174, 255, 153, 51, + 188, 255, 178, 51, + 202, 255, 204, 51, + 218, 255, 230, 51, + 234, 255, 255, 51, + 244, 255, 255, 153, + 255, 255, 255, 255}; +// Gradient palette "fierce-ice_gp", originally from +// http://seaviewsensing.com/pub/cpt-city/neota/elem/fierce-ice.c3g +const uint8_t fierce_ice_gp[] PROGMEM = { + 0, 0, 0, 0, + 59, 0, 51, 128, + 119, 0, 102, 255, + 149, 51, 153, 255, + 180, 102, 204, 255, + 217, 178, 230, 255, + 255, 255, 255, 255}; // Gradient palette "Colorfull_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Colorfull.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 44 bytes of program space. - -const byte Colorfull_gp[] PROGMEM = { - 0, 10, 85, 5, - 25, 29,109, 18, - 60, 59,138, 42, - 93, 83, 99, 52, - 106, 110, 66, 64, - 109, 123, 49, 65, - 113, 139, 35, 66, - 116, 192,117, 98, - 124, 255,255,137, - 168, 100,180,155, - 255, 22,121,174}; - +// http://seaviewsensing.com/pub/cpt-city/nd/atmospheric/Colorfull.c3g +const uint8_t Colorfull_gp[] PROGMEM = { + 0, 76, 155, 54, + 25, 111, 174, 89, + 60, 146, 193, 125, + 93, 166, 166, 136, + 106, 185, 138, 147, + 109, 193, 121, 148, + 113, 202, 104, 149, + 116, 229, 179, 174, + 124, 255, 255, 199, + 168, 178, 218, 209, + 255, 100, 182, 219}; // Gradient palette "Pink_Purple_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Pink_Purple.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 44 bytes of program space. - -const byte Pink_Purple_gp[] PROGMEM = { - 0, 19, 2, 39, - 25, 26, 4, 45, - 51, 33, 6, 52, - 76, 68, 62,125, - 102, 118,187,240, - 109, 163,215,247, - 114, 217,244,255, - 122, 159,149,221, - 149, 113, 78,188, - 183, 128, 57,155, - 255, 146, 40,123}; - +// http://seaviewsensing.com/pub/cpt-city/nd/atmospheric/Pink_Purple.c3g +const uint8_t Pink_Purple_gp[] PROGMEM = { + 0, 95, 32, 121, + 25, 106, 40, 128, + 51, 117, 48, 135, + 76, 154, 135, 192, + 102, 190, 222, 249, + 109, 215, 236, 252, + 114, 240, 250, 255, + 122, 213, 200, 241, + 149, 187, 149, 226, + 183, 196, 130, 209, + 255, 206, 111, 191}; // Gradient palette "Sunset_Real_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Sunset_Real.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 28 bytes of program space. - -const byte Sunset_Real_gp[] PROGMEM = { - 0, 120, 0, 0, - 22, 179, 22, 0, - 51, 255,104, 0, - 85, 167, 22, 18, - 135, 100, 0,103, - 198, 16, 0,130, - 255, 0, 0,160}; - +// http://seaviewsensing.com/pub/cpt-city/nd/atmospheric/Sunset_Real.c3g +const uint8_t Sunset_Real_gp[] PROGMEM = { + 0, 191, 0, 0, + 22, 223, 85, 0, + 51, 255, 170, 0, + 85, 217, 85, 89, + 135, 178, 0, 178, + 198, 89, 0, 195, + 255, 0, 0, 212}; // Gradient palette "Sunset_Yellow_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Sunset_Yellow.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 44 bytes of program space. - -const byte Sunset_Yellow_gp[] PROGMEM = { - 0, 10, 62,123, - 36, 56,130,103, - 87, 153,225, 85, - 100, 199,217, 68, - 107, 255,207, 54, - 115, 247,152, 57, - 120, 239,107, 61, - 128, 247,152, 57, - 180, 255,207, 54, - 223, 255,227, 48, - 255, 255,248, 42}; - +// http://seaviewsensing.com/pub/cpt-city/nd/atmospheric/Sunset_Yellow.c3g +const uint8_t Sunset_Yellow_gp[] PROGMEM = { + 0, 76, 135, 191, + 36, 143, 188, 178, + 87, 210, 241, 165, + 100, 232, 237, 151, + 107, 255, 232, 138, + 115, 252, 202, 141, + 120, 249, 172, 144, + 128, 252, 202, 141, + 180, 255, 232, 138, + 223, 255, 242, 131, + 255, 255, 252, 125}; // Gradient palette "Beech_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Beech.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 60 bytes of program space. - -const byte Beech_gp[] PROGMEM = { - 0, 255,252,214, - 12, 255,252,214, - 22, 255,252,214, - 26, 190,191,115, - 28, 137,141, 52, - 28, 112,255,205, - 50, 51,246,214, - 71, 17,235,226, - 93, 2,193,199, - 120, 0,156,174, - 133, 1,101,115, - 136, 1, 59, 71, - 136, 7,131,170, - 208, 1, 90,151, - 255, 0, 56,133}; - +// http://seaviewsensing.com/pub/cpt-city/nd/atmospheric/Beech.c3g +const uint8_t Beech_gp[] PROGMEM = { + 0, 255, 254, 238, + 12, 255, 254, 238, + 22, 255, 254, 238, + 26, 228, 224, 186, + 28, 201, 195, 135, + 28, 186, 255, 234, + 50, 138, 251, 238, + 71, 90, 246, 243, + 93, 45, 225, 231, + 120, 0, 204, 219, + 133, 8, 168, 186, + 136, 16, 132, 153, + 136, 65, 189, 217, + 208, 33, 159, 207, + 255, 0, 129, 197}; // Gradient palette "Another_Sunset_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Another_Sunset.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 32 bytes of program space. - -const byte Another_Sunset_gp[] PROGMEM = { - 0, 110, 49, 11, - 29, 55, 34, 10, - 68, 22, 22, 9, - 68, 239,124, 8, - 97, 220,156, 27, - 124, 203,193, 61, - 178, 33, 53, 56, - 255, 0, 1, 52}; - - - - +// http://seaviewsensing.com/pub/cpt-city/nd/atmospheric/Another_Sunset.c3g +const uint8_t Another_Sunset_gp[] PROGMEM = { + 0, 185, 121, 73, + 29, 142, 103, 71, + 68, 100, 84, 69, + 68, 249, 184, 66, + 97, 241, 204, 105, + 124, 234, 225, 144, + 178, 117, 125, 140, + 255, 0, 26, 136}; // Gradient palette "es_autumn_19_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/autumn/tn/es_autumn_19.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 52 bytes of program space. - -const byte es_autumn_19_gp[] PROGMEM = { - 0, 26, 1, 1, - 51, 67, 4, 1, - 84, 118, 14, 1, - 104, 137,152, 52, - 112, 113, 65, 1, - 122, 133,149, 59, - 124, 137,152, 52, - 135, 113, 65, 1, - 142, 139,154, 46, - 163, 113, 13, 1, - 204, 55, 3, 1, - 249, 17, 1, 1, - 255, 17, 1, 1}; - +// http://seaviewsensing.com/pub/cpt-city/es/autumn/es_autumn_19.c3g +const uint8_t es_autumn_19_gp[] PROGMEM = { + 0, 106, 14, 8, + 51, 153, 41, 19, + 84, 190, 70, 24, + 104, 201, 202, 136, + 112, 187, 137, 5, + 122, 199, 200, 142, + 124, 201, 202, 135, + 135, 187, 137, 5, + 142, 202, 203, 129, + 163, 187, 68, 24, + 204, 142, 35, 17, + 249, 90, 5, 4, + 255, 90, 5, 4}; // Gradient palette "BlacK_Blue_Magenta_White_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/BlacK_Blue_Magenta_White.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 28 bytes of program space. - -const byte BlacK_Blue_Magenta_White_gp[] PROGMEM = { - 0, 0, 0, 0, - 42, 0, 0, 45, - 84, 0, 0,255, - 127, 42, 0,255, - 170, 255, 0,255, - 212, 255, 55,255, - 255, 255,255,255}; - +// http://seaviewsensing.com/pub/cpt-city/nd/basic/BlacK_Blue_Magenta_White.c3g +const uint8_t BlacK_Blue_Magenta_White_gp[] PROGMEM = { + 0, 0, 0, 0, + 42, 0, 0, 128, + 84, 0, 0, 255, + 127, 128, 0, 255, + 170, 255, 0, 255, + 212, 255, 128, 255, + 255, 255, 255, 255}; // Gradient palette "BlacK_Magenta_Red_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/BlacK_Magenta_Red.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 20 bytes of program space. - -const byte BlacK_Magenta_Red_gp[] PROGMEM = { - 0, 0, 0, 0, - 63, 42, 0, 45, - 127, 255, 0,255, - 191, 255, 0, 45, - 255, 255, 0, 0}; - +// http://seaviewsensing.com/pub/cpt-city/nd/basic/BlacK_Magenta_Red.c3g +const uint8_t BlacK_Magenta_Red_gp[] PROGMEM = { + 0, 0, 0, 0, + 63, 128, 0, 128, + 127, 255, 0, 255, + 191, 255, 0, 128, + 255, 255, 0, 0}; // Gradient palette "BlacK_Red_Magenta_Yellow_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/BlacK_Red_Magenta_Yellow.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 28 bytes of program space. - -const byte BlacK_Red_Magenta_Yellow_gp[] PROGMEM = { - 0, 0, 0, 0, - 42, 42, 0, 0, - 84, 255, 0, 0, - 127, 255, 0, 45, - 170, 255, 0,255, - 212, 255, 55, 45, - 255, 255,255, 0}; - +// http://seaviewsensing.com/pub/cpt-city/nd/basic/BlacK_Red_Magenta_Yellow.c3g +const uint8_t BlacK_Red_Magenta_Yellow_gp[] PROGMEM = { + 0, 0, 0, 0, + 42, 128, 0, 0, + 84, 255, 0, 0, + 127, 255, 0, 128, + 170, 255, 0, 255, + 212, 255, 128, 128, + 255, 255, 255, 0}; // Gradient palette "Blue_Cyan_Yellow_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/Blue_Cyan_Yellow.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 20 bytes of program space. - -const byte Blue_Cyan_Yellow_gp[] PROGMEM = { - 0, 0, 0,255, - 63, 0, 55,255, - 127, 0,255,255, - 191, 42,255, 45, - 255, 255,255, 0}; - +// http://seaviewsensing.com/pub/cpt-city/nd/basic/Blue_Cyan_Yellow.c3g +const uint8_t Blue_Cyan_Yellow_gp[] PROGMEM = { + 0, 0, 0, 255, + 63, 0, 128, 255, + 127, 0, 255, 255, + 191, 128, 255, 128, + 255, 255, 255, 0}; //Custom palette by Aircoookie - const byte Orange_Teal_gp[] PROGMEM = { 0, 0,150, 92, 55, 0,150, 92, @@ -502,7 +373,6 @@ const byte Orange_Teal_gp[] PROGMEM = { 255, 255, 72, 0}; //Custom palette by Aircoookie - const byte Tiamat_gp[] PROGMEM = { 0, 1, 2, 14, //gc 33, 2, 5, 35, //gc from 47, 61,126 @@ -517,7 +387,6 @@ const byte Tiamat_gp[] PROGMEM = { 255, 255,249,255}; //Custom palette by Aircoookie - const byte April_Night_gp[] PROGMEM = { 0, 1, 5, 45, //deep blue 10, 1, 5, 45, @@ -585,271 +454,215 @@ const byte Atlantica_gp[] PROGMEM = { const byte C9_2_gp[] PROGMEM = { 0, 6, 126, 2, //green 45, 6, 126, 2, - 45, 4, 30, 114, //blue + 46, 4, 30, 114, //blue 90, 4, 30, 114, - 90, 255, 5, 0, //red + 91, 255, 5, 0, //red 135, 255, 5, 0, - 135, 196, 57, 2, //amber + 136, 196, 57, 2, //amber 180, 196, 57, 2, - 180, 137, 85, 2, //yellow + 181, 137, 85, 2, //yellow 255, 137, 85, 2}; //C9, but brighter and with a less purple blue const byte C9_new_gp[] PROGMEM = { 0, 255, 5, 0, //red 60, 255, 5, 0, - 60, 196, 57, 2, //amber (start 61?) + 61, 196, 57, 2, //amber (start 61?) 120, 196, 57, 2, - 120, 6, 126, 2, //green (start 126?) + 121, 6, 126, 2, //green (start 126?) 180, 6, 126, 2, - 180, 4, 30, 114, //blue (start 191?) + 181, 4, 30, 114, //blue (start 191?) 255, 4, 30, 114}; // Gradient palette "temperature_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/arendal/tn/temperature.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 144 bytes of program space. +// http://seaviewsensing.com/pub/cpt-city/arendal/temperature.c3g +const uint8_t temperature_gp[] PROGMEM = { + 0, 30, 92, 179, + 14, 23, 111, 193, + 28, 11, 142, 216, + 42, 4, 161, 230, + 56, 25, 181, 241, + 70, 51, 188, 207, + 84, 102, 204, 206, + 99, 153, 219, 184, + 113, 192, 229, 136, + 127, 204, 230, 75, + 141, 243, 240, 29, + 155, 254, 222, 39, + 170, 252, 199, 7, + 184, 248, 157, 14, + 198, 245, 114, 21, + 226, 219, 30, 38, + 240, 164, 38, 44, + 255, 164, 38, 44}; -const byte temperature_gp[] PROGMEM = { - 0, 1, 27,105, - 14, 1, 40,127, - 28, 1, 70,168, - 42, 1, 92,197, - 56, 1,119,221, - 70, 3,130,151, - 84, 23,156,149, - 99, 67,182,112, - 113, 121,201, 52, - 127, 142,203, 11, - 141, 224,223, 1, - 155, 252,187, 2, - 170, 247,147, 1, - 184, 237, 87, 1, - 198, 229, 43, 1, - 226, 171, 2, 2, - 240, 80, 3, 3, - 255, 80, 3, 3}; - - const byte Aurora2_gp[] PROGMEM = { - 0, 17, 177, 13, //Greenish - 64, 121, 242, 5, //Greenish - 128, 25, 173, 121, //Turquoise - 192, 250, 77, 127, //Pink - 255, 171, 101, 221 //Purple - }; - - // Gradient palette "bhw1_01_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw1/tn/bhw1_01.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 12 bytes of program space. - -const byte retro_clown_gp[] PROGMEM = { - 0, 227,101, 3, - 117, 194, 18, 19, - 255, 92, 8,192}; +// Gradient palette "bhw1_01_gp", originally from +// http://seaviewsensing.com/pub/cpt-city/bhw/bhw1/bhw1_01.c3g +const uint8_t retro_clown_gp[] PROGMEM = { + 0, 244, 168, 48, + 117, 230, 78, 92, + 255, 173, 54, 228}; // Gradient palette "bhw1_04_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw1/tn/bhw1_04.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 20 bytes of program space. - -const byte candy_gp[] PROGMEM = { - 0, 229,227, 1, - 15, 227,101, 3, - 142, 40, 1, 80, - 198, 17, 1, 79, - 255, 0, 0, 45}; +// http://seaviewsensing.com/pub/cpt-city/bhw/bhw1/bhw1_04.c3g +const uint8_t candy_gp[] PROGMEM = { + 0, 245, 242, 31, + 15, 244, 168, 48, + 142, 126, 21, 161, + 198, 90, 22, 160, + 255, 0, 0, 128}; // Gradient palette "bhw1_05_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw1/tn/bhw1_05.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 8 bytes of program space. - -const byte toxy_reaf_gp[] PROGMEM = { - 0, 1,221, 53, - 255, 73, 3,178}; +// http://seaviewsensing.com/pub/cpt-city/bhw/bhw1/bhw1_05.c3g +const uint8_t toxy_reaf_gp[] PROGMEM = { + 0, 5, 239, 137, + 255, 158, 35, 221}; // Gradient palette "bhw1_06_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw1/tn/bhw1_06.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 16 bytes of program space. - -const byte fairy_reaf_gp[] PROGMEM = { - 0, 184, 1,128, - 160, 1,193,182, - 219, 153,227,190, - 255, 255,255,255}; +// http://seaviewsensing.com/pub/cpt-city/bhw/bhw1/bhw1_06.c3g +const uint8_t fairy_reaf_gp[] PROGMEM = { + 0, 225, 19, 194, + 160, 19, 225, 223, + 219, 210, 242, 227, + 255, 255, 255, 255}; // Gradient palette "bhw1_14_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw1/tn/bhw1_14.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 36 bytes of program space. - -const byte semi_blue_gp[] PROGMEM = { - 0, 0, 0, 0, - 12, 1, 1, 3, - 53, 8, 1, 22, - 80, 4, 6, 89, - 119, 2, 25,216, - 145, 7, 10, 99, - 186, 15, 2, 31, - 233, 2, 1, 5, - 255, 0, 0, 0}; +// http://seaviewsensing.com/pub/cpt-city/bhw/bhw1/bhw1_14.c3g +const uint8_t semi_blue_gp[] PROGMEM = { + 0, 0, 0, 0, + 12, 35, 4, 48, + 53, 70, 8, 96, + 80, 56, 48, 168, + 119, 43, 89, 239, + 145, 64, 59, 175, + 186, 86, 30, 110, + 233, 43, 15, 55, + 255, 0, 0, 0}; // Gradient palette "bhw1_three_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw1/tn/bhw1_three.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 32 bytes of program space. - -const byte pink_candy_gp[] PROGMEM = { - 0, 255,255,255, - 45, 7, 12,255, - 112, 227, 1,127, - 112, 227, 1,127, - 140, 255,255,255, - 155, 227, 1,127, - 196, 45, 1, 99, - 255, 255,255,255}; +// http://seaviewsensing.com/pub/cpt-city/bhw/bhw1/bhw1_three.c3g +const uint8_t pink_candy_gp[] PROGMEM = { + 0, 255, 255, 255, + 45, 64, 64, 255, + 112, 244, 16, 193, + 140, 255, 255, 255, + 155, 244, 16, 193, + 196, 131, 13, 175, + 255, 255, 255, 255}; // Gradient palette "bhw1_w00t_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw1/tn/bhw1_w00t.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 16 bytes of program space. - -const byte red_reaf_gp[] PROGMEM = { - 0, 3, 13, 43, - 104, 78,141,240, - 188, 255, 0, 0, - 255, 28, 1, 1}; - +// http://seaviewsensing.com/pub/cpt-city/bhw/bhw1/bhw1_w00t.c3g +const uint8_t red_reaf_gp[] PROGMEM = { + 0, 49, 68, 126, + 104, 162, 195, 249, + 188, 255, 0, 0, + 255, 110, 14, 14}; // Gradient palette "bhw2_23_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw2/tn/bhw2_23.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Red & Flash in SR -// Size: 28 bytes of program space. - -const byte aqua_flash_gp[] PROGMEM = { - 0, 0, 0, 0, - 66, 57,227,233, - 96, 255,255, 8, - 124, 255,255,255, - 153, 255,255, 8, - 188, 57,227,233, - 255, 0, 0, 0}; +// http://seaviewsensing.com/pub/cpt-city/bhw/bhw2/bhw2_23.c3g +const uint8_t aqua_flash_gp[] PROGMEM = { + 0, 0, 0, 0, + 66, 144, 242, 246, + 96, 255, 255, 64, + 124, 255, 255, 255, + 153, 255, 255, 64, + 188, 144, 242, 246, + 255, 0, 0, 0}; // Gradient palette "bhw2_xc_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw2/tn/bhw2_xc.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// YBlue in SR -// Size: 28 bytes of program space. +// http://seaviewsensing.com/pub/cpt-city/bhw/bhw2/bhw2_xc.c3g +const uint8_t yelblu_hot_gp[] PROGMEM = { + 0, 56, 30, 68, + 58, 89, 0, 130, + 122, 103, 0, 86, + 158, 205, 57, 29, + 183, 223, 117, 35, + 219, 241, 177, 41, + 255, 247, 247, 35}; -const byte yelblu_hot_gp[] PROGMEM = { - 0, 4, 2, 9, - 58, 16, 0, 47, - 122, 24, 0, 16, - 158, 144, 9, 1, - 183, 179, 45, 1, - 219, 220,114, 2, - 255, 234,237, 1}; - - // Gradient palette "bhw2_45_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw2/tn/bhw2_45.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 24 bytes of program space. - -const byte lite_light_gp[] PROGMEM = { - 0, 0, 0, 0, - 9, 1, 1, 1, - 40, 5, 5, 6, - 66, 5, 5, 6, - 101, 10, 1, 12, - 255, 0, 0, 0}; +// Gradient palette "bhw2_45_gp", originally from +// http://seaviewsensing.com/pub/cpt-city/bhw/bhw2/bhw2_45.c3g +const uint8_t lite_light_gp[] PROGMEM = { + 0, 0, 0, 0, + 9, 30, 21, 30, + 40, 60, 43, 60, + 66, 60, 43, 60, + 101, 76, 16, 77, + 255, 0, 0, 0}; // Gradient palette "bhw2_22_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw2/tn/bhw2_22.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Pink Plasma in SR -// Size: 20 bytes of program space. - -const byte red_flash_gp[] PROGMEM = { - 0, 0, 0, 0, - 99, 227, 1, 1, - 130, 249,199, 95, - 155, 227, 1, 1, - 255, 0, 0, 0}; +// http://seaviewsensing.com/pub/cpt-city/bhw/bhw2/bhw2_22.c3g +const uint8_t red_flash_gp[] PROGMEM = { + 0, 0, 0, 0, + 99, 244, 12, 12, + 130, 253, 228, 172, + 155, 244, 12, 12, + 255, 0, 0, 0}; // Gradient palette "bhw3_40_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw3/tn/bhw3_40.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 32 bytes of program space. - -const byte blink_red_gp[] PROGMEM = { - 0, 1, 1, 1, - 43, 4, 1, 11, - 76, 10, 1, 3, - 109, 161, 4, 29, - 127, 255, 86,123, - 165, 125, 16,160, - 204, 35, 13,223, - 255, 18, 2, 18}; +// http://seaviewsensing.com/pub/cpt-city/bhw/bhw3/bhw3_40.c3g +const uint8_t blink_red_gp[] PROGMEM = { + 0, 7, 7, 7, + 43, 53, 25, 73, + 76, 76, 15, 46, + 109, 214, 39, 108, + 127, 255, 156, 191, + 165, 194, 73, 212, + 204, 120, 66, 242, + 255, 93, 29, 90}; // Gradient palette "bhw3_52_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw3/tn/bhw3_52.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Yellow2Blue in SR -// Size: 28 bytes of program space. - -const byte red_shift_gp[] PROGMEM = { - 0, 31, 1, 27, - 45, 34, 1, 16, - 99, 137, 5, 9, - 132, 213,128, 10, - 175, 199, 22, 1, - 201, 199, 9, 6, - 255, 1, 0, 1}; +// http://seaviewsensing.com/pub/cpt-city/bhw/bhw3/bhw3_52.c3g +const uint8_t red_shift_gp[] PROGMEM = { + 0, 114, 22, 105, + 45, 118, 22, 85, + 99, 201, 45, 67, + 132, 238, 187, 70, + 175, 232, 85, 34, + 201, 232, 56, 59, + 255, 5, 0, 4}; // Gradient palette "bhw4_097_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw4/tn/bhw4_097.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Yellow2Red in SR -// Size: 44 bytes of program space. - -const byte red_tide_gp[] PROGMEM = { - 0, 247, 5, 0, - 28, 255, 67, 1, - 43, 234, 88, 11, - 58, 234,176, 51, - 84, 229, 28, 1, - 114, 113, 12, 1, - 140, 255,225, 44, - 168, 113, 12, 1, - 196, 244,209, 88, - 216, 255, 28, 1, - 255, 53, 1, 1}; +// http://seaviewsensing.com/pub/cpt-city/bhw/bhw4/bhw4_097.c3g +const uint8_t red_tide_gp[] PROGMEM = { + 0, 252, 46, 0, + 28, 255, 139, 33, + 43, 247, 158, 74, + 58, 247, 216, 134, + 84, 245, 94, 15, + 114, 187, 65, 16, + 140, 255, 241, 127, + 168, 187, 65, 16, + 196, 251, 233, 167, + 216, 255, 94, 9, + 255, 140, 8, 6}; // Gradient palette "bhw4_017_gp", originally from -// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw4/tn/bhw4_017.png.index.html -// converted for FastLED with gammas (2.6, 2.2, 2.5) -// Size: 40 bytes of program space. - -const byte candy2_gp[] PROGMEM = { - 0, 39, 33, 34, - 25, 4, 6, 15, - 48, 49, 29, 22, - 73, 224,173, 1, - 89, 177, 35, 5, - 130, 4, 6, 15, - 163, 255,114, 6, - 186, 224,173, 1, - 211, 39, 33, 34, - 255, 1, 1, 1}; +// http://seaviewsensing.com/pub/cpt-city/bhw/bhw4/bhw4_017.c3g +const uint8_t candy2_gp[] PROGMEM = { + 0, 124, 102, 114, + 25, 55, 49, 83, + 48, 136, 96, 96, + 73, 243, 214, 34, + 89, 222, 104, 54, + 130, 55, 49, 83, + 163, 255, 177, 58, + 186, 243, 214, 34, + 211, 124, 102, 114, + 255, 29, 19, 18}; const byte trafficlight_gp[] PROGMEM = { - 0, 0, 0, 0, //black - 85, 0, 255, 0, //green - 170, 255, 255, 0, //yellow - 255, 255, 0, 0}; //red + 0, 0, 0, 0, //black + 85, 0, 255, 0, //green + 170, 255, 255, 0, //yellow + 255, 255, 0, 0}; //red + +const byte Aurora2_gp[] PROGMEM = { + 0, 17, 177, 13, //Greenish + 64, 121, 242, 5, //Greenish + 128, 25, 173, 121, //Turquoise + 192, 250, 77, 127, //Pink + 255, 171, 101, 221}; //Purple // array of fastled palettes (palette 6 - 12) const TProgmemRGBPalette16 *const fastledPalettes[] PROGMEM = { @@ -866,7 +679,7 @@ const TProgmemRGBPalette16 *const fastledPalettes[] PROGMEM = { // This will let us programmatically choose one based on // a number, rather than having to activate each explicitly // by name every time. -const byte* const gGradientPalettes[] PROGMEM = { +const uint8_t* const gGradientPalettes[] PROGMEM = { Sunset_Real_gp, //13-00 Sunset es_rivendell_15_gp, //14-01 Rivendell es_ocean_breeze_036_gp, //15-02 Breeze diff --git a/wled00/presets.cpp b/wled00/presets.cpp index b749289b..0a4380f8 100644 --- a/wled00/presets.cpp +++ b/wled00/presets.cpp @@ -29,8 +29,9 @@ bool presetNeedsSaving() { static void doSaveState() { bool persist = (presetToSave < 251); - unsigned long start = millis(); - while (strip.isUpdating() && millis()-start < (2*FRAMETIME_FIXED)+1) yield(); // wait 2 frames + unsigned long maxWait = millis() + strip.getFrameTime(); + while (strip.isUpdating() && millis() < maxWait) delay(1); // wait for strip to finish updating, accessing FS during sendout causes glitches + if (!requestJSONBufferLock(10)) return; initPresetsFile(); // just in case if someone deleted presets.json using /edit @@ -56,14 +57,10 @@ static void doSaveState() { */ #if defined(ARDUINO_ARCH_ESP32) if (!persist) { - if (tmpRAMbuffer!=nullptr) free(tmpRAMbuffer); + w_free(tmpRAMbuffer); size_t len = measureJson(*pDoc) + 1; - DEBUG_PRINTLN(len); // if possible use SPI RAM on ESP32 - if (psramSafe && psramFound()) - tmpRAMbuffer = (char*) ps_malloc(len); - else - tmpRAMbuffer = (char*) malloc(len); + tmpRAMbuffer = (char*)w_malloc(len); if (tmpRAMbuffer!=nullptr) { serializeJson(*pDoc, tmpRAMbuffer, len); } else { @@ -80,8 +77,8 @@ static void doSaveState() { // clean up saveLedmap = -1; presetToSave = 0; - free(saveName); - free(quickLoad); + w_free(saveName); + w_free(quickLoad); saveName = nullptr; quickLoad = nullptr; playlistSave = false; @@ -168,9 +165,9 @@ void handlePresets() DEBUG_PRINTF_P(PSTR("Applying preset: %u\n"), (unsigned)tmpPreset); - #if defined(ARDUINO_ARCH_ESP32S3) || defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32C3) - unsigned long start = millis(); - while (strip.isUpdating() && millis() - start < FRAMETIME_FIXED) yield(); // wait for strip to finish updating, accessing FS during sendout causes glitches + #if defined(ARDUINO_ARCH_ESP32S2) || defined(ARDUINO_ARCH_ESP32C3) + unsigned long maxWait = millis() + strip.getFrameTime(); + while (strip.isUpdating() && millis() < maxWait) delay(1); // wait for strip to finish updating, accessing FS during sendout causes glitches #endif #ifdef ARDUINO_ARCH_ESP32 @@ -206,7 +203,7 @@ void handlePresets() #if defined(ARDUINO_ARCH_ESP32) //Aircoookie recommended not to delete buffer if (tmpPreset==255 && tmpRAMbuffer!=nullptr) { - free(tmpRAMbuffer); + w_free(tmpRAMbuffer); tmpRAMbuffer = nullptr; } #endif @@ -220,8 +217,8 @@ void handlePresets() //called from handleSet(PS=) [network callback (sObj is empty), IR (irrational), deserializeState, UDP] and deserializeState() [network callback (filedoc!=nullptr)] void savePreset(byte index, const char* pname, JsonObject sObj) { - if (!saveName) saveName = static_cast(malloc(33)); - if (!quickLoad) quickLoad = static_cast(malloc(9)); + if (!saveName) saveName = static_cast(w_malloc(33)); + if (!quickLoad) quickLoad = static_cast(w_malloc(9)); if (!saveName || !quickLoad) return; if (index == 0 || (index > 250 && index < 255)) return; @@ -267,8 +264,8 @@ void savePreset(byte index, const char* pname, JsonObject sObj) presetsModifiedTime = toki.second(); //unix time updateFSInfo(); } - free(saveName); - free(quickLoad); + w_free(saveName); + w_free(quickLoad); saveName = nullptr; quickLoad = nullptr; } else { diff --git a/wled00/set.cpp b/wled00/set.cpp index c817f255..018d349b 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -28,7 +28,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) char gw[5] = "GW"; gw[2] = 48+n; gw[4] = 0; //GW address char sn[5] = "SN"; sn[2] = 48+n; sn[4] = 0; //subnet mask if (request->hasArg(cs)) { - if (n >= multiWiFi.size()) multiWiFi.push_back(WiFiConfig()); // expand vector by one + if (n >= multiWiFi.size()) multiWiFi.emplace_back(); // expand vector by one char oldSSID[33]; strcpy(oldSSID, multiWiFi[n].clientSSID); char oldPass[65]; strcpy(oldPass, multiWiFi[n].clientPass); @@ -129,6 +129,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) unsigned length, start, maMax; uint8_t pins[5] = {255, 255, 255, 255, 255}; + // this will set global ABL max current used when per-port ABL is not used unsigned ablMilliampsMax = request->arg(F("MA")).toInt(); BusManager::setMilliampsMax(ablMilliampsMax); @@ -136,10 +137,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) strip.correctWB = request->hasArg(F("CCT")); strip.cctFromRgb = request->hasArg(F("CR")); cctICused = request->hasArg(F("IC")); - Bus::setCCTBlend(request->arg(F("CB")).toInt()); + uint8_t cctBlending = request->arg(F("CB")).toInt(); + Bus::setCCTBlend(cctBlending); Bus::setGlobalAWMode(request->arg(F("AW")).toInt()); strip.setTargetFps(request->arg(F("FR")).toInt()); - useGlobalLedBuffer = request->hasArg(F("LD")); #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) useParallelI2S = request->hasArg(F("PR")); #endif @@ -207,12 +208,12 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) maMax = 0; } else { maPerLed = request->arg(la).toInt(); - maMax = request->arg(ma).toInt(); // if ABL is disabled this will be 0 + maMax = request->arg(ma).toInt() * request->hasArg(F("PPL")); // if PP-ABL is disabled maMax (per bus) must be 0 } type |= request->hasArg(rf) << 7; // off refresh override // actual finalization is done in WLED::loop() (removing old busses and adding new) // this may happen even before this loop is finished so we do "doInitBusses" after the loop - busConfigs.emplace_back(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freq, useGlobalLedBuffer, maPerLed, maMax); + busConfigs.emplace_back(type, pins, start, length, colorOrder | (channelSwap<<4), request->hasArg(cv), skip, awmode, freq, maPerLed, maMax); busesChanged = true; } //doInitBusses = busesChanged; // we will do that below to ensure all input data is processed @@ -334,6 +335,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) t = request->arg(F("TP")).toInt(); randomPaletteChangeTime = MIN(255,MAX(1,t)); useHarmonicRandomPalette = request->hasArg(F("TH")); + useRainbowWheel = request->hasArg(F("RW")); nightlightTargetBri = request->arg(F("TB")).toInt(); t = request->arg(F("TL")).toInt(); @@ -342,7 +344,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) nightlightMode = request->arg(F("TW")).toInt(); t = request->arg(F("PB")).toInt(); - if (t >= 0 && t < 4) strip.paletteBlend = t; + if (t >= 0 && t < 4) paletteBlend = t; t = request->arg(F("BF")).toInt(); if (t > 0) briMultiplier = t; @@ -358,7 +360,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) DEBUG_PRINTLN(F("Enumerating ledmaps")); enumerateLedmaps(); DEBUG_PRINTLN(F("Loading custom palettes")); - strip.loadCustomPalettes(); // (re)load all custom palettes + loadCustomPalettes(); // (re)load all custom palettes } //SYNC @@ -771,14 +773,14 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) if (subPage == SUBPAGE_2D) { strip.isMatrix = request->arg(F("SOMP")).toInt(); - strip.panel.clear(); // release memory if allocated + strip.panel.clear(); if (strip.isMatrix) { - strip.panels = MAX(1,MIN(WLED_MAX_PANELS,request->arg(F("MPC")).toInt())); - strip.panel.reserve(strip.panels); // pre-allocate memory - for (unsigned i=0; iarg(F("MPC")).toInt(), 1, WLED_MAX_PANELS); + strip.panel.reserve(panels); // pre-allocate memory + for (unsigned i=0; iarg(pO).toInt(); strip.panel.push_back(p); } - strip.setUpMatrix(); // will check limits - strip.makeAutoSegments(true); - strip.deserializeMap(); - } else { - Segment::maxWidth = strip.getLengthTotal(); - Segment::maxHeight = 1; } + strip.panel.shrink_to_fit(); // release unused memory + strip.deserializeMap(); // (re)load default ledmap (will also setUpMatrix() if ledmap does not exist) + strip.makeAutoSegments(true); // force re-creation of segments } #endif @@ -824,7 +823,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) //segment select (sets main segment) pos = req.indexOf(F("SM=")); if (pos > 0 && !realtimeMode) { - strip.setMainSegmentId(getNumVal(&req, pos)); + strip.setMainSegmentId(getNumVal(req, pos)); } byte selectedSeg = strip.getFirstSelectedSegId(); @@ -833,7 +832,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) pos = req.indexOf(F("SS=")); if (pos > 0) { - unsigned t = getNumVal(&req, pos); + unsigned t = getNumVal(req, pos); if (t < strip.getSegmentsNum()) { selectedSeg = t; singleSegment = true; @@ -843,7 +842,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) Segment& selseg = strip.getSegment(selectedSeg); pos = req.indexOf(F("SV=")); //segment selected if (pos > 0) { - unsigned t = getNumVal(&req, pos); + unsigned t = getNumVal(req, pos); if (t == 2) for (unsigned i = 0; i < strip.getSegmentsNum(); i++) strip.getSegment(i).selected = false; // unselect other segments selseg.selected = t; } @@ -872,19 +871,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 = std::abs(getNumVal(&req, pos)); + startI = std::abs(getNumVal(req, pos)); } pos = req.indexOf(F("S2=")); //segment stop if (pos > 0) { - stopI = std::abs(getNumVal(&req, pos)); + stopI = std::abs(getNumVal(req, pos)); } pos = req.indexOf(F("GP=")); //segment grouping if (pos > 0) { - grpI = std::max(1,getNumVal(&req, pos)); + grpI = std::max(1,getNumVal(req, pos)); } pos = req.indexOf(F("SP=")); //segment spacing if (pos > 0) { - spcI = std::max(0,getNumVal(&req, pos)); + spcI = std::max(0,getNumVal(req, pos)); } strip.suspend(); // must suspend strip operations before changing geometry selseg.setGeometry(startI, stopI, grpI, spcI, UINT16_MAX, startY, stopY, selseg.map1D2D); @@ -898,7 +897,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) pos = req.indexOf(F("SB=")); //Segment brightness/opacity if (pos > 0) { - byte segbri = getNumVal(&req, pos); + byte segbri = getNumVal(req, pos); selseg.setOption(SEG_OPTION_ON, segbri); // use transition if (segbri) { selseg.setOpacity(segbri); @@ -907,7 +906,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) pos = req.indexOf(F("SW=")); //segment power if (pos > 0) { - switch (getNumVal(&req, pos)) { + switch (getNumVal(req, pos)) { case 0: selseg.setOption(SEG_OPTION_ON, false); break; // use transition case 1: selseg.setOption(SEG_OPTION_ON, true); break; // use transition default: selseg.setOption(SEG_OPTION_ON, !selseg.on); break; // use transition @@ -915,16 +914,16 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) } pos = req.indexOf(F("PS=")); //saves current in preset - if (pos > 0) savePreset(getNumVal(&req, pos)); + if (pos > 0) savePreset(getNumVal(req, pos)); pos = req.indexOf(F("P1=")); //sets first preset for cycle - if (pos > 0) presetCycMin = getNumVal(&req, pos); + if (pos > 0) presetCycMin = getNumVal(req, pos); pos = req.indexOf(F("P2=")); //sets last preset for cycle - if (pos > 0) presetCycMax = getNumVal(&req, pos); + if (pos > 0) presetCycMax = getNumVal(req, pos); //apply preset - if (updateVal(req.c_str(), "PL=", &presetCycCurr, presetCycMin, presetCycMax)) { + if (updateVal(req.c_str(), "PL=", presetCycCurr, presetCycMin, presetCycMax)) { applyPreset(presetCycCurr); } @@ -932,25 +931,25 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) if (pos > 0) doAdvancePlaylist = true; //set brightness - updateVal(req.c_str(), "&A=", &bri); + updateVal(req.c_str(), "&A=", bri); bool col0Changed = false, col1Changed = false, col2Changed = false; //set colors - col0Changed |= updateVal(req.c_str(), "&R=", &colIn[0]); - col0Changed |= updateVal(req.c_str(), "&G=", &colIn[1]); - col0Changed |= updateVal(req.c_str(), "&B=", &colIn[2]); - col0Changed |= updateVal(req.c_str(), "&W=", &colIn[3]); + col0Changed |= updateVal(req.c_str(), "&R=", colIn[0]); + col0Changed |= updateVal(req.c_str(), "&G=", colIn[1]); + col0Changed |= updateVal(req.c_str(), "&B=", colIn[2]); + col0Changed |= updateVal(req.c_str(), "&W=", colIn[3]); - col1Changed |= updateVal(req.c_str(), "R2=", &colInSec[0]); - col1Changed |= updateVal(req.c_str(), "G2=", &colInSec[1]); - col1Changed |= updateVal(req.c_str(), "B2=", &colInSec[2]); - col1Changed |= updateVal(req.c_str(), "W2=", &colInSec[3]); + col1Changed |= updateVal(req.c_str(), "R2=", colInSec[0]); + col1Changed |= updateVal(req.c_str(), "G2=", colInSec[1]); + col1Changed |= updateVal(req.c_str(), "B2=", colInSec[2]); + col1Changed |= updateVal(req.c_str(), "W2=", colInSec[3]); #ifdef WLED_ENABLE_LOXONE //lox parser pos = req.indexOf(F("LX=")); // Lox primary color if (pos > 0) { - int lxValue = getNumVal(&req, pos); + int lxValue = getNumVal(req, pos); if (parseLx(lxValue, colIn)) { bri = 255; nightlightActive = false; //always disable nightlight when toggling @@ -959,7 +958,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) } pos = req.indexOf(F("LY=")); // Lox secondary color if (pos > 0) { - int lxValue = getNumVal(&req, pos); + int lxValue = getNumVal(req, pos); if(parseLx(lxValue, colInSec)) { bri = 255; nightlightActive = false; //always disable nightlight when toggling @@ -971,11 +970,11 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) //set hue pos = req.indexOf(F("HU=")); if (pos > 0) { - uint16_t temphue = getNumVal(&req, pos); + uint16_t temphue = getNumVal(req, pos); byte tempsat = 255; pos = req.indexOf(F("SA=")); if (pos > 0) { - tempsat = getNumVal(&req, pos); + tempsat = getNumVal(req, pos); } byte sec = req.indexOf(F("H2")); colorHStoRGB(temphue, tempsat, (sec>0) ? colInSec : colIn); @@ -986,25 +985,25 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) pos = req.indexOf(F("&K=")); if (pos > 0) { byte sec = req.indexOf(F("K2")); - colorKtoRGB(getNumVal(&req, pos), (sec>0) ? colInSec : colIn); + colorKtoRGB(getNumVal(req, pos), (sec>0) ? colInSec : colIn); col0Changed |= (!sec); col1Changed |= sec; } //set color from HEX or 32bit DEC pos = req.indexOf(F("CL=")); if (pos > 0) { - colorFromDecOrHexString(colIn, req.substring(pos + 3).c_str()); + colorFromDecOrHexString(colIn, (char*)req.substring(pos + 3).c_str()); col0Changed = true; } pos = req.indexOf(F("C2=")); if (pos > 0) { - colorFromDecOrHexString(colInSec, req.substring(pos + 3).c_str()); + colorFromDecOrHexString(colInSec, (char*)req.substring(pos + 3).c_str()); col1Changed = true; } pos = req.indexOf(F("C3=")); if (pos > 0) { byte tmpCol[4]; - colorFromDecOrHexString(tmpCol, req.substring(pos + 3).c_str()); + colorFromDecOrHexString(tmpCol, (char*)req.substring(pos + 3).c_str()); col2 = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]); selseg.setColor(2, col2); // defined above (SS= or main) col2Changed = true; @@ -1013,7 +1012,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) //set to random hue SR=0->1st SR=1->2nd pos = req.indexOf(F("SR")); if (pos > 0) { - byte sec = getNumVal(&req, pos); + byte sec = getNumVal(req, pos); setRandomColor(sec? colInSec : colIn); col0Changed |= (!sec); col1Changed |= sec; } @@ -1039,19 +1038,19 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) bool fxModeChanged = false, speedChanged = false, intensityChanged = false, paletteChanged = false; bool custom1Changed = false, custom2Changed = false, custom3Changed = false, check1Changed = false, check2Changed = false, check3Changed = false; // set effect parameters - if (updateVal(req.c_str(), "FX=", &effectIn, 0, strip.getModeCount()-1)) { + if (updateVal(req.c_str(), "FX=", effectIn, 0, strip.getModeCount()-1)) { if (request != nullptr) unloadPlaylist(); // unload playlist if changing FX using web request fxModeChanged = true; } - speedChanged = updateVal(req.c_str(), "SX=", &speedIn); - intensityChanged = updateVal(req.c_str(), "IX=", &intensityIn); - paletteChanged = updateVal(req.c_str(), "FP=", &paletteIn, 0, strip.getPaletteCount()-1); - custom1Changed = updateVal(req.c_str(), "X1=", &custom1In); - custom2Changed = updateVal(req.c_str(), "X2=", &custom2In); - custom3Changed = updateVal(req.c_str(), "X3=", &custom3In); - check1Changed = updateVal(req.c_str(), "M1=", &check1In); - check2Changed = updateVal(req.c_str(), "M2=", &check2In); - check3Changed = updateVal(req.c_str(), "M3=", &check3In); + speedChanged = updateVal(req.c_str(), "SX=", speedIn); + intensityChanged = updateVal(req.c_str(), "IX=", intensityIn); + paletteChanged = updateVal(req.c_str(), "FP=", paletteIn, 0, getPaletteCount()-1); + custom1Changed = updateVal(req.c_str(), "X1=", custom1In); + custom2Changed = updateVal(req.c_str(), "X2=", custom2In); + custom3Changed = updateVal(req.c_str(), "X3=", custom3In); + check1Changed = updateVal(req.c_str(), "M1=", check1In); + check2Changed = updateVal(req.c_str(), "M2=", check2In); + check3Changed = updateVal(req.c_str(), "M3=", check3In); stateChanged |= (fxModeChanged || speedChanged || intensityChanged || paletteChanged || custom1Changed || custom2Changed || custom3Changed || check1Changed || check2Changed || check3Changed); @@ -1077,13 +1076,13 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) //set advanced overlay pos = req.indexOf(F("OL=")); if (pos > 0) { - overlayCurrent = getNumVal(&req, pos); + overlayCurrent = getNumVal(req, pos); } //apply macro (deprecated, added for compatibility with pre-0.11 automations) pos = req.indexOf(F("&M=")); if (pos > 0) { - applyPreset(getNumVal(&req, pos) + 16); + applyPreset(getNumVal(req, pos) + 16); } //toggle send UDP direct notifications @@ -1102,7 +1101,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) pos = req.indexOf(F("&T=")); if (pos > 0) { nightlightActive = false; //always disable nightlight when toggling - switch (getNumVal(&req, pos)) + switch (getNumVal(req, pos)) { case 0: if (bri != 0){briLast = bri; bri = 0;} break; //off, only if it was previously on case 1: if (bri == 0) bri = briLast; break; //on, only if it was previously off @@ -1121,7 +1120,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) nightlightActive = false; } else { nightlightActive = true; - if (!aNlDef) nightlightDelayMins = getNumVal(&req, pos); + if (!aNlDef) nightlightDelayMins = getNumVal(req, pos); else nightlightDelayMins = nightlightDelayMinsDefault; nightlightStartTime = millis(); } @@ -1135,7 +1134,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) //set nightlight target brightness pos = req.indexOf(F("NT=")); if (pos > 0) { - nightlightTargetBri = getNumVal(&req, pos); + nightlightTargetBri = getNumVal(req, pos); nightlightActiveOld = false; //re-init } @@ -1143,35 +1142,36 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) pos = req.indexOf(F("NF=")); if (pos > 0) { - nightlightMode = getNumVal(&req, pos); + nightlightMode = getNumVal(req, pos); nightlightActiveOld = false; //re-init } if (nightlightMode > NL_MODE_SUN) nightlightMode = NL_MODE_SUN; pos = req.indexOf(F("TT=")); - if (pos > 0) transitionDelay = getNumVal(&req, pos); + if (pos > 0) transitionDelay = getNumVal(req, pos); strip.setTransition(transitionDelay); //set time (unix timestamp) pos = req.indexOf(F("ST=")); if (pos > 0) { - setTimeFromAPI(getNumVal(&req, pos)); + setTimeFromAPI(getNumVal(req, pos)); } //set countdown goal (unix timestamp) pos = req.indexOf(F("CT=")); if (pos > 0) { - countdownTime = getNumVal(&req, pos); + countdownTime = getNumVal(req, pos); if (countdownTime - toki.second() > 0) countdownOverTriggered = false; } pos = req.indexOf(F("LO=")); if (pos > 0) { - realtimeOverride = getNumVal(&req, pos); + realtimeOverride = getNumVal(req, pos); if (realtimeOverride > 2) realtimeOverride = REALTIME_OVERRIDE_ALWAYS; if (realtimeMode && useMainSegmentOnly) { strip.getMainSegment().freeze = !realtimeOverride; + realtimeOverride = REALTIME_OVERRIDE_NONE; // ignore request for override if using main segment only } } @@ -1184,12 +1184,12 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) pos = req.indexOf(F("U0=")); //user var 0 if (pos > 0) { - userVar0 = getNumVal(&req, pos); + userVar0 = getNumVal(req, pos); } pos = req.indexOf(F("U1=")); //user var 1 if (pos > 0) { - userVar1 = getNumVal(&req, pos); + userVar1 = getNumVal(req, pos); } // you can add more if you need diff --git a/wled00/udp.cpp b/wled00/udp.cpp index 4395b285..ed608da3 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -6,7 +6,7 @@ #define UDP_SEG_SIZE 36 #define SEG_OFFSET (41) -#define WLEDPACKETSIZE (41+(MAX_NUM_SEGMENTS*UDP_SEG_SIZE)+0) +#define WLEDPACKETSIZE (41+(WS2812FX::getMaxSegments()*UDP_SEG_SIZE)+0) #define UDP_IN_MAXSIZE 1472 #define PRESUMED_NETWORK_DELAY 3 //how many ms could it take on avg to reach the receiver? This will be added to transmitted times @@ -55,7 +55,7 @@ void notify(byte callMode, bool followUp) //0: old 1: supports white 2: supports secondary color //3: supports FX intensity, 24 byte packet 4: supports transitionDelay 5: sup palette //6: supports timebase syncing, 29 byte packet 7: supports tertiary color 8: supports sys time sync, 36 byte packet - //9: supports sync groups, 37 byte packet 10: supports CCT, 39 byte packet 11: per segment options, variable packet length (40+MAX_NUM_SEGMENTS*3) + //9: supports sync groups, 37 byte packet 10: supports CCT, 39 byte packet 11: per segment options, variable packet length (40+WS2812FX::getMaxSegments()*3) //12: enhanced effect sliders, 2D & mapping options udpOut[11] = 12; col = mainseg.colors[1]; @@ -104,7 +104,7 @@ void notify(byte callMode, bool followUp) udpOut[40] = UDP_SEG_SIZE; //size of each loop iteration (one segment) size_t s = 0, nsegs = strip.getSegmentsNum(); for (size_t i = 0; i < nsegs; i++) { - Segment &selseg = strip.getSegment(i); + const Segment &selseg = strip.getSegment(i); if (!selseg.isActive()) continue; unsigned ofs = 41 + s*UDP_SEG_SIZE; //start of segment offset byte udpOut[0 +ofs] = s; @@ -177,7 +177,7 @@ void notify(byte callMode, bool followUp) memcpy(buffer.data + packetSize, &udpOut[41+i*UDP_SEG_SIZE], UDP_SEG_SIZE); packetSize += UDP_SEG_SIZE; if (packetSize + UDP_SEG_SIZE < bufferSize) continue; - DEBUG_PRINTF_P(PSTR("ESP-NOW sending packet: %d (%d)\n"), (int)buffer.packet, packetSize+3); + DEBUG_PRINTF_P(PSTR("ESP-NOW sending packet: %d (%u)\n"), (int)buffer.packet, packetSize+3); err = quickEspNow.send(ESPNOW_BROADCAST_ADDRESS, reinterpret_cast(&buffer), packetSize+3); buffer.packet++; packetSize = 0; @@ -266,13 +266,13 @@ static void parseNotifyPacket(const uint8_t *udpIn) { strip.resume(); } size_t inactiveSegs = 0; - for (size_t i = 0; i < numSrcSegs && i < strip.getMaxSegments(); i++) { + for (size_t i = 0; i < numSrcSegs && i < WS2812FX::getMaxSegments(); i++) { unsigned ofs = 41 + i*udpIn[40]; //start of segment offset byte unsigned id = udpIn[0 +ofs]; DEBUG_PRINTF_P(PSTR("UDP segment received: %u\n"), id); if (id > strip.getSegmentsNum()) break; else if (id == strip.getSegmentsNum()) { - if (receiveSegmentBounds && id < strip.getMaxSegments()) strip.appendSegment(); + if (receiveSegmentBounds && id < WS2812FX::getMaxSegments()) strip.appendSegment(); else break; } DEBUG_PRINTF_P(PSTR("UDP segment check: %u\n"), id); @@ -327,7 +327,7 @@ static void parseNotifyPacket(const uint8_t *udpIn) { // freeze, reset should never be synced // LSB to MSB: select, reverse, on, mirror, freeze, reset, reverse_y, mirror_y, transpose, map1d2d (3), ssim (2), set (2) DEBUG_PRINTF_P(PSTR("Apply options: %u\n"), id); - selseg.options = (selseg.options & 0b0000000000110001U) | (udpIn[28+ofs]<<8) | (udpIn[9 +ofs] & 0b11001110U); // ignore selected, freeze, reset + selseg.options = (selseg.options & 0b0000000000110001U) | ((uint16_t)udpIn[28+ofs]<<8) | (udpIn[9 +ofs] & 0b11001110U); // ignore selected, freeze, reset if (applyEffects) { DEBUG_PRINTF_P(PSTR("Apply sliders: %u\n"), id); selseg.custom1 = udpIn[29+ofs]; @@ -406,31 +406,26 @@ static void parseNotifyPacket(const uint8_t *udpIn) { stateUpdated(CALL_MODE_NOTIFICATION); } +// realtimeLock() is called from UDP notifications, JSON API or serial Ada void realtimeLock(uint32_t timeoutMs, byte md) { if (!realtimeMode && !realtimeOverride) { - unsigned stop, start; if (useMainSegmentOnly) { Segment& mainseg = strip.getMainSegment(); - start = mainseg.start; - stop = mainseg.stop; + mainseg.clear(); // clear entire segment (in case sender transmits less pixels) mainseg.freeze = true; // if WLED was off and using main segment only, freeze non-main segments so they stay off if (bri == 0) { - for (size_t s = 0; s < strip.getSegmentsNum(); s++) { - strip.getSegment(s).freeze = true; - } + for (size_t s = 0; s < strip.getSegmentsNum(); s++) strip.getSegment(s).freeze = true; } } else { - start = 0; - stop = strip.getLengthTotal(); + // clear entire strip + strip.fill(BLACK); + } + // if strip is off (bri==0) and not already in RTM + if (briT == 0) { + strip.setBrightness(scaledBri(briLast), true); } - // clear strip/segment - for (size_t i = start; i < stop; i++) strip.setPixelColor(i,BLACK); - } - // if strip is off (bri==0) and not already in RTM - if (briT == 0 && !realtimeMode && !realtimeOverride) { - strip.setBrightness(scaledBri(briLast), true); } if (realtimeTimeout != UINT32_MAX) { @@ -452,6 +447,7 @@ void exitRealtime() { realtimeIP[0] = 0; if (useMainSegmentOnly) { // unfreeze live segment again strip.getMainSegment().freeze = false; + strip.trigger(); } else { strip.show(); // possible fix for #3589 } @@ -481,7 +477,8 @@ void handleNotifications() if (e131NewData && millis() - strip.getLastShow() > 15) { e131NewData = false; - strip.show(); + if (useMainSegmentOnly) strip.trigger(); + else strip.show(); } //unlock strip when realtime UDP times out @@ -508,13 +505,13 @@ void handleNotifications() uint8_t lbuf[packetSize]; rgbUdp.read(lbuf, packetSize); realtimeLock(realtimeTimeoutMs, REALTIME_MODE_HYPERION); - if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return; + if (realtimeOverride) return; unsigned totalLen = strip.getLengthTotal(); - if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); // set up parameters for get/setPixelColor() for (size_t i = 0, id = 0; i < packetSize -2 && id < totalLen; i += 3, id++) { setRealtimePixel(id, lbuf[i], lbuf[i+1], lbuf[i+2], 0); } - if (!(realtimeMode && useMainSegmentOnly)) strip.show(); + if (useMainSegmentOnly) strip.trigger(); + else strip.show(); return; } } @@ -583,7 +580,7 @@ void handleNotifications() realtimeIP = (isSupp) ? notifier2Udp.remoteIP() : notifierUdp.remoteIP(); realtimeLock(realtimeTimeoutMs, REALTIME_MODE_TPM2NET); - if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return; + if (realtimeOverride) return; tpmPacketCount++; //increment the packet count if (tpmPacketCount == 1) tpmPayloadFrameSize = (udpIn[2] << 8) + udpIn[3]; //save frame size for the whole payload if this is the first packet @@ -592,13 +589,13 @@ void handleNotifications() unsigned id = (tpmPayloadFrameSize/3)*(packetNum-1); //start LED unsigned totalLen = strip.getLengthTotal(); - if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); // set up parameters for get/setPixelColor() for (size_t i = 6; i < tpmPayloadFrameSize + 4U && id < totalLen; i += 3, id++) { setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0); } if (tpmPacketCount == numPackets) { //reset packet count and show if all packets were received tpmPacketCount = 0; - strip.show(); + if (useMainSegmentOnly) strip.trigger(); + else strip.show(); } return; } @@ -610,17 +607,15 @@ void handleNotifications() DEBUG_PRINTLN(realtimeIP); if (packetSize < 2) return; - if (udpIn[1] == 0) - { - realtimeTimeout = 0; + if (udpIn[1] == 0) { + realtimeTimeout = 0; // cancel realtime mode immediately return; } else { realtimeLock(udpIn[1]*1000 +1, REALTIME_MODE_UDP); } - if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return; + if (realtimeOverride) return; unsigned totalLen = strip.getLengthTotal(); - if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); // set up parameters for get/setPixelColor() if (udpIn[0] == 1 && packetSize > 5) //warls { for (size_t i = 2; i < packetSize -3; i += 4) @@ -654,7 +649,8 @@ void handleNotifications() setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]); } } - strip.show(); + if (useMainSegmentOnly) strip.trigger(); + else strip.show(); return; } @@ -679,20 +675,7 @@ void handleNotifications() void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w) { unsigned pix = i + arlsOffset; - if (pix < strip.getLengthTotal()) { - if (!arlsDisableGammaCorrection && gammaCorrectCol) { - r = gamma8(r); - g = gamma8(g); - b = gamma8(b); - w = gamma8(w); - } - uint32_t col = RGBW32(r,g,b,w); - if (useMainSegmentOnly) { - strip.getMainSegment().setPixelColor(pix, col); // this expects that strip.getMainSegment().beginDraw() has been called in handleNotification() - } else { - strip.setPixelColor(pix, col); - } - } + strip.setRealtimePixelColor(pix, RGBW32(r,g,b,w)); } /*********************************************************************************************\ @@ -808,7 +791,7 @@ static size_t sequenceNumber = 0; // this needs to be shared across all ou static const size_t ART_NET_HEADER_SIZE = 12; static const byte ART_NET_HEADER[] PROGMEM = {0x41,0x72,0x74,0x2d,0x4e,0x65,0x74,0x00,0x00,0x50,0x00,0x0e}; -uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, const uint8_t* buffer, uint8_t bri, bool isRGBW) { +uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, const uint8_t *buffer, uint8_t bri, bool isRGBW) { if (!(apActive || interfacesInited) || !client[0] || !length) return 1; // network not initialised or dummy/unset IP address 031522 ajn added check for ap WiFiUDP ddpUdp; diff --git a/wled00/util.cpp b/wled00/util.cpp index ac8a1620..8276c9c8 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -4,17 +4,17 @@ //helper to get int value at a position in string -int getNumVal(const String* req, uint16_t pos) +int getNumVal(const String &req, uint16_t pos) { - return req->substring(pos+3).toInt(); + return req.substring(pos+3).toInt(); } //helper to get int value with in/decrementing support via ~ syntax -void parseNumber(const char* str, byte* val, byte minv, byte maxv) +void parseNumber(const char* str, byte &val, byte minv, byte maxv) { if (str == nullptr || str[0] == '\0') return; - if (str[0] == 'r') {*val = hw_random8(minv,maxv?maxv:255); return;} // maxv for random cannot be 0 + if (str[0] == 'r') {val = hw_random8(minv,maxv?maxv:255); return;} // maxv for random cannot be 0 bool wrap = false; if (str[0] == 'w' && strlen(str) > 1) {str++; wrap = true;} if (str[0] == '~') { @@ -22,19 +22,19 @@ void parseNumber(const char* str, byte* val, byte minv, byte maxv) if (out == 0) { if (str[1] == '0') return; if (str[1] == '-') { - *val = (int)(*val -1) < (int)minv ? maxv : min((int)maxv,(*val -1)); //-1, wrap around + val = (int)(val -1) < (int)minv ? maxv : min((int)maxv,(val -1)); //-1, wrap around } else { - *val = (int)(*val +1) > (int)maxv ? minv : max((int)minv,(*val +1)); //+1, wrap around + val = (int)(val +1) > (int)maxv ? minv : max((int)minv,(val +1)); //+1, wrap around } } else { - if (wrap && *val == maxv && out > 0) out = minv; - else if (wrap && *val == minv && out < 0) out = maxv; + if (wrap && val == maxv && out > 0) out = minv; + else if (wrap && val == minv && out < 0) out = maxv; else { - out += *val; + out += val; if (out > maxv) out = maxv; if (out < minv) out = minv; } - *val = out; + val = out; } return; } else if (minv == maxv && minv == 0) { // limits "unset" i.e. both 0 @@ -49,14 +49,14 @@ void parseNumber(const char* str, byte* val, byte minv, byte maxv) } } } - *val = atoi(str); + val = atoi(str); } //getVal supports inc/decrementing and random ("X~Y(r|~[w][-][Z])" form) -bool getVal(JsonVariant elem, byte* val, byte vmin, byte vmax) { +bool getVal(JsonVariant elem, byte &val, byte vmin, byte vmax) { if (elem.is()) { if (elem < 0) return false; //ignore e.g. {"ps":-1} - *val = elem; + val = elem; return true; } else if (elem.is()) { const char* str = elem; @@ -82,7 +82,7 @@ bool getBoolVal(const JsonVariant &elem, bool dflt) { } -bool updateVal(const char* req, const char* key, byte* val, byte minv, byte maxv) +bool updateVal(const char* req, const char* key, byte &val, byte minv, byte maxv) { const char *v = strstr(req, key); if (v) v += strlen(key); @@ -619,6 +619,68 @@ int32_t hw_random(int32_t lowerlimit, int32_t upperlimit) { return hw_random(diff) + lowerlimit; } +#ifndef ESP8266 +void *w_malloc(size_t size) { + int caps1 = MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT; + int caps2 = MALLOC_CAP_DEFAULT | MALLOC_CAP_8BIT; + if (psramSafe) { + if (heap_caps_get_free_size(caps2) > 3*MIN_HEAP_SIZE && size < 512) std::swap(caps1, caps2); // use DRAM for small alloactions & when heap is plenty + return heap_caps_malloc_prefer(size, 2, caps1, caps2); // otherwise prefer PSRAM if it exists + } + return heap_caps_malloc(size, caps2); +} + +void *w_realloc(void *ptr, size_t size) { + int caps1 = MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT; + int caps2 = MALLOC_CAP_DEFAULT | MALLOC_CAP_8BIT; + if (psramSafe) { + if (heap_caps_get_free_size(caps2) > 3*MIN_HEAP_SIZE && size < 512) std::swap(caps1, caps2); // use DRAM for small alloactions & when heap is plenty + return heap_caps_realloc_prefer(ptr, size, 2, caps1, caps2); // otherwise prefer PSRAM if it exists + } + return heap_caps_realloc(ptr, size, caps2); +} + +void *w_calloc(size_t count, size_t size) { + int caps1 = MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT; + int caps2 = MALLOC_CAP_DEFAULT | MALLOC_CAP_8BIT; + if (psramSafe) { + if (heap_caps_get_free_size(caps2) > 3*MIN_HEAP_SIZE && size < 512) std::swap(caps1, caps2); // use DRAM for small alloactions & when heap is plenty + return heap_caps_calloc_prefer(count, size, 2, caps1, caps2); // otherwise prefer PSRAM if it exists + } + return heap_caps_calloc(count, size, caps2); +} + +void *d_malloc(size_t size) { + int caps1 = MALLOC_CAP_DEFAULT | MALLOC_CAP_8BIT; + int caps2 = MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT; + if (psramSafe) { + if (size > MIN_HEAP_SIZE) std::swap(caps1, caps2); // prefer PSRAM for large alloactions + return heap_caps_malloc_prefer(size, 2, caps1, caps2); // otherwise prefer DRAM + } + return heap_caps_malloc(size, caps1); +} + +void *d_realloc(void *ptr, size_t size) { + int caps1 = MALLOC_CAP_DEFAULT | MALLOC_CAP_8BIT; + int caps2 = MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT; + if (psramSafe) { + if (size > MIN_HEAP_SIZE) std::swap(caps1, caps2); // prefer PSRAM for large alloactions + return heap_caps_realloc_prefer(ptr, size, 2, caps1, caps2); // otherwise prefer DRAM + } + return heap_caps_realloc(ptr, size, caps1); +} + +void *d_calloc(size_t count, size_t size) { + int caps1 = MALLOC_CAP_DEFAULT | MALLOC_CAP_8BIT; + int caps2 = MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT; + if (psramSafe) { + if (size > MIN_HEAP_SIZE) std::swap(caps1, caps2); // prefer PSRAM for large alloactions + return heap_caps_calloc_prefer(count, size, 2, caps1, caps2); // otherwise prefer DRAM + } + return heap_caps_calloc(count, size, caps1); +} +#endif + /* * Fixed point integer based Perlin noise functions by @dedehai * Note: optimized for speed and to mimic fastled inoise functions, not for accuracy or best randomness diff --git a/wled00/wled.cpp b/wled00/wled.cpp index cc338d23..e22b94c7 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -529,6 +529,7 @@ void WLED::setup() void WLED::beginStrip() { // Initialize NeoPixel Strip and button + strip.setTransition(0); // temporarily prevent transitions to reduce segment copies strip.finalizeInit(); // busses created during deserializeConfig() if config existed strip.makeAutoSegments(); strip.setBrightness(0); @@ -557,6 +558,8 @@ void WLED::beginStrip() applyPreset(bootPreset, CALL_MODE_INIT); } + strip.setTransition(transitionDelayDefault); // restore transitions + // init relay pin if (rlyPin >= 0) { pinMode(rlyPin, rlyOpenDrain ? OUTPUT_OPEN_DRAIN : OUTPUT); diff --git a/wled00/wled.h b/wled00/wled.h index f8dc1252..230b9cbc 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -602,6 +602,8 @@ WLED_GLOBAL bool wasConnected _INIT(false); // color WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same +WLED_GLOBAL std::vector customPalettes; // custom palettes +WLED_GLOBAL uint8_t paletteBlend _INIT(0); // determines bending and wrapping of palette: 0: blend, wrap if moving (SEGMENT.speed>0); 1: blend, always wrap; 2: blend, never wrap; 3: don't blend or wrap // transitions WLED_GLOBAL uint8_t blendingStyle _INIT(0); // effect blending/transitionig style @@ -612,6 +614,7 @@ WLED_GLOBAL unsigned long transitionStartTime; WLED_GLOBAL bool jsonTransitionOnce _INIT(false); // flag to override transitionDelay (playlist, JSON API: "live" & "seg":{"i"} & "tt") WLED_GLOBAL uint8_t randomPaletteChangeTime _INIT(5); // amount of time [s] between random palette changes (min: 1s, max: 255s) WLED_GLOBAL bool useHarmonicRandomPalette _INIT(true); // use *harmonic* random palette generation (nicer looking) or truly random +WLED_GLOBAL bool useRainbowWheel _INIT(false); // use "rainbow" color wheel instead of "spectrum" color wheel // nightlight WLED_GLOBAL bool nightlightActive _INIT(false); diff --git a/wled00/wled_eeprom.cpp b/wled00/wled_eeprom.cpp index d0451d9a..fb63bc64 100644 --- a/wled00/wled_eeprom.cpp +++ b/wled00/wled_eeprom.cpp @@ -225,7 +225,7 @@ void loadSettingsFromEEPROM() if (lastEEPROMversion > 7) { //strip.paletteFade = EEPROM.read(374); - strip.paletteBlend = EEPROM.read(382); + paletteBlend = EEPROM.read(382); for (int i = 0; i < 8; ++i) { diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 19868d01..ce0662ca 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -291,12 +291,11 @@ void getSettingsJS(byte subPage, Print& settingsScript) printSetFormValue(settingsScript,PSTR("CB"),Bus::getCCTBlend()); printSetFormValue(settingsScript,PSTR("FR"),strip.getTargetFps()); printSetFormValue(settingsScript,PSTR("AW"),Bus::getGlobalAWMode()); - printSetFormCheckbox(settingsScript,PSTR("LD"),useGlobalLedBuffer); printSetFormCheckbox(settingsScript,PSTR("PR"),BusManager::hasParallelOutput()); // get it from bus manager not global variable unsigned sumMa = 0; - for (int s = 0; s < BusManager::getNumBusses(); s++) { - const Bus* bus = BusManager::getBus(s); + for (size_t s = 0; s < BusManager::getNumBusses(); s++) { + const Bus *bus = BusManager::getBus(s); if (!bus || !bus->isOk()) break; // should not happen but for safety int offset = s < 10 ? '0' : 'A'; char lp[4] = "L0"; lp[2] = offset+s; lp[3] = 0; //ascii 0-9 //strip data pin @@ -380,7 +379,8 @@ void getSettingsJS(byte subPage, Print& settingsScript) printSetFormValue(settingsScript,PSTR("TB"),nightlightTargetBri); printSetFormValue(settingsScript,PSTR("TL"),nightlightDelayMinsDefault); printSetFormValue(settingsScript,PSTR("TW"),nightlightMode); - printSetFormIndex(settingsScript,PSTR("PB"),strip.paletteBlend); + printSetFormIndex(settingsScript,PSTR("PB"),paletteBlend); + printSetFormCheckbox(settingsScript,PSTR("RW"),useRainbowWheel); printSetFormValue(settingsScript,PSTR("RL"),rlyPin); printSetFormCheckbox(settingsScript,PSTR("RM"),rlyMde); printSetFormCheckbox(settingsScript,PSTR("RO"),rlyOpenDrain); @@ -666,16 +666,14 @@ void getSettingsJS(byte subPage, Print& settingsScript) #ifndef WLED_DISABLE_2D settingsScript.printf_P(PSTR("maxPanels=%d;resetPanels();"),WLED_MAX_PANELS); if (strip.isMatrix) { - if(strip.panels>0){ - printSetFormValue(settingsScript,PSTR("PW"),strip.panel[0].width); //Set generator Width and Height to first panel size for convenience - printSetFormValue(settingsScript,PSTR("PH"),strip.panel[0].height); - } - printSetFormValue(settingsScript,PSTR("MPC"),strip.panels); + printSetFormValue(settingsScript,PSTR("PW"),strip.panel.size()>0?strip.panel[0].width:8); //Set generator Width and Height to first panel size for convenience + printSetFormValue(settingsScript,PSTR("PH"),strip.panel.size()>0?strip.panel[0].height:8); + printSetFormValue(settingsScript,PSTR("MPC"),strip.panel.size()); // panels - for (unsigned i=0; i Date: Wed, 23 Apr 2025 15:06:31 +0200 Subject: [PATCH 410/463] bugfix in enumerating buttons and busses (#4657) char value was changed from "55" to 'A' which is 65. need to deduct 10 so the result is 'A' if index counter is 10. --- wled00/set.cpp | 6 +++--- wled00/xml.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/wled00/set.cpp b/wled00/set.cpp index c817f255..72587502 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -146,7 +146,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) bool busesChanged = false; for (int s = 0; s < 36; s++) { // theoretical limit is 36 : "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" - int offset = s < 10 ? '0' : 'A'; + int offset = s < 10 ? '0' : 'A' - 10; char lp[4] = "L0"; lp[2] = offset+s; lp[3] = 0; //ascii 0-9 //strip data pin char lc[4] = "LC"; lc[2] = offset+s; lc[3] = 0; //strip length char co[4] = "CO"; co[2] = offset+s; co[3] = 0; //strip color order @@ -220,7 +220,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) // we will not bother with pre-allocating ColorOrderMappings vector BusManager::getColorOrderMap().reset(); for (int s = 0; s < WLED_MAX_COLOR_ORDER_MAPPINGS; s++) { - int offset = s < 10 ? '0' : 'A'; + int offset = s < 10 ? '0' : 'A' - 10; char xs[4] = "XS"; xs[2] = offset+s; xs[3] = 0; //start LED char xc[4] = "XC"; xc[2] = offset+s; xc[3] = 0; //strip length char xo[4] = "XO"; xo[2] = offset+s; xo[3] = 0; //color order @@ -259,7 +259,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) disablePullUp = (bool)request->hasArg(F("IP")); touchThreshold = request->arg(F("TT")).toInt(); for (int i = 0; i < WLED_MAX_BUTTONS; i++) { - int offset = i < 10 ? '0' : 'A'; + int offset = i < 10 ? '0' : 'A' - 10; char bt[4] = "BT"; bt[2] = offset+i; bt[3] = 0; // button pin (use A,B,C,... if WLED_MAX_BUTTONS>10) char be[4] = "BE"; be[2] = offset+i; be[3] = 0; // button type (use A,B,C,... if WLED_MAX_BUTTONS>10) int hw_btn_pin = request->arg(bt).toInt(); diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 19868d01..de2f5590 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -298,7 +298,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) for (int s = 0; s < BusManager::getNumBusses(); s++) { const Bus* bus = BusManager::getBus(s); if (!bus || !bus->isOk()) break; // should not happen but for safety - int offset = s < 10 ? '0' : 'A'; + int offset = s < 10 ? '0' : 'A' - 10; char lp[4] = "L0"; lp[2] = offset+s; lp[3] = 0; //ascii 0-9 //strip data pin char lc[4] = "LC"; lc[2] = offset+s; lc[3] = 0; //strip length char co[4] = "CO"; co[2] = offset+s; co[3] = 0; //strip color order From 0f321bfb383a9aed35a0020e7a710937e833dcf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Wed, 23 Apr 2025 18:38:34 +0200 Subject: [PATCH 411/463] Compilation fixes --- usermods/audioreactive/audio_reactive.cpp | 12 ++++++------ .../usermod_v2_rotary_encoder_ui_ALT.cpp | 16 ++++++++-------- wled00/button.cpp | 6 +++--- wled00/fcn_declare.h | 9 +++------ wled00/image_loader.cpp | 2 +- wled00/json.cpp | 2 +- wled00/wled_server.cpp | 2 +- 7 files changed, 23 insertions(+), 26 deletions(-) diff --git a/usermods/audioreactive/audio_reactive.cpp b/usermods/audioreactive/audio_reactive.cpp index 4b352056..7b0d113f 100644 --- a/usermods/audioreactive/audio_reactive.cpp +++ b/usermods/audioreactive/audio_reactive.cpp @@ -1736,7 +1736,7 @@ class AudioReactive : public Usermod { } void onStateChange(uint8_t callMode) override { - if (initDone && enabled && addPalettes && palettes==0 && strip.customPalettes.size()<10) { + if (initDone && enabled && addPalettes && palettes==0 && customPalettes.size()<10) { // if palettes were removed during JSON call re-add them createAudioPalettes(); } @@ -1966,7 +1966,7 @@ class AudioReactive : public Usermod { void AudioReactive::removeAudioPalettes(void) { DEBUG_PRINTLN(F("Removing audio palettes.")); while (palettes>0) { - strip.customPalettes.pop_back(); + customPalettes.pop_back(); DEBUG_PRINTLN(palettes); palettes--; } @@ -1978,8 +1978,8 @@ void AudioReactive::createAudioPalettes(void) { if (palettes) return; DEBUG_PRINTLN(F("Adding audio palettes.")); for (int i=0; i= palettes) lastCustPalette -= palettes; for (int pal=0; palupdateRedrawTime(); #endif - effectPaletteIndex = max(min((unsigned)(increase ? effectPaletteIndex+1 : effectPaletteIndex-1), strip.getPaletteCount()+strip.customPalettes.size()-1), 0U); + effectPaletteIndex = max(min((unsigned)(increase ? effectPaletteIndex+1 : effectPaletteIndex-1), getPaletteCount()+strip.customPalettes.size()-1), 0U); effectPalette = palettes_alpha_indexes[effectPaletteIndex]; stateChanged = true; if (applyToAll) { diff --git a/wled00/button.cpp b/wled00/button.cpp index cf8fabe4..1c50200a 100644 --- a/wled00/button.cpp +++ b/wled00/button.cpp @@ -74,7 +74,7 @@ void doublePressAction(uint8_t b) if (!macroDoublePress[b]) { switch (b) { //case 0: toggleOnOff(); colorUpdated(CALL_MODE_BUTTON); break; //instant short press on button 0 if no macro set - case 1: ++effectPalette %= strip.getPaletteCount(); colorUpdated(CALL_MODE_BUTTON); break; + case 1: ++effectPalette %= getPaletteCount(); colorUpdated(CALL_MODE_BUTTON); break; } } else { applyPreset(macroDoublePress[b], CALL_MODE_BUTTON_PRESET); @@ -226,8 +226,8 @@ void handleAnalog(uint8_t b) effectIntensity = aRead; } else if (macroDoublePress[b] == 247) { // selected palette - effectPalette = map(aRead, 0, 252, 0, strip.getPaletteCount()-1); - effectPalette = constrain(effectPalette, 0, strip.getPaletteCount()-1); // map is allowed to "overshoot", so we need to contrain the result + effectPalette = map(aRead, 0, 252, 0, getPaletteCount()-1); + effectPalette = constrain(effectPalette, 0, getPaletteCount()-1); // map is allowed to "overshoot", so we need to contrain the result } else if (macroDoublePress[b] == 200) { // primary color, hue, full saturation colorHStoRGB(aRead*256,255,colPri); diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 2846c380..62d05ecd 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -225,9 +225,8 @@ void onHueConnect(void* arg, AsyncClient* client); void sendHuePoll(); void onHueData(void* arg, AsyncClient* client, void *data, size_t len); -#include "FX.h" // must be below colors.cpp declarations (potentially due to duplicate declarations of e.g. color_blend) - //image_loader.cpp +class Segment; #ifdef WLED_ENABLE_GIF bool fileSeekCallback(unsigned long position); unsigned long filePositionCallback(void); @@ -263,9 +262,7 @@ void handleIR(); #include "ESPAsyncWebServer.h" #include "src/dependencies/json/ArduinoJson-v6.h" #include "src/dependencies/json/AsyncJson-v6.h" -#include "FX.h" -bool deserializeSegment(JsonObject elem, byte it, byte presetId = 0); bool deserializeState(JsonObject root, byte callMode = CALL_MODE_DIRECT_CHANGE, byte presetId = 0); void serializeSegment(const JsonObject& root, const Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true); void serializeState(JsonObject root, bool forPreset = false, bool includeBri = true, bool segmentBounds = true, bool selectedSegmentsOnly = false); @@ -279,8 +276,8 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0); //led.cpp void setValuesFromSegment(uint8_t s); -void setValuesFromMainSeg(); -void setValuesFromFirstSelectedSeg(); +#define setValuesFromMainSeg() setValuesFromSegment(strip.getMainSegmentId()) +#define setValuesFromFirstSelectedSeg() setValuesFromSegment(strip.getFirstSelectedSegId()) void toggleOnOff(); void applyBri(); void applyFinalBri(); diff --git a/wled00/image_loader.cpp b/wled00/image_loader.cpp index 96650579..aa4ae2e1 100644 --- a/wled00/image_loader.cpp +++ b/wled00/image_loader.cpp @@ -78,7 +78,7 @@ void drawPixelCallback(int16_t x, int16_t y, uint8_t red, uint8_t green, uint8_t byte renderImageToSegment(Segment &seg) { if (!seg.name) return IMAGE_ERROR_NO_NAME; // disable during effect transition, causes flickering, multiple allocations and depending on image, part of old FX remaining - if (seg.mode != seg.currentMode()) return IMAGE_ERROR_WAITING; + //if (seg.mode != seg.currentMode()) return IMAGE_ERROR_WAITING; if (activeSeg && activeSeg != &seg) return IMAGE_ERROR_SEG_LIMIT; // only one segment at a time activeSeg = &seg; diff --git a/wled00/json.cpp b/wled00/json.cpp index 03f38825..44146810 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -66,7 +66,7 @@ namespace { } } -static bool deserializeSegment(JsonObject elem, byte it, byte presetId) +static bool deserializeSegment(JsonObject elem, byte it, byte presetId = 0) { byte id = elem["id"] | it; if (id >= WS2812FX::getMaxSegments()) return false; diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index 06750838..a41eab83 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -176,7 +176,7 @@ static void handleUpload(AsyncWebServerRequest *request, const String& filename, doReboot = true; request->send(200, FPSTR(CONTENT_TYPE_PLAIN), F("Configuration restore successful.\nRebooting...")); } else { - if (filename.indexOf(F("palette")) >= 0 && filename.indexOf(F(".json")) >= 0) strip.loadCustomPalettes(); + if (filename.indexOf(F("palette")) >= 0 && filename.indexOf(F(".json")) >= 0) loadCustomPalettes(); request->send(200, FPSTR(CONTENT_TYPE_PLAIN), F("File Uploaded!")); } cacheInvalidate++; From 7f2b6a3f10be5f9d8d5a10dd9b902f38b9d96c3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Wed, 23 Apr 2025 18:53:22 +0200 Subject: [PATCH 412/463] More compilation fixes. --- usermods/audioreactive/audio_reactive.cpp | 4 ++-- .../usermod_v2_rotary_encoder_ui_ALT.cpp | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/usermods/audioreactive/audio_reactive.cpp b/usermods/audioreactive/audio_reactive.cpp index 7b0d113f..2587b8be 100644 --- a/usermods/audioreactive/audio_reactive.cpp +++ b/usermods/audioreactive/audio_reactive.cpp @@ -1970,11 +1970,11 @@ void AudioReactive::removeAudioPalettes(void) { DEBUG_PRINTLN(palettes); palettes--; } - DEBUG_PRINT(F("Total # of palettes: ")); DEBUG_PRINTLN(strip.customPalettes.size()); + DEBUG_PRINT(F("Total # of palettes: ")); DEBUG_PRINTLN(customPalettes.size()); } void AudioReactive::createAudioPalettes(void) { - DEBUG_PRINT(F("Total # of palettes: ")); DEBUG_PRINTLN(strip.customPalettes.size()); + DEBUG_PRINT(F("Total # of palettes: ")); DEBUG_PRINTLN(customPalettes.size()); if (palettes) return; DEBUG_PRINTLN(F("Adding audio palettes.")); for (int i=0; iupdateRedrawTime(); #endif - effectPaletteIndex = max(min((unsigned)(increase ? effectPaletteIndex+1 : effectPaletteIndex-1), getPaletteCount()+strip.customPalettes.size()-1), 0U); + effectPaletteIndex = max(min((unsigned)(increase ? effectPaletteIndex+1 : effectPaletteIndex-1), getPaletteCount()+customPalettes.size()-1), 0U); effectPalette = palettes_alpha_indexes[effectPaletteIndex]; stateChanged = true; if (applyToAll) { From f1d52a8ec1e023aea92824cdc829cb99e61e2079 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Apr 2025 16:33:57 +0000 Subject: [PATCH 413/463] Bump h11 from 0.14.0 to 0.16.0 Bumps [h11](https://github.com/python-hyper/h11) from 0.14.0 to 0.16.0. - [Commits](https://github.com/python-hyper/h11/compare/v0.14.0...v0.16.0) --- updated-dependencies: - dependency-name: h11 dependency-version: 0.16.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 1737408a..4d767b05 100644 --- a/requirements.txt +++ b/requirements.txt @@ -20,7 +20,7 @@ click==8.1.8 # uvicorn colorama==0.4.6 # via platformio -h11==0.14.0 +h11==0.16.0 # via # uvicorn # wsproto From c934776f45b0b6f3372ea01188deaa38393d1822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sat, 26 Apr 2025 20:08:15 +0200 Subject: [PATCH 414/463] Address issues reported --- wled00/FX.h | 7 ++++--- wled00/FX_2Dfcn.cpp | 11 ++++++----- wled00/FX_fcn.cpp | 25 ++++++++++++++++--------- wled00/bus_manager.cpp | 26 ++++++++++++++------------ wled00/const.h | 5 +++++ wled00/fcn_declare.h | 29 ++++++++++++++++------------- wled00/file.cpp | 4 ++-- wled00/mqtt.cpp | 10 +++++----- wled00/pin_manager.cpp | 2 +- wled00/pin_manager.h | 5 ----- wled00/presets.cpp | 18 +++++++++--------- wled00/util.cpp | 6 +++--- wled00/wled.cpp | 2 ++ wled00/wled.h | 3 +++ 14 files changed, 86 insertions(+), 67 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index c060c868..9c895c0c 100755 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -833,8 +833,8 @@ class WS2812FX { _length(DEFAULT_LED_COUNT), _transitionDur(750), _frametime(FRAMETIME_FIXED), + _cumulativeFps(WLED_FPS << FPS_CALC_SHIFT), _targetFps(WLED_FPS), - _cumulativeFps(WLED_FPS), _isServicing(false), _isOffRefreshRequired(false), _hasWhiteChannel(false), @@ -845,7 +845,8 @@ class WS2812FX { _callback(nullptr), customMappingTable(nullptr), customMappingSize(0), - _lastShow(0) + _lastShow(0), + _lastServiceShow(0) { _mode.reserve(_modeCount); // allocate memory to prevent initial fragmentation (does not increase size()) _modeData.reserve(_modeCount); // allocate memory to prevent initial fragmentation (does not increase size()) @@ -1011,8 +1012,8 @@ class WS2812FX { uint16_t _transitionDur; uint16_t _frametime; + uint16_t _cumulativeFps; uint8_t _targetFps; - uint8_t _cumulativeFps; // will require only 1 byte struct { diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 69c74318..9a3c6fbe 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -86,7 +86,7 @@ void WS2812FX::setUpMatrix() { JsonArray map = pDoc->as(); gapSize = map.size(); if (!map.isNull() && gapSize >= matrixSize) { // not an empty map - gapTable = static_cast(w_malloc(gapSize)); + gapTable = static_cast(p_malloc(gapSize)); if (gapTable) for (size_t i = 0; i < gapSize; i++) { gapTable[i] = constrain(map[i], -1, 1); } @@ -113,7 +113,7 @@ void WS2812FX::setUpMatrix() { } // delete gap array as we no longer need it - w_free(gapTable); + p_free(gapTable); resume(); #ifdef WLED_DEBUG @@ -246,11 +246,11 @@ void Segment::blur2D(uint8_t blur_x, uint8_t blur_y, bool smear) const { const unsigned cols = vWidth(); const unsigned rows = vHeight(); const auto XY = [&](unsigned x, unsigned y){ return x + y*cols; }; - uint32_t lastnew; + uint32_t lastnew; // not necessary to initialize lastnew and last, as both will be initialized by the first loop iteration uint32_t last; if (blur_x) { const uint8_t keepx = smear ? 255 : 255 - blur_x; - const uint8_t seepx = blur_x >> (1 + smear); + const uint8_t seepx = blur_x >> 1; for (unsigned row = 0; row < rows; row++) { // blur rows (x direction) uint32_t carryover = BLACK; uint32_t curnew = BLACK; @@ -273,7 +273,7 @@ void Segment::blur2D(uint8_t blur_x, uint8_t blur_y, bool smear) const { } if (blur_y) { const uint8_t keepy = smear ? 255 : 255 - blur_y; - const uint8_t seepy = blur_y >> (1 + smear); + const uint8_t seepy = blur_y >> 1; for (unsigned col = 0; col < cols; col++) { uint32_t carryover = BLACK; uint32_t curnew = BLACK; @@ -584,6 +584,7 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, chr -= 32; // align with font table entries const int font = w*h; + // if col2 == BLACK then use currently selected palette for gradient otherwise create gradient from color and col2 CRGBPalette16 grad = col2 ? CRGBPalette16(CRGB(color), CRGB(col2)) : SEGPALETTE; // selected palette as gradient for (int i = 0; i> (1 + smear); + uint8_t seep = blur_amount >> 1; unsigned vlength = vLength(); uint32_t carryover = BLACK; - uint32_t lastnew; + uint32_t lastnew; // not necessary to initialize lastnew and last, as both will be initialized by the first loop iteration uint32_t last; uint32_t curnew = BLACK; for (unsigned i = 0; i < vlength; i++) { @@ -1198,7 +1198,12 @@ void WS2812FX::finalizeInit() { void WS2812FX::service() { unsigned long nowUp = millis(); // Be aware, millis() rolls over every 49 days now = nowUp + timebase; - if (nowUp - _lastShow < MIN_FRAME_DELAY || _suspend) return; + unsigned long elapsed = nowUp - _lastServiceShow; + if (_suspend || elapsed <= MIN_FRAME_DELAY) return; // keep wifi alive - no matter if triggered or unlimited + if (!_triggered && (_targetFps != FPS_UNLIMITED)) { // unlimited mode = no frametime + if (elapsed < _frametime) return; // too early for service + } + bool doShow = false; _isServicing = true; @@ -1255,15 +1260,16 @@ void WS2812FX::service() { } #ifdef WLED_DEBUG - if (millis() - nowUp > _frametime) DEBUG_PRINTF_P(PSTR("Slow effects %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime); + if ((_targetFps != FPS_UNLIMITED) && (millis() - nowUp > _frametime)) DEBUG_PRINTF_P(PSTR("Slow effects %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime); #endif if (doShow && !_suspend) { yield(); Segment::handleRandomPalette(); // slowly transition random palette; move it into for loop when each segment has individual random palette + _lastServiceShow = nowUp; // update timestamp, for precise FPS control show(); } #ifdef WLED_DEBUG - if (millis() - nowUp > _frametime) DEBUG_PRINTF_P(PSTR("Slow strip %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime); + if ((_targetFps != FPS_UNLIMITED) && (millis() - nowUp > _frametime)) DEBUG_PRINTF_P(PSTR("Slow strip %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime); #endif _triggered = false; @@ -1612,8 +1618,8 @@ void WS2812FX::show() { if (newBri != _brightness) BusManager::setBrightness(_brightness); if (diff > 0) { // skip calculation if no time has passed - int fpsCurr = (1000 << FPS_CALC_SHIFT) / diff; // fixed point math (shift left for better precision) - _cumulativeFps += ((fpsCurr - (_cumulativeFps << FPS_CALC_SHIFT)) / FPS_CALC_AVG + ((1<> FPS_CALC_SHIFT; // simple PI controller over FPS_CALC_AVG frames + size_t fpsCurr = (1000 << FPS_CALC_SHIFT) / diff; // fixed point math + _cumulativeFps = (FPS_CALC_AVG * _cumulativeFps + fpsCurr + FPS_CALC_AVG / 2) / (FPS_CALC_AVG + 1); // "+FPS_CALC_AVG/2" for proper rounding _lastShow = showNow; } } @@ -1653,8 +1659,9 @@ void WS2812FX::waitForIt() { }; void WS2812FX::setTargetFps(unsigned fps) { - if (fps > 0 && fps <= 120) _targetFps = fps; - _frametime = 1000 / _targetFps; + if (fps <= 250) _targetFps = fps; + if (_targetFps > 0) _frametime = 1000 / _targetFps; + else _frametime = MIN_FRAME_DELAY; // unlimited mode } void WS2812FX::setCCT(uint16_t k) { diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 59d6f543..56e59479 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -37,19 +37,21 @@ uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, const //util.cpp // PSRAM allocation wrappers #ifndef ESP8266 -void *w_malloc(size_t); // prefer PSRAM over DRAM -void *w_calloc(size_t, size_t); // prefer PSRAM over DRAM -void *w_realloc(void *, size_t); // prefer PSRAM over DRAM -inline void w_free(void *ptr) { heap_caps_free(ptr); } -void *d_malloc(size_t); // prefer DRAM over PSRAM -void *d_calloc(size_t, size_t); // prefer DRAM over PSRAM -void *d_realloc(void *, size_t); // prefer DRAM over PSRAM -inline void d_free(void *ptr) { heap_caps_free(ptr); } +extern "C" { + void *p_malloc(size_t); // prefer PSRAM over DRAM + void *p_calloc(size_t, size_t); // prefer PSRAM over DRAM + void *p_realloc(void *, size_t); // prefer PSRAM over DRAM + inline void p_free(void *ptr) { heap_caps_free(ptr); } + void *d_malloc(size_t); // prefer DRAM over PSRAM + void *d_calloc(size_t, size_t); // prefer DRAM over PSRAM + void *d_realloc(void *, size_t); // prefer DRAM over PSRAM + inline void d_free(void *ptr) { heap_caps_free(ptr); } +} #else -#define w_malloc malloc -#define w_calloc calloc -#define w_realloc realloc -#define w_free free +#define p_malloc malloc +#define p_calloc calloc +#define p_realloc realloc +#define p_free free #define d_malloc malloc #define d_calloc calloc #define d_realloc realloc diff --git a/wled00/const.h b/wled00/const.h index 877e02dc..cfcd0a6b 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -1,3 +1,4 @@ +#pragma once #ifndef WLED_CONST_H #define WLED_CONST_H @@ -49,6 +50,9 @@ #define WLED_MAX_ANALOG_CHANNELS 5 #define WLED_MIN_VIRTUAL_BUSSES 3 // no longer used for bus creation but used to distinguish S2/S3 in UI #else + #if !defined(LEDC_CHANNEL_MAX) || !defined(LEDC_SPEED_MODE_MAX) + #include "driver/ledc.h" // needed for analog/LEDC channel counts + #endif #define WLED_MAX_ANALOG_CHANNELS (LEDC_CHANNEL_MAX*LEDC_SPEED_MODE_MAX) #if defined(CONFIG_IDF_TARGET_ESP32C3) // 2 RMT, 6 LEDC, only has 1 I2S but NPB does not support it ATM #define WLED_MAX_DIGITAL_CHANNELS 2 @@ -76,6 +80,7 @@ #undef WLED_MAX_BUSSES #endif #define WLED_MAX_BUSSES (WLED_MAX_DIGITAL_CHANNELS+WLED_MAX_ANALOG_CHANNELS) +static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit"); // Maximum number of pins per output. 5 for RGBCCT analog LEDs. #define OUTPUT_MAX_PINS 5 diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 62d05ecd..486e5c56 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -173,7 +173,8 @@ inline uint32_t color_blend16(uint32_t c1, uint32_t c2, uint16_t b) { return col CRGBPalette16 generateHarmonicRandomPalette(const CRGBPalette16 &basepalette); CRGBPalette16 generateRandomPalette(); void loadCustomPalettes(); -#define getPaletteCount() (13 + GRADIENT_PALETTE_COUNT + customPalettes.size()) +extern std::vector customPalettes; +inline size_t getPaletteCount() { return 13 + GRADIENT_PALETTE_COUNT + customPalettes.size(); } inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); } void hsv2rgb(const CHSV32& hsv, uint32_t& rgb); void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); @@ -545,19 +546,21 @@ inline uint8_t hw_random8(uint32_t lowerlimit, uint32_t upperlimit) { uint32_t r // PSRAM allocation wrappers #ifndef ESP8266 -void *w_malloc(size_t); // prefer PSRAM over DRAM -void *w_calloc(size_t, size_t); // prefer PSRAM over DRAM -void *w_realloc(void *, size_t); // prefer PSRAM over DRAM -inline void w_free(void *ptr) { heap_caps_free(ptr); } -void *d_malloc(size_t); // prefer DRAM over PSRAM -void *d_calloc(size_t, size_t); // prefer DRAM over PSRAM -void *d_realloc(void *, size_t); // prefer DRAM over PSRAM -inline void d_free(void *ptr) { heap_caps_free(ptr); } +extern "C" { + void *p_malloc(size_t); // prefer PSRAM over DRAM + void *p_calloc(size_t, size_t); // prefer PSRAM over DRAM + void *p_realloc(void *, size_t); // prefer PSRAM over DRAM + inline void p_free(void *ptr) { heap_caps_free(ptr); } + void *d_malloc(size_t); // prefer DRAM over PSRAM + void *d_calloc(size_t, size_t); // prefer DRAM over PSRAM + void *d_realloc(void *, size_t); // prefer DRAM over PSRAM + inline void d_free(void *ptr) { heap_caps_free(ptr); } +} #else -#define w_malloc malloc -#define w_calloc calloc -#define w_realloc realloc -#define w_free free +#define p_malloc malloc +#define p_calloc calloc +#define p_realloc realloc +#define p_free free #define d_malloc malloc #define d_calloc calloc #define d_realloc realloc diff --git a/wled00/file.cpp b/wled00/file.cpp index 4df33199..c1960e61 100644 --- a/wled00/file.cpp +++ b/wled00/file.cpp @@ -392,7 +392,7 @@ static const uint8_t *getPresetCache(size_t &size) { if ((presetsModifiedTime != presetsCachedTime) || (presetsCachedValidate != cacheInvalidate)) { if (presetsCached) { - w_free(presetsCached); + p_free(presetsCached); presetsCached = nullptr; } } @@ -403,7 +403,7 @@ static const uint8_t *getPresetCache(size_t &size) { presetsCachedTime = presetsModifiedTime; presetsCachedValidate = cacheInvalidate; presetsCachedSize = 0; - presetsCached = (uint8_t*)w_malloc(file.size() + 1); + presetsCached = (uint8_t*)p_malloc(file.size() + 1); if (presetsCached) { presetsCachedSize = file.size(); file.read(presetsCached, presetsCachedSize); diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp index a1f65951..19d4e889 100644 --- a/wled00/mqtt.cpp +++ b/wled00/mqtt.cpp @@ -68,8 +68,8 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp } if (index == 0) { // start (1st partial packet or the only packet) - w_free(payloadStr); // release buffer if it exists - payloadStr = static_cast(w_malloc(total+1)); // allocate new buffer + p_free(payloadStr); // release buffer if it exists + payloadStr = static_cast(p_malloc(total+1)); // allocate new buffer } if (payloadStr == nullptr) return; // buffer not allocated @@ -94,7 +94,7 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp } else { // Non-Wled Topic used here. Probably a usermod subscribed to this topic. UsermodManager::onMqttMessage(topic, payloadStr); - w_free(payloadStr); + p_free(payloadStr); payloadStr = nullptr; return; } @@ -124,7 +124,7 @@ static void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProp // topmost topic (just wled/MAC) parseMQTTBriPayload(payloadStr); } - w_free(payloadStr); + p_free(payloadStr); payloadStr = nullptr; } @@ -196,7 +196,7 @@ bool initMqtt() if (!mqttEnabled || mqttServer[0] == 0 || !WLED_CONNECTED) return false; if (mqtt == nullptr) { - void *ptr = w_malloc(sizeof(AsyncMqttClient)); + void *ptr = p_malloc(sizeof(AsyncMqttClient)); mqtt = new (ptr) AsyncMqttClient(); // use placement new (into PSRAM), client will never be deleted if (!mqtt) return false; mqtt->onMessage(onMqttMessage); diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index 6f165230..cdbb8526 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -1,5 +1,5 @@ -#include "pin_manager.h" #include "wled.h" +#include "pin_manager.h" #ifdef ARDUINO_ARCH_ESP32 #ifdef bitRead diff --git a/wled00/pin_manager.h b/wled00/pin_manager.h index b285b6ee..662e499b 100644 --- a/wled00/pin_manager.h +++ b/wled00/pin_manager.h @@ -3,11 +3,6 @@ /* * Registers pins so there is no attempt for two interfaces to use the same pin */ -#include -#ifdef ARDUINO_ARCH_ESP32 -#include "driver/ledc.h" // needed for analog/LEDC channel counts -#endif -#include "const.h" // for USERMOD_* values #ifdef ESP8266 #define WLED_NUM_PINS (GPIO_PIN_COUNT+1) // somehow they forgot GPIO 16 (0-16==17) diff --git a/wled00/presets.cpp b/wled00/presets.cpp index 0a4380f8..fed2c1ed 100644 --- a/wled00/presets.cpp +++ b/wled00/presets.cpp @@ -57,10 +57,10 @@ static void doSaveState() { */ #if defined(ARDUINO_ARCH_ESP32) if (!persist) { - w_free(tmpRAMbuffer); + p_free(tmpRAMbuffer); size_t len = measureJson(*pDoc) + 1; // if possible use SPI RAM on ESP32 - tmpRAMbuffer = (char*)w_malloc(len); + tmpRAMbuffer = (char*)p_malloc(len); if (tmpRAMbuffer!=nullptr) { serializeJson(*pDoc, tmpRAMbuffer, len); } else { @@ -77,8 +77,8 @@ static void doSaveState() { // clean up saveLedmap = -1; presetToSave = 0; - w_free(saveName); - w_free(quickLoad); + p_free(saveName); + p_free(quickLoad); saveName = nullptr; quickLoad = nullptr; playlistSave = false; @@ -203,7 +203,7 @@ void handlePresets() #if defined(ARDUINO_ARCH_ESP32) //Aircoookie recommended not to delete buffer if (tmpPreset==255 && tmpRAMbuffer!=nullptr) { - w_free(tmpRAMbuffer); + p_free(tmpRAMbuffer); tmpRAMbuffer = nullptr; } #endif @@ -217,8 +217,8 @@ void handlePresets() //called from handleSet(PS=) [network callback (sObj is empty), IR (irrational), deserializeState, UDP] and deserializeState() [network callback (filedoc!=nullptr)] void savePreset(byte index, const char* pname, JsonObject sObj) { - if (!saveName) saveName = static_cast(w_malloc(33)); - if (!quickLoad) quickLoad = static_cast(w_malloc(9)); + if (!saveName) saveName = static_cast(p_malloc(33)); + if (!quickLoad) quickLoad = static_cast(p_malloc(9)); if (!saveName || !quickLoad) return; if (index == 0 || (index > 250 && index < 255)) return; @@ -264,8 +264,8 @@ void savePreset(byte index, const char* pname, JsonObject sObj) presetsModifiedTime = toki.second(); //unix time updateFSInfo(); } - w_free(saveName); - w_free(quickLoad); + p_free(saveName); + p_free(quickLoad); saveName = nullptr; quickLoad = nullptr; } else { diff --git a/wled00/util.cpp b/wled00/util.cpp index 8276c9c8..97e1e3b0 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -620,7 +620,7 @@ int32_t hw_random(int32_t lowerlimit, int32_t upperlimit) { } #ifndef ESP8266 -void *w_malloc(size_t size) { +void *p_malloc(size_t size) { int caps1 = MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT; int caps2 = MALLOC_CAP_DEFAULT | MALLOC_CAP_8BIT; if (psramSafe) { @@ -630,7 +630,7 @@ void *w_malloc(size_t size) { return heap_caps_malloc(size, caps2); } -void *w_realloc(void *ptr, size_t size) { +void *p_realloc(void *ptr, size_t size) { int caps1 = MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT; int caps2 = MALLOC_CAP_DEFAULT | MALLOC_CAP_8BIT; if (psramSafe) { @@ -640,7 +640,7 @@ void *w_realloc(void *ptr, size_t size) { return heap_caps_realloc(ptr, size, caps2); } -void *w_calloc(size_t count, size_t size) { +void *p_calloc(size_t count, size_t size) { int caps1 = MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT; int caps2 = MALLOC_CAP_DEFAULT | MALLOC_CAP_8BIT; if (psramSafe) { diff --git a/wled00/wled.cpp b/wled00/wled.cpp index e22b94c7..111fc12e 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -753,7 +753,9 @@ void WLED::handleConnection() static bool scanDone = true; static byte stacO = 0; const unsigned long now = millis(); + #ifdef WLED_DEBUG const unsigned long nowS = now/1000; + #endif const bool wifiConfigured = WLED_WIFI_CONFIGURED; // ignore connection handling if WiFi is configured and scan still running diff --git a/wled00/wled.h b/wled00/wled.h index 230b9cbc..efcbacc1 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -64,6 +64,9 @@ //This is generally a terrible idea, but improves boot success on boards with a 3.3v regulator + cap setup that can't provide 400mA peaks //#define WLED_DISABLE_BROWNOUT_DET +#include +#include + // Library inclusions. #include #ifdef ESP8266 From 125a21da75365883020a58ceba1857abf1ecce5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Sat, 26 Apr 2025 20:15:02 +0200 Subject: [PATCH 415/463] Comment --- wled00/wled.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/wled.h b/wled00/wled.h index efcbacc1..600ed010 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -606,7 +606,7 @@ WLED_GLOBAL bool wasConnected _INIT(false); // color WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same WLED_GLOBAL std::vector customPalettes; // custom palettes -WLED_GLOBAL uint8_t paletteBlend _INIT(0); // determines bending and wrapping of palette: 0: blend, wrap if moving (SEGMENT.speed>0); 1: blend, always wrap; 2: blend, never wrap; 3: don't blend or wrap +WLED_GLOBAL uint8_t paletteBlend _INIT(0); // determines blending and wrapping of palette: 0: blend, wrap if moving (SEGMENT.speed>0); 1: blend, always wrap; 2: blend, never wrap; 3: don't blend or wrap // transitions WLED_GLOBAL uint8_t blendingStyle _INIT(0); // effect blending/transitionig style From f721efca1e6f57b2b9cfcee022fa9fd4e907341d Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 28 Apr 2025 21:12:27 +0200 Subject: [PATCH 416/463] fixed wrong gravity setting, added option for no trail (#4665) --- wled00/FX.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 3daf2c0f..b3d3eeae 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -9308,7 +9308,7 @@ uint16_t mode_particleFireworks1D(void) { uint8_t *forcecounter; if (SEGMENT.call == 0) { // initialization - if (!initParticleSystem1D(PartSys, 4, 150, 4, true)) // init + if (!initParticleSystem1D(PartSys, 4, 150, 4, true)) // init advanced particle system return mode_static(); // allocation failed or is single pixel PartSys->setKillOutOfBounds(true); PartSys->sources[0].sourceFlags.custom1 = 1; // set rocket state to standby @@ -9324,11 +9324,8 @@ uint16_t mode_particleFireworks1D(void) { PartSys->setParticleSize(SEGMENT.check3); // 1 or 2 pixel rendering PartSys->setMotionBlur(SEGMENT.custom2); // anable motion blur - int32_t gravity = (1 + (SEGMENT.speed >> 3)); - if (!SEGMENT.check1) // gravity enabled for sparks - PartSys->setGravity(0); // disable - else - PartSys->setGravity(gravity); // set gravity + int32_t gravity = (1 + (SEGMENT.speed >> 3)); // gravity value used for rocket speed calculation + PartSys->setGravity(SEGMENT.speed ? gravity : 0); // set gravity if (PartSys->sources[0].sourceFlags.custom1 == 1) { // rocket is on standby PartSys->sources[0].source.ttl--; @@ -9343,8 +9340,8 @@ uint16_t mode_particleFireworks1D(void) { PartSys->sources[0].source.hue = hw_random16(); PartSys->sources[0].var = 10; // emit variation PartSys->sources[0].v = -10; // emit speed - PartSys->sources[0].minLife = 100; - PartSys->sources[0].maxLife = 300; + PartSys->sources[0].minLife = 30; + PartSys->sources[0].maxLife = SEGMENT.check2 ? 400 : 40; PartSys->sources[0].source.x = 0; // start from bottom uint32_t speed = sqrt((gravity * ((PartSys->maxX >> 2) + hw_random16(PartSys->maxX >> 1))) >> 4); // set speed such that rocket explods in frame PartSys->sources[0].source.vx = min(speed, (uint32_t)127); @@ -9383,11 +9380,11 @@ uint16_t mode_particleFireworks1D(void) { PartSys->sources[0].maxLife = 1300; PartSys->sources[0].source.ttl = 100 + hw_random16(64 - (SEGMENT.speed >> 2)); // standby time til next launch PartSys->sources[0].sat = 7 + (SEGMENT.custom3 << 3); //color saturation TODO: replace saturation with something more useful? - PartSys->sources[0].size = hw_random16(64); // random particle size in explosion + PartSys->sources[0].size = hw_random16(SEGMENT.intensity); // random particle size in explosion uint32_t explosionsize = 8 + (PartSys->maxXpixel >> 2) + (PartSys->sources[0].source.x >> (PS_P_RADIUS_SHIFT_1D - 1)); explosionsize += hw_random16((explosionsize * SEGMENT.intensity) >> 8); for (uint32_t e = 0; e < explosionsize; e++) { // emit explosion particles - if (SEGMENT.check2) + if (SEGMENT.check1) // colorful mode PartSys->sources[0].source.hue = hw_random16(); //random color for each particle PartSys->sprayEmit(PartSys->sources[0]); // emit a particle } @@ -9407,7 +9404,7 @@ uint16_t mode_particleFireworks1D(void) { return FRAMETIME; } -static const char _data_FX_MODE_PS_FIREWORKS1D[] PROGMEM = "PS Fireworks 1D@Gravity,Explosion,Firing side,Blur,Saturation,,Colorful,Smooth;,!;!;1;sx=150,c2=30,c3=31,o2=1"; +static const char _data_FX_MODE_PS_FIREWORKS1D[] PROGMEM = "PS Fireworks 1D@Gravity,Explosion,Firing side,Blur,Saturation,Colorful,Trail,Smooth;,!;!;1;sx=150,c2=30,c3=31,o1=1,o2=1"; /* Particle based Sparkle effect From 7998650e608c6f31dad692b3c267de5e488f32a4 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Fri, 28 Mar 2025 20:12:30 -0400 Subject: [PATCH 417/463] Fix up usermod libArchive settings The ConfigureProjectLibBuilder process will flush and reload the library settings from the on-disk manifests if any new library is installed at that stage. This has the side effect of reverting the libArchive setting applied to usermods which was performed prior to that call. Apply the setting afterwards, instead. Fixes #4597 --- pio-scripts/load_usermods.py | 39 ++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/pio-scripts/load_usermods.py b/pio-scripts/load_usermods.py index ab3c6476..27a4590d 100644 --- a/pio-scripts/load_usermods.py +++ b/pio-scripts/load_usermods.py @@ -2,16 +2,19 @@ Import('env') import os.path from collections import deque from pathlib import Path # For OS-agnostic path manipulation +from platformio.builder.tools.piolib import LibBuilderBase from platformio.package.manager.library import LibraryPackageManager usermod_dir = Path(env["PROJECT_DIR"]) / "usermods" -all_usermods = [f for f in usermod_dir.iterdir() if f.is_dir() and f.joinpath('library.json').exists()] +# "usermods" environment: expand list of usermods to everything in the folder if env['PIOENV'] == "usermods": # Add all usermods + all_usermods = [f for f in usermod_dir.iterdir() if f.is_dir() and f.joinpath('library.json').exists()] env.GetProjectConfig().set(f"env:usermods", 'custom_usermods', " ".join([f.name for f in all_usermods])) -def find_usermod(mod: str): +# Utility functions +def find_usermod(mod: str) -> Path: """Locate this library in the usermods folder. We do this to avoid needing to rename a bunch of folders; this could be removed later @@ -28,6 +31,13 @@ def find_usermod(mod: str): return mp raise RuntimeError(f"Couldn't locate module {mod} in usermods directory!") +def is_wled_module(dep: LibBuilderBase) -> bool: + """Returns true if the specified library is a wled module + """ + return usermod_dir in Path(dep.src_dir).parents or str(dep.name).startswith("wled-") + +## Script starts here +# Process usermod option usermods = env.GetProjectOption("custom_usermods","") if usermods: # Inject usermods in to project lib_deps @@ -82,13 +92,6 @@ old_ConfigureProjectLibBuilder = env.ConfigureProjectLibBuilder # Our new wrapper def wrapped_ConfigureProjectLibBuilder(xenv): - # Update usermod properties - # Set libArchive before build actions are added - for um in (um for um in xenv.GetLibBuilders() if usermod_dir in Path(um.src_dir).parents): - build = um._manifest.get("build", {}) - build["libArchive"] = False - um._manifest["build"] = build - # Call the wrapped function result = old_ConfigureProjectLibBuilder.clone(xenv)() @@ -102,12 +105,18 @@ def wrapped_ConfigureProjectLibBuilder(xenv): for dep in result.depbuilders: cached_add_includes(dep, processed_deps, extra_include_dirs) - for um in [dep for dep in result.depbuilders if usermod_dir in Path(dep.src_dir).parents]: - # Add the wled folder to the include path - um.env.PrependUnique(CPPPATH=wled_dir) - # Add WLED's own dependencies - for dir in extra_include_dirs: - um.env.PrependUnique(CPPPATH=dir) + for dep in result.depbuilders: + if is_wled_module(dep): + # Add the wled folder to the include path + dep.env.PrependUnique(CPPPATH=wled_dir) + # Add WLED's own dependencies + for dir in extra_include_dirs: + dep.env.PrependUnique(CPPPATH=dir) + # Enforce that libArchive is not set; we must link them directly to the executable + if dep.lib_archive: + build = dep._manifest.get("build", {}) + build["libArchive"] = False + dep._manifest["build"] = build return result From 6464c620c701bf3ad8297ab81572f23c45404353 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Wed, 30 Apr 2025 21:56:56 -0400 Subject: [PATCH 418/463] load_usermods: Enforce CPPPATH type Ensure that entries put in CPPPATH are always strings so SCons can correctlly deduplicate. --- pio-scripts/load_usermods.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pio-scripts/load_usermods.py b/pio-scripts/load_usermods.py index 27a4590d..eeebcbf2 100644 --- a/pio-scripts/load_usermods.py +++ b/pio-scripts/load_usermods.py @@ -108,10 +108,10 @@ def wrapped_ConfigureProjectLibBuilder(xenv): for dep in result.depbuilders: if is_wled_module(dep): # Add the wled folder to the include path - dep.env.PrependUnique(CPPPATH=wled_dir) + dep.env.PrependUnique(CPPPATH=str(wled_dir)) # Add WLED's own dependencies for dir in extra_include_dirs: - dep.env.PrependUnique(CPPPATH=dir) + dep.env.PrependUnique(CPPPATH=str(dir)) # Enforce that libArchive is not set; we must link them directly to the executable if dep.lib_archive: build = dep._manifest.get("build", {}) From d9b086cbe9798003bc7db51f01f24cf1b7ef2f0f Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 1 May 2025 13:39:23 +0200 Subject: [PATCH 419/463] Bugfixes in PS, improvements to PS Fireworks 1D (#4673) - fixed inconsitencies in size rendering - fixed palette being wrapped in color by position and color by age modes - Fixed bug in memory layout: for some unknown reason, if flags come before particles, last flag is sometimes overwritten, changing memory laout seems to fix that - New color modes in PS Fireworks 1D: - custom3 slider < 16: lower saturation (check1: single color or multi-color explosions) - custom3 slider <= 23: full saturation (check1: single color or multi-color explosions) - custom3 slider > 23: color by speed (check 1 has not effect here) - custom slider = max: color by age or color by position (depends on check1) --- wled00/FX.cpp | 49 ++++++++++++++++++------------- wled00/FXparticleSystem.cpp | 58 +++++++++++++++++++++++-------------- wled00/FXparticleSystem.h | 12 ++++---- 3 files changed, 72 insertions(+), 47 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index b3d3eeae..1a756018 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -8127,7 +8127,7 @@ uint16_t mode_particlepit(void) { PartSys->particles[i].sat = ((SEGMENT.custom3) << 3) + 7; // set particle size if (SEGMENT.custom1 == 255) { - PartSys->setParticleSize(1); // set global size to 1 for advanced rendering + PartSys->setParticleSize(1); // set global size to 1 for advanced rendering (no single pixel particles) PartSys->advPartProps[i].size = hw_random16(SEGMENT.custom1); // set each particle to random size } else { PartSys->setParticleSize(SEGMENT.custom1); // set global size @@ -9085,7 +9085,6 @@ uint16_t mode_particlePinball(void) { PartSys->sources[0].sourceFlags.collide = true; // seeded particles will collide (if enabled) PartSys->sources[0].source.x = PS_P_RADIUS_1D; //emit at bottom PartSys->setKillOutOfBounds(true); // out of bounds particles dont return - PartSys->setUsedParticles(255); // use all available particles for init SEGENV.aux0 = 1; SEGENV.aux1 = 5000; //set out of range to ensure uptate on first call } @@ -9308,6 +9307,7 @@ uint16_t mode_particleFireworks1D(void) { uint8_t *forcecounter; if (SEGMENT.call == 0) { // initialization + if (!initParticleSystem1D(PartSys, 4, 150, 4, true)) // init advanced particle system if (!initParticleSystem1D(PartSys, 4, 150, 4, true)) // init advanced particle system return mode_static(); // allocation failed or is single pixel PartSys->setKillOutOfBounds(true); @@ -9321,9 +9321,7 @@ uint16_t mode_particleFireworks1D(void) { // Particle System settings PartSys->updateSystem(); // update system properties (dimensions and data pointers) forcecounter = PartSys->PSdataEnd; - PartSys->setParticleSize(SEGMENT.check3); // 1 or 2 pixel rendering PartSys->setMotionBlur(SEGMENT.custom2); // anable motion blur - int32_t gravity = (1 + (SEGMENT.speed >> 3)); // gravity value used for rocket speed calculation PartSys->setGravity(SEGMENT.speed ? gravity : 0); // set gravity @@ -9337,17 +9335,17 @@ uint16_t mode_particleFireworks1D(void) { SEGENV.aux0 = 0; PartSys->sources[0].sourceFlags.custom1 = 0; //flag used for rocket state - PartSys->sources[0].source.hue = hw_random16(); + PartSys->sources[0].source.hue = hw_random16(); // different color for each launch PartSys->sources[0].var = 10; // emit variation PartSys->sources[0].v = -10; // emit speed PartSys->sources[0].minLife = 30; - PartSys->sources[0].maxLife = SEGMENT.check2 ? 400 : 40; + PartSys->sources[0].maxLife = SEGMENT.check2 ? 400 : 60; PartSys->sources[0].source.x = 0; // start from bottom uint32_t speed = sqrt((gravity * ((PartSys->maxX >> 2) + hw_random16(PartSys->maxX >> 1))) >> 4); // set speed such that rocket explods in frame PartSys->sources[0].source.vx = min(speed, (uint32_t)127); PartSys->sources[0].source.ttl = 4000; PartSys->sources[0].sat = 30; // low saturation exhaust - PartSys->sources[0].size = 0; // default size + PartSys->sources[0].size = SEGMENT.check3; // single or double pixel rendering PartSys->sources[0].sourceFlags.reversegrav = false ; // normal gravity if (SEGENV.aux0) { // inverted rockets launch from end @@ -9360,17 +9358,17 @@ uint16_t mode_particleFireworks1D(void) { } else { // rocket is launched int32_t rocketgravity = -gravity; - int32_t speed = PartSys->sources[0].source.vx; + int32_t currentspeed = PartSys->sources[0].source.vx; if (SEGENV.aux0) { // negative speed rocket rocketgravity = -rocketgravity; - speed = -speed; + currentspeed = -currentspeed; } PartSys->applyForce(PartSys->sources[0].source, rocketgravity, forcecounter[0]); PartSys->particleMoveUpdate(PartSys->sources[0].source, PartSys->sources[0].sourceFlags); - PartSys->particleMoveUpdate(PartSys->sources[0].source, PartSys->sources[0].sourceFlags); // increase speed by calling the move function twice, also ages twice + PartSys->particleMoveUpdate(PartSys->sources[0].source, PartSys->sources[0].sourceFlags); // increase rocket speed by calling the move function twice, also ages twice uint32_t rocketheight = SEGENV.aux0 ? PartSys->maxX - PartSys->sources[0].source.x : PartSys->sources[0].source.x; - if (speed < 0 && PartSys->sources[0].source.ttl > 50) // reached apogee + if (currentspeed < 0 && PartSys->sources[0].source.ttl > 50) // reached apogee PartSys->sources[0].source.ttl = min((uint32_t)50, rocketheight >> (PS_P_RADIUS_SHIFT_1D + 3)); // alive for a few more frames if (PartSys->sources[0].source.ttl < 2) { // explode @@ -9379,19 +9377,32 @@ uint16_t mode_particleFireworks1D(void) { PartSys->sources[0].minLife = 600; PartSys->sources[0].maxLife = 1300; PartSys->sources[0].source.ttl = 100 + hw_random16(64 - (SEGMENT.speed >> 2)); // standby time til next launch - PartSys->sources[0].sat = 7 + (SEGMENT.custom3 << 3); //color saturation TODO: replace saturation with something more useful? - PartSys->sources[0].size = hw_random16(SEGMENT.intensity); // random particle size in explosion + PartSys->sources[0].sat = SEGMENT.custom3 < 16 ? 10 + (SEGMENT.custom3 << 4) : 255; //color saturation + PartSys->sources[0].size = SEGMENT.check3 ? hw_random16(SEGMENT.intensity) : 0; // random particle size in explosion uint32_t explosionsize = 8 + (PartSys->maxXpixel >> 2) + (PartSys->sources[0].source.x >> (PS_P_RADIUS_SHIFT_1D - 1)); explosionsize += hw_random16((explosionsize * SEGMENT.intensity) >> 8); for (uint32_t e = 0; e < explosionsize; e++) { // emit explosion particles - if (SEGMENT.check1) // colorful mode - PartSys->sources[0].source.hue = hw_random16(); //random color for each particle - PartSys->sprayEmit(PartSys->sources[0]); // emit a particle + int idx = PartSys->sprayEmit(PartSys->sources[0]); // emit a particle + if(SEGMENT.custom3 > 23) { + if(SEGMENT.custom3 == 31) { // highest slider value + PartSys->setColorByAge(SEGMENT.check1); // color by age if colorful mode is enabled + PartSys->setColorByPosition(!SEGMENT.check1); // color by position otherwise + } + else { // if custom3 is set to high value (but not highest), set particle color by initial speed + PartSys->particles[idx].hue = map(abs(PartSys->particles[idx].vx), 0, PartSys->sources[0].var, 0, 16 + hw_random16(200)); // set hue according to speed, use random amount of palette width + PartSys->particles[idx].hue += PartSys->sources[0].source.hue; // add hue offset of the rocket (random starting color) + } + } + else { + if (SEGMENT.check1) // colorful mode + PartSys->sources[0].source.hue = hw_random16(); //random color for each particle + } } } } - if ((SEGMENT.call & 0x01) == 0 && PartSys->sources[0].sourceFlags.custom1 == false) // every second frame and not in standby + if ((SEGMENT.call & 0x01) == 0 && PartSys->sources[0].sourceFlags.custom1 == false && PartSys->sources[0].source.ttl > 50) // every second frame and not in standby and not about to explode PartSys->sprayEmit(PartSys->sources[0]); // emit exhaust particle + if ((SEGMENT.call & 0x03) == 0) // every fourth frame PartSys->applyFriction(1); // apply friction to all particles @@ -9401,10 +9412,9 @@ uint16_t mode_particleFireworks1D(void) { if (PartSys->particles[i].ttl > 10) PartSys->particles[i].ttl -= 10; //ttl is linked to brightness, this allows to use higher brightness but still a short spark lifespan else PartSys->particles[i].ttl = 0; } - return FRAMETIME; } -static const char _data_FX_MODE_PS_FIREWORKS1D[] PROGMEM = "PS Fireworks 1D@Gravity,Explosion,Firing side,Blur,Saturation,Colorful,Trail,Smooth;,!;!;1;sx=150,c2=30,c3=31,o1=1,o2=1"; +static const char _data_FX_MODE_PS_FIREWORKS1D[] PROGMEM = "PS Fireworks 1D@Gravity,Explosion,Firing side,Blur,Color,Colorful,Trail,Smooth;,!;!;1;c2=30,o1=1"; /* Particle based Sparkle effect @@ -9925,7 +9935,6 @@ uint16_t mode_particle1DGEQ(void) { PartSys->sources[i].maxLife = 240 + SEGMENT.intensity; PartSys->sources[i].sat = 255; PartSys->sources[i].size = SEGMENT.custom1; - PartSys->setParticleSize(SEGMENT.custom1); PartSys->sources[i].source.x = (spacing >> 1) + spacing * i; //distribute evenly } diff --git a/wled00/FXparticleSystem.cpp b/wled00/FXparticleSystem.cpp index fadc9876..85264b7f 100644 --- a/wled00/FXparticleSystem.cpp +++ b/wled00/FXparticleSystem.cpp @@ -48,6 +48,7 @@ ParticleSystem2D::ParticleSystem2D(uint32_t width, uint32_t height, uint32_t num for (uint32_t i = 0; i < numSources; i++) { sources[i].source.sat = 255; //set saturation to max by default sources[i].source.ttl = 1; //set source alive + sources[i].sourceFlags.asByte = 0; // all flags disabled } } @@ -559,6 +560,10 @@ void ParticleSystem2D::pointAttractor(const uint32_t particleindex, PSparticle & void ParticleSystem2D::render() { CRGB baseRGB; uint32_t brightness; // particle brightness, fades if dying + TBlendType blend = LINEARBLEND; // default color rendering: wrap palette + if (particlesettings.colorByAge) { + blend = LINEARBLEND_NOWRAP; + } if (motionBlur) { // motion-blurring active for (int32_t y = 0; y <= maxYpixel; y++) { @@ -581,11 +586,11 @@ void ParticleSystem2D::render() { if (fireIntesity) { // fire mode brightness = (uint32_t)particles[i].ttl * (3 + (fireIntesity >> 5)) + 20; brightness = min(brightness, (uint32_t)255); - baseRGB = ColorFromPaletteWLED(SEGPALETTE, brightness, 255); + baseRGB = ColorFromPaletteWLED(SEGPALETTE, brightness, 255, LINEARBLEND_NOWRAP); } else { brightness = min((particles[i].ttl << 1), (int)255); - baseRGB = ColorFromPaletteWLED(SEGPALETTE, particles[i].hue, 255); + baseRGB = ColorFromPaletteWLED(SEGPALETTE, particles[i].hue, 255, blend); if (particles[i].sat < 255) { CHSV32 baseHSV; rgb2hsv((uint32_t((byte(baseRGB.r) << 16) | (byte(baseRGB.g) << 8) | (byte(baseRGB.b)))), baseHSV); // convert to HSV @@ -598,6 +603,7 @@ void ParticleSystem2D::render() { renderParticle(i, brightness, baseRGB, particlesettings.wrapX, particlesettings.wrapY); } + // apply global size rendering if (particlesize > 1) { uint32_t passes = particlesize / 64 + 1; // number of blur passes, four passes max uint32_t bluramount = particlesize; @@ -605,7 +611,7 @@ void ParticleSystem2D::render() { for (uint32_t i = 0; i < passes; i++) { if (i == 2) // for the last two passes, use higher amount of blur (results in a nicer brightness gradient with soft edges) bitshift = 1; - blur2D(framebuffer, maxXpixel + 1, maxYpixel + 1, bluramount << bitshift, bluramount << bitshift); + blur2D(framebuffer, maxXpixel + 1, maxYpixel + 1, bluramount << bitshift, bluramount << bitshift); bluramount -= 64; } } @@ -626,7 +632,11 @@ void ParticleSystem2D::render() { // calculate pixel positions and brightness distribution and render the particle to local buffer or global buffer __attribute__((optimize("O2"))) void ParticleSystem2D::renderParticle(const uint32_t particleindex, const uint8_t brightness, const CRGB& color, const bool wrapX, const bool wrapY) { - if (particlesize == 0) { // single pixel rendering + uint32_t size = particlesize; + if (advPartProps && advPartProps[particleindex].size > 0) // use advanced size properties (0 means use global size including single pixel rendering) + size = advPartProps[particleindex].size; + + if (size == 0) { // single pixel rendering uint32_t x = particles[particleindex].x >> PS_P_RADIUS_SHIFT; uint32_t y = particles[particleindex].y >> PS_P_RADIUS_SHIFT; if (x <= (uint32_t)maxXpixel && y <= (uint32_t)maxYpixel) { @@ -667,7 +677,7 @@ __attribute__((optimize("O2"))) void ParticleSystem2D::renderParticle(const uint pxlbrightness[2] = (dx * precal3) >> PS_P_SURFACE; // top right value equal to (dx * dy * brightness) >> PS_P_SURFACE pxlbrightness[3] = (precal1 * precal3) >> PS_P_SURFACE; // top left value equal to ((PS_P_RADIUS-dx) * dy * brightness) >> PS_P_SURFACE - if (advPartProps && advPartProps[particleindex].size > 0) { //render particle to a bigger size + if (advPartProps && advPartProps[particleindex].size > 1) { //render particle to a bigger size CRGB renderbuffer[100]; // 10x10 pixel buffer memset(renderbuffer, 0, sizeof(renderbuffer)); // clear buffer //particle size to pixels: < 64 is 4x4, < 128 is 6x6, < 192 is 8x8, bigger is 10x10 @@ -962,15 +972,13 @@ void ParticleSystem2D::updateSystem(void) { // FX handles the PSsources, need to tell this function how many there are void ParticleSystem2D::updatePSpointers(bool isadvanced, bool sizecontrol) { PSPRINTLN("updatePSpointers"); - // DEBUG_PRINT(F("*** PS pointers ***")); - // DEBUG_PRINTF_P(PSTR("this PS %p "), this); // Note on memory alignment: // a pointer MUST be 4 byte aligned. sizeof() in a struct/class is always aligned to the largest element. if it contains a 32bit, it will be padded to 4 bytes, 16bit is padded to 2byte alignment. // The PS is aligned to 4 bytes, a PSparticle is aligned to 2 and a struct containing only byte sized variables is not aligned at all and may need to be padded when dividing the memoryblock. // by making sure that the number of sources and particles is a multiple of 4, padding can be skipped here as alignent is ensured, independent of struct sizes. - particleFlags = reinterpret_cast(this + 1); // pointer to particle flags - particles = reinterpret_cast(particleFlags + numParticles); // pointer to particles - sources = reinterpret_cast(particles + numParticles); // pointer to source(s) at data+sizeof(ParticleSystem2D) + particles = reinterpret_cast(this + 1); // pointer to particles + particleFlags = reinterpret_cast(particles + numParticles); // pointer to particle flags + sources = reinterpret_cast(particleFlags + numParticles); // pointer to source(s) at data+sizeof(ParticleSystem2D) framebuffer = reinterpret_cast(sources + numSources); // pointer to framebuffer // align pointer after framebuffer uintptr_t p = reinterpret_cast(framebuffer + (maxXpixel+1)*(maxYpixel+1)); @@ -1155,6 +1163,7 @@ ParticleSystem1D::ParticleSystem1D(uint32_t length, uint32_t numberofparticles, // initialize some default non-zero values most FX use for (uint32_t i = 0; i < numSources; i++) { sources[i].source.ttl = 1; //set source alive + sources[i].sourceFlags.asByte = 0; // all flags disabled } if (isadvanced) { @@ -1269,7 +1278,7 @@ int32_t ParticleSystem1D::sprayEmit(const PSsource1D &emitter) { particles[emitIndex].x = emitter.source.x; particles[emitIndex].hue = emitter.source.hue; particles[emitIndex].ttl = hw_random16(emitter.minLife, emitter.maxLife); - particleFlags[emitIndex].collide = emitter.sourceFlags.collide; + particleFlags[emitIndex].collide = emitter.sourceFlags.collide; // TODO: could just set all flags (asByte) but need to check if that breaks any of the FX particleFlags[emitIndex].reversegrav = emitter.sourceFlags.reversegrav; particleFlags[emitIndex].perpetual = emitter.sourceFlags.perpetual; if (advPartProps) { @@ -1419,6 +1428,10 @@ void ParticleSystem1D::applyFriction(int32_t coefficient) { void ParticleSystem1D::render() { CRGB baseRGB; uint32_t brightness; // particle brightness, fades if dying + TBlendType blend = LINEARBLEND; // default color rendering: wrap palette + if (particlesettings.colorByAge || particlesettings.colorByPosition) { + blend = LINEARBLEND_NOWRAP; + } #ifdef ESP8266 // no local buffer on ESP8266 if (motionBlur) @@ -1442,7 +1455,7 @@ void ParticleSystem1D::render() { // generate RGB values for particle brightness = min(particles[i].ttl << 1, (int)255); - baseRGB = ColorFromPaletteWLED(SEGPALETTE, particles[i].hue, 255); + baseRGB = ColorFromPaletteWLED(SEGPALETTE, particles[i].hue, 255, blend); if (advPartProps) { //saturation is advanced property in 1D system if (advPartProps[i].sat < 255) { @@ -1489,9 +1502,9 @@ void ParticleSystem1D::render() { // calculate pixel positions and brightness distribution and render the particle to local buffer or global buffer __attribute__((optimize("O2"))) void ParticleSystem1D::renderParticle(const uint32_t particleindex, const uint8_t brightness, const CRGB &color, const bool wrap) { uint32_t size = particlesize; - if (advPartProps) { // use advanced size properties + if (advPartProps) // use advanced size properties (1D system has no large size global rendering TODO: add large global rendering?) size = advPartProps[particleindex].size; - } + if (size == 0) { //single pixel particle, can be out of bounds as oob checking is made for 2-pixel particles (and updating it uses more code) uint32_t x = particles[particleindex].x >> PS_P_RADIUS_SHIFT_1D; if (x <= (uint32_t)maxXpixel) { //by making x unsigned there is no need to check < 0 as it will overflow @@ -1736,30 +1749,32 @@ void ParticleSystem1D::updatePSpointers(bool isadvanced) { // a pointer MUST be 4 byte aligned. sizeof() in a struct/class is always aligned to the largest element. if it contains a 32bit, it will be padded to 4 bytes, 16bit is padded to 2byte alignment. // The PS is aligned to 4 bytes, a PSparticle is aligned to 2 and a struct containing only byte sized variables is not aligned at all and may need to be padded when dividing the memoryblock. // by making sure that the number of sources and particles is a multiple of 4, padding can be skipped here as alignent is ensured, independent of struct sizes. - particleFlags = reinterpret_cast(this + 1); // pointer to particle flags - particles = reinterpret_cast(particleFlags + numParticles); // pointer to particles - sources = reinterpret_cast(particles + numParticles); // pointer to source(s) + particles = reinterpret_cast(this + 1); // pointer to particles + particleFlags = reinterpret_cast(particles + numParticles); // pointer to particle flags + sources = reinterpret_cast(particleFlags + numParticles); // pointer to source(s) #ifdef ESP8266 // no local buffer on ESP8266 PSdataEnd = reinterpret_cast(sources + numSources); #else framebuffer = reinterpret_cast(sources + numSources); // pointer to framebuffer // align pointer after framebuffer to 4bytes - uintptr_t p = reinterpret_cast(framebuffer + (maxXpixel+1)); + uintptr_t p = reinterpret_cast(framebuffer + (maxXpixel+1)); // maxXpixel is SEGMENT.virtualLength() - 1 p = (p + 3) & ~0x03; // align to 4-byte boundary PSdataEnd = reinterpret_cast(p); // pointer to first available byte after the PS for FX additional data #endif if (isadvanced) { advPartProps = reinterpret_cast(PSdataEnd); - PSdataEnd = reinterpret_cast(advPartProps + numParticles); + PSdataEnd = reinterpret_cast(advPartProps + numParticles); // since numParticles is a multiple of 4, this is always aligned to 4 bytes. No need to add padding bytes here } #ifdef WLED_DEBUG_PS PSPRINTLN(" PS Pointers: "); PSPRINT(" PS : 0x"); Serial.println((uintptr_t)this, HEX); - PSPRINT(" Sources : 0x"); - Serial.println((uintptr_t)sources, HEX); + PSPRINT(" Particleflags : 0x"); + Serial.println((uintptr_t)particleFlags, HEX); PSPRINT(" Particles : 0x"); Serial.println((uintptr_t)particles, HEX); + PSPRINT(" Sources : 0x"); + Serial.println((uintptr_t)sources, HEX); #endif } @@ -1780,6 +1795,7 @@ uint32_t calculateNumberOfParticles1D(const uint32_t fraction, const bool isadva numberofParticles = numberofParticles < 20 ? 20 : numberofParticles; // 20 minimum //make sure it is a multiple of 4 for proper memory alignment (easier than using padding bytes) numberofParticles = (numberofParticles+3) & ~0x03; // note: with a separate particle buffer, this is probably unnecessary + PSPRINTLN(" calc numparticles:" + String(numberofParticles)) return numberofParticles; } diff --git a/wled00/FXparticleSystem.h b/wled00/FXparticleSystem.h index 695a3a02..d188ae23 100644 --- a/wled00/FXparticleSystem.h +++ b/wled00/FXparticleSystem.h @@ -96,7 +96,7 @@ typedef union { // struct for additional particle settings (option) typedef struct { // 2 bytes - uint8_t size; // particle size, 255 means 10 pixels in diameter + uint8_t size; // particle size, 255 means 10 pixels in diameter, 0 means use global size (including single pixel rendering) uint8_t forcecounter; // counter for applying forces to individual particles } PSadvancedParticle; @@ -127,7 +127,7 @@ typedef struct { int8_t var; // variation of emitted speed (adds random(+/- var) to speed) int8_t vx; // emitting speed int8_t vy; - uint8_t size; // particle size (advanced property) + uint8_t size; // particle size (advanced property), global size is added on top to this size } PSsource; // class uses approximately 60 bytes @@ -214,7 +214,7 @@ private: uint8_t gforcecounter; // counter for global gravity int8_t gforce; // gravity strength, default is 8 (negative is allowed, positive is downwards) // global particle properties for basic particles - uint8_t particlesize; // global particle size, 0 = 1 pixel, 1 = 2 pixels, 255 = 10 pixels (note: this is also added to individual sized particles) + uint8_t particlesize; // global particle size, 0 = 1 pixel, 1 = 2 pixels, 255 = 10 pixels (note: this is also added to individual sized particles, set to 0 or 1 for standard advanced particle rendering) uint8_t motionBlur; // motion blur, values > 100 gives smoother animations. Note: motion blurring does not work if particlesize is > 0 uint8_t smearBlur; // 2D smeared blurring of full frame }; @@ -289,7 +289,7 @@ typedef union { // struct for additional particle settings (optional) typedef struct { uint8_t sat; //color saturation - uint8_t size; // particle size, 255 means 10 pixels in diameter + uint8_t size; // particle size, 255 means 10 pixels in diameter, this overrides global size setting uint8_t forcecounter; } PSadvancedParticle1D; @@ -333,7 +333,7 @@ public: void setColorByPosition(const bool enable); void setMotionBlur(const uint8_t bluramount); // note: motion blur can only be used if 'particlesize' is set to zero void setSmearBlur(const uint8_t bluramount); // enable 1D smeared blurring of full frame - void setParticleSize(const uint8_t size); //size 0 = 1 pixel, size 1 = 2 pixels, is overruled by advanced particle size + void setParticleSize(const uint8_t size); //size 0 = 1 pixel, size 1 = 2 pixels, is overruled if advanced particle is used void setGravity(int8_t force = 8); void enableParticleCollisions(bool enable, const uint8_t hardness = 255); @@ -377,7 +377,7 @@ private: uint8_t forcecounter; // counter for globally applied forces uint16_t collisionStartIdx; // particle array start index for collision detection //global particle properties for basic particles - uint8_t particlesize; // global particle size, 0 = 1 pixel, 1 = 2 pixels + uint8_t particlesize; // global particle size, 0 = 1 pixel, 1 = 2 pixels, is overruled by advanced particle size uint8_t motionBlur; // enable motion blur, values > 100 gives smoother animations uint8_t smearBlur; // smeared blurring of full frame }; From a8dd2435ec82b4f348b8a22f2caae0392f95c9da Mon Sep 17 00:00:00 2001 From: Will Miles Date: Tue, 6 May 2025 22:11:17 -0400 Subject: [PATCH 420/463] Revert "Usermods: Remove libArchive" This reverts commit 0d44e7ec272b130f7e3eccf1d1f20a5405a327fe. --- usermods/ADS1115_v2/library.json | 1 + usermods/AHT10_v2/library.json | 1 + usermods/Analog_Clock/library.json | 3 ++- usermods/Animated_Staircase/library.json | 3 ++- usermods/BH1750_v2/library.json | 1 + usermods/BME280_v2/library.json | 1 + usermods/Battery/library.json | 3 ++- usermods/Cronixie/library.json | 3 ++- usermods/EleksTube_IPS/library.json.disabled | 1 + usermods/Internal_Temperature_v2/library.json | 3 ++- usermods/LD2410_v2/library.json | 1 + usermods/LDR_Dusk_Dawn_v2/library.json | 3 ++- usermods/MY9291/library.json | 1 + usermods/PIR_sensor_switch/library.json | 3 ++- usermods/PWM_fan/library.json | 1 + usermods/RTC/library.json | 3 ++- usermods/SN_Photoresistor/library.json | 3 ++- usermods/ST7789_display/library.json.disabled | 3 ++- usermods/Si7021_MQTT_HA/library.json | 1 + usermods/TetrisAI_v2/library.json | 3 ++- usermods/boblight/library.json | 3 ++- usermods/buzzer/library.json | 3 ++- usermods/deep_sleep/library.json | 3 ++- usermods/multi_relay/library.json | 3 ++- usermods/pwm_outputs/library.json | 3 ++- usermods/sd_card/library.json | 3 ++- usermods/seven_segment_display/library.json | 3 ++- usermods/seven_segment_display_reloaded/library.json | 3 ++- usermods/sht/library.json | 1 + usermods/smartnest/library.json | 3 ++- usermods/stairway_wipe_basic/library.json | 3 ++- usermods/usermod_rotary_brightness_color/library.json | 3 ++- usermods/usermod_v2_HttpPullLightControl/library.json | 3 ++- usermods/usermod_v2_animartrix/library.json | 1 + usermods/usermod_v2_auto_save/library.json | 3 ++- usermods/usermod_v2_four_line_display_ALT/library.json | 1 + usermods/usermod_v2_klipper_percentage/library.json | 3 ++- usermods/usermod_v2_ping_pong_clock/library.json | 3 ++- usermods/usermod_v2_rotary_encoder_ui_ALT/library.json | 1 + usermods/usermod_v2_word_clock/library.json | 3 ++- usermods/wizlights/library.json | 3 ++- usermods/word-clock-matrix/library.json | 3 ++- 42 files changed, 71 insertions(+), 29 deletions(-) diff --git a/usermods/ADS1115_v2/library.json b/usermods/ADS1115_v2/library.json index 9f0c021c..5e5d7e45 100644 --- a/usermods/ADS1115_v2/library.json +++ b/usermods/ADS1115_v2/library.json @@ -1,5 +1,6 @@ { "name": "ADS1115_v2", + "build": { "libArchive": false }, "dependencies": { "Adafruit BusIO": "https://github.com/adafruit/Adafruit_BusIO#1.13.2", "Adafruit ADS1X15": "https://github.com/adafruit/Adafruit_ADS1X15#2.4.0" diff --git a/usermods/AHT10_v2/library.json b/usermods/AHT10_v2/library.json index 54f8c171..fa6c2a6f 100644 --- a/usermods/AHT10_v2/library.json +++ b/usermods/AHT10_v2/library.json @@ -1,5 +1,6 @@ { "name": "AHT10_v2", + "build": { "libArchive": false }, "dependencies": { "enjoyneering/AHT10":"~1.1.0" } diff --git a/usermods/Analog_Clock/library.json b/usermods/Analog_Clock/library.json index 3ed596dc..f76cf426 100644 --- a/usermods/Analog_Clock/library.json +++ b/usermods/Analog_Clock/library.json @@ -1,3 +1,4 @@ { - "name": "Analog_Clock" + "name": "Analog_Clock", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/Animated_Staircase/library.json b/usermods/Animated_Staircase/library.json index a2c50ea4..015b15ce 100644 --- a/usermods/Animated_Staircase/library.json +++ b/usermods/Animated_Staircase/library.json @@ -1,3 +1,4 @@ { - "name": "Animated_Staircase" + "name": "Animated_Staircase", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/BH1750_v2/library.json b/usermods/BH1750_v2/library.json index 13740e6c..8323d1ab 100644 --- a/usermods/BH1750_v2/library.json +++ b/usermods/BH1750_v2/library.json @@ -1,5 +1,6 @@ { "name": "BH1750_v2", + "build": { "libArchive": false }, "dependencies": { "claws/BH1750":"^1.2.0" } diff --git a/usermods/BME280_v2/library.json b/usermods/BME280_v2/library.json index 626fb8b2..cfdfe1ba 100644 --- a/usermods/BME280_v2/library.json +++ b/usermods/BME280_v2/library.json @@ -1,5 +1,6 @@ { "name": "BME280_v2", + "build": { "libArchive": false }, "dependencies": { "finitespace/BME280":"~3.0.0" } diff --git a/usermods/Battery/library.json b/usermods/Battery/library.json index d6b8ad38..8e71c60a 100644 --- a/usermods/Battery/library.json +++ b/usermods/Battery/library.json @@ -1,3 +1,4 @@ { - "name": "Battery" + "name": "Battery", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/Cronixie/library.json b/usermods/Cronixie/library.json index a1454a79..4a1b6988 100644 --- a/usermods/Cronixie/library.json +++ b/usermods/Cronixie/library.json @@ -1,3 +1,4 @@ { - "name": "Cronixie" + "name": "Cronixie", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/EleksTube_IPS/library.json.disabled b/usermods/EleksTube_IPS/library.json.disabled index eddd12b8..d143638e 100644 --- a/usermods/EleksTube_IPS/library.json.disabled +++ b/usermods/EleksTube_IPS/library.json.disabled @@ -1,5 +1,6 @@ { "name:": "EleksTube_IPS", + "build": { "libArchive": false }, "dependencies": { "TFT_eSPI" : "2.5.33" } diff --git a/usermods/Internal_Temperature_v2/library.json b/usermods/Internal_Temperature_v2/library.json index 571176f4..b1826ab4 100644 --- a/usermods/Internal_Temperature_v2/library.json +++ b/usermods/Internal_Temperature_v2/library.json @@ -1,3 +1,4 @@ { - "name": "Internal_Temperature_v2" + "name": "Internal_Temperature_v2", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/LD2410_v2/library.json b/usermods/LD2410_v2/library.json index 92ad54da..757ec404 100644 --- a/usermods/LD2410_v2/library.json +++ b/usermods/LD2410_v2/library.json @@ -1,5 +1,6 @@ { "name": "LD2410_v2", + "build": { "libArchive": false }, "dependencies": { "ncmreynolds/ld2410":"^0.1.3" } diff --git a/usermods/LDR_Dusk_Dawn_v2/library.json b/usermods/LDR_Dusk_Dawn_v2/library.json index be06c3a3..709967ea 100644 --- a/usermods/LDR_Dusk_Dawn_v2/library.json +++ b/usermods/LDR_Dusk_Dawn_v2/library.json @@ -1,3 +1,4 @@ { - "name": "LDR_Dusk_Dawn_v2" + "name": "LDR_Dusk_Dawn_v2", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/MY9291/library.json b/usermods/MY9291/library.json index e4c63eaf..9c3a33d4 100644 --- a/usermods/MY9291/library.json +++ b/usermods/MY9291/library.json @@ -1,4 +1,5 @@ { "name": "MY9291", + "build": { "libArchive": false }, "platforms": ["espressif8266"] } \ No newline at end of file diff --git a/usermods/PIR_sensor_switch/library.json b/usermods/PIR_sensor_switch/library.json index d5ebb768..b3cbcbbf 100644 --- a/usermods/PIR_sensor_switch/library.json +++ b/usermods/PIR_sensor_switch/library.json @@ -1,3 +1,4 @@ { - "name": "PIR_sensor_switch" + "name": "PIR_sensor_switch", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/PWM_fan/library.json b/usermods/PWM_fan/library.json index a8f7a944..8ae3d7fd 100644 --- a/usermods/PWM_fan/library.json +++ b/usermods/PWM_fan/library.json @@ -1,6 +1,7 @@ { "name": "PWM_fan", "build": { + "libArchive": false, "extraScript": "setup_deps.py" } } \ No newline at end of file diff --git a/usermods/RTC/library.json b/usermods/RTC/library.json index 8c103e06..688dfc2d 100644 --- a/usermods/RTC/library.json +++ b/usermods/RTC/library.json @@ -1,3 +1,4 @@ { - "name": "RTC" + "name": "RTC", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/SN_Photoresistor/library.json b/usermods/SN_Photoresistor/library.json index 45519dfa..c896644f 100644 --- a/usermods/SN_Photoresistor/library.json +++ b/usermods/SN_Photoresistor/library.json @@ -1,3 +1,4 @@ { - "name": "SN_Photoresistor" + "name": "SN_Photoresistor", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/ST7789_display/library.json.disabled b/usermods/ST7789_display/library.json.disabled index abcd4635..725e20a6 100644 --- a/usermods/ST7789_display/library.json.disabled +++ b/usermods/ST7789_display/library.json.disabled @@ -1,3 +1,4 @@ { - "name:": "ST7789_display" + "name:": "ST7789_display", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/Si7021_MQTT_HA/library.json b/usermods/Si7021_MQTT_HA/library.json index cec2edfb..e3d7635e 100644 --- a/usermods/Si7021_MQTT_HA/library.json +++ b/usermods/Si7021_MQTT_HA/library.json @@ -1,5 +1,6 @@ { "name": "Si7021_MQTT_HA", + "build": { "libArchive": false }, "dependencies": { "finitespace/BME280":"3.0.0", "adafruit/Adafruit Si7021 Library" : "1.5.3" diff --git a/usermods/TetrisAI_v2/library.json b/usermods/TetrisAI_v2/library.json index bfff1aa4..54aa22d3 100644 --- a/usermods/TetrisAI_v2/library.json +++ b/usermods/TetrisAI_v2/library.json @@ -1,3 +1,4 @@ { - "name": "TetrisAI_v2" + "name": "TetrisAI_v2", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/boblight/library.json b/usermods/boblight/library.json index 12debccf..b54fb350 100644 --- a/usermods/boblight/library.json +++ b/usermods/boblight/library.json @@ -1,3 +1,4 @@ { - "name": "boblight" + "name": "boblight", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/buzzer/library.json b/usermods/buzzer/library.json index c6af3158..0dbb547e 100644 --- a/usermods/buzzer/library.json +++ b/usermods/buzzer/library.json @@ -1,3 +1,4 @@ { - "name": "buzzer" + "name": "buzzer", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/deep_sleep/library.json b/usermods/deep_sleep/library.json index 8b39b2ee..82e32c99 100644 --- a/usermods/deep_sleep/library.json +++ b/usermods/deep_sleep/library.json @@ -1,3 +1,4 @@ { - "name": "deep_sleep" + "name": "deep_sleep", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/multi_relay/library.json b/usermods/multi_relay/library.json index f1caf7d4..a5e5c693 100644 --- a/usermods/multi_relay/library.json +++ b/usermods/multi_relay/library.json @@ -1,3 +1,4 @@ { - "name": "multi_relay" + "name": "multi_relay", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/pwm_outputs/library.json b/usermods/pwm_outputs/library.json index bcdb8d5a..a01068bd 100644 --- a/usermods/pwm_outputs/library.json +++ b/usermods/pwm_outputs/library.json @@ -1,3 +1,4 @@ { - "name": "pwm_outputs" + "name": "pwm_outputs", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/sd_card/library.json b/usermods/sd_card/library.json index 44d3e349..33e8f98f 100644 --- a/usermods/sd_card/library.json +++ b/usermods/sd_card/library.json @@ -1,3 +1,4 @@ { - "name": "sd_card" + "name": "sd_card", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/seven_segment_display/library.json b/usermods/seven_segment_display/library.json index 653c3d7f..f78aad87 100644 --- a/usermods/seven_segment_display/library.json +++ b/usermods/seven_segment_display/library.json @@ -1,3 +1,4 @@ { - "name": "seven_segment_display" + "name": "seven_segment_display", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/seven_segment_display_reloaded/library.json b/usermods/seven_segment_display_reloaded/library.json index 4e84e38e..1b7d0687 100644 --- a/usermods/seven_segment_display_reloaded/library.json +++ b/usermods/seven_segment_display_reloaded/library.json @@ -1,6 +1,7 @@ { "name": "seven_segment_display_reloaded", "build": { + "libArchive": false, "extraScript": "setup_deps.py" - } + } } \ No newline at end of file diff --git a/usermods/sht/library.json b/usermods/sht/library.json index 6849628c..0916e9a3 100644 --- a/usermods/sht/library.json +++ b/usermods/sht/library.json @@ -1,5 +1,6 @@ { "name": "sht", + "build": { "libArchive": false }, "dependencies": { "robtillaart/SHT85": "~0.3.3" } diff --git a/usermods/smartnest/library.json b/usermods/smartnest/library.json index 9b428f6b..3e9ea63a 100644 --- a/usermods/smartnest/library.json +++ b/usermods/smartnest/library.json @@ -1,3 +1,4 @@ { - "name": "smartnest" + "name": "smartnest", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/stairway_wipe_basic/library.json b/usermods/stairway_wipe_basic/library.json index b75baef6..f7d353b5 100644 --- a/usermods/stairway_wipe_basic/library.json +++ b/usermods/stairway_wipe_basic/library.json @@ -1,3 +1,4 @@ { - "name": "stairway_wipe_basic" + "name": "stairway_wipe_basic", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/usermod_rotary_brightness_color/library.json b/usermods/usermod_rotary_brightness_color/library.json index ecf73c0f..4f7a146a 100644 --- a/usermods/usermod_rotary_brightness_color/library.json +++ b/usermods/usermod_rotary_brightness_color/library.json @@ -1,3 +1,4 @@ { - "name": "usermod_rotary_brightness_color" + "name": "usermod_rotary_brightness_color", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/usermod_v2_HttpPullLightControl/library.json b/usermods/usermod_v2_HttpPullLightControl/library.json index a9252fc0..870753b9 100644 --- a/usermods/usermod_v2_HttpPullLightControl/library.json +++ b/usermods/usermod_v2_HttpPullLightControl/library.json @@ -1,3 +1,4 @@ { - "name": "usermod_v2_HttpPullLightControl" + "name": "usermod_v2_HttpPullLightControl", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/usermod_v2_animartrix/library.json b/usermods/usermod_v2_animartrix/library.json index 4552be33..667572ba 100644 --- a/usermods/usermod_v2_animartrix/library.json +++ b/usermods/usermod_v2_animartrix/library.json @@ -1,5 +1,6 @@ { "name": "animartrix", + "build": { "libArchive": false }, "dependencies": { "Animartrix": "https://github.com/netmindz/animartrix.git#b172586" } diff --git a/usermods/usermod_v2_auto_save/library.json b/usermods/usermod_v2_auto_save/library.json index d703487a..127767eb 100644 --- a/usermods/usermod_v2_auto_save/library.json +++ b/usermods/usermod_v2_auto_save/library.json @@ -1,3 +1,4 @@ { - "name": "auto_save" + "name": "auto_save", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/usermod_v2_four_line_display_ALT/library.json b/usermods/usermod_v2_four_line_display_ALT/library.json index 87a690f0..b1644822 100644 --- a/usermods/usermod_v2_four_line_display_ALT/library.json +++ b/usermods/usermod_v2_four_line_display_ALT/library.json @@ -1,5 +1,6 @@ { "name": "four_line_display_ALT", + "build": { "libArchive": false }, "dependencies": { "U8g2": "~2.34.4", "Wire": "" diff --git a/usermods/usermod_v2_klipper_percentage/library.json b/usermods/usermod_v2_klipper_percentage/library.json index 7a2df6b2..962dda14 100644 --- a/usermods/usermod_v2_klipper_percentage/library.json +++ b/usermods/usermod_v2_klipper_percentage/library.json @@ -1,3 +1,4 @@ { - "name": "usermod_v2_klipper_percentage" + "name": "usermod_v2_klipper_percentage", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/usermod_v2_ping_pong_clock/library.json b/usermods/usermod_v2_ping_pong_clock/library.json index d6c079e5..4b272eca 100644 --- a/usermods/usermod_v2_ping_pong_clock/library.json +++ b/usermods/usermod_v2_ping_pong_clock/library.json @@ -1,3 +1,4 @@ { - "name": "usermod_v2_ping_pong_clock" + "name": "usermod_v2_ping_pong_clock", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/library.json b/usermods/usermod_v2_rotary_encoder_ui_ALT/library.json index ddb6334b..7c828d08 100644 --- a/usermods/usermod_v2_rotary_encoder_ui_ALT/library.json +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/library.json @@ -1,6 +1,7 @@ { "name": "rotary_encoder_ui_ALT", "build": { + "libArchive": false, "extraScript": "setup_deps.py" } } \ No newline at end of file diff --git a/usermods/usermod_v2_word_clock/library.json b/usermods/usermod_v2_word_clock/library.json index b0dcebc6..0ea99d81 100644 --- a/usermods/usermod_v2_word_clock/library.json +++ b/usermods/usermod_v2_word_clock/library.json @@ -1,3 +1,4 @@ { - "name": "usermod_v2_word_clock" + "name": "usermod_v2_word_clock", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/wizlights/library.json b/usermods/wizlights/library.json index 114424e5..0bfc097c 100644 --- a/usermods/wizlights/library.json +++ b/usermods/wizlights/library.json @@ -1,3 +1,4 @@ { - "name": "wizlights" + "name": "wizlights", + "build": { "libArchive": false } } \ No newline at end of file diff --git a/usermods/word-clock-matrix/library.json b/usermods/word-clock-matrix/library.json index afeae502..7bc3919d 100644 --- a/usermods/word-clock-matrix/library.json +++ b/usermods/word-clock-matrix/library.json @@ -1,3 +1,4 @@ { - "name": "word-clock-matrix" + "name": "word-clock-matrix", + "build": { "libArchive": false } } \ No newline at end of file From 849d5e6667c2f5e682281d21f46dd995606e006c Mon Sep 17 00:00:00 2001 From: Will Miles Date: Tue, 6 May 2025 22:37:57 -0400 Subject: [PATCH 421/463] Add libArchive to other usermods Not all of them were removed by the reverted commit; re-do the rest of them. --- usermods/BH1750_v2/library.json | 2 +- usermods/BME68X_v2/library.json | 1 + usermods/EXAMPLE/library.json | 1 + usermods/INA226_v2/library.json | 1 + usermods/usermod_v2_RF433/library.json | 1 + usermods/usermod_v2_brightness_follow_sun/library.json | 3 ++- 6 files changed, 7 insertions(+), 2 deletions(-) diff --git a/usermods/BH1750_v2/library.json b/usermods/BH1750_v2/library.json index 8323d1ab..4e32099b 100644 --- a/usermods/BH1750_v2/library.json +++ b/usermods/BH1750_v2/library.json @@ -1,6 +1,6 @@ { "name": "BH1750_v2", - "build": { "libArchive": false }, + "build": { "libArchive": false }, "dependencies": { "claws/BH1750":"^1.2.0" } diff --git a/usermods/BME68X_v2/library.json b/usermods/BME68X_v2/library.json index 2f1e1a31..b315aa5d 100644 --- a/usermods/BME68X_v2/library.json +++ b/usermods/BME68X_v2/library.json @@ -1,5 +1,6 @@ { "name": "BME68X", + "build": { "libArchive": false }, "dependencies": { "boschsensortec/BSEC Software Library":"^1.8.1492" } diff --git a/usermods/EXAMPLE/library.json b/usermods/EXAMPLE/library.json index dd8a7e5d..d0dc2f88 100644 --- a/usermods/EXAMPLE/library.json +++ b/usermods/EXAMPLE/library.json @@ -1,4 +1,5 @@ { "name": "EXAMPLE", + "build": { "libArchive": false }, "dependencies": {} } diff --git a/usermods/INA226_v2/library.json b/usermods/INA226_v2/library.json index ab6c81fb..34fcd368 100644 --- a/usermods/INA226_v2/library.json +++ b/usermods/INA226_v2/library.json @@ -1,5 +1,6 @@ { "name": "INA226_v2", + "build": { "libArchive": false }, "dependencies": { "wollewald/INA226_WE":"~1.2.9" } diff --git a/usermods/usermod_v2_RF433/library.json b/usermods/usermod_v2_RF433/library.json index d809d3a0..d8de29b8 100644 --- a/usermods/usermod_v2_RF433/library.json +++ b/usermods/usermod_v2_RF433/library.json @@ -1,5 +1,6 @@ { "name": "usermod_v2_RF433", + "build": { "libArchive": false }, "dependencies": { "sui77/rc-switch":"2.6.4" } diff --git a/usermods/usermod_v2_brightness_follow_sun/library.json b/usermods/usermod_v2_brightness_follow_sun/library.json index 6120d873..dec00e55 100644 --- a/usermods/usermod_v2_brightness_follow_sun/library.json +++ b/usermods/usermod_v2_brightness_follow_sun/library.json @@ -1,3 +1,4 @@ { - "name": "brightness_follow_sun" + "name": "brightness_follow_sun", + "build": { "libArchive": false } } \ No newline at end of file From ee3864175d90fb04030ab592cd73ae9e0b2f8673 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Tue, 6 May 2025 21:55:06 -0400 Subject: [PATCH 422/463] load_usermods: Make missing libArchive an error Rather than try and fail to add this property, abort if it's missing from any requested usermod. --- pio-scripts/load_usermods.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/pio-scripts/load_usermods.py b/pio-scripts/load_usermods.py index eeebcbf2..8cf625ff 100644 --- a/pio-scripts/load_usermods.py +++ b/pio-scripts/load_usermods.py @@ -2,6 +2,8 @@ Import('env') import os.path from collections import deque from pathlib import Path # For OS-agnostic path manipulation +from click import secho +from SCons.Script import Exit from platformio.builder.tools.piolib import LibBuilderBase from platformio.package.manager.library import LibraryPackageManager @@ -105,6 +107,7 @@ def wrapped_ConfigureProjectLibBuilder(xenv): for dep in result.depbuilders: cached_add_includes(dep, processed_deps, extra_include_dirs) + broken_usermods = [] for dep in result.depbuilders: if is_wled_module(dep): # Add the wled folder to the include path @@ -114,9 +117,15 @@ def wrapped_ConfigureProjectLibBuilder(xenv): dep.env.PrependUnique(CPPPATH=str(dir)) # Enforce that libArchive is not set; we must link them directly to the executable if dep.lib_archive: - build = dep._manifest.get("build", {}) - build["libArchive"] = False - dep._manifest["build"] = build + broken_usermods.append(dep) + + if broken_usermods: + broken_usermods = [usermod.name for usermod in broken_usermods] + secho( + f"ERROR: libArchive=false is missing on usermod(s) {' '.join(broken_usermods)} -- modules will not compile in correctly", + fg="red", + err=True) + Exit(1) return result From 0fe722e478eedc013212059d60148f4a1353419c Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Fri, 9 May 2025 18:53:16 +0200 Subject: [PATCH 423/463] add new effect: PS Galaxy - parameters tuned to make it look good on most settings --- wled00/FX.cpp | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++ wled00/FX.h | 3 +- 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 1a756018..b10fc0b7 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -8958,6 +8958,104 @@ uint16_t mode_particleblobs(void) { return FRAMETIME; } static const char _data_FX_MODE_PARTICLEBLOBS[] PROGMEM = "PS Blobs@Speed,Blobs,Size,Life,Blur,Wobble,Collide,Pulsate;;!;2v;sx=30,ix=64,c1=200,c2=130,c3=0,o3=1"; + +/* + Particle Galaxy, particles spiral like in a galaxy + Uses palette for particle color + by DedeHai (Damian Schneider) +*/ +uint16_t mode_particlegalaxy(void) { + ParticleSystem2D *PartSys = nullptr; + PSsettings2D sourcesettings; + sourcesettings.asByte = 0b00001100; // PS settings for bounceY, bounceY used for source movement (it always bounces whereas particles do not) + if (SEGMENT.call == 0) { // initialization + if (!initParticleSystem2D(PartSys, 1, 0, true)) // init using 1 source and advanced particle settings + return mode_static(); // allocation failed or not 2D + PartSys->sources[0].source.vx = -4; // will collide with wall and get random bounce direction + PartSys->sources[0].source.x = PartSys->maxX >> 1; // start in the center + PartSys->sources[0].source.y = PartSys->maxY >> 1; + PartSys->sources[0].sourceFlags.perpetual = true; //source does not age + PartSys->sources[0].maxLife = 4000; // lifetime in frames + PartSys->sources[0].minLife = 800; + PartSys->setWallHardness(255); //bounce forever + PartSys->setWallRoughness(200); //randomize wall bounce + } + else { + PartSys = reinterpret_cast(SEGENV.data); // if not first call, just set the pointer to the PS + } + if (PartSys == nullptr) + return mode_static(); // something went wrong, no data! + // Particle System settings + PartSys->updateSystem(); // update system properties (dimensions and data pointers) + uint8_t particlesize = SEGMENT.custom1; + if(SEGMENT.check3) + particlesize = SEGMENT.custom1 ? 1 : 0; // set size to 0 (single pixel) or 1 (quad pixel) so motion blur works and adds streaks + PartSys->setParticleSize(particlesize); // set size globally + PartSys->setMotionBlur(250 * SEGMENT.check3); // adds trails to single/quad pixel particles, no effect if size > 1 + + if ((SEGMENT.call % ((33 - SEGMENT.custom3) >> 1)) == 0) // change hue of emitted particles + PartSys->sources[0].source.hue+=2; + + if (hw_random8() < (10 + (SEGMENT.intensity >> 1))) // 5%-55% chance to emit a particle in this frame + PartSys->sprayEmit(PartSys->sources[0]); + + if ((SEGMENT.call & 0x3) == 0) // every 4th frame, move the emitter + PartSys->particleMoveUpdate(PartSys->sources[0].source, PartSys->sources[0].sourceFlags, &sourcesettings); + + // move alive particles in a spiral motion (or almost straight in fast starfield mode) + for (uint32_t i = 0; i < PartSys->usedParticles; i++) { //check all particles + if (PartSys->particles[i].ttl == 0) continue; //skip dead particles + + int32_t centerx = PartSys->maxX >> 1; // center of matrix in subpixel coordinates + int32_t centery = PartSys->maxY >> 1; + // (dx/dy): vector pointing from particle to center + int32_t dx = centerx - PartSys->particles[i].x; + int32_t dy = centery - PartSys->particles[i].y; + //speed towards center: + int32_t distance = sqrt32_bw(dx * dx + dy * dy); // absolute distance to center + if (distance < 20) distance = 20; // avoid division by zero, keep a minimum + int32_t speedfactor; + if (SEGMENT.check2) { // starfield mode + PartSys->setKillOutOfBounds(true); + PartSys->sources[0].source.hue = hw_random16(); // start with random color + PartSys->sources[0].var = 7; // emiting variation + PartSys->sources[0].source.x = PartSys->maxX >> 1; // set emitter to center + PartSys->sources[0].source.y = PartSys->maxY >> 1; + speedfactor = 1 + (1 + (SEGMENT.speed >> 1)) * distance; // speed increases towards edge + PartSys->particles[i].x += (-speedfactor * dx) / 400000 - (dy >> 6); + PartSys->particles[i].y += (-speedfactor * dy) / 400000 + (dx >> 6); + } + else { + PartSys->setKillOutOfBounds(false); + PartSys->sources[0].var = 1; // emiting variation + speedfactor = 2 + (((50 + SEGMENT.speed) << 6) / distance); // speed increases towards center + // rotate clockwise + int32_t tempVx = (-speedfactor * dy); // speed is orthogonal to center vector + int32_t tempVy = (speedfactor * dx); + //add speed towards center to make particles spiral in + int vxc = (dx << 9) / (distance - 19); // subtract value from distance to make the pull-in force a bit stronger (helps on faster speeds) + int vyc = (dy << 9) / (distance - 19); + //apply velocity + PartSys->particles[i].x += (tempVx + vxc) / 1024; // note: cannot use bit shift as that causes asymmetric rounding + PartSys->particles[i].y += (tempVy + vyc) / 1024; + + if (distance < 128) { // close to center + if (PartSys->particles[i].ttl > 3) + PartSys->particles[i].ttl -= 4; //age fast + PartSys->particles[i].sat = distance << 1; // turn white towards center + } + } + if(SEGMENT.custom3 == 31) // color by age but mapped to 1024 as particles have a long life, since age is random, this gives more or less random colors + PartSys->particles[i].hue = PartSys->particles[i].ttl >> 2; + else if(SEGMENT.custom3 == 0) // color by distance + PartSys->particles[i].hue = map(distance, 20, (PartSys->maxX + PartSys->maxY) >> 2, 0, 180); // color by distance to center + } + + PartSys->update(); // update and render + return FRAMETIME; +} +static const char _data_FX_MODE_PARTICLEGALAXY[] PROGMEM = "PS Galaxy@!,!,Size,,Color,,Starfield,Trace;;!;2;pal=59,sx=80,c1=2,c3=4"; + #endif //WLED_DISABLE_PARTICLESYSTEM2D #endif // WLED_DISABLE_2D @@ -10657,6 +10755,7 @@ void WS2812FX::setupEffectData() { addEffect(FX_MODE_PARTICLECENTERGEQ, &mode_particlecenterGEQ, _data_FX_MODE_PARTICLECIRCULARGEQ); addEffect(FX_MODE_PARTICLEGHOSTRIDER, &mode_particleghostrider, _data_FX_MODE_PARTICLEGHOSTRIDER); addEffect(FX_MODE_PARTICLEBLOBS, &mode_particleblobs, _data_FX_MODE_PARTICLEBLOBS); + addEffect(FX_MODE_PARTICLEGALAXY, &mode_particlegalaxy, _data_FX_MODE_PARTICLEGALAXY); #endif // WLED_DISABLE_PARTICLESYSTEM2D #endif // WLED_DISABLE_2D diff --git a/wled00/FX.h b/wled00/FX.h index 6481ff75..c5634470 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -353,7 +353,8 @@ extern byte realtimeMode; // used in getMappedPixelIndex() #define FX_MODE_PS1DSONICSTREAM 214 #define FX_MODE_PS1DSONICBOOM 215 #define FX_MODE_PS1DSPRINGY 216 -#define MODE_COUNT 217 +#define FX_MODE_PARTICLEGALAXY 217 +#define MODE_COUNT 218 #define BLEND_STYLE_FADE 0x00 // universal From 891115eceeba59d4e7f29da12297be9311601873 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Fri, 9 May 2025 19:06:06 +0200 Subject: [PATCH 424/463] bugfix --- wled00/FX.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index b10fc0b7..9969d431 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -8977,6 +8977,7 @@ uint16_t mode_particlegalaxy(void) { PartSys->sources[0].sourceFlags.perpetual = true; //source does not age PartSys->sources[0].maxLife = 4000; // lifetime in frames PartSys->sources[0].minLife = 800; + PartSys->sources[0].source.hue = hw_random16(); // start with random color PartSys->setWallHardness(255); //bounce forever PartSys->setWallRoughness(200); //randomize wall bounce } @@ -9017,7 +9018,6 @@ uint16_t mode_particlegalaxy(void) { int32_t speedfactor; if (SEGMENT.check2) { // starfield mode PartSys->setKillOutOfBounds(true); - PartSys->sources[0].source.hue = hw_random16(); // start with random color PartSys->sources[0].var = 7; // emiting variation PartSys->sources[0].source.x = PartSys->maxX >> 1; // set emitter to center PartSys->sources[0].source.y = PartSys->maxY >> 1; @@ -9045,7 +9045,7 @@ uint16_t mode_particlegalaxy(void) { PartSys->particles[i].sat = distance << 1; // turn white towards center } } - if(SEGMENT.custom3 == 31) // color by age but mapped to 1024 as particles have a long life, since age is random, this gives more or less random colors + if(SEGMENT.custom3 == 31) // color by age but mapped to 1024 as particles have a long life, since age is random, this gives more or less random colors but PartSys->particles[i].hue = PartSys->particles[i].ttl >> 2; else if(SEGMENT.custom3 == 0) // color by distance PartSys->particles[i].hue = map(distance, 20, (PartSys->maxX + PartSys->maxY) >> 2, 0, 180); // color by distance to center From 5fe766399b1b2ea8cac8667e8c7fee0bd97cd881 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Fri, 9 May 2025 19:06:38 +0200 Subject: [PATCH 425/463] comment --- wled00/FX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 9969d431..56cd7669 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -9045,7 +9045,7 @@ uint16_t mode_particlegalaxy(void) { PartSys->particles[i].sat = distance << 1; // turn white towards center } } - if(SEGMENT.custom3 == 31) // color by age but mapped to 1024 as particles have a long life, since age is random, this gives more or less random colors but + if(SEGMENT.custom3 == 31) // color by age but mapped to 1024 as particles have a long life, since age is random, this gives more or less random colors PartSys->particles[i].hue = PartSys->particles[i].ttl >> 2; else if(SEGMENT.custom3 == 0) // color by distance PartSys->particles[i].hue = map(distance, 20, (PartSys->maxX + PartSys->maxY) >> 2, 0, 180); // color by distance to center From 608aff1e17dbbf947e78062adbe2f59e58ce1900 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 10 May 2025 09:11:07 +0200 Subject: [PATCH 426/463] slight speed improvement, fixed indentation --- wled00/FX.cpp | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 56cd7669..9584ea8e 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -9004,30 +9004,34 @@ uint16_t mode_particlegalaxy(void) { PartSys->particleMoveUpdate(PartSys->sources[0].source, PartSys->sources[0].sourceFlags, &sourcesettings); // move alive particles in a spiral motion (or almost straight in fast starfield mode) + int32_t centerx = PartSys->maxX >> 1; // center of matrix in subpixel coordinates + int32_t centery = PartSys->maxY >> 1; + if (SEGMENT.check2) { // starfield mode + PartSys->setKillOutOfBounds(true); + PartSys->sources[0].var = 7; // emiting variation + PartSys->sources[0].source.x = centerx; // set emitter to center + PartSys->sources[0].source.y = centery; + } + else { + PartSys->setKillOutOfBounds(false); + PartSys->sources[0].var = 1; // emiting variation + } for (uint32_t i = 0; i < PartSys->usedParticles; i++) { //check all particles if (PartSys->particles[i].ttl == 0) continue; //skip dead particles - - int32_t centerx = PartSys->maxX >> 1; // center of matrix in subpixel coordinates - int32_t centery = PartSys->maxY >> 1; // (dx/dy): vector pointing from particle to center - int32_t dx = centerx - PartSys->particles[i].x; - int32_t dy = centery - PartSys->particles[i].y; + int32_t dx = centerx - PartSys->particles[i].x; + int32_t dy = centery - PartSys->particles[i].y; //speed towards center: - int32_t distance = sqrt32_bw(dx * dx + dy * dy); // absolute distance to center + int32_t distance = sqrt32_bw(dx * dx + dy * dy); // absolute distance to center if (distance < 20) distance = 20; // avoid division by zero, keep a minimum - int32_t speedfactor; + int32_t speedfactor; if (SEGMENT.check2) { // starfield mode - PartSys->setKillOutOfBounds(true); - PartSys->sources[0].var = 7; // emiting variation - PartSys->sources[0].source.x = PartSys->maxX >> 1; // set emitter to center - PartSys->sources[0].source.y = PartSys->maxY >> 1; speedfactor = 1 + (1 + (SEGMENT.speed >> 1)) * distance; // speed increases towards edge + //apply velocity PartSys->particles[i].x += (-speedfactor * dx) / 400000 - (dy >> 6); PartSys->particles[i].y += (-speedfactor * dy) / 400000 + (dx >> 6); } else { - PartSys->setKillOutOfBounds(false); - PartSys->sources[0].var = 1; // emiting variation speedfactor = 2 + (((50 + SEGMENT.speed) << 6) / distance); // speed increases towards center // rotate clockwise int32_t tempVx = (-speedfactor * dy); // speed is orthogonal to center vector From b5a710dbe46d1d4ef8884e6a7ac9e2e7cb2a664d Mon Sep 17 00:00:00 2001 From: srg74 <28492985+srg74@users.noreply.github.com> Date: Sun, 11 May 2025 12:19:03 -0400 Subject: [PATCH 427/463] Fixed markdownlint errors --- usermods/Temperature/readme.md | 8 +++++-- usermods/readme.md | 12 +++++------ usermods/sht/readme.md | 19 +++++++++++++---- .../readme.md | 21 ++++++++++--------- .../readme.md | 2 ++ 5 files changed, 40 insertions(+), 22 deletions(-) diff --git a/usermods/Temperature/readme.md b/usermods/Temperature/readme.md index b7697edc..b09495fe 100644 --- a/usermods/Temperature/readme.md +++ b/usermods/Temperature/readme.md @@ -35,19 +35,23 @@ All parameters can be configured at runtime via the Usermods settings page, incl ## Change Log -2020-09-12 +2020-09-12 + * Changed to use async non-blocking implementation * Do not report erroneous low temperatures to MQTT * Disable plugin if temperature sensor not detected * Report the number of seconds until the first read in the info screen instead of sensor error 2021-04 + * Adaptation for runtime configuration. 2023-05 + * Rewrite to conform to newer recommendations. * Recommended @blazoncek fork of OneWire for ESP32 to avoid Sensor error 2024-09 + * Update OneWire to version 2.3.8, which includes stickbreaker's and garyd9's ESP32 fixes: - blazoncek's fork is no longer needed \ No newline at end of file + blazoncek's fork is no longer needed diff --git a/usermods/readme.md b/usermods/readme.md index 8aa8d6ab..eefb64db 100644 --- a/usermods/readme.md +++ b/usermods/readme.md @@ -1,4 +1,4 @@ -### Usermods +# Usermods This folder serves as a repository for usermods (custom `usermod.cpp` files)! @@ -6,11 +6,11 @@ If you have created a usermod you believe is useful (for example to support a pa In order for other people to be able to have fun with your usermod, please keep these points in mind: -- Create a folder in this folder with a descriptive name (for example `usermod_ds18b20_temp_sensor_mqtt`) -- Include your custom files -- If your usermod requires changes to other WLED files, please write a `readme.md` outlining the steps one needs to take -- Create a pull request! -- If your feature is useful for the majority of WLED users, I will consider adding it to the base code! +* Create a folder in this folder with a descriptive name (for example `usermod_ds18b20_temp_sensor_mqtt`) +* Include your custom files +* If your usermod requires changes to other WLED files, please write a `readme.md` outlining the steps one needs to take +* Create a pull request! +* If your feature is useful for the majority of WLED users, I will consider adding it to the base code! While I do my best to not break too much, keep in mind that as WLED is updated, usermods might break. I am not actively maintaining any usermod in this directory, that is your responsibility as the creator of the usermod. diff --git a/usermods/sht/readme.md b/usermods/sht/readme.md index c2cc5a1f..4470c883 100644 --- a/usermods/sht/readme.md +++ b/usermods/sht/readme.md @@ -1,35 +1,43 @@ # SHT + Usermod to support various SHT i2c sensors like the SHT30, SHT31, SHT35 and SHT85 ## Requirements -* "SHT85" by Rob Tillaart, v0.2 or higher: https://github.com/RobTillaart/SHT85 + +* "SHT85" by Rob Tillaart, v0.2 or higher: ## Usermod installation Simply copy the below block (build task) to your `platformio_override.ini` and compile WLED using this new build task. Or use an existing one, add the custom_usermod `sht`. ESP32: -``` + +```ini [env:custom_esp32dev_usermod_sht] extends = env:esp32dev custom_usermods = ${env:esp32dev.custom_usermods} sht ``` ESP8266: -``` + +```ini [env:custom_d1_mini_usermod_sht] extends = env:d1_mini custom_usermods = ${env:d1_mini.custom_usermods} sht ``` ## MQTT Discovery for Home Assistant + If you're using Home Assistant and want to have the temperature and humidity available as entities in HA, you can tick the "Add-To-Home-Assistant-MQTT-Discovery" option in the usermod settings. If you have an MQTT broker configured under "Sync Settings" and it is connected, the mod will publish the auto discovery message to your broker and HA will instantly find it and create an entity each for the temperature and humidity. ### Publishing readings via MQTT + Regardless of having MQTT discovery ticked or not, the mod will always report temperature and humidity to the WLED MQTT topic of that instance, if you have a broker configured and it's connected. ## Configuration + Navigate to the "Config" and then to the "Usermods" section. If you compiled WLED with `-D USERMOD_SHT`, you will see the config for it there: + * SHT-Type: * What it does: Select the SHT sensor type you want to use * Possible values: SHT30, SHT31, SHT35, SHT85 @@ -44,8 +52,11 @@ Navigate to the "Config" and then to the "Usermods" section. If you compiled WLE * Default: Disabled ## Change log + 2022-12 + * First implementation. ## Credits -ezcGman | Andy: Find me on the Intermit.Tech (QuinLED) Discord server: https://discord.gg/WdbAauG + +ezcGman | Andy: Find me on the Intermit.Tech (QuinLED) Discord server: diff --git a/usermods/usermod_v2_four_line_display_ALT/readme.md b/usermods/usermod_v2_four_line_display_ALT/readme.md index 39bb5d28..663c93a4 100644 --- a/usermods/usermod_v2_four_line_display_ALT/readme.md +++ b/usermods/usermod_v2_four_line_display_ALT/readme.md @@ -5,6 +5,7 @@ This usermod could be used in compination with `usermod_v2_rotary_encoder_ui_ALT ## Functionalities Press the encoder to cycle through the options: + * Brightness * Speed * Intensity @@ -35,15 +36,15 @@ These options are configurable in Config > Usermods * `enabled` - enable/disable usermod * `type` - display type in numeric format - * 1 = I2C SSD1306 128x32 - * 2 = I2C SH1106 128x32 - * 3 = I2C SSD1306 128x64 (4 double-height lines) - * 4 = I2C SSD1305 128x32 - * 5 = I2C SSD1305 128x64 (4 double-height lines) - * 6 = SPI SSD1306 128x32 - * 7 = SPI SSD1306 128x64 (4 double-height lines) - * 8 = SPI SSD1309 128x64 (4 double-height lines) - * 9 = I2C SSD1309 128x64 (4 double-height lines) + * 1 = I2C SSD1306 128x32 + * 2 = I2C SH1106 128x32 + * 3 = I2C SSD1306 128x64 (4 double-height lines) + * 4 = I2C SSD1305 128x32 + * 5 = I2C SSD1305 128x64 (4 double-height lines) + * 6 = SPI SSD1306 128x32 + * 7 = SPI SSD1306 128x64 (4 double-height lines) + * 8 = SPI SSD1309 128x64 (4 double-height lines) + * 9 = I2C SSD1309 128x64 (4 double-height lines) * `pin` - GPIO pins used for display; SPI displays can use SCK, MOSI, CS, DC & RST * `flip` - flip/rotate display 180° * `contrast` - set display contrast (higher contrast may reduce display lifetime) @@ -53,7 +54,6 @@ These options are configurable in Config > Usermods * `showSeconds` - Show seconds on the clock display * `i2c-freq-kHz` - I2C clock frequency in kHz (may help reduce dropped frames, range: 400-3400) - ### PlatformIO requirements Note: the Four Line Display usermod requires the libraries `U8g2` and `Wire`. @@ -61,4 +61,5 @@ Note: the Four Line Display usermod requires the libraries `U8g2` and `Wire`. ## Change Log 2021-10 + * First public release diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/readme.md b/usermods/usermod_v2_rotary_encoder_ui_ALT/readme.md index 3df6de6e..cb6150a4 100644 --- a/usermods/usermod_v2_rotary_encoder_ui_ALT/readme.md +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/readme.md @@ -5,6 +5,7 @@ This usermod supports the UI of the `usermod_v2_rotary_encoder_ui_ALT`. ## Functionalities Press the encoder to cycle through the options: + * Brightness * Speed * Intensity @@ -39,4 +40,5 @@ No special requirements. ## Change Log 2021-10 + * First public release From 42d9a41cf52f0539351e39461b1326735d2a5e29 Mon Sep 17 00:00:00 2001 From: srg74 <28492985+srg74@users.noreply.github.com> Date: Sun, 11 May 2025 12:49:32 -0400 Subject: [PATCH 428/463] Fixed markdownlint errors #2 --- usermods/Animated_Staircase/README.md | 33 +++++---- usermods/BH1750_v2/readme.md | 16 +++-- usermods/PIR_sensor_switch/readme.md | 18 +++-- usermods/PWM_fan/readme.md | 3 + usermods/audioreactive/readme.md | 37 +++++----- usermods/project_cars_shiftlight/readme.md | 10 +-- .../usermod_v2_HttpPullLightControl/readme.md | 71 ++++++++++--------- usermods/usermod_v2_auto_save/readme.md | 6 +- .../README.md | 6 +- usermods/usermod_v2_word_clock/readme.md | 10 +-- 10 files changed, 125 insertions(+), 85 deletions(-) diff --git a/usermods/Animated_Staircase/README.md b/usermods/Animated_Staircase/README.md index c24a037e..263ac806 100644 --- a/usermods/Animated_Staircase/README.md +++ b/usermods/Animated_Staircase/README.md @@ -1,4 +1,5 @@ # Usermod Animated Staircase + This usermod makes your staircase look cool by illuminating it with an animation. It uses PIR or ultrasonic sensors at the top and bottom of your stairs to: @@ -11,11 +12,13 @@ The Animated Staircase can be controlled by the WLED API. Change settings such a speed, on/off time and distance by sending an HTTP request, see below. ## WLED integration + To include this usermod in your WLED setup, you have to be able to [compile WLED from source](https://kno.wled.ge/advanced/compiling-wled/). Before compiling, you have to make the following modifications: Edit your environment in `platformio_override.ini` + 1. Open `platformio_override.ini` 2. add `Animated_Staircase` to the `custom_usermods` line for your environment @@ -25,10 +28,10 @@ If you use PIR sensor enter -1 for echo pin. Maximum distance for ultrasonic sensor can be configured as the time needed for an echo (see below). ## Hardware installation + 1. Attach the LED strip to each step of the stairs. 2. Connect the ESP8266 pin D4 or ESP32 pin D2 to the first LED data pin at the bottom step. -3. Connect the data-out pin at the end of each strip per step to the data-in pin on the - next step, creating one large virtual LED strip. +3. Connect the data-out pin at the end of each strip per step to the data-in pin on the next step, creating one large virtual LED strip. 4. Mount sensors of choice at the bottom and top of the stairs and connect them to the ESP. 5. To make sure all LEDs get enough power and have your staircase lighted evenly, power each step from one side, using at least AWG14 or 2.5mm^2 cable. Don't connect them serial as you @@ -37,24 +40,23 @@ Maximum distance for ultrasonic sensor can be configured as the time needed for You _may_ need to use 10k pull-down resistors on the selected PIR pins, depending on the sensor. ## WLED configuration -1. In the WLED UI, configure a segment for each step. The lowest step of the stairs is the - lowest segment id. -2. Save your segments into a preset. -3. Ideally, add the preset in the config > LED setup menu to the "apply - preset **n** at boot" setting. + +1. In the WLED UI, configure a segment for each step. The lowest step of the stairs is the lowest segment id. +2. Save your segments into a preset. +3. Ideally, add the preset in the config > LED setup menu to the "apply preset **n** at boot" setting. ## Changing behavior through API + The Staircase settings can be changed through the WLED JSON api. **NOTE:** We are using [curl](https://curl.se/) to send HTTP POSTs to the WLED API. If you're using Windows and want to use the curl commands, replace the `\` with a `^` or remove them and put everything on one line. - | Setting | Description | Default | |------------------|---------------------------------------------------------------|---------| | enabled | Enable or disable the usermod | true | -| bottom-sensor | Manually trigger a down to up animation via API | false | +| bottom-sensor | Manually trigger a down to up animation via API | false | | top-sensor | Manually trigger an up to down animation via API | false | @@ -74,6 +76,7 @@ The staircase settings and sensor states are inside the WLED "state" element: ``` ### Enable/disable the usermod + By disabling the usermod you will be able to keep the LED's on, independent from the sensor activity. This enables you to play with the lights without the usermod switching them on or off. @@ -90,6 +93,7 @@ To enable the usermod again, use `"enabled":true`. Alternatively you can use _Usermod_ Settings page where you can change other parameters as well. ### Changing animation parameters and detection range of the ultrasonic HC-SR04 sensor + Using _Usermod_ Settings page you can define different usermod parameters, including sensor pins, delay between segment activation etc. When an ultrasonic sensor is enabled you can enter maximum detection distance in centimeters separately for top and bottom sensors. @@ -99,6 +103,7 @@ distances creates delays in the WLED software, _might_ introduce timing hiccups a less responsive web interface. It is therefore advised to keep the detection distance as short as possible. ### Animation triggering through the API + In addition to activation by one of the stair sensors, you can also trigger the animation manually via the API. To simulate triggering the bottom sensor, use: @@ -115,15 +120,19 @@ curl -X POST -H "Content-Type: application/json" \ -d '{"staircase":{"top-sensor":true}}' \ xxx.xxx.xxx.xxx/json/state ``` + **MQTT** You can publish a message with either `up` or `down` on topic `/swipe` to trigger animation. You can also use `on` or `off` for enabling or disabling the usermod. -Have fun with this usermod.
-www.rolfje.com +Have fun with this usermod + +`www.rolfje.com` Modifications @blazoncek ## Change log + 2021-04 -* Adaptation for runtime configuration. + +- Adaptation for runtime configuration. diff --git a/usermods/BH1750_v2/readme.md b/usermods/BH1750_v2/readme.md index bba4eb71..9f599107 100644 --- a/usermods/BH1750_v2/readme.md +++ b/usermods/BH1750_v2/readme.md @@ -4,6 +4,7 @@ This usermod will read from an ambient light sensor like the BH1750. The luminance is displayed in both the Info section of the web UI, as well as published to the `/luminance` MQTT topic if enabled. ## Dependencies + - Libraries - `claws/BH1750 @^1.2.0` - Data is published over MQTT - make sure you've enabled the MQTT sync interface. @@ -13,23 +14,30 @@ The luminance is displayed in both the Info section of the web UI, as well as pu To enable, compile with `BH1750` in `custom_usermods` (e.g. in `platformio_override.ini`) ### Configuration Options + The following settings can be set at compile-time but are configurable on the usermod menu (except First Measurement time): -* `USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL` - the max number of milliseconds between measurements, defaults to 10000ms -* `USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL` - the min number of milliseconds between measurements, defaults to 500ms -* `USERMOD_BH1750_OFFSET_VALUE` - the offset value to report on, defaults to 1 -* `USERMOD_BH1750_FIRST_MEASUREMENT_AT` - the number of milliseconds after boot to take first measurement, defaults to 10000 ms + +- `USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL` - the max number of milliseconds between measurements, defaults to 10000ms +- `USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL` - the min number of milliseconds between measurements, defaults to 500ms +- `USERMOD_BH1750_OFFSET_VALUE` - the offset value to report on, defaults to 1 +- `USERMOD_BH1750_FIRST_MEASUREMENT_AT` - the number of milliseconds after boot to take first measurement, defaults to 10000 ms In addition, the Usermod screen allows you to: + - enable/disable the usermod - Enable Home Assistant Discovery of usermod - Configure the SCL/SDA pins ## API + The following method is available to interact with the usermod from other code modules: + - `getIlluminance` read the brightness from the sensor ## Change Log + Jul 2022 + - Added Home Assistant Discovery - Implemented PinManager to register pins - Made pins configurable in usermod menu diff --git a/usermods/PIR_sensor_switch/readme.md b/usermods/PIR_sensor_switch/readme.md index be55406d..2b889748 100644 --- a/usermods/PIR_sensor_switch/readme.md +++ b/usermods/PIR_sensor_switch/readme.md @@ -25,7 +25,7 @@ You can also use usermod's off timer instead of sensor's. In such case rotate th **NOTE:** Usermod has been included in master branch of WLED so it can be compiled in directly just by defining `-D USERMOD_PIRSWITCH` and optionally `-D PIR_SENSOR_PIN=16` to override default pin. You can also change the default off time by adding `-D PIR_SENSOR_OFF_SEC=30`. -## API to enable/disable the PIR sensor from outside. For example from another usermod: +## API to enable/disable the PIR sensor from outside. For example from another usermod To query or change the PIR sensor state the methods `bool PIRsensorEnabled()` and `void EnablePIRsensor(bool enable)` are available. @@ -33,15 +33,16 @@ When the PIR sensor state changes an MQTT message is broadcasted with topic `wle Usermod can also be configured to send just the MQTT message but not change WLED state using settings page as well as responding to motion only at night (assuming NTP and latitude/longitude are set to determine sunrise/sunset times). -### There are two options to get access to the usermod instance: +### There are two options to get access to the usermod instance -1. Include `usermod_PIR_sensor_switch.h` **before** you include other usermods in `usermods_list.cpp' +_1._ Include `usermod_PIR_sensor_switch.h` **before** you include other usermods in `usermods_list.cpp' or -2. Use `#include "usermod_PIR_sensor_switch.h"` at the top of the `usermod.h` where you need it. +_2._ Use `#include "usermod_PIR_sensor_switch.h"` at the top of the `usermod.h` where you need it. **Example usermod.h :** + ```cpp #include "wled.h" @@ -79,25 +80,30 @@ Usermod can be configured via the Usermods settings page. * `override` - override PIR input when WLED state is changed using UI * `domoticz-idx` - Domoticz virtual switch ID (used with MQTT `domoticz/in`) - Have fun - @gegu & @blazoncek ## Change log + 2021-04 + * Adaptation for runtime configuration. 2021-11 + * Added information about dynamic configuration options * Added option to temporary enable/disable usermod from WLED UI (Info dialog) 2022-11 + * Added compile time option for off timer. * Added Home Assistant autodiscovery MQTT broadcast. * Updated info on compiling. 2023-?? + * Override option * Domoticz virtual switch ID (used with MQTT `domoticz/in`) 2024-02 -* Added compile time option to expand number of PIR sensors (they are logically ORed) `-D PIR_SENSOR_MAX_SENSORS=3` \ No newline at end of file + +* Added compile time option to expand number of PIR sensors (they are logically ORed) `-D PIR_SENSOR_MAX_SENSORS=3` diff --git a/usermods/PWM_fan/readme.md b/usermods/PWM_fan/readme.md index 9fecaabf..872bbd9b 100644 --- a/usermods/PWM_fan/readme.md +++ b/usermods/PWM_fan/readme.md @@ -40,6 +40,9 @@ If the fan speed is unlocked, it will revert to temperature controlled speed on ## Change Log 2021-10 + * First public release + 2022-05 + * Added JSON API call to allow changing of speed diff --git a/usermods/audioreactive/readme.md b/usermods/audioreactive/readme.md index 8db5c00b..bd253c82 100644 --- a/usermods/audioreactive/readme.md +++ b/usermods/audioreactive/readme.md @@ -8,24 +8,27 @@ Does audio processing and provides data structure that specially written effects **does not** provide effects or draw anything to an LED strip/matrix. ## Additional Documentation + This usermod is an evolution of [SR-WLED](https://github.com/atuline/WLED), and a lot of documentation and information can be found in the [SR-WLED wiki](https://github.com/atuline/WLED/wiki): + * [getting started with audio](https://github.com/atuline/WLED/wiki/First-Time-Setup#sound) * [Sound settings](https://github.com/atuline/WLED/wiki/Sound-Settings) - similar to options on the usemod settings page in WLED. * [Digital Audio](https://github.com/atuline/WLED/wiki/Digital-Microphone-Hookup) * [Analog Audio](https://github.com/atuline/WLED/wiki/Analog-Audio-Input-Options) * [UDP Sound sync](https://github.com/atuline/WLED/wiki/UDP-Sound-Sync) - ## Supported MCUs -This audioreactive usermod works best on "classic ESP32" (dual core), and on ESP32-S3 which also has dual core and hardware floating point support. -It will compile successfully for ESP32-S2 and ESP32-C3, however might not work well, as other WLED functions will become slow. Audio processing requires a lot of computing power, which can be problematic on smaller MCUs like -S2 and -C3. +This audioreactive usermod works best on "classic ESP32" (dual core), and on ESP32-S3 which also has dual core and hardware floating point support. + +It will compile successfully for ESP32-S2 and ESP32-C3, however might not work well, as other WLED functions will become slow. Audio processing requires a lot of computing power, which can be problematic on smaller MCUs like -S2 and -C3. Analog audio is only possible on "classic" ESP32, but not on other MCUs like ESP32-S3. -Currently ESP8266 is not supported, due to low speed and small RAM of this chip. +Currently ESP8266 is not supported, due to low speed and small RAM of this chip. There are however plans to create a lightweight audioreactive for the 8266, with reduced features. -## Installation + +## Installation Add 'ADS1115_v2' to `custom_usermods` in your platformio environment. @@ -35,29 +38,31 @@ All parameters are runtime configurable. Some may require a hard reset after cha If you want to define default GPIOs during compile time, use the following (default values in parentheses): -- `-D SR_DMTYPE=x` : defines digital microphone type: 0=analog, 1=generic I2S (default), 2=ES7243 I2S, 3=SPH0645 I2S, 4=generic I2S with master clock, 5=PDM I2S -- `-D AUDIOPIN=x` : GPIO for analog microphone/AUX-in (36) -- `-D I2S_SDPIN=x` : GPIO for SD pin on digital microphone (32) -- `-D I2S_WSPIN=x` : GPIO for WS pin on digital microphone (15) -- `-D I2S_CKPIN=x` : GPIO for SCK pin on digital microphone (14) -- `-D MCLK_PIN=x` : GPIO for master clock pin on digital Line-In boards (-1) -- `-D ES7243_SDAPIN` : GPIO for I2C SDA pin on ES7243 microphone (-1) -- `-D ES7243_SCLPIN` : GPIO for I2C SCL pin on ES7243 microphone (-1) +* `-D SR_DMTYPE=x` : defines digital microphone type: 0=analog, 1=generic I2S (default), 2=ES7243 I2S, 3=SPH0645 I2S, 4=generic I2S with master clock, 5=PDM I2S +* `-D AUDIOPIN=x` : GPIO for analog microphone/AUX-in (36) +* `-D I2S_SDPIN=x` : GPIO for SD pin on digital microphone (32) +* `-D I2S_WSPIN=x` : GPIO for WS pin on digital microphone (15) +* `-D I2S_CKPIN=x` : GPIO for SCK pin on digital microphone (14) +* `-D MCLK_PIN=x` : GPIO for master clock pin on digital Line-In boards (-1) +* `-D ES7243_SDAPIN` : GPIO for I2C SDA pin on ES7243 microphone (-1) +* `-D ES7243_SCLPIN` : GPIO for I2C SCL pin on ES7243 microphone (-1) Other options: -- `-D UM_AUDIOREACTIVE_ENABLE` : makes usermod default enabled (not the same as include into build option!) -- `-D UM_AUDIOREACTIVE_DYNAMICS_LIMITER_OFF` : disables rise/fall limiter default +* `-D UM_AUDIOREACTIVE_ENABLE` : makes usermod default enabled (not the same as include into build option!) +* `-D UM_AUDIOREACTIVE_DYNAMICS_LIMITER_OFF` : disables rise/fall limiter default **NOTE** I2S is used for analog audio sampling. Hence, the analog *buttons* (i.e. potentiometers) are disabled when running this usermod with an analog microphone. ### Advanced Compile-Time Options + You can use the following additional flags in your `build_flags` + * `-D SR_SQUELCH=x` : Default "squelch" setting (10) * `-D SR_GAIN=x` : Default "gain" setting (60) * `-D I2S_USE_RIGHT_CHANNEL`: Use RIGHT instead of LEFT channel (not recommended unless you strictly need this). * `-D I2S_USE_16BIT_SAMPLES`: Use 16bit instead of 32bit for internal sample buffers. Reduces sampling quality, but frees some RAM ressources (not recommended unless you absolutely need this). -* `-D I2S_GRAB_ADC1_COMPLETELY`: Experimental: continuously sample analog ADC microphone. Only effective on ESP32. WARNING this _will_ cause conflicts(lock-up) with any analogRead() call. +* `-D I2S_GRAB_ADC1_COMPLETELY`: Experimental: continuously sample analog ADC microphone. Only effective on ESP32. WARNING this *will* cause conflicts(lock-up) with any analogRead() call. * `-D MIC_LOGGER` : (debugging) Logs samples from the microphone to serial USB. Use with serial plotter (Arduino IDE) * `-D SR_DEBUG` : (debugging) Additional error diagnostics and debug info on serial USB. diff --git a/usermods/project_cars_shiftlight/readme.md b/usermods/project_cars_shiftlight/readme.md index 433da430..338936a8 100644 --- a/usermods/project_cars_shiftlight/readme.md +++ b/usermods/project_cars_shiftlight/readme.md @@ -1,11 +1,11 @@ -### Shift Light for Project Cars +# Shift Light for Project Cars Turn your WLED lights into a rev light and shift indicator for Project Cars. It's easy to use. -1. Make sure your WLED device and your PC/console are on the same network and can talk to each other +_1._ Make sure your WLED device and your PC/console are on the same network and can talk to each other -2. Go to the gameplay settings menu in PCARS and enable UDP. There are 9 numbers you can choose from. This is the refresh rate. The lower the number, the better. However, you might run into problems at faster rates. +_2._ Go to the gameplay settings menu in PCARS and enable UDP. There are 9 numbers you can choose from. This is the refresh rate. The lower the number, the better. However, you might run into problems at faster rates. | Number | Updates/Second | | ------ | -------------- | @@ -19,5 +19,5 @@ It's easy to use. | 8 | 05 | | 9 | 1 | -3. Once you enter a race, WLED should automatically shift to PCARS mode. -4. Done. +_3._ Once you enter a race, WLED should automatically shift to PCARS mode. +_4._ Done. diff --git a/usermods/usermod_v2_HttpPullLightControl/readme.md b/usermods/usermod_v2_HttpPullLightControl/readme.md index eb56d505..d86ece4d 100644 --- a/usermods/usermod_v2_HttpPullLightControl/readme.md +++ b/usermods/usermod_v2_HttpPullLightControl/readme.md @@ -5,7 +5,7 @@ The `usermod_v2_HttpPullLightControl` is a custom user module for WLED that enab ## Features * Configure the URL endpoint (only support HTTP for now, no HTTPS) and polling interval via the WLED user interface. -* All options from the JSON API are supported (since v0.0.3). See: https://kno.wled.ge/interfaces/json-api/ +* All options from the JSON API are supported (since v0.0.3). See: [https://kno.wled.ge/interfaces/json-api/](https://kno.wled.ge/interfaces/json-api/) * The ability to control the brightness of all lights and the state (on/off) and color of individual lights remotely. * Start or stop an effect and when you run the same effect when its's already running, it won't restart. * The ability to control all these settings per segment. @@ -13,13 +13,15 @@ The `usermod_v2_HttpPullLightControl` is a custom user module for WLED that enab * Unique ID generation based on the device's MAC address and a configurable salt value, appended to the request URL for identification. ## Configuration + * Enable the `usermod_v2_HttpPullLightControl` via the WLED user interface. * Specify the URL endpoint and polling interval. ## JSON Format and examples + * The module sends a GET request to the configured URL, appending a unique identifier as a query parameter: `https://www.example.com/mycustompage.php?id=xxxxxxxx` where xxxxxxx is a 40 character long SHA1 hash of the MAC address combined with a given salt. -* Response Format (since v0.0.3) it is eactly the same as the WLED JSON API, see: https://kno.wled.ge/interfaces/json-api/ +* Response Format (since v0.0.3) it is eactly the same as the WLED JSON API, see: [https://kno.wled.ge/interfaces/json-api/](https://kno.wled.ge/interfaces/json-api/) After getting the URL (it can be a static file like static.json or a mylogic.php which gives a dynamic response), the response is read and parsed to WLED. * An example of a response to set the individual lights: 0 to RED, 12 to Green and 14 to BLUE. Remember that is will SET lights, you might want to set all the others to black. @@ -58,48 +60,51 @@ After getting the URL (it can be a static file like static.json or a mylogic.php }` * Or use the following example to start an effect, but first we UNFREEZE (frz=false) the segment because it was frozen by individual light control in the previous examples (28=Chase effect, Speed=180m Intensity=128). The three color slots are the slots you see under the color wheel and used by the effect. RED, Black, White in this case. + +```json `{ "seg": { - "frz": false, - "fx": 28, - "sx": 200, - "ix": 128, - "col": [ - "FF0000", - "000000", - "FFFFFF" - ] - } + "frz": false, + "fx": 28, + "sx": 200, + "ix": 128, + "col": [ + "FF0000", + "000000", + "FFFFFF" + ] + } }` - +``` ## Installation 1. Add `usermod_v2_HttpPullLightControl` to your WLED project following the instructions provided in the WLED documentation. 2. Compile by setting the build_flag: -D USERMOD_HTTP_PULL_LIGHT_CONTROL and upload to your ESP32/ESP8266! 3. There are several compile options which you can put in your platformio.ini or platformio_override.ini: -- -DUSERMOD_HTTP_PULL_LIGHT_CONTROL ;To Enable the usermod -- -DHTTP_PULL_LIGHT_CONTROL_URL="\"http://mydomain.com/json-response.php\"" ; The URL which will be requested all the time to set the lights/effects -- -DHTTP_PULL_LIGHT_CONTROL_SALT="\"my_very-S3cret_C0de\"" ; A secret SALT which will help by making the ID more safe -- -DHTTP_PULL_LIGHT_CONTROL_INTERVAL=30 ; The interval at which the URL is requested in seconds -- -DHTTP_PULL_LIGHT_CONTROL_HIDE_SALT ; Do you want to Hide the SALT in the User Interface? If yes, Set this flag. Note that the salt can now only be set via the above -DHTTP_PULL_LIGHT_CONTROL_SALT= setting -- -DWLED_AP_SSID="\"Christmas Card\"" ; These flags are not just for my Usermod but you probably want to set them -- -DWLED_AP_PASS="\"christmas\"" -- -DWLED_OTA_PASS="\"otapw-secret\"" -- -DMDNS_NAME="\"christmascard\"" -- -DSERVERNAME="\"CHRISTMASCARD\"" -- -D ABL_MILLIAMPS_DEFAULT=450 -- -D DEFAULT_LED_COUNT=60 ; For a LED Ring of 60 LEDs -- -D BTNPIN=41 ; The M5Stack Atom S3 Lite has a button on GPIO41 -- -D DATA_PINS=2 ; The M5Stack Atom S3 Lite has a Grove connector on the front, we use this GPIO2 -- -D STATUSLED=35 ; The M5Stack Atom S3 Lite has a Multi-Color LED on GPIO35, although I didnt managed to control it -- -D IRPIN=4 ; The M5Stack Atom S3 Lite has a IR LED on GPIO4 +* -DUSERMOD_HTTP_PULL_LIGHT_CONTROL ;To Enable the usermod +* -DHTTP_PULL_LIGHT_CONTROL_URL="\"`http://mydomain.com/json-response.php`\"" ; The URL which will be requested all the time to set the lights/effects +* -DHTTP_PULL_LIGHT_CONTROL_SALT="\"my_very-S3cret_C0de\"" ; A secret SALT which will help by making the ID more safe +* -DHTTP_PULL_LIGHT_CONTROL_INTERVAL=30 ; The interval at which the URL is requested in seconds +* -DHTTP_PULL_LIGHT_CONTROL_HIDE_SALT ; Do you want to Hide the SALT in the User Interface? If yes, Set this flag. Note that the salt can now only be set via the above -DHTTP_PULL_LIGHT_CONTROL_SALT= setting -- -D DEBUG=1 ; Set these DEBUG flags ONLY if you want to debug and read out Serial (using Visual Studio Code - Serial Monitor) -- -DDEBUG_LEVEL=5 -- -DWLED_DEBUG +* -DWLED_AP_SSID="\"Christmas Card\"" ; These flags are not just for my Usermod but you probably want to set them +* -DWLED_AP_PASS="\"christmas\"" +* -DWLED_OTA_PASS="\"otapw-secret\"" +* -DMDNS_NAME="\"christmascard\"" +* -DSERVERNAME="\"CHRISTMASCARD\"" +* -D ABL_MILLIAMPS_DEFAULT=450 +* -D DEFAULT_LED_COUNT=60 ; For a LED Ring of 60 LEDs +* -D BTNPIN=41 ; The M5Stack Atom S3 Lite has a button on GPIO41 +* -D DATA_PINS=2 ; The M5Stack Atom S3 Lite has a Grove connector on the front, we use this GPIO2 +* -D STATUSLED=35 ; The M5Stack Atom S3 Lite has a Multi-Color LED on GPIO35, although I didnt managed to control it +* -D IRPIN=4 ; The M5Stack Atom S3 Lite has a IR LED on GPIO4 + +* -D DEBUG=1 ; Set these DEBUG flags ONLY if you want to debug and read out Serial (using Visual Studio Code - Serial Monitor) +* -DDEBUG_LEVEL=5 +* -DWLED_DEBUG ## Use Case: Interactive Christmas Cards @@ -107,4 +112,4 @@ Imagine distributing interactive Christmas cards embedded with a tiny ESP32 and Your server keeps track of how many cards are active at any given time. If all 20 cards are active, your server instructs each card to light up all of its LEDs. However, if only 4 cards are active, your server instructs each card to light up only 4 LEDs. This creates a real-time interactive experience, symbolizing the collective spirit of the holiday season. Each lit LED represents a friend who's thinking about the others, and the visual feedback creates a sense of connection among the group, despite the physical distance. -This setup demonstrates a unique way to blend traditional holiday sentiments with modern technology, offering an engaging and memorable experience. \ No newline at end of file +This setup demonstrates a unique way to blend traditional holiday sentiments with modern technology, offering an engaging and memorable experience. diff --git a/usermods/usermod_v2_auto_save/readme.md b/usermods/usermod_v2_auto_save/readme.md index f54d87a7..ce15d8c2 100644 --- a/usermods/usermod_v2_auto_save/readme.md +++ b/usermods/usermod_v2_auto_save/readme.md @@ -2,6 +2,7 @@ v2 Usermod to automatically save settings to preset number AUTOSAVE_PRESET_NUM after a change to any of: + * brightness * effect speed * effect intensity @@ -19,7 +20,7 @@ Note: WLED doesn't respect the brightness of the preset being auto loaded, so th ## Installation -Copy and update the example `platformio_override.ini.sample` +Copy and update the example `platformio_override.ini.sample` from the Rotary Encoder UI usermode folder to the root directory of your particular build. This file should be placed in the same directory as `platformio.ini`. @@ -50,6 +51,9 @@ Note: the Four Line Display usermod requires the libraries `U8g2` and `Wire`. ## Change Log 2021-02 + * First public release + 2021-04 + * Adaptation for runtime configuration. diff --git a/usermods/usermod_v2_brightness_follow_sun/README.md b/usermods/usermod_v2_brightness_follow_sun/README.md index 25daf0ba..cbd87a55 100644 --- a/usermods/usermod_v2_brightness_follow_sun/README.md +++ b/usermods/usermod_v2_brightness_follow_sun/README.md @@ -10,8 +10,8 @@ define `USERMOD_BRIGHTNESS_FOLLOW_SUN` e.g. `#define USERMOD_BRIGHTNESS_FOLLOW_S or add `-D USERMOD_BRIGHTNESS_FOLLOW_SUN` to `build_flags` in platformio_override.ini - ### Options + Open Usermod Settings in WLED to change settings: `Enable` - When checked `Enable`, turn on the `Brightness Follow Sun` Usermod, which will automatically turn on the lights, adjust the brightness, and turn off the lights. If you need to completely turn off the lights, please unchecked `Enable`. @@ -24,12 +24,12 @@ Open Usermod Settings in WLED to change settings: `Relax Hour` - The unit is in hours, with an effective range of 0-6. According to the settings, maintain the lowest brightness for 0-6 hours before sunrise and after sunset. - ### PlatformIO requirements No special requirements. -## Change Log +### Change Log 2025-01-02 + * init diff --git a/usermods/usermod_v2_word_clock/readme.md b/usermods/usermod_v2_word_clock/readme.md index c42ee0ee..b81cebce 100644 --- a/usermods/usermod_v2_word_clock/readme.md +++ b/usermods/usermod_v2_word_clock/readme.md @@ -1,14 +1,15 @@ # Word Clock Usermod V2 -This usermod drives an 11x10 pixel matrix wordclock with WLED. There are 4 additional dots for the minutes. +This usermod drives an 11x10 pixel matrix wordclock with WLED. There are 4 additional dots for the minutes. The visualisation is described by 4 masks with LED numbers (single dots for minutes, minutes, hours and "clock"). The index of the LEDs in the masks always starts at 0, even if the ledOffset is not 0. There are 3 parameters that control behavior: - + active: enable/disable usermod diplayItIs: enable/disable display of "Es ist" on the clock ledOffset: number of LEDs before the wordclock LEDs -### Update for alternative wiring pattern +## Update for alternative wiring pattern + Based on this fantastic work I added an alternative wiring pattern. The original used a long wire to connect DO to DI, from one line to the next line. @@ -17,10 +18,9 @@ With this method, every other line was inverted and showed the wrong letter. I added a switch in usermod called "meander wiring?" to enable/disable the alternate wiring pattern. - ## Installation -Copy and update the example `platformio_override.ini.sample` +Copy and update the example `platformio_override.ini.sample` from the Rotary Encoder UI usermod folder to the root directory of your particular build. This file should be placed in the same directory as `platformio.ini`. From d381108dc07915a37faf846f495ef1f4f38bc2ca Mon Sep 17 00:00:00 2001 From: Arcitec <38923130+Arcitec@users.noreply.github.com> Date: Wed, 14 May 2025 00:27:29 +0200 Subject: [PATCH 429/463] AR: add compile-time flag for "Automatic Gain Control" option Automatic Gain Control is a very important aspect of the audioreactive plugin, and is vitally important when the external music volume constantly changes. It makes sense to allow users to choose their preferred AGC behavior at compile-time, since they can already set the Gain and Squelch via flags. Adds `SR_AGC` as a flag, which defaults to 0 (off). --- usermods/audioreactive/audio_reactive.cpp | 5 ++++- usermods/audioreactive/readme.md | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/usermods/audioreactive/audio_reactive.cpp b/usermods/audioreactive/audio_reactive.cpp index 4b352056..e7e79846 100644 --- a/usermods/audioreactive/audio_reactive.cpp +++ b/usermods/audioreactive/audio_reactive.cpp @@ -65,11 +65,14 @@ static bool udpSyncConnected = false; // UDP connection status -> true i // audioreactive variables #ifdef ARDUINO_ARCH_ESP32 + #ifndef SR_AGC // Automatic gain control mode + #define SR_AGC 0 // default mode = off + #endif static float micDataReal = 0.0f; // MicIn data with full 24bit resolution - lowest 8bit after decimal point static float multAgc = 1.0f; // sample * multAgc = sampleAgc. Our AGC multiplier static float sampleAvg = 0.0f; // Smoothed Average sample - sampleAvg < 1 means "quiet" (simple noise gate) static float sampleAgc = 0.0f; // Smoothed AGC sample -static uint8_t soundAgc = 0; // Automagic gain control: 0 - none, 1 - normal, 2 - vivid, 3 - lazy (config value) +static uint8_t soundAgc = SR_AGC; // Automatic gain control: 0 - off, 1 - normal, 2 - vivid, 3 - lazy (config value) #endif //static float volumeSmth = 0.0f; // either sampleAvg or sampleAgc depending on soundAgc; smoothed sample static float FFT_MajorPeak = 1.0f; // FFT: strongest (peak) frequency diff --git a/usermods/audioreactive/readme.md b/usermods/audioreactive/readme.md index bd253c82..5ee575ff 100644 --- a/usermods/audioreactive/readme.md +++ b/usermods/audioreactive/readme.md @@ -60,8 +60,9 @@ You can use the following additional flags in your `build_flags` * `-D SR_SQUELCH=x` : Default "squelch" setting (10) * `-D SR_GAIN=x` : Default "gain" setting (60) +* `-D SR_AGC=x` : (Only ESP32) Default "AGC (Automatic Gain Control)" setting (0): 0=off, 1=normal, 2=vivid, 3=lazy * `-D I2S_USE_RIGHT_CHANNEL`: Use RIGHT instead of LEFT channel (not recommended unless you strictly need this). -* `-D I2S_USE_16BIT_SAMPLES`: Use 16bit instead of 32bit for internal sample buffers. Reduces sampling quality, but frees some RAM ressources (not recommended unless you absolutely need this). +* `-D I2S_USE_16BIT_SAMPLES`: Use 16bit instead of 32bit for internal sample buffers. Reduces sampling quality, but frees some RAM resources (not recommended unless you absolutely need this). * `-D I2S_GRAB_ADC1_COMPLETELY`: Experimental: continuously sample analog ADC microphone. Only effective on ESP32. WARNING this *will* cause conflicts(lock-up) with any analogRead() call. * `-D MIC_LOGGER` : (debugging) Logs samples from the microphone to serial USB. Use with serial plotter (Arduino IDE) * `-D SR_DEBUG` : (debugging) Additional error diagnostics and debug info on serial USB. From d9ad4ec74336e341fc5c543ff3c7f689b9d1ece3 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 19 May 2025 19:50:48 +0200 Subject: [PATCH 430/463] improved & refactored Android FX (#4522) - returns FRAMETIME -> no more flickering in transitions and overlay - no more double-painting of pixels --- wled00/FX.cpp | 74 +++++++++++++++++++++------------------------------ 1 file changed, 31 insertions(+), 43 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 9584ea8e..8835e71f 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -802,57 +802,45 @@ static const char _data_FX_MODE_MULTI_STROBE[] PROGMEM = "Strobe Mega@!,!;!,!;!; /* - * Android loading circle + * Android loading circle, refactored by @dedehai */ uint16_t mode_android(void) { - + if (!SEGENV.allocateData(sizeof(uint32_t))) return mode_static(); + uint32_t* counter = reinterpret_cast(SEGENV.data); + unsigned size = SEGENV.aux1 >> 1; // upper 15 bit + unsigned shrinking = SEGENV.aux1 & 0x01; // lowest bit + if(strip.now >= SEGENV.step) { + SEGENV.step = strip.now + 3 + ((8 * (uint32_t)(255 - SEGMENT.speed)) / SEGLEN); + if (size > (SEGMENT.intensity * SEGLEN) / 255) + shrinking = 1; + else if (size < 2) + shrinking = 0; + if (!shrinking) { // growing + if ((*counter % 3) == 1) + SEGENV.aux0++; // advance start position + else + size++; + } else { // shrinking + SEGENV.aux0++; + if ((*counter % 3) != 1) + size--; + } + SEGENV.aux1 = size << 1 | shrinking; // save back + (*counter)++; + if (SEGENV.aux0 >= SEGLEN) SEGENV.aux0 = 0; + } + uint32_t start = SEGENV.aux0; + uint32_t end = (SEGENV.aux0 + size) % SEGLEN; for (unsigned i = 0; i < SEGLEN; i++) { - SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); - } - - if (SEGENV.aux1 > (SEGMENT.intensity*SEGLEN)/255) - { - SEGENV.aux0 = 1; - } else - { - if (SEGENV.aux1 < 2) SEGENV.aux0 = 0; - } - - unsigned a = SEGENV.step & 0xFFFFU; - - if (SEGENV.aux0 == 0) - { - if (SEGENV.call %3 == 1) {a++;} - else {SEGENV.aux1++;} - } else - { - a++; - if (SEGENV.call %3 != 1) SEGENV.aux1--; - } - - if (a >= SEGLEN) a = 0; - - if (a + SEGENV.aux1 < SEGLEN) - { - for (unsigned i = a; i < a+SEGENV.aux1; i++) { + if ((start < end && i >= start && i < end) || (start >= end && (i >= start || i < end))) SEGMENT.setPixelColor(i, SEGCOLOR(0)); - } - } else - { - for (unsigned i = a; i < SEGLEN; i++) { - SEGMENT.setPixelColor(i, SEGCOLOR(0)); - } - for (unsigned i = 0; i < SEGENV.aux1 - (SEGLEN -a); i++) { - SEGMENT.setPixelColor(i, SEGCOLOR(0)); - } + else + SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); } - SEGENV.step = a; - - return 3 + ((8 * (uint32_t)(255 - SEGMENT.speed)) / SEGLEN); + return FRAMETIME; } static const char _data_FX_MODE_ANDROID[] PROGMEM = "Android@!,Width;!,!;!;;m12=1"; //vertical - /* * color chase function. * color1 = background color From 66ad27ad3a3da160c082f8371ea90ff526598aab Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 19 May 2025 20:34:27 +0200 Subject: [PATCH 431/463] add support for up to 10 ESPNow remotes (#4654) * add support for up to 10 ESPNow remotes * removed debug line * changed todo comment * fixed some issues, shortened html/java code - reverting name to `linked_remote` - ESPNow remote list is now hidden if unchecked - shortened java script function names and variables to save flash - removed now obsolete settings in xml.cpp - correct checking of valid hex string for remote list in java script * fixed indentation, using emplace_back instead of push_back, using JsonVariant, replaced buttons with +/- * shortened java code * updated java code, fixed bug - element is now properly removed - `+` button is hidden if list is full - user needs to remove a remote, then reload the page to add it (workaround for edge case that needs more code to handle otherwise) * add limit * clearer usage description --- wled00/cfg.cpp | 25 ++++++++++++++-- wled00/data/settings_wifi.htm | 55 +++++++++++++++++++++++++++++++---- wled00/remote.cpp | 8 +---- wled00/set.cpp | 17 +++++++++-- wled00/udp.cpp | 18 ++++++++---- wled00/wled.h | 3 +- wled00/xml.cpp | 10 +++---- 7 files changed, 108 insertions(+), 28 deletions(-) diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index fa0397fc..a342886d 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -38,8 +38,24 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { JsonObject nw = doc["nw"]; #ifndef WLED_DISABLE_ESPNOW CJSON(enableESPNow, nw[F("espnow")]); - getStringFromJson(linked_remote, nw[F("linked_remote")], 13); - linked_remote[12] = '\0'; + linked_remotes.clear(); + JsonVariant lrem = nw[F("linked_remote")]; + if (!lrem.isNull()) { + if (lrem.is()) { + for (size_t i = 0; i < lrem.size(); i++) { + std::array entry{}; + getStringFromJson(entry.data(), lrem[i], 13); + entry[12] = '\0'; + linked_remotes.emplace_back(entry); + } + } + else { // legacy support for single MAC address in config + std::array entry{}; + getStringFromJson(entry.data(), lrem, 13); + entry[12] = '\0'; + linked_remotes.emplace_back(entry); + } + } #endif size_t n = 0; @@ -725,7 +741,10 @@ void serializeConfig(JsonObject root) { JsonObject nw = root.createNestedObject("nw"); #ifndef WLED_DISABLE_ESPNOW nw[F("espnow")] = enableESPNow; - nw[F("linked_remote")] = linked_remote; + JsonArray lrem = nw.createNestedArray(F("linked_remote")); + for (size_t i = 0; i < linked_remotes.size(); i++) { + lrem.add(linked_remotes[i].data()); + } #endif JsonArray nw_ins = nw.createNestedArray("ins"); diff --git a/wled00/data/settings_wifi.htm b/wled00/data/settings_wifi.htm index 1531d161..d2d7c66c 100644 --- a/wled00/data/settings_wifi.htm +++ b/wled00/data/settings_wifi.htm @@ -136,12 +136,52 @@ Static subnet mask:
getLoc(); loadJS(getURL('/settings/s.js?p=1'), false); // If we set async false, file is loaded and executed, then next statement is processed if (loc) d.Sf.action = getURL('/settings/wifi'); + setTimeout(tE, 500); // wait for DOM to load before calling tE() } + + var rC = 0; // remote count + // toggle visibility of ESP-NOW remote list based on checkbox state + function tE() { + // keep the hidden input with MAC addresses, only toggle visibility of the list UI + gId('rlc').style.display = d.Sf.RE.checked ? 'block' : 'none'; + } + // reset remotes: initialize empty list (called from xml.cpp) + function rstR() { + gId('rml').innerHTML = ''; // clear remote list + } + // add remote MAC to the list + function aR(id, mac) { + if (!/^[0-9A-F]{12}$/i.test(mac)) return; // check for valid hex string + let inputs = d.querySelectorAll("#rml input"); + for (let i of (inputs || [])) { + if (i.value === mac) return; + } + let l = gId('rml'), r = cE('div'), i = cE('input'); + i.type = 'text'; + i.name = id; + i.value = mac; + i.maxLength = 12; + i.minLength = 12; + //i.onchange = uR; + r.appendChild(i); + let b = cE('button'); + b.type = 'button'; + b.className = 'sml'; + b.innerText = '-'; + b.onclick = (e) => { + r.remove(); + }; + r.appendChild(b); + l.appendChild(r); + rC++; + gId('+').style.display = gId("rml").childElementCount < 10 ? 'inline' : 'none'; // can't append to list anymore, hide button + } + -
+

@@ -202,11 +242,16 @@ Static subnet mask:
This firmware build does not include ESP-NOW support.
- Enable ESP-NOW:
+ Enable ESP-NOW:
Listen for events over ESP-NOW
- Keep disabled if not using a remote or wireless sync, increases power consumption.
- Paired Remote MAC:
- Last device seen: None
+ Keep disabled if not using a remote or ESP-NOW sync, increases power consumption.
+
+ Last device seen: None +
+ Linked MACs (10 max):
+
+
+
diff --git a/wled00/remote.cpp b/wled00/remote.cpp index 8c060a70..14c3c0d0 100644 --- a/wled00/remote.cpp +++ b/wled00/remote.cpp @@ -181,16 +181,10 @@ static bool remoteJson(int button) return parsed; } -// Callback function that will be executed when data is received +// Callback function that will be executed when data is received from a linked remote void handleWiZdata(uint8_t *incomingData, size_t len) { message_structure_t *incoming = reinterpret_cast(incomingData); - if (strcmp(last_signal_src, linked_remote) != 0) { - DEBUG_PRINT(F("ESP Now Message Received from Unlinked Sender: ")); - DEBUG_PRINTLN(last_signal_src); - return; - } - if (len != sizeof(message_structure_t)) { DEBUG_PRINTF_P(PSTR("Unknown incoming ESP Now message received of length %u\n"), len); return; diff --git a/wled00/set.cpp b/wled00/set.cpp index 72587502..501202c7 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -91,8 +91,21 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) bool oldESPNow = enableESPNow; enableESPNow = request->hasArg(F("RE")); if (oldESPNow != enableESPNow) forceReconnect = true; - strlcpy(linked_remote, request->arg(F("RMAC")).c_str(), 13); - strlwr(linked_remote); //Normalize MAC format to lowercase + linked_remotes.clear(); // clear old remotes + for (size_t n = 0; n < 10; n++) { + char rm[4]; + snprintf(rm, sizeof(rm), "RM%d", n); // "RM0" to "RM9" + if (request->hasArg(rm)) { + const String& arg = request->arg(rm); + if (arg.isEmpty()) continue; + std::array mac{}; + strlcpy(mac.data(), request->arg(rm).c_str(), 13); + strlwr(mac.data()); + if (mac[0] != '\0') { + linked_remotes.emplace_back(mac); + } + } + } #endif #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) diff --git a/wled00/udp.cpp b/wled00/udp.cpp index 4395b285..c2d450b9 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -959,14 +959,22 @@ void espNowReceiveCB(uint8_t* address, uint8_t* data, uint8_t len, signed int rs // usermods hook can override processing if (UsermodManager::onEspNowMessage(address, data, len)) return; - // handle WiZ Mote data - if (data[0] == 0x91 || data[0] == 0x81 || data[0] == 0x80) { - handleWiZdata(data, len); + bool knownRemote = false; + for (const auto& mac : linked_remotes) { + if (strlen(mac.data()) == 12 && strcmp(last_signal_src, mac.data()) == 0) { + knownRemote = true; + break; + } + } + if (!knownRemote) { + DEBUG_PRINT(F("ESP Now Message Received from Unlinked Sender: ")); + DEBUG_PRINTLN(last_signal_src); return; } - if (strlen(linked_remote) == 12 && strcmp(last_signal_src, linked_remote) != 0) { - DEBUG_PRINTLN(F("ESP-NOW unpaired remote sender.")); + // handle WiZ Mote data + if (data[0] == 0x91 || data[0] == 0x81 || data[0] == 0x80) { + handleWiZdata(data, len); return; } diff --git a/wled00/wled.h b/wled00/wled.h index f8dc1252..a74df05e 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -538,7 +538,8 @@ WLED_GLOBAL bool serialCanTX _INIT(false); WLED_GLOBAL bool enableESPNow _INIT(false); // global on/off for ESP-NOW WLED_GLOBAL byte statusESPNow _INIT(ESP_NOW_STATE_UNINIT); // state of ESP-NOW stack (0 uninitialised, 1 initialised, 2 error) WLED_GLOBAL bool useESPNowSync _INIT(false); // use ESP-NOW wireless technology for sync -WLED_GLOBAL char linked_remote[13] _INIT(""); // MAC of ESP-NOW remote (Wiz Mote) +//WLED_GLOBAL char linked_remote[13] _INIT(""); // MAC of ESP-NOW remote (Wiz Mote) +WLED_GLOBAL std::vector> linked_remotes; // MAC of ESP-NOW remotes (Wiz Mote) WLED_GLOBAL char last_signal_src[13] _INIT(""); // last seen ESP-NOW sender #endif diff --git a/wled00/xml.cpp b/wled00/xml.cpp index de2f5590..80e1bf12 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -216,7 +216,11 @@ void getSettingsJS(byte subPage, Print& settingsScript) #ifndef WLED_DISABLE_ESPNOW printSetFormCheckbox(settingsScript,PSTR("RE"),enableESPNow); - printSetFormValue(settingsScript,PSTR("RMAC"),linked_remote); + settingsScript.printf_P(PSTR("rstR();")); // reset remote list + for (size_t i = 0; i < linked_remotes.size(); i++) { + settingsScript.printf_P(PSTR("aR(\"RM%u\",\"%s\");"), i, linked_remotes[i].data()); // add remote to list + } + settingsScript.print(F("tE();")); // fill fields #else //hide remote settings if not compiled settingsScript.print(F("toggle('ESPNOW');")); // hide ESP-NOW setting @@ -258,10 +262,6 @@ void getSettingsJS(byte subPage, Print& settingsScript) #ifndef WLED_DISABLE_ESPNOW if (strlen(last_signal_src) > 0) { //Have seen an ESP-NOW Remote printSetClassElementHTML(settingsScript,PSTR("rlid"),0,last_signal_src); - } else if (!enableESPNow) { - printSetClassElementHTML(settingsScript,PSTR("rlid"),0,(char*)F("(Enable ESP-NOW to listen)")); - } else { - printSetClassElementHTML(settingsScript,PSTR("rlid"),0,(char*)F("None")); } #endif } From 25223c446fde50ac2064db324c4d0780e3141351 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 19 May 2025 20:48:00 +0200 Subject: [PATCH 432/463] fixed bouncing bug (#4694) --- wled00/FX.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 8835e71f..d50fd456 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -9540,10 +9540,10 @@ uint16_t mode_particleSparkler(void) { PartSys->sources[i].var = 0; // sparks stationary PartSys->sources[i].minLife = 150 + SEGMENT.intensity; PartSys->sources[i].maxLife = 250 + (SEGMENT.intensity << 1); - uint32_t speed = SEGMENT.speed >> 1; + int32_t speed = SEGMENT.speed >> 1; if (SEGMENT.check1) // sparks move (slide option) PartSys->sources[i].var = SEGMENT.intensity >> 3; - PartSys->sources[i].source.vx = speed; // update speed, do not change direction + PartSys->sources[i].source.vx = PartSys->sources[i].source.vx > 0 ? speed : -speed; // update speed, do not change direction PartSys->sources[i].source.ttl = 400; // replenish its life (setting it perpetual uses more code) PartSys->sources[i].sat = SEGMENT.custom1; // color saturation PartSys->sources[i].size = SEGMENT.check3 ? 120 : 0; From 999637f8adfec4fcef5ecfb41bd141c8ffba57bb Mon Sep 17 00:00:00 2001 From: Will Miles Date: Mon, 19 May 2025 16:37:07 -0400 Subject: [PATCH 433/463] Validate usermods at link time Add additional validation of the linker .map output to confirm that the correct usermods were added. --- pio-scripts/validate_usermods.py | 92 ++++++++++++++++++++++++++++++++ platformio.ini | 1 + 2 files changed, 93 insertions(+) create mode 100644 pio-scripts/validate_usermods.py diff --git a/pio-scripts/validate_usermods.py b/pio-scripts/validate_usermods.py new file mode 100644 index 00000000..50d51f99 --- /dev/null +++ b/pio-scripts/validate_usermods.py @@ -0,0 +1,92 @@ +import re +import sys +from pathlib import Path # For OS-agnostic path manipulation +from click import secho +from SCons.Script import Action, Exit +from platformio import util + +def read_lines(p: Path): + """ Read in the contents of a file for analysis """ + with p.open("r", encoding="utf-8", errors="ignore") as f: + return f.readlines() + +def check_map_file_objects(map_file: list[str], usermod_dirs: list[str]) -> set[str]: + """ Checks that an object file from each usermod_dir appears in the linked output + + Returns the (sub)set of usermod_dirs that are found in the output ELF + """ + # Pattern to match symbols in object directories + # Join directories into alternation + usermod_dir_regex = "|".join([re.escape(dir) for dir in usermod_dirs]) + # Matches nonzero address, any size, and any path in a matching directory + object_path_regex = re.compile(r"0x0*[1-9a-f][0-9a-f]*\s+0x[0-9a-f]+\s+\S+/(" + usermod_dir_regex + r")/\S+\.o") + + found = set() + for line in map_file: + matches = object_path_regex.findall(line) + for m in matches: + found.add(m) + return found + +def count_registered_usermods(map_file: list[str]) -> int: + """ Returns the number of usermod objects in the usermod list """ + # Count the number of entries in the usermods table section + return len([x for x in map_file if ".dtors.tbl.usermods.1" in x]) + + +def validate_map_file(source, target, env): + """ Validate that all usermods appear in the output build """ + build_dir = Path(env.subst("$BUILD_DIR")) + map_file_path = build_dir / env.subst("${PROGNAME}.map") + + if not map_file_path.exists(): + secho(f"ERROR: Map file not found: {map_file_path}", fg="red", err=True) + Exit(1) + + # Load project settings + usermods = env.GetProjectOption("custom_usermods","").split() + libdeps = env.GetProjectOption("lib_deps", []) + lib_builders = env.GetLibBuilders() + + secho(f"INFO: Expecting {len(usermods)} usermods: {', '.join(usermods)}") + + # Map the usermods to libdeps; every usermod should have one + usermod_dirs = [] + for mod in usermods: + modstr = f"{mod} = symlink://" + this_mod_libdeps = [libdep[len(modstr):] for libdep in libdeps if libdep.startswith(modstr)] + if not this_mod_libdeps: + secho( + f"ERROR: Usermod {mod} not found in build libdeps!", + fg="red", + err=True) + Exit(1) + # Save only the final folder name + usermod_dir = Path(this_mod_libdeps[0]).name + # Search lib_builders + this_mod_builders = [builder for builder in lib_builders if Path(builder.src_dir).name == usermod_dir] + if not this_mod_builders: + secho( + f"ERROR: Usermod {mod} not found in library builders!", + fg="red", + err=True) + Exit(1) + usermod_dirs.append(usermod_dir) + + # Now parse the map file + map_file_contents = read_lines(map_file_path) + confirmed_usermods = check_map_file_objects(map_file_contents, usermod_dirs) + usermod_object_count = count_registered_usermods(map_file_contents) + + secho(f"INFO: {len(usermod_dirs)}/{len(usermods)} libraries linked via custom_usermods, producing {usermod_object_count} usermod object entries") + missing_usermods = confirmed_usermods.difference(usermod_dirs) + if missing_usermods: + secho( + f"ERROR: No object files from {missing_usermods} found in linked output!", + fg="red", + err=True) + Exit(1) + return None + +Import("env") +env.AddPostAction("$BUILD_DIR/${PROGNAME}.elf", Action(validate_map_file, cmdstr='Checking map file...')) diff --git a/platformio.ini b/platformio.ini index a7485244..b713a2d3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -116,6 +116,7 @@ extra_scripts = pre:pio-scripts/user_config_copy.py pre:pio-scripts/load_usermods.py pre:pio-scripts/build_ui.py + post:pio-scripts/validate_usermods.py ;; double-check the build output usermods ; post:pio-scripts/obj-dump.py ;; convenience script to create a disassembly dump of the firmware (hardcore debugging) # ------------------------------------------------------------------------------ From 24ab2952ee50dc6bd13bf96eafc3584531631cb2 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Mon, 19 May 2025 16:53:08 -0400 Subject: [PATCH 434/463] Add unambiguous usermod list to info Neither the info panel nor the settings dialog can be trusted to accurately report the usermod list: - Not all usermods necessarily add to the info panel - Not all usermods necessarily add to the config page - #4609 is required for the config page to be correct Add a short list to the info object that lists the loaded usermod IDs. This is not displayed via the UI, but can be queried with curl or web debug tools. To be removed when usermod loading is working well. --- wled00/um_manager.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/wled00/um_manager.cpp b/wled00/um_manager.cpp index 9bfb7e73..1a7cc226 100644 --- a/wled00/um_manager.cpp +++ b/wled00/um_manager.cpp @@ -39,7 +39,13 @@ bool UsermodManager::getUMData(um_data_t **data, uint8_t mod_id) { return false; } void UsermodManager::addToJsonState(JsonObject& obj) { for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) (*mod)->addToJsonState(obj); } -void UsermodManager::addToJsonInfo(JsonObject& obj) { for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) (*mod)->addToJsonInfo(obj); } +void UsermodManager::addToJsonInfo(JsonObject& obj) { + auto um_id_list = obj.createNestedArray("um"); + for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) { + um_id_list.add((*mod)->getId()); + (*mod)->addToJsonInfo(obj); + } +} void UsermodManager::readFromJsonState(JsonObject& obj) { for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) (*mod)->readFromJsonState(obj); } void UsermodManager::addToConfig(JsonObject& obj) { for (auto mod = _usermod_table_begin; mod < _usermod_table_end; ++mod) (*mod)->addToConfig(obj); } bool UsermodManager::readFromConfig(JsonObject& obj) { From ac61eb4b1b2ff260381dad4284ecc734cdf7479d Mon Sep 17 00:00:00 2001 From: Will Miles Date: Mon, 19 May 2025 17:41:11 -0400 Subject: [PATCH 435/463] validate_usermods: Fix inverted check Difference direction was inverted. It's tough to test when it always works correctly on your local machine! H/t @coderabbitai --- pio-scripts/validate_usermods.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pio-scripts/validate_usermods.py b/pio-scripts/validate_usermods.py index 50d51f99..82ea5e07 100644 --- a/pio-scripts/validate_usermods.py +++ b/pio-scripts/validate_usermods.py @@ -79,7 +79,7 @@ def validate_map_file(source, target, env): usermod_object_count = count_registered_usermods(map_file_contents) secho(f"INFO: {len(usermod_dirs)}/{len(usermods)} libraries linked via custom_usermods, producing {usermod_object_count} usermod object entries") - missing_usermods = confirmed_usermods.difference(usermod_dirs) + missing_usermods = set(usermod_dirs).difference(confirmed_usermods) if missing_usermods: secho( f"ERROR: No object files from {missing_usermods} found in linked output!", From 817157bbc1d7c0c725e8c607ff207e6acb470df7 Mon Sep 17 00:00:00 2001 From: "Christian W. Zuckschwerdt" Date: Thu, 22 May 2025 09:36:41 +0200 Subject: [PATCH 436/463] Change to set LWT only once --- wled00/mqtt.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp index a462881e..dfa336d0 100644 --- a/wled00/mqtt.cpp +++ b/wled00/mqtt.cpp @@ -27,7 +27,7 @@ static void parseMQTTBriPayload(char* payload) static void onMqttConnect(bool sessionPresent) { //(re)subscribe to required topics - char subuf[MQTT_MAX_TOPIC_LEN + 6]; + char subuf[MQTT_MAX_TOPIC_LEN + 9]; if (mqttDeviceTopic[0] != 0) { strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); @@ -52,6 +52,13 @@ static void onMqttConnect(bool sessionPresent) UsermodManager::onMqttConnect(sessionPresent); DEBUG_PRINTLN(F("MQTT ready")); + +#ifndef USERMOD_SMARTNEST + strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); + strcat_P(subuf, PSTR("/status")); + mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT +#endif + publishMqtt(); } @@ -174,10 +181,6 @@ void publishMqtt() strcat_P(subuf, PSTR("/c")); mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263) - strlcpy(subuf, mqttDeviceTopic, MQTT_MAX_TOPIC_LEN + 1); - strcat_P(subuf, PSTR("/status")); - mqtt->publish(subuf, 0, true, "online"); // retain message for a LWT - // TODO: use a DynamicBufferList. Requires a list-read-capable MQTT client API. DynamicBuffer buf(1024); bufferPrint pbuf(buf.data(), buf.size()); From c693f63244e9e4bf8732349f86f7392dd0887f86 Mon Sep 17 00:00:00 2001 From: "Christian W. Zuckschwerdt" Date: Thu, 22 May 2025 13:36:55 +0200 Subject: [PATCH 437/463] Fix running initMqtt twice on bootup --- wled00/wled.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/wled00/wled.cpp b/wled00/wled.cpp index cc338d23..7de25354 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -738,9 +738,6 @@ void WLED::initInterfaces() e131.begin(e131Multicast, e131Port, e131Universe, E131_MAX_UNIVERSE_COUNT); ddp.begin(false, DDP_DEFAULT_PORT); reconnectHue(); -#ifndef WLED_DISABLE_MQTT - initMqtt(); -#endif interfacesInited = true; wasConnected = true; } From 358e38e0562b6082e26772d7407e8eed357a44a5 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Thu, 22 May 2025 08:41:59 -0400 Subject: [PATCH 438/463] validate_usermods: Ensure map file is created Not all of our platforms create one by default; ensure it's produced. --- pio-scripts/validate_usermods.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pio-scripts/validate_usermods.py b/pio-scripts/validate_usermods.py index 82ea5e07..1291a561 100644 --- a/pio-scripts/validate_usermods.py +++ b/pio-scripts/validate_usermods.py @@ -89,4 +89,4 @@ def validate_map_file(source, target, env): return None Import("env") -env.AddPostAction("$BUILD_DIR/${PROGNAME}.elf", Action(validate_map_file, cmdstr='Checking map file...')) +env.Append(LINKFLAGS=[env.subst("-Wl,--Map=${BUILD_DIR}/${PROGNAME}.map")]) From 242df4b04994110dd8351b85715558ccc67f5ab0 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Thu, 22 May 2025 08:43:52 -0400 Subject: [PATCH 439/463] validate_usermods: Fix old ESP32 platform The modern linker used with new platforms (ESP8266, ESP32 >v4) always produces paths in the map file with slash; however the old linker for the old ESP32 platform instead produces paths with backslash when building on Windows. Match both types as a path separator when scanning linked symbols. --- pio-scripts/validate_usermods.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pio-scripts/validate_usermods.py b/pio-scripts/validate_usermods.py index 1291a561..7b3bdf8e 100644 --- a/pio-scripts/validate_usermods.py +++ b/pio-scripts/validate_usermods.py @@ -19,7 +19,7 @@ def check_map_file_objects(map_file: list[str], usermod_dirs: list[str]) -> set[ # Join directories into alternation usermod_dir_regex = "|".join([re.escape(dir) for dir in usermod_dirs]) # Matches nonzero address, any size, and any path in a matching directory - object_path_regex = re.compile(r"0x0*[1-9a-f][0-9a-f]*\s+0x[0-9a-f]+\s+\S+/(" + usermod_dir_regex + r")/\S+\.o") + object_path_regex = re.compile(r"0x0*[1-9a-f][0-9a-f]*\s+0x[0-9a-f]+\s+\S+[/\\](" + usermod_dir_regex + r")[/\\]\S+\.o") found = set() for line in map_file: From 7ea510e75b666f2b12ecba2b0f2c5d8d3c1722e1 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Thu, 22 May 2025 08:44:05 -0400 Subject: [PATCH 440/463] validate_usermods: Improve message --- pio-scripts/validate_usermods.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pio-scripts/validate_usermods.py b/pio-scripts/validate_usermods.py index 7b3bdf8e..d3cf5ea8 100644 --- a/pio-scripts/validate_usermods.py +++ b/pio-scripts/validate_usermods.py @@ -90,3 +90,4 @@ def validate_map_file(source, target, env): Import("env") env.Append(LINKFLAGS=[env.subst("-Wl,--Map=${BUILD_DIR}/${PROGNAME}.map")]) +env.AddPostAction("$BUILD_DIR/${PROGNAME}.elf", Action(validate_map_file, cmdstr='Checking linked usermods in map file...')) From 792a7aa0815be4fc3a8e7779f5d0d93a49d3cc51 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Thu, 22 May 2025 09:13:54 -0400 Subject: [PATCH 441/463] load_usermods: Resolve folder paths Ensure all paths used in usermod symlinks are fully resolved, including any case correctness issues on Windows. Apparently PlatformIO does not handle symlink files correctly on Windows if there are case differences between cwd and the resolved path. --- pio-scripts/load_usermods.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pio-scripts/load_usermods.py b/pio-scripts/load_usermods.py index 8cf625ff..4e0457a0 100644 --- a/pio-scripts/load_usermods.py +++ b/pio-scripts/load_usermods.py @@ -7,7 +7,7 @@ from SCons.Script import Exit from platformio.builder.tools.piolib import LibBuilderBase from platformio.package.manager.library import LibraryPackageManager -usermod_dir = Path(env["PROJECT_DIR"]) / "usermods" +usermod_dir = Path(env["PROJECT_DIR"]).resolve() / "usermods" # "usermods" environment: expand list of usermods to everything in the folder if env['PIOENV'] == "usermods": @@ -48,7 +48,7 @@ if usermods: src_dir = proj.get("platformio", "src_dir") src_dir = src_dir.replace('\\','/') mod_paths = {mod: find_usermod(mod) for mod in usermods.split()} - usermods = [f"{mod} = symlink://{path}" for mod, path in mod_paths.items()] + usermods = [f"{mod} = symlink://{path.resolve()}" for mod, path in mod_paths.items()] proj.set("env:" + env['PIOENV'], 'lib_deps', deps + usermods) # Force usermods to be installed in to the environment build state before the LDF runs # Otherwise we won't be able to see them until it's too late to change their paths for LDF From 75cd411073ad9e6c984b0f9ffc0c4efae8bede33 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sat, 24 May 2025 14:13:08 -0400 Subject: [PATCH 442/463] Improve all-usermod handling Use a magic custom_usermods string instead of a magic environment name; and disable the validation script as it triggers on the non- platform-compatible mods. --- pio-scripts/load_usermods.py | 42 +++++++++----------------------- pio-scripts/validate_usermods.py | 5 ++-- platformio.ini | 2 +- 3 files changed, 16 insertions(+), 33 deletions(-) diff --git a/pio-scripts/load_usermods.py b/pio-scripts/load_usermods.py index 4e0457a0..4f986d6f 100644 --- a/pio-scripts/load_usermods.py +++ b/pio-scripts/load_usermods.py @@ -9,12 +9,6 @@ from platformio.package.manager.library import LibraryPackageManager usermod_dir = Path(env["PROJECT_DIR"]).resolve() / "usermods" -# "usermods" environment: expand list of usermods to everything in the folder -if env['PIOENV'] == "usermods": - # Add all usermods - all_usermods = [f for f in usermod_dir.iterdir() if f.is_dir() and f.joinpath('library.json').exists()] - env.GetProjectConfig().set(f"env:usermods", 'custom_usermods', " ".join([f.name for f in all_usermods])) - # Utility functions def find_usermod(mod: str) -> Path: """Locate this library in the usermods folder. @@ -41,38 +35,26 @@ def is_wled_module(dep: LibBuilderBase) -> bool: ## Script starts here # Process usermod option usermods = env.GetProjectOption("custom_usermods","") + +# Handle "all usermods" case +if usermods == '*': + usermods = [f.name for f in usermod_dir.iterdir() if f.is_dir() and f.joinpath('library.json').exists()] + # Update the environment, as many modules use scripts to detect their dependencies + env.GetProjectConfig().set("env:" + env['PIOENV'], 'custom_usermods', " ".join(usermods)) + # Leave a note for the validation script + env.GetProjectConfig().set("env:" + env['PIOENV'], 'custom_all_usermods_enabled', "1") +else: + usermods = usermods.split() + if usermods: # Inject usermods in to project lib_deps proj = env.GetProjectConfig() deps = env.GetProjectOption('lib_deps') src_dir = proj.get("platformio", "src_dir") src_dir = src_dir.replace('\\','/') - mod_paths = {mod: find_usermod(mod) for mod in usermods.split()} + mod_paths = {mod: find_usermod(mod) for mod in usermods} usermods = [f"{mod} = symlink://{path.resolve()}" for mod, path in mod_paths.items()] proj.set("env:" + env['PIOENV'], 'lib_deps', deps + usermods) - # Force usermods to be installed in to the environment build state before the LDF runs - # Otherwise we won't be able to see them until it's too late to change their paths for LDF - # Logic is largely borrowed from PlaformIO internals - not_found_specs = [] - for spec in usermods: - found = False - for storage_dir in env.GetLibSourceDirs(): - #print(f"Checking {storage_dir} for {spec}") - lm = LibraryPackageManager(storage_dir) - if lm.get_package(spec): - #print("Found!") - found = True - break - if not found: - #print("Missing!") - not_found_specs.append(spec) - if not_found_specs: - lm = LibraryPackageManager( - env.subst(os.path.join("$PROJECT_LIBDEPS_DIR", "$PIOENV")) - ) - for spec in not_found_specs: - #print(f"LU: forcing install of {spec}") - lm.install(spec) # Utility function for assembling usermod include paths diff --git a/pio-scripts/validate_usermods.py b/pio-scripts/validate_usermods.py index d3cf5ea8..a1a1e3c2 100644 --- a/pio-scripts/validate_usermods.py +++ b/pio-scripts/validate_usermods.py @@ -89,5 +89,6 @@ def validate_map_file(source, target, env): return None Import("env") -env.Append(LINKFLAGS=[env.subst("-Wl,--Map=${BUILD_DIR}/${PROGNAME}.map")]) -env.AddPostAction("$BUILD_DIR/${PROGNAME}.elf", Action(validate_map_file, cmdstr='Checking linked usermods in map file...')) +if not env.GetProjectOption("custom_all_usermods_enabled",""): # TODO: fix handling of platform mismatches + env.Append(LINKFLAGS=[env.subst("-Wl,--Map=${BUILD_DIR}/${PROGNAME}.map")]) + env.AddPostAction("$BUILD_DIR/${PROGNAME}.elf", Action(validate_map_file, cmdstr='Checking linked usermods in map file...')) diff --git a/platformio.ini b/platformio.ini index b713a2d3..e1a5014b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -660,5 +660,5 @@ build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_ lib_deps = ${esp32_idf_V4.lib_deps} monitor_filters = esp32_exception_decoder board_build.flash_mode = dio -; custom_usermods = *every folder with library.json* -- injected by pio-scripts/load_usermods.py +custom_usermods = * ; Expands to all usermods in usermods folder board_build.partitions = ${esp32.extreme_partitions} ; We're gonna need a bigger boat From 0a7d3a9d9b7437d940739c832f615481b708474a Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sat, 24 May 2025 22:16:01 -0400 Subject: [PATCH 443/463] load_usermods: Simplify load code Remove all the unnecessary bits. --- pio-scripts/load_usermods.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/pio-scripts/load_usermods.py b/pio-scripts/load_usermods.py index 4f986d6f..d50bf196 100644 --- a/pio-scripts/load_usermods.py +++ b/pio-scripts/load_usermods.py @@ -48,14 +48,8 @@ else: if usermods: # Inject usermods in to project lib_deps - proj = env.GetProjectConfig() - deps = env.GetProjectOption('lib_deps') - src_dir = proj.get("platformio", "src_dir") - src_dir = src_dir.replace('\\','/') - mod_paths = {mod: find_usermod(mod) for mod in usermods} - usermods = [f"{mod} = symlink://{path.resolve()}" for mod, path in mod_paths.items()] - proj.set("env:" + env['PIOENV'], 'lib_deps', deps + usermods) - + symlinks = [f"symlink://{find_usermod(mod).resolve()}" for mod in usermods] + env.GetProjectConfig().set("env:" + env['PIOENV'], 'lib_deps', env.GetProjectOption('lib_deps') + symlinks) # Utility function for assembling usermod include paths def cached_add_includes(dep, dep_cache: set, includes: deque): From 75c95d88e25698e09d5806f77249cdde1599cf3b Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sat, 24 May 2025 22:18:22 -0400 Subject: [PATCH 444/463] usermods/*/setup_deps.py: Check lib_deps for deps Check the safest possible location for final information on what components are actually being linked in. This demonstrates a safe approach that works even for out-of-tree modules. --- usermods/PWM_fan/setup_deps.py | 9 +++++---- usermods/seven_segment_display_reloaded/setup_deps.py | 7 ++++--- usermods/usermod_v2_rotary_encoder_ui_ALT/setup_deps.py | 6 +++--- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/usermods/PWM_fan/setup_deps.py b/usermods/PWM_fan/setup_deps.py index b8f7276c..11879079 100644 --- a/usermods/PWM_fan/setup_deps.py +++ b/usermods/PWM_fan/setup_deps.py @@ -1,11 +1,12 @@ +from platformio.package.meta import PackageSpec Import('env') -usermods = env.GetProjectOption("custom_usermods","").split() +libs = [PackageSpec(lib).name for lib in env.GetProjectOption("lib_deps",[])] # Check for dependencies -if "Temperature" in usermods: +if "Temperature" in libs: env.Append(CPPDEFINES=[("USERMOD_DALLASTEMPERATURE")]) -elif "sht" in usermods: +elif "sht" in libs: env.Append(CPPDEFINES=[("USERMOD_SHT")]) -elif "PWM_fan" in usermods: # The script can be run if this module was previously selected +elif "PWM_fan" in libs: # The script can be run if this module was previously selected raise RuntimeError("PWM_fan usermod requires Temperature or sht to be enabled") diff --git a/usermods/seven_segment_display_reloaded/setup_deps.py b/usermods/seven_segment_display_reloaded/setup_deps.py index dd28f5fe..1c51accc 100644 --- a/usermods/seven_segment_display_reloaded/setup_deps.py +++ b/usermods/seven_segment_display_reloaded/setup_deps.py @@ -1,9 +1,10 @@ +from platformio.package.meta import PackageSpec Import('env') -usermods = env.GetProjectOption("custom_usermods","").split() +libs = [PackageSpec(lib).name for lib in env.GetProjectOption("lib_deps",[])] # Check for partner usermods -if "SN_Photoresistor" in usermods: +if "SN_Photoresistor" in libs: env.Append(CPPDEFINES=[("USERMOD_SN_PHOTORESISTOR")]) -if any(mod in ("BH1750_v2", "BH1750") for mod in usermods): +if any(mod in ("BH1750_v2", "BH1750") for mod in libs): env.Append(CPPDEFINES=[("USERMOD_BH1750")]) diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/setup_deps.py b/usermods/usermod_v2_rotary_encoder_ui_ALT/setup_deps.py index a6b56595..ed579bc1 100644 --- a/usermods/usermod_v2_rotary_encoder_ui_ALT/setup_deps.py +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/setup_deps.py @@ -1,8 +1,8 @@ +from platformio.package.meta import PackageSpec Import('env') - -usermods = env.GetProjectOption("custom_usermods","").split() +libs = [PackageSpec(lib).name for lib in env.GetProjectOption("lib_deps",[])] # Check for partner usermod # Allow both "usermod_v2" and unqualified syntax -if any(mod in ("four_line_display_ALT", "usermod_v2_four_line_display_ALT") for mod in usermods): +if any(mod in ("four_line_display_ALT", "usermod_v2_four_line_display_ALT") for mod in libs): env.Append(CPPDEFINES=[("USERMOD_FOUR_LINE_DISPLAY")]) From 309c8d67f3e66298ceb2fcc74267865ecbd3b5a6 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sat, 24 May 2025 23:14:22 -0400 Subject: [PATCH 445/463] Generalize module link validation Perform validation for external modules, too. --- pio-scripts/load_usermods.py | 4 -- pio-scripts/validate_modules.py | 95 ++++++++++++++++++++++++++++++++ pio-scripts/validate_usermods.py | 94 ------------------------------- platformio.ini | 2 +- 4 files changed, 96 insertions(+), 99 deletions(-) create mode 100644 pio-scripts/validate_modules.py delete mode 100644 pio-scripts/validate_usermods.py diff --git a/pio-scripts/load_usermods.py b/pio-scripts/load_usermods.py index d50bf196..31e211fc 100644 --- a/pio-scripts/load_usermods.py +++ b/pio-scripts/load_usermods.py @@ -39,10 +39,6 @@ usermods = env.GetProjectOption("custom_usermods","") # Handle "all usermods" case if usermods == '*': usermods = [f.name for f in usermod_dir.iterdir() if f.is_dir() and f.joinpath('library.json').exists()] - # Update the environment, as many modules use scripts to detect their dependencies - env.GetProjectConfig().set("env:" + env['PIOENV'], 'custom_usermods', " ".join(usermods)) - # Leave a note for the validation script - env.GetProjectConfig().set("env:" + env['PIOENV'], 'custom_all_usermods_enabled', "1") else: usermods = usermods.split() diff --git a/pio-scripts/validate_modules.py b/pio-scripts/validate_modules.py new file mode 100644 index 00000000..eb6ebb44 --- /dev/null +++ b/pio-scripts/validate_modules.py @@ -0,0 +1,95 @@ +import re +import sys +from pathlib import Path # For OS-agnostic path manipulation +from typing import Iterable +from click import secho +from SCons.Script import Action, Exit +from platformio import util +from platformio.builder.tools.piolib import LibBuilderBase + + +def is_wled_module(env, dep: LibBuilderBase) -> bool: + """Returns true if the specified library is a wled module + """ + usermod_dir = Path(env["PROJECT_DIR"]).resolve() / "usermods" + return usermod_dir in Path(dep.src_dir).parents or str(dep.name).startswith("wled-") + + +def read_lines(p: Path): + """ Read in the contents of a file for analysis """ + with p.open("r", encoding="utf-8", errors="ignore") as f: + return f.readlines() + + +def check_map_file_objects(map_file: list[str], dirs: Iterable[str]) -> set[str]: + """ Identify which dirs contributed to the final build + + Returns the (sub)set of dirs that are found in the output ELF + """ + # Pattern to match symbols in object directories + # Join directories into alternation + usermod_dir_regex = "|".join([re.escape(dir) for dir in dirs]) + # Matches nonzero address, any size, and any path in a matching directory + object_path_regex = re.compile(r"0x0*[1-9a-f][0-9a-f]*\s+0x[0-9a-f]+\s+\S+[/\\](" + usermod_dir_regex + r")[/\\]\S+\.o") + + found = set() + for line in map_file: + matches = object_path_regex.findall(line) + for m in matches: + found.add(m) + return found + + +def count_usermod_objects(map_file: list[str]) -> int: + """ Returns the number of usermod objects in the usermod list """ + # Count the number of entries in the usermods table section + return len([x for x in map_file if ".dtors.tbl.usermods.1" in x]) + + +def validate_map_file(source, target, env): + """ Validate that all modules appear in the output build """ + build_dir = Path(env.subst("$BUILD_DIR")) + map_file_path = build_dir / env.subst("${PROGNAME}.map") + + if not map_file_path.exists(): + secho(f"ERROR: Map file not found: {map_file_path}", fg="red", err=True) + Exit(1) + + # Identify the WLED module source directories + module_lib_builders = [builder for builder in env.GetLibBuilders() if is_wled_module(env, builder)] + + if env.GetProjectOption("custom_usermods","") == "*": + # All usermods build; filter non-platform-OK modules + module_lib_builders = [builder for builder in module_lib_builders if env.IsCompatibleLibBuilder(builder)] + else: + incompatible_builders = [builder for builder in module_lib_builders if not env.IsCompatibleLibBuilder(builder)] + if incompatible_builders: + secho( + f"ERROR: Modules {[b.name for b in incompatible_builders]} are not compatible with this platform!", + fg="red", + err=True) + Exit(1) + pass + + # Extract the values we care about + modules = {Path(builder.build_dir).name: builder.name for builder in module_lib_builders} + secho(f"INFO: {len(modules)} libraries linked as WLED optional/user modules") + + # Now parse the map file + map_file_contents = read_lines(map_file_path) + usermod_object_count = count_usermod_objects(map_file_contents) + secho(f"INFO: {usermod_object_count} usermod object entries") + + confirmed_modules = check_map_file_objects(map_file_contents, modules.keys()) + missing_modules = [modname for mdir, modname in modules.items() if mdir not in confirmed_modules] + if missing_modules: + secho( + f"ERROR: No object files from {missing_modules} found in linked output!", + fg="red", + err=True) + Exit(1) + return None + +Import("env") +env.Append(LINKFLAGS=[env.subst("-Wl,--Map=${BUILD_DIR}/${PROGNAME}.map")]) +env.AddPostAction("$BUILD_DIR/${PROGNAME}.elf", Action(validate_map_file, cmdstr='Checking linked optional modules (usermods) in map file')) diff --git a/pio-scripts/validate_usermods.py b/pio-scripts/validate_usermods.py deleted file mode 100644 index a1a1e3c2..00000000 --- a/pio-scripts/validate_usermods.py +++ /dev/null @@ -1,94 +0,0 @@ -import re -import sys -from pathlib import Path # For OS-agnostic path manipulation -from click import secho -from SCons.Script import Action, Exit -from platformio import util - -def read_lines(p: Path): - """ Read in the contents of a file for analysis """ - with p.open("r", encoding="utf-8", errors="ignore") as f: - return f.readlines() - -def check_map_file_objects(map_file: list[str], usermod_dirs: list[str]) -> set[str]: - """ Checks that an object file from each usermod_dir appears in the linked output - - Returns the (sub)set of usermod_dirs that are found in the output ELF - """ - # Pattern to match symbols in object directories - # Join directories into alternation - usermod_dir_regex = "|".join([re.escape(dir) for dir in usermod_dirs]) - # Matches nonzero address, any size, and any path in a matching directory - object_path_regex = re.compile(r"0x0*[1-9a-f][0-9a-f]*\s+0x[0-9a-f]+\s+\S+[/\\](" + usermod_dir_regex + r")[/\\]\S+\.o") - - found = set() - for line in map_file: - matches = object_path_regex.findall(line) - for m in matches: - found.add(m) - return found - -def count_registered_usermods(map_file: list[str]) -> int: - """ Returns the number of usermod objects in the usermod list """ - # Count the number of entries in the usermods table section - return len([x for x in map_file if ".dtors.tbl.usermods.1" in x]) - - -def validate_map_file(source, target, env): - """ Validate that all usermods appear in the output build """ - build_dir = Path(env.subst("$BUILD_DIR")) - map_file_path = build_dir / env.subst("${PROGNAME}.map") - - if not map_file_path.exists(): - secho(f"ERROR: Map file not found: {map_file_path}", fg="red", err=True) - Exit(1) - - # Load project settings - usermods = env.GetProjectOption("custom_usermods","").split() - libdeps = env.GetProjectOption("lib_deps", []) - lib_builders = env.GetLibBuilders() - - secho(f"INFO: Expecting {len(usermods)} usermods: {', '.join(usermods)}") - - # Map the usermods to libdeps; every usermod should have one - usermod_dirs = [] - for mod in usermods: - modstr = f"{mod} = symlink://" - this_mod_libdeps = [libdep[len(modstr):] for libdep in libdeps if libdep.startswith(modstr)] - if not this_mod_libdeps: - secho( - f"ERROR: Usermod {mod} not found in build libdeps!", - fg="red", - err=True) - Exit(1) - # Save only the final folder name - usermod_dir = Path(this_mod_libdeps[0]).name - # Search lib_builders - this_mod_builders = [builder for builder in lib_builders if Path(builder.src_dir).name == usermod_dir] - if not this_mod_builders: - secho( - f"ERROR: Usermod {mod} not found in library builders!", - fg="red", - err=True) - Exit(1) - usermod_dirs.append(usermod_dir) - - # Now parse the map file - map_file_contents = read_lines(map_file_path) - confirmed_usermods = check_map_file_objects(map_file_contents, usermod_dirs) - usermod_object_count = count_registered_usermods(map_file_contents) - - secho(f"INFO: {len(usermod_dirs)}/{len(usermods)} libraries linked via custom_usermods, producing {usermod_object_count} usermod object entries") - missing_usermods = set(usermod_dirs).difference(confirmed_usermods) - if missing_usermods: - secho( - f"ERROR: No object files from {missing_usermods} found in linked output!", - fg="red", - err=True) - Exit(1) - return None - -Import("env") -if not env.GetProjectOption("custom_all_usermods_enabled",""): # TODO: fix handling of platform mismatches - env.Append(LINKFLAGS=[env.subst("-Wl,--Map=${BUILD_DIR}/${PROGNAME}.map")]) - env.AddPostAction("$BUILD_DIR/${PROGNAME}.elf", Action(validate_map_file, cmdstr='Checking linked usermods in map file...')) diff --git a/platformio.ini b/platformio.ini index e1a5014b..9bdf58d3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -116,7 +116,7 @@ extra_scripts = pre:pio-scripts/user_config_copy.py pre:pio-scripts/load_usermods.py pre:pio-scripts/build_ui.py - post:pio-scripts/validate_usermods.py ;; double-check the build output usermods + post:pio-scripts/validate_modules.py ;; double-check the build output usermods ; post:pio-scripts/obj-dump.py ;; convenience script to create a disassembly dump of the firmware (hardcore debugging) # ------------------------------------------------------------------------------ From e80a7c6b757a6c17b58a224c6442ce010fb41993 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sat, 24 May 2025 23:15:36 -0400 Subject: [PATCH 446/463] usermod_v2_HttpPullLightControl: Add usermod object The module instance was missing. --- .../usermod_v2_HttpPullLightControl.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/usermods/usermod_v2_HttpPullLightControl/usermod_v2_HttpPullLightControl.cpp b/usermods/usermod_v2_HttpPullLightControl/usermod_v2_HttpPullLightControl.cpp index b908b057..44a2726e 100644 --- a/usermods/usermod_v2_HttpPullLightControl/usermod_v2_HttpPullLightControl.cpp +++ b/usermods/usermod_v2_HttpPullLightControl/usermod_v2_HttpPullLightControl.cpp @@ -4,6 +4,9 @@ const char HttpPullLightControl::_name[] PROGMEM = "HttpPullLightControl"; const char HttpPullLightControl::_enabled[] PROGMEM = "Enable"; +static HttpPullLightControl http_pull_usermod; +REGISTER_USERMOD(http_pull_usermod); + void HttpPullLightControl::setup() { //Serial.begin(115200); From f3623158d7051ef792bf3f3243ebee90fba794e9 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 25 May 2025 08:33:27 -0400 Subject: [PATCH 447/463] Usermod script cleanup Fix whitespace and remove unused imports --- pio-scripts/load_usermods.py | 8 +++----- pio-scripts/validate_modules.py | 11 ++++------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/pio-scripts/load_usermods.py b/pio-scripts/load_usermods.py index 31e211fc..146cb1f8 100644 --- a/pio-scripts/load_usermods.py +++ b/pio-scripts/load_usermods.py @@ -1,11 +1,9 @@ Import('env') -import os.path from collections import deque from pathlib import Path # For OS-agnostic path manipulation from click import secho from SCons.Script import Exit from platformio.builder.tools.piolib import LibBuilderBase -from platformio.package.manager.library import LibraryPackageManager usermod_dir = Path(env["PROJECT_DIR"]).resolve() / "usermods" @@ -21,7 +19,7 @@ def find_usermod(mod: str) -> Path: return mp mp = usermod_dir / f"{mod}_v2" if mp.exists(): - return mp + return mp mp = usermod_dir / f"usermod_v2_{mod}" if mp.exists(): return mp @@ -50,7 +48,7 @@ if usermods: # Utility function for assembling usermod include paths def cached_add_includes(dep, dep_cache: set, includes: deque): """ Add dep's include paths to includes if it's not in the cache """ - if dep not in dep_cache: + if dep not in dep_cache: dep_cache.add(dep) for include in dep.get_include_dirs(): if include not in includes: @@ -96,7 +94,7 @@ def wrapped_ConfigureProjectLibBuilder(xenv): secho( f"ERROR: libArchive=false is missing on usermod(s) {' '.join(broken_usermods)} -- modules will not compile in correctly", fg="red", - err=True) + err=True) Exit(1) return result diff --git a/pio-scripts/validate_modules.py b/pio-scripts/validate_modules.py index eb6ebb44..f8c9a599 100644 --- a/pio-scripts/validate_modules.py +++ b/pio-scripts/validate_modules.py @@ -1,10 +1,8 @@ import re -import sys from pathlib import Path # For OS-agnostic path manipulation from typing import Iterable from click import secho from SCons.Script import Action, Exit -from platformio import util from platformio.builder.tools.piolib import LibBuilderBase @@ -56,8 +54,8 @@ def validate_map_file(source, target, env): Exit(1) # Identify the WLED module source directories - module_lib_builders = [builder for builder in env.GetLibBuilders() if is_wled_module(env, builder)] - + module_lib_builders = [builder for builder in env.GetLibBuilders() if is_wled_module(env, builder)] + if env.GetProjectOption("custom_usermods","") == "*": # All usermods build; filter non-platform-OK modules module_lib_builders = [builder for builder in module_lib_builders if env.IsCompatibleLibBuilder(builder)] @@ -68,8 +66,7 @@ def validate_map_file(source, target, env): f"ERROR: Modules {[b.name for b in incompatible_builders]} are not compatible with this platform!", fg="red", err=True) - Exit(1) - pass + Exit(1) # Extract the values we care about modules = {Path(builder.build_dir).name: builder.name for builder in module_lib_builders} @@ -77,7 +74,7 @@ def validate_map_file(source, target, env): # Now parse the map file map_file_contents = read_lines(map_file_path) - usermod_object_count = count_usermod_objects(map_file_contents) + usermod_object_count = count_usermod_objects(map_file_contents) secho(f"INFO: {usermod_object_count} usermod object entries") confirmed_modules = check_map_file_objects(map_file_contents, modules.keys()) From a87b562bc27d4caa636233c9bbc35b72be123ae8 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Fri, 6 Jun 2025 17:05:16 +0200 Subject: [PATCH 448/463] update to distortionwave FX (#4693) - fixed "jumpyness" by improving offset calculation resolution - added palette support - added two rendering modes for use with palette: one uses hue-mapping, one uses brightness mapping - added alternate animation mode (from initial source) - extended scaling: zoom checkmark (depends on matrix size) --- wled00/FX.cpp | 63 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index e4c93a02..7b07cc61 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7407,7 +7407,7 @@ static const char _data_FX_MODE_2DAKEMI[] PROGMEM = "Akemi@Color speed,Dance;Hea // Distortion waves - ldirko // https://editor.soulmatelights.com/gallery/1089-distorsion-waves -// adapted for WLED by @blazoncek +// adapted for WLED by @blazoncek, improvements by @dedehai uint16_t mode_2Ddistortionwaves() { if (!strip.isMatrix || !SEGMENT.is2D()) return mode_static(); // not a 2D set-up @@ -7416,20 +7416,23 @@ uint16_t mode_2Ddistortionwaves() { uint8_t speed = SEGMENT.speed/32; uint8_t scale = SEGMENT.intensity/32; - - uint8_t w = 2; + if(SEGMENT.check2) scale += 192 / (cols+rows); // zoom out some more. note: not changing scale slider for backwards compatibility unsigned a = strip.now/32; unsigned a2 = a/2; unsigned a3 = a/3; + unsigned colsScaled = cols * scale; + unsigned rowsScaled = rows * scale; + + unsigned cx = beatsin16_t(10-speed,0,colsScaled); + unsigned cy = beatsin16_t(12-speed,0,rowsScaled); + unsigned cx1 = beatsin16_t(13-speed,0,colsScaled); + unsigned cy1 = beatsin16_t(15-speed,0,rowsScaled); + unsigned cx2 = beatsin16_t(17-speed,0,colsScaled); + unsigned cy2 = beatsin16_t(14-speed,0,rowsScaled); + + byte rdistort, gdistort, bdistort; - unsigned cx = beatsin8_t(10-speed,0,cols-1)*scale; - unsigned cy = beatsin8_t(12-speed,0,rows-1)*scale; - unsigned cx1 = beatsin8_t(13-speed,0,cols-1)*scale; - unsigned cy1 = beatsin8_t(15-speed,0,rows-1)*scale; - unsigned cx2 = beatsin8_t(17-speed,0,cols-1)*scale; - unsigned cy2 = beatsin8_t(14-speed,0,rows-1)*scale; - unsigned xoffs = 0; for (int x = 0; x < cols; x++) { xoffs += scale; @@ -7438,25 +7441,49 @@ uint16_t mode_2Ddistortionwaves() { for (int y = 0; y < rows; y++) { yoffs += scale; - byte rdistort = cos8_t((cos8_t(((x<<3)+a )&255)+cos8_t(((y<<3)-a2)&255)+a3 )&255)>>1; - byte gdistort = cos8_t((cos8_t(((x<<3)-a2)&255)+cos8_t(((y<<3)+a3)&255)+a+32 )&255)>>1; - byte bdistort = cos8_t((cos8_t(((x<<3)+a3)&255)+cos8_t(((y<<3)-a) &255)+a2+64)&255)>>1; + if(SEGMENT.check3) { + // alternate mode from original code + rdistort = cos8_t (((x+y)*8+a2)&255)>>1; + gdistort = cos8_t (((x+y)*8+a3+32)&255)>>1; + bdistort = cos8_t (((x+y)*8+a+64)&255)>>1; + } else { + rdistort = cos8_t((cos8_t(((x<<3)+a )&255)+cos8_t(((y<<3)-a2)&255)+a3 )&255)>>1; + gdistort = cos8_t((cos8_t(((x<<3)-a2)&255)+cos8_t(((y<<3)+a3)&255)+a+32 )&255)>>1; + bdistort = cos8_t((cos8_t(((x<<3)+a3)&255)+cos8_t(((y<<3)-a) &255)+a2+64)&255)>>1; + } - byte valueR = rdistort+ w* (a- ( ((xoffs - cx) * (xoffs - cx) + (yoffs - cy) * (yoffs - cy))>>7 )); - byte valueG = gdistort+ w* (a2-( ((xoffs - cx1) * (xoffs - cx1) + (yoffs - cy1) * (yoffs - cy1))>>7 )); - byte valueB = bdistort+ w* (a3-( ((xoffs - cx2) * (xoffs - cx2) + (yoffs - cy2) * (yoffs - cy2))>>7 )); + byte valueR = rdistort + ((a- ( ((xoffs - cx) * (xoffs - cx) + (yoffs - cy) * (yoffs - cy))>>7 ))<<1); + byte valueG = gdistort + ((a2-( ((xoffs - cx1) * (xoffs - cx1) + (yoffs - cy1) * (yoffs - cy1))>>7 ))<<1); + byte valueB = bdistort + ((a3-( ((xoffs - cx2) * (xoffs - cx2) + (yoffs - cy2) * (yoffs - cy2))>>7 ))<<1); valueR = gamma8(cos8_t(valueR)); valueG = gamma8(cos8_t(valueG)); valueB = gamma8(cos8_t(valueB)); - SEGMENT.setPixelColorXY(x, y, RGBW32(valueR, valueG, valueB, 0)); + if(SEGMENT.palette == 0) { + // use RGB values (original color mode) + SEGMENT.setPixelColorXY(x, y, RGBW32(valueR, valueG, valueB, 0)); + } else { + // use palette + uint8_t brightness = (valueR + valueG + valueB) / 3; + if(SEGMENT.check1) { // map brightness to palette index + SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, brightness, 255, LINEARBLEND_NOWRAP)); + } else { + // color mapping: calculate hue from pixel color, map it to palette index + CHSV hsvclr = rgb2hsv_approximate(CRGB(valueR>>2, valueG>>2, valueB>>2)); // scale colors down to not saturate for better hue extraction + SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, hsvclr.h, brightness)); + } + } } } + // palette mode and not filling: smear-blur to cover up palette wrapping artefacts + if(!SEGMENT.check1 && SEGMENT.palette) + SEGMENT.blur(200, true); + return FRAMETIME; } -static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@!,Scale;;;2"; +static const char _data_FX_MODE_2DDISTORTIONWAVES[] PROGMEM = "Distortion Waves@!,Scale,,,,Fill,Zoom,Alt;;!;2;pal=0"; //Soap From 8b65d873b3013427f4e48dcdbd562830a2ada0ae Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 7 Jun 2025 13:15:45 +0200 Subject: [PATCH 449/463] fix particle brightness distribution with new gamma correction (#4710) Particle System depends on linear brightness distribution, gamma corrected values are non-linear. - added invers gamma table - reversing gamma after brightness distribution makes it linear once again --- wled00/FXparticleSystem.cpp | 18 +++++++++++++++++- wled00/cfg.cpp | 2 +- wled00/colors.cpp | 7 +++++-- wled00/fcn_declare.h | 5 ++++- wled00/set.cpp | 2 +- 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/wled00/FXparticleSystem.cpp b/wled00/FXparticleSystem.cpp index 85264b7f..bc664174 100644 --- a/wled00/FXparticleSystem.cpp +++ b/wled00/FXparticleSystem.cpp @@ -584,7 +584,7 @@ void ParticleSystem2D::render() { continue; // generate RGB values for particle if (fireIntesity) { // fire mode - brightness = (uint32_t)particles[i].ttl * (3 + (fireIntesity >> 5)) + 20; + brightness = (uint32_t)particles[i].ttl * (3 + (fireIntesity >> 5)) + 5; brightness = min(brightness, (uint32_t)255); baseRGB = ColorFromPaletteWLED(SEGPALETTE, brightness, 255, LINEARBLEND_NOWRAP); } @@ -600,6 +600,7 @@ void ParticleSystem2D::render() { baseRGB = (CRGB)tempcolor; } } + brightness = gamma8(brightness); // apply gamma correction, used for gamma-inverted brightness distribution renderParticle(i, brightness, baseRGB, particlesettings.wrapX, particlesettings.wrapY); } @@ -676,6 +677,14 @@ __attribute__((optimize("O2"))) void ParticleSystem2D::renderParticle(const uint pxlbrightness[1] = (dx * precal2) >> PS_P_SURFACE; // bottom right value equal to (dx * (PS_P_RADIUS-dy) * brightness) >> PS_P_SURFACE pxlbrightness[2] = (dx * precal3) >> PS_P_SURFACE; // top right value equal to (dx * dy * brightness) >> PS_P_SURFACE pxlbrightness[3] = (precal1 * precal3) >> PS_P_SURFACE; // top left value equal to ((PS_P_RADIUS-dx) * dy * brightness) >> PS_P_SURFACE + // adjust brightness such that distribution is linear after gamma correction: + // - scale brigthness with gamma correction (done in render()) + // - apply inverse gamma correction to brightness values + // - gamma is applied again in show() -> the resulting brightness distribution is linear but gamma corrected in total + pxlbrightness[0] = gamma8inv(pxlbrightness[0]); // use look-up-table for invers gamma + pxlbrightness[1] = gamma8inv(pxlbrightness[1]); + pxlbrightness[2] = gamma8inv(pxlbrightness[2]); + pxlbrightness[3] = gamma8inv(pxlbrightness[3]); if (advPartProps && advPartProps[particleindex].size > 1) { //render particle to a bigger size CRGB renderbuffer[100]; // 10x10 pixel buffer @@ -1467,6 +1476,7 @@ void ParticleSystem1D::render() { baseRGB = (CRGB)tempcolor; } } + brightness = gamma8(brightness); // apply gamma correction, used for gamma-inverted brightness distribution renderParticle(i, brightness, baseRGB, particlesettings.wrap); } // apply smear-blur to rendered frame @@ -1534,6 +1544,12 @@ __attribute__((optimize("O2"))) void ParticleSystem1D::renderParticle(const uint //calculate the brightness values for both pixels using linear interpolation (note: in standard rendering out of frame pixels could be skipped but if checks add more clock cycles over all) pxlbrightness[0] = (((int32_t)PS_P_RADIUS_1D - dx) * brightness) >> PS_P_SURFACE_1D; pxlbrightness[1] = (dx * brightness) >> PS_P_SURFACE_1D; + // adjust brightness such that distribution is linear after gamma correction: + // - scale brigthness with gamma correction (done in render()) + // - apply inverse gamma correction to brightness values + // - gamma is applied again in show() -> the resulting brightness distribution is linear but gamma corrected in total + pxlbrightness[0] = gamma8inv(pxlbrightness[0]); // use look-up-table for invers gamma + pxlbrightness[1] = gamma8inv(pxlbrightness[1]); // check if particle has advanced size properties and buffer is available if (advPartProps && advPartProps[particleindex].size > 1) { diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index de4aa118..72ace8db 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -532,7 +532,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { gammaCorrectBri = false; gammaCorrectCol = false; } - NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table + NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up tables JsonObject light_tr = light["tr"]; int tdd = light_tr["dur"] | -1; diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 3b3d9ab7..ff6f3ab5 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -564,14 +564,17 @@ uint16_t approximateKelvinFromRGB(uint32_t rgb) { } } -// gamma lookup table used for color correction (filled on 1st use (cfg.cpp & set.cpp)) +// gamma lookup tables used for color correction (filled on 1st use (cfg.cpp & set.cpp)) uint8_t NeoGammaWLEDMethod::gammaT[256]; +uint8_t NeoGammaWLEDMethod::gammaT_inv[256]; -// re-calculates & fills gamma table +// re-calculates & fills gamma tables void NeoGammaWLEDMethod::calcGammaTable(float gamma) { + float gamma_inv = 1.0f / gamma; // inverse gamma for (size_t i = 0; i < 256; i++) { gammaT[i] = (int)(powf((float)i / 255.0f, gamma) * 255.0f + 0.5f); + gammaT_inv[i] = (int)(powf((float)i / 255.0f, gamma_inv) * 255.0f + 0.5f); } } diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 486e5c56..8e4233f2 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -158,13 +158,16 @@ class NeoGammaWLEDMethod { public: [[gnu::hot]] static uint8_t Correct(uint8_t value); // apply Gamma to single channel [[gnu::hot]] static uint32_t Correct32(uint32_t color); // apply Gamma to RGBW32 color (WLED specific, not used by NPB) - static void calcGammaTable(float gamma); // re-calculates & fills gamma table + static void calcGammaTable(float gamma); // re-calculates & fills gamma tables static inline uint8_t rawGamma8(uint8_t val) { return gammaT[val]; } // get value from Gamma table (WLED specific, not used by NPB) + static inline uint8_t rawInverseGamma8(uint8_t val) { return gammaT_inv[val]; } // get value from inverse Gamma table (WLED specific, not used by NPB) private: static uint8_t gammaT[]; + static uint8_t gammaT_inv[]; }; #define gamma32(c) NeoGammaWLEDMethod::Correct32(c) #define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c) +#define gamma8inv(c) NeoGammaWLEDMethod::rawInverseGamma8(c) [[gnu::hot, gnu::pure]] uint32_t color_blend(uint32_t c1, uint32_t c2 , uint8_t blend); inline uint32_t color_blend16(uint32_t c1, uint32_t c2, uint16_t b) { return color_blend(c1, c2, b >> 8); }; [[gnu::hot, gnu::pure]] uint32_t color_add(uint32_t, uint32_t, bool preserveCR = false); diff --git a/wled00/set.cpp b/wled00/set.cpp index 038e84b4..6229ba28 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -341,7 +341,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) gammaCorrectBri = false; gammaCorrectCol = false; } - NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table + NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up tables t = request->arg(F("TD")).toInt(); if (t >= 0) transitionDelayDefault = t; From ab28b6d58fad3636dbbe9bc0e83ad314d9b4a3d5 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sat, 7 Jun 2025 11:08:11 -0400 Subject: [PATCH 450/463] Update crude parallel I2S detection My ESP32s are now reporting a maximum of 32 buses. --- wled00/data/settings_leds.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index d5151231..66bc2f00 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -353,7 +353,7 @@ }); const S2 = (oMaxB == 14) && (maxV == 4); const S3 = (oMaxB == 14) && (maxV == 6); - if (oMaxB == 19 || S2 || S3) { // TODO: crude ESP32 & S2/S3 detection + if (oMaxB == 32 || S2 || S3) { // TODO: crude ESP32 & S2/S3 detection if (maxLC > 300 || dC <= 2) { d.Sf["PR"].checked = false; gId("prl").classList.add("hide"); From fc7d4dfcb0b3ca44195c39afbbd7231f0a6569e3 Mon Sep 17 00:00:00 2001 From: mryndzionek Date: Sun, 8 Jun 2025 10:52:58 +0200 Subject: [PATCH 451/463] Added new "effect usermod" - Added new effect - Diffusion Fire - UM is intended as a base / tutorial (work in progress) --- usermods/user_fx/README.md | 4 ++ usermods/user_fx/library.json | 3 + usermods/user_fx/user_fx.cpp | 116 ++++++++++++++++++++++++++++++++++ wled00/const.h | 1 + 4 files changed, 124 insertions(+) create mode 100644 usermods/user_fx/README.md create mode 100644 usermods/user_fx/library.json create mode 100644 usermods/user_fx/user_fx.cpp diff --git a/usermods/user_fx/README.md b/usermods/user_fx/README.md new file mode 100644 index 00000000..8dc1d128 --- /dev/null +++ b/usermods/user_fx/README.md @@ -0,0 +1,4 @@ +# Usermod user FX + +This Usermod is a common place to put various user's LED effects. + diff --git a/usermods/user_fx/library.json b/usermods/user_fx/library.json new file mode 100644 index 00000000..9420eecd --- /dev/null +++ b/usermods/user_fx/library.json @@ -0,0 +1,3 @@ +{ + "name": "user_fx" +} diff --git a/usermods/user_fx/user_fx.cpp b/usermods/user_fx/user_fx.cpp new file mode 100644 index 00000000..7d8fc308 --- /dev/null +++ b/usermods/user_fx/user_fx.cpp @@ -0,0 +1,116 @@ +#include "wled.h" + +// for information how FX metadata strings work see https://kno.wled.ge/interfaces/json-api/#effect-metadata + +// static effect, used if an effect fails to initialize +static uint16_t mode_static(void) { + SEGMENT.fill(SEGCOLOR(0)); + return strip.isOffRefreshRequired() ? FRAMETIME : 350; +} + +///////////////////////// +// User FX functions // +///////////////////////// + +// Diffusion Fire: fire effect intended for 2D setups smaller than 16x16 +static uint16_t mode_diffusionfire(void) { + if (!strip.isMatrix || !SEGMENT.is2D()) + return mode_static(); // not a 2D set-up + + const int cols = SEG_W; + const int rows = SEG_H; + const auto XY = [&](int x, int y) { return x + y * cols; }; + + const uint8_t refresh_hz = map(SEGMENT.speed, 0, 255, 20, 80); + const unsigned refresh_ms = 1000 / refresh_hz; + const int16_t diffusion = map(SEGMENT.custom1, 0, 255, 0, 100); + const uint8_t spark_rate = SEGMENT.intensity; + const uint8_t turbulence = SEGMENT.custom2; + + unsigned dataSize = SEGMENT.length(); // allocate persistent data for heat value for each pixel + if (!SEGENV.allocateData(dataSize)) + return mode_static(); // allocation failed + + if (SEGENV.call == 0) { + SEGMENT.fill(BLACK); + SEGENV.step = 0; + } + + if ((strip.now - SEGENV.step) >= refresh_ms) { + uint8_t tmp_row[cols]; + SEGENV.step = strip.now; + // scroll up + for (unsigned y = 1; y < rows; y++) + for (unsigned x = 0; x < cols; x++) { + unsigned src = XY(x, y); + unsigned dst = XY(x, y - 1); + SEGMENT.data[dst] = SEGMENT.data[src]; + } + + if (hw_random8() > turbulence) { + // create new sparks at bottom row + for (unsigned x = 0; x < cols; x++) { + uint8_t p = hw_random8(); + if (p < spark_rate) { + unsigned dst = XY(x, rows - 1); + SEGMENT.data[dst] = 255; + } + } + } + + // diffuse + for (unsigned y = 0; y < rows; y++) { + for (unsigned x = 0; x < cols; x++) { + unsigned v = SEGMENT.data[XY(x, y)]; + if (x > 0) { + v += SEGMENT.data[XY(x - 1, y)]; + } + if (x < (cols - 1)) { + v += SEGMENT.data[XY(x + 1, y)]; + } + tmp_row[x] = min(255, (int)(v * 100 / (300 + diffusion))); + } + + for (unsigned x = 0; x < cols; x++) { + SEGMENT.data[XY(x, y)] = tmp_row[x]; + if (SEGMENT.check1) { + uint32_t color = ColorFromPalette(SEGPALETTE, tmp_row[x], 255, LINEARBLEND_NOWRAP); + SEGMENT.setPixelColorXY(x, y, color); + } else { + uint32_t color = SEGCOLOR(0); + SEGMENT.setPixelColorXY(x, y, color_fade(color, tmp_row[x])); + } + } + } + } + return FRAMETIME; +} +static const char _data_FX_MODE_DIFFUSIONFIRE[] PROGMEM = "Diffusion Fire@!,Spark rate,Diffusion Speed,Turbulence,,Use palette;;Color;;2;pal=35"; + + +///////////////////// +// UserMod Class // +///////////////////// + +class UserFxUsermod : public Usermod { + private: + public: + void setup() override { + strip.addEffect(255, &mode_diffusionfire, _data_FX_MODE_DIFFUSIONFIRE); + + //////////////////////////////////////// + // add your effect function(s) here // + //////////////////////////////////////// + + // use id=255 for all custom user FX (the final id is assigned when adding the effect) + + // strip.addEffect(255, &mode_your_effect, _data_FX_MODE_YOUR_EFFECT); + // strip.addEffect(255, &mode_your_effect2, _data_FX_MODE_YOUR_EFFECT2); + // strip.addEffect(255, &mode_your_effect3, _data_FX_MODE_YOUR_EFFECT3); + } + void loop() override {} // nothing to do in the loop + uint16_t getId() override { return USERMOD_ID_USER_FX; } +}; + +static UserFxUsermod user_fx; +REGISTER_USERMOD(user_fx); diff --git a/wled00/const.h b/wled00/const.h index cfcd0a6b..c19843c4 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -198,6 +198,7 @@ static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit"); #define USERMOD_ID_DEEP_SLEEP 55 //Usermod "usermod_deep_sleep.h" #define USERMOD_ID_RF433 56 //Usermod "usermod_v2_RF433.h" #define USERMOD_ID_BRIGHTNESS_FOLLOW_SUN 57 //Usermod "usermod_v2_brightness_follow_sun.h" +#define USERMOD_ID_USER_FX 58 //Usermod "user_fx" //Access point behavior #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot From 00eb4068b0ce7d2e9868bf5cc73366415981164c Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 8 Jun 2025 13:01:52 +0200 Subject: [PATCH 452/463] add pre-applied gamma to c3g & fastled palettes to match original look (#4711) --- wled00/palettes.h | 644 ++++++++++++++++++++++++---------------------- wled00/wled.h | 2 +- 2 files changed, 337 insertions(+), 309 deletions(-) diff --git a/wled00/palettes.h b/wled00/palettes.h index 70cf8418..a77540fd 100755 --- a/wled00/palettes.h +++ b/wled00/palettes.h @@ -2,106 +2,109 @@ #define PalettesWLED_h /* - * Color palettes for FastLED effects (65-73). + * WLED Color palettes + * + * Note: palettes imported from http://seaviewsensing.com/pub/cpt-city are gamma corrected using gammas (1.182, 1.0, 1.136) + * this is done to match colors of the palettes after applying the (default) global gamma of 2.2 to versions + * prior to WLED 0.16 which used pre-applied gammas of (2.6,2.2,2.5) for these palettes. + * Palettes from FastLED are intended to be used without gamma correction, an inverse gamma of 2.2 is applied to original colors */ -// From ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb -// Unfortunately, these are stored in RAM! - // Gradient palette "ib_jul01_gp", originally from // http://seaviewsensing.com/pub/cpt-city/ing/xmas/ib_jul01.c3g const uint8_t ib_jul01_gp[] PROGMEM = { - 0, 230, 6, 17, - 94, 37, 96, 90, - 132, 144, 189, 106, - 255, 187, 3, 13}; + 0, 226, 6, 12, + 94, 26, 96, 78, + 132, 130, 189, 94, + 255, 177, 3, 9}; // Gradient palette "es_vintage_57_gp", originally from // http://seaviewsensing.com/pub/cpt-city/es/vintage/es_vintage_57.c3g const uint8_t es_vintage_57_gp[] PROGMEM = { - 0, 41, 8, 5, - 53, 92, 1, 0, - 104, 155, 96, 36, - 153, 217, 191, 72, - 255, 132, 129, 52}; + 0, 29, 8, 3, + 53, 76, 1, 0, + 104, 142, 96, 28, + 153, 211, 191, 61, + 255, 117, 129, 42}; // Gradient palette "es_vintage_01_gp", originally from // http://seaviewsensing.com/pub/cpt-city/es/vintage/es_vintage_01.c3g const uint8_t es_vintage_01_gp[] PROGMEM = { - 0, 54, 18, 32, - 51, 89, 0, 30, - 76, 176, 170, 48, - 101, 255, 189, 92, - 127, 153, 56, 50, - 153, 89, 0, 30, - 229, 54, 18, 32, - 255, 54, 18, 32}; + 0, 41, 18, 24, + 51, 73, 0, 22, + 76, 165, 170, 38, + 101, 255, 189, 80, + 127, 139, 56, 40, + 153, 73, 0, 22, + 229, 41, 18, 24, + 255, 41, 18, 24}; // Gradient palette "es_rivendell_15_gp", originally from // http://seaviewsensing.com/pub/cpt-city/es/rivendell/es_rivendell_15.c3g const uint8_t es_rivendell_15_gp[] PROGMEM = { - 0, 35, 69, 54, - 101, 88, 105, 82, - 165, 143, 140, 109, - 242, 208, 204, 175, - 255, 208, 204, 175}; + 0, 24, 69, 44, + 101, 73, 105, 70, + 165, 129, 140, 97, + 242, 200, 204, 166, + 255, 200, 204, 166}; // Gradient palette "rgi_15_gp", originally from // http://seaviewsensing.com/pub/cpt-city/ds/rgi/rgi_15.c3g const uint8_t rgi_15_gp[] PROGMEM = { - 0, 54, 14, 111, - 31, 142, 24, 86, - 63, 231, 34, 61, - 95, 146, 31, 88, - 127, 61, 29, 114, - 159, 124, 47, 113, - 191, 186, 66, 112, - 223, 143, 57, 116, - 255, 100, 48, 120}; + 0, 41, 14, 99, + 31, 128, 24, 74, + 63, 227, 34, 50, + 95, 132, 31, 76, + 127, 47, 29, 102, + 159, 109, 47, 101, + 191, 176, 66, 100, + 223, 129, 57, 104, + 255, 84, 48, 108}; // Gradient palette "retro2_16_gp", originally from // http://seaviewsensing.com/pub/cpt-city/ma/retro2/retro2_16.c3g const uint8_t retro2_16_gp[] PROGMEM = { - 0, 227, 191, 12, - 255, 132, 52, 2}; + 0, 222, 191, 8, + 255, 117, 52, 1}; // Gradient palette "Analogous_1_gp", originally from // http://seaviewsensing.com/pub/cpt-city/nd/red/Analogous_1.c3g const uint8_t Analogous_1_gp[] PROGMEM = { - 0, 51, 0, 255, - 63, 102, 0, 255, - 127, 153, 0, 255, - 191, 204, 0, 128, + 0, 38, 0, 255, + 63, 86, 0, 255, + 127, 139, 0, 255, + 191, 196, 0, 117, 255, 255, 0, 0}; // Gradient palette "es_pinksplash_08_gp", originally from // http://seaviewsensing.com/pub/cpt-city/es/pink_splash/es_pinksplash_08.c3g const uint8_t es_pinksplash_08_gp[] PROGMEM = { - 0, 195, 63, 255, - 127, 231, 9, 97, - 175, 237, 205, 218, - 221, 212, 38, 184, - 255, 212, 38, 184}; + 0, 186, 63, 255, + 127, 227, 9, 85, + 175, 234, 205, 213, + 221, 205, 38, 176, + 255, 205, 38, 176, +}; // Gradient palette "es_ocean_breeze_036_gp", originally from // http://seaviewsensing.com/pub/cpt-city/es/ocean_breeze/es_ocean_breeze_036.c3g const uint8_t es_ocean_breeze_036_gp[] PROGMEM = { - 0, 25, 48, 62, - 89, 38, 166, 183, - 153, 205, 233, 255, - 255, 0, 145, 162}; + 0, 16, 48, 51, + 89, 27, 166, 175, + 153, 197, 233, 255, + 255, 0, 145, 152}; // Gradient palette "departure_gp", originally from // http://seaviewsensing.com/pub/cpt-city/mjf/departure.c3g const uint8_t departure_gp[] PROGMEM = { - 0, 68, 34, 0, - 42, 102, 51, 0, - 63, 160, 108, 60, - 84, 218, 166, 120, - 106, 238, 212, 188, + 0, 53, 34, 0, + 42, 86, 51, 0, + 63, 147, 108, 49, + 84, 212, 166, 108, + 106, 235, 212, 180, 116, 255, 255, 255, - 138, 200, 255, 200, - 148, 100, 255, 100, + 138, 191, 255, 193, + 148, 84, 255, 88, 170, 0, 255, 0, 191, 0, 192, 0, 212, 0, 128, 0, @@ -111,227 +114,227 @@ const uint8_t departure_gp[] PROGMEM = { // http://seaviewsensing.com/pub/cpt-city/es/landscape/es_landscape_64.c3g const uint8_t es_landscape_64_gp[] PROGMEM = { 0, 0, 0, 0, - 37, 43, 89, 26, - 76, 87, 178, 53, - 127, 163, 235, 8, - 128, 195, 234, 130, - 130, 227, 233, 252, - 153, 205, 219, 234, - 204, 146, 179, 253, - 255, 39, 107, 228}; + 37, 31, 89, 19, + 76, 72, 178, 43, + 127, 150, 235, 5, + 128, 186, 234, 119, + 130, 222, 233, 252, + 153, 197, 219, 231, + 204, 132, 179, 253, + 255, 28, 107, 225}; // Gradient palette "es_landscape_33_gp", originally from // http://seaviewsensing.com/pub/cpt-city/es/landscape/es_landscape_33.c3g const uint8_t es_landscape_33_gp[] PROGMEM = { - 0, 19, 45, 0, - 19, 116, 86, 3, - 38, 214, 128, 7, - 63, 245, 197, 25, - 66, 124, 196, 156, - 255, 9, 39, 11}; + 0, 12, 45, 0, + 19, 101, 86, 2, + 38, 207, 128, 4, + 63, 243, 197, 18, + 66, 109, 196, 146, + 255, 5, 39, 7}; // Gradient palette "rainbowsherbet_gp", originally from // http://seaviewsensing.com/pub/cpt-city/ma/icecream/rainbowsherbet.c3g const uint8_t rainbowsherbet_gp[] PROGMEM = { - 0, 255, 102, 51, - 43, 255, 140, 102, - 86, 255, 51, 102, - 127, 255, 153, 178, - 170, 255, 255, 250, - 209, 128, 255, 97, - 255, 169, 255, 148}; + 0, 255, 102, 41, + 43, 255, 140, 90, + 86, 255, 51, 90, + 127, 255, 153, 169, + 170, 255, 255, 249, + 209, 113, 255, 85, + 255, 157, 255, 137}; // Gradient palette "gr65_hult_gp", originally from // http://seaviewsensing.com/pub/cpt-city/hult/gr65_hult.c3g const uint8_t gr65_hult_gp[] PROGMEM = { - 0, 252, 216, 252, + 0, 251, 216, 252, 48, 255, 192, 255, - 89, 241, 95, 243, - 160, 65, 153, 221, - 216, 34, 184, 182, - 255, 34, 184, 182}; + 89, 239, 95, 241, + 160, 51, 153, 217, + 216, 24, 184, 174, + 255, 24, 184, 174}; // Gradient palette "gr64_hult_gp", originally from // http://seaviewsensing.com/pub/cpt-city/hult/gr64_hult.c3g const uint8_t gr64_hult_gp[] PROGMEM = { - 0, 34, 184, 182, - 66, 14, 162, 160, - 104, 139, 137, 11, - 130, 188, 186, 30, - 150, 139, 137, 11, - 201, 10, 156, 154, - 239, 0, 128, 128, - 255, 0, 128, 128}; + 0, 24, 184, 174, + 66, 8, 162, 150, + 104, 124, 137, 7, + 130, 178, 186, 22, + 150, 124, 137, 7, + 201, 6, 156, 144, + 239, 0, 128, 117, + 255, 0, 128, 117}; // Gradient palette "GMT_drywet_gp", originally from // http://seaviewsensing.com/pub/cpt-city/gmt/GMT_drywet.c3g const uint8_t GMT_drywet_gp[] PROGMEM = { - 0, 134, 97, 42, - 42, 238, 199, 100, - 84, 180, 238, 135, - 127, 50, 238, 235, - 170, 12, 120, 238, - 212, 38, 1, 183, - 255, 8, 51, 113}; + 0, 119, 97, 33, + 42, 235, 199, 88, + 84, 169, 238, 124, + 127, 37, 238, 232, + 170, 7, 120, 236, + 212, 27, 1, 175, + 255, 4, 51, 101}; // Gradient palette "ib15_gp", originally from // http://seaviewsensing.com/pub/cpt-city/ing/general/ib15.c3g const uint8_t ib15_gp[] PROGMEM = { - 0, 187, 160, 205, - 72, 212, 158, 159, - 89, 236, 155, 113, - 107, 255, 95, 74, - 141, 201, 98, 121, - 255, 146, 101, 168}; + 0, 177, 160, 199, + 72, 205, 158, 149, + 89, 233, 155, 101, + 107, 255, 95, 63, + 141, 192, 98, 109, + 255, 132, 101, 159}; // Gradient palette "Tertiary_01_gp", originally from // http://seaviewsensing.com/pub/cpt-city/nd/vermillion/Tertiary_01.c3g const uint8_t Tertiary_01_gp[] PROGMEM = { 0, 0, 25, 255, - 63, 51, 140, 128, - 127, 102, 255, 0, - 191, 178, 140, 26, - 255, 255, 25, 51}; + 63, 38, 140, 117, + 127, 86, 255, 0, + 191, 167, 140, 19, + 255, 255, 25, 41}; // Gradient palette "lava_gp", originally from // http://seaviewsensing.com/pub/cpt-city/neota/elem/lava.c3g const uint8_t lava_gp[] PROGMEM = { 0, 0, 0, 0, - 46, 93, 0, 0, - 96, 187, 0, 0, - 108, 204, 38, 13, - 119, 221, 76, 26, - 146, 238, 115, 38, - 174, 255, 153, 51, - 188, 255, 178, 51, - 202, 255, 204, 51, - 218, 255, 230, 51, - 234, 255, 255, 51, - 244, 255, 255, 153, + 46, 77, 0, 0, + 96, 177, 0, 0, + 108, 196, 38, 9, + 119, 215, 76, 19, + 146, 235, 115, 29, + 174, 255, 153, 41, + 188, 255, 178, 41, + 202, 255, 204, 41, + 218, 255, 230, 41, + 234, 255, 255, 41, + 244, 255, 255, 143, 255, 255, 255, 255}; // Gradient palette "fierce-ice_gp", originally from // http://seaviewsensing.com/pub/cpt-city/neota/elem/fierce-ice.c3g const uint8_t fierce_ice_gp[] PROGMEM = { 0, 0, 0, 0, - 59, 0, 51, 128, + 59, 0, 51, 117, 119, 0, 102, 255, - 149, 51, 153, 255, - 180, 102, 204, 255, - 217, 178, 230, 255, + 149, 38, 153, 255, + 180, 86, 204, 255, + 217, 167, 230, 255, 255, 255, 255, 255}; // Gradient palette "Colorfull_gp", originally from // http://seaviewsensing.com/pub/cpt-city/nd/atmospheric/Colorfull.c3g const uint8_t Colorfull_gp[] PROGMEM = { - 0, 76, 155, 54, - 25, 111, 174, 89, - 60, 146, 193, 125, - 93, 166, 166, 136, - 106, 185, 138, 147, - 109, 193, 121, 148, - 113, 202, 104, 149, - 116, 229, 179, 174, - 124, 255, 255, 199, - 168, 178, 218, 209, - 255, 100, 182, 219}; + 0, 61, 155, 44, + 25, 95, 174, 77, + 60, 132, 193, 113, + 93, 154, 166, 125, + 106, 175, 138, 136, + 109, 183, 121, 137, + 113, 194, 104, 138, + 116, 225, 179, 165, + 124, 255, 255, 192, + 168, 167, 218, 203, + 255, 84, 182, 215}; // Gradient palette "Pink_Purple_gp", originally from // http://seaviewsensing.com/pub/cpt-city/nd/atmospheric/Pink_Purple.c3g const uint8_t Pink_Purple_gp[] PROGMEM = { - 0, 95, 32, 121, - 25, 106, 40, 128, - 51, 117, 48, 135, - 76, 154, 135, 192, - 102, 190, 222, 249, - 109, 215, 236, 252, - 114, 240, 250, 255, - 122, 213, 200, 241, - 149, 187, 149, 226, - 183, 196, 130, 209, - 255, 206, 111, 191}; + 0, 79, 32, 109, + 25, 90, 40, 117, + 51, 102, 48, 124, + 76, 141, 135, 185, + 102, 180, 222, 248, + 109, 208, 236, 252, + 114, 237, 250, 255, + 122, 206, 200, 239, + 149, 177, 149, 222, + 183, 187, 130, 203, + 255, 198, 111, 184}; // Gradient palette "Sunset_Real_gp", originally from // http://seaviewsensing.com/pub/cpt-city/nd/atmospheric/Sunset_Real.c3g const uint8_t Sunset_Real_gp[] PROGMEM = { - 0, 191, 0, 0, - 22, 223, 85, 0, + 0, 181, 0, 0, + 22, 218, 85, 0, 51, 255, 170, 0, - 85, 217, 85, 89, - 135, 178, 0, 178, - 198, 89, 0, 195, - 255, 0, 0, 212}; + 85, 211, 85, 77, + 135, 167, 0, 169, + 198, 73, 0, 188, + 255, 0, 0, 207}; // Gradient palette "Sunset_Yellow_gp", originally from // http://seaviewsensing.com/pub/cpt-city/nd/atmospheric/Sunset_Yellow.c3g const uint8_t Sunset_Yellow_gp[] PROGMEM = { - 0, 76, 135, 191, - 36, 143, 188, 178, - 87, 210, 241, 165, - 100, 232, 237, 151, - 107, 255, 232, 138, - 115, 252, 202, 141, - 120, 249, 172, 144, - 128, 252, 202, 141, - 180, 255, 232, 138, - 223, 255, 242, 131, - 255, 255, 252, 125}; + 0, 61, 135, 184, + 36, 129, 188, 169, + 87, 203, 241, 155, + 100, 228, 237, 141, + 107, 255, 232, 127, + 115, 251, 202, 130, + 120, 248, 172, 133, + 128, 251, 202, 130, + 180, 255, 232, 127, + 223, 255, 242, 120, + 255, 255, 252, 113}; // Gradient palette "Beech_gp", originally from // http://seaviewsensing.com/pub/cpt-city/nd/atmospheric/Beech.c3g const uint8_t Beech_gp[] PROGMEM = { - 0, 255, 254, 238, - 12, 255, 254, 238, - 22, 255, 254, 238, - 26, 228, 224, 186, - 28, 201, 195, 135, - 28, 186, 255, 234, - 50, 138, 251, 238, - 71, 90, 246, 243, - 93, 45, 225, 231, - 120, 0, 204, 219, - 133, 8, 168, 186, - 136, 16, 132, 153, - 136, 65, 189, 217, - 208, 33, 159, 207, - 255, 0, 129, 197}; + 0, 255, 254, 236, + 12, 255, 254, 236, + 22, 255, 254, 236, + 26, 223, 224, 178, + 28, 192, 195, 124, + 28, 176, 255, 231, + 50, 123, 251, 236, + 71, 74, 246, 241, + 93, 33, 225, 228, + 120, 0, 204, 215, + 133, 4, 168, 178, + 136, 10, 132, 143, + 136, 51, 189, 212, + 208, 23, 159, 201, + 255, 0, 129, 190}; // Gradient palette "Another_Sunset_gp", originally from // http://seaviewsensing.com/pub/cpt-city/nd/atmospheric/Another_Sunset.c3g const uint8_t Another_Sunset_gp[] PROGMEM = { - 0, 185, 121, 73, - 29, 142, 103, 71, - 68, 100, 84, 69, - 68, 249, 184, 66, - 97, 241, 204, 105, - 124, 234, 225, 144, - 178, 117, 125, 140, - 255, 0, 26, 136}; + 0, 175, 121, 62, + 29, 128, 103, 60, + 68, 84, 84, 58, + 68, 248, 184, 55, + 97, 239, 204, 93, + 124, 230, 225, 133, + 178, 102, 125, 129, + 255, 0, 26, 125}; // Gradient palette "es_autumn_19_gp", originally from // http://seaviewsensing.com/pub/cpt-city/es/autumn/es_autumn_19.c3g const uint8_t es_autumn_19_gp[] PROGMEM = { - 0, 106, 14, 8, - 51, 153, 41, 19, - 84, 190, 70, 24, - 104, 201, 202, 136, - 112, 187, 137, 5, - 122, 199, 200, 142, - 124, 201, 202, 135, - 135, 187, 137, 5, - 142, 202, 203, 129, - 163, 187, 68, 24, - 204, 142, 35, 17, - 249, 90, 5, 4, - 255, 90, 5, 4}; + 0, 90, 14, 5, + 51, 139, 41, 13, + 84, 180, 70, 17, + 104, 192, 202, 125, + 112, 177, 137, 3, + 122, 190, 200, 131, + 124, 192, 202, 124, + 135, 177, 137, 3, + 142, 194, 203, 118, + 163, 177, 68, 17, + 204, 128, 35, 12, + 249, 74, 5, 2, + 255, 74, 5, 2}; // Gradient palette "BlacK_Blue_Magenta_White_gp", originally from // http://seaviewsensing.com/pub/cpt-city/nd/basic/BlacK_Blue_Magenta_White.c3g const uint8_t BlacK_Blue_Magenta_White_gp[] PROGMEM = { 0, 0, 0, 0, - 42, 0, 0, 128, + 42, 0, 0, 117, 84, 0, 0, 255, - 127, 128, 0, 255, + 127, 113, 0, 255, 170, 255, 0, 255, 212, 255, 128, 255, 255, 255, 255, 255}; @@ -340,20 +343,20 @@ const uint8_t BlacK_Blue_Magenta_White_gp[] PROGMEM = { // http://seaviewsensing.com/pub/cpt-city/nd/basic/BlacK_Magenta_Red.c3g const uint8_t BlacK_Magenta_Red_gp[] PROGMEM = { 0, 0, 0, 0, - 63, 128, 0, 128, + 63, 113, 0, 117, 127, 255, 0, 255, - 191, 255, 0, 128, + 191, 255, 0, 117, 255, 255, 0, 0}; // Gradient palette "BlacK_Red_Magenta_Yellow_gp", originally from // http://seaviewsensing.com/pub/cpt-city/nd/basic/BlacK_Red_Magenta_Yellow.c3g const uint8_t BlacK_Red_Magenta_Yellow_gp[] PROGMEM = { 0, 0, 0, 0, - 42, 128, 0, 0, + 42, 113, 0, 0, 84, 255, 0, 0, - 127, 255, 0, 128, + 127, 255, 0, 117, 170, 255, 0, 255, - 212, 255, 128, 128, + 212, 255, 128, 117, 255, 255, 255, 0}; // Gradient palette "Blue_Cyan_Yellow_gp", originally from @@ -362,7 +365,7 @@ const uint8_t Blue_Cyan_Yellow_gp[] PROGMEM = { 0, 0, 0, 255, 63, 0, 128, 255, 127, 0, 255, 255, - 191, 128, 255, 128, + 191, 113, 255, 117, 255, 255, 255, 0}; //Custom palette by Aircoookie @@ -477,179 +480,181 @@ const byte Atlantica_gp[] PROGMEM = { // Gradient palette "temperature_gp", originally from // http://seaviewsensing.com/pub/cpt-city/arendal/temperature.c3g const uint8_t temperature_gp[] PROGMEM = { - 0, 30, 92, 179, - 14, 23, 111, 193, - 28, 11, 142, 216, - 42, 4, 161, 230, - 56, 25, 181, 241, - 70, 51, 188, 207, - 84, 102, 204, 206, - 99, 153, 219, 184, - 113, 192, 229, 136, - 127, 204, 230, 75, - 141, 243, 240, 29, - 155, 254, 222, 39, - 170, 252, 199, 7, - 184, 248, 157, 14, - 198, 245, 114, 21, - 226, 219, 30, 38, - 240, 164, 38, 44, - 255, 164, 38, 44}; + 0, 20, 92, 171, + 14, 15, 111, 186, + 28, 6, 142, 211, + 42, 2, 161, 227, + 56, 16, 181, 239, + 70, 38, 188, 201, + 84, 86, 204, 200, + 99, 139, 219, 176, + 113, 182, 229, 125, + 127, 196, 230, 63, + 141, 241, 240, 22, + 155, 254, 222, 30, + 170, 251, 199, 4, + 184, 247, 157, 9, + 198, 243, 114, 15, + 226, 213, 30, 29, + 240, 151, 38, 35, + 255, 151, 38, 35}; // Gradient palette "bhw1_01_gp", originally from // http://seaviewsensing.com/pub/cpt-city/bhw/bhw1/bhw1_01.c3g const uint8_t retro_clown_gp[] PROGMEM = { - 0, 244, 168, 48, - 117, 230, 78, 92, - 255, 173, 54, 228}; + 0, 242, 168, 38, + 117, 226, 78, 80, + 255, 161, 54, 225, +}; // Gradient palette "bhw1_04_gp", originally from // http://seaviewsensing.com/pub/cpt-city/bhw/bhw1/bhw1_04.c3g const uint8_t candy_gp[] PROGMEM = { - 0, 245, 242, 31, - 15, 244, 168, 48, - 142, 126, 21, 161, - 198, 90, 22, 160, - 255, 0, 0, 128}; + 0, 243, 242, 23, + 15, 242, 168, 38, + 142, 111, 21, 151, + 198, 74, 22, 150, + 255, 0, 0, 117}; // Gradient palette "bhw1_05_gp", originally from // http://seaviewsensing.com/pub/cpt-city/bhw/bhw1/bhw1_05.c3g const uint8_t toxy_reaf_gp[] PROGMEM = { - 0, 5, 239, 137, - 255, 158, 35, 221}; + 0, 2, 239, 126, + 255, 145, 35, 217}; // Gradient palette "bhw1_06_gp", originally from // http://seaviewsensing.com/pub/cpt-city/bhw/bhw1/bhw1_06.c3g const uint8_t fairy_reaf_gp[] PROGMEM = { - 0, 225, 19, 194, - 160, 19, 225, 223, - 219, 210, 242, 227, + 0, 220, 19, 187, + 160, 12, 225, 219, + 219, 203, 242, 223, 255, 255, 255, 255}; // Gradient palette "bhw1_14_gp", originally from // http://seaviewsensing.com/pub/cpt-city/bhw/bhw1/bhw1_14.c3g const uint8_t semi_blue_gp[] PROGMEM = { 0, 0, 0, 0, - 12, 35, 4, 48, - 53, 70, 8, 96, - 80, 56, 48, 168, - 119, 43, 89, 239, - 145, 64, 59, 175, - 186, 86, 30, 110, - 233, 43, 15, 55, + 12, 24, 4, 38, + 53, 55, 8, 84, + 80, 43, 48, 159, + 119, 31, 89, 237, + 145, 50, 59, 166, + 186, 71, 30, 98, + 233, 31, 15, 45, 255, 0, 0, 0}; // Gradient palette "bhw1_three_gp", originally from // http://seaviewsensing.com/pub/cpt-city/bhw/bhw1/bhw1_three.c3g const uint8_t pink_candy_gp[] PROGMEM = { 0, 255, 255, 255, - 45, 64, 64, 255, - 112, 244, 16, 193, + 45, 50, 64, 255, + 112, 242, 16, 186, 140, 255, 255, 255, - 155, 244, 16, 193, - 196, 131, 13, 175, + 155, 242, 16, 186, + 196, 116, 13, 166, 255, 255, 255, 255}; // Gradient palette "bhw1_w00t_gp", originally from // http://seaviewsensing.com/pub/cpt-city/bhw/bhw1/bhw1_w00t.c3g const uint8_t red_reaf_gp[] PROGMEM = { - 0, 49, 68, 126, - 104, 162, 195, 249, + 0, 36, 68, 114, + 104, 149, 195, 248, 188, 255, 0, 0, - 255, 110, 14, 14}; + 255, 94, 14, 9}; // Gradient palette "bhw2_23_gp", originally from // http://seaviewsensing.com/pub/cpt-city/bhw/bhw2/bhw2_23.c3g const uint8_t aqua_flash_gp[] PROGMEM = { 0, 0, 0, 0, - 66, 144, 242, 246, - 96, 255, 255, 64, + 66, 130, 242, 245, + 96, 255, 255, 53, 124, 255, 255, 255, - 153, 255, 255, 64, - 188, 144, 242, 246, + 153, 255, 255, 53, + 188, 130, 242, 245, 255, 0, 0, 0}; // Gradient palette "bhw2_xc_gp", originally from // http://seaviewsensing.com/pub/cpt-city/bhw/bhw2/bhw2_xc.c3g const uint8_t yelblu_hot_gp[] PROGMEM = { - 0, 56, 30, 68, - 58, 89, 0, 130, - 122, 103, 0, 86, - 158, 205, 57, 29, - 183, 223, 117, 35, - 219, 241, 177, 41, - 255, 247, 247, 35}; + 0, 43, 30, 57, + 58, 73, 0, 119, + 122, 87, 0, 74, + 158, 197, 57, 22, + 183, 218, 117, 27, + 219, 239, 177, 32, + 255, 246, 247, 27, +}; // Gradient palette "bhw2_45_gp", originally from // http://seaviewsensing.com/pub/cpt-city/bhw/bhw2/bhw2_45.c3g const uint8_t lite_light_gp[] PROGMEM = { 0, 0, 0, 0, - 9, 30, 21, 30, - 40, 60, 43, 60, - 66, 60, 43, 60, - 101, 76, 16, 77, + 9, 20, 21, 22, + 40, 46, 43, 49, + 66, 46, 43, 49, + 101, 61, 16, 65, 255, 0, 0, 0}; // Gradient palette "bhw2_22_gp", originally from // http://seaviewsensing.com/pub/cpt-city/bhw/bhw2/bhw2_22.c3g const uint8_t red_flash_gp[] PROGMEM = { 0, 0, 0, 0, - 99, 244, 12, 12, - 130, 253, 228, 172, - 155, 244, 12, 12, + 99, 242, 12, 8, + 130, 253, 228, 163, + 155, 242, 12, 8, 255, 0, 0, 0}; // Gradient palette "bhw3_40_gp", originally from // http://seaviewsensing.com/pub/cpt-city/bhw/bhw3/bhw3_40.c3g const uint8_t blink_red_gp[] PROGMEM = { - 0, 7, 7, 7, - 43, 53, 25, 73, - 76, 76, 15, 46, - 109, 214, 39, 108, - 127, 255, 156, 191, - 165, 194, 73, 212, - 204, 120, 66, 242, - 255, 93, 29, 90}; + 0, 4, 7, 4, + 43, 40, 25, 62, + 76, 61, 15, 36, + 109, 207, 39, 96, + 127, 255, 156, 184, + 165, 185, 73, 207, + 204, 105, 66, 240, + 255, 77, 29, 78}; // Gradient palette "bhw3_52_gp", originally from // http://seaviewsensing.com/pub/cpt-city/bhw/bhw3/bhw3_52.c3g const uint8_t red_shift_gp[] PROGMEM = { - 0, 114, 22, 105, - 45, 118, 22, 85, - 99, 201, 45, 67, - 132, 238, 187, 70, - 175, 232, 85, 34, - 201, 232, 56, 59, - 255, 5, 0, 4}; + 0, 98, 22, 93, + 45, 103, 22, 73, + 99, 192, 45, 56, + 132, 235, 187, 59, + 175, 228, 85, 26, + 201, 228, 56, 48, + 255, 2, 0, 2}; // Gradient palette "bhw4_097_gp", originally from // http://seaviewsensing.com/pub/cpt-city/bhw/bhw4/bhw4_097.c3g const uint8_t red_tide_gp[] PROGMEM = { - 0, 252, 46, 0, - 28, 255, 139, 33, - 43, 247, 158, 74, - 58, 247, 216, 134, - 84, 245, 94, 15, - 114, 187, 65, 16, - 140, 255, 241, 127, - 168, 187, 65, 16, - 196, 251, 233, 167, - 216, 255, 94, 9, - 255, 140, 8, 6}; + 0, 251, 46, 0, + 28, 255, 139, 25, + 43, 246, 158, 63, + 58, 246, 216, 123, + 84, 243, 94, 10, + 114, 177, 65, 11, + 140, 255, 241, 115, + 168, 177, 65, 11, + 196, 250, 233, 158, + 216, 255, 94, 6, + 255, 126, 8, 4}; // Gradient palette "bhw4_017_gp", originally from // http://seaviewsensing.com/pub/cpt-city/bhw/bhw4/bhw4_017.c3g const uint8_t candy2_gp[] PROGMEM = { - 0, 124, 102, 114, - 25, 55, 49, 83, - 48, 136, 96, 96, - 73, 243, 214, 34, - 89, 222, 104, 54, - 130, 55, 49, 83, - 163, 255, 177, 58, - 186, 243, 214, 34, - 211, 124, 102, 114, - 255, 29, 19, 18}; + 0, 109, 102, 102, + 25, 42, 49, 71, + 48, 121, 96, 84, + 73, 241, 214, 26, + 89, 216, 104, 44, + 130, 42, 49, 71, + 163, 255, 177, 47, + 186, 241, 214, 26, + 211, 109, 102, 102, + 255, 20, 19, 13}; const byte trafficlight_gp[] PROGMEM = { 0, 0, 0, 0, //black @@ -664,15 +669,38 @@ const byte Aurora2_gp[] PROGMEM = { 192, 250, 77, 127, //Pink 255, 171, 101, 221}; //Purple +// FastLed palettes, corrected with inverse gamma of 2.2 to match original looks + +// Party colors +const TProgmemRGBPalette16 PartyColors_gc22 FL_PROGMEM = { + 0x9B00D5, 0xBD00B8, 0xDA0092, 0xF3005C, + 0xF45500, 0xDC8F00, 0xD5B400, 0xD5D500, + 0xD59B00, 0xEF6600, 0xF90044, 0xE10086, + 0xC400B0, 0xA300CF, 0x7600E8, 0x0032FC}; + +// Rainbow colors +const TProgmemRGBPalette16 RainbowColors_gc22 FL_PROGMEM = { + 0xFF0000, 0xEB7000, 0xD59B00, 0xD5BA00, + 0xD5D500, 0x9CEB00, 0x00FF00, 0x00EB70, + 0x00D59B, 0x009CD4, 0x0000FF, 0x7000EB, + 0x9B00D5, 0xBA00BB, 0xD5009B, 0xEB0072}; + +// Rainbow colors with alternatating stripes of black +const TProgmemRGBPalette16 RainbowStripeColors_gc22 FL_PROGMEM = { + 0xFF0000, 0x000000, 0xD59B00, 0x000000, + 0xD5D500, 0x000000, 0x00FF00, 0x000000, + 0x00D59B, 0x000000, 0x0000FF, 0x000000, + 0x9B00D5, 0x000000, 0xD5009B, 0x000000}; + // array of fastled palettes (palette 6 - 12) const TProgmemRGBPalette16 *const fastledPalettes[] PROGMEM = { - &PartyColors_p, //06-00 Party + &PartyColors_gc22, //06-00 Party &CloudColors_p, //07-01 Cloud &LavaColors_p, //08-02 Lava &OceanColors_p, //09-03 Ocean &ForestColors_p, //10-04 Forest - &RainbowColors_p, //11-05 Rainbow - &RainbowStripeColors_p //12-06 Rainbow Bands + &RainbowColors_gc22, //11-05 Rainbow + &RainbowStripeColors_gc22 //12-06 Rainbow Bands }; // Single array of defined cpt-city color palettes. diff --git a/wled00/wled.h b/wled00/wled.h index e9d2c4d8..e4cab539 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -420,7 +420,7 @@ WLED_GLOBAL bool cctICused _INIT(false); // CCT IC used (Athom 15W bulb #endif WLED_GLOBAL bool gammaCorrectCol _INIT(true); // use gamma correction on colors WLED_GLOBAL bool gammaCorrectBri _INIT(false); // use gamma correction on brightness -WLED_GLOBAL float gammaCorrectVal _INIT(2.8f); // gamma correction value +WLED_GLOBAL float gammaCorrectVal _INIT(2.2f); // gamma correction value WLED_GLOBAL byte colPri[] _INIT_N(({ 255, 160, 0, 0 })); // current RGB(W) primary color. colPri[] 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 From 9805ae59d592c721840d247a915638339afb4296 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 8 Jun 2025 13:02:44 +0200 Subject: [PATCH 453/463] PS Fire: added sparks for better looks (#4714) also added some smear-blurring if "smooth" (motion blur) is not used --- wled00/FX.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 7b07cc61..c76c9e6b 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -8034,6 +8034,7 @@ uint16_t mode_particlefire(void) { PartSys->updateSystem(); // update system properties (dimensions and data pointers) PartSys->setWrapX(SEGMENT.check2); PartSys->setMotionBlur(SEGMENT.check1 * 170); // anable/disable motion blur + PartSys->setSmearBlur(!SEGMENT.check1 * 60); // enable smear blur if motion blur is not enabled uint32_t firespeed = max((uint8_t)100, SEGMENT.speed); //limit speed to 100 minimum, reduce frame rate to make it slower (slower speeds than 100 do not look nice) if (SEGMENT.speed < 100) { //slow, limit FPS @@ -8062,7 +8063,7 @@ uint16_t mode_particlefire(void) { PartSys->sources[i].source.ttl = 20 + hw_random16((SEGMENT.custom1 * SEGMENT.custom1) >> 8) / (1 + (firespeed >> 5)); //'hotness' of fire, faster flames reduce the effect or flame height will scale too much with speed PartSys->sources[i].maxLife = hw_random16(SEGMENT.virtualHeight() >> 1) + 16; // defines flame height together with the vy speed, vy speed*maxlife/PS_P_RADIUS is the average flame height PartSys->sources[i].minLife = PartSys->sources[i].maxLife >> 1; - PartSys->sources[i].vx = hw_random16(4) - 2; // emitting speed (sideways) + PartSys->sources[i].vx = hw_random16(5) - 2; // emitting speed (sideways) PartSys->sources[i].vy = (SEGMENT.virtualHeight() >> 1) + (firespeed >> 4) + (SEGMENT.custom1 >> 4); // emitting speed (upwards) PartSys->sources[i].var = 2 + hw_random16(2 + (firespeed >> 4)); // speed variation around vx,vy (+/- var) } @@ -8089,6 +8090,20 @@ uint16_t mode_particlefire(void) { } } + // emit faster sparks at first flame position, amount and speed mostly dependends on intensity + if(hw_random8() < 10 + (SEGMENT.intensity >> 2)) { + for (i = 0; i < PartSys->usedParticles; i++) { + if (PartSys->particles[i].ttl == 0) { // find a dead particle + PartSys->particles[i].ttl = hw_random16(SEGMENT.virtualHeight()) + 30; + PartSys->particles[i].x = PartSys->sources[0].source.x; + PartSys->particles[i].y = PartSys->sources[0].source.y; + PartSys->particles[i].vx = PartSys->sources[0].source.vx; + PartSys->particles[i].vy = (SEGMENT.virtualHeight() >> 1) + (firespeed >> 4) + ((30 + (SEGMENT.intensity >> 1) + SEGMENT.custom1) >> 4); // emitting speed (upwards) + break; // emit only one particle + } + } + } + uint8_t j = hw_random16(); // start with a random flame (so each flame gets the chance to emit a particle if available particles is smaller than number of flames) for (i = 0; i < percycle; i++) { j = (j + 1) % numFlames; From caeda96fbd2453279995964de1a3f338fa372c5f Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 8 Jun 2025 13:03:21 +0200 Subject: [PATCH 454/463] PS bugfix: do not increase saturation of palette colors (#4715) this fix prevents palette colors being saturated more if high (but not full) saturation value is set for a particle --- wled00/FXparticleSystem.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wled00/FXparticleSystem.cpp b/wled00/FXparticleSystem.cpp index bc664174..c07aec39 100644 --- a/wled00/FXparticleSystem.cpp +++ b/wled00/FXparticleSystem.cpp @@ -594,7 +594,7 @@ void ParticleSystem2D::render() { if (particles[i].sat < 255) { CHSV32 baseHSV; rgb2hsv((uint32_t((byte(baseRGB.r) << 16) | (byte(baseRGB.g) << 8) | (byte(baseRGB.b)))), baseHSV); // convert to HSV - baseHSV.s = particles[i].sat; // set the saturation + baseHSV.s = min(baseHSV.s, particles[i].sat); // set the saturation but don't increase it uint32_t tempcolor; hsv2rgb(baseHSV, tempcolor); // convert back to RGB baseRGB = (CRGB)tempcolor; @@ -1177,7 +1177,7 @@ ParticleSystem1D::ParticleSystem1D(uint32_t length, uint32_t numberofparticles, if (isadvanced) { for (uint32_t i = 0; i < numParticles; i++) { - advPartProps[i].sat = 255; // set full saturation (for particles that are transferred from non-advanced system) + advPartProps[i].sat = 255; // set full saturation } } } @@ -1470,7 +1470,7 @@ void ParticleSystem1D::render() { if (advPartProps[i].sat < 255) { CHSV32 baseHSV; rgb2hsv((uint32_t((byte(baseRGB.r) << 16) | (byte(baseRGB.g) << 8) | (byte(baseRGB.b)))), baseHSV); // convert to HSV - baseHSV.s = advPartProps[i].sat; // set the saturation + baseHSV.s = min(baseHSV.s, advPartProps[i].sat); // set the saturation but don't increase it uint32_t tempcolor; hsv2rgb(baseHSV, tempcolor); // convert back to RGB baseRGB = (CRGB)tempcolor; From 00d1fcc5fba677f2a75c6e9be84d62914420fb9d Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 9 Jun 2025 17:41:53 +0200 Subject: [PATCH 455/463] bugfixes: grouping and missing libArchive (#4718) --- usermods/user_fx/library.json | 5 +++-- wled00/FX_fcn.cpp | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/usermods/user_fx/library.json b/usermods/user_fx/library.json index 9420eecd..83f6358b 100644 --- a/usermods/user_fx/library.json +++ b/usermods/user_fx/library.json @@ -1,3 +1,4 @@ { - "name": "user_fx" -} + "name": "user_fx", + "build": { "libArchive": false } +} \ No newline at end of file diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 438c36d5..7d515810 100755 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1459,7 +1459,8 @@ void WS2812FX::blendSegment(const Segment &topSegment) const { const int maxX = std::min(x + topSegment.grouping, width); const int maxY = std::min(y + topSegment.grouping, height); while (y < maxY) { - while (x < maxX) setMirroredPixel(x++, y, c_a, opacity); + int _x = x; + while (_x < maxX) setMirroredPixel(_x++, y, c_a, opacity); y++; } } From 24e71cc6d5f13bc4676f457c67240af98cfad24c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Jun 2025 10:21:51 +0000 Subject: [PATCH 456/463] Bump requests from 2.32.3 to 2.32.4 Bumps [requests](https://github.com/psf/requests) from 2.32.3 to 2.32.4. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v2.32.3...v2.32.4) --- updated-dependencies: - dependency-name: requests dependency-version: 2.32.4 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 4d767b05..7a393786 100644 --- a/requirements.txt +++ b/requirements.txt @@ -38,7 +38,7 @@ pyelftools==0.32 # via platformio pyserial==3.5 # via platformio -requests==2.32.3 +requests==2.32.4 # via platformio semantic-version==2.10.0 # via platformio From ea231cbea8405c7b95f76491eb1b11a36e6214e8 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Tue, 10 Jun 2025 19:29:53 +0200 Subject: [PATCH 457/463] Fixed "Flow Stripe" FX and added palette support --- wled00/FX.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index c76c9e6b..13734b1a 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -4817,7 +4817,7 @@ static const char _data_FX_MODE_WAVESINS[] PROGMEM = "Wavesins@!,Brightness vari ////////////////////////////// // Flow Stripe // ////////////////////////////// -// By: ldirko https://editor.soulmatelights.com/gallery/392-flow-led-stripe , modifed by: Andrew Tuline +// By: ldirko https://editor.soulmatelights.com/gallery/392-flow-led-stripe , modifed by: Andrew Tuline, fixed by @DedeHai uint16_t mode_FlowStripe(void) { if (SEGLEN <= 1) return mode_static(); const int hl = SEGLEN * 10 / 13; @@ -4825,16 +4825,16 @@ uint16_t mode_FlowStripe(void) { uint32_t t = strip.now / (SEGMENT.intensity/8+1); for (unsigned i = 0; i < SEGLEN; i++) { - int c = (abs((int)i - hl) / hl) * 127; + int c = ((abs((int)i - hl) * 127) / hl); c = sin8_t(c); c = sin8_t(c / 2 + t); byte b = sin8_t(c + t/8); - SEGMENT.setPixelColor(i, CHSV(b + hue, 255, 255)); + SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(b + hue, false, true, 3)); } return FRAMETIME; } // mode_FlowStripe() -static const char _data_FX_MODE_FLOWSTRIPE[] PROGMEM = "Flow Stripe@Hue speed,Effect speed;;"; +static const char _data_FX_MODE_FLOWSTRIPE[] PROGMEM = "Flow Stripe@Hue speed,Effect speed;;!;pal=11"; #ifndef WLED_DISABLE_2D From 05f0630b9c2de492c12e37a64db6e6933a3d7e63 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Wed, 11 Jun 2025 08:30:25 +0200 Subject: [PATCH 458/463] add inverse gamma 32 function and fix colors in pride (#4722) * add inverse gamma 32 function and fix for colors in pride --- wled00/FX.cpp | 3 ++- wled00/cfg.cpp | 2 +- wled00/colors.cpp | 14 ++++++++++++++ wled00/fcn_declare.h | 2 ++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index c76c9e6b..887c26ad 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -1918,7 +1918,8 @@ uint16_t mode_colorwaves_pride_base(bool isPride2015) { bri8 += (255 - brightdepth); if (isPride2015) { - CRGB newcolor = CHSV(hue8, sat8, bri8); + CRGBW newcolor = CRGB(CHSV(hue8, sat8, bri8)); + newcolor.color32 = gamma32inv(newcolor.color32); SEGMENT.blendPixelColor(i, newcolor, 64); } else { SEGMENT.blendPixelColor(i, SEGMENT.color_from_palette(hue8, false, PALETTE_SOLID_WRAP, 0, bri8), 128); diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 72ace8db..6d5698f4 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -520,7 +520,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { CJSON(strip.autoSegments, light[F("aseg")]); CJSON(useRainbowWheel, light[F("rw")]); - CJSON(gammaCorrectVal, light["gc"]["val"]); // default 2.8 + CJSON(gammaCorrectVal, light["gc"]["val"]); // default 2.2 float light_gc_bri = light["gc"]["bri"]; float light_gc_col = light["gc"]["col"]; if (light_gc_bri > 1.0f) gammaCorrectBri = true; diff --git a/wled00/colors.cpp b/wled00/colors.cpp index ff6f3ab5..ea5c9779 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -598,3 +598,17 @@ uint32_t IRAM_ATTR_YN NeoGammaWLEDMethod::Correct32(uint32_t color) b = gammaT[b]; return RGBW32(r, g, b, w); } + +uint32_t IRAM_ATTR_YN NeoGammaWLEDMethod::inverseGamma32(uint32_t color) +{ + if (!gammaCorrectCol) return color; + uint8_t w = W(color); + uint8_t r = R(color); + uint8_t g = G(color); + uint8_t b = B(color); + w = gammaT_inv[w]; + r = gammaT_inv[r]; + g = gammaT_inv[g]; + b = gammaT_inv[b]; + return RGBW32(r, g, b, w); +} diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 8e4233f2..d2f62870 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -158,6 +158,7 @@ class NeoGammaWLEDMethod { public: [[gnu::hot]] static uint8_t Correct(uint8_t value); // apply Gamma to single channel [[gnu::hot]] static uint32_t Correct32(uint32_t color); // apply Gamma to RGBW32 color (WLED specific, not used by NPB) + [[gnu::hot]] static uint32_t inverseGamma32(uint32_t color); // apply inverse Gamma to RGBW32 color static void calcGammaTable(float gamma); // re-calculates & fills gamma tables static inline uint8_t rawGamma8(uint8_t val) { return gammaT[val]; } // get value from Gamma table (WLED specific, not used by NPB) static inline uint8_t rawInverseGamma8(uint8_t val) { return gammaT_inv[val]; } // get value from inverse Gamma table (WLED specific, not used by NPB) @@ -167,6 +168,7 @@ class NeoGammaWLEDMethod { }; #define gamma32(c) NeoGammaWLEDMethod::Correct32(c) #define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c) +#define gamma32inv(c) NeoGammaWLEDMethod::inverseGamma32(c) #define gamma8inv(c) NeoGammaWLEDMethod::rawInverseGamma8(c) [[gnu::hot, gnu::pure]] uint32_t color_blend(uint32_t c1, uint32_t c2 , uint8_t blend); inline uint32_t color_blend16(uint32_t c1, uint32_t c2, uint16_t b) { return color_blend(c1, c2, b >> 8); }; From 65f2ced6c231ba8fa1942e22e668d3773e913ec8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 14 Jun 2025 13:46:42 +0000 Subject: [PATCH 459/463] Bump brace-expansion from 1.1.11 to 1.1.12 Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.11 to 1.1.12. - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](https://github.com/juliangruber/brace-expansion/compare/1.1.11...v1.1.12) --- updated-dependencies: - dependency-name: brace-expansion dependency-version: 1.1.12 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index b5e14158..5a19be1d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -129,9 +129,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", From 201d04910a096b7787464ee942cf3f172ee8c491 Mon Sep 17 00:00:00 2001 From: netmindz Date: Sat, 14 Jun 2025 19:04:25 +0000 Subject: [PATCH 460/463] Update pr-merge.yaml --- .github/workflows/pr-merge.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pr-merge.yaml b/.github/workflows/pr-merge.yaml index 9ef843dd..da49289d 100644 --- a/.github/workflows/pr-merge.yaml +++ b/.github/workflows/pr-merge.yaml @@ -1,5 +1,6 @@ name: Notify Discord on PR Merge on: + workflow_dispatch: pull_request: types: [closed] @@ -13,4 +14,4 @@ DISCORD_WEBHOOK_BETA_TESTERS: ${{ secrets.DISCORD_WEBHOOK_BETA_TESTERS }} if: github.event.pull_request.merged == true run: | - curl -H "Content-Type: application/json" -d '{"content": "Pull Request #{{ github.event.pull_request.number }} merged by {{ github.actor }}"}' $DISCORD_WEBHOOK_BETA_TESTERS + curl -H "Content-Type: application/json" -d '{"content": "Pull Request ${{ github.event.pull_request.number }} merged by ${{ github.actor }}"}' $DISCORD_WEBHOOK_BETA_TESTERS From f442d58b7024fe8d9e71508c7317265a9a395ed5 Mon Sep 17 00:00:00 2001 From: netmindz Date: Sat, 14 Jun 2025 19:06:49 +0000 Subject: [PATCH 461/463] Update pr-merge.yaml --- .github/workflows/pr-merge.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-merge.yaml b/.github/workflows/pr-merge.yaml index da49289d..7363b498 100644 --- a/.github/workflows/pr-merge.yaml +++ b/.github/workflows/pr-merge.yaml @@ -12,6 +12,6 @@ shell: bash env: DISCORD_WEBHOOK_BETA_TESTERS: ${{ secrets.DISCORD_WEBHOOK_BETA_TESTERS }} - if: github.event.pull_request.merged == true + # if: github.event.pull_request.merged == true run: | curl -H "Content-Type: application/json" -d '{"content": "Pull Request ${{ github.event.pull_request.number }} merged by ${{ github.actor }}"}' $DISCORD_WEBHOOK_BETA_TESTERS From 80c40f6afd64e7e2a178ebc64de964d4ad270cde Mon Sep 17 00:00:00 2001 From: netmindz Date: Sat, 14 Jun 2025 19:10:45 +0000 Subject: [PATCH 462/463] Update pr-merge.yaml try and fix permissions issue of missing secret on PRs --- .github/workflows/pr-merge.yaml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/pr-merge.yaml b/.github/workflows/pr-merge.yaml index 7363b498..db5937df 100644 --- a/.github/workflows/pr-merge.yaml +++ b/.github/workflows/pr-merge.yaml @@ -8,6 +8,25 @@ notify: runs-on: ubuntu-latest steps: + - name: Get User Permission + id: checkAccess + uses: actions-cool/check-user-permission@v2 + with: + require: write + username: ${{ github.triggering_actor }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Check User Permission + if: steps.checkAccess.outputs.require-result == 'false' + run: | + echo "${{ github.triggering_actor }} does not have permissions on this repo." + echo "Current permission level is ${{ steps.checkAccess.outputs.user-permission }}" + echo "Job originally triggered by ${{ github.actor }}" + exit 1 + - name: Checkout code + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} # This is dangerous without the first access check - name: Send Discord notification shell: bash env: From 42bf8fb40d2e45088b3a411f13abf652ec736454 Mon Sep 17 00:00:00 2001 From: netmindz Date: Sat, 14 Jun 2025 20:02:01 +0000 Subject: [PATCH 463/463] Update pr-merge.yaml --- .github/workflows/pr-merge.yaml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/pr-merge.yaml b/.github/workflows/pr-merge.yaml index db5937df..5f216100 100644 --- a/.github/workflows/pr-merge.yaml +++ b/.github/workflows/pr-merge.yaml @@ -28,9 +28,6 @@ with: ref: ${{ github.event.pull_request.head.sha }} # This is dangerous without the first access check - name: Send Discord notification - shell: bash - env: - DISCORD_WEBHOOK_BETA_TESTERS: ${{ secrets.DISCORD_WEBHOOK_BETA_TESTERS }} # if: github.event.pull_request.merged == true run: | - curl -H "Content-Type: application/json" -d '{"content": "Pull Request ${{ github.event.pull_request.number }} merged by ${{ github.actor }}"}' $DISCORD_WEBHOOK_BETA_TESTERS + curl -H "Content-Type: application/json" -d '{"content": "Pull Request ${{ github.event.pull_request.number }} merged by ${{ github.actor }}"}' ${{ secrets.DISCORD_WEBHOOK_BETA_TESTERS }}