Overridable color order

- Use `ColorOrderMap` to hold optional color order overrides for ranges
  of LEDs.
- Serialization of config to/from filesystem is complete.
- Back-end configuration is complete.
- TODO: front-end changes to the LED settings page.
This commit is contained in:
Mike Ryan 2021-12-31 14:35:27 -06:00
parent 33f72e40da
commit a06846fa74
4 changed files with 107 additions and 5 deletions

View File

@ -73,6 +73,56 @@ 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;
}
_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
class Bus {
public:
@ -152,7 +202,7 @@ class Bus {
class BusDigital : public Bus {
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 (!pinManager.allocatePin(bc.pins[0], true, PinOwner::BusDigital)) return;
_pins[0] = bc.pins[0];
@ -197,7 +247,7 @@ class BusDigital : public Bus {
//TODO only show if no new show due in the next 50ms
void setStatusPixel(uint32_t c) {
if (_skip && canShow()) {
PolyBus::setPixelColor(_busPtr, _iType, 0, c, _colorOrder);
PolyBus::setPixelColor(_busPtr, _iType, 0, c, _colorOrderMap.getPixelColorOrder(_start, _colorOrder));
PolyBus::show(_busPtr, _iType);
}
}
@ -207,13 +257,13 @@ class BusDigital : public Bus {
if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT
if (reversed) pix = _len - pix -1;
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) {
if (reversed) pix = _len - pix -1;
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() {
@ -263,6 +313,7 @@ class BusDigital : public Bus {
uint8_t _iType = I_NONE;
uint8_t _skip = 0;
void * _busPtr = nullptr;
const ColorOrderMap &_colorOrderMap;
};
@ -555,7 +606,7 @@ class BusManager {
if (bc.type >= TYPE_NET_DDP_RGB && bc.type < 96) {
busses[numBusses] = new BusNetwork(bc);
} else if (IS_DIGITAL(bc.type)) {
busses[numBusses] = new BusDigital(bc, numBusses);
busses[numBusses] = new BusDigital(bc, numBusses, colorOrderMap);
} else {
busses[numBusses] = new BusPwm(bc);
}
@ -640,8 +691,17 @@ class BusManager {
return len;
}
void updateColorOrderMap(const ColorOrderMap &com) {
memcpy(&colorOrderMap, &com, sizeof(ColorOrderMap));
}
const ColorOrderMap& getColorOrderMap() const {
return colorOrderMap;
}
private:
uint8_t numBusses = 0;
Bus* busses[WLED_MAX_BUSSES];
ColorOrderMap colorOrderMap;
};
#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
// 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
JsonObject btn_obj = hw["btn"];
JsonArray hw_btn_ins = btn_obj[F("ins")];
@ -573,6 +589,18 @@ void serializeConfig() {
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)
JsonObject hw_btn = hw.createNestedObject("btn");
hw_btn["max"] = WLED_MAX_BUTTONS; // just information about max number of buttons (not actually used)

View File

@ -39,6 +39,8 @@
#endif
#endif
#define WLED_MAX_COLOR_ORDER_MAPPINGS 10
//Usermod IDs
#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

View File

@ -136,6 +136,18 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
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
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
int hw_ir_pin = request->arg(F("IR")).toInt();
if (pinManager.allocatePin(hw_ir_pin,false, PinOwner::IR)) {