Adding ws2812fx lib and its single-led version ws2812sfx
[lpc1224] / extdrv / ws2812fx.c
1 /*
2   WS2812FX.cpp - Library for WS2812 LED effects.
3   Harm Aldick - 2016
4   www.aldick.org
5   FEATURES
6     * A lot of blinken modes and counting
7     * WS2812FX can be used as drop-in replacement for Adafruit Neopixel Library
8   NOTES
9     * Uses the Adafruit Neopixel library. Get it here:
10       https://github.com/adafruit/Adafruit_NeoPixel
11   LICENSE
12   The MIT License (MIT)
13   Copyright (c) 2016  Harm Aldick
14   Permission is hereby granted, free of charge, to any person obtaining a copy
15   of this software and associated documentation files (the "Software"), to deal
16   in the Software without restriction, including without limitation the rights
17   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18   copies of the Software, and to permit persons to whom the Software is
19   furnished to do so, subject to the following conditions:
20   The above copyright notice and this permission notice shall be included in
21   all copies or substantial portions of the Software.
22   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28   THE SOFTWARE.
29   CHANGELOG
30   2016-05-28   Initial beta release
31   2016-06-03   Code cleanup, minor improvements, new modes
32   2016-06-04   2 new fx, fixed setColor (now also resets _mode_color)
33   2017-02-02   added external trigger functionality (e.g. for sound-to-light)
34   2017-02-02   removed "blackout" on mode, speed or color-change
35 */
37 #include "core/systick.h"
38 #include "extdrv/ws2812.h"
39 #include "extdrv/ws2812fx.h"
41 static uint32_t random(uint32_t max)
42 {
43         static uint32_t seed = 0;
44         /* Numerical Recipes */
45         seed = seed * 1664525 + 1013904223;
46         return seed % max;
47 }
49 static uint32_t abs(int32_t val)
50 {
51         return val < 0 ? -val : val;
52 }
54 static uint32_t min(uint32_t a, uint32_t b)
55 {
56         return a < b ? a : b;
57 }
59 static uint32_t max(uint32_t a, uint32_t b)
60 {
61         return a > b ? a : b;
62 }
64 static unsigned long millis(void)
65 {
66         return systick_get_tick_count();
67 }
69 static uint32_t constrain(int32_t val, int32_t min, int32_t max)
70 {
71         return val < min ? min : val > max ? max : val;
72 }
75 /* #####################################################
76 #
77 #  Color and Blinken Functions
78 #
79 ##################################################### */
81 /*
82  * Turns everything off. Doh.
83  */
84 static void strip_off(ws2812fx_t *fx)
85 {
86         ws2812_clear();
87         ws2812_send_frame(fx->_led_count);
88 }
90 #define WHITE 0xffffff
91 #define RED   0xff0000
92 #define GREEN 0x00ff00
93 #define BLUE  0x0000ff
94 #define BLACK 0x000000
96 static void set_pixel_rgb_color(uint32_t i, uint8_t r, uint8_t g, uint8_t b)
97 {
98         ws2812_set_pixel(i, r, g, b);
99 }
101 static void set_pixel_color(uint32_t i, uint32_t color)
103         ws2812_set_pixel(i, color >> 16, (color >> 8) & 0xff, color & 0xff);
106 static uint32_t get_pixel_color(uint32_t i)
108         uint8_t r, g, b;
109         ws2812_get_pixel(i, &r, &g, &b);
110         return (r << 16) | (g << 8) | b;
113 /*
114  * Put a value 0 to 255 in to get a color value.
115  * The colours are a transition r -> g -> b -> back to r
116  * Inspired by the Adafruit examples.
117  */
118 static uint32_t color_wheel(uint8_t pos)
120         pos = 255 - pos;
121         if(pos < 85) {
122                 return ((uint32_t)(255 - pos * 3) << 16) | ((uint32_t)(0) << 8) | (pos * 3);
123         } else if(pos < 170) {
124                 pos -= 85;
125                 return ((uint32_t)(0) << 16) | ((uint32_t)(pos * 3) << 8) | (255 - pos * 3);
126         } else {
127                 pos -= 170;
128                 return ((uint32_t)(pos * 3) << 16) | ((uint32_t)(255 - pos * 3) << 8) | (0);
129         }
133 /*
134  * Returns a new, random wheel index with a minimum distance of 42 from pos.
135  */
136 static uint8_t get_random_wheel_index(uint8_t pos)
138         uint8_t r = 0;
139         uint8_t x = 0;
140         uint8_t y = 0;
141         uint8_t d = 0;
143         while(d < 42) {
144                 r = random(256);
145                 x = abs(pos - r);
146                 y = 255 - x;
147                 d = min(x, y);
148         }
150         return r;
154 /*
155  * No blinking. Just plain old static light.
156  */
157 static void mode_static(ws2812fx_t *fx)
159         for(uint16_t i=0; i < fx->_led_count; i++) {
160                 set_pixel_color(i, fx->_color);
161         }
162         ws2812_send_frame(fx->_led_count);
164         fx->_mode_delay = 50;
168 /*
169  * Normal blinking. 50% on/off time.
170  */
171 static void mode_blink(ws2812fx_t *fx)
173         if(fx->_counter_mode_call % 2 == 1) {
174                 for(uint16_t i=0; i < fx->_led_count; i++) {
175                         set_pixel_color(i, fx->_color);
176                 }
177                 ws2812_send_frame(fx->_led_count);
178         } else {
179                 strip_off(fx);
180         }
182         fx->_mode_delay = 100 + ((1986 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
186 /*
187  * Lights all LEDs after each other up. Then turns them in
188  * that order off. Repeat.
189  */
190 static void mode_color_wipe(ws2812fx_t *fx)
192         if(fx->_counter_mode_step < fx->_led_count) {
193                 set_pixel_color(fx->_counter_mode_step, fx->_color);
194         } else {
195                 set_pixel_color(fx->_counter_mode_step - fx->_led_count, 0);
196         }
197         ws2812_send_frame(fx->_led_count);
199         fx->_counter_mode_step = (fx->_counter_mode_step + 1) % (fx->_led_count * 2);
201         fx->_mode_delay = 5 + ((50 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
205 /*
206  * Turns all LEDs after each other to a random color.
207  * Then starts over with another color.
208  */
209 static void mode_color_wipe_random(ws2812fx_t *fx)
211         if(fx->_counter_mode_step == 0) {
212                 fx->_mode_color = get_random_wheel_index(fx->_mode_color);
213         }
215         set_pixel_color(fx->_counter_mode_step, color_wheel(fx->_mode_color));
216         ws2812_send_frame(fx->_led_count);
218         fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
220         fx->_mode_delay = 5 + ((50 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
224 /*
225  * Lights all LEDs in one random color up. Then switches them
226  * to the next random color.
227  */
228 static void mode_random_color(ws2812fx_t *fx)
230         fx->_mode_color = get_random_wheel_index(fx->_mode_color);
232         for(uint16_t i=0; i < fx->_led_count; i++) {
233                 set_pixel_color(i, color_wheel(fx->_mode_color));
234         }
236         ws2812_send_frame(fx->_led_count);
237         fx->_mode_delay = 100 + ((5000 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
241 /*
242  * Lights every LED in a random color. Changes one random LED after the other
243  * to another random color.
244  */
245 static void mode_single_dynamic(ws2812fx_t *fx)
247         if(fx->_counter_mode_call == 0) {
248                 for(uint16_t i=0; i < fx->_led_count; i++) {
249                         set_pixel_color(i, color_wheel(random(256)));
250                 }
251         }
253         set_pixel_color(random(fx->_led_count), color_wheel(random(256)));
254         ws2812_send_frame(fx->_led_count);
255         fx->_mode_delay = 10 + ((5000 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
259 /*
260  * Lights every LED in a random color. Changes all LED at the same time
261  * to new random colors.
262  */
263 static void mode_multi_dynamic(ws2812fx_t *fx)
265         for(uint16_t i=0; i < fx->_led_count; i++) {
266                 set_pixel_color(i, color_wheel(random(256)));
267         }
268         ws2812_send_frame(fx->_led_count);
269         fx->_mode_delay = 100 + ((5000 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
273 /*
274  * Does the "standby-breathing" of well known i-Devices. Fixed Speed.
275  * Use mode "fade" if you like to have something similar with a different speed.
276  */
277 static void mode_breath(ws2812fx_t *fx)
279         //                                      0    1    2   3   4   5   6    7   8   9  10  11   12   13   14   15   16    // step
280         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
281         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!
283         if(fx->_counter_mode_call == 0) {
284                 fx->_mode_color = breath_brightness_steps[0] + 1;
285         }
287         uint32_t breath_brightness = fx->_mode_color; // we use fx->_mode_color to store the brightness
289         if(fx->_counter_mode_step < 8) {
290                 breath_brightness--;
291         } else {
292                 breath_brightness++;
293         }
295         // update index of current delay when target brightness is reached, start over after the last step
296         if(breath_brightness == breath_brightness_steps[fx->_counter_mode_step]) {
297                 fx->_counter_mode_step = (fx->_counter_mode_step + 1) % (sizeof(breath_brightness_steps)/sizeof(uint8_t));
298         }
300         for(uint16_t i=0; i < fx->_led_count; i++) {
301                 set_pixel_color(i, fx->_color);           // set all LEDs to selected color
302         }
303         int b = (breath_brightness * (fx->_brightness + 1)) >> 8;  // keep brightness below brightness set by user
304         ws2812_set_brightness(b);
305         ws2812_send_frame(fx->_led_count);
307         fx->_mode_color = breath_brightness;                         // we use fx->_mode_color to store the brightness
308         fx->_mode_delay = breath_delay_steps[fx->_counter_mode_step];
312 /*
313  * Fades the LEDs on and (almost) off again.
314  */
315 static void mode_fade(ws2812fx_t *fx)
317         for(uint16_t i=0; i < fx->_led_count; i++) {
318                 set_pixel_color(i, fx->_color);
319         }
321         int b = fx->_counter_mode_step - 127;
322         b = 255 - (abs(b) * 2);
323         b = (b * (min(20, fx->_brightness) + 1)) >> 8;
324         ws2812_set_brightness(b);
325         ws2812_send_frame(fx->_led_count);
327         fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 255;
328         fx->_mode_delay = 5 + ((15 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
332 /*
333  * Runs a single pixel back and forth.
334  */
335 static void mode_scan(ws2812fx_t *fx)
337         if(fx->_counter_mode_step > (fx->_led_count*2) - 2) {
338                 fx->_counter_mode_step = 0;
339         }
340         fx->_counter_mode_step++;
342         int i = fx->_counter_mode_step - (fx->_led_count - 1);
343         i = abs(i);
345         ws2812_clear();
346         set_pixel_color(abs(i), fx->_color);
347         ws2812_send_frame(fx->_led_count);
349         fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
353 /*
354  * Runs two pixel back and forth in opposite directions.
355  */
356 static void mode_dual_scan(ws2812fx_t *fx)
358         if(fx->_counter_mode_step > (fx->_led_count*2) - 2) {
359                 fx->_counter_mode_step = 0;
360         }
361         fx->_counter_mode_step++;
363         int i = fx->_counter_mode_step - (fx->_led_count - 1);
364         i = abs(i);
366         ws2812_clear();
367         set_pixel_color(i, fx->_color);
368         set_pixel_color(fx->_led_count - (i+1), fx->_color);
369         ws2812_send_frame(fx->_led_count);
371         fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
375 /*
376  * Cycles all LEDs at once through a rainbow.
377  */
378 static void mode_rainbow(ws2812fx_t *fx)
380         uint32_t color = color_wheel(fx->_counter_mode_step);
381         for(uint16_t i=0; i < fx->_led_count; i++) {
382                 set_pixel_color(i, color);
383         }
384         ws2812_send_frame(fx->_led_count);
386         fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 256;
388         fx->_mode_delay = 1 + ((50 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
392 /*
393  * Cycles a rainbow over the entire string of LEDs.
394  */
395 static void mode_rainbow_cycle(ws2812fx_t *fx)
397         for(uint16_t i=0; i < fx->_led_count; i++) {
398                 set_pixel_color(i, color_wheel(((i * 256 / fx->_led_count) + fx->_counter_mode_step) % 256));
399         }
400         ws2812_send_frame(fx->_led_count);
402         fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 256;
404         fx->_mode_delay = 1 + ((50 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
408 /*
409  * Theatre-style crawling lights.
410  * Inspired by the Adafruit examples.
411  */
412 static void mode_theater_chase(ws2812fx_t *fx)
414         uint8_t j = fx->_counter_mode_call % 6;
415         if(j % 2 == 0) {
416                 for(uint16_t i=0; i < fx->_led_count; i=i+3) {
417                         set_pixel_color(i+(j/2), fx->_color);
418                 }
419                 ws2812_send_frame(fx->_led_count);
420                 fx->_mode_delay = 50 + ((500 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
421         } else {
422                 for(uint16_t i=0; i < fx->_led_count; i=i+3) {
423                         set_pixel_color(i+(j/2), 0);
424                 }
425                 fx->_mode_delay = 1;
426         }
430 /*
431  * Theatre-style crawling lights with rainbow effect.
432  * Inspired by the Adafruit examples.
433  */
434 static void mode_theater_chase_rainbow(ws2812fx_t *fx)
436         uint8_t j = fx->_counter_mode_call % 6;
437         if(j % 2 == 0) {
438                 for(uint16_t i=0; i < fx->_led_count; i=i+3) {
439                         set_pixel_color(i+(j/2), color_wheel((i+fx->_counter_mode_step) % 256));
440                 }
441                 ws2812_send_frame(fx->_led_count);
442                 fx->_mode_delay = 50 + ((500 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
443         } else {
444                 for(uint16_t i=0; i < fx->_led_count; i=i+3) {
445                         set_pixel_color(i+(j/2), 0);
446                 }
447                 fx->_mode_delay = 1;
448         }
449         fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 256;
453 #if 0
454 /*
455  * Running lights effect with smooth sine transition.
456  */
457 static void mode_running_lights(ws2812fx_t *fx)
459         uint8_t r = ((fx->_color >> 16) & 0xFF);
460         uint8_t g = ((fx->_color >> 8) & 0xFF);
461         uint8_t b = (fx->_color & 0xFF);
463         for(uint16_t i=0; i < fx->_led_count; i++) {
464                 int s = (sin(i+fx->_counter_mode_call) * 127) + 128;
465                 set_pixel_rgb_color(i, (((uint32_t)(r * s)) / 255), (((uint32_t)(g * s)) / 255), (((uint32_t)(b * s)) / 255));
466         }
468         ws2812_send_frame(fx->_led_count);
470         fx->_mode_delay = 35 + ((350 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
472 #endif
475 /*
476  * Blink several LEDs on, reset, repeat.
477  * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
478  */
479 static void mode_twinkle(ws2812fx_t *fx)
481         if(fx->_counter_mode_step == 0) {
482                 strip_off(fx);
483                 uint16_t min_leds = max(1, fx->_led_count/5); // make sure, at least one LED is on
484                 uint16_t max_leds = max(1, fx->_led_count/2); // make sure, at least one LED is on
485                 fx->_counter_mode_step = min_leds + random(max_leds - min_leds);
486         }
488         set_pixel_color(random(fx->_led_count), fx->_mode_color);
489         ws2812_send_frame(fx->_led_count);
491         fx->_counter_mode_step--;
492         fx->_mode_delay = 50 + ((1986 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
496 /*
497  * Blink several LEDs in random colors on, reset, repeat.
498  * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
499  */
500 static void mode_twinkle_random(ws2812fx_t *fx)
502         fx->_mode_color = color_wheel(random(256));
503         mode_twinkle(fx);
507 /*
508  * Blink several LEDs on, fading out.
509  */
510 static void mode_twinkle_fade(ws2812fx_t *fx)
512         for(uint16_t i=0; i < fx->_led_count; i++) {
513                 uint32_t px_rgb = get_pixel_color(i);
515                 uint8_t px_r = (px_rgb & 0x00FF0000) >> 16;
516                 uint8_t px_g = (px_rgb & 0x0000FF00) >>  8;
517                 uint8_t px_b = (px_rgb & 0x000000FF) >>  0;
519                 // fade out (divide by 2)
520                 px_r = px_r >> 1;
521                 px_g = px_g >> 1;
522                 px_b = px_b >> 1;
524                 set_pixel_rgb_color(i, px_r, px_g, px_b);
525         }
527         if(random(3) == 0) {
528                 set_pixel_color(random(fx->_led_count), fx->_mode_color);
529         }
531         ws2812_send_frame(fx->_led_count);
533         fx->_mode_delay = 100 + ((100 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
537 /*
538  * Blink several LEDs in random colors on, fading out.
539  */
540 static void mode_twinkle_fade_random(ws2812fx_t *fx)
542         fx->_mode_color = color_wheel(random(256));
543         mode_twinkle_fade(fx);
547 /*
548  * Blinks one LED at a time.
549  * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
550  */
551 static void mode_sparkle(ws2812fx_t *fx)
553         ws2812_clear();
554         set_pixel_color(random(fx->_led_count),fx->_color);
555         ws2812_send_frame(fx->_led_count);
556         fx->_mode_delay = 10 + ((200 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
560 /*
561  * Lights all LEDs in the fx->_color. Flashes single white pixels randomly.
562  * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
563  */
564 static void mode_flash_sparkle(ws2812fx_t *fx)
566         for(uint16_t i=0; i < fx->_led_count; i++) {
567                 set_pixel_color(i, fx->_color);
568         }
570         if(random(10) == 7) {
571                 set_pixel_color(random(fx->_led_count), WHITE);
572                 fx->_mode_delay = 20;
573         } else {
574                 fx->_mode_delay = 20 + ((200 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
575         }
577         ws2812_send_frame(fx->_led_count);
581 /*
582  * Like flash sparkle. With more flash.
583  * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
584  */
585 static void mode_hyper_sparkle(ws2812fx_t *fx)
587         for(uint16_t i=0; i < fx->_led_count; i++) {
588                 set_pixel_color(i, fx->_color);
589         }
591         if(random(10) < 4) {
592                 for(uint16_t i=0; i < max(1, fx->_led_count/3); i++) {
593                         set_pixel_color(random(fx->_led_count), WHITE);
594                 }
595                 fx->_mode_delay = 20;
596         } else {
597                 fx->_mode_delay = 15 + ((120 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
598         }
600         ws2812_send_frame(fx->_led_count);
604 /*
605  * Classic Strobe effect.
606  */
607 static void mode_strobe(ws2812fx_t *fx)
609         if(fx->_counter_mode_call % 2 == 0) {
610                 for(uint16_t i=0; i < fx->_led_count; i++) {
611                         set_pixel_color(i, fx->_color);
612                 }
613                 fx->_mode_delay = 20;
614         } else {
615                 for(uint16_t i=0; i < fx->_led_count; i++) {
616                         set_pixel_color(i, 0);
617                 }
618                 fx->_mode_delay = 50 + ((1986 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
619         }
620         ws2812_send_frame(fx->_led_count);
624 /*
625  * Strobe effect with different strobe count and pause, controled by fx->_speed.
626  */
627 static void mode_multi_strobe(ws2812fx_t *fx)
629         for(uint16_t i=0; i < fx->_led_count; i++) {
630                 set_pixel_color(i, 0);
631         }
633         if(fx->_counter_mode_step < (2 * ((fx->_speed / 10) + 1))) {
634                 if(fx->_counter_mode_step % 2 == 0) {
635                         for(uint16_t i=0; i < fx->_led_count; i++) {
636                                 set_pixel_color(i, fx->_color);
637                         }
638                         fx->_mode_delay = 20;
639                 } else {
640                         fx->_mode_delay = 50;
641                 }
643         } else {
644                 fx->_mode_delay = 100 + ((9 - (fx->_speed % 10)) * 125);
645         }
647         ws2812_send_frame(fx->_led_count);
648         fx->_counter_mode_step = (fx->_counter_mode_step + 1) % ((2 * ((fx->_speed / 10) + 1)) + 1);
652 /*
653  * Classic Strobe effect. Cycling through the rainbow.
654  */
655 static void mode_strobe_rainbow(ws2812fx_t *fx)
657         if(fx->_counter_mode_call % 2 == 0) {
658                 for(uint16_t i=0; i < fx->_led_count; i++) {
659                         set_pixel_color(i, color_wheel(fx->_counter_mode_call % 256));
660                 }
661                 fx->_mode_delay = 20;
662         } else {
663                 for(uint16_t i=0; i < fx->_led_count; i++) {
664                         set_pixel_color(i, 0);
665                 }
666                 fx->_mode_delay = 50 + ((1986 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
667         }
668         ws2812_send_frame(fx->_led_count);
672 /*
673  * Classic Blink effect. Cycling through the rainbow.
674  */
675 static void mode_blink_rainbow(ws2812fx_t *fx)
677         if(fx->_counter_mode_call % 2 == 1) {
678                 for(uint16_t i=0; i < fx->_led_count; i++) {
679                         set_pixel_color(i, color_wheel(fx->_counter_mode_call % 256));
680                 }
681                 ws2812_send_frame(fx->_led_count);
682         } else {
683                 strip_off(fx);
684         }
686         fx->_mode_delay = 100 + ((1986 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
690 /*
691  * fx->_color running on white.
692  */
693 static void mode_chase_white(ws2812fx_t *fx)
695         for(uint16_t i=0; i < fx->_led_count; i++) {
696                 set_pixel_color(i, WHITE);
697         }
699         uint16_t n = fx->_counter_mode_step;
700         uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
701         set_pixel_color(n, fx->_color);
702         set_pixel_color(m, fx->_color);
703         ws2812_send_frame(fx->_led_count);
705         fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
706         fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
710 /*
711  * White running on fx->_color.
712  */
713 static void mode_chase_color(ws2812fx_t *fx)
715         for(uint16_t i=0; i < fx->_led_count; i++) {
716                 set_pixel_color(i, fx->_color);
717         }
719         uint16_t n = fx->_counter_mode_step;
720         uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
721         set_pixel_color(n, WHITE);
722         set_pixel_color(m, WHITE);
723         ws2812_send_frame(fx->_led_count);
725         fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
726         fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
730 /*
731  * White running followed by random color.
732  */
733 static void mode_chase_random(ws2812fx_t *fx)
735         if(fx->_counter_mode_step == 0) {
736                 set_pixel_color(fx->_led_count-1, color_wheel(fx->_mode_color));
737                 fx->_mode_color = get_random_wheel_index(fx->_mode_color);
738         }
740         for(uint16_t i=0; i < fx->_counter_mode_step; i++) {
741                 set_pixel_color(i, color_wheel(fx->_mode_color));
742         }
744         uint16_t n = fx->_counter_mode_step;
745         uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
746         set_pixel_color(n, WHITE);
747         set_pixel_color(m, WHITE);
749         ws2812_send_frame(fx->_led_count);
751         fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
752         fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
756 /*
757  * White running on rainbow.
758  */
759 static void mode_chase_rainbow(ws2812fx_t *fx)
761         for(uint16_t i=0; i < fx->_led_count; i++) {
762                 set_pixel_color(i, color_wheel(((i * 256 / fx->_led_count) + (fx->_counter_mode_call % 256)) % 256));
763         }
765         uint16_t n = fx->_counter_mode_step;
766         uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
767         set_pixel_color(n, WHITE);
768         set_pixel_color(m, WHITE);
769         ws2812_send_frame(fx->_led_count);
771         fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
772         fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
776 /*
777  * White flashes running on fx->_color.
778  */
779 static void mode_chase_flash(ws2812fx_t *fx)
781         const static uint8_t flash_count = 4;
782         uint8_t flash_step = fx->_counter_mode_call % ((flash_count * 2) + 1);
784         for(uint16_t i=0; i < fx->_led_count; i++) {
785                 set_pixel_color(i, fx->_color);
786         }
788         if(flash_step < (flash_count * 2)) {
789                 if(flash_step % 2 == 0) {
790                         uint16_t n = fx->_counter_mode_step;
791                         uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
792                         set_pixel_color(n, WHITE);
793                         set_pixel_color(m, WHITE);
794                         fx->_mode_delay = 20;
795                 } else {
796                         fx->_mode_delay = 30;
797                 }
798         } else {
799                 fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
800                 fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
801         }
803         ws2812_send_frame(fx->_led_count);
807 /*
808  * White flashes running, followed by random color.
809  */
810 static void mode_chase_flash_random(ws2812fx_t *fx)
812         const static uint8_t flash_count = 4;
813         uint8_t flash_step = fx->_counter_mode_call % ((flash_count * 2) + 1);
815         for(uint16_t i=0; i < fx->_counter_mode_step; i++) {
816                 set_pixel_color(i, color_wheel(fx->_mode_color));
817         }
819         if(flash_step < (flash_count * 2)) {
820                 uint16_t n = fx->_counter_mode_step;
821                 uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
822                 if(flash_step % 2 == 0) {
823                         set_pixel_color(n, WHITE);
824                         set_pixel_color(m, WHITE);
825                         fx->_mode_delay = 20;
826                 } else {
827                         set_pixel_color(n, color_wheel(fx->_mode_color));
828                         set_pixel_color(m, BLACK);
829                         fx->_mode_delay = 30;
830                 }
831         } else {
832                 fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
833                 fx->_mode_delay = 1 + ((10 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
835                 if(fx->_counter_mode_step == 0) {
836                         fx->_mode_color = get_random_wheel_index(fx->_mode_color);
837                 }
838         }
840         ws2812_send_frame(fx->_led_count);
844 /*
845  * Rainbow running on white.
846  */
847 static void mode_chase_rainbow_white(ws2812fx_t *fx)
849         for(uint16_t i=0; i < fx->_led_count; i++) {
850                 set_pixel_color(i, WHITE);
851         }
853         uint16_t n = fx->_counter_mode_step;
854         uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
855         set_pixel_color(n, color_wheel(((n * 256 / fx->_led_count) + (fx->_counter_mode_call % 256)) % 256));
856         set_pixel_color(m, color_wheel(((m * 256 / fx->_led_count) + (fx->_counter_mode_call % 256)) % 256));
857         ws2812_send_frame(fx->_led_count);
859         fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
860         fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
864 /*
865  * Black running on fx->_color.
866  */
867 static void mode_chase_blackout(ws2812fx_t *fx)
869         for(uint16_t i=0; i < fx->_led_count; i++) {
870                 set_pixel_color(i, fx->_color);
871         }
873         uint16_t n = fx->_counter_mode_step;
874         uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
875         set_pixel_color(n, BLACK);
876         set_pixel_color(m, BLACK);
877         ws2812_send_frame(fx->_led_count);
879         fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
880         fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
884 /*
885  * Black running on rainbow.
886  */
887 static void mode_chase_blackout_rainbow(ws2812fx_t *fx)
889         for(uint16_t i=0; i < fx->_led_count; i++) {
890                 set_pixel_color(i, color_wheel(((i * 256 / fx->_led_count) + (fx->_counter_mode_call % 256)) % 256));
891         }
893         uint16_t n = fx->_counter_mode_step;
894         uint16_t m = (fx->_counter_mode_step + 1) % fx->_led_count;
895         set_pixel_color(n, BLACK);
896         set_pixel_color(m, BLACK);
897         ws2812_send_frame(fx->_led_count);
899         fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
900         fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
904 /*
905  * Random color intruduced alternating from start and end of strip.
906  */
907 static void mode_color_sweep_random(ws2812fx_t *fx)
909         if(fx->_counter_mode_step == 0 || fx->_counter_mode_step == fx->_led_count) {
910                 fx->_mode_color = get_random_wheel_index(fx->_mode_color);
911         }
913         if(fx->_counter_mode_step < fx->_led_count) {
914                 set_pixel_color(fx->_counter_mode_step, color_wheel(fx->_mode_color));
915         } else {
916                 set_pixel_color((fx->_led_count * 2) - fx->_counter_mode_step - 1, color_wheel(fx->_mode_color));
917         }
918         ws2812_send_frame(fx->_led_count);
920         fx->_counter_mode_step = (fx->_counter_mode_step + 1) % (fx->_led_count * 2);
921         fx->_mode_delay = 5 + ((50 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
925 /*
926  * Alternating color/white pixels running.
927  */
928 static void mode_running_color(ws2812fx_t *fx)
930         for(uint16_t i=0; i < fx->_led_count; i++) {
931                 if((i + fx->_counter_mode_step) % 4 < 2) {
932                         set_pixel_color(i, fx->_mode_color);
933                 } else {
934                         set_pixel_color(i, WHITE);
935                 }
936         }
937         ws2812_send_frame(fx->_led_count);
939         fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 4;
940         fx->_mode_delay = 10 + ((30 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
944 /*
945  * Alternating red/blue pixels running.
946  */
947 static void mode_running_red_blue(ws2812fx_t *fx)
949         for(uint16_t i=0; i < fx->_led_count; i++) {
950                 if((i + fx->_counter_mode_step) % 4 < 2) {
951                         set_pixel_color(i, RED);
952                 } else {
953                         set_pixel_color(i, BLUE);
954                 }
955         }
956         ws2812_send_frame(fx->_led_count);
958         fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 4;
959         fx->_mode_delay = 100 + ((100 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
963 /*
964  * Random colored pixels running.
965  */
966 static void mode_running_random(ws2812fx_t *fx)
968         for(uint16_t i=fx->_led_count-1; i > 0; i--) {
969                 set_pixel_color(i, get_pixel_color(i-1));
970         }
972         if(fx->_counter_mode_step == 0) {
973                 fx->_mode_color = get_random_wheel_index(fx->_mode_color);
974                 set_pixel_color(0, color_wheel(fx->_mode_color));
975         }
977         ws2812_send_frame(fx->_led_count);
979         fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 2;
981         fx->_mode_delay = 50 + ((50 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
985 /*
986  * K.I.T.T.
987  */
988 static void mode_larson_scanner(ws2812fx_t *fx)
990         for(uint16_t i=0; i < fx->_led_count; i++) {
991                 uint32_t px_rgb = get_pixel_color(i);
993                 uint8_t px_r = (px_rgb & 0x00FF0000) >> 16;
994                 uint8_t px_g = (px_rgb & 0x0000FF00) >>  8;
995                 uint8_t px_b = (px_rgb & 0x000000FF) >>  0;
997                 // fade out (divide by 2)
998                 px_r = px_r >> 1;
999                 px_g = px_g >> 1;
1000                 px_b = px_b >> 1;
1002                 set_pixel_rgb_color(i, px_r, px_g, px_b);
1003         }
1005         uint16_t pos = 0;
1007         if(fx->_counter_mode_step < fx->_led_count) {
1008                 pos = fx->_counter_mode_step;
1009         } else {
1010                 pos = (fx->_led_count * 2) - fx->_counter_mode_step - 2;
1011         }
1013         set_pixel_color(pos, fx->_color);
1014         ws2812_send_frame(fx->_led_count);
1016         fx->_counter_mode_step = (fx->_counter_mode_step + 1) % ((fx->_led_count * 2) - 2);
1017         fx->_mode_delay = 10 + ((10 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
1021 /*
1022  * Fireing comets from one end.
1023  */
1024 static void mode_comet(ws2812fx_t *fx)
1027         for(uint16_t i=0; i < fx->_led_count; i++) {
1028                 uint32_t px_rgb = get_pixel_color(i);
1030                 uint8_t px_r = (px_rgb & 0x00FF0000) >> 16;
1031                 uint8_t px_g = (px_rgb & 0x0000FF00) >>  8;
1032                 uint8_t px_b = (px_rgb & 0x000000FF) >>  0;
1034                 // fade out (divide by 2)
1035                 px_r = px_r >> 1;
1036                 px_g = px_g >> 1;
1037                 px_b = px_b >> 1;
1039                 set_pixel_rgb_color(i, px_r, px_g, px_b);
1040         }
1042         set_pixel_color(fx->_counter_mode_step, fx->_color);
1043         ws2812_send_frame(fx->_led_count);
1045         fx->_counter_mode_step = (fx->_counter_mode_step + 1) % fx->_led_count;
1046         fx->_mode_delay = 10 + ((10 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
1050 /*
1051  * Firework sparks.
1052  */
1053 static void mode_fireworks(ws2812fx_t *fx)
1055         uint32_t px_rgb = 0;
1056         uint8_t px_r = 0;
1057         uint8_t px_g = 0;
1058         uint8_t px_b = 0;
1060         for(uint16_t i=0; i < fx->_led_count; i++) {
1061                 px_rgb = get_pixel_color(i);
1063                 px_r = (px_rgb & 0x00FF0000) >> 16;
1064                 px_g = (px_rgb & 0x0000FF00) >>  8;
1065                 px_b = (px_rgb & 0x000000FF) >>  0;
1067                 // fade out (divide by 2)
1068                 px_r = px_r >> 1;
1069                 px_g = px_g >> 1;
1070                 px_b = px_b >> 1;
1072                 set_pixel_rgb_color(i, px_r, px_g, px_b);
1073         }
1075         // first LED has only one neighbour
1076         px_r = (((get_pixel_color(1) & 0x00FF0000) >> 16) >> 1) + ((get_pixel_color(0) & 0x00FF0000) >> 16);
1077         px_g = (((get_pixel_color(1) & 0x0000FF00) >>  8) >> 1) + ((get_pixel_color(0) & 0x0000FF00) >>  8);
1078         px_b = (((get_pixel_color(1) & 0x000000FF) >>  0) >> 1) + ((get_pixel_color(0) & 0x000000FF) >>  0);
1079         set_pixel_rgb_color(0, px_r, px_g, px_b);
1081         // set brightness(i) = ((brightness(i-1)/2 + brightness(i+1)) / 2) + brightness(i)
1082         for(uint16_t i=1; i < fx->_led_count-1; i++) {
1083                 px_r = ((
1084                                         (((get_pixel_color(i-1) & 0x00FF0000) >> 16) >> 1) +
1085                                         (((get_pixel_color(i+1) & 0x00FF0000) >> 16) >> 0) ) >> 1) +
1086                         (((get_pixel_color(i  ) & 0x00FF0000) >> 16) >> 0);
1088                 px_g = ((
1089                                         (((get_pixel_color(i-1) & 0x0000FF00) >> 8) >> 1) +
1090                                         (((get_pixel_color(i+1) & 0x0000FF00) >> 8) >> 0) ) >> 1) +
1091                         (((get_pixel_color(i  ) & 0x0000FF00) >> 8) >> 0);
1093                 px_b = ((
1094                                         (((get_pixel_color(i-1) & 0x000000FF) >> 0) >> 1) +
1095                                         (((get_pixel_color(i+1) & 0x000000FF) >> 0) >> 0) ) >> 1) +
1096                         (((get_pixel_color(i  ) & 0x000000FF) >> 0) >> 0);
1098                 set_pixel_rgb_color(i, px_r, px_g, px_b);
1099         }
1101         // last LED has only one neighbour
1102         px_r = (((get_pixel_color(fx->_led_count-2) & 0x00FF0000) >> 16) >> 2) + ((get_pixel_color(fx->_led_count-1) & 0x00FF0000) >> 16);
1103         px_g = (((get_pixel_color(fx->_led_count-2) & 0x0000FF00) >>  8) >> 2) + ((get_pixel_color(fx->_led_count-1) & 0x0000FF00) >>  8);
1104         px_b = (((get_pixel_color(fx->_led_count-2) & 0x000000FF) >>  0) >> 2) + ((get_pixel_color(fx->_led_count-1) & 0x000000FF) >>  0);
1105         set_pixel_rgb_color(fx->_led_count-1, px_r, px_g, px_b);
1107         if(!fx->_triggered) {
1108                 for(uint16_t i=0; i<max(1,fx->_led_count/20); i++) {
1109                         if(random(10) == 0) {
1110                                 set_pixel_color(random(fx->_led_count), fx->_mode_color);
1111                         }
1112                 }
1113         } else {
1114                 for(uint16_t i=0; i<max(1,fx->_led_count/10); i++) {
1115                         set_pixel_color(random(fx->_led_count), fx->_mode_color);
1116                 }
1117         }
1119         ws2812_send_frame(fx->_led_count);
1121         fx->_mode_delay = 20 + ((20 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
1125 /*
1126  * Random colored firework sparks.
1127  */
1128 static void mode_fireworks_random(ws2812fx_t *fx)
1130         fx->_mode_color = color_wheel(random(256));
1131         mode_fireworks(fx);
1135 /*
1136  * Alternating red/green pixels running.
1137  */
1138 static void mode_merry_christmas(ws2812fx_t *fx)
1140         for(uint16_t i=0; i < fx->_led_count; i++) {
1141                 if((i + fx->_counter_mode_step) % 4 < 2) {
1142                         set_pixel_color(i, RED);
1143                 } else {
1144                         set_pixel_color(i, GREEN);
1145                 }
1146         }
1147         ws2812_send_frame(fx->_led_count);
1149         fx->_counter_mode_step = (fx->_counter_mode_step + 1) % 4;
1150         fx->_mode_delay = 100 + ((100 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / fx->_led_count);
1154 static void mode_fire_flicker_int(ws2812fx_t *fx, int rev_intensity)
1156         uint8_t p_r = (fx->_color & 0x00FF0000) >> 16;
1157         uint8_t p_g = (fx->_color & 0x0000FF00) >>  8;
1158         uint8_t p_b = (fx->_color & 0x000000FF) >>  0;
1159         uint8_t flicker_val = max(p_r,max(p_g, p_b))/rev_intensity;
1160         for(uint16_t i=0; i < fx->_led_count; i++)
1161         {
1162                 int flicker = random(flicker_val);
1163                 int r1 = p_r-flicker;
1164                 int g1 = p_g-flicker;
1165                 int b1 = p_b-flicker;
1166                 if(g1<0) g1=0;
1167                 if(r1<0) r1=0;
1168                 if(b1<0) b1=0;
1169                 set_pixel_rgb_color(i,r1,g1, b1);
1170         }
1171         ws2812_send_frame(fx->_led_count);
1172         fx->_mode_delay = 10 + ((500 * (uint32_t)(FX_SPEED_MAX - fx->_speed)) / FX_SPEED_MAX);
1175 /*
1176  * Random flickering.
1177  */
1178 static void mode_fire_flicker(ws2812fx_t *fx)
1180         mode_fire_flicker_int(fx, 3);
1183 /*
1184  * Random flickering, less intesity.
1185  */
1186 static void mode_fire_flicker_soft(ws2812fx_t *fx)
1188         mode_fire_flicker_int(fx, 6);
1192 typedef void (*mode_ptr)(ws2812fx_t *fx);
1194 static struct {
1195         mode_ptr _fn;
1196         char *_name;
1197 } const modes[] = {
1198         { mode_static,                  "Static" },
1199         { mode_blink,                   "Blink" },
1200         { mode_breath,                  "Breath" },
1201         { mode_color_wipe,              "Color Wipe" },
1202         { mode_color_wipe_random,       "Color Wipe Random" },
1203         { mode_random_color,            "Random Color" },
1204         { mode_single_dynamic,          "Single Dynamic" },
1205         { mode_multi_dynamic,           "Multi Dynamic" },
1206         { mode_rainbow,                 "Rainbow" },
1207         { mode_rainbow_cycle,           "Rainbow Cycle" },
1208         { mode_theater_chase,           "Theater Chase" },
1209         { mode_theater_chase_rainbow,   "Theater Chase Rainbow" },
1210         { mode_scan,                    "Scan" },
1211         { mode_dual_scan,               "Dual Scan" },
1212         { mode_fade,                    "Fade" },
1213 #if 0
1214         { mode_running_lights,          "Running Lights" },
1215 #endif
1216         { mode_twinkle,                 "Twinkle" },
1217         { mode_twinkle_random,          "Twinkle Random" },
1218         { mode_twinkle_fade,            "Twinkle Fade" },
1219         { mode_twinkle_fade_random,     "Twinkle Fade Random" },
1220         { mode_sparkle,                 "Sparkle" },
1221         { mode_flash_sparkle,           "Flash Sparkle" },
1222         { mode_hyper_sparkle,           "Hyper Sparkle" },
1223         { mode_strobe,                  "Strobe" },
1224         { mode_strobe_rainbow,          "Strobe Rainbow" },
1225         { mode_multi_strobe,            "Multi Strobe" },
1226         { mode_blink_rainbow,           "Blink Rainbow" },
1227         { mode_chase_white,             "Chase White" },
1228         { mode_chase_color,             "Chase Color" },
1229         { mode_chase_random,            "Chase Random" },
1230         { mode_chase_rainbow,           "Chase Rainbow" },
1231         { mode_chase_flash,             "Chase Flash" },
1232         { mode_chase_flash_random,      "Chase Flash Random" },
1233         { mode_chase_rainbow_white,     "Chase Rainbow White" },
1234         { mode_chase_blackout,          "Chase Blackout" },
1235         { mode_chase_blackout_rainbow,  "Chase Blackout Rainbow" },
1236         { mode_color_sweep_random,      "Color Sweep Random" },
1237         { mode_running_color,           "Running Color" },
1238         { mode_running_red_blue,        "Running Red Blue" },
1239         { mode_running_random,          "Running Random" },
1240         { mode_larson_scanner,          "Larson Scanner" },
1241         { mode_comet,                   "Comet" },
1242         { mode_fireworks,               "Fireworks" },
1243         { mode_fireworks_random,        "Fireworks Random" },
1244         { mode_merry_christmas,         "Merry Christmas" },
1245         { mode_fire_flicker,            "Fire Flicker" },
1246         { mode_fire_flicker_soft,       "Fire Flicker (soft)" },
1247 };
1249 #define CALL_MODE(fx, n) (modes[n]._fn)(fx);
1251 void WS2812FX(ws2812fx_t *fx, uint16_t n, const struct pio *pin)
1253         ws2812_config(pin);
1255         fx->_speed = FX_DEFAULT_SPEED;
1256         fx->_brightness = FX_DEFAULT_BRIGHTNESS;
1257         fx->_running = 0;
1258         fx->_led_count = n;
1259         fx->_mode_last_call_time = 0;
1260         fx->_mode_delay = 0;
1261         fx->_color = FX_DEFAULT_COLOR;
1262         fx->_mode_color = FX_DEFAULT_COLOR;
1263         fx->_counter_mode_call = 0;
1264         fx->_counter_mode_step = 0;
1267 void FX_init(ws2812fx_t *fx)
1269         FX_setBrightness(fx, fx->_brightness);
1270         ws2812_send_frame(fx->_led_count);
1273 void FX_service(ws2812fx_t *fx)
1275         if(fx->_running || fx->_triggered) {
1276                 unsigned long now = millis();
1278                 if(now - fx->_mode_last_call_time > fx->_mode_delay || fx->_triggered) {
1279                         CALL_MODE(fx, fx->_mode_index);
1280                         fx->_counter_mode_call++;
1281                         fx->_mode_last_call_time = now;
1282                         fx->_triggered = 0;
1283                 }
1284         }
1287 void FX_start(ws2812fx_t *fx)
1289         fx->_counter_mode_call = 0;
1290         fx->_counter_mode_step = 0;
1291         fx->_mode_last_call_time = 0;
1292         fx->_running = 1;
1295 void FX_stop(ws2812fx_t *fx)
1297         fx->_running = 0;
1298         strip_off(fx);
1301 void FX_trigger(ws2812fx_t *fx)
1303         fx->_triggered = 1;
1306 void FX_setMode(ws2812fx_t *fx, uint8_t m)
1308         fx->_counter_mode_call = 0;
1309         fx->_counter_mode_step = 0;
1310         fx->_mode_last_call_time = 0;
1311         fx->_mode_index = constrain(m, 0, FX_MODE_COUNT-1);
1312         fx->_mode_color = fx->_color;
1313         ws2812_set_brightness(fx->_brightness);
1314         //strip_off(fx);
1317 void FX_setSpeed(ws2812fx_t *fx, uint8_t s)
1319         fx->_counter_mode_call = 0;
1320         fx->_counter_mode_step = 0;
1321         fx->_mode_last_call_time = 0;
1322         fx->_speed = constrain(s, FX_SPEED_MIN, FX_SPEED_MAX);
1323         //strip_off(fx);
1326 void FX_increaseSpeed(ws2812fx_t *fx, uint8_t s)
1328         s = constrain(fx->_speed + s, FX_SPEED_MIN, FX_SPEED_MAX);
1329         FX_setSpeed(fx, s);
1332 void FX_decreaseSpeed(ws2812fx_t *fx, uint8_t s)
1334         s = constrain(fx->_speed - s, FX_SPEED_MIN, FX_SPEED_MAX);
1335         FX_setSpeed(fx, s);
1338 void FX_setRGBColor(ws2812fx_t *fx, uint8_t r, uint8_t g, uint8_t b)
1340         FX_setColor(fx, ((uint32_t)r << 16) | ((uint32_t)g << 8) | b);
1343 void FX_setColor(ws2812fx_t *fx, uint32_t c)
1345         fx->_color = c;
1346         fx->_counter_mode_call = 0;
1347         fx->_counter_mode_step = 0;
1348         fx->_mode_last_call_time = 0;
1349         fx->_mode_color = fx->_color;
1350         ws2812_set_brightness(fx->_brightness);
1351         //strip_off(fx);
1354 void FX_setBrightness(ws2812fx_t *fx, uint8_t b)
1356         fx->_brightness = constrain(b, FX_BRIGHTNESS_MIN, FX_BRIGHTNESS_MAX);
1357         ws2812_set_brightness(fx->_brightness);
1358         ws2812_send_frame(fx->_led_count);
1361 void FX_increaseBrightness(ws2812fx_t *fx, uint8_t s)
1363         s = constrain(fx->_brightness + s, FX_BRIGHTNESS_MIN, FX_BRIGHTNESS_MAX);
1364         FX_setBrightness(fx, s);
1367 void FX_decreaseBrightness(ws2812fx_t *fx, uint8_t s)
1369         s = constrain(fx->_brightness - s, FX_BRIGHTNESS_MIN, FX_BRIGHTNESS_MAX);
1370         FX_setBrightness(fx, s);
1373 int FX_isRunning(ws2812fx_t *fx)
1375         return fx->_running;
1378 uint8_t FX_getMode(ws2812fx_t *fx)
1380         return fx->_mode_index;
1383 uint8_t FX_getSpeed(ws2812fx_t *fx)
1385         return fx->_speed;
1388 uint8_t FX_getBrightness(ws2812fx_t *fx)
1390         return fx->_brightness;
1393 uint8_t FX_getModeCount(ws2812fx_t *fx)
1395         return FX_MODE_COUNT;
1398 uint32_t FX_getColor(ws2812fx_t *fx)
1400         return fx->_color;
1403 const char* FX_getModeName(uint8_t m)
1405         if (m < FX_MODE_COUNT) {
1406                 return modes[m]._name;
1407         } else {
1408                 return "";
1409         }