diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 999684b1..aac0ac76 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -80,7 +80,10 @@ void WS2812FX::setUpMatrix() { if ((size > 0) && (customMappingTable == nullptr)) { // second try DEBUG_PRINTLN("setUpMatrix: trying to get fresh memory block."); customMappingTable = (uint16_t*) calloc(size, sizeof(uint16_t)); - if (customMappingTable == nullptr) USER_PRINTLN("setUpMatrix: alloc failed"); + if (customMappingTable == nullptr) { + USER_PRINTLN("setUpMatrix: alloc failed"); + errorFlag = ERR_LOW_MEM; // WLEDMM raise errorflag + } } if (customMappingTable != nullptr) customMappingTableSize = size; } @@ -159,6 +162,7 @@ void WS2812FX::setUpMatrix() { } else { // memory allocation error customMappingTableSize = 0; USER_PRINTLN(F("Ledmap alloc error.")); + errorFlag = ERR_LOW_MEM; // WLEDMM raise errorflag isMatrix = false; //WLEDMM does not like this done in teh background while end users are confused whats happened... panels = 0; panel.clear(); diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 12f81497..b9f02ac8 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -128,10 +128,13 @@ void Segment::allocLeds() { 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!!"); + if (ledsrgb == nullptr) { + USER_PRINTLN("allocLeds failed!!"); + errorFlag = ERR_LOW_MEM; // WLEDMM raise errorflag + } } else { - USER_PRINTF("reuse Leds %u from %u\n", size, ledsrgb?ledsrgbSize:0); + //USER_PRINTF("reuse Leds %u from %u\n", size, ledsrgb?ledsrgbSize:0); } } @@ -212,7 +215,11 @@ bool Segment::allocateData(size_t len) { //DEBUG_PRINTF("allocateData(%u) start %d, stop %d, vlen %d\n", len, start, stop, virtualLength()); deallocateData(); if (len == 0) return false; // nothing to do - if (Segment::getUsedSegmentData() + len > MAX_SEGMENT_DATA) return false; //not enough memory + if (Segment::getUsedSegmentData() + len > MAX_SEGMENT_DATA) { + //USER_PRINTF("Segment::allocateData: Segment data quota exceeded! used:%u request:%u max:%d\n", Segment::getUsedSegmentData(), len, MAX_SEGMENT_DATA); + if (len > 0) errorFlag = ERR_LOW_SEG_MEM; // WLEDMM raise errorflag + return false; //not enough memory + } // do not use SPI RAM on ESP32 since it is slow //#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) && defined(WLED_USE_PSRAM) //if (psramFound()) @@ -220,10 +227,17 @@ bool Segment::allocateData(size_t len) { //else //#endif data = (byte*) malloc(len); - if (!data) { _dataLen = 0; return false;} //allocation failed // WLEDMM reset dataLen + if (!data) { + _dataLen = 0; // WLEDMM reset dataLen + errorFlag = ERR_LOW_MEM; // WLEDMM raise errorflag + USER_PRINT(F("Segment::allocateData: FAILED to allocate ")); + USER_PRINT(len); USER_PRINTLN(F(" bytes.")); + return false; + } //allocation failed Segment::addUsedSegmentData(len); _dataLen = len; memset(data, 0, len); + if (errorFlag == ERR_LOW_SEG_MEM) errorFlag = ERR_NONE; // WLEDMM reset errorflag on success return true; } @@ -231,7 +245,7 @@ void Segment::deallocateData() { if (!data) {_dataLen = 0; return;} // WLEDMM reset dataLen free(data); data = nullptr; - //DEBUG_PRINTLN("deallocateData() called free()."); + //USER_PRINTF("Segment::deallocateData: free'd %d bytes.\n", _dataLen); Segment::addUsedSegmentData(-_dataLen); _dataLen = 0; } @@ -1656,6 +1670,7 @@ void WS2812FX::finalizeInit(void) //#endif if (arrSize > 0) Segment::_globalLeds = (CRGB*) malloc(arrSize); // WLEDMM avoid malloc(0) if ((Segment::_globalLeds != nullptr) && (arrSize > 0)) memset(Segment::_globalLeds, 0, arrSize); // WLEDMM avoid dereferencing nullptr + if ((Segment::_globalLeds == nullptr) && (arrSize > 0)) errorFlag = ERR_LOW_MEM; // WLEDMM raise errorflag } //segments are created in makeAutoSegments(); @@ -2403,7 +2418,10 @@ bool WS2812FX::deserializeMap(uint8_t n) { if ((size > 0) && (customMappingTable == nullptr)) { // second try DEBUG_PRINTLN("deserializeMap: trying to get fresh memory block."); customMappingTable = (uint16_t*) calloc(size, sizeof(uint16_t)); - if (customMappingTable == nullptr) DEBUG_PRINTLN("deserializeMap: alloc failed!"); + if (customMappingTable == nullptr) { + DEBUG_PRINTLN("deserializeMap: alloc failed!"); + errorFlag = ERR_LOW_MEM; // WLEDMM raise errorflag + } } if (customMappingTable != nullptr) customMappingTableSize = size; } diff --git a/wled00/const.h b/wled00/const.h index fa3ded65..2e155754 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -347,7 +347,9 @@ #define ERR_OVERTEMP 30 // An attached temperature sensor has measured above threshold temperature (not implemented) #define ERR_OVERCURRENT 31 // An attached current sensor has measured a current above the threshold (not implemented) #define ERR_UNDERVOLT 32 // An attached voltmeter has measured a voltage below the threshold (not implemented) -#define ERR_LOW_MEM 33 // low memory (RAM) +#define ERR_LOW_MEM 33 // WLEDMM: low memory (RAM) +#define ERR_LOW_SEG_MEM 34 // WLEDMM: low memory (segment data RAM) +#define ERR_LOW_WS_MEM 35 // WLEDMM: low memory (ws) // Timer mode types #define NL_MODE_SET 0 //After nightlight time elapsed, set to target brightness diff --git a/wled00/data/index.js b/wled00/data/index.js index 3ea998e3..2a4b51ba 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -1968,8 +1968,14 @@ function readState(s,command=false) errstr = "A filesystem error has occured."; break; case 33: - errstr = "Warning: Low Memory (RAM)."; - break; + errstr = "Low Memory (generic RAM)."; + break; + case 34: + errstr = "Low Memory (effect data)."; + break; + case 35: + errstr = "Low Memory (WS data)."; + break; } showToast('Error ' + s.error + ": " + errstr, true); } diff --git a/wled00/wled.h b/wled00/wled.h index 546a1c90..23321384 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2404091 +#define VERSION 2404161 // WLEDMM - you can check for this define in usermods, to only enabled WLEDMM specific code in the "right" fork. Its not defined in AC WLED. #define _MoonModules_WLED_ diff --git a/wled00/ws.cpp b/wled00/ws.cpp index be5e0687..351caad4 100644 --- a/wled00/ws.cpp +++ b/wled00/ws.cpp @@ -162,6 +162,7 @@ void sendDataWs(AsyncWebSocketClient * client) ws.closeAll(1013); //code 1013 = temporary overload, try again later ws.cleanupClients(0); //disconnect all clients to release memory ws._cleanBuffers(); + errorFlag = ERR_LOW_WS_MEM; return; //out of memory }