]> git.donarmstrong.com Git - qmk_firmware.git/blob - keyboards/helix/rev2/keymaps/led_test/rgblight.c
fee614db057ad20917e2e4041568d389dd786112
[qmk_firmware.git] / keyboards / helix / rev2 / keymaps / led_test / 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 <avr/eeprom.h>
18 #include <avr/interrupt.h>
19 #include <util/delay.h>
20 #include "progmem.h"
21 #include "timer.h"
22 #include "rgblight.h"
23 #include "debug.h"
24 #include "led_tables.h"
25
26 __attribute__ ((weak))
27 const uint16_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {1024, 20, 10, 5}; //modify for led_test
28 __attribute__ ((weak))
29 const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[] PROGMEM = {120, 60, 30};
30 __attribute__ ((weak))
31 const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[] PROGMEM = {100, 50, 20};
32 __attribute__ ((weak))
33 const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {100, 50, 20};
34 __attribute__ ((weak))
35 const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {127, 63, 31};
36 __attribute__ ((weak))
37 const uint16_t RGBLED_GRADIENT_RANGES[] PROGMEM = {360, 240, 180, 120, 90};
38
39 rgblight_config_t rgblight_config;
40 rgblight_config_t inmem_config;
41
42 LED_TYPE led[RGBLED_NUM];
43 uint8_t rgblight_inited = 0;
44 bool rgblight_timer_enabled = false;
45
46 void sethsv(uint16_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1) {
47   uint8_t r = 0, g = 0, b = 0, base, color;
48
49   #ifdef RGBLIGHT_LIMIT_VAL
50     if (val > RGBLIGHT_LIMIT_VAL) {
51       val=RGBLIGHT_LIMIT_VAL; // limit the val
52     }
53   #endif
54
55   if (sat == 0) { // Acromatic color (gray). Hue doesn't mind.
56     r = val;
57     g = val;
58     b = val;
59   } else {
60     base = ((255 - sat) * val) >> 8;
61     color = (val - base) * (hue % 60) / 60;
62
63     switch (hue / 60) {
64       case 0:
65         r = val;
66         g = base + color;
67         b = base;
68         break;
69       case 1:
70         r = val - color;
71         g = val;
72         b = base;
73         break;
74       case 2:
75         r = base;
76         g = val;
77         b = base + color;
78         break;
79       case 3:
80         r = base;
81         g = val - color;
82         b = val;
83         break;
84       case 4:
85         r = base + color;
86         g = base;
87         b = val;
88         break;
89       case 5:
90         r = val;
91         g = base;
92         b = val - color;
93         break;
94     }
95   }
96   r = pgm_read_byte(&CIE1931_CURVE[r]);
97   g = pgm_read_byte(&CIE1931_CURVE[g]);
98   b = pgm_read_byte(&CIE1931_CURVE[b]);
99
100   setrgb(r, g, b, led1);
101 }
102
103 void setrgb(uint8_t r, uint8_t g, uint8_t b, LED_TYPE *led1) {
104   (*led1).r = r;
105   (*led1).g = g;
106   (*led1).b = b;
107 }
108
109
110 uint32_t eeconfig_read_rgblight(void) {
111   return eeprom_read_dword(EECONFIG_RGBLIGHT);
112 }
113 void eeconfig_update_rgblight(uint32_t val) {
114   eeprom_update_dword(EECONFIG_RGBLIGHT, val);
115 }
116 void eeconfig_update_rgblight_default(void) {
117   dprintf("eeconfig_update_rgblight_default\n");
118   rgblight_config.enable = 1;
119   rgblight_config.mode = 1;
120   rgblight_config.hue = 0;
121   rgblight_config.sat = 255;
122   rgblight_config.val = 255;
123   eeconfig_update_rgblight(rgblight_config.raw);
124 }
125 void eeconfig_debug_rgblight(void) {
126   dprintf("rgblight_config eprom\n");
127   dprintf("rgblight_config.enable = %d\n", rgblight_config.enable);
128   dprintf("rghlight_config.mode = %d\n", rgblight_config.mode);
129   dprintf("rgblight_config.hue = %d\n", rgblight_config.hue);
130   dprintf("rgblight_config.sat = %d\n", rgblight_config.sat);
131   dprintf("rgblight_config.val = %d\n", rgblight_config.val);
132 }
133
134 void rgblight_init(void) {
135   debug_enable = 1; // Debug ON!
136   dprintf("rgblight_init called.\n");
137   rgblight_inited = 1;
138   dprintf("rgblight_init start!\n");
139   if (!eeconfig_is_enabled()) {
140     dprintf("rgblight_init eeconfig is not enabled.\n");
141     eeconfig_init();
142     eeconfig_update_rgblight_default();
143   }
144   rgblight_config.raw = eeconfig_read_rgblight();
145   if (!rgblight_config.mode) {
146     dprintf("rgblight_init rgblight_config.mode = 0. Write default values to EEPROM.\n");
147     eeconfig_update_rgblight_default();
148     rgblight_config.raw = eeconfig_read_rgblight();
149   }
150   eeconfig_debug_rgblight(); // display current eeprom values
151
152   #ifdef RGBLIGHT_ANIMATIONS
153     rgblight_timer_init(); // setup the timer
154   #endif
155
156   if (rgblight_config.enable) {
157     rgblight_mode(rgblight_config.mode);
158   }
159 }
160
161 void rgblight_update_dword(uint32_t dword) {
162   rgblight_config.raw = dword;
163   eeconfig_update_rgblight(rgblight_config.raw);
164   if (rgblight_config.enable)
165     rgblight_mode(rgblight_config.mode);
166   else {
167     #ifdef RGBLIGHT_ANIMATIONS
168       rgblight_timer_disable();
169     #endif
170       rgblight_set();
171   }
172 }
173
174 void rgblight_increase(void) {
175   uint8_t mode = 0;
176   if (rgblight_config.mode < RGBLIGHT_MODES) {
177     mode = rgblight_config.mode + 1;
178   }
179   rgblight_mode(mode);
180 }
181 void rgblight_decrease(void) {
182   uint8_t mode = 0;
183   // Mode will never be < 1. If it ever is, eeprom needs to be initialized.
184   if (rgblight_config.mode > 1) {
185     mode = rgblight_config.mode - 1;
186   }
187   rgblight_mode(mode);
188 }
189 void rgblight_step(void) {
190   uint8_t mode = 0;
191   mode = rgblight_config.mode + 1;
192   if (mode > RGBLIGHT_MODES) {
193     mode = 1;
194   }
195   rgblight_mode(mode);
196 }
197 void rgblight_step_reverse(void) {
198   uint8_t mode = 0;
199   mode = rgblight_config.mode - 1;
200   if (mode < 1) {
201     mode = RGBLIGHT_MODES;
202   }
203   rgblight_mode(mode);
204 }
205
206 uint32_t rgblight_get_mode(void) {
207   if (!rgblight_config.enable) {
208     return false;
209   }
210
211   return rgblight_config.mode;
212 }
213
214 void rgblight_mode(uint8_t mode) {
215   if (!rgblight_config.enable) {
216     return;
217   }
218   if (mode < 1) {
219     rgblight_config.mode = 1;
220   } else if (mode > RGBLIGHT_MODES) {
221     rgblight_config.mode = RGBLIGHT_MODES;
222   } else {
223     rgblight_config.mode = mode;
224   }
225   eeconfig_update_rgblight(rgblight_config.raw);
226   xprintf("rgblight mode: %u\n", rgblight_config.mode);
227   if (rgblight_config.mode == 1) {
228     #ifdef RGBLIGHT_ANIMATIONS
229       rgblight_timer_disable();
230     #endif
231   } else if (rgblight_config.mode >= 2 && rgblight_config.mode <= 24) {
232     // MODE 2-5, breathing
233     // MODE 6-8, rainbow mood
234     // MODE 9-14, rainbow swirl
235     // MODE 15-20, snake
236     // MODE 21-23, knight
237     // MODE 24, xmas
238     // MODE 25-34, static rainbow
239
240     #ifdef RGBLIGHT_ANIMATIONS
241       rgblight_timer_enable();
242     #endif
243   } else if (rgblight_config.mode >= 25 && rgblight_config.mode <= 34) {
244     // MODE 25-34, static gradient
245
246     #ifdef RGBLIGHT_ANIMATIONS
247       rgblight_timer_disable();
248     #endif
249   }
250   rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val);
251 }
252
253 void rgblight_toggle(void) {
254   xprintf("rgblight toggle: rgblight_config.enable = %u\n", !rgblight_config.enable);
255   if (rgblight_config.enable) {
256     rgblight_disable();
257   }
258   else {
259     rgblight_enable();
260   }
261 }
262
263 void rgblight_enable(void) {
264   rgblight_config.enable = 1;
265   eeconfig_update_rgblight(rgblight_config.raw);
266   xprintf("rgblight enable: rgblight_config.enable = %u\n", rgblight_config.enable);
267   rgblight_mode(rgblight_config.mode);
268 }
269
270 void rgblight_disable(void) {
271   rgblight_config.enable = 0;
272   eeconfig_update_rgblight(rgblight_config.raw);
273   xprintf("rgblight disable: rgblight_config.enable = %u\n", rgblight_config.enable);
274   #ifdef RGBLIGHT_ANIMATIONS
275     rgblight_timer_disable();
276   #endif
277   _delay_ms(50);
278   rgblight_set();
279 }
280
281
282 void rgblight_increase_hue(void) {
283   uint16_t hue;
284   hue = (rgblight_config.hue+RGBLIGHT_HUE_STEP) % 360;
285   rgblight_sethsv(hue, rgblight_config.sat, rgblight_config.val);
286 }
287 void rgblight_decrease_hue(void) {
288   uint16_t hue;
289   if (rgblight_config.hue-RGBLIGHT_HUE_STEP < 0) {
290     hue = (rgblight_config.hue + 360 - RGBLIGHT_HUE_STEP) % 360;
291   } else {
292     hue = (rgblight_config.hue - RGBLIGHT_HUE_STEP) % 360;
293   }
294   rgblight_sethsv(hue, rgblight_config.sat, rgblight_config.val);
295 }
296 void rgblight_increase_sat(void) {
297   uint8_t sat;
298   if (rgblight_config.sat + RGBLIGHT_SAT_STEP > 255) {
299     sat = 255;
300   } else {
301     sat = rgblight_config.sat + RGBLIGHT_SAT_STEP;
302   }
303   rgblight_sethsv(rgblight_config.hue, sat, rgblight_config.val);
304 }
305 void rgblight_decrease_sat(void) {
306   uint8_t sat;
307   if (rgblight_config.sat - RGBLIGHT_SAT_STEP < 0) {
308     sat = 0;
309   } else {
310     sat = rgblight_config.sat - RGBLIGHT_SAT_STEP;
311   }
312   rgblight_sethsv(rgblight_config.hue, sat, rgblight_config.val);
313 }
314 void rgblight_increase_val(void) {
315   uint8_t val;
316   if (rgblight_config.val + RGBLIGHT_VAL_STEP > 255) {
317     val = 255;
318   } else {
319     val = rgblight_config.val + RGBLIGHT_VAL_STEP;
320   }
321   rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, val);
322 }
323 void rgblight_decrease_val(void) {
324   uint8_t val;
325   if (rgblight_config.val - RGBLIGHT_VAL_STEP < 0) {
326     val = 0;
327   } else {
328     val = rgblight_config.val - RGBLIGHT_VAL_STEP;
329   }
330   rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, val);
331 }
332
333 void rgblight_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val) {
334   inmem_config.raw = rgblight_config.raw;
335   if (rgblight_config.enable) {
336     LED_TYPE tmp_led;
337     sethsv(hue, sat, val, &tmp_led);
338     inmem_config.hue = hue;
339     inmem_config.sat = sat;
340     inmem_config.val = val;
341     // dprintf("rgblight set hue [MEMORY]: %u,%u,%u\n", inmem_config.hue, inmem_config.sat, inmem_config.val);
342     rgblight_setrgb(tmp_led.r, tmp_led.g, tmp_led.b);
343   }
344 }
345 void rgblight_sethsv(uint16_t hue, uint8_t sat, uint8_t val) {
346   if (rgblight_config.enable) {
347     if (rgblight_config.mode == 1) {
348       // same static color
349       rgblight_sethsv_noeeprom(hue, sat, val);
350     } else {
351       // all LEDs in same color
352       if (rgblight_config.mode >= 2 && rgblight_config.mode <= 5) {
353         // breathing mode, ignore the change of val, use in memory value instead
354         val = rgblight_config.val;
355       } else if (rgblight_config.mode >= 6 && rgblight_config.mode <= 14) {
356         // rainbow mood and rainbow swirl, ignore the change of hue
357         hue = rgblight_config.hue;
358       } else if (rgblight_config.mode >= 25 && rgblight_config.mode <= 34) {
359         // static gradient
360         uint16_t _hue;
361         int8_t direction = ((rgblight_config.mode - 25) % 2) ? -1 : 1;
362         uint16_t range = pgm_read_word(&RGBLED_GRADIENT_RANGES[(rgblight_config.mode - 25) / 2]);
363         for (uint8_t i = 0; i < RGBLED_NUM; i++) {
364           _hue = (range / RGBLED_NUM * i * direction + hue + 360) % 360;
365           dprintf("rgblight rainbow set hsv: %u,%u,%d,%u\n", i, _hue, direction, range);
366           sethsv(_hue, sat, val, (LED_TYPE *)&led[i]);
367         }
368         rgblight_set();
369       }
370     }
371     rgblight_config.hue = hue;
372     rgblight_config.sat = sat;
373     rgblight_config.val = val;
374     eeconfig_update_rgblight(rgblight_config.raw);
375     xprintf("rgblight set hsv [EEPROM]: %u,%u,%u\n", rgblight_config.hue, rgblight_config.sat, rgblight_config.val);
376   }
377 }
378
379 uint16_t rgblight_get_hue(void) {
380   return rgblight_config.hue;
381 }
382
383 uint8_t rgblight_get_sat(void) {
384   return rgblight_config.sat;
385 }
386
387 uint8_t rgblight_get_val(void) {
388   return rgblight_config.val;
389 }
390
391 void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b) {
392   if (!rgblight_config.enable) { return; }
393
394   for (uint8_t i = 0; i < RGBLED_NUM; i++) {
395     led[i].r = r;
396     led[i].g = g;
397     led[i].b = b;
398   }
399   rgblight_set();
400 }
401
402 void rgblight_setrgb_at(uint8_t r, uint8_t g, uint8_t b, uint8_t index) {
403   if (!rgblight_config.enable || index >= RGBLED_NUM) { return; }
404
405   led[index].r = r;
406   led[index].g = g;
407   led[index].b = b;
408   rgblight_set();
409 }
410
411 void rgblight_sethsv_at(uint16_t hue, uint8_t sat, uint8_t val, uint8_t index) {
412   if (!rgblight_config.enable) { return; }
413
414   LED_TYPE tmp_led;
415   sethsv(hue, sat, val, &tmp_led);
416   rgblight_setrgb_at(tmp_led.r, tmp_led.g, tmp_led.b, index);
417 }
418
419 #ifndef RGBLIGHT_CUSTOM_DRIVER
420 void rgblight_set(void) {
421   if (rgblight_config.enable) {
422     #ifdef RGBW
423       ws2812_setleds_rgbw(led, RGBLED_NUM);
424     #else
425       ws2812_setleds(led, RGBLED_NUM);
426     #endif
427   } else {
428     for (uint8_t i = 0; i < RGBLED_NUM; i++) {
429       led[i].r = 0;
430       led[i].g = 0;
431       led[i].b = 0;
432     }
433     #ifdef RGBW
434       ws2812_setleds_rgbw(led, RGBLED_NUM);
435     #else
436       ws2812_setleds(led, RGBLED_NUM);
437     #endif
438   }
439 }
440 #endif
441
442 #ifdef RGBLIGHT_ANIMATIONS
443
444 // Animation timer -- AVR Timer3
445 void rgblight_timer_init(void) {
446   // static uint8_t rgblight_timer_is_init = 0;
447   // if (rgblight_timer_is_init) {
448   //   return;
449   // }
450   // rgblight_timer_is_init = 1;
451   // /* Timer 3 setup */
452   // TCCR3B = _BV(WGM32) // CTC mode OCR3A as TOP
453   //       | _BV(CS30); // Clock selelct: clk/1
454   // /* Set TOP value */
455   // uint8_t sreg = SREG;
456   // cli();
457   // OCR3AH = (RGBLED_TIMER_TOP >> 8) & 0xff;
458   // OCR3AL = RGBLED_TIMER_TOP & 0xff;
459   // SREG = sreg;
460
461   rgblight_timer_enabled = true;
462 }
463 void rgblight_timer_enable(void) {
464   rgblight_timer_enabled = true;
465   dprintf("TIMER3 enabled.\n");
466 }
467 void rgblight_timer_disable(void) {
468   rgblight_timer_enabled = false;
469   dprintf("TIMER3 disabled.\n");
470 }
471 void rgblight_timer_toggle(void) {
472   rgblight_timer_enabled ^= rgblight_timer_enabled;
473   dprintf("TIMER3 toggled.\n");
474 }
475
476 void rgblight_show_solid_color(uint8_t r, uint8_t g, uint8_t b) {
477   rgblight_enable();
478   rgblight_mode(1);
479   rgblight_setrgb(r, g, b);
480 }
481
482 void rgblight_task(void) {
483   if (rgblight_inited == 1) { //modify for led_test
484       /* first call */
485       rgblight_inited = 2;
486       rgblight_enable();
487       rgblight_mode(2);
488   }
489   if (rgblight_timer_enabled) {
490     // mode = 1, static light, do nothing here
491     if (rgblight_config.mode >= 2 && rgblight_config.mode <= 5) {
492       // mode = 2 to 5, breathing mode
493       rgblight_effect_breathing(rgblight_config.mode - 2);
494 #if 0
495     } else if (rgblight_config.mode >= 6 && rgblight_config.mode <= 8) {
496       // mode = 6 to 8, rainbow mood mod
497       rgblight_effect_rainbow_mood(rgblight_config.mode - 6);
498     } else if (rgblight_config.mode >= 9 && rgblight_config.mode <= 14) {
499       // mode = 9 to 14, rainbow swirl mode
500       rgblight_effect_rainbow_swirl(rgblight_config.mode - 9);
501     } else if (rgblight_config.mode >= 15 && rgblight_config.mode <= 20) {
502       // mode = 15 to 20, snake mode
503       rgblight_effect_snake(rgblight_config.mode - 15);
504     } else if (rgblight_config.mode >= 21 && rgblight_config.mode <= 23) {
505       // mode = 21 to 23, knight mode
506       rgblight_effect_knight(rgblight_config.mode - 21);
507     } else if (rgblight_config.mode == 24) {
508       // mode = 24, christmas mode
509       rgblight_effect_christmas();
510 #endif
511     }
512   }
513 }
514
515 // Effects
516 void rgblight_effect_breathing(uint8_t interval) {
517   static uint8_t pos = 0;
518   static uint16_t last_timer = 0;
519
520   if (timer_elapsed(last_timer) < pgm_read_word(&RGBLED_BREATHING_INTERVALS[interval])) {//modify for led_test
521     return;
522   }
523   last_timer = timer_read();
524
525
526   //modify for led_test
527   rgblight_config.hue = (pos*120)%360;
528   rgblight_sethsv_noeeprom(rgblight_config.hue, rgblight_config.sat, rgblight_config.val);
529   pos = (pos + 1) % 3;
530 }
531 #if 0
532 void rgblight_effect_rainbow_mood(uint8_t interval) {
533   static uint16_t current_hue = 0;
534   static uint16_t last_timer = 0;
535
536   if (timer_elapsed(last_timer) < pgm_read_byte(&RGBLED_RAINBOW_MOOD_INTERVALS[interval])) {
537     return;
538   }
539   last_timer = timer_read();
540   rgblight_sethsv_noeeprom(current_hue, rgblight_config.sat, rgblight_config.val);
541   current_hue = (current_hue + 1) % 360;
542 }
543 void rgblight_effect_rainbow_swirl(uint8_t interval) {
544   static uint16_t current_hue = 0;
545   static uint16_t last_timer = 0;
546   uint16_t hue;
547   uint8_t i;
548   if (timer_elapsed(last_timer) < pgm_read_byte(&RGBLED_RAINBOW_SWIRL_INTERVALS[interval / 2])) {
549     return;
550   }
551   last_timer = timer_read();
552   for (i = 0; i < RGBLED_NUM; i++) {
553     hue = (360 / RGBLED_NUM * i + current_hue) % 360;
554     sethsv(hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[i]);
555   }
556   rgblight_set();
557
558   if (interval % 2) {
559     current_hue = (current_hue + 1) % 360;
560   } else {
561     if (current_hue - 1 < 0) {
562       current_hue = 359;
563     } else {
564       current_hue = current_hue - 1;
565     }
566   }
567 }
568 void rgblight_effect_snake(uint8_t interval) {
569   static uint8_t pos = 0;
570   static uint16_t last_timer = 0;
571   uint8_t i, j;
572   int8_t k;
573   int8_t increment = 1;
574   if (interval % 2) {
575     increment = -1;
576   }
577   if (timer_elapsed(last_timer) < pgm_read_byte(&RGBLED_SNAKE_INTERVALS[interval / 2])) {
578     return;
579   }
580   last_timer = timer_read();
581   for (i = 0; i < RGBLED_NUM; i++) {
582     led[i].r = 0;
583     led[i].g = 0;
584     led[i].b = 0;
585     for (j = 0; j < RGBLIGHT_EFFECT_SNAKE_LENGTH; j++) {
586       k = pos + j * increment;
587       if (k < 0) {
588         k = k + RGBLED_NUM;
589       }
590       if (i == k) {
591         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]);
592       }
593     }
594   }
595   rgblight_set();
596   if (increment == 1) {
597     if (pos - 1 < 0) {
598       pos = RGBLED_NUM - 1;
599     } else {
600       pos -= 1;
601     }
602   } else {
603     pos = (pos + 1) % RGBLED_NUM;
604   }
605 }
606 void rgblight_effect_knight(uint8_t interval) {
607   static uint16_t last_timer = 0;
608   if (timer_elapsed(last_timer) < pgm_read_byte(&RGBLED_KNIGHT_INTERVALS[interval])) {
609     return;
610   }
611   last_timer = timer_read();
612
613   static int8_t low_bound = 0;
614   static int8_t high_bound = RGBLIGHT_EFFECT_KNIGHT_LENGTH - 1;
615   static int8_t increment = 1;
616   uint8_t i, cur;
617
618   // Set all the LEDs to 0
619   for (i = 0; i < RGBLED_NUM; i++) {
620     led[i].r = 0;
621     led[i].g = 0;
622     led[i].b = 0;
623   }
624   // Determine which LEDs should be lit up
625   for (i = 0; i < RGBLIGHT_EFFECT_KNIGHT_LED_NUM; i++) {
626     cur = (i + RGBLIGHT_EFFECT_KNIGHT_OFFSET) % RGBLED_NUM;
627
628     if (i >= low_bound && i <= high_bound) {
629       sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[cur]);
630     } else {
631       led[cur].r = 0;
632       led[cur].g = 0;
633       led[cur].b = 0;
634     }
635   }
636   rgblight_set();
637
638   // Move from low_bound to high_bound changing the direction we increment each
639   // time a boundary is hit.
640   low_bound += increment;
641   high_bound += increment;
642
643   if (high_bound <= 0 || low_bound >= RGBLIGHT_EFFECT_KNIGHT_LED_NUM - 1) {
644     increment = -increment;
645   }
646 }
647
648
649 void rgblight_effect_christmas(void) {
650   static uint16_t current_offset = 0;
651   static uint16_t last_timer = 0;
652   uint16_t hue;
653   uint8_t i;
654   if (timer_elapsed(last_timer) < RGBLIGHT_EFFECT_CHRISTMAS_INTERVAL) {
655     return;
656   }
657   last_timer = timer_read();
658   current_offset = (current_offset + 1) % 2;
659   for (i = 0; i < RGBLED_NUM; i++) {
660     hue = 0 + ((i/RGBLIGHT_EFFECT_CHRISTMAS_STEP + current_offset) % 2) * 120;
661     sethsv(hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[i]);
662   }
663   rgblight_set();
664 }
665 #endif /* 0 */
666 #endif /* RGBLIGHT_ANIMATIONS */