qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

rgblight.c (49924B)


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