From 272f96b40558bffad51bf87b941828bceb70e3de Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Fri, 30 Jun 2023 21:12:59 +0200 Subject: [PATCH] Double buffering at bus level. --- wled00/FX.h | 19 ++--- wled00/FX_2Dfcn.cpp | 4 - wled00/FX_fcn.cpp | 106 ++++----------------------- wled00/bus_manager.cpp | 163 +++++++++++++++++++++++++++-------------- wled00/bus_manager.h | 21 ++++-- wled00/bus_wrapper.h | 118 +++++++++++++++++++++++++++-- wled00/cfg.cpp | 6 +- wled00/set.cpp | 2 +- wled00/wled.cpp | 2 +- wled00/wled.h | 15 ++-- wled00/xml.cpp | 2 +- 11 files changed, 266 insertions(+), 192 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 6b312a21..f5e7a4e3 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -379,7 +379,6 @@ typedef struct Segment { uint16_t aux0; // custom var uint16_t aux1; // custom var byte* data; // effect data pointer - CRGB* leds; // local leds[] array (may be a pointer to global) static uint16_t maxWidth, maxHeight; // these define matrix width & height (max. segment dimensions) private: @@ -462,7 +461,6 @@ typedef struct Segment { aux0(0), aux1(0), data(nullptr), - leds(nullptr), _capabilities(0), _dataLen(0), _t(nullptr) @@ -483,10 +481,8 @@ typedef struct Segment { //Serial.print(F("Destroying segment:")); //if (name) Serial.printf(" %s (%p)", name, name); //if (data) Serial.printf(" %d (%p)", (int)_dataLen, data); - //if (leds) Serial.printf(" [%u]", length()*sizeof(CRGB)); //Serial.println(); //#endif - if (leds) free(leds); if (name) delete[] name; if (_t) delete _t; deallocateData(); @@ -496,7 +492,7 @@ typedef struct Segment { Segment& operator= (Segment &&orig) noexcept; // move assignment #ifdef WLED_DEBUG - size_t getSize() const { return sizeof(Segment) + (data?_dataLen:0) + (name?strlen(name):0) + (_t?sizeof(Transition):0) + (leds?sizeof(CRGB)*length():0); } + size_t getSize() const { return sizeof(Segment) + (data?_dataLen:0) + (name?strlen(name):0) + (_t?sizeof(Transition):0); } #endif inline bool getOption(uint8_t n) const { return ((options >> n) & 0x01); } @@ -537,7 +533,7 @@ typedef struct Segment { * Safe to call from interrupts and network requests. */ inline void markForReset(void) { reset = true; } // setOption(SEG_OPTION_RESET, true) - void setUpLeds(void); // set up leds[] array for loseless getPixelColor() + inline void setUpLeds(void) {} // legacy filler (should be removed) // transition functions void startTransition(uint16_t dur); // transition has to start before actual segment values change @@ -578,7 +574,7 @@ typedef struct Segment { uint16_t virtualHeight(void) const; uint16_t nrOfVStrips(void) const; #ifndef WLED_DISABLE_2D - uint16_t XY(uint16_t x, uint16_t y); // support function to get relative index within segment (for leds[]) + uint16_t XY(uint16_t x, uint16_t y); // support function to get relative index within segment void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } // automatically inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } // automatically inline @@ -677,7 +673,6 @@ class WS2812FX { // 96 bytes // true private variables _length(DEFAULT_LED_COUNT), _brightness(DEFAULT_BRIGHTNESS), - _renderBrightness(0), _transitionDur(750), _targetFps(WLED_FPS), _frametime(FRAMETIME_FIXED), @@ -710,7 +705,6 @@ class WS2812FX { // 96 bytes panel.clear(); #endif customPalettes.clear(); - if (_globalLedBuffer) free(_globalLedBuffer); } static WS2812FX* getInstance(void) { return instance; } @@ -757,8 +751,7 @@ class WS2812FX { // 96 bytes hasCCTBus(void), // return true if the strip is being sent pixel updates isUpdating(void), - deserializeMap(uint8_t n=0), - useGlobalLedBuffer = false; + deserializeMap(uint8_t n=0); inline bool isServicing(void) { return _isServicing; } inline bool hasWhiteChannel(void) {return _hasWhiteChannel;} @@ -876,7 +869,7 @@ class WS2812FX { // 96 bytes private: uint16_t _length; - uint8_t _brightness, _renderBrightness; + uint8_t _brightness; uint16_t _transitionDur; uint8_t _targetFps; @@ -905,8 +898,6 @@ class WS2812FX { // 96 bytes uint8_t _segment_index; uint8_t _mainSegment; - static uint32_t *_globalLedBuffer; // global leds[] array - uint8_t estimateCurrentAndLimitBri(void); }; diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index f4dac68d..5a5720b3 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -199,8 +199,6 @@ void /*IRAM_ATTR*/ Segment::setPixelColorXY(int x, int y, uint32_t col) if (Segment::maxHeight==1) return; // not a matrix set-up if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit - if (leds) leds[XY(x,y)] = col; - uint8_t _bri_t = currentBri(on ? opacity : 0); if (_bri_t < 255) { byte r = scale8(R(col), _bri_t); @@ -286,8 +284,6 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa) // returns RGBW values of pixel uint32_t Segment::getPixelColorXY(uint16_t x, uint16_t y) { - int i = XY(x,y); - if (leds) return RGBW32(leds[i].r, leds[i].g, leds[i].b, 0); if (reverse ) x = virtualWidth() - x - 1; if (reverse_y) y = virtualHeight() - y - 1; if (transpose) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index dbe35a8c..e0f132cd 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -85,11 +85,9 @@ Segment::Segment(const Segment &orig) { data = nullptr; _dataLen = 0; _t = nullptr; - leds = 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.leds) { leds = (CRGB*)malloc(sizeof(CRGB)*length()); if (leds) memcpy(leds, orig.leds, sizeof(CRGB)*length()); } } // move constructor @@ -100,7 +98,6 @@ Segment::Segment(Segment &&orig) noexcept { orig.data = nullptr; orig._dataLen = 0; orig._t = nullptr; - orig.leds = nullptr; } // copy assignment @@ -110,7 +107,6 @@ Segment& Segment::operator= (const Segment &orig) { // clean destination if (name) delete[] name; if (_t) delete _t; - if (leds) free(leds); deallocateData(); // copy source memcpy((void*)this, (void*)&orig, sizeof(Segment)); @@ -119,12 +115,10 @@ Segment& Segment::operator= (const Segment &orig) { data = nullptr; _dataLen = 0; _t = nullptr; - leds = nullptr; // copy source data 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.leds) { leds = (CRGB*)malloc(sizeof(CRGB)*length()); if (leds) memcpy(leds, orig.leds, sizeof(CRGB)*length()); } } return *this; } @@ -136,13 +130,11 @@ Segment& Segment::operator= (Segment &&orig) noexcept { if (name) delete[] name; // free old name deallocateData(); // free old runtime data if (_t) delete _t; - if (leds) free(leds); memcpy((void*)this, (void*)&orig, sizeof(Segment)); orig.name = nullptr; orig.data = nullptr; orig._dataLen = 0; orig._t = nullptr; - orig.leds = nullptr; } return *this; } @@ -182,29 +174,12 @@ void Segment::deallocateData() { */ void Segment::resetIfRequired() { if (reset) { - if (leds) { free(leds); leds = nullptr; } - //if (transitional && _t) { transitional = false; delete _t; _t = nullptr; } deallocateData(); next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0; reset = false; // setOption(SEG_OPTION_RESET, false); } } -void Segment::setUpLeds() { - // deallocation happens in resetIfRequired() as it is called when segment changes or in destructor - if (WS2812FX::_globalLedBuffer) return; // TODO optional seg buffer for FX without lossy restore due to opacity - - // no global buffer - if (leds == nullptr && length() > 0) { //softhack007 quickfix - avoid malloc(0) which is undefined behaviour (should not happen, but i've seen it) - //#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM) - //if (psramFound()) - // leds = (CRGB*)ps_malloc(sizeof(CRGB)*length()); // softhack007 disabled; putting leds into psram leads to horrible slowdown on WROVER boards - //else - //#endif - leds = (CRGB*)malloc(sizeof(CRGB)*length()); - } -} - CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) { static unsigned long _lastPaletteChange = 0; // perhaps it should be per segment static CRGBPalette16 randomPalette = CRGBPalette16(DEFAULT_COLOR); @@ -617,8 +592,6 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col) } #endif - if (leds) leds[i] = col; - uint16_t len = length(); uint8_t _bri_t = currentBri(on ? opacity : 0); if (_bri_t < 255) { @@ -718,8 +691,6 @@ uint32_t Segment::getPixelColor(int i) } #endif - if (leds) return RGBW32(leds[i].r, leds[i].g, leds[i].b, 0); - if (reverse) i = virtualLength() - i - 1; i *= groupLength(); i += start; @@ -1058,24 +1029,6 @@ void WS2812FX::finalizeInit(void) Segment::maxHeight = 1; } - // initialize leds array - if (_globalLedBuffer) { - //purgeSegments(true); - free(_globalLedBuffer); - _globalLedBuffer = nullptr; - } - if (useGlobalLedBuffer) { - size_t arrSize = sizeof(uint32_t) * getLengthTotal(); - // softhack007 disabled; putting leds into psram leads to horrible slowdown on WROVER boards (see setUpLeds()) - //#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM) - //if (psramFound()) - // Segment::_globalLedBuffer = (CRGB*) ps_malloc(arrSize); - //else - //#endif - _globalLedBuffer = (uint32_t*) malloc(arrSize); - memset(_globalLedBuffer, 0, arrSize); - } - //segments are created in makeAutoSegments(); DEBUG_PRINTLN(F("Loading custom palettes")); loadCustomPalettes(); // (re)load all custom palettes @@ -1103,11 +1056,10 @@ void WS2812FX::service() { if(nowUp > seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC)) { if (seg.grouping == 0) seg.grouping = 1; // sanity check - if (!doShow) { - busses.setBrightness(_brightness); // bus luminance must be set before FX using setPixelColor() - _renderBrightness = _brightness; // save in case brightness gets changed while FX is calculated +// if (!doShow) { +// busses.setBrightness(_brightness); // bus luminance must be set before FX using setPixelColor() doShow = true; - } +// } uint16_t delay = FRAMETIME; if (!seg.freeze) { //only run effect function if not frozen @@ -1146,18 +1098,13 @@ void IRAM_ATTR WS2812FX::setPixelColor(int i, uint32_t col) { if (i < customMappingSize) i = customMappingTable[i]; if (i >= _length) return; - if (_globalLedBuffer) { - _globalLedBuffer[i] = col; - } else { - busses.setPixelColor(i, col); - } + busses.setPixelColor(i, col); } uint32_t WS2812FX::getPixelColor(uint16_t i) { if (i < customMappingSize) i = customMappingTable[i]; if (i >= _length) return 0; - if (_globalLedBuffer) return _globalLedBuffer[i]; return busses.getPixelColor(i); } @@ -1188,7 +1135,6 @@ uint8_t WS2812FX::estimateCurrentAndLimitBri() { if (ablMilliampsMax < 150 || actualMilliampsPerLed == 0) { //0 mA per LED and too low numbers turn off calculation currentMilliamps = 0; - busses.setBrightness(_brightness); return _brightness; } @@ -1209,15 +1155,14 @@ uint8_t WS2812FX::estimateCurrentAndLimitBri() { uint16_t len = bus->getLength(); uint32_t busPowerSum = 0; for (uint_fast16_t i = 0; i < len; i++) { //sum up the usage of each LED - uint32_t c = 0; - if (_globalLedBuffer) - { - c = _globalLedBuffer[bus->getStart() + i]; - } else { - c = bus->getPixelColor(i); - } + uint32_t c = bus->getPixelColor(i); byte r = R(c), g = G(c), b = B(c), w = W(c); - + if (useGlobalLedBuffer) { + r = scale8(r, _brightness); + g = scale8(g, _brightness); + b = scale8(b, _brightness); + w = scale8(w, _brightness); + } if(useWackyWS2815PowerModel) { //ignore white component on WS2815 power calculation busPowerSum += (MAX(MAX(r,g),b)) * 3; } else { @@ -1232,22 +1177,14 @@ uint8_t WS2812FX::estimateCurrentAndLimitBri() { powerSum += busPowerSum; } - uint32_t powerSum0 = powerSum; - powerSum *= _brightness; uint8_t newBri = _brightness; - - if (powerSum > powerBudget) //scale brightness down to stay in current limit - { + if (powerSum > powerBudget) {//scale brightness down to stay in current limit float scale = (float)powerBudget / (float)powerSum; uint16_t scaleI = scale * 255; uint8_t scaleB = (scaleI > 255) ? 255 : scaleI; newBri = scale8(_brightness, scaleB); - busses.setBrightness(newBri); //to keep brightness uniform, sets virtual busses too - currentMilliamps = (powerSum0 * newBri) / puPerMilliamp; - } else { - currentMilliamps = powerSum / puPerMilliamp; - busses.setBrightness(_brightness); } + currentMilliamps = (powerSum * newBri) / puPerMilliamp; currentMilliamps += MA_FOR_ESP; //add power of ESP back to estimate currentMilliamps += pLen; //add standby power back to estimate return newBri; @@ -1259,19 +1196,8 @@ void WS2812FX::show(void) { show_callback callback = _callback; if (callback) callback(); - Bus::setRestoreBri(_renderBrightness); uint8_t busBrightness = estimateCurrentAndLimitBri(); - - if (_globalLedBuffer) { // copy data from buffer to bus - //for (uint16_t i = 0; i < _length; i++) busses.setPixelColor(i, _globalLedBuffer[i]); - busses.setColorsFromBuffer(_globalLedBuffer); - } else { - // if brightness changed since last show, must set everything again to update to new luminance - if (_renderBrightness != busBrightness) { - for (uint16_t i = 0; i < _length; i++) busses.setPixelColor(i, busses.getPixelColor(i)); // LOSSLESS due to trick (but still slow!) - Bus::setRestoreBri(busBrightness); - } - } + busses.setBrightness(busBrightness); // some buses send asynchronously and this method will return before // all of the data has been sent. @@ -1283,7 +1209,6 @@ void WS2812FX::show(void) { if (diff > 0) fpsCurr = 1000 / diff; _cumulativeFps = (3 * _cumulativeFps + fpsCurr) >> 2; _lastShow = now; - _renderBrightness = _brightness; } /** @@ -1351,8 +1276,6 @@ void WS2812FX::setBrightness(uint8_t b, bool direct) { if (direct) { // would be dangerous if applied immediately (could exceed ABL), but will not output until the next show() busses.setBrightness(b); - _renderBrightness = b; - Bus::setRestoreBri(b); } else { unsigned long t = millis(); if (_segments[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) show(); //apply brightness change immediately if no refresh soon @@ -1735,7 +1658,6 @@ bool WS2812FX::deserializeMap(uint8_t n) { WS2812FX* WS2812FX::instance = nullptr; -uint32_t* WS2812FX::_globalLedBuffer = nullptr; const char JSON_mode_names[] PROGMEM = R"=====(["FX names moved"])====="; const char JSON_palette_names[] PROGMEM = R"=====([ diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 001ac1d4..a3807dbe 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -91,6 +91,11 @@ uint32_t Bus::autoWhiteCalc(uint32_t c) { return RGBW32(r, g, b, w); } +uint8_t *Bus::allocData(size_t size) { + if (_data) free(_data); // should not happen, but for safety + return _data = (uint8_t *)(size>0 ? calloc(size, sizeof(uint8_t)) : nullptr); +} + BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) : Bus(bc.type, bc.start, bc.autoWhite), _colorOrderMap(com) { if (!IS_DIGITAL(bc.type) || !bc.count) return; @@ -107,22 +112,57 @@ BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) : Bu reversed = bc.reversed; _needsRefresh = bc.refreshReq || bc.type == TYPE_TM1814; _skip = bc.skipAmount; //sacrificial pixels - _len = bc.count + _skip; + _len = bc.count; + _colorOrder = bc.colorOrder; _iType = PolyBus::getI(bc.type, _pins, nr); if (_iType == I_NONE) return; + if (useGlobalLedBuffer && !allocData(_len * (hasWhite() + 3*hasRGB()))) return; //warning: hardcoded channel count uint16_t lenToCreate = _len; - if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(_len); // only needs a third of "RGB" LEDs for NeoPixelBus - _busPtr = PolyBus::create(_iType, _pins, lenToCreate, nr, _frequencykHz); + if (bc.type == TYPE_WS2812_1CH_X3) lenToCreate = NUM_ICS_WS2812_1CH_3X(_len); // only needs a third of "RGB" LEDs for NeoPixelBus + _busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr, _frequencykHz); _valid = (_busPtr != nullptr); - _colorOrder = bc.colorOrder; DEBUG_PRINTF("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u)\n", _valid?"S":"Uns", nr, _len, bc.type, _pins[0],_pins[1],_iType); } void BusDigital::show() { - PolyBus::show(_busPtr, _iType); + if (!_valid) return; + PolyBus::setBrightness(_busPtr, _iType, _bri); + if (useGlobalLedBuffer) { + size_t channels = hasWhite() + 3*hasRGB(); + for (size_t i=0; i<_len; i++) { + size_t offset = i*channels; + uint8_t co = _colorOrderMap.getPixelColorOrder(i+_start, _colorOrder); + uint32_t c; + if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs (_len is always a multiple of 3) + switch (i%3) { + case 0: c = RGBW32(_data[offset] , _data[offset+1], _data[offset+2], 0); break; + case 1: c = RGBW32(_data[offset-1], _data[offset] , _data[offset+1], 0); break; + case 2: c = RGBW32(_data[offset-2], _data[offset-1], _data[offset] , 0); break; + } + } else { + c = RGBW32(_data[offset],_data[offset+1],_data[offset+2],(hasWhite()?_data[offset+3]:0)); + } + uint16_t pix = i; + if (reversed) pix = _len - pix -1; + else pix += _skip; + PolyBus::setPixelColor(_busPtr, _iType, pix, c, co); + } + PolyBus::show(_busPtr, _iType); + } else { + PolyBus::applyPostAdjustments(_busPtr, _iType); + PolyBus::show(_busPtr, _iType); + // now restore (as close as possible) previous colors + // warning: this may not be the best idea as the buffer may still be in use + for (size_t i=0; i<_len; i++) { + uint8_t co = _colorOrderMap.getPixelColorOrder(i+_start, _colorOrder); + setPixelColor(i, restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, i, co), _bri)); + } + } + PolyBus::setBrightness(_busPtr, _iType, 255); // restore full brightness } bool BusDigital::canShow() { + if (!_valid) return true; return PolyBus::canShow(_busPtr, _iType); } @@ -130,57 +170,81 @@ void BusDigital::setBrightness(uint8_t b) { //Fix for turning off onboard LED breaking bus #ifdef LED_BUILTIN if (_bri == 0 && b > 0) { - if (_pins[0] == LED_BUILTIN || _pins[1] == LED_BUILTIN) PolyBus::begin(_busPtr, _iType, _pins); + if (_pins[0] == LED_BUILTIN || _pins[1] == LED_BUILTIN) reinit(); } #endif Bus::setBrightness(b); - PolyBus::setBrightness(_busPtr, _iType, b); } //If LEDs are skipped, it is possible to use the first as a status LED. //TODO only show if no new show due in the next 50ms void BusDigital::setStatusPixel(uint32_t c) { - if (_skip && canShow()) { + if (_valid && _skip && canShow()) { PolyBus::setPixelColor(_busPtr, _iType, 0, c, _colorOrderMap.getPixelColorOrder(_start, _colorOrder)); PolyBus::show(_busPtr, _iType); } } void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) { - if (_type == TYPE_SK6812_RGBW || _type == TYPE_TM1814 || _type == TYPE_WS2812_1CH_X3) c = autoWhiteCalc(c); + if (!_valid) return; + if (hasWhite()) c = autoWhiteCalc(c); if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT - if (reversed) pix = _len - pix -1; - else pix += _skip; - uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder); - if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs - uint16_t pOld = pix; - pix = IC_INDEX_WS2812_1CH_3X(pix); - uint32_t cOld = PolyBus::getPixelColor(_busPtr, _iType, pix, co); - switch (pOld % 3) { // change only the single channel (TODO: this can cause loss because of get/set) - case 0: c = RGBW32(R(cOld), W(c) , B(cOld), 0); break; - case 1: c = RGBW32(W(c) , G(cOld), B(cOld), 0); break; - case 2: c = RGBW32(R(cOld), G(cOld), W(c) , 0); break; + if (useGlobalLedBuffer) { + size_t channels = hasWhite() + 3*hasRGB(); + size_t offset = pix*channels; + if (hasRGB()) { + _data[offset++] = R(c); + _data[offset++] = G(c); + _data[offset++] = B(c); } + if (hasWhite()) _data[offset] = W(c); + } else { + if (reversed) pix = _len - pix -1; + else pix += _skip; + uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder); + if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs + uint16_t pOld = pix; + pix = IC_INDEX_WS2812_1CH_3X(pix); + uint32_t cOld = PolyBus::getPixelColor(_busPtr, _iType, pix, co); + switch (pOld % 3) { // change only the single channel (TODO: this can cause loss because of get/set) + case 0: c = RGBW32(R(cOld), W(c) , B(cOld), 0); break; + case 1: c = RGBW32(W(c) , G(cOld), B(cOld), 0); break; + case 2: c = RGBW32(R(cOld), G(cOld), W(c) , 0); break; + } + } + PolyBus::setPixelColor(_busPtr, _iType, pix, c, co); } - PolyBus::setPixelColor(_busPtr, _iType, pix, c, co); } uint32_t BusDigital::getPixelColor(uint16_t pix) { - if (reversed) pix = _len - pix -1; - else pix += _skip; - uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder); - if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs - uint16_t pOld = pix; - pix = IC_INDEX_WS2812_1CH_3X(pix); - uint32_t c = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, pix, co)); - switch (pOld % 3) { // get only the single channel - case 0: c = RGBW32(G(c), G(c), G(c), G(c)); break; - case 1: c = RGBW32(R(c), R(c), R(c), R(c)); break; - case 2: c = RGBW32(B(c), B(c), B(c), B(c)); break; + if (!_valid) return 0; + if (useGlobalLedBuffer) { + size_t channels = hasWhite() + 3*hasRGB(); + size_t offset = pix*channels; + uint32_t c; + if (!hasRGB()) { + c = RGBW32(_data[offset], _data[offset], _data[offset], _data[offset]); + } else { + c = RGBW32(_data[offset], _data[offset+1], _data[offset+2], hasWhite() ? _data[offset+3] : 0); } return c; + } else { + if (reversed) pix = _len - pix -1; + else pix += _skip; + uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder); + if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs + uint16_t pOld = pix; + pix = IC_INDEX_WS2812_1CH_3X(pix); + uint32_t c = PolyBus::getPixelColor(_busPtr, _iType, pix, co); + switch (pOld % 3) { // get only the single channel + case 0: c = RGBW32(G(c), G(c), G(c), G(c)); break; + case 1: c = RGBW32(R(c), R(c), R(c), R(c)); break; + case 2: c = RGBW32(B(c), B(c), B(c), B(c)); break; + } + return c; + } + return PolyBus::getPixelColor(_busPtr, _iType, pix, co); } - return restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, pix, co)); } uint8_t BusDigital::getPins(uint8_t* pinArray) { @@ -196,6 +260,7 @@ void BusDigital::setColorOrder(uint8_t colorOrder) { } void BusDigital::reinit() { + if (!_valid) return; PolyBus::begin(_busPtr, _iType, _pins); } @@ -205,6 +270,7 @@ void BusDigital::cleanup() { _iType = I_NONE; _valid = false; _busPtr = nullptr; + if (useGlobalLedBuffer) freeData(); pinManager.deallocatePin(_pins[1], PinOwner::BusDigital); pinManager.deallocatePin(_pins[0], PinOwner::BusDigital); } @@ -229,7 +295,7 @@ BusPwm::BusPwm(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) { for (uint8_t i = 0; i < numPins; i++) { uint8_t currentPin = bc.pins[i]; if (!pinManager.allocatePin(currentPin, true, PinOwner::BusPwm)) { - deallocatePins(); return; + deallocatePins(); return; } _pins[i] = currentPin; //store only after allocatePin() succeeds #ifdef ESP8266 @@ -240,6 +306,7 @@ BusPwm::BusPwm(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) { #endif } reversed = bc.reversed; + _data = _pwmdata; // avoid malloc() and use stack _valid = true; } @@ -353,6 +420,7 @@ BusOnOff::BusOnOff(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) { _pin = currentPin; //store only after allocatePin() succeeds pinMode(_pin, OUTPUT); reversed = bc.reversed; + _data = &_onoffdata; // avoid malloc() and use stack _valid = true; } @@ -363,18 +431,17 @@ void BusOnOff::setPixelColor(uint16_t pix, uint32_t c) { uint8_t g = G(c); uint8_t b = B(c); uint8_t w = W(c); - - _data = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0; + _data[0] = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0; } uint32_t BusOnOff::getPixelColor(uint16_t pix) { if (!_valid) return 0; - return RGBW32(_data, _data, _data, _data); + return RGBW32(_data[0], _data[0], _data[0], _data[0]); } void BusOnOff::show() { if (!_valid) return; - digitalWrite(_pin, reversed ? !(bool)_data : (bool)_data); + digitalWrite(_pin, reversed ? !(bool)_data[0] : (bool)_data[0]); } uint8_t BusOnOff::getPins(uint8_t* pinArray) { @@ -401,13 +468,10 @@ BusNetwork::BusNetwork(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) { break; } _UDPchannels = _rgbw ? 4 : 3; - _data = (byte *)malloc(bc.count * _UDPchannels); - if (_data == nullptr) return; - memset(_data, 0, bc.count * _UDPchannels); _len = bc.count; _client = IPAddress(bc.pins[0],bc.pins[1],bc.pins[2],bc.pins[3]); _broadcastLock = false; - _valid = true; + _valid = (allocData(_len * _UDPchannels) != nullptr); } void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) { @@ -424,7 +488,7 @@ void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) { uint32_t BusNetwork::getPixelColor(uint16_t pix) { 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); + return RGBW32(_data[offset], _data[offset+1], _data[offset+2], (_rgbw ? _data[offset+3] : 0)); } void BusNetwork::show() { @@ -444,8 +508,7 @@ uint8_t BusNetwork::getPins(uint8_t* pinArray) { void BusNetwork::cleanup() { _type = I_NONE; _valid = false; - if (_data != nullptr) free(_data); - _data = nullptr; + freeData(); } @@ -515,15 +578,6 @@ void IRAM_ATTR BusManager::setPixelColor(uint16_t pix, uint32_t c) { } } -void BusManager::setColorsFromBuffer(uint32_t* buf) { - for (uint8_t i = 0; i < numBusses; i++) { - Bus* b = busses[i]; - uint16_t bstart = b->getStart(); - for (uint16_t pix = 0; pix < b->getLength(); pix++) - busses[i]->setPixelColor(pix, buf[bstart + pix]); - } -} - void BusManager::setBrightness(uint8_t b) { for (uint8_t i = 0; i < numBusses; i++) { busses[i]->setBrightness(b); @@ -572,4 +626,3 @@ uint16_t BusManager::getTotalLength() { int16_t Bus::_cct = -1; uint8_t Bus::_cctBlend = 0; uint8_t Bus::_gAWM = 255; -uint8_t Bus::_restaurationBri = 255; diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index e550440a..8e78310b 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -18,6 +18,10 @@ #define IC_INDEX_WS2812_2CH_3X(i) ((i)*2/3) #define WS2812_2CH_3X_SPANS_2_ICS(i) ((i)&0x01) // every other LED zone is on two different ICs +// flag for using double buffering in BusDigital +extern bool useGlobalLedBuffer; + + //temporary struct for passing bus configuration to bus struct BusConfig { uint8_t type; @@ -54,6 +58,7 @@ struct BusConfig { } }; + // Defines an LED Strip and its color ordering. struct ColorOrderMapEntry { uint16_t start; @@ -87,12 +92,14 @@ struct ColorOrderMap { ColorOrderMapEntry _mappings[WLED_MAX_COLOR_ORDER_MAPPINGS]; }; + //parent class of BusDigital, BusPwm, and BusNetwork class Bus { public: Bus(uint8_t type, uint16_t start, uint8_t aw) : _bri(255) , _len(1) + , _data(nullptr) // keep data access consistent across all types of buses , _valid(false) , _needsRefresh(false) { @@ -154,7 +161,6 @@ class Bus { inline uint8_t getAutoWhiteMode() { 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; } - inline static void setRestoreBri(uint8_t b) { _restaurationBri = b; } bool reversed = false; @@ -163,15 +169,17 @@ class Bus { uint8_t _bri; uint16_t _start; uint16_t _len; + uint8_t *_data; bool _valid; bool _needsRefresh; uint8_t _autoWhiteMode; static uint8_t _gAWM; static int16_t _cct; static uint8_t _cctBlend; - static uint8_t _restaurationBri; // previous brightness used as setPixelColor was called. Used for lossy restoration uint32_t autoWhiteCalc(uint32_t c); + uint8_t *allocData(size_t size = 1); + void freeData() { if (_data) free(_data); _data = nullptr; } }; @@ -226,7 +234,7 @@ class BusDigital : public Bus { void * _busPtr = nullptr; const ColorOrderMap &_colorOrderMap; - inline uint32_t restoreColorLossy(uint32_t c) { + inline uint32_t restoreColorLossy(uint32_t c, uint8_t _restaurationBri) { if (_bri == 255) return c; uint8_t* chan = (uint8_t*) &c; @@ -265,7 +273,7 @@ class BusPwm : public Bus { private: uint8_t _pins[5] = {255, 255, 255, 255, 255}; - uint8_t _data[5] = {0}; + uint8_t _pwmdata[5] = {0}; #ifdef ARDUINO_ARCH_ESP32 uint8_t _ledcStart = 255; #endif @@ -297,7 +305,7 @@ class BusOnOff : public Bus { private: uint8_t _pin = 255; - uint8_t _data = 0; + uint8_t _onoffdata = 0; }; @@ -337,7 +345,6 @@ class BusNetwork : public Bus { uint8_t _UDPchannels; bool _rgbw; bool _broadcastLock; - byte *_data; }; @@ -359,8 +366,6 @@ class BusManager { void setPixelColor(uint16_t pix, uint32_t c); - void setColorsFromBuffer(uint32_t* buf); - void setBrightness(uint8_t b); void setSegmentCCT(int16_t cct, bool allowWBCorrection = false); diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index 0314a793..9807c54b 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -280,6 +280,7 @@ class PolyBus { #endif if (clock_kHz) dotStar_strip->SetMethodSettings(NeoSpiSettings((uint32_t)clock_kHz*1000)); } + // Begin & initialize the PixelSettings for TM1814 strips. template static void beginTM1814(void* busPtr) { @@ -288,6 +289,7 @@ class PolyBus { // Max current for each LED (22.5 mA). tm1814_strip->SetPixelSettings(NeoTm1814Settings(/*R*/225, /*G*/225, /*B*/225, /*W*/225)); } + static void begin(void* busPtr, uint8_t busType, uint8_t* pins, uint16_t clock_kHz = 0U) { switch (busType) { case I_NONE: break; @@ -390,7 +392,8 @@ class PolyBus { case I_SS_WS1_3: (static_cast(busPtr))->Begin(); break; case I_SS_P98_3: (static_cast(busPtr))->Begin(); break; } - }; + } + static void* create(uint8_t busType, uint8_t* pins, uint16_t len, uint8_t channel, uint16_t clock_kHz = 0U) { void* busPtr = nullptr; switch (busType) { @@ -491,7 +494,8 @@ class PolyBus { } begin(busPtr, busType, pins, clock_kHz); return busPtr; - }; + } + static void show(void* busPtr, uint8_t busType) { switch (busType) { case I_NONE: break; @@ -588,7 +592,8 @@ class PolyBus { case I_HS_P98_3: (static_cast(busPtr))->Show(); break; case I_SS_P98_3: (static_cast(busPtr))->Show(); break; } - }; + } + static bool canShow(void* busPtr, uint8_t busType) { switch (busType) { case I_NONE: return true; @@ -685,7 +690,8 @@ class PolyBus { case I_SS_P98_3: return (static_cast(busPtr))->CanShow(); break; } return true; - }; + } + static void setPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint32_t c, uint8_t co) { uint8_t r = c >> 16; uint8_t g = c >> 8; @@ -805,7 +811,8 @@ class PolyBus { case I_HS_P98_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; case I_SS_P98_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col)); break; } - }; + } + static void setBrightness(void* busPtr, uint8_t busType, uint8_t b) { switch (busType) { case I_NONE: break; @@ -902,7 +909,106 @@ class PolyBus { case I_HS_P98_3: (static_cast(busPtr))->SetLuminance(b); break; case I_SS_P98_3: (static_cast(busPtr))->SetLuminance(b); break; } - }; + } + + static void applyPostAdjustments(void* busPtr, uint8_t busType) { + switch (busType) { + case I_NONE: break; + #ifdef ESP8266 + case I_8266_U0_NEO_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_U1_NEO_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_DM_NEO_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_BB_NEO_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_U0_NEO_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_U1_NEO_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_DM_NEO_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_BB_NEO_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_U0_400_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_U1_400_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_DM_400_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_BB_400_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_U0_TM1_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_U1_TM1_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_DM_TM1_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_BB_TM1_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_U0_TM2_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_U1_TM2_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_DM_TM2_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_BB_TM2_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_U0_UCS_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_U1_UCS_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_DM_UCS_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_BB_UCS_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_U0_UCS_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_U1_UCS_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_DM_UCS_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_BB_UCS_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + #endif + #ifdef ARDUINO_ARCH_ESP32 + case I_32_RN_NEO_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + #ifndef WLED_NO_I2S0_PIXELBUS + case I_32_I0_NEO_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + #endif + #ifndef WLED_NO_I2S1_PIXELBUS + case I_32_I1_NEO_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + #endif +// case I_32_BB_NEO_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_32_RN_NEO_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + #ifndef WLED_NO_I2S0_PIXELBUS + case I_32_I0_NEO_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + #endif + #ifndef WLED_NO_I2S1_PIXELBUS + case I_32_I1_NEO_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + #endif +// case I_32_BB_NEO_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_32_RN_400_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + #ifndef WLED_NO_I2S0_PIXELBUS + case I_32_I0_400_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + #endif + #ifndef WLED_NO_I2S1_PIXELBUS + case I_32_I1_400_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + #endif +// case I_32_BB_400_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_32_RN_TM1_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_32_RN_TM2_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + #ifndef WLED_NO_I2S0_PIXELBUS + case I_32_I0_TM1_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_32_I0_TM2_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + #endif + #ifndef WLED_NO_I2S1_PIXELBUS + case I_32_I1_TM1_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_32_I1_TM2_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + #endif + case I_32_RN_UCS_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + #ifndef WLED_NO_I2S0_PIXELBUS + case I_32_I0_UCS_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + #endif + #ifndef WLED_NO_I2S1_PIXELBUS + case I_32_I1_UCS_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + #endif +// case I_32_BB_UCS_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_32_RN_UCS_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + #ifndef WLED_NO_I2S0_PIXELBUS + case I_32_I0_UCS_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + #endif + #ifndef WLED_NO_I2S1_PIXELBUS + case I_32_I1_UCS_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + #endif +// case I_32_BB_UCS_4: (static_cast(busPtr))->ApplyPostAdjustments(); break; + #endif + case I_HS_DOT_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_SS_DOT_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_HS_LPD_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_SS_LPD_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_HS_LPO_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_SS_LPO_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_HS_WS1_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_SS_WS1_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_HS_P98_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_SS_P98_3: (static_cast(busPtr))->ApplyPostAdjustments(); break; + } + } + static uint32_t getPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint8_t co) { RgbwColor col(0,0,0,0); switch (busType) { diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index bc63f811..6c2e9422 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -90,7 +90,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { CJSON(strip.cctBlending, hw_led[F("cb")]); Bus::setCCTBlend(strip.cctBlending); strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS - CJSON(strip.useGlobalLedBuffer, hw_led[F("ld")]); + CJSON(useGlobalLedBuffer, hw_led[F("ld")]); #ifndef WLED_DISABLE_2D // 2D Matrix Settings @@ -163,7 +163,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { if (fromFS) { BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz); mem += BusManager::memUsage(bc); - if (strip.useGlobalLedBuffer && start + length > maxlen) { + if (useGlobalLedBuffer && start + length > maxlen) { maxlen = start + length; globalBufMem = maxlen * 4; } @@ -711,7 +711,7 @@ void serializeConfig() { hw_led[F("cb")] = strip.cctBlending; hw_led["fps"] = strip.getTargetFps(); hw_led[F("rgbwm")] = Bus::getGlobalAWMode(); // global auto white mode override - hw_led[F("ld")] = strip.useGlobalLedBuffer; + hw_led[F("ld")] = useGlobalLedBuffer; #ifndef WLED_DISABLE_2D // 2D Matrix Settings diff --git a/wled00/set.cpp b/wled00/set.cpp index 30d499d6..3420f22c 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -91,7 +91,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) Bus::setCCTBlend(strip.cctBlending); Bus::setGlobalAWMode(request->arg(F("AW")).toInt()); strip.setTargetFps(request->arg(F("FR")).toInt()); - strip.useGlobalLedBuffer = request->hasArg(F("LD")); + useGlobalLedBuffer = request->hasArg(F("LD")); bool busesChanged = false; for (uint8_t s = 0; s < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; s++) { diff --git a/wled00/wled.cpp b/wled00/wled.cpp index cd027c06..86d14d6a 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -156,7 +156,7 @@ void WLED::loop() for (uint8_t i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { if (busConfigs[i] == nullptr) break; mem += BusManager::memUsage(*busConfigs[i]); - if (strip.useGlobalLedBuffer && busConfigs[i]->start + busConfigs[i]->count > maxlen) { + if (useGlobalLedBuffer && busConfigs[i]->start + busConfigs[i]->count > maxlen) { maxlen = busConfigs[i]->start + busConfigs[i]->count; globalBufMem = maxlen * 4; } diff --git a/wled00/wled.h b/wled00/wled.h index 6cae6a8a..7fc3ba86 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2306240 +#define VERSION 23062490 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG @@ -331,12 +331,13 @@ WLED_GLOBAL byte bootPreset _INIT(0); // save preset to load //if true, a segment per bus will be created on boot and LED settings save //if false, only one segment spanning the total LEDs is created, //but not on LED settings save if there is more than one segment currently -WLED_GLOBAL bool autoSegments _INIT(false); -WLED_GLOBAL bool correctWB _INIT(false); // CCT color correction of RGB color -WLED_GLOBAL bool cctFromRgb _INIT(false); // CCT is calculated from RGB instead of using seg.cct -WLED_GLOBAL bool gammaCorrectCol _INIT(true ); // use gamma correction on colors -WLED_GLOBAL bool gammaCorrectBri _INIT(false); // use gamma correction on brightness -WLED_GLOBAL float gammaCorrectVal _INIT(2.8f); // gamma correction value +WLED_GLOBAL bool autoSegments _INIT(false); +WLED_GLOBAL bool useGlobalLedBuffer _INIT(true); +WLED_GLOBAL bool correctWB _INIT(false); // CCT color correction of RGB color +WLED_GLOBAL bool cctFromRgb _INIT(false); // CCT is calculated from RGB instead of using seg.cct +WLED_GLOBAL bool gammaCorrectCol _INIT(true); // use gamma correction on colors +WLED_GLOBAL bool gammaCorrectBri _INIT(false); // use gamma correction on brightness +WLED_GLOBAL float gammaCorrectVal _INIT(2.8f); // gamma correction value WLED_GLOBAL byte col[] _INIT_N(({ 255, 160, 0, 0 })); // current RGB(W) primary color. col[] should be updated if you want to change the color. WLED_GLOBAL byte colSec[] _INIT_N(({ 0, 0, 0, 0 })); // current RGB(W) secondary color diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 8057aac7..12fc9717 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -404,7 +404,7 @@ void getSettingsJS(byte subPage, char* dest) sappend('v',SET_F("CB"),strip.cctBlending); sappend('v',SET_F("FR"),strip.getTargetFps()); sappend('v',SET_F("AW"),Bus::getGlobalAWMode()); - sappend('c',SET_F("LD"),strip.useGlobalLedBuffer); + sappend('c',SET_F("LD"),useGlobalLedBuffer); for (uint8_t s=0; s < busses.getNumBusses(); s++) { Bus* bus = busses.getBus(s);