diff options
Diffstat (limited to 'quantum/rgblight.c')
| -rw-r--r-- | quantum/rgblight.c | 102 |
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 |
| 691 | rgblight_layer_mask_t _blinked_layer_mask = 0; | 694 | rgblight_layer_mask_t _blinked_layer_mask = 0; |
| 692 | uint16_t _blink_duration = 0; | ||
| 693 | static uint16_t _blink_timer; | 695 | static uint16_t _blink_timer; |
| 694 | 696 | ||
| 695 | void rgblight_blink_layer(uint8_t layer, uint16_t duration_ms) { | 697 | void 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 | ||
| 702 | void rgblight_unblink_layers(void) { | 703 | void 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}; | 1033 | static uint8_t breathe_calc(uint8_t pos) { |
| 1033 | |||
| 1034 | void 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 | |||
| 1049 | void 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 | ||
| 1296 | typedef struct PACKED { | 1304 | typedef 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 | ||
| 1302 | static TwinkleState led_twinkle_state[RGBLED_NUM]; | 1310 | static TwinkleState led_twinkle_state[RGBLED_NUM]; |
| 1303 | 1311 | ||
| 1304 | void rgblight_effect_twinkle(animation_status_t *anim) { | 1312 | void 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 | } |
