qmk

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.z3bra.org/qmk.git
Log | Files | Refs | Submodules | LICENSE

rgblight.c (37057B)


      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 #ifdef __AVR__
     19 #    include <avr/eeprom.h>
     20 #    include <avr/interrupt.h>
     21 #endif
     22 #ifdef STM32_EEPROM_ENABLE
     23 #    include "hal.h"
     24 #    include "eeprom.h"
     25 #    include "eeprom_stm32.h"
     26 #endif
     27 #include "wait.h"
     28 #include "progmem.h"
     29 #include "timer.h"
     30 #include "rgblight.h"
     31 #include "color.h"
     32 #include "debug.h"
     33 #include "led_tables.h"
     34 #include "lib/lib8tion/lib8tion.h"
     35 #ifdef VELOCIKEY_ENABLE
     36 #    include "velocikey.h"
     37 #endif
     38 
     39 #ifdef RGBLIGHT_SPLIT
     40 /* for split keyboard */
     41 #    define RGBLIGHT_SPLIT_SET_CHANGE_MODE rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_MODE
     42 #    define RGBLIGHT_SPLIT_SET_CHANGE_HSVS rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_HSVS
     43 #    define RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS rgblight_status.change_flags |= (RGBLIGHT_STATUS_CHANGE_MODE | RGBLIGHT_STATUS_CHANGE_HSVS)
     44 #    define RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_TIMER
     45 #    define RGBLIGHT_SPLIT_ANIMATION_TICK rgblight_status.change_flags |= RGBLIGHT_STATUS_ANIMATION_TICK
     46 #else
     47 #    define RGBLIGHT_SPLIT_SET_CHANGE_MODE
     48 #    define RGBLIGHT_SPLIT_SET_CHANGE_HSVS
     49 #    define RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS
     50 #    define RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE
     51 #    define RGBLIGHT_SPLIT_ANIMATION_TICK
     52 #endif
     53 
     54 #define _RGBM_SINGLE_STATIC(sym) RGBLIGHT_MODE_##sym,
     55 #define _RGBM_SINGLE_DYNAMIC(sym)
     56 #define _RGBM_MULTI_STATIC(sym) RGBLIGHT_MODE_##sym,
     57 #define _RGBM_MULTI_DYNAMIC(sym)
     58 #define _RGBM_TMP_STATIC(sym, msym) RGBLIGHT_MODE_##sym,
     59 #define _RGBM_TMP_DYNAMIC(sym, msym)
     60 static uint8_t static_effect_table[] = {
     61 #include "rgblight_modes.h"
     62 };
     63 
     64 #define _RGBM_SINGLE_STATIC(sym) RGBLIGHT_MODE_##sym,
     65 #define _RGBM_SINGLE_DYNAMIC(sym) RGBLIGHT_MODE_##sym,
     66 #define _RGBM_MULTI_STATIC(sym) RGBLIGHT_MODE_##sym,
     67 #define _RGBM_MULTI_DYNAMIC(sym) RGBLIGHT_MODE_##sym,
     68 #define _RGBM_TMP_STATIC(sym, msym) RGBLIGHT_MODE_##msym,
     69 #define _RGBM_TMP_DYNAMIC(sym, msym) RGBLIGHT_MODE_##msym,
     70 static uint8_t mode_base_table[] = {
     71     0,  // RGBLIGHT_MODE_zero
     72 #include "rgblight_modes.h"
     73 };
     74 
     75 static inline int is_static_effect(uint8_t mode) { return memchr(static_effect_table, mode, sizeof(static_effect_table)) != NULL; }
     76 
     77 #ifdef RGBLIGHT_LED_MAP
     78 const uint8_t led_map[] PROGMEM = RGBLIGHT_LED_MAP;
     79 #endif
     80 
     81 #ifdef RGBLIGHT_EFFECT_STATIC_GRADIENT
     82 __attribute__((weak)) const uint8_t RGBLED_GRADIENT_RANGES[] PROGMEM = {255, 170, 127, 85, 64};
     83 #endif
     84 
     85 rgblight_config_t rgblight_config;
     86 rgblight_status_t rgblight_status         = {.timer_enabled = false};
     87 bool              is_rgblight_initialized = false;
     88 
     89 #ifdef RGBLIGHT_USE_TIMER
     90 animation_status_t animation_status = {};
     91 #endif
     92 
     93 #ifndef LED_ARRAY
     94 LED_TYPE led[RGBLED_NUM];
     95 #    define LED_ARRAY led
     96 #endif
     97 
     98 static uint8_t clipping_start_pos = 0;
     99 static uint8_t clipping_num_leds  = RGBLED_NUM;
    100 static uint8_t effect_start_pos   = 0;
    101 static uint8_t effect_end_pos     = RGBLED_NUM;
    102 static uint8_t effect_num_leds    = RGBLED_NUM;
    103 
    104 void rgblight_set_clipping_range(uint8_t start_pos, uint8_t num_leds) {
    105     clipping_start_pos = start_pos;
    106     clipping_num_leds  = num_leds;
    107 }
    108 
    109 void rgblight_set_effect_range(uint8_t start_pos, uint8_t num_leds) {
    110     if (start_pos >= RGBLED_NUM) return;
    111     if (start_pos + num_leds > RGBLED_NUM) return;
    112     effect_start_pos = start_pos;
    113     effect_end_pos   = start_pos + num_leds;
    114     effect_num_leds  = num_leds;
    115 }
    116 
    117 void sethsv_raw(uint8_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1) {
    118     HSV hsv = {hue, sat, val};
    119     RGB rgb = hsv_to_rgb(hsv);
    120     setrgb(rgb.r, rgb.g, rgb.b, led1);
    121 }
    122 
    123 void sethsv(uint8_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1) { sethsv_raw(hue, sat, val > RGBLIGHT_LIMIT_VAL ? RGBLIGHT_LIMIT_VAL : val, led1); }
    124 
    125 void setrgb(uint8_t r, uint8_t g, uint8_t b, LED_TYPE *led1) {
    126     (*led1).r = r;
    127     (*led1).g = g;
    128     (*led1).b = b;
    129 }
    130 
    131 void rgblight_check_config(void) {
    132     /* Add some out of bound checks for RGB light config */
    133 
    134     if (rgblight_config.mode < RGBLIGHT_MODE_STATIC_LIGHT) {
    135         rgblight_config.mode = RGBLIGHT_MODE_STATIC_LIGHT;
    136     } else if (rgblight_config.mode > RGBLIGHT_MODES) {
    137         rgblight_config.mode = RGBLIGHT_MODES;
    138     }
    139 
    140     if (rgblight_config.val > RGBLIGHT_LIMIT_VAL) {
    141         rgblight_config.val = RGBLIGHT_LIMIT_VAL;
    142     }
    143 }
    144 
    145 uint32_t eeconfig_read_rgblight(void) {
    146 #if defined(__AVR__) || defined(STM32_EEPROM_ENABLE) || defined(PROTOCOL_ARM_ATSAM) || defined(EEPROM_SIZE)
    147     return eeprom_read_dword(EECONFIG_RGBLIGHT);
    148 #else
    149     return 0;
    150 #endif
    151 }
    152 
    153 void eeconfig_update_rgblight(uint32_t val) {
    154 #if defined(__AVR__) || defined(STM32_EEPROM_ENABLE) || defined(PROTOCOL_ARM_ATSAM) || defined(EEPROM_SIZE)
    155     rgblight_check_config();
    156     eeprom_update_dword(EECONFIG_RGBLIGHT, val);
    157 #endif
    158 }
    159 
    160 void eeconfig_update_rgblight_default(void) {
    161     rgblight_config.enable = 1;
    162     rgblight_config.mode   = RGBLIGHT_MODE_STATIC_LIGHT;
    163     rgblight_config.hue    = 0;
    164     rgblight_config.sat    = UINT8_MAX;
    165     rgblight_config.val    = RGBLIGHT_LIMIT_VAL;
    166     rgblight_config.speed  = 0;
    167     RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS;
    168     eeconfig_update_rgblight(rgblight_config.raw);
    169 }
    170 
    171 void eeconfig_debug_rgblight(void) {
    172     dprintf("rgblight_config EEPROM:\n");
    173     dprintf("rgblight_config.enable = %d\n", rgblight_config.enable);
    174     dprintf("rghlight_config.mode = %d\n", rgblight_config.mode);
    175     dprintf("rgblight_config.hue = %d\n", rgblight_config.hue);
    176     dprintf("rgblight_config.sat = %d\n", rgblight_config.sat);
    177     dprintf("rgblight_config.val = %d\n", rgblight_config.val);
    178     dprintf("rgblight_config.speed = %d\n", rgblight_config.speed);
    179 }
    180 
    181 void rgblight_init(void) {
    182     /* if already initialized, don't do it again.
    183        If you must do it again, extern this and set to false, first.
    184        This is a dirty, dirty hack until proper hooks can be added for keyboard startup. */
    185     if (is_rgblight_initialized) {
    186         return;
    187     }
    188 
    189     debug_enable = 1;  // Debug ON!
    190     dprintf("rgblight_init called.\n");
    191     dprintf("rgblight_init start!\n");
    192     if (!eeconfig_is_enabled()) {
    193         dprintf("rgblight_init eeconfig is not enabled.\n");
    194         eeconfig_init();
    195         eeconfig_update_rgblight_default();
    196     }
    197     rgblight_config.raw = eeconfig_read_rgblight();
    198     RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS;
    199     if (!rgblight_config.mode) {
    200         dprintf("rgblight_init rgblight_config.mode = 0. Write default values to EEPROM.\n");
    201         eeconfig_update_rgblight_default();
    202         rgblight_config.raw = eeconfig_read_rgblight();
    203     }
    204     rgblight_check_config();
    205 
    206     eeconfig_debug_rgblight();  // display current eeprom values
    207 
    208 #ifdef RGBLIGHT_USE_TIMER
    209     rgblight_timer_init();  // setup the timer
    210 #endif
    211 
    212     if (rgblight_config.enable) {
    213         rgblight_mode_noeeprom(rgblight_config.mode);
    214     }
    215 
    216     is_rgblight_initialized = true;
    217 }
    218 
    219 uint32_t rgblight_read_dword(void) { return rgblight_config.raw; }
    220 
    221 void rgblight_update_dword(uint32_t dword) {
    222     RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS;
    223     rgblight_config.raw = dword;
    224     if (rgblight_config.enable)
    225         rgblight_mode_noeeprom(rgblight_config.mode);
    226     else {
    227 #ifdef RGBLIGHT_USE_TIMER
    228         rgblight_timer_disable();
    229 #endif
    230         rgblight_set();
    231     }
    232 }
    233 
    234 void rgblight_increase(void) {
    235     uint8_t mode = 0;
    236     if (rgblight_config.mode < RGBLIGHT_MODES) {
    237         mode = rgblight_config.mode + 1;
    238     }
    239     rgblight_mode(mode);
    240 }
    241 void rgblight_decrease(void) {
    242     uint8_t mode = 0;
    243     // Mode will never be < 1. If it ever is, eeprom needs to be initialized.
    244     if (rgblight_config.mode > RGBLIGHT_MODE_STATIC_LIGHT) {
    245         mode = rgblight_config.mode - 1;
    246     }
    247     rgblight_mode(mode);
    248 }
    249 void rgblight_step_helper(bool write_to_eeprom) {
    250     uint8_t mode = 0;
    251     mode         = rgblight_config.mode + 1;
    252     if (mode > RGBLIGHT_MODES) {
    253         mode = 1;
    254     }
    255     rgblight_mode_eeprom_helper(mode, write_to_eeprom);
    256 }
    257 void rgblight_step_noeeprom(void) { rgblight_step_helper(false); }
    258 void rgblight_step(void) { rgblight_step_helper(true); }
    259 void rgblight_step_reverse_helper(bool write_to_eeprom) {
    260     uint8_t mode = 0;
    261     mode         = rgblight_config.mode - 1;
    262     if (mode < 1) {
    263         mode = RGBLIGHT_MODES;
    264     }
    265     rgblight_mode_eeprom_helper(mode, write_to_eeprom);
    266 }
    267 void rgblight_step_reverse_noeeprom(void) { rgblight_step_reverse_helper(false); }
    268 void rgblight_step_reverse(void) { rgblight_step_reverse_helper(true); }
    269 
    270 uint8_t rgblight_get_mode(void) {
    271     if (!rgblight_config.enable) {
    272         return false;
    273     }
    274 
    275     return rgblight_config.mode;
    276 }
    277 
    278 void rgblight_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom) {
    279     if (!rgblight_config.enable) {
    280         return;
    281     }
    282     if (mode < RGBLIGHT_MODE_STATIC_LIGHT) {
    283         rgblight_config.mode = RGBLIGHT_MODE_STATIC_LIGHT;
    284     } else if (mode > RGBLIGHT_MODES) {
    285         rgblight_config.mode = RGBLIGHT_MODES;
    286     } else {
    287         rgblight_config.mode = mode;
    288     }
    289     RGBLIGHT_SPLIT_SET_CHANGE_MODE;
    290     if (write_to_eeprom) {
    291         eeconfig_update_rgblight(rgblight_config.raw);
    292         dprintf("rgblight mode [EEPROM]: %u\n", rgblight_config.mode);
    293     } else {
    294         dprintf("rgblight mode [NOEEPROM]: %u\n", rgblight_config.mode);
    295     }
    296     if (is_static_effect(rgblight_config.mode)) {
    297 #ifdef RGBLIGHT_USE_TIMER
    298         rgblight_timer_disable();
    299 #endif
    300     } else {
    301 #ifdef RGBLIGHT_USE_TIMER
    302         rgblight_timer_enable();
    303 #endif
    304     }
    305 #ifdef RGBLIGHT_USE_TIMER
    306     animation_status.restart = true;
    307 #endif
    308     rgblight_sethsv_noeeprom(rgblight_config.hue, rgblight_config.sat, rgblight_config.val);
    309 }
    310 
    311 void rgblight_mode(uint8_t mode) { rgblight_mode_eeprom_helper(mode, true); }
    312 
    313 void rgblight_mode_noeeprom(uint8_t mode) { rgblight_mode_eeprom_helper(mode, false); }
    314 
    315 void rgblight_toggle(void) {
    316     dprintf("rgblight toggle [EEPROM]: rgblight_config.enable = %u\n", !rgblight_config.enable);
    317     if (rgblight_config.enable) {
    318         rgblight_disable();
    319     } else {
    320         rgblight_enable();
    321     }
    322 }
    323 
    324 void rgblight_toggle_noeeprom(void) {
    325     dprintf("rgblight toggle [NOEEPROM]: rgblight_config.enable = %u\n", !rgblight_config.enable);
    326     if (rgblight_config.enable) {
    327         rgblight_disable_noeeprom();
    328     } else {
    329         rgblight_enable_noeeprom();
    330     }
    331 }
    332 
    333 void rgblight_enable(void) {
    334     rgblight_config.enable = 1;
    335     // No need to update EEPROM here. rgblight_mode() will do that, actually
    336     // eeconfig_update_rgblight(rgblight_config.raw);
    337     dprintf("rgblight enable [EEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable);
    338     rgblight_mode(rgblight_config.mode);
    339 }
    340 
    341 void rgblight_enable_noeeprom(void) {
    342     rgblight_config.enable = 1;
    343     dprintf("rgblight enable [NOEEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable);
    344     rgblight_mode_noeeprom(rgblight_config.mode);
    345 }
    346 
    347 void rgblight_disable(void) {
    348     rgblight_config.enable = 0;
    349     eeconfig_update_rgblight(rgblight_config.raw);
    350     dprintf("rgblight disable [EEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable);
    351 #ifdef RGBLIGHT_USE_TIMER
    352     rgblight_timer_disable();
    353 #endif
    354     RGBLIGHT_SPLIT_SET_CHANGE_MODE;
    355     wait_ms(50);
    356     rgblight_set();
    357 }
    358 
    359 void rgblight_disable_noeeprom(void) {
    360     rgblight_config.enable = 0;
    361     dprintf("rgblight disable [NOEEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable);
    362 #ifdef RGBLIGHT_USE_TIMER
    363     rgblight_timer_disable();
    364 #endif
    365     RGBLIGHT_SPLIT_SET_CHANGE_MODE;
    366     wait_ms(50);
    367     rgblight_set();
    368 }
    369 
    370 void rgblight_increase_hue_helper(bool write_to_eeprom) {
    371     uint8_t hue = rgblight_config.hue + RGBLIGHT_HUE_STEP;
    372     rgblight_sethsv_eeprom_helper(hue, rgblight_config.sat, rgblight_config.val, write_to_eeprom);
    373 }
    374 void rgblight_increase_hue_noeeprom(void) { rgblight_increase_hue_helper(false); }
    375 void rgblight_increase_hue(void) { rgblight_increase_hue_helper(true); }
    376 void rgblight_decrease_hue_helper(bool write_to_eeprom) {
    377     uint8_t hue = rgblight_config.hue - RGBLIGHT_HUE_STEP;
    378     rgblight_sethsv_eeprom_helper(hue, rgblight_config.sat, rgblight_config.val, write_to_eeprom);
    379 }
    380 void rgblight_decrease_hue_noeeprom(void) { rgblight_decrease_hue_helper(false); }
    381 void rgblight_decrease_hue(void) { rgblight_decrease_hue_helper(true); }
    382 void rgblight_increase_sat_helper(bool write_to_eeprom) {
    383     uint8_t sat = qadd8(rgblight_config.sat, RGBLIGHT_SAT_STEP);
    384     rgblight_sethsv_eeprom_helper(rgblight_config.hue, sat, rgblight_config.val, write_to_eeprom);
    385 }
    386 void rgblight_increase_sat_noeeprom(void) { rgblight_increase_sat_helper(false); }
    387 void rgblight_increase_sat(void) { rgblight_increase_sat_helper(true); }
    388 void rgblight_decrease_sat_helper(bool write_to_eeprom) {
    389     uint8_t sat = qsub8(rgblight_config.sat, RGBLIGHT_SAT_STEP);
    390     rgblight_sethsv_eeprom_helper(rgblight_config.hue, sat, rgblight_config.val, write_to_eeprom);
    391 }
    392 void rgblight_decrease_sat_noeeprom(void) { rgblight_decrease_sat_helper(false); }
    393 void rgblight_decrease_sat(void) { rgblight_decrease_sat_helper(true); }
    394 void rgblight_increase_val_helper(bool write_to_eeprom) {
    395     uint8_t val = qadd8(rgblight_config.val, RGBLIGHT_VAL_STEP);
    396     rgblight_sethsv_eeprom_helper(rgblight_config.hue, rgblight_config.sat, val, write_to_eeprom);
    397 }
    398 void rgblight_increase_val_noeeprom(void) { rgblight_increase_val_helper(false); }
    399 void rgblight_increase_val(void) { rgblight_increase_val_helper(true); }
    400 void rgblight_decrease_val_helper(bool write_to_eeprom) {
    401     uint8_t val = qsub8(rgblight_config.val, RGBLIGHT_VAL_STEP);
    402     rgblight_sethsv_eeprom_helper(rgblight_config.hue, rgblight_config.sat, val, write_to_eeprom);
    403 }
    404 void rgblight_decrease_val_noeeprom(void) { rgblight_decrease_val_helper(false); }
    405 void rgblight_decrease_val(void) { rgblight_decrease_val_helper(true); }
    406 void rgblight_increase_speed(void) {
    407     if (rgblight_config.speed < 3) rgblight_config.speed++;
    408     // RGBLIGHT_SPLIT_SET_CHANGE_HSVS; // NEED?
    409     eeconfig_update_rgblight(rgblight_config.raw);  // EECONFIG needs to be increased to support this
    410 }
    411 
    412 void rgblight_decrease_speed(void) {
    413     if (rgblight_config.speed > 0) rgblight_config.speed--;
    414     // RGBLIGHT_SPLIT_SET_CHANGE_HSVS; // NEED??
    415     eeconfig_update_rgblight(rgblight_config.raw);  // EECONFIG needs to be increased to support this
    416 }
    417 
    418 void rgblight_sethsv_noeeprom_old(uint8_t hue, uint8_t sat, uint8_t val) {
    419     if (rgblight_config.enable) {
    420         LED_TYPE tmp_led;
    421         sethsv(hue, sat, val, &tmp_led);
    422         rgblight_setrgb(tmp_led.r, tmp_led.g, tmp_led.b);
    423     }
    424 }
    425 
    426 void rgblight_sethsv_eeprom_helper(uint8_t hue, uint8_t sat, uint8_t val, bool write_to_eeprom) {
    427     if (rgblight_config.enable) {
    428         rgblight_status.base_mode = mode_base_table[rgblight_config.mode];
    429         if (rgblight_config.mode == RGBLIGHT_MODE_STATIC_LIGHT) {
    430             // same static color
    431             LED_TYPE tmp_led;
    432             sethsv(hue, sat, val, &tmp_led);
    433             rgblight_setrgb(tmp_led.r, tmp_led.g, tmp_led.b);
    434         } else {
    435             // all LEDs in same color
    436             if (1 == 0) {  // dummy
    437             }
    438 #ifdef RGBLIGHT_EFFECT_BREATHING
    439             else if (rgblight_status.base_mode == RGBLIGHT_MODE_BREATHING) {
    440                 // breathing mode, ignore the change of val, use in memory value instead
    441                 val = rgblight_config.val;
    442             }
    443 #endif
    444 #ifdef RGBLIGHT_EFFECT_RAINBOW_MOOD
    445             else if (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_MOOD) {
    446                 // rainbow mood, ignore the change of hue
    447                 hue = rgblight_config.hue;
    448             }
    449 #endif
    450 #ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL
    451             else if (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_SWIRL) {
    452                 // rainbow swirl, ignore the change of hue
    453                 hue = rgblight_config.hue;
    454             }
    455 #endif
    456 #ifdef RGBLIGHT_EFFECT_STATIC_GRADIENT
    457             else if (rgblight_status.base_mode == RGBLIGHT_MODE_STATIC_GRADIENT) {
    458                 // static gradient
    459                 uint8_t delta     = rgblight_config.mode - rgblight_status.base_mode;
    460                 bool    direction = (delta % 2) == 0;
    461 #    ifdef __AVR__
    462                 // probably due to how pgm_read_word is defined for ARM, but the ARM compiler really hates this line
    463                 uint8_t range = pgm_read_word(&RGBLED_GRADIENT_RANGES[delta / 2]);
    464 #    else
    465                 uint8_t range = RGBLED_GRADIENT_RANGES[delta / 2];
    466 #    endif
    467                 for (uint8_t i = 0; i < effect_num_leds; i++) {
    468                     uint8_t _hue = ((uint16_t)i * (uint16_t)range) / effect_num_leds;
    469                     if (direction) {
    470                         _hue = hue + _hue;
    471                     } else {
    472                         _hue = hue - _hue;
    473                     }
    474                     dprintf("rgblight rainbow set hsv: %d,%d,%d,%u\n", i, _hue, direction, range);
    475                     sethsv(_hue, sat, val, (LED_TYPE *)&led[i + effect_start_pos]);
    476                 }
    477                 rgblight_set();
    478             }
    479 #endif
    480         }
    481 #ifdef RGBLIGHT_SPLIT
    482         if (rgblight_config.hue != hue || rgblight_config.sat != sat || rgblight_config.val != val) {
    483             RGBLIGHT_SPLIT_SET_CHANGE_HSVS;
    484         }
    485 #endif
    486         rgblight_config.hue = hue;
    487         rgblight_config.sat = sat;
    488         rgblight_config.val = val;
    489         if (write_to_eeprom) {
    490             eeconfig_update_rgblight(rgblight_config.raw);
    491             dprintf("rgblight set hsv [EEPROM]: %u,%u,%u\n", rgblight_config.hue, rgblight_config.sat, rgblight_config.val);
    492         } else {
    493             dprintf("rgblight set hsv [NOEEPROM]: %u,%u,%u\n", rgblight_config.hue, rgblight_config.sat, rgblight_config.val);
    494         }
    495     }
    496 }
    497 
    498 void rgblight_sethsv(uint8_t hue, uint8_t sat, uint8_t val) { rgblight_sethsv_eeprom_helper(hue, sat, val, true); }
    499 
    500 void rgblight_sethsv_noeeprom(uint8_t hue, uint8_t sat, uint8_t val) { rgblight_sethsv_eeprom_helper(hue, sat, val, false); }
    501 
    502 uint8_t rgblight_get_hue(void) { return rgblight_config.hue; }
    503 
    504 uint8_t rgblight_get_sat(void) { return rgblight_config.sat; }
    505 
    506 uint8_t rgblight_get_val(void) { return rgblight_config.val; }
    507 
    508 void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b) {
    509     if (!rgblight_config.enable) {
    510         return;
    511     }
    512 
    513     for (uint8_t i = effect_start_pos; i < effect_end_pos; i++) {
    514         led[i].r = r;
    515         led[i].g = g;
    516         led[i].b = b;
    517     }
    518     rgblight_set();
    519 }
    520 
    521 void rgblight_setrgb_at(uint8_t r, uint8_t g, uint8_t b, uint8_t index) {
    522     if (!rgblight_config.enable || index >= RGBLED_NUM) {
    523         return;
    524     }
    525 
    526     led[index].r = r;
    527     led[index].g = g;
    528     led[index].b = b;
    529     rgblight_set();
    530 }
    531 
    532 void rgblight_sethsv_at(uint8_t hue, uint8_t sat, uint8_t val, uint8_t index) {
    533     if (!rgblight_config.enable) {
    534         return;
    535     }
    536 
    537     LED_TYPE tmp_led;
    538     sethsv(hue, sat, val, &tmp_led);
    539     rgblight_setrgb_at(tmp_led.r, tmp_led.g, tmp_led.b, index);
    540 }
    541 
    542 #if defined(RGBLIGHT_EFFECT_BREATHING) || defined(RGBLIGHT_EFFECT_RAINBOW_MOOD) || defined(RGBLIGHT_EFFECT_RAINBOW_SWIRL) || defined(RGBLIGHT_EFFECT_SNAKE) || defined(RGBLIGHT_EFFECT_KNIGHT)
    543 
    544 static uint8_t get_interval_time(const uint8_t *default_interval_address, uint8_t velocikey_min, uint8_t velocikey_max) {
    545     return
    546 #    ifdef VELOCIKEY_ENABLE
    547         velocikey_enabled() ? velocikey_match_speed(velocikey_min, velocikey_max) :
    548 #    endif
    549                             pgm_read_byte(default_interval_address);
    550 }
    551 
    552 #endif
    553 
    554 void rgblight_setrgb_range(uint8_t r, uint8_t g, uint8_t b, uint8_t start, uint8_t end) {
    555     if (!rgblight_config.enable || start < 0 || start >= end || end > RGBLED_NUM) {
    556         return;
    557     }
    558 
    559     for (uint8_t i = start; i < end; i++) {
    560         led[i].r = r;
    561         led[i].g = g;
    562         led[i].b = b;
    563     }
    564     rgblight_set();
    565     wait_ms(1);
    566 }
    567 
    568 void rgblight_sethsv_range(uint8_t hue, uint8_t sat, uint8_t val, uint8_t start, uint8_t end) {
    569     if (!rgblight_config.enable) {
    570         return;
    571     }
    572 
    573     LED_TYPE tmp_led;
    574     sethsv(hue, sat, val, &tmp_led);
    575     rgblight_setrgb_range(tmp_led.r, tmp_led.g, tmp_led.b, start, end);
    576 }
    577 
    578 #ifndef RGBLIGHT_SPLIT
    579 void rgblight_setrgb_master(uint8_t r, uint8_t g, uint8_t b) { rgblight_setrgb_range(r, g, b, 0, (uint8_t)RGBLED_NUM / 2); }
    580 
    581 void rgblight_setrgb_slave(uint8_t r, uint8_t g, uint8_t b) { rgblight_setrgb_range(r, g, b, (uint8_t)RGBLED_NUM / 2, (uint8_t)RGBLED_NUM); }
    582 
    583 void rgblight_sethsv_master(uint8_t hue, uint8_t sat, uint8_t val) { rgblight_sethsv_range(hue, sat, val, 0, (uint8_t)RGBLED_NUM / 2); }
    584 
    585 void rgblight_sethsv_slave(uint8_t hue, uint8_t sat, uint8_t val) { rgblight_sethsv_range(hue, sat, val, (uint8_t)RGBLED_NUM / 2, (uint8_t)RGBLED_NUM); }
    586 #endif  // ifndef RGBLIGHT_SPLIT
    587 
    588 #ifndef RGBLIGHT_CUSTOM_DRIVER
    589 void rgblight_set(void) {
    590     LED_TYPE *start_led;
    591     uint16_t  num_leds = clipping_num_leds;
    592 
    593     if (!rgblight_config.enable) {
    594         for (uint8_t i = effect_start_pos; i < effect_end_pos; i++) {
    595             led[i].r = 0;
    596             led[i].g = 0;
    597             led[i].b = 0;
    598         }
    599     }
    600 #    ifdef RGBLIGHT_LED_MAP
    601     LED_TYPE led0[RGBLED_NUM];
    602     for (uint8_t i = 0; i < RGBLED_NUM; i++) {
    603         led0[i] = led[pgm_read_byte(&led_map[i])];
    604     }
    605     start_led = led0 + clipping_start_pos;
    606 #    else
    607     start_led = led + clipping_start_pos;
    608 #    endif
    609 #    ifdef RGBW
    610     ws2812_setleds_rgbw(start_led, num_leds);
    611 #    else
    612     ws2812_setleds(start_led, num_leds);
    613 #    endif
    614 }
    615 #endif
    616 
    617 #ifdef RGBLIGHT_SPLIT
    618 /* for split keyboard master side */
    619 uint8_t rgblight_get_change_flags(void) { return rgblight_status.change_flags; }
    620 
    621 void rgblight_clear_change_flags(void) { rgblight_status.change_flags = 0; }
    622 
    623 void rgblight_get_syncinfo(rgblight_syncinfo_t *syncinfo) {
    624     syncinfo->config = rgblight_config;
    625     syncinfo->status = rgblight_status;
    626 }
    627 
    628 /* for split keyboard slave side */
    629 void rgblight_update_sync(rgblight_syncinfo_t *syncinfo, bool write_to_eeprom) {
    630     if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_MODE) {
    631         if (syncinfo->config.enable) {
    632             rgblight_config.enable = 1;  // == rgblight_enable_noeeprom();
    633             rgblight_mode_eeprom_helper(syncinfo->config.mode, write_to_eeprom);
    634         } else {
    635             rgblight_disable_noeeprom();
    636         }
    637     }
    638     if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_HSVS) {
    639         rgblight_sethsv_eeprom_helper(syncinfo->config.hue, syncinfo->config.sat, syncinfo->config.val, write_to_eeprom);
    640         // rgblight_config.speed = config->speed; // NEED???
    641     }
    642 #    ifdef RGBLIGHT_USE_TIMER
    643     if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_TIMER) {
    644         if (syncinfo->status.timer_enabled) {
    645             rgblight_timer_enable();
    646         } else {
    647             rgblight_timer_disable();
    648         }
    649     }
    650 #        ifndef RGBLIGHT_SPLIT_NO_ANIMATION_SYNC
    651     if (syncinfo->status.change_flags & RGBLIGHT_STATUS_ANIMATION_TICK) {
    652         animation_status.restart = true;
    653     }
    654 #        endif /* RGBLIGHT_SPLIT_NO_ANIMATION_SYNC */
    655 #    endif     /* RGBLIGHT_USE_TIMER */
    656 }
    657 #endif /* RGBLIGHT_SPLIT */
    658 
    659 #ifdef RGBLIGHT_USE_TIMER
    660 
    661 typedef void (*effect_func_t)(animation_status_t *anim);
    662 
    663 // Animation timer -- use system timer (AVR Timer0)
    664 void rgblight_timer_init(void) {
    665     // OLD!!!! Animation timer -- AVR Timer3
    666     // static uint8_t rgblight_timer_is_init = 0;
    667     // if (rgblight_timer_is_init) {
    668     //   return;
    669     // }
    670     // rgblight_timer_is_init = 1;
    671     // /* Timer 3 setup */
    672     // TCCR3B = _BV(WGM32) // CTC mode OCR3A as TOP
    673     //       | _BV(CS30); // Clock selelct: clk/1
    674     // /* Set TOP value */
    675     // uint8_t sreg = SREG;
    676     // cli();
    677     // OCR3AH = (RGBLED_TIMER_TOP >> 8) & 0xff;
    678     // OCR3AL = RGBLED_TIMER_TOP & 0xff;
    679     // SREG = sreg;
    680 
    681     rgblight_status.timer_enabled = false;
    682     RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE;
    683 }
    684 void rgblight_timer_enable(void) {
    685     if (!is_static_effect(rgblight_config.mode)) {
    686         rgblight_status.timer_enabled = true;
    687     }
    688     animation_status.last_timer = timer_read();
    689     RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE;
    690     dprintf("rgblight timer enabled.\n");
    691 }
    692 void rgblight_timer_disable(void) {
    693     rgblight_status.timer_enabled = false;
    694     RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE;
    695     dprintf("rgblight timer disable.\n");
    696 }
    697 void rgblight_timer_toggle(void) {
    698     dprintf("rgblight timer toggle.\n");
    699     if (rgblight_status.timer_enabled) {
    700         rgblight_timer_disable();
    701     } else {
    702         rgblight_timer_enable();
    703     }
    704 }
    705 
    706 void rgblight_show_solid_color(uint8_t r, uint8_t g, uint8_t b) {
    707     rgblight_enable();
    708     rgblight_mode(RGBLIGHT_MODE_STATIC_LIGHT);
    709     rgblight_setrgb(r, g, b);
    710 }
    711 
    712 static void rgblight_effect_dummy(animation_status_t *anim) {
    713     // do nothing
    714     /********
    715     dprintf("rgblight_task() what happened?\n");
    716     dprintf("is_static_effect %d\n", is_static_effect(rgblight_config.mode));
    717     dprintf("mode = %d, base_mode = %d, timer_enabled %d, ",
    718             rgblight_config.mode, rgblight_status.base_mode,
    719             rgblight_status.timer_enabled);
    720     dprintf("last_timer = %d\n",anim->last_timer);
    721     **/
    722 }
    723 
    724 void rgblight_task(void) {
    725     if (rgblight_status.timer_enabled) {
    726         effect_func_t effect_func   = rgblight_effect_dummy;
    727         uint16_t      interval_time = 2000;  // dummy interval
    728         uint8_t       delta         = rgblight_config.mode - rgblight_status.base_mode;
    729         animation_status.delta      = delta;
    730 
    731         // static light mode, do nothing here
    732         if (1 == 0) {  // dummy
    733         }
    734 #    ifdef RGBLIGHT_EFFECT_BREATHING
    735         else if (rgblight_status.base_mode == RGBLIGHT_MODE_BREATHING) {
    736             // breathing mode
    737             interval_time = get_interval_time(&RGBLED_BREATHING_INTERVALS[delta], 1, 100);
    738             effect_func   = rgblight_effect_breathing;
    739         }
    740 #    endif
    741 #    ifdef RGBLIGHT_EFFECT_RAINBOW_MOOD
    742         else if (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_MOOD) {
    743             // rainbow mood mode
    744             interval_time = get_interval_time(&RGBLED_RAINBOW_MOOD_INTERVALS[delta], 5, 100);
    745             effect_func   = rgblight_effect_rainbow_mood;
    746         }
    747 #    endif
    748 #    ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL
    749         else if (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_SWIRL) {
    750             // rainbow swirl mode
    751             interval_time = get_interval_time(&RGBLED_RAINBOW_SWIRL_INTERVALS[delta / 2], 1, 100);
    752             effect_func   = rgblight_effect_rainbow_swirl;
    753         }
    754 #    endif
    755 #    ifdef RGBLIGHT_EFFECT_SNAKE
    756         else if (rgblight_status.base_mode == RGBLIGHT_MODE_SNAKE) {
    757             // snake mode
    758             interval_time = get_interval_time(&RGBLED_SNAKE_INTERVALS[delta / 2], 1, 200);
    759             effect_func   = rgblight_effect_snake;
    760         }
    761 #    endif
    762 #    ifdef RGBLIGHT_EFFECT_KNIGHT
    763         else if (rgblight_status.base_mode == RGBLIGHT_MODE_KNIGHT) {
    764             // knight mode
    765             interval_time = get_interval_time(&RGBLED_KNIGHT_INTERVALS[delta], 5, 100);
    766             effect_func   = rgblight_effect_knight;
    767         }
    768 #    endif
    769 #    ifdef RGBLIGHT_EFFECT_CHRISTMAS
    770         else if (rgblight_status.base_mode == RGBLIGHT_MODE_CHRISTMAS) {
    771             // christmas mode
    772             interval_time = RGBLIGHT_EFFECT_CHRISTMAS_INTERVAL;
    773             effect_func   = (effect_func_t)rgblight_effect_christmas;
    774         }
    775 #    endif
    776 #    ifdef RGBLIGHT_EFFECT_RGB_TEST
    777         else if (rgblight_status.base_mode == RGBLIGHT_MODE_RGB_TEST) {
    778             // RGB test mode
    779             interval_time = pgm_read_word(&RGBLED_RGBTEST_INTERVALS[0]);
    780             effect_func   = (effect_func_t)rgblight_effect_rgbtest;
    781         }
    782 #    endif
    783 #    ifdef RGBLIGHT_EFFECT_ALTERNATING
    784         else if (rgblight_status.base_mode == RGBLIGHT_MODE_ALTERNATING) {
    785             interval_time = 500;
    786             effect_func   = (effect_func_t)rgblight_effect_alternating;
    787         }
    788 #    endif
    789         if (animation_status.restart) {
    790             animation_status.restart    = false;
    791             animation_status.last_timer = timer_read() - interval_time - 1;
    792             animation_status.pos16      = 0;  // restart signal to local each effect
    793         }
    794         if (timer_elapsed(animation_status.last_timer) >= interval_time) {
    795 #    if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
    796             static uint16_t report_last_timer = 0;
    797             static bool     tick_flag         = false;
    798             uint16_t        oldpos16;
    799             if (tick_flag) {
    800                 tick_flag = false;
    801                 if (timer_elapsed(report_last_timer) >= 30000) {
    802                     report_last_timer = timer_read();
    803                     dprintf("rgblight animation tick report to slave\n");
    804                     RGBLIGHT_SPLIT_ANIMATION_TICK;
    805                 }
    806             }
    807             oldpos16 = animation_status.pos16;
    808 #    endif
    809             animation_status.last_timer += interval_time;
    810             effect_func(&animation_status);
    811 #    if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
    812             if (animation_status.pos16 == 0 && oldpos16 != 0) {
    813                 tick_flag = true;
    814             }
    815 #    endif
    816         }
    817     }
    818 }
    819 
    820 #endif /* RGBLIGHT_USE_TIMER */
    821 
    822 // Effects
    823 #ifdef RGBLIGHT_EFFECT_BREATHING
    824 
    825 #    ifndef RGBLIGHT_EFFECT_BREATHE_CENTER
    826 #        ifndef RGBLIGHT_BREATHE_TABLE_SIZE
    827 #            define RGBLIGHT_BREATHE_TABLE_SIZE 256  // 256 or 128 or 64
    828 #        endif
    829 #        include <rgblight_breathe_table.h>
    830 #    endif
    831 
    832 __attribute__((weak)) const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5};
    833 
    834 void rgblight_effect_breathing(animation_status_t *anim) {
    835     float val;
    836 
    837     // http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/
    838 #    ifdef RGBLIGHT_EFFECT_BREATHE_TABLE
    839     val = pgm_read_byte(&rgblight_effect_breathe_table[anim->pos / table_scale]);
    840 #    else
    841     val = (exp(sin((anim->pos / 255.0) * M_PI)) - RGBLIGHT_EFFECT_BREATHE_CENTER / M_E) * (RGBLIGHT_EFFECT_BREATHE_MAX / (M_E - 1 / M_E));
    842 #    endif
    843     rgblight_sethsv_noeeprom_old(rgblight_config.hue, rgblight_config.sat, val);
    844     anim->pos = (anim->pos + 1);
    845 }
    846 #endif
    847 
    848 #ifdef RGBLIGHT_EFFECT_RAINBOW_MOOD
    849 __attribute__((weak)) const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[] PROGMEM = {120, 60, 30};
    850 
    851 void rgblight_effect_rainbow_mood(animation_status_t *anim) {
    852     rgblight_sethsv_noeeprom_old(anim->current_hue, rgblight_config.sat, rgblight_config.val);
    853     anim->current_hue++;
    854 }
    855 #endif
    856 
    857 #ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL
    858 #    ifndef RGBLIGHT_RAINBOW_SWIRL_RANGE
    859 #        define RGBLIGHT_RAINBOW_SWIRL_RANGE 255
    860 #    endif
    861 
    862 __attribute__((weak)) const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[] PROGMEM = {100, 50, 20};
    863 
    864 void rgblight_effect_rainbow_swirl(animation_status_t *anim) {
    865     uint8_t hue;
    866     uint8_t i;
    867 
    868     for (i = 0; i < effect_num_leds; i++) {
    869         hue = (RGBLIGHT_RAINBOW_SWIRL_RANGE / effect_num_leds * i + anim->current_hue);
    870         sethsv(hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[i + effect_start_pos]);
    871     }
    872     rgblight_set();
    873 
    874     if (anim->delta % 2) {
    875         anim->current_hue++;
    876     } else {
    877         anim->current_hue--;
    878     }
    879 }
    880 #endif
    881 
    882 #ifdef RGBLIGHT_EFFECT_SNAKE
    883 __attribute__((weak)) const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {100, 50, 20};
    884 
    885 void rgblight_effect_snake(animation_status_t *anim) {
    886     static uint8_t pos = 0;
    887     uint8_t        i, j;
    888     int8_t         k;
    889     int8_t         increment = 1;
    890 
    891     if (anim->delta % 2) {
    892         increment = -1;
    893     }
    894 
    895 #    if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
    896     if (anim->pos == 0) {  // restart signal
    897         if (increment == 1) {
    898             pos = effect_num_leds - 1;
    899         } else {
    900             pos = 0;
    901         }
    902         anim->pos = 1;
    903     }
    904 #    endif
    905 
    906     for (i = 0; i < effect_num_leds; i++) {
    907         LED_TYPE *ledp = led + i + effect_start_pos;
    908         ledp->r        = 0;
    909         ledp->g        = 0;
    910         ledp->b        = 0;
    911         for (j = 0; j < RGBLIGHT_EFFECT_SNAKE_LENGTH; j++) {
    912             k = pos + j * increment;
    913             if (k < 0) {
    914                 k = k + effect_num_leds;
    915             }
    916             if (i == k) {
    917                 sethsv(rgblight_config.hue, rgblight_config.sat, (uint8_t)(rgblight_config.val * (RGBLIGHT_EFFECT_SNAKE_LENGTH - j) / RGBLIGHT_EFFECT_SNAKE_LENGTH), ledp);
    918             }
    919         }
    920     }
    921     rgblight_set();
    922     if (increment == 1) {
    923         if (pos - 1 < 0) {
    924             pos = effect_num_leds - 1;
    925 #    if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
    926             anim->pos = 0;
    927 #    endif
    928         } else {
    929             pos -= 1;
    930 #    if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
    931             anim->pos = 1;
    932 #    endif
    933         }
    934     } else {
    935         pos = (pos + 1) % effect_num_leds;
    936 #    if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
    937         anim->pos = pos;
    938 #    endif
    939     }
    940 }
    941 #endif
    942 
    943 #ifdef RGBLIGHT_EFFECT_KNIGHT
    944 __attribute__((weak)) const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {127, 63, 31};
    945 
    946 void rgblight_effect_knight(animation_status_t *anim) {
    947     static int8_t low_bound  = 0;
    948     static int8_t high_bound = RGBLIGHT_EFFECT_KNIGHT_LENGTH - 1;
    949     static int8_t increment  = 1;
    950     uint8_t       i, cur;
    951 
    952 #    if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
    953     if (anim->pos == 0) {  // restart signal
    954         anim->pos  = 1;
    955         low_bound  = 0;
    956         high_bound = RGBLIGHT_EFFECT_KNIGHT_LENGTH - 1;
    957         increment  = 1;
    958     }
    959 #    endif
    960     // Set all the LEDs to 0
    961     for (i = effect_start_pos; i < effect_end_pos; i++) {
    962         led[i].r = 0;
    963         led[i].g = 0;
    964         led[i].b = 0;
    965     }
    966     // Determine which LEDs should be lit up
    967     for (i = 0; i < RGBLIGHT_EFFECT_KNIGHT_LED_NUM; i++) {
    968         cur = (i + RGBLIGHT_EFFECT_KNIGHT_OFFSET) % effect_num_leds + effect_start_pos;
    969 
    970         if (i >= low_bound && i <= high_bound) {
    971             sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[cur]);
    972         } else {
    973             led[cur].r = 0;
    974             led[cur].g = 0;
    975             led[cur].b = 0;
    976         }
    977     }
    978     rgblight_set();
    979 
    980     // Move from low_bound to high_bound changing the direction we increment each
    981     // time a boundary is hit.
    982     low_bound += increment;
    983     high_bound += increment;
    984 
    985     if (high_bound <= 0 || low_bound >= RGBLIGHT_EFFECT_KNIGHT_LED_NUM - 1) {
    986         increment = -increment;
    987 #    if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
    988         if (increment == 1) {
    989             anim->pos = 0;
    990         }
    991 #    endif
    992     }
    993 }
    994 #endif
    995 
    996 #ifdef RGBLIGHT_EFFECT_CHRISTMAS
    997 void rgblight_effect_christmas(animation_status_t *anim) {
    998     uint8_t hue;
    999     uint8_t i;
   1000 
   1001     anim->current_offset = (anim->current_offset + 1) % 2;
   1002     for (i = 0; i < effect_num_leds; i++) {
   1003         hue = 0 + ((i / RGBLIGHT_EFFECT_CHRISTMAS_STEP + anim->current_offset) % 2) * 85;
   1004         sethsv(hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[i + effect_start_pos]);
   1005     }
   1006     rgblight_set();
   1007 }
   1008 #endif
   1009 
   1010 #ifdef RGBLIGHT_EFFECT_RGB_TEST
   1011 __attribute__((weak)) const uint16_t RGBLED_RGBTEST_INTERVALS[] PROGMEM = {1024};
   1012 
   1013 void rgblight_effect_rgbtest(animation_status_t *anim) {
   1014     static uint8_t maxval = 0;
   1015     uint8_t        g;
   1016     uint8_t        r;
   1017     uint8_t        b;
   1018 
   1019     if (maxval == 0) {
   1020         LED_TYPE tmp_led;
   1021         sethsv(0, 255, RGBLIGHT_LIMIT_VAL, &tmp_led);
   1022         maxval = tmp_led.r;
   1023     }
   1024     g = r = b = 0;
   1025     switch (anim->pos) {
   1026         case 0:
   1027             r = maxval;
   1028             break;
   1029         case 1:
   1030             g = maxval;
   1031             break;
   1032         case 2:
   1033             b = maxval;
   1034             break;
   1035     }
   1036     rgblight_setrgb(r, g, b);
   1037     anim->pos = (anim->pos + 1) % 3;
   1038 }
   1039 #endif
   1040 
   1041 #ifdef RGBLIGHT_EFFECT_ALTERNATING
   1042 void rgblight_effect_alternating(animation_status_t *anim) {
   1043     for (int i = 0; i < effect_num_leds; i++) {
   1044         LED_TYPE *ledp = led + i + effect_start_pos;
   1045         if (i < effect_num_leds / 2 && anim->pos) {
   1046             sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, ledp);
   1047         } else if (i >= effect_num_leds / 2 && !anim->pos) {
   1048             sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, ledp);
   1049         } else {
   1050             sethsv(rgblight_config.hue, rgblight_config.sat, 0, ledp);
   1051         }
   1052     }
   1053     rgblight_set();
   1054     anim->pos = (anim->pos + 1) % 2;
   1055 }
   1056 #endif