Skip to content

Commit a03f758

Browse files
committed
Add ability to edit LED type on any output
- some string optimisations - imports from/replaces #5014
1 parent a18b133 commit a03f758

File tree

1 file changed

+84
-69
lines changed

1 file changed

+84
-69
lines changed

wled00/data/settings_leds.htm

Lines changed: 84 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!DOCTYPE html>
1+
<!DOCTYPE html>
22
<html lang="en">
33
<head>
44
<meta charset="utf-8">
@@ -13,8 +13,9 @@
1313
function gT(t) { for (let type of d.ledTypes) if (t == type.i) return type; } // getType from available ledTypes
1414
function isPWM(t) { return gT(t).t.charAt(0) === "A"; } // is PWM type
1515
function isAna(t) { return gT(t).t === "" || isPWM(t); } // is analog type
16-
function isDig(t) { return gT(t).t === "D" || isD2P(t); } // is digital type
16+
function isD1P(t) { return gT(t).t === "D"; } // is digital 1 pin type
1717
function isD2P(t) { return gT(t).t === "2P"; } // is digital 2 pin type
18+
function isDig(t) { return isD1P(t) || isD2P(t); } // is digital type
1819
function isNet(t) { return gT(t).t === "N"; } // is network type
1920
function isVir(t) { return gT(t).t === "V" || isNet(t); } // is virtual type
2021
function isHub75(t){ return gT(t).t === "H"; } // is HUB75 type
@@ -71,7 +72,7 @@
7172
return;
7273
}
7374
// ignore IP address
74-
if (isNet(t)) return;
75+
if (isNet(t)) return;
7576
//check for pin conflicts
7677
if (LC.value!="" && LC.value!="-1") {
7778
let p = d.rsvd.concat(d.um_p); // used pin array
@@ -101,10 +102,10 @@
101102
nList[j].focus();
102103
ok = false;
103104
return;
104-
}
105105
}
106106
}
107107
}
108+
}
108109
});
109110
return ok;
110111
}
@@ -215,8 +216,8 @@
215216
mul = 2; // ESP32 RMT uses double buffer
216217
} else if ((is32() || isS2() || isS3()) && toNum(n) > (parallelI2S ? 7 : 0)) {
217218
mul = 2; // ESP32 RMT uses double buffer
218-
} else if ((parallelI2S && toNum(n) < 8) || (n == 0 && is32())) { // I2S uses extra DMA buffer
219-
dbl = len * ch * 3; // DMA buffer for parallel I2S (TODO: ony the bus with largst LED count should be used)
219+
} else if ((parallelI2S && toNum(n) < 8) || (toNum(n) == 0 && is32())) { // I2S uses extra DMA buffer
220+
dbl = len * ch * 3; // DMA buffer for parallel I2S (TODO: only the bus with largst LED count should be used)
220221
}
221222
}
222223
return len * ch * mul + dbl + pbfr;
@@ -229,7 +230,7 @@
229230
let sLC = 0, sPC = 0, sDI = 0, maxLC = 0;
230231
const abl = d.Sf.ABL.checked;
231232
let setPinConfig = (n,t) => {
232-
let p0d = "GPIO:";
233+
let p0d = "GPIO: ";
233234
let p1d = "";
234235
let off = "Off Refresh";
235236
switch (gT(t).t.charAt(0)) {
@@ -240,14 +241,14 @@
240241
p0d = "Data "+p0d;
241242
break;
242243
case 'A': // PWM analog
243-
if (numPins(t) > 1) p0d = "GPIOs:";
244+
if (numPins(t) > 1) p0d = "GPIOs: ";
244245
off = "Dithering";
245246
break;
246247
case 'N': // network
247-
p0d = "IP address:";
248+
p0d = "IP address: ";
248249
break;
249250
case 'V': // virtual/non-GPIO based
250-
p0d = "Config:"
251+
p0d = "Config: "
251252
break;
252253
case 'H': // HUB75
253254
p0d = "Panel size (width x height), Panel count:"
@@ -268,11 +269,10 @@
268269
}
269270

270271
// enable/disable LED fields
272+
updateTypeDropdowns(change);
271273
let dC = 0; // count of digital buses (for parallel I2S)
272274
let LTs = d.Sf.querySelectorAll("#mLC select[name^=LT]");
273275
LTs.forEach((s,i)=>{
274-
s.disabled = (i < LTs.length-1); // prevent changing type (as we can't update options)
275-
// is the field a LED type?
276276
var n = s.name.substring(2,3); // bus number (0-Z)
277277
var t = parseInt(s.value);
278278
memu += getMem(t, n); // calc memory
@@ -321,15 +321,16 @@
321321
}
322322
// do we have a led count field
323323
if (nm=="LC") {
324+
LC.max = isAna(t) ? 1 : (isDig(t) ? maxPB : 16384); // set max value
324325
let c = parseInt(LC.value,10); //get LED count
325326
if (!customStarts || !startsDirty[toNum(n)]) gId("ls"+n).value = sLC; //update start value
326327
gId("ls"+n).disabled = !customStarts; //enable/disable field editing
327328
if (c) {
328329
let s = parseInt(gId("ls"+n).value); //start value
329330
if (s+c > sLC) sLC = s+c; //update total count
330-
if (c > maxLC) maxLC = c; //max per output
331331
if (!isVir(t)) sPC += c; //virtual out busses do not count towards physical LEDs
332332
if (isDig(t)) {
333+
if (c > maxLC) maxLC = c; //max per output
333334
sDI += c; // summarize digital LED count
334335
let maPL = parseInt(d.Sf["LA"+n].value);
335336
if (maPL == 255) maPL = 12;
@@ -409,6 +410,7 @@
409410
gId("pc").textContent = (sLC == sPC) ? "":"(" + sPC + " physical)";
410411

411412
// memory usage and warnings
413+
memu += sLC * (4 + (gN("MS").checked ? 0 : 4)); // pixel buffer (4 bytes per pixel) + at least 1 segment buffer
412414
gId('m0').innerHTML = memu;
413415
bquot = memu / maxM * 100;
414416
gId('dbar').style.background = `linear-gradient(90deg, ${bquot > 60 ? (bquot > 90 ? "red":"orange"):"#ccc"} 0 ${bquot}%, #444 ${bquot}% 100%)`;
@@ -439,26 +441,16 @@
439441
function lastEnd(i) {
440442
if (i-- < 1) return 0;
441443
var s = chrID(i);
442-
v = parseInt(d.getElementsByName("LS"+s)[0].value) + parseInt(d.getElementsByName("LC"+s)[0].value);
443-
var t = parseInt(d.getElementsByName("LT"+s)[0].value);
444+
v = parseInt(gN("LS"+s).value) + parseInt(gN("LC"+s).value);
445+
var t = parseInt(gN("LT"+s).value);
444446
if (isPWM(t)) v = 1; //PWM busses
445447
return isNaN(v) ? 0 : v;
446448
}
447449
function addLEDs(n,init=true)
448450
{
449451
var o = gEBCN("iST");
450452
var i = o.length;
451-
let disable = (sel,opt) => { sel.querySelectorAll(opt).forEach((o)=>{o.disabled=true;}); }
452-
453453
var f = gId("mLC");
454-
let digitalB = 0, analogB = 0, twopinB = 0, virtB = 0;
455-
f.querySelectorAll("select[name^=LT]").forEach((s)=>{
456-
let t = s.value;
457-
if (isDig(t) && !isD2P(t)) digitalB++;
458-
if (isD2P(t)) twopinB++;
459-
if (isPWM(t)) analogB += numPins(t); // each GPIO is assigned to a channel
460-
if (isVir(t)) virtB++;
461-
});
462454

463455
if ((n==1 && i>=36) || (n==-1 && i==0)) return; // used to be i>=maxB+maxV when virtual buses were limited (now :"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")
464456
var s = chrID(i);
@@ -467,7 +459,7 @@
467459
// npm run build has trouble minimizing spaces inside string
468460
var cn = `<div class="iST" draggable="true" ondragstart="hDS(event)" id="l${s}" style="cursor:grab;">
469461
<hr class="sml">
470-
<span id="n${s}">${i+1}</span>:
462+
<span id="n${s}">${++i}</span>:
471463
<select name="LT${s}" onchange="UI(true)"></select><br>
472464
<div id="abl${s}">
473465
mA/LED: <select name="LL${s}" onchange="enLA(this);UI();">
@@ -479,7 +471,7 @@
479471
<option value="0">Custom</option>
480472
</select><br>
481473
<div id="LAdis${s}" style="display: none;">max. mA/LED: <input name="LA${s}" type="number" min="1" max="255" oninput="UI()"> mA<br></div>
482-
<div id="PSU${s}">PSU: <input name="MA${s}" type="number" class="xl" min="250" max="65000" oninput="UI()" value="250"> mA<br></div>
474+
<div id="PSU${s}">PSU: <input name="MA${s}" type="number" class="xl" min="250" max="65500" oninput="UI()" value="250"> mA<br></div>
483475
</div>
484476
<div id="co${s}" style="display:inline">Color Order:
485477
<select name="CO${s}">
@@ -493,7 +485,7 @@
493485
<div id="dig${s}w" style="display:none">Swap: <select name="WO${s}"><option value="0">None</option><option value="1">W & B</option><option value="2">W & G</option><option value="3">W & R</option><option data-opt="CCT" value="4">WW & CW</option></select></div>
494486
<div id="dig${s}l" style="display:none">Clock: <select name="SP${s}"><option value="0">Slowest</option><option value="1">Slow</option><option value="2">Normal</option><option value="3">Fast</option><option value="4">Fastest</option></select></div>
495487
<div>
496-
<span id="psd${s}">Start:</span> <input type="number" name="LS${s}" id="ls${s}" class="l starts" min="0" max="8191" value="${lastEnd(i)}" oninput="startsDirty[${i}]=true;UI();" required />&nbsp;
488+
<span id="psd${s}">Start:</span> <input type="number" name="LS${s}" id="ls${s}" class="l starts" min="0" max="8191" value="${lastEnd(i-1)}" oninput="startsDirty[${i}]=true;UI();" required />&nbsp;
497489
<div id="dig${s}c" style="display:inline">Length: <input type="number" name="LC${s}" class="l" min="1" max="${maxPB}" value="1" required oninput="UI()" /></div><br>
498490
</div>
499491
<span id="p0d${s}">GPIO:</span><input type="number" name="L0${s}" required class="s" onchange="UI();pinUpd(this);"/>
@@ -523,22 +515,15 @@
523515
}
524516
});
525517
enLA(gN("LL"+s)); // update LED mA
526-
// disable inappropriate LED types
527-
let sel = d.getElementsByName("LT"+s)[0];
528-
// 32 & S2 supports mono I2S as well as parallel so we need to take that into account; S3 only supports parallel
529-
let maxDB = maxD - (is32() || isS2() || isS3() ? (!d.Sf["PR"].checked)*8 - (!isS3()) : 0); // adjust max digital buses if parallel I2S is not used
530-
if (digitalB >= maxDB) disable(sel,'option[data-type="D"]'); // NOTE: see isDig()
531-
if (twopinB >= 2) disable(sel,'option[data-type="2P"]'); // NOTE: see isD2P() (we will only allow 2 2pin buses)
532-
disable(sel,`option[data-type^="${'A'.repeat(maxA-analogB+1)}"]`); // NOTE: see isPWM()
533-
sel.selectedIndex = sel.querySelector('option:not(:disabled)').index;
518+
let sel = gN("LT"+s);
519+
sel.selectedIndex = sel.querySelector('option:not([data-type])').index; // select On/Off by default
534520
}
535521
if (n==-1) {
536-
o[--i].remove();--i;
537-
o[i].querySelector("[name^=LT]").disabled = false;
522+
o[--i].remove();
538523
}
539524

540-
gId("+").style.display = (i<35) ? "inline":"none"; // was maxB+maxV-1 when virtual buses were limited (now :"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")
541-
gId("-").style.display = (i>0) ? "inline":"none";
525+
gId("+").style.display = (i<36) ? "inline":"none"; // was maxB+maxV-1 when virtual buses were limited (now :"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")
526+
gId("-").style.display = (i>1) ? "inline":"none";
542527

543528
if (!init) {
544529
UI();
@@ -703,23 +688,23 @@
703688
let l = c.hw.led;
704689
l.ins.forEach((v,i,a)=>{
705690
addLEDs(1);
706-
for (var j=0; j<v.pin.length; j++) d.getElementsByName(`L${j}${i}`)[0].value = v.pin[j];
707-
d.getElementsByName("LT"+i)[0].value = v.type;
708-
d.getElementsByName("LS"+i)[0].value = v.start;
709-
d.getElementsByName("LC"+i)[0].value = v.len;
710-
d.getElementsByName("CO"+i)[0].value = v.order & 0x0F;
711-
d.getElementsByName("SL"+i)[0].value = v.skip;
712-
d.getElementsByName("RF"+i)[0].checked = v.ref;
713-
d.getElementsByName("CV"+i)[0].checked = v.rev;
714-
d.getElementsByName("AW"+i)[0].value = v.rgbwm;
715-
d.getElementsByName("WO"+i)[0].value = (v.order>>4) & 0x0F;
716-
d.getElementsByName("SP"+i)[0].value = v.freq;
717-
d.getElementsByName("LA"+i)[0].value = v.ledma;
718-
d.getElementsByName("MA"+i)[0].value = v.maxpwr;
691+
for (var j=0; j<v.pin.length; j++) gN(`L${j}${i}`).value = v.pin[j];
692+
gN("LT"+i).value = v.type;
693+
gN("LS"+i).value = v.start;
694+
gN("LC"+i).value = v.len;
695+
gN("CO"+i).value = v.order & 0x0F;
696+
gN("SL"+i).value = v.skip;
697+
gN("RF"+i).checked = v.ref;
698+
gN("CV"+i).checked = v.rev;
699+
gN("AW"+i).value = v.rgbwm;
700+
gN("WO"+i).value = (v.order>>4) & 0x0F;
701+
gN("SP"+i).value = v.freq;
702+
gN("LA"+i).value = v.ledma;
703+
gN("MA"+i).value = v.maxpwr;
719704
});
720-
d.getElementsByName("PR")[0].checked = l.prl | 0;
721-
d.getElementsByName("MA")[0].value = l.maxpwr;
722-
d.getElementsByName("ABL")[0].checked = l.maxpwr > 0;
705+
gN("PR").checked = l.prl | 0;
706+
gN("MA").value = l.maxpwr;
707+
gN("ABL").checked = l.maxpwr > 0;
723708
}
724709
if(c.hw.com) {
725710
resetCOM();
@@ -733,22 +718,22 @@
733718
b.ins.forEach((v,i,a)=>{
734719
addBtn(i,v.pin[0],v.type);
735720
});
736-
d.getElementsByName("TT")[0].value = b.tt;
721+
gN("TT").value = b.tt;
737722
}
738723
let ir = c.hw.ir;
739724
if (ir) {
740-
d.getElementsByName("IR")[0].value = ir.pin;
741-
d.getElementsByName("IT")[0].value = ir.type;
725+
gN("IR").value = ir.pin;
726+
gN("IT").value = ir.type;
742727
}
743728
let rl = c.hw.relay;
744729
if (rl) {
745-
d.getElementsByName("RL")[0].value = rl.pin;
746-
d.getElementsByName("RM")[0].checked = rl.rev;
747-
d.getElementsByName("RO")[0].checked = rl.odrain;
730+
gN("RL").value = rl.pin;
731+
gN("RM").checked = rl.rev;
732+
gN("RO").checked = rl.odrain;
748733
}
749734
let li = c.light;
750735
if (li) {
751-
d.getElementsByName("MS")[0].checked = li.aseg;
736+
gN("MS").checked = li.aseg;
752737
}
753738
UI();
754739
}
@@ -817,7 +802,7 @@
817802
function addDropdown(field) {
818803
let sel = cE('select');
819804
sel.classList.add("pin");
820-
let inp = d.getElementsByName(field)[0];
805+
let inp = gN(field);
821806
if (inp && inp.tagName === "INPUT" && (inp.type === "text" || inp.type === "number")) { // may also use nodeName
822807
let v = inp.value;
823808
let n = inp.name;
@@ -850,6 +835,36 @@
850835
}
851836
return opt;
852837
}
838+
// dynamically enforce bus type availability based on current usage
839+
function updateTypeDropdowns(change=false) {
840+
let LTs = d.Sf.querySelectorAll("#mLC select[name^=LT]");
841+
let digitalB = 0, analogB = 0, twopinB = 0, virtB = 0;
842+
// count currently used buses (including last added bus)
843+
LTs.forEach((sel,i) => {
844+
let t = parseInt(sel.value);
845+
if (isD1P(t)) digitalB++;
846+
if (isPWM(t)) analogB += numPins(t);
847+
if (isD2P(t)) twopinB++;
848+
if (isVir(t)) virtB++;
849+
});
850+
// now enable/disable type options according to limits in dropdowns
851+
LTs.forEach((sel,i) => {
852+
const last = i == LTs.length-1;
853+
const curType = parseInt(sel.value);
854+
const disable = (q) => sel.querySelectorAll(q).forEach(o => o.disabled = true);
855+
const enable = (q) => sel.querySelectorAll(q).forEach(o => o.disabled = false);
856+
enable('option'); // reset all first
857+
// max digital count
858+
let maxDB = maxD - ((is32() || isS2() || isS3()) ? (!d.Sf["PR"].checked) * 8 - (!isS3()) : 0);
859+
// disallow adding more of a type that has reached its limit
860+
if (digitalB >= maxDB && !isD1P(curType)) disable('option[data-type="D"]');
861+
if (twopinB >= 2 && !isD2P(curType)) disable('option[data-type="2P"]');
862+
// determine available analog pins
863+
disable(`option[data-type^="${'A'.repeat(maxA - analogB + (isPWM(curType) ? numPins(curType) : 0) + 1)}"]`);
864+
// if last added bus has an invalid type, change it to first available
865+
if (last && sel.selectedOptions[0].disabled) sel.selectedIndex = sel.querySelector('option:not(:disabled)').index;
866+
});
867+
}
853868
</script>
854869
<style>@import url("style.css");</style>
855870
</head>
@@ -871,7 +886,7 @@ <h2>LED &amp; Hardware setup</h2>
871886
Keep at &lt;1A if powering LEDs directly from the ESP 5V pin!<br>
872887
If using multiple outputs it is recommended to use per-output limiter.<br>
873888
Analog (PWM) and virtual LEDs cannot use automatic brightness limiter.<br></i>
874-
<div id="psuMA">Maximum PSU Current: <input name="MA" type="number" class="xl" min="250" max="65000" oninput="UI()" required> mA<br></div>
889+
<div id="psuMA">Maximum PSU Current: <input name="MA" type="number" class="xl" min="250" max="65500" oninput="UI()" required> mA<br></div>
875890
Use per-output limiter: <input type="checkbox" name="PPL" onchange="UI()"><br>
876891
<div id="ppldis" style="display:none;">
877892
<i>Make sure you enter correct value for each LED output.<br>
@@ -897,15 +912,15 @@ <h3>Hardware setup</h3>
897912
</div>
898913
<hr class="sml">
899914
<div id="prl" class="hide">Use parallel I2S: <input type="checkbox" name="PR"><br></div>
900-
Make a segment for each output: <input type="checkbox" name="MS"><br>
915+
Make a segment for each output: <input type="checkbox" name="MS" onchange="UI()"><br>
901916
Custom bus start indices: <input type="checkbox" onchange="tglSi(this.checked)" id="si"><br>
902917
<hr class="sml">
903918
<div id="color_order_mapping">
904919
Color Order Override:
905920
<div id="com_entries"></div>
906921
<hr class="sml">
907922
<button type="button" id="com_add" onclick="addCOM()">+</button>
908-
<button type="button" id="com_rem" onclick="remCOM()">-</button><br>
923+
<button type="button" id="com_rem" onclick="remCOM()">-</button>
909924
</div>
910925
<hr class="sml">
911926
<div id="btns"></div>
@@ -934,9 +949,9 @@ <h3>Defaults</h3>
934949
Turn LEDs on after power up/reset: <input type="checkbox" name="BO"><br>
935950
Default brightness: <input name="CA" type="number" class="m" min="1" max="255" required> (1-255)<br><br>
936951
Apply preset <input name="BP" type="number" class="m" min="0" max="250" required> at boot (0 uses values from above)<br><br>
937-
Use Gamma correction for color: <input type="checkbox" name="GC"> (strongly recommended)<br>
952+
Use Gamma correction for color: <input type="checkbox" name="GC"> (recommended)<br>
938953
Use Gamma correction for brightness: <input type="checkbox" name="GB"> (not recommended)<br>
939-
Use Gamma value: <input name="GV" type="number" class="m" placeholder="2.8" min="1" max="3" step="0.1" required><br><br>
954+
Use Gamma value: <input name="GV" type="number" class="m" min="1" max="3" step="0.1" required><br><br>
940955
Brightness factor: <input name="BF" type="number" class="m" min="1" max="255" required> %
941956
<h3>Transitions</h3>
942957
Default transition time: <input name="TD" type="number" class="xl" min="0" max="65500"> ms<br>

0 commit comments

Comments
 (0)