aboutsummaryrefslogtreecommitdiff
path: root/quantum/rgblight/rgblight.c
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/rgblight/rgblight.c')
-rw-r--r--quantum/rgblight/rgblight.c1391
1 files changed, 1391 insertions, 0 deletions
diff --git a/quantum/rgblight/rgblight.c b/quantum/rgblight/rgblight.c
new file mode 100644
index 000000000..54face173
--- /dev/null
+++ b/quantum/rgblight/rgblight.c
@@ -0,0 +1,1391 @@
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#include <stdlib.h>
19#ifdef __AVR__
20# include <avr/eeprom.h>
21# include <avr/interrupt.h>
22#endif
23#ifdef EEPROM_ENABLE
24# include "eeprom.h"
25#endif
26#ifdef STM32_EEPROM_ENABLE
27# include <hal.h>
28# include "eeprom_stm32.h"
29#endif
30#include "wait.h"
31#include "progmem.h"
32#include "sync_timer.h"
33#include "rgblight.h"
34#include "color.h"
35#include "debug.h"
36#include "led_tables.h"
37#include <lib/lib8tion/lib8tion.h>
38#ifdef VELOCIKEY_ENABLE
39# include "velocikey.h"
40#endif
41
42#ifndef MIN
43# define MIN(a, b) (((a) < (b)) ? (a) : (b))
44#endif
45#ifndef MAX
46# define MAX(a, b) (((a) > (b)) ? (a) : (b))
47#endif
48
49#ifdef RGBLIGHT_SPLIT
50/* for split keyboard */
51# define RGBLIGHT_SPLIT_SET_CHANGE_MODE rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_MODE
52# define RGBLIGHT_SPLIT_SET_CHANGE_HSVS rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_HSVS
53# define RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS rgblight_status.change_flags |= (RGBLIGHT_STATUS_CHANGE_MODE | RGBLIGHT_STATUS_CHANGE_HSVS)
54# define RGBLIGHT_SPLIT_SET_CHANGE_LAYERS rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_LAYERS
55# define RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_TIMER
56# define RGBLIGHT_SPLIT_ANIMATION_TICK rgblight_status.change_flags |= RGBLIGHT_STATUS_ANIMATION_TICK
57#else
58# define RGBLIGHT_SPLIT_SET_CHANGE_MODE
59# define RGBLIGHT_SPLIT_SET_CHANGE_HSVS
60# define RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS
61# define RGBLIGHT_SPLIT_SET_CHANGE_LAYERS
62# define RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE
63# define RGBLIGHT_SPLIT_ANIMATION_TICK
64#endif
65
66#define _RGBM_SINGLE_STATIC(sym) RGBLIGHT_MODE_##sym,
67#define _RGBM_SINGLE_DYNAMIC(sym)
68#define _RGBM_MULTI_STATIC(sym) RGBLIGHT_MODE_##sym,
69#define _RGBM_MULTI_DYNAMIC(sym)
70#define _RGBM_TMP_STATIC(sym, msym) RGBLIGHT_MODE_##sym,
71#define _RGBM_TMP_DYNAMIC(sym, msym)
72static uint8_t static_effect_table[] = {
73#include "rgblight_modes.h"
74};
75
76#define _RGBM_SINGLE_STATIC(sym) RGBLIGHT_MODE_##sym,
77#define _RGBM_SINGLE_DYNAMIC(sym) RGBLIGHT_MODE_##sym,
78#define _RGBM_MULTI_STATIC(sym) RGBLIGHT_MODE_##sym,
79#define _RGBM_MULTI_DYNAMIC(sym) RGBLIGHT_MODE_##sym,
80#define _RGBM_TMP_STATIC(sym, msym) RGBLIGHT_MODE_##msym,
81#define _RGBM_TMP_DYNAMIC(sym, msym) RGBLIGHT_MODE_##msym,
82static uint8_t mode_base_table[] = {
83 0, // RGBLIGHT_MODE_zero
84#include "rgblight_modes.h"
85};
86
87#if !defined(RGBLIGHT_DEFAULT_MODE)
88# define RGBLIGHT_DEFAULT_MODE RGBLIGHT_MODE_STATIC_LIGHT
89#endif
90
91#if !defined(RGBLIGHT_DEFAULT_HUE)
92# define RGBLIGHT_DEFAULT_HUE 0
93#endif
94
95#if !defined(RGBLIGHT_DEFAULT_SAT)
96# define RGBLIGHT_DEFAULT_SAT UINT8_MAX
97#endif
98
99#if !defined(RGBLIGHT_DEFAULT_VAL)
100# define RGBLIGHT_DEFAULT_VAL RGBLIGHT_LIMIT_VAL
101#endif
102
103#if !defined(RGBLIGHT_DEFAULT_SPD)
104# define RGBLIGHT_DEFAULT_SPD 0
105#endif
106
107static inline int is_static_effect(uint8_t mode) { return memchr(static_effect_table, mode, sizeof(static_effect_table)) != NULL; }
108
109#ifdef RGBLIGHT_LED_MAP
110const uint8_t led_map[] PROGMEM = RGBLIGHT_LED_MAP;
111#endif
112
113#ifdef RGBLIGHT_EFFECT_STATIC_GRADIENT
114__attribute__((weak)) const uint8_t RGBLED_GRADIENT_RANGES[] PROGMEM = {255, 170, 127, 85, 64};
115#endif
116
117rgblight_config_t rgblight_config;
118rgblight_status_t rgblight_status = {.timer_enabled = false};
119bool is_rgblight_initialized = false;
120
121#ifdef RGBLIGHT_SLEEP
122static bool is_suspended;
123static bool pre_suspend_enabled;
124#endif
125
126#ifdef RGBLIGHT_USE_TIMER
127animation_status_t animation_status = {};
128#endif
129
130#ifndef LED_ARRAY
131LED_TYPE led[RGBLED_NUM];
132# define LED_ARRAY led
133#endif
134
135#ifdef RGBLIGHT_LAYERS
136rgblight_segment_t const *const *rgblight_layers = NULL;
137#endif
138
139rgblight_ranges_t rgblight_ranges = {0, RGBLED_NUM, 0, RGBLED_NUM, RGBLED_NUM};
140
141void rgblight_set_clipping_range(uint8_t start_pos, uint8_t num_leds) {
142 rgblight_ranges.clipping_start_pos = start_pos;
143 rgblight_ranges.clipping_num_leds = num_leds;
144}
145
146void rgblight_set_effect_range(uint8_t start_pos, uint8_t num_leds) {
147 if (start_pos >= RGBLED_NUM) return;
148 if (start_pos + num_leds > RGBLED_NUM) return;
149 rgblight_ranges.effect_start_pos = start_pos;
150 rgblight_ranges.effect_end_pos = start_pos + num_leds;
151 rgblight_ranges.effect_num_leds = num_leds;
152}
153
154__attribute__((weak)) RGB rgblight_hsv_to_rgb(HSV hsv) { return hsv_to_rgb(hsv); }
155
156void sethsv_raw(uint8_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1) {
157 HSV hsv = {hue, sat, val};
158 RGB rgb = rgblight_hsv_to_rgb(hsv);
159 setrgb(rgb.r, rgb.g, rgb.b, led1);
160}
161
162void sethsv(uint8_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1) { sethsv_raw(hue, sat, val > RGBLIGHT_LIMIT_VAL ? RGBLIGHT_LIMIT_VAL : val, led1); }
163
164void setrgb(uint8_t r, uint8_t g, uint8_t b, LED_TYPE *led1) {
165 led1->r = r;
166 led1->g = g;
167 led1->b = b;
168#ifdef RGBW
169 led1->w = 0;
170#endif
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 } else if (rgblight_config.mode > RGBLIGHT_MODES) {
179 rgblight_config.mode = RGBLIGHT_MODES;
180 }
181
182 if (rgblight_config.val > RGBLIGHT_LIMIT_VAL) {
183 rgblight_config.val = RGBLIGHT_LIMIT_VAL;
184 }
185}
186
187uint32_t eeconfig_read_rgblight(void) {
188#ifdef EEPROM_ENABLE
189 return eeprom_read_dword(EECONFIG_RGBLIGHT);
190#else
191 return 0;
192#endif
193}
194
195void eeconfig_update_rgblight(uint32_t val) {
196#ifdef EEPROM_ENABLE
197 rgblight_check_config();
198 eeprom_update_dword(EECONFIG_RGBLIGHT, val);
199#endif
200}
201
202void eeconfig_update_rgblight_current(void) { eeconfig_update_rgblight(rgblight_config.raw); }
203
204void eeconfig_update_rgblight_default(void) {
205 rgblight_config.enable = 1;
206 rgblight_config.mode = RGBLIGHT_DEFAULT_MODE;
207 rgblight_config.hue = RGBLIGHT_DEFAULT_HUE;
208 rgblight_config.sat = RGBLIGHT_DEFAULT_SAT;
209 rgblight_config.val = RGBLIGHT_DEFAULT_VAL;
210 rgblight_config.speed = RGBLIGHT_DEFAULT_SPD;
211 RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS;
212 eeconfig_update_rgblight(rgblight_config.raw);
213}
214
215void eeconfig_debug_rgblight(void) {
216 dprintf("rgblight_config EEPROM:\n");
217 dprintf("rgblight_config.enable = %d\n", rgblight_config.enable);
218 dprintf("rghlight_config.mode = %d\n", rgblight_config.mode);
219 dprintf("rgblight_config.hue = %d\n", rgblight_config.hue);
220 dprintf("rgblight_config.sat = %d\n", rgblight_config.sat);
221 dprintf("rgblight_config.val = %d\n", rgblight_config.val);
222 dprintf("rgblight_config.speed = %d\n", rgblight_config.speed);
223}
224
225void rgblight_init(void) {
226 /* if already initialized, don't do it again.
227 If you must do it again, extern this and set to false, first.
228 This is a dirty, dirty hack until proper hooks can be added for keyboard startup. */
229 if (is_rgblight_initialized) {
230 return;
231 }
232
233 dprintf("rgblight_init called.\n");
234 dprintf("rgblight_init start!\n");
235 if (!eeconfig_is_enabled()) {
236 dprintf("rgblight_init eeconfig is not enabled.\n");
237 eeconfig_init();
238 eeconfig_update_rgblight_default();
239 }
240 rgblight_config.raw = eeconfig_read_rgblight();
241 RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS;
242 if (!rgblight_config.mode) {
243 dprintf("rgblight_init rgblight_config.mode = 0. Write default values to EEPROM.\n");
244 eeconfig_update_rgblight_default();
245 rgblight_config.raw = eeconfig_read_rgblight();
246 }
247 rgblight_check_config();
248
249 eeconfig_debug_rgblight(); // display current eeprom values
250
251 rgblight_timer_init(); // setup the timer
252
253 if (rgblight_config.enable) {
254 rgblight_mode_noeeprom(rgblight_config.mode);
255 }
256
257 is_rgblight_initialized = true;
258}
259
260void rgblight_reload_from_eeprom(void) {
261 /* Reset back to what we have in eeprom */
262 rgblight_config.raw = eeconfig_read_rgblight();
263 RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS;
264 rgblight_check_config();
265 eeconfig_debug_rgblight(); // display current eeprom values
266 if (rgblight_config.enable) {
267 rgblight_mode_noeeprom(rgblight_config.mode);
268 }
269}
270
271uint32_t rgblight_read_dword(void) { return rgblight_config.raw; }
272
273void rgblight_update_dword(uint32_t dword) {
274 RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS;
275 rgblight_config.raw = dword;
276 if (rgblight_config.enable)
277 rgblight_mode_noeeprom(rgblight_config.mode);
278 else {
279 rgblight_timer_disable();
280 rgblight_set();
281 }
282}
283
284void rgblight_increase(void) {
285 uint8_t mode = 0;
286 if (rgblight_config.mode < RGBLIGHT_MODES) {
287 mode = rgblight_config.mode + 1;
288 }
289 rgblight_mode(mode);
290}
291void rgblight_decrease(void) {
292 uint8_t mode = 0;
293 // Mode will never be < 1. If it ever is, eeprom needs to be initialized.
294 if (rgblight_config.mode > RGBLIGHT_MODE_STATIC_LIGHT) {
295 mode = rgblight_config.mode - 1;
296 }
297 rgblight_mode(mode);
298}
299void rgblight_step_helper(bool write_to_eeprom) {
300 uint8_t mode = 0;
301 mode = rgblight_config.mode + 1;
302 if (mode > RGBLIGHT_MODES) {
303 mode = 1;
304 }
305 rgblight_mode_eeprom_helper(mode, write_to_eeprom);
306}
307void rgblight_step_noeeprom(void) { rgblight_step_helper(false); }
308void rgblight_step(void) { rgblight_step_helper(true); }
309void rgblight_step_reverse_helper(bool write_to_eeprom) {
310 uint8_t mode = 0;
311 mode = rgblight_config.mode - 1;
312 if (mode < 1) {
313 mode = RGBLIGHT_MODES;
314 }
315 rgblight_mode_eeprom_helper(mode, write_to_eeprom);
316}
317void rgblight_step_reverse_noeeprom(void) { rgblight_step_reverse_helper(false); }
318void rgblight_step_reverse(void) { rgblight_step_reverse_helper(true); }
319
320uint8_t rgblight_get_mode(void) {
321 if (!rgblight_config.enable) {
322 return false;
323 }
324
325 return rgblight_config.mode;
326}
327
328void rgblight_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom) {
329 if (!rgblight_config.enable) {
330 return;
331 }
332 if (mode < RGBLIGHT_MODE_STATIC_LIGHT) {
333 rgblight_config.mode = RGBLIGHT_MODE_STATIC_LIGHT;
334 } else if (mode > RGBLIGHT_MODES) {
335 rgblight_config.mode = RGBLIGHT_MODES;
336 } else {
337 rgblight_config.mode = mode;
338 }
339 RGBLIGHT_SPLIT_SET_CHANGE_MODE;
340 if (write_to_eeprom) {
341 eeconfig_update_rgblight(rgblight_config.raw);
342 dprintf("rgblight mode [EEPROM]: %u\n", rgblight_config.mode);
343 } else {
344 dprintf("rgblight mode [NOEEPROM]: %u\n", rgblight_config.mode);
345 }
346 if (is_static_effect(rgblight_config.mode)) {
347 rgblight_timer_disable();
348 } else {
349 rgblight_timer_enable();
350 }
351#ifdef RGBLIGHT_USE_TIMER
352 animation_status.restart = true;
353#endif
354 rgblight_sethsv_noeeprom(rgblight_config.hue, rgblight_config.sat, rgblight_config.val);
355}
356
357void rgblight_mode(uint8_t mode) { rgblight_mode_eeprom_helper(mode, true); }
358
359void rgblight_mode_noeeprom(uint8_t mode) { rgblight_mode_eeprom_helper(mode, false); }
360
361void rgblight_toggle(void) {
362 dprintf("rgblight toggle [EEPROM]: rgblight_config.enable = %u\n", !rgblight_config.enable);
363 if (rgblight_config.enable) {
364 rgblight_disable();
365 } else {
366 rgblight_enable();
367 }
368}
369
370void rgblight_toggle_noeeprom(void) {
371 dprintf("rgblight toggle [NOEEPROM]: rgblight_config.enable = %u\n", !rgblight_config.enable);
372 if (rgblight_config.enable) {
373 rgblight_disable_noeeprom();
374 } else {
375 rgblight_enable_noeeprom();
376 }
377}
378
379void rgblight_enable(void) {
380 rgblight_config.enable = 1;
381 // No need to update EEPROM here. rgblight_mode() will do that, actually
382 // eeconfig_update_rgblight(rgblight_config.raw);
383 dprintf("rgblight enable [EEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable);
384 rgblight_mode(rgblight_config.mode);
385}
386
387void rgblight_enable_noeeprom(void) {
388 rgblight_config.enable = 1;
389 dprintf("rgblight enable [NOEEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable);
390 rgblight_mode_noeeprom(rgblight_config.mode);
391}
392
393void rgblight_disable(void) {
394 rgblight_config.enable = 0;
395 eeconfig_update_rgblight(rgblight_config.raw);
396 dprintf("rgblight disable [EEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable);
397 rgblight_timer_disable();
398 RGBLIGHT_SPLIT_SET_CHANGE_MODE;
399 wait_ms(50);
400 rgblight_set();
401}
402
403void rgblight_disable_noeeprom(void) {
404 rgblight_config.enable = 0;
405 dprintf("rgblight disable [NOEEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable);
406 rgblight_timer_disable();
407 RGBLIGHT_SPLIT_SET_CHANGE_MODE;
408 wait_ms(50);
409 rgblight_set();
410}
411
412bool rgblight_is_enabled(void) { return rgblight_config.enable; }
413
414void rgblight_increase_hue_helper(bool write_to_eeprom) {
415 uint8_t hue = rgblight_config.hue + RGBLIGHT_HUE_STEP;
416 rgblight_sethsv_eeprom_helper(hue, rgblight_config.sat, rgblight_config.val, write_to_eeprom);
417}
418void rgblight_increase_hue_noeeprom(void) { rgblight_increase_hue_helper(false); }
419void rgblight_increase_hue(void) { rgblight_increase_hue_helper(true); }
420void rgblight_decrease_hue_helper(bool write_to_eeprom) {
421 uint8_t hue = rgblight_config.hue - RGBLIGHT_HUE_STEP;
422 rgblight_sethsv_eeprom_helper(hue, rgblight_config.sat, rgblight_config.val, write_to_eeprom);
423}
424void rgblight_decrease_hue_noeeprom(void) { rgblight_decrease_hue_helper(false); }
425void rgblight_decrease_hue(void) { rgblight_decrease_hue_helper(true); }
426void rgblight_increase_sat_helper(bool write_to_eeprom) {
427 uint8_t sat = qadd8(rgblight_config.sat, RGBLIGHT_SAT_STEP);
428 rgblight_sethsv_eeprom_helper(rgblight_config.hue, sat, rgblight_config.val, write_to_eeprom);
429}
430void rgblight_increase_sat_noeeprom(void) { rgblight_increase_sat_helper(false); }
431void rgblight_increase_sat(void) { rgblight_increase_sat_helper(true); }
432void rgblight_decrease_sat_helper(bool write_to_eeprom) {
433 uint8_t sat = qsub8(rgblight_config.sat, RGBLIGHT_SAT_STEP);
434 rgblight_sethsv_eeprom_helper(rgblight_config.hue, sat, rgblight_config.val, write_to_eeprom);
435}
436void rgblight_decrease_sat_noeeprom(void) { rgblight_decrease_sat_helper(false); }
437void rgblight_decrease_sat(void) { rgblight_decrease_sat_helper(true); }
438void rgblight_increase_val_helper(bool write_to_eeprom) {
439 uint8_t val = qadd8(rgblight_config.val, RGBLIGHT_VAL_STEP);
440 rgblight_sethsv_eeprom_helper(rgblight_config.hue, rgblight_config.sat, val, write_to_eeprom);
441}
442void rgblight_increase_val_noeeprom(void) { rgblight_increase_val_helper(false); }
443void rgblight_increase_val(void) { rgblight_increase_val_helper(true); }
444void rgblight_decrease_val_helper(bool write_to_eeprom) {
445 uint8_t val = qsub8(rgblight_config.val, RGBLIGHT_VAL_STEP);
446 rgblight_sethsv_eeprom_helper(rgblight_config.hue, rgblight_config.sat, val, write_to_eeprom);
447}
448void rgblight_decrease_val_noeeprom(void) { rgblight_decrease_val_helper(false); }
449void rgblight_decrease_val(void) { rgblight_decrease_val_helper(true); }
450
451void rgblight_increase_speed_helper(bool write_to_eeprom) {
452 if (rgblight_config.speed < 3) rgblight_config.speed++;
453 // RGBLIGHT_SPLIT_SET_CHANGE_HSVS; // NEED?
454 if (write_to_eeprom) {
455 eeconfig_update_rgblight(rgblight_config.raw); // EECONFIG needs to be increased to support this
456 }
457}
458void rgblight_increase_speed(void) { rgblight_increase_speed_helper(true); }
459void rgblight_increase_speed_noeeprom(void) { rgblight_increase_speed_helper(false); }
460
461void rgblight_decrease_speed_helper(bool write_to_eeprom) {
462 if (rgblight_config.speed > 0) rgblight_config.speed--;
463 // RGBLIGHT_SPLIT_SET_CHANGE_HSVS; // NEED??
464 if (write_to_eeprom) {
465 eeconfig_update_rgblight(rgblight_config.raw); // EECONFIG needs to be increased to support this
466 }
467}
468void rgblight_decrease_speed(void) { rgblight_decrease_speed_helper(true); }
469void rgblight_decrease_speed_noeeprom(void) { rgblight_decrease_speed_helper(false); }
470
471void rgblight_sethsv_noeeprom_old(uint8_t hue, uint8_t sat, uint8_t val) {
472 if (rgblight_config.enable) {
473 LED_TYPE tmp_led;
474 sethsv(hue, sat, val, &tmp_led);
475 rgblight_setrgb(tmp_led.r, tmp_led.g, tmp_led.b);
476 }
477}
478
479void rgblight_sethsv_eeprom_helper(uint8_t hue, uint8_t sat, uint8_t val, bool write_to_eeprom) {
480 if (rgblight_config.enable) {
481 rgblight_status.base_mode = mode_base_table[rgblight_config.mode];
482 if (rgblight_config.mode == RGBLIGHT_MODE_STATIC_LIGHT) {
483 // same static color
484 LED_TYPE tmp_led;
485 sethsv(hue, sat, val, &tmp_led);
486 rgblight_setrgb(tmp_led.r, tmp_led.g, tmp_led.b);
487 } else {
488 // all LEDs in same color
489 if (1 == 0) { // dummy
490 }
491#ifdef RGBLIGHT_EFFECT_BREATHING
492 else if (rgblight_status.base_mode == RGBLIGHT_MODE_BREATHING) {
493 // breathing mode, ignore the change of val, use in memory value instead
494 val = rgblight_config.val;
495 }
496#endif
497#ifdef RGBLIGHT_EFFECT_RAINBOW_MOOD
498 else if (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_MOOD) {
499 // rainbow mood, ignore the change of hue
500 hue = rgblight_config.hue;
501 }
502#endif
503#ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL
504 else if (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_SWIRL) {
505 // rainbow swirl, ignore the change of hue
506 hue = rgblight_config.hue;
507 }
508#endif
509#ifdef RGBLIGHT_EFFECT_STATIC_GRADIENT
510 else if (rgblight_status.base_mode == RGBLIGHT_MODE_STATIC_GRADIENT) {
511 // static gradient
512 uint8_t delta = rgblight_config.mode - rgblight_status.base_mode;
513 bool direction = (delta % 2) == 0;
514# ifdef __AVR__
515 // probably due to how pgm_read_word is defined for ARM, but the ARM compiler really hates this line
516 uint8_t range = pgm_read_word(&RGBLED_GRADIENT_RANGES[delta / 2]);
517# else
518 uint8_t range = RGBLED_GRADIENT_RANGES[delta / 2];
519# endif
520 for (uint8_t i = 0; i < rgblight_ranges.effect_num_leds; i++) {
521 uint8_t _hue = ((uint16_t)i * (uint16_t)range) / rgblight_ranges.effect_num_leds;
522 if (direction) {
523 _hue = hue + _hue;
524 } else {
525 _hue = hue - _hue;
526 }
527 dprintf("rgblight rainbow set hsv: %d,%d,%d,%u\n", i, _hue, direction, range);
528 sethsv(_hue, sat, val, (LED_TYPE *)&led[i + rgblight_ranges.effect_start_pos]);
529 }
530 rgblight_set();
531 }
532#endif
533 }
534#ifdef RGBLIGHT_SPLIT
535 if (rgblight_config.hue != hue || rgblight_config.sat != sat || rgblight_config.val != val) {
536 RGBLIGHT_SPLIT_SET_CHANGE_HSVS;
537 }
538#endif
539 rgblight_config.hue = hue;
540 rgblight_config.sat = sat;
541 rgblight_config.val = val;
542 if (write_to_eeprom) {
543 eeconfig_update_rgblight(rgblight_config.raw);
544 dprintf("rgblight set hsv [EEPROM]: %u,%u,%u\n", rgblight_config.hue, rgblight_config.sat, rgblight_config.val);
545 } else {
546 dprintf("rgblight set hsv [NOEEPROM]: %u,%u,%u\n", rgblight_config.hue, rgblight_config.sat, rgblight_config.val);
547 }
548 }
549}
550
551void rgblight_sethsv(uint8_t hue, uint8_t sat, uint8_t val) { rgblight_sethsv_eeprom_helper(hue, sat, val, true); }
552
553void rgblight_sethsv_noeeprom(uint8_t hue, uint8_t sat, uint8_t val) { rgblight_sethsv_eeprom_helper(hue, sat, val, false); }
554
555uint8_t rgblight_get_speed(void) { return rgblight_config.speed; }
556
557void rgblight_set_speed_eeprom_helper(uint8_t speed, bool write_to_eeprom) {
558 rgblight_config.speed = speed;
559 if (write_to_eeprom) {
560 eeconfig_update_rgblight(rgblight_config.raw); // EECONFIG needs to be increased to support this
561 dprintf("rgblight set speed [EEPROM]: %u\n", rgblight_config.speed);
562 } else {
563 dprintf("rgblight set speed [NOEEPROM]: %u\n", rgblight_config.speed);
564 }
565}
566
567void rgblight_set_speed(uint8_t speed) { rgblight_set_speed_eeprom_helper(speed, true); }
568
569void rgblight_set_speed_noeeprom(uint8_t speed) { rgblight_set_speed_eeprom_helper(speed, false); }
570
571uint8_t rgblight_get_hue(void) { return rgblight_config.hue; }
572
573uint8_t rgblight_get_sat(void) { return rgblight_config.sat; }
574
575uint8_t rgblight_get_val(void) { return rgblight_config.val; }
576
577HSV rgblight_get_hsv(void) { return (HSV){rgblight_config.hue, rgblight_config.sat, rgblight_config.val}; }
578
579void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b) {
580 if (!rgblight_config.enable) {
581 return;
582 }
583
584 for (uint8_t i = rgblight_ranges.effect_start_pos; i < rgblight_ranges.effect_end_pos; i++) {
585 led[i].r = r;
586 led[i].g = g;
587 led[i].b = b;
588#ifdef RGBW
589 led[i].w = 0;
590#endif
591 }
592 rgblight_set();
593}
594
595void rgblight_setrgb_at(uint8_t r, uint8_t g, uint8_t b, uint8_t index) {
596 if (!rgblight_config.enable || index >= RGBLED_NUM) {
597 return;
598 }
599
600 led[index].r = r;
601 led[index].g = g;
602 led[index].b = b;
603#ifdef RGBW
604 led[index].w = 0;
605#endif
606 rgblight_set();
607}
608
609void rgblight_sethsv_at(uint8_t hue, uint8_t sat, uint8_t val, uint8_t index) {
610 if (!rgblight_config.enable) {
611 return;
612 }
613
614 LED_TYPE tmp_led;
615 sethsv(hue, sat, val, &tmp_led);
616 rgblight_setrgb_at(tmp_led.r, tmp_led.g, tmp_led.b, index);
617}
618
619#if defined(RGBLIGHT_EFFECT_BREATHING) || defined(RGBLIGHT_EFFECT_RAINBOW_MOOD) || defined(RGBLIGHT_EFFECT_RAINBOW_SWIRL) || defined(RGBLIGHT_EFFECT_SNAKE) || defined(RGBLIGHT_EFFECT_KNIGHT) || defined(RGBLIGHT_EFFECT_TWINKLE)
620
621static uint8_t get_interval_time(const uint8_t *default_interval_address, uint8_t velocikey_min, uint8_t velocikey_max) {
622 return
623# ifdef VELOCIKEY_ENABLE
624 velocikey_enabled() ? velocikey_match_speed(velocikey_min, velocikey_max) :
625# endif
626 pgm_read_byte(default_interval_address);
627}
628
629#endif
630
631void rgblight_setrgb_range(uint8_t r, uint8_t g, uint8_t b, uint8_t start, uint8_t end) {
632 if (!rgblight_config.enable || start < 0 || start >= end || end > RGBLED_NUM) {
633 return;
634 }
635
636 for (uint8_t i = start; i < end; i++) {
637 led[i].r = r;
638 led[i].g = g;
639 led[i].b = b;
640#ifdef RGBW
641 led[i].w = 0;
642#endif
643 }
644 rgblight_set();
645 wait_ms(1);
646}
647
648void rgblight_sethsv_range(uint8_t hue, uint8_t sat, uint8_t val, uint8_t start, uint8_t end) {
649 if (!rgblight_config.enable) {
650 return;
651 }
652
653 LED_TYPE tmp_led;
654 sethsv(hue, sat, val, &tmp_led);
655 rgblight_setrgb_range(tmp_led.r, tmp_led.g, tmp_led.b, start, end);
656}
657
658#ifndef RGBLIGHT_SPLIT
659void rgblight_setrgb_master(uint8_t r, uint8_t g, uint8_t b) { rgblight_setrgb_range(r, g, b, 0, (uint8_t)RGBLED_NUM / 2); }
660
661void rgblight_setrgb_slave(uint8_t r, uint8_t g, uint8_t b) { rgblight_setrgb_range(r, g, b, (uint8_t)RGBLED_NUM / 2, (uint8_t)RGBLED_NUM); }
662
663void rgblight_sethsv_master(uint8_t hue, uint8_t sat, uint8_t val) { rgblight_sethsv_range(hue, sat, val, 0, (uint8_t)RGBLED_NUM / 2); }
664
665void rgblight_sethsv_slave(uint8_t hue, uint8_t sat, uint8_t val) { rgblight_sethsv_range(hue, sat, val, (uint8_t)RGBLED_NUM / 2, (uint8_t)RGBLED_NUM); }
666#endif // ifndef RGBLIGHT_SPLIT
667
668#ifdef RGBLIGHT_LAYERS
669void rgblight_set_layer_state(uint8_t layer, bool enabled) {
670 rgblight_layer_mask_t mask = (rgblight_layer_mask_t)1 << layer;
671 if (enabled) {
672 rgblight_status.enabled_layer_mask |= mask;
673 } else {
674 rgblight_status.enabled_layer_mask &= ~mask;
675 }
676 RGBLIGHT_SPLIT_SET_CHANGE_LAYERS;
677 // Static modes don't have a ticker running to update the LEDs
678 if (rgblight_status.timer_enabled == false) {
679 rgblight_mode_noeeprom(rgblight_config.mode);
680 }
681
682# ifdef RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF
683 // If not enabled, then nothing else will actually set the LEDs...
684 if (!rgblight_config.enable) {
685 rgblight_set();
686 }
687# endif
688}
689
690bool rgblight_get_layer_state(uint8_t layer) {
691 rgblight_layer_mask_t mask = (rgblight_layer_mask_t)1 << layer;
692 return (rgblight_status.enabled_layer_mask & mask) != 0;
693}
694
695// Write any enabled LED layers into the buffer
696static void rgblight_layers_write(void) {
697 uint8_t i = 0;
698 // For each layer
699 for (const rgblight_segment_t *const *layer_ptr = rgblight_layers; i < RGBLIGHT_MAX_LAYERS; layer_ptr++, i++) {
700 if (!rgblight_get_layer_state(i)) {
701 continue; // Layer is disabled
702 }
703 const rgblight_segment_t *segment_ptr = pgm_read_ptr(layer_ptr);
704 if (segment_ptr == NULL) {
705 break; // No more layers
706 }
707 // For each segment
708 while (1) {
709 rgblight_segment_t segment;
710 memcpy_P(&segment, segment_ptr, sizeof(rgblight_segment_t));
711 if (segment.index == RGBLIGHT_END_SEGMENT_INDEX) {
712 break; // No more segments
713 }
714 // Write segment.count LEDs
715 LED_TYPE *const limit = &led[MIN(segment.index + segment.count, RGBLED_NUM)];
716 for (LED_TYPE *led_ptr = &led[segment.index]; led_ptr < limit; led_ptr++) {
717 sethsv(segment.hue, segment.sat, segment.val, led_ptr);
718 }
719 segment_ptr++;
720 }
721 }
722}
723
724# ifdef RGBLIGHT_LAYER_BLINK
725rgblight_layer_mask_t _blinking_layer_mask = 0;
726static uint16_t _repeat_timer;
727static uint8_t _times_remaining;
728static uint16_t _dur;
729
730void rgblight_blink_layer(uint8_t layer, uint16_t duration_ms) { rgblight_blink_layer_repeat(layer, duration_ms, 1); }
731
732void rgblight_blink_layer_repeat(uint8_t layer, uint16_t duration_ms, uint8_t times) {
733 _times_remaining = times * 2;
734 _dur = duration_ms;
735
736 rgblight_set_layer_state(layer, true);
737 _times_remaining--;
738 _blinking_layer_mask |= (rgblight_layer_mask_t)1 << layer;
739 _repeat_timer = sync_timer_read() + duration_ms;
740}
741
742void rgblight_blink_layer_repeat_helper(void) {
743 if (_blinking_layer_mask != 0 && timer_expired(sync_timer_read(), _repeat_timer)) {
744 for (uint8_t layer = 0; layer < RGBLIGHT_MAX_LAYERS; layer++) {
745 if ((_blinking_layer_mask & (rgblight_layer_mask_t)1 << layer) != 0 && _times_remaining > 0) {
746 if (_times_remaining % 2 == 1) {
747 rgblight_set_layer_state(layer, false);
748 } else {
749 rgblight_set_layer_state(layer, true);
750 }
751 _times_remaining--;
752 _repeat_timer = sync_timer_read() + _dur;
753 }
754 }
755 if (_times_remaining <= 0) {
756 _blinking_layer_mask = 0;
757 }
758 }
759}
760# endif
761
762#endif
763
764#ifdef RGBLIGHT_SLEEP
765
766void rgblight_suspend(void) {
767 rgblight_timer_disable();
768 if (!is_suspended) {
769 is_suspended = true;
770 pre_suspend_enabled = rgblight_config.enable;
771
772# ifdef RGBLIGHT_LAYER_BLINK
773 // make sure any layer blinks don't come back after suspend
774 rgblight_status.enabled_layer_mask &= ~_blinking_layer_mask;
775 _blinking_layer_mask = 0;
776# endif
777
778 rgblight_disable_noeeprom();
779 }
780}
781
782void rgblight_wakeup(void) {
783 is_suspended = false;
784
785 if (pre_suspend_enabled) {
786 rgblight_enable_noeeprom();
787 }
788# ifdef RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF
789 // Need this or else the LEDs won't be set
790 else if (rgblight_status.enabled_layer_mask != 0) {
791 rgblight_set();
792 }
793# endif
794
795 rgblight_timer_enable();
796}
797
798#endif
799
800__attribute__((weak)) void rgblight_call_driver(LED_TYPE *start_led, uint8_t num_leds) { ws2812_setleds(start_led, num_leds); }
801
802#ifndef RGBLIGHT_CUSTOM_DRIVER
803
804void rgblight_set(void) {
805 LED_TYPE *start_led;
806 uint8_t num_leds = rgblight_ranges.clipping_num_leds;
807
808 if (!rgblight_config.enable) {
809 for (uint8_t i = rgblight_ranges.effect_start_pos; i < rgblight_ranges.effect_end_pos; i++) {
810 led[i].r = 0;
811 led[i].g = 0;
812 led[i].b = 0;
813# ifdef RGBW
814 led[i].w = 0;
815# endif
816 }
817 }
818
819# ifdef RGBLIGHT_LAYERS
820 if (rgblight_layers != NULL
821# if !defined(RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF)
822 && rgblight_config.enable
823# elif defined(RGBLIGHT_SLEEP)
824 && !is_suspended
825# endif
826 ) {
827 rgblight_layers_write();
828 }
829# endif
830
831# ifdef RGBLIGHT_LED_MAP
832 LED_TYPE led0[RGBLED_NUM];
833 for (uint8_t i = 0; i < RGBLED_NUM; i++) {
834 led0[i] = led[pgm_read_byte(&led_map[i])];
835 }
836 start_led = led0 + rgblight_ranges.clipping_start_pos;
837# else
838 start_led = led + rgblight_ranges.clipping_start_pos;
839# endif
840
841# ifdef RGBW
842 for (uint8_t i = 0; i < num_leds; i++) {
843 convert_rgb_to_rgbw(&start_led[i]);
844 }
845# endif
846 rgblight_call_driver(start_led, num_leds);
847}
848#endif
849
850#ifdef RGBLIGHT_SPLIT
851/* for split keyboard master side */
852uint8_t rgblight_get_change_flags(void) { return rgblight_status.change_flags; }
853
854void rgblight_clear_change_flags(void) { rgblight_status.change_flags = 0; }
855
856void rgblight_get_syncinfo(rgblight_syncinfo_t *syncinfo) {
857 syncinfo->config = rgblight_config;
858 syncinfo->status = rgblight_status;
859}
860
861/* for split keyboard slave side */
862void rgblight_update_sync(rgblight_syncinfo_t *syncinfo, bool write_to_eeprom) {
863# ifdef RGBLIGHT_LAYERS
864 if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_LAYERS) {
865 rgblight_status.enabled_layer_mask = syncinfo->status.enabled_layer_mask;
866 }
867# endif
868 if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_MODE) {
869 if (syncinfo->config.enable) {
870 rgblight_config.enable = 1; // == rgblight_enable_noeeprom();
871 rgblight_mode_eeprom_helper(syncinfo->config.mode, write_to_eeprom);
872 } else {
873 rgblight_disable_noeeprom();
874 }
875 }
876 if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_HSVS) {
877 rgblight_sethsv_eeprom_helper(syncinfo->config.hue, syncinfo->config.sat, syncinfo->config.val, write_to_eeprom);
878 // rgblight_config.speed = config->speed; // NEED???
879 }
880# ifdef RGBLIGHT_USE_TIMER
881 if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_TIMER) {
882 if (syncinfo->status.timer_enabled) {
883 rgblight_timer_enable();
884 } else {
885 rgblight_timer_disable();
886 }
887 }
888# ifndef RGBLIGHT_SPLIT_NO_ANIMATION_SYNC
889 if (syncinfo->status.change_flags & RGBLIGHT_STATUS_ANIMATION_TICK) {
890 animation_status.restart = true;
891 }
892# endif /* RGBLIGHT_SPLIT_NO_ANIMATION_SYNC */
893# endif /* RGBLIGHT_USE_TIMER */
894}
895#endif /* RGBLIGHT_SPLIT */
896
897#ifdef RGBLIGHT_USE_TIMER
898
899typedef void (*effect_func_t)(animation_status_t *anim);
900
901// Animation timer -- use system timer (AVR Timer0)
902void rgblight_timer_init(void) {
903 rgblight_status.timer_enabled = false;
904 RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE;
905}
906void rgblight_timer_enable(void) {
907 if (!is_static_effect(rgblight_config.mode)) {
908 rgblight_status.timer_enabled = true;
909 }
910 animation_status.last_timer = sync_timer_read();
911 RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE;
912 dprintf("rgblight timer enabled.\n");
913}
914void rgblight_timer_disable(void) {
915 rgblight_status.timer_enabled = false;
916 RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE;
917 dprintf("rgblight timer disable.\n");
918}
919void rgblight_timer_toggle(void) {
920 dprintf("rgblight timer toggle.\n");
921 if (rgblight_status.timer_enabled) {
922 rgblight_timer_disable();
923 } else {
924 rgblight_timer_enable();
925 }
926}
927
928void rgblight_show_solid_color(uint8_t r, uint8_t g, uint8_t b) {
929 rgblight_enable();
930 rgblight_mode(RGBLIGHT_MODE_STATIC_LIGHT);
931 rgblight_setrgb(r, g, b);
932}
933
934static void rgblight_effect_dummy(animation_status_t *anim) {
935 // do nothing
936 /********
937 dprintf("rgblight_task() what happened?\n");
938 dprintf("is_static_effect %d\n", is_static_effect(rgblight_config.mode));
939 dprintf("mode = %d, base_mode = %d, timer_enabled %d, ",
940 rgblight_config.mode, rgblight_status.base_mode,
941 rgblight_status.timer_enabled);
942 dprintf("last_timer = %d\n",anim->last_timer);
943 **/
944}
945
946void rgblight_task(void) {
947 if (rgblight_status.timer_enabled) {
948 effect_func_t effect_func = rgblight_effect_dummy;
949 uint16_t interval_time = 2000; // dummy interval
950 uint8_t delta = rgblight_config.mode - rgblight_status.base_mode;
951 animation_status.delta = delta;
952
953 // static light mode, do nothing here
954 if (1 == 0) { // dummy
955 }
956# ifdef RGBLIGHT_EFFECT_BREATHING
957 else if (rgblight_status.base_mode == RGBLIGHT_MODE_BREATHING) {
958 // breathing mode
959 interval_time = get_interval_time(&RGBLED_BREATHING_INTERVALS[delta], 1, 100);
960 effect_func = rgblight_effect_breathing;
961 }
962# endif
963# ifdef RGBLIGHT_EFFECT_RAINBOW_MOOD
964 else if (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_MOOD) {
965 // rainbow mood mode
966 interval_time = get_interval_time(&RGBLED_RAINBOW_MOOD_INTERVALS[delta], 5, 100);
967 effect_func = rgblight_effect_rainbow_mood;
968 }
969# endif
970# ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL
971 else if (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_SWIRL) {
972 // rainbow swirl mode
973 interval_time = get_interval_time(&RGBLED_RAINBOW_SWIRL_INTERVALS[delta / 2], 1, 100);
974 effect_func = rgblight_effect_rainbow_swirl;
975 }
976# endif
977# ifdef RGBLIGHT_EFFECT_SNAKE
978 else if (rgblight_status.base_mode == RGBLIGHT_MODE_SNAKE) {
979 // snake mode
980 interval_time = get_interval_time(&RGBLED_SNAKE_INTERVALS[delta / 2], 1, 200);
981 effect_func = rgblight_effect_snake;
982 }
983# endif
984# ifdef RGBLIGHT_EFFECT_KNIGHT
985 else if (rgblight_status.base_mode == RGBLIGHT_MODE_KNIGHT) {
986 // knight mode
987 interval_time = get_interval_time(&RGBLED_KNIGHT_INTERVALS[delta], 5, 100);
988 effect_func = rgblight_effect_knight;
989 }
990# endif
991# ifdef RGBLIGHT_EFFECT_CHRISTMAS
992 else if (rgblight_status.base_mode == RGBLIGHT_MODE_CHRISTMAS) {
993 // christmas mode
994 interval_time = RGBLIGHT_EFFECT_CHRISTMAS_INTERVAL;
995 effect_func = (effect_func_t)rgblight_effect_christmas;
996 }
997# endif
998# ifdef RGBLIGHT_EFFECT_RGB_TEST
999 else if (rgblight_status.base_mode == RGBLIGHT_MODE_RGB_TEST) {
1000 // RGB test mode
1001 interval_time = pgm_read_word(&RGBLED_RGBTEST_INTERVALS[0]);
1002 effect_func = (effect_func_t)rgblight_effect_rgbtest;
1003 }
1004# endif
1005# ifdef RGBLIGHT_EFFECT_ALTERNATING
1006 else if (rgblight_status.base_mode == RGBLIGHT_MODE_ALTERNATING) {
1007 interval_time = 500;
1008 effect_func = (effect_func_t)rgblight_effect_alternating;
1009 }
1010# endif
1011# ifdef RGBLIGHT_EFFECT_TWINKLE
1012 else if (rgblight_status.base_mode == RGBLIGHT_MODE_TWINKLE) {
1013 interval_time = get_interval_time(&RGBLED_TWINKLE_INTERVALS[delta % 3], 5, 30);
1014 effect_func = (effect_func_t)rgblight_effect_twinkle;
1015 }
1016# endif
1017 if (animation_status.restart) {
1018 animation_status.restart = false;
1019 animation_status.last_timer = sync_timer_read();
1020 animation_status.pos16 = 0; // restart signal to local each effect
1021 }
1022 uint16_t now = sync_timer_read();
1023 if (timer_expired(now, animation_status.last_timer)) {
1024# if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
1025 static uint16_t report_last_timer = 0;
1026 static bool tick_flag = false;
1027 uint16_t oldpos16;
1028 if (tick_flag) {
1029 tick_flag = false;
1030 if (timer_expired(now, report_last_timer)) {
1031 report_last_timer += 30000;
1032 dprintf("rgblight animation tick report to slave\n");
1033 RGBLIGHT_SPLIT_ANIMATION_TICK;
1034 }
1035 }
1036 oldpos16 = animation_status.pos16;
1037# endif
1038 animation_status.last_timer += interval_time;
1039 effect_func(&animation_status);
1040# if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
1041 if (animation_status.pos16 == 0 && oldpos16 != 0) {
1042 tick_flag = true;
1043 }
1044# endif
1045 }
1046 }
1047
1048# ifdef RGBLIGHT_LAYER_BLINK
1049 rgblight_blink_layer_repeat_helper();
1050# endif
1051}
1052
1053#endif /* RGBLIGHT_USE_TIMER */
1054
1055#if defined(RGBLIGHT_EFFECT_BREATHING) || defined(RGBLIGHT_EFFECT_TWINKLE)
1056
1057# ifndef RGBLIGHT_EFFECT_BREATHE_CENTER
1058# ifndef RGBLIGHT_BREATHE_TABLE_SIZE
1059# define RGBLIGHT_BREATHE_TABLE_SIZE 256 // 256 or 128 or 64
1060# endif
1061# include <rgblight_breathe_table.h>
1062# endif
1063
1064static uint8_t breathe_calc(uint8_t pos) {
1065 // http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/
1066# ifdef RGBLIGHT_EFFECT_BREATHE_TABLE
1067 return pgm_read_byte(&rgblight_effect_breathe_table[pos / table_scale]);
1068# else
1069 return (exp(sin((pos / 255.0) * M_PI)) - RGBLIGHT_EFFECT_BREATHE_CENTER / M_E) * (RGBLIGHT_EFFECT_BREATHE_MAX / (M_E - 1 / M_E));
1070# endif
1071}
1072
1073#endif
1074
1075// Effects
1076#ifdef RGBLIGHT_EFFECT_BREATHING
1077
1078__attribute__((weak)) const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5};
1079
1080void rgblight_effect_breathing(animation_status_t *anim) {
1081 uint8_t val = breathe_calc(anim->pos);
1082 rgblight_sethsv_noeeprom_old(rgblight_config.hue, rgblight_config.sat, val);
1083 anim->pos = (anim->pos + 1);
1084}
1085#endif
1086
1087#ifdef RGBLIGHT_EFFECT_RAINBOW_MOOD
1088__attribute__((weak)) const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[] PROGMEM = {120, 60, 30};
1089
1090void rgblight_effect_rainbow_mood(animation_status_t *anim) {
1091 rgblight_sethsv_noeeprom_old(anim->current_hue, rgblight_config.sat, rgblight_config.val);
1092 anim->current_hue++;
1093}
1094#endif
1095
1096#ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL
1097# ifndef RGBLIGHT_RAINBOW_SWIRL_RANGE
1098# define RGBLIGHT_RAINBOW_SWIRL_RANGE 255
1099# endif
1100
1101__attribute__((weak)) const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[] PROGMEM = {100, 50, 20};
1102
1103void rgblight_effect_rainbow_swirl(animation_status_t *anim) {
1104 uint8_t hue;
1105 uint8_t i;
1106
1107 for (i = 0; i < rgblight_ranges.effect_num_leds; i++) {
1108 hue = (RGBLIGHT_RAINBOW_SWIRL_RANGE / rgblight_ranges.effect_num_leds * i + anim->current_hue);
1109 sethsv(hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[i + rgblight_ranges.effect_start_pos]);
1110 }
1111 rgblight_set();
1112
1113 if (anim->delta % 2) {
1114 anim->current_hue++;
1115 } else {
1116 anim->current_hue--;
1117 }
1118}
1119#endif
1120
1121#ifdef RGBLIGHT_EFFECT_SNAKE
1122__attribute__((weak)) const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {100, 50, 20};
1123
1124void rgblight_effect_snake(animation_status_t *anim) {
1125 static uint8_t pos = 0;
1126 uint8_t i, j;
1127 int8_t k;
1128 int8_t increment = 1;
1129
1130 if (anim->delta % 2) {
1131 increment = -1;
1132 }
1133
1134# if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
1135 if (anim->pos == 0) { // restart signal
1136 if (increment == 1) {
1137 pos = rgblight_ranges.effect_num_leds - 1;
1138 } else {
1139 pos = 0;
1140 }
1141 anim->pos = 1;
1142 }
1143# endif
1144
1145 for (i = 0; i < rgblight_ranges.effect_num_leds; i++) {
1146 LED_TYPE *ledp = led + i + rgblight_ranges.effect_start_pos;
1147 ledp->r = 0;
1148 ledp->g = 0;
1149 ledp->b = 0;
1150# ifdef RGBW
1151 ledp->w = 0;
1152# endif
1153 for (j = 0; j < RGBLIGHT_EFFECT_SNAKE_LENGTH; j++) {
1154 k = pos + j * increment;
1155 if (k > RGBLED_NUM) {
1156 k = k % RGBLED_NUM;
1157 }
1158 if (k < 0) {
1159 k = k + rgblight_ranges.effect_num_leds;
1160 }
1161 if (i == k) {
1162 sethsv(rgblight_config.hue, rgblight_config.sat, (uint8_t)(rgblight_config.val * (RGBLIGHT_EFFECT_SNAKE_LENGTH - j) / RGBLIGHT_EFFECT_SNAKE_LENGTH), ledp);
1163 }
1164 }
1165 }
1166 rgblight_set();
1167 if (increment == 1) {
1168 if (pos - 1 < 0) {
1169 pos = rgblight_ranges.effect_num_leds - 1;
1170# if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
1171 anim->pos = 0;
1172# endif
1173 } else {
1174 pos -= 1;
1175# if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
1176 anim->pos = 1;
1177# endif
1178 }
1179 } else {
1180 pos = (pos + 1) % rgblight_ranges.effect_num_leds;
1181# if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
1182 anim->pos = pos;
1183# endif
1184 }
1185}
1186#endif
1187
1188#ifdef RGBLIGHT_EFFECT_KNIGHT
1189__attribute__((weak)) const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {127, 63, 31};
1190
1191void rgblight_effect_knight(animation_status_t *anim) {
1192 static int8_t low_bound = 0;
1193 static int8_t high_bound = RGBLIGHT_EFFECT_KNIGHT_LENGTH - 1;
1194 static int8_t increment = 1;
1195 uint8_t i, cur;
1196
1197# if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
1198 if (anim->pos == 0) { // restart signal
1199 anim->pos = 1;
1200 low_bound = 0;
1201 high_bound = RGBLIGHT_EFFECT_KNIGHT_LENGTH - 1;
1202 increment = 1;
1203 }
1204# endif
1205 // Set all the LEDs to 0
1206 for (i = rgblight_ranges.effect_start_pos; i < rgblight_ranges.effect_end_pos; i++) {
1207 led[i].r = 0;
1208 led[i].g = 0;
1209 led[i].b = 0;
1210# ifdef RGBW
1211 led[i].w = 0;
1212# endif
1213 }
1214 // Determine which LEDs should be lit up
1215 for (i = 0; i < RGBLIGHT_EFFECT_KNIGHT_LED_NUM; i++) {
1216 cur = (i + RGBLIGHT_EFFECT_KNIGHT_OFFSET) % rgblight_ranges.effect_num_leds + rgblight_ranges.effect_start_pos;
1217
1218 if (i >= low_bound && i <= high_bound) {
1219 sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[cur]);
1220 } else {
1221 led[cur].r = 0;
1222 led[cur].g = 0;
1223 led[cur].b = 0;
1224# ifdef RGBW
1225 led[cur].w = 0;
1226# endif
1227 }
1228 }
1229 rgblight_set();
1230
1231 // Move from low_bound to high_bound changing the direction we increment each
1232 // time a boundary is hit.
1233 low_bound += increment;
1234 high_bound += increment;
1235
1236 if (high_bound <= 0 || low_bound >= RGBLIGHT_EFFECT_KNIGHT_LED_NUM - 1) {
1237 increment = -increment;
1238# if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
1239 if (increment == 1) {
1240 anim->pos = 0;
1241 }
1242# endif
1243 }
1244}
1245#endif
1246
1247#ifdef RGBLIGHT_EFFECT_CHRISTMAS
1248# define CUBED(x) ((x) * (x) * (x))
1249
1250/**
1251 * Christmas lights effect, with a smooth animation between red & green.
1252 */
1253void rgblight_effect_christmas(animation_status_t *anim) {
1254 static int8_t increment = 1;
1255 const uint8_t max_pos = 32;
1256 const uint8_t hue_green = 85;
1257
1258 uint32_t xa;
1259 uint8_t hue, val;
1260 uint8_t i;
1261
1262 // The effect works by animating anim->pos from 0 to 32 and back to 0.
1263 // The pos is used in a cubic bezier formula to ease-in-out between red and green, leaving the interpolated colors visible as short as possible.
1264 xa = CUBED((uint32_t)anim->pos);
1265 hue = ((uint32_t)hue_green) * xa / (xa + CUBED((uint32_t)(max_pos - anim->pos)));
1266 // Additionally, these interpolated colors get shown with a slightly darker value, to make them less prominent than the main colors.
1267 val = 255 - (3 * (hue < hue_green / 2 ? hue : hue_green - hue) / 2);
1268
1269 for (i = 0; i < rgblight_ranges.effect_num_leds; i++) {
1270 uint8_t local_hue = (i / RGBLIGHT_EFFECT_CHRISTMAS_STEP) % 2 ? hue : hue_green - hue;
1271 sethsv(local_hue, rgblight_config.sat, val, (LED_TYPE *)&led[i + rgblight_ranges.effect_start_pos]);
1272 }
1273 rgblight_set();
1274
1275 if (anim->pos == 0) {
1276 increment = 1;
1277 } else if (anim->pos == max_pos) {
1278 increment = -1;
1279 }
1280 anim->pos += increment;
1281}
1282#endif
1283
1284#ifdef RGBLIGHT_EFFECT_RGB_TEST
1285__attribute__((weak)) const uint16_t RGBLED_RGBTEST_INTERVALS[] PROGMEM = {1024};
1286
1287void rgblight_effect_rgbtest(animation_status_t *anim) {
1288 static uint8_t maxval = 0;
1289 uint8_t g;
1290 uint8_t r;
1291 uint8_t b;
1292
1293 if (maxval == 0) {
1294 LED_TYPE tmp_led;
1295 sethsv(0, 255, RGBLIGHT_LIMIT_VAL, &tmp_led);
1296 maxval = tmp_led.r;
1297 }
1298 g = r = b = 0;
1299 switch (anim->pos) {
1300 case 0:
1301 r = maxval;
1302 break;
1303 case 1:
1304 g = maxval;
1305 break;
1306 case 2:
1307 b = maxval;
1308 break;
1309 }
1310 rgblight_setrgb(r, g, b);
1311 anim->pos = (anim->pos + 1) % 3;
1312}
1313#endif
1314
1315#ifdef RGBLIGHT_EFFECT_ALTERNATING
1316void rgblight_effect_alternating(animation_status_t *anim) {
1317 for (int i = 0; i < rgblight_ranges.effect_num_leds; i++) {
1318 LED_TYPE *ledp = led + i + rgblight_ranges.effect_start_pos;
1319 if (i < rgblight_ranges.effect_num_leds / 2 && anim->pos) {
1320 sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, ledp);
1321 } else if (i >= rgblight_ranges.effect_num_leds / 2 && !anim->pos) {
1322 sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, ledp);
1323 } else {
1324 sethsv(rgblight_config.hue, rgblight_config.sat, 0, ledp);
1325 }
1326 }
1327 rgblight_set();
1328 anim->pos = (anim->pos + 1) % 2;
1329}
1330#endif
1331
1332#ifdef RGBLIGHT_EFFECT_TWINKLE
1333__attribute__((weak)) const uint8_t RGBLED_TWINKLE_INTERVALS[] PROGMEM = {30, 15, 5};
1334
1335typedef struct PACKED {
1336 HSV hsv;
1337 uint8_t life;
1338 uint8_t max_life;
1339} TwinkleState;
1340
1341static TwinkleState led_twinkle_state[RGBLED_NUM];
1342
1343void rgblight_effect_twinkle(animation_status_t *anim) {
1344 const bool random_color = anim->delta / 3;
1345 const bool restart = anim->pos == 0;
1346 anim->pos = 1;
1347
1348 const uint8_t bottom = breathe_calc(0);
1349 const uint8_t top = breathe_calc(127);
1350
1351 uint8_t frac(uint8_t n, uint8_t d) { return (uint16_t)255 * n / d; }
1352 uint8_t scale(uint16_t v, uint8_t scale) { return (v * scale) >> 8; }
1353
1354 for (uint8_t i = 0; i < rgblight_ranges.effect_num_leds; i++) {
1355 TwinkleState *t = &(led_twinkle_state[i]);
1356 HSV * c = &(t->hsv);
1357
1358 if (!random_color) {
1359 c->h = rgblight_config.hue;
1360 c->s = rgblight_config.sat;
1361 }
1362
1363 if (restart) {
1364 // Restart
1365 t->life = 0;
1366 c->v = 0;
1367 } else if (t->life) {
1368 // This LED is already on, either brightening or dimming
1369 t->life--;
1370 uint8_t unscaled = frac(breathe_calc(frac(t->life, t->max_life)) - bottom, top - bottom);
1371 c->v = scale(rgblight_config.val, unscaled);
1372 } else if (rand() < scale((uint16_t)RAND_MAX * RGBLIGHT_EFFECT_TWINKLE_PROBABILITY, 127 + rgblight_config.val / 2)) {
1373 // This LED is off, but was randomly selected to start brightening
1374 if (random_color) {
1375 c->h = rand() % 0xFF;
1376 c->s = (rand() % (rgblight_config.sat / 2)) + (rgblight_config.sat / 2);
1377 }
1378 c->v = 0;
1379 t->max_life = MAX(20, MIN(RGBLIGHT_EFFECT_TWINKLE_LIFE, rgblight_config.val));
1380 t->life = t->max_life;
1381 } else {
1382 // This LED is off, and was NOT selected to start brightening
1383 }
1384
1385 LED_TYPE *ledp = led + i + rgblight_ranges.effect_start_pos;
1386 sethsv(c->h, c->s, c->v, ledp);
1387 }
1388
1389 rgblight_set();
1390}
1391#endif