aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJack Humbert <jack.humb@gmail.com>2016-07-06 15:02:51 -0400
committerGitHub <noreply@github.com>2016-07-06 15:02:51 -0400
commit5baaf871bbdd6667625860b0daef7fe9a91e08db (patch)
treee02fdb7bb85a16de027c6c1946817e96d5304ab3
parent19f480992c015aec0a15dca43e740bad8b7834e6 (diff)
parent6c296557909501b71fe344ce379e74094cf77c8e (diff)
downloadqmk_firmware-5baaf871bbdd6667625860b0daef7fe9a91e08db.tar.gz
qmk_firmware-5baaf871bbdd6667625860b0daef7fe9a91e08db.zip
Merge pull request #488 from fredizzimo/add_visualizer
Add visualizer library
-rw-r--r--quantum/visualizer/LICENSE.md29
-rw-r--r--quantum/visualizer/example_integration/callbacks.c36
-rw-r--r--quantum/visualizer/example_integration/gfxconf.h325
-rw-r--r--quantum/visualizer/example_integration/lcd_backlight_hal.c91
-rw-r--r--quantum/visualizer/example_integration/visualizer_user.c121
-rw-r--r--quantum/visualizer/lcd_backlight.c85
-rw-r--r--quantum/visualizer/lcd_backlight.h42
-rw-r--r--quantum/visualizer/led_test.c170
-rw-r--r--quantum/visualizer/led_test.h41
-rw-r--r--quantum/visualizer/readme.md18
-rw-r--r--quantum/visualizer/visualizer.c549
-rw-r--r--quantum/visualizer/visualizer.h149
-rw-r--r--quantum/visualizer/visualizer.mk61
13 files changed, 1717 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/example_integration/callbacks.c b/quantum/visualizer/example_integration/callbacks.c
new file mode 100644
index 000000000..2539615d6
--- /dev/null
+++ b/quantum/visualizer/example_integration/callbacks.c
@@ -0,0 +1,36 @@
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 "keyboard.h"
26#include "action_layer.h"
27#include "visualizer.h"
28#include "host.h"
29
30void post_keyboard_init(void) {
31 visualizer_init();
32}
33
34void post_keyboard_task() {
35 visualizer_set_state(default_layer_state, layer_state, host_keyboard_leds());
36}
diff --git a/quantum/visualizer/example_integration/gfxconf.h b/quantum/visualizer/example_integration/gfxconf.h
new file mode 100644
index 000000000..304c5d187
--- /dev/null
+++ b/quantum/visualizer/example_integration/gfxconf.h
@@ -0,0 +1,325 @@
1/**
2 * This file has a different license to the rest of the uGFX system.
3 * You can copy, modify and distribute this file as you see fit.
4 * You do not need to publish your source modifications to this file.
5 * The only thing you are not permitted to do is to relicense it
6 * under a different license.
7 */
8
9/**
10 * Copy this file into your project directory and rename it as gfxconf.h
11 * Edit your copy to turn on the uGFX features you want to use.
12 * The values below are the defaults.
13 *
14 * Only remove the comments from lines where you want to change the
15 * default value. This allows definitions to be included from
16 * driver makefiles when required and provides the best future
17 * compatibility for your project.
18 *
19 * Please use spaces instead of tabs in this file.
20 */
21
22#ifndef _GFXCONF_H
23#define _GFXCONF_H
24
25
26///////////////////////////////////////////////////////////////////////////
27// GOS - One of these must be defined, preferably in your Makefile //
28///////////////////////////////////////////////////////////////////////////
29#define GFX_USE_OS_CHIBIOS TRUE
30//#define GFX_USE_OS_FREERTOS FALSE
31// #define GFX_FREERTOS_USE_TRACE FALSE
32//#define GFX_USE_OS_WIN32 FALSE
33//#define GFX_USE_OS_LINUX FALSE
34//#define GFX_USE_OS_OSX FALSE
35//#define GFX_USE_OS_ECOS FALSE
36//#define GFX_USE_OS_RAWRTOS FALSE
37//#define GFX_USE_OS_ARDUINO FALSE
38//#define GFX_USE_OS_KEIL FALSE
39//#define GFX_USE_OS_CMSIS FALSE
40//#define GFX_USE_OS_RAW32 FALSE
41// #define INTERRUPTS_OFF() optional_code
42// #define INTERRUPTS_ON() optional_code
43// These are not defined by default for some reason
44#define GOS_NEED_X_THREADS FALSE
45#define GOS_NEED_X_HEAP FALSE
46
47// Options that (should where relevant) apply to all operating systems
48 #define GFX_NO_INLINE FALSE
49// #define GFX_COMPILER GFX_COMPILER_UNKNOWN
50// #define GFX_CPU GFX_CPU_UNKNOWN
51// #define GFX_OS_HEAP_SIZE 0
52// #define GFX_OS_NO_INIT FALSE
53// #define GFX_OS_INIT_NO_WARNING FALSE
54// #define GFX_OS_PRE_INIT_FUNCTION myHardwareInitRoutine
55// #define GFX_OS_EXTRA_INIT_FUNCTION myOSInitRoutine
56// #define GFX_OS_EXTRA_DEINIT_FUNCTION myOSDeInitRoutine
57
58
59///////////////////////////////////////////////////////////////////////////
60// GDISP //
61///////////////////////////////////////////////////////////////////////////
62#define GFX_USE_GDISP TRUE
63
64//#define GDISP_NEED_AUTOFLUSH FALSE
65//#define GDISP_NEED_TIMERFLUSH FALSE
66//#define GDISP_NEED_VALIDATION TRUE
67//#define GDISP_NEED_CLIP TRUE
68//#define GDISP_NEED_CIRCLE FALSE
69//#define GDISP_NEED_ELLIPSE FALSE
70//#define GDISP_NEED_ARC FALSE
71//#define GDISP_NEED_ARCSECTORS FALSE
72//#define GDISP_NEED_CONVEX_POLYGON FALSE
73//#define GDISP_NEED_SCROLL FALSE
74//#define GDISP_NEED_PIXELREAD FALSE
75//#define GDISP_NEED_CONTROL FALSE
76//#define GDISP_NEED_QUERY FALSE
77//#define GDISP_NEED_MULTITHREAD FALSE
78//#define GDISP_NEED_STREAMING FALSE
79#define GDISP_NEED_TEXT TRUE
80// #define GDISP_NEED_TEXT_WORDWRAP FALSE
81// #define GDISP_NEED_ANTIALIAS FALSE
82// #define GDISP_NEED_UTF8 FALSE
83 #define GDISP_NEED_TEXT_KERNING TRUE
84// #define GDISP_INCLUDE_FONT_UI1 FALSE
85// #define GDISP_INCLUDE_FONT_UI2 FALSE // The smallest preferred font.
86// #define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE
87// #define GDISP_INCLUDE_FONT_DEJAVUSANS10 FALSE
88// #define GDISP_INCLUDE_FONT_DEJAVUSANS12 FALSE
89// #define GDISP_INCLUDE_FONT_DEJAVUSANS16 FALSE
90// #define GDISP_INCLUDE_FONT_DEJAVUSANS20 FALSE
91// #define GDISP_INCLUDE_FONT_DEJAVUSANS24 FALSE
92// #define GDISP_INCLUDE_FONT_DEJAVUSANS32 FALSE
93 #define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12 TRUE
94// #define GDISP_INCLUDE_FONT_FIXED_10X20 FALSE
95// #define GDISP_INCLUDE_FONT_FIXED_7X14 FALSE
96 #define GDISP_INCLUDE_FONT_FIXED_5X8 TRUE
97// #define GDISP_INCLUDE_FONT_DEJAVUSANS12_AA FALSE
98// #define GDISP_INCLUDE_FONT_DEJAVUSANS16_AA FALSE
99// #define GDISP_INCLUDE_FONT_DEJAVUSANS20_AA FALSE
100// #define GDISP_INCLUDE_FONT_DEJAVUSANS24_AA FALSE
101// #define GDISP_INCLUDE_FONT_DEJAVUSANS32_AA FALSE
102// #define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12_AA FALSE
103// #define GDISP_INCLUDE_USER_FONTS FALSE
104
105//#define GDISP_NEED_IMAGE FALSE
106// #define GDISP_NEED_IMAGE_NATIVE FALSE
107// #define GDISP_NEED_IMAGE_GIF FALSE
108// #define GDISP_NEED_IMAGE_BMP FALSE
109// #define GDISP_NEED_IMAGE_BMP_1 FALSE
110// #define GDISP_NEED_IMAGE_BMP_4 FALSE
111// #define GDISP_NEED_IMAGE_BMP_4_RLE FALSE
112// #define GDISP_NEED_IMAGE_BMP_8 FALSE
113// #define GDISP_NEED_IMAGE_BMP_8_RLE FALSE
114// #define GDISP_NEED_IMAGE_BMP_16 FALSE
115// #define GDISP_NEED_IMAGE_BMP_24 FALSE
116// #define GDISP_NEED_IMAGE_BMP_32 FALSE
117// #define GDISP_NEED_IMAGE_JPG FALSE
118// #define GDISP_NEED_IMAGE_PNG FALSE
119// #define GDISP_NEED_IMAGE_ACCOUNTING FALSE
120
121//#define GDISP_NEED_PIXMAP FALSE
122// #define GDISP_NEED_PIXMAP_IMAGE FALSE
123
124//#define GDISP_DEFAULT_ORIENTATION GDISP_ROTATE_LANDSCAPE // If not defined the native hardware orientation is used.
125//#define GDISP_LINEBUF_SIZE 128
126//#define GDISP_STARTUP_COLOR Black
127#define GDISP_NEED_STARTUP_LOGO FALSE
128
129//#define GDISP_TOTAL_DISPLAYS 1
130
131//#define GDISP_DRIVER_LIST GDISPVMT_Win32, GDISPVMT_Win32
132// #ifdef GDISP_DRIVER_LIST
133// // For code and speed optimization define as TRUE or FALSE if all controllers have the same capability
134// #define GDISP_HARDWARE_STREAM_WRITE FALSE
135// #define GDISP_HARDWARE_STREAM_READ FALSE
136// #define GDISP_HARDWARE_STREAM_POS FALSE
137// #define GDISP_HARDWARE_DRAWPIXEL FALSE
138// #define GDISP_HARDWARE_CLEARS FALSE
139// #define GDISP_HARDWARE_FILLS FALSE
140// #define GDISP_HARDWARE_BITFILLS FALSE
141// #define GDISP_HARDWARE_SCROLL FALSE
142// #define GDISP_HARDWARE_PIXELREAD FALSE
143// #define GDISP_HARDWARE_CONTROL FALSE
144// #define GDISP_HARDWARE_QUERY FALSE
145// #define GDISP_HARDWARE_CLIP FALSE
146
147 #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888
148// #endif
149
150// The custom format is not defined for some reason, so define it as error
151// so we don't get compiler warnings
152#define GDISP_PIXELFORMAT_CUSTOM GDISP_PIXELFORMAT_ERROR
153
154#define GDISP_USE_GFXNET FALSE
155// #define GDISP_GFXNET_PORT 13001
156// #define GDISP_GFXNET_CUSTOM_LWIP_STARTUP FALSE
157// #define GDISP_DONT_WAIT_FOR_NET_DISPLAY FALSE
158// #define GDISP_GFXNET_UNSAFE_SOCKETS FALSE
159
160
161///////////////////////////////////////////////////////////////////////////
162// GWIN //
163///////////////////////////////////////////////////////////////////////////
164#define GFX_USE_GWIN FALSE
165
166//#define GWIN_NEED_WINDOWMANAGER FALSE
167// #define GWIN_REDRAW_IMMEDIATE FALSE
168// #define GWIN_REDRAW_SINGLEOP FALSE
169// #define GWIN_NEED_FLASHING FALSE
170// #define GWIN_FLASHING_PERIOD 250
171
172//#define GWIN_NEED_CONSOLE FALSE
173// #define GWIN_CONSOLE_USE_HISTORY FALSE
174// #define GWIN_CONSOLE_HISTORY_AVERAGING FALSE
175// #define GWIN_CONSOLE_HISTORY_ATCREATE FALSE
176// #define GWIN_CONSOLE_ESCSEQ FALSE
177// #define GWIN_CONSOLE_USE_BASESTREAM FALSE
178// #define GWIN_CONSOLE_USE_FLOAT FALSE
179//#define GWIN_NEED_GRAPH FALSE
180//#define GWIN_NEED_GL3D FALSE
181
182//#define GWIN_NEED_WIDGET FALSE
183//#define GWIN_FOCUS_HIGHLIGHT_WIDTH 1
184// #define GWIN_NEED_LABEL FALSE
185// #define GWIN_LABEL_ATTRIBUTE FALSE
186// #define GWIN_NEED_BUTTON FALSE
187// #define GWIN_BUTTON_LAZY_RELEASE FALSE
188// #define GWIN_NEED_SLIDER FALSE
189// #define GWIN_SLIDER_NOSNAP FALSE
190// #define GWIN_SLIDER_DEAD_BAND 5
191// #define GWIN_SLIDER_TOGGLE_INC 20
192// #define GWIN_NEED_CHECKBOX FALSE
193// #define GWIN_NEED_IMAGE FALSE
194// #define GWIN_NEED_IMAGE_ANIMATION FALSE
195// #define GWIN_NEED_RADIO FALSE
196// #define GWIN_NEED_LIST FALSE
197// #define GWIN_NEED_LIST_IMAGES FALSE
198// #define GWIN_NEED_PROGRESSBAR FALSE
199// #define GWIN_PROGRESSBAR_AUTO FALSE
200// #define GWIN_NEED_KEYBOARD FALSE
201// #define GWIN_KEYBOARD_DEFAULT_LAYOUT VirtualKeyboard_English1
202// #define GWIN_NEED_KEYBOARD_ENGLISH1 TRUE
203// #define GWIN_NEED_TEXTEDIT FALSE
204// #define GWIN_FLAT_STYLING FALSE
205// #define GWIN_WIDGET_TAGS FALSE
206
207//#define GWIN_NEED_CONTAINERS FALSE
208// #define GWIN_NEED_CONTAINER FALSE
209// #define GWIN_NEED_FRAME FALSE
210// #define GWIN_NEED_TABSET FALSE
211// #define GWIN_TABSET_TABHEIGHT 18
212
213
214///////////////////////////////////////////////////////////////////////////
215// GEVENT //
216///////////////////////////////////////////////////////////////////////////
217#define GFX_USE_GEVENT FALSE
218
219//#define GEVENT_ASSERT_NO_RESOURCE FALSE
220//#define GEVENT_MAXIMUM_SIZE 32
221//#define GEVENT_MAX_SOURCE_LISTENERS 32
222
223
224///////////////////////////////////////////////////////////////////////////
225// GTIMER //
226///////////////////////////////////////////////////////////////////////////
227#define GFX_USE_GTIMER FALSE
228
229//#define GTIMER_THREAD_PRIORITY HIGH_PRIORITY
230//#define GTIMER_THREAD_WORKAREA_SIZE 2048
231
232
233///////////////////////////////////////////////////////////////////////////
234// GQUEUE //
235///////////////////////////////////////////////////////////////////////////
236#define GFX_USE_GQUEUE FALSE
237
238//#define GQUEUE_NEED_ASYNC FALSE
239//#define GQUEUE_NEED_GSYNC FALSE
240//#define GQUEUE_NEED_FSYNC FALSE
241//#define GQUEUE_NEED_BUFFERS FALSE
242
243///////////////////////////////////////////////////////////////////////////
244// GINPUT //
245///////////////////////////////////////////////////////////////////////////
246#define GFX_USE_GINPUT FALSE
247
248//#define GINPUT_NEED_MOUSE FALSE
249// #define GINPUT_TOUCH_STARTRAW FALSE
250// #define GINPUT_TOUCH_NOTOUCH FALSE
251// #define GINPUT_TOUCH_NOCALIBRATE FALSE
252// #define GINPUT_TOUCH_NOCALIBRATE_GUI FALSE
253// #define GINPUT_MOUSE_POLL_PERIOD 25
254// #define GINPUT_MOUSE_CLICK_TIME 300
255// #define GINPUT_TOUCH_CXTCLICK_TIME 700
256// #define GINPUT_TOUCH_USER_CALIBRATION_LOAD FALSE
257// #define GINPUT_TOUCH_USER_CALIBRATION_SAVE FALSE
258// #define GMOUSE_DRIVER_LIST GMOUSEVMT_Win32, GMOUSEVMT_Win32
259//#define GINPUT_NEED_KEYBOARD FALSE
260// #define GINPUT_KEYBOARD_POLL_PERIOD 200
261// #define GKEYBOARD_DRIVER_LIST GKEYBOARDVMT_Win32, GKEYBOARDVMT_Win32
262// #define GKEYBOARD_LAYOUT_OFF FALSE
263// #define GKEYBOARD_LAYOUT_SCANCODE2_US FALSE
264//#define GINPUT_NEED_TOGGLE FALSE
265//#define GINPUT_NEED_DIAL FALSE
266
267
268///////////////////////////////////////////////////////////////////////////
269// GFILE //
270///////////////////////////////////////////////////////////////////////////
271#define GFX_USE_GFILE FALSE
272
273//#define GFILE_NEED_PRINTG FALSE
274//#define GFILE_NEED_SCANG FALSE
275//#define GFILE_NEED_STRINGS FALSE
276//#define GFILE_NEED_FILELISTS FALSE
277//#define GFILE_NEED_STDIO FALSE
278//#define GFILE_NEED_NOAUTOMOUNT FALSE
279//#define GFILE_NEED_NOAUTOSYNC FALSE
280
281//#define GFILE_NEED_MEMFS FALSE
282//#define GFILE_NEED_ROMFS FALSE
283//#define GFILE_NEED_RAMFS FALSE
284//#define GFILE_NEED_FATFS FALSE
285//#define GFILE_NEED_NATIVEFS FALSE
286//#define GFILE_NEED_CHBIOSFS FALSE
287
288//#define GFILE_ALLOW_FLOATS FALSE
289//#define GFILE_ALLOW_DEVICESPECIFIC FALSE
290//#define GFILE_MAX_GFILES 3
291
292///////////////////////////////////////////////////////////////////////////
293// GADC //
294///////////////////////////////////////////////////////////////////////////
295#define GFX_USE_GADC FALSE
296
297//#define GADC_MAX_LOWSPEED_DEVICES 4
298
299
300///////////////////////////////////////////////////////////////////////////
301// GAUDIO //
302///////////////////////////////////////////////////////////////////////////
303#define GFX_USE_GAUDIO FALSE
304// There seems to be a bug in the ugfx code, the wrong define is used
305// So define it in order to avoid warnings
306#define GFX_USE_GAUDIN GFX_USE_GAUDIO
307// #define GAUDIO_NEED_PLAY FALSE
308// #define GAUDIO_NEED_RECORD FALSE
309
310
311///////////////////////////////////////////////////////////////////////////
312// GMISC //
313///////////////////////////////////////////////////////////////////////////
314#define GFX_USE_GMISC FALSE
315
316//#define GMISC_NEED_ARRAYOPS FALSE
317//#define GMISC_NEED_FASTTRIG FALSE
318//#define GMISC_NEED_FIXEDTRIG FALSE
319//#define GMISC_NEED_INVSQRT FALSE
320// #define GMISC_INVSQRT_MIXED_ENDIAN FALSE
321// #define GMISC_INVSQRT_REAL_SLOW FALSE
322//#define GMISC_NEED_MATRIXFLOAT2D FALSE
323//#define GMISC_NEED_MATRIXFIXED2D FALSE
324
325#endif /* _GFXCONF_H */
diff --git a/quantum/visualizer/example_integration/lcd_backlight_hal.c b/quantum/visualizer/example_integration/lcd_backlight_hal.c
new file mode 100644
index 000000000..913131b16
--- /dev/null
+++ b/quantum/visualizer/example_integration/lcd_backlight_hal.c
@@ -0,0 +1,91 @@
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 "hal.h"
27
28#define RED_PIN 1
29#define GREEN_PIN 2
30#define BLUE_PIN 3
31#define CHANNEL_RED FTM0->CHANNEL[0]
32#define CHANNEL_GREEN FTM0->CHANNEL[1]
33#define CHANNEL_BLUE FTM0->CHANNEL[2]
34
35#define RGB_PORT PORTC
36#define RGB_PORT_GPIO GPIOC
37
38// Base FTM clock selection (72 MHz system clock)
39// @ 0xFFFF period, 72 MHz / (0xFFFF * 2) = Actual period
40// Higher pre-scalar will use the most power (also look the best)
41// Pre-scalar calculations
42// 0 - 72 MHz -> 549 Hz
43// 1 - 36 MHz -> 275 Hz
44// 2 - 18 MHz -> 137 Hz
45// 3 - 9 MHz -> 69 Hz (Slightly visible flicker)
46// 4 - 4 500 kHz -> 34 Hz (Visible flickering)
47// 5 - 2 250 kHz -> 17 Hz
48// 6 - 1 125 kHz -> 9 Hz
49// 7 - 562 500 Hz -> 4 Hz
50// Using a higher pre-scalar without flicker is possible but FTM0_MOD will need to be reduced
51// Which will reduce the brightness range
52#define PRESCALAR_DEFINE 0
53
54void lcd_backlight_hal_init(void) {
55 // Setup Backlight
56 SIM->SCGC6 |= SIM_SCGC6_FTM0;
57 FTM0->CNT = 0; // Reset counter
58
59 // PWM Period
60 // 16-bit maximum
61 FTM0->MOD = 0xFFFF;
62
63 // Set FTM to PWM output - Edge Aligned, Low-true pulses
64#define CNSC_MODE FTM_SC_CPWMS | FTM_SC_PS(4) | FTM_SC_CLKS(0)
65 CHANNEL_RED.CnSC = CNSC_MODE;
66 CHANNEL_GREEN.CnSC = CNSC_MODE;
67 CHANNEL_BLUE.CnSC = CNSC_MODE;
68
69 // System clock, /w prescalar setting
70 FTM0->SC = FTM_SC_CLKS(1) | FTM_SC_PS(PRESCALAR_DEFINE);
71
72 CHANNEL_RED.CnV = 0;
73 CHANNEL_GREEN.CnV = 0;
74 CHANNEL_BLUE.CnV = 0;
75
76 RGB_PORT_GPIO->PDDR |= (1 << RED_PIN);
77 RGB_PORT_GPIO->PDDR |= (1 << GREEN_PIN);
78 RGB_PORT_GPIO->PDDR |= (1 << BLUE_PIN);
79
80#define RGB_MODE PORTx_PCRn_SRE | PORTx_PCRn_DSE | PORTx_PCRn_MUX(4)
81 RGB_PORT->PCR[RED_PIN] = RGB_MODE;
82 RGB_PORT->PCR[GREEN_PIN] = RGB_MODE;
83 RGB_PORT->PCR[BLUE_PIN] = RGB_MODE;
84}
85
86void lcd_backlight_hal_color(uint16_t r, uint16_t g, uint16_t b) {
87 CHANNEL_RED.CnV = r;
88 CHANNEL_GREEN.CnV = g;
89 CHANNEL_BLUE.CnV = b;
90}
91
diff --git a/quantum/visualizer/example_integration/visualizer_user.c b/quantum/visualizer/example_integration/visualizer_user.c
new file mode 100644
index 000000000..fc09fe2ea
--- /dev/null
+++ b/quantum/visualizer/example_integration/visualizer_user.c
@@ -0,0 +1,121 @@
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// Currently we are assuming that both the backlight and LCD are enabled
26// But it's entirely possible to write a custom visualizer that use only
27// one of them
28#ifndef LCD_BACKLIGHT_ENABLE
29#error This visualizer needs that LCD backlight is enabled
30#endif
31
32#ifndef LCD_ENABLE
33#error This visualizer needs that LCD is enabled
34#endif
35
36#include "visualizer.h"
37
38static const char* welcome_text[] = {"TMK", "Infinity Ergodox"};
39
40// Just an example how to write custom keyframe functions, we could have moved
41// all this into the init function
42bool display_welcome(keyframe_animation_t* animation, visualizer_state_t* state) {
43 (void)animation;
44 // Read the uGFX documentation for information how to use the displays
45 // http://wiki.ugfx.org/index.php/Main_Page
46 gdispClear(White);
47 // You can use static variables for things that can't be found in the animation
48 // or state structs
49 gdispDrawString(0, 3, welcome_text[0], state->font_dejavusansbold12, Black);
50 gdispDrawString(0, 15, welcome_text[1], state->font_dejavusansbold12, Black);
51 // Always remember to flush the display
52 gdispFlush();
53 // you could set the backlight color as well, but we won't do it here, since
54 // it's part of the following animation
55 // lcd_backlight_color(hue, saturation, intensity);
56 // We don't need constant updates, just drawing the screen once is enough
57 return false;
58}
59
60// Feel free to modify the animations below, or even add new ones if needed
61
62// Don't worry, if the startup animation is long, you can use the keyboard like normal
63// during that time
64static keyframe_animation_t startup_animation = {
65 .num_frames = 4,
66 .loop = false,
67 .frame_lengths = {0, MS2ST(1000), MS2ST(5000), 0},
68 .frame_functions = {display_welcome, keyframe_animate_backlight_color, keyframe_no_operation, enable_visualization},
69};
70
71// The color animation animates the LCD color when you change layers
72static keyframe_animation_t color_animation = {
73 .num_frames = 2,
74 .loop = false,
75 // Note that there's a 200 ms no-operation frame,
76 // this prevents the color from changing when activating the layer
77 // momentarily
78 .frame_lengths = {MS2ST(200), MS2ST(500)},
79 .frame_functions = {keyframe_no_operation, keyframe_animate_backlight_color},
80};
81
82// The LCD animation alternates between the layer name display and a
83// bitmap that displays all active layers
84static keyframe_animation_t lcd_animation = {
85 .num_frames = 2,
86 .loop = true,
87 .frame_lengths = {MS2ST(2000), MS2ST(2000)},
88 .frame_functions = {keyframe_display_layer_text, keyframe_display_layer_bitmap},
89};
90
91void initialize_user_visualizer(visualizer_state_t* state) {
92 // The brightness will be dynamically adjustable in the future
93 // But for now, change it here.
94 lcd_backlight_brightness(0x50);
95 state->current_lcd_color = LCD_COLOR(0x00, 0x00, 0xFF);
96 state->target_lcd_color = LCD_COLOR(0x10, 0xFF, 0xFF);
97 start_keyframe_animation(&startup_animation);
98}
99
100void update_user_visualizer_state(visualizer_state_t* state) {
101 // Add more tests, change the colors and layer texts here
102 // Usually you want to check the high bits (higher layers first)
103 // because that's the order layers are processed for keypresses
104 // You can for check for example:
105 // state->status.layer
106 // state->status.default_layer
107 // state->status.leds (see led.h for available statuses)
108 if (state->status.layer & 0x2) {
109 state->target_lcd_color = LCD_COLOR(0xA0, 0xB0, 0xFF);
110 state->layer_text = "Layer 2";
111 }
112 else {
113 state->target_lcd_color = LCD_COLOR(0x50, 0xB0, 0xFF);
114 state->layer_text = "Layer 1";
115 }
116 // You can also stop existing animations, and start your custom ones here
117 // remember that you should normally have only one animation for the LCD
118 // and one for the background. But you can also combine them if you want.
119 start_keyframe_animation(&lcd_animation);
120 start_keyframe_animation(&color_animation);
121}
diff --git a/quantum/visualizer/lcd_backlight.c b/quantum/visualizer/lcd_backlight.c
new file mode 100644
index 000000000..70187d1e0
--- /dev/null
+++ b/quantum/visualizer/lcd_backlight.c
@@ -0,0 +1,85 @@
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 = 0x00;
29static uint8_t current_saturation = 0x00;
30static uint8_t current_intensity = 0xFF;
31static uint8_t current_brightness = 0x7F;
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}
diff --git a/quantum/visualizer/lcd_backlight.h b/quantum/visualizer/lcd_backlight.h
new file mode 100644
index 000000000..dd3e37a06
--- /dev/null
+++ b/quantum/visualizer/lcd_backlight.h
@@ -0,0 +1,42 @@
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
35void lcd_backlight_init(void);
36void lcd_backlight_color(uint8_t hue, uint8_t saturation, uint8_t intensity);
37void lcd_backlight_brightness(uint8_t b);
38
39void lcd_backlight_hal_init(void);
40void lcd_backlight_hal_color(uint16_t r, uint16_t g, uint16_t b);
41
42#endif /* LCD_BACKLIGHT_H_ */
diff --git a/quantum/visualizer/led_test.c b/quantum/visualizer/led_test.c
new file mode 100644
index 000000000..c2ea30b55
--- /dev/null
+++ b/quantum/visualizer/led_test.c
@@ -0,0 +1,170 @@
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 "led_test.h"
25#include "gfx.h"
26#include "math.h"
27
28#define CROSSFADE_TIME 1000
29#define GRADIENT_TIME 3000
30
31keyframe_animation_t led_test_animation = {
32 .num_frames = 14,
33 .loop = true,
34 .frame_lengths = {
35 gfxMillisecondsToTicks(1000), // fade in
36 gfxMillisecondsToTicks(1000), // no op (leds on)
37 gfxMillisecondsToTicks(1000), // fade out
38 gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
39 gfxMillisecondsToTicks(GRADIENT_TIME), // left to rigt (outside in)
40 gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
41 gfxMillisecondsToTicks(GRADIENT_TIME), // top_to_bottom
42 0, // mirror leds
43 gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
44 gfxMillisecondsToTicks(GRADIENT_TIME), // left_to_right (mirrored, so inside out)
45 gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
46 gfxMillisecondsToTicks(GRADIENT_TIME), // top_to_bottom
47 0, // normal leds
48 gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
49
50 },
51 .frame_functions = {
52 keyframe_fade_in_all_leds,
53 keyframe_no_operation,
54 keyframe_fade_out_all_leds,
55 keyframe_led_crossfade,
56 keyframe_led_left_to_right_gradient,
57 keyframe_led_crossfade,
58 keyframe_led_top_to_bottom_gradient,
59 keyframe_mirror_led_orientation,
60 keyframe_led_crossfade,
61 keyframe_led_left_to_right_gradient,
62 keyframe_led_crossfade,
63 keyframe_led_top_to_bottom_gradient,
64 keyframe_normal_led_orientation,
65 keyframe_led_crossfade,
66 },
67};
68
69static uint8_t fade_led_color(keyframe_animation_t* animation, int from, int to) {
70 int frame_length = animation->frame_lengths[animation->current_frame];
71 int current_pos = frame_length - animation->time_left_in_frame;
72 int delta = to - from;
73 int luma = (delta * current_pos) / frame_length;
74 luma += from;
75 return luma;
76}
77
78static void keyframe_fade_all_leds_from_to(keyframe_animation_t* animation, uint8_t from, uint8_t to) {
79 uint8_t luma = fade_led_color(animation, from, to);
80 color_t color = LUMA2COLOR(luma);
81 gdispGClear(LED_DISPLAY, color);
82}
83
84// TODO: Should be customizable per keyboard
85#define NUM_ROWS 7
86#define NUM_COLS 7
87
88static uint8_t crossfade_start_frame[NUM_ROWS][NUM_COLS];
89static uint8_t crossfade_end_frame[NUM_ROWS][NUM_COLS];
90
91static uint8_t compute_gradient_color(float t, float index, float num) {
92 const float two_pi = 2.0f * PI;
93 float normalized_index = (1.0f - index / (num - 1)) * two_pi;
94 float x = t * two_pi + normalized_index;
95 float v = 0.5 * (cosf(x) + 1.0f);
96 return (uint8_t)(255.0f * v);
97}
98
99bool keyframe_fade_in_all_leds(keyframe_animation_t* animation, visualizer_state_t* state) {
100 (void)state;
101 keyframe_fade_all_leds_from_to(animation, 0, 255);
102 return true;
103}
104
105bool keyframe_fade_out_all_leds(keyframe_animation_t* animation, visualizer_state_t* state) {
106 (void)state;
107 keyframe_fade_all_leds_from_to(animation, 255, 0);
108 return true;
109}
110
111bool keyframe_led_left_to_right_gradient(keyframe_animation_t* animation, visualizer_state_t* state) {
112 (void)state;
113 float frame_length = animation->frame_lengths[animation->current_frame];
114 float current_pos = frame_length - animation->time_left_in_frame;
115 float t = current_pos / frame_length;
116 for (int i=0; i< NUM_COLS; i++) {
117 uint8_t color = compute_gradient_color(t, i, NUM_COLS);
118 gdispGDrawLine(LED_DISPLAY, i, 0, i, NUM_ROWS - 1, LUMA2COLOR(color));
119 }
120 return true;
121}
122
123bool keyframe_led_top_to_bottom_gradient(keyframe_animation_t* animation, visualizer_state_t* state) {
124 (void)state;
125 float frame_length = animation->frame_lengths[animation->current_frame];
126 float current_pos = frame_length - animation->time_left_in_frame;
127 float t = current_pos / frame_length;
128 for (int i=0; i< NUM_ROWS; i++) {
129 uint8_t color = compute_gradient_color(t, i, NUM_ROWS);
130 gdispGDrawLine(LED_DISPLAY, 0, i, NUM_COLS - 1, i, LUMA2COLOR(color));
131 }
132 return true;
133}
134
135static void copy_current_led_state(uint8_t* dest) {
136 for (int i=0;i<NUM_ROWS;i++) {
137 for (int j=0;j<NUM_COLS;j++) {
138 dest[i*NUM_COLS + j] = gdispGGetPixelColor(LED_DISPLAY, j, i);
139 }
140 }
141}
142bool keyframe_led_crossfade(keyframe_animation_t* animation, visualizer_state_t* state) {
143 (void)state;
144 if (animation->first_update_of_frame) {
145 copy_current_led_state(&crossfade_start_frame[0][0]);
146 run_next_keyframe(animation, state);
147 copy_current_led_state(&crossfade_end_frame[0][0]);
148 }
149 for (int i=0;i<NUM_ROWS;i++) {
150 for (int j=0;j<NUM_COLS;j++) {
151 color_t color = LUMA2COLOR(fade_led_color(animation, crossfade_start_frame[i][j], crossfade_end_frame[i][j]));
152 gdispGDrawPixel(LED_DISPLAY, j, i, color);
153 }
154 }
155 return true;
156}
157
158bool keyframe_mirror_led_orientation(keyframe_animation_t* animation, visualizer_state_t* state) {
159 (void)state;
160 (void)animation;
161 gdispGSetOrientation(LED_DISPLAY, GDISP_ROTATE_180);
162 return false;
163}
164
165bool keyframe_normal_led_orientation(keyframe_animation_t* animation, visualizer_state_t* state) {
166 (void)state;
167 (void)animation;
168 gdispGSetOrientation(LED_DISPLAY, GDISP_ROTATE_0);
169 return false;
170}
diff --git a/quantum/visualizer/led_test.h b/quantum/visualizer/led_test.h
new file mode 100644
index 000000000..5e2325753
--- /dev/null
+++ b/quantum/visualizer/led_test.h
@@ -0,0 +1,41 @@
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 TMK_VISUALIZER_LED_TEST_H_
26#define TMK_VISUALIZER_LED_TEST_H_
27
28#include "visualizer.h"
29
30bool keyframe_fade_in_all_leds(keyframe_animation_t* animation, visualizer_state_t* state);
31bool keyframe_fade_out_all_leds(keyframe_animation_t* animation, visualizer_state_t* state);
32bool keyframe_led_left_to_right_gradient(keyframe_animation_t* animation, visualizer_state_t* state);
33bool keyframe_led_top_to_bottom_gradient(keyframe_animation_t* animation, visualizer_state_t* state);
34bool keyframe_led_crossfade(keyframe_animation_t* animation, visualizer_state_t* state);
35bool keyframe_mirror_led_orientation(keyframe_animation_t* animation, visualizer_state_t* state);
36bool keyframe_normal_led_orientation(keyframe_animation_t* animation, visualizer_state_t* state);
37
38extern keyframe_animation_t led_test_animation;
39
40
41#endif /* TMK_VISUALIZER_LED_TEST_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/visualizer.c b/quantum/visualizer/visualizer.c
new file mode 100644
index 000000000..c24073405
--- /dev/null
+++ b/quantum/visualizer/visualizer.c
@@ -0,0 +1,549 @@
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 "visualizer.h"
26#include "config.h"
27#include <string.h>
28#ifdef PROTOCOL_CHIBIOS
29#include "ch.h"
30#endif
31
32#ifdef LCD_ENABLE
33#include "gfx.h"
34#endif
35
36#ifdef LCD_BACKLIGHT_ENABLE
37#include "lcd_backlight.h"
38#endif
39
40//#define DEBUG_VISUALIZER
41
42#ifdef DEBUG_VISUALIZER
43#include "debug.h"
44#else
45#include "nodebug.h"
46#endif
47
48#ifdef USE_SERIAL_LINK
49#include "serial_link/protocol/transport.h"
50#include "serial_link/system/serial_link.h"
51#endif
52
53// Define this in config.h
54#ifndef VISUALIZER_THREAD_PRIORITY
55#define "Visualizer thread priority not defined"
56#endif
57
58
59static visualizer_keyboard_status_t current_status = {
60 .layer = 0xFFFFFFFF,
61 .default_layer = 0xFFFFFFFF,
62 .leds = 0xFFFFFFFF,
63 .suspended = false,
64};
65
66static bool same_status(visualizer_keyboard_status_t* status1, visualizer_keyboard_status_t* status2) {
67 return status1->layer == status2->layer &&
68 status1->default_layer == status2->default_layer &&
69 status1->leds == status2->leds &&
70 status1->suspended == status2->suspended;
71}
72
73static bool visualizer_enabled = false;
74
75#define MAX_SIMULTANEOUS_ANIMATIONS 4
76static keyframe_animation_t* animations[MAX_SIMULTANEOUS_ANIMATIONS] = {};
77
78#ifdef USE_SERIAL_LINK
79MASTER_TO_ALL_SLAVES_OBJECT(current_status, visualizer_keyboard_status_t);
80
81static remote_object_t* remote_objects[] = {
82 REMOTE_OBJECT(current_status),
83};
84
85#endif
86
87GDisplay* LCD_DISPLAY = 0;
88GDisplay* LED_DISPLAY = 0;
89
90__attribute__((weak))
91GDisplay* get_lcd_display(void) {
92 return gdispGetDisplay(0);
93}
94
95__attribute__((weak))
96GDisplay* get_led_display(void) {
97 return gdispGetDisplay(1);
98}
99
100void start_keyframe_animation(keyframe_animation_t* animation) {
101 animation->current_frame = -1;
102 animation->time_left_in_frame = 0;
103 animation->need_update = true;
104 int free_index = -1;
105 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
106 if (animations[i] == animation) {
107 return;
108 }
109 if (free_index == -1 && animations[i] == NULL) {
110 free_index=i;
111 }
112 }
113 if (free_index!=-1) {
114 animations[free_index] = animation;
115 }
116}
117
118void stop_keyframe_animation(keyframe_animation_t* animation) {
119 animation->current_frame = animation->num_frames;
120 animation->time_left_in_frame = 0;
121 animation->need_update = true;
122 animation->first_update_of_frame = false;
123 animation->last_update_of_frame = false;
124 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
125 if (animations[i] == animation) {
126 animations[i] = NULL;
127 return;
128 }
129 }
130}
131
132void stop_all_keyframe_animations(void) {
133 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
134 if (animations[i]) {
135 animations[i]->current_frame = animations[i]->num_frames;
136 animations[i]->time_left_in_frame = 0;
137 animations[i]->need_update = true;
138 animations[i]->first_update_of_frame = false;
139 animations[i]->last_update_of_frame = false;
140 animations[i] = NULL;
141 }
142 }
143}
144
145static bool update_keyframe_animation(keyframe_animation_t* animation, visualizer_state_t* state, systemticks_t delta, systemticks_t* sleep_time) {
146 // TODO: Clean up this messy code
147 dprintf("Animation frame%d, left %d, delta %d\n", animation->current_frame,
148 animation->time_left_in_frame, delta);
149 if (animation->current_frame == animation->num_frames) {
150 animation->need_update = false;
151 return false;
152 }
153 if (animation->current_frame == -1) {
154 animation->current_frame = 0;
155 animation->time_left_in_frame = animation->frame_lengths[0];
156 animation->need_update = true;
157 animation->first_update_of_frame = true;
158 } else {
159 animation->time_left_in_frame -= delta;
160 while (animation->time_left_in_frame <= 0) {
161 int left = animation->time_left_in_frame;
162 if (animation->need_update) {
163 animation->time_left_in_frame = 0;
164 animation->last_update_of_frame = true;
165 (*animation->frame_functions[animation->current_frame])(animation, state);
166 animation->last_update_of_frame = false;
167 }
168 animation->current_frame++;
169 animation->need_update = true;
170 animation->first_update_of_frame = true;
171 if (animation->current_frame == animation->num_frames) {
172 if (animation->loop) {
173 animation->current_frame = 0;
174 }
175 else {
176 stop_keyframe_animation(animation);
177 return false;
178 }
179 }
180 delta = -left;
181 animation->time_left_in_frame = animation->frame_lengths[animation->current_frame];
182 animation->time_left_in_frame -= delta;
183 }
184 }
185 if (animation->need_update) {
186 animation->need_update = (*animation->frame_functions[animation->current_frame])(animation, state);
187 animation->first_update_of_frame = false;
188 }
189
190 systemticks_t wanted_sleep = animation->need_update ? gfxMillisecondsToTicks(10) : (unsigned)animation->time_left_in_frame;
191 if (wanted_sleep < *sleep_time) {
192 *sleep_time = wanted_sleep;
193 }
194
195 return true;
196}
197
198void run_next_keyframe(keyframe_animation_t* animation, visualizer_state_t* state) {
199 int next_frame = animation->current_frame + 1;
200 if (next_frame == animation->num_frames) {
201 next_frame = 0;
202 }
203 keyframe_animation_t temp_animation = *animation;
204 temp_animation.current_frame = next_frame;
205 temp_animation.time_left_in_frame = animation->frame_lengths[next_frame];
206 temp_animation.first_update_of_frame = true;
207 temp_animation.last_update_of_frame = false;
208 temp_animation.need_update = false;
209 visualizer_state_t temp_state = *state;
210 (*temp_animation.frame_functions[next_frame])(&temp_animation, &temp_state);
211}
212
213bool keyframe_no_operation(keyframe_animation_t* animation, visualizer_state_t* state) {
214 (void)animation;
215 (void)state;
216 return false;
217}
218
219#ifdef LCD_BACKLIGHT_ENABLE
220bool keyframe_animate_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state) {
221 int frame_length = animation->frame_lengths[animation->current_frame];
222 int current_pos = frame_length - animation->time_left_in_frame;
223 uint8_t t_h = LCD_HUE(state->target_lcd_color);
224 uint8_t t_s = LCD_SAT(state->target_lcd_color);
225 uint8_t t_i = LCD_INT(state->target_lcd_color);
226 uint8_t p_h = LCD_HUE(state->prev_lcd_color);
227 uint8_t p_s = LCD_SAT(state->prev_lcd_color);
228 uint8_t p_i = LCD_INT(state->prev_lcd_color);
229
230 uint8_t d_h1 = t_h - p_h; //Modulo arithmetic since we want to wrap around
231 int d_h2 = t_h - p_h;
232 // Chose the shortest way around
233 int d_h = abs(d_h2) < d_h1 ? d_h2 : d_h1;
234 int d_s = t_s - p_s;
235 int d_i = t_i - p_i;
236
237 int hue = (d_h * current_pos) / frame_length;
238 int sat = (d_s * current_pos) / frame_length;
239 int intensity = (d_i * current_pos) / frame_length;
240 //dprintf("%X -> %X = %X\n", p_h, t_h, hue);
241 hue += p_h;
242 sat += p_s;
243 intensity += p_i;
244 state->current_lcd_color = LCD_COLOR(hue, sat, intensity);
245 lcd_backlight_color(
246 LCD_HUE(state->current_lcd_color),
247 LCD_SAT(state->current_lcd_color),
248 LCD_INT(state->current_lcd_color));
249
250 return true;
251}
252
253bool keyframe_set_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state) {
254 (void)animation;
255 state->prev_lcd_color = state->target_lcd_color;
256 state->current_lcd_color = state->target_lcd_color;
257 lcd_backlight_color(
258 LCD_HUE(state->current_lcd_color),
259 LCD_SAT(state->current_lcd_color),
260 LCD_INT(state->current_lcd_color));
261 return false;
262}
263#endif // LCD_BACKLIGHT_ENABLE
264
265#ifdef LCD_ENABLE
266bool keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state) {
267 (void)animation;
268 gdispClear(White);
269 gdispDrawString(0, 10, state->layer_text, state->font_dejavusansbold12, Black);
270 gdispFlush();
271 return false;
272}
273
274static void format_layer_bitmap_string(uint16_t default_layer, uint16_t layer, char* buffer) {
275 for (int i=0; i<16;i++)
276 {
277 uint32_t mask = (1u << i);
278 if (default_layer & mask) {
279 if (layer & mask) {
280 *buffer = 'B';
281 } else {
282 *buffer = 'D';
283 }
284 } else if (layer & mask) {
285 *buffer = '1';
286 } else {
287 *buffer = '0';
288 }
289 ++buffer;
290
291 if (i==3 || i==7 || i==11) {
292 *buffer = ' ';
293 ++buffer;
294 }
295 }
296 *buffer = 0;
297}
298
299bool keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state) {
300 (void)animation;
301 const char* layer_help = "1=On D=Default B=Both";
302 char layer_buffer[16 + 4]; // 3 spaces and one null terminator
303 gdispClear(White);
304 gdispDrawString(0, 0, layer_help, state->font_fixed5x8, Black);
305 format_layer_bitmap_string(state->status.default_layer, state->status.layer, layer_buffer);
306 gdispDrawString(0, 10, layer_buffer, state->font_fixed5x8, Black);
307 format_layer_bitmap_string(state->status.default_layer >> 16, state->status.layer >> 16, layer_buffer);
308 gdispDrawString(0, 20, layer_buffer, state->font_fixed5x8, Black);
309 gdispFlush();
310 return false;
311}
312#endif // LCD_ENABLE
313
314bool keyframe_disable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state) {
315 (void)animation;
316 (void)state;
317#ifdef LCD_ENABLE
318 gdispSetPowerMode(powerOff);
319#endif
320#ifdef LCD_BACKLIGHT_ENABLE
321 lcd_backlight_hal_color(0, 0, 0);
322#endif
323 return false;
324}
325
326bool keyframe_enable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state) {
327 (void)animation;
328 (void)state;
329#ifdef LCD_ENABLE
330 gdispSetPowerMode(powerOn);
331#endif
332 return false;
333}
334
335bool enable_visualization(keyframe_animation_t* animation, visualizer_state_t* state) {
336 (void)animation;
337 (void)state;
338 dprint("User visualizer inited\n");
339 visualizer_enabled = true;
340 return false;
341}
342
343// TODO: Optimize the stack size, this is probably way too big
344static DECLARE_THREAD_STACK(visualizerThreadStack, 1024);
345static DECLARE_THREAD_FUNCTION(visualizerThread, arg) {
346 (void)arg;
347
348 GListener event_listener;
349 geventListenerInit(&event_listener);
350 geventAttachSource(&event_listener, (GSourceHandle)&current_status, 0);
351
352 visualizer_keyboard_status_t initial_status = {
353 .default_layer = 0xFFFFFFFF,
354 .layer = 0xFFFFFFFF,
355 .leds = 0xFFFFFFFF,
356 .suspended = false,
357 };
358
359 visualizer_state_t state = {
360 .status = initial_status,
361 .current_lcd_color = 0,
362#ifdef LCD_ENABLE
363 .font_fixed5x8 = gdispOpenFont("fixed_5x8"),
364 .font_dejavusansbold12 = gdispOpenFont("DejaVuSansBold12")
365#endif
366 };
367 initialize_user_visualizer(&state);
368 state.prev_lcd_color = state.current_lcd_color;
369
370#ifdef LCD_BACKLIGHT_ENABLE
371 lcd_backlight_color(
372 LCD_HUE(state.current_lcd_color),
373 LCD_SAT(state.current_lcd_color),
374 LCD_INT(state.current_lcd_color));
375#endif
376
377 systemticks_t sleep_time = TIME_INFINITE;
378 systemticks_t current_time = gfxSystemTicks();
379
380 while(true) {
381 systemticks_t new_time = gfxSystemTicks();
382 systemticks_t delta = new_time - current_time;
383 current_time = new_time;
384 bool enabled = visualizer_enabled;
385 if (!same_status(&state.status, &current_status)) {
386 if (visualizer_enabled) {
387 if (current_status.suspended) {
388 stop_all_keyframe_animations();
389 visualizer_enabled = false;
390 state.status = current_status;
391 user_visualizer_suspend(&state);
392 }
393 else {
394 state.status = current_status;
395 update_user_visualizer_state(&state);
396 }
397 state.prev_lcd_color = state.current_lcd_color;
398 }
399 }
400 if (!enabled && state.status.suspended && current_status.suspended == false) {
401 // Setting the status to the initial status will force an update
402 // when the visualizer is enabled again
403 state.status = initial_status;
404 state.status.suspended = false;
405 stop_all_keyframe_animations();
406 user_visualizer_resume(&state);
407 state.prev_lcd_color = state.current_lcd_color;
408 }
409 sleep_time = TIME_INFINITE;
410 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
411 if (animations[i]) {
412 update_keyframe_animation(animations[i], &state, delta, &sleep_time);
413 }
414 }
415#ifdef LED_ENABLE
416 gdispGFlush(LED_DISPLAY);
417#endif
418
419#ifdef EMULATOR
420 draw_emulator();
421#endif
422 // The animation can enable the visualizer
423 // And we might need to update the state when that happens
424 // so don't sleep
425 if (enabled != visualizer_enabled) {
426 sleep_time = 0;
427 }
428
429 systemticks_t after_update = gfxSystemTicks();
430 unsigned update_delta = after_update - current_time;
431 if (sleep_time != TIME_INFINITE) {
432 if (sleep_time > update_delta) {
433 sleep_time -= update_delta;
434 }
435 else {
436 sleep_time = 0;
437 }
438 }
439 dprintf("Update took %d, last delta %d, sleep_time %d\n", update_delta, delta, sleep_time);
440#ifdef PROTOCOL_CHIBIOS
441 // The gEventWait function really takes milliseconds, even if the documentation says ticks.
442 // Unfortunately there's no generic ugfx conversion from system time to milliseconds,
443 // so let's do it in a platform dependent way.
444
445 // On windows the system ticks is the same as milliseconds anyway
446 if (sleep_time != TIME_INFINITE) {
447 sleep_time = ST2MS(sleep_time);
448 }
449#endif
450 geventEventWait(&event_listener, sleep_time);
451 }
452#ifdef LCD_ENABLE
453 gdispCloseFont(state.font_fixed5x8);
454 gdispCloseFont(state.font_dejavusansbold12);
455#endif
456
457 return 0;
458}
459
460void visualizer_init(void) {
461#ifdef LCD_ENABLE
462 gfxInit();
463#endif
464
465#ifdef LCD_BACKLIGHT_ENABLE
466 lcd_backlight_init();
467#endif
468
469#ifdef USE_SERIAL_LINK
470 add_remote_objects(remote_objects, sizeof(remote_objects) / sizeof(remote_object_t*) );
471#endif
472
473#ifdef LCD_ENABLE
474 LCD_DISPLAY = get_lcd_display();
475#endif
476#ifdef LED_ENABLE
477 LED_DISPLAY = get_led_display();
478#endif
479
480 // We are using a low priority thread, the idea is to have it run only
481 // when the main thread is sleeping during the matrix scanning
482 gfxThreadCreate(visualizerThreadStack, sizeof(visualizerThreadStack),
483 VISUALIZER_THREAD_PRIORITY, visualizerThread, NULL);
484}
485
486void update_status(bool changed) {
487 if (changed) {
488 GSourceListener* listener = geventGetSourceListener((GSourceHandle)&current_status, NULL);
489 if (listener) {
490 geventSendEvent(listener);
491 }
492 }
493#ifdef USE_SERIAL_LINK
494 static systime_t last_update = 0;
495 systime_t current_update = chVTGetSystemTimeX();
496 systime_t delta = current_update - last_update;
497 if (changed || delta > MS2ST(10)) {
498 last_update = current_update;
499 visualizer_keyboard_status_t* r = begin_write_current_status();
500 *r = current_status;
501 end_write_current_status();
502 }
503#endif
504}
505
506void visualizer_update(uint32_t default_state, uint32_t state, uint32_t leds) {
507 // Note that there's a small race condition here, the thread could read
508 // a state where one of these are set but not the other. But this should
509 // not really matter as it will be fixed during the next loop step.
510 // Alternatively a mutex could be used instead of the volatile variables
511
512 bool changed = false;
513#ifdef USE_SERIAL_LINK
514 if (is_serial_link_connected ()) {
515 visualizer_keyboard_status_t* new_status = read_current_status();
516 if (new_status) {
517 if (!same_status(&current_status, new_status)) {
518 changed = true;
519 current_status = *new_status;
520 }
521 }
522 }
523 else {
524#else
525 {
526#endif
527 visualizer_keyboard_status_t new_status = {
528 .layer = state,
529 .default_layer = default_state,
530 .leds = leds,
531 .suspended = current_status.suspended,
532 };
533 if (!same_status(&current_status, &new_status)) {
534 changed = true;
535 current_status = new_status;
536 }
537 }
538 update_status(changed);
539}
540
541void visualizer_suspend(void) {
542 current_status.suspended = true;
543 update_status(true);
544}
545
546void visualizer_resume(void) {
547 current_status.suspended = false;
548 update_status(true);
549}
diff --git a/quantum/visualizer/visualizer.h b/quantum/visualizer/visualizer.h
new file mode 100644
index 000000000..45cfa9aa9
--- /dev/null
+++ b/quantum/visualizer/visualizer.h
@@ -0,0 +1,149 @@
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#ifdef LCD_ENABLE
32#include "gfx.h"
33#endif
34
35#ifdef LCD_BACKLIGHT_ENABLE
36#include "lcd_backlight.h"
37#endif
38
39// This need to be called once at the start
40void visualizer_init(void);
41// This should be called at every matrix scan
42void visualizer_update(uint32_t default_state, uint32_t state, uint32_t leds);
43// This should be called when the keyboard goes to suspend state
44void visualizer_suspend(void);
45// This should be called when the keyboard wakes up from suspend state
46void visualizer_resume(void);
47
48// These functions are week, so they can be overridden by the keyboard
49// if needed
50GDisplay* get_lcd_display(void);
51GDisplay* get_led_display(void);
52
53// For emulator builds, this function need to be implemented
54#ifdef EMULATOR
55void draw_emulator(void);
56#endif
57
58// If you need support for more than 16 keyframes per animation, you can change this
59#define MAX_VISUALIZER_KEY_FRAMES 16
60
61struct keyframe_animation_t;
62
63typedef struct {
64 uint32_t layer;
65 uint32_t default_layer;
66 uint32_t leds; // See led.h for available statuses
67 bool suspended;
68} visualizer_keyboard_status_t;
69
70// The state struct is used by the various keyframe functions
71// It's also used for setting the LCD color and layer text
72// from the user customized code
73typedef struct visualizer_state_t {
74 // The user code should primarily be modifying these
75 uint32_t target_lcd_color;
76 const char* layer_text;
77
78 // The user visualizer(and animation functions) can read these
79 visualizer_keyboard_status_t status;
80
81 // These are used by the animation functions
82 uint32_t current_lcd_color;
83 uint32_t prev_lcd_color;
84#ifdef LCD_ENABLE
85 font_t font_fixed5x8;
86 font_t font_dejavusansbold12;
87#endif
88} visualizer_state_t;
89
90// Any custom keyframe function should have this signature
91// return true to get continuous updates, otherwise you will only get one
92// update per frame
93typedef bool (*frame_func)(struct keyframe_animation_t*, visualizer_state_t*);
94
95// Represents a keyframe animation, so fields are internal to the system
96// while others are meant to be initialized by the user code
97typedef struct keyframe_animation_t {
98 // These should be initialized
99 int num_frames;
100 bool loop;
101 int frame_lengths[MAX_VISUALIZER_KEY_FRAMES];
102 frame_func frame_functions[MAX_VISUALIZER_KEY_FRAMES];
103
104 // Used internally by the system, and can also be read by
105 // keyframe update functions
106 int current_frame;
107 int time_left_in_frame;
108 bool first_update_of_frame;
109 bool last_update_of_frame;
110 bool need_update;
111
112} keyframe_animation_t;
113
114extern GDisplay* LCD_DISPLAY;
115extern GDisplay* LED_DISPLAY;
116
117void start_keyframe_animation(keyframe_animation_t* animation);
118void stop_keyframe_animation(keyframe_animation_t* animation);
119// This runs the next keyframe, but does not update the animation state
120// Useful for crossfades for example
121void run_next_keyframe(keyframe_animation_t* animation, visualizer_state_t* state);
122
123// Some predefined keyframe functions that can be used by the user code
124// Does nothing, useful for adding delays
125bool keyframe_no_operation(keyframe_animation_t* animation, visualizer_state_t* state);
126// Animates the LCD backlight color between the current color and the target color (of the state)
127bool keyframe_animate_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state);
128// Sets the backlight color to the target color
129bool keyframe_set_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state);
130// Displays the layer text centered vertically on the screen
131bool keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state);
132// Displays a bitmap (0/1) of all the currently active layers
133bool keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state);
134
135bool keyframe_disable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state);
136bool keyframe_enable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state);
137
138// Call this once, when the initial animation has finished, alternatively you can call it
139// directly from the initalize_user_visualizer function (the animation can be null)
140bool enable_visualization(keyframe_animation_t* animation, visualizer_state_t* state);
141
142// These functions have to be implemented by the user
143void initialize_user_visualizer(visualizer_state_t* state);
144void update_user_visualizer_state(visualizer_state_t* state);
145void user_visualizer_suspend(visualizer_state_t* state);
146void user_visualizer_resume(visualizer_state_t* state);
147
148
149#endif /* VISUALIZER_H */
diff --git a/quantum/visualizer/visualizer.mk b/quantum/visualizer/visualizer.mk
new file mode 100644
index 000000000..56525ffd9
--- /dev/null
+++ b/quantum/visualizer/visualizer.mk
@@ -0,0 +1,61 @@
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
23GFXLIB = $(VISUALIZER_DIR)/ugfx
24SRC += $(VISUALIZER_DIR)/visualizer.c
25UINCDIR += $(GFXINC) $(VISUALIZER_DIR)
26
27ifdef LCD_ENABLE
28UDEFS += -DLCD_ENABLE
29ULIBS += -lm
30USE_UGFX = yes
31endif
32
33ifdef LCD_BACKLIGHT_ENABLE
34SRC += $(VISUALIZER_DIR)/lcd_backlight.c
35ifndef EMULATOR
36SRC += lcd_backlight_hal.c
37endif
38UDEFS += -DLCD_BACKLIGHT_ENABLE
39endif
40
41ifdef LED_ENABLE
42SRC += $(VISUALIZER_DIR)/led_test.c
43UDEFS += -DLED_ENABLE
44USE_UGFX = yes
45endif
46
47ifdef USE_UGFX
48include $(GFXLIB)/gfx.mk
49SRC += $(GFXSRC)
50UDEFS += $(patsubst %,-D%,$(patsubst -D%,%,$(GFXDEFS)))
51ULIBS += $(patsubst %,-l%,$(patsubst -l%,%,$(GFXLIBS)))
52endif
53
54ifndef VISUALIZER_USER
55VISUALIZER_USER = visualizer_user.c
56endif
57SRC += $(VISUALIZER_USER)
58
59ifdef EMULATOR
60UINCDIR += $(TMK_DIR)/common
61endif \ No newline at end of file