Dynamic allocation for bus manager.

This commit is contained in:
Blaz Kristan 2021-01-17 00:20:31 +01:00
parent d02bf37167
commit bb8d5ac13f
11 changed files with 585 additions and 243 deletions

38
wled00/FX.h Normal file → Executable file
View File

@ -27,36 +27,6 @@
#ifndef WS2812FX_h #ifndef WS2812FX_h
#define WS2812FX_h #define WS2812FX_h
//TEMPORARY DEFINES FOR TESTING - MAKE THESE RUNTIME CONFIGURABLE TOO!
#ifndef LEDPIN
#define LEDPIN 2
#endif
#ifndef BTNPIN
#define BTNPIN 0 //button pin. Needs to have pullup (gpio0 recommended)
#endif
#ifndef TOUCHPIN
//#define TOUCHPIN T0 //touch pin. Behaves the same as button. ESP32 only.
#endif
#ifndef IRPIN
#define IRPIN 4 //infrared pin (-1 to disable) MagicHome: 4, H801 Wifi: 0
#endif
#ifndef RLYPIN
#define RLYPIN 12 //pin for relay, will be set HIGH if LEDs are on (-1 to disable). Also usable for standby leds, triggers,...
#endif
#ifndef AUXPIN
#define AUXPIN -1 //debug auxiliary output pin (-1 to disable)
#endif
#ifndef RLYMDE
#define RLYMDE 1 //mode for relay, 0: LOW if LEDs are on 1: HIGH if LEDs are on
#endif
//END OF TEMP DEFINES
#ifdef ESP32_MULTISTRIP #ifdef ESP32_MULTISTRIP
#include "../usermods/esp32_multistrip/NpbWrapper.h" #include "../usermods/esp32_multistrip/NpbWrapper.h"
#else #else
@ -659,6 +629,8 @@ class WS2812FX {
paletteFade = 0, paletteFade = 0,
paletteBlend = 0, paletteBlend = 0,
milliampsPerLed = 55, milliampsPerLed = 55,
// getStripType(uint8_t strip=0),
// setStripType(uint8_t type, uint8_t strip=0),
getBrightness(void), getBrightness(void),
getMode(void), getMode(void),
getSpeed(void), getSpeed(void),
@ -673,11 +645,17 @@ class WS2812FX {
get_random_wheel_index(uint8_t); get_random_wheel_index(uint8_t);
int8_t int8_t
// setStripPin(uint8_t strip, int8_t pin),
// getStripPin(uint8_t strip=0),
// setStripPinClk(uint8_t strip, int8_t pin),
// getStripPinClk(uint8_t strip=0),
tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec); tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec);
uint16_t uint16_t
ablMilliampsMax, ablMilliampsMax,
currentMilliamps, currentMilliamps,
// setStripLen(uint8_t strip, uint16_t len),
// getStripLen(uint8_t strip=0),
triwave16(uint16_t); triwave16(uint16_t);
uint32_t uint32_t

0
wled00/FX_fcn.cpp Normal file → Executable file
View File

View File

@ -17,9 +17,7 @@ void shortPressAction()
bool isButtonPressed() bool isButtonPressed()
{ {
#if defined(BTNPIN) && BTNPIN > -1 if (btnPin>=0 && digitalRead(btnPin) == LOW) return true;
if (digitalRead(BTNPIN) == LOW) return true;
#endif
#ifdef TOUCHPIN #ifdef TOUCHPIN
if (touchRead(TOUCHPIN) <= TOUCH_THRESHOLD) return true; if (touchRead(TOUCHPIN) <= TOUCH_THRESHOLD) return true;
#endif #endif
@ -29,8 +27,7 @@ bool isButtonPressed()
void handleButton() void handleButton()
{ {
#if (defined(BTNPIN) && BTNPIN > -1) || defined(TOUCHPIN) if (btnPin<0 || !buttonEnabled) return;
if (!buttonEnabled) return;
if (isButtonPressed()) //pressed if (isButtonPressed()) //pressed
{ {
@ -75,7 +72,6 @@ void handleButton()
buttonWaitTime = 0; buttonWaitTime = 0;
shortPressAction(); shortPressAction();
} }
#endif
} }
void handleIO() void handleIO()
@ -88,37 +84,43 @@ void handleIO()
lastOnTime = millis(); lastOnTime = millis();
if (offMode) if (offMode)
{ {
#if RLYPIN >= 0 if (rlyPin>=0) {
digitalWrite(RLYPIN, RLYMDE); pinMode(rlyPin, OUTPUT);
#endif digitalWrite(rlyPin, rlyMde);
}
offMode = false; offMode = false;
} }
} else if (millis() - lastOnTime > 600) } else if (millis() - lastOnTime > 600)
{ {
if (!offMode) { if (!offMode) {
#if LEDPIN == LED_BUILTIN #ifdef ESP8266
for (uint8_t s=0; s<strip.numStrips; s++) {
if (strip.getStripPin(s)==LED_BUILTIN) {
pinMode(LED_BUILTIN, OUTPUT); pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH); digitalWrite(LED_BUILTIN, HIGH);
break;
}
}
#endif #endif
#if RLYPIN >= 0 if (rlyPin>=0) {
digitalWrite(RLYPIN, !RLYMDE); pinMode(rlyPin, OUTPUT);
#endif digitalWrite(rlyPin, !rlyMde);
}
} }
offMode = true; offMode = true;
} }
#if AUXPIN >= 0
//output //output
if (auxActive || auxActiveBefore) if (auxPin>=1 && (auxActive || auxActiveBefore))
{ {
if (!auxActiveBefore) if (!auxActiveBefore)
{ {
auxActiveBefore = true; auxActiveBefore = true;
switch (auxTriggeredState) switch (auxTriggeredState)
{ {
case 0: pinMode(AUXPIN, INPUT); break; case 0: pinMode(auxPin, INPUT); break;
case 1: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, HIGH); break; case 1: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, HIGH); break;
case 2: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, LOW); break; case 2: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, LOW); break;
} }
auxStartTime = millis(); auxStartTime = millis();
} }
@ -128,11 +130,10 @@ void handleIO()
auxActiveBefore = false; auxActiveBefore = false;
switch (auxDefaultState) switch (auxDefaultState)
{ {
case 0: pinMode(AUXPIN, INPUT); break; case 0: pinMode(auxPin, INPUT); break;
case 1: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, HIGH); break; case 1: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, HIGH); break;
case 2: pinMode(AUXPIN, OUTPUT); digitalWrite(AUXPIN, LOW); break; case 2: pinMode(auxPin, OUTPUT); digitalWrite(auxPin, LOW); break;
} }
} }
} }
#endif
} }

