diff options
| author | Joshua Diamond <josh@windowoffire.com> | 2020-05-09 04:56:16 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-05-09 01:56:16 -0700 |
| commit | 2fe7e221ec9e412cc008aa5c03eaf27e35ff62c6 (patch) | |
| tree | 79ae7e86cfb9048b3bd9795b596ec318581d801e | |
| parent | e0f548085cc9c29e85122d393e74143eb5de1d4d (diff) | |
| download | qmk_firmware-2fe7e221ec9e412cc008aa5c03eaf27e35ff62c6.tar.gz qmk_firmware-2fe7e221ec9e412cc008aa5c03eaf27e35ff62c6.zip | |
New RGB Lighting effect: Twinkle (#8887)
* Add twinkle RGB Lighting effect
* 2nd twinkle algo - double-buffering
* Further refinement: Per-LED twinkle
* Add documentation for Twinkle RBG Lighting mode
* Bias twinkle saturation closer to the set value
* Fix whitespace
| -rw-r--r-- | docs/feature_rgblight.md | 11 | ||||
| -rw-r--r-- | quantum/rgblight.c | 65 | ||||
| -rw-r--r-- | quantum/rgblight.h | 20 | ||||
| -rw-r--r-- | quantum/rgblight_modes.h | 8 |
4 files changed, 100 insertions, 4 deletions
diff --git a/docs/feature_rgblight.md b/docs/feature_rgblight.md index de19b7419..045d97775 100644 --- a/docs/feature_rgblight.md +++ b/docs/feature_rgblight.md | |||
| @@ -94,6 +94,7 @@ if `RGBLIGHT_EFFECT_xxxx` or `RGBLIGHT_ANIMATIONS` is defined, you also have a n | |||
| 94 | |`RGBLIGHT_MODE_STATIC_GRADIENT`| 0,1,..,9 |Static gradient | | 94 | |`RGBLIGHT_MODE_STATIC_GRADIENT`| 0,1,..,9 |Static gradient | |
| 95 | |`RGBLIGHT_MODE_RGB_TEST` | *None* |RGB Test | | 95 | |`RGBLIGHT_MODE_RGB_TEST` | *None* |RGB Test | |
| 96 | |`RGBLIGHT_MODE_ALTERNATING` | *None* |Alternating | | 96 | |`RGBLIGHT_MODE_ALTERNATING` | *None* |Alternating | |
| 97 | |`RGBLIGHT_MODE_TWINKLE` | 0,1,2,3,4,5 |Twinkle | | ||
| 97 | 98 | ||
| 98 | Check out [this video](https://youtube.com/watch?v=VKrpPAHlisY) for a demonstration. | 99 | Check out [this video](https://youtube.com/watch?v=VKrpPAHlisY) for a demonstration. |
| 99 | 100 | ||
| @@ -103,8 +104,8 @@ Note: For versions older than 0.6.117, The mode numbers were written directly. I | |||
| 103 | 104 | ||
| 104 | Use these defines to add or remove animations from the firmware. When you are running low on flash space, it can be helpful to disable animations you are not using. | 105 | Use these defines to add or remove animations from the firmware. When you are running low on flash space, it can be helpful to disable animations you are not using. |
| 105 | 106 | ||
| 106 | |Define |Default |Description | | 107 | |Define |Default |Description | |
| 107 | |------------------------------------|-------------|-------------------------------------------------------------------------------------| | 108 | |------------------------------------|-------------|-------------------------------------------------------------------------| |
| 108 | |`RGBLIGHT_ANIMATIONS` |*Not defined*|Enable all additional animation modes. | | 109 | |`RGBLIGHT_ANIMATIONS` |*Not defined*|Enable all additional animation modes. | |
| 109 | |`RGBLIGHT_EFFECT_ALTERNATING` |*Not defined*|Enable alternating animation mode. | | 110 | |`RGBLIGHT_EFFECT_ALTERNATING` |*Not defined*|Enable alternating animation mode. | |
| 110 | |`RGBLIGHT_EFFECT_BREATHING` |*Not defined*|Enable breathing animation mode. | | 111 | |`RGBLIGHT_EFFECT_BREATHING` |*Not defined*|Enable breathing animation mode. | |
| @@ -115,6 +116,7 @@ Use these defines to add or remove animations from the firmware. When you are ru | |||
| 115 | |`RGBLIGHT_EFFECT_RGB_TEST` |*Not defined*|Enable RGB test animation mode. | | 116 | |`RGBLIGHT_EFFECT_RGB_TEST` |*Not defined*|Enable RGB test animation mode. | |
| 116 | |`RGBLIGHT_EFFECT_SNAKE` |*Not defined*|Enable snake animation mode. | | 117 | |`RGBLIGHT_EFFECT_SNAKE` |*Not defined*|Enable snake animation mode. | |
| 117 | |`RGBLIGHT_EFFECT_STATIC_GRADIENT` |*Not defined*|Enable static gradient mode. | | 118 | |`RGBLIGHT_EFFECT_STATIC_GRADIENT` |*Not defined*|Enable static gradient mode. | |
| 119 | |`RGBLIGHT_EFFECT_TWINKLE` |*Not defined*|Enable twinkle animation mode. | | ||
| 118 | 120 | ||
| 119 | ### Effect and Animation Settings | 121 | ### Effect and Animation Settings |
| 120 | 122 | ||
| @@ -131,6 +133,8 @@ The following options are used to tweak the various animations: | |||
| 131 | |`RGBLIGHT_EFFECT_KNIGHT_OFFSET` |`0` |The number of LEDs to start the "Knight" animation from the start of the strip by | | 133 | |`RGBLIGHT_EFFECT_KNIGHT_OFFSET` |`0` |The number of LEDs to start the "Knight" animation from the start of the strip by | |
| 132 | |`RGBLIGHT_RAINBOW_SWIRL_RANGE` |`255` |Range adjustment for the rainbow swirl effect to get different swirls | | 134 | |`RGBLIGHT_RAINBOW_SWIRL_RANGE` |`255` |Range adjustment for the rainbow swirl effect to get different swirls | |
| 133 | |`RGBLIGHT_EFFECT_SNAKE_LENGTH` |`4` |The number of LEDs to light up for the "Snake" animation | | 135 | |`RGBLIGHT_EFFECT_SNAKE_LENGTH` |`4` |The number of LEDs to light up for the "Snake" animation | |
| 136 | |`RGBLIGHT_EFFECT_TWINKLE_LIFE` |`75` |Adjusts how quickly each LED brightens and dims when twinkling (in animation steps) | | ||
| 137 | |`RGBLIGHT_EFFECT_TWINKLE_PROBABILITY`|`1/127` |Adjusts how likely each LED is to twinkle (on each animation step) | | ||
| 134 | 138 | ||
| 135 | ### Example Usage to Reduce Memory Footprint | 139 | ### Example Usage to Reduce Memory Footprint |
| 136 | 1. Remove `RGBLIGHT_ANIMATIONS` from `config.h`. | 140 | 1. Remove `RGBLIGHT_ANIMATIONS` from `config.h`. |
| @@ -168,6 +172,9 @@ const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {100, 50, 20}; | |||
| 168 | // How long (in milliseconds) to wait between animation steps for each of the "Knight" animations | 172 | // How long (in milliseconds) to wait between animation steps for each of the "Knight" animations |
| 169 | const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {127, 63, 31}; | 173 | const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {127, 63, 31}; |
| 170 | 174 | ||
| 175 | // How long (in milliseconds) to wait between animation steps for each of the "Twinkle" animations | ||
| 176 | const uint8_t RGBLED_TWINKLE_INTERVALS[] PROGMEM = {50, 25, 10}; | ||
| 177 | |||
| 171 | // These control which hues are selected for each of the "Static gradient" modes | 178 | // These control which hues are selected for each of the "Static gradient" modes |
| 172 | const uint8_t RGBLED_GRADIENT_RANGES[] PROGMEM = {255, 170, 127, 85, 64}; | 179 | const uint8_t RGBLED_GRADIENT_RANGES[] PROGMEM = {255, 170, 127, 85, 64}; |
| 173 | ``` | 180 | ``` |
diff --git a/quantum/rgblight.c b/quantum/rgblight.c index 33326fa86..8d01bcf0e 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> |
| @@ -561,7 +562,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); | 562 | rgblight_setrgb_at(tmp_led.r, tmp_led.g, tmp_led.b, index); |
| 562 | } | 563 | } |
| 563 | 564 | ||
| 564 | #if defined(RGBLIGHT_EFFECT_BREATHING) || defined(RGBLIGHT_EFFECT_RAINBOW_MOOD) || defined(RGBLIGHT_EFFECT_RAINBOW_SWIRL) || defined(RGBLIGHT_EFFECT_SNAKE) || defined(RGBLIGHT_EFFECT_KNIGHT) | 565 | #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 | 566 | ||
| 566 | static uint8_t get_interval_time(const uint8_t *default_interval_address, uint8_t velocikey_min, uint8_t velocikey_max) { | 567 | static uint8_t get_interval_time(const uint8_t *default_interval_address, uint8_t velocikey_min, uint8_t velocikey_max) { |
| 567 | return | 568 | return |
| @@ -905,6 +906,12 @@ void rgblight_task(void) { | |||
| 905 | effect_func = (effect_func_t)rgblight_effect_alternating; | 906 | effect_func = (effect_func_t)rgblight_effect_alternating; |
| 906 | } | 907 | } |
| 907 | # endif | 908 | # endif |
| 909 | # ifdef RGBLIGHT_EFFECT_TWINKLE | ||
| 910 | else if (rgblight_status.base_mode == RGBLIGHT_MODE_TWINKLE) { | ||
| 911 | interval_time = get_interval_time(&RGBLED_TWINKLE_INTERVALS[delta % 3], 5, 50); | ||
| 912 | effect_func = (effect_func_t)rgblight_effect_twinkle; | ||
| 913 | } | ||
| 914 | # endif | ||
| 908 | if (animation_status.restart) { | 915 | if (animation_status.restart) { |
| 909 | animation_status.restart = false; | 916 | animation_status.restart = false; |
| 910 | animation_status.last_timer = timer_read() - interval_time - 1; | 917 | animation_status.last_timer = timer_read() - interval_time - 1; |
| @@ -1189,3 +1196,59 @@ void rgblight_effect_alternating(animation_status_t *anim) { | |||
| 1189 | anim->pos = (anim->pos + 1) % 2; | 1196 | anim->pos = (anim->pos + 1) % 2; |
| 1190 | } | 1197 | } |
| 1191 | #endif | 1198 | #endif |
| 1199 | |||
| 1200 | #ifdef RGBLIGHT_EFFECT_TWINKLE | ||
| 1201 | __attribute__((weak)) const uint8_t RGBLED_TWINKLE_INTERVALS[] PROGMEM = {50, 25, 10}; | ||
| 1202 | |||
| 1203 | typedef struct PACKED { | ||
| 1204 | HSV hsv; | ||
| 1205 | uint8_t life; | ||
| 1206 | bool up; | ||
| 1207 | } TwinkleState; | ||
| 1208 | |||
| 1209 | static TwinkleState led_twinkle_state[RGBLED_NUM]; | ||
| 1210 | |||
| 1211 | void rgblight_effect_twinkle(animation_status_t *anim) { | ||
| 1212 | |||
| 1213 | bool random_color = anim->delta / 3; | ||
| 1214 | bool restart = anim->pos == 0; | ||
| 1215 | anim->pos = 1; | ||
| 1216 | |||
| 1217 | for (uint8_t i = 0; i < rgblight_ranges.effect_num_leds; i++) { | ||
| 1218 | TwinkleState *t = &(led_twinkle_state[i]); | ||
| 1219 | HSV *c = &(t->hsv); | ||
| 1220 | if (restart) { | ||
| 1221 | // Restart | ||
| 1222 | t->life = 0; | ||
| 1223 | t->hsv.v = 0; | ||
| 1224 | } else if (t->life) { | ||
| 1225 | // This LED is already on, either brightening or dimming | ||
| 1226 | t->life--; | ||
| 1227 | uint8_t on = t->up ? RGBLIGHT_EFFECT_TWINKLE_LIFE - t->life : t->life; | ||
| 1228 | c->v = (uint16_t) rgblight_config.val * on / RGBLIGHT_EFFECT_TWINKLE_LIFE; | ||
| 1229 | if (t->life == 0 && t->up) { | ||
| 1230 | t->up = false; | ||
| 1231 | t->life = RGBLIGHT_EFFECT_TWINKLE_LIFE; | ||
| 1232 | } | ||
| 1233 | if (!random_color) { | ||
| 1234 | c->h = rgblight_config.hue; | ||
| 1235 | c->s = rgblight_config.sat; | ||
| 1236 | } | ||
| 1237 | } else if (rand() < RAND_MAX * RGBLIGHT_EFFECT_TWINKLE_PROBABILITY) { | ||
| 1238 | // This LED is off, but was randomly selected to start brightening | ||
| 1239 | c->h = random_color ? rand() % 0xFF : rgblight_config.hue; | ||
| 1240 | c->s = random_color ? (rand() % (rgblight_config.sat / 2)) + (rgblight_config.sat / 2) : rgblight_config.sat; | ||
| 1241 | c->v = 0; | ||
| 1242 | t->life = RGBLIGHT_EFFECT_TWINKLE_LIFE; | ||
| 1243 | t->up = true; | ||
| 1244 | } else { | ||
| 1245 | // This LED is off, and was NOT selected to start brightening | ||
| 1246 | } | ||
| 1247 | |||
| 1248 | LED_TYPE *ledp = led + i + rgblight_ranges.effect_start_pos; | ||
| 1249 | sethsv(c->h, c->s, c->v, ledp); | ||
| 1250 | } | ||
| 1251 | |||
| 1252 | rgblight_set(); | ||
| 1253 | } | ||
| 1254 | #endif | ||
diff --git a/quantum/rgblight.h b/quantum/rgblight.h index e06073728..7de9c3f3d 100644 --- a/quantum/rgblight.h +++ b/quantum/rgblight.h | |||
| @@ -59,6 +59,12 @@ | |||
| 59 | | 34 | RGBLIGHT_MODE_STATIC_GRADIENT + 9 | | 59 | | 34 | RGBLIGHT_MODE_STATIC_GRADIENT + 9 | |
| 60 | | 35 | RGBLIGHT_MODE_RGB_TEST | | 60 | | 35 | RGBLIGHT_MODE_RGB_TEST | |
| 61 | | 36 | RGBLIGHT_MODE_ALTERNATING | | 61 | | 36 | RGBLIGHT_MODE_ALTERNATING | |
| 62 | | 37 | RGBLIGHT_MODE_TWINKLE | | ||
| 63 | | 38 | RGBLIGHT_MODE_TWINKLE + 1 | | ||
| 64 | | 39 | RGBLIGHT_MODE_TWINKLE + 2 | | ||
| 65 | | 40 | RGBLIGHT_MODE_TWINKLE + 3 | | ||
| 66 | | 41 | RGBLIGHT_MODE_TWINKLE + 4 | | ||
| 67 | | 42 | RGBLIGHT_MODE_TWINKLE + 5 | | ||
| 62 | |-----------------|-----------------------------------| | 68 | |-----------------|-----------------------------------| |
| 63 | *****/ | 69 | *****/ |
| 64 | 70 | ||
| @@ -73,6 +79,7 @@ | |||
| 73 | # define RGBLIGHT_EFFECT_STATIC_GRADIENT | 79 | # define RGBLIGHT_EFFECT_STATIC_GRADIENT |
| 74 | # define RGBLIGHT_EFFECT_RGB_TEST | 80 | # define RGBLIGHT_EFFECT_RGB_TEST |
| 75 | # define RGBLIGHT_EFFECT_ALTERNATING | 81 | # define RGBLIGHT_EFFECT_ALTERNATING |
| 82 | # define RGBLIGHT_EFFECT_TWINKLE | ||
| 76 | #endif | 83 | #endif |
| 77 | 84 | ||
| 78 | #ifdef RGBLIGHT_STATIC_PATTERNS | 85 | #ifdef RGBLIGHT_STATIC_PATTERNS |
| @@ -89,7 +96,8 @@ | |||
| 89 | || defined(RGBLIGHT_EFFECT_KNIGHT) \ | 96 | || defined(RGBLIGHT_EFFECT_KNIGHT) \ |
| 90 | || defined(RGBLIGHT_EFFECT_CHRISTMAS) \ | 97 | || defined(RGBLIGHT_EFFECT_CHRISTMAS) \ |
| 91 | || defined(RGBLIGHT_EFFECT_RGB_TEST) \ | 98 | || defined(RGBLIGHT_EFFECT_RGB_TEST) \ |
| 92 | || defined(RGBLIGHT_EFFECT_ALTERNATING) | 99 | || defined(RGBLIGHT_EFFECT_ALTERNATING) \ |
| 100 | || defined(RGBLIGHT_EFFECT_TWINKLE) | ||
| 93 | # define RGBLIGHT_USE_TIMER | 101 | # define RGBLIGHT_USE_TIMER |
| 94 | #endif | 102 | #endif |
| 95 | 103 | ||
| @@ -141,6 +149,14 @@ enum RGBLIGHT_EFFECT_MODE { | |||
| 141 | # define RGBLIGHT_EFFECT_CHRISTMAS_STEP 2 | 149 | # define RGBLIGHT_EFFECT_CHRISTMAS_STEP 2 |
| 142 | # endif | 150 | # endif |
| 143 | 151 | ||
| 152 | # ifndef RGBLIGHT_EFFECT_TWINKLE_LIFE | ||
| 153 | # define RGBLIGHT_EFFECT_TWINKLE_LIFE 75 | ||
| 154 | # endif | ||
| 155 | |||
| 156 | # ifndef RGBLIGHT_EFFECT_TWINKLE_PROBABILITY | ||
| 157 | # define RGBLIGHT_EFFECT_TWINKLE_PROBABILITY 1/127 | ||
| 158 | # endif | ||
| 159 | |||
| 144 | # ifndef RGBLIGHT_HUE_STEP | 160 | # ifndef RGBLIGHT_HUE_STEP |
| 145 | # define RGBLIGHT_HUE_STEP 8 | 161 | # define RGBLIGHT_HUE_STEP 8 |
| 146 | # endif | 162 | # endif |
| @@ -208,6 +224,7 @@ extern const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[3] PROGMEM; | |||
| 208 | extern const uint8_t RGBLED_SNAKE_INTERVALS[3] PROGMEM; | 224 | extern const uint8_t RGBLED_SNAKE_INTERVALS[3] PROGMEM; |
| 209 | extern const uint8_t RGBLED_KNIGHT_INTERVALS[3] PROGMEM; | 225 | extern const uint8_t RGBLED_KNIGHT_INTERVALS[3] PROGMEM; |
| 210 | extern const uint16_t RGBLED_RGBTEST_INTERVALS[1] PROGMEM; | 226 | extern const uint16_t RGBLED_RGBTEST_INTERVALS[1] PROGMEM; |
| 227 | extern const uint8_t RGBLED_TWINKLE_INTERVALS[3] PROGMEM; | ||
| 211 | extern bool is_rgblight_initialized; | 228 | extern bool is_rgblight_initialized; |
| 212 | 229 | ||
| 213 | // Should stay in sycn with rgb matrix config as we reuse eeprom storage for both (for now) | 230 | // Should stay in sycn with rgb matrix config as we reuse eeprom storage for both (for now) |
| @@ -398,6 +415,7 @@ void rgblight_effect_knight(animation_status_t *anim); | |||
| 398 | void rgblight_effect_christmas(animation_status_t *anim); | 415 | void rgblight_effect_christmas(animation_status_t *anim); |
| 399 | void rgblight_effect_rgbtest(animation_status_t *anim); | 416 | void rgblight_effect_rgbtest(animation_status_t *anim); |
| 400 | void rgblight_effect_alternating(animation_status_t *anim); | 417 | void rgblight_effect_alternating(animation_status_t *anim); |
| 418 | void rgblight_effect_twinkle(animation_status_t *anim); | ||
| 401 | 419 | ||
| 402 | # endif | 420 | # endif |
| 403 | 421 | ||
diff --git a/quantum/rgblight_modes.h b/quantum/rgblight_modes.h index 40c9ce498..7abdb87bc 100644 --- a/quantum/rgblight_modes.h +++ b/quantum/rgblight_modes.h | |||
| @@ -53,6 +53,14 @@ _RGBM_SINGLE_DYNAMIC(RGB_TEST) | |||
| 53 | # ifdef RGBLIGHT_EFFECT_ALTERNATING | 53 | # ifdef RGBLIGHT_EFFECT_ALTERNATING |
| 54 | _RGBM_SINGLE_DYNAMIC(ALTERNATING) | 54 | _RGBM_SINGLE_DYNAMIC(ALTERNATING) |
| 55 | # endif | 55 | # endif |
| 56 | # ifdef RGBLIGHT_EFFECT_TWINKLE | ||
| 57 | _RGBM_MULTI_DYNAMIC(TWINKLE) | ||
| 58 | _RGBM_TMP_DYNAMIC(twinkle_38, TWINKLE) | ||
| 59 | _RGBM_TMP_DYNAMIC(twinkle_39, TWINKLE) | ||
| 60 | _RGBM_TMP_DYNAMIC(twinkle_40, TWINKLE) | ||
| 61 | _RGBM_TMP_DYNAMIC(twinkle_41, TWINKLE) | ||
| 62 | _RGBM_TMP_DYNAMIC(TWINKLE_end, TWINKLE) | ||
| 63 | # endif | ||
| 56 | //// Add a new mode here. | 64 | //// Add a new mode here. |
| 57 | // #ifdef RGBLIGHT_EFFECT_<name> | 65 | // #ifdef RGBLIGHT_EFFECT_<name> |
| 58 | // _RGBM_<SINGLE|MULTI>_<STATIC|DYNAMIC>( <name> ) | 66 | // _RGBM_<SINGLE|MULTI>_<STATIC|DYNAMIC>( <name> ) |
