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
master
Joshua Diamond 2020-05-09 04:56:16 -04:00 committed by GitHub
parent e0f548085c
commit 2fe7e221ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 100 additions and 4 deletions

View File

@ -94,6 +94,7 @@ if `RGBLIGHT_EFFECT_xxxx` or `RGBLIGHT_ANIMATIONS` is defined, you also have a n
|`RGBLIGHT_MODE_STATIC_GRADIENT`| 0,1,..,9 |Static gradient | |`RGBLIGHT_MODE_STATIC_GRADIENT`| 0,1,..,9 |Static gradient |
|`RGBLIGHT_MODE_RGB_TEST` | *None* |RGB Test | |`RGBLIGHT_MODE_RGB_TEST` | *None* |RGB Test |
|`RGBLIGHT_MODE_ALTERNATING` | *None* |Alternating | |`RGBLIGHT_MODE_ALTERNATING` | *None* |Alternating |
|`RGBLIGHT_MODE_TWINKLE` | 0,1,2,3,4,5 |Twinkle |
Check out [this video](https://youtube.com/watch?v=VKrpPAHlisY) for a demonstration. Check out [this video](https://youtube.com/watch?v=VKrpPAHlisY) for a demonstration.
@ -103,8 +104,8 @@ Note: For versions older than 0.6.117, The mode numbers were written directly. I
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. 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.
|Define |Default |Description | |Define |Default |Description |
|------------------------------------|-------------|-------------------------------------------------------------------------------------| |------------------------------------|-------------|-------------------------------------------------------------------------|
|`RGBLIGHT_ANIMATIONS` |*Not defined*|Enable all additional animation modes. | |`RGBLIGHT_ANIMATIONS` |*Not defined*|Enable all additional animation modes. |
|`RGBLIGHT_EFFECT_ALTERNATING` |*Not defined*|Enable alternating animation mode. | |`RGBLIGHT_EFFECT_ALTERNATING` |*Not defined*|Enable alternating animation mode. |
|`RGBLIGHT_EFFECT_BREATHING` |*Not defined*|Enable breathing animation mode. | |`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
|`RGBLIGHT_EFFECT_RGB_TEST` |*Not defined*|Enable RGB test animation mode. | |`RGBLIGHT_EFFECT_RGB_TEST` |*Not defined*|Enable RGB test animation mode. |
|`RGBLIGHT_EFFECT_SNAKE` |*Not defined*|Enable snake animation mode. | |`RGBLIGHT_EFFECT_SNAKE` |*Not defined*|Enable snake animation mode. |
|`RGBLIGHT_EFFECT_STATIC_GRADIENT` |*Not defined*|Enable static gradient mode. | |`RGBLIGHT_EFFECT_STATIC_GRADIENT` |*Not defined*|Enable static gradient mode. |
|`RGBLIGHT_EFFECT_TWINKLE` |*Not defined*|Enable twinkle animation mode. |
### Effect and Animation Settings ### Effect and Animation Settings
@ -131,6 +133,8 @@ The following options are used to tweak the various animations:
|`RGBLIGHT_EFFECT_KNIGHT_OFFSET` |`0` |The number of LEDs to start the "Knight" animation from the start of the strip by | |`RGBLIGHT_EFFECT_KNIGHT_OFFSET` |`0` |The number of LEDs to start the "Knight" animation from the start of the strip by |
|`RGBLIGHT_RAINBOW_SWIRL_RANGE` |`255` |Range adjustment for the rainbow swirl effect to get different swirls | |`RGBLIGHT_RAINBOW_SWIRL_RANGE` |`255` |Range adjustment for the rainbow swirl effect to get different swirls |
|`RGBLIGHT_EFFECT_SNAKE_LENGTH` |`4` |The number of LEDs to light up for the "Snake" animation | |`RGBLIGHT_EFFECT_SNAKE_LENGTH` |`4` |The number of LEDs to light up for the "Snake" animation |
|`RGBLIGHT_EFFECT_TWINKLE_LIFE` |`75` |Adjusts how quickly each LED brightens and dims when twinkling (in animation steps) |
|`RGBLIGHT_EFFECT_TWINKLE_PROBABILITY`|`1/127` |Adjusts how likely each LED is to twinkle (on each animation step) |
### Example Usage to Reduce Memory Footprint ### Example Usage to Reduce Memory Footprint
1. Remove `RGBLIGHT_ANIMATIONS` from `config.h`. 1. Remove `RGBLIGHT_ANIMATIONS` from `config.h`.
@ -168,6 +172,9 @@ const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {100, 50, 20};
// How long (in milliseconds) to wait between animation steps for each of the "Knight" animations // How long (in milliseconds) to wait between animation steps for each of the "Knight" animations
const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {127, 63, 31}; const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {127, 63, 31};
// How long (in milliseconds) to wait between animation steps for each of the "Twinkle" animations
const uint8_t RGBLED_TWINKLE_INTERVALS[] PROGMEM = {50, 25, 10};
// These control which hues are selected for each of the "Static gradient" modes // These control which hues are selected for each of the "Static gradient" modes
const uint8_t RGBLED_GRADIENT_RANGES[] PROGMEM = {255, 170, 127, 85, 64}; const uint8_t RGBLED_GRADIENT_RANGES[] PROGMEM = {255, 170, 127, 85, 64};
``` ```

View File

@ -15,6 +15,7 @@
*/ */
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
#ifdef __AVR__ #ifdef __AVR__
# include <avr/eeprom.h> # include <avr/eeprom.h>
# include <avr/interrupt.h> # include <avr/interrupt.h>
@ -561,7 +562,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); 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) { static uint8_t get_interval_time(const uint8_t *default_interval_address, uint8_t velocikey_min, uint8_t velocikey_max) {
return return
@ -904,6 +905,12 @@ void rgblight_task(void) {
interval_time = 500; interval_time = 500;
effect_func = (effect_func_t)rgblight_effect_alternating; 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 # endif
if (animation_status.restart) { if (animation_status.restart) {
animation_status.restart = false; animation_status.restart = false;
@ -1189,3 +1196,59 @@ void rgblight_effect_alternating(animation_status_t *anim) {
anim->pos = (anim->pos + 1) % 2; anim->pos = (anim->pos + 1) % 2;
} }
#endif #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

View File

@ -59,6 +59,12 @@
| 34 | RGBLIGHT_MODE_STATIC_GRADIENT + 9 | | 34 | RGBLIGHT_MODE_STATIC_GRADIENT + 9 |
| 35 | RGBLIGHT_MODE_RGB_TEST | | 35 | RGBLIGHT_MODE_RGB_TEST |
| 36 | RGBLIGHT_MODE_ALTERNATING | | 36 | RGBLIGHT_MODE_ALTERNATING |
| 37 | RGBLIGHT_MODE_TWINKLE |
| 38 | RGBLIGHT_MODE_TWINKLE + 1 |
| 39 | RGBLIGHT_MODE_TWINKLE + 2 |
| 40 | RGBLIGHT_MODE_TWINKLE + 3 |
| 41 | RGBLIGHT_MODE_TWINKLE + 4 |
| 42 | RGBLIGHT_MODE_TWINKLE + 5 |
|-----------------|-----------------------------------| |-----------------|-----------------------------------|
*****/ *****/
@ -73,6 +79,7 @@
# define RGBLIGHT_EFFECT_STATIC_GRADIENT # define RGBLIGHT_EFFECT_STATIC_GRADIENT
# define RGBLIGHT_EFFECT_RGB_TEST # define RGBLIGHT_EFFECT_RGB_TEST
# define RGBLIGHT_EFFECT_ALTERNATING # define RGBLIGHT_EFFECT_ALTERNATING
# define RGBLIGHT_EFFECT_TWINKLE
#endif #endif
#ifdef RGBLIGHT_STATIC_PATTERNS #ifdef RGBLIGHT_STATIC_PATTERNS
@ -89,7 +96,8 @@
|| defined(RGBLIGHT_EFFECT_KNIGHT) \ || defined(RGBLIGHT_EFFECT_KNIGHT) \
|| defined(RGBLIGHT_EFFECT_CHRISTMAS) \ || defined(RGBLIGHT_EFFECT_CHRISTMAS) \
|| defined(RGBLIGHT_EFFECT_RGB_TEST) \ || defined(RGBLIGHT_EFFECT_RGB_TEST) \
|| defined(RGBLIGHT_EFFECT_ALTERNATING) || defined(RGBLIGHT_EFFECT_ALTERNATING) \
|| defined(RGBLIGHT_EFFECT_TWINKLE)
# define RGBLIGHT_USE_TIMER # define RGBLIGHT_USE_TIMER
#endif #endif
@ -141,6 +149,14 @@ enum RGBLIGHT_EFFECT_MODE {
# define RGBLIGHT_EFFECT_CHRISTMAS_STEP 2 # define RGBLIGHT_EFFECT_CHRISTMAS_STEP 2
# endif # endif
# ifndef RGBLIGHT_EFFECT_TWINKLE_LIFE
# define RGBLIGHT_EFFECT_TWINKLE_LIFE 75
# endif
# ifndef RGBLIGHT_EFFECT_TWINKLE_PROBABILITY
# define RGBLIGHT_EFFECT_TWINKLE_PROBABILITY 1/127
# endif
# ifndef RGBLIGHT_HUE_STEP # ifndef RGBLIGHT_HUE_STEP
# define RGBLIGHT_HUE_STEP 8 # define RGBLIGHT_HUE_STEP 8
# endif # endif
@ -208,6 +224,7 @@ extern const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[3] PROGMEM;
extern const uint8_t RGBLED_SNAKE_INTERVALS[3] PROGMEM; extern const uint8_t RGBLED_SNAKE_INTERVALS[3] PROGMEM;
extern const uint8_t RGBLED_KNIGHT_INTERVALS[3] PROGMEM; extern const uint8_t RGBLED_KNIGHT_INTERVALS[3] PROGMEM;
extern const uint16_t RGBLED_RGBTEST_INTERVALS[1] PROGMEM; extern const uint16_t RGBLED_RGBTEST_INTERVALS[1] PROGMEM;
extern const uint8_t RGBLED_TWINKLE_INTERVALS[3] PROGMEM;
extern bool is_rgblight_initialized; extern bool is_rgblight_initialized;
// Should stay in sycn with rgb matrix config as we reuse eeprom storage for both (for now) // 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);
void rgblight_effect_christmas(animation_status_t *anim); void rgblight_effect_christmas(animation_status_t *anim);
void rgblight_effect_rgbtest(animation_status_t *anim); void rgblight_effect_rgbtest(animation_status_t *anim);
void rgblight_effect_alternating(animation_status_t *anim); void rgblight_effect_alternating(animation_status_t *anim);
void rgblight_effect_twinkle(animation_status_t *anim);
# endif # endif

View File

@ -53,6 +53,14 @@ _RGBM_SINGLE_DYNAMIC(RGB_TEST)
# ifdef RGBLIGHT_EFFECT_ALTERNATING # ifdef RGBLIGHT_EFFECT_ALTERNATING
_RGBM_SINGLE_DYNAMIC(ALTERNATING) _RGBM_SINGLE_DYNAMIC(ALTERNATING)
# endif # endif
# ifdef RGBLIGHT_EFFECT_TWINKLE
_RGBM_MULTI_DYNAMIC(TWINKLE)
_RGBM_TMP_DYNAMIC(twinkle_38, TWINKLE)
_RGBM_TMP_DYNAMIC(twinkle_39, TWINKLE)
_RGBM_TMP_DYNAMIC(twinkle_40, TWINKLE)
_RGBM_TMP_DYNAMIC(twinkle_41, TWINKLE)
_RGBM_TMP_DYNAMIC(TWINKLE_end, TWINKLE)
# endif
//// Add a new mode here. //// Add a new mode here.
// #ifdef RGBLIGHT_EFFECT_<name> // #ifdef RGBLIGHT_EFFECT_<name>
// _RGBM_<SINGLE|MULTI>_<STATIC|DYNAMIC>( <name> ) // _RGBM_<SINGLE|MULTI>_<STATIC|DYNAMIC>( <name> )