Add strip off refresh option in LED settings. (#2259)
* Add strip off refresh option in LED settings. New strip initialization logic. Minor code clen-up. * Dev code removal. * Missing ethernet include * Renamed mainseg to selseg * Fix for preset cycling bounds. * "Preset 0" bugfix. * Auto segments only if segments were not modified Co-authored-by: cschwinne <dev.aircoookie@gmail.com>
This commit is contained in:
parent
b89f7180db
commit
8b2145bd88
@ -619,7 +619,7 @@ class WS2812FX {
|
||||
}
|
||||
|
||||
void
|
||||
finalizeInit(uint16_t countPixels),
|
||||
finalizeInit(),
|
||||
service(void),
|
||||
blur(uint8_t),
|
||||
fill(uint32_t),
|
||||
@ -636,7 +636,8 @@ class WS2812FX {
|
||||
trigger(void),
|
||||
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 0, uint8_t spacing = 0),
|
||||
resetSegments(),
|
||||
populateDefaultSegments(),
|
||||
makeAutoSegments(),
|
||||
fixInvalidSegments(),
|
||||
setPixelColor(uint16_t n, uint32_t c),
|
||||
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
|
||||
show(void),
|
||||
@ -650,6 +651,7 @@ class WS2812FX {
|
||||
gammaCorrectCol = true,
|
||||
applyToAllSelected = true,
|
||||
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
|
||||
isUpdating(void);
|
||||
|
||||
|
@ -65,25 +65,22 @@
|
||||
#endif
|
||||
|
||||
//do not call this method from system context (network callback)
|
||||
void WS2812FX::finalizeInit(uint16_t countPixels)
|
||||
void WS2812FX::finalizeInit(void)
|
||||
{
|
||||
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) {
|
||||
const uint8_t defDataPins[] = {DATA_PINS};
|
||||
const uint16_t defCounts[] = {PIXEL_COUNTS};
|
||||
const uint8_t defNumBusses = ((sizeof defDataPins) / (sizeof defDataPins[0]));
|
||||
const uint8_t defNumCounts = ((sizeof defCounts) / (sizeof defCounts[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]};
|
||||
uint16_t start = prevLen;
|
||||
uint16_t count = _length;
|
||||
if (defNumBusses > 1 && defNumCounts) {
|
||||
count = defCounts[(i < defNumCounts) ? i : defNumCounts -1];
|
||||
}
|
||||
uint16_t count = defCounts[(i < defNumCounts) ? i : defNumCounts -1];
|
||||
prevLen += count;
|
||||
BusConfig defCfg = BusConfig(DEFAULT_LED_TYPE, defPin, start, count, COL_ORDER_GRB);
|
||||
busses.add(defCfg);
|
||||
@ -92,60 +89,30 @@ void WS2812FX::finalizeInit(uint16_t countPixels)
|
||||
|
||||
deserializeMap();
|
||||
|
||||
uint16_t segStarts[MAX_NUM_SEGMENTS] = {0};
|
||||
uint16_t segStops [MAX_NUM_SEGMENTS] = {0};
|
||||
|
||||
setBrightness(_brightness);
|
||||
|
||||
//TODO make sure segments are only refreshed when bus config actually changed (new settings page)
|
||||
uint8_t s = 0;
|
||||
for (uint8_t i = 0; i < busses.getNumBusses(); i++) {
|
||||
Bus* b = busses.getBus(i);
|
||||
|
||||
if (autoSegments) { //make one segment per bus
|
||||
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++;
|
||||
}
|
||||
|
||||
_length = 0;
|
||||
for (uint8_t i=0; i<busses.getNumBusses(); i++) {
|
||||
Bus *bus = busses.getBus(i);
|
||||
if (bus == nullptr) continue;
|
||||
if (bus->getStart() + bus->getLength() > MAX_LEDS) break;
|
||||
//RGBW mode is enabled if at least one of the strips is RGBW
|
||||
isRgbw |= bus->isRgbw();
|
||||
//refresh is required to remain off if at least one of the strips requires the refresh.
|
||||
isOffRefreshRequred |= bus->isOffRefreshRequired();
|
||||
uint16_t busEnd = bus->getStart() + bus->getLength();
|
||||
if (busEnd > _length) _length = busEnd;
|
||||
#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];
|
||||
b->getPins(pins);
|
||||
BusDigital* bd = static_cast<BusDigital*>(b);
|
||||
if (!bus->getPins(pins)) continue;
|
||||
BusDigital* bd = static_cast<BusDigital*>(bus);
|
||||
if (pins[0] == 3) bd->reinit();
|
||||
#endif
|
||||
}
|
||||
ledCount = _length;
|
||||
|
||||
if (autoSegments) {
|
||||
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);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
//segments are created in makeAutoSegments();
|
||||
|
||||
setBrightness(_brightness);
|
||||
}
|
||||
|
||||
void WS2812FX::service() {
|
||||
@ -654,23 +621,67 @@ void WS2812FX::resetSegments() {
|
||||
_segment_runtimes[0].reset();
|
||||
}
|
||||
|
||||
void WS2812FX::populateDefaultSegments() {
|
||||
uint16_t length = 0;
|
||||
for (uint8_t i=0; i<busses.getNumBusses(); i++) {
|
||||
Bus *bus = busses.getBus(i);
|
||||
if (bus == nullptr) continue;
|
||||
_segments[i].start = bus->getStart();
|
||||
length += bus->getLength();
|
||||
_segments[i].stop = _segments[i].start + bus->getLength();
|
||||
_segments[i].mode = DEFAULT_MODE;
|
||||
_segments[i].colors[0] = DEFAULT_COLOR;
|
||||
_segments[i].speed = DEFAULT_SPEED;
|
||||
_segments[i].intensity = DEFAULT_INTENSITY;
|
||||
_segments[i].grouping = 1;
|
||||
_segments[i].setOption(SEG_OPTION_SELECTED, 1);
|
||||
_segments[i].setOption(SEG_OPTION_ON, 1);
|
||||
_segments[i].opacity = 255;
|
||||
void WS2812FX::makeAutoSegments() {
|
||||
uint16_t segStarts[MAX_NUM_SEGMENTS] = {0};
|
||||
uint16_t segStops [MAX_NUM_SEGMENTS] = {0};
|
||||
|
||||
if (autoSegments) { //make one segment per bus
|
||||
uint8_t s = 0;
|
||||
for (uint8_t i = 0; i < busses.getNumBusses(); i++) {
|
||||
Bus* b = busses.getBus(i);
|
||||
|
||||
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++;
|
||||
}
|
||||
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)
|
||||
|
@ -24,6 +24,10 @@
|
||||
#define DEBUG_PRINTF(x...)
|
||||
#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
|
||||
struct BusConfig {
|
||||
uint8_t type = TYPE_WS2812_RGB;
|
||||
@ -32,10 +36,12 @@ struct BusConfig {
|
||||
uint8_t colorOrder = COL_ORDER_GRB;
|
||||
bool reversed = false;
|
||||
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) {
|
||||
type = busType; count = len; start = pstart;
|
||||
colorOrder = pcolorOrder; reversed = rev; skipAmount = skip;
|
||||
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) {
|
||||
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;
|
||||
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;
|
||||
@ -120,6 +126,10 @@ class Bus {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool isOffRefreshRequired() {
|
||||
return _needsRefresh;
|
||||
}
|
||||
|
||||
bool reversed = false;
|
||||
|
||||
protected:
|
||||
@ -127,6 +137,7 @@ class Bus {
|
||||
uint8_t _bri = 255;
|
||||
uint16_t _start = 0;
|
||||
bool _valid = false;
|
||||
bool _needsRefresh = false;
|
||||
};
|
||||
|
||||
|
||||
@ -143,6 +154,7 @@ class BusDigital : public Bus {
|
||||
_pins[1] = bc.pins[1];
|
||||
}
|
||||
reversed = bc.reversed;
|
||||
_needsRefresh = bc.refreshReq || bc.type == TYPE_TM1814;
|
||||
_skip = bc.skipAmount; //sacrificial pixels
|
||||
_len = bc.count + _skip;
|
||||
_iType = PolyBus::getI(bc.type, _pins, nr);
|
||||
@ -204,7 +216,7 @@ class BusDigital : public Bus {
|
||||
}
|
||||
|
||||
inline bool isRgbw() {
|
||||
return (_type == TYPE_SK6812_RGBW || _type == TYPE_TM1814);
|
||||
return Bus::isRgbw(_type);
|
||||
}
|
||||
|
||||
inline uint8_t skippedLeds() {
|
||||
@ -216,7 +228,7 @@ class BusDigital : public Bus {
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
DEBUG_PRINTLN("Digital Cleanup");
|
||||
DEBUG_PRINTLN(F("Digital Cleanup."));
|
||||
PolyBus::cleanup(_busPtr, _iType);
|
||||
_iType = I_NONE;
|
||||
_valid = false;
|
||||
@ -326,7 +338,7 @@ class BusPwm : public Bus {
|
||||
}
|
||||
|
||||
bool isRgbw() {
|
||||
return (_type > TYPE_ONOFF && _type <= TYPE_ANALOG_5CH && _type != TYPE_ANALOG_3CH);
|
||||
return Bus::isRgbw(_type);
|
||||
}
|
||||
|
||||
inline void cleanup() {
|
||||
@ -481,7 +493,7 @@ class BusManager {
|
||||
static uint32_t memUsage(BusConfig &bc) {
|
||||
uint8_t type = bc.type;
|
||||
uint16_t len = bc.count;
|
||||
if (type < 32) {
|
||||
if (type > 15 && type < 32) {
|
||||
#ifdef ESP8266
|
||||
if (bc.pins[0] == 3) { //8266 DMA uses 5x the mem
|
||||
if (type > 29) return len*20; //RGBW
|
||||
@ -496,7 +508,7 @@ class BusManager {
|
||||
}
|
||||
if (type > 31 && type < 48) return 5;
|
||||
if (type == 44 || type == 45) return len*4; //RGBW
|
||||
return len*3;
|
||||
return len*3; //RGB
|
||||
}
|
||||
|
||||
int add(BusConfig &bc) {
|
||||
@ -513,7 +525,7 @@ class BusManager {
|
||||
|
||||
//do not call this method from system context (network callback)
|
||||
void removeAll() {
|
||||
//Serial.println("Removing all.");
|
||||
DEBUG_PRINTLN(F("Removing all."));
|
||||
//prevents crashes due to deleting busses while in use.
|
||||
while (!canAllShow()) yield();
|
||||
for (uint8_t i = 0; i < numBusses; i++) delete busses[i];
|
||||
@ -573,16 +585,6 @@ class BusManager {
|
||||
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:
|
||||
uint8_t numBusses = 0;
|
||||
Bus* busses[WLED_MAX_BUSSES];
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "wled.h"
|
||||
#include "wled_ethernet.h"
|
||||
|
||||
/*
|
||||
* 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")]);
|
||||
|
||||
JsonArray ins = hw_led["ins"];
|
||||
|
||||
uint16_t lC = 0;
|
||||
|
||||
if (fromFS || !ins.isNull()) {
|
||||
uint8_t s = 0; //bus iterator
|
||||
strip.isRgbw = false;
|
||||
strip.isOffRefreshRequred = false;
|
||||
uint8_t s = 0; // bus iterator
|
||||
busses.removeAll();
|
||||
uint32_t mem = 0;
|
||||
for (JsonObject elm : ins) {
|
||||
@ -107,22 +109,21 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
uint8_t colorOrder = (int)elm[F("order")];
|
||||
uint8_t skipFirst = elm[F("skip")];
|
||||
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;
|
||||
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);
|
||||
if (bc.adjustBounds(ledCount)) {
|
||||
//RGBW mode is enabled if at least one of the strips is RGBW
|
||||
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);
|
||||
}
|
||||
mem += BusManager::memUsage(bc);
|
||||
if (mem <= MAX_LED_MEMORY && busses.getNumBusses() <= WLED_MAX_BUSSES) busses.add(bc); // finalization will be done in WLED::beginStrip()
|
||||
}
|
||||
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
|
||||
|
||||
// read multiple button configuration
|
||||
@ -501,6 +502,25 @@ void serializeConfig() {
|
||||
#ifdef WLED_USE_ETHERNET
|
||||
JsonObject ethernet = doc.createNestedObject("eth");
|
||||
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
|
||||
|
||||
JsonObject hw = doc.createNestedObject("hw");
|
||||
@ -526,7 +546,9 @@ void serializeConfig() {
|
||||
ins[F("order")] = bus->getColorOrder();
|
||||
ins["rev"] = bus->reversed;
|
||||
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)
|
||||
@ -551,7 +573,7 @@ void serializeConfig() {
|
||||
|
||||
JsonObject hw_ir = hw.createNestedObject("ir");
|
||||
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"));
|
||||
hw_relay["pin"] = rlyPin;
|
||||
|
@ -240,10 +240,10 @@
|
||||
|
||||
#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
|
||||
#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
|
||||
#define MAX_LEDS 8192
|
||||
#endif
|
||||
|
@ -1296,9 +1296,9 @@ var plJson = {"0":{
|
||||
"end": 0
|
||||
}};
|
||||
|
||||
//var plSelContent = "";
|
||||
function makePlSel(incPl=false) {
|
||||
var plSelContent = "";
|
||||
delete pJson["0"]; // remove filler preset
|
||||
var arr = Object.entries(pJson);
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
var n = arr[i][1].n ? arr[i][1].n : "Preset " + arr[i][0];
|
||||
|
@ -160,13 +160,16 @@
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
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
|
||||
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+"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("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
|
||||
}
|
||||
@ -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="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()"/>
|
||||
<br>
|
||||
<div id="dig${i}r" style="display:inline"><span id="rev${i}">Reversed</span>: <input type="checkbox" name="CV${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}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}"> </div>
|
||||
</div>`;
|
||||
f.insertAdjacentHTML("beforeend", cn);
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
1546
wled00/html_ui.h
1546
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@ -90,7 +90,6 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
}
|
||||
}
|
||||
|
||||
strip.isRgbw = false;
|
||||
uint8_t colorOrder, type, skip;
|
||||
uint16_t length, start;
|
||||
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 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
|
||||
if (!request->hasArg(lp)) {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
||||
colorOrder = request->arg(co).toInt();
|
||||
start = (request->hasArg(ls)) ? request->arg(ls).toInt() : t;
|
||||
if (request->hasArg(lc) && request->arg(lc).toInt() > 0) {
|
||||
length = request->arg(lc).toInt();
|
||||
t += length = request->arg(lc).toInt();
|
||||
} else {
|
||||
break; // no parameter
|
||||
}
|
||||
|
||||
colorOrder = request->arg(co).toInt();
|
||||
start = (request->hasArg(ls)) ? request->arg(ls).toInt() : 0;
|
||||
|
||||
// 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);
|
||||
if (!doInitBusses) ledCount = 1;
|
||||
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
|
||||
@ -181,7 +178,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
|
||||
fadeTransition = request->hasArg(F("TF"));
|
||||
t = request->arg(F("TD")).toInt();
|
||||
if (t > 0) transitionDelay = t;
|
||||
if (t >= 0) transitionDelay = t;
|
||||
transitionDelayDefault = t;
|
||||
strip.paletteFade = request->hasArg(F("PF"));
|
||||
|
||||
@ -506,9 +503,6 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
DEBUG_PRINTLN(value);
|
||||
}
|
||||
}
|
||||
#ifdef WLED_DEBUG
|
||||
serializeJson(um,Serial); DEBUG_PRINTLN();
|
||||
#endif
|
||||
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);
|
||||
if (out == 0)
|
||||
{
|
||||
if (req->charAt(pos+4) == '-')
|
||||
{
|
||||
*val = (*val <= minv)? maxv : *val -1;
|
||||
if (req->charAt(pos+4) == '-') {
|
||||
*val = min((int)maxv, max((int)minv, (int)(*val -1)));
|
||||
} else {
|
||||
*val = (*val >= maxv)? minv : *val +1;
|
||||
*val = min((int)maxv, max((int)minv, (int)(*val +1)));
|
||||
}
|
||||
} else {
|
||||
out += *val;
|
||||
@ -581,7 +574,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
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
|
||||
if (pos > 0) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
mainseg.setOption(SEG_OPTION_SELECTED, t);
|
||||
selseg.setOption(SEG_OPTION_SELECTED, t);
|
||||
}
|
||||
|
||||
uint16_t startI = mainseg.start;
|
||||
uint16_t stopI = mainseg.stop;
|
||||
uint8_t grpI = mainseg.grouping;
|
||||
uint16_t spcI = mainseg.spacing;
|
||||
uint16_t startI = selseg.start;
|
||||
uint16_t stopI = selseg.stop;
|
||||
uint8_t grpI = selseg.grouping;
|
||||
uint16_t spcI = selseg.spacing;
|
||||
pos = req.indexOf(F("&S=")); //segment start
|
||||
if (pos > 0) {
|
||||
startI = getNumVal(&req, pos);
|
||||
@ -617,9 +610,36 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
}
|
||||
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
|
||||
if (pos > 0) savePreset(getNumVal(&req, pos));
|
||||
|
||||
byte presetCycleMin = 1;
|
||||
byte presetCycleMax = 5;
|
||||
|
||||
pos = req.indexOf(F("P1=")); //sets first preset for cycle
|
||||
if (pos > 0) presetCycleMin = getNumVal(&req, pos);
|
||||
|
||||
@ -707,7 +727,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
strip.applyToAllSelected = true;
|
||||
strip.setColor(2, t[0], t[1], t[2], t[3]);
|
||||
} 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="));
|
||||
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)
|
||||
pos = req.indexOf(F("ST="));
|
||||
if (pos > 0) {
|
||||
|
@ -209,25 +209,23 @@ void WLED::loop()
|
||||
if (doInitBusses) {
|
||||
doInitBusses = false;
|
||||
DEBUG_PRINTLN(F("Re-init busses."));
|
||||
bool aligned = strip.checkSegmentAlignment(); //see if old segments match old bus(ses)
|
||||
busses.removeAll();
|
||||
uint32_t mem = 0;
|
||||
strip.isRgbw = false;
|
||||
ledCount = 1;
|
||||
for (uint8_t i = 0; i < WLED_MAX_BUSSES; i++) {
|
||||
if (busConfigs[i] == nullptr) break;
|
||||
|
||||
if (busConfigs[i]->adjustBounds(ledCount)) {
|
||||
mem += busses.memUsage(*busConfigs[i]);
|
||||
if (mem <= MAX_LED_MEMORY) {
|
||||
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);
|
||||
}
|
||||
mem += BusManager::memUsage(*busConfigs[i]);
|
||||
if (mem <= MAX_LED_MEMORY) {
|
||||
uint16_t totalNew = busConfigs[i]->start + busConfigs[i]->count;
|
||||
if (totalNew > ledCount && totalNew <= MAX_LEDS) ledCount = totalNew; //total is end of last bus (where start + len is max.)
|
||||
busses.add(*busConfigs[i]);
|
||||
}
|
||||
delete busConfigs[i]; busConfigs[i] = nullptr;
|
||||
}
|
||||
strip.finalizeInit(ledCount);
|
||||
strip.finalizeInit();
|
||||
if (aligned) strip.makeAutoSegments();
|
||||
else strip.fixInvalidSegments();
|
||||
yield();
|
||||
serializeConfig();
|
||||
}
|
||||
@ -407,11 +405,8 @@ void WLED::setup()
|
||||
void WLED::beginStrip()
|
||||
{
|
||||
// Initialize NeoPixel Strip and button
|
||||
|
||||
if (ledCount > MAX_LEDS || ledCount == 0)
|
||||
ledCount = 30;
|
||||
|
||||
strip.finalizeInit(ledCount);
|
||||
strip.finalizeInit(); // busses created during deserializeConfig()
|
||||
strip.makeAutoSegments();
|
||||
strip.setBrightness(0);
|
||||
strip.setShowCallback(handleOverlayDraw);
|
||||
|
||||
@ -784,4 +779,4 @@ void WLED::handleStatusLED()
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
@ -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 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 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 int16_t currentPlaylist _INIT(-1);
|
||||
//still used for "PL=~" HTTP API command
|
||||
WLED_GLOBAL byte presetCycleMin _INIT(1), presetCycleMax _INIT(5);
|
||||
WLED_GLOBAL byte presetCycCurr _INIT(presetCycleMin);
|
||||
WLED_GLOBAL byte presetCycCurr _INIT(0);
|
||||
|
||||
// realtime
|
||||
WLED_GLOBAL byte realtimeMode _INIT(REALTIME_MODE_INACTIVE);
|
||||
|
@ -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 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
|
||||
oappend(SET_F("addLEDs(1);"));
|
||||
uint8_t pins[5];
|
||||
uint8_t nPins = bus->getPins(pins);
|
||||
@ -393,6 +394,7 @@ void getSettingsJS(byte subPage, char* dest)
|
||||
sappend('v',ls,bus->getStart());
|
||||
sappend('c',cv,bus->reversed);
|
||||
sappend('c',sl,bus->skippedLeds());
|
||||
sappend('c',rf,bus->isOffRefreshRequired());
|
||||
}
|
||||
sappend('v',SET_F("MA"),strip.ablMilliampsMax);
|
||||
sappend('v',SET_F("LA"),strip.milliampsPerLed);
|
||||
|
Loading…
Reference in New Issue
Block a user