Small optimisations.

2D liveView (non-WS) core
soundSim fix
This commit is contained in:
Blaz Kristan 2023-10-25 20:27:01 +02:00
parent 789e34702b
commit db881ee011
6 changed files with 92 additions and 40 deletions

View File

@ -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, "o2"); check2 = (sOpt >= 0) ? (bool)sOpt : false;
sOpt = extractModeDefaults(fx, "o3"); check3 = (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, "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, "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, "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; sOpt = extractModeDefaults(fx, "rY"); if (sOpt >= 0) reverse_y = (bool)sOpt;

View File

@ -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 if ((spc>0 && spc!=seg.spacing) || seg.map1D2D!=map1D2D) seg.fill(BLACK); // clear spacing gaps
seg.map1D2D = constrain(map1D2D, 0, 7); 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; uint8_t set = elem[F("set")] | seg.set;
seg.set = constrain(set, 0, 3); seg.set = constrain(set, 0, 3);
@ -1015,8 +1015,15 @@ void serializeModeNames(JsonArray arr)
} }
} }
static volatile bool servingClient = false;
void serveJson(AsyncWebServerRequest* request) void serveJson(AsyncWebServerRequest* request)
{ {
if (servingClient) {
request->send(503, "application/json", F("{\"error\":2}")); // ERR_CONCURENCY
return;
}
servingClient = true;
byte subJson = 0; byte subJson = 0;
const String& url = request->url(); const String& url = request->url();
if (url.indexOf("state") > 0) subJson = JSON_PATH_STATE; if (url.indexOf("state") > 0) subJson = JSON_PATH_STATE;
@ -1030,23 +1037,28 @@ void serveJson(AsyncWebServerRequest* request)
#ifdef WLED_ENABLE_JSONLIVE #ifdef WLED_ENABLE_JSONLIVE
else if (url.indexOf("live") > 0) { else if (url.indexOf("live") > 0) {
serveLiveLeds(request); serveLiveLeds(request);
servingClient = false;
return; return;
} }
#endif #endif
else if (url.indexOf("pal") > 0) { else if (url.indexOf("pal") > 0) {
request->send_P(200, "application/json", JSON_palette_names); request->send_P(200, "application/json", JSON_palette_names);
servingClient = false;
return; return;
} }
else if (url.indexOf("cfg") > 0 && handleFileRead(request, "/cfg.json")) { else if (url.indexOf("cfg") > 0 && handleFileRead(request, "/cfg.json")) {
servingClient = false;
return; return;
} }
else if (url.length() > 6) { //not just /json else if (url.length() > 6) { //not just /json
request->send(501, "application/json", F("{\"error\":\"Not implemented\"}")); request->send(501, "application/json", F("{\"error\":\"Not implemented\"}"));
servingClient = false;
return; return;
} }
if (!requestJSONBufferLock(17)) { if (!requestJSONBufferLock(17)) {
request->send(503, "application/json", F("{\"error\":3}")); request->send(503, "application/json", F("{\"error\":3}"));
servingClient = false;
return; return;
} }
AsyncJsonResponse *response = new AsyncJsonResponse(&doc, subJson==JSON_PATH_FXDATA || subJson==JSON_PATH_EFFECTS); // will clear and convert JsonDocument into JsonArray if necessary 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); request->send(response);
releaseJSONBufferLock(); releaseJSONBufferLock();
servingClient = false;
} }
#ifdef WLED_ENABLE_JSONLIVE #ifdef WLED_ENABLE_JSONLIVE
#define MAX_LIVE_LEDS 180 #define MAX_LIVE_LEDS 256
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient) 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 used = strip.getLengthTotal();
uint16_t n = (used -1) /MAX_LIVE_LEDS +1; //only serve every n'th LED if count over MAX_LIVE_LEDS 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\":[")); strcpy_P(buffer, PSTR("{\"leds\":["));
obuf = buffer; obuf = buffer; // assign buffer for oappnd() functions
olen = 9; 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); uint32_t c = strip.getPixelColor(i);
uint8_t r = R(c); uint8_t r = R(c);
uint8_t g = G(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 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 g = scale8(qadd8(w, g), strip.getBrightness()); //G
b = scale8(qadd8(w, b), strip.getBrightness()); //B 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; olen -= 1;
oappend((const char*)F("],\"n\":")); oappend((const char*)F("],\"n\":"));
oappendi(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("}"); oappend("}");
if (request) { if (request) {
request->send(200, "application/json", buffer); request->send(200, "application/json", buffer);
@ -1139,6 +1173,7 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
wsc->text(obuf, olen); wsc->text(obuf, olen);
} }
#endif #endif
obuf = nullptr;
return true; return true;
} }
#endif #endif