View File

@ -89,31 +89,59 @@ void deserializeConfig() {
JsonObject hw = doc[F("hw")]; JsonObject hw = doc[F("hw")];
// initialize LED pins and lengths prior to other HW
JsonObject hw_led = hw[F("led")]; JsonObject hw_led = hw[F("led")];
CJSON(ledCount, hw_led[F("total")]);
if (ledCount > MAX_LEDS) ledCount = MAX_LEDS;
// CJSON(ledCount, hw_led[F("total")]);
ledCount = 0;
CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]); CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]);
CJSON(strip.milliampsPerLed, hw_led[F("ledma")]); CJSON(strip.milliampsPerLed, hw_led[F("ledma")]);
CJSON(strip.reverseMode, hw_led[F("rev")]); CJSON(strip.reverseMode, hw_led[F("rev")]);
CJSON(strip.rgbwMode, hw_led[F("rgbwm")]); CJSON(strip.rgbwMode, hw_led[F("rgbwm")]);
JsonObject hw_led_ins_0 = hw_led[F("ins")][0]; JsonVariant strVar = hw_led["ins"];
//bool hw_led_ins_0_en = hw_led_ins_0[F("en")]; // true if (strVar.is<JsonObject>()) {
//int hw_led_ins_0_start = hw_led_ins_0[F("start")]; // 0 // some safety measures here?
//int hw_led_ins_0_len = hw_led_ins_0[F("len")]; // 1200 } else {
JsonArray elms = strVar.as<JsonArray>();
//int hw_led_ins_0_pin_0 = hw_led_ins_0[F("pin")][0]; // 2 uint8_t s=0;
for ( JsonObject elm : elms ) {
strip.setColorOrder(hw_led_ins_0[F("order")]); if (s>=WLED_MAX_BUSSES) break;
//bool hw_led_ins_0_rev = hw_led_ins_0[F("rev")]; // false int8_t pins[2] = {-1,-1};
skipFirstLed = hw_led_ins_0[F("skip")]; // 0 pins[0] = elm[F("pin")][0];
useRGBW = (hw_led_ins_0[F("type")] == TYPE_SK6812_RGBW); if (pins[0] >= 0 && pinManager.allocatePin(pins[0])) {
if (elm[F("pin")].size()==2) {
pins[1] = elm[F("pin")][1];
if (pins[1] >= 0)
if (!pinManager.allocatePin(pins[1])) {
pinManager.deallocatePin(pins[0]);
break; // pin not ok
}
}
} else {
break; // pin not ok
}
uint16_t length = elm[F("len")]);
if (length==0) break;
uint8_t colorOrder = (int)elm[F("order")];
uint8_t skipFirstLed = elm[F("skip")]; // 0
uint8_t ledType = elm[F("type")];
uint8_t useRGBW = ((ledType == TYPE_SK6812_RGBW) || ledType == TYPE_TM1814);
ledCount += length;
busses->add(ledType? TYPE_SK6812_RGBW : TYPE_WS2812_RGB, pins, 0, ledCount, colorOrder);
}
}
if (ledCount > MAX_LEDS) ledCount = MAX_LEDS;
JsonObject hw_btn_ins_0 = hw[F("btn")][F("ins")][0]; JsonObject hw_btn_ins_0 = hw[F("btn")][F("ins")][0];
buttonEnabled = hw_btn_ins_0[F("en")] | buttonEnabled; CJSON(buttonEnabled, hw_btn_ins_0[F("type")]);
int hw_btn_pin = hw_btn_ins_0[F("pin")][0];
//int hw_btn_ins_0_pin_0 = hw_btn_ins_0[F("pin")][0]; // 0 if (pinManager.allocatePin(hw_btn_pin,false)) {
btnPin = hw_btn_pin;
pinMode(btnPin, INPUT_PULLUP);
} else {
btnPin = -1;
}
JsonArray hw_btn_ins_0_macros = hw_btn_ins_0[F("macros")]; JsonArray hw_btn_ins_0_macros = hw_btn_ins_0[F("macros")];
CJSON(macroButton, hw_btn_ins_0_macros[0]); CJSON(macroButton, hw_btn_ins_0_macros[0]);
@ -122,11 +150,24 @@ void deserializeConfig() {
//int hw_btn_ins_0_type = hw_btn_ins_0[F("type")]; // 0 //int hw_btn_ins_0_type = hw_btn_ins_0[F("type")]; // 0
//int hw_ir_pin = hw[F("ir")][F("pin")]; // 4 #ifndef WLED_DISABLE_INFRARED
CJSON(irEnabled, hw[F("ir")][F("type")]); // 0 int hw_ir_pin = hw[F("ir")][F("pin")]; // 4
if (pinManager.allocatePin(hw_ir_pin,false)) {
irPin = hw_ir_pin;
} else {
irPin = -1;
}
#endif
CJSON(irEnabled, hw[F("ir")][F("type")]);
//int hw_relay_pin = hw[F("relay")][F("pin")]; // 12 int hw_relay_pin = hw[F("relay")][F("pin")];
//bool hw_relay_rev = hw[F("relay")][F("rev")]; // false if (pinManager.allocatePin(hw_relay_pin,true)) {
rlyPin = hw_relay_pin;
pinMode(rlyPin, OUTPUT);
} else {
rlyPin = -1;
}
CJSON(rlyMde, hw[F("relay")][F("rev")]);
//int hw_status_pin = hw[F("status")][F("pin")]; // -1 //int hw_status_pin = hw[F("status")][F("pin")]; // -1
@ -404,70 +445,57 @@ void serializeConfig() {
JsonArray hw_led_ins = hw_led.createNestedArray("ins"); JsonArray hw_led_ins = hw_led.createNestedArray("ins");
uint16_t start = 0;
for (uint8_t s=0; s<busses->getNumBusses(); s++) {
Bus *bus = busses->getBus(s);
if (!bus || bus->getLength()==0) break;
JsonObject hw_led_ins_0 = hw_led_ins.createNestedObject(); JsonObject hw_led_ins_0 = hw_led_ins.createNestedObject();
hw_led_ins_0[F("en")] = true; hw_led_ins_0[F("en")] = true;
hw_led_ins_0[F("start")] = 0; hw_led_ins_0[F("start")] = start;
hw_led_ins_0[F("len")] = ledCount; start += bus->getLength();
hw_led_ins_0[F("len")] = bus->getLength();
JsonArray hw_led_ins_0_pin = hw_led_ins_0.createNestedArray("pin"); JsonArray hw_led_ins_0_pin = hw_led_ins_0.createNestedArray("pin");
hw_led_ins_0_pin.add(LEDPIN); hw_led_ins_0_pin.add(bus->getBusPins(s)[0]);
#ifdef DATAPIN if (bus->getBusPins(s)[1]>=0) hw_led_ins_0_pin.add(bus->getBusPins(s)[1]);
hw_led_ins_0_pin.add(DATAPIN); hw_led_ins_0[F("order")] = bus->getColorOrder();
#endif
hw_led_ins_0[F("order")] = strip.getColorOrder();
hw_led_ins_0[F("rev")] = false; hw_led_ins_0[F("rev")] = false;
hw_led_ins_0[F("skip")] = skipFirstLed ? 1 : 0; hw_led_ins_0[F("skip")] = skipFirstLed ? 1 : 0;
hw_led_ins_0[F("type")] = bus->getType();
//this is very crude and temporary }
byte ledType = TYPE_WS2812_RGB;
if (useRGBW) ledType = TYPE_SK6812_RGBW;
#ifdef USE_WS2801
ledType = TYPE_WS2801;
#endif
#ifdef USE_APA102
ledType = TYPE_APA102;
#endif
#ifdef USE_LPD8806
ledType = TYPE_LPD8806;
#endif
#ifdef USE_P9813
ledType = TYPE_P9813;
#endif
#ifdef USE_TM1814
ledType = TYPE_TM1814;
#endif
hw_led_ins_0[F("type")] = ledType;
JsonObject hw_btn = hw.createNestedObject("btn"); JsonObject hw_btn = hw.createNestedObject("btn");
JsonArray hw_btn_ins = hw_btn.createNestedArray("ins"); JsonArray hw_btn_ins = hw_btn.createNestedArray("ins");
#if defined(BTNPIN) && BTNPIN > -1 // button BTNPIN
JsonObject hw_btn_ins_0 = hw_btn_ins.createNestedObject(); JsonObject hw_btn_ins_0 = hw_btn_ins.createNestedObject();
hw_btn_ins_0[F("type")] = (buttonEnabled) ? BTN_TYPE_PUSH : BTN_TYPE_NONE; hw_btn_ins_0[F("type")] = (buttonEnabled) ? BTN_TYPE_PUSH : BTN_TYPE_NONE;
JsonArray hw_btn_ins_0_pin = hw_btn_ins_0.createNestedArray("pin"); JsonArray hw_btn_ins_0_pin = hw_btn_ins_0.createNestedArray("pin");
hw_btn_ins_0_pin.add(BTNPIN); hw_btn_ins_0_pin.add(btnPin);
JsonArray hw_btn_ins_0_macros = hw_btn_ins_0.createNestedArray("macros"); JsonArray hw_btn_ins_0_macros = hw_btn_ins_0.createNestedArray("macros");
hw_btn_ins_0_macros.add(macroButton); hw_btn_ins_0_macros.add(macroButton);
hw_btn_ins_0_macros.add(macroLongPress); hw_btn_ins_0_macros.add(macroLongPress);
hw_btn_ins_0_macros.add(macroDoublePress); hw_btn_ins_0_macros.add(macroDoublePress);
#endif
#if defined(IRPIN) && IRPIN > -1 #ifndef WLED_DISABLE_INFRARED
if (irPin>=0) {
JsonObject hw_ir = hw.createNestedObject("ir"); JsonObject hw_ir = hw.createNestedObject("ir");
hw_ir[F("pin")] = IRPIN; hw_ir[F("pin")] = irPin;
hw_ir[F("type")] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled ) hw_ir[F("type")] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled )
}
#endif #endif
#if defined(RLYPIN) && RLYPIN > -1
JsonObject hw_relay = hw.createNestedObject("relay"); JsonObject hw_relay = hw.createNestedObject("relay");
hw_relay[F("pin")] = RLYPIN; hw_relay[F("pin")] = rlyPin;
hw_relay[F("rev")] = (RLYMDE) ? false : true; hw_relay[F("rev")] = rlyMde;
JsonObject hw_status = hw.createNestedObject("status");
hw_status[F("pin")] = -1; //JsonObject hw_status = hw.createNestedObject("status");
#endif //hw_status[F("pin")] = -1;
JsonObject hw_aux = hw.createNestedObject("aux");
hw_aux[F("pin")] = auxPin;
JsonObject light = doc.createNestedObject("light"); JsonObject light = doc.createNestedObject("light");
light[F("scale-bri")] = briMultiplier; light[F("scale-bri")] = briMultiplier;

