]> git.donarmstrong.com Git - qmk_firmware.git/blob - quantum/rgblight.c
[Keyboard] Added WT69-A PCB (#5721)
[qmk_firmware.git] / quantum / rgblight.c
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)
58 static 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,
68 static uint8_t mode_base_table [] = {
69     0, // RGBLIGHT_MODE_zero
70 #include "rgblight_modes.h"
71 };
72
73 static 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
81 const uint8_t led_map[] PROGMEM = RGBLIGHT_LED_MAP;
82 #endif
83
84 #ifdef RGBLIGHT_EFFECT_STATIC_GRADIENT
85 __attribute__ ((weak))
86 const uint16_t RGBLED_GRADIENT_RANGES[] PROGMEM = {360, 240, 180, 120, 90};
87 #endif
88
89 rgblight_config_t rgblight_config;
90 rgblight_status_t rgblight_status = { .timer_enabled = false };
91 bool is_rgblight_initialized = false;
92
93 #ifdef RGBLIGHT_USE_TIMER
94 animation_status_t animation_status = {};
95 #endif
96
97 #ifndef LED_ARRAY
98 LED_TYPE led[RGBLED_NUM];
99   #define LED_ARRAY led
100 #endif
101
102
103 static uint8_t clipping_start_pos = 0;
104 static uint8_t clipping_num_leds = RGBLED_NUM;
105
106 void 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
112 void 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
167 void 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
173 void 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
203 uint32_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
211 void 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
218 void 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
230 void 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
240 void 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
277 uint32_t rgblight_read_dword(void) {
278   return rgblight_config.raw;
279 }
280
281 void 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
294 void 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 }
301 void 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 }
309 void 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 }
317 void rgblight_step_noeeprom(void) {
318   rgblight_step_helper(false);
319 }
320 void rgblight_step(void) {
321   rgblight_step_helper(true);
322 }
323 void 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 }
331 void rgblight_step_reverse_noeeprom(void) {
332   rgblight_step_reverse_helper(false);
333 }
334 void rgblight_step_reverse(void) {
335   rgblight_step_reverse_helper(true);
336 }
337
338 uint8_t rgblight_get_mode(void) {
339   if (!rgblight_config.enable) {
340     return false;
341   }
342
343   return rgblight_config.mode;
344 }
345
346 void 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
379 void rgblight_mode(uint8_t mode) {
380   rgblight_mode_eeprom_helper(mode, true);
381 }
382
383 void rgblight_mode_noeeprom(uint8_t mode) {
384   rgblight_mode_eeprom_helper(mode, false);
385 }
386
387
388 void 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
398 void 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
408 void 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
416 void 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
422 void 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
434 void 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
447 static 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
453 static 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
459 void 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 }
464 void rgblight_increase_hue_noeeprom(void) {
465   rgblight_increase_hue_helper(false);
466 }
467 void rgblight_increase_hue(void) {
468   rgblight_increase_hue_helper(true);
469 }
470 void 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 }
479 void rgblight_decrease_hue_noeeprom(void) {
480   rgblight_decrease_hue_helper(false);
481 }
482 void rgblight_decrease_hue(void) {
483   rgblight_decrease_hue_helper(true);
484 }
485 void 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 }
494 void rgblight_increase_sat_noeeprom(void) {
495   rgblight_increase_sat_helper(false);
496 }
497 void rgblight_increase_sat(void) {
498   rgblight_increase_sat_helper(true);
499 }
500 void 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 }
509 void rgblight_decrease_sat_noeeprom(void) {
510   rgblight_decrease_sat_helper(false);
511 }
512 void rgblight_decrease_sat(void) {
513   rgblight_decrease_sat_helper(true);
514 }
515 void 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 }
524 void rgblight_increase_val_noeeprom(void) {
525   rgblight_increase_val_helper(false);
526 }
527 void rgblight_increase_val(void) {
528   rgblight_increase_val_helper(true);
529 }
530 void 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 }
539 void rgblight_decrease_val_noeeprom(void) {
540   rgblight_decrease_val_helper(false);
541 }
542 void rgblight_decrease_val(void) {
543   rgblight_decrease_val_helper(true);
544 }
545 void 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
551 void 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
557 void 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
566 void 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
631 void rgblight_sethsv(uint16_t hue, uint8_t sat, uint8_t val) {
632   rgblight_sethsv_eeprom_helper(hue, sat, val, true);
633 }
634
635 void rgblight_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val) {
636   rgblight_sethsv_eeprom_helper(hue, sat, val, false);
637 }
638
639 uint16_t rgblight_get_hue(void) {
640   return rgblight_config.hue;
641 }
642
643 uint8_t rgblight_get_sat(void) {
644   return rgblight_config.sat;
645 }
646
647 uint8_t rgblight_get_val(void) {
648   return rgblight_config.val;
649 }
650
651 void 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
662 void 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
671 void 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
682 static 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
692 void 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
704 void 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
712 void 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
716 void 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
720 void 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
724 void 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
729 void 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 */
762 uint8_t rgblight_get_change_flags(void) {
763     return rgblight_status.change_flags;
764 }
765
766 void rgblight_clear_change_flags(void) {
767     rgblight_status.change_flags = 0;
768 }
769
770 void 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 */
776 void 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
808 typedef void (*effect_func_t)(animation_status_t *anim);
809
810 // Animation timer -- use system timer (AVR Timer0)
811 void 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 }
831 void 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 }
839 void rgblight_timer_disable(void) {
840   rgblight_status.timer_enabled = false;
841   RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE;
842   dprintf("rgblight timer disable.\n");
843 }
844 void 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
853 void 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
859 static 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
871 void 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))
977 const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5};
978
979 void 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))
991 const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[] PROGMEM = {120, 60, 30};
992
993 void 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))
1005 const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[] PROGMEM = {100, 50, 20};
1006
1007 void 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))
1031 const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {100, 50, 20};
1032
1033 void 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))
1094 const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {127, 63, 31};
1095
1096 void 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
1148 void 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))
1163 const uint16_t RGBLED_RGBTEST_INTERVALS[] PROGMEM = {1024};
1164
1165 void 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
1186 void 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