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