From e1f14628b03ff21623a149251246b759c823099e Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 2 Feb 2023 18:37:13 +0100 Subject: [PATCH] 4LD + rotary hotfix: corrupted display on esp32 This s a temporary fix for display problems (corrupted display, sometimes crash). These problems exists since 0.14. as display updates are now running in a separate task. The fix is still incomplete. If nothing else works, you can use the 0.13.x behavior by compiling with `-D FLD_ESP32_NO_THREADS` * fixing a few unsafe string operations and non-initialized strings * fix max length for "two lines" names * make sure that display methods are exiting early if display is not configured * rotary_ALT : additional checks to ensure that drawing on the display does not overlap with redraw * added some safeguards to prevent overlapping display redraw operations --> Actually this should use semaphore/mutex instead of global booleans -> Still on my toDo list. --- .../usermod_v2_four_line_display_ALT.h | 158 +++++++++++++----- .../usermod_v2_rotary_encoder_ui_ALT.h | 19 ++- wled00/wled.h | 2 +- wled00/wled_serial.cpp | 1 + 4 files changed, 134 insertions(+), 46 deletions(-) diff --git a/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h b/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h index 6747c80e..ebe066c3 100644 --- a/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h +++ b/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h @@ -9,6 +9,10 @@ #include // from https://github.com/olikraus/u8g2/ #include "4LD_wled_fonts.c" +#ifndef FLD_ESP32_NO_THREADS +#define FLD_ESP32_USE_THREADS // comment out to use 0.13.x behviour without parallel update task - slower, but more robust. May delay other tasks like LEDs or audioreactive!! +#endif + // // Insired by the usermod_v2_four_line_display // @@ -103,7 +107,8 @@ class FourLineDisplayUsermod : public Usermod { static FourLineDisplayUsermod *instance; bool initDone = false; - volatile bool drawing = false; + volatile bool drawing = false; // true of overlay drawing is active + volatile bool reDrawing = false; // true if redraw ongoing (on esp32, this happens in a separate task) char errorMessage[100] = ""; //WLEDMM: show error in um settings if occurred @@ -119,7 +124,7 @@ class FourLineDisplayUsermod : public Usermod { #endif DisplayType type = FLD_TYPE; // display type - bool typeOK = true; //WLEDMM: instead of type == NULL and type=NULL + bool typeOK = false; //WLEDMM: instead of type == NULL and type=NULL. Intially false, as display was not initialized yet bool flip = false; // flip display 180° uint8_t contrast = 10; // screen contrast uint8_t lineHeight = 1; // 1 row or 2 rows @@ -187,6 +192,9 @@ class FourLineDisplayUsermod : public Usermod { // some displays need this to properly apply contrast void setVcomh(bool highContrast) { + if (!typeOK || !enabled) return; // WLEDMM make sure the display is initialized before we try to draw on it + if (!canDraw()) return; // don't interfere with ongoing draw + u8x8_t *u8x8_struct = u8x8->getU8x8(); u8x8_cad_StartTransfer(u8x8_struct); u8x8_cad_SendCmd(u8x8_struct, 0x0db); //address of value @@ -198,17 +206,17 @@ class FourLineDisplayUsermod : public Usermod { * Wrappers for screen drawing */ void setFlipMode(uint8_t mode) { - if (!typeOK || !enabled) return; - u8x8->setFlipMode(mode); + if (!typeOK || !enabled) return; // WLEDMM make sure the display is initialized before we try to draw on it + if (canDraw()) u8x8->setFlipMode(mode); } void setContrast(uint8_t contrast) { - if (!typeOK || !enabled) return; - u8x8->setContrast(contrast); + if (!typeOK || !enabled) return; // WLEDMM make sure the display is initialized before we try to draw on it + if (canDraw()) u8x8->setContrast(contrast); } void drawString(uint8_t col, uint8_t row, const char *string, bool ignoreLH=false) { - if (!typeOK || !enabled) return; - u8x8->setFont(u8x8_font_chroma48medium8_r); - if (!ignoreLH && lineHeight==2) u8x8->draw1x2String(col, row, string); + if (!typeOK || !enabled) return; // WLEDMM make sure the display is initialized before we try to draw on it + u8x8->setFont(u8x8_font_chroma48medium8_r); // crashes randomly on ESP32 + if (!ignoreLH && lineHeight==2) u8x8->draw1x2String(col, row, string); // crashes randomly on ESP32 else u8x8->drawString(col, row, string); } void draw2x2String(uint8_t col, uint8_t row, const char *string) { @@ -233,10 +241,11 @@ class FourLineDisplayUsermod : public Usermod { } void clear() { if (!typeOK || !enabled) return; - u8x8->clear(); + if (nullptr == u8x8) return; // prevents some crashes + u8x8->clear(); // crashes randomly on ESP32 } void setPowerSave(uint8_t save) { - if (!typeOK || !enabled) return; + if (!typeOK || !enabled) return; // WLEDMM make sure the display is initialized before we try to draw on it u8x8->setPowerSave(save); } @@ -247,6 +256,7 @@ class FourLineDisplayUsermod : public Usermod { } void draw2x2GlyphIcons() { + if (!typeOK || !enabled) return; // WLEDMM make sure the display is initialized before we try to draw on it if (lineHeight == 2) { drawGlyph( 1, 0, 1, u8x8_4LineDisplay_WLED_icons_2x2, true); //brightness icon drawGlyph( 5, 0, 2, u8x8_4LineDisplay_WLED_icons_2x2, true); //speed icon @@ -274,7 +284,7 @@ class FourLineDisplayUsermod : public Usermod { while (drawing && millis()-now < 250) delay(1); // wait if someone else is drawing drawing = true; - char lineBuffer[LINE_BUFFER_SIZE]; + char lineBuffer[LINE_BUFFER_SIZE] = { '\0' }; static byte lastSecond; byte secondCurrent = second(localTime); byte minuteCurrent = minute(localTime); @@ -290,10 +300,10 @@ class FourLineDisplayUsermod : public Usermod { } if (knownHour != hourCurrent) { // only update date when hour changes - sprintf_P(lineBuffer, PSTR("%s %2d "), monthShortStr(month(localTime)), day(localTime)); + snprintf_P(lineBuffer, LINE_BUFFER_SIZE, PSTR("%s %2d "), monthShortStr(month(localTime)), day(localTime)); draw2x2String(2, lineHeight==1 ? 0 : lineHeight, lineBuffer); // adjust for 8 line displays, draw month and day } - sprintf_P(lineBuffer,PSTR("%2d:%02d"), (useAMPM ? AmPmHour : hourCurrent), minuteCurrent); + snprintf_P(lineBuffer,LINE_BUFFER_SIZE, PSTR("%2d:%02d"), (useAMPM ? AmPmHour : hourCurrent), minuteCurrent); draw2x2String(2, lineHeight*2, lineBuffer); //draw hour, min. blink ":" depending on odd/even seconds if (useAMPM) drawString(12, lineHeight*2, (isitAM ? "AM" : "PM"), true); //draw am/pm if using 12 time @@ -305,7 +315,7 @@ class FourLineDisplayUsermod : public Usermod { if (showSeconds && secondCurrent != lastSecond) { lastSecond = secondCurrent; draw2x2String(6, lineHeight*2, secondCurrent%2 ? " " : ":"); - sprintf_P(lineBuffer, PSTR("%02d"), secondCurrent); + snprintf_P(lineBuffer, LINE_BUFFER_SIZE, PSTR("%02d"), secondCurrent); drawString(12, lineHeight*2+1, lineBuffer, true); // even with double sized rows print seconds in 1 line } drawing = false; @@ -316,7 +326,7 @@ class FourLineDisplayUsermod : public Usermod { // gets called once at boot. Do all initialization that doesn't depend on // network here void setup() { - if (!typeOK || !enabled) return; + if (!enabled) return; // typeOK = true will be set after successfull setup bool isHW, isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64); PinOwner po = PinOwner::UM_FourLineDisplay; @@ -439,9 +449,16 @@ class FourLineDisplayUsermod : public Usermod { } lineHeight = u8x8->getRows() > 4 ? 2 : 1; - USER_PRINTLN(F("Starting display.")); + if (isSPI) { + USER_PRINTLN(isHW ? F("Starting display (SPI HW).") : F("Starting display (SPI Soft).")); + } else { + USER_PRINTLN(isHW ? F("Starting display (I2C HW).") : F("Starting display (I2C Soft).")); + } u8x8->setBusClock(ioFrequency); // can be used for SPI too u8x8->begin(); + typeOK = true; + drawing = false; + reDrawing = false; setFlipMode(flip); setVcomh(contrastFix); setContrast(contrast); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255 @@ -464,12 +481,17 @@ class FourLineDisplayUsermod : public Usermod { * Da loop. */ void loop() { - #ifndef ARDUINO_ARCH_ESP32 - if (!enabled || !typeOK || strip.isUpdating()) return; + #if !defined(ARDUINO_ARCH_ESP32) || !defined(FLD_ESP32_USE_THREADS) + static unsigned long lastRunTime = 0; unsigned long now = millis(); + if (!enabled || !typeOK || (strip.isUpdating() && (now - lastRunTime < 50))) return; + lastRunTime = now; + if (now < nextUpdate) return; nextUpdate = now + ((displayTurnedOff && clockMode && showSeconds) ? 1000 : refreshRate); + reDrawing = true; redraw(false); + reDrawing = false; #endif } @@ -478,15 +500,47 @@ class FourLineDisplayUsermod : public Usermod { lastRedraw = millis(); } + //function to to check if a redraw or overlay draw is active. Needed for UM Rotary, to avoid random/concurrent drawing + bool canDraw(void) { + #if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS) // only necessary on ESP32 + if (drawing) return(false); // overlay draws someting + if (reDrawing) return(false); // redraw task draws something + #endif + return(true); + } + /** * Redraw the screen (but only if things have changed * or if forceRedraw). */ void redraw(bool forceRedraw) { + #if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS) + // use a wrapper onESP32, to ensure the functions is not running several times in parallel ! + static bool doForceRedraw = false; // for delaying "force redraw" + + if ((overlayUntil > 0) && (millis() >= overlayUntil)) { + forceRedraw = true; // Time to display the overlay has elapsed, force redraw needed + } + + if (forceRedraw) doForceRedraw = true; + if (reDrawing) return; // redraw already active + if (drawing) return; // overlay draw active + + reDrawing = true; // set redraw lock + if (doForceRedraw) forceRedraw = true; + redraw_core(forceRedraw); + if (overlayUntil == 0) doForceRedraw = false; // redraw was skipped if overlay is still visible + reDrawing = false; // reset activity flag, as redraw has too many early returns that don't take care of this + } + + void redraw_core(bool forceRedraw) { +#endif bool needRedraw = false; unsigned long now = millis(); + + if (!typeOK || !enabled) return; // WLEDMM make sure the display is initialized before we try to draw on it + if (nullptr == u8x8) return; // prevent crash in case u8x8 is re-initialized (du to user changing setings) - if (!typeOK || !enabled) return; if (overlayUntil > 0) { if (now >= overlayUntil) { // Time to display the overlay has elapsed. @@ -575,6 +629,8 @@ class FourLineDisplayUsermod : public Usermod { knownnightlight = nightlightActive; wificonnected = interfacesInited; + while (drawing && millis()-now < 150) delay(8); // wait if someone else is drawing + // Do the actual drawing // First row: Icons draw2x2GlyphIcons(); @@ -598,7 +654,7 @@ class FourLineDisplayUsermod : public Usermod { if (overlayUntil == 0) { brightness100 = ((uint16_t)bri*100)/255; char lineBuffer[4]; - sprintf_P(lineBuffer, PSTR("%-3d"), brightness100); + snprintf_P(lineBuffer, 4, PSTR("%-3d"), brightness100); drawString(1, lineHeight, lineBuffer); //lastRedraw = millis(); } @@ -609,7 +665,7 @@ class FourLineDisplayUsermod : public Usermod { if (overlayUntil == 0) { fxspeed100 = ((uint16_t)effectSpeed*100)/255; char lineBuffer[4]; - sprintf_P(lineBuffer, PSTR("%-3d"), fxspeed100); + snprintf_P(lineBuffer, 4, PSTR("%-3d"), fxspeed100); drawString(5, lineHeight, lineBuffer); //lastRedraw = millis(); } @@ -620,7 +676,7 @@ class FourLineDisplayUsermod : public Usermod { if (overlayUntil == 0) { fxintensity100 = ((uint16_t)effectIntensity*100)/255; char lineBuffer[4]; - sprintf_P(lineBuffer, PSTR("%-3d"), fxintensity100); + snprintf_P(lineBuffer, 4, PSTR("%-3d"), fxintensity100); drawString(9, lineHeight, lineBuffer); //lastRedraw = millis(); } @@ -654,10 +710,12 @@ class FourLineDisplayUsermod : public Usermod { //Display the current effect or palette (desiredEntry) // on the appropriate line (row). void showCurrentEffectOrPalette(int inputEffPal, const char *qstring, uint8_t row) { - char lineBuffer[MAX_JSON_CHARS]; + char lineBuffer[MAX_JSON_CHARS] = { '\0' }; + if (!typeOK || !enabled) return; // WLEDMM make sure the display is initialized before we try to draw on it if (overlayUntil == 0) { // Find the mode name in JSON uint8_t printedChars = extractModeName(inputEffPal, qstring, lineBuffer, MAX_JSON_CHARS-1); + if (printedChars < 2) strcpy(lineBuffer, "invalid"); // catch possible error if (lineBuffer[0]=='*' && lineBuffer[1]==' ') { // remove "* " from dynamic palettes for (byte i=2; i<=printedChars; i++) lineBuffer[i-2] = lineBuffer[i]; //include '\0' @@ -668,8 +726,8 @@ class FourLineDisplayUsermod : public Usermod { printedChars -= 5; } if (lineHeight == 2) { // use this code for 8 line display - char smallBuffer1[MAX_MODE_LINE_SPACE]; - char smallBuffer2[MAX_MODE_LINE_SPACE]; + char smallBuffer1[MAX_MODE_LINE_SPACE+1] = { '\0' }; + char smallBuffer2[MAX_MODE_LINE_SPACE+1] = { '\0' }; uint8_t smallChars1 = 0; uint8_t smallChars2 = 0; if (printedChars < MAX_MODE_LINE_SPACE) { // use big font if the text fits @@ -696,13 +754,15 @@ class FourLineDisplayUsermod : public Usermod { } while (smallChars1 < (MAX_MODE_LINE_SPACE-1)) smallBuffer1[smallChars1++]=' '; smallBuffer1[smallChars1] = 0; + smallBuffer1[MAX_MODE_LINE_SPACE -1] = '\0'; // ensure the string ends where it should (while loop avove can overshoot by 1) drawString(1, row*lineHeight, smallBuffer1, true); while (smallChars2 < (MAX_MODE_LINE_SPACE-1)) smallBuffer2[smallChars2++]=' '; smallBuffer2[smallChars2] = 0; + smallBuffer2[MAX_MODE_LINE_SPACE -1] = '\0'; // ensure the string ends where it should (while loop avove can overshoot by 1) drawString(1, row*lineHeight+1, smallBuffer2, true); } } else { // use this code for 4 ling displays - char smallBuffer3[MAX_MODE_LINE_SPACE+1]; // uses 1x1 icon for mode/palette + char smallBuffer3[MAX_MODE_LINE_SPACE+1] = {'\0'}; // uses 1x1 icon for mode/palette uint8_t smallChars3 = 0; for (uint8_t i = 0; i < MAX_MODE_LINE_SPACE; i++) smallBuffer3[smallChars3++] = (i >= printedChars) ? ' ' : lineBuffer[i]; smallBuffer3[smallChars3] = 0; @@ -739,8 +799,10 @@ class FourLineDisplayUsermod : public Usermod { * Used in Rotary Encoder usermod. */ void overlay(const char* line1, long showHowLong, byte glyphType) { + if (!typeOK || !enabled) return; // WLEDMM make sure the display is initialized before we try to draw on it unsigned long now = millis(); while (drawing && millis()-now < 250) delay(1); // wait if someone else is drawing + while ((reDrawing && overlayUntil == 0) && (millis()-now < 250)) delay(10); // wait if someone else is re-drawing drawing = true; // Turn the display back on if (!wakeDisplay()) clear(); @@ -763,6 +825,7 @@ class FourLineDisplayUsermod : public Usermod { * Clears the screen and prints. */ void overlayLogo(long showHowLong) { + if (!typeOK || !enabled) return; // WLEDMM make sure the display is initialized before we try to draw on it unsigned long now = millis(); while (drawing && millis()-now < 250) delay(1); // wait if someone else is drawing drawing = true; @@ -824,8 +887,10 @@ class FourLineDisplayUsermod : public Usermod { * Used in Auto Save usermod */ void overlay(const char* line1, const char* line2, long showHowLong) { + if (!typeOK || !enabled) return; // WLEDMM make sure the display is initialized before we try to draw on it unsigned long now = millis(); while (drawing && millis()-now < 250) delay(1); // wait if someone else is drawing + while ((reDrawing && overlayUntil == 0) && (millis()-now < 250)) delay(10); // wait if someone else is re-drawing drawing = true; // Turn the display back on if (!wakeDisplay()) clear(); @@ -845,6 +910,7 @@ class FourLineDisplayUsermod : public Usermod { } void networkOverlay(const char* line1, long showHowLong) { + if (!typeOK || !enabled) return; // WLEDMM make sure the display is initialized before we try to draw on it unsigned long now = millis(); while (drawing && millis()-now < 250) delay(1); // wait if someone else is drawing drawing = true; @@ -982,7 +1048,7 @@ class FourLineDisplayUsermod : public Usermod { #endif #endif void onUpdateBegin(bool init) { - #ifdef ARDUINO_ARCH_ESP32 + #if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS) if (init && Display_Task) { vTaskSuspend(Display_Task); // update is about to begin, disable task to prevent crash } else { @@ -990,7 +1056,7 @@ class FourLineDisplayUsermod : public Usermod { if (Display_Task) vTaskResume(Display_Task); else - xTaskCreatePinnedToCore( + xTaskCreateUniversal( // this is guaranteed to work on any ESP32 (single or dual core) [](void * par) { // Function to implement the task // see https://www.freertos.org/vtaskdelayuntil.html const TickType_t xFrequency = REFRESH_RATE_MS * portTICK_PERIOD_MS / 2; @@ -998,12 +1064,14 @@ class FourLineDisplayUsermod : public Usermod { for(;;) { delay(1); // DO NOT DELETE THIS LINE! It is needed to give the IDLE(0) task enough time and to keep the watchdog happy. // taskYIELD(), yield(), vTaskDelay() and esp_task_wdt_feed() didn't seem to work. - vTaskDelayUntil(&xLastWakeTime, xFrequency); // release CPU, by doing nothing for REFRESH_RATE_MS millis + xLastWakeTime = xTaskGetTickCount(); // workaround for vTaskDelayUntil bug: it does not always keep the last time so we refresh it explicitly FourLineDisplayUsermod::getInstance()->redraw(false); + vTaskDelayUntil(&xLastWakeTime, xFrequency); // release CPU, by doing nothing until next REFRESH_RATE_MS millis } }, "4LD", // Name of the task - 3072, // Stack size in words +// 3072, // Stack size in words + 4096, // bigger Stack size in words NULL, // Task input parameter 1, // Priority of the task (not idle) &Display_Task, // Task handle @@ -1136,7 +1204,7 @@ class FourLineDisplayUsermod : public Usermod { top[FPSTR(_flip)] = (bool) flip; top[FPSTR(_contrast)] = contrast; top[FPSTR(_contrastFix)] = (bool) contrastFix; - #ifndef ARDUINO_ARCH_ESP32 + #if !defined(ARDUINO_ARCH_ESP32) || !defined(FLD_ESP32_USE_THREADS) top[FPSTR(_refreshRate)] = refreshRate; #endif top[FPSTR(_screenTimeOut)] = screenTimeout/1000; @@ -1172,7 +1240,7 @@ class FourLineDisplayUsermod : public Usermod { for (byte i=0; i<5; i++) ioPin[i] = top["pin"][i] | ioPin[i]; flip = top[FPSTR(_flip)] | flip; contrast = top[FPSTR(_contrast)] | contrast; - #ifndef ARDUINO_ARCH_ESP32 + #if !defined(ARDUINO_ARCH_ESP32) || !defined(FLD_ESP32_USE_THREADS) refreshRate = top[FPSTR(_refreshRate)] | refreshRate; refreshRate = min(5000, max(250, (int)refreshRate)); #endif @@ -1196,8 +1264,20 @@ class FourLineDisplayUsermod : public Usermod { // changing parameters from settings page bool pinsChanged = false; for (byte i=0; i<5; i++) if (ioPin[i] != oldPin[i]) { pinsChanged = true; break; } + #if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS) + unsigned long now = millis(); + while ((drawing || reDrawing) && millis()-now < 300) delay(10); // wait if someone else is drawing + #endif + drawing = false; + reDrawing = false; + if (pinsChanged || type!=newType) { - if (typeOK) delete u8x8; + if (typeOK) { + typeOK = false; + if (u8x8 != nullptr) delete u8x8; + u8x8 = nullptr; + USER_PRINTLN(F("Display terminated.")); + } PinOwner po = PinOwner::UM_FourLineDisplay; bool isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64); if (isSPI) { @@ -1213,10 +1293,12 @@ class FourLineDisplayUsermod : public Usermod { setup(); needsRedraw |= true; } else { - u8x8->setBusClock(ioFrequency); // can be used for SPI too - setVcomh(contrastFix); - setContrast(contrast); - setFlipMode(flip); + if (enabled && typeOK && (nullptr != u8x8)) { // WLEDMM ensure we have a valid, active driver + u8x8->setBusClock(ioFrequency); // can be used for SPI too + setVcomh(contrastFix); + setContrast(contrast); + setFlipMode(flip); + } } knownHour = 99; if (needsRedraw && !wakeDisplay()) redraw(true); diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h index 37b08d15..526ee7a0 100644 --- a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h @@ -383,7 +383,7 @@ public: buttonWaitTime = 0; char newState = select_state + 1; bool changedState = false; - char lineBuffer[64]; + char lineBuffer[64] = { '\0' }; do { // finde new state switch (newState) { @@ -525,7 +525,8 @@ public: bri = max(min((increase ? bri+fadeAmount : bri-fadeAmount), 255), 0); lampUdated(); #ifdef USERMOD_FOUR_LINE_DISPLAY - display->updateBrightness(); + if (display->canDraw()) // only draw if nothing else is drawing + display->updateBrightness(); #endif } @@ -554,7 +555,8 @@ public: } lampUdated(); #ifdef USERMOD_FOUR_LINE_DISPLAY - display->showCurrentEffectOrPalette(effectCurrent, JSON_mode_names, 3); + if (display->canDraw()) // only draw if nothing else is drawing + display->showCurrentEffectOrPalette(effectCurrent, JSON_mode_names, 3); #endif } @@ -582,7 +584,8 @@ public: } lampUdated(); #ifdef USERMOD_FOUR_LINE_DISPLAY - display->updateSpeed(); + if (display->canDraw()) // only draw if nothing else is drawing + display->updateSpeed(); #endif } @@ -610,7 +613,8 @@ public: } lampUdated(); #ifdef USERMOD_FOUR_LINE_DISPLAY - display->updateIntensity(); + if (display->canDraw()) // only draw if nothing else is drawing + display->updateIntensity(); #endif } @@ -688,7 +692,8 @@ public: } lampUdated(); #ifdef USERMOD_FOUR_LINE_DISPLAY - display->showCurrentEffectOrPalette(effectPalette, JSON_palette_names, 2); + if (display->canDraw()) // only draw if nothing else is drawing + display->showCurrentEffectOrPalette(effectPalette, JSON_palette_names, 2); #endif } @@ -764,7 +769,7 @@ public: if (presetHigh && presetLow && presetHigh > presetLow) { StaticJsonDocument<64> root; char str[64] = { '\0' }; - sprintf_P(str, PSTR("%d~%d~%s"), presetLow, presetHigh, increase?"":"-"); + snprintf_P(str, 64, PSTR("%d~%d~%s"), presetLow, presetHigh, increase?"":"-"); root["ps"] = str; deserializeState(root.as(), CALL_MODE_BUTTON_PRESET); /* diff --git a/wled00/wled.h b/wled00/wled.h index 22d3f23c..cc528f11 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2301310 +#define VERSION 2302020 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG diff --git a/wled00/wled_serial.cpp b/wled00/wled_serial.cpp index 8e52d567..b6ae511b 100644 --- a/wled00/wled_serial.cpp +++ b/wled00/wled_serial.cpp @@ -86,6 +86,7 @@ bool canUseSerial(void) { // WLEDMM returns true if Serial can be used for deb void handleSerial() { if (pinManager.isPinAllocated(hardwareRX)) return; + if (!Serial) return; // WLEDMM - serial not connected (USB CDC) #ifdef WLED_ENABLE_ADALIGHT static auto state = AdaState::Header_A;