Moved auto white calcualtion into bus manager.

This commit is contained in:
Blaz Kristan 2021-10-24 21:07:05 +02:00
parent 1b23210902
commit b8013a57e2
13 changed files with 87 additions and 93 deletions

View File

@ -658,7 +658,6 @@ class WS2812FX {
uint8_t
mainSegment = 0,
rgbwMode = RGBW_MODE_DUAL,
paletteFade = 0,
paletteBlend = 0,
milliampsPerLed = 55,

View File

@ -192,20 +192,6 @@ uint16_t WS2812FX::realPixelIndex(uint16_t i) {
void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
{
//auto calculate white channel value if enabled
if (isRgbw) {
switch (rgbwMode) {
case RGBW_MODE_MANUAL_ONLY:
break;
default:
//white value is set to lowest RGB channel
//thank you to @Def3nder!
if (rgbwMode == RGBW_MODE_AUTO_BRIGHTER || w == 0) w = r < g ? (r < b ? r : b) : (g < b ? g : b);
if (rgbwMode == RGBW_MODE_AUTO_ACCURATE) { r -= w; g -= w; b -= w; }
break;
}
}
if (SEGLEN) {//from segment
uint16_t realIndex = realPixelIndex(i);
uint16_t len = SEGMENT.length();
@ -218,21 +204,6 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
if (bus == nullptr || !bus->containsPixel(realIndex)) continue;
//if (bus == nullptr || bus->getStart()<realIndex || bus->getStart()+bus->getLength()>realIndex) continue;
uint8_t busType = bus->getType();
/*
// if we are in accurate white calculation mode subtract W but only for RGBW strip
if (rgbwMode == RGBW_MODE_AUTO_ACCURATE
&& ( busType == TYPE_SK6812_RGBW
|| busType == TYPE_TM1814
|| busType == TYPE_ANALOG_1CH
|| busType == TYPE_ANALOG_2CH
|| busType == TYPE_ANALOG_4CH
|| busType == TYPE_ANALOG_5CH )
) {
// this will produce a bug (some out of bounds/mem leak error)
// causing loop() no longer being executed.
//r -= w; g -= w; b -= w;
}
*/
if (allowCCT
|| busType == TYPE_ANALOG_2CH
|| busType == TYPE_ANALOG_5CH) {

View File

@ -10,8 +10,9 @@
#include "bus_wrapper.h"
#include <Arduino.h>
//color.cpp
//colors.cpp
uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb);
void colorRGBtoRGBW(byte* rgb);
// enable additional debug output
#ifdef WLED_DEBUG
@ -41,10 +42,11 @@ struct BusConfig {
uint8_t skipAmount;
bool refreshReq;
uint8_t pins[5] = {LEDPIN, 255, 255, 255, 255};
BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false, uint8_t skip = 0) {
uint8_t autoWhite;
BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false, uint8_t skip = 0, uint8_t aw = 0) {
refreshReq = (bool) GET_BIT(busType,7);
type = busType & 0x7F; // bit 7 may be/is hacked to include refresh info (1=refresh in off state, 0=no refresh)
count = len; start = pstart; colorOrder = pcolorOrder; reversed = rev; skipAmount = skip;
count = len; start = pstart; colorOrder = pcolorOrder; reversed = rev; skipAmount = skip; autoWhite = aw;
uint8_t nPins = 1;
if (type >= TYPE_NET_DDP_RGB && type < 96) nPins = 4; //virtual network bus. 4 "pins" store IP address
else if (type > 47) nPins = 2;
@ -68,9 +70,10 @@ struct BusConfig {
//parent class of BusDigital and BusPwm
class Bus {
public:
Bus(uint8_t type, uint16_t start) {
Bus(uint8_t type, uint16_t start, uint8_t aw) {
_type = type;
_start = start;
_autoWhiteMode = isRgbw(_type) ? aw : RGBW_MODE_MANUAL_ONLY;
};
virtual ~Bus() {} //throw the bus under the bus
@ -87,7 +90,7 @@ class Bus {
virtual void setColorOrder() {}
virtual uint8_t getColorOrder() { return COL_ORDER_RGB; }
virtual uint8_t skippedLeds() { return 0; }
inline uint8_t getAutoWhiteMode() { return _autoWhiteMode; }
inline uint16_t getStart() { return _start; }
inline void setStart(uint16_t start) { _start = start; }
inline uint8_t getType() { return _type; }
@ -95,7 +98,7 @@ class Bus {
inline bool isOffRefreshRequired() { return _needsRefresh; }
bool containsPixel(uint16_t pix) { return pix >= _start && pix < _start+_len; }
virtual bool isRgbw() { return false; }
virtual bool isRgbw() { return Bus::isRgbw(_type); }
static bool isRgbw(uint8_t type) {
if (type == TYPE_SK6812_RGBW || type == TYPE_TM1814) return true;
if (type > TYPE_ONOFF && type <= TYPE_ANALOG_5CH && type != TYPE_ANALOG_3CH) return true;
@ -111,12 +114,40 @@ class Bus {
uint16_t _len = 1;
bool _valid = false;
bool _needsRefresh = false;
uint8_t _autoWhiteMode = 0;
uint32_t autoWhiteCalc(uint32_t c) {
switch (_autoWhiteMode) {
case RGBW_MODE_MANUAL_ONLY:
break;
case RGBW_MODE_LEGACY:
byte rgb[4];
rgb[0] = c >> 16;
rgb[1] = c >> 8;
rgb[2] = c ;
rgb[3] = c >> 24;
colorRGBtoRGBW(rgb);
c = ((rgb[3] << 24) | (rgb[0] << 16) | (rgb[1] << 8) | (rgb[2]));
break;
default:
//white value is set to lowest RGB channel, thank you to @Def3nder!
uint8_t r = c >> 16;
uint8_t g = c >> 8;
uint8_t b = c ;
uint8_t w = c >> 24;
if (_autoWhiteMode == RGBW_MODE_AUTO_BRIGHTER || w == 0) w = r < g ? (r < b ? r : b) : (g < b ? g : b);
if (_autoWhiteMode == RGBW_MODE_AUTO_ACCURATE) { r -= w; g -= w; b -= w; }
c = ((w << 24) | (r << 16) | (g << 8) | (b));
break;
}
return c;
}
};
class BusDigital : public Bus {
public:
BusDigital(BusConfig &bc, uint8_t nr) : Bus(bc.type, bc.start) {
BusDigital(BusConfig &bc, uint8_t nr) : Bus(bc.type, bc.start, bc.autoWhite) {
if (!IS_DIGITAL(bc.type) || !bc.count) return;
if (!pinManager.allocatePin(bc.pins[0], true, PinOwner::BusDigital)) return;
_pins[0] = bc.pins[0];
@ -158,6 +189,7 @@ class BusDigital : public Bus {
}
void setPixelColor(uint16_t pix, uint32_t c) {
if (getAutoWhiteMode() != RGBW_MODE_MANUAL_ONLY) c = autoWhiteCalc(c);
if (reversed) pix = _len - pix -1;
else pix += _skip;
PolyBus::setPixelColor(_busPtr, _iType, pix, c, _colorOrder);
@ -193,10 +225,6 @@ class BusDigital : public Bus {
_colorOrder = colorOrder;
}
inline bool isRgbw() {
return Bus::isRgbw(_type);
}
inline uint8_t skippedLeds() {
return _skip;
}
@ -230,7 +258,7 @@ class BusDigital : public Bus {
class BusPwm : public Bus {
public:
BusPwm(BusConfig &bc) : Bus(bc.type, bc.start) {
BusPwm(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
_valid = false;
if (!IS_PWM(bc.type)) return;
uint8_t numPins = NUM_PWM_PINS(bc.type);
@ -265,6 +293,7 @@ class BusPwm : public Bus {
void setPixelColor(uint16_t pix, uint32_t c, uint8_t cct) {
if (pix != 0 || !_valid) return; //only react to first pixel
c = colorBalanceFromKelvin(2000+(cct<<5), c); // color correction from CCT (w remains unchanged)
if (getAutoWhiteMode() != RGBW_MODE_MANUAL_ONLY) c = autoWhiteCalc(c);
uint8_t r = c >> 16;
uint8_t g = c >> 8;
uint8_t b = c ;
@ -294,6 +323,7 @@ class BusPwm : public Bus {
void setPixelColor(uint16_t pix, uint32_t c) {
if (pix != 0 || !_valid) return; //only react to first pixel
if (getAutoWhiteMode() != RGBW_MODE_MANUAL_ONLY) c = autoWhiteCalc(c);
uint8_t r = c >> 16;
uint8_t g = c >> 8;
uint8_t b = c ;
@ -343,10 +373,6 @@ class BusPwm : public Bus {
return numPins;
}
bool isRgbw() {
return Bus::isRgbw(_type);
}
inline void cleanup() {
deallocatePins();
}
@ -382,7 +408,7 @@ class BusPwm : public Bus {
class BusNetwork : public Bus {
public:
BusNetwork(BusConfig &bc) : Bus(bc.type, bc.start) {
BusNetwork(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
_valid = false;
// switch (bc.type) {
// case TYPE_NET_ARTNET_RGB:
@ -414,6 +440,7 @@ class BusNetwork : public Bus {
void setPixelColor(uint16_t pix, uint32_t c) {
if (!_valid || pix >= _len) return;
if (getAutoWhiteMode() != RGBW_MODE_MANUAL_ONLY) c = autoWhiteCalc(c);
uint16_t offset = pix * _UDPchannels;
_data[offset] = 0xFF & (c >> 16);
_data[offset+1] = 0xFF & (c >> 8);

View File

@ -85,7 +85,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]);
CJSON(strip.milliampsPerLed, hw_led[F("ledma")]);
CJSON(strip.rgbwMode, hw_led[F("rgbwm")]);
uint8_t rgbwMode = hw_led[F("rgbwm")] | RGBW_MODE_DUAL; // use global setting (legacy)
CJSON(allowCCT, hw_led["cct"]);
JsonArray ins = hw_led["ins"];
@ -115,13 +115,14 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
uint16_t start = elm["start"] | 0;
if (length==0 || start + length > MAX_LEDS) continue; // zero length or we reached max. number of LEDs, just stop
uint8_t ledType = elm["type"] | TYPE_WS2812_RGB;
uint8_t awMode = elm[F("rgbwm")] | rgbwMode;
bool reversed = elm["rev"];
bool refresh = elm["ref"] | false;
ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh
s++;
uint16_t busEnd = start + length;
if (busEnd > lC) lC = busEnd;
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst);
BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst, awMode);
mem += BusManager::memUsage(bc);
if (mem <= MAX_LED_MEMORY && busses.getNumBusses() <= WLED_MAX_BUSSES) busses.add(bc); // finalization will be done in WLED::beginStrip()
}
@ -534,7 +535,6 @@ void serializeConfig() {
hw_led[F("total")] = ledCount;
hw_led[F("maxpwr")] = strip.ablMilliampsMax;
hw_led[F("ledma")] = strip.milliampsPerLed;
hw_led[F("rgbwm")] = strip.rgbwMode;
hw_led["cct"] = allowCCT;
JsonArray hw_led_ins = hw_led.createNestedArray("ins");
@ -555,6 +555,7 @@ void serializeConfig() {
ins["type"] = bus->getType() & 0x7F;
ins["ref"] = bus->isOffRefreshRequired();
ins[F("rgbw")] = bus->isRgbw();
ins[F("rgbwm")] = bus->getAutoWhiteMode();
}
// button(s)

View File

@ -64,7 +64,6 @@ void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb
case 4: rgb[0]=t,rgb[1]=p,rgb[2]=255;break;
case 5: rgb[0]=255,rgb[1]=p,rgb[2]=q;
}
if (strip.isRgbw && strip.rgbwMode == RGBW_MODE_LEGACY) colorRGBtoRGBW(col);
}
//get RGB values from color temperature in K (https://tannerhelland.com/2012/09/18/convert-temperature-rgb-algorithm-code.html)
@ -112,7 +111,6 @@ void colorCTtoRGB(uint16_t mired, byte* rgb) //white spectrum to rgb, bins
} else {
rgb[0]=237;rgb[1]=255;rgb[2]=239;//150
}
if (strip.isRgbw && strip.rgbwMode == RGBW_MODE_LEGACY) colorRGBtoRGBW(col);
}
#ifndef WLED_DISABLE_HUESYNC
@ -170,7 +168,6 @@ void colorXYtoRGB(float x, float y, byte* rgb) //coordinates to rgb (https://www
rgb[0] = 255.0*r;
rgb[1] = 255.0*g;
rgb[2] = 255.0*b;
if (strip.isRgbw && strip.rgbwMode == RGBW_MODE_LEGACY) colorRGBtoRGBW(col);
}
void colorRGBtoXY(byte* rgb, float* xy) //rgb to coordinates (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy)
@ -237,6 +234,17 @@ float maxf (float v, float w)
return v;
}
uint32_t colorRGBtoRGBW(uint32_t c)
{
byte rgb[4];
rgb[0] = c >> 16;
rgb[1] = c >> 8;
rgb[2] = c ;
rgb[3] = c >> 24;
colorRGBtoRGBW(rgb);
return ((rgb[3] << 24) | (rgb[0] << 16) | (rgb[1] << 8) | (rgb[2]));
}
void colorRGBtoRGBW(byte* rgb) //rgb to rgbw (http://codewelt.com/rgbw). (RGBW_MODE_LEGACY)
{
float low = minf(rgb[0],minf(rgb[1],rgb[2]));

View File

@ -170,6 +170,7 @@
gId("dig"+n+"r").style.display = (t>=80 && t<96) ? "none":"inline"; // hide reversed for virtual
gId("dig"+n+"s").style.display = ((t>=80 && t<96) || (t > 40 && t < 48)) ? "none":"inline"; // hide skip 1st for virtual & analog
gId("dig"+n+"f").style.display = (t>=16 && t<32 || t>=50 && t<64) ? "inline":"none"; // hide refresh
gId("dig"+n+"a").style.display = (isRGBW) ? "inline":"none"; // auto calculate white
gId("rev"+n).innerHTML = (t > 40 && t < 48) ? "Inverted output":"Reversed (rotated 180°)"; // change reverse text for analog
gId("psd"+n).innerHTML = (t > 40 && t < 48) ? "Index:":"Start:"; // change analog start description
}
@ -334,6 +335,7 @@ ${i+1}:
<div id="dig${i}r" style="display:inline"><br><span id="rev${i}">Reversed</span>: <input type="checkbox" name="CV${i}"></div>
<div id="dig${i}s" style="display:inline"><br>Skip 1<sup>st</sup> LED: <input id="sl${i}" type="checkbox" name="SL${i}"></div>
<div id="dig${i}f" style="display:inline"><br>Off Refresh: <input id="rf${i}" type="checkbox" name="RF${i}">&nbsp;</div>
<div id="dig${i}a" style="display:inline"><br>Auto-calculate white channel from RGB:<br><select name="AW${i}"><option value=0>None</option><option value=1>Brighter</option><option value=2>Accurate</option><option value=3>Dual</option><option value=4>Legacy</option></select>&nbsp;</div>
</div>`;
f.insertAdjacentHTML("beforeend", cn);
}
@ -559,16 +561,6 @@ ${i+1}:
<option value="2">Linear (never wrap)</option>
<option value="3">None (not recommended)</option>
</select><br>
<span class="wc">
Auto-calculate white channel from RGB:<br>
<select name="AW">
<option value=0>None</option>
<option value=1>Brighter</option>
<option value=2>Accurate</option>
<option value=3>Dual</option>
<option value=4>Legacy</option>
</select>
<br></span>
<hr style="width:260px">
<div id="cfg">Config template: <input type="file" name="data2" accept=".json"> <input type="button" value="Apply" onclick="loadCfg(d.Sf.data2);"><br></div>
<hr>

File diff suppressed because one or more lines are too long

View File

@ -460,17 +460,23 @@ void serializeInfo(JsonObject root)
JsonObject leds = root.createNestedObject("leds");
leds[F("count")] = ledCount;
leds[F("rgbw")] = strip.isRgbw;
leds[F("wv")] = strip.isRgbw && (strip.rgbwMode == RGBW_MODE_MANUAL_ONLY || strip.rgbwMode == RGBW_MODE_DUAL); //should a white channel slider be displayed?
leds[F("wv")] = false;
leds["cct"] = allowCCT;
for (uint8_t s = 0; s < busses.getNumBusses(); s++) {
Bus *bus = busses.getBus(s);
if (!bus || bus->getLength()==0) break;
switch (bus->getType() & 0x7F) {
if (bus == nullptr || bus->getLength()==0) break;
switch (bus->getType()) {
case TYPE_ANALOG_5CH:
case TYPE_ANALOG_2CH:
leds["cct"] = true;
break;
}
switch (bus->getAutoWhiteMode()) {
case RGBW_MODE_MANUAL_ONLY:
case RGBW_MODE_DUAL:
if (bus->isRgbw()) leds[F("wv")] = true;
break;
}
}
JsonArray leds_pin = leds.createNestedArray("pin");

View File

@ -44,17 +44,8 @@ byte scaledBri(byte in)
void setAllLeds() {
if (strip.isRgbw && strip.rgbwMode == RGBW_MODE_LEGACY)
{
colorRGBtoRGBW(col);
colorRGBtoRGBW(colSec);
}
strip.setColor(0, col[0], col[1], col[2], col[3]);
strip.setColor(1, colSec[0], colSec[1], colSec[2], colSec[3]);
if (strip.isRgbw && strip.rgbwMode == RGBW_MODE_LEGACY)
{
col[3] = 0; colSec[3] = 0;
}
if (!realtimeMode || !arlsForceMaxBri)
{
strip.setBrightness(scaledBri(briT));

View File

@ -67,7 +67,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
}
}
uint8_t colorOrder, type, skip;
uint8_t colorOrder, type, skip, awMode;
uint16_t length, start;
uint8_t pins[5] = {255, 255, 255, 255, 255};
@ -83,6 +83,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
char cv[4] = "CV"; cv[2] = 48+s; cv[3] = 0; //strip reverse
char sl[4] = "SL"; sl[2] = 48+s; sl[3] = 0; //skip 1st LED
char rf[4] = "RF"; rf[2] = 48+s; rf[3] = 0; //refresh required
char aw[4] = "AW"; aw[2] = 48+s; aw[3] = 0; //auto white calculate mode
if (!request->hasArg(lp)) {
DEBUG_PRINTLN(F("No data.")); break;
}
@ -94,7 +95,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
type = request->arg(lt).toInt();
type |= request->hasArg(rf) << 7; // off refresh override
skip = request->hasArg(sl) ? LED_SKIP_AMOUNT : 0;
awMode = request->arg(aw).toInt();
colorOrder = request->arg(co).toInt();
start = (request->hasArg(ls)) ? request->arg(ls).toInt() : t;
if (request->hasArg(lc) && request->arg(lc).toInt() > 0) {
@ -105,7 +106,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
// actual finalization is done in WLED::loop() (removing old busses and adding new)
if (busConfigs[s] != nullptr) delete busConfigs[s];
busConfigs[s] = new BusConfig(type, pins, start, length, colorOrder, request->hasArg(cv), skip);
busConfigs[s] = new BusConfig(type, pins, start, length, colorOrder, request->hasArg(cv), skip, awMode);
doInitBusses = true;
}
@ -144,8 +145,6 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
strip.ablMilliampsMax = request->arg(F("MA")).toInt();
strip.milliampsPerLed = request->arg(F("LA")).toInt();
strip.rgbwMode = request->arg(F("AW")).toInt();
briS = request->arg(F("CA")).toInt();
turnOnAtBoot = request->hasArg(F("BO"));

View File

@ -8,7 +8,7 @@
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2110231
#define VERSION 2110241
//uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG

View File

@ -320,7 +320,7 @@ void loadSettingsFromEEPROM()
receiveDirect = !EEPROM.read(2200);
notifyMacro = EEPROM.read(2201);
strip.rgbwMode = EEPROM.read(2203);
//strip.rgbwMode = EEPROM.read(2203);
//skipFirstLed = EEPROM.read(2204);
bootPreset = EEPROM.read(389);

View File

@ -264,6 +264,7 @@ void getSettingsJS(byte subPage, char* dest)
#ifdef WLED_ENABLE_ADALIGHT
// inform settings page that pin 3 is used by ADALights if not aleready used by strip (previous setup)
// NOTE: this will prohibit pin 3 use on new installs
/*
{
bool pin3used = false;
for (uint8_t s=0; s < busses.getNumBusses(); s++) {
@ -280,6 +281,7 @@ void getSettingsJS(byte subPage, char* dest)
}
if (!pin3used && pinManager.isPinAllocated(3)) oappend(SET_F(",3")); // ADALight (RX) pin
}
*/
#endif
#ifdef WLED_DEBUG
@ -326,6 +328,7 @@ void getSettingsJS(byte subPage, char* dest)
for (uint8_t s=0; s < busses.getNumBusses(); s++) {
Bus* bus = busses.getBus(s);
if (bus == nullptr) continue;
char lp[4] = "L0"; lp[2] = 48+s; lp[3] = 0; //ascii 0-9 //strip data pin
char lc[4] = "LC"; lc[2] = 48+s; lc[3] = 0; //strip length
char co[4] = "CO"; co[2] = 48+s; co[3] = 0; //strip color order
@ -334,6 +337,7 @@ void getSettingsJS(byte subPage, char* dest)
char cv[4] = "CV"; cv[2] = 48+s; cv[3] = 0; //strip reverse
char sl[4] = "SL"; sl[2] = 48+s; sl[3] = 0; //skip 1st LED
char rf[4] = "RF"; rf[2] = 48+s; rf[3] = 0; //off refresh
char aw[4] = "AW"; aw[2] = 48+s; aw[3] = 0; //auto white channel calculation
oappend(SET_F("addLEDs(1);"));
uint8_t pins[5];
uint8_t nPins = bus->getPins(pins);
@ -348,6 +352,7 @@ void getSettingsJS(byte subPage, char* dest)
sappend('c',cv,bus->reversed);
sappend('c',sl,bus->skippedLeds());
sappend('c',rf,bus->isOffRefreshRequired());
sappend('v',aw,bus->getAutoWhiteMode());
}
sappend('v',SET_F("MA"),strip.ablMilliampsMax);
sappend('v',SET_F("LA"),strip.milliampsPerLed);
@ -360,7 +365,6 @@ void getSettingsJS(byte subPage, char* dest)
}
sappend('v',SET_F("CA"),briS);
sappend('v',SET_F("AW"),strip.rgbwMode);
sappend('c',SET_F("BO"),turnOnAtBoot);
sappend('v',SET_F("BP"),bootPreset);