Configurable Rainbow Swirl range (#4376)
[jackhill/qmk/firmware.git] / quantum / rgblight.c
CommitLineData
23839b8c 1/* Copyright 2016-2017 Yang Liu
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
ad49db8c 16#include <math.h>
6d6d91c8 17#include <string.h>
ade22f8e
JH
18#ifdef __AVR__
19 #include <avr/eeprom.h>
20 #include <avr/interrupt.h>
21#endif
22#include "wait.h"
0a40654b
YL
23#include "progmem.h"
24#include "timer.h"
25#include "rgblight.h"
26#include "debug.h"
f113f954 27#include "led_tables.h"
0a40654b 28
2038a515 29#ifndef RGBLIGHT_LIMIT_VAL
30#define RGBLIGHT_LIMIT_VAL 255
31#endif
32
6d6d91c8
TI
33#define _RGBM_SINGLE_STATIC(sym) RGBLIGHT_MODE_ ## sym,
34#define _RGBM_SINGLE_DYNAMIC(sym)
35#define _RGBM_MULTI_STATIC(sym) RGBLIGHT_MODE_ ## sym,
36#define _RGBM_MULTI_DYNAMIC(sym)
37#define _RGBM_TMP_STATIC(sym) RGBLIGHT_MODE_ ## sym,
38#define _RGBM_TMP_DYNAMIC(sym)
39static uint8_t static_effect_table [] = {
40#include "rgblight.h"
41};
42
43static inline int is_static_effect(uint8_t mode) {
44 return memchr(static_effect_table, mode, sizeof(static_effect_table)) != NULL;
45}
46
afacd423 47#define MIN(a,b) (((a)<(b))?(a):(b))
48#define MAX(a,b) (((a)>(b))?(a):(b))
49
6d6d91c8 50#ifdef RGBLIGHT_EFFECT_STATIC_GRADIENT
a7882b1f 51__attribute__ ((weak))
52const uint16_t RGBLED_GRADIENT_RANGES[] PROGMEM = {360, 240, 180, 120, 90};
6d6d91c8 53#endif
0a40654b
YL
54
55rgblight_config_t rgblight_config;
0a40654b 56
e9f74875 57LED_TYPE led[RGBLED_NUM];
e9f74875 58bool rgblight_timer_enabled = false;
0a40654b 59
e9f74875 60void sethsv(uint16_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1) {
ea2d2f5d 61 uint8_t r = 0, g = 0, b = 0, base, color;
0a40654b 62
2038a515 63 if (val > RGBLIGHT_LIMIT_VAL) {
6c24e28b 64 val=RGBLIGHT_LIMIT_VAL; // limit the val
2038a515 65 }
6c24e28b 66
3a860c4b
JO
67 if (sat == 0) { // Acromatic color (gray). Hue doesn't mind.
68 r = val;
69 g = val;
70 b = val;
71 } else {
72 base = ((255 - sat) * val) >> 8;
ea2d2f5d 73 color = (val - base) * (hue % 60) / 60;
3a860c4b
JO
74
75 switch (hue / 60) {
76 case 0:
77 r = val;
ea2d2f5d 78 g = base + color;
3a860c4b
JO
79 b = base;
80 break;
81 case 1:
ea2d2f5d 82 r = val - color;
3a860c4b
JO
83 g = val;
84 b = base;
85 break;
86 case 2:
87 r = base;
88 g = val;
ea2d2f5d 89 b = base + color;
3a860c4b
JO
90 break;
91 case 3:
92 r = base;
ea2d2f5d 93 g = val - color;
3a860c4b
JO
94 b = val;
95 break;
96 case 4:
ea2d2f5d 97 r = base + color;
3a860c4b
JO
98 g = base;
99 b = val;
100 break;
101 case 5:
102 r = val;
103 g = base;
ea2d2f5d 104 b = val - color;
3a860c4b
JO
105 break;
106 }
107 }
f113f954
FS
108 r = pgm_read_byte(&CIE1931_CURVE[r]);
109 g = pgm_read_byte(&CIE1931_CURVE[g]);
110 b = pgm_read_byte(&CIE1931_CURVE[b]);
ea2d2f5d
JO
111
112 setrgb(r, g, b, led1);
0a40654b
YL
113}
114
e9f74875 115void setrgb(uint8_t r, uint8_t g, uint8_t b, LED_TYPE *led1) {
0a40654b
YL
116 (*led1).r = r;
117 (*led1).g = g;
118 (*led1).b = b;
119}
120
121
122uint32_t eeconfig_read_rgblight(void) {
ade22f8e
JH
123 #ifdef __AVR__
124 return eeprom_read_dword(EECONFIG_RGBLIGHT);
125 #else
126 return 0;
127 #endif
0a40654b 128}
620ac4b2 129void eeconfig_update_rgblight(uint32_t val) {
ade22f8e
JH
130 #ifdef __AVR__
131 eeprom_update_dword(EECONFIG_RGBLIGHT, val);
132 #endif
0a40654b 133}
620ac4b2 134void eeconfig_update_rgblight_default(void) {
0fab3bbd 135 //dprintf("eeconfig_update_rgblight_default\n");
3a860c4b 136 rgblight_config.enable = 1;
6d6d91c8 137 rgblight_config.mode = RGBLIGHT_MODE_STATIC_LIGHT;
e9f74875
JH
138 rgblight_config.hue = 0;
139 rgblight_config.sat = 255;
2038a515 140 rgblight_config.val = RGBLIGHT_LIMIT_VAL;
afacd423 141 rgblight_config.speed = 0;
3a860c4b 142 eeconfig_update_rgblight(rgblight_config.raw);
0a40654b
YL
143}
144void eeconfig_debug_rgblight(void) {
3a860c4b
JO
145 dprintf("rgblight_config eprom\n");
146 dprintf("rgblight_config.enable = %d\n", rgblight_config.enable);
147 dprintf("rghlight_config.mode = %d\n", rgblight_config.mode);
148 dprintf("rgblight_config.hue = %d\n", rgblight_config.hue);
149 dprintf("rgblight_config.sat = %d\n", rgblight_config.sat);
150 dprintf("rgblight_config.val = %d\n", rgblight_config.val);
afacd423 151 dprintf("rgblight_config.speed = %d\n", rgblight_config.speed);
0a40654b
YL
152}
153
154void rgblight_init(void) {
155 debug_enable = 1; // Debug ON!
3a860c4b 156 dprintf("rgblight_init called.\n");
3a860c4b 157 dprintf("rgblight_init start!\n");
0a40654b 158 if (!eeconfig_is_enabled()) {
3a860c4b 159 dprintf("rgblight_init eeconfig is not enabled.\n");
0a40654b 160 eeconfig_init();
3a860c4b 161 eeconfig_update_rgblight_default();
0a40654b
YL
162 }
163 rgblight_config.raw = eeconfig_read_rgblight();
3a860c4b
JO
164 if (!rgblight_config.mode) {
165 dprintf("rgblight_init rgblight_config.mode = 0. Write default values to EEPROM.\n");
166 eeconfig_update_rgblight_default();
167 rgblight_config.raw = eeconfig_read_rgblight();
168 }
169 eeconfig_debug_rgblight(); // display current eeprom values
0a40654b 170
6d6d91c8 171#ifdef RGBLIGHT_USE_TIMER
3a860c4b 172 rgblight_timer_init(); // setup the timer
6d6d91c8 173#endif
0a40654b
YL
174
175 if (rgblight_config.enable) {
751719e6 176 rgblight_mode_noeeprom(rgblight_config.mode);
0a40654b
YL
177 }
178}
179
2e23689b
JH
180void rgblight_update_dword(uint32_t dword) {
181 rgblight_config.raw = dword;
182 eeconfig_update_rgblight(rgblight_config.raw);
183 if (rgblight_config.enable)
184 rgblight_mode(rgblight_config.mode);
185 else {
6d6d91c8 186#ifdef RGBLIGHT_USE_TIMER
2e23689b 187 rgblight_timer_disable();
6d6d91c8 188#endif
2e23689b
JH
189 rgblight_set();
190 }
191}
192
0a40654b 193void rgblight_increase(void) {
3a860c4b 194 uint8_t mode = 0;
0a40654b
YL
195 if (rgblight_config.mode < RGBLIGHT_MODES) {
196 mode = rgblight_config.mode + 1;
197 }
3a860c4b 198 rgblight_mode(mode);
0a40654b 199}
0a40654b 200void rgblight_decrease(void) {
3a860c4b
JO
201 uint8_t mode = 0;
202 // Mode will never be < 1. If it ever is, eeprom needs to be initialized.
6d6d91c8 203 if (rgblight_config.mode > RGBLIGHT_MODE_STATIC_LIGHT) {
3a860c4b 204 mode = rgblight_config.mode - 1;
0a40654b 205 }
3a860c4b 206 rgblight_mode(mode);
0a40654b 207}
0a40654b 208void rgblight_step(void) {
3a860c4b 209 uint8_t mode = 0;
0a40654b
YL
210 mode = rgblight_config.mode + 1;
211 if (mode > RGBLIGHT_MODES) {
212 mode = 1;
213 }
3a860c4b 214 rgblight_mode(mode);
0a40654b 215}
5a1b68d5 216void rgblight_step_reverse(void) {
217 uint8_t mode = 0;
218 mode = rgblight_config.mode - 1;
219 if (mode < 1) {
220 mode = RGBLIGHT_MODES;
221 }
222 rgblight_mode(mode);
223}
0a40654b 224
4580d3a7 225uint32_t rgblight_get_mode(void) {
226 if (!rgblight_config.enable) {
227 return false;
228 }
229
230 return rgblight_config.mode;
231}
232
751719e6 233void rgblight_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom) {
3a860c4b
JO
234 if (!rgblight_config.enable) {
235 return;
236 }
6d6d91c8
TI
237 if (mode < RGBLIGHT_MODE_STATIC_LIGHT) {
238 rgblight_config.mode = RGBLIGHT_MODE_STATIC_LIGHT;
3a860c4b
JO
239 } else if (mode > RGBLIGHT_MODES) {
240 rgblight_config.mode = RGBLIGHT_MODES;
241 } else {
242 rgblight_config.mode = mode;
243 }
751719e6
DJ
244 if (write_to_eeprom) {
245 eeconfig_update_rgblight(rgblight_config.raw);
246 xprintf("rgblight mode [EEPROM]: %u\n", rgblight_config.mode);
247 } else {
248 xprintf("rgblight mode [NOEEPROM]: %u\n", rgblight_config.mode);
249 }
6d6d91c8
TI
250 if( is_static_effect(rgblight_config.mode) ) {
251#ifdef RGBLIGHT_USE_TIMER
3a860c4b 252 rgblight_timer_disable();
6d6d91c8
TI
253#endif
254 } else {
255#ifdef RGBLIGHT_USE_TIMER
3a860c4b 256 rgblight_timer_enable();
6d6d91c8 257#endif
3a860c4b 258 }
751719e6
DJ
259 rgblight_sethsv_noeeprom(rgblight_config.hue, rgblight_config.sat, rgblight_config.val);
260}
261
262void rgblight_mode(uint8_t mode) {
263 rgblight_mode_eeprom_helper(mode, true);
264}
265
266void rgblight_mode_noeeprom(uint8_t mode) {
267 rgblight_mode_eeprom_helper(mode, false);
0a40654b
YL
268}
269
751719e6 270
0a40654b 271void rgblight_toggle(void) {
751719e6 272 xprintf("rgblight toggle [EEPROM]: rgblight_config.enable = %u\n", !rgblight_config.enable);
3a860c4b 273 if (rgblight_config.enable) {
16546ee0
CG
274 rgblight_disable();
275 }
276 else {
277 rgblight_enable();
3a860c4b 278 }
0a40654b
YL
279}
280
751719e6
DJ
281void rgblight_toggle_noeeprom(void) {
282 xprintf("rgblight toggle [NOEEPROM]: rgblight_config.enable = %u\n", !rgblight_config.enable);
283 if (rgblight_config.enable) {
284 rgblight_disable_noeeprom();
285 }
286 else {
287 rgblight_enable_noeeprom();
288 }
289}
290
285c5a91
EZ
291void rgblight_enable(void) {
292 rgblight_config.enable = 1;
751719e6
DJ
293 // No need to update EEPROM here. rgblight_mode() will do that, actually
294 //eeconfig_update_rgblight(rgblight_config.raw);
295 xprintf("rgblight enable [EEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable);
285c5a91
EZ
296 rgblight_mode(rgblight_config.mode);
297}
298
751719e6
DJ
299void rgblight_enable_noeeprom(void) {
300 rgblight_config.enable = 1;
301 xprintf("rgblight enable [NOEEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable);
302 rgblight_mode_noeeprom(rgblight_config.mode);
303}
304
16546ee0
CG
305void rgblight_disable(void) {
306 rgblight_config.enable = 0;
307 eeconfig_update_rgblight(rgblight_config.raw);
751719e6 308 xprintf("rgblight disable [EEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable);
6d6d91c8
TI
309#ifdef RGBLIGHT_USE_TIMER
310 rgblight_timer_disable();
311#endif
ade22f8e 312 wait_ms(50);
16546ee0
CG
313 rgblight_set();
314}
315
751719e6
DJ
316void rgblight_disable_noeeprom(void) {
317 rgblight_config.enable = 0;
318 xprintf("rgblight disable [noEEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable);
6d6d91c8 319#ifdef RGBLIGHT_USE_TIMER
751719e6 320 rgblight_timer_disable();
6d6d91c8 321#endif
751719e6
DJ
322 _delay_ms(50);
323 rgblight_set();
324}
325
326
afacd423 327// Deals with the messy details of incrementing an integer
328uint8_t increment( uint8_t value, uint8_t step, uint8_t min, uint8_t max ) {
329 int16_t new_value = value;
330 new_value += step;
331 return MIN( MAX( new_value, min ), max );
332}
333
334uint8_t decrement( uint8_t value, uint8_t step, uint8_t min, uint8_t max ) {
335 int16_t new_value = value;
336 new_value -= step;
337 return MIN( MAX( new_value, min ), max );
338}
0a40654b 339
3a860c4b
JO
340void rgblight_increase_hue(void) {
341 uint16_t hue;
0a40654b
YL
342 hue = (rgblight_config.hue+RGBLIGHT_HUE_STEP) % 360;
343 rgblight_sethsv(hue, rgblight_config.sat, rgblight_config.val);
344}
3a860c4b
JO
345void rgblight_decrease_hue(void) {
346 uint16_t hue;
347 if (rgblight_config.hue-RGBLIGHT_HUE_STEP < 0) {
348 hue = (rgblight_config.hue + 360 - RGBLIGHT_HUE_STEP) % 360;
349 } else {
350 hue = (rgblight_config.hue - RGBLIGHT_HUE_STEP) % 360;
351 }
0a40654b
YL
352 rgblight_sethsv(hue, rgblight_config.sat, rgblight_config.val);
353}
354void rgblight_increase_sat(void) {
3a860c4b 355 uint8_t sat;
0a40654b
YL
356 if (rgblight_config.sat + RGBLIGHT_SAT_STEP > 255) {
357 sat = 255;
358 } else {
3a860c4b 359 sat = rgblight_config.sat + RGBLIGHT_SAT_STEP;
0a40654b
YL
360 }
361 rgblight_sethsv(rgblight_config.hue, sat, rgblight_config.val);
362}
3a860c4b
JO
363void rgblight_decrease_sat(void) {
364 uint8_t sat;
0a40654b
YL
365 if (rgblight_config.sat - RGBLIGHT_SAT_STEP < 0) {
366 sat = 0;
367 } else {
3a860c4b 368 sat = rgblight_config.sat - RGBLIGHT_SAT_STEP;
0a40654b
YL
369 }
370 rgblight_sethsv(rgblight_config.hue, sat, rgblight_config.val);
371}
3a860c4b
JO
372void rgblight_increase_val(void) {
373 uint8_t val;
2038a515 374 if (rgblight_config.val + RGBLIGHT_VAL_STEP > RGBLIGHT_LIMIT_VAL) {
375 val = RGBLIGHT_LIMIT_VAL;
0a40654b 376 } else {
3a860c4b 377 val = rgblight_config.val + RGBLIGHT_VAL_STEP;
0a40654b
YL
378 }
379 rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, val);
380}
381void rgblight_decrease_val(void) {
3a860c4b 382 uint8_t val;
0a40654b
YL
383 if (rgblight_config.val - RGBLIGHT_VAL_STEP < 0) {
384 val = 0;
385 } else {
3a860c4b 386 val = rgblight_config.val - RGBLIGHT_VAL_STEP;
0a40654b
YL
387 }
388 rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, val);
389}
afacd423 390void rgblight_increase_speed(void) {
391 rgblight_config.speed = increment( rgblight_config.speed, 1, 0, 3 );
392 eeconfig_update_rgblight(rgblight_config.raw);//EECONFIG needs to be increased to support this
393}
394
395void rgblight_decrease_speed(void) {
396 rgblight_config.speed = decrement( rgblight_config.speed, 1, 0, 3 );
397 eeconfig_update_rgblight(rgblight_config.raw);//EECONFIG needs to be increased to support this
398}
0a40654b 399
751719e6 400void rgblight_sethsv_noeeprom_old(uint16_t hue, uint8_t sat, uint8_t val) {
0a40654b 401 if (rgblight_config.enable) {
e9f74875 402 LED_TYPE tmp_led;
0a40654b 403 sethsv(hue, sat, val, &tmp_led);
0a40654b
YL
404 // dprintf("rgblight set hue [MEMORY]: %u,%u,%u\n", inmem_config.hue, inmem_config.sat, inmem_config.val);
405 rgblight_setrgb(tmp_led.r, tmp_led.g, tmp_led.b);
406 }
407}
751719e6
DJ
408
409void rgblight_sethsv_eeprom_helper(uint16_t hue, uint8_t sat, uint8_t val, bool write_to_eeprom) {
0a40654b 410 if (rgblight_config.enable) {
6d6d91c8 411 if (rgblight_config.mode == RGBLIGHT_MODE_STATIC_LIGHT) {
3a860c4b 412 // same static color
751719e6
DJ
413 LED_TYPE tmp_led;
414 sethsv(hue, sat, val, &tmp_led);
415 rgblight_setrgb(tmp_led.r, tmp_led.g, tmp_led.b);
3a860c4b
JO
416 } else {
417 // all LEDs in same color
6d6d91c8
TI
418 if ( 1 == 0 ) { //dummy
419 }
420#ifdef RGBLIGHT_EFFECT_BREATHING
421 else if (rgblight_config.mode >= RGBLIGHT_MODE_BREATHING &&
422 rgblight_config.mode <= RGBLIGHT_MODE_BREATHING_end) {
3a860c4b
JO
423 // breathing mode, ignore the change of val, use in memory value instead
424 val = rgblight_config.val;
6d6d91c8
TI
425 }
426#endif
427#ifdef RGBLIGHT_EFFECT_RAINBOW_MOOD
428 else if (rgblight_config.mode >= RGBLIGHT_MODE_RAINBOW_MOOD &&
429 rgblight_config.mode <= RGBLIGHT_MODE_RAINBOW_MOOD_end) {
430 // rainbow mood, ignore the change of hue
431 hue = rgblight_config.hue;
432 }
433#endif
434#ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL
435 else if (rgblight_config.mode >= RGBLIGHT_MODE_RAINBOW_SWIRL &&
436 rgblight_config.mode <= RGBLIGHT_MODE_RAINBOW_SWIRL_end) {
437 // rainbow swirl, ignore the change of hue
3a860c4b 438 hue = rgblight_config.hue;
6d6d91c8
TI
439 }
440#endif
441#ifdef RGBLIGHT_EFFECT_STATIC_GRADIENT
442 else if (rgblight_config.mode >= RGBLIGHT_MODE_STATIC_GRADIENT &&
443 rgblight_config.mode <= RGBLIGHT_MODE_STATIC_GRADIENT_end) {
a7882b1f 444 // static gradient
445 uint16_t _hue;
6d6d91c8
TI
446 int8_t direction = ((rgblight_config.mode - RGBLIGHT_MODE_STATIC_GRADIENT) % 2) ? -1 : 1;
447 uint16_t range = pgm_read_word(&RGBLED_GRADIENT_RANGES[(rgblight_config.mode - RGBLIGHT_MODE_STATIC_GRADIENT) / 2]);
a7882b1f 448 for (uint8_t i = 0; i < RGBLED_NUM; i++) {
449 _hue = (range / RGBLED_NUM * i * direction + hue + 360) % 360;
450 dprintf("rgblight rainbow set hsv: %u,%u,%d,%u\n", i, _hue, direction, range);
451 sethsv(_hue, sat, val, (LED_TYPE *)&led[i]);
452 }
453 rgblight_set();
3a860c4b 454 }
6d6d91c8 455#endif
3a860c4b
JO
456 }
457 rgblight_config.hue = hue;
458 rgblight_config.sat = sat;
459 rgblight_config.val = val;
751719e6
DJ
460 if (write_to_eeprom) {
461 eeconfig_update_rgblight(rgblight_config.raw);
462 xprintf("rgblight set hsv [EEPROM]: %u,%u,%u\n", rgblight_config.hue, rgblight_config.sat, rgblight_config.val);
463 } else {
464 xprintf("rgblight set hsv [NOEEPROM]: %u,%u,%u\n", rgblight_config.hue, rgblight_config.sat, rgblight_config.val);
465 }
3a860c4b
JO
466 }
467}
468
751719e6
DJ
469void rgblight_sethsv(uint16_t hue, uint8_t sat, uint8_t val) {
470 rgblight_sethsv_eeprom_helper(hue, sat, val, true);
471}
472
473void rgblight_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val) {
474 rgblight_sethsv_eeprom_helper(hue, sat, val, false);
475}
476
12e66330 477uint16_t rgblight_get_hue(void) {
478 return rgblight_config.hue;
479}
480
481uint8_t rgblight_get_sat(void) {
482 return rgblight_config.sat;
483}
484
485uint8_t rgblight_get_val(void) {
486 return rgblight_config.val;
487}
488
3a860c4b 489void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b) {
16546ee0
CG
490 if (!rgblight_config.enable) { return; }
491
3a860c4b 492 for (uint8_t i = 0; i < RGBLED_NUM; i++) {
0a40654b
YL
493 led[i].r = r;
494 led[i].g = g;
495 led[i].b = b;
496 }
497 rgblight_set();
0a40654b
YL
498}
499
16546ee0
CG
500void rgblight_setrgb_at(uint8_t r, uint8_t g, uint8_t b, uint8_t index) {
501 if (!rgblight_config.enable || index >= RGBLED_NUM) { return; }
502
503 led[index].r = r;
504 led[index].g = g;
505 led[index].b = b;
506 rgblight_set();
507}
508
509void rgblight_sethsv_at(uint16_t hue, uint8_t sat, uint8_t val, uint8_t index) {
510 if (!rgblight_config.enable) { return; }
511
512 LED_TYPE tmp_led;
513 sethsv(hue, sat, val, &tmp_led);
514 rgblight_setrgb_at(tmp_led.r, tmp_led.g, tmp_led.b, index);
515}
516
d4cd5dda 517#ifndef RGBLIGHT_CUSTOM_DRIVER
0a40654b 518void rgblight_set(void) {
3a860c4b 519 if (rgblight_config.enable) {
b8679bbe
JH
520 #ifdef RGBW
521 ws2812_setleds_rgbw(led, RGBLED_NUM);
522 #else
523 ws2812_setleds(led, RGBLED_NUM);
524 #endif
3a860c4b
JO
525 } else {
526 for (uint8_t i = 0; i < RGBLED_NUM; i++) {
527 led[i].r = 0;
528 led[i].g = 0;
529 led[i].b = 0;
530 }
b8679bbe
JH
531 #ifdef RGBW
532 ws2812_setleds_rgbw(led, RGBLED_NUM);
533 #else
534 ws2812_setleds(led, RGBLED_NUM);
535 #endif
3a860c4b 536 }
0a40654b 537}
d4cd5dda 538#endif
0a40654b 539
6d6d91c8 540#ifdef RGBLIGHT_USE_TIMER
57e08eb8 541
0a40654b
YL
542// Animation timer -- AVR Timer3
543void rgblight_timer_init(void) {
e9f74875
JH
544 // static uint8_t rgblight_timer_is_init = 0;
545 // if (rgblight_timer_is_init) {
546 // return;
547 // }
548 // rgblight_timer_is_init = 1;
549 // /* Timer 3 setup */
550 // TCCR3B = _BV(WGM32) // CTC mode OCR3A as TOP
551 // | _BV(CS30); // Clock selelct: clk/1
552 // /* Set TOP value */
553 // uint8_t sreg = SREG;
554 // cli();
555 // OCR3AH = (RGBLED_TIMER_TOP >> 8) & 0xff;
556 // OCR3AL = RGBLED_TIMER_TOP & 0xff;
557 // SREG = sreg;
558
559 rgblight_timer_enabled = true;
0a40654b
YL
560}
561void rgblight_timer_enable(void) {
e9f74875 562 rgblight_timer_enabled = true;
3a860c4b 563 dprintf("TIMER3 enabled.\n");
0a40654b
YL
564}
565void rgblight_timer_disable(void) {
e9f74875 566 rgblight_timer_enabled = false;
3a860c4b 567 dprintf("TIMER3 disabled.\n");
0a40654b
YL
568}
569void rgblight_timer_toggle(void) {
e9f74875 570 rgblight_timer_enabled ^= rgblight_timer_enabled;
3a860c4b 571 dprintf("TIMER3 toggled.\n");
0a40654b
YL
572}
573
4094544d
EZ
574void rgblight_show_solid_color(uint8_t r, uint8_t g, uint8_t b) {
575 rgblight_enable();
6d6d91c8 576 rgblight_mode(RGBLIGHT_MODE_STATIC_LIGHT);
4094544d
EZ
577 rgblight_setrgb(r, g, b);
578}
579
e9f74875
JH
580void rgblight_task(void) {
581 if (rgblight_timer_enabled) {
6d6d91c8
TI
582 // static light mode, do nothing here
583 if ( 1 == 0 ) { //dummy
584 }
585#ifdef RGBLIGHT_EFFECT_BREATHING
586 else if (rgblight_config.mode >= RGBLIGHT_MODE_BREATHING &&
587 rgblight_config.mode <= RGBLIGHT_MODE_BREATHING_end) {
588 // breathing mode
589 rgblight_effect_breathing(rgblight_config.mode - RGBLIGHT_MODE_BREATHING );
590 }
591#endif
592#ifdef RGBLIGHT_EFFECT_RAINBOW_MOOD
593 else if (rgblight_config.mode >= RGBLIGHT_MODE_RAINBOW_MOOD &&
594 rgblight_config.mode <= RGBLIGHT_MODE_RAINBOW_MOOD_end) {
595 // rainbow mood mode
596 rgblight_effect_rainbow_mood(rgblight_config.mode - RGBLIGHT_MODE_RAINBOW_MOOD);
597 }
598#endif
599#ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL
600 else if (rgblight_config.mode >= RGBLIGHT_MODE_RAINBOW_SWIRL &&
601 rgblight_config.mode <= RGBLIGHT_MODE_RAINBOW_SWIRL_end) {
602 // rainbow swirl mode
603 rgblight_effect_rainbow_swirl(rgblight_config.mode - RGBLIGHT_MODE_RAINBOW_SWIRL);
604 }
605#endif
606#ifdef RGBLIGHT_EFFECT_SNAKE
607 else if (rgblight_config.mode >= RGBLIGHT_MODE_SNAKE &&
608 rgblight_config.mode <= RGBLIGHT_MODE_SNAKE_end) {
609 // snake mode
610 rgblight_effect_snake(rgblight_config.mode - RGBLIGHT_MODE_SNAKE);
611 }
612#endif
613#ifdef RGBLIGHT_EFFECT_KNIGHT
614 else if (rgblight_config.mode >= RGBLIGHT_MODE_KNIGHT &&
615 rgblight_config.mode <= RGBLIGHT_MODE_KNIGHT_end) {
616 // knight mode
617 rgblight_effect_knight(rgblight_config.mode - RGBLIGHT_MODE_KNIGHT);
618 }
619#endif
620#ifdef RGBLIGHT_EFFECT_CHRISTMAS
621 else if (rgblight_config.mode == RGBLIGHT_MODE_CHRISTMAS) {
622 // christmas mode
cae269b0 623 rgblight_effect_christmas();
6d6d91c8
TI
624 }
625#endif
626#ifdef RGBLIGHT_EFFECT_RGB_TEST
627 else if (rgblight_config.mode == RGBLIGHT_MODE_RGB_TEST) {
628 // RGB test mode
52297346 629 rgblight_effect_rgbtest();
6d6d91c8
TI
630 }
631#endif
632#ifdef RGBLIGHT_EFFECT_ALTERNATING
633 else if (rgblight_config.mode == RGBLIGHT_MODE_ALTERNATING){
595f3cbe 634 rgblight_effect_alternating();
e9f74875 635 }
6d6d91c8 636#endif
3a860c4b
JO
637 }
638}
639
6d6d91c8
TI
640#endif /* RGBLIGHT_USE_TIMER */
641
3a860c4b 642// Effects
6d6d91c8
TI
643#ifdef RGBLIGHT_EFFECT_BREATHING
644__attribute__ ((weak))
645const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5};
646
0a40654b 647void rgblight_effect_breathing(uint8_t interval) {
3a860c4b
JO
648 static uint8_t pos = 0;
649 static uint16_t last_timer = 0;
ad49db8c 650 float val;
0a40654b 651
3a860c4b
JO
652 if (timer_elapsed(last_timer) < pgm_read_byte(&RGBLED_BREATHING_INTERVALS[interval])) {
653 return;
654 }
655 last_timer = timer_read();
0a40654b 656
ad49db8c 657 // http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/
658 val = (exp(sin((pos/255.0)*M_PI)) - RGBLIGHT_EFFECT_BREATHE_CENTER/M_E)*(RGBLIGHT_EFFECT_BREATHE_MAX/(M_E-1/M_E));
751719e6 659 rgblight_sethsv_noeeprom_old(rgblight_config.hue, rgblight_config.sat, val);
3a860c4b 660 pos = (pos + 1) % 256;
0a40654b 661}
6d6d91c8
TI
662#endif
663
664#ifdef RGBLIGHT_EFFECT_RAINBOW_MOOD
665__attribute__ ((weak))
666const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[] PROGMEM = {120, 60, 30};
667
0a40654b 668void rgblight_effect_rainbow_mood(uint8_t interval) {
3a860c4b
JO
669 static uint16_t current_hue = 0;
670 static uint16_t last_timer = 0;
0a40654b 671
3a860c4b
JO
672 if (timer_elapsed(last_timer) < pgm_read_byte(&RGBLED_RAINBOW_MOOD_INTERVALS[interval])) {
673 return;
674 }
675 last_timer = timer_read();
751719e6 676 rgblight_sethsv_noeeprom_old(current_hue, rgblight_config.sat, rgblight_config.val);
3a860c4b 677 current_hue = (current_hue + 1) % 360;
0a40654b 678}
6d6d91c8
TI
679#endif
680
681#ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL
94f58322
FT
682#ifndef RGBLIGHT_RAINBOW_SWIRL_RANGE
683 #define RGBLIGHT_RAINBOW_SWIRL_RANGE 360
684#endif
685
6d6d91c8
TI
686__attribute__ ((weak))
687const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[] PROGMEM = {100, 50, 20};
688
0a40654b 689void rgblight_effect_rainbow_swirl(uint8_t interval) {
3a860c4b
JO
690 static uint16_t current_hue = 0;
691 static uint16_t last_timer = 0;
692 uint16_t hue;
693 uint8_t i;
da887ea4 694 if (timer_elapsed(last_timer) < pgm_read_byte(&RGBLED_RAINBOW_SWIRL_INTERVALS[interval / 2])) {
3a860c4b
JO
695 return;
696 }
697 last_timer = timer_read();
698 for (i = 0; i < RGBLED_NUM; i++) {
94f58322 699 hue = (RGBLIGHT_RAINBOW_SWIRL_RANGE / RGBLED_NUM * i + current_hue) % 360;
e9f74875 700 sethsv(hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[i]);
3a860c4b
JO
701 }
702 rgblight_set();
703
704 if (interval % 2) {
705 current_hue = (current_hue + 1) % 360;
706 } else {
707 if (current_hue - 1 < 0) {
708 current_hue = 359;
709 } else {
710 current_hue = current_hue - 1;
711 }
712 }
0a40654b 713}
6d6d91c8
TI
714#endif
715
716#ifdef RGBLIGHT_EFFECT_SNAKE
717__attribute__ ((weak))
718const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {100, 50, 20};
719
0a40654b 720void rgblight_effect_snake(uint8_t interval) {
3a860c4b
JO
721 static uint8_t pos = 0;
722 static uint16_t last_timer = 0;
723 uint8_t i, j;
724 int8_t k;
899c88cd 725 int8_t increment = 1;
3a860c4b 726 if (interval % 2) {
899c88cd 727 increment = -1;
3a860c4b
JO
728 }
729 if (timer_elapsed(last_timer) < pgm_read_byte(&RGBLED_SNAKE_INTERVALS[interval / 2])) {
730 return;
731 }
732 last_timer = timer_read();
733 for (i = 0; i < RGBLED_NUM; i++) {
734 led[i].r = 0;
735 led[i].g = 0;
736 led[i].b = 0;
737 for (j = 0; j < RGBLIGHT_EFFECT_SNAKE_LENGTH; j++) {
899c88cd 738 k = pos + j * increment;
3a860c4b
JO
739 if (k < 0) {
740 k = k + RGBLED_NUM;
741 }
742 if (i == k) {
e9f74875 743 sethsv(rgblight_config.hue, rgblight_config.sat, (uint8_t)(rgblight_config.val*(RGBLIGHT_EFFECT_SNAKE_LENGTH-j)/RGBLIGHT_EFFECT_SNAKE_LENGTH), (LED_TYPE *)&led[i]);
3a860c4b
JO
744 }
745 }
746 }
747 rgblight_set();
899c88cd 748 if (increment == 1) {
3a860c4b
JO
749 if (pos - 1 < 0) {
750 pos = RGBLED_NUM - 1;
751 } else {
752 pos -= 1;
753 }
754 } else {
755 pos = (pos + 1) % RGBLED_NUM;
756 }
0a40654b 757}
6d6d91c8
TI
758#endif
759
760#ifdef RGBLIGHT_EFFECT_KNIGHT
761__attribute__ ((weak))
762const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {127, 63, 31};
763
0a40654b 764void rgblight_effect_knight(uint8_t interval) {
3a860c4b 765 static uint16_t last_timer = 0;
3a860c4b
JO
766 if (timer_elapsed(last_timer) < pgm_read_byte(&RGBLED_KNIGHT_INTERVALS[interval])) {
767 return;
768 }
769 last_timer = timer_read();
4edfa97e
DS
770
771 static int8_t low_bound = 0;
772 static int8_t high_bound = RGBLIGHT_EFFECT_KNIGHT_LENGTH - 1;
773 static int8_t increment = 1;
774 uint8_t i, cur;
775
4580d3a7 776 // Set all the LEDs to 0
94f8b758 777 for (i = 0; i < RGBLED_NUM; i++) {
4580d3a7 778 led[i].r = 0;
779 led[i].g = 0;
780 led[i].b = 0;
781 }
782 // Determine which LEDs should be lit up
783 for (i = 0; i < RGBLIGHT_EFFECT_KNIGHT_LED_NUM; i++) {
94f8b758 784 cur = (i + RGBLIGHT_EFFECT_KNIGHT_OFFSET) % RGBLED_NUM;
4edfa97e
DS
785
786 if (i >= low_bound && i <= high_bound) {
787 sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[cur]);
3a860c4b 788 } else {
4edfa97e
DS
789 led[cur].r = 0;
790 led[cur].g = 0;
791 led[cur].b = 0;
3a860c4b
JO
792 }
793 }
4edfa97e
DS
794 rgblight_set();
795
4580d3a7 796 // Move from low_bound to high_bound changing the direction we increment each
797 // time a boundary is hit.
4edfa97e
DS
798 low_bound += increment;
799 high_bound += increment;
800
4580d3a7 801 if (high_bound <= 0 || low_bound >= RGBLIGHT_EFFECT_KNIGHT_LED_NUM - 1) {
4edfa97e
DS
802 increment = -increment;
803 }
3a860c4b 804}
6d6d91c8 805#endif
3a860c4b 806
6d6d91c8 807#ifdef RGBLIGHT_EFFECT_CHRISTMAS
cae269b0
JH
808void rgblight_effect_christmas(void) {
809 static uint16_t current_offset = 0;
810 static uint16_t last_timer = 0;
811 uint16_t hue;
812 uint8_t i;
0e548f8b 813 if (timer_elapsed(last_timer) < RGBLIGHT_EFFECT_CHRISTMAS_INTERVAL) {
cae269b0
JH
814 return;
815 }
816 last_timer = timer_read();
817 current_offset = (current_offset + 1) % 2;
818 for (i = 0; i < RGBLED_NUM; i++) {
0e548f8b 819 hue = 0 + ((i/RGBLIGHT_EFFECT_CHRISTMAS_STEP + current_offset) % 2) * 120;
cae269b0
JH
820 sethsv(hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[i]);
821 }
822 rgblight_set();
823}
6d6d91c8
TI
824#endif
825
826#ifdef RGBLIGHT_EFFECT_RGB_TEST
827__attribute__ ((weak))
828const uint16_t RGBLED_RGBTEST_INTERVALS[] PROGMEM = {1024};
cae269b0 829
52297346
TI
830void rgblight_effect_rgbtest(void) {
831 static uint8_t pos = 0;
832 static uint16_t last_timer = 0;
833 static uint8_t maxval = 0;
834 uint8_t g; uint8_t r; uint8_t b;
835
836 if (timer_elapsed(last_timer) < pgm_read_word(&RGBLED_RGBTEST_INTERVALS[0])) {
837 return;
838 }
839
840 if( maxval == 0 ) {
841 LED_TYPE tmp_led;
842 sethsv(0, 255, RGBLIGHT_LIMIT_VAL, &tmp_led);
843 maxval = tmp_led.r;
844 }
845 last_timer = timer_read();
846 g = r = b = 0;
847 switch( pos ) {
848 case 0: r = maxval; break;
849 case 1: g = maxval; break;
850 case 2: b = maxval; break;
851 }
852 rgblight_setrgb(r, g, b);
853 pos = (pos + 1) % 3;
854}
6d6d91c8 855#endif
52297346 856
6d6d91c8 857#ifdef RGBLIGHT_EFFECT_ALTERNATING
595f3cbe
B
858void rgblight_effect_alternating(void){
859 static uint16_t last_timer = 0;
860 static uint16_t pos = 0;
861 if (timer_elapsed(last_timer) < 500) {
862 return;
863 }
864 last_timer = timer_read();
865
866 for(int i = 0; i<RGBLED_NUM; i++){
db03b769 867 if(i<RGBLED_NUM/2 && pos){
868 sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[i]);
869 }else if (i>=RGBLED_NUM/2 && !pos){
870 sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[i]);
871 }else{
872 sethsv(rgblight_config.hue, rgblight_config.sat, 0, (LED_TYPE *)&led[i]);
873 }
595f3cbe
B
874 }
875 rgblight_set();
876 pos = (pos + 1) % 2;
877}
6d6d91c8 878#endif