-
-
-
-
-
-
-
+
)=====";
-
diff --git a/examples/esp8266_webinterface/main.js.cpp b/examples/esp8266_webinterface/main.js.cpp
index d0f99bf..3c7f54c 100644
--- a/examples/esp8266_webinterface/main.js.cpp
+++ b/examples/esp8266_webinterface/main.js.cpp
@@ -1,121 +1,110 @@
#include
+
+/*
+The tiny Javascript/canvas based color picker is based on the clever work of the folks
+at Sparkbox. https://seesparkbox.com/foundry/how_i_built_a_canvas_color_picker
+*/
+
char main_js[] PROGMEM = R"=====(
-window.addEventListener('load', setup);
-window.addEventListener('resize', drawColorbar);
-
-function handle_M_B_S(e) {
- e.preventDefault();
- var name = e.target.className;
- var val = e.target.id;
- if(e.target.className.indexOf('m') > -1) {
- elems = document.querySelectorAll('#mode li a');
- [].forEach.call(elems, function(el) {
- el.classList.remove('active');
- name = e.target.className;
- });
- e.target.classList.add('active');
- }
- submitVal(name, val);
-}
-function submitVal(name, val) {
+var activeButton = null;
+var colorCanvas = null;
+
+window.addEventListener('DOMContentLoaded', (event) => {
+ // init the canvas color picker
+ colorCanvas = document.getElementById('color-canvas');
+ var colorctx = colorCanvas.getContext('2d');
+
+ // Create color gradient
+ var gradient = colorctx.createLinearGradient(0, 0, colorCanvas.width - 1, 0);
+ gradient.addColorStop(0, "rgb(255, 0, 0)");
+ gradient.addColorStop(0.16, "rgb(255, 0, 255)");
+ gradient.addColorStop(0.33, "rgb(0, 0, 255)");
+ gradient.addColorStop(0.49, "rgb(0, 255, 255)");
+ gradient.addColorStop(0.66, "rgb(0, 255, 0)");
+ gradient.addColorStop(0.82, "rgb(255, 255, 0)");
+ gradient.addColorStop(1, "rgb(255, 0, 0)");
+
+ // Apply gradient to canvas
+ colorctx.fillStyle = gradient;
+ colorctx.fillRect(0, 0, colorCanvas.width - 1, colorCanvas.height - 1);
+
+ // Create semi transparent gradient (white -> transparent -> black)
+ gradient = colorctx.createLinearGradient(0, 0, 0, colorCanvas.height - 1);
+ gradient.addColorStop(0, "rgba(255, 255, 255, 1)");
+ gradient.addColorStop(0.48, "rgba(255, 255, 255, 0)");
+ gradient.addColorStop(0.52, "rgba(0, 0, 0, 0)");
+ gradient.addColorStop(1, "rgba(0, 0, 0, 1)");
+
+ // Apply gradient to canvas
+ colorctx.fillStyle = gradient;
+ colorctx.fillRect(0, 0, colorCanvas.width - 1, colorCanvas.height - 1);
+
+ // setup the canvas click listener
+ colorCanvas.addEventListener('click', (event) => {
+ var imageData = colorCanvas.getContext('2d').getImageData(event.offsetX, event.offsetY, 1, 1);
+
+ var selectedColor = 'rgb(' + imageData.data[0] + ',' + imageData.data[1] + ',' + imageData.data[2] + ')';
+ //console.log('click: ' + event.offsetX + ', ' + event.offsetY + ', ' + selectedColor);
+ document.getElementById('color-value').value = selectedColor;
+
+ selectedColor = imageData.data[0] * 65536 + imageData.data[1] * 256 + imageData.data[2];
+ submitVal('c', selectedColor);
+ });
+
+ // get list of modes from ESP
var xhttp = new XMLHttpRequest();
- xhttp.open('GET', 'set?' + name + '=' + val, true);
+ xhttp.onreadystatechange = function() {
+ if (xhttp.readyState == 4 && xhttp.status == 200) {
+ document.getElementById('modes').innerHTML = xhttp.responseText;
+ modes = document.querySelectorAll('ul#modes li a');
+ modes.forEach(initMode);
+ }
+ };
+ xhttp.open('GET', 'modes', true);
xhttp.send();
-}
+});
-function compToHex(c) {
- hex = c.toString(16);
- return hex.length == 1 ? '0' + hex : hex;
+function initMode(mode, index) {
+ mode.addEventListener('click', (event) => onMode(event, index));
}
-function getMousePos(can, evt) {
- r = can.getBoundingClientRect();
- return {
- x: evt.clientX - r.left,
- y: evt.clientY - r.top
- };
+function onColor(event, color) {
+ event.preventDefault();
+ var match = color.match(/rgb\(([0-9]*),([0-9]*),([0-9]*)\)/);
+ if(match) {
+ var colorValue = Number(match[1]) * 65536 + Number(match[2]) * 256 + Number(match[3]);
+ //console.log('onColor:' + match[1] + "," + match[2] + "," + match[3] + "," + colorValue);
+ submitVal('c', colorValue);
+ }
}
-function Touch(e) {
- e.preventDefault();
- pos = {
- x: Math.round(e.targetTouches[0].pageX),
- y: Math.round(e.targetTouches[0].pageY)
- };
- rgb = ctx.getImageData(pos.x, pos.y, 1, 1).data;
- drawColorbar(rgb);
- submitVal('c', compToHex(rgb[0]) + compToHex(rgb[1]) + compToHex(rgb[2]));
+function onMode(event, mode) {
+ event.preventDefault();
+ if(activeButton) activeButton.classList.remove('active')
+ activeButton = event.target;
+ activeButton.classList.add('active');
+ submitVal('m', mode);
}
-function Click(e) {
- pos = getMousePos(can, e);
- rgb = ctx.getImageData(pos.x, pos.y, 1, 1).data;
- drawColorbar(rgb);
- submitVal('c', compToHex(rgb[0]) + compToHex(rgb[1]) + compToHex(rgb[2]));
+function onBrightness(event, dir) {
+ event.preventDefault();
+ submitVal('b', dir);
}
-// Thanks to the backup at http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
-function rgbToHsl(r, g, b){
- r = r / 255;
- g = g / 255;
- b = b / 255;
- var max = Math.max(r, g, b);
- var min = Math.min(r, g, b);
- var h, s, l = (max + min) / 2;
- if(max == min) {
- h = s = 0;
- } else {
- var d = max - min;
- s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
- switch(max) {
- case r: h = (g - b) / d + (g < b ? 6 : 0); break;
- case g: h = (b - r) / d + 2; break;
- case b: h = (r - g) / d + 4; break;
- }
- h = h / 6;
- }
- return [h, s, l];
+function onSpeed(event, dir) {
+ event.preventDefault();
+ submitVal('s', dir);
}
-function drawColorbar(rgb = [0, 0, 0]) {
- can = document.getElementById('colorbar');
- ctx = can.getContext('2d');
- can.width = document.body.clientWidth * 0.25;
- var h = can.height / 360;
-
- var hsl = rgbToHsl(rgb[0], rgb[1], rgb[2]);
-
- for(var i=0; i<=360; i++) {
- ctx.fillStyle = 'hsl('+i+', 100%, 50%)';
- ctx.fillRect(0, i * h, can.width/2, h);
- ctx.fillStyle = 'hsl(' + hsl[0] * 360 + ', 100%, ' + i * (100/360) + '%)';
- ctx.fillRect(can.width/2, i * h, can.width/2, h);
- }
+function onAuto(event, dir) {
+ event.preventDefault();
+ submitVal('a', dir);
}
-function setup(){
+function submitVal(name, val) {
var xhttp = new XMLHttpRequest();
- xhttp.onreadystatechange = function() {
- if (xhttp.readyState == 4 && xhttp.status == 200) {
- document.getElementById('mode').innerHTML = xhttp.responseText;
- elems = document.querySelectorAll('ul li a'); // adds listener also to existing s and b buttons
- [].forEach.call(elems, function(el) {
- el.addEventListener('touchstart', handle_M_B_S, false);
- el.addEventListener('click', handle_M_B_S, false);
- });
- }
- };
- xhttp.open('GET', 'modes', true);
+ xhttp.open('GET', 'set?' + name + '=' + val, true);
xhttp.send();
-
- var can = document.getElementById('colorbar');
- var ctx = can.getContext('2d');
-
- drawColorbar();
-
- can.addEventListener('touchstart', Touch, false);
- can.addEventListener('click', Click, false);
}
)=====";
-
diff --git a/examples/ws2812fx_segment_sequence/ws2812fx_segment_sequence.ino b/examples/ws2812fx_segment_sequence/ws2812fx_segment_sequence.ino
new file mode 100644
index 0000000..c5aacd8
--- /dev/null
+++ b/examples/ws2812fx_segment_sequence/ws2812fx_segment_sequence.ino
@@ -0,0 +1,105 @@
+/*
+ WS2812FX segment sequence demo. Creates a list of segments and dynamically
+ changes which segments are active.
+
+ FEATURES
+ * example of creating idle segments
+
+
+ LICENSE
+
+ The MIT License (MIT)
+
+ Copyright (c) 2020 Keith Lord
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+
+ CHANGELOG
+ 2020-05-16 initial version
+
+*/
+
+#include
+
+#define LED_PIN 10 // digital pin used to drive the LED strip
+#define LED_COUNT 144 // number of LEDs on the strip
+
+#define NUM_SEGMENTS 4 // maximum total number of segments that can be created
+#define NUM_ACTIVE_SEGMENTS 2 // maximum number of segments that can be actively running
+
+// create helper macros that define the start and end LEDs for each of our two segments
+#define LOWER_SEG_RANGE 0, LED_COUNT/2 - 1
+#define UPPER_SEG_RANGE LED_COUNT/2, LED_COUNT - 1
+
+// example of the new WS2812FX constructor that adds parameters for the number of
+// segments allowed and the number of active segments allowed.
+WS2812FX ws2812fx = WS2812FX(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800, NUM_SEGMENTS, NUM_ACTIVE_SEGMENTS);
+
+void setup() {
+ Serial.begin(115200);
+
+ ws2812fx.init();
+ ws2812fx.setBrightness(32);
+
+ // create two active segments
+ ws2812fx.setSegment(0, LOWER_SEG_RANGE, FX_MODE_BLINK, YELLOW, 2000, NO_OPTIONS);
+ ws2812fx.setSegment(1, UPPER_SEG_RANGE, FX_MODE_BLINK, COLORS(RED, GREEN), 2000, NO_OPTIONS);
+
+ // create additional "idle" segments that will be activated later
+ ws2812fx.setIdleSegment(2, LOWER_SEG_RANGE, FX_MODE_BLINK, CYAN, 2000, NO_OPTIONS);
+ ws2812fx.setIdleSegment(3, UPPER_SEG_RANGE, FX_MODE_BLINK, COLORS(PINK, BLUE), 2000, NO_OPTIONS);
+
+ ws2812fx.start();
+}
+
+void loop() {
+ static unsigned long timer = millis();
+ static unsigned int blink_counter = 0;
+
+ ws2812fx.service();
+
+ /* the lower segment is updated based on a timer.
+ the lower segment will change every 10 seconds
+ */
+ if(millis() > timer + 10000) { // every 10 seconds...
+ if(ws2812fx.isActiveSegment(0)) { // if seg[0] is active, switch to seg[2]
+ ws2812fx.swapActiveSegment(0, 2);
+ } else { // else, switch to seg[0]
+ ws2812fx.swapActiveSegment(2, 0);
+ }
+ timer = millis();
+ }
+
+ /* the upper segment is updated based on counting animation cycles. One "cycle" for the Blink
+ * effect is one on/off sequence. We'll change the upper segment every 5 blinks.
+ */
+ // increment the blink counter every time seg[1] or seg[3] complete an animation cycle
+ if(ws2812fx.isCycle(1) || ws2812fx.isCycle(3)) {
+ blink_counter++;
+ }
+ if(blink_counter >= 5) { // every 5 blinks...
+ if(ws2812fx.isActiveSegment(1)) { // if seg[1] active, switch to seg[3]
+ ws2812fx.swapActiveSegment(1, 3);
+ } else { // else, switch to seg[1]
+ ws2812fx.swapActiveSegment(3, 1);
+ }
+ blink_counter = 0;
+ }
+}
diff --git a/examples/ws2812fx_segments_web/ws2812fx_segments_web.ino b/examples/ws2812fx_segments_web/ws2812fx_segments_web.ino
index 0f8e058..774508d 100644
--- a/examples/ws2812fx_segments_web/ws2812fx_segments_web.ino
+++ b/examples/ws2812fx_segments_web/ws2812fx_segments_web.ino
@@ -198,7 +198,7 @@ void setup() {
JsonObject seg = segments[i];
JsonArray colors = seg["colors"];
// the web interface sends three color values
- uint32_t _colors[NUM_COLORS] = {colors[0], colors[1], colors[2]};
+ uint32_t _colors[] = {colors[0], colors[1], colors[2]};
uint8_t _options = seg["options"];
ws2812fx.setSegment(i, seg["start"], seg["stop"], seg["mode"], _colors, seg["speed"], _options);
}
@@ -230,7 +230,7 @@ void setup() {
JsonObject seg = segments[i];
JsonArray colors = seg["colors"];
// the web interface sends three color values
- uint32_t _colors[NUM_COLORS] = {colors[0], colors[1], colors[2]};
+ uint32_t _colors[] = {colors[0], colors[1], colors[2]};
uint8_t _options = seg["options"];
ws2812fx.setSegment(i, seg["start"], seg["stop"], seg["mode"], _colors, seg["speed"], _options);
}
diff --git a/extras/WS2812FX change log.txt b/extras/WS2812FX change log.txt
index cd3a2bf..c517568 100644
--- a/extras/WS2812FX change log.txt
+++ b/extras/WS2812FX change log.txt
@@ -1,6 +1,47 @@
WS2182FX Change Log
+v1.3.0 changes 5/11/2020
+------------------------
+
+1) This library now makes use of the new Adafruit fill() function,
+ so requires Adafruit_NeoPixel library v1.1.7 or newer.
+
+2) Added the cycle flag to the effects that did not have it implemented.
+
+3) Refactored many effects, because the flash memory footprint was
+ getting too big to fit in my Arduino Leonardo. Some of the effects
+ don't look exactly the same, but they're pretty close.
+
+4) Changed the ICU effect from a built-in effect to a custom effect,
+ since it was quite large and removing it from the built-in effects
+ made more room for custom effects. It always seemed like a specialty
+ effect to me anyway.
+
+5) Refactored the Matrix custom effect so it can be configured from
+ outside of the Matrix.h file.
+
+6) Refactored the ws2812fx_webinterface example sketch to take advantage
+ of flex box layout and a more modern color picker.
+
+7) Added API for managing idle/active segments.
+ a) segment arrays are now configured at runtime instead of compile
+ time, allowing more flexibility in allocating SRAM for
+ that data (see the new WS2812FX constructor).
+
+ b) The number of segments and the number of segment_runtimes
+ are independent now, allowing for more fine grained SRAM
+ allocation and the creation of "idle" segments that are
+ activated at a later time. See the new
+ ws2812fx_segment_sequence example sketch.
+
+8) Increased the maximum number of custom effects from 4 to 8.
+
+9) Substantial refactoring of the segment code to use global variables
+ instead of macros, which makes sketches significantly smaller.
+
+
+
v1.2.4 changes 5/8/2020
------------------------
@@ -118,7 +159,7 @@ v1.1.7 changes 1/18/2019
setSegment(uint8_t, uint16_t, uint16_t, uint8_t, uint32_t, uint16_t, uint8_t)
4) Fixed a bug in the Larson Scanner effect that caused it to
- crash if SEGMENT_LENGTH==1. Fixes issue #145:
+ crash if the length of the segment is 1. Fixes issue #145:
https://github.com/kitesurfer1404/WS2812FX/issues/145
5) Updated the Rain custom effect to make use of all three colors.
diff --git a/keywords.txt b/keywords.txt
index 86d2c17..41db7e8 100644
--- a/keywords.txt
+++ b/keywords.txt
@@ -9,8 +9,11 @@ MAGENTA LITERAL1
PURPLE LITERAL1
ORANGE LITERAL1
PINK LITERAL1
+GRAY LITERAL1
ULTRAWHITE LITERAL1
+DIM LITERAL1
DARK LITERAL1
+COLORS LITERAL1
NO_OPTIONS LITERAL1
REVERSE LITERAL1
@@ -55,6 +58,10 @@ setColors KEYWORD2
setBrightness KEYWORD2
setLength KEYWORD2
setSegment KEYWORD2
+setIdleSegment KEYWORD2
+addActiveSegment KEYWORD2
+removeActiveSegment KEYWORD2
+swapActiveSegment KEYWORD2
resetSegments KEYWORD2
resetSegmentRuntimes KEYWORD2
resetSegmentRuntime KEYWORD2
diff --git a/library.json b/library.json
index 476b098..b4e97b3 100644
--- a/library.json
+++ b/library.json
@@ -6,7 +6,7 @@
"name": "Harm Aldick",
"url": "https://github.com/kitesurfer1404/WS2812FX"
},
- "version": "1.2.4",
+ "version": "1.3.0",
"downloadUrl": "https://github.com/kitesurfer1404/WS2812FX/archive/master.zip",
"export": {
"include": "WS2812FX-master"
@@ -20,7 +20,7 @@
"dependencies": [
{
"name": "Adafruit NeoPixel",
- "version": ">=1.1.4"
+ "version": ">=1.1.7"
}
],
"examples": [
diff --git a/library.properties b/library.properties
index 0c63cc1..c59667a 100644
--- a/library.properties
+++ b/library.properties
@@ -1,5 +1,5 @@
name=WS2812FX
-version=1.2.4
+version=1.3.0
author=Harm Aldick
maintainer=Harm Aldick
sentence=WS2812 FX Library for Arduino and ESP microprocessors.
diff --git a/src/WS2812FX.cpp b/src/WS2812FX.cpp
index 73baeff..3833fe8 100644
--- a/src/WS2812FX.cpp
+++ b/src/WS2812FX.cpp
@@ -61,7 +61,7 @@ void WS2812FX::init() {
// void WS2812FX::timer() {
// for (int j=0; j < 1000; j++) {
-// uint16_t delay = (this->*_mode[SEGMENT.mode])();
+// uint16_t delay = (this->*_mode[_seg->mode])();
// }
// }
@@ -69,15 +69,19 @@ void WS2812FX::service() {
if(_running || _triggered) {
unsigned long now = millis(); // Be aware, millis() rolls over every 49 days
bool doShow = false;
- for(uint8_t i=0; i < _num_segments; i++) {
- _segment_index = i;
- CLR_FRAME;
- if(now > SEGMENT_RUNTIME.next_time || _triggered) {
- SET_FRAME;
- doShow = true;
- uint16_t delay = (this->*_mode[SEGMENT.mode])();
- SEGMENT_RUNTIME.next_time = now + max(delay, SPEED_MIN);
- SEGMENT_RUNTIME.counter_mode_call++;
+ for(uint8_t i=0; i < _active_segments_len; i++) {
+ if(_active_segments[i] != INACTIVE_SEGMENT) {
+ _seg = &_segments[_active_segments[i]];
+ _seg_len = (uint16_t)(_seg->stop - _seg->start + 1);
+ _seg_rt = &_segment_runtimes[i];
+ CLR_FRAME_CYCLE;
+ if(now > _seg_rt->next_time || _triggered) {
+ SET_FRAME;
+ doShow = true;
+ uint16_t delay = (this->*_mode[_seg->mode])();
+ _seg_rt->next_time = now + max(delay, SPEED_MIN);
+ _seg_rt->counter_mode_call++;
+ }
}
}
if(doShow) {
@@ -91,23 +95,15 @@ void WS2812FX::service() {
// overload setPixelColor() functions so we can use gamma correction
// (see https://learn.adafruit.com/led-tricks-gamma-correction/the-issue)
void WS2812FX::setPixelColor(uint16_t n, uint32_t c) {
- if(IS_GAMMA) {
- uint8_t w = (c >> 24) & 0xFF;
- uint8_t r = (c >> 16) & 0xFF;
- uint8_t g = (c >> 8) & 0xFF;
- uint8_t b = c & 0xFF;
- Adafruit_NeoPixel::setPixelColor(n, gamma8(r), gamma8(g), gamma8(b), gamma8(w));
- } else {
- Adafruit_NeoPixel::setPixelColor(n, c);
- }
+ uint8_t w = (c >> 24) & 0xFF;
+ uint8_t r = (c >> 16) & 0xFF;
+ uint8_t g = (c >> 8) & 0xFF;
+ uint8_t b = c & 0xFF;
+ setPixelColor(n, r, g, b, w);
}
void WS2812FX::setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b) {
- if(IS_GAMMA) {
- Adafruit_NeoPixel::setPixelColor(n, gamma8(r), gamma8(g), gamma8(b));
- } else {
- Adafruit_NeoPixel::setPixelColor(n, r, g, b);
- }
+ setPixelColor(n, r, g, b, 0);
}
void WS2812FX::setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
@@ -125,13 +121,17 @@ void WS2812FX::copyPixels(uint16_t dest, uint16_t src, uint16_t count) {
memmove(pixels + (dest * bytesPerPixel), pixels + (src * bytesPerPixel), count * bytesPerPixel);
}
+// change the underlying Adafruit_NeoPixel pixels pointer (use with care)
+void WS2812FX::setPixels(uint16_t num_leds, uint8_t* ptr) {
+ free(Adafruit_NeoPixel::pixels); // free existing data (if any)
+ Adafruit_NeoPixel::pixels = ptr;
+ Adafruit_NeoPixel::numLEDs = num_leds;
+ Adafruit_NeoPixel::numBytes = num_leds * ((wOffset == rOffset) ? 3 : 4);
+}
+
// overload show() functions so we can use custom show()
void WS2812FX::show(void) {
- if(customShow == NULL) {
- Adafruit_NeoPixel::show();
- } else {
- customShow();
- }
+ customShow == NULL ? Adafruit_NeoPixel::show() : customShow();
}
void WS2812FX::start() {
@@ -174,17 +174,16 @@ void WS2812FX::setSpeed(uint16_t s) {
}
void WS2812FX::setSpeed(uint8_t seg, uint16_t s) {
-// resetSegmentRuntime(seg);
_segments[seg].speed = constrain(s, SPEED_MIN, SPEED_MAX);
}
void WS2812FX::increaseSpeed(uint8_t s) {
- uint16_t newSpeed = constrain(SEGMENT.speed + s, SPEED_MIN, SPEED_MAX);
+ uint16_t newSpeed = constrain(_seg->speed + s, SPEED_MIN, SPEED_MAX);
setSpeed(newSpeed);
}
void WS2812FX::decreaseSpeed(uint8_t s) {
- uint16_t newSpeed = constrain(SEGMENT.speed - s, SPEED_MIN, SPEED_MAX);
+ uint16_t newSpeed = constrain(_seg->speed - s, SPEED_MIN, SPEED_MAX);
setSpeed(newSpeed);
}
@@ -201,13 +200,11 @@ void WS2812FX::setColor(uint32_t c) {
}
void WS2812FX::setColor(uint8_t seg, uint32_t c) {
-// resetSegmentRuntime(seg);
_segments[seg].colors[0] = c;
}
void WS2812FX::setColors(uint8_t seg, uint32_t* c) {
-// resetSegmentRuntime(seg);
- for(uint8_t i=0; i _segments[0].stop - _segments[0].start + 1) s = 1;
- s = _segments[0].stop - _segments[0].start + 1 - s;
-
- for(uint16_t i=_segments[0].start + s; i <= (_segments[0].stop - _segments[0].start + 1); i++) {
- setPixelColor(i, 0);
- }
+ uint16_t seglen = _segments[0].stop - _segments[0].start + 1;
+ fill(BLACK, _segments[0].start, seglen);
show();
- setLength(s);
+ if (s < seglen) setLength(seglen - s);
}
boolean WS2812FX::isRunning() {
@@ -271,16 +264,24 @@ boolean WS2812FX::isFrame() {
return isFrame(0);
}
-boolean WS2812FX::isFrame(uint8_t segIndex) {
- return (_segment_runtimes[segIndex].aux_param2 & FRAME);
+boolean WS2812FX::isFrame(uint8_t seg) {
+ uint8_t* ptr = (uint8_t*)memchr(_active_segments, seg, _active_segments_len);
+ if(ptr == NULL) return false; // segment not active
+ return (_segment_runtimes[ptr - _active_segments].aux_param2 & FRAME);
}
boolean WS2812FX::isCycle() {
return isCycle(0);
}
-boolean WS2812FX::isCycle(uint8_t segIndex) {
- return (_segment_runtimes[segIndex].aux_param2 & CYCLE);
+boolean WS2812FX::isCycle(uint8_t seg) {
+ uint8_t* ptr = (uint8_t*)memchr(_active_segments, seg, _active_segments_len);
+ if(ptr == NULL) return false; // segment not active
+ return (_segment_runtimes[ptr - _active_segments].aux_param2 & CYCLE);
+}
+
+void WS2812FX::setCycle() {
+ SET_CYCLE;
}
uint8_t WS2812FX::getMode(void) {
@@ -299,7 +300,6 @@ uint16_t WS2812FX::getSpeed(uint8_t seg) {
return _segments[seg].speed;
}
-
uint8_t WS2812FX::getOptions(uint8_t seg) {
return _segments[seg].options;
}
@@ -341,7 +341,7 @@ uint32_t* WS2812FX::getColors(uint8_t seg) {
}
WS2812FX::Segment* WS2812FX::getSegment(void) {
- return &_segments[_segment_index];
+ return _seg;
}
WS2812FX::Segment* WS2812FX::getSegment(uint8_t seg) {
@@ -353,17 +353,23 @@ WS2812FX::Segment* WS2812FX::getSegments(void) {
}
WS2812FX::Segment_runtime* WS2812FX::getSegmentRuntime(void) {
- return &_segment_runtimes[_segment_index];
+ return _seg_rt;
}
WS2812FX::Segment_runtime* WS2812FX::getSegmentRuntime(uint8_t seg) {
- return &_segment_runtimes[seg];
+ uint8_t* ptr = (uint8_t*)memchr(_active_segments, seg, _active_segments_len);
+ if(ptr == NULL) return NULL; // segment not active
+ return &_segment_runtimes[ptr - _active_segments];
}
WS2812FX::Segment_runtime* WS2812FX::getSegmentRuntimes(void) {
return _segment_runtimes;
}
+uint8_t* WS2812FX::getActiveSegments(void) {
+ return _active_segments;
+}
+
const __FlashStringHelper* WS2812FX::getModeName(uint8_t m) {
if(m < MODE_COUNT) {
return _names[m];
@@ -372,22 +378,32 @@ const __FlashStringHelper* WS2812FX::getModeName(uint8_t m) {
}
}
-void WS2812FX::setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t color, uint16_t speed, bool reverse) {
+void WS2812FX::setIdleSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t color, uint16_t speed, uint8_t options) {
uint32_t colors[] = {color, 0, 0};
- setSegment(n, start, stop, mode, colors, speed, reverse);
+ setIdleSegment(n, start, stop, mode, colors, speed, options);
}
-void WS2812FX::setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t color, uint16_t speed, uint8_t options) {
- uint32_t colors[] = {color, 0, 0};
+void WS2812FX::setIdleSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, const uint32_t colors[], uint16_t speed, uint8_t options) {
setSegment(n, start, stop, mode, colors, speed, options);
+ if(n < _active_segments_len) removeActiveSegment(n);;
+}
+
+void WS2812FX::setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t color, uint16_t speed, bool reverse) {
+ uint32_t colors[] = {color, 0, 0};
+ setSegment(n, start, stop, mode, colors, speed, (uint8_t)(reverse ? REVERSE : NO_OPTIONS));
}
void WS2812FX::setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, const uint32_t colors[], uint16_t speed, bool reverse) {
setSegment(n, start, stop, mode, colors, speed, (uint8_t)(reverse ? REVERSE : NO_OPTIONS));
}
+void WS2812FX::setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t color, uint16_t speed, uint8_t options) {
+ uint32_t colors[] = {color, 0, 0};
+ setSegment(n, start, stop, mode, colors, speed, options);
+}
+
void WS2812FX::setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, const uint32_t colors[], uint16_t speed, uint8_t options) {
- if(n < (sizeof(_segments) / sizeof(_segments[0]))) {
+ if(n < _segments_len) {
if(n + 1 > _num_segments) _num_segments = n + 1;
_segments[n].start = start;
_segments[n].stop = stop;
@@ -395,34 +411,75 @@ void WS2812FX::setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode
_segments[n].speed = speed;
_segments[n].options = options;
- for(uint8_t i=0; i g -> b -> back to r
@@ -450,7 +506,6 @@ uint32_t WS2812FX::color_wheel(uint8_t pos) {
}
}
-
/*
* Returns a new, random wheel index with a minimum distance of 42 from pos.
*/
@@ -479,7 +534,7 @@ uint8_t WS2812FX::random8() {
// note random8(lim) generates numbers in the range 0 to (lim -1)
uint8_t WS2812FX::random8(uint8_t lim) {
uint8_t r = random8();
- r = (r * lim) >> 8;
+ r = ((uint16_t)r * lim) >> 8;
return r;
}
@@ -524,14 +579,20 @@ uint32_t* WS2812FX::intensitySums() {
return intensities;
}
+
+/* #####################################################
+#
+# Mode Functions
+#
+##################################################### */
+
/*
* No blinking. Just plain old static light.
*/
uint16_t WS2812FX::mode_static(void) {
- for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) {
- setPixelColor(i, SEGMENT.colors[0]);
- }
- return SEGMENT.speed;
+ fill(_seg->colors[0], _seg->start, _seg_len);
+ SET_CYCLE;
+ return _seg->speed;
}
@@ -541,16 +602,15 @@ uint16_t WS2812FX::mode_static(void) {
* if(strobe == true) then create a strobe effect
*/
uint16_t WS2812FX::blink(uint32_t color1, uint32_t color2, bool strobe) {
- uint32_t color = ((SEGMENT_RUNTIME.counter_mode_call & 1) == 0) ? color1 : color2;
- if(IS_REVERSE) color = (color == color1) ? color2 : color1;
- for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) {
- setPixelColor(i, color);
- }
-
- if((SEGMENT_RUNTIME.counter_mode_call & 1) == 0) {
- return strobe ? 20 : (SEGMENT.speed / 2);
+ if(_seg_rt->counter_mode_call & 1) {
+ uint32_t color = (IS_REVERSE) ? color1 : color2; // off
+ fill(color, _seg->start, _seg_len);
+ SET_CYCLE;
+ return strobe ? _seg->speed - 20 : (_seg->speed / 2);
} else {
- return strobe ? SEGMENT.speed - 20 : (SEGMENT.speed / 2);
+ uint32_t color = (IS_REVERSE) ? color2 : color1; // on
+ fill(color, _seg->start, _seg_len);
+ return strobe ? 20 : (_seg->speed / 2);
}
}
@@ -559,7 +619,7 @@ uint16_t WS2812FX::blink(uint32_t color1, uint32_t color2, bool strobe) {
* Normal blinking. 50% on/off time.
*/
uint16_t WS2812FX::mode_blink(void) {
- return blink(SEGMENT.colors[0], SEGMENT.colors[1], false);
+ return blink(_seg->colors[0], _seg->colors[1], false);
}
@@ -567,7 +627,7 @@ uint16_t WS2812FX::mode_blink(void) {
* Classic Blink effect. Cycling through the rainbow.
*/
uint16_t WS2812FX::mode_blink_rainbow(void) {
- return blink(color_wheel(SEGMENT_RUNTIME.counter_mode_call & 0xFF), SEGMENT.colors[1], false);
+ return blink(color_wheel(_seg_rt->counter_mode_call & 0xFF), _seg->colors[1], false);
}
@@ -575,7 +635,7 @@ uint16_t WS2812FX::mode_blink_rainbow(void) {
* Classic Strobe effect.
*/
uint16_t WS2812FX::mode_strobe(void) {
- return blink(SEGMENT.colors[0], SEGMENT.colors[1], true);
+ return blink(_seg->colors[0], _seg->colors[1], true);
}
@@ -583,7 +643,7 @@ uint16_t WS2812FX::mode_strobe(void) {
* Classic Strobe effect. Cycling through the rainbow.
*/
uint16_t WS2812FX::mode_strobe_rainbow(void) {
- return blink(color_wheel(SEGMENT_RUNTIME.counter_mode_call & 0xFF), SEGMENT.colors[1], true);
+ return blink(color_wheel(_seg_rt->counter_mode_call & 0xFF), _seg->colors[1], true);
}
@@ -593,46 +653,46 @@ uint16_t WS2812FX::mode_strobe_rainbow(void) {
* if (bool rev == true) then LEDs are turned off in reverse order
*/
uint16_t WS2812FX::color_wipe(uint32_t color1, uint32_t color2, bool rev) {
- if(SEGMENT_RUNTIME.counter_mode_step < SEGMENT_LENGTH) {
- uint32_t led_offset = SEGMENT_RUNTIME.counter_mode_step;
+ if(_seg_rt->counter_mode_step < _seg_len) {
+ uint32_t led_offset = _seg_rt->counter_mode_step;
if(IS_REVERSE) {
- setPixelColor(SEGMENT.stop - led_offset, color1);
+ setPixelColor(_seg->stop - led_offset, color1);
} else {
- setPixelColor(SEGMENT.start + led_offset, color1);
+ setPixelColor(_seg->start + led_offset, color1);
}
} else {
- uint32_t led_offset = SEGMENT_RUNTIME.counter_mode_step - SEGMENT_LENGTH;
+ uint32_t led_offset = _seg_rt->counter_mode_step - _seg_len;
if((IS_REVERSE && !rev) || (!IS_REVERSE && rev)) {
- setPixelColor(SEGMENT.stop - led_offset, color2);
+ setPixelColor(_seg->stop - led_offset, color2);
} else {
- setPixelColor(SEGMENT.start + led_offset, color2);
+ setPixelColor(_seg->start + led_offset, color2);
}
}
- if(SEGMENT_RUNTIME.counter_mode_step % SEGMENT_LENGTH == 0) SET_CYCLE;
- else CLR_CYCLE;
+ _seg_rt->counter_mode_step = (_seg_rt->counter_mode_step + 1) % (_seg_len * 2);
- SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % (SEGMENT_LENGTH * 2);
- return (SEGMENT.speed / (SEGMENT_LENGTH * 2));
+ if(_seg_rt->counter_mode_step == 0) SET_CYCLE;
+
+ return (_seg->speed / (_seg_len * 2));
}
/*
* Lights all LEDs one after another.
*/
uint16_t WS2812FX::mode_color_wipe(void) {
- return color_wipe(SEGMENT.colors[0], SEGMENT.colors[1], false);
+ return color_wipe(_seg->colors[0], _seg->colors[1], false);
}
uint16_t WS2812FX::mode_color_wipe_inv(void) {
- return color_wipe(SEGMENT.colors[1], SEGMENT.colors[0], false);
+ return color_wipe(_seg->colors[1], _seg->colors[0], false);
}
uint16_t WS2812FX::mode_color_wipe_rev(void) {
- return color_wipe(SEGMENT.colors[0], SEGMENT.colors[1], true);
+ return color_wipe(_seg->colors[0], _seg->colors[1], true);
}
uint16_t WS2812FX::mode_color_wipe_rev_inv(void) {
- return color_wipe(SEGMENT.colors[1], SEGMENT.colors[0], true);
+ return color_wipe(_seg->colors[1], _seg->colors[0], true);
}
@@ -641,10 +701,10 @@ uint16_t WS2812FX::mode_color_wipe_rev_inv(void) {
* Then starts over with another color.
*/
uint16_t WS2812FX::mode_color_wipe_random(void) {
- if(SEGMENT_RUNTIME.counter_mode_step % SEGMENT_LENGTH == 0) { // aux_param will store our random color wheel index
- SEGMENT_RUNTIME.aux_param = get_random_wheel_index(SEGMENT_RUNTIME.aux_param);
+ if(_seg_rt->counter_mode_step % _seg_len == 0) { // aux_param will store our random color wheel index
+ _seg_rt->aux_param = get_random_wheel_index(_seg_rt->aux_param);
}
- uint32_t color = color_wheel(SEGMENT_RUNTIME.aux_param);
+ uint32_t color = color_wheel(_seg_rt->aux_param);
return color_wipe(color, color, false) * 2;
}
@@ -653,10 +713,10 @@ uint16_t WS2812FX::mode_color_wipe_random(void) {
* Random color introduced alternating from start and end of strip.
*/
uint16_t WS2812FX::mode_color_sweep_random(void) {
- if(SEGMENT_RUNTIME.counter_mode_step % SEGMENT_LENGTH == 0) { // aux_param will store our random color wheel index
- SEGMENT_RUNTIME.aux_param = get_random_wheel_index(SEGMENT_RUNTIME.aux_param);
+ if(_seg_rt->counter_mode_step % _seg_len == 0) { // aux_param will store our random color wheel index
+ _seg_rt->aux_param = get_random_wheel_index(_seg_rt->aux_param);
}
- uint32_t color = color_wheel(SEGMENT_RUNTIME.aux_param);
+ uint32_t color = color_wheel(_seg_rt->aux_param);
return color_wipe(color, color, true) * 2;
}
@@ -666,13 +726,11 @@ uint16_t WS2812FX::mode_color_sweep_random(void) {
* to the next random color.
*/
uint16_t WS2812FX::mode_random_color(void) {
- SEGMENT_RUNTIME.aux_param = get_random_wheel_index(SEGMENT_RUNTIME.aux_param); // aux_param will store our random color wheel index
- uint32_t color = color_wheel(SEGMENT_RUNTIME.aux_param);
-
- for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) {
- setPixelColor(i, color);
- }
- return SEGMENT.speed;
+ _seg_rt->aux_param = get_random_wheel_index(_seg_rt->aux_param); // aux_param will store our random color wheel index
+ uint32_t color = color_wheel(_seg_rt->aux_param);
+ fill(color, _seg->start, _seg_len);
+ SET_CYCLE;
+ return _seg->speed;
}
@@ -681,14 +739,15 @@ uint16_t WS2812FX::mode_random_color(void) {
* to another random color.
*/
uint16_t WS2812FX::mode_single_dynamic(void) {
- if(SEGMENT_RUNTIME.counter_mode_call == 0) {
- for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) {
+ if(_seg_rt->counter_mode_call == 0) {
+ for(uint16_t i=_seg->start; i <= _seg->stop; i++) {
setPixelColor(i, color_wheel(random8()));
}
}
- setPixelColor(SEGMENT.start + random16(SEGMENT_LENGTH), color_wheel(random8()));
- return SEGMENT.speed;
+ setPixelColor(_seg->start + random16(_seg_len), color_wheel(random8()));
+ SET_CYCLE;
+ return _seg->speed;
}
@@ -697,10 +756,11 @@ uint16_t WS2812FX::mode_single_dynamic(void) {
* to new random colors.
*/
uint16_t WS2812FX::mode_multi_dynamic(void) {
- for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) {
+ for(uint16_t i=_seg->start; i <= _seg->stop; i++) {
setPixelColor(i, color_wheel(random8()));
}
- return SEGMENT.speed;
+ SET_CYCLE;
+ return _seg->speed;
}
@@ -709,7 +769,7 @@ uint16_t WS2812FX::mode_multi_dynamic(void) {
* Use mode "fade" if you like to have something similar with a different speed.
*/
uint16_t WS2812FX::mode_breath(void) {
- int lum = SEGMENT_RUNTIME.counter_mode_step;
+ int lum = _seg_rt->counter_mode_step;
if(lum > 255) lum = 511 - lum; // lum = 15 -> 255 -> 15
uint16_t delay;
@@ -722,17 +782,14 @@ uint16_t WS2812FX::mode_breath(void) {
else if(lum <= 150) delay = 11; // 5
else delay = 10; // 4
- uint32_t color = SEGMENT.colors[0];
- uint8_t w = (color >> 24 & 0xFF) * lum / 256;
- uint8_t r = (color >> 16 & 0xFF) * lum / 256;
- uint8_t g = (color >> 8 & 0xFF) * lum / 256;
- uint8_t b = (color & 0xFF) * lum / 256;
- for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) {
- setPixelColor(i, r, g, b, w);
- }
+ uint32_t color = color_blend(_seg->colors[1], _seg->colors[0], lum);
+ fill(color, _seg->start, _seg_len);
- SEGMENT_RUNTIME.counter_mode_step += 2;
- if(SEGMENT_RUNTIME.counter_mode_step > (512-15)) SEGMENT_RUNTIME.counter_mode_step = 15;
+ _seg_rt->counter_mode_step += 2;
+ if(_seg_rt->counter_mode_step > (512-15)) {
+ _seg_rt->counter_mode_step = 15;
+ SET_CYCLE;
+ }
return delay;
}
@@ -741,17 +798,18 @@ uint16_t WS2812FX::mode_breath(void) {
* Fades the LEDs between two colors
*/
uint16_t WS2812FX::mode_fade(void) {
- int lum = SEGMENT_RUNTIME.counter_mode_step;
+ int lum = _seg_rt->counter_mode_step;
if(lum > 255) lum = 511 - lum; // lum = 0 -> 255 -> 0
- uint32_t color = color_blend(SEGMENT.colors[0], SEGMENT.colors[1], lum);
- for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) {
- setPixelColor(i, color);
- }
+ uint32_t color = color_blend(_seg->colors[1], _seg->colors[0], lum);
+ fill(color, _seg->start, _seg_len);
- SEGMENT_RUNTIME.counter_mode_step += 4;
- if(SEGMENT_RUNTIME.counter_mode_step > 511) SEGMENT_RUNTIME.counter_mode_step = 0;
- return (SEGMENT.speed / 128);
+ _seg_rt->counter_mode_step += 4;
+ if(_seg_rt->counter_mode_step > 511) {
+ _seg_rt->counter_mode_step = 0;
+ SET_CYCLE;
+ }
+ return (_seg->speed / 128);
}
@@ -759,27 +817,28 @@ uint16_t WS2812FX::mode_fade(void) {
* scan function - runs a block of pixels back and forth.
*/
uint16_t WS2812FX::scan(uint32_t color1, uint32_t color2, bool dual) {
- int8_t dir = SEGMENT_RUNTIME.aux_param ? -1 : 1;
+ int8_t dir = _seg_rt->aux_param ? -1 : 1;
uint8_t size = 1 << SIZE_OPTION;
- for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) {
- setPixelColor(i, color2);
- }
+ fill(color2, _seg->start, _seg_len);
for(uint8_t i = 0; i < size; i++) {
if(IS_REVERSE || dual) {
- setPixelColor(SEGMENT.stop - SEGMENT_RUNTIME.counter_mode_step - i, color1);
+ setPixelColor(_seg->stop - _seg_rt->counter_mode_step - i, color1);
}
if(!IS_REVERSE || dual) {
- setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step + i, color1);
+ setPixelColor(_seg->start + _seg_rt->counter_mode_step + i, color1);
}
}
- SEGMENT_RUNTIME.counter_mode_step += dir;
- if(SEGMENT_RUNTIME.counter_mode_step == 0) SEGMENT_RUNTIME.aux_param = 0;
- if(SEGMENT_RUNTIME.counter_mode_step >= (uint16_t)(SEGMENT_LENGTH - size)) SEGMENT_RUNTIME.aux_param = 1;
+ _seg_rt->counter_mode_step += dir;
+ if(_seg_rt->counter_mode_step == 0) {
+ _seg_rt->aux_param = 0;
+ SET_CYCLE;
+ }
+ if(_seg_rt->counter_mode_step >= (uint16_t)(_seg_len - size)) _seg_rt->aux_param = 1;
- return (SEGMENT.speed / (SEGMENT_LENGTH * 2));
+ return (_seg->speed / (_seg_len * 2));
}
@@ -787,7 +846,7 @@ uint16_t WS2812FX::scan(uint32_t color1, uint32_t color2, bool dual) {
* Runs a block of pixels back and forth.
*/
uint16_t WS2812FX::mode_scan(void) {
- return scan(SEGMENT.colors[0], SEGMENT.colors[1], false);
+ return scan(_seg->colors[0], _seg->colors[1], false);
}
@@ -795,7 +854,7 @@ uint16_t WS2812FX::mode_scan(void) {
* Runs two blocks of pixels back and forth in opposite directions.
*/
uint16_t WS2812FX::mode_dual_scan(void) {
- return scan(SEGMENT.colors[0], SEGMENT.colors[1], true);
+ return scan(_seg->colors[0], _seg->colors[1], true);
}
@@ -803,13 +862,14 @@ uint16_t WS2812FX::mode_dual_scan(void) {
* Cycles all LEDs at once through a rainbow.
*/
uint16_t WS2812FX::mode_rainbow(void) {
- uint32_t color = color_wheel(SEGMENT_RUNTIME.counter_mode_step);
- for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) {
- setPixelColor(i, color);
- }
+ uint32_t color = color_wheel(_seg_rt->counter_mode_step);
+ fill(color, _seg->start, _seg_len);
- SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) & 0xFF;
- return (SEGMENT.speed / 256);
+ _seg_rt->counter_mode_step = (_seg_rt->counter_mode_step + 1) & 0xFF;
+
+ if(_seg_rt->counter_mode_step == 0) SET_CYCLE;
+
+ return (_seg->speed / 256);
}
@@ -817,13 +877,61 @@ uint16_t WS2812FX::mode_rainbow(void) {
* Cycles a rainbow over the entire string of LEDs.
*/
uint16_t WS2812FX::mode_rainbow_cycle(void) {
- for(uint16_t i=0; i < SEGMENT_LENGTH; i++) {
- uint32_t color = color_wheel(((i * 256 / SEGMENT_LENGTH) + SEGMENT_RUNTIME.counter_mode_step) & 0xFF);
- setPixelColor(SEGMENT.start + i, color);
+ for(uint16_t i=0; i < _seg_len; i++) {
+ uint32_t color = color_wheel(((i * 256 / _seg_len) + _seg_rt->counter_mode_step) & 0xFF);
+ setPixelColor(_seg->start + i, color);
}
- SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) & 0xFF;
- return (SEGMENT.speed / 256);
+ _seg_rt->counter_mode_step = (_seg_rt->counter_mode_step + 1) & 0xFF;
+
+ if(_seg_rt->counter_mode_step == 0) SET_CYCLE;
+
+ return (_seg->speed / 256);
+}
+
+
+/*
+ * Tricolor chase function
+ */
+uint16_t WS2812FX::tricolor_chase(uint32_t color1, uint32_t color2, uint32_t color3) {
+ uint8_t sizeCnt = 1 << SIZE_OPTION;
+ uint8_t sizeCnt2 = sizeCnt + sizeCnt;
+ uint8_t sizeCnt3 = sizeCnt2 + sizeCnt;
+ uint16_t index = _seg_rt->counter_mode_step % sizeCnt3;
+ for(uint16_t i=0; i < _seg_len; i++, index++) {
+ index = index % sizeCnt3;
+
+ uint32_t color = color3;
+ if(index < sizeCnt) color = color1;
+ else if(index < sizeCnt2) color = color2;
+
+ if(IS_REVERSE) {
+ setPixelColor(_seg->start + i, color);
+ } else {
+ setPixelColor(_seg->stop - i, color);
+ }
+ }
+
+ _seg_rt->counter_mode_step++;
+ if(_seg_rt->counter_mode_step % _seg_len == 0) SET_CYCLE;
+
+ return (_seg->speed / _seg_len);
+}
+
+
+/*
+ * Tricolor chase mode
+ */
+uint16_t WS2812FX::mode_tricolor_chase(void) {
+ return tricolor_chase(_seg->colors[0], _seg->colors[1], _seg->colors[2]);
+}
+
+
+/*
+ * Alternating white/red/black pixels running.
+ */
+uint16_t WS2812FX::mode_circus_combustus(void) {
+ return tricolor_chase(RED, WHITE, BLACK);
}
@@ -832,7 +940,7 @@ uint16_t WS2812FX::mode_rainbow_cycle(void) {
* Inspired by the Adafruit examples.
*/
uint16_t WS2812FX::mode_theater_chase(void) {
- return tricolor_chase(SEGMENT.colors[0], SEGMENT.colors[1], SEGMENT.colors[1]);
+ return tricolor_chase(_seg->colors[0], _seg->colors[1], _seg->colors[1]);
}
@@ -841,9 +949,9 @@ uint16_t WS2812FX::mode_theater_chase(void) {
* Inspired by the Adafruit examples.
*/
uint16_t WS2812FX::mode_theater_chase_rainbow(void) {
- SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) & 0xFF;
- uint32_t color = color_wheel(SEGMENT_RUNTIME.counter_mode_step);
- return tricolor_chase(color, SEGMENT.colors[1], SEGMENT.colors[1]);
+ _seg_rt->counter_mode_step = (_seg_rt->counter_mode_step + 1) & 0xFF;
+ uint32_t color = color_wheel(_seg_rt->counter_mode_step);
+ return tricolor_chase(color, _seg->colors[1], _seg->colors[1]);
}
@@ -852,18 +960,19 @@ uint16_t WS2812FX::mode_theater_chase_rainbow(void) {
*/
uint16_t WS2812FX::mode_running_lights(void) {
uint8_t size = 1 << SIZE_OPTION;
- uint8_t sineIncr = max(1, (256 / SEGMENT_LENGTH) * size);
- for(uint16_t i=0; i < SEGMENT_LENGTH; i++) {
- int lum = (int)sine8(((i + SEGMENT_RUNTIME.counter_mode_step) * sineIncr));
- uint32_t color = color_blend(SEGMENT.colors[0], SEGMENT.colors[1], lum);
+ uint8_t sineIncr = max(1, (256 / _seg_len) * size);
+ for(uint16_t i=0; i < _seg_len; i++) {
+ int lum = (int)sine8(((i + _seg_rt->counter_mode_step) * sineIncr));
+ uint32_t color = color_blend(_seg->colors[0], _seg->colors[1], lum);
if(IS_REVERSE) {
- setPixelColor(SEGMENT.start + i, color);
+ setPixelColor(_seg->start + i, color);
} else {
- setPixelColor(SEGMENT.stop - i, color);
+ setPixelColor(_seg->stop - i, color);
}
}
- SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % 256;
- return (SEGMENT.speed / SEGMENT_LENGTH);
+ _seg_rt->counter_mode_step = (_seg_rt->counter_mode_step + 1) % 256;
+ if(_seg_rt->counter_mode_step == 0) SET_CYCLE;
+ return (_seg->speed / _seg_len);
}
@@ -871,19 +980,17 @@ uint16_t WS2812FX::mode_running_lights(void) {
* twinkle function
*/
uint16_t WS2812FX::twinkle(uint32_t color1, uint32_t color2) {
- if(SEGMENT_RUNTIME.counter_mode_step == 0) {
- for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) {
- setPixelColor(i, color2);
- }
- uint16_t min_leds = max(1, SEGMENT_LENGTH / 5); // make sure, at least one LED is on
- uint16_t max_leds = max(1, SEGMENT_LENGTH / 2); // make sure, at least one LED is on
- SEGMENT_RUNTIME.counter_mode_step = random(min_leds, max_leds);
+ if(_seg_rt->counter_mode_step == 0) {
+ fill(color2, _seg->start, _seg_len);
+ uint16_t min_leds = (_seg_len / 4) + 1; // make sure, at least one LED is on
+ _seg_rt->counter_mode_step = random(min_leds, min_leds * 2);
+ SET_CYCLE;
}
- setPixelColor(SEGMENT.start + random16(SEGMENT_LENGTH), color1);
+ setPixelColor(_seg->start + random16(_seg_len), color1);
- SEGMENT_RUNTIME.counter_mode_step--;
- return (SEGMENT.speed / SEGMENT_LENGTH);
+ _seg_rt->counter_mode_step--;
+ return (_seg->speed / _seg_len);
}
/*
@@ -891,7 +998,7 @@ uint16_t WS2812FX::twinkle(uint32_t color1, uint32_t color2) {
* Inspired by www.tweaking4all.com/hardware/arduino/arduino-led-strip-effects/
*/
uint16_t WS2812FX::mode_twinkle(void) {
- return twinkle(SEGMENT.colors[0], SEGMENT.colors[1]);
+ return twinkle(_seg->colors[0], _seg->colors[1]);
}
/*
@@ -899,7 +1006,7 @@ uint16_t WS2812FX::mode_twinkle(void) {
* Inspired by www.tweaking4all.com/hardware/arduino/arduino-led-strip-effects/
*/
uint16_t WS2812FX::mode_twinkle_random(void) {
- return twinkle(color_wheel(random8()), SEGMENT.colors[1]);
+ return twinkle(color_wheel(random8()), _seg->colors[1]);
}
@@ -907,7 +1014,7 @@ uint16_t WS2812FX::mode_twinkle_random(void) {
* fade out functions
*/
void WS2812FX::fade_out() {
- return fade_out(SEGMENT.colors[1]);
+ return fade_out(_seg->colors[1]);
}
void WS2812FX::fade_out(uint32_t targetColor) {
@@ -924,7 +1031,7 @@ void WS2812FX::fade_out(uint32_t targetColor) {
int g2 = (color >> 8) & 0xff;
int b2 = color & 0xff;
- for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) {
+ for(uint16_t i=_seg->start; i <= _seg->stop; i++) {
color = getPixelColor(i); // current color
if(rate == 0) { // old fade-to-black algorithm
setPixelColor(i, (color >> 1) & 0x7F7F7F7F);
@@ -987,12 +1094,11 @@ uint16_t WS2812FX::twinkle_fade(uint32_t color) {
if(random8(3) == 0) {
uint8_t size = 1 << SIZE_OPTION;
- uint16_t index = SEGMENT.start + random16(SEGMENT_LENGTH - size);
- for(uint8_t i=0; istart + random16(_seg_len - size);
+ fill(color, index, size);
+ SET_CYCLE;
}
- return (SEGMENT.speed / 8);
+ return (_seg->speed / 8);
}
@@ -1000,7 +1106,7 @@ uint16_t WS2812FX::twinkle_fade(uint32_t color) {
* Blink several LEDs on, fading out.
*/
uint16_t WS2812FX::mode_twinkle_fade(void) {
- return twinkle_fade(SEGMENT.colors[0]);
+ return twinkle_fade(_seg->colors[0]);
}
@@ -1011,21 +1117,33 @@ uint16_t WS2812FX::mode_twinkle_fade_random(void) {
return twinkle_fade(color_wheel(random8()));
}
+/*
+ * Sparkle function
+ * color1 = background color
+ * color2 = sparkle color
+ */
+uint16_t WS2812FX::sparkle(uint32_t color1, uint32_t color2) {
+ if(_seg_rt->counter_mode_step == 0) {
+ fill(color1, _seg->start, _seg_len);
+ }
+
+ uint8_t size = 1 << SIZE_OPTION;
+ fill(color1, _seg->start + _seg_rt->aux_param3, size);
+
+ _seg_rt->aux_param3 = random16(_seg_len - size); // aux_param3 stores the random led index
+ fill(color2, _seg->start + _seg_rt->aux_param3, size);
+
+ SET_CYCLE;
+ return (_seg->speed / 32);
+}
+
/*
* Blinks one LED at a time.
* Inspired by www.tweaking4all.com/hardware/arduino/arduino-led-strip-effects/
*/
uint16_t WS2812FX::mode_sparkle(void) {
- uint8_t size = 1 << SIZE_OPTION;
- for(uint8_t i=0; icolors[1], _seg->colors[0]);
}
@@ -1034,20 +1152,7 @@ uint16_t WS2812FX::mode_sparkle(void) {
* Inspired by www.tweaking4all.com/hardware/arduino/arduino-led-strip-effects/
*/
uint16_t WS2812FX::mode_flash_sparkle(void) {
- for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) {
- setPixelColor(i, SEGMENT.colors[0]);
- }
-
- if(random8(5) == 0) {
- uint8_t size = 1 << SIZE_OPTION;
- uint16_t index = SEGMENT.start + random16(SEGMENT_LENGTH - size);
- for(uint8_t j=0; jcolors[0], WHITE);
}
@@ -1056,17 +1161,15 @@ uint16_t WS2812FX::mode_flash_sparkle(void) {
* Inspired by www.tweaking4all.com/hardware/arduino/arduino-led-strip-effects/
*/
uint16_t WS2812FX::mode_hyper_sparkle(void) {
- for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) {
- setPixelColor(i, SEGMENT.colors[0]);
- }
+ fill(_seg->colors[0], _seg->start, _seg_len);
- if(random8(5) < 2) {
- for(uint16_t i=0; i < max(1, SEGMENT_LENGTH/3); i++) {
- setPixelColor(SEGMENT.start + random16(SEGMENT_LENGTH), WHITE);
- }
- return 20;
+ uint8_t size = 1 << SIZE_OPTION;
+ for(uint8_t i=0; i<8; i++) {
+ fill(WHITE, _seg->start + random16(_seg_len - size), size);
}
- return SEGMENT.speed;
+
+ SET_CYCLE;
+ return (_seg->speed / 32);
}
@@ -1074,23 +1177,21 @@ uint16_t WS2812FX::mode_hyper_sparkle(void) {
* Strobe effect with different strobe count and pause, controlled by speed.
*/
uint16_t WS2812FX::mode_multi_strobe(void) {
- for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) {
- setPixelColor(i, BLACK);
- }
+ fill(_seg->colors[1], _seg->start, _seg_len);
- uint16_t delay = 200 + ((9 - (SEGMENT.speed % 10)) * 100);
- uint16_t count = 2 * ((SEGMENT.speed / 100) + 1);
- if(SEGMENT_RUNTIME.counter_mode_step < count) {
- if((SEGMENT_RUNTIME.counter_mode_step & 1) == 0) {
- for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) {
- setPixelColor(i, SEGMENT.colors[0]);
- }
+ uint16_t delay = 200 + ((9 - (_seg->speed % 10)) * 100);
+ uint16_t count = 2 * ((_seg->speed / 100) + 1);
+ if(_seg_rt->counter_mode_step < count) {
+ if((_seg_rt->counter_mode_step & 1) == 0) {
+ fill(_seg->colors[0], _seg->start, _seg_len);
delay = 20;
} else {
delay = 50;
}
}
- SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % (count + 1);
+
+ _seg_rt->counter_mode_step = (_seg_rt->counter_mode_step + 1) % (count + 1);
+ if(_seg_rt->counter_mode_step == 0) SET_CYCLE;
return delay;
}
@@ -1100,29 +1201,27 @@ uint16_t WS2812FX::mode_multi_strobe(void) {
* color1 = background color
* color2 and color3 = colors of two adjacent leds
*/
-
uint16_t WS2812FX::chase(uint32_t color1, uint32_t color2, uint32_t color3) {
uint8_t size = 1 << SIZE_OPTION;
for(uint8_t i=0; icounter_mode_step + i) % _seg_len;
+ uint16_t b = (a + size) % _seg_len;
+ uint16_t c = (b + size) % _seg_len;
if(IS_REVERSE) {
- setPixelColor(SEGMENT.stop - a, color1);
- setPixelColor(SEGMENT.stop - b, color2);
- setPixelColor(SEGMENT.stop - c, color3);
+ setPixelColor(_seg->stop - a, color1);
+ setPixelColor(_seg->stop - b, color2);
+ setPixelColor(_seg->stop - c, color3);
} else {
- setPixelColor(SEGMENT.start + a, color1);
- setPixelColor(SEGMENT.start + b, color2);
- setPixelColor(SEGMENT.start + c, color3);
+ setPixelColor(_seg->start + a, color1);
+ setPixelColor(_seg->start + b, color2);
+ setPixelColor(_seg->start + c, color3);
}
}
- if(SEGMENT_RUNTIME.counter_mode_step + (size * 3) == SEGMENT_LENGTH) SET_CYCLE;
- else CLR_CYCLE;
+ if(_seg_rt->counter_mode_step + (size * 3) == _seg_len) SET_CYCLE;
- SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH;
- return (SEGMENT.speed / SEGMENT_LENGTH);
+ _seg_rt->counter_mode_step = (_seg_rt->counter_mode_step + 1) % _seg_len;
+ return (_seg->speed / _seg_len);
}
@@ -1130,7 +1229,7 @@ uint16_t WS2812FX::chase(uint32_t color1, uint32_t color2, uint32_t color3) {
* Bicolor chase mode
*/
uint16_t WS2812FX::mode_bicolor_chase(void) {
- return chase(SEGMENT.colors[0], SEGMENT.colors[1], SEGMENT.colors[2]);
+ return chase(_seg->colors[0], _seg->colors[1], _seg->colors[2]);
}
@@ -1138,7 +1237,7 @@ uint16_t WS2812FX::mode_bicolor_chase(void) {
* White running on _color.
*/
uint16_t WS2812FX::mode_chase_color(void) {
- return chase(SEGMENT.colors[0], WHITE, WHITE);
+ return chase(_seg->colors[0], WHITE, WHITE);
}
@@ -1146,7 +1245,7 @@ uint16_t WS2812FX::mode_chase_color(void) {
* Black running on _color.
*/
uint16_t WS2812FX::mode_chase_blackout(void) {
- return chase(SEGMENT.colors[0], BLACK, BLACK);
+ return chase(_seg->colors[0], BLACK, BLACK);
}
@@ -1154,7 +1253,7 @@ uint16_t WS2812FX::mode_chase_blackout(void) {
* _color running on white.
*/
uint16_t WS2812FX::mode_chase_white(void) {
- return chase(WHITE, SEGMENT.colors[0], SEGMENT.colors[0]);
+ return chase(WHITE, _seg->colors[0], _seg->colors[0]);
}
@@ -1162,10 +1261,10 @@ uint16_t WS2812FX::mode_chase_white(void) {
* White running followed by random color.
*/
uint16_t WS2812FX::mode_chase_random(void) {
- if(SEGMENT_RUNTIME.counter_mode_step == 0) {
- SEGMENT_RUNTIME.aux_param = get_random_wheel_index(SEGMENT_RUNTIME.aux_param);
+ if(_seg_rt->counter_mode_step == 0) {
+ _seg_rt->aux_param = get_random_wheel_index(_seg_rt->aux_param);
}
- return chase(color_wheel(SEGMENT_RUNTIME.aux_param), WHITE, WHITE);
+ return chase(color_wheel(_seg_rt->aux_param), WHITE, WHITE);
}
@@ -1173,10 +1272,10 @@ uint16_t WS2812FX::mode_chase_random(void) {
* Rainbow running on white.
*/
uint16_t WS2812FX::mode_chase_rainbow_white(void) {
- uint16_t n = SEGMENT_RUNTIME.counter_mode_step;
- uint16_t m = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH;
- uint32_t color2 = color_wheel(((n * 256 / SEGMENT_LENGTH) + (SEGMENT_RUNTIME.counter_mode_call & 0xFF)) & 0xFF);
- uint32_t color3 = color_wheel(((m * 256 / SEGMENT_LENGTH) + (SEGMENT_RUNTIME.counter_mode_call & 0xFF)) & 0xFF);
+ uint16_t n = _seg_rt->counter_mode_step;
+ uint16_t m = (_seg_rt->counter_mode_step + 1) % _seg_len;
+ uint32_t color2 = color_wheel(((n * 256 / _seg_len) + (_seg_rt->counter_mode_call & 0xFF)) & 0xFF);
+ uint32_t color3 = color_wheel(((m * 256 / _seg_len) + (_seg_rt->counter_mode_call & 0xFF)) & 0xFF);
return chase(WHITE, color2, color3);
}
@@ -1186,9 +1285,9 @@ uint16_t WS2812FX::mode_chase_rainbow_white(void) {
* White running on rainbow.
*/
uint16_t WS2812FX::mode_chase_rainbow(void) {
- uint8_t color_sep = 256 / SEGMENT_LENGTH;
- uint8_t color_index = SEGMENT_RUNTIME.counter_mode_call & 0xFF;
- uint32_t color = color_wheel(((SEGMENT_RUNTIME.counter_mode_step * color_sep) + color_index) & 0xFF);
+ uint8_t color_sep = 256 / _seg_len;
+ uint8_t color_index = _seg_rt->counter_mode_call & 0xFF;
+ uint32_t color = color_wheel(((_seg_rt->counter_mode_step * color_sep) + color_index) & 0xFF);
return chase(color, WHITE, WHITE);
}
@@ -1198,45 +1297,50 @@ uint16_t WS2812FX::mode_chase_rainbow(void) {
* Black running on rainbow.
*/
uint16_t WS2812FX::mode_chase_blackout_rainbow(void) {
- uint8_t color_sep = 256 / SEGMENT_LENGTH;
- uint8_t color_index = SEGMENT_RUNTIME.counter_mode_call & 0xFF;
- uint32_t color = color_wheel(((SEGMENT_RUNTIME.counter_mode_step * color_sep) + color_index) & 0xFF);
+ uint8_t color_sep = 256 / _seg_len;
+ uint8_t color_index = _seg_rt->counter_mode_call & 0xFF;
+ uint32_t color = color_wheel(((_seg_rt->counter_mode_step * color_sep) + color_index) & 0xFF);
return chase(color, BLACK, BLACK);
}
-
/*
- * White flashes running on _color.
+ * running white flashes function.
+ * color1 = background color
+ * color2 = flash color
*/
-uint16_t WS2812FX::mode_chase_flash(void) {
+uint16_t WS2812FX::chase_flash(uint32_t color1, uint32_t color2) {
const static uint8_t flash_count = 4;
- uint8_t flash_step = SEGMENT_RUNTIME.counter_mode_call % ((flash_count * 2) + 1);
-
- for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) {
- setPixelColor(i, SEGMENT.colors[0]);
- }
+ uint8_t flash_step = _seg_rt->counter_mode_call % ((flash_count * 2) + 1);
- uint16_t delay = (SEGMENT.speed / SEGMENT_LENGTH);
if(flash_step < (flash_count * 2)) {
- if(flash_step % 2 == 0) {
- uint16_t n = SEGMENT_RUNTIME.counter_mode_step;
- uint16_t m = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH;
- if(IS_REVERSE) {
- setPixelColor(SEGMENT.stop - n, WHITE);
- setPixelColor(SEGMENT.stop - m, WHITE);
- } else {
- setPixelColor(SEGMENT.start + n, WHITE);
- setPixelColor(SEGMENT.start + m, WHITE);
- }
- delay = 20;
+ uint32_t color = (flash_step % 2 == 0) ? color2 : color1;
+ uint16_t n = _seg_rt->counter_mode_step;
+ uint16_t m = (_seg_rt->counter_mode_step + 1) % _seg_len;
+ if(IS_REVERSE) {
+ setPixelColor(_seg->stop - n, color);
+ setPixelColor(_seg->stop - m, color);
} else {
- delay = 30;
+ setPixelColor(_seg->start + n, color);
+ setPixelColor(_seg->start + m, color);
}
+ return 30;
} else {
- SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH;
+ _seg_rt->counter_mode_step = (_seg_rt->counter_mode_step + 1) % _seg_len;
+ if(_seg_rt->counter_mode_step == 0) {
+ // update aux_param so mode_chase_flash_random() will select the next color
+ _seg_rt->aux_param = get_random_wheel_index(_seg_rt->aux_param);
+ SET_CYCLE;
+ }
}
- return delay;
+ return (_seg->speed / _seg_len);
+}
+
+/*
+ * White flashes running on _color.
+ */
+uint16_t WS2812FX::mode_chase_flash(void) {
+ return chase_flash(_seg->colors[0], WHITE);
}
@@ -1244,34 +1348,7 @@ uint16_t WS2812FX::mode_chase_flash(void) {
* White flashes running, followed by random color.
*/
uint16_t WS2812FX::mode_chase_flash_random(void) {
- const static uint8_t flash_count = 4;
- uint8_t flash_step = SEGMENT_RUNTIME.counter_mode_call % ((flash_count * 2) + 1);
-
- for(uint16_t i=0; i < SEGMENT_RUNTIME.counter_mode_step; i++) {
- setPixelColor(SEGMENT.start + i, color_wheel(SEGMENT_RUNTIME.aux_param));
- }
-
- uint16_t delay = (SEGMENT.speed / SEGMENT_LENGTH);
- if(flash_step < (flash_count * 2)) {
- uint16_t n = SEGMENT_RUNTIME.counter_mode_step;
- uint16_t m = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH;
- if(flash_step % 2 == 0) {
- setPixelColor(SEGMENT.start + n, WHITE);
- setPixelColor(SEGMENT.start + m, WHITE);
- delay = 20;
- } else {
- setPixelColor(SEGMENT.start + n, color_wheel(SEGMENT_RUNTIME.aux_param));
- setPixelColor(SEGMENT.start + m, BLACK);
- delay = 30;
- }
- } else {
- SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH;
-
- if(SEGMENT_RUNTIME.counter_mode_step == 0) {
- SEGMENT_RUNTIME.aux_param = get_random_wheel_index(SEGMENT_RUNTIME.aux_param);
- }
- }
- return delay;
+ return chase_flash(color_wheel(_seg_rt->aux_param), WHITE);
}
@@ -1279,32 +1356,28 @@ uint16_t WS2812FX::mode_chase_flash_random(void) {
* Alternating pixels running function.
*/
uint16_t WS2812FX::running(uint32_t color1, uint32_t color2) {
- uint8_t size = 4 << SIZE_OPTION;
- for(uint16_t i=0; i < SEGMENT_LENGTH; i++) {
- if((i + SEGMENT_RUNTIME.counter_mode_step) % size < (size / 2)) {
- if(IS_REVERSE) {
- setPixelColor(SEGMENT.start + i, color1);
- } else {
- setPixelColor(SEGMENT.stop - i, color1);
- }
- } else {
- if(IS_REVERSE) {
- setPixelColor(SEGMENT.start + i, color2);
- } else {
- setPixelColor(SEGMENT.stop - i, color2);
- }
- }
+ uint8_t size = 2 << SIZE_OPTION;
+ uint32_t color = (_seg_rt->counter_mode_step & size) ? color1 : color2;
+
+ if(IS_REVERSE) {
+ copyPixels(_seg->start, _seg->start + 1, _seg_len - 1);
+ setPixelColor(_seg->stop, color);
+ } else {
+ copyPixels(_seg->start + 1, _seg->start, _seg_len - 1);
+ setPixelColor(_seg->start, color);
}
- SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % size;
- return (SEGMENT.speed / SEGMENT_LENGTH);
+ _seg_rt->counter_mode_step = (_seg_rt->counter_mode_step + 1) % _seg_len;
+ if(_seg_rt->counter_mode_step == 0) SET_CYCLE;
+ return (_seg->speed / _seg_len);
}
+
/*
* Alternating color/white pixels running.
*/
uint16_t WS2812FX::mode_running_color(void) {
- return running(SEGMENT.colors[0], WHITE);
+ return running(_seg->colors[0], WHITE);
}
@@ -1335,23 +1408,14 @@ uint16_t WS2812FX::mode_halloween(void) {
* Random colored pixels running.
*/
uint16_t WS2812FX::mode_running_random(void) {
- if(IS_REVERSE) {
- copyPixels(SEGMENT.start, SEGMENT.start + 1, SEGMENT_LENGTH - 1);
- } else {
- copyPixels(SEGMENT.start + 1, SEGMENT.start, SEGMENT_LENGTH - 1);
+ uint8_t size = 2 << SIZE_OPTION;
+ if((_seg_rt->counter_mode_step) % size == 0) {
+ _seg_rt->aux_param = get_random_wheel_index(_seg_rt->aux_param);
}
- if(SEGMENT_RUNTIME.counter_mode_step == 0) {
- SEGMENT_RUNTIME.aux_param = get_random_wheel_index(SEGMENT_RUNTIME.aux_param);
- if(IS_REVERSE) {
- setPixelColor(SEGMENT.stop, color_wheel(SEGMENT_RUNTIME.aux_param));
- } else {
- setPixelColor(SEGMENT.start, color_wheel(SEGMENT_RUNTIME.aux_param));
- }
- }
+ uint32_t color = color_wheel(_seg_rt->aux_param);
- SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % (2 << SIZE_OPTION);
- return (SEGMENT.speed / SEGMENT_LENGTH);
+ return running(color, color);
}
@@ -1361,30 +1425,28 @@ uint16_t WS2812FX::mode_running_random(void) {
uint16_t WS2812FX::mode_larson_scanner(void) {
fade_out();
- if(SEGMENT_RUNTIME.counter_mode_step < SEGMENT_LENGTH) {
+ if(_seg_rt->counter_mode_step < _seg_len) {
if(IS_REVERSE) {
- setPixelColor(SEGMENT.stop - SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]);
+ setPixelColor(_seg->stop - _seg_rt->counter_mode_step, _seg->colors[0]);
} else {
- setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]);
+ setPixelColor(_seg->start + _seg_rt->counter_mode_step, _seg->colors[0]);
}
} else {
- uint16_t index = (SEGMENT_LENGTH * 2) - SEGMENT_RUNTIME.counter_mode_step - 2;
+ uint16_t index = (_seg_len * 2) - _seg_rt->counter_mode_step - 2;
if(IS_REVERSE) {
- setPixelColor(SEGMENT.stop - index, SEGMENT.colors[0]);
+ setPixelColor(_seg->stop - index, _seg->colors[0]);
} else {
- setPixelColor(SEGMENT.start + index, SEGMENT.colors[0]);
+ setPixelColor(_seg->start + index, _seg->colors[0]);
}
}
- if(SEGMENT_RUNTIME.counter_mode_step % SEGMENT_LENGTH == 0) SET_CYCLE;
- else CLR_CYCLE;
-
- SEGMENT_RUNTIME.counter_mode_step++;
- if(SEGMENT_RUNTIME.counter_mode_step >= (uint16_t)((SEGMENT_LENGTH * 2) - 2)) {
- SEGMENT_RUNTIME.counter_mode_step = 0;
+ _seg_rt->counter_mode_step++;
+ if(_seg_rt->counter_mode_step >= (uint16_t)((_seg_len * 2) - 2)) {
+ _seg_rt->counter_mode_step = 0;
+ SET_CYCLE;
}
- return (SEGMENT.speed / (SEGMENT_LENGTH * 2));
+ return (_seg->speed / (_seg_len * 2));
}
@@ -1395,13 +1457,15 @@ uint16_t WS2812FX::mode_comet(void) {
fade_out();
if(IS_REVERSE) {
- setPixelColor(SEGMENT.stop - SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]);
+ setPixelColor(_seg->stop - _seg_rt->counter_mode_step, _seg->colors[0]);
} else {
- setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]);
+ setPixelColor(_seg->start + _seg_rt->counter_mode_step, _seg->colors[0]);
}
- SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH;
- return (SEGMENT.speed / SEGMENT_LENGTH);
+ _seg_rt->counter_mode_step = (_seg_rt->counter_mode_step + 1) % _seg_len;
+ if(_seg_rt->counter_mode_step == 0) SET_CYCLE;
+
+ return (_seg->speed / _seg_len);
}
@@ -1414,8 +1478,8 @@ uint16_t WS2812FX::fireworks(uint32_t color) {
// for better performance, manipulate the Adafruit_NeoPixels pixels[] array directly
uint8_t *pixels = getPixels();
uint8_t bytesPerPixel = getNumBytesPerPixel(); // 3=RGB, 4=RGBW
- uint16_t startPixel = SEGMENT.start * bytesPerPixel + bytesPerPixel;
- uint16_t stopPixel = SEGMENT.stop * bytesPerPixel ;
+ uint16_t startPixel = _seg->start * bytesPerPixel + bytesPerPixel;
+ uint16_t stopPixel = _seg->stop * bytesPerPixel ;
for(uint16_t i=startPixel; i > 2) +
pixels[i] +
@@ -1425,23 +1489,22 @@ uint16_t WS2812FX::fireworks(uint32_t color) {
uint8_t size = 2 << SIZE_OPTION;
if(!_triggered) {
- for(uint16_t i=0; istart + random16(_seg_len - size);
+ fill(color, index, size);
+ SET_CYCLE;
}
}
} else {
- for(uint16_t i=0; istart + random16(_seg_len - size);
+ fill(color, index, size);
+ SET_CYCLE;
}
}
- return (SEGMENT.speed / SEGMENT_LENGTH);
+
+ return (_seg->speed / _seg_len);
}
/*
@@ -1450,7 +1513,7 @@ uint16_t WS2812FX::fireworks(uint32_t color) {
uint16_t WS2812FX::mode_fireworks(void) {
uint32_t color = BLACK;
do { // randomly choose a non-BLACK color from the colors array
- color = SEGMENT.colors[random8(NUM_COLORS)];
+ color = _seg->colors[random8(MAX_NUM_COLORS)];
} while (color == BLACK);
return fireworks(color);
}
@@ -1467,16 +1530,18 @@ uint16_t WS2812FX::mode_fireworks_random(void) {
* Fire flicker function
*/
uint16_t WS2812FX::fire_flicker(int rev_intensity) {
- byte w = (SEGMENT.colors[0] >> 24) & 0xFF;
- byte r = (SEGMENT.colors[0] >> 16) & 0xFF;
- byte g = (SEGMENT.colors[0] >> 8) & 0xFF;
- byte b = (SEGMENT.colors[0] & 0xFF);
+ byte w = (_seg->colors[0] >> 24) & 0xFF;
+ byte r = (_seg->colors[0] >> 16) & 0xFF;
+ byte g = (_seg->colors[0] >> 8) & 0xFF;
+ byte b = (_seg->colors[0] & 0xFF);
byte lum = max(w, max(r, max(g, b))) / rev_intensity;
- for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) {
+ for(uint16_t i=_seg->start; i <= _seg->stop; i++) {
int flicker = random8(lum);
setPixelColor(i, max(r - flicker, 0), max(g - flicker, 0), max(b - flicker, 0), max(w - flicker, 0));
}
- return (SEGMENT.speed / SEGMENT_LENGTH);
+
+ SET_CYCLE;
+ return (_seg->speed / _seg_len);
}
/*
@@ -1497,84 +1562,46 @@ uint16_t WS2812FX::mode_fire_flicker_soft(void) {
* Random flickering, more intensity.
*/
uint16_t WS2812FX::mode_fire_flicker_intense(void) {
- return fire_flicker(1.7);
+ return fire_flicker(1);
}
-/*
- * Tricolor chase function
- */
-uint16_t WS2812FX::tricolor_chase(uint32_t color1, uint32_t color2, uint32_t color3) {
- uint8_t sizeCnt = 1 << SIZE_OPTION;
- uint16_t index = SEGMENT_RUNTIME.counter_mode_call % (sizeCnt * 3);
- for(uint16_t i=0; i < SEGMENT_LENGTH; i++, index++) {
- index = index % (sizeCnt * 3);
-
- uint32_t color = color3;
- if(index < sizeCnt) color = color1;
- else if(index < (sizeCnt * 2)) color = color2;
-
- if(IS_REVERSE) {
- setPixelColor(SEGMENT.start + i, color);
- } else {
- setPixelColor(SEGMENT.stop - i, color);
- }
- }
-
- return (SEGMENT.speed / SEGMENT_LENGTH);
-}
-
-
-/*
- * Tricolor chase mode
- */
-uint16_t WS2812FX::mode_tricolor_chase(void) {
- return tricolor_chase(SEGMENT.colors[0], SEGMENT.colors[1], SEGMENT.colors[2]);
-}
-
-
-/*
- * Alternating white/red/black pixels running.
- */
-uint16_t WS2812FX::mode_circus_combustus(void) {
- return tricolor_chase(RED, WHITE, BLACK);
-}
-
/*
* ICU mode
*/
-uint16_t WS2812FX::mode_icu(void) {
- uint16_t dest = SEGMENT_RUNTIME.counter_mode_step & 0xFFFF;
+// uint16_t WS2812FX::mode_icu(void) {
+// uint16_t dest = _seg_rt->counter_mode_step & 0xFFFF;
- setPixelColor(SEGMENT.start + dest, SEGMENT.colors[0]);
- setPixelColor(SEGMENT.start + dest + SEGMENT_LENGTH/2, SEGMENT.colors[0]);
-
- if(SEGMENT_RUNTIME.aux_param3 == dest) { // pause between eye movements
- if(random8(6) == 0) { // blink once in a while
- setPixelColor(SEGMENT.start + dest, BLACK);
- setPixelColor(SEGMENT.start + dest + SEGMENT_LENGTH/2, BLACK);
- return 200;
- }
- SEGMENT_RUNTIME.aux_param3 = random16(SEGMENT_LENGTH/2);
- return 1000 + random16(2000);
- }
-
- setPixelColor(SEGMENT.start + dest, BLACK);
- setPixelColor(SEGMENT.start + dest + SEGMENT_LENGTH/2, BLACK);
-
- if(SEGMENT_RUNTIME.aux_param3 > SEGMENT_RUNTIME.counter_mode_step) {
- SEGMENT_RUNTIME.counter_mode_step++;
- dest++;
- } else if (SEGMENT_RUNTIME.aux_param3 < SEGMENT_RUNTIME.counter_mode_step) {
- SEGMENT_RUNTIME.counter_mode_step--;
- dest--;
- }
-
- setPixelColor(SEGMENT.start + dest, SEGMENT.colors[0]);
- setPixelColor(SEGMENT.start + dest + SEGMENT_LENGTH/2, SEGMENT.colors[0]);
-
- return (SEGMENT.speed / SEGMENT_LENGTH);
-}
+// setPixelColor(_seg->start + dest, _seg->colors[0]);
+// setPixelColor(_seg->start + dest + _seg_len/2, _seg->colors[0]);
+
+// if(_seg_rt->aux_param3 == dest) { // pause between eye movements
+// if(random8(6) == 0) { // blink once in a while
+// setPixelColor(_seg->start + dest, BLACK);
+// setPixelColor(_seg->start + dest + _seg_len/2, BLACK);
+// return 200;
+// }
+// _seg_rt->aux_param3 = random16(_seg_len/2);
+// SET_CYCLE;
+// return 1000 + random16(2000);
+// }
+
+// setPixelColor(_seg->start + dest, BLACK);
+// setPixelColor(_seg->start + dest + _seg_len/2, BLACK);
+
+// if(_seg_rt->aux_param3 > _seg_rt->counter_mode_step) {
+// _seg_rt->counter_mode_step++;
+// dest++;
+// } else if (_seg_rt->aux_param3 < _seg_rt->counter_mode_step) {
+// _seg_rt->counter_mode_step--;
+// dest--;
+// }
+
+// setPixelColor(_seg->start + dest, _seg->colors[0]);
+// setPixelColor(_seg->start + dest + _seg_len/2, _seg->colors[0]);
+
+// return (_seg->speed / _seg_len);
+// }
/*
* Custom modes
@@ -1591,6 +1618,18 @@ uint16_t WS2812FX::mode_custom_2() {
uint16_t WS2812FX::mode_custom_3() {
return customModes[3]();
}
+uint16_t WS2812FX::mode_custom_4() {
+ return customModes[4]();
+}
+uint16_t WS2812FX::mode_custom_5() {
+ return customModes[5]();
+}
+uint16_t WS2812FX::mode_custom_6() {
+ return customModes[6]();
+}
+uint16_t WS2812FX::mode_custom_7() {
+ return customModes[7]();
+}
/*
* Custom mode helpers
diff --git a/src/WS2812FX.h b/src/WS2812FX.h
index c3b8ea0..d028a2c 100644
--- a/src/WS2812FX.h
+++ b/src/WS2812FX.h
@@ -45,6 +45,8 @@
#define DEFAULT_MODE (uint8_t)0
#define DEFAULT_SPEED (uint16_t)1000
#define DEFAULT_COLOR (uint32_t)0xFF0000
+#define DEFAULT_COLORS { RED, GREEN, BLUE }
+#define COLORS(...) (const uint32_t[]){__VA_ARGS__}
#if defined(ESP8266) || defined(ESP32)
//#pragma message("Compiling for ESP")
@@ -58,14 +60,13 @@
#define BRIGHTNESS_MIN (uint8_t)0
#define BRIGHTNESS_MAX (uint8_t)255
-/* each segment uses 36 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
-#define NUM_COLORS 3 /* number of colors per segment */
-#define MAX_CUSTOM_MODES 4
-#define SEGMENT _segments[_segment_index]
-#define SEGMENT_RUNTIME _segment_runtimes[_segment_index]
-#define SEGMENT_LENGTH (uint16_t)(SEGMENT.stop - SEGMENT.start + 1)
+/* each segment uses 36 bytes of SRAM memory, so if you're compile fails
+ because of insufficient flash memory, decreasing MAX_NUM_SEGMENTS may help */
+#define MAX_NUM_SEGMENTS 10
+#define MAX_NUM_ACTIVE_SEGMENTS 10
+#define INACTIVE_SEGMENT 255 /* max uint_8 */
+#define MAX_NUM_COLORS 3 /* number of colors per segment */
+#define MAX_CUSTOM_MODES 8
// some common colors
#define RED (uint32_t)0xFF0000
@@ -79,8 +80,11 @@
#define PURPLE (uint32_t)0x400080
#define ORANGE (uint32_t)0xFF3000
#define PINK (uint32_t)0xFF1493
+#define GRAY (uint32_t)0x101010
#define ULTRAWHITE (uint32_t)0xFFFFFFFF
-#define DARK(c) (uint32_t)((c >> 4) & 0x0f0f0f0f)
+#define DIM(c) (uint32_t)((c >> 2) & 0x3f3f3f3f) // color at 25% intensity
+#define DARK(c) (uint32_t)((c >> 4) & 0x0f0f0f0f) // color at 6% intensity
+
// segment options
// bit 7: reverse animation
@@ -90,7 +94,7 @@
// bits 0: TBD
#define NO_OPTIONS (uint8_t)B00000000
#define REVERSE (uint8_t)B10000000
-#define IS_REVERSE ((SEGMENT.options & REVERSE) == REVERSE)
+#define IS_REVERSE ((_seg->options & REVERSE) == REVERSE)
#define FADE_XFAST (uint8_t)B00010000
#define FADE_FAST (uint8_t)B00100000
#define FADE_MEDIUM (uint8_t)B00110000
@@ -98,22 +102,23 @@
#define FADE_XSLOW (uint8_t)B01010000
#define FADE_XXSLOW (uint8_t)B01100000
#define FADE_GLACIAL (uint8_t)B01110000
-#define FADE_RATE ((SEGMENT.options >> 4) & 7)
+#define FADE_RATE ((_seg->options >> 4) & 7)
#define GAMMA (uint8_t)B00001000
-#define IS_GAMMA ((SEGMENT.options & GAMMA) == GAMMA)
+#define IS_GAMMA ((_seg->options & GAMMA) == GAMMA)
#define SIZE_SMALL (uint8_t)B00000000
#define SIZE_MEDIUM (uint8_t)B00000010
#define SIZE_LARGE (uint8_t)B00000100
#define SIZE_XLARGE (uint8_t)B00000110
-#define SIZE_OPTION ((SEGMENT.options >> 1) & 3)
+#define SIZE_OPTION ((_seg->options >> 1) & 3)
// segment runtime options (aux_param2)
-#define FRAME (uint8_t)B10000000
-#define SET_FRAME (SEGMENT_RUNTIME.aux_param2 |= FRAME)
-#define CLR_FRAME (SEGMENT_RUNTIME.aux_param2 &= ~FRAME)
-#define CYCLE (uint8_t)B01000000
-#define SET_CYCLE (SEGMENT_RUNTIME.aux_param2 |= CYCLE)
-#define CLR_CYCLE (SEGMENT_RUNTIME.aux_param2 &= ~CYCLE)
+#define FRAME (uint8_t)B10000000
+#define SET_FRAME (_seg_rt->aux_param2 |= FRAME)
+#define CLR_FRAME (_seg_rt->aux_param2 &= ~FRAME)
+#define CYCLE (uint8_t)B01000000
+#define SET_CYCLE (_seg_rt->aux_param2 |= CYCLE)
+#define CLR_CYCLE (_seg_rt->aux_param2 &= ~CYCLE)
+#define CLR_FRAME_CYCLE (_seg_rt->aux_param2 &= ~(FRAME | CYCLE))
#define MODE_COUNT (sizeof(_names)/sizeof(_names[0]))
@@ -172,15 +177,19 @@
#define FX_MODE_HALLOWEEN 52
#define FX_MODE_BICOLOR_CHASE 53
#define FX_MODE_TRICOLOR_CHASE 54
-#define FX_MODE_ICU 55
-#define FX_MODE_CUSTOM 56 // keep this for backward compatiblity
-#define FX_MODE_CUSTOM_0 56 // custom modes need to go at the end
-#define FX_MODE_CUSTOM_1 57
-#define FX_MODE_CUSTOM_2 58
-#define FX_MODE_CUSTOM_3 59
-
-// create GLOBAL names to allow WS2812FX to compile with sketches and other libs that store strings
-// in PROGMEM (get rid of the "section type conflict with __c" errors once and for all. Amen.)
+#define FX_MODE_CUSTOM 55 // keep this for backward compatiblity
+#define FX_MODE_CUSTOM_0 55 // custom modes need to go at the end
+#define FX_MODE_CUSTOM_1 56
+#define FX_MODE_CUSTOM_2 57
+#define FX_MODE_CUSTOM_3 58
+#define FX_MODE_CUSTOM_4 59
+#define FX_MODE_CUSTOM_5 60
+#define FX_MODE_CUSTOM_6 61
+#define FX_MODE_CUSTOM_7 62
+
+// create GLOBAL names to allow WS2812FX to compile with sketches and other libs
+// that store strings in PROGMEM (get rid of the "section type conflict with __c"
+// errors once and for all. Amen.)
const char name_0[] PROGMEM = "Static";
const char name_1[] PROGMEM = "Blink";
const char name_2[] PROGMEM = "Breath";
@@ -236,11 +245,14 @@ const char name_51[] PROGMEM = "Circus Combustus";
const char name_52[] PROGMEM = "Halloween";
const char name_53[] PROGMEM = "Bicolor Chase";
const char name_54[] PROGMEM = "Tricolor Chase";
-const char name_55[] PROGMEM = "ICU";
-const char name_56[] PROGMEM = "Custom 0"; // custom modes need to go at the end
-const char name_57[] PROGMEM = "Custom 1";
-const char name_58[] PROGMEM = "Custom 2";
-const char name_59[] PROGMEM = "Custom 3";
+const char name_55[] PROGMEM = "Custom 0"; // custom modes need to go at the end
+const char name_56[] PROGMEM = "Custom 1";
+const char name_57[] PROGMEM = "Custom 2";
+const char name_58[] PROGMEM = "Custom 3";
+const char name_59[] PROGMEM = "Custom 4";
+const char name_60[] PROGMEM = "Custom 5";
+const char name_61[] PROGMEM = "Custom 6";
+const char name_62[] PROGMEM = "Custom 7";
static const __FlashStringHelper* _names[] = {
FSH(name_0),
@@ -302,25 +314,28 @@ static const __FlashStringHelper* _names[] = {
FSH(name_56),
FSH(name_57),
FSH(name_58),
- FSH(name_59)
+ FSH(name_59),
+ FSH(name_60),
+ FSH(name_61),
+ FSH(name_62)
};
class WS2812FX : public Adafruit_NeoPixel {
- typedef uint16_t (WS2812FX::*mode_ptr)(void);
-
- // segment parameters
+typedef uint16_t (WS2812FX::*mode_ptr)(void);
+
public:
+ // segment parameters
typedef struct Segment { // 20 bytes
uint16_t start;
uint16_t stop;
uint16_t speed;
uint8_t mode;
uint8_t options;
- uint32_t colors[NUM_COLORS];
+ uint32_t colors[MAX_NUM_COLORS];
} segment;
- // segment runtime parameters
+ // segment runtime parameters
typedef struct Segment_runtime { // 16 bytes
unsigned long next_time;
uint32_t counter_mode_step;
@@ -330,7 +345,10 @@ class WS2812FX : public Adafruit_NeoPixel {
uint16_t aux_param3; // auxilary param (usually stores a segment index)
} segment_runtime;
- WS2812FX(uint16_t n, uint8_t p, neoPixelType t) : Adafruit_NeoPixel(n, p, t) {
+ WS2812FX(uint16_t num_leds, uint8_t pin, neoPixelType type,
+ uint8_t max_num_segments=MAX_NUM_SEGMENTS,
+ uint8_t max_num_active_segments=MAX_NUM_ACTIVE_SEGMENTS)
+ : Adafruit_NeoPixel(num_leds, pin, type) {
_mode[FX_MODE_STATIC] = &WS2812FX::mode_static;
_mode[FX_MODE_BLINK] = &WS2812FX::mode_blink;
_mode[FX_MODE_COLOR_WIPE] = &WS2812FX::mode_color_wipe;
@@ -384,31 +402,30 @@ class WS2812FX : public Adafruit_NeoPixel {
_mode[FX_MODE_HALLOWEEN] = &WS2812FX::mode_halloween;
_mode[FX_MODE_BICOLOR_CHASE] = &WS2812FX::mode_bicolor_chase;
_mode[FX_MODE_TRICOLOR_CHASE] = &WS2812FX::mode_tricolor_chase;
-// if flash memory is constrained (I'm looking at you Arduino Nano), replace modes
-// that use a lot of flash with mode_static (reduces flash footprint by about 2100 bytes)
-#ifdef REDUCED_MODES
- _mode[FX_MODE_BREATH] = &WS2812FX::mode_static;
- _mode[FX_MODE_RUNNING_LIGHTS] = &WS2812FX::mode_static;
- _mode[FX_MODE_ICU] = &WS2812FX::mode_static;
-#else
_mode[FX_MODE_BREATH] = &WS2812FX::mode_breath;
_mode[FX_MODE_RUNNING_LIGHTS] = &WS2812FX::mode_running_lights;
- _mode[FX_MODE_ICU] = &WS2812FX::mode_icu;
-#endif
_mode[FX_MODE_CUSTOM_0] = &WS2812FX::mode_custom_0;
_mode[FX_MODE_CUSTOM_1] = &WS2812FX::mode_custom_1;
_mode[FX_MODE_CUSTOM_2] = &WS2812FX::mode_custom_2;
_mode[FX_MODE_CUSTOM_3] = &WS2812FX::mode_custom_3;
+ _mode[FX_MODE_CUSTOM_4] = &WS2812FX::mode_custom_4;
+ _mode[FX_MODE_CUSTOM_5] = &WS2812FX::mode_custom_5;
+ _mode[FX_MODE_CUSTOM_6] = &WS2812FX::mode_custom_6;
+ _mode[FX_MODE_CUSTOM_7] = &WS2812FX::mode_custom_7;
brightness = DEFAULT_BRIGHTNESS + 1; // Adafruit_NeoPixel internally offsets brightness by 1
_running = false;
- _num_segments = 1;
- _segments[0].mode = DEFAULT_MODE;
- _segments[0].colors[0] = DEFAULT_COLOR;
- _segments[0].start = 0;
- _segments[0].stop = n - 1;
- _segments[0].speed = DEFAULT_SPEED;
- resetSegmentRuntimes();
+
+ _segments_len = max_num_segments;
+ _active_segments_len = max_num_active_segments;
+
+ // create all the segment arrays and init to zeros
+ _segments = new segment[_segments_len]();
+ _active_segments = new uint8_t[_active_segments_len]();
+ _segment_runtimes = new segment_runtime[_active_segments_len]();
+
+ resetSegments();
+ setSegment(0, 0, num_leds - 1, DEFAULT_MODE, DEFAULT_COLOR, DEFAULT_SPEED, NO_OPTIONS);
}
void
@@ -443,18 +460,25 @@ class WS2812FX : public Adafruit_NeoPixel {
increaseLength(uint16_t s),
decreaseLength(uint16_t s),
trigger(void),
+ setCycle(void),
setNumSegments(uint8_t n),
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t color, uint16_t speed, bool reverse),
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t color, uint16_t speed, uint8_t options),
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, const uint32_t colors[], uint16_t speed, bool reverse),
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, const uint32_t colors[], uint16_t speed, uint8_t options),
- resetSegments(),
- resetSegmentRuntimes(),
+ setIdleSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t color, uint16_t speed, uint8_t options),
+ setIdleSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, const uint32_t colors[], uint16_t speed, uint8_t options),
+ addActiveSegment(uint8_t seg),
+ removeActiveSegment(uint8_t seg),
+ swapActiveSegment(uint8_t oldSeg, uint8_t newSeg),
+ resetSegments(void),
+ resetSegmentRuntimes(void),
resetSegmentRuntime(uint8_t),
setPixelColor(uint16_t n, uint32_t c),
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b),
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w),
copyPixels(uint16_t d, uint16_t s, uint16_t c),
+ setPixels(uint16_t, uint8_t*),
show(void);
boolean
@@ -463,7 +487,8 @@ class WS2812FX : public Adafruit_NeoPixel {
isFrame(void),
isFrame(uint8_t),
isCycle(void),
- isCycle(uint8_t);
+ isCycle(uint8_t),
+ isActiveSegment(uint8_t seg);
uint8_t
random8(void),
@@ -494,6 +519,7 @@ class WS2812FX : public Adafruit_NeoPixel {
uint32_t* getColors(uint8_t);
uint32_t* intensitySums(void);
+ uint8_t* getActiveSegments(void);
const __FlashStringHelper* getModeName(uint8_t m);
@@ -515,12 +541,15 @@ class WS2812FX : public Adafruit_NeoPixel {
color_wipe(uint32_t, uint32_t, bool),
twinkle(uint32_t, uint32_t),
twinkle_fade(uint32_t),
+ sparkle(uint32_t, uint32_t),
chase(uint32_t, uint32_t, uint32_t),
+ chase_flash(uint32_t, uint32_t),
running(uint32_t, uint32_t),
fireworks(uint32_t),
fire_flicker(int),
tricolor_chase(uint32_t, uint32_t, uint32_t),
scan(uint32_t, uint32_t, bool);
+
uint32_t
color_blend(uint32_t, uint32_t, uint8_t);
@@ -581,15 +610,22 @@ class WS2812FX : public Adafruit_NeoPixel {
mode_circus_combustus(void),
mode_bicolor_chase(void),
mode_tricolor_chase(void),
- mode_icu(void),
mode_custom_0(void),
mode_custom_1(void),
mode_custom_2(void),
- mode_custom_3(void);
+ mode_custom_3(void),
+ mode_custom_4(void),
+ mode_custom_5(void),
+ mode_custom_6(void),
+ mode_custom_7(void);
private:
uint16_t _rand16seed;
uint16_t (*customModes[MAX_CUSTOM_MODES])(void) {
+ []{ return (uint16_t)1000; },
+ []{ return (uint16_t)1000; },
+ []{ return (uint16_t)1000; },
+ []{ return (uint16_t)1000; },
[]{ return (uint16_t)1000; },
[]{ return (uint16_t)1000; },
[]{ return (uint16_t)1000; },
@@ -601,15 +637,20 @@ class WS2812FX : public Adafruit_NeoPixel {
_running,
_triggered;
- mode_ptr _mode[MODE_COUNT]; // SRAM footprint: 4 bytes per element
+ mode_ptr _mode[MODE_COUNT]; // array of mode function pointers (4 bytes per element)
- uint8_t _segment_index = 0;
- uint8_t _num_segments = 1;
- segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 20 bytes per element
- // start, stop, speed, mode, options, color[]
- { 0, 7, DEFAULT_SPEED, FX_MODE_STATIC, NO_OPTIONS, {DEFAULT_COLOR}}
- };
- segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 16 bytes per element
+ segment* _segments; // array of segments (20 bytes per element)
+ segment_runtime* _segment_runtimes; // array of segment runtimes (16 bytes per element)
+ uint8_t* _active_segments; // array of active segments (1 bytes per element)
+
+ uint8_t _segments_len = 0; // size of _segments array
+ uint8_t _active_segments_len = 0; // size of _segments_runtime and _active_segments arrays
+ uint8_t _num_segments = 0; // number of configured segments in the _segments array
+
+ segment* _seg; // currently active segment (20 bytes)
+ segment_runtime* _seg_rt; // currently active segment runtime (16 bytes)
+
+ uint16_t _seg_len; // num LEDs in the currently active segment
};
#endif
diff --git a/src/custom/BlockDissolve.h b/src/custom/BlockDissolve.h
index 3efc9d0..e77724c 100644
--- a/src/custom/BlockDissolve.h
+++ b/src/custom/BlockDissolve.h
@@ -61,7 +61,8 @@ uint16_t blockDissolve(void) {
ws2812fx.setPixelColor(i, color);
}
- segrt->aux_param = (segrt->aux_param + 1) % NUM_COLORS;
+ segrt->aux_param = (segrt->aux_param + 1) % MAX_NUM_COLORS;
+ if(segrt->aux_param == 0) ws2812fx.setCycle();
return seg->speed;
}
diff --git a/src/custom/DualLarson.h b/src/custom/DualLarson.h
index dcceff6..5ef0942 100644
--- a/src/custom/DualLarson.h
+++ b/src/custom/DualLarson.h
@@ -59,6 +59,7 @@ uint16_t dualLarson(void) {
if(segrt->aux_param3 >= (seg->stop - seg->start) || segrt->aux_param3 <= 0) {
segrt->aux_param = !segrt->aux_param;
if(seg->options & REVERSE) offset = (offset + 1) % seglen;
+ if(!segrt->aux_param) ws2812fx.setCycle();
}
return (seg->speed / (seglen * 2));
diff --git a/src/custom/Fillerup.h b/src/custom/Fillerup.h
index 78613f7..2e48fc8 100644
--- a/src/custom/Fillerup.h
+++ b/src/custom/Fillerup.h
@@ -84,6 +84,7 @@ uint16_t fillerup(void) {
if(segrt->aux_param3 >= seglen) {
segrt->aux_param = !segrt->aux_param;
segrt->aux_param3 = 0;
+ ws2812fx.setCycle();
}
return (seg->speed / seglen);
diff --git a/src/custom/Heartbeat.h b/src/custom/Heartbeat.h
index 3caa79e..1f2f6c3 100644
--- a/src/custom/Heartbeat.h
+++ b/src/custom/Heartbeat.h
@@ -72,6 +72,7 @@ uint16_t heartbeat(void) {
beatIt(seg, size); // create the first beat
secondBeatActive = false;
lastBeat = millis();
+ ws2812fx.setCycle();
}
return(seg->speed / 32);
diff --git a/src/custom/ICU.h b/src/custom/ICU.h
new file mode 100644
index 0000000..d0c606b
--- /dev/null
+++ b/src/custom/ICU.h
@@ -0,0 +1,79 @@
+/*
+ Custom effect that mimics two eyes looking about
+
+ Keith Lord - 2018
+
+ LICENSE
+
+ The MIT License (MIT)
+
+ Copyright (c) 2018 Keith Lord
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ CHANGELOG
+ 2018-07-26 initial version
+*/
+
+#ifndef ICU_h
+#define ICU_h
+
+#include
+
+extern WS2812FX ws2812fx;
+
+uint16_t icu(void) {
+ WS2812FX::Segment* seg = ws2812fx.getSegment(); // get the current segment
+ WS2812FX::Segment_runtime* segrt = ws2812fx.getSegmentRuntime();
+ int seglen = seg->stop - seg->start + 1;
+
+ uint16_t dest = segrt->counter_mode_step & 0xFFFF;
+
+ ws2812fx.setPixelColor(seg->start + dest, seg->colors[0]);
+ ws2812fx.setPixelColor(seg->start + dest + seglen/2, seg->colors[0]);
+
+ if(segrt->aux_param3 == dest) { // pause between eye movements
+ if(ws2812fx.random8(6) == 0) { // blink once in a while
+ ws2812fx.setPixelColor(seg->start + dest, BLACK);
+ ws2812fx.setPixelColor(seg->start + dest + seglen/2, BLACK);
+ return 200;
+ }
+ segrt->aux_param3 = ws2812fx.random16(seglen/2);
+ ws2812fx.setCycle();
+ return 1000 + ws2812fx.random16(2000);
+ }
+
+ ws2812fx.setPixelColor(seg->start + dest, BLACK);
+ ws2812fx.setPixelColor(seg->start + dest + seglen/2, BLACK);
+
+ if(segrt->aux_param3 > segrt->counter_mode_step) {
+ segrt->counter_mode_step++;
+ dest++;
+ } else if (segrt->aux_param3 < segrt->counter_mode_step) {
+ segrt->counter_mode_step--;
+ dest--;
+ }
+
+ ws2812fx.setPixelColor(seg->start + dest, seg->colors[0]);
+ ws2812fx.setPixelColor(seg->start + dest + seglen/2, seg->colors[0]);
+
+ return (seg->speed / seglen);
+}
+
+#endif
diff --git a/src/custom/Matrix.h b/src/custom/Matrix.h
index b8063fb..70fece3 100644
--- a/src/custom/Matrix.h
+++ b/src/custom/Matrix.h
@@ -1,6 +1,26 @@
/*
Custom effect that animates a 2D matrix of LEDs
+ In your sketch create an array of led color data:
+ uint32_t matrix_leds[][3][8] = {
+ { // page 0
+ {RED, RED, RED, RED, RED, RED, RED, RED}, // row 0
+ {WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE}, // row 1
+ {BLUE, BLUE, BLUE, BLUE, BLUE, BLUE, BLUE, BLUE} // row 2
+ },
+ { // page 1
+ {YELLOW, YELLOW, YELLOW, YELLOW, YELLOW, YELLOW, YELLOW, YELLOW}, // row 0
+ {PINK, PINK, PINK, PINK, PINK, PINK, PINK, PINK}, // row 1
+ {GREEN, GREEN, GREEN, GREEN, GREEN, GREEN, GREEN, GREEN} // row 2
+ }
+ };
+
+ Then tell the matrix effect about your array:
+ configMatrix(NUM_PAGES, NUM_ROWS, NUM_COLS, (uint32_t*)matrix_leds);
+
+ Then setup your matrix effect with setCustomMode() like you would any other
+ custom effect.
+
Keith Lord - 2020
LICENSE
@@ -38,45 +58,41 @@
extern WS2812FX ws2812fx;
-uint32_t matrix_leds[][3][8] = { // setup for a 3x8 LED matrix
- { // page 0
- {RED, RED, RED, RED, RED, RED, RED, RED}, // row 0
- {WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE}, // row 1
- {BLUE, BLUE, BLUE, BLUE, BLUE, BLUE, BLUE, BLUE} // row 2
- },
- { // page 1
- {YELLOW, YELLOW, YELLOW, YELLOW, YELLOW, YELLOW, YELLOW, YELLOW}, // row 0
- {PINK, PINK, PINK, PINK, PINK, PINK, PINK, PINK}, // row 1
- {GREEN, GREEN, GREEN, GREEN, GREEN, GREEN, GREEN, GREEN} // row 2
- }
+struct Matrix {
+ int8_t numPages;
+ int8_t numRows;
+ int8_t numCols;
+ int32_t* colors;
};
+struct Matrix _matrix; // global variable, so this custom effect shouldn't be used in more then one segment
+
+void configMatrix(uint8_t numPages, uint8_t numRows, uint8_t numCols, uint32_t* colors) {
+ _matrix.numPages = numPages;
+ _matrix.numRows = numRows;
+ _matrix.numCols = numCols;
+ _matrix.colors = colors;
+}
uint16_t matrix(void) {
WS2812FX::Segment* seg = ws2812fx.getSegment();
WS2812FX::Segment_runtime* segrt = ws2812fx.getSegmentRuntime();
int seglen = seg->stop - seg->start + 1;
- const int numPages = sizeof(matrix_leds) / sizeof(matrix_leds[0]);
- const int numRows = sizeof(matrix_leds[0]) / sizeof(matrix_leds[0][0]);
- const int numCols = sizeof(matrix_leds[0][0]) / sizeof(matrix_leds[0][0][0]);
-// Serial.print("numPages:"); Serial.println(numPages);
-// Serial.print("numRows:"); Serial.println(numRows);
-// Serial.print("numCols:"); Serial.println(numCols);
-
- uint16_t segIndex = 0;
- uint8_t pageIndex = segrt->aux_param; // aux_param will store the page index
- for(int i=0; istart;
+ uint8_t pageIndex = segrt->aux_param * _matrix.numRows * _matrix.numCols; // aux_param will store the page index
+ for(int rowIndex=0; rowIndex < _matrix.numRows; rowIndex++) {
+ uint16_t matrixIndex = pageIndex + (rowIndex * _matrix.numCols);
+ for(int colIndex=0; colIndex < _matrix.numCols; colIndex++) {
+ if(segIndex <= seg->stop) {
+ ws2812fx.setPixelColor(segIndex, _matrix.colors[matrixIndex + colIndex]);
segIndex++;
}
}
}
// increment to the next page
- segrt->aux_param < (numPages - 1) ? segrt->aux_param++ : segrt->aux_param = 0;
-
+ segrt->aux_param < (_matrix.numPages - 1) ? segrt->aux_param++ : segrt->aux_param = 0;
+ if(segrt->aux_param == 0) ws2812fx.setCycle();
return seg->speed;
}
diff --git a/src/custom/MultiComet.h b/src/custom/MultiComet.h
index 8f0b850..f43a777 100644
--- a/src/custom/MultiComet.h
+++ b/src/custom/MultiComet.h
@@ -60,6 +60,7 @@ uint16_t multiComet(void) {
} else {
if(!random(seglen)) {
comets[i] = 0;
+ ws2812fx.setCycle();
}
}
}
diff --git a/src/custom/Oscillate.h b/src/custom/Oscillate.h
index d44c69a..da0f3a5 100644
--- a/src/custom/Oscillate.h
+++ b/src/custom/Oscillate.h
@@ -49,7 +49,7 @@ uint16_t oscillate(void) {
WS2812FX::Segment* seg = ws2812fx.getSegment(); // get the current segment
int seglen = seg->stop - seg->start + 1;
- static oscillator oscillators[NUM_COLORS] = {
+ static oscillator oscillators[] = {
{seglen/4, seglen/8, 1, 1},
{seglen/4*2, seglen/8, -1, 1},
{seglen/4*3, seglen/8, 1, 2}
@@ -61,11 +61,13 @@ uint16_t oscillate(void) {
oscillators[i].pos = 0;
oscillators[i].dir = 1;
oscillators[i].speed = random(1, 3);
+ ws2812fx.setCycle();
}
if((oscillators[i].dir == 1) && (oscillators[i].pos >= (seglen - 1))) {
oscillators[i].pos = seglen - 1;
oscillators[i].dir = -1;
oscillators[i].speed = random(1, 3);
+ ws2812fx.setCycle();
}
}
diff --git a/src/custom/Popcorn.h b/src/custom/Popcorn.h
index 53d2942..94bfcda 100644
--- a/src/custom/Popcorn.h
+++ b/src/custom/Popcorn.h
@@ -84,6 +84,7 @@ uint16_t popcorn(void) {
popcorn[i].color = popcornColor;
ledIndex = isReverse ? seg->stop : seg->start;
ws2812fx.setPixelColor(ledIndex, popcorn[i].color);
+ ws2812fx.setCycle();
}
}
}
diff --git a/src/custom/RainbowFireworks.h b/src/custom/RainbowFireworks.h
index 8c167bd..da79513 100644
--- a/src/custom/RainbowFireworks.h
+++ b/src/custom/RainbowFireworks.h
@@ -80,6 +80,7 @@ uint16_t rainbowFireworks(void) {
if(ws2812fx.random8(10) == 0) {
uint16_t index = seg->start + 6 + ws2812fx.random16(seglen - 12);
ws2812fx.setPixelColor(index, RED);
+ ws2812fx.setCycle();
}
}
diff --git a/src/custom/RainbowLarson.h b/src/custom/RainbowLarson.h
index 2512361..74777b0 100644
--- a/src/custom/RainbowLarson.h
+++ b/src/custom/RainbowLarson.h
@@ -42,6 +42,8 @@
#include
+#define DIR_BIT (uint8_t)B00000001 // segrt->aux_param2 direction bit
+
extern WS2812FX ws2812fx;
uint16_t rainbowLarson(void) {
@@ -49,7 +51,7 @@ uint16_t rainbowLarson(void) {
WS2812FX::Segment_runtime* segrt = ws2812fx.getSegmentRuntime();
int seglen = seg->stop - seg->start + 1;
- int8_t dir = segrt->aux_param2 ? -1 : 1;
+ int8_t dir = ((segrt->aux_param2 & DIR_BIT) == DIR_BIT) ? -1 : 1; // forward?
segrt->aux_param3 += dir;
int16_t index = segrt->aux_param3 % seglen;
@@ -63,7 +65,8 @@ uint16_t rainbowLarson(void) {
}
if(segrt->aux_param3 >= (seg->stop - seg->start) || segrt->aux_param3 <= 0) {
- segrt->aux_param2 = !segrt->aux_param2;
+ segrt->aux_param2 ^= DIR_BIT; // change direction
+ ws2812fx.setCycle();
}
return (seg->speed / (seglen * 2));
diff --git a/src/custom/RandomChase.h b/src/custom/RandomChase.h
index b0d7df6..d96e6eb 100644
--- a/src/custom/RandomChase.h
+++ b/src/custom/RandomChase.h
@@ -40,13 +40,17 @@ extern WS2812FX ws2812fx;
uint16_t randomChase(void) {
WS2812FX::Segment* seg = ws2812fx.getSegment();
+ WS2812FX::Segment_runtime* segrt = ws2812fx.getSegmentRuntime();
int seglen = seg->stop - seg->start + 1;
+
ws2812fx.copyPixels(seg->start + 1, seg->start, seglen - 1);
uint32_t color = ws2812fx.getPixelColor(seg->start + 1);
int r = random(6) != 0 ? (color >> 16 & 0xFF) : random(256);
int g = random(6) != 0 ? (color >> 8 & 0xFF) : random(256);
int b = random(6) != 0 ? (color & 0xFF) : random(256);
ws2812fx.setPixelColor(seg->start, r, g, b);
+
+ if((segrt->counter_mode_call % seglen) == 0) ws2812fx.setCycle();
return seg->speed;
}
diff --git a/src/custom/TriFade.h b/src/custom/TriFade.h
index 501e945..2e1488f 100644
--- a/src/custom/TriFade.h
+++ b/src/custom/TriFade.h
@@ -82,7 +82,10 @@ uint16_t triFade(void) {
}
segrt->aux_param3 += 4;
- if(segrt->aux_param3 >= 1536) segrt->aux_param3 = 0;
+ if(segrt->aux_param3 >= 1536) {
+ segrt->aux_param3 = 0;
+ ws2812fx.setCycle();
+ }
return (seg->speed / 128);
}
diff --git a/src/custom/TwinkleFox.h b/src/custom/TwinkleFox.h
index 17ccd20..52564d7 100644
--- a/src/custom/TwinkleFox.h
+++ b/src/custom/TwinkleFox.h
@@ -69,7 +69,7 @@ uint16_t twinkleFox(void) {
// Index into the built-in Adafruit_NeoPixel sine table to lookup the blend amount
uint8_t blendAmt = Adafruit_NeoPixel::sine8(blendIndex); // 0-255
- // If colors[0] is BLACK, bland random colors
+ // If colors[0] is BLACK, blend random colors
if(color0 == BLACK) {
blendedColor = ws2812fx.color_blend(ws2812fx.color_wheel(initValue), color1, blendAmt);
// If colors[2] isn't BLACK, choose to blend colors[0]/colors[1] or colors[1]/colors[2]
@@ -88,6 +88,7 @@ uint16_t twinkleFox(void) {
}
}
}
+ ws2812fx.setCycle();
return seg->speed / 32;
}
diff --git a/src/custom/VUMeter.h b/src/custom/VUMeter.h
index 77ca20c..d245a54 100644
--- a/src/custom/VUMeter.h
+++ b/src/custom/VUMeter.h
@@ -73,6 +73,7 @@ uint16_t vuMeter(void) {
}
}
}
+ ws2812fx.setCycle();
return seg->speed;
}