diff --git a/usermods/smartnest/usermod_smartnest.h b/usermods/smartnest/usermod_smartnest.h index 92d524c88a..9d21ef2e73 100644 --- a/usermods/smartnest/usermod_smartnest.h +++ b/usermods/smartnest/usermod_smartnest.h @@ -49,7 +49,7 @@ class Smartnest : public Usermod void setColor(int r, int g, int b) { - strip.setColor(0, r, g, b); + strip.getMainSegment().setColor(0, RGBW32(r, g, b, 0)); stateUpdated(CALL_MODE_DIRECT_CHANGE); char msg[18] {}; sprintf(msg, "rgb(%d,%d,%d)", r, g, b); diff --git a/wled00/FX.h b/wled00/FX.h index 065daa86d5..14c2681620 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -30,6 +30,7 @@ #include #include "const.h" +#include "bus_manager.h" #define FASTLED_INTERNAL //remove annoying pragma messages #define USE_GET_MILLISECOND_TIMER @@ -654,7 +655,7 @@ typedef struct Segment { void blurCol(int col, fract8 blur_amount, bool smear = false); void moveX(int delta, bool wrap = false); void moveY(int delta, bool wrap = false); - void move(uint8_t dir, uint8_t delta, bool wrap = false); + void move(unsigned dir, unsigned delta, bool wrap = false); void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false); inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) { drawCircle(cx, cy, radius, RGBW32(c.r,c.g,c.b,0), soft); } void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false); @@ -781,25 +782,22 @@ class WS2812FX { // 96 bytes #endif finalizeInit(), // initialises strip components service(), // executes effect functions when due and calls strip.show() - setMode(uint8_t segid, uint8_t m), // sets effect/mode for given segment (high level API) - setColor(uint8_t slot, uint32_t c), // sets color (in slot) for given segment (high level API) setCCT(uint16_t k), // sets global CCT (either in relative 0-255 value or in K) setBrightness(uint8_t b, bool direct = false), // sets strip brightness setRange(uint16_t i, uint16_t i2, uint32_t col), // used for clock overlay purgeSegments(), // removes inactive segments from RAM (may incure penalty and memory fragmentation but reduces vector footprint) setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 1, uint8_t spacing = 0, uint16_t offset = UINT16_MAX, uint16_t startY=0, uint16_t stopY=1), - setMainSegmentId(uint8_t n), + setMainSegmentId(unsigned n = 0), resetSegments(), // marks all segments for reset makeAutoSegments(bool forceReset = false), // will create segments based on configured outputs fixInvalidSegments(), // fixes incorrect segment configuration setPixelColor(unsigned n, uint32_t c), // paints absolute strip pixel with index n and color c show(), // initiates LED output - setTargetFps(uint8_t fps), + setTargetFps(unsigned fps), setupEffectData(); // add default effects to the list; defined in FX.cpp inline void restartRuntime() { for (Segment &seg : _segments) seg.markForReset(); } inline void setTransitionMode(bool t) { for (Segment &seg : _segments) seg.startTransition(t ? _transitionDur : 0); } - inline void setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setColor(slot, RGBW32(r,g,b,w)); } inline void setPixelColor(unsigned n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } inline void setPixelColor(unsigned n, CRGB c) { setPixelColor(n, c.red, c.green, c.blue); } inline void fill(uint32_t c) { for (unsigned i = 0; i < getLengthTotal(); i++) setPixelColor(i, c); } // fill whole strip with color (inline) @@ -815,9 +813,9 @@ class WS2812FX { // 96 bytes checkSegmentAlignment(), hasRGBWBus() const, hasCCTBus() const, - isUpdating() const, // return true if the strip is being sent pixel updates - deserializeMap(uint8_t n=0); + deserializeMap(unsigned n = 0); + inline bool isUpdating() const { return !BusManager::canAllShow(); } // return true if the strip is being sent pixel updates inline bool isServicing() const { return _isServicing; } // returns true if strip.service() is executing inline bool hasWhiteChannel() const { return _hasWhiteChannel; } // returns true if strip contains separate white chanel inline bool isOffRefreshRequired() const { return _isOffRefreshRequired; } // returns true if strip requires regular updates (i.e. TM1814 chipset) @@ -844,9 +842,9 @@ class WS2812FX { // 96 bytes uint16_t getLengthPhysical() const, - getLengthTotal() const, // will include virtual/nonexistent pixels in matrix - getFps() const; + getLengthTotal() const; // will include virtual/nonexistent pixels in matrix + inline uint16_t getFps() const { return (millis() - _lastShow > 2000) ? 0 : _cumulativeFps +1; } // Returns the refresh rate of the LED strip inline uint16_t getFrameTime() const { return _frametime; } // returns amount of time a frame should take (in ms) inline uint16_t getMinShowDelay() const { return MIN_SHOW_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant) inline uint16_t getLength() const { return _length; } // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H) @@ -859,15 +857,12 @@ class WS2812FX { // 96 bytes uint32_t now, timebase; uint32_t getPixelColor(unsigned) const; - inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call + inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call - const char * - getModeData(uint8_t id = 0) const { return (id && id<_modeCount) ? _modeData[id] : PSTR("Solid"); } + const char *getModeData(unsigned id = 0) const { return (id && id < _modeCount) ? _modeData[id] : PSTR("Solid"); } + inline const char **getModeDataSrc() { return &(_modeData[0]); } // vectors use arrays for underlying data - const char ** - getModeDataSrc() { return &(_modeData[0]); } // vectors use arrays for underlying data - - Segment& getSegment(uint8_t id); + Segment& getSegment(unsigned id); inline Segment& getFirstSelectedSeg() { return _segments[getFirstSelectedSegId()]; } // returns reference to first segment that is "selected" inline Segment& getMainSegment() { return _segments[getMainSegmentId()]; } // returns reference to main segment inline Segment* getSegments() { return &(_segments[0]); } // returns pointer to segment vector structure (warning: use carefully) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 8804cdbb63..9b39b4c8fc 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -499,7 +499,7 @@ void Segment::moveY(int delta, bool wrap) { // @param dir direction: 0=left, 1=left-up, 2=up, 3=right-up, 4=right, 5=right-down, 6=down, 7=left-down // @param delta number of pixels to move // @param wrap around -void Segment::move(uint8_t dir, uint8_t delta, bool wrap) { +void Segment::move(unsigned dir, unsigned delta, bool wrap) { if (delta==0) return; switch (dir) { case 0: moveX( delta, wrap); break; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 13e9e73bb9..7927269ed6 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1464,49 +1464,11 @@ void WS2812FX::show() { _lastShow = showNow; } -/** - * Returns a true value if any of the strips are still being updated. - * On some hardware (ESP32), strip updates are done asynchronously. - */ -bool WS2812FX::isUpdating() const { - return !BusManager::canAllShow(); -} - -/** - * Returns the refresh rate of the LED strip. Useful for finding out whether a given setup is fast enough. - * Only updates on show() or is set to 0 fps if last show is more than 2 secs ago, so accuracy varies - */ -uint16_t WS2812FX::getFps() const { - if (millis() - _lastShow > 2000) return 0; - return _cumulativeFps +1; -} - -void WS2812FX::setTargetFps(uint8_t fps) { +void WS2812FX::setTargetFps(unsigned fps) { if (fps > 0 && fps <= 120) _targetFps = fps; _frametime = 1000 / _targetFps; } -void WS2812FX::setMode(uint8_t segid, uint8_t m) { - if (segid >= _segments.size()) return; - - if (m >= getModeCount()) m = getModeCount() - 1; - - if (_segments[segid].mode != m) { - _segments[segid].setMode(m); // do not load defaults - } -} - -//applies to all active and selected segments -void WS2812FX::setColor(uint8_t slot, uint32_t c) { - if (slot >= NUM_COLORS) return; - - for (segment &seg : _segments) { - if (seg.isActive() && seg.isSelected()) { - seg.setColor(slot, c); - } - } -} - void WS2812FX::setCCT(uint16_t k) { for (segment &seg : _segments) { if (seg.isActive() && seg.isSelected()) { @@ -1553,7 +1515,7 @@ uint8_t WS2812FX::getFirstSelectedSegId() const { return getMainSegmentId(); } -void WS2812FX::setMainSegmentId(uint8_t n) { +void WS2812FX::setMainSegmentId(unsigned n) { _mainSegment = 0; if (n < _segments.size()) { _mainSegment = n; @@ -1629,7 +1591,7 @@ void WS2812FX::purgeSegments() { } } -Segment& WS2812FX::getSegment(uint8_t id) { +Segment& WS2812FX::getSegment(unsigned id) { return _segments[id >= _segments.size() ? getMainSegmentId() : id]; // vectors } @@ -1844,7 +1806,7 @@ void WS2812FX::loadCustomPalettes() { } //load custom mapping table from JSON file (called from finalizeInit() or deserializeState()) -bool WS2812FX::deserializeMap(uint8_t n) { +bool WS2812FX::deserializeMap(unsigned n) { // 2D support creates its own ledmap (on the fly) if a ledmap.json exists it will overwrite built one. char fileName[32]; diff --git a/wled00/alexa.cpp b/wled00/alexa.cpp index b108f294b3..81b9ec3469 100644 --- a/wled00/alexa.cpp +++ b/wled00/alexa.cpp @@ -126,10 +126,10 @@ void onAlexaChange(EspalexaDevice* dev) } else { colorKtoRGB(k, rgbw); } - strip.setColor(0, RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3])); + strip.getMainSegment().setColor(0, RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3])); } else { uint32_t color = dev->getRGB(); - strip.setColor(0, color); + strip.getMainSegment().setColor(0, color); } stateUpdated(CALL_MODE_ALEXA); } diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 1b324d7137..e25a068498 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -6,6 +6,7 @@ */ #include "const.h" +#include "pin_manager.h" #include //colors.cpp diff --git a/wled00/led.cpp b/wled00/led.cpp index 9de0495b45..5439fbb686 100644 --- a/wled00/led.cpp +++ b/wled00/led.cpp @@ -80,6 +80,7 @@ byte scaledBri(byte in) void applyBri() { if (!realtimeMode || !arlsForceMaxBri) { + //DEBUG_PRINTF_P(PSTR("Applying strip brightness: %d (%d,%d)\n"), (int)briT, (int)bri, (int)briOld); strip.setBrightness(scaledBri(briT)); } } @@ -144,7 +145,6 @@ void stateUpdated(byte callMode) { if (transitionActive) { briOld = briT; - tperLast = 0; } else strip.setTransitionMode(true); // force all segments to transition mode transitionActive = true; @@ -184,22 +184,21 @@ void handleTransitions() updateInterfaces(interfaceUpdateCallMode); if (transitionActive && strip.getTransition() > 0) { - float tper = (millis() - transitionStartTime)/(float)strip.getTransition(); - if (tper >= 1.0f) { + int ti = millis() - transitionStartTime; + int tr = strip.getTransition(); + if (ti/tr) { strip.setTransitionMode(false); // stop all transitions // restore (global) transition time if not called from UDP notifier or single/temporary transition from JSON (also playlist) if (jsonTransitionOnce) strip.setTransition(transitionDelay); transitionActive = false; jsonTransitionOnce = false; - tperLast = 0; applyFinalBri(); return; } - if (tper - tperLast < 0.004f) return; // less than 1 bit change (1/255) - tperLast = tper; - briT = briOld + ((bri - briOld) * tper); - - applyBri(); + byte briTO = briT; + int deltaBri = (int)bri - (int)briOld; + briT = briOld + (deltaBri * ti / tr); + if (briTO != briT) applyBri(); } } @@ -234,8 +233,8 @@ void handleNightlight() colNlT[1] = effectSpeed; colNlT[2] = effectPalette; - strip.setMode(strip.getFirstSelectedSegId(), FX_MODE_STATIC); // make sure seg runtime is reset if it was in sunrise mode - effectCurrent = FX_MODE_SUNRISE; + strip.getFirstSelectedSeg().setMode(FX_MODE_STATIC); // make sure seg runtime is reset if it was in sunrise mode + effectCurrent = FX_MODE_SUNRISE; // colorUpdated() will take care of assigning that to all selected segments effectSpeed = nightlightDelayMins; effectPalette = 0; if (effectSpeed > 60) effectSpeed = 60; //currently limited to 60 minutes diff --git a/wled00/set.cpp b/wled00/set.cpp index 9b7aa92a52..cf3a07dd02 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -837,8 +837,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) } // temporary values, write directly to segments, globals are updated by setValuesFromFirstSelectedSeg() - uint32_t col0 = selseg.colors[0]; - uint32_t col1 = selseg.colors[1]; + uint32_t col0 = selseg.colors[0]; + uint32_t col1 = selseg.colors[1]; + uint32_t col2 = selseg.colors[2]; byte colIn[4] = {R(col0), G(col0), B(col0), W(col0)}; byte colInSec[4] = {R(col1), G(col1), B(col1), W(col1)}; byte effectIn = selseg.mode; @@ -919,7 +920,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) //set brightness updateVal(req.c_str(), "&A=", &bri); - bool col0Changed = false, col1Changed = false; + bool col0Changed = false, col1Changed = false, col2Changed = false; //set colors col0Changed |= updateVal(req.c_str(), "&R=", &colIn[0]); col0Changed |= updateVal(req.c_str(), "&G=", &colIn[1]); @@ -976,7 +977,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) } //set color from HEX or 32bit DEC - byte tmpCol[4]; pos = req.indexOf(F("CL=")); if (pos > 0) { colorFromDecOrHexString(colIn, (char*)req.substring(pos + 3).c_str()); @@ -989,10 +989,11 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) } pos = req.indexOf(F("C3=")); if (pos > 0) { + byte tmpCol[4]; colorFromDecOrHexString(tmpCol, (char*)req.substring(pos + 3).c_str()); - uint32_t col2 = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]); + col2 = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]); selseg.setColor(2, col2); // defined above (SS= or main) - if (!singleSegment) strip.setColor(2, col2); // will set color to all active & selected segments + col2Changed = true; } //set to random hue SR=0->1st SR=1->2nd @@ -1003,29 +1004,22 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) col0Changed |= (!sec); col1Changed |= sec; } - //swap 2nd & 1st - pos = req.indexOf(F("SC")); - if (pos > 0) { - byte temp; - for (unsigned i=0; i<4; i++) { - temp = colIn[i]; - colIn[i] = colInSec[i]; - colInSec[i] = temp; - } - col0Changed = col1Changed = true; - } - // apply colors to selected segment, and all selected segments if applicable if (col0Changed) { - uint32_t colIn0 = RGBW32(colIn[0], colIn[1], colIn[2], colIn[3]); - selseg.setColor(0, colIn0); - if (!singleSegment) strip.setColor(0, colIn0); // will set color to all active & selected segments + col0 = RGBW32(colIn[0], colIn[1], colIn[2], colIn[3]); + selseg.setColor(0, col0); } if (col1Changed) { - uint32_t colIn1 = RGBW32(colInSec[0], colInSec[1], colInSec[2], colInSec[3]); - selseg.setColor(1, colIn1); - if (!singleSegment) strip.setColor(1, colIn1); // will set color to all active & selected segments + col1 = RGBW32(colInSec[0], colInSec[1], colInSec[2], colInSec[3]); + selseg.setColor(1, col1); + } + + //swap 2nd & 1st + pos = req.indexOf(F("SC")); + if (pos > 0) { + std::swap(col0,col1); + col0Changed = col1Changed = true; } bool fxModeChanged = false, speedChanged = false, intensityChanged = false, paletteChanged = false; @@ -1055,6 +1049,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) if (speedChanged) seg.speed = speedIn; if (intensityChanged) seg.intensity = intensityIn; if (paletteChanged) seg.setPalette(paletteIn); + if (col0Changed) seg.setColor(0, col0); + if (col1Changed) seg.setColor(1, col1); + if (col2Changed) seg.setColor(2, col2); if (custom1Changed) seg.custom1 = custom1In; if (custom2Changed) seg.custom2 = custom2In; if (custom3Changed) seg.custom3 = custom3In; diff --git a/wled00/udp.cpp b/wled00/udp.cpp index a615cefcba..0ff39f1109 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -234,12 +234,12 @@ void parseNotifyPacket(uint8_t *udpIn) { //apply colors from notification to main segment, only if not syncing full segments if ((receiveNotificationColor || !someSel) && (version < 11 || !receiveSegmentOptions)) { // primary color, only apply white if intented (version > 0) - strip.setColor(0, RGBW32(udpIn[3], udpIn[4], udpIn[5], (version > 0) ? udpIn[10] : 0)); + strip.getMainSegment().setColor(0, RGBW32(udpIn[3], udpIn[4], udpIn[5], (version > 0) ? udpIn[10] : 0)); if (version > 1) { - strip.setColor(1, RGBW32(udpIn[12], udpIn[13], udpIn[14], udpIn[15])); // secondary color + strip.getMainSegment().setColor(1, RGBW32(udpIn[12], udpIn[13], udpIn[14], udpIn[15])); // secondary color } if (version > 6) { - strip.setColor(2, RGBW32(udpIn[20], udpIn[21], udpIn[22], udpIn[23])); // tertiary color + strip.getMainSegment().setColor(2, RGBW32(udpIn[20], udpIn[21], udpIn[22], udpIn[23])); // tertiary color if (version > 9 && udpIn[37] < 255) { // valid CCT/Kelvin value unsigned cct = udpIn[38]; if (udpIn[37] > 0) { //Kelvin diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 39e0d250be..a80808a782 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -221,6 +221,7 @@ void WLED::loop() strip.finalizeInit(); // also loads default ledmap if present if (aligned) strip.makeAutoSegments(); else strip.fixInvalidSegments(); + BusManager::setBrightness(bri); // fix re-initialised bus' brightness doSerializeConfig = true; } if (loadLedmap >= 0) { @@ -571,10 +572,11 @@ void WLED::beginStrip() } else { // fix for #3196 if (bootPreset > 0) { - bool oldTransition = fadeTransition; // workaround if transitions are enabled - fadeTransition = false; // ignore transitions temporarily - strip.setColor(0, BLACK); // set all segments black - fadeTransition = oldTransition; // restore transitions + // set all segments black (no transition) + for (unsigned i = 0; i < strip.getSegmentsNum(); i++) { + Segment &seg = strip.getSegment(i); + if (seg.isActive()) seg.colors[0] = BLACK; + } col[0] = col[1] = col[2] = col[3] = 0; // needed for colorUpdated() } briLast = briS; bri = 0; diff --git a/wled00/wled.h b/wled00/wled.h index 052f29b29f..f8021e92b6 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -584,7 +584,6 @@ WLED_GLOBAL bool transitionActive _INIT(false); WLED_GLOBAL uint16_t transitionDelay _INIT(750); // global transition duration WLED_GLOBAL uint16_t transitionDelayDefault _INIT(750); // default transition time (stored in cfg.json) WLED_GLOBAL unsigned long transitionStartTime; -WLED_GLOBAL float tperLast _INIT(0.0f); // crossfade transition progress, 0.0f - 1.0f WLED_GLOBAL bool jsonTransitionOnce _INIT(false); // flag to override transitionDelay (playlist, JSON API: "live" & "seg":{"i"} & "tt") WLED_GLOBAL uint8_t randomPaletteChangeTime _INIT(5); // amount of time [s] between random palette changes (min: 1s, max: 255s) WLED_GLOBAL bool useHarmonicRandomPalette _INIT(true); // use *harmonic* random palette generation (nicer looking) or truly random