瀏覽代碼

Merge pull request #1217 from fredizzimo/ergodox_default_visualizer

Enable Ergodox Infinity LCD visualization
Jack Humbert 8 年之前
父節點
當前提交
e5f610b70e
共有 43 個文件被更改,包括 1787 次插入1302 次删除
  1. 103 79
      build_keyboard.mk
  2. 0 4
      keyboards/ergodox/ez/rules.mk
  3. 1 1
      keyboards/ergodox/infinity/Makefile
  4. 107 0
      keyboards/ergodox/infinity/animations.c
  5. 30 0
      keyboards/ergodox/infinity/animations.h
  6. 3 1
      keyboards/ergodox/infinity/config.h
  7. 5 32
      keyboards/ergodox/infinity/drivers/gdisp/IS31FL3731C/gdisp_IS31FL3731C.c
  8. 33 47
      keyboards/ergodox/infinity/drivers/gdisp/st7565ergodox/board_ST7565.h
  9. 224 187
      keyboards/ergodox/infinity/drivers/gdisp/st7565ergodox/gdisp_lld_ST7565.c
  10. 6 5
      keyboards/ergodox/infinity/drivers/gdisp/st7565ergodox/gdisp_lld_config.h
  11. 2 0
      keyboards/ergodox/infinity/drivers/gdisp/st7565ergodox/st7565.h
  12. 1 1
      keyboards/ergodox/infinity/gfxconf.h
  13. 44 7
      keyboards/ergodox/infinity/infinity.c
  14. 41 30
      keyboards/ergodox/infinity/infinity.h
  15. 5 8
      keyboards/ergodox/infinity/rules.mk
  16. 123 0
      keyboards/ergodox/infinity/simple_visualizer.h
  17. 329 0
      keyboards/ergodox/infinity/visualizer.c
  18. 42 0
      keyboards/ergodox/keymaps/default/visualizer.c
  19. 71 0
      quantum/led_tables.c
  20. 30 0
      quantum/led_tables.h
  21. 5 53
      quantum/rgblight.c
  22. 1 1
      quantum/serial_link/system/serial_link.c
  23. 0 36
      quantum/visualizer/example_integration/callbacks.c
  24. 0 325
      quantum/visualizer/example_integration/gfxconf.h
  25. 0 91
      quantum/visualizer/example_integration/lcd_backlight_hal.c
  26. 0 121
      quantum/visualizer/example_integration/visualizer_user.c
  27. 4 4
      quantum/visualizer/lcd_backlight.c
  28. 4 0
      quantum/visualizer/lcd_backlight.h
  29. 77 0
      quantum/visualizer/lcd_backlight_keyframes.c
  30. 30 0
      quantum/visualizer/lcd_backlight_keyframes.h
  31. 188 0
      quantum/visualizer/lcd_keyframes.c
  32. 39 0
      quantum/visualizer/lcd_keyframes.h
  33. 8 49
      quantum/visualizer/led_keyframes.c
  34. 10 10
      quantum/visualizer/led_keyframes.h
  35. 61 0
      quantum/visualizer/resources/lcd_logo.c
  36. 二進制
      quantum/visualizer/resources/lcd_logo.png
  37. 27 0
      quantum/visualizer/resources/resources.h
  38. 47 179
      quantum/visualizer/visualizer.c
  39. 17 24
      quantum/visualizer/visualizer.h
  40. 15 6
      quantum/visualizer/visualizer.mk
  41. 23 0
      quantum/visualizer/visualizer_keyframes.c
  42. 26 0
      quantum/visualizer/visualizer_keyframes.h
  43. 5 1
      tmk_core/common/action_util.c

+ 103 - 79
build_keyboard.mk

@@ -7,11 +7,11 @@ endif
 include common.mk
 include common.mk
 
 
 ifneq ($(SUBPROJECT),)
 ifneq ($(SUBPROJECT),)
-	TARGET ?= $(KEYBOARD)_$(SUBPROJECT)_$(KEYMAP)
-	KEYBOARD_OUTPUT := $(BUILD_DIR)/obj_$(KEYBOARD)_$(SUBPROJECT)
+    TARGET ?= $(KEYBOARD)_$(SUBPROJECT)_$(KEYMAP)
+    KEYBOARD_OUTPUT := $(BUILD_DIR)/obj_$(KEYBOARD)_$(SUBPROJECT)
 else
 else
-	TARGET ?= $(KEYBOARD)_$(KEYMAP)
-	KEYBOARD_OUTPUT := $(BUILD_DIR)/obj_$(KEYBOARD)
+    TARGET ?= $(KEYBOARD)_$(KEYMAP)
+    KEYBOARD_OUTPUT := $(BUILD_DIR)/obj_$(KEYBOARD)
 endif
 endif
 
 
 # Force expansion
 # Force expansion
@@ -20,15 +20,15 @@ TARGET := $(TARGET)
 
 
 MASTER ?= left
 MASTER ?= left
 ifdef master
 ifdef master
-	MASTER = $(master)
+    MASTER = $(master)
 endif
 endif
 
 
 ifeq ($(MASTER),right)
 ifeq ($(MASTER),right)
-	OPT_DEFS += -DMASTER_IS_ON_RIGHT
+    OPT_DEFS += -DMASTER_IS_ON_RIGHT
 else
 else
-	ifneq ($(MASTER),left)
+    ifneq ($(MASTER),left)
 $(error MASTER does not have a valid value(left/right))
 $(error MASTER does not have a valid value(left/right))
-	endif
+    endif
 endif
 endif
 
 
 
 
@@ -56,31 +56,31 @@ endif
 
 
 # We can assume a ChibiOS target When MCU_FAMILY is defined, since it's not used for LUFA
 # We can assume a ChibiOS target When MCU_FAMILY is defined, since it's not used for LUFA
 ifdef MCU_FAMILY
 ifdef MCU_FAMILY
-	PLATFORM=CHIBIOS
+    PLATFORM=CHIBIOS
 else
 else
-	PLATFORM=AVR
+    PLATFORM=AVR
 endif
 endif
 
 
 ifeq ($(PLATFORM),CHIBIOS)
 ifeq ($(PLATFORM),CHIBIOS)
-	include $(TMK_PATH)/protocol/chibios.mk
-	include $(TMK_PATH)/chibios.mk
-	OPT_OS = chibios
-	ifneq ("$(wildcard $(SUBPROJECT_PATH)/bootloader_defs.h)","")
-		OPT_DEFS += -include $(SUBPROJECT_PATH)/bootloader_defs.h
-	else ifneq ("$(wildcard $(SUBPROJECT_PATH)/boards/$(BOARD)/bootloader_defs.h)","")
-		OPT_DEFS += -include $(SUBPROJECT_PATH)/boards/$(BOARD)/bootloader_defs.h
-	else ifneq ("$(wildcard $(KEYBOARD_PATH)/bootloader_defs.h)","")
-		OPT_DEFS += -include $(KEYBOARD_PATH)/bootloader_defs.h
-	else ifneq ("$(wildcard $(KEYBOARD_PATH)/boards/$(BOARD)/bootloader_defs.h)","")
-		OPT_DEFS += -include $(KEYBOARD_PATH)/boards/$(BOARD)/bootloader_defs.h
-	endif
+    include $(TMK_PATH)/protocol/chibios.mk
+    include $(TMK_PATH)/chibios.mk
+    OPT_OS = chibios
+    ifneq ("$(wildcard $(SUBPROJECT_PATH)/bootloader_defs.h)","")
+        OPT_DEFS += -include $(SUBPROJECT_PATH)/bootloader_defs.h
+    else ifneq ("$(wildcard $(SUBPROJECT_PATH)/boards/$(BOARD)/bootloader_defs.h)","")
+        OPT_DEFS += -include $(SUBPROJECT_PATH)/boards/$(BOARD)/bootloader_defs.h
+    else ifneq ("$(wildcard $(KEYBOARD_PATH)/bootloader_defs.h)","")
+        OPT_DEFS += -include $(KEYBOARD_PATH)/bootloader_defs.h
+    else ifneq ("$(wildcard $(KEYBOARD_PATH)/boards/$(BOARD)/bootloader_defs.h)","")
+        OPT_DEFS += -include $(KEYBOARD_PATH)/boards/$(BOARD)/bootloader_defs.h
+    endif
 endif
 endif
 
 
 CONFIG_H = $(KEYBOARD_PATH)/config.h
 CONFIG_H = $(KEYBOARD_PATH)/config.h
 ifneq ($(SUBPROJECT),)
 ifneq ($(SUBPROJECT),)
-	ifneq ("$(wildcard $(SUBPROJECT_C))","")
-		CONFIG_H = $(SUBPROJECT_PATH)/config.h
-	endif
+    ifneq ("$(wildcard $(SUBPROJECT_C))","")
+        CONFIG_H = $(SUBPROJECT_PATH)/config.h
+    endif
 endif
 endif
 
 
 # Save the defines and includes here, so we don't include any keymap specific ones
 # Save the defines and includes here, so we don't include any keymap specific ones
@@ -112,30 +112,30 @@ KEYMAP_OUTPUT := $(BUILD_DIR)/obj_$(TARGET)
 
 
 
 
 ifneq ("$(wildcard $(KEYMAP_PATH)/config.h)","")
 ifneq ("$(wildcard $(KEYMAP_PATH)/config.h)","")
-	CONFIG_H = $(KEYMAP_PATH)/config.h
+    CONFIG_H = $(KEYMAP_PATH)/config.h
 endif
 endif
 
 
 # # project specific files
 # # project specific files
 SRC += $(KEYBOARD_C) \
 SRC += $(KEYBOARD_C) \
-	$(KEYMAP_C) \
-	$(QUANTUM_DIR)/quantum.c \
-	$(QUANTUM_DIR)/keymap_common.c \
-	$(QUANTUM_DIR)/keycode_config.c \
-	$(QUANTUM_DIR)/process_keycode/process_leader.c
+    $(KEYMAP_C) \
+    $(QUANTUM_DIR)/quantum.c \
+    $(QUANTUM_DIR)/keymap_common.c \
+    $(QUANTUM_DIR)/keycode_config.c \
+    $(QUANTUM_DIR)/process_keycode/process_leader.c
 
 
 ifneq ($(SUBPROJECT),)
 ifneq ($(SUBPROJECT),)
-	SRC += $(SUBPROJECT_C)
+    SRC += $(SUBPROJECT_C)
 endif
 endif
 
 
 ifndef CUSTOM_MATRIX
 ifndef CUSTOM_MATRIX
-	SRC += $(QUANTUM_DIR)/matrix.c
+    SRC += $(QUANTUM_DIR)/matrix.c
 endif
 endif
 
 
 ifeq ($(strip $(API_SYSEX_ENABLE)), yes)
 ifeq ($(strip $(API_SYSEX_ENABLE)), yes)
-	OPT_DEFS += -DAPI_SYSEX_ENABLE
-	SRC += $(QUANTUM_DIR)/api/api_sysex.c
-	OPT_DEFS += -DAPI_ENABLE
-	SRC += $(QUANTUM_DIR)/api.c
+    OPT_DEFS += -DAPI_SYSEX_ENABLE
+    SRC += $(QUANTUM_DIR)/api/api_sysex.c
+    OPT_DEFS += -DAPI_ENABLE
+    SRC += $(QUANTUM_DIR)/api.c
     MIDI_ENABLE=yes
     MIDI_ENABLE=yes
 endif
 endif
 
 
@@ -144,25 +144,25 @@ MUSIC_ENABLE := 0
 ifeq ($(strip $(AUDIO_ENABLE)), yes)
 ifeq ($(strip $(AUDIO_ENABLE)), yes)
     OPT_DEFS += -DAUDIO_ENABLE
     OPT_DEFS += -DAUDIO_ENABLE
     MUSIC_ENABLE := 1
     MUSIC_ENABLE := 1
-	SRC += $(QUANTUM_DIR)/process_keycode/process_audio.c
-	SRC += $(QUANTUM_DIR)/audio/audio.c
-	SRC += $(QUANTUM_DIR)/audio/voices.c
-	SRC += $(QUANTUM_DIR)/audio/luts.c
+    SRC += $(QUANTUM_DIR)/process_keycode/process_audio.c
+    SRC += $(QUANTUM_DIR)/audio/audio.c
+    SRC += $(QUANTUM_DIR)/audio/voices.c
+    SRC += $(QUANTUM_DIR)/audio/luts.c
 endif
 endif
 
 
 ifeq ($(strip $(MIDI_ENABLE)), yes)
 ifeq ($(strip $(MIDI_ENABLE)), yes)
     OPT_DEFS += -DMIDI_ENABLE
     OPT_DEFS += -DMIDI_ENABLE
-	MUSIC_ENABLE := 1
-	SRC += $(QUANTUM_DIR)/process_keycode/process_midi.c
+    MUSIC_ENABLE := 1
+    SRC += $(QUANTUM_DIR)/process_keycode/process_midi.c
 endif
 endif
 
 
 ifeq ($(MUSIC_ENABLE), 1)
 ifeq ($(MUSIC_ENABLE), 1)
-	SRC += $(QUANTUM_DIR)/process_keycode/process_music.c
+    SRC += $(QUANTUM_DIR)/process_keycode/process_music.c
 endif
 endif
 
 
 ifeq ($(strip $(COMBO_ENABLE)), yes)
 ifeq ($(strip $(COMBO_ENABLE)), yes)
     OPT_DEFS += -DCOMBO_ENABLE
     OPT_DEFS += -DCOMBO_ENABLE
-	SRC += $(QUANTUM_DIR)/process_keycode/process_combo.c
+    SRC += $(QUANTUM_DIR)/process_keycode/process_combo.c
 endif
 endif
 
 
 ifeq ($(strip $(VIRTSER_ENABLE)), yes)
 ifeq ($(strip $(VIRTSER_ENABLE)), yes)
@@ -171,56 +171,80 @@ endif
 
 
 ifeq ($(strip $(FAUXCLICKY_ENABLE)), yes)
 ifeq ($(strip $(FAUXCLICKY_ENABLE)), yes)
     OPT_DEFS += -DFAUXCLICKY_ENABLE
     OPT_DEFS += -DFAUXCLICKY_ENABLE
-	SRC += $(QUANTUM_DIR)/fauxclicky.c
+    SRC += $(QUANTUM_DIR)/fauxclicky.c
 endif
 endif
 
 
 ifeq ($(strip $(UCIS_ENABLE)), yes)
 ifeq ($(strip $(UCIS_ENABLE)), yes)
-	OPT_DEFS += -DUCIS_ENABLE
-	SRC += $(QUANTUM_DIR)/process_keycode/process_unicode_common.c
-	SRC += $(QUANTUM_DIR)/process_keycode/process_ucis.c
+    OPT_DEFS += -DUCIS_ENABLE
+    SRC += $(QUANTUM_DIR)/process_keycode/process_unicode_common.c
+    SRC += $(QUANTUM_DIR)/process_keycode/process_ucis.c
 endif
 endif
 
 
 ifeq ($(strip $(UNICODEMAP_ENABLE)), yes)
 ifeq ($(strip $(UNICODEMAP_ENABLE)), yes)
-	OPT_DEFS += -DUNICODEMAP_ENABLE
-	SRC += $(QUANTUM_DIR)/process_keycode/process_unicode_common.c
-	SRC += $(QUANTUM_DIR)/process_keycode/process_unicodemap.c
+    OPT_DEFS += -DUNICODEMAP_ENABLE
+    SRC += $(QUANTUM_DIR)/process_keycode/process_unicode_common.c
+    SRC += $(QUANTUM_DIR)/process_keycode/process_unicodemap.c
 endif
 endif
 
 
 ifeq ($(strip $(UNICODE_ENABLE)), yes)
 ifeq ($(strip $(UNICODE_ENABLE)), yes)
     OPT_DEFS += -DUNICODE_ENABLE
     OPT_DEFS += -DUNICODE_ENABLE
-	SRC += $(QUANTUM_DIR)/process_keycode/process_unicode_common.c
-	SRC += $(QUANTUM_DIR)/process_keycode/process_unicode.c
+    SRC += $(QUANTUM_DIR)/process_keycode/process_unicode_common.c
+    SRC += $(QUANTUM_DIR)/process_keycode/process_unicode.c
 endif
 endif
 
 
 ifeq ($(strip $(RGBLIGHT_ENABLE)), yes)
 ifeq ($(strip $(RGBLIGHT_ENABLE)), yes)
-	OPT_DEFS += -DRGBLIGHT_ENABLE
-	SRC += $(QUANTUM_DIR)/light_ws2812.c
-	SRC += $(QUANTUM_DIR)/rgblight.c
+    OPT_DEFS += -DRGBLIGHT_ENABLE
+    SRC += $(QUANTUM_DIR)/light_ws2812.c
+    SRC += $(QUANTUM_DIR)/rgblight.c
+    CIE1931_CURVE = yes
+    LED_BREATHING_TABLE = yes
 endif
 endif
 
 
 ifeq ($(strip $(TAP_DANCE_ENABLE)), yes)
 ifeq ($(strip $(TAP_DANCE_ENABLE)), yes)
-	OPT_DEFS += -DTAP_DANCE_ENABLE
-	SRC += $(QUANTUM_DIR)/process_keycode/process_tap_dance.c
+    OPT_DEFS += -DTAP_DANCE_ENABLE
+    SRC += $(QUANTUM_DIR)/process_keycode/process_tap_dance.c
 endif
 endif
 
 
 ifeq ($(strip $(PRINTING_ENABLE)), yes)
 ifeq ($(strip $(PRINTING_ENABLE)), yes)
