From b0ba1b2eccd2eac6f394f8ec2bbafec7c43da2cb Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sat, 30 Jul 2022 10:49:54 +0200 Subject: [PATCH 1/5] Bugfix. - defult transitions - conditional 2D compile --- wled00/FX_fcn.cpp | 4 ++++ wled00/json.cpp | 21 +++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index a4cb9c48..cdb8952f 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1297,7 +1297,11 @@ void WS2812FX::restartRuntime() { void WS2812FX::resetSegments() { _segments.clear(); // destructs all Segment as part of clearing + #ifndef WLED_DISABLE_2D segment seg = isMatrix ? Segment(0, matrixWidth, 0, matrixHeight) : Segment(0, _length); + #else + segment seg = Segment(0, _length); + #endif _segments.push_back(seg); _mainSegment = 0; /* diff --git a/wled00/json.cpp b/wled00/json.cpp index 1eeebe70..352b17d9 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -187,6 +187,8 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId) && elem[F("c2")].isNull() && elem[F("c3")].isNull() ) { + int16_t sOpt; + uint8_t tmp = 255; // compatibility mode begin char buf[5]; // dummy buffer for (int i=0; i<5; i++) { @@ -200,21 +202,32 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId) } extractModeSlider(fx, i, buf, 4, var); } - extractModeSlider(fx, 255, buf, 4, &seg.palette); + extractModeSlider(fx, 255, buf, 4, &tmp); + if (tmp < strip.getPaletteCount() + strip.customPalettes.size()) { + if (tmp != seg.palette) { + if (strip.paletteBlend && !seg.transitional) seg.startTransition(strip.getTransition()); + seg.palette = tmp; + } + } //end compatibility mode - int16_t sOpt; sOpt = extractModeDefaults(fx, SET_F("sx")); if (sOpt >= 0) seg.speed = sOpt; sOpt = extractModeDefaults(fx, SET_F("ix")); if (sOpt >= 0) seg.intensity = sOpt; sOpt = extractModeDefaults(fx, SET_F("c1")); if (sOpt >= 0) seg.custom1 = sOpt; sOpt = extractModeDefaults(fx, SET_F("c2")); if (sOpt >= 0) seg.custom2 = sOpt; sOpt = extractModeDefaults(fx, SET_F("c3")); if (sOpt >= 0) seg.custom3 = sOpt; - sOpt = extractModeDefaults(fx, "pal"); if (sOpt >= 0 && sOpt < strip.getPaletteCount()) seg.palette = sOpt; sOpt = extractModeDefaults(fx, SET_F("mp12")); if (sOpt >= 0) seg.map1D2D = sOpt & 0x03; sOpt = extractModeDefaults(fx, SET_F("ssim")); if (sOpt >= 0) seg.soundSim = sOpt & 0x07; sOpt = extractModeDefaults(fx, "rev"); if (sOpt >= 0) seg.reverse = (bool)sOpt; // setOption(SEG_OPTION_REVERSED, (bool)sOpt); // NOTE: setting this option is a risky business sOpt = extractModeDefaults(fx, SET_F("mi")); if (sOpt >= 0) seg.mirror = (bool)sOpt; // setOption(SEG_OPTION_MIRROR, (bool)sOpt); // NOTE: setting this option is a risky business sOpt = extractModeDefaults(fx, SET_F("rY")); if (sOpt >= 0) seg.reverse_y = (bool)sOpt; // setOption(SEG_OPTION_REVERSED_Y, (bool)sOpt); // NOTE: setting this option is a risky business sOpt = extractModeDefaults(fx, SET_F("mY")); if (sOpt >= 0) seg.mirror_y = (bool)sOpt; // setOption(SEG_OPTION_MIRROR_Y, (bool)sOpt); // NOTE: setting this option is a risky business + sOpt = extractModeDefaults(fx, "pal"); + if (sOpt >= 0 && sOpt < strip.getPaletteCount() + strip.customPalettes.size()) { + if (sOpt != seg.palette) { + if (strip.paletteBlend && !seg.transitional) seg.startTransition(strip.getTransition()); + seg.palette = sOpt; + } + } } } } @@ -225,7 +238,7 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId) uint8_t pal = seg.palette; if (getVal(elem["pal"], &pal, 1, strip.getPaletteCount())) { if (pal != seg.palette) { - if (strip.paletteBlend) seg.startTransition(strip.getTransition()); + if (strip.paletteBlend && !seg.transitional) seg.startTransition(strip.getTransition()); seg.palette = pal; } } From 1abf0fc134c61ff766305a6fe9691e1b2b5ccccb Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sat, 30 Jul 2022 11:04:04 +0200 Subject: [PATCH 2/5] Deprecate EEPROM support (compile time option). --- wled00/button.cpp | 2 ++ wled00/cfg.cpp | 4 ++++ wled00/fcn_declare.h | 2 ++ wled00/set.cpp | 2 ++ wled00/wled.cpp | 5 ++++- wled00/wled.h | 6 ++++-- wled00/wled_eeprom.cpp | 4 +++- 7 files changed, 21 insertions(+), 4 deletions(-) diff --git a/wled00/button.cpp b/wled00/button.cpp index 0567abb0..2bd093ce 100644 --- a/wled00/button.cpp +++ b/wled00/button.cpp @@ -265,7 +265,9 @@ void handleButton() if (b == 0 && dur > WLED_LONG_AP) { // long press on button 0 (when released) if (dur > WLED_LONG_FACTORY_RESET) { // factory reset if pressed > 10 seconds WLED_FS.format(); + #ifdef WLED_ADD_EEPROM_SUPPORT clearEEPROM(); + #endif doReboot = true; } else { WLED::instance().initAP(true); diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index b8796b8d..06261a24 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -507,7 +507,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { void deserializeConfigFromFS() { bool success = deserializeConfigSec(); if (!success) { //if file does not exist, try reading from EEPROM + #ifdef WLED_ADD_EEPROM_SUPPORT deEEPSettings(); + #endif return; } @@ -517,7 +519,9 @@ void deserializeConfigFromFS() { success = readObjectFromFile("/cfg.json", nullptr, &doc); if (!success) { //if file does not exist, try reading from EEPROM + #ifdef WLED_ADD_EEPROM_SUPPORT deEEPSettings(); + #endif releaseJSONBufferLock(); return; } diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index a9a3dd8c..d1dace1f 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -329,11 +329,13 @@ int16_t extractModeDefaults(uint8_t mode, const char *segVar); uint16_t crc16(const unsigned char* data_p, size_t length); um_data_t* simulateSound(uint8_t simulationId); +#ifdef WLED_ADD_EEPROM_SUPPORT //wled_eeprom.cpp void applyMacro(byte index); void deEEP(); void deEEPSettings(); void clearEEPROM(); +#endif //wled_math.cpp #ifndef WLED_USE_REAL_MATH diff --git a/wled00/set.cpp b/wled00/set.cpp index f53a07b5..fc2b2116 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -398,7 +398,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) if (request->hasArg(F("RS"))) //complete factory reset { WLED_FS.format(); + #ifdef WLED_ADD_EEPROM_SUPPORT clearEEPROM(); + #endif serveMessage(request, 200, F("All Settings erased."), F("Connect to WLED-AP to setup again"),255); doReboot = true; } diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 3e63c28e..4640270c 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -314,7 +314,10 @@ void WLED::setup() if (!fsinit) { DEBUGFS_PRINTLN(F("FS failed!")); errorFlag = ERR_FS_BEGIN; - } else deEEP(); + } +#ifdef WLED_ADD_EEPROM_SUPPORT + else deEEP(); +#endif updateFSInfo(); DEBUG_PRINTLN(F("Reading config")); diff --git a/wled00/wled.h b/wled00/wled.h index 228fec29..2b1c9d85 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2207293 +#define VERSION 2207301 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG @@ -94,7 +94,9 @@ #endif #include -#include +#ifdef WLED_ADD_EEPROM_SUPPORT + #include +#endif #include #include #ifndef WLED_DISABLE_OTA diff --git a/wled00/wled_eeprom.cpp b/wled00/wled_eeprom.cpp index 32ba9f50..1fec4e8a 100644 --- a/wled00/wled_eeprom.cpp +++ b/wled00/wled_eeprom.cpp @@ -1,3 +1,4 @@ +#ifdef WLED_ADD_EEPROM_SUPPORT #include #include "wled.h" @@ -472,4 +473,5 @@ void deEEPSettings() { usermods.readFromConfig(empty); serializeConfig(); -} \ No newline at end of file +} +#endif From f16558c126914dfde1d617df7370be23fe9b69c0 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sat, 30 Jul 2022 14:20:36 +0200 Subject: [PATCH 3/5] Optimisations. --- wled00/FX.cpp | 2 +- wled00/FX.h | 41 ++++++++++++--------------- wled00/FX_2Dfcn.cpp | 3 +- wled00/FX_fcn.cpp | 67 +++++++++++++++++++++++---------------------- 4 files changed, 55 insertions(+), 58 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 4292f4a2..1793b32a 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -75,7 +75,7 @@ int8_t tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec) { */ uint16_t mode_static(void) { SEGMENT.fill(SEGCOLOR(0)); - return (SEGMENT.getOption(SEG_OPTION_TRANSITIONAL)) ? FRAMETIME : 350; //update faster if in transition + return /*(SEGMENT.getOption(SEG_OPTION_TRANSITIONAL)) ? FRAMETIME :*/ 350; //update faster if in transition } static const char *_data_FX_MODE_STATIC PROGMEM = "Solid"; diff --git a/wled00/FX.h b/wled00/FX.h index 7f66f074..6e2c81a3 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -56,10 +56,6 @@ #define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b)))) #endif -//colors.cpp (.h does not like including other .h) -uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16); -uint32_t color_add(uint32_t,uint32_t); - /* Not used in all effects yet */ #define WLED_FPS 42 #define FRAMETIME_FIXED (1000/WLED_FPS) @@ -71,12 +67,12 @@ uint32_t color_add(uint32_t,uint32_t); #ifdef ESP8266 #define MAX_NUM_SEGMENTS 16 /* How much data bytes all segments combined may allocate */ - #define MAX_SEGMENT_DATA 4096 + #define MAX_SEGMENT_DATA 5120 #else #ifndef MAX_NUM_SEGMENTS #define MAX_NUM_SEGMENTS 32 #endif - #define MAX_SEGMENT_DATA 32768 + #define MAX_SEGMENT_DATA 32767 #endif /* How much data bytes each segment should max allocate to leave enough space for other segments, @@ -88,7 +84,7 @@ uint32_t color_add(uint32_t,uint32_t); #define NUM_COLORS 3 /* number of colors per segment */ #define SEGMENT strip._segments[strip.getCurrSegmentId()] #define SEGENV strip._segments[strip.getCurrSegmentId()] -//#define SEGCOLOR(x) strip._segments[s//trip.getCurrSegmentId()].currentColor(x, strip._segments[strip.getCurrSegmentId()].colors[x]) +//#define SEGCOLOR(x) strip._segments[strip.getCurrSegmentId()].currentColor(x, strip._segments[strip.getCurrSegmentId()].colors[x]) //#define SEGLEN strip._segments[strip.getCurrSegmentId()].virtualLength() #define SEGCOLOR(x) strip.segColor(x) /* saves us a few kbytes of code */ #define SEGPALETTE strip._currentPalette @@ -427,6 +423,7 @@ typedef struct Segment { }; }; uint16_t _dataLen; + static uint16_t _usedSegmentData; // transition data, valid only if getOption(SEG_OPTION_TRANSITIONAL)==true, holds values during transition //struct Transition { @@ -504,23 +501,27 @@ typedef struct Segment { inline bool getOption(uint8_t n) { return ((options >> n) & 0x01); } inline bool isSelected(void) { return getOption(0); } inline bool isActive(void) { return stop > start; } + inline bool is2D(void) { return !(startY == 0 && stopY == 1); } inline uint16_t width(void) { return stop - start; } inline uint16_t height(void) { return stopY - startY; } inline uint16_t length(void) { return width(); } inline uint16_t groupLength(void) { return grouping + spacing; } inline uint8_t getLightCapabilities(void) { return _capabilities; } - bool setColor(uint8_t slot, uint32_t c); //returns true if changed - void setCCT(uint16_t k); - void setOpacity(uint8_t o); - void setOption(uint8_t n, bool val); + static uint16_t getUsedSegmentData(void) { return _usedSegmentData; } + static void addUsedSegmentData(int len) { _usedSegmentData += len; } + + bool setColor(uint8_t slot, uint32_t c); //returns true if changed + void setCCT(uint16_t k); + void setOpacity(uint8_t o); + void setOption(uint8_t n, bool val); uint8_t differs(Segment& b); - void refreshLightCapabilities(void); + void refreshLightCapabilities(void); // runtime data functions - bool allocateData(uint16_t len); - void deallocateData(void); inline uint16_t dataSize(void) { return _dataLen; } + bool allocateData(size_t len); + void deallocateData(void); void resetIfRequired(void); /** * Flags that before the next effect is calculated, @@ -531,11 +532,11 @@ typedef struct Segment { inline void markForReset(void) { reset = true; } // setOption(SEG_OPTION_RESET, true) // transition functions - void startTransition(uint16_t dur); // transition has to start before actual segment values change - void handleTransition(void); + void startTransition(uint16_t dur); // transition has to start before actual segment values change + void handleTransition(void); uint16_t progress(void); //transition progression between 0-65535 uint8_t currentBri(uint8_t briNew, bool useCct = false); - uint32_t currentColor(uint8_t slot, uint32_t colorNew) { return getOption(SEG_OPTION_TRANSITIONAL) /*&& !_t*/ ? color_blend(/*_t->*/_colorT[slot], colorNew, progress(), true) : colorNew; } + uint32_t currentColor(uint8_t slot, uint32_t colorNew); CRGBPalette16 &loadPalette(CRGBPalette16 &tgt, uint8_t pal); CRGBPalette16 ¤tPalette(CRGBPalette16 &tgt, uint8_t paletteID); @@ -633,13 +634,11 @@ class WS2812FX { // 96 bytes #endif // semi-private (just obscured) used in effect functions through macros _currentPalette(CRGBPalette16(CRGB::Black)), - _bri_t(0), _colors_t{0,0,0}, _virtualSegmentLength(0), // true private variables _length(DEFAULT_LED_COUNT), _brightness(DEFAULT_BRIGHTNESS), - _usedSegmentData(0), _transitionDur(750), _targetFps(WLED_FPS), _frametime(FRAMETIME_FIXED), @@ -707,7 +706,6 @@ class WS2812FX { // 96 bytes inline void setShowCallback(show_callback cb) { _callback = cb; } inline void setTransition(uint16_t t) { _transitionDur = t; } inline void appendSegment(const Segment &seg = Segment()) { _segments.push_back(seg); } - inline void addUsedSegmentData(int16_t size) { _usedSegmentData += size; } bool gammaCorrectBri, @@ -753,7 +751,6 @@ class WS2812FX { // 96 bytes inline uint16_t getMinShowDelay(void) { return MIN_SHOW_DELAY; } inline uint16_t getLengthTotal(void) { return _length; } inline uint16_t getTransition(void) { return _transitionDur; } - inline uint16_t getUsedSegmentData(void) { return _usedSegmentData; } uint32_t now, @@ -823,7 +820,6 @@ class WS2812FX { // 96 bytes // using public variables to reduce code size increase due to inline function getSegment() (with bounds checking) // and color transitions - uint8_t _bri_t; // opacity used for effect (includes transition) uint32_t _colors_t[3]; // color used for effect (includes transition) uint16_t _virtualSegmentLength; @@ -833,7 +829,6 @@ class WS2812FX { // 96 bytes private: uint16_t _length; uint8_t _brightness; - uint16_t _usedSegmentData; uint16_t _transitionDur; uint8_t _targetFps; diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 63530080..3d3fae65 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -152,8 +152,7 @@ void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col) #ifndef WLED_DISABLE_2D if (!strip.isMatrix) return; // not a matrix set-up - uint8_t _bri_t = strip._bri_t; - //uint8_t _bri_t = currentBri(getOption(SEG_OPTION_ON) ? opacity : 0); + uint8_t _bri_t = currentBri(getOption(SEG_OPTION_ON) ? opacity : 0); if (_bri_t < 255) { byte r = scale8(R(col), _bri_t); byte g = scale8(G(col), _bri_t); diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index cdb8952f..1138912a 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -73,6 +73,7 @@ /////////////////////////////////////////////////////////////////////////////// // Segment class implementation /////////////////////////////////////////////////////////////////////////////// +uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for their data[] Segment::Segment(const Segment &orig) { DEBUG_PRINTLN(F("-- Segment duplicated --")); @@ -138,11 +139,10 @@ Segment& Segment::operator= (Segment &&orig) noexcept { return *this; } -bool Segment::allocateData(uint16_t len) { +bool Segment::allocateData(size_t len) { if (data && _dataLen == len) return true; //already allocated deallocateData(); - // TODO: move out to WS2812FX class: for (seg : _segments) sum += seg.dataSize(); - if (strip.getUsedSegmentData() + len > MAX_SEGMENT_DATA) return false; //not enough memory + if (Segment::getUsedSegmentData() + len > MAX_SEGMENT_DATA) return false; //not enough memory // if possible use SPI RAM on ESP32 #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM) if (psramFound()) @@ -151,7 +151,7 @@ bool Segment::allocateData(uint16_t len) { #endif data = (byte*) malloc(len); if (!data) return false; //allocation failed - strip.addUsedSegmentData(len); // TODO: move out to WS2812FX class: for (seg : _segments) sum += seg.dataSize(); + Segment::addUsedSegmentData(len); _dataLen = len; memset(data, 0, len); DEBUG_PRINTF("-- Allocated data %p (%d)\n", data, (int)len); @@ -159,13 +159,12 @@ bool Segment::allocateData(uint16_t len) { } void Segment::deallocateData() { - // NOTE: deallocating data sometimes produces corrupt heap. if (!data) return; DEBUG_PRINTF("-- Deallocating data: %p (%d)\n", data, (int)_dataLen); free(data); DEBUG_PRINTLN(F("-- Data freed.")); data = nullptr; - strip.addUsedSegmentData(-(int16_t)_dataLen); // TODO: move out to WS2812FX class: for (seg : _segments) sum -= seg.dataSize(); + Segment::addUsedSegmentData(-_dataLen); _dataLen = 0; DEBUG_PRINTLN(F("-- Dealocated data.")); } @@ -216,16 +215,20 @@ uint16_t Segment::progress() { //transition progression between 0-65535 } uint8_t Segment::currentBri(uint8_t briNew, bool useCct) { - //if (!_t) return (useCct) ? cct : opacity; + //if (_t) { if (getOption(SEG_OPTION_TRANSITIONAL)) { uint32_t prog = progress() + 1; if (useCct) return ((briNew * prog) + /*_t->*/_cctT * (0x10000 - prog)) >> 16; else return ((briNew * prog) + /*_t->*/_briT * (0x10000 - prog)) >> 16; } else { - return (useCct) ? cct : (getOption(SEG_OPTION_ON) ? opacity : 0); + return briNew; } } +uint32_t Segment::currentColor(uint8_t slot, uint32_t colorNew) { + return getOption(SEG_OPTION_TRANSITIONAL) /*&& _t*/ ? color_blend(/*_t->*/_colorT[slot], colorNew, progress(), true) : colorNew; +} + CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) { static unsigned long _lastPaletteChange = 0; // perhaps it should be per segment byte tcp[72]; @@ -375,7 +378,7 @@ uint16_t Segment::virtualHeight() { // 1D strip uint16_t Segment::virtualLength() { #ifndef WLED_DISABLE_2D - if (height() > 1) { + if (is2D()) { uint16_t vW = virtualWidth(); uint16_t vH = virtualHeight(); uint32_t vLen = vW * vH; // use all pixels from segment @@ -400,7 +403,7 @@ uint16_t Segment::virtualLength() { void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col) { #ifndef WLED_DISABLE_2D - if (height() > 1) { // if this does not work use strip.isMatrix + if (is2D()) { // if this does not work use strip.isMatrix uint16_t vH = virtualHeight(); // segment height in logical pixels uint16_t vW = virtualWidth(); switch (map1D2D) { @@ -431,8 +434,7 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col) #endif uint16_t len = length(); - uint8_t _bri_t = strip._bri_t; - //uint8_t _bri_t = currentBri(getOption(SEG_OPTION_ON) ? opacity : 0); + uint8_t _bri_t = currentBri(getOption(SEG_OPTION_ON) ? opacity : 0); if (_bri_t < 255) { byte r = scale8(R(col), _bri_t); byte g = scale8(G(col), _bri_t); @@ -501,7 +503,7 @@ void Segment::setPixelColor(float i, uint32_t col, bool aa) uint32_t Segment::getPixelColor(uint16_t i) { #ifndef WLED_DISABLE_2D - if (height() > 1) { // if this does not work use strip.isMatrix + if (is2D()) { // if this does not work use strip.isMatrix uint16_t vH = virtualHeight(); // segment height in logical pixels uint16_t vW = virtualWidth(); switch (map1D2D) { @@ -589,11 +591,11 @@ void Segment::refreshLightCapabilities() { * Fills segment with color */ void Segment::fill(uint32_t c) { - const uint16_t cols = strip.isMatrix ? virtualWidth() : virtualLength(); + const uint16_t cols = is2D() ? virtualWidth() : virtualLength(); const uint16_t rows = virtualHeight(); // will be 1 for 1D for(uint16_t y = 0; y < rows; y++) for (uint16_t x = 0; x < cols; x++) { - if (strip.isMatrix) setPixelColorXY(x, y, c); - else setPixelColor(x, c); + if (is2D()) setPixelColorXY(x, y, c); + else setPixelColor(x, c); } } @@ -611,7 +613,7 @@ void Segment::addPixelColor(uint16_t n, uint32_t color) { * fade out function, higher rate = quicker fade */ void Segment::fade_out(uint8_t rate) { - const uint16_t cols = strip.isMatrix ? virtualWidth() : virtualLength(); + const uint16_t cols = is2D() ? virtualWidth() : virtualLength(); const uint16_t rows = virtualHeight(); // will be 1 for 1D rate = (255-rate) >> 1; @@ -624,7 +626,7 @@ void Segment::fade_out(uint8_t rate) { int b2 = B(color); for (uint16_t y = 0; y < rows; y++) for (uint16_t x = 0; x < cols; x++) { - color = strip.isMatrix ? getPixelColorXY(x, y) : getPixelColor(x); + color = is2D() ? getPixelColorXY(x, y) : getPixelColor(x); int w1 = W(color); int r1 = R(color); int g1 = G(color); @@ -641,19 +643,19 @@ void Segment::fade_out(uint8_t rate) { gdelta += (g2 == g1) ? 0 : (g2 > g1) ? 1 : -1; bdelta += (b2 == b1) ? 0 : (b2 > b1) ? 1 : -1; - if (strip.isMatrix) setPixelColorXY(x, y, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta); - else setPixelColor(x, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta); + if (is2D()) setPixelColorXY(x, y, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta); + else setPixelColor(x, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta); } } // fades all pixels to black using nscale8() void Segment::fadeToBlackBy(uint8_t fadeBy) { - const uint16_t cols = strip.isMatrix ? virtualWidth() : virtualLength(); + const uint16_t cols = is2D() ? virtualWidth() : virtualLength(); const uint16_t rows = virtualHeight(); // will be 1 for 1D for (uint16_t y = 0; y < rows; y++) for (uint16_t x = 0; x < cols; x++) { - if (strip.isMatrix) setPixelColorXY(x, y, CRGB(getPixelColorXY(x,y)).nscale8(255-fadeBy)); - else setPixelColor(x, CRGB(getPixelColor(x)).nscale8(255-fadeBy)); + if (is2D()) setPixelColorXY(x, y, CRGB(getPixelColorXY(x,y)).nscale8(255-fadeBy)); + else setPixelColor(x, CRGB(getPixelColor(x)).nscale8(255-fadeBy)); } } @@ -662,7 +664,8 @@ void Segment::fadeToBlackBy(uint8_t fadeBy) { */ void Segment::blur(uint8_t blur_amount) { - if (strip.isMatrix) { +#ifndef WLED_DISABLE_2D + if (is2D()) { // compatibility with 2D const uint16_t cols = virtualWidth(); const uint16_t rows = virtualHeight(); @@ -670,6 +673,7 @@ void Segment::blur(uint8_t blur_amount) for (uint16_t k = 0; k < cols; k++) blurCol(k, blur_amount); // blur all columns return; } +#endif uint8_t keep = 255 - blur_amount; uint8_t seep = blur_amount >> 1; CRGB carryover = CRGB::Black; @@ -844,25 +848,24 @@ void WS2812FX::service() { if (!seg.getOption(SEG_OPTION_FREEZE)) { //only run effect function if not frozen _virtualSegmentLength = seg.virtualLength(); - _bri_t = seg.currentBri(seg.getOption(SEG_OPTION_ON) ? seg.opacity : 0); - uint8_t _cct_t = seg.currentBri(seg.cct, true); - _colors_t[0] = seg.currentColor(0, seg.colors[0]); - _colors_t[1] = seg.currentColor(1, seg.colors[1]); - _colors_t[2] = seg.currentColor(2, seg.colors[2]); + _colors_t[0] = seg.currentColor(0, seg.colors[0]); + _colors_t[1] = seg.currentColor(1, seg.colors[1]); + _colors_t[2] = seg.currentColor(2, seg.colors[2]); seg.currentPalette(_currentPalette, seg.palette); - seg.handleTransition(); - - if (!cctFromRgb || correctWB) busses.setSegmentCCT(_cct_t, correctWB); + 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.handleTransition(); + // effect blending (execute previous effect) // actual code may be a bit more involved as effects have runtime data including allocated memory //if (getOption(SEG_OPTION_TRANSITIONAL) && seg._modeP) (*_mode[seg._modeP])(progress()); delay = (*_mode[seg.mode])(); if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.call++; + if (seg.transitional && delay > FRAMETIME) delay = FRAMETIME; // foce faster updates during transition } seg.next_time = nowUp + delay; From eb9eda1f6d2f41a7eecd7da3ebafcc20141633c6 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sat, 30 Jul 2022 14:50:11 +0200 Subject: [PATCH 4/5] Transition struct (reduced RAM footprint). --- wled00/FX.h | 18 +++++----- wled00/FX_fcn.cpp | 85 ++++++++++++++++++++++++++--------------------- wled00/wled.h | 2 +- 3 files changed, 57 insertions(+), 48 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 6e2c81a3..6b4fd7c1 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -426,7 +426,7 @@ typedef struct Segment { static uint16_t _usedSegmentData; // transition data, valid only if getOption(SEG_OPTION_TRANSITIONAL)==true, holds values during transition - //struct Transition { + struct Transition { uint32_t _colorT[NUM_COLORS]; uint8_t _briT; // temporary brightness uint8_t _cctT; // temporary CCT @@ -434,11 +434,11 @@ typedef struct Segment { //uint8_t _modeP; // previous mode/effect (transitioning effects is way more complex than this) uint32_t _start; uint16_t _dur; - // Transition(uint16_t dur=750) : _briT(255), _cctT(127), _palT(CRGBPalette16(CRGB::Black)), _modeP(FX_MODE_STATIC), _start(millis()), _dur(dur) {} - // Transition(uint16_t d, uint8_t b, uint8_t c, const uint32_t *o) : _briT(b), _cctT(c), _palT(CRGBPalette16(CRGB::Black)), _modeP(FX_MODE_STATIC), _start(millis()), _dur(d) { - // for (size_t i=0; i_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); } + if (orig._t) { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); } DEBUG_PRINTF(" Original data: %p (%d)\n", orig.data, (int)orig._dataLen); DEBUG_PRINTF(" Constructed data: %p (%d)\n", data, (int)_dataLen); } +// move constructor Segment::Segment(Segment &&orig) noexcept { DEBUG_PRINTLN(F("-- Move constructor --")); memcpy(this, &orig, sizeof(Segment)); orig.name = nullptr; orig.data = nullptr; orig._dataLen = 0; - //orig._t = nullptr; + orig._t = nullptr; } +// copy assignment Segment& Segment::operator= (const Segment &orig) { DEBUG_PRINTLN(F("-- Segment copied --")); if (this != &orig) { @@ -105,22 +108,23 @@ Segment& Segment::operator= (const Segment &orig) { DEBUG_PRINTF(" Copy Deleting %s (%p)\n", name, name); delete[] name; } - //if (_t) delete _t; + if (_t) delete _t; deallocateData(); memcpy(this, &orig, sizeof(Segment)); name = nullptr; data = nullptr; _dataLen = 0; - //_t = nullptr; + _t = nullptr; if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); } if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); } - //if (orig._t) { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); } + if (orig._t) { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); } DEBUG_PRINTF(" Original data: %p (%d)\n", orig.data, (int)orig._dataLen); DEBUG_PRINTF(" Copied data: %p (%d)\n", data, (int)_dataLen); } return *this; } +// move assignment Segment& Segment::operator= (Segment &&orig) noexcept { DEBUG_PRINTLN(F("-- Moving segment --")); if (this != &orig) { @@ -128,13 +132,13 @@ Segment& Segment::operator= (Segment &&orig) noexcept { DEBUG_PRINTF(" Move Deleting %s (%p)\n", name, name); delete[] name; // free old name } - //if (_t) delete _t; deallocateData(); // free old runtime data + if (_t) delete _t; memcpy(this, &orig, sizeof(Segment)); orig.name = nullptr; orig.data = nullptr; orig._dataLen = 0; - //orig._t = nullptr; + orig._t = nullptr; } return *this; } @@ -184,49 +188,51 @@ void Segment::resetIfRequired() { } void Segment::startTransition(uint16_t dur) { + if (transitional || _t) return; // already in transition + // starting a transition has to occur before change so we get current values 1st - /*uint8_t*/ _briT = currentBri(getOption(SEG_OPTION_ON) ? opacity : 0); // comment out uint8_t if not using Transition struct - /*uint8_t*/ _cctT = currentBri(cct, true); // comment out uint8_t if not using Transition struct - /*CRGBPalette16 _palT;*/ loadPalette(_palT, palette); + uint8_t _briT = currentBri(getOption(SEG_OPTION_ON) ? opacity : 0); // comment out uint8_t if not using Transition struct + uint8_t _cctT = currentBri(cct, true); // comment out uint8_t if not using Transition struct + CRGBPalette16 _palT; loadPalette(_palT, palette); ///*uint8_t*/ _modeP = mode; // comment out uint8_t if not using Transition struct - //uint32_t _colorT[NUM_COLORS]; // comment out if not using Transition struct + uint32_t _colorT[NUM_COLORS]; // comment out if not using Transition struct for (size_t i=0; i_briT = _briT; - //_t->_cctT = _cctT; - //_t->_palT = _palT; + if (!_t) _t = new Transition(dur); // no previous transition running + if (!_t) return; // failed to allocat data + _t->_briT = _briT; + _t->_cctT = _cctT; + _t->_palT = _palT; //_t->_modeT = _modeP; - //for (size_t i=0; i_colorT[i] = _colorT[i]; + for (size_t i=0; i_colorT[i] = _colorT[i]; // comment out if using transition struct as it is done in constructor - _dur = dur; - _start = millis(); + //_dur = dur; + //_start = millis(); setOption(SEG_OPTION_TRANSITIONAL, true); } uint16_t Segment::progress() { //transition progression between 0-65535 - //if (!_t) return 0xFFFFU; + if (!transitional || !_t) return 0xFFFFU; uint32_t timeNow = millis(); - if (timeNow - /*_t->*/_start > /*_t->*/_dur) return 0xFFFFU; - return (timeNow - /*_t->*/_start) * 0xFFFFU / /*_t->*/_dur; + if (timeNow - _t->_start > _t->_dur) return 0xFFFFU; + return (timeNow - _t->_start) * 0xFFFFU / _t->_dur; } uint8_t Segment::currentBri(uint8_t briNew, bool useCct) { - //if (_t) { - if (getOption(SEG_OPTION_TRANSITIONAL)) { + if (transitional && _t) { + //if (getOption(SEG_OPTION_TRANSITIONAL)) { uint32_t prog = progress() + 1; - if (useCct) return ((briNew * prog) + /*_t->*/_cctT * (0x10000 - prog)) >> 16; - else return ((briNew * prog) + /*_t->*/_briT * (0x10000 - prog)) >> 16; + if (useCct) return ((briNew * prog) + _t->_cctT * (0x10000 - prog)) >> 16; + else return ((briNew * prog) + _t->_briT * (0x10000 - prog)) >> 16; } else { return briNew; } } uint32_t Segment::currentColor(uint8_t slot, uint32_t colorNew) { - return getOption(SEG_OPTION_TRANSITIONAL) /*&& _t*/ ? color_blend(/*_t->*/_colorT[slot], colorNew, progress(), true) : colorNew; + return transitional && _t ? color_blend(_t->_colorT[slot], colorNew, progress(), true) : colorNew; } CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) { @@ -309,23 +315,26 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) { CRGBPalette16 &Segment::currentPalette(CRGBPalette16 &targetPalette, uint8_t pal) { loadPalette(targetPalette, pal); - //if (_t && progress() < 0xFFFFU) { - if (strip.paletteFade && getOption(SEG_OPTION_TRANSITIONAL) && progress() < 0xFFFFU) { // TODO: get rid of + if (transitional && _t && progress() < 0xFFFFU) { + //if (strip.paletteFade && getOption(SEG_OPTION_TRANSITIONAL) && progress() < 0xFFFFU) { // blend palettes - uint8_t blends = map(_dur, 0, 0xFFFF, 48, 6); // do not blend palettes too quickly (0-65.5s) - nblendPaletteTowardPalette(/*_t->*/_palT, targetPalette, blends); - targetPalette = /*_t->*/_palT; // copy transitioning/temporary palette + uint8_t blends = map(_t->_dur, 0, 0xFFFF, 48, 6); // do not blend palettes too quickly (0-65.5s) + nblendPaletteTowardPalette(_t->_palT, targetPalette, blends); + targetPalette = _t->_palT; // copy transitioning/temporary palette } return targetPalette; } void Segment::handleTransition() { - if (!getOption(SEG_OPTION_TRANSITIONAL)) return; + if (!transitional) return; unsigned long maxWait = millis() + 20; if (mode == FX_MODE_STATIC && next_time > maxWait) next_time = maxWait; if (progress() == 0xFFFFU) { - //if (_t) { delete _t; _t = nullptr; } - setOption(SEG_OPTION_TRANSITIONAL, false); // finish transitioning segment + if (_t) { + delete _t; + _t = nullptr; + } + transitional = false; // finish transitioning segment } } @@ -753,8 +762,8 @@ uint32_t IRAM_ATTR Segment::color_from_palette(uint16_t i, bool mapping, bool wr if (!wrap) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end" CRGB fastled_col; CRGBPalette16 curPal; - if (transitional) curPal = /*_t->*/_palT; - else loadPalette(curPal, palette); + if (transitional && _t) curPal = _t->_palT; + else loadPalette(curPal, palette); fastled_col = ColorFromPalette(curPal, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global return RGBW32(fastled_col.r, fastled_col.g, fastled_col.b, 0); diff --git a/wled00/wled.h b/wled00/wled.h index 2b1c9d85..f5f2d7cd 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2207301 +#define VERSION 2207302 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG From 96da48ae82cd91dcd14359a14a1ca8e719b4be24 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Sat, 30 Jul 2022 15:03:06 +0200 Subject: [PATCH 5/5] 1D mapping bugfix. --- wled00/data/index.js | 2 +- wled00/html_ui.h | 1426 +++++++++++++++++++++--------------------- 2 files changed, 714 insertions(+), 714 deletions(-) diff --git a/wled00/data/index.js b/wled00/data/index.js index ae73482e..b67a52f4 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -755,7 +755,7 @@ function populateSegments(s)
${!isM?rvXck:''} - ${map2D} + ${isM?map2D:''} ${s.AudioReactive && s.AudioReactive.on ? "" : sndSim}