Double buffering at bus level.

This commit is contained in:
Blaz Kristan 2023-06-30 21:12:59 +02:00
parent fa9b151c36
commit 272f96b405
11 changed files with 266 additions and 192 deletions

View File

@ -379,7 +379,6 @@ typedef struct Segment {
uint16_t aux0; // custom var uint16_t aux0; // custom var
uint16_t aux1; // custom var uint16_t aux1; // custom var
byte* data; // effect data pointer 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) static uint16_t maxWidth, maxHeight; // these define matrix width & height (max. segment dimensions)
private: private:
@ -462,7 +461,6 @@ typedef struct Segment {
aux0(0), aux0(0),
aux1(0), aux1(0),
data(nullptr), data(nullptr),
leds(nullptr),
_capabilities(0), _capabilities(0),
_dataLen(0), _dataLen(0),
_t(nullptr) _t(nullptr)
@ -483,10 +481,8 @@ typedef struct Segment {
//Serial.print(F("Destroying segment:")); //Serial.print(F("Destroying segment:"));
//if (name) Serial.printf(" %s (%p)", name, name); //if (name) Serial.printf(" %s (%p)", name, name);
//if (data) Serial.printf(" %d (%p)", (int)_dataLen, data); //if (data) Serial.printf(" %d (%p)", (int)_dataLen, data);
//if (leds) Serial.printf(" [%u]", length()*sizeof(CRGB));
//Serial.println(); //Serial.println();
//#endif //#endif
if (leds) free(leds);
if (name) delete[] name; if (name) delete[] name;
if (_t) delete _t; if (_t) delete _t;
deallocateData(); deallocateData();
@ -496,7 +492,7 @@ typedef struct Segment {
Segment& operator= (Segment &&orig) noexcept; // move assignment Segment& operator= (Segment &&orig) noexcept; // move assignment
#ifdef WLED_DEBUG #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 #endif
inline bool getOption(uint8_t n) const { return ((options >> n) & 0x01); } 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. * Safe to call from interrupts and network requests.
*/ */
inline void markForReset(void) { reset = true; } // setOption(SEG_OPTION_RESET, true) 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 // transition functions
void startTransition(uint16_t dur); // transition has to start before actual segment values change 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 virtualHeight(void) const;
uint16_t nrOfVStrips(void) const; uint16_t nrOfVStrips(void) const;
#ifndef WLED_DISABLE_2D #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, 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, 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 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 // true private variables
_length(DEFAULT_LED_COUNT), _length(DEFAULT_LED_COUNT),
_brightness(DEFAULT_BRIGHTNESS), _brightness(DEFAULT_BRIGHTNESS),
_renderBrightness(0),
_transitionDur(750), _transitionDur(750),
_targetFps(WLED_FPS), _targetFps(WLED_FPS),
_frametime(FRAMETIME_FIXED), _frametime(FRAMETIME_FIXED),
@ -710,7 +705,6 @@ class WS2812FX { // 96 bytes
panel.clear(); panel.clear();
#endif #endif
customPalettes.clear(); customPalettes.clear();
if (_globalLedBuffer) free(_globalLedBuffer);
} }
static WS2812FX* getInstance(void) { return instance; } static WS2812FX* getInstance(void) { return instance; }
@ -757,8 +751,7 @@ class WS2812FX { // 96 bytes
hasCCTBus(void), hasCCTBus(void),
// return true if the strip is being sent pixel updates // return true if the strip is being sent pixel updates
isUpdating(void), isUpdating(void),
deserializeMap(uint8_t n=0), deserializeMap(uint8_t n=0);
useGlobalLedBuffer = false;
inline bool isServicing(void) { return _isServicing; } inline bool isServicing(void) { return _isServicing; }
inline bool hasWhiteChannel(void) {return _hasWhiteChannel;} inline bool hasWhiteChannel(void) {return _hasWhiteChannel;}
@ -876,7 +869,7 @@ class WS2812FX { // 96 bytes
private: private:
uint16_t _length; uint16_t _length;
uint8_t _brightness, _renderBrightness; uint8_t _brightness;
uint16_t _transitionDur; uint16_t _transitionDur;
uint8_t _targetFps; uint8_t _targetFps;
@ -905,8 +898,6 @@ class WS2812FX { // 96 bytes
uint8_t _segment_index; uint8_t _segment_index;
uint8_t _mainSegment; uint8_t _mainSegment;
static uint32_t *_globalLedBuffer; // global leds[] array
uint8_t uint8_t
estimateCurrentAndLimitBri(void); estimateCurrentAndLimitBri(void);
}; };

View File

@ -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 (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 (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); uint8_t _bri_t = currentBri(on ? opacity : 0);
if (_bri_t < 255) { if (_bri_t < 255) {
byte r = scale8(R(col), _bri_t); 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 // returns RGBW values of pixel
uint32_t Segment::getPixelColorXY(uint16_t x, uint16_t y) { 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 ) x = virtualWidth() - x - 1;
if (reverse_y) y = virtualHeight() - y - 1; if (reverse_y) y = virtualHeight() - y - 1;
if (transpose) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed if (transpose) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed

View File

@ -85,11 +85,9 @@ Segment::Segment(const Segment &orig) {
data = nullptr; data = nullptr;
_dataLen = 0; _dataLen = 0;
_t = nullptr; _t = nullptr;
leds = nullptr;
if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); } 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.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); }
if (orig.leds) { leds = (CRGB*)malloc(sizeof(CRGB)*length()); if (leds) memcpy(leds, orig.leds, sizeof(CRGB)*length()); }
} }
// move constructor // move constructor
@ -100,7 +98,6 @@ Segment::Segment(Segment &&orig) noexcept {
orig.data = nullptr; orig.data = nullptr;
orig._dataLen = 0; orig._dataLen = 0;
orig._t = nullptr; orig._t = nullptr;
orig.leds = nullptr;
} }
// copy assignment // copy assignment
@ -110,7 +107,6 @@ Segment& Segment::operator= (const Segment &orig) {
// clean destination // clean destination
if (name) delete[] name; if (name) delete[] name;
if (_t) delete _t; if (_t) delete _t;
if (leds) free(leds);
deallocateData(); deallocateData();
// copy source // copy source
memcpy((void*)this, (void*)&orig, sizeof(Segment)); memcpy((void*)this, (void*)&orig, sizeof(Segment));
@ -119,12 +115,10 @@ Segment& Segment::operator= (const Segment &orig) {
data = nullptr; data = nullptr;
_dataLen = 0; _dataLen = 0;
_t = nullptr; _t = nullptr;
leds = nullptr;
// copy source data // copy source data
if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); } 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.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); }
if (orig.leds) { leds = (CRGB*)malloc(sizeof(CRGB)*length()); if (leds) memcpy(leds, orig.leds, sizeof(CRGB)*length()); }
} }
return *this; return *this;
} }
@ -136,13 +130,11 @@ Segment& Segment::operator= (Segment &&orig) noexcept {
if (name) delete[] name; // free old name if (name) delete[] name; // free old name
deallocateData(); // free old runtime data deallocateData(); // free old runtime data
if (_t) delete _t; if (_t) delete _t;
if (leds) free(leds);
memcpy((void*)this, (void*)&orig, sizeof(Segment)); memcpy((void*)this, (void*)&orig, sizeof(Segment));
orig.name = nullptr; orig.name = nullptr;
orig.data = nullptr; orig.data = nullptr;
orig._dataLen = 0; orig._dataLen = 0;
orig._t = nullptr; orig._t = nullptr;
orig.leds = nullptr;
} }
return *this; return *this;
} }
@ -182,29 +174,12 @@ void Segment::deallocateData() {
*/ */
void Segment::resetIfRequired() { void Segment::resetIfRequired() {
if (reset) { if (reset) {
if (leds) { free(leds); leds = nullptr; }
//if (transitional && _t) { transitional = false; delete _t; _t = nullptr; }
deallocateData(); deallocateData();
next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0; next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
reset = false; // setOption(SEG_OPTION_RESET, false); 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) { CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
static unsigned long _lastPaletteChange = 0; // perhaps it should be per segment static unsigned long _lastPaletteChange = 0; // perhaps it should be per segment
static CRGBPalette16 randomPalette = CRGBPalette16(DEFAULT_COLOR); static CRGBPalette16 randomPalette = CRGBPalette16(DEFAULT_COLOR);
@ -617,8 +592,6 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
} }
#endif #endif
if (leds) leds[i] = col;
uint16_t len = length(); uint16_t len = length();
uint8_t _bri_t = currentBri(on ? opacity : 0); uint8_t _bri_t = currentBri(on ? opacity : 0);
if (_bri_t < 255) { if (_bri_t < 255) {
@ -718,8 +691,6 @@ uint32_t Segment::getPixelColor(int i)
} }
#endif #endif
if (leds) return RGBW32(leds[i].r, leds[i].g, leds[i].b, 0);
if (reverse) i = virtualLength() - i - 1; if (reverse) i = virtualLength() - i - 1;
i *= groupLength(); i *= groupLength();
i += start; i += start;
@ -1058,24 +1029,6 @@ void WS2812FX::finalizeInit(void)
Segment::maxHeight = 1; 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(); //segments are created in makeAutoSegments();
DEBUG_PRINTLN(F("Loading custom palettes")); DEBUG_PRINTLN(F("Loading custom palettes"));
loadCustomPalettes(); // (re)load all 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(nowUp > seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC))
{ {
if (seg.grouping == 0) seg.grouping = 1; // sanity check if (seg.grouping == 0) seg.grouping = 1; // sanity check
if (!doShow) { // if (!doShow) {
busses.setBrightness(_brightness); // bus luminance must be set before FX using setPixelColor() // busses.setBrightness(_brightness); // bus luminance must be set before FX using setPixelColor()
_renderBrightness = _brightness; // save in case brightness gets changed while FX is calculated
doShow = true; doShow = true;
} // }
uint16_t delay = FRAMETIME; uint16_t delay = FRAMETIME;
if (!seg.freeze) { //only run effect function if not frozen 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 < customMappingSize) i = customMappingTable[i];
if (i >= _length) return; 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) uint32_t WS2812FX::getPixelColor(uint16_t i)
{ {
if (i < customMappingSize) i = customMappingTable[i]; if (i < customMappingSize) i = customMappingTable[i];
if (i >= _length) return 0; if (i >= _length) return 0;
if (_globalLedBuffer) return _globalLedBuffer[i];
return busses.getPixelColor(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 if (ablMilliampsMax < 150 || actualMilliampsPerLed == 0) { //0 mA per LED and too low numbers turn off calculation
currentMilliamps = 0; currentMilliamps = 0;
busses.setBrightness(_brightness);
return _brightness; return _brightness;
} }
@ -1209,15 +1155,14 @@ uint8_t WS2812FX::estimateCurrentAndLimitBri() {
uint16_t len = bus->getLength(); uint16_t len = bus->getLength();
uint32_t busPowerSum = 0; uint32_t busPowerSum = 0;
for (uint_fast16_t i = 0; i < len; i++) { //sum up the usage of each LED for (uint_fast16_t i = 0; i < len; i++) { //sum up the usage of each LED
uint32_t c = 0; uint32_t c = bus->getPixelColor(i);
if (_globalLedBuffer)
{
c = _globalLedBuffer[bus->getStart() + i];
} else {
c = bus->getPixelColor(i);
}
byte r = R(c), g = G(c), b = B(c), w = W(c); 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 if(useWackyWS2815PowerModel) { //ignore white component on WS2815 power calculation
busPowerSum += (MAX(MAX(r,g),b)) * 3; busPowerSum += (MAX(MAX(r,g),b)) * 3;
} else { } else {
@ -1232,22 +1177,14 @@ uint8_t WS2812FX::estimateCurrentAndLimitBri() {
powerSum += busPowerSum; powerSum += busPowerSum;
} }
uint32_t powerSum0 = powerSum;
powerSum *= _brightness;
uint8_t newBri = _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; float scale = (float)powerBudget / (float)powerSum;
uint16_t scaleI = scale * 255; uint16_t scaleI = scale * 255;
uint8_t scaleB = (scaleI > 255) ? 255 : scaleI; uint8_t scaleB = (scaleI > 255) ? 255 : scaleI;
newBri = scale8(_brightness, scaleB); 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 += MA_FOR_ESP; //add power of ESP back to estimate
currentMilliamps += pLen; //add standby power back to estimate currentMilliamps += pLen; //add standby power back to estimate
return newBri; return newBri;
@ -1259,19 +1196,8 @@ void WS2812FX::show(void) {
show_callback callback = _callback; show_callback callback = _callback;
if (callback) callback(); if (callback) callback();
Bus::setRestoreBri(_renderBrightness);
uint8_t busBrightness = estimateCurrentAndLimitBri(); uint8_t busBrightness = estimateCurrentAndLimitBri();
busses.setBrightness(busBrightness);
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);
}
}
// some buses send asynchronously and this method will return before // some buses send asynchronously and this method will return before
// all of the data has been sent. // all of the data has been sent.
@ -1283,7 +1209,6 @@ void WS2812FX::show(void) {
if (diff > 0) fpsCurr = 1000 / diff; if (diff > 0) fpsCurr = 1000 / diff;
_cumulativeFps = (3 * _cumulativeFps + fpsCurr) >> 2; _cumulativeFps = (3 * _cumulativeFps + fpsCurr) >> 2;
_lastShow = now; _lastShow = now;
_renderBrightness = _brightness;
} }
/** /**
@ -1351,8 +1276,6 @@ void WS2812FX::setBrightness(uint8_t b, bool direct) {
if (direct) { if (direct) {
// would be dangerous if applied immediately (could exceed ABL), but will not output until the next show() // would be dangerous if applied immediately (could exceed ABL), but will not output until the next show()
busses.setBrightness(b); busses.setBrightness(b);
_renderBrightness = b;
Bus::setRestoreBri(b);
} else { } else {
unsigned long t = millis(); 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 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; WS2812FX* WS2812FX::instance = nullptr;
uint32_t* WS2812FX::_globalLedBuffer = nullptr;
const char JSON_mode_names[] PROGMEM = R"=====(["FX names moved"])====="; const char JSON_mode_names[] PROGMEM = R"=====(["FX names moved"])=====";
const char JSON_palette_names[] PROGMEM = R"=====([ const char JSON_palette_names[] PROGMEM = R"=====([

View File

@ -91,6 +91,11 @@ uint32_t Bus::autoWhiteCalc(uint32_t c) {
return RGBW32(r, g, b, w); 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) { 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; 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; reversed = bc.reversed;
_needsRefresh = bc.refreshReq || bc.type == TYPE_TM1814; _needsRefresh = bc.refreshReq || bc.type == TYPE_TM1814;
_skip = bc.skipAmount; //sacrificial pixels _skip = bc.skipAmount; //sacrificial pixels
_len = bc.count + _skip; _len = bc.count;
_colorOrder = bc.colorOrder;
_iType = PolyBus::getI(bc.type, _pins, nr); _iType = PolyBus::getI(bc.type, _pins, nr);
if (_iType == I_NONE) return; if (_iType == I_NONE) return;
if (useGlobalLedBuffer && !allocData(_len * (hasWhite() + 3*hasRGB()))) return; //warning: hardcoded channel count
uint16_t lenToCreate = _len; 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 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); _busPtr = PolyBus::create(_iType, _pins, lenToCreate + _skip, nr, _frequencykHz);
_valid = (_busPtr != nullptr); _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); 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() { void BusDigital::show() {
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); 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() { bool BusDigital::canShow() {
if (!_valid) return true;
return PolyBus::canShow(_busPtr, _iType); return PolyBus::canShow(_busPtr, _iType);
} }
@ -130,25 +170,35 @@ void BusDigital::setBrightness(uint8_t b) {
//Fix for turning off onboard LED breaking bus //Fix for turning off onboard LED breaking bus
#ifdef LED_BUILTIN #ifdef LED_BUILTIN
if (_bri == 0 && b > 0) { 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 #endif
Bus::setBrightness(b); Bus::setBrightness(b);
PolyBus::setBrightness(_busPtr, _iType, b);
} }
//If LEDs are skipped, it is possible to use the first as a status LED. //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 //TODO only show if no new show due in the next 50ms
void BusDigital::setStatusPixel(uint32_t c) { void BusDigital::setStatusPixel(uint32_t c) {
if (_skip && canShow()) { if (_valid && _skip && canShow()) {
PolyBus::setPixelColor(_busPtr, _iType, 0, c, _colorOrderMap.getPixelColorOrder(_start, _colorOrder)); PolyBus::setPixelColor(_busPtr, _iType, 0, c, _colorOrderMap.getPixelColorOrder(_start, _colorOrder));
PolyBus::show(_busPtr, _iType); PolyBus::show(_busPtr, _iType);
} }
} }
void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) { 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 (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT
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; if (reversed) pix = _len - pix -1;
else pix += _skip; else pix += _skip;
uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder); uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder);
@ -163,16 +213,29 @@ void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) {
} }
} }
PolyBus::setPixelColor(_busPtr, _iType, pix, c, co); PolyBus::setPixelColor(_busPtr, _iType, pix, c, co);
}
} }
uint32_t BusDigital::getPixelColor(uint16_t pix) { uint32_t BusDigital::getPixelColor(uint16_t pix) {
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; if (reversed) pix = _len - pix -1;
else pix += _skip; else pix += _skip;
uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder); uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder);
if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs
uint16_t pOld = pix; uint16_t pOld = pix;
pix = IC_INDEX_WS2812_1CH_3X(pix); pix = IC_INDEX_WS2812_1CH_3X(pix);
uint32_t c = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, pix, co)); uint32_t c = PolyBus::getPixelColor(_busPtr, _iType, pix, co);
switch (pOld % 3) { // get only the single channel switch (pOld % 3) { // get only the single channel
case 0: c = RGBW32(G(c), G(c), G(c), G(c)); break; 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 1: c = RGBW32(R(c), R(c), R(c), R(c)); break;
@ -180,7 +243,8 @@ uint32_t BusDigital::getPixelColor(uint16_t pix) {
} }
return c; return c;
} }
return restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, pix, co)); return PolyBus::getPixelColor(_busPtr, _iType, pix, co);
}
} }
uint8_t BusDigital::getPins(uint8_t* pinArray) { uint8_t BusDigital::getPins(uint8_t* pinArray) {
@ -196,6 +260,7 @@ void BusDigital::setColorOrder(uint8_t colorOrder) {
} }
void BusDigital::reinit() { void BusDigital::reinit() {
if (!_valid) return;
PolyBus::begin(_busPtr, _iType, _pins); PolyBus::begin(_busPtr, _iType, _pins);
} }
@ -205,6 +270,7 @@ void BusDigital::cleanup() {
_iType = I_NONE; _iType = I_NONE;
_valid = false; _valid = false;
_busPtr = nullptr; _busPtr = nullptr;
if (useGlobalLedBuffer) freeData();
pinManager.deallocatePin(_pins[1], PinOwner::BusDigital); pinManager.deallocatePin(_pins[1], PinOwner::BusDigital);
pinManager.deallocatePin(_pins[0], PinOwner::BusDigital); pinManager.deallocatePin(_pins[0], PinOwner::BusDigital);
} }
@ -240,6 +306,7 @@ BusPwm::BusPwm(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
#endif #endif
} }
reversed = bc.reversed; reversed = bc.reversed;
_data = _pwmdata; // avoid malloc() and use stack
_valid = true; _valid = true;
} }
@ -353,6 +420,7 @@ BusOnOff::BusOnOff(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
_pin = currentPin; //store only after allocatePin() succeeds _pin = currentPin; //store only after allocatePin() succeeds
pinMode(_pin, OUTPUT); pinMode(_pin, OUTPUT);
reversed = bc.reversed; reversed = bc.reversed;
_data = &_onoffdata; // avoid malloc() and use stack
_valid = true; _valid = true;
} }
@ -363,18 +431,17 @@ void BusOnOff::setPixelColor(uint16_t pix, uint32_t c) {
uint8_t g = G(c); uint8_t g = G(c);
uint8_t b = B(c); uint8_t b = B(c);
uint8_t w = W(c); uint8_t w = W(c);
_data[0] = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0;
_data = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0;
} }
uint32_t BusOnOff::getPixelColor(uint16_t pix) { uint32_t BusOnOff::getPixelColor(uint16_t pix) {
if (!_valid) return 0; if (!_valid) return 0;
return RGBW32(_data, _data, _data, _data); return RGBW32(_data[0], _data[0], _data[0], _data[0]);
} }
void BusOnOff::show() { void BusOnOff::show() {
if (!_valid) return; 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) { uint8_t BusOnOff::getPins(uint8_t* pinArray) {
@ -401,13 +468,10 @@ BusNetwork::BusNetwork(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
break; break;
} }
_UDPchannels = _rgbw ? 4 : 3; _UDPchannels = _rgbw ? 4 : 3;
_data = (byte *)malloc(bc.count * _UDPchannels);
if (_data == nullptr) return;
memset(_data, 0, bc.count * _UDPchannels);
_len = bc.count; _len = bc.count;
_client = IPAddress(bc.pins[0],bc.pins[1],bc.pins[2],bc.pins[3]); _client = IPAddress(bc.pins[0],bc.pins[1],bc.pins[2],bc.pins[3]);
_broadcastLock = false; _broadcastLock = false;
_valid = true; _valid = (allocData(_len * _UDPchannels) != nullptr);
} }
void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) { 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) { uint32_t BusNetwork::getPixelColor(uint16_t pix) {
if (!_valid || pix >= _len) return 0; if (!_valid || pix >= _len) return 0;
uint16_t offset = pix * _UDPchannels; 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() { void BusNetwork::show() {
@ -444,8 +508,7 @@ uint8_t BusNetwork::getPins(uint8_t* pinArray) {
void BusNetwork::cleanup() { void BusNetwork::cleanup() {
_type = I_NONE; _type = I_NONE;
_valid = false; _valid = false;
if (_data != nullptr) free(_data); freeData();
_data = nullptr;
} }
@ -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) { void BusManager::setBrightness(uint8_t b) {
for (uint8_t i = 0; i < numBusses; i++) { for (uint8_t i = 0; i < numBusses; i++) {
busses[i]->setBrightness(b); busses[i]->setBrightness(b);
@ -572,4 +626,3 @@ uint16_t BusManager::getTotalLength() {
int16_t Bus::_cct = -1; int16_t Bus::_cct = -1;
uint8_t Bus::_cctBlend = 0; uint8_t Bus::_cctBlend = 0;
uint8_t Bus::_gAWM = 255; uint8_t Bus::_gAWM = 255;
uint8_t Bus::_restaurationBri = 255;

View File

@ -18,6 +18,10 @@
#define IC_INDEX_WS2812_2CH_3X(i) ((i)*2/3) #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 #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 //temporary struct for passing bus configuration to bus
struct BusConfig { struct BusConfig {
uint8_t type; uint8_t type;
@ -54,6 +58,7 @@ struct BusConfig {
} }
}; };
// Defines an LED Strip and its color ordering. // Defines an LED Strip and its color ordering.
struct ColorOrderMapEntry { struct ColorOrderMapEntry {
uint16_t start; uint16_t start;
@ -87,12 +92,14 @@ struct ColorOrderMap {
ColorOrderMapEntry _mappings[WLED_MAX_COLOR_ORDER_MAPPINGS]; ColorOrderMapEntry _mappings[WLED_MAX_COLOR_ORDER_MAPPINGS];
}; };
//parent class of BusDigital, BusPwm, and BusNetwork //parent class of BusDigital, BusPwm, and BusNetwork
class Bus { class Bus {
public: public:
Bus(uint8_t type, uint16_t start, uint8_t aw) Bus(uint8_t type, uint16_t start, uint8_t aw)
: _bri(255) : _bri(255)
, _len(1) , _len(1)
, _data(nullptr) // keep data access consistent across all types of buses
, _valid(false) , _valid(false)
, _needsRefresh(false) , _needsRefresh(false)
{ {
@ -154,7 +161,6 @@ class Bus {
inline uint8_t getAutoWhiteMode() { return _autoWhiteMode; } 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 void setGlobalAWMode(uint8_t m) { if (m < 5) _gAWM = m; else _gAWM = AW_GLOBAL_DISABLED; }
inline static uint8_t getGlobalAWMode() { return _gAWM; } inline static uint8_t getGlobalAWMode() { return _gAWM; }
inline static void setRestoreBri(uint8_t b) { _restaurationBri = b; }
bool reversed = false; bool reversed = false;
@ -163,15 +169,17 @@ class Bus {
uint8_t _bri; uint8_t _bri;
uint16_t _start; uint16_t _start;
uint16_t _len; uint16_t _len;
uint8_t *_data;
bool _valid; bool _valid;
bool _needsRefresh; bool _needsRefresh;
uint8_t _autoWhiteMode; uint8_t _autoWhiteMode;
static uint8_t _gAWM; static uint8_t _gAWM;
static int16_t _cct; static int16_t _cct;
static uint8_t _cctBlend; 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); 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; void * _busPtr = nullptr;
const ColorOrderMap &_colorOrderMap; 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; if (_bri == 255) return c;
uint8_t* chan = (uint8_t*) &c; uint8_t* chan = (uint8_t*) &c;
@ -265,7 +273,7 @@ class BusPwm : public Bus {
private: private:
uint8_t _pins[5] = {255, 255, 255, 255, 255}; uint8_t _pins[5] = {255, 255, 255, 255, 255};
uint8_t _data[5] = {0}; uint8_t _pwmdata[5] = {0};
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
uint8_t _ledcStart = 255; uint8_t _ledcStart = 255;
#endif #endif
@ -297,7 +305,7 @@ class BusOnOff : public Bus {
private: private:
uint8_t _pin = 255; uint8_t _pin = 255;
uint8_t _data = 0; uint8_t _onoffdata = 0;
}; };
@ -337,7 +345,6 @@ class BusNetwork : public Bus {
uint8_t _UDPchannels; uint8_t _UDPchannels;
bool _rgbw; bool _rgbw;
bool _broadcastLock; bool _broadcastLock;
byte *_data;
}; };
@ -359,8 +366,6 @@ class BusManager {
void setPixelColor(uint16_t pix, uint32_t c); void setPixelColor(uint16_t pix, uint32_t c);
void setColorsFromBuffer(uint32_t* buf);
void setBrightness(uint8_t b); void setBrightness(uint8_t b);
void setSegmentCCT(int16_t cct, bool allowWBCorrection = false); void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);

View File

@ -280,6 +280,7 @@ class PolyBus {
#endif #endif
if (clock_kHz) dotStar_strip->SetMethodSettings(NeoSpiSettings((uint32_t)clock_kHz*1000)); if (clock_kHz) dotStar_strip->SetMethodSettings(NeoSpiSettings((uint32_t)clock_kHz*1000));
} }
// Begin & initialize the PixelSettings for TM1814 strips. // Begin & initialize the PixelSettings for TM1814 strips.
template <class T> template <class T>
static void beginTM1814(void* busPtr) { static void beginTM1814(void* busPtr) {
@ -288,6 +289,7 @@ class PolyBus {
// Max current for each LED (22.5 mA). // Max current for each LED (22.5 mA).
tm1814_strip->SetPixelSettings(NeoTm1814Settings(/*R*/225, /*G*/225, /*B*/225, /*W*/225)); 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) { static void begin(void* busPtr, uint8_t busType, uint8_t* pins, uint16_t clock_kHz = 0U) {
switch (busType) { switch (busType) {
case I_NONE: break; case I_NONE: break;
@ -390,7 +392,8 @@ class PolyBus {
case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->Begin(); break; case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->Begin(); break;
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->Begin(); break; case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->Begin(); break;
} }
}; }
static void* create(uint8_t busType, uint8_t* pins, uint16_t len, uint8_t channel, uint16_t clock_kHz = 0U) { static void* create(uint8_t busType, uint8_t* pins, uint16_t len, uint8_t channel, uint16_t clock_kHz = 0U) {
void* busPtr = nullptr; void* busPtr = nullptr;
switch (busType) { switch (busType) {
@ -491,7 +494,8 @@ class PolyBus {
} }
begin(busPtr, busType, pins, clock_kHz); begin(busPtr, busType, pins, clock_kHz);
return busPtr; return busPtr;
}; }
static void show(void* busPtr, uint8_t busType) { static void show(void* busPtr, uint8_t busType) {
switch (busType) { switch (busType) {
case I_NONE: break; case I_NONE: break;
@ -588,7 +592,8 @@ class PolyBus {
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->Show(); break; case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->Show(); break;
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->Show(); break; case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->Show(); break;
} }
}; }
static bool canShow(void* busPtr, uint8_t busType) { static bool canShow(void* busPtr, uint8_t busType) {
switch (busType) { switch (busType) {
case I_NONE: return true; case I_NONE: return true;
@ -685,7 +690,8 @@ class PolyBus {
case I_SS_P98_3: return (static_cast<B_SS_P98_3*>(busPtr))->CanShow(); break; case I_SS_P98_3: return (static_cast<B_SS_P98_3*>(busPtr))->CanShow(); break;
} }
return true; return true;
}; }
static void setPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint32_t c, uint8_t co) { static void setPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint32_t c, uint8_t co) {
uint8_t r = c >> 16; uint8_t r = c >> 16;
uint8_t g = c >> 8; uint8_t g = c >> 8;
@ -805,7 +811,8 @@ class PolyBus {
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break; case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->SetPixelColor(pix, RgbColor(col)); break;
} }
}; }
static void setBrightness(void* busPtr, uint8_t busType, uint8_t b) { static void setBrightness(void* busPtr, uint8_t busType, uint8_t b) {
switch (busType) { switch (busType) {
case I_NONE: break; case I_NONE: break;
@ -902,7 +909,106 @@ class PolyBus {
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->SetLuminance(b); break; case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->SetLuminance(b); break;
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->SetLuminance(b); break; case I_SS_P98_3: (static_cast<B_SS_P98_3*>(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<B_8266_U0_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U1_NEO_3: (static_cast<B_8266_U1_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_DM_NEO_3: (static_cast<B_8266_DM_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_BB_NEO_3: (static_cast<B_8266_BB_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U0_NEO_4: (static_cast<B_8266_U0_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U1_NEO_4: (static_cast<B_8266_U1_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_DM_NEO_4: (static_cast<B_8266_DM_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_BB_NEO_4: (static_cast<B_8266_BB_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U0_400_3: (static_cast<B_8266_U0_400_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U1_400_3: (static_cast<B_8266_U1_400_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_DM_400_3: (static_cast<B_8266_DM_400_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_BB_400_3: (static_cast<B_8266_BB_400_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U0_TM1_4: (static_cast<B_8266_U0_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U1_TM1_4: (static_cast<B_8266_U1_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_DM_TM1_4: (static_cast<B_8266_DM_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_BB_TM1_4: (static_cast<B_8266_BB_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U0_TM2_3: (static_cast<B_8266_U0_TM2_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U1_TM2_3: (static_cast<B_8266_U1_TM2_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_DM_TM2_3: (static_cast<B_8266_DM_TM2_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_BB_TM2_3: (static_cast<B_8266_BB_TM2_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U0_UCS_3: (static_cast<B_8266_U0_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U1_UCS_3: (static_cast<B_8266_U1_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_DM_UCS_3: (static_cast<B_8266_DM_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_BB_UCS_3: (static_cast<B_8266_BB_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U0_UCS_4: (static_cast<B_8266_U0_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_U1_UCS_4: (static_cast<B_8266_U1_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_DM_UCS_4: (static_cast<B_8266_DM_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_8266_BB_UCS_4: (static_cast<B_8266_BB_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
#endif
#ifdef ARDUINO_ARCH_ESP32
case I_32_RN_NEO_3: (static_cast<B_32_RN_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
#ifndef WLED_NO_I2S0_PIXELBUS
case I_32_I0_NEO_3: (static_cast<B_32_I0_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
case I_32_I1_NEO_3: (static_cast<B_32_I1_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
#endif
// case I_32_BB_NEO_3: (static_cast<B_32_BB_NEO_3*>(busPtr))->SetLuminance(b); (static_cast<B_32_BB_NEO_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_32_RN_NEO_4: (static_cast<B_32_RN_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
#ifndef WLED_NO_I2S0_PIXELBUS
case I_32_I0_NEO_4: (static_cast<B_32_I0_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
case I_32_I1_NEO_4: (static_cast<B_32_I1_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
#endif
// case I_32_BB_NEO_4: (static_cast<B_32_BB_NEO_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_32_RN_400_3: (static_cast<B_32_RN_400_3*>(busPtr))->ApplyPostAdjustments(); break;
#ifndef WLED_NO_I2S0_PIXELBUS
case I_32_I0_400_3: (static_cast<B_32_I0_400_3*>(busPtr))->ApplyPostAdjustments(); break;
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
case I_32_I1_400_3: (static_cast<B_32_I1_400_3*>(busPtr))->ApplyPostAdjustments(); break;
#endif
// case I_32_BB_400_3: (static_cast<B_32_BB_400_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_32_RN_TM1_4: (static_cast<B_32_RN_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_32_RN_TM2_3: (static_cast<B_32_RN_TM2_3*>(busPtr))->ApplyPostAdjustments(); break;
#ifndef WLED_NO_I2S0_PIXELBUS
case I_32_I0_TM1_4: (static_cast<B_32_I0_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_32_I0_TM2_3: (static_cast<B_32_I0_TM2_3*>(busPtr))->ApplyPostAdjustments(); break;
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
case I_32_I1_TM1_4: (static_cast<B_32_I1_TM1_4*>(busPtr))->ApplyPostAdjustments(); break;
case I_32_I1_TM2_3: (static_cast<B_32_I1_TM2_3*>(busPtr))->ApplyPostAdjustments(); break;
#endif
case I_32_RN_UCS_3: (static_cast<B_32_RN_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
#ifndef WLED_NO_I2S0_PIXELBUS
case I_32_I0_UCS_3: (static_cast<B_32_I0_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
case I_32_I1_UCS_3: (static_cast<B_32_I1_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
#endif
// case I_32_BB_UCS_3: (static_cast<B_32_BB_UCS_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_32_RN_UCS_4: (static_cast<B_32_RN_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
#ifndef WLED_NO_I2S0_PIXELBUS
case I_32_I0_UCS_4: (static_cast<B_32_I0_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
case I_32_I1_UCS_4: (static_cast<B_32_I1_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
#endif
// case I_32_BB_UCS_4: (static_cast<B_32_BB_UCS_4*>(busPtr))->ApplyPostAdjustments(); break;
#endif
case I_HS_DOT_3: (static_cast<B_HS_DOT_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_SS_DOT_3: (static_cast<B_SS_DOT_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_HS_LPD_3: (static_cast<B_HS_LPD_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_SS_LPD_3: (static_cast<B_SS_LPD_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_HS_LPO_3: (static_cast<B_HS_LPO_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_SS_LPO_3: (static_cast<B_SS_LPO_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_HS_WS1_3: (static_cast<B_HS_WS1_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_SS_WS1_3: (static_cast<B_SS_WS1_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_HS_P98_3: (static_cast<B_HS_P98_3*>(busPtr))->ApplyPostAdjustments(); break;
case I_SS_P98_3: (static_cast<B_SS_P98_3*>(busPtr))->ApplyPostAdjustments(); break;
}
}
static uint32_t getPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint8_t co) { static uint32_t getPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint8_t co) {
RgbwColor col(0,0,0,0); RgbwColor col(0,0,0,0);
switch (busType) { switch (busType) {

View File

@ -90,7 +90,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(strip.cctBlending, hw_led[F("cb")]); CJSON(strip.cctBlending, hw_led[F("cb")]);
Bus::setCCTBlend(strip.cctBlending); Bus::setCCTBlend(strip.cctBlending);
strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS 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 #ifndef WLED_DISABLE_2D
// 2D Matrix Settings // 2D Matrix Settings
@ -163,7 +163,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
if (fromFS) { if (fromFS) {
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz); BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz);
mem += BusManager::memUsage(bc); mem += BusManager::memUsage(bc);
if (strip.useGlobalLedBuffer && start + length > maxlen) { if (useGlobalLedBuffer && start + length > maxlen) {
maxlen = start + length; maxlen = start + length;
globalBufMem = maxlen * 4; globalBufMem = maxlen * 4;
} }
@ -711,7 +711,7 @@ void serializeConfig() {
hw_led[F("cb")] = strip.cctBlending; hw_led[F("cb")] = strip.cctBlending;
hw_led["fps"] = strip.getTargetFps(); hw_led["fps"] = strip.getTargetFps();
hw_led[F("rgbwm")] = Bus::getGlobalAWMode(); // global auto white mode override 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 #ifndef WLED_DISABLE_2D
// 2D Matrix Settings // 2D Matrix Settings

View File

@ -91,7 +91,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
Bus::setCCTBlend(strip.cctBlending); Bus::setCCTBlend(strip.cctBlending);
Bus::setGlobalAWMode(request->arg(F("AW")).toInt()); Bus::setGlobalAWMode(request->arg(F("AW")).toInt());
strip.setTargetFps(request->arg(F("FR")).toInt()); strip.setTargetFps(request->arg(F("FR")).toInt());
strip.useGlobalLedBuffer = request->hasArg(F("LD")); useGlobalLedBuffer = request->hasArg(F("LD"));
bool busesChanged = false; bool busesChanged = false;
for (uint8_t s = 0; s < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; s++) { for (uint8_t s = 0; s < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; s++) {

View File

@ -156,7 +156,7 @@ void WLED::loop()
for (uint8_t i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) { for (uint8_t i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) {
if (busConfigs[i] == nullptr) break; if (busConfigs[i] == nullptr) break;
mem += BusManager::memUsage(*busConfigs[i]); 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; maxlen = busConfigs[i]->start + busConfigs[i]->count;
globalBufMem = maxlen * 4; globalBufMem = maxlen * 4;
} }

View File

@ -8,7 +8,7 @@
*/ */
// version code in format yymmddb (b = daily build) // 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 //uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG //#define WLED_USE_MY_CONFIG
@ -332,9 +332,10 @@ WLED_GLOBAL byte bootPreset _INIT(0); // save preset to load
//if false, only one segment spanning the total LEDs is created, //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 //but not on LED settings save if there is more than one segment currently
WLED_GLOBAL bool autoSegments _INIT(false); 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 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 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 gammaCorrectCol _INIT(true); // use gamma correction on colors
WLED_GLOBAL bool gammaCorrectBri _INIT(false); // use gamma correction on brightness WLED_GLOBAL bool gammaCorrectBri _INIT(false); // use gamma correction on brightness
WLED_GLOBAL float gammaCorrectVal _INIT(2.8f); // gamma correction value WLED_GLOBAL float gammaCorrectVal _INIT(2.8f); // gamma correction value

View File

@ -404,7 +404,7 @@ void getSettingsJS(byte subPage, char* dest)
sappend('v',SET_F("CB"),strip.cctBlending); sappend('v',SET_F("CB"),strip.cctBlending);
sappend('v',SET_F("FR"),strip.getTargetFps()); sappend('v',SET_F("FR"),strip.getTargetFps());
sappend('v',SET_F("AW"),Bus::getGlobalAWMode()); 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++) { for (uint8_t s=0; s < busses.getNumBusses(); s++) {
Bus* bus = busses.getBus(s); Bus* bus = busses.getBus(s);