-	OPT_DEFS += -DPRINTING_ENABLE
-	SRC += $(QUANTUM_DIR)/process_keycode/process_printer.c
-	SRC += $(TMK_DIR)/protocol/serial_uart.c
+    OPT_DEFS += -DPRINTING_ENABLE
+    SRC += $(QUANTUM_DIR)/process_keycode/process_printer.c
+    SRC += $(TMK_DIR)/protocol/serial_uart.c
 endif
 endif
 
 
 ifeq ($(strip $(SERIAL_LINK_ENABLE)), yes)
 ifeq ($(strip $(SERIAL_LINK_ENABLE)), yes)
-	SRC += $(patsubst $(QUANTUM_PATH)/%,%,$(SERIAL_SRC))
-	OPT_DEFS += $(SERIAL_DEFS)
-	VAPTH += $(SERIAL_PATH)
+    SRC += $(patsubst $(QUANTUM_PATH)/%,%,$(SERIAL_SRC))
+    OPT_DEFS += $(SERIAL_DEFS)
+    VAPTH += $(SERIAL_PATH)
 endif
 endif
 
 
 ifneq ($(strip $(VARIABLE_TRACE)),)
 ifneq ($(strip $(VARIABLE_TRACE)),)
-	SRC += $(QUANTUM_DIR)/variable_trace.c
-	OPT_DEFS += -DNUM_TRACED_VARIABLES=$(strip $(VARIABLE_TRACE))
+    SRC += $(QUANTUM_DIR)/variable_trace.c
+    OPT_DEFS += -DNUM_TRACED_VARIABLES=$(strip $(VARIABLE_TRACE))
 ifneq ($(strip $(MAX_VARIABLE_TRACE_SIZE)),)
 ifneq ($(strip $(MAX_VARIABLE_TRACE_SIZE)),)
-	OPT_DEFS += -DMAX_VARIABLE_TRACE_SIZE=$(strip $(MAX_VARIABLE_TRACE_SIZE))
+    OPT_DEFS += -DMAX_VARIABLE_TRACE_SIZE=$(strip $(MAX_VARIABLE_TRACE_SIZE))
+endif
+endif
+
+ifeq ($(strip $(LCD_ENABLE)), yes)
+    CIE1931_CURVE = yes
 endif
 endif
+
+ifeq ($(strip $(LED_ENABLE)), yes)
+    CIE1931_CURVE = yes
+endif
+
+ifeq ($(strip $(CIE1931_CURVE)), yes)
+    OPT_DEFS += -DUSE_CIE1931_CURVE
+    LED_TABLES = yes
+endif
+
+ifeq ($(strip $(LED_BREATHING_TABLE)), yes)
+    OPT_DEFS += -DUSE_LED_BREATHING_TABLE
+    LED_TABLES = yes
+endif
+
+ifeq ($(strip $(LED_TABLES)), yes)
+    SRC += $(QUANTUM_DIR)/led_tables.c
 endif
 endif
 
 
 # Optimize size but this may cause error "relocation truncated to fit"
 # Optimize size but this may cause error "relocation truncated to fit"
@@ -229,7 +253,7 @@ endif
 # Search Path
 # Search Path
 VPATH += $(KEYMAP_PATH)
 VPATH += $(KEYMAP_PATH)
 ifneq ($(SUBPROJECT),)
 ifneq ($(SUBPROJECT),)
-	VPATH += $(SUBPROJECT_PATH)
+    VPATH += $(SUBPROJECT_PATH)
 endif
 endif
 VPATH += $(KEYBOARD_PATH)
 VPATH += $(KEYBOARD_PATH)
 VPATH += $(COMMON_VPATH)
 VPATH += $(COMMON_VPATH)
@@ -243,27 +267,27 @@ EXTRALDFLAGS += $(TMK_COMMON_LDFLAGS)
 
 
 ifeq ($(PLATFORM),AVR)
 ifeq ($(PLATFORM),AVR)
 ifeq ($(strip $(PROTOCOL)), VUSB)
 ifeq ($(strip $(PROTOCOL)), VUSB)
-	include $(TMK_PATH)/protocol/vusb.mk
+    include $(TMK_PATH)/protocol/vusb.mk
 else
 else
-	include $(TMK_PATH)/protocol/lufa.mk
+    include $(TMK_PATH)/protocol/lufa.mk
 endif
 endif
-	include $(TMK_PATH)/avr.mk
+    include $(TMK_PATH)/avr.mk
 endif
 endif
 
 
 ifeq ($(strip $(VISUALIZER_ENABLE)), yes)
 ifeq ($(strip $(VISUALIZER_ENABLE)), yes)
-	VISUALIZER_DIR = $(QUANTUM_DIR)/visualizer
-	VISUALIZER_PATH = $(QUANTUM_PATH)/visualizer
-	include $(VISUALIZER_PATH)/visualizer.mk
+    VISUALIZER_DIR = $(QUANTUM_DIR)/visualizer
+    VISUALIZER_PATH = $(QUANTUM_PATH)/visualizer
+    include $(VISUALIZER_PATH)/visualizer.mk
 endif
 endif
 
 
 OUTPUTS := $(KEYMAP_OUTPUT) $(KEYBOARD_OUTPUT)
 OUTPUTS := $(KEYMAP_OUTPUT) $(KEYBOARD_OUTPUT)
 $(KEYMAP_OUTPUT)_SRC := $(SRC)
 $(KEYMAP_OUTPUT)_SRC := $(SRC)
-$(KEYMAP_OUTPUT)_DEFS := $(OPT_DEFS) -DQMK_KEYBOARD=\"$(KEYBOARD)\" -DQMK_KEYMAP=\"$(KEYMAP)\"
+$(KEYMAP_OUTPUT)_DEFS := $(OPT_DEFS) $(GFXDEFS) -DQMK_KEYBOARD=\"$(KEYBOARD)\" -DQMK_KEYMAP=\"$(KEYMAP)\"
 $(KEYMAP_OUTPUT)_INC :=  $(VPATH) $(EXTRAINCDIRS)
 $(KEYMAP_OUTPUT)_INC :=  $(VPATH) $(EXTRAINCDIRS)
 $(KEYMAP_OUTPUT)_CONFIG := $(CONFIG_H)
 $(KEYMAP_OUTPUT)_CONFIG := $(CONFIG_H)
-$(KEYBOARD_OUTPUT)_SRC := $(CHIBISRC)
-$(KEYBOARD_OUTPUT)_DEFS := $(PROJECT_DEFS)
-$(KEYBOARD_OUTPUT)_INC := $(PROJECT_INC)
+$(KEYBOARD_OUTPUT)_SRC := $(CHIBISRC) $(GFXSRC)
+$(KEYBOARD_OUTPUT)_DEFS := $(PROJECT_DEFS) $(GFXDEFS)
+$(KEYBOARD_OUTPUT)_INC := $(PROJECT_INC) $(GFXINC)
 $(KEYBOARD_OUTPUT)_CONFIG  := $(PROJECT_CONFIG)
 $(KEYBOARD_OUTPUT)_CONFIG  := $(PROJECT_CONFIG)
 
 
 # Default target.
 # Default target.

+ 0 - 4
keyboards/ergodox/ez/rules.mk

@@ -74,7 +74,3 @@ OPT_DEFS += -DBOOTLOADER_SIZE=512
 SLEEP_LED_ENABLE = no
 SLEEP_LED_ENABLE = no
 API_SYSEX_ENABLE ?= no
 API_SYSEX_ENABLE ?= no
 RGBLIGHT_ENABLE ?= yes
 RGBLIGHT_ENABLE ?= yes
-
-ifndef QUANTUM_DIR
-	include ../../../Makefile
-endif

+ 1 - 1
keyboards/ergodox/infinity/Makefile

@@ -1,3 +1,3 @@
 ifndef MAKEFILE_INCLUDED
 ifndef MAKEFILE_INCLUDED
 	include ../../../Makefile
 	include ../../../Makefile
-endif
+endif

+ 107 - 0
keyboards/ergodox/infinity/animations.c

@@ -0,0 +1,107 @@
+/* Copyright 2017 Fred Sundvik
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if defined(VISUALIZER_ENABLE)
+
+#include "animations.h"
+#include "visualizer.h"
+#ifdef LCD_ENABLE
+#include "lcd_keyframes.h"
+#endif
+#ifdef LCD_BACKLIGHT_ENABLE
+#include "lcd_backlight_keyframes.h"
+#endif
+
+#ifdef LED_ENABLE
+#include "led_keyframes.h"
+#endif
+
+#include "visualizer_keyframes.h"
+
+
+#if defined(LCD_ENABLE) && defined(LCD_BACKLIGHT_ENABLE)
+
+// Don't worry, if the startup animation is long, you can use the keyboard like normal
+// during that time
+keyframe_animation_t default_startup_animation = {
+    .num_frames = 4,
+    .loop = false,
+    .frame_lengths = {0, 0, 0, gfxMillisecondsToTicks(5000), 0},
+    .frame_functions = {
+            lcd_keyframe_enable,
+            backlight_keyframe_enable,
+            lcd_keyframe_draw_logo,
+            backlight_keyframe_animate_color,
+    },
+};
+
+keyframe_animation_t default_suspend_animation = {
+    .num_frames = 4,
+    .loop = false,
+    .frame_lengths = {0, gfxMillisecondsToTicks(1000), 0, 0},
+    .frame_functions = {
+            lcd_keyframe_display_layer_text,
+            backlight_keyframe_animate_color,
+            lcd_keyframe_disable,
+            backlight_keyframe_disable,
+    },
+};
+#endif
+
+#if defined(LED_ENABLE)
+#define CROSSFADE_TIME 1000
+#define GRADIENT_TIME 3000
+
+keyframe_animation_t led_test_animation = {
+    .num_frames = 14,
+    .loop = true,
+    .frame_lengths = {
+        gfxMillisecondsToTicks(1000), // fade in
+        gfxMillisecondsToTicks(1000), // no op (leds on)
+        gfxMillisecondsToTicks(1000), // fade out
+        gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
+        gfxMillisecondsToTicks(GRADIENT_TIME), // left to rigt (outside in)
+        gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
+        gfxMillisecondsToTicks(GRADIENT_TIME), // top_to_bottom
+        0,           // mirror leds
+        gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
+        gfxMillisecondsToTicks(GRADIENT_TIME), // left_to_right (mirrored, so inside out)
+        gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
+        gfxMillisecondsToTicks(GRADIENT_TIME), // top_to_bottom
+        0,           // normal leds
+        gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
+
+    },
+    .frame_functions = {
+        led_keyframe_fade_in_all,
+        keyframe_no_operation,
+        led_keyframe_fade_out_all,
+        led_keyframe_crossfade,
+        led_keyframe_left_to_right_gradient,
+        led_keyframe_crossfade,
+        led_keyframe_top_to_bottom_gradient,
+        led_keyframe_mirror_orientation,
+        led_keyframe_crossfade,
+        led_keyframe_left_to_right_gradient,
+        led_keyframe_crossfade,
+        led_keyframe_top_to_bottom_gradient,
+        led_keyframe_normal_orientation,
+        led_keyframe_crossfade,
+    },
+};
+#endif
+
+#endif

+ 30 - 0
keyboards/ergodox/infinity/animations.h

@@ -0,0 +1,30 @@
+/* Copyright 2017 Fred Sundvik
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KEYBOARDS_ERGODOX_INFINITY_ANIMATIONS_H_
+#define KEYBOARDS_ERGODOX_INFINITY_ANIMATIONS_H_
+
+#include "visualizer.h"
+
+// You can use these default animations, but of course you can also write your own custom ones instead
+extern keyframe_animation_t default_startup_animation;
+extern keyframe_animation_t default_suspend_animation;
+
+// An animation for testing and demonstrating the led support, should probably not be used for real world
+// cases
+extern keyframe_animation_t led_test_animation;
+
+#endif /* KEYBOARDS_ERGODOX_INFINITY_ANIMATIONS_H_ */

+ 3 - 1
keyboards/ergodox/infinity/config.h

@@ -40,7 +40,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 /* number of backlight levels */
 /* number of backlight levels */
 #define BACKLIGHT_LEVELS 3
 #define BACKLIGHT_LEVELS 3
 
 
-#define LED_BRIGHTNESS_LO       15
+#define LED_BRIGHTNESS_LO       100
 #define LED_BRIGHTNESS_HI       255
 #define LED_BRIGHTNESS_HI       255
 
 
 /* define if matrix has ghost */
 /* define if matrix has ghost */
@@ -54,6 +54,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // The visualizer needs gfx thread priorities
 // The visualizer needs gfx thread priorities
 #define VISUALIZER_THREAD_PRIORITY (NORMAL_PRIORITY - 2)
 #define VISUALIZER_THREAD_PRIORITY (NORMAL_PRIORITY - 2)
 
 
+#define VISUALIZER_USER_DATA_SIZE 16
+
 /*
 /*
  * Feature disable options
  * Feature disable options
  *  These options are also useful to firmware size reduction.
  *  These options are also useful to firmware size reduction.

+ 5 - 32
keyboards/ergodox/infinity/drivers/gdisp/IS31FL3731C/gdisp_IS31FL3731C.c

@@ -25,6 +25,10 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
 #include "board_IS31FL3731C.h"
 #include "board_IS31FL3731C.h"
 
 
+
+// Can't include led_tables from here
+extern const uint8_t CIE1931_CURVE[];
+
 /*===========================================================================*/
 /*===========================================================================*/
 /* Driver local definitions.                                                 */
 /* Driver local definitions.                                                 */
 /*===========================================================================*/
 /*===========================================================================*/
@@ -100,37 +104,6 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
 #define IS31
 #define IS31
 
 
-//Generated by http://jared.geek.nz/2013/feb/linear-led-pwm
-const unsigned char cie[256] = {
-    0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
-    2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
-    3, 4, 4, 4, 4, 4, 4, 5, 5, 5,
-    5, 5, 6, 6, 6, 6, 6, 7, 7, 7,
-    7, 8, 8, 8, 8, 9, 9, 9, 10, 10,
-    10, 10, 11, 11, 11, 12, 12, 12, 13, 13,
-    13, 14, 14, 15, 15, 15, 16, 16, 17, 17,
-    17, 18, 18, 19, 19, 20, 20, 21, 21, 22,
-    22, 23, 23, 24, 24, 25, 25, 26, 26, 27,
-    28, 28, 29, 29, 30, 31, 31, 32, 32, 33,
-    34, 34, 35, 36, 37, 37, 38, 39, 39, 40,
-    41, 42, 43, 43, 44, 45, 46, 47, 47, 48,
-    49, 50, 51, 52, 53, 54, 54, 55, 56, 57,
-    58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
-    68, 70, 71, 72, 73, 74, 75, 76, 77, 79,
-    80, 81, 82, 83, 85, 86, 87, 88, 90, 91,
-    92, 94, 95, 96, 98, 99, 100, 102, 103, 105,
-    106, 108, 109, 110, 112, 113, 115, 116, 118, 120,
-    121, 123, 124, 126, 128, 129, 131, 132, 134, 136,
-    138, 139, 141, 143, 145, 146, 148, 150, 152, 154,
-    155, 157, 159, 161, 163, 165, 167, 169, 171, 173,
-    175, 177, 179, 181, 183, 185, 187, 189, 191, 193,
-    196, 198, 200, 202, 204, 207, 209, 211, 214, 216,
-    218, 220, 223, 225, 228, 230, 232, 235, 237, 240,
-    242, 245, 247, 250, 252, 255,
-};
-
-
 /*===========================================================================*/
 /*===========================================================================*/
 /* Driver local functions.                                                   */
 /* Driver local functions.                                                   */
 /*===========================================================================*/
 /*===========================================================================*/
