Clear spaced segment

- also wait for strip before updating segment
This commit is contained in:
Blaž Kristan 2024-12-31 17:31:34 +01:00
parent e16c4b8681
commit 249c124176
3 changed files with 97 additions and 68 deletions

View File

@ -596,6 +596,7 @@ typedef struct Segment {
[[gnu::hot]] uint32_t getPixelColor(int i) const; [[gnu::hot]] uint32_t getPixelColor(int i) const;
// 1D support functions (some implement 2D as well) // 1D support functions (some implement 2D as well)
void blur(uint8_t, bool smear = false); void blur(uint8_t, bool smear = false);
void clear();
void fill(uint32_t c); void fill(uint32_t c);
void fade_out(uint8_t r); void fade_out(uint8_t r);
void fadeToBlackBy(uint8_t fadeBy); void fadeToBlackBy(uint8_t fadeBy);

View File

@ -279,8 +279,7 @@ void Segment::startTransition(uint16_t dur) {
_t->_briT = on ? opacity : 0; _t->_briT = on ? opacity : 0;
_t->_cctT = cct; _t->_cctT = cct;
#ifndef WLED_DISABLE_MODE_BLEND #ifndef WLED_DISABLE_MODE_BLEND
if (modeBlending) { swapSegenv(_t->_segT); // copy runtime data to temporary
swapSegenv(_t->_segT);
_t->_modeT = mode; _t->_modeT = mode;
_t->_segT._dataLenT = 0; _t->_segT._dataLenT = 0;
_t->_segT._dataT = nullptr; _t->_segT._dataT = nullptr;
@ -291,10 +290,16 @@ void Segment::startTransition(uint16_t dur) {
memcpy(_t->_segT._dataT, data, _dataLen); memcpy(_t->_segT._dataT, data, _dataLen);
_t->_segT._dataLenT = _dataLen; _t->_segT._dataLenT = _dataLen;
} }
}
} else { } else {
for (size_t i=0; i<NUM_COLORS; i++) _t->_segT._colorT[i] = colors[i]; for (size_t i=0; i<NUM_COLORS; i++) _t->_segT._colorT[i] = colors[i];
} }
DEBUG_PRINTF_P(PSTR("-- pal: %d, bri: %d, C:[%08X,%08X,%08X], m: %d\n"),
(int)_t->_palTid,
(int)_t->_briT,
_t->_segT._colorT[0],
_t->_segT._colorT[1],
_t->_segT._colorT[2],
(int)_t->_modeT);
#else #else
for (size_t i=0; i<NUM_COLORS; i++) _t->_colorT[i] = colors[i]; for (size_t i=0; i<NUM_COLORS; i++) _t->_colorT[i] = colors[i];
#endif #endif
@ -462,13 +467,16 @@ void Segment::setGeometry(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, ui
#ifndef WLED_DISABLE_2D #ifndef WLED_DISABLE_2D
if (Segment::maxHeight>1) boundsUnchanged &= (startY == i1Y && stopY == i2Y); // 2D if (Segment::maxHeight>1) boundsUnchanged &= (startY == i1Y && stopY == i2Y); // 2D
#endif #endif
if (stop && (spc > 0 || m12 != map1D2D)) clear();
/*
if (boundsUnchanged if (boundsUnchanged
&& (!grp || (grouping == grp && spacing == spc)) && (!grp || (grouping == grp && spacing == spc))
&& (ofs == UINT16_MAX || ofs == offset)) return; && (m12 == map1D2D)
) return;
*/
stateChanged = true; // send UDP/WS broadcast stateChanged = true; // send UDP/WS broadcast
if (stop) fill(BLACK); // turn old segment range off (clears pixels if changing spacing)
if (grp) { // prevent assignment of 0 if (grp) { // prevent assignment of 0
grouping = grp; grouping = grp;
spacing = spc; spacing = spc;
@ -478,10 +486,7 @@ void Segment::setGeometry(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, ui
} }
if (ofs < UINT16_MAX) offset = ofs; if (ofs < UINT16_MAX) offset = ofs;
DEBUG_PRINT(F("setUp segment: ")); DEBUG_PRINT(i1); DEBUG_PRINTF_P(PSTR("Segment geometry: %d,%d -> %d,%d\n"), (int)i1, (int)i2, (int)i1Y, (int)i2Y);
DEBUG_PRINT(','); DEBUG_PRINT(i2);
DEBUG_PRINT(F(" -> ")); DEBUG_PRINT(i1Y);
DEBUG_PRINT(','); DEBUG_PRINTLN(i2Y);
markForReset(); markForReset();
if (boundsUnchanged) return; if (boundsUnchanged) return;
@ -1040,6 +1045,26 @@ void Segment::refreshLightCapabilities() {
_capabilities = capabilities; _capabilities = capabilities;
} }
/*
* Fills segment with black
*/
void Segment::clear() {
if (!isActive()) return; // not active
unsigned oldVW = _vWidth;
unsigned oldVH = _vHeight;
unsigned oldVL = _vLength;
unsigned oldSB = _segBri;
_vWidth = virtualWidth();
_vHeight = virtualHeight();
_vLength = virtualLength();
_segBri = currentBri();
fill(BLACK);
_vWidth = oldVW;
_vHeight = oldVH;
_vLength = oldVL;
_segBri = oldSB;
}
/* /*
* Fills segment with color * Fills segment with color
*/ */
@ -1364,7 +1389,7 @@ void WS2812FX::service() {
_segment_index = 0; _segment_index = 0;
for (segment &seg : _segments) { for (segment &seg : _segments) {
if (_suspend) return; // immediately stop processing segments if suspend requested during service() if (_suspend) break; // immediately stop processing segments if suspend requested during service()
// process transition (mode changes in the middle of transition) // process transition (mode changes in the middle of transition)
seg.handleTransition(); seg.handleTransition();
@ -1429,8 +1454,8 @@ void WS2812FX::service() {
if (doShow) { if (doShow) {
yield(); yield();
Segment::handleRandomPalette(); // slowly transition random palette; move it into for loop when each segment has individual random palette Segment::handleRandomPalette(); // slowly transition random palette; move it into for loop when each segment has individual random palette
show();
_lastServiceShow = nowUp; // update timestamp, for precise FPS control _lastServiceShow = nowUp; // update timestamp, for precise FPS control
if (!_suspend) show();
} }
#ifdef WLED_DEBUG #ifdef WLED_DEBUG
if ((_targetFps != FPS_UNLIMITED) && (millis() - nowUp > _frametime)) DEBUG_PRINTF_P(PSTR("Slow strip %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime); if ((_targetFps != FPS_UNLIMITED) && (millis() - nowUp > _frametime)) DEBUG_PRINTF_P(PSTR("Slow strip %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime);

View File

@ -96,11 +96,15 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
uint16_t of = seg.offset; uint16_t of = seg.offset;
uint8_t soundSim = elem["si"] | seg.soundSim; uint8_t soundSim = elem["si"] | seg.soundSim;
uint8_t map1D2D = elem["m12"] | seg.map1D2D; uint8_t map1D2D = elem["m12"] | seg.map1D2D;
uint8_t set = elem[F("set")] | seg.set;
if ((spc>0 && spc!=seg.spacing) || seg.map1D2D!=map1D2D) seg.fill(BLACK); // clear spacing gaps bool selected = getBoolVal(elem["sel"], seg.selected);
bool reverse = getBoolVal(elem["rev"], seg.reverse);
seg.map1D2D = constrain(map1D2D, 0, 7); bool mirror = getBoolVal(elem["mi"] , seg.mirror);
seg.soundSim = constrain(soundSim, 0, 3); #ifndef WLED_DISABLE_2D
bool reverse_y = getBoolVal(elem["rY"] , seg.reverse_y);
bool mirror_y = getBoolVal(elem["mY"] , seg.mirror_y);
bool transpose = getBoolVal(elem[F("tp")], seg.transpose);
#endif
uint8_t set = elem[F("set")] | seg.set; uint8_t set = elem[F("set")] | seg.set;
seg.set = constrain(set, 0, 3); seg.set = constrain(set, 0, 3);
@ -206,20 +210,16 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
} }
#endif #endif
//seg.map1D2D = constrain(map1D2D, 0, 7); // done in setGeometry()
seg.set = constrain(set, 0, 3);
seg.soundSim = constrain(soundSim, 0, 3);
seg.selected = selected;
seg.reverse = reverse;
seg.mirror = mirror;
#ifndef WLED_DISABLE_2D #ifndef WLED_DISABLE_2D
bool reverse = seg.reverse; seg.reverse_y = reverse_y;
bool mirror = seg.mirror; seg.mirror_y = mirror_y;
#endif seg.transpose = transpose;
seg.selected = getBoolVal(elem["sel"], seg.selected);
seg.reverse = getBoolVal(elem["rev"], seg.reverse);
seg.mirror = getBoolVal(elem["mi"] , seg.mirror);
#ifndef WLED_DISABLE_2D
bool reverse_y = seg.reverse_y;
bool mirror_y = seg.mirror_y;
seg.reverse_y = getBoolVal(elem["rY"] , seg.reverse_y);
seg.mirror_y = getBoolVal(elem["mY"] , seg.mirror_y);
seg.transpose = getBoolVal(elem[F("tp")], seg.transpose);
if (seg.is2D() && seg.map1D2D == M12_pArc && (reverse != seg.reverse || reverse_y != seg.reverse_y || mirror != seg.mirror || mirror_y != seg.mirror_y)) seg.fill(BLACK); // clear entire segment (in case of Arc 1D to 2D expansion)
#endif #endif
byte fx = seg.mode; byte fx = seg.mode;
@ -393,23 +393,25 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
int it = 0; int it = 0;
JsonVariant segVar = root["seg"]; JsonVariant segVar = root["seg"];
if (!segVar.isNull()) strip.suspend(); if (!segVar.isNull()) {
if (segVar.is<JsonObject>()) // we may be called during strip.service() so we must not modify segments while effects are executing
{ strip.suspend();
const unsigned long start = millis();
while (strip.isServicing() && millis() - start < strip.getFrameTime()) yield(); // wait until frame is over
#ifdef WLED_DEBUG
if (millis() - start > 0) DEBUG_PRINTLN(F("JSON: Waited for strip to finish servicing."));
#endif
if (segVar.is<JsonObject>()) {
int id = segVar["id"] | -1; int id = segVar["id"] | -1;
//if "seg" is not an array and ID not specified, apply to all selected/checked segments //if "seg" is not an array and ID not specified, apply to all selected/checked segments
if (id < 0) { if (id < 0) {
//apply all selected segments //apply all selected segments
//bool didSet = false;
for (size_t s = 0; s < strip.getSegmentsNum(); s++) { for (size_t s = 0; s < strip.getSegmentsNum(); s++) {
Segment &sg = strip.getSegment(s); Segment &sg = strip.getSegment(s);
if (sg.isActive() && sg.isSelected()) { if (sg.isActive() && sg.isSelected()) {
deserializeSegment(segVar, s, presetId); deserializeSegment(segVar, s, presetId);
//didSet = true;
} }
} }
//TODO: not sure if it is good idea to change first active but unselected segment
//if (!didSet) deserializeSegment(segVar, strip.getMainSegmentId(), presetId);
} else { } else {
deserializeSegment(segVar, id, presetId); //apply only the segment with the specified ID deserializeSegment(segVar, id, presetId); //apply only the segment with the specified ID
} }
@ -422,6 +424,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
if (strip.getSegmentsNum() > 3 && deleted >= strip.getSegmentsNum()/2U) strip.purgeSegments(); // batch deleting more than half segments if (strip.getSegmentsNum() > 3 && deleted >= strip.getSegmentsNum()/2U) strip.purgeSegments(); // batch deleting more than half segments
} }
strip.resume(); strip.resume();
}
UsermodManager::readFromJsonState(root); UsermodManager::readFromJsonState(root);