X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=quantum%2Frgblight.c;h=75e4ef0d8696e1ec6d074a9a82a4e4f155612569;hb=2121de919253b52e94e66e3eae6af01c3f56f463;hp=b1b0f035d58d48bc53035db4655c04963d385b48;hpb=68ceffe53e299fb504bdd4733b1555a8558b472b;p=qmk_firmware.git diff --git a/quantum/rgblight.c b/quantum/rgblight.c index b1b0f035d..75e4ef0d8 100644 --- a/quantum/rgblight.c +++ b/quantum/rgblight.c @@ -1,520 +1,1131 @@ -#include -#include -#include +/* Copyright 2016-2017 Yang Liu + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#ifdef __AVR__ + #include + #include +#endif +#ifdef STM32_EEPROM_ENABLE + #include "hal.h" + #include "eeprom.h" + #include "eeprom_stm32.h" +#endif +#include "wait.h" #include "progmem.h" #include "timer.h" #include "rgblight.h" +#include "color.h" #include "debug.h" +#include "led_tables.h" +#include "lib/lib8tion/lib8tion.h" +#ifdef VELOCIKEY_ENABLE + #include "velocikey.h" +#endif -const uint8_t DIM_CURVE[] PROGMEM = { - 0, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, - 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, - 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, - 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, - 15, 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 20, - 20, 20, 21, 21, 22, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26, 26, - 27, 27, 28, 28, 29, 29, 30, 30, 31, 32, 32, 33, 33, 34, 35, 35, - 36, 36, 37, 38, 38, 39, 40, 40, 41, 42, 43, 43, 44, 45, 46, 47, - 48, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, - 63, 64, 65, 66, 68, 69, 70, 71, 73, 74, 75, 76, 78, 79, 81, 82, - 83, 85, 86, 88, 90, 91, 93, 94, 96, 98, 99, 101, 103, 105, 107, 109, - 110, 112, 114, 116, 118, 121, 123, 125, 127, 129, 132, 134, 136, 139, 141, 144, - 146, 149, 151, 154, 157, 159, 162, 165, 168, 171, 174, 177, 180, 183, 186, 190, - 193, 196, 200, 203, 207, 211, 214, 218, 222, 226, 230, 234, 238, 242, 248, 255, +#ifdef RGBLIGHT_SPLIT + /* for split keyboard */ + #define RGBLIGHT_SPLIT_SET_CHANGE_MODE rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_MODE + #define RGBLIGHT_SPLIT_SET_CHANGE_HSVS rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_HSVS + #define RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS rgblight_status.change_flags |= (RGBLIGHT_STATUS_CHANGE_MODE|RGBLIGHT_STATUS_CHANGE_HSVS) + #define RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_TIMER + #define RGBLIGHT_SPLIT_ANIMATION_TICK rgblight_status.change_flags |= RGBLIGHT_STATUS_ANIMATION_TICK +#else + #define RGBLIGHT_SPLIT_SET_CHANGE_MODE + #define RGBLIGHT_SPLIT_SET_CHANGE_HSVS + #define RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS + #define RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE + #define RGBLIGHT_SPLIT_ANIMATION_TICK +#endif + +#define _RGBM_SINGLE_STATIC(sym) RGBLIGHT_MODE_ ## sym, +#define _RGBM_SINGLE_DYNAMIC(sym) +#define _RGBM_MULTI_STATIC(sym) RGBLIGHT_MODE_ ## sym, +#define _RGBM_MULTI_DYNAMIC(sym) +#define _RGBM_TMP_STATIC(sym, msym) RGBLIGHT_MODE_ ## sym, +#define _RGBM_TMP_DYNAMIC(sym, msym) +static uint8_t static_effect_table [] = { +#include "rgblight_modes.h" }; -const uint8_t RGBLED_BREATHING_TABLE[] PROGMEM = {0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,17,18,20,21,23,25,27,29,31,33,35,37,40,42,44,47,49,52,54,57,59,62,65,67,70,73,76,79,82,85,88,90,93,97,100,103,106,109,112,115,118,121,124,127,131,134,137,140,143,146,149,152,155,158,162,165,167,170,173,176,179,182,185,188,190,193,196,198,201,203,206,208,211,213,215,218,220,222,224,226,228,230,232,234,235,237,238,240,241,243,244,245,246,248,249,250,250,251,252,253,253,254,254,254,255,255,255,255,255,255,255,254,254,254,253,253,252,251,250,250,249,248,246,245,244,243,241,240,238,237,235,234,232,230,228,226,224,222,220,218,215,213,211,208,206,203,201,198,196,193,190,188,185,182,179,176,173,170,167,165,162,158,155,152,149,146,143,140,137,134,131,128,124,121,118,115,112,109,106,103,100,97,93,90,88,85,82,79,76,73,70,67,65,62,59,57,54,52,49,47,44,42,40,37,35,33,31,29,27,25,23,21,20,18,17,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0}; -const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5}; -const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[] PROGMEM = {120, 60, 30}; -const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[] PROGMEM = {100, 50, 20}; -const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {100, 50, 20}; -const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {100, 50, 20}; + +#define _RGBM_SINGLE_STATIC(sym) RGBLIGHT_MODE_ ## sym, +#define _RGBM_SINGLE_DYNAMIC(sym) RGBLIGHT_MODE_ ## sym, +#define _RGBM_MULTI_STATIC(sym) RGBLIGHT_MODE_ ## sym, +#define _RGBM_MULTI_DYNAMIC(sym) RGBLIGHT_MODE_ ## sym, +#define _RGBM_TMP_STATIC(sym, msym) RGBLIGHT_MODE_ ## msym, +#define _RGBM_TMP_DYNAMIC(sym, msym) RGBLIGHT_MODE_ ## msym, +static uint8_t mode_base_table [] = { + 0, // RGBLIGHT_MODE_zero +#include "rgblight_modes.h" +}; + +static inline int is_static_effect(uint8_t mode) { + return memchr(static_effect_table, mode, sizeof(static_effect_table)) != NULL; +} + +#ifdef RGBLIGHT_LED_MAP +const uint8_t led_map[] PROGMEM = RGBLIGHT_LED_MAP; +#endif + +#ifdef RGBLIGHT_EFFECT_STATIC_GRADIENT +__attribute__ ((weak)) +const uint8_t RGBLED_GRADIENT_RANGES[] PROGMEM = {255, 170, 127, 85, 64}; +#endif rgblight_config_t rgblight_config; -rgblight_config_t inmem_config; -struct cRGB led[RGBLED_NUM]; -uint8_t rgblight_inited = 0; - - -void sethsv(uint16_t hue, uint8_t sat, uint8_t val, struct cRGB *led1) { - /* convert hue, saturation and brightness ( HSB/HSV ) to RGB - The DIM_CURVE is used only on brightness/value and on saturation (inverted). - This looks the most natural. - */ - uint8_t r = 0, g = 0, b = 0; - - val = pgm_read_byte(&DIM_CURVE[val]); - sat = 255 - pgm_read_byte(&DIM_CURVE[255 - sat]); - - uint8_t base; - - if (sat == 0) { // Acromatic color (gray). Hue doesn't mind. - r = val; - g = val; - b = val; - } else { - base = ((255 - sat) * val) >> 8; - - switch (hue / 60) { - case 0: - r = val; - g = (((val - base)*hue) / 60) + base; - b = base; - break; - - case 1: - r = (((val - base)*(60 - (hue % 60))) / 60) + base; - g = val; - b = base; - break; - - case 2: - r = base; - g = val; - b = (((val - base)*(hue % 60)) / 60) + base; - break; - - case 3: - r = base; - g = (((val - base)*(60 - (hue % 60))) / 60) + base; - b = val; - break; - - case 4: - r = (((val - base)*(hue % 60)) / 60) + base; - g = base; - b = val; - break; - - case 5: - r = val; - g = base; - b = (((val - base)*(60 - (hue % 60))) / 60) + base; - break; - } - } - setrgb(r,g,b, led1); -} - -void setrgb(uint8_t r, uint8_t g, uint8_t b, struct cRGB *led1) { +rgblight_status_t rgblight_status = { .timer_enabled = false }; +bool is_rgblight_initialized = false; + +#ifdef RGBLIGHT_USE_TIMER +animation_status_t animation_status = {}; +#endif + +#ifndef LED_ARRAY +LED_TYPE led[RGBLED_NUM]; + #define LED_ARRAY led +#endif + + +static uint8_t clipping_start_pos = 0; +static uint8_t clipping_num_leds = RGBLED_NUM; +static uint8_t effect_start_pos = 0; +static uint8_t effect_end_pos = RGBLED_NUM; +static uint8_t effect_num_leds = RGBLED_NUM; + +void rgblight_set_clipping_range(uint8_t start_pos, uint8_t num_leds) { + clipping_start_pos = start_pos; + clipping_num_leds = num_leds; +} + +void rgblight_set_effect_range(uint8_t start_pos, uint8_t num_leds) { + if (start_pos >= RGBLED_NUM) return; + if (start_pos + num_leds > RGBLED_NUM) return; + effect_start_pos = start_pos; + effect_end_pos = start_pos + num_leds; + effect_num_leds = num_leds; +} + +void sethsv_raw(uint8_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1) { + HSV hsv = { hue, sat, val }; + RGB rgb = hsv_to_rgb(hsv); + setrgb(rgb.r, rgb.g, rgb.b, led1); +} + +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); +} + +void setrgb(uint8_t r, uint8_t g, uint8_t b, LED_TYPE *led1) { (*led1).r = r; (*led1).g = g; (*led1).b = b; } +void rgblight_check_config(void) { + /* Add some out of bound checks for RGB light config */ + + if (rgblight_config.mode < RGBLIGHT_MODE_STATIC_LIGHT) { + rgblight_config.mode = RGBLIGHT_MODE_STATIC_LIGHT; + } + else if (rgblight_config.mode > RGBLIGHT_MODES) { + rgblight_config.mode = RGBLIGHT_MODES; + } + + if (rgblight_config.val > RGBLIGHT_LIMIT_VAL) { + rgblight_config.val = RGBLIGHT_LIMIT_VAL; + } +} uint32_t eeconfig_read_rgblight(void) { - return eeprom_read_dword(EECONFIG_RGBLIGHT); + #if defined(__AVR__) || defined(STM32_EEPROM_ENABLE) || defined(PROTOCOL_ARM_ATSAM) || defined(EEPROM_SIZE) + return eeprom_read_dword(EECONFIG_RGBLIGHT); + #else + return 0; + #endif } + void eeconfig_update_rgblight(uint32_t val) { - eeprom_update_dword(EECONFIG_RGBLIGHT, val); + #if defined(__AVR__) || defined(STM32_EEPROM_ENABLE) || defined(PROTOCOL_ARM_ATSAM) || defined(EEPROM_SIZE) + rgblight_check_config(); + eeprom_update_dword(EECONFIG_RGBLIGHT, val); + #endif } + void eeconfig_update_rgblight_default(void) { - dprintf("eeconfig_update_rgblight_default\n"); - rgblight_config.enable = 1; - rgblight_config.mode = 1; - rgblight_config.hue = 200; - rgblight_config.sat = 204; - rgblight_config.val = 204; - eeconfig_update_rgblight(rgblight_config.raw); + //dprintf("eeconfig_update_rgblight_default\n"); + rgblight_config.enable = 1; + rgblight_config.mode = RGBLIGHT_MODE_STATIC_LIGHT; + rgblight_config.hue = 0; + rgblight_config.sat = UINT8_MAX; + rgblight_config.val = RGBLIGHT_LIMIT_VAL; + rgblight_config.speed = 0; + RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS; + eeconfig_update_rgblight(rgblight_config.raw); } + void eeconfig_debug_rgblight(void) { - dprintf("rgblight_config eprom\n"); - dprintf("rgblight_config.enable = %d\n", rgblight_config.enable); - dprintf("rghlight_config.mode = %d\n", rgblight_config.mode); - dprintf("rgblight_config.hue = %d\n", rgblight_config.hue); - dprintf("rgblight_config.sat = %d\n", rgblight_config.sat); - dprintf("rgblight_config.val = %d\n", rgblight_config.val); + dprintf("rgblight_config eprom\n"); + dprintf("rgblight_config.enable = %d\n", rgblight_config.enable); + dprintf("rghlight_config.mode = %d\n", rgblight_config.mode); + dprintf("rgblight_config.hue = %d\n", rgblight_config.hue); + dprintf("rgblight_config.sat = %d\n", rgblight_config.sat); + dprintf("rgblight_config.val = %d\n", rgblight_config.val); + dprintf("rgblight_config.speed = %d\n", rgblight_config.speed); } void rgblight_init(void) { + /* if already initialized, don't do it again. + If you must do it again, extern this and set to false, first. + This is a dirty, dirty hack until proper hooks can be added for keyboard startup. */ + if (is_rgblight_initialized) { return; } + debug_enable = 1; // Debug ON! - dprintf("rgblight_init called.\n"); - rgblight_inited = 1; - dprintf("rgblight_init start!\n"); + dprintf("rgblight_init called.\n"); + dprintf("rgblight_init start!\n"); if (!eeconfig_is_enabled()) { - dprintf("rgblight_init eeconfig is not enabled.\n"); + dprintf("rgblight_init eeconfig is not enabled.\n"); eeconfig_init(); - eeconfig_update_rgblight_default(); + eeconfig_update_rgblight_default(); } rgblight_config.raw = eeconfig_read_rgblight(); - if (!rgblight_config.mode) { - dprintf("rgblight_init rgblight_config.mode = 0. Write default values to EEPROM.\n"); - eeconfig_update_rgblight_default(); - rgblight_config.raw = eeconfig_read_rgblight(); - } - eeconfig_debug_rgblight(); // display current eeprom values + RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS; + if (!rgblight_config.mode) { + dprintf("rgblight_init rgblight_config.mode = 0. Write default values to EEPROM.\n"); + eeconfig_update_rgblight_default(); + rgblight_config.raw = eeconfig_read_rgblight(); + } + rgblight_check_config(); + + eeconfig_debug_rgblight(); // display current eeprom values - #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER) - rgblight_timer_init(); // setup the timer - #endif +#ifdef RGBLIGHT_USE_TIMER + rgblight_timer_init(); // setup the timer +#endif if (rgblight_config.enable) { - rgblight_mode(rgblight_config.mode); + rgblight_mode_noeeprom(rgblight_config.mode); + } + + is_rgblight_initialized = true; + +} + +uint32_t rgblight_read_dword(void) { + return rgblight_config.raw; +} + +void rgblight_update_dword(uint32_t dword) { + RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS; + rgblight_config.raw = dword; + if (rgblight_config.enable) + rgblight_mode_noeeprom(rgblight_config.mode); + else { +#ifdef RGBLIGHT_USE_TIMER + rgblight_timer_disable(); +#endif + rgblight_set(); } } void rgblight_increase(void) { - uint8_t mode = 0; + uint8_t mode = 0; if (rgblight_config.mode < RGBLIGHT_MODES) { mode = rgblight_config.mode + 1; } - rgblight_mode(mode); + rgblight_mode(mode); } - void rgblight_decrease(void) { - uint8_t mode = 0; - if (rgblight_config.mode > 1) { //mode will never < 1, if mode is less than 1, eeprom need to be initialized. - mode = rgblight_config.mode-1; + uint8_t mode = 0; + // Mode will never be < 1. If it ever is, eeprom needs to be initialized. + if (rgblight_config.mode > RGBLIGHT_MODE_STATIC_LIGHT) { + mode = rgblight_config.mode - 1; } - rgblight_mode(mode); + rgblight_mode(mode); } - -void rgblight_step(void) { - uint8_t mode = 0; +void rgblight_step_helper(bool write_to_eeprom) { + uint8_t mode = 0; mode = rgblight_config.mode + 1; if (mode > RGBLIGHT_MODES) { mode = 1; } - rgblight_mode(mode); + rgblight_mode_eeprom_helper(mode, write_to_eeprom); +} +void rgblight_step_noeeprom(void) { + rgblight_step_helper(false); +} +void rgblight_step(void) { + rgblight_step_helper(true); +} +void rgblight_step_reverse_helper(bool write_to_eeprom) { + uint8_t mode = 0; + mode = rgblight_config.mode - 1; + if (mode < 1) { + mode = RGBLIGHT_MODES; + } + rgblight_mode_eeprom_helper(mode, write_to_eeprom); +} +void rgblight_step_reverse_noeeprom(void) { + rgblight_step_reverse_helper(false); +} +void rgblight_step_reverse(void) { + rgblight_step_reverse_helper(true); +} + +uint8_t rgblight_get_mode(void) { + if (!rgblight_config.enable) { + return false; + } + + return rgblight_config.mode; +} + +void rgblight_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom) { + if (!rgblight_config.enable) { + return; + } + if (mode < RGBLIGHT_MODE_STATIC_LIGHT) { + rgblight_config.mode = RGBLIGHT_MODE_STATIC_LIGHT; + } else if (mode > RGBLIGHT_MODES) { + rgblight_config.mode = RGBLIGHT_MODES; + } else { + rgblight_config.mode = mode; + } + RGBLIGHT_SPLIT_SET_CHANGE_MODE; + if (write_to_eeprom) { + eeconfig_update_rgblight(rgblight_config.raw); + xprintf("rgblight mode [EEPROM]: %u\n", rgblight_config.mode); + } else { + xprintf("rgblight mode [NOEEPROM]: %u\n", rgblight_config.mode); + } + if( is_static_effect(rgblight_config.mode) ) { +#ifdef RGBLIGHT_USE_TIMER + rgblight_timer_disable(); +#endif + } else { +#ifdef RGBLIGHT_USE_TIMER + rgblight_timer_enable(); +#endif + } +#ifdef RGBLIGHT_USE_TIMER + animation_status.restart = true; +#endif + rgblight_sethsv_noeeprom(rgblight_config.hue, rgblight_config.sat, rgblight_config.val); } void rgblight_mode(uint8_t mode) { - if (!rgblight_config.enable) { - return; - } - if (mode<1) { - rgblight_config.mode = 1; - } else if (mode > RGBLIGHT_MODES) { - rgblight_config.mode = RGBLIGHT_MODES; - } else { - rgblight_config.mode = mode; - } - eeconfig_update_rgblight(rgblight_config.raw); - xprintf("rgblight mode: %u\n", rgblight_config.mode); - if (rgblight_config.mode == 1) { - #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER) - rgblight_timer_disable(); - #endif - } else if (rgblight_config.mode >=2 && rgblight_config.mode <=23) { - // MODE 2-5, breathing - // MODE 6-8, rainbow mood - // MODE 9-14, rainbow swirl - // MODE 15-20, snake - // MODE 21-23, knight - - #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER) - rgblight_timer_enable(); - #endif - } - rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val); + rgblight_mode_eeprom_helper(mode, true); +} + +void rgblight_mode_noeeprom(uint8_t mode) { + rgblight_mode_eeprom_helper(mode, false); } + void rgblight_toggle(void) { - rgblight_config.enable ^= 1; + xprintf("rgblight toggle [EEPROM]: rgblight_config.enable = %u\n", !rgblight_config.enable); + if (rgblight_config.enable) { + rgblight_disable(); + } + else { + rgblight_enable(); + } +} + +void rgblight_toggle_noeeprom(void) { + xprintf("rgblight toggle [NOEEPROM]: rgblight_config.enable = %u\n", !rgblight_config.enable); + if (rgblight_config.enable) { + rgblight_disable_noeeprom(); + } + else { + rgblight_enable_noeeprom(); + } +} + +void rgblight_enable(void) { + rgblight_config.enable = 1; + // No need to update EEPROM here. rgblight_mode() will do that, actually + //eeconfig_update_rgblight(rgblight_config.raw); + xprintf("rgblight enable [EEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable); + rgblight_mode(rgblight_config.mode); +} + +void rgblight_enable_noeeprom(void) { + rgblight_config.enable = 1; + xprintf("rgblight enable [NOEEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable); + rgblight_mode_noeeprom(rgblight_config.mode); +} + +void rgblight_disable(void) { + rgblight_config.enable = 0; eeconfig_update_rgblight(rgblight_config.raw); - xprintf("rgblight toggle: rgblight_config.enable = %u\n", rgblight_config.enable); - if (rgblight_config.enable) { - rgblight_mode(rgblight_config.mode); - } else { - - #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER) - rgblight_timer_disable(); - #endif - _delay_ms(50); - rgblight_set(); - } -} - - -void rgblight_increase_hue(void){ - uint16_t hue; - hue = (rgblight_config.hue+RGBLIGHT_HUE_STEP) % 360; - rgblight_sethsv(hue, rgblight_config.sat, rgblight_config.val); -} -void rgblight_decrease_hue(void){ - uint16_t hue; - if (rgblight_config.hue-RGBLIGHT_HUE_STEP <0 ) { - hue = (rgblight_config.hue+360-RGBLIGHT_HUE_STEP) % 360; - } else { - hue = (rgblight_config.hue-RGBLIGHT_HUE_STEP) % 360; - } - rgblight_sethsv(hue, rgblight_config.sat, rgblight_config.val); + xprintf("rgblight disable [EEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable); +#ifdef RGBLIGHT_USE_TIMER + rgblight_timer_disable(); +#endif + RGBLIGHT_SPLIT_SET_CHANGE_MODE; + wait_ms(50); + rgblight_set(); +} + +void rgblight_disable_noeeprom(void) { + rgblight_config.enable = 0; + xprintf("rgblight disable [noEEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable); +#ifdef RGBLIGHT_USE_TIMER + rgblight_timer_disable(); +#endif + RGBLIGHT_SPLIT_SET_CHANGE_MODE; + wait_ms(50); + rgblight_set(); +} + +void rgblight_increase_hue_helper(bool write_to_eeprom) { + uint8_t hue = rgblight_config.hue + RGBLIGHT_HUE_STEP; + rgblight_sethsv_eeprom_helper(hue, rgblight_config.sat, rgblight_config.val, write_to_eeprom); +} +void rgblight_increase_hue_noeeprom(void) { + rgblight_increase_hue_helper(false); +} +void rgblight_increase_hue(void) { + rgblight_increase_hue_helper(true); +} +void rgblight_decrease_hue_helper(bool write_to_eeprom) { + uint8_t hue = rgblight_config.hue - RGBLIGHT_HUE_STEP; + rgblight_sethsv_eeprom_helper(hue, rgblight_config.sat, rgblight_config.val, write_to_eeprom); +} +void rgblight_decrease_hue_noeeprom(void) { + rgblight_decrease_hue_helper(false); +} +void rgblight_decrease_hue(void) { + rgblight_decrease_hue_helper(true); +} +void rgblight_increase_sat_helper(bool write_to_eeprom) { + uint8_t sat = qadd8(rgblight_config.sat, RGBLIGHT_SAT_STEP); + rgblight_sethsv_eeprom_helper(rgblight_config.hue, sat, rgblight_config.val, write_to_eeprom); +} +void rgblight_increase_sat_noeeprom(void) { + rgblight_increase_sat_helper(false); } void rgblight_increase_sat(void) { - uint8_t sat; - if (rgblight_config.sat + RGBLIGHT_SAT_STEP > 255) { - sat = 255; - } else { - sat = rgblight_config.sat+RGBLIGHT_SAT_STEP; - } - rgblight_sethsv(rgblight_config.hue, sat, rgblight_config.val); + rgblight_increase_sat_helper(true); } -void rgblight_decrease_sat(void){ - uint8_t sat; - if (rgblight_config.sat - RGBLIGHT_SAT_STEP < 0) { - sat = 0; - } else { - sat = rgblight_config.sat-RGBLIGHT_SAT_STEP; - } - rgblight_sethsv(rgblight_config.hue, sat, rgblight_config.val); +void rgblight_decrease_sat_helper(bool write_to_eeprom) { + uint8_t sat = qsub8(rgblight_config.sat, RGBLIGHT_SAT_STEP); + rgblight_sethsv_eeprom_helper(rgblight_config.hue, sat, rgblight_config.val, write_to_eeprom); } -void rgblight_increase_val(void){ - uint8_t val; - if (rgblight_config.val + RGBLIGHT_VAL_STEP > 255) { - val = 255; - } else { - val = rgblight_config.val+RGBLIGHT_VAL_STEP; - } - rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, val); +void rgblight_decrease_sat_noeeprom(void) { + rgblight_decrease_sat_helper(false); +} +void rgblight_decrease_sat(void) { + rgblight_decrease_sat_helper(true); +} +void rgblight_increase_val_helper(bool write_to_eeprom) { + uint8_t val = qadd8(rgblight_config.val, RGBLIGHT_VAL_STEP); + rgblight_sethsv_eeprom_helper(rgblight_config.hue, rgblight_config.sat, val, write_to_eeprom); +} +void rgblight_increase_val_noeeprom(void) { + rgblight_increase_val_helper(false); +} +void rgblight_increase_val(void) { + rgblight_increase_val_helper(true); +} +void rgblight_decrease_val_helper(bool write_to_eeprom) { + uint8_t val = qsub8(rgblight_config.val, RGBLIGHT_VAL_STEP); + rgblight_sethsv_eeprom_helper(rgblight_config.hue, rgblight_config.sat, val, write_to_eeprom); +} +void rgblight_decrease_val_noeeprom(void) { + rgblight_decrease_val_helper(false); } void rgblight_decrease_val(void) { - uint8_t val; - if (rgblight_config.val - RGBLIGHT_VAL_STEP < 0) { - val = 0; - } else { - val = rgblight_config.val-RGBLIGHT_VAL_STEP; - } - rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, val); + rgblight_decrease_val_helper(true); +} +void rgblight_increase_speed(void) { + if (rgblight_config.speed < 3) + rgblight_config.speed++; + //RGBLIGHT_SPLIT_SET_CHANGE_HSVS; // NEED? + eeconfig_update_rgblight(rgblight_config.raw);//EECONFIG needs to be increased to support this } -void rgblight_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val){ - inmem_config.raw = rgblight_config.raw; +void rgblight_decrease_speed(void) { + if (rgblight_config.speed > 0) + rgblight_config.speed--; + //RGBLIGHT_SPLIT_SET_CHANGE_HSVS; // NEED?? + eeconfig_update_rgblight(rgblight_config.raw);//EECONFIG needs to be increased to support this +} + +void rgblight_sethsv_noeeprom_old(uint8_t hue, uint8_t sat, uint8_t val) { if (rgblight_config.enable) { - struct cRGB tmp_led; + LED_TYPE tmp_led; sethsv(hue, sat, val, &tmp_led); - inmem_config.hue = hue; - inmem_config.sat = sat; - inmem_config.val = val; // dprintf("rgblight set hue [MEMORY]: %u,%u,%u\n", inmem_config.hue, inmem_config.sat, inmem_config.val); rgblight_setrgb(tmp_led.r, tmp_led.g, tmp_led.b); } } -void rgblight_sethsv(uint16_t hue, uint8_t sat, uint8_t val){ + +void rgblight_sethsv_eeprom_helper(uint8_t hue, uint8_t sat, uint8_t val, bool write_to_eeprom) { if (rgblight_config.enable) { - if (rgblight_config.mode == 1) { - // same static color - rgblight_sethsv_noeeprom(hue, sat, val); - } else { - // all LEDs in same color - if (rgblight_config.mode >= 2 && rgblight_config.mode <= 5) { - // breathing mode, ignore the change of val, use in memory value instead - val = rgblight_config.val; - } else if (rgblight_config.mode >= 6 && rgblight_config.mode <= 14) { - // rainbow mood and rainbow swirl, ignore the change of hue - hue = rgblight_config.hue; - } - } - rgblight_config.hue = hue; - rgblight_config.sat = sat; - rgblight_config.val = val; - eeconfig_update_rgblight(rgblight_config.raw); - xprintf("rgblight set hsv [EEPROM]: %u,%u,%u\n", rgblight_config.hue, rgblight_config.sat, rgblight_config.val); - } -} - -void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b){ - // dprintf("rgblight set rgb: %u,%u,%u\n", r,g,b); - for (uint8_t i=0;i= RGBLED_NUM) { return; } + + led[index].r = r; + led[index].g = g; + led[index].b = b; + rgblight_set(); +} + +void rgblight_sethsv_at(uint8_t hue, uint8_t sat, uint8_t val, uint8_t index) { + if (!rgblight_config.enable) { return; } + + LED_TYPE tmp_led; + sethsv(hue, sat, val, &tmp_led); + rgblight_setrgb_at(tmp_led.r, tmp_led.g, tmp_led.b, index); +} + +#if defined(RGBLIGHT_EFFECT_BREATHING) || defined(RGBLIGHT_EFFECT_RAINBOW_MOOD) || defined(RGBLIGHT_EFFECT_RAINBOW_SWIRL) \ + || defined(RGBLIGHT_EFFECT_SNAKE) || defined(RGBLIGHT_EFFECT_KNIGHT) + +static uint8_t get_interval_time(const uint8_t* default_interval_address, uint8_t velocikey_min, uint8_t velocikey_max) { + return +#ifdef VELOCIKEY_ENABLE + velocikey_enabled() ? velocikey_match_speed(velocikey_min, velocikey_max) : +#endif + pgm_read_byte(default_interval_address); +} + +#endif + +void rgblight_setrgb_range(uint8_t r, uint8_t g, uint8_t b, uint8_t start, uint8_t end) { + if (!rgblight_config.enable || start < 0 || start >= end || end > RGBLED_NUM) { return; } + + for (uint8_t i = start; i < end; i++) { + led[i].r = r; + led[i].g = g; + led[i].b = b; + } + rgblight_set(); + wait_ms(1); +} + +void rgblight_sethsv_range(uint8_t hue, uint8_t sat, uint8_t val, uint8_t start, uint8_t end) { + if (!rgblight_config.enable) { return; } + + LED_TYPE tmp_led; + sethsv(hue, sat, val, &tmp_led); + rgblight_setrgb_range(tmp_led.r, tmp_led.g, tmp_led.b, start, end); +} + +#ifndef RGBLIGHT_SPLIT +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); +} +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); } +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); +} + +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); +} +#endif // ifndef RGBLIGHT_SPLIT + +#ifndef RGBLIGHT_CUSTOM_DRIVER void rgblight_set(void) { - if (rgblight_config.enable) { - ws2812_setleds(led, RGBLED_NUM); - } else { - for (uint8_t i=0;iconfig = rgblight_config; + syncinfo->status = rgblight_status; +} + +/* for split keyboard slave side */ +void rgblight_update_sync(rgblight_syncinfo_t *syncinfo, bool write_to_eeprom) { + if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_MODE) { + if (syncinfo->config.enable) { + rgblight_config.enable = 1; // == rgblight_enable_noeeprom(); + rgblight_mode_eeprom_helper(syncinfo->config.mode, write_to_eeprom); + } else { + rgblight_disable_noeeprom(); + } + } + if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_HSVS) { + rgblight_sethsv_eeprom_helper(syncinfo->config.hue, syncinfo->config.sat, syncinfo->config.val, write_to_eeprom); + // rgblight_config.speed = config->speed; // NEED??? + } + #ifdef RGBLIGHT_USE_TIMER + if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_TIMER) { + if (syncinfo->status.timer_enabled) { + rgblight_timer_enable(); + } else { + rgblight_timer_disable(); + } + } + #ifndef RGBLIGHT_SPLIT_NO_ANIMATION_SYNC + if (syncinfo->status.change_flags & RGBLIGHT_STATUS_ANIMATION_TICK) { + animation_status.restart = true; + } + #endif /* RGBLIGHT_SPLIT_NO_ANIMATION_SYNC */ + #endif /* RGBLIGHT_USE_TIMER */ } +#endif /* RGBLIGHT_SPLIT */ +#ifdef RGBLIGHT_USE_TIMER -#if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER) +typedef void (*effect_func_t)(animation_status_t *anim); -// Animation timer -- AVR Timer3 +// Animation timer -- use system timer (AVR Timer0) void rgblight_timer_init(void) { - static uint8_t rgblight_timer_is_init = 0; - if (rgblight_timer_is_init) { - return; - } - rgblight_timer_is_init = 1; - /* Timer 3 setup */ - TCCR3B = _BV(WGM32) //CTC mode OCR3A as TOP - | _BV(CS30); //Clock selelct: clk/1 - /* Set TOP value */ - uint8_t sreg = SREG; - cli(); - OCR3AH = (RGBLED_TIMER_TOP>>8)&0xff; - OCR3AL = RGBLED_TIMER_TOP&0xff; - SREG = sreg; + // OLD!!!! Animation timer -- AVR Timer3 + // static uint8_t rgblight_timer_is_init = 0; + // if (rgblight_timer_is_init) { + // return; + // } + // rgblight_timer_is_init = 1; + // /* Timer 3 setup */ + // TCCR3B = _BV(WGM32) // CTC mode OCR3A as TOP + // | _BV(CS30); // Clock selelct: clk/1 + // /* Set TOP value */ + // uint8_t sreg = SREG; + // cli(); + // OCR3AH = (RGBLED_TIMER_TOP >> 8) & 0xff; + // OCR3AL = RGBLED_TIMER_TOP & 0xff; + // SREG = sreg; + + rgblight_status.timer_enabled = false; + RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE; } void rgblight_timer_enable(void) { - TIMSK3 |= _BV(OCIE3A); - dprintf("TIMER3 enabled.\n"); + if( !is_static_effect(rgblight_config.mode) ) { + rgblight_status.timer_enabled = true; + } + animation_status.last_timer = timer_read(); + RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE; + dprintf("rgblight timer enabled.\n"); } void rgblight_timer_disable(void) { - TIMSK3 &= ~_BV(OCIE3A); - dprintf("TIMER3 disabled.\n"); + rgblight_status.timer_enabled = false; + RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE; + dprintf("rgblight timer disable.\n"); } void rgblight_timer_toggle(void) { - TIMSK3 ^= _BV(OCIE3A); - dprintf("TIMER3 toggled.\n"); -} - -ISR(TIMER3_COMPA_vect) { - // Mode = 1, static light, do nothing here - if (rgblight_config.mode>=2 && rgblight_config.mode<=5) { - // mode = 2 to 5, breathing mode - rgblight_effect_breathing(rgblight_config.mode-2); - - } else if (rgblight_config.mode>=6 && rgblight_config.mode<=8) { - rgblight_effect_rainbow_mood(rgblight_config.mode-6); - } else if (rgblight_config.mode>=9 && rgblight_config.mode<=14) { - rgblight_effect_rainbow_swirl(rgblight_config.mode-9); - } else if (rgblight_config.mode>=15 && rgblight_config.mode<=20) { - rgblight_effect_snake(rgblight_config.mode-15); - } else if (rgblight_config.mode>=21 && rgblight_config.mode<=23) { - rgblight_effect_knight(rgblight_config.mode-21); - } -} - -// effects -void rgblight_effect_breathing(uint8_t interval) { - static uint8_t pos = 0; - static uint16_t last_timer = 0; - - if (timer_elapsed(last_timer)=RGBLED_NUM) k=RGBLED_NUM-1; - if (i==k) { - sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, &preled[i]); - } - } - } - if (RGBLIGHT_EFFECT_KNIGHT_OFFSET) { - for (i=0;iRGBLED_NUM+RGBLIGHT_EFFECT_KNIGHT_LENGTH) { - pos = RGBLED_NUM+RGBLIGHT_EFFECT_KNIGHT_LENGTH-1; - increament = 1; - } else { - pos += 1; - } - } - -} - -#endif \ No newline at end of file + dprintf("rgblight timer toggle.\n"); + if(rgblight_status.timer_enabled) { + rgblight_timer_disable(); + } else { + rgblight_timer_enable(); + } +} + +void rgblight_show_solid_color(uint8_t r, uint8_t g, uint8_t b) { + rgblight_enable(); + rgblight_mode(RGBLIGHT_MODE_STATIC_LIGHT); + rgblight_setrgb(r, g, b); +} + +static void rgblight_effect_dummy(animation_status_t *anim) { + // do nothing + /******** + dprintf("rgblight_task() what happened?\n"); + dprintf("is_static_effect %d\n", is_static_effect(rgblight_config.mode)); + dprintf("mode = %d, base_mode = %d, timer_enabled %d, ", + rgblight_config.mode, rgblight_status.base_mode, + rgblight_status.timer_enabled); + dprintf("last_timer = %d\n",anim->last_timer); + **/ +} + +void rgblight_task(void) { + if (rgblight_status.timer_enabled) { + effect_func_t effect_func = rgblight_effect_dummy; + uint16_t interval_time = 2000; // dummy interval + uint8_t delta = rgblight_config.mode - rgblight_status.base_mode; + animation_status.delta = delta; + + // static light mode, do nothing here + if ( 1 == 0 ) { //dummy + } +#ifdef RGBLIGHT_EFFECT_BREATHING + else if (rgblight_status.base_mode == RGBLIGHT_MODE_BREATHING) { + // breathing mode + interval_time = get_interval_time(&RGBLED_BREATHING_INTERVALS[delta], 1, 100); + effect_func = rgblight_effect_breathing; + } +#endif +#ifdef RGBLIGHT_EFFECT_RAINBOW_MOOD + else if (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_MOOD) { + // rainbow mood mode + interval_time = get_interval_time(&RGBLED_RAINBOW_MOOD_INTERVALS[delta], 5, 100); + effect_func = rgblight_effect_rainbow_mood; + } +#endif +#ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL + else if (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_SWIRL) { + // rainbow swirl mode + interval_time = get_interval_time(&RGBLED_RAINBOW_SWIRL_INTERVALS[delta / 2], 1, 100); + effect_func = rgblight_effect_rainbow_swirl; + } +#endif +#ifdef RGBLIGHT_EFFECT_SNAKE + else if (rgblight_status.base_mode == RGBLIGHT_MODE_SNAKE) { + // snake mode + interval_time = get_interval_time(&RGBLED_SNAKE_INTERVALS[delta / 2], 1, 200); + effect_func = rgblight_effect_snake; + } +#endif +#ifdef RGBLIGHT_EFFECT_KNIGHT + else if (rgblight_status.base_mode == RGBLIGHT_MODE_KNIGHT) { + // knight mode + interval_time = get_interval_time(&RGBLED_KNIGHT_INTERVALS[delta], 5, 100); + effect_func = rgblight_effect_knight; + } +#endif +#ifdef RGBLIGHT_EFFECT_CHRISTMAS + else if (rgblight_status.base_mode == RGBLIGHT_MODE_CHRISTMAS) { + // christmas mode + interval_time = RGBLIGHT_EFFECT_CHRISTMAS_INTERVAL; + effect_func = (effect_func_t)rgblight_effect_christmas; + } +#endif +#ifdef RGBLIGHT_EFFECT_RGB_TEST + else if (rgblight_status.base_mode == RGBLIGHT_MODE_RGB_TEST) { + // RGB test mode + interval_time = pgm_read_word(&RGBLED_RGBTEST_INTERVALS[0]); + effect_func = (effect_func_t)rgblight_effect_rgbtest; + } +#endif +#ifdef RGBLIGHT_EFFECT_ALTERNATING + else if (rgblight_status.base_mode == RGBLIGHT_MODE_ALTERNATING){ + interval_time = 500; + effect_func = (effect_func_t)rgblight_effect_alternating; + } +#endif + if (animation_status.restart) { + animation_status.restart = false; + animation_status.last_timer = timer_read() - interval_time - 1; + animation_status.pos16 = 0; // restart signal to local each effect + } + if (timer_elapsed(animation_status.last_timer) >= interval_time) { +#if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) + static uint16_t report_last_timer = 0; + static bool tick_flag = false; + uint16_t oldpos16; + if (tick_flag) { + tick_flag = false; + //dprintf("rgblight animation tick\n"); + if (timer_elapsed(report_last_timer) >= 30000) { + report_last_timer = timer_read(); + dprintf("rgblight animation tick report to slave\n"); + RGBLIGHT_SPLIT_ANIMATION_TICK; + } + } + oldpos16 = animation_status.pos16; + //dprintf("call effect function\n"); +#endif + animation_status.last_timer += interval_time; + effect_func(&animation_status); +#if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) + //dprintf("pos16, oldpos16 = %d %d\n", + // animation_status.pos16,oldpos16); + if (animation_status.pos16 == 0 && oldpos16 != 0) { + //dprintf("flag on\n"); + tick_flag = true; + } +#endif + } + } +} + +#endif /* RGBLIGHT_USE_TIMER */ + +// Effects +#ifdef RGBLIGHT_EFFECT_BREATHING + +#ifndef RGBLIGHT_EFFECT_BREATHE_CENTER + #ifndef RGBLIGHT_BREATHE_TABLE_SIZE + #define RGBLIGHT_BREATHE_TABLE_SIZE 256 // 256 or 128 or 64 + #endif + #include +#endif + +__attribute__ ((weak)) +const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5}; + +void rgblight_effect_breathing(animation_status_t *anim) { + float val; + + // http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/ +#ifdef RGBLIGHT_EFFECT_BREATHE_TABLE + val = pgm_read_byte(&rgblight_effect_breathe_table[anim->pos / table_scale]); +#else + val = (exp(sin((anim->pos/255.0)*M_PI)) - RGBLIGHT_EFFECT_BREATHE_CENTER/M_E)*(RGBLIGHT_EFFECT_BREATHE_MAX/(M_E-1/M_E)); +#endif + rgblight_sethsv_noeeprom_old(rgblight_config.hue, rgblight_config.sat, val); + anim->pos = (anim->pos + 1); +} +#endif + +#ifdef RGBLIGHT_EFFECT_RAINBOW_MOOD +__attribute__ ((weak)) +const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[] PROGMEM = {120, 60, 30}; + +void rgblight_effect_rainbow_mood(animation_status_t *anim) { + rgblight_sethsv_noeeprom_old(anim->current_hue, rgblight_config.sat, rgblight_config.val); + anim->current_hue++; +} +#endif + +#ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL +#ifndef RGBLIGHT_RAINBOW_SWIRL_RANGE + #define RGBLIGHT_RAINBOW_SWIRL_RANGE 255 +#endif + +__attribute__ ((weak)) +const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[] PROGMEM = {100, 50, 20}; + +void rgblight_effect_rainbow_swirl(animation_status_t *anim) { + uint8_t hue; + uint8_t i; + + for (i = 0; i < effect_num_leds; i++) { + hue = (RGBLIGHT_RAINBOW_SWIRL_RANGE / effect_num_leds * i + anim->current_hue); + sethsv(hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[i + effect_start_pos]); + } + rgblight_set(); + + if (anim->delta % 2) { + anim->current_hue++; + } else { + anim->current_hue--; + } +} +#endif + +#ifdef RGBLIGHT_EFFECT_SNAKE +__attribute__ ((weak)) +const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {100, 50, 20}; + +void rgblight_effect_snake(animation_status_t *anim) { + static uint8_t pos = 0; + uint8_t i, j; + int8_t k; + int8_t increment = 1; + + if (anim->delta % 2) { + increment = -1; + } + +#if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) + if (anim->pos == 0) { // restart signal + if (increment == 1) { + pos = effect_num_leds - 1; + } else { + pos = 0; + } + anim->pos = 1; + } +#endif + + for (i = 0; i < effect_num_leds; i++) { + LED_TYPE *ledp = led + i + effect_start_pos; + ledp->r = 0; + ledp->g = 0; + ledp->b = 0; + for (j = 0; j < RGBLIGHT_EFFECT_SNAKE_LENGTH; j++) { + k = pos + j * increment; + if (k < 0) { + k = k + effect_num_leds; + } + if (i == k) { + sethsv(rgblight_config.hue, rgblight_config.sat, + (uint8_t)(rgblight_config.val*(RGBLIGHT_EFFECT_SNAKE_LENGTH-j)/RGBLIGHT_EFFECT_SNAKE_LENGTH), + ledp); + } + } + } + rgblight_set(); + if (increment == 1) { + if (pos - 1 < 0) { + pos = effect_num_leds - 1; +#if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) + anim->pos = 0; +#endif + } else { + pos -= 1; +#if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) + anim->pos = 1; +#endif + } + } else { + pos = (pos + 1) % effect_num_leds; +#if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) + anim->pos = pos; +#endif + } +} +#endif + +#ifdef RGBLIGHT_EFFECT_KNIGHT +__attribute__ ((weak)) +const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {127, 63, 31}; + +void rgblight_effect_knight(animation_status_t *anim) { + + static int8_t low_bound = 0; + static int8_t high_bound = RGBLIGHT_EFFECT_KNIGHT_LENGTH - 1; + static int8_t increment = 1; + uint8_t i, cur; + +#if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) + if (anim->pos == 0) { // restart signal + anim->pos = 1; + low_bound = 0; + high_bound = RGBLIGHT_EFFECT_KNIGHT_LENGTH - 1; + increment = 1; + } +#endif + // Set all the LEDs to 0 + for (i = effect_start_pos; i < effect_end_pos; i++) { + led[i].r = 0; + led[i].g = 0; + led[i].b = 0; + } + // Determine which LEDs should be lit up + for (i = 0; i < RGBLIGHT_EFFECT_KNIGHT_LED_NUM; i++) { + cur = (i + RGBLIGHT_EFFECT_KNIGHT_OFFSET) % effect_num_leds + effect_start_pos; + + if (i >= low_bound && i <= high_bound) { + sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[cur]); + } else { + led[cur].r = 0; + led[cur].g = 0; + led[cur].b = 0; + } + } + rgblight_set(); + + // Move from low_bound to high_bound changing the direction we increment each + // time a boundary is hit. + low_bound += increment; + high_bound += increment; + + if (high_bound <= 0 || low_bound >= RGBLIGHT_EFFECT_KNIGHT_LED_NUM - 1) { + increment = -increment; +#if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) + if (increment == 1) { + anim->pos = 0; + } +#endif + } +} +#endif + +#ifdef RGBLIGHT_EFFECT_CHRISTMAS +void rgblight_effect_christmas(animation_status_t *anim) { + uint8_t hue; + uint8_t i; + + anim->current_offset = (anim->current_offset + 1) % 2; + for (i = 0; i < effect_num_leds; i++) { + hue = 0 + ((i/RGBLIGHT_EFFECT_CHRISTMAS_STEP + anim->current_offset) % 2) * 85; + sethsv(hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[i + effect_start_pos]); + } + rgblight_set(); +} +#endif + +#ifdef RGBLIGHT_EFFECT_RGB_TEST +__attribute__ ((weak)) +const uint16_t RGBLED_RGBTEST_INTERVALS[] PROGMEM = {1024}; + +void rgblight_effect_rgbtest(animation_status_t *anim) { + static uint8_t maxval = 0; + uint8_t g; uint8_t r; uint8_t b; + + if( maxval == 0 ) { + LED_TYPE tmp_led; + sethsv(0, 255, RGBLIGHT_LIMIT_VAL, &tmp_led); + maxval = tmp_led.r; + } + g = r = b = 0; + switch( anim->pos ) { + case 0: r = maxval; break; + case 1: g = maxval; break; + case 2: b = maxval; break; + } + rgblight_setrgb(r, g, b); + anim->pos = (anim->pos + 1) % 3; +} +#endif + +#ifdef RGBLIGHT_EFFECT_ALTERNATING +void rgblight_effect_alternating(animation_status_t *anim) { + + for (int i = 0; i < effect_num_leds; i++) { + LED_TYPE *ledp = led + i + effect_start_pos; + if (ipos) { + sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, ledp); + } else if (i>=effect_num_leds/2 && !anim->pos) { + sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, ledp); + } else { + sethsv(rgblight_config.hue, rgblight_config.sat, 0, ledp); + } + } + rgblight_set(); + anim->pos = (anim->pos + 1) % 2; +} +#endif