@@ -231,7 +204,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) {
 		uint8_t* src = PRIV(g)->frame_buffer;
 		uint8_t* src = PRIV(g)->frame_buffer;
 		for (int y=0;y<GDISP_SCREEN_HEIGHT;y++) {
 		for (int y=0;y<GDISP_SCREEN_HEIGHT;y++) {
 		    for (int x=0;x<GDISP_SCREEN_WIDTH;x++) {
 		    for (int x=0;x<GDISP_SCREEN_WIDTH;x++) {
-		        PRIV(g)->write_buffer[get_led_address(g, x, y)]=cie[*src];
+		        PRIV(g)->write_buffer[get_led_address(g, x, y)]=CIE1931_CURVE[*src];
 		        ++src;
 		        ++src;
 		    }
 		    }
 		}
 		}

+ 33 - 47
keyboards/ergodox/infinity/drivers/gdisp/st7565ergodox/board_ST7565.h

@@ -8,8 +8,6 @@
 #ifndef _GDISP_LLD_BOARD_H
 #ifndef _GDISP_LLD_BOARD_H
 #define _GDISP_LLD_BOARD_H
 #define _GDISP_LLD_BOARD_H
 
 
-#include "print.h"
-
 #define ST7565_LCD_BIAS         ST7565_LCD_BIAS_9 // actually 6
 #define ST7565_LCD_BIAS         ST7565_LCD_BIAS_9 // actually 6
 #define ST7565_ADC              ST7565_ADC_NORMAL
 #define ST7565_ADC              ST7565_ADC_NORMAL
 #define ST7565_COM_SCAN         ST7565_COM_SCAN_DEC
 #define ST7565_COM_SCAN         ST7565_COM_SCAN_DEC
@@ -39,35 +37,49 @@
 // MSB First
 // MSB First
 // CLK Low by default
 // CLK Low by default
 static const SPIConfig spi1config = {
 static const SPIConfig spi1config = {
-	NULL,
-	/* HW dependent part.*/
-	ST7565_GPIOPORT,
-    ST7565_SS_PIN,
-    SPIx_CTARn_FMSZ(7)
-    | SPIx_CTARn_ASC(7)
-    | SPIx_CTARn_DT(7)
-    | SPIx_CTARn_CSSCK(7)
-    | SPIx_CTARn_PBR(0)
-    | SPIx_CTARn_BR(7)
-	//SPI_CR1_BR_0
+   // Operation complete callback or @p NULL.
+  .end_cb = NULL,
+   //The chip select line port - when not using pcs.
+  .ssport = ST7565_GPIOPORT,
+   // brief The chip select line pad number - when not using pcs.
+  .sspad=ST7565_SS_PIN,
+   // SPI initialization data.
+  .tar0 =
+    SPIx_CTARn_FMSZ(7) // Frame size = 8 bytes
+    | SPIx_CTARn_ASC(1) // After SCK Delay Scaler (min 50 ns) = 55.56ns
+    | SPIx_CTARn_DT(0) // Delay After Transfer Scaler (no minimum)= 27.78ns
+    | SPIx_CTARn_CSSCK(0) // PCS to SCK Delay Scaler (min 20 ns) = 27.78ns
+    | SPIx_CTARn_PBR(0) // Baud Rate Prescaler = 2
+    | SPIx_CTARn_BR(0) // Baud rate (min 50ns) = 55.56ns
 };
 };
 
 
-static bool_t st7565_is_data_mode = 1;
+static GFXINLINE void acquire_bus(GDisplay *g) {
+    (void) g;
+    // Only the LCD is using the SPI bus, so no need to acquire
+    // spiAcquireBus(&SPID1);
+    spiSelect(&SPID1);
+}
+
+static GFXINLINE void release_bus(GDisplay *g) {
+    (void) g;
+    // Only the LCD is using the SPI bus, so no need to release
+    //spiReleaseBus(&SPID1);
+    spiUnselect(&SPID1);
+}
 
 
 static GFXINLINE void init_board(GDisplay *g) {
 static GFXINLINE void init_board(GDisplay *g) {
     (void) g;
     (void) g;
     palSetPadModeNamed(A0, PAL_MODE_OUTPUT_PUSHPULL);
     palSetPadModeNamed(A0, PAL_MODE_OUTPUT_PUSHPULL);
     palSetPad(ST7565_GPIOPORT, ST7565_A0_PIN);
     palSetPad(ST7565_GPIOPORT, ST7565_A0_PIN);
-    st7565_is_data_mode = 1;
     palSetPadModeNamed(RST, PAL_MODE_OUTPUT_PUSHPULL);
     palSetPadModeNamed(RST, PAL_MODE_OUTPUT_PUSHPULL);
     palSetPad(ST7565_GPIOPORT, ST7565_RST_PIN);
     palSetPad(ST7565_GPIOPORT, ST7565_RST_PIN);
     palSetPadModeRaw(MOSI, ST7565_SPI_MODE);
     palSetPadModeRaw(MOSI, ST7565_SPI_MODE);
     palSetPadModeRaw(SLCK, ST7565_SPI_MODE);
     palSetPadModeRaw(SLCK, ST7565_SPI_MODE);
-    palSetPadModeRaw(SS, ST7565_SPI_MODE);
+    palSetPadModeRaw(SS, PAL_MODE_OUTPUT_PUSHPULL);
 
 
     spiInit();
     spiInit();
     spiStart(&SPID1, &spi1config);
     spiStart(&SPID1, &spi1config);
-    spiSelect(&SPID1);
+    release_bus(g);
 }
 }
 
 
 static GFXINLINE void post_init_board(GDisplay *g) {
 static GFXINLINE void post_init_board(GDisplay *g) {
@@ -84,43 +96,17 @@ static GFXINLINE void setpin_reset(GDisplay *g, bool_t state) {
     }
     }
 }
 }
 
 
-static GFXINLINE void acquire_bus(GDisplay *g) {
-    (void) g;
-    // Only the LCD is using the SPI bus, so no need to acquire
-    // spiAcquireBus(&SPID1);
+static GFXINLINE void enter_data_mode(GDisplay *g) {
+    palSetPad(ST7565_GPIOPORT, ST7565_A0_PIN);
 }
 }
 
 
-static GFXINLINE void release_bus(GDisplay *g) {
-    (void) g;
-    // Only the LCD is using the SPI bus, so no need to release
-    //spiReleaseBus(&SPID1);
+static GFXINLINE void enter_cmd_mode(GDisplay *g) {
+    palClearPad(ST7565_GPIOPORT, ST7565_A0_PIN);
 }
 }
 
 
-static GFXINLINE void write_cmd(GDisplay *g, uint8_t cmd) {
-	(void) g;
-	if (st7565_is_data_mode) {
-	    // The sleeps need to be at lest 10 vs 25 ns respectively
-	    // So let's sleep two ticks, one tick might not be enough
-	    // if we are at the end of the tick
-	    chThdSleep(2);
-        palClearPad(ST7565_GPIOPORT, ST7565_A0_PIN);
-        chThdSleep(2);
-        st7565_is_data_mode = 0;
-	}
-	spiSend(&SPID1, 1, &cmd);
-}
 
 
 static GFXINLINE void write_data(GDisplay *g, uint8_t* data, uint16_t length) {
 static GFXINLINE void write_data(GDisplay *g, uint8_t* data, uint16_t length) {
 	(void) g;
 	(void) g;
-	if (!st7565_is_data_mode) {
-	    // The sleeps need to be at lest 10 vs 25 ns respectively
-	    // So let's sleep two ticks, one tick might not be enough
-	    // if we are at the end of the tick
-	    chThdSleep(2);
-        palSetPad(ST7565_GPIOPORT, ST7565_A0_PIN);
-	    chThdSleep(2);
-        st7565_is_data_mode = 1;
-	}
 	spiSend(&SPID1, length, data);
 	spiSend(&SPID1, length, data);
 }
 }
 
 

+ 224 - 187
keyboards/ergodox/infinity/drivers/gdisp/st7565ergodox/gdisp_lld_ST7565.c

@@ -20,16 +20,16 @@
 /*===========================================================================*/
 /*===========================================================================*/
 
 
 #ifndef GDISP_SCREEN_HEIGHT
 #ifndef GDISP_SCREEN_HEIGHT
-	#define GDISP_SCREEN_HEIGHT		32
+#define GDISP_SCREEN_HEIGHT		32
 #endif
 #endif
 #ifndef GDISP_SCREEN_WIDTH
 #ifndef GDISP_SCREEN_WIDTH
-	#define GDISP_SCREEN_WIDTH		128
+#define GDISP_SCREEN_WIDTH		128
 #endif
 #endif
 #ifndef GDISP_INITIAL_CONTRAST
 #ifndef GDISP_INITIAL_CONTRAST
-	#define GDISP_INITIAL_CONTRAST	0
+#define GDISP_INITIAL_CONTRAST	35
 #endif
 #endif
 #ifndef GDISP_INITIAL_BACKLIGHT
 #ifndef GDISP_INITIAL_BACKLIGHT
-	#define GDISP_INITIAL_BACKLIGHT	100
+#define GDISP_INITIAL_BACKLIGHT	100
 #endif
 #endif
 
 
 #define GDISP_FLG_NEEDFLUSH			(GDISP_FLG_DRIVER<<0)
 #define GDISP_FLG_NEEDFLUSH			(GDISP_FLG_DRIVER<<0)
@@ -40,16 +40,16 @@
 /* Driver config defaults for backward compatibility.               	     */
 /* Driver config defaults for backward compatibility.               	     */
 /*===========================================================================*/
 /*===========================================================================*/
 #ifndef ST7565_LCD_BIAS
 #ifndef ST7565_LCD_BIAS
-  #define ST7565_LCD_BIAS         ST7565_LCD_BIAS_7
+#define ST7565_LCD_BIAS         ST7565_LCD_BIAS_7
 #endif
 #endif
 #ifndef ST7565_ADC
 #ifndef ST7565_ADC
-  #define ST7565_ADC              ST7565_ADC_NORMAL
+#define ST7565_ADC              ST7565_ADC_NORMAL
 #endif
 #endif
 #ifndef ST7565_COM_SCAN
 #ifndef ST7565_COM_SCAN
-  #define ST7565_COM_SCAN         ST7565_COM_SCAN_INC
+#define ST7565_COM_SCAN         ST7565_COM_SCAN_INC
 #endif
 #endif
 #ifndef ST7565_PAGE_ORDER
 #ifndef ST7565_PAGE_ORDER
-  #define ST7565_PAGE_ORDER       0,1,2,3
+#define ST7565_PAGE_ORDER       0,1,2,3
 #endif
 #endif
 
 
 /*===========================================================================*/
 /*===========================================================================*/
@@ -58,12 +58,24 @@
 
 
 typedef struct{
 typedef struct{
     bool_t buffer2;
     bool_t buffer2;
+    uint8_t data_pos;
+    uint8_t data[16];
     uint8_t ram[GDISP_SCREEN_HEIGHT * GDISP_SCREEN_WIDTH / 8];
     uint8_t ram[GDISP_SCREEN_HEIGHT * GDISP_SCREEN_WIDTH / 8];
 }PrivData;
 }PrivData;
 
 
 // Some common routines and macros
 // Some common routines and macros
 #define PRIV(g)                         ((PrivData*)g->priv)
 #define PRIV(g)                         ((PrivData*)g->priv)
 #define RAM(g)							(PRIV(g)->ram)
 #define RAM(g)							(PRIV(g)->ram)
+
+static GFXINLINE void write_cmd(GDisplay* g, uint8_t cmd) {
+    PRIV(g)->data[PRIV(g)->data_pos++] = cmd;
+}
+
+static GFXINLINE void flush_cmd(GDisplay* g) {
+    write_data(g, PRIV(g)->data, PRIV(g)->data_pos);
+    PRIV(g)->data_pos = 0;
+}
+
 #define write_cmd2(g, cmd1, cmd2)		{ write_cmd(g, cmd1); write_cmd(g, cmd2); }
 #define write_cmd2(g, cmd1, cmd2)		{ write_cmd(g, cmd1); write_cmd(g, cmd2); }
 #define write_cmd3(g, cmd1, cmd2, cmd3)	{ write_cmd(g, cmd1); write_cmd(g, cmd2); write_cmd(g, cmd3); }
 #define write_cmd3(g, cmd1, cmd2, cmd3)	{ write_cmd(g, cmd1); write_cmd(g, cmd2); write_cmd(g, cmd3); }
 
 
@@ -86,207 +98,232 @@ typedef struct{
  */
  */
 
 
 LLDSPEC bool_t gdisp_lld_init(GDisplay *g) {
 LLDSPEC bool_t gdisp_lld_init(GDisplay *g) {
-	// The private area is the display surface.
-	g->priv = gfxAlloc(sizeof(PrivData));
-	PRIV(g)->buffer2 = false;
-
-	// Initialise the board interface
-	init_board(g);
-
-	// Hardware reset
-	setpin_reset(g, TRUE);
-	gfxSleepMilliseconds(20);
-	setpin_reset(g, FALSE);
-	gfxSleepMilliseconds(20);
-
-	acquire_bus(g);
-    write_cmd(g, ST7565_DISPLAY_OFF);
-	write_cmd(g, ST7565_LCD_BIAS);
+    // The private area is the display surface.
+    g->priv = gfxAlloc(sizeof(PrivData));
+    PRIV(g)->buffer2 = false;
+    PRIV(g)->data_pos = 0;
+
+    // Initialise the board interface
+    init_board(g);
+
+    // Hardware reset
+    setpin_reset(g, TRUE);
+    gfxSleepMilliseconds(20);
+    setpin_reset(g, FALSE);
+    gfxSleepMilliseconds(20);
+    acquire_bus(g);
+    enter_cmd_mode(g);
+
+    write_cmd(g, ST7565_RESET);
+    write_cmd(g, ST7565_LCD_BIAS);
     write_cmd(g, ST7565_ADC);
     write_cmd(g, ST7565_ADC);
     write_cmd(g, ST7565_COM_SCAN);
     write_cmd(g, ST7565_COM_SCAN);
-    
-    write_cmd(g, ST7565_START_LINE | 0);
-
-	write_cmd(g, ST7565_RESISTOR_RATIO | 0x6);
-
-	// turn on voltage converter (VC=1, VR=0, VF=0)
-	write_cmd(g, ST7565_POWER_CONTROL | 0x04);
-	delay_ms(50);
 
 
-	// turn on voltage regulator (VC=1, VR=1, VF=0)
-	write_cmd(g, ST7565_POWER_CONTROL | 0x06);
-	delay_ms(50);
+    write_cmd(g, ST7565_RESISTOR_RATIO | 0x1);
+    write_cmd2(g, ST7565_CONTRAST, GDISP_INITIAL_CONTRAST);
 
 
-	// turn on voltage follower (VC=1, VR=1, VF=1)
-	write_cmd(g, ST7565_POWER_CONTROL | 0x07);
-	delay_ms(50);
+    // turn on internal power supply (VC=1, VR=1, VF=1)
+    write_cmd(g, ST7565_POWER_CONTROL | 0x07);
 
 
-	write_cmd(g, 0xE2);
-    write_cmd(g, ST7565_COM_SCAN);
-	write_cmd2(g, ST7565_CONTRAST, GDISP_INITIAL_CONTRAST*64/101);
-	//write_cmd2(g, ST7565_CONTRAST, 0);
-	write_cmd(g, ST7565_DISPLAY_ON);
-	write_cmd(g, ST7565_ALLON_NORMAL);
-	write_cmd(g, ST7565_INVERT_DISPLAY);
+    write_cmd(g, ST7565_INVERT_DISPLAY);
+    write_cmd(g, ST7565_ALLON_NORMAL);
 
 
-	write_cmd(g, ST7565_RMW);
+    write_cmd(g, ST7565_START_LINE | 0);
+    write_cmd(g, ST7565_RMW);
+    flush_cmd(g);
 
 
     // Finish Init
     // Finish Init
     post_init_board(g);
     post_init_board(g);
 
 
- 	// Release the bus
-	release_bus(g);
-
-	/* Initialise the GDISP structure */
-	g->g.Width = GDISP_SCREEN_WIDTH;
-	g->g.Height = GDISP_SCREEN_HEIGHT;
-	g->g.Orientation = GDISP_ROTATE_0;
-	g->g.Powermode = powerOn;
-	g->g.Backlight = GDISP_INITIAL_BACKLIGHT;
-	g->g.Contrast = GDISP_INITIAL_CONTRAST;
-	return TRUE;
+    // Release the bus
+    release_bus(g);
+
+    /* Initialise the GDISP structure */
+    g->g.Width = GDISP_SCREEN_WIDTH;
+    g->g.Height = GDISP_SCREEN_HEIGHT;
+    g->g.Orientation = GDISP_ROTATE_0;
+    g->g.Powermode = powerOff;
+    g->g.Backlight = GDISP_INITIAL_BACKLIGHT;
+    g->g.Contrast = GDISP_INITIAL_CONTRAST;
+    return TRUE;
 }
 }
 
 
 #if GDISP_HARDWARE_FLUSH
 #if GDISP_HARDWARE_FLUSH
-	LLDSPEC void gdisp_lld_flush(GDisplay *g) {
-		unsigned	p;
-
-		// Don't flush if we don't need it.
-		if (!(g->flags & GDISP_FLG_NEEDFLUSH))
-			return;
-
-		acquire_bus(g);
-		unsigned dstOffset = (PRIV(g)->buffer2 ? 4 : 0);
-		for (p = 0; p < 4; p++) {
-			write_cmd(g, ST7565_PAGE | (p + dstOffset));
-			write_cmd(g, ST7565_COLUMN_MSB | 0);
-			write_cmd(g, ST7565_COLUMN_LSB | 0);
-			write_cmd(g, ST7565_RMW);
-			write_data(g, RAM(g) + (p*GDISP_SCREEN_WIDTH), GDISP_SCREEN_WIDTH);
-		}
-		unsigned line = (PRIV(g)->buffer2 ? 32 : 0);
-        write_cmd(g, ST7565_START_LINE | line);
-        PRIV(g)->buffer2 = !PRIV(g)->buffer2;
-		release_bus(g);
-
-		g->flags &= ~GDISP_FLG_NEEDFLUSH;
-	}
+LLDSPEC void gdisp_lld_flush(GDisplay *g) {
+    unsigned	p;
+
+    // Don't flush if we don't need it.
+    if (!(g->flags & GDISP_FLG_NEEDFLUSH))
+        return;
+
+    acquire_bus(g);
+    enter_cmd_mode(g);
+    unsigned dstOffset = (PRIV(g)->buffer2 ? 4 : 0);
+    for (p = 0; p < 4; p++) {
+        write_cmd(g, ST7565_PAGE | (p + dstOffset));
+        write_cmd(g, ST7565_COLUMN_MSB | 0);
+        write_cmd(g, ST7565_COLUMN_LSB | 0);
+        write_cmd(g, ST7565_RMW);
+        flush_cmd(g);
+        enter_data_mode(g);
+        write_data(g, RAM(g) + (p*GDISP_SCREEN_WIDTH), GDISP_SCREEN_WIDTH);
+        enter_cmd_mode(g);
+    }
+    unsigned line = (PRIV(g)->buffer2 ? 32 : 0);
+    write_cmd(g, ST7565_START_LINE | line);
+    flush_cmd(g);
+    PRIV(g)->buffer2 = !PRIV(g)->buffer2;
+    release_bus(g);
+
+    g->flags &= ~GDISP_FLG_NEEDFLUSH;
+}
 #endif
 #endif
 
 
 #if GDISP_HARDWARE_DRAWPIXEL
 #if GDISP_HARDWARE_DRAWPIXEL
-	LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) {
-		coord_t		x, y;
-
-		switch(g->g.Orientation) {
-		default:
-		case GDISP_ROTATE_0:
-			x = g->p.x;
-			y = g->p.y;
-			break;
-		case GDISP_ROTATE_90:
-			x = g->p.y;
-			y = GDISP_SCREEN_HEIGHT-1 - g->p.x;
-			break;
-		case GDISP_ROTATE_180:
-			x = GDISP_SCREEN_WIDTH-1 - g->p.x;
-			y = GDISP_SCREEN_HEIGHT-1 - g->p.y;
-			break;
-		case GDISP_ROTATE_270:
-			x = GDISP_SCREEN_HEIGHT-1 - g->p.y;
-			y = g->p.x;
-			break;
-		}
-		if (gdispColor2Native(g->p.color) != Black)
-			RAM(g)[xyaddr(x, y)] |= xybit(y);
-		else
-			RAM(g)[xyaddr(x, y)] &= ~xybit(y);
-		g->flags |= GDISP_FLG_NEEDFLUSH;
-	}
+LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) {
+    coord_t		x, y;
+
+    switch(g->g.Orientation) {
+    default:
+    case GDISP_ROTATE_0:
+        x = g->p.x;
+        y = g->p.y;
+        break;
+    case GDISP_ROTATE_90:
+        x = g->p.y;
+        y = GDISP_SCREEN_HEIGHT-1 - g->p.x;
+        break;
+    case GDISP_ROTATE_180:
+        x = GDISP_SCREEN_WIDTH-1 - g->p.x;
+        y = GDISP_SCREEN_HEIGHT-1 - g->p.y;
+        break;
+    case GDISP_ROTATE_270:
+        x = GDISP_SCREEN_HEIGHT-1 - g->p.y;
+        y = g->p.x;
+        break;
+    }
+    if (gdispColor2Native(g->p.color) != Black)
+        RAM(g)[xyaddr(x, y)] |= xybit(y);
+    else
+        RAM(g)[xyaddr(x, y)] &= ~xybit(y);
+    g->flags |= GDISP_FLG_NEEDFLUSH;
+}
 #endif
 #endif
 
 
 #if GDISP_HARDWARE_PIXELREAD
 #if GDISP_HARDWARE_PIXELREAD
