From 70042db2dea8ff7a1b4b00430b250a60c30f3ef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Wed, 22 Jan 2025 20:33:56 +0100 Subject: [PATCH] Allow "unlimited" virtual buses - added config upload options - number of buses it limited to 36 (0-9+A-Z identifiers) - WRNING web server may not support that many variables --- wled00/cfg.cpp | 22 +++------- wled00/const.h | 24 ++++++----- wled00/data/settings_leds.htm | 76 ++++++++++++++++++++++++----------- wled00/set.cpp | 4 +- wled00/xml.cpp | 2 +- 5 files changed, 75 insertions(+), 53 deletions(-) diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 0d3165e0ea..3e8782a995 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -192,7 +192,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { #endif for (JsonObject elm : ins) { - if (s >= WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES) break; + if (s >= WLED_MAX_BUSSES) break; uint8_t pins[5] = {255, 255, 255, 255, 255}; JsonArray pinArr = elm["pin"]; if (pinArr.size() == 0) continue; @@ -220,21 +220,11 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { maMax = 0; } ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh - if (fromFS) { - BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax); - if (useParallel && s < 8) { - // if for some unexplained reason the above pre-calculation was wrong, update - unsigned memT = BusManager::memUsage(bc); // includes x8 memory allocation for parallel I2S - if (memT > mem) mem = memT; // if we have unequal LED count use the largest - } else - mem += BusManager::memUsage(bc); // includes global buffer - if (mem <= MAX_LED_MEMORY) if (BusManager::add(bc) == -1) break; // finalization will be done in WLED::beginStrip() - } else { - if (busConfigs[s] != nullptr) delete busConfigs[s]; - busConfigs[s] = new BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax); - doInitBusses = true; // finalization done in beginStrip() - } - s++; + + //busConfigs.push_back(std::move(BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax))); + busConfigs.emplace_back(ledType, pins, start, length, colorOrder, reversed, skipFirst, AWmode, freqkHz, useGlobalLedBuffer, maPerLed, maMax); + doInitBusses = true; // finalization done in beginStrip() + if (!Bus::isVirtual(ledType)) s++; // have as many virtual buses as you want } DEBUG_PRINTF_P(PSTR("LED buffer size: %uB\n"), mem); DEBUG_PRINTF_P(PSTR("Heap after buses: %d\n"), ESP.getFreeHeap()); diff --git a/wled00/const.h b/wled00/const.h index 1ebcb9397d..0f0fc4f99c 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -49,31 +49,31 @@ #define WLED_MAX_DIGITAL_CHANNELS 3 #define WLED_MAX_ANALOG_CHANNELS 5 #define WLED_MAX_BUSSES 4 // will allow 3 digital & 1 analog RGB - #define WLED_MIN_VIRTUAL_BUSSES 2 + #define WLED_MIN_VIRTUAL_BUSSES 3 // no longer used for bus creation but used to distinguish S2/S3 in UI #else #define WLED_MAX_ANALOG_CHANNELS (LEDC_CHANNEL_MAX*LEDC_SPEED_MODE_MAX) #if defined(CONFIG_IDF_TARGET_ESP32C3) // 2 RMT, 6 LEDC, only has 1 I2S but NPB does not support it ATM #define WLED_MAX_BUSSES 6 // will allow 2 digital & 2 analog RGB or 6 PWM white #define WLED_MAX_DIGITAL_CHANNELS 2 //#define WLED_MAX_ANALOG_CHANNELS 6 - #define WLED_MIN_VIRTUAL_BUSSES 3 + #define WLED_MIN_VIRTUAL_BUSSES 4 // no longer used for bus creation but used to distinguish S2/S3 in UI #elif defined(CONFIG_IDF_TARGET_ESP32S2) // 4 RMT, 8 LEDC, only has 1 I2S bus, supported in NPB // the 5th bus (I2S) will prevent Audioreactive usermod from functioning (it is last used though) #define WLED_MAX_BUSSES 7 // will allow 5 digital & 2 analog RGB #define WLED_MAX_DIGITAL_CHANNELS 5 //#define WLED_MAX_ANALOG_CHANNELS 8 - #define WLED_MIN_VIRTUAL_BUSSES 3 - #elif defined(CONFIG_IDF_TARGET_ESP32S3) // 4 RMT, 8 LEDC, has 2 I2S but NPB does not support them ATM - #define WLED_MAX_BUSSES 6 // will allow 4 digital & 2 analog RGB - #define WLED_MAX_DIGITAL_CHANNELS 4 + #define WLED_MIN_VIRTUAL_BUSSES 4 // no longer used for bus creation but used to distinguish S2/S3 in UI + #elif defined(CONFIG_IDF_TARGET_ESP32S3) // 4 RMT, 8 LEDC, has 2 I2S but NPB supports parallel x8 LCD on I2S1 + #define WLED_MAX_BUSSES 14 // will allow 12 digital & 2 analog RGB + #define WLED_MAX_DIGITAL_CHANNELS 12 // x4 RMT + x8 I2S-LCD //#define WLED_MAX_ANALOG_CHANNELS 8 - #define WLED_MIN_VIRTUAL_BUSSES 4 + #define WLED_MIN_VIRTUAL_BUSSES 6 // no longer used for bus creation but used to distinguish S2/S3 in UI #else // the last digital bus (I2S0) will prevent Audioreactive usermod from functioning #define WLED_MAX_BUSSES 20 // will allow 17 digital & 3 analog RGB #define WLED_MAX_DIGITAL_CHANNELS 17 //#define WLED_MAX_ANALOG_CHANNELS 16 - #define WLED_MIN_VIRTUAL_BUSSES 4 + #define WLED_MIN_VIRTUAL_BUSSES 6 // no longer used for bus creation but used to distinguish S2/S3 in UI #endif #endif #else @@ -87,7 +87,7 @@ #ifndef WLED_MAX_DIGITAL_CHANNELS #error You must also define WLED_MAX_DIGITAL_CHANNELS. #endif - #define WLED_MIN_VIRTUAL_BUSSES (5-WLED_MAX_BUSSES) + #define WLED_MIN_VIRTUAL_BUSSES 3 #else #if WLED_MAX_BUSSES > 20 #error Maximum number of buses is 20. @@ -98,7 +98,11 @@ #ifndef WLED_MAX_DIGITAL_CHANNELS #error You must also define WLED_MAX_DIGITAL_CHANNELS. #endif - #define WLED_MIN_VIRTUAL_BUSSES (20-WLED_MAX_BUSSES) + #if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) + #define WLED_MIN_VIRTUAL_BUSSES 4 + #else + #define WLED_MIN_VIRTUAL_BUSSES 6 + #endif #endif #endif diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 02ebb6ed0b..87e76e9b63 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -42,10 +42,10 @@ if (loc) d.Sf.action = getURL('/settings/leds'); } function bLimits(b,v,p,m,l,o=5,d=2,a=6) { - oMaxB = maxB = b; // maxB - max buses (can be changed if using ESP32 parallel I2S) - maxD = d; // maxD - max digital channels (can be changed if using ESP32 parallel I2S) - maxA = a; // maxA - max analog channels - maxV = v; // maxV - min virtual buses + oMaxB = maxB = b; // maxB - max buses (can be changed if using ESP32 parallel I2S): 20 - ESP32, 14 - S3/S2, 6 - C3, 4 - 8266 + maxD = d; // maxD - max digital channels (can be changed if using ESP32 parallel I2S): 17 - ESP32, 12 - S3/S2, 2 - C3, 3 - 8266 + maxA = a; // maxA - max analog channels: 16 - ESP32, 8 - S3/S2, 6 - C3, 5 - 8266 + maxV = v; // maxV - min virtual buses: 6 - ESP32/S3, 4 - S2/C3, 3 - ESP8266 (only used to distinguish S2/S3) maxPB = p; // maxPB - max LEDs per bus maxM = m; // maxM - max LED memory maxL = l; // maxL - max LEDs (will serve to determine ESP >1664 == ESP32) @@ -350,6 +350,18 @@ else LC.style.color = d.ro_gpio.some((e)=>e==parseInt(LC.value)) ? "orange" : "#fff"; } }); + const S2 = (oMaxB == 14) && (maxV == 4); + const S3 = (oMaxB == 14) && (maxV == 6); + if (oMaxB == 19 || S2 || S3) { // TODO: crude ESP32 & S2/S3 detection + if (maxLC > 300 || dC <= 2) { + d.Sf["PR"].checked = false; + gId("prl").classList.add("hide"); + } else + gId("prl").classList.remove("hide"); + // S2 supports mono I2S as well as parallel so we need to take that into account; S3 only supports parallel + maxD = (S2 || S3 ? 4 : 8) + (d.Sf["PR"].checked ? 8 : S2); // TODO: use bLimits() : 4/8RMT + (x1/x8 parallel) I2S1 + maxB = oMaxB - (d.Sf["PR"].checked ? 0 : 7 + S3); // S2 (maxV==4) does support mono I2S + } // distribute ABL current if not using PPL enPPL(sDI); @@ -409,8 +421,8 @@ if (isVir(t)) virtB++; }); - if ((n==1 && i>=maxB+maxV) || (n==-1 && i==0)) return; - var s = String.fromCharCode((i<10?48:55)+i); + if ((n==1 && i>=36) || (n==-1 && i==0)) return; // used to be i>=maxB+maxV when virtual buses were limited (now :"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") + var s = chrID(i); if (n==1) { // npm run build has trouble minimizing spaces inside string @@ -484,7 +496,7 @@ o[i].querySelector("[name^=LT]").disabled = false; } - gId("+").style.display = (i0) ? "inline":"none"; if (!init) { @@ -603,22 +615,32 @@ function receivedText(e) { let lines = e.target.result; - var c = JSON.parse(lines); + let c = JSON.parse(lines); if (c.hw) { if (c.hw.led) { - for (var i=0; i<10; i++) addLEDs(-1); - var l = c.hw.led; + // remove all existing outputs + for (const i=0; i<36; i++) addLEDs(-1); // was i{ addLEDs(1); for (var j=0; j>4) & 0x0F; + d.getElementsByName("SP"+i)[0].value = v.freq; + d.getElementsByName("LA"+i)[0].value = v.ledma; + d.getElementsByName("MA"+i)[0].value = v.maxpwr; }); + d.getElementsByName("PR")[0].checked = l.prl | 0; + d.getElementsByName("LD")[0].checked = l.ld; + d.getElementsByName("MA")[0].value = l.maxpwr; + d.getElementsByName("ABL")[0].checked = l.maxpwr > 0; } if(c.hw.com) { resetCOM(); @@ -626,22 +648,28 @@ addCOM(e.start, e.len, e.order); }); } - if (c.hw.btn) { - var b = c.hw.btn; + let b = c.hw.btn; + if (b) { if (Array.isArray(b.ins)) gId("btns").innerHTML = ""; b.ins.forEach((v,i,a)=>{ addBtn(i,v.pin[0],v.type); }); d.getElementsByName("TT")[0].value = b.tt; } - if (c.hw.ir) { - d.getElementsByName("IR")[0].value = c.hw.ir.pin; - d.getElementsByName("IT")[0].value = c.hw.ir.type; + let ir = c.hw.ir; + if (ir) { + d.getElementsByName("IR")[0].value = ir.pin; + d.getElementsByName("IT")[0].value = ir.type; + } + let rl = c.hw.relay; + if (rl) { + d.getElementsByName("RL")[0].value = rl.pin; + d.getElementsByName("RM")[0].checked = rl.rev; + d.getElementsByName("RO")[0].checked = rl.odrain; } - if (c.hw.relay) { - d.getElementsByName("RL")[0].value = c.hw.relay.pin; - d.getElementsByName("RM")[0].checked = c.hw.relay.rev; - d.getElementsByName("RO")[0].checked = c.hw.relay.odrain; + let li = c.light; + if (li) { + d.getElementsByName("MS")[0].checked = li.aseg; } UI(); } diff --git a/wled00/set.cpp b/wled00/set.cpp index f7be16e0fd..193574c74d 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -141,7 +141,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) useGlobalLedBuffer = request->hasArg(F("LD")); bool busesChanged = false; - for (int s = 0; s < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; s++) { + for (int s = 0; s < 36; s++) { // theoretical limit is 36 : "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" int offset = s < 10 ? 48 : 55; char lp[4] = "L0"; lp[2] = offset+s; lp[3] = 0; //ascii 0-9 //strip data pin char lc[4] = "LC"; lc[2] = offset+s; lc[3] = 0; //strip length @@ -157,7 +157,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) char la[4] = "LA"; la[2] = offset+s; la[3] = 0; //LED mA char ma[4] = "MA"; ma[2] = offset+s; ma[3] = 0; //max mA if (!request->hasArg(lp)) { - DEBUG_PRINTF_P(PSTR("No data for %d\n"), s); + DEBUG_PRINTF_P(PSTR("# of buses: %d\n"), s+1); break; } for (int i = 0; i < 5; i++) { diff --git a/wled00/xml.cpp b/wled00/xml.cpp index a31b130724..2fbc32a603 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -272,7 +272,7 @@ void getSettingsJS(byte subPage, Print& settingsScript) // set limits settingsScript.printf_P(PSTR("bLimits(%d,%d,%d,%d,%d,%d,%d,%d);"), WLED_MAX_BUSSES, - WLED_MIN_VIRTUAL_BUSSES, + WLED_MIN_VIRTUAL_BUSSES, // irrelevant, but kept to distinguish S2/S3 in UI MAX_LEDS_PER_BUS, MAX_LED_MEMORY, MAX_LEDS,