From 55e2bc27c684afda1017890a2bc736c95b225cc1 Mon Sep 17 00:00:00 2001 From: Warren Spits Date: Thu, 5 Dec 2019 17:59:05 +1100 Subject: [PATCH] Converted segments to use lengths.Segment stop is now derived.Clears the skipped pixels.Fixed getPixelColor. --- wled00/FX.h | 27 ++++++----- wled00/FX_fcn.cpp | 101 ++++++++++++++++++++------------------- wled00/wled00.ino | 2 +- wled00/wled01_eeprom.ino | 4 +- wled00/wled02_xml.ino | 2 +- wled00/wled03_set.ino | 6 +-- wled00/wled05_init.ino | 6 +-- wled00/wled19_json.ino | 4 +- 8 files changed, 81 insertions(+), 71 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 6eb7fdeb..f5f12230 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -44,7 +44,7 @@ #define WLED_FPS 42 #define FRAMETIME 1000/WLED_FPS -/* each segment uses 37 bytes of SRAM memory, so if you're application fails because of +/* each segment uses 41 bytes of SRAM memory, so if you're application fails because of insufficient memory, decreasing MAX_NUM_SEGMENTS may help */ #define MAX_NUM_SEGMENTS 10 @@ -180,14 +180,14 @@ class WS2812FX { // segment parameters public: - typedef struct Segment { // 24 bytes + typedef struct Segment { // 25 bytes uint16_t start; uint16_t stop; //segment invalid if stop == 0 + uint16_t rawLength; uint8_t speed; uint8_t intensity; uint8_t palette; uint8_t mode; - uint8_t grouping; uint8_t options; //bit pattern: msb first: transitional tbd tbd tbd tbd paused reverse selected uint8_t group, spacing; uint8_t opacity; @@ -217,6 +217,9 @@ class WS2812FX { { return stop - start; } + uint16_t ledGroup() { + return group + spacing; + } } segment; // segment runtime parameters @@ -332,7 +335,7 @@ class WS2812FX { } void - init(bool supportWhite, uint16_t countPixels, uint8_t grouping, uint8_t disableNLeds, bool skipFirst), + init(bool supportWhite, uint16_t countPixels, uint8_t group, uint8_t spacing, bool skipFirst), service(void), blur(uint8_t), fade_out(uint8_t r), @@ -352,7 +355,7 @@ class WS2812FX { unlockAll(void), setTransitionMode(bool t), trigger(void), - setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping), + setSegment(uint8_t n, uint16_t start, uint16_t length, uint8_t group, uint8_t spacing), resetSegments(), setPixelColor(uint16_t n, uint32_t c), setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0), @@ -372,8 +375,8 @@ class WS2812FX { paletteBlend = 0, colorOrder = 0, milliampsPerLed = 55, - _disableNLeds = 0, - _grouping = 1, + _spacing = 0, + _group = 1, getBrightness(void), getMode(void), getSpeed(void), @@ -510,7 +513,7 @@ class WS2812FX { CRGBPalette16 targetPalette; uint32_t now; - uint16_t _length, _lengthRaw; + uint16_t _length; uint16_t _rand16seed; uint8_t _brightness; @@ -554,11 +557,13 @@ class WS2812FX { uint8_t _segment_index = 0; uint8_t _segment_index_palette_last = 99; - segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 24 bytes per element - // start, stop, speed, intensity, palette, mode, options, 3 unused bytes (group, spacing, opacity), color[] - { 0, 7, DEFAULT_SPEED, 128, 0, DEFAULT_MODE, NO_OPTIONS, 1, 0, 255, {DEFAULT_COLOR}} + segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 25 bytes per element + // start, stop, length, speed, intensity, palette, mode, options, group, spacing, opacity (unused), color[] + { 0, 7, 7, DEFAULT_SPEED, 128, 0, DEFAULT_MODE, NO_OPTIONS, 1, 0, 255, {DEFAULT_COLOR}} }; segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 16 bytes per element + + uint16_t realPixelIndex(uint16_t i); }; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 02cc7bd8..158a766c 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -30,38 +30,36 @@ #define LED_SKIP_AMOUNT 1 #define MIN_SHOW_DELAY 15 -void WS2812FX::init(bool supportWhite, uint16_t countPixels, uint8_t grouping, uint8_t disableNLeds, bool skipFirst) +void WS2812FX::init(bool supportWhite, uint16_t countPixels, uint8_t group, uint8_t spacing, bool skipFirst) { - if (supportWhite == _rgbwMode && countPixels == _length && _locked != NULL && grouping == _grouping && disableNLeds == _disableNLeds) return; + if (supportWhite == _rgbwMode && countPixels == _length && _locked != NULL && group == _group && spacing == _spacing) return; RESET_RUNTIME; _rgbwMode = supportWhite; _skipFirstMode = skipFirst; _length = countPixels; - _grouping = grouping; - _disableNLeds = disableNLeds; + _group = group; + _spacing = spacing; uint8_t ty = 1; if (supportWhite) ty =2; - _lengthRaw = _length; - if (_skipFirstMode) { - _lengthRaw += LED_SKIP_AMOUNT; - } + uint16_t lengthRaw = _length + (_skipFirstMode ? LED_SKIP_AMOUNT : 0); - bus->Begin((NeoPixelType)ty, _lengthRaw); + bus->Begin((NeoPixelType)ty, lengthRaw); delete[] _locked; _locked = new byte[_length]; _segments[0].start = 0; _segments[0].stop = getUsableCount(); + _segments[0].rawLength = _length; unlockAll(); setBrightness(_brightness); } uint16_t WS2812FX::getUsableCount() { - uint16_t totalGroup = _grouping + _disableNLeds; - return (_length + totalGroup -1) / totalGroup; + uint16_t ledGroup = _group + _spacing; + return (_length + ledGroup -1) / ledGroup; } void WS2812FX::service() { @@ -107,6 +105,21 @@ void WS2812FX::setPixelColor(uint16_t n, uint32_t c) { setPixelColor(n, r, g, b, w); } +uint16_t WS2812FX::realPixelIndex(uint16_t i) { + int16_t iGroup = (i - SEGMENT.start) * SEGMENT.ledGroup(); + + /* reverse just an individual segment */ + int16_t realIndex; + if IS_REVERSE + realIndex = SEGMENT.stop - iGroup -1; + else + realIndex = SEGMENT.start + iGroup; + /* Reverse the whole string */ + if (reverseMode) realIndex = _length - 1 - realIndex; + + return realIndex; +} + void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) { if (_locked[i] && !_modeUsesLock) return; @@ -122,27 +135,16 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) } if (!_cronixieMode) { - uint16_t totalGroup = SEGMENT.grouping + _disableNLeds; - uint16_t iMax = (SEGMENT.stop - SEGMENT.start) * totalGroup; - int16_t iGroup = (i - SEGMENT.start) * totalGroup; - - /* reverse just an individual segment */ - int16_t realIndex; - if IS_REVERSE - realIndex = SEGMENT.stop - iGroup -1; - else - realIndex = SEGMENT.start + iGroup; - /* Reverse the whole string */ - if (reverseMode) realIndex = _length - 1 - realIndex; - /* Set all the pixels in the group, ensuring _skipFirstMode is honored */ - { - bool reversed = reverseMode ^ IS_REVERSE; - uint16_t skip = _skipFirstMode ? LED_SKIP_AMOUNT : 0; - for (uint8_t l = 0; l < totalGroup; l++) { - int16_t indexSet = realIndex + (reversed ? -l : l); - if (indexSet >= SEGMENT.start && (indexSet < SEGMENT.start + iMax)) - bus->SetPixelColor(indexSet + skip, l < SEGMENT.grouping ? color : RgbwColor(0, 0, 0, 0)); + bool reversed = reverseMode ^ IS_REVERSE; + uint16_t realIndex = realPixelIndex(i); + uint16_t skip = _skipFirstMode ? LED_SKIP_AMOUNT : 0; + for (uint16_t l = 0; l < SEGMENT.ledGroup(); l++) { + int16_t indexSet = realIndex + (reversed ? -l : l); + if (indexSet >= SEGMENT.start && (indexSet < SEGMENT.start + SEGMENT.rawLength)) + bus->SetPixelColor(indexSet + skip, l < SEGMENT.group ? color : RgbwColor(0, 0, 0, 0)); + for (uint16_t l = 0; indexSet == 0 && l < skip; l++) {// Clear the skipped pixels + bus->SetPixelColor(l, RgbwColor(0, 0, 0, 0)); } } } else { @@ -399,10 +401,7 @@ uint32_t WS2812FX::getColor(void) { uint32_t WS2812FX::getPixelColor(uint16_t i) { - i = i * (_disableNLeds+1); - if (reverseMode) i = _length- 1 -i; - if (IS_REVERSE) i = SEGMENT.stop -1 -i + SEGMENT.start; //reverse just individual segment - if (_skipFirstMode) i += LED_SKIP_AMOUNT; + i = realPixelIndex(i) + (_skipFirstMode ? LED_SKIP_AMOUNT : 0); if (_cronixieMode) { if(i>6)return 0; @@ -422,7 +421,8 @@ uint32_t WS2812FX::getPixelColor(uint16_t i) default: return 0; } } - if (i >= _lengthRaw) return 0; + uint16_t skip = _skipFirstMode ? LED_SKIP_AMOUNT : 0; + if (i >= (_length + skip)) return 0; RgbwColor lColor = bus->GetPixelColorRgbw(i); byte r = lColor.R, g = lColor.G, b = lColor.B; switch (colorOrder) @@ -452,10 +452,10 @@ uint32_t WS2812FX::getLastShow(void) { return _lastShow; } -void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping) { +void WS2812FX::setSegment(uint8_t n, uint16_t start, uint16_t length, uint8_t group, uint8_t spacing) { if (n >= MAX_NUM_SEGMENTS) return; Segment& seg = _segments[n]; - if (seg.start == i1 && seg.stop == i2 && seg.grouping == grouping) return; + if (seg.start == start && seg.rawLength == length && seg.group == group && seg.spacing == spacing) return; if (seg.isActive() && modeUsesLock(seg.mode)) { _modeUsesLock = false; @@ -463,16 +463,19 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping) _modeUsesLock = true; } _segment_index = n; fill(0); //turn old segment range off - if (i2 <= i1) //disable segment - { - seg.stop = 0; return; + + seg.rawLength = min(_length - start, length); + seg.spacing = spacing; + seg.group = group; + seg.start = start; + uint16_t ledGroup = seg.ledGroup(); + seg.stop = (seg.rawLength - seg.start + ledGroup -1) / ledGroup + seg.start; + if (seg.start >= seg.stop) { + seg.stop = 0; + } + else { + _segment_runtimes[n].reset(); } - if (grouping > 0) seg.grouping = grouping; - if (i1 < _length) seg.start = i1; - uint16_t maxStop = (_length - seg.start) / seg.grouping; - seg.stop = i2; - if (i2 > maxStop) seg.stop = maxStop; - _segment_runtimes[n].reset(); } void WS2812FX::resetSegments() { @@ -484,8 +487,10 @@ void WS2812FX::resetSegments() { _segments[0].start = 0; _segments[0].speed = DEFAULT_SPEED; _segments[0].stop = getUsableCount(); + _segments[0].rawLength = _length; _segments[0].setOption(0, 1); //select - _segments[0].grouping = _grouping; + _segments[0].group = _group; + _segments[0].spacing = _spacing; } void WS2812FX::setIndividual(uint16_t i, uint32_t col) diff --git a/wled00/wled00.ino b/wled00/wled00.ino index f3ce4833..7052ee94 100644 --- a/wled00/wled00.ino +++ b/wled00/wled00.ino @@ -149,7 +149,7 @@ uint16_t transitionDelay = 750; //default crossfade duration in ms //bool strip.reverseMode = false; //flip entire LED strip (reverses all effect directions) --> edit in WS2812FX.h bool skipFirstLed = false; //ignore first LED in strip (useful if you need the LED as signal repeater) -uint8_t disableNLeds = 0; //disables N LEDs between active nodes. (Useful for spacing out lights for more traditional christmas light look) +uint8_t spacing = 0; //disables N LEDs between active nodes. (Useful for spacing out lights for more traditional christmas light look) byte briMultiplier = 100; //% of brightness to set (to limit power, if you set it to 50 and set bri to 255, actual brightness will be 127) diff --git a/wled00/wled01_eeprom.ino b/wled00/wled01_eeprom.ino index 879b345e..38ea7c41 100644 --- a/wled00/wled01_eeprom.ino +++ b/wled00/wled01_eeprom.ino @@ -229,7 +229,7 @@ void saveSettingsToEEPROM() saveCurrPresetCycConf = false; } - EEPROM.write(2213, disableNLeds); + EEPROM.write(2213, spacing); writeStringToEEPROM(2220, blynkApiKey, 35); @@ -480,7 +480,7 @@ void loadSettingsFromEEPROM(bool first) presetApplyFx = EEPROM.read(2212); } - disableNLeds = EEPROM.read(2213); + spacing = EEPROM.read(2213); bootPreset = EEPROM.read(389); wifiLock = EEPROM.read(393); diff --git a/wled00/wled02_xml.ino b/wled00/wled02_xml.ino index 094b0358..8303f7fd 100644 --- a/wled00/wled02_xml.ino +++ b/wled00/wled02_xml.ino @@ -237,7 +237,7 @@ void getSettingsJS(byte subPage, char* dest) sappend('i',"PB",strip.paletteBlend); sappend('c',"RV",strip.reverseMode); sappend('c',"SL",skipFirstLed); - sappend('v',"DL",disableNLeds); + sappend('v',"DL",spacing); } if (subPage == 3) diff --git a/wled00/wled03_set.ino b/wled00/wled03_set.ino index debb3d09..21332ddd 100644 --- a/wled00/wled03_set.ino +++ b/wled00/wled03_set.ino @@ -93,7 +93,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) if (t >= 0 && t < 4) strip.paletteBlend = t; strip.reverseMode = request->hasArg("RV"); skipFirstLed = request->hasArg("SL"); - disableNLeds = request->arg("DL").toInt(); + spacing = request->arg("DL").toInt(); t = request->arg("BF").toInt(); if (t > 0) briMultiplier = t; } @@ -274,7 +274,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) } if (subPage != 6 || !doReboot) saveSettingsToEEPROM(); //do not save if factory reset if (subPage == 2) { - strip.init(useRGBW,ledCount,1,disableNLeds,skipFirstLed); + strip.init(useRGBW,ledCount,1,spacing,skipFirstLed); } if (subPage == 4) alexaInit(); } @@ -375,7 +375,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req) if (pos > 0) { stopI = getNumVal(&req, pos); } - strip.setSegment(main, startI, stopI, 1); + strip.setSegment(main, startI, stopI, 1, 0); main = strip.getMainSegmentId(); diff --git a/wled00/wled05_init.ino b/wled00/wled05_init.ino index 2288646c..3559d7b6 100644 --- a/wled00/wled05_init.ino +++ b/wled00/wled05_init.ino @@ -8,9 +8,9 @@ void wledInit() ledCount = EEPROM.read(229) + ((EEPROM.read(398) << 8) & 0xFF00); if (ledCount > MAX_LEDS || ledCount == 0) ledCount = 30; - disableNLeds = EEPROM.read(2213); + spacing = EEPROM.read(2213); //this was reading 255 after inital flash causing bootloop. Don't know why. - disableNLeds = disableNLeds != 255 ? disableNLeds : 0; + spacing = spacing!= 255 ? spacing : 0; #ifdef ESP8266 #if LEDPIN == 3 @@ -30,7 +30,7 @@ void wledInit() DEBUG_PRINT("heap "); DEBUG_PRINTLN(ESP.getFreeHeap()); - strip.init(EEPROM.read(372),ledCount,1,disableNLeds,EEPROM.read(2204)); //init LEDs quickly + strip.init(EEPROM.read(372),ledCount,1,spacing,EEPROM.read(2204)); //init LEDs quickly strip.setBrightness(0); DEBUG_PRINT("LEDs inited. heap usage ~"); diff --git a/wled00/wled19_json.ino b/wled00/wled19_json.ino index c187afff..0d1b7d4b 100644 --- a/wled00/wled19_json.ino +++ b/wled00/wled19_json.ino @@ -15,7 +15,7 @@ void deserializeSegment(JsonObject elem, byte it) uint16_t len = elem["len"]; stop = (len > 0) ? start + len : seg.stop; } - strip.setSegment(id, start, stop, 1); + strip.setSegment(id, start, stop, 1, 0); JsonArray colarr = elem["col"]; if (!colarr.isNull()) @@ -177,7 +177,7 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id) root["ix"] = seg.intensity; root["pal"] = seg.palette; root["sel"] = seg.isSelected(); - root["grp"] = seg.grouping; + root["grp"] = seg.group; root["rev"] = seg.getOption(1); }