aboutsummaryrefslogtreecommitdiff
path: root/quantum/led_matrix.c
diff options
context:
space:
mode:
authorJames Young <18669334+noroadsleft@users.noreply.github.com>2021-05-29 14:38:50 -0700
committerGitHub <noreply@github.com>2021-05-29 14:38:50 -0700
commit1646c0f26cfa21a7023d404008e4d0aa4917193d (patch)
tree337ab0498a929285a234518fee34a4d9dcf51656 /quantum/led_matrix.c
parentf55e39e8a2246f6f96fd5d4a84a866e2615cde7b (diff)
downloadqmk_firmware-1646c0f26cfa21a7023d404008e4d0aa4917193d.tar.gz
qmk_firmware-1646c0f26cfa21a7023d404008e4d0aa4917193d.zip
2021 May 29 Breaking Changes Update (#13034)
* Add Per Key functionality for AutoShift (#11536) * LED Matrix: Reactive effect buffers & advanced indicators (#12588) * [Keyboard] kint36: switch to sym_eager_pk debouncing (#12626) * [Keyboard] kint2pp: reduce input latency by ≈10ms (#12625) * LED Matrix: Split (#12633) * [CI] Format code according to conventions (#12650) * feat: infinite timeout for leader key (#6580) * feat: implement leader_no_timeout logic * docs(leader_key): infinite leader timeout docs * Format code according to conventions (#12680) * Update ADC driver for STM32F1xx, STM32F3xx, STM32F4xx (#12403) * Fix default ADC_RESOLUTION for ADCv3 (and ADCv4) Recent ChibiOS update removed ADC_CFGR1_RES_10BIT from the ADCv3 headers (that macro should not have been there, because ADCv3 has CFGR instead of CFGR1). Fix the default value for ADC_RESOLUTION to use ADC_CFGR_RES_10BITS if it is defined (that name is used for ADCv3 and ADCv4). * Update ADC docs to match the actually used resolution ADC driver for ChibiOS actually uses the 10-bit resolution by default (probably to match AVR); fix the documentation accordingly. Also add both ADC_CFGR_RES_10BITS and ADC_CFGR1_RES_10BIT constants (these names differ according to the ADC implementation in the particular MCU). * Fix pinToMux() for B12 and B13 on STM32F3xx Testing on STM32F303CCT6 revealed that the ADC mux values for B12 and B13 pins were wrong. * Add support for all possible analog pins on STM32F1xx Added ADC mux values for pins A0...A7, B0, B1, C0...C5 on STM32F1xx (they are the same at least for STM32F103x8 and larger F103 devices, and also F102, F105, F107 families). Actually tested on STM32F103C8T6 (therefore pins C0...C5 were not tested). Pins F6...F10, which are present on STM32F103x[C-G] in 144-pin packages, cannot be supported at the moment, because those pins are connected only to ADC3, but the ChibiOS ADC driver for STM32F1xx supports only ADC1. * Add support for all possible analog pins on STM32F4xx Added ADC mux values for pins A0...A7, B0, B1, C0...C5 and optionally F3...F10 (if STM32_ADC_USE_ADC3 is enabled). These mux values are apparently the same for all F4xx devices, except some smaller devices may not have ADC3. Actually tested on STM32F401CCU6, STM32F401CEU6, STM32F411CEU6 (using various WeAct “Blackpill” boards); only pins A0...A7, B0, B1 were tested. Pins F3...F10 are inside `#if STM32_ADC_USE_ADC3` because some devices which don't have ADC3 also don't have the GPIOF port, therefore the code which refers to Fx pins does not compile. * Fix STM32F3xx ADC mux table in documentation The ADC driver documentation had some errors in the mux table for STM32F3xx. Fix this table to match the datasheet and the actual code (mux settings for B12 and B13 were also tested on a real STM32F303CCT6 chip). * Add STM32F1xx ADC pins to the documentation * Add STM32F4xx ADC pins to the documentation * Add initial support for tinyuf2 bootloader (when hosted on F411 blackpill) (#12600) * Add support for jumping to tinyuf2 bootloader. Adds blackpill UF2 example. * Update flashing.md * Update chconf.h * Update config.h * Update halconf.h * Update mcuconf.h * eeprom driver: Refactor where eeprom driver initialisation (and EEPROM emulation initialisation) occurs to make it non-target-specific. (#12671) * Add support for MCU = STM32F446 (#12619) * Add support for MCU = STM32F446 * Update platforms/chibios/GENERIC_STM32_F446XE/configs/config.h * Restore mcuconf.h to the one used by RT-STM32F446RE-NUCLEO64 * stm32f446: update mcuconf.h and board.h for 16MHz operation, with USB enabled, and other peripherals disabled. * Format code according to conventions (#12682) * Format code according to conventions (#12687) * Add STM32L433 and L443 support (#12063) * initial L433 commit * change to XC * fix L433 * disable all peripherals * update system and peripheral clocks * 433 change * use its own board files * revert its own board files * l433 specific change * fix stm32l432xx define * remove duplicate #define * fix bootloader jump * move to L443xx and add i2c2, spi2, usart3 to mcuconf.h * move to L443 * move to L443 * fix sdmmc in mcuconf.h * include STM32L443 * add L443 * Include L443 in compatible microcontrollers * Include L443 in compatible microcontrollers * Update config bootloader jump description * Update ChibiOS define reasoning * Update quantum/mcu_selection.mk * fix git conflict * Updated Function96 with V2 files and removed chconf.h and halconf.h (#12613) * Fix bad PR merge for #6580. (#12721) * Change RGB/LED Matrix to use a simple define for USB suspend (#12697) * [CI] Format code according to conventions (#12731) * Fixing transport's led/rgb matrix suspend state logic (#12770) * [CI] Format code according to conventions (#12772) * Fix comment parsing (#12750) * Added OLED fade out support (#12086) * fix some references to bin/qmk that slipped in (#12832) * Resolve a number of warnings in `qmk generate-api` (#12833) * New command: qmk console (#12828) * stash poc * stash * tidy up implementation * Tidy up slightly for review * Tidy up slightly for review * Bodge environment to make tests pass * Refactor away from asyncio due to windows issues * Filter devices * align vid/pid printing * Add hidapi to the installers * start preparing for multiple hid_listeners * udev rules for hid_listen * refactor to move closer to end state * very basic implementation of the threaded model * refactor how vid/pid/index are supplied and parsed * windows improvements * read the report directly when usage page isn't available * add per-device colors, the choice to show names or numbers, and refactor * add timestamps * Add support for showing bootloaders * tweak the color for bootloaders * Align bootloader disconnect with connect color * add support for showing all bootloaders * fix the pyusb check * tweaks * fix exception * hide a stack trace behind -v * add --no-bootloaders option * add documentation for qmk console * Apply suggestions from code review * pyformat * clean up and flesh out KNOWN_BOOTLOADERS * Remove pointless SERIAL_LINK_ENABLE rules (#12846) * Make Swap Hands use PROGMEM (#12284) This converts the array that the Swap Hands feature uses to use PROGMEM, and to read from that array, as such. Since this array never changes at runtime, there is no reason to keep it in memory. Especially for AVR boards, as memory is a precious resource. * Fix another bin/qmk reference (#12856) * [Keymap] Turn OLED off on suspend in soundmonster keymap (#10419) * Fixup build errors on `develop` branch. (#12723) * LED Matrix: Effects! (#12651) * Fix syntax error when compiling for ARM (#12866) * Remove KEYMAP and LAYOUT_kc (#12160) * alias KEYMAP to LAYOUT * remove KEYMAP and LAYOUT_kc * Add setup, clone, and env to the list of commands we allow even with broken modules (#12868) * Rename `point_t` -> `led_point_t` (#12864) * [Keyboard] updated a vendor name / fixed minor keymap issues (#12881) * Add missing LED Matrix suspend code to suspend.c (#12878) * LED Matrix: Documentation (#12685) * Deprecate `send_unicode_hex_string()` (#12602) * Fix spelling mistake regarding LED Matrix in split_common. (#12888) * [Keymap] Fix QWERTY/DVORAK status output for kzar keymap (#12895) * Use milc.subcommand.config instead of qmk.cli.config (#12915) * Use milc.subcommand.config instead * pyformat * remove the config test * Add function to allow repeated blinking of one layer (#12237) * Implement function rgblight_blink_layer_repeat to allow repeated blinking of one layer at a time * Update doc * Rework rgblight blinking according to requested change * optimize storage * Fixup housekeeping from being invoked twice per loop. (#12933) * matrix: wait for row signal to go HIGH for every row (#12945) I noticed this discrepancy (last row of the matrix treated differently than the others) when optimizing the input latency of my keyboard controller, see also https://michael.stapelberg.ch/posts/2021-05-08-keyboard-input-latency-qmk-kinesis/ Before this commit, when tuning the delays I noticed ghost key presses when pressing the F2 key, which is on the last row of the keyboard matrix: the dead_grave key, which is on the first row of the keyboard matrix, would be incorrectly detected as pressed. After this commit, all keyboard matrix rows are interpreted correctly. I suspect that my setup is more susceptible to this nuance than others because I use GPIO_INPUT_PIN_DELAY=0 and hence don’t have another delay that might mask the problem. * ensure we do not conflict with existing keymap aliases (#12976) * Add support for up to 4 IS31FL3733 drivers (#12342) * Convert Encoder callbacks to be boolean functions (#12805) * [Keyboard] Fix Terrazzo build failure (#12977) * Do not hard set config in CPTC files (#11864) * [Keyboard] Corne - Remove legacy revision support (#12226) * [Keymap] Update to Drashna keymap and user code (based on develop) (#12936) * Add Full-duplex serial driver for ARM boards (#9842) * Document LED_MATRIX_FRAMEBUFFER_EFFECTS (#12987) * Backlight: add defines for default level and breathing state (#12560) * Add dire message about LUFA mass storage bootloader (#13014) * [Keyboard] Remove redundant legacy and common headers for crkbd (#13023) Was causing compiler errors on some systems. * Fix keyboards/keymaps for boolean encoder callback changes (#12985) * `backlight.c`: include `eeprom.h` (#13024) * Add changelog for 2021-05-29 Breaking Changes merge (#12939) * Add ChangeLog for 2021-05-29 Breaking Changes Merge: initial version * Add recent develop changes * Sort recent develop changes * Remove sections for ChibiOS changes per tzarc No ChibiOS changes this round. * Add and sort recent develop changes * add notes about keyboard moves/deletions * import changelog for PR 12172 Documents the change to BOOTMAGIC_ENABLE. * update section headings * re-sort changelog * add additional note regarding Bootmagic changes * remove changelog timestamp * update dates in main Breaking Changes docs * fix broken section anchors in previous changelogs * add link to backlight/eeprom patch to changelog * highlight some more changes * link PRs from section headers * Restore standard readme * run: qmk cformat --core-only
Diffstat (limited to 'quantum/led_matrix.c')
-rw-r--r--quantum/led_matrix.c615
1 files changed, 425 insertions, 190 deletions
diff --git a/quantum/led_matrix.c b/quantum/led_matrix.c
index 4f1f06c7a..d612fbfa9 100644
--- a/quantum/led_matrix.c
+++ b/quantum/led_matrix.c
@@ -17,79 +17,143 @@
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */ 18 */
19 19
20#include <stdint.h>
21#include <stdbool.h>
22#include "quantum.h"
23#include "led_matrix.h" 20#include "led_matrix.h"
24#include "progmem.h" 21#include "progmem.h"
25#include "config.h" 22#include "config.h"
26#include "eeprom.h" 23#include "eeprom.h"
27#include <string.h> 24#include <string.h>
28#include <math.h> 25#include <math.h>
26#include "led_tables.h"
29 27
30led_eeconfig_t led_matrix_eeconfig; 28#include <lib/lib8tion/lib8tion.h>
31 29
32#ifndef MAX 30#ifndef LED_MATRIX_CENTER
33# define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) 31const led_point_t k_led_matrix_center = {112, 32};
32#else
33const led_point_t k_led_matrix_center = LED_MATRIX_CENTER;
34#endif 34#endif
35 35
36#ifndef MIN 36// Generic effect runners
37# define MIN(a, b) ((a) < (b) ? (a) : (b)) 37#include "led_matrix_runners/effect_runner_dx_dy_dist.h"
38#include "led_matrix_runners/effect_runner_dx_dy.h"
39#include "led_matrix_runners/effect_runner_i.h"
40#include "led_matrix_runners/effect_runner_sin_cos_i.h"
41#include "led_matrix_runners/effect_runner_reactive.h"
42#include "led_matrix_runners/effect_runner_reactive_splash.h"
43
44// ------------------------------------------
45// -----Begin led effect includes macros-----
46#define LED_MATRIX_EFFECT(name)
47#define LED_MATRIX_CUSTOM_EFFECT_IMPLS
48
49#include "led_matrix_animations/led_matrix_effects.inc"
50#ifdef LED_MATRIX_CUSTOM_KB
51# include "led_matrix_kb.inc"
38#endif 52#endif
53#ifdef LED_MATRIX_CUSTOM_USER
54# include "led_matrix_user.inc"
55#endif
56
57#undef LED_MATRIX_CUSTOM_EFFECT_IMPLS
58#undef LED_MATRIX_EFFECT
59// -----End led effect includes macros-------
60// ------------------------------------------
39 61
40#ifndef LED_DISABLE_AFTER_TIMEOUT 62#if defined(LED_DISABLE_AFTER_TIMEOUT) && !defined(LED_DISABLE_TIMEOUT)
41# define LED_DISABLE_AFTER_TIMEOUT 0 63# define LED_DISABLE_TIMEOUT (LED_DISABLE_AFTER_TIMEOUT * 1200UL)
42#endif 64#endif
43 65
44#ifndef LED_DISABLE_WHEN_USB_SUSPENDED 66#ifndef LED_DISABLE_TIMEOUT
45# define LED_DISABLE_WHEN_USB_SUSPENDED false 67# define LED_DISABLE_TIMEOUT 0
46#endif 68#endif
47 69
48#ifndef EECONFIG_LED_MATRIX 70#if LED_DISABLE_WHEN_USB_SUSPENDED == false
49# define EECONFIG_LED_MATRIX EECONFIG_RGBLIGHT 71# undef LED_DISABLE_WHEN_USB_SUSPENDED
50#endif 72#endif
51 73
52#if !defined(LED_MATRIX_MAXIMUM_BRIGHTNESS) || LED_MATRIX_MAXIMUM_BRIGHTNESS > 255 74#if !defined(LED_MATRIX_MAXIMUM_BRIGHTNESS) || LED_MATRIX_MAXIMUM_BRIGHTNESS > UINT8_MAX
53# define LED_MATRIX_MAXIMUM_BRIGHTNESS 255 75# undef LED_MATRIX_MAXIMUM_BRIGHTNESS
76# define LED_MATRIX_MAXIMUM_BRIGHTNESS UINT8_MAX
54#endif 77#endif
55 78
56bool g_suspend_state = false; 79#if !defined(LED_MATRIX_VAL_STEP)
80# define LED_MATRIX_VAL_STEP 8
81#endif
57 82
58// Global tick at 20 Hz 83#if !defined(LED_MATRIX_SPD_STEP)
59uint32_t g_tick = 0; 84# define LED_MATRIX_SPD_STEP 16
85#endif
60 86
61// Ticks since this key was last hit. 87#if !defined(LED_MATRIX_STARTUP_MODE)
62uint8_t g_key_hit[DRIVER_LED_TOTAL]; 88# define LED_MATRIX_STARTUP_MODE LED_MATRIX_SOLID
89#endif
63 90
64// Ticks since any key was last hit. 91#if !defined(LED_MATRIX_STARTUP_VAL)
65uint32_t g_any_key_hit = 0; 92# define LED_MATRIX_STARTUP_VAL LED_MATRIX_MAXIMUM_BRIGHTNESS
93#endif
66 94
67uint32_t eeconfig_read_led_matrix(void) { return eeprom_read_dword(EECONFIG_LED_MATRIX); } 95#if !defined(LED_MATRIX_STARTUP_SPD)
96# define LED_MATRIX_STARTUP_SPD UINT8_MAX / 2
97#endif
68 98
69void eeconfig_update_led_matrix(uint32_t config_value) { eeprom_update_dword(EECONFIG_LED_MATRIX, config_value); } 99// globals
100led_eeconfig_t led_matrix_eeconfig; // TODO: would like to prefix this with g_ for global consistancy, do this in another pr
101uint32_t g_led_timer;
102#ifdef LED_MATRIX_FRAMEBUFFER_EFFECTS
103uint8_t g_led_frame_buffer[MATRIX_ROWS][MATRIX_COLS] = {{0}};
104#endif // LED_MATRIX_FRAMEBUFFER_EFFECTS
105#ifdef LED_MATRIX_KEYREACTIVE_ENABLED
106last_hit_t g_last_hit_tracker;
107#endif // LED_MATRIX_KEYREACTIVE_ENABLED
108
109// internals
110static bool suspend_state = false;
111static uint8_t led_last_enable = UINT8_MAX;
112static uint8_t led_last_effect = UINT8_MAX;
113static effect_params_t led_effect_params = {0, LED_FLAG_ALL, false};
114static led_task_states led_task_state = SYNCING;
115#if LED_DISABLE_TIMEOUT > 0
116static uint32_t led_anykey_timer;
117#endif // LED_DISABLE_TIMEOUT > 0
118
119// double buffers
120static uint32_t led_timer_buffer;
121#ifdef LED_MATRIX_KEYREACTIVE_ENABLED
122static last_hit_t last_hit_buffer;
123#endif // LED_MATRIX_KEYREACTIVE_ENABLED
124
125// split led matrix
126#if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
127const uint8_t k_led_matrix_split[2] = LED_MATRIX_SPLIT;
128#endif
129
130void eeconfig_read_led_matrix(void) { eeprom_read_block(&led_matrix_eeconfig, EECONFIG_LED_MATRIX, sizeof(led_matrix_eeconfig)); }
131
132void eeconfig_update_led_matrix(void) { eeprom_update_block(&led_matrix_eeconfig, EECONFIG_LED_MATRIX, sizeof(led_matrix_eeconfig)); }
70 133
71void eeconfig_update_led_matrix_default(void) { 134void eeconfig_update_led_matrix_default(void) {
72 dprintf("eeconfig_update_led_matrix_default\n"); 135 dprintf("eeconfig_update_led_matrix_default\n");
73 led_matrix_eeconfig.enable = 1; 136 led_matrix_eeconfig.enable = 1;
74 led_matrix_eeconfig.mode = LED_MATRIX_UNIFORM_BRIGHTNESS; 137 led_matrix_eeconfig.mode = LED_MATRIX_STARTUP_MODE;
75 led_matrix_eeconfig.val = 128; 138 led_matrix_eeconfig.val = LED_MATRIX_STARTUP_VAL;
76 led_matrix_eeconfig.speed = 0; 139 led_matrix_eeconfig.speed = LED_MATRIX_STARTUP_SPD;
77 eeconfig_update_led_matrix(led_matrix_eeconfig.raw); 140 led_matrix_eeconfig.flags = LED_FLAG_ALL;
141 eeconfig_update_led_matrix();
78} 142}
79 143
80void eeconfig_debug_led_matrix(void) { 144void eeconfig_debug_led_matrix(void) {
81 dprintf("led_matrix_eeconfig eeprom\n"); 145 dprintf("led_matrix_eeconfig EEPROM\n");
82 dprintf("led_matrix_eeconfig.enable = %d\n", led_matrix_eeconfig.enable); 146 dprintf("led_matrix_eeconfig.enable = %d\n", led_matrix_eeconfig.enable);
83 dprintf("led_matrix_eeconfig.mode = %d\n", led_matrix_eeconfig.mode); 147 dprintf("led_matrix_eeconfig.mode = %d\n", led_matrix_eeconfig.mode);
84 dprintf("led_matrix_eeconfig.val = %d\n", led_matrix_eeconfig.val); 148 dprintf("led_matrix_eeconfig.val = %d\n", led_matrix_eeconfig.val);
85 dprintf("led_matrix_eeconfig.speed = %d\n", led_matrix_eeconfig.speed); 149 dprintf("led_matrix_eeconfig.speed = %d\n", led_matrix_eeconfig.speed);
150 dprintf("led_matrix_eeconfig.flags = %d\n", led_matrix_eeconfig.flags);
86} 151}
87 152
88uint8_t g_last_led_hit[LED_HITS_TO_REMEMBER] = {255}; 153__attribute__((weak)) uint8_t led_matrix_map_row_column_to_led_kb(uint8_t row, uint8_t column, uint8_t *led_i) { return 0; }
89uint8_t g_last_led_count = 0;
90 154
91uint8_t map_row_column_to_led(uint8_t row, uint8_t column, uint8_t *led_i) { 155uint8_t led_matrix_map_row_column_to_led(uint8_t row, uint8_t column, uint8_t *led_i) {
92 uint8_t led_count = 0; 156 uint8_t led_count = led_matrix_map_row_column_to_led_kb(row, column, led_i);
93 uint8_t led_index = g_led_config.matrix_co[row][column]; 157 uint8_t led_index = g_led_config.matrix_co[row][column];
94 if (led_index != NO_LED) { 158 if (led_index != NO_LED) {
95 led_i[led_count] = led_index; 159 led_i[led_count] = led_index;
@@ -100,88 +164,235 @@ uint8_t map_row_column_to_led(uint8_t row, uint8_t column, uint8_t *led_i) {
100 164
101void led_matrix_update_pwm_buffers(void) { led_matrix_driver.flush(); } 165void led_matrix_update_pwm_buffers(void) { led_matrix_driver.flush(); }
102 166
103void led_matrix_set_index_value(int index, uint8_t value) { led_matrix_driver.set_value(index, value); } 167void led_matrix_set_value(int index, uint8_t value) {
104 168#if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
105void led_matrix_set_index_value_all(uint8_t value) { led_matrix_driver.set_value_all(value); } 169 if (!is_keyboard_left() && index >= k_led_matrix_split[0])
106 170# ifdef USE_CIE1931_CURVE
107bool process_led_matrix(uint16_t keycode, keyrecord_t *record) { 171 led_matrix_driver.set_value(index - k_led_matrix_split[0], pgm_read_byte(&CIE1931_CURVE[value]));
108 if (record->event.pressed) { 172# else
109 uint8_t led[8]; 173 led_matrix_driver.set_value(index - k_led_matrix_split[0], value);
110 uint8_t led_count = map_row_column_to_led(record->event.key.row, record->event.key.col, led); 174# endif
111 if (led_count > 0) { 175 else if (is_keyboard_left() && index < k_led_matrix_split[0])
112 for (uint8_t i = LED_HITS_TO_REMEMBER; i > 1; i--) { 176#endif
113 g_last_led_hit[i - 1] = g_last_led_hit[i - 2]; 177#ifdef USE_CIE1931_CURVE
114 } 178 led_matrix_driver.set_value(index, pgm_read_byte(&CIE1931_CURVE[value]));
115 g_last_led_hit[0] = led[0]; 179#else
116 g_last_led_count = MIN(LED_HITS_TO_REMEMBER, g_last_led_count + 1); 180 led_matrix_driver.set_value(index, value);
117 } 181#endif
118 for (uint8_t i = 0; i < led_count; i++) g_key_hit[led[i]] = 0; 182}
119 g_any_key_hit = 0;
120 } else {
121#ifdef LED_MATRIX_KEYRELEASES
122 uint8_t led[8];
123 uint8_t led_count = map_row_column_to_led(record->event.key.row, record->event.key.col, led);
124 for (uint8_t i = 0; i < led_count; i++) g_key_hit[led[i]] = 255;
125 183
126 g_any_key_hit = 255; 184void led_matrix_set_value_all(uint8_t value) {
185#if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
186 for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) led_matrix_set_value(i, value);
187#else
188# ifdef USE_CIE1931_CURVE
189 led_matrix_driver.set_value_all(pgm_read_byte(&CIE1931_CURVE[value]));
190# else
191 led_matrix_driver.set_value_all(value);
192# endif
127#endif 193#endif
128 }
129 return true;
130} 194}
131 195
132void led_matrix_set_suspend_state(bool state) { g_suspend_state = state; } 196void process_led_matrix(uint8_t row, uint8_t col, bool pressed) {
197#ifndef LED_MATRIX_SPLIT
198 if (!is_keyboard_master()) return;
199#endif
200#if LED_DISABLE_TIMEOUT > 0
201 led_anykey_timer = 0;
202#endif // LED_DISABLE_TIMEOUT > 0
133 203
134// All LEDs off 204#ifdef LED_MATRIX_KEYREACTIVE_ENABLED
135void led_matrix_all_off(void) { led_matrix_set_index_value_all(0); } 205 uint8_t led[LED_HITS_TO_REMEMBER];
206 uint8_t led_count = 0;
136 207
137// Uniform brightness 208# if defined(LED_MATRIX_KEYRELEASES)
138void led_matrix_uniform_brightness(void) { led_matrix_set_index_value_all(LED_MATRIX_MAXIMUM_BRIGHTNESS / BACKLIGHT_LEVELS * led_matrix_eeconfig.val); } 209 if (!pressed)
210# elif defined(LED_MATRIX_KEYPRESSES)
211 if (pressed)
212# endif // defined(LED_MATRIX_KEYRELEASES)
213 {
214 led_count = led_matrix_map_row_column_to_led(row, col, led);
215 }
139 216
140void led_matrix_custom(void) {} 217 if (last_hit_buffer.count + led_count > LED_HITS_TO_REMEMBER) {
218 memcpy(&last_hit_buffer.x[0], &last_hit_buffer.x[led_count], LED_HITS_TO_REMEMBER - led_count);
219 memcpy(&last_hit_buffer.y[0], &last_hit_buffer.y[led_count], LED_HITS_TO_REMEMBER - led_count);
220 memcpy(&last_hit_buffer.tick[0], &last_hit_buffer.tick[led_count], (LED_HITS_TO_REMEMBER - led_count) * 2); // 16 bit
221 memcpy(&last_hit_buffer.index[0], &last_hit_buffer.index[led_count], LED_HITS_TO_REMEMBER - led_count);
222 last_hit_buffer.count--;
223 }
141 224
142void led_matrix_task(void) { 225 for (uint8_t i = 0; i < led_count; i++) {
143 if (!led_matrix_eeconfig.enable) { 226 uint8_t index = last_hit_buffer.count;
144 led_matrix_all_off(); 227 last_hit_buffer.x[index] = g_led_config.point[led[i]].x;
145 led_matrix_indicators(); 228 last_hit_buffer.y[index] = g_led_config.point[led[i]].y;
146 return; 229 last_hit_buffer.index[index] = led[i];
230 last_hit_buffer.tick[index] = 0;
231 last_hit_buffer.count++;
147 } 232 }
233#endif // LED_MATRIX_KEYREACTIVE_ENABLED
148 234
149 g_tick++; 235#if defined(LED_MATRIX_FRAMEBUFFER_EFFECTS) && !defined(DISABLE_LED_MATRIX_TYPING_HEATMAP)
236 if (led_matrix_eeconfig.mode == LED_MATRIX_TYPING_HEATMAP) {
237 process_led_matrix_typing_heatmap(row, col);
238 }
239#endif // defined(LED_MATRIX_FRAMEBUFFER_EFFECTS) && !defined(DISABLE_LED_MATRIX_TYPING_HEATMAP)
240}
150 241
151 if (g_any_key_hit < 0xFFFFFFFF) { 242static bool led_matrix_none(effect_params_t *params) {
152 g_any_key_hit++; 243 if (!params->init) {
244 return false;
153 } 245 }
154 246
155 for (int led = 0; led < DRIVER_LED_TOTAL; led++) { 247 led_matrix_set_value_all(0);
156 if (g_key_hit[led] < 255) { 248 return false;
157 if (g_key_hit[led] == 254) g_last_led_count = MAX(g_last_led_count - 1, 0); 249}
158 g_key_hit[led]++; 250
251static void led_task_timers(void) {
252#if defined(LED_MATRIX_KEYREACTIVE_ENABLED) || LED_DISABLE_TIMEOUT > 0
253 uint32_t deltaTime = sync_timer_elapsed32(led_timer_buffer);
254#endif // defined(LED_MATRIX_KEYREACTIVE_ENABLED) || LED_DISABLE_TIMEOUT > 0
255 led_timer_buffer = sync_timer_read32();
256
257 // Update double buffer timers
258#if LED_DISABLE_TIMEOUT > 0
259 if (led_anykey_timer < UINT32_MAX) {
260 if (UINT32_MAX - deltaTime < led_anykey_timer) {
261 led_anykey_timer = UINT32_MAX;
262 } else {
263 led_anykey_timer += deltaTime;
159 } 264 }
160 } 265 }
266#endif // LED_DISABLE_TIMEOUT > 0
267
268 // Update double buffer last hit timers
269#ifdef LED_MATRIX_KEYREACTIVE_ENABLED
270 uint8_t count = last_hit_buffer.count;
271 for (uint8_t i = 0; i < count; ++i) {
272 if (UINT16_MAX - deltaTime < last_hit_buffer.tick[i]) {
273 last_hit_buffer.count--;
274 continue;
275 }
276 last_hit_buffer.tick[i] += deltaTime;
277 }
278#endif // LED_MATRIX_KEYREACTIVE_ENABLED
279}
161 280
162 // Ideally we would also stop sending zeros to the LED driver PWM buffers 281static void led_task_sync(void) {
163 // while suspended and just do a software shutdown. This is a cheap hack for now. 282 // next task
164 bool suspend_backlight = ((g_suspend_state && LED_DISABLE_WHEN_USB_SUSPENDED) || (LED_DISABLE_AFTER_TIMEOUT > 0 && g_any_key_hit > LED_DISABLE_AFTER_TIMEOUT * 60 * 20)); 283 if (sync_timer_elapsed32(g_led_timer) >= LED_MATRIX_LED_FLUSH_LIMIT) led_task_state = STARTING;
165 uint8_t effect = suspend_backlight ? 0 : led_matrix_eeconfig.mode; 284}
285
286static void led_task_start(void) {
287 // reset iter
288 led_effect_params.iter = 0;
289
290 // update double buffers
291 g_led_timer = led_timer_buffer;
292#ifdef LED_MATRIX_KEYREACTIVE_ENABLED
293 g_last_hit_tracker = last_hit_buffer;
294#endif // LED_MATRIX_KEYREACTIVE_ENABLED
295
296 // next task
297 led_task_state = RENDERING;
298}
299
300static void led_task_render(uint8_t effect) {
301 bool rendering = false;
302 led_effect_params.init = (effect != led_last_effect) || (led_matrix_eeconfig.enable != led_last_enable);
303 if (led_effect_params.flags != led_matrix_eeconfig.flags) {
304 led_effect_params.flags = led_matrix_eeconfig.flags;
305 led_matrix_set_value_all(0);
306 }
166 307
167 // this gets ticked at 20 Hz.
168 // each effect can opt to do calculations 308 // each effect can opt to do calculations
169 // and/or request PWM buffer updates. 309 // and/or request PWM buffer updates.
170 switch (effect) { 310 switch (effect) {
171 case LED_MATRIX_UNIFORM_BRIGHTNESS: 311 case LED_MATRIX_NONE:
172 led_matrix_uniform_brightness(); 312 rendering = led_matrix_none(&led_effect_params);
173 break; 313 break;
174 default: 314
175 led_matrix_custom(); 315// ---------------------------------------------
316// -----Begin led effect switch case macros-----
317#define LED_MATRIX_EFFECT(name, ...) \
318 case LED_MATRIX_##name: \
319 rendering = name(&led_effect_params); \
320 break;
321#include "led_matrix_animations/led_matrix_effects.inc"
322#undef LED_MATRIX_EFFECT
323
324#if defined(LED_MATRIX_CUSTOM_KB) || defined(LED_MATRIX_CUSTOM_USER)
325# define LED_MATRIX_EFFECT(name, ...) \
326 case LED_MATRIX_CUSTOM_##name: \
327 rendering = name(&led_effect_params); \
176 break; 328 break;
329# ifdef LED_MATRIX_CUSTOM_KB
330# include "led_matrix_kb.inc"
331# endif
332# ifdef LED_MATRIX_CUSTOM_USER
333# include "led_matrix_user.inc"
334# endif
335# undef LED_MATRIX_EFFECT
336#endif
337 // -----End led effect switch case macros-------
338 // ---------------------------------------------
177 } 339 }
178 340
179 if (!suspend_backlight) { 341 led_effect_params.iter++;
180 led_matrix_indicators(); 342
343 // next task
344 if (!rendering) {
345 led_task_state = FLUSHING;
346 if (!led_effect_params.init && effect == LED_MATRIX_NONE) {
347 // We only need to flush once if we are LED_MATRIX_NONE
348 led_task_state = SYNCING;
349 }
181 } 350 }
351}
352
353static void led_task_flush(uint8_t effect) {
354 // update last trackers after the first full render so we can init over several frames
355 led_last_effect = effect;
356 led_last_enable = led_matrix_eeconfig.enable;
357
358 // update pwm buffers
359 led_matrix_update_pwm_buffers();
182 360
183 // Tell the LED driver to update its state 361 // next task
184 led_matrix_driver.flush(); 362 led_task_state = SYNCING;
363}
364
365void led_matrix_task(void) {
366 led_task_timers();
367
368 // Ideally we would also stop sending zeros to the LED driver PWM buffers
369 // while suspended and just do a software shutdown. This is a cheap hack for now.
370 bool suspend_backlight = suspend_state ||
371#if LED_DISABLE_TIMEOUT > 0
372 (led_anykey_timer > (uint32_t)LED_DISABLE_TIMEOUT) ||
373#endif // LED_DISABLE_TIMEOUT > 0
374 false;
375
376 uint8_t effect = suspend_backlight || !led_matrix_eeconfig.enable ? 0 : led_matrix_eeconfig.mode;
377
378 switch (led_task_state) {
379 case STARTING:
380 led_task_start();
381 break;
382 case RENDERING:
383 led_task_render(effect);
384 if (effect) {
385 led_matrix_indicators();
386 led_matrix_indicators_advanced(&led_effect_params);
387 }
388 break;
389 case FLUSHING:
390 led_task_flush(effect);
391 break;
392 case SYNCING:
393 led_task_sync();
394 break;
395 }
185} 396}
186 397
187void led_matrix_indicators(void) { 398void led_matrix_indicators(void) {
@@ -193,33 +404,42 @@ __attribute__((weak)) void led_matrix_indicators_kb(void) {}
193 404
194__attribute__((weak)) void led_matrix_indicators_user(void) {} 405__attribute__((weak)) void led_matrix_indicators_user(void) {}
195 406
196// void led_matrix_set_indicator_index(uint8_t *index, uint8_t row, uint8_t column) 407void led_matrix_indicators_advanced(effect_params_t *params) {
197// { 408 /* special handling is needed for "params->iter", since it's already been incremented.
198// if (row >= MATRIX_ROWS) 409 * Could move the invocations to led_task_render, but then it's missing a few checks
199// { 410 * and not sure which would be better. Otherwise, this should be called from
200// // Special value, 255=none, 254=all 411 * led_task_render, right before the iter++ line.
201// *index = row; 412 */
202// } 413#if defined(LED_MATRIX_LED_PROCESS_LIMIT) && LED_MATRIX_LED_PROCESS_LIMIT > 0 && LED_MATRIX_LED_PROCESS_LIMIT < DRIVER_LED_TOTAL
203// else 414 uint8_t min = LED_MATRIX_LED_PROCESS_LIMIT * (params->iter - 1);
204// { 415 uint8_t max = min + LED_MATRIX_LED_PROCESS_LIMIT;
205// // This needs updated to something like 416 if (max > DRIVER_LED_TOTAL) max = DRIVER_LED_TOTAL;
206// // uint8_t led[8]; 417#else
207// // uint8_t led_count = map_row_column_to_led(row, column, led); 418 uint8_t min = 0;
208// // for(uint8_t i = 0; i < led_count; i++) 419 uint8_t max = DRIVER_LED_TOTAL;
209// map_row_column_to_led(row, column, index); 420#endif
210// } 421 led_matrix_indicators_advanced_kb(min, max);
211// } 422 led_matrix_indicators_advanced_user(min, max);
423}
424
425__attribute__((weak)) void led_matrix_indicators_advanced_kb(uint8_t led_min, uint8_t led_max) {}
426
427__attribute__((weak)) void led_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {}
212 428
213void led_matrix_init(void) { 429void led_matrix_init(void) {
214 led_matrix_driver.init(); 430 led_matrix_driver.init();
215 431
216 // Wait half a second for the driver to finish initializing 432#ifdef LED_MATRIX_KEYREACTIVE_ENABLED
217 wait_ms(500); 433 g_last_hit_tracker.count = 0;
434 for (uint8_t i = 0; i < LED_HITS_TO_REMEMBER; ++i) {
435 g_last_hit_tracker.tick[i] = UINT16_MAX;
436 }
218 437
219 // clear the key hits 438 last_hit_buffer.count = 0;
220 for (int led = 0; led < DRIVER_LED_TOTAL; led++) { 439 for (uint8_t i = 0; i < LED_HITS_TO_REMEMBER; ++i) {
221 g_key_hit[led] = 255; 440 last_hit_buffer.tick[i] = UINT16_MAX;
222 } 441 }
442#endif // LED_MATRIX_KEYREACTIVE_ENABLED
223 443
224 if (!eeconfig_is_enabled()) { 444 if (!eeconfig_is_enabled()) {
225 dprintf("led_matrix_init_drivers eeconfig is not enabled.\n"); 445 dprintf("led_matrix_init_drivers eeconfig is not enabled.\n");
@@ -227,122 +447,137 @@ void led_matrix_init(void) {
227 eeconfig_update_led_matrix_default(); 447 eeconfig_update_led_matrix_default();
228 } 448 }
229 449
230 led_matrix_eeconfig.raw = eeconfig_read_led_matrix(); 450 eeconfig_read_led_matrix();
231
232 if (!led_matrix_eeconfig.mode) { 451 if (!led_matrix_eeconfig.mode) {
233 dprintf("led_matrix_init_drivers led_matrix_eeconfig.mode = 0. Write default values to EEPROM.\n"); 452 dprintf("led_matrix_init_drivers led_matrix_eeconfig.mode = 0. Write default values to EEPROM.\n");
234 eeconfig_update_led_matrix_default(); 453 eeconfig_update_led_matrix_default();
235 led_matrix_eeconfig.raw = eeconfig_read_led_matrix();
236 } 454 }
237
238 eeconfig_debug_led_matrix(); // display current eeprom values 455 eeconfig_debug_led_matrix(); // display current eeprom values
239} 456}
240 457
241// Deals with the messy details of incrementing an integer 458void led_matrix_set_suspend_state(bool state) {
242static uint8_t increment(uint8_t value, uint8_t step, uint8_t min, uint8_t max) { 459#ifdef LED_DISABLE_WHEN_USB_SUSPENDED
243 int16_t new_value = value; 460 if (state) {
244 new_value += step; 461 led_matrix_set_value_all(0); // turn off all LEDs when suspending
245 return MIN(MAX(new_value, min), max); 462 }
463 suspend_state = state;
464#endif
246} 465}
247 466
248static uint8_t decrement(uint8_t value, uint8_t step, uint8_t min, uint8_t max) { 467bool led_matrix_get_suspend_state(void) { return suspend_state; }
249 int16_t new_value = value;
250 new_value -= step;
251 return MIN(MAX(new_value, min), max);
252}
253 468
254// void *backlight_get_custom_key_value_eeprom_address(uint8_t led) { 469void led_matrix_toggle_eeprom_helper(bool write_to_eeprom) {
255// // 3 bytes per value
256// return EECONFIG_LED_MATRIX + (led * 3);
257// }
258
259// void backlight_get_key_value(uint8_t led, uint8_t *value) {
260// void *address = backlight_get_custom_key_value_eeprom_address(led);
261// value = eeprom_read_byte(address);
262// }
263
264// void backlight_set_key_value(uint8_t row, uint8_t column, uint8_t value) {
265// uint8_t led[8];
266// uint8_t led_count = map_row_column_to_led(row, column, led);
267// for(uint8_t i = 0; i < led_count; i++) {
268// if (led[i] < DRIVER_LED_TOTAL) {
269// void *address = backlight_get_custom_key_value_eeprom_address(led[i]);
270// eeprom_update_byte(address, value);
271// }
272// }
273// }
274
275uint32_t led_matrix_get_tick(void) { return g_tick; }
276
277void led_matrix_toggle(void) {
278 led_matrix_eeconfig.enable ^= 1; 470 led_matrix_eeconfig.enable ^= 1;
279 eeconfig_update_led_matrix(led_matrix_eeconfig.raw); 471 led_task_state = STARTING;
472 if (write_to_eeprom) {
473 eeconfig_update_led_matrix();
474 }
475 dprintf("led matrix toggle [%s]: led_matrix_eeconfig.enable = %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.enable);
280} 476}
477void led_matrix_toggle_noeeprom(void) { led_matrix_toggle_eeprom_helper(false); }
478void led_matrix_toggle(void) { led_matrix_toggle_eeprom_helper(true); }
281 479
282void led_matrix_enable(void) { 480void led_matrix_enable(void) {
283 led_matrix_eeconfig.enable = 1; 481 led_matrix_enable_noeeprom();
284 eeconfig_update_led_matrix(led_matrix_eeconfig.raw); 482 eeconfig_update_led_matrix();
285} 483}
286 484
287void led_matrix_enable_noeeprom(void) { led_matrix_eeconfig.enable = 1; } 485void led_matrix_enable_noeeprom(void) {
486 if (!led_matrix_eeconfig.enable) led_task_state = STARTING;
487 led_matrix_eeconfig.enable = 1;
488}
288 489
289void led_matrix_disable(void) { 490void led_matrix_disable(void) {
491 led_matrix_disable_noeeprom();
492 eeconfig_update_led_matrix();
493}
494
495void led_matrix_disable_noeeprom(void) {
496 if (led_matrix_eeconfig.enable) led_task_state = STARTING;
290 led_matrix_eeconfig.enable = 0; 497 led_matrix_eeconfig.enable = 0;
291 eeconfig_update_led_matrix(led_matrix_eeconfig.raw);
292} 498}
293 499
294void led_matrix_disable_noeeprom(void) { led_matrix_eeconfig.enable = 0; } 500uint8_t led_matrix_is_enabled(void) { return led_matrix_eeconfig.enable; }
295 501
296void led_matrix_step(void) { 502void led_matrix_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom) {
297 led_matrix_eeconfig.mode++; 503 if (!led_matrix_eeconfig.enable) {
298 if (led_matrix_eeconfig.mode >= LED_MATRIX_EFFECT_MAX) { 504 return;
299 led_matrix_eeconfig.mode = 1;
300 } 505 }
301 eeconfig_update_led_matrix(led_matrix_eeconfig.raw); 506 if (mode < 1) {
302} 507 led_matrix_eeconfig.mode = 1;
303 508 } else if (mode >= LED_MATRIX_EFFECT_MAX) {
304void led_matrix_step_reverse(void) {
305 led_matrix_eeconfig.mode--;
306 if (led_matrix_eeconfig.mode < 1) {
307 led_matrix_eeconfig.mode = LED_MATRIX_EFFECT_MAX - 1; 509 led_matrix_eeconfig.mode = LED_MATRIX_EFFECT_MAX - 1;
510 } else {
511 led_matrix_eeconfig.mode = mode;
512 }
513 led_task_state = STARTING;
514 if (write_to_eeprom) {
515 eeconfig_update_led_matrix();
308 } 516 }
309 eeconfig_update_led_matrix(led_matrix_eeconfig.raw); 517 dprintf("led matrix mode [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.mode);
310} 518}
519void led_matrix_mode_noeeprom(uint8_t mode) { led_matrix_mode_eeprom_helper(mode, false); }
520void led_matrix_mode(uint8_t mode) { led_matrix_mode_eeprom_helper(mode, true); }
311 521
312void led_matrix_increase_val(void) { 522uint8_t led_matrix_get_mode(void) { return led_matrix_eeconfig.mode; }
313 led_matrix_eeconfig.val = increment(led_matrix_eeconfig.val, 8, 0, LED_MATRIX_MAXIMUM_BRIGHTNESS);
314 eeconfig_update_led_matrix(led_matrix_eeconfig.raw);
315}
316 523
317void led_matrix_decrease_val(void) { 524void led_matrix_step_helper(bool write_to_eeprom) {
318 led_matrix_eeconfig.val = decrement(led_matrix_eeconfig.val, 8, 0, LED_MATRIX_MAXIMUM_BRIGHTNESS); 525 uint8_t mode = led_matrix_eeconfig.mode + 1;
319 eeconfig_update_led_matrix(led_matrix_eeconfig.raw); 526 led_matrix_mode_eeprom_helper((mode < LED_MATRIX_EFFECT_MAX) ? mode : 1, write_to_eeprom);
320} 527}
528void led_matrix_step_noeeprom(void) { led_matrix_step_helper(false); }
529void led_matrix_step(void) { led_matrix_step_helper(true); }
321 530
322void led_matrix_increase_speed(void) { 531void led_matrix_step_reverse_helper(bool write_to_eeprom) {
323 led_matrix_eeconfig.speed = increment(led_matrix_eeconfig.speed, 1, 0, 3); 532 uint8_t mode = led_matrix_eeconfig.mode - 1;
324 eeconfig_update_led_matrix(led_matrix_eeconfig.raw); // EECONFIG needs to be increased to support this 533 led_matrix_mode_eeprom_helper((mode < 1) ? LED_MATRIX_EFFECT_MAX - 1 : mode, write_to_eeprom);
325} 534}
535void led_matrix_step_reverse_noeeprom(void) { led_matrix_step_reverse_helper(false); }
536void led_matrix_step_reverse(void) { led_matrix_step_reverse_helper(true); }
326 537
327void led_matrix_decrease_speed(void) { 538void led_matrix_set_val_eeprom_helper(uint8_t val, bool write_to_eeprom) {
328 led_matrix_eeconfig.speed = decrement(led_matrix_eeconfig.speed, 1, 0, 3); 539 if (!led_matrix_eeconfig.enable) {
329 eeconfig_update_led_matrix(led_matrix_eeconfig.raw); // EECONFIG needs to be increased to support this 540 return;
541 }
542 led_matrix_eeconfig.val = (val > LED_MATRIX_MAXIMUM_BRIGHTNESS) ? LED_MATRIX_MAXIMUM_BRIGHTNESS : val;
543 if (write_to_eeprom) {
544 eeconfig_update_led_matrix();
545 }
546 dprintf("led matrix set val [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.val);
330} 547}
548void led_matrix_set_val_noeeprom(uint8_t val) { led_matrix_set_val_eeprom_helper(val, false); }
549void led_matrix_set_val(uint8_t val) { led_matrix_set_val_eeprom_helper(val, true); }
331 550
332void led_matrix_mode(uint8_t mode, bool eeprom_write) { 551uint8_t led_matrix_get_val(void) { return led_matrix_eeconfig.val; }
333 led_matrix_eeconfig.mode = mode; 552
334 if (eeprom_write) { 553void led_matrix_increase_val_helper(bool write_to_eeprom) { led_matrix_set_val_eeprom_helper(qadd8(led_matrix_eeconfig.val, LED_MATRIX_VAL_STEP), write_to_eeprom); }
335 eeconfig_update_led_matrix(led_matrix_eeconfig.raw); 554void led_matrix_increase_val_noeeprom(void) { led_matrix_increase_val_helper(false); }
555void led_matrix_increase_val(void) { led_matrix_increase_val_helper(true); }
556
557void led_matrix_decrease_val_helper(bool write_to_eeprom) { led_matrix_set_val_eeprom_helper(qsub8(led_matrix_eeconfig.val, LED_MATRIX_VAL_STEP), write_to_eeprom); }
558void led_matrix_decrease_val_noeeprom(void) { led_matrix_decrease_val_helper(false); }
559void led_matrix_decrease_val(void) { led_matrix_decrease_val_helper(true); }
560
561void led_matrix_set_speed_eeprom_helper(uint8_t speed, bool write_to_eeprom) {
562 led_matrix_eeconfig.speed = speed;
563 if (write_to_eeprom) {
564 eeconfig_update_led_matrix();
336 } 565 }
566 dprintf("led matrix set speed [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.speed);
337} 567}
568void led_matrix_set_speed_noeeprom(uint8_t speed) { led_matrix_set_speed_eeprom_helper(speed, false); }
569void led_matrix_set_speed(uint8_t speed) { led_matrix_set_speed_eeprom_helper(speed, true); }
338 570
339uint8_t led_matrix_get_mode(void) { return led_matrix_eeconfig.mode; } 571uint8_t led_matrix_get_speed(void) { return led_matrix_eeconfig.speed; }
340 572
341void led_matrix_set_value_noeeprom(uint8_t val) { led_matrix_eeconfig.val = val; } 573void led_matrix_increase_speed_helper(bool write_to_eeprom) { led_matrix_set_speed_eeprom_helper(qadd8(led_matrix_eeconfig.speed, LED_MATRIX_SPD_STEP), write_to_eeprom); }
574void led_matrix_increase_speed_noeeprom(void) { led_matrix_increase_speed_helper(false); }
575void led_matrix_increase_speed(void) { led_matrix_increase_speed_helper(true); }
342 576
343void led_matrix_set_value(uint8_t val) { 577void led_matrix_decrease_speed_helper(bool write_to_eeprom) { led_matrix_set_speed_eeprom_helper(qsub8(led_matrix_eeconfig.speed, LED_MATRIX_SPD_STEP), write_to_eeprom); }
344 led_matrix_set_value_noeeprom(val); 578void led_matrix_decrease_speed_noeeprom(void) { led_matrix_decrease_speed_helper(false); }
345 eeconfig_update_led_matrix(led_matrix_eeconfig.raw); 579void led_matrix_decrease_speed(void) { led_matrix_decrease_speed_helper(true); }
346} 580
581led_flags_t led_matrix_get_flags(void) { return led_matrix_eeconfig.flags; }
347 582
348void backlight_set(uint8_t val) { led_matrix_set_value(val); } 583void led_matrix_set_flags(led_flags_t flags) { led_matrix_eeconfig.flags = flags; }