aboutsummaryrefslogtreecommitdiff
path: root/quantum/led_matrix.c
diff options
context:
space:
mode:
authorskullY <skullydazed@gmail.com>2019-01-23 15:43:48 -0800
committerskullydazed <skullydazed@users.noreply.github.com>2019-02-10 15:37:12 -0800
commitfd698c43d78ebbc42c1eb2bec74078b791616ad1 (patch)
treef55a2cd8a3af7052d9244e5ad96dd3fffa6fb5e0 /quantum/led_matrix.c
parentaeafcc9fd3f41fce6506af5ccf9d9a1fe3b968d8 (diff)
downloadqmk_firmware-fd698c43d78ebbc42c1eb2bec74078b791616ad1.tar.gz
qmk_firmware-fd698c43d78ebbc42c1eb2bec74078b791616ad1.zip
The beginning of a simple led matrix driver for is31fl3731
Diffstat (limited to 'quantum/led_matrix.c')
-rw-r--r--quantum/led_matrix.c404
1 files changed, 404 insertions, 0 deletions
diff --git a/quantum/led_matrix.c b/quantum/led_matrix.c
new file mode 100644
index 000000000..9a0aa6acd
--- /dev/null
+++ b/quantum/led_matrix.c
@@ -0,0 +1,404 @@
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 <stdint.h>
21#include <stdbool.h>
22#include "quantum.h"
23#include "led_matrix.h"
24#include "progmem.h"
25#include "config.h"
26#include "eeprom.h"
27#include <string.h>
28#include <math.h>
29
30led_config_t led_matrix_config;
31
32#ifndef MAX
33 #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
34#endif
35
36#ifndef MIN
37 #define MIN(a,b) ((a) < (b)? (a): (b))
38#endif
39
40#ifndef LED_DISABLE_AFTER_TIMEOUT
41 #define LED_DISABLE_AFTER_TIMEOUT 0
42#endif
43
44#ifndef LED_DISABLE_WHEN_USB_SUSPENDED
45 #define LED_DISABLE_WHEN_USB_SUSPENDED false
46#endif
47
48#ifndef EECONFIG_LED_MATRIX
49 #define EECONFIG_LED_MATRIX EECONFIG_RGBLIGHT
50#endif
51
52#if !defined(LED_MATRIX_MAXIMUM_BRIGHTNESS) || LED_MATRIX_MAXIMUM_BRIGHTNESS > 255
53 #define LED_MATRIX_MAXIMUM_BRIGHTNESS 255
54#endif
55
56bool g_suspend_state = false;
57
58// Global tick at 20 Hz
59uint32_t g_tick = 0;
60
61// Ticks since this key was last hit.
62uint8_t g_key_hit[DRIVER_LED_TOTAL];
63
64// Ticks since any key was last hit.
65uint32_t g_any_key_hit = 0;
66
67uint32_t eeconfig_read_led_matrix(void) {
68 return eeprom_read_dword(EECONFIG_LED_MATRIX);
69}
70void eeconfig_update_led_matrix(uint32_t config_value) {
71 eeprom_update_dword(EECONFIG_LED_MATRIX, config_value);
72}
73void eeconfig_update_led_matrix_default(void) {
74 dprintf("eeconfig_update_led_matrix_default\n");
75 led_matrix_config.enable = 1;
76 led_matrix_config.mode = LED_MATRIX_UNIFORM_BRIGHTNESS;
77 led_matrix_config.val = 128;
78 led_matrix_config.speed = 0;
79 eeconfig_update_led_matrix(led_matrix_config.raw);
80}
81void eeconfig_debug_led_matrix(void) {
82 dprintf("led_matrix_config eprom\n");
83 dprintf("led_matrix_config.enable = %d\n", led_matrix_config.enable);
84 dprintf("led_matrix_config.mode = %d\n", led_matrix_config.mode);
85 dprintf("led_matrix_config.val = %d\n", led_matrix_config.val);
86 dprintf("led_matrix_config.speed = %d\n", led_matrix_config.speed);
87}
88
89// Last led hit
90#define LED_HITS_TO_REMEMBER 8
91uint8_t g_last_led_hit[LED_HITS_TO_REMEMBER] = {255};
92uint8_t g_last_led_count = 0;
93
94void map_row_column_to_led(uint8_t row, uint8_t column, uint8_t *led_i, uint8_t *led_count) {
95 led_matrix led;
96 *led_count = 0;
97
98 for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
99 // map_index_to_led(i, &led);
100 led = g_leds[i];
101 if (row == led.matrix_co.row && column == led.matrix_co.col) {
102 led_i[*led_count] = i;
103 (*led_count)++;
104 }
105 }
106}
107
108void led_matrix_update_pwm_buffers(void) {
109 led_matrix_driver.flush();
110}
111
112void led_matrix_set_index_value(int index, uint8_t value) {
113 led_matrix_driver.set_value(index, value);
114}
115
116void led_matrix_set_index_value_all(uint8_t value) {
117 led_matrix_driver.set_value_all(value);
118}
119
120bool process_led_matrix(uint16_t keycode, keyrecord_t *record) {
121 if (record->event.pressed) {
122 uint8_t led[8], led_count;
123 map_row_column_to_led(record->event.key.row, record->event.key.col, led, &led_count);
124 if (led_count > 0) {
125 for (uint8_t i = LED_HITS_TO_REMEMBER; i > 1; i--) {
126 g_last_led_hit[i - 1] = g_last_led_hit[i - 2];
127 }
128 g_last_led_hit[0] = led[0];
129 g_last_led_count = MIN(LED_HITS_TO_REMEMBER, g_last_led_count + 1);
130 }
131 for(uint8_t i = 0; i < led_count; i++)
132 g_key_hit[led[i]] = 0;
133 g_any_key_hit = 0;
134 } else {
135 #ifdef LED_MATRIX_KEYRELEASES
136 uint8_t led[8], led_count;
137 map_row_column_to_led(record->event.key.row, record->event.key.col, led, &led_count);
138 for(uint8_t i = 0; i < led_count; i++)
139 g_key_hit[led[i]] = 255;
140
141 g_any_key_hit = 255;
142 #endif
143 }
144 return true;
145}
146
147void led_matrix_set_suspend_state(bool state) {
148 g_suspend_state = state;
149}
150
151// All LEDs off
152void led_matrix_all_off(void) {
153 led_matrix_set_index_value_all(0);
154}
155
156// Uniform brightness
157void led_matrix_uniform_brightness(void) {
158 led_matrix_set_index_value_all(led_matrix_config.val);
159}
160
161void led_matrix_custom(void) {}
162
163void led_matrix_task(void) {
164 #ifdef TRACK_PREVIOUS_EFFECT
165 static uint8_t toggle_enable_last = 255;
166 #endif
167 if (!led_matrix_config.enable) {
168 led_matrix_all_off();
169 led_matrix_indicators();
170 #ifdef TRACK_PREVIOUS_EFFECT
171 toggle_enable_last = led_matrix_config.enable;
172 #endif
173 return;
174 }
175
176 // delay 1 second before driving LEDs or doing anything else
177 // FIXME: Can't we use wait_ms() here?
178 static uint8_t startup_tick = 0;
179 if (startup_tick < 20) {
180 startup_tick++;
181 return;
182 }
183
184 g_tick++;
185
186 if (g_any_key_hit < 0xFFFFFFFF) {
187 g_any_key_hit++;
188 }
189
190 for (int led = 0; led < DRIVER_LED_TOTAL; led++) {
191 if (g_key_hit[led] < 255) {
192 if (g_key_hit[led] == 254)
193 g_last_led_count = MAX(g_last_led_count - 1, 0);
194 g_key_hit[led]++;
195 }
196 }
197
198 // Factory default magic value
199 if (led_matrix_config.mode == 255) {
200 led_matrix_uniform_brightness();
201 return;
202 }
203
204 // Ideally we would also stop sending zeros to the LED driver PWM buffers
205 // while suspended and just do a software shutdown. This is a cheap hack for now.
206 bool suspend_backlight = ((g_suspend_state && LED_DISABLE_WHEN_USB_SUSPENDED) ||
207 (LED_DISABLE_AFTER_TIMEOUT > 0 && g_any_key_hit > LED_DISABLE_AFTER_TIMEOUT * 60 * 20));
208 uint8_t effect = suspend_backlight ? 0 : led_matrix_config.mode;
209
210 #ifdef TRACK_PREVIOUS_EFFECT
211 // Keep track of the effect used last time,
212 // detect change in effect, so each effect can
213 // have an optional initialization.
214
215 static uint8_t effect_last = 255;
216 bool initialize = (effect != effect_last) || (led_matrix_config.enable != toggle_enable_last);
217 effect_last = effect;
218 toggle_enable_last = led_matrix_config.enable;
219 #endif
220
221 // this gets ticked at 20 Hz.
222 // each effect can opt to do calculations
223 // and/or request PWM buffer updates.
224 switch (effect) {
225 case LED_MATRIX_UNIFORM_BRIGHTNESS:
226 led_matrix_uniform_brightness();
227 break;
228 default:
229 led_matrix_custom();
230 break;
231 }
232
233 if (! suspend_backlight) {
234 led_matrix_indicators();
235 }
236
237}
238
239void led_matrix_indicators(void) {
240 led_matrix_indicators_kb();
241 led_matrix_indicators_user();
242}
243
244__attribute__((weak))
245void led_matrix_indicators_kb(void) {}
246
247__attribute__((weak))
248void led_matrix_indicators_user(void) {}
249
250
251// void led_matrix_set_indicator_index(uint8_t *index, uint8_t row, uint8_t column)
252// {
253// if (row >= MATRIX_ROWS)
254// {
255// // Special value, 255=none, 254=all
256// *index = row;
257// }
258// else
259// {
260// // This needs updated to something like
261// // uint8_t led[8], led_count;
262// // map_row_column_to_led(row,column,led,&led_count);
263// // for(uint8_t i = 0; i < led_count; i++)
264// map_row_column_to_led(row, column, index);
265// }
266// }
267
268void led_matrix_init(void) {
269 led_matrix_driver.init();
270
271 // TODO: put the 1 second startup delay here?
272
273 // clear the key hits
274 for (int led=0; led<DRIVER_LED_TOTAL; led++) {
275 g_key_hit[led] = 255;
276 }
277
278
279 if (!eeconfig_is_enabled()) {
280 dprintf("led_matrix_init_drivers eeconfig is not enabled.\n");
281 eeconfig_init();
282 eeconfig_update_led_matrix_default();
283 }
284 led_matrix_config.raw = eeconfig_read_led_matrix();
285 if (!led_matrix_config.mode) {
286 dprintf("led_matrix_init_drivers led_matrix_config.mode = 0. Write default values to EEPROM.\n");
287 eeconfig_update_led_matrix_default();
288 led_matrix_config.raw = eeconfig_read_led_matrix();
289 }
290 eeconfig_debug_led_matrix(); // display current eeprom values
291}
292
293// Deals with the messy details of incrementing an integer
294static uint8_t increment(uint8_t value, uint8_t step, uint8_t min, uint8_t max) {
295 int16_t new_value = value;
296 new_value += step;
297 return MIN(MAX( new_value, min), max );
298}
299
300static uint8_t decrement(uint8_t value, uint8_t step, uint8_t min, uint8_t max) {
301 int16_t new_value = value;
302 new_value -= step;
303 return MIN(MAX( new_value, min), max );
304}
305
306// void *backlight_get_custom_key_value_eeprom_address(uint8_t led) {
307// // 3 bytes per value
308// return EECONFIG_LED_MATRIX + (led * 3);
309// }
310
311// void backlight_get_key_value(uint8_t led, uint8_t *value) {
312// void *address = backlight_get_custom_key_value_eeprom_address(led);
313// value = eeprom_read_byte(address);
314// }
315
316// void backlight_set_key_value(uint8_t row, uint8_t column, uint8_t value) {
317// uint8_t led[8], led_count;
318// map_row_column_to_led(row,column,led,&led_count);
319// for(uint8_t i = 0; i < led_count; i++) {
320// if (led[i] < DRIVER_LED_TOTAL) {
321// void *address = backlight_get_custom_key_value_eeprom_address(led[i]);
322// eeprom_update_byte(address, value);
323// }
324// }
325// }
326
327uint32_t led_matrix_get_tick(void) {
328 return g_tick;
329}
330
331void led_matrix_toggle(void) {
332 led_matrix_config.enable ^= 1;
333 eeconfig_update_led_matrix(led_matrix_config.raw);
334}
335
336void led_matrix_enable(void) {
337 led_matrix_config.enable = 1;
338 eeconfig_update_led_matrix(led_matrix_config.raw);
339}
340
341void led_matrix_enable_noeeprom(void) {
342 led_matrix_config.enable = 1;
343}
344
345void led_matrix_disable(void) {
346 led_matrix_config.enable = 0;
347 eeconfig_update_led_matrix(led_matrix_config.raw);
348}
349
350void led_matrix_disable_noeeprom(void) {
351 led_matrix_config.enable = 0;
352}
353
354void led_matrix_step(void) {
355 led_matrix_config.mode++;
356 if (led_matrix_config.mode >= LED_MATRIX_EFFECT_MAX)
357 led_matrix_config.mode = 1;
358 eeconfig_update_led_matrix(led_matrix_config.raw);
359}
360
361void led_matrix_step_reverse(void) {
362 led_matrix_config.mode--;
363 if (led_matrix_config.mode < 1)
364 led_matrix_config.mode = LED_MATRIX_EFFECT_MAX - 1;
365 eeconfig_update_led_matrix(led_matrix_config.raw);
366}
367
368void led_matrix_increase_val(void) {
369 led_matrix_config.val = increment(led_matrix_config.val, 8, 0, LED_MATRIX_MAXIMUM_BRIGHTNESS);
370 eeconfig_update_led_matrix(led_matrix_config.raw);
371}
372
373void led_matrix_decrease_val(void) {
374 led_matrix_config.val = decrement(led_matrix_config.val, 8, 0, LED_MATRIX_MAXIMUM_BRIGHTNESS);
375 eeconfig_update_led_matrix(led_matrix_config.raw);
376}
377
378void led_matrix_increase_speed(void) {
379 led_matrix_config.speed = increment(led_matrix_config.speed, 1, 0, 3);
380 eeconfig_update_led_matrix(led_matrix_config.raw);//EECONFIG needs to be increased to support this
381}
382
383void led_matrix_decrease_speed(void) {
384 led_matrix_config.speed = decrement(led_matrix_config.speed, 1, 0, 3);
385 eeconfig_update_led_matrix(led_matrix_config.raw);//EECONFIG needs to be increased to support this
386}
387
388void led_matrix_mode(uint8_t mode, bool eeprom_write) {
389 led_matrix_config.mode = mode;
390 if (eeprom_write) {
391 eeconfig_update_led_matrix(led_matrix_config.raw);
392 }
393}
394
395uint8_t led_matrix_get_mode(void) {
396 return led_matrix_config.mode;
397}
398
399void led_matrix_set_value(uint8_t val, bool eeprom_write) {
400 led_matrix_config.val = val;
401 if (eeprom_write) {
402 eeconfig_update_led_matrix(led_matrix_config.raw);
403 }
404}