Skip to content

Commit 8b2145b

Browse files
Add strip off refresh option in LED settings. (wled#2259)
* Add strip off refresh option in LED settings. New strip initialization logic. Minor code clen-up. * Dev code removal. * Missing ethernet include * Renamed mainseg to selseg * Fix for preset cycling bounds. * "Preset 0" bugfix. * Auto segments only if segments were not modified Co-authored-by: cschwinne <[email protected]>
1 parent b89f718 commit 8b2145b

File tree

13 files changed

+990
-952
lines changed

13 files changed

+990
-952
lines changed

wled00/FX.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ class WS2812FX {
619619
}
620620

621621
void
622-
finalizeInit(uint16_t countPixels),
622+
finalizeInit(),
623623
service(void),
624624
blur(uint8_t),
625625
fill(uint32_t),
@@ -636,7 +636,8 @@ class WS2812FX {
636636
trigger(void),
637637
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 0, uint8_t spacing = 0),
638638
resetSegments(),
639-
populateDefaultSegments(),
639+
makeAutoSegments(),
640+
fixInvalidSegments(),
640641
setPixelColor(uint16_t n, uint32_t c),
641642
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
642643
show(void),
@@ -650,6 +651,7 @@ class WS2812FX {
650651
gammaCorrectCol = true,
651652
applyToAllSelected = true,
652653
setEffectConfig(uint8_t m, uint8_t s, uint8_t i, uint8_t p),
654+
checkSegmentAlignment(void),
653655
// return true if the strip is being sent pixel updates
654656
isUpdating(void);
655657

wled00/FX_fcn.cpp

Lines changed: 83 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -65,25 +65,22 @@
6565
#endif
6666

6767
//do not call this method from system context (network callback)
68-
void WS2812FX::finalizeInit(uint16_t countPixels)
68+
void WS2812FX::finalizeInit(void)
6969
{
7070
RESET_RUNTIME;
71-
_length = countPixels;
71+
isRgbw = isOffRefreshRequred = false;
7272

73-
//if busses failed to load, add default (FS issue...)
73+
//if busses failed to load, add default (fresh install, FS issue, ...)
7474
if (busses.getNumBusses() == 0) {
7575
const uint8_t defDataPins[] = {DATA_PINS};
7676
const uint16_t defCounts[] = {PIXEL_COUNTS};
7777
const uint8_t defNumBusses = ((sizeof defDataPins) / (sizeof defDataPins[0]));
7878
const uint8_t defNumCounts = ((sizeof defCounts) / (sizeof defCounts[0]));
7979
uint16_t prevLen = 0;
80-
for (uint8_t i = 0; i < defNumBusses; i++) {
80+
for (uint8_t i = 0; i < defNumBusses && i < WLED_MAX_BUSSES; i++) {
8181
uint8_t defPin[] = {defDataPins[i]};
8282
uint16_t start = prevLen;
83-
uint16_t count = _length;
84-
if (defNumBusses > 1 && defNumCounts) {
85-
count = defCounts[(i < defNumCounts) ? i : defNumCounts -1];
86-
}
83+
uint16_t count = defCounts[(i < defNumCounts) ? i : defNumCounts -1];
8784
prevLen += count;
8885
BusConfig defCfg = BusConfig(DEFAULT_LED_TYPE, defPin, start, count, COL_ORDER_GRB);
8986
busses.add(defCfg);
@@ -92,60 +89,30 @@ void WS2812FX::finalizeInit(uint16_t countPixels)
9289

9390
deserializeMap();
9491

95-
uint16_t segStarts[MAX_NUM_SEGMENTS] = {0};
96-
uint16_t segStops [MAX_NUM_SEGMENTS] = {0};
97-
98-
setBrightness(_brightness);
99-
100-
//TODO make sure segments are only refreshed when bus config actually changed (new settings page)
101-
uint8_t s = 0;
102-
for (uint8_t i = 0; i < busses.getNumBusses(); i++) {
103-
Bus* b = busses.getBus(i);
104-
105-
if (autoSegments) { //make one segment per bus
106-
segStarts[s] = b->getStart();
107-
segStops[s] = segStarts[s] + b->getLength();
108-
109-
//check for overlap with previous segments
110-
for (uint8_t j = 0; j < s; j++) {
111-
if (segStops[j] > segStarts[s] && segStarts[j] < segStops[s]) {
112-
//segments overlap, merge
113-
segStarts[j] = min(segStarts[s],segStarts[j]);
114-
segStops [j] = max(segStops [s],segStops [j]); segStops[s] = 0;
115-
s--;
116-
}
117-
}
118-
s++;
119-
}
120-
92+
_length = 0;
93+
for (uint8_t i=0; i<busses.getNumBusses(); i++) {
94+
Bus *bus = busses.getBus(i);
95+
if (bus == nullptr) continue;
96+
if (bus->getStart() + bus->getLength() > MAX_LEDS) break;
97+
//RGBW mode is enabled if at least one of the strips is RGBW
98+
isRgbw |= bus->isRgbw();
99+
//refresh is required to remain off if at least one of the strips requires the refresh.
100+
isOffRefreshRequred |= bus->isOffRefreshRequired();
101+
uint16_t busEnd = bus->getStart() + bus->getLength();
102+
if (busEnd > _length) _length = busEnd;
121103
#ifdef ESP8266
122-
if ((!IS_DIGITAL(b->getType()) || IS_2PIN(b->getType()))) continue;
104+
if ((!IS_DIGITAL(bus->getType()) || IS_2PIN(bus->getType()))) continue;
123105
uint8_t pins[5];
124-
b->getPins(pins);
125-
BusDigital* bd = static_cast<BusDigital*>(b);
106+
if (!bus->getPins(pins)) continue;
107+
BusDigital* bd = static_cast<BusDigital*>(bus);
126108
if (pins[0] == 3) bd->reinit();
127109
#endif
128110
}
111+
ledCount = _length;
129112

130-
if (autoSegments) {
131-
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) {
132-
setSegment(i, segStarts[i], segStops[i]);
133-
}
134-
} else {
135-
//expand the main seg to the entire length, but only if there are no other segments
136-
uint8_t mainSeg = getMainSegmentId();
137-
138-
if (getActiveSegmentsNum() < 2) {
139-
setSegment(mainSeg, 0, _length);
140-
} else {
141-
//there are multiple segments, leave them, but prune length to total
142-
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
143-
{
144-
if (_segments[i].start >= _length) setSegment(i, 0, 0);
145-
if (_segments[i].stop > _length) setSegment(i, _segments[i].start, _length);
146-
}
147-
}
148-
}
113+
//segments are created in makeAutoSegments();
114+
115+
setBrightness(_brightness);
149116
}
150117

151118
void WS2812FX::service() {
@@ -654,23 +621,67 @@ void WS2812FX::resetSegments() {
654621
_segment_runtimes[0].reset();
655622
}
656623

657-
void WS2812FX::populateDefaultSegments() {
658-
uint16_t length = 0;
659-
for (uint8_t i=0; i<busses.getNumBusses(); i++) {
660-
Bus *bus = busses.getBus(i);
661-
if (bus == nullptr) continue;
662-
_segments[i].start = bus->getStart();
663-
length += bus->getLength();
664-
_segments[i].stop = _segments[i].start + bus->getLength();
665-
_segments[i].mode = DEFAULT_MODE;
666-
_segments[i].colors[0] = DEFAULT_COLOR;
667-
_segments[i].speed = DEFAULT_SPEED;
668-
_segments[i].intensity = DEFAULT_INTENSITY;
669-
_segments[i].grouping = 1;
670-
_segments[i].setOption(SEG_OPTION_SELECTED, 1);
671-
_segments[i].setOption(SEG_OPTION_ON, 1);
672-
_segments[i].opacity = 255;
624+
void WS2812FX::makeAutoSegments() {
625+
uint16_t segStarts[MAX_NUM_SEGMENTS] = {0};
626+
uint16_t segStops [MAX_NUM_SEGMENTS] = {0};
627+
628+
if (autoSegments) { //make one segment per bus
629+
uint8_t s = 0;
630+
for (uint8_t i = 0; i < busses.getNumBusses(); i++) {
631+
Bus* b = busses.getBus(i);
632+
633+
segStarts[s] = b->getStart();
634+
segStops[s] = segStarts[s] + b->getLength();
635+
636+
//check for overlap with previous segments
637+
for (uint8_t j = 0; j < s; j++) {
638+
if (segStops[j] > segStarts[s] && segStarts[j] < segStops[s]) {
639+
//segments overlap, merge
640+
segStarts[j] = min(segStarts[s],segStarts[j]);
641+
segStops [j] = max(segStops [s],segStops [j]); segStops[s] = 0;
642+
s--;
643+
}
644+
}
645+
s++;
646+
}
647+
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) {
648+
setSegment(i, segStarts[i], segStops[i]);
649+
}
650+
} else {
651+
//expand the main seg to the entire length, but only if there are no other segments
652+
uint8_t mainSeg = getMainSegmentId();
653+
654+
if (getActiveSegmentsNum() < 2) {
655+
setSegment(mainSeg, 0, _length);
656+
}
657+
}
658+
659+
fixInvalidSegments();
660+
}
661+
662+
void WS2812FX::fixInvalidSegments() {
663+
//make sure no segment is longer than total (sanity check)
664+
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
665+
{
666+
if (_segments[i].start >= _length) setSegment(i, 0, 0);
667+
if (_segments[i].stop > _length) setSegment(i, _segments[i].start, _length);
668+
}
669+
}
670+
671+
//true if all segments align with a bus, or if a segment covers the total length
672+
bool WS2812FX::checkSegmentAlignment() {
673+
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
674+
{
675+
if (_segments[i].start >= _segments[i].stop) continue; //inactive segment
676+
bool aligned = false;
677+
for (uint8_t b = 0; b<busses.getNumBusses(); b++) {
678+
Bus *bus = busses.getBus(b);
679+
if (_segments[i].start == bus->getStart() && _segments[i].stop == bus->getStart() + bus->getLength()) aligned = true;
680+
}
681+
if (_segments[i].start == 0 && _segments[i].stop == _length) aligned = true;
682+
if (!aligned) return false;
673683
}
684+
return true;
674685
}
675686

676687
//After this function is called, setPixelColor() will use that segment (offsets, grouping, ... will apply)

wled00/bus_manager.h

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
#define DEBUG_PRINTF(x...)
2525
#endif
2626

27+
#define GET_BIT(var,bit) (((var)>>(bit))&0x01)
28+
#define SET_BIT(var,bit) ((var)|=(uint16_t)(0x0001<<(bit)))
29+
#define UNSET_BIT(var,bit) ((var)&=(~(uint16_t)(0x0001<<(bit))))
30+
2731
//temporary struct for passing bus configuration to bus
2832
struct BusConfig {
2933
uint8_t type = TYPE_WS2812_RGB;
@@ -32,10 +36,12 @@ struct BusConfig {
3236
uint8_t colorOrder = COL_ORDER_GRB;
3337
bool reversed = false;
3438
uint8_t skipAmount;
39+
bool refreshReq;
3540
uint8_t pins[5] = {LEDPIN, 255, 255, 255, 255};
36-
BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false, uint8_t skip=0) {
37-
type = busType; count = len; start = pstart;
38-
colorOrder = pcolorOrder; reversed = rev; skipAmount = skip;
41+
BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false, uint8_t skip = 0) {
42+
refreshReq = (bool) GET_BIT(busType,7);
43+
type = busType & 0x7F; // bit 7 may be/is hacked to include refresh info (1=refresh in off state, 0=no refresh)
44+
count = len; start = pstart; colorOrder = pcolorOrder; reversed = rev; skipAmount = skip;
3945
uint8_t nPins = 1;
4046
if (type >= TYPE_NET_DDP_RGB && type < 96) nPins = 4; //virtual network bus. 4 "pins" store IP address
4147
else if (type > 47) nPins = 2;
@@ -120,13 +126,18 @@ class Bus {
120126
return false;
121127
}
122128

129+
inline bool isOffRefreshRequired() {
130+
return _needsRefresh;
131+
}
132+
123133
bool reversed = false;
124134

125135
protected:
126136
uint8_t _type = TYPE_NONE;
127137
uint8_t _bri = 255;
128138
uint16_t _start = 0;
129139
bool _valid = false;
140+
bool _needsRefresh = false;
130141
};
131142

132143

@@ -143,6 +154,7 @@ class BusDigital : public Bus {
143154
_pins[1] = bc.pins[1];
144155
}
145156
reversed = bc.reversed;
157+
_needsRefresh = bc.refreshReq || bc.type == TYPE_TM1814;
146158
_skip = bc.skipAmount; //sacrificial pixels
147159
_len = bc.count + _skip;
148160
_iType = PolyBus::getI(bc.type, _pins, nr);
@@ -204,7 +216,7 @@ class BusDigital : public Bus {
204216
}
205217

206218
inline bool isRgbw() {
207-
return (_type == TYPE_SK6812_RGBW || _type == TYPE_TM1814);
219+
return Bus::isRgbw(_type);
208220
}
209221

210222
inline uint8_t skippedLeds() {
@@ -216,7 +228,7 @@ class BusDigital : public Bus {
216228
}
217229

218230
void cleanup() {
219-
DEBUG_PRINTLN("Digital Cleanup");
231+
DEBUG_PRINTLN(F("Digital Cleanup."));
220232
PolyBus::cleanup(_busPtr, _iType);
221233
_iType = I_NONE;
222234
_valid = false;
@@ -326,7 +338,7 @@ class BusPwm : public Bus {
326338
}
327339

328340
bool isRgbw() {
329-
return (_type > TYPE_ONOFF && _type <= TYPE_ANALOG_5CH && _type != TYPE_ANALOG_3CH);
341+
return Bus::isRgbw(_type);
330342
}
331343

332344
inline void cleanup() {
@@ -481,7 +493,7 @@ class BusManager {
481493
static uint32_t memUsage(BusConfig &bc) {
482494
uint8_t type = bc.type;
483495
uint16_t len = bc.count;
484-
if (type < 32) {
496+
if (type > 15 && type < 32) {
485497
#ifdef ESP8266
486498
if (bc.pins[0] == 3) { //8266 DMA uses 5x the mem
487499
if (type > 29) return len*20; //RGBW
@@ -496,7 +508,7 @@ class BusManager {
496508
}
497509
if (type > 31 && type < 48) return 5;
498510
if (type == 44 || type == 45) return len*4; //RGBW
499-
return len*3;
511+
return len*3; //RGB
500512
}
501513

502514
int add(BusConfig &bc) {
@@ -513,7 +525,7 @@ class BusManager {
513525

514526
//do not call this method from system context (network callback)
515527
void removeAll() {
516-
//Serial.println("Removing all.");
528+
DEBUG_PRINTLN(F("Removing all."));
517529
//prevents crashes due to deleting busses while in use.
518530
while (!canAllShow()) yield();
519531
for (uint8_t i = 0; i < numBusses; i++) delete busses[i];
@@ -573,16 +585,6 @@ class BusManager {
573585
return len;
574586
}
575587

576-
// a workaround
577-
static inline bool isRgbw(uint8_t type) {
578-
return Bus::isRgbw(type);
579-
}
580-
581-
//Return true if the strip requires a refresh to stay off.
582-
static bool isOffRefreshRequred(uint8_t type) {
583-
return type == TYPE_TM1814;
584-
}
585-
586588
private:
587589
uint8_t numBusses = 0;
588590
Bus* busses[WLED_MAX_BUSSES];

0 commit comments

Comments
 (0)