diff options
Diffstat (limited to 'quantum/rgblight.c')
-rw-r--r-- | quantum/rgblight.c | 125 |
1 files changed, 116 insertions, 9 deletions
diff --git a/quantum/rgblight.c b/quantum/rgblight.c index 26cb41a96f..d33484ccfd 100644 --- a/quantum/rgblight.c +++ b/quantum/rgblight.c @@ -15,6 +15,7 @@ */ #include <math.h> #include <string.h> +#include <stdlib.h> #ifdef __AVR__ # include <avr/eeprom.h> # include <avr/interrupt.h> @@ -367,6 +368,8 @@ void rgblight_disable_noeeprom(void) { rgblight_set(); } +bool rgblight_is_enabled(void) { return rgblight_config.enable; } + 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); @@ -521,6 +524,8 @@ uint8_t rgblight_get_sat(void) { return rgblight_config.sat; } uint8_t rgblight_get_val(void) { return rgblight_config.val; } +HSV rgblight_get_hsv(void) { return (HSV){rgblight_config.hue, rgblight_config.sat, rgblight_config.val}; } + void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b) { if (!rgblight_config.enable) { return; @@ -561,7 +566,7 @@ void rgblight_sethsv_at(uint8_t hue, uint8_t sat, uint8_t val, uint8_t index) { 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) +#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) static uint8_t get_interval_time(const uint8_t *default_interval_address, uint8_t velocikey_min, uint8_t velocikey_max) { return @@ -612,7 +617,7 @@ void rgblight_sethsv_slave(uint8_t hue, uint8_t sat, uint8_t val) { rgblight_set #ifdef RGBLIGHT_LAYERS void rgblight_set_layer_state(uint8_t layer, bool enabled) { - uint8_t mask = 1 << layer; + rgblight_layer_mask_t mask = 1 << layer; if (enabled) { rgblight_status.enabled_layer_mask |= mask; } else { @@ -623,10 +628,17 @@ void rgblight_set_layer_state(uint8_t layer, bool enabled) { if (rgblight_status.timer_enabled == false) { rgblight_mode_noeeprom(rgblight_config.mode); } + +# ifdef RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF + // If not enabled, then nothing else will actually set the LEDs... + if (!rgblight_config.enable) { + rgblight_set(); + } +# endif } bool rgblight_get_layer_state(uint8_t layer) { - uint8_t mask = 1 << layer; + rgblight_layer_mask_t mask = 1 << layer; return (rgblight_status.enabled_layer_mask & mask) != 0; } @@ -658,21 +670,41 @@ static void rgblight_layers_write(void) { } } } + +# ifdef RGBLIGHT_LAYER_BLINK +rgblight_layer_mask_t _blinked_layer_mask = 0; +uint16_t _blink_duration = 0; +static uint16_t _blink_timer; + +void rgblight_blink_layer(uint8_t layer, uint16_t duration_ms) { + rgblight_set_layer_state(layer, true); + _blinked_layer_mask |= 1 << layer; + _blink_timer = timer_read(); + _blink_duration = duration_ms; +} + +void rgblight_unblink_layers(void) { + if (_blinked_layer_mask != 0 && timer_elapsed(_blink_timer) > _blink_duration) { + for (uint8_t layer = 0; layer < RGBLIGHT_MAX_LAYERS; layer++) { + if ((_blinked_layer_mask & 1 << layer) != 0) { + rgblight_set_layer_state(layer, false); + } + } + _blinked_layer_mask = 0; + } +} +# endif + #endif __attribute__((weak)) void rgblight_call_driver(LED_TYPE *start_led, uint8_t num_leds) { ws2812_setleds(start_led, num_leds); } #ifndef RGBLIGHT_CUSTOM_DRIVER + void rgblight_set(void) { LED_TYPE *start_led; uint8_t num_leds = rgblight_ranges.clipping_num_leds; -# ifdef RGBLIGHT_LAYERS - if (rgblight_layers != NULL) { - rgblight_layers_write(); - } -# endif - if (!rgblight_config.enable) { for (uint8_t i = rgblight_ranges.effect_start_pos; i < rgblight_ranges.effect_end_pos; i++) { led[i].r = 0; @@ -684,6 +716,16 @@ void rgblight_set(void) { } } +# ifdef RGBLIGHT_LAYERS + if (rgblight_layers != NULL +# ifndef RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF + && rgblight_config.enable +# endif + ) { + rgblight_layers_write(); + } +# endif + # ifdef RGBLIGHT_LED_MAP LED_TYPE led0[RGBLED_NUM]; for (uint8_t i = 0; i < RGBLED_NUM; i++) { @@ -880,6 +922,12 @@ void rgblight_task(void) { effect_func = (effect_func_t)rgblight_effect_alternating; } # endif +# ifdef RGBLIGHT_EFFECT_TWINKLE + else if (rgblight_status.base_mode == RGBLIGHT_MODE_TWINKLE) { + interval_time = get_interval_time(&RGBLED_TWINKLE_INTERVALS[delta % 3], 5, 50); + effect_func = (effect_func_t)rgblight_effect_twinkle; + } +# endif if (animation_status.restart) { animation_status.restart = false; animation_status.last_timer = timer_read() - interval_time - 1; @@ -909,6 +957,10 @@ void rgblight_task(void) { # endif } } + +# ifdef RGBLIGHT_LAYER_BLINK + rgblight_unblink_layers(); +# endif } #endif /* RGBLIGHT_USE_TIMER */ @@ -1160,3 +1212,58 @@ void rgblight_effect_alternating(animation_status_t *anim) { anim->pos = (anim->pos + 1) % 2; } #endif + +#ifdef RGBLIGHT_EFFECT_TWINKLE +__attribute__((weak)) const uint8_t RGBLED_TWINKLE_INTERVALS[] PROGMEM = {50, 25, 10}; + +typedef struct PACKED { + HSV hsv; + uint8_t life; + bool up; +} TwinkleState; + +static TwinkleState led_twinkle_state[RGBLED_NUM]; + +void rgblight_effect_twinkle(animation_status_t *anim) { + bool random_color = anim->delta / 3; + bool restart = anim->pos == 0; + anim->pos = 1; + + for (uint8_t i = 0; i < rgblight_ranges.effect_num_leds; i++) { + TwinkleState *t = &(led_twinkle_state[i]); + HSV * c = &(t->hsv); + if (restart) { + // Restart + t->life = 0; + t->hsv.v = 0; + } else if (t->life) { + // This LED is already on, either brightening or dimming + t->life--; + uint8_t on = t->up ? RGBLIGHT_EFFECT_TWINKLE_LIFE - t->life : t->life; + c->v = (uint16_t)rgblight_config.val * on / RGBLIGHT_EFFECT_TWINKLE_LIFE; + if (t->life == 0 && t->up) { + t->up = false; + t->life = RGBLIGHT_EFFECT_TWINKLE_LIFE; + } + if (!random_color) { + c->h = rgblight_config.hue; + c->s = rgblight_config.sat; + } + } else if (rand() < RAND_MAX * RGBLIGHT_EFFECT_TWINKLE_PROBABILITY) { + // This LED is off, but was randomly selected to start brightening + c->h = random_color ? rand() % 0xFF : rgblight_config.hue; + c->s = random_color ? (rand() % (rgblight_config.sat / 2)) + (rgblight_config.sat / 2) : rgblight_config.sat; + c->v = 0; + t->life = RGBLIGHT_EFFECT_TWINKLE_LIFE; + t->up = true; + } else { + // This LED is off, and was NOT selected to start brightening + } + + LED_TYPE *ledp = led + i + rgblight_ranges.effect_start_pos; + sethsv(c->h, c->s, c->v, ledp); + } + + rgblight_set(); +} +#endif |