aboutsummaryrefslogtreecommitdiff
path: root/quantum/rgblight.c
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/rgblight.c')
-rw-r--r--quantum/rgblight.c100
1 files changed, 57 insertions, 43 deletions
diff --git a/quantum/rgblight.c b/quantum/rgblight.c
index ac4ff9bfd..7d7d015ba 100644
--- a/quantum/rgblight.c
+++ b/quantum/rgblight.c
@@ -29,7 +29,7 @@
29#endif 29#endif
30#include "wait.h" 30#include "wait.h"
31#include "progmem.h" 31#include "progmem.h"
32#include "timer.h" 32#include "sync_timer.h"
33#include "rgblight.h" 33#include "rgblight.h"
34#include "color.h" 34#include "color.h"
35#include "debug.h" 35#include "debug.h"
@@ -42,6 +42,9 @@
42#ifndef MIN 42#ifndef MIN
43# define MIN(a, b) (((a) < (b)) ? (a) : (b)) 43# define MIN(a, b) (((a) < (b)) ? (a) : (b))
44#endif 44#endif
45#ifndef MAX
46# define MAX(a, b) (((a) > (b)) ? (a) : (b))
47#endif
45 48
46#ifdef RGBLIGHT_SPLIT 49#ifdef RGBLIGHT_SPLIT
47/* for split keyboard */ 50/* for split keyboard */
@@ -700,18 +703,16 @@ static void rgblight_layers_write(void) {
700 703
701# ifdef RGBLIGHT_LAYER_BLINK 704# ifdef RGBLIGHT_LAYER_BLINK
702rgblight_layer_mask_t _blinked_layer_mask = 0; 705rgblight_layer_mask_t _blinked_layer_mask = 0;
703uint16_t _blink_duration = 0;
704static uint16_t _blink_timer; 706static uint16_t _blink_timer;
705 707
706void rgblight_blink_layer(uint8_t layer, uint16_t duration_ms) { 708void rgblight_blink_layer(uint8_t layer, uint16_t duration_ms) {
707 rgblight_set_layer_state(layer, true); 709 rgblight_set_layer_state(layer, true);
708 _blinked_layer_mask |= (rgblight_layer_mask_t)1 << layer; 710 _blinked_layer_mask |= (rgblight_layer_mask_t)1 << layer;
709 _blink_timer = timer_read(); 711 _blink_timer = sync_timer_read() + duration_ms;
710 _blink_duration = duration_ms;
711} 712}
712 713
713void rgblight_unblink_layers(void) { 714void rgblight_unblink_layers(void) {
714 if (_blinked_layer_mask != 0 && timer_elapsed(_blink_timer) > _blink_duration) { 715 if (_blinked_layer_mask != 0 && timer_expired(sync_timer_read(), _blink_timer)) {
715 for (uint8_t layer = 0; layer < RGBLIGHT_MAX_LAYERS; layer++) { 716 for (uint8_t layer = 0; layer < RGBLIGHT_MAX_LAYERS; layer++) {
716 if ((_blinked_layer_mask & (rgblight_layer_mask_t)1 << layer) != 0) { 717 if ((_blinked_layer_mask & (rgblight_layer_mask_t)1 << layer) != 0) {
717 rgblight_set_layer_state(layer, false); 718 rgblight_set_layer_state(layer, false);
@@ -886,7 +887,7 @@ void rgblight_timer_enable(void) {
886 if (!is_static_effect(rgblight_config.mode)) { 887 if (!is_static_effect(rgblight_config.mode)) {
887 rgblight_status.timer_enabled = true; 888 rgblight_status.timer_enabled = true;
888 } 889 }
889 animation_status.last_timer = timer_read(); 890 animation_status.last_timer = sync_timer_read();
890 RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE; 891 RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE;
891 dprintf("rgblight timer enabled.\n"); 892 dprintf("rgblight timer enabled.\n");
892} 893}
@@ -989,24 +990,25 @@ void rgblight_task(void) {
989# endif 990# endif
990# ifdef RGBLIGHT_EFFECT_TWINKLE 991# ifdef RGBLIGHT_EFFECT_TWINKLE
991 else if (rgblight_status.base_mode == RGBLIGHT_MODE_TWINKLE) { 992 else if (rgblight_status.base_mode == RGBLIGHT_MODE_TWINKLE) {
992 interval_time = get_interval_time(&RGBLED_TWINKLE_INTERVALS[delta % 3], 5, 50); 993 interval_time = get_interval_time(&RGBLED_TWINKLE_INTERVALS[delta % 3], 5, 30);
993 effect_func = (effect_func_t)rgblight_effect_twinkle; 994 effect_func = (effect_func_t)rgblight_effect_twinkle;
994 } 995 }
995# endif 996# endif
996 if (animation_status.restart) { 997 if (animation_status.restart) {
997 animation_status.restart = false; 998 animation_status.restart = false;
998 animation_status.last_timer = timer_read() - interval_time - 1; 999 animation_status.last_timer = sync_timer_read();
999 animation_status.pos16 = 0; // restart signal to local each effect 1000 animation_status.pos16 = 0; // restart signal to local each effect
1000 } 1001 }
1001 if (timer_elapsed(animation_status.last_timer) >= interval_time) { 1002 uint16_t now = sync_timer_read();
1003 if (timer_expired(now, animation_status.last_timer)) {
1002# if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) 1004# if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
1003 static uint16_t report_last_timer = 0; 1005 static uint16_t report_last_timer = 0;
1004 static bool tick_flag = false; 1006 static bool tick_flag = false;
1005 uint16_t oldpos16; 1007 uint16_t oldpos16;
1006 if (tick_flag) { 1008 if (tick_flag) {
1007 tick_flag = false; 1009 tick_flag = false;
1008 if (timer_elapsed(report_last_timer) >= 30000) { 1010 if (timer_expired(now, report_last_timer)) {
1009 report_last_timer = timer_read(); 1011 report_last_timer += 30000;
1010 dprintf("rgblight animation tick report to slave\n"); 1012 dprintf("rgblight animation tick report to slave\n");
1011 RGBLIGHT_SPLIT_ANIMATION_TICK; 1013 RGBLIGHT_SPLIT_ANIMATION_TICK;
1012 } 1014 }
@@ -1030,8 +1032,7 @@ void rgblight_task(void) {
1030 1032
1031#endif /* RGBLIGHT_USE_TIMER */ 1033#endif /* RGBLIGHT_USE_TIMER */
1032 1034
1033// Effects 1035#if defined(RGBLIGHT_EFFECT_BREATHING) || defined(RGBLIGHT_EFFECT_TWINKLE)
1034#ifdef RGBLIGHT_EFFECT_BREATHING
1035 1036
1036# ifndef RGBLIGHT_EFFECT_BREATHE_CENTER 1037# ifndef RGBLIGHT_EFFECT_BREATHE_CENTER
1037# ifndef RGBLIGHT_BREATHE_TABLE_SIZE 1038# ifndef RGBLIGHT_BREATHE_TABLE_SIZE
@@ -1040,17 +1041,24 @@ void rgblight_task(void) {
1040# include <rgblight_breathe_table.h> 1041# include <rgblight_breathe_table.h>
1041# endif 1042# endif
1042 1043
1043__attribute__((weak)) const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5}; 1044static uint8_t breathe_calc(uint8_t pos) {
1044
1045void rgblight_effect_breathing(animation_status_t *anim) {
1046 float val;
1047
1048 // http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/ 1045 // http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/
1049# ifdef RGBLIGHT_EFFECT_BREATHE_TABLE 1046# ifdef RGBLIGHT_EFFECT_BREATHE_TABLE
1050 val = pgm_read_byte(&rgblight_effect_breathe_table[anim->pos / table_scale]); 1047 return pgm_read_byte(&rgblight_effect_breathe_table[pos / table_scale]);
1051# else 1048# else
1052 val = (exp(sin((anim->pos / 255.0) * M_PI)) - RGBLIGHT_EFFECT_BREATHE_CENTER / M_E) * (RGBLIGHT_EFFECT_BREATHE_MAX / (M_E - 1 / M_E)); 1049 return (exp(sin((pos / 255.0) * M_PI)) - RGBLIGHT_EFFECT_BREATHE_CENTER / M_E) * (RGBLIGHT_EFFECT_BREATHE_MAX / (M_E - 1 / M_E));
1053# endif 1050# endif
1051}
1052
1053#endif
1054
1055// Effects
1056#ifdef RGBLIGHT_EFFECT_BREATHING
1057
1058__attribute__((weak)) const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5};
1059
1060void rgblight_effect_breathing(animation_status_t *anim) {
1061 uint8_t val = breathe_calc(anim->pos);
1054 rgblight_sethsv_noeeprom_old(rgblight_config.hue, rgblight_config.sat, val); 1062 rgblight_sethsv_noeeprom_old(rgblight_config.hue, rgblight_config.sat, val);
1055 anim->pos = (anim->pos + 1); 1063 anim->pos = (anim->pos + 1);
1056} 1064}
@@ -1302,48 +1310,54 @@ void rgblight_effect_alternating(animation_status_t *anim) {
1302#endif 1310#endif
1303 1311
1304#ifdef RGBLIGHT_EFFECT_TWINKLE 1312#ifdef RGBLIGHT_EFFECT_TWINKLE
1305__attribute__((weak)) const uint8_t RGBLED_TWINKLE_INTERVALS[] PROGMEM = {50, 25, 10}; 1313__attribute__((weak)) const uint8_t RGBLED_TWINKLE_INTERVALS[] PROGMEM = {30, 15, 5};
1306 1314
1307typedef struct PACKED { 1315typedef struct PACKED {
1308 HSV hsv; 1316 HSV hsv;
1309 uint8_t life; 1317 uint8_t life;
1310 bool up; 1318 uint8_t max_life;
1311} TwinkleState; 1319} TwinkleState;
1312 1320
1313static TwinkleState led_twinkle_state[RGBLED_NUM]; 1321static TwinkleState led_twinkle_state[RGBLED_NUM];
1314 1322
1315void rgblight_effect_twinkle(animation_status_t *anim) { 1323void rgblight_effect_twinkle(animation_status_t *anim) {
1316 bool random_color = anim->delta / 3; 1324 const bool random_color = anim->delta / 3;
1317 bool restart = anim->pos == 0; 1325 const bool restart = anim->pos == 0;
1318 anim->pos = 1; 1326 anim->pos = 1;
1327
1328 const uint8_t bottom = breathe_calc(0);
1329 const uint8_t top = breathe_calc(127);
1330
1331 uint8_t frac(uint8_t n, uint8_t d) { return (uint16_t)255 * n / d; }
1332 uint8_t scale(uint16_t v, uint8_t scale) { return (v * scale) >> 8; }
1319 1333
1320 for (uint8_t i = 0; i < rgblight_ranges.effect_num_leds; i++) { 1334 for (uint8_t i = 0; i < rgblight_ranges.effect_num_leds; i++) {
1321 TwinkleState *t = &(led_twinkle_state[i]); 1335 TwinkleState *t = &(led_twinkle_state[i]);
1322 HSV * c = &(t->hsv); 1336 HSV * c = &(t->hsv);
1337
1338 if (!random_color) {
1339 c->h = rgblight_config.hue;
1340 c->s = rgblight_config.sat;
1341 }
1342
1323 if (restart) { 1343 if (restart) {
1324 // Restart 1344 // Restart
1325 t->life = 0; 1345 t->life = 0;
1326 t->hsv.v = 0; 1346 c->v = 0;
1327 } else if (t->life) { 1347 } else if (t->life) {
1328 // This LED is already on, either brightening or dimming 1348 // This LED is already on, either brightening or dimming
1329 t->life--; 1349 t->life--;
1330 uint8_t on = t->up ? RGBLIGHT_EFFECT_TWINKLE_LIFE - t->life : t->life; 1350 uint8_t unscaled = frac(breathe_calc(frac(t->life, t->max_life)) - bottom, top - bottom);
1331 c->v = (uint16_t)rgblight_config.val * on / RGBLIGHT_EFFECT_TWINKLE_LIFE; 1351 c->v = scale(rgblight_config.val, unscaled);
1332 if (t->life == 0 && t->up) { 1352 } else if (rand() < scale((uint16_t)RAND_MAX * RGBLIGHT_EFFECT_TWINKLE_PROBABILITY, 127 + rgblight_config.val / 2)) {
1333 t->up = false;
1334 t->life = RGBLIGHT_EFFECT_TWINKLE_LIFE;
1335 }
1336 if (!random_color) {
1337 c->h = rgblight_config.hue;
1338 c->s = rgblight_config.sat;
1339 }
1340 } else if (rand() < RAND_MAX * RGBLIGHT_EFFECT_TWINKLE_PROBABILITY) {
1341 // This LED is off, but was randomly selected to start brightening 1353 // This LED is off, but was randomly selected to start brightening
1342 c->h = random_color ? rand() % 0xFF : rgblight_config.hue; 1354 if (random_color) {
1343 c->s = random_color ? (rand() % (rgblight_config.sat / 2)) + (rgblight_config.sat / 2) : rgblight_config.sat; 1355 c->h = rand() % 0xFF;
1344 c->v = 0; 1356 c->s = (rand() % (rgblight_config.sat / 2)) + (rgblight_config.sat / 2);
1345 t->life = RGBLIGHT_EFFECT_TWINKLE_LIFE; 1357 }
1346 t->up = true; 1358 c->v = 0;
1359 t->max_life = MAX(20, MIN(RGBLIGHT_EFFECT_TWINKLE_LIFE, rgblight_config.val));
1360 t->life = t->max_life;
1347 } else { 1361 } else {
1348 // This LED is off, and was NOT selected to start brightening 1362 // This LED is off, and was NOT selected to start brightening
1349 } 1363 }