This commit is contained in:
Blaz Kristan 2022-01-27 19:26:56 +01:00
commit 07216db864
10 changed files with 229 additions and 23 deletions

View File

@ -2,6 +2,13 @@
### Builds after release 0.12.0 ### Builds after release 0.12.0
#### Build 2201260
- Initial ESP32-C3 and ESP32-S2 support (PRs #2452, )
- Full segment sync (PR #2427)
- Allow overriding of color order by ranges (PR #2463)
- Added white channel to Peek
#### Build 2112080 #### Build 2112080
- Version bump to 0.13.0-b6 "Toki" - Version bump to 0.13.0-b6 "Toki"

View File

@ -73,6 +73,62 @@ struct BusConfig {
} }
}; };
// Defines an LED Strip and its color ordering.
struct ColorOrderMapEntry {
uint16_t start;
uint16_t len;
uint8_t colorOrder;
};
struct ColorOrderMap {
void add(uint16_t start, uint16_t len, uint8_t colorOrder) {
if (_count >= WLED_MAX_COLOR_ORDER_MAPPINGS) {
return;
}
if (len == 0) {
return;
}
if (colorOrder > COL_ORDER_MAX) {
return;
}
_mappings[_count].start = start;
_mappings[_count].len = len;
_mappings[_count].colorOrder = colorOrder;
_count++;
}
uint8_t count() const {
return _count;
}
void reset() {
_count = 0;
memset(_mappings, 0, sizeof(_mappings));
}
const ColorOrderMapEntry* get(uint8_t n) const {
if (n > _count) {
return nullptr;
}
return &(_mappings[n]);
}
inline uint8_t getPixelColorOrder(uint16_t pix, uint8_t defaultColorOrder) const {
if (_count == 0) return defaultColorOrder;
for (uint8_t i = 0; i < _count; i++) {
if (pix >= _mappings[i].start && pix < (_mappings[i].start + _mappings[i].len)) {
return _mappings[i].colorOrder;
}
}
return defaultColorOrder;
}
private:
uint8_t _count;
ColorOrderMapEntry _mappings[WLED_MAX_COLOR_ORDER_MAPPINGS];
};
//parent class of BusDigital, BusPwm, and BusNetwork //parent class of BusDigital, BusPwm, and BusNetwork
class Bus { class Bus {
public: public:
@ -152,7 +208,7 @@ class Bus {
class BusDigital : public Bus { class BusDigital : public Bus {
public: public:
BusDigital(BusConfig &bc, uint8_t nr) : Bus(bc.type, bc.start) { BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) : Bus(bc.type, bc.start), _colorOrderMap(com) {
if (!IS_DIGITAL(bc.type) || !bc.count) return; if (!IS_DIGITAL(bc.type) || !bc.count) return;
if (!pinManager.allocatePin(bc.pins[0], true, PinOwner::BusDigital)) return; if (!pinManager.allocatePin(bc.pins[0], true, PinOwner::BusDigital)) return;
_pins[0] = bc.pins[0]; _pins[0] = bc.pins[0];
@ -197,7 +253,7 @@ class BusDigital : public Bus {
//TODO only show if no new show due in the next 50ms //TODO only show if no new show due in the next 50ms
void setStatusPixel(uint32_t c) { void setStatusPixel(uint32_t c) {
if (_skip && canShow()) { if (_skip && canShow()) {
PolyBus::setPixelColor(_busPtr, _iType, 0, c, _colorOrder); PolyBus::setPixelColor(_busPtr, _iType, 0, c, _colorOrderMap.getPixelColorOrder(_start, _colorOrder));
PolyBus::show(_busPtr, _iType); PolyBus::show(_busPtr, _iType);
} }
} }
@ -207,13 +263,13 @@ class BusDigital : public Bus {
if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT
if (reversed) pix = _len - pix -1; if (reversed) pix = _len - pix -1;
else pix += _skip; else pix += _skip;
PolyBus::setPixelColor(_busPtr, _iType, pix, c, _colorOrder); PolyBus::setPixelColor(_busPtr, _iType, pix, c, _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder));
} }
uint32_t getPixelColor(uint16_t pix) { uint32_t getPixelColor(uint16_t pix) {
if (reversed) pix = _len - pix -1; if (reversed) pix = _len - pix -1;
else pix += _skip; else pix += _skip;
return PolyBus::getPixelColor(_busPtr, _iType, pix, _colorOrder); return PolyBus::getPixelColor(_busPtr, _iType, pix, _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder));
} }
inline uint8_t getColorOrder() { inline uint8_t getColorOrder() {
@ -263,6 +319,7 @@ class BusDigital : public Bus {
uint8_t _iType = I_NONE; uint8_t _iType = I_NONE;
uint8_t _skip = 0; uint8_t _skip = 0;
void * _busPtr = nullptr; void * _busPtr = nullptr;
const ColorOrderMap &_colorOrderMap;
}; };
@ -555,7 +612,7 @@ class BusManager {
if (bc.type >= TYPE_NET_DDP_RGB && bc.type < 96) { if (bc.type >= TYPE_NET_DDP_RGB && bc.type < 96) {
busses[numBusses] = new BusNetwork(bc); busses[numBusses] = new BusNetwork(bc);
} else if (IS_DIGITAL(bc.type)) { } else if (IS_DIGITAL(bc.type)) {
busses[numBusses] = new BusDigital(bc, numBusses); busses[numBusses] = new BusDigital(bc, numBusses, colorOrderMap);
} else { } else {
busses[numBusses] = new BusPwm(bc); busses[numBusses] = new BusPwm(bc);
} }
@ -640,8 +697,17 @@ class BusManager {
return len; return len;
} }
void updateColorOrderMap(const ColorOrderMap &com) {
memcpy(&colorOrderMap, &com, sizeof(ColorOrderMap));
}
const ColorOrderMap& getColorOrderMap() const {
return colorOrderMap;
}
private: private:
uint8_t numBusses = 0; uint8_t numBusses = 0;
Bus* busses[WLED_MAX_BUSSES]; Bus* busses[WLED_MAX_BUSSES];
ColorOrderMap colorOrderMap;
}; };
#endif #endif

View File

@ -123,6 +123,22 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
} }
if (hw_led["rev"]) busses.getBus(0)->reversed = true; //set 0.11 global reversed setting for first bus if (hw_led["rev"]) busses.getBus(0)->reversed = true; //set 0.11 global reversed setting for first bus
// read color order map configuration
JsonArray hw_com = hw[F("com")];
if (!hw_com.isNull()) {
ColorOrderMap com = {};
uint8_t s = 0;
for (JsonObject entry : hw_com) {
if (s > WLED_MAX_COLOR_ORDER_MAPPINGS) break;
uint16_t start = entry[F("start")] | 0;
uint16_t len = entry[F("len")] | 0;
uint8_t colorOrder = (int)entry[F("order")];
com.add(start, len, colorOrder);
s++;
}
busses.updateColorOrderMap(com);
}
// read multiple button configuration // read multiple button configuration
JsonObject btn_obj = hw["btn"]; JsonObject btn_obj = hw["btn"];
JsonArray hw_btn_ins = btn_obj[F("ins")]; JsonArray hw_btn_ins = btn_obj[F("ins")];
@ -574,6 +590,18 @@ void serializeConfig() {
ins[F("rgbw")] = bus->isRgbw(); ins[F("rgbw")] = bus->isRgbw();
} }
JsonArray hw_com = hw.createNestedArray(F("com"));
const ColorOrderMap& com = busses.getColorOrderMap();
for (uint8_t s = 0; s < com.count(); s++) {
const ColorOrderMapEntry *entry = com.get(s);
if (!entry) break;
JsonObject co = hw_com.createNestedObject();
co[F("start")] = entry->start;
co[F("len")] = entry->len;
co[F("order")] = entry->colorOrder;
}
// button(s) // button(s)
JsonObject hw_btn = hw.createNestedObject("btn"); JsonObject hw_btn = hw.createNestedObject("btn");
hw_btn["max"] = WLED_MAX_BUTTONS; // just information about max number of buttons (not actually used) hw_btn["max"] = WLED_MAX_BUTTONS; // just information about max number of buttons (not actually used)

