From 4d8d69237d0a9e73e1723480e4225c9390533021 Mon Sep 17 00:00:00 2001
From: James Young <18669334+noroadsleft@users.noreply.github.com>
Date: Sat, 28 Nov 2020 12:02:18 -0800
Subject: 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
---
Makefile | 24 +-
build_keyboard.mk | 13 +
build_test.mk | 1 +
common.mk | 1 +
common_features.mk | 122 ++--
drivers/avr/serial.c | 139 ++--
drivers/chibios/i2c_master.c | 21 +-
drivers/chibios/spi_master.c | 27 +-
drivers/eeprom/eeprom_i2c.c | 12 +-
drivers/eeprom/eeprom_spi.c | 14 +-
drivers/haptic/haptic.c | 53 +-
drivers/haptic/solenoid.c | 10 +-
drivers/haptic/solenoid.h | 18 +-
drivers/oled/oled_driver.c | 22 +-
keyboards/ergodox_ez/rules.mk | 3 +-
keyboards/moonlander/rules.mk | 3 +-
keyboards/planck/ez/glow/rules.mk | 2 +-
keyboards/planck/ez/rules.mk | 1 +
keyboards/planck/planck.h | 23 +-
lib/python/qmk/cli/__init__.py | 1 +
lib/python/qmk/cli/chibios/__init__.py | 1 +
lib/python/qmk/cli/chibios/confmigrate.py | 161 +++++
lib/python/qmk/cli/doctor.py | 2 +-
lib/python/qmk/questions.py | 183 ------
message.mk | 3 +
.../chibios/BLACKPILL_STM32_F401/configs/config.h | 4 +-
.../chibios/BLACKPILL_STM32_F411/configs/config.h | 4 +-
.../chibios/GENERIC_STM32_F042X6/configs/mcuconf.h | 168 +++++
.../chibios/GENERIC_STM32_F072XB/board/board.c | 250 --------
.../chibios/GENERIC_STM32_F072XB/board/board.h | 407 ------------
.../chibios/GENERIC_STM32_F072XB/board/board.mk | 4 +-
.../chibios/GENERIC_STM32_F072XB/configs/board.h | 20 +
.../chibios/GENERIC_STM32_F072XB/configs/mcuconf.h | 177 +++++
.../chibios/GENERIC_STM32_F303XC/configs/chconf.h | 714 ---------------------
.../chibios/GENERIC_STM32_F303XC/configs/config.h | 4 +-
.../chibios/GENERIC_STM32_F303XC/configs/halconf.h | 525 ---------------
.../STM32_F103_STM32DUINO/configs/mcuconf.h | 209 ++++++
platforms/chibios/common/configs/chconf.h | 714 +++++++++++++++++++++
platforms/chibios/common/configs/halconf.h | 525 +++++++++++++++
platforms/chibios/common/ld/MKL26Z64.ld | 105 +++
.../common/ld/STM32F103x8_stm32duino_bootloader.ld | 85 +++
platforms/chibios/ld/MKL26Z64.ld | 105 ---
.../ld/STM32F103x8_stm32duino_bootloader.ld | 85 ---
quantum/backlight/backlight_avr.c | 12 +-
quantum/backlight/backlight_chibios.c | 14 +-
quantum/config_common.h | 92 ++-
quantum/encoder.c | 24 +-
quantum/joystick.h | 12 +-
quantum/led_matrix.c | 2 +-
quantum/led_matrix.h | 127 ++++
quantum/led_matrix_drivers.c | 2 +-
quantum/ledmatrix.h | 127 ----
quantum/matrix.c | 35 +-
quantum/mcu_selection.mk | 3 +
quantum/process_keycode/process_auto_shift.c | 213 ++++--
quantum/process_keycode/process_auto_shift.h | 11 +-
quantum/process_keycode/process_joystick.c | 8 +-
quantum/process_keycode/process_midi.c | 25 +-
quantum/process_keycode/process_midi.h | 2 +-
quantum/process_keycode/process_sequencer.c | 62 ++
quantum/process_keycode/process_sequencer.h | 21 +
quantum/quantum.c | 15 +
quantum/quantum.h | 62 +-
quantum/quantum_keycodes.h | 38 +-
quantum/rgb_matrix.c | 32 +-
quantum/rgb_matrix.h | 9 +
quantum/rgb_matrix_animations/alpha_mods_anim.h | 4 +-
quantum/rgb_matrix_animations/breathing_anim.h | 2 +-
.../gradient_left_right_anim.h | 2 +-
.../rgb_matrix_animations/gradient_up_down_anim.h | 2 +-
.../jellybean_raindrops_anim.h | 2 +-
quantum/rgb_matrix_animations/raindrops_anim.h | 2 +-
quantum/rgb_matrix_animations/solid_color_anim.h | 2 +-
.../rgb_matrix_animations/typing_heatmap_anim.h | 2 +-
quantum/rgb_matrix_runners/effect_runner_dx_dy.h | 2 +-
.../rgb_matrix_runners/effect_runner_dx_dy_dist.h | 2 +-
quantum/rgb_matrix_runners/effect_runner_i.h | 2 +-
.../rgb_matrix_runners/effect_runner_reactive.h | 2 +-
.../effect_runner_reactive_splash.h | 2 +-
.../rgb_matrix_runners/effect_runner_sin_cos_i.h | 2 +-
quantum/rgblight.c | 4 +-
quantum/sequencer/sequencer.c | 275 ++++++++
quantum/sequencer/sequencer.h | 122 ++++
quantum/sequencer/tests/midi_mock.c | 26 +
quantum/sequencer/tests/midi_mock.h | 26 +
quantum/sequencer/tests/rules.mk | 11 +
quantum/sequencer/tests/sequencer_tests.cpp | 590 +++++++++++++++++
quantum/sequencer/tests/testlist.mk | 1 +
quantum/split_common/matrix.c | 35 +-
requirements.txt | 2 +-
show_options.mk | 1 +
testlist.mk | 1 +
tmk_core/chibios.mk | 10 +-
tmk_core/common/action.c | 66 +-
tmk_core/common/action_util.c | 31 +-
tmk_core/common/action_util.h | 7 +-
tmk_core/common/arm_atsam/suspend.c | 2 +-
tmk_core/common/chibios/bootloader.c | 10 +-
tmk_core/common/eeconfig.c | 15 +-
tmk_core/common/keyboard.c | 21 +
tmk_core/common/keyboard.h | 3 +
tmk_core/common/matrix.h | 10 -
tmk_core/common/report.h | 4 +
tmk_core/protocol/arm_atsam.mk | 6 +-
tmk_core/protocol/arm_atsam/arm_atsam_protocol.h | 2 +-
tmk_core/protocol/arm_atsam/led_matrix.c | 470 --------------
tmk_core/protocol/arm_atsam/led_matrix.h | 158 -----
tmk_core/protocol/arm_atsam/led_matrix_programs.c | 99 ---
tmk_core/protocol/arm_atsam/main_arm_atsam.c | 4 +
tmk_core/protocol/arm_atsam/md_rgb_matrix.c | 470 ++++++++++++++
tmk_core/protocol/arm_atsam/md_rgb_matrix.h | 158 +++++
.../protocol/arm_atsam/md_rgb_matrix_programs.c | 99 +++
tmk_core/protocol/chibios/main.c | 10 +
tmk_core/protocol/chibios/usb_main.c | 81 +++
tmk_core/protocol/chibios/usb_main.h | 3 +
tmk_core/protocol/lufa/lufa.c | 4 +
tmk_core/protocol/usb_descriptor.c | 15 +-
tmk_core/protocol/usb_descriptor.h | 20 +
tmk_core/protocol/vusb/main.c | 4 +
119 files changed, 5309 insertions(+), 3510 deletions(-)
create mode 100644 lib/python/qmk/cli/chibios/__init__.py
create mode 100644 lib/python/qmk/cli/chibios/confmigrate.py
delete mode 100644 lib/python/qmk/questions.py
create mode 100644 platforms/chibios/GENERIC_STM32_F042X6/configs/mcuconf.h
delete mode 100644 platforms/chibios/GENERIC_STM32_F072XB/board/board.c
delete mode 100644 platforms/chibios/GENERIC_STM32_F072XB/board/board.h
create mode 100644 platforms/chibios/GENERIC_STM32_F072XB/configs/board.h
create mode 100644 platforms/chibios/GENERIC_STM32_F072XB/configs/mcuconf.h
delete mode 100644 platforms/chibios/GENERIC_STM32_F303XC/configs/chconf.h
delete mode 100644 platforms/chibios/GENERIC_STM32_F303XC/configs/halconf.h
create mode 100644 platforms/chibios/STM32_F103_STM32DUINO/configs/mcuconf.h
create mode 100644 platforms/chibios/common/configs/chconf.h
create mode 100644 platforms/chibios/common/configs/halconf.h
create mode 100644 platforms/chibios/common/ld/MKL26Z64.ld
create mode 100644 platforms/chibios/common/ld/STM32F103x8_stm32duino_bootloader.ld
delete mode 100644 platforms/chibios/ld/MKL26Z64.ld
delete mode 100644 platforms/chibios/ld/STM32F103x8_stm32duino_bootloader.ld
create mode 100644 quantum/led_matrix.h
delete mode 100644 quantum/ledmatrix.h
create mode 100644 quantum/process_keycode/process_sequencer.c
create mode 100644 quantum/process_keycode/process_sequencer.h
create mode 100644 quantum/sequencer/sequencer.c
create mode 100644 quantum/sequencer/sequencer.h
create mode 100644 quantum/sequencer/tests/midi_mock.c
create mode 100644 quantum/sequencer/tests/midi_mock.h
create mode 100644 quantum/sequencer/tests/rules.mk
create mode 100644 quantum/sequencer/tests/sequencer_tests.cpp
create mode 100644 quantum/sequencer/tests/testlist.mk
delete mode 100644 tmk_core/protocol/arm_atsam/led_matrix.c
delete mode 100644 tmk_core/protocol/arm_atsam/led_matrix.h
delete mode 100644 tmk_core/protocol/arm_atsam/led_matrix_programs.c
create mode 100644 tmk_core/protocol/arm_atsam/md_rgb_matrix.c
create mode 100644 tmk_core/protocol/arm_atsam/md_rgb_matrix.h
create mode 100644 tmk_core/protocol/arm_atsam/md_rgb_matrix_programs.c
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 .
+ */
+
+/*
+ * 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[a-zA-Z0-9_]+(\([^\)]*\))?)\s*(?P.*)', 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 \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 \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 \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 .
+ */
+#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/chconf.h b/platforms/chibios/GENERIC_STM32_F303XC/configs/chconf.h
deleted file mode 100644
index aac3303705..0000000000
--- a/platforms/chibios/GENERIC_STM32_F303XC/configs/chconf.h
+++ /dev/null
@@ -1,714 +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.
-*/
-
-/**
- * @file rt/templates/chconf.h
- * @brief Configuration file template.
- * @details A copy of this file must be placed in each project directory, it
- * contains the application specific kernel settings.
- *
- * @addtogroup config
- * @details Kernel related settings and hooks.
- * @{
- */
-
-#ifndef CHCONF_H
-#define CHCONF_H
-
-#define _CHIBIOS_RT_CONF_
-#define _CHIBIOS_RT_CONF_VER_6_0_
-
-/*===========================================================================*/
-/**
- * @name System timers settings
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief System time counter resolution.
- * @note Allowed values are 16 or 32 bits.
- */
-#if !defined(CH_CFG_ST_RESOLUTION)
-#define CH_CFG_ST_RESOLUTION 32
-#endif
-
-/**
- * @brief System tick frequency.
- * @details Frequency of the system timer that drives the system ticks. This
- * setting also defines the system tick time unit.
- */
-#if !defined(CH_CFG_ST_FREQUENCY)
-#define CH_CFG_ST_FREQUENCY 100000
-#endif
-
-/**
- * @brief Time intervals data size.
- * @note Allowed values are 16, 32 or 64 bits.
- */
-#if !defined(CH_CFG_INTERVALS_SIZE)
-#define CH_CFG_INTERVALS_SIZE 32
-#endif
-
-/**
- * @brief Time types data size.
- * @note Allowed values are 16 or 32 bits.
- */
-#if !defined(CH_CFG_TIME_TYPES_SIZE)
-#define CH_CFG_TIME_TYPES_SIZE 32
-#endif
-
-/**
- * @brief Time delta constant for the tick-less mode.
- * @note If this value is zero then the system uses the classic
- * periodic tick. This value represents the minimum number
- * of ticks that is safe to specify in a timeout directive.
- * The value one is not valid, timeouts are rounded up to
- * this value.
- */
-#if !defined(CH_CFG_ST_TIMEDELTA)
-#define CH_CFG_ST_TIMEDELTA 2
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name Kernel parameters and options
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief Round robin interval.
- * @details This constant is the number of system ticks allowed for the
- * threads before preemption occurs. Setting this value to zero
- * disables the preemption for threads with equal priority and the
- * round robin becomes cooperative. Note that higher priority
- * threads can still preempt, the kernel is always preemptive.
- * @note Disabling the round robin preemption makes the kernel more compact
- * and generally faster.
- * @note The round robin preemption is not supported in tickless mode and
- * must be set to zero in that case.
- */
-#if !defined(CH_CFG_TIME_QUANTUM)
-#define CH_CFG_TIME_QUANTUM 0
-#endif
-
-/**
- * @brief Managed RAM size.
- * @details Size of the RAM area to be managed by the OS. If set to zero
- * then the whole available RAM is used. The core memory is made
- * available to the heap allocator and/or can be used directly through
- * the simplified core memory allocator.
- *
- * @note In order to let the OS manage the whole RAM the linker script must
- * provide the @p __heap_base__ and @p __heap_end__ symbols.
- * @note Requires @p CH_CFG_USE_MEMCORE.
- */
-#if !defined(CH_CFG_MEMCORE_SIZE)
-#define CH_CFG_MEMCORE_SIZE 0
-#endif
-
-/**
- * @brief Idle thread automatic spawn suppression.
- * @details When this option is activated the function @p chSysInit()
- * does not spawn the idle thread. The application @p main()
- * function becomes the idle thread and must implement an
- * infinite loop.
- */
-#if !defined(CH_CFG_NO_IDLE_THREAD)
-#define CH_CFG_NO_IDLE_THREAD FALSE
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name Performance options
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief OS optimization.
- * @details If enabled then time efficient rather than space efficient code
- * is used when two possible implementations exist.
- *
- * @note This is not related to the compiler optimization options.
- * @note The default is @p TRUE.
- */
-#if !defined(CH_CFG_OPTIMIZE_SPEED)
-#define CH_CFG_OPTIMIZE_SPEED TRUE
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name Subsystem options
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief Time Measurement APIs.
- * @details If enabled then the time measurement APIs are included in
- * the kernel.
- *
- * @note The default is @p TRUE.
- */
-#if !defined(CH_CFG_USE_TM)
-#define CH_CFG_USE_TM TRUE
-#endif
-
-/**
- * @brief Threads registry APIs.
- * @details If enabled then the registry APIs are included in the kernel.
- *
- * @note The default is @p TRUE.
- */
-#if !defined(CH_CFG_USE_REGISTRY)
-#define CH_CFG_USE_REGISTRY TRUE
-#endif
-
-/**
- * @brief Threads synchronization APIs.
- * @details If enabled then the @p chThdWait() function is included in
- * the kernel.
- *
- * @note The default is @p TRUE.
- */
-#if !defined(CH_CFG_USE_WAITEXIT)
-#define CH_CFG_USE_WAITEXIT TRUE
-#endif
-
-/**
- * @brief Semaphores APIs.
- * @details If enabled then the Semaphores APIs are included in the kernel.
- *
- * @note The default is @p TRUE.
- */
-#if !defined(CH_CFG_USE_SEMAPHORES)
-#define CH_CFG_USE_SEMAPHORES TRUE
-#endif
-
-/**
- * @brief Semaphores queuing mode.
- * @details If enabled then the threads are enqueued on semaphores by
- * priority rather than in FIFO order.
- *
- * @note The default is @p FALSE. Enable this if you have special
- * requirements.
- * @note Requires @p CH_CFG_USE_SEMAPHORES.
- */
-#if !defined(CH_CFG_USE_SEMAPHORES_PRIORITY)
-#define CH_CFG_USE_SEMAPHORES_PRIORITY FALSE
-#endif
-
-/**
- * @brief Mutexes APIs.
- * @details If enabled then the mutexes APIs are included in the kernel.
- *
- * @note The default is @p TRUE.
- */
-#if !defined(CH_CFG_USE_MUTEXES)
-#define CH_CFG_USE_MUTEXES TRUE
-#endif
-
-/**
- * @brief Enables recursive behavior on mutexes.
- * @note Recursive mutexes are heavier and have an increased
- * memory footprint.
- *
- * @note The default is @p FALSE.
- * @note Requires @p CH_CFG_USE_MUTEXES.
- */
-#if !defined(CH_CFG_USE_MUTEXES_RECURSIVE)
-#define CH_CFG_USE_MUTEXES_RECURSIVE FALSE
-#endif
-
-/**
- * @brief Conditional Variables APIs.
- * @details If enabled then the conditional variables APIs are included
- * in the kernel.
- *
- * @note The default is @p TRUE.
- * @note Requires @p CH_CFG_USE_MUTEXES.
- */
-#if !defined(CH_CFG_USE_CONDVARS)
-#define CH_CFG_USE_CONDVARS TRUE
-#endif
-
-/**
- * @brief Conditional Variables APIs with timeout.
- * @details If enabled then the conditional variables APIs with timeout
- * specification are included in the kernel.
- *
- * @note The default is @p TRUE.
- * @note Requires @p CH_CFG_USE_CONDVARS.
- */
-#if !defined(CH_CFG_USE_CONDVARS_TIMEOUT)
-#define CH_CFG_USE_CONDVARS_TIMEOUT TRUE
-#endif
-
-/**
- * @brief Events Flags APIs.
- * @details If enabled then the event flags APIs are included in the kernel.
- *
- * @note The default is @p TRUE.
- */
-#if !defined(CH_CFG_USE_EVENTS)
-#define CH_CFG_USE_EVENTS TRUE
-#endif
-
-/**
- * @brief Events Flags APIs with timeout.
- * @details If enabled then the events APIs with timeout specification
- * are included in the kernel.
- *
- * @note The default is @p TRUE.
- * @note Requires @p CH_CFG_USE_EVENTS.
- */
-#if !defined(CH_CFG_USE_EVENTS_TIMEOUT)
-#define CH_CFG_USE_EVENTS_TIMEOUT TRUE
-#endif
-
-/**
- * @brief Synchronous Messages APIs.
- * @details If enabled then the synchronous messages APIs are included
- * in the kernel.
- *
- * @note The default is @p TRUE.
- */
-#if !defined(CH_CFG_USE_MESSAGES)
-#define CH_CFG_USE_MESSAGES TRUE
-#endif
-
-/**
- * @brief Synchronous Messages queuing mode.
- * @details If enabled then messages are served by priority rather than in
- * FIFO order.
- *
- * @note The default is @p FALSE. Enable this if you have special
- * requirements.
- * @note Requires @p CH_CFG_USE_MESSAGES.
- */
-#if !defined(CH_CFG_USE_MESSAGES_PRIORITY)
-#define CH_CFG_USE_MESSAGES_PRIORITY TRUE
-#endif
-
-/**
- * @brief Mailboxes APIs.
- * @details If enabled then the asynchronous messages (mailboxes) APIs are
- * included in the kernel.
- *
- * @note The default is @p TRUE.
- * @note Requires @p CH_CFG_USE_SEMAPHORES.
- */
-#if !defined(CH_CFG_USE_MAILBOXES)
-#define CH_CFG_USE_MAILBOXES TRUE
-#endif
-
-/**
- * @brief Core Memory Manager APIs.
- * @details If enabled then the core memory manager APIs are included
- * in the kernel.
- *
- * @note The default is @p TRUE.
- */
-#if !defined(CH_CFG_USE_MEMCORE)
-#define CH_CFG_USE_MEMCORE TRUE
-#endif
-
-/**
- * @brief Heap Allocator APIs.
- * @details If enabled then the memory heap allocator APIs are included
- * in the kernel.
- *
- * @note The default is @p TRUE.
- * @note Requires @p CH_CFG_USE_MEMCORE and either @p CH_CFG_USE_MUTEXES or
- * @p CH_CFG_USE_SEMAPHORES.
- * @note Mutexes are recommended.
- */
-#if !defined(CH_CFG_USE_HEAP)
-#define CH_CFG_USE_HEAP TRUE
-#endif
-
-/**
- * @brief Memory Pools Allocator APIs.
- * @details If enabled then the memory pools allocator APIs are included
- * in the kernel.
- *
- * @note The default is @p TRUE.
- */
-#if !defined(CH_CFG_USE_MEMPOOLS)
-#define CH_CFG_USE_MEMPOOLS TRUE
-#endif
-
-/**
- * @brief Objects FIFOs APIs.
- * @details If enabled then the objects FIFOs APIs are included
- * in the kernel.
- *
- * @note The default is @p TRUE.
- */
-#if !defined(CH_CFG_USE_OBJ_FIFOS)
-#define CH_CFG_USE_OBJ_FIFOS TRUE
-#endif
-
-/**
- * @brief Pipes APIs.
- * @details If enabled then the pipes APIs are included
- * in the kernel.
- *
- * @note The default is @p TRUE.
- */
-#if !defined(CH_CFG_USE_PIPES)
-#define CH_CFG_USE_PIPES TRUE
-#endif
-
-/**
- * @brief Dynamic Threads APIs.
- * @details If enabled then the dynamic threads creation APIs are included
- * in the kernel.
- *
- * @note The default is @p TRUE.
- * @note Requires @p CH_CFG_USE_WAITEXIT.
- * @note Requires @p CH_CFG_USE_HEAP and/or @p CH_CFG_USE_MEMPOOLS.
- */
-#if !defined(CH_CFG_USE_DYNAMIC)
-#define CH_CFG_USE_DYNAMIC TRUE
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name Objects factory options
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief Objects Factory APIs.
- * @details If enabled then the objects factory APIs are included in the
- * kernel.
- *
- * @note The default is @p FALSE.
- */
-#if !defined(CH_CFG_USE_FACTORY)
-#define CH_CFG_USE_FACTORY TRUE
-#endif
-
-/**
- * @brief Maximum length for object names.
- * @details If the specified length is zero then the name is stored by
- * pointer but this could have unintended side effects.
- */
-#if !defined(CH_CFG_FACTORY_MAX_NAMES_LENGTH)
-#define CH_CFG_FACTORY_MAX_NAMES_LENGTH 8
-#endif
-
-/**
- * @brief Enables the registry of generic objects.
- */
-#if !defined(CH_CFG_FACTORY_OBJECTS_REGISTRY)
-#define CH_CFG_FACTORY_OBJECTS_REGISTRY TRUE
-#endif
-
-/**
- * @brief Enables factory for generic buffers.
- */
-#if !defined(CH_CFG_FACTORY_GENERIC_BUFFERS)
-#define CH_CFG_FACTORY_GENERIC_BUFFERS TRUE
-#endif
-
-/**
- * @brief Enables factory for semaphores.
- */
-#if !defined(CH_CFG_FACTORY_SEMAPHORES)
-#define CH_CFG_FACTORY_SEMAPHORES TRUE
-#endif
-
-/**
- * @brief Enables factory for mailboxes.
- */
-#if !defined(CH_CFG_FACTORY_MAILBOXES)
-#define CH_CFG_FACTORY_MAILBOXES TRUE
-#endif
-
-/**
- * @brief Enables factory for objects FIFOs.
- */
-#if !defined(CH_CFG_FACTORY_OBJ_FIFOS)
-#define CH_CFG_FACTORY_OBJ_FIFOS TRUE
-#endif
-
-/**
- * @brief Enables factory for Pipes.
- */
-#if !defined(CH_CFG_FACTORY_PIPES) || defined(__DOXYGEN__)
-#define CH_CFG_FACTORY_PIPES TRUE
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name Debug options
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief Debug option, kernel statistics.
- *
- * @note The default is @p FALSE.
- */
-#if !defined(CH_DBG_STATISTICS)
-#define CH_DBG_STATISTICS FALSE
-#endif
-
-/**
- * @brief Debug option, system state check.
- * @details If enabled the correct call protocol for system APIs is checked
- * at runtime.
- *
- * @note The default is @p FALSE.
- */
-#if !defined(CH_DBG_SYSTEM_STATE_CHECK)
-#define CH_DBG_SYSTEM_STATE_CHECK FALSE
-#endif
-
-/**
- * @brief Debug option, parameters checks.
- * @details If enabled then the checks on the API functions input
- * parameters are activated.
- *
- * @note The default is @p FALSE.
- */
-#if !defined(CH_DBG_ENABLE_CHECKS)
-#define CH_DBG_ENABLE_CHECKS FALSE
-#endif
-
-/**
- * @brief Debug option, consistency checks.
- * @details If enabled then all the assertions in the kernel code are
- * activated. This includes consistency checks inside the kernel,
- * runtime anomalies and port-defined checks.
- *
- * @note The default is @p FALSE.
- */
-#if !defined(CH_DBG_ENABLE_ASSERTS)
-#define CH_DBG_ENABLE_ASSERTS FALSE
-#endif
-
-/**
- * @brief Debug option, trace buffer.
- * @details If enabled then the trace buffer is activated.
- *
- * @note The default is @p CH_DBG_TRACE_MASK_DISABLED.
- */
-#if !defined(CH_DBG_TRACE_MASK)
-#define CH_DBG_TRACE_MASK CH_DBG_TRACE_MASK_DISABLED
-#endif
-
-/**
- * @brief Trace buffer entries.
- * @note The trace buffer is only allocated if @p CH_DBG_TRACE_MASK is
- * different from @p CH_DBG_TRACE_MASK_DISABLED.
- */
-#if !defined(CH_DBG_TRACE_BUFFER_SIZE)
-#define CH_DBG_TRACE_BUFFER_SIZE 128
-#endif
-
-/**
- * @brief Debug option, stack checks.
- * @details If enabled then a runtime stack check is performed.
- *
- * @note The default is @p FALSE.
- * @note The stack check is performed in a architecture/port dependent way.
- * It may not be implemented or some ports.
- * @note The default failure mode is to halt the system with the global
- * @p panic_msg variable set to @p NULL.
- */
-#if !defined(CH_DBG_ENABLE_STACK_CHECK)
-#define CH_DBG_ENABLE_STACK_CHECK TRUE
-#endif
-
-/**
- * @brief Debug option, stacks initialization.
- * @details If enabled then the threads working area is filled with a byte
- * value when a thread is created. This can be useful for the
- * runtime measurement of the used stack.
- *
- * @note The default is @p FALSE.
- */
-#if !defined(CH_DBG_FILL_THREADS)
-#define CH_DBG_FILL_THREADS FALSE
-#endif
-
-/**
- * @brief Debug option, threads profiling.
- * @details If enabled then a field is added to the @p thread_t structure that
- * counts the system ticks occurred while executing the thread.
- *
- * @note The default is @p FALSE.
- * @note This debug option is not currently compatible with the
- * tickless mode.
- */
-#if !defined(CH_DBG_THREADS_PROFILING)
-#define CH_DBG_THREADS_PROFILING FALSE
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name Kernel hooks
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief System structure extension.
- * @details User fields added to the end of the @p ch_system_t structure.
- */
-#define CH_CFG_SYSTEM_EXTRA_FIELDS \
- /* Add threads custom fields here.*/
-
-/**
- * @brief System initialization hook.
- * @details User initialization code added to the @p chSysInit() function
- * just before interrupts are enabled globally.
- */
-#define CH_CFG_SYSTEM_INIT_HOOK() { \
- /* Add threads initialization code here.*/ \
-}
-
-/**
- * @brief Threads descriptor structure extension.
- * @details User fields added to the end of the @p thread_t structure.
- */
-#define CH_CFG_THREAD_EXTRA_FIELDS \
- /* Add threads custom fields here.*/
-
-/**
- * @brief Threads initialization hook.
- * @details User initialization code added to the @p _thread_init() function.
- *
- * @note It is invoked from within @p _thread_init() and implicitly from all
- * the threads creation APIs.
- */
-#define CH_CFG_THREAD_INIT_HOOK(tp) { \
- /* Add threads initialization code here.*/ \
-}
-
-/**
- * @brief Threads finalization hook.
- * @details User finalization code added to the @p chThdExit() API.
- */
-#define CH_CFG_THREAD_EXIT_HOOK(tp) { \
- /* Add threads finalization code here.*/ \
-}
-
-/**
- * @brief Context switch hook.
- * @details This hook is invoked just before switching between threads.
- */
-#define CH_CFG_CONTEXT_SWITCH_HOOK(ntp, otp) { \
- /* Context switch code here.*/ \
-}
-
-/**
- * @brief ISR enter hook.
- */
-#define CH_CFG_IRQ_PROLOGUE_HOOK() { \
- /* IRQ prologue code here.*/ \
-}
-
-/**
- * @brief ISR exit hook.
- */
-#define CH_CFG_IRQ_EPILOGUE_HOOK() { \
- /* IRQ epilogue code here.*/ \
-}
-
-/**
- * @brief Idle thread enter hook.
- * @note This hook is invoked within a critical zone, no OS functions
- * should be invoked from here.
- * @note This macro can be used to activate a power saving mode.
- */
-#define CH_CFG_IDLE_ENTER_HOOK() { \
- /* Idle-enter code here.*/ \
-}
-
-/**
- * @brief Idle thread leave hook.
- * @note This hook is invoked within a critical zone, no OS functions
- * should be invoked from here.
- * @note This macro can be used to deactivate a power saving mode.
- */
-#define CH_CFG_IDLE_LEAVE_HOOK() { \
- /* Idle-leave code here.*/ \
-}
-
-/**
- * @brief Idle Loop hook.
- * @details This hook is continuously invoked by the idle thread loop.
- */
-#define CH_CFG_IDLE_LOOP_HOOK() { \
- /* Idle loop code here.*/ \
-}
-
-/**
- * @brief System tick event hook.
- * @details This hook is invoked in the system tick handler immediately
- * after processing the virtual timers queue.
- */
-#define CH_CFG_SYSTEM_TICK_HOOK() { \
- /* System tick event code here.*/ \
-}
-
-/**
- * @brief System halt hook.
- * @details This hook is invoked in case to a system halting error before
- * the system is halted.
- */
-#define CH_CFG_SYSTEM_HALT_HOOK(reason) { \
- /* System halt code here.*/ \
-}
-
-/**
- * @brief Trace hook.
- * @details This hook is invoked each time a new record is written in the
- * trace buffer.
- */
-#define CH_CFG_TRACE_HOOK(tep) { \
- /* Trace code here.*/ \
-}
-
-/** @} */
-
-/*===========================================================================*/
-/* Port-specific settings (override port settings defaulted in chcore.h). */
-/*===========================================================================*/
-
-#endif /* CHCONF_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/GENERIC_STM32_F303XC/configs/halconf.h b/platforms/chibios/GENERIC_STM32_F303XC/configs/halconf.h
deleted file mode 100644
index 6b48e289f9..0000000000
--- a/platforms/chibios/GENERIC_STM32_F303XC/configs/halconf.h
+++ /dev/null
@@ -1,525 +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.
-*/
-
-/**
- * @file templates/halconf.h
- * @brief HAL configuration header.
- * @details HAL configuration file, this file allows to enable or disable the
- * various device drivers from your application. You may also use
- * this file in order to override the device drivers default settings.
- *
- * @addtogroup HAL_CONF
- * @{
- */
-
-#ifndef HALCONF_H
-#define HALCONF_H
-
-#define _CHIBIOS_HAL_CONF_
-#define _CHIBIOS_HAL_CONF_VER_7_0_
-
-#include "mcuconf.h"
-
-/**
- * @brief Enables the PAL subsystem.
- */
-#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__)
-#define HAL_USE_PAL TRUE
-#endif
-
-/**
- * @brief Enables the ADC subsystem.
- */
-#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__)
-#define HAL_USE_ADC FALSE
-#endif
-
-/**
- * @brief Enables the CAN subsystem.
- */
-#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__)
-#define HAL_USE_CAN FALSE
-#endif
-
-/**
- * @brief Enables the cryptographic subsystem.
- */
-#if !defined(HAL_USE_CRY) || defined(__DOXYGEN__)
-#define HAL_USE_CRY FALSE
-#endif
-
-/**
- * @brief Enables the DAC subsystem.
- */
-#if !defined(HAL_USE_DAC) || defined(__DOXYGEN__)
-#define HAL_USE_DAC TRUE
-#endif
-
-/**
- * @brief Enables the GPT subsystem.
- */
-#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__)
-#define HAL_USE_GPT TRUE
-#endif
-
-/**
- * @brief Enables the I2C subsystem.
- */
-#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__)
-#define HAL_USE_I2C TRUE
-#endif
-
-/**
- * @brief Enables the I2S subsystem.
- */
-#if !defined(HAL_USE_I2S) || defined(__DOXYGEN__)
-#define HAL_USE_I2S FALSE
-#endif
-
-/**
- * @brief Enables the ICU subsystem.
- */
-#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__)
-#define HAL_USE_ICU FALSE
-#endif
-
-/**
- * @brief Enables the MAC subsystem.
- */
-#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__)
-#define HAL_USE_MAC FALSE
-#endif
-
-/**
- * @brief Enables the MMC_SPI subsystem.
- */
-#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__)
-#define HAL_USE_MMC_SPI FALSE
-#endif
-
-/**
- * @brief Enables the PWM subsystem.
- */
-#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__)
-#define HAL_USE_PWM TRUE
-#endif
-
-/**
- * @brief Enables the RTC subsystem.
- */
-#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__)
-#define HAL_USE_RTC FALSE
-#endif
-
-/**
- * @brief Enables the SDC subsystem.
- */
-#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__)
-#define HAL_USE_SDC FALSE
-#endif
-
-/**
- * @brief Enables the SERIAL subsystem.
- */
-#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__)
-#define HAL_USE_SERIAL FALSE
-#endif
-
-/**
- * @brief Enables the SERIAL over USB subsystem.
- */
-#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
-#define HAL_USE_SERIAL_USB TRUE
-#endif
-
-/**
- * @brief Enables the SIO subsystem.
- */
-#if !defined(HAL_USE_SIO) || defined(__DOXYGEN__)
-#define HAL_USE_SIO FALSE
-#endif
-
-/**
- * @brief Enables the SPI subsystem.
- */
-#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__)
-#define HAL_USE_SPI TRUE
-#endif
-
-/**
- * @brief Enables the TRNG subsystem.
- */
-#if !defined(HAL_USE_TRNG) || defined(__DOXYGEN__)
-#define HAL_USE_TRNG FALSE
-#endif
-
-/**
- * @brief Enables the UART subsystem.
- */
-#if !defined(HAL_USE_UART) || defined(__DOXYGEN__)
-#define HAL_USE_UART FALSE
-#endif
-
-/**
- * @brief Enables the USB subsystem.
- */
-#if !defined(HAL_USE_USB) || defined(__DOXYGEN__)
-#define HAL_USE_USB TRUE
-#endif
-
-/**
- * @brief Enables the WDG subsystem.
- */
-#if !defined(HAL_USE_WDG) || defined(__DOXYGEN__)
-#define HAL_USE_WDG FALSE
-#endif
-
-/**
- * @brief Enables the WSPI subsystem.
- */
-#if !defined(HAL_USE_WSPI) || defined(__DOXYGEN__)
-#define HAL_USE_WSPI FALSE
-#endif
-
-/*===========================================================================*/
-/* PAL driver related settings. */
-/*===========================================================================*/
-
-/**
- * @brief Enables synchronous APIs.
- * @note Disabling this option saves both code and data space.
- */
-#if !defined(PAL_USE_CALLBACKS) || defined(__DOXYGEN__)
-#define PAL_USE_CALLBACKS TRUE
-#endif
-
-/**
- * @brief Enables synchronous APIs.
- * @note Disabling this option saves both code and data space.
- */
-#if !defined(PAL_USE_WAIT) || defined(__DOXYGEN__)
-#define PAL_USE_WAIT TRUE
-#endif
-
-/*===========================================================================*/
-/* ADC driver related settings. */
-/*===========================================================================*/
-
-/**
- * @brief Enables synchronous APIs.
- * @note Disabling this option saves both code and data space.
- */
-#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__)
-#define ADC_USE_WAIT TRUE
-#endif
-
-/**
- * @brief Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs.
- * @note Disabling this option saves both code and data space.
- */
-#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
-#define ADC_USE_MUTUAL_EXCLUSION TRUE
-#endif
-
-/*===========================================================================*/
-/* CAN driver related settings. */
-/*===========================================================================*/
-
-/**
- * @brief Sleep mode related APIs inclusion switch.
- */
-#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__)
-#define CAN_USE_SLEEP_MODE TRUE
-#endif
-
-/**
- * @brief Enforces the driver to use direct callbacks rather than OSAL events.
- */
-#if !defined(CAN_ENFORCE_USE_CALLBACKS) || defined(__DOXYGEN__)
-#define CAN_ENFORCE_USE_CALLBACKS FALSE
-#endif
-
-/*===========================================================================*/
-/* CRY driver related settings. */
-/*===========================================================================*/
-
-/**
- * @brief Enables the SW fall-back of the cryptographic driver.
- * @details When enabled, this option, activates a fall-back software
- * implementation for algorithms not supported by the underlying
- * hardware.
- * @note Fall-back implementations may not be present for all algorithms.
- */
-#if !defined(HAL_CRY_USE_FALLBACK) || defined(__DOXYGEN__)
-#define HAL_CRY_USE_FALLBACK FALSE
-#endif
-
-/**
- * @brief Makes the driver forcibly use the fall-back implementations.
- */
-#if !defined(HAL_CRY_ENFORCE_FALLBACK) || defined(__DOXYGEN__)
-#define HAL_CRY_ENFORCE_FALLBACK FALSE
-#endif
-
-/*===========================================================================*/
-/* DAC driver related settings. */
-/*===========================================================================*/
-
-/**
- * @brief Enables synchronous APIs.
- * @note Disabling this option saves both code and data space.
- */
-#if !defined(DAC_USE_WAIT) || defined(__DOXYGEN__)
-#define DAC_USE_WAIT TRUE
-#endif
-
-/**
- * @brief Enables the @p dacAcquireBus() and @p dacReleaseBus() APIs.
- * @note Disabling this option saves both code and data space.
- */
-#if !defined(DAC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
-#define DAC_USE_MUTUAL_EXCLUSION TRUE
-#endif
-
-/*===========================================================================*/
-/* I2C driver related settings. */
-/*===========================================================================*/
-
-/**
- * @brief Enables the mutual exclusion APIs on the I2C bus.
- */
-#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
-#define I2C_USE_MUTUAL_EXCLUSION TRUE
-#endif
-
-/*===========================================================================*/
-/* MAC driver related settings. */
-/*===========================================================================*/
-
-/**
- * @brief Enables the zero-copy API.
- */
-#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__)
-#define MAC_USE_ZERO_COPY FALSE
-#endif
-
-/**
- * @brief Enables an event sources for incoming packets.
- */
-#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__)
-#define MAC_USE_EVENTS TRUE
-#endif
-
-/*===========================================================================*/
-/* MMC_SPI driver related settings. */
-/*===========================================================================*/
-
-/**
- * @brief Delays insertions.
- * @details If enabled this options inserts delays into the MMC waiting
- * routines releasing some extra CPU time for the threads with
- * lower priority, this may slow down the driver a bit however.
- * This option is recommended also if the SPI driver does not
- * use a DMA channel and heavily loads the CPU.
- */
-#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__)
-#define MMC_NICE_WAITING TRUE
-#endif
-
-/*===========================================================================*/
-/* SDC driver related settings. */
-/*===========================================================================*/
-
-/**
- * @brief Number of initialization attempts before rejecting the card.
- * @note Attempts are performed at 10mS intervals.
- */
-#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__)
-#define SDC_INIT_RETRY 100
-#endif
-
-/**
- * @brief Include support for MMC cards.
- * @note MMC support is not yet implemented so this option must be kept
- * at @p FALSE.
- */
-#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__)
-#define SDC_MMC_SUPPORT FALSE
-#endif
-
-/**
- * @brief Delays insertions.
- * @details If enabled this options inserts delays into the MMC waiting
- * routines releasing some extra CPU time for the threads with
- * lower priority, this may slow down the driver a bit however.
- */
-#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__)
-#define SDC_NICE_WAITING TRUE
-#endif
-
-/**
- * @brief OCR initialization constant for V20 cards.
- */
-#if !defined(SDC_INIT_OCR_V20) || defined(__DOXYGEN__)
-#define SDC_INIT_OCR_V20 0x50FF8000U
-#endif
-
-/**
- * @brief OCR initialization constant for non-V20 cards.
- */
-#if !defined(SDC_INIT_OCR) || defined(__DOXYGEN__)
-#define SDC_INIT_OCR 0x80100000U
-#endif
-
-/*===========================================================================*/
-/* SERIAL driver related settings. */
-/*===========================================================================*/
-
-/**
- * @brief Default bit rate.
- * @details Configuration parameter, this is the baud rate selected for the
- * default configuration.
- */
-#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__)
-#define SERIAL_DEFAULT_BITRATE 38400
-#endif
-
-/**
- * @brief Serial buffers size.
- * @details Configuration parameter, you can change the depth of the queue
- * buffers depending on the requirements of your application.
- * @note The default is 16 bytes for both the transmission and receive
- * buffers.
- */
-#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
-#define SERIAL_BUFFERS_SIZE 16
-#endif
-
-/*===========================================================================*/
-/* SERIAL_USB driver related setting. */
-/*===========================================================================*/
-
-/**
- * @brief Serial over USB buffers size.
- * @details Configuration parameter, the buffer size must be a multiple of
- * the USB data endpoint maximum packet size.
- * @note The default is 256 bytes for both the transmission and receive
- * buffers.
- */
-#if !defined(SERIAL_USB_BUFFERS_SIZE) || defined(__DOXYGEN__)
-#define SERIAL_USB_BUFFERS_SIZE 1
-#endif
-
-/**
- * @brief Serial over USB number of buffers.
- * @note The default is 2 buffers.
- */
-#if !defined(SERIAL_USB_BUFFERS_NUMBER) || defined(__DOXYGEN__)
-#define SERIAL_USB_BUFFERS_NUMBER 2
-#endif
-
-/*===========================================================================*/
-/* SPI driver related settings. */
-/*===========================================================================*/
-
-/**
- * @brief Enables synchronous APIs.
- * @note Disabling this option saves both code and data space.
- */
-#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
-#define SPI_USE_WAIT TRUE
-#endif
-
-/**
- * @brief Enables circular transfers APIs.
- * @note Disabling this option saves both code and data space.
- */
-#if !defined(SPI_USE_CIRCULAR) || defined(__DOXYGEN__)
-#define SPI_USE_CIRCULAR FALSE
-#endif
-
-
-/**
- * @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs.
- * @note Disabling this option saves both code and data space.
- */
-#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
-#define SPI_USE_MUTUAL_EXCLUSION TRUE
-#endif
-
-/**
- * @brief Handling method for SPI CS line.
- * @note Disabling this option saves both code and data space.
- */
-#if !defined(SPI_SELECT_MODE) || defined(__DOXYGEN__)
-#define SPI_SELECT_MODE SPI_SELECT_MODE_PAD
-#endif
-
-/*===========================================================================*/
-/* UART driver related settings. */
-/*===========================================================================*/
-
-/**
- * @brief Enables synchronous APIs.
- * @note Disabling this option saves both code and data space.
- */
-#if !defined(UART_USE_WAIT) || defined(__DOXYGEN__)
-#define UART_USE_WAIT FALSE
-#endif
-
-/**
- * @brief Enables the @p uartAcquireBus() and @p uartReleaseBus() APIs.
- * @note Disabling this option saves both code and data space.
- */
-#if !defined(UART_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
-#define UART_USE_MUTUAL_EXCLUSION FALSE
-#endif
-
-/*===========================================================================*/
-/* USB driver related settings. */
-/*===========================================================================*/
-
-/**
- * @brief Enables synchronous APIs.
- * @note Disabling this option saves both code and data space.
- */
-#if !defined(USB_USE_WAIT) || defined(__DOXYGEN__)
-#define USB_USE_WAIT TRUE
-#endif
-
-/*===========================================================================*/
-/* WSPI driver related settings. */
-/*===========================================================================*/
-
-/**
- * @brief Enables synchronous APIs.
- * @note Disabling this option saves both code and data space.
- */
-#if !defined(WSPI_USE_WAIT) || defined(__DOXYGEN__)
-#define WSPI_USE_WAIT TRUE
-#endif
-
-/**
- * @brief Enables the @p wspiAcquireBus() and @p wspiReleaseBus() APIs.
- * @note Disabling this option saves both code and data space.
- */
-#if !defined(WSPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
-#define WSPI_USE_MUTUAL_EXCLUSION TRUE
-#endif
-
-#endif /* HALCONF_H */
-
-/** @} */
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/common/configs/chconf.h b/platforms/chibios/common/configs/chconf.h
new file mode 100644
index 0000000000..aac3303705
--- /dev/null
+++ b/platforms/chibios/common/configs/chconf.h
@@ -0,0 +1,714 @@
+/*
+ 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.
+*/
+
+/**
+ * @file rt/templates/chconf.h
+ * @brief Configuration file template.
+ * @details A copy of this file must be placed in each project directory, it
+ * contains the application specific kernel settings.
+ *
+ * @addtogroup config
+ * @details Kernel related settings and hooks.
+ * @{
+ */
+
+#ifndef CHCONF_H
+#define CHCONF_H
+
+#define _CHIBIOS_RT_CONF_
+#define _CHIBIOS_RT_CONF_VER_6_0_
+
+/*===========================================================================*/
+/**
+ * @name System timers settings
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief System time counter resolution.
+ * @note Allowed values are 16 or 32 bits.
+ */
+#if !defined(CH_CFG_ST_RESOLUTION)
+#define CH_CFG_ST_RESOLUTION 32
+#endif
+
+/**
+ * @brief System tick frequency.
+ * @details Frequency of the system timer that drives the system ticks. This
+ * setting also defines the system tick time unit.
+ */
+#if !defined(CH_CFG_ST_FREQUENCY)
+#define CH_CFG_ST_FREQUENCY 100000
+#endif
+
+/**
+ * @brief Time intervals data size.
+ * @note Allowed values are 16, 32 or 64 bits.
+ */
+#if !defined(CH_CFG_INTERVALS_SIZE)
+#define CH_CFG_INTERVALS_SIZE 32
+#endif
+
+/**
+ * @brief Time types data size.
+ * @note Allowed values are 16 or 32 bits.
+ */
+#if !defined(CH_CFG_TIME_TYPES_SIZE)
+#define CH_CFG_TIME_TYPES_SIZE 32
+#endif
+
+/**
+ * @brief Time delta constant for the tick-less mode.
+ * @note If this value is zero then the system uses the classic
+ * periodic tick. This value represents the minimum number
+ * of ticks that is safe to specify in a timeout directive.
+ * The value one is not valid, timeouts are rounded up to
+ * this value.
+ */
+#if !defined(CH_CFG_ST_TIMEDELTA)
+#define CH_CFG_ST_TIMEDELTA 2
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Kernel parameters and options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief Round robin interval.
+ * @details This constant is the number of system ticks allowed for the
+ * threads before preemption occurs. Setting this value to zero
+ * disables the preemption for threads with equal priority and the
+ * round robin becomes cooperative. Note that higher priority
+ * threads can still preempt, the kernel is always preemptive.
+ * @note Disabling the round robin preemption makes the kernel more compact
+ * and generally faster.
+ * @note The round robin preemption is not supported in tickless mode and
+ * must be set to zero in that case.
+ */
+#if !defined(CH_CFG_TIME_QUANTUM)
+#define CH_CFG_TIME_QUANTUM 0
+#endif
+
+/**
+ * @brief Managed RAM size.
+ * @details Size of the RAM area to be managed by the OS. If set to zero
+ * then the whole available RAM is used. The core memory is made
+ * available to the heap allocator and/or can be used directly through
+ * the simplified core memory allocator.
+ *
+ * @note In order to let the OS manage the whole RAM the linker script must
+ * provide the @p __heap_base__ and @p __heap_end__ symbols.
+ * @note Requires @p CH_CFG_USE_MEMCORE.
+ */
+#if !defined(CH_CFG_MEMCORE_SIZE)
+#define CH_CFG_MEMCORE_SIZE 0
+#endif
+
+/**
+ * @brief Idle thread automatic spawn suppression.
+ * @details When this option is activated the function @p chSysInit()
+ * does not spawn the idle thread. The application @p main()
+ * function becomes the idle thread and must implement an
+ * infinite loop.
+ */
+#if !defined(CH_CFG_NO_IDLE_THREAD)
+#define CH_CFG_NO_IDLE_THREAD FALSE
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Performance options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief OS optimization.
+ * @details If enabled then time efficient rather than space efficient code
+ * is used when two possible implementations exist.
+ *
+ * @note This is not related to the compiler optimization options.
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_OPTIMIZE_SPEED)
+#define CH_CFG_OPTIMIZE_SPEED TRUE
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Subsystem options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief Time Measurement APIs.
+ * @details If enabled then the time measurement APIs are included in
+ * the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_TM)
+#define CH_CFG_USE_TM TRUE
+#endif
+
+/**
+ * @brief Threads registry APIs.
+ * @details If enabled then the registry APIs are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_REGISTRY)
+#define CH_CFG_USE_REGISTRY TRUE
+#endif
+
+/**
+ * @brief Threads synchronization APIs.
+ * @details If enabled then the @p chThdWait() function is included in
+ * the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_WAITEXIT)
+#define CH_CFG_USE_WAITEXIT TRUE
+#endif
+
+/**
+ * @brief Semaphores APIs.
+ * @details If enabled then the Semaphores APIs are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_SEMAPHORES)
+#define CH_CFG_USE_SEMAPHORES TRUE
+#endif
+
+/**
+ * @brief Semaphores queuing mode.
+ * @details If enabled then the threads are enqueued on semaphores by
+ * priority rather than in FIFO order.
+ *
+ * @note The default is @p FALSE. Enable this if you have special
+ * requirements.
+ * @note Requires @p CH_CFG_USE_SEMAPHORES.
+ */
+#if !defined(CH_CFG_USE_SEMAPHORES_PRIORITY)
+#define CH_CFG_USE_SEMAPHORES_PRIORITY FALSE
+#endif
+
+/**
+ * @brief Mutexes APIs.
+ * @details If enabled then the mutexes APIs are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_MUTEXES)
+#define CH_CFG_USE_MUTEXES TRUE
+#endif
+
+/**
+ * @brief Enables recursive behavior on mutexes.
+ * @note Recursive mutexes are heavier and have an increased
+ * memory footprint.
+ *
+ * @note The default is @p FALSE.
+ * @note Requires @p CH_CFG_USE_MUTEXES.
+ */
+#if !defined(CH_CFG_USE_MUTEXES_RECURSIVE)
+#define CH_CFG_USE_MUTEXES_RECURSIVE FALSE
+#endif
+
+/**
+ * @brief Conditional Variables APIs.
+ * @details If enabled then the conditional variables APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_CFG_USE_MUTEXES.
+ */
+#if !defined(CH_CFG_USE_CONDVARS)
+#define CH_CFG_USE_CONDVARS TRUE
+#endif
+
+/**
+ * @brief Conditional Variables APIs with timeout.
+ * @details If enabled then the conditional variables APIs with timeout
+ * specification are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_CFG_USE_CONDVARS.
+ */
+#if !defined(CH_CFG_USE_CONDVARS_TIMEOUT)
+#define CH_CFG_USE_CONDVARS_TIMEOUT TRUE
+#endif
+
+/**
+ * @brief Events Flags APIs.
+ * @details If enabled then the event flags APIs are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_EVENTS)
+#define CH_CFG_USE_EVENTS TRUE
+#endif
+
+/**
+ * @brief Events Flags APIs with timeout.
+ * @details If enabled then the events APIs with timeout specification
+ * are included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_CFG_USE_EVENTS.
+ */
+#if !defined(CH_CFG_USE_EVENTS_TIMEOUT)
+#define CH_CFG_USE_EVENTS_TIMEOUT TRUE
+#endif
+
+/**
+ * @brief Synchronous Messages APIs.
+ * @details If enabled then the synchronous messages APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_MESSAGES)
+#define CH_CFG_USE_MESSAGES TRUE
+#endif
+
+/**
+ * @brief Synchronous Messages queuing mode.
+ * @details If enabled then messages are served by priority rather than in
+ * FIFO order.
+ *
+ * @note The default is @p FALSE. Enable this if you have special
+ * requirements.
+ * @note Requires @p CH_CFG_USE_MESSAGES.
+ */
+#if !defined(CH_CFG_USE_MESSAGES_PRIORITY)
+#define CH_CFG_USE_MESSAGES_PRIORITY TRUE
+#endif
+
+/**
+ * @brief Mailboxes APIs.
+ * @details If enabled then the asynchronous messages (mailboxes) APIs are
+ * included in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_CFG_USE_SEMAPHORES.
+ */
+#if !defined(CH_CFG_USE_MAILBOXES)
+#define CH_CFG_USE_MAILBOXES TRUE
+#endif
+
+/**
+ * @brief Core Memory Manager APIs.
+ * @details If enabled then the core memory manager APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_MEMCORE)
+#define CH_CFG_USE_MEMCORE TRUE
+#endif
+
+/**
+ * @brief Heap Allocator APIs.
+ * @details If enabled then the memory heap allocator APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_CFG_USE_MEMCORE and either @p CH_CFG_USE_MUTEXES or
+ * @p CH_CFG_USE_SEMAPHORES.
+ * @note Mutexes are recommended.
+ */
+#if !defined(CH_CFG_USE_HEAP)
+#define CH_CFG_USE_HEAP TRUE
+#endif
+
+/**
+ * @brief Memory Pools Allocator APIs.
+ * @details If enabled then the memory pools allocator APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_MEMPOOLS)
+#define CH_CFG_USE_MEMPOOLS TRUE
+#endif
+
+/**
+ * @brief Objects FIFOs APIs.
+ * @details If enabled then the objects FIFOs APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_OBJ_FIFOS)
+#define CH_CFG_USE_OBJ_FIFOS TRUE
+#endif
+
+/**
+ * @brief Pipes APIs.
+ * @details If enabled then the pipes APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ */
+#if !defined(CH_CFG_USE_PIPES)
+#define CH_CFG_USE_PIPES TRUE
+#endif
+
+/**
+ * @brief Dynamic Threads APIs.
+ * @details If enabled then the dynamic threads creation APIs are included
+ * in the kernel.
+ *
+ * @note The default is @p TRUE.
+ * @note Requires @p CH_CFG_USE_WAITEXIT.
+ * @note Requires @p CH_CFG_USE_HEAP and/or @p CH_CFG_USE_MEMPOOLS.
+ */
+#if !defined(CH_CFG_USE_DYNAMIC)
+#define CH_CFG_USE_DYNAMIC TRUE
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Objects factory options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief Objects Factory APIs.
+ * @details If enabled then the objects factory APIs are included in the
+ * kernel.
+ *
+ * @note The default is @p FALSE.
+ */
+#if !defined(CH_CFG_USE_FACTORY)
+#define CH_CFG_USE_FACTORY TRUE
+#endif
+
+/**
+ * @brief Maximum length for object names.
+ * @details If the specified length is zero then the name is stored by
+ * pointer but this could have unintended side effects.
+ */
+#if !defined(CH_CFG_FACTORY_MAX_NAMES_LENGTH)
+#define CH_CFG_FACTORY_MAX_NAMES_LENGTH 8
+#endif
+
+/**
+ * @brief Enables the registry of generic objects.
+ */
+#if !defined(CH_CFG_FACTORY_OBJECTS_REGISTRY)
+#define CH_CFG_FACTORY_OBJECTS_REGISTRY TRUE
+#endif
+
+/**
+ * @brief Enables factory for generic buffers.
+ */
+#if !defined(CH_CFG_FACTORY_GENERIC_BUFFERS)
+#define CH_CFG_FACTORY_GENERIC_BUFFERS TRUE
+#endif
+
+/**
+ * @brief Enables factory for semaphores.
+ */
+#if !defined(CH_CFG_FACTORY_SEMAPHORES)
+#define CH_CFG_FACTORY_SEMAPHORES TRUE
+#endif
+
+/**
+ * @brief Enables factory for mailboxes.
+ */
+#if !defined(CH_CFG_FACTORY_MAILBOXES)
+#define CH_CFG_FACTORY_MAILBOXES TRUE
+#endif
+
+/**
+ * @brief Enables factory for objects FIFOs.
+ */
+#if !defined(CH_CFG_FACTORY_OBJ_FIFOS)
+#define CH_CFG_FACTORY_OBJ_FIFOS TRUE
+#endif
+
+/**
+ * @brief Enables factory for Pipes.
+ */
+#if !defined(CH_CFG_FACTORY_PIPES) || defined(__DOXYGEN__)
+#define CH_CFG_FACTORY_PIPES TRUE
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Debug options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief Debug option, kernel statistics.
+ *
+ * @note The default is @p FALSE.
+ */
+#if !defined(CH_DBG_STATISTICS)
+#define CH_DBG_STATISTICS FALSE
+#endif
+
+/**
+ * @brief Debug option, system state check.
+ * @details If enabled the correct call protocol for system APIs is checked
+ * at runtime.
+ *
+ * @note The default is @p FALSE.
+ */
+#if !defined(CH_DBG_SYSTEM_STATE_CHECK)
+#define CH_DBG_SYSTEM_STATE_CHECK FALSE
+#endif
+
+/**
+ * @brief Debug option, parameters checks.
+ * @details If enabled then the checks on the API functions input
+ * parameters are activated.
+ *
+ * @note The default is @p FALSE.
+ */
+#if !defined(CH_DBG_ENABLE_CHECKS)
+#define CH_DBG_ENABLE_CHECKS FALSE
+#endif
+
+/**
+ * @brief Debug option, consistency checks.
+ * @details If enabled then all the assertions in the kernel code are
+ * activated. This includes consistency checks inside the kernel,
+ * runtime anomalies and port-defined checks.
+ *
+ * @note The default is @p FALSE.
+ */
+#if !defined(CH_DBG_ENABLE_ASSERTS)
+#define CH_DBG_ENABLE_ASSERTS FALSE
+#endif
+
+/**
+ * @brief Debug option, trace buffer.
+ * @details If enabled then the trace buffer is activated.
+ *
+ * @note The default is @p CH_DBG_TRACE_MASK_DISABLED.
+ */
+#if !defined(CH_DBG_TRACE_MASK)
+#define CH_DBG_TRACE_MASK CH_DBG_TRACE_MASK_DISABLED
+#endif
+
+/**
+ * @brief Trace buffer entries.
+ * @note The trace buffer is only allocated if @p CH_DBG_TRACE_MASK is
+ * different from @p CH_DBG_TRACE_MASK_DISABLED.
+ */
+#if !defined(CH_DBG_TRACE_BUFFER_SIZE)
+#define CH_DBG_TRACE_BUFFER_SIZE 128
+#endif
+
+/**
+ * @brief Debug option, stack checks.
+ * @details If enabled then a runtime stack check is performed.
+ *
+ * @note The default is @p FALSE.
+ * @note The stack check is performed in a architecture/port dependent way.
+ * It may not be implemented or some ports.
+ * @note The default failure mode is to halt the system with the global
+ * @p panic_msg variable set to @p NULL.
+ */
+#if !defined(CH_DBG_ENABLE_STACK_CHECK)
+#define CH_DBG_ENABLE_STACK_CHECK TRUE
+#endif
+
+/**
+ * @brief Debug option, stacks initialization.
+ * @details If enabled then the threads working area is filled with a byte
+ * value when a thread is created. This can be useful for the
+ * runtime measurement of the used stack.
+ *
+ * @note The default is @p FALSE.
+ */
+#if !defined(CH_DBG_FILL_THREADS)
+#define CH_DBG_FILL_THREADS FALSE
+#endif
+
+/**
+ * @brief Debug option, threads profiling.
+ * @details If enabled then a field is added to the @p thread_t structure that
+ * counts the system ticks occurred while executing the thread.
+ *
+ * @note The default is @p FALSE.
+ * @note This debug option is not currently compatible with the
+ * tickless mode.
+ */
+#if !defined(CH_DBG_THREADS_PROFILING)
+#define CH_DBG_THREADS_PROFILING FALSE
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Kernel hooks
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief System structure extension.
+ * @details User fields added to the end of the @p ch_system_t structure.
+ */
+#define CH_CFG_SYSTEM_EXTRA_FIELDS \
+ /* Add threads custom fields here.*/
+
+/**
+ * @brief System initialization hook.
+ * @details User initialization code added to the @p chSysInit() function
+ * just before interrupts are enabled globally.
+ */
+#define CH_CFG_SYSTEM_INIT_HOOK() { \
+ /* Add threads initialization code here.*/ \
+}
+
+/**
+ * @brief Threads descriptor structure extension.
+ * @details User fields added to the end of the @p thread_t structure.
+ */
+#define CH_CFG_THREAD_EXTRA_FIELDS \
+ /* Add threads custom fields here.*/
+
+/**
+ * @brief Threads initialization hook.
+ * @details User initialization code added to the @p _thread_init() function.
+ *
+ * @note It is invoked from within @p _thread_init() and implicitly from all
+ * the threads creation APIs.
+ */
+#define CH_CFG_THREAD_INIT_HOOK(tp) { \
+ /* Add threads initialization code here.*/ \
+}
+
+/**
+ * @brief Threads finalization hook.
+ * @details User finalization code added to the @p chThdExit() API.
+ */
+#define CH_CFG_THREAD_EXIT_HOOK(tp) { \
+ /* Add threads finalization code here.*/ \
+}
+
+/**
+ * @brief Context switch hook.
+ * @details This hook is invoked just before switching between threads.
+ */
+#define CH_CFG_CONTEXT_SWITCH_HOOK(ntp, otp) { \
+ /* Context switch code here.*/ \
+}
+
+/**
+ * @brief ISR enter hook.
+ */
+#define CH_CFG_IRQ_PROLOGUE_HOOK() { \
+ /* IRQ prologue code here.*/ \
+}
+
+/**
+ * @brief ISR exit hook.
+ */
+#define CH_CFG_IRQ_EPILOGUE_HOOK() { \
+ /* IRQ epilogue code here.*/ \
+}
+
+/**
+ * @brief Idle thread enter hook.
+ * @note This hook is invoked within a critical zone, no OS functions
+ * should be invoked from here.
+ * @note This macro can be used to activate a power saving mode.
+ */
+#define CH_CFG_IDLE_ENTER_HOOK() { \
+ /* Idle-enter code here.*/ \
+}
+
+/**
+ * @brief Idle thread leave hook.
+ * @note This hook is invoked within a critical zone, no OS functions
+ * should be invoked from here.
+ * @note This macro can be used to deactivate a power saving mode.
+ */
+#define CH_CFG_IDLE_LEAVE_HOOK() { \
+ /* Idle-leave code here.*/ \
+}
+
+/**
+ * @brief Idle Loop hook.
+ * @details This hook is continuously invoked by the idle thread loop.
+ */
+#define CH_CFG_IDLE_LOOP_HOOK() { \
+ /* Idle loop code here.*/ \
+}
+
+/**
+ * @brief System tick event hook.
+ * @details This hook is invoked in the system tick handler immediately
+ * after processing the virtual timers queue.
+ */
+#define CH_CFG_SYSTEM_TICK_HOOK() { \
+ /* System tick event code here.*/ \
+}
+
+/**
+ * @brief System halt hook.
+ * @details This hook is invoked in case to a system halting error before
+ * the system is halted.
+ */
+#define CH_CFG_SYSTEM_HALT_HOOK(reason) { \
+ /* System halt code here.*/ \
+}
+
+/**
+ * @brief Trace hook.
+ * @details This hook is invoked each time a new record is written in the
+ * trace buffer.
+ */
+#define CH_CFG_TRACE_HOOK(tep) { \
+ /* Trace code here.*/ \
+}
+
+/** @} */
+
+/*===========================================================================*/
+/* Port-specific settings (override port settings defaulted in chcore.h). */
+/*===========================================================================*/
+
+#endif /* CHCONF_H */
+
+/** @} */
diff --git a/platforms/chibios/common/configs/halconf.h b/platforms/chibios/common/configs/halconf.h
new file mode 100644
index 0000000000..6b48e289f9
--- /dev/null
+++ b/platforms/chibios/common/configs/halconf.h
@@ -0,0 +1,525 @@
+/*
+ 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.
+*/
+
+/**
+ * @file templates/halconf.h
+ * @brief HAL configuration header.
+ * @details HAL configuration file, this file allows to enable or disable the
+ * various device drivers from your application. You may also use
+ * this file in order to override the device drivers default settings.
+ *
+ * @addtogroup HAL_CONF
+ * @{
+ */
+
+#ifndef HALCONF_H
+#define HALCONF_H
+
+#define _CHIBIOS_HAL_CONF_
+#define _CHIBIOS_HAL_CONF_VER_7_0_
+
+#include "mcuconf.h"
+
+/**
+ * @brief Enables the PAL subsystem.
+ */
+#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__)
+#define HAL_USE_PAL TRUE
+#endif
+
+/**
+ * @brief Enables the ADC subsystem.
+ */
+#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__)
+#define HAL_USE_ADC FALSE
+#endif
+
+/**
+ * @brief Enables the CAN subsystem.
+ */
+#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__)
+#define HAL_USE_CAN FALSE
+#endif
+
+/**
+ * @brief Enables the cryptographic subsystem.
+ */
+#if !defined(HAL_USE_CRY) || defined(__DOXYGEN__)
+#define HAL_USE_CRY FALSE
+#endif
+
+/**
+ * @brief Enables the DAC subsystem.
+ */
+#if !defined(HAL_USE_DAC) || defined(__DOXYGEN__)
+#define HAL_USE_DAC TRUE
+#endif
+
+/**
+ * @brief Enables the GPT subsystem.
+ */
+#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__)
+#define HAL_USE_GPT TRUE
+#endif
+
+/**
+ * @brief Enables the I2C subsystem.
+ */
+#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__)
+#define HAL_USE_I2C TRUE
+#endif
+
+/**
+ * @brief Enables the I2S subsystem.
+ */
+#if !defined(HAL_USE_I2S) || defined(__DOXYGEN__)
+#define HAL_USE_I2S FALSE
+#endif
+
+/**
+ * @brief Enables the ICU subsystem.
+ */
+#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__)
+#define HAL_USE_ICU FALSE
+#endif
+
+/**
+ * @brief Enables the MAC subsystem.
+ */
+#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__)
+#define HAL_USE_MAC FALSE
+#endif
+
+/**
+ * @brief Enables the MMC_SPI subsystem.
+ */
+#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__)
+#define HAL_USE_MMC_SPI FALSE
+#endif
+
+/**
+ * @brief Enables the PWM subsystem.
+ */
+#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__)
+#define HAL_USE_PWM TRUE
+#endif
+
+/**
+ * @brief Enables the RTC subsystem.
+ */
+#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__)
+#define HAL_USE_RTC FALSE
+#endif
+
+/**
+ * @brief Enables the SDC subsystem.
+ */
+#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__)
+#define HAL_USE_SDC FALSE
+#endif
+
+/**
+ * @brief Enables the SERIAL subsystem.
+ */
+#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__)
+#define HAL_USE_SERIAL FALSE
+#endif
+
+/**
+ * @brief Enables the SERIAL over USB subsystem.
+ */
+#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
+#define HAL_USE_SERIAL_USB TRUE
+#endif
+
+/**
+ * @brief Enables the SIO subsystem.
+ */
+#if !defined(HAL_USE_SIO) || defined(__DOXYGEN__)
+#define HAL_USE_SIO FALSE
+#endif
+
+/**
+ * @brief Enables the SPI subsystem.
+ */
+#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__)
+#define HAL_USE_SPI TRUE
+#endif
+
+/**
+ * @brief Enables the TRNG subsystem.
+ */
+#if !defined(HAL_USE_TRNG) || defined(__DOXYGEN__)
+#define HAL_USE_TRNG FALSE
+#endif
+
+/**
+ * @brief Enables the UART subsystem.
+ */
+#if !defined(HAL_USE_UART) || defined(__DOXYGEN__)
+#define HAL_USE_UART FALSE
+#endif
+
+/**
+ * @brief Enables the USB subsystem.
+ */
+#if !defined(HAL_USE_USB) || defined(__DOXYGEN__)
+#define HAL_USE_USB TRUE
+#endif
+
+/**
+ * @brief Enables the WDG subsystem.
+ */
+#if !defined(HAL_USE_WDG) || defined(__DOXYGEN__)
+#define HAL_USE_WDG FALSE
+#endif
+
+/**
+ * @brief Enables the WSPI subsystem.
+ */
+#if !defined(HAL_USE_WSPI) || defined(__DOXYGEN__)
+#define HAL_USE_WSPI FALSE
+#endif
+
+/*===========================================================================*/
+/* PAL driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(PAL_USE_CALLBACKS) || defined(__DOXYGEN__)
+#define PAL_USE_CALLBACKS TRUE
+#endif
+
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(PAL_USE_WAIT) || defined(__DOXYGEN__)
+#define PAL_USE_WAIT TRUE
+#endif
+
+/*===========================================================================*/
+/* ADC driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__)
+#define ADC_USE_WAIT TRUE
+#endif
+
+/**
+ * @brief Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define ADC_USE_MUTUAL_EXCLUSION TRUE
+#endif
+
+/*===========================================================================*/
+/* CAN driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Sleep mode related APIs inclusion switch.
+ */
+#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__)
+#define CAN_USE_SLEEP_MODE TRUE
+#endif
+
+/**
+ * @brief Enforces the driver to use direct callbacks rather than OSAL events.
+ */
+#if !defined(CAN_ENFORCE_USE_CALLBACKS) || defined(__DOXYGEN__)
+#define CAN_ENFORCE_USE_CALLBACKS FALSE
+#endif
+
+/*===========================================================================*/
+/* CRY driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables the SW fall-back of the cryptographic driver.
+ * @details When enabled, this option, activates a fall-back software
+ * implementation for algorithms not supported by the underlying
+ * hardware.
+ * @note Fall-back implementations may not be present for all algorithms.
+ */
+#if !defined(HAL_CRY_USE_FALLBACK) || defined(__DOXYGEN__)
+#define HAL_CRY_USE_FALLBACK FALSE
+#endif
+
+/**
+ * @brief Makes the driver forcibly use the fall-back implementations.
+ */
+#if !defined(HAL_CRY_ENFORCE_FALLBACK) || defined(__DOXYGEN__)
+#define HAL_CRY_ENFORCE_FALLBACK FALSE
+#endif
+
+/*===========================================================================*/
+/* DAC driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(DAC_USE_WAIT) || defined(__DOXYGEN__)
+#define DAC_USE_WAIT TRUE
+#endif
+
+/**
+ * @brief Enables the @p dacAcquireBus() and @p dacReleaseBus() APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(DAC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define DAC_USE_MUTUAL_EXCLUSION TRUE
+#endif
+
+/*===========================================================================*/
+/* I2C driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables the mutual exclusion APIs on the I2C bus.
+ */
+#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define I2C_USE_MUTUAL_EXCLUSION TRUE
+#endif
+
+/*===========================================================================*/
+/* MAC driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables the zero-copy API.
+ */
+#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__)
+#define MAC_USE_ZERO_COPY FALSE
+#endif
+
+/**
+ * @brief Enables an event sources for incoming packets.
+ */
+#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__)
+#define MAC_USE_EVENTS TRUE
+#endif
+
+/*===========================================================================*/
+/* MMC_SPI driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Delays insertions.
+ * @details If enabled this options inserts delays into the MMC waiting
+ * routines releasing some extra CPU time for the threads with
+ * lower priority, this may slow down the driver a bit however.
+ * This option is recommended also if the SPI driver does not
+ * use a DMA channel and heavily loads the CPU.
+ */
+#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__)
+#define MMC_NICE_WAITING TRUE
+#endif
+
+/*===========================================================================*/
+/* SDC driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Number of initialization attempts before rejecting the card.
+ * @note Attempts are performed at 10mS intervals.
+ */
+#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__)
+#define SDC_INIT_RETRY 100
+#endif
+
+/**
+ * @brief Include support for MMC cards.
+ * @note MMC support is not yet implemented so this option must be kept
+ * at @p FALSE.
+ */
+#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__)
+#define SDC_MMC_SUPPORT FALSE
+#endif
+
+/**
+ * @brief Delays insertions.
+ * @details If enabled this options inserts delays into the MMC waiting
+ * routines releasing some extra CPU time for the threads with
+ * lower priority, this may slow down the driver a bit however.
+ */
+#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__)
+#define SDC_NICE_WAITING TRUE
+#endif
+
+/**
+ * @brief OCR initialization constant for V20 cards.
+ */
+#if !defined(SDC_INIT_OCR_V20) || defined(__DOXYGEN__)
+#define SDC_INIT_OCR_V20 0x50FF8000U
+#endif
+
+/**
+ * @brief OCR initialization constant for non-V20 cards.
+ */
+#if !defined(SDC_INIT_OCR) || defined(__DOXYGEN__)
+#define SDC_INIT_OCR 0x80100000U
+#endif
+
+/*===========================================================================*/
+/* SERIAL driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Default bit rate.
+ * @details Configuration parameter, this is the baud rate selected for the
+ * default configuration.
+ */
+#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__)
+#define SERIAL_DEFAULT_BITRATE 38400
+#endif
+
+/**
+ * @brief Serial buffers size.
+ * @details Configuration parameter, you can change the depth of the queue
+ * buffers depending on the requirements of your application.
+ * @note The default is 16 bytes for both the transmission and receive
+ * buffers.
+ */
+#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
+#define SERIAL_BUFFERS_SIZE 16
+#endif
+
+/*===========================================================================*/
+/* SERIAL_USB driver related setting. */
+/*===========================================================================*/
+
+/**
+ * @brief Serial over USB buffers size.
+ * @details Configuration parameter, the buffer size must be a multiple of
+ * the USB data endpoint maximum packet size.
+ * @note The default is 256 bytes for both the transmission and receive
+ * buffers.
+ */
+#if !defined(SERIAL_USB_BUFFERS_SIZE) || defined(__DOXYGEN__)
+#define SERIAL_USB_BUFFERS_SIZE 1
+#endif
+
+/**
+ * @brief Serial over USB number of buffers.
+ * @note The default is 2 buffers.
+ */
+#if !defined(SERIAL_USB_BUFFERS_NUMBER) || defined(__DOXYGEN__)
+#define SERIAL_USB_BUFFERS_NUMBER 2
+#endif
+
+/*===========================================================================*/
+/* SPI driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
+#define SPI_USE_WAIT TRUE
+#endif
+
+/**
+ * @brief Enables circular transfers APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(SPI_USE_CIRCULAR) || defined(__DOXYGEN__)
+#define SPI_USE_CIRCULAR FALSE
+#endif
+
+
+/**
+ * @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define SPI_USE_MUTUAL_EXCLUSION TRUE
+#endif
+
+/**
+ * @brief Handling method for SPI CS line.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(SPI_SELECT_MODE) || defined(__DOXYGEN__)
+#define SPI_SELECT_MODE SPI_SELECT_MODE_PAD
+#endif
+
+/*===========================================================================*/
+/* UART driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(UART_USE_WAIT) || defined(__DOXYGEN__)
+#define UART_USE_WAIT FALSE
+#endif
+
+/**
+ * @brief Enables the @p uartAcquireBus() and @p uartReleaseBus() APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(UART_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define UART_USE_MUTUAL_EXCLUSION FALSE
+#endif
+
+/*===========================================================================*/
+/* USB driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(USB_USE_WAIT) || defined(__DOXYGEN__)
+#define USB_USE_WAIT TRUE
+#endif
+
+/*===========================================================================*/
+/* WSPI driver related settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Enables synchronous APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(WSPI_USE_WAIT) || defined(__DOXYGEN__)
+#define WSPI_USE_WAIT TRUE
+#endif
+
+/**
+ * @brief Enables the @p wspiAcquireBus() and @p wspiReleaseBus() APIs.
+ * @note Disabling this option saves both code and data space.
+ */
+#if !defined(WSPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define WSPI_USE_MUTUAL_EXCLUSION TRUE
+#endif
+
+#endif /* HALCONF_H */
+
+/** @} */
diff --git a/platforms/chibios/common/ld/MKL26Z64.ld b/platforms/chibios/common/ld/MKL26Z64.ld
new file mode 100644
index 0000000000..c4ca8b874c
--- /dev/null
+++ b/platforms/chibios/common/ld/MKL26Z64.ld
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2013-2016 Fabio Utzig, http://fabioutzig.com
+ * (C) 2016 flabbergast
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * KL26Z64 memory setup.
+ */
+MEMORY
+{
+ flash0 : org = 0x00000000, len = 0x100
+ flash1 : org = 0x00000400, len = 0x10
+ flash2 : org = 0x00000410, len = 62k - 0x410
+ flash3 : org = 0x0000F800, len = 2k
+ flash4 : org = 0x00000000, len = 0
+ flash5 : org = 0x00000000, len = 0
+ flash6 : org = 0x00000000, len = 0
+ flash7 : org = 0x00000000, len = 0
+ ram0 : org = 0x1FFFF800, len = 8k
+ ram1 : org = 0x00000000, len = 0
+ ram2 : org = 0x00000000, len = 0
+ ram3 : org = 0x00000000, len = 0
+ ram4 : org = 0x00000000, len = 0
+ ram5 : org = 0x00000000, len = 0
+ ram6 : org = 0x00000000, len = 0
+ ram7 : org = 0x00000000, len = 0
+}
+
+/* Flash region for the configuration bytes.*/
+SECTIONS
+{
+ .cfmprotect : ALIGN(4) SUBALIGN(4)
+ {
+ KEEP(*(.cfmconfig))
+ } > flash1
+}
+
+/* For each data/text section two region are defined, a virtual region
+ and a load region (_LMA suffix).*/
+
+/* Flash region to be used for exception vectors.*/
+REGION_ALIAS("VECTORS_FLASH", flash0);
+REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
+
+/* Flash region to be used for constructors and destructors.*/
+REGION_ALIAS("XTORS_FLASH", flash2);
+REGION_ALIAS("XTORS_FLASH_LMA", flash2);
+
+/* Flash region to be used for code text.*/
+REGION_ALIAS("TEXT_FLASH", flash2);
+REGION_ALIAS("TEXT_FLASH_LMA", flash2);
+
+/* Flash region to be used for read only data.*/
+REGION_ALIAS("RODATA_FLASH", flash2);
+REGION_ALIAS("RODATA_FLASH_LMA", flash2);
+
+/* Flash region to be used for various.*/
+REGION_ALIAS("VARIOUS_FLASH", flash2);
+REGION_ALIAS("VARIOUS_FLASH_LMA", flash2);
+
+/* Flash region to be used for RAM(n) initialization data.*/
+REGION_ALIAS("RAM_INIT_FLASH_LMA", flash2);
+
+/* RAM region to be used for Main stack. This stack accommodates the processing
+ of all exceptions and interrupts.*/
+REGION_ALIAS("MAIN_STACK_RAM", ram0);
+
+/* RAM region to be used for the process stack. This is the stack used by
+ the main() function.*/
+REGION_ALIAS("PROCESS_STACK_RAM", ram0);
+
+/* RAM region to be used for data segment.*/
+REGION_ALIAS("DATA_RAM", ram0);
+REGION_ALIAS("DATA_RAM_LMA", flash2);
+
+/* RAM region to be used for BSS segment.*/
+REGION_ALIAS("BSS_RAM", ram0);
+
+/* RAM region to be used for the default heap.*/
+REGION_ALIAS("HEAP_RAM", ram0);
+
+__eeprom_workarea_start__ = ORIGIN(flash3);
+__eeprom_workarea_size__ = LENGTH(flash3);
+__eeprom_workarea_end__ = __eeprom_workarea_start__ + __eeprom_workarea_size__;
+
+/* Generic rules inclusion.*/
+INCLUDE rules.ld
diff --git a/platforms/chibios/common/ld/STM32F103x8_stm32duino_bootloader.ld b/platforms/chibios/common/ld/STM32F103x8_stm32duino_bootloader.ld
new file mode 100644
index 0000000000..bb852422a3
--- /dev/null
+++ b/platforms/chibios/common/ld/STM32F103x8_stm32duino_bootloader.ld
@@ -0,0 +1,85 @@
+/*
+ ChibiOS - Copyright (C) 2006..2016 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.
+*/
+
+/*
+ * ST32F103xB memory setup for use with the maplemini bootloader.
+ */
+MEMORY
+{
+ flash0 : org = 0x08002000, len = 64k - 0x2000
+ flash1 : org = 0x00000000, len = 0
+ flash2 : org = 0x00000000, len = 0
+ flash3 : org = 0x00000000, len = 0
+ flash4 : org = 0x00000000, len = 0
+ flash5 : org = 0x00000000, len = 0
+ flash6 : org = 0x00000000, len = 0
+ flash7 : org = 0x00000000, len = 0
+ ram0 : org = 0x20000000, len = 20k
+ ram1 : org = 0x00000000, len = 0
+ ram2 : org = 0x00000000, len = 0
+ ram3 : org = 0x00000000, len = 0
+ ram4 : org = 0x00000000, len = 0
+ ram5 : org = 0x00000000, len = 0
+ ram6 : org = 0x00000000, len = 0
+ ram7 : org = 0x00000000, len = 0
+}
+
+/* For each data/text section two region are defined, a virtual region
+ and a load region (_LMA suffix).*/
+
+/* Flash region to be used for exception vectors.*/
+REGION_ALIAS("VECTORS_FLASH", flash0);
+REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
+
+/* Flash region to be used for constructors and destructors.*/
+REGION_ALIAS("XTORS_FLASH", flash0);
+REGION_ALIAS("XTORS_FLASH_LMA", flash0);
+
+/* Flash region to be used for code text.*/
+REGION_ALIAS("TEXT_FLASH", flash0);
+REGION_ALIAS("TEXT_FLASH_LMA", flash0);
+
+/* Flash region to be used for read only data.*/
+REGION_ALIAS("RODATA_FLASH", flash0);
+REGION_ALIAS("RODATA_FLASH_LMA", flash0);
+
+/* Flash region to be used for various.*/
+REGION_ALIAS("VARIOUS_FLASH", flash0);
+REGION_ALIAS("VARIOUS_FLASH_LMA", flash0);
+
+/* Flash region to be used for RAM(n) initialization data.*/
+REGION_ALIAS("RAM_INIT_FLASH_LMA", flash0);
+
+/* RAM region to be used for Main stack. This stack accommodates the processing
+ of all exceptions and interrupts.*/
+REGION_ALIAS("MAIN_STACK_RAM", ram0);
+
+/* RAM region to be used for the process stack. This is the stack used by
+ the main() function.*/
+REGION_ALIAS("PROCESS_STACK_RAM", ram0);
+
+/* RAM region to be used for data segment.*/
+REGION_ALIAS("DATA_RAM", ram0);
+REGION_ALIAS("DATA_RAM_LMA", flash0);
+
+/* RAM region to be used for BSS segment.*/
+REGION_ALIAS("BSS_RAM", ram0);
+
+/* RAM region to be used for the default heap.*/
+REGION_ALIAS("HEAP_RAM", ram0);
+
+/* Generic rules inclusion.*/
+INCLUDE rules.ld
diff --git a/platforms/chibios/ld/MKL26Z64.ld b/platforms/chibios/ld/MKL26Z64.ld
deleted file mode 100644
index c4ca8b874c..0000000000
--- a/platforms/chibios/ld/MKL26Z64.ld
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2013-2016 Fabio Utzig, http://fabioutzig.com
- * (C) 2016 flabbergast
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- * KL26Z64 memory setup.
- */
-MEMORY
-{
- flash0 : org = 0x00000000, len = 0x100
- flash1 : org = 0x00000400, len = 0x10
- flash2 : org = 0x00000410, len = 62k - 0x410
- flash3 : org = 0x0000F800, len = 2k
- flash4 : org = 0x00000000, len = 0
- flash5 : org = 0x00000000, len = 0
- flash6 : org = 0x00000000, len = 0
- flash7 : org = 0x00000000, len = 0
- ram0 : org = 0x1FFFF800, len = 8k
- ram1 : org = 0x00000000, len = 0
- ram2 : org = 0x00000000, len = 0
- ram3 : org = 0x00000000, len = 0
- ram4 : org = 0x00000000, len = 0
- ram5 : org = 0x00000000, len = 0
- ram6 : org = 0x00000000, len = 0
- ram7 : org = 0x00000000, len = 0
-}
-
-/* Flash region for the configuration bytes.*/
-SECTIONS
-{
- .cfmprotect : ALIGN(4) SUBALIGN(4)
- {
- KEEP(*(.cfmconfig))
- } > flash1
-}
-
-/* For each data/text section two region are defined, a virtual region
- and a load region (_LMA suffix).*/
-
-/* Flash region to be used for exception vectors.*/
-REGION_ALIAS("VECTORS_FLASH", flash0);
-REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
-
-/* Flash region to be used for constructors and destructors.*/
-REGION_ALIAS("XTORS_FLASH", flash2);
-REGION_ALIAS("XTORS_FLASH_LMA", flash2);
-
-/* Flash region to be used for code text.*/
-REGION_ALIAS("TEXT_FLASH", flash2);
-REGION_ALIAS("TEXT_FLASH_LMA", flash2);
-
-/* Flash region to be used for read only data.*/
-REGION_ALIAS("RODATA_FLASH", flash2);
-REGION_ALIAS("RODATA_FLASH_LMA", flash2);
-
-/* Flash region to be used for various.*/
-REGION_ALIAS("VARIOUS_FLASH", flash2);
-REGION_ALIAS("VARIOUS_FLASH_LMA", flash2);
-
-/* Flash region to be used for RAM(n) initialization data.*/
-REGION_ALIAS("RAM_INIT_FLASH_LMA", flash2);
-
-/* RAM region to be used for Main stack. This stack accommodates the processing
- of all exceptions and interrupts.*/
-REGION_ALIAS("MAIN_STACK_RAM", ram0);
-
-/* RAM region to be used for the process stack. This is the stack used by
- the main() function.*/
-REGION_ALIAS("PROCESS_STACK_RAM", ram0);
-
-/* RAM region to be used for data segment.*/
-REGION_ALIAS("DATA_RAM", ram0);
-REGION_ALIAS("DATA_RAM_LMA", flash2);
-
-/* RAM region to be used for BSS segment.*/
-REGION_ALIAS("BSS_RAM", ram0);
-
-/* RAM region to be used for the default heap.*/
-REGION_ALIAS("HEAP_RAM", ram0);
-
-__eeprom_workarea_start__ = ORIGIN(flash3);
-__eeprom_workarea_size__ = LENGTH(flash3);
-__eeprom_workarea_end__ = __eeprom_workarea_start__ + __eeprom_workarea_size__;
-
-/* Generic rules inclusion.*/
-INCLUDE rules.ld
diff --git a/platforms/chibios/ld/STM32F103x8_stm32duino_bootloader.ld b/platforms/chibios/ld/STM32F103x8_stm32duino_bootloader.ld
deleted file mode 100644
index bb852422a3..0000000000
--- a/platforms/chibios/ld/STM32F103x8_stm32duino_bootloader.ld
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- ChibiOS - Copyright (C) 2006..2016 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.
-*/
-
-/*
- * ST32F103xB memory setup for use with the maplemini bootloader.
- */
-MEMORY
-{
- flash0 : org = 0x08002000, len = 64k - 0x2000
- flash1 : org = 0x00000000, len = 0
- flash2 : org = 0x00000000, len = 0
- flash3 : org = 0x00000000, len = 0
- flash4 : org = 0x00000000, len = 0
- flash5 : org = 0x00000000, len = 0
- flash6 : org = 0x00000000, len = 0
- flash7 : org = 0x00000000, len = 0
- ram0 : org = 0x20000000, len = 20k
- ram1 : org = 0x00000000, len = 0
- ram2 : org = 0x00000000, len = 0
- ram3 : org = 0x00000000, len = 0
- ram4 : org = 0x00000000, len = 0
- ram5 : org = 0x00000000, len = 0
- ram6 : org = 0x00000000, len = 0
- ram7 : org = 0x00000000, len = 0
-}
-
-/* For each data/text section two region are defined, a virtual region
- and a load region (_LMA suffix).*/
-
-/* Flash region to be used for exception vectors.*/
-REGION_ALIAS("VECTORS_FLASH", flash0);
-REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
-
-/* Flash region to be used for constructors and destructors.*/
-REGION_ALIAS("XTORS_FLASH", flash0);
-REGION_ALIAS("XTORS_FLASH_LMA", flash0);
-
-/* Flash region to be used for code text.*/
-REGION_ALIAS("TEXT_FLASH", flash0);
-REGION_ALIAS("TEXT_FLASH_LMA", flash0);
-
-/* Flash region to be used for read only data.*/
-REGION_ALIAS("RODATA_FLASH", flash0);
-REGION_ALIAS("RODATA_FLASH_LMA", flash0);
-
-/* Flash region to be used for various.*/
-REGION_ALIAS("VARIOUS_FLASH", flash0);
-REGION_ALIAS("VARIOUS_FLASH_LMA", flash0);
-
-/* Flash region to be used for RAM(n) initialization data.*/
-REGION_ALIAS("RAM_INIT_FLASH_LMA", flash0);
-
-/* RAM region to be used for Main stack. This stack accommodates the processing
- of all exceptions and interrupts.*/
-REGION_ALIAS("MAIN_STACK_RAM", ram0);
-
-/* RAM region to be used for the process stack. This is the stack used by
- the main() function.*/
-REGION_ALIAS("PROCESS_STACK_RAM", ram0);
-
-/* RAM region to be used for data segment.*/
-REGION_ALIAS("DATA_RAM", ram0);
-REGION_ALIAS("DATA_RAM_LMA", flash0);
-
-/* RAM region to be used for BSS segment.*/
-REGION_ALIAS("BSS_RAM", ram0);
-
-/* RAM region to be used for the default heap.*/
-REGION_ALIAS("HEAP_RAM", ram0);
-
-/* Generic rules inclusion.*/
-INCLUDE rules.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
#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
-#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
+
#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
+#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
#include
#include "quantum.h"
-#include "ledmatrix.h"
+#include "led_matrix.h"
#include "progmem.h"
#include "config.h"
#include "eeprom.h"
diff --git a/quantum/led_matrix.h b/quantum/led_matrix.h
new file mode 100644
index 0000000000..5867ba9876
--- /dev/null
+++ b/quantum/led_matrix.h
@@ -0,0 +1,127 @@
+/* Copyright 2017 Jason Williams
+ * Copyright 2017 Jack Humbert
+ * Copyright 2018 Yiancar
+ * Copyright 2019 Clueboard
+ *
+ * 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 .
+ */
+
+#ifndef LED_MATRIX_H
+#define LED_MATRIX_H
+
+#ifndef BACKLIGHT_ENABLE
+# error You must define BACKLIGHT_ENABLE with LED_MATRIX_ENABLE
+#endif
+
+typedef struct Point {
+ uint8_t x;
+ uint8_t y;
+} __attribute__((packed)) Point;
+
+typedef struct led_matrix {
+ union {
+ uint8_t raw;
+ struct {
+ uint8_t row : 4; // 16 max
+ uint8_t col : 4; // 16 max
+ };
+ } matrix_co;
+ Point point;
+ uint8_t modifier : 1;
+} __attribute__((packed)) led_matrix;
+
+extern const led_matrix g_leds[LED_DRIVER_LED_COUNT];
+
+typedef struct {
+ uint8_t index;
+ uint8_t value;
+} led_indicator;
+
+typedef union {
+ uint32_t raw;
+ struct {
+ bool enable : 1;
+ uint8_t mode : 6;
+ uint8_t hue : 8; // Unused by led_matrix
+ uint8_t sat : 8; // Unused by led_matrix
+ uint8_t val : 8;
+ uint8_t speed : 8; // EECONFIG needs to be increased to support this
+ };
+} led_config_t;
+
+enum led_matrix_effects {
+ LED_MATRIX_UNIFORM_BRIGHTNESS = 1,
+ // All new effects go above this line
+ LED_MATRIX_EFFECT_MAX
+};
+
+void led_matrix_set_index_value(int index, uint8_t value);
+void led_matrix_set_index_value_all(uint8_t value);
+
+// This runs after another backlight effect and replaces
+// colors already set
+void led_matrix_indicators(void);
+void led_matrix_indicators_kb(void);
+void led_matrix_indicators_user(void);
+
+void led_matrix_init(void);
+void led_matrix_setup_drivers(void);
+
+void led_matrix_set_suspend_state(bool state);
+void led_matrix_set_indicator_state(uint8_t state);
+
+void led_matrix_task(void);
+
+// This should not be called from an interrupt
+// (eg. from a timer interrupt).
+// Call this while idle (in between matrix scans).
+// If the buffer is dirty, it will update the driver with the buffer.
+void led_matrix_update_pwm_buffers(void);
+
+bool process_led_matrix(uint16_t keycode, keyrecord_t *record);
+
+uint32_t led_matrix_get_tick(void);
+
+void led_matrix_toggle(void);
+void led_matrix_enable(void);
+void led_matrix_enable_noeeprom(void);
+void led_matrix_disable(void);
+void led_matrix_disable_noeeprom(void);
+void led_matrix_step(void);
+void led_matrix_step_reverse(void);
+void led_matrix_increase_val(void);
+void led_matrix_decrease_val(void);
+void led_matrix_increase_speed(void);
+void led_matrix_decrease_speed(void);
+void led_matrix_mode(uint8_t mode, bool eeprom_write);
+void led_matrix_mode_noeeprom(uint8_t mode);
+uint8_t led_matrix_get_mode(void);
+void led_matrix_set_value(uint8_t mode);
+void led_matrix_set_value_noeeprom(uint8_t mode);
+
+typedef struct {
+ /* Perform any initialisation required for the other driver functions to work. */
+ void (*init)(void);
+
+ /* Set the brightness of a single LED in the buffer. */
+ void (*set_value)(int index, uint8_t value);
+ /* Set the brightness of all LEDS on the keyboard in the buffer. */
+ void (*set_value_all)(uint8_t value);
+ /* Flush any buffered changes to the hardware. */
+ void (*flush)(void);
+} led_matrix_driver_t;
+
+extern const led_matrix_driver_t led_matrix_driver;
+
+#endif
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
#include
#include "quantum.h"
-#include "ledmatrix.h"
+#include "led_matrix.h"
/* Each driver needs to define a struct:
*
diff --git a/quantum/ledmatrix.h b/quantum/ledmatrix.h
deleted file mode 100644
index 5867ba9876..0000000000
--- a/quantum/ledmatrix.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/* Copyright 2017 Jason Williams
- * Copyright 2017 Jack Humbert
- * Copyright 2018 Yiancar
- * Copyright 2019 Clueboard
- *
- * 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 .
- */
-
-#ifndef LED_MATRIX_H
-#define LED_MATRIX_H
-
-#ifndef BACKLIGHT_ENABLE
-# error You must define BACKLIGHT_ENABLE with LED_MATRIX_ENABLE
-#endif
-
-typedef struct Point {
- uint8_t x;
- uint8_t y;
-} __attribute__((packed)) Point;
-
-typedef struct led_matrix {
- union {
- uint8_t raw;
- struct {
- uint8_t row : 4; // 16 max
- uint8_t col : 4; // 16 max
- };
- } matrix_co;
- Point point;
- uint8_t modifier : 1;
-} __attribute__((packed)) led_matrix;
-
-extern const led_matrix g_leds[LED_DRIVER_LED_COUNT];
-
-typedef struct {
- uint8_t index;
- uint8_t value;
-} led_indicator;
-
-typedef union {
- uint32_t raw;
- struct {
- bool enable : 1;
- uint8_t mode : 6;
- uint8_t hue : 8; // Unused by led_matrix
- uint8_t sat : 8; // Unused by led_matrix
- uint8_t val : 8;
- uint8_t speed : 8; // EECONFIG needs to be increased to support this
- };
-} led_config_t;
-
-enum led_matrix_effects {
- LED_MATRIX_UNIFORM_BRIGHTNESS = 1,
- // All new effects go above this line
- LED_MATRIX_EFFECT_MAX
-};
-
-void led_matrix_set_index_value(int index, uint8_t value);
-void led_matrix_set_index_value_all(uint8_t value);
-
-// This runs after another backlight effect and replaces
-// colors already set
-void led_matrix_indicators(void);
-void led_matrix_indicators_kb(void);
-void led_matrix_indicators_user(void);
-
-void led_matrix_init(void);
-void led_matrix_setup_drivers(void);
-
-void led_matrix_set_suspend_state(bool state);
-void led_matrix_set_indicator_state(uint8_t state);
-
-void led_matrix_task(void);
-
-// This should not be called from an interrupt
-// (eg. from a timer interrupt).
-// Call this while idle (in between matrix scans).
-// If the buffer is dirty, it will update the driver with the buffer.
-void led_matrix_update_pwm_buffers(void);
-
-bool process_led_matrix(uint16_t keycode, keyrecord_t *record);
-
-uint32_t led_matrix_get_tick(void);
-
-void led_matrix_toggle(void);
-void led_matrix_enable(void);
-void led_matrix_enable_noeeprom(void);
-void led_matrix_disable(void);
-void led_matrix_disable_noeeprom(void);
-void led_matrix_step(void);
-void led_matrix_step_reverse(void);
-void led_matrix_increase_val(void);
-void led_matrix_decrease_val(void);
-void led_matrix_increase_speed(void);
-void led_matrix_decrease_speed(void);
-void led_matrix_mode(uint8_t mode, bool eeprom_write);
-void led_matrix_mode_noeeprom(uint8_t mode);
-uint8_t led_matrix_get_mode(void);
-void led_matrix_set_value(uint8_t mode);
-void led_matrix_set_value_noeeprom(uint8_t mode);
-
-typedef struct {
- /* Perform any initialisation required for the other driver functions to work. */
- void (*init)(void);
-
- /* Set the brightness of a single LED in the buffer. */
- void (*set_value)(int index, uint8_t value);
- /* Set the brightness of all LEDS on the keyboard in the buffer. */
- void (*set_value_all)(uint8_t value);
- /* Flush any buffered changes to the hardware. */
- void (*flush)(void);
-} led_matrix_driver_t;
-
-extern const led_matrix_driver_t led_matrix_driver;
-
-#endif
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
# include
# 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 .
+ */
+
+#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 .
+ */
+
+#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
+
+# 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 .
+ */
+
+#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 .
+ */
+
+#pragma once
+
+#include
+#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 .
+ */
+
+#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 .
+ */
+
+#pragma once
+
+#include
+
+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 .
+ */
+
+#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 .
# 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 .
# 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/led_matrix.c b/tmk_core/protocol/arm_atsam/led_matrix.c
deleted file mode 100644
index 4b8cc7c5e1..0000000000
--- a/tmk_core/protocol/arm_atsam/led_matrix.c
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
-Copyright 2018 Massdrop Inc.
-
-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 .
-*/
-
-#include "arm_atsam_protocol.h"
-#include "tmk_core/common/led.h"
-#include "rgb_matrix.h"
-#include
-#include
-
-#ifdef USE_MASSDROP_CONFIGURATOR
-__attribute__((weak)) led_instruction_t led_instructions[] = {{.end = 1}};
-static void led_matrix_massdrop_config_override(int i);
-#endif // USE_MASSDROP_CONFIGURATOR
-
-void SERCOM1_0_Handler(void) {
- if (SERCOM1->I2CM.INTFLAG.bit.ERROR) {
- SERCOM1->I2CM.INTFLAG.reg = SERCOM_I2CM_INTENCLR_ERROR;
- }
-}
-
-void DMAC_0_Handler(void) {
- if (DMAC->Channel[0].CHINTFLAG.bit.TCMPL) {
- DMAC->Channel[0].CHINTFLAG.reg = DMAC_CHINTENCLR_TCMPL;
-
- i2c1_stop();
-
- i2c_led_q_running = 0;
-
- i2c_led_q_run();
-
- return;
- }
-
- if (DMAC->Channel[0].CHINTFLAG.bit.TERR) {
- DMAC->Channel[0].CHINTFLAG.reg = DMAC_CHINTENCLR_TERR;
- }
-}
-
-issi3733_driver_t issidrv[ISSI3733_DRIVER_COUNT];
-
-issi3733_led_t led_map[ISSI3733_LED_COUNT] = ISSI3733_LED_MAP;
-RGB led_buffer[ISSI3733_LED_COUNT];
-
-uint8_t gcr_desired;
-uint8_t gcr_actual;
-uint8_t gcr_actual_last;
-#ifdef USE_MASSDROP_CONFIGURATOR
-uint8_t gcr_breathe;
-float breathe_mult;
-float pomod;
-#endif
-
-#define ACT_GCR_NONE 0
-#define ACT_GCR_INC 1
-#define ACT_GCR_DEC 2
-
-#define LED_GCR_STEP_AUTO 2
-
-static uint8_t gcr_min_counter;
-static uint8_t v_5v_cat_hit;
-
-// WARNING: Automatic GCR is in place to prevent USB shutdown and LED driver overloading
-void gcr_compute(void) {
- uint8_t action = ACT_GCR_NONE;
- uint8_t gcr_use = gcr_desired;
-
-#ifdef USE_MASSDROP_CONFIGURATOR
- if (led_animation_breathing) {
- gcr_use = gcr_breathe;
- }
-#endif
-
- // If the 5v takes a catastrophic hit, disable the LED drivers briefly, assert auto gcr mode, min gcr and let the auto take over
- if (v_5v < V5_CAT) {
- I2C3733_Control_Set(0);
- // CDC_print("USB: WARNING: 5V catastrophic level reached! Disabling LED drivers!\r\n"); //Blocking print is bad here!
- v_5v_cat_hit = 20; //~100ms recover
- gcr_actual = 0; // Minimize GCR
- usb_gcr_auto = 1; // Force auto mode enabled
- return;
- } else if (v_5v_cat_hit > 1) {
- v_5v_cat_hit--;
- return;
- } else if (v_5v_cat_hit == 1) {
- I2C3733_Control_Set(1);
- CDC_print("USB: WARNING: Re-enabling LED drivers\r\n");
- v_5v_cat_hit = 0;
- return;
- }
-
- if (usb_gcr_auto) {
- if (v_5v_avg < V5_LOW)
- action = ACT_GCR_DEC;
- else if (v_5v_avg > V5_HIGH && gcr_actual < gcr_use)
- action = ACT_GCR_INC;
- else if (gcr_actual > gcr_use)
- action = ACT_GCR_DEC;
- } else {
- if (gcr_actual < gcr_use)
- action = ACT_GCR_INC;
- else if (gcr_actual > gcr_use)
- action = ACT_GCR_DEC;
- }
-
- if (action == ACT_GCR_NONE) {
- gcr_min_counter = 0;
- } else if (action == ACT_GCR_INC) {
- if (LED_GCR_STEP_AUTO > LED_GCR_MAX - gcr_actual)
- gcr_actual = LED_GCR_MAX; // Obey max and prevent wrapping
- else
- gcr_actual += LED_GCR_STEP_AUTO;
- gcr_min_counter = 0;
- } else if (action == ACT_GCR_DEC) {
- if (LED_GCR_STEP_AUTO > gcr_actual) // Prevent wrapping
- {
- gcr_actual = 0;
- // At this point, power can no longer be cut from the LED drivers, so focus on cutting out extra port if active
- if (usb_extra_state != USB_EXTRA_STATE_DISABLED_UNTIL_REPLUG) // If not in a wait for replug state
- {
- if (usb_extra_state == USB_EXTRA_STATE_ENABLED) // If extra usb is enabled
- {
- gcr_min_counter++;
- if (gcr_min_counter > 200) // 5ms per check = 1s delay
- {
- USB_ExtraSetState(USB_EXTRA_STATE_DISABLED_UNTIL_REPLUG);
- usb_extra_manual = 0; // Force disable manual mode of extra port
- if (usb_extra_manual)
- CDC_print("USB: Disabling extra port until replug and manual mode toggle!\r\n");
- else
- CDC_print("USB: Disabling extra port until replug!\r\n");
- }
- }
- }
- } else {
- // Power successfully cut back from LED drivers
- gcr_actual -= LED_GCR_STEP_AUTO;
- gcr_min_counter = 0;
-
-#ifdef USE_MASSDROP_CONFIGURATOR
- // If breathe mode is active, the top end can fluctuate if the host can not supply enough current
- // So set the breathe GCR to where it becomes stable
- if (led_animation_breathing == 1) {
- gcr_breathe = gcr_actual;
- // PS: At this point, setting breathing to exhale makes a noticebly shorter cycle
- // and the same would happen maybe one or two more times. Therefore I'm favoring
- // powering through one full breathe and letting gcr settle completely
- }
-#endif
- }
- }
-}
-
-void issi3733_prepare_arrays(void) {
- memset(issidrv, 0, sizeof(issi3733_driver_t) * ISSI3733_DRIVER_COUNT);
-
- int i;
- uint8_t addrs[ISSI3733_DRIVER_COUNT] = ISSI3773_DRIVER_ADDRESSES;
-
- for (i = 0; i < ISSI3733_DRIVER_COUNT; i++) {
- issidrv[i].addr = addrs[i];
- }
-
- for (uint8_t i = 0; i < ISSI3733_LED_COUNT; i++) {
- // BYTE: 1 + (SW-1)*16 + (CS-1)
- led_map[i].rgb.g = issidrv[led_map[i].adr.drv - 1].pwm + 1 + ((led_map[i].adr.swg - 1) * 16 + (led_map[i].adr.cs - 1));
- led_map[i].rgb.r = issidrv[led_map[i].adr.drv - 1].pwm + 1 + ((led_map[i].adr.swr - 1) * 16 + (led_map[i].adr.cs - 1));
- led_map[i].rgb.b = issidrv[led_map[i].adr.drv - 1].pwm + 1 + ((led_map[i].adr.swb - 1) * 16 + (led_map[i].adr.cs - 1));
-
- // BYTE: 1 + (SW-1)*2 + (CS-1)/8
- // BIT: (CS-1)%8
- *(issidrv[led_map[i].adr.drv - 1].onoff + 1 + (led_map[i].adr.swg - 1) * 2 + (led_map[i].adr.cs - 1) / 8) |= (1 << ((led_map[i].adr.cs - 1) % 8));
- *(issidrv[led_map[i].adr.drv - 1].onoff + 1 + (led_map[i].adr.swr - 1) * 2 + (led_map[i].adr.cs - 1) / 8) |= (1 << ((led_map[i].adr.cs - 1) % 8));
- *(issidrv[led_map[i].adr.drv - 1].onoff + 1 + (led_map[i].adr.swb - 1) * 2 + (led_map[i].adr.cs - 1) / 8) |= (1 << ((led_map[i].adr.cs - 1) % 8));
- }
-}
-
-void led_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;
- *led_map[i].rgb.b = 0;
- }
-}
-
-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);
-#else
- led_buffer[i].r = r;
- led_buffer[i].g = g;
- led_buffer[i].b = b;
-#endif
- }
-}
-
-void led_set_all(uint8_t r, uint8_t g, uint8_t b) {
- for (uint8_t i = 0; i < ISSI3733_LED_COUNT; i++) {
- led_set_one(i, r, g, b);
- }
-}
-
-void init(void) {
- DBGC(DC_LED_MATRIX_INIT_BEGIN);
-
- issi3733_prepare_arrays();
-
- led_matrix_prepare();
-
- gcr_min_counter = 0;
- v_5v_cat_hit = 0;
-
- DBGC(DC_LED_MATRIX_INIT_COMPLETE);
-}
-
-void flush(void) {
-#ifdef USE_MASSDROP_CONFIGURATOR
- if (!led_enabled) {
- return;
- } // Prevent calculations and I2C traffic if LED drivers are not enabled
-#else
- if (!sr_exp_data.bit.SDB_N) {
- return;
- } // Prevent calculations and I2C traffic if LED drivers are not enabled
-#endif
-
- // Wait for previous transfer to complete
- while (i2c_led_q_running) {
- }
-
- // Copy buffer to live DMA region
- for (uint8_t i = 0; i < ISSI3733_LED_COUNT; i++) {
- *led_map[i].rgb.r = led_buffer[i].r;
- *led_map[i].rgb.g = led_buffer[i].g;
- *led_map[i].rgb.b = led_buffer[i].b;
- }
-
-#ifdef USE_MASSDROP_CONFIGURATOR
- breathe_mult = 1;
-
- if (led_animation_breathing) {
- //+60us 119 LED
- led_animation_breathe_cur += BREATHE_STEP * breathe_dir;
-
- if (led_animation_breathe_cur >= BREATHE_MAX_STEP)
- breathe_dir = -1;
- else if (led_animation_breathe_cur <= BREATHE_MIN_STEP)
- breathe_dir = 1;
-
- // Brightness curve created for 256 steps, 0 - ~98%
- breathe_mult = 0.000015 * led_animation_breathe_cur * led_animation_breathe_cur;
- if (breathe_mult > 1)
- breathe_mult = 1;
- else if (breathe_mult < 0)
- breathe_mult = 0;
- }
-
- // This should only be performed once per frame
- pomod = (float)((g_rgb_timer / 10) % (uint32_t)(1000.0f / led_animation_speed)) / 10.0f * led_animation_speed;
- pomod *= 100.0f;
- pomod = (uint32_t)pomod % 10000;
- pomod /= 100.0f;
-
-#endif // USE_MASSDROP_CONFIGURATOR
-
- uint8_t drvid;
-
- // NOTE: GCR does not need to be timed with LED processing, but there is really no harm
- if (gcr_actual != gcr_actual_last) {
- for (drvid = 0; drvid < ISSI3733_DRIVER_COUNT; drvid++) I2C_LED_Q_GCR(drvid); // Queue data
- gcr_actual_last = gcr_actual;
- }
-
- for (drvid = 0; drvid < ISSI3733_DRIVER_COUNT; drvid++) I2C_LED_Q_PWM(drvid); // Queue data
-
- i2c_led_q_run();
-}
-
-void led_matrix_indicators(void) {
- uint8_t kbled = keyboard_leds();
- if (kbled && rgb_matrix_config.enable) {
- for (uint8_t i = 0; i < ISSI3733_LED_COUNT; i++) {
- if (
-#if USB_LED_NUM_LOCK_SCANCODE != 255
- (led_map[i].scan == USB_LED_NUM_LOCK_SCANCODE && (kbled & (1 << USB_LED_NUM_LOCK))) ||
-#endif // NUM LOCK
-#if USB_LED_CAPS_LOCK_SCANCODE != 255
- (led_map[i].scan == USB_LED_CAPS_LOCK_SCANCODE && (kbled & (1 << USB_LED_CAPS_LOCK))) ||
-#endif // CAPS LOCK
-#if USB_LED_SCROLL_LOCK_SCANCODE != 255
- (led_map[i].scan == USB_LED_SCROLL_LOCK_SCANCODE && (kbled & (1 << USB_LED_SCROLL_LOCK))) ||
-#endif // SCROLL LOCK
-#if USB_LED_COMPOSE_SCANCODE != 255
- (led_map[i].scan == USB_LED_COMPOSE_SCANCODE && (kbled & (1 << USB_LED_COMPOSE))) ||
-#endif // COMPOSE
-#if USB_LED_KANA_SCANCODE != 255
- (led_map[i].scan == USB_LED_KANA_SCANCODE && (kbled & (1 << USB_LED_KANA))) ||
-#endif // KANA
- (0)) {
- led_buffer[i].r = 255 - led_buffer[i].r;
- led_buffer[i].g = 255 - led_buffer[i].g;
- led_buffer[i].b = 255 - led_buffer[i].b;
- }
- }
- }
-}
-
-const rgb_matrix_driver_t rgb_matrix_driver = {.init = init, .flush = flush, .set_color = led_set_one, .set_color_all = led_set_all};
-
-/*==============================================================================
-= Legacy Lighting Support =
-==============================================================================*/
-
-#ifdef USE_MASSDROP_CONFIGURATOR
-// Ported from Massdrop QMK GitHub Repo
-
-// TODO?: wire these up to keymap.c
-uint8_t led_animation_orientation = 0;
-uint8_t led_animation_direction = 0;
-uint8_t led_animation_breathing = 0;
-uint8_t led_animation_id = 0;
-float led_animation_speed = 4.0f;
-uint8_t led_lighting_mode = LED_MODE_NORMAL;
-uint8_t led_enabled = 1;
-uint8_t led_animation_breathe_cur = BREATHE_MIN_STEP;
-uint8_t breathe_dir = 1;
-
-static void led_run_pattern(led_setup_t* f, float* ro, float* go, float* bo, float pos) {
- float po;
-
- while (f->end != 1) {
- po = pos; // Reset po for new frame
-
- // Add in any moving effects
- if ((!led_animation_direction && f->ef & EF_SCR_R) || (led_animation_direction && (f->ef & EF_SCR_L))) {
- po -= pomod;
-
- if (po > 100)
- po -= 100;
- else if (po < 0)
- po += 100;
- } else if ((!led_animation_direction && f->ef & EF_SCR_L) || (led_animation_direction && (f->ef & EF_SCR_R))) {
- po += pomod;
-
- if (po > 100)
- po -= 100;
- else if (po < 0)
- po += 100;
- }
-
- // Check if LED's po is in current frame
- if (po < f->hs) {
- f++;
- continue;
- }
- if (po > f->he) {
- f++;
- continue;
- }
- // note: < 0 or > 100 continue
-
- // Calculate the po within the start-stop percentage for color blending
- po = (po - f->hs) / (f->he - f->hs);
-
- // Add in any color effects
- if (f->ef & EF_OVER) {
- *ro = (po * (f->re - f->rs)) + f->rs; // + 0.5;
- *go = (po * (f->ge - f->gs)) + f->gs; // + 0.5;
- *bo = (po * (f->be - f->bs)) + f->bs; // + 0.5;
- } else if (f->ef & EF_SUBTRACT) {
- *ro -= (po * (f->re - f->rs)) + f->rs; // + 0.5;
- *go -= (po * (f->ge - f->gs)) + f->gs; // + 0.5;
- *bo -= (po * (f->be - f->bs)) + f->bs; // + 0.5;
- } else {
- *ro += (po * (f->re - f->rs)) + f->rs; // + 0.5;
- *go += (po * (f->ge - f->gs)) + f->gs; // + 0.5;
- *bo += (po * (f->be - f->bs)) + f->bs; // + 0.5;
- }
-
- f++;
- }
-}
-
-static void led_matrix_massdrop_config_override(int i) {
- float ro = 0;
- float go = 0;
- float bo = 0;
-
- float po = (led_animation_orientation) ? (float)g_led_config.point[i].y / 64.f * 100 : (float)g_led_config.point[i].x / 224.f * 100;
-
- uint8_t highest_active_layer = biton32(layer_state);
-
- if (led_lighting_mode == LED_MODE_KEYS_ONLY && HAS_FLAGS(g_led_config.flags[i], LED_FLAG_UNDERGLOW)) {
- // Do not act on this LED
- } else if (led_lighting_mode == LED_MODE_NON_KEYS_ONLY && !HAS_FLAGS(g_led_config.flags[i], LED_FLAG_UNDERGLOW)) {
- // Do not act on this LED
- } else if (led_lighting_mode == LED_MODE_INDICATORS_ONLY) {
- // Do not act on this LED (Only show indicators)
- } else {
- led_instruction_t* led_cur_instruction = led_instructions;
- while (!led_cur_instruction->end) {
- // Check if this applies to current layer
- if ((led_cur_instruction->flags & LED_FLAG_MATCH_LAYER) && (led_cur_instruction->layer != highest_active_layer)) {
- goto next_iter;
- }
-
- // Check if this applies to current index
- if (led_cur_instruction->flags & LED_FLAG_MATCH_ID) {
- uint8_t modid = i / 32; // Calculate which id# contains the led bit
- uint32_t modidbit = 1 << (i % 32); // Calculate the bit within the id#
- uint32_t* bitfield = &led_cur_instruction->id0 + modid; // Add modid as offset to id0 address. *bitfield is now idX of the led id
- if (~(*bitfield) & modidbit) { // Check if led bit is not set in idX
- goto next_iter;
- }
- }
-
- if (led_cur_instruction->flags & LED_FLAG_USE_RGB) {
- ro = led_cur_instruction->r;
- go = led_cur_instruction->g;
- bo = led_cur_instruction->b;
- } else if (led_cur_instruction->flags & LED_FLAG_USE_PATTERN) {
- led_run_pattern(led_setups[led_cur_instruction->pattern_id], &ro, &go, &bo, po);
- } else if (led_cur_instruction->flags & LED_FLAG_USE_ROTATE_PATTERN) {
- led_run_pattern(led_setups[led_animation_id], &ro, &go, &bo, po);
- }
-
- next_iter:
- led_cur_instruction++;
- }
-
- if (ro > 255)
- ro = 255;
- else if (ro < 0)
- ro = 0;
- if (go > 255)
- go = 255;
- else if (go < 0)
- go = 0;
- if (bo > 255)
- bo = 255;
- else if (bo < 0)
- bo = 0;
-
- if (led_animation_breathing) {
- ro *= breathe_mult;
- go *= breathe_mult;
- bo *= breathe_mult;
- }
- }
-
- led_buffer[i].r = (uint8_t)ro;
- led_buffer[i].g = (uint8_t)go;
- led_buffer[i].b = (uint8_t)bo;
-}
-
-#endif // USE_MASSDROP_CONFIGURATOR
diff --git a/tmk_core/protocol/arm_atsam/led_matrix.h b/tmk_core/protocol/arm_atsam/led_matrix.h
deleted file mode 100644
index 8eaa5623bd..0000000000
--- a/tmk_core/protocol/arm_atsam/led_matrix.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
-Copyright 2018 Massdrop Inc.
-
-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 .
-*/
-
-#ifndef _LED_MATRIX_H_
-#define _LED_MATRIX_H_
-
-#include "quantum.h"
-
-// From keyboard
-#include "config_led.h"
-
-// CS1-CS16 Current Source "Col"
-#define ISSI3733_CS_COUNT 16
-
-// SW1-SW12 Switch "Row"
-#define ISSI3733_SW_COUNT 12
-
-#define ISSI3733_LED_RGB_COUNT ISSI3733_CS_COUNT *ISSI3733_SW_COUNT
-#define ISSI3733_PG0_BYTES ISSI3733_LED_RGB_COUNT / 8 + 1 //+1 for first byte being memory start offset for I2C transfer
-#define ISSI3733_PG1_BYTES ISSI3733_LED_RGB_COUNT + 1 //+1 for first byte being memory start offset for I2C transfer
-#define ISSI3733_PG2_BYTES ISSI3733_LED_RGB_COUNT + 1 //+1 for first byte being memory start offset for I2C transfer
-#define ISSI3733_PG3_BYTES 18 + 1 //+1 for first byte being memory start offset for I2C transfer
-
-#define ISSI3733_PG_ONOFF_BYTES ISSI3733_PG0_BYTES
-#define ISSI3733_PG_OR_BYTES ISSI3733_PG0_BYTES
-#define ISSI3733_PG_SR_BYTES ISSI3733_PG0_BYTES
-#define ISSI3733_PG_PWM_BYTES ISSI3733_PG1_BYTES
-#define ISSI3733_PG_ABM_BYTES ISSI3733_PG2_BYTES
-#define ISSI3733_PG_FN_BYTES ISSI3733_PG3_BYTES
-
-typedef struct issi3733_driver_s {
- uint8_t addr; // Address of the driver according to wiring "ISSI3733: Table 1 Slave Address"
- uint8_t onoff[ISSI3733_PG_ONOFF_BYTES]; // PG0 - LED Control Register - LED On/Off Register
- uint8_t open[ISSI3733_PG_OR_BYTES]; // PG0 - LED Control Register - LED Open Register
- uint8_t shrt[ISSI3733_PG_SR_BYTES]; // PG0 - LED Control Register - LED Short Register
- uint8_t pwm[ISSI3733_PG_PWM_BYTES]; // PG1 - PWM Register
- uint8_t abm[ISSI3733_PG_ABM_BYTES]; // PG2 - Auto Breath Mode Register
- uint8_t conf[ISSI3733_PG_FN_BYTES]; // PG3 - Function Register
-} issi3733_driver_t;
-
-typedef struct issi3733_rgb_s {
- uint8_t *r; // Direct access into PWM data
- uint8_t *g; // Direct access into PWM data
- uint8_t *b; // Direct access into PWM data
-} issi3733_rgb_t;
-
-typedef struct issi3733_rgb_adr_s {
- uint8_t drv; // Driver from given list
- uint8_t cs; // CS
- uint8_t swr; // SW Red
- uint8_t swg; // SW Green
- uint8_t swb; // SW Blue
-} issi3733_rgb_adr_t;
-
-typedef struct issi3733_led_s {
- uint8_t id; // According to PCB ref
- issi3733_rgb_t rgb; // PWM settings of R G B
- issi3733_rgb_adr_t adr; // Hardware addresses
- float x; // Physical position X
- float y; // Physical position Y
- float px; // Physical position X in percent
- float py; // Physical position Y in percent
- uint8_t scan; // Key scan code from wiring (set 0xFF if no key)
-} issi3733_led_t;
-
-extern issi3733_driver_t issidrv[ISSI3733_DRIVER_COUNT];
-
-extern uint8_t gcr_desired;
-extern uint8_t gcr_breathe;
-extern uint8_t gcr_actual;
-extern uint8_t gcr_actual_last;
-
-void gcr_compute(void);
-
-void led_matrix_indicators(void);
-
-/*------------------------- Legacy Lighting Support ------------------------*/
-
-#ifdef USE_MASSDROP_CONFIGURATOR
-
-# define EF_NONE 0x00000000 // No effect
-# define EF_OVER 0x00000001 // Overwrite any previous color information with new
-# define EF_SCR_L 0x00000002 // Scroll left
-# define EF_SCR_R 0x00000004 // Scroll right
-# define EF_SUBTRACT 0x00000008 // Subtract color values
-
-typedef struct led_setup_s {
- float hs; // Band begin at percent
- float he; // Band end at percent
- uint8_t rs; // Red start value
- uint8_t re; // Red end value
- uint8_t gs; // Green start value
- uint8_t ge; // Green end value
- uint8_t bs; // Blue start value
- uint8_t be; // Blue end value
- uint32_t ef; // Animation and color effects
- uint8_t end; // Set to signal end of the setup
-} led_setup_t;
-
-extern const uint8_t led_setups_count;
-extern void * led_setups[];
-
-// LED Extra Instructions
-# define LED_FLAG_NULL 0x00 // Matching and coloring not used (default)
-# define LED_FLAG_MATCH_ID 0x01 // Match on the ID of the LED (set id#'s to desired bit pattern, first LED is id 1)
-# define LED_FLAG_MATCH_LAYER 0x02 // Match on the current active layer (set layer to desired match layer)
-# define LED_FLAG_USE_RGB 0x10 // Use a specific RGB value (set r, g, b to desired output color values)
-# define LED_FLAG_USE_PATTERN 0x20 // Use a specific pattern ID (set pattern_id to desired output pattern)
-# define LED_FLAG_USE_ROTATE_PATTERN 0x40 // Use pattern the user has cycled to manually
-
-typedef struct led_instruction_s {
- uint16_t flags; // Bitfield for LED instructions
- uint32_t id0; // Bitwise id, IDs 0-31
- uint32_t id1; // Bitwise id, IDs 32-63
- uint32_t id2; // Bitwise id, IDs 64-95
- uint32_t id3; // Bitwise id, IDs 96-127
- uint8_t layer;
- uint8_t r;
- uint8_t g;
- uint8_t b;
- uint8_t pattern_id;
- uint8_t end;
-} led_instruction_t;
-
-extern led_instruction_t led_instructions[];
-
-extern uint8_t led_animation_breathing;
-extern uint8_t led_animation_id;
-extern float led_animation_speed;
-extern uint8_t led_lighting_mode;
-extern uint8_t led_enabled;
-extern uint8_t led_animation_breathe_cur;
-extern uint8_t led_animation_direction;
-extern uint8_t breathe_dir;
-
-# define LED_MODE_NORMAL 0 // Must be 0
-# define LED_MODE_KEYS_ONLY 1
-# define LED_MODE_NON_KEYS_ONLY 2
-# define LED_MODE_INDICATORS_ONLY 3
-# define LED_MODE_MAX_INDEX LED_MODE_INDICATORS_ONLY // Must be highest value
-
-#endif // USE_MASSDROP_CONFIGURATOR
-
-#endif //_LED_MATRIX_H_
diff --git a/tmk_core/protocol/arm_atsam/led_matrix_programs.c b/tmk_core/protocol/arm_atsam/led_matrix_programs.c
deleted file mode 100644
index 360102ba84..0000000000
--- a/tmk_core/protocol/arm_atsam/led_matrix_programs.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
-Copyright 2018 Massdrop Inc.
-
-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 .
-*/
-
-#ifdef USE_MASSDROP_CONFIGURATOR
-
-# include "led_matrix.h"
-
-// Teal <-> Salmon
-led_setup_t leds_teal_salmon[] = {
- {.hs = 0, .he = 33, .rs = 24, .re = 24, .gs = 215, .ge = 215, .bs = 204, .be = 204, .ef = EF_NONE},
- {.hs = 33, .he = 66, .rs = 24, .re = 255, .gs = 215, .ge = 114, .bs = 204, .be = 118, .ef = EF_NONE},
- {.hs = 66, .he = 100, .rs = 255, .re = 255, .gs = 114, .ge = 114, .bs = 118, .be = 118, .ef = EF_NONE},
- {.end = 1},
-};
-
-// Yellow
-led_setup_t leds_yellow[] = {
- {.hs = 0, .he = 100, .rs = 255, .re = 255, .gs = 255, .ge = 255, .bs = 0, .be = 0, .ef = EF_NONE},
- {.end = 1},
-};
-
-// Off
-led_setup_t leds_off[] = {
- {.hs = 0, .he = 100, .rs = 0, .re = 0, .gs = 0, .ge = 0, .bs = 0, .be = 0, .ef = EF_NONE},
- {.end = 1},
-};
-
-// Red
-led_setup_t leds_red[] = {
- {.hs = 0, .he = 100, .rs = 255, .re = 255, .gs = 0, .ge = 0, .bs = 0, .be = 0, .ef = EF_NONE},
- {.end = 1},
-};
-
-// Green
-led_setup_t leds_green[] = {
- {.hs = 0, .he = 100, .rs = 0, .re = 0, .gs = 255, .ge = 255, .bs = 0, .be = 0, .ef = EF_NONE},
- {.end = 1},
-};
-
-// Blue
-led_setup_t leds_blue[] = {
- {.hs = 0, .he = 100, .rs = 0, .re = 0, .gs = 0, .ge = 0, .bs = 255, .be = 255, .ef = EF_NONE},
- {.end = 1},
-};
-
-// White
-led_setup_t leds_white[] = {
- {.hs = 0, .he = 100, .rs = 255, .re = 255, .gs = 255, .ge = 255, .bs = 255, .be = 255, .ef = EF_NONE},
- {.end = 1},
-};
-
-// White with moving red stripe
-led_setup_t leds_white_with_red_stripe[] = {
- {.hs = 0, .he = 100, .rs = 255, .re = 255, .gs = 255, .ge = 255, .bs = 255, .be = 255, .ef = EF_NONE},
- {.hs = 0, .he = 15, .rs = 0, .re = 0, .gs = 0, .ge = 255, .bs = 0, .be = 255, .ef = EF_SCR_R | EF_SUBTRACT},
- {.hs = 15, .he = 30, .rs = 0, .re = 0, .gs = 255, .ge = 0, .bs = 255, .be = 0, .ef = EF_SCR_R | EF_SUBTRACT},
- {.end = 1},
-};
-
-// Black with moving red stripe
-led_setup_t leds_black_with_red_stripe[] = {
- {.hs = 0, .he = 15, .rs = 0, .re = 255, .gs = 0, .ge = 0, .bs = 0, .be = 0, .ef = EF_SCR_R},
- {.hs = 15, .he = 30, .rs = 255, .re = 0, .gs = 0, .ge = 0, .bs = 0, .be = 0, .ef = EF_SCR_R},
- {.end = 1},
-};
-
-// Rainbow no scrolling
-led_setup_t leds_rainbow_ns[] = {
- {.hs = 0, .he = 16.67, .rs = 255, .re = 255, .gs = 0, .ge = 255, .bs = 0, .be = 0, .ef = EF_OVER}, {.hs = 16.67, .he = 33.33, .rs = 255, .re = 0, .gs = 255, .ge = 255, .bs = 0, .be = 0, .ef = EF_OVER}, {.hs = 33.33, .he = 50, .rs = 0, .re = 0, .gs = 255, .ge = 255, .bs = 0, .be = 255, .ef = EF_OVER}, {.hs = 50, .he = 66.67, .rs = 0, .re = 0, .gs = 255, .ge = 0, .bs = 255, .be = 255, .ef = EF_OVER}, {.hs = 66.67, .he = 83.33, .rs = 0, .re = 255, .gs = 0, .ge = 0, .bs = 255, .be = 255, .ef = EF_OVER}, {.hs = 83.33, .he = 100, .rs = 255, .re = 255, .gs = 0, .ge = 0, .bs = 255, .be = 0, .ef = EF_OVER}, {.end = 1},
-};
-
-// Rainbow scrolling
-led_setup_t leds_rainbow_s[] = {
- {.hs = 0, .he = 16.67, .rs = 255, .re = 255, .gs = 0, .ge = 255, .bs = 0, .be = 0, .ef = EF_OVER | EF_SCR_R}, {.hs = 16.67, .he = 33.33, .rs = 255, .re = 0, .gs = 255, .ge = 255, .bs = 0, .be = 0, .ef = EF_OVER | EF_SCR_R}, {.hs = 33.33, .he = 50, .rs = 0, .re = 0, .gs = 255, .ge = 255, .bs = 0, .be = 255, .ef = EF_OVER | EF_SCR_R}, {.hs = 50, .he = 66.67, .rs = 0, .re = 0, .gs = 255, .ge = 0, .bs = 255, .be = 255, .ef = EF_OVER | EF_SCR_R}, {.hs = 66.67, .he = 83.33, .rs = 0, .re = 255, .gs = 0, .ge = 0, .bs = 255, .be = 255, .ef = EF_OVER | EF_SCR_R}, {.hs = 83.33, .he = 100, .rs = 255, .re = 255, .gs = 0, .ge = 0, .bs = 255, .be = 0, .ef = EF_OVER | EF_SCR_R}, {.end = 1},
-};
-
-// Add new LED animations here using one from above as example
-// The last entry must be { .end = 1 }
-// Add the new animation name to the list below following its format
-
-void *led_setups[] = {leds_rainbow_s, leds_rainbow_ns, leds_teal_salmon, leds_yellow, leds_red, leds_green, leds_blue, leds_white, leds_white_with_red_stripe, leds_black_with_red_stripe, leds_off};
-
-const uint8_t led_setups_count = sizeof(led_setups) / sizeof(led_setups[0]);
-
-#endif
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/md_rgb_matrix.c b/tmk_core/protocol/arm_atsam/md_rgb_matrix.c
new file mode 100644
index 0000000000..b337df7627
--- /dev/null
+++ b/tmk_core/protocol/arm_atsam/md_rgb_matrix.c
@@ -0,0 +1,470 @@
+/*
+Copyright 2018 Massdrop Inc.
+
+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 .
+*/
+
+#include "arm_atsam_protocol.h"
+#include "tmk_core/common/led.h"
+#include "rgb_matrix.h"
+#include
+#include
+
+#ifdef USE_MASSDROP_CONFIGURATOR
+__attribute__((weak)) led_instruction_t led_instructions[] = {{.end = 1}};
+static void md_rgb_matrix_config_override(int i);
+#endif // USE_MASSDROP_CONFIGURATOR
+
+void SERCOM1_0_Handler(void) {
+ if (SERCOM1->I2CM.INTFLAG.bit.ERROR) {
+ SERCOM1->I2CM.INTFLAG.reg = SERCOM_I2CM_INTENCLR_ERROR;
+ }
+}
+
+void DMAC_0_Handler(void) {
+ if (DMAC->Channel[0].CHINTFLAG.bit.TCMPL) {
+ DMAC->Channel[0].CHINTFLAG.reg = DMAC_CHINTENCLR_TCMPL;
+
+ i2c1_stop();
+
+ i2c_led_q_running = 0;
+
+ i2c_led_q_run();
+
+ return;
+ }
+
+ if (DMAC->Channel[0].CHINTFLAG.bit.TERR) {
+ DMAC->Channel[0].CHINTFLAG.reg = DMAC_CHINTENCLR_TERR;
+ }
+}
+
+issi3733_driver_t issidrv[ISSI3733_DRIVER_COUNT];
+
+issi3733_led_t led_map[ISSI3733_LED_COUNT] = ISSI3733_LED_MAP;
+RGB led_buffer[ISSI3733_LED_COUNT];
+
+uint8_t gcr_desired;
+uint8_t gcr_actual;
+uint8_t gcr_actual_last;
+#ifdef USE_MASSDROP_CONFIGURATOR
+uint8_t gcr_breathe;
+float breathe_mult;
+float pomod;
+#endif
+
+#define ACT_GCR_NONE 0
+#define ACT_GCR_INC 1
+#define ACT_GCR_DEC 2
+
+#define LED_GCR_STEP_AUTO 2
+
+static uint8_t gcr_min_counter;
+static uint8_t v_5v_cat_hit;
+
+// WARNING: Automatic GCR is in place to prevent USB shutdown and LED driver overloading
+void gcr_compute(void) {
+ uint8_t action = ACT_GCR_NONE;
+ uint8_t gcr_use = gcr_desired;
+
+#ifdef USE_MASSDROP_CONFIGURATOR
+ if (led_animation_breathing) {
+ gcr_use = gcr_breathe;
+ }
+#endif
+
+ // If the 5v takes a catastrophic hit, disable the LED drivers briefly, assert auto gcr mode, min gcr and let the auto take over
+ if (v_5v < V5_CAT) {
+ I2C3733_Control_Set(0);
+ // CDC_print("USB: WARNING: 5V catastrophic level reached! Disabling LED drivers!\r\n"); //Blocking print is bad here!
+ v_5v_cat_hit = 20; //~100ms recover
+ gcr_actual = 0; // Minimize GCR
+ usb_gcr_auto = 1; // Force auto mode enabled
+ return;
+ } else if (v_5v_cat_hit > 1) {
+ v_5v_cat_hit--;
+ return;
+ } else if (v_5v_cat_hit == 1) {
+ I2C3733_Control_Set(1);
+ CDC_print("USB: WARNING: Re-enabling LED drivers\r\n");
+ v_5v_cat_hit = 0;
+ return;
+ }
+
+ if (usb_gcr_auto) {
+ if (v_5v_avg < V5_LOW)
+ action = ACT_GCR_DEC;
+ else if (v_5v_avg > V5_HIGH && gcr_actual < gcr_use)
+ action = ACT_GCR_INC;
+ else if (gcr_actual > gcr_use)
+ action = ACT_GCR_DEC;
+ } else {
+ if (gcr_actual < gcr_use)
+ action = ACT_GCR_INC;
+ else if (gcr_actual > gcr_use)
+ action = ACT_GCR_DEC;
+ }
+
+ if (action == ACT_GCR_NONE) {
+ gcr_min_counter = 0;
+ } else if (action == ACT_GCR_INC) {
+ if (LED_GCR_STEP_AUTO > LED_GCR_MAX - gcr_actual)
+ gcr_actual = LED_GCR_MAX; // Obey max and prevent wrapping
+ else
+ gcr_actual += LED_GCR_STEP_AUTO;
+ gcr_min_counter = 0;
+ } else if (action == ACT_GCR_DEC) {
+ if (LED_GCR_STEP_AUTO > gcr_actual) // Prevent wrapping
+ {
+ gcr_actual = 0;
+ // At this point, power can no longer be cut from the LED drivers, so focus on cutting out extra port if active
+ if (usb_extra_state != USB_EXTRA_STATE_DISABLED_UNTIL_REPLUG) // If not in a wait for replug state
+ {
+ if (usb_extra_state == USB_EXTRA_STATE_ENABLED) // If extra usb is enabled
+ {
+ gcr_min_counter++;
+ if (gcr_min_counter > 200) // 5ms per check = 1s delay
+ {
+ USB_ExtraSetState(USB_EXTRA_STATE_DISABLED_UNTIL_REPLUG);
+ usb_extra_manual = 0; // Force disable manual mode of extra port
+ if (usb_extra_manual)
+ CDC_print("USB: Disabling extra port until replug and manual mode toggle!\r\n");
+ else
+ CDC_print("USB: Disabling extra port until replug!\r\n");
+ }
+ }
+ }
+ } else {
+ // Power successfully cut back from LED drivers
+ gcr_actual -= LED_GCR_STEP_AUTO;
+ gcr_min_counter = 0;
+
+#ifdef USE_MASSDROP_CONFIGURATOR
+ // If breathe mode is active, the top end can fluctuate if the host can not supply enough current
+ // So set the breathe GCR to where it becomes stable
+ if (led_animation_breathing == 1) {
+ gcr_breathe = gcr_actual;
+ // PS: At this point, setting breathing to exhale makes a noticebly shorter cycle
+ // and the same would happen maybe one or two more times. Therefore I'm favoring
+ // powering through one full breathe and letting gcr settle completely
+ }
+#endif
+ }
+ }
+}
+
+void issi3733_prepare_arrays(void) {
+ memset(issidrv, 0, sizeof(issi3733_driver_t) * ISSI3733_DRIVER_COUNT);
+
+ int i;
+ uint8_t addrs[ISSI3733_DRIVER_COUNT] = ISSI3773_DRIVER_ADDRESSES;
+
+ for (i = 0; i < ISSI3733_DRIVER_COUNT; i++) {
+ issidrv[i].addr = addrs[i];
+ }
+
+ for (uint8_t i = 0; i < ISSI3733_LED_COUNT; i++) {
+ // BYTE: 1 + (SW-1)*16 + (CS-1)
+ led_map[i].rgb.g = issidrv[led_map[i].adr.drv - 1].pwm + 1 + ((led_map[i].adr.swg - 1) * 16 + (led_map[i].adr.cs - 1));
+ led_map[i].rgb.r = issidrv[led_map[i].adr.drv - 1].pwm + 1 + ((led_map[i].adr.swr - 1) * 16 + (led_map[i].adr.cs - 1));
+ led_map[i].rgb.b = issidrv[led_map[i].adr.drv - 1].pwm + 1 + ((led_map[i].adr.swb - 1) * 16 + (led_map[i].adr.cs - 1));
+
+ // BYTE: 1 + (SW-1)*2 + (CS-1)/8
+ // BIT: (CS-1)%8
+ *(issidrv[led_map[i].adr.drv - 1].onoff + 1 + (led_map[i].adr.swg - 1) * 2 + (led_map[i].adr.cs - 1) / 8) |= (1 << ((led_map[i].adr.cs - 1) % 8));
+ *(issidrv[led_map[i].adr.drv - 1].onoff + 1 + (led_map[i].adr.swr - 1) * 2 + (led_map[i].adr.cs - 1) / 8) |= (1 << ((led_map[i].adr.cs - 1) % 8));
+ *(issidrv[led_map[i].adr.drv - 1].onoff + 1 + (led_map[i].adr.swb - 1) * 2 + (led_map[i].adr.cs - 1) / 8) |= (1 << ((led_map[i].adr.cs - 1) % 8));
+ }
+}
+
+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;
+ *led_map[i].rgb.b = 0;
+ }
+}
+
+void led_set_one(int i, uint8_t r, uint8_t g, uint8_t b) {
+ if (i < ISSI3733_LED_COUNT) {
+#ifdef USE_MASSDROP_CONFIGURATOR
+ md_rgb_matrix_config_override(i);
+#else
+ led_buffer[i].r = r;
+ led_buffer[i].g = g;
+ led_buffer[i].b = b;
+#endif
+ }
+}
+
+void led_set_all(uint8_t r, uint8_t g, uint8_t b) {
+ for (uint8_t i = 0; i < ISSI3733_LED_COUNT; i++) {
+ led_set_one(i, r, g, b);
+ }
+}
+
+void init(void) {
+ DBGC(DC_LED_MATRIX_INIT_BEGIN);
+
+ issi3733_prepare_arrays();
+
+ md_rgb_matrix_prepare();
+
+ gcr_min_counter = 0;
+ v_5v_cat_hit = 0;
+
+ DBGC(DC_LED_MATRIX_INIT_COMPLETE);
+}
+
+void flush(void) {
+#ifdef USE_MASSDROP_CONFIGURATOR
+ if (!led_enabled) {
+ return;
+ } // Prevent calculations and I2C traffic if LED drivers are not enabled
+#else
+ if (!sr_exp_data.bit.SDB_N) {
+ return;
+ } // Prevent calculations and I2C traffic if LED drivers are not enabled
+#endif
+
+ // Wait for previous transfer to complete
+ while (i2c_led_q_running) {
+ }
+
+ // Copy buffer to live DMA region
+ for (uint8_t i = 0; i < ISSI3733_LED_COUNT; i++) {
+ *led_map[i].rgb.r = led_buffer[i].r;
+ *led_map[i].rgb.g = led_buffer[i].g;
+ *led_map[i].rgb.b = led_buffer[i].b;
+ }
+
+#ifdef USE_MASSDROP_CONFIGURATOR
+ breathe_mult = 1;
+
+ if (led_animation_breathing) {
+ //+60us 119 LED
+ led_animation_breathe_cur += BREATHE_STEP * breathe_dir;
+
+ if (led_animation_breathe_cur >= BREATHE_MAX_STEP)
+ breathe_dir = -1;
+ else if (led_animation_breathe_cur <= BREATHE_MIN_STEP)
+ breathe_dir = 1;
+
+ // Brightness curve created for 256 steps, 0 - ~98%
+ breathe_mult = 0.000015 * led_animation_breathe_cur * led_animation_breathe_cur;
+ if (breathe_mult > 1)
+ breathe_mult = 1;
+ else if (breathe_mult < 0)
+ breathe_mult = 0;
+ }
+
+ // This should only be performed once per frame
+ pomod = (float)((g_rgb_timer / 10) % (uint32_t)(1000.0f / led_animation_speed)) / 10.0f * led_animation_speed;
+ pomod *= 100.0f;
+ pomod = (uint32_t)pomod % 10000;
+ pomod /= 100.0f;
+
+#endif // USE_MASSDROP_CONFIGURATOR
+
+ uint8_t drvid;
+
+ // NOTE: GCR does not need to be timed with LED processing, but there is really no harm
+ if (gcr_actual != gcr_actual_last) {
+ for (drvid = 0; drvid < ISSI3733_DRIVER_COUNT; drvid++) I2C_LED_Q_GCR(drvid); // Queue data
+ gcr_actual_last = gcr_actual;
+ }
+
+ for (drvid = 0; drvid < ISSI3733_DRIVER_COUNT; drvid++) I2C_LED_Q_PWM(drvid); // Queue data
+
+ i2c_led_q_run();
+}
+
+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++) {
+ if (
+#if USB_LED_NUM_LOCK_SCANCODE != 255
+ (led_map[i].scan == USB_LED_NUM_LOCK_SCANCODE && (kbled & (1 << USB_LED_NUM_LOCK))) ||
+#endif // NUM LOCK
+#if USB_LED_CAPS_LOCK_SCANCODE != 255
+ (led_map[i].scan == USB_LED_CAPS_LOCK_SCANCODE && (kbled & (1 << USB_LED_CAPS_LOCK))) ||
+#endif // CAPS LOCK
+#if USB_LED_SCROLL_LOCK_SCANCODE != 255
+ (led_map[i].scan == USB_LED_SCROLL_LOCK_SCANCODE && (kbled & (1 << USB_LED_SCROLL_LOCK))) ||
+#endif // SCROLL LOCK
+#if USB_LED_COMPOSE_SCANCODE != 255
+ (led_map[i].scan == USB_LED_COMPOSE_SCANCODE && (kbled & (1 << USB_LED_COMPOSE))) ||
+#endif // COMPOSE
+#if USB_LED_KANA_SCANCODE != 255
+ (led_map[i].scan == USB_LED_KANA_SCANCODE && (kbled & (1 << USB_LED_KANA))) ||
+#endif // KANA
+ (0)) {
+ led_buffer[i].r = 255 - led_buffer[i].r;
+ led_buffer[i].g = 255 - led_buffer[i].g;
+ led_buffer[i].b = 255 - led_buffer[i].b;
+ }
+ }
+ }
+}
+
+const rgb_matrix_driver_t rgb_matrix_driver = {.init = init, .flush = flush, .set_color = led_set_one, .set_color_all = led_set_all};
+
+/*==============================================================================
+= Legacy Lighting Support =
+==============================================================================*/
+
+#ifdef USE_MASSDROP_CONFIGURATOR
+// Ported from Massdrop QMK GitHub Repo
+
+// TODO?: wire these up to keymap.c
+uint8_t led_animation_orientation = 0;
+uint8_t led_animation_direction = 0;
+uint8_t led_animation_breathing = 0;
+uint8_t led_animation_id = 0;
+float led_animation_speed = 4.0f;
+uint8_t led_lighting_mode = LED_MODE_NORMAL;
+uint8_t led_enabled = 1;
+uint8_t led_animation_breathe_cur = BREATHE_MIN_STEP;
+uint8_t breathe_dir = 1;
+
+static void led_run_pattern(led_setup_t* f, float* ro, float* go, float* bo, float pos) {
+ float po;
+
+ while (f->end != 1) {
+ po = pos; // Reset po for new frame
+
+ // Add in any moving effects
+ if ((!led_animation_direction && f->ef & EF_SCR_R) || (led_animation_direction && (f->ef & EF_SCR_L))) {
+ po -= pomod;
+
+ if (po > 100)
+ po -= 100;
+ else if (po < 0)
+ po += 100;
+ } else if ((!led_animation_direction && f->ef & EF_SCR_L) || (led_animation_direction && (f->ef & EF_SCR_R))) {
+ po += pomod;
+
+ if (po > 100)
+ po -= 100;
+ else if (po < 0)
+ po += 100;
+ }
+
+ // Check if LED's po is in current frame
+ if (po < f->hs) {
+ f++;
+ continue;
+ }
+ if (po > f->he) {
+ f++;
+ continue;
+ }
+ // note: < 0 or > 100 continue
+
+ // Calculate the po within the start-stop percentage for color blending
+ po = (po - f->hs) / (f->he - f->hs);
+
+ // Add in any color effects
+ if (f->ef & EF_OVER) {
+ *ro = (po * (f->re - f->rs)) + f->rs; // + 0.5;
+ *go = (po * (f->ge - f->gs)) + f->gs; // + 0.5;
+ *bo = (po * (f->be - f->bs)) + f->bs; // + 0.5;
+ } else if (f->ef & EF_SUBTRACT) {
+ *ro -= (po * (f->re - f->rs)) + f->rs; // + 0.5;
+ *go -= (po * (f->ge - f->gs)) + f->gs; // + 0.5;
+ *bo -= (po * (f->be - f->bs)) + f->bs; // + 0.5;
+ } else {
+ *ro += (po * (f->re - f->rs)) + f->rs; // + 0.5;
+ *go += (po * (f->ge - f->gs)) + f->gs; // + 0.5;
+ *bo += (po * (f->be - f->bs)) + f->bs; // + 0.5;
+ }
+
+ f++;
+ }
+}
+
+static void md_rgb_matrix_config_override(int i) {
+ float ro = 0;
+ float go = 0;
+ float bo = 0;
+
+ float po = (led_animation_orientation) ? (float)g_led_config.point[i].y / 64.f * 100 : (float)g_led_config.point[i].x / 224.f * 100;
+
+ uint8_t highest_active_layer = biton32(layer_state);
+
+ if (led_lighting_mode == LED_MODE_KEYS_ONLY && HAS_FLAGS(g_led_config.flags[i], LED_FLAG_UNDERGLOW)) {
+ // Do not act on this LED
+ } else if (led_lighting_mode == LED_MODE_NON_KEYS_ONLY && !HAS_FLAGS(g_led_config.flags[i], LED_FLAG_UNDERGLOW)) {
+ // Do not act on this LED
+ } else if (led_lighting_mode == LED_MODE_INDICATORS_ONLY) {
+ // Do not act on this LED (Only show indicators)
+ } else {
+ led_instruction_t* led_cur_instruction = led_instructions;
+ while (!led_cur_instruction->end) {
+ // Check if this applies to current layer
+ if ((led_cur_instruction->flags & LED_FLAG_MATCH_LAYER) && (led_cur_instruction->layer != highest_active_layer)) {
+ goto next_iter;
+ }
+
+ // Check if this applies to current index
+ if (led_cur_instruction->flags & LED_FLAG_MATCH_ID) {
+ uint8_t modid = i / 32; // Calculate which id# contains the led bit
+ uint32_t modidbit = 1 << (i % 32); // Calculate the bit within the id#
+ uint32_t* bitfield = &led_cur_instruction->id0 + modid; // Add modid as offset to id0 address. *bitfield is now idX of the led id
+ if (~(*bitfield) & modidbit) { // Check if led bit is not set in idX
+ goto next_iter;
+ }
+ }
+
+ if (led_cur_instruction->flags & LED_FLAG_USE_RGB) {
+ ro = led_cur_instruction->r;
+ go = led_cur_instruction->g;
+ bo = led_cur_instruction->b;
+ } else if (led_cur_instruction->flags & LED_FLAG_USE_PATTERN) {
+ led_run_pattern(led_setups[led_cur_instruction->pattern_id], &ro, &go, &bo, po);
+ } else if (led_cur_instruction->flags & LED_FLAG_USE_ROTATE_PATTERN) {
+ led_run_pattern(led_setups[led_animation_id], &ro, &go, &bo, po);
+ }
+
+ next_iter:
+ led_cur_instruction++;
+ }
+
+ if (ro > 255)
+ ro = 255;
+ else if (ro < 0)
+ ro = 0;
+ if (go > 255)
+ go = 255;
+ else if (go < 0)
+ go = 0;
+ if (bo > 255)
+ bo = 255;
+ else if (bo < 0)
+ bo = 0;
+
+ if (led_animation_breathing) {
+ ro *= breathe_mult;
+ go *= breathe_mult;
+ bo *= breathe_mult;
+ }
+ }
+
+ led_buffer[i].r = (uint8_t)ro;
+ led_buffer[i].g = (uint8_t)go;
+ led_buffer[i].b = (uint8_t)bo;
+}
+
+#endif // USE_MASSDROP_CONFIGURATOR
diff --git a/tmk_core/protocol/arm_atsam/md_rgb_matrix.h b/tmk_core/protocol/arm_atsam/md_rgb_matrix.h
new file mode 100644
index 0000000000..322b0f99d1
--- /dev/null
+++ b/tmk_core/protocol/arm_atsam/md_rgb_matrix.h
@@ -0,0 +1,158 @@
+/*
+Copyright 2018 Massdrop Inc.
+
+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 .
+*/
+
+#ifndef _LED_MATRIX_H_
+#define _LED_MATRIX_H_
+
+#include "quantum.h"
+
+// From keyboard
+#include "config_led.h"
+
+// CS1-CS16 Current Source "Col"
+#define ISSI3733_CS_COUNT 16
+
+// SW1-SW12 Switch "Row"
+#define ISSI3733_SW_COUNT 12
+
+#define ISSI3733_LED_RGB_COUNT ISSI3733_CS_COUNT *ISSI3733_SW_COUNT
+#define ISSI3733_PG0_BYTES ISSI3733_LED_RGB_COUNT / 8 + 1 //+1 for first byte being memory start offset for I2C transfer
+#define ISSI3733_PG1_BYTES ISSI3733_LED_RGB_COUNT + 1 //+1 for first byte being memory start offset for I2C transfer
+#define ISSI3733_PG2_BYTES ISSI3733_LED_RGB_COUNT + 1 //+1 for first byte being memory start offset for I2C transfer
+#define ISSI3733_PG3_BYTES 18 + 1 //+1 for first byte being memory start offset for I2C transfer
+
+#define ISSI3733_PG_ONOFF_BYTES ISSI3733_PG0_BYTES
+#define ISSI3733_PG_OR_BYTES ISSI3733_PG0_BYTES
+#define ISSI3733_PG_SR_BYTES ISSI3733_PG0_BYTES
+#define ISSI3733_PG_PWM_BYTES ISSI3733_PG1_BYTES
+#define ISSI3733_PG_ABM_BYTES ISSI3733_PG2_BYTES
+#define ISSI3733_PG_FN_BYTES ISSI3733_PG3_BYTES
+
+typedef struct issi3733_driver_s {
+ uint8_t addr; // Address of the driver according to wiring "ISSI3733: Table 1 Slave Address"
+ uint8_t onoff[ISSI3733_PG_ONOFF_BYTES]; // PG0 - LED Control Register - LED On/Off Register
+ uint8_t open[ISSI3733_PG_OR_BYTES]; // PG0 - LED Control Register - LED Open Register
+ uint8_t shrt[ISSI3733_PG_SR_BYTES]; // PG0 - LED Control Register - LED Short Register
+ uint8_t pwm[ISSI3733_PG_PWM_BYTES]; // PG1 - PWM Register
+ uint8_t abm[ISSI3733_PG_ABM_BYTES]; // PG2 - Auto Breath Mode Register
+ uint8_t conf[ISSI3733_PG_FN_BYTES]; // PG3 - Function Register
+} issi3733_driver_t;
+
+typedef struct issi3733_rgb_s {
+ uint8_t *r; // Direct access into PWM data
+ uint8_t *g; // Direct access into PWM data
+ uint8_t *b; // Direct access into PWM data
+} issi3733_rgb_t;
+
+typedef struct issi3733_rgb_adr_s {
+ uint8_t drv; // Driver from given list
+ uint8_t cs; // CS
+ uint8_t swr; // SW Red
+ uint8_t swg; // SW Green
+ uint8_t swb; // SW Blue
+} issi3733_rgb_adr_t;
+
+typedef struct issi3733_led_s {
+ uint8_t id; // According to PCB ref
+ issi3733_rgb_t rgb; // PWM settings of R G B
+ issi3733_rgb_adr_t adr; // Hardware addresses
+ float x; // Physical position X
+ float y; // Physical position Y
+ float px; // Physical position X in percent
+ float py; // Physical position Y in percent
+ uint8_t scan; // Key scan code from wiring (set 0xFF if no key)
+} issi3733_led_t;
+
+extern issi3733_driver_t issidrv[ISSI3733_DRIVER_COUNT];
+
+extern uint8_t gcr_desired;
+extern uint8_t gcr_breathe;
+extern uint8_t gcr_actual;
+extern uint8_t gcr_actual_last;
+
+void gcr_compute(void);
+
+void md_rgb_matrix_indicators(void);
+
+/*------------------------- Legacy Lighting Support ------------------------*/
+
+#ifdef USE_MASSDROP_CONFIGURATOR
+
+# define EF_NONE 0x00000000 // No effect
+# define EF_OVER 0x00000001 // Overwrite any previous color information with new
+# define EF_SCR_L 0x00000002 // Scroll left
+# define EF_SCR_R 0x00000004 // Scroll right
+# define EF_SUBTRACT 0x00000008 // Subtract color values
+
+typedef struct led_setup_s {
+ float hs; // Band begin at percent
+ float he; // Band end at percent
+ uint8_t rs; // Red start value
+ uint8_t re; // Red end value
+ uint8_t gs; // Green start value
+ uint8_t ge; // Green end value
+ uint8_t bs; // Blue start value
+ uint8_t be; // Blue end value
+ uint32_t ef; // Animation and color effects
+ uint8_t end; // Set to signal end of the setup
+} led_setup_t;
+
+extern const uint8_t led_setups_count;
+extern void * led_setups[];
+
+// LED Extra Instructions
+# define LED_FLAG_NULL 0x00 // Matching and coloring not used (default)
+# define LED_FLAG_MATCH_ID 0x01 // Match on the ID of the LED (set id#'s to desired bit pattern, first LED is id 1)
+# define LED_FLAG_MATCH_LAYER 0x02 // Match on the current active layer (set layer to desired match layer)
+# define LED_FLAG_USE_RGB 0x10 // Use a specific RGB value (set r, g, b to desired output color values)
+# define LED_FLAG_USE_PATTERN 0x20 // Use a specific pattern ID (set pattern_id to desired output pattern)
+# define LED_FLAG_USE_ROTATE_PATTERN 0x40 // Use pattern the user has cycled to manually
+
+typedef struct led_instruction_s {
+ uint16_t flags; // Bitfield for LED instructions
+ uint32_t id0; // Bitwise id, IDs 0-31
+ uint32_t id1; // Bitwise id, IDs 32-63
+ uint32_t id2; // Bitwise id, IDs 64-95
+ uint32_t id3; // Bitwise id, IDs 96-127
+ uint8_t layer;
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ uint8_t pattern_id;
+ uint8_t end;
+} led_instruction_t;
+
+extern led_instruction_t led_instructions[];
+
+extern uint8_t led_animation_breathing;
+extern uint8_t led_animation_id;
+extern float led_animation_speed;
+extern uint8_t led_lighting_mode;
+extern uint8_t led_enabled;
+extern uint8_t led_animation_breathe_cur;
+extern uint8_t led_animation_direction;
+extern uint8_t breathe_dir;
+
+# define LED_MODE_NORMAL 0 // Must be 0
+# define LED_MODE_KEYS_ONLY 1
+# define LED_MODE_NON_KEYS_ONLY 2
+# define LED_MODE_INDICATORS_ONLY 3
+# define LED_MODE_MAX_INDEX LED_MODE_INDICATORS_ONLY // Must be highest value
+
+#endif // USE_MASSDROP_CONFIGURATOR
+
+#endif //_LED_MATRIX_H_
diff --git a/tmk_core/protocol/arm_atsam/md_rgb_matrix_programs.c b/tmk_core/protocol/arm_atsam/md_rgb_matrix_programs.c
new file mode 100644
index 0000000000..b43008cc5b
--- /dev/null
+++ b/tmk_core/protocol/arm_atsam/md_rgb_matrix_programs.c
@@ -0,0 +1,99 @@
+/*
+Copyright 2018 Massdrop Inc.
+
+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 .
+*/
+
+#ifdef USE_MASSDROP_CONFIGURATOR
+
+# include "md_rgb_matrix.h"
+
+// Teal <-> Salmon
+led_setup_t leds_teal_salmon[] = {
+ {.hs = 0, .he = 33, .rs = 24, .re = 24, .gs = 215, .ge = 215, .bs = 204, .be = 204, .ef = EF_NONE},
+ {.hs = 33, .he = 66, .rs = 24, .re = 255, .gs = 215, .ge = 114, .bs = 204, .be = 118, .ef = EF_NONE},
+ {.hs = 66, .he = 100, .rs = 255, .re = 255, .gs = 114, .ge = 114, .bs = 118, .be = 118, .ef = EF_NONE},
+ {.end = 1},
+};
+
+// Yellow
+led_setup_t leds_yellow[] = {
+ {.hs = 0, .he = 100, .rs = 255, .re = 255, .gs = 255, .ge = 255, .bs = 0, .be = 0, .ef = EF_NONE},
+ {.end = 1},
+};
+
+// Off
+led_setup_t leds_off[] = {
+ {.hs = 0, .he = 100, .rs = 0, .re = 0, .gs = 0, .ge = 0, .bs = 0, .be = 0, .ef = EF_NONE},
+ {.end = 1},
+};
+
+// Red
+led_setup_t leds_red[] = {
+ {.hs = 0, .he = 100, .rs = 255, .re = 255, .gs = 0, .ge = 0, .bs = 0, .be = 0, .ef = EF_NONE},
+ {.end = 1},
+};
+
+// Green
+led_setup_t leds_green[] = {
+ {.hs = 0, .he = 100, .rs = 0, .re = 0, .gs = 255, .ge = 255, .bs = 0, .be = 0, .ef = EF_NONE},
+ {.end = 1},
+};
+
+// Blue
+led_setup_t leds_blue[] = {
+ {.hs = 0, .he = 100, .rs = 0, .re = 0, .gs = 0, .ge = 0, .bs = 255, .be = 255, .ef = EF_NONE},
+ {.end = 1},
+};
+
+// White
+led_setup_t leds_white[] = {
+ {.hs = 0, .he = 100, .rs = 255, .re = 255, .gs = 255, .ge = 255, .bs = 255, .be = 255, .ef = EF_NONE},
+ {.end = 1},
+};
+
+// White with moving red stripe
+led_setup_t leds_white_with_red_stripe[] = {
+ {.hs = 0, .he = 100, .rs = 255, .re = 255, .gs = 255, .ge = 255, .bs = 255, .be = 255, .ef = EF_NONE},
+ {.hs = 0, .he = 15, .rs = 0, .re = 0, .gs = 0, .ge = 255, .bs = 0, .be = 255, .ef = EF_SCR_R | EF_SUBTRACT},
+ {.hs = 15, .he = 30, .rs = 0, .re = 0, .gs = 255, .ge = 0, .bs = 255, .be = 0, .ef = EF_SCR_R | EF_SUBTRACT},
+ {.end = 1},
+};
+
+// Black with moving red stripe
+led_setup_t leds_black_with_red_stripe[] = {
+ {.hs = 0, .he = 15, .rs = 0, .re = 255, .gs = 0, .ge = 0, .bs = 0, .be = 0, .ef = EF_SCR_R},
+ {.hs = 15, .he = 30, .rs = 255, .re = 0, .gs = 0, .ge = 0, .bs = 0, .be = 0, .ef = EF_SCR_R},
+ {.end = 1},
+};
+
+// Rainbow no scrolling
+led_setup_t leds_rainbow_ns[] = {
+ {.hs = 0, .he = 16.67, .rs = 255, .re = 255, .gs = 0, .ge = 255, .bs = 0, .be = 0, .ef = EF_OVER}, {.hs = 16.67, .he = 33.33, .rs = 255, .re = 0, .gs = 255, .ge = 255, .bs = 0, .be = 0, .ef = EF_OVER}, {.hs = 33.33, .he = 50, .rs = 0, .re = 0, .gs = 255, .ge = 255, .bs = 0, .be = 255, .ef = EF_OVER}, {.hs = 50, .he = 66.67, .rs = 0, .re = 0, .gs = 255, .ge = 0, .bs = 255, .be = 255, .ef = EF_OVER}, {.hs = 66.67, .he = 83.33, .rs = 0, .re = 255, .gs = 0, .ge = 0, .bs = 255, .be = 255, .ef = EF_OVER}, {.hs = 83.33, .he = 100, .rs = 255, .re = 255, .gs = 0, .ge = 0, .bs = 255, .be = 0, .ef = EF_OVER}, {.end = 1},
+};
+
+// Rainbow scrolling
+led_setup_t leds_rainbow_s[] = {
+ {.hs = 0, .he = 16.67, .rs = 255, .re = 255, .gs = 0, .ge = 255, .bs = 0, .be = 0, .ef = EF_OVER | EF_SCR_R}, {.hs = 16.67, .he = 33.33, .rs = 255, .re = 0, .gs = 255, .ge = 255, .bs = 0, .be = 0, .ef = EF_OVER | EF_SCR_R}, {.hs = 33.33, .he = 50, .rs = 0, .re = 0, .gs = 255, .ge = 255, .bs = 0, .be = 255, .ef = EF_OVER | EF_SCR_R}, {.hs = 50, .he = 66.67, .rs = 0, .re = 0, .gs = 255, .ge = 0, .bs = 255, .be = 255, .ef = EF_OVER | EF_SCR_R}, {.hs = 66.67, .he = 83.33, .rs = 0, .re = 255, .gs = 0, .ge = 0, .bs = 255, .be = 255, .ef = EF_OVER | EF_SCR_R}, {.hs = 83.33, .he = 100, .rs = 255, .re = 255, .gs = 0, .ge = 0, .bs = 255, .be = 0, .ef = EF_OVER | EF_SCR_R}, {.end = 1},
+};
+
+// Add new LED animations here using one from above as example
+// The last entry must be { .end = 1 }
+// Add the new animation name to the list below following its format
+
+void *led_setups[] = {leds_rainbow_s, leds_rainbow_ns, leds_teal_salmon, leds_yellow, leds_red, leds_green, leds_blue, leds_white, leds_white_with_red_stripe, leds_black_with_red_stripe, leds_off};
+
+const uint8_t led_setups_count = sizeof(led_setups) / sizeof(led_setups[0]);
+
+#endif
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();
}
--
cgit v1.2.3