aboutsummaryrefslogtreecommitdiff
path: root/quantum/rgblight.c
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/rgblight.c')
-rw-r--r--quantum/rgblight.c102
1 files changed, 58 insertions, 44 deletions
diff --git a/quantum/rgblight.c b/quantum/rgblight.c
index d856f6d6c..b16c3e7c2 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 */
@@ -689,18 +692,16 @@ static void rgblight_layers_write(void) {
689 692
690# ifdef RGBLIGHT_LAYER_BLINK 693# ifdef RGBLIGHT_LAYER_BLINK
691rgblight_layer_mask_t _blinked_layer_mask = 0; 694rgblight_layer_mask_t _blinked_layer_mask = 0;
692uint16_t _blink_duration = 0;
693static uint16_t _blink_timer; 695static uint16_t _blink_timer;
694 696
695void rgblight_blink_layer(uint8_t layer, uint16_t duration_ms) { 697void rgblight_blink_layer(uint8_t layer, uint16_t duration_ms) {
696 rgblight_set_layer_state(layer, true); 698 rgblight_set_layer_state(layer, true);
697 _blinked_layer_mask |= (rgblight_layer_mask_t)1 << layer; 699 _blinked_layer_mask |= (rgblight_layer_mask_t)1 << layer;
698 _blink_timer = timer_read(); 700 _blink_timer = sync_timer_read() + duration_ms;
699 _blink_duration = duration_ms;
700} 701}
701 702
702void rgblight_unblink_layers(void) { 703void rgblight_unblink_layers(void) {
703 if (_blinked_layer_mask != 0 && timer_elapsed(_blink_timer) > _blink_duration) { 704 if (_blinked_layer_mask != 0 && timer_expired(sync_timer_read(), _blink_timer)) {
704 for (uint8_t layer = 0; layer < RGBLIGHT_MAX_LAYERS; layer++) { 705 for (uint8_t layer = 0; layer < RGBLIGHT_MAX_LAYERS; layer++) {
705 if ((_blinked_layer_mask & (rgblight_layer_mask_t)1 << layer) != 0) { 706 if ((_blinked_layer_mask & (rgblight_layer_mask_t)1 << layer) != 0) {
706 rgblight_set_layer_state(layer, false); 707 rgblight_set_layer_state(layer, false);
@@ -842,7 +843,7 @@ void rgblight_update_sync(rgblight_syncinfo_t *syncinfo, bool write_to_eeprom) {
842 animation_status.restart = true; 843 animation_status.restart = true;
843 } 844 }
844# endif /* RGBLIGHT_SPLIT_NO_ANIMATION_SYNC */ 845# endif /* RGBLIGHT_SPLIT_NO_ANIMATION_SYNC */
845# endif /* RGBLIGHT_USE_TIMER */ 846# endif /* RGBLIGHT_USE_TIMER */
846} 847}
847#endif /* RGBLIGHT_SPLIT */ 848#endif /* RGBLIGHT_SPLIT */
848 849
@@ -875,7 +876,7 @@ void rgblight_timer_enable(void) {
875 if (!is_static_effect(rgblight_config.mode)) { 876 if (!is_static_effect(rgblight_config.mode)) {
876 rgblight_status.timer_enabled = true; 877 rgblight_status.timer_enabled = true;
877 } 878 }
878 animation_status.last_timer = timer_read(); 879 animation_status.last_timer = sync_timer_read();
879 RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE; 880 RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE;
880 dprintf("rgblight timer enabled.\n"); 881 dprintf("rgblight timer enabled.\n");
881} 882}
@@ -978,24 +979,25 @@ void rgblight_task(void) {
978# endif 979# endif
979# ifdef RGBLIGHT_EFFECT_TWINKLE 980# ifdef RGBLIGHT_EFFECT_TWINKLE
980 else if (rgblight_status.base_mode == RGBLIGHT_MODE_TWINKLE) { 981 else if (rgblight_status.base_mode == RGBLIGHT_MODE_TWINKLE) {
981 interval_time = get_interval_time(&RGBLED_TWINKLE_INTERVALS[delta % 3], 5, 50); 982 interval_time = get_interval_time(&RGBLED_TWINKLE_INTERVALS[delta % 3], 5, 30);
982 effect_func = (effect_func_t)rgblight_effect_twinkle; 983 effect_func = (effect_func_t)rgblight_effect_twinkle;
983 } 984 }
984# endif 985# endif
985 if (animation_status.restart) { 986 if (animation_status.restart) {
986 animation_status.restart = false; 987 animation_status.restart = false;
987 animation_status.last_timer = timer_read() - interval_time - 1; 988 animation_status.last_timer = sync_timer_read();
988 animation_status.pos16 = 0; // restart signal to local each effect 989 animation_status.pos16 = 0; // restart signal to local each effect
989 } 990 }
990 if (timer_elapsed(animation_status.last_timer) >= interval_time) { 991 uint16_t now = sync_timer_read();
992 if (timer_expired(now, animation_status.last_timer)) {
991# if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) 993# if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
992 static uint16_t report_last_timer = 0; 994 static uint16_t report_last_timer = 0;
993 static bool tick_flag = false; 995 static bool tick_flag = false;
994 uint16_t oldpos16; 996 uint16_t oldpos16;
995 if (tick_flag) { 997 if (tick_flag) {
996 tick_flag = false; 998 tick_flag = false;
997 if (timer_elapsed(report_last_timer) >= 30000) { 999 if (timer_expired(now, report_last_timer)) {
998 report_last_timer = timer_read(); 1000 report_last_timer += 30000;
999 dprintf("rgblight animation tick report to slave\n"); 1001 dprintf("rgblight animation tick report to slave\n");
1000 RGBLIGHT_SPLIT_ANIMATION_TICK; 1002 RGBLIGHT_SPLIT_ANIMATION_TICK;
1001 } 1003 }
@@ -1019,8 +1021,7 @@ void rgblight_task(void) {
1019 1021
1020#endif /* RGBLIGHT_USE_TIMER */ 1022#endif /* RGBLIGHT_USE_TIMER */
1021 1023
1022// Effects 1024#if defined(RGBLIGHT_EFFECT_BREATHING) || defined(RGBLIGHT_EFFECT_TWINKLE)
1023#ifdef RGBLIGHT_EFFECT_BREATHING
1024 1025
1025# ifndef RGBLIGHT_EFFECT_BREATHE_CENTER 1026# ifndef RGBLIGHT_EFFECT_BREATHE_CENTER
1026# ifndef RGBLIGHT_BREATHE_TABLE_SIZE 1027# ifndef RGBLIGHT_BREATHE_TABLE_SIZE
@@ -1029,17 +1030,24 @@ void rgblight_task(void) {
1029# include <rgblight_breathe_table.h> 1030# include <rgblight_breathe_table.h>
1030# endif 1031# endif
1031 1032
1032__attribute__((weak)) const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5}; 1033static uint8_t breathe_calc(uint8_t pos) {
1033
1034void rgblight_effect_breathing(animation_status_t *anim) {
1035 float val;
1036
1037 // http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/ 1034 // http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/
1038# ifdef RGBLIGHT_EFFECT_BREATHE_TABLE 1035# ifdef RGBLIGHT_EFFECT_BREATHE_TABLE
1039 val = pgm_read_byte(&rgblight_effect_breathe_table[anim->pos / table_scale]); 1036 return pgm_read_byte(&rgblight_effect_breathe_table[pos / table_scale]);
1040# else 1037# else
1041 val = (exp(sin((anim->pos / 255.0) * M_PI)) - RGBLIGHT_EFFECT_BREATHE_CENTER / M_E) * (RGBLIGHT_EFFECT_BREATHE_MAX / (M_E - 1 / M_E)); 1038 return (exp(sin((pos / 255.0) * M_PI)) - RGBLIGHT_EFFECT_BREATHE_CENTER / M_E) * (RGBLIGHT_EFFECT_BREATHE_MAX / (M_E - 1 / M_E));
1042# endif 1039# endif
1040}
1041
1042#endif
1043
1044// Effects
1045#ifdef RGBLIGHT_EFFECT_BREATHING
1046
1047__attribute__((weak)) const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5};
1048
1049void rgblight_effect_breathing(animation_status_t *anim) {
1050 uint8_t val = breathe_calc(anim->pos);
1043 rgblight_sethsv_noeeprom_old(rgblight_config.hue, rgblight_config.sat, val); 1051 rgblight_sethsv_noeeprom_old(rgblight_config.hue, rgblight_config.sat, val);
1044 anim->pos = (anim->pos + 1); 1052 anim->pos = (anim->pos + 1);
1045} 1053}
@@ -1291,48 +1299,54 @@ void rgblight_effect_alternating(animation_status_t *anim) {
1291#endif 1299#endif
1292 1300
1293#ifdef RGBLIGHT_EFFECT_TWINKLE 1301#ifdef RGBLIGHT_EFFECT_TWINKLE
1294__attribute__((weak)) const uint8_t RGBLED_TWINKLE_INTERVALS[] PROGMEM = {50, 25, 10}; 1302__attribute__((weak)) const uint8_t RGBLED_TWINKLE_INTERVALS[] PROGMEM = {30, 15, 5};
1295 1303
1296typedef struct PACKED { 1304typedef struct PACKED {
1297 HSV hsv; 1305 HSV hsv;
1298 uint8_t life; 1306 uint8_t life;
1299 bool up; 1307 uint8_t max_life;
1300} TwinkleState; 1308} TwinkleState;
1301 1309
1302static TwinkleState led_twinkle_state[RGBLED_NUM]; 1310static TwinkleState led_twinkle_state[RGBLED_NUM];
1303 1311
1304void rgblight_effect_twinkle(animation_status_t *anim) { 1312void rgblight_effect_twinkle(animation_status_t *anim) {
1305 bool random_color = anim->delta / 3; 1313 const bool random_color = anim->delta / 3;
1306 bool restart = anim->pos == 0; 1314 const bool restart = anim->pos == 0;
1307 anim->pos = 1; 1315 anim->pos = 1;
1316
1317 const uint8_t bottom = breathe_calc(0);
1318 const uint8_t top = breathe_calc(127);
1319
1320 uint8_t frac(uint8_t n, uint8_t d) { return (uint16_t)255 * n / d; }
1321 uint8_t scale(uint16_t v, uint8_t scale) { return (v * scale) >> 8; }
1308 1322
1309 for (uint8_t i = 0; i < rgblight_ranges.effect_num_leds; i++) { 1323 for (uint8_t i = 0; i < rgblight_ranges.effect_num_leds; i++) {
1310 TwinkleState *t = &(led_twinkle_state[i]); 1324 TwinkleState *t = &(led_twinkle_state[i]);
1311 HSV * c = &(t->hsv); 1325 HSV * c = &(t->hsv);
1326
1327 if (!random_color) {
1328 c->h = rgblight_config.hue;
1329 c->s = rgblight_config.sat;
1330 }
1331
1312 if (restart) { 1332 if (restart) {
1313 // Restart 1333 // Restart
1314 t->life = 0; 1334 t->life = 0;
1315 t->hsv.v = 0; 1335 c->v = 0;
1316 } else if (t->life) { 1336 } else if (t->life) {
1317 // This LED is already on, either brightening or dimming 1337 // This LED is already on, either brightening or dimming
1318 t->life--; 1338 t->life--;
1319 uint8_t on = t->up ? RGBLIGHT_EFFECT_TWINKLE_LIFE - t->life : t->life; 1339 uint8_t unscaled = frac(breathe_calc(frac(t->life, t->max_life)) - bottom, top - bottom);
1320 c->v = (uint16_t)rgblight_config.val * on / RGBLIGHT_EFFECT_TWINKLE_LIFE; 1340 c->v = scale(rgblight_config.val, unscaled);
1321 if (t->life == 0 && t->up) { 1341 } else if (rand() < scale((uint16_t)RAND_MAX * RGBLIGHT_EFFECT_TWINKLE_PROBABILITY, 127 + rgblight_config.val / 2)) {
1322 t->up = false;
1323 t->life = RGBLIGHT_EFFECT_TWINKLE_LIFE;
1324 }
1325 if (!random_color) {
1326 c->h = rgblight_config.hue;
1327 c->s = rgblight_config.sat;
1328 }
1329 } else if (rand() < RAND_MAX * RGBLIGHT_EFFECT_TWINKLE_PROBABILITY) {
1330 // This LED is off, but was randomly selected to start brightening 1342 // This LED is off, but was randomly selected to start brightening
1331 c->h = random_color ? rand() % 0xFF : rgblight_config.hue; 1343 if (random_color) {
1332 c->s = random_color ? (rand() % (rgblight_config.sat / 2)) + (rgblight_config.sat / 2) : rgblight_config.sat; 1344 c->h = rand() % 0xFF;
1333 c->v = 0; 1345 c->s = (rand() % (rgblight_config.sat / 2)) + (rgblight_config.sat / 2);
1334 t->life = RGBLIGHT_EFFECT_TWINKLE_LIFE; 1346 }
1335 t->up = true; 1347 c->v = 0;
1348 t->max_life = MAX(20, MIN(RGBLIGHT_EFFECT_TWINKLE_LIFE, rgblight_config.val));
1349 t->life = t->max_life;
1336 } else { 1350 } else {
1337 // This LED is off, and was NOT selected to start brightening 1351 // This LED is off, and was NOT selected to start brightening
1338 } 1352 }