add RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS; to rgblight_update_dword()
[jackhill/qmk/firmware.git] / quantum / rgblight.c
... / ...
CommitLineData
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 */
16#include <math.h>
17#include <string.h>
18#ifdef __AVR__
19 #include <avr/eeprom.h>
20 #include <avr/interrupt.h>
21#endif
22#ifdef STM32_EEPROM_ENABLE
23 #include "hal.h"
24 #include "eeprom.h"
25 #include "eeprom_stm32.h"
26#endif
27#include "wait.h"
28#include "progmem.h"
29#include "timer.h"
30#include "rgblight.h"
31#include "debug.h"
32#include "led_tables.h"
33#ifdef VELOCIKEY_ENABLE
34 #include "velocikey.h"
35#endif
36
37#ifdef RGBLIGHT_SPLIT
38 /* for split keyboard */
39 #define RGBLIGHT_SPLIT_SET_CHANGE_MODE rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_MODE
40 #define RGBLIGHT_SPLIT_SET_CHANGE_HSVS rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_HSVS
41 #define RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS rgblight_status.change_flags |= (RGBLIGHT_STATUS_CHANGE_MODE|RGBLIGHT_STATUS_CHANGE_HSVS)
42 #define RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_TIMER
43 #define RGBLIGHT_SPLIT_ANIMATION_TICK rgblight_status.change_flags |= RGBLIGHT_STATUS_ANIMATION_TICK
44#else
45 #define RGBLIGHT_SPLIT_SET_CHANGE_MODE
46 #define RGBLIGHT_SPLIT_SET_CHANGE_HSVS
47 #define RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS
48 #define RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE
49 #define RGBLIGHT_SPLIT_ANIMATION_TICK
50#endif
51
52#define _RGBM_SINGLE_STATIC(sym) RGBLIGHT_MODE_ ## sym,
53#define _RGBM_SINGLE_DYNAMIC(sym)
54#define _RGBM_MULTI_STATIC(sym) RGBLIGHT_MODE_ ## sym,
55#define _RGBM_MULTI_DYNAMIC(sym)
56#define _RGBM_TMP_STATIC(sym, msym) RGBLIGHT_MODE_ ## sym,
57#define _RGBM_TMP_DYNAMIC(sym, msym)
58static uint8_t static_effect_table [] = {
59#include "rgblight_modes.h"
60};
61
62#define _RGBM_SINGLE_STATIC(sym) RGBLIGHT_MODE_ ## sym,
63#define _RGBM_SINGLE_DYNAMIC(sym) RGBLIGHT_MODE_ ## sym,
64#define _RGBM_MULTI_STATIC(sym) RGBLIGHT_MODE_ ## sym,
65#define _RGBM_MULTI_DYNAMIC(sym) RGBLIGHT_MODE_ ## sym,
66#define _RGBM_TMP_STATIC(sym, msym) RGBLIGHT_MODE_ ## msym,
67#define _RGBM_TMP_DYNAMIC(sym, msym) RGBLIGHT_MODE_ ## msym,
68static uint8_t mode_base_table [] = {
69 0, // RGBLIGHT_MODE_zero
70#include "rgblight_modes.h"
71};
72
73static inline int is_static_effect(uint8_t mode) {
74 return memchr(static_effect_table, mode, sizeof(static_effect_table)) != NULL;
75}
76
77#define MIN(a,b) (((a)<(b))?(a):(b))
78#define MAX(a,b) (((a)>(b))?(a):(b))
79
80#ifdef RGBLIGHT_LED_MAP
81const uint8_t led_map[] PROGMEM = RGBLIGHT_LED_MAP;
82#endif
83
84#ifdef RGBLIGHT_EFFECT_STATIC_GRADIENT
85__attribute__ ((weak))
86const uint16_t RGBLED_GRADIENT_RANGES[] PROGMEM = {360, 240, 180, 120, 90};
87#endif
88
89rgblight_config_t rgblight_config;
90rgblight_status_t rgblight_status = { .timer_enabled = false };
91bool is_rgblight_initialized = false;
92
93#ifdef RGBLIGHT_USE_TIMER
94animation_status_t animation_status = {};
95#endif
96
97#ifndef LED_ARRAY
98LED_TYPE led[RGBLED_NUM];
99 #define LED_ARRAY led
100#endif
101
102
103static uint8_t clipping_start_pos = 0;
104static uint8_t clipping_num_leds = RGBLED_NUM;
105
106void rgblight_set_clipping_range(uint8_t start_pos, uint8_t num_leds) {
107 clipping_start_pos = start_pos;
108 clipping_num_leds = num_leds;
109}
110
111
112void sethsv(uint16_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1) {
113 uint8_t r = 0, g = 0, b = 0, base, color;
114
115 if (val > RGBLIGHT_LIMIT_VAL) {
116 val=RGBLIGHT_LIMIT_VAL; // limit the val
117 }
118
119 if (sat == 0) { // Acromatic color (gray). Hue doesn't mind.
120 r = val;
121 g = val;
122 b = val;
123 } else {
124 base = ((255 - sat) * val) >> 8;
125 color = (val - base) * (hue % 60) / 60;
126
127 switch (hue / 60) {
128 case 0:
129 r = val;
130 g = base + color;
131 b = base;
132 break;
133 case 1:
134 r = val - color;
135 g = val;
136 b = base;
137 break;
138 case 2:
139 r = base;
140 g = val;
141 b = base + color;
142 break;
143 case 3:
144 r = base;
145 g = val - color;
146 b = val;
147 break;
148 case 4:
149 r = base + color;
150 g = base;
151 b = val;
152 break;
153 case 5:
154 r = val;
155 g = base;
156 b = val - color;
157 break;
158 }
159 }
160 r = pgm_read_byte(&CIE1931_CURVE[r]);
161 g = pgm_read_byte(&CIE1931_CURVE[g]);
162 b = pgm_read_byte(&CIE1931_CURVE[b]);
163
164 setrgb(r, g, b, led1);
165}
166
167void setrgb(uint8_t r, uint8_t g, uint8_t b, LED_TYPE *led1) {
168 (*led1).r = r;
169 (*led1).g = g;
170 (*led1).b = b;
171}
172
173void rgblight_check_config(void) {
174 /* Add some out of bound checks for RGB light config */
175
176 if (rgblight_config.mode < RGBLIGHT_MODE_STATIC_LIGHT) {
177 rgblight_config.mode = RGBLIGHT_MODE_STATIC_LIGHT;
178 }
179 else if (rgblight_config.mode > RGBLIGHT_MODES) {
180 rgblight_config.mode = RGBLIGHT_MODES;
181 }
182
183 if (rgblight_config.hue < 0) {
184 rgblight_config.hue = 0;
185 } else if (rgblight_config.hue > 360) {
186 rgblight_config.hue %= 360;
187 }
188
189 if (rgblight_config.sat < 0) {
190 rgblight_config.sat = 0;
191 } else if (rgblight_config.sat > 255) {
192 rgblight_config.sat = 255;
193 }
194
195 if (rgblight_config.val < 0) {
196 rgblight_config.val = 0;
197 } else if (rgblight_config.val > RGBLIGHT_LIMIT_VAL) {
198 rgblight_config.val = RGBLIGHT_LIMIT_VAL;
199 }
200
201}
202
203uint32_t eeconfig_read_rgblight(void) {
204 #if defined(__AVR__) || defined(STM32_EEPROM_ENABLE) || defined(PROTOCOL_ARM_ATSAM) || defined(EEPROM_SIZE)
205 return eeprom_read_dword(EECONFIG_RGBLIGHT);
206 #else
207 return 0;
208 #endif
209}
210
211void eeconfig_update_rgblight(uint32_t val) {
212 #if defined(__AVR__) || defined(STM32_EEPROM_ENABLE) || defined(PROTOCOL_ARM_ATSAM) || defined(EEPROM_SIZE)
213 rgblight_check_config();
214 eeprom_update_dword(EECONFIG_RGBLIGHT, val);
215 #endif
216}
217
218void eeconfig_update_rgblight_default(void) {
219 //dprintf("eeconfig_update_rgblight_default\n");
220 rgblight_config.enable = 1;
221 rgblight_config.mode = RGBLIGHT_MODE_STATIC_LIGHT;
222 rgblight_config.hue = 0;
223 rgblight_config.sat = 255;
224 rgblight_config.val = RGBLIGHT_LIMIT_VAL;
225 rgblight_config.speed = 0;
226 RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS;
227 eeconfig_update_rgblight(rgblight_config.raw);
228}
229
230void eeconfig_debug_rgblight(void) {
231 dprintf("rgblight_config eprom\n");
232 dprintf("rgblight_config.enable = %d\n", rgblight_config.enable);
233 dprintf("rghlight_config.mode = %d\n", rgblight_config.mode);
234 dprintf("rgblight_config.hue = %d\n", rgblight_config.hue);
235 dprintf("rgblight_config.sat = %d\n", rgblight_config.sat);
236 dprintf("rgblight_config.val = %d\n", rgblight_config.val);
237 dprintf("rgblight_config.speed = %d\n", rgblight_config.speed);
238}
239
240void rgblight_init(void) {
241 /* if already initialized, don't do it again.
242 If you must do it again, extern this and set to false, first.
243 This is a dirty, dirty hack until proper hooks can be added for keyboard startup. */
244 if (is_rgblight_initialized) { return; }
245
246 debug_enable = 1; // Debug ON!
247 dprintf("rgblight_init called.\n");
248 dprintf("rgblight_init start!\n");
249 if (!eeconfig_is_enabled()) {
250 dprintf("rgblight_init eeconfig is not enabled.\n");
251 eeconfig_init();
252 eeconfig_update_rgblight_default();
253 }
254 rgblight_config.raw = eeconfig_read_rgblight();
255 RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS;
256 if (!rgblight_config.mode) {
257 dprintf("rgblight_init rgblight_config.mode = 0. Write default values to EEPROM.\n");
258 eeconfig_update_rgblight_default();
259 rgblight_config.raw = eeconfig_read_rgblight();
260 }
261 rgblight_check_config();
262
263 eeconfig_debug_rgblight(); // display current eeprom values
264
265#ifdef RGBLIGHT_USE_TIMER
266 rgblight_timer_init(); // setup the timer
267#endif
268
269 if (rgblight_config.enable) {
270 rgblight_mode_noeeprom(rgblight_config.mode);
271 }
272
273 is_rgblight_initialized = true;
274
275}
276
277uint32_t rgblight_read_dword(void) {
278 return rgblight_config.raw;
279}
280
281void rgblight_update_dword(uint32_t dword) {
282 RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS;
283 rgblight_config.raw = dword;
284 if (rgblight_config.enable)
285 rgblight_mode_noeeprom(rgblight_config.mode);
286 else {
287#ifdef RGBLIGHT_USE_TIMER
288 rgblight_timer_disable();
289#endif
290 rgblight_set();
291 }
292}
293
294void rgblight_increase(void) {
295 uint8_t mode = 0;
296 if (rgblight_config.mode < RGBLIGHT_MODES) {
297 mode = rgblight_config.mode + 1;
298 }
299 rgblight_mode(mode);
300}
301void rgblight_decrease(void) {
302 uint8_t mode = 0;
303 // Mode will never be < 1. If it ever is, eeprom needs to be initialized.
304 if (rgblight_config.mode > RGBLIGHT_MODE_STATIC_LIGHT) {
305 mode = rgblight_config.mode - 1;
306 }
307 rgblight_mode(mode);
308}
309void rgblight_step_helper(bool write_to_eeprom) {
310 uint8_t mode = 0;
311 mode = rgblight_config.mode + 1;
312 if (mode > RGBLIGHT_MODES) {
313 mode = 1;
314 }
315 rgblight_mode_eeprom_helper(mode, write_to_eeprom);
316}
317void rgblight_step_noeeprom(void) {
318 rgblight_step_helper(false);
319}
320void rgblight_step(void) {
321 rgblight_step_helper(true);
322}
323void rgblight_step_reverse_helper(bool write_to_eeprom) {
324 uint8_t mode = 0;
325 mode = rgblight_config.mode - 1;
326 if (mode < 1) {
327 mode = RGBLIGHT_MODES;
328 }
329 rgblight_mode_eeprom_helper(mode, write_to_eeprom);
330}
331void rgblight_step_reverse_noeeprom(void) {
332 rgblight_step_reverse_helper(false);
333}
334void rgblight_step_reverse(void) {
335 rgblight_step_reverse_helper(true);
336}
337
338uint8_t rgblight_get_mode(void) {
339 if (!rgblight_config.enable) {
340 return false;
341 }
342
343 return rgblight_config.mode;
344}
345
346void rgblight_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom) {
347 if (!rgblight_config.enable) {
348 return;
349 }
350 if (mode < RGBLIGHT_MODE_STATIC_LIGHT) {
351 rgblight_config.mode = RGBLIGHT_MODE_STATIC_LIGHT;
352 } else if (mode > RGBLIGHT_MODES) {
353 rgblight_config.mode = RGBLIGHT_MODES;
354 } else {
355 rgblight_config.mode = mode;
356 }
357 RGBLIGHT_SPLIT_SET_CHANGE_MODE;
358 if (write_to_eeprom) {
359 eeconfig_update_rgblight(rgblight_config.raw);
360 xprintf("rgblight mode [EEPROM]: %u\n", rgblight_config.mode);
361 } else {
362 xprintf("rgblight mode [NOEEPROM]: %u\n", rgblight_config.mode);
363 }
364 if( is_static_effect(rgblight_config.mode) ) {
365#ifdef RGBLIGHT_USE_TIMER
366 rgblight_timer_disable();
367#endif
368 } else {
369#ifdef RGBLIGHT_USE_TIMER
370 rgblight_timer_enable();
371#endif
372 }
373#ifdef RGBLIGHT_USE_TIMER
374 animation_status.restart = true;
375#endif
376 rgblight_sethsv_noeeprom(rgblight_config.hue, rgblight_config.sat, rgblight_config.val);
377}
378
379void rgblight_mode(uint8_t mode) {
380 rgblight_mode_eeprom_helper(mode, true);
381}
382
383void rgblight_mode_noeeprom(uint8_t mode) {
384 rgblight_mode_eeprom_helper(mode, false);
385}
386
387
388void rgblight_toggle(void) {
389 xprintf("rgblight toggle [EEPROM]: rgblight_config.enable = %u\n", !rgblight_config.enable);
390 if (rgblight_config.enable) {
391 rgblight_disable();
392 }
393 else {
394 rgblight_enable();
395 }
396}
397
398void rgblight_toggle_noeeprom(void) {
399 xprintf("rgblight toggle [NOEEPROM]: rgblight_config.enable = %u\n", !rgblight_config.enable);
400 if (rgblight_config.enable) {
401 rgblight_disable_noeeprom();
402 }
403 else {
404 rgblight_enable_noeeprom();
405 }
406}
407
408void rgblight_enable(void) {
409 rgblight_config.enable = 1;
410 // No need to update EEPROM here. rgblight_mode() will do that, actually
411 //eeconfig_update_rgblight(rgblight_config.raw);
412 xprintf("rgblight enable [EEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable);
413 rgblight_mode(rgblight_config.mode);
414}
415
416void rgblight_enable_noeeprom(void) {
417 rgblight_config.enable = 1;
418 xprintf("rgblight enable [NOEEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable);
419 rgblight_mode_noeeprom(rgblight_config.mode);
420}
421
422void rgblight_disable(void) {
423 rgblight_config.enable = 0;
424 eeconfig_update_rgblight(rgblight_config.raw);
425 xprintf("rgblight disable [EEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable);
426#ifdef RGBLIGHT_USE_TIMER
427 rgblight_timer_disable();
428#endif
429 RGBLIGHT_SPLIT_SET_CHANGE_MODE;
430 wait_ms(50);
431 rgblight_set();
432}
433
434void rgblight_disable_noeeprom(void) {
435 rgblight_config.enable = 0;
436 xprintf("rgblight disable [noEEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable);
437#ifdef RGBLIGHT_USE_TIMER
438 rgblight_timer_disable();
439#endif
440 RGBLIGHT_SPLIT_SET_CHANGE_MODE;
441 wait_ms(50);
442 rgblight_set();
443}
444
445
446// Deals with the messy details of incrementing an integer
447static uint8_t increment( uint8_t value, uint8_t step, uint8_t min, uint8_t max ) {
448 int16_t new_value = value;
449 new_value += step;
450 return MIN( MAX( new_value, min ), max );
451}
452
453static uint8_t decrement( uint8_t value, uint8_t step, uint8_t min, uint8_t max ) {
454 int16_t new_value = value;
455 new_value -= step;
456 return MIN( MAX( new_value, min ), max );
457}
458
459void rgblight_increase_hue_helper(bool write_to_eeprom) {
460 uint16_t hue;
461 hue = (rgblight_config.hue+RGBLIGHT_HUE_STEP) % 360;
462 rgblight_sethsv_eeprom_helper(hue, rgblight_config.sat, rgblight_config.val, write_to_eeprom);
463}
464void rgblight_increase_hue_noeeprom(void) {
465 rgblight_increase_hue_helper(false);
466}
467void rgblight_increase_hue(void) {
468 rgblight_increase_hue_helper(true);
469}
470void rgblight_decrease_hue_helper(bool write_to_eeprom) {
471 uint16_t hue;
472 if (rgblight_config.hue-RGBLIGHT_HUE_STEP < 0) {
473 hue = (rgblight_config.hue + 360 - RGBLIGHT_HUE_STEP) % 360;
474 } else {
475 hue = (rgblight_config.hue - RGBLIGHT_HUE_STEP) % 360;
476 }
477 rgblight_sethsv_eeprom_helper(hue, rgblight_config.sat, rgblight_config.val, write_to_eeprom);
478}
479void rgblight_decrease_hue_noeeprom(void) {
480 rgblight_decrease_hue_helper(false);
481}
482void rgblight_decrease_hue(void) {
483 rgblight_decrease_hue_helper(true);
484}
485void rgblight_increase_sat_helper(bool write_to_eeprom) {
486 uint8_t sat;
487 if (rgblight_config.sat + RGBLIGHT_SAT_STEP > 255) {
488 sat = 255;
489 } else {
490 sat = rgblight_config.sat + RGBLIGHT_SAT_STEP;
491 }
492 rgblight_sethsv_eeprom_helper(rgblight_config.hue, sat, rgblight_config.val, write_to_eeprom);
493}
494void rgblight_increase_sat_noeeprom(void) {
495 rgblight_increase_sat_helper(false);
496}
497void rgblight_increase_sat(void) {
498 rgblight_increase_sat_helper(true);
499}
500void rgblight_decrease_sat_helper(bool write_to_eeprom) {
501 uint8_t sat;
502 if (rgblight_config.sat - RGBLIGHT_SAT_STEP < 0) {
503 sat = 0;
504 } else {
505 sat = rgblight_config.sat - RGBLIGHT_SAT_STEP;
506 }
507 rgblight_sethsv_eeprom_helper(rgblight_config.hue, sat, rgblight_config.val, write_to_eeprom);
508}
509void rgblight_decrease_sat_noeeprom(void) {
510 rgblight_decrease_sat_helper(false);
511}
512void rgblight_decrease_sat(void) {
513 rgblight_decrease_sat_helper(true);
514}
515void rgblight_increase_val_helper(bool write_to_eeprom) {
516 uint8_t val;
517 if (rgblight_config.val + RGBLIGHT_VAL_STEP > RGBLIGHT_LIMIT_VAL) {
518 val = RGBLIGHT_LIMIT_VAL;
519 } else {
520 val = rgblight_config.val + RGBLIGHT_VAL_STEP;
521 }
522 rgblight_sethsv_eeprom_helper(rgblight_config.hue, rgblight_config.sat, val, write_to_eeprom);
523}
524void rgblight_increase_val_noeeprom(void) {
525 rgblight_increase_val_helper(false);
526}
527void rgblight_increase_val(void) {
528 rgblight_increase_val_helper(true);
529}
530void rgblight_decrease_val_helper(bool write_to_eeprom) {
531 uint8_t val;
532 if (rgblight_config.val - RGBLIGHT_VAL_STEP < 0) {
533 val = 0;
534 } else {
535 val = rgblight_config.val - RGBLIGHT_VAL_STEP;
536 }
537 rgblight_sethsv_eeprom_helper(rgblight_config.hue, rgblight_config.sat, val, write_to_eeprom);
538}
539void rgblight_decrease_val_noeeprom(void) {
540 rgblight_decrease_val_helper(false);
541}
542void rgblight_decrease_val(void) {
543 rgblight_decrease_val_helper(true);
544}
545void rgblight_increase_speed(void) {
546 rgblight_config.speed = increment( rgblight_config.speed, 1, 0, 3 );
547 //RGBLIGHT_SPLIT_SET_CHANGE_HSVS; // NEED?
548 eeconfig_update_rgblight(rgblight_config.raw);//EECONFIG needs to be increased to support this
549}
550
551void rgblight_decrease_speed(void) {
552 rgblight_config.speed = decrement( rgblight_config.speed, 1, 0, 3 );
553 //RGBLIGHT_SPLIT_SET_CHANGE_HSVS; // NEED??
554 eeconfig_update_rgblight(rgblight_config.raw);//EECONFIG needs to be increased to support this
555}
556
557void rgblight_sethsv_noeeprom_old(uint16_t hue, uint8_t sat, uint8_t val) {
558 if (rgblight_config.enable) {
559 LED_TYPE tmp_led;
560 sethsv(hue, sat, val, &tmp_led);
561 // dprintf("rgblight set hue [MEMORY]: %u,%u,%u\n", inmem_config.hue, inmem_config.sat, inmem_config.val);
562 rgblight_setrgb(tmp_led.r, tmp_led.g, tmp_led.b);
563 }
564}
565
566void rgblight_sethsv_eeprom_helper(uint16_t hue, uint8_t sat, uint8_t val, bool write_to_eeprom) {
567 if (rgblight_config.enable) {
568 rgblight_status.base_mode = mode_base_table[rgblight_config.mode];
569 if (rgblight_config.mode == RGBLIGHT_MODE_STATIC_LIGHT) {
570 // same static color
571 LED_TYPE tmp_led;
572 sethsv(hue, sat, val, &tmp_led);
573 rgblight_setrgb(tmp_led.r, tmp_led.g, tmp_led.b);
574 } else {
575 // all LEDs in same color
576 if ( 1 == 0 ) { //dummy
577 }
578#ifdef RGBLIGHT_EFFECT_BREATHING
579 else if (rgblight_status.base_mode == RGBLIGHT_MODE_BREATHING ) {
580 // breathing mode, ignore the change of val, use in memory value instead
581 val = rgblight_config.val;
582 }
583#endif
584#ifdef RGBLIGHT_EFFECT_RAINBOW_MOOD
585 else if (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_MOOD) {
586 // rainbow mood, ignore the change of hue
587 hue = rgblight_config.hue;
588 }
589#endif
590#ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL
591 else if (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_SWIRL) {
592 // rainbow swirl, ignore the change of hue
593 hue = rgblight_config.hue;
594 }
595#endif
596#ifdef RGBLIGHT_EFFECT_STATIC_GRADIENT
597 else if (rgblight_status.base_mode == RGBLIGHT_MODE_STATIC_GRADIENT) {
598 // static gradient
599 uint16_t _hue;
600 uint8_t delta = rgblight_config.mode - rgblight_status.base_mode;
601 int8_t direction = (delta % 2) ? -1 : 1;
602 uint16_t range = pgm_read_word(&RGBLED_GRADIENT_RANGES[delta / 2]);
603 for (uint8_t i = 0; i < RGBLED_NUM; i++) {
604 _hue = (range / RGBLED_NUM * i * direction + hue + 360) % 360;
605 dprintf("rgblight rainbow set hsv: %u,%u,%d,%u\n", i, _hue, direction, range);
606 sethsv(_hue, sat, val, (LED_TYPE *)&led[i]);
607 }
608 rgblight_set();
609 }
610#endif
611 }
612#ifdef RGBLIGHT_SPLIT
613 if( rgblight_config.hue != hue ||
614 rgblight_config.sat != sat ||
615 rgblight_config.val != val ) {
616 RGBLIGHT_SPLIT_SET_CHANGE_HSVS;
617 }
618#endif
619 rgblight_config.hue = hue;
620 rgblight_config.sat = sat;
621 rgblight_config.val = val;
622 if (write_to_eeprom) {
623 eeconfig_update_rgblight(rgblight_config.raw);
624 xprintf("rgblight set hsv [EEPROM]: %u,%u,%u\n", rgblight_config.hue, rgblight_config.sat, rgblight_config.val);
625 } else {
626 xprintf("rgblight set hsv [NOEEPROM]: %u,%u,%u\n", rgblight_config.hue, rgblight_config.sat, rgblight_config.val);
627 }
628 }
629}
630
631void rgblight_sethsv(uint16_t hue, uint8_t sat, uint8_t val) {
632 rgblight_sethsv_eeprom_helper(hue, sat, val, true);
633}
634
635void rgblight_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val) {
636 rgblight_sethsv_eeprom_helper(hue, sat, val, false);
637}
638
639uint16_t rgblight_get_hue(void) {
640 return rgblight_config.hue;
641}
642
643uint8_t rgblight_get_sat(void) {
644 return rgblight_config.sat;
645}
646
647uint8_t rgblight_get_val(void) {
648 return rgblight_config.val;
649}
650
651void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b) {
652 if (!rgblight_config.enable) { return; }
653
654 for (uint8_t i = 0; i < RGBLED_NUM; i++) {
655 led[i].r = r;
656 led[i].g = g;
657 led[i].b = b;
658 }
659 rgblight_set();
660}
661
662void rgblight_setrgb_at(uint8_t r, uint8_t g, uint8_t b, uint8_t index) {
663 if (!rgblight_config.enable || index >= RGBLED_NUM) { return; }
664
665 led[index].r = r;
666 led[index].g = g;
667 led[index].b = b;
668 rgblight_set();
669}
670
671void rgblight_sethsv_at(uint16_t hue, uint8_t sat, uint8_t val, uint8_t index) {
672 if (!rgblight_config.enable) { return; }
673
674 LED_TYPE tmp_led;
675 sethsv(hue, sat, val, &tmp_led);
676 rgblight_setrgb_at(tmp_led.r, tmp_led.g, tmp_led.b, index);
677}
678
679#if defined(RGBLIGHT_EFFECT_BREATHING) || defined(RGBLIGHT_EFFECT_RAINBOW_MOOD) || defined(RGBLIGHT_EFFECT_RAINBOW_SWIRL) \
680 || defined(RGBLIGHT_EFFECT_SNAKE) || defined(RGBLIGHT_EFFECT_KNIGHT)
681
682static uint8_t get_interval_time(const uint8_t* default_interval_address, uint8_t velocikey_min, uint8_t velocikey_max) {
683 return
684#ifdef VELOCIKEY_ENABLE
685 velocikey_enabled() ? velocikey_match_speed(velocikey_min, velocikey_max) :
686#endif
687 pgm_read_byte(default_interval_address);
688}
689
690#endif
691
692void rgblight_setrgb_range(uint8_t r, uint8_t g, uint8_t b, uint8_t start, uint8_t end) {
693 if (!rgblight_config.enable || start < 0 || start >= end || end > RGBLED_NUM) { return; }
694
695 for (uint8_t i = start; i < end; i++) {
696 led[i].r = r;
697 led[i].g = g;
698 led[i].b = b;
699 }
700 rgblight_set();
701 wait_ms(1);
702}
703
704void rgblight_sethsv_range(uint16_t hue, uint8_t sat, uint8_t val, uint8_t start, uint8_t end) {
705 if (!rgblight_config.enable) { return; }
706
707 LED_TYPE tmp_led;
708 sethsv(hue, sat, val, &tmp_led);
709 rgblight_setrgb_range(tmp_led.r, tmp_led.g, tmp_led.b, start, end);
710}
711
712void rgblight_setrgb_master(uint8_t r, uint8_t g, uint8_t b) {
713 rgblight_setrgb_range(r, g, b, 0 , (uint8_t) RGBLED_NUM/2);
714}
715
716void rgblight_setrgb_slave(uint8_t r, uint8_t g, uint8_t b) {
717 rgblight_setrgb_range(r, g, b, (uint8_t) RGBLED_NUM/2, (uint8_t) RGBLED_NUM);
718}
719
720void rgblight_sethsv_master(uint16_t hue, uint8_t sat, uint8_t val) {
721 rgblight_sethsv_range(hue, sat, val, 0, (uint8_t) RGBLED_NUM/2);
722}
723
724void rgblight_sethsv_slave(uint16_t hue, uint8_t sat, uint8_t val) {
725 rgblight_sethsv_range(hue, sat, val, (uint8_t) RGBLED_NUM/2, (uint8_t) RGBLED_NUM);
726}
727
728#ifndef RGBLIGHT_CUSTOM_DRIVER
729void rgblight_set(void) {
730 LED_TYPE *start_led = led + clipping_start_pos;
731 uint16_t num_leds = clipping_num_leds;
732 if (rgblight_config.enable) {
733 #ifdef RGBLIGHT_LED_MAP
734 LED_TYPE led0[RGBLED_NUM];
735 for(uint8_t i = 0; i < RGBLED_NUM; i++) {
736 led0[i] = led[pgm_read_byte(&led_map[i])];
737 }
738 start_led = led0 + clipping_start_pos;
739 #endif
740 #ifdef RGBW
741 ws2812_setleds_rgbw(start_led, num_leds);
742 #else
743 ws2812_setleds(start_led, num_leds);
744 #endif
745 } else {
746 for (uint8_t i = 0; i < RGBLED_NUM; i++) {
747 led[i].r = 0;
748 led[i].g = 0;
749 led[i].b = 0;
750 }
751 #ifdef RGBW
752 ws2812_setleds_rgbw(start_led, num_leds);
753 #else
754 ws2812_setleds(start_led, num_leds);
755 #endif
756 }
757}
758#endif
759
760#ifdef RGBLIGHT_SPLIT
761/* for split keyboard master side */
762uint8_t rgblight_get_change_flags(void) {
763 return rgblight_status.change_flags;
764}
765
766void rgblight_clear_change_flags(void) {
767 rgblight_status.change_flags = 0;
768}
769
770void rgblight_get_syncinfo(rgblight_syncinfo_t *syncinfo) {
771 syncinfo->config = rgblight_config;
772 syncinfo->status = rgblight_status;
773}
774
775/* for split keyboard slave side */
776void rgblight_update_sync(rgblight_syncinfo_t *syncinfo, bool write_to_eeprom) {
777 if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_MODE) {
778 if (syncinfo->config.enable) {
779 rgblight_config.enable = 1; // == rgblight_enable_noeeprom();
780 rgblight_mode_eeprom_helper(syncinfo->config.mode, write_to_eeprom);
781 } else {
782 rgblight_disable_noeeprom();
783 }
784 }
785 if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_HSVS) {
786 rgblight_sethsv_eeprom_helper(syncinfo->config.hue, syncinfo->config.sat, syncinfo->config.val, write_to_eeprom);
787 // rgblight_config.speed = config->speed; // NEED???
788 }
789 #ifdef RGBLIGHT_USE_TIMER
790 if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_TIMER) {
791 if (syncinfo->status.timer_enabled) {
792 rgblight_timer_enable();
793 } else {
794 rgblight_timer_disable();
795 }
796 }
797 #ifndef RGBLIGHT_SPLIT_NO_ANIMATION_SYNC
798 if (syncinfo->status.change_flags & RGBLIGHT_STATUS_ANIMATION_TICK) {
799 animation_status.restart = true;
800 }
801 #endif /* RGBLIGHT_SPLIT_NO_ANIMATION_SYNC */
802 #endif /* RGBLIGHT_USE_TIMER */
803}
804#endif /* RGBLIGHT_SPLIT */
805
806#ifdef RGBLIGHT_USE_TIMER
807
808typedef void (*effect_func_t)(animation_status_t *anim);
809
810// Animation timer -- use system timer (AVR Timer0)
811void rgblight_timer_init(void) {
812 // OLD!!!! Animation timer -- AVR Timer3
813 // static uint8_t rgblight_timer_is_init = 0;
814 // if (rgblight_timer_is_init) {
815 // return;
816 // }
817 // rgblight_timer_is_init = 1;
818 // /* Timer 3 setup */
819 // TCCR3B = _BV(WGM32) // CTC mode OCR3A as TOP
820 // | _BV(CS30); // Clock selelct: clk/1
821 // /* Set TOP value */
822 // uint8_t sreg = SREG;
823 // cli();
824 // OCR3AH = (RGBLED_TIMER_TOP >> 8) & 0xff;
825 // OCR3AL = RGBLED_TIMER_TOP & 0xff;
826 // SREG = sreg;
827
828 rgblight_status.timer_enabled = false;
829 RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE;
830}
831void rgblight_timer_enable(void) {
832 if( !is_static_effect(rgblight_config.mode) ) {
833 rgblight_status.timer_enabled = true;
834 }
835 animation_status.last_timer = timer_read();
836 RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE;
837 dprintf("rgblight timer enabled.\n");
838}
839void rgblight_timer_disable(void) {
840 rgblight_status.timer_enabled = false;
841 RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE;
842 dprintf("rgblight timer disable.\n");
843}
844void rgblight_timer_toggle(void) {
845 dprintf("rgblight timer toggle.\n");
846 if(rgblight_status.timer_enabled) {
847 rgblight_timer_disable();
848 } else {
849 rgblight_timer_enable();
850 }
851}
852
853void rgblight_show_solid_color(uint8_t r, uint8_t g, uint8_t b) {
854 rgblight_enable();
855 rgblight_mode(RGBLIGHT_MODE_STATIC_LIGHT);
856 rgblight_setrgb(r, g, b);
857}
858
859static void rgblight_effect_dummy(animation_status_t *anim) {
860 // do nothing
861 /********
862 dprintf("rgblight_task() what happened?\n");
863 dprintf("is_static_effect %d\n", is_static_effect(rgblight_config.mode));
864 dprintf("mode = %d, base_mode = %d, timer_enabled %d, ",
865 rgblight_config.mode, rgblight_status.base_mode,
866 rgblight_status.timer_enabled);
867 dprintf("last_timer = %d\n",anim->last_timer);
868 **/
869}
870
871void rgblight_task(void) {
872 if (rgblight_status.timer_enabled) {
873 effect_func_t effect_func = rgblight_effect_dummy;
874 uint16_t interval_time = 2000; // dummy interval
875 uint8_t delta = rgblight_config.mode - rgblight_status.base_mode;
876 animation_status.delta = delta;
877
878 // static light mode, do nothing here
879 if ( 1 == 0 ) { //dummy
880 }
881#ifdef RGBLIGHT_EFFECT_BREATHING
882 else if (rgblight_status.base_mode == RGBLIGHT_MODE_BREATHING) {
883 // breathing mode
884 interval_time = get_interval_time(&RGBLED_BREATHING_INTERVALS[delta], 1, 100);
885 effect_func = rgblight_effect_breathing;
886 }
887#endif
888#ifdef RGBLIGHT_EFFECT_RAINBOW_MOOD
889 else if (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_MOOD) {
890 // rainbow mood mode
891 interval_time = get_interval_time(&RGBLED_RAINBOW_MOOD_INTERVALS[delta], 5, 100);
892 effect_func = rgblight_effect_rainbow_mood;
893 }
894#endif
895#ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL
896 else if (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_SWIRL) {
897 // rainbow swirl mode
898 interval_time = get_interval_time(&RGBLED_RAINBOW_SWIRL_INTERVALS[delta / 2], 1, 100);
899 effect_func = rgblight_effect_rainbow_swirl;
900 }
901#endif
902#ifdef RGBLIGHT_EFFECT_SNAKE
903 else if (rgblight_status.base_mode == RGBLIGHT_MODE_SNAKE) {
904 // snake mode
905 interval_time = get_interval_time(&RGBLED_SNAKE_INTERVALS[delta / 2], 1, 200);
906 effect_func = rgblight_effect_snake;
907 }
908#endif
909#ifdef RGBLIGHT_EFFECT_KNIGHT
910 else if (rgblight_status.base_mode == RGBLIGHT_MODE_KNIGHT) {
911 // knight mode
912 interval_time = get_interval_time(&RGBLED_KNIGHT_INTERVALS[delta], 5, 100);
913 effect_func = rgblight_effect_knight;
914 }
915#endif
916#ifdef RGBLIGHT_EFFECT_CHRISTMAS
917 else if (rgblight_status.base_mode == RGBLIGHT_MODE_CHRISTMAS) {
918 // christmas mode
919 interval_time = RGBLIGHT_EFFECT_CHRISTMAS_INTERVAL;
920 effect_func = (effect_func_t)rgblight_effect_christmas;
921 }
922#endif
923#ifdef RGBLIGHT_EFFECT_RGB_TEST
924 else if (rgblight_status.base_mode == RGBLIGHT_MODE_RGB_TEST) {
925 // RGB test mode
926 interval_time = pgm_read_word(&RGBLED_RGBTEST_INTERVALS[0]);
927 effect_func = (effect_func_t)rgblight_effect_rgbtest;
928 }
929#endif
930#ifdef RGBLIGHT_EFFECT_ALTERNATING
931 else if (rgblight_status.base_mode == RGBLIGHT_MODE_ALTERNATING){
932 interval_time = 500;
933 effect_func = (effect_func_t)rgblight_effect_alternating;
934 }
935#endif
936 if (animation_status.restart) {
937 animation_status.restart = false;
938 animation_status.last_timer = timer_read() - interval_time - 1;
939 animation_status.pos16 = 0; // restart signal to local each effect
940 }
941 if (timer_elapsed(animation_status.last_timer) >= interval_time) {
942#if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
943 static uint16_t report_last_timer = 0;
944 static bool tick_flag = false;
945 uint16_t oldpos16;
946 if (tick_flag) {
947 tick_flag = false;
948 //dprintf("rgblight animation tick\n");
949 if (timer_elapsed(report_last_timer) >= 30000) {
950 report_last_timer = timer_read();
951 dprintf("rgblight animation tick report to slave\n");
952 RGBLIGHT_SPLIT_ANIMATION_TICK;
953 }
954 }
955 oldpos16 = animation_status.pos16;
956 //dprintf("call effect function\n");
957#endif
958 animation_status.last_timer += interval_time;
959 effect_func(&animation_status);
960#if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
961 //dprintf("pos16, oldpos16 = %d %d\n",
962 // animation_status.pos16,oldpos16);
963 if (animation_status.pos16 == 0 && oldpos16 != 0) {
964 //dprintf("flag on\n");
965 tick_flag = true;
966 }
967#endif
968 }
969 }
970}
971
972#endif /* RGBLIGHT_USE_TIMER */
973
974// Effects
975#ifdef RGBLIGHT_EFFECT_BREATHING
976__attribute__ ((weak))
977const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5};
978
979void rgblight_effect_breathing(animation_status_t *anim) {
980 float val;
981
982 // http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/
983 val = (exp(sin((anim->pos/255.0)*M_PI)) - RGBLIGHT_EFFECT_BREATHE_CENTER/M_E)*(RGBLIGHT_EFFECT_BREATHE_MAX/(M_E-1/M_E));
984 rgblight_sethsv_noeeprom_old(rgblight_config.hue, rgblight_config.sat, val);
985 anim->pos = (anim->pos + 1) % 256;
986}
987#endif
988
989#ifdef RGBLIGHT_EFFECT_RAINBOW_MOOD
990__attribute__ ((weak))
991const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[] PROGMEM = {120, 60, 30};
992
993void rgblight_effect_rainbow_mood(animation_status_t *anim) {
994 rgblight_sethsv_noeeprom_old(anim->current_hue, rgblight_config.sat, rgblight_config.val);
995 anim->current_hue = (anim->current_hue + 1) % 360;
996}
997#endif
998
999#ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL
1000#ifndef RGBLIGHT_RAINBOW_SWIRL_RANGE
1001 #define RGBLIGHT_RAINBOW_SWIRL_RANGE 360
1002#endif
1003
1004__attribute__ ((weak))
1005const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[] PROGMEM = {100, 50, 20};
1006
1007void rgblight_effect_rainbow_swirl(animation_status_t *anim) {
1008 uint16_t hue;
1009 uint8_t i;
1010
1011 for (i = 0; i < RGBLED_NUM; i++) {
1012 hue = (RGBLIGHT_RAINBOW_SWIRL_RANGE / RGBLED_NUM * i + anim->current_hue) % 360;
1013 sethsv(hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[i]);
1014 }
1015 rgblight_set();
1016
1017 if (anim->delta % 2) {
1018 anim->current_hue = (anim->current_hue + 1) % 360;
1019 } else {
1020 if (anim->current_hue - 1 < 0) {
1021 anim->current_hue = 359;
1022 } else {
1023 anim->current_hue = anim->current_hue - 1;
1024 }
1025 }
1026}
1027#endif
1028
1029#ifdef RGBLIGHT_EFFECT_SNAKE
1030__attribute__ ((weak))
1031const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {100, 50, 20};
1032
1033void rgblight_effect_snake(animation_status_t *anim) {
1034 static uint8_t pos = 0;
1035 uint8_t i, j;
1036 int8_t k;
1037 int8_t increment = 1;
1038
1039 if (anim->delta % 2) {
1040 increment = -1;
1041 }
1042
1043#if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
1044 if (anim->pos == 0) { // restart signal
1045 if (increment == 1) {
1046 pos = RGBLED_NUM - 1;
1047 } else {
1048 pos = 0;
1049 }
1050 anim->pos = 1;
1051 }
1052#endif
1053
1054 for (i = 0; i < RGBLED_NUM; i++) {
1055 led[i].r = 0;
1056 led[i].g = 0;
1057 led[i].b = 0;
1058 for (j = 0; j < RGBLIGHT_EFFECT_SNAKE_LENGTH; j++) {
1059 k = pos + j * increment;
1060 if (k < 0) {
1061 k = k + RGBLED_NUM;
1062 }
1063 if (i == k) {
1064 sethsv(rgblight_config.hue, rgblight_config.sat,
1065 (uint8_t)(rgblight_config.val*(RGBLIGHT_EFFECT_SNAKE_LENGTH-j)/RGBLIGHT_EFFECT_SNAKE_LENGTH),
1066 (LED_TYPE *)&led[i]);
1067 }
1068 }
1069 }
1070 rgblight_set();
1071 if (increment == 1) {
1072 if (pos - 1 < 0) {
1073 pos = RGBLED_NUM - 1;
1074#if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
1075 anim->pos = 0;
1076#endif
1077 } else {
1078 pos -= 1;
1079#if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
1080 anim->pos = 1;
1081#endif
1082 }
1083 } else {
1084 pos = (pos + 1) % RGBLED_NUM;
1085#if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
1086 anim->pos = pos;
1087#endif
1088 }
1089}
1090#endif
1091
1092#ifdef RGBLIGHT_EFFECT_KNIGHT
1093__attribute__ ((weak))
1094const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {127, 63, 31};
1095
1096void rgblight_effect_knight(animation_status_t *anim) {
1097
1098 static int8_t low_bound = 0;
1099 static int8_t high_bound = RGBLIGHT_EFFECT_KNIGHT_LENGTH - 1;
1100 static int8_t increment = 1;
1101 uint8_t i, cur;
1102
1103#if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
1104 if (anim->pos == 0) { // restart signal
1105 anim->pos = 1;
1106 low_bound = 0;
1107 high_bound = RGBLIGHT_EFFECT_KNIGHT_LENGTH - 1;
1108 increment = 1;
1109 }
1110#endif
1111 // Set all the LEDs to 0
1112 for (i = 0; i < RGBLED_NUM; i++) {
1113 led[i].r = 0;
1114 led[i].g = 0;
1115 led[i].b = 0;
1116 }
1117 // Determine which LEDs should be lit up
1118 for (i = 0; i < RGBLIGHT_EFFECT_KNIGHT_LED_NUM; i++) {
1119 cur = (i + RGBLIGHT_EFFECT_KNIGHT_OFFSET) % RGBLED_NUM;
1120
1121 if (i >= low_bound && i <= high_bound) {
1122 sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[cur]);
1123 } else {
1124 led[cur].r = 0;
1125 led[cur].g = 0;
1126 led[cur].b = 0;
1127 }
1128 }
1129 rgblight_set();
1130
1131 // Move from low_bound to high_bound changing the direction we increment each
1132 // time a boundary is hit.
1133 low_bound += increment;
1134 high_bound += increment;
1135
1136 if (high_bound <= 0 || low_bound >= RGBLIGHT_EFFECT_KNIGHT_LED_NUM - 1) {
1137 increment = -increment;
1138#if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
1139 if (increment == 1) {
1140 anim->pos = 0;
1141 }
1142#endif
1143 }
1144}
1145#endif
1146
1147#ifdef RGBLIGHT_EFFECT_CHRISTMAS
1148void rgblight_effect_christmas(animation_status_t *anim) {
1149 uint16_t hue;
1150 uint8_t i;
1151
1152 anim->current_offset = (anim->current_offset + 1) % 2;
1153 for (i = 0; i < RGBLED_NUM; i++) {
1154 hue = 0 + ((i/RGBLIGHT_EFFECT_CHRISTMAS_STEP + anim->current_offset) % 2) * 120;
1155 sethsv(hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[i]);
1156 }
1157 rgblight_set();
1158}
1159#endif
1160
1161#ifdef RGBLIGHT_EFFECT_RGB_TEST
1162__attribute__ ((weak))
1163const uint16_t RGBLED_RGBTEST_INTERVALS[] PROGMEM = {1024};
1164
1165void rgblight_effect_rgbtest(animation_status_t *anim) {
1166 static uint8_t maxval = 0;
1167 uint8_t g; uint8_t r; uint8_t b;
1168
1169 if( maxval == 0 ) {
1170 LED_TYPE tmp_led;
1171 sethsv(0, 255, RGBLIGHT_LIMIT_VAL, &tmp_led);
1172 maxval = tmp_led.r;
1173 }
1174 g = r = b = 0;
1175 switch( anim->pos ) {
1176 case 0: r = maxval; break;
1177 case 1: g = maxval; break;
1178 case 2: b = maxval; break;
1179 }
1180 rgblight_setrgb(r, g, b);
1181 anim->pos = (anim->pos + 1) % 3;
1182}
1183#endif
1184
1185#ifdef RGBLIGHT_EFFECT_ALTERNATING
1186void rgblight_effect_alternating(animation_status_t *anim) {
1187
1188 for(int i = 0; i<RGBLED_NUM; i++){
1189 if(i<RGBLED_NUM/2 && anim->pos){
1190 sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[i]);
1191 }else if (i>=RGBLED_NUM/2 && !anim->pos){
1192 sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[i]);
1193 }else{
1194 sethsv(rgblight_config.hue, rgblight_config.sat, 0, (LED_TYPE *)&led[i]);
1195 }
1196 }
1197 rgblight_set();
1198 anim->pos = (anim->pos + 1) % 2;
1199}
1200#endif