View File

@ -39,6 +39,12 @@
#endif #endif
#endif #endif
#ifdef ESP8266
#define WLED_MAX_COLOR_ORDER_MAPPINGS 5
#else
#define WLED_MAX_COLOR_ORDER_MAPPINGS 10
#endif
//Usermod IDs //Usermod IDs
#define USERMOD_ID_RESERVED 0 //Unused. Might indicate no usermod present #define USERMOD_ID_RESERVED 0 //Unused. Might indicate no usermod present
#define USERMOD_ID_UNSPECIFIED 1 //Default value for a general user mod that does not specify a custom ID #define USERMOD_ID_UNSPECIFIED 1 //Default value for a general user mod that does not specify a custom ID
@ -170,6 +176,7 @@
#define COL_ORDER_RBG 3 #define COL_ORDER_RBG 3
#define COL_ORDER_BGR 4 #define COL_ORDER_BGR 4
#define COL_ORDER_GBR 5 #define COL_ORDER_GBR 5
#define COL_ORDER_MAX 5
//Button type //Button type

View File

@ -6,7 +6,7 @@
<title>LED Settings</title> <title>LED Settings</title>
<script> <script>
var d=document,laprev=55,maxB=1,maxM=4000,maxPB=4096,maxL=1333,maxLbquot=0; //maximum bytes for LED allocation: 4kB for 8266, 32kB for 32 var d=document,laprev=55,maxB=1,maxM=4000,maxPB=4096,maxL=1333,maxLbquot=0; //maximum bytes for LED allocation: 4kB for 8266, 32kB for 32
var customStarts=false,startsDirty=[]; var customStarts=false,startsDirty=[],maxCOOverrides=5;
function H() function H()
{ {
window.open("https://kno.wled.ge/features/settings/#led-settings"); window.open("https://kno.wled.ge/features/settings/#led-settings");
@ -347,6 +347,53 @@ ${i+1}:
if (!init) UI(); if (!init) UI();
} }
function addCOM(start=0,len=1,co=0) {
var i = d.getElementsByClassName("com_entry").length;
if (i >= 10) return;
var b = `<div class="com_entry">
<hr style="width:260px">
${i+1}: Start: <input type="number" name="XS${i}" id="xs${i}" class="l starts" min="0" max="65535" value="${start}" oninput="UI();" required="">&nbsp;
Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65535" value="${len}" required="" oninput="UI()">
<div style="display:inline">Color Order:
<select id="xo${i}" name="XO${i}">
<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>
</div><br></div>`;
gId("com_entries").insertAdjacentHTML("beforeend", b);
gId("xo"+i).value = co;
btnCOM(i+1);
}
function remCOM() {
var entries = d.getElementsByClassName("com_entry");
var i = entries.length;
if (i === 0) return;
entries[i-1].remove();
btnCOM(i-1);
}
function resetCOM(_newMaxCOOverrides=undefined) {
if (_newMaxCOOverrides) {
maxCOOverrides = _newMaxCOOverrides;
}
for (let e of d.getElementsByClassName("com_entry")) {
e.remove();
}
btnCOM(0);
}
function btnCOM(i) {
gId("com_add").style.display = (i<maxCOOverrides) ? "inline":"none";
gId("com_rem").style.display = (i>0) ? "inline":"none";
}
function addBtn(i,p,t) { function addBtn(i,p,t) {
var c = gId("btns").innerHTML; var c = gId("btns").innerHTML;
var bt = "BT" + String.fromCharCode((i<10?48:55)+i);; var bt = "BT" + String.fromCharCode((i<10?48:55)+i);;
@ -431,6 +478,12 @@ ${i+1}:
d.getElementsByName("CV"+i)[0].checked = v.rev; d.getElementsByName("CV"+i)[0].checked = v.rev;
}); });
} }
if(c.hw.com) {
resetCOM();
c.hw.com.forEach(e => {
addCOM(e.start, e.len, e.order);
});
}
if (c.hw.btn) { if (c.hw.btn) {
var b = c.hw.btn; var b = c.hw.btn;
if (Array.isArray(b.ins)) gId("btns").innerHTML = ""; if (Array.isArray(b.ins)) gId("btns").innerHTML = "";
@ -510,6 +563,14 @@ ${i+1}:
Make a segment for each output: <input type="checkbox" name="MS"> <br> Make a segment for each output: <input type="checkbox" name="MS"> <br>
Custom bus start indices: <input type="checkbox" onchange="tglSi(this.checked)" id="si"> <br> Custom bus start indices: <input type="checkbox" onchange="tglSi(this.checked)" id="si"> <br>
<hr style="width:260px"> <hr style="width:260px">
<div id="color_order_mapping">
Color Order Override:
<div id="com_entries"></div>
<hr style="width:260px">
<button type="button" id="com_add" onclick="addCOM();UI()" style="display:none;border-radius:20px;height:36px;">+</button>
<button type="button" id="com_rem" onclick="remCOM();UI()" style="display:none;border-radius:20px;width:36px;height:36px;">-</button><br>
</div>
<hr style="width:260px">
<div id="btns"></div> <div id="btns"></div>
Touch threshold: <input type="number" class="s" min="0" max="100" name="TT" required><br> Touch threshold: <input type="number" class="s" min="0" max="100" name="TT" required><br>
IR GPIO: <input type="number" min="-1" max="40" name="IR" onchange="UI()" class="xs"><select name="IT" onchange="UI()"> IR GPIO: <input type="number" min="-1" max="40" name="IR" onchange="UI()" class="xs"><select name="IT" onchange="UI()">

File diff suppressed because one or more lines are too long

View File

@ -909,7 +909,11 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
for (uint16_t i= 0; i < used; i += n) for (uint16_t i= 0; i < used; i += n)
{ {
olen += sprintf(obuf + olen, "\"%06X\",", strip.getPixelColor(i) & 0xFFFFFF); uint32_t c = strip.getPixelColor(i);
uint8_t r = qadd8(W(c), R(c)); //add white channel to RGB channels as a simple RGBW -> RGB map
uint8_t g = qadd8(W(c), G(c));
uint8_t b = qadd8(W(c), B(c));
olen += sprintf(obuf + olen, "\"%06X\",", RGBW32(r,g,b,0));
} }
olen -= 1; olen -= 1;
oappend((const char*)F("],\"n\":")); oappend((const char*)F("],\"n\":"));

View File

@ -136,6 +136,20 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
doInitBusses = true; doInitBusses = true;
} }
ColorOrderMap com = {};
for (uint8_t s = 0; s < WLED_MAX_COLOR_ORDER_MAPPINGS; s++) {
char xs[4] = "XS"; xs[2] = 48+s; xs[3] = 0; //start LED
char xc[4] = "XC"; xc[2] = 48+s; xc[3] = 0; //strip length
char xo[4] = "XO"; xo[2] = 48+s; xo[3] = 0; //color order
if (request->hasArg(xs)) {
start = request->arg(xs).toInt();
length = request->arg(xc).toInt();
colorOrder = request->arg(xo).toInt();
com.add(start, length, colorOrder);
}
}
busses.updateColorOrderMap(com);
// upate other pins // upate other pins
int hw_ir_pin = request->arg(F("IR")).toInt(); int hw_ir_pin = request->arg(F("IR")).toInt();
if (pinManager.allocatePin(hw_ir_pin,false, PinOwner::IR)) { if (pinManager.allocatePin(hw_ir_pin,false, PinOwner::IR)) {

View File

@ -8,7 +8,7 @@
*/ */
// version code in format yymmddb (b = daily build) // version code in format yymmddb (b = daily build)
#define VERSION 2112080 #define VERSION 2201260
//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

View File

@ -421,6 +421,19 @@ void getSettingsJS(byte subPage, char* dest)
oappend(SET_F("mA\";")); oappend(SET_F("mA\";"));
} }
oappend(SET_F("resetCOM("));
oappend(itoa(WLED_MAX_COLOR_ORDER_MAPPINGS,nS,10));
oappend(SET_F(");"));
const ColorOrderMap& com = busses.getColorOrderMap();
for (uint8_t s=0; s < com.count(); s++) {
const ColorOrderMapEntry* entry = com.get(s);
if (entry == nullptr) break;
oappend(SET_F("addCOM("));
oappend(itoa(entry->start,nS,10)); oappend(",");
oappend(itoa(entry->len,nS,10)); oappend(",");
oappend(itoa(entry->colorOrder,nS,10)); oappend(");");
}
sappend('v',SET_F("CA"),briS); sappend('v',SET_F("CA"),briS);
sappend('c',SET_F("BO"),turnOnAtBoot); sappend('c',SET_F("BO"),turnOnAtBoot);