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 beeef6568..59b3f4026 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 */
@@ -684,18 +687,16 @@ static void rgblight_layers_write(void) {
684 687
685# ifdef RGBLIGHT_LAYER_BLINK 688# ifdef RGBLIGHT_LAYER_BLINK
686rgblight_layer_mask_t _blinked_layer_mask = 0; 689rgblight_layer_mask_t _blinked_layer_mask = 0;
687uint16_t _blink_duration = 0;
688static uint16_t _blink_timer; 690static uint16_t _blink_timer;
689 691
690void rgblight_blink_layer(uint8_t layer, uint16_t duration_ms) { 692void rgblight_blink_layer(uint8_t layer, uint16_t duration_ms) {
691 rgblight_set_layer_state(layer, true); 693 rgblight_set_layer_state(layer, true);
692 _blinked_layer_mask |= (rgblight_layer_mask_t)1 << layer; 694 _blinked_layer_mask |= (rgblight_layer_mask_t)1 << layer;
693 _blink_timer = timer_read(); 695 _blink_timer = sync_timer_read() + duration_ms;
694 _blink_duration = duration_ms;
695} 696}
696 697
697void rgblight_unblink_layers(void) { 698void rgblight_unblink_layers(void) {
698 if (_blinked_layer_mask != 0 && timer_elapsed(_blink_timer) > _blink_duration) { 699 if (_blinked_layer_mask != 0 && timer_expired(sync_timer_read(), _blink_timer)) {
699 for (uint8_t layer = 0; layer < RGBLIGHT_MAX_LAYERS; layer++) { 700 for (uint8_t layer = 0; layer < RGBLIGHT_MAX_LAYERS; layer++) {
700 if ((_blinked_layer_mask & (rgblight_layer_mask_t)1 << layer) != 0) { 701 if ((_blinked_layer_mask & (rgblight_layer_mask_t)1 << layer) != 0) {
701 rgblight_set_layer_state(layer, false); 702 rgblight_set_layer_state(layer, false);
@@ -799,7 +800,7 @@ void rgblight_update_sync(rgblight_syncinfo_t *syncinfo, bool write_to_eeprom) {
799 animation_status.restart = true; 800 animation_status.restart = true;
800 } 801 }
801# endif /* RGBLIGHT_SPLIT_NO_ANIMATION_SYNC */ 802# endif /* RGBLIGHT_SPLIT_NO_ANIMATION_SYNC */
802# endif /* RGBLIGHT_USE_TIMER */ 803# endif /* RGBLIGHT_USE_TIMER */
803} 804}
804#endif /* RGBLIGHT_SPLIT */ 805#endif /* RGBLIGHT_SPLIT */
805 806
@@ -832,7 +833,7 @@ void rgblight_timer_enable(void) {
832 if (!is_static_effect(rgblight_config.mode)) { 833 if (!is_static_effect(rgblight_config.mode)) {
833 rgblight_status.timer_enabled = true; 834 rgblight_status.timer_enabled = true;
834 } 835 }
835 animation_status.last_timer = timer_read(); 836 animation_status.last_timer = sync_timer_read();
836 RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE; 837 RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE;
837 dprintf("rgblight timer enabled.\n"); 838 dprintf("rgblight timer enabled.\n");
838} 839}
@@ -935,24 +936,25 @@ void rgblight_task(void) {
935# endif 936# endif
936# ifdef RGBLIGHT_EFFECT_TWINKLE 937# ifdef RGBLIGHT_EFFECT_TWINKLE
937 else if (rgblight_status.base_mode == RGBLIGHT_MODE_TWINKLE) { 938 else if (rgblight_status.base_mode == RGBLIGHT_MODE_TWINKLE) {
938 interval_time = get_interval_time(&RGBLED_TWINKLE_INTERVALS[delta % 3], 5, 50); 939 interval_time = get_interval_time(&RGBLED_TWINKLE_INTERVALS[delta % 3], 5, 30);
939 effect_func = (effect_func_t)rgblight_effect_twinkle; 940 effect_func = (effect_func_t)rgblight_effect_twinkle;
940 } 941 }
941# endif 942# endif
942 if (animation_status.restart) { 943 if (animation_status.restart) {
943 animation_status.restart = false; 944 animation_status.restart = false;
944 animation_status.last_timer = timer_read() - interval_time - 1; 945 animation_status.last_timer = sync_timer_read();
945 animation_status.pos16 = 0; // restart signal to local each effect 946 animation_status.pos16 = 0; // restart signal to local each effect
946 } 947 }
947 if (timer_elapsed(animation_status.last_timer) >= interval_time) { 948 uint16_t now = sync_timer_read();
949 if (timer_expired(now, animation_status.last_timer)) {
948# if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) 950# if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC)
949 static uint16_t report_last_timer = 0; 951 static uint16_t report_last_timer = 0;
950 static bool tick_flag = false; 952 static bool tick_flag = false;
951 uint16_t oldpos16; 953 uint16_t oldpos16;
952 if (tick_flag) { 954 if (tick_flag) {
953 tick_flag = false; 955 tick_flag = false;
954 if (timer_elapsed(report_last_timer) >= 30000) { 956 if (timer_expired(now, report_last_timer)) {
955 report_last_timer = timer_read(); 957 report_last_timer += 30000;
956 dprintf("rgblight animation tick report to slave\n"); 958 dprintf("rgblight animation tick report to slave\n");
957 RGBLIGHT_SPLIT_ANIMATION_TICK; 959 RGBLIGHT_SPLIT_ANIMATION_TICK;
958 } 960 }
@@ -976,8 +978,7 @@ void rgblight_task(void) {
976 978
977#endif /* RGBLIGHT_USE_TIMER */ 979#endif /* RGBLIGHT_USE_TIMER */
978 980
979// Effects 981#if defined(RGBLIGHT_EFFECT_BREATHING) || defined(RGBLIGHT_EFFECT_TWINKLE)
980#ifdef RGBLIGHT_EFFECT_BREATHING
981 982
982# ifndef RGBLIGHT_EFFECT_BREATHE_CENTER 983# ifndef RGBLIGHT_EFFECT_BREATHE_CENTER
983# ifndef RGBLIGHT_BREATHE_TABLE_SIZE 984# ifndef RGBLIGHT_BREATHE_TABLE_SIZE
@@ -986,17 +987,24 @@ void rgblight_task(void) {
986# include <rgblight_breathe_table.h> 987# include <rgblight_breathe_table.h>
987# endif 988# endif
988 989
989__attribute__((weak)) const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5}; 990static uint8_t breathe_calc(uint8_t pos) {
990
991void rgblight_effect_breathing(animation_status_t *anim) {
992 float val;
993
994 // http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/ 991 // http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/
995# ifdef RGBLIGHT_EFFECT_BREATHE_TABLE 992# ifdef RGBLIGHT_EFFECT_BREATHE_TABLE
996 val = pgm_read_byte(&rgblight_effect_breathe_table[anim->pos / table_scale]); 993 return pgm_read_byte(&rgblight_effect_breathe_table[pos / table_scale]);
997# else 994# else
998 val = (exp(sin((anim->pos / 255.0) * M_PI)) - RGBLIGHT_EFFECT_BREATHE_CENTER / M_E) * (RGBLIGHT_EFFECT_BREATHE_MAX / (M_E - 1 / M_E)); 995 return (exp(sin((pos / 255.0) * M_PI)) - RGBLIGHT_EFFECT_BREATHE_CENTER / M_E) * (RGBLIGHT_EFFECT_BREATHE_MAX / (M_E - 1 / M_E));
999# endif 996# endif
997}
998
999#endif
1000
1001// Effects
1002#ifdef RGBLIGHT_EFFECT_BREATHING
1003
1004__attribute__((weak)) const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5};
1005
1006void rgblight_effect_breathing(animation_status_t *anim) {
1007 uint8_t val = breathe_calc(anim->pos);
1000 rgblight_sethsv_noeeprom_old(rgblight_config.hue, rgblight_config.sat, val); 1008 rgblight_sethsv_noeeprom_old(rgblight_config.hue, rgblight_config.sat, val);
1001 anim->pos = (anim->pos + 1); 1009 anim->pos = (anim->pos + 1);
1002} 1010}
@@ -1248,48 +1256,54 @@ void rgblight_effect_alternating(animation_status_t *anim) {
1248#endif 1256#endif
1249 1257
1250#ifdef RGBLIGHT_EFFECT_TWINKLE 1258#ifdef RGBLIGHT_EFFECT_TWINKLE
1251__attribute__((weak)) const uint8_t RGBLED_TWINKLE_INTERVALS[] PROGMEM = {50, 25, 10}; 1259__attribute__((weak)) const uint8_t RGBLED_TWINKLE_INTERVALS[] PROGMEM = {30, 15, 5};
1252 1260
1253typedef struct PACKED { 1261typedef struct PACKED {
1254 HSV hsv; 1262 HSV hsv;
1255 uint8_t life; 1263 uint8_t life;
1256 bool up; 1264 uint8_t max_life;
1257} TwinkleState; 1265} TwinkleState;
1258 1266
1259static TwinkleState led_twinkle_state[RGBLED_NUM]; 1267static TwinkleState led_twinkle_state[RGBLED_NUM];
1260 1268
1261void rgblight_effect_twinkle(animation_status_t *anim) { 1269void rgblight_effect_twinkle(animation_status_t *anim) {
1262 bool random_color = anim->delta / 3; 1270 const bool random_color = anim->delta / 3;
1263 bool restart = anim->pos == 0; 1271 const bool restart = anim->pos == 0;
1264 anim->pos = 1; 1272 anim->pos = 1;
1273
1274 const uint8_t bottom = breathe_calc(0);
1275 const uint8_t top = breathe_calc(127);
1276
1277 uint8_t frac(uint8_t n, uint8_t d) { return (uint16_t)255 * n / d; }
1278 uint8_t scale(uint16_t v, uint8_t scale) { return (v * scale) >> 8; }
1265 1279
1266 for (uint8_t i = 0; i < rgblight_ranges.effect_num_leds; i++) { 1280 for (uint8_t i = 0; i < rgblight_ranges.effect_num_leds; i++) {
1267 TwinkleState *t = &(led_twinkle_state[i]); 1281 TwinkleState *t = &(led_twinkle_state[i]);
1268 HSV * c = &(t->hsv); 1282 HSV * c = &(t->hsv);
1283
1284 if (!random_color) {
1285 c->h = rgblight_config.hue;
1286 c->s = rgblight_config.sat;
1287 }
1288
1269 if (restart) { 1289 if (restart) {
1270 // Restart 1290 // Restart
1271 t->life = 0; 1291 t->life = 0;
1272 t->hsv.v = 0; 1292 c->v = 0;
1273 } else if (t->life) { 1293 } else if (t->life) {
1274 // This LED is already on, either brightening or dimming 1294 // This LED is already on, either brightening or dimming
1275 t->life--; 1295 t->life--;
1276 uint8_t on = t->up ? RGBLIGHT_EFFECT_TWINKLE_LIFE - t->life : t->life; 1296 uint8_t unscaled = frac(breathe_calc(frac(t->life, t->max_life)) - bottom, top - bottom);
1277 c->v = (uint16_t)rgblight_config.val * on / RGBLIGHT_EFFECT_TWINKLE_LIFE; 1297 c->v = scale(rgblight_config.val, unscaled);
1278 if (t->life == 0 && t->up) { 1298 } else if (rand() < scale((uint16_t)RAND_MAX * RGBLIGHT_EFFECT_TWINKLE_PROBABILITY, 127 + rgblight_config.val / 2)) {
1279 t->up = false;
1280 t->life = RGBLIGHT_EFFECT_TWINKLE_LIFE;
1281 }
1282 if (!random_color) {
1283 c->h = rgblight_config.hue;
1284 c->s = rgblight_config.sat;
1285 }
1286 } else if (rand() < RAND_MAX * RGBLIGHT_EFFECT_TWINKLE_PROBABILITY) {
1287 // This LED is off, but was randomly selected to start brightening 1299 // This LED is off, but was randomly selected to start brightening
1288 c->h = random_color ? rand() % 0xFF : rgblight_config.hue; 1300 if (random_color) {
1289 c->s = random_color ? (rand() % (rgblight_config.sat / 2)) + (rgblight_config.sat / 2) : rgblight_config.sat; 1301 c->h = rand() % 0xFF;
1290 c->v = 0; 1302 c->s = (rand() % (rgblight_config.sat / 2)) + (rgblight_config.sat / 2);
1291 t->life = RGBLIGHT_EFFECT_TWINKLE_LIFE; 1303 }
1292 t->up = true; 1304 c->v = 0;
1305 t->max_life = MAX(20, MIN(RGBLIGHT_EFFECT_TWINKLE_LIFE, rgblight_config.val));
1306 t->life = t->max_life;
1293 } else { 1307 } else {
1294 // This LED is off, and was NOT selected to start brightening 1308 // This LED is off, and was NOT selected to start brightening
1295 } 1309 }