]> git.donarmstrong.com Git - qmk_firmware.git/blob - quantum/rgb_matrix.c
Update KBD67 readme so that it mentions the KBD65 PCB (#5143)
[qmk_firmware.git] / quantum / rgb_matrix.c
1 /* Copyright 2017 Jason Williams
2  * Copyright 2017 Jack Humbert
3  * Copyright 2018 Yiancar
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19
20 #include "rgb_matrix.h"
21 #include "progmem.h"
22 #include "config.h"
23 #include "eeprom.h"
24 #include <string.h>
25 #include <math.h>
26
27 rgb_config_t rgb_matrix_config;
28
29 #ifndef MAX
30     #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
31 #endif
32
33 #ifndef MIN
34     #define MIN(a,b) ((a) < (b)? (a): (b))
35 #endif
36
37 #ifndef RGB_DISABLE_AFTER_TIMEOUT
38     #define RGB_DISABLE_AFTER_TIMEOUT 0
39 #endif
40
41 #ifndef RGB_DISABLE_WHEN_USB_SUSPENDED
42     #define RGB_DISABLE_WHEN_USB_SUSPENDED false
43 #endif
44
45 #ifndef EECONFIG_RGB_MATRIX
46     #define EECONFIG_RGB_MATRIX EECONFIG_RGBLIGHT
47 #endif
48
49 #if !defined(RGB_MATRIX_MAXIMUM_BRIGHTNESS) || RGB_MATRIX_MAXIMUM_BRIGHTNESS > 255
50     #define RGB_MATRIX_MAXIMUM_BRIGHTNESS 255
51 #endif
52
53 #ifndef RGB_DIGITAL_RAIN_DROPS
54     // lower the number for denser effect/wider keyboard
55     #define RGB_DIGITAL_RAIN_DROPS 24
56 #endif
57
58 #if !defined(DISABLE_RGB_MATRIX_RAINDROPS) || !defined(DISABLE_RGB_MATRIX_JELLYBEAN_RAINDROPS) || !defined(DISABLE_RGB_MATRIX_DIGITAL_RAIN)
59     #define TRACK_PREVIOUS_EFFECT
60 #endif
61
62 bool g_suspend_state = false;
63
64 // Global tick at 20 Hz
65 uint32_t g_tick = 0;
66
67 // Ticks since this key was last hit.
68 uint8_t g_key_hit[DRIVER_LED_TOTAL];
69
70 // Ticks since any key was last hit.
71 uint32_t g_any_key_hit = 0;
72
73 #ifndef PI
74 #define PI 3.14159265
75 #endif
76
77 uint32_t eeconfig_read_rgb_matrix(void) {
78   return eeprom_read_dword(EECONFIG_RGB_MATRIX);
79 }
80 void eeconfig_update_rgb_matrix(uint32_t val) {
81   eeprom_update_dword(EECONFIG_RGB_MATRIX, val);
82 }
83 void eeconfig_update_rgb_matrix_default(void) {
84   dprintf("eeconfig_update_rgb_matrix_default\n");
85   rgb_matrix_config.enable = 1;
86 #ifndef DISABLE_RGB_MATRIX_CYCLE_ALL
87   rgb_matrix_config.mode = RGB_MATRIX_CYCLE_LEFT_RIGHT;
88 #else
89   // fallback to solid colors if RGB_MATRIX_CYCLE_LEFT_RIGHT is disabled in userspace
90   rgb_matrix_config.mode = RGB_MATRIX_SOLID_COLOR;
91 #endif
92   rgb_matrix_config.hue = 0;
93   rgb_matrix_config.sat = 255;
94   rgb_matrix_config.val = RGB_MATRIX_MAXIMUM_BRIGHTNESS;
95   rgb_matrix_config.speed = 0;
96   eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
97 }
98 void eeconfig_debug_rgb_matrix(void) {
99   dprintf("rgb_matrix_config eprom\n");
100   dprintf("rgb_matrix_config.enable = %d\n", rgb_matrix_config.enable);
101   dprintf("rgb_matrix_config.mode = %d\n", rgb_matrix_config.mode);
102   dprintf("rgb_matrix_config.hue = %d\n", rgb_matrix_config.hue);
103   dprintf("rgb_matrix_config.sat = %d\n", rgb_matrix_config.sat);
104   dprintf("rgb_matrix_config.val = %d\n", rgb_matrix_config.val);
105   dprintf("rgb_matrix_config.speed = %d\n", rgb_matrix_config.speed);
106 }
107
108 // Last led hit
109 #define LED_HITS_TO_REMEMBER 8
110 uint8_t g_last_led_hit[LED_HITS_TO_REMEMBER] = {255};
111 uint8_t g_last_led_count = 0;
112
113 void map_row_column_to_led( uint8_t row, uint8_t column, uint8_t *led_i, uint8_t *led_count) {
114     rgb_led led;
115     *led_count = 0;
116
117     for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
118         // map_index_to_led(i, &led);
119         led = g_rgb_leds[i];
120         if (row == led.matrix_co.row && column == led.matrix_co.col) {
121             led_i[*led_count] = i;
122             (*led_count)++;
123         }
124     }
125 }
126
127 void rgb_matrix_update_pwm_buffers(void) {
128     rgb_matrix_driver.flush();
129 }
130
131 void rgb_matrix_set_color( int index, uint8_t red, uint8_t green, uint8_t blue ) {
132     rgb_matrix_driver.set_color(index, red, green, blue);
133 }
134
135 void rgb_matrix_set_color_all( uint8_t red, uint8_t green, uint8_t blue ) {
136     rgb_matrix_driver.set_color_all(red, green, blue);
137 }
138
139 bool process_rgb_matrix(uint16_t keycode, keyrecord_t *record) {
140     if ( record->event.pressed ) {
141         uint8_t led[8], led_count;
142         map_row_column_to_led(record->event.key.row, record->event.key.col, led, &led_count);
143         if (led_count > 0) {
144             for (uint8_t i = LED_HITS_TO_REMEMBER; i > 1; i--) {
145                 g_last_led_hit[i - 1] = g_last_led_hit[i - 2];
146             }
147             g_last_led_hit[0] = led[0];
148             g_last_led_count = MIN(LED_HITS_TO_REMEMBER, g_last_led_count + 1);
149         }
150         for(uint8_t i = 0; i < led_count; i++)
151             g_key_hit[led[i]] = 0;
152         g_any_key_hit = 0;
153     } else {
154         #ifdef RGB_MATRIX_KEYRELEASES
155         uint8_t led[8], led_count;
156         map_row_column_to_led(record->event.key.row, record->event.key.col, led, &led_count);
157         for(uint8_t i = 0; i < led_count; i++)
158             g_key_hit[led[i]] = 255;
159
160         g_any_key_hit = 255;
161         #endif
162     }
163     return true;
164 }
165
166 void rgb_matrix_set_suspend_state(bool state) {
167     g_suspend_state = state;
168 }
169
170 void rgb_matrix_test(void) {
171     // Mask out bits 4 and 5
172     // Increase the factor to make the test animation slower (and reduce to make it faster)
173     uint8_t factor = 10;
174     switch ( (g_tick & (0b11 << factor)) >> factor )
175     {
176         case 0:
177         {
178             rgb_matrix_set_color_all( 20, 0, 0 );
179             break;
180         }
181         case 1:
182         {
183             rgb_matrix_set_color_all( 0, 20, 0 );
184             break;
185         }
186         case 2:
187         {
188             rgb_matrix_set_color_all( 0, 0, 20 );
189             break;
190         }
191         case 3:
192         {
193             rgb_matrix_set_color_all( 20, 20, 20 );
194             break;
195         }
196     }
197 }
198
199 // All LEDs off
200 void rgb_matrix_all_off(void) {
201     rgb_matrix_set_color_all( 0, 0, 0 );
202 }
203
204 // Solid color
205 void rgb_matrix_solid_color(void) {
206     HSV hsv = { .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val };
207     RGB rgb = hsv_to_rgb( hsv );
208     rgb_matrix_set_color_all( rgb.r, rgb.g, rgb.b );
209 }
210
211 void rgb_matrix_solid_reactive(void) {
212         // Relies on hue being 8-bit and wrapping
213         for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
214         {
215                 uint16_t offset2 = g_key_hit[i]<<2;
216                 offset2 = (offset2<=130) ? (130-offset2) : 0;
217
218                 HSV hsv = { .h = rgb_matrix_config.hue+offset2, .s = 255, .v = rgb_matrix_config.val };
219                 RGB rgb = hsv_to_rgb( hsv );
220                 rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
221         }
222 }
223
224 void rgb_matrix_solid_reactive_simple(void)
225 {
226     HSV hsv = {.h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val};
227     RGB rgb;
228     
229     for (int i = 0; i < DRIVER_LED_TOTAL; i++) {
230         uint16_t offset2 = g_key_hit[i] << 2;
231         offset2 = (offset2 <= 255) ? (255 - offset2) : 0;
232         hsv.v = offset2 * rgb_matrix_config.val / RGB_MATRIX_MAXIMUM_BRIGHTNESS;
233         rgb = hsv_to_rgb(hsv);
234         rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
235     }
236 }
237
238 // alphas = color1, mods = color2
239 void rgb_matrix_alphas_mods(void) {
240
241     RGB rgb1 = hsv_to_rgb( (HSV){ .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val } );
242     RGB rgb2 = hsv_to_rgb( (HSV){ .h = (rgb_matrix_config.hue + 180) % 360, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val } );
243
244     rgb_led led;
245     for (int i = 0; i < DRIVER_LED_TOTAL; i++) {
246         led = g_rgb_leds[i];
247         if ( led.matrix_co.raw < 0xFF ) {
248             if ( led.modifier )
249             {
250                 rgb_matrix_set_color( i, rgb2.r, rgb2.g, rgb2.b );
251             }
252             else
253             {
254                 rgb_matrix_set_color( i, rgb1.r, rgb1.g, rgb1.b );
255             }
256         }
257     }
258 }
259
260 void rgb_matrix_gradient_up_down(void) {
261     int16_t h1 = rgb_matrix_config.hue;
262     int16_t h2 = (rgb_matrix_config.hue + 180) % 360;
263     int16_t deltaH = h2 - h1;
264
265     // Take the shortest path between hues
266     if ( deltaH > 127 )
267     {
268         deltaH -= 256;
269     }
270     else if ( deltaH < -127 )
271     {
272         deltaH += 256;
273     }
274     // Divide delta by 4, this gives the delta per row
275     deltaH /= 4;
276
277     int16_t s1 = rgb_matrix_config.sat;
278     int16_t s2 = rgb_matrix_config.hue;
279     int16_t deltaS = ( s2 - s1 ) / 4;
280
281     HSV hsv = { .h = 0, .s = 255, .v = rgb_matrix_config.val };
282     RGB rgb;
283     Point point;
284     for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
285     {
286         // map_led_to_point( i, &point );
287         point = g_rgb_leds[i].point;
288         // The y range will be 0..64, map this to 0..4
289         uint8_t y = (point.y>>4);
290         // Relies on hue being 8-bit and wrapping
291         hsv.h = rgb_matrix_config.hue + ( deltaH * y );
292         hsv.s = rgb_matrix_config.sat + ( deltaS * y );
293         rgb = hsv_to_rgb( hsv );
294         rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
295     }
296 }
297
298 void rgb_matrix_raindrops(bool initialize) {
299     int16_t h1 = rgb_matrix_config.hue;
300     int16_t h2 = (rgb_matrix_config.hue + 180) % 360;
301     int16_t deltaH = h2 - h1;
302     deltaH /= 4;
303
304     // Take the shortest path between hues
305     if ( deltaH > 127 )
306     {
307         deltaH -= 256;
308     }
309     else if ( deltaH < -127 )
310     {
311         deltaH += 256;
312     }
313
314     int16_t s1 = rgb_matrix_config.sat;
315     int16_t s2 = rgb_matrix_config.sat;
316     int16_t deltaS = ( s2 - s1 ) / 4;
317
318     HSV hsv;
319     RGB rgb;
320
321     // Change one LED every tick, make sure speed is not 0
322     uint8_t led_to_change = ( g_tick & ( 0x0A / (rgb_matrix_config.speed == 0 ? 1 : rgb_matrix_config.speed) ) ) == 0 ? rand() % (DRIVER_LED_TOTAL) : 255;
323
324     for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
325     {
326         // If initialize, all get set to random colors
327         // If not, all but one will stay the same as before.
328         if ( initialize || i == led_to_change )
329         {
330             hsv.h = h1 + ( deltaH * ( rand() & 0x03 ) );
331             hsv.s = s1 + ( deltaS * ( rand() & 0x03 ) );
332             // Override brightness with global brightness control
333             hsv.v = rgb_matrix_config.val;
334
335             rgb = hsv_to_rgb( hsv );
336             rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
337         }
338     }
339 }
340
341 void rgb_matrix_cycle_all(void) {
342     uint8_t offset = ( g_tick << rgb_matrix_config.speed ) & 0xFF;
343
344     rgb_led led;
345
346     // Relies on hue being 8-bit and wrapping
347     for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
348     {
349         // map_index_to_led(i, &led);
350         led = g_rgb_leds[i];
351         if (led.matrix_co.raw < 0xFF) {
352             uint16_t offset2 = g_key_hit[i]<<2;
353             offset2 = (offset2<=63) ? (63-offset2) : 0;
354
355             HSV hsv = { .h = offset+offset2, .s = 255, .v = rgb_matrix_config.val };
356             RGB rgb = hsv_to_rgb( hsv );
357             rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
358         }
359     }
360 }
361
362 void rgb_matrix_cycle_left_right(void) {
363     uint8_t offset = ( g_tick << rgb_matrix_config.speed ) & 0xFF;
364     HSV hsv = { .h = 0, .s = 255, .v = rgb_matrix_config.val };
365     RGB rgb;
366     Point point;
367     rgb_led led;
368     for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
369     {
370         // map_index_to_led(i, &led);
371         led = g_rgb_leds[i];
372         if (led.matrix_co.raw < 0xFF) {
373             uint16_t offset2 = g_key_hit[i]<<2;
374             offset2 = (offset2<=63) ? (63-offset2) : 0;
375
376             // map_led_to_point( i, &point );
377             point = g_rgb_leds[i].point;
378             // Relies on hue being 8-bit and wrapping
379             hsv.h = point.x + offset + offset2;
380             rgb = hsv_to_rgb( hsv );
381             rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
382         }
383     }
384 }
385
386 void rgb_matrix_cycle_up_down(void) {
387     uint8_t offset = ( g_tick << rgb_matrix_config.speed ) & 0xFF;
388     HSV hsv = { .h = 0, .s = 255, .v = rgb_matrix_config.val };
389     RGB rgb;
390     Point point;
391     rgb_led led;
392     for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
393     {
394         // map_index_to_led(i, &led);
395         led = g_rgb_leds[i];
396         if (led.matrix_co.raw < 0xFF) {
397             uint16_t offset2 = g_key_hit[i]<<2;
398             offset2 = (offset2<=63) ? (63-offset2) : 0;
399
400             // map_led_to_point( i, &point );
401             point = g_rgb_leds[i].point;
402             // Relies on hue being 8-bit and wrapping
403             hsv.h = point.y + offset + offset2;
404             rgb = hsv_to_rgb( hsv );
405             rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
406         }
407     }
408 }
409
410
411 void rgb_matrix_dual_beacon(void) {
412     HSV hsv = { .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val };
413     RGB rgb;
414     Point point;
415     double cos_value = cos(g_tick * PI / 128) / 32;
416     double sin_value =  sin(g_tick * PI / 128) / 112;
417     for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
418         point = g_rgb_leds[i].point;
419         hsv.h = ((point.y - 32.0)* cos_value + (point.x - 112.0) * sin_value) * (180) + rgb_matrix_config.hue;
420         rgb = hsv_to_rgb( hsv );
421         rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
422     }
423 }
424
425 void rgb_matrix_rainbow_beacon(void) {
426     HSV hsv = { .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val };
427     RGB rgb;
428     Point point;
429     double cos_value = cos(g_tick * PI / 128);
430     double sin_value =  sin(g_tick * PI / 128);
431     for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
432         point = g_rgb_leds[i].point;
433         hsv.h = (1.5 * (rgb_matrix_config.speed == 0 ? 1 : rgb_matrix_config.speed)) * (point.y - 32.0)* cos_value + (1.5 * (rgb_matrix_config.speed == 0 ? 1 : rgb_matrix_config.speed)) * (point.x - 112.0) * sin_value + rgb_matrix_config.hue;
434         rgb = hsv_to_rgb( hsv );
435         rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
436     }
437 }
438
439 void rgb_matrix_rainbow_pinwheels(void) {
440     HSV hsv = { .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val };
441     RGB rgb;
442     Point point;
443     double cos_value = cos(g_tick * PI / 128);
444     double sin_value =  sin(g_tick * PI / 128);
445     for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
446         point = g_rgb_leds[i].point;
447         hsv.h = (2 * (rgb_matrix_config.speed == 0 ? 1 : rgb_matrix_config.speed)) * (point.y - 32.0)* cos_value + (2 * (rgb_matrix_config.speed == 0 ? 1 : rgb_matrix_config.speed)) * (66 - abs(point.x - 112.0)) * sin_value + rgb_matrix_config.hue;
448         rgb = hsv_to_rgb( hsv );
449         rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
450     }
451 }
452
453 void rgb_matrix_rainbow_moving_chevron(void) {
454     HSV hsv = { .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val };
455     RGB rgb;
456     Point point;
457     uint8_t r = 128;
458     double cos_value = cos(r * PI / 128);
459     double sin_value =  sin(r * PI / 128);
460     double multiplier = (g_tick / 256.0 * 224);
461     for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
462         point = g_rgb_leds[i].point;
463         hsv.h = (1.5 * (rgb_matrix_config.speed == 0 ? 1 : rgb_matrix_config.speed)) * abs(point.y - 32.0)* sin_value + (1.5 * (rgb_matrix_config.speed == 0 ? 1 : rgb_matrix_config.speed)) * (point.x - multiplier) * cos_value + rgb_matrix_config.hue;
464         rgb = hsv_to_rgb( hsv );
465         rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
466     }
467 }
468
469
470 void rgb_matrix_jellybean_raindrops( bool initialize ) {
471     HSV hsv;
472     RGB rgb;
473
474     // Change one LED every tick, make sure speed is not 0
475     uint8_t led_to_change = ( g_tick & ( 0x0A / (rgb_matrix_config.speed == 0 ? 1 : rgb_matrix_config.speed) ) ) == 0 ? rand() % (DRIVER_LED_TOTAL) : 255;
476
477     for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
478     {
479         // If initialize, all get set to random colors
480         // If not, all but one will stay the same as before.
481         if ( initialize || i == led_to_change )
482         {
483             hsv.h = rand() & 0xFF;
484             hsv.s = rand() & 0xFF;
485             // Override brightness with global brightness control
486             hsv.v = rgb_matrix_config.val;
487
488             rgb = hsv_to_rgb( hsv );
489             rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
490         }
491     }
492 }
493
494 void rgb_matrix_digital_rain( const bool initialize ) {
495     // algorithm ported from https://github.com/tremby/Kaleidoscope-LEDEffect-DigitalRain
496     const uint8_t drop_ticks           = 28;
497     const uint8_t pure_green_intensity = 0xd0;
498     const uint8_t max_brightness_boost = 0xc0;
499     const uint8_t max_intensity        = 0xff;
500
501     static uint8_t map[MATRIX_COLS][MATRIX_ROWS] = {{0}};
502     static uint8_t drop = 0;
503
504     if (initialize) {
505         rgb_matrix_set_color_all(0, 0, 0);
506         memset(map, 0, sizeof map);
507         drop = 0;
508     }
509     for (uint8_t col = 0; col < MATRIX_COLS; col++) {
510         for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
511             if (row == 0 && drop == 0 && rand() < RAND_MAX / RGB_DIGITAL_RAIN_DROPS) {
512                 // top row, pixels have just fallen and we're
513                 // making a new rain drop in this column
514                 map[col][row] = max_intensity;
515             }
516             else if (map[col][row] > 0 && map[col][row] < max_intensity) {
517                 // neither fully bright nor dark, decay it
518                 map[col][row]--;
519             }
520             // set the pixel colour
521             uint8_t led, led_count;
522             map_row_column_to_led(row, col, &led, &led_count);
523
524             if (map[col][row] > pure_green_intensity) {
525                 const uint8_t boost = (uint8_t) ((uint16_t) max_brightness_boost
526                         * (map[col][row] - pure_green_intensity) / (max_intensity - pure_green_intensity));
527                 rgb_matrix_set_color(led, boost, max_intensity, boost);
528             }
529             else {
530                 const uint8_t green = (uint8_t) ((uint16_t) max_intensity * map[col][row] / pure_green_intensity);
531                 rgb_matrix_set_color(led, 0, green, 0);
532             }
533         }
534     }
535     if (++drop > drop_ticks) {
536         // reset drop timer
537         drop = 0;
538         for (uint8_t row = MATRIX_ROWS - 1; row > 0; row--) {
539             for (uint8_t col = 0; col < MATRIX_COLS; col++) {
540                 // if ths is on the bottom row and bright allow decay
541                 if (row == MATRIX_ROWS - 1 && map[col][row] == max_intensity) {
542                     map[col][row]--;
543                 }
544                 // check if the pixel above is bright
545                 if (map[col][row - 1] == max_intensity) {
546                     // allow old bright pixel to decay
547                     map[col][row - 1]--;
548                     // make this pixel bright
549                     map[col][row] = max_intensity;
550                 }
551             }
552         }
553     }
554 }
555
556 void rgb_matrix_multisplash(void) {
557     // if (g_any_key_hit < 0xFF) {
558         HSV hsv = { .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val };
559         RGB rgb;
560         rgb_led led;
561         for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
562             led = g_rgb_leds[i];
563             uint16_t c = 0, d = 0;
564             rgb_led last_led;
565             // if (g_last_led_count) {
566                 for (uint8_t last_i = 0; last_i < g_last_led_count; last_i++) {
567                     last_led = g_rgb_leds[g_last_led_hit[last_i]];
568                     uint16_t dist = (uint16_t)sqrt(pow(led.point.x - last_led.point.x, 2) + pow(led.point.y - last_led.point.y, 2));
569                     uint16_t effect = (g_key_hit[g_last_led_hit[last_i]] << 2) - dist;
570                     c += MIN(MAX(effect, 0), 255);
571                     d += 255 - MIN(MAX(effect, 0), 255);
572                 }
573             // } else {
574             //     d = 255;
575             // }
576             hsv.h = (rgb_matrix_config.hue + c) % 256;
577             hsv.v = MAX(MIN(d, 255), 0);
578             rgb = hsv_to_rgb( hsv );
579             rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
580         }
581     // } else {
582         // rgb_matrix_set_color_all( 0, 0, 0 );
583     // }
584 }
585
586
587 void rgb_matrix_splash(void) {
588     g_last_led_count = MIN(g_last_led_count, 1);
589     rgb_matrix_multisplash();
590 }
591
592
593 void rgb_matrix_solid_multisplash(void) {
594     // if (g_any_key_hit < 0xFF) {
595         HSV hsv = { .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val };
596         RGB rgb;
597         rgb_led led;
598         for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
599             led = g_rgb_leds[i];
600             uint16_t d = 0;
601             rgb_led last_led;
602             // if (g_last_led_count) {
603                 for (uint8_t last_i = 0; last_i < g_last_led_count; last_i++) {
604                     last_led = g_rgb_leds[g_last_led_hit[last_i]];
605                     uint16_t dist = (uint16_t)sqrt(pow(led.point.x - last_led.point.x, 2) + pow(led.point.y - last_led.point.y, 2));
606                     uint16_t effect = (g_key_hit[g_last_led_hit[last_i]] << 2) - dist;
607                     d += 255 - MIN(MAX(effect, 0), 255);
608                 }
609             // } else {
610             //     d = 255;
611             // }
612             hsv.v = MAX(MIN(d, 255), 0);
613             rgb = hsv_to_rgb( hsv );
614             rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
615         }
616     // } else {
617         // rgb_matrix_set_color_all( 0, 0, 0 );
618     // }
619 }
620
621
622 void rgb_matrix_solid_splash(void) {
623     g_last_led_count = MIN(g_last_led_count, 1);
624     rgb_matrix_solid_multisplash();
625 }
626
627
628 // Needs eeprom access that we don't have setup currently
629
630 void rgb_matrix_custom(void) {
631 //     HSV hsv;
632 //     RGB rgb;
633 //     for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
634 //     {
635 //         backlight_get_key_color(i, &hsv);
636 //         // Override brightness with global brightness control
637 //         hsv.v = rgb_matrix_config.val;
638 //         rgb = hsv_to_rgb( hsv );
639 //         rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
640 //     }
641 }
642
643 void rgb_matrix_task(void) {
644   #ifdef TRACK_PREVIOUS_EFFECT
645       static uint8_t toggle_enable_last = 255;
646   #endif
647         if (!rgb_matrix_config.enable) {
648      rgb_matrix_all_off();
649      rgb_matrix_indicators();
650      #ifdef TRACK_PREVIOUS_EFFECT
651          toggle_enable_last = rgb_matrix_config.enable;
652      #endif
653      return;
654     }
655     // delay 1 second before driving LEDs or doing anything else
656     static uint8_t startup_tick = 0;
657     if ( startup_tick < 20 ) {
658         startup_tick++;
659         return;
660     }
661
662     g_tick++;
663
664     if ( g_any_key_hit < 0xFFFFFFFF ) {
665         g_any_key_hit++;
666     }
667
668     for ( int led = 0; led < DRIVER_LED_TOTAL; led++ ) {
669         if ( g_key_hit[led] < 255 ) {
670             if (g_key_hit[led] == 254)
671                 g_last_led_count = MAX(g_last_led_count - 1, 0);
672             g_key_hit[led]++;
673         }
674     }
675
676     // Factory default magic value
677     if ( rgb_matrix_config.mode == 255 ) {
678         rgb_matrix_test();
679         return;
680     }
681
682     // Ideally we would also stop sending zeros to the LED driver PWM buffers
683     // while suspended and just do a software shutdown. This is a cheap hack for now.
684     bool suspend_backlight = ((g_suspend_state && RGB_DISABLE_WHEN_USB_SUSPENDED) ||
685             (RGB_DISABLE_AFTER_TIMEOUT > 0 && g_any_key_hit > RGB_DISABLE_AFTER_TIMEOUT * 60 * 20));
686     uint8_t effect = suspend_backlight ? 0 : rgb_matrix_config.mode;
687
688     #ifdef TRACK_PREVIOUS_EFFECT
689         // Keep track of the effect used last time,
690         // detect change in effect, so each effect can
691         // have an optional initialization.
692
693         static uint8_t effect_last = 255;
694         bool initialize = (effect != effect_last) || (rgb_matrix_config.enable != toggle_enable_last);
695         effect_last = effect;
696         toggle_enable_last = rgb_matrix_config.enable;
697     #endif
698
699     // this gets ticked at 20 Hz.
700     // each effect can opt to do calculations
701     // and/or request PWM buffer updates.
702     switch ( effect ) {
703         case RGB_MATRIX_SOLID_COLOR:
704             rgb_matrix_solid_color();
705             break;
706         #ifndef DISABLE_RGB_MATRIX_ALPHAS_MODS
707             case RGB_MATRIX_ALPHAS_MODS:
708                 rgb_matrix_alphas_mods();
709                 break;
710         #endif
711         #ifndef DISABLE_RGB_MATRIX_DUAL_BEACON
712             case RGB_MATRIX_DUAL_BEACON:
713                 rgb_matrix_dual_beacon();
714                 break;
715         #endif
716         #ifndef DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
717             case RGB_MATRIX_GRADIENT_UP_DOWN:
718                 rgb_matrix_gradient_up_down();
719                 break;
720         #endif
721         #ifndef DISABLE_RGB_MATRIX_RAINDROPS
722             case RGB_MATRIX_RAINDROPS:
723                 rgb_matrix_raindrops( initialize );
724                 break;
725         #endif
726         #ifndef DISABLE_RGB_MATRIX_CYCLE_ALL
727             case RGB_MATRIX_CYCLE_ALL:
728                 rgb_matrix_cycle_all();
729                 break;
730         #endif
731         #ifndef DISABLE_RGB_MATRIX_CYCLE_LEFT_RIGHT
732             case RGB_MATRIX_CYCLE_LEFT_RIGHT:
733                 rgb_matrix_cycle_left_right();
734                 break;
735         #endif
736         #ifndef DISABLE_RGB_MATRIX_CYCLE_UP_DOWN
737             case RGB_MATRIX_CYCLE_UP_DOWN:
738                 rgb_matrix_cycle_up_down();
739                 break;
740         #endif
741         #ifndef DISABLE_RGB_MATRIX_RAINBOW_BEACON
742             case RGB_MATRIX_RAINBOW_BEACON:
743                 rgb_matrix_rainbow_beacon();
744                 break;
745         #endif
746         #ifndef DISABLE_RGB_MATRIX_RAINBOW_PINWHEELS
747             case RGB_MATRIX_RAINBOW_PINWHEELS:
748                 rgb_matrix_rainbow_pinwheels();
749                 break;
750         #endif
751         #ifndef DISABLE_RGB_MATRIX_RAINBOW_MOVING_CHEVRON
752             case RGB_MATRIX_RAINBOW_MOVING_CHEVRON:
753                 rgb_matrix_rainbow_moving_chevron();
754                 break;
755         #endif
756         #ifndef DISABLE_RGB_MATRIX_JELLYBEAN_RAINDROPS
757             case RGB_MATRIX_JELLYBEAN_RAINDROPS:
758                 rgb_matrix_jellybean_raindrops( initialize );
759                 break;
760         #endif
761         #ifndef DISABLE_RGB_MATRIX_DIGITAL_RAIN
762             case RGB_MATRIX_DIGITAL_RAIN:
763                 rgb_matrix_digital_rain( initialize );
764                 break;
765         #endif
766         #ifdef RGB_MATRIX_KEYPRESSES
767             #ifndef DISABLE_RGB_MATRIX_SOLID_REACTIVE
768                 case RGB_MATRIX_SOLID_REACTIVE:
769                     rgb_matrix_solid_reactive();
770                     break;
771             #endif
772             #ifndef DISABLE_RGB_MATRIX_SOLID_REACTIVE_SIMPLE
773                 case RGB_MATRIX_SOLID_REACTIVE_SIMPLE:
774                     rgb_matrix_solid_reactive_simple();
775                     break;
776             #endif
777             #ifndef DISABLE_RGB_MATRIX_SPLASH
778                 case RGB_MATRIX_SPLASH:
779                     rgb_matrix_splash();
780                     break;
781             #endif
782             #ifndef DISABLE_RGB_MATRIX_MULTISPLASH
783                 case RGB_MATRIX_MULTISPLASH:
784                     rgb_matrix_multisplash();
785                     break;
786             #endif
787             #ifndef DISABLE_RGB_MATRIX_SOLID_SPLASH
788                 case RGB_MATRIX_SOLID_SPLASH:
789                     rgb_matrix_solid_splash();
790                     break;
791             #endif
792             #ifndef DISABLE_RGB_MATRIX_SOLID_MULTISPLASH
793                 case RGB_MATRIX_SOLID_MULTISPLASH:
794                     rgb_matrix_solid_multisplash();
795                     break;
796             #endif
797         #endif
798         default:
799             rgb_matrix_custom();
800             break;
801     }
802
803     if ( ! suspend_backlight ) {
804         rgb_matrix_indicators();
805     }
806
807 }
808
809 void rgb_matrix_indicators(void) {
810     rgb_matrix_indicators_kb();
811     rgb_matrix_indicators_user();
812 }
813
814 __attribute__((weak))
815 void rgb_matrix_indicators_kb(void) {}
816
817 __attribute__((weak))
818 void rgb_matrix_indicators_user(void) {}
819
820
821 // void rgb_matrix_set_indicator_index( uint8_t *index, uint8_t row, uint8_t column )
822 // {
823 //  if ( row >= MATRIX_ROWS )
824 //  {
825 //      // Special value, 255=none, 254=all
826 //      *index = row;
827 //  }
828 //  else
829 //  {
830 //      // This needs updated to something like
831 //      // uint8_t led[8], led_count;
832 //      // map_row_column_to_led(row,column,led,&led_count);
833 //      // for(uint8_t i = 0; i < led_count; i++)
834 //      map_row_column_to_led( row, column, index );
835 //  }
836 // }
837
838 void rgb_matrix_init(void) {
839   rgb_matrix_driver.init();
840
841   // TODO: put the 1 second startup delay here?
842
843   // clear the key hits
844   for ( int led=0; led<DRIVER_LED_TOTAL; led++ ) {
845       g_key_hit[led] = 255;
846   }
847
848
849   if (!eeconfig_is_enabled()) {
850       dprintf("rgb_matrix_init_drivers eeconfig is not enabled.\n");
851       eeconfig_init();
852       eeconfig_update_rgb_matrix_default();
853   }
854   rgb_matrix_config.raw = eeconfig_read_rgb_matrix();
855   if (!rgb_matrix_config.mode) {
856       dprintf("rgb_matrix_init_drivers rgb_matrix_config.mode = 0. Write default values to EEPROM.\n");
857       eeconfig_update_rgb_matrix_default();
858       rgb_matrix_config.raw = eeconfig_read_rgb_matrix();
859   }
860   eeconfig_debug_rgb_matrix(); // display current eeprom values
861 }
862
863 // Deals with the messy details of incrementing an integer
864 static uint8_t increment( uint8_t value, uint8_t step, uint8_t min, uint8_t max ) {
865     int16_t new_value = value;
866     new_value += step;
867     return MIN( MAX( new_value, min ), max );
868 }
869
870 static uint8_t decrement( uint8_t value, uint8_t step, uint8_t min, uint8_t max ) {
871     int16_t new_value = value;
872     new_value -= step;
873     return MIN( MAX( new_value, min ), max );
874 }
875
876 // void *backlight_get_custom_key_color_eeprom_address( uint8_t led )
877 // {
878 //     // 3 bytes per color
879 //     return EECONFIG_RGB_MATRIX + ( led * 3 );
880 // }
881
882 // void backlight_get_key_color( uint8_t led, HSV *hsv )
883 // {
884 //     void *address = backlight_get_custom_key_color_eeprom_address( led );
885 //     hsv->h = eeprom_read_byte(address);
886 //     hsv->s = eeprom_read_byte(address+1);
887 //     hsv->v = eeprom_read_byte(address+2);
888 // }
889
890 // void backlight_set_key_color( uint8_t row, uint8_t column, HSV hsv )
891 // {
892 //     uint8_t led[8], led_count;
893 //     map_row_column_to_led(row,column,led,&led_count);
894 //     for(uint8_t i = 0; i < led_count; i++) {
895 //         if ( led[i] < DRIVER_LED_TOTAL )
896 //         {
897 //             void *address = backlight_get_custom_key_color_eeprom_address(led[i]);
898 //             eeprom_update_byte(address, hsv.h);
899 //             eeprom_update_byte(address+1, hsv.s);
900 //             eeprom_update_byte(address+2, hsv.v);
901 //         }
902 //     }
903 // }
904
905 uint32_t rgb_matrix_get_tick(void) {
906     return g_tick;
907 }
908
909 void rgb_matrix_toggle(void) {
910         rgb_matrix_config.enable ^= 1;
911     eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
912 }
913
914 void rgb_matrix_enable(void) {
915         rgb_matrix_config.enable = 1;
916     eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
917 }
918
919 void rgb_matrix_enable_noeeprom(void) {
920         rgb_matrix_config.enable = 1;
921 }
922
923 void rgb_matrix_disable(void) {
924         rgb_matrix_config.enable = 0;
925     eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
926 }
927
928 void rgb_matrix_disable_noeeprom(void) {
929         rgb_matrix_config.enable = 0;
930 }
931
932 void rgb_matrix_step(void) {
933     rgb_matrix_config.mode++;
934     if (rgb_matrix_config.mode >= RGB_MATRIX_EFFECT_MAX)
935         rgb_matrix_config.mode = 1;
936     eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
937 }
938
939 void rgb_matrix_step_reverse(void) {
940     rgb_matrix_config.mode--;
941     if (rgb_matrix_config.mode < 1)
942         rgb_matrix_config.mode = RGB_MATRIX_EFFECT_MAX - 1;
943     eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
944 }
945
946 void rgb_matrix_increase_hue(void) {
947     rgb_matrix_config.hue = increment( rgb_matrix_config.hue, 8, 0, 255 );
948     eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
949 }
950
951 void rgb_matrix_decrease_hue(void) {
952     rgb_matrix_config.hue = decrement( rgb_matrix_config.hue, 8, 0, 255 );
953     eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
954 }
955
956 void rgb_matrix_increase_sat(void) {
957     rgb_matrix_config.sat = increment( rgb_matrix_config.sat, 8, 0, 255 );
958     eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
959 }
960
961 void rgb_matrix_decrease_sat(void) {
962     rgb_matrix_config.sat = decrement( rgb_matrix_config.sat, 8, 0, 255 );
963     eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
964 }
965
966 void rgb_matrix_increase_val(void) {
967     rgb_matrix_config.val = increment( rgb_matrix_config.val, 8, 0, RGB_MATRIX_MAXIMUM_BRIGHTNESS );
968     eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
969 }
970
971 void rgb_matrix_decrease_val(void) {
972     rgb_matrix_config.val = decrement( rgb_matrix_config.val, 8, 0, RGB_MATRIX_MAXIMUM_BRIGHTNESS );
973     eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
974 }
975
976 void rgb_matrix_increase_speed(void) {
977     rgb_matrix_config.speed = increment( rgb_matrix_config.speed, 1, 0, 3 );
978     eeconfig_update_rgb_matrix(rgb_matrix_config.raw);//EECONFIG needs to be increased to support this
979 }
980
981 void rgb_matrix_decrease_speed(void) {
982     rgb_matrix_config.speed = decrement( rgb_matrix_config.speed, 1, 0, 3 );
983     eeconfig_update_rgb_matrix(rgb_matrix_config.raw);//EECONFIG needs to be increased to support this
984 }
985
986 void rgb_matrix_mode(uint8_t mode) {
987     rgb_matrix_config.mode = mode;
988     eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
989 }
990
991 void rgb_matrix_mode_noeeprom(uint8_t mode) {
992     rgb_matrix_config.mode = mode;
993 }
994
995 uint8_t rgb_matrix_get_mode(void) {
996     return rgb_matrix_config.mode;
997 }
998
999 void rgb_matrix_sethsv(uint16_t hue, uint8_t sat, uint8_t val) {
1000   rgb_matrix_config.hue = hue;
1001   rgb_matrix_config.sat = sat;
1002   rgb_matrix_config.val = val;
1003   eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
1004 }
1005
1006 void rgb_matrix_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val) {
1007   rgb_matrix_config.hue = hue;
1008   rgb_matrix_config.sat = sat;
1009   rgb_matrix_config.val = val;
1010 }