-	LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) {
-		coord_t		x, y;
-
-		switch(g->g.Orientation) {
-		default:
-		case GDISP_ROTATE_0:
-			x = g->p.x;
-			y = g->p.y;
-			break;
-		case GDISP_ROTATE_90:
-			x = g->p.y;
-			y = GDISP_SCREEN_HEIGHT-1 - g->p.x;
-			break;
-		case GDISP_ROTATE_180:
-			x = GDISP_SCREEN_WIDTH-1 - g->p.x;
-			y = GDISP_SCREEN_HEIGHT-1 - g->p.y;
-			break;
-		case GDISP_ROTATE_270:
-			x = GDISP_SCREEN_HEIGHT-1 - g->p.y;
-			y = g->p.x;
-			break;
-		}
-		return (RAM(g)[xyaddr(x, y)] & xybit(y)) ? White : Black;
-	}
+LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) {
+    coord_t		x, y;
+
+    switch(g->g.Orientation) {
+    default:
+    case GDISP_ROTATE_0:
+        x = g->p.x;
+        y = g->p.y;
+        break;
+    case GDISP_ROTATE_90:
+        x = g->p.y;
+        y = GDISP_SCREEN_HEIGHT-1 - g->p.x;
+        break;
+    case GDISP_ROTATE_180:
+        x = GDISP_SCREEN_WIDTH-1 - g->p.x;
+        y = GDISP_SCREEN_HEIGHT-1 - g->p.y;
+        break;
+    case GDISP_ROTATE_270:
+        x = GDISP_SCREEN_HEIGHT-1 - g->p.y;
+        y = g->p.x;
+        break;
+    }
+    return (RAM(g)[xyaddr(x, y)] & xybit(y)) ? White : Black;
+}
 #endif
 #endif
 
 
+LLDSPEC void gdisp_lld_blit_area(GDisplay *g) {
+    uint8_t* buffer = (uint8_t*)g->p.ptr;
+    int linelength = g->p.cx;
+    for (int i = 0; i < g->p.cy; i++) {
+        unsigned dstx = g->p.x;
+        unsigned dsty = g->p.y + i;
+        unsigned srcx = g->p.x1;
+        unsigned srcy = g->p.y1 + i;
+        unsigned srcbit = srcy * g->p.x2 + srcx;
+        for(int j=0; j < linelength; j++) {
+            uint8_t src = buffer[srcbit / 8];
+            uint8_t bit = 7-(srcbit % 8);
+            uint8_t bitset = (src >> bit) & 1;
+            uint8_t* dst = &(RAM(g)[xyaddr(dstx, dsty)]);
+            if (bitset) {
+                *dst |= xybit(dsty);
+            }
+            else {
+                *dst &= ~xybit(dsty);
+            }
+			dstx++;
+            srcbit++;
+        }
+    }
+    g->flags |= GDISP_FLG_NEEDFLUSH;
+}
+
 #if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
 #if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
-	LLDSPEC void gdisp_lld_control(GDisplay *g) {
-		switch(g->p.x) {
-		case GDISP_CONTROL_POWER:
-			if (g->g.Powermode == (powermode_t)g->p.ptr)
-				return;
-			switch((powermode_t)g->p.ptr) {
-			case powerOff:
-			case powerSleep:
-			case powerDeepSleep:
-				acquire_bus(g);
-				write_cmd(g, ST7565_DISPLAY_OFF);
-				release_bus(g);
-				break;
-			case powerOn:
-				acquire_bus(g);
-				write_cmd(g, ST7565_DISPLAY_ON);
-				release_bus(g);
-				break;
-			default:
-				return;
-			}
-			g->g.Powermode = (powermode_t)g->p.ptr;
-			return;
-
-		case GDISP_CONTROL_ORIENTATION:
-			if (g->g.Orientation == (orientation_t)g->p.ptr)
-				return;
-			switch((orientation_t)g->p.ptr) {
-			/* Rotation is handled by the drawing routines */
-			case GDISP_ROTATE_0:
-			case GDISP_ROTATE_180:
-				g->g.Height = GDISP_SCREEN_HEIGHT;
-				g->g.Width = GDISP_SCREEN_WIDTH;
-				break;
-			case GDISP_ROTATE_90:
-			case GDISP_ROTATE_270:
-				g->g.Height = GDISP_SCREEN_WIDTH;
-				g->g.Width = GDISP_SCREEN_HEIGHT;
-				break;
-			default:
-				return;
-			}
-			g->g.Orientation = (orientation_t)g->p.ptr;
-			return;
-
-		case GDISP_CONTROL_CONTRAST:
-            if ((unsigned)g->p.ptr > 100)
-            	g->p.ptr = (void *)100;
-			acquire_bus(g);
-			write_cmd2(g, ST7565_CONTRAST, ((((unsigned)g->p.ptr)<<6)/101) & 0x3F);
-			release_bus(g);
-            g->g.Contrast = (unsigned)g->p.ptr;
-			return;
-		}
-	}
+LLDSPEC void gdisp_lld_control(GDisplay *g) {
+    switch(g->p.x) {
+    case GDISP_CONTROL_POWER:
+        if (g->g.Powermode == (powermode_t)g->p.ptr)
+            return;
+        switch((powermode_t)g->p.ptr) {
+        case powerOff:
+        case powerSleep:
+        case powerDeepSleep:
+            acquire_bus(g);
+            enter_cmd_mode(g);
+            write_cmd(g, ST7565_DISPLAY_OFF);
+            flush_cmd(g);
+            release_bus(g);
+            break;
+        case powerOn:
+            acquire_bus(g);
+            enter_cmd_mode(g);
+            write_cmd(g, ST7565_DISPLAY_ON);
+            flush_cmd(g);
+            release_bus(g);
+            break;
+        default:
+            return;
+        }
+        g->g.Powermode = (powermode_t)g->p.ptr;
+        return;
+
+        case GDISP_CONTROL_ORIENTATION:
+            if (g->g.Orientation == (orientation_t)g->p.ptr)
+                return;
+            switch((orientation_t)g->p.ptr) {
+            /* Rotation is handled by the drawing routines */
+            case GDISP_ROTATE_0:
+            case GDISP_ROTATE_180:
+                g->g.Height = GDISP_SCREEN_HEIGHT;
+                g->g.Width = GDISP_SCREEN_WIDTH;
+                break;
+            case GDISP_ROTATE_90:
+            case GDISP_ROTATE_270:
+                g->g.Height = GDISP_SCREEN_WIDTH;
+                g->g.Width = GDISP_SCREEN_HEIGHT;
+                break;
+            default:
+                return;
+            }
+            g->g.Orientation = (orientation_t)g->p.ptr;
+            return;
+
+            case GDISP_CONTROL_CONTRAST:
+                g->g.Contrast = (unsigned)g->p.ptr & 63;
+                acquire_bus(g);
+                enter_cmd_mode(g);
+                write_cmd2(g, ST7565_CONTRAST, g->g.Contrast);
+                flush_cmd(g);
+                release_bus(g);
+                return;
+    }
+}
 #endif // GDISP_NEED_CONTROL
 #endif // GDISP_NEED_CONTROL
 
 
 #endif // GFX_USE_GDISP
 #endif // GFX_USE_GDISP

+ 6 - 5
keyboards/ergodox/infinity/drivers/gdisp/st7565ergodox/gdisp_lld_config.h

@@ -14,12 +14,13 @@
 /* Driver hardware support.                                                  */
 /* Driver hardware support.                                                  */
 /*===========================================================================*/
 /*===========================================================================*/
 
 
-#define GDISP_HARDWARE_FLUSH			TRUE		// This controller requires flushing
-#define GDISP_HARDWARE_DRAWPIXEL		TRUE
-#define GDISP_HARDWARE_PIXELREAD		TRUE
-#define GDISP_HARDWARE_CONTROL			TRUE
+#define GDISP_HARDWARE_FLUSH            TRUE		// This controller requires flushing
+#define GDISP_HARDWARE_DRAWPIXEL        TRUE
+#define GDISP_HARDWARE_PIXELREAD        TRUE
+#define GDISP_HARDWARE_CONTROL          TRUE
+#define GDISP_HARDWARE_BITFILLS         TRUE
 
 
-#define GDISP_LLD_PIXELFORMAT			GDISP_PIXELFORMAT_MONO
+#define GDISP_LLD_PIXELFORMAT           GDISP_PIXELFORMAT_MONO
 
 
 #endif	/* GFX_USE_GDISP */
 #endif	/* GFX_USE_GDISP */
 
 

+ 2 - 0
keyboards/ergodox/infinity/drivers/gdisp/st7565ergodox/st7565.h

@@ -34,4 +34,6 @@
 #define ST7565_RESISTOR_RATIO       0x20
 #define ST7565_RESISTOR_RATIO       0x20
 #define ST7565_POWER_CONTROL        0x28
 #define ST7565_POWER_CONTROL        0x28
 
 
+#define ST7565_RESET                0xE2
+
 #endif /* _ST7565_H */
 #endif /* _ST7565_H */

+ 1 - 1
keyboards/ergodox/infinity/gfxconf.h

@@ -143,7 +143,7 @@
         #define GDISP_HARDWARE_DRAWPIXEL             TRUE
         #define GDISP_HARDWARE_DRAWPIXEL             TRUE
         #define GDISP_HARDWARE_CLEARS                FALSE
         #define GDISP_HARDWARE_CLEARS                FALSE
         #define GDISP_HARDWARE_FILLS                 FALSE
         #define GDISP_HARDWARE_FILLS                 FALSE
-        #define GDISP_HARDWARE_BITFILLS              FALSE
+        //#define GDISP_HARDWARE_BITFILLS              FALSE
         #define GDISP_HARDWARE_SCROLL                FALSE
         #define GDISP_HARDWARE_SCROLL                FALSE
         #define GDISP_HARDWARE_PIXELREAD             TRUE
         #define GDISP_HARDWARE_PIXELREAD             TRUE
         #define GDISP_HARDWARE_CONTROL               TRUE
         #define GDISP_HARDWARE_CONTROL               TRUE

+ 44 - 7
keyboards/ergodox/infinity/infinity.c

@@ -70,10 +70,33 @@ void lcd_backlight_hal_init(void) {
     RGB_PORT->PCR[BLUE_PIN] = RGB_MODE;
     RGB_PORT->PCR[BLUE_PIN] = RGB_MODE;
 }
 }
 
 
+static uint16_t cie_lightness(uint16_t v) {
+    // The CIE 1931 formula for lightness
+    // Y = luminance (output) 0-1
+    // L = lightness input 0 - 100
+
+    // Y = (L* / 902.3)           if L* <= 8
+    // Y = ((L* + 16) / 116)^3    if L* > 8
+
+    float l =  100.0f * (v / 65535.0f);
+    float y = 0.0f;
+    if (l <= 8.0f) {
+       y = l / 902.3;
+    }
+    else {
+        y = ((l + 16.0f) / 116.0f);
+        y = y * y * y;
+        if (y > 1.0f) {
+            y = 1.0f;
+        }
+    }
+    return y * 65535.0f;
+}
+
 void lcd_backlight_hal_color(uint16_t r, uint16_t g, uint16_t b) {
 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;
+	CHANNEL_RED.CnV = cie_lightness(r);
+	CHANNEL_GREEN.CnV = cie_lightness(g);
+	CHANNEL_BLUE.CnV = cie_lightness(b);
 }
 }
 
 
 __attribute__ ((weak))
 __attribute__ ((weak))
@@ -103,34 +126,48 @@ void matrix_scan_kb(void) {
 	matrix_scan_user();
 	matrix_scan_user();
 }
 }
 
 
+__attribute__ ((weak))
 void ergodox_board_led_on(void){
 void ergodox_board_led_on(void){
 }
 }
 
 
+__attribute__ ((weak))
 void ergodox_right_led_1_on(void){
 void ergodox_right_led_1_on(void){
 }
 }
 
 
+__attribute__ ((weak))
 void ergodox_right_led_2_on(void){
 void ergodox_right_led_2_on(void){
 }
 }
 
 
+__attribute__ ((weak))
 void ergodox_right_led_3_on(void){
 void ergodox_right_led_3_on(void){
 }
 }
 
 
-void ergodox_right_led_on(uint8_t led){
-}
-
+__attribute__ ((weak))
 void ergodox_board_led_off(void){
 void ergodox_board_led_off(void){
 }
 }
 
 
+__attribute__ ((weak))
 void ergodox_right_led_1_off(void){
 void ergodox_right_led_1_off(void){
 }
 }
 
 
+__attribute__ ((weak))
 void ergodox_right_led_2_off(void){
 void ergodox_right_led_2_off(void){
 }
 }
 
 
+__attribute__ ((weak))
 void ergodox_right_led_3_off(void){
 void ergodox_right_led_3_off(void){
 }
 }
 
 
-void ergodox_right_led_off(uint8_t led){
+__attribute__ ((weak))
+void ergodox_right_led_1_set(uint8_t n) {
+}
+
+__attribute__ ((weak))
+void ergodox_right_led_2_set(uint8_t n) {
+}
+
+__attribute__ ((weak))
+void ergodox_right_led_3_set(uint8_t n) {
 }
 }
 
 
 #ifdef ONEHAND_ENABLE
 #ifdef ONEHAND_ENABLE

+ 41 - 30
keyboards/ergodox/infinity/infinity.h

@@ -7,13 +7,38 @@ void ergodox_board_led_on(void);
 void ergodox_right_led_1_on(void);
 void ergodox_right_led_1_on(void);
 void ergodox_right_led_2_on(void);
 void ergodox_right_led_2_on(void);
 void ergodox_right_led_3_on(void);
 void ergodox_right_led_3_on(void);
-void ergodox_right_led_on(uint8_t led);
+
+inline void ergodox_right_led_on(uint8_t led) {
+    switch (led) {
+    case 0:
+        ergodox_right_led_1_on();
+        break;
+    case 1:
+        ergodox_right_led_2_on();
+        break;
+    case 2:
+        ergodox_right_led_3_on();
+        break;
+    }
+}
 
 
 void ergodox_board_led_off(void);
 void ergodox_board_led_off(void);
 void ergodox_right_led_1_off(void);
 void ergodox_right_led_1_off(void);
 void ergodox_right_led_2_off(void);
 void ergodox_right_led_2_off(void);
 void ergodox_right_led_3_off(void);
 void ergodox_right_led_3_off(void);
