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 //parent class of BusDigital, BusPwm, and BusNetwork
class Bus { class Bus {
public: public:
@ -152,7 +202,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 +247,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 +257,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 +313,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 +606,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 +691,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")];
@ -573,6 +589,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,8 @@
#endif #endif
#endif #endif
#define WLED_MAX_COLOR_ORDER_MAPPINGS 10
//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

View File

@ -136,6 +136,18 @@ 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
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)) {