rgblight.c (49924B)
1 /* Copyright 2016-2017 Yang Liu 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 2 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 */ 16 #include <math.h> 17 #include <string.h> 18 #include <stdlib.h> 19 #include "progmem.h" 20 #include "sync_timer.h" 21 #include "rgblight.h" 22 #include "color.h" 23 #include "debug.h" 24 #include "util.h" 25 #include "led_tables.h" 26 #include <lib/lib8tion/lib8tion.h> 27 #include "eeconfig.h" 28 29 #ifdef RGBLIGHT_SPLIT 30 /* for split keyboard */ 31 # define RGBLIGHT_SPLIT_SET_CHANGE_MODE rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_MODE 32 # define RGBLIGHT_SPLIT_SET_CHANGE_HSVS rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_HSVS 33 # define RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS rgblight_status.change_flags |= (RGBLIGHT_STATUS_CHANGE_MODE | RGBLIGHT_STATUS_CHANGE_HSVS) 34 # define RGBLIGHT_SPLIT_SET_CHANGE_LAYERS rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_LAYERS 35 # define RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_TIMER 36 # define RGBLIGHT_SPLIT_ANIMATION_TICK rgblight_status.change_flags |= RGBLIGHT_STATUS_ANIMATION_TICK 37 #else 38 # define RGBLIGHT_SPLIT_SET_CHANGE_MODE 39 # define RGBLIGHT_SPLIT_SET_CHANGE_HSVS 40 # define RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS 41 # define RGBLIGHT_SPLIT_SET_CHANGE_LAYERS 42 # define RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE 43 # define RGBLIGHT_SPLIT_ANIMATION_TICK 44 #endif 45 46 #define _RGBM_SINGLE_STATIC(sym) RGBLIGHT_MODE_##sym, 47 #define _RGBM_SINGLE_DYNAMIC(sym) 48 #define _RGBM_MULTI_STATIC(sym) RGBLIGHT_MODE_##sym, 49 #define _RGBM_MULTI_DYNAMIC(sym) 50 #define _RGBM_TMP_STATIC(sym, msym) RGBLIGHT_MODE_##sym, 51 #define _RGBM_TMP_DYNAMIC(sym, msym) 52 static uint8_t static_effect_table[] = { 53 #include "rgblight_modes.h" 54 }; 55 56 #define _RGBM_SINGLE_STATIC(sym) RGBLIGHT_MODE_##sym, 57 #define _RGBM_SINGLE_DYNAMIC(sym) RGBLIGHT_MODE_##sym, 58 #define _RGBM_MULTI_STATIC(sym) RGBLIGHT_MODE_##sym, 59 #define _RGBM_MULTI_DYNAMIC(sym) RGBLIGHT_MODE_##sym, 60 #define _RGBM_TMP_STATIC(sym, msym) RGBLIGHT_MODE_##msym, 61 #define _RGBM_TMP_DYNAMIC(sym, msym) RGBLIGHT_MODE_##msym, 62 static uint8_t mode_base_table[] = { 63 0, // RGBLIGHT_MODE_zero 64 #include "rgblight_modes.h" 65 }; 66 67 #if !defined(RGBLIGHT_DEFAULT_MODE) 68 # define RGBLIGHT_DEFAULT_MODE RGBLIGHT_MODE_STATIC_LIGHT 69 #endif 70 71 #if !defined(RGBLIGHT_DEFAULT_HUE) 72 # define RGBLIGHT_DEFAULT_HUE 0 73 #endif 74 75 #if !defined(RGBLIGHT_DEFAULT_SAT) 76 # define RGBLIGHT_DEFAULT_SAT UINT8_MAX 77 #endif 78 79 #if !defined(RGBLIGHT_DEFAULT_VAL) 80 # define RGBLIGHT_DEFAULT_VAL RGBLIGHT_LIMIT_VAL 81 #endif 82 83 #if !defined(RGBLIGHT_DEFAULT_SPD) 84 # define RGBLIGHT_DEFAULT_SPD 0 85 #endif 86 87 #if !defined(RGBLIGHT_DEFAULT_ON) 88 # define RGBLIGHT_DEFAULT_ON true 89 #endif 90 91 static inline int is_static_effect(uint8_t mode) { 92 return memchr(static_effect_table, mode, sizeof(static_effect_table)) != NULL; 93 } 94 95 #ifdef RGBLIGHT_LED_MAP 96 const uint8_t led_map[] PROGMEM = RGBLIGHT_LED_MAP; 97 #endif 98 99 #ifdef RGBLIGHT_EFFECT_STATIC_GRADIENT 100 __attribute__((weak)) const uint8_t RGBLED_GRADIENT_RANGES[] PROGMEM = {255, 170, 127, 85, 64}; 101 #endif 102 103 rgblight_config_t rgblight_config; 104 rgblight_status_t rgblight_status = {.timer_enabled = false}; 105 bool is_rgblight_initialized = false; 106 107 #ifdef RGBLIGHT_SLEEP 108 static bool is_suspended; 109 static bool pre_suspend_enabled; 110 #endif 111 112 #ifdef RGBLIGHT_USE_TIMER 113 animation_status_t animation_status = {}; 114 #endif 115 116 #ifdef RGBLIGHT_LAYERS 117 rgblight_segment_t const *const *rgblight_layers = NULL; 118 119 static bool deferred_set_layer_state = false; 120 #endif 121 122 rgblight_ranges_t rgblight_ranges = {0, RGBLIGHT_LED_COUNT, 0, RGBLIGHT_LED_COUNT, RGBLIGHT_LED_COUNT}; 123 124 void rgblight_set_clipping_range(uint8_t start_pos, uint8_t num_leds) { 125 rgblight_ranges.clipping_start_pos = start_pos; 126 rgblight_ranges.clipping_num_leds = num_leds; 127 } 128 129 void rgblight_set_effect_range(uint8_t start_pos, uint8_t num_leds) { 130 if (start_pos >= RGBLIGHT_LED_COUNT) return; 131 if (start_pos + num_leds > RGBLIGHT_LED_COUNT) return; 132 rgblight_ranges.effect_start_pos = start_pos; 133 rgblight_ranges.effect_end_pos = start_pos + num_leds; 134 rgblight_ranges.effect_num_leds = num_leds; 135 } 136 137 __attribute__((weak)) rgb_t rgblight_hsv_to_rgb(hsv_t hsv) { 138 return hsv_to_rgb(hsv); 139 } 140 141 uint8_t rgblight_led_index(uint8_t index) { 142 #if defined(RGBLIGHT_LED_MAP) 143 return pgm_read_byte(&led_map[index]) - rgblight_ranges.clipping_start_pos; 144 #else 145 return index - rgblight_ranges.clipping_start_pos; 146 #endif 147 } 148 149 void setrgb(uint8_t r, uint8_t g, uint8_t b, int index) { 150 rgblight_driver.set_color(rgblight_led_index(index), r, g, b); 151 } 152 153 void sethsv_raw(uint8_t hue, uint8_t sat, uint8_t val, int index) { 154 hsv_t hsv = {hue, sat, val}; 155 rgb_t rgb = rgblight_hsv_to_rgb(hsv); 156 setrgb(rgb.r, rgb.g, rgb.b, index); 157 } 158 159 void sethsv(uint8_t hue, uint8_t sat, uint8_t val, int index) { 160 sethsv_raw(hue, sat, val > RGBLIGHT_LIMIT_VAL ? RGBLIGHT_LIMIT_VAL : val, index); 161 } 162 163 void rgblight_check_config(void) { 164 /* Add some out of bound checks for RGB light config */ 165 166 if (rgblight_config.mode < RGBLIGHT_MODE_STATIC_LIGHT) { 167 rgblight_config.mode = RGBLIGHT_MODE_STATIC_LIGHT; 168 } else if (rgblight_config.mode > RGBLIGHT_MODES) { 169 rgblight_config.mode = RGBLIGHT_MODES; 170 } 171 172 if (rgblight_config.val > RGBLIGHT_LIMIT_VAL) { 173 rgblight_config.val = RGBLIGHT_LIMIT_VAL; 174 } 175 } 176 177 void eeconfig_update_rgblight_current(void) { 178 rgblight_check_config(); 179 eeconfig_update_rgblight(&rgblight_config); 180 } 181 182 void eeconfig_update_rgblight_default(void) { 183 rgblight_config.enable = RGBLIGHT_DEFAULT_ON; 184 rgblight_config.velocikey = 0; 185 rgblight_config.mode = RGBLIGHT_DEFAULT_MODE; 186 rgblight_config.hue = RGBLIGHT_DEFAULT_HUE; 187 rgblight_config.sat = RGBLIGHT_DEFAULT_SAT; 188 rgblight_config.val = RGBLIGHT_DEFAULT_VAL; 189 rgblight_config.speed = RGBLIGHT_DEFAULT_SPD; 190 RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS; 191 eeconfig_update_rgblight(&rgblight_config); 192 } 193 194 void eeconfig_debug_rgblight(void) { 195 dprintf("rgblight_config EEPROM:\n"); 196 dprintf("rgblight_config.enable = %d\n", rgblight_config.enable); 197 dprintf("rgblight_config.velocikey = %d\n", rgblight_config.velocikey); 198 dprintf("rghlight_config.mode = %d\n", rgblight_config.mode); 199 dprintf("rgblight_config.hue = %d\n", rgblight_config.hue); 200 dprintf("rgblight_config.sat = %d\n", rgblight_config.sat); 201 dprintf("rgblight_config.val = %d\n", rgblight_config.val); 202 dprintf("rgblight_config.speed = %d\n", rgblight_config.speed); 203 } 204 205 void rgblight_init(void) { 206 /* if already initialized, don't do it again. 207 If you must do it again, extern this and set to false, first. 208 This is a dirty, dirty hack until proper hooks can be added for keyboard startup. */ 209 if (is_rgblight_initialized) { 210 return; 211 } 212 213 dprintf("rgblight_init start!\n"); 214 eeconfig_read_rgblight(&rgblight_config); 215 RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS; 216 if (!rgblight_config.mode) { 217 dprintf("rgblight_init rgblight_config.mode = 0. Write default values to EEPROM.\n"); 218 eeconfig_update_rgblight_default(); 219 eeconfig_read_rgblight(&rgblight_config); 220 } 221 rgblight_check_config(); 222 223 eeconfig_debug_rgblight(); // display current eeprom values 224 225 rgblight_timer_init(); // setup the timer 226 227 rgblight_driver.init(); 228 229 if (rgblight_config.enable) { 230 rgblight_mode_noeeprom(rgblight_config.mode); 231 } 232 233 is_rgblight_initialized = true; 234 } 235 236 void rgblight_reload_from_eeprom(void) { 237 /* Reset back to what we have in eeprom */ 238 eeconfig_read_rgblight(&rgblight_config); 239 RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS; 240 rgblight_check_config(); 241 eeconfig_debug_rgblight(); // display current eeprom values 242 if (rgblight_config.enable) { 243 rgblight_mode_noeeprom(rgblight_config.mode); 244 } 245 } 246 247 uint64_t rgblight_read_qword(void) { 248 return rgblight_config.raw; 249 } 250 251 void rgblight_update_qword(uint64_t qword) { 252 RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS; 253 rgblight_config.raw = qword; 254 if (rgblight_config.enable) 255 rgblight_mode_noeeprom(rgblight_config.mode); 256 else { 257 rgblight_timer_disable(); 258 rgblight_set(); 259 } 260 } 261 262 void rgblight_increase(void) { 263 uint8_t mode = 0; 264 if (rgblight_config.mode < RGBLIGHT_MODES) { 265 mode = rgblight_config.mode + 1; 266 } 267 rgblight_mode(mode); 268 } 269 void rgblight_decrease(void) { 270 uint8_t mode = 0; 271 // Mode will never be < 1. If it ever is, eeprom needs to be initialized. 272 if (rgblight_config.mode > RGBLIGHT_MODE_STATIC_LIGHT) { 273 mode = rgblight_config.mode - 1; 274 } 275 rgblight_mode(mode); 276 } 277 void rgblight_step_helper(bool write_to_eeprom) { 278 uint8_t mode = 0; 279 mode = rgblight_config.mode + 1; 280 if (mode > RGBLIGHT_MODES) { 281 mode = 1; 282 } 283 rgblight_mode_eeprom_helper(mode, write_to_eeprom); 284 } 285 void rgblight_step_noeeprom(void) { 286 rgblight_step_helper(false); 287 } 288 void rgblight_step(void) { 289 rgblight_step_helper(true); 290 } 291 void rgblight_step_reverse_helper(bool write_to_eeprom) { 292 uint8_t mode = 0; 293 mode = rgblight_config.mode - 1; 294 if (mode < 1) { 295 mode = RGBLIGHT_MODES; 296 } 297 rgblight_mode_eeprom_helper(mode, write_to_eeprom); 298 } 299 void rgblight_step_reverse_noeeprom(void) { 300 rgblight_step_reverse_helper(false); 301 } 302 void rgblight_step_reverse(void) { 303 rgblight_step_reverse_helper(true); 304 } 305 306 uint8_t rgblight_get_mode(void) { 307 if (!rgblight_config.enable) { 308 return false; 309 } 310 311 return rgblight_config.mode; 312 } 313 314 void rgblight_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom) { 315 if (!rgblight_config.enable) { 316 return; 317 } 318 if (mode < RGBLIGHT_MODE_STATIC_LIGHT) { 319 rgblight_config.mode = RGBLIGHT_MODE_STATIC_LIGHT; 320 } else if (mode > RGBLIGHT_MODES) { 321 rgblight_config.mode = RGBLIGHT_MODES; 322 } else { 323 rgblight_config.mode = mode; 324 } 325 RGBLIGHT_SPLIT_SET_CHANGE_MODE; 326 if (write_to_eeprom) { 327 eeconfig_update_rgblight(&rgblight_config); 328 dprintf("rgblight mode [EEPROM]: %u\n", rgblight_config.mode); 329 } else { 330 dprintf("rgblight mode [NOEEPROM]: %u\n", rgblight_config.mode); 331 } 332 if (is_static_effect(rgblight_config.mode)) { 333 rgblight_timer_disable(); 334 } else { 335 rgblight_timer_enable(); 336 } 337 #ifdef RGBLIGHT_USE_TIMER 338 animation_status.restart = true; 339 #endif 340 rgblight_sethsv_noeeprom(rgblight_config.hue, rgblight_config.sat, rgblight_config.val); 341 } 342 343 void rgblight_mode(uint8_t mode) { 344 rgblight_mode_eeprom_helper(mode, true); 345 } 346 347 void rgblight_mode_noeeprom(uint8_t mode) { 348 rgblight_mode_eeprom_helper(mode, false); 349 } 350 351 void rgblight_toggle(void) { 352 dprintf("rgblight toggle [EEPROM]: rgblight_config.enable = %u\n", !rgblight_config.enable); 353 if (rgblight_config.enable) { 354 rgblight_disable(); 355 } else { 356 rgblight_enable(); 357 } 358 } 359 360 void rgblight_toggle_noeeprom(void) { 361 dprintf("rgblight toggle [NOEEPROM]: rgblight_config.enable = %u\n", !rgblight_config.enable); 362 if (rgblight_config.enable) { 363 rgblight_disable_noeeprom(); 364 } else { 365 rgblight_enable_noeeprom(); 366 } 367 } 368 369 void rgblight_enable(void) { 370 rgblight_config.enable = 1; 371 // No need to update EEPROM here. rgblight_mode() will do that, actually 372 // eeconfig_update_rgblight(&rgblight_config); 373 dprintf("rgblight enable [EEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable); 374 rgblight_mode(rgblight_config.mode); 375 } 376 377 void rgblight_enable_noeeprom(void) { 378 rgblight_config.enable = 1; 379 dprintf("rgblight enable [NOEEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable); 380 rgblight_mode_noeeprom(rgblight_config.mode); 381 } 382 383 void rgblight_disable(void) { 384 rgblight_config.enable = 0; 385 eeconfig_update_rgblight(&rgblight_config); 386 dprintf("rgblight disable [EEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable); 387 rgblight_timer_disable(); 388 RGBLIGHT_SPLIT_SET_CHANGE_MODE; 389 rgblight_set(); 390 } 391 392 void rgblight_disable_noeeprom(void) { 393 rgblight_config.enable = 0; 394 dprintf("rgblight disable [NOEEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable); 395 rgblight_timer_disable(); 396 RGBLIGHT_SPLIT_SET_CHANGE_MODE; 397 rgblight_set(); 398 } 399 400 void rgblight_enabled_noeeprom(bool state) { 401 state ? rgblight_enable_noeeprom() : rgblight_disable_noeeprom(); 402 } 403 404 bool rgblight_is_enabled(void) { 405 return rgblight_config.enable; 406 } 407 408 void rgblight_increase_hue_helper(bool write_to_eeprom) { 409 uint8_t hue = rgblight_config.hue + RGBLIGHT_HUE_STEP; 410 rgblight_sethsv_eeprom_helper(hue, rgblight_config.sat, rgblight_config.val, write_to_eeprom); 411 } 412 void rgblight_increase_hue_noeeprom(void) { 413 rgblight_increase_hue_helper(false); 414 } 415 void rgblight_increase_hue(void) { 416 rgblight_increase_hue_helper(true); 417 } 418 void rgblight_decrease_hue_helper(bool write_to_eeprom) { 419 uint8_t hue = rgblight_config.hue - RGBLIGHT_HUE_STEP; 420 rgblight_sethsv_eeprom_helper(hue, rgblight_config.sat, rgblight_config.val, write_to_eeprom); 421 } 422 void rgblight_decrease_hue_noeeprom(void) { 423 rgblight_decrease_hue_helper(false); 424 } 425 void rgblight_decrease_hue(void) { 426 rgblight_decrease_hue_helper(true); 427 } 428 void rgblight_increase_sat_helper(bool write_to_eeprom) { 429 uint8_t sat = qadd8(rgblight_config.sat, RGBLIGHT_SAT_STEP); 430 rgblight_sethsv_eeprom_helper(rgblight_config.hue, sat, rgblight_config.val, write_to_eeprom); 431 } 432 void rgblight_increase_sat_noeeprom(void) { 433 rgblight_increase_sat_helper(false); 434 } 435 void rgblight_increase_sat(void) { 436 rgblight_increase_sat_helper(true); 437 } 438 void rgblight_decrease_sat_helper(bool write_to_eeprom) { 439 uint8_t sat = qsub8(rgblight_config.sat, RGBLIGHT_SAT_STEP); 440 rgblight_sethsv_eeprom_helper(rgblight_config.hue, sat, rgblight_config.val, write_to_eeprom); 441 } 442 void rgblight_decrease_sat_noeeprom(void) { 443 rgblight_decrease_sat_helper(false); 444 } 445 void rgblight_decrease_sat(void) { 446 rgblight_decrease_sat_helper(true); 447 } 448 void rgblight_increase_val_helper(bool write_to_eeprom) { 449 uint8_t val = qadd8(rgblight_config.val, RGBLIGHT_VAL_STEP); 450 rgblight_sethsv_eeprom_helper(rgblight_config.hue, rgblight_config.sat, val, write_to_eeprom); 451 } 452 void rgblight_increase_val_noeeprom(void) { 453 rgblight_increase_val_helper(false); 454 } 455 void rgblight_increase_val(void) { 456 rgblight_increase_val_helper(true); 457 } 458 void rgblight_decrease_val_helper(bool write_to_eeprom) { 459 uint8_t val = qsub8(rgblight_config.val, RGBLIGHT_VAL_STEP); 460 rgblight_sethsv_eeprom_helper(rgblight_config.hue, rgblight_config.sat, val, write_to_eeprom); 461 } 462 void rgblight_decrease_val_noeeprom(void) { 463 rgblight_decrease_val_helper(false); 464 } 465 void rgblight_decrease_val(void) { 466 rgblight_decrease_val_helper(true); 467 } 468 469 void rgblight_increase_speed_helper(bool write_to_eeprom) { 470 if (rgblight_config.speed < 3) rgblight_config.speed++; 471 // RGBLIGHT_SPLIT_SET_CHANGE_HSVS; // NEED? 472 if (write_to_eeprom) { 473 eeconfig_update_rgblight(&rgblight_config); 474 } 475 } 476 void rgblight_increase_speed(void) { 477 rgblight_increase_speed_helper(true); 478 } 479 void rgblight_increase_speed_noeeprom(void) { 480 rgblight_increase_speed_helper(false); 481 } 482 483 void rgblight_decrease_speed_helper(bool write_to_eeprom) { 484 if (rgblight_config.speed > 0) rgblight_config.speed--; 485 // RGBLIGHT_SPLIT_SET_CHANGE_HSVS; // NEED?? 486 if (write_to_eeprom) { 487 eeconfig_update_rgblight(&rgblight_config); 488 } 489 } 490 void rgblight_decrease_speed(void) { 491 rgblight_decrease_speed_helper(true); 492 } 493 void rgblight_decrease_speed_noeeprom(void) { 494 rgblight_decrease_speed_helper(false); 495 } 496 497 void rgblight_sethsv_noeeprom_old(uint8_t hue, uint8_t sat, uint8_t val) { 498 if (rgblight_config.enable) { 499 rgb_t rgb = rgblight_hsv_to_rgb((hsv_t){hue, sat, val > RGBLIGHT_LIMIT_VAL ? RGBLIGHT_LIMIT_VAL : val}); 500 rgblight_setrgb(rgb.r, rgb.g, rgb.b); 501 } 502 } 503 504 void rgblight_sethsv_eeprom_helper(uint8_t hue, uint8_t sat, uint8_t val, bool write_to_eeprom) { 505 if (rgblight_config.enable) { 506 #ifdef RGBLIGHT_SPLIT 507 if (rgblight_config.hue != hue || rgblight_config.sat != sat || rgblight_config.val != val) { 508 RGBLIGHT_SPLIT_SET_CHANGE_HSVS; 509 } 510 #endif 511 rgblight_status.base_mode = mode_base_table[rgblight_config.mode]; 512 if (rgblight_config.mode == RGBLIGHT_MODE_STATIC_LIGHT) { 513 // same static color 514 #ifdef RGBLIGHT_LAYERS_RETAIN_VAL 515 // needed for rgblight_layers_write() to get the new val, since it reads rgblight_config.val 516 rgblight_config.val = val; 517 #endif 518 rgb_t rgb = rgblight_hsv_to_rgb((hsv_t){hue, sat, val > RGBLIGHT_LIMIT_VAL ? RGBLIGHT_LIMIT_VAL : val}); 519 rgblight_setrgb(rgb.r, rgb.g, rgb.b); 520 } else { 521 // all LEDs in same color 522 if (1 == 0) { // dummy 523 } 524 #ifdef RGBLIGHT_EFFECT_BREATHING 525 else if (rgblight_status.base_mode == RGBLIGHT_MODE_BREATHING) { 526 // breathing mode, ignore the change of val, use in memory value instead 527 val = rgblight_config.val; 528 } 529 #endif 530 #ifdef RGBLIGHT_EFFECT_RAINBOW_MOOD 531 else if (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_MOOD) { 532 // rainbow mood, ignore the change of hue 533 hue = rgblight_config.hue; 534 } 535 #endif 536 #ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL 537 else if (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_SWIRL) { 538 // rainbow swirl, ignore the change of hue 539 hue = rgblight_config.hue; 540 } 541 #endif 542 #ifdef RGBLIGHT_EFFECT_STATIC_GRADIENT 543 else if (rgblight_status.base_mode == RGBLIGHT_MODE_STATIC_GRADIENT) { 544 // static gradient 545 uint8_t delta = rgblight_config.mode - rgblight_status.base_mode; 546 bool direction = (delta % 2) == 0; 547 548 uint8_t range = pgm_read_byte(&RGBLED_GRADIENT_RANGES[delta / 2]); 549 for (uint8_t i = 0; i < rgblight_ranges.effect_num_leds; i++) { 550 uint8_t _hue = ((uint16_t)i * (uint16_t)range) / rgblight_ranges.effect_num_leds; 551 if (direction) { 552 _hue = hue + _hue; 553 } else { 554 _hue = hue - _hue; 555 } 556 dprintf("rgblight rainbow set hsv: %d,%d,%d,%u\n", i, _hue, direction, range); 557 sethsv(_hue, sat, val, i + rgblight_ranges.effect_start_pos); 558 } 559 # ifdef RGBLIGHT_LAYERS_RETAIN_VAL 560 // needed for rgblight_layers_write() to get the new val, since it reads rgblight_config.val 561 rgblight_config.val = val; 562 # endif 563 rgblight_set(); 564 } 565 #endif 566 } 567 rgblight_config.hue = hue; 568 rgblight_config.sat = sat; 569 rgblight_config.val = val; 570 if (write_to_eeprom) { 571 eeconfig_update_rgblight(&rgblight_config); 572 dprintf("rgblight set hsv [EEPROM]: %u,%u,%u\n", rgblight_config.hue, rgblight_config.sat, rgblight_config.val); 573 } else { 574 dprintf("rgblight set hsv [NOEEPROM]: %u,%u,%u\n", rgblight_config.hue, rgblight_config.sat, rgblight_config.val); 575 } 576 } 577 } 578 579 void rgblight_sethsv(uint8_t hue, uint8_t sat, uint8_t val) { 580 rgblight_sethsv_eeprom_helper(hue, sat, val, true); 581 } 582 583 void rgblight_sethsv_noeeprom(uint8_t hue, uint8_t sat, uint8_t val) { 584 rgblight_sethsv_eeprom_helper(hue, sat, val, false); 585 } 586 587 uint8_t rgblight_get_speed(void) { 588 return rgblight_config.speed; 589 } 590 591 void rgblight_set_speed_eeprom_helper(uint8_t speed, bool write_to_eeprom) { 592 rgblight_config.speed = speed; 593 if (write_to_eeprom) { 594 eeconfig_update_rgblight(&rgblight_config); 595 dprintf("rgblight set speed [EEPROM]: %u\n", rgblight_config.speed); 596 } else { 597 dprintf("rgblight set speed [NOEEPROM]: %u\n", rgblight_config.speed); 598 } 599 } 600 601 void rgblight_set_speed(uint8_t speed) { 602 rgblight_set_speed_eeprom_helper(speed, true); 603 } 604 605 void rgblight_set_speed_noeeprom(uint8_t speed) { 606 rgblight_set_speed_eeprom_helper(speed, false); 607 } 608 609 uint8_t rgblight_get_hue(void) { 610 return rgblight_config.hue; 611 } 612 613 uint8_t rgblight_get_sat(void) { 614 return rgblight_config.sat; 615 } 616 617 uint8_t rgblight_get_val(void) { 618 return rgblight_config.val; 619 } 620 621 hsv_t rgblight_get_hsv(void) { 622 return (hsv_t){rgblight_config.hue, rgblight_config.sat, rgblight_config.val}; 623 } 624 625 void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b) { 626 if (!rgblight_config.enable) { 627 return; 628 } 629 630 for (uint8_t i = rgblight_ranges.effect_start_pos; i < rgblight_ranges.effect_end_pos; i++) { 631 rgblight_driver.set_color(rgblight_led_index(i), r, g, b); 632 } 633 rgblight_set(); 634 } 635 636 void rgblight_setrgb_at(uint8_t r, uint8_t g, uint8_t b, uint8_t index) { 637 if (!rgblight_config.enable || index >= RGBLIGHT_LED_COUNT) { 638 return; 639 } 640 641 rgblight_driver.set_color(rgblight_led_index(index), r, g, b); 642 rgblight_set(); 643 } 644 645 void rgblight_sethsv_at(uint8_t hue, uint8_t sat, uint8_t val, uint8_t index) { 646 if (!rgblight_config.enable) { 647 return; 648 } 649 650 rgb_t rgb = rgblight_hsv_to_rgb((hsv_t){hue, sat, val > RGBLIGHT_LIMIT_VAL ? RGBLIGHT_LIMIT_VAL : val}); 651 rgblight_setrgb_at(rgb.r, rgb.g, rgb.b, index); 652 } 653 654 #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) 655 656 static uint8_t get_interval_time(const uint8_t *default_interval_address, uint8_t velocikey_min, uint8_t velocikey_max) { 657 return 658 # ifdef VELOCIKEY_ENABLE 659 rgblight_velocikey_enabled() ? rgblight_velocikey_match_speed(velocikey_min, velocikey_max) : 660 # endif 661 pgm_read_byte(default_interval_address); 662 } 663 664 #endif 665 666 void rgblight_setrgb_range(uint8_t r, uint8_t g, uint8_t b, uint8_t start, uint8_t end) { 667 if (!rgblight_config.enable || start < 0 || start >= end || end > RGBLIGHT_LED_COUNT) { 668 return; 669 } 670 671 for (uint8_t i = start; i < end; i++) { 672 rgblight_driver.set_color(rgblight_led_index(i), r, g, b); 673 } 674 rgblight_set(); 675 } 676 677 void rgblight_sethsv_range(uint8_t hue, uint8_t sat, uint8_t val, uint8_t start, uint8_t end) { 678 if (!rgblight_config.enable) { 679 return; 680 } 681 682 rgb_t rgb = rgblight_hsv_to_rgb((hsv_t){hue, sat, val > RGBLIGHT_LIMIT_VAL ? RGBLIGHT_LIMIT_VAL : val}); 683 rgblight_setrgb_range(rgb.r, rgb.g, rgb.b, start, end); 684 } 685 686 #ifndef RGBLIGHT_SPLIT 687 void rgblight_setrgb_master(uint8_t r, uint8_t g, uint8_t b) { 688 rgblight_setrgb_range(r, g, b, 0, (uint8_t)RGBLIGHT_LED_COUNT / 2); 689 } 690 691 void rgblight_setrgb_slave(uint8_t r, uint8_t g, uint8_t b) { 692 rgblight_setrgb_range(r, g, b, (uint8_t)RGBLIGHT_LED_COUNT / 2, (uint8_t)RGBLIGHT_LED_COUNT); 693 } 694 695 void rgblight_sethsv_master(uint8_t hue, uint8_t sat, uint8_t val) { 696 rgblight_sethsv_range(hue, sat, val, 0, (uint8_t)RGBLIGHT_LED_COUNT / 2); 697 } 698 699 void rgblight_sethsv_slave(uint8_t hue, uint8_t sat, uint8_t val) { 700 rgblight_sethsv_range(hue, sat, val, (uint8_t)RGBLIGHT_LED_COUNT / 2, (uint8_t)RGBLIGHT_LED_COUNT); 701 } 702 #endif // ifndef RGBLIGHT_SPLIT 703 704 #ifdef RGBLIGHT_LAYERS 705 void rgblight_set_layer_state(uint8_t layer, bool enabled) { 706 rgblight_layer_mask_t mask = (rgblight_layer_mask_t)1 << layer; 707 if (enabled) { 708 rgblight_status.enabled_layer_mask |= mask; 709 } else { 710 rgblight_status.enabled_layer_mask &= ~mask; 711 } 712 RGBLIGHT_SPLIT_SET_CHANGE_LAYERS; 713 714 // Calling rgblight_set() here (directly or indirectly) could 715 // potentially cause timing issues when there are multiple 716 // successive calls to rgblight_set_layer_state(). Instead, 717 // set a flag and do it the next time rgblight_task() runs. 718 719 deferred_set_layer_state = true; 720 } 721 722 bool rgblight_get_layer_state(uint8_t layer) { 723 rgblight_layer_mask_t mask = (rgblight_layer_mask_t)1 << layer; 724 return (rgblight_status.enabled_layer_mask & mask) != 0; 725 } 726 727 // Write any enabled LED layers into the buffer 728 static void rgblight_layers_write(void) { 729 # ifdef RGBLIGHT_LAYERS_RETAIN_VAL 730 uint8_t current_val = rgblight_get_val(); 731 # endif 732 uint8_t i = 0; 733 // For each layer 734 for (const rgblight_segment_t *const *layer_ptr = rgblight_layers; i < RGBLIGHT_MAX_LAYERS; layer_ptr++, i++) { 735 if (!rgblight_get_layer_state(i)) { 736 continue; // Layer is disabled 737 } 738 const rgblight_segment_t *segment_ptr = pgm_read_ptr(layer_ptr); 739 if (segment_ptr == NULL) { 740 break; // No more layers 741 } 742 // For each segment 743 while (1) { 744 rgblight_segment_t segment; 745 memcpy_P(&segment, segment_ptr, sizeof(rgblight_segment_t)); 746 if (segment.index == RGBLIGHT_END_SEGMENT_INDEX) { 747 break; // No more segments 748 } 749 // Write segment.count LEDs 750 int limit = MIN(segment.index + segment.count, RGBLIGHT_LED_COUNT); 751 for (int i = segment.index; i < limit; i++) { 752 # ifdef RGBLIGHT_LAYERS_RETAIN_VAL 753 sethsv(segment.hue, segment.sat, current_val, i); 754 # else 755 sethsv(segment.hue, segment.sat, segment.val, i); 756 # endif 757 } 758 segment_ptr++; 759 } 760 } 761 } 762 763 # ifdef RGBLIGHT_LAYER_BLINK 764 rgblight_layer_mask_t _blinking_layer_mask = 0; 765 static uint16_t _repeat_timer; 766 static uint8_t _times_remaining; 767 static uint16_t _dur; 768 769 void rgblight_blink_layer(uint8_t layer, uint16_t duration_ms) { 770 rgblight_blink_layer_repeat(layer, duration_ms, 1); 771 } 772 773 void rgblight_blink_layer_repeat(uint8_t layer, uint16_t duration_ms, uint8_t times) { 774 if (times > UINT8_MAX / 2) { 775 times = UINT8_MAX / 2; 776 } 777 778 _times_remaining = times * 2; 779 _dur = duration_ms; 780 781 rgblight_set_layer_state(layer, true); 782 _times_remaining--; 783 _blinking_layer_mask |= (rgblight_layer_mask_t)1 << layer; 784 _repeat_timer = sync_timer_read() + duration_ms; 785 } 786 787 void rgblight_unblink_layer(uint8_t layer) { 788 rgblight_set_layer_state(layer, false); 789 _blinking_layer_mask &= ~((rgblight_layer_mask_t)1 << layer); 790 } 791 792 void rgblight_unblink_all_but_layer(uint8_t layer) { 793 for (uint8_t i = 0; i < RGBLIGHT_MAX_LAYERS; i++) { 794 if (i != layer) { 795 if ((_blinking_layer_mask & (rgblight_layer_mask_t)1 << i) != 0) { 796 rgblight_unblink_layer(i); 797 } 798 } 799 } 800 } 801 802 void rgblight_blink_layer_repeat_helper(void) { 803 if (_blinking_layer_mask != 0 && timer_expired(sync_timer_read(), _repeat_timer)) { 804 for (uint8_t layer = 0; layer < RGBLIGHT_MAX_LAYERS; layer++) { 805 if ((_blinking_layer_mask & (rgblight_layer_mask_t)1 << layer) != 0) { 806 if (_times_remaining % 2 == 1) { 807 rgblight_set_layer_state(layer, false); 808 } else { 809 rgblight_set_layer_state(layer, true); 810 } 811 } 812 } 813 _times_remaining--; 814 if (_times_remaining <= 0) { 815 _blinking_layer_mask = 0; 816 } else { 817 _repeat_timer = sync_timer_read() + _dur; 818 } 819 } 820 } 821 # endif 822 823 #endif 824 825 #ifdef RGBLIGHT_SLEEP 826 827 void rgblight_suspend(void) { 828 rgblight_timer_disable(); 829 if (!is_suspended) { 830 is_suspended = true; 831 pre_suspend_enabled = rgblight_config.enable; 832 833 # ifdef RGBLIGHT_LAYER_BLINK 834 // make sure any layer blinks don't come back after suspend 835 rgblight_status.enabled_layer_mask &= ~_blinking_layer_mask; 836 _blinking_layer_mask = 0; 837 # endif 838 839 rgblight_disable_noeeprom(); 840 } 841 } 842 843 void rgblight_wakeup(void) { 844 is_suspended = false; 845 846 if (pre_suspend_enabled) { 847 rgblight_enable_noeeprom(); 848 } 849 # ifdef RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF 850 // Need this or else the LEDs won't be set 851 else if (rgblight_status.enabled_layer_mask != 0) { 852 rgblight_set(); 853 } 854 # endif 855 856 rgblight_timer_enable(); 857 } 858 859 #endif 860 861 void rgblight_set(void) { 862 if (!rgblight_config.enable) { 863 for (uint8_t i = rgblight_ranges.effect_start_pos; i < rgblight_ranges.effect_end_pos; i++) { 864 rgblight_driver.set_color(rgblight_led_index(i), 0, 0, 0); 865 } 866 } 867 868 #ifdef RGBLIGHT_LAYERS 869 if (rgblight_layers != NULL 870 # if !defined(RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF) 871 && rgblight_config.enable 872 # elif defined(RGBLIGHT_SLEEP) 873 && !is_suspended 874 # endif 875 ) { 876 rgblight_layers_write(); 877 } 878 #endif 879 880 rgblight_driver.flush(); 881 } 882 883 #ifdef RGBLIGHT_SPLIT 884 /* for split keyboard master side */ 885 uint8_t rgblight_get_change_flags(void) { 886 return rgblight_status.change_flags; 887 } 888 889 void rgblight_clear_change_flags(void) { 890 rgblight_status.change_flags = 0; 891 } 892 893 void rgblight_get_syncinfo(rgblight_syncinfo_t *syncinfo) { 894 syncinfo->config = rgblight_config; 895 syncinfo->status = rgblight_status; 896 } 897 898 /* for split keyboard slave side */ 899 void rgblight_update_sync(rgblight_syncinfo_t *syncinfo, bool write_to_eeprom) { 900 # ifdef RGBLIGHT_LAYERS 901 if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_LAYERS) { 902 rgblight_status.enabled_layer_mask = syncinfo->status.enabled_layer_mask; 903 } 904 # endif 905 if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_MODE) { 906 if (syncinfo->config.enable) { 907 rgblight_config.enable = 1; // == rgblight_enable_noeeprom(); 908 rgblight_mode_eeprom_helper(syncinfo->config.mode, write_to_eeprom); 909 } else { 910 rgblight_disable_noeeprom(); 911 } 912 } 913 if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_HSVS) { 914 rgblight_sethsv_eeprom_helper(syncinfo->config.hue, syncinfo->config.sat, syncinfo->config.val, write_to_eeprom); 915 // rgblight_config.speed = config->speed; // NEED??? 916 } 917 # ifdef RGBLIGHT_USE_TIMER 918 if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_TIMER) { 919 if (syncinfo->status.timer_enabled) { 920 rgblight_timer_enable(); 921 } else { 922 rgblight_timer_disable(); 923 } 924 } 925 # ifndef RGBLIGHT_SPLIT_NO_ANIMATION_SYNC 926 if (syncinfo->status.change_flags & RGBLIGHT_STATUS_ANIMATION_TICK) { 927 animation_status.restart = true; 928 } 929 # endif /* RGBLIGHT_SPLIT_NO_ANIMATION_SYNC */ 930 # endif /* RGBLIGHT_USE_TIMER */ 931 } 932 #endif /* RGBLIGHT_SPLIT */ 933 934 #ifdef RGBLIGHT_USE_TIMER 935 936 typedef void (*effect_func_t)(animation_status_t *anim); 937 938 // Animation timer -- use system timer (AVR Timer0) 939 void rgblight_timer_init(void) { 940 rgblight_status.timer_enabled = false; 941 RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE; 942 } 943 void rgblight_timer_enable(void) { 944 if (!is_static_effect(rgblight_config.mode)) { 945 rgblight_status.timer_enabled = true; 946 } 947 animation_status.last_timer = sync_timer_read(); 948 RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE; 949 dprintf("rgblight timer enabled.\n"); 950 } 951 void rgblight_timer_disable(void) { 952 rgblight_status.timer_enabled = false; 953 RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE; 954 dprintf("rgblight timer disable.\n"); 955 } 956 void rgblight_timer_toggle(void) { 957 dprintf("rgblight timer toggle.\n"); 958 if (rgblight_status.timer_enabled) { 959 rgblight_timer_disable(); 960 } else { 961 rgblight_timer_enable(); 962 } 963 } 964 965 void rgblight_show_solid_color(uint8_t r, uint8_t g, uint8_t b) { 966 rgblight_enable(); 967 rgblight_mode(RGBLIGHT_MODE_STATIC_LIGHT); 968 rgblight_setrgb(r, g, b); 969 } 970 971 static void rgblight_effect_dummy(animation_status_t *anim) { 972 // do nothing 973 /******** 974 dprintf("rgblight_task() what happened?\n"); 975 dprintf("is_static_effect %d\n", is_static_effect(rgblight_config.mode)); 976 dprintf("mode = %d, base_mode = %d, timer_enabled %d, ", 977 rgblight_config.mode, rgblight_status.base_mode, 978 rgblight_status.timer_enabled); 979 dprintf("last_timer = %d\n",anim->last_timer); 980 **/ 981 } 982 983 void rgblight_timer_task(void) { 984 if (rgblight_status.timer_enabled) { 985 effect_func_t effect_func = rgblight_effect_dummy; 986 uint16_t interval_time = 2000; // dummy interval 987 uint8_t delta = rgblight_config.mode - rgblight_status.base_mode; 988 animation_status.delta = delta; 989 990 // static light mode, do nothing here 991 if (1 == 0) { // dummy 992 } 993 # ifdef RGBLIGHT_EFFECT_BREATHING 994 else if (rgblight_status.base_mode == RGBLIGHT_MODE_BREATHING) { 995 // breathing mode 996 interval_time = get_interval_time(&RGBLED_BREATHING_INTERVALS[delta], 1, 100); 997 effect_func = rgblight_effect_breathing; 998 } 999 # endif 1000 # ifdef RGBLIGHT_EFFECT_RAINBOW_MOOD 1001 else if (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_MOOD) { 1002 // rainbow mood mode 1003 interval_time = get_interval_time(&RGBLED_RAINBOW_MOOD_INTERVALS[delta], 5, 100); 1004 effect_func = rgblight_effect_rainbow_mood; 1005 } 1006 # endif 1007 # ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL 1008 else if (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_SWIRL) { 1009 // rainbow swirl mode 1010 interval_time = get_interval_time(&RGBLED_RAINBOW_SWIRL_INTERVALS[delta / 2], 1, 100); 1011 effect_func = rgblight_effect_rainbow_swirl; 1012 } 1013 # endif 1014 # ifdef RGBLIGHT_EFFECT_SNAKE 1015 else if (rgblight_status.base_mode == RGBLIGHT_MODE_SNAKE) { 1016 // snake mode 1017 interval_time = get_interval_time(&RGBLED_SNAKE_INTERVALS[delta / 2], 1, 200); 1018 effect_func = rgblight_effect_snake; 1019 } 1020 # endif 1021 # ifdef RGBLIGHT_EFFECT_KNIGHT 1022 else if (rgblight_status.base_mode == RGBLIGHT_MODE_KNIGHT) { 1023 // knight mode 1024 interval_time = get_interval_time(&RGBLED_KNIGHT_INTERVALS[delta], 5, 100); 1025 effect_func = rgblight_effect_knight; 1026 } 1027 # endif 1028 # ifdef RGBLIGHT_EFFECT_CHRISTMAS 1029 else if (rgblight_status.base_mode == RGBLIGHT_MODE_CHRISTMAS) { 1030 // christmas mode 1031 interval_time = RGBLIGHT_EFFECT_CHRISTMAS_INTERVAL; 1032 effect_func = (effect_func_t)rgblight_effect_christmas; 1033 } 1034 # endif 1035 # ifdef RGBLIGHT_EFFECT_RGB_TEST 1036 else if (rgblight_status.base_mode == RGBLIGHT_MODE_RGB_TEST) { 1037 // RGB test mode 1038 interval_time = pgm_read_word(&RGBLED_RGBTEST_INTERVALS[0]); 1039 effect_func = (effect_func_t)rgblight_effect_rgbtest; 1040 } 1041 # endif 1042 # ifdef RGBLIGHT_EFFECT_ALTERNATING 1043 else if (rgblight_status.base_mode == RGBLIGHT_MODE_ALTERNATING) { 1044 interval_time = 500; 1045 effect_func = (effect_func_t)rgblight_effect_alternating; 1046 } 1047 # endif 1048 # ifdef RGBLIGHT_EFFECT_TWINKLE 1049 else if (rgblight_status.base_mode == RGBLIGHT_MODE_TWINKLE) { 1050 interval_time = get_interval_time(&RGBLED_TWINKLE_INTERVALS[delta % 3], 5, 30); 1051 effect_func = (effect_func_t)rgblight_effect_twinkle; 1052 } 1053 # endif 1054 if (animation_status.restart) { 1055 animation_status.restart = false; 1056 animation_status.last_timer = sync_timer_read(); 1057 animation_status.pos16 = 0; // restart signal to local each effect 1058 } 1059 uint16_t now = sync_timer_read(); 1060 if (timer_expired(now, animation_status.last_timer)) { 1061 # if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) 1062 static uint16_t report_last_timer = 0; 1063 static bool tick_flag = false; 1064 uint16_t oldpos16; 1065 if (tick_flag) { 1066 tick_flag = false; 1067 if (timer_expired(now, report_last_timer)) { 1068 report_last_timer += 30000; 1069 dprintf("rgblight animation tick report to slave\n"); 1070 RGBLIGHT_SPLIT_ANIMATION_TICK; 1071 } 1072 } 1073 oldpos16 = animation_status.pos16; 1074 # endif 1075 animation_status.last_timer += interval_time; 1076 effect_func(&animation_status); 1077 # if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) 1078 if (animation_status.pos16 == 0 && oldpos16 != 0) { 1079 tick_flag = true; 1080 } 1081 # endif 1082 } 1083 } 1084 1085 # ifdef RGBLIGHT_LAYERS 1086 # ifdef RGBLIGHT_LAYER_BLINK 1087 rgblight_blink_layer_repeat_helper(); 1088 # endif 1089 1090 if (deferred_set_layer_state) { 1091 deferred_set_layer_state = false; 1092 1093 // Static modes don't have a ticker running to update the LEDs 1094 if (rgblight_status.timer_enabled == false) { 1095 rgblight_mode_noeeprom(rgblight_config.mode); 1096 } 1097 1098 # ifdef RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF 1099 // If not enabled, then nothing else will actually set the LEDs... 1100 if (!rgblight_config.enable) { 1101 rgblight_set(); 1102 } 1103 # endif 1104 } 1105 # endif 1106 } 1107 1108 #endif /* RGBLIGHT_USE_TIMER */ 1109 1110 #if defined(RGBLIGHT_EFFECT_BREATHING) || defined(RGBLIGHT_EFFECT_TWINKLE) 1111 1112 # ifndef RGBLIGHT_EFFECT_BREATHE_CENTER 1113 # ifndef RGBLIGHT_BREATHE_TABLE_SIZE 1114 # define RGBLIGHT_BREATHE_TABLE_SIZE 256 // 256 or 128 or 64 1115 # endif 1116 # include <rgblight_breathe_table.h> 1117 # endif 1118 1119 static uint8_t breathe_calc(uint8_t pos) { 1120 // http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/ 1121 # ifdef RGBLIGHT_EFFECT_BREATHE_TABLE 1122 return pgm_read_byte(&rgblight_effect_breathe_table[pos / table_scale]); 1123 # else 1124 return (exp(sin((pos / 255.0) * M_PI)) - RGBLIGHT_EFFECT_BREATHE_CENTER / M_E) * (RGBLIGHT_EFFECT_BREATHE_MAX / (M_E - 1 / M_E)); 1125 # endif 1126 } 1127 1128 #endif 1129 1130 // Effects 1131 #ifdef RGBLIGHT_EFFECT_BREATHING 1132 1133 __attribute__((weak)) const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5}; 1134 1135 void rgblight_effect_breathing(animation_status_t *anim) { 1136 uint8_t val = breathe_calc(anim->pos); 1137 rgblight_sethsv_noeeprom_old(rgblight_config.hue, rgblight_config.sat, val); 1138 anim->pos = (anim->pos + 1); 1139 } 1140 #endif 1141 1142 #ifdef RGBLIGHT_EFFECT_RAINBOW_MOOD 1143 __attribute__((weak)) const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[] PROGMEM = {120, 60, 30}; 1144 1145 void rgblight_effect_rainbow_mood(animation_status_t *anim) { 1146 rgblight_sethsv_noeeprom_old(anim->current_hue, rgblight_config.sat, rgblight_config.val); 1147 anim->current_hue++; 1148 } 1149 #endif 1150 1151 #ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL 1152 # ifndef RGBLIGHT_RAINBOW_SWIRL_RANGE 1153 # define RGBLIGHT_RAINBOW_SWIRL_RANGE 255 1154 # endif 1155 1156 __attribute__((weak)) const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[] PROGMEM = {100, 50, 20}; 1157 1158 void rgblight_effect_rainbow_swirl(animation_status_t *anim) { 1159 uint8_t hue; 1160 uint8_t i; 1161 1162 for (i = 0; i < rgblight_ranges.effect_num_leds; i++) { 1163 hue = (RGBLIGHT_RAINBOW_SWIRL_RANGE / rgblight_ranges.effect_num_leds * i + anim->current_hue); 1164 sethsv(hue, rgblight_config.sat, rgblight_config.val, i + rgblight_ranges.effect_start_pos); 1165 } 1166 rgblight_set(); 1167 1168 if (anim->delta % 2) { 1169 anim->current_hue++; 1170 } else { 1171 anim->current_hue--; 1172 } 1173 } 1174 #endif 1175 1176 #ifdef RGBLIGHT_EFFECT_SNAKE 1177 __attribute__((weak)) const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {100, 50, 20}; 1178 1179 void rgblight_effect_snake(animation_status_t *anim) { 1180 static uint8_t pos = 0; 1181 uint8_t i, j; 1182 int8_t k; 1183 int8_t increment = 1; 1184 1185 if (anim->delta % 2) { 1186 increment = -1; 1187 } 1188 1189 # if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) 1190 if (anim->pos == 0) { // restart signal 1191 if (increment == 1) { 1192 pos = rgblight_ranges.effect_num_leds - 1; 1193 } else { 1194 pos = 0; 1195 } 1196 anim->pos = 1; 1197 } 1198 # endif 1199 1200 for (i = 0; i < rgblight_ranges.effect_num_leds; i++) { 1201 rgblight_driver.set_color(rgblight_led_index(i + rgblight_ranges.effect_start_pos), 0, 0, 0); 1202 1203 for (j = 0; j < RGBLIGHT_EFFECT_SNAKE_LENGTH; j++) { 1204 k = pos + j * increment; 1205 if (k > RGBLIGHT_LED_COUNT) { 1206 k = k % (RGBLIGHT_LED_COUNT); 1207 } 1208 if (k < 0) { 1209 k = k + rgblight_ranges.effect_num_leds; 1210 } 1211 if (i == k) { 1212 sethsv(rgblight_config.hue, rgblight_config.sat, (uint8_t)(rgblight_config.val * (RGBLIGHT_EFFECT_SNAKE_LENGTH - j) / RGBLIGHT_EFFECT_SNAKE_LENGTH), i + rgblight_ranges.effect_start_pos); 1213 } 1214 } 1215 } 1216 rgblight_set(); 1217 if (increment == 1) { 1218 if (pos - RGBLIGHT_EFFECT_SNAKE_INCREMENT < 0) { 1219 pos = rgblight_ranges.effect_num_leds - 1; 1220 # if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) 1221 anim->pos = 0; 1222 # endif 1223 } else { 1224 pos -= RGBLIGHT_EFFECT_SNAKE_INCREMENT; 1225 # if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) 1226 anim->pos = 1; 1227 # endif 1228 } 1229 } else { 1230 pos = (pos + RGBLIGHT_EFFECT_SNAKE_INCREMENT) % rgblight_ranges.effect_num_leds; 1231 # if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) 1232 anim->pos = pos; 1233 # endif 1234 } 1235 } 1236 #endif 1237 1238 #ifdef RGBLIGHT_EFFECT_KNIGHT 1239 __attribute__((weak)) const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {127, 63, 31}; 1240 1241 void rgblight_effect_knight(animation_status_t *anim) { 1242 static int8_t low_bound = 0; 1243 static int8_t high_bound = RGBLIGHT_EFFECT_KNIGHT_LENGTH - 1; 1244 static int8_t increment = RGBLIGHT_EFFECT_KNIGHT_INCREMENT; 1245 uint8_t i, cur; 1246 1247 # if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) 1248 if (anim->pos == 0) { // restart signal 1249 anim->pos = 1; 1250 low_bound = 0; 1251 high_bound = RGBLIGHT_EFFECT_KNIGHT_LENGTH - 1; 1252 increment = 1; 1253 } 1254 # endif 1255 // Set all the LEDs to 0 1256 for (i = rgblight_ranges.effect_start_pos; i < rgblight_ranges.effect_end_pos; i++) { 1257 rgblight_driver.set_color(rgblight_led_index(i), 0, 0, 0); 1258 } 1259 // Determine which LEDs should be lit up 1260 for (i = 0; i < RGBLIGHT_EFFECT_KNIGHT_LED_NUM; i++) { 1261 cur = (i + RGBLIGHT_EFFECT_KNIGHT_OFFSET) % rgblight_ranges.effect_num_leds + rgblight_ranges.effect_start_pos; 1262 1263 if (i >= low_bound && i <= high_bound) { 1264 sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, cur); 1265 } else { 1266 rgblight_driver.set_color(rgblight_led_index(cur), 0, 0, 0); 1267 } 1268 } 1269 rgblight_set(); 1270 1271 // Move from low_bound to high_bound changing the direction we increment each 1272 // time a boundary is hit. 1273 low_bound += increment; 1274 high_bound += increment; 1275 1276 if (high_bound <= 0 || low_bound >= RGBLIGHT_EFFECT_KNIGHT_LED_NUM - 1) { 1277 increment = -increment; 1278 # if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) 1279 if (increment == 1) { 1280 anim->pos = 0; 1281 } 1282 # endif 1283 } 1284 } 1285 #endif 1286 1287 #ifdef RGBLIGHT_EFFECT_CHRISTMAS 1288 # define CUBED(x) ((x) * (x) * (x)) 1289 1290 /** 1291 * Christmas lights effect, with a smooth animation between red & green. 1292 */ 1293 void rgblight_effect_christmas(animation_status_t *anim) { 1294 static int8_t increment = 1; 1295 const uint8_t max_pos = 32; 1296 const uint8_t hue_green = 85; 1297 1298 uint32_t xa; 1299 uint8_t hue, val; 1300 uint8_t i; 1301 1302 // The effect works by animating anim->pos from 0 to 32 and back to 0. 1303 // The pos is used in a cubic bezier formula to ease-in-out between red and green, leaving the interpolated colors visible as short as possible. 1304 xa = CUBED((uint32_t)anim->pos); 1305 hue = ((uint32_t)hue_green) * xa / (xa + CUBED((uint32_t)(max_pos - anim->pos))); 1306 // Additionally, these interpolated colors get shown with a slightly darker value, to make them less prominent than the main colors. 1307 val = 255 - (3 * (hue < hue_green / 2 ? hue : hue_green - hue) / 2); 1308 1309 for (i = 0; i < rgblight_ranges.effect_num_leds; i++) { 1310 uint8_t local_hue = (i / RGBLIGHT_EFFECT_CHRISTMAS_STEP) % 2 ? hue : hue_green - hue; 1311 sethsv(local_hue, rgblight_config.sat, val, i + rgblight_ranges.effect_start_pos); 1312 } 1313 rgblight_set(); 1314 1315 if (anim->pos == 0) { 1316 increment = 1; 1317 } else if (anim->pos == max_pos) { 1318 increment = -1; 1319 } 1320 anim->pos += increment; 1321 } 1322 #endif 1323 1324 #ifdef RGBLIGHT_EFFECT_RGB_TEST 1325 __attribute__((weak)) const uint16_t RGBLED_RGBTEST_INTERVALS[] PROGMEM = {1024}; 1326 1327 void rgblight_effect_rgbtest(animation_status_t *anim) { 1328 uint8_t val = rgblight_get_val(); 1329 1330 uint8_t r = anim->pos & 1 ? val : 0; 1331 uint8_t g = anim->pos & 2 ? val : 0; 1332 uint8_t b = anim->pos & 4 ? val : 0; 1333 rgblight_setrgb(r, g, b); 1334 anim->pos = (anim->pos + 1) % 8; 1335 } 1336 #endif 1337 1338 #ifdef RGBLIGHT_EFFECT_ALTERNATING 1339 void rgblight_effect_alternating(animation_status_t *anim) { 1340 for (int i = 0; i < rgblight_ranges.effect_num_leds; i++) { 1341 if (i < rgblight_ranges.effect_num_leds / 2 && anim->pos) { 1342 sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, i + rgblight_ranges.effect_start_pos); 1343 } else if (i >= rgblight_ranges.effect_num_leds / 2 && !anim->pos) { 1344 sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, i + rgblight_ranges.effect_start_pos); 1345 } else { 1346 sethsv(rgblight_config.hue, rgblight_config.sat, 0, i + rgblight_ranges.effect_start_pos); 1347 } 1348 } 1349 rgblight_set(); 1350 anim->pos = (anim->pos + 1) % 2; 1351 } 1352 #endif 1353 1354 #ifdef RGBLIGHT_EFFECT_TWINKLE 1355 __attribute__((weak)) const uint8_t RGBLED_TWINKLE_INTERVALS[] PROGMEM = {30, 15, 5}; 1356 1357 typedef struct PACKED { 1358 hsv_t hsv; 1359 uint8_t life; 1360 uint8_t max_life; 1361 } TwinkleState; 1362 1363 static TwinkleState led_twinkle_state[RGBLIGHT_LED_COUNT]; 1364 1365 void rgblight_effect_twinkle(animation_status_t *anim) { 1366 const bool random_color = anim->delta / 3; 1367 const bool restart = anim->pos == 0; 1368 anim->pos = 1; 1369 1370 const uint8_t bottom = breathe_calc(0); 1371 const uint8_t top = breathe_calc(127); 1372 1373 uint8_t frac(uint8_t n, uint8_t d) { 1374 return (uint16_t)255 * n / d; 1375 } 1376 uint8_t scale(uint16_t v, uint8_t scale) { 1377 return (v * scale) >> 8; 1378 } 1379 1380 const uint8_t trigger = scale((uint16_t)0xFF * RGBLIGHT_EFFECT_TWINKLE_PROBABILITY, 127 + rgblight_config.val / 2); 1381 1382 for (uint8_t i = 0; i < rgblight_ranges.effect_num_leds; i++) { 1383 TwinkleState *t = &(led_twinkle_state[i]); 1384 hsv_t *c = &(t->hsv); 1385 1386 if (!random_color) { 1387 c->h = rgblight_config.hue; 1388 c->s = rgblight_config.sat; 1389 } 1390 1391 if (restart) { 1392 // Restart 1393 t->life = 0; 1394 c->v = 0; 1395 } else if (t->life) { 1396 // This LED is already on, either brightening or dimming 1397 t->life--; 1398 uint8_t unscaled = frac(breathe_calc(frac(t->life, t->max_life)) - bottom, top - bottom); 1399 c->v = scale(rgblight_config.val, unscaled); 1400 } else if ((rand() % 0xFF) < trigger) { 1401 // This LED is off, but was randomly selected to start brightening 1402 if (random_color) { 1403 c->h = rand() % 0xFF; 1404 c->s = (rand() % (rgblight_config.sat / 2)) + (rgblight_config.sat / 2); 1405 } 1406 c->v = 0; 1407 t->max_life = MAX(20, MIN(RGBLIGHT_EFFECT_TWINKLE_LIFE, rgblight_config.val)); 1408 t->life = t->max_life; 1409 } else { 1410 // This LED is off, and was NOT selected to start brightening 1411 } 1412 1413 sethsv(c->h, c->s, c->v, i + rgblight_ranges.effect_start_pos); 1414 } 1415 1416 rgblight_set(); 1417 } 1418 #endif 1419 1420 void preprocess_rgblight(void) { 1421 #ifdef VELOCIKEY_ENABLE 1422 if (rgblight_velocikey_enabled()) { 1423 rgblight_velocikey_accelerate(); 1424 } 1425 #endif 1426 } 1427 1428 void rgblight_task(void) { 1429 #ifdef RGBLIGHT_USE_TIMER 1430 rgblight_timer_task(); 1431 #endif 1432 1433 #ifdef VELOCIKEY_ENABLE 1434 if (rgblight_velocikey_enabled()) { 1435 rgblight_velocikey_decelerate(); 1436 } 1437 #endif 1438 } 1439 1440 #ifdef VELOCIKEY_ENABLE 1441 # define TYPING_SPEED_MAX_VALUE 200 1442 1443 static uint8_t typing_speed = 0; 1444 1445 bool rgblight_velocikey_enabled(void) { 1446 return rgblight_config.velocikey; 1447 } 1448 1449 void rgblight_velocikey_toggle(void) { 1450 dprintf("rgblight velocikey toggle [EEPROM]: rgblight_config.velocikey = %u\n", !rgblight_config.velocikey); 1451 rgblight_config.velocikey = !rgblight_config.velocikey; 1452 eeconfig_update_rgblight_current(); 1453 } 1454 1455 void rgblight_velocikey_accelerate(void) { 1456 if (typing_speed < TYPING_SPEED_MAX_VALUE) typing_speed += (TYPING_SPEED_MAX_VALUE / 100); 1457 } 1458 1459 void rgblight_velocikey_decelerate(void) { 1460 static uint16_t decay_timer = 0; 1461 1462 if (timer_elapsed(decay_timer) > 500 || decay_timer == 0) { 1463 if (typing_speed > 0) typing_speed -= 1; 1464 // Decay a little faster at half of max speed 1465 if (typing_speed > TYPING_SPEED_MAX_VALUE / 2) typing_speed -= 1; 1466 // Decay even faster at 3/4 of max speed 1467 if (typing_speed > TYPING_SPEED_MAX_VALUE / 4 * 3) typing_speed -= 2; 1468 decay_timer = timer_read(); 1469 } 1470 } 1471 1472 uint8_t rgblight_velocikey_match_speed(uint8_t minValue, uint8_t maxValue) { 1473 return MAX(minValue, maxValue - (maxValue - minValue) * ((float)typing_speed / TYPING_SPEED_MAX_VALUE)); 1474 } 1475 1476 #endif