From 3ad56ea103d794082b3475fd22591a5a7787e63d Mon Sep 17 00:00:00 2001 From: Christian Schwinne Date: Sun, 10 Mar 2024 14:34:15 +0100 Subject: [PATCH 01/15] 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 02/15] 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 03/15] 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 04/15] 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 d4ba603cf745de2f88a39e7cf13a8967073ab64b Mon Sep 17 00:00:00 2001 From: Christian Schwinne Date: Tue, 19 Mar 2024 22:39:33 +0100 Subject: [PATCH 05/15] 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 06/15] 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 07/15] 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 08/15] 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 09/15] 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 1df717084b944f570ab5b5dde81d412def785b0c Mon Sep 17 00:00:00 2001 From: Will Miles Date: Tue, 27 Aug 2024 13:45:33 -0400 Subject: [PATCH 10/15] Update to AsyncWebServer v2.4.0 Includes update to use matching newer AsyncTCP on ESP32 --- platformio.ini | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/platformio.ini b/platformio.ini index 5e0c01db..6f1d923d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -140,7 +140,7 @@ lib_deps = IRremoteESP8266 @ 2.8.2 makuna/NeoPixelBus @ 2.8.0 #https://github.com/makuna/NeoPixelBus.git#CoreShaderBeta - https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.2.1 + https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.4.0 # for I2C interface ;Wire # ESP-NOW library @@ -236,7 +236,7 @@ lib_deps_compat = IRremoteESP8266 @ 2.8.2 makuna/NeoPixelBus @ 2.7.9 https://github.com/blazoncek/QuickESPNow.git#optional-debug - https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.2.1 + https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.4.0 [esp32] @@ -259,7 +259,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 + willmmiles/AsyncTCP @ 1.3.1 ${env.lib_deps} # additional build flags for audioreactive AR_build_flags = -D USERMOD_AUDIOREACTIVE @@ -284,7 +284,7 @@ build_flags = -g -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 + willmmiles/AsyncTCP @ 1.3.1 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 @@ -304,7 +304,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 + willmmiles/AsyncTCP @ 1.3.1 ${env.lib_deps} board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs @@ -322,7 +322,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 + willmmiles/AsyncTCP @ 1.3.1 ${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 @@ -342,7 +342,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 + willmmiles/AsyncTCP @ 1.3.1 ${env.lib_deps} board_build.partitions = ${esp32.large_partitions} ;; default partioning for 8MB flash - can be overridden in build envs From 981750a48a2e6841b01db12cd8c7333a1b080b64 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 4 Aug 2024 14:02:05 -0400 Subject: [PATCH 11/15] Enable webserver queue and limits Enable the new concurrent request and queue size limit features of AsyncWebServer. This should improve the handling of burst traffic or many clients, and significantly reduce the likelihood of OOM crashes due to HTTP requests. --- wled00/const.h | 21 +++++++++++++++++++-- wled00/wled.h | 2 +- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/wled00/const.h b/wled00/const.h index 3f82219d..1ebcb939 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -560,8 +560,25 @@ #endif #endif -//#define MIN_HEAP_SIZE (8k for AsyncWebServer) -#define MIN_HEAP_SIZE 8192 +//#define MIN_HEAP_SIZE +#define MIN_HEAP_SIZE 2048 + +// Web server limits +#ifdef ESP8266 +// Minimum heap to consider handling a request +#define WLED_REQUEST_MIN_HEAP (8*1024) +// Estimated maximum heap required by any one request +#define WLED_REQUEST_HEAP_USAGE (6*1024) +#else +// ESP32 TCP stack needs much more RAM than ESP8266 +// Minimum heap remaining before queuing a request +#define WLED_REQUEST_MIN_HEAP (12*1024) +// Estimated maximum heap required by any one request +#define WLED_REQUEST_HEAP_USAGE (12*1024) +#endif +// Maximum number of requests in queue; absolute cap on web server resource usage. +// Websockets do not count against this limit. +#define WLED_REQUEST_MAX_QUEUE 6 // Maximum size of node map (list of other WLED instances) #ifdef ESP8266 diff --git a/wled00/wled.h b/wled00/wled.h index 37154661..a1819944 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -874,7 +874,7 @@ WLED_GLOBAL bool ledStatusState _INIT(false); // the current LED state #endif // server library objects -WLED_GLOBAL AsyncWebServer server _INIT_N(((80))); +WLED_GLOBAL AsyncWebServer server _INIT_N(((80, {0, WLED_REQUEST_MAX_QUEUE, WLED_REQUEST_MIN_HEAP, WLED_REQUEST_HEAP_USAGE}))); #ifdef WLED_ENABLE_WEBSOCKETS WLED_GLOBAL AsyncWebSocket ws _INIT_N((("/ws"))); #endif From dc317220b39ae35cba13a84179df96f63489b4cc Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 4 Aug 2024 14:02:05 -0400 Subject: [PATCH 12/15] Debug: Dump web server queue state This can be helpful for debugging web handler related issues. --- wled00/wled.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/wled00/wled.cpp b/wled00/wled.cpp index da1c3304..dd260b1c 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -303,6 +303,7 @@ void WLED::loop() DEBUG_PRINTF_P(PSTR("Strip time[ms]:%u/%lu\n"), avgStripMillis/loops, maxStripMillis); } strip.printSize(); + server.printStatus(DEBUGOUT); loops = 0; maxLoopMillis = 0; maxUsermodMillis = 0; From bec7e54f7fc56abff2c90ccb66f6bab8f0a49ed5 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sun, 4 Aug 2024 14:02:05 -0400 Subject: [PATCH 13/15] Defer web requests if JSON lock contended Use the web server's queuing mechanism to call us back later. --- wled00/json.cpp | 2 +- wled00/set.cpp | 5 ++++- wled00/wled_server.cpp | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/wled00/json.cpp b/wled00/json.cpp index 5fae9544..d4f0d777 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -1060,7 +1060,7 @@ void serveJson(AsyncWebServerRequest* request) } if (!requestJSONBufferLock(17)) { - serveJsonError(request, 503, ERR_NOBUF); + request->deferResponse(); return; } // releaseJSONBufferLock() will be called when "response" is destroyed (from AsyncWebServer) diff --git a/wled00/set.cpp b/wled00/set.cpp index 88249d3c..c0977f26 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -628,7 +628,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) //USERMODS if (subPage == SUBPAGE_UM) { - if (!requestJSONBufferLock(5)) return; + if (!requestJSONBufferLock(5)) { + request->deferResponse(); + return; + } // global I2C & SPI pins int8_t hw_sda_pin = !request->arg(F("SDA")).length() ? -1 : (int)request->arg(F("SDA")).toInt(); diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index 8768b2b4..da7fd2a3 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -288,7 +288,7 @@ void initServer() bool isConfig = false; if (!requestJSONBufferLock(14)) { - serveJsonError(request, 503, ERR_NOBUF); + request->deferResponse(); return; } From 21816183572ad363015d973485fa61266c7d6b53 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Wed, 21 Aug 2024 01:06:09 -0400 Subject: [PATCH 14/15] stress_test: Add replicated index as a target No locking contention, but a much larger target --- tools/stress_test.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/stress_test.sh b/tools/stress_test.sh index d7c344c5..d86c5086 100644 --- a/tools/stress_test.sh +++ b/tools/stress_test.sh @@ -27,6 +27,7 @@ read -a JSON_TINY_TARGETS <<< $(replicate "json/nodes") read -a JSON_SMALL_TARGETS <<< $(replicate "json/info") read -a JSON_LARGE_TARGETS <<< $(replicate "json/si") read -a JSON_LARGER_TARGETS <<< $(replicate "json/fxdata") +read -a INDEX_TARGETS <<< $(replicate "") # Expand target URLS to full arguments for curl TARGETS=(${TARGET_STR[@]}) From e27fa882fab85320feec437047a66918dd1bb488 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sun, 26 Jan 2025 16:12:08 +0000 Subject: [PATCH 15/15] 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