diff --git a/CHANGELOG.md b/CHANGELOG.md index 19bf7186..baa1e307 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ ### Builds after release 0.12.0 +#### Build 2109220 + +- Version bump to 0.13.0-b3 "Toki" +- Added segment names (PR #2184) +- Improved Police and other effects (PR #2184) +- Reverted PR #1902 (Live color correction - will be implemented as usermod) (PR #2175) +- Added transitions for segment on/off +- Improved number of sparks/stars in Fireworks effect with low number of segments +- Fixed segment name edit pencil disappearing with request +- Fixed color transition active even if the segment is off +- Disallowed file upload with OTA lock active +- Fixed analog invert option missing (PR #2219) + #### Build 2109100 - Added an auto create segments per bus setting diff --git a/package-lock.json b/package-lock.json index 617b3aa5..480775e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "wled", - "version": "0.13.0-bl2", + "version": "0.13.0-bl3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 99b6b0cd..677f1160 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2629,7 +2629,7 @@ typedef struct Spark { */ uint16_t WS2812FX::mode_popcorn(void) { //allocate segment data - uint16_t maxNumPopcorn = 22; // max 22 on 16 segment ESP8266 + uint16_t maxNumPopcorn = 21; // max 21 on 16 segment ESP8266 uint16_t dataSize = sizeof(spark) * maxNumPopcorn; if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed @@ -2688,7 +2688,7 @@ uint16_t WS2812FX::candle(bool multi) if (multi) { //allocate segment data - uint16_t dataSize = (SEGLEN -1) *3; // max length of segment on 16 segment ESP8266 is 75 pixels + uint16_t dataSize = (SEGLEN -1) *3; //max. 1365 pixels (ESP8266) if (!SEGENV.allocateData(dataSize)) return candle(false); //allocation failed } @@ -2776,13 +2776,11 @@ uint16_t WS2812FX::mode_candle_multi() / Speed sets frequency of new starbursts, intensity is the intensity of the burst */ #ifdef ESP8266 - #define STARBURST_MAX_FRAG 4 - #define STARBURST_MAX_STARS 6 + #define STARBURST_MAX_FRAG 8 //52 bytes / star #else - #define STARBURST_MAX_FRAG 10 - #define STARBURST_MAX_STARS 11 + #define STARBURST_MAX_FRAG 10 //60 bytes / star #endif -//each needs 18+STARBURST_MAX_FRAG*4 bytes +//each needs 20+STARBURST_MAX_FRAG*4 bytes typedef struct particle { CRGB color; uint32_t birth =0; @@ -2793,7 +2791,14 @@ typedef struct particle { } star; uint16_t WS2812FX::mode_starburst(void) { - uint8_t numStars = min(1 + (SEGLEN >> 3), STARBURST_MAX_STARS); // 11 * 58 * 32 = 19k (ESP32), 6 * 34 * 16 = 3.2k (ESP8266) + uint16_t maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640 + uint8_t segs = getActiveSegmentsNum(); + if (segs <= (MAX_NUM_SEGMENTS /2)) maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs + if (segs <= (MAX_NUM_SEGMENTS /4)) maxData *= 2; //ESP8266: 1024 if <= 4 segs ESP32: 2560 if <= 8 segs + uint16_t maxStars = maxData / sizeof(star); //ESP8266: max. 4/9/19 stars/seg, ESP32: max. 10/21/42 stars/seg + + uint8_t numStars = 1 + (SEGLEN >> 3); + if (numStars > maxStars) numStars = maxStars; uint16_t dataSize = sizeof(star) * numStars; if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed @@ -2895,24 +2900,29 @@ uint16_t WS2812FX::mode_starburst(void) { return FRAMETIME; } #undef STARBURST_MAX_FRAG -#undef STARBURST_MAX_STARS /* * Exploding fireworks effect * adapted from: http://www.anirama.com/1000leds/1d-fireworks/ */ -#ifdef ESP8266 - #define MAX_SPARKS 20 // number of fragments (11 bytes per fragment) -#else - #define MAX_SPARKS 58 // number of fragments -#endif uint16_t WS2812FX::mode_exploding_fireworks(void) { //allocate segment data - uint16_t numSparks = min(2 + (SEGLEN >> 1), MAX_SPARKS); // max 58 for 32 segment ESP32, 20 for 16 segment ESP8266 + uint16_t maxData = FAIR_DATA_PER_SEG; //ESP8266: 256 ESP32: 640 + uint8_t segs = getActiveSegmentsNum(); + if (segs <= (MAX_NUM_SEGMENTS /2)) maxData *= 2; //ESP8266: 512 if <= 8 segs ESP32: 1280 if <= 16 segs + if (segs <= (MAX_NUM_SEGMENTS /4)) maxData *= 2; //ESP8266: 1024 if <= 4 segs ESP32: 2560 if <= 8 segs + int maxSparks = maxData / sizeof(spark); //ESP8266: max. 21/42/85 sparks/seg, ESP32: max. 53/106/213 sparks/seg + + uint16_t numSparks = min(2 + (SEGLEN >> 1), maxSparks); uint16_t dataSize = sizeof(spark) * numSparks; if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed + if (dataSize != SEGENV.aux1) { //reset to flare if sparks were reallocated + SEGENV.aux0 = 0; + SEGENV.aux1 = dataSize; + } + fill(BLACK); bool actuallyReverse = SEGMENT.getOption(SEG_OPTION_REVERSED); diff --git a/wled00/FX.h b/wled00/FX.h index baf3ec5c..210c397e 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -57,7 +57,7 @@ /* How many color transitions can run at once */ #define MAX_NUM_TRANSITIONS 8 /* How much data bytes all segments combined may allocate */ - #define MAX_SEGMENT_DATA 3584 + #define MAX_SEGMENT_DATA 4096 #else #ifndef MAX_NUM_SEGMENTS #define MAX_NUM_SEGMENTS 32 @@ -66,6 +66,10 @@ #define MAX_SEGMENT_DATA 20480 #endif +/* How much data bytes each segment should max allocate to leave enough space for other segments, + assuming each segment uses the same amount of data. 256 for ESP8266, 640 for ESP32. */ +#define FAIR_DATA_PER_SEG (MAX_SEGMENT_DATA / MAX_NUM_SEGMENTS) + #define LED_SKIP_AMOUNT 1 #define MIN_SHOW_DELAY 15 @@ -243,7 +247,7 @@ class WS2812FX { // segment parameters public: - typedef struct Segment { // 25 (28 in memory?) bytes + typedef struct Segment { // 29 (32 in memory?) bytes uint16_t start; uint16_t stop; //segment invalid if stop == 0 uint16_t offset; @@ -274,22 +278,24 @@ class WS2812FX { }*/ void setOption(uint8_t n, bool val, uint8_t segn = 255) { - //bool prevOn = false; - //if (n == SEG_OPTION_ON) prevOn = getOption(SEG_OPTION_ON); + bool prevOn = false; + if (n == SEG_OPTION_ON) { + prevOn = getOption(SEG_OPTION_ON); + if (!val && prevOn) { //fade off + ColorTransition::startTransition(opacity, colors[0], instance->_transitionDur, segn, 0); + } + } + if (val) { options |= 0x01 << n; } else { options &= ~(0x01 << n); } - //transitions on segment on/off don't work correctly at this point - /*if (n == SEG_OPTION_ON && segn < MAX_NUM_SEGMENTS && getOption(SEG_OPTION_ON) != prevOn) { - if (getOption(SEG_OPTION_ON)) { - ColorTransition::startTransition(0, colors[0], instance->_transitionDur, segn, 0); - } else { - ColorTransition::startTransition(opacity, colors[0], instance->_transitionDur, segn, 0); - } - }*/ + + if (n == SEG_OPTION_ON && val && !prevOn) { //fade on + ColorTransition::startTransition(0, colors[0], instance->_transitionDur, segn, 0); + } } bool getOption(uint8_t n) { @@ -409,6 +415,7 @@ class WS2812FX { static void startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot) { if (segn >= MAX_NUM_SEGMENTS || slot >= NUM_COLORS || dur == 0) return; if (instance->_brightness == 0) return; //do not need transitions if master bri is off + if (!instance->_segments[segn].getOption(SEG_OPTION_ON)) return; //not if segment is off either uint8_t tIndex = 0xFF; //none found uint16_t tProgression = 0; uint8_t s = segn + (slot << 6); //merge slot and segment into one byte @@ -437,7 +444,8 @@ class WS2812FX { ColorTransition& t = instance->transitions[tIndex]; if (t.segment == s) //this is an active transition on the same segment+color { - t.briOld = t.currentBri(); + bool wasTurningOff = (oldBri == 0); + t.briOld = t.currentBri(wasTurningOff); t.colorOld = t.currentColor(oldCol); } else { t.briOld = oldBri; @@ -469,10 +477,11 @@ class WS2812FX { uint32_t currentColor(uint32_t colorNew) { return instance->color_blend(colorOld, colorNew, progress(true), true); } - uint8_t currentBri() { + uint8_t currentBri(bool turningOff = false) { uint8_t segn = segment & 0x3F; if (segn >= MAX_NUM_SEGMENTS) return 0; uint8_t briNew = instance->_segments[segn].opacity; + if (!instance->_segments[segn].getOption(SEG_OPTION_ON) || turningOff) briNew = 0; uint32_t prog = progress() + 1; return ((briNew * prog) + (briOld * (0x10000 - prog))) >> 16; } @@ -656,6 +665,7 @@ class WS2812FX { getModeCount(void), getPaletteCount(void), getMaxSegments(void), + getActiveSegmentsNum(void), //getFirstSelectedSegment(void), getMainSegmentId(void), gamma8(uint8_t), diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index f240eea5..cff70027 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -510,6 +510,15 @@ uint8_t WS2812FX::getMainSegmentId(void) { return 0; } +uint8_t WS2812FX::getActiveSegmentsNum(void) { + uint8_t c = 0; + for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) + { + if (_segments[i].isActive()) c++; + } + return c; +} + uint32_t WS2812FX::getColor(void) { return _segments[getMainSegmentId()].colors[0]; } @@ -548,15 +557,6 @@ uint32_t WS2812FX::getLastShow(void) { return _lastShow; } -// there is no longer any need for these two -//uint8_t WS2812FX::getColorOrder(void) { -// return COL_ORDER_GRB; -//} -// -//void WS2812FX::setColorOrder(uint8_t co) { -// //bus->SetColorOrder(co); -//} - void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing) { if (n >= MAX_NUM_SEGMENTS) return; Segment& seg = _segments[n]; @@ -1035,9 +1035,10 @@ uint32_t WS2812FX::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8 //load custom mapping table from JSON file void WS2812FX::deserializeMap(uint8_t n) { - String fileName = String(F("/ledmap")); - if (n) fileName += String(n); - fileName += String(F(".json")); + char fileName[32]; + strcpy_P(fileName, PSTR("/ledmap")); + if (n) sprintf(fileName +7, "%d", n); + strcat(fileName, ".json"); bool isFile = WLED_FS.exists(fileName); if (!isFile) { @@ -1054,7 +1055,7 @@ void WS2812FX::deserializeMap(uint8_t n) { DEBUG_PRINT(F("Reading LED map from ")); DEBUG_PRINTLN(fileName); - if (!readObjectFromFile(fileName.c_str(), nullptr, &doc)) return; //if file does not exist just exit + if (!readObjectFromFile(fileName, nullptr, &doc)) return; //if file does not exist just exit // erase old custom ledmap if (customMappingTable != nullptr) { diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index ebdd01bd..73483a33 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -110,7 +110,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { if (length==0 || length+lC > MAX_LEDS) continue; // zero length or we reached max. number of LEDs, just stop uint8_t colorOrder = (int)elm[F("order")]; uint8_t skipFirst = elm[F("skip")]; - uint16_t start = elm[F("start")] | 0; + uint16_t start = elm["start"] | 0; if (start > lC+length) continue; // something is very wrong :) uint8_t ledType = elm["type"] | TYPE_WS2812_RGB; bool reversed = elm["rev"]; @@ -411,7 +411,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { JsonObject dmx = doc["dmx"]; CJSON(DMXChannels, dmx[F("chan")]); CJSON(DMXGap,dmx[F("gap")]); - CJSON(DMXStart, dmx[F("start")]); + CJSON(DMXStart, dmx["start"]); CJSON(DMXStartLED,dmx[F("start-led")]); JsonArray dmx_fixmap = dmx[F("fixmap")]; @@ -549,7 +549,7 @@ void serializeConfig() { Bus *bus = busses.getBus(s); if (!bus || bus->getLength()==0) break; JsonObject ins = hw_led_ins.createNestedObject(); - ins[F("start")] = bus->getStart(); + ins["start"] = bus->getStart(); ins[F("len")] = bus->getLength(); JsonArray ins_pin = ins.createNestedArray("pin"); uint8_t pins[5]; @@ -753,7 +753,7 @@ void serializeConfig() { JsonObject dmx = doc.createNestedObject("dmx"); dmx[F("chan")] = DMXChannels; dmx[F("gap")] = DMXGap; - dmx[F("start")] = DMXStart; + dmx["start"] = DMXStart; dmx[F("start-led")] = DMXStartLED; JsonArray dmx_fixmap = dmx.createNestedArray(F("fixmap")); diff --git a/wled00/data/index.css b/wled00/data/index.css index 5b3ebdb3..150472dc 100644 --- a/wled00/data/index.css +++ b/wled00/data/index.css @@ -1,6 +1,5 @@ @font-face { font-family: "WIcons"; - /*src: url(data:application/x-font-woff;charset=utf-8;base64,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) format('woff');*/ src: url(data:font/woff2;charset=utf-8;base64,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) format('woff'); } diff --git a/wled00/data/index.js b/wled00/data/index.js index 26b47c7e..e7f835c7 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -1568,6 +1568,12 @@ function tglSegn(s) (window.getComputedStyle(d.gId(`seg${s}t`)).display === "none") ? "inline":"none"; } +function tglSegn(s) +{ + d.getElementById(`seg${s}t`).style.display = + (window.getComputedStyle(d.getElementById(`seg${s}t`)).display === "none") ? "inline":"none"; +} + function selSegEx(s) { var obj = {"seg":[]}; diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 110fed77..3ba144c4 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -330,7 +330,7 @@ ${i+1}: } function uploadFile(name) { var req = new XMLHttpRequest(); - req.addEventListener('load', function(){showToast(this.responseText)}); + req.addEventListener('load', function(){showToast(this.responseText,this.status >= 400)}); req.addEventListener('error', function(e){showToast(e.stack,true);}); req.open("POST", "/upload"); var formData = new FormData(); diff --git a/wled00/data/settings_sec.htm b/wled00/data/settings_sec.htm index 0d37ac51..d14a8ba3 100644 --- a/wled00/data/settings_sec.htm +++ b/wled00/data/settings_sec.htm @@ -37,7 +37,7 @@ } function uploadFile(fO,name) { var req = new XMLHttpRequest(); - req.addEventListener('load', function(){showToast(this.responseText)}); + req.addEventListener('load', function(){showToast(this.responseText,this.status >= 400)}); req.addEventListener('error', function(e){showToast(e.stack,true);}); req.open("POST", "/upload"); var formData = new FormData(); diff --git a/wled00/data/settings_ui.htm b/wled00/data/settings_ui.htm index 3ba50a56..eb4ea9a1 100644 --- a/wled00/data/settings_ui.htm +++ b/wled00/data/settings_ui.htm @@ -202,7 +202,7 @@ } function uploadFile(fO,name) { var req = new XMLHttpRequest(); - req.addEventListener('load', function(){showToast(this.responseText)}); + req.addEventListener('load', function(){showToast(this.responseText,this.status >= 400)}); req.addEventListener('error', function(e){showToast(e.stack,true);}); req.open("POST", "/upload"); var formData = new FormData(); diff --git a/wled00/html_settings.h b/wled00/html_settings.h index 1b267892..de50889a 100644 --- a/wled00/html_settings.h +++ b/wled00/html_settings.h @@ -77,7 +77,7 @@ onclick="B()">Back // Autogenerated from wled00/data/settings_leds.htm, do not edit!! const char PAGE_settings_leds[] PROGMEM = R"=====(LED Settings