Dynamic bus config

- provide LED types from BusManager for settings
Credit: @netmindz for the idea.
This commit is contained in:
Blaz Kristan
2024-08-22 17:15:12 +02:00
parent 0bbd6b7c4b
commit 6f3267aee9
6 changed files with 278 additions and 253 deletions

View File

@@ -7,6 +7,7 @@
<script>
var d=document,laprev=55,maxB=1,maxD=1,maxA=1,maxV=0,maxM=4000,maxPB=4096,maxL=1333,maxCO=10,maxLbquot=0; //maximum bytes for LED allocation: 4kB for 8266, 32kB for 32
var oMaxB=1;
d.ledTypes = []; // filled from GetV()
d.um_p = [];
d.rsvd = [];
d.ro_gpio = [];
@@ -18,14 +19,15 @@
function gId(n){return d.getElementById(n);}
function off(n){d.getElementsByName(n)[0].value = -1;}
// these functions correspond to C macros found in const.h
function isPWM(t) { return t > 40 && t < 46; } // is PWM type
function isAna(t) { return t == 40 || isPWM(t); } // is analog type
function isDig(t) { return (t > 15 && t < 40) || isD2P(t); } // is digital type
function isD2P(t) { return t > 47 && t < 64; } // is digital 2 pin type
function is16b(t) { return t == 26 || t == 29 || t == 34; } // is digital 16 bit type
function isVir(t) { return t >= 80 && t < 96; } // is virtual type
function hasW(t) { return (t >= 18 && t <= 21) || (t >= 28 && t <= 32) || t == 34 || (t >= 44 && t <= 45) || (t >= 88 && t <= 89); }
function hasCCT(t) { return t == 20 || t == 21 || t == 42 || t == 45 || t == 28 || t == 32 || t == 34; }
function gT(t) { for (let type of d.ledTypes) if (t == type.i) return type; } // getType from available ledTypes
function isPWM(t) { return gT(t).t.charAt(0) === "A"; } // is PWM type
function isAna(t) { return gT(t).t === "" || isPWM(t); } // is analog type
function isDig(t) { return gT(t).t === "D" || isD2P(t); } // is digital type
function isD2P(t) { return gT(t).t === "2P"; } // is digital 2 pin type
function isVir(t) { return gT(t).t === "V"; } // is virtual type
function hasW(t) { return gT(t).w == 1; } // has white channel
function hasCCT(t) { return gT(t).c == 1; } // is white CCT enabled
function is16b(t) { return gT(t).s == 1; } // is digital 16 bit type
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
function loadJS(FILE_URL, async = true) {
let scE = d.createElement("script");
@@ -224,6 +226,35 @@
let sLC = 0, sPC = 0, sDI = 0, maxLC = 0;
const ablEN = d.Sf.ABL.checked;
maxB = oMaxB; // TODO make sure we start with all possible buses
let setPinConfig = (n,t) => {
let p0d = "GPIO:";
let p1d = "";
switch (gT(t).t.charAt(0)) {
case '2':
p1d = "Clk "+p0d;
case 'D':
p0d = "Data "+p0d;
break;
case 'A':
if (gT(t).t.length > 1) p0d = "GPIOs:";
break;
case 'V':
p0d = "IP address:";
break;
}
gId("p0d"+n).innerHTML = p0d;
gId("p1d"+n).innerHTML = p1d;
// secondary pins show/hide (type string length is equivalent to number of pins used; except for virtual and on/off)
let pins = gT(t).t.length + 3*isVir(t); // fixes virtual pins to 4
if (pins == 0) pins = 1; // fixes on/off pin
for (let p=1; p<5; p++) {
var LK = d.Sf["L"+p+n];
if (!LK) continue;
LK.style.display = (p < pins) ? "inline" : "none";
LK.required = (p < pins);
if (p >= pins) LK.value="";
}
}
// enable/disable LED fields
let LTs = d.Sf.querySelectorAll("#mLC select[name^=LT]");
@@ -232,49 +263,29 @@
// is the field a LED type?
var n = s.name.substring(2);
var t = parseInt(s.value);
gId("p0d"+n).innerHTML = isVir(t) ? "IP address:" : isD2P(t) ? "Data GPIO:" : (t > 41) ? "GPIOs:" : "GPIO:";
gId("p1d"+n).innerHTML = isD2P(t) ? "Clk GPIO:" : "";
gId("abl"+n).style.display = (!ablEN || isVir(t) || isAna(t)) ? "none" : "inline";
//var LK = d.getElementsByName("L1"+n)[0]; // clock pin
memu += getMem(t, n); // calc memory
// enumerate pins
for (p=1; p<5; p++) {
var LK = d.Sf["L"+p+n]; // secondary pins
if (!LK) continue;
if ((isVir(t) && p<4) || (isD2P(t) && p==1) || (isPWM(t) && (p+40 < t))) // TYPE_xxxx values from const.h
{
// display pin field
LK.style.display = "inline";
LK.required = true;
} else {
// hide pin field
LK.style.display = "none";
LK.required = false;
LK.value="";
}
}
setPinConfig(n,t);
gId("abl"+n).style.display = (!ablEN || isVir(t) || isAna(t)) ? "none" : "inline";
if (change) {
gId("rf"+n).checked = (gId("rf"+n).checked || t == 31); // LEDs require data in off state
if (isAna(t)) d.Sf["LC"+n].value = 1; // for sanity change analog count just to 1 LED
gId("rf"+n).checked = (gId("rf"+n).checked || t == 31); // LEDs require data in off state (mandatory for TM1814)
if (isAna(t)) d.Sf["LC"+n].value = 1; // for sanity change analog count just to 1 LED
d.Sf["LA"+n].min = (isVir(t) || isAna(t)) ? 0 : 1;
d.Sf["MA"+n].min = (isVir(t) || isAna(t)) ? 0 : 250;
}
gId("rf"+n).onclick = (t == 31) ? (()=>{return false}) : (()=>{}); // prevent change for TM1814
gRGBW |= hasW(t); // RGBW checkbox, TYPE_xxxx values from const.h
gId("co"+n).style.display = (isVir(t) || isAna(t)) ? "none":"inline"; // hide color order for PWM
gId("dig"+n+"w").style.display = (isDig(t) && hasW(t)) ? "inline":"none"; // show swap channels dropdown
gId("dig"+n+"w").querySelector("[data-opt=CCT]").disabled = !hasCCT(t); // disable WW/CW swapping
if (!(isDig(t) && hasW(t))) d.Sf["WO"+n].value = 0; // reset swapping
gId("dig"+n+"c").style.display = (isAna(t)) ? "none":"inline"; // hide count for analog
gId("dig"+n+"r").style.display = (isVir(t)) ? "none":"inline"; // hide reversed for virtual
gId("rf"+n).onclick = (t == 31) ? (()=>{return false}) : (()=>{}); // prevent change for TM1814
gRGBW |= hasW(t); // RGBW checkbox
gId("co"+n).style.display = (isVir(t) || isAna(t)) ? "none":"inline"; // hide color order for PWM
gId("dig"+n+"w").style.display = (isDig(t) && hasW(t)) ? "inline":"none"; // show swap channels dropdown
gId("dig"+n+"w").querySelector("[data-opt=CCT]").disabled = !hasCCT(t); // disable WW/CW swapping
if (!(isDig(t) && hasW(t))) d.Sf["WO"+n].value = 0; // reset swapping
gId("dig"+n+"c").style.display = (isAna(t)) ? "none":"inline"; // hide count for analog
gId("dig"+n+"r").style.display = (isVir(t)) ? "none":"inline"; // hide reversed for virtual
gId("dig"+n+"s").style.display = (isVir(t) || isAna(t)) ? "none":"inline"; // hide skip 1st for virtual & analog
gId("dig"+n+"f").style.display = (isDig(t)) ? "inline":"none"; // hide refresh
gId("dig"+n+"a").style.display = (hasW(t)) ? "inline":"none"; // auto calculate white
gId("dig"+n+"f").style.display = (isDig(t)) ? "inline":"none"; // hide refresh
gId("dig"+n+"a").style.display = (hasW(t)) ? "inline":"none"; // auto calculate white
gId("dig"+n+"l").style.display = (isD2P(t) || isPWM(t)) ? "inline":"none"; // bus clock speed / PWM speed (relative) (not On/Off)
gId("rev"+n).innerHTML = isAna(t) ? "Inverted output":"Reversed (rotated 180°)"; // change reverse text for analog
//gId("psd"+n).innerHTML = isAna(t) ? "Index:":"Start:"; // change analog start description
gId("rev"+n).innerHTML = isAna(t) ? "Inverted output":"Reversed"; // change reverse text for analog else (rotated 180°)
//gId("psd"+n).innerHTML = isAna(t) ? "Index:":"Start:"; // change analog start description
});
// display global white channel overrides
gId("wc").style.display = (gRGBW) ? 'inline':'none';
@@ -408,38 +419,7 @@
var cn = `<div class="iST">
<hr class="sml">
${i+1}:
<select name="LT${s}" onchange="UI(true)">${i>=maxB && false ? '' :
'<option value="22" data-type="D">WS281x</option>\
<option value="30" data-type="D">SK6812/WS2814 RGBW</option>\
<option value="31" data-type="D">TM1814</option>\
<option value="24" data-type="D">400kHz</option>\
<option value="25" data-type="D">TM1829</option>\
<option value="26" data-type="D">UCS8903</option>\
<option value="27" data-type="D">APA106/PL9823</option>\
<option value="33" data-type="D">TM1914</option>\
<option value="28" data-type="D">FW1906 GRBCW</option>\
<option value="29" data-type="D">UCS8904 RGBW</option>\
<option value="32" data-type="D">WS2805 RGBCW</option>\
<option value="34" data-type="D">SM16825 RGBCW</option>\
<option value="50" data-type="2P">WS2801</option>\
<option value="51" data-type="2P">APA102</option>\
<option value="52" data-type="2P">LPD8806</option>\
<option value="54" data-type="2P">LPD6803</option>\
<option value="53" data-type="2P">P9813</option>\
<option value="19" data-type="D">WS2811 White</option>\
<option value="40">On/Off</option>\
<option value="41" data-type="A">PWM White</option>\
<option value="42" data-type="AA">PWM CCT</option>\
<option value="43" data-type="AAA">PWM RGB</option>\
<option value="44" data-type="AAAA">PWM RGBW</option>\
<option value="45" data-type="AAAAA">PWM RGB+CCT</option>\
<!--option value="46" data-type="AAAAAA">PWM RGB+DCCT</option-->'}
<option value="80" data-type="V">DDP RGB (network)</option>
<!--option value="81" data-type="V">E1.31 RGB (network)</option-->
<option value="82" data-type="V">Art-Net RGB (network)</option>
<option value="88" data-type="V">DDP RGBW (network)</option>
<option value="89" data-type="V">Art-Net RGBW (network)</option>
</select><br>
<select name="LT${s}" onchange="UI(true)"></select><br>
<div id="abl${s}">
mA/LED: <select name="LAsel${s}" onchange="enLA(this,'${s}');UI();">
<option value="55" selected>55mA (typ. 5V WS281x)</option>
@@ -478,6 +458,21 @@ mA/LED: <select name="LAsel${s}" onchange="enLA(this,'${s}');UI();">
<div id="dig${s}a" style="display:inline"><br>Auto-calculate white channel from RGB:<br><select name="AW${s}"><option value=0>None</option><option value=1>Brighter</option><option value=2>Accurate</option><option value=3>Dual</option><option value=4>Max</option></select>&nbsp;</div>
</div>`;
f.insertAdjacentHTML("beforeend", cn);
// fill led types (credit @netmindz)
d.Sf.querySelectorAll("#mLC select[name^=LT]").forEach((sel,n)=>{
if (sel.length == 0) { // ignore already updated
for (let type of d.ledTypes) {
let opt = d.createElement("option");
opt.value = type.i;
opt.text = type.n;
if (type.t != undefined && type.t != "") {
opt.setAttribute('data-type', type.t);
}
sel.appendChild(opt);
}
}
});
// disable inappropriate LED types
let sel = d.getElementsByName("LT"+s)[0]
if (i >= maxB || digitalB >= maxD) disable(sel,'option[data-type="D"]');
if (i >= maxB || twopinB >= 1) disable(sel,'option[data-type="2P"]');
@@ -810,7 +805,7 @@ Swap: <select id="xw${s}" name="XW${s}">
Use per-output limiter: <input type="checkbox" name="PPL" onchange="UI()"><br>
<div id="ppldis" style="display:none;">
<i>Make sure you enter correct values in each LED output.<br>
If using multiple outputs with only one PSU, distribute its power proportionally amongst ouputs.</i><br>
If using multiple outputs with only one PSU, distribute its power proportionally amongst outputs.</i><br>
</div>
<div id="ampwarning" class="warn" style="display: none;">
&#9888; Your power supply provides high current.<br>