172
wled00/data/settings_leds.htm Normal file → Executable file
View File

@ -52,13 +52,53 @@
myC[i].style.display = (d.getElementById('rgbw').checked) ? 'inline':'none'; myC[i].style.display = (d.getElementById('rgbw').checked) ? 'inline':'none';
} }
d.getElementById('ledwarning').style.display = (d.Sf.LC.value > 1000) ? 'inline':'none';
d.getElementById('ampwarning').style.display = (d.Sf.MA.value > 7200) ? 'inline':'none'; d.getElementById('ampwarning').style.display = (d.Sf.MA.value > 7200) ? 'inline':'none';
if (d.Sf.LA.value == 255) laprev = 12; if (d.Sf.LA.value == 255) laprev = 12;
else if (d.Sf.LA.value > 0) laprev = d.Sf.LA.value; else if (d.Sf.LA.value > 0) laprev = d.Sf.LA.value;
var val = Math.ceil((100 + d.Sf.LC.value * laprev)/500)/2; var s = d.getElementsByTagName("select");
for (i=0; i<s.length; i++) {
if (s[i].name.substring(0,5)=="LTsel") {
n=s[i].name.substring(5);
d.getElementsByName("EW"+n)[0].checked = (parseInt(s[i].value)==30||parseInt(s[i].value)==54); // TYPE_xxxx values from const.h
var LK = d.getElementsByName("LK"+n)[0];
var o = d.getElementsByName("iLK");
n=(n==""?0:parseInt(n,10));
if (s[i].value>49 && s[i].value!=54) // TYPE_xxxx values from const.h
{
o[n].style = "display:inline;";
LK.required = true;
} else {
o[n].style = "display:none;";
LK.required = false;
LK.value="";
}
}
}
var LCs = d.getElementsByTagName("input");
var sLC = 0;
for (i=0; i<LCs.length; i++) {
var nm = LCs[i].name.substring(0,2);
if (nm=="LC") {sLC+=parseInt(LCs[i].value,10);continue;}
if (nm=="LP") {var lc=d.getElementsByName("LC"+LCs[i].name.substring(2))[0]; if(LCs[i].value==3) lc.max=500; else lc.max=1500;}
if (nm=="LP" || nm=="LK" || nm=="RL" || nm=="BT" || nm=="IR" || nm=="AX")
if (LCs[i].value!="" && LCs[i].value!="-1") {
if (d.um_p && d.um_p.some((e)=>e==parseInt(LCs[i].value,10))) {alert("Usermod pin clash!");LCs[i].value="";LCs[i].focus();continue;}
for (j=0; j<LCs.length; j++)
{
if (i==j) continue;
var n2 = LCs[j].name.substring(0,2);
if (n2=="LP" || n2=="LK" || n2=="RL" || n2=="BT" || n2=="IR" || n2=="AX")
if (LCs[j].value!="" && LCs[i].value==LCs[j].value) {alert("Pin clash!");LCs[i].value="";LCs[i].focus();break;}
}
}
}
d.getElementById('ledwarning').style.display = (sLC > 1000) ? 'inline':'none';
//var val = Math.ceil((100 + d.Sf.LC.value * laprev)/500)/2;
var val = Math.ceil((100 + sLC * laprev)/500)/2;
val = (val > 5) ? Math.ceil(val) : val; val = (val > 5) ? Math.ceil(val) : val;
var s = ""; var s = "";
var is12V = (d.Sf.LAsel.value == 30); var is12V = (d.Sf.LAsel.value == 30);
@ -79,6 +119,86 @@
s2 += "A is enough)<br>"; s2 += "A is enough)<br>";
d.getElementById('psu').innerHTML = s; d.getElementById('psu').innerHTML = s;
d.getElementById('psu2').innerHTML = isWS2815 ? "" : s2; d.getElementById('psu2').innerHTML = isWS2815 ? "" : s2;
}
function addLEDs(n)
{
if (n>1) {d.maxST=n; d.getElementById("+").style="display:inline;"; return;}
var o = d.getElementsByName("iST");
var i = o.length;
if ((n==1 && i>=d.maxST) || (n==-1 && i<=1)) return;
var f = d.getElementById("mLC");
if (n==1) {
var s, t = d.createElement("div");
t.setAttribute("name","iST");
t.appendChild(d.createTextNode((i+1)+": "));
s = d.createElement("select");
s.setAttribute("name","LTsel"+i);
s.onchange = function(){UI()}
o = d.createElement("option"); o.text = "WS281x"; o.value = "22"; s.add(o);
o = d.createElement("option"); o.text = "SK6812"; o.value = "30"; s.add(o);
o = d.createElement("option"); o.text = "WS2801"; o.value = "50"; s.add(o);
o = d.createElement("option"); o.text = "APA102"; o.value = "51"; s.add(o);
o = d.createElement("option"); o.text = "LPD8806"; o.value = "52"; s.add(o);
o = d.createElement("option"); o.text = "P9813"; o.value = "53"; s.add(o);
o = d.createElement("option"); o.text = "TM1814"; o.value = "54"; s.add(o);
t.appendChild(s);
t.appendChild(d.createTextNode(" CO: "));
s = d.createElement("select");
s.setAttribute("name","CO"+i);
o = d.createElement("option"); o.text = "GRB"; o.value = "0"; s.add(o);
o = d.createElement("option"); o.text = "RGB"; o.value = "1"; s.add(o);
o = d.createElement("option"); o.text = "BRG"; o.value = "2"; s.add(o);
o = d.createElement("option"); o.text = "RBG"; o.value = "3"; s.add(o);
o = d.createElement("option"); o.text = "BGR"; o.value = "4"; s.add(o);
o = d.createElement("option"); o.text = "GBR"; o.value = "5"; s.add(o);
t.appendChild(s);
t.appendChild(d.createTextNode(" RGBW: "));
s = d.createElement("input");
s.type = "checkbox";
s.setAttribute("name","EW"+i);
t.appendChild(s);
t.appendChild(d.createElement("br"));
t.appendChild(d.createTextNode("pin:"));
var e = d.createElement("input");
e.type = "number"; e.value = ""; e.name = "LP"+i; e.min=0; e.max=40; e.required=true; e.onchange=function(){UI()};
t.appendChild(e);
var b = d.createElement("div");
b.setAttribute("name","iLK");
b.appendChild(d.createTextNode(" clk:"));
e = d.createElement("input");
e.type = "number"; e.value = ""; e.name = "LK"+i; e.min=0; e.max=40; e.onchange=function(){UI()};
if (d.getElementsByName("LTsel")[0].value>49) e.required = true;
b.appendChild(e);
t.appendChild(b);
t.appendChild(d.createTextNode(" count:"));
e = d.createElement("input");
e.type = "number"; e.value = "0"; e.name = "LC"+i; e.min=0; e.max=1000; e.required=true; e.oninput = function(){UI()};
t.appendChild(e);
t.appendChild(d.createElement("br"));
f.appendChild(t);
}
if (n==-1) {
o[--i].remove();--i;
}
var p = d.getElementById("+");
var m = d.getElementById("-");
if (i<d.maxST-1) {p.style="display:inline";} else {p.style="display:none";}
if (i>0) {m.style="display:inline";} else {m.style="display:none";}
UI();
} }
function GetV() function GetV()
{ {
@ -93,8 +213,40 @@
<form id="form_s" name="Sf" method="post"> <form id="form_s" name="Sf" method="post">
<div class="helpB"><button type="button" onclick="H()">?</button></div> <div class="helpB"><button type="button" onclick="H()">?</button></div>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr> <button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
<h2>LED setup</h2> <h2>LED &amp; HW setup</h2>
LED count: <input name="LC" type="number" min="1" max="1500" oninput="UI()" required><br> LED strips
<button type="button" id="+" onclick="addLEDs(1)" style="display:none;">+</button><button type="button" id="-" onclick="addLEDs(-1)" style="display:none;">-</button><br>
<div id="mLC">
<div name="iST">
1:
<select name="LTsel" onchange="UI()">
<option value="22">WS281x</option><!--TYPE_WS2812_RGB-->
<option value="30">SK6812</option><!--TYPE_WS2812_RGB-->
<option value="50">WS2801</option><!--TYPE_WS2801-->
<option value="51">APA102</option><!--TYPE_APA102-->
<option value="52">LPD8806</option><!--TYPE_LPD8806-->
<option value="53">P9813</option><!--TYPE_P9813-->
<option value="54">TM1814</option><!--TYPE_TM1814-->
</select>
CO:
<select name="CO">
<option value=0>GRB</option>
<option value=1>RGB</option>
<option value=2>BRG</option>
<option value=3>RBG</option>
<option value=4>BGR</option>
<option value=5>GBR</option>
</select>
RGBW: <input type="checkbox" name="EW" onchange=UI() id="rgbw"><br>
pin:<input name="LP" type="number" min="0" max="40" required onchange="UI()">
<div name="iLK" style="display:inline;">clk:<input name="LK" type="number" min="0" max="40" onchange="UI()"></div>
count:<input name="LC" type="number" min="1" max="1500" oninput="UI()" required>
</div>
</div><hr>
Relay pin: <input type="number" min="-1" max="40" name="RL" onchange="UI()"> Active high? <input type="checkbox" name="RM"><br>
Button pin: <input type="number" min="-1" max="40" name="BT" onchange="UI()"><br>
IR pin: <input type="number" min="-1" max="40" name="IR" onchange="UI()"><br>
AUX pin: <input type="number" min="-1" max="40" name="AX" onchange="UI()"><hr>
<div id="ledwarning" style="color: orange; display: none;"> <div id="ledwarning" style="color: orange; display: none;">
&#9888; You might run into stability or lag issues.<br> &#9888; You might run into stability or lag issues.<br>
Use less than 1000 LEDs per ESP for the best experience!<br> Use less than 1000 LEDs per ESP for the best experience!<br>
@ -128,10 +280,9 @@
<i>Keep at default if you are unsure about your type of LEDs.</i><br> <i>Keep at default if you are unsure about your type of LEDs.</i><br>
</div> </div>
<br> <br>
LEDs are 4-channel type (RGBW): <input type="checkbox" name="EW" onchange=UI() id="rgbw"><br>
<span class="wc"> <span class="wc">
Auto-calculate white channel from RGB:<br> Auto-calculate white channel from RGB:<br>
<select name=AW> <select name="AW">
<option value=0>None</option> <option value=0>None</option>
<option value=1>Brighter</option> <option value=1>Brighter</option>
<option value=2>Accurate</option> <option value=2>Accurate</option>
@ -139,15 +290,6 @@
<option value=4>Legacy</option> <option value=4>Legacy</option>
</select> </select>
<br></span> <br></span>
Color order:
<select name="CO">
<option value=0>GRB</option>
<option value=1>RGB</option>
<option value=2>BRG</option>
<option value=3>RBG</option>
<option value=4>BGR</option>
<option value=5>GBR</option>
</select>
<h3>Defaults</h3> <h3>Defaults</h3>
Turn LEDs on after power up/reset: <input type="checkbox" name="BO"><br> Turn LEDs on after power up/reset: <input type="checkbox" name="BO"><br>
Default brightness: <input name="CA" type="number" min="0" max="255" required> (0-255)<br><br> Default brightness: <input name="CA" type="number" min="0" max="255" required> (0-255)<br><br>

File diff suppressed because one or more lines are too long

View File

@ -488,7 +488,7 @@ void initIR()
{ {
if (irEnabled > 0) if (irEnabled > 0)
{ {
irrecv = new IRrecv(IRPIN); irrecv = new IRrecv(irPin);
irrecv->enableIRIn(); irrecv->enableIRIn();
} }
} }

View File

@ -75,18 +75,123 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
//LED SETTINGS //LED SETTINGS
if (subPage == 2) if (subPage == 2)
{ {
int t = request->arg(F("LC")).toInt(); String LC=F("LC"), LP=F("LP"), LK=F("LK"), CO=F("CO"), LTsel=F("LTsel");
int8_t pin;
int t;
// deallocate all pins
for (uint8_t s=0; s<busses->getNumBuses(); s++) {
Bus *bus = busses->getBus(s);
pinManager.deallocatePin(bus->getPins()[0]);
pinManager.deallocatePin(bus->getPins()[1]);
}
if (rlyPin>=0 && pinManager.isPinAllocated(rlyPin)) pinManager.deallocatePin(rlyPin);
#ifndef WLED_DISABLE_INFRARED
if (irPin>=0 && pinManager.isPinAllocated(irPin)) pinManager.deallocatePin(irPin);
#endif
if (btnPin>=0 && pinManager.isPinAllocated(btnPin)) pinManager.deallocatePin(btnPin);
// remove all busses
busses->removeAll();
// initial bus
uint8_t colorOrder, type;
uint8_t ledType = request->arg(LTsel).toInt();
uint16_t length;
int8_t pins[2] = {-1,-1};
pins[0] = request->arg(LP).toInt();
if (pinManager.allocatePin(pins[0])) {
t = length = request->arg(LC).toInt();
if ( request->hasArg(LK.c_str()) ) {
pins[1] = (request->arg(LK)).length() > 0 ? request->arg(LK).toInt() : -1;
if (pinManager.allocatePin(pins[1])) {
} else {
// fallback
pins[1] = -1;
}
}
colorOrder = request->arg(CO).toInt();
type = request->arg(LTsel).toInt();
busses->add(type? TYPE_SK6812_RGBW : TYPE_WS2812_RGB, pins, 0, length, colorOrder);
} else {
// fallback
}
// secondary busses
for (uint8_t i=1; i<WLED_MAX_BUSSES; i++) {
if ( request->hasArg((LP+i).c_str()) ) {
pins[0] = request->arg((LP+i).c_str()).toInt();
if (pinManager.allocatePin(pins[0])) {
if ( request->hasArg((LK+i).c_str()) ) {
pins[1] = (request->arg(LK+i)).length() > 0 ? request->arg((LK+i).c_str()).toInt() : -1;
if (pins[1]>=0) {
pinManager.allocatePin(pins[1]);
}
}
} else {
DEBUG_PRINTLN(F("Pin not ok."));
type = TYPE_NONE;
break; // pin not ok
}
type = request->arg((LTsel+i).c_str()).toInt();
} else {
DEBUG_PRINTLN("No data.");
type = TYPE_NONE;
break; // no parameter
}
if ( request->hasArg((LC+i).c_str()) && request->arg((LC+i).c_str()).toInt() > 0 ) {
t += lenght = request->arg((LC+i).c_str()).toInt();
} else {
type = TYPE_NONE;
break; // no parameter
}
colorOrder = request->arg((CO+i).c_str()).toInt();
busses->add(type? TYPE_SK6812_RGBW : TYPE_WS2812_RGB, pins, 0, length, colorOrder);
}
// what to do with these?
if (t > 0 && t <= MAX_LEDS) ledCount = t; if (t > 0 && t <= MAX_LEDS) ledCount = t;
#ifdef ESP8266 #ifdef ESP8266
#if LEDPIN == 3 if ( pinManager.isPinAllocated(3) && ledCount > MAX_LEDS_DMA) ledCount = MAX_LEDS_DMA; //DMA method uses too much ram
if (ledCount > MAX_LEDS_DMA) ledCount = MAX_LEDS_DMA; //DMA method uses too much ram
#endif #endif
// upate other pins
#ifndef WLED_DISABLE_INFRARED
int hw_ir_pin = request->arg(F("IR")).toInt();
if (pinManager.isPinOk(hw_ir_pin) && pinManager.allocatePin(hw_ir_pin,false)) {
irPin = hw_ir_pin;
} else {
irPin = -1;
}
#endif #endif
int hw_rly_pin = request->arg(F("RL")).toInt();
if (pinManager.allocatePin(hw_rly_pin,true)) {
rlyPin = hw_rly_pin;
} else {
rlyPin = -1;
}
rlyMde = (bool)request->hasArg(F("RM"));
int hw_btn_pin = request->arg(F("BT")).toInt();
if (pinManager.allocatePin(hw_btn_pin,false)) {
btnPin = hw_btn_pin;
pinMode(btnPin, INPUT_PULLUP);
} else {
btnPin = -1;
}
int hw_aux_pin = request->arg(F("AX")).toInt();
if (pinManager.allocatePin(hw_aux_pin,true)) {
auxPin = hw_aux_pin;
} else {
auxPin = -1;
}
strip.ablMilliampsMax = request->arg(F("MA")).toInt(); strip.ablMilliampsMax = request->arg(F("MA")).toInt();
strip.milliampsPerLed = request->arg(F("LA")).toInt(); strip.milliampsPerLed = request->arg(F("LA")).toInt();
useRGBW = request->hasArg(F("EW")); useRGBW = request->hasArg(F("EW"));
strip.setColorOrder(request->arg(F("CO")).toInt());
strip.rgbwMode = request->arg(F("AW")).toInt(); strip.rgbwMode = request->arg(F("AW")).toInt();
briS = request->arg(F("CA")).toInt(); briS = request->arg(F("CA")).toInt();
@ -328,8 +433,8 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
DMXFixtureMap[i] = t; DMXFixtureMap[i] = t;
} }
} }
#endif #endif
if (subPage != 6 || !doReboot) serializeConfig(); //do not save if factory reset if (subPage != 6 || !doReboot) serializeConfig(); //do not save if factory reset
if (subPage == 2) { if (subPage == 2) {
strip.init(useRGBW,ledCount,skipFirstLed); strip.init(useRGBW,ledCount,skipFirstLed);
@ -646,15 +751,15 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
} }
if (nightlightMode > NL_MODE_SUN) nightlightMode = NL_MODE_SUN; if (nightlightMode > NL_MODE_SUN) nightlightMode = NL_MODE_SUN;
#if AUXPIN >= 0
//toggle general purpose output //toggle general purpose output
if (auxPin>=0) {
pos = req.indexOf(F("AX=")); pos = req.indexOf(F("AX="));
if (pos > 0) { if (pos > 0) {
auxTime = getNumVal(&req, pos); auxTime = getNumVal(&req, pos);
auxActive = true; auxActive = true;
if (auxTime == 0) auxActive = false; if (auxTime == 0) auxActive = false;
} }
#endif }
pos = req.indexOf(F("TT=")); pos = req.indexOf(F("TT="));
if (pos > 0) transitionDelay = getNumVal(&req, pos); if (pos > 0) transitionDelay = getNumVal(&req, pos);

49
wled00/wled.cpp Normal file → Executable file
View File

@ -288,7 +288,15 @@ void WLED::setup()
updateFSInfo(); updateFSInfo();
deserializeConfig(); deserializeConfig();
#if STATUSLED && STATUSLED != LEDPIN #if STATUSLED
bool lStatusLed = false;
for (uint8_t i=0; i<strip.numStrips; i++) {
if (strip.getStripPin(i)==STATUSLED) {
lStatusLed = true;
break;
}
}
if (!lStatusLed)
pinMode(STATUSLED, OUTPUT); pinMode(STATUSLED, OUTPUT);
#endif #endif
@ -302,7 +310,8 @@ void WLED::setup()
WiFi.persistent(false); WiFi.persistent(false);
WiFi.onEvent(WiFiEvent); WiFi.onEvent(WiFiEvent);
Serial.println(F("Ada")); // Serial.println(F("Ada"));
DEBUG_PRINTLN(F("Ada"));
// generate module IDs // generate module IDs
escapedMac = WiFi.macAddress(); escapedMac = WiFi.macAddress();
@ -346,12 +355,6 @@ void WLED::setup()
void WLED::beginStrip() void WLED::beginStrip()
{ {
// Initialize NeoPixel Strip and button // Initialize NeoPixel Strip and button
#ifdef ESP8266
#if LEDPIN == 3
if (ledCount > MAX_LEDS_DMA)
ledCount = MAX_LEDS_DMA; // DMA method uses too much ram
#endif
#endif
if (ledCount > MAX_LEDS || ledCount == 0) if (ledCount > MAX_LEDS || ledCount == 0)
ledCount = 30; ledCount = 30;
@ -360,11 +363,6 @@ void WLED::beginStrip()
strip.setBrightness(0); strip.setBrightness(0);
strip.setShowCallback(handleOverlayDraw); strip.setShowCallback(handleOverlayDraw);
#if defined(BTNPIN) && BTNPIN > -1
pinManager.allocatePin(BTNPIN, false);
pinMode(BTNPIN, INPUT_PULLUP);
#endif
if (bootPreset > 0) applyPreset(bootPreset); if (bootPreset > 0) applyPreset(bootPreset);
if (turnOnAtBoot) { if (turnOnAtBoot) {
if (briS > 0) bri = briS; if (briS > 0) bri = briS;
@ -375,23 +373,12 @@ void WLED::beginStrip()
colorUpdated(NOTIFIER_CALL_MODE_INIT); colorUpdated(NOTIFIER_CALL_MODE_INIT);
// init relay pin // init relay pin
#if RLYPIN >= 0 if (rlyPin>=0)
pinManager.allocatePin(RLYPIN); digitalWrite(rlyPin, (rlyMde ? bri : !bri));
pinMode(RLYPIN, OUTPUT);
#if RLYMDE
digitalWrite(RLYPIN, bri);
#else
digitalWrite(RLYPIN, !bri);
#endif
#endif
// disable button if it is "pressed" unintentionally // disable button if it is "pressed" unintentionally
#if (defined(BTNPIN) && BTNPIN > -1) || defined(TOUCHPIN) if (btnPin>=0 && isButtonPressed())
if (isButtonPressed())
buttonEnabled = false; buttonEnabled = false;
#else
buttonEnabled = false;
#endif
} }
void WLED::initAP(bool resetAP) void WLED::initAP(bool resetAP)
@ -637,7 +624,13 @@ void WLED::handleConnection()
void WLED::handleStatusLED() void WLED::handleStatusLED()
{ {
#if STATUSLED && STATUSLED != LEDPIN #if STATUSLED
for (uint8_t s=0; s<strip.numStrips; s++) {
if (strip.getStripPin(s)==STATUSLED) {
return; // pin used for strip
}
}
ledStatusType = WLED_CONNECTED ? 0 : 2; ledStatusType = WLED_CONNECTED ? 0 : 2;
if (mqttEnabled && ledStatusType != 2) // Wi-Fi takes presendence over MQTT if (mqttEnabled && ledStatusType != 2) // Wi-Fi takes presendence over MQTT
ledStatusType = WLED_MQTT_CONNECTED ? 0 : 4; ledStatusType = WLED_MQTT_CONNECTED ? 0 : 4;

View File

@ -131,7 +131,7 @@
Comment out this error message to build regardless. Comment out this error message to build regardless.
#endif #endif
#if IRPIN < 0 #if !defined(IRPIN) || IRPIN < 0
#ifndef WLED_DISABLE_INFRARED #ifndef WLED_DISABLE_INFRARED
#define WLED_DISABLE_INFRARED #define WLED_DISABLE_INFRARED
#endif #endif
@ -184,13 +184,29 @@ WLED_GLOBAL char otaPass[33] _INIT(DEFAULT_OTA_PASS);
// Hardware CONFIG (only changeble HERE, not at runtime) // Hardware CONFIG (only changeble HERE, not at runtime)
// LED strip pin, button pin and IR pin changeable in NpbWrapper.h! // LED strip pin, button pin and IR pin changeable in NpbWrapper.h!
#ifndef BTNPIN
WLED_GLOBAL int8_t btnPin _INIT(-1);
#else
WLED_GLOBAL int8_t btnPin _INIT(BTNPIN);
#endif
#ifndef RLYPIN
WLED_GLOBAL int8_t rlyPin _INIT(-1);
#else
WLED_GLOBAL int8_t rlyPin _INIT(RLYPIN);
#endif
#ifndef RLYMDE
WLED_GLOBAL bool rlyMde _INIT(1);
#else
WLED_GLOBAL bool rlyMde _INIT(RLYMDE);
#endif
#ifndef IRPIN
WLED_GLOBAL int8_t irPin _INIT(-1);
#else
WLED_GLOBAL int8_t irPin _INIT(IRPIN);
#endif
//WLED_GLOBAL byte presetToApply _INIT(0); //WLED_GLOBAL byte presetToApply _INIT(0);
#if AUXPIN >= 0
WLED_GLOBAL byte auxDefaultState _INIT(0); // 0: input 1: high 2: low
WLED_GLOBAL byte auxTriggeredState _INIT(0); // 0: input 1: high 2: low
#endif
WLED_GLOBAL char ntpServerName[33] _INIT("0.wled.pool.ntp.org"); // NTP server to use WLED_GLOBAL char ntpServerName[33] _INIT("0.wled.pool.ntp.org"); // NTP server to use
// WiFi CONFIG (all these can be changed via web UI, no need to set them here) // WiFi CONFIG (all these can be changed via web UI, no need to set them here)
@ -463,12 +479,18 @@ WLED_GLOBAL long lastInterfaceUpdate _INIT(0);
WLED_GLOBAL byte interfaceUpdateCallMode _INIT(NOTIFIER_CALL_MODE_INIT); WLED_GLOBAL byte interfaceUpdateCallMode _INIT(NOTIFIER_CALL_MODE_INIT);
WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers WLED_GLOBAL char mqttStatusTopic[40] _INIT(""); // this must be global because of async handlers
#if AUXPIN >= 0
// auxiliary debug pin // auxiliary debug pin
#ifndef AUXPIN
WLED_GLOBAL int8_t auxPin _INIT(-1);
#else
WLED_GLOBAL int8_t auxPin _INIT(AUXPIN);
#endif
WLED_GLOBAL byte auxTime _INIT(0); WLED_GLOBAL byte auxTime _INIT(0);
WLED_GLOBAL unsigned long auxStartTime _INIT(0); WLED_GLOBAL unsigned long auxStartTime _INIT(0);
WLED_GLOBAL bool auxActive _INIT(false, auxActiveBefore _INIT(false); WLED_GLOBAL bool auxActive _INIT(false);
#endif WLED_GLOBAL bool auxActiveBefore _INIT(false);
WLED_GLOBAL byte auxDefaultState _INIT(0); // 0: input 1: high 2: low
WLED_GLOBAL byte auxTriggeredState _INIT(0); // 0: input 1: high 2: low
// alexa udp // alexa udp
WLED_GLOBAL String escapedMac; WLED_GLOBAL String escapedMac;
@ -532,8 +554,10 @@ WLED_GLOBAL WS2812FX strip _INIT(WS2812FX());
// Usermod manager // Usermod manager
WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager()); WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager());
WLED_GLOBAL PinManagerClass pinManager _INIT(PinManagerClass());
// Status LED // Status LED
#if STATUSLED && STATUSLED != LEDPIN #if STATUSLED
WLED_GLOBAL unsigned long ledStatusLastMillis _INIT(0); WLED_GLOBAL unsigned long ledStatusLastMillis _INIT(0);
WLED_GLOBAL unsigned short ledStatusType _INIT(0); // current status type - corresponds to number of blinks per second WLED_GLOBAL unsigned short ledStatusType _INIT(0); // current status type - corresponds to number of blinks per second
WLED_GLOBAL bool ledStatusState _INIT(0); // the current LED state WLED_GLOBAL bool ledStatusState _INIT(0); // the current LED state

63
wled00/xml.cpp Normal file → Executable file
View File

@ -254,14 +254,66 @@ void getSettingsJS(byte subPage, char* dest)
} }
if (subPage == 2) { if (subPage == 2) {
char nS[3];
// add usermod pins as d.um_p array
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
JsonObject mods = doc.createNestedObject(F("mods"));
usermods.addToJsonState(mods);
if (!mods.isNull()) {
uint8_t i=0;
oappend(SET_F("d.um_p=["));
for (JsonPair kv : mods) {
if (strncmp_P(kv.key().c_str(),PSTR("pin_"),4) == 0) {
if (i++) oappend(SET_F(","));
oappend(itoa((int)kv.value(),nS,10));
}
}
oappend(SET_F("];"));
}
#if defined(WLED_MAX_BUSSES) && WLED_MAX_BUSSES>1
oappend(SET_F("addLEDs("));
oappend(itoa(WLED_MAX_BUSSES,nS,10));
oappend(SET_F(");"));
#endif
Bus *bus = busses->getBus(0);
#ifdef ESP8266 #ifdef ESP8266
#if LEDPIN == 3 if (bus->getPins()[0]==3)
oappend(SET_F("d.Sf.LC.max=500;")); oappend(SET_F("d.Sf.LC.max=500;"));
#else else
oappend(SET_F("d.Sf.LC.max=1500;")); oappend(SET_F("d.Sf.LC.max=1500;"));
#endif #endif
//sappend('v',SET_F("LC"),ledCount);
sappend('v',SET_F("LP"),bus->getPins()[0]);
if (bus->getPins()[1]>=0) sappend('v',SET_F("LK"),bus->getPins()[1]);
sappend('v',SET_F("LC"),bus->getLength());
sappend('v',SET_F("LTsel"),bus->getType());
sappend('v',SET_F("CO"),bus->getColorOrder());
for (uint8_t s=1; s<busses->getNumBusses(); s++){
bus = busses->getBus(s);
String LP = F("LP"), LK = F("LK"), LC = F("LC"), CO = F("CO"), LTsel = F("LTsel");
LP += s; LK += s; LC += s; CO += s; LTsel += s;
oappend(SET_F("addLEDs(1);"));
sappend('v',LP.c_str(),bus->getPins()[0]);
if (bus->getPins()[1]>=0) sappend('v',LK.c_str(),bus->getPins()[1]);
sappend('v',LC.c_str(),bus->getLength());
#ifdef ESP8266
if (bus->getPins()[0]==3) {
oappend(SET_F("d.Sf."));
oappend(LC.c_str());
oappend(SET_F(".max=500;"));
} else {
oappend(SET_F("d.Sf."));
oappend(LC.c_str());
oappend(SET_F(".max=1500;"));
}
#endif #endif
sappend('v',SET_F("LC"),ledCount); sappend('v',LTsel.c_str(),bus->getType());
sappend('v',CO.c_str(),bus->getColorOrder());
}
sappend('v',SET_F("MA"),strip.ablMilliampsMax); sappend('v',SET_F("MA"),strip.ablMilliampsMax);
sappend('v',SET_F("LA"),strip.milliampsPerLed); sappend('v',SET_F("LA"),strip.milliampsPerLed);
if (strip.currentMilliamps) if (strip.currentMilliamps)
@ -292,6 +344,11 @@ void getSettingsJS(byte subPage, char* dest)
sappend('i',SET_F("PB"),strip.paletteBlend); sappend('i',SET_F("PB"),strip.paletteBlend);
sappend('c',SET_F("RV"),strip.reverseMode); sappend('c',SET_F("RV"),strip.reverseMode);
sappend('c',SET_F("SL"),skipFirstLed); sappend('c',SET_F("SL"),skipFirstLed);
sappend('v',SET_F("RL"),rlyPin);
sappend('c',SET_F("RM"),rlyMde);
sappend('v',SET_F("BT"),btnPin);
sappend('v',SET_F("IR"),irPin);
sappend('v',SET_F("AX"),auxPin);
} }
if (subPage == 3) if (subPage == 3)