Memory management!

This commit is contained in:
Blaz Kristan 2022-08-03 21:36:47 +02:00
parent c5f3e76b21
commit d0a08a55d1
10 changed files with 295 additions and 334 deletions

File diff suppressed because it is too large Load Diff

View File

@ -245,58 +245,78 @@
#define FX_MODE_BLENDS 115
#define FX_MODE_TV_SIMULATOR 116
#define FX_MODE_DYNAMIC_SMOOTH 117
// new 2D effects
#define FX_MODE_2DSPACESHIPS 118
#define FX_MODE_2DCRAZYBEES 119
#define FX_MODE_2DGHOSTRIDER 120
#define FX_MODE_2DBLOBS 121
#define FX_MODE_2DSCROLLTEXT 122
#define FX_MODE_2DDRIFTROSE 123
// WLED-SR effects (non SR compatible IDs)
#define FX_MODE_2DBLACKHOLE 124 // non audio
#define FX_MODE_2DDNASPIRAL 125 // non audio
#define FX_MODE_2DHIPHOTIC 126 // non audio
#define FX_MODE_2DPLASMABALL 127 // non audio
#define FX_MODE_2DSINDOTS 128 // non audio
#define FX_MODE_2DFRIZZLES 129 // non audio
#define FX_MODE_2DLISSAJOUS 130 // non audio
#define FX_MODE_2DPOLARLIGHTS 131 // non audio
#define FX_MODE_2DTARTAN 132 // non audio
#define FX_MODE_2DGAMEOFLIFE 133 // non audio
#define FX_MODE_2DJULIA 134 // non audio
#define FX_MODE_2DCOLOREDBURSTS 135 // non audio
#define FX_MODE_2DSUNRADIATION 136 // non audio
#define FX_MODE_2DNOISE 137 // non audio
#define FX_MODE_2DFIRENOISE 138 // non audio
#define FX_MODE_2DSQUAREDSWIRL 139 // non audio
#define FX_MODE_2DDNA 140 // non audio
#define FX_MODE_2DMATRIX 141 // non audio
#define FX_MODE_2DMETABALLS 142 // non audio
#define FX_MODE_2DPULSER 143 // non audio
#define FX_MODE_2DDRIFT 144 // non audio
#define FX_MODE_2DWAVERLY 145 // audio enhanced
#define FX_MODE_2DSWIRL 146 // audio enhanced
#define FX_MODE_2DAKEMI 147 // audio enhanced
#define FX_MODE_PIXELWAVE 160 // audio enhanced
#define FX_MODE_JUGGLES 161 // audio enhanced
#define FX_MODE_MATRIPIX 162 // audio enhanced
#define FX_MODE_GRAVIMETER 163 // audio enhanced
#define FX_MODE_PLASMOID 164 // audio enhanced
#define FX_MODE_PUDDLES 165 // audio enhanced
#define FX_MODE_MIDNOISE 166 // audio enhanced
#define FX_MODE_NOISEMETER 167 // audio enhanced
#define FX_MODE_NOISEFIRE 168 // audio enhanced
#define FX_MODE_PUDDLEPEAK 169 // audio enhanced
#define FX_MODE_RIPPLEPEAK 170 // audio enhanced
#define FX_MODE_GRAVCENTER 171 // audio enhanced
#define FX_MODE_GRAVCENTRIC 172 // audio enhanced
#ifndef WLED_DISABLE_2D
// new 2D effects
#define FX_MODE_2DSPACESHIPS 118
#define FX_MODE_2DCRAZYBEES 119
#define FX_MODE_2DGHOSTRIDER 120
#define FX_MODE_2DBLOBS 121
#define FX_MODE_2DSCROLLTEXT 122
#define FX_MODE_2DDRIFTROSE 123
// WLED-SR effects (non SR compatible IDs)
#define FX_MODE_2DBLACKHOLE 124 // non audio
#define FX_MODE_2DDNASPIRAL 125 // non audio
#define FX_MODE_2DHIPHOTIC 126 // non audio
#define FX_MODE_2DPLASMABALL 127 // non audio
#define FX_MODE_2DSINDOTS 128 // non audio
#define FX_MODE_2DFRIZZLES 129 // non audio
#define FX_MODE_2DLISSAJOUS 130 // non audio
#define FX_MODE_2DPOLARLIGHTS 131 // non audio
#define FX_MODE_2DTARTAN 132 // non audio
#define FX_MODE_2DGAMEOFLIFE 133 // non audio
#define FX_MODE_2DJULIA 134 // non audio
#define FX_MODE_2DCOLOREDBURSTS 135 // non audio
#define FX_MODE_2DSUNRADIATION 136 // non audio
#define FX_MODE_2DNOISE 137 // non audio
#define FX_MODE_2DFIRENOISE 138 // non audio
#define FX_MODE_2DSQUAREDSWIRL 139 // non audio
#define FX_MODE_2DDNA 140 // non audio
#define FX_MODE_2DMATRIX 141 // non audio
#define FX_MODE_2DMETABALLS 142 // non audio
#define FX_MODE_2DPULSER 143 // non audio
#define FX_MODE_2DDRIFT 144 // non audio
#endif
#ifndef WLED_NO_AUDIO
#ifndef WLED_DISABLE_2D
#define FX_MODE_2DWAVERLY 145 // audio enhanced
#define FX_MODE_2DSWIRL 146 // audio enhanced
#define FX_MODE_2DAKEMI 147 // audio enhanced
#endif
#define FX_MODE_PIXELWAVE 160 // audio enhanced
#define FX_MODE_JUGGLES 161 // audio enhanced
#define FX_MODE_MATRIPIX 162 // audio enhanced
#define FX_MODE_GRAVIMETER 163 // audio enhanced
#define FX_MODE_PLASMOID 164 // audio enhanced
#define FX_MODE_PUDDLES 165 // audio enhanced
#define FX_MODE_MIDNOISE 166 // audio enhanced
#define FX_MODE_NOISEMETER 167 // audio enhanced
#define FX_MODE_NOISEFIRE 168 // audio enhanced
#define FX_MODE_PUDDLEPEAK 169 // audio enhanced
#define FX_MODE_RIPPLEPEAK 170 // audio enhanced
#define FX_MODE_GRAVCENTER 171 // audio enhanced
#define FX_MODE_GRAVCENTRIC 172 // audio enhanced
#endif
#ifndef USERMOD_AUDIOREACTIVE
#define MODE_COUNT 173
#ifndef WLED_NO_AUDIO
#define MODE_COUNT 173
#else
#ifndef WLED_DISABLE_2D
#define MODE_COUNT 145
#else
#define MODE_COUNT 118
#endif
#endif
#else
#ifdef WLED_DISABLE_2D
#error Audioreactive usermod requires 2D support.
#endif
#ifdef WLED_NO_AUDIO
#error Audioreactive usermod requires audio support.
#endif
#define FX_MODE_PIXELS 173
// #define FX_MODE_PIXELWAVE 129 // audio enhanced
// #define FX_MODE_JUGGLES 130 // audio enhanced
@ -488,13 +508,14 @@ typedef struct Segment {
Segment(Segment &&orig) noexcept; // move constructor
~Segment() {
if (leds) { free(leds); Serial.println(F("Freeing leds.")); }
#ifdef WLED_DEBUG
Serial.print(F("Destroying segment."));
Serial.print(F("Destroying segment:"));
if (name) Serial.printf(" %s (%p)", name, name);
if (data) Serial.printf(" %p", data);
if (data) Serial.printf(" %d (%p)", (int)_dataLen, data);
if (leds) Serial.printf(" [%u]", length()*sizeof(CRGB));
Serial.println();
#endif
if (leds) free(leds);
if (name) delete[] name;
if (_t) delete _t;
deallocateData();
@ -503,6 +524,10 @@ typedef struct Segment {
Segment& operator= (const Segment &orig); // copy assignment
Segment& operator= (Segment &&orig) noexcept; // move assignment
#ifdef WLED_DEBUG
size_t getSize() { return sizeof(Segment) + (data?_dataLen:0) + (name?strlen(name):0) + (_t?sizeof(Transition):0) + (leds?sizeof(CRGB)*length():0); }
#endif
inline bool getOption(uint8_t n) { return ((options >> n) & 0x01); }
inline bool isSelected(void) { return getOption(0); }
inline bool isActive(void) { return stop > start; }
@ -717,6 +742,9 @@ class WS2812FX { // 96 bytes
static WS2812FX* getInstance(void) { return instance; }
void
#ifdef WLED_DEBUG
printSize(),
#endif
finalizeInit(),
service(void),
setMode(uint8_t segid, uint8_t m),
@ -726,7 +754,7 @@ class WS2812FX { // 96 bytes
setBrightness(uint8_t b, bool direct = false),
setRange(uint16_t i, uint16_t i2, uint32_t col),
setTransitionMode(bool t),
purgeSegments(void),
purgeSegments(bool force = false),
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),
restartRuntime(),

View File

@ -766,7 +766,7 @@ uint8_t Segment::get_random_wheel_index(uint8_t pos) {
* @param pbri Value to scale the brightness of the returned color by. Default is 255. (no scaling)
* @returns Single color from palette
*/
uint32_t IRAM_ATTR Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri)
uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri)
{
// default palette or no RGB support on segment
if ((palette == 0 && mcol < NUM_COLORS) || !(_capabilities & 0x01)) {
@ -908,99 +908,16 @@ void WS2812FX::service() {
_isServicing = false;
}
void WS2812FX::setPixelColor(int i, uint32_t col)
void IRAM_ATTR WS2812FX::setPixelColor(int i, uint32_t col)
{
if (i >= _length) return;
// if realtime mode is active and applying to main segment
if (realtimeMode && useMainSegmentOnly) {
Segment &seg = _segments[_mainSegment];
uint16_t len = seg.length(); // length of segment in number of pixels
if (i >= seg.virtualLength()) return;
#ifndef WLED_DISABLE_2D
// adjust pixel index if within 2D segment
if (isMatrix) {
uint16_t vH = seg.virtualHeight(); // segment height in logical pixels
uint16_t vW = seg.virtualWidth();
switch (seg.map1D2D) {
case M12_Pixels:
// use all available pixels as a long strip
setPixelColorXY(seg.start + i % vW, seg.startY + i / vW, col);
break;
case M12_VerticalBar:
// expand 1D effect vertically
for (int y = 0; y < vH; y++) setPixelColorXY(seg.start + i, seg.startY + y, col);
break;
case M12_Circle:
// expand in circular fashion from center
for (float degrees = 0.0f; degrees <= 90.0f; degrees += 89.99f / (sqrtf((float)max(vH,vW))*i+1)) { // this may prove too many iterations on larger matrices
// may want to try float version as well (with or without antialiasing)
int x = roundf(sin_t(degrees*DEG_TO_RAD) * i);
int y = roundf(cos_t(degrees*DEG_TO_RAD) * i);
setPixelColorXY(seg.start + x, seg.startY + y, col);
}
break;
case M12_Block:
for (int x = 0; x <= i; x++) setPixelColorXY(seg.start + x, seg.startY + i, col);
for (int y = 0; y < i; y++) setPixelColorXY(seg.start + i, seg.startY + y, col);
break;
}
return;
}
#endif
if (seg.opacity < 255) {
byte r = scale8(R(col), seg.opacity);
byte g = scale8(G(col), seg.opacity);
byte b = scale8(B(col), seg.opacity);
byte w = scale8(W(col), seg.opacity);
col = RGBW32(r, g, b, w);
}
// get physical pixel address (taking into account start, grouping, spacing [and offset])
i = i * seg.groupLength();
if (seg.getOption(SEG_OPTION_REVERSED)) { // is segment reversed?
if (seg.getOption(SEG_OPTION_MIRROR)) { // is segment mirrored?
i = (len - 1) / 2 - i; //only need to index half the pixels
} else {
i = (len - 1) - i;
}
}
i += seg.start; // starting pixel in a group
// set all the pixels in the group
for (uint16_t j = 0; j < seg.grouping; j++) {
uint16_t indexSet = i + ((seg.getOption(SEG_OPTION_REVERSED)) ? -j : j);
if (indexSet >= seg.start && indexSet < seg.stop) {
if (seg.getOption(SEG_OPTION_MIRROR)) { //set the corresponding mirrored pixel
uint16_t indexMir = seg.stop - indexSet + seg.start - 1;
indexMir += seg.offset; // offset/phase
if (indexMir >= seg.stop) indexMir -= len; // wrap
if (indexMir < customMappingSize) indexMir = customMappingTable[indexMir];
busses.setPixelColor(indexMir, col);
}
indexSet += seg.offset; // offset/phase
if (indexSet >= seg.stop) indexSet -= len; // wrap
if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet];
busses.setPixelColor(indexSet, col);
}
}
} else {
if (i < customMappingSize) i = customMappingTable[i];
busses.setPixelColor(i, col);
}
if (i < customMappingSize) i = customMappingTable[i];
busses.setPixelColor(i, col);
}
uint32_t WS2812FX::getPixelColor(uint16_t i)
{
if (i >= _length) return 0;
//#ifndef WLED_DISABLE_2D
//if (isMatrix) return getPixelColorXY(i%matrixWidth, i/matrixWidth); // compatibility w/ non-effect fn
//#endif
if (i < customMappingSize) i = customMappingTable[i];
return busses.getPixelColor(i);
}
@ -1276,13 +1193,13 @@ bool WS2812FX::hasCCTBus(void) {
return false;
}
void WS2812FX::purgeSegments(void) {
void WS2812FX::purgeSegments(bool force) {
// remove all inactive segments (from the back)
int deleted = 0;
if (_segments.size() <= 1 || _isServicing) return;
if (_segments.size() <= 1) return;
for (int i = _segments.size()-1; i > 0; i--)
if (_segments[i].stop == 0) {
DEBUG_PRINT(F("-- Removing segment: ")); DEBUG_PRINTLN(i);
if (_segments[i].stop == 0 || force) {
DEBUG_PRINT(F("Purging segment segment: ")); DEBUG_PRINTLN(i);
deleted++;
_segments.erase(_segments.begin() + i);
}
@ -1535,6 +1452,18 @@ void WS2812FX::setTransitionMode(bool t)
// }
}
#ifdef WLED_DEBUG
void WS2812FX::printSize()
{
size_t size = 0;
for (Segment seg : _segments) size += seg.getSize();
DEBUG_PRINTF("Segments: %d -> %uB\n", sizeof(Segment), _segments.size(), size);
DEBUG_PRINTF("Modes: %d*%d=%uB\n", sizeof(mode_ptr), _mode.size(), (_mode.capacity()*sizeof(mode_ptr)));
DEBUG_PRINTF("Data: %d*%d=%uB\n", sizeof(const char *), _modeData.size(), (_modeData.capacity()*sizeof(const char *)));
DEBUG_PRINTF("Map: %d*%d=%uB\n", sizeof(uint16_t), (int)customMappingSize, customMappingSize*sizeof(uint16_t));
}
#endif
void WS2812FX::loadCustomPalettes()
{
byte tcp[72]; //support gradient palettes with up to 18 entries

View File

@ -7,7 +7,7 @@
/*
* color blend function
*/
uint32_t IRAM_ATTR color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) {
uint32_t color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) {
if(blend == 0) return color1;
uint16_t blendmax = b16 ? 0xFFFF : 0xFF;
if(blend == blendmax) return color2;

View File

@ -284,7 +284,7 @@ const uint8_t PAGE_liveviewws[] PROGMEM = {
// Autogenerated from wled00/data/liveviewws2D.htm, do not edit!!
const uint16_t PAGE_liveviewws2D_length = 878;
const uint8_t PAGE_liveviewws2D[] PROGMEM = {
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0a, 0x6d, 0x54, 0x6d, 0x73, 0xda, 0x46,
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x6d, 0x54, 0x6d, 0x73, 0xda, 0x46,
0x10, 0xfe, 0xce, 0xaf, 0x90, 0xaf, 0x69, 0xa2, 0x33, 0x42, 0xc2, 0xd8, 0x6e, 0x5d, 0xe0, 0xc8,
0x34, 0x0e, 0x33, 0xce, 0x8c, 0x13, 0x33, 0x83, 0x5b, 0xa6, 0xc3, 0x78, 0x26, 0x87, 0xb4, 0xa0,
0x6b, 0xa4, 0x3b, 0xe6, 0x6e, 0x41, 0xa6, 0x44, 0xff, 0xbd, 0x2b, 0x09, 0x13, 0xd2, 0x94, 0x0f,

View File

@ -927,8 +927,7 @@ void serializeNodes(JsonObject root)
void serializeModeData(JsonArray fxdata)
{
for (size_t i = 0; i < strip.getModeCount(); i++) {
//String lineBuffer = (const char*)pgm_read_dword(&(WS2812FX::_modeData[i]));
String lineBuffer = strip.getModeData(i);
String lineBuffer = FPSTR(strip.getModeData(i));
if (lineBuffer.length() > 0) {
uint8_t endPos = lineBuffer.indexOf('@');
if (endPos>0) fxdata.add(lineBuffer.substring(endPos));
@ -941,8 +940,7 @@ void serializeModeData(JsonArray fxdata)
// also removes WLED-SR extensions (@...) from deserialised names
void serializeModeNames(JsonArray arr) {
for (size_t i = 0; i < strip.getModeCount(); i++) {
//String lineBuffer = (const char*)pgm_read_dword(&(WS2812FX::_modeData[i]));
String lineBuffer = strip.getModeData(i);
String lineBuffer = FPSTR(strip.getModeData(i));
if (lineBuffer.length() > 0) {
uint8_t endPos = lineBuffer.indexOf('@');
if (endPos>0) arr.add(lineBuffer.substring(0, endPos));

View File

@ -155,7 +155,7 @@ void realtimeLock(uint32_t timeoutMs, byte md)
stop = strip.getLengthTotal();
}
// clear strip/segment
for (size_t i = start; i < stop; i++) strip.setPixelColor(i,0,0,0,0);
for (size_t i = start; i < stop; i++) strip.setPixelColor(i,BLACK);
// if WLED was off and using main segment only, freeze non-main segments so they stay off
if (useMainSegmentOnly && bri == 0) {
for (size_t s=0; s < strip.getSegmentsNum(); s++) {
@ -563,11 +563,16 @@ void handleNotifications()
void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w)
{
uint16_t pix = i + arlsOffset;
if (pix < strip.getLengthTotal())
{
if (!arlsDisableGammaCorrection && strip.gammaCorrectCol)
{
strip.setPixelColor(pix, gamma8(r), gamma8(g), gamma8(b), gamma8(w));
if (pix < strip.getLengthTotal()) {
if (!arlsDisableGammaCorrection && strip.gammaCorrectCol) {
r = gamma8(r);
g = gamma8(g);
b = gamma8(b);
w = gamma8(w);
}
if (useMainSegmentOnly) {
Segment &seg = strip.getMainSegment();
if (pix<seg.length()) seg.setPixelColor(pix, r, g, b, w);
} else {
strip.setPixelColor(pix, r, g, b, w);
}

View File

@ -286,7 +286,7 @@ uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxL
dest[0] = '\0'; // start by clearing buffer
if (mode < strip.getModeCount()) {
String lineBuffer = strip.getModeData(mode);
String lineBuffer = FPSTR(strip.getModeData(mode));
if (lineBuffer.length() > 0) {
int16_t start = lineBuffer.indexOf('@');
int16_t stop = lineBuffer.indexOf(';', start);
@ -356,7 +356,7 @@ uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxL
int16_t extractModeDefaults(uint8_t mode, const char *segVar)
{
if (mode < strip.getModeCount()) {
String lineBuffer = strip.getModeData(mode);
String lineBuffer = FPSTR(strip.getModeData(mode));
if (lineBuffer.length() > 0) {
int16_t start = lineBuffer.lastIndexOf(';');
if (start<0) return -1;

View File

@ -205,6 +205,7 @@ void WLED::loop()
DEBUG_PRINT(F("Loops/sec: ")); DEBUG_PRINTLN(loops / 30);
DEBUG_PRINT(F("UM time[ms]: ")); DEBUG_PRINT(avgUsermodMillis/loops); DEBUG_PRINT("/");DEBUG_PRINTLN(maxUsermodMillis);
DEBUG_PRINT(F("Strip time[ms]: ")); DEBUG_PRINT(avgStripMillis/loops); DEBUG_PRINT("/"); DEBUG_PRINTLN(maxStripMillis);
strip.printSize();
loops = 0;
maxUsermodMillis = 0;
maxStripMillis = 0;
@ -697,7 +698,7 @@ void WLED::handleConnection()
DEBUG_PRINT(F("Heap too low! "));
DEBUG_PRINTLN(heap);
forceReconnect = true;
strip.purgeSegments(); // remove inactive segments from memory
strip.purgeSegments(true); // remove all but one segments from memory
}
lastHeap = heap;
heapTime = now;

View File

@ -8,7 +8,7 @@
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2208031
#define VERSION 2208032
//uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG