aboutsummaryrefslogtreecommitdiff
path: root/quantum/visualizer
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/visualizer')
-rw-r--r--quantum/visualizer/.gitmodules3
-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/readme.md18
m---------quantum/visualizer/ugfx0
-rw-r--r--quantum/visualizer/visualizer.c481
-rw-r--r--quantum/visualizer/visualizer.h131
-rw-r--r--quantum/visualizer/visualizer.mk41
13 files changed, 1403 insertions, 0 deletions
diff --git a/quantum/visualizer/.gitmodules b/quantum/visualizer/.gitmodules
new file mode 100644
index 000000000..b320458c0
--- /dev/null
+++ b/quantum/visualizer/.gitmodules
@@ -0,0 +1,3 @@
1[submodule "ugfx"]
2 path = ugfx
3 url = https://bitbucket.org/fredizzimo/ugfx.git
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/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/ugfx b/quantum/visualizer/ugfx
new file mode 160000
Subproject e221a690616e20f87e0b0088baffdbd5427be86
diff --git a/quantum/visualizer/visualizer.c b/quantum/visualizer/visualizer.c
new file mode 100644
index 000000000..605be3059
--- /dev/null
+++ b/quantum/visualizer/visualizer.c
@@ -0,0 +1,481 @@
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 "ch.h"
27#include "config.h"
28#include <string.h>
29
30#ifdef LCD_ENABLE
31#include "gfx.h"
32#endif
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 USE_SERIAL_LINK
47#include "serial_link/protocol/transport.h"
48#include "serial_link/system/serial_link.h"
49#endif
50
51// Define this in config.h
52#ifndef VISUALIZER_THREAD_PRIORITY
53#define "Visualizer thread priority not defined"
54#endif
55
56
57static visualizer_keyboard_status_t current_status = {
58 .layer = 0xFFFFFFFF,
59 .default_layer = 0xFFFFFFFF,
60 .leds = 0xFFFFFFFF,
61 .suspended = false,
62};
63
64static bool same_status(visualizer_keyboard_status_t* status1, visualizer_keyboard_status_t* status2) {
65 return status1->layer == status2->layer &&
66 status1->default_layer == status2->default_layer &&
67 status1->leds == status2->leds &&
68 status1->suspended == status2->suspended;
69}
70
71static event_source_t layer_changed_event;
72static bool visualizer_enabled = false;
73
74#define MAX_SIMULTANEOUS_ANIMATIONS 4
75static keyframe_animation_t* animations[MAX_SIMULTANEOUS_ANIMATIONS] = {};
76
77#ifdef USE_SERIAL_LINK
78MASTER_TO_ALL_SLAVES_OBJECT(current_status, visualizer_keyboard_status_t);
79
80static remote_object_t* remote_objects[] = {
81 REMOTE_OBJECT(current_status),
82};
83
84#endif
85
86
87void start_keyframe_animation(keyframe_animation_t* animation) {
88 animation->current_frame = -1;
89 animation->time_left_in_frame = 0;
90 animation->need_update = true;
91 int free_index = -1;
92 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
93 if (animations[i] == animation) {
94 return;
95 }
96 if (free_index == -1 && animations[i] == NULL) {
97 free_index=i;
98 }
99 }
100 if (free_index!=-1) {
101 animations[free_index] = animation;
102 }
103}
104
105void stop_keyframe_animation(keyframe_animation_t* animation) {
106 animation->current_frame = animation->num_frames;
107 animation->time_left_in_frame = 0;
108 animation->need_update = true;
109 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
110 if (animations[i] == animation) {
111 animations[i] = NULL;
112 return;
113 }
114 }
115}
116
117void stop_all_keyframe_animations(void) {
118 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
119 if (animations[i]) {
120 animations[i]->current_frame = animations[i]->num_frames;
121 animations[i]->time_left_in_frame = 0;
122 animations[i]->need_update = true;
123 animations[i] = NULL;
124 }
125 }
126}
127
128static bool update_keyframe_animation(keyframe_animation_t* animation, visualizer_state_t* state, systime_t delta, systime_t* sleep_time) {
129 dprintf("Animation frame%d, left %d, delta %d\n", animation->current_frame,
130 animation->time_left_in_frame, delta);
131 if (animation->current_frame == animation->num_frames) {
132 animation->need_update = false;
133 return false;
134 }
135 if (animation->current_frame == -1) {
136 animation->current_frame = 0;
137 animation->time_left_in_frame = animation->frame_lengths[0];
138 animation->need_update = true;
139 } else {
140 animation->time_left_in_frame -= delta;
141 while (animation->time_left_in_frame <= 0) {
142 int left = animation->time_left_in_frame;
143 if (animation->need_update) {
144 animation->time_left_in_frame = 0;
145 (*animation->frame_functions[animation->current_frame])(animation, state);
146 }
147 animation->current_frame++;
148 animation->need_update = true;
149 if (animation->current_frame == animation->num_frames) {
150 if (animation->loop) {
151 animation->current_frame = 0;
152 }
153 else {
154 stop_keyframe_animation(animation);
155 return false;
156 }
157 }
158 delta = -left;
159 animation->time_left_in_frame = animation->frame_lengths[animation->current_frame];
160 animation->time_left_in_frame -= delta;
161 }
162 }
163 if (animation->need_update) {
164 animation->need_update = (*animation->frame_functions[animation->current_frame])(animation, state);
165 }
166
167 int wanted_sleep = animation->need_update ? 10 : animation->time_left_in_frame;
168 if ((unsigned)wanted_sleep < *sleep_time) {
169 *sleep_time = wanted_sleep;
170 }
171
172 return true;
173}
174
175bool keyframe_no_operation(keyframe_animation_t* animation, visualizer_state_t* state) {
176 (void)animation;
177 (void)state;
178 return false;
179}
180
181#ifdef LCD_BACKLIGHT_ENABLE
182bool keyframe_animate_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state) {
183 int frame_length = animation->frame_lengths[animation->current_frame];
184 int current_pos = frame_length - animation->time_left_in_frame;
185 uint8_t t_h = LCD_HUE(state->target_lcd_color);
186 uint8_t t_s = LCD_SAT(state->target_lcd_color);
187 uint8_t t_i = LCD_INT(state->target_lcd_color);
188 uint8_t p_h = LCD_HUE(state->prev_lcd_color);
189 uint8_t p_s = LCD_SAT(state->prev_lcd_color);
190 uint8_t p_i = LCD_INT(state->prev_lcd_color);
191
192 uint8_t d_h1 = t_h - p_h; //Modulo arithmetic since we want to wrap around
193 int d_h2 = t_h - p_h;
194 // Chose the shortest way around
195 int d_h = abs(d_h2) < d_h1 ? d_h2 : d_h1;
196 int d_s = t_s - p_s;
197 int d_i = t_i - p_i;
198
199 int hue = (d_h * current_pos) / frame_length;
200 int sat = (d_s * current_pos) / frame_length;
201 int intensity = (d_i * current_pos) / frame_length;
202 //dprintf("%X -> %X = %X\n", p_h, t_h, hue);
203 hue += p_h;
204 sat += p_s;
205 intensity += p_i;
206 state->current_lcd_color = LCD_COLOR(hue, sat, intensity);
207 lcd_backlight_color(
208 LCD_HUE(state->current_lcd_color),
209 LCD_SAT(state->current_lcd_color),
210 LCD_INT(state->current_lcd_color));
211
212 return true;
213}
214
215bool keyframe_set_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state) {
216 (void)animation;
217 state->prev_lcd_color = state->target_lcd_color;
218 state->current_lcd_color = state->target_lcd_color;
219 lcd_backlight_color(
220 LCD_HUE(state->current_lcd_color),
221 LCD_SAT(state->current_lcd_color),
222 LCD_INT(state->current_lcd_color));
223 return false;
224}
225#endif // LCD_BACKLIGHT_ENABLE
226
227#ifdef LCD_ENABLE
228bool keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state) {
229 (void)animation;
230 gdispClear(White);
231 gdispDrawString(0, 10, state->layer_text, state->font_dejavusansbold12, Black);
232 gdispFlush();
233 return false;
234}
235
236static void format_layer_bitmap_string(uint16_t default_layer, uint16_t layer, char* buffer) {
237 for (int i=0; i<16;i++)
238 {
239 uint32_t mask = (1u << i);
240 if (default_layer & mask) {
241 if (layer & mask) {
242 *buffer = 'B';
243 } else {
244 *buffer = 'D';
245 }
246 } else if (layer & mask) {
247 *buffer = '1';
248 } else {
249 *buffer = '0';
250 }
251 ++buffer;
252
253 if (i==3 || i==7 || i==11) {
254 *buffer = ' ';
255 ++buffer;
256 }
257 }
258 *buffer = 0;
259}
260
261bool keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state) {
262 (void)animation;
263 const char* layer_help = "1=On D=Default B=Both";
264 char layer_buffer[16 + 4]; // 3 spaces and one null terminator
265 gdispClear(White);
266 gdispDrawString(0, 0, layer_help, state->font_fixed5x8, Black);
267 format_layer_bitmap_string(state->status.default_layer, state->status.layer, layer_buffer);
268 gdispDrawString(0, 10, layer_buffer, state->font_fixed5x8, Black);
269 format_layer_bitmap_string(state->status.default_layer >> 16, state->status.layer >> 16, layer_buffer);
270 gdispDrawString(0, 20, layer_buffer, state->font_fixed5x8, Black);
271 gdispFlush();
272 return false;
273}
274#endif // LCD_ENABLE
275
276bool keyframe_disable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state) {
277 (void)animation;
278 (void)state;
279#ifdef LCD_ENABLE
280 gdispSetPowerMode(powerOff);
281#endif
282#ifdef LCD_BACKLIGHT_ENABLE
283 lcd_backlight_hal_color(0, 0, 0);
284#endif
285 return false;
286}
287
288bool keyframe_enable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state) {
289 (void)animation;
290 (void)state;
291#ifdef LCD_ENABLE
292 gdispSetPowerMode(powerOn);
293#endif
294 return false;
295}
296
297bool enable_visualization(keyframe_animation_t* animation, visualizer_state_t* state) {
298 (void)animation;
299 (void)state;
300 dprint("User visualizer inited\n");
301 visualizer_enabled = true;
302 return false;
303}
304
305// TODO: Optimize the stack size, this is probably way too big
306static THD_WORKING_AREA(visualizerThreadStack, 1024);
307static THD_FUNCTION(visualizerThread, arg) {
308 (void)arg;
309
310 event_listener_t event_listener;
311 chEvtRegister(&layer_changed_event, &event_listener, 0);
312
313 visualizer_keyboard_status_t initial_status = {
314 .default_layer = 0xFFFFFFFF,
315 .layer = 0xFFFFFFFF,
316 .leds = 0xFFFFFFFF,
317 .suspended = false,
318 };
319
320 visualizer_state_t state = {
321 .status = initial_status,
322 .current_lcd_color = 0,
323#ifdef LCD_ENABLE
324 .font_fixed5x8 = gdispOpenFont("fixed_5x8"),
325 .font_dejavusansbold12 = gdispOpenFont("DejaVuSansBold12")
326#endif
327 };
328 initialize_user_visualizer(&state);
329 state.prev_lcd_color = state.current_lcd_color;
330
331#ifdef LCD_BACKLIGHT_ENABLE
332 lcd_backlight_color(
333 LCD_HUE(state.current_lcd_color),
334 LCD_SAT(state.current_lcd_color),
335 LCD_INT(state.current_lcd_color));
336#endif
337
338 systime_t sleep_time = TIME_INFINITE;
339 systime_t current_time = chVTGetSystemTimeX();
340
341 while(true) {
342 systime_t new_time = chVTGetSystemTimeX();
343 systime_t delta = new_time - current_time;
344 current_time = new_time;
345 bool enabled = visualizer_enabled;
346 if (!same_status(&state.status, &current_status)) {
347 if (visualizer_enabled) {
348 if (current_status.suspended) {
349 stop_all_keyframe_animations();
350 visualizer_enabled = false;
351 state.status = current_status;
352 user_visualizer_suspend(&state);
353 }
354 else {
355 state.status = current_status;
356 update_user_visualizer_state(&state);
357 }
358 state.prev_lcd_color = state.current_lcd_color;
359 }
360 }
361 if (!enabled && state.status.suspended && current_status.suspended == false) {
362 // Setting the status to the initial status will force an update
363 // when the visualizer is enabled again
364 state.status = initial_status;
365 state.status.suspended = false;
366 stop_all_keyframe_animations();
367 user_visualizer_resume(&state);
368 state.prev_lcd_color = state.current_lcd_color;
369 }
370 sleep_time = TIME_INFINITE;
371 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
372 if (animations[i]) {
373 update_keyframe_animation(animations[i], &state, delta, &sleep_time);
374 }
375 }
376 // The animation can enable the visualizer
377 // And we might need to update the state when that happens
378 // so don't sleep
379 if (enabled != visualizer_enabled) {
380 sleep_time = 0;
381 }
382
383 systime_t after_update = chVTGetSystemTimeX();
384 unsigned update_delta = after_update - current_time;
385 if (sleep_time != TIME_INFINITE) {
386 if (sleep_time > update_delta) {
387 sleep_time -= update_delta;
388 }
389 else {
390 sleep_time = 0;
391 }
392 }
393 dprintf("Update took %d, last delta %d, sleep_time %d\n", update_delta, delta, sleep_time);
394 chEvtWaitOneTimeout(EVENT_MASK(0), sleep_time);
395 }
396#ifdef LCD_ENABLE
397 gdispCloseFont(state.font_fixed5x8);
398 gdispCloseFont(state.font_dejavusansbold12);
399#endif
400}
401
402void visualizer_init(void) {
403#ifdef LCD_ENABLE
404 gfxInit();
405#endif
406
407#ifdef LCD_BACKLIGHT_ENABLE
408 lcd_backlight_init();
409#endif
410
411#ifdef USE_SERIAL_LINK
412 add_remote_objects(remote_objects, sizeof(remote_objects) / sizeof(remote_object_t*) );
413#endif
414 // We are using a low priority thread, the idea is to have it run only
415 // when the main thread is sleeping during the matrix scanning
416 chEvtObjectInit(&layer_changed_event);
417 (void)chThdCreateStatic(visualizerThreadStack, sizeof(visualizerThreadStack),
418 VISUALIZER_THREAD_PRIORITY, visualizerThread, NULL);
419}
420
421void update_status(bool changed) {
422 if (changed) {
423 chEvtBroadcast(&layer_changed_event);
424 }
425#ifdef USE_SERIAL_LINK
426 static systime_t last_update = 0;
427 systime_t current_update = chVTGetSystemTimeX();
428 systime_t delta = current_update - last_update;
429 if (changed || delta > MS2ST(10)) {
430 last_update = current_update;
431 visualizer_keyboard_status_t* r = begin_write_current_status();
432 *r = current_status;
433 end_write_current_status();
434 }
435#endif
436}
437
438void visualizer_update(uint32_t default_state, uint32_t state, uint32_t leds) {
439 // Note that there's a small race condition here, the thread could read
440 // a state where one of these are set but not the other. But this should
441 // not really matter as it will be fixed during the next loop step.
442 // Alternatively a mutex could be used instead of the volatile variables
443
444 bool changed = false;
445#ifdef USE_SERIAL_LINK
446 if (is_serial_link_connected ()) {
447 visualizer_keyboard_status_t* new_status = read_current_status();
448 if (new_status) {
449 if (!same_status(&current_status, new_status)) {
450 changed = true;
451 current_status = *new_status;
452 }
453 }
454 }
455 else {
456#else
457 {
458#endif
459 visualizer_keyboard_status_t new_status = {
460 .layer = state,
461 .default_layer = default_state,
462 .leds = leds,
463 .suspended = current_status.suspended,
464 };
465 if (!same_status(&current_status, &new_status)) {
466 changed = true;
467 current_status = new_status;
468 }
469 }
470 update_status(changed);
471}
472
473void visualizer_suspend(void) {
474 current_status.suspended = true;
475 update_status(true);
476}
477
478void visualizer_resume(void) {
479 current_status.suspended = false;
480 update_status(true);
481}
diff --git a/quantum/visualizer/visualizer.h b/quantum/visualizer/visualizer.h
new file mode 100644
index 000000000..22798cda6
--- /dev/null
+++ b/quantum/visualizer/visualizer.h
@@ -0,0 +1,131 @@
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// If you need support for more than 8 keyframes per animation, you can change this
49#define MAX_VISUALIZER_KEY_FRAMES 8
50
51struct keyframe_animation_t;
52
53typedef struct {
54 uint32_t layer;
55 uint32_t default_layer;
56 uint32_t leds; // See led.h for available statuses
57 bool suspended;
58} visualizer_keyboard_status_t;
59
60// The state struct is used by the various keyframe functions
61// It's also used for setting the LCD color and layer text
62// from the user customized code
63typedef struct visualizer_state_t {
64 // The user code should primarily be modifying these
65 uint32_t target_lcd_color;
66 const char* layer_text;
67
68 // The user visualizer(and animation functions) can read these
69 visualizer_keyboard_status_t status;
70
71 // These are used by the animation functions
72 uint32_t current_lcd_color;
73 uint32_t prev_lcd_color;
74#ifdef LCD_ENABLE
75 font_t font_fixed5x8;
76 font_t font_dejavusansbold12;
77#endif
78} visualizer_state_t;
79
80// Any custom keyframe function should have this signature
81// return true to get continuous updates, otherwise you will only get one
82// update per frame
83typedef bool (*frame_func)(struct keyframe_animation_t*, visualizer_state_t*);
84
85// Represents a keyframe animation, so fields are internal to the system
86// while others are meant to be initialized by the user code
87typedef struct keyframe_animation_t {
88 // These should be initialized
89 int num_frames;
90 bool loop;
91 int frame_lengths[MAX_VISUALIZER_KEY_FRAMES];
92 frame_func frame_functions[MAX_VISUALIZER_KEY_FRAMES];
93
94 // Used internally by the system, and can also be read by
95 // keyframe update functions
96 int current_frame;
97 int time_left_in_frame;
98 bool need_update;
99
100} keyframe_animation_t;
101
102void start_keyframe_animation(keyframe_animation_t* animation);
103void stop_keyframe_animation(keyframe_animation_t* animation);
104
105// Some predefined keyframe functions that can be used by the user code
106// Does nothing, useful for adding delays
107bool keyframe_no_operation(keyframe_animation_t* animation, visualizer_state_t* state);
108// Animates the LCD backlight color between the current color and the target color (of the state)
109bool keyframe_animate_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state);
110// Sets the backlight color to the target color
111bool keyframe_set_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state);
112// Displays the layer text centered vertically on the screen
113bool keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state);
114// Displays a bitmap (0/1) of all the currently active layers
115bool keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state);
116
117bool keyframe_disable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state);
118bool keyframe_enable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state);
119
120// Call this once, when the initial animation has finished, alternatively you can call it
121// directly from the initalize_user_visualizer function (the animation can be null)
122bool enable_visualization(keyframe_animation_t* animation, visualizer_state_t* state);
123
124// These two functions have to be implemented by the user
125void initialize_user_visualizer(visualizer_state_t* state);
126void update_user_visualizer_state(visualizer_state_t* state);
127void user_visualizer_suspend(visualizer_state_t* state);
128void user_visualizer_resume(visualizer_state_t* state);
129
130
131#endif /* VISUALIZER_H */
diff --git a/quantum/visualizer/visualizer.mk b/quantum/visualizer/visualizer.mk
new file mode 100644
index 000000000..13c5d3158
--- /dev/null
+++ b/quantum/visualizer/visualizer.mk
@@ -0,0 +1,41 @@
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
24ifdef LCD_ENABLE
25include $(GFXLIB)/gfx.mk
26UDEFS += -DLCD_ENABLE
27ULIBS += -lm
28endif
29SRC += $(GFXSRC) $(VISUALIZER_DIR)/visualizer.c
30UINCDIR += $(GFXINC) $(VISUALIZER_DIR)
31
32ifdef LCD_BACKLIGHT_ENABLE
33SRC += $(VISUALIZER_DIR)/lcd_backlight.c
34SRC += lcd_backlight_hal.c
35UDEFS += -DLCD_BACKLIGHT_ENABLE
36endif
37
38ifndef VISUALIZER_USER
39VISUALIZER_USER = visualizer_user.c
40endif
41SRC += $(VISUALIZER_USER) \ No newline at end of file