From fb19f1ecbc869b366fc10371bb5d6f56eb9cb1e3 Mon Sep 17 00:00:00 2001 From: Mike Ryan Date: Tue, 25 Jan 2022 17:42:04 -0600 Subject: [PATCH 1/2] Allow overriding of color order by LED pixel range. (#2463) * 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. * Add Color order override settings - Adds color order override section to settings page. * PR Feedback - Limit max number of color order overrides to 5 on ESP8266 - Only append color overrides if they were provided in the POST of LED settings. --- wled00/bus_manager.h | 76 ++++++++++++++++++++++++++++++++--- wled00/cfg.cpp | 28 +++++++++++++ wled00/const.h | 7 ++++ wled00/data/settings_leds.htm | 63 ++++++++++++++++++++++++++++- wled00/html_settings.h | 36 ++++++++++------- wled00/set.cpp | 14 +++++++ wled00/xml.cpp | 13 ++++++ 7 files changed, 216 insertions(+), 21 deletions(-) diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 721183832..da5467b53 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -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 class Bus { public: @@ -152,7 +208,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 +253,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 +263,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 +319,7 @@ class BusDigital : public Bus { uint8_t _iType = I_NONE; uint8_t _skip = 0; void * _busPtr = nullptr; + const ColorOrderMap &_colorOrderMap; }; @@ -555,7 +612,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 +697,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 diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index f16c69263..18d5d2a77 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -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")]; @@ -574,6 +590,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) diff --git a/wled00/const.h b/wled00/const.h index 3d3cf1cbc..aaeb7fc5e 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -39,6 +39,12 @@ #endif #endif +#ifdef ESP8266 +#define WLED_MAX_COLOR_ORDER_MAPPINGS 5 +#else +#define WLED_MAX_COLOR_ORDER_MAPPINGS 10 +#endif + //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 @@ -170,6 +176,7 @@ #define COL_ORDER_RBG 3 #define COL_ORDER_BGR 4 #define COL_ORDER_GBR 5 +#define COL_ORDER_MAX 5 //Button type diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 8dd81e446..24d2acff2 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -6,7 +6,7 @@ LED Settings