aboutsummaryrefslogtreecommitdiff
path: root/quantum/visualizer
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/visualizer')
-rw-r--r--quantum/visualizer/LICENSE.md29
-rw-r--r--quantum/visualizer/lcd_backlight.c89
-rw-r--r--quantum/visualizer/lcd_backlight.h47
-rw-r--r--quantum/visualizer/lcd_backlight_keyframes.c77
-rw-r--r--quantum/visualizer/lcd_backlight_keyframes.h30
-rw-r--r--quantum/visualizer/lcd_keyframes.c188
-rw-r--r--quantum/visualizer/lcd_keyframes.h39
-rw-r--r--quantum/visualizer/led_keyframes.c143
-rw-r--r--quantum/visualizer/led_keyframes.h44
-rw-r--r--quantum/visualizer/readme.md18
-rw-r--r--quantum/visualizer/resources/lcd_logo.c61
-rw-r--r--quantum/visualizer/resources/lcd_logo.pngbin0 -> 490 bytes
-rw-r--r--quantum/visualizer/resources/resources.h27
-rw-r--r--quantum/visualizer/visualizer.c502
-rw-r--r--quantum/visualizer/visualizer.h155
-rw-r--r--quantum/visualizer/visualizer.mk73
-rw-r--r--quantum/visualizer/visualizer_keyframes.c23
-rw-r--r--quantum/visualizer/visualizer_keyframes.h26
18 files changed, 1571 insertions, 0 deletions
diff --git a/quantum/visualizer/LICENSE.md b/quantum/visualizer/LICENSE.md
new file mode 100644
index 000000000..22d4c3f08
--- /dev/null
+++ b/quantum/visualizer/LICENSE.md
@@ -0,0 +1,29 @@
1The files in this project are licensed under the MIT license
2It uses the following libraries
3uGFX - with it's own license, see the license.html file in the uGFX subfolder for more information
4tmk_core - is indirectly used and not included in the repository. It's licensed under the GPLv2 license
5Chibios - which is used by tmk_core is licensed under GPLv3.
6
7Therefore the effective license for any project using the library is GPLv3
8
9The MIT License (MIT)
10
11Copyright (c) 2016 Fred Sundvik
12
13Permission is hereby granted, free of charge, to any person obtaining a copy
14of this software and associated documentation files (the "Software"), to deal
15in the Software without restriction, including without limitation the rights
16to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17copies of the Software, and to permit persons to whom the Software is
18furnished to do so, subject to the following conditions:
19
20The above copyright notice and this permission notice shall be included in all
21copies or substantial portions of the Software.
22
23THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29SOFTWARE.
diff --git a/quantum/visualizer/lcd_backlight.c b/quantum/visualizer/lcd_backlight.c
new file mode 100644
index 000000000..6cd996f75
--- /dev/null
+++ b/quantum/visualizer/lcd_backlight.c
@@ -0,0 +1,89 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "lcd_backlight.h"
26#include <math.h>
27
28static uint8_t current_hue = 0;
29static uint8_t current_saturation = 0;
30static uint8_t current_intensity = 0;
31static uint8_t current_brightness = 0;
32
33void lcd_backlight_init(void) {
34 lcd_backlight_hal_init();
35 lcd_backlight_color(current_hue, current_saturation, current_intensity);
36}
37
38// This code is based on Brian Neltner's blogpost and example code
39// "Why every LED light should be using HSI colorspace".
40// http://blog.saikoled.com/post/43693602826/why-every-led-light-should-be-using-hsi
41static void hsi_to_rgb(float h, float s, float i, uint16_t* r_out, uint16_t* g_out, uint16_t* b_out) {
42 unsigned int r, g, b;
43 h = fmodf(h, 360.0f); // cycle h around to 0-360 degrees
44 h = 3.14159f * h / 180.0f; // Convert to radians.
45 s = s > 0.0f ? (s < 1.0f ? s : 1.0f) : 0.0f; // clamp s and i to interval [0,1]
46 i = i > 0.0f ? (i < 1.0f ? i : 1.0f) : 0.0f;
47
48 // Math! Thanks in part to Kyle Miller.
49 if(h < 2.09439f) {
50 r = 65535.0f * i/3.0f *(1.0f + s * cos(h) / cosf(1.047196667f - h));
51 g = 65535.0f * i/3.0f *(1.0f + s *(1.0f - cosf(h) / cos(1.047196667f - h)));
52 b = 65535.0f * i/3.0f *(1.0f - s);
53 } else if(h < 4.188787) {
54 h = h - 2.09439;
55 g = 65535.0f * i/3.0f *(1.0f + s * cosf(h) / cosf(1.047196667f - h));
56 b = 65535.0f * i/3.0f *(1.0f + s * (1.0f - cosf(h) / cosf(1.047196667f - h)));
57 r = 65535.0f * i/3.0f *(1.0f - s);
58 } else {
59 h = h - 4.188787;
60 b = 65535.0f*i/3.0f * (1.0f + s * cosf(h) / cosf(1.047196667f - h));
61 r = 65535.0f*i/3.0f * (1.0f + s * (1.0f - cosf(h) / cosf(1.047196667f - h)));
62 g = 65535.0f*i/3.0f * (1.0f - s);
63 }
64 *r_out = r > 65535 ? 65535 : r;
65 *g_out = g > 65535 ? 65535 : g;
66 *b_out = b > 65535 ? 65535 : b;
67}
68
69void lcd_backlight_color(uint8_t hue, uint8_t saturation, uint8_t intensity) {
70 uint16_t r, g, b;
71 float hue_f = 360.0f * (float)hue / 255.0f;
72 float saturation_f = (float)saturation / 255.0f;
73 float intensity_f = (float)intensity / 255.0f;
74 intensity_f *= (float)current_brightness / 255.0f;
75 hsi_to_rgb(hue_f, saturation_f, intensity_f, &r, &g, &b);
76 current_hue = hue;
77 current_saturation = saturation;
78 current_intensity = intensity;
79 lcd_backlight_hal_color(r, g, b);
80}
81
82void lcd_backlight_brightness(uint8_t b) {
83 current_brightness = b;
84 lcd_backlight_color(current_hue, current_saturation, current_intensity);
85}
86
87uint8_t lcd_get_backlight_brightness(void) {
88 return current_brightness;
89}
diff --git a/quantum/visualizer/lcd_backlight.h b/quantum/visualizer/lcd_backlight.h
new file mode 100644
index 000000000..95d7a07b4
--- /dev/null
+++ b/quantum/visualizer/lcd_backlight.h
@@ -0,0 +1,47 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#ifndef LCD_BACKLIGHT_H_
26#define LCD_BACKLIGHT_H_
27#include "stdint.h"
28
29// Helper macros for storing hue, staturation and intensity as unsigned integers
30#define LCD_COLOR(hue, saturation, intensity) (hue << 16 | saturation << 8 | intensity)
31#define LCD_HUE(color) ((color >> 16) & 0xFF)
32#define LCD_SAT(color) ((color >> 8) & 0xFF)
33#define LCD_INT(color) (color & 0xFF)
34
35static inline uint32_t change_lcd_color_intensity(uint32_t color, uint8_t new_intensity) {
36 return (color & 0xFFFFFF00) | new_intensity;
37}
38
39void lcd_backlight_init(void);
40void lcd_backlight_color(uint8_t hue, uint8_t saturation, uint8_t intensity);
41void lcd_backlight_brightness(uint8_t b);
42uint8_t lcd_get_backlight_brightness(void);
43
44void lcd_backlight_hal_init(void);
45void lcd_backlight_hal_color(uint16_t r, uint16_t g, uint16_t b);
46
47#endif /* LCD_BACKLIGHT_H_ */
diff --git a/quantum/visualizer/lcd_backlight_keyframes.c b/quantum/visualizer/lcd_backlight_keyframes.c
new file mode 100644
index 000000000..8436d4e3d
--- /dev/null
+++ b/quantum/visualizer/lcd_backlight_keyframes.c
@@ -0,0 +1,77 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "lcd_backlight_keyframes.h"
18
19bool backlight_keyframe_animate_color(keyframe_animation_t* animation, visualizer_state_t* state) {
20 int frame_length = animation->frame_lengths[animation->current_frame];
21 int current_pos = frame_length - animation->time_left_in_frame;
22 uint8_t t_h = LCD_HUE(state->target_lcd_color);
23 uint8_t t_s = LCD_SAT(state->target_lcd_color);
24 uint8_t t_i = LCD_INT(state->target_lcd_color);
25 uint8_t p_h = LCD_HUE(state->prev_lcd_color);
26 uint8_t p_s = LCD_SAT(state->prev_lcd_color);
27 uint8_t p_i = LCD_INT(state->prev_lcd_color);
28
29 uint8_t d_h1 = t_h - p_h; //Modulo arithmetic since we want to wrap around
30 int d_h2 = t_h - p_h;
31 // Chose the shortest way around
32 int d_h = abs(d_h2) < d_h1 ? d_h2 : d_h1;
33 int d_s = t_s - p_s;
34 int d_i = t_i - p_i;
35
36 int hue = (d_h * current_pos) / frame_length;
37 int sat = (d_s * current_pos) / frame_length;
38 int intensity = (d_i * current_pos) / frame_length;
39 //dprintf("%X -> %X = %X\n", p_h, t_h, hue);
40 hue += p_h;
41 sat += p_s;
42 intensity += p_i;
43 state->current_lcd_color = LCD_COLOR(hue, sat, intensity);
44 lcd_backlight_color(
45 LCD_HUE(state->current_lcd_color),
46 LCD_SAT(state->current_lcd_color),
47 LCD_INT(state->current_lcd_color));
48
49 return true;
50}
51
52bool backlight_keyframe_set_color(keyframe_animation_t* animation, visualizer_state_t* state) {
53 (void)animation;
54 state->prev_lcd_color = state->target_lcd_color;
55 state->current_lcd_color = state->target_lcd_color;
56 lcd_backlight_color(
57 LCD_HUE(state->current_lcd_color),
58 LCD_SAT(state->current_lcd_color),
59 LCD_INT(state->current_lcd_color));
60 return false;
61}
62
63bool backlight_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state) {
64 (void)animation;
65 (void)state;
66 lcd_backlight_hal_color(0, 0, 0);
67 return false;
68}
69
70bool backlight_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state) {
71 (void)animation;
72 (void)state;
73 lcd_backlight_color(LCD_HUE(state->current_lcd_color),
74 LCD_SAT(state->current_lcd_color),
75 LCD_INT(state->current_lcd_color));
76 return false;
77}
diff --git a/quantum/visualizer/lcd_backlight_keyframes.h b/quantum/visualizer/lcd_backlight_keyframes.h
new file mode 100644
index 000000000..e1c125cf9
--- /dev/null
+++ b/quantum/visualizer/lcd_backlight_keyframes.h
@@ -0,0 +1,30 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef QUANTUM_VISUALIZER_LCD_BACKLIGHT_KEYFRAMES_H_
18#define QUANTUM_VISUALIZER_LCD_BACKLIGHT_KEYFRAMES_H_
19
20#include "visualizer.h"
21
22// Animates the LCD backlight color between the current color and the target color (of the state)
23bool backlight_keyframe_animate_color(keyframe_animation_t* animation, visualizer_state_t* state);
24// Sets the backlight color to the target color
25bool backlight_keyframe_set_color(keyframe_animation_t* animation, visualizer_state_t* state);
26
27bool backlight_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state);
28bool backlight_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state);
29
30#endif /* QUANTUM_VISUALIZER_LCD_BACKLIGHT_KEYFRAMES_H_ */
diff --git a/quantum/visualizer/lcd_keyframes.c b/quantum/visualizer/lcd_keyframes.c
new file mode 100644
index 000000000..82e4184d2
--- /dev/null
+++ b/quantum/visualizer/lcd_keyframes.c
@@ -0,0 +1,188 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "lcd_keyframes.h"
18#include <string.h>
19#include "action_util.h"
20#include "led.h"
21#include "resources/resources.h"
22
23bool lcd_keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state) {
24 (void)animation;
25 gdispClear(White);
26 gdispDrawString(0, 10, state->layer_text, state->font_dejavusansbold12, Black);
27 return false;
28}
29
30static void format_layer_bitmap_string(uint16_t default_layer, uint16_t layer, char* buffer) {
31 for (int i=0; i<16;i++)
32 {
33 uint32_t mask = (1u << i);
34 if (default_layer & mask) {
35 if (layer & mask) {
36 *buffer = 'B';
37 } else {
38 *buffer = 'D';
39 }
40 } else if (layer & mask) {
41 *buffer = '1';
42 } else {
43 *buffer = '0';
44 }
45 ++buffer;
46
47 if (i==3 || i==7 || i==11) {
48 *buffer = ' ';
49 ++buffer;
50 }
51 }
52 *buffer = 0;
53}
54
55bool lcd_keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state) {
56 (void)animation;
57 const char* layer_help = "1=On D=Default B=Both";
58 char layer_buffer[16 + 4]; // 3 spaces and one null terminator
59 gdispClear(White);
60 gdispDrawString(0, 0, layer_help, state->font_fixed5x8, Black);
61 format_layer_bitmap_string(state->status.default_layer, state->status.layer, layer_buffer);
62 gdispDrawString(0, 10, layer_buffer, state->font_fixed5x8, Black);
63 format_layer_bitmap_string(state->status.default_layer >> 16, state->status.layer >> 16, layer_buffer);
64 gdispDrawString(0, 20, layer_buffer, state->font_fixed5x8, Black);
65 return false;
66}
67
68static void format_mods_bitmap_string(uint8_t mods, char* buffer) {
69 *buffer = ' ';
70 ++buffer;
71
72 for (int i = 0; i<8; i++)
73 {
74 uint32_t mask = (1u << i);
75 if (mods & mask) {
76 *buffer = '1';
77 } else {
78 *buffer = '0';
79 }
80 ++buffer;
81
82 if (i==3) {
83 *buffer = ' ';
84 ++buffer;
85 }
86 }
87 *buffer = 0;
88}
89
90bool lcd_keyframe_display_mods_bitmap(keyframe_animation_t* animation, visualizer_state_t* state) {
91 (void)animation;
92
93 const char* title = "Modifier states";
94 const char* mods_header = " CSAG CSAG ";
95 char status_buffer[12];
96
97 gdispClear(White);
98 gdispDrawString(0, 0, title, state->font_fixed5x8, Black);
99 gdispDrawString(0, 10, mods_header, state->font_fixed5x8, Black);
100 format_mods_bitmap_string(state->status.mods, status_buffer);
101 gdispDrawString(0, 20, status_buffer, state->font_fixed5x8, Black);
102
103 return false;
104}
105
106#define LED_STATE_STRING_SIZE sizeof("NUM CAPS SCRL COMP KANA")
107
108static void get_led_state_string(char* output, visualizer_state_t* state) {
109 uint8_t pos = 0;
110
111 if (state->status.leds & (1u << USB_LED_NUM_LOCK)) {
112 memcpy(output + pos, "NUM ", 4);
113 pos += 4;
114 }
115 if (state->status.leds & (1u << USB_LED_CAPS_LOCK)) {
116 memcpy(output + pos, "CAPS ", 5);
117 pos += 5;
118 }
119 if (state->status.leds & (1u << USB_LED_SCROLL_LOCK)) {
120 memcpy(output + pos, "SCRL ", 5);
121 pos += 5;
122 }
123 if (state->status.leds & (1u << USB_LED_COMPOSE)) {
124 memcpy(output + pos, "COMP ", 5);
125 pos += 5;
126 }
127 if (state->status.leds & (1u << USB_LED_KANA)) {
128 memcpy(output + pos, "KANA", 4);
129 pos += 4;
130 }
131 output[pos] = 0;
132}
133
134bool lcd_keyframe_display_led_states(keyframe_animation_t* animation, visualizer_state_t* state)
135{
136 (void)animation;
137 char output[LED_STATE_STRING_SIZE];
138 get_led_state_string(output, state);
139 gdispClear(White);
140 gdispDrawString(0, 10, output, state->font_dejavusansbold12, Black);
141 return false;
142}
143
144bool lcd_keyframe_display_layer_and_led_states(keyframe_animation_t* animation, visualizer_state_t* state) {
145 (void)animation;
146 gdispClear(White);
147 uint8_t y = 10;
148 if (state->status.leds) {
149 char output[LED_STATE_STRING_SIZE];
150 get_led_state_string(output, state);
151 gdispDrawString(0, 1, output, state->font_dejavusansbold12, Black);
152 y = 17;
153 }
154 gdispDrawString(0, y, state->layer_text, state->font_dejavusansbold12, Black);
155 return false;
156}
157
158bool lcd_keyframe_draw_logo(keyframe_animation_t* animation, visualizer_state_t* state) {
159 (void)state;
160 (void)animation;
161 // Read the uGFX documentation for information how to use the displays
162 // http://wiki.ugfx.org/index.php/Main_Page
163 gdispClear(White);
164
165 // You can use static variables for things that can't be found in the animation
166 // or state structs, here we use the image
167
168 //gdispGBlitArea is a tricky function to use since it supports blitting part of the image
169 // if you have full screen image, then just use 128 and 32 for both source and target dimensions
170 gdispGBlitArea(GDISP, 0, 0, 128, 32, 0, 0, 128, (pixel_t*)resource_lcd_logo);
171
172 return false;
173}
174
175
176bool lcd_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state) {
177 (void)animation;
178 (void)state;
179 gdispSetPowerMode(powerOff);
180 return false;
181}
182
183bool lcd_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state) {
184 (void)animation;
185 (void)state;
186 gdispSetPowerMode(powerOn);
187 return false;
188}
diff --git a/quantum/visualizer/lcd_keyframes.h b/quantum/visualizer/lcd_keyframes.h
new file mode 100644
index 000000000..2e912b4c7
--- /dev/null
+++ b/quantum/visualizer/lcd_keyframes.h
@@ -0,0 +1,39 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef QUANTUM_VISUALIZER_LCD_KEYFRAMES_H_
18#define QUANTUM_VISUALIZER_LCD_KEYFRAMES_H_
19
20#include "visualizer.h"
21
22// Displays the layer text centered vertically on the screen
23bool lcd_keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state);
24// Displays a bitmap (0/1) of all the currently active layers
25bool lcd_keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state);
26// Displays a bitmap (0/1) of all the currently active mods
27bool lcd_keyframe_display_mods_bitmap(keyframe_animation_t* animation, visualizer_state_t* state);
28// Displays the keyboard led states (CAPS (Caps lock), NUM (Num lock), SCRL (Scroll lock), COMP (Compose), KANA)
29bool lcd_keyframe_display_led_states(keyframe_animation_t* animation, visualizer_state_t* state);
30// Displays both the layer text and the led states
31bool lcd_keyframe_display_layer_and_led_states(keyframe_animation_t* animation, visualizer_state_t* state);
32// Displays the QMK logo on the LCD screen
33bool lcd_keyframe_draw_logo(keyframe_animation_t* animation, visualizer_state_t* state);
34
35bool lcd_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state);
36bool lcd_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state);
37
38
39#endif /* QUANTUM_VISUALIZER_LCD_KEYFRAMES_H_ */
diff --git a/quantum/visualizer/led_keyframes.c b/quantum/visualizer/led_keyframes.c
new file mode 100644
index 000000000..7e6e5d1ab
--- /dev/null
+++ b/quantum/visualizer/led_keyframes.c
@@ -0,0 +1,143 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24#include "gfx.h"
25#include "math.h"
26#include "led_keyframes.h"
27
28static uint8_t fade_led_color(keyframe_animation_t* animation, int from, int to) {
29 int frame_length = animation->frame_lengths[animation->current_frame];
30 int current_pos = frame_length - animation->time_left_in_frame;
31 int delta = to - from;
32 int luma = (delta * current_pos) / frame_length;
33 luma += from;
34 return luma;
35}
36
37static void keyframe_fade_all_leds_from_to(keyframe_animation_t* animation, uint8_t from, uint8_t to) {
38 uint8_t luma = fade_led_color(animation, from, to);
39 color_t color = LUMA2COLOR(luma);
40 gdispGClear(LED_DISPLAY, color);
41}
42
43// TODO: Should be customizable per keyboard
44#define NUM_ROWS LED_NUM_ROWS
45#define NUM_COLS LED_NUM_COLS
46
47static uint8_t crossfade_start_frame[NUM_ROWS][NUM_COLS];
48static uint8_t crossfade_end_frame[NUM_ROWS][NUM_COLS];
49
50static uint8_t compute_gradient_color(float t, float index, float num) {
51 const float two_pi = M_PI * 2.0f;
52 float normalized_index = (1.0f - index / (num - 1.0f)) * two_pi;
53 float x = t * two_pi + normalized_index;
54 float v = 0.5 * (cosf(x) + 1.0f);
55 return (uint8_t)(255.0f * v);
56}
57
58bool led_keyframe_fade_in_all(keyframe_animation_t* animation, visualizer_state_t* state) {
59 (void)state;
60 keyframe_fade_all_leds_from_to(animation, 0, 255);
61 return true;
62}
63
64bool led_keyframe_fade_out_all(keyframe_animation_t* animation, visualizer_state_t* state) {
65 (void)state;
66 keyframe_fade_all_leds_from_to(animation, 255, 0);
67 return true;
68}
69
70bool led_keyframe_left_to_right_gradient(keyframe_animation_t* animation, visualizer_state_t* state) {
71 (void)state;
72 float frame_length = animation->frame_lengths[animation->current_frame];
73 float current_pos = frame_length - animation->time_left_in_frame;
74 float t = current_pos / frame_length;
75 for (int i=0; i< NUM_COLS; i++) {
76 uint8_t color = compute_gradient_color(t, i, NUM_COLS);
77 gdispGDrawLine(LED_DISPLAY, i, 0, i, NUM_ROWS - 1, LUMA2COLOR(color));
78 }
79 return true;
80}
81
82bool led_keyframe_top_to_bottom_gradient(keyframe_animation_t* animation, visualizer_state_t* state) {
83 (void)state;
84 float frame_length = animation->frame_lengths[animation->current_frame];
85 float current_pos = frame_length - animation->time_left_in_frame;
86 float t = current_pos / frame_length;
87 for (int i=0; i< NUM_ROWS; i++) {
88 uint8_t color = compute_gradient_color(t, i, NUM_ROWS);
89 gdispGDrawLine(LED_DISPLAY, 0, i, NUM_COLS - 1, i, LUMA2COLOR(color));
90 }
91 return true;
92}
93
94static void copy_current_led_state(uint8_t* dest) {
95 for (int i=0;i<NUM_ROWS;i++) {
96 for (int j=0;j<NUM_COLS;j++) {
97 dest[i*NUM_COLS + j] = gdispGGetPixelColor(LED_DISPLAY, j, i);
98 }
99 }
100}
101bool led_keyframe_crossfade(keyframe_animation_t* animation, visualizer_state_t* state) {
102 (void)state;
103 if (animation->first_update_of_frame) {
104 copy_current_led_state(&crossfade_start_frame[0][0]);
105 run_next_keyframe(animation, state);
106 copy_current_led_state(&crossfade_end_frame[0][0]);
107 }
108 for (int i=0;i<NUM_ROWS;i++) {
109 for (int j=0;j<NUM_COLS;j++) {
110 color_t color = LUMA2COLOR(fade_led_color(animation, crossfade_start_frame[i][j], crossfade_end_frame[i][j]));
111 gdispGDrawPixel(LED_DISPLAY, j, i, color);
112 }
113 }
114 return true;
115}
116
117bool led_keyframe_mirror_orientation(keyframe_animation_t* animation, visualizer_state_t* state) {
118 (void)state;
119 (void)animation;
120 gdispGSetOrientation(LED_DISPLAY, GDISP_ROTATE_180);
121 return false;
122}
123
124bool led_keyframe_normal_orientation(keyframe_animation_t* animation, visualizer_state_t* state) {
125 (void)state;
126 (void)animation;
127 gdispGSetOrientation(LED_DISPLAY, GDISP_ROTATE_0);
128 return false;
129}
130
131bool led_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state) {
132 (void)state;
133 (void)animation;
134 gdispGSetPowerMode(LED_DISPLAY, powerOff);
135 return false;
136}
137
138bool led_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state) {
139 (void)state;
140 (void)animation;
141 gdispGSetPowerMode(LED_DISPLAY, powerOn);
142 return false;
143}
diff --git a/quantum/visualizer/led_keyframes.h b/quantum/visualizer/led_keyframes.h
new file mode 100644
index 000000000..a59a4f37d
--- /dev/null
+++ b/quantum/visualizer/led_keyframes.h
@@ -0,0 +1,44 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#ifndef LED_KEYFRAMES_H
26#define LED_KEYFRAMES_H
27
28#include "visualizer.h"
29
30bool led_keyframe_fade_in_all(keyframe_animation_t* animation, visualizer_state_t* state);
31bool led_keyframe_fade_out_all(keyframe_animation_t* animation, visualizer_state_t* state);
32bool led_keyframe_left_to_right_gradient(keyframe_animation_t* animation, visualizer_state_t* state);
33bool led_keyframe_top_to_bottom_gradient(keyframe_animation_t* animation, visualizer_state_t* state);
34bool led_keyframe_crossfade(keyframe_animation_t* animation, visualizer_state_t* state);
35bool led_keyframe_mirror_orientation(keyframe_animation_t* animation, visualizer_state_t* state);
36bool led_keyframe_normal_orientation(keyframe_animation_t* animation, visualizer_state_t* state);
37
38bool led_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state);
39bool led_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state);
40
41extern keyframe_animation_t led_test_animation;
42
43
44#endif /* LED_KEYFRAMES_H */
diff --git a/quantum/visualizer/readme.md b/quantum/visualizer/readme.md
new file mode 100644
index 000000000..545ba2270
--- /dev/null
+++ b/quantum/visualizer/readme.md
@@ -0,0 +1,18 @@
1# A visualization library for the TMK keyboard firmware
2
3This library is designed to work together with the [TMK keyboard firmware](https://github.com/tmk/tmk_keyboard). Currently it only works for [Chibios](http://www.chibios.org/)
4 flavors, but it would be possible to add support for other configurations as well. The LCD display functionality is provided by the [uGFX library](http://www.ugfx.org/).
5
6## To use this library as a user
7You can and should modify the visualizer\_user.c file. Check the comments in the file for more information.
8
9## To add this library to custom keyboard projects
10
111. Add tmk_visualizer as a submodule to your project
121. Set VISUALIZER_DIR in the main keyboard project makefile to point to the submodule
131. Define LCD\_ENABLE and/or LCD\_BACKLIGHT\_ENABLE, to enable support
141. Include the visualizer.mk make file
151. Copy the files in the example\_integration folder to your keyboard project
161. All other files than the callback.c file are included automatically, so you will need to add callback.c to your makefile manually. If you already have a similar file in your project, you can just copy the functions instead of the whole file.
171. Edit the files to match your hardware. You might might want to read the Chibios and UGfx documentation, for more information.
181. If you enable LCD support you might also have to write a custom uGFX display driver, check the uGFX documentation for that. You probably also want to enable SPI support in your Chibios configuration.
diff --git a/quantum/visualizer/resources/lcd_logo.c b/quantum/visualizer/resources/lcd_logo.c
new file mode 100644
index 000000000..d1a0ffa7f
--- /dev/null
+++ b/quantum/visualizer/resources/lcd_logo.c
@@ -0,0 +1,61 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "resources.h"
18
19
20// To generate an image array like this
21// Ensure the image is 128 x 32 or smaller
22// Convert the bitmap to a C array using a program like http://www.riuson.com/lcd-image-converter/
23// Ensure the the conversion process produces a monochrome format array - 1 bit/pixel, left to right, top to bottom
24// Update array in the source code with the C array produced by the conversion program
25
26// The image below is generated from lcd_logo.png
27const uint8_t resource_lcd_logo[512] = {
28 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
32 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
33 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34 0x00, 0xf8, 0xfe, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
35 0x00, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36 0x00, 0x38, 0x38, 0x38, 0x06, 0x29, 0x41, 0x24, 0x52, 0x24, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00,
37 0x00, 0x38, 0x38, 0x38, 0x09, 0x55, 0x42, 0xaa, 0xaa, 0xaa, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00,
38 0x00, 0x38, 0x38, 0x38, 0x09, 0x55, 0x82, 0x28, 0xaa, 0xae, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00,
39 0x00, 0x38, 0x38, 0x38, 0x09, 0x55, 0x43, 0x28, 0xaa, 0xaa, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00,
40 0x00, 0x38, 0x38, 0x38, 0x0a, 0x55, 0x42, 0x28, 0xaa, 0xaa, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00,
41 0x00, 0x38, 0x38, 0x38, 0x05, 0x45, 0x42, 0x28, 0x89, 0x4a, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00,
42 0x00, 0x18, 0x38, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
43 0x00, 0x1c, 0x38, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
44 0x00, 0x0e, 0x38, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
45 0x00, 0x03, 0xff, 0x80, 0x04, 0x45, 0x14, 0xa4, 0x92, 0x83, 0x52, 0x22, 0x22, 0x36, 0x00, 0x00,
46 0x00, 0x00, 0x38, 0x00, 0x0a, 0xaa, 0xaa, 0xaa, 0xba, 0x84, 0x55, 0x55, 0x57, 0x45, 0x00, 0x00,
47 0x00, 0x00, 0x38, 0x00, 0x08, 0xaa, 0xaa, 0xaa, 0x92, 0xb2, 0x55, 0x55, 0x42, 0x65, 0x00, 0x00,
48 0x00, 0x00, 0x38, 0x00, 0x08, 0xaa, 0xaa, 0xaa, 0x92, 0x81, 0x56, 0x65, 0x42, 0x45, 0x00, 0x00,
49 0x00, 0x00, 0x38, 0x00, 0x0a, 0xaa, 0xaa, 0xaa, 0x92, 0x81, 0x54, 0x45, 0x42, 0x45, 0x00, 0x00,
50 0x00, 0x00, 0x38, 0x00, 0x04, 0x48, 0xa2, 0x4a, 0x89, 0x06, 0x24, 0x42, 0x41, 0x36, 0x00, 0x00,
51 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
54 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
55 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
60};
61
diff --git a/quantum/visualizer/resources/lcd_logo.png b/quantum/visualizer/resources/lcd_logo.png
new file mode 100644
index 000000000..6cf26fc67
--- /dev/null
+++ b/quantum/visualizer/resources/lcd_logo.png
Binary files differ
diff --git a/quantum/visualizer/resources/resources.h b/quantum/visualizer/resources/resources.h
new file mode 100644
index 000000000..1ea27a536
--- /dev/null
+++ b/quantum/visualizer/resources/resources.h
@@ -0,0 +1,27 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef QUANTUM_VISUALIZER_RESOURCES_RESOURCES_H_
18#define QUANTUM_VISUALIZER_RESOURCES_RESOURCES_H_
19
20#include <stdint.h>
21
22#ifdef LCD_ENABLE
23extern const uint8_t resource_lcd_logo[];
24#endif
25
26
27#endif /* QUANTUM_VISUALIZER_RESOURCES_RESOURCES_H_ */
diff --git a/quantum/visualizer/visualizer.c b/quantum/visualizer/visualizer.c
new file mode 100644
index 000000000..cc99d1e3b
--- /dev/null
+++ b/quantum/visualizer/visualizer.c
@@ -0,0 +1,502 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "config.h"
26#include "visualizer.h"
27#include <string.h>
28#ifdef PROTOCOL_CHIBIOS
29#include "ch.h"
30#endif
31
32#include "gfx.h"
33
34#ifdef LCD_BACKLIGHT_ENABLE
35#include "lcd_backlight.h"
36#endif
37
38//#define DEBUG_VISUALIZER
39
40#ifdef DEBUG_VISUALIZER
41#include "debug.h"
42#else
43#include "nodebug.h"
44#endif
45
46#ifdef SERIAL_LINK_ENABLE
47#include "serial_link/protocol/transport.h"
48#include "serial_link/system/serial_link.h"
49#endif
50
51#include "action_util.h"
52
53// Define this in config.h
54#ifndef VISUALIZER_THREAD_PRIORITY
55#define "Visualizer thread priority not defined"
56#endif
57
58static visualizer_keyboard_status_t current_status = {
59 .layer = 0xFFFFFFFF,
60 .default_layer = 0xFFFFFFFF,
61 .leds = 0xFFFFFFFF,
62#ifdef BACKLIGHT_ENABLE
63 .backlight_level = 0,
64#endif
65 .mods = 0xFF,
66 .suspended = false,
67#ifdef VISUALIZER_USER_DATA_SIZE
68 .user_data = {0}
69#endif
70};
71
72static bool same_status(visualizer_keyboard_status_t* status1, visualizer_keyboard_status_t* status2) {
73 return status1->layer == status2->layer &&
74 status1->default_layer == status2->default_layer &&
75 status1->mods == status2->mods &&
76 status1->leds == status2->leds &&
77 status1->suspended == status2->suspended
78#ifdef BACKLIGHT_ENABLE
79 && status1->backlight_level == status2->backlight_level
80#endif
81#ifdef VISUALIZER_USER_DATA_SIZE
82 && memcmp(status1->user_data, status2->user_data, VISUALIZER_USER_DATA_SIZE) == 0
83#endif
84 ;
85}
86
87static bool visualizer_enabled = false;
88
89#ifdef VISUALIZER_USER_DATA_SIZE
90static uint8_t user_data[VISUALIZER_USER_DATA_SIZE];
91#endif
92
93#define MAX_SIMULTANEOUS_ANIMATIONS 4
94static keyframe_animation_t* animations[MAX_SIMULTANEOUS_ANIMATIONS] = {};
95
96#ifdef SERIAL_LINK_ENABLE
97MASTER_TO_ALL_SLAVES_OBJECT(current_status, visualizer_keyboard_status_t);
98
99static remote_object_t* remote_objects[] = {
100 REMOTE_OBJECT(current_status),
101};
102
103#endif
104
105GDisplay* LCD_DISPLAY = 0;
106GDisplay* LED_DISPLAY = 0;
107
108#ifdef LCD_DISPLAY_NUMBER
109__attribute__((weak))
110GDisplay* get_lcd_display(void) {
111 return gdispGetDisplay(LCD_DISPLAY_NUMBER);
112}
113#endif
114
115#ifdef LED_DISPLAY_NUMBER
116__attribute__((weak))
117GDisplay* get_led_display(void) {
118 return gdispGetDisplay(LED_DISPLAY_NUMBER);
119}
120#endif
121
122void start_keyframe_animation(keyframe_animation_t* animation) {
123 animation->current_frame = -1;
124 animation->time_left_in_frame = 0;
125 animation->need_update = true;
126 int free_index = -1;
127 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
128 if (animations[i] == animation) {
129 return;
130 }
131 if (free_index == -1 && animations[i] == NULL) {
132 free_index=i;
133 }
134 }
135 if (free_index!=-1) {
136 animations[free_index] = animation;
137 }
138}
139
140void stop_keyframe_animation(keyframe_animation_t* animation) {
141 animation->current_frame = animation->num_frames;
142 animation->time_left_in_frame = 0;
143 animation->need_update = true;
144 animation->first_update_of_frame = false;
145 animation->last_update_of_frame = false;
146 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
147 if (animations[i] == animation) {
148 animations[i] = NULL;
149 return;
150 }
151 }
152}
153
154void stop_all_keyframe_animations(void) {
155 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
156 if (animations[i]) {
157 animations[i]->current_frame = animations[i]->num_frames;
158 animations[i]->time_left_in_frame = 0;
159 animations[i]->need_update = true;
160 animations[i]->first_update_of_frame = false;
161 animations[i]->last_update_of_frame = false;
162 animations[i] = NULL;
163 }
164 }
165}
166
167static uint8_t get_num_running_animations(void) {
168 uint8_t count = 0;
169 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
170 count += animations[i] ? 1 : 0;
171 }
172 return count;
173}
174
175static bool update_keyframe_animation(keyframe_animation_t* animation, visualizer_state_t* state, systemticks_t delta, systemticks_t* sleep_time) {
176 // TODO: Clean up this messy code
177 dprintf("Animation frame%d, left %d, delta %d\n", animation->current_frame,
178 animation->time_left_in_frame, delta);
179 if (animation->current_frame == animation->num_frames) {
180 animation->need_update = false;
181 return false;
182 }
183 if (animation->current_frame == -1) {
184 animation->current_frame = 0;
185 animation->time_left_in_frame = animation->frame_lengths[0];
186 animation->need_update = true;
187 animation->first_update_of_frame = true;
188 } else {
189 animation->time_left_in_frame -= delta;
190 while (animation->time_left_in_frame <= 0) {
191 int left = animation->time_left_in_frame;
192 if (animation->need_update) {
193 animation->time_left_in_frame = 0;
194 animation->last_update_of_frame = true;
195 (*animation->frame_functions[animation->current_frame])(animation, state);
196 animation->last_update_of_frame = false;
197 }
198 animation->current_frame++;
199 animation->need_update = true;
200 animation->first_update_of_frame = true;
201 if (animation->current_frame == animation->num_frames) {
202 if (animation->loop) {
203 animation->current_frame = 0;
204 }
205 else {
206 stop_keyframe_animation(animation);
207 return false;
208 }
209 }
210 delta = -left;
211 animation->time_left_in_frame = animation->frame_lengths[animation->current_frame];
212 animation->time_left_in_frame -= delta;
213 }
214 }
215 if (animation->need_update) {
216 animation->need_update = (*animation->frame_functions[animation->current_frame])(animation, state);
217 animation->first_update_of_frame = false;
218 }
219
220 systemticks_t wanted_sleep = animation->need_update ? gfxMillisecondsToTicks(10) : (unsigned)animation->time_left_in_frame;
221 if (wanted_sleep < *sleep_time) {
222 *sleep_time = wanted_sleep;
223 }
224
225 return true;
226}
227
228void run_next_keyframe(keyframe_animation_t* animation, visualizer_state_t* state) {
229 int next_frame = animation->current_frame + 1;
230 if (next_frame == animation->num_frames) {
231 next_frame = 0;
232 }
233 keyframe_animation_t temp_animation = *animation;
234 temp_animation.current_frame = next_frame;
235 temp_animation.time_left_in_frame = animation->frame_lengths[next_frame];
236 temp_animation.first_update_of_frame = true;
237 temp_animation.last_update_of_frame = false;
238 temp_animation.need_update = false;
239 visualizer_state_t temp_state = *state;
240 (*temp_animation.frame_functions[next_frame])(&temp_animation, &temp_state);
241}
242
243// TODO: Optimize the stack size, this is probably way too big
244static DECLARE_THREAD_STACK(visualizerThreadStack, 1024);
245static DECLARE_THREAD_FUNCTION(visualizerThread, arg) {
246 (void)arg;
247
248 GListener event_listener;
249 geventListenerInit(&event_listener);
250 geventAttachSource(&event_listener, (GSourceHandle)&current_status, 0);
251
252 visualizer_keyboard_status_t initial_status = {
253 .default_layer = 0xFFFFFFFF,
254 .layer = 0xFFFFFFFF,
255 .mods = 0xFF,
256 .leds = 0xFFFFFFFF,
257 .suspended = false,
258 #ifdef VISUALIZER_USER_DATA_SIZE
259 .user_data = {0},
260 #endif
261 };
262
263 visualizer_state_t state = {
264 .status = initial_status,
265 .current_lcd_color = 0,
266#ifdef LCD_ENABLE
267 .font_fixed5x8 = gdispOpenFont("fixed_5x8"),
268 .font_dejavusansbold12 = gdispOpenFont("DejaVuSansBold12")
269#endif
270 };
271 initialize_user_visualizer(&state);
272 state.prev_lcd_color = state.current_lcd_color;
273
274#ifdef LCD_BACKLIGHT_ENABLE
275 lcd_backlight_color(
276 LCD_HUE(state.current_lcd_color),
277 LCD_SAT(state.current_lcd_color),
278 LCD_INT(state.current_lcd_color));
279#endif
280
281 systemticks_t sleep_time = TIME_INFINITE;
282 systemticks_t current_time = gfxSystemTicks();
283 bool force_update = true;
284
285 while(true) {
286 systemticks_t new_time = gfxSystemTicks();
287 systemticks_t delta = new_time - current_time;
288 current_time = new_time;
289 bool enabled = visualizer_enabled;
290 if (force_update || !same_status(&state.status, &current_status)) {
291 force_update = false;
292 #if BACKLIGHT_ENABLE
293 if(current_status.backlight_level != state.status.backlight_level) {
294 if (current_status.backlight_level != 0) {
295 gdispGSetPowerMode(LED_DISPLAY, powerOn);
296 uint16_t percent = (uint16_t)current_status.backlight_level * 100 / BACKLIGHT_LEVELS;
297 gdispGSetBacklight(LED_DISPLAY, percent);
298 }
299 else {
300 gdispGSetPowerMode(LED_DISPLAY, powerOff);
301 }
302 }
303 #endif
304 if (visualizer_enabled) {
305 if (current_status.suspended) {
306 stop_all_keyframe_animations();
307 visualizer_enabled = false;
308 state.status = current_status;
309 user_visualizer_suspend(&state);
310 }
311 else {
312 visualizer_keyboard_status_t prev_status = state.status;
313 state.status = current_status;
314 update_user_visualizer_state(&state, &prev_status);
315 }
316 state.prev_lcd_color = state.current_lcd_color;
317 }
318 }
319 if (!enabled && state.status.suspended && current_status.suspended == false) {
320 // Setting the status to the initial status will force an update
321 // when the visualizer is enabled again
322 state.status = initial_status;
323 state.status.suspended = false;
324 stop_all_keyframe_animations();
325 user_visualizer_resume(&state);
326 state.prev_lcd_color = state.current_lcd_color;
327 }
328 sleep_time = TIME_INFINITE;
329 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
330 if (animations[i]) {
331 update_keyframe_animation(animations[i], &state, delta, &sleep_time);
332 }
333 }
334#ifdef BACKLIGHT_ENABLE
335 gdispGFlush(LED_DISPLAY);
336#endif
337
338#ifdef LCD_ENABLE
339 gdispGFlush(LCD_DISPLAY);
340#endif
341
342#ifdef EMULATOR
343 draw_emulator();
344#endif
345 // Enable the visualizer when the startup or the suspend animation has finished
346 if (!visualizer_enabled && state.status.suspended == false && get_num_running_animations() == 0) {
347 visualizer_enabled = true;
348 force_update = true;
349 sleep_time = 0;
350 }
351
352 systemticks_t after_update = gfxSystemTicks();
353 unsigned update_delta = after_update - current_time;
354 if (sleep_time != TIME_INFINITE) {
355 if (sleep_time > update_delta) {
356 sleep_time -= update_delta;
357 }
358 else {
359 sleep_time = 0;
360 }
361 }
362 dprintf("Update took %d, last delta %d, sleep_time %d\n", update_delta, delta, sleep_time);
363#ifdef PROTOCOL_CHIBIOS
364 // The gEventWait function really takes milliseconds, even if the documentation says ticks.
365 // Unfortunately there's no generic ugfx conversion from system time to milliseconds,
366 // so let's do it in a platform dependent way.
367
368 // On windows the system ticks is the same as milliseconds anyway
369 if (sleep_time != TIME_INFINITE) {
370 sleep_time = ST2MS(sleep_time);
371 }
372#endif
373 geventEventWait(&event_listener, sleep_time);
374 }
375#ifdef LCD_ENABLE
376 gdispCloseFont(state.font_fixed5x8);
377 gdispCloseFont(state.font_dejavusansbold12);
378#endif
379
380 return 0;
381}
382
383void visualizer_init(void) {
384 gfxInit();
385
386 #ifdef LCD_BACKLIGHT_ENABLE
387 lcd_backlight_init();
388 #endif
389
390 #ifdef SERIAL_LINK_ENABLE
391 add_remote_objects(remote_objects, sizeof(remote_objects) / sizeof(remote_object_t*) );
392 #endif
393
394 #ifdef LCD_ENABLE
395 LCD_DISPLAY = get_lcd_display();
396 #endif
397
398 #ifdef BACKLIGHT_ENABLE
399 LED_DISPLAY = get_led_display();
400 #endif
401
402 // We are using a low priority thread, the idea is to have it run only
403 // when the main thread is sleeping during the matrix scanning
404 gfxThreadCreate(visualizerThreadStack, sizeof(visualizerThreadStack),
405 VISUALIZER_THREAD_PRIORITY, visualizerThread, NULL);
406}
407
408void update_status(bool changed) {
409 if (changed) {
410 GSourceListener* listener = geventGetSourceListener((GSourceHandle)&current_status, NULL);
411 if (listener) {
412 geventSendEvent(listener);
413 }
414 }
415#ifdef SERIAL_LINK_ENABLE
416 static systime_t last_update = 0;
417 systime_t current_update = chVTGetSystemTimeX();
418 systime_t delta = current_update - last_update;
419 if (changed || delta > MS2ST(10)) {
420 last_update = current_update;
421 visualizer_keyboard_status_t* r = begin_write_current_status();
422 *r = current_status;
423 end_write_current_status();
424 }
425#endif
426}
427
428uint8_t visualizer_get_mods() {
429 uint8_t mods = get_mods();
430
431#ifndef NO_ACTION_ONESHOT
432 if (!has_oneshot_mods_timed_out()) {
433 mods |= get_oneshot_mods();
434 }
435#endif
436 return mods;
437}
438
439#ifdef VISUALIZER_USER_DATA_SIZE
440void visualizer_set_user_data(void* u) {
441 memcpy(user_data, u, VISUALIZER_USER_DATA_SIZE);
442}
443#endif
444
445void visualizer_update(uint32_t default_state, uint32_t state, uint8_t mods, uint32_t leds) {
446 // Note that there's a small race condition here, the thread could read
447 // a state where one of these are set but not the other. But this should
448 // not really matter as it will be fixed during the next loop step.
449 // Alternatively a mutex could be used instead of the volatile variables
450
451 bool changed = false;
452#ifdef SERIAL_LINK_ENABLE
453 if (is_serial_link_connected ()) {
454 visualizer_keyboard_status_t* new_status = read_current_status();
455 if (new_status) {
456 if (!same_status(&current_status, new_status)) {
457 changed = true;
458 current_status = *new_status;
459 }
460 }
461 }
462 else {
463#else
464 {
465#endif
466 visualizer_keyboard_status_t new_status = {
467 .layer = state,
468 .default_layer = default_state,
469 .mods = mods,
470 .leds = leds,
471#ifdef BACKLIGHT_ENABLE
472 .backlight_level = current_status.backlight_level,
473#endif
474 .suspended = current_status.suspended,
475 };
476#ifdef VISUALIZER_USER_DATA_SIZE
477 memcpy(new_status.user_data, user_data, VISUALIZER_USER_DATA_SIZE);
478#endif
479 if (!same_status(&current_status, &new_status)) {
480 changed = true;
481 current_status = new_status;
482 }
483 }
484 update_status(changed);
485}
486
487void visualizer_suspend(void) {
488 current_status.suspended = true;
489 update_status(true);
490}
491
492void visualizer_resume(void) {
493 current_status.suspended = false;
494 update_status(true);
495}
496
497#ifdef BACKLIGHT_ENABLE
498void backlight_set(uint8_t level) {
499 current_status.backlight_level = level;
500 update_status(true);
501}
502#endif
diff --git a/quantum/visualizer/visualizer.h b/quantum/visualizer/visualizer.h
new file mode 100644
index 000000000..90ecdcbae
--- /dev/null
+++ b/quantum/visualizer/visualizer.h
@@ -0,0 +1,155 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#ifndef VISUALIZER_H
26#define VISUALIZER_H
27#include <stdlib.h>
28#include <stdint.h>
29#include <stdbool.h>
30
31#include "config.h"
32#include "gfx.h"
33
34#ifdef LCD_BACKLIGHT_ENABLE
35#include "lcd_backlight.h"
36#endif
37
38#ifdef BACKLIGHT_ENABLE
39#include "backlight.h"
40#endif
41
42// use this function to merge both real_mods and oneshot_mods in a uint16_t
43uint8_t visualizer_get_mods(void);
44
45// This need to be called once at the start
46void visualizer_init(void);
47// This should be called at every matrix scan
48void visualizer_update(uint32_t default_state, uint32_t state, uint8_t mods, uint32_t leds);
49
50// This should be called when the keyboard goes to suspend state
51void visualizer_suspend(void);
52// This should be called when the keyboard wakes up from suspend state
53void visualizer_resume(void);
54
55// These functions are week, so they can be overridden by the keyboard
56// if needed
57GDisplay* get_lcd_display(void);
58GDisplay* get_led_display(void);
59
60// For emulator builds, this function need to be implemented
61#ifdef EMULATOR
62void draw_emulator(void);
63#endif
64
65// If you need support for more than 16 keyframes per animation, you can change this
66#define MAX_VISUALIZER_KEY_FRAMES 16
67
68struct keyframe_animation_t;
69
70typedef struct {
71 uint32_t layer;
72 uint32_t default_layer;
73 uint32_t leds; // See led.h for available statuses
74 uint8_t mods;
75 bool suspended;
76#ifdef BACKLIGHT_ENABLE
77 uint8_t backlight_level;
78#endif
79#ifdef VISUALIZER_USER_DATA_SIZE
80 uint8_t user_data[VISUALIZER_USER_DATA_SIZE];
81#endif
82} visualizer_keyboard_status_t;
83
84// The state struct is used by the various keyframe functions
85// It's also used for setting the LCD color and layer text
86// from the user customized code
87typedef struct visualizer_state_t {
88 // The user code should primarily be modifying these
89 uint32_t target_lcd_color;
90 const char* layer_text;
91
92 // The user visualizer(and animation functions) can read these
93 visualizer_keyboard_status_t status;
94
95 // These are used by the animation functions
96 uint32_t current_lcd_color;
97 uint32_t prev_lcd_color;
98#ifdef LCD_ENABLE
99 font_t font_fixed5x8;
100 font_t font_dejavusansbold12;
101#endif
102} visualizer_state_t;
103
104// Any custom keyframe function should have this signature
105// return true to get continuous updates, otherwise you will only get one
106// update per frame
107typedef bool (*frame_func)(struct keyframe_animation_t*, visualizer_state_t*);
108
109// Represents a keyframe animation, so fields are internal to the system
110// while others are meant to be initialized by the user code
111typedef struct keyframe_animation_t {
112 // These should be initialized
113 int num_frames;
114 bool loop;
115 int frame_lengths[MAX_VISUALIZER_KEY_FRAMES];
116 frame_func frame_functions[MAX_VISUALIZER_KEY_FRAMES];
117
118 // Used internally by the system, and can also be read by
119 // keyframe update functions
120 int current_frame;
121 int time_left_in_frame;
122 bool first_update_of_frame;
123 bool last_update_of_frame;
124 bool need_update;
125
126} keyframe_animation_t;
127
128extern GDisplay* LCD_DISPLAY;
129extern GDisplay* LED_DISPLAY;
130
131void start_keyframe_animation(keyframe_animation_t* animation);
132void stop_keyframe_animation(keyframe_animation_t* animation);
133// This runs the next keyframe, but does not update the animation state
134// Useful for crossfades for example
135void run_next_keyframe(keyframe_animation_t* animation, visualizer_state_t* state);
136
137// The master can set userdata which will be transferred to the slave
138#ifdef VISUALIZER_USER_DATA_SIZE
139void visualizer_set_user_data(void* user_data);
140#endif
141
142// These functions have to be implemented by the user
143// Called regularly each time the state has changed (but not every scan loop)
144void update_user_visualizer_state(visualizer_state_t* state, visualizer_keyboard_status_t* prev_status);
145// Called when the computer goes to suspend, will also stop calling update_user_visualizer_state
146void user_visualizer_suspend(visualizer_state_t* state);
147// You have to start at least one animation as a response to the following two functions
148// When the animation has finished the visualizer will resume normal operation and start calling the
149// update_user_visualizer_state again
150// Called when the keyboard boots up
151void initialize_user_visualizer(visualizer_state_t* state);
152// Called when the computer resumes from a suspend
153void user_visualizer_resume(visualizer_state_t* state);
154
155#endif /* VISUALIZER_H */
diff --git a/quantum/visualizer/visualizer.mk b/quantum/visualizer/visualizer.mk
new file mode 100644
index 000000000..0f7d8636c
--- /dev/null
+++ b/quantum/visualizer/visualizer.mk
@@ -0,0 +1,73 @@
1# The MIT License (MIT)
2#
3# Copyright (c) 2016 Fred Sundvik
4#
5# Permission is hereby granted, free of charge, to any person obtaining a copy
6# of this software and associated documentation files (the "Software"), to deal
7# in the Software without restriction, including without limitation the rights
8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9# copies of the Software, and to permit persons to whom the Software is
10# furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in all
13# copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21# SOFTWARE.
22
23SRC += $(VISUALIZER_DIR)/visualizer.c \
24 $(VISUALIZER_DIR)/visualizer_keyframes.c
25EXTRAINCDIRS += $(GFXINC) $(VISUALIZER_DIR)
26GFXLIB = $(LIB_PATH)/ugfx
27VPATH += $(VISUALIZER_PATH)
28
29OPT_DEFS += -DVISUALIZER_ENABLE
30
31ifdef LCD_ENABLE
32OPT_DEFS += -DLCD_ENABLE
33ULIBS += -lm
34endif
35
36ifeq ($(strip $(LCD_ENABLE)), yes)
37SRC += $(VISUALIZER_DIR)/lcd_backlight.c
38SRC += $(VISUALIZER_DIR)/lcd_keyframes.c
39SRC += $(VISUALIZER_DIR)/lcd_backlight_keyframes.c
40# Note, that the linker will strip out any resources that are not actually in use
41SRC += $(VISUALIZER_DIR)/resources/lcd_logo.c
42OPT_DEFS += -DLCD_BACKLIGHT_ENABLE
43endif
44
45ifeq ($(strip $(BACKLIGHT_ENABLE)), yes)
46SRC += $(VISUALIZER_DIR)/led_keyframes.c
47endif
48
49include $(GFXLIB)/gfx.mk
50GFXSRC := $(patsubst $(TOP_DIR)/%,%,$(GFXSRC))
51GFXDEFS := $(patsubst %,-D%,$(patsubst -D%,%,$(GFXDEFS)))
52
53ifneq ("$(wildcard $(KEYMAP_PATH)/visualizer.c)","")
54 SRC += keyboards/$(KEYBOARD)/keymaps/$(KEYMAP)/visualizer.c
55else
56 ifeq ("$(wildcard $(SUBPROJECT_PATH)/keymaps/$(KEYMAP)/visualizer.c)","")
57 ifeq ("$(wildcard $(SUBPROJECT_PATH)/visualizer.c)","")
58 ifeq ("$(wildcard $(KEYBOARD_PATH)/visualizer.c)","")
59$(error "visualizer.c" not found")
60 else
61 SRC += keyboards/$(KEYBOARD)/visualizer.c
62 endif
63 else
64 SRC += keyboards/$(KEYBOARD)/$(SUBPROJECT)/visualizer.c
65 endif
66 else
67 SRC += keyboards/$(KEYBOARD)/$(SUBPROJECT)/keymaps/$(KEYMAP)/visualizer.c
68 endif
69endif
70
71ifdef EMULATOR
72UINCDIR += $(TMK_DIR)/common
73endif
diff --git a/quantum/visualizer/visualizer_keyframes.c b/quantum/visualizer/visualizer_keyframes.c
new file mode 100644
index 000000000..8f6a7e15a
--- /dev/null
+++ b/quantum/visualizer/visualizer_keyframes.c
@@ -0,0 +1,23 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "visualizer_keyframes.h"
18
19bool keyframe_no_operation(keyframe_animation_t* animation, visualizer_state_t* state) {
20 (void)animation;
21 (void)state;
22 return false;
23}
diff --git a/quantum/visualizer/visualizer_keyframes.h b/quantum/visualizer/visualizer_keyframes.h
new file mode 100644
index 000000000..9ef7653c5
--- /dev/null
+++ b/quantum/visualizer/visualizer_keyframes.h
@@ -0,0 +1,26 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef QUANTUM_VISUALIZER_VISUALIZER_KEYFRAMES_H_
18#define QUANTUM_VISUALIZER_VISUALIZER_KEYFRAMES_H_
19
20#include "visualizer.h"
21
22// Some predefined keyframe functions that can be used by the user code
23// Does nothing, useful for adding delays
24bool keyframe_no_operation(keyframe_animation_t* animation, visualizer_state_t* state);
25
26#endif /* QUANTUM_VISUALIZER_VISUALIZER_KEYFRAMES_H_ */