@@ -159,8 +159,16 @@ bool Segment::allocateData(size_t len) {
159159 return false ;
160160 }
161161 // prefer DRAM over SPI RAM on ESP32 since it is slow
162- if (data) data = (byte*)d_realloc (data, len);
163- else data = (byte*)d_malloc (len);
162+ if (data) {
163+ data = (byte*)d_realloc_malloc (data, len); // realloc with malloc fallback
164+ if (!data) {
165+ data = nullptr ;
166+ Segment::addUsedSegmentData (-_dataLen); // subtract original buffer size
167+ _dataLen = 0 ; // reset data length
168+ }
169+ }
170+ else data = (byte*)d_malloc (len);
171+
164172 if (data) {
165173 memset (data, 0 , len); // erase buffer
166174 Segment::addUsedSegmentData (len - _dataLen);
@@ -170,7 +178,6 @@ bool Segment::allocateData(size_t len) {
170178 }
171179 // allocation failed
172180 DEBUG_PRINTLN (F (" !!! Allocation failed. !!!" ));
173- Segment::addUsedSegmentData (-_dataLen); // subtract original buffer size
174181 errorFlag = ERR_NORAM;
175182 return false ;
176183}
@@ -449,8 +456,8 @@ void Segment::setGeometry(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, ui
449456 }
450457 // re-allocate FX render buffer
451458 if (length () != oldLength) {
452- if (pixels) pixels = static_cast < uint32_t *>( d_realloc (pixels, sizeof ( uint32_t ) * length ()));
453- else pixels = static_cast <uint32_t *>(d_malloc (sizeof (uint32_t ) * length ()));
459+ if (pixels) d_free ( pixels); // using realloc on large buffers can cause additional fragmentation instead of reducing it
460+ pixels = static_cast <uint32_t *>(d_malloc (sizeof (uint32_t ) * length ()));
454461 if (!pixels) {
455462 DEBUG_PRINTLN (F (" !!! Not enough RAM for pixel buffer !!!" ));
456463 errorFlag = ERR_NORAM_PX;
@@ -563,8 +570,8 @@ Segment &Segment::setName(const char *newName) {
563570 if (newName) {
564571 const int newLen = min (strlen (newName), (size_t )WLED_MAX_SEGNAME_LEN);
565572 if (newLen) {
566- if (name) name = static_cast < char *>( d_realloc ( name, newLen+ 1 ));
567- else name = static_cast <char *>(d_malloc (newLen+1 ));
573+ if (name) d_free ( name); // free old name
574+ name = static_cast <char *>(d_malloc (newLen+1 ));
568575 if (name) strlcpy (name, newName, newLen+1 );
569576 name[newLen] = 0 ;
570577 return *this ;
@@ -645,6 +652,14 @@ uint16_t Segment::virtualLength() const {
645652 return vLength;
646653}
647654
655+ #ifndef WLED_DISABLE_2D
656+ // maximum length of a mapped 1D segment, used in PS for buffer allocation
657+ uint16_t Segment::maxMappingLength () const {
658+ uint32_t vW = virtualWidth ();
659+ uint32_t vH = virtualHeight ();
660+ return max (sqrt32_bw (vH*vH + vW*vW), (uint32_t )getPinwheelLength (vW, vH)); // use diagonal
661+ }
662+ #endif
648663// pixel is clipped if it falls outside clipping range
649664// if clipping start > stop the clipping range is inverted
650665bool IRAM_ATTR_YN Segment::isPixelClipped (int i) const {
@@ -729,8 +744,8 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) const
729744 }
730745 break ;
731746 case M12_pCorner:
732- for (int x = 0 ; x <= i; x++) setPixelColorRaw ( XY ( x, i) , col);
733- for (int y = 0 ; y < i; y++) setPixelColorRaw ( XY ( i, y) , col);
747+ for (int x = 0 ; x <= i; x++) setPixelColorXY ( x, i, col); // note: <= to include i=0. Relies on overflow check in sPC()
748+ for (int y = 0 ; y < i; y++) setPixelColorXY ( i, y, col);
734749 break ;
735750 case M12_sPinwheel: {
736751 // Uses Bresenham's algorithm to place coordinates of two lines in arrays then draws between them
@@ -1139,21 +1154,27 @@ void WS2812FX::finalizeInit() {
11391154 #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
11401155 // determine if it is sensible to use parallel I2S outputs on ESP32 (i.e. more than 5 outputs = 1 I2S + 4 RMT)
11411156 unsigned maxLedsOnBus = 0 ;
1157+ unsigned busType = 0 ;
11421158 for (const auto &bus : busConfigs) {
11431159 if (Bus::isDigital (bus.type ) && !Bus::is2Pin (bus.type )) {
11441160 digitalCount++;
1161+ if (busType == 0 ) busType = bus.type ; // remember first bus type
1162+ if (busType != bus.type ) {
1163+ DEBUG_PRINTF_P (PSTR (" Mixed digital bus types detected! Forcing single I2S output.\n " ));
1164+ useParallelI2S = false ; // mixed bus types, no parallel I2S
1165+ }
11451166 if (bus.count > maxLedsOnBus) maxLedsOnBus = bus.count ;
11461167 }
11471168 }
11481169 DEBUG_PRINTF_P (PSTR (" Maximum LEDs on a bus: %u\n Digital buses: %u\n " ), maxLedsOnBus, digitalCount);
1149- // we may remove 300 LEDs per bus limit when NeoPixelBus is updated beyond 2.9.0
1150- if (maxLedsOnBus <= 300 && useParallelI2S) BusManager::useParallelOutput (); // must call before creating buses
1170+ // we may remove 600 LEDs per bus limit when NeoPixelBus is updated beyond 2.8.3
1171+ if (maxLedsOnBus <= 600 && useParallelI2S) BusManager::useParallelOutput (); // must call before creating buses
11511172 else useParallelI2S = false ; // enforce single I2S
1173+ digitalCount = 0 ;
11521174 #endif
11531175
11541176 // create buses/outputs
11551177 unsigned mem = 0 ;
1156- digitalCount = 0 ;
11571178 for (const auto &bus : busConfigs) {
11581179 mem += bus.memUsage (Bus::isDigital (bus.type ) && !Bus::is2Pin (bus.type ) ? digitalCount++ : 0 ); // includes global buffer
11591180 if (mem <= MAX_LED_MEMORY) {
@@ -1189,8 +1210,8 @@ void WS2812FX::finalizeInit() {
11891210 deserializeMap (); // (re)load default ledmap (will also setUpMatrix() if ledmap does not exist)
11901211
11911212 // allocate frame buffer after matrix has been set up (gaps!)
1192- if (_pixels) _pixels = static_cast < uint32_t *>( d_realloc (_pixels, getLengthTotal () * sizeof ( uint32_t )));
1193- else _pixels = static_cast <uint32_t *>(d_malloc (getLengthTotal () * sizeof (uint32_t )));
1213+ if (_pixels) d_free ( _pixels); // using realloc on large buffers can cause additional fragmentation instead of reducing it
1214+ _pixels = static_cast <uint32_t *>(d_malloc (getLengthTotal () * sizeof (uint32_t )));
11941215 DEBUG_PRINTF_P (PSTR (" strip buffer size: %uB\n " ), getLengthTotal () * sizeof (uint32_t ));
11951216
11961217 DEBUG_PRINTF_P (PSTR (" Heap after strip init: %uB\n " ), ESP.getFreeHeap ());
@@ -1677,7 +1698,7 @@ void WS2812FX::setTransitionMode(bool t) {
16771698
16781699// wait until frame is over (service() has finished or time for 1 frame has passed; yield() crashes on 8266)
16791700void WS2812FX::waitForIt () {
1680- unsigned long maxWait = millis () + getFrameTime ();
1701+ unsigned long maxWait = millis () + getFrameTime () + 100 ; // TODO: this needs a proper fix for timeout!
16811702 while (isServicing () && maxWait > millis ()) delay (1 );
16821703 #ifdef WLED_DEBUG
16831704 if (millis () >= maxWait) DEBUG_PRINTLN (F (" Waited for strip to finish servicing." ));
0 commit comments