-void ergodox_right_led_off(uint8_t led);
+inline void ergodox_right_led_off(uint8_t led) {
+    switch (led) {
+    case 0:
+        ergodox_right_led_1_off();
+        break;
+    case 1:
+        ergodox_right_led_2_off();
+        break;
+    case 2:
+        ergodox_right_led_3_off();
+        break;
+    }
+}
 
 
 inline void ergodox_led_all_on(void)
 inline void ergodox_led_all_on(void)
 {
 {
@@ -31,36 +56,22 @@ inline void ergodox_led_all_off(void)
     ergodox_right_led_3_off();
     ergodox_right_led_3_off();
 }
 }
 
 
-inline void ergodox_right_led_1_set(uint8_t n){
-	if (n) {
-		ergodox_right_led_1_on();
-	} else {
-		ergodox_right_led_1_off();
-	}
-}
-
-inline void ergodox_right_led_2_set(uint8_t n){
-	if (n) {
-		ergodox_right_led_2_on();
-	} else {
-		ergodox_right_led_2_off();
-	}
-}
-
-inline void ergodox_right_led_3_set(uint8_t n){
-	if (n) {
-		ergodox_right_led_3_on();
-	} else {
-		ergodox_right_led_3_off();
-	}
-}
+void ergodox_right_led_1_set(uint8_t n);
+void ergodox_right_led_2_set(uint8_t n);
+void ergodox_right_led_3_set(uint8_t n);
 
 
 inline void ergodox_right_led_set(uint8_t led, uint8_t n){
 inline void ergodox_right_led_set(uint8_t led, uint8_t n){
-	if (n) {
-		ergodox_right_led_on(led);
-	} else {
-		ergodox_right_led_off(led);
-	}
+    switch (led) {
+    case 0:
+        ergodox_right_led_1_set(n);
+        break;
+    case 1:
+        ergodox_right_led_2_set(n);
+        break;
+    case 2:
+        ergodox_right_led_3_set(n);
+        break;
+    }
 }
 }
 
 
 inline void ergodox_led_all_set(uint8_t n) {
 inline void ergodox_led_all_set(uint8_t n) {

+ 5 - 8
keyboards/ergodox/infinity/rules.mk

@@ -1,6 +1,7 @@
 # project specific files
 # project specific files
 SRC =	matrix.c \
 SRC =	matrix.c \
-	led.c
+	led.c \
+	animations.c
 
 
 ## chip/board settings
 ## chip/board settings
 # - the next two should match the directories in
 # - the next two should match the directories in
@@ -59,21 +60,17 @@ OPT_DEFS += -DCORTEX_VTOR_INIT=0x00002000
 #
 #
 CUSTOM_MATRIX ?= yes # Custom matrix file
 CUSTOM_MATRIX ?= yes # Custom matrix file
 SERIAL_LINK_ENABLE = yes
 SERIAL_LINK_ENABLE = yes
-VISUALIZER_ENABLE ?= no #temporarily disabled to make everything compile
+VISUALIZER_ENABLE ?= yes
 LCD_ENABLE ?= yes
 LCD_ENABLE ?= yes
-LED_ENABLE ?= yes
+LED_ENABLE ?= no
 LCD_BACKLIGHT_ENABLE ?= yes
 LCD_BACKLIGHT_ENABLE ?= yes
 MIDI_ENABLE = no
 MIDI_ENABLE = no
 RGBLIGHT_ENABLE = no
 RGBLIGHT_ENABLE = no
 
 
-ifndef QUANTUM_DIR
-	include ../../../Makefile
-endif
-
 ifdef LCD_ENABLE
 ifdef LCD_ENABLE
 include $(SUBPROJECT_PATH)/drivers/gdisp/st7565ergodox/driver.mk
 include $(SUBPROJECT_PATH)/drivers/gdisp/st7565ergodox/driver.mk
 endif
 endif
 
 
 ifdef LED_ENABLE
 ifdef LED_ENABLE
 include $(SUBPROJECT_PATH)/drivers/gdisp/IS31FL3731C/driver.mk
 include $(SUBPROJECT_PATH)/drivers/gdisp/IS31FL3731C/driver.mk
-endif
+endif

+ 123 - 0
keyboards/ergodox/infinity/simple_visualizer.h

@@ -0,0 +1,123 @@
+/* Copyright 2017 Fred Sundvik
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KEYBOARDS_ERGODOX_INFINITY_SIMPLE_VISUALIZER_H_
+#define KEYBOARDS_ERGODOX_INFINITY_SIMPLE_VISUALIZER_H_
+
+// 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"
+#include "visualizer_keyframes.h"
+#include "lcd_keyframes.h"
+#include "lcd_backlight_keyframes.h"
+#include "system/serial_link.h"
+#include "led.h"
+#include "animations.h"
+
+static const uint32_t logo_background_color = LCD_COLOR(0x00, 0x00, 0xFF);
+static const uint32_t initial_color = LCD_COLOR(0, 0, 0);
+
+static bool initial_update = true;
+
+// Feel free to modify the animations below, or even add new ones if needed
+
+static keyframe_animation_t lcd_layer_display = {
+    .num_frames = 1,
+    .loop = false,
+    .frame_lengths = {gfxMillisecondsToTicks(0)},
+    .frame_functions = {lcd_keyframe_display_layer_and_led_states}
+};
+
+// 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 = {gfxMillisecondsToTicks(200), gfxMillisecondsToTicks(500)},
+    .frame_functions = {keyframe_no_operation, backlight_keyframe_animate_color},
+};
+
+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(130);
+    state->current_lcd_color = initial_color;
+    state->target_lcd_color = logo_background_color;
+    initial_update = true;
+    start_keyframe_animation(&default_startup_animation);
+}
+
+
+// This function should be implemented by the keymap visualizer
+// Don't change anything else than state->target_lcd_color and state->layer_text as that's the only thing
+// that the simple_visualizer assumes that you are updating
+// Also make sure that the buffer passed to state->layer_text remains valid until the previous animation is
+// stopped. This can be done by either double buffering it or by using constant strings
+static void get_visualizer_layer_and_color(visualizer_state_t* state);
+
+void update_user_visualizer_state(visualizer_state_t* state, visualizer_keyboard_status_t* prev_status) {
+    // 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)
+
+    uint32_t prev_color = state->target_lcd_color;
+    const char* prev_layer_text = state->layer_text;
+
+    get_visualizer_layer_and_color(state);
+
+    if (initial_update || prev_color != state->target_lcd_color) {
+        start_keyframe_animation(&color_animation);
+    }
+
+    if (initial_update || prev_layer_text != state->layer_text) {
+        start_keyframe_animation(&lcd_layer_display);
+    }
+    // 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.
+}
+
+void user_visualizer_suspend(visualizer_state_t* state) {
+    state->layer_text = "Suspending...";
+    uint8_t hue = LCD_HUE(state->current_lcd_color);
+    uint8_t sat = LCD_SAT(state->current_lcd_color);
+    state->target_lcd_color = LCD_COLOR(hue, sat, 0);
+    start_keyframe_animation(&default_suspend_animation);
+}
+
+void user_visualizer_resume(visualizer_state_t* state) {
+    state->current_lcd_color = initial_color;
+    state->target_lcd_color = logo_background_color;
+    initial_update = true;
+    start_keyframe_animation(&default_startup_animation);
+}
+
+#endif /* KEYBOARDS_ERGODOX_INFINITY_SIMPLE_VISUALIZER_H_ */

+ 329 - 0
keyboards/ergodox/infinity/visualizer.c

@@ -0,0 +1,329 @@
+/*
+Copyright 2016 Fred Sundvik <fsundvik@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+// 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"
+#include "visualizer_keyframes.h"
+#include "lcd_keyframes.h"
+#include "lcd_backlight_keyframes.h"
+#include "system/serial_link.h"
+#include "animations.h"
+
+static const uint32_t logo_background_color = LCD_COLOR(0x00, 0x00, 0xFF);
+static const uint32_t initial_color = LCD_COLOR(0, 0, 0);
+
+static const uint32_t led_emulation_colors[4] = {
+    LCD_COLOR(0, 0, 0),
+    LCD_COLOR(255, 255, 255),
+    LCD_COLOR(84, 255, 255),
+    LCD_COLOR(168, 255, 255),
+};
+
+static uint32_t next_led_target_color = 0;
+
+typedef enum {
+    LCD_STATE_INITIAL,
+    LCD_STATE_LAYER_BITMAP,
+    LCD_STATE_BITMAP_AND_LEDS,
+} lcd_state_t;
+
+static lcd_state_t lcd_state = LCD_STATE_INITIAL;
+
+typedef struct {
+    uint8_t led_on;
+    uint8_t led1;
+    uint8_t led2;
+    uint8_t led3;
+} visualizer_user_data_t;
+
+// Don't access from visualization function, use the visualizer state instead
+static visualizer_user_data_t user_data_keyboard = {
+    .led_on = 0,
+    .led1 = LED_BRIGHTNESS_HI,
+    .led2 = LED_BRIGHTNESS_HI,
+    .led3 = LED_BRIGHTNESS_HI,
+};
+
+_Static_assert(sizeof(visualizer_user_data_t) <= VISUALIZER_USER_DATA_SIZE,
+    "Please increase the VISUALIZER_USER_DATA_SIZE");
+
+// Feel free to modify the animations below, or even add new ones if needed
+
+
+// The color animation animates the LCD color when you change layers
+static keyframe_animation_t one_led_color = {
+    .num_frames = 1,
+    .loop = false,
+    .frame_lengths = {gfxMillisecondsToTicks(0)},
+    .frame_functions = {backlight_keyframe_set_color},
+};
+
+bool swap_led_target_color(keyframe_animation_t* animation, visualizer_state_t* state) {
+    uint32_t temp = next_led_target_color;
+    next_led_target_color = state->target_lcd_color;
+    state->target_lcd_color = temp;
+    return false;
+}
+
+// The color animation animates the LCD color when you change layers
+static keyframe_animation_t two_led_colors = {
+    .num_frames = 2,
+    .loop = true,
+    .frame_lengths = {gfxMillisecondsToTicks(1000), gfxMillisecondsToTicks(0)},
+    .frame_functions = {backlight_keyframe_set_color, swap_led_target_color},
+};
+
+// The LCD animation alternates between the layer name display and a
+// bitmap that displays all active layers
+static keyframe_animation_t lcd_bitmap_animation = {
+    .num_frames = 1,
+    .loop = false,
+    .frame_lengths = {gfxMillisecondsToTicks(0)},
+    .frame_functions = {lcd_keyframe_display_layer_bitmap},
+};
+
+static keyframe_animation_t lcd_bitmap_leds_animation = {
+    .num_frames = 2,
+    .loop = true,
+    .frame_lengths = {gfxMillisecondsToTicks(2000), gfxMillisecondsToTicks(2000)},
+    .frame_functions = {lcd_keyframe_display_layer_bitmap, lcd_keyframe_display_led_states},
+};
+
+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(130);
+    state->current_lcd_color = initial_color;
+    state->target_lcd_color = logo_background_color;
+    lcd_state = LCD_STATE_INITIAL;
+    start_keyframe_animation(&default_startup_animation);
+}
+
+inline bool is_led_on(visualizer_user_data_t* user_data, uint8_t num) {
+    return user_data->led_on & (1u << num);
+}
+
+static uint8_t get_led_index_master(visualizer_user_data_t* user_data) {
+    for (int i=0; i < 3; i++) {
+        if (is_led_on(user_data, i)) {
+            return i + 1;
+        }
+    }
+    return 0;
+}
+
+static uint8_t get_led_index_slave(visualizer_user_data_t* user_data) {
+    uint8_t master_index = get_led_index_master(user_data);
+    if (master_index!=0) {
+        for (int i=master_index; i < 3; i++) {
+            if (is_led_on(user_data, i)) {
+                return i + 1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+static uint8_t get_secondary_led_index(visualizer_user_data_t* user_data) {
+    if (is_led_on(user_data, 0) &&
+            is_led_on(user_data, 1) &&
+            is_led_on(user_data, 2)) {
+        return 3;
+    }
+    return 0;
+}
+
+static uint8_t get_brightness(visualizer_user_data_t* user_data, uint8_t index) {
+    switch (index) {
+    case 1:
+        return user_data->led1;
+    case 2:
+        return user_data->led2;
+    case 3:
+        return user_data->led3;
+    }
+    return 0;
+}
+
+static void update_emulated_leds(visualizer_state_t* state, visualizer_keyboard_status_t* prev_status) {
+    visualizer_user_data_t* user_data_new = (visualizer_user_data_t*)state->status.user_data;
+    visualizer_user_data_t* user_data_old = (visualizer_user_data_t*)prev_status->user_data;
+
+    uint8_t new_index;
+    uint8_t old_index;
+
+    if (is_serial_link_master()) {
+        new_index = get_led_index_master(user_data_new);
+        old_index = get_led_index_master(user_data_old);
+    }
+    else {
+        new_index = get_led_index_slave(user_data_new);
+        old_index = get_led_index_slave(user_data_old);
+    }
+    uint8_t new_secondary_index = get_secondary_led_index(user_data_new);
+    uint8_t old_secondary_index = get_secondary_led_index(user_data_old);
+
+    uint8_t old_brightness = get_brightness(user_data_old, old_index);
+    uint8_t new_brightness = get_brightness(user_data_new, new_index);
+
+    uint8_t old_secondary_brightness = get_brightness(user_data_old, old_secondary_index);
+    uint8_t new_secondary_brightness = get_brightness(user_data_new, new_secondary_index);
+
+    if (lcd_state == LCD_STATE_INITIAL ||
+            new_index != old_index ||
+            new_secondary_index != old_secondary_index ||
+            new_brightness != old_brightness ||
+            new_secondary_brightness != old_secondary_brightness) {
+
+        if (new_secondary_index != 0) {
+            state->target_lcd_color = change_lcd_color_intensity(
+                led_emulation_colors[new_index], new_brightness);
+            next_led_target_color = change_lcd_color_intensity(
+                led_emulation_colors[new_secondary_index], new_secondary_brightness);
+
+            stop_keyframe_animation(&one_led_color);
+            start_keyframe_animation(&two_led_colors);
+        } else {
+            state->target_lcd_color = change_lcd_color_intensity(
+                led_emulation_colors[new_index], new_brightness);
+            stop_keyframe_animation(&two_led_colors);
+            start_keyframe_animation(&one_led_color);
+        }
+    }
+}
+
+static void update_lcd_text(visualizer_state_t* state, visualizer_keyboard_status_t* prev_status) {
+    if (state->status.leds) {
+        if (lcd_state != LCD_STATE_BITMAP_AND_LEDS ||
+                state->status.leds != prev_status->leds ||
+                state->status.layer != prev_status->layer ||
+                state->status.default_layer != prev_status->default_layer) {
+
+            // NOTE: that it doesn't matter if the animation isn't playing, stop will do nothing in that case
+            stop_keyframe_animation(&lcd_bitmap_animation);
+
+            lcd_state = LCD_STATE_BITMAP_AND_LEDS;
+            // For information:
+            // The logic in this function makes sure that this doesn't happen, but if you call start on an
+            // animation that is already playing it will be restarted.
+            start_keyframe_animation(&lcd_bitmap_leds_animation);
+        }
+    } else {
+        if (lcd_state != LCD_STATE_LAYER_BITMAP ||
+                state->status.layer != prev_status->layer ||
+                state->status.default_layer != prev_status->default_layer) {
+
+            stop_keyframe_animation(&lcd_bitmap_leds_animation);
+
+            lcd_state = LCD_STATE_LAYER_BITMAP;
+            start_keyframe_animation(&lcd_bitmap_animation);
+        }
+    }
+}
+
+void update_user_visualizer_state(visualizer_state_t* state, visualizer_keyboard_status_t* prev_status) {
+    // Check the status here to start and stop animations
+    // You might have to save some state, like the current animation here so that you can start the right
+    // This function is called every time the status changes
+
+    // NOTE that this is called from the visualizer thread, so don't access anything else outside the status
+    // This is also important because the slave won't have access to the active layer for example outside the
+    // status.
+
+    update_emulated_leds(state, prev_status);
+    update_lcd_text(state, prev_status);
+
+}
+
+void user_visualizer_suspend(visualizer_state_t* state) {
+    state->layer_text = "Suspending...";
+    uint8_t hue = LCD_HUE(state->current_lcd_color);
+    uint8_t sat = LCD_SAT(state->current_lcd_color);
+    state->target_lcd_color = LCD_COLOR(hue, sat, 0);
+    start_keyframe_animation(&default_suspend_animation);
+}
+
+void user_visualizer_resume(visualizer_state_t* state) {
+    state->current_lcd_color = initial_color;
+    state->target_lcd_color = logo_background_color;
+    lcd_state = LCD_STATE_INITIAL;
+    start_keyframe_animation(&default_startup_animation);
+}
+
+void ergodox_board_led_on(void){
+    // No board led support
+}
+
+void ergodox_right_led_1_on(void){
+    user_data_keyboard.led_on |= (1u << 0);
+    visualizer_set_user_data(&user_data_keyboard);
+}
+
+void ergodox_right_led_2_on(void){
+    user_data_keyboard.led_on |= (1u << 1);
+    visualizer_set_user_data(&user_data_keyboard);
+}
+
+void ergodox_right_led_3_on(void){
+    user_data_keyboard.led_on |= (1u << 2);
+    visualizer_set_user_data(&user_data_keyboard);
+}
+
+void ergodox_board_led_off(void){
+    // No board led support
+}
+
+void ergodox_right_led_1_off(void){
+    user_data_keyboard.led_on &= ~(1u << 0);
+    visualizer_set_user_data(&user_data_keyboard);
+}
+
+void ergodox_right_led_2_off(void){
+    user_data_keyboard.led_on &= ~(1u << 1);
+    visualizer_set_user_data(&user_data_keyboard);
+}
+
+void ergodox_right_led_3_off(void){
+    user_data_keyboard.led_on &= ~(1u << 2);
+    visualizer_set_user_data(&user_data_keyboard);
+}
+
+void ergodox_right_led_1_set(uint8_t n) {
+    user_data_keyboard.led1 = n;
+    visualizer_set_user_data(&user_data_keyboard);
+}
+
+void ergodox_right_led_2_set(uint8_t n) {
+    user_data_keyboard.led2 = n;
+    visualizer_set_user_data(&user_data_keyboard);
+}
+
+void ergodox_right_led_3_set(uint8_t n) {
+    user_data_keyboard.led3 = n;
+    visualizer_set_user_data(&user_data_keyboard);
+}

+ 42 - 0
keyboards/ergodox/keymaps/default/visualizer.c

@@ -0,0 +1,42 @@
+/*
+Copyright 2017 Fred Sundvik
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "simple_visualizer.h"
+
+// This function should be implemented by the keymap visualizer
+// Don't change anything else than state->target_lcd_color and state->layer_text as that's the only thing
+// that the simple_visualizer assumes that you are updating
+// Also make sure that the buffer passed to state->layer_text remains valid until the previous animation is
+// stopped. This can be done by either double buffering it or by using constant strings
+static void get_visualizer_layer_and_color(visualizer_state_t* state) {
+    uint8_t saturation = 60;
+    if (state->status.leds & (1u << USB_LED_CAPS_LOCK)) {
+        saturation = 255;
+    }
+    if (state->status.layer & 0x4) {
+        state->target_lcd_color = LCD_COLOR(0, saturation, 0xFF);
+        state->layer_text = "Media & Mouse";
+    }
+    else if (state->status.layer & 0x2) {
+        state->target_lcd_color = LCD_COLOR(168, saturation, 0xFF);
+        state->layer_text = "Symbol";
+    }
+    else {
+        state->target_lcd_color = LCD_COLOR(84, saturation, 0xFF);
+        state->layer_text = "Default";
+    }
+}

+ 71 - 0
quantum/led_tables.c

@@ -0,0 +1,71 @@
+/*
+Copyright 2017 Fred Sundvik
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "led_tables.h"
+
+
+#ifdef USE_CIE1931_CURVE
+// Lightness curve using the CIE 1931 lightness formula
+//Generated by the python script provided in http://jared.geek.nz/2013/feb/linear-led-pwm
+const uint8_t CIE1931_CURVE[] PROGMEM = {
+    0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
+    3, 4, 4, 4, 4, 4, 4, 5, 5, 5,
+    5, 5, 6, 6, 6, 6, 6, 7, 7, 7,
+    7, 8, 8, 8, 8, 9, 9, 9, 10, 10,
+    10, 10, 11, 11, 11, 12, 12, 12, 13, 13,
+    13, 14, 14, 15, 15, 15, 16, 16, 17, 17,
+    17, 18, 18, 19, 19, 20, 20, 21, 21, 22,
+    22, 23, 23, 24, 24, 25, 25, 26, 26, 27,
+    28, 28, 29, 29, 30, 31, 31, 32, 32, 33,
+    34, 34, 35, 36, 37, 37, 38, 39, 39, 40,
+    41, 42, 43, 43, 44, 45, 46, 47, 47, 48,
+    49, 50, 51, 52, 53, 54, 54, 55, 56, 57,
+    58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
+    68, 70, 71, 72, 73, 74, 75, 76, 77, 79,
+    80, 81, 82, 83, 85, 86, 87, 88, 90, 91,
+    92, 94, 95, 96, 98, 99, 100, 102, 103, 105,
+    106, 108, 109, 110, 112, 113, 115, 116, 118, 120,
+    121, 123, 124, 126, 128, 129, 131, 132, 134, 136,
+    138, 139, 141, 143, 145, 146, 148, 150, 152, 154,
+    155, 157, 159, 161, 163, 165, 167, 169, 171, 173,
+    175, 177, 179, 181, 183, 185, 187, 189, 191, 193,
+    196, 198, 200, 202, 204, 207, 209, 211, 214, 216,
+    218, 220, 223, 225, 228, 230, 232, 235, 237, 240,
+    242, 245, 247, 250, 252, 255,
+    };
+#endif
+
+#ifdef USE_LED_BREATHING_TABLE
+const uint8_t LED_BREATHING_TABLE[] PROGMEM = {
+  0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 9,
+  10, 11, 12, 14, 15, 17, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35,
+  37, 40, 42, 44, 47, 49, 52, 54, 57, 59, 62, 65, 67, 70, 73, 76,
+  79, 82, 85, 88, 90, 93, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124,
+  127, 131, 134, 137, 140, 143, 146, 149, 152, 155, 158, 162, 165, 167, 170, 173,
+  176, 179, 182, 185, 188, 190, 193, 196, 198, 201, 203, 206, 208, 211, 213, 215,
+  218, 220, 222, 224, 226, 228, 230, 232, 234, 235, 237, 238, 240, 241, 243, 244,
+  245, 246, 248, 249, 250, 250, 251, 252, 253, 253, 254, 254, 254, 255, 255, 255,
+  255, 255, 255, 255, 254, 254, 254, 253, 253, 252, 251, 250, 250, 249, 248, 246,
+  245, 244, 243, 241, 240, 238, 237, 235, 234, 232, 230, 228, 226, 224, 222, 220,
+  218, 215, 213, 211, 208, 206, 203, 201, 198, 196, 193, 190, 188, 185, 182, 179,
+  176, 173, 170, 167, 165, 162, 158, 155, 152, 149, 146, 143, 140, 137, 134, 131,
+  128, 124, 121, 118, 115, 112, 109, 106, 103, 100, 97, 93, 90, 88, 85, 82,
+  79, 76, 73, 70, 67, 65, 62, 59, 57, 54, 52, 49, 47, 44, 42, 40,
+  37, 35, 33, 31, 29, 27, 25, 23, 21, 20, 18, 17, 15, 14, 12, 11,
+  10, 9, 7, 6, 5, 5, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0
+};
+#endif

+ 30 - 0
quantum/led_tables.h

@@ -0,0 +1,30 @@
+/*
+Copyright 2017 Fred Sundvik
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef LED_TABLES_H
+#define LED_TABLES_H
+
+#include "progmem.h"
+#include <stdint.h>
+
+#ifdef USE_CIE1931_CURVE
+extern const uint8_t CIE1931_CURVE[] PROGMEM;
+#endif
+
+#ifdef USE_LED_BREATHING_TABLE
+extern const uint8_t LED_BREATHING_TABLE[] PROGMEM;
+#endif
+
+#endif

+ 5 - 53
quantum/rgblight.c

@@ -20,56 +20,8 @@
 #include "timer.h"
 #include "timer.h"
 #include "rgblight.h"
 #include "rgblight.h"
 #include "debug.h"
 #include "debug.h"
+#include "led_tables.h"
 
 
-// Lightness curve using the CIE 1931 lightness formula
-//Generated by the python script provided in http://jared.geek.nz/2013/feb/linear-led-pwm
-const uint8_t DIM_CURVE[] PROGMEM = {
-    0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
-    1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
-    2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
-    3, 4, 4, 4, 4, 4, 4, 5, 5, 5,
-    5, 5, 6, 6, 6, 6, 6, 7, 7, 7,
-    7, 8, 8, 8, 8, 9, 9, 9, 10, 10,
-    10, 10, 11, 11, 11, 12, 12, 12, 13, 13,
-    13, 14, 14, 15, 15, 15, 16, 16, 17, 17,
-    17, 18, 18, 19, 19, 20, 20, 21, 21, 22,
-    22, 23, 23, 24, 24, 25, 25, 26, 26, 27,
-    28, 28, 29, 29, 30, 31, 31, 32, 32, 33,
-    34, 34, 35, 36, 37, 37, 38, 39, 39, 40,
-    41, 42, 43, 43, 44, 45, 46, 47, 47, 48,
-    49, 50, 51, 52, 53, 54, 54, 55, 56, 57,
-    58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
-    68, 70, 71, 72, 73, 74, 75, 76, 77, 79,
-    80, 81, 82, 83, 85, 86, 87, 88, 90, 91,
-    92, 94, 95, 96, 98, 99, 100, 102, 103, 105,
-    106, 108, 109, 110, 112, 113, 115, 116, 118, 120,
-    121, 123, 124, 126, 128, 129, 131, 132, 134, 136,
-    138, 139, 141, 143, 145, 146, 148, 150, 152, 154,
-    155, 157, 159, 161, 163, 165, 167, 169, 171, 173,
-    175, 177, 179, 181, 183, 185, 187, 189, 191, 193,
-    196, 198, 200, 202, 204, 207, 209, 211, 214, 216,
-    218, 220, 223, 225, 228, 230, 232, 235, 237, 240,
-    242, 245, 247, 250, 252, 255,
-    };
-
-const uint8_t RGBLED_BREATHING_TABLE[] PROGMEM = {
-  0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 9,
-  10, 11, 12, 14, 15, 17, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35,
-  37, 40, 42, 44, 47, 49, 52, 54, 57, 59, 62, 65, 67, 70, 73, 76,
-  79, 82, 85, 88, 90, 93, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124,
-  127, 131, 134, 137, 140, 143, 146, 149, 152, 155, 158, 162, 165, 167, 170, 173,
-  176, 179, 182, 185, 188, 190, 193, 196, 198, 201, 203, 206, 208, 211, 213, 215,
-  218, 220, 222, 224, 226, 228, 230, 232, 234, 235, 237, 238, 240, 241, 243, 244,
-  245, 246, 248, 249, 250, 250, 251, 252, 253, 253, 254, 254, 254, 255, 255, 255,
-  255, 255, 255, 255, 254, 254, 254, 253, 253, 252, 251, 250, 250, 249, 248, 246,
-  245, 244, 243, 241, 240, 238, 237, 235, 234, 232, 230, 228, 226, 224, 222, 220,
-  218, 215, 213, 211, 208, 206, 203, 201, 198, 196, 193, 190, 188, 185, 182, 179,
-  176, 173, 170, 167, 165, 162, 158, 155, 152, 149, 146, 143, 140, 137, 134, 131,
-  128, 124, 121, 118, 115, 112, 109, 106, 103, 100, 97, 93, 90, 88, 85, 82,
-  79, 76, 73, 70, 67, 65, 62, 59, 57, 54, 52, 49, 47, 44, 42, 40,
-  37, 35, 33, 31, 29, 27, 25, 23, 21, 20, 18, 17, 15, 14, 12, 11,
-  10, 9, 7, 6, 5, 5, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0
-};
 
 
 __attribute__ ((weak))
 __attribute__ ((weak))
 const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5};
 const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5};
@@ -135,9 +87,9 @@ void sethsv(uint16_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1) {
         break;
         break;
     }
     }
   }
   }
-  r = pgm_read_byte(&DIM_CURVE[r]);
-  g = pgm_read_byte(&DIM_CURVE[g]);
-  b = pgm_read_byte(&DIM_CURVE[b]);
+  r = pgm_read_byte(&CIE1931_CURVE[r]);
+  g = pgm_read_byte(&CIE1931_CURVE[g]);
+  b = pgm_read_byte(&CIE1931_CURVE[b]);
 
 
   setrgb(r, g, b, led1);
   setrgb(r, g, b, led1);
 }
 }
@@ -509,7 +461,7 @@ void rgblight_effect_breathing(uint8_t interval) {
   }
   }
   last_timer = timer_read();
   last_timer = timer_read();
 
 
-  rgblight_sethsv_noeeprom(rgblight_config.hue, rgblight_config.sat, pgm_read_byte(&RGBLED_BREATHING_TABLE[pos]));
+  rgblight_sethsv_noeeprom(rgblight_config.hue, rgblight_config.sat, pgm_read_byte(&LED_BREATHING_TABLE[pos]));
   pos = (pos + 1) % 256;
   pos = (pos + 1) % 256;
 }
 }
 void rgblight_effect_rainbow_mood(uint8_t interval) {
 void rgblight_effect_rainbow_mood(uint8_t interval) {

+ 1 - 1
quantum/serial_link/system/serial_link.c

@@ -212,7 +212,7 @@ void serial_link_update(void) {
 
 
     systime_t current_time = chVTGetSystemTimeX();
     systime_t current_time = chVTGetSystemTimeX();
     systime_t delta = current_time - last_update;
     systime_t delta = current_time - last_update;
-    if (changed || delta > US2ST(1000)) {
+    if (changed || delta > US2ST(5000)) {
         last_update = current_time;
         last_update = current_time;
         last_matrix = matrix;
         last_matrix = matrix;
         matrix_object_t* m = begin_write_keyboard_matrix();
         matrix_object_t* m = begin_write_keyboard_matrix();

+ 0 - 36
quantum/visualizer/example_integration/callbacks.c

@@ -1,36 +0,0 @@
-/*
-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());
-}

+ 0 - 325
quantum/visualizer/example_integration/gfxconf.h

@@ -1,325 +0,0 @@
-/**
- * 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 */

+ 0 - 91
quantum/visualizer/example_integration/lcd_backlight_hal.c

@@ -1,91 +0,0 @@
-/*
-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;
-}
-

+ 0 - 121
quantum/visualizer/example_integration/visualizer_user.c

@@ -1,121 +0,0 @@
-/*
-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);
-}

+ 4 - 4
quantum/visualizer/lcd_backlight.c

@@ -25,10 +25,10 @@ SOFTWARE.
 #include "lcd_backlight.h"
 #include "lcd_backlight.h"
 #include <math.h>
 #include <math.h>
 
 
-static uint8_t current_hue = 0x00;
-static uint8_t current_saturation = 0x00;
-static uint8_t current_intensity = 0xFF;
-static uint8_t current_brightness = 0x7F;
+static uint8_t current_hue = 0;
+static uint8_t current_saturation = 0;
+static uint8_t current_intensity = 0;
+static uint8_t current_brightness = 0;
 
 
 void lcd_backlight_init(void) {
 void lcd_backlight_init(void) {
     lcd_backlight_hal_init();
     lcd_backlight_hal_init();

+ 4 - 0
quantum/visualizer/lcd_backlight.h

@@ -32,6 +32,10 @@ SOFTWARE.
 #define LCD_SAT(color) ((color >> 8) & 0xFF)
 #define LCD_SAT(color) ((color >> 8) & 0xFF)
 #define LCD_INT(color) (color & 0xFF)
 #define LCD_INT(color) (color & 0xFF)
 
 
+inline uint32_t change_lcd_color_intensity(uint32_t color, uint8_t new_intensity) {
+    return (color & 0xFFFFFF00) | new_intensity;
+}
+
 void lcd_backlight_init(void);
 void lcd_backlight_init(void);
 void lcd_backlight_color(uint8_t hue, uint8_t saturation, uint8_t intensity);
 void lcd_backlight_color(uint8_t hue, uint8_t saturation, uint8_t intensity);
 void lcd_backlight_brightness(uint8_t b);
 void lcd_backlight_brightness(uint8_t b);

+ 77 - 0
quantum/visualizer/lcd_backlight_keyframes.c

@@ -0,0 +1,77 @@
+/* Copyright 2017 Fred Sundvik
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "lcd_backlight_keyframes.h"
+
+bool backlight_keyframe_animate_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 backlight_keyframe_set_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;
+}
+
+bool backlight_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state) {
+    (void)animation;
+    (void)state;
+    lcd_backlight_hal_color(0, 0, 0);
+    return false;
+}
+
+bool backlight_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state) {
+    (void)animation;
+    (void)state;
+    lcd_backlight_color(LCD_HUE(state->current_lcd_color),
+        LCD_SAT(state->current_lcd_color),
+        LCD_INT(state->current_lcd_color));
+    return false;
+}

+ 30 - 0
quantum/visualizer/lcd_backlight_keyframes.h

@@ -0,0 +1,30 @@
+/* Copyright 2017 Fred Sundvik
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QUANTUM_VISUALIZER_LCD_BACKLIGHT_KEYFRAMES_H_
+#define QUANTUM_VISUALIZER_LCD_BACKLIGHT_KEYFRAMES_H_
+
+#include "visualizer.h"
+
+// Animates the LCD backlight color between the current color and the target color (of the state)
+bool backlight_keyframe_animate_color(keyframe_animation_t* animation, visualizer_state_t* state);
+// Sets the backlight color to the target color
+bool backlight_keyframe_set_color(keyframe_animation_t* animation, visualizer_state_t* state);
+
+bool backlight_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state);
+bool backlight_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state);
+
+#endif /* QUANTUM_VISUALIZER_LCD_BACKLIGHT_KEYFRAMES_H_ */

+ 188 - 0
quantum/visualizer/lcd_keyframes.c

@@ -0,0 +1,188 @@
+/* Copyright 2017 Fred Sundvik
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "lcd_keyframes.h"
+#include <string.h>
+#include "action_util.h"
+#include "led.h"
+#include "resources/resources.h"
+
+bool lcd_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);
+    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 lcd_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);
+    return false;
+}
+
+static void format_mods_bitmap_string(uint8_t mods, char* buffer) {
+    *buffer = ' ';
+    ++buffer;
+
+    for (int i = 0; i<8; i++)
+    {
+        uint32_t mask = (1u << i);
+        if (mods & mask) {
+            *buffer = '1';
+        } else {
+            *buffer = '0';
+        }
+        ++buffer;
+
+        if (i==3) {
+            *buffer = ' ';
+            ++buffer;
+        }
+    }
+    *buffer = 0;
+}
+
+bool lcd_keyframe_display_mods_bitmap(keyframe_animation_t* animation, visualizer_state_t* state) {
+    (void)animation;
+
+    const char* title = "Modifier states";
+    const char* mods_header = " CSAG CSAG ";
+    char status_buffer[12];
+
+    gdispClear(White);
+    gdispDrawString(0, 0, title, state->font_fixed5x8, Black);
+    gdispDrawString(0, 10, mods_header, state->font_fixed5x8, Black);
+    format_mods_bitmap_string(state->status.mods, status_buffer);
+    gdispDrawString(0, 20, status_buffer, state->font_fixed5x8, Black);
+
+    return false;
+}
+
+#define LED_STATE_STRING_SIZE sizeof("NUM CAPS SCRL COMP KANA")
+
+static void get_led_state_string(char* output, visualizer_state_t* state) {
+    uint8_t pos = 0;
+
+    if (state->status.leds & (1u << USB_LED_NUM_LOCK)) {
+       memcpy(output + pos, "NUM ", 4);
+       pos += 4;
+    }
+    if (state->status.leds & (1u << USB_LED_CAPS_LOCK)) {
+       memcpy(output + pos, "CAPS ", 5);
+       pos += 5;
+    }
+    if (state->status.leds & (1u << USB_LED_SCROLL_LOCK)) {
+       memcpy(output + pos, "SCRL ", 5);
+       pos += 5;
+    }
+    if (state->status.leds & (1u << USB_LED_COMPOSE)) {
+       memcpy(output + pos, "COMP ", 5);
+       pos += 5;
+    }
+    if (state->status.leds & (1u << USB_LED_KANA)) {
+       memcpy(output + pos, "KANA ", 5);
+       pos += 5;
+    }
+    output[pos] = 0;
+}
+
+bool lcd_keyframe_display_led_states(keyframe_animation_t* animation, visualizer_state_t* state)
+{
+    (void)animation;
+    char output[LED_STATE_STRING_SIZE];
+    get_led_state_string(output, state);
+    gdispClear(White);
+    gdispDrawString(0, 10, output, state->font_dejavusansbold12, Black);
+    return false;
+}
+
+bool lcd_keyframe_display_layer_and_led_states(keyframe_animation_t* animation, visualizer_state_t* state) {
+    (void)animation;
+    gdispClear(White);
+    uint8_t y = 10;
+    if (state->status.leds) {
+        char output[LED_STATE_STRING_SIZE];
+        get_led_state_string(output, state);
+        gdispDrawString(0, 1, output, state->font_dejavusansbold12, Black);
+        y = 17;
+    }
+    gdispDrawString(0, y, state->layer_text, state->font_dejavusansbold12, Black);
+    return false;
+}
+
+bool lcd_keyframe_draw_logo(keyframe_animation_t* animation, visualizer_state_t* state) {
+    (void)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, here we use the image
+
+    //gdispGBlitArea is a tricky function to use since it supports blitting part of the image
+    // if you have full screen image, then just use 128 and 32 for both source and target dimensions
+    gdispGBlitArea(GDISP, 0, 0, 128, 32, 0, 0, 128, (pixel_t*)resource_lcd_logo);
+
+    return false;
+}
+
+
+bool lcd_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state) {
+    (void)animation;
+    (void)state;
+    gdispSetPowerMode(powerOff);
+    return false;
+}
+
+bool lcd_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state) {
+    (void)animation;
+    (void)state;
+    gdispSetPowerMode(powerOn);
+    return false;
+}

+ 39 - 0
quantum/visualizer/lcd_keyframes.h

@@ -0,0 +1,39 @@
+/* Copyright 2017 Fred Sundvik
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QUANTUM_VISUALIZER_LCD_KEYFRAMES_H_
+#define QUANTUM_VISUALIZER_LCD_KEYFRAMES_H_
+
+#include "visualizer.h"
+
+// Displays the layer text centered vertically on the screen
+bool lcd_keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state);
+// Displays a bitmap (0/1) of all the currently active layers
+bool lcd_keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state);
+// Displays a bitmap (0/1) of all the currently active mods
+bool lcd_keyframe_display_mods_bitmap(keyframe_animation_t* animation, visualizer_state_t* state);
+// Displays the keyboard led states (CAPS (Caps lock), NUM (Num lock), SCRL (Scroll lock), COMP (Compose), KANA)
+bool lcd_keyframe_display_led_states(keyframe_animation_t* animation, visualizer_state_t* state);
+// Displays both the layer text and the led states
+bool lcd_keyframe_display_layer_and_led_states(keyframe_animation_t* animation, visualizer_state_t* state);
+// Displays the QMK logo on the LCD screen
+bool lcd_keyframe_draw_logo(keyframe_animation_t* animation, visualizer_state_t* state);
+
+bool lcd_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state);
+bool lcd_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state);
+
+
+#endif /* QUANTUM_VISUALIZER_LCD_KEYFRAMES_H_ */

+ 8 - 49
quantum/visualizer/led_test.c → quantum/visualizer/led_keyframes.c

@@ -21,50 +21,9 @@ 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
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 SOFTWARE.
 */
 */
-#include "led_test.h"
 #include "gfx.h"
 #include "gfx.h"
 #include "math.h"
 #include "math.h"
-
-#define CROSSFADE_TIME 1000
-#define GRADIENT_TIME 3000
-
-keyframe_animation_t led_test_animation = {
-    .num_frames = 14,
-    .loop = true,
-    .frame_lengths = {
-        gfxMillisecondsToTicks(1000), // fade in
-        gfxMillisecondsToTicks(1000), // no op (leds on)
-        gfxMillisecondsToTicks(1000), // fade out
-        gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
-        gfxMillisecondsToTicks(GRADIENT_TIME), // left to rigt (outside in)
-        gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
-        gfxMillisecondsToTicks(GRADIENT_TIME), // top_to_bottom
-        0,           // mirror leds
-        gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
-        gfxMillisecondsToTicks(GRADIENT_TIME), // left_to_right (mirrored, so inside out)
-        gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
-        gfxMillisecondsToTicks(GRADIENT_TIME), // top_to_bottom
-        0,           // normal leds
-        gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
-
-    },
-    .frame_functions = {
-        keyframe_fade_in_all_leds,
-        keyframe_no_operation,
-        keyframe_fade_out_all_leds,
-        keyframe_led_crossfade,
-        keyframe_led_left_to_right_gradient,
-        keyframe_led_crossfade,
-        keyframe_led_top_to_bottom_gradient,
-        keyframe_mirror_led_orientation,
-        keyframe_led_crossfade,
-        keyframe_led_left_to_right_gradient,
-        keyframe_led_crossfade,
-        keyframe_led_top_to_bottom_gradient,
-        keyframe_normal_led_orientation,
-        keyframe_led_crossfade,
-    },
-};
+#include "led_keyframes.h"
 
 
 static uint8_t fade_led_color(keyframe_animation_t* animation, int from, int to) {
 static uint8_t fade_led_color(keyframe_animation_t* animation, int from, int to) {
     int frame_length = animation->frame_lengths[animation->current_frame];
     int frame_length = animation->frame_lengths[animation->current_frame];
@@ -96,19 +55,19 @@ static uint8_t compute_gradient_color(float t, float index, float num) {
     return (uint8_t)(255.0f * v);
     return (uint8_t)(255.0f * v);
 }
 }
 
 
-bool keyframe_fade_in_all_leds(keyframe_animation_t* animation, visualizer_state_t* state) {
+bool led_keyframe_fade_in_all(keyframe_animation_t* animation, visualizer_state_t* state) {
     (void)state;
     (void)state;
     keyframe_fade_all_leds_from_to(animation, 0, 255);
     keyframe_fade_all_leds_from_to(animation, 0, 255);
     return true;
     return true;
 }
 }
 
 
-bool keyframe_fade_out_all_leds(keyframe_animation_t* animation, visualizer_state_t* state) {
+bool led_keyframe_fade_out_all(keyframe_animation_t* animation, visualizer_state_t* state) {
     (void)state;
     (void)state;
     keyframe_fade_all_leds_from_to(animation, 255, 0);
     keyframe_fade_all_leds_from_to(animation, 255, 0);
     return true;
     return true;
 }
 }
 
 
-bool keyframe_led_left_to_right_gradient(keyframe_animation_t* animation, visualizer_state_t* state) {
+bool led_keyframe_left_to_right_gradient(keyframe_animation_t* animation, visualizer_state_t* state) {
     (void)state;
     (void)state;
     float frame_length = animation->frame_lengths[animation->current_frame];
     float frame_length = animation->frame_lengths[animation->current_frame];
     float current_pos = frame_length - animation->time_left_in_frame;
     float current_pos = frame_length - animation->time_left_in_frame;
@@ -120,7 +79,7 @@ bool keyframe_led_left_to_right_gradient(keyframe_animation_t* animation, visual
     return true;
     return true;
 }
 }
 
 
-bool keyframe_led_top_to_bottom_gradient(keyframe_animation_t* animation, visualizer_state_t* state) {
+bool led_keyframe_top_to_bottom_gradient(keyframe_animation_t* animation, visualizer_state_t* state) {
     (void)state;
     (void)state;
     float frame_length = animation->frame_lengths[animation->current_frame];
     float frame_length = animation->frame_lengths[animation->current_frame];
     float current_pos = frame_length - animation->time_left_in_frame;
     float current_pos = frame_length - animation->time_left_in_frame;
@@ -139,7 +98,7 @@ static void copy_current_led_state(uint8_t* dest) {
         }
         }
     }
     }
 }
 }
-bool keyframe_led_crossfade(keyframe_animation_t* animation, visualizer_state_t* state) {
+bool led_keyframe_crossfade(keyframe_animation_t* animation, visualizer_state_t* state) {
     (void)state;
     (void)state;
     if (animation->first_update_of_frame) {
     if (animation->first_update_of_frame) {
         copy_current_led_state(&crossfade_start_frame[0][0]);
         copy_current_led_state(&crossfade_start_frame[0][0]);
@@ -155,14 +114,14 @@ bool keyframe_led_crossfade(keyframe_animation_t* animation, visualizer_state_t*
     return true;
     return true;
 }
 }
 
 
-bool keyframe_mirror_led_orientation(keyframe_animation_t* animation, visualizer_state_t* state) {
+bool led_keyframe_mirror_orientation(keyframe_animation_t* animation, visualizer_state_t* state) {
     (void)state;
     (void)state;
     (void)animation;
     (void)animation;
     gdispGSetOrientation(LED_DISPLAY, GDISP_ROTATE_180);
     gdispGSetOrientation(LED_DISPLAY, GDISP_ROTATE_180);
     return false;
     return false;
 }
 }
 
 
-bool keyframe_normal_led_orientation(keyframe_animation_t* animation, visualizer_state_t* state) {
+bool led_keyframe_normal_orientation(keyframe_animation_t* animation, visualizer_state_t* state) {
     (void)state;
     (void)state;
     (void)animation;
     (void)animation;
     gdispGSetOrientation(LED_DISPLAY, GDISP_ROTATE_0);
     gdispGSetOrientation(LED_DISPLAY, GDISP_ROTATE_0);

+ 10 - 10
quantum/visualizer/led_test.h → quantum/visualizer/led_keyframes.h

@@ -22,20 +22,20 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 SOFTWARE.
 */
 */
 
 
-#ifndef TMK_VISUALIZER_LED_TEST_H_
-#define TMK_VISUALIZER_LED_TEST_H_
+#ifndef LED_KEYFRAMES_H
+#define LED_KEYFRAMES_H
 
 
 #include "visualizer.h"
 #include "visualizer.h"
 
 
-bool keyframe_fade_in_all_leds(keyframe_animation_t* animation, visualizer_state_t* state);
-bool keyframe_fade_out_all_leds(keyframe_animation_t* animation, visualizer_state_t* state);
-bool keyframe_led_left_to_right_gradient(keyframe_animation_t* animation, visualizer_state_t* state);
-bool keyframe_led_top_to_bottom_gradient(keyframe_animation_t* animation, visualizer_state_t* state);
-bool keyframe_led_crossfade(keyframe_animation_t* animation, visualizer_state_t* state);
-bool keyframe_mirror_led_orientation(keyframe_animation_t* animation, visualizer_state_t* state);
-bool keyframe_normal_led_orientation(keyframe_animation_t* animation, visualizer_state_t* state);
+bool led_keyframe_fade_in_all(keyframe_animation_t* animation, visualizer_state_t* state);
+bool led_keyframe_fade_out_all(keyframe_animation_t* animation, visualizer_state_t* state);
+bool led_keyframe_left_to_right_gradient(keyframe_animation_t* animation, visualizer_state_t* state);
+bool led_keyframe_top_to_bottom_gradient(keyframe_animation_t* animation, visualizer_state_t* state);
+bool led_keyframe_crossfade(keyframe_animation_t* animation, visualizer_state_t* state);
+bool led_keyframe_mirror_orientation(keyframe_animation_t* animation, visualizer_state_t* state);
+bool led_keyframe_normal_orientation(keyframe_animation_t* animation, visualizer_state_t* state);
 
 
 extern keyframe_animation_t led_test_animation;
 extern keyframe_animation_t led_test_animation;
 
 
 
 
-#endif /* TMK_VISUALIZER_LED_TEST_H_ */
+#endif /* LED_KEYFRAMES_H */

+ 61 - 0
quantum/visualizer/resources/lcd_logo.c

@@ -0,0 +1,61 @@
+/* Copyright 2017 Fred Sundvik
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "resources.h"
+
+
+// To generate an image array like this
+// Ensure the image is 128 x 32 or smaller
+// Convert the bitmap to a C array using a program like http://www.riuson.com/lcd-image-converter/
+// Ensure the the conversion process produces a monochrome format array - 1 bit/pixel, left to right, top to bottom
+// Update array in the source code with the C array produced by the conversion program
+
+// The image below is generated from lcd_logo.png
+const uint8_t resource_lcd_logo[512] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0xf8, 0xfe, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x38, 0x38, 0x38, 0x06, 0x29, 0x41, 0x24, 0x52, 0x24, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x38, 0x38, 0x38, 0x09, 0x55, 0x42, 0xaa, 0xaa, 0xaa, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x38, 0x38, 0x38, 0x09, 0x55, 0x82, 0x28, 0xaa, 0xae, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x38, 0x38, 0x38, 0x09, 0x55, 0x43, 0x28, 0xaa, 0xaa, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x38, 0x38, 0x38, 0x0a, 0x55, 0x42, 0x28, 0xaa, 0xaa, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x38, 0x38, 0x38, 0x05, 0x45, 0x42, 0x28, 0x89, 0x4a, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x18, 0x38, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x1c, 0x38, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x0e, 0x38, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x03, 0xff, 0x80, 0x04, 0x45, 0x14, 0xa4, 0x92, 0x83, 0x52, 0x22, 0x22, 0x36, 0x00, 0x00,
+    0x00, 0x00, 0x38, 0x00, 0x0a, 0xaa, 0xaa, 0xaa, 0xba, 0x84, 0x55, 0x55, 0x57, 0x45, 0x00, 0x00,
+    0x00, 0x00, 0x38, 0x00, 0x08, 0xaa, 0xaa, 0xaa, 0x92, 0xb2, 0x55, 0x55, 0x42, 0x65, 0x00, 0x00,
+    0x00, 0x00, 0x38, 0x00, 0x08, 0xaa, 0xaa, 0xaa, 0x92, 0x81, 0x56, 0x65, 0x42, 0x45, 0x00, 0x00,
+    0x00, 0x00, 0x38, 0x00, 0x0a, 0xaa, 0xaa, 0xaa, 0x92, 0x81, 0x54, 0x45, 0x42, 0x45, 0x00, 0x00,
+    0x00, 0x00, 0x38, 0x00, 0x04, 0x48, 0xa2, 0x4a, 0x89, 0x06, 0x24, 0x42, 0x41, 0x36, 0x00, 0x00,
+    0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+

二進制
quantum/visualizer/resources/lcd_logo.png


+ 27 - 0
quantum/visualizer/resources/resources.h

@@ -0,0 +1,27 @@
+/* Copyright 2017 Fred Sundvik
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QUANTUM_VISUALIZER_RESOURCES_RESOURCES_H_
+#define QUANTUM_VISUALIZER_RESOURCES_RESOURCES_H_
+
+#include <stdint.h>
+
+#ifdef LCD_ENABLE
+extern const uint8_t resource_lcd_logo[];
+#endif
+
+
+#endif /* QUANTUM_VISUALIZER_RESOURCES_RESOURCES_H_ */

+ 47 - 179
quantum/visualizer/visualizer.c

@@ -48,20 +48,22 @@ SOFTWARE.
 #include "serial_link/system/serial_link.h"
 #include "serial_link/system/serial_link.h"
 #endif
 #endif
 
 
+#include "action_util.h"
+
 // Define this in config.h
 // Define this in config.h
 #ifndef VISUALIZER_THREAD_PRIORITY
 #ifndef VISUALIZER_THREAD_PRIORITY
 #define "Visualizer thread priority not defined"
 #define "Visualizer thread priority not defined"
 #endif
 #endif
 
 
-// mods status
-#include "action_util.h"
-
 static visualizer_keyboard_status_t current_status = {
 static visualizer_keyboard_status_t current_status = {
     .layer = 0xFFFFFFFF,
     .layer = 0xFFFFFFFF,
     .default_layer = 0xFFFFFFFF,
     .default_layer = 0xFFFFFFFF,
     .mods = 0xFF,
     .mods = 0xFF,
     .leds = 0xFFFFFFFF,
     .leds = 0xFFFFFFFF,
     .suspended = false,
     .suspended = false,
+#ifdef VISUALIZER_USER_DATA_SIZE
+    .user_data = {0}
+#endif
 };
 };
 
 
 static bool same_status(visualizer_keyboard_status_t* status1, visualizer_keyboard_status_t* status2) {
 static bool same_status(visualizer_keyboard_status_t* status1, visualizer_keyboard_status_t* status2) {
@@ -69,11 +71,19 @@ static bool same_status(visualizer_keyboard_status_t* status1, visualizer_keyboa
         status1->default_layer == status2->default_layer &&
         status1->default_layer == status2->default_layer &&
         status1->mods == status2->mods &&
         status1->mods == status2->mods &&
         status1->leds == status2->leds &&
         status1->leds == status2->leds &&
-        status1->suspended == status2->suspended;
+        status1->suspended == status2->suspended
+#ifdef VISUALIZER_USER_DATA_SIZE
+        && memcmp(status1->user_data, status2->user_data, VISUALIZER_USER_DATA_SIZE) == 0
+#endif
+    ;
 }
 }
 
 
 static bool visualizer_enabled = false;
 static bool visualizer_enabled = false;
 
 
+#ifdef VISUALIZER_USER_DATA_SIZE
+static uint8_t user_data[VISUALIZER_USER_DATA_SIZE];
+#endif
+
 #define MAX_SIMULTANEOUS_ANIMATIONS 4
 #define MAX_SIMULTANEOUS_ANIMATIONS 4
 static keyframe_animation_t* animations[MAX_SIMULTANEOUS_ANIMATIONS] = {};
 static keyframe_animation_t* animations[MAX_SIMULTANEOUS_ANIMATIONS] = {};
 
 
@@ -144,6 +154,14 @@ void stop_all_keyframe_animations(void) {
     }
     }
 }
 }
 
 
+static uint8_t get_num_running_animations(void) {
+    uint8_t count = 0;
+    for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
+        count += animations[i] ? 1 : 0;
+    }
+    return count;
+}
+
 static bool update_keyframe_animation(keyframe_animation_t* animation, visualizer_state_t* state, systemticks_t delta, systemticks_t* sleep_time) {
 static bool update_keyframe_animation(keyframe_animation_t* animation, visualizer_state_t* state, systemticks_t delta, systemticks_t* sleep_time) {
     // TODO: Clean up this messy code
     // TODO: Clean up this messy code
     dprintf("Animation frame%d, left %d, delta %d\n", animation->current_frame,
     dprintf("Animation frame%d, left %d, delta %d\n", animation->current_frame,
@@ -212,175 +230,6 @@ void run_next_keyframe(keyframe_animation_t* animation, visualizer_state_t* stat
     (*temp_animation.frame_functions[next_frame])(&temp_animation, &temp_state);
     (*temp_animation.frame_functions[next_frame])(&temp_animation, &temp_state);
 }
 }
 
 
-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;
-}
-
-static void format_mods_bitmap_string(uint8_t mods, char* buffer) {
-    *buffer = ' ';
-    ++buffer;
-
-    for (int i = 0; i<8; i++)
-    {
-        uint32_t mask = (1u << i);
-        if (mods & mask) {
-            *buffer = '1';
-        } else {
-            *buffer = '0';
-        }
-        ++buffer;
-
-        if (i==3) {
-            *buffer = ' ';
-            ++buffer;
-        }
-    }
-    *buffer = 0;
-}
-
-bool keyframe_display_mods_bitmap(keyframe_animation_t* animation, visualizer_state_t* state) {
-    (void)animation;
-
-    const char* title = "Modifier states";
-    const char* mods_header = " CSAG CSAG ";
-    char status_buffer[12]; 
-    
-    gdispClear(White);
-    gdispDrawString(0, 0, title, state->font_fixed5x8, Black);
-    gdispDrawString(0, 10, mods_header, state->font_fixed5x8, Black);
-    format_mods_bitmap_string(state->status.mods, status_buffer);
-    gdispDrawString(0, 20, status_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
 // TODO: Optimize the stack size, this is probably way too big
 static DECLARE_THREAD_STACK(visualizerThreadStack, 1024);
 static DECLARE_THREAD_STACK(visualizerThreadStack, 1024);
 static DECLARE_THREAD_FUNCTION(visualizerThread, arg) {
 static DECLARE_THREAD_FUNCTION(visualizerThread, arg) {
@@ -396,6 +245,9 @@ static DECLARE_THREAD_FUNCTION(visualizerThread, arg) {
         .mods = 0xFF,
         .mods = 0xFF,
         .leds = 0xFFFFFFFF,
         .leds = 0xFFFFFFFF,
         .suspended = false,
         .suspended = false,
+#ifdef VISUALIZER_USER_DATA_SIZE
+        .user_data = {0},
+#endif
     };
     };
 
 
     visualizer_state_t state = {
     visualizer_state_t state = {
@@ -418,13 +270,15 @@ static DECLARE_THREAD_FUNCTION(visualizerThread, arg) {
 
 
     systemticks_t sleep_time = TIME_INFINITE;
     systemticks_t sleep_time = TIME_INFINITE;
     systemticks_t current_time = gfxSystemTicks();
     systemticks_t current_time = gfxSystemTicks();
+    bool force_update = true;
 
 
     while(true) {
     while(true) {
         systemticks_t new_time = gfxSystemTicks();
         systemticks_t new_time = gfxSystemTicks();
         systemticks_t delta = new_time - current_time;
         systemticks_t delta = new_time - current_time;
         current_time = new_time;
         current_time = new_time;
         bool enabled = visualizer_enabled;
         bool enabled = visualizer_enabled;
-        if (!same_status(&state.status, &current_status)) {
+        if (force_update || !same_status(&state.status, &current_status)) {
+            force_update = false;
             if (visualizer_enabled) {
             if (visualizer_enabled) {
                 if (current_status.suspended) {
                 if (current_status.suspended) {
                     stop_all_keyframe_animations();
                     stop_all_keyframe_animations();
@@ -433,8 +287,9 @@ static DECLARE_THREAD_FUNCTION(visualizerThread, arg) {
                     user_visualizer_suspend(&state);
                     user_visualizer_suspend(&state);
                 }
                 }
                 else {
                 else {
+                    visualizer_keyboard_status_t prev_status = state.status;
                     state.status = current_status;
                     state.status = current_status;
-                    update_user_visualizer_state(&state);
+                    update_user_visualizer_state(&state, &prev_status);
                 }
                 }
                 state.prev_lcd_color = state.current_lcd_color;
                 state.prev_lcd_color = state.current_lcd_color;
             }
             }
@@ -458,13 +313,17 @@ static DECLARE_THREAD_FUNCTION(visualizerThread, arg) {
         gdispGFlush(LED_DISPLAY);
         gdispGFlush(LED_DISPLAY);
 #endif
 #endif
 
 
+#ifdef LCD_ENABLE
+        gdispGFlush(LCD_DISPLAY);
+#endif
+
 #ifdef EMULATOR
 #ifdef EMULATOR
         draw_emulator();
         draw_emulator();
 #endif
 #endif
-        // The animation can enable the visualizer
-        // And we might need to update the state when that happens
-        // so don't sleep
-        if (enabled != visualizer_enabled) {
+        // Enable the visualizer when the startup or the suspend animation has finished
+        if (!visualizer_enabled && state.status.suspended == false && get_num_running_animations() == 0) {
+            visualizer_enabled = true;
+            force_update = true;
             sleep_time = 0;
             sleep_time = 0;
         }
         }
 
 
@@ -554,6 +413,12 @@ uint8_t visualizer_get_mods() {
   return mods;
   return mods;
 }
 }
 
 
+#ifdef VISUALIZER_USER_DATA_SIZE
+void visualizer_set_user_data(void* u) {
+    memcpy(user_data, u, VISUALIZER_USER_DATA_SIZE);
+}
+#endif
+
 void visualizer_update(uint32_t default_state, uint32_t state, uint8_t mods, uint32_t leds) {
 void visualizer_update(uint32_t default_state, uint32_t state, uint8_t mods, uint32_t leds) {
     // Note that there's a small race condition here, the thread could read
     // 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
     // a state where one of these are set but not the other. But this should
@@ -582,6 +447,9 @@ void visualizer_update(uint32_t default_state, uint32_t state, uint8_t mods, uin
             .leds = leds,
             .leds = leds,
             .suspended = current_status.suspended,
             .suspended = current_status.suspended,
         };
         };
+#ifdef VISUALIZER_USER_DATA_SIZE
+       memcpy(new_status.user_data, user_data, VISUALIZER_USER_DATA_SIZE);
+#endif
         if (!same_status(&current_status, &new_status)) {
         if (!same_status(&current_status, &new_status)) {
             changed = true;
             changed = true;
             current_status = new_status;
             current_status = new_status;

+ 17 - 24
quantum/visualizer/visualizer.h

@@ -34,7 +34,7 @@ SOFTWARE.
 #include "lcd_backlight.h"
 #include "lcd_backlight.h"
 #endif
 #endif
 
 
-// use this function to merget both real_mods and oneshot_mods in a uint16_t
+// use this function to merge both real_mods and oneshot_mods in a uint16_t
 uint8_t visualizer_get_mods(void);
 uint8_t visualizer_get_mods(void);
 
 
 // This need to be called once at the start
 // This need to be called once at the start
@@ -68,6 +68,9 @@ typedef struct {
     uint8_t mods;
     uint8_t mods;
     uint32_t leds; // See led.h for available statuses
     uint32_t leds; // See led.h for available statuses
     bool suspended;
     bool suspended;
+#ifdef VISUALIZER_USER_DATA_SIZE
+    uint8_t user_data[VISUALIZER_USER_DATA_SIZE];
+#endif
 } visualizer_keyboard_status_t;
 } visualizer_keyboard_status_t;
 
 
 // The state struct is used by the various keyframe functions
 // The state struct is used by the various keyframe functions
@@ -123,32 +126,22 @@ void stop_keyframe_animation(keyframe_animation_t* animation);
 // Useful for crossfades for example
 // Useful for crossfades for example
 void run_next_keyframe(keyframe_animation_t* animation, visualizer_state_t* state);
 void run_next_keyframe(keyframe_animation_t* animation, visualizer_state_t* state);
 
 
-// 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);
-// Displays a bitmap (0/1) of all the currently active mods
-bool keyframe_display_mods_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);
+// The master can set userdata which will be transferred to the slave
+#ifdef VISUALIZER_USER_DATA_SIZE
+void visualizer_set_user_data(void* user_data);
+#endif
 
 
 // These functions have to be implemented by the user
 // These 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);
+// Called regularly each time the state has changed (but not every scan loop)
+void update_user_visualizer_state(visualizer_state_t* state, visualizer_keyboard_status_t* prev_status);
+// Called when the computer goes to suspend, will also stop calling update_user_visualizer_state
 void user_visualizer_suspend(visualizer_state_t* state);
 void user_visualizer_suspend(visualizer_state_t* state);
+// You have to start at least one animation as a response to the following two functions
+// When the animation has finished the visualizer will resume normal operation and start calling the
+// update_user_visualizer_state again
+// Called when the keyboard boots up
+void initialize_user_visualizer(visualizer_state_t* state);
+// Called when the computer resumes from a suspend
 void user_visualizer_resume(visualizer_state_t* state);
 void user_visualizer_resume(visualizer_state_t* state);
 
 
-
 #endif /* VISUALIZER_H */
 #endif /* VISUALIZER_H */

+ 15 - 6
quantum/visualizer/visualizer.mk

@@ -20,7 +20,8 @@
 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 # SOFTWARE.
 # SOFTWARE.
 
 
-SRC += $(VISUALIZER_DIR)/visualizer.c
+SRC += $(VISUALIZER_DIR)/visualizer.c \
+	$(VISUALIZER_DIR)/visualizer_keyframes.c
 EXTRAINCDIRS += $(GFXINC) $(VISUALIZER_DIR)
 EXTRAINCDIRS += $(GFXINC) $(VISUALIZER_DIR)
 GFXLIB = $(LIB_PATH)/ugfx
 GFXLIB = $(LIB_PATH)/ugfx
 VPATH += $(VISUALIZER_PATH)
 VPATH += $(VISUALIZER_PATH)
@@ -32,25 +33,33 @@ OPT_DEFS += -DLCD_ENABLE
 ULIBS += -lm
 ULIBS += -lm
 endif
 endif
 
 
-ifdef LCD_BACKLIGHT_ENABLE
+ifeq ($(strip $(LCD_ENABLE)), yes)
 SRC += $(VISUALIZER_DIR)/lcd_backlight.c
 SRC += $(VISUALIZER_DIR)/lcd_backlight.c
+SRC += $(VISUALIZER_DIR)/lcd_keyframes.c
+SRC += $(VISUALIZER_DIR)/lcd_backlight_keyframes.c
+# Note, that the linker will strip out any resources that are not actually in use
+SRC += $(VISUALIZER_DIR)/resources/lcd_logo.c
 OPT_DEFS += -DLCD_BACKLIGHT_ENABLE
 OPT_DEFS += -DLCD_BACKLIGHT_ENABLE
 endif
 endif
 
 
-ifdef LED_ENABLE
-SRC += $(VISUALIZER_DIR)/led_test.c
+ifeq ($(strip $(LED_ENABLE)), yes)
+SRC += $(VISUALIZER_DIR)/led_keyframes.c
 OPT_DEFS += -DLED_ENABLE
 OPT_DEFS += -DLED_ENABLE
 endif
 endif
 
 
 include $(GFXLIB)/gfx.mk
 include $(GFXLIB)/gfx.mk
-SRC += $(patsubst $(TOP_DIR)/%,%,$(GFXSRC))
-OPT_DEFS += $(patsubst %,-D%,$(patsubst -D%,%,$(GFXDEFS)))
+GFXSRC := $(patsubst $(TOP_DIR)/%,%,$(GFXSRC))
+GFXDEFS := $(patsubst %,-D%,$(patsubst -D%,%,$(GFXDEFS)))
 
 
 ifneq ("$(wildcard $(KEYMAP_PATH)/visualizer.c)","")
 ifneq ("$(wildcard $(KEYMAP_PATH)/visualizer.c)","")
 	SRC += keyboards/$(KEYBOARD)/keymaps/$(KEYMAP)/visualizer.c
 	SRC += keyboards/$(KEYBOARD)/keymaps/$(KEYMAP)/visualizer.c
 else 
 else 
 	ifeq ("$(wildcard $(SUBPROJECT_PATH)/keymaps/$(KEYMAP)/visualizer.c)","")
 	ifeq ("$(wildcard $(SUBPROJECT_PATH)/keymaps/$(KEYMAP)/visualizer.c)","")
+		ifeq ("$(wildcard $(SUBPROJECT_PATH)/visualizer.c)","")
 $(error "$(KEYMAP_PATH)/visualizer.c" does not exist)
 $(error "$(KEYMAP_PATH)/visualizer.c" does not exist)
+		else
+			SRC += keyboards/$(KEYBOARD)/$(SUBPROJECT)/visualizer.c
+		endif
 	else
 	else
 		SRC += keyboards/$(KEYBOARD)/$(SUBPROJECT)/keymaps/$(KEYMAP)/visualizer.c
 		SRC += keyboards/$(KEYBOARD)/$(SUBPROJECT)/keymaps/$(KEYMAP)/visualizer.c
 	endif
 	endif

+ 23 - 0
quantum/visualizer/visualizer_keyframes.c

@@ -0,0 +1,23 @@
+/* Copyright 2017 Fred Sundvik
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "visualizer_keyframes.h"
+
+bool keyframe_no_operation(keyframe_animation_t* animation, visualizer_state_t* state) {
+    (void)animation;
+    (void)state;
+    return false;
+}

+ 26 - 0
quantum/visualizer/visualizer_keyframes.h

@@ -0,0 +1,26 @@
+/* Copyright 2017 Fred Sundvik
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QUANTUM_VISUALIZER_VISUALIZER_KEYFRAMES_H_
+#define QUANTUM_VISUALIZER_VISUALIZER_KEYFRAMES_H_
+
+#include "visualizer.h"
+
+// 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);
+
+#endif /* QUANTUM_VISUALIZER_VISUALIZER_KEYFRAMES_H_ */

+ 5 - 1
tmk_core/common/action_util.c

@@ -58,9 +58,13 @@ void set_oneshot_locked_mods(int8_t mods) { oneshot_locked_mods = mods; }
 void clear_oneshot_locked_mods(void) { oneshot_locked_mods = 0; }
 void clear_oneshot_locked_mods(void) { oneshot_locked_mods = 0; }
 #if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
 #if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
 static int16_t oneshot_time = 0;
 static int16_t oneshot_time = 0;
-inline bool has_oneshot_mods_timed_out() {
+bool has_oneshot_mods_timed_out(void) {
   return TIMER_DIFF_16(timer_read(), oneshot_time) >= ONESHOT_TIMEOUT;
   return TIMER_DIFF_16(timer_read(), oneshot_time) >= ONESHOT_TIMEOUT;
 }
 }
+#else
+bool has_oneshot_mods_timed_out(void) {
+    return false;
+}
 #endif
 #endif
 #endif
 #endif