fix for random crashes on changing presets (UI)
Segments are created/deleted on-the-fly; it seems that "local leds" buffers did not follow properly. * revise segment copy/move constructors * de-optimize use of local leds (as they need to be re-allocated when segment size changes) * minor stability improvements
This commit is contained in:
@@ -92,7 +92,7 @@ CRGB *Segment::_globalLeds = nullptr;
|
||||
uint16_t Segment::maxWidth = DEFAULT_LED_COUNT;
|
||||
uint16_t Segment::maxHeight = 1;
|
||||
|
||||
// copy constructor
|
||||
// copy constructor - creates a new segment by copy from orig, but does not copy buffers. Does not modify orig!
|
||||
Segment::Segment(const Segment &orig) {
|
||||
USER_PRINTLN(F("-- Copy segment constructor --"));
|
||||
memcpy((void*)this, (void*)&orig, sizeof(Segment)); //WLEDMM copy to this
|
||||
@@ -100,11 +100,12 @@ Segment::Segment(const Segment &orig) {
|
||||
data = nullptr;
|
||||
_dataLen = 0;
|
||||
_t = nullptr;
|
||||
if (ledsrgb && !Segment::_globalLeds) ledsrgb = nullptr; //WLEDMM constructor so there was nothing. ledsrgb not freed as still used by orig!
|
||||
if (ledsrgb && !Segment::_globalLeds) {ledsrgb = nullptr; ledsrgbSize = 0;} // WLEDMM
|
||||
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._t) { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); }
|
||||
if (orig.ledsrgb && !Segment::_globalLeds) { allocLeds(); if (ledsrgb) memcpy(ledsrgb, orig.ledsrgb, sizeof(CRGB)*length()); }
|
||||
else markForReset(); // WLEDMM
|
||||
// if (orig.ledsrgb && !Segment::_globalLeds) { allocLeds(); if (ledsrgb) memcpy(ledsrgb, orig.ledsrgb, sizeof(CRGB)*length()); } // WLEDMM
|
||||
jMap = nullptr; //WLEDMM jMap
|
||||
}
|
||||
|
||||
@@ -120,16 +121,18 @@ void Segment::allocLeds() {
|
||||
} // softhack007 clean up buffer
|
||||
}
|
||||
if ((size > 0) && (!ledsrgb || size > ledsrgbSize)) { //softhack dont allocate zero bytes
|
||||
USER_PRINTF("allocLeds %u from %u\n", size, ledsrgb?ledsrgbSize:0);
|
||||
ledsrgb = (CRGB*)malloc(size);
|
||||
USER_PRINTF("allocLeds (%d,%d to %d,%d), %u from %u\n", start, startY, stop, stopY, size, ledsrgb?ledsrgbSize:0);
|
||||
if (ledsrgb) free(ledsrgb); // we need a bigger buffer, so free the old one first
|
||||
ledsrgb = (CRGB*)calloc(size, 1);
|
||||
ledsrgbSize = ledsrgb?size:0;
|
||||
if (ledsrgb == nullptr) USER_PRINTLN("allocLeds failed!!");
|
||||
}
|
||||
else {
|
||||
USER_PRINTF("reuse Leds %u from %u\n", size, ledsrgb?ledsrgbSize:0);
|
||||
}
|
||||
}
|
||||
|
||||
// move constructor
|
||||
// move constructor --> moves everything (including buffer) from orig to this
|
||||
Segment::Segment(Segment &&orig) noexcept {
|
||||
USER_PRINTLN(F("-- Move segment constructor --"));
|
||||
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
||||
@@ -137,21 +140,21 @@ Segment::Segment(Segment &&orig) noexcept {
|
||||
orig.data = nullptr;
|
||||
orig._dataLen = 0;
|
||||
orig._t = nullptr;
|
||||
orig.ledsrgb = nullptr; //WLEDMM: do not free as moved to here (constructor so there where no leds)
|
||||
orig.jMap = nullptr; //WLEDMM jMap
|
||||
orig.ledsrgb = nullptr; //WLEDMM
|
||||
orig.ledsrgbSize = 0; // WLEDMM
|
||||
orig.jMap = nullptr; //WLEDMM jMap
|
||||
}
|
||||
|
||||
// copy assignment
|
||||
// copy assignment --> overwrite segment withg orig - deletes old buffers in "this", but does not change orig!
|
||||
Segment& Segment::operator= (const Segment &orig) {
|
||||
USER_PRINTLN(F("-- Copying segment --"));
|
||||
USER_PRINTLN(F("-- Copy-assignment segment --"));
|
||||
if (this != &orig) {
|
||||
// clean destination
|
||||
if (name) delete[] name;
|
||||
if (_t) delete _t;
|
||||
// WLEDMM reuse leds instead of removing themn
|
||||
// if (ledsrgb && !Segment::_globalLeds) free(ledsrgb); //WLEDMM: nullify below!
|
||||
CRGB* oldLeds = ledsrgb;
|
||||
size_t oldLedsSize = ledsrgbSize;
|
||||
if (ledsrgb && !Segment::_globalLeds) free(ledsrgb);
|
||||
deallocateData();
|
||||
// copy source
|
||||
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
||||
@@ -160,20 +163,22 @@ Segment& Segment::operator= (const Segment &orig) {
|
||||
data = nullptr;
|
||||
_dataLen = 0;
|
||||
_t = nullptr;
|
||||
if (!Segment::_globalLeds) {ledsrgb = oldLeds; ledsrgbSize = oldLedsSize;};// WLEDMM reuse leds instead of ledsrgb = nullptr;
|
||||
//if (!Segment::_globalLeds) {ledsrgb = oldLeds; ledsrgbSize = oldLedsSize;}; // WLEDMM reuse leds instead of ledsrgb = nullptr;
|
||||
if (!Segment::_globalLeds) {ledsrgb = nullptr; ledsrgbSize = 0;}; // WLEDMM copy has no buffers (yet)
|
||||
// copy source data
|
||||
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._t) { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); }
|
||||
if (orig.ledsrgb && !Segment::_globalLeds) { allocLeds(); if (ledsrgb) memcpy(ledsrgb, orig.ledsrgb, sizeof(CRGB)*length()); }
|
||||
else markForReset(); // WLEDMM
|
||||
//if (orig.ledsrgb && !Segment::_globalLeds) { allocLeds(); if (ledsrgb) memcpy(ledsrgb, orig.ledsrgb, sizeof(CRGB)*length()); } // WLEDMM don't copy old buffer
|
||||
jMap = nullptr; //WLEDMM jMap
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// move assignment
|
||||
// move assignment --> moves everything (including buffers) from "orig" to "this"
|
||||
Segment& Segment::operator= (Segment &&orig) noexcept {
|
||||
USER_PRINTLN(F("-- Moving segment --"));
|
||||
USER_PRINTLN(F("-- Move-assignment segment --"));
|
||||
if (this != &orig) {
|
||||
if (name) delete[] name; // free old name
|
||||
deallocateData(); // free old runtime data
|
||||
@@ -185,13 +190,18 @@ Segment& Segment::operator= (Segment &&orig) noexcept {
|
||||
orig._dataLen = 0;
|
||||
orig._t = nullptr;
|
||||
orig.ledsrgb = nullptr; //WLEDMM: do not free as moved to here
|
||||
orig.ledsrgbSize = 0; //WLEDMM
|
||||
orig.jMap = nullptr; //WLEDMM jMap
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Segment::allocateData(size_t len) {
|
||||
if (data && _dataLen == len) return true; //already allocated
|
||||
if (data && _dataLen >= len) {
|
||||
if (call == 0) memset(data, 0, len); // WLEDMM: clear data when SEGENV.call==0
|
||||
return true; //already allocated
|
||||
}
|
||||
//DEBUG_PRINTF("allocateData(%u) start %d, stop %d, vlen %d\n", len, start, stop, virtualLength());
|
||||
deallocateData();
|
||||
if (Segment::getUsedSegmentData() + len > MAX_SEGMENT_DATA) return false; //not enough memory
|
||||
// do not use SPI RAM on ESP32 since it is slow
|
||||
@@ -201,7 +211,7 @@ bool Segment::allocateData(size_t len) {
|
||||
//else
|
||||
//#endif
|
||||
data = (byte*) malloc(len);
|
||||
if (!data) return false; //allocation failed
|
||||
if (!data) { _dataLen = 0; return false;} //allocation failed // WLEDMM reset dataLen
|
||||
Segment::addUsedSegmentData(len);
|
||||
_dataLen = len;
|
||||
memset(data, 0, len);
|
||||
@@ -209,9 +219,10 @@ bool Segment::allocateData(size_t len) {
|
||||
}
|
||||
|
||||
void Segment::deallocateData() {
|
||||
if (!data) return;
|
||||
if (!data) {_dataLen = 0; return;} // WLEDMM reset dataLen
|
||||
free(data);
|
||||
data = nullptr;
|
||||
//DEBUG_PRINTLN("deallocateData() called free().");
|
||||
Segment::addUsedSegmentData(-_dataLen);
|
||||
_dataLen = 0;
|
||||
}
|
||||
@@ -225,8 +236,7 @@ void Segment::deallocateData() {
|
||||
*/
|
||||
void Segment::resetIfRequired() {
|
||||
if (reset) {
|
||||
//WLEDMM no need to free leds as we will reuse them
|
||||
// if (ledsrgb && !Segment::_globalLeds) { free(ledsrgb); ledsrgb = nullptr; }
|
||||
if (ledsrgb && !Segment::_globalLeds) { free(ledsrgb); ledsrgb = nullptr; ledsrgbSize=0;} // WLEDMM segment has changed, so we need a fresh buffer.
|
||||
if (transitional && _t) { transitional = false; delete _t; _t = nullptr; }
|
||||
deallocateData();
|
||||
next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
|
||||
@@ -236,19 +246,22 @@ void Segment::resetIfRequired() {
|
||||
|
||||
void Segment::setUpLeds() {
|
||||
// deallocation happens in resetIfRequired() as it is called when segment changes or in destructor
|
||||
if (Segment::_globalLeds)
|
||||
if (Segment::_globalLeds) {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
ledsrgb = &Segment::_globalLeds[start + startY*Segment::maxWidth];
|
||||
ledsrgbSize = length() * sizeof(CRGB); // also set this when using global leds.
|
||||
//USER_PRINTF("\nsetUpLeds() Global LEDs: startX=%d stopx=%d startY=%d stopy=%d maxwidth=%d; length=%d, size=%d\n\n", start, stop, startY, stopY, Segment::maxWidth, length(), ledsrgbSize/3);
|
||||
#else
|
||||
leds = &Segment::_globalLeds[start];
|
||||
#endif
|
||||
else if ((ledsrgb == nullptr) && (length() > 0)) { //softhack007 quickfix - avoid malloc(0) which is undefined behaviour (should not happen, but i've seen it)
|
||||
} else if (length() > 0) { //WLEDMM we always want a new buffer //softhack007 quickfix - avoid malloc(0) which is undefined behaviour (should not happen, but i've seen it)
|
||||
//#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM)
|
||||
//if (psramFound())
|
||||
// ledsrgb = (CRGB*)ps_malloc(sizeof(CRGB)*length()); // softhack007 disabled; putting leds into psram leads to horrible slowdown on WROVER boards
|
||||
//else
|
||||
//#endif
|
||||
allocLeds(); //WLEDMM
|
||||
//USER_PRINTF("\nsetUpLeds() local LEDs: startX=%d stopx=%d startY=%d stopy=%d maxwidth=%d; length=%d, size=%d\n\n", start, stop, startY, stopY, Segment::maxWidth, length(), ledsrgbSize/3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,7 +469,7 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t
|
||||
&& (!grp || (grouping == grp && spacing == spc))
|
||||
&& (ofs == UINT16_MAX || ofs == offset)) return;
|
||||
|
||||
if (stop) fill(BLACK); //turn old segment range off
|
||||
if (stop>start) fill(BLACK); //turn old segment range off // WLEDMM stop > start
|
||||
if (i2 <= i1) { //disable segment
|
||||
stop = 0;
|
||||
markForReset();
|
||||
@@ -1049,8 +1062,9 @@ uint32_t Segment::getPixelColor(int i)
|
||||
i *= groupLength();
|
||||
i += start;
|
||||
/* offset/phase */
|
||||
i += offset;
|
||||
if (offset < INT16_MAX) i += offset; // WLEDMM
|
||||
if ((i >= stop) && (stop>0)) i -= length(); // WLEDMM avoid negative index (stop = 0 is a possible value)
|
||||
if (i<0) i=0; // WLEDMM just to be 100% sure
|
||||
return strip.getPixelColor(i);
|
||||
}
|
||||
|
||||
@@ -1540,7 +1554,7 @@ void WS2812FX::finalizeInit(void)
|
||||
//else
|
||||
//#endif
|
||||
if (arrSize > 0) Segment::_globalLeds = (CRGB*) malloc(arrSize); // WLEDMM avoid malloc(0)
|
||||
if (Segment::_globalLeds != nullptr) memset(Segment::_globalLeds, 0, arrSize); // WLEDMM avoid dereferencing nullptr
|
||||
if ((Segment::_globalLeds != nullptr) && (arrSize > 0)) memset(Segment::_globalLeds, 0, arrSize); // WLEDMM avoid dereferencing nullptr
|
||||
}
|
||||
|
||||
//segments are created in makeAutoSegments();
|
||||
@@ -1563,7 +1577,7 @@ void WS2812FX::waitUntilIdle(void) {
|
||||
delay(2); // Suspending for 1 tick (or more) gives other tasks a chance to run.
|
||||
//yield(); // seems to be a no-op on esp32
|
||||
} while (isServicing() && (millis() - waitStarted < MAX_IDLE_WAIT_MS));
|
||||
USER_PRINTF("strip.waitUntilIdle(): strip %sidle after %d ms. (task %s)\n", isServicing()?"not ":"", int(millis() - waitStarted), pcTaskGetTaskName(NULL));
|
||||
USER_PRINTF("strip.waitUntilIdle(): strip %sidle after %d ms. (task %s with prio=%d)\n", isServicing()?"not ":"", int(millis() - waitStarted), pcTaskGetTaskName(NULL), uxTaskPriorityGet(NULL));
|
||||
}
|
||||
return;
|
||||
#else
|
||||
@@ -1945,7 +1959,9 @@ void WS2812FX::purgeSegments(bool force) {
|
||||
}
|
||||
|
||||
Segment& WS2812FX::getSegment(uint8_t id) {
|
||||
return _segments[id >= _segments.size() ? getMainSegmentId() : id]; // vectors
|
||||
uint8_t mainSegID = getMainSegmentId();
|
||||
if (mainSegID >= _segments.size()) mainSegID=0; // WLEDMM fallback in case that getMainSegmentId() is invalid
|
||||
return _segments[id >= _segments.size() ? mainSegID : id]; // vectors
|
||||
}
|
||||
|
||||
void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing, uint16_t offset, uint16_t startY, uint16_t stopY) {
|
||||
|
||||
Reference in New Issue
Block a user