diff options
Diffstat (limited to 'quantum/led_matrix.c')
-rw-r--r-- | quantum/led_matrix.c | 190 |
1 files changed, 134 insertions, 56 deletions
diff --git a/quantum/led_matrix.c b/quantum/led_matrix.c index 4f05109b1..c40e5bd7d 100644 --- a/quantum/led_matrix.c +++ b/quantum/led_matrix.c | |||
@@ -75,15 +75,19 @@ | |||
75 | // globals | 75 | // globals |
76 | bool g_suspend_state = false; | 76 | bool g_suspend_state = false; |
77 | led_eeconfig_t led_matrix_eeconfig; // TODO: would like to prefix this with g_ for global consistancy, do this in another pr | 77 | led_eeconfig_t led_matrix_eeconfig; // TODO: would like to prefix this with g_ for global consistancy, do this in another pr |
78 | uint32_t g_led_timer; | ||
78 | 79 | ||
79 | // Global tick at 20 Hz | 80 | // internals |
80 | uint32_t g_tick = 0; | 81 | static uint8_t led_last_enable = UINT8_MAX; |
81 | 82 | static uint8_t led_last_effect = UINT8_MAX; | |
82 | // Ticks since this key was last hit. | 83 | static effect_params_t led_effect_params = {0, LED_FLAG_ALL, false}; |
83 | uint8_t g_key_hit[DRIVER_LED_TOTAL]; | 84 | static led_task_states led_task_state = SYNCING; |
85 | #if LED_DISABLE_TIMEOUT > 0 | ||
86 | static uint32_t led_anykey_timer; | ||
87 | #endif // LED_DISABLE_TIMEOUT > 0 | ||
84 | 88 | ||
85 | // Ticks since any key was last hit. | 89 | // double buffers |
86 | uint32_t g_any_key_hit = 0; | 90 | static uint32_t led_timer_buffer; |
87 | 91 | ||
88 | void eeconfig_read_led_matrix(void) { eeprom_read_block(&led_matrix_eeconfig, EECONFIG_LED_MATRIX, sizeof(led_matrix_eeconfig)); } | 92 | void eeconfig_read_led_matrix(void) { eeprom_read_block(&led_matrix_eeconfig, EECONFIG_LED_MATRIX, sizeof(led_matrix_eeconfig)); } |
89 | 93 | ||
@@ -95,6 +99,7 @@ void eeconfig_update_led_matrix_default(void) { | |||
95 | led_matrix_eeconfig.mode = LED_MATRIX_STARTUP_MODE; | 99 | led_matrix_eeconfig.mode = LED_MATRIX_STARTUP_MODE; |
96 | led_matrix_eeconfig.val = LED_MATRIX_STARTUP_VAL; | 100 | led_matrix_eeconfig.val = LED_MATRIX_STARTUP_VAL; |
97 | led_matrix_eeconfig.speed = LED_MATRIX_STARTUP_SPD; | 101 | led_matrix_eeconfig.speed = LED_MATRIX_STARTUP_SPD; |
102 | led_matrix_eeconfig.flags = LED_FLAG_ALL; | ||
98 | eeconfig_update_led_matrix(); | 103 | eeconfig_update_led_matrix(); |
99 | } | 104 | } |
100 | 105 | ||
@@ -104,6 +109,7 @@ void eeconfig_debug_led_matrix(void) { | |||
104 | dprintf("led_matrix_eeconfig.mode = %d\n", led_matrix_eeconfig.mode); | 109 | dprintf("led_matrix_eeconfig.mode = %d\n", led_matrix_eeconfig.mode); |
105 | dprintf("led_matrix_eeconfig.val = %d\n", led_matrix_eeconfig.val); | 110 | dprintf("led_matrix_eeconfig.val = %d\n", led_matrix_eeconfig.val); |
106 | dprintf("led_matrix_eeconfig.speed = %d\n", led_matrix_eeconfig.speed); | 111 | dprintf("led_matrix_eeconfig.speed = %d\n", led_matrix_eeconfig.speed); |
112 | dprintf("led_matrix_eeconfig.flags = %d\n", led_matrix_eeconfig.flags); | ||
107 | } | 113 | } |
108 | 114 | ||
109 | uint8_t g_last_led_hit[LED_HITS_TO_REMEMBER] = {255}; | 115 | uint8_t g_last_led_hit[LED_HITS_TO_REMEMBER] = {255}; |
@@ -140,6 +146,10 @@ void led_matrix_set_value_all(uint8_t value) { | |||
140 | } | 146 | } |
141 | 147 | ||
142 | void process_led_matrix(uint8_t row, uint8_t col, bool pressed) { | 148 | void process_led_matrix(uint8_t row, uint8_t col, bool pressed) { |
149 | #if LED_DISABLE_TIMEOUT > 0 | ||
150 | led_anykey_timer = 0; | ||
151 | #endif // LED_DISABLE_TIMEOUT > 0 | ||
152 | |||
143 | if (pressed) { | 153 | if (pressed) { |
144 | uint8_t led[8]; | 154 | uint8_t led[8]; |
145 | uint8_t led_count = led_matrix_map_row_column_to_led(row, col, led); | 155 | uint8_t led_count = led_matrix_map_row_column_to_led(row, col, led); |
@@ -150,45 +160,112 @@ void process_led_matrix(uint8_t row, uint8_t col, bool pressed) { | |||
150 | g_last_led_hit[0] = led[0]; | 160 | g_last_led_hit[0] = led[0]; |
151 | g_last_led_count = MIN(LED_HITS_TO_REMEMBER, g_last_led_count + 1); | 161 | g_last_led_count = MIN(LED_HITS_TO_REMEMBER, g_last_led_count + 1); |
152 | } | 162 | } |
153 | for (uint8_t i = 0; i < led_count; i++) g_key_hit[led[i]] = 0; | ||
154 | g_any_key_hit = 0; | ||
155 | } else { | 163 | } else { |
156 | #ifdef LED_MATRIX_KEYRELEASES | 164 | #ifdef LED_MATRIX_KEYRELEASES |
157 | uint8_t led[8]; | 165 | uint8_t led[8]; |
158 | uint8_t led_count = led_matrix_map_row_column_to_led(row, .col, led); | 166 | uint8_t led_count = led_matrix_map_row_column_to_led(row, .col, led); |
159 | for (uint8_t i = 0; i < led_count; i++) g_key_hit[led[i]] = 255; | ||
160 | |||
161 | g_any_key_hit = 255; | ||
162 | #endif | 167 | #endif |
163 | } | 168 | } |
164 | } | 169 | } |
165 | 170 | ||
166 | static void led_matrix_none(void) { led_matrix_set_value_all(0); } | 171 | static bool led_matrix_none(effect_params_t *params) { |
172 | if (!params->init) { | ||
173 | return false; | ||
174 | } | ||
167 | 175 | ||
168 | // Uniform brightness | 176 | led_matrix_set_value_all(0); |
169 | void led_matrix_uniform_brightness(void) { led_matrix_set_value_all(led_matrix_eeconfig.val); } | 177 | return false; |
178 | } | ||
170 | 179 | ||
171 | void led_matrix_custom(void) {} | 180 | static bool led_matrix_uniform_brightness(effect_params_t *params) { |
181 | LED_MATRIX_USE_LIMITS(led_min, led_max); | ||
172 | 182 | ||
173 | void led_matrix_task(void) { | 183 | uint8_t val = led_matrix_eeconfig.val; |
174 | if (!led_matrix_eeconfig.enable) { | 184 | for (uint8_t i = led_min; i < led_max; i++) { |
175 | led_matrix_none(); | 185 | LED_MATRIX_TEST_LED_FLAGS(); |
176 | led_matrix_indicators(); | 186 | led_matrix_set_value(i, val); |
177 | return; | ||
178 | } | 187 | } |
188 | return led_max < DRIVER_LED_TOTAL; | ||
189 | } | ||
179 | 190 | ||
180 | g_tick++; | 191 | static void led_task_timers(void) { |
192 | #if LED_DISABLE_TIMEOUT > 0 | ||
193 | uint32_t deltaTime = sync_timer_elapsed32(led_timer_buffer); | ||
194 | #endif // LED_DISABLE_TIMEOUT > 0 | ||
195 | led_timer_buffer = sync_timer_read32(); | ||
181 | 196 | ||
182 | if (g_any_key_hit < 0xFFFFFFFF) { | 197 | // Update double buffer timers |
183 | g_any_key_hit++; | 198 | #if LED_DISABLE_TIMEOUT > 0 |
199 | if (led_anykey_timer < UINT32_MAX) { | ||
200 | if (UINT32_MAX - deltaTime < led_anykey_timer) { | ||
201 | led_anykey_timer = UINT32_MAX; | ||
202 | } else { | ||
203 | led_anykey_timer += deltaTime; | ||
204 | } | ||
205 | } | ||
206 | #endif // LED_DISABLE_TIMEOUT > 0 | ||
207 | } | ||
208 | |||
209 | static void led_task_sync(void) { | ||
210 | // next task | ||
211 | if (sync_timer_elapsed32(g_led_timer) >= LED_MATRIX_LED_FLUSH_LIMIT) led_task_state = STARTING; | ||
212 | } | ||
213 | |||
214 | static void led_task_start(void) { | ||
215 | // reset iter | ||
216 | led_effect_params.iter = 0; | ||
217 | |||
218 | // update double buffers | ||
219 | g_led_timer = led_timer_buffer; | ||
220 | |||
221 | // next task | ||
222 | led_task_state = RENDERING; | ||
223 | } | ||
224 | |||
225 | static void led_task_render(uint8_t effect) { | ||
226 | bool rendering = false; | ||
227 | led_effect_params.init = (effect != led_last_effect) || (led_matrix_eeconfig.enable != led_last_enable); | ||
228 | if (led_effect_params.flags != led_matrix_eeconfig.flags) { | ||
229 | led_effect_params.flags = led_matrix_eeconfig.flags; | ||
230 | led_matrix_set_value_all(0); | ||
231 | } | ||
232 | |||
233 | // each effect can opt to do calculations | ||
234 | // and/or request PWM buffer updates. | ||
235 | switch (effect) { | ||
236 | case LED_MATRIX_NONE: | ||
237 | rendering = led_matrix_none(&led_effect_params); | ||
238 | case LED_MATRIX_UNIFORM_BRIGHTNESS: | ||
239 | rendering = led_matrix_uniform_brightness(&led_effect_params); | ||
240 | break; | ||
184 | } | 241 | } |
185 | 242 | ||
186 | for (int led = 0; led < DRIVER_LED_TOTAL; led++) { | 243 | led_effect_params.iter++; |
187 | if (g_key_hit[led] < 255) { | 244 | |
188 | if (g_key_hit[led] == 254) g_last_led_count = MAX(g_last_led_count - 1, 0); | 245 | // next task |
189 | g_key_hit[led]++; | 246 | if (!rendering) { |
247 | led_task_state = FLUSHING; | ||
248 | if (!led_effect_params.init && effect == LED_MATRIX_NONE) { | ||
249 | // We only need to flush once if we are LED_MATRIX_NONE | ||
250 | led_task_state = SYNCING; | ||
190 | } | 251 | } |
191 | } | 252 | } |
253 | } | ||
254 | |||
255 | static void led_task_flush(uint8_t effect) { | ||
256 | // update last trackers after the first full render so we can init over several frames | ||
257 | led_last_effect = effect; | ||
258 | led_last_enable = led_matrix_eeconfig.enable; | ||
259 | |||
260 | // update pwm buffers | ||
261 | led_matrix_update_pwm_buffers(); | ||
262 | |||
263 | // next task | ||
264 | led_task_state = SYNCING; | ||
265 | } | ||
266 | |||
267 | void led_matrix_task(void) { | ||
268 | led_task_timers(); | ||
192 | 269 | ||
193 | // Ideally we would also stop sending zeros to the LED driver PWM buffers | 270 | // Ideally we would also stop sending zeros to the LED driver PWM buffers |
194 | // while suspended and just do a software shutdown. This is a cheap hack for now. | 271 | // while suspended and just do a software shutdown. This is a cheap hack for now. |
@@ -197,32 +274,29 @@ void led_matrix_task(void) { | |||
197 | g_suspend_state || | 274 | g_suspend_state || |
198 | #endif // LED_DISABLE_WHEN_USB_SUSPENDED == true | 275 | #endif // LED_DISABLE_WHEN_USB_SUSPENDED == true |
199 | #if LED_DISABLE_TIMEOUT > 0 | 276 | #if LED_DISABLE_TIMEOUT > 0 |
200 | (g_any_key_hit > (uint32_t)LED_DISABLE_TIMEOUT) || | 277 | (led_anykey_timer > (uint32_t)LED_DISABLE_TIMEOUT) || |
201 | #endif // LED_DISABLE_TIMEOUT > 0 | 278 | #endif // LED_DISABLE_TIMEOUT > 0 |
202 | false; | 279 | false; |
203 | 280 | ||
204 | uint8_t effect = suspend_backlight || !led_matrix_eeconfig.enable ? 0 : led_matrix_eeconfig.mode; | 281 | uint8_t effect = suspend_backlight || !led_matrix_eeconfig.enable ? 0 : led_matrix_eeconfig.mode; |
205 | 282 | ||
206 | // this gets ticked at 20 Hz. | 283 | switch (led_task_state) { |
207 | // each effect can opt to do calculations | 284 | case STARTING: |
208 | // and/or request PWM buffer updates. | 285 | led_task_start(); |
209 | switch (effect) { | ||
210 | case LED_MATRIX_NONE: | ||
211 | led_matrix_none(); | ||
212 | case LED_MATRIX_UNIFORM_BRIGHTNESS: | ||
213 | led_matrix_uniform_brightness(); | ||
214 | break; | 286 | break; |
215 | default: | 287 | case RENDERING: |
216 | led_matrix_custom(); | 288 | led_task_render(effect); |
289 | if (effect) { | ||
290 | led_matrix_indicators(); | ||
291 | } | ||
292 | break; | ||
293 | case FLUSHING: | ||
294 | led_task_flush(effect); | ||
295 | break; | ||
296 | case SYNCING: | ||
297 | led_task_sync(); | ||
217 | break; | 298 | break; |
218 | } | 299 | } |
219 | |||
220 | if (effect) { | ||
221 | led_matrix_indicators(); | ||
222 | } | ||
223 | |||
224 | // Tell the LED driver to update its state | ||
225 | led_matrix_driver.flush(); | ||
226 | } | 300 | } |
227 | 301 | ||
228 | void led_matrix_indicators(void) { | 302 | void led_matrix_indicators(void) { |
@@ -237,14 +311,6 @@ __attribute__((weak)) void led_matrix_indicators_user(void) {} | |||
237 | void led_matrix_init(void) { | 311 | void led_matrix_init(void) { |
238 | led_matrix_driver.init(); | 312 | led_matrix_driver.init(); |
239 | 313 | ||
240 | // Wait half a second for the driver to finish initializing | ||
241 | wait_ms(500); | ||
242 | |||
243 | // clear the key hits | ||
244 | for (int led = 0; led < DRIVER_LED_TOTAL; led++) { | ||
245 | g_key_hit[led] = 255; | ||
246 | } | ||
247 | |||
248 | if (!eeconfig_is_enabled()) { | 314 | if (!eeconfig_is_enabled()) { |
249 | dprintf("led_matrix_init_drivers eeconfig is not enabled.\n"); | 315 | dprintf("led_matrix_init_drivers eeconfig is not enabled.\n"); |
250 | eeconfig_init(); | 316 | eeconfig_init(); |
@@ -270,6 +336,7 @@ bool led_matrix_get_suspend_state(void) { return g_suspend_state; } | |||
270 | 336 | ||
271 | void led_matrix_toggle_eeprom_helper(bool write_to_eeprom) { | 337 | void led_matrix_toggle_eeprom_helper(bool write_to_eeprom) { |
272 | led_matrix_eeconfig.enable ^= 1; | 338 | led_matrix_eeconfig.enable ^= 1; |
339 | led_task_state = STARTING; | ||
273 | if (write_to_eeprom) { | 340 | if (write_to_eeprom) { |
274 | eeconfig_update_led_matrix(); | 341 | eeconfig_update_led_matrix(); |
275 | } | 342 | } |
@@ -283,14 +350,20 @@ void led_matrix_enable(void) { | |||
283 | eeconfig_update_led_matrix(); | 350 | eeconfig_update_led_matrix(); |
284 | } | 351 | } |
285 | 352 | ||
286 | void led_matrix_enable_noeeprom(void) { led_matrix_eeconfig.enable = 1; } | 353 | void led_matrix_enable_noeeprom(void) { |
354 | if (!led_matrix_eeconfig.enable) led_task_state = STARTING; | ||
355 | led_matrix_eeconfig.enable = 1; | ||
356 | } | ||
287 | 357 | ||
288 | void led_matrix_disable(void) { | 358 | void led_matrix_disable(void) { |
289 | led_matrix_disable_noeeprom(); | 359 | led_matrix_disable_noeeprom(); |
290 | eeconfig_update_led_matrix(); | 360 | eeconfig_update_led_matrix(); |
291 | } | 361 | } |
292 | 362 | ||
293 | void led_matrix_disable_noeeprom(void) { led_matrix_eeconfig.enable = 0; } | 363 | void led_matrix_disable_noeeprom(void) { |
364 | if (led_matrix_eeconfig.enable) led_task_state = STARTING; | ||
365 | led_matrix_eeconfig.enable = 0; | ||
366 | } | ||
294 | 367 | ||
295 | uint8_t led_matrix_is_enabled(void) { return led_matrix_eeconfig.enable; } | 368 | uint8_t led_matrix_is_enabled(void) { return led_matrix_eeconfig.enable; } |
296 | 369 | ||
@@ -305,6 +378,7 @@ void led_matrix_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom) { | |||
305 | } else { | 378 | } else { |
306 | led_matrix_eeconfig.mode = mode; | 379 | led_matrix_eeconfig.mode = mode; |
307 | } | 380 | } |
381 | led_task_state = STARTING; | ||
308 | if (write_to_eeprom) { | 382 | if (write_to_eeprom) { |
309 | eeconfig_update_led_matrix(); | 383 | eeconfig_update_led_matrix(); |
310 | } | 384 | } |
@@ -371,3 +445,7 @@ void led_matrix_increase_speed(void) { led_matrix_increase_speed_helper(true); } | |||
371 | void 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); } | 445 | void 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); } |
372 | void led_matrix_decrease_speed_noeeprom(void) { led_matrix_decrease_speed_helper(false); } | 446 | void led_matrix_decrease_speed_noeeprom(void) { led_matrix_decrease_speed_helper(false); } |
373 | void led_matrix_decrease_speed(void) { led_matrix_decrease_speed_helper(true); } | 447 | void led_matrix_decrease_speed(void) { led_matrix_decrease_speed_helper(true); } |
448 | |||
449 | led_flags_t led_matrix_get_flags(void) { return led_matrix_eeconfig.flags; } | ||
450 | |||
451 | void led_matrix_set_flags(led_flags_t flags) { led_matrix_eeconfig.flags = flags; } | ||