From db881ee011ebe79c4ceb5b1c02a43ff6cf73b042 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Wed, 25 Oct 2023 20:27:01 +0200 Subject: [PATCH] Small optimisations. 2D liveView (non-WS) core soundSim fix --- wled00/FX_fcn.cpp | 2 +- wled00/json.cpp | 47 ++++++++++++++++++++++++++++++++++++------ wled00/wled.cpp | 38 ++++++++++++++++++++-------------- wled00/wled.h | 6 +++++- wled00/wled_server.cpp | 5 +++++ wled00/ws.cpp | 34 ++++++++++++++++-------------- 6 files changed, 92 insertions(+), 40 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 3cdf6ee2..a02a8556 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -588,7 +588,7 @@ void Segment::setMode(uint8_t fx, bool loadDefaults) { sOpt = extractModeDefaults(fx, "o2"); check2 = (sOpt >= 0) ? (bool)sOpt : false; sOpt = extractModeDefaults(fx, "o3"); check3 = (sOpt >= 0) ? (bool)sOpt : false; sOpt = extractModeDefaults(fx, "m12"); if (sOpt >= 0) map1D2D = constrain(sOpt, 0, 7); - sOpt = extractModeDefaults(fx, "si"); if (sOpt >= 0) soundSim = constrain(sOpt, 0, 1); + sOpt = extractModeDefaults(fx, "si"); if (sOpt >= 0) soundSim = constrain(sOpt, 0, 3); sOpt = extractModeDefaults(fx, "rev"); if (sOpt >= 0) reverse = (bool)sOpt; sOpt = extractModeDefaults(fx, "mi"); if (sOpt >= 0) mirror = (bool)sOpt; // NOTE: setting this option is a risky business sOpt = extractModeDefaults(fx, "rY"); if (sOpt >= 0) reverse_y = (bool)sOpt; diff --git a/wled00/json.cpp b/wled00/json.cpp index e3d071e4..77bdd174 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -100,7 +100,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId) if ((spc>0 && spc!=seg.spacing) || seg.map1D2D!=map1D2D) seg.fill(BLACK); // clear spacing gaps seg.map1D2D = constrain(map1D2D, 0, 7); - seg.soundSim = constrain(soundSim, 0, 1); + seg.soundSim = constrain(soundSim, 0, 3); uint8_t set = elem[F("set")] | seg.set; seg.set = constrain(set, 0, 3); @@ -1015,8 +1015,15 @@ void serializeModeNames(JsonArray arr) } } +static volatile bool servingClient = false; void serveJson(AsyncWebServerRequest* request) { + if (servingClient) { + request->send(503, "application/json", F("{\"error\":2}")); // ERR_CONCURENCY + return; + } + servingClient = true; + byte subJson = 0; const String& url = request->url(); if (url.indexOf("state") > 0) subJson = JSON_PATH_STATE; @@ -1030,23 +1037,28 @@ void serveJson(AsyncWebServerRequest* request) #ifdef WLED_ENABLE_JSONLIVE else if (url.indexOf("live") > 0) { serveLiveLeds(request); + servingClient = false; return; } #endif else if (url.indexOf("pal") > 0) { request->send_P(200, "application/json", JSON_palette_names); + servingClient = false; return; } else if (url.indexOf("cfg") > 0 && handleFileRead(request, "/cfg.json")) { + servingClient = false; return; } else if (url.length() > 6) { //not just /json request->send(501, "application/json", F("{\"error\":\"Not implemented\"}")); + servingClient = false; return; } if (!requestJSONBufferLock(17)) { request->send(503, "application/json", F("{\"error\":3}")); + servingClient = false; return; } AsyncJsonResponse *response = new AsyncJsonResponse(&doc, subJson==JSON_PATH_FXDATA || subJson==JSON_PATH_EFFECTS); // will clear and convert JsonDocument into JsonArray if necessary @@ -1093,10 +1105,11 @@ void serveJson(AsyncWebServerRequest* request) request->send(response); releaseJSONBufferLock(); + servingClient = false; } #ifdef WLED_ENABLE_JSONLIVE -#define MAX_LIVE_LEDS 180 +#define MAX_LIVE_LEDS 256 bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient) { @@ -1110,13 +1123,26 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient) uint16_t used = strip.getLengthTotal(); uint16_t n = (used -1) /MAX_LIVE_LEDS +1; //only serve every n'th LED if count over MAX_LIVE_LEDS - char buffer[2000]; +#ifndef WLED_DISABLE_2D + if (strip.isMatrix) { + // ignore anything behid matrix (i.e. extra strip) + used = Segment::maxWidth*Segment::maxHeight; // always the size of matrix (more or less than strip.getLengthTotal()) + n = 1; + if (used > MAX_LIVE_LEDS) n = 2; + if (used > MAX_LIVE_LEDS*4) n = 4; + } +#endif + + char buffer[2048]; // shoud be enough for 256 LEDs [RRGGBB] + all other text (9+25) strcpy_P(buffer, PSTR("{\"leds\":[")); - obuf = buffer; + obuf = buffer; // assign buffer for oappnd() functions olen = 9; - for (size_t i= 0; i < used; i += n) + for (size_t i = 0; i < used; i += n) { +#ifndef WLED_DISABLE_2D + if (strip.isMatrix && n>1 && (i/Segment::maxWidth)%n) i += Segment::maxWidth * (n-1); +#endif uint32_t c = strip.getPixelColor(i); uint8_t r = R(c); uint8_t g = G(c); @@ -1125,11 +1151,19 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient) r = scale8(qadd8(w, r), strip.getBrightness()); //R, add white channel to RGB channels as a simple RGBW -> RGB map g = scale8(qadd8(w, g), strip.getBrightness()); //G b = scale8(qadd8(w, b), strip.getBrightness()); //B - olen += sprintf(obuf + olen, "\"%06X\",", RGBW32(r,g,b,0)); + olen += sprintf_P(obuf + olen, PSTR("\"%06X\","), RGBW32(r,g,b,0)); } olen -= 1; oappend((const char*)F("],\"n\":")); oappendi(n); +#ifndef WLED_DISABLE_2D + if (strip.isMatrix) { + oappend((const char*)F(",\"w\":")); + oappendi(Segment::maxWidth/n); + oappend((const char*)F(",\"h\":")); + oappendi(Segment::maxHeight/n); + } +#endif oappend("}"); if (request) { request->send(200, "application/json", buffer); @@ -1139,6 +1173,7 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient) wsc->text(obuf, olen); } #endif + obuf = nullptr; return true; } #endif diff --git a/wled00/wled.cpp b/wled00/wled.cpp index ca6bb9a2..33c0350a 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -61,11 +61,11 @@ void WLED::loop() #ifdef WLED_ENABLE_DMX handleDMX(); #endif - userLoop(); #ifdef WLED_DEBUG unsigned long usermodMillis = millis(); #endif + userLoop(); usermods.loop(); #ifdef WLED_DEBUG usermodMillis = millis() - usermodMillis; @@ -186,7 +186,9 @@ void WLED::loop() yield(); handleWs(); +#if defined(STATUSLED) handleStatusLED(); +#endif toki.resetTick(); @@ -256,9 +258,9 @@ void WLED::loop() #endif // WLED_DEBUG } -void WLED::enableWatchdog() { #if WLED_WATCHDOG_TIMEOUT > 0 -#ifdef ARDUINO_ARCH_ESP32 +void WLED::enableWatchdog() { + #ifdef ARDUINO_ARCH_ESP32 esp_err_t watchdog = esp_task_wdt_init(WLED_WATCHDOG_TIMEOUT, true); DEBUG_PRINT(F("Watchdog enabled: ")); if (watchdog == ESP_OK) { @@ -268,22 +270,20 @@ void WLED::enableWatchdog() { return; } esp_task_wdt_add(NULL); -#else + #else ESP.wdtEnable(WLED_WATCHDOG_TIMEOUT * 1000); -#endif -#endif + #endif } void WLED::disableWatchdog() { -#if WLED_WATCHDOG_TIMEOUT > 0 -DEBUG_PRINTLN(F("Watchdog: disabled")); -#ifdef ARDUINO_ARCH_ESP32 + DEBUG_PRINTLN(F("Watchdog: disabled")); + #ifdef ARDUINO_ARCH_ESP32 esp_task_wdt_delete(NULL); -#else + #else ESP.wdtDisable(); -#endif -#endif + #endif } +#endif void WLED::setup() { @@ -464,15 +464,19 @@ void WLED::setup() #ifndef WLED_DISABLE_OTA if (aOtaEnabled) { ArduinoOTA.onStart([]() { -#ifdef ESP8266 + #ifdef ESP8266 wifi_set_sleep_type(NONE_SLEEP_T); -#endif + #endif + #if WLED_WATCHDOG_TIMEOUT > 0 WLED::instance().disableWatchdog(); + #endif DEBUG_PRINTLN(F("Start ArduinoOTA")); }); ArduinoOTA.onError([](ota_error_t error) { + #if WLED_WATCHDOG_TIMEOUT > 0 // reenable watchdog on failed update WLED::instance().enableWatchdog(); + #endif }); if (strlen(cmDNS) > 0) ArduinoOTA.setHostname(cmDNS); @@ -491,7 +495,9 @@ void WLED::setup() initServer(); DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); + #if WLED_WATCHDOG_TIMEOUT > 0 enableWatchdog(); + #endif #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET) WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 1); //enable brownout detector @@ -915,9 +921,9 @@ void WLED::handleConnection() // else blink at 1Hz when WLED_CONNECTED is false (no WiFi, ?? no Ethernet ??) // else blink at 2Hz when MQTT is enabled but not connected // else turn the status LED off +#if defined(STATUSLED) void WLED::handleStatusLED() { - #if defined(STATUSLED) uint32_t c = 0; #if STATUSLED>=0 @@ -957,5 +963,5 @@ void WLED::handleStatusLED() busses.setStatusPixel(0); #endif } - #endif } +#endif diff --git a/wled00/wled.h b/wled00/wled.h index 6cb6d1ce..21c0ec2a 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2310180 +#define VERSION 2310250 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG @@ -864,8 +864,12 @@ public: void initAP(bool resetAP = false); void initConnection(); void initInterfaces(); + #if defined(STATUSLED) void handleStatusLED(); + #endif + #if WLED_WATCHDOG_TIMEOUT > 0 void enableWatchdog(); void disableWatchdog(); + #endif }; #endif // WLED_H diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index 296b6dce..4dbfa190 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -308,10 +308,13 @@ void initServer() if (!correctPIN || otaLock) return; if(!index){ DEBUG_PRINTLN(F("OTA Update Start")); + #if WLED_WATCHDOG_TIMEOUT > 0 WLED::instance().disableWatchdog(); + #endif usermods.onUpdateBegin(true); // notify usermods that update is about to begin (some may require task de-init) lastEditTime = millis(); // make sure PIN does not lock during update #ifdef ESP8266 + strip.purgeSegments(true); // free as much memory as you can Update.runAsync(true); #endif Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000); @@ -323,7 +326,9 @@ void initServer() } else { DEBUG_PRINTLN(F("Update Failed")); usermods.onUpdateBegin(false); // notify usermods that update has failed (some may require task init) + #if WLED_WATCHDOG_TIMEOUT > 0 WLED::instance().enableWatchdog(); + #endif } } }); diff --git a/wled00/ws.cpp b/wled00/ws.cpp index 49780d02..a4deca4c 100644 --- a/wled00/ws.cpp +++ b/wled00/ws.cpp @@ -164,39 +164,39 @@ bool sendLiveLedsWs(uint32_t wsClient) const size_t MAX_LIVE_LEDS_WS = 1024U; #endif size_t n = ((used -1)/MAX_LIVE_LEDS_WS) +1; //only serve every n'th LED if count over MAX_LIVE_LEDS_WS - size_t pos = (strip.isMatrix ? 4 : 2); // start of data + size_t pos = 2; // start of data +#ifndef WLED_DISABLE_2D + if (strip.isMatrix) { + // ignore anything behid matrix (i.e. extra strip) + used = Segment::maxWidth*Segment::maxHeight; // always the size of matrix (more or less than strip.getLengthTotal()) + n = 1; + if (used > MAX_LIVE_LEDS_WS) n = 2; + if (used > MAX_LIVE_LEDS_WS*4) n = 4; + pos = 4; + } +#endif size_t bufSize = pos + (used/n)*3; AsyncWebSocketMessageBuffer * wsBuf = ws.makeBuffer(bufSize); if (!wsBuf) return false; //out of memory uint8_t* buffer = wsBuf->get(); + if (!buffer) return false; //out of memory + wsBuf->lock(); // protect buffer from being cleaned by another WS instance buffer[0] = 'L'; buffer[1] = 1; //version #ifndef WLED_DISABLE_2D - size_t skipLines = 0; if (strip.isMatrix) { buffer[1] = 2; //version - buffer[2] = Segment::maxWidth; - buffer[3] = Segment::maxHeight; - if (used > MAX_LIVE_LEDS_WS*4) { - buffer[2] = Segment::maxWidth/4; - buffer[3] = Segment::maxHeight/4; - skipLines = 3; - } else if (used > MAX_LIVE_LEDS_WS) { - buffer[2] = Segment::maxWidth/2; - buffer[3] = Segment::maxHeight/2; - skipLines = 1; - } + buffer[2] = Segment::maxWidth/n; + buffer[3] = Segment::maxHeight/n; } #endif for (size_t i = 0; pos < bufSize -2; i += n) { #ifndef WLED_DISABLE_2D - if (strip.isMatrix && skipLines) { - if ((i/Segment::maxWidth)%(skipLines+1)) i += Segment::maxWidth * skipLines; - } + if (strip.isMatrix && n>1 && (i/Segment::maxWidth)%n) i += Segment::maxWidth * (n-1); #endif uint32_t c = strip.getPixelColor(i); uint8_t r = R(c); @@ -209,6 +209,8 @@ bool sendLiveLedsWs(uint32_t wsClient) } wsc->binary(wsBuf); + wsBuf->unlock(); // un-protect buffer + ws._cleanBuffers(); return true; }