From 18f9d64e24fe31921d4c8f0cfc88a8830898e7dc Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sat, 3 Aug 2024 23:49:13 +0200 Subject: [PATCH 01/29] HUB75 lib version 3.0.11 using the git hash of version 3.0.11 --- platformio.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 59b43b1f..ec1a387d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -1036,9 +1036,9 @@ HUB75_build_flags = -D NO_FAST_FUNCTIONS ;; If you are not using AdafruitGFX than you probably do not need this either, save memory/code size -D NO_CIE1931 ;; Do not use LED brightness compensation described in CIE 1931. We use FastLED dimming already -D S3_LCD_DIV_NUM=20 ;; Attempt to fix wifi performance issue when panel active with S3 chips -;; HUB75_lib_deps = https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA.git @ 3.0.10 ;; does not work any more ;; HUB75_lib_deps = https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA.git @ 3.0.11 ;; breaks the build (2024-07-30) -HUB75_lib_deps = https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA.git#1e4c80a26454aca7b8129bd5a966b0af329d2703 ;; something strange is going on here ... +;; HUB75_lib_deps = https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA.git#1e4c80a26454aca7b8129bd5a966b0af329d2703 ;; 3.0.10 - something strange is going on here ... +HUB75_lib_deps = https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA.git#c4ecdcfeeb5aa668d92ddf3c3c74bc93316f6e10 ;; 3.0.11 HUB75_lib_ignore = ESP32 HUB75 LED MATRIX PANEL DMA Display ;; to remove the HUB75 lib dependancy (saves a few bytes) NetDebug_build_flags = From 5f4834dec4acb4cfe3613a1145cc06697c5582ed Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 5 Aug 2024 17:06:38 +0200 Subject: [PATCH 02/29] small improvements * optimized fadeToBlackBy() - don't repaint unchanged pixels * made MIN_HEAP_SIZE configurable by build_flags * specific error message when not enough memory for LEDs buffer --- wled00/FX_fcn.cpp | 8 +++++--- wled00/const.h | 3 +++ wled00/data/index.js | 3 +++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 65849ff1..4c43218a 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -132,7 +132,7 @@ void Segment::allocLeds() { ledsrgbSize = ledsrgb?size:0; if (ledsrgb == nullptr) { USER_PRINTLN("allocLeds failed!!"); - errorFlag = ERR_LOW_MEM; // WLEDMM raise errorflag + errorFlag = ERR_LOW_BUF; // WLEDMM raise errorflag } } else { @@ -1442,8 +1442,10 @@ void Segment::fadeToBlackBy(uint8_t fadeBy) { // WLEDMM minor optimization if(is2D()) { - for (uint_fast16_t y = 0; y < rows; y++) for (uint_fast16_t x = 0; x < cols; x++) { - setPixelColorXY((uint16_t)x, (uint16_t)y, CRGB(getPixelColorXY(x,y)).nscale8(scaledown)); + for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) { + uint32_t cc = getPixelColorXY(x,y); // WLEDMM avoid RGBW32 -> CRGB -> RGBW32 conversion + uint32_t cc2 = color_fade(cc, scaledown); // fade + if (cc2 != cc) setPixelColorXY((uint16_t)x, (uint16_t)y, cc2); // WLEDMM only re-paint if faded color is different } } else { for (uint_fast16_t x = 0; x < cols; x++) { diff --git a/wled00/const.h b/wled00/const.h index 5203d774..ff8b0371 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -352,6 +352,7 @@ #define ERR_LOW_SEG_MEM 34 // WLEDMM: low memory (segment data RAM) #define ERR_LOW_WS_MEM 35 // WLEDMM: low memory (ws) #define ERR_LOW_AJAX_MEM 36 // WLEDMM: low memory (oappend) +#define ERR_LOW_BUF 37 // WLEDMM: low memory (LED buffer from allocLEDs) // Timer mode types #define NL_MODE_SET 0 //After nightlight time elapsed, set to target brightness @@ -480,7 +481,9 @@ #endif //#define MIN_HEAP_SIZE (8k for AsyncWebServer) +#if !defined(MIN_HEAP_SIZE) #define MIN_HEAP_SIZE 8192 +#endif // Maximum size of node map (list of other WLED instances) #ifdef ESP8266 diff --git a/wled00/data/index.js b/wled00/data/index.js index e89ad78e..61480d5e 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -2008,6 +2008,9 @@ function readState(s,command=false) case 36: errstr = "Low Memory (oappend buffer)."; break; + case 37: + errstr = "no memory for LEDs buffer."; + break; } showToast('Error ' + s.error + ": " + errstr, true); } From 6505e04cbf9b978068feed57588c41a49a2fc61b Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 5 Aug 2024 17:09:50 +0200 Subject: [PATCH 03/29] minor effect improvements * 2DBlackHole: improved accuracy * 2Dfloatingblobs: draw anti-aliased blobs when "blur" slider = 1 * FX framework: un-clutter and optimize "XY()" --- wled00/FX.cpp | 16 +++++++++------- wled00/FX.h | 6 ++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 4f89af77..4cce3230 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -4922,17 +4922,18 @@ uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulma } SEGMENT.fadeToBlackBy(16 + (SEGMENT.speed>>3)); // create fading trails - unsigned long t = strip.now/128; // timebase + const unsigned long ratio = 128; // rotation speed + unsigned long t = strip.now; // timebase // outer stars - for (size_t i = 0; i < 8; i++) { - x = beatsin8(SEGMENT.custom1>>3, 0, cols - 1, 0, ((i % 2) ? 128 : 0) + t * i); - y = beatsin8(SEGMENT.intensity>>3, 0, rows - 1, 0, ((i % 2) ? 192 : 64) + t * i); + for (unsigned i = 0; i < 8; i++) { + x = beatsin8(SEGMENT.custom1>>3, 0, cols - 1, 0, ((i % 2) ? 128 : 0) + (t * i)/ratio); + y = beatsin8(SEGMENT.intensity>>3, 0, rows - 1, 0, ((i % 2) ? 192 : 64) + (t * i)/ratio); SEGMENT.addPixelColorXY(x, y, CHSV(i*32, 255, 255)); } // inner stars for (size_t i = 0; i < 4; i++) { - x = beatsin8(SEGMENT.custom2>>3, cols/4, cols - 1 - cols/4, 0, ((i % 2) ? 128 : 0) + t * i); - y = beatsin8(SEGMENT.custom3 , rows/4, rows - 1 - rows/4, 0, ((i % 2) ? 192 : 64) + t * i); + x = beatsin8(SEGMENT.custom2>>3, cols/4, cols - 1 - cols/4, 0, ((i % 2) ? 128 : 0) + (t * i)/ratio); + y = beatsin8(SEGMENT.custom3 , rows/4, rows - 1 - rows/4, 0, ((i % 2) ? 192 : 64) + (t * i)/ratio); SEGMENT.addPixelColorXY(x, y, CHSV(i*32, 255, 255)); } // central white dot @@ -6270,6 +6271,7 @@ uint16_t mode_2Dfloatingblobs(void) { } SEGMENT.fadeToBlackBy(20); + bool drawAA = (SEGMENT.custom1 > 0) && (SEGMENT.custom1 < 5); //WLEDMM // Bounce balls around for (size_t i = 0; i < Amount; i++) { @@ -6289,7 +6291,7 @@ uint16_t mode_2Dfloatingblobs(void) { } } uint32_t c = SEGMENT.color_from_palette(blob->color[i], false, false, 0); - if (blob->r[i] > 1.f) SEGMENT.fillCircle(roundf(blob->x[i]), roundf(blob->y[i]), roundf(blob->r[i]), c); + if (blob->r[i] > 1.f) SEGMENT.fillCircle(roundf(blob->x[i]), roundf(blob->y[i]), roundf(blob->r[i]), c, drawAA); else SEGMENT.setPixelColorXY((int)roundf(blob->x[i]), (int)roundf(blob->y[i]), c); // move x if (blob->x[i] + blob->r[i] >= cols - 1) blob->x[i] += (blob->sX[i] * ((cols - 1 - blob->x[i]) / blob->r[i] + 0.005f)); diff --git a/wled00/FX.h b/wled00/FX.h index af707b41..00ae3183 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -661,10 +661,8 @@ typedef struct Segment { #ifndef WLED_DISABLE_2D inline uint16_t XY(uint_fast16_t x, uint_fast16_t y) { // support function to get relative index within segment (for leds[]) // WLEDMM inline for speed - uint_fast16_t width = virtualWidth(); // segment width in logical pixels - uint_fast16_t height = virtualHeight(); // segment height in logical pixels - if (width == 0) return 0; // softhack007 avoid div/0 - if (height == 0) return (x%width); // softhack007 avoid div/0 + uint_fast16_t width = max(uint16_t(1), virtualWidth()); // segment width in logical pixels -- softhack007 avoid div/0 + uint_fast16_t height = max(uint16_t(1), virtualHeight()); // segment height in logical pixels -- softhack007 avoid div/0 return (x%width) + (y%height) * width; } From 078bd7077504f8fca97dfb5c1cac5613a50f6fa0 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 5 Aug 2024 17:28:03 +0200 Subject: [PATCH 04/29] HUB75 speedups and minor improvements * HUB75: allow to use native driver gamma correction - requires to undo WLED gamma * added unGamma24() function * HUB75: optimized setPixelColor() * some experimental HUB75 stuff --- wled00/bus_manager.cpp | 33 ++++++++++++++++++++++++--------- wled00/bus_manager.h | 3 ++- wled00/colors.cpp | 6 ++++++ wled00/fcn_declare.h | 1 + wled00/wled.h | 2 +- 5 files changed, 34 insertions(+), 11 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index a24fdf28..604a92c5 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -501,6 +501,7 @@ void BusNetwork::cleanup() { BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) { + _valid = false; mxconfig.double_buff = false; // default to off, known to cause issue with some effects but needs more memory @@ -594,6 +595,13 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh mxconfig.gpio.d = 21; mxconfig.gpio.e = 12; + // mxconfig.double_buff = true; // <------------- Turn on double buffer + // mxconfig.driver = HUB75_I2S_CFG::ICN2038S; // experimental - use specific shift register driver + //mxconfig.latch_blanking = 3; + // mxconfig.i2sspeed = HUB75_I2S_CFG::HZ_10M; // experimental - 5MHZ should be enugh, but colours looks slightly better at 10MHz + //mxconfig.min_refresh_rate = 90; + //mxconfig.min_refresh_rate = 120; + #else USER_PRINTLN("MatrixPanel_I2S_DMA - Default pins"); /* @@ -691,18 +699,25 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh } void BusHub75Matrix::setPixelColor(uint16_t pix, uint32_t c) { - r = R(c); - g = G(c); - b = B(c); + if (!_valid || pix >= _len) return; +#ifndef NO_CIE1931 + c = unGamma24(c); // to use the driver linear brightness feature, we first need to undo WLED gamma correction +#endif + uint8_t r = R(c); + uint8_t g = G(c); + uint8_t b = B(c); + if(fourScanPanel != nullptr) { - x = pix % fourScanPanel->width(); - y = floor(pix / fourScanPanel->width()); - fourScanPanel->drawPixelRGB888(x, y, r, g, b); + int pxwidth = fourScanPanel->width(); + int x = pix % pxwidth; + int y = pix / pxwidth; + fourScanPanel->drawPixelRGB888(int16_t(x), int16_t(y), r, g, b); } else { - x = pix % display->width(); - y = floor(pix / display->width()); - display->drawPixelRGB888(x, y, r, g, b); + int pxwidth = display->width(); + int x = pix % pxwidth; + int y = pix / pxwidth; + display->drawPixelRGB888(int16_t(x), int16_t(y), r, g, b); } } diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 0bfd3e04..40fc0061 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -4,6 +4,7 @@ #ifdef WLED_ENABLE_HUB75MATRIX #include #include +//extern volatile bool previousBufferFree; // experimental #endif /* * Class for addressing various light types @@ -348,6 +349,7 @@ class BusHub75Matrix : public Bus { void show() { if(mxconfig.double_buff) { display->flipDMABuffer(); // Show the back buffer, set currently output buffer to the back (i.e. no longer being sent to LED panels) + // while(!previousBufferFree) delay(1); // experimental - Wait before we allow any writing to the buffer. Stop flicker. display->clearScreen(); // Now clear the back-buffer } } @@ -377,7 +379,6 @@ class BusHub75Matrix : public Bus { MatrixPanel_I2S_DMA *display = nullptr; VirtualMatrixPanel *fourScanPanel = nullptr; HUB75_I2S_CFG mxconfig; - uint8_t r, g, b, x, y; }; #endif diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 465fefbb..f7751861 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -413,6 +413,12 @@ uint8_t unGamma8(uint8_t value) { if (gammaTinv[255] == 0) calcInvGammaTable(gammaCorrectVal); return gammaTinv[value]; } + +uint32_t unGamma24(uint32_t c) { + if ((gammaCorrectVal < 0.999f) || (gammaCorrectVal > 3.0f)) return c; + if (gammaTinv[255] == 0) calcInvGammaTable(gammaCorrectVal); + return RGBW32(gammaTinv[R(c)], gammaTinv[G(c)], gammaTinv[B(c)], W(c)); +} // wleDMM end uint8_t gamma8_cal(uint8_t b, float gamma) diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index aa0645d0..a0713d0f 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -69,6 +69,7 @@ void calcGammaTable(float gamma); uint8_t __attribute__((pure)) gamma8(uint8_t b); // WLEDMM: added attribute pure uint32_t __attribute__((pure)) gamma32(uint32_t); // WLEDMM: added attribute pure uint8_t unGamma8(uint8_t value); // WLEDMM revert gamma correction +uint32_t unGamma24(uint32_t c); // WLEDMM for 24bit color (white left as-is) //dmx_output.cpp void initDMXOutput(); diff --git a/wled00/wled.h b/wled00/wled.h index 5d881cf0..be21de04 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2407171 +#define VERSION 2408050 // WLEDMM - you can check for this define in usermods, to only enabled WLEDMM specific code in the "right" fork. Its not defined in AC WLED. #define _MoonModules_WLED_ From 5240c3450b116dc1df935926487c1549e525b304 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 5 Aug 2024 21:30:25 +0200 Subject: [PATCH 05/29] Segment drawing optimizations (FASTPATH only) * cache width, height, and a few more values that are normally re-calculated for each pixel * make normal sPC a bit faster * Segment::fade_out() optimization --> only active in FASTPATH mode, to preserve flash on small devices (8266) --> code still needs some polishing --> up to 20% speedup with some 2D effects (esp32, flash qio 80Mhz, -O2) --- wled00/FX.h | 50 ++++++++++++++++++++++++++++++++++++++++++++- wled00/FX_2Dfcn.cpp | 23 ++++++++++++++++++--- wled00/FX_fcn.cpp | 24 ++++++++++++++++------ wled00/wled.h | 2 +- 4 files changed, 88 insertions(+), 11 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 00ae3183..aa5014e2 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -434,6 +434,19 @@ typedef struct Segment { static size_t _usedSegmentData; // WLEDMM uint16_t is too small void setPixelColorXY_fast(int x, int y,uint32_t c, uint32_t scaled_col, int cols, int rows); // set relative pixel within segment with color - faster, but no error checking!!! +#ifdef WLEDMM_FASTPATH + // WLEDMM cache some values that won't change while drawing a frame + bool _isSimpleSegment = false; + bool _isValid2D = false; + uint8_t _brightness = 255; // final pixel brightness - including transitions and segment opacity + uint16_t _2dWidth = 0; // virtualWidth + uint16_t _2dHeight = 0; // virtualHeight + + void setPixelColorXY_slow(int x, int y, uint32_t c); // set relative pixel within segment with color - full slow version +#else + void setPixelColorXY_slow(int x, int y, uint32_t c) { setPixelColorXY(x,y,c); } // not FASTPATH - slow is the normal +#endif + // perhaps this should be per segment, not static static CRGBPalette16 _currentPalette; // palette used for current effect (includes transition, used in color_from_palette()) @@ -587,6 +600,7 @@ typedef struct Segment { bool allocateData(size_t len); void deallocateData(void); void resetIfRequired(void); + void startFrame(void); // cache a few values that don't change while an effect is drawing /** * Flags that before the next effect is calculated, * the internal segment state should be reset. @@ -642,6 +656,7 @@ typedef struct Segment { uint32_t __attribute__((pure)) color_wheel(uint8_t pos); // 2D matrix +#ifndef WLEDMM_FASTPATH inline uint16_t virtualWidth() const { // WLEDMM use fast types, and make function inline uint_fast16_t groupLen = groupLength(); uint_fast16_t vWidth = ((transpose ? height() : width()) + groupLen - 1) / groupLen; @@ -654,6 +669,23 @@ typedef struct Segment { if (mirror_y) vHeight = (vHeight + 1) /2; // divide by 2 if mirror, leave at least a single LED return vHeight; } +#else + inline uint16_t virtualWidth() const { return(_2dWidth);} // WLEDMM get pre-calculated virtualWidth + inline uint16_t virtualHeight() const { return(_2dHeight);} // WLEDMM get pre-calculated virtualHeight + + uint16_t calc_virtualWidth() const { + uint_fast16_t groupLen = groupLength(); + uint_fast16_t 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 calc_virtualHeight() const { + uint_fast16_t groupLen = groupLength(); + uint_fast16_t 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; + } +#endif uint16_t nrOfVStrips(void) const; void createjMap(); //WLEDMM jMap @@ -666,8 +698,24 @@ typedef struct Segment { return (x%width) + (y%height) * width; } - //void setPixelColorXY_fast(int x, int y,uint32_t c); // set relative pixel within segment with color - wrapper for _fast +#ifdef WLEDMM_FASTPATH + // WLEDMM this is a "gateway" function - we either call _fast or fall back to "slow" + inline void setPixelColorXY(int x, int y, uint32_t col) { + if (!_isSimpleSegment) { // slow path + setPixelColorXY_slow(x, y, col); + } else { // fast path + // some sanity checks + if (!_isValid2D) return; // not active + if ((unsigned(x) >= _2dWidth) || (unsigned(y) >= _2dHeight)) return; // check if (x,y) are out-of-range - due to 2's complement, this also catches negative values + if (!_brightness && !transitional) return; // black-out + + uint32_t scaled_col = (_brightness == 255) ? col : color_fade(col, _brightness); // calculate final color + setPixelColorXY_fast(x, y, col, scaled_col, int(_2dWidth), int(_2dHeight)); // call "fast" function + } +} +#else void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color +#endif 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)); } diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 83ec0f54..df4387db 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -217,6 +217,19 @@ uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) { #ifndef WLED_DISABLE_2D +// WLEDMM cache some values so we don't need to re-calc then for each pixel +void Segment::startFrame(void) { +#ifdef WLEDMM_FASTPATH + _isValid2D = isActive() && is2D(); + _brightness = currentBri(on ? opacity : 0); + _isSimpleSegment = (grouping == 1) && (spacing == 0); // we can handle pixels faster when no grouping or spacing is involved + // if (reverse_y) _isSimpleSegment = false; // for A/B testing + _2dWidth = is2D() ? calc_virtualWidth() : virtualLength(); + _2dHeight = calc_virtualHeight(); +#endif +} +// WLEDMM end + // XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element) // WLEDMM Segment::XY()is declared inline, see FX.h @@ -266,7 +279,11 @@ void IRAM_ATTR Segment::setPixelColorXY_fast(int x, int y, uint32_t col, uint32_ // normal Segment::setPixelColorXY with error checking, and support for grouping / spacing +#ifdef WLEDMM_FASTPATH +void IRAM_ATTR_YN Segment::setPixelColorXY_slow(int x, int y, uint32_t col) //WLEDMM: IRAM_ATTR conditionally, renamed to "_slow" +#else void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) //WLEDMM: IRAM_ATTR conditionally +#endif { if (Segment::maxHeight==1) return; // not a matrix set-up const int_fast16_t cols = virtualWidth(); // WLEDMM optimization @@ -520,7 +537,7 @@ void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) { for (int j = 0; j < dim1; j++) { int x = vertical ? i : j; int y = vertical ? j : i; - setPixelColorXY(x, y, out[j]); + if (in[j] != out[j]) setPixelColorXY(x, y, out[j]); } } @@ -698,7 +715,7 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3 // single pixel (line length == 0) if (dx+dy == 0) { if (simpleSegment) setPixelColorXY_fast(x0, y0, c, scaled_col, cols, rows); - else setPixelColorXY(x0, y0, c); + else setPixelColorXY_slow(x0, y0, c); return; } @@ -734,7 +751,7 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3 for (;;) { // if (x0 >= cols || y0 >= rows) break; // WLEDMM we hit the edge - should never happen if (simpleSegment) setPixelColorXY_fast(x0, y0, c, scaled_col, cols, rows); - else setPixelColorXY(x0, y0, c); + else setPixelColorXY_slow(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 4c43218a..faf23625 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -266,6 +266,7 @@ void Segment::resetIfRequired() { deallocateData(); next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0; reset = false; // setOption(SEG_OPTION_RESET, false); + startFrame(); // WLEDMM update cached propoerties } } @@ -673,7 +674,11 @@ class JMapC { if (size > 0) return size; else +#ifndef WLEDMM_FASTPATH return SEGMENT.virtualWidth() * SEGMENT.virtualHeight(); //pixels +#else + return SEGMENT.calc_virtualWidth() * SEGMENT.calc_virtualHeight(); // calc pixel sizes +#endif } void setPixelColor(uint16_t i, uint32_t col) { updatejMapDoc(); @@ -765,7 +770,11 @@ class JMapC { jMapFile.close(); maxWidth++; maxHeight++; +#ifndef WLEDMM_FASTPATH scale = min(SEGMENT.virtualWidth() / maxWidth, SEGMENT.virtualHeight() / maxHeight); // WLEDMM use native min/max +#else + scale = min(SEGMENT.calc_virtualWidth() / maxWidth, SEGMENT.calc_virtualHeight() / maxHeight); // WLEDMM re-calc width/heiht from active settings +#endif dataSize += sizeof(jVectorMap); USER_PRINT("dataSize "); USER_PRINT(dataSize); @@ -1057,7 +1066,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATT // set pixel if (x != lastX || y != lastY) { // only paint if pixel position is different if (simpleSegment) setPixelColorXY_fast(x, y, col, scaled_col, vW, vH); - else setPixelColorXY(x, y, col); + else setPixelColorXY_slow(x, y, col); } lastX = x; lastY = y; @@ -1353,7 +1362,7 @@ void Segment::fill(uint32_t c) { // fill 2D segment for(int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) { if (simpleSegment) setPixelColorXY_fast(x, y, c, scaled_col, cols, rows); - else setPixelColorXY(x, y, c); + else setPixelColorXY_slow(x, y, c); } } else { // fill 1D strip for (int x = 0; x < cols; x++) setPixelColor(x, c); @@ -1408,7 +1417,7 @@ void Segment::fade_out(uint8_t rate) { int g2 = G(color2); int b2 = B(color2); - for (uint_fast16_t y = 0; y < rows; y++) for (uint_fast16_t x = 0; x < cols; x++) { + for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) { uint32_t color = is2D() ? getPixelColorXY(x, y) : getPixelColor(x); if (color == color2) continue; // WLEDMM speedup - pixel color = target color, so nothing to do int w1 = W(color); @@ -1426,10 +1435,12 @@ void Segment::fade_out(uint8_t rate) { rdelta += (r2 == r1) ? 0 : (r2 > r1) ? 1 : -1; gdelta += (g2 == g1) ? 0 : (g2 > g1) ? 1 : -1; bdelta += (b2 == b1) ? 0 : (b2 > b1) ? 1 : -1; + uint32_t colorNew = RGBW32(r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta); // WLEDMM - //if ((wdelta == 0) && (rdelta == 0) && (gdelta == 0) && (bdelta == 0)) continue; // WLEDMM delta = zero => no change // causes problem with text overlay - if (is2D()) setPixelColorXY((uint16_t)x, (uint16_t)y, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta); - else setPixelColor((uint16_t)x, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta); + if (colorNew != color) { // WLEDMM speedup - do not repaint the same color + if (is2D()) setPixelColorXY(x, y, colorNew); + else setPixelColor(x, colorNew); + } } } @@ -1836,6 +1847,7 @@ void WS2812FX::service() { if (!cctFromRgb || correctWB) busses.setSegmentCCT(seg.currentBri(seg.cct, true), correctWB); for (uint8_t c = 0; c < NUM_COLORS; c++) _colors_t[c] = gamma32(_colors_t[c]); + seg.startFrame(); // WLEDMM // effect blending (execute previous effect) // actual code may be a bit more involved as effects have runtime data including allocated memory //if (seg.transitional && seg._modeP) (*_mode[seg._modeP])(progress()); diff --git a/wled00/wled.h b/wled00/wled.h index be21de04..2ff0d902 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2408050 +#define VERSION 2408051 // WLEDMM - you can check for this define in usermods, to only enabled WLEDMM specific code in the "right" fork. Its not defined in AC WLED. #define _MoonModules_WLED_ From 9ee4165dad6fefd65fedc483ef34b8a620bcf073 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Mon, 5 Aug 2024 16:37:49 -0400 Subject: [PATCH 06/29] Freqmatrix stop identical first pixel/line --- wled00/FX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 4cce3230..d6c5820c 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7513,9 +7513,9 @@ uint16_t mode_freqmatrix(void) { // Freqmatrix. By Andreas Plesch } // shift the pixels one pixel up - SEGMENT.setPixelColor(0, color); // if SEGLEN equals 1 this loop won't execute for (int i = SEGLEN - 1; i > 0; i--) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i-1)); //move to the left + SEGMENT.setPixelColor(0, color); } return FRAMETIME; From 42919f9daf8e1073840b511cbc34f1e16f5986de Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 6 Aug 2024 15:53:46 +0200 Subject: [PATCH 07/29] blob effect improvements, and a dirty hack for HUB75 double buffer * mode_2Dfloatingblobs() improvements for large panels * Segment::fillCircle() speed optimizations * HUB75 hack (disabled by default): skip first fill(BLACK) when using double buffering (as the buffer gets cleared after each frame) --- wled00/FX.cpp | 9 ++++++--- wled00/FX.h | 5 +++-- wled00/FX_2Dfcn.cpp | 30 ++++++++++++++++++++++-------- wled00/FX_fcn.cpp | 12 ++++++++++++ wled00/wled.h | 2 +- 5 files changed, 44 insertions(+), 14 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index d6c5820c..a9bfccbb 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -6271,7 +6271,10 @@ uint16_t mode_2Dfloatingblobs(void) { } SEGMENT.fadeToBlackBy(20); - bool drawAA = (SEGMENT.custom1 > 0) && (SEGMENT.custom1 < 5); //WLEDMM + bool drawAA = (SEGMENT.custom1 > 0) && (SEGMENT.custom1 < 6); //WLEDMM + const uint16_t minDim = min(cols, rows); // WLEDMM use smaller dimension to find good blob size + float max_grow = min(minDim/4.f,2.f); + if (minDim>=24) max_grow =(minDim/8.0f); // WLEDMM allow bigger blobs // Bounce balls around for (size_t i = 0; i < Amount; i++) { @@ -6280,13 +6283,13 @@ uint16_t mode_2Dfloatingblobs(void) { if (blob->grow[i]) { // enlarge radius until it is >= 4 blob->r[i] += (fabsf(blob->sX[i]) > fabsf(blob->sY[i]) ? fabsf(blob->sX[i]) : fabsf(blob->sY[i])) * 0.05f; - if (blob->r[i] >= min(cols/4.f,2.f)) { + if (blob->r[i] >= max_grow) { blob->grow[i] = false; } } else { // reduce radius until it is < 1 blob->r[i] -= (fabsf(blob->sX[i]) > fabsf(blob->sY[i]) ? fabsf(blob->sX[i]) : fabsf(blob->sY[i])) * 0.05f; - if (blob->r[i] < 1.f) { + if (blob->r[i] < 0.8f) { blob->grow[i] = true; } } diff --git a/wled00/FX.h b/wled00/FX.h index aa5014e2..1393d5a2 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -439,6 +439,7 @@ typedef struct Segment { bool _isSimpleSegment = false; bool _isValid2D = false; uint8_t _brightness = 255; // final pixel brightness - including transitions and segment opacity + bool _firstFill = true; // dirty HACK support uint16_t _2dWidth = 0; // virtualWidth uint16_t _2dHeight = 0; // virtualHeight @@ -741,8 +742,8 @@ typedef struct Segment { 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); } - void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false); - 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 fillCircle(unsigned cx, unsigned cy, int radius, uint32_t col, bool soft); + inline void fillCircle(unsigned cx, unsigned cy, int 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, uint8_t depth = UINT8_MAX); inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, bool soft = false, uint8_t depth = UINT8_MAX) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0), soft, depth); } // automatic inline void drawArc(uint16_t x0, uint16_t y0, uint16_t radius, uint32_t color, uint32_t fillColor = 0); diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index df4387db..e6587d7d 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -226,6 +226,9 @@ void Segment::startFrame(void) { // if (reverse_y) _isSimpleSegment = false; // for A/B testing _2dWidth = is2D() ? calc_virtualWidth() : virtualLength(); _2dHeight = calc_virtualHeight(); + #if 0 && defined(WLED_ENABLE_HUB75MATRIX) + _firstFill = true; // dirty HACK + #endif #endif } // WLEDMM end @@ -651,19 +654,26 @@ 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 +void Segment::fillCircle(unsigned cx, unsigned cy, int radius, uint32_t col, bool soft) { + if (!isActive() || radius <= 0) return; // not active // draw soft bounding circle if (soft) drawCircle(cx, cy, radius, col, soft); - // 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 && - int16_t(cx)+x>=0 && int16_t(cy)+y>=0 && - int16_t(cx)+x 3) && !soft) ? 1:0); // WLEDMM pre-compute r^2; '-1' removes spikes from bigger blobs + // WLEDMM pre-compute boundaries + const int startx = max(-radius, -int(cx)); + const int endx = min(radius, cols-1-int(cx)); + const int starty = max(-radius, -int(cy)); + const int endy = min(radius, rows-1-int(cy)); + + // fill it - WLEDMM optimized + for (int y = starty; y <= endy; y++) { + for (int x = startx; x <= endx; x++) { + if ((x * x + y * y) <= maxRadius2) { setPixelColorXY(cx + x, cy + y, col); + } } } } @@ -690,7 +700,11 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3 uint32_t scaled_col = c; if (simpleSegment) { // segment brightness must be pre-calculated for the "fast" setPixelColorXY variant! + #ifdef WLEDMM_FASTPATH + uint8_t _bri_t = _brightness; + #else uint8_t _bri_t = currentBri(on ? opacity : 0); + #endif if (!_bri_t && !transitional) return; if (_bri_t < 255) scaled_col = color_fade(c, _bri_t); } diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index faf23625..0e63c853 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1347,6 +1347,18 @@ void Segment::refreshLightCapabilities() { */ void Segment::fill(uint32_t c) { if (!isActive()) return; // not active + + #if 0 && defined(WLED_ENABLE_HUB75MATRIX) && defined(WLEDMM_FASTPATH) + // DIRTY HACK - this ignores the first fill(black) in each frame, knowing that HUB75 has already blanked out the display. + if (_firstFill) { + _firstFill = false; + if (c == BLACK) { + if (ledsrgb && ledsrgbSize > 0) memset(ledsrgb, 0, ledsrgbSize); + return; + } + } + #endif + const uint_fast16_t cols = is2D() ? virtualWidth() : virtualLength(); // WLEDMM use fast int types const uint_fast16_t rows = virtualHeight(); // will be 1 for 1D diff --git a/wled00/wled.h b/wled00/wled.h index 2ff0d902..34667df1 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2408051 +#define VERSION 2408060 // WLEDMM - you can check for this define in usermods, to only enabled WLEDMM specific code in the "right" fork. Its not defined in AC WLED. #define _MoonModules_WLED_ From 5778b596beb8142896cd8a008ae98adb71c6c73d Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Tue, 6 Aug 2024 10:44:44 -0400 Subject: [PATCH 08/29] ESP32-ETHERNET-KIT-VE Fix Changed eth_address from 0 to 1 based on testing with devkit as it wasn't working by default with 0 --- wled00/network.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/network.cpp b/wled00/network.cpp index 1e414d81..7e0048d8 100644 --- a/wled00/network.cpp +++ b/wled00/network.cpp @@ -89,7 +89,7 @@ const ethernet_settings ethernetBoards[] = { // ESP32-ETHERNET-KIT-VE { - 0, // eth_address, + 1, // eth_address, WLED-MM: Changed from 0 to 1 based on not working with 0 on same devkit. 5, // eth_power, 23, // eth_mdc, 18, // eth_mdio, From 273154db762f8e17c0a756c4370741f8c7acdcd4 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 6 Aug 2024 18:13:59 +0200 Subject: [PATCH 09/29] drawArc speedup (Circle mapping mode) * Optimize drawArc to skip pixels that are off-screen or outside the circle's bounding box. Also move repeating calculations out of the inner loop. testcase 64x64 : 8fps --> 33 fps :-) --- wled00/FX.h | 4 ++-- wled00/FX_2Dfcn.cpp | 42 +++++++++++++++++++++++++----------------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 1393d5a2..98e934e0 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -746,8 +746,8 @@ typedef struct Segment { inline void fillCircle(unsigned cx, unsigned cy, int 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, uint8_t depth = UINT8_MAX); inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, bool soft = false, uint8_t depth = UINT8_MAX) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0), soft, depth); } // automatic inline - void drawArc(uint16_t x0, uint16_t y0, uint16_t radius, uint32_t color, uint32_t fillColor = 0); - inline void drawArc(uint16_t x0, uint16_t y0, uint16_t radius, CRGB color, CRGB fillColor = BLACK) { drawArc(x0, y0, radius, RGBW32(color.r,color.g,color.b,0), RGBW32(fillColor.r,fillColor.g,fillColor.b,0)); } // automatic inline + void drawArc(unsigned x0, unsigned y0, int radius, uint32_t color, uint32_t fillColor = 0); + inline void drawArc(unsigned x0, unsigned y0, int radius, CRGB color, CRGB fillColor = BLACK) { drawArc(x0, y0, radius, RGBW32(color.r,color.g,color.b,0), RGBW32(fillColor.r,fillColor.g,fillColor.b,0)); } // 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); inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0)); } // automatic inline void wu_pixel(uint32_t x, uint32_t y, CRGB c); diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index e6587d7d..71fb0cb2 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -774,27 +774,34 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3 } } -void Segment::drawArc(uint16_t x0, uint16_t y0, uint16_t radius, uint32_t color, uint32_t fillColor) { - if (!isActive()) return; // not active - // float step = degrees / (2.85f*MAX(radius,1)); - // for (float rad = 0.0f; rad <= degrees+step/2; rad += step) { - // // may want to try float version as well (with or without antialiasing) - // int x = roundf(sin_t(rad) * radius); - // int y = roundf(cos_t(rad) * radius); - // setPixelColorXY(x+x0, y+y0, c); - // } - float minradius = radius - .5; - float maxradius = radius + .5; - for (int x=0; x= minradius * minradius && newX*newX + newY*newY <= maxradius * maxradius) + for (int x=startx; x= minradius2) && (distance2 <= maxradius2)) { setPixelColorXY(x, y, color); + } else { if (fillColor != 0) - if (newX*newX + newY*newY < minradius * minradius) + if (distance2 < minradius2) setPixelColorXY(x, y, fillColor); + } } } @@ -890,10 +897,11 @@ void Segment::wu_pixel(uint32_t x, uint32_t y, CRGB c) { //awesome wu_pixel // multiply the intensities by the colour, and saturating-add them to the pixels for (int i = 0; i < 4; i++) { CRGB led = getPixelColorXY((x >> 8) + (i & 1), (y >> 8) + ((i >> 1) & 1)); + CRGB oldLed = led; led.r = qadd8(led.r, c.r * wu[i] >> 8); led.g = qadd8(led.g, c.g * wu[i] >> 8); led.b = qadd8(led.b, c.b * wu[i] >> 8); - setPixelColorXY(int((x >> 8) + (i & 1)), int((y >> 8) + ((i >> 1) & 1)), led); + if (led != oldLed) setPixelColorXY(int((x >> 8) + (i & 1)), int((y >> 8) + ((i >> 1) & 1)), led); // WLEDMM don't repaint same color } } #undef WU_WEIGHT From 7f9da309c9d37a27226b0a2e247e47494fafa50b Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 7 Aug 2024 14:58:38 +0200 Subject: [PATCH 10/29] const const const adding hints for the compiler for optimization. In case your custom build complains about "const", just remove the keyword. based on https://github.com/Aircoookie/WLED/commit/e82f38e277b6ad3d7b943b8868c3f88cb7c53382, but going further :-) * "const" class functions : function does not modify any class attributes ( --> "this" becomes const) * __attribute__((pure)) : function return value depends only on the parameters and/or global variables. The function does not modify any global or static variables. * __attribute__((const)) : function only examines arguments (no globals), and has no effects except the return value. This slightly more strict than "pure" * hot: tells the compiler "this functions is called very often" * cold: the opposite of hot --- usermods/audioreactive/audio_reactive.h | 2 +- wled00/FX.h | 74 ++++++++++---------- wled00/FX_2Dfcn.cpp | 8 +-- wled00/FX_fcn.cpp | 36 +++++----- wled00/bus_manager.cpp | 34 +++++----- wled00/bus_manager.h | 90 ++++++++++++------------- wled00/colors.cpp | 14 ++-- wled00/fcn_declare.h | 15 +++-- wled00/led.cpp | 2 +- wled00/pin_manager.cpp | 4 +- wled00/pin_manager.h | 4 +- wled00/src/dependencies/time/TimeLib.h | 2 +- wled00/wled.h | 6 +- wled00/wled00.ino | 2 + 14 files changed, 148 insertions(+), 145 deletions(-) diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index f7c91594..709a5960 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -285,7 +285,7 @@ static volatile float micReal_max2 = 0.0f; // MicIn data max afte // some prototypes, to ensure consistent interfaces static float mapf(float x, float in_min, float in_max, float out_min, float out_max); // map function for float static float fftAddAvg(int from, int to); // average of several FFT result bins -void FFTcode(void * parameter); // audio processing task: read samples, run FFT, fill GEQ channels from FFT results +void FFTcode(void * parameter) __attribute__((noreturn)); // audio processing task: read samples, run FFT, fill GEQ channels from FFT results static void runMicFilter(uint16_t numSamples, float *sampleBuffer); // pre-filtering of raw samples (band-pass) static void postProcessFFTResults(bool noiseGateOpen, int numberOfChannels, bool i2sFastpath); // post-processing and post-amp of GEQ channels diff --git a/wled00/FX.h b/wled00/FX.h index 98e934e0..387b9e55 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -33,7 +33,7 @@ bool canUseSerial(void); // WLEDMM implemented in wled_serial.cpp void strip_wait_until_idle(String whoCalledMe); // WLEDMM implemented in FX_fcn.cpp -bool strip_uses_global_leds(void); // WLEDMM implemented in FX_fcn.cpp +bool strip_uses_global_leds(void) __attribute__((pure)); // WLEDMM implemented in FX_fcn.cpp #define FASTLED_INTERNAL //remove annoying pragma messages #define USE_GET_MILLISECOND_TIMER @@ -640,7 +640,7 @@ 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); } - uint32_t __attribute__((pure)) getPixelColor(int i); // WLEDMM attribute added + uint32_t __attribute__((pure)) getPixelColor(int i) const; // WLEDMM attribute added // 1D support functions (some implement 2D as well) void blur(uint8_t, bool smear = false); void fill(uint32_t c); @@ -652,7 +652,7 @@ typedef struct Segment { inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColor(n, RGBW32(r,g,b,w), fast); } // automatically inline inline void addPixelColor(int n, CRGB c, bool fast = false) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), fast); } // automatically inline void fadePixelColor(uint16_t n, uint8_t fade); - uint8_t get_random_wheel_index(uint8_t pos); + uint8_t get_random_wheel_index(uint8_t pos) const; uint32_t __attribute__((pure)) color_from_palette(uint_fast16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255); uint32_t __attribute__((pure)) color_wheel(uint8_t pos); @@ -693,7 +693,7 @@ typedef struct Segment { void deletejMap(); //WLEDMM jMap #ifndef WLED_DISABLE_2D - inline uint16_t XY(uint_fast16_t x, uint_fast16_t y) { // support function to get relative index within segment (for leds[]) // WLEDMM inline for speed + inline uint16_t XY(uint_fast16_t x, uint_fast16_t y) const { // support function to get relative index within segment (for leds[]) // WLEDMM inline for speed uint_fast16_t width = max(uint16_t(1), virtualWidth()); // segment width in logical pixels -- softhack007 avoid div/0 uint_fast16_t height = max(uint16_t(1), virtualHeight()); // segment height in logical pixels -- softhack007 avoid div/0 return (x%width) + (y%height) * width; @@ -726,7 +726,7 @@ typedef struct Segment { inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColorXY(x, y, RGBW32(r,g,b,w), aa); } inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), aa); } //#endif - uint32_t __attribute__((pure)) getPixelColorXY(int x, int y); + uint32_t __attribute__((pure)) getPixelColorXY(int x, int y) const; // 2D support functions void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t 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); } @@ -792,7 +792,7 @@ typedef struct Segment { 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 wu_pixel(uint32_t x, uint32_t y, CRGB c) {} #endif - uint8_t * getAudioPalette(int pal); //WLEDMM netmindz ar palette + uint8_t * getAudioPalette(int pal) const; //WLEDMM netmindz ar palette } segment; //static int segSize = sizeof(Segment); @@ -915,64 +915,64 @@ class WS2812FX { // 96 bytes bool checkSegmentAlignment(void), - hasRGBWBus(void), - hasCCTBus(void), + hasRGBWBus(void) const, + hasCCTBus(void) const, // return true if the strip is being sent pixel updates - isUpdating(void), + isUpdating(void) const, deserializeMap(uint8_t n=0), useLedsArray = false; - inline bool isServicing(void) { return _isServicing; } - inline bool hasWhiteChannel(void) {return _hasWhiteChannel;} - inline bool isOffRefreshRequired(void) {return _isOffRefreshRequired;} + inline bool isServicing(void) const { return _isServicing; } + inline bool hasWhiteChannel(void) const {return _hasWhiteChannel;} + inline bool isOffRefreshRequired(void) const {return _isOffRefreshRequired;} uint8_t paletteFade, paletteBlend, milliampsPerLed, cctBlending, - getActiveSegmentsNum(void), - getFirstSelectedSegId(void), - getLastActiveSegmentId(void), - getActiveSegsLightCapabilities(bool selectedOnly = false), + getActiveSegmentsNum(void) const, + getFirstSelectedSegId(void) __attribute__((pure)), + getLastActiveSegmentId(void) const, + getActiveSegsLightCapabilities(bool selectedOnly = false) __attribute__((pure)), setPixelSegment(uint8_t n); - inline uint8_t getBrightness(void) { return _brightness; } - inline uint8_t getMaxSegments(void) { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value) - inline uint8_t getSegmentsNum(void) { return _segments.size(); } // returns currently present segments - inline uint8_t getCurrSegmentId(void) { return _segment_index; } - inline uint8_t getMainSegmentId(void) { return _mainSegment; } - inline uint8_t getPaletteCount() { return 13 + GRADIENT_PALETTE_COUNT; } // will only return built-in palette count - inline uint8_t getTargetFps() { return _targetFps; } - inline uint8_t getModeCount() { return _modeCount; } + inline uint8_t getBrightness(void) const { return _brightness; } + inline uint8_t getMaxSegments(void) const { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value) + inline uint8_t getSegmentsNum(void) const { return _segments.size(); } // returns currently present segments + inline uint8_t getCurrSegmentId(void) const { return _segment_index; } + inline uint8_t getMainSegmentId(void) const { return _mainSegment; } + inline uint8_t getPaletteCount() const { return 13 + GRADIENT_PALETTE_COUNT; } // will only return built-in palette count + inline uint8_t getTargetFps() const { return _targetFps; } + inline uint8_t getModeCount() const { return _modeCount; } uint16_t ablMilliampsMax, currentMilliamps, - getLengthPhysical(void), - __attribute__((pure)) getLengthTotal(void), // will include virtual/nonexistent pixels in matrix //WLEDMM attribute added - getFps(); + getLengthPhysical(void) const, + __attribute__((pure)) getLengthTotal(void) const, // will include virtual/nonexistent pixels in matrix //WLEDMM attribute added + getFps() const; - inline uint16_t getFrameTime(void) { return _frametime; } - inline uint16_t getMinShowDelay(void) { return MIN_SHOW_DELAY; } - inline uint16_t getLength(void) { return _length; } // 2D matrix may have less pixels than W*H - inline uint16_t getTransition(void) { return _transitionDur; } + inline uint16_t getFrameTime(void) const { return _frametime; } + inline uint16_t getMinShowDelay(void) const { return MIN_SHOW_DELAY; } + inline uint16_t getLength(void) const { return _length; } // 2D matrix may have less pixels than W*H + inline uint16_t getTransition(void) const { return _transitionDur; } uint32_t now, timebase; - uint32_t __attribute__((pure)) getPixelColor(uint_fast16_t); // WLEDMM attribute pure = does not have side-effects + uint32_t __attribute__((pure)) getPixelColor(uint_fast16_t) const; // WLEDMM attribute pure = does not have side-effects - inline uint32_t getLastShow(void) { return _lastShow; } - inline uint32_t segColor(uint8_t i) { return _colors_t[i]; } + inline uint32_t getLastShow(void) const { return _lastShow; } + inline uint32_t segColor(uint8_t i) const { return _colors_t[i]; } const char * - getModeData(uint8_t id = 0) { return (id && id<_modeCount) ? _modeData[id] : PSTR("Solid"); } + getModeData(uint8_t id = 0) const { return (id && id<_modeCount) ? _modeData[id] : PSTR("Solid"); } const char ** getModeDataSrc(void) { return &(_modeData[0]); } // vectors use arrays for underlying data - Segment& getSegment(uint8_t id); + Segment& getSegment(uint8_t id) __attribute__((pure)); inline Segment& getFirstSelectedSeg(void) { return _segments[getFirstSelectedSegId()]; } inline Segment& getMainSegment(void) { return _segments[getMainSegmentId()]; } inline Segment* getSegments(void) { return &(_segments[0]); } @@ -1039,7 +1039,7 @@ class WS2812FX { // 96 bytes inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } uint32_t - getPixelColorXY(uint16_t, uint16_t); + getPixelColorXY(uint16_t, uint16_t) const; // end 2D support diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 71fb0cb2..e966381a 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -177,7 +177,7 @@ void WS2812FX::setUpMatrix() { } // absolute matrix version of setPixelColor(), without error checking -void IRAM_ATTR WS2812FX::setPixelColorXY_fast(int x, int y, uint32_t col) //WLEDMM: IRAM_ATTR conditionally +void IRAM_ATTR __attribute__((hot)) WS2812FX::setPixelColorXY_fast(int x, int y, uint32_t col) //WLEDMM: IRAM_ATTR conditionally { uint_fast16_t index = y * Segment::maxWidth + x; if (index < customMappingSize) index = customMappingTable[index]; @@ -200,7 +200,7 @@ void IRAM_ATTR_YN WS2812FX::setPixelColorXY(int x, int y, uint32_t col) //WLEDMM } // returns RGBW values of pixel -uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) { +uint32_t __attribute__((hot)) WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) const { #ifndef WLED_DISABLE_2D uint_fast16_t index = (y * Segment::maxWidth + x); //WLEDMM: use fast types #else @@ -239,7 +239,7 @@ void Segment::startFrame(void) { // Simplified version of Segment::setPixelColorXY - without error checking. Does not support grouping or spacing // * expects scaled color (final brightness) as additional input parameter, plus segment virtualWidth() and virtualHeight() -void IRAM_ATTR Segment::setPixelColorXY_fast(int x, int y, uint32_t col, uint32_t scaled_col, int cols, int rows) //WLEDMM +void IRAM_ATTR __attribute__((hot)) Segment::setPixelColorXY_fast(int x, int y, uint32_t col, uint32_t scaled_col, int cols, int rows) //WLEDMM { unsigned i = UINT_MAX; bool sameColor = false; @@ -406,7 +406,7 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa, bool fast } // returns RGBW values of pixel -uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) { +uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const { if (x<0 || y<0 || !isActive()) return 0; // not active or out-of range if (ledsrgb) { int i = XY(x,y); diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 0e63c853..8a9533cd 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -882,7 +882,7 @@ uint16_t Segment::virtualLength() const { } //WLEDMM used for M12_sBlock -void xyFromBlock(uint16_t &x,uint16_t &y, uint16_t i, uint16_t vW, uint16_t vH, uint16_t vStrip) { +static void xyFromBlock(uint16_t &x,uint16_t &y, uint16_t i, uint16_t vW, uint16_t vH, uint16_t vStrip) { float i2; if (i<=SEGLEN*0.25) { //top, left to right i2 = i/(SEGLEN*0.25); @@ -907,7 +907,7 @@ void xyFromBlock(uint16_t &x,uint16_t &y, uint16_t i, uint16_t vW, uint16_t vH, } -void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATTR conditionally +void IRAM_ATTR_YN __attribute__((hot)) Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATTR conditionally { if (!isActive()) return; // not active #ifndef WLED_DISABLE_2D @@ -1171,7 +1171,7 @@ void Segment::setPixelColor(float i, uint32_t col, bool aa) } } -uint32_t Segment::getPixelColor(int i) +uint32_t __attribute__((hot)) Segment::getPixelColor(int i) const { if (!isActive()) return 0; // not active #ifndef WLED_DISABLE_2D @@ -1345,7 +1345,7 @@ void Segment::refreshLightCapabilities() { /* * Fills segment with color - WLEDMM using faster sPC if possible */ -void Segment::fill(uint32_t c) { +void __attribute__((hot)) Segment::fill(uint32_t c) { if (!isActive()) return; // not active #if 0 && defined(WLED_ENABLE_HUB75MATRIX) && defined(WLEDMM_FASTPATH) @@ -1457,7 +1457,7 @@ void Segment::fade_out(uint8_t rate) { } // fades all pixels to black using nscale8() -void Segment::fadeToBlackBy(uint8_t fadeBy) { +void __attribute__((hot)) Segment::fadeToBlackBy(uint8_t fadeBy) { if (!isActive() || fadeBy == 0) return; // optimization - no scaling to apply const uint_fast16_t cols = is2D() ? virtualWidth() : virtualLength(); // WLEDMM use fast int types const uint_fast16_t rows = virtualHeight(); // will be 1 for 1D @@ -1480,7 +1480,7 @@ void Segment::fadeToBlackBy(uint8_t fadeBy) { /* * blurs segment content, source: FastLED colorutils.cpp */ -void Segment::blur(uint8_t blur_amount, bool smear) { +void __attribute__((hot)) Segment::blur(uint8_t blur_amount, bool smear) { if (!isActive() || blur_amount == 0) return; // optimization: 0 means "don't blur" #ifndef WLED_DISABLE_2D if (is2D()) { @@ -1541,7 +1541,7 @@ uint32_t Segment::color_wheel(uint8_t pos) { /* * Returns a new, random wheel index with a minimum distance of 42 from pos. */ -uint8_t Segment::get_random_wheel_index(uint8_t pos) { // WLEDMM use fast int types, use native min/max +uint8_t Segment::get_random_wheel_index(uint8_t pos) const { // WLEDMM use fast int types, use native min/max uint_fast8_t r = 0, x = 0, y = 0, d = 0; while(d < 42) { @@ -1562,7 +1562,7 @@ uint8_t Segment::get_random_wheel_index(uint8_t pos) { // WLEDMM use fast int ty * @param pbri Value to scale the brightness of the returned color by. Default is 255. (no scaling) * @returns Single color from palette */ -uint32_t Segment::color_from_palette(uint_fast16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) // WLEDMM use fast int types +uint32_t __attribute__((hot)) Segment::color_from_palette(uint_fast16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) // WLEDMM use fast int types { // default palette or no RGB support on segment if ((palette == 0 && mcol < NUM_COLORS) || !_isRGB) { @@ -1582,7 +1582,7 @@ uint32_t Segment::color_from_palette(uint_fast16_t i, bool mapping, bool wrap, u } //WLEDMM netmindz ar palette -uint8_t * Segment::getAudioPalette(int pal) { +uint8_t * Segment::getAudioPalette(int pal) const { // https://forum.makerforums.info/t/hi-is-it-possible-to-define-a-gradient-palette-at-runtime-the-define-gradient-palette-uses-the/63339 um_data_t *um_data; @@ -1891,7 +1891,7 @@ void IRAM_ATTR WS2812FX::setPixelColor(int i, uint32_t col) busses.setPixelColor(i, col); } -uint32_t WS2812FX::getPixelColor(uint_fast16_t i) // WLEDMM fast int types +uint32_t WS2812FX::getPixelColor(uint_fast16_t i) const // WLEDMM fast int types { if (i < customMappingSize) i = customMappingTable[i]; if (i >= _length) return 0; @@ -2029,7 +2029,7 @@ void WS2812FX::show(void) { * Returns a true value if any of the strips are still being updated. * On some hardware (ESP32), strip updates are done asynchronously. */ -bool WS2812FX::isUpdating() { +bool WS2812FX::isUpdating() const { return !busses.canAllShow(); } @@ -2037,7 +2037,7 @@ bool WS2812FX::isUpdating() { * Returns the refresh rate of the LED strip. Useful for finding out whether a given setup is fast enough. * Only updates on show() or is set to 0 fps if last show is more than 2 secs ago, so accuracy varies */ -uint16_t WS2812FX::getFps() { +uint16_t WS2812FX::getFps() const { if (millis() - _lastShow > 2000) return 0; #ifdef ARDUINO_ARCH_ESP32 return ((_cumulativeFps500 + 250) / 500); // +250 for proper rounding @@ -2128,14 +2128,14 @@ void WS2812FX::setMainSegmentId(uint8_t n) { return; } -uint8_t WS2812FX::getLastActiveSegmentId(void) { +uint8_t WS2812FX::getLastActiveSegmentId(void) const { for (size_t i = _segments.size() -1; i > 0; i--) { if (_segments[i].isActive()) return i; } return 0; } -uint8_t WS2812FX::getActiveSegmentsNum(void) { +uint8_t WS2812FX::getActiveSegmentsNum(void) const { uint8_t c = 0; for (size_t i = 0; i < _segments.size(); i++) { if (_segments[i].isActive()) c++; @@ -2143,13 +2143,13 @@ uint8_t WS2812FX::getActiveSegmentsNum(void) { return c; } -uint16_t WS2812FX::getLengthTotal(void) { // WLEDMM fast int types +uint16_t WS2812FX::getLengthTotal(void) const { // WLEDMM fast int types uint_fast16_t len = Segment::maxWidth * Segment::maxHeight; // will be _length for 1D (see finalizeInit()) but should cover whole matrix for 2D if (isMatrix && _length > len) len = _length; // for 2D with trailing strip return len; } -uint16_t WS2812FX::getLengthPhysical(void) { // WLEDMM fast int types +uint16_t WS2812FX::getLengthPhysical(void) const { // WLEDMM fast int types uint_fast16_t len = 0; for (unsigned b = 0; b < busses.getNumBusses(); b++) { // WLEDMM use native (fast) types Bus *bus = busses.getBus(b); @@ -2162,7 +2162,7 @@ uint16_t WS2812FX::getLengthPhysical(void) { // WLEDMM fast int types //used for JSON API info.leds.rgbw. Little practical use, deprecate with info.leds.rgbw. //returns if there is an RGBW bus (supports RGB and White, not only white) //not influenced by auto-white mode, also true if white slider does not affect output white channel -bool WS2812FX::hasRGBWBus(void) { +bool WS2812FX::hasRGBWBus(void) const { for (unsigned b = 0; b < busses.getNumBusses(); b++) { // WLEDMM use native (fast) types Bus *bus = busses.getBus(b); if (bus == nullptr || bus->getLength()==0) break; @@ -2171,7 +2171,7 @@ bool WS2812FX::hasRGBWBus(void) { return false; } -bool WS2812FX::hasCCTBus(void) { +bool WS2812FX::hasCCTBus(void) const { if (cctFromRgb && !correctWB) return false; for (unsigned b = 0; b < busses.getNumBusses(); b++) { // WLEDMM use native (fast) types Bus *bus = busses.getBus(b); diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 604a92c5..c8e42c57 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -86,7 +86,7 @@ uint8_t IRAM_ATTR ColorOrderMap::getPixelColorOrder(uint16_t pix, uint8_t defaul } -uint32_t Bus::autoWhiteCalc(uint32_t c) { +uint32_t Bus::autoWhiteCalc(uint32_t c) const { uint8_t aWM = _autoWhiteMode; if (_gAWM != AW_GLOBAL_DISABLED) aWM = _gAWM; if (aWM == RGBW_MODE_MANUAL_ONLY) return c; @@ -139,7 +139,7 @@ void BusDigital::show() { PolyBus::show(_busPtr, _iType); } -bool BusDigital::canShow() { +bool BusDigital::canShow() const { return PolyBus::canShow(_busPtr, _iType); } @@ -182,7 +182,7 @@ void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) { PolyBus::setPixelColor(_busPtr, _iType, pix, c, co); } -uint32_t IRAM_ATTR_YN BusDigital::getPixelColor(uint16_t pix) { +uint32_t IRAM_ATTR_YN BusDigital::getPixelColor(uint16_t pix) const { if (reversed) pix = _len - pix -1; else pix += _skip; uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder); @@ -200,7 +200,7 @@ uint32_t IRAM_ATTR_YN BusDigital::getPixelColor(uint16_t pix) { return PolyBus::getPixelColor(_busPtr, _iType, pix, co); } -uint8_t BusDigital::getPins(uint8_t* pinArray) { +uint8_t BusDigital::getPins(uint8_t* pinArray) const { uint8_t numPins = IS_2PIN(_type) ? 2 : 1; for (uint8_t i = 0; i < numPins; i++) pinArray[i] = _pins[i]; return numPins; @@ -317,7 +317,7 @@ void BusPwm::setPixelColor(uint16_t pix, uint32_t c) { } //does no index check -uint32_t BusPwm::getPixelColor(uint16_t pix) { +uint32_t BusPwm::getPixelColor(uint16_t pix) const { if (!_valid) return 0; #if 1 // WLEDMM stick with the old code - we don't have cctICused @@ -356,7 +356,7 @@ void BusPwm::show() { } } -uint8_t BusPwm::getPins(uint8_t* pinArray) { +uint8_t BusPwm::getPins(uint8_t* pinArray) const { if (!_valid) return 0; uint8_t numPins = NUM_PWM_PINS(_type); for (uint8_t i = 0; i < numPins; i++) { @@ -408,7 +408,7 @@ void BusOnOff::setPixelColor(uint16_t pix, uint32_t c) { _data = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0; } -uint32_t BusOnOff::getPixelColor(uint16_t pix) { +uint32_t BusOnOff::getPixelColor(uint16_t pix) const { if (!_valid) return 0; return RGBW32(_data, _data, _data, _data); } @@ -418,7 +418,7 @@ void BusOnOff::show() { digitalWrite(_pin, reversed ? !(bool)_data : (bool)_data); } -uint8_t BusOnOff::getPins(uint8_t* pinArray) { +uint8_t BusOnOff::getPins(uint8_t* pinArray) const { if (!_valid) return 0; pinArray[0] = _pin; return 1; @@ -467,7 +467,7 @@ void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) { if (_rgbw) _data[offset+3] = W(c); } -uint32_t BusNetwork::getPixelColor(uint16_t pix) { +uint32_t BusNetwork::getPixelColor(uint16_t pix) const { if (!_valid || pix >= _len) return 0; uint16_t offset = pix * _UDPchannels; return RGBW32(_data[offset], _data[offset+1], _data[offset+2], _rgbw ? (_data[offset+3] << 24) : 0); @@ -480,7 +480,7 @@ void BusNetwork::show() { _broadcastLock = false; } -uint8_t BusNetwork::getPins(uint8_t* pinArray) { +uint8_t BusNetwork::getPins(uint8_t* pinArray) const { for (uint8_t i = 0; i < 4; i++) { pinArray[i] = _client[i]; } @@ -698,7 +698,7 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh USER_PRINTLN("MatrixPanel_I2S_DMA started"); } -void BusHub75Matrix::setPixelColor(uint16_t pix, uint32_t c) { +void __attribute__((hot)) BusHub75Matrix::setPixelColor(uint16_t pix, uint32_t c) { if (!_valid || pix >= _len) return; #ifndef NO_CIE1931 c = unGamma24(c); // to use the driver linear brightness feature, we first need to undo WLED gamma correction @@ -823,7 +823,7 @@ void BusManager::setStatusPixel(uint32_t c) { } } -void IRAM_ATTR BusManager::setPixelColor(uint16_t pix, uint32_t c, int16_t cct) { +void IRAM_ATTR __attribute__((hot)) BusManager::setPixelColor(uint16_t pix, uint32_t c, int16_t cct) { if ((pix >= laststart) && (pix < lastend ) && (lastBus != nullptr)) { // WLEDMM same bus as last time - no need to search again lastBus->setPixelColor(pix - laststart, c); @@ -851,7 +851,7 @@ void BusManager::setBrightness(uint8_t b, bool immediate) { } } -void BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) { +void __attribute__((cold)) BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) { if (cct > 255) cct = 255; if (cct >= 0) { //if white balance correction allowed, save as kelvin value instead of 0-255 @@ -860,7 +860,7 @@ void BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) { Bus::setCCT(cct); } -uint32_t IRAM_ATTR BusManager::getPixelColor(uint_fast16_t pix) { // WLEDMM use fast native types, IRAM_ATTR +uint32_t IRAM_ATTR __attribute__((hot)) BusManager::getPixelColor(uint_fast16_t pix) { // WLEDMM use fast native types, IRAM_ATTR if ((pix >= laststart) && (pix < lastend ) && (lastBus != nullptr)) { // WLEDMM same bus as last time - no need to search again return lastBus->getPixelColor(pix - laststart); @@ -881,20 +881,20 @@ uint32_t IRAM_ATTR BusManager::getPixelColor(uint_fast16_t pix) { // WLEDMM return 0; } -bool BusManager::canAllShow() { +bool BusManager::canAllShow() const { for (uint8_t i = 0; i < numBusses; i++) { if (!busses[i]->canShow()) return false; } return true; } -Bus* BusManager::getBus(uint8_t busNr) { +Bus* BusManager::getBus(uint8_t busNr) const { if (busNr >= numBusses) return nullptr; return busses[busNr]; } //semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit()) -uint16_t BusManager::getTotalLength() { +uint16_t BusManager::getTotalLength() const { uint_fast16_t len = 0; for (uint_fast8_t i=0; igetLength(); // WLEDMM use fast native types return len; diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 40fc0061..18337026 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -113,35 +113,35 @@ class Bus { virtual bool canShow() { return true; } virtual void setStatusPixel(uint32_t c) {} virtual void setPixelColor(uint16_t pix, uint32_t c) = 0; - virtual uint32_t getPixelColor(uint16_t pix) { return 0; } + virtual uint32_t getPixelColor(uint16_t pix) const { return 0; } virtual void setBrightness(uint8_t b, bool immediate=false) { _bri = b; }; virtual void cleanup() = 0; - virtual uint8_t getPins(uint8_t* pinArray) { return 0; } - virtual uint16_t getLength() { return _len; } + virtual uint8_t getPins(uint8_t* pinArray) const { return 0; } + virtual uint16_t getLength() const { return _len; } virtual void setColorOrder() {} - virtual uint8_t getColorOrder() { return COL_ORDER_RGB; } + virtual uint8_t getColorOrder() const { return COL_ORDER_RGB; } virtual uint8_t skippedLeds() { return 0; } - virtual uint16_t getFrequency() { return 0U; } - inline uint16_t getStart() { return _start; } + virtual uint16_t getFrequency() const { return 0U; } + inline uint16_t getStart() const { return _start; } inline void setStart(uint16_t start) { _start = start; } - inline uint8_t getType() { return _type; } - inline bool isOk() { return _valid; } - inline bool isOffRefreshRequired() { return _needsRefresh; } - bool containsPixel(uint16_t pix) { return pix >= _start && pix < _start+_len; } - virtual uint16_t getMaxPixels() { return MAX_LEDS_PER_BUS; }; + inline uint8_t getType() const { return _type; } + inline bool isOk() const { return _valid; } + inline bool isOffRefreshRequired() const { return _needsRefresh; } + bool containsPixel(uint16_t pix) const { return pix >= _start && pix < _start+_len; } + virtual uint16_t getMaxPixels() const { return MAX_LEDS_PER_BUS; }; - virtual bool hasRGB() { + virtual bool hasRGB() const { if ((_type >= TYPE_WS2812_1CH && _type <= TYPE_WS2812_WWA) || _type == TYPE_ANALOG_1CH || _type == TYPE_ANALOG_2CH || _type == TYPE_ONOFF) return false; return true; } - virtual bool hasWhite() { return Bus::hasWhite(_type); } + virtual bool hasWhite() const { return Bus::hasWhite(_type); } static bool hasWhite(uint8_t type) { if ((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_SK6812_RGBW || type == TYPE_TM1814 || type == TYPE_UCS8904) return true; // digital types with white channel if (type > TYPE_ONOFF && type <= TYPE_ANALOG_5CH && type != TYPE_ANALOG_3CH) return true; // analog types with white channel if (type == TYPE_NET_DDP_RGBW) return true; // network types with white channel return false; } - virtual bool hasCCT() { + virtual bool hasCCT() const { if (_type == TYPE_WS2812_2CH_X3 || _type == TYPE_WS2812_WWA || _type == TYPE_ANALOG_2CH || _type == TYPE_ANALOG_5CH) return true; return false; @@ -158,7 +158,7 @@ class Bus { #endif } inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; } - inline uint8_t getAutoWhiteMode() { return _autoWhiteMode; } + inline uint8_t getAutoWhiteMode() const { return _autoWhiteMode; } inline static void setGlobalAWMode(uint8_t m) { if (m < 5) _gAWM = m; else _gAWM = AW_GLOBAL_DISABLED; } inline static uint8_t getGlobalAWMode() { return _gAWM; } @@ -176,7 +176,7 @@ class Bus { static int16_t _cct; static uint8_t _cctBlend; - uint32_t autoWhiteCalc(uint32_t c); + uint32_t autoWhiteCalc(uint32_t c) const; }; @@ -186,7 +186,7 @@ class BusDigital : public Bus { inline void show(); - bool canShow(); + bool canShow() const; void setBrightness(uint8_t b, bool immediate); @@ -194,25 +194,25 @@ class BusDigital : public Bus { void setPixelColor(uint16_t pix, uint32_t c); - uint32_t getPixelColor(uint16_t pix); + uint32_t getPixelColor(uint16_t pix) const; - uint8_t getColorOrder() { + uint8_t getColorOrder() const { return _colorOrder; } - uint16_t getLength() { + uint16_t getLength() const { return _len - _skip; } - uint8_t getPins(uint8_t* pinArray); + uint8_t getPins(uint8_t* pinArray) const; void setColorOrder(uint8_t colorOrder); - uint8_t skippedLeds() { + uint8_t skippedLeds() const { return _skip; } - uint16_t getFrequency() { return _frequencykHz; } + uint16_t getFrequency() const { return _frequencykHz; } void reinit(); @@ -240,13 +240,13 @@ class BusPwm : public Bus { void setPixelColor(uint16_t pix, uint32_t c); //does no index check - uint32_t getPixelColor(uint16_t pix); + uint32_t getPixelColor(uint16_t pix) const; void show(); - uint8_t getPins(uint8_t* pinArray); + uint8_t getPins(uint8_t* pinArray) const; - uint16_t getFrequency() { return _frequency; } + uint16_t getFrequency() const { return _frequency; } void cleanup() { deallocatePins(); @@ -274,11 +274,11 @@ class BusOnOff : public Bus { void setPixelColor(uint16_t pix, uint32_t c); - uint32_t getPixelColor(uint16_t pix); + uint32_t getPixelColor(uint16_t pix) const; void show(); - uint8_t getPins(uint8_t* pinArray); + uint8_t getPins(uint8_t* pinArray) const; void cleanup() { pinManager.deallocatePin(_pin, PinOwner::BusOnOff); @@ -298,24 +298,24 @@ class BusNetwork : public Bus { public: BusNetwork(BusConfig &bc); - uint16_t getMaxPixels() override { return 4096; }; - bool hasRGB() { return true; } - bool hasWhite() { return _rgbw; } + uint16_t getMaxPixels() const override { return 4096; }; + bool hasRGB() const { return true; } + bool hasWhite() const { return _rgbw; } void setPixelColor(uint16_t pix, uint32_t c); - uint32_t __attribute__((pure)) getPixelColor(uint16_t pix); // WLEDMM attribute added + uint32_t __attribute__((pure)) getPixelColor(uint16_t pix) const; // WLEDMM attribute added void show(); - bool canShow() { + bool canShow() const { // this should be a return value from UDP routine if it is still sending data out return !_broadcastLock; } - uint8_t getPins(uint8_t* pinArray); + uint8_t getPins(uint8_t* pinArray) const; - uint16_t getLength() { + uint16_t getLength() const { return _len; } @@ -339,10 +339,10 @@ class BusHub75Matrix : public Bus { public: BusHub75Matrix(BusConfig &bc); - uint16_t getMaxPixels() override { return 4096; }; + uint16_t getMaxPixels() const override { return 4096; }; - bool hasRGB() { return true; } - bool hasWhite() { return false; } + bool hasRGB() const { return true; } + bool hasWhite() const { return false; } void setPixelColor(uint16_t pix, uint32_t c); @@ -356,7 +356,7 @@ class BusHub75Matrix : public Bus { void setBrightness(uint8_t b, bool immediate); - uint8_t getPins(uint8_t* pinArray) { + uint8_t getPins(uint8_t* pinArray) const { pinArray[0] = mxconfig.chain_length; return 1; } // Fake value due to keep finaliseInit happy @@ -388,7 +388,7 @@ class BusManager { BusManager() {}; //utility to get the approx. memory usage of a given BusConfig - static uint32_t memUsage(BusConfig &bc); + static uint32_t memUsage(BusConfig &bc) __attribute__((pure)); int add(BusConfig &bc); @@ -407,12 +407,12 @@ class BusManager { uint32_t __attribute__((pure)) getPixelColor(uint_fast16_t pix); // WLEDMM attribute added - bool canAllShow(); + bool canAllShow() const; - Bus* getBus(uint8_t busNr); + Bus* getBus(uint8_t busNr) const; //semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit()) - uint16_t getTotalLength(); + uint16_t getTotalLength() const; inline void updateColorOrderMap(const ColorOrderMap &com) { memcpy(&colorOrderMap, &com, sizeof(ColorOrderMap)); @@ -422,7 +422,7 @@ class BusManager { return colorOrderMap; } - inline uint8_t getNumBusses() { + inline uint8_t getNumBusses() const { return numBusses; } @@ -435,7 +435,7 @@ class BusManager { unsigned laststart = 0; unsigned lastend = 0; - inline uint8_t getNumVirtualBusses() { + inline uint8_t getNumVirtualBusses() const { int j = 0; for (int i=0; igetType() >= TYPE_NET_DDP_RGB && busses[i]->getType() < 96) j++; return j; diff --git a/wled00/colors.cpp b/wled00/colors.cpp index f7751861..23cf2f13 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -7,7 +7,7 @@ /* * color blend function */ -IRAM_ATTR_YN uint32_t color_blend(uint32_t color1, uint32_t color2, uint_fast16_t blend, bool b16) { +IRAM_ATTR_YN __attribute__((hot)) uint32_t color_blend(uint32_t color1, uint32_t color2, uint_fast16_t blend, bool b16) { if(blend == 0) return color1; if (color1 == color2) return color1; // WLEDMM shortcut const uint_fast16_t blendmax = b16 ? 0xFFFF : 0xFF; @@ -71,7 +71,7 @@ IRAM_ATTR_YN uint32_t color_add(uint32_t c1, uint32_t c2, bool fast) // WLEDMM * if using "video" method the resulting color will never become black unless it is already black */ -IRAM_ATTR_YN uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) +IRAM_ATTR_YN __attribute__((hot)) uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) { if (amount == 0) return 0; // WLEDMM shortcut @@ -297,7 +297,7 @@ static float maxf (float v, float w) // WLEDMM better use standard library fmax // adjust RGB values based on color temperature in K (range [2800-10200]) (https://en.wikipedia.org/wiki/Color_balance) // called from bus manager when color correction is enabled! -uint32_t IRAM_ATTR_YN colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb) // WLEDMM: IRAM_ATTR_YN +uint32_t __attribute__((hot)) IRAM_ATTR_YN colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb) // WLEDMM: IRAM_ATTR_YN { //remember so that slow colorKtoRGB() doesn't have to run for every setPixelColor() static byte correctionRGB[4] = {0,0,0,0}; @@ -406,7 +406,7 @@ static void calcInvGammaTable(float gamma) gammaTinv[i] = (int)(powf((float)i / 255.0f, gammaInv) * 255.0f + 0.5f); } } -uint8_t unGamma8(uint8_t value) { +uint8_t __attribute__((hot)) unGamma8(uint8_t value) { //if (!gammaCorrectCol || (value == 0) || (value == 255)) return value; if ((value == 0) || (value == 255)) return value; if ((gammaCorrectVal < 0.999f) || (gammaCorrectVal > 3.0f)) return value; @@ -414,7 +414,7 @@ uint8_t unGamma8(uint8_t value) { return gammaTinv[value]; } -uint32_t unGamma24(uint32_t c) { +uint32_t __attribute__((hot)) unGamma24(uint32_t c) { if ((gammaCorrectVal < 0.999f) || (gammaCorrectVal > 3.0f)) return c; if (gammaTinv[255] == 0) calcInvGammaTable(gammaCorrectVal); return RGBW32(gammaTinv[R(c)], gammaTinv[G(c)], gammaTinv[B(c)], W(c)); @@ -438,13 +438,13 @@ void calcGammaTable(float gamma) } // used for individual channel or brightness gamma correction -IRAM_ATTR_YN uint8_t gamma8(uint8_t b) // WLEDMM added IRAM_ATTR_YN +IRAM_ATTR_YN __attribute__((hot)) uint8_t gamma8(uint8_t b) // WLEDMM added IRAM_ATTR_YN { return gammaT[b]; } // used for color gamma correction -uint32_t gamma32(uint32_t color) +uint32_t __attribute__((hot)) gamma32(uint32_t color) { if (!gammaCorrectCol) return color; uint8_t w = W(color); diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index a0713d0f..09f9724b 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -250,7 +250,7 @@ void refreshNodeList(); void sendSysInfoUDP(); //network.cpp -int getSignalQuality(int rssi); +int getSignalQuality(int rssi) __attribute__((const)); void WiFiEvent(WiFiEvent_t event); //um_manager.cpp @@ -369,7 +369,7 @@ bool oappendi(int i); // append new number to temp buffer efficiently void sappend(char stype, const char* key, int val); void sappends(char stype, const char* key, char* val); void prepareHostname(char* hostname); -bool isAsterisksOnly(const char* str, byte maxLen); +bool isAsterisksOnly(const char* str, byte maxLen) __attribute__((pure)); bool requestJSONBufferLock(uint8_t module=255); void releaseJSONBufferLock(); uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen); @@ -410,13 +410,14 @@ void clearEEPROM(); //wled_math.cpp #ifndef WLED_USE_REAL_MATH template T atan_t(T x); - float cos_t(float phi); - float sin_t(float x); - float tan_t(float x); + float cos_t(float phi) __attribute__((const)); + float sin_t(float x) __attribute__((const)); + float tan_t(float x) __attribute__((const)); float acos_t(float x); float asin_t(float x); - float floor_t(float x); - float fmod_t(float num, float denom); + float atan_t(float x) __attribute__((const)); + float floor_t(float x) __attribute__((const)); + float fmod_t(float num, float denom) __attribute__((const)); #else #include // WLEDMM use "float" variants #define sin_t sinf diff --git a/wled00/led.cpp b/wled00/led.cpp index 70863396..74520147 100644 --- a/wled00/led.cpp +++ b/wled00/led.cpp @@ -68,7 +68,7 @@ void toggleOnOff() //scales the brightness with the briMultiplier factor -IRAM_ATTR_YN byte scaledBri(byte in) // WLEDMM added IRAM_ATTR_YN +IRAM_ATTR_YN __attribute__((hot)) byte scaledBri(byte in) // WLEDMM added IRAM_ATTR_YN { if (briMultiplier == 100) return(in); // WLEDMM shortcut uint_fast16_t val = ((uint_fast16_t)in*(uint_fast16_t)briMultiplier)/100; // WLEDMM diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index a9c31bde..d1e7a18b 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -723,7 +723,7 @@ bool PinManagerClass::joinWire(int8_t pinSDA, int8_t pinSCL) { */ // Check if supplied GPIO is ok to use -bool PinManagerClass::isPinOk(byte gpio, bool output) +bool PinManagerClass::isPinOk(byte gpio, bool output) const { #ifdef ESP32 if (digitalPinIsValid(gpio)) { @@ -757,7 +757,7 @@ bool PinManagerClass::isPinOk(byte gpio, bool output) return false; } -PinOwner PinManagerClass::getPinOwner(byte gpio) { +PinOwner PinManagerClass::getPinOwner(byte gpio) const { if (gpio >= WLED_NUM_PINS) return PinOwner::None; // catch error case, to avoid array out-of-bounds access if (!isPinOk(gpio, false)) return PinOwner::None; return ownerTag[gpio]; diff --git a/wled00/pin_manager.h b/wled00/pin_manager.h index cb107f49..23d8d951 100644 --- a/wled00/pin_manager.h +++ b/wled00/pin_manager.h @@ -125,9 +125,9 @@ class PinManagerClass { // 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 isPinOk(byte gpio, bool output = true) const; - PinOwner getPinOwner(byte gpio); + PinOwner getPinOwner(byte gpio) const; // WLEDMM begin String getOwnerText(PinOwner tag); // WLEDMM - return PIN owner tag as text diff --git a/wled00/src/dependencies/time/TimeLib.h b/wled00/src/dependencies/time/TimeLib.h index 5004f071..a4388a03 100644 --- a/wled00/src/dependencies/time/TimeLib.h +++ b/wled00/src/dependencies/time/TimeLib.h @@ -116,7 +116,7 @@ char* dayShortStr(uint8_t day); /* low level functions to convert to and from system time */ void breakTime(time_t time, tmElements_t &tm); // break time_t into elements -time_t makeTime(tmElements_t &tm); // convert time elements into time_t +time_t makeTime(tmElements_t &tm) __attribute__((pure)); // convert time elements into time_t } // extern "C++" #endif // __cplusplus diff --git a/wled00/wled.h b/wled00/wled.h index 34667df1..1ea73805 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2408060 +#define VERSION 2408070 // WLEDMM - you can check for this define in usermods, to only enabled WLEDMM specific code in the "right" fork. Its not defined in AC WLED. #define _MoonModules_WLED_ @@ -928,9 +928,9 @@ public: } // boot starts here - void setup(); + void setup() __attribute__((used)); - void loop(); + void loop() __attribute__((used)); void reset(); void beginStrip(); diff --git a/wled00/wled00.ino b/wled00/wled00.ino index 056d8f28..b19441a2 100644 --- a/wled00/wled00.ino +++ b/wled00/wled00.ino @@ -61,6 +61,7 @@ void esp_heap_trace_free_hook(void* ptr) unsigned long lastMillis = 0; //WLEDMM unsigned long loopCounter = 0; //WLEDMM +void setup() __attribute__((used)); // needed for -flto void setup() { #ifdef WLED_DEBUG_HEAP esp_err_t error = heap_caps_register_failed_alloc_callback(heap_caps_alloc_failed_hook); @@ -68,6 +69,7 @@ void setup() { WLED::instance().setup(); } +void loop() __attribute__((used)); // needed for -flto void loop() { //WLEDMM show loops per second loopCounter++; From b2844645c6c3d4d505dcfe3429d26c623c786f71 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 7 Aug 2024 16:53:25 +0200 Subject: [PATCH 11/29] pinwheel mapping XXL - no holes at 64x64 --- wled00/FX_fcn.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 8a9533cd..35ed815e 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -812,10 +812,13 @@ 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 int Pinwheel_Size_XL = 58; // larger than this -> use "XXL" +constexpr int Pinwheel_Steps_XXL = 456; 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 float Int_to_Rad_XXL = (DEG_TO_RAD * 360) / Pinwheel_Steps_XXL; // conversion: from 0...456 to Radians constexpr int Fixed_Scale = 512; // fixpoint scaling factor (9bit for fraction) @@ -825,8 +828,9 @@ static float getPinwheelAngle(int i, int vW, int 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; + if (maxXY <= Pinwheel_Size_XL) return float(i) * Int_to_Rad_XL; // else - return float(i) * Int_to_Rad_XL; + return float(i) * Int_to_Rad_XXL; } // Pinwheel helper function: matrix dimensions to number of rays static int getPinwheelLength(int vW, int vH) { @@ -834,8 +838,9 @@ static int getPinwheelLength(int vW, int 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; + if (maxXY <= Pinwheel_Size_XL) return Pinwheel_Steps_XL; // else - return Pinwheel_Steps_XL; + return Pinwheel_Steps_XXL; } #endif From fb2402fb9766665f5f75d4a249791609c39b5ec5 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 7 Aug 2024 17:02:46 +0200 Subject: [PATCH 12/29] HUB75 optimization (double buffer only) In double duffer mode, the screen is blanked at each show(). So we can drop setPixelColor(BLACK) calls until we receive a pixel with different color. --- wled00/bus_manager.cpp | 6 +++++- wled00/bus_manager.h | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index c8e42c57..0f892f5f 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -503,7 +503,7 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh _valid = false; mxconfig.double_buff = false; // default to off, known to cause issue with some effects but needs more memory - + isBlack = false; fourScanPanel = nullptr; @@ -671,6 +671,8 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh } else { _valid = true; + display->clearScreen(); // initially clear the screen buffer + isBlack = true; } switch(bc.type) { @@ -700,6 +702,7 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh void __attribute__((hot)) BusHub75Matrix::setPixelColor(uint16_t pix, uint32_t c) { if (!_valid || pix >= _len) return; + if (isBlack && (c == BLACK)) return; // reject black pixels directly after clearScreen() #ifndef NO_CIE1931 c = unGamma24(c); // to use the driver linear brightness feature, we first need to undo WLED gamma correction #endif @@ -719,6 +722,7 @@ void __attribute__((hot)) BusHub75Matrix::setPixelColor(uint16_t pix, uint32_t int y = pix / pxwidth; display->drawPixelRGB888(int16_t(x), int16_t(y), r, g, b); } + isBlack = false; } void BusHub75Matrix::setBrightness(uint8_t b, bool immediate) { diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 18337026..cfea2674 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -351,6 +351,7 @@ class BusHub75Matrix : public Bus { display->flipDMABuffer(); // Show the back buffer, set currently output buffer to the back (i.e. no longer being sent to LED panels) // while(!previousBufferFree) delay(1); // experimental - Wait before we allow any writing to the buffer. Stop flicker. display->clearScreen(); // Now clear the back-buffer + isBlack = true; } } @@ -369,6 +370,7 @@ class BusHub75Matrix : public Bus { // delete fourScanPanel; delete display; _valid = false; + isBlack = false; } ~BusHub75Matrix() { @@ -379,6 +381,7 @@ class BusHub75Matrix : public Bus { MatrixPanel_I2S_DMA *display = nullptr; VirtualMatrixPanel *fourScanPanel = nullptr; HUB75_I2S_CFG mxconfig; + bool isBlack = false; }; #endif From 6e415dfbbeedc968eb47b678c130e1d4782cc5bd Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 7 Aug 2024 18:31:06 +0200 Subject: [PATCH 13/29] HUB75 hack HUB75 is very memory hungry - this hack deletes the mapping table when its not needed --> frees 8Kb with a 64x64 panel. --- wled00/FX_2Dfcn.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index e966381a..9660df63 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -171,6 +171,24 @@ void WS2812FX::setUpMatrix() { //WLEDMM: no resetSegments here, only do it in set.cpp/handleSettingsSet - as we want t0 maintain the segment settings after setup has changed } } + +#ifdef WLED_ENABLE_HUB75MATRIX + // softhack007 hack: delete mapping table in case it only contains "identity" + if (customMappingTable != nullptr && customMappingTableSize > 0) { + bool isIdentity = true; + for (size_t i = 0; (i< customMappingSize) && isIdentity; i++) { //WLEDMM use customMappingTableSize + if (customMappingTable[i] != (uint16_t)i ) isIdentity = false; + } + if (isIdentity) { + free(customMappingTable); customMappingTable = nullptr; + USER_PRINTF("!setupmatrix: customMappingTable is not needed. Dropping %d bytes.\n", customMappingTableSize * sizeof(uint16_t)); + customMappingTableSize = 0; + customMappingSize = 0; + loadedLedmap = 0; //WLEDMM + } + } +#endif + #else isMatrix = false; // no matter what config says #endif From 90dd04887848803cee976239e9fe94d57fa5c22a Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 8 Aug 2024 17:41:05 +0200 Subject: [PATCH 14/29] revert fadeToBlackBy optimization causes problems with overlay text (scrolling text) --- 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 35ed815e..0f6eb6da 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1473,7 +1473,8 @@ void __attribute__((hot)) Segment::fadeToBlackBy(uint8_t fadeBy) { for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) { uint32_t cc = getPixelColorXY(x,y); // WLEDMM avoid RGBW32 -> CRGB -> RGBW32 conversion uint32_t cc2 = color_fade(cc, scaledown); // fade - if (cc2 != cc) setPixelColorXY((uint16_t)x, (uint16_t)y, cc2); // WLEDMM only re-paint if faded color is different + //if (cc2 != cc) // WLEDMM only re-paint if faded color is different - disabled - causes problem with text overlay + setPixelColorXY((uint16_t)x, (uint16_t)y, cc2); } } else { for (uint_fast16_t x = 0; x < cols; x++) { From c66a8af85cfa91055be56802d1eed8865683943e Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 8 Aug 2024 17:44:13 +0200 Subject: [PATCH 15/29] reduce WiFi disconnects HUB75 is very heap-hungry - use a more relaxed metric for triggering "low heap emergency" actions --- wled00/wled.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 171be5c7..dfc7e75c 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -1220,7 +1220,7 @@ void WLED::handleConnection() #ifdef ARDUINO_ARCH_ESP32 // reconnect WiFi to clear stale allocations if heap gets too low if ((!strip.isUpdating()) && (now - heapTime > 5000)) { // WLEDMM: updated with better logic for small heap available by block, not total. // WLEDMM trying to use a moment when the strip is idle -#if defined(ARDUINO_ARCH_ESP32S2) +#if defined(ARDUINO_ARCH_ESP32S2) || defined(WLED_ENABLE_HUB75MATRIX) uint32_t heap = ESP.getFreeHeap(); // WLEDMM works better on -S2 #else uint32_t heap = heap_caps_get_largest_free_block(0x1800); // WLEDMM: This is a better metric for free heap. From 5b7345ef39e9a22c5429457b9927b254284e3e22 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 8 Aug 2024 18:48:49 +0200 Subject: [PATCH 16/29] HUB75 refactoring * move HUB75 implementation into bus_manager.cpp * add "override" keyword * include FastLED.h if not included previously * move RGB macros into bus_manager.h --- wled00/bus_manager.cpp | 30 +++++++++++++++++++++--------- wled00/bus_manager.h | 42 +++++++++++++++++++++--------------------- 2 files changed, 42 insertions(+), 30 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 0f892f5f..8ba2c6ca 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -49,13 +49,6 @@ uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, byte #include "wled.h" #endif -//color mangling macros -#define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b)))) -#define R(c) (byte((c) >> 16)) -#define G(c) (byte((c) >> 8)) -#define B(c) (byte(c)) -#define W(c) (byte((c) >> 24)) - void ColorOrderMap::add(uint16_t start, uint16_t len, uint8_t colorOrder) { if (_count >= WLED_MAX_COLOR_ORDER_MAPPINGS) { @@ -696,11 +689,12 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh break; } + USER_PRINT(F("MatrixPanel_I2S_DMA ")); + USER_PRINTF("%sstarted.\n", _valid? "":"not "); - USER_PRINTLN("MatrixPanel_I2S_DMA started"); } -void __attribute__((hot)) BusHub75Matrix::setPixelColor(uint16_t pix, uint32_t c) { +void __attribute__((hot)) BusHub75Matrix::setPixelColor(uint16_t pix, uint32_t c) { if (!_valid || pix >= _len) return; if (isBlack && (c == BLACK)) return; // reject black pixels directly after clearScreen() #ifndef NO_CIE1931 @@ -729,6 +723,24 @@ void BusHub75Matrix::setBrightness(uint8_t b, bool immediate) { this->display->setBrightness(b); } +void __attribute__((hot)) BusHub75Matrix::show(void) { + if(mxconfig.double_buff) { + display->flipDMABuffer(); // Show the back buffer, set currently output buffer to the back (i.e. no longer being sent to LED panels) + // while(!previousBufferFree) delay(1); // experimental - Wait before we allow any writing to the buffer. Stop flicker. + display->clearScreen(); // Now clear the back-buffer + isBlack = true; + } +} + +void BusHub75Matrix::cleanup() { + deallocatePins(); + fourScanPanel = nullptr; + // delete fourScanPanel; + delete display; + _valid = false; + isBlack = false; +} + void BusHub75Matrix::deallocatePins() { pinManager.deallocatePin(mxconfig.gpio.r1, PinOwner::HUB75); diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index cfea2674..b85bf5a6 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -12,6 +12,20 @@ #include "const.h" +#if !defined(FASTLED_VERSION) // only pull in FastLED if we don't have it yet + #define FASTLED_INTERNAL + #include +#endif + +//color mangling macros +#if !defined(RGBW32) + #define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b)))) + #define R(c) (byte((c) >> 16)) + #define G(c) (byte((c) >> 8)) + #define B(c) (byte(c)) + #define W(c) (byte((c) >> 24)) +#endif + #define GET_BIT(var,bit) (((var)>>(bit))&0x01) #define SET_BIT(var,bit) ((var)|=(uint16_t)(0x0001<<(bit))) #define UNSET_BIT(var,bit) ((var)&=(~(uint16_t)(0x0001<<(bit)))) @@ -341,37 +355,23 @@ class BusHub75Matrix : public Bus { uint16_t getMaxPixels() const override { return 4096; }; - bool hasRGB() const { return true; } - bool hasWhite() const { return false; } + bool hasRGB() const override { return true; } + bool hasWhite() const override { return false; } - void setPixelColor(uint16_t pix, uint32_t c); + void setPixelColor(uint16_t pix, uint32_t c) override; - void show() { - if(mxconfig.double_buff) { - display->flipDMABuffer(); // Show the back buffer, set currently output buffer to the back (i.e. no longer being sent to LED panels) - // while(!previousBufferFree) delay(1); // experimental - Wait before we allow any writing to the buffer. Stop flicker. - display->clearScreen(); // Now clear the back-buffer - isBlack = true; - } - } + void show(void) override; - void setBrightness(uint8_t b, bool immediate); + void setBrightness(uint8_t b, bool immediate) override; - uint8_t getPins(uint8_t* pinArray) const { + uint8_t getPins(uint8_t* pinArray) const override { pinArray[0] = mxconfig.chain_length; return 1; } // Fake value due to keep finaliseInit happy void deallocatePins(); - void cleanup() { - deallocatePins(); - fourScanPanel = nullptr; - // delete fourScanPanel; - delete display; - _valid = false; - isBlack = false; - } + void cleanup(void) override; ~BusHub75Matrix() { cleanup(); From b5d97cca9399cebb0646f163f8acafe574525c65 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 8 Aug 2024 18:56:12 +0200 Subject: [PATCH 17/29] HUB75 leds buffer with dirty bit acceleration Instead of using the memory-hungry driver double buffer, this implements a LEDS buffer inside the BusHub75Matrix class. --> up to 50% faster --> uses one "dirty" bit per pixel, to only re-transmit pixels that changed after the last "show" --- wled00/bus_manager.cpp | 145 ++++++++++++++++++++++++++++++++++------- wled00/bus_manager.h | 11 +++- 2 files changed, 133 insertions(+), 23 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 8ba2c6ca..8fb12639 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -9,6 +9,36 @@ #include "bus_wrapper.h" #include "bus_manager.h" +// WLEDMM functions to get/set bits in an array - based on functions created by Brandon for GOL +// toDo : make this a class that's completely defined in a header file +bool getBitFromArray(const uint8_t* byteArray, size_t position) { // get bit value + size_t byteIndex = position / 8; + unsigned bitIndex = position % 8; + uint8_t byteValue = byteArray[byteIndex]; + return (byteValue >> bitIndex) & 1; +} + +void setBitInArray(uint8_t* byteArray, size_t position, bool value) { // set bit - with error handling for nullptr + if (byteArray == nullptr) return; + size_t byteIndex = position / 8; + unsigned bitIndex = position % 8; + if (value) + byteArray[byteIndex] |= (1 << bitIndex); + else + byteArray[byteIndex] &= ~(1 << bitIndex); +} + +size_t getBitArrayBytes(size_t num_bits) { // number of bytes needed for an array with num_bits bits + return (num_bits + 7) / 8; +} + +void setBitArray(uint8_t* byteArray, size_t numBits, bool value) { // set all bits to same value + if (byteArray == nullptr) return; + size_t len = getBitArrayBytes(numBits); + if (value) memset(byteArray, 0xFF, len); + else memset(byteArray, 0x00, len); +} + //WLEDMM: #define DEBUGOUT(x) netDebugEnabled?NetDebug.print(x):Serial.print(x) not supported in this file as netDebugEnabled not in scope #if 0 //colors.cpp @@ -665,6 +695,16 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh else { _valid = true; display->clearScreen(); // initially clear the screen buffer + + if (_ledBuffer) free(_ledBuffer); // should not happen + if (_ledsDirty) free(_ledsDirty); // should not happen + if(mxconfig.double_buff == false) { + _ledBuffer = (CRGB*) calloc(_len, sizeof(CRGB)); // create LEDs buffer (initialized to BLACK) + _ledsDirty = (byte*) malloc(getBitArrayBytes(_len)); // create LEDs dirty bits + //_ledsDirty = nullptr; + setBitArray(_ledsDirty, _len, false); // reset dirty bits + } + isBlack = true; } @@ -692,31 +732,58 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh USER_PRINT(F("MatrixPanel_I2S_DMA ")); USER_PRINTF("%sstarted.\n", _valid? "":"not "); + if (mxconfig.double_buff == true) USER_PRINTLN(F("MatrixPanel_I2S_DMA driver native double-buffering enabled.")); + if (_ledBuffer != nullptr) USER_PRINTLN(F("MatrixPanel_I2S_DMA LEDS buffer enabled.")); + if (_ledsDirty != nullptr) USER_PRINTLN(F("MatrixPanel_I2S_DMA LEDS dirty bit optimization enabled.")); + if ((_ledBuffer != nullptr) || (_ledsDirty != nullptr)) { + USER_PRINT(F("MatrixPanel_I2S_DMA LEDS buffer uses ")); + USER_PRINT((_ledBuffer? _len*sizeof(CRGB) :0) + (_ledsDirty? getBitArrayBytes(_len) :0)); + USER_PRINTLN(F(" bytes.")); + } } void __attribute__((hot)) BusHub75Matrix::setPixelColor(uint16_t pix, uint32_t c) { if (!_valid || pix >= _len) return; - if (isBlack && (c == BLACK)) return; // reject black pixels directly after clearScreen() -#ifndef NO_CIE1931 - c = unGamma24(c); // to use the driver linear brightness feature, we first need to undo WLED gamma correction -#endif - uint8_t r = R(c); - uint8_t g = G(c); - uint8_t b = B(c); + // if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT - if(fourScanPanel != nullptr) { - int pxwidth = fourScanPanel->width(); - int x = pix % pxwidth; - int y = pix / pxwidth; - fourScanPanel->drawPixelRGB888(int16_t(x), int16_t(y), r, g, b); + if (_ledBuffer) { + CRGB fastled_col = CRGB(c); + if (_ledBuffer[pix] != fastled_col) { + _ledBuffer[pix] = fastled_col; + setBitInArray(_ledsDirty, pix, true); // flag pixel as "dirty" + isBlack = false; + } } else { - int pxwidth = display->width(); - int x = pix % pxwidth; - int y = pix / pxwidth; - display->drawPixelRGB888(int16_t(x), int16_t(y), r, g, b); + //if (isBlack && (c == BLACK)) return; // reject black pixels directly after clearScreen() + #ifndef NO_CIE1931 + c = unGamma24(c); // to use the driver linear brightness feature, we first need to undo WLED gamma correction + #endif + uint8_t r = R(c); + uint8_t g = G(c); + uint8_t b = B(c); + + if(fourScanPanel != nullptr) { + unsigned width = fourScanPanel->width(); + int x = pix % width; + int y = pix / width; + fourScanPanel->drawPixelRGB888(int16_t(x), int16_t(y), r, g, b); + } else { + unsigned width = display->width(); + int x = pix % width; + int y = pix / width; + display->drawPixelRGB888(int16_t(x), int16_t(y), r, g, b); + } + isBlack = false; } - isBlack = false; +} + +uint32_t BusHub75Matrix::getPixelColor(uint16_t pix) const { + if (!_valid || pix >= _len) return BLACK; + if (_ledBuffer) + return uint32_t(_ledBuffer[pix]) & 0x00FFFFFF; + else + return BLACK; } void BusHub75Matrix::setBrightness(uint8_t b, bool immediate) { @@ -724,8 +791,36 @@ void BusHub75Matrix::setBrightness(uint8_t b, bool immediate) { } void __attribute__((hot)) BusHub75Matrix::show(void) { + if (!_valid) return; + if (_ledBuffer) { + // write out buffered LEDs + bool haveDirtyBits = (_ledsDirty != nullptr); + bool isFourScan = (fourScanPanel != nullptr); + unsigned width = isFourScan ? fourScanPanel->width() : display->width(); + unsigned height = isFourScan ? fourScanPanel->height() : display->height(); + + //while(!previousBufferFree) delay(1); // experimental - Wait before we allow any writing to the buffer. Stop flicker. + + size_t pix = 0; // running pixel index + for (int y=0; ydrawPixelRGB888(int16_t(x), int16_t(y), r, g, b); + else display->drawPixelRGB888(int16_t(x), int16_t(y), r, g, b); + } + pix ++; + } + if (haveDirtyBits) setBitArray(_ledsDirty, _len, false); // reset dirty bits + } + if(mxconfig.double_buff) { - display->flipDMABuffer(); // Show the back buffer, set currently output buffer to the back (i.e. no longer being sent to LED panels) + display->flipDMABuffer(); // Show the back buffer, set current output buffer to the back (i.e. no longer being sent to LED panels) // while(!previousBufferFree) delay(1); // experimental - Wait before we allow any writing to the buffer. Stop flicker. display->clearScreen(); // Now clear the back-buffer isBlack = true; @@ -733,12 +828,18 @@ void __attribute__((hot)) BusHub75Matrix::show(void) { } void BusHub75Matrix::cleanup() { - deallocatePins(); - fourScanPanel = nullptr; - // delete fourScanPanel; - delete display; + if (display && _valid) display->stopDMAoutput(); // terminate DMA driver (display goes black) _valid = false; + deallocatePins(); + USER_PRINTLN("HUB75 output ended."); + + //if (fourScanPanel != nullptr) delete fourScanPanel; // warning: deleting object of polymorphic class type 'VirtualMatrixPanel' which has non-virtual destructor might cause undefined behavior + delete display; + display = nullptr; + fourScanPanel = nullptr; isBlack = false; + if (_ledBuffer != nullptr) free(_ledBuffer); _ledBuffer = nullptr; + if (_ledsDirty != nullptr) free(_ledsDirty); _ledsDirty = nullptr; } void BusHub75Matrix::deallocatePins() { diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index b85bf5a6..93d5eb46 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -26,6 +26,13 @@ #define W(c) (byte((c) >> 24)) #endif +// WLEDMM bitarray utilities +void setBitInArray(uint8_t* byteArray, size_t position, bool value); // set bit +bool getBitFromArray(const uint8_t* byteArray, size_t position) __attribute__((pure)); // get bit value +size_t getBitArrayBytes(size_t num_bits) __attribute__((const)); // number of bytes needed for an array with num_bits bits +void setBitArray(uint8_t* byteArray, size_t numBits, bool value); // set all bits to same value + + #define GET_BIT(var,bit) (((var)>>(bit))&0x01) #define SET_BIT(var,bit) ((var)|=(uint16_t)(0x0001<<(bit))) #define UNSET_BIT(var,bit) ((var)&=(~(uint16_t)(0x0001<<(bit)))) @@ -359,6 +366,7 @@ class BusHub75Matrix : public Bus { bool hasWhite() const override { return false; } void setPixelColor(uint16_t pix, uint32_t c) override; + uint32_t getPixelColor(uint16_t pix) const override; void show(void) override; @@ -382,7 +390,8 @@ class BusHub75Matrix : public Bus { VirtualMatrixPanel *fourScanPanel = nullptr; HUB75_I2S_CFG mxconfig; bool isBlack = false; - + CRGB *_ledBuffer = nullptr; + byte *_ledsDirty = nullptr; }; #endif From 1b098b9863b823cedc74eb0be33ec6dae8690fd4 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 8 Aug 2024 19:00:19 +0200 Subject: [PATCH 18/29] fixie --- wled00/bus_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 8fb12639..183c89b8 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -755,7 +755,7 @@ void __attribute__((hot)) BusHub75Matrix::setPixelColor(uint16_t pix, uint32_t c } } else { - //if (isBlack && (c == BLACK)) return; // reject black pixels directly after clearScreen() + if (isBlack && (c == BLACK)) return; // reject black pixels directly after clearScreen() #ifndef NO_CIE1931 c = unGamma24(c); // to use the driver linear brightness feature, we first need to undo WLED gamma correction #endif From bad923570bc18a5bd9386375d535a8fe08ab8dd7 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 8 Aug 2024 19:04:10 +0200 Subject: [PATCH 19/29] double buffer off (MatrixPortal S3) `mxconfig.double_buff = true` should not be necessary any more. --- wled00/bus_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 183c89b8..08743552 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -570,7 +570,7 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh USER_PRINTLN("MatrixPanel_I2S_DMA - Matrix Portal S3 config"); - mxconfig.double_buff = true; // <------------- Turn on double buffer + //mxconfig.double_buff = true; // <------------- Turn on double buffer mxconfig.gpio.r1 = 42; mxconfig.gpio.g1 = 41; From f8154a8c7870a06a12edefdf9137e9da7f40c250 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 8 Aug 2024 19:08:34 +0200 Subject: [PATCH 20/29] Update wled.h - build 2408080 --- wled00/wled.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/wled.h b/wled00/wled.h index 1ea73805..c1f56732 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2408070 +#define VERSION 2408080 // WLEDMM - you can check for this define in usermods, to only enabled WLEDMM specific code in the "right" fork. Its not defined in AC WLED. #define _MoonModules_WLED_ From 56e72ef22db4de414ae7bcf7dbf14d3a408ad1e7 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 8 Aug 2024 20:57:15 +0200 Subject: [PATCH 21/29] HUB75 live preview --- wled00/bus_manager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 08743552..ced434a4 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -695,6 +695,8 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh else { _valid = true; display->clearScreen(); // initially clear the screen buffer + display->setBrightness8(127); // range is 0-255, 0 - 0%, 255 - 100% + _bri = 127; if (_ledBuffer) free(_ledBuffer); // should not happen if (_ledsDirty) free(_ledsDirty); // should not happen @@ -781,13 +783,14 @@ void __attribute__((hot)) BusHub75Matrix::setPixelColor(uint16_t pix, uint32_t c uint32_t BusHub75Matrix::getPixelColor(uint16_t pix) const { if (!_valid || pix >= _len) return BLACK; if (_ledBuffer) - return uint32_t(_ledBuffer[pix]) & 0x00FFFFFF; + return uint32_t(_ledBuffer[pix].scale8(_bri)) & 0x00FFFFFF; // scale8() is needed to mimic NeoPixelBus, which returns scaled-down colours else return BLACK; } void BusHub75Matrix::setBrightness(uint8_t b, bool immediate) { this->display->setBrightness(b); + _bri = b; } void __attribute__((hot)) BusHub75Matrix::show(void) { From 28db9bfcfdb161b952fb9a1ece0c751e56f8f6c7 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 8 Aug 2024 22:03:49 +0200 Subject: [PATCH 22/29] waverly effect speedup * faster math * limit height to visible area --- wled00/FX.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index a9bfccbb..0f6653bd 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -6667,13 +6667,19 @@ uint16_t mode_2DWaverly(void) { long t = strip.now / 2; for (int i = 0; i < cols; i++) { - uint16_t thisVal = volumeSmth*SEGMENT.intensity/64 * inoise8(i * 45 , t , t)/64; // WLEDMM back to SR code - uint16_t thisMax = map(thisVal, 0, 512, 0, rows); + //uint16_t thisVal = volumeSmth*SEGMENT.intensity/64 * inoise8(i * 45 , t , t)/64; // WLEDMM back to SR code + unsigned thisVal = unsigned(volumeSmth*SEGMENT.intensity) * inoise8(i * 45 , t , t) / (64*64); // WLEDMM same result but more accurate - for (int j = 0; j < thisMax; j++) { + //int thisMax = map(thisVal, 0, 512, 0, rows); + int thisMax = (thisVal * rows) / 512; // WLEDMM same result, just faster + int thisMax2 = min(int(rows), thisMax); // WLEDMM limit height to visible are + + for (int j = 0; j < thisMax2; j++) { + //int jmap = map(j, 0, thisMax, 250, 0); + int jmap = 250 - ((j * 250) / thisMax); // WLEDMM same result, just faster if (!SEGENV.check1) - 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.addPixelColorXY(i, j, ColorFromPalette(SEGPALETTE, jmap, 255, LINEARBLEND)); + SEGMENT.addPixelColorXY((cols - 1) - i, (rows - 1) - j, ColorFromPalette(SEGPALETTE, jmap, 255, LINEARBLEND)); } } SEGMENT.blur(16); From d00b3147b463a3471ed18bb11970ad908c140943 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 8 Aug 2024 22:28:14 +0200 Subject: [PATCH 23/29] Waverly: better slider names Slider names were misleading. First slider: fade speed (low values means longer hold times) Second slider: signal gain (i.e. amplification) --- wled00/FX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 0f6653bd..a541983e 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -6686,7 +6686,7 @@ uint16_t mode_2DWaverly(void) { return FRAMETIME; } // mode_2DWaverly() -static const char _data_FX_MODE_2DWAVERLY[] PROGMEM = "Waverly ☾@Amplification,Sensitivity,,,,No Clouds,Sound Pressure,AGC debug;;!;2v;ix=64,si=0"; // Beatsin +static const char _data_FX_MODE_2DWAVERLY[] PROGMEM = "Waverly ☾@Fade Rate,Amplification,,,,No Clouds,Sound Pressure,AGC debug;;!;2v;ix=64,si=0"; // Beatsin #endif // WLED_DISABLE_2D From 89412b999d74288cc6b5ecd1ddbfd5d2aa478c0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Mon, 29 Jul 2024 07:31:33 +0200 Subject: [PATCH 24/29] Merge pull request #4078 from apanteleev/fire-blur-control Add a parameter for blur amount in the Fire 2012 effect --- wled00/FX.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index a541983e..bffcc455 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2156,14 +2156,17 @@ uint16_t mode_fire_2012() { for (int stripNr=0; stripNr> 2; + SEGMENT.blur(blurAmount); + } if (it != SEGENV.step) SEGENV.step = it; return FRAMETIME; } -static const char _data_FX_MODE_FIRE_2012[] PROGMEM = "Fire 2012@Cooling,Spark rate,,,Boost;;!;1.5d;sx=64,ix=160,m12=1"; // bars WLEDMM 1.5d, +static const char _data_FX_MODE_FIRE_2012[] PROGMEM = "Fire 2012@Cooling,Spark rate,,2D Blur,Boost;;!;1.5d;sx=64,ix=160,c2=128,m12=1"; // bars WLEDMM 1.5d, // ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb From a44aa92c753013e28b01fa826608d2b1e14f6e44 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Fri, 9 Aug 2024 12:53:41 +0200 Subject: [PATCH 25/29] playing with Fire2012 * speedup: add functions to only blur rows or columns (50% faster) * fire2012: tinkering with bur options. Vertical blur only when slider < 64 (faster); extra blur for slider values >192 (bush burn) --- wled00/FX.cpp | 6 ++++-- wled00/FX.h | 10 ++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index bffcc455..3d00dbb8 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2148,7 +2148,7 @@ uint16_t mode_fire_2012() { // Step 4. Map from heat cells to LED colors for (int j = 0; j < SEGLEN; j++) { - SEGMENT.setPixelColor(indexToVStrip(j, stripNr), ColorFromPalette(SEGPALETTE, min(heat[j],byte(240)), 255, NOBLEND)); + SEGMENT.setPixelColor(indexToVStrip(j, stripNr), ColorFromPalette(SEGPALETTE, min(heat[j], byte(240)), 255, NOBLEND)); } } }; @@ -2158,7 +2158,9 @@ uint16_t mode_fire_2012() { if (SEGMENT.is2D()) { uint8_t blurAmount = SEGMENT.custom2 >> 2; - SEGMENT.blur(blurAmount); + if (blurAmount > 48) blurAmount += blurAmount-48; // extra blur when slider > 192 (bush burn) + if (blurAmount < 16) SEGMENT.blurCols(SEGMENT.custom2 >> 1); // no side-burn when slider < 64 (faster) + else SEGMENT.blur(blurAmount); } if (it != SEGENV.step) diff --git a/wled00/FX.h b/wled00/FX.h index 387b9e55..b61cdf72 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -656,6 +656,16 @@ typedef struct Segment { uint32_t __attribute__((pure)) color_from_palette(uint_fast16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255); uint32_t __attribute__((pure)) color_wheel(uint8_t pos); + // 2D Blur: shortcuts for bluring columns or rows only (50% faster than full 2D blur) + inline void blurCols(fract8 blur_amount, bool smear = false) { // blur all columns + const unsigned cols = virtualWidth(); + for (unsigned k = 0; k < cols; k++) blurCol(k, blur_amount, smear); + } + inline void blurRows(fract8 blur_amount, bool smear = false) { // blur all rows + const unsigned rows = virtualHeight(); + for ( unsigned i = 0; i < rows; i++) blurRow(i, blur_amount, smear); + } + // 2D matrix #ifndef WLEDMM_FASTPATH inline uint16_t virtualWidth() const { // WLEDMM use fast types, and make function inline From 2934739ebf3156eb69b4471adadd61d2cee52bd2 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Fri, 9 Aug 2024 17:46:14 +0200 Subject: [PATCH 26/29] HUB75 cleanup, double buffer improvement * code cleanup, removing some unneeded sanity checks * use dirty bits in double buffer mode, too -> only not-black pixels are drawn into the back-buffer (20%-30% faster) --- wled00/bus_manager.cpp | 39 +++++++++++++++++++++------------------ wled00/bus_manager.h | 1 - 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index ced434a4..f5ecb5d6 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -19,7 +19,7 @@ bool getBitFromArray(const uint8_t* byteArray, size_t position) { // get bit val } void setBitInArray(uint8_t* byteArray, size_t position, bool value) { // set bit - with error handling for nullptr - if (byteArray == nullptr) return; + //if (byteArray == nullptr) return; size_t byteIndex = position / 8; unsigned bitIndex = position % 8; if (value) @@ -526,7 +526,6 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh _valid = false; mxconfig.double_buff = false; // default to off, known to cause issue with some effects but needs more memory - isBlack = false; fourScanPanel = nullptr; @@ -700,14 +699,20 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh if (_ledBuffer) free(_ledBuffer); // should not happen if (_ledsDirty) free(_ledsDirty); // should not happen - if(mxconfig.double_buff == false) { - _ledBuffer = (CRGB*) calloc(_len, sizeof(CRGB)); // create LEDs buffer (initialized to BLACK) - _ledsDirty = (byte*) malloc(getBitArrayBytes(_len)); // create LEDs dirty bits - //_ledsDirty = nullptr; - setBitArray(_ledsDirty, _len, false); // reset dirty bits - } + _ledsDirty = (byte*) malloc(getBitArrayBytes(_len)); // create LEDs dirty bits - isBlack = true; + if (_ledsDirty == nullptr) { + display->stopDMAoutput(); + delete display; display = nullptr; + _valid = false; + USER_PRINTLN(F("MatrixPanel_I2S_DMA not started - not enough memory for dirty bits!")); + return; // fail is we cannot get memory for the buffer + } + setBitArray(_ledsDirty, _len, false); // reset dirty bits + + if (mxconfig.double_buff == false) { + _ledBuffer = (CRGB*) calloc(_len, sizeof(CRGB)); // create LEDs buffer (initialized to BLACK) + } } switch(bc.type) { @@ -753,11 +758,12 @@ void __attribute__((hot)) BusHub75Matrix::setPixelColor(uint16_t pix, uint32_t c if (_ledBuffer[pix] != fastled_col) { _ledBuffer[pix] = fastled_col; setBitInArray(_ledsDirty, pix, true); // flag pixel as "dirty" - isBlack = false; } } else { - if (isBlack && (c == BLACK)) return; // reject black pixels directly after clearScreen() + if ((c == BLACK) && (getBitFromArray(_ledsDirty, pix) == false)) return; // ignore black if pixel is already black + setBitInArray(_ledsDirty, pix, c != BLACK); // dirty = true means "color is not BLACK" + #ifndef NO_CIE1931 c = unGamma24(c); // to use the driver linear brightness feature, we first need to undo WLED gamma correction #endif @@ -776,7 +782,6 @@ void __attribute__((hot)) BusHub75Matrix::setPixelColor(uint16_t pix, uint32_t c int y = pix / width; display->drawPixelRGB888(int16_t(x), int16_t(y), r, g, b); } - isBlack = false; } } @@ -785,7 +790,7 @@ uint32_t BusHub75Matrix::getPixelColor(uint16_t pix) const { if (_ledBuffer) return uint32_t(_ledBuffer[pix].scale8(_bri)) & 0x00FFFFFF; // scale8() is needed to mimic NeoPixelBus, which returns scaled-down colours else - return BLACK; + return getBitFromArray(_ledsDirty, pix) ? DARKGREY: BLACK; // just a hack - we only know if the pixel is black or not } void BusHub75Matrix::setBrightness(uint8_t b, bool immediate) { @@ -797,7 +802,6 @@ void __attribute__((hot)) BusHub75Matrix::show(void) { if (!_valid) return; if (_ledBuffer) { // write out buffered LEDs - bool haveDirtyBits = (_ledsDirty != nullptr); bool isFourScan = (fourScanPanel != nullptr); unsigned width = isFourScan ? fourScanPanel->width() : display->width(); unsigned height = isFourScan ? fourScanPanel->height() : display->height(); @@ -806,7 +810,7 @@ void __attribute__((hot)) BusHub75Matrix::show(void) { size_t pix = 0; // running pixel index for (int y=0; yflipDMABuffer(); // Show the back buffer, set current output buffer to the back (i.e. no longer being sent to LED panels) // while(!previousBufferFree) delay(1); // experimental - Wait before we allow any writing to the buffer. Stop flicker. display->clearScreen(); // Now clear the back-buffer - isBlack = true; + setBitArray(_ledsDirty, _len, false); // dislay buffer is blank - reset all dirty bits } } @@ -840,7 +844,6 @@ void BusHub75Matrix::cleanup() { delete display; display = nullptr; fourScanPanel = nullptr; - isBlack = false; if (_ledBuffer != nullptr) free(_ledBuffer); _ledBuffer = nullptr; if (_ledsDirty != nullptr) free(_ledsDirty); _ledsDirty = nullptr; } diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 93d5eb46..96aba376 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -389,7 +389,6 @@ class BusHub75Matrix : public Bus { MatrixPanel_I2S_DMA *display = nullptr; VirtualMatrixPanel *fourScanPanel = nullptr; HUB75_I2S_CFG mxconfig; - bool isBlack = false; CRGB *_ledBuffer = nullptr; byte *_ledsDirty = nullptr; }; From e90f8e7f0de268210f905194fc9530168d304656 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Tue, 30 Jul 2024 19:15:08 +0100 Subject: [PATCH 27/29] 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 821481e5..3be973cc 100644 --- a/wled00/dmx_input.cpp +++ b/wled00/dmx_input.cpp @@ -187,6 +187,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) { @@ -199,6 +202,9 @@ void DMXInput::updateInternal() } } else { + if(connected) { + USER_PRINTLN("DMX Input - disconnected"); + } connected = false; } } From a257e49bb4430be72560425f37ac17439b9afa07 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 12 Aug 2024 12:20:15 +0200 Subject: [PATCH 28/29] HUB75 trying to reduce glitches the HUB75 driver seems to randomly produce glitches, especially on hight contrast edges. * roll back to HUB75 version 3.0.10 (known good) * limit max brightness to 238 (=92%) * add short delay after starting the driver --- platformio.ini | 3 ++- wled00/bus_manager.cpp | 23 ++++++++++++++++------- wled00/bus_manager.h | 1 + 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/platformio.ini b/platformio.ini index ec1a387d..93ca4974 100644 --- a/platformio.ini +++ b/platformio.ini @@ -1038,7 +1038,8 @@ HUB75_build_flags = -D S3_LCD_DIV_NUM=20 ;; Attempt to fix wifi performance issue when panel active with S3 chips ;; HUB75_lib_deps = https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA.git @ 3.0.11 ;; breaks the build (2024-07-30) ;; HUB75_lib_deps = https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA.git#1e4c80a26454aca7b8129bd5a966b0af329d2703 ;; 3.0.10 - something strange is going on here ... -HUB75_lib_deps = https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA.git#c4ecdcfeeb5aa668d92ddf3c3c74bc93316f6e10 ;; 3.0.11 +HUB75_lib_deps = https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA.git#1e4c80a26454aca7b8129bd5a966b0af329d2703 ;; 3.0.10 - something strange is going on here ... +;; HUB75_lib_deps = https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA.git#c4ecdcfeeb5aa668d92ddf3c3c74bc93316f6e10 ;; 3.0.11 HUB75_lib_ignore = ESP32 HUB75 LED MATRIX PANEL DMA Display ;; to remove the HUB75 lib dependancy (saves a few bytes) NetDebug_build_flags = diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index f5ecb5d6..189b779a 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -685,17 +685,18 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh USER_PRINTLN("MatrixPanel_I2S_DMA created"); // let's adjust default brightness display->setBrightness8(25); // range is 0-255, 0 - 0%, 255 - 100% + _bri = 25; + delay(24); // experimental // Allocate memory and start DMA display if( not display->begin() ) { USER_PRINTLN("****** MatrixPanel_I2S_DMA !KABOOM! I2S memory allocation failed ***********"); return; } else { + delay(18); // experiment - give the driver a moment (~ one full frame @ 60hz) to settle _valid = true; display->clearScreen(); // initially clear the screen buffer - display->setBrightness8(127); // range is 0-255, 0 - 0%, 255 - 100% - _bri = 127; if (_ledBuffer) free(_ledBuffer); // should not happen if (_ledsDirty) free(_ledsDirty); // should not happen @@ -736,8 +737,12 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh break; } + if (_valid) { + _panelWidth = fourScanPanel ? fourScanPanel->width() : display->width(); // cache width - it will never change + } + USER_PRINT(F("MatrixPanel_I2S_DMA ")); - USER_PRINTF("%sstarted.\n", _valid? "":"not "); + USER_PRINTF("%sstarted, width=%u, %u pixels.\n", _valid? "":"not ", _panelWidth, _len); if (mxconfig.double_buff == true) USER_PRINTLN(F("MatrixPanel_I2S_DMA driver native double-buffering enabled.")); if (_ledBuffer != nullptr) USER_PRINTLN(F("MatrixPanel_I2S_DMA LEDS buffer enabled.")); @@ -772,12 +777,12 @@ void __attribute__((hot)) BusHub75Matrix::setPixelColor(uint16_t pix, uint32_t c uint8_t b = B(c); if(fourScanPanel != nullptr) { - unsigned width = fourScanPanel->width(); + int width = _panelWidth; int x = pix % width; int y = pix / width; fourScanPanel->drawPixelRGB888(int16_t(x), int16_t(y), r, g, b); } else { - unsigned width = display->width(); + int width = _panelWidth; int x = pix % width; int y = pix / width; display->drawPixelRGB888(int16_t(x), int16_t(y), r, g, b); @@ -794,16 +799,19 @@ uint32_t BusHub75Matrix::getPixelColor(uint16_t pix) const { } void BusHub75Matrix::setBrightness(uint8_t b, bool immediate) { - this->display->setBrightness(b); _bri = b; + if (_bri > 238) _bri=238; + display->setBrightness(_bri); } void __attribute__((hot)) BusHub75Matrix::show(void) { if (!_valid) return; + display->setBrightness(_bri); + if (_ledBuffer) { // write out buffered LEDs bool isFourScan = (fourScanPanel != nullptr); - unsigned width = isFourScan ? fourScanPanel->width() : display->width(); + //if (isFourScan) fourScanPanel->setRotation(0); unsigned height = isFourScan ? fourScanPanel->height() : display->height(); //while(!previousBufferFree) delay(1); // experimental - Wait before we allow any writing to the buffer. Stop flicker. @@ -837,6 +845,7 @@ void __attribute__((hot)) BusHub75Matrix::show(void) { void BusHub75Matrix::cleanup() { if (display && _valid) display->stopDMAoutput(); // terminate DMA driver (display goes black) _valid = false; + _panelWidth = 0; deallocatePins(); USER_PRINTLN("HUB75 output ended."); diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 96aba376..2379f430 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -389,6 +389,7 @@ class BusHub75Matrix : public Bus { MatrixPanel_I2S_DMA *display = nullptr; VirtualMatrixPanel *fourScanPanel = nullptr; HUB75_I2S_CFG mxconfig; + unsigned _panelWidth = 0; CRGB *_ledBuffer = nullptr; byte *_ledsDirty = nullptr; }; From a77520aa05f7e18c10eea2eeab65ad1e860326fc Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 12 Aug 2024 12:36:45 +0200 Subject: [PATCH 29/29] bugfix forgot to commit one line ... --- wled00/bus_manager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 189b779a..66cbd7f3 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -813,6 +813,7 @@ void __attribute__((hot)) BusHub75Matrix::show(void) { bool isFourScan = (fourScanPanel != nullptr); //if (isFourScan) fourScanPanel->setRotation(0); unsigned height = isFourScan ? fourScanPanel->height() : display->height(); + unsigned width = _panelWidth; //while(!previousBufferFree) delay(1); // experimental - Wait before we allow any writing to the buffer. Stop flicker.