Move ws2812fx library to extlib/ws2812fx directory
authorNathael Pajani <nathael.pajani@ed3l.fr>
Mon, 27 Feb 2023 13:24:49 +0000 (14:24 +0100)
committerNathael Pajani <nathael.pajani@ed3l.fr>
Mon, 27 Feb 2023 13:24:49 +0000 (14:24 +0100)
Update header.

extdrv/ws2812fx.c [deleted file]
extlib/ws2812fx/ws2812fx.c [new file with mode: 0644]
include/extdrv/ws2812fx.h [deleted file]
include/extlib/ws2812fx/ws2812fx.h [new file with mode: 0644]

diff --git a/extdrv/ws2812fx.c b/extdrv/ws2812fx.c
deleted file mode 100644 (file)
index f66c023..0000000
+++ /dev/null
@@ -1,1392 +0,0 @@
-/*
-  WS2812FX.cpp - Library for WS2812 LED effects.
-  Harm Aldick - 2016
-  www.aldick.org
-  FEATURES
-    * A lot of blinken modes and counting
-    * WS2812FX can be used as drop-in replacement for Adafruit Neopixel Library
-  NOTES
-    * Uses the Adafruit Neopixel library. Get it here:
-      https://github.com/adafruit/Adafruit_NeoPixel
-  LICENSE
-  The MIT License (MIT)
-  Copyright (c) 2016  Harm Aldick
-  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
-  2016-05-28   Initial beta release
-  2016-06-03   Code cleanup, minor improvements, new modes
-  2016-06-04   2 new fx, fixed setColor (now also resets _mode_color)
-  2017-02-02   added external trigger functionality (e.g. for sound-to-light)
-  2017-02-02   removed "blackout" on mode, speed or color-change
-*/
-
-#include "core/systick.h"
-#include "lib/utils.h"
-#include "extdrv/ws2812.h"
-#include "extdrv/ws2812fx.h"
-
-static uint32_t random(uint32_t max)
-{
-       static uint32_t seed = 0;
-       /* Numerical Recipes */
-       seed = seed * 1664525 + 1013904223;
-       return seed % max;
-}
-
-static unsigned long millis(void)
-{
-       return systick_get_tick_count();
-}
-
-
-/* #####################################################
-#
-#  Color and Blinken Functions
-#
-##################################################### */
-
-/*
- * Turns everything off. Doh.
- */
-static void strip_off(struct ws2812fx* fx)
-{
-       ws2812_clear(fx->wsconf);
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-}
-
-#define WHITE 0xffffff
-#define RED   0xff0000
-#define GREEN 0x00ff00
-#define BLUE  0x0000ff
-#define BLACK 0x000000
-
-static void set_pixel_rgb_color(struct ws2812fx* fx, uint32_t i, uint8_t r, uint8_t g, uint8_t b)
-{
-       ws2812_set_pixel(fx->wsconf, i, r, g, b);
-}
-
-static void set_pixel_color(struct ws2812fx* fx, uint32_t i, uint32_t color)
-{
-       ws2812_set_pixel(fx->wsconf, i, color >> 16, (color >> 8) & 0xff, color & 0xff);
-}
-
-static uint32_t get_pixel_color(struct ws2812fx* fx, uint32_t i)
-{
-       uint8_t r, g, b;
-       ws2812_get_pixel(fx->wsconf, i, &r, &g, &b);
-       return (r << 16) | (g << 8) | b;
-}
-
-/*
- * Put a value 0 to 255 in to get a color value.
- * The colours are a transition r -> g -> b -> back to r
- * Inspired by the Adafruit examples.
- */
-static uint32_t color_wheel(uint8_t pos)
-{
-       pos = 255 - pos;
-       if (pos < 85) {
-               return ((uint32_t)(255 - pos * 3) << 16) | ((uint32_t)(0) << 8) | (pos * 3);
-       } else if (pos < 170) {
-               pos -= 85;
-               return ((uint32_t)(0) << 16) | ((uint32_t)(pos * 3) << 8) | (255 - pos * 3);
-       } else {
-               pos -= 170;
-               return ((uint32_t)(pos * 3) << 16) | ((uint32_t)(255 - pos * 3) << 8) | (0);
-       }
-}
-
-
-/*
- * Returns a new, random wheel index with a minimum distance of 42 from pos.
- */
-static uint8_t get_random_wheel_index(uint8_t pos)
-{
-       uint8_t r = 0;
-       uint8_t x = 0;
-       uint8_t y = 0;
-       uint8_t d = 0;
-
-       while (d < 42) {
-               r = random(256);
-               x = abs(pos - r);
-               y = 255 - x;
-               d = min(x, y);
-       }
-
-       return r;
-}
-
-
-/*
- * No blinking. Just plain old static light.
- */
-static void mode_static(struct ws2812fx* fx)
-{
-       for (uint16_t i = 0; i < fx->_led_count; i++) {
-               set_pixel_color(fx, i, fx->_color);
-       }
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_mode_delay = 50;
-}
-
-
-/*
- * Normal blinking. 50% on/off time.
- */
-static void mode_blink(struct ws2812fx* fx)
-{
-       if (fx->_counter_mode_call % 2 == 1) {
-               for (uint16_t i=0; i < fx->_led_count; i++) {
-                       set_pixel_color(fx, i, fx->_color);
-               }
-               ws2812_send_frame(fx->wsconf, fx->_led_count);
-       } else {
-               strip_off(fx);
-       }
-
-       fx->_mode_delay = 100 + ((1986 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
-}
-
-
-/*
- * Lights all LEDs after each other up. Then turns them in
- * that order off. Repeat.
- */
-static void mode_color_wipe(struct ws2812fx* fx)
-{
-       if (fx->_counter_mode_step < fx->_led_count) {
-               set_pixel_color(fx, fx->_counter_mode_step, fx->_color);
-       } else {
-               set_pixel_color(fx, fx->_counter_mode_step - fx->_led_count, 0);
-       }
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % (fx->_led_count * 2);
-
-       fx->_mode_delay = 5 + ((50 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
-}
-
-
-/*
- * Turns all LEDs after each other to a random color.
- * Then starts over with another color.
- */
-static void mode_color_wipe_random(struct ws2812fx* fx)
-{
-       if (fx->_counter_mode_step == 0) {
-               fx->_mode_color = get_random_wheel_index(fx->_mode_color);
-       }
-
-       set_pixel_color(fx, fx->_counter_mode_step, color_wheel(fx->_mode_color));
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
-
-       fx->_mode_delay = 5 + ((50 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
-}
-
-
-/*
- * Lights all LEDs in one random color up. Then switches them
- * to the next random color.
- */
-static void mode_random_color(struct ws2812fx* fx)
-{
-       fx->_mode_color = get_random_wheel_index(fx->_mode_color);
-
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               set_pixel_color(fx, i, color_wheel(fx->_mode_color));
-       }
-
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-       fx->_mode_delay = 100 + ((5000 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
-}
-
-
-/*
- * Lights every LED in a random color. Changes one random LED after the other
- * to another random color.
- */
-static void mode_single_dynamic(struct ws2812fx* fx)
-{
-       if (fx->_counter_mode_call == 0) {
-               for (uint16_t i=0; i < fx->_led_count; i++) {
-                       set_pixel_color(fx, i, color_wheel(random(256)));
-               }
-       }
-
-       set_pixel_color(fx, random(fx->_led_count), color_wheel(random(256)));
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-       fx->_mode_delay = 10 + ((5000 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
-}
-
-
-/*
- * Lights every LED in a random color. Changes all LED at the same time
- * to new random colors.
- */
-static void mode_multi_dynamic(struct ws2812fx* fx)
-{
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               set_pixel_color(fx, i, color_wheel(random(256)));
-       }
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-       fx->_mode_delay = 100 + ((5000 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
-}
-
-
-/*
- * Does the "standby-breathing" of well known i-Devices. Fixed Speed.
- * Use mode "fade" if you like to have something similar with a different speed.
- */
-static void mode_breath(struct ws2812fx* fx)
-{
-       //                                      0    1    2   3   4   5   6    7   8   9  10  11   12   13   14   15   16    // step
-       uint16_t breath_delay_steps[] =     {   7,   9,  13, 15, 16, 17, 18, 930, 19, 18, 15, 13,   9,   7,   4,   5,  10 }; // magic numbers for breathing LED
-       uint8_t breath_brightness_steps[] = { 150, 125, 100, 75, 50, 25, 16,  15, 16, 25, 50, 75, 100, 125, 150, 220, 255 }; // even more magic numbers!
-
-       if (fx->_counter_mode_call == 0) {
-               fx->_mode_color = breath_brightness_steps[0] + 1;
-       }
-
-       uint32_t breath_brightness = fx->_mode_color; // we use fx->_mode_color to store the brightness
-
-       if (fx->_counter_mode_step < 8) {
-               breath_brightness--;
-       } else {
-               breath_brightness++;
-       }
-
-       // update index of current delay when target brightness is reached, start over after the last step
-       if (breath_brightness == breath_brightness_steps[fx->_counter_mode_step]) {
-               fx->_counter_mode_step = (fx->_counter_mode_step + 1) % (sizeof(breath_brightness_steps)/sizeof(uint8_t));
-       }
-
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               set_pixel_color(fx, i, fx->_color);           // set all LEDs to selected color
-       }
-       int b = (breath_brightness * (fx->_brightness + 1)) >> 8;  // keep brightness below brightness set by user
-       ws2812_set_brightness(fx->wsconf, b);
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_mode_color = breath_brightness;                         // we use fx->_mode_color to store the brightness
-       fx->_mode_delay = breath_delay_steps[fx->_counter_mode_step];
-}
-
-
-/*
- * Fades the LEDs on and (almost) off again.
- */
-static void mode_fade(struct ws2812fx* fx)
-{
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               set_pixel_color(fx, i, fx->_color);
-       }
-
-       int b = fx->_counter_mode_step - 127;
-       b = 255 - (abs(b) * 2);
-       b = (b * (min(20, fx->_brightness) + 1)) >> 8;
-       ws2812_set_brightness(fx->wsconf, b);
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 255;
-       fx->_mode_delay = 5 + ((15 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
-}
-
-
-/*
- * Runs a single pixel back and forth.
- */
-static void mode_scan(struct ws2812fx* fx)
-{
-       if (fx->_counter_mode_step > (fx->_led_count*2) - 2) {
-               fx->_counter_mode_step = 0;
-       }
-       fx->_counter_mode_step++;
-
-       int i = fx->_counter_mode_step - (fx->_led_count - 1);
-       i = abs(i);
-
-       ws2812_clear(fx->wsconf);
-       set_pixel_color(fx, abs(i), fx->_color);
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
-}
-
-
-/*
- * Runs two pixel back and forth in opposite directions.
- */
-static void mode_dual_scan(struct ws2812fx* fx)
-{
-       if (fx->_counter_mode_step > (fx->_led_count*2) - 2) {
-               fx->_counter_mode_step = 0;
-       }
-       fx->_counter_mode_step++;
-
-       int i = fx->_counter_mode_step - (fx->_led_count - 1);
-       i = abs(i);
-
-       ws2812_clear(fx->wsconf);
-       set_pixel_color(fx, i, fx->_color);
-       set_pixel_color(fx, fx->_led_count - (i+1), fx->_color);
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
-}
-
-
-/*
- * Cycles all LEDs at once through a rainbow.
- */
-static void mode_rainbow(struct ws2812fx* fx)
-{
-       uint32_t color = color_wheel(fx->_counter_mode_step);
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               set_pixel_color(fx, i, color);
-       }
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 256;
-
-       fx->_mode_delay = 1 + ((50 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
-}
-
-
-/*
- * Cycles a rainbow over the entire string of LEDs.
- */
-static void mode_rainbow_cycle(struct ws2812fx* fx)
-{
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               set_pixel_color(fx, i, color_wheel(((i * 256 / fx->_led_count) + fx->_counter_mode_step) % 256));
-       }
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 256;
-
-       fx->_mode_delay = 1 + ((50 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
-}
-
-
-/*
- * Theatre-style crawling lights.
- * Inspired by the Adafruit examples.
- */
-static void mode_theater_chase(struct ws2812fx* fx)
-{
-       uint8_t j = fx->_counter_mode_call % 6;
-       if (j % 2 == 0) {
-               for (uint16_t i=0; i < fx->_led_count; i=i+3) {
-                       set_pixel_color(fx, i+(j/2), fx->_color);
-               }
-               ws2812_send_frame(fx->wsconf, fx->_led_count);
-               fx->_mode_delay = 50 + ((500 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
-       } else {
-               for (uint16_t i=0; i < fx->_led_count; i=i+3) {
-                       set_pixel_color(fx, i+(j/2), 0);
-               }
-               fx->_mode_delay = 1;
-       }
-}
-
-
-/*
- * Theatre-style crawling lights with rainbow effect.
- * Inspired by the Adafruit examples.
- */
-static void mode_theater_chase_rainbow(struct ws2812fx* fx)
-{
-       uint8_t j = fx->_counter_mode_call % 6;
-       if (j % 2 == 0) {
-               for (uint16_t i=0; i < fx->_led_count; i=i+3) {
-                       set_pixel_color(fx, i+(j/2), color_wheel((i+fx->_counter_mode_step) % 256));
-               }
-               ws2812_send_frame(fx->wsconf, fx->_led_count);
-               fx->_mode_delay = 50 + ((500 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
-       } else {
-               for (uint16_t i=0; i < fx->_led_count; i=i+3) {
-                       set_pixel_color(fx, i+(j/2), 0);
-               }
-               fx->_mode_delay = 1;
-       }
-       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 256;
-}
-
-
-#if 0
-/*
- * Running lights effect with smooth sine transition.
- */
-static void mode_running_lights(struct ws2812fx* fx)
-{
-       uint8_t r = ((fx->_color >> 16) & 0xFF);
-       uint8_t g = ((fx->_color >> 8) & 0xFF);
-       uint8_t b = (fx->_color & 0xFF);
-
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               int s = (sin(i+fx->_counter_mode_call) * 127) + 128;
-               set_pixel_rgb_color(fx, i, (((uint32_t)(r * s)) / 255), (((uint32_t)(g * s)) / 255), (((uint32_t)(b * s)) / 255));
-       }
-
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_mode_delay = 35 + ((350 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
-}
-#endif
-
-
-/*
- * Blink several LEDs on, reset, repeat.
- * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
- */
-static void mode_twinkle(struct ws2812fx* fx)
-{
-       if (fx->_counter_mode_step == 0) {
-               strip_off(fx);
-               uint16_t min_leds = max(1, fx->_led_count/5); // make sure, at least one LED is on
-               uint16_t max_leds = max(1, fx->_led_count/2); // make sure, at least one LED is on
-               fx->_counter_mode_step = min_leds + random(max_leds - min_leds);
-       }
-
-       set_pixel_color(fx, random(fx->_led_count), fx->_mode_color);
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_counter_mode_step--;
-       fx->_mode_delay = 50 + ((1986 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
-}
-
-
-/*
- * Blink several LEDs in random colors on, reset, repeat.
- * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
- */
-static void mode_twinkle_random(struct ws2812fx* fx)
-{
-       fx->_mode_color = color_wheel(random(256));
-       mode_twinkle(fx);
-}
-
-
-/*
- * Blink several LEDs on, fading out.
- */
-static void mode_twinkle_fade(struct ws2812fx* fx)
-{
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               uint32_t px_rgb = get_pixel_color(fx, i);
-
-               uint8_t px_r = (px_rgb & 0x00FF0000) >> 16;
-               uint8_t px_g = (px_rgb & 0x0000FF00) >>  8;
-               uint8_t px_b = (px_rgb & 0x000000FF) >>  0;
-
-               // fade out (divide by 2)
-               px_r = px_r >> 1;
-               px_g = px_g >> 1;
-               px_b = px_b >> 1;
-
-               set_pixel_rgb_color(fx, i, px_r, px_g, px_b);
-       }
-
-       if (random(3) == 0) {
-               set_pixel_color(fx, random(fx->_led_count), fx->_mode_color);
-       }
-
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_mode_delay = 100 + ((100 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
-}
-
-
-/*
- * Blink several LEDs in random colors on, fading out.
- */
-static void mode_twinkle_fade_random(struct ws2812fx* fx)
-{
-       fx->_mode_color = color_wheel(random(256));
-       mode_twinkle_fade(fx);
-}
-
-
-/*
- * Blinks one LED at a time.
- * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
- */
-static void mode_sparkle(struct ws2812fx* fx)
-{
-       ws2812_clear(fx->wsconf);
-       set_pixel_color(fx, random(fx->_led_count),fx->_color);
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-       fx->_mode_delay = 10 + ((200 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
-}
-
-
-/*
- * Lights all LEDs in the fx->_color. Flashes single white pixels randomly.
- * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
- */
-static void mode_flash_sparkle(struct ws2812fx* fx)
-{
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               set_pixel_color(fx, i, fx->_color);
-       }
-
-       if (random(10) == 7) {
-               set_pixel_color(fx, random(fx->_led_count), WHITE);
-               fx->_mode_delay = 20;
-       } else {
-               fx->_mode_delay = 20 + ((200 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
-       }
-
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-}
-
-
-/*
- * Like flash sparkle. With more flash.
- * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
- */
-static void mode_hyper_sparkle(struct ws2812fx* fx)
-{
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               set_pixel_color(fx, i, fx->_color);
-       }
-
-       if (random(10) < 4) {
-               for (uint16_t i=0; i < max(1, fx->_led_count/3); i++) {
-                       set_pixel_color(fx, random(fx->_led_count), WHITE);
-               }
-               fx->_mode_delay = 20;
-       } else {
-               fx->_mode_delay = 15 + ((120 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
-       }
-
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-}
-
-
-/*
- * Classic Strobe effect.
- */
-static void mode_strobe(struct ws2812fx* fx)
-{
-       if (fx->_counter_mode_call % 2 == 0) {
-               for (uint16_t i=0; i < fx->_led_count; i++) {
-                       set_pixel_color(fx, i, fx->_color);
-               }
-               fx->_mode_delay = 20;
-       } else {
-               for (uint16_t i=0; i < fx->_led_count; i++) {
-                       set_pixel_color(fx, i, 0);
-               }
-               fx->_mode_delay = 50 + ((1986 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
-       }
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-}
-
-
-/*
- * Strobe effect with different strobe count and pause, controled by fx->_speed.
- */
-static void mode_multi_strobe(struct ws2812fx* fx)
-{
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               set_pixel_color(fx, i, 0);
-       }
-
-       if (fx->_counter_mode_step < (2 * ((fx->_speed / 10) + 1))) {
-               if (fx->_counter_mode_step % 2 == 0) {
-                       for (uint16_t i=0; i < fx->_led_count; i++) {
-                               set_pixel_color(fx, i, fx->_color);
-                       }
-                       fx->_mode_delay = 20;
-               } else {
-                       fx->_mode_delay = 50;
-               }
-
-       } else {
-               fx->_mode_delay = 100 + ((9 - (fx->_speed % 10)) * 125);
-       }
-
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % ((2 * ((fx->_speed / 10) + 1)) + 1);
-}
-
-
-/*
- * Classic Strobe effect. Cycling through the rainbow.
- */
-static void mode_strobe_rainbow(struct ws2812fx* fx)
-{
-       if (fx->_counter_mode_call % 2 == 0) {
-               for (uint16_t i=0; i < fx->_led_count; i++) {
-                       set_pixel_color(fx, i, color_wheel(fx->_counter_mode_call % 256));
-               }
-               fx->_mode_delay = 20;
-       } else {
-               for (uint16_t i=0; i < fx->_led_count; i++) {
-                       set_pixel_color(fx, i, 0);
-               }
-               fx->_mode_delay = 50 + ((1986 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
-       }
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-}
-
-
-/*
- * Classic Blink effect. Cycling through the rainbow.
- */
-static void mode_blink_rainbow(struct ws2812fx* fx)
-{
-       if (fx->_counter_mode_call % 2 == 1) {
-               for (uint16_t i=0; i < fx->_led_count; i++) {
-                       set_pixel_color(fx, i, color_wheel(fx->_counter_mode_call % 256));
-               }
-               ws2812_send_frame(fx->wsconf, fx->_led_count);
-       } else {
-               strip_off(fx);
-       }
-
-       fx->_mode_delay = 100 + ((1986 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
-}
-
-
-/*
- * fx->_color running on white.
- */
-static void mode_chase_white(struct ws2812fx* fx)
-{
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               set_pixel_color(fx, i, WHITE);
-       }
-
-       uint16_t n = fx->_counter_mode_step;
-       uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
-       set_pixel_color(fx, n, fx->_color);
-       set_pixel_color(fx, m, fx->_color);
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
-       fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
-}
-
-
-/*
- * White running on fx->_color.
- */
-static void mode_chase_color(struct ws2812fx* fx)
-{
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               set_pixel_color(fx, i, fx->_color);
-       }
-
-       uint16_t n = fx->_counter_mode_step;
-       uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
-       set_pixel_color(fx, n, WHITE);
-       set_pixel_color(fx, m, WHITE);
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
-       fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
-}
-
-
-/*
- * White running followed by random color.
- */
-static void mode_chase_random(struct ws2812fx* fx)
-{
-       if (fx->_counter_mode_step == 0) {
-               set_pixel_color(fx, fx->_led_count-1, color_wheel(fx->_mode_color));
-               fx->_mode_color = get_random_wheel_index(fx->_mode_color);
-       }
-
-       for (uint16_t i=0; i < fx->_counter_mode_step; i++) {
-               set_pixel_color(fx, i, color_wheel(fx->_mode_color));
-       }
-
-       uint16_t n = fx->_counter_mode_step;
-       uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
-       set_pixel_color(fx, n, WHITE);
-       set_pixel_color(fx, m, WHITE);
-
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
-       fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
-}
-
-
-/*
- * White running on rainbow.
- */
-static void mode_chase_rainbow(struct ws2812fx* fx)
-{
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               set_pixel_color(fx, i, color_wheel(((i * 256 / fx->_led_count) + (fx->_counter_mode_call % 256)) % 256));
-       }
-
-       uint16_t n = fx->_counter_mode_step;
-       uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
-       set_pixel_color(fx, n, WHITE);
-       set_pixel_color(fx, m, WHITE);
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
-       fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
-}
-
-
-/*
- * White flashes running on fx->_color.
- */
-static void mode_chase_flash(struct ws2812fx* fx)
-{
-       const static uint8_t flash_count = 4;
-       uint8_t flash_step = fx->_counter_mode_call % ((flash_count * 2) + 1);
-
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               set_pixel_color(fx, i, fx->_color);
-       }
-
-       if (flash_step < (flash_count * 2)) {
-               if (flash_step % 2 == 0) {
-                       uint16_t n = fx->_counter_mode_step;
-                       uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
-                       set_pixel_color(fx, n, WHITE);
-                       set_pixel_color(fx, m, WHITE);
-                       fx->_mode_delay = 20;
-               } else {
-                       fx->_mode_delay = 30;
-               }
-       } else {
-               fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
-               fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
-       }
-
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-}
-
-
-/*
- * White flashes running, followed by random color.
- */
-static void mode_chase_flash_random(struct ws2812fx* fx)
-{
-       const static uint8_t flash_count = 4;
-       uint8_t flash_step = fx->_counter_mode_call % ((flash_count * 2) + 1);
-
-       for (uint16_t i=0; i < fx->_counter_mode_step; i++) {
-               set_pixel_color(fx, i, color_wheel(fx->_mode_color));
-       }
-
-       if (flash_step < (flash_count * 2)) {
-               uint16_t n = fx->_counter_mode_step;
-               uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
-               if (flash_step % 2 == 0) {
-                       set_pixel_color(fx, n, WHITE);
-                       set_pixel_color(fx, m, WHITE);
-                       fx->_mode_delay = 20;
-               } else {
-                       set_pixel_color(fx, n, color_wheel(fx->_mode_color));
-                       set_pixel_color(fx, m, BLACK);
-                       fx->_mode_delay = 30;
-               }
-       } else {
-               fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
-               fx->_mode_delay = 1 + ((10 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
-
-               if (fx->_counter_mode_step == 0) {
-                       fx->_mode_color = get_random_wheel_index(fx->_mode_color);
-               }
-       }
-
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-}
-
-
-/*
- * Rainbow running on white.
- */
-static void mode_chase_rainbow_white(struct ws2812fx* fx)
-{
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               set_pixel_color(fx, i, WHITE);
-       }
-
-       uint16_t n = fx->_counter_mode_step;
-       uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
-       set_pixel_color(fx, n, color_wheel(((n * 256 / fx->_led_count) + (fx->_counter_mode_call % 256)) % 256));
-       set_pixel_color(fx, m, color_wheel(((m * 256 / fx->_led_count) + (fx->_counter_mode_call % 256)) % 256));
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
-       fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
-}
-
-
-/*
- * Black running on fx->_color.
- */
-static void mode_chase_blackout(struct ws2812fx* fx)
-{
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               set_pixel_color(fx, i, fx->_color);
-       }
-
-       uint16_t n = fx->_counter_mode_step;
-       uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
-       set_pixel_color(fx, n, BLACK);
-       set_pixel_color(fx, m, BLACK);
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
-       fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
-}
-
-
-/*
- * Black running on rainbow.
- */
-static void mode_chase_blackout_rainbow(struct ws2812fx* fx)
-{
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               set_pixel_color(fx, i, color_wheel(((i * 256 / fx->_led_count) + (fx->_counter_mode_call % 256)) % 256));
-       }
-
-       uint16_t n = fx->_counter_mode_step;
-       uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
-       set_pixel_color(fx, n, BLACK);
-       set_pixel_color(fx, m, BLACK);
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
-       fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
-}
-
-
-/*
- * Random color intruduced alternating from start and end of strip.
- */
-static void mode_color_sweep_random(struct ws2812fx* fx)
-{
-       if (fx->_counter_mode_step == 0 || fx->_counter_mode_step == fx->_led_count) {
-               fx->_mode_color = get_random_wheel_index(fx->_mode_color);
-       }
-
-       if (fx->_counter_mode_step < fx->_led_count) {
-               set_pixel_color(fx, fx->_counter_mode_step, color_wheel(fx->_mode_color));
-       } else {
-               set_pixel_color(fx, (fx->_led_count * 2) - fx->_counter_mode_step - 1, color_wheel(fx->_mode_color));
-       }
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % (fx->_led_count * 2);
-       fx->_mode_delay = 5 + ((50 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
-}
-
-
-/*
- * Alternating color/white pixels running.
- */
-static void mode_running_color(struct ws2812fx* fx)
-{
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               if ((i + fx->_counter_mode_step) % 4 < 2) {
-                       set_pixel_color(fx, i, fx->_mode_color);
-               } else {
-                       set_pixel_color(fx, i, WHITE);
-               }
-       }
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 4;
-       fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
-}
-
-
-/*
- * Alternating red/blue pixels running.
- */
-static void mode_running_red_blue(struct ws2812fx* fx)
-{
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               if ((i + fx->_counter_mode_step) % 4 < 2) {
-                       set_pixel_color(fx, i, RED);
-               } else {
-                       set_pixel_color(fx, i, BLUE);
-               }
-       }
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 4;
-       fx->_mode_delay = 100 + ((100 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
-}
-
-
-/*
- * Random colored pixels running.
- */
-static void mode_running_random(struct ws2812fx* fx)
-{
-       for (uint16_t i=fx->_led_count-1; i > 0; i--) {
-               set_pixel_color(fx, i, get_pixel_color(fx, i-1));
-       }
-
-       if (fx->_counter_mode_step == 0) {
-               fx->_mode_color = get_random_wheel_index(fx->_mode_color);
-               set_pixel_color(fx, 0, color_wheel(fx->_mode_color));
-       }
-
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 2;
-
-       fx->_mode_delay = 50 + ((50 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
-}
-
-
-/*
- * K.I.T.T.
- */
-static void mode_larson_scanner(struct ws2812fx* fx)
-{
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               uint32_t px_rgb = get_pixel_color(fx, i);
-
-               uint8_t px_r = (px_rgb & 0x00FF0000) >> 16;
-               uint8_t px_g = (px_rgb & 0x0000FF00) >>  8;
-               uint8_t px_b = (px_rgb & 0x000000FF) >>  0;
-
-               // fade out (divide by 2)
-               px_r = px_r >> 1;
-               px_g = px_g >> 1;
-               px_b = px_b >> 1;
-
-               set_pixel_rgb_color(fx, i, px_r, px_g, px_b);
-       }
-
-       uint16_t pos = 0;
-
-       if (fx->_counter_mode_step < fx->_led_count) {
-               pos = fx->_counter_mode_step;
-       } else {
-               pos = (fx->_led_count * 2) - fx->_counter_mode_step - 2;
-       }
-
-       set_pixel_color(fx, pos, fx->_color);
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % ((fx->_led_count * 2) - 2);
-       fx->_mode_delay = 10 + ((10 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
-}
-
-
-/*
- * Fireing comets from one end.
- */
-static void mode_comet(struct ws2812fx* fx)
-{
-
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               uint32_t px_rgb = get_pixel_color(fx, i);
-
-               uint8_t px_r = (px_rgb & 0x00FF0000) >> 16;
-               uint8_t px_g = (px_rgb & 0x0000FF00) >>  8;
-               uint8_t px_b = (px_rgb & 0x000000FF) >>  0;
-
-               // fade out (divide by 2)
-               px_r = px_r >> 1;
-               px_g = px_g >> 1;
-               px_b = px_b >> 1;
-
-               set_pixel_rgb_color(fx, i, px_r, px_g, px_b);
-       }
-
-       set_pixel_color(fx, fx->_counter_mode_step, fx->_color);
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
-       fx->_mode_delay = 10 + ((10 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
-}
-
-
-/*
- * Firework sparks.
- */
-static void mode_fireworks(struct ws2812fx* fx)
-{
-       uint32_t px_rgb = 0;
-       uint8_t px_r = 0;
-       uint8_t px_g = 0;
-       uint8_t px_b = 0;
-
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               px_rgb = get_pixel_color(fx, i);
-
-               px_r = (px_rgb & 0x00FF0000) >> 16;
-               px_g = (px_rgb & 0x0000FF00) >>  8;
-               px_b = (px_rgb & 0x000000FF) >>  0;
-
-               // fade out (divide by 2)
-               px_r = px_r >> 1;
-               px_g = px_g >> 1;
-               px_b = px_b >> 1;
-
-               set_pixel_rgb_color(fx, i, px_r, px_g, px_b);
-       }
-
-       // first LED has only one neighbour
-       px_r = (((get_pixel_color(fx, 1) & 0x00FF0000) >> 16) >> 1) + ((get_pixel_color(fx, 0) & 0x00FF0000) >> 16);
-       px_g = (((get_pixel_color(fx, 1) & 0x0000FF00) >>  8) >> 1) + ((get_pixel_color(fx, 0) & 0x0000FF00) >>  8);
-       px_b = (((get_pixel_color(fx, 1) & 0x000000FF) >>  0) >> 1) + ((get_pixel_color(fx, 0) & 0x000000FF) >>  0);
-       set_pixel_rgb_color(fx, 0, px_r, px_g, px_b);
-
-       // set brightness(i) = ((brightness(i-1)/2 + brightness(i+1)) / 2) + brightness(i)
-       for (uint16_t i=1; i < fx->_led_count-1; i++) {
-               px_r = ((
-                                       (((get_pixel_color(fx, i-1) & 0x00FF0000) >> 16) >> 1) +
-                                       (((get_pixel_color(fx, i+1) & 0x00FF0000) >> 16) >> 0) ) >> 1) +
-                       (((get_pixel_color(fx, i  ) & 0x00FF0000) >> 16) >> 0);
-
-               px_g = ((
-                                       (((get_pixel_color(fx, i-1) & 0x0000FF00) >> 8) >> 1) +
-                                       (((get_pixel_color(fx, i+1) & 0x0000FF00) >> 8) >> 0) ) >> 1) +
-                       (((get_pixel_color(fx, i  ) & 0x0000FF00) >> 8) >> 0);
-
-               px_b = ((
-                                       (((get_pixel_color(fx, i-1) & 0x000000FF) >> 0) >> 1) +
-                                       (((get_pixel_color(fx, i+1) & 0x000000FF) >> 0) >> 0) ) >> 1) +
-                       (((get_pixel_color(fx, i  ) & 0x000000FF) >> 0) >> 0);
-
-               set_pixel_rgb_color(fx, i, px_r, px_g, px_b);
-       }
-
-       // last LED has only one neighbour
-       px_r = (((get_pixel_color(fx, fx->_led_count-2) & 0x00FF0000) >> 16) >> 2) + ((get_pixel_color(fx, fx->_led_count-1) & 0x00FF0000) >> 16);
-       px_g = (((get_pixel_color(fx, fx->_led_count-2) & 0x0000FF00) >>  8) >> 2) + ((get_pixel_color(fx, fx->_led_count-1) & 0x0000FF00) >>  8);
-       px_b = (((get_pixel_color(fx, fx->_led_count-2) & 0x000000FF) >>  0) >> 2) + ((get_pixel_color(fx, fx->_led_count-1) & 0x000000FF) >>  0);
-       set_pixel_rgb_color(fx, fx->_led_count-1, px_r, px_g, px_b);
-
-       if (!fx->_triggered) {
-               for (uint16_t i=0; i<max(1,fx->_led_count/20); i++) {
-                       if (random(10) == 0) {
-                               set_pixel_color(fx, random(fx->_led_count), fx->_mode_color);
-                       }
-               }
-       } else {
-               for (uint16_t i=0; i<max(1,fx->_led_count/10); i++) {
-                       set_pixel_color(fx, random(fx->_led_count), fx->_mode_color);
-               }
-       }
-
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_mode_delay = 20 + ((20 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
-}
-
-
-/*
- * Random colored firework sparks.
- */
-static void mode_fireworks_random(struct ws2812fx* fx)
-{
-       fx->_mode_color = color_wheel(random(256));
-       mode_fireworks(fx);
-}
-
-
-/*
- * Alternating red/green pixels running.
- */
-static void mode_merry_christmas(struct ws2812fx* fx)
-{
-       for (uint16_t i=0; i < fx->_led_count; i++) {
-               if ((i + fx->_counter_mode_step) % 4 < 2) {
-                       set_pixel_color(fx, i, RED);
-               } else {
-                       set_pixel_color(fx, i, GREEN);
-               }
-       }
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-
-       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 4;
-       fx->_mode_delay = 100 + ((100 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
-}
-
-
-static void mode_fire_flicker_int(struct ws2812fx* fx, int rev_intensity)
-{
-       uint8_t p_r = (fx->_color & 0x00FF0000) >> 16;
-       uint8_t p_g = (fx->_color & 0x0000FF00) >>  8;
-       uint8_t p_b = (fx->_color & 0x000000FF) >>  0;
-       uint8_t flicker_val = max(p_r,max(p_g, p_b))/rev_intensity;
-       for (uint16_t i=0; i < fx->_led_count; i++)
-       {
-               int flicker = random(flicker_val);
-               int r1 = p_r-flicker;
-               int g1 = p_g-flicker;
-               int b1 = p_b-flicker;
-               if (g1<0) g1=0;
-               if (r1<0) r1=0;
-               if (b1<0) b1=0;
-               set_pixel_rgb_color(fx, i, r1, g1, b1);
-       }
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-       fx->_mode_delay = 10 + ((500 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
-}
-
-/*
- * Random flickering.
- */
-static void mode_fire_flicker(struct ws2812fx* fx)
-{
-       mode_fire_flicker_int(fx, 3);
-}
-
-/*
- * Random flickering, less intesity.
- */
-static void mode_fire_flicker_soft(struct ws2812fx* fx)
-{
-       mode_fire_flicker_int(fx, 6);
-}
-
-
-typedef void (*mode_ptr)(struct ws2812fx* fx);
-
-static struct {
-       mode_ptr _fn;
-       char *_name;
-} const modes[] = {
-       { mode_static,                  "Static" },
-       { mode_blink,                   "Blink" },
-       { mode_breath,                  "Breath" },
-       { mode_color_wipe,              "Color Wipe" },
-       { mode_color_wipe_random,       "Color Wipe Random" },
-       { mode_random_color,            "Random Color" },
-       { mode_single_dynamic,          "Single Dynamic" },
-       { mode_multi_dynamic,           "Multi Dynamic" },
-       { mode_rainbow,                 "Rainbow" },
-       { mode_rainbow_cycle,           "Rainbow Cycle" },
-       { mode_theater_chase,           "Theater Chase" },
-       { mode_theater_chase_rainbow,   "Theater Chase Rainbow" },
-       { mode_scan,                    "Scan" },
-       { mode_dual_scan,               "Dual Scan" },
-       { mode_fade,                    "Fade" },
-#if 0
-       { mode_running_lights,          "Running Lights" },
-#endif
-       { mode_twinkle,                 "Twinkle" },
-       { mode_twinkle_random,          "Twinkle Random" },
-       { mode_twinkle_fade,            "Twinkle Fade" },
-       { mode_twinkle_fade_random,     "Twinkle Fade Random" },
-       { mode_sparkle,                 "Sparkle" },
-       { mode_flash_sparkle,           "Flash Sparkle" },
-       { mode_hyper_sparkle,           "Hyper Sparkle" },
-       { mode_strobe,                  "Strobe" },
-       { mode_strobe_rainbow,          "Strobe Rainbow" },
-       { mode_multi_strobe,            "Multi Strobe" },
-       { mode_blink_rainbow,           "Blink Rainbow" },
-       { mode_chase_white,             "Chase White" },
-       { mode_chase_color,             "Chase Color" },
-       { mode_chase_random,            "Chase Random" },
-       { mode_chase_rainbow,           "Chase Rainbow" },
-       { mode_chase_flash,             "Chase Flash" },
-       { mode_chase_flash_random,      "Chase Flash Random" },
-       { mode_chase_rainbow_white,     "Chase Rainbow White" },
-       { mode_chase_blackout,          "Chase Blackout" },
-       { mode_chase_blackout_rainbow,  "Chase Blackout Rainbow" },
-       { mode_color_sweep_random,      "Color Sweep Random" },
-       { mode_running_color,           "Running Color" },
-       { mode_running_red_blue,        "Running Red Blue" },
-       { mode_running_random,          "Running Random" },
-       { mode_larson_scanner,          "Larson Scanner" },
-       { mode_comet,                   "Comet" },
-       { mode_fireworks,               "Fireworks" },
-       { mode_fireworks_random,        "Fireworks Random" },
-       { mode_merry_christmas,         "Merry Christmas" },
-       { mode_fire_flicker,            "Fire Flicker" },
-       { mode_fire_flicker_soft,       "Fire Flicker (soft)" },
-};
-
-#define CALL_MODE(fx, n) (modes[n]._fn)(fx);
-
-void WS2812FX(struct ws2812fx* fx, uint16_t n, const struct pio *pin)
-{
-       fx->wsconf->nb_leds = n;
-       ws2812_config(fx->wsconf, pin);
-
-       fx->_speed = FX_DEFAULT_SPEED;
-       fx->_brightness = FX_DEFAULT_BRIGHTNESS;
-       fx->_running = 0;
-       fx->_led_count = n;
-       fx->_mode_last_call_time = 0;
-       fx->_mode_delay = 0;
-       fx->_color = FX_DEFAULT_COLOR;
-       fx->_mode_color = FX_DEFAULT_COLOR;
-       fx->_counter_mode_call = 0;
-       fx->_counter_mode_step = 0;
-}
-
-void FX_init(struct ws2812fx* fx)
-{
-       FX_setBrightness(fx, fx->_brightness);
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-}
-
-void FX_service(struct ws2812fx* fx)
-{
-       if (fx->_running || fx->_triggered) {
-               unsigned long now = millis();
-
-               if (now - fx->_mode_last_call_time > fx->_mode_delay || fx->_triggered) {
-                       CALL_MODE(fx, fx->_mode_index);
-                       fx->_counter_mode_call++;
-                       fx->_mode_last_call_time = now;
-                       fx->_triggered = 0;
-               }
-       }
-}
-
-void FX_start(struct ws2812fx* fx)
-{
-       fx->_counter_mode_call = 0;
-       fx->_counter_mode_step = 0;
-       fx->_mode_last_call_time = 0;
-       fx->_running = 1;
-}
-
-void FX_stop(struct ws2812fx* fx)
-{
-       fx->_running = 0;
-       strip_off(fx);
-}
-
-void FX_trigger(struct ws2812fx* fx)
-{
-       fx->_triggered = 1;
-}
-
-void FX_setMode(struct ws2812fx* fx, uint8_t m)
-{
-       fx->_counter_mode_call = 0;
-       fx->_counter_mode_step = 0;
-       fx->_mode_last_call_time = 0;
-       fx->_mode_index = constrain(m, 0, FX_MODE_COUNT-1);
-       fx->_mode_color = fx->_color;
-       ws2812_set_brightness(fx->wsconf, fx->_brightness);
-       //strip_off(fx);
-}
-
-void FX_setSpeed(struct ws2812fx* fx, uint8_t s)
-{
-       fx->_counter_mode_call = 0;
-       fx->_counter_mode_step = 0;
-       fx->_mode_last_call_time = 0;
-       fx->_speed = constrain(s, FX_SPEED_MIN, FX_SPEED_MAX);
-       //strip_off(fx);
-}
-
-void FX_increaseSpeed(struct ws2812fx* fx, uint8_t s)
-{
-       s = constrain(fx->_speed + s, FX_SPEED_MIN, FX_SPEED_MAX);
-       FX_setSpeed(fx, s);
-}
-
-void FX_decreaseSpeed(struct ws2812fx* fx, uint8_t s)
-{
-       s = constrain(fx->_speed - s, FX_SPEED_MIN, FX_SPEED_MAX);
-       FX_setSpeed(fx, s);
-}
-
-void FX_setRGBColor(struct ws2812fx* fx, uint8_t r, uint8_t g, uint8_t b)
-{
-       FX_setColor(fx, ((uint32_t)r << 16) | ((uint32_t)g << 8) | b);
-}
-
-void FX_setColor(struct ws2812fx* fx, uint32_t c)
-{
-       fx->_color = c;
-       fx->_counter_mode_call = 0;
-       fx->_counter_mode_step = 0;
-       fx->_mode_last_call_time = 0;
-       fx->_mode_color = fx->_color;
-       ws2812_set_brightness(fx->wsconf, fx->_brightness);
-       //strip_off(fx);
-}
-
-void FX_setBrightness(struct ws2812fx* fx, uint8_t b)
-{
-       fx->_brightness = constrain(b, FX_BRIGHTNESS_MIN, FX_BRIGHTNESS_MAX);
-       ws2812_set_brightness(fx->wsconf, fx->_brightness);
-       ws2812_send_frame(fx->wsconf, fx->_led_count);
-}
-
-void FX_increaseBrightness(struct ws2812fx* fx, uint8_t s)
-{
-       s = constrain(fx->_brightness + s, FX_BRIGHTNESS_MIN, FX_BRIGHTNESS_MAX);
-       FX_setBrightness(fx, s);
-}
-
-void FX_decreaseBrightness(struct ws2812fx* fx, uint8_t s)
-{
-       s = constrain(fx->_brightness - s, FX_BRIGHTNESS_MIN, FX_BRIGHTNESS_MAX);
-       FX_setBrightness(fx, s);
-}
-
-int FX_isRunning(struct ws2812fx* fx)
-{
-       return fx->_running;
-}
-
-uint8_t FX_getMode(struct ws2812fx* fx)
-{
-       return fx->_mode_index;
-}
-
-uint8_t FX_getSpeed(struct ws2812fx* fx)
-{
-       return fx->_speed;
-}
-
-uint8_t FX_getBrightness(struct ws2812fx* fx)
-{
-       return fx->_brightness;
-}
-
-uint8_t FX_getModeCount(struct ws2812fx* fx)
-{
-       return FX_MODE_COUNT;
-}
-
-uint32_t FX_getColor(struct ws2812fx* fx)
-{
-       return fx->_color;
-}
-
-const char* FX_getModeName(uint8_t m)
-{
-       if (m < FX_MODE_COUNT) {
-               return modes[m]._name;
-       } else {
-               return "";
-       }
-}
diff --git a/extlib/ws2812fx/ws2812fx.c b/extlib/ws2812fx/ws2812fx.c
new file mode 100644 (file)
index 0000000..bc1f3a5
--- /dev/null
@@ -0,0 +1,1395 @@
+/****************************************************************************
+ *
+ * extlib/ws2812fx/ws2812fx.c - Library for WS2812 LED effects.
+ *
+ * Fork from Harm Aldick's work - 2016 - www.aldick.org
+ * https://github.com/kitesurfer1404/WS2812FX.git
+ *
+ * FEATURES
+ *  - A lot of blinken modes and counting
+ *  - WS2812FX can be used as drop-in replacement for Adafruit Neopixel Library
+ *
+ * LICENSE
+ * The MIT License (MIT)
+ * Copyright (c) 2016  Harm Aldick
+ * 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
+ * 2016-05-28   Initial beta release
+ * 2016-06-03   Code cleanup, minor improvements, new modes
+ * 2016-06-04   2 new fx, fixed setColor (now also resets _mode_color)
+ * 2017-02-02   added external trigger functionality (e.g. for sound-to-light)
+ * 2017-02-02   removed "blackout" on mode, speed or color-change
+ *
+ *************************************************************************** */
+
+#include "core/systick.h"
+#include "lib/utils.h"
+#include "extdrv/ws2812.h"
+#include "extlib/ws2812fx/ws2812fx.h"
+
+static uint32_t random(uint32_t max)
+{
+       static uint32_t seed = 0;
+       /* Numerical Recipes */
+       seed = seed * 1664525 + 1013904223;
+       return seed % max;
+}
+
+static unsigned long millis(void)
+{
+       return systick_get_tick_count();
+}
+
+
+/* #####################################################
+#
+#  Color and Blinken Functions
+#
+##################################################### */
+
+/*
+ * Turns everything off. Doh.
+ */
+static void strip_off(struct ws2812fx* fx)
+{
+       ws2812_clear(fx->wsconf);
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+}
+
+#define WHITE 0xffffff
+#define RED   0xff0000
+#define GREEN 0x00ff00
+#define BLUE  0x0000ff
+#define BLACK 0x000000
+
+static void set_pixel_rgb_color(struct ws2812fx* fx, uint32_t i, uint8_t r, uint8_t g, uint8_t b)
+{
+       ws2812_set_pixel(fx->wsconf, i, r, g, b);
+}
+
+static void set_pixel_color(struct ws2812fx* fx, uint32_t i, uint32_t color)
+{
+       ws2812_set_pixel(fx->wsconf, i, color >> 16, (color >> 8) & 0xff, color & 0xff);
+}
+
+static uint32_t get_pixel_color(struct ws2812fx* fx, uint32_t i)
+{
+       uint8_t r, g, b;
+       ws2812_get_pixel(fx->wsconf, i, &r, &g, &b);
+       return (r << 16) | (g << 8) | b;
+}
+
+/*
+ * Put a value 0 to 255 in to get a color value.
+ * The colours are a transition r -> g -> b -> back to r
+ * Inspired by the Adafruit examples.
+ */
+static uint32_t color_wheel(uint8_t pos)
+{
+       pos = 255 - pos;
+       if (pos < 85) {
+               return ((uint32_t)(255 - pos * 3) << 16) | ((uint32_t)(0) << 8) | (pos * 3);
+       } else if (pos < 170) {
+               pos -= 85;
+               return ((uint32_t)(0) << 16) | ((uint32_t)(pos * 3) << 8) | (255 - pos * 3);
+       } else {
+               pos -= 170;
+               return ((uint32_t)(pos * 3) << 16) | ((uint32_t)(255 - pos * 3) << 8) | (0);
+       }
+}
+
+
+/*
+ * Returns a new, random wheel index with a minimum distance of 42 from pos.
+ */
+static uint8_t get_random_wheel_index(uint8_t pos)
+{
+       uint8_t r = 0;
+       uint8_t x = 0;
+       uint8_t y = 0;
+       uint8_t d = 0;
+
+       while (d < 42) {
+               r = random(256);
+               x = abs(pos - r);
+               y = 255 - x;
+               d = min(x, y);
+       }
+
+       return r;
+}
+
+
+/*
+ * No blinking. Just plain old static light.
+ */
+static void mode_static(struct ws2812fx* fx)
+{
+       for (uint16_t i = 0; i < fx->_led_count; i++) {
+               set_pixel_color(fx, i, fx->_color);
+       }
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_mode_delay = 50;
+}
+
+
+/*
+ * Normal blinking. 50% on/off time.
+ */
+static void mode_blink(struct ws2812fx* fx)
+{
+       if (fx->_counter_mode_call % 2 == 1) {
+               for (uint16_t i=0; i < fx->_led_count; i++) {
+                       set_pixel_color(fx, i, fx->_color);
+               }
+               ws2812_send_frame(fx->wsconf, fx->_led_count);
+       } else {
+               strip_off(fx);
+       }
+
+       fx->_mode_delay = 100 + ((1986 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
+}
+
+
+/*
+ * Lights all LEDs after each other up. Then turns them in
+ * that order off. Repeat.
+ */
+static void mode_color_wipe(struct ws2812fx* fx)
+{
+       if (fx->_counter_mode_step < fx->_led_count) {
+               set_pixel_color(fx, fx->_counter_mode_step, fx->_color);
+       } else {
+               set_pixel_color(fx, fx->_counter_mode_step - fx->_led_count, 0);
+       }
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % (fx->_led_count * 2);
+
+       fx->_mode_delay = 5 + ((50 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
+}
+
+
+/*
+ * Turns all LEDs after each other to a random color.
+ * Then starts over with another color.
+ */
+static void mode_color_wipe_random(struct ws2812fx* fx)
+{
+       if (fx->_counter_mode_step == 0) {
+               fx->_mode_color = get_random_wheel_index(fx->_mode_color);
+       }
+
+       set_pixel_color(fx, fx->_counter_mode_step, color_wheel(fx->_mode_color));
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
+
+       fx->_mode_delay = 5 + ((50 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
+}
+
+
+/*
+ * Lights all LEDs in one random color up. Then switches them
+ * to the next random color.
+ */
+static void mode_random_color(struct ws2812fx* fx)
+{
+       fx->_mode_color = get_random_wheel_index(fx->_mode_color);
+
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               set_pixel_color(fx, i, color_wheel(fx->_mode_color));
+       }
+
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+       fx->_mode_delay = 100 + ((5000 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
+}
+
+
+/*
+ * Lights every LED in a random color. Changes one random LED after the other
+ * to another random color.
+ */
+static void mode_single_dynamic(struct ws2812fx* fx)
+{
+       if (fx->_counter_mode_call == 0) {
+               for (uint16_t i=0; i < fx->_led_count; i++) {
+                       set_pixel_color(fx, i, color_wheel(random(256)));
+               }
+       }
+
+       set_pixel_color(fx, random(fx->_led_count), color_wheel(random(256)));
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+       fx->_mode_delay = 10 + ((5000 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
+}
+
+
+/*
+ * Lights every LED in a random color. Changes all LED at the same time
+ * to new random colors.
+ */
+static void mode_multi_dynamic(struct ws2812fx* fx)
+{
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               set_pixel_color(fx, i, color_wheel(random(256)));
+       }
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+       fx->_mode_delay = 100 + ((5000 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
+}
+
+
+/*
+ * Does the "standby-breathing" of well known i-Devices. Fixed Speed.
+ * Use mode "fade" if you like to have something similar with a different speed.
+ */
+static void mode_breath(struct ws2812fx* fx)
+{
+       //                                      0    1    2   3   4   5   6    7   8   9  10  11   12   13   14   15   16    // step
+       uint16_t breath_delay_steps[] =     {   7,   9,  13, 15, 16, 17, 18, 930, 19, 18, 15, 13,   9,   7,   4,   5,  10 }; // magic numbers for breathing LED
+       uint8_t breath_brightness_steps[] = { 150, 125, 100, 75, 50, 25, 16,  15, 16, 25, 50, 75, 100, 125, 150, 220, 255 }; // even more magic numbers!
+
+       if (fx->_counter_mode_call == 0) {
+               fx->_mode_color = breath_brightness_steps[0] + 1;
+       }
+
+       uint32_t breath_brightness = fx->_mode_color; // we use fx->_mode_color to store the brightness
+
+       if (fx->_counter_mode_step < 8) {
+               breath_brightness--;
+       } else {
+               breath_brightness++;
+       }
+
+       // update index of current delay when target brightness is reached, start over after the last step
+       if (breath_brightness == breath_brightness_steps[fx->_counter_mode_step]) {
+               fx->_counter_mode_step = (fx->_counter_mode_step + 1) % (sizeof(breath_brightness_steps)/sizeof(uint8_t));
+       }
+
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               set_pixel_color(fx, i, fx->_color);           // set all LEDs to selected color
+       }
+       int b = (breath_brightness * (fx->_brightness + 1)) >> 8;  // keep brightness below brightness set by user
+       ws2812_set_brightness(fx->wsconf, b);
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_mode_color = breath_brightness;                         // we use fx->_mode_color to store the brightness
+       fx->_mode_delay = breath_delay_steps[fx->_counter_mode_step];
+}
+
+
+/*
+ * Fades the LEDs on and (almost) off again.
+ */
+static void mode_fade(struct ws2812fx* fx)
+{
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               set_pixel_color(fx, i, fx->_color);
+       }
+
+       int b = fx->_counter_mode_step - 127;
+       b = 255 - (abs(b) * 2);
+       b = (b * (min(20, fx->_brightness) + 1)) >> 8;
+       ws2812_set_brightness(fx->wsconf, b);
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 255;
+       fx->_mode_delay = 5 + ((15 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
+}
+
+
+/*
+ * Runs a single pixel back and forth.
+ */
+static void mode_scan(struct ws2812fx* fx)
+{
+       if (fx->_counter_mode_step > (fx->_led_count*2) - 2) {
+               fx->_counter_mode_step = 0;
+       }
+       fx->_counter_mode_step++;
+
+       int i = fx->_counter_mode_step - (fx->_led_count - 1);
+       i = abs(i);
+
+       ws2812_clear(fx->wsconf);
+       set_pixel_color(fx, abs(i), fx->_color);
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
+}
+
+
+/*
+ * Runs two pixel back and forth in opposite directions.
+ */
+static void mode_dual_scan(struct ws2812fx* fx)
+{
+       if (fx->_counter_mode_step > (fx->_led_count*2) - 2) {
+               fx->_counter_mode_step = 0;
+       }
+       fx->_counter_mode_step++;
+
+       int i = fx->_counter_mode_step - (fx->_led_count - 1);
+       i = abs(i);
+
+       ws2812_clear(fx->wsconf);
+       set_pixel_color(fx, i, fx->_color);
+       set_pixel_color(fx, fx->_led_count - (i+1), fx->_color);
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
+}
+
+
+/*
+ * Cycles all LEDs at once through a rainbow.
+ */
+static void mode_rainbow(struct ws2812fx* fx)
+{
+       uint32_t color = color_wheel(fx->_counter_mode_step);
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               set_pixel_color(fx, i, color);
+       }
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 256;
+
+       fx->_mode_delay = 1 + ((50 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
+}
+
+
+/*
+ * Cycles a rainbow over the entire string of LEDs.
+ */
+static void mode_rainbow_cycle(struct ws2812fx* fx)
+{
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               set_pixel_color(fx, i, color_wheel(((i * 256 / fx->_led_count) + fx->_counter_mode_step) % 256));
+       }
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 256;
+
+       fx->_mode_delay = 1 + ((50 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
+}
+
+
+/*
+ * Theatre-style crawling lights.
+ * Inspired by the Adafruit examples.
+ */
+static void mode_theater_chase(struct ws2812fx* fx)
+{
+       uint8_t j = fx->_counter_mode_call % 6;
+       if (j % 2 == 0) {
+               for (uint16_t i=0; i < fx->_led_count; i=i+3) {
+                       set_pixel_color(fx, i+(j/2), fx->_color);
+               }
+               ws2812_send_frame(fx->wsconf, fx->_led_count);
+               fx->_mode_delay = 50 + ((500 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
+       } else {
+               for (uint16_t i=0; i < fx->_led_count; i=i+3) {
+                       set_pixel_color(fx, i+(j/2), 0);
+               }
+               fx->_mode_delay = 1;
+       }
+}
+
+
+/*
+ * Theatre-style crawling lights with rainbow effect.
+ * Inspired by the Adafruit examples.
+ */
+static void mode_theater_chase_rainbow(struct ws2812fx* fx)
+{
+       uint8_t j = fx->_counter_mode_call % 6;
+       if (j % 2 == 0) {
+               for (uint16_t i=0; i < fx->_led_count; i=i+3) {
+                       set_pixel_color(fx, i+(j/2), color_wheel((i+fx->_counter_mode_step) % 256));
+               }
+               ws2812_send_frame(fx->wsconf, fx->_led_count);
+               fx->_mode_delay = 50 + ((500 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
+       } else {
+               for (uint16_t i=0; i < fx->_led_count; i=i+3) {
+                       set_pixel_color(fx, i+(j/2), 0);
+               }
+               fx->_mode_delay = 1;
+       }
+       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 256;
+}
+
+
+#if 0
+/*
+ * Running lights effect with smooth sine transition.
+ */
+static void mode_running_lights(struct ws2812fx* fx)
+{
+       uint8_t r = ((fx->_color >> 16) & 0xFF);
+       uint8_t g = ((fx->_color >> 8) & 0xFF);
+       uint8_t b = (fx->_color & 0xFF);
+
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               int s = (sin(i+fx->_counter_mode_call) * 127) + 128;
+               set_pixel_rgb_color(fx, i, (((uint32_t)(r * s)) / 255), (((uint32_t)(g * s)) / 255), (((uint32_t)(b * s)) / 255));
+       }
+
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_mode_delay = 35 + ((350 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
+}
+#endif
+
+
+/*
+ * Blink several LEDs on, reset, repeat.
+ * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
+ */
+static void mode_twinkle(struct ws2812fx* fx)
+{
+       if (fx->_counter_mode_step == 0) {
+               strip_off(fx);
+               uint16_t min_leds = max(1, fx->_led_count/5); // make sure, at least one LED is on
+               uint16_t max_leds = max(1, fx->_led_count/2); // make sure, at least one LED is on
+               fx->_counter_mode_step = min_leds + random(max_leds - min_leds);
+       }
+
+       set_pixel_color(fx, random(fx->_led_count), fx->_mode_color);
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_counter_mode_step--;
+       fx->_mode_delay = 50 + ((1986 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
+}
+
+
+/*
+ * Blink several LEDs in random colors on, reset, repeat.
+ * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
+ */
+static void mode_twinkle_random(struct ws2812fx* fx)
+{
+       fx->_mode_color = color_wheel(random(256));
+       mode_twinkle(fx);
+}
+
+
+/*
+ * Blink several LEDs on, fading out.
+ */
+static void mode_twinkle_fade(struct ws2812fx* fx)
+{
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               uint32_t px_rgb = get_pixel_color(fx, i);
+
+               uint8_t px_r = (px_rgb & 0x00FF0000) >> 16;
+               uint8_t px_g = (px_rgb & 0x0000FF00) >>  8;
+               uint8_t px_b = (px_rgb & 0x000000FF) >>  0;
+
+               // fade out (divide by 2)
+               px_r = px_r >> 1;
+               px_g = px_g >> 1;
+               px_b = px_b >> 1;
+
+               set_pixel_rgb_color(fx, i, px_r, px_g, px_b);
+       }
+
+       if (random(3) == 0) {
+               set_pixel_color(fx, random(fx->_led_count), fx->_mode_color);
+       }
+
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_mode_delay = 100 + ((100 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
+}
+
+
+/*
+ * Blink several LEDs in random colors on, fading out.
+ */
+static void mode_twinkle_fade_random(struct ws2812fx* fx)
+{
+       fx->_mode_color = color_wheel(random(256));
+       mode_twinkle_fade(fx);
+}
+
+
+/*
+ * Blinks one LED at a time.
+ * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
+ */
+static void mode_sparkle(struct ws2812fx* fx)
+{
+       ws2812_clear(fx->wsconf);
+       set_pixel_color(fx, random(fx->_led_count),fx->_color);
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+       fx->_mode_delay = 10 + ((200 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
+}
+
+
+/*
+ * Lights all LEDs in the fx->_color. Flashes single white pixels randomly.
+ * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
+ */
+static void mode_flash_sparkle(struct ws2812fx* fx)
+{
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               set_pixel_color(fx, i, fx->_color);
+       }
+
+       if (random(10) == 7) {
+               set_pixel_color(fx, random(fx->_led_count), WHITE);
+               fx->_mode_delay = 20;
+       } else {
+               fx->_mode_delay = 20 + ((200 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
+       }
+
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+}
+
+
+/*
+ * Like flash sparkle. With more flash.
+ * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
+ */
+static void mode_hyper_sparkle(struct ws2812fx* fx)
+{
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               set_pixel_color(fx, i, fx->_color);
+       }
+
+       if (random(10) < 4) {
+               for (uint16_t i=0; i < max(1, fx->_led_count/3); i++) {
+                       set_pixel_color(fx, random(fx->_led_count), WHITE);
+               }
+               fx->_mode_delay = 20;
+       } else {
+               fx->_mode_delay = 15 + ((120 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
+       }
+
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+}
+
+
+/*
+ * Classic Strobe effect.
+ */
+static void mode_strobe(struct ws2812fx* fx)
+{
+       if (fx->_counter_mode_call % 2 == 0) {
+               for (uint16_t i=0; i < fx->_led_count; i++) {
+                       set_pixel_color(fx, i, fx->_color);
+               }
+               fx->_mode_delay = 20;
+       } else {
+               for (uint16_t i=0; i < fx->_led_count; i++) {
+                       set_pixel_color(fx, i, 0);
+               }
+               fx->_mode_delay = 50 + ((1986 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
+       }
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+}
+
+
+/*
+ * Strobe effect with different strobe count and pause, controled by fx->_speed.
+ */
+static void mode_multi_strobe(struct ws2812fx* fx)
+{
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               set_pixel_color(fx, i, 0);
+       }
+
+       if (fx->_counter_mode_step < (2 * ((fx->_speed / 10) + 1))) {
+               if (fx->_counter_mode_step % 2 == 0) {
+                       for (uint16_t i=0; i < fx->_led_count; i++) {
+                               set_pixel_color(fx, i, fx->_color);
+                       }
+                       fx->_mode_delay = 20;
+               } else {
+                       fx->_mode_delay = 50;
+               }
+
+       } else {
+               fx->_mode_delay = 100 + ((9 - (fx->_speed % 10)) * 125);
+       }
+
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % ((2 * ((fx->_speed / 10) + 1)) + 1);
+}
+
+
+/*
+ * Classic Strobe effect. Cycling through the rainbow.
+ */
+static void mode_strobe_rainbow(struct ws2812fx* fx)
+{
+       if (fx->_counter_mode_call % 2 == 0) {
+               for (uint16_t i=0; i < fx->_led_count; i++) {
+                       set_pixel_color(fx, i, color_wheel(fx->_counter_mode_call % 256));
+               }
+               fx->_mode_delay = 20;
+       } else {
+               for (uint16_t i=0; i < fx->_led_count; i++) {
+                       set_pixel_color(fx, i, 0);
+               }
+               fx->_mode_delay = 50 + ((1986 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
+       }
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+}
+
+
+/*
+ * Classic Blink effect. Cycling through the rainbow.
+ */
+static void mode_blink_rainbow(struct ws2812fx* fx)
+{
+       if (fx->_counter_mode_call % 2 == 1) {
+               for (uint16_t i=0; i < fx->_led_count; i++) {
+                       set_pixel_color(fx, i, color_wheel(fx->_counter_mode_call % 256));
+               }
+               ws2812_send_frame(fx->wsconf, fx->_led_count);
+       } else {
+               strip_off(fx);
+       }
+
+       fx->_mode_delay = 100 + ((1986 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
+}
+
+
+/*
+ * fx->_color running on white.
+ */
+static void mode_chase_white(struct ws2812fx* fx)
+{
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               set_pixel_color(fx, i, WHITE);
+       }
+
+       uint16_t n = fx->_counter_mode_step;
+       uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
+       set_pixel_color(fx, n, fx->_color);
+       set_pixel_color(fx, m, fx->_color);
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
+       fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
+}
+
+
+/*
+ * White running on fx->_color.
+ */
+static void mode_chase_color(struct ws2812fx* fx)
+{
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               set_pixel_color(fx, i, fx->_color);
+       }
+
+       uint16_t n = fx->_counter_mode_step;
+       uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
+       set_pixel_color(fx, n, WHITE);
+       set_pixel_color(fx, m, WHITE);
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
+       fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
+}
+
+
+/*
+ * White running followed by random color.
+ */
+static void mode_chase_random(struct ws2812fx* fx)
+{
+       if (fx->_counter_mode_step == 0) {
+               set_pixel_color(fx, fx->_led_count-1, color_wheel(fx->_mode_color));
+               fx->_mode_color = get_random_wheel_index(fx->_mode_color);
+       }
+
+       for (uint16_t i=0; i < fx->_counter_mode_step; i++) {
+               set_pixel_color(fx, i, color_wheel(fx->_mode_color));
+       }
+
+       uint16_t n = fx->_counter_mode_step;
+       uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
+       set_pixel_color(fx, n, WHITE);
+       set_pixel_color(fx, m, WHITE);
+
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
+       fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
+}
+
+
+/*
+ * White running on rainbow.
+ */
+static void mode_chase_rainbow(struct ws2812fx* fx)
+{
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               set_pixel_color(fx, i, color_wheel(((i * 256 / fx->_led_count) + (fx->_counter_mode_call % 256)) % 256));
+       }
+
+       uint16_t n = fx->_counter_mode_step;
+       uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
+       set_pixel_color(fx, n, WHITE);
+       set_pixel_color(fx, m, WHITE);
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
+       fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
+}
+
+
+/*
+ * White flashes running on fx->_color.
+ */
+static void mode_chase_flash(struct ws2812fx* fx)
+{
+       const static uint8_t flash_count = 4;
+       uint8_t flash_step = fx->_counter_mode_call % ((flash_count * 2) + 1);
+
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               set_pixel_color(fx, i, fx->_color);
+       }
+
+       if (flash_step < (flash_count * 2)) {
+               if (flash_step % 2 == 0) {
+                       uint16_t n = fx->_counter_mode_step;
+                       uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
+                       set_pixel_color(fx, n, WHITE);
+                       set_pixel_color(fx, m, WHITE);
+                       fx->_mode_delay = 20;
+               } else {
+                       fx->_mode_delay = 30;
+               }
+       } else {
+               fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
+               fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
+       }
+
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+}
+
+
+/*
+ * White flashes running, followed by random color.
+ */
+static void mode_chase_flash_random(struct ws2812fx* fx)
+{
+       const static uint8_t flash_count = 4;
+       uint8_t flash_step = fx->_counter_mode_call % ((flash_count * 2) + 1);
+
+       for (uint16_t i=0; i < fx->_counter_mode_step; i++) {
+               set_pixel_color(fx, i, color_wheel(fx->_mode_color));
+       }
+
+       if (flash_step < (flash_count * 2)) {
+               uint16_t n = fx->_counter_mode_step;
+               uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
+               if (flash_step % 2 == 0) {
+                       set_pixel_color(fx, n, WHITE);
+                       set_pixel_color(fx, m, WHITE);
+                       fx->_mode_delay = 20;
+               } else {
+                       set_pixel_color(fx, n, color_wheel(fx->_mode_color));
+                       set_pixel_color(fx, m, BLACK);
+                       fx->_mode_delay = 30;
+               }
+       } else {
+               fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
+               fx->_mode_delay = 1 + ((10 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
+
+               if (fx->_counter_mode_step == 0) {
+                       fx->_mode_color = get_random_wheel_index(fx->_mode_color);
+               }
+       }
+
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+}
+
+
+/*
+ * Rainbow running on white.
+ */
+static void mode_chase_rainbow_white(struct ws2812fx* fx)
+{
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               set_pixel_color(fx, i, WHITE);
+       }
+
+       uint16_t n = fx->_counter_mode_step;
+       uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
+       set_pixel_color(fx, n, color_wheel(((n * 256 / fx->_led_count) + (fx->_counter_mode_call % 256)) % 256));
+       set_pixel_color(fx, m, color_wheel(((m * 256 / fx->_led_count) + (fx->_counter_mode_call % 256)) % 256));
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
+       fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
+}
+
+
+/*
+ * Black running on fx->_color.
+ */
+static void mode_chase_blackout(struct ws2812fx* fx)
+{
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               set_pixel_color(fx, i, fx->_color);
+       }
+
+       uint16_t n = fx->_counter_mode_step;
+       uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
+       set_pixel_color(fx, n, BLACK);
+       set_pixel_color(fx, m, BLACK);
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
+       fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
+}
+
+
+/*
+ * Black running on rainbow.
+ */
+static void mode_chase_blackout_rainbow(struct ws2812fx* fx)
+{
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               set_pixel_color(fx, i, color_wheel(((i * 256 / fx->_led_count) + (fx->_counter_mode_call % 256)) % 256));
+       }
+
+       uint16_t n = fx->_counter_mode_step;
+       uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
+       set_pixel_color(fx, n, BLACK);
+       set_pixel_color(fx, m, BLACK);
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
+       fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
+}
+
+
+/*
+ * Random color intruduced alternating from start and end of strip.
+ */
+static void mode_color_sweep_random(struct ws2812fx* fx)
+{
+       if (fx->_counter_mode_step == 0 || fx->_counter_mode_step == fx->_led_count) {
+               fx->_mode_color = get_random_wheel_index(fx->_mode_color);
+       }
+
+       if (fx->_counter_mode_step < fx->_led_count) {
+               set_pixel_color(fx, fx->_counter_mode_step, color_wheel(fx->_mode_color));
+       } else {
+               set_pixel_color(fx, (fx->_led_count * 2) - fx->_counter_mode_step - 1, color_wheel(fx->_mode_color));
+       }
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % (fx->_led_count * 2);
+       fx->_mode_delay = 5 + ((50 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
+}
+
+
+/*
+ * Alternating color/white pixels running.
+ */
+static void mode_running_color(struct ws2812fx* fx)
+{
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               if ((i + fx->_counter_mode_step) % 4 < 2) {
+                       set_pixel_color(fx, i, fx->_mode_color);
+               } else {
+                       set_pixel_color(fx, i, WHITE);
+               }
+       }
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 4;
+       fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
+}
+
+
+/*
+ * Alternating red/blue pixels running.
+ */
+static void mode_running_red_blue(struct ws2812fx* fx)
+{
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               if ((i + fx->_counter_mode_step) % 4 < 2) {
+                       set_pixel_color(fx, i, RED);
+               } else {
+                       set_pixel_color(fx, i, BLUE);
+               }
+       }
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 4;
+       fx->_mode_delay = 100 + ((100 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
+}
+
+
+/*
+ * Random colored pixels running.
+ */
+static void mode_running_random(struct ws2812fx* fx)
+{
+       for (uint16_t i=fx->_led_count-1; i > 0; i--) {
+               set_pixel_color(fx, i, get_pixel_color(fx, i-1));
+       }
+
+       if (fx->_counter_mode_step == 0) {
+               fx->_mode_color = get_random_wheel_index(fx->_mode_color);
+               set_pixel_color(fx, 0, color_wheel(fx->_mode_color));
+       }
+
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 2;
+
+       fx->_mode_delay = 50 + ((50 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
+}
+
+
+/*
+ * K.I.T.T.
+ */
+static void mode_larson_scanner(struct ws2812fx* fx)
+{
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               uint32_t px_rgb = get_pixel_color(fx, i);
+
+               uint8_t px_r = (px_rgb & 0x00FF0000) >> 16;
+               uint8_t px_g = (px_rgb & 0x0000FF00) >>  8;
+               uint8_t px_b = (px_rgb & 0x000000FF) >>  0;
+
+               // fade out (divide by 2)
+               px_r = px_r >> 1;
+               px_g = px_g >> 1;
+               px_b = px_b >> 1;
+
+               set_pixel_rgb_color(fx, i, px_r, px_g, px_b);
+       }
+
+       uint16_t pos = 0;
+
+       if (fx->_counter_mode_step < fx->_led_count) {
+               pos = fx->_counter_mode_step;
+       } else {
+               pos = (fx->_led_count * 2) - fx->_counter_mode_step - 2;
+       }
+
+       set_pixel_color(fx, pos, fx->_color);
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % ((fx->_led_count * 2) - 2);
+       fx->_mode_delay = 10 + ((10 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
+}
+
+
+/*
+ * Fireing comets from one end.
+ */
+static void mode_comet(struct ws2812fx* fx)
+{
+
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               uint32_t px_rgb = get_pixel_color(fx, i);
+
+               uint8_t px_r = (px_rgb & 0x00FF0000) >> 16;
+               uint8_t px_g = (px_rgb & 0x0000FF00) >>  8;
+               uint8_t px_b = (px_rgb & 0x000000FF) >>  0;
+
+               // fade out (divide by 2)
+               px_r = px_r >> 1;
+               px_g = px_g >> 1;
+               px_b = px_b >> 1;
+
+               set_pixel_rgb_color(fx, i, px_r, px_g, px_b);
+       }
+
+       set_pixel_color(fx, fx->_counter_mode_step, fx->_color);
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
+       fx->_mode_delay = 10 + ((10 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
+}
+
+
+/*
+ * Firework sparks.
+ */
+static void mode_fireworks(struct ws2812fx* fx)
+{
+       uint32_t px_rgb = 0;
+       uint8_t px_r = 0;
+       uint8_t px_g = 0;
+       uint8_t px_b = 0;
+
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               px_rgb = get_pixel_color(fx, i);
+
+               px_r = (px_rgb & 0x00FF0000) >> 16;
+               px_g = (px_rgb & 0x0000FF00) >>  8;
+               px_b = (px_rgb & 0x000000FF) >>  0;
+
+               // fade out (divide by 2)
+               px_r = px_r >> 1;
+               px_g = px_g >> 1;
+               px_b = px_b >> 1;
+
+               set_pixel_rgb_color(fx, i, px_r, px_g, px_b);
+       }
+
+       // first LED has only one neighbour
+       px_r = (((get_pixel_color(fx, 1) & 0x00FF0000) >> 16) >> 1) + ((get_pixel_color(fx, 0) & 0x00FF0000) >> 16);
+       px_g = (((get_pixel_color(fx, 1) & 0x0000FF00) >>  8) >> 1) + ((get_pixel_color(fx, 0) & 0x0000FF00) >>  8);
+       px_b = (((get_pixel_color(fx, 1) & 0x000000FF) >>  0) >> 1) + ((get_pixel_color(fx, 0) & 0x000000FF) >>  0);
+       set_pixel_rgb_color(fx, 0, px_r, px_g, px_b);
+
+       // set brightness(i) = ((brightness(i-1)/2 + brightness(i+1)) / 2) + brightness(i)
+       for (uint16_t i=1; i < fx->_led_count-1; i++) {
+               px_r = ((
+                                       (((get_pixel_color(fx, i-1) & 0x00FF0000) >> 16) >> 1) +
+                                       (((get_pixel_color(fx, i+1) & 0x00FF0000) >> 16) >> 0) ) >> 1) +
+                       (((get_pixel_color(fx, i  ) & 0x00FF0000) >> 16) >> 0);
+
+               px_g = ((
+                                       (((get_pixel_color(fx, i-1) & 0x0000FF00) >> 8) >> 1) +
+                                       (((get_pixel_color(fx, i+1) & 0x0000FF00) >> 8) >> 0) ) >> 1) +
+                       (((get_pixel_color(fx, i  ) & 0x0000FF00) >> 8) >> 0);
+
+               px_b = ((
+                                       (((get_pixel_color(fx, i-1) & 0x000000FF) >> 0) >> 1) +
+                                       (((get_pixel_color(fx, i+1) & 0x000000FF) >> 0) >> 0) ) >> 1) +
+                       (((get_pixel_color(fx, i  ) & 0x000000FF) >> 0) >> 0);
+
+               set_pixel_rgb_color(fx, i, px_r, px_g, px_b);
+       }
+
+       // last LED has only one neighbour
+       px_r = (((get_pixel_color(fx, fx->_led_count-2) & 0x00FF0000) >> 16) >> 2) + ((get_pixel_color(fx, fx->_led_count-1) & 0x00FF0000) >> 16);
+       px_g = (((get_pixel_color(fx, fx->_led_count-2) & 0x0000FF00) >>  8) >> 2) + ((get_pixel_color(fx, fx->_led_count-1) & 0x0000FF00) >>  8);
+       px_b = (((get_pixel_color(fx, fx->_led_count-2) & 0x000000FF) >>  0) >> 2) + ((get_pixel_color(fx, fx->_led_count-1) & 0x000000FF) >>  0);
+       set_pixel_rgb_color(fx, fx->_led_count-1, px_r, px_g, px_b);
+
+       if (!fx->_triggered) {
+               for (uint16_t i=0; i<max(1,fx->_led_count/20); i++) {
+                       if (random(10) == 0) {
+                               set_pixel_color(fx, random(fx->_led_count), fx->_mode_color);
+                       }
+               }
+       } else {
+               for (uint16_t i=0; i<max(1,fx->_led_count/10); i++) {
+                       set_pixel_color(fx, random(fx->_led_count), fx->_mode_color);
+               }
+       }
+
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_mode_delay = 20 + ((20 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
+}
+
+
+/*
+ * Random colored firework sparks.
+ */
+static void mode_fireworks_random(struct ws2812fx* fx)
+{
+       fx->_mode_color = color_wheel(random(256));
+       mode_fireworks(fx);
+}
+
+
+/*
+ * Alternating red/green pixels running.
+ */
+static void mode_merry_christmas(struct ws2812fx* fx)
+{
+       for (uint16_t i=0; i < fx->_led_count; i++) {
+               if ((i + fx->_counter_mode_step) % 4 < 2) {
+                       set_pixel_color(fx, i, RED);
+               } else {
+                       set_pixel_color(fx, i, GREEN);
+               }
+       }
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+
+       fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 4;
+       fx->_mode_delay = 100 + ((100 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
+}
+
+
+static void mode_fire_flicker_int(struct ws2812fx* fx, int rev_intensity)
+{
+       uint8_t p_r = (fx->_color & 0x00FF0000) >> 16;
+       uint8_t p_g = (fx->_color & 0x0000FF00) >>  8;
+       uint8_t p_b = (fx->_color & 0x000000FF) >>  0;
+       uint8_t flicker_val = max(p_r,max(p_g, p_b))/rev_intensity;
+       for (uint16_t i=0; i < fx->_led_count; i++)
+       {
+               int flicker = random(flicker_val);
+               int r1 = p_r-flicker;
+               int g1 = p_g-flicker;
+               int b1 = p_b-flicker;
+               if (g1<0) g1=0;
+               if (r1<0) r1=0;
+               if (b1<0) b1=0;
+               set_pixel_rgb_color(fx, i, r1, g1, b1);
+       }
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+       fx->_mode_delay = 10 + ((500 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
+}
+
+/*
+ * Random flickering.
+ */
+static void mode_fire_flicker(struct ws2812fx* fx)
+{
+       mode_fire_flicker_int(fx, 3);
+}
+
+/*
+ * Random flickering, less intesity.
+ */
+static void mode_fire_flicker_soft(struct ws2812fx* fx)
+{
+       mode_fire_flicker_int(fx, 6);
+}
+
+
+typedef void (*mode_ptr)(struct ws2812fx* fx);
+
+static struct {
+       mode_ptr _fn;
+       char *_name;
+} const modes[] = {
+       { mode_static,                  "Static" },
+       { mode_blink,                   "Blink" },
+       { mode_breath,                  "Breath" },
+       { mode_color_wipe,              "Color Wipe" },
+       { mode_color_wipe_random,       "Color Wipe Random" },
+       { mode_random_color,            "Random Color" },
+       { mode_single_dynamic,          "Single Dynamic" },
+       { mode_multi_dynamic,           "Multi Dynamic" },
+       { mode_rainbow,                 "Rainbow" },
+       { mode_rainbow_cycle,           "Rainbow Cycle" },
+       { mode_theater_chase,           "Theater Chase" },
+       { mode_theater_chase_rainbow,   "Theater Chase Rainbow" },
+       { mode_scan,                    "Scan" },
+       { mode_dual_scan,               "Dual Scan" },
+       { mode_fade,                    "Fade" },
+#if 0
+       { mode_running_lights,          "Running Lights" },
+#endif
+       { mode_twinkle,                 "Twinkle" },
+       { mode_twinkle_random,          "Twinkle Random" },
+       { mode_twinkle_fade,            "Twinkle Fade" },
+       { mode_twinkle_fade_random,     "Twinkle Fade Random" },
+       { mode_sparkle,                 "Sparkle" },
+       { mode_flash_sparkle,           "Flash Sparkle" },
+       { mode_hyper_sparkle,           "Hyper Sparkle" },
+       { mode_strobe,                  "Strobe" },
+       { mode_strobe_rainbow,          "Strobe Rainbow" },
+       { mode_multi_strobe,            "Multi Strobe" },
+       { mode_blink_rainbow,           "Blink Rainbow" },
+       { mode_chase_white,             "Chase White" },
+       { mode_chase_color,             "Chase Color" },
+       { mode_chase_random,            "Chase Random" },
+       { mode_chase_rainbow,           "Chase Rainbow" },
+       { mode_chase_flash,             "Chase Flash" },
+       { mode_chase_flash_random,      "Chase Flash Random" },
+       { mode_chase_rainbow_white,     "Chase Rainbow White" },
+       { mode_chase_blackout,          "Chase Blackout" },
+       { mode_chase_blackout_rainbow,  "Chase Blackout Rainbow" },
+       { mode_color_sweep_random,      "Color Sweep Random" },
+       { mode_running_color,           "Running Color" },
+       { mode_running_red_blue,        "Running Red Blue" },
+       { mode_running_random,          "Running Random" },
+       { mode_larson_scanner,          "Larson Scanner" },
+       { mode_comet,                   "Comet" },
+       { mode_fireworks,               "Fireworks" },
+       { mode_fireworks_random,        "Fireworks Random" },
+       { mode_merry_christmas,         "Merry Christmas" },
+       { mode_fire_flicker,            "Fire Flicker" },
+       { mode_fire_flicker_soft,       "Fire Flicker (soft)" },
+};
+
+#define CALL_MODE(fx, n) (modes[n]._fn)(fx);
+
+void WS2812FX(struct ws2812fx* fx, uint16_t n, const struct pio *pin)
+{
+       fx->wsconf->nb_leds = n;
+       ws2812_config(fx->wsconf, pin);
+
+       fx->_speed = FX_DEFAULT_SPEED;
+       fx->_brightness = FX_DEFAULT_BRIGHTNESS;
+       fx->_running = 0;
+       fx->_led_count = n;
+       fx->_mode_last_call_time = 0;
+       fx->_mode_delay = 0;
+       fx->_color = FX_DEFAULT_COLOR;
+       fx->_mode_color = FX_DEFAULT_COLOR;
+       fx->_counter_mode_call = 0;
+       fx->_counter_mode_step = 0;
+}
+
+void FX_init(struct ws2812fx* fx)
+{
+       FX_setBrightness(fx, fx->_brightness);
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+}
+
+void FX_service(struct ws2812fx* fx)
+{
+       if (fx->_running || fx->_triggered) {
+               unsigned long now = millis();
+
+               if (now - fx->_mode_last_call_time > fx->_mode_delay || fx->_triggered) {
+                       CALL_MODE(fx, fx->_mode_index);
+                       fx->_counter_mode_call++;
+                       fx->_mode_last_call_time = now;
+                       fx->_triggered = 0;
+               }
+       }
+}
+
+void FX_start(struct ws2812fx* fx)
+{
+       fx->_counter_mode_call = 0;
+       fx->_counter_mode_step = 0;
+       fx->_mode_last_call_time = 0;
+       fx->_running = 1;
+}
+
+void FX_stop(struct ws2812fx* fx)
+{
+       fx->_running = 0;
+       strip_off(fx);
+}
+
+void FX_trigger(struct ws2812fx* fx)
+{
+       fx->_triggered = 1;
+}
+
+void FX_setMode(struct ws2812fx* fx, uint8_t m)
+{
+       fx->_counter_mode_call = 0;
+       fx->_counter_mode_step = 0;
+       fx->_mode_last_call_time = 0;
+       fx->_mode_index = constrain(m, 0, FX_MODE_COUNT-1);
+       fx->_mode_color = fx->_color;
+       ws2812_set_brightness(fx->wsconf, fx->_brightness);
+       //strip_off(fx);
+}
+
+void FX_setSpeed(struct ws2812fx* fx, uint8_t s)
+{
+       fx->_counter_mode_call = 0;
+       fx->_counter_mode_step = 0;
+       fx->_mode_last_call_time = 0;
+       fx->_speed = constrain(s, FX_SPEED_MIN, FX_SPEED_MAX);
+       //strip_off(fx);
+}
+
+void FX_increaseSpeed(struct ws2812fx* fx, uint8_t s)
+{
+       s = constrain(fx->_speed + s, FX_SPEED_MIN, FX_SPEED_MAX);
+       FX_setSpeed(fx, s);
+}
+
+void FX_decreaseSpeed(struct ws2812fx* fx, uint8_t s)
+{
+       s = constrain(fx->_speed - s, FX_SPEED_MIN, FX_SPEED_MAX);
+       FX_setSpeed(fx, s);
+}
+
+void FX_setRGBColor(struct ws2812fx* fx, uint8_t r, uint8_t g, uint8_t b)
+{
+       FX_setColor(fx, ((uint32_t)r << 16) | ((uint32_t)g << 8) | b);
+}
+
+void FX_setColor(struct ws2812fx* fx, uint32_t c)
+{
+       fx->_color = c;
+       fx->_counter_mode_call = 0;
+       fx->_counter_mode_step = 0;
+       fx->_mode_last_call_time = 0;
+       fx->_mode_color = fx->_color;
+       ws2812_set_brightness(fx->wsconf, fx->_brightness);
+       //strip_off(fx);
+}
+
+void FX_setBrightness(struct ws2812fx* fx, uint8_t b)
+{
+       fx->_brightness = constrain(b, FX_BRIGHTNESS_MIN, FX_BRIGHTNESS_MAX);
+       ws2812_set_brightness(fx->wsconf, fx->_brightness);
+       ws2812_send_frame(fx->wsconf, fx->_led_count);
+}
+
+void FX_increaseBrightness(struct ws2812fx* fx, uint8_t s)
+{
+       s = constrain(fx->_brightness + s, FX_BRIGHTNESS_MIN, FX_BRIGHTNESS_MAX);
+       FX_setBrightness(fx, s);
+}
+
+void FX_decreaseBrightness(struct ws2812fx* fx, uint8_t s)
+{
+       s = constrain(fx->_brightness - s, FX_BRIGHTNESS_MIN, FX_BRIGHTNESS_MAX);
+       FX_setBrightness(fx, s);
+}
+
+int FX_isRunning(struct ws2812fx* fx)
+{
+       return fx->_running;
+}
+
+uint8_t FX_getMode(struct ws2812fx* fx)
+{
+       return fx->_mode_index;
+}
+
+uint8_t FX_getSpeed(struct ws2812fx* fx)
+{
+       return fx->_speed;
+}
+
+uint8_t FX_getBrightness(struct ws2812fx* fx)
+{
+       return fx->_brightness;
+}
+
+uint8_t FX_getModeCount(struct ws2812fx* fx)
+{
+       return FX_MODE_COUNT;
+}
+
+uint32_t FX_getColor(struct ws2812fx* fx)
+{
+       return fx->_color;
+}
+
+const char* FX_getModeName(uint8_t m)
+{
+       if (m < FX_MODE_COUNT) {
+               return modes[m]._name;
+       } else {
+               return "";
+       }
+}
diff --git a/include/extdrv/ws2812fx.h b/include/extdrv/ws2812fx.h
deleted file mode 100644 (file)
index df00f2e..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
-  WS2812FX.h - Library for WS2812 LED effects.
-
-  Harm Aldick - 2016
-  www.aldick.org
-  FEATURES
-/    * A lot of blinken modes and countin2
-    * WS2812FX can be used as drop-in replacement for Adafruit Neopixel Library
-  NOTES
-    * Uses the Adafruit Neopixel library. Get it here:
-      https://github.com/adafruit/Adafruit_NeoPixel
-  LICENSE
-  The MIT License (MIT)
-  Copyright (c) 2016  Harm Aldick
-  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
-  2016-05-28   Initial beta release
-  2016-06-03   Code cleanup, minor improvements, new modes
-  2016-06-04   2 new fx, fixed setColor (now also resets _mode_color)
-  2017-02-02   added external trigger functionality (e.g. for sound-to-light)
-*/
-
-#ifndef WS2812FX_h
-#define WS2812FX_h
-
-#include "core/pio.h"
-#include "extdrv/ws2812.h"
-
-#define FX_DEFAULT_BRIGHTNESS 50
-#define FX_DEFAULT_MODE 0
-#define FX_DEFAULT_SPEED 150
-#define FX_DEFAULT_COLOR 0xFF0000
-
-#define FX_SPEED_MIN 0
-#define FX_SPEED_MAX 255
-
-#define FX_BRIGHTNESS_MIN 0
-#define FX_BRIGHTNESS_MAX 255
-
-enum ModeFX {
-       FX_MODE_STATIC,
-       FX_MODE_BLINK,
-       FX_MODE_BREATH,
-       FX_MODE_COLOR_WIPE,
-       FX_MODE_COLOR_WIPE_RANDOM,
-       FX_MODE_RANDOM_COLOR,
-       FX_MODE_SINGLE_DYNAMIC,
-       FX_MODE_MULTI_DYNAMIC,
-       FX_MODE_RAINBOW,
-       FX_MODE_RAINBOW_CYCLE,
-       FX_MODE_THEATER_CHASE,
-       FX_MODE_THEATER_CHASE_RAINBOW,
-       FX_MODE_SCAN,
-       FX_MODE_DUAL_SCAN,
-       FX_MODE_FADE,
-#if 0
-       FX_MODE_RUNNING_LIGHTS,
-#endif
-       FX_MODE_TWINKLE,
-       FX_MODE_TWINKLE_RANDOM,
-       FX_MODE_TWINKLE_FADE,
-       FX_MODE_TWINKLE_FADE_RANDOM,
-       FX_MODE_SPARKLE,
-       FX_MODE_FLASH_SPARKLE,
-       FX_MODE_HYPER_SPARKLE,
-       FX_MODE_STROBE,
-       FX_MODE_STROBE_RAINBOW,
-       FX_MODE_MULTI_STROBE,
-       FX_MODE_BLINK_RAINBOW,
-       FX_MODE_CHASE_WHITE,
-       FX_MODE_CHASE_COLOR,
-       FX_MODE_CHASE_RANDOM,
-       FX_MODE_CHASE_RAINBOW,
-       FX_MODE_CHASE_FLASH,
-       FX_MODE_CHASE_FLASH_RANDOM,
-       FX_MODE_CHASE_RAINBOW_WHITE,
-       FX_MODE_CHASE_BLACKOUT,
-       FX_MODE_CHASE_BLACKOUT_RAINBOW,
-       FX_MODE_COLOR_SWEEP_RANDOM,
-       FX_MODE_RUNNING_COLOR,
-       FX_MODE_RUNNING_RED_BLUE,
-       FX_MODE_RUNNING_RANDOM,
-       FX_MODE_LARSON_SCANNER,
-       FX_MODE_COMET,
-       FX_MODE_FIREWORKS,
-       FX_MODE_FIREWORKS_RANDOM,
-       FX_MODE_MERRY_CHRISTMAS,
-       FX_MODE_FIRE_FLICKER,
-       FX_MODE_FIRE_FLICKER_SOFT,
-       FX_MODE_COUNT
-};
-
-struct ws2812fx {
-       struct ws2812_conf* wsconf;
-       int _running;
-       int _triggered;
-
-       uint32_t _color;
-       uint32_t _counter_mode_call;
-       uint32_t _counter_mode_step;
-       uint32_t _mode_color;
-       uint32_t _mode_delay;
-
-       unsigned long _mode_last_call_time;
-
-       uint16_t _led_count;
-
-       uint8_t _mode_index;
-       uint8_t _speed;
-       uint8_t _brightness;
-};
-
-void WS2812FX(struct ws2812fx* fx, uint16_t n, const struct pio* pin);
-
-void FX_init(struct ws2812fx* fx);
-void FX_service(struct ws2812fx* fx);
-void FX_start(struct ws2812fx* fx);
-void FX_stop(struct ws2812fx* fx);
-void FX_setMode(struct ws2812fx* fx, uint8_t m);
-void FX_setSpeed(struct ws2812fx* fx, uint8_t s);
-void FX_increaseSpeed(struct ws2812fx* fx, uint8_t s);
-void FX_decreaseSpeed(struct ws2812fx* fx, uint8_t s);
-void FX_setRGBColor(struct ws2812fx* fx, uint8_t r, uint8_t g, uint8_t b);
-void FX_setColor(struct ws2812fx* fx, uint32_t c);
-void FX_trigger(struct ws2812fx* fx);
-void FX_setBrightness(struct ws2812fx* fx, uint8_t b);
-void FX_increaseBrightness(struct ws2812fx* fx, uint8_t s);
-void FX_decreaseBrightness(struct ws2812fx* fx, uint8_t s);
-
-int FX_isRunning(struct ws2812fx* fx);
-
-uint8_t FX_getMode(struct ws2812fx* fx);
-uint8_t FX_getSpeed(struct ws2812fx* fx);
-uint8_t FX_getBrightness(struct ws2812fx* fx);
-uint8_t FX_getModeCount(struct ws2812fx* fx);
-
-uint32_t FX_getColor(struct ws2812fx* fx);
-
-const char* FX_getModeName(uint8_t m);
-
-#endif
diff --git a/include/extlib/ws2812fx/ws2812fx.h b/include/extlib/ws2812fx/ws2812fx.h
new file mode 100644 (file)
index 0000000..51b1cc7
--- /dev/null
@@ -0,0 +1,158 @@
+/****************************************************************************
+ *
+ * include/extlib/ws2812fx/ws2812fx.h - Library for WS2812 LED effects.
+ *
+ * Fork from Harm Aldick's work - 2016 - www.aldick.org
+ * https://github.com/kitesurfer1404/WS2812FX.git
+ *
+ * FEATURES
+ *  - A lot of blinken modes and counting
+ *  - WS2812FX can be used as drop-in replacement for Adafruit Neopixel Library
+ *
+ * LICENSE
+ * The MIT License (MIT)
+ * Copyright (c) 2016  Harm Aldick
+ * 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
+ * 2016-05-28   Initial beta release
+ * 2016-06-03   Code cleanup, minor improvements, new modes
+ * 2016-06-04   2 new fx, fixed setColor (now also resets _mode_color)
+ * 2017-02-02   added external trigger functionality (e.g. for sound-to-light)
+ * 2017-02-02   removed "blackout" on mode, speed or color-change
+ *
+ *************************************************************************** */
+
+#ifndef WS2812FX_h
+#define WS2812FX_h
+
+#include "core/pio.h"
+#include "extdrv/ws2812.h"
+
+#define FX_DEFAULT_BRIGHTNESS 50
+#define FX_DEFAULT_MODE 0
+#define FX_DEFAULT_SPEED 150
+#define FX_DEFAULT_COLOR 0xFF0000
+
+#define FX_SPEED_MIN 0
+#define FX_SPEED_MAX 255
+
+#define FX_BRIGHTNESS_MIN 0
+#define FX_BRIGHTNESS_MAX 255
+
+enum ModeFX {
+       FX_MODE_STATIC,
+       FX_MODE_BLINK,
+       FX_MODE_BREATH,
+       FX_MODE_COLOR_WIPE,
+       FX_MODE_COLOR_WIPE_RANDOM,
+       FX_MODE_RANDOM_COLOR,
+       FX_MODE_SINGLE_DYNAMIC,
+       FX_MODE_MULTI_DYNAMIC,
+       FX_MODE_RAINBOW,
+       FX_MODE_RAINBOW_CYCLE,
+       FX_MODE_THEATER_CHASE,
+       FX_MODE_THEATER_CHASE_RAINBOW,
+       FX_MODE_SCAN,
+       FX_MODE_DUAL_SCAN,
+       FX_MODE_FADE,
+#if 0
+       FX_MODE_RUNNING_LIGHTS,
+#endif
+       FX_MODE_TWINKLE,
+       FX_MODE_TWINKLE_RANDOM,
+       FX_MODE_TWINKLE_FADE,
+       FX_MODE_TWINKLE_FADE_RANDOM,
+       FX_MODE_SPARKLE,
+       FX_MODE_FLASH_SPARKLE,
+       FX_MODE_HYPER_SPARKLE,
+       FX_MODE_STROBE,
+       FX_MODE_STROBE_RAINBOW,
+       FX_MODE_MULTI_STROBE,
+       FX_MODE_BLINK_RAINBOW,
+       FX_MODE_CHASE_WHITE,
+       FX_MODE_CHASE_COLOR,
+       FX_MODE_CHASE_RANDOM,
+       FX_MODE_CHASE_RAINBOW,
+       FX_MODE_CHASE_FLASH,
+       FX_MODE_CHASE_FLASH_RANDOM,
+       FX_MODE_CHASE_RAINBOW_WHITE,
+       FX_MODE_CHASE_BLACKOUT,
+       FX_MODE_CHASE_BLACKOUT_RAINBOW,
+       FX_MODE_COLOR_SWEEP_RANDOM,
+       FX_MODE_RUNNING_COLOR,
+       FX_MODE_RUNNING_RED_BLUE,
+       FX_MODE_RUNNING_RANDOM,
+       FX_MODE_LARSON_SCANNER,
+       FX_MODE_COMET,
+       FX_MODE_FIREWORKS,
+       FX_MODE_FIREWORKS_RANDOM,
+       FX_MODE_MERRY_CHRISTMAS,
+       FX_MODE_FIRE_FLICKER,
+       FX_MODE_FIRE_FLICKER_SOFT,
+       FX_MODE_COUNT
+};
+
+struct ws2812fx {
+       struct ws2812_conf* wsconf;
+       int _running;
+       int _triggered;
+
+       uint32_t _color;
+       uint32_t _counter_mode_call;
+       uint32_t _counter_mode_step;
+       uint32_t _mode_color;
+       uint32_t _mode_delay;
+
+       unsigned long _mode_last_call_time;
+
+       uint16_t _led_count;
+
+       uint8_t _mode_index;
+       uint8_t _speed;
+       uint8_t _brightness;
+};
+
+void WS2812FX(struct ws2812fx* fx, uint16_t n, const struct pio* pin);
+
+void FX_init(struct ws2812fx* fx);
+void FX_service(struct ws2812fx* fx);
+void FX_start(struct ws2812fx* fx);
+void FX_stop(struct ws2812fx* fx);
+void FX_setMode(struct ws2812fx* fx, uint8_t m);
+void FX_setSpeed(struct ws2812fx* fx, uint8_t s);
+void FX_increaseSpeed(struct ws2812fx* fx, uint8_t s);
+void FX_decreaseSpeed(struct ws2812fx* fx, uint8_t s);
+void FX_setRGBColor(struct ws2812fx* fx, uint8_t r, uint8_t g, uint8_t b);
+void FX_setColor(struct ws2812fx* fx, uint32_t c);
+void FX_trigger(struct ws2812fx* fx);
+void FX_setBrightness(struct ws2812fx* fx, uint8_t b);
+void FX_increaseBrightness(struct ws2812fx* fx, uint8_t s);
+void FX_decreaseBrightness(struct ws2812fx* fx, uint8_t s);
+
+int FX_isRunning(struct ws2812fx* fx);
+
+uint8_t FX_getMode(struct ws2812fx* fx);
+uint8_t FX_getSpeed(struct ws2812fx* fx);
+uint8_t FX_getBrightness(struct ws2812fx* fx);
+uint8_t FX_getModeCount(struct ws2812fx* fx);
+
+uint32_t FX_getColor(struct ws2812fx* fx);
+
+const char* FX_getModeName(uint8_t m);
+
+#endif