Merge branch 'master' of https://github.com/Aircoookie/WLED into overlayum

This commit is contained in:
Gregory Schmidt 2021-10-10 16:27:47 -08:00
commit 0327f9428e
13 changed files with 1074 additions and 1018 deletions

View File

@ -619,7 +619,7 @@ class WS2812FX {
} }
void void
finalizeInit(uint16_t countPixels), finalizeInit(),
service(void), service(void),
blur(uint8_t), blur(uint8_t),
fill(uint32_t), fill(uint32_t),
@ -636,7 +636,8 @@ class WS2812FX {
trigger(void), trigger(void),
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 0, uint8_t spacing = 0), setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 0, uint8_t spacing = 0),
resetSegments(), resetSegments(),
populateDefaultSegments(), makeAutoSegments(),
fixInvalidSegments(),
setPixelColor(uint16_t n, uint32_t c), setPixelColor(uint16_t n, uint32_t c),
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0), setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
show(void), show(void),
@ -650,6 +651,7 @@ class WS2812FX {
gammaCorrectCol = true, gammaCorrectCol = true,
applyToAllSelected = true, applyToAllSelected = true,
setEffectConfig(uint8_t m, uint8_t s, uint8_t i, uint8_t p), setEffectConfig(uint8_t m, uint8_t s, uint8_t i, uint8_t p),
checkSegmentAlignment(void),
// return true if the strip is being sent pixel updates // return true if the strip is being sent pixel updates
isUpdating(void); isUpdating(void);
@ -680,6 +682,8 @@ class WS2812FX {
ablMilliampsMax, ablMilliampsMax,
currentMilliamps, currentMilliamps,
triwave16(uint16_t), triwave16(uint16_t),
getLengthTotal(void),
getLengthPhysical(void),
getFps(); getFps();
uint32_t uint32_t
@ -839,9 +843,6 @@ class WS2812FX {
uint16_t _cumulativeFps = 2; uint16_t _cumulativeFps = 2;
void load_gradient_palette(uint8_t);
void handle_palette(void);
bool bool
_triggered; _triggered;
@ -875,7 +876,10 @@ class WS2812FX {
void void
blendPixelColor(uint16_t n, uint32_t color, uint8_t blend), blendPixelColor(uint16_t n, uint32_t color, uint8_t blend),
startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot); startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot),
estimateCurrentAndLimitBri(void),
load_gradient_palette(uint8_t),
handle_palette(void);
uint16_t* customMappingTable = nullptr; uint16_t* customMappingTable = nullptr;
uint16_t customMappingSize = 0; uint16_t customMappingSize = 0;

View File

@ -65,25 +65,22 @@
#endif #endif
//do not call this method from system context (network callback) //do not call this method from system context (network callback)
void WS2812FX::finalizeInit(uint16_t countPixels) void WS2812FX::finalizeInit(void)
{ {
RESET_RUNTIME; RESET_RUNTIME;
_length = countPixels; isRgbw = isOffRefreshRequred = false;
//if busses failed to load, add default (FS issue...) //if busses failed to load, add default (fresh install, FS issue, ...)
if (busses.getNumBusses() == 0) { if (busses.getNumBusses() == 0) {
const uint8_t defDataPins[] = {DATA_PINS}; const uint8_t defDataPins[] = {DATA_PINS};
const uint16_t defCounts[] = {PIXEL_COUNTS}; const uint16_t defCounts[] = {PIXEL_COUNTS};
const uint8_t defNumBusses = ((sizeof defDataPins) / (sizeof defDataPins[0])); const uint8_t defNumBusses = ((sizeof defDataPins) / (sizeof defDataPins[0]));
const uint8_t defNumCounts = ((sizeof defCounts) / (sizeof defCounts[0])); const uint8_t defNumCounts = ((sizeof defCounts) / (sizeof defCounts[0]));
uint16_t prevLen = 0; uint16_t prevLen = 0;
for (uint8_t i = 0; i < defNumBusses; i++) { for (uint8_t i = 0; i < defNumBusses && i < WLED_MAX_BUSSES; i++) {
uint8_t defPin[] = {defDataPins[i]}; uint8_t defPin[] = {defDataPins[i]};
uint16_t start = prevLen; uint16_t start = prevLen;
uint16_t count = _length; uint16_t count = defCounts[(i < defNumCounts) ? i : defNumCounts -1];
if (defNumBusses > 1 && defNumCounts) {
count = defCounts[(i < defNumCounts) ? i : defNumCounts -1];
}
prevLen += count; prevLen += count;
BusConfig defCfg = BusConfig(DEFAULT_LED_TYPE, defPin, start, count, COL_ORDER_GRB); BusConfig defCfg = BusConfig(DEFAULT_LED_TYPE, defPin, start, count, COL_ORDER_GRB);
busses.add(defCfg); busses.add(defCfg);
@ -92,60 +89,30 @@ void WS2812FX::finalizeInit(uint16_t countPixels)
deserializeMap(); deserializeMap();
uint16_t segStarts[MAX_NUM_SEGMENTS] = {0}; _length = 0;
uint16_t segStops [MAX_NUM_SEGMENTS] = {0}; for (uint8_t i=0; i<busses.getNumBusses(); i++) {
Bus *bus = busses.getBus(i);
setBrightness(_brightness); if (bus == nullptr) continue;
if (bus->getStart() + bus->getLength() > MAX_LEDS) break;
//TODO make sure segments are only refreshed when bus config actually changed (new settings page) //RGBW mode is enabled if at least one of the strips is RGBW
uint8_t s = 0; isRgbw |= bus->isRgbw();
for (uint8_t i = 0; i < busses.getNumBusses(); i++) { //refresh is required to remain off if at least one of the strips requires the refresh.
Bus* b = busses.getBus(i); isOffRefreshRequred |= bus->isOffRefreshRequired();
uint16_t busEnd = bus->getStart() + bus->getLength();
if (autoSegments) { //make one segment per bus if (busEnd > _length) _length = busEnd;
segStarts[s] = b->getStart();
segStops[s] = segStarts[s] + b->getLength();
//check for overlap with previous segments
for (uint8_t j = 0; j < s; j++) {
if (segStops[j] > segStarts[s] && segStarts[j] < segStops[s]) {
//segments overlap, merge
segStarts[j] = min(segStarts[s],segStarts[j]);
segStops [j] = max(segStops [s],segStops [j]); segStops[s] = 0;
s--;
}
}
s++;
}
#ifdef ESP8266 #ifdef ESP8266
if ((!IS_DIGITAL(b->getType()) || IS_2PIN(b->getType()))) continue; if ((!IS_DIGITAL(bus->getType()) || IS_2PIN(bus->getType()))) continue;
uint8_t pins[5]; uint8_t pins[5];
b->getPins(pins); if (!bus->getPins(pins)) continue;
BusDigital* bd = static_cast<BusDigital*>(b); BusDigital* bd = static_cast<BusDigital*>(bus);
if (pins[0] == 3) bd->reinit(); if (pins[0] == 3) bd->reinit();
#endif #endif
} }
ledCount = _length;
if (autoSegments) { //segments are created in makeAutoSegments();
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) {
setSegment(i, segStarts[i], segStops[i]); setBrightness(_brightness);
}
} else {
//expand the main seg to the entire length, but only if there are no other segments
uint8_t mainSeg = getMainSegmentId();
if (getActiveSegmentsNum() < 2) {
setSegment(mainSeg, 0, _length);
} else {
//there are multiple segments, leave them, but prune length to total
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
if (_segments[i].start >= _length) setSegment(i, 0, 0);
if (_segments[i].stop > _length) setSegment(i, _segments[i].start, _length);
}
}
}
} }
void WS2812FX::service() { void WS2812FX::service() {
@ -292,12 +259,7 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
#define MA_FOR_ESP 100 //how much mA does the ESP use (Wemos D1 about 80mA, ESP32 about 120mA) #define MA_FOR_ESP 100 //how much mA does the ESP use (Wemos D1 about 80mA, ESP32 about 120mA)
//you can set it to 0 if the ESP is powered by USB and the LEDs by external //you can set it to 0 if the ESP is powered by USB and the LEDs by external
void WS2812FX::show(void) { void WS2812FX::estimateCurrentAndLimitBri() {
// avoid race condition, caputre _callback value
show_callback callback = _callback;
if (callback) callback();
//power limit calculation //power limit calculation
//each LED can draw up 195075 "power units" (approx. 53mA) //each LED can draw up 195075 "power units" (approx. 53mA)
//one PU is the power it takes to have 1 channel 1 step brighter per brightness step //one PU is the power it takes to have 1 channel 1 step brighter per brightness step
@ -310,65 +272,72 @@ void WS2812FX::show(void) {
actualMilliampsPerLed = 12; // from testing an actual strip actualMilliampsPerLed = 12; // from testing an actual strip
} }
if (ablMilliampsMax > 149 && actualMilliampsPerLed > 0) //0 mA per LED and too low numbers turn off calculation if (ablMilliampsMax < 150 || actualMilliampsPerLed == 0) { //0 mA per LED and too low numbers turn off calculation
{
uint32_t puPerMilliamp = 195075 / actualMilliampsPerLed;
uint32_t powerBudget = (ablMilliampsMax - MA_FOR_ESP) * puPerMilliamp; //100mA for ESP power
if (powerBudget > puPerMilliamp * _length) //each LED uses about 1mA in standby, exclude that from power budget
{
powerBudget -= puPerMilliamp * _length;
} else
{
powerBudget = 0;
}
uint32_t powerSum = 0;
for (uint16_t i = 0; i < _length; i++) //sum up the usage of each LED
{
uint32_t c = busses.getPixelColor(i);
byte r = c >> 16, g = c >> 8, b = c, w = c >> 24;
if(useWackyWS2815PowerModel)
{
// ignore white component on WS2815 power calculation
powerSum += (MAX(MAX(r,g),b)) * 3;
}
else
{
powerSum += (r + g + b + w);
}
}
if (isRgbw) //RGBW led total output with white LEDs enabled is still 50mA, so each channel uses less
{
powerSum *= 3;
powerSum = powerSum >> 2; //same as /= 4
}
uint32_t powerSum0 = powerSum;
powerSum *= _brightness;
if (powerSum > powerBudget) //scale brightness down to stay in current limit
{
float scale = (float)powerBudget / (float)powerSum;
uint16_t scaleI = scale * 255;
uint8_t scaleB = (scaleI > 255) ? 255 : scaleI;
uint8_t newBri = scale8(_brightness, scaleB);
busses.setBrightness(newBri);
currentMilliamps = (powerSum0 * newBri) / puPerMilliamp;
} else
{
currentMilliamps = powerSum / puPerMilliamp;
busses.setBrightness(_brightness);
}
currentMilliamps += MA_FOR_ESP; //add power of ESP back to estimate
currentMilliamps += _length; //add standby power back to estimate
} else {
currentMilliamps = 0; currentMilliamps = 0;
busses.setBrightness(_brightness); busses.setBrightness(_brightness);
return;
} }
uint16_t pLen = getLengthPhysical();
uint32_t puPerMilliamp = 195075 / actualMilliampsPerLed;
uint32_t powerBudget = (ablMilliampsMax - MA_FOR_ESP) * puPerMilliamp; //100mA for ESP power
if (powerBudget > puPerMilliamp * pLen) { //each LED uses about 1mA in standby, exclude that from power budget
powerBudget -= puPerMilliamp * pLen;
} else {
powerBudget = 0;
}
uint32_t powerSum = 0;
for (uint8_t b = 0; b < busses.getNumBusses(); b++) {
Bus *bus = busses.getBus(b);
if (bus->getType() >= TYPE_NET_DDP_RGB) continue; //exclude non-physical network busses
uint16_t len = bus->getLength();
uint32_t busPowerSum = 0;
for (uint16_t i = 0; i < len; i++) { //sum up the usage of each LED
uint32_t c = bus->getPixelColor(i);
byte r = c >> 16, g = c >> 8, b = c, w = c >> 24;
if(useWackyWS2815PowerModel) { //ignore white component on WS2815 power calculation
busPowerSum += (MAX(MAX(r,g),b)) * 3;
} else {
busPowerSum += (r + g + b + w);
}
}
if (bus->isRgbw()) { //RGBW led total output with white LEDs enabled is still 50mA, so each channel uses less
busPowerSum *= 3;
busPowerSum = busPowerSum >> 2; //same as /= 4
}
powerSum += busPowerSum;
}
uint32_t powerSum0 = powerSum;
powerSum *= _brightness;
if (powerSum > powerBudget) //scale brightness down to stay in current limit
{
float scale = (float)powerBudget / (float)powerSum;
uint16_t scaleI = scale * 255;
uint8_t scaleB = (scaleI > 255) ? 255 : scaleI;
uint8_t newBri = scale8(_brightness, scaleB);
busses.setBrightness(newBri); //to keep brightness uniform, sets virtual busses too
currentMilliamps = (powerSum0 * newBri) / puPerMilliamp;
} else {
currentMilliamps = powerSum / puPerMilliamp;
busses.setBrightness(_brightness);
}
currentMilliamps += MA_FOR_ESP; //add power of ESP back to estimate
currentMilliamps += pLen; //add standby power back to estimate
}
void WS2812FX::show(void) {
// avoid race condition, caputre _callback value
show_callback callback = _callback;
if (callback) callback();
estimateCurrentAndLimitBri();
// some buses send asynchronously and this method will return before // some buses send asynchronously and this method will return before
// all of the data has been sent. // all of the data has been sent.
@ -586,6 +555,20 @@ uint32_t WS2812FX::getLastShow(void) {
return _lastShow; return _lastShow;
} }
uint16_t WS2812FX::getLengthTotal(void) {
return _length;
}
uint16_t WS2812FX::getLengthPhysical(void) {
uint16_t len = 0;
for (uint8_t b = 0; b < busses.getNumBusses(); b++) {
Bus *bus = busses.getBus(b);
if (bus->getType() >= TYPE_NET_DDP_RGB) continue; //exclude non-physical network busses
len += bus->getLength();
}
return len;
}
void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing) { void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing) {
if (n >= MAX_NUM_SEGMENTS) return; if (n >= MAX_NUM_SEGMENTS) return;
Segment& seg = _segments[n]; Segment& seg = _segments[n];
@ -654,23 +637,67 @@ void WS2812FX::resetSegments() {
_segment_runtimes[0].reset(); _segment_runtimes[0].reset();
} }
void WS2812FX::populateDefaultSegments() { void WS2812FX::makeAutoSegments() {
uint16_t length = 0; uint16_t segStarts[MAX_NUM_SEGMENTS] = {0};
for (uint8_t i=0; i<busses.getNumBusses(); i++) { uint16_t segStops [MAX_NUM_SEGMENTS] = {0};
Bus *bus = busses.getBus(i);
if (bus == nullptr) continue; if (autoSegments) { //make one segment per bus
_segments[i].start = bus->getStart(); uint8_t s = 0;
length += bus->getLength(); for (uint8_t i = 0; i < busses.getNumBusses(); i++) {
_segments[i].stop = _segments[i].start + bus->getLength(); Bus* b = busses.getBus(i);
_segments[i].mode = DEFAULT_MODE;
_segments[i].colors[0] = DEFAULT_COLOR; segStarts[s] = b->getStart();
_segments[i].speed = DEFAULT_SPEED; segStops[s] = segStarts[s] + b->getLength();
_segments[i].intensity = DEFAULT_INTENSITY;
_segments[i].grouping = 1; //check for overlap with previous segments
_segments[i].setOption(SEG_OPTION_SELECTED, 1); for (uint8_t j = 0; j < s; j++) {
_segments[i].setOption(SEG_OPTION_ON, 1); if (segStops[j] > segStarts[s] && segStarts[j] < segStops[s]) {
_segments[i].opacity = 255; //segments overlap, merge
segStarts[j] = min(segStarts[s],segStarts[j]);
segStops [j] = max(segStops [s],segStops [j]); segStops[s] = 0;
s--;
}
}
s++;
}
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) {
setSegment(i, segStarts[i], segStops[i]);
}
} else {
//expand the main seg to the entire length, but only if there are no other segments
uint8_t mainSeg = getMainSegmentId();
if (getActiveSegmentsNum() < 2) {
setSegment(mainSeg, 0, _length);
}
} }
fixInvalidSegments();
}
void WS2812FX::fixInvalidSegments() {
//make sure no segment is longer than total (sanity check)
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
if (_segments[i].start >= _length) setSegment(i, 0, 0);
if (_segments[i].stop > _length) setSegment(i, _segments[i].start, _length);
}
}
//true if all segments align with a bus, or if a segment covers the total length
bool WS2812FX::checkSegmentAlignment() {
for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++)
{
if (_segments[i].start >= _segments[i].stop) continue; //inactive segment
bool aligned = false;
for (uint8_t b = 0; b<busses.getNumBusses(); b++) {
Bus *bus = busses.getBus(b);
if (_segments[i].start == bus->getStart() && _segments[i].stop == bus->getStart() + bus->getLength()) aligned = true;
}
if (_segments[i].start == 0 && _segments[i].stop == _length) aligned = true;
if (!aligned) return false;
}
return true;
} }
//After this function is called, setPixelColor() will use that segment (offsets, grouping, ... will apply) //After this function is called, setPixelColor() will use that segment (offsets, grouping, ... will apply)

View File

@ -24,6 +24,10 @@
#define DEBUG_PRINTF(x...) #define DEBUG_PRINTF(x...)
#endif #endif
#define GET_BIT(var,bit) (((var)>>(bit))&0x01)
#define SET_BIT(var,bit) ((var)|=(uint16_t)(0x0001<<(bit)))
#define UNSET_BIT(var,bit) ((var)&=(~(uint16_t)(0x0001<<(bit))))
//temporary struct for passing bus configuration to bus //temporary struct for passing bus configuration to bus
struct BusConfig { struct BusConfig {
uint8_t type = TYPE_WS2812_RGB; uint8_t type = TYPE_WS2812_RGB;
@ -32,10 +36,12 @@ struct BusConfig {
uint8_t colorOrder = COL_ORDER_GRB; uint8_t colorOrder = COL_ORDER_GRB;
bool reversed = false; bool reversed = false;
uint8_t skipAmount; uint8_t skipAmount;
bool refreshReq;
uint8_t pins[5] = {LEDPIN, 255, 255, 255, 255}; 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) { 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) {
type = busType; count = len; start = pstart; refreshReq = (bool) GET_BIT(busType,7);
colorOrder = pcolorOrder; reversed = rev; skipAmount = skip; 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;
uint8_t nPins = 1; uint8_t nPins = 1;
if (type >= TYPE_NET_DDP_RGB && type < 96) nPins = 4; //virtual network bus. 4 "pins" store IP address if (type >= TYPE_NET_DDP_RGB && type < 96) nPins = 4; //virtual network bus. 4 "pins" store IP address
else if (type > 47) nPins = 2; else if (type > 47) nPins = 2;
@ -120,6 +126,10 @@ class Bus {
return false; return false;
} }
inline bool isOffRefreshRequired() {
return _needsRefresh;
}
bool reversed = false; bool reversed = false;
protected: protected:
@ -127,6 +137,7 @@ class Bus {
uint8_t _bri = 255; uint8_t _bri = 255;
uint16_t _start = 0; uint16_t _start = 0;
bool _valid = false; bool _valid = false;
bool _needsRefresh = false;
}; };
@ -143,6 +154,7 @@ class BusDigital : public Bus {
_pins[1] = bc.pins[1]; _pins[1] = bc.pins[1];
} }
reversed = bc.reversed; reversed = bc.reversed;
_needsRefresh = bc.refreshReq || bc.type == TYPE_TM1814;
_skip = bc.skipAmount; //sacrificial pixels _skip = bc.skipAmount; //sacrificial pixels
_len = bc.count + _skip; _len = bc.count + _skip;
_iType = PolyBus::getI(bc.type, _pins, nr); _iType = PolyBus::getI(bc.type, _pins, nr);
@ -204,7 +216,7 @@ class BusDigital : public Bus {
} }
inline bool isRgbw() { inline bool isRgbw() {
return (_type == TYPE_SK6812_RGBW || _type == TYPE_TM1814); return Bus::isRgbw(_type);
} }
inline uint8_t skippedLeds() { inline uint8_t skippedLeds() {
@ -216,7 +228,7 @@ class BusDigital : public Bus {
} }
void cleanup() { void cleanup() {
DEBUG_PRINTLN("Digital Cleanup"); DEBUG_PRINTLN(F("Digital Cleanup."));
PolyBus::cleanup(_busPtr, _iType); PolyBus::cleanup(_busPtr, _iType);
_iType = I_NONE; _iType = I_NONE;
_valid = false; _valid = false;
@ -326,7 +338,7 @@ class BusPwm : public Bus {
} }
bool isRgbw() { bool isRgbw() {
return (_type > TYPE_ONOFF && _type <= TYPE_ANALOG_5CH && _type != TYPE_ANALOG_3CH); return Bus::isRgbw(_type);
} }
inline void cleanup() { inline void cleanup() {
@ -481,7 +493,7 @@ class BusManager {
static uint32_t memUsage(BusConfig &bc) { static uint32_t memUsage(BusConfig &bc) {
uint8_t type = bc.type; uint8_t type = bc.type;
uint16_t len = bc.count; uint16_t len = bc.count;
if (type < 32) { if (type > 15 && type < 32) {
#ifdef ESP8266 #ifdef ESP8266
if (bc.pins[0] == 3) { //8266 DMA uses 5x the mem if (bc.pins[0] == 3) { //8266 DMA uses 5x the mem
if (type > 29) return len*20; //RGBW if (type > 29) return len*20; //RGBW
@ -496,7 +508,7 @@ class BusManager {
} }
if (type > 31 && type < 48) return 5; if (type > 31 && type < 48) return 5;
if (type == 44 || type == 45) return len*4; //RGBW if (type == 44 || type == 45) return len*4; //RGBW
return len*3; return len*3; //RGB
} }
int add(BusConfig &bc) { int add(BusConfig &bc) {
@ -513,7 +525,7 @@ class BusManager {
//do not call this method from system context (network callback) //do not call this method from system context (network callback)
void removeAll() { void removeAll() {
//Serial.println("Removing all."); DEBUG_PRINTLN(F("Removing all."));
//prevents crashes due to deleting busses while in use. //prevents crashes due to deleting busses while in use.
while (!canAllShow()) yield(); while (!canAllShow()) yield();
for (uint8_t i = 0; i < numBusses; i++) delete busses[i]; for (uint8_t i = 0; i < numBusses; i++) delete busses[i];
@ -573,16 +585,6 @@ class BusManager {
return len; return len;
} }
// a workaround
static inline bool isRgbw(uint8_t type) {
return Bus::isRgbw(type);
}
//Return true if the strip requires a refresh to stay off.
static bool isOffRefreshRequred(uint8_t type) {
return type == TYPE_TM1814;
}
private: private:
uint8_t numBusses = 0; uint8_t numBusses = 0;
Bus* busses[WLED_MAX_BUSSES]; Bus* busses[WLED_MAX_BUSSES];

View File

@ -1,4 +1,5 @@
#include "wled.h" #include "wled.h"
#include "wled_ethernet.h"
/* /*
* Serializes and parses the cfg.json and wsec.json settings files, stored in internal FS. * Serializes and parses the cfg.json and wsec.json settings files, stored in internal FS.
@ -85,10 +86,11 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(strip.rgbwMode, hw_led[F("rgbwm")]); CJSON(strip.rgbwMode, hw_led[F("rgbwm")]);
JsonArray ins = hw_led["ins"]; JsonArray ins = hw_led["ins"];
uint16_t lC = 0;
if (fromFS || !ins.isNull()) { if (fromFS || !ins.isNull()) {
uint8_t s = 0; //bus iterator uint8_t s = 0; // bus iterator
strip.isRgbw = false;
strip.isOffRefreshRequred = false;
busses.removeAll(); busses.removeAll();
uint32_t mem = 0; uint32_t mem = 0;
for (JsonObject elm : ins) { for (JsonObject elm : ins) {
@ -107,22 +109,21 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
uint8_t colorOrder = (int)elm[F("order")]; uint8_t colorOrder = (int)elm[F("order")];
uint8_t skipFirst = elm[F("skip")]; uint8_t skipFirst = elm[F("skip")];
uint16_t start = elm["start"] | 0; 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 ledType = elm["type"] | TYPE_WS2812_RGB;
bool reversed = elm["rev"]; 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);
if (bc.adjustBounds(ledCount)) { mem += BusManager::memUsage(bc);
//RGBW mode is enabled if at least one of the strips is RGBW if (mem <= MAX_LED_MEMORY && busses.getNumBusses() <= WLED_MAX_BUSSES) busses.add(bc); // finalization will be done in WLED::beginStrip()
strip.isRgbw = (strip.isRgbw || BusManager::isRgbw(ledType));
//refresh is required to remain off if at least one of the strips requires the refresh.
strip.isOffRefreshRequred |= BusManager::isOffRefreshRequred(ledType);
s++;
mem += busses.memUsage(bc);
if (mem <= MAX_LED_MEMORY) busses.add(bc);
}
} }
strip.finalizeInit(ledCount); // finalization done in beginStrip()
} }
if (lC > ledCount) ledCount = lC; // fix incorrect total length (honour analog setup)
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 multiple button configuration // read multiple button configuration
@ -501,6 +502,25 @@ void serializeConfig() {
#ifdef WLED_USE_ETHERNET #ifdef WLED_USE_ETHERNET
JsonObject ethernet = doc.createNestedObject("eth"); JsonObject ethernet = doc.createNestedObject("eth");
ethernet["type"] = ethernetType; ethernet["type"] = ethernetType;
if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) {
JsonArray pins = ethernet.createNestedArray("pin");
for (uint8_t p=0; p<WLED_ETH_RSVD_PINS_COUNT; p++) pins.add(esp32_nonconfigurable_ethernet_pins[p].pin);
if (ethernetBoards[ethernetType].eth_power>=0) pins.add(ethernetBoards[ethernetType].eth_power);
if (ethernetBoards[ethernetType].eth_mdc>=0) pins.add(ethernetBoards[ethernetType].eth_mdc);
if (ethernetBoards[ethernetType].eth_mdio>=0) pins.add(ethernetBoards[ethernetType].eth_mdio);
switch (ethernetBoards[ethernetType].eth_clk_mode) {
case ETH_CLOCK_GPIO0_IN:
case ETH_CLOCK_GPIO0_OUT:
pins.add(0);
break;
case ETH_CLOCK_GPIO16_OUT:
pins.add(16);
break;
case ETH_CLOCK_GPIO17_OUT:
pins.add(17);
break;
}
}
#endif #endif
JsonObject hw = doc.createNestedObject("hw"); JsonObject hw = doc.createNestedObject("hw");
@ -526,7 +546,9 @@ void serializeConfig() {
ins[F("order")] = bus->getColorOrder(); ins[F("order")] = bus->getColorOrder();
ins["rev"] = bus->reversed; ins["rev"] = bus->reversed;
ins[F("skip")] = bus->skippedLeds(); ins[F("skip")] = bus->skippedLeds();
ins["type"] = bus->getType(); ins["type"] = bus->getType() & 0x7F;;
ins["ref"] = bus->isOffRefreshRequired();
ins[F("rgbw")] = bus->isRgbw();
} }
// button(s) // button(s)
@ -551,7 +573,7 @@ void serializeConfig() {
JsonObject hw_ir = hw.createNestedObject("ir"); JsonObject hw_ir = hw.createNestedObject("ir");
hw_ir["pin"] = irPin; hw_ir["pin"] = irPin;
hw_ir[F("type")] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled ) hw_ir["type"] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled )
JsonObject hw_relay = hw.createNestedObject(F("relay")); JsonObject hw_relay = hw.createNestedObject(F("relay"));
hw_relay["pin"] = rlyPin; hw_relay["pin"] = rlyPin;

View File

@ -241,10 +241,10 @@
#define NTP_PACKET_SIZE 48 #define NTP_PACKET_SIZE 48
// maximum number of LEDs - more than 1500 LEDs (or 500 DMA "LEDPIN 3" driven ones) will cause a low memory condition on ESP8266 //maximum number of rendered LEDs - this does not have to match max. physical LEDs, e.g. if there are virtual busses
#ifndef MAX_LEDS #ifndef MAX_LEDS
#ifdef ESP8266 #ifdef ESP8266
#define MAX_LEDS 1664 // can't rely on memory limit to limit this to 1600 LEDs #define MAX_LEDS 1664 //can't rely on memory limit to limit this to 1600 LEDs
#else #else
#define MAX_LEDS 8192 #define MAX_LEDS 8192
#endif #endif

View File

@ -1296,9 +1296,9 @@ var plJson = {"0":{
"end": 0 "end": 0
}}; }};
//var plSelContent = "";
function makePlSel(incPl=false) { function makePlSel(incPl=false) {
var plSelContent = ""; var plSelContent = "";
delete pJson["0"]; // remove filler preset
var arr = Object.entries(pJson); var arr = Object.entries(pJson);
for (var i = 0; i < arr.length; i++) { for (var i = 0; i < arr.length; i++) {
var n = arr[i][1].n ? arr[i][1].n : "Preset " + arr[i][0]; var n = arr[i][1].n ? arr[i][1].n : "Preset " + arr[i][0];

View File

@ -160,13 +160,16 @@
} }
} }
if (change) { if (change) {
gId("rf"+n).checked = (gId("rf"+n).checked || t == 31); // LEDs require data in off state
if (t > 31 && t < 48) d.getElementsByName("LC"+n)[0].value = 1; // for sanity change analog count just to 1 LED if (t > 31 && t < 48) d.getElementsByName("LC"+n)[0].value = 1; // for sanity change analog count just to 1 LED
} }
gId("rf"+n).onclick = (t == 31) ? (function(){return false}) : (function(){}); // prevent change for TM1814
isRGBW |= (t == 30 || t == 31 || (t > 40 && t < 46 && t != 43)); // RGBW checkbox, TYPE_xxxx values from const.h isRGBW |= (t == 30 || t == 31 || (t > 40 && t < 46 && t != 43)); // RGBW checkbox, TYPE_xxxx values from const.h
gId("co"+n).style.display = ((t>=80 && t<96) || t == 41 || t == 42) ? "none":"inline"; // hide color order for PWM W & WW/CW gId("co"+n).style.display = ((t>=80 && t<96) || t == 41 || t == 42) ? "none":"inline"; // hide color order for PWM W & WW/CW
gId("dig"+n+"c").style.display = (t > 40 && t < 48) ? "none":"inline"; // hide count for analog gId("dig"+n+"c").style.display = (t > 40 && t < 48) ? "none":"inline"; // hide count for analog
gId("dig"+n+"r").style.display = (t>=80 && t<96) ? "none":"inline"; // hide reversed for virtual 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+"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("rev"+n).innerHTML = (t > 40 && t < 48) ? "Inverted output":"Reversed (rotated 180°)"; // change reverse text for analog 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 gId("psd"+n).innerHTML = (t > 40 && t < 48) ? "Index:":"Start:"; // change analog start description
} }
@ -328,9 +331,9 @@ ${i+1}:
<span id="p2d${i}"></span><input type="number" name="L2${i}" min="0" max="33" class="xs" onchange="UI()"/> <span id="p2d${i}"></span><input type="number" name="L2${i}" min="0" max="33" class="xs" onchange="UI()"/>
<span id="p3d${i}"></span><input type="number" name="L3${i}" min="0" max="33" class="xs" onchange="UI()"/> <span id="p3d${i}"></span><input type="number" name="L3${i}" min="0" max="33" class="xs" onchange="UI()"/>
<span id="p4d${i}"></span><input type="number" name="L4${i}" min="0" max="33" class="xs" onchange="UI()"/> <span id="p4d${i}"></span><input type="number" name="L4${i}" min="0" max="33" class="xs" onchange="UI()"/>
<br> <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}r" style="display:inline"><span id="rev${i}">Reversed</span>: <input type="checkbox" name="CV${i}">&nbsp;</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}s" style="display:inline">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>`; </div>`;
f.insertAdjacentHTML("beforeend", cn); f.insertAdjacentHTML("beforeend", cn);
} }

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -90,7 +90,6 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
} }
} }
strip.isRgbw = false;
uint8_t colorOrder, type, skip; uint8_t colorOrder, type, skip;
uint16_t length, start; uint16_t length, start;
uint8_t pins[5] = {255, 255, 255, 255, 255}; uint8_t pins[5] = {255, 255, 255, 255, 255};
@ -105,6 +104,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
char ls[4] = "LS"; ls[2] = 48+s; ls[3] = 0; //strip start LED char ls[4] = "LS"; ls[2] = 48+s; ls[3] = 0; //strip start LED
char cv[4] = "CV"; cv[2] = 48+s; cv[3] = 0; //strip reverse 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 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
if (!request->hasArg(lp)) { if (!request->hasArg(lp)) {
DEBUG_PRINTLN(F("No data.")); break; DEBUG_PRINTLN(F("No data.")); break;
} }
@ -114,24 +114,21 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
pins[i] = (request->arg(lp).length() > 0) ? request->arg(lp).toInt() : 255; pins[i] = (request->arg(lp).length() > 0) ? request->arg(lp).toInt() : 255;
} }
type = request->arg(lt).toInt(); type = request->arg(lt).toInt();
strip.isRgbw = strip.isRgbw || BusManager::isRgbw(type); type |= request->hasArg(rf) << 7; // off refresh override
skip = request->hasArg(sl) ? LED_SKIP_AMOUNT : 0; skip = request->hasArg(sl) ? LED_SKIP_AMOUNT : 0;
colorOrder = request->arg(co).toInt();
start = (request->hasArg(ls)) ? request->arg(ls).toInt() : t;
if (request->hasArg(lc) && request->arg(lc).toInt() > 0) { if (request->hasArg(lc) && request->arg(lc).toInt() > 0) {
length = request->arg(lc).toInt(); t += length = request->arg(lc).toInt();
} else { } else {
break; // no parameter break; // no parameter
} }
colorOrder = request->arg(co).toInt(); // actual finalization is done in WLED::loop() (removing old busses and adding new)
start = (request->hasArg(ls)) ? request->arg(ls).toInt() : 0;
if (busConfigs[s] != nullptr) delete busConfigs[s]; 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);
if (!doInitBusses) ledCount = 1;
doInitBusses = true; doInitBusses = true;
uint16_t totalNew = start + length;
if (totalNew > ledCount && totalNew <= MAX_LEDS) ledCount = totalNew; //total is end of last bus (where start + len is max.)
} }
// upate other pins // upate other pins
@ -181,7 +178,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
fadeTransition = request->hasArg(F("TF")); fadeTransition = request->hasArg(F("TF"));
t = request->arg(F("TD")).toInt(); t = request->arg(F("TD")).toInt();
if (t > 0) transitionDelay = t; if (t >= 0) transitionDelay = t;
transitionDelayDefault = t; transitionDelayDefault = t;
strip.paletteFade = request->hasArg(F("PF")); strip.paletteFade = request->hasArg(F("PF"));
@ -506,9 +503,6 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
DEBUG_PRINTLN(value); DEBUG_PRINTLN(value);
} }
} }
#ifdef WLED_DEBUG
serializeJson(um,Serial); DEBUG_PRINTLN();
#endif
usermods.readFromConfig(um); // force change of usermod parameters usermods.readFromConfig(um); // force change of usermod parameters
} }
@ -535,11 +529,10 @@ bool updateVal(const String* req, const char* key, byte* val, byte minv, byte ma
int out = getNumVal(req, pos+1); int out = getNumVal(req, pos+1);
if (out == 0) if (out == 0)
{ {
if (req->charAt(pos+4) == '-') if (req->charAt(pos+4) == '-') {
{ *val = min((int)maxv, max((int)minv, (int)(*val -1)));
*val = (*val <= minv)? maxv : *val -1;
} else { } else {
*val = (*val >= maxv)? minv : *val +1; *val = min((int)maxv, max((int)minv, (int)(*val +1)));
} }
} else { } else {
out += *val; out += *val;
@ -581,7 +574,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
if (t < strip.getMaxSegments()) selectedSeg = t; if (t < strip.getMaxSegments()) selectedSeg = t;
} }
WS2812FX::Segment& mainseg = strip.getSegment(selectedSeg); WS2812FX::Segment& selseg = strip.getSegment(selectedSeg);
pos = req.indexOf(F("SV=")); //segment selected pos = req.indexOf(F("SV=")); //segment selected
if (pos > 0) { if (pos > 0) {
byte t = getNumVal(&req, pos); byte t = getNumVal(&req, pos);
@ -591,13 +584,13 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
strip.getSegment(i).setOption(SEG_OPTION_SELECTED, 0); strip.getSegment(i).setOption(SEG_OPTION_SELECTED, 0);
} }
} }
mainseg.setOption(SEG_OPTION_SELECTED, t); selseg.setOption(SEG_OPTION_SELECTED, t);
} }
uint16_t startI = mainseg.start; uint16_t startI = selseg.start;
uint16_t stopI = mainseg.stop; uint16_t stopI = selseg.stop;
uint8_t grpI = mainseg.grouping; uint8_t grpI = selseg.grouping;
uint16_t spcI = mainseg.spacing; uint16_t spcI = selseg.spacing;
pos = req.indexOf(F("&S=")); //segment start pos = req.indexOf(F("&S=")); //segment start
if (pos > 0) { if (pos > 0) {
startI = getNumVal(&req, pos); startI = getNumVal(&req, pos);
@ -617,9 +610,36 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
} }
strip.setSegment(selectedSeg, startI, stopI, grpI, spcI); strip.setSegment(selectedSeg, startI, stopI, grpI, spcI);
pos = req.indexOf(F("RV=")); //Segment reverse
if (pos > 0) selseg.setOption(SEG_OPTION_REVERSED, req.charAt(pos+3) != '0');
pos = req.indexOf(F("MI=")); //Segment mirror
if (pos > 0) selseg.setOption(SEG_OPTION_MIRROR, req.charAt(pos+3) != '0');
pos = req.indexOf(F("SB=")); //Segment brightness/opacity
if (pos > 0) {
byte segbri = getNumVal(&req, pos);
selseg.setOption(SEG_OPTION_ON, segbri, selectedSeg);
if (segbri) {
selseg.setOpacity(segbri, selectedSeg);
}
}
pos = req.indexOf(F("SW=")); //segment power
if (pos > 0) {
switch (getNumVal(&req, pos)) {
case 0: selseg.setOption(SEG_OPTION_ON, false); break;
case 1: selseg.setOption(SEG_OPTION_ON, true); break;
default: selseg.setOption(SEG_OPTION_ON, !selseg.getOption(SEG_OPTION_ON)); break;
}
}
pos = req.indexOf(F("PS=")); //saves current in preset pos = req.indexOf(F("PS=")); //saves current in preset
if (pos > 0) savePreset(getNumVal(&req, pos)); if (pos > 0) savePreset(getNumVal(&req, pos));
byte presetCycleMin = 1;
byte presetCycleMax = 5;
pos = req.indexOf(F("P1=")); //sets first preset for cycle pos = req.indexOf(F("P1=")); //sets first preset for cycle
if (pos > 0) presetCycleMin = getNumVal(&req, pos); if (pos > 0) presetCycleMin = getNumVal(&req, pos);
@ -707,7 +727,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
strip.applyToAllSelected = true; strip.applyToAllSelected = true;
strip.setColor(2, t[0], t[1], t[2], t[3]); strip.setColor(2, t[0], t[1], t[2], t[3]);
} else { } else {
strip.getSegment(selectedSeg).setColor(2,((t[0] << 16) + (t[1] << 8) + t[2] + (t[3] << 24)), selectedSeg); selseg.setColor(2,((t[0] << 16) + (t[1] << 8) + t[2] + (t[3] << 24)), selectedSeg); // defined above (SS=)
} }
} }
@ -811,24 +831,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
pos = req.indexOf(F("TT=")); pos = req.indexOf(F("TT="));
if (pos > 0) transitionDelay = getNumVal(&req, pos); if (pos > 0) transitionDelay = getNumVal(&req, pos);
//Segment reverse
pos = req.indexOf(F("RV="));
if (pos > 0) strip.getSegment(selectedSeg).setOption(SEG_OPTION_REVERSED, req.charAt(pos+3) != '0');
//Segment reverse
pos = req.indexOf(F("MI="));
if (pos > 0) strip.getSegment(selectedSeg).setOption(SEG_OPTION_MIRROR, req.charAt(pos+3) != '0');
//Segment brightness/opacity
pos = req.indexOf(F("SB="));
if (pos > 0) {
byte segbri = getNumVal(&req, pos);
strip.getSegment(selectedSeg).setOption(SEG_OPTION_ON, segbri, selectedSeg);
if (segbri) {
strip.getSegment(selectedSeg).setOpacity(segbri, selectedSeg);
}
}
//set time (unix timestamp) //set time (unix timestamp)
pos = req.indexOf(F("ST=")); pos = req.indexOf(F("ST="));
if (pos > 0) { if (pos > 0) {

View File

@ -209,25 +209,23 @@ void WLED::loop()
if (doInitBusses) { if (doInitBusses) {
doInitBusses = false; doInitBusses = false;
DEBUG_PRINTLN(F("Re-init busses.")); DEBUG_PRINTLN(F("Re-init busses."));
bool aligned = strip.checkSegmentAlignment(); //see if old segments match old bus(ses)
busses.removeAll(); busses.removeAll();
uint32_t mem = 0; uint32_t mem = 0;
strip.isRgbw = false; ledCount = 1;
for (uint8_t i = 0; i < WLED_MAX_BUSSES; i++) { for (uint8_t i = 0; i < WLED_MAX_BUSSES; i++) {
if (busConfigs[i] == nullptr) break; if (busConfigs[i] == nullptr) break;
mem += BusManager::memUsage(*busConfigs[i]);
if (busConfigs[i]->adjustBounds(ledCount)) { if (mem <= MAX_LED_MEMORY) {
mem += busses.memUsage(*busConfigs[i]); uint16_t totalNew = busConfigs[i]->start + busConfigs[i]->count;
if (mem <= MAX_LED_MEMORY) { if (totalNew > ledCount && totalNew <= MAX_LEDS) ledCount = totalNew; //total is end of last bus (where start + len is max.)
busses.add(*busConfigs[i]); busses.add(*busConfigs[i]);
//RGBW mode is enabled if at least one of the strips is RGBW
strip.isRgbw = (strip.isRgbw || BusManager::isRgbw(busConfigs[i]->type));
//refresh is required to remain off if at least one of the strips requires the refresh.
strip.isOffRefreshRequred |= BusManager::isOffRefreshRequred(busConfigs[i]->type);
}
} }
delete busConfigs[i]; busConfigs[i] = nullptr; delete busConfigs[i]; busConfigs[i] = nullptr;
} }
strip.finalizeInit(ledCount); strip.finalizeInit();
if (aligned) strip.makeAutoSegments();
else strip.fixInvalidSegments();
yield(); yield();
serializeConfig(); serializeConfig();
} }
@ -407,11 +405,8 @@ void WLED::setup()
void WLED::beginStrip() void WLED::beginStrip()
{ {
// Initialize NeoPixel Strip and button // Initialize NeoPixel Strip and button
strip.finalizeInit(); // busses created during deserializeConfig()
if (ledCount > MAX_LEDS || ledCount == 0) strip.makeAutoSegments();
ledCount = 30;
strip.finalizeInit(ledCount);
strip.setBrightness(0); strip.setBrightness(0);
strip.setShowCallback(handleOverlayDraw); strip.setShowCallback(handleOverlayDraw);
@ -784,4 +779,4 @@ void WLED::handleStatusLED()
} }
#endif #endif
} }

View File

@ -366,7 +366,7 @@ WLED_GLOBAL byte currentTimezone _INIT(0); // Timezone ID. Refer to timez
WLED_GLOBAL int utcOffsetSecs _INIT(0); // Seconds to offset from UTC before timzone calculation WLED_GLOBAL int utcOffsetSecs _INIT(0); // Seconds to offset from UTC before timzone calculation
WLED_GLOBAL byte overlayDefault _INIT(0); // 0: no overlay 1: analog clock 2: single-digit clock 3: cronixie WLED_GLOBAL byte overlayDefault _INIT(0); // 0: no overlay 1: analog clock 2: single-digit clock 3: cronixie
WLED_GLOBAL byte overlayMin _INIT(0), overlayMax _INIT(ledCount - 1); // boundaries of overlay mode WLED_GLOBAL byte overlayMin _INIT(0), overlayMax _INIT(DEFAULT_LED_COUNT - 1); // boundaries of overlay mode
WLED_GLOBAL byte analogClock12pixel _INIT(0); // The pixel in your strip where "midnight" would be WLED_GLOBAL byte analogClock12pixel _INIT(0); // The pixel in your strip where "midnight" would be
WLED_GLOBAL bool analogClockSecondsTrail _INIT(false); // Display seconds as trail of LEDs instead of a single pixel WLED_GLOBAL bool analogClockSecondsTrail _INIT(false); // Display seconds as trail of LEDs instead of a single pixel
@ -511,8 +511,7 @@ WLED_GLOBAL bool blynkEnabled _INIT(false);
WLED_GLOBAL unsigned long presetCycledTime _INIT(0); WLED_GLOBAL unsigned long presetCycledTime _INIT(0);
WLED_GLOBAL int16_t currentPlaylist _INIT(-1); WLED_GLOBAL int16_t currentPlaylist _INIT(-1);
//still used for "PL=~" HTTP API command //still used for "PL=~" HTTP API command
WLED_GLOBAL byte presetCycleMin _INIT(1), presetCycleMax _INIT(5); WLED_GLOBAL byte presetCycCurr _INIT(0);
WLED_GLOBAL byte presetCycCurr _INIT(presetCycleMin);
// realtime // realtime
WLED_GLOBAL byte realtimeMode _INIT(REALTIME_MODE_INACTIVE); WLED_GLOBAL byte realtimeMode _INIT(REALTIME_MODE_INACTIVE);

View File

@ -380,6 +380,7 @@ void getSettingsJS(byte subPage, char* dest)
char ls[4] = "LS"; ls[2] = 48+s; ls[3] = 0; //strip start LED char ls[4] = "LS"; ls[2] = 48+s; ls[3] = 0; //strip start LED
char cv[4] = "CV"; cv[2] = 48+s; cv[3] = 0; //strip reverse 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 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
oappend(SET_F("addLEDs(1);")); oappend(SET_F("addLEDs(1);"));
uint8_t pins[5]; uint8_t pins[5];
uint8_t nPins = bus->getPins(pins); uint8_t nPins = bus->getPins(pins);
@ -393,6 +394,7 @@ void getSettingsJS(byte subPage, char* dest)
sappend('v',ls,bus->getStart()); sappend('v',ls,bus->getStart());
sappend('c',cv,bus->reversed); sappend('c',cv,bus->reversed);
sappend('c',sl,bus->skippedLeds()); sappend('c',sl,bus->skippedLeds());
sappend('c',rf,bus->isOffRefreshRequired());
} }
sappend('v',SET_F("MA"),strip.ablMilliampsMax); sappend('v',SET_F("MA"),strip.ablMilliampsMax);
sappend('v',SET_F("LA"),strip.milliampsPerLed); sappend('v',SET_F("LA"),strip.milliampsPerLed);