summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Young <18669334+noroadsleft@users.noreply.github.com>2020-11-28 12:02:18 -0800
committerDrashna Jael're <drashna@live.com>2021-01-12 22:46:05 -0800
commit4d8d69237d0a9e73e1723480e4225c9390533021 (patch)
tree633dc5903f4e8db2f9f601bff0205713df5d16a4
parent546a0e1edccaa7a53ae72c124f792783009b693b (diff)
2020 November 28 Breaking Changes Update (#11053)
* Branch point for 2020 November 28 Breaking Change * Remove matrix_col_t to allow MATRIX_ROWS > 32 (#10183) * Add support for soft serial to ATmega32U2 (#10204) * Change MIDI velocity implementation to allow direct control of velocity value (#9940) * Add ability to build a subset of all keyboards based on platform. * Actually use eeprom_driver_init(). * Make bootloader_jump weak for ChibiOS. (#10417) * Joystick 16-bit support (#10439) * Per-encoder resolutions (#10259) * Share button state from mousekey to pointing_device (#10179) * Add hotfix for chibios keyboards not wake (#10088) * Add advanced/efficient RGB Matrix Indicators (#8564) * Naming change. * Support for STM32 GPIOF,G,H,I,J,K (#10206) * Add milc as a dependency and remove the installed milc (#10563) * ChibiOS upgrade: early init conversions (#10214) * ChibiOS upgrade: configuration file migrator (#9952) * Haptic and solenoid cleanup (#9700) * XD75 cleanup (#10524) * OLED display update interval support (#10388) * Add definition based on currently-selected serial driver. (#10716) * New feature: Retro Tapping per key (#10622) * Allow for modification of output RGB values when using rgblight/rgb_matrix. (#10638) * Add housekeeping task callbacks so that keyboards/keymaps are capable of executing code for each main loop iteration. (#10530) * Rescale both ChibiOS and AVR backlighting. * Reduce Helix keyboard build variation (#8669) * Minor change to behavior allowing display updates to continue between task ticks (#10750) * Some GPIO manipulations in matrix.c change to atomic. (#10491) * qmk cformat (#10767) * [Keyboard] Update the Speedo firmware for v3.0 (#10657) * Maartenwut/Maarten namechange to evyd13/Evy (#10274) * [quantum] combine repeated lines of code (#10837) * Add step sequencer feature (#9703) * aeboards/ext65 refactor (#10820) * Refactor xelus/dawn60 for Rev2 later (#10584) * add DEBUG_MATRIX_SCAN_RATE_ENABLE to common_features.mk (#10824) * [Core] Added `add_oneshot_mods` & `del_oneshot_mods` (#10549) * update chibios os usb for the otg driver (#8893) * Remove HD44780 References, Part 4 (#10735) * [Keyboard] Add Valor FRL TKL (+refactor) (#10512) * Fix cursor position bug in oled_write_raw functions (#10800) * Fixup version.h writing when using SKIP_VERSION=yes (#10972) * Allow for certain code in the codebase assuming length of string. (#10974) * Add AT90USB support for serial.c (#10706) * Auto shift: support repeats and early registration (#9826) * Rename ledmatrix.h to match .c file (#7949) * Split RGB_MATRIX_ENABLE into _ENABLE and _DRIVER (#10231) * Split LED_MATRIX_ENABLE into _ENABLE and _DRIVER (#10840) * Merge point for 2020 Nov 28 Breaking Change
-rw-r--r--Makefile24
-rw-r--r--build_keyboard.mk13
-rw-r--r--build_test.mk1
-rw-r--r--common.mk1
-rw-r--r--common_features.mk122
-rw-r--r--drivers/avr/serial.c139
-rw-r--r--drivers/chibios/i2c_master.c21
-rw-r--r--drivers/chibios/spi_master.c27
-rw-r--r--drivers/eeprom/eeprom_i2c.c12
-rw-r--r--drivers/eeprom/eeprom_spi.c14
-rw-r--r--drivers/haptic/haptic.c53
-rw-r--r--drivers/haptic/solenoid.c10
-rw-r--r--drivers/haptic/solenoid.h18
-rw-r--r--drivers/oled/oled_driver.c22
-rw-r--r--keyboards/ergodox_ez/rules.mk3
-rw-r--r--keyboards/moonlander/rules.mk3
-rw-r--r--keyboards/planck/ez/glow/rules.mk2
-rw-r--r--keyboards/planck/ez/rules.mk1
-rw-r--r--keyboards/planck/planck.h23
-rw-r--r--lib/python/qmk/cli/__init__.py1
-rw-r--r--lib/python/qmk/cli/chibios/__init__.py1
-rw-r--r--lib/python/qmk/cli/chibios/confmigrate.py161
-rwxr-xr-xlib/python/qmk/cli/doctor.py2
-rw-r--r--lib/python/qmk/questions.py183
-rw-r--r--message.mk3
-rw-r--r--platforms/chibios/BLACKPILL_STM32_F401/configs/config.h4
-rw-r--r--platforms/chibios/BLACKPILL_STM32_F411/configs/config.h4
-rw-r--r--platforms/chibios/GENERIC_STM32_F042X6/configs/mcuconf.h168
-rw-r--r--platforms/chibios/GENERIC_STM32_F072XB/board/board.c250
-rw-r--r--platforms/chibios/GENERIC_STM32_F072XB/board/board.h407
-rw-r--r--platforms/chibios/GENERIC_STM32_F072XB/board/board.mk4
-rw-r--r--platforms/chibios/GENERIC_STM32_F072XB/configs/board.h20
-rw-r--r--platforms/chibios/GENERIC_STM32_F072XB/configs/mcuconf.h177
-rw-r--r--platforms/chibios/GENERIC_STM32_F303XC/configs/config.h4
-rw-r--r--platforms/chibios/STM32_F103_STM32DUINO/configs/mcuconf.h209
-rw-r--r--platforms/chibios/common/configs/chconf.h (renamed from platforms/chibios/GENERIC_STM32_F303XC/configs/chconf.h)0
-rw-r--r--platforms/chibios/common/configs/halconf.h (renamed from platforms/chibios/GENERIC_STM32_F303XC/configs/halconf.h)0
-rw-r--r--platforms/chibios/common/ld/MKL26Z64.ld (renamed from platforms/chibios/ld/MKL26Z64.ld)0
-rw-r--r--platforms/chibios/common/ld/STM32F103x8_stm32duino_bootloader.ld (renamed from platforms/chibios/ld/STM32F103x8_stm32duino_bootloader.ld)0
-rw-r--r--quantum/backlight/backlight_avr.c12
-rw-r--r--quantum/backlight/backlight_chibios.c14
-rw-r--r--quantum/config_common.h92
-rw-r--r--quantum/encoder.c24
-rw-r--r--quantum/joystick.h12
-rw-r--r--quantum/led_matrix.c2
-rw-r--r--quantum/led_matrix.h (renamed from quantum/ledmatrix.h)0
-rw-r--r--quantum/led_matrix_drivers.c2
-rw-r--r--quantum/matrix.c35
-rw-r--r--quantum/mcu_selection.mk3
-rw-r--r--quantum/process_keycode/process_auto_shift.c213
-rw-r--r--quantum/process_keycode/process_auto_shift.h11
-rw-r--r--quantum/process_keycode/process_joystick.c8
-rw-r--r--quantum/process_keycode/process_midi.c25
-rw-r--r--quantum/process_keycode/process_midi.h2
-rw-r--r--quantum/process_keycode/process_sequencer.c62
-rw-r--r--quantum/process_keycode/process_sequencer.h21
-rw-r--r--quantum/quantum.c15
-rw-r--r--quantum/quantum.h62
-rw-r--r--quantum/quantum_keycodes.h38
-rw-r--r--quantum/rgb_matrix.c32
-rw-r--r--quantum/rgb_matrix.h9
-rw-r--r--quantum/rgb_matrix_animations/alpha_mods_anim.h4
-rw-r--r--quantum/rgb_matrix_animations/breathing_anim.h2
-rw-r--r--quantum/rgb_matrix_animations/gradient_left_right_anim.h2
-rw-r--r--quantum/rgb_matrix_animations/gradient_up_down_anim.h2
-rw-r--r--quantum/rgb_matrix_animations/jellybean_raindrops_anim.h2
-rw-r--r--quantum/rgb_matrix_animations/raindrops_anim.h2
-rw-r--r--quantum/rgb_matrix_animations/solid_color_anim.h2
-rw-r--r--quantum/rgb_matrix_animations/typing_heatmap_anim.h2
-rw-r--r--quantum/rgb_matrix_runners/effect_runner_dx_dy.h2
-rw-r--r--quantum/rgb_matrix_runners/effect_runner_dx_dy_dist.h2
-rw-r--r--quantum/rgb_matrix_runners/effect_runner_i.h2
-rw-r--r--quantum/rgb_matrix_runners/effect_runner_reactive.h2
-rw-r--r--quantum/rgb_matrix_runners/effect_runner_reactive_splash.h2
-rw-r--r--quantum/rgb_matrix_runners/effect_runner_sin_cos_i.h2
-rw-r--r--quantum/rgblight.c4
-rw-r--r--quantum/sequencer/sequencer.c275
-rw-r--r--quantum/sequencer/sequencer.h122
-rw-r--r--quantum/sequencer/tests/midi_mock.c26
-rw-r--r--quantum/sequencer/tests/midi_mock.h26
-rw-r--r--quantum/sequencer/tests/rules.mk11
-rw-r--r--quantum/sequencer/tests/sequencer_tests.cpp590
-rw-r--r--quantum/sequencer/tests/testlist.mk1
-rw-r--r--quantum/split_common/matrix.c35
-rw-r--r--requirements.txt2
-rw-r--r--show_options.mk1
-rw-r--r--testlist.mk1
-rw-r--r--tmk_core/chibios.mk10
-rw-r--r--tmk_core/common/action.c66
-rw-r--r--tmk_core/common/action_util.c31
-rw-r--r--tmk_core/common/action_util.h7
-rw-r--r--tmk_core/common/arm_atsam/suspend.c2
-rw-r--r--tmk_core/common/chibios/bootloader.c10
-rw-r--r--tmk_core/common/eeconfig.c15
-rw-r--r--tmk_core/common/keyboard.c21
-rw-r--r--tmk_core/common/keyboard.h3
-rw-r--r--tmk_core/common/matrix.h10
-rw-r--r--tmk_core/common/report.h4
-rw-r--r--tmk_core/protocol/arm_atsam.mk6
-rw-r--r--tmk_core/protocol/arm_atsam/arm_atsam_protocol.h2
-rw-r--r--tmk_core/protocol/arm_atsam/main_arm_atsam.c4
-rw-r--r--tmk_core/protocol/arm_atsam/md_rgb_matrix.c (renamed from tmk_core/protocol/arm_atsam/led_matrix.c)12
-rw-r--r--tmk_core/protocol/arm_atsam/md_rgb_matrix.h (renamed from tmk_core/protocol/arm_atsam/led_matrix.h)2
-rw-r--r--tmk_core/protocol/arm_atsam/md_rgb_matrix_programs.c (renamed from tmk_core/protocol/arm_atsam/led_matrix_programs.c)2
-rw-r--r--tmk_core/protocol/chibios/main.c10
-rw-r--r--tmk_core/protocol/chibios/usb_main.c81
-rw-r--r--tmk_core/protocol/chibios/usb_main.h3
-rw-r--r--tmk_core/protocol/lufa/lufa.c4
-rw-r--r--tmk_core/protocol/usb_descriptor.c15
-rw-r--r--tmk_core/protocol/usb_descriptor.h20
-rw-r--r--tmk_core/protocol/vusb/main.c4
111 files changed, 3034 insertions, 1235 deletions
diff --git a/Makefile b/Makefile
index 8f68a1ce74..5d4ba58c01 100644
--- a/Makefile
+++ b/Makefile
@@ -272,10 +272,23 @@ endef
define PARSE_RULE
RULE := $1
COMMANDS :=
+ REQUIRE_PLATFORM_KEY :=
# If the rule starts with all, then continue the parsing from
# PARSE_ALL_KEYBOARDS
ifeq ($$(call COMPARE_AND_REMOVE_FROM_RULE,all),true)
$$(eval $$(call PARSE_ALL_KEYBOARDS))
+ else ifeq ($$(call COMPARE_AND_REMOVE_FROM_RULE,all-avr),true)
+ KEYBOARD_RULE=all
+ REQUIRE_PLATFORM_KEY := avr
+ $$(eval $$(call PARSE_ALL_KEYBOARDS))
+ else ifeq ($$(call COMPARE_AND_REMOVE_FROM_RULE,all-chibios),true)
+ KEYBOARD_RULE=all
+ REQUIRE_PLATFORM_KEY := chibios
+ $$(eval $$(call PARSE_ALL_KEYBOARDS))
+ else ifeq ($$(call COMPARE_AND_REMOVE_FROM_RULE,all-arm_atsam),true)
+ KEYBOARD_RULE=all
+ REQUIRE_PLATFORM_KEY := arm_atsam
+ $$(eval $$(call PARSE_ALL_KEYBOARDS))
else ifeq ($$(call COMPARE_AND_REMOVE_FROM_RULE,test),true)
$$(eval $$(call PARSE_TEST))
# If the rule starts with the name of a known keyboard, then continue
@@ -442,7 +455,7 @@ define PARSE_KEYMAP
# Format it in bold
KB_SP := $(BOLD)$$(KB_SP)$(NO_COLOR)
# Specify the variables that we are passing forward to submake
- MAKE_VARS := KEYBOARD=$$(CURRENT_KB) KEYMAP=$$(CURRENT_KM)
+ MAKE_VARS := KEYBOARD=$$(CURRENT_KB) KEYMAP=$$(CURRENT_KM) REQUIRE_PLATFORM_KEY=$$(REQUIRE_PLATFORM_KEY)
# And the first part of the make command
MAKE_CMD := $$(MAKE) -r -R -C $(ROOT_DIR) -f build_keyboard.mk $$(MAKE_TARGET)
# The message to display
@@ -461,6 +474,8 @@ define BUILD
LOG=$$$$($$(MAKE_CMD) $$(MAKE_VARS) SILENT=true 2>&1) ; \
if [ $$$$? -gt 0 ]; \
then $$(PRINT_ERROR_PLAIN); \
+ elif [ "$$$$LOG" = "skipped" ] ; \
+ then $$(PRINT_SKIPPED_PLAIN); \
elif [ "$$$$LOG" != "" ] ; \
then $$(PRINT_WARNING_PLAIN); \
else \
@@ -632,12 +647,13 @@ else
endif
ifndef SKIP_VERSION
BUILD_DATE := $(shell date +"%Y-%m-%d-%H:%M:%S")
+else
+BUILD_DATE := 2020-01-01-00:00:00
+endif
+
$(shell echo '#define QMK_VERSION "$(GIT_VERSION)"' > $(ROOT_DIR)/quantum/version.h)
$(shell echo '#define QMK_BUILDDATE "$(BUILD_DATE)"' >> $(ROOT_DIR)/quantum/version.h)
$(shell echo '#define CHIBIOS_VERSION "$(CHIBIOS_VERSION)"' >> $(ROOT_DIR)/quantum/version.h)
$(shell echo '#define CHIBIOS_CONTRIB_VERSION "$(CHIBIOS_CONTRIB_VERSION)"' >> $(ROOT_DIR)/quantum/version.h)
-else
-BUILD_DATE := NA
-endif
include $(ROOT_DIR)/testlist.mk
diff --git a/build_keyboard.mk b/build_keyboard.mk
index 1d80d89824..7bcfb51ed5 100644
--- a/build_keyboard.mk
+++ b/build_keyboard.mk
@@ -317,6 +317,13 @@ SRC += $(TMK_COMMON_SRC)
OPT_DEFS += $(TMK_COMMON_DEFS)
EXTRALDFLAGS += $(TMK_COMMON_LDFLAGS)
+SKIP_COMPILE := no
+ifneq ($(REQUIRE_PLATFORM_KEY),)
+ ifneq ($(REQUIRE_PLATFORM_KEY),$(PLATFORM_KEY))
+ SKIP_COMPILE := yes
+ endif
+endif
+
include $(TMK_PATH)/$(PLATFORM_KEY).mk
ifneq ($(strip $(PROTOCOL)),)
include $(TMK_PATH)/protocol/$(strip $(shell echo $(PROTOCOL) | tr '[:upper:]' '[:lower:]')).mk
@@ -352,7 +359,13 @@ $(KEYBOARD_OUTPUT)_INC := $(PROJECT_INC) $(GFXINC)
$(KEYBOARD_OUTPUT)_CONFIG := $(PROJECT_CONFIG)
# Default target.
+ifeq ($(SKIP_COMPILE),no)
all: build check-size
+else
+all:
+ echo "skipped" >&2
+endif
+
build: elf cpfirmware
check-size: build
objs-size: build
diff --git a/build_test.mk b/build_test.mk
index d13d9a515b..e705c6a3ba 100644
--- a/build_test.mk
+++ b/build_test.mk
@@ -49,6 +49,7 @@ endif
include common_features.mk
include $(TMK_PATH)/common.mk
+include $(QUANTUM_PATH)/sequencer/tests/rules.mk
include $(QUANTUM_PATH)/serial_link/tests/rules.mk
ifneq ($(filter $(FULL_TESTS),$(TEST)),)
include build_full_test.mk
diff --git a/common.mk b/common.mk
index aea29a7a20..c13b5e2768 100644
--- a/common.mk
+++ b/common.mk
@@ -21,4 +21,5 @@ COMMON_VPATH += $(QUANTUM_PATH)/keymap_extras
COMMON_VPATH += $(QUANTUM_PATH)/audio
COMMON_VPATH += $(QUANTUM_PATH)/process_keycode
COMMON_VPATH += $(QUANTUM_PATH)/api
+COMMON_VPATH += $(QUANTUM_PATH)/sequencer
COMMON_VPATH += $(DRIVER_PATH)
diff --git a/common_features.mk b/common_features.mk
index f65b4cf81c..22cd53d8a3 100644
--- a/common_features.mk
+++ b/common_features.mk
@@ -21,6 +21,11 @@ QUANTUM_SRC += \
$(QUANTUM_DIR)/keymap_common.c \
$(QUANTUM_DIR)/keycode_config.c
+ifeq ($(strip $(DEBUG_MATRIX_SCAN_RATE_ENABLE)), yes)
+ OPT_DEFS += -DDEBUG_MATRIX_SCAN_RATE
+ CONSOLE_ENABLE = yes
+endif
+
ifeq ($(strip $(API_SYSEX_ENABLE)), yes)
OPT_DEFS += -DAPI_SYSEX_ENABLE
OPT_DEFS += -DAPI_ENABLE
@@ -39,6 +44,13 @@ ifeq ($(strip $(AUDIO_ENABLE)), yes)
SRC += $(QUANTUM_DIR)/audio/luts.c
endif
+ifeq ($(strip $(SEQUENCER_ENABLE)), yes)
+ OPT_DEFS += -DSEQUENCER_ENABLE
+ MUSIC_ENABLE = yes
+ SRC += $(QUANTUM_DIR)/sequencer/sequencer.c
+ SRC += $(QUANTUM_DIR)/process_keycode/process_sequencer.c
+endif
+
ifeq ($(strip $(MIDI_ENABLE)), yes)
OPT_DEFS += -DMIDI_ENABLE
MUSIC_ENABLE = yes
@@ -156,12 +168,14 @@ ifeq ($(strip $(RGBLIGHT_ENABLE)), yes)
endif
endif
-VALID_MATRIX_TYPES := yes IS31FL3731 IS31FL3733 IS31FL3737 IS31FL3741 WS2812 custom
LED_MATRIX_ENABLE ?= no
-ifneq ($(strip $(LED_MATRIX_ENABLE)), no)
- ifeq ($(filter $(LED_MATRIX_ENABLE),$(VALID_MATRIX_TYPES)),)
- $(error LED_MATRIX_ENABLE="$(LED_MATRIX_ENABLE)" is not a valid matrix type)
+VALID_LED_MATRIX_TYPES := IS31FL3731 custom
+# TODO: IS31FL3733 IS31FL3737 IS31FL3741
+
+ifeq ($(strip $(LED_MATRIX_ENABLE)), yes)
+ ifeq ($(filter $(LED_MATRIX_DRIVER),$(VALID_LED_MATRIX_TYPES)),)
+ $(error LED_MATRIX_DRIVER="$(LED_MATRIX_DRIVER)" is not a valid matrix type)
else
BACKLIGHT_ENABLE = yes
BACKLIGHT_DRIVER = custom
@@ -169,21 +183,22 @@ ifneq ($(strip $(LED_MATRIX_ENABLE)), no)
SRC += $(QUANTUM_DIR)/led_matrix.c
SRC += $(QUANTUM_DIR)/led_matrix_drivers.c
endif
-endif
-ifeq ($(strip $(LED_MATRIX_ENABLE)), IS31FL3731)
- OPT_DEFS += -DIS31FL3731
- COMMON_VPATH += $(DRIVER_PATH)/issi
- SRC += is31fl3731-simple.c
- QUANTUM_LIB_SRC += i2c_master.c
+ ifeq ($(strip $(LED_MATRIX_DRIVER)), IS31FL3731)
+ OPT_DEFS += -DIS31FL3731 -DSTM32_I2C -DHAL_USE_I2C=TRUE
+ COMMON_VPATH += $(DRIVER_PATH)/issi
+ SRC += is31fl3731-simple.c
+ QUANTUM_LIB_SRC += i2c_master.c
+ endif
endif
RGB_MATRIX_ENABLE ?= no
+VALID_RGB_MATRIX_TYPES := IS31FL3731 IS31FL3733 IS31FL3737 IS31FL3741 WS2812 custom
-ifneq ($(strip $(RGB_MATRIX_ENABLE)), no)
-ifeq ($(filter $(RGB_MATRIX_ENABLE),$(VALID_MATRIX_TYPES)),)
- $(error RGB_MATRIX_ENABLE="$(RGB_MATRIX_ENABLE)" is not a valid matrix type)
-endif
+ifeq ($(strip $(RGB_MATRIX_ENABLE)), yes)
+ ifeq ($(filter $(RGB_MATRIX_DRIVER),$(VALID_RGB_MATRIX_TYPES)),)
+ $(error "$(RGB_MATRIX_DRIVER)" is not a valid matrix type)
+ endif
OPT_DEFS += -DRGB_MATRIX_ENABLE
ifneq (,$(filter $(MCU), atmega16u2 atmega32u2))
# ATmegaxxU2 does not have hardware MUL instruction - lib8tion must be told to use software multiplication routines
@@ -194,51 +209,47 @@ endif
SRC += $(QUANTUM_DIR)/rgb_matrix_drivers.c
CIE1931_CURVE := yes
RGB_KEYCODES_ENABLE := yes
-endif
-
-ifeq ($(strip $(RGB_MATRIX_ENABLE)), yes)
- RGB_MATRIX_ENABLE := IS31FL3731
-endif
-ifeq ($(strip $(RGB_MATRIX_ENABLE)), IS31FL3731)
- OPT_DEFS += -DIS31FL3731 -DSTM32_I2C -DHAL_USE_I2C=TRUE
- COMMON_VPATH += $(DRIVER_PATH)/issi
- SRC += is31fl3731.c
- QUANTUM_LIB_SRC += i2c_master.c
-endif
+ ifeq ($(strip $(RGB_MATRIX_DRIVER)), IS31FL3731)
+ OPT_DEFS += -DIS31FL3731 -DSTM32_I2C -DHAL_USE_I2C=TRUE
+ COMMON_VPATH += $(DRIVER_PATH)/issi
+ SRC += is31fl3731.c
+ QUANTUM_LIB_SRC += i2c_master.c
+ endif
-ifeq ($(strip $(RGB_MATRIX_ENABLE)), IS31FL3733)
- OPT_DEFS += -DIS31FL3733 -DSTM32_I2C -DHAL_USE_I2C=TRUE
- COMMON_VPATH += $(DRIVER_PATH)/issi
- SRC += is31fl3733.c
- QUANTUM_LIB_SRC += i2c_master.c
-endif
+ ifeq ($(strip $(RGB_MATRIX_DRIVER)), IS31FL3733)
+ OPT_DEFS += -DIS31FL3733 -DSTM32_I2C -DHAL_USE_I2C=TRUE
+ COMMON_VPATH += $(DRIVER_PATH)/issi
+ SRC += is31fl3733.c
+ QUANTUM_LIB_SRC += i2c_master.c
+ endif
-ifeq ($(strip $(RGB_MATRIX_ENABLE)), IS31FL3737)
- OPT_DEFS += -DIS31FL3737 -DSTM32_I2C -DHAL_USE_I2C=TRUE
- COMMON_VPATH += $(DRIVER_PATH)/issi
- SRC += is31fl3737.c
- QUANTUM_LIB_SRC += i2c_master.c
-endif
+ ifeq ($(strip $(RGB_MATRIX_DRIVER)), IS31FL3737)
+ OPT_DEFS += -DIS31FL3737 -DSTM32_I2C -DHAL_USE_I2C=TRUE
+ COMMON_VPATH += $(DRIVER_PATH)/issi
+ SRC += is31fl3737.c
+ QUANTUM_LIB_SRC += i2c_master.c
+ endif
-ifeq ($(strip $(RGB_MATRIX_ENABLE)), IS31FL3741)
- OPT_DEFS += -DIS31FL3741 -DSTM32_I2C -DHAL_USE_I2C=TRUE
- COMMON_VPATH += $(DRIVER_PATH)/issi
- SRC += is31fl3741.c
- QUANTUM_LIB_SRC += i2c_master.c
-endif
+ ifeq ($(strip $(RGB_MATRIX_DRIVER)), IS31FL3741)
+ OPT_DEFS += -DIS31FL3741 -DSTM32_I2C -DHAL_USE_I2C=TRUE
+ COMMON_VPATH += $(DRIVER_PATH)/issi
+ SRC += is31fl3741.c
+ QUANTUM_LIB_SRC += i2c_master.c
+ endif
-ifeq ($(strip $(RGB_MATRIX_ENABLE)), WS2812)
- OPT_DEFS += -DWS2812
- WS2812_DRIVER_REQUIRED := yes
-endif
+ ifeq ($(strip $(RGB_MATRIX_DRIVER)), WS2812)
+ OPT_DEFS += -DWS2812
+ WS2812_DRIVER_REQUIRED := yes
+ endif
-ifeq ($(strip $(RGB_MATRIX_CUSTOM_KB)), yes)
- OPT_DEFS += -DRGB_MATRIX_CUSTOM_KB
-endif
+ ifeq ($(strip $(RGB_MATRIX_CUSTOM_KB)), yes)
+ OPT_DEFS += -DRGB_MATRIX_CUSTOM_KB
+ endif
-ifeq ($(strip $(RGB_MATRIX_CUSTOM_USER)), yes)
- OPT_DEFS += -DRGB_MATRIX_CUSTOM_USER
+ ifeq ($(strip $(RGB_MATRIX_CUSTOM_USER)), yes)
+ OPT_DEFS += -DRGB_MATRIX_CUSTOM_USER
+ endif
endif
ifeq ($(strip $(RGB_KEYCODES_ENABLE)), yes)
@@ -453,11 +464,14 @@ ifeq ($(strip $(SPLIT_KEYBOARD)), yes)
# Functions added via QUANTUM_LIB_SRC are only included in the final binary if they're called.
# Unused functions are pruned away, which is why we can add multiple drivers here without bloat.
ifeq ($(PLATFORM),AVR)
- QUANTUM_LIB_SRC += i2c_master.c \
- i2c_slave.c
+ ifneq ($(NO_I2C),yes)
+ QUANTUM_LIB_SRC += i2c_master.c \
+ i2c_slave.c
+ endif
endif
SERIAL_DRIVER ?= bitbang
+ OPT_DEFS += -DSERIAL_DRIVER_$(strip $(shell echo $(SERIAL_DRIVER) | tr '[:lower:]' '[:upper:]'))
ifeq ($(strip $(SERIAL_DRIVER)), bitbang)
QUANTUM_LIB_SRC += serial.c
else
diff --git a/drivers/avr/serial.c b/drivers/avr/serial.c
index c4ef2a97e7..d161b249cc 100644
--- a/drivers/avr/serial.c
+++ b/drivers/avr/serial.c
@@ -21,50 +21,111 @@
#ifdef SOFT_SERIAL_PIN
-# ifdef __AVR_ATmega32U4__
-// if using ATmega32U4 I2C, can not use PD0 and PD1 in soft serial.
-# ifdef USE_AVR_I2C
-# if SOFT_SERIAL_PIN == D0 || SOFT_SERIAL_PIN == D1
-# error Using ATmega32U4 I2C, so can not use PD0, PD1
-# endif
+# if !(defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__))
+# error serial.c is not supported for the currently selected MCU
+# endif
+// if using ATmega32U4/2, AT90USBxxx I2C, can not use PD0 and PD1 in soft serial.
+# if defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
+# if defined(USE_AVR_I2C) && (SOFT_SERIAL_PIN == D0 || SOFT_SERIAL_PIN == D1)
+# error Using I2C, so can not use PD0, PD1
# endif
+# endif
+// PD0..PD3, common config
+# if SOFT_SERIAL_PIN == D0
+# define EIMSK_BIT _BV(INT0)
+# define EICRx_BIT (~(_BV(ISC00) | _BV(ISC01)))
+# define SERIAL_PIN_INTERRUPT INT0_vect
+# define EICRx EICRA
+# elif SOFT_SERIAL_PIN == D1
+# define EIMSK_BIT _BV(INT1)
+# define EICRx_BIT (~(_BV(ISC10) | _BV(ISC11)))
+# define SERIAL_PIN_INTERRUPT INT1_vect
+# define EICRx EICRA
+# elif SOFT_SERIAL_PIN == D2
+# define EIMSK_BIT _BV(INT2)
+# define EICRx_BIT (~(_BV(ISC20) | _BV(ISC21)))
+# define SERIAL_PIN_INTERRUPT INT2_vect
+# define EICRx EICRA
+# elif SOFT_SERIAL_PIN == D3
+# define EIMSK_BIT _BV(INT3)
+# define EICRx_BIT (~(_BV(ISC30) | _BV(ISC31)))
+# define SERIAL_PIN_INTERRUPT INT3_vect
+# define EICRx EICRA
+# endif
-# define setPinInputHigh(pin) (DDRx_ADDRESS(pin) &= ~_BV((pin)&0xF), PORTx_ADDRESS(pin) |= _BV((pin)&0xF))
-# define setPinOutput(pin) (DDRx_ADDRESS(pin) |= _BV((pin)&0xF))
-# define writePinHigh(pin) (PORTx_ADDRESS(pin) |= _BV((pin)&0xF))
-# define writePinLow(pin) (PORTx_ADDRESS(pin) &= ~_BV((pin)&0xF))
-# define readPin(pin) ((bool)(PINx_ADDRESS(pin) & _BV((pin)&0xF)))
-
-# if SOFT_SERIAL_PIN >= D0 && SOFT_SERIAL_PIN <= D3
-# if SOFT_SERIAL_PIN == D0
-# define EIMSK_BIT _BV(INT0)
-# define EICRx_BIT (~(_BV(ISC00) | _BV(ISC01)))
-# define SERIAL_PIN_INTERRUPT INT0_vect
-# elif SOFT_SERIAL_PIN == D1
-# define EIMSK_BIT _BV(INT1)
-# define EICRx_BIT (~(_BV(ISC10) | _BV(ISC11)))
-# define SERIAL_PIN_INTERRUPT INT1_vect
-# elif SOFT_SERIAL_PIN == D2
-# define EIMSK_BIT _BV(INT2)
-# define EICRx_BIT (~(_BV(ISC20) | _BV(ISC21)))
-# define SERIAL_PIN_INTERRUPT INT2_vect
-# elif SOFT_SERIAL_PIN == D3
-# define EIMSK_BIT _BV(INT3)
-# define EICRx_BIT (~(_BV(ISC30) | _BV(ISC31)))
-# define SERIAL_PIN_INTERRUPT INT3_vect
-# endif
+// ATmegaxxU2 specific config
+# if defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__)
+// PD4(INT5), PD6(INT6), PD7(INT7), PC7(INT4)
+# if SOFT_SERIAL_PIN == D4
+# define EIMSK_BIT _BV(INT5)
+# define EICRx_BIT (~(_BV(ISC50) | _BV(ISC51)))
+# define SERIAL_PIN_INTERRUPT INT5_vect
+# define EICRx EICRB
+# elif SOFT_SERIAL_PIN == D6
+# define EIMSK_BIT _BV(INT6)
+# define EICRx_BIT (~(_BV(ISC60) | _BV(ISC61)))
+# define SERIAL_PIN_INTERRUPT INT6_vect
+# define EICRx EICRB
+# elif SOFT_SERIAL_PIN == D7
+# define EIMSK_BIT _BV(INT7)
+# define EICRx_BIT (~(_BV(ISC70) | _BV(ISC71)))
+# define SERIAL_PIN_INTERRUPT INT7_vect
+# define EICRx EICRB
+# elif SOFT_SERIAL_PIN == C7
+# define EIMSK_BIT _BV(INT4)
+# define EICRx_BIT (~(_BV(ISC40) | _BV(ISC41)))
+# define SERIAL_PIN_INTERRUPT INT4_vect
+# define EICRx EICRB
+# endif
+# endif
+
+// ATmegaxxU4 specific config
+# if defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)
+// PE6(INT6)
+# if SOFT_SERIAL_PIN == E6
+# define EIMSK_BIT _BV(INT6)
+# define EICRx_BIT (~(_BV(ISC60) | _BV(ISC61)))
+# define SERIAL_PIN_INTERRUPT INT6_vect
+# define EICRx EICRB
+# endif
+# endif
+
+// AT90USBxxx specific config
+# if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
+// PE4..PE7(INT4..INT7)
+# if SOFT_SERIAL_PIN == E4
+# define EIMSK_BIT _BV(INT4)
+# define EICRx_BIT (~(_BV(ISC40) | _BV(ISC41)))
+# define SERIAL_PIN_INTERRUPT INT4_vect
+# define EICRx EICRB
+# elif SOFT_SERIAL_PIN == E5
+# define EIMSK_BIT _BV(INT5)
+# define EICRx_BIT (~(_BV(ISC50) | _BV(ISC51)))
+# define SERIAL_PIN_INTERRUPT INT5_vect
+# define EICRx EICRB
# elif SOFT_SERIAL_PIN == E6
# define EIMSK_BIT _BV(INT6)
# define EICRx_BIT (~(_BV(ISC60) | _BV(ISC61)))
# define SERIAL_PIN_INTERRUPT INT6_vect
-# else
-# error invalid SOFT_SERIAL_PIN value
+# define EICRx EICRB
+# elif SOFT_SERIAL_PIN == E7
+# define EIMSK_BIT _BV(INT7)
+# define EICRx_BIT (~(_BV(ISC70) | _BV(ISC71)))
+# define SERIAL_PIN_INTERRUPT INT7_vect
+# define EICRx EICRB
# endif
+# endif
-# else
-# error serial.c now support ATmega32U4 only
+# ifndef SERIAL_PIN_INTERRUPT
+# error invalid SOFT_SERIAL_PIN value
# endif
+# define setPinInputHigh(pin) (DDRx_ADDRESS(pin) &= ~_BV((pin)&0xF), PORTx_ADDRESS(pin) |= _BV((pin)&0xF))
+# define setPinOutput(pin) (DDRx_ADDRESS(pin) |= _BV((pin)&0xF))
+# define writePinHigh(pin) (PORTx_ADDRESS(pin) |= _BV((pin)&0xF))
+# define writePinLow(pin) (PORTx_ADDRESS(pin) &= ~_BV((pin)&0xF))
+# define readPin(pin) ((bool)(PINx_ADDRESS(pin) & _BV((pin)&0xF)))
+
# define ALWAYS_INLINE __attribute__((always_inline))
# define NO_INLINE __attribute__((noinline))
# define _delay_sub_us(x) __builtin_avr_delay_cycles(x)
@@ -211,15 +272,9 @@ void soft_serial_target_init(SSTD_t *sstd_table, int sstd_table_size) {
Transaction_table_size = (uint8_t)sstd_table_size;
serial_input_with_pullup();
- // Enable INT0-INT3,INT6
+ // Enable INT0-INT7
EIMSK |= EIMSK_BIT;
-# if SOFT_SERIAL_PIN == E6
- // Trigger on falling edge of INT6
- EICRB &= EICRx_BIT;
-# else
- // Trigger on falling edge of INT0-INT3
- EICRA &= EICRx_BIT;
-# endif
+ EICRx &= EICRx_BIT;
}
// Used by the sender to synchronize timing with the reciver.
diff --git a/drivers/chibios/i2c_master.c b/drivers/chibios/i2c_master.c
index 4bd8e2af76..fc4bb2ab37 100644
--- a/drivers/chibios/i2c_master.c
+++ b/drivers/chibios/i2c_master.c
@@ -58,18 +58,23 @@ static i2c_status_t chibios_to_qmk(const msg_t* status) {
}
__attribute__((weak)) void i2c_init(void) {
- // Try releasing special pins for a short time
- palSetPadMode(I2C1_SCL_BANK, I2C1_SCL, PAL_MODE_INPUT);
- palSetPadMode(I2C1_SDA_BANK, I2C1_SDA, PAL_MODE_INPUT);
+ static bool is_initialised = false;
+ if (!is_initialised) {
+ is_initialised = true;
- chThdSleepMilliseconds(10);
+ // Try releasing special pins for a short time
+ palSetPadMode(I2C1_SCL_BANK, I2C1_SCL, PAL_MODE_INPUT);
+ palSetPadMode(I2C1_SDA_BANK, I2C1_SDA, PAL_MODE_INPUT);
+
+ chThdSleepMilliseconds(10);
#if defined(USE_GPIOV1)
- palSetPadMode(I2C1_SCL_BANK, I2C1_SCL, I2C1_SCL_PAL_MODE);
- palSetPadMode(I2C1_SDA_BANK, I2C1_SDA, I2C1_SDA_PAL_MODE);
+ palSetPadMode(I2C1_SCL_BANK, I2C1_SCL, I2C1_SCL_PAL_MODE);
+ palSetPadMode(I2C1_SDA_BANK, I2C1_SDA, I2C1_SDA_PAL_MODE);
#else
- palSetPadMode(I2C1_SCL_BANK, I2C1_SCL, PAL_MODE_ALTERNATE(I2C1_SCL_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN);
- palSetPadMode(I2C1_SDA_BANK, I2C1_SDA, PAL_MODE_ALTERNATE(I2C1_SDA_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN);
+ palSetPadMode(I2C1_SCL_BANK, I2C1_SCL, PAL_MODE_ALTERNATE(I2C1_SCL_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN);
+ palSetPadMode(I2C1_SDA_BANK, I2C1_SDA, PAL_MODE_ALTERNATE(I2C1_SDA_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN);
#endif
+ }
}
i2c_status_t i2c_start(uint8_t address) {
diff --git a/drivers/chibios/spi_master.c b/drivers/chibios/spi_master.c
index 552ac663c1..5aa60742e3 100644
--- a/drivers/chibios/spi_master.c
+++ b/drivers/chibios/spi_master.c
@@ -22,21 +22,26 @@ static pin_t currentSlavePin = NO_PIN;
static SPIConfig spiConfig = {false, NULL, 0, 0, 0, 0};
__attribute__((weak)) void spi_init(void) {
- // Try releasing special pins for a short time
- palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), PAL_MODE_INPUT);
- palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), PAL_MODE_INPUT);
- palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), PAL_MODE_INPUT);
+ static bool is_initialised = false;
+ if (!is_initialised) {
+ is_initialised = true;
- chThdSleepMilliseconds(10);
+ // Try releasing special pins for a short time
+ palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), PAL_MODE_INPUT);
+ palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), PAL_MODE_INPUT);
+ palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), PAL_MODE_INPUT);
+
+ chThdSleepMilliseconds(10);
#if defined(USE_GPIOV1)
- palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), PAL_MODE_STM32_ALTERNATE_PUSHPULL);
- palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), PAL_MODE_STM32_ALTERNATE_PUSHPULL);
- palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), PAL_MODE_STM32_ALTERNATE_PUSHPULL);
+ palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), PAL_MODE_STM32_ALTERNATE_PUSHPULL);
+ palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), PAL_MODE_STM32_ALTERNATE_PUSHPULL);
+ palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), PAL_MODE_STM32_ALTERNATE_PUSHPULL);
#else
- palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), PAL_MODE_ALTERNATE(SPI_SCK_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST);
- palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), PAL_MODE_ALTERNATE(SPI_MOSI_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST);
- palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), PAL_MODE_ALTERNATE(SPI_MISO_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST);
+ palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), PAL_MODE_ALTERNATE(SPI_SCK_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST);
+ palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), PAL_MODE_ALTERNATE(SPI_MOSI_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST);
+ palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), PAL_MODE_ALTERNATE(SPI_MISO_PAL_MODE) | PAL_STM32_OTYPE_PUSHPULL | PAL_STM32_OSPEED_HIGHEST);
#endif
+ }
}
bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
diff --git a/drivers/eeprom/eeprom_i2c.c b/drivers/eeprom/eeprom_i2c.c
index ca8af3da51..4210f06f9f 100644
--- a/drivers/eeprom/eeprom_i2c.c
+++ b/drivers/eeprom/eeprom_i2c.c
@@ -42,14 +42,6 @@
# include "debug.h"
#endif // DEBUG_EEPROM_OUTPUT
-static inline void init_i2c_if_required(void) {
- static int done = 0;
- if (!done) {
- i2c_init();
- done = 1;
- }
-}
-
static inline void fill_target_address(uint8_t *buffer, const void *addr) {
uintptr_t p = (uintptr_t)addr;
for (int i = 0; i < EXTERNAL_EEPROM_ADDRESS_SIZE; ++i) {
@@ -58,7 +50,7 @@ static inline void fill_target_address(uint8_t *buffer, const void *addr) {
}
}
-void eeprom_driver_init(void) {}
+void eeprom_driver_init(void) { i2c_init(); }
void eeprom_driver_erase(void) {
#if defined(CONSOLE_ENABLE) && defined(DEBUG_EEPROM_OUTPUT)
@@ -80,7 +72,6 @@ void eeprom_read_block(void *buf, const void *addr, size_t len) {
uint8_t complete_packet[EXTERNAL_EEPROM_ADDRESS_SIZE];
fill_target_address(complete_packet, addr);
- init_i2c_if_required();
i2c_transmit(EXTERNAL_EEPROM_I2C_ADDRESS((uintptr_t)addr), complete_packet, EXTERNAL_EEPROM_ADDRESS_SIZE, 100);
i2c_receive(EXTERNAL_EEPROM_I2C_ADDRESS((uintptr_t)addr), buf, len, 100);
@@ -98,7 +89,6 @@ void eeprom_write_block(const void *buf, void *addr, size_t len) {
uint8_t * read_buf = (uint8_t *)buf;
uintptr_t target_addr = (uintptr_t)addr;
- init_i2c_if_required();
while (len > 0) {
uintptr_t page_offset = target_addr % EXTERNAL_EEPROM_PAGE_SIZE;
int write_length = EXTERNAL_EEPROM_PAGE_SIZE - page_offset;
diff --git a/drivers/eeprom/eeprom_spi.c b/drivers/eeprom/eeprom_spi.c
index 7b6416eafb..182731d82f 100644
--- a/drivers/eeprom/eeprom_spi.c
+++ b/drivers/eeprom/eeprom_spi.c
@@ -55,14 +55,6 @@
# include "debug.h"
#endif // CONSOLE_ENABLE
-static void init_spi_if_required(void) {
- static int done = 0;
- if (!done) {
- spi_init();
- done = 1;
- }
-}
-
static bool spi_eeprom_start(void) { return spi_start(EXTERNAL_EEPROM_SPI_SLAVE_SELECT_PIN, EXTERNAL_EEPROM_SPI_LSBFIRST, EXTERNAL_EEPROM_SPI_MODE, EXTERNAL_EEPROM_SPI_CLOCK_DIVISOR); }
static spi_status_t spi_eeprom_wait_while_busy(int timeout) {
@@ -91,7 +83,7 @@ static void spi_eeprom_transmit_address(uintptr_t addr) {
//----------------------------------------------------------------------------------------------------------------------
-void eeprom_driver_init(void) {}
+void eeprom_driver_init(void) { spi_init(); }
void eeprom_driver_erase(void) {
#if defined(CONSOLE_ENABLE) && defined(DEBUG_EEPROM_OUTPUT)
@@ -110,8 +102,6 @@ void eeprom_driver_erase(void) {
}
void eeprom_read_block(void *buf, const void *addr, size_t len) {
- init_spi_if_required();
-
//-------------------------------------------------
// Wait for the write-in-progress bit to be cleared
bool res = spi_eeprom_start();
@@ -154,8 +144,6 @@ void eeprom_read_block(void *buf, const void *addr, size_t len) {
}
void eeprom_write_block(const void *buf, void *addr, size_t len) {
- init_spi_if_required();
-
bool res;
uint8_t * read_buf = (uint8_t *)buf;
uintptr_t target_addr = (uintptr_t)addr;
diff --git a/drivers/haptic/haptic.c b/drivers/haptic/haptic.c
index 989970beee..8fef1cb225 100644
--- a/drivers/haptic/haptic.c
+++ b/drivers/haptic/haptic.c
@@ -33,11 +33,18 @@ void haptic_init(void) {
eeconfig_init();
}
haptic_config.raw = eeconfig_read_haptic();
- if (haptic_config.mode < 1) {
- haptic_config.mode = 1;
- }
- if (!haptic_config.mode) {
- dprintf("No haptic config found in eeprom, setting default configs\n");
+#ifdef SOLENOID_ENABLE
+ solenoid_set_dwell(haptic_config.dwell);
+#endif
+ if ((haptic_config.raw == 0)
+#ifdef SOLENOID_ENABLE
+ || (haptic_config.dwell == 0)
+#endif
+ ) {
+ // this will be called, if the eeprom is not corrupt,
+ // but the previous firmware didn't have haptic enabled,
+ // or the previous firmware didn't have solenoid enabled,
+ // and the current one has solenoid enabled.
haptic_reset();
}
#ifdef SOLENOID_ENABLE
@@ -118,25 +125,37 @@ void haptic_mode_decrease(void) {
}
void haptic_dwell_increase(void) {
- uint8_t dwell = haptic_config.dwell + 1;
#ifdef SOLENOID_ENABLE
+ int16_t next_dwell = ((int16_t)haptic_config.dwell) + SOLENOID_DWELL_STEP_SIZE;
if (haptic_config.dwell >= SOLENOID_MAX_DWELL) {
- dwell = 1;
+ // if it's already at max, we wrap back to min
+ next_dwell = SOLENOID_MIN_DWELL;
+ } else if (next_dwell > SOLENOID_MAX_DWELL) {
+ // if we overshoot the max, then cap at max
+ next_dwell = SOLENOID_MAX_DWELL;
}
- solenoid_set_dwell(dwell);
+ solenoid_set_dwell(next_dwell);
+#else
+ int16_t next_dwell = ((int16_t)haptic_config.dwell) + 1;
#endif
- haptic_set_dwell(dwell);
+ haptic_set_dwell(next_dwell);
}
void haptic_dwell_decrease(void) {
- uint8_t dwell = haptic_config.dwell - 1;
#ifdef SOLENOID_ENABLE
- if (haptic_config.dwell < SOLENOID_MIN_DWELL) {
- dwell = SOLENOID_MAX_DWELL;
+ int16_t next_dwell = ((int16_t)haptic_config.dwell) - SOLENOID_DWELL_STEP_SIZE;
+ if (haptic_config.dwell <= SOLENOID_MIN_DWELL) {
+ // if it's already at min, we wrap to max
+ next_dwell = SOLENOID_MAX_DWELL;
+ } else if (next_dwell < SOLENOID_MIN_DWELL) {
+ // if we go below min, then we cap to min
+ next_dwell = SOLENOID_MIN_DWELL;
}
- solenoid_set_dwell(dwell);
+ solenoid_set_dwell(next_dwell);
+#else
+ int16_t next_dwell = ((int16_t)haptic_config.dwell) - 1;
#endif
- haptic_set_dwell(dwell);
+ haptic_set_dwell(next_dwell);
}
void haptic_reset(void) {
@@ -150,6 +169,12 @@ void haptic_reset(void) {
#ifdef SOLENOID_ENABLE
uint8_t dwell = SOLENOID_DEFAULT_DWELL;
haptic_config.dwell = dwell;
+ haptic_config.buzz = SOLENOID_DEFAULT_BUZZ;
+ solenoid_set_dwell(dwell);
+#else
+ // This is to trigger haptic_reset again, if solenoid is enabled in the future.
+ haptic_config.dwell = 0;
+ haptic_config.buzz = 0;
#endif
eeconfig_update_haptic(haptic_config.raw);
xprintf("haptic_config.feedback = %u\n", haptic_config.feedback);
diff --git a/drivers/haptic/solenoid.c b/drivers/haptic/solenoid.c
index d645c379ae..2975ef893a 100644
--- a/drivers/haptic/solenoid.c
+++ b/drivers/haptic/solenoid.c
@@ -32,14 +32,6 @@ void solenoid_buzz_off(void) { haptic_set_buzz(0); }
void solenoid_set_buzz(int buzz) { haptic_set_buzz(buzz); }
-void solenoid_dwell_minus(uint8_t solenoid_dwell) {
- if (solenoid_dwell > 0) solenoid_dwell--;
-}
-
-void solenoid_dwell_plus(uint8_t solenoid_dwell) {
- if (solenoid_dwell < SOLENOID_MAX_DWELL) solenoid_dwell++;
-}
-
void solenoid_set_dwell(uint8_t dwell) { solenoid_dwell = dwell; }
void solenoid_stop(void) {
@@ -73,7 +65,7 @@ void solenoid_check(void) {
// Check whether to buzz the solenoid on and off
if (haptic_config.buzz) {
- if (elapsed / SOLENOID_MIN_DWELL % 2 == 0) {
+ if ((elapsed % (SOLENOID_BUZZ_ACTUATED + SOLENOID_BUZZ_NONACTUATED)) < SOLENOID_BUZZ_ACTUATED) {
if (!solenoid_buzzing) {
solenoid_buzzing = true;
writePinHigh(SOLENOID_PIN);
diff --git a/drivers/haptic/solenoid.h b/drivers/haptic/solenoid.h
index dd6ececa68..f2a3bc4c30 100644
--- a/drivers/haptic/solenoid.h
+++ b/drivers/haptic/solenoid.h
@@ -29,6 +29,22 @@
# define SOLENOID_MIN_DWELL 4
#endif
+#ifndef SOLENOID_DWELL_STEP_SIZE
+# define SOLENOID_DWELL_STEP_SIZE 1
+#endif
+
+#ifndef SOLENOID_DEFAULT_BUZZ
+# define SOLENOID_DEFAULT_BUZZ 0
+#endif
+
+#ifndef SOLENOID_BUZZ_ACTUATED
+# define SOLENOID_BUZZ_ACTUATED SOLENOID_MIN_DWELL
+#endif
+
+#ifndef SOLENOID_BUZZ_NONACTUATED
+# define SOLENOID_BUZZ_NONACTUATED SOLENOID_MIN_DWELL
+#endif
+
#ifndef SOLENOID_PIN
# error SOLENOID_PIN not defined
#endif
@@ -37,8 +53,6 @@ void solenoid_buzz_on(void);
void solenoid_buzz_off(void);
void solenoid_set_buzz(int buzz);
-void solenoid_dwell_minus(uint8_t solenoid_dwell);
-void solenoid_dwell_plus(uint8_t solenoid_dwell);
void solenoid_set_dwell(uint8_t dwell);
void solenoid_stop(void);
diff --git a/drivers/oled/oled_driver.c b/drivers/oled/oled_driver.c
index ba11db1d2a..53bb8ca3fa 100644
--- a/drivers/oled/oled_driver.c
+++ b/drivers/oled/oled_driver.c
@@ -119,6 +119,9 @@ uint32_t oled_timeout;
#if OLED_SCROLL_TIMEOUT > 0
uint32_t oled_scroll_timeout;
#endif
+#if OLED_UPDATE_INTERVAL > 0
+uint16_t oled_update_timeout;
+#endif
// Internal variables to reduce math instructions
@@ -468,8 +471,9 @@ void oled_write_raw_byte(const char data, uint16_t index) {
}
void oled_write_raw(const char *data, uint16_t size) {
- if (size > OLED_MATRIX_SIZE) size = OLED_MATRIX_SIZE;
- for (uint16_t i = 0; i < size; i++) {
+ uint16_t cursor_start_index = oled_cursor - &oled_buffer[0];
+ if ((size + cursor_start_index) > OLED_MATRIX_SIZE) size = OLED_MATRIX_SIZE - cursor_start_index;
+ for (uint16_t i = cursor_start_index; i < cursor_start_index + size; i++) {
if (oled_buffer[i] == data[i]) continue;
oled_buffer[i] = data[i];
oled_dirty |= ((OLED_BLOCK_TYPE)1 << (i / OLED_BLOCK_SIZE));
@@ -511,8 +515,9 @@ void oled_write_ln_P(const char *data, bool invert) {
}
void oled_write_raw_P(const char *data, uint16_t size) {
- if (size > OLED_MATRIX_SIZE) size = OLED_MATRIX_SIZE;
- for (uint16_t i = 0; i < size; i++) {
+ uint16_t cursor_start_index = oled_cursor - &oled_buffer[0];
+ if ((size + cursor_start_index) > OLED_MATRIX_SIZE) size = OLED_MATRIX_SIZE - cursor_start_index;
+ for (uint16_t i = cursor_start_index; i < cursor_start_index + size; i++) {
uint8_t c = pgm_read_byte(data++);
if (oled_buffer[i] == c) continue;
oled_buffer[i] = c;
@@ -650,9 +655,16 @@ void oled_task(void) {
return;
}
+#if OLED_UPDATE_INTERVAL > 0
+ if (timer_elapsed(oled_update_timeout) >= OLED_UPDATE_INTERVAL) {
+ oled_update_timeout = timer_read();
+ oled_set_cursor(0, 0);
+ oled_task_user();
+ }
+#else
oled_set_cursor(0, 0);
-
oled_task_user();
+#endif
#if OLED_SCROLL_TIMEOUT > 0
if (oled_dirty && oled_scrolling) {
diff --git a/keyboards/ergodox_ez/rules.mk b/keyboards/ergodox_ez/rules.mk
index 773737399f..b7b7b6c143 100644
--- a/keyboards/ergodox_ez/rules.mk
+++ b/keyboards/ergodox_ez/rules.mk
@@ -31,7 +31,8 @@ SWAP_HANDS_ENABLE= yes # Allow swapping hands of keyboard
SLEEP_LED_ENABLE = no
API_SYSEX_ENABLE = no
-RGB_MATRIX_ENABLE = no # enable later
+RGB_MATRIX_ENABLE = no # enable later
+RGB_MATRIX_DRIVER = IS31FL3731
DEBOUNCE_TYPE = eager_pr
# project specific files
diff --git a/keyboards/moonlander/rules.mk b/keyboards/moonlander/rules.mk
index 3d7d623f76..0cff2528f2 100644
--- a/keyboards/moonlander/rules.mk
+++ b/keyboards/moonlander/rules.mk
@@ -15,7 +15,8 @@ NKRO_ENABLE = yes # USB Nkey Rollover
CUSTOM_MATRIX = yes # Custom matrix file
AUDIO_ENABLE = yes
SWAP_HANDS_ENABLE = yes
-RGB_MATRIX_ENABLE = IS31FL3731
+RGB_MATRIX_ENABLE = yes
+RGB_MATRIX_DRIVER = IS31FL3731
#SERIAL_LINK_ENABLE = yes
EEPROM_DRIVER = i2c
diff --git a/keyboards/planck/ez/glow/rules.mk b/keyboards/planck/ez/glow/rules.mk
index 575a9c8fa4..aad92997d0 100644
--- a/keyboards/planck/ez/glow/rules.mk
+++ b/keyboards/planck/ez/glow/rules.mk
@@ -1 +1 @@
-RGB_MATRIX_ENABLE = IS31FL3737
+RGB_MATRIX_ENABLE = yes
diff --git a/keyboards/planck/ez/rules.mk b/keyboards/planck/ez/rules.mk
index a4a53ceeb4..a146c65aa9 100644
--- a/keyboards/planck/ez/rules.mk
+++ b/keyboards/planck/ez/rules.mk
@@ -17,6 +17,7 @@ AUDIO_ENABLE = yes
RGBLIGHT_ENABLE = no
# SERIAL_LINK_ENABLE = yes
ENCODER_ENABLE = yes
+RGB_MATRIX_DRIVER = IS31FL3737
LAYOUTS += ortho_4x12
diff --git a/keyboards/planck/planck.h b/keyboards/planck/planck.h
index 1beafa7764..d575112d36 100644
--- a/keyboards/planck/planck.h
+++ b/keyboards/planck/planck.h
@@ -1,26 +1,9 @@
-#ifndef PLANCK_H
-#define PLANCK_H
+#pragma once
#include "quantum.h"
#define encoder_update(clockwise) encoder_update_user(uint8_t index, clockwise)
#if defined(KEYBOARD_planck_ez)
- #include "ez.h"
-#elif defined(KEYBOARD_planck_light)
- #include "light.h"
-#elif defined(KEYBOARD_planck_rev1)
- #include "rev1.h"
-#elif defined(KEYBOARD_planck_rev2)
- #include "rev2.h"
-#elif defined(KEYBOARD_planck_rev3)
- #include "rev3.h"
-#elif defined(KEYBOARD_planck_rev4)
- #include "rev4.h"
-#elif defined(KEYBOARD_planck_rev5)
- #include "rev5.h"
-#elif defined(KEYBOARD_planck_rev6)
- #include "rev6.h"
-#endif // Planck revisions
-
-#endif
+# include "ez.h"
+#endif // Planck revisions
diff --git a/lib/python/qmk/cli/__init__.py b/lib/python/qmk/cli/__init__.py
index 77724a2448..10536bb230 100644
--- a/lib/python/qmk/cli/__init__.py
+++ b/lib/python/qmk/cli/__init__.py
@@ -8,6 +8,7 @@ from milc import cli
from . import c2json
from . import cformat
+from . import chibios
from . import clean
from . import compile
from . import config
diff --git a/lib/python/qmk/cli/chibios/__init__.py b/lib/python/qmk/cli/chibios/__init__.py
new file mode 100644
index 0000000000..4301837def
--- /dev/null
+++ b/lib/python/qmk/cli/chibios/__init__.py
@@ -0,0 +1 @@
+from . import confmigrate
diff --git a/lib/python/qmk/cli/chibios/confmigrate.py b/lib/python/qmk/cli/chibios/confmigrate.py
new file mode 100644
index 0000000000..eae294a0c6
--- /dev/null
+++ b/lib/python/qmk/cli/chibios/confmigrate.py
@@ -0,0 +1,161 @@
+"""This script automates the copying of the default keymap into your own keymap.
+"""
+import re
+import sys
+import os
+
+from qmk.constants import QMK_FIRMWARE
+from qmk.path import normpath
+from milc import cli
+
+
+def eprint(*args, **kwargs):
+ print(*args, file=sys.stderr, **kwargs)
+
+
+fileHeader = """\
+/* Copyright 2020 QMK
+ *
+ * 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/>.
+ */
+
+/*
+ * This file was auto-generated by:
+ * `qmk chibios-confupdate -i {0} -r {1}`
+ */
+
+#pragma once
+"""
+
+
+def collect_defines(filepath):
+ with open(filepath, 'r') as f:
+ content = f.read()
+ define_search = re.compile(r'(?m)^#\s*define\s+(?:.*\\\r?\n)*.*$', re.MULTILINE)
+ value_search = re.compile(r'^#\s*define\s+(?P<name>[a-zA-Z0-9_]+(\([^\)]*\))?)\s*(?P<value>.*)', re.DOTALL)
+ define_matches = define_search.findall(content)
+
+ defines = {"keys": [], "dict": {}}
+ for define_match in define_matches:
+ value_match = value_search.search(define_match)
+ defines["keys"].append(value_match.group("name"))
+ defines["dict"][value_match.group("name")] = value_match.group("value")
+ return defines
+
+
+def check_diffs(input_defs, reference_defs):
+ not_present_in_input = []
+ not_present_in_reference = []
+ to_override = []
+
+ for key in reference_defs["keys"]:
+ if key not in input_defs["dict"]:
+ not_present_in_input.append(key)
+ continue
+
+ for key in input_defs["keys"]:
+ if key not in input_defs["dict"]:
+ not_present_in_input.append(key)
+ continue
+
+ for key in input_defs["keys"]:
+ if key in reference_defs["keys"] and input_defs["dict"][key] != reference_defs["dict"][key]:
+ to_override.append((key, input_defs["dict"][key]))
+
+ return (to_override, not_present_in_input, not_present_in_reference)
+
+
+def migrate_chconf_h(to_override, outfile):
+ print(fileHeader.format(cli.args.input.relative_to(QMK_FIRMWARE), cli.args.reference.relative_to(QMK_FIRMWARE)), file=outfile)
+
+ for override in to_override:
+ print("#define %s %s" % (override[0], override[1]), file=outfile)
+ print("", file=outfile)
+
+ print("#include_next <chconf.h>\n", file=outfile)
+
+
+def migrate_halconf_h(to_override, outfile):
+ print(fileHeader.format(cli.args.input.relative_to(QMK_FIRMWARE), cli.args.reference.relative_to(QMK_FIRMWARE)), file=outfile)
+
+ for override in to_override:
+ print("#define %s %s" % (override[0], override[1]), file=outfile)
+ print("", file=outfile)
+
+ print("#include_next <halconf.h>\n", file=outfile)
+
+
+def migrate_mcuconf_h(to_override, outfile):
+ print(fileHeader.format(cli.args.input.relative_to(QMK_FIRMWARE), cli.args.reference.relative_to(QMK_FIRMWARE)), file=outfile)
+
+ print("#include_next <mcuconf.h>\n", file=outfile)
+
+ for override in to_override:
+ print("#undef %s" % (override[0]), file=outfile)
+ print("#define %s %s" % (override[0], override[1]), file=outfile)
+ print("", file=outfile)
+
+
+@cli.argument('-i', '--input', type=normpath, arg_only=True, help='Specify input config file.')
+@cli.argument('-r', '--reference', type=normpath, arg_only=True, help='Specify the reference file to compare against')
+@cli.argument('-o', '--overwrite', arg_only=True, action='store_true', help='Overwrites the input file during migration.')
+@cli.argument('-d', '--delete', arg_only=True, action='store_true', help='If the file has no overrides, migration will delete the input file.')
+@cli.subcommand('Generates a migrated ChibiOS configuration file, as a result of comparing the input against a reference')
+def chibios_confmigrate(cli):
+ """Generates a usable ChibiOS replacement configuration file, based on a fully-defined conf and a reference config.
+ """
+
+ input_defs = collect_defines(cli.args.input)
+ reference_defs = collect_defines(cli.args.reference)
+
+ (to_override, not_present_in_input, not_present_in_reference) = check_diffs(input_defs, reference_defs)
+
+ if len(not_present_in_input) > 0:
+ eprint("Keys not in input, but present inside reference (potential manual migration required):")
+ for key in not_present_in_input:
+ eprint(" %s" % (key))
+
+ if len(not_present_in_reference) > 0:
+ eprint("Keys not in reference, but present inside input (potential manual migration required):")
+ for key in not_present_in_reference:
+ eprint(" %s" % (key))
+
+ if len(to_override) == 0:
+ eprint('No overrides found! If there were no missing keys above, it should be safe to delete the input file.')
+ if cli.args.delete:
+ os.remove(cli.args.input)
+ else:
+ eprint('Overrides found:')
+ for override in to_override:
+ eprint("%40s: %s -> %s" % (override[0], reference_defs["dict"][override[0]].encode('unicode_escape').decode("utf-8"), override[1].encode('unicode_escape').decode("utf-8")))
+
+ eprint('--------------------------------------')
+
+ if "CHCONF_H" in input_defs["dict"] or "_CHCONF_H_" in input_defs["dict"]:
+ migrate_chconf_h(to_override, outfile=sys.stdout)
+ if cli.args.overwrite:
+ with open(cli.args.input, "w") as out_file:
+ migrate_chconf_h(to_override, outfile=out_file)
+
+ elif "HALCONF_H" in input_defs["dict"] or "_HALCONF_H_" in input_defs["dict"]:
+ migrate_halconf_h(to_override, outfile=sys.stdout)
+ if cli.args.overwrite:
+ with open(cli.args.input, "w") as out_file:
+ migrate_halconf_h(to_override, outfile=out_file)
+
+ elif "MCUCONF_H" in input_defs["dict"] or "_MCUCONF_H_" in input_defs["dict"]:
+ migrate_mcuconf_h(to_override, outfile=sys.stdout)
+ if cli.args.overwrite:
+ with open(cli.args.input, "w") as out_file:
+ migrate_mcuconf_h(to_override, outfile=out_file)
diff --git a/lib/python/qmk/cli/doctor.py b/lib/python/qmk/cli/doctor.py
index a5eda555f0..4fe318b636 100755
--- a/lib/python/qmk/cli/doctor.py
+++ b/lib/python/qmk/cli/doctor.py
@@ -10,9 +10,9 @@ from pathlib import Path
from enum import Enum
from milc import cli
+from milc.questions import yesno
from qmk import submodules
from qmk.constants import QMK_FIRMWARE
-from qmk.questions import yesno
from qmk.commands import run
diff --git a/lib/python/qmk/questions.py b/lib/python/qmk/questions.py
deleted file mode 100644
index 865c6bbdc5..0000000000
--- a/lib/python/qmk/questions.py
+++ /dev/null
@@ -1,183 +0,0 @@
-"""Functions to collect user input.
-"""
-
-from milc import cli
-
-try:
- from milc import format_ansi
-except ImportError:
- from milc.ansi import format_ansi
-
-
-def yesno(prompt, *args, default=None, **kwargs):
- """Displays prompt to the user and gets a yes or no response.
-
- Returns True for a yes and False for a no.
-
- If you add `--yes` and `--no` arguments to your program the user can answer questions by passing command line flags.
-
- @add_argument('-y', '--yes', action='store_true', arg_only=True, help='Answer yes to all questions.')
- @add_argument('-n', '--no', action='store_true', arg_only=True, help='Answer no to all questions.')
-
- Arguments:
- prompt
- The prompt to present to the user. Can include ANSI and format strings like milc's `cli.echo()`.
-
- default
- Whether to default to a Yes or No when the user presses enter.
-
- None- force the user to enter Y or N
-
- True- Default to yes
-
- False- Default to no
- """
- if not args and kwargs:
- args = kwargs
-
- if 'no' in cli.args and cli.args.no:
- return False
-
- if 'yes' in cli.args and cli.args.yes:
- return True
-
- if default is not None:
- if default:
- prompt = prompt + ' [Y/n] '
- else:
- prompt = prompt + ' [y/N] '
-
- while True:
- cli.echo('')
- answer = input(format_ansi(prompt % args))
- cli.echo('')
-
- if not answer and prompt is not None:
- return default
-
- elif answer.lower() in ['y', 'yes']:
- return True
-
- elif answer.lower() in ['n', 'no']:
- return False
-
-
-def question(prompt, *args, default=None, confirm=False, answer_type=str, validate=None, **kwargs):
- """Prompt the user to answer a question with a free-form input.
-
- Arguments:
- prompt
- The prompt to present to the user. Can include ANSI and format strings like milc's `cli.echo()`.
-
- default
- The value to return when the user doesn't enter any value. Use None to prompt until they enter a value.
-
- confirm
- Present the user with a confirmation dialog before accepting their answer.
-
- answer_type
- Specify a type function for the answer. Will re-prompt the user if the function raises any errors. Common choices here include int, float, and decimal.Decimal.
-
- validate
- This is an optional function that can be used to validate the answer. It should return True or False and have the following signature:
-
- def function_name(answer, *args, **kwargs):
- """
- if not args and kwargs:
- args = kwargs
-
- if default is not None:
- prompt = '%s [%s] ' % (prompt, default)
-
- while True:
- cli.echo('')
- answer = input(format_ansi(prompt % args))
- cli.echo('')
-
- if answer:
- if validate is not None and not validate(answer, *args, **kwargs):
- continue
-
- elif confirm:
- if yesno('Is the answer "%s" correct?', answer, default=True):
- try:
- return answer_type(answer)
- except Exception as e:
- cli.log.error('Could not convert answer (%s) to type %s: %s', answer, answer_type.__name__, str(e))
-
- else:
- try:
- return answer_type(answer)
- except Exception as e:
- cli.log.error('Could not convert answer (%s) to type %s: %s', answer, answer_type.__name__, str(e))
-
- elif default is not None:
- return default
-
-
-def choice(heading, options, *args, default=None, confirm=False, prompt='Please enter your choice: ', **kwargs):
- """Present the user with a list of options and let them pick one.
-
- Users can enter either the number or the text of their choice.
-
- This will return the value of the item they choose, not the numerical index.
-
- Arguments:
- heading
- The text to place above the list of options.
-
- options
- A sequence of items to choose from.
-
- default
- The index of the item to return when the user doesn't enter any value. Use None to prompt until they enter a value.
-
- confirm
- Present the user with a confirmation dialog before accepting their answer.
-
- prompt
- The prompt to present to the user. Can include ANSI and format strings like milc's `cli.echo()`.
- """
- if not args and kwargs:
- args = kwargs
-
- if prompt and default:
- prompt = prompt + ' [%s] ' % (default + 1,)
-
- while True:
- # Prompt for an answer.
- cli.echo('')
- cli.echo(heading % args)
- cli.echo('')
- for i, option in enumerate(options, 1):
- cli.echo('\t{fg_cyan}%d.{fg_reset} %s', i, option)
-
- cli.echo('')
- answer = input(format_ansi(prompt))
- cli.echo('')
-
- # If the user types in one of the options exactly use that
- if answer in options:
- return answer
-
- # Massage the answer into a valid integer
- if answer == '' and default:
- answer = default
- else:
- try:
- answer = int(answer) - 1
- except Exception:
- # Normally we would log the exception here, but in the interest of clean UI we do not.
- cli.log.error('Invalid choice: %s', answer + 1)
- continue
-
- # Validate the answer
- if answer >= len(options) or answer < 0:
- cli.log.error('Invalid choice: %s', answer + 1)
- continue
-
- if confirm and not yesno('Is the answer "%s" correct?', answer + 1, default=True):
- continue
-
- # Return the answer they chose.
- return options[answer]
diff --git a/message.mk b/message.mk
index be04fa9b81..84b23c1ba8 100644
--- a/message.mk
+++ b/message.mk
@@ -5,6 +5,7 @@ ifeq ($(COLOR),true)
OK_COLOR=\033[32;01m
ERROR_COLOR=\033[31;01m
WARN_COLOR=\033[33;01m
+ SKIPPED_COLOR=\033[36;01m
BLUE=\033[0;34m
BOLD=\033[1m
endif
@@ -20,6 +21,7 @@ ON_ERROR ?= exit 1
OK_STRING=$(OK_COLOR)[OK]$(NO_COLOR)\n
ERROR_STRING=$(ERROR_COLOR)[ERRORS]$(NO_COLOR)\n
WARN_STRING=$(WARN_COLOR)[WARNINGS]$(NO_COLOR)\n
+SKIPPED_STRING=$(SKIPPED_COLOR)[SKIPPED]$(NO_COLOR)\n
TAB_LOG = printf "\n%s\n\n" "$$LOG" | $(AWK) '{ sub(/^/," | "); print }'
TAB_LOG_PLAIN = printf "%s\n" "$$LOG"
@@ -29,6 +31,7 @@ PRINT_ERROR = ($(SILENT) ||printf " $(ERROR_STRING)" | $(AWK_STATUS)) && $(TAB_L
PRINT_WARNING = ($(SILENT) || printf " $(WARN_STRING)" | $(AWK_STATUS)) && $(TAB_LOG)
PRINT_ERROR_PLAIN = ($(SILENT) ||printf " $(ERROR_STRING)" | $(AWK_STATUS)) && $(TAB_LOG_PLAIN) && $(ON_ERROR)
PRINT_WARNING_PLAIN = ($(SILENT) || printf " $(WARN_STRING)" | $(AWK_STATUS)) && $(TAB_LOG_PLAIN)
+PRINT_SKIPPED_PLAIN = ($(SILENT) || printf " $(SKIPPED_STRING)" | $(AWK_STATUS))
PRINT_OK = $(SILENT) || printf " $(OK_STRING)" | $(AWK_STATUS)
BUILD_CMD = LOG=$$($(CMD) 2>&1) ; if [ $$? -gt 0 ]; then $(PRINT_ERROR); elif [ "$$LOG" != "" ] ; then $(PRINT_WARNING); else $(PRINT_OK); fi;
MAKE_MSG_FORMAT = $(AWK) '{ printf "%-118s", $$0;}'
diff --git a/platforms/chibios/BLACKPILL_STM32_F401/configs/config.h b/platforms/chibios/BLACKPILL_STM32_F401/configs/config.h
index eb73e72ef2..1c9d9c6126 100644
--- a/platforms/chibios/BLACKPILL_STM32_F401/configs/config.h
+++ b/platforms/chibios/BLACKPILL_STM32_F401/configs/config.h
@@ -20,4 +20,6 @@
#define STM32_LSECLK 32768U
#define STM32_HSECLK 25000000U
-#define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE
+#ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP
+# define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE
+#endif
diff --git a/platforms/chibios/BLACKPILL_STM32_F411/configs/config.h b/platforms/chibios/BLACKPILL_STM32_F411/configs/config.h
index eb73e72ef2..1c9d9c6126 100644
--- a/platforms/chibios/BLACKPILL_STM32_F411/configs/config.h
+++ b/platforms/chibios/BLACKPILL_STM32_F411/configs/config.h
@@ -20,4 +20,6 @@
#define STM32_LSECLK 32768U
#define STM32_HSECLK 25000000U
-#define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE
+#ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP
+# define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE
+#endif
diff --git a/platforms/chibios/GENERIC_STM32_F042X6/configs/mcuconf.h b/platforms/chibios/GENERIC_STM32_F042X6/configs/mcuconf.h
new file mode 100644
index 0000000000..4643e9f92e
--- /dev/null
+++ b/platforms/chibios/GENERIC_STM32_F042X6/configs/mcuconf.h
@@ -0,0 +1,168 @@
+/*
+ ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef _MCUCONF_H_
+#define _MCUCONF_H_
+
+/*
+ * STM32F0xx drivers configuration.
+ * The following settings override the default settings present in
+ * the various device driver implementation headers.
+ * Note that the settings for each driver only have effect if the whole
+ * driver is enabled in halconf.h.
+ *
+ * IRQ priorities:
+ * 3...0 Lowest...Highest.
+ *
+ * DMA priorities:
+ * 0...3 Lowest...Highest.
+ */
+
+#define STM32F0xx_MCUCONF
+
+/*
+ * HAL driver system settings.
+ */
+#define STM32_NO_INIT FALSE
+#define STM32_PVD_ENABLE FALSE
+#define STM32_PLS STM32_PLS_LEV0
+#define STM32_HSI_ENABLED TRUE
+#define STM32_HSI14_ENABLED TRUE
+#define STM32_HSI48_ENABLED FALSE
+#define STM32_LSI_ENABLED TRUE
+#define STM32_HSE_ENABLED FALSE
+#define STM32_LSE_ENABLED FALSE
+#define STM32_SW STM32_SW_PLL
+#define STM32_PLLSRC STM32_PLLSRC_HSI_DIV2
+#define STM32_PREDIV_VALUE 1
+#define STM32_PLLMUL_VALUE 12
+#define STM32_HPRE STM32_HPRE_DIV1
+#define STM32_PPRE STM32_PPRE_DIV1
+#define STM32_ADCSW STM32_ADCSW_HSI14
+#define STM32_ADCPRE STM32_ADCPRE_DIV4
+#define STM32_MCOSEL STM32_MCOSEL_NOCLOCK
+#define STM32_ADCPRE STM32_ADCPRE_DIV4
+#define STM32_ADCSW STM32_ADCSW_HSI14
+#define STM32_USBSW STM32_USBSW_HSI48
+#define STM32_CECSW STM32_CECSW_HSI
+#define STM32_I2C1SW STM32_I2C1SW_HSI
+#define STM32_USART1SW STM32_USART1SW_PCLK
+#define STM32_RTCSEL STM32_RTCSEL_LSI
+
+/*
+ * ADC driver system settings.
+ */
+#define STM32_ADC_USE_ADC1 FALSE
+#define STM32_ADC_ADC1_DMA_PRIORITY 2
+#define STM32_ADC_IRQ_PRIORITY 2
+#define STM32_ADC_ADC1_DMA_IRQ_PRIORITY 2
+
+/*
+ * EXT driver system settings.
+ */
+#define STM32_EXT_EXTI0_1_IRQ_PRIORITY 3
+#define STM32_EXT_EXTI2_3_IRQ_PRIORITY 3
+#define STM32_EXT_EXTI4_15_IRQ_PRIORITY 3
+#define STM32_EXT_EXTI16_IRQ_PRIORITY 3
+#define STM32_EXT_EXTI17_IRQ_PRIORITY 3
+
+/*
+ * GPT driver system settings.
+ */
+#define STM32_GPT_USE_TIM1 FALSE
+#define STM32_GPT_USE_TIM2 FALSE
+#define STM32_GPT_USE_TIM3 FALSE
+#define STM32_GPT_USE_TIM14 FALSE
+#define STM32_GPT_TIM1_IRQ_PRIORITY 2
+#define STM32_GPT_TIM2_IRQ_PRIORITY 2
+#define STM32_GPT_TIM3_IRQ_PRIORITY 2
+#define STM32_GPT_TIM14_IRQ_PRIORITY 2
+
+/*
+ * I2C driver system settings.
+ */
+#define STM32_I2C_USE_I2C1 FALSE
+#define STM32_I2C_USE_I2C2 FALSE
+#define STM32_I2C_BUSY_TIMEOUT 50
+#define STM32_I2C_I2C1_IRQ_PRIORITY 3
+#define STM32_I2C_I2C2_IRQ_PRIORITY 3
+#define STM32_I2C_USE_DMA TRUE
+#define STM32_I2C_I2C1_DMA_PRIORITY 1
+#define STM32_I2C_I2C2_DMA_PRIORITY 1
+#define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure")
+
+/*
+ * ICU driver system settings.
+ */
+#define STM32_ICU_USE_TIM1 FALSE
+#define STM32_ICU_USE_TIM2 FALSE
+#define STM32_ICU_USE_TIM3 FALSE
+#define STM32_ICU_TIM1_IRQ_PRIORITY 3
+#define STM32_ICU_TIM2_IRQ_PRIORITY 3
+#define STM32_ICU_TIM3_IRQ_PRIORITY 3
+
+/*
+ * PWM driver system settings.
+ */
+#define STM32_PWM_USE_ADVANCED FALSE
+#define STM32_PWM_USE_TIM1 FALSE
+#define STM32_PWM_USE_TIM2 FALSE
+#define STM32_PWM_USE_TIM3 FALSE
+#define STM32_PWM_TIM1_IRQ_PRIORITY 3
+#define STM32_PWM_TIM2_IRQ_PRIORITY 3
+#define STM32_PWM_TIM3_IRQ_PRIORITY 3
+
+/*
+ * SERIAL driver system settings.
+ */
+#define STM32_SERIAL_USE_USART1 FALSE
+#define STM32_SERIAL_USE_USART2 FALSE
+#define STM32_SERIAL_USART1_PRIORITY 3
+#define STM32_SERIAL_USART2_PRIORITY 3
+
+/*
+ * SPI driver system settings.
+ */
+#define STM32_SPI_USE_SPI1 FALSE
+#define STM32_SPI_USE_SPI2 FALSE
+#define STM32_SPI_SPI1_DMA_PRIORITY 1
+#define STM32_SPI_SPI2_DMA_PRIORITY 1
+#define STM32_SPI_SPI1_IRQ_PRIORITY 2
+#define STM32_SPI_SPI2_IRQ_PRIORITY 2
+#define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure")
+
+/*
+ * ST driver system settings.
+ */
+#define STM32_ST_IRQ_PRIORITY 2
+#define STM32_ST_USE_TIMER 2
+
+/*
+ * UART driver system settings.
+ */
+#define STM32_UART_USE_USART1 FALSE
+#define STM32_UART_USE_USART2 FALSE
+#define STM32_UART_USART1_IRQ_PRIORITY 3
+#define STM32_UART_USART2_IRQ_PRIORITY 3
+#define STM32_UART_USART1_DMA_PRIORITY 0
+#define STM32_UART_USART2_DMA_PRIORITY 0
+#define STM32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure")
+
+/*
+ * USB driver system settings.
+ */
+#define STM32_USB_USE_USB1 TRUE
+#define STM32_USB_LOW_POWER_ON_SUSPEND FALSE
+#define STM32_USB_USB1_LP_IRQ_PRIORITY 3
+
+#endif /* _MCUCONF_H_ */ \ No newline at end of file
diff --git a/platforms/chibios/GENERIC_STM32_F072XB/board/board.c b/platforms/chibios/GENERIC_STM32_F072XB/board/board.c
deleted file mode 100644
index c91136e8f6..0000000000
--- a/platforms/chibios/GENERIC_STM32_F072XB/board/board.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-/*
- * This file has been automatically generated using ChibiStudio board
- * generator plugin. Do not edit manually.
- */
-
-#include "hal.h"
-#include "stm32_gpio.h"
-
-/*===========================================================================*/
-/* Driver local definitions. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver exported variables. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver local variables and types. */
-/*===========================================================================*/
-
-/**
- * @brief Type of STM32 GPIO port setup.
- */
-typedef struct {
- uint32_t moder;
- uint32_t otyper;
- uint32_t ospeedr;
- uint32_t pupdr;
- uint32_t odr;
- uint32_t afrl;
- uint32_t afrh;
-} gpio_setup_t;
-
-/**
- * @brief Type of STM32 GPIO initialization data.
- */
-typedef struct {
-#if STM32_HAS_GPIOA || defined(__DOXYGEN__)
- gpio_setup_t PAData;
-#endif
-#if STM32_HAS_GPIOB || defined(__DOXYGEN__)
- gpio_setup_t PBData;
-#endif
-#if STM32_HAS_GPIOC || defined(__DOXYGEN__)
- gpio_setup_t PCData;
-#endif
-#if STM32_HAS_GPIOD || defined(__DOXYGEN__)
- gpio_setup_t PDData;
-#endif
-#if STM32_HAS_GPIOE || defined(__DOXYGEN__)
- gpio_setup_t PEData;
-#endif
-#if STM32_HAS_GPIOF || defined(__DOXYGEN__)
- gpio_setup_t PFData;
-#endif
-#if STM32_HAS_GPIOG || defined(__DOXYGEN__)
- gpio_setup_t PGData;
-#endif
-#if STM32_HAS_GPIOH || defined(__DOXYGEN__)
- gpio_setup_t PHData;
-#endif
-#if STM32_HAS_GPIOI || defined(__DOXYGEN__)
- gpio_setup_t PIData;
-#endif
-#if STM32_HAS_GPIOJ || defined(__DOXYGEN__)
- gpio_setup_t PJData;
-#endif
-#if STM32_HAS_GPIOK || defined(__DOXYGEN__)
- gpio_setup_t PKData;
-#endif
-} gpio_config_t;
-
-/**
- * @brief STM32 GPIO static initialization data.
- */
-static const gpio_config_t gpio_default_config = {
-#if STM32_HAS_GPIOA
- {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR, VAL_GPIOA_ODR, VAL_GPIOA_AFRL, VAL_GPIOA_AFRH},
-#endif
-#if STM32_HAS_GPIOB
- {VAL_GPIOB_MODER, VAL_GPIOB_OTYPER, VAL_GPIOB_OSPEEDR, VAL_GPIOB_PUPDR, VAL_GPIOB_ODR, VAL_GPIOB_AFRL, VAL_GPIOB_AFRH},
-#endif
-#if STM32_HAS_GPIOC
- {VAL_GPIOC_MODER, VAL_GPIOC_OTYPER, VAL_GPIOC_OSPEEDR, VAL_GPIOC_PUPDR, VAL_GPIOC_ODR, VAL_GPIOC_AFRL, VAL_GPIOC_AFRH},
-#endif
-#if STM32_HAS_GPIOD
- {VAL_GPIOD_MODER, VAL_GPIOD_OTYPER, VAL_GPIOD_OSPEEDR, VAL_GPIOD_PUPDR, VAL_GPIOD_ODR, VAL_GPIOD_AFRL, VAL_GPIOD_AFRH},
-#endif
-#if STM32_HAS_GPIOE
- {VAL_GPIOE_MODER, VAL_GPIOE_OTYPER, VAL_GPIOE_OSPEEDR, VAL_GPIOE_PUPDR, VAL_GPIOE_ODR, VAL_GPIOE_AFRL, VAL_GPIOE_AFRH},
-#endif
-#if STM32_HAS_GPIOF
- {VAL_GPIOF_MODER, VAL_GPIOF_OTYPER, VAL_GPIOF_OSPEEDR, VAL_GPIOF_PUPDR, VAL_GPIOF_ODR, VAL_GPIOF_AFRL, VAL_GPIOF_AFRH},
-#endif
-#if STM32_HAS_GPIOG
- {VAL_GPIOG_MODER, VAL_GPIOG_OTYPER, VAL_GPIOG_OSPEEDR, VAL_GPIOG_PUPDR, VAL_GPIOG_ODR, VAL_GPIOG_AFRL, VAL_GPIOG_AFRH},
-#endif
-#if STM32_HAS_GPIOH
- {VAL_GPIOH_MODER, VAL_GPIOH_OTYPER, VAL_GPIOH_OSPEEDR, VAL_GPIOH_PUPDR, VAL_GPIOH_ODR, VAL_GPIOH_AFRL, VAL_GPIOH_AFRH},
-#endif
-#if STM32_HAS_GPIOI
- {VAL_GPIOI_MODER, VAL_GPIOI_OTYPER, VAL_GPIOI_OSPEEDR, VAL_GPIOI_PUPDR, VAL_GPIOI_ODR, VAL_GPIOI_AFRL, VAL_GPIOI_AFRH},
-#endif
-#if STM32_HAS_GPIOJ
- {VAL_GPIOJ_MODER, VAL_GPIOJ_OTYPER, VAL_GPIOJ_OSPEEDR, VAL_GPIOJ_PUPDR, VAL_GPIOJ_ODR, VAL_GPIOJ_AFRL, VAL_GPIOJ_AFRH},
-#endif
-#if STM32_HAS_GPIOK
- {VAL_GPIOK_MODER, VAL_GPIOK_OTYPER, VAL_GPIOK_OSPEEDR, VAL_GPIOK_PUPDR, VAL_GPIOK_ODR, VAL_GPIOK_AFRL, VAL_GPIOK_AFRH}
-#endif
-};
-
-/*===========================================================================*/
-/* Driver local functions. */
-/*===========================================================================*/
-
-static void gpio_init(stm32_gpio_t *gpiop, const gpio_setup_t *config) {
- gpiop->OTYPER = config->otyper;
- gpiop->OSPEEDR = config->ospeedr;
- gpiop->PUPDR = config->pupdr;
- gpiop->ODR = config->odr;
- gpiop->AFRL = config->afrl;
- gpiop->AFRH = config->afrh;
- gpiop->MODER = config->moder;
-}
-
-static void stm32_gpio_init(void) {
- /* Enabling GPIO-related clocks, the mask comes from the
- registry header file.*/
- rccResetAHB(STM32_GPIO_EN_MASK);
- rccEnableAHB(STM32_GPIO_EN_MASK, true);
-
- /* Initializing all the defined GPIO ports.*/
-#if STM32_HAS_GPIOA
- gpio_init(GPIOA, &gpio_default_config.PAData);
-#endif
-#if STM32_HAS_GPIOB
- gpio_init(GPIOB, &gpio_default_config.PBData);
-#endif
-#if STM32_HAS_GPIOC
- gpio_init(GPIOC, &gpio_default_config.PCData);
-#endif
-#if STM32_HAS_GPIOD
- gpio_init(GPIOD, &gpio_default_config.PDData);
-#endif
-#if STM32_HAS_GPIOE
- gpio_init(GPIOE, &gpio_default_config.PEData);
-#endif
-#if STM32_HAS_GPIOF
- gpio_init(GPIOF, &gpio_default_config.PFData);
-#endif
-#if STM32_HAS_GPIOG
- gpio_init(GPIOG, &gpio_default_config.PGData);
-#endif
-#if STM32_HAS_GPIOH
- gpio_init(GPIOH, &gpio_default_config.PHData);
-#endif
-#if STM32_HAS_GPIOI
- gpio_init(GPIOI, &gpio_default_config.PIData);
-#endif
-#if STM32_HAS_GPIOJ
- gpio_init(GPIOJ, &gpio_default_config.PJData);
-#endif
-#if STM32_HAS_GPIOK
- gpio_init(GPIOK, &gpio_default_config.PKData);
-#endif
-}
-
-/*===========================================================================*/
-/* Driver interrupt handlers. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver exported functions. */
-/*===========================================================================*/
-
-__attribute__((weak)) void enter_bootloader_mode_if_requested(void) {}
-
-/**
- * @brief Early initialization code.
- * @details GPIO ports and system clocks are initialized before everything
- * else.
- */
-void __early_init(void) {
- enter_bootloader_mode_if_requested();
-
- stm32_gpio_init();
- stm32_clock_init();
-}
-
-#if HAL_USE_SDC || defined(__DOXYGEN__)
-/**
- * @brief SDC card detection.
- */
-bool sdc_lld_is_card_inserted(SDCDriver *sdcp) {
- (void)sdcp;
- /* TODO: Fill the implementation.*/
- return true;
-}
-
-/**
- * @brief SDC card write protection detection.
- */
-bool sdc_lld_is_write_protected(SDCDriver *sdcp) {
- (void)sdcp;
- /* TODO: Fill the implementation.*/
- return false;
-}
-#endif /* HAL_USE_SDC */
-
-#if HAL_USE_MMC_SPI || defined(__DOXYGEN__)
-/**
- * @brief MMC_SPI card detection.
- */
-bool mmc_lld_is_card_inserted(MMCDriver *mmcp) {
- (void)mmcp;
- /* TODO: Fill the implementation.*/
- return true;
-}
-
-/**
- * @brief MMC_SPI card write protection detection.
- */
-bool mmc_lld_is_write_protected(MMCDriver *mmcp) {
- (void)mmcp;
- /* TODO: Fill the implementation.*/
- return false;
-}
-#endif
-
-/**
- * @brief Board-specific initialization code.
- * @todo Add your board-specific code, if any.
- */
-void boardInit(void) {}
diff --git a/platforms/chibios/GENERIC_STM32_F072XB/board/board.h b/platforms/chibios/GENERIC_STM32_F072XB/board/board.h
deleted file mode 100644
index 87570e62d2..0000000000
--- a/platforms/chibios/GENERIC_STM32_F072XB/board/board.h
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-/*
- * This file has been automatically generated using ChibiStudio board
- * generator plugin. Do not edit manually.
- */
-
-#ifndef BOARD_H
-#define BOARD_H
-
-/*===========================================================================*/
-/* Driver constants. */
-/*===========================================================================*/
-
-/*
- * Setup for Generic STM32_F072 Board
- */
-
-/*
- * Board identifier.
- */
-#define BOARD_GENERIC_STM32_F072XB
-#define BOARD_NAME "STM32_F072"
-
-/*
- * Board oscillators-related settings.
- * NOTE: LSE not fitted.
- * NOTE: HSE not fitted.
- */
-#if !defined(STM32_LSECLK)
-# define STM32_LSECLK 0U
-#endif
-
-#define STM32_LSEDRV (3U << 3U)
-
-#if !defined(STM32_HSECLK)
-# define STM32_HSECLK 0U
-#endif
-
-#define STM32_HSE_BYPASS
-
-/*
- * MCU type as defined in the ST header.
- */
-#define STM32F072xB
-
-/*
- * IO pins assignments.
- */
-#define GPIOA_BUTTON 0U
-#define GPIOA_PIN1 1U
-#define GPIOA_PIN2 2U
-#define GPIOA_PIN3 3U
-#define GPIOA_PIN4 4U
-#define GPIOA_PIN5 5U
-#define GPIOA_PIN6 6U
-#define GPIOA_PIN7 7U
-#define GPIOA_PIN8 8U
-#define GPIOA_PIN9 9U
-#define GPIOA_PIN10 10U
-#define GPIOA_USB_DM 11U
-#define GPIOA_USB_DP 12U
-#define GPIOA_SWDIO 13U
-#define GPIOA_SWCLK 14U
-#define GPIOA_PIN15 15U
-
-#define GPIOB_PIN0 0U
-#define GPIOB_PIN1 1U
-#define GPIOB_PIN2 2U
-#define GPIOB_PIN3 3U
-#define GPIOB_PIN4 4U
-#define GPIOB_PIN5 5U
-#define GPIOB_PIN6 6U
-#define GPIOB_PIN7 7U
-#define GPIOB_PIN8 8U
-#define GPIOB_PIN9 9U
-#define GPIOB_PIN10 10U
-#define GPIOB_PIN11 11U
-#define GPIOB_PIN12 12U
-#define GPIOB_SPI2_SCK 13U
-#define GPIOB_SPI2_MISO 14U
-#define GPIOB_SPI2_MOSI 15U
-
-#define GPIOC_MEMS_CS 0U
-#define GPIOC_PIN1 1U
-#define GPIOC_PIN2 2U
-#define GPIOC_PIN3 3U
-#define GPIOC_PIN4 4U
-#define GPIOC_PIN5 5U
-#define GPIOC_LED_RED 6U
-#define GPIOC_LED_BLUE 7U
-#define GPIOC_LED_ORANGE 8U
-#define GPIOC_LED_GREEN 9U
-#define GPIOC_PIN10 10U
-#define GPIOC_PIN11 11U
-#define GPIOC_PIN12 12U
-#define GPIOC_PIN13 13U
-#define GPIOC_OSC32_IN 14U
-#define GPIOC_OSC32_OUT 15U
-
-#define GPIOD_PIN0 0U
-#define GPIOD_PIN1 1U
-#define GPIOD_PIN2 2U
-#define GPIOD_PIN3 3U
-#define GPIOD_PIN4 4U
-#define GPIOD_PIN5 5U
-#define GPIOD_PIN6 6U
-#define GPIOD_PIN7 7U
-#define GPIOD_PIN8 8U
-#define GPIOD_PIN9 9U
-#define GPIOD_PIN10 10U
-#define GPIOD_PIN11 11U
-#define GPIOD_PIN12 12U
-#define GPIOD_PIN13 13U
-#define GPIOD_PIN14 14U
-#define GPIOD_PIN15 15U
-
-#define GPIOE_PIN0 0U
-#define GPIOE_PIN1 1U
-#define GPIOE_PIN2 2U
-#define GPIOE_PIN3 3U
-#define GPIOE_PIN4 4U
-#define GPIOE_PIN5 5U
-#define GPIOE_PIN6 6U
-#define GPIOE_PIN7 7U
-#define GPIOE_PIN8 8U
-#define GPIOE_PIN9 9U
-#define GPIOE_PIN10 10U
-#define GPIOE_PIN11 11U
-#define GPIOE_PIN12 12U
-#define GPIOE_PIN13 13U
-#define GPIOE_PIN14 14U
-#define GPIOE_PIN15 15U
-
-#define GPIOF_OSC_IN 0U
-#define GPIOF_OSC_OUT 1U
-#define GPIOF_PIN2 2U
-#define GPIOF_PIN3 3U
-#define GPIOF_PIN4 4U
-#define GPIOF_PIN5 5U
-#define GPIOF_PIN6 6U
-#define GPIOF_PIN7 7U
-#define GPIOF_PIN8 8U
-#define GPIOF_PIN9 9U
-#define GPIOF_PIN10 10U
-#define GPIOF_PIN11 11U
-#define GPIOF_PIN12 12U
-#define GPIOF_PIN13 13U
-#define GPIOF_PIN14 14U
-#define GPIOF_PIN15 15U
-
-/*
- * IO lines assignments.
- */
-#define LINE_BUTTON PAL_LINE(GPIOA, 0U)
-#define LINE_USB_DM PAL_LINE(GPIOA, 11U)
-#define LINE_USB_DP PAL_LINE(GPIOA, 12U)
-#define LINE_SWDIO PAL_LINE(GPIOA, 13U)
-#define LINE_SWCLK PAL_LINE(GPIOA, 14U)
-#define LINE_SPI2_SCK PAL_LINE(GPIOB, 13U)
-#define LINE_SPI2_MISO PAL_LINE(GPIOB, 14U)
-#define LINE_SPI2_MOSI PAL_LINE(GPIOB, 15U)
-#define LINE_MEMS_CS PAL_LINE(GPIOC, 0U)
-#define LINE_LED_RED PAL_LINE(GPIOC, 6U)
-#define LINE_LED_BLUE PAL_LINE(GPIOC, 7U)
-#define LINE_LED_ORANGE PAL_LINE(GPIOC, 8U)
-#define LINE_LED_GREEN PAL_LINE(GPIOC, 9U)
-#define LINE_OSC32_IN PAL_LINE(GPIOC, 14U)
-#define LINE_OSC32_OUT PAL_LINE(GPIOC, 15U)
-#define LINE_OSC_IN PAL_LINE(GPIOF, 0U)
-#define LINE_OSC_OUT PAL_LINE(GPIOF, 1U)
-
-/*===========================================================================*/
-/* Driver pre-compile time settings. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Derived constants and error checks. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver data structures and types. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver macros. */
-/*===========================================================================*/
-
-/*
- * I/O ports initial setup, this configuration is established soon after reset
- * in the initialization code.
- * Please refer to the STM32 Reference Manual for details.
- */
-#define PIN_MODE_INPUT(n) (0U << ((n)*2U))
-#define PIN_MODE_OUTPUT(n) (1U << ((n)*2U))
-#define PIN_MODE_ALTERNATE(n) (2U << ((n)*2U))
-#define PIN_MODE_ANALOG(n) (3U << ((n)*2U))
-#define PIN_ODR_LOW(n) (0U << (n))
-#define PIN_ODR_HIGH(n) (1U << (n))
-#define PIN_OTYPE_PUSHPULL(n) (0U << (n))
-#define PIN_OTYPE_OPENDRAIN(n) (1U << (n))
-#define PIN_OSPEED_VERYLOW(n) (0U << ((n)*2U))
-#define PIN_OSPEED_LOW(n) (1U << ((n)*2U))
-#define PIN_OSPEED_MEDIUM(n) (2U << ((n)*2U))
-#define PIN_OSPEED_HIGH(n) (3U << ((n)*2U))
-#define PIN_PUPDR_FLOATING(n) (0U << ((n)*2U))
-#define PIN_PUPDR_PULLUP(n) (1U << ((n)*2U))
-#define PIN_PUPDR_PULLDOWN(n) (2U << ((n)*2U))
-#define PIN_AFIO_AF(n, v) ((v) << (((n) % 8U) * 4U))
-
-/*
- * GPIOA setup:
- *
- * PA0 - BUTTON (input floating).
- * PA1 - PIN1 (input pullup).
- * PA2 - PIN2 (input pullup).
- * PA3 - PIN3 (input pullup).
- * PA4 - PIN4 (input pullup).
- * PA5 - PIN5 (input pullup).
- * PA6 - PIN6 (input pullup).
- * PA7 - PIN7 (input pullup).
- * PA8 - PIN8 (input pullup).
- * PA9 - PIN9 (input pullup).
- * PA10 - PIN10 (input pullup).
- * PA11 - USB_DM (input floating).
- * PA12 - USB_DP (input floating).
- * PA13 - SWDIO (alternate 0).
- * PA14 - SWCLK (alternate 0).
- * PA15 - PIN15 (input pullup).
- */
-#define VAL_GPIOA_MODER (PIN_MODE_INPUT(GPIOA_BUTTON) | PIN_MODE_INPUT(GPIOA_PIN1) | PIN_MODE_INPUT(GPIOA_PIN2) | PIN_MODE_INPUT(GPIOA_PIN3) | PIN_MODE_INPUT(GPIOA_PIN4) | PIN_MODE_INPUT(GPIOA_PIN5) | PIN_MODE_INPUT(GPIOA_PIN6) | PIN_MODE_INPUT(GPIOA_PIN7) | PIN_MODE_INPUT(GPIOA_PIN8) | PIN_MODE_INPUT(GPIOA_PIN9) | PIN_MODE_INPUT(GPIOA_PIN10) | PIN_MODE_INPUT(GPIOA_USB_DM) | PIN_MODE_INPUT(GPIOA_USB_DP) | PIN_MODE_ALTERNATE(GPIOA_SWDIO) | PIN_MODE_ALTERNATE(GPIOA_SWCLK) | PIN_MODE_INPUT(GPIOA_PIN15))
-#define VAL_GPIOA_OTYPER (PIN_OTYPE_PUSHPULL(GPIOA_BUTTON) | PIN_OTYPE_PUSHPULL(GPIOA_PIN1) | PIN_OTYPE_PUSHPULL(GPIOA_PIN2) | PIN_OTYPE_PUSHPULL(GPIOA_PIN3) | PIN_OTYPE_PUSHPULL(GPIOA_PIN4) | PIN_OTYPE_PUSHPULL(GPIOA_PIN5) | PIN_OTYPE_PUSHPULL(GPIOA_PIN6) | PIN_OTYPE_PUSHPULL(GPIOA_PIN7) | PIN_OTYPE_PUSHPULL(GPIOA_PIN8) | PIN_OTYPE_PUSHPULL(GPIOA_PIN9) | PIN_OTYPE_PUSHPULL(GPIOA_PIN10) | PIN_OTYPE_PUSHPULL(GPIOA_USB_DM) | PIN_OTYPE_PUSHPULL(GPIOA_USB_DP) | PIN_OTYPE_PUSHPULL(GPIOA_SWDIO) | PIN_OTYPE_PUSHPULL(GPIOA_SWCLK) | PIN_OTYPE_PUSHPULL(GPIOA_PIN15))
-#define VAL_GPIOA_OSPEEDR (PIN_OSPEED_VERYLOW(GPIOA_BUTTON) | PIN_OSPEED_VERYLOW(GPIOA_PIN1) | PIN_OSPEED_VERYLOW(GPIOA_PIN2) | PIN_OSPEED_VERYLOW(GPIOA_PIN3) | PIN_OSPEED_VERYLOW(GPIOA_PIN4) | PIN_OSPEED_VERYLOW(GPIOA_PIN5) | PIN_OSPEED_VERYLOW(GPIOA_PIN6) | PIN_OSPEED_VERYLOW(GPIOA_PIN7) | PIN_OSPEED_VERYLOW(GPIOA_PIN8) | PIN_OSPEED_VERYLOW(GPIOA_PIN9) | PIN_OSPEED_VERYLOW(GPIOA_PIN10) | PIN_OSPEED_VERYLOW(GPIOA_USB_DM) | PIN_OSPEED_VERYLOW(GPIOA_USB_DP) | PIN_OSPEED_HIGH(GPIOA_SWDIO) | PIN_OSPEED_HIGH(GPIOA_SWCLK) | PIN_OSPEED_HIGH(GPIOA_PIN15))
-#define VAL_GPIOA_PUPDR (PIN_PUPDR_FLOATING(GPIOA_BUTTON) | PIN_PUPDR_PULLUP(GPIOA_PIN1) | PIN_PUPDR_PULLUP(GPIOA_PIN2) | PIN_PUPDR_PULLUP(GPIOA_PIN3) | PIN_PUPDR_PULLUP(GPIOA_PIN4) | PIN_PUPDR_PULLUP(GPIOA_PIN5) | PIN_PUPDR_PULLUP(GPIOA_PIN6) | PIN_PUPDR_PULLUP(GPIOA_PIN7) | PIN_PUPDR_PULLUP(GPIOA_PIN8) | PIN_PUPDR_PULLUP(GPIOA_PIN9) | PIN_PUPDR_PULLUP(GPIOA_PIN10) | PIN_PUPDR_FLOATING(GPIOA_USB_DM) | PIN_PUPDR_FLOATING(GPIOA_USB_DP) | PIN_PUPDR_PULLUP(GPIOA_SWDIO) | PIN_PUPDR_PULLDOWN(GPIOA_SWCLK) | PIN_PUPDR_PULLUP(GPIOA_PIN15))
-#define VAL_GPIOA_ODR (PIN_ODR_HIGH(GPIOA_BUTTON) | PIN_ODR_HIGH(GPIOA_PIN1) | PIN_ODR_HIGH(GPIOA_PIN2) | PIN_ODR_HIGH(GPIOA_PIN3) | PIN_ODR_HIGH(GPIOA_PIN4) | PIN_ODR_HIGH(GPIOA_PIN5) | PIN_ODR_HIGH(GPIOA_PIN6) | PIN_ODR_HIGH(GPIOA_PIN7) | PIN_ODR_HIGH(GPIOA_PIN8) | PIN_ODR_HIGH(GPIOA_PIN9) | PIN_ODR_HIGH(GPIOA_PIN10) | PIN_ODR_HIGH(GPIOA_USB_DM) | PIN_ODR_HIGH(GPIOA_USB_DP) | PIN_ODR_HIGH(GPIOA_SWDIO) | PIN_ODR_HIGH(GPIOA_SWCLK) | PIN_ODR_HIGH(GPIOA_PIN15))
-#define VAL_GPIOA_AFRL (PIN_AFIO_AF(GPIOA_BUTTON, 0U) | PIN_AFIO_AF(GPIOA_PIN1, 0U) | PIN_AFIO_AF(GPIOA_PIN2, 0U) | PIN_AFIO_AF(GPIOA_PIN3, 0U) | PIN_AFIO_AF(GPIOA_PIN4, 0U) | PIN_AFIO_AF(GPIOA_PIN5, 0U) | PIN_AFIO_AF(GPIOA_PIN6, 0U) | PIN_AFIO_AF(GPIOA_PIN7, 0U))
-#define VAL_GPIOA_AFRH (PIN_AFIO_AF(GPIOA_PIN8, 0U) | PIN_AFIO_AF(GPIOA_PIN9, 0U) | PIN_AFIO_AF(GPIOA_PIN10, 0U) | PIN_AFIO_AF(GPIOA_USB_DM, 0U) | PIN_AFIO_AF(GPIOA_USB_DP, 0U) | PIN_AFIO_AF(GPIOA_SWDIO, 0U) | PIN_AFIO_AF(GPIOA_SWCLK, 0U) | PIN_AFIO_AF(GPIOA_PIN15, 0U))
-
-/*
- * GPIOB setup:
- *
- * PB0 - PIN0 (input pullup).
- * PB1 - PIN1 (input pullup).
- * PB2 - PIN2 (input pullup).
- * PB3 - PIN3 (input pullup).
- * PB4 - PIN4 (input pullup).
- * PB5 - PIN5 (input pullup).
- * PB6 - PIN6 (input pullup).
- * PB7 - PIN7 (input pullup).
- * PB8 - PIN8 (input pullup).
- * PB9 - PIN9 (input pullup).
- * PB10 - PIN10 (input pullup).
- * PB11 - PIN11 (input pullup).
- * PB12 - PIN12 (input pullup).
- * PB13 - SPI2_SCK (alternate 0).
- * PB14 - SPI2_MISO (alternate 0).
- * PB15 - SPI2_MOSI (alternate 0).
- */
-#define VAL_GPIOB_MODER (PIN_MODE_INPUT(GPIOB_PIN0) | PIN_MODE_INPUT(GPIOB_PIN1) | PIN_MODE_INPUT(GPIOB_PIN2) | PIN_MODE_INPUT(GPIOB_PIN3) | PIN_MODE_INPUT(GPIOB_PIN4) | PIN_MODE_INPUT(GPIOB_PIN5) | PIN_MODE_INPUT(GPIOB_PIN6) | PIN_MODE_INPUT(GPIOB_PIN7) | PIN_MODE_INPUT(GPIOB_PIN8) | PIN_MODE_INPUT(GPIOB_PIN9) | PIN_MODE_INPUT(GPIOB_PIN10) | PIN_MODE_INPUT(GPIOB_PIN11) | PIN_MODE_INPUT(GPIOB_PIN12) | PIN_MODE_ALTERNATE(GPIOB_SPI2_SCK) | PIN_MODE_ALTERNATE(GPIOB_SPI2_MISO) | PIN_MODE_ALTERNATE(GPIOB_SPI2_MOSI))
-#define VAL_GPIOB_OTYPER (PIN_OTYPE_PUSHPULL(GPIOB_PIN0) | PIN_OTYPE_PUSHPULL(GPIOB_PIN1) | PIN_OTYPE_PUSHPULL(GPIOB_PIN2) | PIN_OTYPE_PUSHPULL(GPIOB_PIN3) | PIN_OTYPE_PUSHPULL(GPIOB_PIN4) | PIN_OTYPE_PUSHPULL(GPIOB_PIN5) | PIN_OTYPE_PUSHPULL(GPIOB_PIN6) | PIN_OTYPE_PUSHPULL(GPIOB_PIN7) | PIN_OTYPE_PUSHPULL(GPIOB_PIN8) | PIN_OTYPE_PUSHPULL(GPIOB_PIN9) | PIN_OTYPE_PUSHPULL(GPIOB_PIN10) | PIN_OTYPE_PUSHPULL(GPIOB_PIN11) | PIN_OTYPE_PUSHPULL(GPIOB_PIN12) | PIN_OTYPE_PUSHPULL(GPIOB_SPI2_SCK) | PIN_OTYPE_PUSHPULL(GPIOB_SPI2_MISO) | PIN_OTYPE_PUSHPULL(GPIOB_SPI2_MOSI))
-#define VAL_GPIOB_OSPEEDR (PIN_OSPEED_VERYLOW(GPIOB_PIN0) | PIN_OSPEED_VERYLOW(GPIOB_PIN1) | PIN_OSPEED_HIGH(GPIOB_PIN2) | PIN_OSPEED_HIGH(GPIOB_PIN3) | PIN_OSPEED_HIGH(GPIOB_PIN4) | PIN_OSPEED_VERYLOW(GPIOB_PIN5) | PIN_OSPEED_VERYLOW(GPIOB_PIN6) | PIN_OSPEED_VERYLOW(GPIOB_PIN7) | PIN_OSPEED_VERYLOW(GPIOB_PIN8) | PIN_OSPEED_VERYLOW(GPIOB_PIN9) | PIN_OSPEED_VERYLOW(GPIOB_PIN10) | PIN_OSPEED_VERYLOW(GPIOB_PIN11) | PIN_OSPEED_VERYLOW(GPIOB_PIN12) | PIN_OSPEED_VERYLOW(GPIOB_SPI2_SCK) | PIN_OSPEED_VERYLOW(GPIOB_SPI2_MISO) | PIN_OSPEED_VERYLOW(GPIOB_SPI2_MOSI))
-#define VAL_GPIOB_PUPDR (PIN_PUPDR_PULLUP(GPIOB_PIN0) | PIN_PUPDR_PULLUP(GPIOB_PIN1) | PIN_PUPDR_PULLUP(GPIOB_PIN2) | PIN_PUPDR_PULLUP(GPIOB_PIN3) | PIN_PUPDR_PULLUP(GPIOB_PIN4) | PIN_PUPDR_PULLUP(GPIOB_PIN5) | PIN_PUPDR_PULLUP(GPIOB_PIN6) | PIN_PUPDR_PULLUP(GPIOB_PIN7) | PIN_PUPDR_PULLUP(GPIOB_PIN8) | PIN_PUPDR_PULLUP(GPIOB_PIN9) | PIN_PUPDR_PULLUP(GPIOB_PIN10) | PIN_PUPDR_PULLUP(GPIOB_PIN11) | PIN_PUPDR_PULLUP(GPIOB_PIN12) | PIN_PUPDR_FLOATING(GPIOB_SPI2_SCK) | PIN_PUPDR_FLOATING(GPIOB_SPI2_MISO) | PIN_PUPDR_FLOATING(GPIOB_SPI2_MOSI))
-#define VAL_GPIOB_ODR (PIN_ODR_HIGH(GPIOB_PIN0) | PIN_ODR_HIGH(GPIOB_PIN1) | PIN_ODR_HIGH(GPIOB_PIN2) | PIN_ODR_HIGH(GPIOB_PIN3) | PIN_ODR_HIGH(GPIOB_PIN4) | PIN_ODR_HIGH(GPIOB_PIN5) | PIN_ODR_HIGH(GPIOB_PIN6) | PIN_ODR_HIGH(GPIOB_PIN7) | PIN_ODR_HIGH(GPIOB_PIN8) | PIN_ODR_HIGH(GPIOB_PIN9) | PIN_ODR_HIGH(GPIOB_PIN10) | PIN_ODR_HIGH(GPIOB_PIN11) | PIN_ODR_HIGH(GPIOB_PIN12) | PIN_ODR_HIGH(GPIOB_SPI2_SCK) | PIN_ODR_HIGH(GPIOB_SPI2_MISO) | PIN_ODR_HIGH(GPIOB_SPI2_MOSI))
-#define VAL_GPIOB_AFRL (PIN_AFIO_AF(GPIOB_PIN0, 0U) | PIN_AFIO_AF(GPIOB_PIN1, 0U) | PIN_AFIO_AF(GPIOB_PIN2, 0U) | PIN_AFIO_AF(GPIOB_PIN3, 0U) | PIN_AFIO_AF(GPIOB_PIN4, 0U) | PIN_AFIO_AF(GPIOB_PIN5, 0U) | PIN_AFIO_AF(GPIOB_PIN6, 0U) | PIN_AFIO_AF(GPIOB_PIN7, 0U))
-#define VAL_GPIOB_AFRH (PIN_AFIO_AF(GPIOB_PIN8, 0U) | PIN_AFIO_AF(GPIOB_PIN9, 0U) | PIN_AFIO_AF(GPIOB_PIN10, 0U) | PIN_AFIO_AF(GPIOB_PIN11, 0U) | PIN_AFIO_AF(GPIOB_PIN12, 0U) | PIN_AFIO_AF(GPIOB_SPI2_SCK, 0U) | PIN_AFIO_AF(GPIOB_SPI2_MISO, 0U) | PIN_AFIO_AF(GPIOB_SPI2_MOSI, 0U))
-
-/*
- * GPIOC setup:
- *
- * PC0 - MEMS_CS (output pushpull maximum).
- * PC1 - PIN1 (input pullup).
- * PC2 - PIN2 (input pullup).
- * PC3 - PIN3 (input pullup).
- * PC4 - PIN4 (input pullup).
- * PC5 - PIN5 (input pullup).
- * PC6 - LED_RED (output pushpull maximum).
- * PC7 - LED_BLUE (output pushpull maximum).
- * PC8 - LED_ORANGE (output pushpull maximum).
- * PC9 - LED_GREEN (output pushpull maximum).
- * PC10 - PIN10 (input pullup).
- * PC11 - PIN11 (input pullup).
- * PC12 - PIN12 (input pullup).
- * PC13 - PIN13 (input pullup).
- * PC14 - OSC32_IN (input floating).
- * PC15 - OSC32_OUT (input floating).
- */
-#define VAL_GPIOC_MODER (PIN_MODE_OUTPUT(GPIOC_MEMS_CS) | PIN_MODE_INPUT(GPIOC_PIN1) | PIN_MODE_INPUT(GPIOC_PIN2) | PIN_MODE_INPUT(GPIOC_PIN3) | PIN_MODE_INPUT(GPIOC_PIN4) | PIN_MODE_INPUT(GPIOC_PIN5) | PIN_MODE_OUTPUT(GPIOC_LED_RED) | PIN_MODE_OUTPUT(GPIOC_LED_BLUE) | PIN_MODE_OUTPUT(GPIOC_LED_ORANGE) | PIN_MODE_OUTPUT(GPIOC_LED_GREEN) | PIN_MODE_INPUT(GPIOC_PIN10) | PIN_MODE_INPUT(GPIOC_PIN11) | PIN_MODE_INPUT(GPIOC_PIN12) | PIN_MODE_INPUT(GPIOC_PIN13) | PIN_MODE_INPUT(GPIOC_OSC32_IN) | PIN_MODE_INPUT(GPIOC_OSC32_OUT))
-#define VAL_GPIOC_OTYPER (PIN_OTYPE_PUSHPULL(GPIOC_MEMS_CS) | PIN_OTYPE_PUSHPULL(GPIOC_PIN1) | PIN_OTYPE_PUSHPULL(GPIOC_PIN2) | PIN_OTYPE_PUSHPULL(GPIOC_PIN3) | PIN_OTYPE_PUSHPULL(GPIOC_PIN4) | PIN_OTYPE_PUSHPULL(GPIOC_PIN5) | PIN_OTYPE_PUSHPULL(GPIOC_LED_RED) | PIN_OTYPE_PUSHPULL(GPIOC_LED_BLUE) | PIN_OTYPE_PUSHPULL(GPIOC_LED_ORANGE) | PIN_OTYPE_PUSHPULL(GPIOC_LED_GREEN) | PIN_OTYPE_PUSHPULL(GPIOC_PIN10) | PIN_OTYPE_PUSHPULL(GPIOC_PIN11) | PIN_OTYPE_PUSHPULL(GPIOC_PIN12) | PIN_OTYPE_PUSHPULL(GPIOC_PIN13) | PIN_OTYPE_PUSHPULL(GPIOC_OSC32_IN) | PIN_OTYPE_PUSHPULL(GPIOC_OSC32_OUT))
-#define VAL_GPIOC_OSPEEDR (PIN_OSPEED_HIGH(GPIOC_MEMS_CS) | PIN_OSPEED_VERYLOW(GPIOC_PIN1) | PIN_OSPEED_VERYLOW(GPIOC_PIN2) | PIN_OSPEED_VERYLOW(GPIOC_PIN3) | PIN_OSPEED_VERYLOW(GPIOC_PIN4) | PIN_OSPEED_VERYLOW(GPIOC_PIN5) | PIN_OSPEED_HIGH(GPIOC_LED_RED) | PIN_OSPEED_HIGH(GPIOC_LED_BLUE) | PIN_OSPEED_HIGH(GPIOC_LED_ORANGE) | PIN_OSPEED_HIGH(GPIOC_LED_GREEN) | PIN_OSPEED_VERYLOW(GPIOC_PIN10) | PIN_OSPEED_VERYLOW(GPIOC_PIN11) | PIN_OSPEED_VERYLOW(GPIOC_PIN12) | PIN_OSPEED_VERYLOW(GPIOC_PIN13) | PIN_OSPEED_HIGH(GPIOC_OSC32_IN) | PIN_OSPEED_HIGH(GPIOC_OSC32_OUT))
-#define VAL_GPIOC_PUPDR (PIN_PUPDR_FLOATING(GPIOC_MEMS_CS) | PIN_PUPDR_PULLUP(GPIOC_PIN1) | PIN_PUPDR_PULLUP(GPIOC_PIN2) | PIN_PUPDR_PULLUP(GPIOC_PIN3) | PIN_PUPDR_PULLUP(GPIOC_PIN4) | PIN_PUPDR_PULLUP(GPIOC_PIN5) | PIN_PUPDR_FLOATING(GPIOC_LED_RED) | PIN_PUPDR_FLOATING(GPIOC_LED_BLUE) | PIN_PUPDR_FLOATING(GPIOC_LED_ORANGE) | PIN_PUPDR_FLOATING(GPIOC_LED_GREEN) | PIN_PUPDR_PULLUP(GPIOC_PIN10) | PIN_PUPDR_PULLUP(GPIOC_PIN11) | PIN_PUPDR_PULLUP(GPIOC_PIN12) | PIN_PUPDR_PULLUP(GPIOC_PIN13) | PIN_PUPDR_FLOATING(GPIOC_OSC32_IN) | PIN_PUPDR_FLOATING(GPIOC_OSC32_OUT))
-#define VAL_GPIOC_ODR (PIN_ODR_HIGH(GPIOC_MEMS_CS) | PIN_ODR_HIGH(GPIOC_PIN1) | PIN_ODR_HIGH(GPIOC_PIN2) | PIN_ODR_HIGH(GPIOC_PIN3) | PIN_ODR_HIGH(GPIOC_PIN4) | PIN_ODR_HIGH(GPIOC_PIN5) | PIN_ODR_LOW(GPIOC_LED_RED) | PIN_ODR_LOW(GPIOC_LED_BLUE) | PIN_ODR_LOW(GPIOC_LED_ORANGE) | PIN_ODR_LOW(GPIOC_LED_GREEN) | PIN_ODR_HIGH(GPIOC_PIN10) | PIN_ODR_HIGH(GPIOC_PIN11) | PIN_ODR_HIGH(GPIOC_PIN12) | PIN_ODR_HIGH(GPIOC_PIN13) | PIN_ODR_HIGH(GPIOC_OSC32_IN) | PIN_ODR_HIGH(GPIOC_OSC32_OUT))
-#define VAL_GPIOC_AFRL (PIN_AFIO_AF(GPIOC_MEMS_CS, 0U) | PIN_AFIO_AF(GPIOC_PIN1, 0U) | PIN_AFIO_AF(GPIOC_PIN2, 0U) | PIN_AFIO_AF(GPIOC_PIN3, 0U) | PIN_AFIO_AF(GPIOC_PIN4, 0U) | PIN_AFIO_AF(GPIOC_PIN5, 0U) | PIN_AFIO_AF(GPIOC_LED_RED, 0U) | PIN_AFIO_AF(GPIOC_LED_BLUE, 0U))
-#define VAL_GPIOC_AFRH (PIN_AFIO_AF(GPIOC_LED_ORANGE, 0U) | PIN_AFIO_AF(GPIOC_LED_GREEN, 0U) | PIN_AFIO_AF(GPIOC_PIN10, 0U) | PIN_AFIO_AF(GPIOC_PIN11, 0U) | PIN_AFIO_AF(GPIOC_PIN12, 0U) | PIN_AFIO_AF(GPIOC_PIN13, 0U) | PIN_AFIO_AF(GPIOC_OSC32_IN, 0U) | PIN_AFIO_AF(GPIOC_OSC32_OUT, 0U))
-
-/*
- * GPIOD setup:
- *
- * PD0 - PIN0 (input pullup).
- * PD1 - PIN1 (input pullup).
- * PD2 - PIN2 (input pullup).
- * PD3 - PIN3 (input pullup).
- * PD4 - PIN4 (input pullup).
- * PD5 - PIN5 (input pullup).
- * PD6 - PIN6 (input pullup).
- * PD7 - PIN7 (input pullup).
- * PD8 - PIN8 (input pullup).
- * PD9 - PIN9 (input pullup).
- * PD10 - PIN10 (input pullup).
- * PD11 - PIN11 (input pullup).
- * PD12 - PIN12 (input pullup).
- * PD13 - PIN13 (input pullup).
- * PD14 - PIN14 (input pullup).
- * PD15 - PIN15 (input pullup).
- */
-#define VAL_GPIOD_MODER (PIN_MODE_INPUT(GPIOD_PIN0) | PIN_MODE_INPUT(GPIOD_PIN1) | PIN_MODE_INPUT(GPIOD_PIN2) | PIN_MODE_INPUT(GPIOD_PIN3) | PIN_MODE_INPUT(GPIOD_PIN4) | PIN_MODE_INPUT(GPIOD_PIN5) | PIN_MODE_INPUT(GPIOD_PIN6) | PIN_MODE_INPUT(GPIOD_PIN7) | PIN_MODE_INPUT(GPIOD_PIN8) | PIN_MODE_INPUT(GPIOD_PIN9) | PIN_MODE_INPUT(GPIOD_PIN10) | PIN_MODE_INPUT(GPIOD_PIN11) | PIN_MODE_INPUT(GPIOD_PIN12) | PIN_MODE_INPUT(GPIOD_PIN13) | PIN_MODE_INPUT(GPIOD_PIN14) | PIN_MODE_INPUT(GPIOD_PIN15))
-#define VAL_GPIOD_OTYPER (PIN_OTYPE_PUSHPULL(GPIOD_PIN0) | PIN_OTYPE_PUSHPULL(GPIOD_PIN1) | PIN_OTYPE_PUSHPULL(GPIOD_PIN2) | PIN_OTYPE_PUSHPULL(GPIOD_PIN3) | PIN_OTYPE_PUSHPULL(GPIOD_PIN4) | PIN_OTYPE_PUSHPULL(GPIOD_PIN5) | PIN_OTYPE_PUSHPULL(GPIOD_PIN6) | PIN_OTYPE_PUSHPULL(GPIOD_PIN7) | PIN_OTYPE_PUSHPULL(GPIOD_PIN8) | PIN_OTYPE_PUSHPULL(GPIOD_PIN9) | PIN_OTYPE_PUSHPULL(GPIOD_PIN10) | PIN_OTYPE_PUSHPULL(GPIOD_PIN11) | PIN_OTYPE_PUSHPULL(GPIOD_PIN12) | PIN_OTYPE_PUSHPULL(GPIOD_PIN13) | PIN_OTYPE_PUSHPULL(GPIOD_PIN14) | PIN_OTYPE_PUSHPULL(GPIOD_PIN15))
-#define VAL_GPIOD_OSPEEDR (PIN_OSPEED_VERYLOW(GPIOD_PIN0) | PIN_OSPEED_VERYLOW(GPIOD_PIN1) | PIN_OSPEED_VERYLOW(GPIOD_PIN2) | PIN_OSPEED_VERYLOW(GPIOD_PIN3) | PIN_OSPEED_VERYLOW(GPIOD_PIN4) | PIN_OSPEED_VERYLOW(GPIOD_PIN5) | PIN_OSPEED_VERYLOW(GPIOD_PIN6) | PIN_OSPEED_VERYLOW(GPIOD_PIN7) | PIN_OSPEED_VERYLOW(GPIOD_PIN8) | PIN_OSPEED_VERYLOW(GPIOD_PIN9) | PIN_OSPEED_VERYLOW(GPIOD_PIN10) | PIN_OSPEED_VERYLOW(GPIOD_PIN11) | PIN_OSPEED_VERYLOW(GPIOD_PIN12) | PIN_OSPEED_VERYLOW(GPIOD_PIN13) | PIN_OSPEED_VERYLOW(GPIOD_PIN14) | PIN_OSPEED_VERYLOW(GPIOD_PIN15))
-#define VAL_GPIOD_PUPDR (PIN_PUPDR_PULLUP(GPIOD_PIN0) | PIN_PUPDR_PULLUP(GPIOD_PIN1) | PIN_PUPDR_PULLUP(GPIOD_PIN2) | PIN_PUPDR_PULLUP(GPIOD_PIN3) | PIN_PUPDR_PULLUP(GPIOD_PIN4) | PIN_PUPDR_PULLUP(GPIOD_PIN5) | PIN_PUPDR_PULLUP(GPIOD_PIN6) | PIN_PUPDR_PULLUP(GPIOD_PIN7) | PIN_PUPDR_PULLUP(GPIOD_PIN8) | PIN_PUPDR_PULLUP(GPIOD_PIN9) | PIN_PUPDR_PULLUP(GPIOD_PIN10) | PIN_PUPDR_PULLUP(GPIOD_PIN11) | PIN_PUPDR_PULLUP(GPIOD_PIN12) | PIN_PUPDR_PULLUP(GPIOD_PIN13) | PIN_PUPDR_PULLUP(GPIOD_PIN14) | PIN_PUPDR_PULLUP(GPIOD_PIN15))
-#define VAL_GPIOD_ODR (PIN_ODR_HIGH(GPIOD_PIN0) | PIN_ODR_HIGH(GPIOD_PIN1) | PIN_ODR_HIGH(GPIOD_PIN2) | PIN_ODR_HIGH(GPIOD_PIN3) | PIN_ODR_HIGH(GPIOD_PIN4) | PIN_ODR_HIGH(GPIOD_PIN5) | PIN_ODR_HIGH(GPIOD_PIN6) | PIN_ODR_HIGH(GPIOD_PIN7) | PIN_ODR_HIGH(GPIOD_PIN8) | PIN_ODR_HIGH(GPIOD_PIN9) | PIN_ODR_HIGH(GPIOD_PIN10) | PIN_ODR_HIGH(GPIOD_PIN11) | PIN_ODR_HIGH(GPIOD_PIN12) | PIN_ODR_HIGH(GPIOD_PIN13) | PIN_ODR_HIGH(GPIOD_PIN14) | PIN_ODR_HIGH(GPIOD_PIN15))
-#define VAL_GPIOD_AFRL (PIN_AFIO_AF(GPIOD_PIN0, 0U) | PIN_AFIO_AF(GPIOD_PIN1, 0U) | PIN_AFIO_AF(GPIOD_PIN2, 0U) | PIN_AFIO_AF(GPIOD_PIN3, 0U) | PIN_AFIO_AF(GPIOD_PIN4, 0U) | PIN_AFIO_AF(GPIOD_PIN5, 0U) | PIN_AFIO_AF(GPIOD_PIN6, 0U) | PIN_AFIO_AF(GPIOD_PIN7, 0U))
-#define VAL_GPIOD_AFRH (PIN_AFIO_AF(GPIOD_PIN8, 0U) | PIN_AFIO_AF(GPIOD_PIN9, 0U) | PIN_AFIO_AF(GPIOD_PIN10, 0U) | PIN_AFIO_AF(GPIOD_PIN11, 0U) | PIN_AFIO_AF(GPIOD_PIN12, 0U) | PIN_AFIO_AF(GPIOD_PIN13, 0U) | PIN_AFIO_AF(GPIOD_PIN14, 0U) | PIN_AFIO_AF(GPIOD_PIN15, 0U))
-
-/*
- * GPIOE setup:
- *
- * PE0 - PIN0 (input pullup).
- * PE1 - PIN1 (input pullup).
- * PE2 - PIN2 (input pullup).
- * PE3 - PIN3 (input pullup).
- * PE4 - PIN4 (input pullup).
- * PE5 - PIN5 (input pullup).
- * PE6 - PIN6 (input pullup).
- * PE7 - PIN7 (input pullup).
- * PE8 - PIN8 (input pullup).
- * PE9 - PIN9 (input pullup).
- * PE10 - PIN10 (input pullup).
- * PE11 - PIN11 (input pullup).
- * PE12 - PIN12 (input pullup).
- * PE13 - PIN13 (input pullup).
- * PE14 - PIN14 (input pullup).
- * PE15 - PIN15 (input pullup).
- */
-#define VAL_GPIOE_MODER (PIN_MODE_INPUT(GPIOE_PIN0) | PIN_MODE_INPUT(GPIOE_PIN1) | PIN_MODE_INPUT(GPIOE_PIN2) | PIN_MODE_INPUT(GPIOE_PIN3) | PIN_MODE_INPUT(GPIOE_PIN4) | PIN_MODE_INPUT(GPIOE_PIN5) | PIN_MODE_INPUT(GPIOE_PIN6) | PIN_MODE_INPUT(GPIOE_PIN7) | PIN_MODE_INPUT(GPIOE_PIN8) | PIN_MODE_INPUT(GPIOE_PIN9) | PIN_MODE_INPUT(GPIOE_PIN10) | PIN_MODE_INPUT(GPIOE_PIN11) | PIN_MODE_INPUT(GPIOE_PIN12) | PIN_MODE_INPUT(GPIOE_PIN13) | PIN_MODE_INPUT(GPIOE_PIN14) | PIN_MODE_INPUT(GPIOE_PIN15))
-#define VAL_GPIOE_OTYPER (PIN_OTYPE_PUSHPULL(GPIOE_PIN0) | PIN_OTYPE_PUSHPULL(GPIOE_PIN1) | PIN_OTYPE_PUSHPULL(GPIOE_PIN2) | PIN_OTYPE_PUSHPULL(GPIOE_PIN3) | PIN_OTYPE_PUSHPULL(GPIOE_PIN4) | PIN_OTYPE_PUSHPULL(GPIOE_PIN5) | PIN_OTYPE_PUSHPULL(GPIOE_PIN6) | PIN_OTYPE_PUSHPULL(GPIOE_PIN7) | PIN_OTYPE_PUSHPULL(GPIOE_PIN8) | PIN_OTYPE_PUSHPULL(GPIOE_PIN9) | PIN_OTYPE_PUSHPULL(GPIOE_PIN10) | PIN_OTYPE_PUSHPULL(GPIOE_PIN11) | PIN_OTYPE_PUSHPULL(GPIOE_PIN12) | PIN_OTYPE_PUSHPULL(GPIOE_PIN13) | PIN_OTYPE_PUSHPULL(GPIOE_PIN14) | PIN_OTYPE_PUSHPULL(GPIOE_PIN15))
-#define VAL_GPIOE_OSPEEDR (PIN_OSPEED_VERYLOW(GPIOE_PIN0) | PIN_OSPEED_VERYLOW(GPIOE_PIN1) | PIN_OSPEED_VERYLOW(GPIOE_PIN2) | PIN_OSPEED_VERYLOW(GPIOE_PIN3) | PIN_OSPEED_VERYLOW(GPIOE_PIN4) | PIN_OSPEED_VERYLOW(GPIOE_PIN5) | PIN_OSPEED_VERYLOW(GPIOE_PIN6) | PIN_OSPEED_VERYLOW(GPIOE_PIN7) | PIN_OSPEED_VERYLOW(GPIOE_PIN8) | PIN_OSPEED_VERYLOW(GPIOE_PIN9) | PIN_OSPEED_VERYLOW(GPIOE_PIN10) | PIN_OSPEED_VERYLOW(GPIOE_PIN11) | PIN_OSPEED_VERYLOW(GPIOE_PIN12) | PIN_OSPEED_VERYLOW(GPIOE_PIN13) | PIN_OSPEED_VERYLOW(GPIOE_PIN14) | PIN_OSPEED_VERYLOW(GPIOE_PIN15))
-#define VAL_GPIOE_PUPDR (PIN_PUPDR_PULLUP(GPIOE_PIN0) | PIN_PUPDR_PULLUP(GPIOE_PIN1) | PIN_PUPDR_PULLUP(GPIOE_PIN2) | PIN_PUPDR_PULLUP(GPIOE_PIN3) | PIN_PUPDR_PULLUP(GPIOE_PIN4) | PIN_PUPDR_PULLUP(GPIOE_PIN5) | PIN_PUPDR_PULLUP(GPIOE_PIN6) | PIN_PUPDR_PULLUP(GPIOE_PIN7) | PIN_PUPDR_PULLUP(GPIOE_PIN8) | PIN_PUPDR_PULLUP(GPIOE_PIN9) | PIN_PUPDR_PULLUP(GPIOE_PIN10) | PIN_PUPDR_PULLUP(GPIOE_PIN11) | PIN_PUPDR_PULLUP(GPIOE_PIN12) | PIN_PUPDR_PULLUP(GPIOE_PIN13) | PIN_PUPDR_PULLUP(GPIOE_PIN14) | PIN_PUPDR_PULLUP(GPIOE_PIN15))
-#define VAL_GPIOE_ODR (PIN_ODR_HIGH(GPIOE_PIN0) | PIN_ODR_HIGH(GPIOE_PIN1) | PIN_ODR_HIGH(GPIOE_PIN2) | PIN_ODR_HIGH(GPIOE_PIN3) | PIN_ODR_HIGH(GPIOE_PIN4) | PIN_ODR_HIGH(GPIOE_PIN5) | PIN_ODR_HIGH(GPIOE_PIN6) | PIN_ODR_HIGH(GPIOE_PIN7) | PIN_ODR_HIGH(GPIOE_PIN8) | PIN_ODR_HIGH(GPIOE_PIN9) | PIN_ODR_HIGH(GPIOE_PIN10) | PIN_ODR_HIGH(GPIOE_PIN11) | PIN_ODR_HIGH(GPIOE_PIN12) | PIN_ODR_HIGH(GPIOE_PIN13) | PIN_ODR_HIGH(GPIOE_PIN14) | PIN_ODR_HIGH(GPIOE_PIN15))
-#define VAL_GPIOE_AFRL (PIN_AFIO_AF(GPIOE_PIN0, 0U) | PIN_AFIO_AF(GPIOE_PIN1, 0U) | PIN_AFIO_AF(GPIOE_PIN2, 0U) | PIN_AFIO_AF(GPIOE_PIN3, 0U) | PIN_AFIO_AF(GPIOE_PIN4, 0U) | PIN_AFIO_AF(GPIOE_PIN5, 0U) | PIN_AFIO_AF(GPIOE_PIN6, 0U) | PIN_AFIO_AF(GPIOE_PIN7, 0U))
-#define VAL_GPIOE_AFRH (PIN_AFIO_AF(GPIOE_PIN8, 0U) | PIN_AFIO_AF(GPIOE_PIN9, 0U) | PIN_AFIO_AF(GPIOE_PIN10, 0U) | PIN_AFIO_AF(GPIOE_PIN11, 0U) | PIN_AFIO_AF(GPIOE_PIN12, 0U) | PIN_AFIO_AF(GPIOE_PIN13, 0U) | PIN_AFIO_AF(GPIOE_PIN14, 0U) | PIN_AFIO_AF(GPIOE_PIN15, 0U))
-
-/*
- * GPIOF setup:
- *
- * PF0 - OSC_IN (input floating).
- * PF1 - OSC_OUT (input floating).
- * PF2 - PIN2 (input pullup).
- * PF3 - PIN3 (input pullup).
- * PF4 - PIN4 (input pullup).
- * PF5 - PIN5 (input pullup).
- * PF6 - PIN6 (input pullup).
- * PF7 - PIN7 (input pullup).
- * PF8 - PIN8 (input pullup).
- * PF9 - PIN9 (input pullup).
- * PF10 - PIN10 (input pullup).
- * PF11 - PIN11 (input pullup).
- * PF12 - PIN12 (input pullup).
- * PF13 - PIN13 (input pullup).
- * PF14 - PIN14 (input pullup).
- * PF15 - PIN15 (input pullup).
- */
-#define VAL_GPIOF_MODER (PIN_MODE_INPUT(GPIOF_OSC_IN) | PIN_MODE_INPUT(GPIOF_OSC_OUT) | PIN_MODE_INPUT(GPIOF_PIN2) | PIN_MODE_INPUT(GPIOF_PIN3) | PIN_MODE_INPUT(GPIOF_PIN4) | PIN_MODE_INPUT(GPIOF_PIN5) | PIN_MODE_INPUT(GPIOF_PIN6) | PIN_MODE_INPUT(GPIOF_PIN7) | PIN_MODE_INPUT(GPIOF_PIN8) | PIN_MODE_INPUT(GPIOF_PIN9) | PIN_MODE_INPUT(GPIOF_PIN10) | PIN_MODE_INPUT(GPIOF_PIN11) | PIN_MODE_INPUT(GPIOF_PIN12) | PIN_MODE_INPUT(GPIOF_PIN13) | PIN_MODE_INPUT(GPIOF_PIN14) | PIN_MODE_INPUT(GPIOF_PIN15))
-#define VAL_GPIOF_OTYPER (PIN_OTYPE_PUSHPULL(GPIOF_OSC_IN) | PIN_OTYPE_PUSHPULL(GPIOF_OSC_OUT) | PIN_OTYPE_PUSHPULL(GPIOF_PIN2) | PIN_OTYPE_PUSHPULL(GPIOF_PIN3) | PIN_OTYPE_PUSHPULL(GPIOF_PIN4) | PIN_OTYPE_PUSHPULL(GPIOF_PIN5) | PIN_OTYPE_PUSHPULL(GPIOF_PIN6) | PIN_OTYPE_PUSHPULL(GPIOF_PIN7) | PIN_OTYPE_PUSHPULL(GPIOF_PIN8) | PIN_OTYPE_PUSHPULL(GPIOF_PIN9) | PIN_OTYPE_PUSHPULL(GPIOF_PIN10) | PIN_OTYPE_PUSHPULL(GPIOF_PIN11) | PIN_OTYPE_PUSHPULL(GPIOF_PIN12) | PIN_OTYPE_PUSHPULL(GPIOF_PIN13) | PIN_OTYPE_PUSHPULL(GPIOF_PIN14) | PIN_OTYPE_PUSHPULL(GPIOF_PIN15))
-#define VAL_GPIOF_OSPEEDR (PIN_OSPEED_VERYLOW(GPIOF_OSC_IN) | PIN_OSPEED_VERYLOW(GPIOF_OSC_OUT) | PIN_OSPEED_VERYLOW(GPIOF_PIN2) | PIN_OSPEED_VERYLOW(GPIOF_PIN3) | PIN_OSPEED_VERYLOW(GPIOF_PIN4) | PIN_OSPEED_VERYLOW(GPIOF_PIN5) | PIN_OSPEED_VERYLOW(GPIOF_PIN6) | PIN_OSPEED_VERYLOW(GPIOF_PIN7) | PIN_OSPEED_VERYLOW(GPIOF_PIN8) | PIN_OSPEED_VERYLOW(GPIOF_PIN9) | PIN_OSPEED_VERYLOW(GPIOF_PIN10) | PIN_OSPEED_VERYLOW(GPIOF_PIN11) | PIN_OSPEED_VERYLOW(GPIOF_PIN12) | PIN_OSPEED_VERYLOW(GPIOF_PIN13) | PIN_OSPEED_VERYLOW(GPIOF_PIN14) | PIN_OSPEED_VERYLOW(GPIOF_PIN15))
-#define VAL_GPIOF_PUPDR (PIN_PUPDR_FLOATING(GPIOF_OSC_IN) | PIN_PUPDR_FLOATING(GPIOF_OSC_OUT) | PIN_PUPDR_PULLUP(GPIOF_PIN2) | PIN_PUPDR_PULLUP(GPIOF_PIN3) | PIN_PUPDR_PULLUP(GPIOF_PIN4) | PIN_PUPDR_PULLUP(GPIOF_PIN5) | PIN_PUPDR_PULLUP(GPIOF_PIN6) | PIN_PUPDR_PULLUP(GPIOF_PIN7) | PIN_PUPDR_PULLUP(GPIOF_PIN8) | PIN_PUPDR_PULLUP(GPIOF_PIN9) | PIN_PUPDR_PULLUP(GPIOF_PIN10) | PIN_PUPDR_PULLUP(GPIOF_PIN11) | PIN_PUPDR_PULLUP(GPIOF_PIN12) | PIN_PUPDR_PULLUP(GPIOF_PIN13) | PIN_PUPDR_PULLUP(GPIOF_PIN14) | PIN_PUPDR_PULLUP(GPIOF_PIN15))
-#define VAL_GPIOF_ODR (PIN_ODR_HIGH(GPIOF_OSC_IN) | PIN_ODR_HIGH(GPIOF_OSC_OUT) | PIN_ODR_HIGH(GPIOF_PIN2) | PIN_ODR_HIGH(GPIOF_PIN3) | PIN_ODR_HIGH(GPIOF_PIN4) | PIN_ODR_HIGH(GPIOF_PIN5) | PIN_ODR_HIGH(GPIOF_PIN6) | PIN_ODR_HIGH(GPIOF_PIN7) | PIN_ODR_HIGH(GPIOF_PIN8) | PIN_ODR_HIGH(GPIOF_PIN9) | PIN_ODR_HIGH(GPIOF_PIN10) | PIN_ODR_HIGH(GPIOF_PIN11) | PIN_ODR_HIGH(GPIOF_PIN12) | PIN_ODR_HIGH(GPIOF_PIN13) | PIN_ODR_HIGH(GPIOF_PIN14) | PIN_ODR_HIGH(GPIOF_PIN15))
-#define VAL_GPIOF_AFRL (PIN_AFIO_AF(GPIOF_OSC_IN, 0U) | PIN_AFIO_AF(GPIOF_OSC_OUT, 0U) | PIN_AFIO_AF(GPIOF_PIN2, 0U) | PIN_AFIO_AF(GPIOF_PIN3, 0U) | PIN_AFIO_AF(GPIOF_PIN4, 0U) | PIN_AFIO_AF(GPIOF_PIN5, 0U) | PIN_AFIO_AF(GPIOF_PIN6, 0U) | PIN_AFIO_AF(GPIOF_PIN7, 0U))
-#define VAL_GPIOF_AFRH (PIN_AFIO_AF(GPIOF_PIN8, 0U) | PIN_AFIO_AF(GPIOF_PIN9, 0U) | PIN_AFIO_AF(GPIOF_PIN10, 0U) | PIN_AFIO_AF(GPIOF_PIN11, 0U) | PIN_AFIO_AF(GPIOF_PIN12, 0U) | PIN_AFIO_AF(GPIOF_PIN13, 0U) | PIN_AFIO_AF(GPIOF_PIN14, 0U) | PIN_AFIO_AF(GPIOF_PIN15, 0U))
-
-/*===========================================================================*/
-/* External declarations. */
-/*===========================================================================*/
-
-#if !defined(_FROM_ASM_)
-# ifdef __cplusplus
-extern "C" {
-# endif
-void boardInit(void);
-# ifdef __cplusplus
-}
-# endif
-#endif /* _FROM_ASM_ */
-
-#endif /* BOARD_H */
diff --git a/platforms/chibios/GENERIC_STM32_F072XB/board/board.mk b/platforms/chibios/GENERIC_STM32_F072XB/board/board.mk
index 842e335905..3f0e6c46e8 100644
--- a/platforms/chibios/GENERIC_STM32_F072XB/board/board.mk
+++ b/platforms/chibios/GENERIC_STM32_F072XB/board/board.mk
@@ -1,8 +1,8 @@
# List of all the board related files.
-BOARDSRC = $(BOARD_PATH)/board/board.c
+BOARDSRC = $(CHIBIOS)/os/hal/boards/ST_NUCLEO64_F072RB/board.c
# Required include directories
-BOARDINC = $(BOARD_PATH)/board
+BOARDINC = $(CHIBIOS)/os/hal/boards/ST_NUCLEO64_F072RB
# Shared variables
ALLCSRC += $(BOARDSRC)
diff --git a/platforms/chibios/GENERIC_STM32_F072XB/configs/board.h b/platforms/chibios/GENERIC_STM32_F072XB/configs/board.h
new file mode 100644
index 0000000000..30af6b0c86
--- /dev/null
+++ b/platforms/chibios/GENERIC_STM32_F072XB/configs/board.h
@@ -0,0 +1,20 @@
+/* Copyright 2020 Nick Brassel (tzarc)
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ */
+#pragma once
+
+#include_next "board.h"
+
+#undef STM32_HSE_BYPASS
diff --git a/platforms/chibios/GENERIC_STM32_F072XB/configs/mcuconf.h b/platforms/chibios/GENERIC_STM32_F072XB/configs/mcuconf.h
new file mode 100644
index 0000000000..688350e9ce
--- /dev/null
+++ b/platforms/chibios/GENERIC_STM32_F072XB/configs/mcuconf.h
@@ -0,0 +1,177 @@
+/*
+ ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef _MCUCONF_H_
+#define _MCUCONF_H_
+
+/*
+ * STM32F0xx drivers configuration.
+ * The following settings override the default settings present in
+ * the various device driver implementation headers.
+ * Note that the settings for each driver only have effect if the whole
+ * driver is enabled in halconf.h.
+ *
+ * IRQ priorities:
+ * 3...0 Lowest...Highest.
+ *
+ * DMA priorities:
+ * 0...3 Lowest...Highest.
+ */
+
+#define STM32F0xx_MCUCONF
+// #define STM32F070xB
+
+/*
+ * HAL driver system settings.
+ */
+#define STM32_NO_INIT FALSE
+#define STM32_PVD_ENABLE FALSE
+#define STM32_PLS STM32_PLS_LEV0
+#define STM32_HSI_ENABLED TRUE
+#define STM32_HSI14_ENABLED TRUE
+#define STM32_HSI48_ENABLED FALSE
+#define STM32_LSI_ENABLED TRUE
+#define STM32_HSE_ENABLED FALSE
+#define STM32_LSE_ENABLED FALSE
+#define STM32_SW STM32_SW_PLL
+#define STM32_PLLSRC STM32_PLLSRC_HSI_DIV2
+#define STM32_PREDIV_VALUE 1
+#define STM32_PLLMUL_VALUE 12
+#define STM32_HPRE STM32_HPRE_DIV1
+#define STM32_PPRE STM32_PPRE_DIV1
+#define STM32_ADCSW STM32_ADCSW_HSI14
+#define STM32_ADCPRE STM32_ADCPRE_DIV4
+#define STM32_MCOSEL STM32_MCOSEL_NOCLOCK
+#define STM32_ADCPRE STM32_ADCPRE_DIV4
+#define STM32_ADCSW STM32_ADCSW_HSI14
+#define STM32_USBSW STM32_USBSW_HSI48
+#define STM32_CECSW STM32_CECSW_HSI
+#define STM32_I2C1SW STM32_I2C1SW_HSI
+#define STM32_USART1SW STM32_USART1SW_PCLK
+#define STM32_RTCSEL STM32_RTCSEL_LSI
+
+/*
+ * IRQ system settings.
+ */
+#define STM32_IRQ_EXTI0_1_IRQ_PRIORITY 3
+#define STM32_IRQ_EXTI2_3_IRQ_PRIORITY 3
+#define STM32_IRQ_EXTI4_15_IRQ_PRIORITY 3
+#define STM32_IRQ_EXTI16_IRQ_PRIORITY 3
+#define STM32_IRQ_EXTI17_20_IRQ_PRIORITY 3
+#define STM32_IRQ_EXTI21_22_IRQ_PRIORITY 3
+
+/*
+ * ADC driver system settings.
+ */
+#define STM32_ADC_USE_ADC1 FALSE
+#define STM32_ADC_ADC1_DMA_PRIORITY 2
+#define STM32_ADC_IRQ_PRIORITY 2
+#define STM32_ADC_ADC1_DMA_IRQ_PRIORITY 2
+
+/*
+ * GPT driver system settings.
+ */
+#define STM32_GPT_USE_TIM1 FALSE
+#define STM32_GPT_USE_TIM2 FALSE
+#define STM32_GPT_USE_TIM3 FALSE
+#define STM32_GPT_USE_TIM14 FALSE
+#define STM32_GPT_TIM1_IRQ_PRIORITY 2
+#define STM32_GPT_TIM2_IRQ_PRIORITY 2
+#define STM32_GPT_TIM3_IRQ_PRIORITY 2
+#define STM32_GPT_TIM14_IRQ_PRIORITY 2
+
+/*
+ * I2C driver system settings.
+ */
+#define STM32_I2C_USE_I2C1 FALSE
+#define STM32_I2C_USE_I2C2 FALSE
+#define STM32_I2C_BUSY_TIMEOUT 50
+#define STM32_I2C_I2C1_IRQ_PRIORITY 3
+#define STM32_I2C_I2C2_IRQ_PRIORITY 3
+#define STM32_I2C_USE_DMA TRUE
+#define STM32_I2C_I2C1_DMA_PRIORITY 1
+#define STM32_I2C_I2C2_DMA_PRIORITY 1
+#define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
+#define STM32_I2C_I2C1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
+#define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure")
+
+/*
+ * ICU driver system settings.
+ */
+#define STM32_ICU_USE_TIM1 FALSE
+#define STM32_ICU_USE_TIM2 FALSE
+#define STM32_ICU_USE_TIM3 FALSE
+#define STM32_ICU_TIM1_IRQ_PRIORITY 3
+#define STM32_ICU_TIM2_IRQ_PRIORITY 3
+#define STM32_ICU_TIM3_IRQ_PRIORITY 3
+
+/*
+ * PWM driver system settings.
+ */
+#define STM32_PWM_USE_ADVANCED FALSE
+#define STM32_PWM_USE_TIM1 FALSE
+#define STM32_PWM_USE_TIM2 FALSE
+#define STM32_PWM_USE_TIM3 TRUE
+#define STM32_PWM_TIM1_IRQ_PRIORITY 3
+#define STM32_PWM_TIM2_IRQ_PRIORITY 3
+#define STM32_PWM_TIM3_IRQ_PRIORITY 3
+
+/*
+ * SERIAL driver system settings.
+ */
+#define STM32_SERIAL_USE_USART1 FALSE
+#define STM32_SERIAL_USE_USART2 FALSE
+#define STM32_SERIAL_USART1_PRIORITY 3
+#define STM32_SERIAL_USART2_PRIORITY 3
+
+/*
+ * SPI driver system settings.
+ */
+#define STM32_SPI_USE_SPI1 FALSE
+#define STM32_SPI_USE_SPI2 TRUE
+#define STM32_SPI_SPI1_DMA_PRIORITY 1
+#define STM32_SPI_SPI2_DMA_PRIORITY 1
+#define STM32_SPI_SPI1_IRQ_PRIORITY 2
+#define STM32_SPI_SPI2_IRQ_PRIORITY 2
+#define STM32_SPI_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
+#define STM32_SPI_SPI2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 5)
+#define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure")
+
+/*
+ * ST driver system settings.
+ */
+#define STM32_ST_IRQ_PRIORITY 2
+#define STM32_ST_USE_TIMER 2
+
+/*
+ * UART driver system settings.
+ */
+#define STM32_UART_USE_USART1 FALSE
+#define STM32_UART_USE_USART2 FALSE
+#define STM32_UART_USART1_IRQ_PRIORITY 3
+#define STM32_UART_USART2_IRQ_PRIORITY 3
+#define STM32_UART_USART1_DMA_PRIORITY 0
+#define STM32_UART_USART2_DMA_PRIORITY 0
+#define STM32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure")
+
+/*
+ * USB driver system settings.
+ */
+#define STM32_USB_USE_USB1 TRUE
+#define STM32_USB_LOW_POWER_ON_SUSPEND FALSE
+#define STM32_USB_USB1_LP_IRQ_PRIORITY 3
+
+#endif /* _MCUCONF_H_ */
diff --git a/platforms/chibios/GENERIC_STM32_F303XC/configs/config.h b/platforms/chibios/GENERIC_STM32_F303XC/configs/config.h
index 48a7a90093..a73f0c0b47 100644
--- a/platforms/chibios/GENERIC_STM32_F303XC/configs/config.h
+++ b/platforms/chibios/GENERIC_STM32_F303XC/configs/config.h
@@ -15,4 +15,6 @@
*/
#pragma once
-#define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE
+#ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP
+# define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE
+#endif
diff --git a/platforms/chibios/STM32_F103_STM32DUINO/configs/mcuconf.h b/platforms/chibios/STM32_F103_STM32DUINO/configs/mcuconf.h
new file mode 100644
index 0000000000..9945e7408d
--- /dev/null
+++ b/platforms/chibios/STM32_F103_STM32DUINO/configs/mcuconf.h
@@ -0,0 +1,209 @@
+/*
+ ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef _MCUCONF_H_
+#define _MCUCONF_H_
+
+#define STM32F103_MCUCONF
+
+/*
+ * STM32F103 drivers configuration.
+ * The following settings override the default settings present in
+ * the various device driver implementation headers.
+ * Note that the settings for each driver only have effect if the whole
+ * driver is enabled in halconf.h.
+ *
+ * IRQ priorities:
+ * 15...0 Lowest...Highest.
+ *
+ * DMA priorities:
+ * 0...3 Lowest...Highest.
+ */
+
+/*
+ * HAL driver system settings.
+ */
+#define STM32_NO_INIT FALSE
+#define STM32_HSI_ENABLED TRUE
+#define STM32_LSI_ENABLED FALSE
+#define STM32_HSE_ENABLED TRUE
+#define STM32_LSE_ENABLED FALSE
+#define STM32_SW STM32_SW_PLL
+#define STM32_PLLSRC STM32_PLLSRC_HSE
+#define STM32_PLLXTPRE STM32_PLLXTPRE_DIV1
+#define STM32_PLLMUL_VALUE 9
+#define STM32_HPRE STM32_HPRE_DIV1
+#define STM32_PPRE1 STM32_PPRE1_DIV2
+#define STM32_PPRE2 STM32_PPRE2_DIV2
+#define STM32_ADCPRE STM32_ADCPRE_DIV4
+#define STM32_USB_CLOCK_REQUIRED TRUE
+#define STM32_USBPRE STM32_USBPRE_DIV1P5
+#define STM32_MCOSEL STM32_MCOSEL_NOCLOCK
+#define STM32_RTCSEL STM32_RTCSEL_HSEDIV
+#define STM32_PVD_ENABLE FALSE
+#define STM32_PLS STM32_PLS_LEV0
+
+/*
+ * ADC driver system settings.
+ */
+#define STM32_ADC_USE_ADC1 FALSE
+#define STM32_ADC_ADC1_DMA_PRIORITY 2
+#define STM32_ADC_ADC1_IRQ_PRIORITY 6
+
+/*
+ * CAN driver system settings.
+ */
+#define STM32_CAN_USE_CAN1 FALSE
+#define STM32_CAN_CAN1_IRQ_PRIORITY 11
+
+/*
+ * EXT driver system settings.
+ */
+#define STM32_EXT_EXTI0_IRQ_PRIORITY 6
+#define STM32_EXT_EXTI1_IRQ_PRIORITY 6
+#define STM32_EXT_EXTI2_IRQ_PRIORITY 6
+#define STM32_EXT_EXTI3_IRQ_PRIORITY 6
+#define STM32_EXT_EXTI4_IRQ_PRIORITY 6
+#define STM32_EXT_EXTI5_9_IRQ_PRIORITY 6
+#define STM32_EXT_EXTI10_15_IRQ_PRIORITY 6
+#define STM32_EXT_EXTI16_IRQ_PRIORITY 6
+#define STM32_EXT_EXTI17_IRQ_PRIORITY 6
+#define STM32_EXT_EXTI18_IRQ_PRIORITY 6
+#define STM32_EXT_EXTI19_IRQ_PRIORITY 6
+
+/*
+ * GPT driver system settings.
+ */
+#define STM32_GPT_USE_TIM1 FALSE
+#define STM32_GPT_USE_TIM2 FALSE
+#define STM32_GPT_USE_TIM3 FALSE
+#define STM32_GPT_USE_TIM4 FALSE
+#define STM32_GPT_USE_TIM5 FALSE
+#define STM32_GPT_USE_TIM8 FALSE
+#define STM32_GPT_TIM1_IRQ_PRIORITY 7
+#define STM32_GPT_TIM2_IRQ_PRIORITY 7
+#define STM32_GPT_TIM3_IRQ_PRIORITY 7
+#define STM32_GPT_TIM4_IRQ_PRIORITY 7
+#define STM32_GPT_TIM5_IRQ_PRIORITY 7
+#define STM32_GPT_TIM8_IRQ_PRIORITY 7
+
+/*
+ * I2C driver system settings.
+ */
+#define STM32_I2C_USE_I2C1 FALSE
+#define STM32_I2C_USE_I2C2 FALSE
+#define STM32_I2C_BUSY_TIMEOUT 50
+#define STM32_I2C_I2C1_IRQ_PRIORITY 5
+#define STM32_I2C_I2C2_IRQ_PRIORITY 5
+#define STM32_I2C_I2C1_DMA_PRIORITY 3
+#define STM32_I2C_I2C2_DMA_PRIORITY 3
+#define STM32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure")
+
+/*
+ * ICU driver system settings.
+ */
+#define STM32_ICU_USE_TIM1 FALSE
+#define STM32_ICU_USE_TIM2 FALSE
+#define STM32_ICU_USE_TIM3 FALSE
+#define STM32_ICU_USE_TIM4 FALSE
+#define STM32_ICU_USE_TIM5 FALSE
+#define STM32_ICU_USE_TIM8 FALSE
+#define STM32_ICU_TIM1_IRQ_PRIORITY 7
+#define STM32_ICU_TIM2_IRQ_PRIORITY 7
+#define STM32_ICU_TIM3_IRQ_PRIORITY 7
+#define STM32_ICU_TIM4_IRQ_PRIORITY 7
+#define STM32_ICU_TIM5_IRQ_PRIORITY 7
+#define STM32_ICU_TIM8_IRQ_PRIORITY 7
+
+/*
+ * PWM driver system settings.
+ */
+#define STM32_PWM_USE_ADVANCED FALSE
+#define STM32_PWM_USE_TIM1 FALSE
+#define STM32_PWM_USE_TIM2 FALSE
+#define STM32_PWM_USE_TIM3 FALSE
+#define STM32_PWM_USE_TIM4 FALSE
+#define STM32_PWM_USE_TIM5 FALSE
+#define STM32_PWM_USE_TIM8 FALSE
+#define STM32_PWM_TIM1_IRQ_PRIORITY 7
+#define STM32_PWM_TIM2_IRQ_PRIORITY 7
+#define STM32_PWM_TIM3_IRQ_PRIORITY 7
+#define STM32_PWM_TIM4_IRQ_PRIORITY 7
+#define STM32_PWM_TIM5_IRQ_PRIORITY 7
+#define STM32_PWM_TIM8_IRQ_PRIORITY 7
+
+/*
+ * RTC driver system settings.
+ */
+#define STM32_RTC_IRQ_PRIORITY 15
+
+/*
+ * SERIAL driver system settings.
+ */
+#define STM32_SERIAL_USE_USART1 FALSE
+#define STM32_SERIAL_USE_USART2 FALSE
+#define STM32_SERIAL_USE_USART3 FALSE
+#define STM32_SERIAL_USE_UART4 FALSE
+#define STM32_SERIAL_USE_UART5 FALSE
+#define STM32_SERIAL_USART1_PRIORITY 12
+#define STM32_SERIAL_USART2_PRIORITY 12
+#define STM32_SERIAL_USART3_PRIORITY 12
+#define STM32_SERIAL_UART4_PRIORITY 12
+#define STM32_SERIAL_UART5_PRIORITY 12
+
+/*
+ * SPI driver system settings.
+ */
+#define STM32_SPI_USE_SPI1 FALSE
+#define STM32_SPI_USE_SPI2 TRUE
+#define STM32_SPI_USE_SPI3 FALSE
+#define STM32_SPI_SPI1_DMA_PRIORITY 1
+#define STM32_SPI_SPI2_DMA_PRIORITY 1
+#define STM32_SPI_SPI3_DMA_PRIORITY 1
+#define STM32_SPI_SPI1_IRQ_PRIORITY 10
+#define STM32_SPI_SPI2_IRQ_PRIORITY 10
+#define STM32_SPI_SPI3_IRQ_PRIORITY 10
+#define STM32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure")
+
+/*
+ * ST driver system settings.
+ */
+#define STM32_ST_IRQ_PRIORITY 8
+#define STM32_ST_USE_TIMER 2
+
+/*
+ * UART driver system settings.
+ */
+#define STM32_UART_USE_USART1 FALSE
+#define STM32_UART_USE_USART2 FALSE
+#define STM32_UART_USE_USART3 FALSE
+#define STM32_UART_USART1_IRQ_PRIORITY 12
+#define STM32_UART_USART2_IRQ_PRIORITY 12
+#define STM32_UART_USART3_IRQ_PRIORITY 12
+#define STM32_UART_USART1_DMA_PRIORITY 0
+#define STM32_UART_USART2_DMA_PRIORITY 0
+#define STM32_UART_USART3_DMA_PRIORITY 0
+#define STM32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure")
+
+/*
+ * USB driver system settings.
+ */
+#define STM32_USB_USE_USB1 TRUE
+#define STM32_USB_LOW_POWER_ON_SUSPEND FALSE
+#define STM32_USB_USB1_HP_IRQ_PRIORITY 13
+#define STM32_USB_USB1_LP_IRQ_PRIORITY 14
+
+#endif /* _MCUCONF_H_ */
diff --git a/platforms/chibios/GENERIC_STM32_F303XC/configs/chconf.h b/platforms/chibios/common/configs/chconf.h
index aac3303705..aac3303705 100644
--- a/platforms/chibios/GENERIC_STM32_F303XC/configs/chconf.h
+++ b/platforms/chibios/common/configs/chconf.h
diff --git a/platforms/chibios/GENERIC_STM32_F303XC/configs/halconf.h b/platforms/chibios/common/configs/halconf.h
index 6b48e289f9..6b48e289f9 100644
--- a/platforms/chibios/GENERIC_STM32_F303XC/configs/halconf.h
+++ b/platforms/chibios/common/configs/halconf.h
diff --git a/platforms/chibios/ld/MKL26Z64.ld b/platforms/chibios/common/ld/MKL26Z64.ld
index c4ca8b874c..c4ca8b874c 100644
--- a/platforms/chibios/ld/MKL26Z64.ld
+++ b/platforms/chibios/common/ld/MKL26Z64.ld
diff --git a/platforms/chibios/ld/STM32F103x8_stm32duino_bootloader.ld b/platforms/chibios/common/ld/STM32F103x8_stm32duino_bootloader.ld
index bb852422a3..bb852422a3 100644
--- a/platforms/chibios/ld/STM32F103x8_stm32duino_bootloader.ld
+++ b/platforms/chibios/common/ld/STM32F103x8_stm32duino_bootloader.ld
diff --git a/quantum/backlight/backlight_avr.c b/quantum/backlight/backlight_avr.c
index b3e882ffe1..4d66da80ba 100644
--- a/quantum/backlight/backlight_avr.c
+++ b/quantum/backlight/backlight_avr.c
@@ -3,6 +3,11 @@
#include "backlight_driver_common.h"
#include "debug.h"
+// Maximum duty cycle limit
+#ifndef BACKLIGHT_LIMIT_VAL
+# define BACKLIGHT_LIMIT_VAL 255
+#endif
+
// This logic is a bit complex, we support 3 setups:
//
// 1. Hardware PWM when backlight is wired to a PWM pin.
@@ -240,6 +245,9 @@ static uint16_t cie_lightness(uint16_t v) {
}
}
+// rescale the supplied backlight value to be in terms of the value limit
+static uint32_t rescale_limit_val(uint32_t val) { return (val * (BACKLIGHT_LIMIT_VAL + 1)) / 256; }
+
// range for val is [0..TIMER_TOP]. PWM pin is high while the timer count is below val.
static inline void set_pwm(uint16_t val) { OCRxx = val; }
@@ -269,7 +277,7 @@ void backlight_set(uint8_t level) {
#endif
}
// Set the brightness
- set_pwm(cie_lightness(TIMER_TOP * (uint32_t)level / BACKLIGHT_LEVELS));
+ set_pwm(cie_lightness(rescale_limit_val(TIMER_TOP * (uint32_t)level / BACKLIGHT_LEVELS)));
}
void backlight_task(void) {}
@@ -375,7 +383,7 @@ ISR(TIMERx_OVF_vect)
breathing_interrupt_disable();
}
- set_pwm(cie_lightness(scale_backlight((uint16_t)pgm_read_byte(&breathing_table[index]) * 0x0101U)));
+ set_pwm(cie_lightness(rescale_limit_val(scale_backlight((uint16_t)pgm_read_byte(&breathing_table[index]) * 0x0101U))));
}
#endif // BACKLIGHT_BREATHING
diff --git a/quantum/backlight/backlight_chibios.c b/quantum/backlight/backlight_chibios.c
index 0fe812bf27..4d5a69e14e 100644
--- a/quantum/backlight/backlight_chibios.c
+++ b/quantum/backlight/backlight_chibios.c
@@ -3,6 +3,11 @@
#include <hal.h>
#include "debug.h"
+// Maximum duty cycle limit
+#ifndef BACKLIGHT_LIMIT_VAL
+# define BACKLIGHT_LIMIT_VAL 255
+#endif
+
// GPIOV2 && GPIOV3
#ifndef BACKLIGHT_PAL_MODE
# define BACKLIGHT_PAL_MODE 2
@@ -58,6 +63,11 @@ static uint16_t cie_lightness(uint16_t v) {
}
}
+static uint32_t rescale_limit_val(uint32_t val) {
+ // rescale the supplied backlight value to be in terms of the value limit
+ return (val * (BACKLIGHT_LIMIT_VAL + 1)) / 256;
+}
+
void backlight_init_ports(void) {
#ifdef USE_GPIOV1
palSetPadMode(PAL_PORT(BACKLIGHT_PIN), PAL_PAD(BACKLIGHT_PIN), PAL_MODE_STM32_ALTERNATE_PUSHPULL);
@@ -85,7 +95,7 @@ void backlight_set(uint8_t level) {
pwmDisableChannel(&BACKLIGHT_PWM_DRIVER, BACKLIGHT_PWM_CHANNEL - 1);
} else {
// Turn backlight on
- uint32_t duty = (uint32_t)(cie_lightness(0xFFFF * (uint32_t)level / BACKLIGHT_LEVELS));
+ uint32_t duty = (uint32_t)(cie_lightness(rescale_limit_val(0xFFFF * (uint32_t)level / BACKLIGHT_LEVELS)));
pwmEnableChannel(&BACKLIGHT_PWM_DRIVER, BACKLIGHT_PWM_CHANNEL - 1, PWM_FRACTION_TO_WIDTH(&BACKLIGHT_PWM_DRIVER, 0xFFFF, duty));
}
}
@@ -129,7 +139,7 @@ void breathing_callback(PWMDriver *pwmp) {
static uint16_t breathing_counter = 0;
breathing_counter = (breathing_counter + 1) % (breathing_period * 256);
uint8_t index = breathing_counter / interval % BREATHING_STEPS;
- uint32_t duty = cie_lightness(scale_backlight(breathing_table[index] * 256));
+ uint32_t duty = cie_lightness(rescale_limit_val(scale_backlight(breathing_table[index] * 256)));
chSysLockFromISR();
pwmEnableChannelI(pwmp, BACKLIGHT_PWM_CHANNEL - 1, PWM_FRACTION_TO_WIDTH(&BACKLIGHT_PWM_DRIVER, 0xFFFF, duty));
diff --git a/quantum/config_common.h b/quantum/config_common.h
index c6a96e673c..53377f2b61 100644
--- a/quantum/config_common.h
+++ b/quantum/config_common.h
@@ -40,7 +40,7 @@
# define PIND_ADDRESS 0x9
# define PINE_ADDRESS 0xC
# define PINF_ADDRESS 0xF
-# elif defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__)
+# elif defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)
# define ADDRESS_BASE 0x00
# define PINB_ADDRESS 0x3
# define PINC_ADDRESS 0x6
@@ -59,11 +59,6 @@
# define PINC_ADDRESS 0x3
# define PINB_ADDRESS 0x6
# define PINA_ADDRESS 0x9
-# elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)
-# define ADDRESS_BASE 0x00
-# define PINB_ADDRESS 0x3
-# define PINC_ADDRESS 0x6
-# define PIND_ADDRESS 0x9
# elif defined(__AVR_ATtiny85__)
# define ADDRESS_BASE 0x10
# define PINB_ADDRESS 0x6
@@ -285,6 +280,91 @@
# define F13 PAL_LINE(GPIOF, 13)
# define F14 PAL_LINE(GPIOF, 14)
# define F15 PAL_LINE(GPIOF, 15)
+# define G0 PAL_LINE(GPIOG, 0)
+# define G1 PAL_LINE(GPIOG, 1)
+# define G2 PAL_LINE(GPIOG, 2)
+# define G3 PAL_LINE(GPIOG, 3)
+# define G4 PAL_LINE(GPIOG, 4)
+# define G5 PAL_LINE(GPIOG, 5)
+# define G6 PAL_LINE(GPIOG, 6)
+# define G7 PAL_LINE(GPIOG, 7)
+# define G8 PAL_LINE(GPIOG, 8)
+# define G9 PAL_LINE(GPIOG, 9)
+# define G10 PAL_LINE(GPIOG, 10)
+# define G11 PAL_LINE(GPIOG, 11)
+# define G12 PAL_LINE(GPIOG, 12)
+# define G13 PAL_LINE(GPIOG, 13)
+# define G14 PAL_LINE(GPIOG, 14)
+# define G15 PAL_LINE(GPIOG, 15)
+# define H0 PAL_LINE(GPIOH, 0)
+# define H1 PAL_LINE(GPIOH, 1)
+# define H2 PAL_LINE(GPIOH, 2)
+# define H3 PAL_LINE(GPIOH, 3)
+# define H4 PAL_LINE(GPIOH, 4)
+# define H5 PAL_LINE(GPIOH, 5)
+# define H6 PAL_LINE(GPIOH, 6)
+# define H7 PAL_LINE(GPIOH, 7)
+# define H8 PAL_LINE(GPIOH, 8)
+# define H9 PAL_LINE(GPIOH, 9)
+# define H10 PAL_LINE(GPIOH, 10)
+# define H11 PAL_LINE(GPIOH, 11)
+# define H12 PAL_LINE(GPIOH, 12)
+# define H13 PAL_LINE(GPIOH, 13)
+# define H14 PAL_LINE(GPIOH, 14)
+# define H15 PAL_LINE(GPIOH, 15)
+# define I0 PAL_LINE(GPIOI, 0)
+# define I1 PAL_LINE(GPIOI, 1)
+# define I2 PAL_LINE(GPIOI, 2)
+# define I3 PAL_LINE(GPIOI, 3)
+# define I4 PAL_LINE(GPIOI, 4)
+# define I5 PAL_LINE(GPIOI, 5)
+# define I6 PAL_LINE(GPIOI, 6)
+# define I7 PAL_LINE(GPIOI, 7)
+# define I8 PAL_LINE(GPIOI, 8)
+# define I9 PAL_LINE(GPIOI, 9)
+# define I10 PAL_LINE(GPIOI, 10)
+# define I11 PAL_LINE(GPIOI, 11)
+# define I12 PAL_LINE(GPIOI, 12)
+# define I13 PAL_LINE(GPIOI, 13)
+# define I14 PAL_LINE(GPIOI, 14)
+# define I15 PAL_LINE(GPIOI, 15)
+# define J0 PAL_LINE(GPIOJ, 0)
+# define J1 PAL_LINE(GPIOJ, 1)
+# define J2 PAL_LINE(GPIOJ, 2)
+# define J3 PAL_LINE(GPIOJ, 3)
+# define J4 PAL_LINE(GPIOJ, 4)
+# define J5 PAL_LINE(GPIOJ, 5)
+# define J6 PAL_LINE(GPIOJ, 6)
+# define J7 PAL_LINE(GPIOJ, 7)
+# define J8 PAL_LINE(GPIOJ, 8)
+# define J9 PAL_LINE(GPIOJ, 9)
+# define J10 PAL_LINE(GPIOJ, 10)
+# define J11 PAL_LINE(GPIOJ, 11)
+# define J12 PAL_LINE(GPIOJ, 12)
+# define J13 PAL_LINE(GPIOJ, 13)
+# define J14 PAL_LINE(GPIOJ, 14)
+# define J15 PAL_LINE(GPIOJ, 15)
+// Keyboards can `#define KEYBOARD_REQUIRES_GPIOK` if they need to access GPIO-K pins. These conflict with a whole
+// bunch of layout definitions, so it's intentionally left out unless absolutely required -- in that case, the
+// keyboard designer should use a different symbol when defining their layout macros.
+# ifdef KEYBOARD_REQUIRES_GPIOK
+# define K0 PAL_LINE(GPIOK, 0)
+# define K1 PAL_LINE(GPIOK, 1)
+# define K2 PAL_LINE(GPIOK, 2)
+# define K3 PAL_LINE(GPIOK, 3)
+# define K4 PAL_LINE(GPIOK, 4)
+# define K5 PAL_LINE(GPIOK, 5)
+# define K6 PAL_LINE(GPIOK, 6)
+# define K7 PAL_LINE(GPIOK, 7)
+# define K8 PAL_LINE(GPIOK, 8)
+# define K9 PAL_LINE(GPIOK, 9)
+# define K10 PAL_LINE(GPIOK, 10)
+# define K11 PAL_LINE(GPIOK, 11)
+# define K12 PAL_LINE(GPIOK, 12)
+# define K13 PAL_LINE(GPIOK, 13)
+# define K14 PAL_LINE(GPIOK, 14)
+# define K15 PAL_LINE(GPIOK, 15)
+# endif
# endif
#endif
diff --git a/quantum/encoder.c b/quantum/encoder.c
index 81ec1bb376..7ca31afedc 100644
--- a/quantum/encoder.c
+++ b/quantum/encoder.c
@@ -23,7 +23,7 @@
// for memcpy
#include <string.h>
-#ifndef ENCODER_RESOLUTION
+#if !defined(ENCODER_RESOLUTIONS) && !defined(ENCODER_RESOLUTION)
# define ENCODER_RESOLUTION 4
#endif
@@ -34,6 +34,9 @@
#define NUMBER_OF_ENCODERS (sizeof(encoders_pad_a) / sizeof(pin_t))
static pin_t encoders_pad_a[] = ENCODERS_PAD_A;
static pin_t encoders_pad_b[] = ENCODERS_PAD_B;
+#ifdef ENCODER_RESOLUTIONS
+static uint8_t encoder_resolutions[] = ENCODER_RESOLUTIONS;
+#endif
#ifndef ENCODER_DIRECTION_FLIP
# define ENCODER_CLOCKWISE true
@@ -65,9 +68,15 @@ void encoder_init(void) {
if (!isLeftHand) {
const pin_t encoders_pad_a_right[] = ENCODERS_PAD_A_RIGHT;
const pin_t encoders_pad_b_right[] = ENCODERS_PAD_B_RIGHT;
+# if defined(ENCODER_RESOLUTIONS_RIGHT)
+ const uint8_t encoder_resolutions_right[] = ENCODER_RESOLUTIONS_RIGHT;
+# endif
for (uint8_t i = 0; i < NUMBER_OF_ENCODERS; i++) {
encoders_pad_a[i] = encoders_pad_a_right[i];
encoders_pad_b[i] = encoders_pad_b_right[i];
+# if defined(ENCODER_RESOLUTIONS_RIGHT)
+ encoder_resolutions[i] = encoder_resolutions_right[i];
+# endif
}
}
#endif
@@ -87,19 +96,26 @@ void encoder_init(void) {
static void encoder_update(int8_t index, uint8_t state) {
uint8_t i = index;
+
+#ifdef ENCODER_RESOLUTIONS
+ int8_t resolution = encoder_resolutions[i];
+#else
+ int8_t resolution = ENCODER_RESOLUTION;
+#endif
+
#ifdef SPLIT_KEYBOARD
index += thisHand;
#endif
encoder_pulses[i] += encoder_LUT[state & 0xF];
- if (encoder_pulses[i] >= ENCODER_RESOLUTION) {
+ if (encoder_pulses[i] >= resolution) {
encoder_value[index]++;
encoder_update_kb(index, ENCODER_COUNTER_CLOCKWISE);
}
- if (encoder_pulses[i] <= -ENCODER_RESOLUTION) { // direction is arbitrary here, but this clockwise
+ if (encoder_pulses[i] <= -resolution) { // direction is arbitrary here, but this clockwise
encoder_value[index]--;
encoder_update_kb(index, ENCODER_CLOCKWISE);
}
- encoder_pulses[i] %= ENCODER_RESOLUTION;
+ encoder_pulses[i] %= resolution;
}
void encoder_read(void) {
diff --git a/quantum/joystick.h b/quantum/joystick.h
index a95472b9fd..87dbc24aff 100644
--- a/quantum/joystick.h
+++ b/quantum/joystick.h
@@ -1,5 +1,9 @@
#pragma once
+#include "quantum.h"
+
+#include <stdint.h>
+
#ifndef JOYSTICK_BUTTON_COUNT
# define JOYSTICK_BUTTON_COUNT 8
#endif
@@ -8,9 +12,13 @@
# define JOYSTICK_AXES_COUNT 4
#endif
-#include "quantum.h"
+#ifndef JOYSTICK_AXES_RESOLUTION
+# define JOYSTICK_AXES_RESOLUTION 8
+#elif JOYSTICK_AXES_RESOLUTION < 8 || JOYSTICK_AXES_RESOLUTION > 16
+# error JOYSTICK_AXES_RESOLUTION must be between 8 and 16
+#endif
-#include <stdint.h>
+#define JOYSTICK_RESOLUTION ((1L << (JOYSTICK_AXES_RESOLUTION - 1)) - 1)
// configure on input_pin of the joystick_axes array entry to JS_VIRTUAL_AXIS
// to prevent it from being read from the ADC. This allows outputing forged axis value.
diff --git a/quantum/led_matrix.c b/quantum/led_matrix.c
index 5c24c797a9..eb523990a6 100644
--- a/quantum/led_matrix.c
+++ b/quantum/led_matrix.c
@@ -20,7 +20,7 @@
#include <stdint.h>
#include <stdbool.h>
#include "quantum.h"
-#include "ledmatrix.h"
+#include "led_matrix.h"
#include "progmem.h"
#include "config.h"
#include "eeprom.h"
diff --git a/quantum/ledmatrix.h b/quantum/led_matrix.h
index 5867ba9876..5867ba9876 100644
--- a/quantum/ledmatrix.h
+++ b/quantum/led_matrix.h
diff --git a/quantum/led_matrix_drivers.c b/quantum/led_matrix_drivers.c
index 6877bf4c6b..9decaa33c2 100644
--- a/quantum/led_matrix_drivers.c
+++ b/quantum/led_matrix_drivers.c
@@ -18,7 +18,7 @@
#include <stdint.h>
#include <stdbool.h>
#include "quantum.h"
-#include "ledmatrix.h"
+#include "led_matrix.h"
/* Each driver needs to define a struct:
*
diff --git a/quantum/matrix.c b/quantum/matrix.c
index c68c56cac2..cab0d2ddca 100644
--- a/quantum/matrix.c
+++ b/quantum/matrix.c
@@ -32,6 +32,19 @@ static const pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
extern matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values
extern matrix_row_t matrix[MATRIX_ROWS]; // debounced values
+static inline void setPinOutput_writeLow(pin_t pin) {
+ ATOMIC_BLOCK_FORCEON {
+ setPinOutput(pin);
+ writePinLow(pin);
+ }
+}
+
+static inline void setPinInputHigh_atomic(pin_t pin) {
+ ATOMIC_BLOCK_FORCEON {
+ setPinInputHigh(pin);
+ }
+}
+
// matrix code
#ifdef DIRECT_PINS
@@ -70,22 +83,23 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
# if (DIODE_DIRECTION == COL2ROW)
static void select_row(uint8_t row) {
- setPinOutput(row_pins[row]);
- writePinLow(row_pins[row]);
+ setPinOutput_writeLow(row_pins[row]);
}
-static void unselect_row(uint8_t row) { setPinInputHigh(row_pins[row]); }
+static void unselect_row(uint8_t row) {
+ setPinInputHigh_atomic(row_pins[row]);
+}
static void unselect_rows(void) {
for (uint8_t x = 0; x < MATRIX_ROWS; x++) {
- setPinInputHigh(row_pins[x]);
+ setPinInputHigh_atomic(row_pins[x]);
}
}
static void init_pins(void) {
unselect_rows();
for (uint8_t x = 0; x < MATRIX_COLS; x++) {
- setPinInputHigh(col_pins[x]);
+ setPinInputHigh_atomic(col_pins[x]);
}
}
@@ -120,22 +134,23 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
# elif (DIODE_DIRECTION == ROW2COL)
static void select_col(uint8_t col) {
- setPinOutput(col_pins[col]);
- writePinLow(col_pins[col]);
+ setPinOutput_writeLow(col_pins[col]);
}
-static void unselect_col(uint8_t col) { setPinInputHigh(col_pins[col]); }
+static void unselect_col(uint8_t col) {
+ setPinInputHigh_atomic(col_pins[col]);
+}
static void unselect_cols(void) {
for (uint8_t x = 0; x < MATRIX_COLS; x++) {
- setPinInputHigh(col_pins[x]);
+ setPinInputHigh_atomic(col_pins[x]);
}
}
static void init_pins(void) {
unselect_cols();
for (uint8_t x = 0; x < MATRIX_ROWS; x++) {
- setPinInputHigh(row_pins[x]);
+ setPinInputHigh_atomic(row_pins[x]);
}
}
diff --git a/quantum/mcu_selection.mk b/quantum/mcu_selection.mk
index 6fb5f88b05..ea88d9ab9e 100644
--- a/quantum/mcu_selection.mk
+++ b/quantum/mcu_selection.mk
@@ -318,6 +318,9 @@ ifneq (,$(filter $(MCU),atmega16u2 atmega32u2 atmega16u4 atmega32u4 at90usb646 a
ifeq (,$(filter $(NO_INTERRUPT_CONTROL_ENDPOINT),yes))
OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT
endif
+ ifneq (,$(filter $(MCU),atmega16u2 atmega32u2))
+ NO_I2C = yes
+ endif
endif
ifneq (,$(filter $(MCU),atmega32a))
diff --git a/quantum/process_keycode/process_auto_shift.c b/quantum/process_keycode/process_auto_shift.c
index 76530959c9..41e60496b9 100644
--- a/quantum/process_keycode/process_auto_shift.c
+++ b/quantum/process_keycode/process_auto_shift.c
@@ -16,49 +16,149 @@
#ifdef AUTO_SHIFT_ENABLE
+# include <stdbool.h>
# include <stdio.h>
# include "process_auto_shift.h"
-static bool autoshift_enabled = true;
-static uint16_t autoshift_time = 0;
+static uint16_t autoshift_time = 0;
static uint16_t autoshift_timeout = AUTO_SHIFT_TIMEOUT;
static uint16_t autoshift_lastkey = KC_NO;
+static struct {
+ // Whether autoshift is enabled.
+ bool enabled : 1;
+ // Whether the last auto-shifted key was released after the timeout. This
+ // is used to replicate the last key for a tap-then-hold.
+ bool lastshifted : 1;
+ // Whether an auto-shiftable key has been pressed but not processed.
+ bool in_progress : 1;
+ // Whether the auto-shifted keypress has been registered.
+ bool holding_shift : 1;
+} autoshift_flags = {true, false, false, false};
+
+/** \brief Record the press of an autoshiftable key
+ *
+ * \return Whether the record should be further processed.
+ */
+static bool autoshift_press(uint16_t keycode, uint16_t now, keyrecord_t *record) {
+ if (!autoshift_flags.enabled) {
+ return true;
+ }
-void autoshift_flush(void) {
- if (autoshift_lastkey != KC_NO) {
- uint16_t elapsed = timer_elapsed(autoshift_time);
+# ifndef AUTO_SHIFT_MODIFIERS
+ if (get_mods() & (~MOD_BIT(KC_LSFT))) {
+ return true;
+ }
+# endif
+# ifdef AUTO_SHIFT_REPEAT
+ const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time);
+# ifndef AUTO_SHIFT_NO_AUTO_REPEAT
+ if (!autoshift_flags.lastshifted) {
+# endif
+ if (elapsed < TAPPING_TERM && keycode == autoshift_lastkey) {
+ // Allow a tap-then-hold for keyrepeat.
+ if (!autoshift_flags.lastshifted) {
+ register_code(autoshift_lastkey);
+ } else {
+ // Simulate pressing the shift key.
+ add_weak_mods(MOD_BIT(KC_LSFT));
+ register_code(autoshift_lastkey);
+ }
+ return false;
+ }
+# ifndef AUTO_SHIFT_NO_AUTO_REPEAT
+ }
+# endif
+# endif
+
+ // Record the keycode so we can simulate it later.
+ autoshift_lastkey = keycode;
+ autoshift_time = now;
+ autoshift_flags.in_progress = true;
- if (elapsed > autoshift_timeout) {
- tap_code16(LSFT(autoshift_lastkey));
+# if !defined(NO_ACTION_ONESHOT) && !defined(NO_ACTION_TAPPING)
+ clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
+# endif
+ return false;
+}
+
+/** \brief Registers an autoshiftable key under the right conditions
+ *
+ * If the autoshift delay has elapsed, register a shift and the key.
+ *
+ * If the autoshift key is released before the delay has elapsed, register the
+ * key without a shift.
+ */
+static void autoshift_end(uint16_t keycode, uint16_t now, bool matrix_trigger) {
+ // Called on key down with KC_NO, auto-shifted key up, and timeout.
+ if (autoshift_flags.in_progress) {
+ // Process the auto-shiftable key.
+ autoshift_flags.in_progress = false;
+
+ // Time since the initial press was recorded.
+ const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time);
+ if (elapsed < autoshift_timeout) {
+ register_code(autoshift_lastkey);
+ autoshift_flags.lastshifted = false;
} else {
- tap_code(autoshift_lastkey);
+ // Simulate pressing the shift key.
+ add_weak_mods(MOD_BIT(KC_LSFT));
+ register_code(autoshift_lastkey);
+ autoshift_flags.lastshifted = true;
+# if defined(AUTO_SHIFT_REPEAT) && !defined(AUTO_SHIFT_NO_AUTO_REPEAT)
+ if (matrix_trigger) {
+ // Prevents release.
+ return;
+ }
+# endif
}
- autoshift_time = 0;
- autoshift_lastkey = KC_NO;
+# if TAP_CODE_DELAY > 0
+ wait_ms(TAP_CODE_DELAY);
+# endif
+ unregister_code(autoshift_lastkey);
+ del_weak_mods(MOD_BIT(KC_LSFT));
+ } else {
+ // Release after keyrepeat.
+ unregister_code(keycode);
+ if (keycode == autoshift_lastkey) {
+ // This will only fire when the key was the last auto-shiftable
+ // pressed. That prevents aaaaBBBB then releasing a from unshifting
+ // later Bs (if B wasn't auto-shiftable).
+ del_weak_mods(MOD_BIT(KC_LSFT));
+ }
}
+ send_keyboard_report(); // del_weak_mods doesn't send one.
+ // Roll the autoshift_time forward for detecting tap-and-hold.
+ autoshift_time = now;
}
-
-void autoshift_on(uint16_t keycode) {
- autoshift_time = timer_read();
- autoshift_lastkey = keycode;
+/** \brief Simulates auto-shifted key releases when timeout is hit
+ *
+ * Can be called from \c matrix_scan_user so that auto-shifted keys are sent
+ * immediately after the timeout has expired, rather than waiting for the key
+ * to be released.
+ */
+void autoshift_matrix_scan(void) {
+ if (autoshift_flags.in_progress) {
+ const uint16_t now = timer_read();
+ const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time);
+ if (elapsed >= autoshift_timeout) {
+ autoshift_end(autoshift_lastkey, now, true);
+ }
+ }
}
void autoshift_toggle(void) {
- if (autoshift_enabled) {
- autoshift_enabled = false;
- autoshift_flush();
- } else {
- autoshift_enabled = true;
- }
+ autoshift_flags.enabled = !autoshift_flags.enabled;
+ del_weak_mods(MOD_BIT(KC_LSFT));
}
-void autoshift_enable(void) { autoshift_enabled = true; }
+void autoshift_enable(void) { autoshift_flags.enabled = true; }
+
void autoshift_disable(void) {
- autoshift_enabled = false;
- autoshift_flush();
+ autoshift_flags.enabled = false;
+ del_weak_mods(MOD_BIT(KC_LSFT));
}
# ifndef AUTO_SHIFT_NO_SETUP
@@ -71,24 +171,30 @@ void autoshift_timer_report(void) {
}
# endif
-bool get_autoshift_state(void) { return autoshift_enabled; }
+bool get_autoshift_state(void) { return autoshift_flags.enabled; }
-uint16_t get_autoshift_timeout(void) {
- return autoshift_timeout;
-}
+uint16_t get_autoshift_timeout(void) { return autoshift_timeout; }
-void set_autoshift_timeout(uint16_t timeout) {
- autoshift_timeout = timeout;
-}
+void set_autoshift_timeout(uint16_t timeout) { autoshift_timeout = timeout; }
bool process_auto_shift(uint16_t keycode, keyrecord_t *record) {
+ // Note that record->event.time isn't reliable, see:
+ // https://github.com/qmk/qmk_firmware/pull/9826#issuecomment-733559550
+ const uint16_t now = timer_read();
if (record->event.pressed) {
+ if (autoshift_flags.in_progress) {
+ // Evaluate previous key if there is one. Doing this elsewhere is
+ // more complicated and easier to break.
+ autoshift_end(KC_NO, now, false);
+ }
+ // For pressing another key while keyrepeating shifted autoshift.
+ del_weak_mods(MOD_BIT(KC_LSFT));
+
switch (keycode) {
case KC_ASTG:
autoshift_toggle();
return true;
-
case KC_ASON:
autoshift_enable();
return true;
@@ -108,43 +214,30 @@ bool process_auto_shift(uint16_t keycode, keyrecord_t *record) {
autoshift_timer_report();
return true;
# endif
+ }
+ }
+
+ switch (keycode) {
# ifndef NO_AUTO_SHIFT_ALPHA
- case KC_A ... KC_Z:
+ case KC_A ... KC_Z:
# endif
# ifndef NO_AUTO_SHIFT_NUMERIC
- case KC_1 ... KC_0:
+ case KC_1 ... KC_0:
# endif
# ifndef NO_AUTO_SHIFT_SPECIAL
-# ifndef NO_AUTO_SHIFT_TAB
- case KC_TAB:
-# endif
- case KC_MINUS ... KC_SLASH:
- case KC_NONUS_BSLASH:
-# endif
- autoshift_flush();
- if (!autoshift_enabled) return true;
-
-# ifndef AUTO_SHIFT_MODIFIERS
- if (get_mods()) {
- return true;
- }
-# endif
- autoshift_on(keycode);
-
- // We need some extra handling here for OSL edge cases
-# if !defined(NO_ACTION_ONESHOT) && !defined(NO_ACTION_TAPPING)
- clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
+# ifndef NO_AUTO_SHIFT_TAB
+ case KC_TAB:
+# endif
+ case KC_MINUS ... KC_SLASH:
+ case KC_NONUS_BSLASH:
# endif
+ if (record->event.pressed) {
+ return autoshift_press(keycode, now, record);
+ } else {
+ autoshift_end(keycode, now, false);
return false;
-
- default:
- autoshift_flush();
- return true;
- }
- } else {
- autoshift_flush();
+ }
}
-
return true;
}
diff --git a/quantum/process_keycode/process_auto_shift.h b/quantum/process_keycode/process_auto_shift.h
index b909d28eef..5b2718f11c 100644
--- a/quantum/process_keycode/process_auto_shift.h
+++ b/quantum/process_keycode/process_auto_shift.h
@@ -24,9 +24,10 @@
bool process_auto_shift(uint16_t keycode, keyrecord_t *record);
-void autoshift_enable(void);
-void autoshift_disable(void);
-void autoshift_toggle(void);
-bool get_autoshift_state(void);
+void autoshift_enable(void);
+void autoshift_disable(void);
+void autoshift_toggle(void);
+bool get_autoshift_state(void);
uint16_t get_autoshift_timeout(void);
-void set_autoshift_timeout(uint16_t timeout);
+void set_autoshift_timeout(uint16_t timeout);
+void autoshift_matrix_scan(void);
diff --git a/quantum/process_keycode/process_joystick.c b/quantum/process_keycode/process_joystick.c
index 5778a7434c..3ffaf42bf8 100644
--- a/quantum/process_keycode/process_joystick.c
+++ b/quantum/process_keycode/process_joystick.c
@@ -129,17 +129,17 @@ bool process_joystick_analogread_quantum() {
// test the converted value against the lower range
int32_t ref = joystick_axes[axis_index].mid_digit;
int32_t range = joystick_axes[axis_index].min_digit;
- int32_t ranged_val = ((axis_val - ref) * -127) / (range - ref);
+ int32_t ranged_val = ((axis_val - ref) * -JOYSTICK_RESOLUTION) / (range - ref);
if (ranged_val > 0) {
// the value is in the higher range
range = joystick_axes[axis_index].max_digit;
- ranged_val = ((axis_val - ref) * 127) / (range - ref);
+ ranged_val = ((axis_val - ref) * JOYSTICK_RESOLUTION) / (range - ref);
}
// clamp the result in the valid range
- ranged_val = ranged_val < -127 ? -127 : ranged_val;
- ranged_val = ranged_val > 127 ? 127 : ranged_val;
+ ranged_val = ranged_val < -JOYSTICK_RESOLUTION ? -JOYSTICK_RESOLUTION : ranged_val;
+ ranged_val = ranged_val > JOYSTICK_RESOLUTION ? JOYSTICK_RESOLUTION : ranged_val;
if (ranged_val != joystick_status.axes[axis_index]) {
joystick_status.axes[axis_index] = ranged_val;
diff --git a/quantum/process_keycode/process_midi.c b/quantum/process_keycode/process_midi.c
index e525770144..8e2fb955e7 100644
--- a/quantum/process_keycode/process_midi.c
+++ b/quantum/process_keycode/process_midi.c
@@ -41,12 +41,12 @@ static int8_t midi_modulation_step;
static uint16_t midi_modulation_timer;
midi_config_t midi_config;
-inline uint8_t compute_velocity(uint8_t setting) { return (setting + 1) * (128 / (MIDI_VELOCITY_MAX - MIDI_VELOCITY_MIN + 1)); }
+inline uint8_t compute_velocity(uint8_t setting) { return setting * (128 / (MIDI_VELOCITY_MAX - MIDI_VELOCITY_MIN)); }
void midi_init(void) {
midi_config.octave = MI_OCT_2 - MIDI_OCTAVE_MIN;
midi_config.transpose = 0;
- midi_config.velocity = (MIDI_VELOCITY_MAX - MIDI_VELOCITY_MIN);
+ midi_config.velocity = 127;
midi_config.channel = 0;
midi_config.modulation_interval = 8;
@@ -66,7 +66,7 @@ bool process_midi(uint16_t keycode, keyrecord_t *record) {
case MIDI_TONE_MIN ... MIDI_TONE_MAX: {
uint8_t channel = midi_config.channel;
uint8_t tone = keycode - MIDI_TONE_MIN;
- uint8_t velocity = compute_velocity(midi_config.velocity);
+ uint8_t velocity = midi_config.velocity;
if (record->event.pressed) {
if (tone_status[tone] == MIDI_INVALID_NOTE) {
uint8_t note = midi_compute_note(keycode);
@@ -124,19 +124,30 @@ bool process_midi(uint16_t keycode, keyrecord_t *record) {
return false;
case MIDI_VELOCITY_MIN ... MIDI_VELOCITY_MAX:
if (record->event.pressed) {
- midi_config.velocity = keycode - MIDI_VELOCITY_MIN;
+ midi_config.velocity = compute_velocity(keycode - MIDI_VELOCITY_MIN);
dprintf("midi velocity %d\n", midi_config.velocity);
}
return false;
case MI_VELD:
if (record->event.pressed && midi_config.velocity > 0) {
- midi_config.velocity--;
+ if (midi_config.velocity == 127) {
+ midi_config.velocity -= 10;
+ } else if (midi_config.velocity > 12) {
+ midi_config.velocity -= 13;
+ } else {
+ midi_config.velocity = 0;
+ }
+
dprintf("midi velocity %d\n", midi_config.velocity);
}
return false;
case MI_VELU:
- if (record->event.pressed) {
- midi_config.velocity++;
+ if (record->event.pressed && midi_config.velocity < 127) {
+ if (midi_config.velocity < 115) {
+ midi_config.velocity += 13;
+ } else {
+ midi_config.velocity = 127;
+ }
dprintf("midi velocity %d\n", midi_config.velocity);
}
return false;
diff --git a/quantum/process_keycode/process_midi.h b/quantum/process_keycode/process_midi.h
index 0007b3ed25..ef5661dd4d 100644
--- a/quantum/process_keycode/process_midi.h
+++ b/quantum/process_keycode/process_midi.h
@@ -35,7 +35,7 @@ typedef union {
struct {
uint8_t octave : 4;
int8_t transpose : 4;
- uint8_t velocity : 4;
+ uint8_t velocity : 7;
uint8_t channel : 4;
uint8_t modulation_interval : 4;
};
diff --git a/quantum/process_keycode/process_sequencer.c b/quantum/process_keycode/process_sequencer.c
new file mode 100644
index 0000000000..334b4c0092
--- /dev/null
+++ b/quantum/process_keycode/process_sequencer.c
@@ -0,0 +1,62 @@
+/* Copyright 2020 Rodolphe Belouin
+ *
+ * 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 "process_sequencer.h"
+
+bool process_sequencer(uint16_t keycode, keyrecord_t *record) {
+ if (record->event.pressed) {
+ switch (keycode) {
+ case SQ_ON:
+ sequencer_on();
+ return false;
+ case SQ_OFF:
+ sequencer_off();
+ return false;
+ case SQ_TOG:
+ sequencer_toggle();
+ return false;
+ case SQ_TMPD:
+ sequencer_decrease_tempo();
+ return false;
+ case SQ_TMPU:
+ sequencer_increase_tempo();
+ return false;
+ case SEQUENCER_RESOLUTION_MIN ... SEQUENCER_RESOLUTION_MAX:
+ sequencer_set_resolution(keycode - SEQUENCER_RESOLUTION_MIN);
+ return false;
+ case SQ_RESD:
+ sequencer_decrease_resolution();
+ return false;
+ case SQ_RESU:
+ sequencer_increase_resolution();
+ return false;
+ case SQ_SALL:
+ sequencer_set_all_steps_on();
+ return false;
+ case SQ_SCLR:
+ sequencer_set_all_steps_off();
+ return false;
+ case SEQUENCER_STEP_MIN ... SEQUENCER_STEP_MAX:
+ sequencer_toggle_step(keycode - SEQUENCER_STEP_MIN);
+ return false;
+ case SEQUENCER_TRACK_MIN ... SEQUENCER_TRACK_MAX:
+ sequencer_toggle_single_active_track(keycode - SEQUENCER_TRACK_MIN);
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/quantum/process_keycode/process_sequencer.h b/quantum/process_keycode/process_sequencer.h
new file mode 100644
index 0000000000..2b85f24299
--- /dev/null
+++ b/quantum/process_keycode/process_sequencer.h
@@ -0,0 +1,21 @@
+/* Copyright 2020 Rodolphe Belouin
+ *
+ * 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/>.
+ */
+
+#pragma once
+
+#include "quantum.h"
+
+bool process_sequencer(uint16_t keycode, keyrecord_t *record);
diff --git a/quantum/quantum.c b/quantum/quantum.c
index 4f21e6eea9..0af3f62c4d 100644
--- a/quantum/quantum.c
+++ b/quantum/quantum.c
@@ -55,6 +55,10 @@ float default_layer_songs[][16][2] = DEFAULT_LAYER_SONGS;
# endif
#endif
+#ifdef AUTO_SHIFT_ENABLE
+# include "process_auto_shift.h"
+#endif
+
static void do_code16(uint16_t code, void (*f)(uint8_t)) {
switch (code) {
case QK_MODS ... QK_MODS_MAX:
@@ -228,6 +232,9 @@ bool process_record_quantum(keyrecord_t *record) {
process_record_via(keycode, record) &&
#endif
process_record_kb(keycode, record) &&
+#if defined(SEQUENCER_ENABLE)
+ process_sequencer(keycode, record) &&
+#endif
#if defined(MIDI_ENABLE) && defined(MIDI_ADVANCED)
process_midi(keycode, record) &&
#endif
@@ -649,6 +656,10 @@ void matrix_scan_quantum() {
matrix_scan_music();
#endif
+#ifdef SEQUENCER_ENABLE
+ matrix_scan_sequencer();
+#endif
+
#ifdef TAP_DANCE_ENABLE
matrix_scan_tap_dance();
#endif
@@ -677,6 +688,10 @@ void matrix_scan_quantum() {
dip_switch_read(false);
#endif
+#ifdef AUTO_SHIFT_ENABLE
+ autoshift_matrix_scan();
+#endif
+
matrix_scan_kb();
}
diff --git a/quantum/quantum.h b/quantum/quantum.h
index 2c06578652..94188a8543 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -31,7 +31,7 @@
#ifdef BACKLIGHT_ENABLE
# ifdef LED_MATRIX_ENABLE
-# include "ledmatrix.h"
+# include "led_matrix.h"
# else
# include "backlight.h"
# endif
@@ -68,6 +68,11 @@ extern layer_state_t default_layer_state;
extern layer_state_t layer_state;
#endif
+#if defined(SEQUENCER_ENABLE)
+# include "sequencer.h"
+# include "process_sequencer.h"
+#endif
+
#if defined(MIDI_ENABLE) && defined(MIDI_ADVANCED)
# include "process_midi.h"
#endif
@@ -229,6 +234,61 @@ typedef ioline_t pin_t;
# define togglePin(pin) palToggleLine(pin)
#endif
+// Atomic macro to help make GPIO and other controls atomic.
+#ifdef IGNORE_ATOMIC_BLOCK
+/* do nothing atomic macro */
+# define ATOMIC_BLOCK for (uint8_t __ToDo = 1; __ToDo; __ToDo = 0)
+# define ATOMIC_BLOCK_RESTORESTATE ATOMIC_BLOCK
+# define ATOMIC_BLOCK_FORCEON ATOMIC_BLOCK
+
+#elif defined(__AVR__)
+/* atomic macro for AVR */
+# include <util/atomic.h>
+
+# define ATOMIC_BLOCK_RESTORESTATE ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
+# define ATOMIC_BLOCK_FORCEON ATOMIC_BLOCK(ATOMIC_FORCEON)
+
+#elif defined(PROTOCOL_CHIBIOS) || defined(PROTOCOL_ARM_ATSAM)
+/* atomic macro for ChibiOS / ARM ATSAM */
+# if defined(PROTOCOL_ARM_ATSAM)
+# include "arm_atsam_protocol.h"
+# endif
+
+static __inline__ uint8_t __interrupt_disable__(void) {
+# if defined(PROTOCOL_CHIBIOS)
+ chSysLock();
+# endif
+# if defined(PROTOCOL_ARM_ATSAM)
+ __disable_irq();
+# endif
+ return 1;
+}
+
+static __inline__ void __interrupt_enable__(const uint8_t *__s) {
+# if defined(PROTOCOL_CHIBIOS)
+ chSysUnlock();
+# endif
+# if defined(PROTOCOL_ARM_ATSAM)
+ __enable_irq();
+# endif
+ __asm__ volatile("" ::: "memory");
+ (void)__s;
+}
+
+# define ATOMIC_BLOCK(type) for (type, __ToDo = __interrupt_disable__(); __ToDo; __ToDo = 0)
+# define ATOMIC_FORCEON uint8_t sreg_save __attribute__((__cleanup__(__interrupt_enable__))) = 0
+
+# define ATOMIC_BLOCK_RESTORESTATE _Static_assert(0, "ATOMIC_BLOCK_RESTORESTATE dose not implement")
+# define ATOMIC_BLOCK_FORCEON ATOMIC_BLOCK(ATOMIC_FORCEON)
+
+/* Other platform */
+#else
+
+# define ATOMIC_BLOCK_RESTORESTATE _Static_assert(0, "ATOMIC_BLOCK_RESTORESTATE dose not implement")
+# define ATOMIC_BLOCK_FORCEON _Static_assert(0, "ATOMIC_BLOCK_FORCEON dose not implement")
+
+#endif
+
#define SEND_STRING(string) send_string_P(PSTR(string))
#define SEND_STRING_DELAY(string, interval) send_string_with_delay_P(PSTR(string), interval)
diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h
index 38618964e3..34102aab2d 100644
--- a/quantum/quantum_keycodes.h
+++ b/quantum/quantum_keycodes.h
@@ -16,6 +16,10 @@
#ifndef QUANTUM_KEYCODES_H
#define QUANTUM_KEYCODES_H
+#if defined(SEQUENCER_ENABLE)
+# include "sequencer.h"
+#endif
+
#ifndef MIDI_ENABLE_STRICT
# define MIDI_ENABLE_STRICT 0
#endif
@@ -343,7 +347,8 @@ enum quantum_keycodes {
MI_TRNSU, // transpose up
MIDI_VELOCITY_MIN,
- MI_VEL_1 = MIDI_VELOCITY_MIN,
+ MI_VEL_0 = MIDI_VELOCITY_MIN,
+ MI_VEL_1,
MI_VEL_2,
MI_VEL_3,
MI_VEL_4,
@@ -551,6 +556,37 @@ enum quantum_keycodes {
JS_BUTTON31,
JS_BUTTON_MAX = JS_BUTTON31,
+#if defined(SEQUENCER_ENABLE)
+ SQ_ON,
+ SQ_OFF,
+ SQ_TOG,
+
+ SQ_TMPD, // Decrease tempo
+ SQ_TMPU, // Increase tempo
+
+ SEQUENCER_RESOLUTION_MIN,
+ SEQUENCER_RESOLUTION_MAX = SEQUENCER_RESOLUTION_MIN + SEQUENCER_RESOLUTIONS,
+ SQ_RESD, // Decrease resolution
+ SQ_RESU, // Increase resolution
+
+ SQ_SALL, // All steps on
+ SQ_SCLR, // All steps off
+ SEQUENCER_STEP_MIN,
+ SEQUENCER_STEP_MAX = SEQUENCER_STEP_MIN + SEQUENCER_STEPS,
+
+ SEQUENCER_TRACK_MIN,
+ SEQUENCER_TRACK_MAX = SEQUENCER_TRACK_MIN + SEQUENCER_TRACKS,
+
+/**
+ * Helpers to assign a keycode to a step, a resolution, or a track.
+ * Falls back to NOOP if n is out of range.
+ */
+# define SQ_S(n) (n < SEQUENCER_STEPS ? SEQUENCER_STEP_MIN + n : XXXXXXX)
+# define SQ_R(n) (n < SEQUENCER_RESOLUTIONS ? SEQUENCER_RESOLUTION_MIN + n : XXXXXXX)
+# define SQ_T(n) (n < SEQUENCER_TRACKS ? SEQUENCER_TRACK_MIN + n : XXXXXXX)
+
+#endif
+
// always leave at the end
SAFE_RANGE
};
diff --git a/quantum/rgb_matrix.c b/quantum/rgb_matrix.c
index 2a55a8926f..404e5bc1f9 100644
--- a/quantum/rgb_matrix.c
+++ b/quantum/rgb_matrix.c
@@ -31,6 +31,8 @@ const point_t k_rgb_matrix_center = {112, 32};
const point_t k_rgb_matrix_center = RGB_MATRIX_CENTER;
#endif
+__attribute__((weak)) RGB rgb_matrix_hsv_to_rgb(HSV hsv) { return hsv_to_rgb(hsv); }
+
// Generic effect runners
#include "rgb_matrix_runners/effect_runner_dx_dy_dist.h"
#include "rgb_matrix_runners/effect_runner_dx_dy.h"
@@ -402,6 +404,10 @@ void rgb_matrix_task(void) {
break;
case RENDERING:
rgb_task_render(effect);
+ if (!suspend_backlight) {
+ rgb_matrix_indicators();
+ rgb_matrix_indicators_advanced(&rgb_effect_params);
+ }
break;
case FLUSHING:
rgb_task_flush(effect);
@@ -410,10 +416,6 @@ void rgb_matrix_task(void) {
rgb_task_sync();
break;
}
-
- if (!suspend_backlight) {
- rgb_matrix_indicators();
- }
}
void rgb_matrix_indicators(void) {
@@ -425,6 +427,28 @@ __attribute__((weak)) void rgb_matrix_indicators_kb(void) {}
__attribute__((weak)) void rgb_matrix_indicators_user(void) {}
+void rgb_matrix_indicators_advanced(effect_params_t *params) {
+ /* special handling is needed for "params->iter", since it's already been incremented.
+ * Could move the invocations to rgb_task_render, but then it's missing a few checks
+ * and not sure which would be better. Otherwise, this should be called from
+ * rgb_task_render, right before the iter++ line.
+ */
+#if defined(RGB_MATRIX_LED_PROCESS_LIMIT) && RGB_MATRIX_LED_PROCESS_LIMIT > 0 && RGB_MATRIX_LED_PROCESS_LIMIT < DRIVER_LED_TOTAL
+ uint8_t min = RGB_MATRIX_LED_PROCESS_LIMIT * (params->iter - 1);
+ uint8_t max = min + RGB_MATRIX_LED_PROCESS_LIMIT;
+ if (max > DRIVER_LED_TOTAL) max = DRIVER_LED_TOTAL;
+#else
+ uint8_t min = 0;
+ uint8_t max = DRIVER_LED_TOTAL;
+#endif
+ rgb_matrix_indicators_advanced_kb(min, max);
+ rgb_matrix_indicators_advanced_user(min, max);
+}
+
+__attribute__((weak)) void rgb_matrix_indicators_advanced_kb(uint8_t led_min, uint8_t led_max) {}
+
+__attribute__((weak)) void rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {}
+
void rgb_matrix_init(void) {
rgb_matrix_driver.init();
diff --git a/quantum/rgb_matrix.h b/quantum/rgb_matrix.h
index 733333349f..771a1fcd35 100644
--- a/quantum/rgb_matrix.h
+++ b/quantum/rgb_matrix.h
@@ -57,6 +57,11 @@
uint8_t max = DRIVER_LED_TOTAL;
#endif
+#define RGB_MATRIX_INDICATOR_SET_COLOR(i, r, g, b) \
+ if (i >= led_min && i <= led_max) { \
+ rgb_matrix_set_color(i, r, g, b); \
+ }
+
#define RGB_MATRIX_TEST_LED_FLAGS() \
if (!HAS_ANY_FLAGS(g_led_config.flags[i], params->flags)) continue
@@ -103,6 +108,10 @@ void rgb_matrix_indicators(void);
void rgb_matrix_indicators_kb(void);
void rgb_matrix_indicators_user(void);
+void rgb_matrix_indicators_advanced(effect_params_t *params);
+void rgb_matrix_indicators_advanced_kb(uint8_t led_min, uint8_t led_max);
+void rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max);
+
void rgb_matrix_init(void);
void rgb_matrix_set_suspend_state(bool state);
diff --git a/quantum/rgb_matrix_animations/alpha_mods_anim.h b/quantum/rgb_matrix_animations/alpha_mods_anim.h
index 0778ab2098..426d88ef35 100644
--- a/quantum/rgb_matrix_animations/alpha_mods_anim.h
+++ b/quantum/rgb_matrix_animations/alpha_mods_anim.h
@@ -7,9 +7,9 @@ bool ALPHAS_MODS(effect_params_t* params) {
RGB_MATRIX_USE_LIMITS(led_min, led_max);
HSV hsv = rgb_matrix_config.hsv;
- RGB rgb1 = hsv_to_rgb(hsv);
+ RGB rgb1 = rgb_matrix_hsv_to_rgb(hsv);
hsv.h += rgb_matrix_config.speed;
- RGB rgb2 = hsv_to_rgb(hsv);
+ RGB rgb2 = rgb_matrix_hsv_to_rgb(hsv);
for (uint8_t i = led_min; i < led_max; i++) {
RGB_MATRIX_TEST_LED_FLAGS();
diff --git a/quantum/rgb_matrix_animations/breathing_anim.h b/quantum/rgb_matrix_animations/breathing_anim.h
index 887425f9da..340bd93e5d 100644
--- a/quantum/rgb_matrix_animations/breathing_anim.h
+++ b/quantum/rgb_matrix_animations/breathing_anim.h
@@ -8,7 +8,7 @@ bool BREATHING(effect_params_t* params) {
HSV hsv = rgb_matrix_config.hsv;
uint16_t time = scale16by8(g_rgb_timer, rgb_matrix_config.speed / 8);
hsv.v = scale8(abs8(sin8(time) - 128) * 2, hsv.v);
- RGB rgb = hsv_to_rgb(hsv);
+ RGB rgb = rgb_matrix_hsv_to_rgb(hsv);
for (uint8_t i = led_min; i < led_max; i++) {
RGB_MATRIX_TEST_LED_FLAGS();
rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
diff --git a/quantum/rgb_matrix_animations/gradient_left_right_anim.h b/quantum/rgb_matrix_animations/gradient_left_right_anim.h
index 2eab2eb759..53dfd04e2c 100644
--- a/quantum/rgb_matrix_animations/gradient_left_right_anim.h
+++ b/quantum/rgb_matrix_animations/gradient_left_right_anim.h
@@ -12,7 +12,7 @@ bool GRADIENT_LEFT_RIGHT(effect_params_t* params) {
// The x range will be 0..224, map this to 0..7
// Relies on hue being 8-bit and wrapping
hsv.h = rgb_matrix_config.hsv.h + (scale * g_led_config.point[i].x >> 5);
- RGB rgb = hsv_to_rgb(hsv);
+ RGB rgb = rgb_matrix_hsv_to_rgb(hsv);
rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
}
return led_max < DRIVER_LED_TOTAL;
diff --git a/quantum/rgb_matrix_animations/gradient_up_down_anim.h b/quantum/rgb_matrix_animations/gradient_up_down_anim.h
index 0f1f8e23cf..7e0d2898cf 100644
--- a/quantum/rgb_matrix_animations/gradient_up_down_anim.h
+++ b/quantum/rgb_matrix_animations/gradient_up_down_anim.h
@@ -12,7 +12,7 @@ bool GRADIENT_UP_DOWN(effect_params_t* params) {
// The y range will be 0..64, map this to 0..4
// Relies on hue being 8-bit and wrapping
hsv.h = rgb_matrix_config.hsv.h + scale * (g_led_config.point[i].y >> 4);
- RGB rgb = hsv_to_rgb(hsv);
+ RGB rgb = rgb_matrix_hsv_to_rgb(hsv);
rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
}
return led_max < DRIVER_LED_TOTAL;
diff --git a/quantum/rgb_matrix_animations/jellybean_raindrops_anim.h b/quantum/rgb_matrix_animations/jellybean_raindrops_anim.h
index ef2d1500b0..9493b38508 100644
--- a/quantum/rgb_matrix_animations/jellybean_raindrops_anim.h
+++ b/quantum/rgb_matrix_animations/jellybean_raindrops_anim.h
@@ -5,7 +5,7 @@ RGB_MATRIX_EFFECT(JELLYBEAN_RAINDROPS)
static void jellybean_raindrops_set_color(int i, effect_params_t* params) {
if (!HAS_ANY_FLAGS(g_led_config.flags[i], params->flags)) return;
HSV hsv = {rand() & 0xFF, rand() & 0xFF, rgb_matrix_config.hsv.v};
- RGB rgb = hsv_to_rgb(hsv);
+ RGB rgb = rgb_matrix_hsv_to_rgb(hsv);
rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
}
diff --git a/quantum/rgb_matrix_animations/raindrops_anim.h b/quantum/rgb_matrix_animations/raindrops_anim.h
index 6e1b5acb0d..38359cdca7 100644
--- a/quantum/rgb_matrix_animations/raindrops_anim.h
+++ b/quantum/rgb_matrix_animations/raindrops_anim.h
@@ -15,7 +15,7 @@ static void raindrops_set_color(int i, effect_params_t* params) {
}
hsv.h = rgb_matrix_config.hsv.h + (deltaH * (rand() & 0x03));
- RGB rgb = hsv_to_rgb(hsv);
+ RGB rgb = rgb_matrix_hsv_to_rgb(hsv);
rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
}
diff --git a/quantum/rgb_matrix_animations/solid_color_anim.h b/quantum/rgb_matrix_animations/solid_color_anim.h
index c8f5e70e7a..79d63cf133 100644
--- a/quantum/rgb_matrix_animations/solid_color_anim.h
+++ b/quantum/rgb_matrix_animations/solid_color_anim.h
@@ -4,7 +4,7 @@ RGB_MATRIX_EFFECT(SOLID_COLOR)
bool SOLID_COLOR(effect_params_t* params) {
RGB_MATRIX_USE_LIMITS(led_min, led_max);
- RGB rgb = hsv_to_rgb(rgb_matrix_config.hsv);
+ RGB rgb = rgb_matrix_hsv_to_rgb(rgb_matrix_config.hsv);
for (uint8_t i = led_min; i < led_max; i++) {
RGB_MATRIX_TEST_LED_FLAGS();
rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
diff --git a/quantum/rgb_matrix_animations/typing_heatmap_anim.h b/quantum/rgb_matrix_animations/typing_heatmap_anim.h
index e82c1b49ee..b855fdc190 100644
--- a/quantum/rgb_matrix_animations/typing_heatmap_anim.h
+++ b/quantum/rgb_matrix_animations/typing_heatmap_anim.h
@@ -51,7 +51,7 @@ bool TYPING_HEATMAP(effect_params_t* params) {
if (!HAS_ANY_FLAGS(g_led_config.flags[led[j]], params->flags)) continue;
HSV hsv = {170 - qsub8(val, 85), rgb_matrix_config.hsv.s, scale8((qadd8(170, val) - 170) * 3, rgb_matrix_config.hsv.v)};
- RGB rgb = hsv_to_rgb(hsv);
+ RGB rgb = rgb_matrix_hsv_to_rgb(hsv);
rgb_matrix_set_color(led[j], rgb.r, rgb.g, rgb.b);
}
diff --git a/quantum/rgb_matrix_runners/effect_runner_dx_dy.h b/quantum/rgb_matrix_runners/effect_runner_dx_dy.h
index 9d0c9fab19..4867609c81 100644
--- a/quantum/rgb_matrix_runners/effect_runner_dx_dy.h
+++ b/quantum/rgb_matrix_runners/effect_runner_dx_dy.h
@@ -10,7 +10,7 @@ bool effect_runner_dx_dy(effect_params_t* params, dx_dy_f effect_func) {
RGB_MATRIX_TEST_LED_FLAGS();
int16_t dx = g_led_config.point[i].x - k_rgb_matrix_center.x;
int16_t dy = g_led_config.point[i].y - k_rgb_matrix_center.y;
- RGB rgb = hsv_to_rgb(effect_func(rgb_matrix_config.hsv, dx, dy, time));
+ RGB rgb = rgb_matrix_hsv_to_rgb(effect_func(rgb_matrix_config.hsv, dx, dy, time));
rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
}
return led_max < DRIVER_LED_TOTAL;
diff --git a/quantum/rgb_matrix_runners/effect_runner_dx_dy_dist.h b/quantum/rgb_matrix_runners/effect_runner_dx_dy_dist.h
index 2824c82527..9545b418d9 100644
--- a/quantum/rgb_matrix_runners/effect_runner_dx_dy_dist.h
+++ b/quantum/rgb_matrix_runners/effect_runner_dx_dy_dist.h
@@ -11,7 +11,7 @@ bool effect_runner_dx_dy_dist(effect_params_t* params, dx_dy_dist_f effect_func)
int16_t dx = g_led_config.point[i].x - k_rgb_matrix_center.x;
int16_t dy = g_led_config.point[i].y - k_rgb_matrix_center.y;
uint8_t dist = sqrt16(dx * dx + dy * dy);
- RGB rgb = hsv_to_rgb(effect_func(rgb_matrix_config.hsv, dx, dy, dist, time));
+ RGB rgb = rgb_matrix_hsv_to_rgb(effect_func(rgb_matrix_config.hsv, dx, dy, dist, time));
rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
}
return led_max < DRIVER_LED_TOTAL;
diff --git a/quantum/rgb_matrix_runners/effect_runner_i.h b/quantum/rgb_matrix_runners/effect_runner_i.h
index 5e6bf5daaf..95bfe8b390 100644
--- a/quantum/rgb_matrix_runners/effect_runner_i.h
+++ b/quantum/rgb_matrix_runners/effect_runner_i.h
@@ -8,7 +8,7 @@ bool effect_runner_i(effect_params_t* params, i_f effect_func) {
uint8_t time = scale16by8(g_rgb_timer, rgb_matrix_config.speed / 4);
for (uint8_t i = led_min; i < led_max; i++) {
RGB_MATRIX_TEST_LED_FLAGS();
- RGB rgb = hsv_to_rgb(effect_func(rgb_matrix_config.hsv, i, time));
+ RGB rgb = rgb_matrix_hsv_to_rgb(effect_func(rgb_matrix_config.hsv, i, time));
rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
}
return led_max < DRIVER_LED_TOTAL;
diff --git a/quantum/rgb_matrix_runners/effect_runner_reactive.h b/quantum/rgb_matrix_runners/effect_runner_reactive.h
index 53e77e3fb2..8485b61f3d 100644
--- a/quantum/rgb_matrix_runners/effect_runner_reactive.h
+++ b/quantum/rgb_matrix_runners/effect_runner_reactive.h
@@ -20,7 +20,7 @@ bool effect_runner_reactive(effect_params_t* params, reactive_f effect_func) {
}
uint16_t offset = scale16by8(tick, rgb_matrix_config.speed);
- RGB rgb = hsv_to_rgb(effect_func(rgb_matrix_config.hsv, offset));
+ RGB rgb = rgb_matrix_hsv_to_rgb(effect_func(rgb_matrix_config.hsv, offset));
rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
}
return led_max < DRIVER_LED_TOTAL;
diff --git a/quantum/rgb_matrix_runners/effect_runner_reactive_splash.h b/quantum/rgb_matrix_runners/effect_runner_reactive_splash.h
index b5d284a40f..5c69d0fbb9 100644
--- a/quantum/rgb_matrix_runners/effect_runner_reactive_splash.h
+++ b/quantum/rgb_matrix_runners/effect_runner_reactive_splash.h
@@ -20,7 +20,7 @@ bool effect_runner_reactive_splash(uint8_t start, effect_params_t* params, react
hsv = effect_func(hsv, dx, dy, dist, tick);
}
hsv.v = scale8(hsv.v, rgb_matrix_config.hsv.v);
- RGB rgb = hsv_to_rgb(hsv);
+ RGB rgb = rgb_matrix_hsv_to_rgb(hsv);
rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
}
return led_max < DRIVER_LED_TOTAL;
diff --git a/quantum/rgb_matrix_runners/effect_runner_sin_cos_i.h b/quantum/rgb_matrix_runners/effect_runner_sin_cos_i.h
index 3fb7d48051..02351de51e 100644
--- a/quantum/rgb_matrix_runners/effect_runner_sin_cos_i.h
+++ b/quantum/rgb_matrix_runners/effect_runner_sin_cos_i.h
@@ -10,7 +10,7 @@ bool effect_runner_sin_cos_i(effect_params_t* params, sin_cos_i_f effect_func) {
int8_t sin_value = sin8(time) - 128;
for (uint8_t i = led_min; i < led_max; i++) {
RGB_MATRIX_TEST_LED_FLAGS();
- RGB rgb = hsv_to_rgb(effect_func(rgb_matrix_config.hsv, cos_value, sin_value, i, time));
+ RGB rgb = rgb_matrix_hsv_to_rgb(effect_func(rgb_matrix_config.hsv, cos_value, sin_value, i, time));
rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
}
return led_max < DRIVER_LED_TOTAL;
diff --git a/quantum/rgblight.c b/quantum/rgblight.c
index 5ed3e8ac5f..4aa5cb4ac9 100644
--- a/quantum/rgblight.c
+++ b/quantum/rgblight.c
@@ -123,9 +123,11 @@ void rgblight_set_effect_range(uint8_t start_pos, uint8_t num_leds) {
rgblight_ranges.effect_num_leds = num_leds;
}
+__attribute__((weak)) RGB rgblight_hsv_to_rgb(HSV hsv) { return hsv_to_rgb(hsv); }
+
void sethsv_raw(uint8_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1) {
HSV hsv = {hue, sat, val};
- RGB rgb = hsv_to_rgb(hsv);
+ RGB rgb = rgblight_hsv_to_rgb(hsv);
setrgb(rgb.r, rgb.g, rgb.b, led1);
}
diff --git a/quantum/sequencer/sequencer.c b/quantum/sequencer/sequencer.c
new file mode 100644
index 0000000000..0eaf3a17aa
--- /dev/null
+++ b/quantum/sequencer/sequencer.c
@@ -0,0 +1,275 @@
+/* Copyright 2020 Rodolphe Belouin
+ *
+ * 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 "sequencer.h"
+
+#ifdef MIDI_ENABLE
+# include "process_midi.h"
+#endif
+
+#ifdef MIDI_MOCKED
+# include "tests/midi_mock.h"
+#endif
+
+sequencer_config_t sequencer_config = {
+ false, // enabled
+ {false}, // steps
+ {0}, // track notes
+ 60, // tempo
+ SQ_RES_4, // resolution
+};
+
+sequencer_state_t sequencer_internal_state = {0, 0, 0, 0, SEQUENCER_PHASE_ATTACK};
+
+bool is_sequencer_on(void) { return sequencer_config.enabled; }
+
+void sequencer_on(void) {
+ dprintln("sequencer on");
+ sequencer_config.enabled = true;
+ sequencer_internal_state.current_track = 0;
+ sequencer_internal_state.current_step = 0;
+ sequencer_internal_state.timer = timer_read();
+ sequencer_internal_state.phase = SEQUENCER_PHASE_ATTACK;
+}
+
+void sequencer_off(void) {
+ dprintln("sequencer off");
+ sequencer_config.enabled = false;
+ sequencer_internal_state.current_step = 0;
+}
+
+void sequencer_toggle(void) {
+ if (is_sequencer_on()) {
+ sequencer_off();
+ } else {
+ sequencer_on();
+ }
+}
+
+void sequencer_set_track_notes(const uint16_t track_notes[SEQUENCER_TRACKS]) {
+ for (uint8_t i = 0; i < SEQUENCER_TRACKS; i++) {
+ sequencer_config.track_notes[i] = track_notes[i];
+ }
+}
+
+bool is_sequencer_track_active(uint8_t track) { return (sequencer_internal_state.active_tracks >> track) & true; }
+
+void sequencer_set_track_activation(uint8_t track, bool value) {
+ if (value) {
+ sequencer_internal_state.active_tracks |= (1 << track);
+ } else {
+ sequencer_internal_state.active_tracks &= ~(1 << track);
+ }
+ dprintf("sequencer: track %d is %s\n", track, value ? "active" : "inactive");
+}
+
+void sequencer_toggle_track_activation(uint8_t track) { sequencer_set_track_activation(track, !is_sequencer_track_active(track)); }
+
+void sequencer_toggle_single_active_track(uint8_t track) {
+ if (is_sequencer_track_active(track)) {
+ sequencer_internal_state.active_tracks = 0;
+ } else {
+ sequencer_internal_state.active_tracks = 1 << track;
+ }
+}
+
+bool is_sequencer_step_on(uint8_t step) { return step < SEQUENCER_STEPS && (sequencer_config.steps[step] & sequencer_internal_state.active_tracks) > 0; }
+
+bool is_sequencer_step_on_for_track(uint8_t step, uint8_t track) { return step < SEQUENCER_STEPS && (sequencer_config.steps[step] >> track) & true; }
+
+void sequencer_set_step(uint8_t step, bool value) {
+ if (step < SEQUENCER_STEPS) {
+ if (value) {
+ sequencer_config.steps[step] |= sequencer_internal_state.active_tracks;
+ } else {
+ sequencer_config.steps[step] &= ~sequencer_internal_state.active_tracks;
+ }
+ dprintf("sequencer: step %d is %s\n", step, value ? "on" : "off");
+ } else {
+ dprintf("sequencer: step %d is out of range\n", step);
+ }
+}
+
+void sequencer_toggle_step(uint8_t step) {
+ if (is_sequencer_step_on(step)) {
+ sequencer_set_step_off(step);
+ } else {
+ sequencer_set_step_on(step);
+ }
+}
+
+void sequencer_set_all_steps(bool value) {
+ for (uint8_t step = 0; step < SEQUENCER_STEPS; step++) {
+ if (value) {
+ sequencer_config.steps[step] |= sequencer_internal_state.active_tracks;
+ } else {
+ sequencer_config.steps[step] &= ~sequencer_internal_state.active_tracks;
+ }
+ }
+ dprintf("sequencer: all steps are %s\n", value ? "on" : "off");
+}
+
+uint8_t sequencer_get_tempo(void) { return sequencer_config.tempo; }
+
+void sequencer_set_tempo(uint8_t tempo) {
+ if (tempo > 0) {
+ sequencer_config.tempo = tempo;
+ dprintf("sequencer: tempo set to %d bpm\n", tempo);
+ } else {
+ dprintln("sequencer: cannot set tempo to 0");
+ }
+}
+
+void sequencer_increase_tempo(void) {
+ // Handling potential uint8_t overflow
+ if (sequencer_config.tempo < UINT8_MAX) {
+ sequencer_set_tempo(sequencer_config.tempo + 1);
+ } else {
+ dprintf("sequencer: cannot set tempo above %d\n", UINT8_MAX);
+ }
+}
+
+void sequencer_decrease_tempo(void) { sequencer_set_tempo(sequencer_config.tempo - 1); }
+
+sequencer_resolution_t sequencer_get_resolution(void) { return sequencer_config.resolution; }
+
+void sequencer_set_resolution(sequencer_resolution_t resolution) {
+ if (resolution >= 0 && resolution < SEQUENCER_RESOLUTIONS) {
+ sequencer_config.resolution = resolution;
+ dprintf("sequencer: resolution set to %d\n", resolution);
+ } else {
+ dprintf("sequencer: resolution %d is out of range\n", resolution);
+ }
+}
+
+void sequencer_increase_resolution(void) { sequencer_set_resolution(sequencer_config.resolution + 1); }
+
+void sequencer_decrease_resolution(void) { sequencer_set_resolution(sequencer_config.resolution - 1); }
+
+uint8_t sequencer_get_current_step(void) { return sequencer_internal_state.current_step; }
+
+void sequencer_phase_attack(void) {
+ dprintf("sequencer: step %d\n", sequencer_internal_state.current_step);
+ dprintf("sequencer: time %d\n", timer_read());
+
+ if (sequencer_internal_state.current_track == 0) {
+ sequencer_internal_state.timer = timer_read();
+ }
+
+ if (timer_elapsed(sequencer_internal_state.timer) < sequencer_internal_state.current_track * SEQUENCER_TRACK_THROTTLE) {
+ return;
+ }
+
+#if defined(MIDI_ENABLE) || defined(MIDI_MOCKED)
+ if (is_sequencer_step_on_for_track(sequencer_internal_state.current_step, sequencer_internal_state.current_track)) {
+ process_midi_basic_noteon(midi_compute_note(sequencer_config.track_notes[sequencer_internal_state.current_track]));
+ }
+#endif
+
+ if (sequencer_internal_state.current_track < SEQUENCER_TRACKS - 1) {
+ sequencer_internal_state.current_track++;
+ } else {
+ sequencer_internal_state.phase = SEQUENCER_PHASE_RELEASE;
+ }
+}
+
+void sequencer_phase_release(void) {
+ if (timer_elapsed(sequencer_internal_state.timer) < SEQUENCER_PHASE_RELEASE_TIMEOUT + sequencer_internal_state.current_track * SEQUENCER_TRACK_THROTTLE) {
+ return;
+ }
+#if defined(MIDI_ENABLE) || defined(MIDI_MOCKED)
+ if (is_sequencer_step_on_for_track(sequencer_internal_state.current_step, sequencer_internal_state.current_track)) {
+ process_midi_basic_noteoff(midi_compute_note(sequencer_config.track_notes[sequencer_internal_state.current_track]));
+ }
+#endif
+ if (sequencer_internal_state.current_track > 0) {
+ sequencer_internal_state.current_track--;
+ } else {
+ sequencer_internal_state.phase = SEQUENCER_PHASE_PAUSE;
+ }
+}
+
+void sequencer_phase_pause(void) {
+ if (timer_elapsed(sequencer_internal_state.timer) < sequencer_get_step_duration()) {
+ return;
+ }
+
+ sequencer_internal_state.current_step = (sequencer_internal_state.current_step + 1) % SEQUENCER_STEPS;
+ sequencer_internal_state.phase = SEQUENCER_PHASE_ATTACK;
+}
+
+void matrix_scan_sequencer(void) {
+ if (!sequencer_config.enabled) {
+ return;
+ }
+
+ if (sequencer_internal_state.phase == SEQUENCER_PHASE_PAUSE) {
+ sequencer_phase_pause();
+ }
+
+ if (sequencer_internal_state.phase == SEQUENCER_PHASE_RELEASE) {
+ sequencer_phase_release();
+ }
+
+ if (sequencer_internal_state.phase == SEQUENCER_PHASE_ATTACK) {
+ sequencer_phase_attack();
+ }
+}
+
+uint16_t sequencer_get_beat_duration(void) { return get_beat_duration(sequencer_config.tempo); }
+
+uint16_t sequencer_get_step_duration(void) { return get_step_duration(sequencer_config.tempo, sequencer_config.resolution); }
+
+uint16_t get_beat_duration(uint8_t tempo) {
+ // Don’t crash in the unlikely case where the given tempo is 0
+ if (tempo == 0) {
+ return get_beat_duration(60);
+ }
+
+ /**
+ * Given
+ * t = tempo and d = duration, both strictly greater than 0
+ * When
+ * t beats / minute = 1 beat / d ms
+ * Then
+ * t beats / 60000ms = 1 beat / d ms
+ * d ms = 60000ms / t
+ */
+ return 60000 / tempo;
+}
+
+uint16_t get_step_duration(uint8_t tempo, sequencer_resolution_t resolution) {
+ /**
+ * Resolution cheatsheet:
+ * 1/2 => 2 steps per 4 beats
+ * 1/2T => 3 steps per 4 beats
+ * 1/4 => 4 steps per 4 beats
+ * 1/4T => 6 steps per 4 beats
+ * 1/8 => 8 steps per 4 beats
+ * 1/8T => 12 steps per 4 beats
+ * 1/16 => 16 steps per 4 beats
+ * 1/16T => 24 steps per 4 beats
+ * 1/32 => 32 steps per 4 beats
+ *
+ * The number of steps for binary resolutions follows the powers of 2.
+ * The ternary variants are simply 1.5x faster.
+ */
+ bool is_binary = resolution % 2 == 0;
+ uint8_t binary_steps = 2 << (resolution / 2);
+ uint16_t binary_step_duration = get_beat_duration(tempo) * 4 / binary_steps;
+
+ return is_binary ? binary_step_duration : 2 * binary_step_duration / 3;
+}
diff --git a/quantum/sequencer/sequencer.h b/quantum/sequencer/sequencer.h
new file mode 100644
index 0000000000..aeca7a1e9b
--- /dev/null
+++ b/quantum/sequencer/sequencer.h
@@ -0,0 +1,122 @@
+/* Copyright 2020 Rodolphe Belouin
+ *
+ * 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/>.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include "debug.h"
+#include "timer.h"
+
+// Maximum number of steps: 256
+#ifndef SEQUENCER_STEPS
+# define SEQUENCER_STEPS 16
+#endif
+
+// Maximum number of tracks: 8
+#ifndef SEQUENCER_TRACKS
+# define SEQUENCER_TRACKS 8
+#endif
+
+#ifndef SEQUENCER_TRACK_THROTTLE
+# define SEQUENCER_TRACK_THROTTLE 3
+#endif
+
+#ifndef SEQUENCER_PHASE_RELEASE_TIMEOUT
+# define SEQUENCER_PHASE_RELEASE_TIMEOUT 30
+#endif
+
+/**
+ * Make sure that the items of this enumeration follow the powers of 2, separated by a ternary variant.
+ * Check the implementation of `get_step_duration` for further explanation.
+ */
+typedef enum { SQ_RES_2, SQ_RES_2T, SQ_RES_4, SQ_RES_4T, SQ_RES_8, SQ_RES_8T, SQ_RES_16, SQ_RES_16T, SQ_RES_32, SEQUENCER_RESOLUTIONS } sequencer_resolution_t;
+
+typedef struct {
+ bool enabled;
+ uint8_t steps[SEQUENCER_STEPS];
+ uint16_t track_notes[SEQUENCER_TRACKS];
+ uint8_t tempo; // Is a maximum tempo of 255 reasonable?
+ sequencer_resolution_t resolution;
+} sequencer_config_t;
+
+/**
+ * Because Digital Audio Workstations get overwhelmed when too many MIDI signals are sent concurrently,
+ * We use a "phase" state machine to delay some of the events.
+ */
+typedef enum sequencer_phase_t {
+ SEQUENCER_PHASE_ATTACK, // t=0ms, send the MIDI note on signal
+ SEQUENCER_PHASE_RELEASE, // t=SEQUENCER_PHASE_RELEASE_TIMEOUT ms, send the MIDI note off signal
+ SEQUENCER_PHASE_PAUSE // t=step duration ms, loop
+} sequencer_phase_t;
+
+typedef struct {
+ uint8_t active_tracks;
+ uint8_t current_track;
+ uint8_t current_step;
+ uint16_t timer;
+ sequencer_phase_t phase;
+} sequencer_state_t;
+
+extern sequencer_config_t sequencer_config;
+
+// We expose the internal state to make the feature more "unit-testable"
+extern sequencer_state_t sequencer_internal_state;
+
+bool is_sequencer_on(void);
+void sequencer_toggle(void);
+void sequencer_on(void);
+void sequencer_off(void);
+
+void sequencer_set_track_notes(const uint16_t track_notes[SEQUENCER_TRACKS]);
+
+bool is_sequencer_track_active(uint8_t track);
+void sequencer_set_track_activation(uint8_t track, bool value);
+void sequencer_toggle_track_activation(uint8_t track);
+void sequencer_toggle_single_active_track(uint8_t track);
+
+#define sequencer_activate_track(track) sequencer_set_track_activation(track, true)
+#define sequencer_deactivate_track(track) sequencer_set_track_activation(track, false)
+
+bool is_sequencer_step_on(uint8_t step);
+bool is_sequencer_step_on_for_track(uint8_t step, uint8_t track);
+void sequencer_set_step(uint8_t step, bool value);
+void sequencer_toggle_step(uint8_t step);
+void sequencer_set_all_steps(bool value);
+
+#define sequencer_set_step_on(step) sequencer_set_step(step, true)
+#define sequencer_set_step_off(step) sequencer_set_step(step, false)
+#define sequencer_set_all_steps_on() sequencer_set_all_steps(true)
+#define sequencer_set_all_steps_off() sequencer_set_all_steps(false)
+
+uint8_t sequencer_get_tempo(void);
+void sequencer_set_tempo(uint8_t tempo);
+void sequencer_increase_tempo(void);
+void sequencer_decrease_tempo(void);
+
+sequencer_resolution_t sequencer_get_resolution(void);
+void sequencer_set_resolution(sequencer_resolution_t resolution);
+void sequencer_increase_resolution(void);
+void sequencer_decrease_resolution(void);
+
+uint8_t sequencer_get_current_step(void);
+
+uint16_t sequencer_get_beat_duration(void);
+uint16_t sequencer_get_step_duration(void);
+
+uint16_t get_beat_duration(uint8_t tempo);
+uint16_t get_step_duration(uint8_t tempo, sequencer_resolution_t resolution);
+
+void matrix_scan_sequencer(void);
diff --git a/quantum/sequencer/tests/midi_mock.c b/quantum/sequencer/tests/midi_mock.c
new file mode 100644
index 0000000000..236e16f9d7
--- /dev/null
+++ b/quantum/sequencer/tests/midi_mock.c
@@ -0,0 +1,26 @@
+/* Copyright 2020 Rodolphe Belouin
+ *
+ * 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 "midi_mock.h"
+
+uint16_t last_noteon = 0;
+uint16_t last_noteoff = 0;
+
+uint16_t midi_compute_note(uint16_t keycode) { return keycode; }
+
+void process_midi_basic_noteon(uint16_t note) { last_noteon = note; }
+
+void process_midi_basic_noteoff(uint16_t note) { last_noteoff = note; }
diff --git a/quantum/sequencer/tests/midi_mock.h b/quantum/sequencer/tests/midi_mock.h
new file mode 100644
index 0000000000..4d8c2eb307
--- /dev/null
+++ b/quantum/sequencer/tests/midi_mock.h
@@ -0,0 +1,26 @@
+/* Copyright 2020 Rodolphe Belouin
+ *
+ * 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/>.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+extern uint16_t last_noteon;
+extern uint16_t last_noteoff;
+
+uint16_t midi_compute_note(uint16_t keycode);
+void process_midi_basic_noteon(uint16_t note);
+void process_midi_basic_noteoff(uint16_t note);
diff --git a/quantum/sequencer/tests/rules.mk b/quantum/sequencer/tests/rules.mk
new file mode 100644
index 0000000000..76c221cf92
--- /dev/null
+++ b/quantum/sequencer/tests/rules.mk
@@ -0,0 +1,11 @@
+# The letter case of these variables might seem odd. However:
+# - it is consistent with the serial_link example that is used as a reference in the Unit Testing article (https://docs.qmk.fm/#/unit_testing?id=adding-tests-for-new-or-existing-features)
+# - Neither `make test:sequencer` or `make test:SEQUENCER` work when using SCREAMING_SNAKE_CASE
+
+sequencer_DEFS := -DNO_DEBUG -DMIDI_MOCKED
+
+sequencer_SRC := \
+ $(QUANTUM_PATH)/sequencer/tests/midi_mock.c \
+ $(QUANTUM_PATH)/sequencer/tests/sequencer_tests.cpp \
+ $(QUANTUM_PATH)/sequencer/sequencer.c \
+ $(TMK_PATH)/common/test/timer.c
diff --git a/quantum/sequencer/tests/sequencer_tests.cpp b/quantum/sequencer/tests/sequencer_tests.cpp
new file mode 100644
index 0000000000..e81984e5b5
--- /dev/null
+++ b/quantum/sequencer/tests/sequencer_tests.cpp
@@ -0,0 +1,590 @@
+/* Copyright 2020 Rodolphe Belouin
+ *
+ * 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 "gtest/gtest.h"
+
+extern "C" {
+#include "sequencer.h"
+#include "midi_mock.h"
+#include "quantum/quantum_keycodes.h"
+}
+
+extern "C" {
+void set_time(uint32_t t);
+void advance_time(uint32_t ms);
+}
+
+class SequencerTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ config_copy.enabled = sequencer_config.enabled;
+
+ for (int i = 0; i < SEQUENCER_STEPS; i++) {
+ config_copy.steps[i] = sequencer_config.steps[i];
+ }
+
+ for (int i = 0; i < SEQUENCER_TRACKS; i++) {
+ config_copy.track_notes[i] = sequencer_config.track_notes[i];
+ }
+
+ config_copy.tempo = sequencer_config.tempo;
+ config_copy.resolution = sequencer_config.resolution;
+
+ state_copy.active_tracks = sequencer_internal_state.active_tracks;
+ state_copy.current_track = sequencer_internal_state.current_track;
+ state_copy.current_step = sequencer_internal_state.current_step;
+ state_copy.timer = sequencer_internal_state.timer;
+
+ last_noteon = 0;
+ last_noteoff = 0;
+
+ set_time(0);
+ }
+
+ void TearDown() override {
+ sequencer_config.enabled = config_copy.enabled;
+
+ for (int i = 0; i < SEQUENCER_STEPS; i++) {
+ sequencer_config.steps[i] = config_copy.steps[i];
+ }
+
+ for (int i = 0; i < SEQUENCER_TRACKS; i++) {
+ sequencer_config.track_notes[i] = config_copy.track_notes[i];
+ }
+
+ sequencer_config.tempo = config_copy.tempo;
+ sequencer_config.resolution = config_copy.resolution;
+
+ sequencer_internal_state.active_tracks = state_copy.active_tracks;
+ sequencer_internal_state.current_track = state_copy.current_track;
+ sequencer_internal_state.current_step = state_copy.current_step;
+ sequencer_internal_state.timer = state_copy.timer;
+ }
+
+ sequencer_config_t config_copy;
+ sequencer_state_t state_copy;
+};
+
+TEST_F(SequencerTest, TestOffByDefault) { EXPECT_EQ(is_sequencer_on(), false); }
+
+TEST_F(SequencerTest, TestOn) {
+ sequencer_config.enabled = false;
+
+ sequencer_on();
+ EXPECT_EQ(is_sequencer_on(), true);
+
+ // sequencer_on is idempotent
+ sequencer_on();
+ EXPECT_EQ(is_sequencer_on(), true);
+}
+
+TEST_F(SequencerTest, TestOff) {
+ sequencer_config.enabled = true;
+
+ sequencer_off();
+ EXPECT_EQ(is_sequencer_on(), false);
+
+ // sequencer_off is idempotent
+ sequencer_off();
+ EXPECT_EQ(is_sequencer_on(), false);
+}
+
+TEST_F(SequencerTest, TestToggle) {
+ sequencer_config.enabled = false;
+
+ sequencer_toggle();
+ EXPECT_EQ(is_sequencer_on(), true);
+
+ sequencer_toggle();
+ EXPECT_EQ(is_sequencer_on(), false);
+}
+
+TEST_F(SequencerTest, TestNoActiveTrackByDefault) {
+ for (int i = 0; i < SEQUENCER_TRACKS; i++) {
+ EXPECT_EQ(is_sequencer_track_active(i), false);
+ }
+}
+
+TEST_F(SequencerTest, TestGetActiveTracks) {
+ sequencer_internal_state.active_tracks = (1 << 7) + (1 << 6) + (1 << 3) + (1 << 1) + (1 << 0);
+
+ EXPECT_EQ(is_sequencer_track_active(0), true);
+ EXPECT_EQ(is_sequencer_track_active(1), true);
+ EXPECT_EQ(is_sequencer_track_active(2), false);
+ EXPECT_EQ(is_sequencer_track_active(3), true);
+ EXPECT_EQ(is_sequencer_track_active(4), false);
+ EXPECT_EQ(is_sequencer_track_active(5), false);
+ EXPECT_EQ(is_sequencer_track_active(6), true);
+ EXPECT_EQ(is_sequencer_track_active(7), true);
+}
+
+TEST_F(SequencerTest, TestGetActiveTracksOutOfBound) {
+ sequencer_set_track_activation(-1, true);
+ sequencer_set_track_activation(8, true);
+
+ EXPECT_EQ(is_sequencer_track_active(-1), false);
+ EXPECT_EQ(is_sequencer_track_active(8), false);
+}
+
+TEST_F(SequencerTest, TestToggleTrackActivation) {
+ sequencer_internal_state.active_tracks = (1 << 7) + (1 << 6) + (1 << 3) + (1 << 1) + (1 << 0);
+
+ sequencer_toggle_track_activation(6);
+
+ EXPECT_EQ(is_sequencer_track_active(0), true);
+ EXPECT_EQ(is_sequencer_track_active(1), true);
+ EXPECT_EQ(is_sequencer_track_active(2), false);
+ EXPECT_EQ(is_sequencer_track_active(3), true);
+ EXPECT_EQ(is_sequencer_track_active(4), false);
+ EXPECT_EQ(is_sequencer_track_active(5), false);
+ EXPECT_EQ(is_sequencer_track_active(6), false);
+ EXPECT_EQ(is_sequencer_track_active(7), true);
+}
+
+TEST_F(SequencerTest, TestToggleSingleTrackActivation) {
+ sequencer_internal_state.active_tracks = (1 << 7) + (1 << 6) + (1 << 3) + (1 << 1) + (1 << 0);
+
+ sequencer_toggle_single_active_track(2);
+
+ EXPECT_EQ(is_sequencer_track_active(0), false);
+ EXPECT_EQ(is_sequencer_track_active(1), false);
+ EXPECT_EQ(is_sequencer_track_active(2), true);
+ EXPECT_EQ(is_sequencer_track_active(3), false);
+ EXPECT_EQ(is_sequencer_track_active(4), false);
+ EXPECT_EQ(is_sequencer_track_active(5), false);
+ EXPECT_EQ(is_sequencer_track_active(6), false);
+ EXPECT_EQ(is_sequencer_track_active(7), false);
+}
+
+TEST_F(SequencerTest, TestStepOffByDefault) {
+ for (int i = 0; i < SEQUENCER_STEPS; i++) {
+ EXPECT_EQ(is_sequencer_step_on(i), false);
+ }
+}
+
+TEST_F(SequencerTest, TestIsStepOffWithNoActiveTracks) {
+ sequencer_config.steps[3] = 0xFF;
+ EXPECT_EQ(is_sequencer_step_on(3), false);
+}
+
+TEST_F(SequencerTest, TestIsStepOffWithGivenActiveTracks) {
+ sequencer_set_track_activation(2, true);
+ sequencer_set_track_activation(3, true);
+
+ sequencer_config.steps[3] = (1 << 0) + (1 << 1);
+
+ // No active tracks have the step enabled, so it is off
+ EXPECT_EQ(is_sequencer_step_on(3), false);
+}
+
+TEST_F(SequencerTest, TestIsStepOnWithGivenActiveTracks) {
+ sequencer_set_track_activation(2, true);
+ sequencer_set_track_activation(3, true);
+
+ sequencer_config.steps[3] = (1 << 2);
+
+ // Track 2 has the step enabled, so it is on
+ EXPECT_EQ(is_sequencer_step_on(3), true);
+}
+
+TEST_F(SequencerTest, TestIsStepOffForGivenTrack) {
+ sequencer_config.steps[3] = 0x00;
+ EXPECT_EQ(is_sequencer_step_on_for_track(3, 5), false);
+}
+
+TEST_F(SequencerTest, TestIsStepOnForGivenTrack) {
+ sequencer_config.steps[3] = (1 << 5);
+ EXPECT_EQ(is_sequencer_step_on_for_track(3, 5), true);
+}
+
+TEST_F(SequencerTest, TestSetStepOn) {
+ sequencer_internal_state.active_tracks = (1 << 6) + (1 << 3) + (1 << 2);
+ sequencer_config.steps[2] = (1 << 5) + (1 << 2);
+
+ sequencer_set_step(2, true);
+
+ EXPECT_EQ(sequencer_config.steps[2], (1 << 6) + (1 << 5) + (1 << 3) + (1 << 2));
+}
+
+TEST_F(SequencerTest, TestSetStepOff) {
+ sequencer_internal_state.active_tracks = (1 << 6) + (1 << 3) + (1 << 2);
+ sequencer_config.steps[2] = (1 << 5) + (1 << 2);
+
+ sequencer_set_step(2, false);
+
+ EXPECT_EQ(sequencer_config.steps[2], (1 << 5));
+}
+
+TEST_F(SequencerTest, TestToggleStepOff) {
+ sequencer_internal_state.active_tracks = (1 << 6) + (1 << 3) + (1 << 2);
+ sequencer_config.steps[2] = (1 << 5) + (1 << 2);
+
+ sequencer_toggle_step(2);
+
+ EXPECT_EQ(sequencer_config.steps[2], (1 << 5));
+}
+
+TEST_F(SequencerTest, TestToggleStepOn) {
+ sequencer_internal_state.active_tracks = (1 << 6) + (1 << 3) + (1 << 2);
+ sequencer_config.steps[2] = 0;
+
+ sequencer_toggle_step(2);
+
+ EXPECT_EQ(sequencer_config.steps[2], (1 << 6) + (1 << 3) + (1 << 2));
+}
+
+TEST_F(SequencerTest, TestSetAllStepsOn) {
+ sequencer_internal_state.active_tracks = (1 << 6) + (1 << 3) + (1 << 2);
+ sequencer_config.steps[2] = (1 << 7) + (1 << 6);
+ sequencer_config.steps[4] = (1 << 3) + (1 << 1);
+
+ sequencer_set_all_steps(true);
+
+ EXPECT_EQ(sequencer_config.steps[2], (1 << 7) + (1 << 6) + (1 << 3) + (1 << 2));
+ EXPECT_EQ(sequencer_config.steps[4], (1 << 6) + (1 << 3) + (1 << 2) + (1 << 1));
+}
+
+TEST_F(SequencerTest, TestSetAllStepsOff) {
+ sequencer_internal_state.active_tracks = (1 << 6) + (1 << 3) + (1 << 2);
+ sequencer_config.steps[2] = (1 << 7) + (1 << 6);
+ sequencer_config.steps[4] = (1 << 3) + (1 << 1);
+
+ sequencer_set_all_steps(false);
+
+ EXPECT_EQ(sequencer_config.steps[2], (1 << 7));
+ EXPECT_EQ(sequencer_config.steps[4], (1 << 1));
+}
+
+TEST_F(SequencerTest, TestSetTempoZero) {
+ sequencer_config.tempo = 123;
+
+ sequencer_set_tempo(0);
+
+ EXPECT_EQ(sequencer_config.tempo, 123);
+}
+
+TEST_F(SequencerTest, TestIncreaseTempoMax) {
+ sequencer_config.tempo = UINT8_MAX;
+
+ sequencer_increase_tempo();
+
+ EXPECT_EQ(sequencer_config.tempo, UINT8_MAX);
+}
+
+TEST_F(SequencerTest, TestSetResolutionLowerBound) {
+ sequencer_config.resolution = SQ_RES_4;
+
+ sequencer_set_resolution((sequencer_resolution_t)-1);
+
+ EXPECT_EQ(sequencer_config.resolution, SQ_RES_4);
+}
+
+TEST_F(SequencerTest, TestSetResolutionUpperBound) {
+ sequencer_config.resolution = SQ_RES_4;
+
+ sequencer_set_resolution(SEQUENCER_RESOLUTIONS);
+
+ EXPECT_EQ(sequencer_config.resolution, SQ_RES_4);
+}
+
+TEST_F(SequencerTest, TestGetBeatDuration) {
+ EXPECT_EQ(get_beat_duration(60), 1000);
+ EXPECT_EQ(get_beat_duration(120), 500);
+ EXPECT_EQ(get_beat_duration(240), 250);
+ EXPECT_EQ(get_beat_duration(0), 1000);
+}
+
+TEST_F(SequencerTest, TestGetStepDuration60) {
+ /**
+ * Resolution cheatsheet:
+ * 1/2 => 2 steps per 4 beats
+ * 1/2T => 3 steps per 4 beats
+ * 1/4 => 4 steps per 4 beats
+ * 1/4T => 6 steps per 4 beats
+ * 1/8 => 8 steps per 4 beats
+ * 1/8T => 12 steps per 4 beats
+ * 1/16 => 16 steps per 4 beats
+ * 1/16T => 24 steps per 4 beats
+ * 1/32 => 32 steps per 4 beats
+ *
+ * The number of steps for binary resolutions follows the powers of 2.
+ * The ternary variants are simply 1.5x faster.
+ */
+ EXPECT_EQ(get_step_duration(60, SQ_RES_2), 2000);
+ EXPECT_EQ(get_step_duration(60, SQ_RES_4), 1000);
+ EXPECT_EQ(get_step_duration(60, SQ_RES_8), 500);
+ EXPECT_EQ(get_step_duration(60, SQ_RES_16), 250);
+ EXPECT_EQ(get_step_duration(60, SQ_RES_32), 125);
+
+ EXPECT_EQ(get_step_duration(60, SQ_RES_2T), 1333);
+ EXPECT_EQ(get_step_duration(60, SQ_RES_4T), 666);
+ EXPECT_EQ(get_step_duration(60, SQ_RES_8T), 333);
+ EXPECT_EQ(get_step_duration(60, SQ_RES_16T), 166);
+}
+
+TEST_F(SequencerTest, TestGetStepDuration120) {
+ /**
+ * Resolution cheatsheet:
+ * 1/2 => 2 steps per 4 beats
+ * 1/2T => 3 steps per 4 beats
+ * 1/4 => 4 steps per 4 beats
+ * 1/4T => 6 steps per 4 beats
+ * 1/8 => 8 steps per 4 beats
+ * 1/8T => 12 steps per 4 beats
+ * 1/16 => 16 steps per 4 beats
+ * 1/16T => 24 steps per 4 beats
+ * 1/32 => 32 steps per 4 beats
+ *
+ * The number of steps for binary resolutions follows the powers of 2.
+ * The ternary variants are simply 1.5x faster.
+ */
+ EXPECT_EQ(get_step_duration(30, SQ_RES_2), 4000);
+ EXPECT_EQ(get_step_duration(30, SQ_RES_4), 2000);
+ EXPECT_EQ(get_step_duration(30, SQ_RES_8), 1000);
+ EXPECT_EQ(get_step_duration(30, SQ_RES_16), 500);
+ EXPECT_EQ(get_step_duration(30, SQ_RES_32), 250);
+
+ EXPECT_EQ(get_step_duration(30, SQ_RES_2T), 2666);
+ EXPECT_EQ(get_step_duration(30, SQ_RES_4T), 1333);
+ EXPECT_EQ(get_step_duration(30, SQ_RES_8T), 666);
+ EXPECT_EQ(get_step_duration(30, SQ_RES_16T), 333);
+}
+
+void setUpMatrixScanSequencerTest(void) {
+ sequencer_config.enabled = true;
+ sequencer_config.tempo = 120;
+ sequencer_config.resolution = SQ_RES_16;
+
+ // Configure the notes for each track
+ sequencer_config.track_notes[0] = MI_C;
+ sequencer_config.track_notes[1] = MI_D;
+ sequencer_config.track_notes[2] = MI_E;
+ sequencer_config.track_notes[3] = MI_F;
+ sequencer_config.track_notes[4] = MI_G;
+ sequencer_config.track_notes[5] = MI_A;
+ sequencer_config.track_notes[6] = MI_B;
+ sequencer_config.track_notes[7] = MI_C;
+
+ // Turn on some steps
+ sequencer_config.steps[0] = (1 << 0);
+ sequencer_config.steps[2] = (1 << 1) + (1 << 0);
+}
+
+TEST_F(SequencerTest, TestMatrixScanSequencerShouldAttackFirstTrackOfFirstStep) {
+ setUpMatrixScanSequencerTest();
+
+ matrix_scan_sequencer();
+ EXPECT_EQ(last_noteon, MI_C);
+ EXPECT_EQ(last_noteoff, 0);
+}
+
+TEST_F(SequencerTest, TestMatrixScanSequencerShouldAttackSecondTrackAfterFirstTrackOfFirstStep) {
+ setUpMatrixScanSequencerTest();
+
+ matrix_scan_sequencer();
+ EXPECT_EQ(sequencer_internal_state.current_step, 0);
+ EXPECT_EQ(sequencer_internal_state.current_track, 1);
+ EXPECT_EQ(sequencer_internal_state.phase, SEQUENCER_PHASE_ATTACK);
+}
+
+TEST_F(SequencerTest, TestMatrixScanSequencerShouldNotAttackInactiveTrackFirstStep) {
+ setUpMatrixScanSequencerTest();
+
+ sequencer_internal_state.current_step = 0;
+ sequencer_internal_state.current_track = 1;
+
+ // Wait some time after the first track has been attacked
+ advance_time(SEQUENCER_TRACK_THROTTLE);
+
+ matrix_scan_sequencer();
+ EXPECT_EQ(last_noteon, 0);
+ EXPECT_EQ(last_noteoff, 0);
+}
+
+TEST_F(SequencerTest, TestMatrixScanSequencerShouldAttackThirdTrackAfterSecondTrackOfFirstStep) {
+ setUpMatrixScanSequencerTest();
+
+ sequencer_internal_state.current_step = 0;
+ sequencer_internal_state.current_track = 1;
+
+ // Wait some time after the second track has been attacked
+ advance_time(2 * SEQUENCER_TRACK_THROTTLE);
+
+ matrix_scan_sequencer();
+ EXPECT_EQ(sequencer_internal_state.current_step, 0);
+ EXPECT_EQ(sequencer_internal_state.current_track, 2);
+ EXPECT_EQ(sequencer_internal_state.phase, SEQUENCER_PHASE_ATTACK);
+}
+
+TEST_F(SequencerTest, TestMatrixScanSequencerShouldEnterReleasePhaseAfterLastTrackHasBeenProcessedFirstStep) {
+ setUpMatrixScanSequencerTest();
+
+ sequencer_internal_state.current_step = 0;
+ sequencer_internal_state.current_track = SEQUENCER_TRACKS - 1;
+
+ // Wait until all notes have been attacked
+ advance_time((SEQUENCER_TRACKS - 1) * SEQUENCER_TRACK_THROTTLE);
+
+ matrix_scan_sequencer();
+ EXPECT_EQ(last_noteon, 0);
+ EXPECT_EQ(last_noteoff, 0);
+ EXPECT_EQ(sequencer_internal_state.current_step, 0);
+ EXPECT_EQ(sequencer_internal_state.current_track, SEQUENCER_TRACKS - 1);
+ EXPECT_EQ(sequencer_internal_state.phase, SEQUENCER_PHASE_RELEASE);
+}
+
+TEST_F(SequencerTest, TestMatrixScanSequencerShouldReleaseBackwards) {
+ setUpMatrixScanSequencerTest();
+
+ sequencer_internal_state.current_step = 0;
+ sequencer_internal_state.current_track = SEQUENCER_TRACKS - 1;
+ sequencer_internal_state.phase = SEQUENCER_PHASE_RELEASE;
+
+ // Wait until all notes have been attacked
+ advance_time((SEQUENCER_TRACKS - 1) * SEQUENCER_TRACK_THROTTLE);
+ // + the release timeout
+ advance_time(SEQUENCER_PHASE_RELEASE_TIMEOUT);
+
+ matrix_scan_sequencer();
+ EXPECT_EQ(sequencer_internal_state.current_step, 0);
+ EXPECT_EQ(sequencer_internal_state.current_track, SEQUENCER_TRACKS - 2);
+ EXPECT_EQ(sequencer_internal_state.phase, SEQUENCER_PHASE_RELEASE);
+}
+
+TEST_F(SequencerTest, TestMatrixScanSequencerShouldNotReleaseInactiveTrackFirstStep) {
+ setUpMatrixScanSequencerTest();
+
+ sequencer_internal_state.current_step = 0;
+ sequencer_internal_state.current_track = SEQUENCER_TRACKS - 1;
+ sequencer_internal_state.phase = SEQUENCER_PHASE_RELEASE;
+
+ // Wait until all notes have been attacked
+ advance_time((SEQUENCER_TRACKS - 1) * SEQUENCER_TRACK_THROTTLE);
+ // + the release timeout
+ advance_time(SEQUENCER_PHASE_RELEASE_TIMEOUT);
+
+ matrix_scan_sequencer();
+ EXPECT_EQ(last_noteon, 0);
+ EXPECT_EQ(last_noteoff, 0);
+}
+
+TEST_F(SequencerTest, TestMatrixScanSequencerShouldReleaseFirstTrackFirstStep) {
+ setUpMatrixScanSequencerTest();
+
+ sequencer_internal_state.current_step = 0;
+ sequencer_internal_state.current_track = 0;
+ sequencer_internal_state.phase = SEQUENCER_PHASE_RELEASE;
+
+ // Wait until all notes have been attacked
+ advance_time((SEQUENCER_TRACKS - 1) * SEQUENCER_TRACK_THROTTLE);
+ // + the release timeout
+ advance_time(SEQUENCER_PHASE_RELEASE_TIMEOUT);
+ // + all the other notes have been released
+ advance_time((SEQUENCER_TRACKS - 1) * SEQUENCER_TRACK_THROTTLE);
+
+ matrix_scan_sequencer();
+ EXPECT_EQ(last_noteon, 0);
+ EXPECT_EQ(last_noteoff, MI_C);
+}
+
+TEST_F(SequencerTest, TestMatrixScanSequencerShouldEnterPausePhaseAfterRelease) {
+ setUpMatrixScanSequencerTest();
+
+ sequencer_internal_state.current_step = 0;
+ sequencer_internal_state.current_track = 0;
+ sequencer_internal_state.phase = SEQUENCER_PHASE_RELEASE;
+
+ // Wait until all notes have been attacked
+ advance_time((SEQUENCER_TRACKS - 1) * SEQUENCER_TRACK_THROTTLE);
+ // + the release timeout
+ advance_time(SEQUENCER_PHASE_RELEASE_TIMEOUT);
+ // + all the other notes have been released
+ advance_time((SEQUENCER_TRACKS - 1) * SEQUENCER_TRACK_THROTTLE);
+
+ matrix_scan_sequencer();
+ EXPECT_EQ(sequencer_internal_state.current_step, 0);
+ EXPECT_EQ(sequencer_internal_state.current_track, 0);
+ EXPECT_EQ(sequencer_internal_state.phase, SEQUENCER_PHASE_PAUSE);
+}
+
+TEST_F(SequencerTest, TestMatrixScanSequencerShouldProcessFirstTrackOfSecondStepAfterPause) {
+ setUpMatrixScanSequencerTest();
+
+ sequencer_internal_state.current_step = 0;
+ sequencer_internal_state.current_track = 0;
+ sequencer_internal_state.phase = SEQUENCER_PHASE_PAUSE;
+
+ // Wait until all notes have been attacked
+ advance_time((SEQUENCER_TRACKS - 1) * SEQUENCER_TRACK_THROTTLE);
+ // + the release timeout
+ advance_time(SEQUENCER_PHASE_RELEASE_TIMEOUT);
+ // + all the other notes have been released
+ advance_time((SEQUENCER_TRACKS - 1) * SEQUENCER_TRACK_THROTTLE);
+ // + the step duration (one 16th at tempo=120 lasts 125ms)
+ advance_time(125);
+
+ matrix_scan_sequencer();
+ EXPECT_EQ(sequencer_internal_state.current_step, 1);
+ EXPECT_EQ(sequencer_internal_state.current_track, 1);
+ EXPECT_EQ(sequencer_internal_state.phase, SEQUENCER_PHASE_ATTACK);
+}
+
+TEST_F(SequencerTest, TestMatrixScanSequencerShouldProcessSecondTrackTooEarly) {
+ setUpMatrixScanSequencerTest();
+
+ sequencer_internal_state.current_step = 2;
+ sequencer_internal_state.current_track = 1;
+
+ matrix_scan_sequencer();
+ EXPECT_EQ(last_noteon, 0);
+ EXPECT_EQ(last_noteoff, 0);
+}
+
+TEST_F(SequencerTest, TestMatrixScanSequencerShouldProcessSecondTrackOnTime) {
+ setUpMatrixScanSequencerTest();
+
+ sequencer_internal_state.current_step = 2;
+ sequencer_internal_state.current_track = 1;
+
+ // Wait until first track has been attacked
+ advance_time(SEQUENCER_TRACK_THROTTLE);
+
+ matrix_scan_sequencer();
+ EXPECT_EQ(last_noteon, MI_D);
+ EXPECT_EQ(last_noteoff, 0);
+}
+
+TEST_F(SequencerTest, TestMatrixScanSequencerShouldLoopOnceSequenceIsOver) {
+ setUpMatrixScanSequencerTest();
+
+ sequencer_internal_state.current_step = SEQUENCER_STEPS - 1;
+ sequencer_internal_state.current_track = 0;
+ sequencer_internal_state.phase = SEQUENCER_PHASE_PAUSE;
+
+ // Wait until all notes have been attacked
+ advance_time((SEQUENCER_TRACKS - 1) * SEQUENCER_TRACK_THROTTLE);
+ // + the release timeout
+ advance_time(SEQUENCER_PHASE_RELEASE_TIMEOUT);
+ // + all the other notes have been released
+ advance_time((SEQUENCER_TRACKS - 1) * SEQUENCER_TRACK_THROTTLE);
+ // + the step duration (one 16th at tempo=120 lasts 125ms)
+ advance_time(125);
+
+ matrix_scan_sequencer();
+ EXPECT_EQ(sequencer_internal_state.current_step, 0);
+ EXPECT_EQ(sequencer_internal_state.current_track, 1);
+ EXPECT_EQ(sequencer_internal_state.phase, SEQUENCER_PHASE_ATTACK);
+}
diff --git a/quantum/sequencer/tests/testlist.mk b/quantum/sequencer/tests/testlist.mk
new file mode 100644
index 0000000000..bb38991109
--- /dev/null
+++ b/quantum/sequencer/tests/testlist.mk
@@ -0,0 +1 @@
+TEST_LIST += sequencer
diff --git a/quantum/split_common/matrix.c b/quantum/split_common/matrix.c
index 5bad9db08f..cd5a024c3d 100644
--- a/quantum/split_common/matrix.c
+++ b/quantum/split_common/matrix.c
@@ -45,6 +45,19 @@ uint8_t thisHand, thatHand;
// user-defined overridable functions
__attribute__((weak)) void matrix_slave_scan_user(void) {}
+static inline void setPinOutput_writeLow(pin_t pin) {
+ ATOMIC_BLOCK_FORCEON {
+ setPinOutput(pin);
+ writePinLow(pin);
+ }
+}
+
+static inline void setPinInputHigh_atomic(pin_t pin) {
+ ATOMIC_BLOCK_FORCEON {
+ setPinInputHigh(pin);
+ }
+}
+
// matrix code
#ifdef DIRECT_PINS
@@ -83,22 +96,23 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
# if (DIODE_DIRECTION == COL2ROW)
static void select_row(uint8_t row) {
- setPinOutput(row_pins[row]);
- writePinLow(row_pins[row]);
+ setPinOutput_writeLow(row_pins[row]);
}
-static void unselect_row(uint8_t row) { setPinInputHigh(row_pins[row]); }
+static void unselect_row(uint8_t row) {
+ setPinInputHigh_atomic(row_pins[row]);
+}
static void unselect_rows(void) {
for (uint8_t x = 0; x < ROWS_PER_HAND; x++) {
- setPinInputHigh(row_pins[x]);
+ setPinInputHigh_atomic(row_pins[x]);
}
}
static void init_pins(void) {
unselect_rows();
for (uint8_t x = 0; x < MATRIX_COLS; x++) {
- setPinInputHigh(col_pins[x]);
+ setPinInputHigh_atomic(col_pins[x]);
}
}
@@ -133,22 +147,23 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
# elif (DIODE_DIRECTION == ROW2COL)
static void select_col(uint8_t col) {
- setPinOutput(col_pins[col]);
- writePinLow(col_pins[col]);
+ setPinOutput_writeLow(col_pins[col]);
}
-static void unselect_col(uint8_t col) { setPinInputHigh(col_pins[col]); }
+static void unselect_col(uint8_t col) {
+ setPinInputHigh_atomic(col_pins[col]);
+}
static void unselect_cols(void) {
for (uint8_t x = 0; x < MATRIX_COLS; x++) {
- setPinInputHigh(col_pins[x]);
+ setPinInputHigh_atomic(col_pins[x]);
}
}
static void init_pins(void) {
unselect_cols();
for (uint8_t x = 0; x < ROWS_PER_HAND; x++) {
- setPinInputHigh(row_pins[x]);
+ setPinInputHigh_atomic(row_pins[x]);
}
}
diff --git a/requirements.txt b/requirements.txt
index d20803577e..6e907cf8e8 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,7 @@
# Python requirements
-# milc FIXME(skullydazed): Included in the repo for now.
appdirs
argcomplete
colorama
hjson
+milc
pygments
diff --git a/show_options.mk b/show_options.mk
index 8eef258778..15407dfd2a 100644
--- a/show_options.mk
+++ b/show_options.mk
@@ -20,6 +20,7 @@ HARDWARE_OPTION_NAMES = \
RGBLIGHT_ENABLE \
RGBLIGHT_CUSTOM_DRIVER \
RGB_MATRIX_ENABLE \
+ RGB_MATRIX_DRIVER \
SERIAL_LINK_ENABLE \
CIE1931_CURVE \
MIDI_ENABLE \
diff --git a/testlist.mk b/testlist.mk
index d949fb3eae..ca1408806c 100644
--- a/testlist.mk
+++ b/testlist.mk
@@ -1,6 +1,7 @@
TEST_LIST = $(notdir $(patsubst %/rules.mk,%,$(wildcard $(ROOT_DIR)/tests/*/rules.mk)))
FULL_TESTS := $(TEST_LIST)
+include $(ROOT_DIR)/quantum/sequencer/tests/testlist.mk
include $(ROOT_DIR)/quantum/serial_link/tests/testlist.mk
define VALIDATE_TEST_LIST
diff --git a/tmk_core/chibios.mk b/tmk_core/chibios.mk
index 2bd53f0dc8..e53edccee2 100644
--- a/tmk_core/chibios.mk
+++ b/tmk_core/chibios.mk
@@ -123,6 +123,8 @@ else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/chconf.h)","")
CHCONFDIR = $(KEYBOARD_PATH_1)
else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/$(BOARD)/configs/chconf.h)","")
CHCONFDIR = $(TOP_DIR)/platforms/chibios/$(BOARD)/configs
+else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/common/configs/chconf.h)","")
+ CHCONFDIR = $(TOP_DIR)/platforms/chibios/common/configs
endif
ifneq ("$(wildcard $(KEYBOARD_PATH_5)/halconf.h)","")
@@ -137,6 +139,8 @@ else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/halconf.h)","")
HALCONFDIR = $(KEYBOARD_PATH_1)
else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/$(BOARD)/configs/halconf.h)","")
HALCONFDIR = $(TOP_DIR)/platforms/chibios/$(BOARD)/configs
+else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/common/configs/halconf.h)","")
+ HALCONFDIR = $(TOP_DIR)/platforms/chibios/common/configs
endif
# HAL-OSAL files (optional).
@@ -183,8 +187,8 @@ else ifneq ("$(wildcard $(KEYBOARD_PATH_2)/ld/$(MCU_LDSCRIPT).ld)","")
LDSCRIPT = $(KEYBOARD_PATH_2)/ld/$(MCU_LDSCRIPT).ld
else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/ld/$(MCU_LDSCRIPT).ld)","")
LDSCRIPT = $(KEYBOARD_PATH_1)/ld/$(MCU_LDSCRIPT).ld
-else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/ld/$(MCU_LDSCRIPT).ld)","")
- LDSCRIPT = $(TOP_DIR)/platforms/chibios/ld/$(MCU_LDSCRIPT).ld
+else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/common/ld/$(MCU_LDSCRIPT).ld)","")
+ LDSCRIPT = $(TOP_DIR)/platforms/chibios/common/ld/$(MCU_LDSCRIPT).ld
else ifneq ("$(wildcard $(STARTUPLD_CONTRIB)/$(MCU_LDSCRIPT).ld)","")
LDSCRIPT = $(STARTUPLD_CONTRIB)/$(MCU_LDSCRIPT).ld
USE_CHIBIOS_CONTRIB = yes
@@ -209,6 +213,8 @@ CHIBISRC := $(patsubst $(TOP_DIR)/%,%,$(CHIBISRC))
EXTRAINCDIRS += $(CHIBIOS)/os/license $(CHIBIOS)/os/oslib/include \
$(TOP_DIR)/platforms/chibios/$(BOARD)/configs \
+ $(TOP_DIR)/platforms/chibios/common/configs \
+ $(HALCONFDIR) $(CHCONFDIR) \
$(STARTUPINC) $(KERNINC) $(PORTINC) $(OSALINC) \
$(HALINC) $(PLATFORMINC) $(BOARDINC) $(TESTINC) \
$(STREAMSINC) $(CHIBIOS)/os/various $(COMMON_VPATH)
diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c
index aa1a2999e0..fa87433db2 100644
--- a/tmk_core/common/action.c
+++ b/tmk_core/common/action.c
@@ -37,9 +37,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
# include "nodebug.h"
#endif
+#ifdef POINTING_DEVICE_ENABLE
+# include "pointing_device.h"
+#endif
+
int tp_buttons;
-#ifdef RETRO_TAPPING
+#if defined(RETRO_TAPPING) || defined(RETRO_TAPPING_PER_KEY)
int retro_tapping_counter = 0;
#endif
@@ -51,6 +55,10 @@ int retro_tapping_counter = 0;
__attribute__((weak)) bool get_ignore_mod_tap_interrupt(uint16_t keycode, keyrecord_t *record) { return false; }
#endif
+#ifdef RETRO_TAPPING_PER_KEY
+__attribute__((weak)) bool get_retro_tapping(uint16_t keycode, keyrecord_t *record) { return false; }
+#endif
+
#ifndef TAP_CODE_DELAY
# define TAP_CODE_DELAY 0
#endif
@@ -67,7 +75,7 @@ void action_exec(keyevent_t event) {
dprint("EVENT: ");
debug_event(event);
dprintln();
-#ifdef RETRO_TAPPING
+#if defined(RETRO_TAPPING) || defined(RETRO_TAPPING_PER_KEY)
retro_tapping_counter++;
#endif
}
@@ -220,6 +228,19 @@ void process_record_handler(keyrecord_t *record) {
process_action(record, action);
}
+#if defined(PS2_MOUSE_ENABLE) || defined(POINTING_DEVICE_ENABLE)
+void register_button(bool pressed, enum mouse_buttons button) {
+# ifdef PS2_MOUSE_ENABLE
+ tp_buttons = pressed ? tp_buttons | button : tp_buttons & ~button;
+# endif
+# ifdef POINTING_DEVICE_ENABLE
+ report_mouse_t currentReport = pointing_device_get_report();
+ currentReport.buttons = pressed ? currentReport.buttons | button : currentReport.buttons & ~button;
+ pointing_device_set_report(currentReport);
+# endif
+}
+#endif
+
/** \brief Take an action and processes it.
*
* FIXME: Needs documentation.
@@ -404,15 +425,23 @@ void process_action(keyrecord_t *record, action_t action) {
if (event.pressed) {
mousekey_on(action.key.code);
switch (action.key.code) {
-# ifdef PS2_MOUSE_ENABLE
+# if defined(PS2_MOUSE_ENABLE) || defined(POINTING_DEVICE_ENABLE)
case KC_MS_BTN1:
- tp_buttons |= (1 << 0);
+ register_button(true, MOUSE_BTN1);
break;
case KC_MS_BTN2:
- tp_buttons |= (1 << 1);
+ register_button(true, MOUSE_BTN2);
break;
case KC_MS_BTN3:
- tp_buttons |= (1 << 2);
+ register_button(true, MOUSE_BTN3);
+ break;
+# endif
+# ifdef POINTING_DEVICE_ENABLE
+ case KC_MS_BTN4:
+ register_button(true, MOUSE_BTN4);
+ break;
+ case KC_MS_BTN5:
+ register_button(true, MOUSE_BTN5);
break;
# endif
default:
@@ -422,15 +451,23 @@ void process_action(keyrecord_t *record, action_t action) {
} else {
mousekey_off(action.key.code);
switch (action.key.code) {
-# ifdef PS2_MOUSE_ENABLE
+# if defined(PS2_MOUSE_ENABLE) || defined(POINTING_DEVICE_ENABLE)
case KC_MS_BTN1:
- tp_buttons &= ~(1 << 0);
+ register_button(false, MOUSE_BTN1);
break;
case KC_MS_BTN2:
- tp_buttons &= ~(1 << 1);
+ register_button(false, MOUSE_BTN2);
break;
case KC_MS_BTN3:
- tp_buttons &= ~(1 << 2);
+ register_button(false, MOUSE_BTN3);
+ break;
+# endif
+# ifdef POINTING_DEVICE_ENABLE
+ case KC_MS_BTN4:
+ register_button(false, MOUSE_BTN4);
+ break;
+ case KC_MS_BTN5:
+ register_button(false, MOUSE_BTN5);
break;
# endif
default:
@@ -692,20 +729,23 @@ void process_action(keyrecord_t *record, action_t action) {
#endif
#ifndef NO_ACTION_TAPPING
-# ifdef RETRO_TAPPING
+# if defined(RETRO_TAPPING) || defined(RETRO_TAPPING_PER_KEY)
if (!is_tap_action(action)) {
retro_tapping_counter = 0;
} else {
if (event.pressed) {
if (tap_count > 0) {
retro_tapping_counter = 0;
- } else {
}
} else {
if (tap_count > 0) {
retro_tapping_counter = 0;
} else {
- if (retro_tapping_counter == 2) {
+ if (
+# ifdef RETRO_TAPPING_PER_KEY
+ get_retro_tapping(get_event_keycode(record->event, false), record) &&
+# endif
+ retro_tapping_counter == 2) {
tap_code(action.layer_tap.code);
}
retro_tapping_counter = 0;
diff --git a/tmk_core/common/action_util.c b/tmk_core/common/action_util.c
index fd0e4409f0..000503b082 100644
--- a/tmk_core/common/action_util.c
+++ b/tmk_core/common/action_util.c
@@ -290,6 +290,32 @@ void set_macro_mods(uint8_t mods) { macro_mods = mods; }
void clear_macro_mods(void) { macro_mods = 0; }
#ifndef NO_ACTION_ONESHOT
+/** \brief get oneshot mods
+ *
+ * FIXME: needs doc
+ */
+uint8_t get_oneshot_mods(void) { return oneshot_mods; }
+
+void add_oneshot_mods(uint8_t mods) {
+ if ((oneshot_mods & mods) != mods) {
+# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
+ oneshot_time = timer_read();
+# endif
+ oneshot_mods |= mods;
+ oneshot_mods_changed_kb(mods);
+ }
+}
+
+void del_oneshot_mods(uint8_t mods) {
+ if (oneshot_mods & mods) {
+ oneshot_mods &= ~mods;
+# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
+ oneshot_time = oneshot_mods ? timer_read() : 0;
+# endif
+ oneshot_mods_changed_kb(oneshot_mods);
+ }
+}
+
/** \brief set oneshot mods
*
* FIXME: needs doc
@@ -316,11 +342,6 @@ void clear_oneshot_mods(void) {
oneshot_mods_changed_kb(oneshot_mods);
}
}
-/** \brief get oneshot mods
- *
- * FIXME: needs doc
- */
-uint8_t get_oneshot_mods(void) { return oneshot_mods; }
#endif
/** \brief Called when the one shot modifiers have been changed.
diff --git a/tmk_core/common/action_util.h b/tmk_core/common/action_util.h
index 5dd8393da4..743ff1406b 100644
--- a/tmk_core/common/action_util.h
+++ b/tmk_core/common/action_util.h
@@ -57,12 +57,11 @@ void set_macro_mods(uint8_t mods);
void clear_macro_mods(void);
/* oneshot modifier */
-void set_oneshot_mods(uint8_t mods);
uint8_t get_oneshot_mods(void);
+void add_oneshot_mods(uint8_t mods);
+void del_oneshot_mods(uint8_t mods);
+void set_oneshot_mods(uint8_t mods);
void clear_oneshot_mods(void);
-void oneshot_toggle(void);
-void oneshot_enable(void);
-void oneshot_disable(void);
bool has_oneshot_mods_timed_out(void);
uint8_t get_oneshot_locked_mods(void);
diff --git a/tmk_core/common/arm_atsam/suspend.c b/tmk_core/common/arm_atsam/suspend.c
index 2dad005706..6a36740658 100644
--- a/tmk_core/common/arm_atsam/suspend.c
+++ b/tmk_core/common/arm_atsam/suspend.c
@@ -1,6 +1,6 @@
#include "matrix.h"
#include "i2c_master.h"
-#include "led_matrix.h"
+#include "md_rgb_matrix.h"
#include "suspend.h"
/** \brief Suspend idle
diff --git a/tmk_core/common/chibios/bootloader.c b/tmk_core/common/chibios/bootloader.c
index 7b2cf5c435..f6d016ec9d 100644
--- a/tmk_core/common/chibios/bootloader.c
+++ b/tmk_core/common/chibios/bootloader.c
@@ -32,7 +32,7 @@
extern uint32_t __ram0_end__;
-void bootloader_jump(void) {
+__attribute__((weak)) void bootloader_jump(void) {
// For STM32 MCUs with dual-bank flash, and we're incapable of jumping to the bootloader. The first valid flash
// bank is executed unconditionally after a reset, so it doesn't enter DFU unless BOOT0 is high. Instead, we do
// it with hardware...in this case, we pull a GPIO high/low depending on the configuration, connects 3.3V to
@@ -58,7 +58,7 @@ void enter_bootloader_mode_if_requested(void) {} // not needed at all, but if a
extern uint32_t __ram0_end__;
-void bootloader_jump(void) {
+__attribute__((weak)) void bootloader_jump(void) {
*MAGIC_ADDR = BOOTLOADER_MAGIC; // set magic flag => reset handler will jump into boot loader
NVIC_SystemReset();
}
@@ -85,8 +85,8 @@ void enter_bootloader_mode_if_requested(void) {
# if defined(BOOTLOADER_KIIBOHD)
/* Kiibohd Bootloader (MCHCK and Infinity KB) */
# define SCB_AIRCR_VECTKEY_WRITEMAGIC 0x05FA0000
-const uint8_t sys_reset_to_loader_magic[] = "\xff\x00\x7fRESET TO LOADER\x7f\x00\xff";
-void bootloader_jump(void) {
+const uint8_t sys_reset_to_loader_magic[] = "\xff\x00\x7fRESET TO LOADER\x7f\x00\xff";
+__attribute__((weak)) void bootloader_jump(void) {
__builtin_memcpy((void *)VBAT, (const void *)sys_reset_to_loader_magic, sizeof(sys_reset_to_loader_magic));
// request reset
SCB->AIRCR = SCB_AIRCR_VECTKEY_WRITEMAGIC | SCB_AIRCR_SYSRESETREQ_Msk;
@@ -95,7 +95,7 @@ void bootloader_jump(void) {
# else /* defined(BOOTLOADER_KIIBOHD) */
/* Default for Kinetis - expecting an ARM Teensy */
# include "wait.h"
-void bootloader_jump(void) {
+__attribute__((weak)) void bootloader_jump(void) {
wait_ms(100);
__BKPT(0);
}
diff --git a/tmk_core/common/eeconfig.c b/tmk_core/common/eeconfig.c
index 3c26b8f613..8ae4c30519 100644
--- a/tmk_core/common/eeconfig.c
+++ b/tmk_core/common/eeconfig.c
@@ -15,7 +15,10 @@
# include "eeprom_driver.h"
#endif
-extern layer_state_t default_layer_state;
+#if defined(HAPTIC_ENABLE)
+# include "haptic.h"
+#endif
+
/** \brief eeconfig enable
*
* FIXME: needs doc
@@ -70,6 +73,16 @@ void eeconfig_init_quantum(void) {
#ifdef ORYX_ENABLE
eeconfig_init_oryx();
#endif
+
+#if defined(HAPTIC_ENABLE)
+ haptic_reset();
+#else
+ // this is used in case haptic is disabled, but we still want sane defaults
+ // in the haptic configuration eeprom. All zero will trigger a haptic_reset
+ // when a haptic-enabled firmware is loaded onto the keyboard.
+ eeprom_update_dword(EECONFIG_HAPTIC, 0);
+#endif
+
eeconfig_init_kb();
}
diff --git a/tmk_core/common/keyboard.c b/tmk_core/common/keyboard.c
index 4b241b7b3d..aefdd2bfb6 100644
--- a/tmk_core/common/keyboard.c
+++ b/tmk_core/common/keyboard.c
@@ -230,6 +230,20 @@ __attribute__((weak)) bool is_keyboard_left(void) { return true; }
*/
__attribute__((weak)) bool should_process_keypress(void) { return is_keyboard_master(); }
+/** \brief housekeeping_task_kb
+ *
+ * Override this function if you have a need to execute code for every keyboard main loop iteration.
+ * This is specific to keyboard-level functionality.
+ */
+__attribute__((weak)) void housekeeping_task_kb(void) {}
+
+/** \brief housekeeping_task_user
+ *
+ * Override this function if you have a need to execute code for every keyboard main loop iteration.
+ * This is specific to user/keymap-level functionality.
+ */
+__attribute__((weak)) void housekeeping_task_user(void) {}
+
/** \brief keyboard_init
*
* FIXME: needs doc
@@ -286,6 +300,10 @@ void keyboard_init(void) {
dip_switch_init();
#endif
+#if defined(DEBUG_MATRIX_SCAN_RATE) && defined(CONSOLE_ENABLE)
+ debug_enable = true;
+#endif
+
keyboard_post_init_kb(); /* Always keep this last */
}
@@ -310,6 +328,9 @@ void keyboard_task(void) {
uint8_t keys_processed = 0;
#endif
+ housekeeping_task_kb();
+ housekeeping_task_user();
+
#if defined(OLED_DRIVER_ENABLE) && !defined(OLED_DISABLE_TIMEOUT)
uint8_t ret = matrix_scan();
#else
diff --git a/tmk_core/common/keyboard.h b/tmk_core/common/keyboard.h
index d5836c40f9..1e16a3f489 100644
--- a/tmk_core/common/keyboard.h
+++ b/tmk_core/common/keyboard.h
@@ -73,6 +73,9 @@ void keyboard_pre_init_user(void);
void keyboard_post_init_kb(void);
void keyboard_post_init_user(void);
+void housekeeping_task_kb(void);
+void housekeeping_task_user(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/tmk_core/common/matrix.h b/tmk_core/common/matrix.h
index 78506059e6..31ec844302 100644
--- a/tmk_core/common/matrix.h
+++ b/tmk_core/common/matrix.h
@@ -30,16 +30,6 @@ typedef uint32_t matrix_row_t;
# error "MATRIX_COLS: invalid value"
#endif
-#if (MATRIX_ROWS <= 8)
-typedef uint8_t matrix_col_t;
-#elif (MATRIX_ROWS <= 16)
-typedef uint16_t matrix_col_t;
-#elif (MATRIX_ROWS <= 32)
-typedef uint32_t matrix_col_t;
-#else
-# error "MATRIX_ROWS: invalid value"
-#endif
-
#define MATRIX_ROW_SHIFTER ((matrix_row_t)1)
#define MATRIX_IS_ON(row, col) (matrix_get_row(row) && (1 << col))
diff --git a/tmk_core/common/report.h b/tmk_core/common/report.h
index 1aa33c998d..610addf431 100644
--- a/tmk_core/common/report.h
+++ b/tmk_core/common/report.h
@@ -192,7 +192,11 @@ typedef struct {
typedef struct {
#if JOYSTICK_AXES_COUNT > 0
+# if JOYSTICK_AXES_RESOLUTION > 8
+ int16_t axes[JOYSTICK_AXES_COUNT];
+# else
int8_t axes[JOYSTICK_AXES_COUNT];
+# endif
#endif
#if JOYSTICK_BUTTON_COUNT > 0
diff --git a/tmk_core/protocol/arm_atsam.mk b/tmk_core/protocol/arm_atsam.mk
index 8d6f724f09..5bb45d658e 100644
--- a/tmk_core/protocol/arm_atsam.mk
+++ b/tmk_core/protocol/arm_atsam.mk
@@ -4,9 +4,9 @@ SRC += $(ARM_ATSAM_DIR)/adc.c
SRC += $(ARM_ATSAM_DIR)/clks.c
SRC += $(ARM_ATSAM_DIR)/d51_util.c
SRC += $(ARM_ATSAM_DIR)/i2c_master.c
-ifeq ($(RGB_MATRIX_ENABLE),custom)
- SRC += $(ARM_ATSAM_DIR)/led_matrix_programs.c
- SRC += $(ARM_ATSAM_DIR)/led_matrix.c
+ifeq ($(RGB_MATRIX_DRIVER),custom)
+ SRC += $(ARM_ATSAM_DIR)/md_rgb_matrix_programs.c
+ SRC += $(ARM_ATSAM_DIR)/md_rgb_matrix.c
endif
SRC += $(ARM_ATSAM_DIR)/main_arm_atsam.c
SRC += $(ARM_ATSAM_DIR)/spi.c
diff --git a/tmk_core/protocol/arm_atsam/arm_atsam_protocol.h b/tmk_core/protocol/arm_atsam/arm_atsam_protocol.h
index 8cb00b872a..d126c66e7d 100644
--- a/tmk_core/protocol/arm_atsam/arm_atsam_protocol.h
+++ b/tmk_core/protocol/arm_atsam/arm_atsam_protocol.h
@@ -35,7 +35,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
# include "main_arm_atsam.h"
# ifdef RGB_MATRIX_ENABLE
-# include "led_matrix.h"
+# include "md_rgb_matrix.h"
# include "rgb_matrix.h"
# endif
# include "issi3733_driver.h"
diff --git a/tmk_core/protocol/arm_atsam/main_arm_atsam.c b/tmk_core/protocol/arm_atsam/main_arm_atsam.c
index e4e79d3510..e10be52fb8 100644
--- a/tmk_core/protocol/arm_atsam/main_arm_atsam.c
+++ b/tmk_core/protocol/arm_atsam/main_arm_atsam.c
@@ -305,6 +305,10 @@ int main(void) {
// dprintf("5v=%u 5vu=%u dlow=%u dhi=%u gca=%u gcd=%u\r\n", v_5v, v_5v_avg, v_5v_avg - V5_LOW, v_5v_avg - V5_HIGH, gcr_actual, gcr_desired);
}
#endif // CONSOLE_ENABLE
+
+ // Run housekeeping
+ housekeeping_task_kb();
+ housekeeping_task_user();
}
return 1;
diff --git a/tmk_core/protocol/arm_atsam/led_matrix.c b/tmk_core/protocol/arm_atsam/md_rgb_matrix.c
index 4b8cc7c5e1..b337df7627 100644
--- a/tmk_core/protocol/arm_atsam/led_matrix.c
+++ b/tmk_core/protocol/arm_atsam/md_rgb_matrix.c
@@ -23,7 +23,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef USE_MASSDROP_CONFIGURATOR
__attribute__((weak)) led_instruction_t led_instructions[] = {{.end = 1}};
-static void led_matrix_massdrop_config_override(int i);
+static void md_rgb_matrix_config_override(int i);
#endif // USE_MASSDROP_CONFIGURATOR
void SERCOM1_0_Handler(void) {
@@ -188,7 +188,7 @@ void issi3733_prepare_arrays(void) {
}
}
-void led_matrix_prepare(void) {
+void md_rgb_matrix_prepare(void) {
for (uint8_t i = 0; i < ISSI3733_LED_COUNT; i++) {
*led_map[i].rgb.r = 0;
*led_map[i].rgb.g = 0;
@@ -199,7 +199,7 @@ void led_matrix_prepare(void) {
void led_set_one(int i, uint8_t r, uint8_t g, uint8_t b) {
if (i < ISSI3733_LED_COUNT) {
#ifdef USE_MASSDROP_CONFIGURATOR
- led_matrix_massdrop_config_override(i);
+ md_rgb_matrix_config_override(i);
#else
led_buffer[i].r = r;
led_buffer[i].g = g;
@@ -219,7 +219,7 @@ void init(void) {
issi3733_prepare_arrays();
- led_matrix_prepare();
+ md_rgb_matrix_prepare();
gcr_min_counter = 0;
v_5v_cat_hit = 0;
@@ -290,7 +290,7 @@ void flush(void) {
i2c_led_q_run();
}
-void led_matrix_indicators(void) {
+void md_rgb_matrix_indicators(void) {
uint8_t kbled = keyboard_leds();
if (kbled && rgb_matrix_config.enable) {
for (uint8_t i = 0; i < ISSI3733_LED_COUNT; i++) {
@@ -395,7 +395,7 @@ static void led_run_pattern(led_setup_t* f, float* ro, float* go, float* bo, flo
}
}
-static void led_matrix_massdrop_config_override(int i) {
+static void md_rgb_matrix_config_override(int i) {
float ro = 0;
float go = 0;
float bo = 0;
diff --git a/tmk_core/protocol/arm_atsam/led_matrix.h b/tmk_core/protocol/arm_atsam/md_rgb_matrix.h
index 8eaa5623bd..322b0f99d1 100644
--- a/tmk_core/protocol/arm_atsam/led_matrix.h
+++ b/tmk_core/protocol/arm_atsam/md_rgb_matrix.h
@@ -86,7 +86,7 @@ extern uint8_t gcr_actual_last;
void gcr_compute(void);
-void led_matrix_indicators(void);
+void md_rgb_matrix_indicators(void);
/*------------------------- Legacy Lighting Support ------------------------*/
diff --git a/tmk_core/protocol/arm_atsam/led_matrix_programs.c b/tmk_core/protocol/arm_atsam/md_rgb_matrix_programs.c
index 360102ba84..b43008cc5b 100644
--- a/tmk_core/protocol/arm_atsam/led_matrix_programs.c
+++ b/tmk_core/protocol/arm_atsam/md_rgb_matrix_programs.c
@@ -17,7 +17,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef USE_MASSDROP_CONFIGURATOR
-# include "led_matrix.h"
+# include "md_rgb_matrix.h"
// Teal <-> Salmon
led_setup_t leds_teal_salmon[] = {
diff --git a/tmk_core/protocol/chibios/main.c b/tmk_core/protocol/chibios/main.c
index 2c4bf4b896..ea8279d7c3 100644
--- a/tmk_core/protocol/chibios/main.c
+++ b/tmk_core/protocol/chibios/main.c
@@ -54,6 +54,9 @@
#ifdef STM32_EEPROM_ENABLE
# include "eeprom_stm32.h"
#endif
+#ifdef EEPROM_DRIVER
+# include "eeprom_driver.h"
+#endif
#include "suspend.h"
#include "wait.h"
@@ -154,6 +157,9 @@ int main(void) {
#ifdef STM32_EEPROM_ENABLE
EEPROM_Init();
#endif
+#ifdef EEPROM_DRIVER
+ eeprom_driver_init();
+#endif
// TESTING
// chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL);
@@ -234,6 +240,7 @@ int main(void) {
/* Remote wakeup */
if (suspend_wakeup_condition()) {
usbWakeupHost(&USB_DRIVER);
+ restart_usb_driver(&USB_DRIVER);
}
}
/* Woken up */
@@ -266,5 +273,8 @@ int main(void) {
webusb_task();
#endif
+ // Run housekeeping
+ housekeeping_task_kb();
+ housekeeping_task_user();
}
}
diff --git a/tmk_core/protocol/chibios/usb_main.c b/tmk_core/protocol/chibios/usb_main.c
index 037aa077ce..2ecaaf65dc 100644
--- a/tmk_core/protocol/chibios/usb_main.c
+++ b/tmk_core/protocol/chibios/usb_main.c
@@ -184,6 +184,19 @@ const MS_OS_20_Descriptor_t PROGMEM MS_OS_20_Descriptor = MS_OS_20_DESCRIPTOR;
const WebUSB_URL_Descriptor_t PROGMEM WebUSB_LandingPage = WEBUSB_URL_DESCRIPTOR(WEBUSB_LANDING_PAGE_URL);
#endif
+#if STM32_USB_USE_OTG1
+typedef struct {
+ size_t queue_capacity_in;
+ size_t queue_capacity_out;
+ USBInEndpointState in_ep_state;
+ USBOutEndpointState out_ep_state;
+ USBInEndpointState int_ep_state;
+ USBEndpointConfig inout_ep_config;
+ USBEndpointConfig int_ep_config;
+ const QMKUSBConfig config;
+ QMKUSBDriver driver;
+} usb_driver_config_t;
+#else
typedef struct {
size_t queue_capacity_in;
size_t queue_capacity_out;
@@ -196,7 +209,54 @@ typedef struct {
const QMKUSBConfig config;
QMKUSBDriver driver;
} usb_driver_config_t;
+#endif
+#if STM32_USB_USE_OTG1
+/* Reusable initialization structure - see USBEndpointConfig comment at top of file */
+#define QMK_USB_DRIVER_CONFIG(stream, notification, fixedsize) \
+ { \
+ .queue_capacity_in = stream##_IN_CAPACITY, .queue_capacity_out = stream##_OUT_CAPACITY, \
+ .inout_ep_config = \
+ { \
+ stream##_IN_MODE, /* Interrupt EP */ \
+ NULL, /* SETUP packet notification callback */ \
+ qmkusbDataTransmitted, /* IN notification callback */ \
+ qmkusbDataReceived, /* OUT notification callback */ \
+ stream##_EPSIZE, /* IN maximum packet size */ \
+ stream##_EPSIZE, /* OUT maximum packet size */ \
+ NULL, /* IN Endpoint state */ \
+ NULL, /* OUT endpoint state */ \
+ 2, /* IN multiplier */ \
+ NULL /* SETUP buffer (not a SETUP endpoint) */ \
+ }, \
+ .int_ep_config = \
+ { \
+ USB_EP_MODE_TYPE_INTR, /* Interrupt EP */ \
+ NULL, /* SETUP packet notification callback */ \
+ qmkusbInterruptTransmitted, /* IN notification callback */ \
+ NULL, /* OUT notification callback */ \
+ CDC_NOTIFICATION_EPSIZE, /* IN maximum packet size */ \
+ 0, /* OUT maximum packet size */ \
+ NULL, /* IN Endpoint state */ \
+ NULL, /* OUT endpoint state */ \
+ 2, /* IN multiplier */ \
+ NULL, /* SETUP buffer (not a SETUP endpoint) */ \
+ }, \
+ .config = { \
+ .usbp = &USB_DRIVER, \
+ .bulk_in = stream##_IN_EPNUM, \
+ .bulk_out = stream##_OUT_EPNUM, \
+ .int_in = notification, \
+ .in_buffers = stream##_IN_CAPACITY, \
+ .out_buffers = stream##_OUT_CAPACITY, \
+ .in_size = stream##_EPSIZE, \
+ .out_size = stream##_EPSIZE, \
+ .fixed_size = fixedsize, \
+ .ib = (__attribute__((aligned(4))) uint8_t[BQ_BUFFER_SIZE(stream##_IN_CAPACITY, stream##_EPSIZE)]){}, \
+ .ob = (__attribute__((aligned(4))) uint8_t[BQ_BUFFER_SIZE(stream##_OUT_CAPACITY, stream##_EPSIZE)]){}, \
+ } \
+ }
+#else
/* Reusable initialization structure - see USBEndpointConfig comment at top of file */
#define QMK_USB_DRIVER_CONFIG(stream, notification, fixedsize) \
{ \
@@ -254,6 +314,7 @@ typedef struct {
.ob = (__attribute__((aligned(4))) uint8_t[BQ_BUFFER_SIZE(stream##_OUT_CAPACITY, stream##_EPSIZE)]){}, \
} \
}
+#endif
typedef struct {
union {
@@ -356,8 +417,12 @@ static void usb_event_cb(USBDriver *usbp, usbevent_t event) {
usbInitEndpointI(usbp, SHARED_IN_EPNUM, &shared_ep_config);
#endif
for (int i = 0; i < NUM_USB_DRIVERS; i++) {
+ #if STM32_USB_USE_OTG1
+ usbInitEndpointI(usbp, drivers.array[i].config.bulk_in, &drivers.array[i].inout_ep_config);
+ #else
usbInitEndpointI(usbp, drivers.array[i].config.bulk_in, &drivers.array[i].in_ep_config);
usbInitEndpointI(usbp, drivers.array[i].config.bulk_out, &drivers.array[i].out_ep_config);
+ #endif
if (drivers.array[i].config.int_in) {
usbInitEndpointI(usbp, drivers.array[i].config.int_in, &drivers.array[i].int_ep_config);
}
@@ -603,12 +668,21 @@ static const USBConfig usbcfg = {
*/
void init_usb_driver(USBDriver *usbp) {
for (int i = 0; i < NUM_USB_DRIVERS; i++) {
+ #if STM32_USB_USE_OTG1
+ QMKUSBDriver *driver = &drivers.array[i].driver;
+ drivers.array[i].inout_ep_config.in_state = &drivers.array[i].in_ep_state;
+ drivers.array[i].inout_ep_config.out_state = &drivers.array[i].out_ep_state;
+ drivers.array[i].int_ep_config.in_state = &drivers.array[i].int_ep_state;
+ qmkusbObjectInit(driver, &drivers.array[i].config);
+ qmkusbStart(driver, &drivers.array[i].config);
+ #else
QMKUSBDriver *driver = &drivers.array[i].driver;
drivers.array[i].in_ep_config.in_state = &drivers.array[i].in_ep_state;
drivers.array[i].out_ep_config.out_state = &drivers.array[i].out_ep_state;
drivers.array[i].int_ep_config.in_state = &drivers.array[i].int_ep_state;
qmkusbObjectInit(driver, &drivers.array[i].config);
qmkusbStart(driver, &drivers.array[i].config);
+ #endif
}
/*
@@ -624,6 +698,13 @@ void init_usb_driver(USBDriver *usbp) {
chVTObjectInit(&keyboard_idle_timer);
}
+void restart_usb_driver(USBDriver *usbp) {
+ usbStop(usbp);
+ usbDisconnectBus(usbp);
+ usbStart(usbp, &usbcfg);
+ usbConnectBus(usbp);
+}
+
/* ---------------------------------------------------------
* Keyboard functions
* ---------------------------------------------------------
diff --git a/tmk_core/protocol/chibios/usb_main.h b/tmk_core/protocol/chibios/usb_main.h
index 94baf9b35e..d8813f4801 100644
--- a/tmk_core/protocol/chibios/usb_main.h
+++ b/tmk_core/protocol/chibios/usb_main.h
@@ -35,6 +35,9 @@
/* Initialize the USB driver and bus */
void init_usb_driver(USBDriver *usbp);
+/* Restart the USB driver and bus */
+void restart_usb_driver(USBDriver *usbp);
+
/* ---------------
* Keyboard header
* ---------------
diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c
index 1cd9b1eae1..568d1dd501 100644
--- a/tmk_core/protocol/lufa/lufa.c
+++ b/tmk_core/protocol/lufa/lufa.c
@@ -1219,6 +1219,10 @@ int main(void) {
#if !defined(INTERRUPT_CONTROL_ENDPOINT)
USB_USBTask();
#endif
+
+ // Run housekeeping
+ housekeeping_task_kb();
+ housekeeping_task_user();
}
}
diff --git a/tmk_core/protocol/usb_descriptor.c b/tmk_core/protocol/usb_descriptor.c
index 764824f4dc..1d5a62aaa1 100644
--- a/tmk_core/protocol/usb_descriptor.c
+++ b/tmk_core/protocol/usb_descriptor.c
@@ -44,6 +44,10 @@
#endif
#include "usb_descriptor_common.h"
+#ifdef JOYSTICK_ENABLE
+# include "joystick.h"
+#endif
+
// clang-format off
/*
@@ -317,10 +321,17 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM JoystickReport[] = {
HID_RI_USAGE(8, 0x35), // Rz
# endif
# if JOYSTICK_AXES_COUNT >= 1
- HID_RI_LOGICAL_MINIMUM(8, -127),
- HID_RI_LOGICAL_MAXIMUM(8, 127),
+ # if JOYSTICK_AXES_RESOLUTION == 8
+ HID_RI_LOGICAL_MINIMUM(8, -JOYSTICK_RESOLUTION),
+ HID_RI_LOGICAL_MAXIMUM(8, JOYSTICK_RESOLUTION),
HID_RI_REPORT_COUNT(8, JOYSTICK_AXES_COUNT),
HID_RI_REPORT_SIZE(8, 0x08),
+ # else
+ HID_RI_LOGICAL_MINIMUM(16, -JOYSTICK_RESOLUTION),
+ HID_RI_LOGICAL_MAXIMUM(16, JOYSTICK_RESOLUTION),
+ HID_RI_REPORT_COUNT(8, JOYSTICK_AXES_COUNT),
+ HID_RI_REPORT_SIZE(8, 0x10),
+ # endif
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
# endif
diff --git a/tmk_core/protocol/usb_descriptor.h b/tmk_core/protocol/usb_descriptor.h
index 4157906544..ac897720f5 100644
--- a/tmk_core/protocol/usb_descriptor.h
+++ b/tmk_core/protocol/usb_descriptor.h
@@ -218,7 +218,11 @@ enum usb_endpoints {
#ifdef RAW_ENABLE
RAW_IN_EPNUM = NEXT_EPNUM,
+ #if STM32_USB_USE_OTG1
+ #define RAW_OUT_EPNUM RAW_IN_EPNUM
+ #else
RAW_OUT_EPNUM = NEXT_EPNUM,
+ #endif
#endif
#ifdef SHARED_EP_ENABLE
@@ -232,7 +236,11 @@ enum usb_endpoints {
// ChibiOS has enough memory and descriptor to actually enable the endpoint
// It could use the same endpoint numbers, as that's supported by ChibiOS
// But the QMK code currently assumes that the endpoint numbers are different
+ #if STM32_USB_USE_OTG1
+ #define CONSOLE_OUT_EPNUM CONSOLE_IN_EPNUM
+ #else
CONSOLE_OUT_EPNUM = NEXT_EPNUM,
+ #endif
# else
# define CONSOLE_OUT_EPNUM CONSOLE_IN_EPNUM
# endif
@@ -240,13 +248,21 @@ enum usb_endpoints {
#ifdef MIDI_ENABLE
MIDI_STREAM_IN_EPNUM = NEXT_EPNUM,
+ #if STM32_USB_USE_OTG1
+ #define MIDI_STREAM_OUT_EPNUM MIDI_STREAM_IN_EPNUM
+ #else
MIDI_STREAM_OUT_EPNUM = NEXT_EPNUM,
+ #endif
#endif
#ifdef VIRTSER_ENABLE
CDC_NOTIFICATION_EPNUM = NEXT_EPNUM,
CDC_IN_EPNUM = NEXT_EPNUM,
+ #if STM32_USB_USE_OTG1
+ #define CDC_OUT_EPNUM CDC_IN_EPNUM
+ #else
CDC_OUT_EPNUM = NEXT_EPNUM,
+ #endif
#endif
#ifdef WEBUSB_ENABLE
@@ -257,7 +273,11 @@ enum usb_endpoints {
#endif
#ifdef JOYSTICK_ENABLE
JOYSTICK_IN_EPNUM = NEXT_EPNUM,
+ #if STM32_USB_USE_OTG1
+ JOYSTICK_OUT_EPNUM = JOYSTICK_IN_EPNUM,
+ #else
JOYSTICK_OUT_EPNUM = NEXT_EPNUM,
+ #endif
#endif
};
diff --git a/tmk_core/protocol/vusb/main.c b/tmk_core/protocol/vusb/main.c
index a57df5ce06..0e3447d926 100644
--- a/tmk_core/protocol/vusb/main.c
+++ b/tmk_core/protocol/vusb/main.c
@@ -153,6 +153,10 @@ int main(void) {
console_task();
}
#endif
+
+ // Run housekeeping
+ housekeeping_task_kb();
+ housekeeping_task_user();
} else if (suspend_wakeup_condition()) {
usb_remote_wakeup();
}