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 26cb41a96..d33484ccf 100644 --- a/quantum/rgblight.c +++ b/quantum/rgblight.c | |||
@@ -15,6 +15,7 @@ | |||
15 | */ | 15 | */ |
16 | #include <math.h> | 16 | #include <math.h> |
17 | #include <string.h> | 17 | #include <string.h> |
18 | #include <stdlib.h> | ||
18 | #ifdef __AVR__ | 19 | #ifdef __AVR__ |
19 | # include <avr/eeprom.h> | 20 | # include <avr/eeprom.h> |
20 | # include <avr/interrupt.h> | 21 | # include <avr/interrupt.h> |
@@ -367,6 +368,8 @@ void rgblight_disable_noeeprom(void) { | |||
367 | rgblight_set(); | 368 | rgblight_set(); |
368 | } | 369 | } |
369 | 370 | ||
371 | bool rgblight_is_enabled(void) { return rgblight_config.enable; } | ||
372 | |||
370 | void rgblight_increase_hue_helper(bool write_to_eeprom) { | 373 | void rgblight_increase_hue_helper(bool write_to_eeprom) { |
371 | uint8_t hue = rgblight_config.hue + RGBLIGHT_HUE_STEP; | 374 | uint8_t hue = rgblight_config.hue + RGBLIGHT_HUE_STEP; |
372 | rgblight_sethsv_eeprom_helper(hue, rgblight_config.sat, rgblight_config.val, write_to_eeprom); | 375 | 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; } | |||
521 | 524 | ||
522 | uint8_t rgblight_get_val(void) { return rgblight_config.val; } | 525 | uint8_t rgblight_get_val(void) { return rgblight_config.val; } |
523 | 526 | ||
527 | HSV rgblight_get_hsv(void) { return (HSV){rgblight_config.hue, rgblight_config.sat, rgblight_config.val}; } | ||
528 | |||
524 | void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b) { | 529 | void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b) { |
525 | if (!rgblight_config.enable) { | 530 | if (!rgblight_config.enable) { |
526 | return; | 531 | return; |
@@ -561,7 +566,7 @@ void rgblight_sethsv_at(uint8_t hue, uint8_t sat, uint8_t val, uint8_t index) { | |||
561 | rgblight_setrgb_at(tmp_led.r, tmp_led.g, tmp_led.b, index); | 566 | rgblight_setrgb_at(tmp_led.r, tmp_led.g, tmp_led.b, index); |
562 | } | 567 | } |
563 | 568 | ||
564 | #if defined(RGBLIGHT_EFFECT_BREATHING) || defined(RGBLIGHT_EFFECT_RAINBOW_MOOD) || defined(RGBLIGHT_EFFECT_RAINBOW_SWIRL) || defined(RGBLIGHT_EFFECT_SNAKE) || defined(RGBLIGHT_EFFECT_KNIGHT) | 569 | #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) |
565 | 570 | ||
566 | static uint8_t get_interval_time(const uint8_t *default_interval_address, uint8_t velocikey_min, uint8_t velocikey_max) { | 571 | static uint8_t get_interval_time(const uint8_t *default_interval_address, uint8_t velocikey_min, uint8_t velocikey_max) { |
567 | return | 572 | return |
@@ -612,7 +617,7 @@ void rgblight_sethsv_slave(uint8_t hue, uint8_t sat, uint8_t val) { rgblight_set | |||
612 | 617 | ||
613 | #ifdef RGBLIGHT_LAYERS | 618 | #ifdef RGBLIGHT_LAYERS |
614 | void rgblight_set_layer_state(uint8_t layer, bool enabled) { | 619 | void rgblight_set_layer_state(uint8_t layer, bool enabled) { |
615 | uint8_t mask = 1 << layer; | 620 | rgblight_layer_mask_t mask = 1 << layer; |
616 | if (enabled) { | 621 | if (enabled) { |
617 | rgblight_status.enabled_layer_mask |= mask; | 622 | rgblight_status.enabled_layer_mask |= mask; |
618 | } else { | 623 | } else { |
@@ -623,10 +628,17 @@ void rgblight_set_layer_state(uint8_t layer, bool enabled) { | |||
623 | if (rgblight_status.timer_enabled == false) { | 628 | if (rgblight_status.timer_enabled == false) { |
624 | rgblight_mode_noeeprom(rgblight_config.mode); | 629 | rgblight_mode_noeeprom(rgblight_config.mode); |
625 | } | 630 | } |
631 | |||
632 | # ifdef RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF | ||
633 | // If not enabled, then nothing else will actually set the LEDs... | ||
634 | if (!rgblight_config.enable) { | ||
635 | rgblight_set(); | ||
636 | } | ||
637 | # endif | ||
626 | } | 638 | } |
627 | 639 | ||
628 | bool rgblight_get_layer_state(uint8_t layer) { | 640 | bool rgblight_get_layer_state(uint8_t layer) { |
629 | uint8_t mask = 1 << layer; | 641 | rgblight_layer_mask_t mask = 1 << layer; |
630 | return (rgblight_status.enabled_layer_mask & mask) != 0; | 642 | return (rgblight_status.enabled_layer_mask & mask) != 0; |
631 | } | 643 | } |
632 | 644 | ||
@@ -658,21 +670,41 @@ static void rgblight_layers_write(void) { | |||
658 | } | 670 | } |
659 | } | 671 | } |
660 | } | 672 | } |
673 | |||
674 | # ifdef RGBLIGHT_LAYER_BLINK | ||
675 | rgblight_layer_mask_t _blinked_layer_mask = 0; | ||
676 | uint16_t _blink_duration = 0; | ||
677 | static uint16_t _blink_timer; | ||
678 | |||
679 | void rgblight_blink_layer(uint8_t layer, uint16_t duration_ms) { | ||
680 | rgblight_set_layer_state(layer, true); | ||
681 | _blinked_layer_mask |= 1 << layer; | ||
682 | _blink_timer = timer_read(); | ||
683 | _blink_duration = duration_ms; | ||
684 | } | ||
685 | |||
686 | void rgblight_unblink_layers(void) { | ||
687 | if (_blinked_layer_mask != 0 && timer_elapsed(_blink_timer) > _blink_duration) { | ||
688 | for (uint8_t layer = 0; layer < RGBLIGHT_MAX_LAYERS; layer++) { | ||
689 | if ((_blinked_layer_mask & 1 << layer) != 0) { | ||
690 | rgblight_set_layer_state(layer, false); | ||
691 | } | ||
692 | } | ||
693 | _blinked_layer_mask = 0; | ||
694 | } | ||
695 | } | ||
696 | # endif | ||
697 | |||
661 | #endif | 698 | #endif |
662 | 699 | ||
663 | __attribute__((weak)) void rgblight_call_driver(LED_TYPE *start_led, uint8_t num_leds) { ws2812_setleds(start_led, num_leds); } | 700 | __attribute__((weak)) void rgblight_call_driver(LED_TYPE *start_led, uint8_t num_leds) { ws2812_setleds(start_led, num_leds); } |
664 | 701 | ||
665 | #ifndef RGBLIGHT_CUSTOM_DRIVER | 702 | #ifndef RGBLIGHT_CUSTOM_DRIVER |
703 | |||
666 | void rgblight_set(void) { | 704 | void rgblight_set(void) { |
667 | LED_TYPE *start_led; | 705 | LED_TYPE *start_led; |
668 | uint8_t num_leds = rgblight_ranges.clipping_num_leds; | 706 | uint8_t num_leds = rgblight_ranges.clipping_num_leds; |
669 | 707 | ||
670 | # ifdef RGBLIGHT_LAYERS | ||
671 | if (rgblight_layers != NULL) { | ||
672 | rgblight_layers_write(); | ||
673 | } | ||
674 | # endif | ||
675 | |||
676 | if (!rgblight_config.enable) { | 708 | if (!rgblight_config.enable) { |
677 | for (uint8_t i = rgblight_ranges.effect_start_pos; i < rgblight_ranges.effect_end_pos; i++) { | 709 | for (uint8_t i = rgblight_ranges.effect_start_pos; i < rgblight_ranges.effect_end_pos; i++) { |
678 | led[i].r = 0; | 710 | led[i].r = 0; |
@@ -684,6 +716,16 @@ void rgblight_set(void) { | |||
684 | } | 716 | } |
685 | } | 717 | } |
686 | 718 | ||
719 | # ifdef RGBLIGHT_LAYERS | ||
720 | if (rgblight_layers != NULL | ||
721 | # ifndef RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF | ||
722 | && rgblight_config.enable | ||
723 | # endif | ||
724 | ) { | ||
725 | rgblight_layers_write(); | ||
726 | } | ||
727 | # endif | ||
728 | |||
687 | # ifdef RGBLIGHT_LED_MAP | 729 | # ifdef RGBLIGHT_LED_MAP |
688 | LED_TYPE led0[RGBLED_NUM]; | 730 | LED_TYPE led0[RGBLED_NUM]; |
689 | for (uint8_t i = 0; i < RGBLED_NUM; i++) { | 731 | for (uint8_t i = 0; i < RGBLED_NUM; i++) { |
@@ -880,6 +922,12 @@ void rgblight_task(void) { | |||
880 | effect_func = (effect_func_t)rgblight_effect_alternating; | 922 | effect_func = (effect_func_t)rgblight_effect_alternating; |
881 | } | 923 | } |
882 | # endif | 924 | # endif |
925 | # ifdef RGBLIGHT_EFFECT_TWINKLE | ||
926 | else if (rgblight_status.base_mode == RGBLIGHT_MODE_TWINKLE) { | ||
927 | interval_time = get_interval_time(&RGBLED_TWINKLE_INTERVALS[delta % 3], 5, 50); | ||
928 | effect_func = (effect_func_t)rgblight_effect_twinkle; | ||
929 | } | ||
930 | # endif | ||
883 | if (animation_status.restart) { | 931 | if (animation_status.restart) { |
884 | animation_status.restart = false; | 932 | animation_status.restart = false; |
885 | animation_status.last_timer = timer_read() - interval_time - 1; | 933 | animation_status.last_timer = timer_read() - interval_time - 1; |
@@ -909,6 +957,10 @@ void rgblight_task(void) { | |||
909 | # endif | 957 | # endif |
910 | } | 958 | } |
911 | } | 959 | } |
960 | |||
961 | # ifdef RGBLIGHT_LAYER_BLINK | ||
962 | rgblight_unblink_layers(); | ||
963 | # endif | ||
912 | } | 964 | } |
913 | 965 | ||
914 | #endif /* RGBLIGHT_USE_TIMER */ | 966 | #endif /* RGBLIGHT_USE_TIMER */ |
@@ -1160,3 +1212,58 @@ void rgblight_effect_alternating(animation_status_t *anim) { | |||
1160 | anim->pos = (anim->pos + 1) % 2; | 1212 | anim->pos = (anim->pos + 1) % 2; |
1161 | } | 1213 | } |
1162 | #endif | 1214 | #endif |
1215 | |||
1216 | #ifdef RGBLIGHT_EFFECT_TWINKLE | ||
1217 | __attribute__((weak)) const uint8_t RGBLED_TWINKLE_INTERVALS[] PROGMEM = {50, 25, 10}; | ||
1218 | |||
1219 | typedef struct PACKED { | ||
1220 | HSV hsv; | ||
1221 | uint8_t life; | ||
1222 | bool up; | ||
1223 | } TwinkleState; | ||
1224 | |||
1225 | static TwinkleState led_twinkle_state[RGBLED_NUM]; | ||
1226 | |||
1227 | void rgblight_effect_twinkle(animation_status_t *anim) { | ||
1228 | bool random_color = anim->delta / 3; | ||
1229 | bool restart = anim->pos == 0; | ||
1230 | anim->pos = 1; | ||
1231 | |||
1232 | for (uint8_t i = 0; i < rgblight_ranges.effect_num_leds; i++) { | ||
1233 | TwinkleState *t = &(led_twinkle_state[i]); | ||
1234 | HSV * c = &(t->hsv); | ||
1235 | if (restart) { | ||
1236 | // Restart | ||
1237 | t->life = 0; | ||
1238 | t->hsv.v = 0; | ||
1239 | } else if (t->life) { | ||
1240 | // This LED is already on, either brightening or dimming | ||
1241 | t->life--; | ||
1242 | uint8_t on = t->up ? RGBLIGHT_EFFECT_TWINKLE_LIFE - t->life : t->life; | ||
1243 | c->v = (uint16_t)rgblight_config.val * on / RGBLIGHT_EFFECT_TWINKLE_LIFE; | ||
1244 | if (t->life == 0 && t->up) { | ||
1245 | t->up = false; | ||
1246 | t->life = RGBLIGHT_EFFECT_TWINKLE_LIFE; | ||
1247 | } | ||
1248 | if (!random_color) { | ||
1249 | c->h = rgblight_config.hue; | ||
1250 | c->s = rgblight_config.sat; | ||
1251 | } | ||
1252 | } else if (rand() < RAND_MAX * RGBLIGHT_EFFECT_TWINKLE_PROBABILITY) { | ||
1253 | // This LED is off, but was randomly selected to start brightening | ||
1254 | c->h = random_color ? rand() % 0xFF : rgblight_config.hue; | ||
1255 | c->s = random_color ? (rand() % (rgblight_config.sat / 2)) + (rgblight_config.sat / 2) : rgblight_config.sat; | ||
1256 | c->v = 0; | ||
1257 | t->life = RGBLIGHT_EFFECT_TWINKLE_LIFE; | ||
1258 | t->up = true; | ||
1259 | } else { | ||
1260 | // This LED is off, and was NOT selected to start brightening | ||
1261 | } | ||
1262 | |||
1263 | LED_TYPE *ledp = led + i + rgblight_ranges.effect_start_pos; | ||
1264 | sethsv(c->h, c->s, c->v, ledp); | ||
1265 | } | ||
1266 | |||
1267 | rgblight_set(); | ||
1268 | } | ||
1269 | #endif | ||