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