View File

@ -61,11 +61,11 @@ void WLED::loop()
#ifdef WLED_ENABLE_DMX #ifdef WLED_ENABLE_DMX
handleDMX(); handleDMX();
#endif #endif
userLoop();
#ifdef WLED_DEBUG #ifdef WLED_DEBUG
unsigned long usermodMillis = millis(); unsigned long usermodMillis = millis();
#endif #endif
userLoop();
usermods.loop(); usermods.loop();
#ifdef WLED_DEBUG #ifdef WLED_DEBUG
usermodMillis = millis() - usermodMillis; usermodMillis = millis() - usermodMillis;
@ -186,7 +186,9 @@ void WLED::loop()
yield(); yield();
handleWs(); handleWs();
#if defined(STATUSLED)
handleStatusLED(); handleStatusLED();
#endif
toki.resetTick(); toki.resetTick();
@ -256,8 +258,8 @@ void WLED::loop()
#endif // WLED_DEBUG #endif // WLED_DEBUG
} }
void WLED::enableWatchdog() {
#if WLED_WATCHDOG_TIMEOUT > 0 #if WLED_WATCHDOG_TIMEOUT > 0
void WLED::enableWatchdog() {
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
esp_err_t watchdog = esp_task_wdt_init(WLED_WATCHDOG_TIMEOUT, true); esp_err_t watchdog = esp_task_wdt_init(WLED_WATCHDOG_TIMEOUT, true);
DEBUG_PRINT(F("Watchdog enabled: ")); DEBUG_PRINT(F("Watchdog enabled: "));
@ -271,19 +273,17 @@ void WLED::enableWatchdog() {
#else #else
ESP.wdtEnable(WLED_WATCHDOG_TIMEOUT * 1000); ESP.wdtEnable(WLED_WATCHDOG_TIMEOUT * 1000);
#endif #endif
#endif
} }
void WLED::disableWatchdog() { void WLED::disableWatchdog() {
#if WLED_WATCHDOG_TIMEOUT > 0
DEBUG_PRINTLN(F("Watchdog: disabled")); DEBUG_PRINTLN(F("Watchdog: disabled"));
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
esp_task_wdt_delete(NULL); esp_task_wdt_delete(NULL);
#else #else
ESP.wdtDisable(); ESP.wdtDisable();
#endif #endif
#endif
} }
#endif
void WLED::setup() void WLED::setup()
{ {
@ -467,12 +467,16 @@ void WLED::setup()
#ifdef ESP8266 #ifdef ESP8266
wifi_set_sleep_type(NONE_SLEEP_T); wifi_set_sleep_type(NONE_SLEEP_T);
#endif #endif
#if WLED_WATCHDOG_TIMEOUT > 0
WLED::instance().disableWatchdog(); WLED::instance().disableWatchdog();
#endif
DEBUG_PRINTLN(F("Start ArduinoOTA")); DEBUG_PRINTLN(F("Start ArduinoOTA"));
}); });
ArduinoOTA.onError([](ota_error_t error) { ArduinoOTA.onError([](ota_error_t error) {
#if WLED_WATCHDOG_TIMEOUT > 0
// reenable watchdog on failed update // reenable watchdog on failed update
WLED::instance().enableWatchdog(); WLED::instance().enableWatchdog();
#endif
}); });
if (strlen(cmDNS) > 0) if (strlen(cmDNS) > 0)
ArduinoOTA.setHostname(cmDNS); ArduinoOTA.setHostname(cmDNS);
@ -491,7 +495,9 @@ void WLED::setup()
initServer(); initServer();
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
#if WLED_WATCHDOG_TIMEOUT > 0
enableWatchdog(); enableWatchdog();
#endif
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET) #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET)
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 1); //enable brownout detector 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 1Hz when WLED_CONNECTED is false (no WiFi, ?? no Ethernet ??)
// else blink at 2Hz when MQTT is enabled but not connected // else blink at 2Hz when MQTT is enabled but not connected
// else turn the status LED off // else turn the status LED off
#if defined(STATUSLED)
void WLED::handleStatusLED() void WLED::handleStatusLED()
{ {
#if defined(STATUSLED)
uint32_t c = 0; uint32_t c = 0;
#if STATUSLED>=0 #if STATUSLED>=0
@ -957,5 +963,5 @@ void WLED::handleStatusLED()
busses.setStatusPixel(0); busses.setStatusPixel(0);
#endif #endif
} }
#endif
} }
#endif

