From: Fred Sundvik Date: Wed, 6 Jul 2016 17:15:45 +0000 (+0300) Subject: Add 'quantum/visualizer/' from commit 'bde869aa7ec8601459bc63b9636081d21108d1be' X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=9f33a5593cc70dfb0885328061f1aa4b2c2fa386;p=qmk_firmware.git Add 'quantum/visualizer/' from commit 'bde869aa7ec8601459bc63b9636081d21108d1be' git-subtree-dir: quantum/visualizer git-subtree-mainline: 19f480992c015aec0a15dca43e740bad8b7834e6 git-subtree-split: bde869aa7ec8601459bc63b9636081d21108d1be --- 9f33a5593cc70dfb0885328061f1aa4b2c2fa386 diff --cc quantum/visualizer/.gitmodules index 000000000,000000000..b320458c0 new file mode 100644 --- /dev/null +++ b/quantum/visualizer/.gitmodules @@@ -1,0 -1,0 +1,3 @@@ ++[submodule "ugfx"] ++ path = ugfx ++ url = https://bitbucket.org/fredizzimo/ugfx.git diff --cc quantum/visualizer/LICENSE.md index 000000000,000000000..22d4c3f08 new file mode 100644 --- /dev/null +++ b/quantum/visualizer/LICENSE.md @@@ -1,0 -1,0 +1,29 @@@ ++The files in this project are licensed under the MIT license ++It uses the following libraries ++uGFX - with it's own license, see the license.html file in the uGFX subfolder for more information ++tmk_core - is indirectly used and not included in the repository. It's licensed under the GPLv2 license ++Chibios - which is used by tmk_core is licensed under GPLv3. ++ ++Therefore the effective license for any project using the library is GPLv3 ++ ++The MIT License (MIT) ++ ++Copyright (c) 2016 Fred Sundvik ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy ++of this software and associated documentation files (the "Software"), to deal ++in the Software without restriction, including without limitation the rights ++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++copies of the Software, and to permit persons to whom the Software is ++furnished to do so, subject to the following conditions: ++ ++The above copyright notice and this permission notice shall be included in all ++copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++SOFTWARE. diff --cc quantum/visualizer/example_integration/callbacks.c index 000000000,000000000..2539615d6 new file mode 100644 --- /dev/null +++ b/quantum/visualizer/example_integration/callbacks.c @@@ -1,0 -1,0 +1,36 @@@ ++/* ++The MIT License (MIT) ++ ++Copyright (c) 2016 Fred Sundvik ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy ++of this software and associated documentation files (the "Software"), to deal ++in the Software without restriction, including without limitation the rights ++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++copies of the Software, and to permit persons to whom the Software is ++furnished to do so, subject to the following conditions: ++ ++The above copyright notice and this permission notice shall be included in all ++copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++SOFTWARE. ++*/ ++ ++#include "keyboard.h" ++#include "action_layer.h" ++#include "visualizer.h" ++#include "host.h" ++ ++void post_keyboard_init(void) { ++ visualizer_init(); ++} ++ ++void post_keyboard_task() { ++ visualizer_set_state(default_layer_state, layer_state, host_keyboard_leds()); ++} diff --cc quantum/visualizer/example_integration/gfxconf.h index 000000000,000000000..304c5d187 new file mode 100644 --- /dev/null +++ b/quantum/visualizer/example_integration/gfxconf.h @@@ -1,0 -1,0 +1,325 @@@ ++/** ++ * This file has a different license to the rest of the uGFX system. ++ * You can copy, modify and distribute this file as you see fit. ++ * You do not need to publish your source modifications to this file. ++ * The only thing you are not permitted to do is to relicense it ++ * under a different license. ++ */ ++ ++/** ++ * Copy this file into your project directory and rename it as gfxconf.h ++ * Edit your copy to turn on the uGFX features you want to use. ++ * The values below are the defaults. ++ * ++ * Only remove the comments from lines where you want to change the ++ * default value. This allows definitions to be included from ++ * driver makefiles when required and provides the best future ++ * compatibility for your project. ++ * ++ * Please use spaces instead of tabs in this file. ++ */ ++ ++#ifndef _GFXCONF_H ++#define _GFXCONF_H ++ ++ ++/////////////////////////////////////////////////////////////////////////// ++// GOS - One of these must be defined, preferably in your Makefile // ++/////////////////////////////////////////////////////////////////////////// ++#define GFX_USE_OS_CHIBIOS TRUE ++//#define GFX_USE_OS_FREERTOS FALSE ++// #define GFX_FREERTOS_USE_TRACE FALSE ++//#define GFX_USE_OS_WIN32 FALSE ++//#define GFX_USE_OS_LINUX FALSE ++//#define GFX_USE_OS_OSX FALSE ++//#define GFX_USE_OS_ECOS FALSE ++//#define GFX_USE_OS_RAWRTOS FALSE ++//#define GFX_USE_OS_ARDUINO FALSE ++//#define GFX_USE_OS_KEIL FALSE ++//#define GFX_USE_OS_CMSIS FALSE ++//#define GFX_USE_OS_RAW32 FALSE ++// #define INTERRUPTS_OFF() optional_code ++// #define INTERRUPTS_ON() optional_code ++// These are not defined by default for some reason ++#define GOS_NEED_X_THREADS FALSE ++#define GOS_NEED_X_HEAP FALSE ++ ++// Options that (should where relevant) apply to all operating systems ++ #define GFX_NO_INLINE FALSE ++// #define GFX_COMPILER GFX_COMPILER_UNKNOWN ++// #define GFX_CPU GFX_CPU_UNKNOWN ++// #define GFX_OS_HEAP_SIZE 0 ++// #define GFX_OS_NO_INIT FALSE ++// #define GFX_OS_INIT_NO_WARNING FALSE ++// #define GFX_OS_PRE_INIT_FUNCTION myHardwareInitRoutine ++// #define GFX_OS_EXTRA_INIT_FUNCTION myOSInitRoutine ++// #define GFX_OS_EXTRA_DEINIT_FUNCTION myOSDeInitRoutine ++ ++ ++/////////////////////////////////////////////////////////////////////////// ++// GDISP // ++/////////////////////////////////////////////////////////////////////////// ++#define GFX_USE_GDISP TRUE ++ ++//#define GDISP_NEED_AUTOFLUSH FALSE ++//#define GDISP_NEED_TIMERFLUSH FALSE ++//#define GDISP_NEED_VALIDATION TRUE ++//#define GDISP_NEED_CLIP TRUE ++//#define GDISP_NEED_CIRCLE FALSE ++//#define GDISP_NEED_ELLIPSE FALSE ++//#define GDISP_NEED_ARC FALSE ++//#define GDISP_NEED_ARCSECTORS FALSE ++//#define GDISP_NEED_CONVEX_POLYGON FALSE ++//#define GDISP_NEED_SCROLL FALSE ++//#define GDISP_NEED_PIXELREAD FALSE ++//#define GDISP_NEED_CONTROL FALSE ++//#define GDISP_NEED_QUERY FALSE ++//#define GDISP_NEED_MULTITHREAD FALSE ++//#define GDISP_NEED_STREAMING FALSE ++#define GDISP_NEED_TEXT TRUE ++// #define GDISP_NEED_TEXT_WORDWRAP FALSE ++// #define GDISP_NEED_ANTIALIAS FALSE ++// #define GDISP_NEED_UTF8 FALSE ++ #define GDISP_NEED_TEXT_KERNING TRUE ++// #define GDISP_INCLUDE_FONT_UI1 FALSE ++// #define GDISP_INCLUDE_FONT_UI2 FALSE // The smallest preferred font. ++// #define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE ++// #define GDISP_INCLUDE_FONT_DEJAVUSANS10 FALSE ++// #define GDISP_INCLUDE_FONT_DEJAVUSANS12 FALSE ++// #define GDISP_INCLUDE_FONT_DEJAVUSANS16 FALSE ++// #define GDISP_INCLUDE_FONT_DEJAVUSANS20 FALSE ++// #define GDISP_INCLUDE_FONT_DEJAVUSANS24 FALSE ++// #define GDISP_INCLUDE_FONT_DEJAVUSANS32 FALSE ++ #define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12 TRUE ++// #define GDISP_INCLUDE_FONT_FIXED_10X20 FALSE ++// #define GDISP_INCLUDE_FONT_FIXED_7X14 FALSE ++ #define GDISP_INCLUDE_FONT_FIXED_5X8 TRUE ++// #define GDISP_INCLUDE_FONT_DEJAVUSANS12_AA FALSE ++// #define GDISP_INCLUDE_FONT_DEJAVUSANS16_AA FALSE ++// #define GDISP_INCLUDE_FONT_DEJAVUSANS20_AA FALSE ++// #define GDISP_INCLUDE_FONT_DEJAVUSANS24_AA FALSE ++// #define GDISP_INCLUDE_FONT_DEJAVUSANS32_AA FALSE ++// #define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12_AA FALSE ++// #define GDISP_INCLUDE_USER_FONTS FALSE ++ ++//#define GDISP_NEED_IMAGE FALSE ++// #define GDISP_NEED_IMAGE_NATIVE FALSE ++// #define GDISP_NEED_IMAGE_GIF FALSE ++// #define GDISP_NEED_IMAGE_BMP FALSE ++// #define GDISP_NEED_IMAGE_BMP_1 FALSE ++// #define GDISP_NEED_IMAGE_BMP_4 FALSE ++// #define GDISP_NEED_IMAGE_BMP_4_RLE FALSE ++// #define GDISP_NEED_IMAGE_BMP_8 FALSE ++// #define GDISP_NEED_IMAGE_BMP_8_RLE FALSE ++// #define GDISP_NEED_IMAGE_BMP_16 FALSE ++// #define GDISP_NEED_IMAGE_BMP_24 FALSE ++// #define GDISP_NEED_IMAGE_BMP_32 FALSE ++// #define GDISP_NEED_IMAGE_JPG FALSE ++// #define GDISP_NEED_IMAGE_PNG FALSE ++// #define GDISP_NEED_IMAGE_ACCOUNTING FALSE ++ ++//#define GDISP_NEED_PIXMAP FALSE ++// #define GDISP_NEED_PIXMAP_IMAGE FALSE ++ ++//#define GDISP_DEFAULT_ORIENTATION GDISP_ROTATE_LANDSCAPE // If not defined the native hardware orientation is used. ++//#define GDISP_LINEBUF_SIZE 128 ++//#define GDISP_STARTUP_COLOR Black ++#define GDISP_NEED_STARTUP_LOGO FALSE ++ ++//#define GDISP_TOTAL_DISPLAYS 1 ++ ++//#define GDISP_DRIVER_LIST GDISPVMT_Win32, GDISPVMT_Win32 ++// #ifdef GDISP_DRIVER_LIST ++// // For code and speed optimization define as TRUE or FALSE if all controllers have the same capability ++// #define GDISP_HARDWARE_STREAM_WRITE FALSE ++// #define GDISP_HARDWARE_STREAM_READ FALSE ++// #define GDISP_HARDWARE_STREAM_POS FALSE ++// #define GDISP_HARDWARE_DRAWPIXEL FALSE ++// #define GDISP_HARDWARE_CLEARS FALSE ++// #define GDISP_HARDWARE_FILLS FALSE ++// #define GDISP_HARDWARE_BITFILLS FALSE ++// #define GDISP_HARDWARE_SCROLL FALSE ++// #define GDISP_HARDWARE_PIXELREAD FALSE ++// #define GDISP_HARDWARE_CONTROL FALSE ++// #define GDISP_HARDWARE_QUERY FALSE ++// #define GDISP_HARDWARE_CLIP FALSE ++ ++ #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 ++// #endif ++ ++// The custom format is not defined for some reason, so define it as error ++// so we don't get compiler warnings ++#define GDISP_PIXELFORMAT_CUSTOM GDISP_PIXELFORMAT_ERROR ++ ++#define GDISP_USE_GFXNET FALSE ++// #define GDISP_GFXNET_PORT 13001 ++// #define GDISP_GFXNET_CUSTOM_LWIP_STARTUP FALSE ++// #define GDISP_DONT_WAIT_FOR_NET_DISPLAY FALSE ++// #define GDISP_GFXNET_UNSAFE_SOCKETS FALSE ++ ++ ++/////////////////////////////////////////////////////////////////////////// ++// GWIN // ++/////////////////////////////////////////////////////////////////////////// ++#define GFX_USE_GWIN FALSE ++ ++//#define GWIN_NEED_WINDOWMANAGER FALSE ++// #define GWIN_REDRAW_IMMEDIATE FALSE ++// #define GWIN_REDRAW_SINGLEOP FALSE ++// #define GWIN_NEED_FLASHING FALSE ++// #define GWIN_FLASHING_PERIOD 250 ++ ++//#define GWIN_NEED_CONSOLE FALSE ++// #define GWIN_CONSOLE_USE_HISTORY FALSE ++// #define GWIN_CONSOLE_HISTORY_AVERAGING FALSE ++// #define GWIN_CONSOLE_HISTORY_ATCREATE FALSE ++// #define GWIN_CONSOLE_ESCSEQ FALSE ++// #define GWIN_CONSOLE_USE_BASESTREAM FALSE ++// #define GWIN_CONSOLE_USE_FLOAT FALSE ++//#define GWIN_NEED_GRAPH FALSE ++//#define GWIN_NEED_GL3D FALSE ++ ++//#define GWIN_NEED_WIDGET FALSE ++//#define GWIN_FOCUS_HIGHLIGHT_WIDTH 1 ++// #define GWIN_NEED_LABEL FALSE ++// #define GWIN_LABEL_ATTRIBUTE FALSE ++// #define GWIN_NEED_BUTTON FALSE ++// #define GWIN_BUTTON_LAZY_RELEASE FALSE ++// #define GWIN_NEED_SLIDER FALSE ++// #define GWIN_SLIDER_NOSNAP FALSE ++// #define GWIN_SLIDER_DEAD_BAND 5 ++// #define GWIN_SLIDER_TOGGLE_INC 20 ++// #define GWIN_NEED_CHECKBOX FALSE ++// #define GWIN_NEED_IMAGE FALSE ++// #define GWIN_NEED_IMAGE_ANIMATION FALSE ++// #define GWIN_NEED_RADIO FALSE ++// #define GWIN_NEED_LIST FALSE ++// #define GWIN_NEED_LIST_IMAGES FALSE ++// #define GWIN_NEED_PROGRESSBAR FALSE ++// #define GWIN_PROGRESSBAR_AUTO FALSE ++// #define GWIN_NEED_KEYBOARD FALSE ++// #define GWIN_KEYBOARD_DEFAULT_LAYOUT VirtualKeyboard_English1 ++// #define GWIN_NEED_KEYBOARD_ENGLISH1 TRUE ++// #define GWIN_NEED_TEXTEDIT FALSE ++// #define GWIN_FLAT_STYLING FALSE ++// #define GWIN_WIDGET_TAGS FALSE ++ ++//#define GWIN_NEED_CONTAINERS FALSE ++// #define GWIN_NEED_CONTAINER FALSE ++// #define GWIN_NEED_FRAME FALSE ++// #define GWIN_NEED_TABSET FALSE ++// #define GWIN_TABSET_TABHEIGHT 18 ++ ++ ++/////////////////////////////////////////////////////////////////////////// ++// GEVENT // ++/////////////////////////////////////////////////////////////////////////// ++#define GFX_USE_GEVENT FALSE ++ ++//#define GEVENT_ASSERT_NO_RESOURCE FALSE ++//#define GEVENT_MAXIMUM_SIZE 32 ++//#define GEVENT_MAX_SOURCE_LISTENERS 32 ++ ++ ++/////////////////////////////////////////////////////////////////////////// ++// GTIMER // ++/////////////////////////////////////////////////////////////////////////// ++#define GFX_USE_GTIMER FALSE ++ ++//#define GTIMER_THREAD_PRIORITY HIGH_PRIORITY ++//#define GTIMER_THREAD_WORKAREA_SIZE 2048 ++ ++ ++/////////////////////////////////////////////////////////////////////////// ++// GQUEUE // ++/////////////////////////////////////////////////////////////////////////// ++#define GFX_USE_GQUEUE FALSE ++ ++//#define GQUEUE_NEED_ASYNC FALSE ++//#define GQUEUE_NEED_GSYNC FALSE ++//#define GQUEUE_NEED_FSYNC FALSE ++//#define GQUEUE_NEED_BUFFERS FALSE ++ ++/////////////////////////////////////////////////////////////////////////// ++// GINPUT // ++/////////////////////////////////////////////////////////////////////////// ++#define GFX_USE_GINPUT FALSE ++ ++//#define GINPUT_NEED_MOUSE FALSE ++// #define GINPUT_TOUCH_STARTRAW FALSE ++// #define GINPUT_TOUCH_NOTOUCH FALSE ++// #define GINPUT_TOUCH_NOCALIBRATE FALSE ++// #define GINPUT_TOUCH_NOCALIBRATE_GUI FALSE ++// #define GINPUT_MOUSE_POLL_PERIOD 25 ++// #define GINPUT_MOUSE_CLICK_TIME 300 ++// #define GINPUT_TOUCH_CXTCLICK_TIME 700 ++// #define GINPUT_TOUCH_USER_CALIBRATION_LOAD FALSE ++// #define GINPUT_TOUCH_USER_CALIBRATION_SAVE FALSE ++// #define GMOUSE_DRIVER_LIST GMOUSEVMT_Win32, GMOUSEVMT_Win32 ++//#define GINPUT_NEED_KEYBOARD FALSE ++// #define GINPUT_KEYBOARD_POLL_PERIOD 200 ++// #define GKEYBOARD_DRIVER_LIST GKEYBOARDVMT_Win32, GKEYBOARDVMT_Win32 ++// #define GKEYBOARD_LAYOUT_OFF FALSE ++// #define GKEYBOARD_LAYOUT_SCANCODE2_US FALSE ++//#define GINPUT_NEED_TOGGLE FALSE ++//#define GINPUT_NEED_DIAL FALSE ++ ++ ++/////////////////////////////////////////////////////////////////////////// ++// GFILE // ++/////////////////////////////////////////////////////////////////////////// ++#define GFX_USE_GFILE FALSE ++ ++//#define GFILE_NEED_PRINTG FALSE ++//#define GFILE_NEED_SCANG FALSE ++//#define GFILE_NEED_STRINGS FALSE ++//#define GFILE_NEED_FILELISTS FALSE ++//#define GFILE_NEED_STDIO FALSE ++//#define GFILE_NEED_NOAUTOMOUNT FALSE ++//#define GFILE_NEED_NOAUTOSYNC FALSE ++ ++//#define GFILE_NEED_MEMFS FALSE ++//#define GFILE_NEED_ROMFS FALSE ++//#define GFILE_NEED_RAMFS FALSE ++//#define GFILE_NEED_FATFS FALSE ++//#define GFILE_NEED_NATIVEFS FALSE ++//#define GFILE_NEED_CHBIOSFS FALSE ++ ++//#define GFILE_ALLOW_FLOATS FALSE ++//#define GFILE_ALLOW_DEVICESPECIFIC FALSE ++//#define GFILE_MAX_GFILES 3 ++ ++/////////////////////////////////////////////////////////////////////////// ++// GADC // ++/////////////////////////////////////////////////////////////////////////// ++#define GFX_USE_GADC FALSE ++ ++//#define GADC_MAX_LOWSPEED_DEVICES 4 ++ ++ ++/////////////////////////////////////////////////////////////////////////// ++// GAUDIO // ++/////////////////////////////////////////////////////////////////////////// ++#define GFX_USE_GAUDIO FALSE ++// There seems to be a bug in the ugfx code, the wrong define is used ++// So define it in order to avoid warnings ++#define GFX_USE_GAUDIN GFX_USE_GAUDIO ++// #define GAUDIO_NEED_PLAY FALSE ++// #define GAUDIO_NEED_RECORD FALSE ++ ++ ++/////////////////////////////////////////////////////////////////////////// ++// GMISC // ++/////////////////////////////////////////////////////////////////////////// ++#define GFX_USE_GMISC FALSE ++ ++//#define GMISC_NEED_ARRAYOPS FALSE ++//#define GMISC_NEED_FASTTRIG FALSE ++//#define GMISC_NEED_FIXEDTRIG FALSE ++//#define GMISC_NEED_INVSQRT FALSE ++// #define GMISC_INVSQRT_MIXED_ENDIAN FALSE ++// #define GMISC_INVSQRT_REAL_SLOW FALSE ++//#define GMISC_NEED_MATRIXFLOAT2D FALSE ++//#define GMISC_NEED_MATRIXFIXED2D FALSE ++ ++#endif /* _GFXCONF_H */ diff --cc quantum/visualizer/example_integration/lcd_backlight_hal.c index 000000000,000000000..913131b16 new file mode 100644 --- /dev/null +++ b/quantum/visualizer/example_integration/lcd_backlight_hal.c @@@ -1,0 -1,0 +1,91 @@@ ++/* ++The MIT License (MIT) ++ ++Copyright (c) 2016 Fred Sundvik ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy ++of this software and associated documentation files (the "Software"), to deal ++in the Software without restriction, including without limitation the rights ++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++copies of the Software, and to permit persons to whom the Software is ++furnished to do so, subject to the following conditions: ++ ++The above copyright notice and this permission notice shall be included in all ++copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++SOFTWARE. ++*/ ++ ++#include "lcd_backlight.h" ++#include "hal.h" ++ ++#define RED_PIN 1 ++#define GREEN_PIN 2 ++#define BLUE_PIN 3 ++#define CHANNEL_RED FTM0->CHANNEL[0] ++#define CHANNEL_GREEN FTM0->CHANNEL[1] ++#define CHANNEL_BLUE FTM0->CHANNEL[2] ++ ++#define RGB_PORT PORTC ++#define RGB_PORT_GPIO GPIOC ++ ++// Base FTM clock selection (72 MHz system clock) ++// @ 0xFFFF period, 72 MHz / (0xFFFF * 2) = Actual period ++// Higher pre-scalar will use the most power (also look the best) ++// Pre-scalar calculations ++// 0 - 72 MHz -> 549 Hz ++// 1 - 36 MHz -> 275 Hz ++// 2 - 18 MHz -> 137 Hz ++// 3 - 9 MHz -> 69 Hz (Slightly visible flicker) ++// 4 - 4 500 kHz -> 34 Hz (Visible flickering) ++// 5 - 2 250 kHz -> 17 Hz ++// 6 - 1 125 kHz -> 9 Hz ++// 7 - 562 500 Hz -> 4 Hz ++// Using a higher pre-scalar without flicker is possible but FTM0_MOD will need to be reduced ++// Which will reduce the brightness range ++#define PRESCALAR_DEFINE 0 ++ ++void lcd_backlight_hal_init(void) { ++ // Setup Backlight ++ SIM->SCGC6 |= SIM_SCGC6_FTM0; ++ FTM0->CNT = 0; // Reset counter ++ ++ // PWM Period ++ // 16-bit maximum ++ FTM0->MOD = 0xFFFF; ++ ++ // Set FTM to PWM output - Edge Aligned, Low-true pulses ++#define CNSC_MODE FTM_SC_CPWMS | FTM_SC_PS(4) | FTM_SC_CLKS(0) ++ CHANNEL_RED.CnSC = CNSC_MODE; ++ CHANNEL_GREEN.CnSC = CNSC_MODE; ++ CHANNEL_BLUE.CnSC = CNSC_MODE; ++ ++ // System clock, /w prescalar setting ++ FTM0->SC = FTM_SC_CLKS(1) | FTM_SC_PS(PRESCALAR_DEFINE); ++ ++ CHANNEL_RED.CnV = 0; ++ CHANNEL_GREEN.CnV = 0; ++ CHANNEL_BLUE.CnV = 0; ++ ++ RGB_PORT_GPIO->PDDR |= (1 << RED_PIN); ++ RGB_PORT_GPIO->PDDR |= (1 << GREEN_PIN); ++ RGB_PORT_GPIO->PDDR |= (1 << BLUE_PIN); ++ ++#define RGB_MODE PORTx_PCRn_SRE | PORTx_PCRn_DSE | PORTx_PCRn_MUX(4) ++ RGB_PORT->PCR[RED_PIN] = RGB_MODE; ++ RGB_PORT->PCR[GREEN_PIN] = RGB_MODE; ++ RGB_PORT->PCR[BLUE_PIN] = RGB_MODE; ++} ++ ++void lcd_backlight_hal_color(uint16_t r, uint16_t g, uint16_t b) { ++ CHANNEL_RED.CnV = r; ++ CHANNEL_GREEN.CnV = g; ++ CHANNEL_BLUE.CnV = b; ++} ++ diff --cc quantum/visualizer/example_integration/visualizer_user.c index 000000000,000000000..fc09fe2ea new file mode 100644 --- /dev/null +++ b/quantum/visualizer/example_integration/visualizer_user.c @@@ -1,0 -1,0 +1,121 @@@ ++/* ++The MIT License (MIT) ++ ++Copyright (c) 2016 Fred Sundvik ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy ++of this software and associated documentation files (the "Software"), to deal ++in the Software without restriction, including without limitation the rights ++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++copies of the Software, and to permit persons to whom the Software is ++furnished to do so, subject to the following conditions: ++ ++The above copyright notice and this permission notice shall be included in all ++copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++SOFTWARE. ++*/ ++ ++// Currently we are assuming that both the backlight and LCD are enabled ++// But it's entirely possible to write a custom visualizer that use only ++// one of them ++#ifndef LCD_BACKLIGHT_ENABLE ++#error This visualizer needs that LCD backlight is enabled ++#endif ++ ++#ifndef LCD_ENABLE ++#error This visualizer needs that LCD is enabled ++#endif ++ ++#include "visualizer.h" ++ ++static const char* welcome_text[] = {"TMK", "Infinity Ergodox"}; ++ ++// Just an example how to write custom keyframe functions, we could have moved ++// all this into the init function ++bool display_welcome(keyframe_animation_t* animation, visualizer_state_t* state) { ++ (void)animation; ++ // Read the uGFX documentation for information how to use the displays ++ // http://wiki.ugfx.org/index.php/Main_Page ++ gdispClear(White); ++ // You can use static variables for things that can't be found in the animation ++ // or state structs ++ gdispDrawString(0, 3, welcome_text[0], state->font_dejavusansbold12, Black); ++ gdispDrawString(0, 15, welcome_text[1], state->font_dejavusansbold12, Black); ++ // Always remember to flush the display ++ gdispFlush(); ++ // you could set the backlight color as well, but we won't do it here, since ++ // it's part of the following animation ++ // lcd_backlight_color(hue, saturation, intensity); ++ // We don't need constant updates, just drawing the screen once is enough ++ return false; ++} ++ ++// Feel free to modify the animations below, or even add new ones if needed ++ ++// Don't worry, if the startup animation is long, you can use the keyboard like normal ++// during that time ++static keyframe_animation_t startup_animation = { ++ .num_frames = 4, ++ .loop = false, ++ .frame_lengths = {0, MS2ST(1000), MS2ST(5000), 0}, ++ .frame_functions = {display_welcome, keyframe_animate_backlight_color, keyframe_no_operation, enable_visualization}, ++}; ++ ++// The color animation animates the LCD color when you change layers ++static keyframe_animation_t color_animation = { ++ .num_frames = 2, ++ .loop = false, ++ // Note that there's a 200 ms no-operation frame, ++ // this prevents the color from changing when activating the layer ++ // momentarily ++ .frame_lengths = {MS2ST(200), MS2ST(500)}, ++ .frame_functions = {keyframe_no_operation, keyframe_animate_backlight_color}, ++}; ++ ++// The LCD animation alternates between the layer name display and a ++// bitmap that displays all active layers ++static keyframe_animation_t lcd_animation = { ++ .num_frames = 2, ++ .loop = true, ++ .frame_lengths = {MS2ST(2000), MS2ST(2000)}, ++ .frame_functions = {keyframe_display_layer_text, keyframe_display_layer_bitmap}, ++}; ++ ++void initialize_user_visualizer(visualizer_state_t* state) { ++ // The brightness will be dynamically adjustable in the future ++ // But for now, change it here. ++ lcd_backlight_brightness(0x50); ++ state->current_lcd_color = LCD_COLOR(0x00, 0x00, 0xFF); ++ state->target_lcd_color = LCD_COLOR(0x10, 0xFF, 0xFF); ++ start_keyframe_animation(&startup_animation); ++} ++ ++void update_user_visualizer_state(visualizer_state_t* state) { ++ // Add more tests, change the colors and layer texts here ++ // Usually you want to check the high bits (higher layers first) ++ // because that's the order layers are processed for keypresses ++ // You can for check for example: ++ // state->status.layer ++ // state->status.default_layer ++ // state->status.leds (see led.h for available statuses) ++ if (state->status.layer & 0x2) { ++ state->target_lcd_color = LCD_COLOR(0xA0, 0xB0, 0xFF); ++ state->layer_text = "Layer 2"; ++ } ++ else { ++ state->target_lcd_color = LCD_COLOR(0x50, 0xB0, 0xFF); ++ state->layer_text = "Layer 1"; ++ } ++ // You can also stop existing animations, and start your custom ones here ++ // remember that you should normally have only one animation for the LCD ++ // and one for the background. But you can also combine them if you want. ++ start_keyframe_animation(&lcd_animation); ++ start_keyframe_animation(&color_animation); ++} diff --cc quantum/visualizer/lcd_backlight.c index 000000000,000000000..70187d1e0 new file mode 100644 --- /dev/null +++ b/quantum/visualizer/lcd_backlight.c @@@ -1,0 -1,0 +1,85 @@@ ++/* ++The MIT License (MIT) ++ ++Copyright (c) 2016 Fred Sundvik ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy ++of this software and associated documentation files (the "Software"), to deal ++in the Software without restriction, including without limitation the rights ++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++copies of the Software, and to permit persons to whom the Software is ++furnished to do so, subject to the following conditions: ++ ++The above copyright notice and this permission notice shall be included in all ++copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++SOFTWARE. ++*/ ++ ++#include "lcd_backlight.h" ++#include ++ ++static uint8_t current_hue = 0x00; ++static uint8_t current_saturation = 0x00; ++static uint8_t current_intensity = 0xFF; ++static uint8_t current_brightness = 0x7F; ++ ++void lcd_backlight_init(void) { ++ lcd_backlight_hal_init(); ++ lcd_backlight_color(current_hue, current_saturation, current_intensity); ++} ++ ++// This code is based on Brian Neltner's blogpost and example code ++// "Why every LED light should be using HSI colorspace". ++// http://blog.saikoled.com/post/43693602826/why-every-led-light-should-be-using-hsi ++static void hsi_to_rgb(float h, float s, float i, uint16_t* r_out, uint16_t* g_out, uint16_t* b_out) { ++ unsigned int r, g, b; ++ h = fmodf(h, 360.0f); // cycle h around to 0-360 degrees ++ h = 3.14159f * h / 180.0f; // Convert to radians. ++ s = s > 0.0f ? (s < 1.0f ? s : 1.0f) : 0.0f; // clamp s and i to interval [0,1] ++ i = i > 0.0f ? (i < 1.0f ? i : 1.0f) : 0.0f; ++ ++ // Math! Thanks in part to Kyle Miller. ++ if(h < 2.09439f) { ++ r = 65535.0f * i/3.0f *(1.0f + s * cos(h) / cosf(1.047196667f - h)); ++ g = 65535.0f * i/3.0f *(1.0f + s *(1.0f - cosf(h) / cos(1.047196667f - h))); ++ b = 65535.0f * i/3.0f *(1.0f - s); ++ } else if(h < 4.188787) { ++ h = h - 2.09439; ++ g = 65535.0f * i/3.0f *(1.0f + s * cosf(h) / cosf(1.047196667f - h)); ++ b = 65535.0f * i/3.0f *(1.0f + s * (1.0f - cosf(h) / cosf(1.047196667f - h))); ++ r = 65535.0f * i/3.0f *(1.0f - s); ++ } else { ++ h = h - 4.188787; ++ b = 65535.0f*i/3.0f * (1.0f + s * cosf(h) / cosf(1.047196667f - h)); ++ r = 65535.0f*i/3.0f * (1.0f + s * (1.0f - cosf(h) / cosf(1.047196667f - h))); ++ g = 65535.0f*i/3.0f * (1.0f - s); ++ } ++ *r_out = r > 65535 ? 65535 : r; ++ *g_out = g > 65535 ? 65535 : g; ++ *b_out = b > 65535 ? 65535 : b; ++} ++ ++void lcd_backlight_color(uint8_t hue, uint8_t saturation, uint8_t intensity) { ++ uint16_t r, g, b; ++ float hue_f = 360.0f * (float)hue / 255.0f; ++ float saturation_f = (float)saturation / 255.0f; ++ float intensity_f = (float)intensity / 255.0f; ++ intensity_f *= (float)current_brightness / 255.0f; ++ hsi_to_rgb(hue_f, saturation_f, intensity_f, &r, &g, &b); ++ current_hue = hue; ++ current_saturation = saturation; ++ current_intensity = intensity; ++ lcd_backlight_hal_color(r, g, b); ++} ++ ++void lcd_backlight_brightness(uint8_t b) { ++ current_brightness = b; ++ lcd_backlight_color(current_hue, current_saturation, current_intensity); ++} diff --cc quantum/visualizer/lcd_backlight.h index 000000000,000000000..dd3e37a06 new file mode 100644 --- /dev/null +++ b/quantum/visualizer/lcd_backlight.h @@@ -1,0 -1,0 +1,42 @@@ ++/* ++The MIT License (MIT) ++ ++Copyright (c) 2016 Fred Sundvik ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy ++of this software and associated documentation files (the "Software"), to deal ++in the Software without restriction, including without limitation the rights ++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++copies of the Software, and to permit persons to whom the Software is ++furnished to do so, subject to the following conditions: ++ ++The above copyright notice and this permission notice shall be included in all ++copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++SOFTWARE. ++*/ ++ ++#ifndef LCD_BACKLIGHT_H_ ++#define LCD_BACKLIGHT_H_ ++#include "stdint.h" ++ ++// Helper macros for storing hue, staturation and intensity as unsigned integers ++#define LCD_COLOR(hue, saturation, intensity) (hue << 16 | saturation << 8 | intensity) ++#define LCD_HUE(color) ((color >> 16) & 0xFF) ++#define LCD_SAT(color) ((color >> 8) & 0xFF) ++#define LCD_INT(color) (color & 0xFF) ++ ++void lcd_backlight_init(void); ++void lcd_backlight_color(uint8_t hue, uint8_t saturation, uint8_t intensity); ++void lcd_backlight_brightness(uint8_t b); ++ ++void lcd_backlight_hal_init(void); ++void lcd_backlight_hal_color(uint16_t r, uint16_t g, uint16_t b); ++ ++#endif /* LCD_BACKLIGHT_H_ */ diff --cc quantum/visualizer/readme.md index 000000000,000000000..545ba2270 new file mode 100644 --- /dev/null +++ b/quantum/visualizer/readme.md @@@ -1,0 -1,0 +1,18 @@@ ++# A visualization library for the TMK keyboard firmware ++ ++This 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/) ++ 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/). ++ ++## To use this library as a user ++You can and should modify the visualizer\_user.c file. Check the comments in the file for more information. ++ ++## To add this library to custom keyboard projects ++ ++1. Add tmk_visualizer as a submodule to your project ++1. Set VISUALIZER_DIR in the main keyboard project makefile to point to the submodule ++1. Define LCD\_ENABLE and/or LCD\_BACKLIGHT\_ENABLE, to enable support ++1. Include the visualizer.mk make file ++1. Copy the files in the example\_integration folder to your keyboard project ++1. 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. ++1. Edit the files to match your hardware. You might might want to read the Chibios and UGfx documentation, for more information. ++1. 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 --cc quantum/visualizer/ugfx index 000000000,000000000..e221a6906 new file mode 160000 --- /dev/null +++ b/quantum/visualizer/ugfx @@@ -1,0 -1,0 +1,1 @@@ ++Subproject commit e221a690616e20f87e0b0088baffdbd5427be862 diff --cc quantum/visualizer/visualizer.c index 000000000,000000000..605be3059 new file mode 100644 --- /dev/null +++ b/quantum/visualizer/visualizer.c @@@ -1,0 -1,0 +1,481 @@@ ++/* ++The MIT License (MIT) ++ ++Copyright (c) 2016 Fred Sundvik ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy ++of this software and associated documentation files (the "Software"), to deal ++in the Software without restriction, including without limitation the rights ++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++copies of the Software, and to permit persons to whom the Software is ++furnished to do so, subject to the following conditions: ++ ++The above copyright notice and this permission notice shall be included in all ++copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++SOFTWARE. ++*/ ++ ++#include "visualizer.h" ++#include "ch.h" ++#include "config.h" ++#include ++ ++#ifdef LCD_ENABLE ++#include "gfx.h" ++#endif ++ ++#ifdef LCD_BACKLIGHT_ENABLE ++#include "lcd_backlight.h" ++#endif ++ ++//#define DEBUG_VISUALIZER ++ ++#ifdef DEBUG_VISUALIZER ++#include "debug.h" ++#else ++#include "nodebug.h" ++#endif ++ ++#ifdef USE_SERIAL_LINK ++#include "serial_link/protocol/transport.h" ++#include "serial_link/system/serial_link.h" ++#endif ++ ++// Define this in config.h ++#ifndef VISUALIZER_THREAD_PRIORITY ++#define "Visualizer thread priority not defined" ++#endif ++ ++ ++static visualizer_keyboard_status_t current_status = { ++ .layer = 0xFFFFFFFF, ++ .default_layer = 0xFFFFFFFF, ++ .leds = 0xFFFFFFFF, ++ .suspended = false, ++}; ++ ++static bool same_status(visualizer_keyboard_status_t* status1, visualizer_keyboard_status_t* status2) { ++ return status1->layer == status2->layer && ++ status1->default_layer == status2->default_layer && ++ status1->leds == status2->leds && ++ status1->suspended == status2->suspended; ++} ++ ++static event_source_t layer_changed_event; ++static bool visualizer_enabled = false; ++ ++#define MAX_SIMULTANEOUS_ANIMATIONS 4 ++static keyframe_animation_t* animations[MAX_SIMULTANEOUS_ANIMATIONS] = {}; ++ ++#ifdef USE_SERIAL_LINK ++MASTER_TO_ALL_SLAVES_OBJECT(current_status, visualizer_keyboard_status_t); ++ ++static remote_object_t* remote_objects[] = { ++ REMOTE_OBJECT(current_status), ++}; ++ ++#endif ++ ++ ++void start_keyframe_animation(keyframe_animation_t* animation) { ++ animation->current_frame = -1; ++ animation->time_left_in_frame = 0; ++ animation->need_update = true; ++ int free_index = -1; ++ for (int i=0;icurrent_frame = animation->num_frames; ++ animation->time_left_in_frame = 0; ++ animation->need_update = true; ++ for (int i=0;icurrent_frame = animations[i]->num_frames; ++ animations[i]->time_left_in_frame = 0; ++ animations[i]->need_update = true; ++ animations[i] = NULL; ++ } ++ } ++} ++ ++static bool update_keyframe_animation(keyframe_animation_t* animation, visualizer_state_t* state, systime_t delta, systime_t* sleep_time) { ++ dprintf("Animation frame%d, left %d, delta %d\n", animation->current_frame, ++ animation->time_left_in_frame, delta); ++ if (animation->current_frame == animation->num_frames) { ++ animation->need_update = false; ++ return false; ++ } ++ if (animation->current_frame == -1) { ++ animation->current_frame = 0; ++ animation->time_left_in_frame = animation->frame_lengths[0]; ++ animation->need_update = true; ++ } else { ++ animation->time_left_in_frame -= delta; ++ while (animation->time_left_in_frame <= 0) { ++ int left = animation->time_left_in_frame; ++ if (animation->need_update) { ++ animation->time_left_in_frame = 0; ++ (*animation->frame_functions[animation->current_frame])(animation, state); ++ } ++ animation->current_frame++; ++ animation->need_update = true; ++ if (animation->current_frame == animation->num_frames) { ++ if (animation->loop) { ++ animation->current_frame = 0; ++ } ++ else { ++ stop_keyframe_animation(animation); ++ return false; ++ } ++ } ++ delta = -left; ++ animation->time_left_in_frame = animation->frame_lengths[animation->current_frame]; ++ animation->time_left_in_frame -= delta; ++ } ++ } ++ if (animation->need_update) { ++ animation->need_update = (*animation->frame_functions[animation->current_frame])(animation, state); ++ } ++ ++ int wanted_sleep = animation->need_update ? 10 : animation->time_left_in_frame; ++ if ((unsigned)wanted_sleep < *sleep_time) { ++ *sleep_time = wanted_sleep; ++ } ++ ++ return true; ++} ++ ++bool keyframe_no_operation(keyframe_animation_t* animation, visualizer_state_t* state) { ++ (void)animation; ++ (void)state; ++ return false; ++} ++ ++#ifdef LCD_BACKLIGHT_ENABLE ++bool keyframe_animate_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state) { ++ int frame_length = animation->frame_lengths[animation->current_frame]; ++ int current_pos = frame_length - animation->time_left_in_frame; ++ uint8_t t_h = LCD_HUE(state->target_lcd_color); ++ uint8_t t_s = LCD_SAT(state->target_lcd_color); ++ uint8_t t_i = LCD_INT(state->target_lcd_color); ++ uint8_t p_h = LCD_HUE(state->prev_lcd_color); ++ uint8_t p_s = LCD_SAT(state->prev_lcd_color); ++ uint8_t p_i = LCD_INT(state->prev_lcd_color); ++ ++ uint8_t d_h1 = t_h - p_h; //Modulo arithmetic since we want to wrap around ++ int d_h2 = t_h - p_h; ++ // Chose the shortest way around ++ int d_h = abs(d_h2) < d_h1 ? d_h2 : d_h1; ++ int d_s = t_s - p_s; ++ int d_i = t_i - p_i; ++ ++ int hue = (d_h * current_pos) / frame_length; ++ int sat = (d_s * current_pos) / frame_length; ++ int intensity = (d_i * current_pos) / frame_length; ++ //dprintf("%X -> %X = %X\n", p_h, t_h, hue); ++ hue += p_h; ++ sat += p_s; ++ intensity += p_i; ++ state->current_lcd_color = LCD_COLOR(hue, sat, intensity); ++ lcd_backlight_color( ++ LCD_HUE(state->current_lcd_color), ++ LCD_SAT(state->current_lcd_color), ++ LCD_INT(state->current_lcd_color)); ++ ++ return true; ++} ++ ++bool keyframe_set_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state) { ++ (void)animation; ++ state->prev_lcd_color = state->target_lcd_color; ++ state->current_lcd_color = state->target_lcd_color; ++ lcd_backlight_color( ++ LCD_HUE(state->current_lcd_color), ++ LCD_SAT(state->current_lcd_color), ++ LCD_INT(state->current_lcd_color)); ++ return false; ++} ++#endif // LCD_BACKLIGHT_ENABLE ++ ++#ifdef LCD_ENABLE ++bool keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state) { ++ (void)animation; ++ gdispClear(White); ++ gdispDrawString(0, 10, state->layer_text, state->font_dejavusansbold12, Black); ++ gdispFlush(); ++ return false; ++} ++ ++static void format_layer_bitmap_string(uint16_t default_layer, uint16_t layer, char* buffer) { ++ for (int i=0; i<16;i++) ++ { ++ uint32_t mask = (1u << i); ++ if (default_layer & mask) { ++ if (layer & mask) { ++ *buffer = 'B'; ++ } else { ++ *buffer = 'D'; ++ } ++ } else if (layer & mask) { ++ *buffer = '1'; ++ } else { ++ *buffer = '0'; ++ } ++ ++buffer; ++ ++ if (i==3 || i==7 || i==11) { ++ *buffer = ' '; ++ ++buffer; ++ } ++ } ++ *buffer = 0; ++} ++ ++bool keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state) { ++ (void)animation; ++ const char* layer_help = "1=On D=Default B=Both"; ++ char layer_buffer[16 + 4]; // 3 spaces and one null terminator ++ gdispClear(White); ++ gdispDrawString(0, 0, layer_help, state->font_fixed5x8, Black); ++ format_layer_bitmap_string(state->status.default_layer, state->status.layer, layer_buffer); ++ gdispDrawString(0, 10, layer_buffer, state->font_fixed5x8, Black); ++ format_layer_bitmap_string(state->status.default_layer >> 16, state->status.layer >> 16, layer_buffer); ++ gdispDrawString(0, 20, layer_buffer, state->font_fixed5x8, Black); ++ gdispFlush(); ++ return false; ++} ++#endif // LCD_ENABLE ++ ++bool keyframe_disable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state) { ++ (void)animation; ++ (void)state; ++#ifdef LCD_ENABLE ++ gdispSetPowerMode(powerOff); ++#endif ++#ifdef LCD_BACKLIGHT_ENABLE ++ lcd_backlight_hal_color(0, 0, 0); ++#endif ++ return false; ++} ++ ++bool keyframe_enable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state) { ++ (void)animation; ++ (void)state; ++#ifdef LCD_ENABLE ++ gdispSetPowerMode(powerOn); ++#endif ++ return false; ++} ++ ++bool enable_visualization(keyframe_animation_t* animation, visualizer_state_t* state) { ++ (void)animation; ++ (void)state; ++ dprint("User visualizer inited\n"); ++ visualizer_enabled = true; ++ return false; ++} ++ ++// TODO: Optimize the stack size, this is probably way too big ++static THD_WORKING_AREA(visualizerThreadStack, 1024); ++static THD_FUNCTION(visualizerThread, arg) { ++ (void)arg; ++ ++ event_listener_t event_listener; ++ chEvtRegister(&layer_changed_event, &event_listener, 0); ++ ++ visualizer_keyboard_status_t initial_status = { ++ .default_layer = 0xFFFFFFFF, ++ .layer = 0xFFFFFFFF, ++ .leds = 0xFFFFFFFF, ++ .suspended = false, ++ }; ++ ++ visualizer_state_t state = { ++ .status = initial_status, ++ .current_lcd_color = 0, ++#ifdef LCD_ENABLE ++ .font_fixed5x8 = gdispOpenFont("fixed_5x8"), ++ .font_dejavusansbold12 = gdispOpenFont("DejaVuSansBold12") ++#endif ++ }; ++ initialize_user_visualizer(&state); ++ state.prev_lcd_color = state.current_lcd_color; ++ ++#ifdef LCD_BACKLIGHT_ENABLE ++ lcd_backlight_color( ++ LCD_HUE(state.current_lcd_color), ++ LCD_SAT(state.current_lcd_color), ++ LCD_INT(state.current_lcd_color)); ++#endif ++ ++ systime_t sleep_time = TIME_INFINITE; ++ systime_t current_time = chVTGetSystemTimeX(); ++ ++ while(true) { ++ systime_t new_time = chVTGetSystemTimeX(); ++ systime_t delta = new_time - current_time; ++ current_time = new_time; ++ bool enabled = visualizer_enabled; ++ if (!same_status(&state.status, ¤t_status)) { ++ if (visualizer_enabled) { ++ if (current_status.suspended) { ++ stop_all_keyframe_animations(); ++ visualizer_enabled = false; ++ state.status = current_status; ++ user_visualizer_suspend(&state); ++ } ++ else { ++ state.status = current_status; ++ update_user_visualizer_state(&state); ++ } ++ state.prev_lcd_color = state.current_lcd_color; ++ } ++ } ++ if (!enabled && state.status.suspended && current_status.suspended == false) { ++ // Setting the status to the initial status will force an update ++ // when the visualizer is enabled again ++ state.status = initial_status; ++ state.status.suspended = false; ++ stop_all_keyframe_animations(); ++ user_visualizer_resume(&state); ++ state.prev_lcd_color = state.current_lcd_color; ++ } ++ sleep_time = TIME_INFINITE; ++ for (int i=0;i update_delta) { ++ sleep_time -= update_delta; ++ } ++ else { ++ sleep_time = 0; ++ } ++ } ++ dprintf("Update took %d, last delta %d, sleep_time %d\n", update_delta, delta, sleep_time); ++ chEvtWaitOneTimeout(EVENT_MASK(0), sleep_time); ++ } ++#ifdef LCD_ENABLE ++ gdispCloseFont(state.font_fixed5x8); ++ gdispCloseFont(state.font_dejavusansbold12); ++#endif ++} ++ ++void visualizer_init(void) { ++#ifdef LCD_ENABLE ++ gfxInit(); ++#endif ++ ++#ifdef LCD_BACKLIGHT_ENABLE ++ lcd_backlight_init(); ++#endif ++ ++#ifdef USE_SERIAL_LINK ++ add_remote_objects(remote_objects, sizeof(remote_objects) / sizeof(remote_object_t*) ); ++#endif ++ // We are using a low priority thread, the idea is to have it run only ++ // when the main thread is sleeping during the matrix scanning ++ chEvtObjectInit(&layer_changed_event); ++ (void)chThdCreateStatic(visualizerThreadStack, sizeof(visualizerThreadStack), ++ VISUALIZER_THREAD_PRIORITY, visualizerThread, NULL); ++} ++ ++void update_status(bool changed) { ++ if (changed) { ++ chEvtBroadcast(&layer_changed_event); ++ } ++#ifdef USE_SERIAL_LINK ++ static systime_t last_update = 0; ++ systime_t current_update = chVTGetSystemTimeX(); ++ systime_t delta = current_update - last_update; ++ if (changed || delta > MS2ST(10)) { ++ last_update = current_update; ++ visualizer_keyboard_status_t* r = begin_write_current_status(); ++ *r = current_status; ++ end_write_current_status(); ++ } ++#endif ++} ++ ++void visualizer_update(uint32_t default_state, uint32_t state, uint32_t leds) { ++ // Note that there's a small race condition here, the thread could read ++ // a state where one of these are set but not the other. But this should ++ // not really matter as it will be fixed during the next loop step. ++ // Alternatively a mutex could be used instead of the volatile variables ++ ++ bool changed = false; ++#ifdef USE_SERIAL_LINK ++ if (is_serial_link_connected ()) { ++ visualizer_keyboard_status_t* new_status = read_current_status(); ++ if (new_status) { ++ if (!same_status(¤t_status, new_status)) { ++ changed = true; ++ current_status = *new_status; ++ } ++ } ++ } ++ else { ++#else ++ { ++#endif ++ visualizer_keyboard_status_t new_status = { ++ .layer = state, ++ .default_layer = default_state, ++ .leds = leds, ++ .suspended = current_status.suspended, ++ }; ++ if (!same_status(¤t_status, &new_status)) { ++ changed = true; ++ current_status = new_status; ++ } ++ } ++ update_status(changed); ++} ++ ++void visualizer_suspend(void) { ++ current_status.suspended = true; ++ update_status(true); ++} ++ ++void visualizer_resume(void) { ++ current_status.suspended = false; ++ update_status(true); ++} diff --cc quantum/visualizer/visualizer.h index 000000000,000000000..22798cda6 new file mode 100644 --- /dev/null +++ b/quantum/visualizer/visualizer.h @@@ -1,0 -1,0 +1,131 @@@ ++/* ++The MIT License (MIT) ++ ++Copyright (c) 2016 Fred Sundvik ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy ++of this software and associated documentation files (the "Software"), to deal ++in the Software without restriction, including without limitation the rights ++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++copies of the Software, and to permit persons to whom the Software is ++furnished to do so, subject to the following conditions: ++ ++The above copyright notice and this permission notice shall be included in all ++copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++SOFTWARE. ++*/ ++ ++#ifndef VISUALIZER_H ++#define VISUALIZER_H ++#include ++#include ++#include ++ ++#ifdef LCD_ENABLE ++#include "gfx.h" ++#endif ++ ++#ifdef LCD_BACKLIGHT_ENABLE ++#include "lcd_backlight.h" ++#endif ++ ++// This need to be called once at the start ++void visualizer_init(void); ++// This should be called at every matrix scan ++void visualizer_update(uint32_t default_state, uint32_t state, uint32_t leds); ++// This should be called when the keyboard goes to suspend state ++void visualizer_suspend(void); ++// This should be called when the keyboard wakes up from suspend state ++void visualizer_resume(void); ++ ++// If you need support for more than 8 keyframes per animation, you can change this ++#define MAX_VISUALIZER_KEY_FRAMES 8 ++ ++struct keyframe_animation_t; ++ ++typedef struct { ++ uint32_t layer; ++ uint32_t default_layer; ++ uint32_t leds; // See led.h for available statuses ++ bool suspended; ++} visualizer_keyboard_status_t; ++ ++// The state struct is used by the various keyframe functions ++// It's also used for setting the LCD color and layer text ++// from the user customized code ++typedef struct visualizer_state_t { ++ // The user code should primarily be modifying these ++ uint32_t target_lcd_color; ++ const char* layer_text; ++ ++ // The user visualizer(and animation functions) can read these ++ visualizer_keyboard_status_t status; ++ ++ // These are used by the animation functions ++ uint32_t current_lcd_color; ++ uint32_t prev_lcd_color; ++#ifdef LCD_ENABLE ++ font_t font_fixed5x8; ++ font_t font_dejavusansbold12; ++#endif ++} visualizer_state_t; ++ ++// Any custom keyframe function should have this signature ++// return true to get continuous updates, otherwise you will only get one ++// update per frame ++typedef bool (*frame_func)(struct keyframe_animation_t*, visualizer_state_t*); ++ ++// Represents a keyframe animation, so fields are internal to the system ++// while others are meant to be initialized by the user code ++typedef struct keyframe_animation_t { ++ // These should be initialized ++ int num_frames; ++ bool loop; ++ int frame_lengths[MAX_VISUALIZER_KEY_FRAMES]; ++ frame_func frame_functions[MAX_VISUALIZER_KEY_FRAMES]; ++ ++ // Used internally by the system, and can also be read by ++ // keyframe update functions ++ int current_frame; ++ int time_left_in_frame; ++ bool need_update; ++ ++} keyframe_animation_t; ++ ++void start_keyframe_animation(keyframe_animation_t* animation); ++void stop_keyframe_animation(keyframe_animation_t* animation); ++ ++// Some predefined keyframe functions that can be used by the user code ++// Does nothing, useful for adding delays ++bool keyframe_no_operation(keyframe_animation_t* animation, visualizer_state_t* state); ++// Animates the LCD backlight color between the current color and the target color (of the state) ++bool keyframe_animate_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state); ++// Sets the backlight color to the target color ++bool keyframe_set_backlight_color(keyframe_animation_t* animation, visualizer_state_t* state); ++// Displays the layer text centered vertically on the screen ++bool keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state); ++// Displays a bitmap (0/1) of all the currently active layers ++bool keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state); ++ ++bool keyframe_disable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state); ++bool keyframe_enable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state); ++ ++// Call this once, when the initial animation has finished, alternatively you can call it ++// directly from the initalize_user_visualizer function (the animation can be null) ++bool enable_visualization(keyframe_animation_t* animation, visualizer_state_t* state); ++ ++// These two functions have to be implemented by the user ++void initialize_user_visualizer(visualizer_state_t* state); ++void update_user_visualizer_state(visualizer_state_t* state); ++void user_visualizer_suspend(visualizer_state_t* state); ++void user_visualizer_resume(visualizer_state_t* state); ++ ++ ++#endif /* VISUALIZER_H */ diff --cc quantum/visualizer/visualizer.mk index 000000000,000000000..13c5d3158 new file mode 100644 --- /dev/null +++ b/quantum/visualizer/visualizer.mk @@@ -1,0 -1,0 +1,41 @@@ ++# The MIT License (MIT) ++# ++# Copyright (c) 2016 Fred Sundvik ++# ++# Permission is hereby granted, free of charge, to any person obtaining a copy ++# of this software and associated documentation files (the "Software"), to deal ++# in the Software without restriction, including without limitation the rights ++# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++# copies of the Software, and to permit persons to whom the Software is ++# furnished to do so, subject to the following conditions: ++# ++# The above copyright notice and this permission notice shall be included in all ++# copies or substantial portions of the Software. ++# ++# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++# SOFTWARE. ++ ++GFXLIB = $(VISUALIZER_DIR)/ugfx ++ifdef LCD_ENABLE ++include $(GFXLIB)/gfx.mk ++UDEFS += -DLCD_ENABLE ++ULIBS += -lm ++endif ++SRC += $(GFXSRC) $(VISUALIZER_DIR)/visualizer.c ++UINCDIR += $(GFXINC) $(VISUALIZER_DIR) ++ ++ifdef LCD_BACKLIGHT_ENABLE ++SRC += $(VISUALIZER_DIR)/lcd_backlight.c ++SRC += lcd_backlight_hal.c ++UDEFS += -DLCD_BACKLIGHT_ENABLE ++endif ++ ++ifndef VISUALIZER_USER ++VISUALIZER_USER = visualizer_user.c ++endif ++SRC += $(VISUALIZER_USER)