led_matrix.c (25622B)
1 /* Copyright 2017 Jason Williams 2 * Copyright 2017 Jack Humbert 3 * Copyright 2018 Yiancar 4 * Copyright 2019 Clueboard 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "led_matrix.h" 21 #include "progmem.h" 22 #include "eeconfig.h" 23 #include "keyboard.h" 24 #include "sync_timer.h" 25 #include "debug.h" 26 #include <string.h> 27 #include <math.h> 28 #include <stdlib.h> 29 #include "led_tables.h" 30 31 #include <lib/lib8tion/lib8tion.h> 32 33 #ifndef LED_MATRIX_CENTER 34 const led_point_t k_led_matrix_center = {112, 32}; 35 #else 36 const led_point_t k_led_matrix_center = LED_MATRIX_CENTER; 37 #endif 38 39 // Generic effect runners 40 #include "led_matrix_runners.inc" 41 42 // ------------------------------------------ 43 // -----Begin led effect includes macros----- 44 #define LED_MATRIX_EFFECT(name) 45 #define LED_MATRIX_CUSTOM_EFFECT_IMPLS 46 47 #include "led_matrix_effects.inc" 48 #ifdef COMMUNITY_MODULES_ENABLE 49 # include "led_matrix_community_modules.inc" 50 #endif 51 #ifdef LED_MATRIX_CUSTOM_KB 52 # include "led_matrix_kb.inc" 53 #endif 54 #ifdef LED_MATRIX_CUSTOM_USER 55 # include "led_matrix_user.inc" 56 #endif 57 58 #undef LED_MATRIX_CUSTOM_EFFECT_IMPLS 59 #undef LED_MATRIX_EFFECT 60 // -----End led effect includes macros------- 61 // ------------------------------------------ 62 63 // globals 64 led_eeconfig_t led_matrix_eeconfig; // TODO: would like to prefix this with g_ for global consistancy, do this in another pr 65 uint32_t g_led_timer; 66 #ifdef LED_MATRIX_FRAMEBUFFER_EFFECTS 67 uint8_t g_led_frame_buffer[MATRIX_ROWS][MATRIX_COLS] = {{0}}; 68 #endif // LED_MATRIX_FRAMEBUFFER_EFFECTS 69 #ifdef LED_MATRIX_KEYREACTIVE_ENABLED 70 last_hit_t g_last_hit_tracker; 71 #endif // LED_MATRIX_KEYREACTIVE_ENABLED 72 73 #ifndef LED_MATRIX_FLAG_STEPS 74 # define LED_MATRIX_FLAG_STEPS {LED_FLAG_ALL, LED_FLAG_KEYLIGHT | LED_FLAG_MODIFIER, LED_FLAG_NONE} 75 #endif 76 static const uint8_t led_matrix_flag_steps[] = LED_MATRIX_FLAG_STEPS; 77 #define LED_MATRIX_FLAG_STEPS_COUNT ARRAY_SIZE(led_matrix_flag_steps) 78 79 // internals 80 static bool suspend_state = false; 81 static uint8_t led_last_enable = UINT8_MAX; 82 static uint8_t led_last_effect = UINT8_MAX; 83 static uint8_t led_current_effect = 0; 84 static effect_params_t led_effect_params = {0, LED_FLAG_ALL, false}; 85 static led_task_states led_task_state = SYNCING; 86 87 // double buffers 88 static uint32_t led_timer_buffer; 89 #ifdef LED_MATRIX_KEYREACTIVE_ENABLED 90 static last_hit_t last_hit_buffer; 91 #endif // LED_MATRIX_KEYREACTIVE_ENABLED 92 93 // split led matrix 94 #if defined(LED_MATRIX_SPLIT) 95 const uint8_t k_led_matrix_split[2] = LED_MATRIX_SPLIT; 96 #endif 97 98 EECONFIG_DEBOUNCE_HELPER(led_matrix, led_matrix_eeconfig); 99 100 void eeconfig_force_flush_led_matrix(void) { 101 eeconfig_flush_led_matrix(true); 102 } 103 104 void eeconfig_update_led_matrix_default(void) { 105 dprintf("eeconfig_update_led_matrix_default\n"); 106 led_matrix_eeconfig.enable = LED_MATRIX_DEFAULT_ON; 107 led_matrix_eeconfig.mode = LED_MATRIX_DEFAULT_MODE; 108 led_matrix_eeconfig.val = LED_MATRIX_DEFAULT_VAL; 109 led_matrix_eeconfig.speed = LED_MATRIX_DEFAULT_SPD; 110 led_matrix_eeconfig.flags = LED_MATRIX_DEFAULT_FLAGS; 111 eeconfig_flush_led_matrix(true); 112 } 113 114 void eeconfig_debug_led_matrix(void) { 115 dprintf("led_matrix_eeconfig EEPROM\n"); 116 dprintf("led_matrix_eeconfig.enable = %d\n", led_matrix_eeconfig.enable); 117 #ifdef LED_MATRIX_MODE_NAME_ENABLE 118 dprintf("led_matrix_eeconfig.mode = %d (%s)\n", led_matrix_eeconfig.mode, led_matrix_get_mode_name(led_matrix_eeconfig.mode)); 119 #else 120 dprintf("led_matrix_eeconfig.mode = %d\n", led_matrix_eeconfig.mode); 121 #endif // LED_MATRIX_MODE_NAME_ENABLE 122 dprintf("led_matrix_eeconfig.val = %d\n", led_matrix_eeconfig.val); 123 dprintf("led_matrix_eeconfig.speed = %d\n", led_matrix_eeconfig.speed); 124 dprintf("led_matrix_eeconfig.flags = %d\n", led_matrix_eeconfig.flags); 125 } 126 127 void led_matrix_reload_from_eeprom(void) { 128 led_matrix_disable_noeeprom(); 129 /* Reset back to what we have in eeprom */ 130 eeconfig_init_led_matrix(); 131 eeconfig_debug_led_matrix(); // display current eeprom values 132 if (led_matrix_eeconfig.enable) { 133 led_matrix_mode_noeeprom(led_matrix_eeconfig.mode); 134 } 135 } 136 137 __attribute__((weak)) uint8_t led_matrix_map_row_column_to_led_kb(uint8_t row, uint8_t column, uint8_t *led_i) { 138 return 0; 139 } 140 141 uint8_t led_matrix_map_row_column_to_led(uint8_t row, uint8_t column, uint8_t *led_i) { 142 uint8_t led_count = led_matrix_map_row_column_to_led_kb(row, column, led_i); 143 uint8_t led_index = g_led_config.matrix_co[row][column]; 144 if (led_index != NO_LED) { 145 led_i[led_count] = led_index; 146 led_count++; 147 } 148 return led_count; 149 } 150 151 void led_matrix_update_pwm_buffers(void) { 152 led_matrix_driver.flush(); 153 } 154 155 __attribute__((weak)) int led_matrix_led_index(int index) { 156 #if defined(LED_MATRIX_SPLIT) 157 if (!is_keyboard_left() && index >= k_led_matrix_split[0]) { 158 return index - k_led_matrix_split[0]; 159 } 160 #endif 161 return index; 162 } 163 164 void led_matrix_set_value(int index, uint8_t value) { 165 #ifdef USE_CIE1931_CURVE 166 value = pgm_read_byte(&CIE1931_CURVE[value]); 167 #endif 168 led_matrix_driver.set_value(led_matrix_led_index(index), value); 169 } 170 171 void led_matrix_set_value_all(uint8_t value) { 172 #if defined(LED_MATRIX_SPLIT) 173 for (uint8_t i = 0; i < LED_MATRIX_LED_COUNT; i++) 174 led_matrix_set_value(i, value); 175 #else 176 # ifdef USE_CIE1931_CURVE 177 led_matrix_driver.set_value_all(pgm_read_byte(&CIE1931_CURVE[value])); 178 # else 179 led_matrix_driver.set_value_all(value); 180 # endif 181 #endif 182 } 183 184 void led_matrix_handle_key_event(uint8_t row, uint8_t col, bool pressed) { 185 #ifndef LED_MATRIX_SPLIT 186 if (!is_keyboard_master()) return; 187 #endif 188 189 #ifdef LED_MATRIX_KEYREACTIVE_ENABLED 190 uint8_t led[LED_HITS_TO_REMEMBER]; 191 uint8_t led_count = 0; 192 193 # if defined(LED_MATRIX_KEYRELEASES) 194 if (!pressed) 195 # elif defined(LED_MATRIX_KEYPRESSES) 196 if (pressed) 197 # endif // defined(LED_MATRIX_KEYRELEASES) 198 { 199 led_count = led_matrix_map_row_column_to_led(row, col, led); 200 } 201 202 if (last_hit_buffer.count + led_count > LED_HITS_TO_REMEMBER) { 203 memcpy(&last_hit_buffer.x[0], &last_hit_buffer.x[led_count], LED_HITS_TO_REMEMBER - led_count); 204 memcpy(&last_hit_buffer.y[0], &last_hit_buffer.y[led_count], LED_HITS_TO_REMEMBER - led_count); 205 memcpy(&last_hit_buffer.tick[0], &last_hit_buffer.tick[led_count], (LED_HITS_TO_REMEMBER - led_count) * 2); // 16 bit 206 memcpy(&last_hit_buffer.index[0], &last_hit_buffer.index[led_count], LED_HITS_TO_REMEMBER - led_count); 207 last_hit_buffer.count = LED_HITS_TO_REMEMBER - led_count; 208 } 209 210 for (uint8_t i = 0; i < led_count; i++) { 211 uint8_t index = last_hit_buffer.count; 212 last_hit_buffer.x[index] = g_led_config.point[led[i]].x; 213 last_hit_buffer.y[index] = g_led_config.point[led[i]].y; 214 last_hit_buffer.index[index] = led[i]; 215 last_hit_buffer.tick[index] = 0; 216 last_hit_buffer.count++; 217 } 218 #endif // LED_MATRIX_KEYREACTIVE_ENABLED 219 220 #if defined(LED_MATRIX_FRAMEBUFFER_EFFECTS) && defined(ENABLE_LED_MATRIX_TYPING_HEATMAP) 221 if (led_matrix_eeconfig.mode == LED_MATRIX_TYPING_HEATMAP) { 222 process_led_matrix_typing_heatmap(row, col); 223 } 224 #endif // defined(LED_MATRIX_FRAMEBUFFER_EFFECTS) && defined(ENABLE_LED_MATRIX_TYPING_HEATMAP) 225 } 226 227 static bool led_matrix_none(effect_params_t *params) { 228 if (!params->init) { 229 return false; 230 } 231 232 led_matrix_set_value_all(0); 233 return false; 234 } 235 236 static void led_task_timers(void) { 237 #if defined(LED_MATRIX_KEYREACTIVE_ENABLED) 238 uint32_t deltaTime = sync_timer_elapsed32(led_timer_buffer); 239 #endif // defined(LED_MATRIX_KEYREACTIVE_ENABLED) 240 led_timer_buffer = sync_timer_read32(); 241 242 // Update double buffer last hit timers 243 #ifdef LED_MATRIX_KEYREACTIVE_ENABLED 244 uint8_t count = last_hit_buffer.count; 245 for (uint8_t i = 0; i < count; ++i) { 246 if (UINT16_MAX - deltaTime < last_hit_buffer.tick[i]) { 247 last_hit_buffer.count--; 248 continue; 249 } 250 last_hit_buffer.tick[i] += deltaTime; 251 } 252 #endif // LED_MATRIX_KEYREACTIVE_ENABLED 253 } 254 255 static void led_task_sync(void) { 256 eeconfig_flush_led_matrix(false); 257 // next task 258 if (sync_timer_elapsed32(g_led_timer) >= LED_MATRIX_LED_FLUSH_LIMIT) led_task_state = STARTING; 259 } 260 261 static void led_task_start(void) { 262 // reset iter 263 led_effect_params.iter = 0; 264 265 // update double buffers 266 g_led_timer = led_timer_buffer; 267 #ifdef LED_MATRIX_KEYREACTIVE_ENABLED 268 g_last_hit_tracker = last_hit_buffer; 269 #endif // LED_MATRIX_KEYREACTIVE_ENABLED 270 271 // Ideally we would also stop sending zeros to the LED driver PWM buffers 272 // while suspended and just do a software shutdown. This is a cheap hack for now. 273 bool suspend_backlight = suspend_state || 274 #if LED_MATRIX_TIMEOUT > 0 275 (last_input_activity_elapsed() > (uint32_t)LED_MATRIX_TIMEOUT) || 276 #endif // LED_MATRIX_TIMEOUT > 0 277 false; 278 279 // Set effect to be renedered 280 led_current_effect = suspend_backlight || !led_matrix_eeconfig.enable ? 0 : led_matrix_eeconfig.mode; 281 282 // next task 283 led_task_state = RENDERING; 284 } 285 286 static void led_task_render(uint8_t effect) { 287 bool rendering = false; 288 led_effect_params.init = (effect != led_last_effect) || (led_matrix_eeconfig.enable != led_last_enable); 289 if (led_effect_params.flags != led_matrix_eeconfig.flags) { 290 led_effect_params.flags = led_matrix_eeconfig.flags; 291 led_matrix_set_value_all(0); 292 } 293 294 // each effect can opt to do calculations 295 // and/or request PWM buffer updates. 296 switch (effect) { 297 case LED_MATRIX_NONE: 298 rendering = led_matrix_none(&led_effect_params); 299 break; 300 301 // --------------------------------------------- 302 // -----Begin led effect switch case macros----- 303 #define LED_MATRIX_EFFECT(name, ...) \ 304 case LED_MATRIX_##name: \ 305 rendering = name(&led_effect_params); \ 306 break; 307 #include "led_matrix_effects.inc" 308 #undef LED_MATRIX_EFFECT 309 310 #ifdef COMMUNITY_MODULES_ENABLE 311 # define LED_MATRIX_EFFECT(name, ...) \ 312 case LED_MATRIX_COMMUNITY_MODULE_##name: \ 313 rendering = name(&led_effect_params); \ 314 break; 315 # include "led_matrix_community_modules.inc" 316 # undef LED_MATRIX_EFFECT 317 #endif 318 319 #if defined(LED_MATRIX_CUSTOM_KB) || defined(LED_MATRIX_CUSTOM_USER) 320 # define LED_MATRIX_EFFECT(name, ...) \ 321 case LED_MATRIX_CUSTOM_##name: \ 322 rendering = name(&led_effect_params); \ 323 break; 324 # ifdef LED_MATRIX_CUSTOM_KB 325 # include "led_matrix_kb.inc" 326 # endif 327 # ifdef LED_MATRIX_CUSTOM_USER 328 # include "led_matrix_user.inc" 329 # endif 330 # undef LED_MATRIX_EFFECT 331 #endif 332 // -----End led effect switch case macros------- 333 // --------------------------------------------- 334 } 335 336 led_effect_params.iter++; 337 338 // next task 339 if (!rendering) { 340 led_task_state = FLUSHING; 341 if (!led_effect_params.init && effect == LED_MATRIX_NONE) { 342 // We only need to flush once if we are LED_MATRIX_NONE 343 led_task_state = SYNCING; 344 } 345 } 346 } 347 348 static void led_task_flush(uint8_t effect) { 349 // update last trackers after the first full render so we can init over several frames 350 led_last_effect = effect; 351 led_last_enable = led_matrix_eeconfig.enable; 352 353 // update pwm buffers 354 led_matrix_update_pwm_buffers(); 355 356 // next task 357 led_task_state = SYNCING; 358 } 359 360 void led_matrix_task(void) { 361 led_task_timers(); 362 363 uint8_t effect = led_current_effect; 364 365 switch (led_task_state) { 366 case STARTING: 367 led_task_start(); 368 break; 369 case RENDERING: 370 led_task_render(effect); 371 if (effect) { 372 if (led_task_state == FLUSHING) { 373 led_matrix_indicators(); // ensure we only draw basic indicators once rendering is finished 374 } 375 led_matrix_indicators_advanced(&led_effect_params); 376 } 377 break; 378 case FLUSHING: 379 led_task_flush(effect); 380 break; 381 case SYNCING: 382 led_task_sync(); 383 break; 384 } 385 } 386 387 __attribute__((weak)) bool led_matrix_indicators_modules(void) { 388 return true; 389 } 390 391 void led_matrix_indicators(void) { 392 led_matrix_indicators_modules(); 393 led_matrix_indicators_kb(); 394 } 395 396 __attribute__((weak)) bool led_matrix_indicators_kb(void) { 397 return led_matrix_indicators_user(); 398 } 399 400 __attribute__((weak)) bool led_matrix_indicators_user(void) { 401 return true; 402 } 403 404 __attribute__((weak)) bool led_matrix_indicators_advanced_modules(uint8_t led_min, uint8_t led_max) { 405 return true; 406 } 407 408 void led_matrix_indicators_advanced(effect_params_t *params) { 409 /* special handling is needed for "params->iter", since it's already been incremented. 410 * Could move the invocations to led_task_render, but then it's missing a few checks 411 * and not sure which would be better. Otherwise, this should be called from 412 * led_task_render, right before the iter++ line. 413 */ 414 LED_MATRIX_USE_LIMITS_ITER(min, max, params->iter - 1); 415 led_matrix_indicators_advanced_modules(min, max); 416 led_matrix_indicators_advanced_kb(min, max); 417 } 418 419 __attribute__((weak)) bool led_matrix_indicators_advanced_kb(uint8_t led_min, uint8_t led_max) { 420 return led_matrix_indicators_advanced_user(led_min, led_max); 421 } 422 423 __attribute__((weak)) bool led_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) { 424 return true; 425 } 426 427 struct led_matrix_limits_t led_matrix_get_limits(uint8_t iter) { 428 struct led_matrix_limits_t limits = {0}; 429 #if defined(LED_MATRIX_LED_PROCESS_LIMIT) && LED_MATRIX_LED_PROCESS_LIMIT > 0 && LED_MATRIX_LED_PROCESS_LIMIT < LED_MATRIX_LED_COUNT 430 # if defined(LED_MATRIX_SPLIT) 431 limits.led_min_index = LED_MATRIX_LED_PROCESS_LIMIT * (iter); 432 limits.led_max_index = limits.led_min_index + LED_MATRIX_LED_PROCESS_LIMIT; 433 if (limits.led_max_index > LED_MATRIX_LED_COUNT) limits.led_max_index = LED_MATRIX_LED_COUNT; 434 if (is_keyboard_left() && (limits.led_max_index > k_led_matrix_split[0])) limits.led_max_index = k_led_matrix_split[0]; 435 if (!(is_keyboard_left()) && (limits.led_min_index < k_led_matrix_split[0])) limits.led_min_index = k_led_matrix_split[0]; 436 # else 437 limits.led_min_index = LED_MATRIX_LED_PROCESS_LIMIT * (iter); 438 limits.led_max_index = limits.led_min_index + LED_MATRIX_LED_PROCESS_LIMIT; 439 if (limits.led_max_index > LED_MATRIX_LED_COUNT) limits.led_max_index = LED_MATRIX_LED_COUNT; 440 # endif 441 #else 442 # if defined(LED_MATRIX_SPLIT) 443 limits.led_min_index = 0; 444 limits.led_max_index = LED_MATRIX_LED_COUNT; 445 if (is_keyboard_left() && (limits.led_max_index > k_led_matrix_split[0])) limits.led_max_index = k_led_matrix_split[0]; 446 if (!(is_keyboard_left()) && (limits.led_min_index < k_led_matrix_split[0])) limits.led_min_index = k_led_matrix_split[0]; 447 # else 448 limits.led_min_index = 0; 449 limits.led_max_index = LED_MATRIX_LED_COUNT; 450 # endif 451 #endif 452 return limits; 453 } 454 455 void led_matrix_init(void) { 456 led_matrix_driver.init(); 457 458 #ifdef LED_MATRIX_KEYREACTIVE_ENABLED 459 g_last_hit_tracker.count = 0; 460 for (uint8_t i = 0; i < LED_HITS_TO_REMEMBER; ++i) { 461 g_last_hit_tracker.tick[i] = UINT16_MAX; 462 } 463 464 last_hit_buffer.count = 0; 465 for (uint8_t i = 0; i < LED_HITS_TO_REMEMBER; ++i) { 466 last_hit_buffer.tick[i] = UINT16_MAX; 467 } 468 #endif // LED_MATRIX_KEYREACTIVE_ENABLED 469 470 eeconfig_init_led_matrix(); 471 if (!led_matrix_eeconfig.mode) { 472 dprintf("led_matrix_init_drivers led_matrix_eeconfig.mode = 0. Write default values to EEPROM.\n"); 473 eeconfig_update_led_matrix_default(); 474 } 475 eeconfig_debug_led_matrix(); // display current eeprom values 476 } 477 478 void led_matrix_set_suspend_state(bool state) { 479 #ifdef LED_MATRIX_SLEEP 480 if (state && !suspend_state && is_keyboard_master()) { // only run if turning off, and only once 481 led_task_render(0); // turn off all LEDs when suspending 482 led_task_flush(0); // and actually flash led state to LEDs 483 } 484 suspend_state = state; 485 #endif 486 } 487 488 bool led_matrix_get_suspend_state(void) { 489 return suspend_state; 490 } 491 492 void led_matrix_toggle_eeprom_helper(bool write_to_eeprom) { 493 led_matrix_eeconfig.enable ^= 1; 494 led_task_state = STARTING; 495 eeconfig_flag_led_matrix(write_to_eeprom); 496 dprintf("led matrix toggle [%s]: led_matrix_eeconfig.enable = %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.enable); 497 } 498 void led_matrix_toggle_noeeprom(void) { 499 led_matrix_toggle_eeprom_helper(false); 500 } 501 void led_matrix_toggle(void) { 502 led_matrix_toggle_eeprom_helper(true); 503 } 504 505 void led_matrix_enable(void) { 506 led_matrix_enable_noeeprom(); 507 eeconfig_flag_led_matrix(true); 508 } 509 510 void led_matrix_enable_noeeprom(void) { 511 if (!led_matrix_eeconfig.enable) led_task_state = STARTING; 512 led_matrix_eeconfig.enable = 1; 513 } 514 515 void led_matrix_disable(void) { 516 led_matrix_disable_noeeprom(); 517 eeconfig_flag_led_matrix(true); 518 } 519 520 void led_matrix_disable_noeeprom(void) { 521 if (led_matrix_eeconfig.enable) led_task_state = STARTING; 522 led_matrix_eeconfig.enable = 0; 523 } 524 525 uint8_t led_matrix_is_enabled(void) { 526 return led_matrix_eeconfig.enable; 527 } 528 529 void led_matrix_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom) { 530 if (!led_matrix_eeconfig.enable) { 531 return; 532 } 533 if (mode < 1) { 534 led_matrix_eeconfig.mode = 1; 535 } else if (mode >= LED_MATRIX_EFFECT_MAX) { 536 led_matrix_eeconfig.mode = LED_MATRIX_EFFECT_MAX - 1; 537 } else { 538 led_matrix_eeconfig.mode = mode; 539 } 540 led_task_state = STARTING; 541 eeconfig_flag_led_matrix(write_to_eeprom); 542 #ifdef LED_MATRIX_MODE_NAME_ENABLE 543 dprintf("led matrix mode [%s]: %u (%s)\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", (unsigned)led_matrix_eeconfig.mode, led_matrix_get_mode_name(led_matrix_eeconfig.mode)); 544 #else 545 dprintf("led matrix mode [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", (unsigned)led_matrix_eeconfig.mode); 546 #endif // LED_MATRIX_MODE_NAME_ENABLE 547 } 548 void led_matrix_mode_noeeprom(uint8_t mode) { 549 led_matrix_mode_eeprom_helper(mode, false); 550 } 551 void led_matrix_mode(uint8_t mode) { 552 led_matrix_mode_eeprom_helper(mode, true); 553 } 554 555 uint8_t led_matrix_get_mode(void) { 556 return led_matrix_eeconfig.mode; 557 } 558 559 void led_matrix_step_helper(bool write_to_eeprom) { 560 uint8_t mode = led_matrix_eeconfig.mode + 1; 561 led_matrix_mode_eeprom_helper((mode < LED_MATRIX_EFFECT_MAX) ? mode : 1, write_to_eeprom); 562 } 563 void led_matrix_step_noeeprom(void) { 564 led_matrix_step_helper(false); 565 } 566 void led_matrix_step(void) { 567 led_matrix_step_helper(true); 568 } 569 570 void led_matrix_step_reverse_helper(bool write_to_eeprom) { 571 uint8_t mode = led_matrix_eeconfig.mode - 1; 572 led_matrix_mode_eeprom_helper((mode < 1) ? LED_MATRIX_EFFECT_MAX - 1 : mode, write_to_eeprom); 573 } 574 void led_matrix_step_reverse_noeeprom(void) { 575 led_matrix_step_reverse_helper(false); 576 } 577 void led_matrix_step_reverse(void) { 578 led_matrix_step_reverse_helper(true); 579 } 580 581 void led_matrix_set_val_eeprom_helper(uint8_t val, bool write_to_eeprom) { 582 if (!led_matrix_eeconfig.enable) { 583 return; 584 } 585 led_matrix_eeconfig.val = (val > LED_MATRIX_MAXIMUM_BRIGHTNESS) ? LED_MATRIX_MAXIMUM_BRIGHTNESS : val; 586 eeconfig_flag_led_matrix(write_to_eeprom); 587 dprintf("led matrix set val [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.val); 588 } 589 void led_matrix_set_val_noeeprom(uint8_t val) { 590 led_matrix_set_val_eeprom_helper(val, false); 591 } 592 void led_matrix_set_val(uint8_t val) { 593 led_matrix_set_val_eeprom_helper(val, true); 594 } 595 596 uint8_t led_matrix_get_val(void) { 597 return led_matrix_eeconfig.val; 598 } 599 600 void led_matrix_increase_val_helper(bool write_to_eeprom) { 601 led_matrix_set_val_eeprom_helper(qadd8(led_matrix_eeconfig.val, LED_MATRIX_VAL_STEP), write_to_eeprom); 602 } 603 void led_matrix_increase_val_noeeprom(void) { 604 led_matrix_increase_val_helper(false); 605 } 606 void led_matrix_increase_val(void) { 607 led_matrix_increase_val_helper(true); 608 } 609 610 void led_matrix_decrease_val_helper(bool write_to_eeprom) { 611 led_matrix_set_val_eeprom_helper(qsub8(led_matrix_eeconfig.val, LED_MATRIX_VAL_STEP), write_to_eeprom); 612 } 613 void led_matrix_decrease_val_noeeprom(void) { 614 led_matrix_decrease_val_helper(false); 615 } 616 void led_matrix_decrease_val(void) { 617 led_matrix_decrease_val_helper(true); 618 } 619 620 void led_matrix_set_speed_eeprom_helper(uint8_t speed, bool write_to_eeprom) { 621 led_matrix_eeconfig.speed = speed; 622 eeconfig_flag_led_matrix(write_to_eeprom); 623 dprintf("led matrix set speed [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.speed); 624 } 625 void led_matrix_set_speed_noeeprom(uint8_t speed) { 626 led_matrix_set_speed_eeprom_helper(speed, false); 627 } 628 void led_matrix_set_speed(uint8_t speed) { 629 led_matrix_set_speed_eeprom_helper(speed, true); 630 } 631 632 uint8_t led_matrix_get_speed(void) { 633 return led_matrix_eeconfig.speed; 634 } 635 636 void led_matrix_increase_speed_helper(bool write_to_eeprom) { 637 led_matrix_set_speed_eeprom_helper(qadd8(led_matrix_eeconfig.speed, LED_MATRIX_SPD_STEP), write_to_eeprom); 638 } 639 void led_matrix_increase_speed_noeeprom(void) { 640 led_matrix_increase_speed_helper(false); 641 } 642 void led_matrix_increase_speed(void) { 643 led_matrix_increase_speed_helper(true); 644 } 645 646 void led_matrix_decrease_speed_helper(bool write_to_eeprom) { 647 led_matrix_set_speed_eeprom_helper(qsub8(led_matrix_eeconfig.speed, LED_MATRIX_SPD_STEP), write_to_eeprom); 648 } 649 void led_matrix_decrease_speed_noeeprom(void) { 650 led_matrix_decrease_speed_helper(false); 651 } 652 void led_matrix_decrease_speed(void) { 653 led_matrix_decrease_speed_helper(true); 654 } 655 656 void led_matrix_set_flags_eeprom_helper(led_flags_t flags, bool write_to_eeprom) { 657 led_matrix_eeconfig.flags = flags; 658 eeconfig_flag_led_matrix(write_to_eeprom); 659 dprintf("led matrix set flags [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.flags); 660 } 661 662 led_flags_t led_matrix_get_flags(void) { 663 return led_matrix_eeconfig.flags; 664 } 665 666 void led_matrix_set_flags(led_flags_t flags) { 667 led_matrix_set_flags_eeprom_helper(flags, true); 668 } 669 670 void led_matrix_set_flags_noeeprom(led_flags_t flags) { 671 led_matrix_set_flags_eeprom_helper(flags, false); 672 } 673 674 void led_matrix_flags_step_helper(bool write_to_eeprom) { 675 led_flags_t flags = led_matrix_get_flags(); 676 677 uint8_t next = 0; 678 for (uint8_t i = 0; i < LED_MATRIX_FLAG_STEPS_COUNT; i++) { 679 if (led_matrix_flag_steps[i] == flags) { 680 next = i == LED_MATRIX_FLAG_STEPS_COUNT - 1 ? 0 : i + 1; 681 break; 682 } 683 } 684 685 led_matrix_set_flags_eeprom_helper(led_matrix_flag_steps[next], write_to_eeprom); 686 } 687 688 void led_matrix_flags_step_noeeprom(void) { 689 led_matrix_flags_step_helper(false); 690 } 691 692 void led_matrix_flags_step(void) { 693 led_matrix_flags_step_helper(true); 694 } 695 696 void led_matrix_flags_step_reverse_helper(bool write_to_eeprom) { 697 led_flags_t flags = led_matrix_get_flags(); 698 699 uint8_t next = 0; 700 for (uint8_t i = 0; i < LED_MATRIX_FLAG_STEPS_COUNT; i++) { 701 if (led_matrix_flag_steps[i] == flags) { 702 next = i == 0 ? LED_MATRIX_FLAG_STEPS_COUNT - 1 : i - 1; 703 break; 704 } 705 } 706 707 led_matrix_set_flags_eeprom_helper(led_matrix_flag_steps[next], write_to_eeprom); 708 } 709 710 void led_matrix_flags_step_reverse_noeeprom(void) { 711 led_matrix_flags_step_reverse_helper(false); 712 } 713 714 void led_matrix_flags_step_reverse(void) { 715 led_matrix_flags_step_reverse_helper(true); 716 } 717 718 // LED Matrix naming 719 #undef LED_MATRIX_EFFECT 720 #ifdef LED_MATRIX_MODE_NAME_ENABLE 721 const char *led_matrix_get_mode_name(uint8_t mode) { 722 switch (mode) { 723 case LED_MATRIX_NONE: 724 return "NONE"; 725 726 # define LED_MATRIX_EFFECT(name, ...) \ 727 case LED_MATRIX_##name: \ 728 return #name; 729 # include "led_matrix_effects.inc" 730 # undef LED_MATRIX_EFFECT 731 732 # ifdef COMMUNITY_MODULES_ENABLE 733 # define LED_MATRIX_EFFECT(name, ...) \ 734 case LED_MATRIX_COMMUNITY_MODULE_##name: \ 735 return #name; 736 # include "led_matrix_community_modules.inc" 737 # undef LED_MATRIX_EFFECT 738 # endif // COMMUNITY_MODULES_ENABLE 739 740 # if defined(LED_MATRIX_CUSTOM_KB) || defined(LED_MATRIX_CUSTOM_USER) 741 # define LED_MATRIX_EFFECT(name, ...) \ 742 case LED_MATRIX_CUSTOM_##name: \ 743 return #name; 744 745 # ifdef LED_MATRIX_CUSTOM_KB 746 # include "led_matrix_kb.inc" 747 # endif // LED_MATRIX_CUSTOM_KB 748 749 # ifdef LED_MATRIX_CUSTOM_USER 750 # include "led_matrix_user.inc" 751 # endif // LED_MATRIX_CUSTOM_USER 752 753 # undef LED_MATRIX_EFFECT 754 # endif // LED_MATRIX_CUSTOM_KB || LED_MATRIX_CUSTOM_USER 755 756 default: 757 return "UNKNOWN"; 758 } 759 } 760 # undef LED_MATRIX_EFFECT 761 #endif // LED_MATRIX_MODE_NAME_ENABLE