View File

@ -8,7 +8,7 @@
*/ */
// version code in format yymmddb (b = daily build) // 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 //uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG //#define WLED_USE_MY_CONFIG
@ -864,8 +864,12 @@ public:
void initAP(bool resetAP = false); void initAP(bool resetAP = false);
void initConnection(); void initConnection();
void initInterfaces(); void initInterfaces();
#if defined(STATUSLED)
void handleStatusLED(); void handleStatusLED();
#endif
#if WLED_WATCHDOG_TIMEOUT > 0
void enableWatchdog(); void enableWatchdog();
void disableWatchdog(); void disableWatchdog();
#endif
}; };
#endif // WLED_H #endif // WLED_H

View File

@ -308,10 +308,13 @@ void initServer()
if (!correctPIN || otaLock) return; if (!correctPIN || otaLock) return;
if(!index){ if(!index){
DEBUG_PRINTLN(F("OTA Update Start")); DEBUG_PRINTLN(F("OTA Update Start"));
#if WLED_WATCHDOG_TIMEOUT > 0
WLED::instance().disableWatchdog(); WLED::instance().disableWatchdog();
#endif
usermods.onUpdateBegin(true); // notify usermods that update is about to begin (some may require task de-init) 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 lastEditTime = millis(); // make sure PIN does not lock during update
#ifdef ESP8266 #ifdef ESP8266
strip.purgeSegments(true); // free as much memory as you can
Update.runAsync(true); Update.runAsync(true);
#endif #endif
Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000); Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000);
@ -323,7 +326,9 @@ void initServer()
} else { } else {
DEBUG_PRINTLN(F("Update Failed")); DEBUG_PRINTLN(F("Update Failed"));
usermods.onUpdateBegin(false); // notify usermods that update has failed (some may require task init) usermods.onUpdateBegin(false); // notify usermods that update has failed (some may require task init)
#if WLED_WATCHDOG_TIMEOUT > 0
WLED::instance().enableWatchdog(); WLED::instance().enableWatchdog();
#endif
} }
} }
}); });

View File

@ -164,39 +164,39 @@ bool sendLiveLedsWs(uint32_t wsClient)
const size_t MAX_LIVE_LEDS_WS = 1024U; const size_t MAX_LIVE_LEDS_WS = 1024U;
#endif #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 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; size_t bufSize = pos + (used/n)*3;
AsyncWebSocketMessageBuffer * wsBuf = ws.makeBuffer(bufSize); AsyncWebSocketMessageBuffer * wsBuf = ws.makeBuffer(bufSize);
if (!wsBuf) return false; //out of memory if (!wsBuf) return false; //out of memory
uint8_t* buffer = wsBuf->get(); 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[0] = 'L';
buffer[1] = 1; //version buffer[1] = 1; //version
#ifndef WLED_DISABLE_2D #ifndef WLED_DISABLE_2D
size_t skipLines = 0;
if (strip.isMatrix) { if (strip.isMatrix) {
buffer[1] = 2; //version buffer[1] = 2; //version
buffer[2] = Segment::maxWidth; buffer[2] = Segment::maxWidth/n;
buffer[3] = Segment::maxHeight; buffer[3] = Segment::maxHeight/n;
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;
}
} }
#endif #endif
for (size_t i = 0; pos < bufSize -2; i += n) for (size_t i = 0; pos < bufSize -2; i += n)
{ {
#ifndef WLED_DISABLE_2D #ifndef WLED_DISABLE_2D
if (strip.isMatrix && skipLines) { if (strip.isMatrix && n>1 && (i/Segment::maxWidth)%n) i += Segment::maxWidth * (n-1);
if ((i/Segment::maxWidth)%(skipLines+1)) i += Segment::maxWidth * skipLines;
}
#endif #endif
uint32_t c = strip.getPixelColor(i); uint32_t c = strip.getPixelColor(i);
uint8_t r = R(c); uint8_t r = R(c);
@ -209,6 +209,8 @@ bool sendLiveLedsWs(uint32_t wsClient)
} }
wsc->binary(wsBuf); wsc->binary(wsBuf);
wsBuf->unlock(); // un-protect buffer
ws._cleanBuffers();
return true; return true;
} }