diff --git a/wled00/FX.h b/wled00/FX.h index 059bf820c..6b312a21a 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -677,6 +677,7 @@ class WS2812FX { // 96 bytes // true private variables _length(DEFAULT_LED_COUNT), _brightness(DEFAULT_BRIGHTNESS), + _renderBrightness(0), _transitionDur(750), _targetFps(WLED_FPS), _frametime(FRAMETIME_FIXED), @@ -875,7 +876,7 @@ class WS2812FX { // 96 bytes private: uint16_t _length; - uint8_t _brightness; + uint8_t _brightness, _renderBrightness; uint16_t _transitionDur; uint8_t _targetFps; @@ -906,7 +907,7 @@ class WS2812FX { // 96 bytes static uint32_t *_globalLedBuffer; // global leds[] array - void + uint8_t estimateCurrentAndLimitBri(void); }; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 181819e60..90a285546 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1102,8 +1102,12 @@ void WS2812FX::service() { // last condition ensures all solid segments are updated at the same time if(nowUp > seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC)) { - if (seg.grouping == 0) seg.grouping = 1; //sanity check - doShow = true; + 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 + doShow = true; + } uint16_t delay = FRAMETIME; if (!seg.freeze) { //only run effect function if not frozen @@ -1142,13 +1146,18 @@ void IRAM_ATTR WS2812FX::setPixelColor(int i, uint32_t col) { if (i < customMappingSize) i = customMappingTable[i]; if (i >= _length) return; - busses.setPixelColor(i, col); + if (_globalLedBuffer) { + _globalLedBuffer[i] = col; + } else { + 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); } @@ -1164,7 +1173,7 @@ uint32_t WS2812FX::getPixelColor(uint16_t i) #define MA_FOR_ESP 100 //how much mA does the ESP use (Wemos D1 about 80mA, ESP32 about 120mA) //you can set it to 0 if the ESP is powered by USB and the LEDs by external -void WS2812FX::estimateCurrentAndLimitBri() { +uint8_t WS2812FX::estimateCurrentAndLimitBri() { //power limit calculation //each LED can draw up 195075 "power units" (approx. 53mA) //one PU is the power it takes to have 1 channel 1 step brighter per brightness step @@ -1180,7 +1189,7 @@ void WS2812FX::estimateCurrentAndLimitBri() { if (ablMilliampsMax < 150 || actualMilliampsPerLed == 0) { //0 mA per LED and too low numbers turn off calculation currentMilliamps = 0; busses.setBrightness(_brightness); - return; + return _brightness; } uint16_t pLen = getLengthPhysical(); @@ -1219,13 +1228,14 @@ void WS2812FX::estimateCurrentAndLimitBri() { uint32_t powerSum0 = powerSum; powerSum *= _brightness; + uint8_t newBri = _brightness; 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; - uint8_t newBri = scale8(_brightness, scaleB); + newBri = scale8(_brightness, scaleB); busses.setBrightness(newBri); //to keep brightness uniform, sets virtual busses too currentMilliamps = (powerSum0 * newBri) / puPerMilliamp; } else { @@ -1234,6 +1244,7 @@ void WS2812FX::estimateCurrentAndLimitBri() { } currentMilliamps += MA_FOR_ESP; //add power of ESP back to estimate currentMilliamps += pLen; //add standby power back to estimate + return newBri; } void WS2812FX::show(void) { @@ -1242,7 +1253,16 @@ void WS2812FX::show(void) { show_callback callback = _callback; if (callback) callback(); - estimateCurrentAndLimitBri(); + 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]); + } 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)); // LOSSY and slow! + } + } // some buses send asynchronously and this method will return before // all of the data has been sent. @@ -1254,6 +1274,7 @@ void WS2812FX::show(void) { if (diff > 0) fpsCurr = 1000 / diff; _cumulativeFps = (3 * _cumulativeFps + fpsCurr) >> 2; _lastShow = now; + _renderBrightness = _brightness; } /** @@ -1321,6 +1342,7 @@ 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; } 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 diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 4b96060ef..729393cb6 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -172,7 +172,7 @@ uint32_t BusDigital::getPixelColor(uint16_t pix) { 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); + 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; @@ -180,7 +180,7 @@ uint32_t BusDigital::getPixelColor(uint16_t pix) { } return c; } - return PolyBus::getPixelColor(_busPtr, _iType, pix, co); + return restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, pix, co)); } uint8_t BusDigital::getPins(uint8_t* pinArray) { diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index b6d79d077..fd5d8651f 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -223,6 +223,18 @@ class BusDigital : public Bus { uint16_t _frequencykHz = 0U; void * _busPtr = nullptr; const ColorOrderMap &_colorOrderMap; + + inline uint32_t restoreColorLossy(uint32_t c) { + if (_bri == 255) return c; + uint8_t* chan = (uint8_t*) &c; + + for (uint8_t i=0; i<4; i++) + { + uint16_t val = chan[i]; + chan[i] = (val << 8) / (_bri + 1); + } + return c; + } }; diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index dce23478d..0314a793e 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -810,97 +810,97 @@ class PolyBus { switch (busType) { case I_NONE: break; #ifdef ESP8266 - case I_8266_U0_NEO_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_U1_NEO_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_DM_NEO_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_BB_NEO_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_U0_NEO_4: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_U1_NEO_4: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_DM_NEO_4: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_BB_NEO_4: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_U0_400_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_U1_400_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_DM_400_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_BB_400_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_U0_TM1_4: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_U1_TM1_4: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_DM_TM1_4: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_BB_TM1_4: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_U0_TM2_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_U1_TM2_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_DM_TM2_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_BB_TM2_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_U0_UCS_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_U1_UCS_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_DM_UCS_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_BB_UCS_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_U0_UCS_4: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_U1_UCS_4: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_DM_UCS_4: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_8266_BB_UCS_4: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_8266_U0_NEO_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_U1_NEO_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_DM_NEO_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_BB_NEO_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_U0_NEO_4: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_U1_NEO_4: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_DM_NEO_4: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_BB_NEO_4: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_U0_400_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_U1_400_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_DM_400_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_BB_400_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_U0_TM1_4: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_U1_TM1_4: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_DM_TM1_4: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_BB_TM1_4: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_U0_TM2_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_U1_TM2_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_DM_TM2_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_BB_TM2_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_U0_UCS_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_U1_UCS_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_DM_UCS_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_BB_UCS_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_U0_UCS_4: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_U1_UCS_4: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_DM_UCS_4: (static_cast(busPtr))->SetLuminance(b); break; + case I_8266_BB_UCS_4: (static_cast(busPtr))->SetLuminance(b); break; #endif #ifdef ARDUINO_ARCH_ESP32 - case I_32_RN_NEO_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_32_RN_NEO_3: (static_cast(busPtr))->SetLuminance(b); break; #ifndef WLED_NO_I2S0_PIXELBUS - case I_32_I0_NEO_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_32_I0_NEO_3: (static_cast(busPtr))->SetLuminance(b); break; #endif #ifndef WLED_NO_I2S1_PIXELBUS - case I_32_I1_NEO_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_32_I1_NEO_3: (static_cast(busPtr))->SetLuminance(b); 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))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; +// case I_32_BB_NEO_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_32_RN_NEO_4: (static_cast(busPtr))->SetLuminance(b); break; #ifndef WLED_NO_I2S0_PIXELBUS - case I_32_I0_NEO_4: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_32_I0_NEO_4: (static_cast(busPtr))->SetLuminance(b); break; #endif #ifndef WLED_NO_I2S1_PIXELBUS - case I_32_I1_NEO_4: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_32_I1_NEO_4: (static_cast(busPtr))->SetLuminance(b); break; #endif -// case I_32_BB_NEO_4: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_32_RN_400_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; +// case I_32_BB_NEO_4: (static_cast(busPtr))->SetLuminance(b); break; + case I_32_RN_400_3: (static_cast(busPtr))->SetLuminance(b); break; #ifndef WLED_NO_I2S0_PIXELBUS - case I_32_I0_400_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_32_I0_400_3: (static_cast(busPtr))->SetLuminance(b); break; #endif #ifndef WLED_NO_I2S1_PIXELBUS - case I_32_I1_400_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_32_I1_400_3: (static_cast(busPtr))->SetLuminance(b); break; #endif -// case I_32_BB_400_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_32_RN_TM1_4: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_32_RN_TM2_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; +// case I_32_BB_400_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_32_RN_TM1_4: (static_cast(busPtr))->SetLuminance(b); break; + case I_32_RN_TM2_3: (static_cast(busPtr))->SetLuminance(b); break; #ifndef WLED_NO_I2S0_PIXELBUS - case I_32_I0_TM1_4: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_32_I0_TM2_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_32_I0_TM1_4: (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I0_TM2_3: (static_cast(busPtr))->SetLuminance(b); break; #endif #ifndef WLED_NO_I2S1_PIXELBUS - case I_32_I1_TM1_4: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_32_I1_TM2_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_32_I1_TM1_4: (static_cast(busPtr))->SetLuminance(b); break; + case I_32_I1_TM2_3: (static_cast(busPtr))->SetLuminance(b); break; #endif - case I_32_RN_UCS_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_32_RN_UCS_3: (static_cast(busPtr))->SetLuminance(b); break; #ifndef WLED_NO_I2S0_PIXELBUS - case I_32_I0_UCS_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_32_I0_UCS_3: (static_cast(busPtr))->SetLuminance(b); break; #endif #ifndef WLED_NO_I2S1_PIXELBUS - case I_32_I1_UCS_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_32_I1_UCS_3: (static_cast(busPtr))->SetLuminance(b); break; #endif -// case I_32_BB_UCS_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_32_RN_UCS_4: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; +// case I_32_BB_UCS_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_32_RN_UCS_4: (static_cast(busPtr))->SetLuminance(b); break; #ifndef WLED_NO_I2S0_PIXELBUS - case I_32_I0_UCS_4: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_32_I0_UCS_4: (static_cast(busPtr))->SetLuminance(b); break; #endif #ifndef WLED_NO_I2S1_PIXELBUS - case I_32_I1_UCS_4: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_32_I1_UCS_4: (static_cast(busPtr))->SetLuminance(b); break; #endif -// case I_32_BB_UCS_4: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; +// case I_32_BB_UCS_4: (static_cast(busPtr))->SetLuminance(b); break; #endif - case I_HS_DOT_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_SS_DOT_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_HS_LPD_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_SS_LPD_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_HS_LPO_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_SS_LPO_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_HS_WS1_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_SS_WS1_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_HS_P98_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; - case I_SS_P98_3: (static_cast(busPtr))->SetLuminance(b); (static_cast(busPtr))->ApplyPostAdjustments(); break; + case I_HS_DOT_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_SS_DOT_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_HS_LPD_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_SS_LPD_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_HS_LPO_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_SS_LPO_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_HS_WS1_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_SS_WS1_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_HS_P98_3: (static_cast(busPtr))->SetLuminance(b); break; + case I_SS_P98_3: (static_cast(busPtr))->SetLuminance(b); break; } }; static uint32_t getPixelColor(void* busPtr, uint8_t busType, uint16_t pix, uint8_t co) { @@ -1209,4 +1209,4 @@ class PolyBus { } }; -#endif +#endif \ No newline at end of file