summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Vagrantfile2
-rw-r--r--build_json.mk12
-rw-r--r--build_keyboard.mk18
-rw-r--r--build_test.mk1
-rw-r--r--common_features.mk28
-rw-r--r--data/schemas/keyboard.jsonschema14
-rw-r--r--docs/_summary.md1
-rw-r--r--docs/breaking_changes.md4
-rw-r--r--docs/chibios_upgrade_instructions.md56
-rw-r--r--docs/config_options.md29
-rw-r--r--docs/custom_quantum_functions.md8
-rw-r--r--docs/feature_debounce_type.md4
-rw-r--r--docs/feature_haptic_feedback.md26
-rw-r--r--docs/feature_oled_driver.md4
-rw-r--r--docs/feature_rgb_matrix.md68
-rw-r--r--docs/feature_split_keyboard.md114
-rw-r--r--docs/feature_st7565.md274
-rw-r--r--drivers/avr/i2c_master.c19
-rw-r--r--drivers/avr/i2c_slave.c29
-rw-r--r--drivers/avr/i2c_slave.h13
-rw-r--r--drivers/avr/serial.c82
-rw-r--r--drivers/avr/serial.h62
-rw-r--r--drivers/awinic/aw20216.c166
-rw-r--r--drivers/awinic/aw20216.h251
-rw-r--r--drivers/chibios/serial.c52
-rw-r--r--drivers/chibios/serial.h62
-rw-r--r--drivers/chibios/serial_usart.c47
-rw-r--r--drivers/chibios/spi_master.c70
-rw-r--r--drivers/chibios/spi_master.h19
-rw-r--r--drivers/haptic/haptic.c71
-rw-r--r--drivers/lcd/st7565.c496
-rw-r--r--drivers/lcd/st7565.h219
-rw-r--r--drivers/oled/oled_driver.c26
-rw-r--r--drivers/oled/oled_driver.h4
-rw-r--r--drivers/serial.h46
-rw-r--r--keyboards/anavi/macropad8/keymaps/default/config.h19
-rw-r--r--keyboards/basekeys/trifecta/config.h4
-rwxr-xr-xkeyboards/bm40hsrgb/config.h4
-rw-r--r--keyboards/bm68rgb/keymaps/peepeetee/config.h2
-rw-r--r--keyboards/boardsource/the_mark/config.h2
-rw-r--r--keyboards/crkbd/keymaps/devdev/config.h14
-rw-r--r--keyboards/crkbd/keymaps/gotham/config.h2
-rw-r--r--keyboards/crkbd/keymaps/kidbrazil/config.h2
-rw-r--r--keyboards/crkbd/keymaps/rpbaptist/config.h2
-rw-r--r--keyboards/crkbd/keymaps/soundmonster/config.h4
-rw-r--r--keyboards/crkbd/readme.md2
-rw-r--r--keyboards/draculad/config.h2
-rw-r--r--keyboards/dztech/dz60rgb/v1/config.h2
-rw-r--r--keyboards/dztech/dz60rgb/v2/config.h2
-rw-r--r--keyboards/dztech/dz60rgb_ansi/v1/config.h2
-rw-r--r--keyboards/dztech/dz60rgb_ansi/v2/config.h2
-rw-r--r--keyboards/dztech/dz60rgb_wkl/v1/config.h2
-rw-r--r--keyboards/dztech/dz60rgb_wkl/v2/config.h2
-rw-r--r--keyboards/dztech/dz65rgb/v1/config.h4
-rw-r--r--keyboards/dztech/dz65rgb/v2/config.h2
-rw-r--r--keyboards/ergodox_ez/config.h2
-rw-r--r--keyboards/ergodox_ez/keymaps/hacker_dvorak/config.h2
-rw-r--r--keyboards/ergodox_infinity/config.h15
-rw-r--r--keyboards/ergodox_infinity/ergodox_infinity.c302
-rw-r--r--keyboards/ergodox_infinity/matrix.c18
-rw-r--r--keyboards/ergodox_infinity/rules.mk7
-rw-r--r--keyboards/geekboards/macropad_v2/config.h4
-rw-r--r--keyboards/geekboards/tester/config.h4
-rw-r--r--keyboards/gmmk/pro/config.h17
-rw-r--r--keyboards/gmmk/pro/halconf.h7
-rw-r--r--keyboards/gmmk/pro/mcuconf.h6
-rw-r--r--keyboards/gmmk/pro/pro.c222
-rw-r--r--keyboards/gmmk/pro/rules.mk2
-rw-r--r--keyboards/handwired/colorlice/config.h2
-rw-r--r--keyboards/handwired/frankie_macropad/keymaps/default/config.h19
-rw-r--r--keyboards/handwired/freoduo/rules.mk4
-rw-r--r--keyboards/handwired/hnah40rgb/config.h2
-rw-r--r--keyboards/handwired/p65rgb/config.h2
-rw-r--r--keyboards/helix/rev2/keymaps/default/rules.mk2
-rw-r--r--keyboards/helix/rev3_4rows/config.h2
-rw-r--r--keyboards/helix/rev3_5rows/config.h2
-rw-r--r--keyboards/hs60/v1/config.h2
-rw-r--r--keyboards/kbdfans/bella/rgb/config.h2
-rw-r--r--keyboards/kbdfans/bella/rgb_iso/config.h2
-rw-r--r--keyboards/kbdfans/kbd67/mkiirgb/v1/config.h4
-rw-r--r--keyboards/kbdfans/kbd67/mkiirgb/v2/config.h4
-rw-r--r--keyboards/kbdfans/kbd67/rev1/keymaps/default/config.h2
-rw-r--r--keyboards/kbdfans/kbdmini/config.h2
-rwxr-xr-xkeyboards/kbdfans/maja/config.h4
-rw-r--r--keyboards/keebio/iris/rev2/rules.mk2
-rw-r--r--keyboards/keebio/iris/rev3/rules.mk1
-rw-r--r--keyboards/keebio/iris/rev4/rules.mk2
-rw-r--r--keyboards/keebio/quefrency/rules.mk1
-rw-r--r--keyboards/keebio/viterbi/rev2/rules.mk2
-rw-r--r--keyboards/keebio/viterbi/rules.mk8
-rw-r--r--keyboards/latin17rgb/config.h32
-rw-r--r--keyboards/latin60rgb/config.h31
-rw-r--r--keyboards/le_chiffre/config.h2
-rw-r--r--keyboards/marksard/rhymestone/rev1/config.h2
-rw-r--r--keyboards/massdrop/alt/keymaps/pregame/config.h4
-rw-r--r--keyboards/massdrop/alt/keymaps/urbanvanilla/config.h2
-rw-r--r--keyboards/massdrop/ctrl/keymaps/endgame/config.h2
-rw-r--r--keyboards/massdrop/ctrl/keymaps/matthewrobo/config.h2
-rw-r--r--keyboards/mechlovin/adelais/rgb_led/rev1/config.h4
-rw-r--r--keyboards/mechlovin/adelais/rgb_led/rev2/config.h6
-rw-r--r--keyboards/mechlovin/delphine/rgb_led/config.h4
-rw-r--r--keyboards/mechlovin/hannah60rgb/rev1/config.h4
-rw-r--r--keyboards/mechlovin/hannah60rgb/rev2/config.h4
-rw-r--r--keyboards/mechlovin/infinity87/rgb_rev1/config.h2
-rw-r--r--keyboards/melgeek/mj61/config.h2
-rw-r--r--keyboards/melgeek/mj63/config.h2
-rw-r--r--keyboards/melgeek/mj64/config.h2
-rw-r--r--keyboards/melgeek/mj65/config.h2
-rw-r--r--keyboards/melgeek/mojo75/config.h2
-rw-r--r--keyboards/melgeek/z70ultra/config.h2
-rw-r--r--keyboards/miller/gm862/config.h4
-rw-r--r--keyboards/monstargear/xo87/rgb/config.h2
-rw-r--r--keyboards/moonlander/config.h2
-rw-r--r--keyboards/mt84/keymaps/default/config.h19
-rw-r--r--keyboards/naked48/keymaps/salicylic/config.h3
-rw-r--r--keyboards/opendeck/32/rev1/config.h2
-rw-r--r--keyboards/percent/canoe_gen2/config.h2
-rw-r--r--keyboards/phase_studio/titan65/config.h2
-rw-r--r--keyboards/planck/ez/config.h2
-rw-r--r--keyboards/planck/rev6/config.h2
-rw-r--r--keyboards/setta21/keymaps/salicylic/config.h3
-rw-r--r--keyboards/sofle/keymaps/devdev/config.h44
-rw-r--r--keyboards/sofle/keymaps/killmaster/config.h64
-rw-r--r--keyboards/sofle/keymaps/killmaster/keymap.c403
-rw-r--r--keyboards/sofle/keymaps/killmaster/readme.md19
-rw-r--r--keyboards/sofle/keymaps/killmaster/rules.mk4
-rw-r--r--keyboards/sofle/keymaps/rgb_default/config.h44
-rw-r--r--keyboards/sofle/rev1/readme.md27
-rw-r--r--keyboards/sofle/rev1/rev1.c86
-rw-r--r--keyboards/terrazzo/config.h4
-rw-r--r--keyboards/tkc/portico/config.h2
-rw-r--r--keyboards/tokyokeyboard/tokyo60/config.h (renamed from keyboards/tokyo60/config.h)0
-rw-r--r--keyboards/tokyokeyboard/tokyo60/info.json (renamed from keyboards/tokyo60/info.json)0
-rw-r--r--keyboards/tokyokeyboard/tokyo60/keymaps/default/config.h (renamed from keyboards/tokyo60/keymaps/default/config.h)0
-rw-r--r--keyboards/tokyokeyboard/tokyo60/keymaps/default/keymap.c (renamed from keyboards/tokyo60/keymaps/default/keymap.c)0
-rw-r--r--keyboards/tokyokeyboard/tokyo60/keymaps/swappedBottomRow/config.h (renamed from keyboards/tokyo60/keymaps/swappedBottomRow/config.h)0
-rw-r--r--keyboards/tokyokeyboard/tokyo60/keymaps/swappedBottomRow/keymap.c (renamed from keyboards/tokyo60/keymaps/swappedBottomRow/keymap.c)0
-rw-r--r--keyboards/tokyokeyboard/tokyo60/keymaps/via/keymap.c (renamed from keyboards/tokyo60/keymaps/via/keymap.c)0
-rw-r--r--keyboards/tokyokeyboard/tokyo60/keymaps/via/rules.mk (renamed from keyboards/tokyo60/keymaps/via/rules.mk)0
-rw-r--r--keyboards/tokyokeyboard/tokyo60/readme.md (renamed from keyboards/tokyo60/readme.md)8
-rw-r--r--keyboards/tokyokeyboard/tokyo60/rules.mk (renamed from keyboards/tokyo60/rules.mk)0
-rw-r--r--keyboards/tokyokeyboard/tokyo60/tokyo60.c (renamed from keyboards/tokyo60/tokyo60.c)0
-rw-r--r--keyboards/tokyokeyboard/tokyo60/tokyo60.h (renamed from keyboards/tokyo60/tokyo60.h)0
-rw-r--r--keyboards/whitefox/config.h14
-rw-r--r--keyboards/whitefox/rules.mk8
-rw-r--r--keyboards/whitefox/whitefox.c76
-rw-r--r--keyboards/xbows/nature/config.h2
-rw-r--r--keyboards/xbows/woody/config.h6
-rw-r--r--keyboards/yncognito/batpad/config.h14
-rw-r--r--layouts/community/ortho_4x12/bocaj/config.h2
-rw-r--r--layouts/community/ortho_4x12/drashna/config.h2
-rw-r--r--layouts/community/split_3x6_3/drashna/config.h2
m---------lib/chibios0
m---------lib/chibios-contrib0
-rw-r--r--lib/python/qmk/info.py3
-rw-r--r--platforms/chibios/IC_TEENSY_4_1/board/board.mk1
-rw-r--r--platforms/chibios/IC_TEENSY_4_1/rules.mk1
-rw-r--r--quantum/crc.c59
-rw-r--r--quantum/crc.h44
-rw-r--r--quantum/debounce.h2
-rw-r--r--quantum/debounce/asym_eager_defer_pk.c171
-rw-r--r--quantum/debounce/none.c31
-rw-r--r--quantum/debounce/sym_defer_g.c26
-rw-r--r--quantum/debounce/sym_defer_pk.c67
-rw-r--r--quantum/debounce/sym_eager_pk.c72
-rw-r--r--quantum/debounce/sym_eager_pr.c76
-rw-r--r--quantum/debounce/tests/asym_eager_defer_pk_tests.cpp374
-rw-r--r--quantum/debounce/tests/debounce_test_common.cpp229
-rw-r--r--quantum/debounce/tests/debounce_test_common.h83
-rw-r--r--quantum/debounce/tests/rules.mk44
-rw-r--r--quantum/debounce/tests/sym_defer_g_tests.cpp223
-rw-r--r--quantum/debounce/tests/sym_defer_pk_tests.cpp225
-rw-r--r--quantum/debounce/tests/sym_eager_pk_tests.cpp237
-rw-r--r--quantum/debounce/tests/sym_eager_pr_tests.cpp280
-rw-r--r--quantum/debounce/tests/testlist.mk6
-rw-r--r--quantum/led_matrix.c34
-rw-r--r--quantum/matrix.c79
-rw-r--r--quantum/quantum.h4
-rw-r--r--quantum/rgb_matrix.c34
-rw-r--r--quantum/rgb_matrix.h2
-rw-r--r--quantum/rgb_matrix_animations/jellybean_raindrops_anim.h2
-rw-r--r--quantum/rgb_matrix_drivers.c16
-rw-r--r--quantum/serial_link/system/serial_link.c22
-rw-r--r--quantum/split_common/matrix.c83
-rw-r--r--quantum/split_common/post_config.h9
-rw-r--r--quantum/split_common/transaction_id_define.h94
-rw-r--r--quantum/split_common/transactions.c670
-rw-r--r--quantum/split_common/transactions.h54
-rw-r--r--quantum/split_common/transport.c484
-rw-r--r--quantum/split_common/transport.h165
-rw-r--r--testlist.mk1
-rw-r--r--tmk_core/avr.mk2
-rw-r--r--tmk_core/chibios.mk6
-rw-r--r--tmk_core/common/arm_atsam/_timer.h19
-rw-r--r--tmk_core/common/avr/_timer.h19
-rw-r--r--tmk_core/common/avr/gpio.h15
-rw-r--r--tmk_core/common/chibios/_timer.h19
-rw-r--r--tmk_core/common/chibios/bootloader.c2
-rw-r--r--tmk_core/common/chibios/gpio.h16
-rw-r--r--tmk_core/common/host.c14
-rw-r--r--tmk_core/common/keyboard.c24
-rw-r--r--tmk_core/common/sync_timer.c2
-rw-r--r--tmk_core/common/sync_timer.h2
-rw-r--r--tmk_core/common/timer.h24
-rw-r--r--tmk_core/protocol/chibios/usb_main.c34
-rw-r--r--tmk_core/protocol/lufa/lufa.c34
-rw-r--r--tmk_core/protocol/usb_descriptor.c2
-rw-r--r--tmk_core/protocol/vusb/vusb.c3
-rw-r--r--tmk_core/rules.mk2
-rw-r--r--users/bcat/config.h2
-rw-r--r--users/bocaj/config.h2
-rw-r--r--users/curry/config.h2
-rw-r--r--users/drashna/config.h2
-rw-r--r--users/spidey3/config.h4
-rw-r--r--users/tominabox1/config.h2
-rwxr-xr-xutil/update_chibios_mirror.sh55
216 files changed, 7194 insertions, 1263 deletions
diff --git a/Vagrantfile b/Vagrantfile
index adb93a3cee..8125b05890 100644
--- a/Vagrantfile
+++ b/Vagrantfile
@@ -6,7 +6,7 @@ Vagrant.configure(2) do |config|
config.vm.define "qmk_firmware"
# VMware/Virtualbox ( and also Hyperv/Parallels) 64 bit
- config.vm.box = "generic/debian9"
+ config.vm.box = "generic/debian10"
config.vm.synced_folder '.', '/vagrant'
diff --git a/build_json.mk b/build_json.mk
index 8822be6a12..28659f2603 100644
--- a/build_json.mk
+++ b/build_json.mk
@@ -1,22 +1,22 @@
# Look for a json keymap file
ifneq ("$(wildcard $(MAIN_KEYMAP_PATH_5)/keymap.json)","")
- KEYMAP_C := $(KEYBOARD_OUTPUT)/src/keymap.c
+ KEYMAP_C := $(KEYMAP_OUTPUT)/keymap.c
KEYMAP_JSON := $(MAIN_KEYMAP_PATH_5)/keymap.json
KEYMAP_PATH := $(MAIN_KEYMAP_PATH_5)
else ifneq ("$(wildcard $(MAIN_KEYMAP_PATH_4)/keymap.json)","")
- KEYMAP_C := $(KEYBOARD_OUTPUT)/src/keymap.c
+ KEYMAP_C := $(KEYMAP_OUTPUT)/keymap.c
KEYMAP_JSON := $(MAIN_KEYMAP_PATH_4)/keymap.json
KEYMAP_PATH := $(MAIN_KEYMAP_PATH_4)
else ifneq ("$(wildcard $(MAIN_KEYMAP_PATH_3)/keymap.json)","")
- KEYMAP_C := $(KEYBOARD_OUTPUT)/src/keymap.c
+ KEYMAP_C := $(KEYMAP_OUTPUT)/keymap.c
KEYMAP_JSON := $(MAIN_KEYMAP_PATH_3)/keymap.json
KEYMAP_PATH := $(MAIN_KEYMAP_PATH_3)
else ifneq ("$(wildcard $(MAIN_KEYMAP_PATH_2)/keymap.json)","")
- KEYMAP_C := $(KEYBOARD_OUTPUT)/src/keymap.c
+ KEYMAP_C := $(KEYMAP_OUTPUT)/keymap.c
KEYMAP_JSON := $(MAIN_KEYMAP_PATH_2)/keymap.json
KEYMAP_PATH := $(MAIN_KEYMAP_PATH_2)
else ifneq ("$(wildcard $(MAIN_KEYMAP_PATH_1)/keymap.json)","")
- KEYMAP_C := $(KEYBOARD_OUTPUT)/src/keymap.c
+ KEYMAP_C := $(KEYMAP_OUTPUT)/keymap.c
KEYMAP_JSON := $(MAIN_KEYMAP_PATH_1)/keymap.json
KEYMAP_PATH := $(MAIN_KEYMAP_PATH_1)
endif
@@ -27,5 +27,5 @@ ifneq ("$(wildcard $(KEYMAP_PATH))", "")
endif
# Generate the keymap.c
-$(KEYBOARD_OUTPUT)/src/keymap.c: $(KEYMAP_JSON)
+$(KEYMAP_C): $(KEYMAP_JSON)
$(QMK_BIN) json2c --quiet --output $(KEYMAP_C) $(KEYMAP_JSON)
diff --git a/build_keyboard.mk b/build_keyboard.mk
index 91a6c23b71..4c4ff3b5fd 100644
--- a/build_keyboard.mk
+++ b/build_keyboard.mk
@@ -103,6 +103,15 @@ MAIN_KEYMAP_PATH_5 := $(KEYBOARD_PATH_5)/keymaps/$(KEYMAP)
INFO_RULES_MK = $(shell $(QMK_BIN) generate-rules-mk --quiet --escape --keyboard $(KEYBOARD) --output $(KEYBOARD_OUTPUT)/src/rules.mk)
include $(INFO_RULES_MK)
+ifneq ($(FORCE_LAYOUT),)
+ TARGET := $(TARGET)_$(FORCE_LAYOUT)
+endif
+
+# Object files and generated keymap directory
+# To put object files in current directory, use a dot (.), do NOT make
+# this an empty or blank macro!
+KEYMAP_OUTPUT := $(BUILD_DIR)/obj_$(TARGET)
+
# Check for keymap.json first, so we can regenerate keymap.c
include build_json.mk
@@ -145,10 +154,6 @@ ifeq ($(strip $(CONVERT_TO_PROTON_C)), yes)
include platforms/chibios/QMK_PROTON_C/convert_to_proton_c.mk
endif
-ifneq ($(FORCE_LAYOUT),)
- TARGET := $(TARGET)_$(FORCE_LAYOUT)
-endif
-
include quantum/mcu_selection.mk
# Find all the C source files to be compiled in subfolders.
@@ -327,11 +332,6 @@ endif
# Disable features that a keyboard doesn't support
-include disable_features.mk
-# Object files directory
-# To put object files in current directory, use a dot (.), do NOT make
-# this an empty or blank macro!
-KEYMAP_OUTPUT := $(BUILD_DIR)/obj_$(TARGET)
-
ifneq ("$(wildcard $(KEYMAP_PATH)/config.h)","")
CONFIG_H += $(KEYMAP_PATH)/config.h
endif
diff --git a/build_test.mk b/build_test.mk
index 77c4265f93..5171c58c36 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)/debounce/tests/rules.mk
include $(QUANTUM_PATH)/sequencer/tests/rules.mk
include $(QUANTUM_PATH)/serial_link/tests/rules.mk
ifneq ($(filter $(FULL_TESTS),$(TEST)),)
diff --git a/common_features.mk b/common_features.mk
index 1a9fd46b55..9c6fc9cdf8 100644
--- a/common_features.mk
+++ b/common_features.mk
@@ -244,7 +244,7 @@ endif
endif
RGB_MATRIX_ENABLE ?= no
-VALID_RGB_MATRIX_TYPES := IS31FL3731 IS31FL3733 IS31FL3737 IS31FL3741 WS2812 custom
+VALID_RGB_MATRIX_TYPES := AW20216 IS31FL3731 IS31FL3733 IS31FL3737 IS31FL3741 WS2812 custom
ifeq ($(strip $(RGB_MATRIX_ENABLE)), yes)
ifeq ($(filter $(RGB_MATRIX_DRIVER),$(VALID_RGB_MATRIX_TYPES)),)
@@ -261,6 +261,13 @@ endif
CIE1931_CURVE := yes
RGB_KEYCODES_ENABLE := yes
+ ifeq ($(strip $(RGB_MATRIX_DRIVER)), AW20216)
+ OPT_DEFS += -DAW20216 -DSTM32_SPI -DHAL_USE_SPI=TRUE
+ COMMON_VPATH += $(DRIVER_PATH)/awinic
+ SRC += aw20216.c
+ QUANTUM_LIB_SRC += spi_master.c
+ endif
+
ifeq ($(strip $(RGB_MATRIX_DRIVER)), IS31FL3731)
OPT_DEFS += -DIS31FL3731 -DSTM32_I2C -DHAL_USE_I2C=TRUE
COMMON_VPATH += $(DRIVER_PATH)/issi
@@ -529,7 +536,11 @@ ifeq ($(strip $(SPLIT_KEYBOARD)), yes)
# Determine which (if any) transport files are required
ifneq ($(strip $(SPLIT_TRANSPORT)), custom)
- QUANTUM_LIB_SRC += $(QUANTUM_DIR)/split_common/transport.c
+ QUANTUM_SRC += $(QUANTUM_DIR)/split_common/transport.c \
+ $(QUANTUM_DIR)/split_common/transactions.c
+
+ OPT_DEFS += -DSPLIT_COMMON_TRANSACTIONS
+
# 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)
@@ -550,6 +561,11 @@ ifeq ($(strip $(SPLIT_KEYBOARD)), yes)
COMMON_VPATH += $(QUANTUM_PATH)/split_common
endif
+ifeq ($(strip $(CRC_ENABLE)), yes)
+ OPT_DEFS += -DCRC_ENABLE
+ QUANTUM_LIB_SRC += crc.c
+endif
+
HAPTIC_ENABLE ?= no
ifneq ($(strip $(HAPTIC_ENABLE)),no)
COMMON_VPATH += $(DRIVER_PATH)/haptic
@@ -580,6 +596,14 @@ ifeq ($(strip $(OLED_DRIVER_ENABLE)), yes)
SRC += oled_driver.c
endif
+ifeq ($(strip $(ST7565_ENABLE)), yes)
+ OPT_DEFS += -DST7565_ENABLE
+ COMMON_VPATH += $(DRIVER_PATH)/oled # For glcdfont.h
+ COMMON_VPATH += $(DRIVER_PATH)/lcd
+ QUANTUM_LIB_SRC += spi_master.c
+ SRC += st7565.c
+endif
+
include $(DRIVER_PATH)/qwiic/qwiic.mk
ifeq ($(strip $(UCIS_ENABLE)), yes)
diff --git a/data/schemas/keyboard.jsonschema b/data/schemas/keyboard.jsonschema
index c335f49d52..177bb0a961 100644
--- a/data/schemas/keyboard.jsonschema
+++ b/data/schemas/keyboard.jsonschema
@@ -180,6 +180,10 @@
"pattern": "^[A-K]\\d{1,2}$"
},
{
+ "type": "string",
+ "pattern": "^LINE_PIN\\d{1,2}$"
+ },
+ {
"type": "number",
"multipleOf": 1
},
@@ -199,6 +203,10 @@
"pattern": "^[A-K]\\d{1,2}$"
},
{
+ "type": "string",
+ "pattern": "^LINE_PIN\\d{1,2}$"
+ },
+ {
"type": "number",
"multipleOf": 1
},
@@ -217,6 +225,10 @@
"pattern": "^[A-K]\\d{1,2}$"
},
{
+ "type": "string",
+ "pattern": "^LINE_PIN\\d{1,2}$"
+ },
+ {
"type": "number",
"multipleOf": 1
},
@@ -261,7 +273,7 @@
},
"pin": {
"type": "string",
- "pattern": "^[A-K]\\d{1,2}$"
+ "pattern": "^([A-K]\\d{1,2}|LINE_PIN\\d{1,2})$"
},
"saturation_steps": {
"type": "number",
diff --git a/docs/_summary.md b/docs/_summary.md
index 9798ef5127..4141e01e77 100644
--- a/docs/_summary.md
+++ b/docs/_summary.md
@@ -93,6 +93,7 @@
* Hardware Features
* Displays
* [HD44780 LCD Controller](feature_hd44780.md)
+ * [ST7565 LCD Driver](feature_st7565.md)
* [OLED Driver](feature_oled_driver.md)
* Lighting
* [Backlight](feature_backlight.md)
diff --git a/docs/breaking_changes.md b/docs/breaking_changes.md
index b0d56a81bd..a1a56bd457 100644
--- a/docs/breaking_changes.md
+++ b/docs/breaking_changes.md
@@ -100,3 +100,7 @@ This happens immediately after the previous `develop` branch is merged.
* [ ] `git pull --ff-only`
* [ ] `git merge --no-ff develop`
* [ ] `git push upstream master`
+
+## Post-merge operations
+
+* (Optional) [update ChibiOS + ChibiOS-Contrib on `develop`](chibios_upgrade_instructions.md)
diff --git a/docs/chibios_upgrade_instructions.md b/docs/chibios_upgrade_instructions.md
new file mode 100644
index 0000000000..40c2faafcf
--- /dev/null
+++ b/docs/chibios_upgrade_instructions.md
@@ -0,0 +1,56 @@
+# ChibiOS Upgrade Procedure
+
+ChibiOS and ChibiOS-Contrib need to be updated in tandem -- the latter has a branch tied to the ChibiOS version in use and should not be mixed with different versions.
+
+## Getting ChibiOS
+
+* `svn` Initialisation:
+ * Only needed to be done once
+ * You might need to separately install `git-svn` package in your OS's package manager
+ * `git svn init --stdlayout --prefix='svn/' http://svn.osdn.net/svnroot/chibios/`
+ * `git remote add qmk git@github.com:qmk/ChibiOS.git`
+* Updating:
+ * `git svn fetch`
+ * First time around this will take several hours
+ * Subsequent updates will be incremental only
+* Tagging example (work out which version first!):
+ * `git tag -a ver20.3.3 -m ver20.3.3 svn/tags/ver20.3.3`
+ * `git push qmk ver20.3.3`
+ * `git tag -a breaking_YYYY_qN -m breaking_YYYY_qN svn/tags/ver20.3.3`
+ * `git push qmk breaking_YYYY_qN`
+
+## Getting ChibiOS-Contrib
+
+* `git` Initialisation:
+ * `git clone git@github.com:qmk/ChibiOS-Contrib`
+ * `git remote add upstream https://github.com/ChibiOS/ChibiOS-Contrib`
+ * `git checkout -b chibios-20.3.x upstream/chibios-20.3.x`
+* Updating:
+ * `git fetch --all --tags --prune`
+ * `git checkout chibios-20.3.x`
+ * `git pull --ff-only`
+ * `git push origin chibios-20.3.x`
+ * `git tag -a breaking_YYYY_qN -m breaking_YYYY_qN chibios-20.3.x`
+ * `git push origin breaking_YYYY_qN`
+
+## Updating submodules
+
+* Update the submodules
+ * `cd $QMK_FIRMWARE`
+ * `git checkout develop`
+ * `git pull --ff-only`
+ * `git checkout -b chibios-version-bump`
+ * `cd lib/chibios`
+ * `git fetch --all --tags --prune`
+ * `git checkout breaking_YYYY_qN`
+ * `cd ../chibios-contrib`
+ * `git fetch --all --tags --prune`
+ * `git checkout breaking_YYYY_qN`
+* Build everything
+ * `cd $QMK_FIRMWARE`
+ * `qmk multibuild -j4`
+ * Make sure there are no errors
+* Push to the repo
+ * `git commit -am 'Update ChibiOS to XXXXXXXXX'`
+ * `git push --set-upstream origin chibios-version-bump`
+* Make a PR to qmk_firmware with the new branch \ No newline at end of file
diff --git a/docs/config_options.md b/docs/config_options.md
index d0f0b316e0..980195ac68 100644
--- a/docs/config_options.md
+++ b/docs/config_options.md
@@ -51,8 +51,10 @@ This is a C header file that is one of the first things included, and will persi
* the number of columns in your keyboard's matrix
* `#define MATRIX_ROW_PINS { D0, D5, B5, B6 }`
* pins of the rows, from top to bottom
+ * may be omitted by the keyboard designer if matrix reads are handled in an alternate manner. See [low-level matrix overrides](custom_quantum_functions.md?id=low-level-matrix-overrides) for more information.
* `#define MATRIX_COL_PINS { F1, F0, B0, C7, F4, F5, F6, F7, D4, D6, B4, D7 }`
* pins of the columns, from left to right
+ * may be omitted by the keyboard designer if matrix reads are handled in an alternate manner. See [low-level matrix overrides](custom_quantum_functions.md?id=low-level-matrix-overrides) for more information.
* `#define MATRIX_IO_DELAY 30`
* the delay in microseconds when between changing matrix pin state and reading values
* `#define UNUSED_PINS { D1, D2, D3, B1, B2, B3 }`
@@ -272,7 +274,7 @@ There are a few different ways to set handedness for split keyboards (listed in
### Other Options
* `#define USE_I2C`
- * For using I2C instead of Serial (defaults to serial)
+ * For using I2C instead of Serial (default is serial; serial transport is supported on ARM -- I2C is AVR-only)
* `#define SOFT_SERIAL_PIN D0`
* When using serial, define this. `D0` or `D1`,`D2`,`D3`,`E6`.
@@ -280,6 +282,7 @@ There are a few different ways to set handedness for split keyboards (listed in
* `#define MATRIX_ROW_PINS_RIGHT { <row pins> }`
* `#define MATRIX_COL_PINS_RIGHT { <col pins> }`
* If you want to specify a different pinout for the right half than the left half, you can define `MATRIX_ROW_PINS_RIGHT`/`MATRIX_COL_PINS_RIGHT`. Currently, the size of `MATRIX_ROW_PINS` must be the same as `MATRIX_ROW_PINS_RIGHT` and likewise for the definition of columns.
+ * may be omitted by the keyboard designer if matrix reads are handled in an alternate manner. See [low-level matrix overrides](custom_quantum_functions.md?id=low-level-matrix-overrides) for more information.
* `#define DIRECT_PINS_RIGHT { { F1, F0, B0, C7 }, { F4, F5, F6, F7 } }`
* If you want to specify a different direct pinout for the right half than the left half, you can define `DIRECT_PINS_RIGHT`. Currently, the size of `DIRECT_PINS` must be the same as `DIRECT_PINS_RIGHT`.
@@ -300,7 +303,7 @@ There are a few different ways to set handedness for split keyboards (listed in
* `#define SPLIT_USB_DETECT`
* Detect (with timeout) USB connection when delegating master/slave
* Default behavior for ARM
- * Required for AVR Teensy
+ * Required for AVR Teensy (without hardware mods)
* `#define SPLIT_USB_TIMEOUT 2000`
* Maximum timeout when detecting master/slave when using `SPLIT_USB_DETECT`
@@ -308,6 +311,28 @@ There are a few different ways to set handedness for split keyboards (listed in
* `#define SPLIT_USB_TIMEOUT_POLL 10`
* Poll frequency when detecting master/slave when using `SPLIT_USB_DETECT`
+* `#define FORCED_SYNC_THROTTLE_MS 100`
+ * Deadline for synchronizing data from master to slave when using the QMK-provided split transport.
+
+* `#define SPLIT_TRANSPORT_MIRROR`
+ * Mirrors the master-side matrix on the slave when using the QMK-provided split transport.
+
+* `#define SPLIT_LAYER_STATE_ENABLE`
+ * Ensures the current layer state is available on the slave when using the QMK-provided split transport.
+
+* `#define SPLIT_LED_STATE_ENABLE`
+ * Ensures the current host indicator state (caps/num/scroll) is available on the slave when using the QMK-provided split transport.
+
+* `#define SPLIT_MODS_ENABLE`
+ * Ensures the current modifier state (normal, weak, and oneshot) is available on the slave when using the QMK-provided split transport.
+
+* `#define SPLIT_WPM_ENABLE`
+ * Ensures the current WPM is available on the slave when using the QMK-provided split transport.
+
+* `#define SPLIT_TRANSACTION_IDS_KB .....`
+* `#define SPLIT_TRANSACTION_IDS_USER .....`
+ * Allows for custom data sync with the slave when using the QMK-provided split transport. See [custom data sync between sides](feature_split_keyboard.md#custom-data-sync) for more information.
+
# The `rules.mk` File
This is a [make](https://www.gnu.org/software/make/manual/make.html) file that is included by the top-level `Makefile`. It is used to set some information about the MCU that we will be compiling for as well as enabling and disabling certain features.
diff --git a/docs/custom_quantum_functions.md b/docs/custom_quantum_functions.md
index 694b421e79..30c637bb49 100644
--- a/docs/custom_quantum_functions.md
+++ b/docs/custom_quantum_functions.md
@@ -144,6 +144,14 @@ This is useful for setting up stuff that you may need elsewhere, but isn't hardw
* Keyboard/Revision: `void matrix_init_kb(void)`
* Keymap: `void matrix_init_user(void)`
+### Low-level Matrix Overrides Function Documentation :id=low-level-matrix-overrides
+
+* GPIO pin initialisation: `void matrix_init_pins(void)`
+ * This needs to perform the low-level initialisation of all row and column pins. By default this will initialise the input/output state of each of the GPIO pins listed in `MATRIX_ROW_PINS` and `MATRIX_COL_PINS`, based on whether or not the keyboard is set up for `ROW2COL`, `COL2ROW`, or `DIRECT_PINS`. Should the keyboard designer override this function, no initialisation of pin state will occur within QMK itself, instead deferring to the keyboard's override.
+* `COL2ROW`-based row reads: `void matrix_read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)`
+* `ROW2COL`-based column reads: `void matrix_read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)`
+* `DIRECT_PINS`-based reads: `void matrix_read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)`
+ * These three functions need to perform the low-level retrieval of matrix state of relevant input pins, based on the matrix type. Only one of the functions should be implemented, if needed. By default this will iterate through `MATRIX_ROW_PINS` and `MATRIX_COL_PINS`, configuring the inputs and outputs based on whether or not the keyboard is set up for `ROW2COL`, `COL2ROW`, or `DIRECT_PINS`. Should the keyboard designer override this function, no manipulation of matrix GPIO pin state will occur within QMK itself, instead deferring to the keyboard's override.
## Keyboard Post Initialization code
diff --git a/docs/feature_debounce_type.md b/docs/feature_debounce_type.md
index 3ad74224c1..306185fe83 100644
--- a/docs/feature_debounce_type.md
+++ b/docs/feature_debounce_type.md
@@ -121,16 +121,16 @@ DEBOUNCE_TYPE = <name of algorithm>
Where name of algorithm is one of:
* ```sym_defer_g``` - debouncing per keyboard. On any state change, a global timer is set. When ```DEBOUNCE``` milliseconds of no changes has occurred, all input changes are pushed.
* This is the current default algorithm. This is the highest performance algorithm with lowest memory usage, and it's also noise-resistant.
-* ```sym_eager_pr``` - debouncing per row. On any state change, response is immediate, followed by locking the row ```DEBOUNCE``` milliseconds of no further input for that row.
+* ```sym_eager_pr``` - debouncing per row. On any state change, response is immediate, followed by locking the row ```DEBOUNCE``` milliseconds of no further input for that row.
For use in keyboards where refreshing ```NUM_KEYS``` 8-bit counters is computationally expensive / low scan rate, and fingers usually only hit one row at a time. This could be
appropriate for the ErgoDox models; the matrix is rotated 90°, and hence its "rows" are really columns, and each finger only hits a single "row" at a time in normal use.
* ```sym_eager_pk``` - debouncing per key. On any state change, response is immediate, followed by ```DEBOUNCE``` milliseconds of no further input for that key
* ```sym_defer_pk``` - debouncing per key. On any state change, a per-key timer is set. When ```DEBOUNCE``` milliseconds of no changes have occurred on that key, the key status change is pushed.
+* ```asym_eager_defer_pk``` - debouncing per key. On a key-down state change, response is immediate, followed by ```DEBOUNCE``` milliseconds of no further input for that key. On a key-up state change, a per-key timer is set. When ```DEBOUNCE``` milliseconds of no changes have occurred on that key, the key-up status change is pushed.
### A couple algorithms that could be implemented in the future:
* ```sym_defer_pr```
* ```sym_eager_g```
-* ```asym_eager_defer_pk```
### Use your own debouncing code
You have the option to implement you own debouncing algorithm. To do this:
diff --git a/docs/feature_haptic_feedback.md b/docs/feature_haptic_feedback.md
index a092e784c7..469c9c7981 100644
--- a/docs/feature_haptic_feedback.md
+++ b/docs/feature_haptic_feedback.md
@@ -162,4 +162,28 @@ This will set what sequence HPT_RST will set as the active mode. If not defined,
### DRV2605L Continuous Haptic Mode
-This mode sets continuous haptic feedback with the option to increase or decrease strength.
+This mode sets continuous haptic feedback with the option to increase or decrease strength.
+
+## Haptic Key Exclusion
+The Haptic Exclusion is implemented as `__attribute__((weak)) bool get_haptic_enabled_key(uint16_t keycode, keyrecord_t *record)` in haptic.c. This allows a re-definition at the required level with the specific requirement / exclusion.
+
+### NO_HAPTIC_MOD
+With the entry of `#define NO_HAPTIC_MOD` in config.h, modifiers from Left Control to Right GUI will not trigger a feedback. This also includes modifiers in a Mod Tap configuration.
+
+### NO_HAPTIC_FN
+With the entry of `#define NO_HAPTIC_FN` in config.h, layer keys will not rigger a feedback.
+
+### NO_HAPTIC_ALPHA
+With the entry of `#define NO_HAPTIC_ALPHA` in config.h, none of the alpha keys (A ... Z) will trigger a feedback.
+
+### NO_HAPTIC_PUNCTUATION
+With the entry of `#define NO_HAPTIC_PUNCTUATION` in config.h, none of the following keys will trigger a feedback: Enter, ESC, Backspace, Space, Minus, Equal, Left Bracket, Right Bracket, Backslash, Non-US Hash, Semicolon, Quote, Grave, Comma, Slash, Dot, Non-US Backslash.
+
+### NO_HAPTIC_LOCKKEYS
+With the entry of `#define NO_HAPTIC_LOCKKEYS` in config.h, none of the following keys will trigger a feedback: Caps Lock, Scroll Lock, Num Lock.
+
+### NO_HAPTIC_NAV
+With the entry of `#define NO_HAPTIC_NAV` in config.h, none of the following keys will trigger a feedback: Print Screen, Pause, Insert, Delete, Page Down, Page Up, Left Arrow, Up Arrow, Right Arrow, Down Arrow, End, Home.
+
+### NO_HAPTIC_NUMERIC
+With the entry of `#define NO_HAPTIC_NUMERIC` in config.h, none of the following keys between 0 and 9 (KC_1 ... KC_0) will trigger a feedback. \ No newline at end of file
diff --git a/docs/feature_oled_driver.md b/docs/feature_oled_driver.md
index f3b659b1bc..c90aabb9c6 100644
--- a/docs/feature_oled_driver.md
+++ b/docs/feature_oled_driver.md
@@ -346,6 +346,10 @@ bool oled_scroll_left(void);
// Returns true if the screen was not scrolling or stops scrolling
bool oled_scroll_off(void);
+// Inverts the display
+// Returns true if the screen was or is inverted
+bool oled_invert(bool invert);
+
// Returns the maximum number of characters that will fit on a line
uint8_t oled_max_chars(void);
diff --git a/docs/feature_rgb_matrix.md b/docs/feature_rgb_matrix.md
index bfb3688b67..25ba3ffe32 100644
--- a/docs/feature_rgb_matrix.md
+++ b/docs/feature_rgb_matrix.md
@@ -228,6 +228,74 @@ Configure the hardware via your `config.h`:
```
---
+### AW20216 :id=aw20216
+There is basic support for addressable RGB matrix lighting with the SPI AW20216 RGB controller. To enable it, add this to your `rules.mk`:
+
+```makefile
+RGB_MATRIX_ENABLE = yes
+RGB_MATRIX_DRIVER = AW20216
+```
+
+You can use up to 2 AW20216 IC's. Do not specify `DRIVER_<N>_xxx` defines for IC's that are not present on your keyboard. You can define the following items in `config.h`:
+
+| Variable | Description | Default |
+|----------|-------------|---------|
+| `DRIVER_1_CS` | (Required) MCU pin connected to first RGB driver chip select line | B13 |
+| `DRIVER_2_CS` | (Optional) MCU pin connected to second RGB driver chip select line | |
+| `DRIVER_1_EN` | (Required) MCU pin connected to first RGB driver hardware enable line | C13 |
+| `DRIVER_2_EN` | (Optional) MCU pin connected to second RGB driver hardware enable line | |
+| `DRIVER_1_LED_TOTAL` | (Required) How many RGB lights are connected to first RGB driver | |
+| `DRIVER_2_LED_TOTAL` | (Optional) How many RGB lights are connected to second RGB driver | |
+| `DRIVER_COUNT` | (Required) How many RGB driver IC's are present | |
+| `DRIVER_LED_TOTAL` | (Required) How many RGB lights are present across all drivers | |
+| `AW_SCALING_MAX` | (Optional) LED current scaling value (0-255, higher values mean LED is brighter at full PWM) | 150 |
+| `AW_GLOBAL_CURRENT_MAX` | (Optional) Driver global current limit (0-255, higher values means the driver may consume more power) | 150 |
+
+Here is an example using 2 drivers.
+
+```c
+#define DRIVER_1_CS B13
+#define DRIVER_2_CS B14
+// Hardware enable lines may be connected to the same pin
+#define DRIVER_1_EN C13
+#define DRIVER_2_EN C13
+
+#define DRIVER_COUNT 2
+#define DRIVER_1_LED_TOTAL 66
+#define DRIVER_2_LED_TOTAL 32
+#define DRIVER_LED_TOTAL (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)
+```
+
+!> Note the parentheses, this is so when `DRIVER_LED_TOTAL` is used in code and expanded, the values are added together before any additional math is applied to them. As an example, `rand() % (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)` will give very different results than `rand() % DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL`.
+
+Define these arrays listing all the LEDs in your `<keyboard>.c`:
+
+```c
+const aw_led g_aw_leds[DRIVER_LED_TOTAL] = {
+/* Each AW20216 channel is controlled by a register at some offset between 0x00
+ * and 0xD7 inclusive.
+ * See drivers/awinic/aw20216.h for the mapping between register offsets and
+ * driver pin locations.
+ * driver
+ * | R location
+ * | | G location
+ * | | | B location
+ * | | | | */
+ { 0, CS1_SW1, CS2_SW1, CS3_SW1 },
+ { 0, CS4_SW1, CS5_SW1, CS6_SW1 },
+ { 0, CS7_SW1, CS8_SW1, CS9_SW1 },
+ { 0, CS10_SW1, CS11_SW1, CS12_SW1 },
+ { 0, CS13_SW1, CS14_SW1, CS15_SW1 },
+ ...
+ { 1, CS1_SW1, CS2_SW1, CS3_SW1 },
+ { 1, CS13_SW1, CS14_SW1, CS15_SW1 },
+ { 1, CS16_SW1, CS17_SW1, CS18_SW1 },
+ { 1, CS4_SW2, CS5_SW2, CS6_SW2 },
+ ...
+};
+```
+
+---
## Common Configuration :id=common-configuration
diff --git a/docs/feature_split_keyboard.md b/docs/feature_split_keyboard.md
index 4ebf585f5c..603c387c2d 100644
--- a/docs/feature_split_keyboard.md
+++ b/docs/feature_split_keyboard.md
@@ -8,8 +8,7 @@ QMK Firmware has a generic implementation that is usable by any board, as well a
For this, we will mostly be talking about the generic implementation used by the Let's Split and other keyboards.
-!> ARM is not yet fully supported for Split Keyboards and has many limitations. Progress is being made, but we have not yet reached 100% feature parity.
-
+!> ARM split supports most QMK subsystems when using the 'serial' and 'serial_usart' drivers. I2C slave is currently unsupported.
## Compatibility Overview
@@ -169,7 +168,7 @@ Because not every split keyboard is identical, there are a number of additional
#define USE_I2C
```
-This enables I<sup>2</sup>C support for split keyboards. This isn't strictly for communication, but can be used for OLED or other I<sup>2</sup>C-based devices.
+This configures the use of I<sup>2</sup>C support for split keyboard transport (AVR only).
```c
#define SOFT_SERIAL_PIN D0
@@ -193,20 +192,115 @@ If you're having issues with serial communication, you can change this value, as
* **`5`**: about 20kbps
```c
-#define SPLIT_MODS_ENABLE
+#define FORCED_SYNC_THROTTLE_MS 100
```
-This enables transmitting modifier state (normal, weak and oneshot) to the non
-primary side of the split keyboard. This adds a few bytes of data to the split
-communication protocol and may impact the matrix scan speed when enabled.
-The purpose of this feature is to support cosmetic use of modifer state (e.g.
-displaying status on an OLED screen).
+This sets the maximum number of milliseconds before forcing a synchronization of data from master to slave. Under normal circumstances this sync occurs whenever the data _changes_, for safety a data transfer occurs after this number of milliseconds if no change has been detected since the last sync.
```c
#define SPLIT_TRANSPORT_MIRROR
```
-This mirrors the master side matrix to the slave side for features that react or require knowledge of master side key presses on the slave side. This adds a few bytes of data to the split communication protocol and may impact the matrix scan speed when enabled. The purpose of this feature is to support cosmetic use of key events (e.g. RGB reacting to Keypresses).
+This mirrors the master side matrix to the slave side for features that react or require knowledge of master side key presses on the slave side. The purpose of this feature is to support cosmetic use of key events (e.g. RGB reacting to keypresses). This adds overhead to the split communication protocol and may negatively impact the matrix scan speed when enabled.
+
+```c
+#define SPLIT_LAYER_STATE_ENABLE
+```
+
+This enables syncing of the layer state between both halves of the split keyboard. The main purpose of this feature is to enable support for use of things like OLED display of the currently active layer. This adds overhead to the split communication protocol and may negatively impact the matrix scan speed when enabled.
+
+```c
+#define SPLIT_LED_STATE_ENABLE
+```
+
+This enables syncing of the Host LED status (caps lock, num lock, etc) between both halves of the split keyboard. The main purpose of this feature is to enable support for use of things like OLED display of the Host LED status. This adds overhead to the split communication protocol and may negatively impact the matrix scan speed when enabled.
+
+```c
+#define SPLIT_MODS_ENABLE
+```
+
+This enables transmitting modifier state (normal, weak and oneshot) to the non primary side of the split keyboard. The purpose of this feature is to support cosmetic use of modifer state (e.g. displaying status on an OLED screen). This adds overhead to the split communication protocol and may negatively impact the matrix scan speed when enabled.
+
+```c
+#define SPLIT_WPM_ENABLE
+```
+
+This enables transmitting the current WPM to the slave side of the split keyboard. The purpose of this feature is to support cosmetic use of WPM (e.g. displaying the current value on an OLED screen). This adds overhead to the split communication protocol and may negatively impact the matrix scan speed when enabled.
+
+### Custom data sync between sides :id=custom-data-sync
+
+QMK's split transport allows for arbitrary data transactions at both the keyboard and user levels. This is modelled on a remote procedure call, with the master invoking a function on the slave side, with the ability to send data from master to slave, process it slave side, and send data back from slave to master.
+
+To leverage this, a keyboard or user/keymap can define a comma-separated list of _transaction IDs_:
+
+```c
+// for keyboard-level data sync:
+#define SPLIT_TRANSACTION_IDS_KB KEYBOARD_SYNC_A, KEYBOARD_SYNC_B
+// or, for user:
+#define SPLIT_TRANSACTION_IDS_USER USER_SYNC_A, USER_SYNC_B, USER_SYNC_C
+```
+
+These _transaction IDs_ then need a slave-side handler function to be registered with the split transport, for example:
+
+```c
+typedef struct _master_to_slave_t {
+ int m2s_data;
+} master_to_slave_t;
+
+typedef struct _slave_to_master_t {
+ int s2m_data;
+} slave_to_master_t;
+
+void user_sync_a_slave_handler(uint8_t in_buflen, const void* in_data, uint8_t out_buflen, void* out_data) {
+ const master_to_slave_t *m2s = (const master_to_slave_t*)in_data;
+ slave_to_master_t *s2m = (slave_to_master_t*)out_data;
+ s2m->s2m_data = m2s->m2s_data + 5; // whatever comes in, add 5 so it can be sent back
+}
+
+void keyboard_post_init_user(void) {
+ transaction_register_rpc(USER_SYNC_A, user_sync_a_slave_handler);
+}
+```
+
+The master side can then invoke the slave-side handler - for normal keyboard functionality to be minimally affected, any keyboard- or user-level code attempting to sync data should be throttled:
+
+```c
+void housekeeping_task_user(void) {
+ if (is_keyboard_master()) {
+ // Interact with slave every 500ms
+ static uint32_t last_sync = 0;
+ if (timer_elapsed32(last_sync) > 500) {
+ master_to_slave_t m2s = {6};
+ slave_to_master_t s2m = {0};
+ if(transaction_rpc_exec(USER_SYNC_A, sizeof(m2s), &m2s, sizeof(s2m), &s2m)) {
+ last_sync = timer_read32();
+ dprintf("Slave value: %d\n", s2m.s2m_data); // this will now be 11, as the slave adds 5
+ } else {
+ dprint("Slave sync failed!\n");
+ }
+ }
+ }
+}
+```
+
+!> It is recommended that any data sync between halves happens during the master side's _housekeeping task_. This ensures timely retries should failures occur.
+
+If only one-way data transfer is needed, helper methods are provided:
+
+```c
+bool transaction_rpc_exec(int8_t transaction_id, uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer);
+bool transaction_rpc_send(int8_t transaction_id, uint8_t initiator2target_buffer_size, const void *initiator2target_buffer);
+bool transaction_rpc_recv(int8_t transaction_id, uint8_t target2initiator_buffer_size, void *target2initiator_buffer);
+```
+
+By default, the inbound and outbound data is limited to a maximum of 32 bytes each. The sizes can be altered if required:
+
+```c
+// Master to slave:
+#define RPC_M2S_BUFFER_SIZE 48
+// Slave to master:
+#define RPC_S2M_BUFFER_SIZE 48
+```
### Hardware Configuration Options
diff --git a/docs/feature_st7565.md b/docs/feature_st7565.md
new file mode 100644
index 0000000000..de3e44d8e9
--- /dev/null
+++ b/docs/feature_st7565.md
@@ -0,0 +1,274 @@
+# ST7565 LCD Driver
+
+## Supported Hardware
+
+LCD modules using ST7565 driver IC, communicating over SPI.
+
+|Module |IC |Size |Notes |
+|------------------------------|-------|------|----------------------------------------------------------|
+|Newhaven Display NHD-C12832A1Z|ST7565R|128x32|Used by Ergodox Infinity; primary consumer of this feature|
+|Zolentech ZLE12864B |ST7565P|128x64|Requires contrast adjustment |
+
+## Usage
+
+To enable the feature, there are three steps. First, when compiling your keyboard, you'll need to add the following to your `rules.mk`:
+
+```make
+ST7565_ENABLE = yes
+```
+
+Then in your `keymap.c` file, implement the ST7565 task call. This example assumes your keymap has three layers named `_QWERTY`, `_FN` and `_ADJ`:
+
+```c
+#ifdef ST7565_ENABLE
+void st7565_task_user(void) {
+ // Host Keyboard Layer Status
+ st7565_write_P(PSTR("Layer: "), false);
+
+ switch (get_highest_layer(layer_state)) {
+ case _QWERTY:
+ st7565_write_P(PSTR("Default\n"), false);
+ break;
+ case _FN:
+ st7565_write_P(PSTR("FN\n"), false);
+ break;
+ case _ADJ:
+ st7565_write_P(PSTR("ADJ\n"), false);
+ break;
+ default:
+ // Or use the write_ln shortcut over adding '\n' to the end of your string
+ st7565_write_ln_P(PSTR("Undefined"), false);
+ }
+
+ // Host Keyboard LED Status
+ led_t led_state = host_keyboard_led_state();
+ st7565_write_P(led_state.num_lock ? PSTR("NUM ") : PSTR(" "), false);
+ st7565_write_P(led_state.caps_lock ? PSTR("CAP ") : PSTR(" "), false);
+ st7565_write_P(led_state.scroll_lock ? PSTR("SCR ") : PSTR(" "), false);
+}
+#endif
+```
+
+## Logo Example
+
+In the default font, certain ranges of characters are reserved for a QMK logo. To render this logo to the screen, use the following code example:
+
+```c
+static void render_logo(void) {
+ static const char PROGMEM qmk_logo[] = {
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94,
+ 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4,
+ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0x00
+ };
+
+ st7565_write_P(qmk_logo, false);
+}
+```
+
+## Buffer Read Example
+For some purposes, you may need to read the current state of the display buffer. The `st7565_read_raw` function can be used to safely read bytes from the buffer.
+
+In this example, calling `fade_display` in the `st7565_task_user` function will slowly fade away whatever is on the screen by turning random pixels off over time.
+```c
+//Setup some mask which can be or'd with bytes to turn off pixels
+const uint8_t single_bit_masks[8] = {127, 191, 223, 239, 247, 251, 253, 254};
+
+static void fade_display(void) {
+ //Define the reader structure
+ display_buffer_reader_t reader;
+ uint8_t buff_char;
+ if (random() % 30 == 0) {
+ srand(timer_read());
+ // Fetch a pointer for the buffer byte at index 0. The return structure
+ // will have the pointer and the number of bytes remaining from this
+ // index position if we want to perform a sequential read by
+ // incrementing the buffer pointer
+ reader = st7565_read_raw(0);
+ //Loop over the remaining buffer and erase pixels as we go
+ for (uint16_t i = 0; i < reader.remaining_element_count; i++) {
+ //Get the actual byte in the buffer by dereferencing the pointer
+ buff_char = *reader.current_element;
+ if (buff_char != 0) {
+ st7565_write_raw_byte(buff_char & single_bit_masks[rand() % 8], i);
+ }
+ //increment the pointer to fetch a new byte during the next loop
+ reader.current_element++;
+ }
+ }
+}
+```
+
+## Other Examples
+
+In split keyboards, it is very common to have two displays that each render different content and are oriented or flipped differently. You can do this by switching which content to render by using the return value from `is_keyboard_master()` or `is_keyboard_left()` found in `split_util.h`, e.g:
+
+```c
+#ifdef ST7565_ENABLE
+display_rotation_t st7565_init_user(display_rotation_t rotation) {
+ if (!is_keyboard_master()) {
+ return DISPLAY_ROTATION_180; // flips the display 180 degrees if offhand
+ }
+
+ return rotation;
+}
+
+void st7565_task_user(void) {
+ if (is_keyboard_master()) {
+ render_status(); // Renders the current keyboard state (layer, lock, caps, scroll, etc)
+ } else {
+ render_logo(); // Renders a static logo
+ }
+}
+#endif
+```
+
+## Basic Configuration
+
+|Define |Default |Description |
+|------------------------|--------------|-----------------------------------------------------------------------------------------------------|
+|`ST7565_A0_PIN` |*Not defined* |(Required) The GPIO connected to the display's A0 (data/command) pin |
+|`ST7565_RST_PIN` |*Not defined* |(Required) The GPIO connected to the display's reset pin |
+|`ST7565_SS_PIN` |*Not defined* |(Required) The GPIO connected to the display's slave select pin |
+|`ST7565_SPI_CLK_DIVISOR`|`4` |The SPI clock divisor to use |
+|`ST7565_FONT_H` |`"glcdfont.c"`|The font code file to use for custom fonts |
+|`ST7565_FONT_START` |`0` |The starting character index for custom fonts |
+|`ST7565_FONT_END` |`223` |The ending character index for custom fonts |
+|`ST7565_FONT_WIDTH` |`6` |The font width |
+|`ST7565_FONT_HEIGHT` |`8` |The font height (untested) |
+|`ST7565_TIMEOUT` |`60000` |Turns off the screen after 60000ms of keyboard inactivity. Helps reduce burn-in. Set to 0 to disable.|
+|`ST7565_COLUMN_OFFSET` |`0` |Shift output to the right this many pixels. |
+|`ST7565_CONTRAST` |`32` |The default contrast level of the display, from 0 to 255. |
+|`ST7565_UPDATE_INTERVAL`|`0` |Set the time interval for updating the display in ms. This will improve the matrix scan rate. |
+
+## Custom sized displays
+
+The default display size for this feature is 128x32 and all necessary defines are precalculated with that in mind.
+
+|Define |Default |Description |
+|-----------------------|----------|-----------------------------------------------------------------------------------------------------------|
+|`ST7565_DISPLAY_WIDTH` |`128` |The width of the display. |
+|`ST7565_DISPLAY_HEIGHT`|`32` |The height of the display. |
+|`ST7565_MATRIX_SIZE` |`512` |The local buffer size to allocate.<br>`(ST7565_DISPLAY_HEIGHT / 8 * ST7565_DISPLAY_WIDTH)`. |
+|`ST7565_BLOCK_TYPE` |`uint16_t`|The unsigned integer type to use for dirty rendering. |
+|`ST7565_BLOCK_COUNT` |`16` |The number of blocks the display is divided into for dirty rendering.<br>`(sizeof(ST7565_BLOCK_TYPE) * 8)`.|
+|`ST7565_BLOCK_SIZE` |`32` |The size of each block for dirty rendering<br>`(ST7565_MATRIX_SIZE / ST7565_BLOCK_COUNT)`. |
+
+## API
+
+```c
+// Rotation enum values are flags
+typedef enum {
+ DISPLAY_ROTATION_0,
+ DISPLAY_ROTATION_180
+} display_rotation_t;
+
+// Initialize the display, rotating the rendered output based on the define passed in.
+// Returns true if the was initialized successfully
+bool st7565_init(display_rotation_t rotation);
+
+// Called at the start of st7565_init, weak function overridable by the user
+// rotation - the value passed into st7565_init
+// Return new display_rotation_t if you want to override default rotation
+display_rotation_t st7565_init_user(display_rotation_t rotation);
+
+// Clears the display buffer, resets cursor position to 0, and sets the buffer to dirty for rendering
+void st7565_clear(void);
+
+// Renders the dirty chunks of the buffer to display
+void st7565_render(void);
+
+// Moves cursor to character position indicated by column and line, wraps if out of bounds
+// Max column denoted by 'st7565_max_chars()' and max lines by 'st7565_max_lines()' functions
+void st7565_set_cursor(uint8_t col, uint8_t line);
+
+// Advances the cursor to the next page, writing ' ' if true
+// Wraps to the begining when out of bounds
+void st7565_advance_page(bool clearPageRemainder);
+
+// Moves the cursor forward 1 character length
+// Advance page if there is not enough room for the next character
+// Wraps to the begining when out of bounds
+void st7565_advance_char(void);
+
+// Writes a single character to the buffer at current cursor position
+// Advances the cursor while writing, inverts the pixels if true
+// Main handler that writes character data to the display buffer
+void st7565_write_char(const char data, bool invert);
+
+// Writes a string to the buffer at current cursor position
+// Advances the cursor while writing, inverts the pixels if true
+void st7565_write(const char *data, bool invert);
+
+// Writes a string to the buffer at current cursor position
+// Advances the cursor while writing, inverts the pixels if true
+// Advances the cursor to the next page, wiring ' ' to the remainder of the current page
+void st7565_write_ln(const char *data, bool invert);
+
+// Pans the buffer to the right (or left by passing true) by moving contents of the buffer
+// Useful for moving the screen in preparation for new drawing
+void st7565_pan(bool left);
+
+// Returns a pointer to the requested start index in the buffer plus remaining
+// buffer length as struct
+display_buffer_reader_t st7565_read_raw(uint16_t start_index);
+
+// Writes a string to the buffer at current cursor position
+void st7565_write_raw(const char *data, uint16_t size);
+
+// Writes a single byte into the buffer at the specified index
+void st7565_write_raw_byte(const char data, uint16_t index);
+
+// Sets a specific pixel on or off
+// Coordinates start at top-left and go right and down for positive x and y
+void st7565_write_pixel(uint8_t x, uint8_t y, bool on);
+
+// Writes a PROGMEM string to the buffer at current cursor position
+// Advances the cursor while writing, inverts the pixels if true
+// Remapped to call 'void st7565_write(const char *data, bool invert);' on ARM
+void st7565_write_P(const char *data, bool invert);
+
+// Writes a PROGMEM string to the buffer at current cursor position
+// Advances the cursor while writing, inverts the pixels if true
+// Advances the cursor to the next page, wiring ' ' to the remainder of the current page
+// Remapped to call 'void st7565_write_ln(const char *data, bool invert);' on ARM
+void st7565_write_ln_P(const char *data, bool invert);
+
+// Writes a PROGMEM string to the buffer at current cursor position
+void st7565_write_raw_P(const char *data, uint16_t size);
+
+// Can be used to manually turn on the screen if it is off
+// Returns true if the screen was on or turns on
+bool st7565_on(void);
+
+// Called when st7565_on() turns on the screen, weak function overridable by the user
+// Not called if the screen is already on
+void st7565_on_user(void);
+
+// Can be used to manually turn off the screen if it is on
+// Returns true if the screen was off or turns off
+bool st7565_off(void);
+
+// Called when st7565_off() turns off the screen, weak function overridable by the user
+// Not called if the screen is already off
+void st7565_off_user(void);
+
+// Returns true if the screen is currently on, false if it is
+// not
+bool st7565_is_on(void);
+
+// Basically it's st7565_render, but with timeout management and st7565_task_user calling!
+void st7565_task(void);
+
+// Called at the start of st7565_task, weak function overridable by the user
+void st7565_task_user(void);
+
+// Inverts the display
+// Returns true if the screen was or is inverted
+bool st7565_invert(bool invert);
+
+// Returns the maximum number of characters that will fit on a line
+uint8_t st7565_max_chars(void);
+
+// Returns the maximum number of lines that will fit on the display
+uint8_t st7565_max_lines(void);
+```
diff --git a/drivers/avr/i2c_master.c b/drivers/avr/i2c_master.c
index b1e4885298..2773e00778 100644
--- a/drivers/avr/i2c_master.c
+++ b/drivers/avr/i2c_master.c
@@ -28,8 +28,14 @@
# define F_SCL 400000UL // SCL frequency
#endif
+#ifndef I2C_START_RETRY_COUNT
+# define I2C_START_RETRY_COUNT 20
+#endif // I2C_START_RETRY_COUNT
+
#define TWBR_val (((F_CPU / F_SCL) - 16) / 2)
+#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
+
void i2c_init(void) {
TWSR = 0; /* no prescaler */
TWBR = (uint8_t)TWBR_val;
@@ -47,7 +53,7 @@ void i2c_init(void) {
#endif
}
-i2c_status_t i2c_start(uint8_t address, uint16_t timeout) {
+static i2c_status_t i2c_start_impl(uint8_t address, uint16_t timeout) {
// reset TWI control register
TWCR = 0;
// transmit START condition
@@ -86,6 +92,17 @@ i2c_status_t i2c_start(uint8_t address, uint16_t timeout) {
return I2C_STATUS_SUCCESS;
}
+i2c_status_t i2c_start(uint8_t address, uint16_t timeout) {
+ // Retry i2c_start_impl a bunch times in case the remote side has interrupts disabled.
+ uint16_t timeout_timer = timer_read();
+ uint16_t time_slice = MAX(1, (timeout == (I2C_TIMEOUT_INFINITE)) ? 5 : (timeout / (I2C_START_RETRY_COUNT))); // if it's infinite, wait 1ms between attempts, otherwise split up the entire timeout into the number of retries
+ i2c_status_t status;
+ do {
+ status = i2c_start_impl(address, time_slice);
+ } while ((status < 0) && ((timeout == I2C_TIMEOUT_INFINITE) || (timer_elapsed(timeout_timer) < timeout)));
+ return status;
+}
+
i2c_status_t i2c_write(uint8_t data, uint16_t timeout) {
// load data into data register
TWDR = data;
diff --git a/drivers/avr/i2c_slave.c b/drivers/avr/i2c_slave.c
index 62a378165a..2907f164c0 100644
--- a/drivers/avr/i2c_slave.c
+++ b/drivers/avr/i2c_slave.c
@@ -17,6 +17,7 @@
* GitHub repository: https://github.com/g4lvanix/I2C-slave-lib
*/
+#include <stddef.h>
#include <avr/io.h>
#include <util/twi.h>
#include <avr/interrupt.h>
@@ -24,6 +25,12 @@
#include "i2c_slave.h"
+#if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
+# include "transactions.h"
+
+static volatile bool is_callback_executor = false;
+#endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
+
volatile uint8_t i2c_slave_reg[I2C_SLAVE_REG_COUNT];
static volatile uint8_t buffer_address;
@@ -48,11 +55,14 @@ ISR(TWI_vect) {
case TW_SR_SLA_ACK:
// The device is now a slave receiver
slave_has_register_set = false;
+#if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
+ is_callback_executor = false;
+#endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
break;
case TW_SR_DATA_ACK:
// This device is a slave receiver and has received data
- // First byte is the location then the bytes will be writen in buffer with auto-incriment
+ // First byte is the location then the bytes will be writen in buffer with auto-increment
if (!slave_has_register_set) {
buffer_address = TWDR;
@@ -60,10 +70,25 @@ ISR(TWI_vect) {
ack = 0;
buffer_address = 0;
}
- slave_has_register_set = true; // address has been receaved now fill in buffer
+ slave_has_register_set = true; // address has been received now fill in buffer
+
+#if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
+ // Work out if we're attempting to execute a callback
+ is_callback_executor = buffer_address == split_transaction_table[I2C_EXECUTE_CALLBACK].initiator2target_offset;
+#endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
} else {
i2c_slave_reg[buffer_address] = TWDR;
buffer_address++;
+
+#if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
+ // If we're intending to execute a transaction callback, do so, as we've just received the transaction ID
+ if (is_callback_executor) {
+ split_transaction_desc_t *trans = &split_transaction_table[split_shmem->transaction_id];
+ if (trans->slave_callback) {
+ trans->slave_callback(trans->initiator2target_buffer_size, split_trans_initiator2target_buffer(trans), trans->target2initiator_buffer_size, split_trans_target2initiator_buffer(trans));
+ }
+ }
+#endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
}
break;
diff --git a/drivers/avr/i2c_slave.h b/drivers/avr/i2c_slave.h
index 1cd0625ef4..a8647c9da3 100644
--- a/drivers/avr/i2c_slave.h
+++ b/drivers/avr/i2c_slave.h
@@ -22,7 +22,18 @@
#pragma once
-#define I2C_SLAVE_REG_COUNT 30
+#ifndef I2C_SLAVE_REG_COUNT
+
+# if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
+# include "transport.h"
+# define I2C_SLAVE_REG_COUNT sizeof(split_shared_memory_t)
+# else // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
+# define I2C_SLAVE_REG_COUNT 30
+# endif // defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS)
+
+#endif // I2C_SLAVE_REG_COUNT
+
+_Static_assert(I2C_SLAVE_REG_COUNT < 256, "I2C target registers must be single byte");
extern volatile uint8_t i2c_slave_reg[I2C_SLAVE_REG_COUNT];
diff --git a/drivers/avr/serial.c b/drivers/avr/serial.c
index 3647bee0d3..9a7345a53d 100644
--- a/drivers/avr/serial.c
+++ b/drivers/avr/serial.c
@@ -224,15 +224,8 @@
# define SERIAL_DELAY_HALF2 (SERIAL_DELAY - SERIAL_DELAY / 2)
# define SLAVE_INT_WIDTH_US 1
-# ifndef SERIAL_USE_MULTI_TRANSACTION
-# define SLAVE_INT_RESPONSE_TIME SERIAL_DELAY
-# else
-# define SLAVE_INT_ACK_WIDTH_UNIT 2
-# define SLAVE_INT_ACK_WIDTH 4
-# endif
-
-static SSTD_t *Transaction_table = NULL;
-static uint8_t Transaction_table_size = 0;
+# define SLAVE_INT_ACK_WIDTH_UNIT 2
+# define SLAVE_INT_ACK_WIDTH 4
inline static void serial_delay(void) ALWAYS_INLINE;
inline static void serial_delay(void) { _delay_us(SERIAL_DELAY); }
@@ -259,16 +252,12 @@ inline static void serial_low(void) { writePinLow(SOFT_SERIAL_PIN); }
inline static void serial_high(void) ALWAYS_INLINE;
inline static void serial_high(void) { writePinHigh(SOFT_SERIAL_PIN); }
-void soft_serial_initiator_init(SSTD_t *sstd_table, int sstd_table_size) {
- Transaction_table = sstd_table;
- Transaction_table_size = (uint8_t)sstd_table_size;
+void soft_serial_initiator_init(void) {
serial_output();
serial_high();
}
-void soft_serial_target_init(SSTD_t *sstd_table, int sstd_table_size) {
- Transaction_table = sstd_table;
- Transaction_table_size = (uint8_t)sstd_table_size;
+void soft_serial_target_init(void) {
serial_input_with_pullup();
// Enable INT0-INT7
@@ -395,19 +384,14 @@ static inline uint8_t nibble_bits_count(uint8_t bits) {
// interrupt handle to be used by the target device
ISR(SERIAL_PIN_INTERRUPT) {
-# ifndef SERIAL_USE_MULTI_TRANSACTION
- serial_low();
- serial_output();
- SSTD_t *trans = Transaction_table;
-# else
// recive transaction table index
uint8_t tid, bits;
uint8_t pecount = 0;
sync_recv();
- bits = serial_read_chunk(&pecount, 7);
+ bits = serial_read_chunk(&pecount, 8);
tid = bits >> 3;
- bits = (bits & 7) != nibble_bits_count(tid);
- if (bits || pecount > 0 || tid > Transaction_table_size) {
+ bits = (bits & 7) != (nibble_bits_count(tid) & 7);
+ if (bits || pecount > 0 || tid > NUM_TOTAL_TRANSACTIONS) {
return;
}
serial_delay_half1();
@@ -415,18 +399,22 @@ ISR(SERIAL_PIN_INTERRUPT) {
serial_high(); // response step1 low->high
serial_output();
_delay_sub_us(SLAVE_INT_ACK_WIDTH_UNIT * SLAVE_INT_ACK_WIDTH);
- SSTD_t *trans = &Transaction_table[tid];
+ split_transaction_desc_t *trans = &split_transaction_table[tid];
serial_low(); // response step2 ack high->low
-# endif
+
+ // If the transaction has a callback, we can execute it now
+ if (trans->slave_callback) {
+ trans->slave_callback(trans->initiator2target_buffer_size, split_trans_initiator2target_buffer(trans), trans->target2initiator_buffer_size, split_trans_target2initiator_buffer(trans));
+ }
// target send phase
- if (trans->target2initiator_buffer_size > 0) serial_send_packet((uint8_t *)trans->target2initiator_buffer, trans->target2initiator_buffer_size);
+ if (trans->target2initiator_buffer_size > 0) serial_send_packet((uint8_t *)split_trans_target2initiator_buffer(trans), trans->target2initiator_buffer_size);
// target switch to input
change_sender2reciver();
// target recive phase
if (trans->initiator2target_buffer_size > 0) {
- if (serial_recive_packet((uint8_t *)trans->initiator2target_buffer, trans->initiator2target_buffer_size)) {
+ if (serial_recive_packet((uint8_t *)split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size)) {
*trans->status = TRANSACTION_ACCEPTED;
} else {
*trans->status = TRANSACTION_DATA_ERROR;
@@ -448,14 +436,12 @@ ISR(SERIAL_PIN_INTERRUPT) {
// TRANSACTION_NO_RESPONSE
// TRANSACTION_DATA_ERROR
// this code is very time dependent, so we need to disable interrupts
-# ifndef SERIAL_USE_MULTI_TRANSACTION
-int soft_serial_transaction(void) {
- SSTD_t *trans = Transaction_table;
-# else
int soft_serial_transaction(int sstd_index) {
- if (sstd_index > Transaction_table_size) return TRANSACTION_TYPE_ERROR;
- SSTD_t *trans = &Transaction_table[sstd_index];
-# endif
+ if (sstd_index > NUM_TOTAL_TRANSACTIONS) return TRANSACTION_TYPE_ERROR;
+ split_transaction_desc_t *trans = &split_transaction_table[sstd_index];
+
+ if (!trans->status) return TRANSACTION_TYPE_ERROR; // not registered
+
cli();
// signal to the target that we want to start a transaction
@@ -463,27 +449,11 @@ int soft_serial_transaction(int sstd_index) {
serial_low();
_delay_us(SLAVE_INT_WIDTH_US);
-# ifndef SERIAL_USE_MULTI_TRANSACTION
- // wait for the target response
- serial_input_with_pullup();
- _delay_us(SLAVE_INT_RESPONSE_TIME);
-
- // check if the target is present
- if (serial_read_pin()) {
- // target failed to pull the line low, assume not present
- serial_output();
- serial_high();
- *trans->status = TRANSACTION_NO_RESPONSE;
- sei();
- return TRANSACTION_NO_RESPONSE;
- }
-
-# else
// send transaction table index
int tid = (sstd_index << 3) | (7 & nibble_bits_count(sstd_index));
sync_send();
_delay_sub_us(TID_SEND_ADJUST);
- serial_write_chunk(tid, 7);
+ serial_write_chunk(tid, 8);
serial_delay_half1();
// wait for the target response (step1 low->high)
@@ -504,12 +474,11 @@ int soft_serial_transaction(int sstd_index) {
}
_delay_sub_us(SLAVE_INT_ACK_WIDTH_UNIT);
}
-# endif
// initiator recive phase
// if the target is present syncronize with it
if (trans->target2initiator_buffer_size > 0) {
- if (!serial_recive_packet((uint8_t *)trans->target2initiator_buffer, trans->target2initiator_buffer_size)) {
+ if (!serial_recive_packet((uint8_t *)split_trans_target2initiator_buffer(trans), trans->target2initiator_buffer_size)) {
serial_output();
serial_high();
*trans->status = TRANSACTION_DATA_ERROR;
@@ -523,7 +492,7 @@ int soft_serial_transaction(int sstd_index) {
// initiator send phase
if (trans->initiator2target_buffer_size > 0) {
- serial_send_packet((uint8_t *)trans->initiator2target_buffer, trans->initiator2target_buffer_size);
+ serial_send_packet((uint8_t *)split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size);
}
// always, release the line when not in use
@@ -534,9 +503,8 @@ int soft_serial_transaction(int sstd_index) {
return TRANSACTION_END;
}
-# ifdef SERIAL_USE_MULTI_TRANSACTION
int soft_serial_get_and_clean_status(int sstd_index) {
- SSTD_t *trans = &Transaction_table[sstd_index];
+ split_transaction_desc_t *trans = &split_transaction_table[sstd_index];
cli();
int retval = *trans->status;
*trans->status = 0;
@@ -544,8 +512,6 @@ int soft_serial_get_and_clean_status(int sstd_index) {
sei();
return retval;
}
-# endif
-
#endif
// Helix serial.c history
diff --git a/drivers/avr/serial.h b/drivers/avr/serial.h
deleted file mode 100644
index 53e66cf905..0000000000
--- a/drivers/avr/serial.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#pragma once
-
-#include <stdbool.h>
-
-// /////////////////////////////////////////////////////////////////
-// Need Soft Serial defines in config.h
-// /////////////////////////////////////////////////////////////////
-// ex.
-// #define SOFT_SERIAL_PIN ?? // ?? = D0,D1,D2,D3,E6
-// OPTIONAL: #define SELECT_SOFT_SERIAL_SPEED ? // ? = 1,2,3,4,5
-// // 1: about 137kbps (default)
-// // 2: about 75kbps
-// // 3: about 39kbps
-// // 4: about 26kbps
-// // 5: about 20kbps
-//
-// //// USE simple API (using signle-type transaction function)
-// /* nothing */
-// //// USE flexible API (using multi-type transaction function)
-// #define SERIAL_USE_MULTI_TRANSACTION
-//
-// /////////////////////////////////////////////////////////////////
-
-// Soft Serial Transaction Descriptor
-typedef struct _SSTD_t {
- uint8_t *status;
- uint8_t initiator2target_buffer_size;
- uint8_t *initiator2target_buffer;
- uint8_t target2initiator_buffer_size;
- uint8_t *target2initiator_buffer;
-} SSTD_t;
-#define TID_LIMIT(table) (sizeof(table) / sizeof(SSTD_t))
-
-// initiator is transaction start side
-void soft_serial_initiator_init(SSTD_t *sstd_table, int sstd_table_size);
-// target is interrupt accept side
-void soft_serial_target_init(SSTD_t *sstd_table, int sstd_table_size);
-
-// initiator resullt
-#define TRANSACTION_END 0
-#define TRANSACTION_NO_RESPONSE 0x1
-#define TRANSACTION_DATA_ERROR 0x2
-#define TRANSACTION_TYPE_ERROR 0x4
-#ifndef SERIAL_USE_MULTI_TRANSACTION
-int soft_serial_transaction(void);
-#else
-int soft_serial_transaction(int sstd_index);
-#endif
-
-// target status
-// *SSTD_t.status has
-// initiator:
-// TRANSACTION_END
-// or TRANSACTION_NO_RESPONSE
-// or TRANSACTION_DATA_ERROR
-// target:
-// TRANSACTION_DATA_ERROR
-// or TRANSACTION_ACCEPTED
-#define TRANSACTION_ACCEPTED 0x8
-#ifdef SERIAL_USE_MULTI_TRANSACTION
-int soft_serial_get_and_clean_status(int sstd_index);
-#endif
diff --git a/drivers/awinic/aw20216.c b/drivers/awinic/aw20216.c
new file mode 100644
index 0000000000..236c42a3cd
--- /dev/null
+++ b/drivers/awinic/aw20216.c
@@ -0,0 +1,166 @@
+/* Copyright 2021 Jasper Chan
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "aw20216.h"
+#include "spi_master.h"
+
+/* The AW20216 appears to be somewhat similar to the IS31FL743, although quite
+ * a few things are different, such as the command byte format and page ordering.
+ * The LED addresses start from 0x00 instead of 0x01.
+ */
+#define AWINIC_ID 0b1010 << 4
+
+#define AW_PAGE_FUNCTION 0x00 << 1 // PG0, Function registers
+#define AW_PAGE_PWM 0x01 << 1 // PG1, LED PWM control
+#define AW_PAGE_SCALING 0x02 << 1 // PG2, LED current scaling control
+#define AW_PAGE_PATCHOICE 0x03 << 1 // PG3, Pattern choice?
+#define AW_PAGE_PWMSCALING 0x04 << 1 // PG4, LED PWM + Scaling control?
+
+#define AW_WRITE 0
+#define AW_READ 1
+
+#define AW_REG_CONFIGURATION 0x00 // PG0
+#define AW_REG_GLOBALCURRENT 0x01 // PG0
+
+// Default value of AW_REG_CONFIGURATION
+// D7:D4 = 1011, SWSEL (SW1~SW12 active)
+// D3 = 0?, reserved (apparently this should be 1 but it doesn't seem to matter)
+// D2:D1 = 00, OSDE (open/short detection enable)
+// D0 = 0, CHIPEN (write 1 to enable LEDs when hardware enable pulled high)
+#define AW_CONFIG_DEFAULT 0b10110000
+#define AW_CHIPEN 1
+
+#ifndef AW_SCALING_MAX
+# define AW_SCALING_MAX 150
+#endif
+
+#ifndef AW_GLOBAL_CURRENT_MAX
+# define AW_GLOBAL_CURRENT_MAX 150
+#endif
+
+#ifndef DRIVER_1_CS
+# define DRIVER_1_CS B13
+#endif
+
+#ifndef DRIVER_1_EN
+# define DRIVER_1_EN C13
+#endif
+
+uint8_t g_spi_transfer_buffer[20] = {0};
+aw_led g_pwm_buffer[DRIVER_LED_TOTAL];
+bool g_pwm_buffer_update_required[DRIVER_LED_TOTAL];
+
+bool AW20216_write_register(pin_t slave_pin, uint8_t page, uint8_t reg, uint8_t data) {
+ // Do we need to call spi_stop() if this fails?
+ if (!spi_start(slave_pin, false, 0, 16)) {
+ return false;
+ }
+
+ g_spi_transfer_buffer[0] = (AWINIC_ID | page | AW_WRITE);
+ g_spi_transfer_buffer[1] = reg;
+ g_spi_transfer_buffer[2] = data;
+
+ if (spi_transmit(g_spi_transfer_buffer, 3) != SPI_STATUS_SUCCESS) {
+ spi_stop();
+ return false;
+ }
+ spi_stop();
+ return true;
+}
+
+bool AW20216_init_scaling(void) {
+ // Set constant current to the max, control brightness with PWM
+ aw_led led;
+ for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
+ led = g_aw_leds[i];
+ if (led.driver == 0) {
+ AW20216_write_register(DRIVER_1_CS, AW_PAGE_SCALING, led.r, AW_SCALING_MAX);
+ AW20216_write_register(DRIVER_1_CS, AW_PAGE_SCALING, led.g, AW_SCALING_MAX);
+ AW20216_write_register(DRIVER_1_CS, AW_PAGE_SCALING, led.b, AW_SCALING_MAX);
+ }
+#ifdef DRIVER_2_CS
+ else if (led.driver == 1) {
+ AW20216_write_register(DRIVER_2_CS, AW_PAGE_SCALING, led.r, AW_SCALING_MAX);
+ AW20216_write_register(DRIVER_2_CS, AW_PAGE_SCALING, led.g, AW_SCALING_MAX);
+ AW20216_write_register(DRIVER_2_CS, AW_PAGE_SCALING, led.b, AW_SCALING_MAX);
+ }
+#endif
+ }
+ return true;
+}
+
+bool AW20216_soft_enable(void) {
+ AW20216_write_register(DRIVER_1_CS, AW_PAGE_FUNCTION, AW_REG_CONFIGURATION, AW_CONFIG_DEFAULT | AW_CHIPEN);
+#ifdef DRIVER_2_CS
+ AW20216_write_register(DRIVER_2_CS, AW_PAGE_FUNCTION, AW_REG_CONFIGURATION, AW_CONFIG_DEFAULT | AW_CHIPEN);
+#endif
+ return true;
+}
+
+void AW20216_update_pwm(int index, uint8_t red, uint8_t green, uint8_t blue) {
+ aw_led led = g_aw_leds[index];
+ if (led.driver == 0) {
+ AW20216_write_register(DRIVER_1_CS, AW_PAGE_PWM, led.r, red);
+ AW20216_write_register(DRIVER_1_CS, AW_PAGE_PWM, led.g, green);
+ AW20216_write_register(DRIVER_1_CS, AW_PAGE_PWM, led.b, blue);
+ }
+#ifdef DRIVER_2_CS
+ else if (led.driver == 1) {
+ AW20216_write_register(DRIVER_2_CS, AW_PAGE_PWM, led.r, red);
+ AW20216_write_register(DRIVER_2_CS, AW_PAGE_PWM, led.g, green);
+ AW20216_write_register(DRIVER_2_CS, AW_PAGE_PWM, led.b, blue);
+ }
+#endif
+ return;
+}
+
+void AW20216_init(void) {
+ // All LEDs should start with all scaling and PWM registers as off
+ setPinOutput(DRIVER_1_EN);
+ writePinHigh(DRIVER_1_EN);
+ AW20216_write_register(DRIVER_1_CS, AW_PAGE_FUNCTION, AW_REG_GLOBALCURRENT, AW_GLOBAL_CURRENT_MAX);
+#ifdef DRIVER_2_EN
+ setPinOutput(DRIVER_2_EN);
+ writePinHigh(DRIVER_2_EN);
+ AW20216_write_register(DRIVER_2_CS, AW_PAGE_FUNCTION, AW_REG_GLOBALCURRENT, AW_GLOBAL_CURRENT_MAX);
+#endif
+ AW20216_init_scaling();
+ AW20216_soft_enable();
+ return;
+}
+
+void AW20216_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
+ g_pwm_buffer[index].r = red;
+ g_pwm_buffer[index].g = green;
+ g_pwm_buffer[index].b = blue;
+ g_pwm_buffer_update_required[index] = true;
+ return;
+}
+void AW20216_set_color_all(uint8_t red, uint8_t green, uint8_t blue) {
+ for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
+ AW20216_set_color(i, red, green, blue);
+ }
+ return;
+}
+void AW20216_update_pwm_buffers(void) {
+ for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
+ if (g_pwm_buffer_update_required[i]) {
+ AW20216_update_pwm(i, g_pwm_buffer[i].r, g_pwm_buffer[i].g, g_pwm_buffer[i].b);
+ g_pwm_buffer_update_required[i] = false;
+ }
+ }
+ return;
+}
diff --git a/drivers/awinic/aw20216.h b/drivers/awinic/aw20216.h
new file mode 100644
index 0000000000..9c6865cc82
--- /dev/null
+++ b/drivers/awinic/aw20216.h
@@ -0,0 +1,251 @@
+/* Copyright 2021 Jasper Chan (Gigahawk)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef struct aw_led {
+ uint8_t driver : 2;
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+} aw_led;
+
+extern const aw_led g_aw_leds[DRIVER_LED_TOTAL];
+
+void AW20216_init(void);
+void AW20216_set_color(int index, uint8_t red, uint8_t green, uint8_t blue);
+void AW20216_set_color_all(uint8_t red, uint8_t green, uint8_t blue);
+void AW20216_update_pwm_buffers(void);
+
+#define CS1_SW1 0x00
+#define CS2_SW1 0x01
+#define CS3_SW1 0x02
+#define CS4_SW1 0x03
+#define CS5_SW1 0x04
+#define CS6_SW1 0x05
+#define CS7_SW1 0x06
+#define CS8_SW1 0x07
+#define CS9_SW1 0x08
+#define CS10_SW1 0x09
+#define CS11_SW1 0x0A
+#define CS12_SW1 0x0B
+#define CS13_SW1 0x0C
+#define CS14_SW1 0x0D
+#define CS15_SW1 0x0E
+#define CS16_SW1 0x0F
+#define CS17_SW1 0x10
+#define CS18_SW1 0x11
+#define CS1_SW2 0x12
+#define CS2_SW2 0x13
+#define CS3_SW2 0x14
+#define CS4_SW2 0x15
+#define CS5_SW2 0x16
+#define CS6_SW2 0x17
+#define CS7_SW2 0x18
+#define CS8_SW2 0x19
+#define CS9_SW2 0x1A
+#define CS10_SW2 0x1B
+#define CS11_SW2 0x1C
+#define CS12_SW2 0x1D
+#define CS13_SW2 0x1E
+#define CS14_SW2 0x1F
+#define CS15_SW2 0x20
+#define CS16_SW2 0x21
+#define CS17_SW2 0x22
+#define CS18_SW2 0x23
+#define CS1_SW3 0x24
+#define CS2_SW3 0x25
+#define CS3_SW3 0x26
+#define CS4_SW3 0x27
+#define CS5_SW3 0x28
+#define CS6_SW3 0x29
+#define CS7_SW3 0x2A
+#define CS8_SW3 0x2B
+#define CS9_SW3 0x2C
+#define CS10_SW3 0x2D
+#define CS11_SW3 0x2E
+#define CS12_SW3 0x2F
+#define CS13_SW3 0x30
+#define CS14_SW3 0x31
+#define CS15_SW3 0x32
+#define CS16_SW3 0x33
+#define CS17_SW3 0x34
+#define CS18_SW3 0x35
+#define CS1_SW4 0x36
+#define CS2_SW4 0x37
+#define CS3_SW4 0x38
+#define CS4_SW4 0x39
+#define CS5_SW4 0x3A
+#define CS6_SW4 0x3B
+#define CS7_SW4 0x3C
+#define CS8_SW4 0x3D
+#define CS9_SW4 0x3E
+#define CS10_SW4 0x3F
+#define CS11_SW4 0x40
+#define CS12_SW4 0x41
+#define CS13_SW4 0x42
+#define CS14_SW4 0x43
+#define CS15_SW4 0x44
+#define CS16_SW4 0x45
+#define CS17_SW4 0x46
+#define CS18_SW4 0x47
+#define CS1_SW5 0x48
+#define CS2_SW5 0x49
+#define CS3_SW5 0x4A
+#define CS4_SW5 0x4B
+#define CS5_SW5 0x4C
+#define CS6_SW5 0x4D
+#define CS7_SW5 0x4E
+#define CS8_SW5 0x4F
+#define CS9_SW5 0x50
+#define CS10_SW5 0x51
+#define CS11_SW5 0x52
+#define CS12_SW5 0x53
+#define CS13_SW5 0x54
+#define CS14_SW5 0x55
+#define CS15_SW5 0x56
+#define CS16_SW5 0x57
+#define CS17_SW5 0x58
+#define CS18_SW5 0x59
+#define CS1_SW6 0x5A
+#define CS2_SW6 0x5B
+#define CS3_SW6 0x5C
+#define CS4_SW6 0x5D
+#define CS5_SW6 0x5E
+#define CS6_SW6 0x5F
+#define CS7_SW6 0x60
+#define CS8_SW6 0x61
+#define CS9_SW6 0x62
+#define CS10_SW6 0x63
+#define CS11_SW6 0x64
+#define CS12_SW6 0x65
+#define CS13_SW6 0x66
+#define CS14_SW6 0x67
+#define CS15_SW6 0x68
+#define CS16_SW6 0x69
+#define CS17_SW6 0x6A
+#define CS18_SW6 0x6B
+#define CS1_SW7 0x6C
+#define CS2_SW7 0x6D
+#define CS3_SW7 0x6E
+#define CS4_SW7 0x6F
+#define CS5_SW7 0x70
+#define CS6_SW7 0x71
+#define CS7_SW7 0x72
+#define CS8_SW7 0x73
+#define CS9_SW7 0x74
+#define CS10_SW7 0x75
+#define CS11_SW7 0x76
+#define CS12_SW7 0x77
+#define CS13_SW7 0x78
+#define CS14_SW7 0x79
+#define CS15_SW7 0x7A
+#define CS16_SW7 0x7B
+#define CS17_SW7 0x7C
+#define CS18_SW7 0x7D
+#define CS1_SW8 0x7E
+#define CS2_SW8 0x7F
+#define CS3_SW8 0x80
+#define CS4_SW8 0x81
+#define CS5_SW8 0x82
+#define CS6_SW8 0x83
+#define CS7_SW8 0x84
+#define CS8_SW8 0x85
+#define CS9_SW8 0x86
+#define CS10_SW8 0x87
+#define CS11_SW8 0x88
+#define CS12_SW8 0x89
+#define CS13_SW8 0x8A
+#define CS14_SW8 0x8B
+#define CS15_SW8 0x8C
+#define CS16_SW8 0x8D
+#define CS17_SW8 0x8E
+#define CS18_SW8 0x8F
+#define CS1_SW9 0x90
+#define CS2_SW9 0x91
+#define CS3_SW9 0x92
+#define CS4_SW9 0x93
+#define CS5_SW9 0x94
+#define CS6_SW9 0x95
+#define CS7_SW9 0x96
+#define CS8_SW9 0x97
+#define CS9_SW9 0x98
+#define CS10_SW9 0x99
+#define CS11_SW9 0x9A
+#define CS12_SW9 0x9B
+#define CS13_SW9 0x9C
+#define CS14_SW9 0x9D
+#define CS15_SW9 0x9E
+#define CS16_SW9 0x9F
+#define CS17_SW9 0xA0
+#define CS18_SW9 0xA1
+#define CS1_SW10 0xA2
+#define CS2_SW10 0xA3
+#define CS3_SW10 0xA4
+#define CS4_SW10 0xA5
+#define CS5_SW10 0xA6
+#define CS6_SW10 0xA7
+#define CS7_SW10 0xA8
+#define CS8_SW10 0xA9
+#define CS9_SW10 0xAA
+#define CS10_SW10 0xAB
+#define CS11_SW10 0xAC
+#define CS12_SW10 0xAD
+#define CS13_SW10 0xAE
+#define CS14_SW10 0xAF
+#define CS15_SW10 0xB0
+#define CS16_SW10 0xB1
+#define CS17_SW10 0xB2
+#define CS18_SW10 0xB3
+#define CS1_SW11 0xB4
+#define CS2_SW11 0xB5
+#define CS3_SW11 0xB6
+#define CS4_SW11 0xB7
+#define CS5_SW11 0xB8
+#define CS6_SW11 0xB9
+#define CS7_SW11 0xBA
+#define CS8_SW11 0xBB
+#define CS9_SW11 0xBC
+#define CS10_SW11 0xBD
+#define CS11_SW11 0xBE
+#define CS12_SW11 0xBF
+#define CS13_SW11 0xC0
+#define CS14_SW11 0xC1
+#define CS15_SW11 0xC2
+#define CS16_SW11 0xC3
+#define CS17_SW11 0xC4
+#define CS18_SW11 0xC5
+#define CS1_SW12 0xC6
+#define CS2_SW12 0xC7
+#define CS3_SW12 0xC8
+#define CS4_SW12 0xC9
+#define CS5_SW12 0xCA
+#define CS6_SW12 0xCB
+#define CS7_SW12 0xCC
+#define CS8_SW12 0xCD
+#define CS9_SW12 0xCE
+#define CS10_SW12 0xCF
+#define CS11_SW12 0xD0
+#define CS12_SW12 0xD1
+#define CS13_SW12 0xD2
+#define CS14_SW12 0xD3
+#define CS15_SW12 0xD4
+#define CS16_SW12 0xD5
+#define CS17_SW12 0xD6
+#define CS18_SW12 0xD7
diff --git a/drivers/chibios/serial.c b/drivers/chibios/serial.c
index 54f7e1321f..f54fbcee4e 100644
--- a/drivers/chibios/serial.c
+++ b/drivers/chibios/serial.c
@@ -74,21 +74,12 @@ static THD_FUNCTION(Thread1, arg) {
}
}
-static SSTD_t *Transaction_table = NULL;
-static uint8_t Transaction_table_size = 0;
-
-void soft_serial_initiator_init(SSTD_t *sstd_table, int sstd_table_size) {
- Transaction_table = sstd_table;
- Transaction_table_size = (uint8_t)sstd_table_size;
-
+void soft_serial_initiator_init(void) {
serial_output();
serial_high();
}
-void soft_serial_target_init(SSTD_t *sstd_table, int sstd_table_size) {
- Transaction_table = sstd_table;
- Transaction_table_size = (uint8_t)sstd_table_size;
-
+void soft_serial_target_init(void) {
serial_input();
palEnablePadEvent(PAL_PORT(SOFT_SERIAL_PIN), PAL_PAD(SOFT_SERIAL_PIN), PAL_EVENT_MODE_FALLING_EDGE);
@@ -154,16 +145,14 @@ void interrupt_handler(void *arg) {
uint8_t checksum_computed = 0;
int sstd_index = 0;
-#ifdef SERIAL_USE_MULTI_TRANSACTION
sstd_index = serial_read_byte();
sync_send();
-#endif
- SSTD_t *trans = &Transaction_table[sstd_index];
+ split_transaction_desc_t *trans = &split_transaction_table[sstd_index];
for (int i = 0; i < trans->initiator2target_buffer_size; ++i) {
- trans->initiator2target_buffer[i] = serial_read_byte();
+ split_trans_initiator2target_buffer(trans)[i] = serial_read_byte();
sync_send();
- checksum_computed += trans->initiator2target_buffer[i];
+ checksum_computed += split_trans_initiator2target_buffer(trans)[i];
}
checksum_computed ^= 7;
uint8_t checksum_received = serial_read_byte();
@@ -172,12 +161,17 @@ void interrupt_handler(void *arg) {
// wait for the sync to finish sending
serial_delay();
+ // Allow any slave processing to occur
+ if (trans->slave_callback) {
+ trans->slave_callback(trans->initiator2target_buffer_size, split_trans_initiator2target_buffer(trans), trans->target2initiator_buffer_size, split_trans_target2initiator_buffer(trans));
+ }
+
uint8_t checksum = 0;
for (int i = 0; i < trans->target2initiator_buffer_size; ++i) {
- serial_write_byte(trans->target2initiator_buffer[i]);
+ serial_write_byte(split_trans_target2initiator_buffer(trans)[i]);
sync_send();
serial_delay_half();
- checksum += trans->target2initiator_buffer[i];
+ checksum += split_trans_target2initiator_buffer(trans)[i];
}
serial_write_byte(checksum ^ 7);
sync_send();
@@ -206,15 +200,10 @@ void interrupt_handler(void *arg) {
// TRANSACTION_NO_RESPONSE
// TRANSACTION_DATA_ERROR
// this code is very time dependent, so we need to disable interrupts
-#ifndef SERIAL_USE_MULTI_TRANSACTION
-int soft_serial_transaction(void) {
- int sstd_index = 0;
-#else
int soft_serial_transaction(int sstd_index) {
-#endif
-
- if (sstd_index > Transaction_table_size) return TRANSACTION_TYPE_ERROR;
- SSTD_t *trans = &Transaction_table[sstd_index];
+ if (sstd_index > NUM_TOTAL_TRANSACTIONS) return TRANSACTION_TYPE_ERROR;
+ split_transaction_desc_t *trans = &split_transaction_table[sstd_index];
+ if (!trans->status) return TRANSACTION_TYPE_ERROR; // not registered
// TODO: remove extra delay between transactions
serial_delay();
@@ -244,14 +233,13 @@ int soft_serial_transaction(int sstd_index) {
uint8_t checksum = 0;
// send data to the slave
-#ifdef SERIAL_USE_MULTI_TRANSACTION
serial_write_byte(sstd_index); // first chunk is transaction id
sync_recv();
-#endif
+
for (int i = 0; i < trans->initiator2target_buffer_size; ++i) {
- serial_write_byte(trans->initiator2target_buffer[i]);
+ serial_write_byte(split_trans_initiator2target_buffer(trans)[i]);
sync_recv();
- checksum += trans->initiator2target_buffer[i];
+ checksum += split_trans_initiator2target_buffer(trans)[i];
}
serial_write_byte(checksum ^ 7);
sync_recv();
@@ -262,9 +250,9 @@ int soft_serial_transaction(int sstd_index) {
// receive data from the slave
uint8_t checksum_computed = 0;
for (int i = 0; i < trans->target2initiator_buffer_size; ++i) {
- trans->target2initiator_buffer[i] = serial_read_byte();
+ split_trans_target2initiator_buffer(trans)[i] = serial_read_byte();
sync_recv();
- checksum_computed += trans->target2initiator_buffer[i];
+ checksum_computed += split_trans_target2initiator_buffer(trans)[i];
}
checksum_computed ^= 7;
uint8_t checksum_received = serial_read_byte();
diff --git a/drivers/chibios/serial.h b/drivers/chibios/serial.h
deleted file mode 100644
index 0c1857d52e..0000000000
--- a/drivers/chibios/serial.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#pragma once
-
-#include <stdbool.h>
-
-// /////////////////////////////////////////////////////////////////
-// Need Soft Serial defines in config.h
-// /////////////////////////////////////////////////////////////////
-// ex.
-// #define SOFT_SERIAL_PIN ?? // ?? = D0,D1,D2,D3,E6
-// OPTIONAL: #define SELECT_SOFT_SERIAL_SPEED ? // ? = 1,2,3,4,5
-// // 1: about 137kbps (default)
-// // 2: about 75kbps
-// // 3: about 39kbps
-// // 4: about 26kbps
-// // 5: about 20kbps
-//
-// //// USE simple API (using signle-type transaction function)
-// /* nothing */
-// //// USE flexible API (using multi-type transaction function)
-// #define SERIAL_USE_MULTI_TRANSACTION
-//
-// /////////////////////////////////////////////////////////////////
-
-// Soft Serial Transaction Descriptor
-typedef struct _SSTD_t {
- uint8_t *status;
- uint8_t initiator2target_buffer_size;
- uint8_t *initiator2target_buffer;
- uint8_t target2initiator_buffer_size;
- uint8_t *target2initiator_buffer;
-} SSTD_t;
-#define TID_LIMIT(table) (sizeof(table) / sizeof(SSTD_t))
-
-// initiator is transaction start side
-void soft_serial_initiator_init(SSTD_t *sstd_table, int sstd_table_size);
-// target is interrupt accept side
-void soft_serial_target_init(SSTD_t *sstd_table, int sstd_table_size);
-
-// initiator result
-#define TRANSACTION_END 0
-#define TRANSACTION_NO_RESPONSE 0x1
-#define TRANSACTION_DATA_ERROR 0x2
-#define TRANSACTION_TYPE_ERROR 0x4
-#ifndef SERIAL_USE_MULTI_TRANSACTION
-int soft_serial_transaction(void);
-#else
-int soft_serial_transaction(int sstd_index);
-#endif
-
-// target status
-// *SSTD_t.status has
-// initiator:
-// TRANSACTION_END
-// or TRANSACTION_NO_RESPONSE
-// or TRANSACTION_DATA_ERROR
-// target:
-// TRANSACTION_DATA_ERROR
-// or TRANSACTION_ACCEPTED
-#define TRANSACTION_ACCEPTED 0x8
-#ifdef SERIAL_USE_MULTI_TRANSACTION
-int soft_serial_get_and_clean_status(int sstd_index);
-#endif
diff --git a/drivers/chibios/serial_usart.c b/drivers/chibios/serial_usart.c
index cae29388c3..9f180d2d74 100644
--- a/drivers/chibios/serial_usart.c
+++ b/drivers/chibios/serial_usart.c
@@ -113,37 +113,29 @@ void usart_slave_init(void) {
chThdCreateStatic(waSlaveThread, sizeof(waSlaveThread), HIGHPRIO, SlaveThread, NULL);
}
-static SSTD_t* Transaction_table = NULL;
-static uint8_t Transaction_table_size = 0;
+void soft_serial_initiator_init(void) { usart_master_init(); }
-void soft_serial_initiator_init(SSTD_t* sstd_table, int sstd_table_size) {
- Transaction_table = sstd_table;
- Transaction_table_size = (uint8_t)sstd_table_size;
-
- usart_master_init();
-}
-
-void soft_serial_target_init(SSTD_t* sstd_table, int sstd_table_size) {
- Transaction_table = sstd_table;
- Transaction_table_size = (uint8_t)sstd_table_size;
-
- usart_slave_init();
-}
+void soft_serial_target_init(void) { usart_slave_init(); }
void handle_soft_serial_slave(void) {
- uint8_t sstd_index = sdGet(&SERIAL_USART_DRIVER); // first chunk is always transaction id
- SSTD_t* trans = &Transaction_table[sstd_index];
+ uint8_t sstd_index = sdGet(&SERIAL_USART_DRIVER); // first chunk is always transaction id
+ split_transaction_desc_t* trans = &split_transaction_table[sstd_index];
// Always write back the sstd_index as part of a basic handshake
sstd_index ^= HANDSHAKE_MAGIC;
sdWrite(&SERIAL_USART_DRIVER, &sstd_index, sizeof(sstd_index));
if (trans->initiator2target_buffer_size) {
- sdRead(&SERIAL_USART_DRIVER, trans->initiator2target_buffer, trans->initiator2target_buffer_size);
+ sdRead(&SERIAL_USART_DRIVER, split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size);
+ }
+
+ // Allow any slave processing to occur
+ if (trans->slave_callback) {
+ trans->slave_callback(trans->initiator2target_buffer_size, split_trans_initiator2target_buffer(trans), trans->target2initiator_buffer_size, split_trans_target2initiator_buffer(trans));
}
if (trans->target2initiator_buffer_size) {
- sdWrite(&SERIAL_USART_DRIVER, trans->target2initiator_buffer, trans->target2initiator_buffer_size);
+ sdWrite(&SERIAL_USART_DRIVER, split_trans_target2initiator_buffer(trans), trans->target2initiator_buffer_size);
}
if (trans->status) {
@@ -160,17 +152,14 @@ void handle_soft_serial_slave(void) {
// TRANSACTION_END
// TRANSACTION_NO_RESPONSE
// TRANSACTION_DATA_ERROR
-#ifndef SERIAL_USE_MULTI_TRANSACTION
-int soft_serial_transaction(void) {
- uint8_t sstd_index = 0;
-#else
int soft_serial_transaction(int index) {
uint8_t sstd_index = index;
-#endif
- if (sstd_index > Transaction_table_size) return TRANSACTION_TYPE_ERROR;
- SSTD_t* trans = &Transaction_table[sstd_index];
- msg_t res = 0;
+ if (sstd_index > NUM_TOTAL_TRANSACTIONS) return TRANSACTION_TYPE_ERROR;
+ split_transaction_desc_t* trans = &split_transaction_table[sstd_index];
+ msg_t res = 0;
+
+ if (!trans->status) return TRANSACTION_TYPE_ERROR; // not registered
sdClear(&SERIAL_USART_DRIVER);
@@ -189,7 +178,7 @@ int soft_serial_transaction(int index) {
}
if (trans->initiator2target_buffer_size) {
- res = sdWriteTimeout(&SERIAL_USART_DRIVER, trans->initiator2target_buffer, trans->initiator2target_buffer_size, TIME_MS2I(SERIAL_USART_TIMEOUT));
+ res = sdWriteTimeout(&SERIAL_USART_DRIVER, split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size, TIME_MS2I(SERIAL_USART_TIMEOUT));
if (res < 0) {
dprintf("serial::usart_transmit NO_RESPONSE\n");
return TRANSACTION_NO_RESPONSE;
@@ -197,7 +186,7 @@ int soft_serial_transaction(int index) {
}
if (trans->target2initiator_buffer_size) {
- res = sdReadTimeout(&SERIAL_USART_DRIVER, trans->target2initiator_buffer, trans->target2initiator_buffer_size, TIME_MS2I(SERIAL_USART_TIMEOUT));
+ res = sdReadTimeout(&SERIAL_USART_DRIVER, split_trans_target2initiator_buffer(trans), trans->target2initiator_buffer_size, TIME_MS2I(SERIAL_USART_TIMEOUT));
if (res < 0) {
dprintf("serial::usart_receive NO_RESPONSE\n");
return TRANSACTION_NO_RESPONSE;
diff --git a/drivers/chibios/spi_master.c b/drivers/chibios/spi_master.c
index 4852a6eba4..28ddcbb2ba 100644
--- a/drivers/chibios/spi_master.c
+++ b/drivers/chibios/spi_master.c
@@ -18,8 +18,13 @@
#include "timer.h"
-static pin_t currentSlavePin = NO_PIN;
-static SPIConfig spiConfig = {false, NULL, 0, 0, 0, 0};
+static pin_t currentSlavePin = NO_PIN;
+
+#if defined(K20x) || defined(KL2x)
+static SPIConfig spiConfig = {NULL, 0, 0, 0};
+#else
+static SPIConfig spiConfig = {false, NULL, 0, 0, 0, 0};
+#endif
__attribute__((weak)) void spi_init(void) {
static bool is_initialised = false;
@@ -27,15 +32,15 @@ __attribute__((weak)) void spi_init(void) {
is_initialised = true;
// 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);
+ setPinInput(SPI_SCK_PIN);
+ setPinInput(SPI_MOSI_PIN);
+ setPinInput(SPI_MISO_PIN);
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), SPI_SCK_PAL_MODE);
+ palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), SPI_MOSI_PAL_MODE);
+ palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), SPI_MISO_PAL_MODE);
#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);
@@ -58,6 +63,54 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
return false;
}
+#if defined(K20x) || defined(KL2x)
+ spiConfig.tar0 = SPIx_CTARn_FMSZ(7) | SPIx_CTARn_ASC(1);
+
+ if (lsbFirst) {
+ spiConfig.tar0 |= SPIx_CTARn_LSBFE;
+ }
+
+ switch (mode) {
+ case 0:
+ break;
+ case 1:
+ spiConfig.tar0 |= SPIx_CTARn_CPHA;
+ break;
+ case 2:
+ spiConfig.tar0 |= SPIx_CTARn_CPOL;
+ break;
+ case 3:
+ spiConfig.tar0 |= SPIx_CTARn_CPHA | SPIx_CTARn_CPOL;
+ break;
+ }
+
+ switch (roundedDivisor) {
+ case 2:
+ spiConfig.tar0 |= SPIx_CTARn_BR(0);
+ break;
+ case 4:
+ spiConfig.tar0 |= SPIx_CTARn_BR(1);
+ break;
+ case 8:
+ spiConfig.tar0 |= SPIx_CTARn_BR(3);
+ break;
+ case 16:
+ spiConfig.tar0 |= SPIx_CTARn_BR(4);
+ break;
+ case 32:
+ spiConfig.tar0 |= SPIx_CTARn_BR(5);
+ break;
+ case 64:
+ spiConfig.tar0 |= SPIx_CTARn_BR(6);
+ break;
+ case 128:
+ spiConfig.tar0 |= SPIx_CTARn_BR(7);
+ break;
+ case 256:
+ spiConfig.tar0 |= SPIx_CTARn_BR(8);
+ break;
+ }
+#else
spiConfig.cr1 = 0;
if (lsbFirst) {
@@ -103,6 +156,7 @@ bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
spiConfig.cr1 |= SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0;
break;
}
+#endif
currentSlavePin = slavePin;
spiConfig.ssport = PAL_PORT(slavePin);
diff --git a/drivers/chibios/spi_master.h b/drivers/chibios/spi_master.h
index e93580e319..b5a6ef1437 100644
--- a/drivers/chibios/spi_master.h
+++ b/drivers/chibios/spi_master.h
@@ -21,6 +21,7 @@
#include <stdbool.h>
#include "gpio.h"
+#include "chibios_config.h"
#ifndef SPI_DRIVER
# define SPI_DRIVER SPID2
@@ -31,7 +32,11 @@
#endif
#ifndef SPI_SCK_PAL_MODE
-# define SPI_SCK_PAL_MODE 5
+# if defined(USE_GPIOV1)
+# define SPI_SCK_PAL_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL
+# else
+# define SPI_SCK_PAL_MODE 5
+# endif
#endif
#ifndef SPI_MOSI_PIN
@@ -39,7 +44,11 @@
#endif
#ifndef SPI_MOSI_PAL_MODE
-# define SPI_MOSI_PAL_MODE 5
+# if defined(USE_GPIOV1)
+# define SPI_MOSI_PAL_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL
+# else
+# define SPI_MOSI_PAL_MODE 5
+# endif
#endif
#ifndef SPI_MISO_PIN
@@ -47,7 +56,11 @@
#endif
#ifndef SPI_MISO_PAL_MODE
-# define SPI_MISO_PAL_MODE 5
+# if defined(USE_GPIOV1)
+# define SPI_MISO_PAL_MODE PAL_MODE_STM32_ALTERNATE_PUSHPULL
+# else
+# define SPI_MISO_PAL_MODE 5
+# endif
#endif
typedef int16_t spi_status_t;
diff --git a/drivers/haptic/haptic.c b/drivers/haptic/haptic.c
index de3f400527..3fab1be1ae 100644
--- a/drivers/haptic/haptic.c
+++ b/drivers/haptic/haptic.c
@@ -291,6 +291,73 @@ void haptic_play(void) {
#endif
}
+__attribute__((weak)) bool get_haptic_enabled_key(uint16_t keycode, keyrecord_t *record) {
+ switch(keycode) {
+# ifdef NO_HAPTIC_MOD
+ case QK_MOD_TAP ... QK_MOD_TAP_MAX:
+ if (record->tap.count == 0) return false;
+ break;
+ case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX:
+ if (record->tap.count != TAPPING_TOGGLE) return false;
+ break;
+ case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
+ if (record->tap.count == 0) return false;
+ break;
+ case KC_LCTRL ... KC_RGUI:
+ case QK_MOMENTARY ... QK_MOMENTARY_MAX:
+# endif
+# ifdef NO_HAPTIC_FN
+ case KC_FN0 ... KC_FN31:
+# endif
+# ifdef NO_HAPTIC_ALPHA
+ case KC_A ... KC_Z:
+# endif
+# ifdef NO_HAPTIC_PUNCTUATION
+ case KC_ENTER:
+ case KC_ESCAPE:
+ case KC_BSPACE:
+ case KC_SPACE:
+ case KC_MINUS:
+ case KC_EQUAL:
+ case KC_LBRACKET:
+ case KC_RBRACKET:
+ case KC_BSLASH:
+ case KC_NONUS_HASH:
+ case KC_SCOLON:
+ case KC_QUOTE:
+ case KC_GRAVE:
+ case KC_COMMA:
+ case KC_SLASH:
+ case KC_DOT:
+ case KC_NONUS_BSLASH:
+# endif
+# ifdef NO_HAPTIC_LOCKKEYS
+ case KC_CAPSLOCK:
+ case KC_SCROLLLOCK:
+ case KC_NUMLOCK:
+# endif
+# ifdef NO_HAPTIC_NAV
+ case KC_PSCREEN:
+ case KC_PAUSE:
+ case KC_INSERT:
+ case KC_DELETE:
+ case KC_PGDOWN:
+ case KC_PGUP:
+ case KC_LEFT:
+ case KC_UP:
+ case KC_RIGHT:
+ case KC_DOWN:
+ case KC_END:
+ case KC_HOME:
+# endif
+# ifdef NO_HAPTIC_NUMERIC
+ case KC_1 ... KC_0:
+# endif
+ return false;
+ }
+ return true;
+}
+
bool process_haptic(uint16_t keycode, keyrecord_t *record) {
if (keycode == HPT_ON && record->event.pressed) {
haptic_enable();
@@ -335,12 +402,12 @@ bool process_haptic(uint16_t keycode, keyrecord_t *record) {
if (haptic_config.enable) {
if (record->event.pressed) {
// keypress
- if (haptic_config.feedback < 2) {
+ if (haptic_config.feedback < 2 && get_haptic_enabled_key(keycode, record)) {
haptic_play();
}
} else {
// keyrelease
- if (haptic_config.feedback > 0) {
+ if (haptic_config.feedback > 0 && get_haptic_enabled_key(keycode, record)) {
haptic_play();
}
}
diff --git a/drivers/lcd/st7565.c b/drivers/lcd/st7565.c
new file mode 100644
index 0000000000..49b13c00f1
--- /dev/null
+++ b/drivers/lcd/st7565.c
@@ -0,0 +1,496 @@
+/*
+Copyright 2021
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "st7565.h"
+
+#include <string.h>
+
+#include "keyboard.h"
+#include "progmem.h"
+#include "timer.h"
+#include "wait.h"
+
+#include ST7565_FONT_H
+
+// Fundamental Commands
+#define CONTRAST 0x81
+#define DISPLAY_ALL_ON 0xA5
+#define DISPLAY_ALL_ON_RESUME 0xA4
+#define NORMAL_DISPLAY 0xA6
+#define INVERT_DISPLAY 0xA7
+#define DISPLAY_ON 0xAF
+#define DISPLAY_OFF 0xAE
+#define NOP 0xE3
+
+// Addressing Setting Commands
+#define PAM_SETCOLUMN_LSB 0x00
+#define PAM_SETCOLUMN_MSB 0x10
+#define PAM_PAGE_ADDR 0xB0 // 0xb0 -- 0xb7
+
+// Hardware Configuration Commands
+#define DISPLAY_START_LINE 0x40
+#define SEGMENT_REMAP 0xA0
+#define SEGMENT_REMAP_INV 0xA1
+#define COM_SCAN_INC 0xC0
+#define COM_SCAN_DEC 0xC8
+#define LCD_BIAS_7 0xA3
+#define LCD_BIAS_9 0xA2
+#define RESISTOR_RATIO 0x20
+#define POWER_CONTROL 0x28
+
+// Misc defines
+#ifndef ST7565_BLOCK_COUNT
+# define ST7565_BLOCK_COUNT (sizeof(ST7565_BLOCK_TYPE) * 8)
+#endif
+#ifndef ST7565_BLOCK_SIZE
+# define ST7565_BLOCK_SIZE (ST7565_MATRIX_SIZE / ST7565_BLOCK_COUNT)
+#endif
+
+#define ST7565_ALL_BLOCKS_MASK (((((ST7565_BLOCK_TYPE)1 << (ST7565_BLOCK_COUNT - 1)) - 1) << 1) | 1)
+
+#define HAS_FLAGS(bits, flags) ((bits & flags) == flags)
+
+// Display buffer's is the same as the display memory layout
+// this is so we don't end up with rounding errors with
+// parts of the display unusable or don't get cleared correctly
+// and also allows for drawing & inverting
+uint8_t st7565_buffer[ST7565_MATRIX_SIZE];
+uint8_t * st7565_cursor;
+ST7565_BLOCK_TYPE st7565_dirty = 0;
+bool st7565_initialized = false;
+bool st7565_active = false;
+bool st7565_inverted = false;
+display_rotation_t st7565_rotation = DISPLAY_ROTATION_0;
+#if ST7565_TIMEOUT > 0
+uint32_t st7565_timeout;
+#endif
+#if ST7565_UPDATE_INTERVAL > 0
+uint16_t st7565_update_timeout;
+#endif
+
+// Flips the rendering bits for a character at the current cursor position
+static void InvertCharacter(uint8_t *cursor) {
+ const uint8_t *end = cursor + ST7565_FONT_WIDTH;
+ while (cursor < end) {
+ *cursor = ~(*cursor);
+ cursor++;
+ }
+}
+
+bool st7565_init(display_rotation_t rotation) {
+ setPinOutput(ST7565_A0_PIN);
+ writePinHigh(ST7565_A0_PIN);
+ setPinOutput(ST7565_RST_PIN);
+ writePinHigh(ST7565_RST_PIN);
+
+ st7565_rotation = st7565_init_user(rotation);
+
+ spi_init();
+ spi_start(ST7565_SS_PIN, false, 0, ST7565_SPI_CLK_DIVISOR);
+
+ st7565_reset();
+
+ st7565_send_cmd(LCD_BIAS_7);
+ if (!HAS_FLAGS(st7565_rotation, DISPLAY_ROTATION_180)) {
+ st7565_send_cmd(SEGMENT_REMAP);
+ st7565_send_cmd(COM_SCAN_DEC);
+ } else {
+ st7565_send_cmd(SEGMENT_REMAP_INV);
+ st7565_send_cmd(COM_SCAN_INC);
+ }
+ st7565_send_cmd(DISPLAY_START_LINE | 0x00);
+ st7565_send_cmd(CONTRAST);
+ st7565_send_cmd(ST7565_CONTRAST);
+ st7565_send_cmd(RESISTOR_RATIO | 0x01);
+ st7565_send_cmd(POWER_CONTROL | 0x04);
+ wait_ms(50);
+ st7565_send_cmd(POWER_CONTROL | 0x06);
+ wait_ms(50);
+ st7565_send_cmd(POWER_CONTROL | 0x07);
+ wait_ms(10);
+ st7565_send_cmd(DISPLAY_ON);
+ st7565_send_cmd(DISPLAY_ALL_ON_RESUME);
+ st7565_send_cmd(NORMAL_DISPLAY);
+
+ spi_stop();
+
+#if ST7565_TIMEOUT > 0
+ st7565_timeout = timer_read32() + ST7565_TIMEOUT;
+#endif
+
+ st7565_clear();
+ st7565_initialized = true;
+ st7565_active = true;
+ return true;
+}
+
+__attribute__((weak)) display_rotation_t st7565_init_user(display_rotation_t rotation) { return rotation; }
+
+void st7565_clear(void) {
+ memset(st7565_buffer, 0, sizeof(st7565_buffer));
+ st7565_cursor = &st7565_buffer[0];
+ st7565_dirty = ST7565_ALL_BLOCKS_MASK;
+}
+
+uint8_t crot(uint8_t a, int8_t n) {
+ const uint8_t mask = 0x7;
+ n &= mask;
+ return a << n | a >> (-n & mask);
+}
+
+void st7565_render(void) {
+ if (!st7565_initialized) {
+ return;
+ }
+
+ // Do we have work to do?
+ st7565_dirty &= ST7565_ALL_BLOCKS_MASK;
+ if (!st7565_dirty) {
+ return;
+ }
+
+ // Find first dirty block
+ uint8_t update_start = 0;
+ while (!(st7565_dirty & ((ST7565_BLOCK_TYPE)1 << update_start))) {
+ ++update_start;
+ }
+
+ // Calculate commands to set memory addressing bounds.
+ uint8_t start_page = ST7565_BLOCK_SIZE * update_start / ST7565_DISPLAY_WIDTH;
+ uint8_t start_column = ST7565_BLOCK_SIZE * update_start % ST7565_DISPLAY_WIDTH;
+ // IC has 132 segment drivers, for panels with less width we need to offset the starting column
+ if (HAS_FLAGS(st7565_rotation, DISPLAY_ROTATION_180)) {
+ start_column += (132 - ST7565_DISPLAY_WIDTH);
+ }
+
+ spi_start(ST7565_SS_PIN, false, 0, ST7565_SPI_CLK_DIVISOR);
+
+ st7565_send_cmd(PAM_PAGE_ADDR | start_page);
+ st7565_send_cmd(PAM_SETCOLUMN_LSB | ((ST7565_COLUMN_OFFSET + start_column) & 0x0f));
+ st7565_send_cmd(PAM_SETCOLUMN_MSB | ((ST7565_COLUMN_OFFSET + start_column) >> 4 & 0x0f));
+
+ st7565_send_data(&st7565_buffer[ST7565_BLOCK_SIZE * update_start], ST7565_BLOCK_SIZE);
+
+ // Turn on display if it is off
+ st7565_on();
+
+ // Clear dirty flag
+ st7565_dirty &= ~((ST7565_BLOCK_TYPE)1 << update_start);
+}
+
+void st7565_set_cursor(uint8_t col, uint8_t line) {
+ uint16_t index = line * ST7565_DISPLAY_WIDTH + col * ST7565_FONT_WIDTH;
+
+ // Out of bounds?
+ if (index >= ST7565_MATRIX_SIZE) {
+ index = 0;
+ }
+
+ st7565_cursor = &st7565_buffer[index];
+}
+
+void st7565_advance_page(bool clearPageRemainder) {
+ uint16_t index = st7565_cursor - &st7565_buffer[0];
+ uint8_t remaining = ST7565_DISPLAY_WIDTH - (index % ST7565_DISPLAY_WIDTH);
+
+ if (clearPageRemainder) {
+ // Remaining Char count
+ remaining = remaining / ST7565_FONT_WIDTH;
+
+ // Write empty character until next line
+ while (remaining--) st7565_write_char(' ', false);
+ } else {
+ // Next page index out of bounds?
+ if (index + remaining >= ST7565_MATRIX_SIZE) {
+ index = 0;
+ remaining = 0;
+ }
+
+ st7565_cursor = &st7565_buffer[index + remaining];
+ }
+}
+
+void st7565_advance_char(void) {
+ uint16_t nextIndex = st7565_cursor - &st7565_buffer[0] + ST7565_FONT_WIDTH;
+ uint8_t remainingSpace = ST7565_DISPLAY_WIDTH - (nextIndex % ST7565_DISPLAY_WIDTH);
+
+ // Do we have enough space on the current line for the next character
+ if (remainingSpace < ST7565_FONT_WIDTH) {
+ nextIndex += remainingSpace;
+ }
+
+ // Did we go out of bounds
+ if (nextIndex >= ST7565_MATRIX_SIZE) {
+ nextIndex = 0;
+ }
+
+ // Update cursor position
+ st7565_cursor = &st7565_buffer[nextIndex];
+}
+
+// Main handler that writes character data to the display buffer
+void st7565_write_char(const char data, bool invert) {
+ // Advance to the next line if newline
+ if (data == '\n') {
+ // Old source wrote ' ' until end of line...
+ st7565_advance_page(true);
+ return;
+ }
+
+ if (data == '\r') {
+ st7565_advance_page(false);
+ return;
+ }
+
+ // copy the current render buffer to check for dirty after
+ static uint8_t st7565_temp_buffer[ST7565_FONT_WIDTH];
+ memcpy(&st7565_temp_buffer, st7565_cursor, ST7565_FONT_WIDTH);
+
+ _Static_assert(sizeof(font) >= ((ST7565_FONT_END + 1 - ST7565_FONT_START) * ST7565_FONT_WIDTH), "ST7565_FONT_END references outside array");
+
+ // set the reder buffer data
+ uint8_t cast_data = (uint8_t)data; // font based on unsigned type for index
+ if (cast_data < ST7565_FONT_START || cast_data > ST7565_FONT_END) {
+ memset(st7565_cursor, 0x00, ST7565_FONT_WIDTH);
+ } else {
+ const uint8_t *glyph = &font[(cast_data - ST7565_FONT_START) * ST7565_FONT_WIDTH];
+ memcpy_P(st7565_cursor, glyph, ST7565_FONT_WIDTH);
+ }
+
+ // Invert if needed
+ if (invert) {
+ InvertCharacter(st7565_cursor);
+ }
+
+ // Dirty check
+ if (memcmp(&st7565_temp_buffer, st7565_cursor, ST7565_FONT_WIDTH)) {
+ uint16_t index = st7565_cursor - &st7565_buffer[0];
+ st7565_dirty |= ((ST7565_BLOCK_TYPE)1 << (index / ST7565_BLOCK_SIZE));
+ // Edgecase check if the written data spans the 2 chunks
+ st7565_dirty |= ((ST7565_BLOCK_TYPE)1 << ((index + ST7565_FONT_WIDTH - 1) / ST7565_BLOCK_SIZE));
+ }
+
+ // Finally move to the next char
+ st7565_advance_char();
+}
+
+void st7565_write(const char *data, bool invert) {
+ const char *end = data + strlen(data);
+ while (data < end) {
+ st7565_write_char(*data, invert);
+ data++;
+ }
+}
+
+void st7565_write_ln(const char *data, bool invert) {
+ st7565_write(data, invert);
+ st7565_advance_page(true);
+}
+
+void st7565_pan(bool left) {
+ uint16_t i = 0;
+ for (uint16_t y = 0; y < ST7565_DISPLAY_HEIGHT / 8; y++) {
+ if (left) {
+ for (uint16_t x = 0; x < ST7565_DISPLAY_WIDTH - 1; x++) {
+ i = y * ST7565_DISPLAY_WIDTH + x;
+ st7565_buffer[i] = st7565_buffer[i + 1];
+ }
+ } else {
+ for (uint16_t x = ST7565_DISPLAY_WIDTH - 1; x > 0; x--) {
+ i = y * ST7565_DISPLAY_WIDTH + x;
+ st7565_buffer[i] = st7565_buffer[i - 1];
+ }
+ }
+ }
+ st7565_dirty = ST7565_ALL_BLOCKS_MASK;
+}
+
+display_buffer_reader_t st7565_read_raw(uint16_t start_index) {
+ if (start_index > ST7565_MATRIX_SIZE) start_index = ST7565_MATRIX_SIZE;
+ display_buffer_reader_t ret_reader;
+ ret_reader.current_element = &st7565_buffer[start_index];
+ ret_reader.remaining_element_count = ST7565_MATRIX_SIZE - start_index;
+ return ret_reader;
+}
+
+void st7565_write_raw_byte(const char data, uint16_t index) {
+ if (index > ST7565_MATRIX_SIZE) index = ST7565_MATRIX_SIZE;
+ if (st7565_buffer[index] == data) return;
+ st7565_buffer[index] = data;
+ st7565_dirty |= ((ST7565_BLOCK_TYPE)1 << (index / ST7565_BLOCK_SIZE));
+}
+
+void st7565_write_raw(const char *data, uint16_t size) {
+ uint16_t cursor_start_index = st7565_cursor - &st7565_buffer[0];
+ if ((size + cursor_start_index) > ST7565_MATRIX_SIZE) size = ST7565_MATRIX_SIZE - cursor_start_index;
+ for (uint16_t i = cursor_start_index; i < cursor_start_index + size; i++) {
+ uint8_t c = *data++;
+ if (st7565_buffer[i] == c) continue;
+ st7565_buffer[i] = c;
+ st7565_dirty |= ((ST7565_BLOCK_TYPE)1 << (i / ST7565_BLOCK_SIZE));
+ }
+}
+
+void st7565_write_pixel(uint8_t x, uint8_t y, bool on) {
+ if (x >= ST7565_DISPLAY_WIDTH) {
+ return;
+ }
+ uint16_t index = x + (y / 8) * ST7565_DISPLAY_WIDTH;
+ if (index >= ST7565_MATRIX_SIZE) {
+ return;
+ }
+ uint8_t data = st7565_buffer[index];
+ if (on) {
+ data |= (1 << (y % 8));
+ } else {
+ data &= ~(1 << (y % 8));
+ }
+ if (st7565_buffer[index] != data) {
+ st7565_buffer[index] = data;
+ st7565_dirty |= ((ST7565_BLOCK_TYPE)1 << (index / ST7565_BLOCK_SIZE));
+ }
+}
+
+#if defined(__AVR__)
+void st7565_write_P(const char *data, bool invert) {
+ uint8_t c = pgm_read_byte(data);
+ while (c != 0) {
+ st7565_write_char(c, invert);
+ c = pgm_read_byte(++data);
+ }
+}
+
+void st7565_write_ln_P(const char *data, bool invert) {
+ st7565_write_P(data, invert);
+ st7565_advance_page(true);
+}
+
+void st7565_write_raw_P(const char *data, uint16_t size) {
+ uint16_t cursor_start_index = st7565_cursor - &st7565_buffer[0];
+ if ((size + cursor_start_index) > ST7565_MATRIX_SIZE) size = ST7565_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 (st7565_buffer[i] == c) continue;
+ st7565_buffer[i] = c;
+ st7565_dirty |= ((ST7565_BLOCK_TYPE)1 << (i / ST7565_BLOCK_SIZE));
+ }
+}
+#endif // defined(__AVR__)
+
+bool st7565_on(void) {
+ if (!st7565_initialized) {
+ return st7565_active;
+ }
+
+#if ST7565_TIMEOUT > 0
+ st7565_timeout = timer_read32() + ST7565_TIMEOUT;
+#endif
+
+ if (!st7565_active) {
+ spi_start(ST7565_SS_PIN, false, 0, ST7565_SPI_CLK_DIVISOR);
+ st7565_send_cmd(DISPLAY_ON);
+ spi_stop();
+ st7565_active = true;
+ st7565_on_user();
+ }
+ return st7565_active;
+}
+
+__attribute__((weak)) void st7565_on_user(void) {}
+
+bool st7565_off(void) {
+ if (!st7565_initialized) {
+ return !st7565_active;
+ }
+
+ if (st7565_active) {
+ spi_start(ST7565_SS_PIN, false, 0, ST7565_SPI_CLK_DIVISOR);
+ st7565_send_cmd(DISPLAY_OFF);
+ spi_stop();
+ st7565_active = false;
+ st7565_off_user();
+ }
+ return !st7565_active;
+}
+
+__attribute__((weak)) void st7565_off_user(void) {}
+
+bool st7565_is_on(void) { return st7565_active; }
+
+bool st7565_invert(bool invert) {
+ if (!st7565_initialized) {
+ return st7565_inverted;
+ }
+
+ if (invert != st7565_inverted) {
+ spi_start(ST7565_SS_PIN, false, 0, ST7565_SPI_CLK_DIVISOR);
+ st7565_send_cmd(invert ? INVERT_DISPLAY : NORMAL_DISPLAY);
+ spi_stop();
+ st7565_inverted = invert;
+ }
+ return st7565_inverted;
+}
+
+uint8_t st7565_max_chars(void) { return ST7565_DISPLAY_WIDTH / ST7565_FONT_WIDTH; }
+
+uint8_t st7565_max_lines(void) { return ST7565_DISPLAY_HEIGHT / ST7565_FONT_HEIGHT; }
+
+void st7565_task(void) {
+ if (!st7565_initialized) {
+ return;
+ }
+
+#if ST7565_UPDATE_INTERVAL > 0
+ if (timer_elapsed(st7565_update_timeout) >= ST7565_UPDATE_INTERVAL) {
+ st7565_update_timeout = timer_read();
+ st7565_set_cursor(0, 0);
+ st7565_task_user();
+ }
+#else
+ st7565_set_cursor(0, 0);
+ st7565_task_user();
+#endif
+
+ // Smart render system, no need to check for dirty
+ st7565_render();
+
+ // Display timeout check
+#if ST7565_TIMEOUT > 0
+ if (st7565_active && timer_expired32(timer_read32(), st7565_timeout)) {
+ st7565_off();
+ }
+#endif
+}
+
+__attribute__((weak)) void st7565_task_user(void) {}
+
+void st7565_reset(void) {
+ writePinLow(ST7565_RST_PIN);
+ wait_ms(20);
+ writePinHigh(ST7565_RST_PIN);
+ wait_ms(20);
+}
+
+spi_status_t st7565_send_cmd(uint8_t cmd) {
+ writePinLow(ST7565_A0_PIN);
+ return spi_write(cmd);
+}
+
+spi_status_t st7565_send_data(uint8_t *data, uint16_t length) {
+ writePinHigh(ST7565_A0_PIN);
+ return spi_transmit(data, length);
+}
diff --git a/drivers/lcd/st7565.h b/drivers/lcd/st7565.h
new file mode 100644
index 0000000000..d453dbe6da
--- /dev/null
+++ b/drivers/lcd/st7565.h
@@ -0,0 +1,219 @@
+/*
+Copyright 2021
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "spi_master.h"
+
+#ifndef ST7565_DISPLAY_WIDTH
+# define ST7565_DISPLAY_WIDTH 128
+#endif
+#ifndef ST7565_DISPLAY_HEIGHT
+# define ST7565_DISPLAY_HEIGHT 32
+#endif
+#ifndef ST7565_MATRIX_SIZE
+# define ST7565_MATRIX_SIZE (ST7565_DISPLAY_HEIGHT / 8 * ST7565_DISPLAY_WIDTH) // 1024 (compile time mathed)
+#endif
+#ifndef ST7565_BLOCK_TYPE
+# define ST7565_BLOCK_TYPE uint16_t
+#endif
+#ifndef ST7565_BLOCK_COUNT
+# define ST7565_BLOCK_COUNT (sizeof(ST7565_BLOCK_TYPE) * 8) // 32 (compile time mathed)
+#endif
+#ifndef ST7565_BLOCK_SIZE
+# define ST7565_BLOCK_SIZE (ST7565_MATRIX_SIZE / ST7565_BLOCK_COUNT) // 32 (compile time mathed)
+#endif
+
+// the column address corresponding to the first column in the display hardware
+#if !defined(ST7565_COLUMN_OFFSET)
+# define ST7565_COLUMN_OFFSET 0
+#endif
+
+// spi clock divisor
+#if !defined(ST7565_SPI_CLK_DIVISOR)
+# define ST7565_SPI_CLK_DIVISOR 4
+#endif
+
+// Custom font file to use
+#if !defined(ST7565_FONT_H)
+# define ST7565_FONT_H "glcdfont.c"
+#endif
+// unsigned char value of the first character in the font file
+#if !defined(ST7565_FONT_START)
+# define ST7565_FONT_START 0
+#endif
+// unsigned char value of the last character in the font file
+#if !defined(ST7565_FONT_END)
+# define ST7565_FONT_END 223
+#endif
+// Font render width
+#if !defined(ST7565_FONT_WIDTH)
+# define ST7565_FONT_WIDTH 6
+#endif
+// Font render height
+#if !defined(ST7565_FONT_HEIGHT)
+# define ST7565_FONT_HEIGHT 8
+#endif
+// Default contrast level
+#if !defined(ST7565_CONTRAST)
+# define ST7565_CONTRAST 32
+#endif
+
+#if !defined(ST7565_TIMEOUT)
+# if defined(ST7565_DISABLE_TIMEOUT)
+# define ST7565_TIMEOUT 0
+# else
+# define ST7565_TIMEOUT 60000
+# endif
+#endif
+
+#if !defined(ST7565_UPDATE_INTERVAL) && defined(SPLIT_KEYBOARD)
+# define ST7565_UPDATE_INTERVAL 50
+#endif
+
+typedef struct __attribute__((__packed__)) {
+ uint8_t *current_element;
+ uint16_t remaining_element_count;
+} display_buffer_reader_t;
+
+// Rotation enum values are flags
+typedef enum { DISPLAY_ROTATION_0, DISPLAY_ROTATION_180 } display_rotation_t;
+
+// Initialize the display, rotating the rendered output based on the define passed in.
+// Returns true if the display was initialized successfully
+bool st7565_init(display_rotation_t rotation);
+
+// Called at the start of st7565_init, weak function overridable by the user
+// rotation - the value passed into st7565_init
+// Return new display_rotation_t if you want to override default rotation
+display_rotation_t st7565_init_user(display_rotation_t rotation);
+
+// Clears the display buffer, resets cursor position to 0, and sets the buffer to dirty for rendering
+void st7565_clear(void);
+
+// Renders the dirty chunks of the buffer to display
+void st7565_render(void);
+
+// Moves cursor to character position indicated by column and line, wraps if out of bounds
+// Max column denoted by 'st7565_max_chars()' and max lines by 'st7565_max_lines()' functions
+void st7565_set_cursor(uint8_t col, uint8_t line);
+
+// Advances the cursor to the next page, writing ' ' if true
+// Wraps to the begining when out of bounds
+void st7565_advance_page(bool clearPageRemainder);
+
+// Moves the cursor forward 1 character length
+// Advance page if there is not enough room for the next character
+// Wraps to the begining when out of bounds
+void st7565_advance_char(void);
+
+// Writes a single character to the buffer at current cursor position
+// Advances the cursor while writing, inverts the pixels if true
+// Main handler that writes character data to the display buffer
+void st7565_write_char(const char data, bool invert);
+
+// Writes a string to the buffer at current cursor position
+// Advances the cursor while writing, inverts the pixels if true
+void st7565_write(const char *data, bool invert);
+
+// Writes a string to the buffer at current cursor position
+// Advances the cursor while writing, inverts the pixels if true
+// Advances the cursor to the next page, wiring ' ' to the remainder of the current page
+void st7565_write_ln(const char *data, bool invert);
+
+// Pans the buffer to the right (or left by passing true) by moving contents of the buffer
+// Useful for moving the screen in preparation for new drawing
+void st7565_pan(bool left);
+
+// Returns a pointer to the requested start index in the buffer plus remaining
+// buffer length as struct
+display_buffer_reader_t st7565_read_raw(uint16_t start_index);
+
+// Writes a string to the buffer at current cursor position
+void st7565_write_raw(const char *data, uint16_t size);
+
+// Writes a single byte into the buffer at the specified index
+void st7565_write_raw_byte(const char data, uint16_t index);
+
+// Sets a specific pixel on or off
+// Coordinates start at top-left and go right and down for positive x and y
+void st7565_write_pixel(uint8_t x, uint8_t y, bool on);
+
+#if defined(__AVR__)
+// Writes a PROGMEM string to the buffer at current cursor position
+// Advances the cursor while writing, inverts the pixels if true
+// Remapped to call 'void st7565_write(const char *data, bool invert);' on ARM
+void st7565_write_P(const char *data, bool invert);
+
+// Writes a PROGMEM string to the buffer at current cursor position
+// Advances the cursor while writing, inverts the pixels if true
+// Advances the cursor to the next page, wiring ' ' to the remainder of the current page
+// Remapped to call 'void st7565_write_ln(const char *data, bool invert);' on ARM
+void st7565_write_ln_P(const char *data, bool invert);
+
+// Writes a PROGMEM string to the buffer at current cursor position
+void st7565_write_raw_P(const char *data, uint16_t size);
+#else
+# define st7565_write_P(data, invert) st7565_write(data, invert)
+# define st7565_write_ln_P(data, invert) st7565_write_ln(data, invert)
+# define st7565_write_raw_P(data, size) st7565_write_raw(data, size)
+#endif // defined(__AVR__)
+
+// Can be used to manually turn on the screen if it is off
+// Returns true if the screen was on or turns on
+bool st7565_on(void);
+
+// Called when st7565_on() turns on the screen, weak function overridable by the user
+// Not called if the screen is already on
+void st7565_on_user(void);
+
+// Can be used to manually turn off the screen if it is on
+// Returns true if the screen was off or turns off
+bool st7565_off(void);
+
+// Called when st7565_off() turns off the screen, weak function overridable by the user
+// Not called if the screen is already off
+void st7565_off_user(void);
+
+// Returns true if the screen is currently on, false if it is
+// not
+bool st7565_is_on(void);
+
+// Basically it's st7565_render, but with timeout management and st7565_task_user calling!
+void st7565_task(void);
+
+// Called at the start of st7565_task, weak function overridable by the user
+void st7565_task_user(void);
+
+// Inverts the display
+// Returns true if the screen was or is inverted
+bool st7565_invert(bool invert);
+
+// Returns the maximum number of characters that will fit on a line
+uint8_t st7565_max_chars(void);
+
+// Returns the maximum number of lines that will fit on the display
+uint8_t st7565_max_lines(void);
+
+void st7565_reset(void);
+
+spi_status_t st7565_send_cmd(uint8_t cmd);
+
+spi_status_t st7565_send_data(uint8_t *data, uint16_t length);
diff --git a/drivers/oled/oled_driver.c b/drivers/oled/oled_driver.c
index 8e5ed5f070..7d41978905 100644
--- a/drivers/oled/oled_driver.c
+++ b/drivers/oled/oled_driver.c
@@ -34,6 +34,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define DISPLAY_ALL_ON 0xA5
#define DISPLAY_ALL_ON_RESUME 0xA4
#define NORMAL_DISPLAY 0xA6
+#define INVERT_DISPLAY 0xA7
#define DISPLAY_ON 0xAF
#define DISPLAY_OFF 0xAE
#define NOP 0xE3
@@ -114,6 +115,7 @@ OLED_BLOCK_TYPE oled_dirty = 0;
bool oled_initialized = false;
bool oled_active = false;
bool oled_scrolling = false;
+bool oled_inverted = false;
uint8_t oled_brightness = OLED_BRIGHTNESS;
oled_rotation_t oled_rotation = 0;
uint8_t oled_rotation_width = 0;
@@ -690,6 +692,30 @@ bool oled_scroll_off(void) {
return !oled_scrolling;
}
+bool oled_invert(bool invert) {
+ if (!oled_initialized) {
+ return oled_inverted;
+ }
+
+ if (invert && !oled_inverted) {
+ static const uint8_t PROGMEM display_inverted[] = {I2C_CMD, INVERT_DISPLAY};
+ if (I2C_TRANSMIT_P(display_inverted) != I2C_STATUS_SUCCESS) {
+ print("oled_invert cmd failed\n");
+ return oled_inverted;
+ }
+ oled_inverted = true;
+ } else if (!invert && oled_inverted) {
+ static const uint8_t PROGMEM display_normal[] = {I2C_CMD, NORMAL_DISPLAY};
+ if (I2C_TRANSMIT_P(display_normal) != I2C_STATUS_SUCCESS) {
+ print("oled_invert cmd failed\n");
+ return oled_inverted;
+ }
+ oled_inverted = false;
+ }
+
+ return oled_inverted;
+}
+
uint8_t oled_max_chars(void) {
if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
return OLED_DISPLAY_WIDTH / OLED_FONT_WIDTH;
diff --git a/drivers/oled/oled_driver.h b/drivers/oled/oled_driver.h
index a6b85f37e6..fc68f0ec95 100644
--- a/drivers/oled/oled_driver.h
+++ b/drivers/oled/oled_driver.h
@@ -313,6 +313,10 @@ bool oled_scroll_left(void);
// Returns true if the screen was not scrolling or stops scrolling
bool oled_scroll_off(void);
+// Inverts the display
+// Returns true if the screen was or is inverted
+bool oled_invert(bool invert);
+
// Returns the maximum number of characters that will fit on a line
uint8_t oled_max_chars(void);
diff --git a/drivers/serial.h b/drivers/serial.h
new file mode 100644
index 0000000000..d9c2a69e96
--- /dev/null
+++ b/drivers/serial.h
@@ -0,0 +1,46 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <transactions.h>
+
+// initiator is transaction start side
+void soft_serial_initiator_init(void);
+// target is interrupt accept side
+void soft_serial_target_init(void);
+
+// initiator result
+#define TRANSACTION_END 0
+#define TRANSACTION_NO_RESPONSE 0x1
+#define TRANSACTION_DATA_ERROR 0x2
+#define TRANSACTION_TYPE_ERROR 0x4
+int soft_serial_transaction(int sstd_index);
+
+// target status
+// *SSTD_t.status has
+// initiator:
+// TRANSACTION_END
+// or TRANSACTION_NO_RESPONSE
+// or TRANSACTION_DATA_ERROR
+// target:
+// TRANSACTION_DATA_ERROR
+// or TRANSACTION_ACCEPTED
+#define TRANSACTION_ACCEPTED 0x8
+int soft_serial_get_and_clean_status(int sstd_index);
diff --git a/keyboards/anavi/macropad8/keymaps/default/config.h b/keyboards/anavi/macropad8/keymaps/default/config.h
new file mode 100644
index 0000000000..dd687cad58
--- /dev/null
+++ b/keyboards/anavi/macropad8/keymaps/default/config.h
@@ -0,0 +1,19 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#define LAYER_STATE_8BIT
diff --git a/keyboards/basekeys/trifecta/config.h b/keyboards/basekeys/trifecta/config.h
index 8a95291260..28c9c18fb2 100644
--- a/keyboards/basekeys/trifecta/config.h
+++ b/keyboards/basekeys/trifecta/config.h
@@ -80,11 +80,11 @@
# define RGB_MATRIX_KEYPRESSES // reacts to keypresses
// # define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (instead of keypresses)
// # define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-//# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+//# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
# define RGB_MATRIX_LED_PROCESS_LIMIT (DRIVER_LED_TOTAL + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
# define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
-# define RGB_MATRIX_MAXIMUM_BRIGHTNESS 150 // limits maximum brightness of LEDs to 150 out of 255. Higher may cause the controller to crash.
+# define RGB_MATRIX_MAXIMUM_BRIGHTNESS 150 // limits maximum brightness of LEDs to 150 out of 255. Higher may cause the controller to crash.
# define RGB_MATRIX_HUE_STEP 8
# define RGB_MATRIX_SAT_STEP 8
# define RGB_MATRIX_VAL_STEP 8
diff --git a/keyboards/bm40hsrgb/config.h b/keyboards/bm40hsrgb/config.h
index 167a5667a4..8ef9a78c7d 100755
--- a/keyboards/bm40hsrgb/config.h
+++ b/keyboards/bm40hsrgb/config.h
@@ -50,6 +50,6 @@
#ifdef RGB_DI_PIN
#define RGB_MATRIX_KEYPRESSES // reacts to keypresses
#endif
-#ifndef RGB_DISABLE_WHEN_USB_SUSPENDED
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+#ifdef RGB_MATRIX_ENABLE
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#endif
diff --git a/keyboards/bm68rgb/keymaps/peepeetee/config.h b/keyboards/bm68rgb/keymaps/peepeetee/config.h
index 53eebce7f2..aada255cd7 100644
--- a/keyboards/bm68rgb/keymaps/peepeetee/config.h
+++ b/keyboards/bm68rgb/keymaps/peepeetee/config.h
@@ -64,7 +64,7 @@
// #define RGBLIGHT_SAT_STEP 25 // Units to step when in/decreasing saturation
// #define RGBLIGHT_VAL_STEP 12 // Units to step when in/decreasing value (brightness)
// #define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-// #define RGB_DISABLE_WHEN_USB_SUSPENDED false // turn off effects when suspended
+// #define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
// #define RGB_MATRIX_LED_PROCESS_LIMIT (DRIVER_LED_TOTAL + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
// #define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
// #define RGBLIGHT_ANIMATIONS // Run RGB animations
diff --git a/keyboards/boardsource/the_mark/config.h b/keyboards/boardsource/the_mark/config.h
index 5888452ce4..9ca598b40e 100644
--- a/keyboards/boardsource/the_mark/config.h
+++ b/keyboards/boardsource/the_mark/config.h
@@ -59,7 +59,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define DRIVER_LED_TOTAL 24 // Number of LEDs
#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 200
# ifndef RGB_DISABLE_WHEN_USB_SUSPENDED
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# endif
#endif
diff --git a/keyboards/crkbd/keymaps/devdev/config.h b/keyboards/crkbd/keymaps/devdev/config.h
index 793c7b020b..c858f8f2d0 100644
--- a/keyboards/crkbd/keymaps/devdev/config.h
+++ b/keyboards/crkbd/keymaps/devdev/config.h
@@ -32,7 +32,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define CUSTOM_FONT
-#define CUSTOM_LAYER_READ //if you remove this it causes issues - needs better guarding
+#define CUSTOM_LAYER_READ //if you remove this it causes issues - needs better guarding
#define TAPPING_FORCE_HOLD
#define TAPPING_TERM 200
@@ -43,7 +43,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef RGBLIGHT_ENABLE
#undef RGBLED_NUM
-
+
//#define RGBLIGHT_ANIMATIONS
#define RGBLIGHT_EFFECT_BREATHING
#define RGBLIGHT_EFFECT_RAINBOW_MOOD
@@ -55,11 +55,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
//#define RGBLIGHT_EFFECT_RGB_TEST
//#define RGBLIGHT_EFFECT_ALTERNATING
//#define RGBLIGHT_EFFECT_TWINKLE
-
+
//#define RGBLED_NUM 54
//#define RGBLED_SPLIT 27
- //#define RGBLED_SPLIT { 27, 27 } // haven't figured out how to use this yet
-
+ //#define RGBLED_SPLIT { 27, 27 } // haven't figured out how to use this yet
+
#define RGBLED_NUM 27
#define RGBLIGHT_LIMIT_VAL 120
#define RGBLIGHT_HUE_STEP 10
@@ -71,11 +71,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
# define RGB_MATRIX_KEYPRESSES // reacts to keypresses
// # define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (instead of keypresses)
// # define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
// # define RGB_MATRIX_LED_PROCESS_LIMIT (DRIVER_LED_TOTAL + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
// # define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
-# define RGB_MATRIX_MAXIMUM_BRIGHTNESS 150 // limits maximum brightness of LEDs to 150 out of 255. Higher may cause the controller to crash.
+# define RGB_MATRIX_MAXIMUM_BRIGHTNESS 150 // limits maximum brightness of LEDs to 150 out of 255. Higher may cause the controller to crash.
#define RGB_MATRIX_STARTUP_MODE RGB_MATRIX_GRADIENT_LEFT_RIGHT
diff --git a/keyboards/crkbd/keymaps/gotham/config.h b/keyboards/crkbd/keymaps/gotham/config.h
index dd58a0fe05..05b04e0aa3 100644
--- a/keyboards/crkbd/keymaps/gotham/config.h
+++ b/keyboards/crkbd/keymaps/gotham/config.h
@@ -39,7 +39,7 @@
#ifdef RGB_MATRIX_ENABLE
# define RGB_MATRIX_KEYPRESSES // reacts to keypresses
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_MAXIMUM_BRIGHTNESS 150 // limits maximum brightness of LEDs to 150 out of 255. Higher may cause the controller to crash.
# define RGB_MATRIX_HUE_STEP 32
# define RGB_MATRIX_SAT_STEP 64
diff --git a/keyboards/crkbd/keymaps/kidbrazil/config.h b/keyboards/crkbd/keymaps/kidbrazil/config.h
index be1777e575..752ea862e0 100644
--- a/keyboards/crkbd/keymaps/kidbrazil/config.h
+++ b/keyboards/crkbd/keymaps/kidbrazil/config.h
@@ -56,7 +56,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
//# define RGB_MATRIX_KEYPRESSES // reacts to keypresses
// # define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (instead of keypresses)
// # define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
- #define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+ #define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_FRAMEBUFFER_EFFECTS
// # define RGB_MATRIX_LED_PROCESS_LIMIT (DRIVER_LED_TOTAL + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
// # define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
diff --git a/keyboards/crkbd/keymaps/rpbaptist/config.h b/keyboards/crkbd/keymaps/rpbaptist/config.h
index 6bd16725f5..9e5f75c362 100644
--- a/keyboards/crkbd/keymaps/rpbaptist/config.h
+++ b/keyboards/crkbd/keymaps/rpbaptist/config.h
@@ -42,7 +42,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define NO_ACTION_ONESHOT
#ifdef RGB_MATRIX_ENABLE
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_MAXIMUM_BRIGHTNESS 150
# define RGB_MATRIX_HUE_STEP 8
diff --git a/keyboards/crkbd/keymaps/soundmonster/config.h b/keyboards/crkbd/keymaps/soundmonster/config.h
index 1e58af3abe..8235b48697 100644
--- a/keyboards/crkbd/keymaps/soundmonster/config.h
+++ b/keyboards/crkbd/keymaps/soundmonster/config.h
@@ -59,11 +59,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
# define RGB_MATRIX_KEYPRESSES // reacts to keypresses
// # define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (instead of keypresses)
// # define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
# define RGB_MATRIX_LED_PROCESS_LIMIT (DRIVER_LED_TOTAL + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
# define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
-# define RGB_MATRIX_MAXIMUM_BRIGHTNESS 150 // limits maximum brightness of LEDs to 150 out of 255. Higher may cause the controller to crash.
+# define RGB_MATRIX_MAXIMUM_BRIGHTNESS 150 // limits maximum brightness of LEDs to 150 out of 255. Higher may cause the controller to crash.
# define RGB_MATRIX_HUE_STEP 8
# define RGB_MATRIX_SAT_STEP 8
# define RGB_MATRIX_VAL_STEP 8
diff --git a/keyboards/crkbd/readme.md b/keyboards/crkbd/readme.md
index 1e5bfb39ab..f0b5672cf6 100644
--- a/keyboards/crkbd/readme.md
+++ b/keyboards/crkbd/readme.md
@@ -38,7 +38,7 @@ And in your `config.h` file, add the following:
# define RGB_MATRIX_KEYPRESSES // reacts to keypresses
// # define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (instead of keypresses)
// # define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
// # define RGB_MATRIX_LED_PROCESS_LIMIT (DRIVER_LED_TOTAL + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
// # define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
diff --git a/keyboards/draculad/config.h b/keyboards/draculad/config.h
index 8a27fdea4d..d8a9fbd37c 100644
--- a/keyboards/draculad/config.h
+++ b/keyboards/draculad/config.h
@@ -65,3 +65,5 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define UNUSED_PINS
#define EE_HANDS
+
+#define LAYER_STATE_8BIT \ No newline at end of file
diff --git a/keyboards/dztech/dz60rgb/v1/config.h b/keyboards/dztech/dz60rgb/v1/config.h
index 6e5b3da6ff..f6ee7c4e2f 100644
--- a/keyboards/dztech/dz60rgb/v1/config.h
+++ b/keyboards/dztech/dz60rgb/v1/config.h
@@ -37,7 +37,7 @@
#ifdef RGB_MATRIX_ENABLE
# define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_KEYPRESSES
# define RGB_MATRIX_LED_PROCESS_LIMIT 4
# define RGB_MATRIX_LED_FLUSH_LIMIT 26
diff --git a/keyboards/dztech/dz60rgb/v2/config.h b/keyboards/dztech/dz60rgb/v2/config.h
index df84fff59a..6108e99034 100644
--- a/keyboards/dztech/dz60rgb/v2/config.h
+++ b/keyboards/dztech/dz60rgb/v2/config.h
@@ -37,7 +37,7 @@
#ifdef RGB_MATRIX_ENABLE
# define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_KEYPRESSES
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
# define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
diff --git a/keyboards/dztech/dz60rgb_ansi/v1/config.h b/keyboards/dztech/dz60rgb_ansi/v1/config.h
index 8710f8d07b..dc2a6f4bc0 100644
--- a/keyboards/dztech/dz60rgb_ansi/v1/config.h
+++ b/keyboards/dztech/dz60rgb_ansi/v1/config.h
@@ -37,7 +37,7 @@
#ifdef RGB_MATRIX_ENABLE
# define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_KEYPRESSES
# define RGB_MATRIX_LED_PROCESS_LIMIT 4
# define RGB_MATRIX_LED_FLUSH_LIMIT 26
diff --git a/keyboards/dztech/dz60rgb_ansi/v2/config.h b/keyboards/dztech/dz60rgb_ansi/v2/config.h
index f3c9b73fb4..6c1e006821 100644
--- a/keyboards/dztech/dz60rgb_ansi/v2/config.h
+++ b/keyboards/dztech/dz60rgb_ansi/v2/config.h
@@ -37,7 +37,7 @@
#ifdef RGB_MATRIX_ENABLE
# define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_KEYPRESSES
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
# define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
diff --git a/keyboards/dztech/dz60rgb_wkl/v1/config.h b/keyboards/dztech/dz60rgb_wkl/v1/config.h
index 9c630c75be..12317c2d35 100644
--- a/keyboards/dztech/dz60rgb_wkl/v1/config.h
+++ b/keyboards/dztech/dz60rgb_wkl/v1/config.h
@@ -37,7 +37,7 @@
#ifdef RGB_MATRIX_ENABLE
# define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_KEYPRESSES
# define RGB_MATRIX_LED_PROCESS_LIMIT 4
# define RGB_MATRIX_LED_FLUSH_LIMIT 26
diff --git a/keyboards/dztech/dz60rgb_wkl/v2/config.h b/keyboards/dztech/dz60rgb_wkl/v2/config.h
index a6145c2749..945b591ce6 100644
--- a/keyboards/dztech/dz60rgb_wkl/v2/config.h
+++ b/keyboards/dztech/dz60rgb_wkl/v2/config.h
@@ -37,7 +37,7 @@
#ifdef RGB_MATRIX_ENABLE
# define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_KEYPRESSES
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
# define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
diff --git a/keyboards/dztech/dz65rgb/v1/config.h b/keyboards/dztech/dz65rgb/v1/config.h
index adfa934b04..1ecd9002cb 100644
--- a/keyboards/dztech/dz65rgb/v1/config.h
+++ b/keyboards/dztech/dz65rgb/v1/config.h
@@ -51,9 +51,9 @@
# define RGB_MATRIX_LED_FLUSH_LIMIT 26
# define DEBOUNCE 3
# define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_KEYPRESSES
-# define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
+# define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
# define DISABLE_RGB_MATRIX_BAND_SAT
# define DISABLE_RGB_MATRIX_BAND_PINWHEEL_SAT
# define DISABLE_RGB_MATRIX_BAND_SPIRAL_SAT
diff --git a/keyboards/dztech/dz65rgb/v2/config.h b/keyboards/dztech/dz65rgb/v2/config.h
index f86d65cd06..1e1e21f5e9 100644
--- a/keyboards/dztech/dz65rgb/v2/config.h
+++ b/keyboards/dztech/dz65rgb/v2/config.h
@@ -51,7 +51,7 @@
# define RGB_MATRIX_LED_FLUSH_LIMIT 26
# define DEBOUNCE 3
# define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_KEYPRESSES
# define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
# define DISABLE_RGB_MATRIX_BAND_SAT
diff --git a/keyboards/ergodox_ez/config.h b/keyboards/ergodox_ez/config.h
index bc63f6108f..9dcfc341e1 100644
--- a/keyboards/ergodox_ez/config.h
+++ b/keyboards/ergodox_ez/config.h
@@ -129,7 +129,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define RGB_MATRIX_LED_PROCESS_LIMIT 5
#define RGB_MATRIX_LED_FLUSH_LIMIT 26
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true
+#define RGB_DISABLE_WHEN_USB_SUSPENDED
// #define RGBLIGHT_COLOR_LAYER_0 0x00, 0x00, 0xFF
/* #define RGBLIGHT_COLOR_LAYER_1 0x00, 0x00, 0xFF */
diff --git a/keyboards/ergodox_ez/keymaps/hacker_dvorak/config.h b/keyboards/ergodox_ez/keymaps/hacker_dvorak/config.h
index a0ba655ede..da20820787 100644
--- a/keyboards/ergodox_ez/keymaps/hacker_dvorak/config.h
+++ b/keyboards/ergodox_ez/keymaps/hacker_dvorak/config.h
@@ -14,7 +14,7 @@
#undef IGNORE_MOD_TAP_INTERRUPT
#define IGNORE_MOD_TAP_INTERRUPT
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true
+#define RGB_DISABLE_WHEN_USB_SUSPENDED
#undef FORCE_NKRO
#define FORCE_NKRO
diff --git a/keyboards/ergodox_infinity/config.h b/keyboards/ergodox_infinity/config.h
index a64f3f4a13..a00c593eeb 100644
--- a/keyboards/ergodox_infinity/config.h
+++ b/keyboards/ergodox_infinity/config.h
@@ -62,6 +62,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define LED_BRIGHTNESS_LO 100
#define LED_BRIGHTNESS_HI 255
+/* LED matrix driver */
+#define LED_DRIVER_ADDR_1 0x74
+#define LED_DRIVER_COUNT 1
+#define DRIVER_LED_TOTAL 76
+#define LED_MATRIX_SPLIT { 38, 38 }
+#define LED_DISABLE_WHEN_USB_SUSPENDED
+
+/* i2c (for LED matrix) */
+#define I2C1_CLOCK_SPEED 400000
+#define I2C1_SCL_PAL_MODE PAL_MODE_ALTERNATIVE_2
+#define I2C1_SDA_PAL_MODE PAL_MODE_ALTERNATIVE_2
+#define I2C1_BANK GPIOB
+#define I2C1_SCL 0
+#define I2C1_SDA 1
+
/* define if matrix has ghost */
//#define MATRIX_HAS_GHOST
diff --git a/keyboards/ergodox_infinity/ergodox_infinity.c b/keyboards/ergodox_infinity/ergodox_infinity.c
index 97b628470b..da8ea311ad 100644
--- a/keyboards/ergodox_infinity/ergodox_infinity.c
+++ b/keyboards/ergodox_infinity/ergodox_infinity.c
@@ -1,20 +1,45 @@
#include QMK_KEYBOARD_H
#include <ch.h>
#include <hal.h>
+#include <string.h>
+#include "eeconfig.h"
#include "serial_link/system/serial_link.h"
#ifdef VISUALIZER_ENABLE
-#include "lcd_backlight.h"
+# include "lcd_backlight.h"
#endif
-#ifdef WPM_ENABLE
-# include "serial_link/protocol/transport.h"
-# include "wpm.h"
+#if (defined(LED_MATRIX_ENABLE) || defined(WPM_ENABLE))
+# include "serial_link/protocol/transport.h"
+
+# ifdef LED_MATRIX_ENABLE
+MASTER_TO_ALL_SLAVES_OBJECT(led_matrix, led_eeconfig_t);
+MASTER_TO_ALL_SLAVES_OBJECT(led_suspend_state, bool);
+static led_eeconfig_t last_sent_led_matrix;
+static uint16_t led_matrix_sent_timer = 0;
+
+void send_led_suspend_state(void) {
+ if (is_serial_link_master()) {
+ *begin_write_led_suspend_state() = led_matrix_get_suspend_state();
+ end_write_led_suspend_state();
+ }
+}
+# endif
+# ifdef WPM_ENABLE
+# include "wpm.h"
MASTER_TO_ALL_SLAVES_OBJECT(current_wpm, uint8_t);
-static remote_object_t* remote_objects[] = {
+static uint8_t last_sent_wpm = 0;
+# endif
+
+static remote_object_t *remote_objects[] = {
+# ifdef LED_MATRIX_ENABLE
+ REMOTE_OBJECT(led_matrix),
+ REMOTE_OBJECT(led_suspend_state),
+# endif
+# ifdef WPM_ENABLE
REMOTE_OBJECT(current_wpm),
+# endif
};
-static uint8_t last_sent_wpm = 0;
#endif
void init_serial_link_hal(void) {
@@ -52,7 +77,7 @@ void init_serial_link_hal(void) {
void lcd_backlight_hal_init(void) {
// Setup Backlight
SIM->SCGC6 |= SIM_SCGC6_FTM0;
- FTM0->CNT = 0; // Reset counter
+ FTM0->CNT = 0; // Reset counter
// PWM Period
// 16-bit maximum
@@ -60,25 +85,25 @@ void lcd_backlight_hal_init(void) {
// Set FTM to PWM output - Edge Aligned, Low-true pulses
#define CNSC_MODE FTM_SC_CPWMS | FTM_SC_PS(4) | FTM_SC_CLKS(0)
- CHANNEL_RED.CnSC = CNSC_MODE;
+ CHANNEL_RED.CnSC = CNSC_MODE;
CHANNEL_GREEN.CnSC = CNSC_MODE;
- CHANNEL_BLUE.CnSC = CNSC_MODE;
+ CHANNEL_BLUE.CnSC = CNSC_MODE;
// System clock, /w prescalar setting
FTM0->SC = FTM_SC_CLKS(1) | FTM_SC_PS(PRESCALAR_DEFINE);
- CHANNEL_RED.CnV = 0;
+ CHANNEL_RED.CnV = 0;
CHANNEL_GREEN.CnV = 0;
- CHANNEL_BLUE.CnV = 0;
+ CHANNEL_BLUE.CnV = 0;
RGB_PORT_GPIO->PDDR |= (1 << RED_PIN);
RGB_PORT_GPIO->PDDR |= (1 << GREEN_PIN);
RGB_PORT_GPIO->PDDR |= (1 << BLUE_PIN);
#define RGB_MODE PORTx_PCRn_SRE | PORTx_PCRn_DSE | PORTx_PCRn_MUX(4)
- RGB_PORT->PCR[RED_PIN] = RGB_MODE;
+ RGB_PORT->PCR[RED_PIN] = RGB_MODE;
RGB_PORT->PCR[GREEN_PIN] = RGB_MODE;
- RGB_PORT->PCR[BLUE_PIN] = RGB_MODE;
+ RGB_PORT->PCR[BLUE_PIN] = RGB_MODE;
}
static uint16_t cie_lightness(uint16_t v) {
@@ -89,12 +114,11 @@ static uint16_t cie_lightness(uint16_t v) {
// Y = (L* / 902.3) if L* <= 8
// Y = ((L* + 16) / 116)^3 if L* > 8
- float l = 100.0f * (v / 65535.0f);
+ float l = 100.0f * (v / 65535.0f);
float y = 0.0f;
if (l <= 8.0f) {
- y = l / 902.3;
- }
- else {
+ y = l / 902.3;
+ } else {
y = ((l + 16.0f) / 116.0f);
y = y * y * y;
if (y > 1.0f) {
@@ -105,31 +129,48 @@ static uint16_t cie_lightness(uint16_t v) {
}
void lcd_backlight_hal_color(uint16_t r, uint16_t g, uint16_t b) {
- CHANNEL_RED.CnV = cie_lightness(r);
+ CHANNEL_RED.CnV = cie_lightness(r);
CHANNEL_GREEN.CnV = cie_lightness(g);
- CHANNEL_BLUE.CnV = cie_lightness(b);
+ CHANNEL_BLUE.CnV = cie_lightness(b);
}
-__attribute__ ((weak))
-void matrix_init_user(void) {
-}
+__attribute__ ((weak)) void matrix_init_user(void) {}
+
+__attribute__ ((weak)) void matrix_scan_user(void) {}
-__attribute__ ((weak))
-void matrix_scan_user(void) {
-}
+void keyboard_pre_init_kb() {
+#ifdef LED_MATRIX_ENABLE
+ // Turn on LED controller
+ setPinOutput(B16);
+ writePinHigh(B16);
+#endif
+ keyboard_pre_init_user();
+}
void matrix_init_kb(void) {
// put your keyboard start-up code here
// runs once when the firmware starts up
+#ifdef LED_MATRIX_ENABLE
+ /*
+ * Since K20x is stuck with a 32 byte EEPROM (see tmk_core/common/chibios/eeprom_teensy.c),
+ * and neither led_matrix_eeconfig.speed or .flags fit in this boundary, just force their values to default on boot.
+ */
+# if !defined(LED_MATRIX_STARTUP_SPD)
+# define LED_MATRIX_STARTUP_SPD UINT8_MAX / 2
+# endif
+ led_matrix_set_speed(LED_MATRIX_STARTUP_SPD);
+ led_matrix_set_flags(LED_FLAG_ALL);
+#endif
+
matrix_init_user();
// The backlight always has to be initialized, otherwise it will stay lit
#ifndef VISUALIZER_ENABLE
lcd_backlight_hal_init();
#endif
-#ifdef WPM_ENABLE
- add_remote_objects(remote_objects, sizeof(remote_objects) / sizeof(remote_object_t*));
+#if (defined(LED_MATRIX_ENABLE) || defined(WPM_ENABLE))
+ add_remote_objects(remote_objects, sizeof(remote_objects) / sizeof(remote_object_t *));
#endif
}
@@ -137,6 +178,30 @@ void matrix_scan_kb(void) {
// put your looping keyboard code here
// runs every cycle (a lot)
+#ifdef LED_MATRIX_ENABLE
+ if (is_serial_link_master()) {
+ if (!led_matrix_get_suspend_state()) {
+ if (timer_elapsed(led_matrix_sent_timer) >= 5000 || memcmp((void *)&last_sent_led_matrix, (void *)&led_matrix_eeconfig, sizeof(last_sent_led_matrix))) {
+ led_matrix_sent_timer = timer_read();
+ memcpy((void *)&last_sent_led_matrix, (void *)&led_matrix_eeconfig, sizeof(last_sent_led_matrix));
+ *begin_write_led_matrix() = last_sent_led_matrix;
+ end_write_led_matrix();
+ }
+ }
+ } else if (is_serial_link_connected()) {
+ bool *new_led_suspend_state = read_led_suspend_state();
+ if (new_led_suspend_state) {
+ led_matrix_set_suspend_state(*new_led_suspend_state);
+ }
+ if (!led_matrix_get_suspend_state()) {
+ led_eeconfig_t *new_led_matrix = read_led_matrix();
+ if (new_led_matrix) {
+ memcpy((void *)&led_matrix_eeconfig, (void *)new_led_matrix, sizeof(last_sent_led_matrix));
+ }
+ }
+ }
+#endif
+
#ifdef WPM_ENABLE
if (is_serial_link_master()) {
uint8_t current_wpm = get_current_wpm();
@@ -146,67 +211,68 @@ void matrix_scan_kb(void) {
last_sent_wpm = current_wpm;
}
} else if (is_serial_link_connected()) {
- uint8_t* new_wpm = read_current_wpm();
+ uint8_t *new_wpm = read_current_wpm();
if (new_wpm) {
set_current_wpm(*new_wpm);
}
}
#endif
+
matrix_scan_user();
}
-bool is_keyboard_master(void) {
- return is_serial_link_master();
-}
+bool is_keyboard_master(void) { return is_serial_link_master(); }
-__attribute__ ((weak))
-void ergodox_board_led_on(void){
+bool is_keyboard_left(void) {
+#if defined(EE_HANDS)
+ return eeconfig_read_handedness();
+#elif defined(MASTER_IS_ON_RIGHT)
+ return !is_keyboard_master();
+#else
+ return is_keyboard_master();
+#endif
}
-__attribute__ ((weak))
-void ergodox_right_led_1_on(void){
-}
+__attribute__ ((weak)) void ergodox_board_led_on(void) {}
-__attribute__ ((weak))
-void ergodox_right_led_2_on(void){
-}
+__attribute__ ((weak)) void ergodox_right_led_1_on(void) {}
-__attribute__ ((weak))
-void ergodox_right_led_3_on(void){
-}
+__attribute__ ((weak)) void ergodox_right_led_2_on(void) {}
-__attribute__ ((weak))
-void ergodox_board_led_off(void){
-}
+__attribute__ ((weak)) void ergodox_right_led_3_on(void) {}
-__attribute__ ((weak))
-void ergodox_right_led_1_off(void){
-}
+__attribute__ ((weak)) void ergodox_board_led_off(void) {}
-__attribute__ ((weak))
-void ergodox_right_led_2_off(void){
-}
+__attribute__ ((weak)) void ergodox_right_led_1_off(void) {}
-__attribute__ ((weak))
-void ergodox_right_led_3_off(void){
-}
+__attribute__ ((weak)) void ergodox_right_led_2_off(void) {}
-__attribute__ ((weak))
-void ergodox_right_led_1_set(uint8_t n) {
-}
+__attribute__ ((weak)) void ergodox_right_led_3_off(void) {}
-__attribute__ ((weak))
-void ergodox_right_led_2_set(uint8_t n) {
+__attribute__ ((weak)) void ergodox_right_led_1_set(uint8_t n) {}
+
+__attribute__ ((weak)) void ergodox_right_led_2_set(uint8_t n) {}
+
+__attribute__ ((weak)) void ergodox_right_led_3_set(uint8_t n) {}
+
+void suspend_power_down_kb(void) {
+#ifdef LED_MATRIX_ENABLE
+ send_led_suspend_state();
+#endif
+ suspend_power_down_user();
}
-__attribute__ ((weak))
-void ergodox_right_led_3_set(uint8_t n) {
+void suspend_wakeup_init_kb(void) {
+#ifdef LED_MATRIX_ENABLE
+ send_led_suspend_state();
+#endif
+ suspend_wakeup_init_user();
}
#ifdef SWAP_HANDS_ENABLE
__attribute__ ((weak))
const keypos_t PROGMEM hand_swap_config[MATRIX_ROWS][MATRIX_COLS] = {
- {{0, 9}, {1, 9}, {2, 9}, {3, 9}, {4, 9}},
+ {{0, 9}, {1, 9}, {2, 9}, {3, 9}, {4, 9}},
{{0, 10}, {1, 10}, {2, 10}, {3, 10}, {4, 10}},
{{0, 11}, {1, 11}, {2, 11}, {3, 11}, {4, 11}},
{{0, 12}, {1, 12}, {2, 12}, {3, 12}, {4, 12}},
@@ -226,3 +292,115 @@ const keypos_t PROGMEM hand_swap_config[MATRIX_ROWS][MATRIX_COLS] = {
{{0, 8}, {1, 8}, {2, 8}, {3, 8}, {4, 8}},
};
#endif
+
+#ifdef LED_MATRIX_ENABLE
+const is31_led g_is31_leds[DRIVER_LED_TOTAL] = {
+// The numbers in the comments are the led numbers DXX on the PCB
+/* Refer to IS31 manual for these locations
+ * driver
+ * | LED address
+ * | | */
+// Left half
+// 45 44 43 42 41 40 39
+ { 0, C2_2 }, { 0, C1_2 }, { 0, C5_1 }, { 0, C4_1 }, { 0, C3_1 }, { 0, C2_1 }, { 0, C1_1 },
+// 52 51 50 49 48 47 46
+ { 0, C4_3 }, { 0, C3_3 }, { 0, C2_3 }, { 0, C1_3 }, { 0, C5_2 }, { 0, C4_2 }, { 0, C3_2 },
+// 58 57 56 55 54 53
+ { 0, C5_4 }, { 0, C4_4 }, { 0, C3_4 }, { 0, C2_4 }, { 0, C1_4 }, { 0, C5_3 },
+// 67 66 65 64 63 62 61
+ { 0, C4_6 }, { 0, C3_6 }, { 0, C2_6 }, { 0, C1_6 }, { 0, C5_5 }, { 0, C4_5 }, { 0, C3_5 },
+// 76 75 74 73 72
+ { 0, C4_8 }, { 0, C3_8 }, { 0, C2_8 }, { 0, C1_8 }, { 0, C4_7 },
+// 60 59
+ { 0, C2_5 }, { 0, C1_5 },
+// 68
+ { 0, C5_6 },
+// 71 70 69
+ { 0, C3_7 }, { 0, C2_7 }, { 0, C1_7 },
+// Right half (mirrored)
+// Due to how LED_MATRIX_SPLIT is implemented, only the first half of g_is31_leds is actually used.
+// Luckily, the right half has the same LED pinouts, just mirrored.
+// 45 44 43 42 41 40 39
+ { 0, C2_2 }, { 0, C1_2 }, { 0, C5_1 }, { 0, C4_1 }, { 0, C3_1 }, { 0, C2_1 }, { 0, C1_1 },
+// 52 51 50 49 48 47 46
+ { 0, C4_3 }, { 0, C3_3 }, { 0, C2_3 }, { 0, C1_3 }, { 0, C5_2 }, { 0, C4_2 }, { 0, C3_2 },
+// 58 57 56 55 54 53
+ { 0, C5_4 }, { 0, C4_4 }, { 0, C3_4 }, { 0, C2_4 }, { 0, C1_4 }, { 0, C5_3 },
+// 67 66 65 64 63 62 61
+ { 0, C4_6 }, { 0, C3_6 }, { 0, C2_6 }, { 0, C1_6 }, { 0, C5_5 }, { 0, C4_5 }, { 0, C3_5 },
+// 76 75 74 73 72
+ { 0, C4_8 }, { 0, C3_8 }, { 0, C2_8 }, { 0, C1_8 }, { 0, C4_7 },
+// 60 59
+ { 0, C2_5 }, { 0, C1_5 },
+// 68
+ { 0, C5_6 },
+// 71 70 69
+ { 0, C3_7 }, { 0, C2_7 }, { 0, C1_7 },
+};
+
+led_config_t g_led_config = {
+ {
+ // Key Matrix to LED Index
+ // Left half
+ { NO_LED, NO_LED, NO_LED, 33, 34 },
+ { NO_LED, NO_LED, NO_LED, 32, 37 },
+ { 6, 13, NO_LED, 26, 36 },
+ { 5, 12, 19, 25, 35 },
+ { 4, 11, 18, 24, 31 },
+ { 3, 10, 17, 23, 30 },
+ { 2, 9, 16, 22, 29 },
+ { 1, 8, 15, 21, 28 },
+ { 0, 7, 14, 20, 27 },
+ // Right half
+ { NO_LED, NO_LED, NO_LED, 71, 72 },
+ { NO_LED, NO_LED, NO_LED, 70, 75 },
+ { 44, 51, NO_LED, 64, 74 },
+ { 43, 50, 57, 63, 73 },
+ { 42, 49, 56, 62, 69 },
+ { 41, 48, 55, 61, 68 },
+ { 40, 47, 54, 60, 67 },
+ { 39, 46, 53, 59, 66 },
+ { 38, 45, 52, 58, 65 },
+ }, {
+ // LED Index to Physical Position (assumes a reasonable gap between halves)
+ // Left half
+ { 0, 3 }, { 15, 3 }, { 27, 1 }, { 39, 0 }, { 51, 1 }, { 63, 2 }, { 75, 2 },
+ { 0, 13 }, { 15, 13 }, { 27, 11 }, { 39, 10 }, { 51, 11 }, { 63, 12 }, { 78, 17 },
+ { 0, 23 }, { 15, 23 }, { 27, 21 }, { 39, 20 }, { 51, 21 }, { 63, 22 },
+ { 0, 33 }, { 15, 33 }, { 27, 31 }, { 39, 30 }, { 51, 31 }, { 63, 32 }, { 78, 32 },
+ { 4, 43 }, { 15, 43 }, { 27, 41 }, { 39, 40 }, { 51, 41 },
+ { 89, 41 }, { 100, 46 },
+ { 95, 55 },
+ { 72, 54 }, { 83, 59 }, { 90, 64 },
+ // Right half (mirrored)
+ { 224, 3 }, { 209, 3 }, { 197, 1 }, { 185, 0 }, { 173, 1 }, { 161, 2 }, { 149, 2 },
+ { 224, 13 }, { 209, 13 }, { 197, 11 }, { 185, 10 }, { 173, 11 }, { 161, 12 }, { 146, 17 },
+ { 224, 23 }, { 209, 23 }, { 197, 21 }, { 185, 20 }, { 173, 21 }, { 161, 22 },
+ { 224, 33 }, { 209, 33 }, { 197, 31 }, { 185, 30 }, { 173, 31 }, { 161, 32 }, { 146, 32 },
+ { 220, 43 }, { 209, 43 }, { 197, 41 }, { 185, 40 }, { 173, 41 },
+ { 135, 41 }, { 124, 46 },
+ { 129, 55 },
+ { 152, 54 }, { 141, 59 }, { 134, 64 },
+ }, {
+ // LED Index to Flag
+ // Left half
+ 1, 4, 4, 4, 4, 4, 1,
+ 1, 4, 4, 4, 4, 4, 1,
+ 1, 4, 4, 4, 4, 4,
+ 1, 4, 4, 4, 4, 4, 1,
+ 1, 1, 1, 1, 1,
+ 1, 1,
+ 1,
+ 1, 1, 1,
+ // Right half (mirrored)
+ 1, 4, 4, 4, 4, 4, 1,
+ 1, 4, 4, 4, 4, 4, 1,
+ 1, 4, 4, 4, 4, 4,
+ 1, 4, 4, 4, 4, 4, 1,
+ 1, 1, 1, 1, 1,
+ 1, 1,
+ 1,
+ 1, 1, 1,
+ }
+};
+#endif
diff --git a/keyboards/ergodox_infinity/matrix.c b/keyboards/ergodox_infinity/matrix.c
index 7baacd24d0..0fca56a979 100644
--- a/keyboards/ergodox_infinity/matrix.c
+++ b/keyboards/ergodox_infinity/matrix.c
@@ -24,7 +24,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "print.h"
#include "debug.h"
#include "matrix.h"
-#include "eeconfig.h"
+#include "keyboard.h"
#include "serial_link/system/serial_link.h"
@@ -119,15 +119,9 @@ uint8_t matrix_scan(void)
}
uint8_t offset = 0;
-#if (defined(EE_HANDS) || defined(MASTER_IS_ON_RIGHT))
-#ifdef EE_HANDS
- if (is_serial_link_master() && !eeconfig_read_handedness()) {
-#else
- if (is_serial_link_master()) {
-#endif
+ if (is_serial_link_master() && !is_keyboard_left()) {
offset = MATRIX_ROWS - LOCAL_MATRIX_ROWS;
}
-#endif
if (debouncing && timer_elapsed(debouncing_time) > DEBOUNCE) {
for (int row = 0; row < LOCAL_MATRIX_ROWS; row++) {
@@ -167,17 +161,11 @@ void matrix_print(void)
void matrix_set_remote(matrix_row_t* rows, uint8_t index) {
uint8_t offset = 0;
-#ifdef EE_HANDS
- if (eeconfig_read_handedness()) {
+ if (is_keyboard_left()) {
offset = LOCAL_MATRIX_ROWS * (index + 1);
} else {
offset = MATRIX_ROWS - LOCAL_MATRIX_ROWS * (index + 2);
}
-#elif defined(MASTER_IS_ON_RIGHT)
- offset = MATRIX_ROWS - LOCAL_MATRIX_ROWS * (index + 2);
-#else
- offset = LOCAL_MATRIX_ROWS * (index + 1);
-#endif
for (int row = 0; row < LOCAL_MATRIX_ROWS; row++) {
matrix[offset + row] = rows[row];
}
diff --git a/keyboards/ergodox_infinity/rules.mk b/keyboards/ergodox_infinity/rules.mk
index b9ead9e87c..70bcabe80e 100644
--- a/keyboards/ergodox_infinity/rules.mk
+++ b/keyboards/ergodox_infinity/rules.mk
@@ -22,8 +22,6 @@ CUSTOM_MATRIX = yes # Custom matrix file
SERIAL_LINK_ENABLE = yes
VISUALIZER_ENABLE = yes
LCD_ENABLE = yes
-BACKLIGHT_ENABLE = yes
-BACKLIGHT_DRIVER = custom
LCD_BACKLIGHT_ENABLE = yes
MIDI_ENABLE = no
RGBLIGHT_ENABLE = no
@@ -32,9 +30,8 @@ LCD_DRIVER = st7565
LCD_WIDTH = 128
LCD_HEIGHT = 32
-LED_DRIVER = is31fl3731c
-LED_WIDTH = 7
-LED_HEIGHT = 7
+LED_MATRIX_ENABLE = yes
+LED_MATRIX_DRIVER = IS31FL3731
# project specific files
SRC = matrix.c \
diff --git a/keyboards/geekboards/macropad_v2/config.h b/keyboards/geekboards/macropad_v2/config.h
index 5f11cdddb0..d0e208f9b9 100644
--- a/keyboards/geekboards/macropad_v2/config.h
+++ b/keyboards/geekboards/macropad_v2/config.h
@@ -41,7 +41,7 @@
#define WS2812_DMA_CHANNEL 3
#ifdef RGB_MATRIX_ENABLE
-#define RGB_MATRIX_KEYPRESSES
+#define RGB_MATRIX_KEYPRESSES
#define RGB_MATRIX_FRAMEBUFFER_EFFECTS
#define DISABLE_RGB_MATRIX_ALPHAS_MODS
#define DISABLE_RGB_MATRIX_BAND_SAT
@@ -67,7 +67,7 @@
#define RGB_MATRIX_STARTUP_SPD 30
#endif //RGB_MATRIX_ENABLE
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true
+#define RGB_DISABLE_WHEN_USB_SUSPENDED
#define WAIT_FOR_USB
/* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */
diff --git a/keyboards/geekboards/tester/config.h b/keyboards/geekboards/tester/config.h
index 4f072c0ee6..3e3daccd57 100644
--- a/keyboards/geekboards/tester/config.h
+++ b/keyboards/geekboards/tester/config.h
@@ -24,7 +24,7 @@
#define DEBOUNCE 3
#ifdef RGB_MATRIX_ENABLE
#define RGB_DISABLE_AFTER_TIMEOUT 0
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true
+#define RGB_DISABLE_WHEN_USB_SUSPENDED
#define RGB_MATRIX_KEYPRESSES
#define DISABLE_RGB_MATRIX_SPLASH
#define DISABLE_RGB_MATRIX_MULTISPLASH
@@ -36,4 +36,4 @@
#define DRIVER_1_LED_TOTAL 8
#define DRIVER_2_LED_TOTAL 0
#define DRIVER_LED_TOTAL (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)
-#endif \ No newline at end of file
+#endif
diff --git a/keyboards/gmmk/pro/config.h b/keyboards/gmmk/pro/config.h
index ab3c7a7a21..64062becea 100644
--- a/keyboards/gmmk/pro/config.h
+++ b/keyboards/gmmk/pro/config.h
@@ -46,3 +46,20 @@
#define LOCKING_SUPPORT_ENABLE
/* Locking resynchronize hack */
#define LOCKING_RESYNC_ENABLE
+
+/* SPI Config for LED Driver */
+#define SPI_DRIVER SPID1
+#define SPI_SCK_PIN A5
+#define SPI_MOSI_PIN A6
+#define SPI_MISO_PIN A7
+
+#define DRIVER_1_CS B13
+#define DRIVER_2_CS B14
+#define DRIVER_1_EN C13
+#define DRIVER_2_EN C13
+
+#define DRIVER_COUNT 2
+#define DRIVER_1_LED_TOTAL 66
+#define DRIVER_2_LED_TOTAL 32
+#define DRIVER_LED_TOTAL (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)
+
diff --git a/keyboards/gmmk/pro/halconf.h b/keyboards/gmmk/pro/halconf.h
new file mode 100644
index 0000000000..23ecb202a1
--- /dev/null
+++ b/keyboards/gmmk/pro/halconf.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#define HAL_USE_SPI TRUE
+#define SPI_USE_WAIT TRUE
+#define SPI_SELECT_MODE SPI_SELECT_MODE_PAD
+
+#include_next <halconf.h>
diff --git a/keyboards/gmmk/pro/mcuconf.h b/keyboards/gmmk/pro/mcuconf.h
new file mode 100644
index 0000000000..bb1c0acde2
--- /dev/null
+++ b/keyboards/gmmk/pro/mcuconf.h
@@ -0,0 +1,6 @@
+#pragma once
+
+#include_next <mcuconf.h>
+
+#undef STM32_SPI_USE_SPI1
+#define STM32_SPI_USE_SPI1 TRUE
diff --git a/keyboards/gmmk/pro/pro.c b/keyboards/gmmk/pro/pro.c
index 816d089a58..9ed7ac8865 100644
--- a/keyboards/gmmk/pro/pro.c
+++ b/keyboards/gmmk/pro/pro.c
@@ -14,3 +14,225 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pro.h"
+
+#ifdef RGB_MATRIX_ENABLE
+led_config_t g_led_config = { {
+ { 4, NO_LED, NO_LED, 95, 65, 79, 5, 28 },
+ { 8, 2, 9, 0, 10, 75, 1, 7 },
+ { 14, 3, 15, NO_LED, 16, 86, 6, 13 },
+ { 20, 18, 21, 23, 22, 94, 12, 19 },
+ { 25, 30, 26, 31, 27, 32, 29, 24 },
+ { 41, 36, 42, 37, 43, 38, 35, 40 },
+ { 46, 89, 47, 34, 48, 72, 78, 45 },
+ { 52, 39, 53, 97, 54, 82, 44, 51 },
+ { 58, 63, 59, 64, NO_LED, 60, 62, 57 },
+ { 11, 90, 55, 17, 33, 49, NO_LED, 69 },
+ { NO_LED, 85, 93, 61, 96, 66, 50, 56 }
+}, {
+ { 0, 0 }, // 0, ESC, k13
+ { 0, 15 }, // 1, ~, k16
+ { 4, 26 }, // 2, Tab, k11
+ { 5, 38 }, // 3, Caps, k21
+ { 9, 49 }, // 4, Sh_L, k00
+ { 2, 61 }, // 5, Ct_L, k06
+ { 18, 0 }, // 6, F1, k26
+ { 14, 15 }, // 7, 1, k17
+ { 22, 26 }, // 8, Q, k10
+ { 25, 38 }, // 9, A, k12
+ { 33, 49 }, // 10, Z, k14
+ { 20, 61 }, // 11, Win_L, k90
+ { 33, 0 }, // 12, F2, k36
+ { 29, 15 }, // 13, 2, k27
+ { 36, 26 }, // 14, W, k20
+ { 40, 38 }, // 15, S, k22
+ { 47, 49 }, // 16, X, k24
+ { 38, 61 }, // 17, Alt_L, k93
+ { 47, 0 }, // 18, F3, k31
+ { 43, 15 }, // 19, 3, k37
+ { 51, 26 }, // 20, E, k30
+ { 54, 38 }, // 21, D, k32
+ { 61, 49 }, // 22, C, k34
+ { 61, 0 }, // 23, F4, k33
+ { 58, 15 }, // 24, 4, k47
+ { 65, 26 }, // 25, R, k40
+ { 69, 38 }, // 26, F, k42
+ { 76, 49 }, // 27, V, k44
+ { 79, 0 }, // 28, F5, k07
+ { 72, 15 }, // 29, 5, k46
+ { 79, 26 }, // 30, T, k41
+ { 83, 38 }, // 31, G, k43
+ { 90, 49 }, // 32, B, k45
+ { 92, 61 }, // 33, SPACE, k94
+ { 94, 0 }, // 34, F6, k63
+ { 87, 15 }, // 35, 6, k56
+ { 94, 26 }, // 36, Y, k51
+ { 98, 38 }, // 37, H, k53
+ { 105, 49 }, // 38, N, k55
+ { 108, 0 }, // 39, F7, k71
+ { 101, 15 }, // 40, 7, k57
+ { 108, 26 }, // 41, U, k50
+ { 112, 38 }, // 42, J, k52
+ { 119, 49 }, // 43, M, k54
+ { 123, 0 }, // 44, F8, k76
+ { 116, 15 }, // 45, 8, k67
+ { 123, 26 }, // 46, I, k60
+ { 126, 38 }, // 47, K, k62
+ { 134, 49 }, // 48, ,, k64
+ { 145, 61 }, // 49, Alt_R, k95
+ { 141, 0 }, // 50, F9, ka6
+ { 130, 15 }, // 51, 9, k77
+ { 137, 26 }, // 52, O, k70
+ { 141, 38 }, // 53, L, k72
+ { 148, 49 }, // 54, ., k74
+ { 159, 61 }, // 55, FN, k92
+ { 155, 0 }, // 56, F10, ka7
+ { 145, 15 }, // 57, 0, k87
+ { 152, 26 }, // 58, P, k80
+ { 155, 38 }, // 59, ;, k82
+ { 163, 49 }, // 60, ?, k85
+ { 170, 0 }, // 61, F11, ka3
+ { 159, 15 }, // 62, -, k86
+ { 166, 26 }, // 63, [, k81
+ { 170, 38 }, // 64, ", k83
+ { 173, 61 }, // 65, Ct_R, k04
+ { 184, 0 }, // 66, F12, ka5
+ { 0, 8 }, // 67, LED, l01
+ { 224, 8 }, // 68, LED, l11
+ { 202, 0 }, // 69, Prt, k97
+ { 0, 15 }, // 70, LED, l02
+ { 224, 15 }, // 71, LED, l12
+ { 224, 15 }, // 72, Del, k65
+ { 0, 21 }, // 73, LED, l03
+ { 224, 21 }, // 74, LED, l13
+ { 224, 26 }, // 75, PgUp, k15
+ { 0, 28 }, // 76, LED, l04
+ { 224, 28 }, // 77, LED, l14
+ { 173, 15 }, // 78, =, k66
+ { 220, 64 }, // 79, Right, k05
+ { 0, 35 }, // 80, LED, l05
+ { 224, 35 }, // 81, LED, l15
+ { 224, 49 }, // 82, End, k75
+ { 0, 42 }, // 83, LED, l06
+ { 224, 42 }, // 84, LED, l16
+ { 195, 15 }, // 85, BSpc, ka1
+ { 224, 38 }, // 86, PgDn, k25
+ { 0, 48 }, // 87, LED, l07
+ { 224, 48 }, // 88, LED, l17
+ { 181, 26 }, // 89, ], k61
+ { 182, 49 }, // 90, Sh_R, k91
+ { 0, 55 }, // 91, LED, l08
+ { 224, 55 }, // 92, LED, l18
+ { 199, 26 }, // 93, \, ka2
+ { 206, 52 }, // 94, Up, k35
+ { 191, 64 }, // 95, Left, k03
+ { 193, 38 }, // 96, Enter, ka4
+ { 206, 64 } // 97, Down, k73
+}, {
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 4, 2, 2, 4, 2, 2,
+ 4, 2, 2, 4, 4, 2, 2, 4, 2, 2, 4, 4, 2, 2, 4, 4, 2, 2, 4, 4, 4, 4, 4
+} };
+
+const aw_led g_aw_leds[DRIVER_LED_TOTAL] = {
+ { 0, CS1_SW1, CS2_SW1, CS3_SW1 }, // 0, ESC, k13
+ { 0, CS4_SW1, CS5_SW1, CS6_SW1 }, // 1, ~, k16
+ { 0, CS7_SW1, CS8_SW1, CS9_SW1 }, // 2, Tab, k11
+ { 0, CS10_SW1, CS11_SW1, CS12_SW1 }, // 3, Caps, k21
+ { 0, CS13_SW1, CS14_SW1, CS15_SW1 }, // 4, Sh_L, k00
+ { 0, CS16_SW1, CS17_SW1, CS18_SW1 }, // 5, Ct_L, k06
+ { 0, CS1_SW2, CS2_SW2, CS3_SW2 }, // 6, F1, k26
+ { 0, CS4_SW2, CS5_SW2, CS6_SW2 }, // 7, 1, k17
+ { 0, CS7_SW2, CS8_SW2, CS9_SW2 }, // 8, Q, k10
+ { 0, CS10_SW2, CS11_SW2, CS12_SW2 }, // 9, A, k12
+ { 0, CS13_SW2, CS14_SW2, CS15_SW2 }, // 10, Z, k14
+ { 0, CS16_SW2, CS17_SW2, CS18_SW2 }, // 11, Win_L, k90
+ { 0, CS1_SW3, CS2_SW3, CS3_SW3 }, // 12, F2, k36
+ { 0, CS4_SW3, CS5_SW3, CS6_SW3 }, // 13, 2, k27
+ { 0, CS7_SW3, CS8_SW3, CS9_SW3 }, // 14, W, k20
+ { 0, CS10_SW3, CS11_SW3, CS12_SW3 }, // 15, S, k22
+ { 0, CS13_SW3, CS14_SW3, CS15_SW3 }, // 16, X, k24
+ { 0, CS16_SW3, CS17_SW3, CS18_SW3 }, // 17, Alt_L, k93
+ { 0, CS1_SW4, CS2_SW4, CS3_SW4 }, // 18, F3, k31
+ { 0, CS4_SW4, CS5_SW4, CS6_SW4 }, // 19, 3, k37
+ { 0, CS7_SW4, CS8_SW4, CS9_SW4 }, // 20, E, k30
+ { 0, CS10_SW4, CS11_SW4, CS12_SW4 }, // 21, D, k32
+ { 0, CS13_SW4, CS14_SW4, CS15_SW4 }, // 22, C, k34
+ { 0, CS1_SW5, CS2_SW5, CS3_SW5 }, // 23, F4, k33
+ { 0, CS4_SW5, CS5_SW5, CS6_SW5 }, // 24, 4, k47
+ { 0, CS7_SW5, CS8_SW5, CS9_SW5 }, // 25, R, k40
+ { 0, CS10_SW5, CS11_SW5, CS12_SW5 }, // 26, F, k42
+ { 0, CS13_SW5, CS14_SW5, CS15_SW5 }, // 27, V, k44
+ { 0, CS1_SW6, CS2_SW6, CS3_SW6 }, // 28, F5, k07
+ { 0, CS4_SW6, CS5_SW6, CS6_SW6 }, // 29, 5, k46
+ { 0, CS7_SW6, CS8_SW6, CS9_SW6 }, // 30, T, k41
+ { 0, CS10_SW6, CS11_SW6, CS12_SW6 }, // 31, G, k43
+ { 0, CS13_SW6, CS14_SW6, CS15_SW6 }, // 32, B, k45
+ { 0, CS16_SW6, CS17_SW6, CS18_SW6 }, // 33, SPACE, k94
+ { 0, CS1_SW7, CS2_SW7, CS3_SW7 }, // 34, F6, k63
+ { 0, CS4_SW7, CS5_SW7, CS6_SW7 }, // 35, 6, k56
+ { 0, CS7_SW7, CS8_SW7, CS9_SW7 }, // 36, Y, k51
+ { 0, CS10_SW7, CS11_SW7, CS12_SW7 }, // 37, H, k53
+ { 0, CS13_SW7, CS14_SW7, CS15_SW7 }, // 38, N, k55
+ { 0, CS1_SW8, CS2_SW8, CS3_SW8 }, // 39, F7, k71
+ { 0, CS4_SW8, CS5_SW8, CS6_SW8 }, // 40, 7, k57
+ { 0, CS7_SW8, CS8_SW8, CS9_SW8 }, // 41, U, k50
+ { 0, CS10_SW8, CS11_SW8, CS12_SW8 }, // 42, J, k52
+ { 0, CS13_SW8, CS14_SW8, CS15_SW8 }, // 43, M, k54
+ { 0, CS1_SW9, CS2_SW9, CS3_SW9 }, // 44, F8, k76
+ { 0, CS4_SW9, CS5_SW9, CS6_SW9 }, // 45, 8, k67
+ { 0, CS7_SW9, CS8_SW9, CS9_SW9 }, // 46, I, k60
+ { 0, CS10_SW9, CS11_SW9, CS12_SW9 }, // 47, K, k62
+ { 0, CS13_SW9, CS14_SW9, CS15_SW9 }, // 48, ,, k64
+ { 0, CS16_SW9, CS17_SW9, CS18_SW9 }, // 49, Alt_R, k95
+ { 0, CS1_SW10, CS2_SW10, CS3_SW10 }, // 50, F9, ka6
+ { 0, CS4_SW10, CS5_SW10, CS6_SW10 }, // 51, 9, k77
+ { 0, CS7_SW10, CS8_SW10, CS9_SW10 }, // 52, O, k70
+ { 0, CS10_SW10, CS11_SW10, CS12_SW10 }, // 53, L, k72
+ { 0, CS13_SW10, CS14_SW10, CS15_SW10 }, // 54, ., k74
+ { 0, CS16_SW10, CS17_SW10, CS18_SW10 }, // 55, FN, k92
+ { 0, CS1_SW11, CS2_SW11, CS3_SW11 }, // 56, F10, ka7
+ { 0, CS4_SW11, CS5_SW11, CS6_SW11 }, // 57, 0, k87
+ { 0, CS7_SW11, CS8_SW11, CS9_SW11 }, // 58, P, k80
+ { 0, CS10_SW11, CS11_SW11, CS12_SW11 }, // 59, ;, k82
+ { 0, CS13_SW11, CS14_SW11, CS15_SW11 }, // 60, ?, k85
+ { 0, CS1_SW12, CS2_SW12, CS3_SW12 }, // 61, F11, ka3
+ { 0, CS4_SW12, CS5_SW12, CS6_SW12 }, // 62, -, k86
+ { 0, CS7_SW12, CS8_SW12, CS9_SW12 }, // 63, [, k81
+ { 0, CS10_SW12, CS11_SW12, CS12_SW12 }, // 64, ", k83
+ { 0, CS16_SW12, CS17_SW12, CS18_SW12 }, // 65, Ct_R, k04
+
+ { 1, CS1_SW1, CS2_SW1, CS3_SW1 }, // 66, F12, ka5
+ { 1, CS13_SW1, CS14_SW1, CS15_SW1 }, // 67, LED, l01
+ { 1, CS16_SW1, CS17_SW1, CS18_SW1 }, // 68, LED, l11
+ { 1, CS4_SW2, CS5_SW2, CS6_SW2 }, // 69, Prt, k97
+ { 1, CS13_SW2, CS14_SW2, CS15_SW2 }, // 70, LED, l02
+ { 1, CS16_SW2, CS17_SW2, CS18_SW2 }, // 71, LED, l12
+ { 1, CS4_SW3, CS5_SW3, CS6_SW3 }, // 72, Del, k65
+ { 1, CS13_SW3, CS14_SW3, CS15_SW3 }, // 73, LED, l03
+ { 1, CS16_SW3, CS17_SW3, CS18_SW3 }, // 74, LED, l13
+ { 1, CS4_SW4, CS5_SW4, CS6_SW4 }, // 75, PgUp, k15
+ { 1, CS13_SW4, CS14_SW4, CS15_SW4 }, // 76, LED, l04
+ { 1, CS16_SW4, CS17_SW4, CS18_SW4 }, // 77, LED, l14
+ { 1, CS1_SW5, CS2_SW5, CS3_SW5 }, // 78, =, k66
+ { 1, CS10_SW5, CS11_SW5, CS12_SW5 }, // 79, Right, k05
+ { 1, CS13_SW5, CS14_SW5, CS15_SW5 }, // 80, LED, l05
+ { 1, CS16_SW5, CS17_SW5, CS18_SW5 }, // 81, LED, l15
+ { 1, CS4_SW6, CS5_SW6, CS6_SW6 }, // 82, End, k75
+ { 1, CS13_SW6, CS14_SW6, CS15_SW6 }, // 83, LED, l06
+ { 1, CS16_SW6, CS17_SW6, CS18_SW6 }, // 84, LED, l16
+ { 1, CS1_SW7, CS2_SW7, CS3_SW7 }, // 85, BSpc, ka1
+ { 1, CS4_SW7, CS5_SW7, CS6_SW7 }, // 86, PgDn, k25
+ { 1, CS13_SW7, CS14_SW7, CS15_SW7 }, // 87, LED, l07
+ { 1, CS16_SW7, CS17_SW7, CS18_SW7 }, // 88, LED, l17
+ { 1, CS1_SW8, CS2_SW8, CS3_SW8 }, // 89, ], k61
+ { 1, CS4_SW8, CS5_SW8, CS6_SW8 }, // 90, Sh_R, k91
+ { 1, CS13_SW8, CS14_SW8, CS15_SW8 }, // 91, LED, l08
+ { 1, CS16_SW8, CS17_SW8, CS18_SW8 }, // 92, LED, l18
+ { 1, CS1_SW9, CS2_SW9, CS3_SW9 }, // 93, \, ka2
+ { 1, CS4_SW9, CS5_SW9, CS6_SW9 }, // 94, Up, k35
+ { 1, CS4_SW10, CS5_SW10, CS6_SW10 }, // 95, Left, k03
+ { 1, CS1_SW11, CS2_SW11, CS3_SW11 }, // 96, Enter, ka4
+ { 1, CS4_SW11, CS5_SW11, CS6_SW11 }, // 97, Down, k73
+};
+#endif
diff --git a/keyboards/gmmk/pro/rules.mk b/keyboards/gmmk/pro/rules.mk
index b12d055a3d..6221d64082 100644
--- a/keyboards/gmmk/pro/rules.mk
+++ b/keyboards/gmmk/pro/rules.mk
@@ -21,3 +21,5 @@ RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
BLUETOOTH_ENABLE = no # Enable Bluetooth
AUDIO_ENABLE = no # Audio output
ENCODER_ENABLE = yes
+RGB_MATRIX_ENABLE = yes
+RGB_MATRIX_DRIVER = AW20216
diff --git a/keyboards/handwired/colorlice/config.h b/keyboards/handwired/colorlice/config.h
index 206a4004ea..0148817f3f 100644
--- a/keyboards/handwired/colorlice/config.h
+++ b/keyboards/handwired/colorlice/config.h
@@ -49,7 +49,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
/* RGB LEDs */
#define RGB_DI_PIN B1
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+#define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_KEYPRESSES
#define RGB_MATRIX_FRAMEBUFFER_EFFECTS
#define RGB_MATRIX_LED_PROCESS_LIMIT 4
diff --git a/keyboards/handwired/frankie_macropad/keymaps/default/config.h b/keyboards/handwired/frankie_macropad/keymaps/default/config.h
new file mode 100644
index 0000000000..dd687cad58
--- /dev/null
+++ b/keyboards/handwired/frankie_macropad/keymaps/default/config.h
@@ -0,0 +1,19 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#define LAYER_STATE_8BIT
diff --git a/keyboards/handwired/freoduo/rules.mk b/keyboards/handwired/freoduo/rules.mk
index e3da3753e4..d8923557d6 100644
--- a/keyboards/handwired/freoduo/rules.mk
+++ b/keyboards/handwired/freoduo/rules.mk
@@ -11,7 +11,7 @@ BOOTMAGIC_ENABLE = no # Virtual DIP switch configuration
MOUSEKEY_ENABLE = yes # Mouse keys
EXTRAKEY_ENABLE = yes # Audio control and System control
CONSOLE_ENABLE = no # Console for debug
-COMMAND_ENABLE = yes # Commands for debug and configuration
+COMMAND_ENABLE = no # Commands for debug and configuration
# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
# if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
@@ -21,4 +21,4 @@ RGBLIGHT_ENABLE = yes # Enable keyboard RGB underglow
BLUETOOTH_ENABLE = no # Enable Bluetooth
AUDIO_ENABLE = no # Audio output
VELOCIKEY_ENABLE = yes
-SPLIT_KEYBOARD = yes \ No newline at end of file
+SPLIT_KEYBOARD = yes
diff --git a/keyboards/handwired/hnah40rgb/config.h b/keyboards/handwired/hnah40rgb/config.h
index e6271738c0..3d558f97fc 100644
--- a/keyboards/handwired/hnah40rgb/config.h
+++ b/keyboards/handwired/hnah40rgb/config.h
@@ -60,7 +60,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (instead of keypresses)
#define RGB_MATRIX_FRAMEBUFFER_EFFECTS
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-#define RGB_DISABLE_WHEN_USB_SUSPENDED false // turn off effects when suspended
+// #define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 200 // limits maximum brightness of LEDs to 200 out of 255. If not defined maximum brightness is set to 255
#define RGB_MATRIX_STARTUP_MODE RGB_MATRIX_CYCLE_PINWHEEL // Sets the default mode, if none has been set
diff --git a/keyboards/handwired/p65rgb/config.h b/keyboards/handwired/p65rgb/config.h
index c50fc2826a..142d3c03ea 100644
--- a/keyboards/handwired/p65rgb/config.h
+++ b/keyboards/handwired/p65rgb/config.h
@@ -40,7 +40,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define RGB_DI_PIN B4
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+#define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_KEYPRESSES
#define RGB_MATRIX_FRAMEBUFFER_EFFECTS
#define RGB_MATRIX_LED_PROCESS_LIMIT 4
diff --git a/keyboards/helix/rev2/keymaps/default/rules.mk b/keyboards/helix/rev2/keymaps/default/rules.mk
index 206e836ec0..c16f3e2b87 100644
--- a/keyboards/helix/rev2/keymaps/default/rules.mk
+++ b/keyboards/helix/rev2/keymaps/default/rules.mk
@@ -5,7 +5,7 @@
# See TOP/keyboards/helix/rules.mk for a list of options that can be set.
# See TOP/docs/config_options.md for more information.
#
-LTO_ENABLE = no # if firmware size over limit, try this option
+LTO_ENABLE = yes # if firmware size over limit, try this option
# Helix Spacific Build Options
# you can uncomment and edit follows 7 Variables
diff --git a/keyboards/helix/rev3_4rows/config.h b/keyboards/helix/rev3_4rows/config.h
index 9102104bfc..95eb8bf0cf 100644
--- a/keyboards/helix/rev3_4rows/config.h
+++ b/keyboards/helix/rev3_4rows/config.h
@@ -68,7 +68,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
# define RGB_MATRIX_KEYPRESSES // reacts to keypresses
// # define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (instead of keypresses)
// # define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
// # define RGB_MATRIX_LED_PROCESS_LIMIT (DRIVER_LED_TOTAL + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
// # define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
diff --git a/keyboards/helix/rev3_5rows/config.h b/keyboards/helix/rev3_5rows/config.h
index 4dda76206b..a373de7d12 100644
--- a/keyboards/helix/rev3_5rows/config.h
+++ b/keyboards/helix/rev3_5rows/config.h
@@ -68,7 +68,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
# define RGB_MATRIX_KEYPRESSES // reacts to keypresses
// # define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (instead of keypresses)
// # define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
// # define RGB_MATRIX_LED_PROCESS_LIMIT (DRIVER_LED_TOTAL + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
// # define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
diff --git a/keyboards/hs60/v1/config.h b/keyboards/hs60/v1/config.h
index 68c75b2af0..41246b6ee8 100644
--- a/keyboards/hs60/v1/config.h
+++ b/keyboards/hs60/v1/config.h
@@ -118,7 +118,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
//#define RGB_MATRIX_KEYPRESSES // reacts to keypresses (will slow down matrix scan by a lot)
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-#define RGB_DISABLE_WHEN_USB_SUSPENDED false // turn off effects when suspended
+// #define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 215
#define DRIVER_ADDR_1 0b1110100
diff --git a/keyboards/kbdfans/bella/rgb/config.h b/keyboards/kbdfans/bella/rgb/config.h
index f56049690b..07594a34ab 100644
--- a/keyboards/kbdfans/bella/rgb/config.h
+++ b/keyboards/kbdfans/bella/rgb/config.h
@@ -37,7 +37,7 @@
/* disable these deprecated features by default */
#ifdef RGB_MATRIX_ENABLE
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+#define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_KEYPRESSES
#define RGB_MATRIX_FRAMEBUFFER_EFFECTS
#define RGB_MATRIX_LED_PROCESS_LIMIT 4
diff --git a/keyboards/kbdfans/bella/rgb_iso/config.h b/keyboards/kbdfans/bella/rgb_iso/config.h
index fc7a9d7c08..4fda998677 100644
--- a/keyboards/kbdfans/bella/rgb_iso/config.h
+++ b/keyboards/kbdfans/bella/rgb_iso/config.h
@@ -37,7 +37,7 @@
/* disable these deprecated features by default */
#ifdef RGB_MATRIX_ENABLE
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+#define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_KEYPRESSES
#define RGB_MATRIX_FRAMEBUFFER_EFFECTS
#define RGB_MATRIX_LED_PROCESS_LIMIT 4
diff --git a/keyboards/kbdfans/kbd67/mkiirgb/v1/config.h b/keyboards/kbdfans/kbd67/mkiirgb/v1/config.h
index a832110d3c..b0b7e1dad2 100644
--- a/keyboards/kbdfans/kbd67/mkiirgb/v1/config.h
+++ b/keyboards/kbdfans/kbd67/mkiirgb/v1/config.h
@@ -16,9 +16,9 @@
#define RGB_MATRIX_LED_FLUSH_LIMIT 26
#define DEBOUNCE 3
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+#define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_KEYPRESSES
-#define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
+#define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
#define DISABLE_RGB_MATRIX_BAND_SAT
#define DISABLE_RGB_MATRIX_BAND_PINWHEEL_SAT
#define DISABLE_RGB_MATRIX_BAND_SPIRAL_SAT
diff --git a/keyboards/kbdfans/kbd67/mkiirgb/v2/config.h b/keyboards/kbdfans/kbd67/mkiirgb/v2/config.h
index 1ac9c770db..51e732f101 100644
--- a/keyboards/kbdfans/kbd67/mkiirgb/v2/config.h
+++ b/keyboards/kbdfans/kbd67/mkiirgb/v2/config.h
@@ -16,10 +16,10 @@
#define RGB_MATRIX_LED_FLUSH_LIMIT 26
#define DEBOUNCE 3
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+#define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_KEYPRESSES
#define RGB_MATRIX_STARTUP_MODE RGB_MATRIX_CYCLE_ALL
-#define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
+#define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
#define DISABLE_RGB_MATRIX_BAND_SAT
#define DISABLE_RGB_MATRIX_BAND_PINWHEEL_SAT
#define DISABLE_RGB_MATRIX_BAND_SPIRAL_SAT
diff --git a/keyboards/kbdfans/kbd67/rev1/keymaps/default/config.h b/keyboards/kbdfans/kbd67/rev1/keymaps/default/config.h
index a3ed4f762a..90fb10ebbe 100644
--- a/keyboards/kbdfans/kbd67/rev1/keymaps/default/config.h
+++ b/keyboards/kbdfans/kbd67/rev1/keymaps/default/config.h
@@ -16,4 +16,4 @@
#pragma once
-// place overrides here
+#define LAYER_STATE_8BIT
diff --git a/keyboards/kbdfans/kbdmini/config.h b/keyboards/kbdfans/kbdmini/config.h
index 5a36e983d1..fc65f43411 100644
--- a/keyboards/kbdfans/kbdmini/config.h
+++ b/keyboards/kbdfans/kbdmini/config.h
@@ -35,7 +35,7 @@
#ifdef RGB_MATRIX_ENABLE
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+#define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_KEYPRESSES
#define RGB_MATRIX_FRAMEBUFFER_EFFECTS
#define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
diff --git a/keyboards/kbdfans/maja/config.h b/keyboards/kbdfans/maja/config.h
index d8553766bb..3722c8381d 100755
--- a/keyboards/kbdfans/maja/config.h
+++ b/keyboards/kbdfans/maja/config.h
@@ -18,9 +18,9 @@
#define RGB_MATRIX_LED_FLUSH_LIMIT 26
#define DEBOUNCE 3
#define RGB_DISABLE_AFTER_TIMEOUT 0
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true
+#define RGB_DISABLE_WHEN_USB_SUSPENDED
#define RGB_MATRIX_KEYPRESSES
-#define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
+#define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
#define DISABLE_RGB_MATRIX_BAND_SAT
#define DISABLE_RGB_MATRIX_BAND_PINWHEEL_SAT
#define DISABLE_RGB_MATRIX_BAND_SPIRAL_SAT
diff --git a/keyboards/keebio/iris/rev2/rules.mk b/keyboards/keebio/iris/rev2/rules.mk
index 765fa7f07a..197bad4764 100644
--- a/keyboards/keebio/iris/rev2/rules.mk
+++ b/keyboards/keebio/iris/rev2/rules.mk
@@ -32,3 +32,5 @@ RGBLIGHT_ENABLE = yes # Enable WS2812 RGB underlight.
SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
SPLIT_KEYBOARD = yes
+
+LTO_ENABLE = yes \ No newline at end of file
diff --git a/keyboards/keebio/iris/rev3/rules.mk b/keyboards/keebio/iris/rev3/rules.mk
index ea92bc98f5..b64eab5a4b 100644
--- a/keyboards/keebio/iris/rev3/rules.mk
+++ b/keyboards/keebio/iris/rev3/rules.mk
@@ -33,3 +33,4 @@ SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
SPLIT_KEYBOARD = yes
ENCODER_ENABLE = yes
+LTO_ENABLE = yes \ No newline at end of file
diff --git a/keyboards/keebio/iris/rev4/rules.mk b/keyboards/keebio/iris/rev4/rules.mk
index ea92bc98f5..9bf5688da0 100644
--- a/keyboards/keebio/iris/rev4/rules.mk
+++ b/keyboards/keebio/iris/rev4/rules.mk
@@ -33,3 +33,5 @@ SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
SPLIT_KEYBOARD = yes
ENCODER_ENABLE = yes
+
+LTO_ENABLE = yes \ No newline at end of file
diff --git a/keyboards/keebio/quefrency/rules.mk b/keyboards/keebio/quefrency/rules.mk
index 2c5ad0c36b..c674e10162 100644
--- a/keyboards/keebio/quefrency/rules.mk
+++ b/keyboards/keebio/quefrency/rules.mk
@@ -19,3 +19,4 @@ SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
SPLIT_KEYBOARD = yes
DEFAULT_FOLDER = keebio/quefrency/rev1
+LTO_ENABLE = yes
diff --git a/keyboards/keebio/viterbi/rev2/rules.mk b/keyboards/keebio/viterbi/rev2/rules.mk
index f95e7ae6a4..829d6a56e0 100644
--- a/keyboards/keebio/viterbi/rev2/rules.mk
+++ b/keyboards/keebio/viterbi/rev2/rules.mk
@@ -1,3 +1,5 @@
BACKLIGHT_ENABLE = yes
LAYOUTS = ortho_5x14
+
+LTO_ENABLE = yes \ No newline at end of file
diff --git a/keyboards/keebio/viterbi/rules.mk b/keyboards/keebio/viterbi/rules.mk
index 0b746d1720..92576d33e8 100644
--- a/keyboards/keebio/viterbi/rules.mk
+++ b/keyboards/keebio/viterbi/rules.mk
@@ -19,16 +19,16 @@ BOOTMAGIC_ENABLE = no # Virtual DIP switch configuration
MOUSEKEY_ENABLE = yes # Mouse keys
EXTRAKEY_ENABLE = yes # Audio control and System control
CONSOLE_ENABLE = no # Console for debug
-COMMAND_ENABLE = yes # Commands for debug and configuration
+COMMAND_ENABLE = no # Commands for debug and configuration
NKRO_ENABLE = no # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
-BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
+BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
MIDI_ENABLE = no # MIDI controls
AUDIO_ENABLE = no # Audio output on port C6
UNICODE_ENABLE = no # Unicode
BLUETOOTH_ENABLE = no # Enable Bluetooth with the Adafruit EZ-Key HID
-RGBLIGHT_ENABLE = no # Enable WS2812 RGB underlight.
+RGBLIGHT_ENABLE = no # Enable WS2812 RGB underlight.
# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
-SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
+SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
SPLIT_KEYBOARD = yes
diff --git a/keyboards/latin17rgb/config.h b/keyboards/latin17rgb/config.h
index 013899f600..6a7ea8e781 100644
--- a/keyboards/latin17rgb/config.h
+++ b/keyboards/latin17rgb/config.h
@@ -1,18 +1,18 @@
/* Copyright 2021 18438880
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
#pragma once
@@ -56,7 +56,7 @@
#ifdef RGB_MATRIX_ENABLE
# define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_KEYPRESSES
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
# define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
@@ -100,5 +100,3 @@
#define RGBLIGHT_VAL_STEP 5
#define RGBLIGHT_SLEEP
#endif
-
-
diff --git a/keyboards/latin60rgb/config.h b/keyboards/latin60rgb/config.h
index bbe502054a..97b4812910 100644
--- a/keyboards/latin60rgb/config.h
+++ b/keyboards/latin60rgb/config.h
@@ -1,18 +1,18 @@
/* Copyright 2021 latincompass
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
#pragma once
/* USB Device descriptor parameter */
@@ -53,7 +53,7 @@
#ifdef RGB_MATRIX_ENABLE
# define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_KEYPRESSES
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
# define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
@@ -77,4 +77,3 @@
# define DRIVER_1_LED_TOTAL 60
# define DRIVER_LED_TOTAL DRIVER_1_LED_TOTAL
#endif
-
diff --git a/keyboards/le_chiffre/config.h b/keyboards/le_chiffre/config.h
index e14b4665f2..af4d1e49cf 100644
--- a/keyboards/le_chiffre/config.h
+++ b/keyboards/le_chiffre/config.h
@@ -69,7 +69,7 @@
#ifdef RGB_MATRIX_ENABLE
#define RGB_MATRIX_KEYPRESSES // reacts to keypresses
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+#define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_FRAMEBUFFER_EFFECTS
#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 150 // limits maximum brightness of LEDs to 150 out of 255. Higher may cause the controller to crash.
#define RGB_MATRIX_HUE_STEP 8
diff --git a/keyboards/marksard/rhymestone/rev1/config.h b/keyboards/marksard/rhymestone/rev1/config.h
index 9a1bf0a1d8..9833925110 100644
--- a/keyboards/marksard/rhymestone/rev1/config.h
+++ b/keyboards/marksard/rhymestone/rev1/config.h
@@ -93,7 +93,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define RGB_MATRIX_KEYPRESSES // reacts to keypresses
// #define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (instead of keypresses)
// #define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
- #define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+ #define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
// #define RGB_MATRIX_LED_PROCESS_LIMIT (DRIVER_LED_TOTAL + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
// #define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 150 // limits maximum brightness of LEDs to 200 out of 255. If not defined maximum brightness is set to 255
diff --git a/keyboards/massdrop/alt/keymaps/pregame/config.h b/keyboards/massdrop/alt/keymaps/pregame/config.h
index acd041ce14..32dee56d30 100644
--- a/keyboards/massdrop/alt/keymaps/pregame/config.h
+++ b/keyboards/massdrop/alt/keymaps/pregame/config.h
@@ -89,7 +89,7 @@
// #define RGBLIGHT_SAT_STEP 25 // Units to step when in/decreasing saturation
// #define RGBLIGHT_VAL_STEP 12 // Units to step when in/decreasing value (brightness)
// #define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-// #define RGB_DISABLE_WHEN_USB_SUSPENDED false // turn off effects when suspended
+// #define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
// #define RGB_MATRIX_LED_PROCESS_LIMIT (DRIVER_LED_TOTAL + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
// #define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
#define RGBLIGHT_ANIMATIONS // Run RGB animations
@@ -103,7 +103,7 @@
// #define RGBLIGHT_EFFECT_RGB_TEST // Enable RGB test animation mode.
// #define RGBLIGHT_EFFECT_SNAKE // Enable snake animation mode.
// #define RGBLIGHT_EFFECT_STATIC_GRADIENT // Enable static gradient mode.
-
+
// #define RGBLIGHT_EFFECT_BREATHE_CENTER // If defined, used to calculate the curve for the breathing animation. Valid values are 1.0 to 2.7
// #define RGBLIGHT_EFFECT_BREATHE_MAX 255 // The maximum brightness for the breathing mode. Valid values are 1 to 255
// #define RGBLIGHT_EFFECT_CHRISTMAS_INTERVAL 1000 // How long to wait between light changes for the "Christmas" animation, in milliseconds
diff --git a/keyboards/massdrop/alt/keymaps/urbanvanilla/config.h b/keyboards/massdrop/alt/keymaps/urbanvanilla/config.h
index 0f2740013d..f2a7e50386 100644
--- a/keyboards/massdrop/alt/keymaps/urbanvanilla/config.h
+++ b/keyboards/massdrop/alt/keymaps/urbanvanilla/config.h
@@ -24,4 +24,4 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define RGB_MATRIX_LED_PROCESS_LIMIT 15
#define RGB_MATRIX_LED_FLUSH_LIMIT 10
-#define RGB_DISABLE_WHEN_USB_SUSPENDED false // turn off effects when suspended
+// #define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
diff --git a/keyboards/massdrop/ctrl/keymaps/endgame/config.h b/keyboards/massdrop/ctrl/keymaps/endgame/config.h
index 0ef485591f..ad738347ab 100644
--- a/keyboards/massdrop/ctrl/keymaps/endgame/config.h
+++ b/keyboards/massdrop/ctrl/keymaps/endgame/config.h
@@ -49,7 +49,7 @@
// #define RGBLIGHT_SAT_STEP 25 // Units to step when in/decreasing saturation
// #define RGBLIGHT_VAL_STEP 12 // Units to step when in/decreasing value (brightness)
// #define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-// #define RGB_DISABLE_WHEN_USB_SUSPENDED false // turn off effects when suspended
+// #define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
// #define RGB_MATRIX_LED_PROCESS_LIMIT (DRIVER_LED_TOTAL + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
// #define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
// #define RGBLIGHT_ANIMATIONS // Run RGB animations
diff --git a/keyboards/massdrop/ctrl/keymaps/matthewrobo/config.h b/keyboards/massdrop/ctrl/keymaps/matthewrobo/config.h
index 6e16c3a5f9..89c129c58e 100644
--- a/keyboards/massdrop/ctrl/keymaps/matthewrobo/config.h
+++ b/keyboards/massdrop/ctrl/keymaps/matthewrobo/config.h
@@ -67,7 +67,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// #define RGBLIGHT_SAT_STEP 25 // Units to step when in/decreasing saturation
// #define RGBLIGHT_VAL_STEP 12 // Units to step when in/decreasing value (brightness)
// #define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-// #define RGB_DISABLE_WHEN_USB_SUSPENDED false // turn off effects when suspended
+// #define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
// #define RGB_MATRIX_LED_PROCESS_LIMIT (DRIVER_LED_TOTAL + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
// #define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
// #define RGBLIGHT_ANIMATIONS // Run RGB animations
diff --git a/keyboards/mechlovin/adelais/rgb_led/rev1/config.h b/keyboards/mechlovin/adelais/rgb_led/rev1/config.h
index 1ba7d27dff..d75cbd3f2a 100644
--- a/keyboards/mechlovin/adelais/rgb_led/rev1/config.h
+++ b/keyboards/mechlovin/adelais/rgb_led/rev1/config.h
@@ -13,7 +13,7 @@
#define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (instead of keypresses)
#define RGB_MATRIX_FRAMEBUFFER_EFFECTS
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-#define RGB_DISABLE_WHEN_USB_SUSPENDED false // turn off effects when suspended
+// #define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 220 // limits maximum brightness of LEDs to 200 out of 255. If not defined maximum brightness is set to 255
-#define RGB_MATRIX_STARTUP_MODE RGB_MATRIX_CYCLE_PINWHEEL // Sets the default mode, if none has been set \ No newline at end of file
+#define RGB_MATRIX_STARTUP_MODE RGB_MATRIX_CYCLE_PINWHEEL // Sets the default mode, if none has been set
diff --git a/keyboards/mechlovin/adelais/rgb_led/rev2/config.h b/keyboards/mechlovin/adelais/rgb_led/rev2/config.h
index 38ffdd40ae..c830edce26 100644
--- a/keyboards/mechlovin/adelais/rgb_led/rev2/config.h
+++ b/keyboards/mechlovin/adelais/rgb_led/rev2/config.h
@@ -1,7 +1,7 @@
#pragma once
#define PRODUCT_ID 0xAEC2
-#define PRODUCT Adelais En Ciel Rev2
+#define PRODUCT Adelais En Ciel Rev2
#define MATRIX_ROW_PINS { B1, A0, C13, A1, A2}
#define MATRIX_COL_PINS { A10, A9, A8, B15, B14, B13, B12, B11, B10, B8, B4, B5, B3, C14, A7 }
@@ -31,7 +31,7 @@
#define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (instead of keypresses)
#define RGB_MATRIX_FRAMEBUFFER_EFFECTS
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-#define RGB_DISABLE_WHEN_USB_SUSPENDED false // turn off effects when suspended
+// #define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 255 // limits maximum brightness of LEDs to 200 out of 255. If not defined maximum brightness is set to 255
#define RGB_MATRIX_STARTUP_MODE RGB_MATRIX_CYCLE_PINWHEEL // Sets the default mode, if none has been set
@@ -42,4 +42,4 @@
#define ENCODERS_PAD_B { A3 }
#define ENCODER_RESOLUTION 4
-#define TAP_CODE_DELAY 10 \ No newline at end of file
+#define TAP_CODE_DELAY 10
diff --git a/keyboards/mechlovin/delphine/rgb_led/config.h b/keyboards/mechlovin/delphine/rgb_led/config.h
index 4d5c853d0c..9a653d7595 100644
--- a/keyboards/mechlovin/delphine/rgb_led/config.h
+++ b/keyboards/mechlovin/delphine/rgb_led/config.h
@@ -24,7 +24,7 @@
// #define RGBLIGHT_EFFECT_RGB_TEST
// #define RGBLIGHT_EFFECT_ALTERNATING
#endif
-
+
//rgb matrix setting// This is a 7-bit address, that gets left-shifted and bit 0
// set to 0 for write, 1 for read (as per I2C protocol)
// The address will vary depending on your wiring:
@@ -41,7 +41,7 @@
#define RGB_MATRIX_KEYPRESSES // reacts to keypresses
#define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (instead of keypresses)
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-#define RGB_DISABLE_WHEN_USB_SUSPENDED false // turn off effects when suspended
+// #define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 255 // limits maximum brightness of LEDs to 200 out of 255. If not defined maximum brightness is set to 255
#define RGB_MATRIX_STARTUP_MODE RGB_MATRIX_CYCLE_PINWHEEL // Sets the default mode, if none has been set
diff --git a/keyboards/mechlovin/hannah60rgb/rev1/config.h b/keyboards/mechlovin/hannah60rgb/rev1/config.h
index 20873e7161..fd45ecca6c 100644
--- a/keyboards/mechlovin/hannah60rgb/rev1/config.h
+++ b/keyboards/mechlovin/hannah60rgb/rev1/config.h
@@ -11,8 +11,8 @@
# define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (instead of keypresses)
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
# define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED false // turn off effects when suspended
+// # define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
# define RGB_MATRIX_MAXIMUM_BRIGHTNESS 255 // limits maximum brightness of LEDs to 200 out of 255. If not defined maximum brightness is set to 255
# define RGB_MATRIX_STARTUP_MODE RGB_MATRIX_CYCLE_PINWHEEL // Sets the default mode, if none has been set
-#endif \ No newline at end of file
+#endif
diff --git a/keyboards/mechlovin/hannah60rgb/rev2/config.h b/keyboards/mechlovin/hannah60rgb/rev2/config.h
index 2bcffbc856..5e57f985d3 100644
--- a/keyboards/mechlovin/hannah60rgb/rev2/config.h
+++ b/keyboards/mechlovin/hannah60rgb/rev2/config.h
@@ -30,11 +30,11 @@
#define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (instead of keypresses)
#define RGB_MATRIX_FRAMEBUFFER_EFFECTS
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-#define RGB_DISABLE_WHEN_USB_SUSPENDED false // turn off effects when suspended
+// #define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 255 // limits maximum brightness of LEDs to 200 out of 255. If not defined maximum brightness is set to 255
#define RGB_MATRIX_STARTUP_MODE RGB_MATRIX_CYCLE_PINWHEEL // Sets the default mode, if none has been set
#if defined(RGBLIGHT_ENABLE) && defined(RGB_MATRIX_ENABLE)
# define RGB_MATRIX_DISABLE_KEYCODES
-#endif \ No newline at end of file
+#endif
diff --git a/keyboards/mechlovin/infinity87/rgb_rev1/config.h b/keyboards/mechlovin/infinity87/rgb_rev1/config.h
index 0c16c684cf..76c6e0db73 100644
--- a/keyboards/mechlovin/infinity87/rgb_rev1/config.h
+++ b/keyboards/mechlovin/infinity87/rgb_rev1/config.h
@@ -35,7 +35,7 @@
// 0b0110001 AD <-> SCL
// 0b0110010 AD <-> SDA
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+#define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_KEYPRESSES
#define DISABLE_RGB_MATRIX_SPLASH
#define DISABLE_RGB_MATRIX_MULTISPLASH
diff --git a/keyboards/melgeek/mj61/config.h b/keyboards/melgeek/mj61/config.h
index 164c04fb50..6ba19dd757 100644
--- a/keyboards/melgeek/mj61/config.h
+++ b/keyboards/melgeek/mj61/config.h
@@ -37,7 +37,7 @@
#define NO_ACTION_FUNCTION
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+#define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_KEYPRESSES
#define RGB_MATRIX_LED_PROCESS_LIMIT 4
#define RGB_MATRIX_LED_FLUSH_LIMIT 26
diff --git a/keyboards/melgeek/mj63/config.h b/keyboards/melgeek/mj63/config.h
index 47ad2f96cf..46d3b0fb7b 100644
--- a/keyboards/melgeek/mj63/config.h
+++ b/keyboards/melgeek/mj63/config.h
@@ -37,7 +37,7 @@
#define NO_ACTION_FUNCTION
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+#define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_KEYPRESSES
#define RGB_MATRIX_LED_PROCESS_LIMIT 4
#define RGB_MATRIX_LED_FLUSH_LIMIT 26
diff --git a/keyboards/melgeek/mj64/config.h b/keyboards/melgeek/mj64/config.h
index 29cb95f171..920d34acd5 100644
--- a/keyboards/melgeek/mj64/config.h
+++ b/keyboards/melgeek/mj64/config.h
@@ -37,7 +37,7 @@
#define NO_ACTION_FUNCTION
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+#define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_KEYPRESSES
#define RGB_MATRIX_LED_PROCESS_LIMIT 4
#define RGB_MATRIX_LED_FLUSH_LIMIT 26
diff --git a/keyboards/melgeek/mj65/config.h b/keyboards/melgeek/mj65/config.h
index 12a7c7ce18..399c243ac6 100644
--- a/keyboards/melgeek/mj65/config.h
+++ b/keyboards/melgeek/mj65/config.h
@@ -37,7 +37,7 @@
#define NO_ACTION_FUNCTION
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+#define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_KEYPRESSES
#define RGB_MATRIX_LED_PROCESS_LIMIT 4
#define RGB_MATRIX_LED_FLUSH_LIMIT 26
diff --git a/keyboards/melgeek/mojo75/config.h b/keyboards/melgeek/mojo75/config.h
index c1a8083f1c..d5bb4b4547 100644
--- a/keyboards/melgeek/mojo75/config.h
+++ b/keyboards/melgeek/mojo75/config.h
@@ -37,7 +37,7 @@
#define NO_ACTION_FUNCTION
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+#define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_KEYPRESSES
#define RGB_MATRIX_LED_PROCESS_LIMIT 4
#define RGB_MATRIX_LED_FLUSH_LIMIT 26
diff --git a/keyboards/melgeek/z70ultra/config.h b/keyboards/melgeek/z70ultra/config.h
index d5a9d0a894..e4530e2eaa 100644
--- a/keyboards/melgeek/z70ultra/config.h
+++ b/keyboards/melgeek/z70ultra/config.h
@@ -36,7 +36,7 @@
#define NO_ACTION_FUNCTION
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+#define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_KEYPRESSES
#define RGB_MATRIX_LED_PROCESS_LIMIT 4
#define RGB_MATRIX_LED_FLUSH_LIMIT 26
diff --git a/keyboards/miller/gm862/config.h b/keyboards/miller/gm862/config.h
index 2b084efc25..e6e1b4c1df 100644
--- a/keyboards/miller/gm862/config.h
+++ b/keyboards/miller/gm862/config.h
@@ -36,10 +36,10 @@
#define DEBOUNCE 3
#ifdef RGB_MATRIX_ENABLE
# define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_KEYPRESSES
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
-# define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
+# define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
# define DISABLE_RGB_MATRIX_BAND_SAT
# define DISABLE_RGB_MATRIX_BAND_PINWHEEL_SAT
# define DISABLE_RGB_MATRIX_BAND_SPIRAL_SAT
diff --git a/keyboards/monstargear/xo87/rgb/config.h b/keyboards/monstargear/xo87/rgb/config.h
index 83eee83492..5ed0ed445d 100644
--- a/keyboards/monstargear/xo87/rgb/config.h
+++ b/keyboards/monstargear/xo87/rgb/config.h
@@ -36,7 +36,7 @@
#define DIODE_DIRECTION ROW2COL
#define RGB_DI_PIN D7
#define DRIVER_LED_TOTAL 110
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true
+#define RGB_DISABLE_WHEN_USB_SUSPENDED
#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 100 // limits maximum brightness of LEDs to 100 out of 255.
#define RGBLIGHT_LIMIT_VAL 100 // limits maximum brightness of LEDs to 100 out of 255.
diff --git a/keyboards/moonlander/config.h b/keyboards/moonlander/config.h
index c88feea3d0..c1a139dc77 100644
--- a/keyboards/moonlander/config.h
+++ b/keyboards/moonlander/config.h
@@ -91,7 +91,7 @@
#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 175
#define RGB_MATRIX_FRAMEBUFFER_EFFECTS
#define RGB_MATRIX_KEYPRESSES
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true
+#define RGB_DISABLE_WHEN_USB_SUSPENDED
#define MUSIC_MAP
diff --git a/keyboards/mt84/keymaps/default/config.h b/keyboards/mt84/keymaps/default/config.h
new file mode 100644
index 0000000000..dd687cad58
--- /dev/null
+++ b/keyboards/mt84/keymaps/default/config.h
@@ -0,0 +1,19 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#define LAYER_STATE_8BIT
diff --git a/keyboards/naked48/keymaps/salicylic/config.h b/keyboards/naked48/keymaps/salicylic/config.h
index b6372db3b9..71a43e208c 100644
--- a/keyboards/naked48/keymaps/salicylic/config.h
+++ b/keyboards/naked48/keymaps/salicylic/config.h
@@ -31,7 +31,7 @@
# define RGB_MATRIX_KEYPRESSES // reacts to keypresses
// # define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (instead of keypresses)
// # define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
// # define RGB_MATRIX_LED_PROCESS_LIMIT (DRIVER_LED_TOTAL + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
// # define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
// # define RGB_MATRIX_MAXIMUM_BRIGHTNESS 150 // limits maximum brightness of LEDs to 200 out of 255. If not defined maximum brightness is set to 255
@@ -41,4 +41,3 @@
# define RGB_MATRIX_VAL_STEP 5
# define RGB_MATRIX_SPD_STEP 10
#endif
-
diff --git a/keyboards/opendeck/32/rev1/config.h b/keyboards/opendeck/32/rev1/config.h
index 9f8ed74278..8b25ab2564 100644
--- a/keyboards/opendeck/32/rev1/config.h
+++ b/keyboards/opendeck/32/rev1/config.h
@@ -38,7 +38,7 @@
#define DRIVER_COUNT 1
#define DRIVER_1_LED_TOTAL (4 * 8 * 3)
#define DRIVER_LED_TOTAL (DRIVER_1_LED_TOTAL)
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true
+#define RGB_DISABLE_WHEN_USB_SUSPENDED
#define RGB_MATRIX_STARTUP_MODE RGB_MATRIX_CYCLE_SPIRAL
#define RGB_MATRIX_DISABLE_KEYCODES
diff --git a/keyboards/percent/canoe_gen2/config.h b/keyboards/percent/canoe_gen2/config.h
index bac5ebb3f3..6409371d40 100644
--- a/keyboards/percent/canoe_gen2/config.h
+++ b/keyboards/percent/canoe_gen2/config.h
@@ -64,4 +64,4 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define RGB_MATRIX_STARTUP_SAT 255
#define RGB_MATRIX_STARTUP_VAL RGB_MATRIX_MAXIMUM_BRIGHTNESS
#define RGB_MATRIX_STARTUP_SPD 127
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true
+#define RGB_DISABLE_WHEN_USB_SUSPENDED
diff --git a/keyboards/phase_studio/titan65/config.h b/keyboards/phase_studio/titan65/config.h
index 4104c2ec2c..66ae4f20be 100644
--- a/keyboards/phase_studio/titan65/config.h
+++ b/keyboards/phase_studio/titan65/config.h
@@ -47,5 +47,5 @@
#define RGB_DI_PIN E6
#define DRIVER_LED_TOTAL 67
#define RGB_MATRIX_KEYPRESSES // reacts to keypresses
-#define RGB_DISABLE_WHEN_USB_SUSPENDED false // turn off effects when suspended
+// #define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 150 // limits maximum brightness of LEDs to 200 out of 255. If not defined maximum brightness is set to 255
diff --git a/keyboards/planck/ez/config.h b/keyboards/planck/ez/config.h
index 7f88764963..5317a51568 100644
--- a/keyboards/planck/ez/config.h
+++ b/keyboards/planck/ez/config.h
@@ -147,7 +147,7 @@
#define RGB_MATRIX_KEYPRESSES
#define RGB_MATRIX_FRAMEBUFFER_EFFECTS
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true
+#define RGB_DISABLE_WHEN_USB_SUSPENDED
#define RGB_MATRIX_LED_PROCESS_LIMIT 5
#define RGB_MATRIX_LED_FLUSH_LIMIT 26
diff --git a/keyboards/planck/rev6/config.h b/keyboards/planck/rev6/config.h
index 4bc8a509f6..18bb740968 100644
--- a/keyboards/planck/rev6/config.h
+++ b/keyboards/planck/rev6/config.h
@@ -141,7 +141,7 @@
#define WS2812_DMA_CHANNEL 2
#ifndef RGB_DISABLE_WHEN_USB_SUSPENDED
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true
+# define RGB_DISABLE_WHEN_USB_SUSPENDED
#endif
#endif
diff --git a/keyboards/setta21/keymaps/salicylic/config.h b/keyboards/setta21/keymaps/salicylic/config.h
index 44b34aa2fd..06e23ba7a3 100644
--- a/keyboards/setta21/keymaps/salicylic/config.h
+++ b/keyboards/setta21/keymaps/salicylic/config.h
@@ -27,7 +27,7 @@
# define RGB_MATRIX_KEYPRESSES // reacts to keypresses
// # define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (instead of keypresses)
// # define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
// # define RGB_MATRIX_LED_PROCESS_LIMIT (DRIVER_LED_TOTAL + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
// # define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
// # define RGB_MATRIX_MAXIMUM_BRIGHTNESS 150 // limits maximum brightness of LEDs to 200 out of 255. If not defined maximum brightness is set to 255
@@ -37,4 +37,3 @@
# define RGB_MATRIX_VAL_STEP 5
# define RGB_MATRIX_SPD_STEP 10
#endif
-
diff --git a/keyboards/sofle/keymaps/devdev/config.h b/keyboards/sofle/keymaps/devdev/config.h
index 7d597d991a..32d0717352 100644
--- a/keyboards/sofle/keymaps/devdev/config.h
+++ b/keyboards/sofle/keymaps/devdev/config.h
@@ -1,18 +1,18 @@
/* Copyright 2021 Dane Evans
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
#pragma once
@@ -29,7 +29,7 @@
#define CUSTOM_FONT
-#define CUSTOM_LAYER_READ //if you remove this it causes issues - needs better guarding
+#define CUSTOM_LAYER_READ //if you remove this it causes issues - needs better guarding
#define TAPPING_FORCE_HOLD
@@ -56,7 +56,7 @@
#ifdef RGBLIGHT_ENABLE
#undef RGBLED_NUM
-
+
//#define RGBLIGHT_ANIMATIONS
//#define RGBLIGHT_EFFECT_BREATHING
#define RGBLIGHT_EFFECT_RAINBOW_MOOD
@@ -68,11 +68,11 @@
//#define RGBLIGHT_EFFECT_RGB_TEST
//#define RGBLIGHT_EFFECT_ALTERNATING
//#define RGBLIGHT_EFFECT_TWINKLE
-
+
#define RGBLED_NUM 70
//#define RGBLED_SPLIT
- #define RGBLED_SPLIT { 35, 35 } // haven't figured out how to use this yet
-
+ #define RGBLED_SPLIT { 35, 35 } // haven't figured out how to use this yet
+
//#define RGBLED_NUM 30
#define RGBLIGHT_LIMIT_VAL 120
#define RGBLIGHT_HUE_STEP 10
@@ -84,11 +84,11 @@
# define RGB_MATRIX_KEYPRESSES // reacts to keypresses
// # define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (instead of keypresses)
// # define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
// # define RGB_MATRIX_LED_PROCESS_LIMIT (DRIVER_LED_TOTAL + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
// # define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
-# define RGB_MATRIX_MAXIMUM_BRIGHTNESS 150 // limits maximum brightness of LEDs to 150 out of 255. Higher may cause the controller to crash.
+# define RGB_MATRIX_MAXIMUM_BRIGHTNESS 150 // limits maximum brightness of LEDs to 150 out of 255. Higher may cause the controller to crash.
#define RGB_MATRIX_STARTUP_MODE RGB_MATRIX_GRADIENT_LEFT_RIGHT
@@ -127,4 +127,4 @@
// # define DISABLE_RGB_MATRIX_MULTISPLASH
// # define DISABLE_RGB_MATRIX_SOLID_SPLASH
// # define DISABLE_RGB_MATRIX_SOLID_MULTISPLASH
-#endif \ No newline at end of file
+#endif
diff --git a/keyboards/sofle/keymaps/killmaster/config.h b/keyboards/sofle/keymaps/killmaster/config.h
new file mode 100644
index 0000000000..2e6abe84e3
--- /dev/null
+++ b/keyboards/sofle/keymaps/killmaster/config.h
@@ -0,0 +1,64 @@
+/* Copyright 2021 Carlos Martins
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#pragma once
+
+/* The way how "handedness" is decided (which half is which),
+see https://docs.qmk.fm/#/feature_split_keyboard?id=setting-handedness
+for more options.
+*/
+
+#define RGB_DI_PIN D3
+
+#ifdef RGB_MATRIX_ENABLE
+
+#define RGBLED_NUM 72
+#define DRIVER_LED_TOTAL RGBLED_NUM
+#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 120 // limits maximum brightness of LEDs to 150 out of 255. Higher may cause the controller to crash.
+#define RGB_MATRIX_HUE_STEP 8
+#define RGB_MATRIX_SAT_STEP 8
+#define RGB_MATRIX_VAL_STEP 8
+#define RGB_MATRIX_SPD_STEP 10
+#define RGB_MATRIX_KEYPRESSES
+#define RGB_MATRIX_FRAMEBUFFER_EFFECTS
+#define RGB_MATRIX_SPLIT {36,36}
+#define SPLIT_TRANSPORT_MIRROR
+
+#endif
+
+#ifdef RGBLIGHT_ENABLE
+#define RGBLIGHT_SPLIT
+#define RGBLED_NUM 70
+#define RGB_SPLIT {36,36}
+#define RGBLIGHT_LIMIT_VAL 120
+// #define RGBLIGHT_SLEEP /* If defined, the RGB lighting will be switched off when the host goes to sleep */
+// /*== all animations enable ==*/
+// #define RGBLIGHT_ANIMATIONS
+// /*== or choose animations ==*/
+// #define RGBLIGHT_EFFECT_BREATHING
+ //#define RGBLIGHT_EFFECT_RAINBOW_MOOD
+ //#define RGBLIGHT_EFFECT_RAINBOW_SWIRL
+// #define RGBLIGHT_EFFECT_SNAKE
+// #define RGBLIGHT_EFFECT_KNIGHT
+// #define RGBLIGHT_EFFECT_CHRISTMAS
+ #define RGBLIGHT_EFFECT_STATIC_GRADIENT
+ #define RGBLIGHT_EFFECT_RGB_TEST
+// #define RGBLIGHT_EFFECT_ALTERNATING
+#endif
+
+#define MEDIA_KEY_DELAY 2
+
+#define USB_POLLING_INTERVAL_MS 1
+#define QMK_KEYS_PER_SCAN 12
diff --git a/keyboards/sofle/keymaps/killmaster/keymap.c b/keyboards/sofle/keymaps/killmaster/keymap.c
new file mode 100644
index 0000000000..950dee36b1
--- /dev/null
+++ b/keyboards/sofle/keymaps/killmaster/keymap.c
@@ -0,0 +1,403 @@
+/* Copyright 2021 Carlos Martins
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include QMK_KEYBOARD_H
+#include <stdio.h>
+
+enum sofle_layers {
+ /* _M_XYZ = Mac Os, _W_XYZ = Win/Linux */
+ _QWERTY,
+ _LOWER,
+ _RAISE,
+ _ADJUST,
+};
+
+enum custom_keycodes {
+ KC_QWERTY = SAFE_RANGE,
+ KC_LOWER,
+ KC_RAISE,
+ KC_ADJUST,
+ KC_PRVWD,
+ KC_NXTWD,
+ KC_LSTRT,
+ KC_LEND,
+ KC_DLINE
+};
+
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+/*
+ * QWERTY
+ * ,-----------------------------------------. ,-----------------------------------------.
+ * | ` | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | ` |
+ * |------+------+------+------+------+------| |------+------+------+------+------+------|
+ * | ESC | Q | W | E | R | T | | Y | U | I | O | P | Bspc |
+ * |------+------+------+------+------+------| |------+------+------+------+------+------|
+ * | Tab | A | S | D | F | G |-------. ,-------| H | J | K | L | ; | ' |
+ * |------+------+------+------+------+------| | | |------+------+------+------+------+------|
+ * |LShift| Z | X | C | V | B |-------| |-------| N | M | , | . | / |RShift|
+ * `-----------------------------------------/ / \ \-----------------------------------------'
+ * | LGUI | LAlt | LCTR |LOWER | /Space / \Enter \ |RAISE | RCTR | RAlt | RGUI |
+ * | | | | |/ / \ \ | | | | |
+ * `----------------------------------' '------''---------------------------'
+ */
+
+[_QWERTY] = LAYOUT(
+ KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS,
+ KC_ESC, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSPC,
+ KC_TAB, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT,
+ KC_LSPO, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_MUTE, KC_MPLY,KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSPC,
+ KC_LGUI,KC_LALT,KC_LCTRL, KC_LOWER, KC_SPC, KC_ENT, KC_RAISE, KC_RCTRL, KC_RALT, KC_RGUI
+),
+/* LOWER
+ * ,-----------------------------------------. ,-----------------------------------------.
+ * | | F1 | F2 | F3 | F4 | F5 | | F6 | F7 | F8 | F9 | F10 | F11 |
+ * |------+------+------+------+------+------| |------+------+------+------+------+------|
+ * | ` | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | F12 |
+ * |------+------+------+------+------+------| |------+------+------+------+------+------|
+ * | Tab | ! | @ | # | $ | % |-------. ,-------| ^ | & | * | ( | ) | | |
+ * |------+------+------+------+------+------| MUTE | | |------+------+------+------+------+------|
+ * | Shift| = | - | + | { | } |-------| |-------| [ | ] | ; | : | \ | Shift|
+ * `-----------------------------------------/ / \ \-----------------------------------------'
+ * | LGUI | LAlt | LCTR |LOWER | /Enter / \Space \ |RAISE | RCTR | RAlt | RGUI |
+ * | | | | |/ / \ \ | | | | |
+ * `----------------------------------' '------''---------------------------'
+ */
+[_LOWER] = LAYOUT(
+ _______, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11,
+ KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_F12,
+ _______, KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN, KC_PIPE,
+ _______, KC_EQL, KC_MINS, KC_PLUS, KC_LCBR, KC_RCBR, _______, _______, KC_LBRC, KC_RBRC, KC_SCLN, KC_COLN, KC_BSLS, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______
+),
+/* RAISE
+ * ,----------------------------------------. ,-----------------------------------------.
+ * | | | | | | | | | | | | | |
+ * |------+------+------+------+------+------| |------+------+------+------+------+------|
+ * | Esc | Ins | Pscr | Menu | |RGBTog| | | PWrd | Up | NWrd | DLine| Bspc |
+ * |------+------+------+------+------+------| |------+------+------+------+------+------|
+ * | Tab | LAt | LCtl |LShift| | Caps |-------. ,-------| | Left | Down | Rigth| Del | Bspc |
+ * |------+------+------+------+------+------| MUTE | | |------+------+------+------+------+------|
+ * |Shift | Undo | Cut | Copy | Paste| |-------| |-------| | LStr | | LEnd | | Shift|
+ * `-----------------------------------------/ / \ \-----------------------------------------'
+ * | LGUI | LAlt | LCTR |LOWER | /Enter / \Space \ |RAISE | RCTR | RAlt | RGUI |
+ * | | | | |/ / \ \ | | | | |
+ * `----------------------------------' '------''---------------------------'
+ */
+[_RAISE] = LAYOUT(
+ _______, _______ , _______ , _______ , RGB_RMOD , RGB_MOD, _______, _______ , _______, _______ , _______ ,_______,
+ _______, KC_INS, KC_PSCR, KC_APP, XXXXXXX, RGB_TOG, KC_PGUP, KC_PRVWD, KC_UP, KC_NXTWD,KC_DLINE, KC_BSPC,
+ _______, KC_LALT, KC_LCTL, KC_LSFT, XXXXXXX, KC_CAPS, KC_PGDN, KC_LEFT, KC_DOWN, KC_RGHT, KC_DEL, KC_BSPC,
+ _______,XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, _______, _______, XXXXXXX, KC_LSTRT, XXXXXXX, KC_LEND, XXXXXXX, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______
+),
+/* ADJUST
+ * ,-----------------------------------------. ,-----------------------------------------.
+ * | | | | | | | | | | | | | |
+ * |------+------+------+------+------+------| |------+------+------+------+------+------|
+ * | RESET| |QWERTY|COLEMAK| | | | | | | | | |
+ * |------+------+------+------+------+------| |------+------+------+------+------+------|
+ * | | |MACWIN| | | |-------. ,-------| | VOLDO| MUTE | VOLUP| | |
+ * |------+------+------+------+------+------| MUTE | | |------+------+------+------+------+------|
+ * | | | | | | |-------| |-------| | PREV | PLAY | NEXT | | |
+ * `-----------------------------------------/ / \ \-----------------------------------------'
+ * | LGUI | LAlt | LCTR |LOWER | /Enter / \Space \ |RAISE | RCTR | RAlt | RGUI |
+ * | | | | |/ / \ \ | | | | |
+ * `----------------------------------' '------''---------------------------'
+ */
+ [_ADJUST] = LAYOUT(
+ XXXXXXX , XXXXXXX, XXXXXXX , XXXXXXX , XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+ RESET , XXXXXXX, KC_QWERTY, XXXXXXX , CG_TOGG,XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+ XXXXXXX , XXXXXXX,CG_TOGG, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC_VOLD, KC_MUTE, KC_VOLU, XXXXXXX, XXXXXXX,
+ XXXXXXX , XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC_MPRV, KC_MPLY, KC_MNXT, XXXXXXX, XXXXXXX,
+ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______
+ )
+};
+
+#ifdef OLED_DRIVER_ENABLE
+
+static void render_logo(void) {
+ static const char PROGMEM bananas_logo[] = {
+ // 'killmaster_bananas', 128x32px
+ 0x00, 0x00, 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xe0, 0x02, 0x0e, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
+ 0x00, 0x00, 0x80, 0xc0, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40, 0xd8, 0xc8, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x08, 0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0xf8, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc0, 0x40, 0x40, 0xc0, 0x80, 0x40, 0xc0, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x40, 0x40, 0xc0, 0x40, 0x00, 0x00, 0x40, 0x40, 0xf0,
+ 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x40, 0x40, 0xc0, 0x80, 0x00, 0x00, 0x00,
+ 0x40, 0xc0, 0x80, 0x40, 0x40, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x0f, 0x3f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xf0,
+ 0xe0, 0xc0, 0xc0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
+ 0x02, 0x07, 0x0d, 0x10, 0x20, 0x20, 0x00, 0x00, 0x20, 0x20, 0x3f, 0x3f, 0x20, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x1f, 0x3f, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x3f, 0x20, 0x20, 0x20,
+ 0x00, 0x00, 0x3f, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x1c, 0x36, 0x22, 0x22, 0x22,
+ 0x1f, 0x20, 0x00, 0x00, 0x10, 0x23, 0x22, 0x22, 0x26, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x1f,
+ 0x30, 0x20, 0x20, 0x20, 0x00, 0x00, 0x0f, 0x1f, 0x32, 0x22, 0x22, 0x32, 0x23, 0x00, 0x00, 0x00,
+ 0x20, 0x3f, 0x21, 0x20, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07, 0x07, 0x0f, 0x0f, 0x0f, 0x1f, 0x1f,
+ 0x1f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3e, 0x3e, 0x1c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ oled_write_raw_P(bananas_logo, sizeof(bananas_logo));
+}
+
+static void print_status_narrow(void) {
+ // Print current mode
+ oled_write_P(PSTR("Sofle"), false);
+ oled_write_P(PSTR("\n\n\n"), false);
+ switch (get_highest_layer(default_layer_state)) {
+ case _QWERTY:
+ oled_write_ln_P(PSTR("QWERT"), false);
+ break;
+ default:
+ oled_write_P(PSTR("Undef"), false);
+ }
+ oled_write_P(PSTR("\n\n"), false);
+ // Print current layer
+ oled_write_ln_P(PSTR("Layer"), false);
+ switch (get_highest_layer(layer_state)) {
+ case _QWERTY:
+ oled_write_P(PSTR("Base\n"), false);
+ break;
+ case _RAISE:
+ oled_write_P(PSTR("Raise"), false);
+ break;
+ case _LOWER:
+ oled_write_P(PSTR("Lower"), false);
+ break;
+ case _ADJUST:
+ oled_write_P(PSTR("Adj\n"), false);
+ break;
+ default:
+ oled_write_ln_P(PSTR("Undef"), false);
+ }
+ oled_write_P(PSTR("\n\n"), false);
+}
+
+oled_rotation_t oled_init_user(oled_rotation_t rotation) {
+ if (is_keyboard_master()) {
+ return OLED_ROTATION_270;
+ }
+ else {
+ return OLED_ROTATION_180;
+ }
+ return rotation;
+}
+
+void oled_task_user(void) {
+ if (is_keyboard_master()) {
+ print_status_narrow();
+ } else {
+ render_logo();
+ }
+}
+
+
+
+#endif // OLED_DRIVER_ENABLE
+
+bool process_record_user(uint16_t keycode, keyrecord_t *record) {
+ switch (keycode) {
+ case KC_QWERTY:
+ if (record->event.pressed) {
+ set_single_persistent_default_layer(_QWERTY);
+ }
+ return false;
+ case KC_LOWER:
+ if (record->event.pressed) {
+ layer_on(_LOWER);
+ update_tri_layer(_LOWER, _RAISE, _ADJUST);
+ } else {
+ layer_off(_LOWER);
+ update_tri_layer(_LOWER, _RAISE, _ADJUST);
+ }
+ return false;
+ case KC_RAISE:
+ if (record->event.pressed) {
+ layer_on(_RAISE);
+ update_tri_layer(_LOWER, _RAISE, _ADJUST);
+ } else {
+ layer_off(_RAISE);
+ update_tri_layer(_LOWER, _RAISE, _ADJUST);
+ }
+ return false;
+ case KC_ADJUST:
+ if (record->event.pressed) {
+ layer_on(_ADJUST);
+ } else {
+ layer_off(_ADJUST);
+ }
+ return false;
+ case KC_PRVWD:
+ if (record->event.pressed) {
+ if (keymap_config.swap_lctl_lgui) {
+ register_mods(mod_config(MOD_LALT));
+ register_code(KC_LEFT);
+ } else {
+ register_mods(mod_config(MOD_LCTL));
+ register_code(KC_LEFT);
+ }
+ } else {
+ if (keymap_config.swap_lctl_lgui) {
+ unregister_mods(mod_config(MOD_LALT));
+ unregister_code(KC_LEFT);
+ } else {
+ unregister_mods(mod_config(MOD_LCTL));
+ unregister_code(KC_LEFT);
+ }
+ }
+ break;
+ case KC_NXTWD:
+ if (record->event.pressed) {
+ if (keymap_config.swap_lctl_lgui) {
+ register_mods(mod_config(MOD_LALT));
+ register_code(KC_RIGHT);
+ } else {
+ register_mods(mod_config(MOD_LCTL));
+ register_code(KC_RIGHT);
+ }
+ } else {
+ if (keymap_config.swap_lctl_lgui) {
+ unregister_mods(mod_config(MOD_LALT));
+ unregister_code(KC_RIGHT);
+ } else {
+ unregister_mods(mod_config(MOD_LCTL));
+ unregister_code(KC_RIGHT);
+ }
+ }
+ break;
+ case KC_LSTRT:
+ if (record->event.pressed) {
+ if (keymap_config.swap_lctl_lgui) {
+ //CMD-arrow on Mac, but we have CTL and GUI swapped
+ register_mods(mod_config(MOD_LCTL));
+ register_code(KC_LEFT);
+ } else {
+ register_code(KC_HOME);
+ }
+ } else {
+ if (keymap_config.swap_lctl_lgui) {
+ unregister_mods(mod_config(MOD_LCTL));
+ unregister_code(KC_LEFT);
+ } else {
+ unregister_code(KC_HOME);
+ }
+ }
+ break;
+ case KC_LEND:
+ if (record->event.pressed) {
+ if (keymap_config.swap_lctl_lgui) {
+ //CMD-arrow on Mac, but we have CTL and GUI swapped
+ register_mods(mod_config(MOD_LCTL));
+ register_code(KC_RIGHT);
+ } else {
+ register_code(KC_END);
+ }
+ } else {
+ if (keymap_config.swap_lctl_lgui) {
+ unregister_mods(mod_config(MOD_LCTL));
+ unregister_code(KC_RIGHT);
+ } else {
+ unregister_code(KC_END);
+ }
+ }
+ break;
+ case KC_DLINE:
+ if (record->event.pressed) {
+ register_mods(mod_config(MOD_LCTL));
+ register_code(KC_BSPC);
+ } else {
+ unregister_mods(mod_config(MOD_LCTL));
+ unregister_code(KC_BSPC);
+ }
+ break;
+ }
+ return true;
+}
+
+#ifdef ENCODER_ENABLE
+
+bool encoder_update_user(uint8_t index, bool clockwise) {
+ uint8_t temp_mod = get_mods();
+ uint8_t temp_osm = get_oneshot_mods();
+ bool is_ctrl = (temp_mod | temp_osm) & MOD_MASK_CTRL;
+ bool is_shift = (temp_mod | temp_osm) & MOD_MASK_SHIFT;
+
+ if (is_shift) {
+ if (index == 0) { /* First encoder */
+ if (clockwise) {
+ rgb_matrix_increase_hue();
+ } else {
+ rgb_matrix_decrease_hue();
+ }
+ } else if (index == 1) { /* Second encoder */
+ if (clockwise) {
+ rgb_matrix_decrease_sat();
+ } else {
+ rgb_matrix_increase_sat();
+ }
+ }
+ } else if (is_ctrl) {
+ if (index == 0) { /* First encoder */
+ if (clockwise) {
+ rgb_matrix_increase_val();
+ } else {
+ rgb_matrix_decrease_val();
+ }
+ } else if (index == 1) { /* Second encoder */
+ if (clockwise) {
+ rgb_matrix_increase_speed();
+ } else {
+ rgb_matrix_decrease_speed();
+ }
+ }
+ } else {
+ if (index == 1) { /* First encoder */
+ if (clockwise) {
+ tap_code(KC_PGUP);
+ // tap_code(KC_MS_WH_UP);
+ } else {
+ tap_code(KC_PGDOWN);
+ // tap_code(KC_MS_WH_DOWN);
+ }
+ } else if (index == 0) { /* Second encoder */
+ uint16_t mapped_code = 0;
+ if (clockwise) {
+ mapped_code = KC_VOLD;
+ } else {
+ mapped_code = KC_VOLU;
+ }
+ tap_code_delay(mapped_code, MEDIA_KEY_DELAY);
+ }
+ }
+ return true;
+}
+
+#endif
diff --git a/keyboards/sofle/keymaps/killmaster/readme.md b/keyboards/sofle/keymaps/killmaster/readme.md
new file mode 100644
index 0000000000..6d6dea228c
--- /dev/null
+++ b/keyboards/sofle/keymaps/killmaster/readme.md
@@ -0,0 +1,19 @@
+![SofleKeyboard default keymap](https://github.com/josefadamcik/SofleKeyboard/raw/master/Images/soflekeyboard.png)
+![SofleKeyboard adjust layer](https://github.com/josefadamcik/SofleKeyboard/raw/master/Images/soflekeyboard_layout_adjust.png)
+
+
+# Default keymap for Sofle Keyboard
+
+Layout in [Keyboard Layout Editor](http://www.keyboard-layout-editor.com/#/gists/76efb423a46cbbea75465cb468eef7ff) and [adjust layer](http://www.keyboard-layout-editor.com/#/gists/4bcf66f922cfd54da20ba04905d56bd4)
+
+
+Features:
+
+- Symmetric modifiers (CMD/Super, Alt/Opt, Ctrl, Shift)
+- Various modes, can be switched (using Adjust layer and the selected one is stored in EEPROM.
+- Modes for Qwerty and Colemak support
+- Modes for Mac vs Linux/Win support -> different order of modifiers and different action shortcuts on the "UPPER" layer (the red one in the image). Designed to simplify transtions when switching between operating systems often.
+- The OLED on master half shows selected mode and caps lock state and is rotated.
+- Left encoder controls volume up/down/mute. Right encoder PGUP/PGDOWN.
+
+
diff --git a/keyboards/sofle/keymaps/killmaster/rules.mk b/keyboards/sofle/keymaps/killmaster/rules.mk
new file mode 100644
index 0000000000..38d6114506
--- /dev/null
+++ b/keyboards/sofle/keymaps/killmaster/rules.mk
@@ -0,0 +1,4 @@
+EXTRAKEY_ENABLE = yes
+LTO_ENABLE = yes
+RGB_MATRIX_ENABLE = yes
+RGB_MATRIX_DRIVER = WS2812
diff --git a/keyboards/sofle/keymaps/rgb_default/config.h b/keyboards/sofle/keymaps/rgb_default/config.h
index 7d597d991a..32d0717352 100644
--- a/keyboards/sofle/keymaps/rgb_default/config.h
+++ b/keyboards/sofle/keymaps/rgb_default/config.h
@@ -1,18 +1,18 @@
/* Copyright 2021 Dane Evans
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
#pragma once
@@ -29,7 +29,7 @@
#define CUSTOM_FONT
-#define CUSTOM_LAYER_READ //if you remove this it causes issues - needs better guarding
+#define CUSTOM_LAYER_READ //if you remove this it causes issues - needs better guarding
#define TAPPING_FORCE_HOLD
@@ -56,7 +56,7 @@
#ifdef RGBLIGHT_ENABLE
#undef RGBLED_NUM
-
+
//#define RGBLIGHT_ANIMATIONS
//#define RGBLIGHT_EFFECT_BREATHING
#define RGBLIGHT_EFFECT_RAINBOW_MOOD
@@ -68,11 +68,11 @@
//#define RGBLIGHT_EFFECT_RGB_TEST
//#define RGBLIGHT_EFFECT_ALTERNATING
//#define RGBLIGHT_EFFECT_TWINKLE
-
+
#define RGBLED_NUM 70
//#define RGBLED_SPLIT
- #define RGBLED_SPLIT { 35, 35 } // haven't figured out how to use this yet
-
+ #define RGBLED_SPLIT { 35, 35 } // haven't figured out how to use this yet
+
//#define RGBLED_NUM 30
#define RGBLIGHT_LIMIT_VAL 120
#define RGBLIGHT_HUE_STEP 10
@@ -84,11 +84,11 @@
# define RGB_MATRIX_KEYPRESSES // reacts to keypresses
// # define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (instead of keypresses)
// # define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
// # define RGB_MATRIX_LED_PROCESS_LIMIT (DRIVER_LED_TOTAL + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
// # define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
-# define RGB_MATRIX_MAXIMUM_BRIGHTNESS 150 // limits maximum brightness of LEDs to 150 out of 255. Higher may cause the controller to crash.
+# define RGB_MATRIX_MAXIMUM_BRIGHTNESS 150 // limits maximum brightness of LEDs to 150 out of 255. Higher may cause the controller to crash.
#define RGB_MATRIX_STARTUP_MODE RGB_MATRIX_GRADIENT_LEFT_RIGHT
@@ -127,4 +127,4 @@
// # define DISABLE_RGB_MATRIX_MULTISPLASH
// # define DISABLE_RGB_MATRIX_SOLID_SPLASH
// # define DISABLE_RGB_MATRIX_SOLID_MULTISPLASH
-#endif \ No newline at end of file
+#endif
diff --git a/keyboards/sofle/rev1/readme.md b/keyboards/sofle/rev1/readme.md
new file mode 100644
index 0000000000..629d568e60
--- /dev/null
+++ b/keyboards/sofle/rev1/readme.md
@@ -0,0 +1,27 @@
+# Sofle Keyboard
+
+![SofleKeyboard version 1](https://raw.githubusercontent.com/josefadamcik/SofleKeyboard/master/Images/IMG_20200126_114622.jpg)
+
+Sofle is 6×4+5 keys column-staggered split keyboard. Based on Lily58, Corne and Helix keyboards.
+
+More details about the keyboard on my blog: [Let me introduce you SofleKeyboard - a split keyboard based on Lily58 and Crkbd](https://josef-adamcik.cz/electronics/let-me-introduce-you-sofle-keyboard-split-keyboard-based-on-lily58.html)
+
+The current (temporary) build guide and a build log is available here: [SofleKeyboard build log/guide](https://josef-adamcik.cz/electronics/soflekeyboard-build-log-and-build-guide.html)
+
+* Keyboard Maintainer: [Josef Adamcik](https://josef-adamcik.cz) [Twitter:@josefadamcik](https://twitter.com/josefadamcik)
+* Hardware Supported: SofleKeyboard PCB, ProMicro
+* Hardware Availability: [PCB & Case Data](https://github.com/josefadamcik/SofleKeyboard)
+
+Make example for this keyboard (after setting up your build environment):
+
+ make sofle:default
+
+Flashing example for this keyboard:
+
+ make sofle:default:flash
+
+Press reset button on he keyboard when asked.
+
+Disconnect the first half, connect the second one and repeat the process.
+
+See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
diff --git a/keyboards/sofle/rev1/rev1.c b/keyboards/sofle/rev1/rev1.c
index bbb014c4df..88a28e6a40 100644
--- a/keyboards/sofle/rev1/rev1.c
+++ b/keyboards/sofle/rev1/rev1.c
@@ -1 +1,87 @@
+/* Copyright 2021 Carlos Martins
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
#include "sofle.h"
+
+#ifdef RGB_MATRIX_ENABLE
+ // Physical Layout
+ // Columns
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13
+ // ROWS
+ // 12 13 22 23 32 33 33 32 23 22 13 12 0
+ // 02 03 04 04 03 02
+ // 11 14 21 24 31 34 34 31 24 21 14 11 1
+ // 01 01
+ // 10 15 20 25 30 35 35 30 25 20 15 10 2
+ //
+ // 09 16 19 26 29 36 36 29 26 19 16 09 3
+ //
+ // 08 17 18 27 28 28 27 18 17 08 4
+ // 07 06 05 05 06 07
+
+led_config_t g_led_config = {
+ {
+ { 11, 12, 21, 22, 31, 32 },
+ { 10, 13, 20, 23, 30, 33 },
+ { 9, 14, 19, 24, 29, 34},
+ { 8, 15, 18, 25, 28, 35},
+ { 7, 16, 17, 26, 27, NO_LED },
+ { 47, 48, 57, 58, 67, 68},
+ { 46, 49, 56, 59, 66, 69},
+ { 45, 50, 55, 60, 65, 70},
+ { 44, 51, 54, 61, 64, 71},
+ { 43, 52, 53, 62, 63, NO_LED }
+ },
+ {
+ // Left side underglow
+ {96, 40}, {16, 20}, {48, 10}, {80, 18}, {88, 60}, {56, 57}, {24,60},
+ // Left side Matrix
+ {32, 57}, { 0, 48}, { 0, 36}, { 0, 24}, { 0, 12},
+ {16, 12}, {16, 24}, {16, 36}, {16, 48}, {48, 55},
+ {64, 57}, {32, 45}, {32, 33}, {32, 21}, {32, 9},
+ {48, 7}, {48, 19}, {48, 31}, {48, 43}, {80, 59},
+ {96, 64}, {64, 45}, {64, 33}, {64, 21}, {64, 9},
+ {80, 10}, {80, 22}, {80, 34}, {80, 47},
+
+
+ // Right side underglow
+ {128, 40}, {208, 20}, {176, 10}, {144, 18}, {136, 60}, {168, 57}, {200,60},
+ // Right side Matrix
+ {192, 57}, {224, 48}, {224, 36}, {224, 24}, {224, 12},
+ {208, 12}, {208, 24}, {208, 36}, {208, 48}, {176, 55},
+ {160, 57}, {192, 45}, {192, 33}, {192, 21}, {192, 9},
+ {176, 7}, {176, 19}, {176, 31}, {176, 43}, {144, 59},
+ {128, 64}, {160, 45}, {160, 33}, {160, 21}, {160, 9},
+ {144, 10}, {144, 22}, {144, 34}, {144, 47},
+ },
+ {
+ LED_FLAG_NONE, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_NONE, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW, LED_FLAG_UNDERGLOW,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT,
+ LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT, LED_FLAG_KEYLIGHT
+ }
+};
+#endif
diff --git a/keyboards/terrazzo/config.h b/keyboards/terrazzo/config.h
index 985110d16b..907c94ff52 100644
--- a/keyboards/terrazzo/config.h
+++ b/keyboards/terrazzo/config.h
@@ -83,13 +83,13 @@ so there is only one configuration. */
#ifdef LED_MATRIX_ENABLE
-#define LED_DRIVER_ADDR_1 0x74
+#define LED_DRIVER_ADDR_1 0x74
#define LED_DRIVER_COUNT 1
#define DRIVER_LED_TOTAL 105
#define LED_MATRIX_ROWS 15
#define LED_MATRIX_COLS 7
#define LED_MATRIX_MAXIMUM_BRIGHTNESS 20
-#define LED_DISABLE_WHEN_USB_SUSPENDED true
+#define LED_DISABLE_WHEN_USB_SUSPENDED
#define DISABLE_LED_MATRIX_ALPHAS_MODS
#define DISABLE_LED_MATRIX_BREATHING
diff --git a/keyboards/tkc/portico/config.h b/keyboards/tkc/portico/config.h
index 4a7da833f7..ef6e46658a 100644
--- a/keyboards/tkc/portico/config.h
+++ b/keyboards/tkc/portico/config.h
@@ -45,7 +45,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
# define RGB_MATRIX_LED_FLUSH_LIMIT 26
# define DEBOUNCE 3
# define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_KEYPRESSES
# define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
# define DISABLE_RGB_MATRIX_BAND_SAT
diff --git a/keyboards/tokyo60/config.h b/keyboards/tokyokeyboard/tokyo60/config.h
index 03dee74e9b..03dee74e9b 100644
--- a/keyboards/tokyo60/config.h
+++ b/keyboards/tokyokeyboard/tokyo60/config.h
diff --git a/keyboards/tokyo60/info.json b/keyboards/tokyokeyboard/tokyo60/info.json
index 10d1bf093f..10d1bf093f 100644
--- a/keyboards/tokyo60/info.json
+++ b/keyboards/tokyokeyboard/tokyo60/info.json
diff --git a/keyboards/tokyo60/keymaps/default/config.h b/keyboards/tokyokeyboard/tokyo60/keymaps/default/config.h
index 271f48d001..271f48d001 100644
--- a/keyboards/tokyo60/keymaps/default/config.h
+++ b/keyboards/tokyokeyboard/tokyo60/keymaps/default/config.h
diff --git a/keyboards/tokyo60/keymaps/default/keymap.c b/keyboards/tokyokeyboard/tokyo60/keymaps/default/keymap.c
index 9139d15bc4..9139d15bc4 100644
--- a/keyboards/tokyo60/keymaps/default/keymap.c
+++ b/keyboards/tokyokeyboard/tokyo60/keymaps/default/keymap.c
diff --git a/keyboards/tokyo60/keymaps/swappedBottomRow/config.h b/keyboards/tokyokeyboard/tokyo60/keymaps/swappedBottomRow/config.h
index 271f48d001..271f48d001 100644
--- a/keyboards/tokyo60/keymaps/swappedBottomRow/config.h
+++ b/keyboards/tokyokeyboard/tokyo60/keymaps/swappedBottomRow/config.h
diff --git a/keyboards/tokyo60/keymaps/swappedBottomRow/keymap.c b/keyboards/tokyokeyboard/tokyo60/keymaps/swappedBottomRow/keymap.c
index 54b68f5825..54b68f5825 100644
--- a/keyboards/tokyo60/keymaps/swappedBottomRow/keymap.c
+++ b/keyboards/tokyokeyboard/tokyo60/keymaps/swappedBottomRow/keymap.c
diff --git a/keyboards/tokyo60/keymaps/via/keymap.c b/keyboards/tokyokeyboard/tokyo60/keymaps/via/keymap.c
index ffef9af795..ffef9af795 100644
--- a/keyboards/tokyo60/keymaps/via/keymap.c
+++ b/keyboards/tokyokeyboard/tokyo60/keymaps/via/keymap.c
diff --git a/keyboards/tokyo60/keymaps/via/rules.mk b/keyboards/tokyokeyboard/tokyo60/keymaps/via/rules.mk
index 1e5b99807c..1e5b99807c 100644
--- a/keyboards/tokyo60/keymaps/via/rules.mk
+++ b/keyboards/tokyokeyboard/tokyo60/keymaps/via/rules.mk
diff --git a/keyboards/tokyo60/readme.md b/keyboards/tokyokeyboard/tokyo60/readme.md
index 74f4e07ccd..56c31efad9 100644
--- a/keyboards/tokyo60/readme.md
+++ b/keyboards/tokyokeyboard/tokyo60/readme.md
@@ -1,15 +1,15 @@
# Tokyo60
​
-![Tokyo60](http://tokyokeyboard.com/wp-content/uploads/2018/02/AI7B4543_copy_page_20180215141449-1200x800.jpg)
+![Tokyo60](https://i2.wp.com/tokyokeyboard.com/wp-content/uploads/2018/02/AI7B4543_copy_page_20180215141449-1200x800.jpg)
​
Minimal hacker style mechanical keyboard designed in Tokyo. Full aluminum hi-pro construction with integrated top-plate. Cherry MX compatible. More Info at [Tokyo Keyboard](http://tokyokeyboard.com).
​
-* Keyboard Maintainer: [Tokyo Keyboard](http://tokyokeyboard.com)
-* Hardware Supported: Tokyo60 Rev.1
+* Keyboard Maintainer: [Tokyo Keyboard](https://tokyokeyboard.com)
+* Hardware Supported: Tokyo60 Rev.1 - 4
* Hardware Availability: [Drop](https://drop.com/buy/massdrop-x-tokyo-keyboard-tokyo60-keyboard-kit?mode=guest_open)
​
Make example for this keyboard (after setting up your build environment):
​
- make tokyo60:default
+ make tokyokeyboard/tokyo60:default
​
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
diff --git a/keyboards/tokyo60/rules.mk b/keyboards/tokyokeyboard/tokyo60/rules.mk
index fa639b1cab..fa639b1cab 100644
--- a/keyboards/tokyo60/rules.mk
+++ b/keyboards/tokyokeyboard/tokyo60/rules.mk
diff --git a/keyboards/tokyo60/tokyo60.c b/keyboards/tokyokeyboard/tokyo60/tokyo60.c
index 2126bb612d..2126bb612d 100644
--- a/keyboards/tokyo60/tokyo60.c
+++ b/keyboards/tokyokeyboard/tokyo60/tokyo60.c
diff --git a/keyboards/tokyo60/tokyo60.h b/keyboards/tokyokeyboard/tokyo60/tokyo60.h
index 9eb5f3e624..9eb5f3e624 100644
--- a/keyboards/tokyo60/tokyo60.h
+++ b/keyboards/tokyokeyboard/tokyo60/tokyo60.h
diff --git a/keyboards/whitefox/config.h b/keyboards/whitefox/config.h
index 4d7a460d26..1cdac01d07 100644
--- a/keyboards/whitefox/config.h
+++ b/keyboards/whitefox/config.h
@@ -62,6 +62,20 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define LED_BRIGHTNESS_LO 100
#define LED_BRIGHTNESS_HI 255
+/* LED matrix driver */
+#define LED_DRIVER_ADDR_1 0x74
+#define LED_DRIVER_COUNT 1
+#define DRIVER_LED_TOTAL 71
+#define LED_DISABLE_WHEN_USB_SUSPENDED
+
+/* i2c (for LED matrix) */
+#define I2C1_CLOCK_SPEED 400000
+#define I2C1_SCL_PAL_MODE PAL_MODE_ALTERNATIVE_2
+#define I2C1_SDA_PAL_MODE PAL_MODE_ALTERNATIVE_2
+#define I2C1_BANK GPIOB
+#define I2C1_SCL 0
+#define I2C1_SDA 1
+
/* If defined, GRAVE_ESC will always act as ESC when CTRL is held.
* This is useful for the Windows task manager shortcut (ctrl+shift+esc).
*/
diff --git a/keyboards/whitefox/rules.mk b/keyboards/whitefox/rules.mk
index 771804369c..7c1d0c3def 100644
--- a/keyboards/whitefox/rules.mk
+++ b/keyboards/whitefox/rules.mk
@@ -25,16 +25,12 @@ COMMAND_ENABLE = yes # Commands for debug and configuration
SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
# if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
NKRO_ENABLE = yes # USB Nkey Rollover
-BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality
RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
BLUETOOTH_ENABLE = no # Enable Bluetooth
AUDIO_ENABLE = no # Audio output
-BACKLIGHT_DRIVER = custom
-VISUALIZER_ENABLE = yes
-LED_DRIVER = is31fl3731c
-LED_WIDTH = 16
-LED_HEIGHT = 5
+LED_MATRIX_ENABLE = yes
+LED_MATRIX_DRIVER = IS31FL3731
LAYOUTS = 65_ansi 65_ansi_blocker 65_ansi_blocker_split_bs 65_iso 65_iso_blocker 65_iso_blocker_split_bs
diff --git a/keyboards/whitefox/whitefox.c b/keyboards/whitefox/whitefox.c
index ea083c6e09..f10f0fd5c4 100644
--- a/keyboards/whitefox/whitefox.c
+++ b/keyboards/whitefox/whitefox.c
@@ -16,3 +16,79 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "whitefox.h"
+
+#ifdef LED_MATRIX_ENABLE
+const is31_led g_is31_leds[DRIVER_LED_TOTAL] = {
+// The numbers in the comments are the led numbers DXX on the PCB
+/* Refer to IS31 manual for these locations
+ * driver
+ * | LED address
+ * | | */
+// 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ { 0, C1_1 }, { 0, C1_2 }, { 0, C1_3 }, { 0, C1_4 }, { 0, C1_5 }, { 0, C1_6 }, { 0, C1_7 }, { 0, C1_8 }, { 0, C2_1 }, { 0, C2_2 }, { 0, C2_3 }, { 0, C2_4 }, { 0, C2_5 }, { 0, C2_6 }, { 0, C2_7 }, { 0, C2_8 },
+// 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+ { 0, C3_1 }, { 0, C3_2 }, { 0, C3_3 }, { 0, C3_4 }, { 0, C3_5 }, { 0, C3_6 }, { 0, C3_7 }, { 0, C3_8 }, { 0, C4_1 }, { 0, C4_2 }, { 0, C4_3 }, { 0, C4_4 }, { 0, C4_5 }, { 0, C4_6 }, { 0, C4_7 },
+// 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
+ { 0, C4_8 }, { 0, C5_1 }, { 0, C5_2 }, { 0, C5_3 }, { 0, C5_4 }, { 0, C5_5 }, { 0, C5_6 }, { 0, C5_7 }, { 0, C5_8 }, { 0, C6_1 }, { 0, C6_2 }, { 0, C6_3 }, { 0, C6_4 }, { 0, C6_5 }, { 0, C6_6 },
+// 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
+ { 0, C6_7 }, { 0, C6_8 }, { 0, C7_1 }, { 0, C7_2 }, { 0, C7_3 }, { 0, C7_4 }, { 0, C7_5 }, { 0, C7_6 }, { 0, C7_7 }, { 0, C7_8 }, { 0, C8_1 }, { 0, C8_2 }, { 0, C8_3 }, { 0, C8_4 }, { 0, C8_5 },
+// 62 63 64 65 66 67 68 69 70 71
+ { 0, C8_6 }, { 0, C8_7 }, { 0, C8_8 }, { 0, C9_1 }, { 0, C9_2 }, { 0, C9_3 }, { 0, C9_4 }, { 0, C9_5 }, { 0, C9_6 }, { 0, C9_7 },
+};
+
+led_config_t g_led_config = {
+ {
+ // Key Matrix to LED Index
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8 },
+ { 9, 10, 11, 12, 13, 14, 15, 16, 17 },
+ { 18, 19, 20, 21, 22, 23, 24, 25, 26 },
+ { 27, 28, 29, 30, 31, 32, 33, 34, 35 },
+ { 36, 37, 38, 39, 40, 41, 42, 43, 44 },
+ { 45, 46, 47, 48, 49, 50, 51, 52, 53 },
+ { 54, 55, 56, 57, 58, 59, 60, 61, 62 },
+ { 63, 64, 65, 66, 67, 68, 69, 70, NO_LED },
+ }, {
+ // LED Index to Physical Position
+ { 0, 0 }, { 15, 0 }, { 30, 0 }, { 45, 0 }, { 60, 0 }, { 75, 0 }, { 90, 0 }, { 105, 0 }, { 119, 0 }, { 134, 0 }, { 149, 0 }, { 164, 0 }, { 179, 0 }, { 194, 0 }, { 209, 0 }, { 224, 0 },
+ { 4, 16 }, { 22, 16 }, { 37, 16 }, { 52, 16 }, { 67, 16 }, { 82, 16 }, { 97, 16 }, { 112, 16 }, { 127, 16 }, { 142, 16 }, { 157, 16 }, { 172, 16 }, { 187, 16 }, { 205, 16 }, { 224, 16 },
+ { 6, 32 }, { 26, 32 }, { 41, 32 }, { 56, 32 }, { 71, 32 }, { 86, 32 }, { 101, 32 }, { 116, 32 }, { 131, 32 }, { 146, 32 }, { 161, 32 }, { 175, 32 }, { 190, 32 }, { 207, 32 }, { 224, 32 },
+ { 2, 48 }, { 19, 48 }, { 34, 48 }, { 49, 48 }, { 63, 48 }, { 78, 48 }, { 93, 48 }, { 108, 48 }, { 123, 48 }, { 138, 48 }, { 153, 48 }, { 168, 48 }, { 189, 48 }, { 209, 48 }, { 224, 48 },
+ { 2, 64 }, { 21, 64 }, { 39, 64 }, { 95, 64 }, { 149, 64 }, { 164, 64 }, { 179, 64 }, { 194, 64 }, { 209, 64 }, { 224, 64 }
+ }, {
+ // LED Index to Flag
+ 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1,
+ 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1,
+ 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1,
+ 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ }
+};
+#endif
+
+void keyboard_pre_init_kb(void) {
+#ifdef LED_MATRIX_ENABLE
+ // Turn on LED controller
+ setPinOutput(B16);
+ writePinHigh(B16);
+#endif
+ keyboard_pre_init_user();
+}
+
+void matrix_init_kb(void) {
+ // put your keyboard start-up code here
+ // runs once when the firmware starts up
+
+#ifdef LED_MATRIX_ENABLE
+ /*
+ * Since K20x is stuck with a 32 byte EEPROM (see tmk_core/common/chibios/eeprom_teensy.c),
+ * and neither led_matrix_eeconfig.speed or .flags fit in this boundary, just force their values to default on boot.
+ */
+# if !defined(LED_MATRIX_STARTUP_SPD)
+# define LED_MATRIX_STARTUP_SPD UINT8_MAX / 2
+# endif
+ led_matrix_set_speed(LED_MATRIX_STARTUP_SPD),
+ led_matrix_set_flags(LED_FLAG_ALL);
+#endif
+
+ matrix_init_user();
+}
diff --git a/keyboards/xbows/nature/config.h b/keyboards/xbows/nature/config.h
index c1ff793352..e321f7ee1e 100644
--- a/keyboards/xbows/nature/config.h
+++ b/keyboards/xbows/nature/config.h
@@ -35,7 +35,7 @@
# define RGB_MATRIX_LED_PROCESS_LIMIT 18
# define RGB_MATRIX_LED_FLUSH_LIMIT 16
# define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# define RGB_MATRIX_KEYPRESSES
# define RGB_MATRIX_MAXIMUM_BRIGHTNESS 200
# define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
diff --git a/keyboards/xbows/woody/config.h b/keyboards/xbows/woody/config.h
index 7f396d0008..ea27508da8 100644
--- a/keyboards/xbows/woody/config.h
+++ b/keyboards/xbows/woody/config.h
@@ -16,10 +16,10 @@
#define RGB_MATRIX_LED_FLUSH_LIMIT 26
#define DEBOUNCE 3
#define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+#define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_KEYPRESSES
#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 200
-#define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
+#define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
#define DISABLE_RGB_MATRIX_BAND_SAT
#define DISABLE_RGB_MATRIX_BAND_PINWHEEL_SAT
#define DISABLE_RGB_MATRIX_BAND_SPIRAL_SAT
@@ -40,4 +40,4 @@
#define DRIVER_1_LED_TOTAL 35
#define DRIVER_2_LED_TOTAL 32
#define DRIVER_LED_TOTAL (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)
-#endif \ No newline at end of file
+#endif
diff --git a/keyboards/yncognito/batpad/config.h b/keyboards/yncognito/batpad/config.h
index 02c84a514a..7ca4072e07 100644
--- a/keyboards/yncognito/batpad/config.h
+++ b/keyboards/yncognito/batpad/config.h
@@ -47,13 +47,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define RGB_DI_PIN B5
#define DRIVER_LED_TOTAL 8
-#define RGB_MATRIX_KEYPRESSES
-#define RGB_MATRIX_KEYRELEASES
+#define RGB_MATRIX_KEYPRESSES
+#define RGB_MATRIX_KEYRELEASES
#define RGB_MATRIX_FRAMEBUFFER_EFFECTS
-#define RGB_DISABLE_AFTER_TIMEOUT 0
-#define RGB_DISABLE_WHEN_USB_SUSPENDED false
-#define RGB_MATRIX_LED_FLUSH_LIMIT 16
-#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 255
+#define RGB_DISABLE_AFTER_TIMEOUT 0
+// #define RGB_DISABLE_WHEN_USB_SUSPENDED
+#define RGB_MATRIX_LED_FLUSH_LIMIT 16
+#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 255
#define RGB_MATRIX_STARTUP_MODE RGB_MATRIX_CYCLE_ALL
-
-
diff --git a/layouts/community/ortho_4x12/bocaj/config.h b/layouts/community/ortho_4x12/bocaj/config.h
index 9a65684f35..c9d297f927 100644
--- a/layouts/community/ortho_4x12/bocaj/config.h
+++ b/layouts/community/ortho_4x12/bocaj/config.h
@@ -24,7 +24,7 @@
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
// #define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
// #define RGB_MATRIX_MAXIMUM_BRIGHTNESS 200 // limits maximum brightness of LEDs to 200 out of 255. If not defined maximum brightness is set to 255
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# undef RGB_MATRIX_LED_PROCESS_LIMIT
# undef RGB_MATRIX_LED_FLUSH_LIMIT
#endif
diff --git a/layouts/community/ortho_4x12/drashna/config.h b/layouts/community/ortho_4x12/drashna/config.h
index f4abd64f57..43143c3a3a 100644
--- a/layouts/community/ortho_4x12/drashna/config.h
+++ b/layouts/community/ortho_4x12/drashna/config.h
@@ -37,7 +37,7 @@
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
// #define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
// #define RGB_MATRIX_MAXIMUM_BRIGHTNESS 200 // limits maximum brightness of LEDs to 200 out of 255. If not defined maximum brightness is set to 255
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
# undef RGB_MATRIX_LED_PROCESS_LIMIT
# undef RGB_MATRIX_LED_FLUSH_LIMIT
# ifdef KEYBOARD_planck_rev6
diff --git a/layouts/community/split_3x6_3/drashna/config.h b/layouts/community/split_3x6_3/drashna/config.h
index dd950ce7bc..cc53d4c367 100644
--- a/layouts/community/split_3x6_3/drashna/config.h
+++ b/layouts/community/split_3x6_3/drashna/config.h
@@ -47,7 +47,7 @@
# define RGB_MATRIX_KEYPRESSES // reacts to keypresses
// # define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (instead of keypresses)
// # define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
// # define RGB_MATRIX_LED_PROCESS_LIMIT (DRIVER_LED_TOTAL + 4) / 5 // limits the number of LEDs to process in an animation per task run (increases keyboard responsiveness)
// # define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
# define RGB_MATRIX_MAXIMUM_BRIGHTNESS 120 // limits maximum brightness of LEDs to 200 out of 255. If not defined maximum brightness is set to 255
diff --git a/lib/chibios b/lib/chibios
-Subproject ffe54d63cb10a355add318f8e922e39f1c3d4bf
+Subproject 413e39c5681d181720440f2a8b7391f581788d7
diff --git a/lib/chibios-contrib b/lib/chibios-contrib
-Subproject 61baa6b036138c155f7cfc5646d833d9423f324
+Subproject 9c2bfa6aeba993345f5425d82807c101f8e25e6
diff --git a/lib/python/qmk/info.py b/lib/python/qmk/info.py
index 47c8bff7a8..b43cf4e417 100644
--- a/lib/python/qmk/info.py
+++ b/lib/python/qmk/info.py
@@ -146,6 +146,9 @@ def _pin_name(pin):
elif pin[0] in 'ABCDEFGHIJK' and pin[1].isdigit():
return pin
+ elif pin.startswith('LINE_PIN'):
+ return pin
+
raise ValueError(f'Invalid pin: {pin}')
diff --git a/platforms/chibios/IC_TEENSY_4_1/board/board.mk b/platforms/chibios/IC_TEENSY_4_1/board/board.mk
new file mode 100644
index 0000000000..bc242ac3c5
--- /dev/null
+++ b/platforms/chibios/IC_TEENSY_4_1/board/board.mk
@@ -0,0 +1 @@
+include $(CHIBIOS_CONTRIB)/os/hal/boards/PJRC_TEENSY_4_1/board.mk
diff --git a/platforms/chibios/IC_TEENSY_4_1/rules.mk b/platforms/chibios/IC_TEENSY_4_1/rules.mk
new file mode 100644
index 0000000000..0c62d209c5
--- /dev/null
+++ b/platforms/chibios/IC_TEENSY_4_1/rules.mk
@@ -0,0 +1 @@
+TEENSY_LOADER_CLI_MCU = imxrt1062
diff --git a/quantum/crc.c b/quantum/crc.c
new file mode 100644
index 0000000000..0d8b9d6017
--- /dev/null
+++ b/quantum/crc.c
@@ -0,0 +1,59 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "crc.h"
+
+__attribute__((weak)) void crc_init(void){
+ /* Software implementation nothing todo here. */
+};
+
+#if defined(CRC8_USE_TABLE)
+/**
+ * Static table used for the table_driven implementation.
+ */
+static const crc_t crc_table[256] = {0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d, 0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65, 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, 0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd, 0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd, 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea, 0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a, 0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a, 0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a,
+ 0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4, 0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4, 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44, 0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34, 0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63, 0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, 0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83, 0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3};
+
+__attribute__((weak)) uint8_t crc8(const void *data, size_t data_len) {
+ const uint8_t *d = (const uint8_t *)data;
+ crc_t crc = 0xff;
+ size_t tbl_idx;
+
+ while (data_len--) {
+ tbl_idx = crc ^ *d;
+ crc = crc_table[tbl_idx] & 0xff;
+ d++;
+ }
+ return crc & 0xff;
+}
+#else
+__attribute__((weak)) uint8_t crc8(const void *data, size_t data_len) {
+ const uint8_t *d = (const uint8_t *)data;
+ crc_t crc = 0xff;
+ size_t i, j;
+
+ for (i = 0; i < data_len; i++) {
+ crc ^= d[i];
+ for (j = 0; j < 8; j++) {
+ if ((crc & 0x80) != 0)
+ crc = (crc_t)((crc << 1) ^ 0x31);
+ else
+ crc <<= 1;
+ }
+ }
+ return crc;
+}
+#endif \ No newline at end of file
diff --git a/quantum/crc.h b/quantum/crc.h
new file mode 100644
index 0000000000..c17f5888e2
--- /dev/null
+++ b/quantum/crc.h
@@ -0,0 +1,44 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "quantum.h"
+
+/**
+ * The type of the CRC values.
+ *
+ * This type must be big enough to contain at least 8 bits.
+ */
+#if defined(CRC8_OPTIMIZE_SPEED)
+typedef uint_fast8_t crc_t;
+#else
+typedef uint_least8_t crc_t;
+#endif
+
+/**
+ * Initialize crc subsystem.
+ */
+__attribute__((weak)) void crc_init(void);
+
+/**
+ * Generate CRC8 value from given data.
+ *
+ * \param[in] data Pointer to a buffer of \a data_len bytes.
+ * \param[in] data_len Number of bytes in the \a data buffer.
+ * \return The calculated crc value.
+ */
+__attribute__((weak)) uint8_t crc8(const void *data, size_t data_len); \ No newline at end of file
diff --git a/quantum/debounce.h b/quantum/debounce.h
index 9ca05c6824..5043868289 100644
--- a/quantum/debounce.h
+++ b/quantum/debounce.h
@@ -9,3 +9,5 @@ void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
bool debounce_active(void);
void debounce_init(uint8_t num_rows);
+
+void debounce_free(void);
diff --git a/quantum/debounce/asym_eager_defer_pk.c b/quantum/debounce/asym_eager_defer_pk.c
new file mode 100644
index 0000000000..24380dc5e5
--- /dev/null
+++ b/quantum/debounce/asym_eager_defer_pk.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2017 Alex Ong <the.onga@gmail.com>
+ * Copyright 2020 Andrei Purdea <andrei@purdea.ro>
+ * Copyright 2021 Simon Arlott
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+Basic symmetric per-key algorithm. Uses an 8-bit counter per key.
+When no state changes have occured for DEBOUNCE milliseconds, we push the state.
+*/
+
+#include "matrix.h"
+#include "timer.h"
+#include "quantum.h"
+#include <stdlib.h>
+
+#ifdef PROTOCOL_CHIBIOS
+# if CH_CFG_USE_MEMCORE == FALSE
+# error ChibiOS is configured without a memory allocator. Your keyboard may have set `#define CH_CFG_USE_MEMCORE FALSE`, which is incompatible with this debounce algorithm.
+# endif
+#endif
+
+#ifndef DEBOUNCE
+# define DEBOUNCE 5
+#endif
+
+// Maximum debounce: 127ms
+#if DEBOUNCE > 127
+# undef DEBOUNCE
+# define DEBOUNCE 127
+#endif
+
+#define ROW_SHIFTER ((matrix_row_t)1)
+
+typedef struct {
+ bool pressed : 1;
+ uint8_t time : 7;
+} debounce_counter_t;
+
+#if DEBOUNCE > 0
+static debounce_counter_t *debounce_counters;
+static fast_timer_t last_time;
+static bool counters_need_update;
+static bool matrix_need_update;
+
+#define DEBOUNCE_ELAPSED 0
+
+static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time);
+static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
+
+// we use num_rows rather than MATRIX_ROWS to support split keyboards
+void debounce_init(uint8_t num_rows) {
+ debounce_counters = malloc(num_rows * MATRIX_COLS * sizeof(debounce_counter_t));
+ int i = 0;
+ for (uint8_t r = 0; r < num_rows; r++) {
+ for (uint8_t c = 0; c < MATRIX_COLS; c++) {
+ debounce_counters[i++].time = DEBOUNCE_ELAPSED;
+ }
+ }
+}
+
+void debounce_free(void) {
+ free(debounce_counters);
+ debounce_counters = NULL;
+}
+
+void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
+ bool updated_last = false;
+
+ if (counters_need_update) {
+ fast_timer_t now = timer_read_fast();
+ fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time);
+
+ last_time = now;
+ updated_last = true;
+ if (elapsed_time > UINT8_MAX) {
+ elapsed_time = UINT8_MAX;
+ }
+
+ if (elapsed_time > 0) {
+ update_debounce_counters_and_transfer_if_expired(raw, cooked, num_rows, elapsed_time);
+ }
+ }
+
+ if (changed || matrix_need_update) {
+ if (!updated_last) {
+ last_time = timer_read_fast();
+ }
+
+ transfer_matrix_values(raw, cooked, num_rows);
+ }
+}
+
+static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time) {
+ debounce_counter_t *debounce_pointer = debounce_counters;
+
+ counters_need_update = false;
+ matrix_need_update = false;
+
+ for (uint8_t row = 0; row < num_rows; row++) {
+ for (uint8_t col = 0; col < MATRIX_COLS; col++) {
+ matrix_row_t col_mask = (ROW_SHIFTER << col);
+
+ if (debounce_pointer->time != DEBOUNCE_ELAPSED) {
+ if (debounce_pointer->time <= elapsed_time) {
+ debounce_pointer->time = DEBOUNCE_ELAPSED;
+
+ if (debounce_pointer->pressed) {
+ // key-down: eager
+ matrix_need_update = true;
+ } else {
+ // key-up: defer
+ cooked[row] = (cooked[row] & ~col_mask) | (raw[row] & col_mask);
+ }
+ } else {
+ debounce_pointer->time -= elapsed_time;
+ counters_need_update = true;
+ }
+ }
+ debounce_pointer++;
+ }
+ }
+}
+
+static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) {
+ debounce_counter_t *debounce_pointer = debounce_counters;
+
+ for (uint8_t row = 0; row < num_rows; row++) {
+ matrix_row_t delta = raw[row] ^ cooked[row];
+ for (uint8_t col = 0; col < MATRIX_COLS; col++) {
+ matrix_row_t col_mask = (ROW_SHIFTER << col);
+
+ if (delta & col_mask) {
+ if (debounce_pointer->time == DEBOUNCE_ELAPSED) {
+ debounce_pointer->pressed = (raw[row] & col_mask);
+ debounce_pointer->time = DEBOUNCE;
+ counters_need_update = true;
+
+ if (debounce_pointer->pressed) {
+ // key-down: eager
+ cooked[row] ^= col_mask;
+ }
+ }
+ } else if (debounce_pointer->time != DEBOUNCE_ELAPSED) {
+ if (!debounce_pointer->pressed) {
+ // key-up: defer
+ debounce_pointer->time = DEBOUNCE_ELAPSED;
+ }
+ }
+ debounce_pointer++;
+ }
+ }
+}
+
+bool debounce_active(void) { return true; }
+#else
+# include "none.c"
+#endif
diff --git a/quantum/debounce/none.c b/quantum/debounce/none.c
new file mode 100644
index 0000000000..b03892bc5b
--- /dev/null
+++ b/quantum/debounce/none.c
@@ -0,0 +1,31 @@
+/* Copyright 2021 Simon Arlott
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "matrix.h"
+#include "quantum.h"
+#include <stdlib.h>
+
+void debounce_init(uint8_t num_rows) {}
+
+void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
+ for (int i = 0; i < num_rows; i++) {
+ cooked[i] = raw[i];
+ }
+}
+
+bool debounce_active(void) { return false; }
+
+void debounce_free(void) {}
diff --git a/quantum/debounce/sym_defer_g.c b/quantum/debounce/sym_defer_g.c
index 3ed9055d2a..fbefd55ede 100644
--- a/quantum/debounce/sym_defer_g.c
+++ b/quantum/debounce/sym_defer_g.c
@@ -1,5 +1,6 @@
/*
Copyright 2017 Alex Ong<the.onga@gmail.com>
+Copyright 2021 Simon Arlott
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
@@ -23,30 +24,29 @@ When no state changes have occured for DEBOUNCE milliseconds, we push the state.
# define DEBOUNCE 5
#endif
-void debounce_init(uint8_t num_rows) {}
+#if DEBOUNCE > 0
static bool debouncing = false;
+static fast_timer_t debouncing_time;
-#if DEBOUNCE > 0
-static uint16_t debouncing_time;
-void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
+void debounce_init(uint8_t num_rows) {}
+
+void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
if (changed) {
debouncing = true;
- debouncing_time = timer_read();
+ debouncing_time = timer_read_fast();
}
- if (debouncing && timer_elapsed(debouncing_time) > DEBOUNCE) {
+ if (debouncing && timer_elapsed_fast(debouncing_time) >= DEBOUNCE) {
for (int i = 0; i < num_rows; i++) {
cooked[i] = raw[i];
}
debouncing = false;
}
}
-#else // no debouncing.
-void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
- for (int i = 0; i < num_rows; i++) {
- cooked[i] = raw[i];
- }
-}
-#endif
bool debounce_active(void) { return debouncing; }
+
+void debounce_free(void) {}
+#else // no debouncing.
+# include "none.c"
+#endif
diff --git a/quantum/debounce/sym_defer_pk.c b/quantum/debounce/sym_defer_pk.c
index 60513f98e1..626a9be841 100644
--- a/quantum/debounce/sym_defer_pk.c
+++ b/quantum/debounce/sym_defer_pk.c
@@ -1,6 +1,7 @@
/*
Copyright 2017 Alex Ong<the.onga@gmail.com>
Copyright 2020 Andrei Purdea<andrei@purdea.ro>
+Copyright 2021 Simon Arlott
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
@@ -33,28 +34,25 @@ When no state changes have occured for DEBOUNCE milliseconds, we push the state.
# define DEBOUNCE 5
#endif
+// Maximum debounce: 255ms
+#if DEBOUNCE > UINT8_MAX
+# undef DEBOUNCE
+# define DEBOUNCE UINT8_MAX
+#endif
+
#define ROW_SHIFTER ((matrix_row_t)1)
-#define debounce_counter_t uint8_t
+typedef uint8_t debounce_counter_t;
+#if DEBOUNCE > 0
static debounce_counter_t *debounce_counters;
+static fast_timer_t last_time;
static bool counters_need_update;
-#define DEBOUNCE_ELAPSED 251
-#define MAX_DEBOUNCE (DEBOUNCE_ELAPSED - 1)
-
-static uint8_t wrapping_timer_read(void) {
- static uint16_t time = 0;
- static uint8_t last_result = 0;
- uint16_t new_time = timer_read();
- uint16_t diff = new_time - time;
- time = new_time;
- last_result = (last_result + diff) % (MAX_DEBOUNCE + 1);
- return last_result;
-}
+#define DEBOUNCE_ELAPSED 0
-void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time);
-void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time);
+static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time);
+static void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
// we use num_rows rather than MATRIX_ROWS to support split keyboards
void debounce_init(uint8_t num_rows) {
@@ -67,27 +65,49 @@ void debounce_init(uint8_t num_rows) {
}
}
+void debounce_free(void) {
+ free(debounce_counters);
+ debounce_counters = NULL;
+}
+
void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
- uint8_t current_time = wrapping_timer_read();
+ bool updated_last = false;
+
if (counters_need_update) {
- update_debounce_counters_and_transfer_if_expired(raw, cooked, num_rows, current_time);
+ fast_timer_t now = timer_read_fast();
+ fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time);
+
+ last_time = now;
+ updated_last = true;
+ if (elapsed_time > UINT8_MAX) {
+ elapsed_time = UINT8_MAX;
+ }
+
+ if (elapsed_time > 0) {
+ update_debounce_counters_and_transfer_if_expired(raw, cooked, num_rows, elapsed_time);
+ }
}
if (changed) {
- start_debounce_counters(raw, cooked, num_rows, current_time);
+ if (!updated_last) {
+ last_time = timer_read_fast();
+ }
+
+ start_debounce_counters(raw, cooked, num_rows);
}
}
-void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time) {
+static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time) {
counters_need_update = false;
debounce_counter_t *debounce_pointer = debounce_counters;
for (uint8_t row = 0; row < num_rows; row++) {
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
if (*debounce_pointer != DEBOUNCE_ELAPSED) {
- if (TIMER_DIFF(current_time, *debounce_pointer, MAX_DEBOUNCE) >= DEBOUNCE) {
+ if (*debounce_pointer <= elapsed_time) {
*debounce_pointer = DEBOUNCE_ELAPSED;
cooked[row] = (cooked[row] & ~(ROW_SHIFTER << col)) | (raw[row] & (ROW_SHIFTER << col));
} else {
+ *debounce_pointer -= elapsed_time;
counters_need_update = true;
}
}
@@ -96,14 +116,14 @@ void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix
}
}
-void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time) {
+static void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) {
debounce_counter_t *debounce_pointer = debounce_counters;
for (uint8_t row = 0; row < num_rows; row++) {
matrix_row_t delta = raw[row] ^ cooked[row];
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
if (delta & (ROW_SHIFTER << col)) {
if (*debounce_pointer == DEBOUNCE_ELAPSED) {
- *debounce_pointer = current_time;
+ *debounce_pointer = DEBOUNCE;
counters_need_update = true;
}
} else {
@@ -115,3 +135,6 @@ void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[], uint8_t
}
bool debounce_active(void) { return true; }
+#else
+# include "none.c"
+#endif
diff --git a/quantum/debounce/sym_eager_pk.c b/quantum/debounce/sym_eager_pk.c
index e66cf92d79..15a3242e68 100644
--- a/quantum/debounce/sym_eager_pk.c
+++ b/quantum/debounce/sym_eager_pk.c
@@ -1,5 +1,6 @@
/*
Copyright 2017 Alex Ong<the.onga@gmail.com>
+Copyright 2021 Simon Arlott
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
@@ -33,29 +34,26 @@ No further inputs are accepted until DEBOUNCE milliseconds have occurred.
# define DEBOUNCE 5
#endif
+// Maximum debounce: 255ms
+#if DEBOUNCE > UINT8_MAX
+# undef DEBOUNCE
+# define DEBOUNCE UINT8_MAX
+#endif
+
#define ROW_SHIFTER ((matrix_row_t)1)
-#define debounce_counter_t uint8_t
+typedef uint8_t debounce_counter_t;
+#if DEBOUNCE > 0
static debounce_counter_t *debounce_counters;
+static fast_timer_t last_time;
static bool counters_need_update;
static bool matrix_need_update;
-#define DEBOUNCE_ELAPSED 251
-#define MAX_DEBOUNCE (DEBOUNCE_ELAPSED - 1)
-
-static uint8_t wrapping_timer_read(void) {
- static uint16_t time = 0;
- static uint8_t last_result = 0;
- uint16_t new_time = timer_read();
- uint16_t diff = new_time - time;
- time = new_time;
- last_result = (last_result + diff) % (MAX_DEBOUNCE + 1);
- return last_result;
-}
+#define DEBOUNCE_ELAPSED 0
-void update_debounce_counters(uint8_t num_rows, uint8_t current_time);
-void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time);
+static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time);
+static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
// we use num_rows rather than MATRIX_ROWS to support split keyboards
void debounce_init(uint8_t num_rows) {
@@ -68,27 +66,51 @@ void debounce_init(uint8_t num_rows) {
}
}
+void debounce_free(void) {
+ free(debounce_counters);
+ debounce_counters = NULL;
+}
+
void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
- uint8_t current_time = wrapping_timer_read();
+ bool updated_last = false;
+
if (counters_need_update) {
- update_debounce_counters(num_rows, current_time);
+ fast_timer_t now = timer_read_fast();
+ fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time);
+
+ last_time = now;
+ updated_last = true;
+ if (elapsed_time > UINT8_MAX) {
+ elapsed_time = UINT8_MAX;
+ }
+
+ if (elapsed_time > 0) {
+ update_debounce_counters(num_rows, elapsed_time);
+ }
}
if (changed || matrix_need_update) {
- transfer_matrix_values(raw, cooked, num_rows, current_time);
+ if (!updated_last) {
+ last_time = timer_read_fast();
+ }
+
+ transfer_matrix_values(raw, cooked, num_rows);
}
}
// If the current time is > debounce counter, set the counter to enable input.
-void update_debounce_counters(uint8_t num_rows, uint8_t current_time) {
+static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time) {
counters_need_update = false;
+ matrix_need_update = false;
debounce_counter_t *debounce_pointer = debounce_counters;
for (uint8_t row = 0; row < num_rows; row++) {
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
if (*debounce_pointer != DEBOUNCE_ELAPSED) {
- if (TIMER_DIFF(current_time, *debounce_pointer, MAX_DEBOUNCE) >= DEBOUNCE) {
+ if (*debounce_pointer <= elapsed_time) {
*debounce_pointer = DEBOUNCE_ELAPSED;
+ matrix_need_update = true;
} else {
+ *debounce_pointer -= elapsed_time;
counters_need_update = true;
}
}
@@ -98,8 +120,7 @@ void update_debounce_counters(uint8_t num_rows, uint8_t current_time) {
}
// upload from raw_matrix to final matrix;
-void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time) {
- matrix_need_update = false;
+static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) {
debounce_counter_t *debounce_pointer = debounce_counters;
for (uint8_t row = 0; row < num_rows; row++) {
matrix_row_t delta = raw[row] ^ cooked[row];
@@ -108,11 +129,9 @@ void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t n
matrix_row_t col_mask = (ROW_SHIFTER << col);
if (delta & col_mask) {
if (*debounce_pointer == DEBOUNCE_ELAPSED) {
- *debounce_pointer = current_time;
+ *debounce_pointer = DEBOUNCE;
counters_need_update = true;
existing_row ^= col_mask; // flip the bit.
- } else {
- matrix_need_update = true;
}
}
debounce_pointer++;
@@ -122,3 +141,6 @@ void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t n
}
bool debounce_active(void) { return true; }
+#else
+# include "none.c"
+#endif
diff --git a/quantum/debounce/sym_eager_pr.c b/quantum/debounce/sym_eager_pr.c
index 20ccb46f1d..2ad592c5a6 100644
--- a/quantum/debounce/sym_eager_pr.c
+++ b/quantum/debounce/sym_eager_pr.c
@@ -1,5 +1,6 @@
/*
Copyright 2019 Alex Ong<the.onga@gmail.com>
+Copyright 2021 Simon Arlott
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
@@ -33,27 +34,25 @@ No further inputs are accepted until DEBOUNCE milliseconds have occurred.
# define DEBOUNCE 5
#endif
-#define debounce_counter_t uint8_t
+// Maximum debounce: 255ms
+#if DEBOUNCE > UINT8_MAX
+# undef DEBOUNCE
+# define DEBOUNCE UINT8_MAX
+#endif
+
+typedef uint8_t debounce_counter_t;
+
+#if DEBOUNCE > 0
static bool matrix_need_update;
static debounce_counter_t *debounce_counters;
+static fast_timer_t last_time;
static bool counters_need_update;
-#define DEBOUNCE_ELAPSED 251
-#define MAX_DEBOUNCE (DEBOUNCE_ELAPSED - 1)
-
-static uint8_t wrapping_timer_read(void) {
- static uint16_t time = 0;
- static uint8_t last_result = 0;
- uint16_t new_time = timer_read();
- uint16_t diff = new_time - time;
- time = new_time;
- last_result = (last_result + diff) % (MAX_DEBOUNCE + 1);
- return last_result;
-}
+#define DEBOUNCE_ELAPSED 0
-void update_debounce_counters(uint8_t num_rows, uint8_t current_time);
-void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time);
+static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time);
+static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
// we use num_rows rather than MATRIX_ROWS to support split keyboards
void debounce_init(uint8_t num_rows) {
@@ -63,27 +62,50 @@ void debounce_init(uint8_t num_rows) {
}
}
+void debounce_free(void) {
+ free(debounce_counters);
+ debounce_counters = NULL;
+}
+
void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
- uint8_t current_time = wrapping_timer_read();
- bool needed_update = counters_need_update;
+ bool updated_last = false;
+
if (counters_need_update) {
- update_debounce_counters(num_rows, current_time);
+ fast_timer_t now = timer_read_fast();
+ fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time);
+
+ last_time = now;
+ updated_last = true;
+ if (elapsed_time > UINT8_MAX) {
+ elapsed_time = UINT8_MAX;
+ }
+
+ if (elapsed_time > 0) {
+ update_debounce_counters(num_rows, elapsed_time);
+ }
}
- if (changed || (needed_update && !counters_need_update) || matrix_need_update) {
- transfer_matrix_values(raw, cooked, num_rows, current_time);
+ if (changed || matrix_need_update) {
+ if (!updated_last) {
+ last_time = timer_read_fast();
+ }
+
+ transfer_matrix_values(raw, cooked, num_rows);
}
}
// If the current time is > debounce counter, set the counter to enable input.
-void update_debounce_counters(uint8_t num_rows, uint8_t current_time) {
+static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time) {
counters_need_update = false;
+ matrix_need_update = false;
debounce_counter_t *debounce_pointer = debounce_counters;
for (uint8_t row = 0; row < num_rows; row++) {
if (*debounce_pointer != DEBOUNCE_ELAPSED) {
- if (TIMER_DIFF(current_time, *debounce_pointer, MAX_DEBOUNCE) >= DEBOUNCE) {
+ if (*debounce_pointer <= elapsed_time) {
*debounce_pointer = DEBOUNCE_ELAPSED;
+ matrix_need_update = true;
} else {
+ *debounce_pointer -= elapsed_time;
counters_need_update = true;
}
}
@@ -92,8 +114,7 @@ void update_debounce_counters(uint8_t num_rows, uint8_t current_time) {
}
// upload from raw_matrix to final matrix;
-void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time) {
- matrix_need_update = false;
+static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) {
debounce_counter_t *debounce_pointer = debounce_counters;
for (uint8_t row = 0; row < num_rows; row++) {
matrix_row_t existing_row = cooked[row];
@@ -102,11 +123,9 @@ void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t n
// determine new value basd on debounce pointer + raw value
if (existing_row != raw_row) {
if (*debounce_pointer == DEBOUNCE_ELAPSED) {
- *debounce_pointer = current_time;
+ *debounce_pointer = DEBOUNCE;
cooked[row] = raw_row;
counters_need_update = true;
- } else {
- matrix_need_update = true;
}
}
debounce_pointer++;
@@ -114,3 +133,6 @@ void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t n
}
bool debounce_active(void) { return true; }
+#else
+# include "none.c"
+#endif
diff --git a/quantum/debounce/tests/asym_eager_defer_pk_tests.cpp b/quantum/debounce/tests/asym_eager_defer_pk_tests.cpp
new file mode 100644
index 0000000000..fe374c3dfa
--- /dev/null
+++ b/quantum/debounce/tests/asym_eager_defer_pk_tests.cpp
@@ -0,0 +1,374 @@
+/* Copyright 2021 Simon Arlott
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gtest/gtest.h"
+
+#include "debounce_test_common.h"
+
+TEST_F(DebounceTest, OneKeyShort1) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ /* Release key after 1ms delay */
+ {1, {{0, 1, UP}}, {}},
+
+ /*
+ * Until the eager timer on DOWN is observed to finish, the defer timer
+ * on UP can't start. There's no workaround for this because it's not
+ * possible to debounce an event that isn't being tracked.
+ *
+ * sym_defer_pk has the same problem but the test has to track that the
+ * key changed state so the DOWN timer is always allowed to finish
+ * before starting the UP timer.
+ */
+ {5, {}, {}},
+
+ {10, {}, {{0, 1, UP}}}, /* 5ms+5ms after DOWN at time 0 */
+ /* Press key again after 1ms delay */
+ {11, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort2) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ /* Release key after 2ms delay */
+ {2, {{0, 1, UP}}, {}},
+
+ {5, {}, {}}, /* See OneKeyShort1 */
+
+ {10, {}, {{0, 1, UP}}}, /* 5ms+5ms after DOWN at time 0 */
+ /* Press key again after 1ms delay */
+ {11, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort3) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ /* Release key after 3ms delay */
+ {3, {{0, 1, UP}}, {}},
+
+ {5, {}, {}}, /* See OneKeyShort1 */
+
+ {10, {}, {{0, 1, UP}}}, /* 5ms+5ms after DOWN at time 0 */
+ /* Press key again after 1ms delay */
+ {11, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort4) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ /* Release key after 4ms delay */
+ {4, {{0, 1, UP}}, {}},
+
+ {5, {}, {}}, /* See OneKeyShort1 */
+
+ {10, {}, {{0, 1, UP}}}, /* 5ms+5ms after DOWN at time 0 */
+ /* Press key again after 1ms delay */
+ {11, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort5) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Release key after 5ms delay */
+ {5, {{0, 1, UP}}, {}},
+
+ {10, {}, {{0, 1, UP}}}, /* 5ms+5ms after DOWN at time 0 */
+ /* Press key again after 1ms delay */
+ {11, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort6) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Release key after 6ms delay */
+ {6, {{0, 1, UP}}, {}},
+
+ {11, {}, {{0, 1, UP}}}, /* 5ms after UP at time 6 */
+ /* Press key again after 1ms delay */
+ {12, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort7) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Release key after 7ms delay */
+ {7, {{0, 1, UP}}, {}},
+
+ {12, {}, {{0, 1, UP}}}, /* 5ms after UP at time 7 */
+ /* Press key again after 1ms delay */
+ {13, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort8) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ /* Release key after 1ms delay */
+ {1, {{0, 1, UP}}, {}},
+
+ {5, {}, {}}, /* See OneKeyShort1 */
+
+ {10, {}, {{0, 1, UP}}}, /* 5ms after UP at time 7 */
+ /* Press key again after 0ms delay (scan 2) */
+ {10, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort9) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ /* Release key after 1ms delay */
+ {1, {{0, 1, UP}}, {}},
+
+ {5, {}, {}}, /* See OneKeyShort1 */
+
+ /* Press key again after 0ms delay (same scan) before debounce finishes */
+ {10, {{0, 1, DOWN}}, {}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyBouncing1) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ {1, {{0, 1, UP}}, {}},
+ {2, {{0, 1, DOWN}}, {}},
+ {3, {{0, 1, UP}}, {}},
+ {4, {{0, 1, DOWN}}, {}},
+ {5, {{0, 1, UP}}, {}},
+ {6, {{0, 1, DOWN}}, {}},
+ {7, {{0, 1, UP}}, {}},
+ {8, {{0, 1, DOWN}}, {}},
+ {9, {{0, 1, UP}}, {}},
+ {10, {{0, 1, DOWN}}, {}},
+ {11, {{0, 1, UP}}, {}},
+ {12, {{0, 1, DOWN}}, {}},
+ {13, {{0, 1, UP}}, {}},
+ {14, {{0, 1, DOWN}}, {}},
+ {15, {{0, 1, UP}}, {}},
+
+ {20, {}, {{0, 1, UP}}},
+ /* Press key again after 1ms delay */
+ {21, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyBouncing2) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ /* Change twice in the same time period */
+ {1, {{0, 1, UP}}, {}},
+ {1, {{0, 1, DOWN}}, {}},
+ /* Change three times in the same time period */
+ {2, {{0, 1, UP}}, {}},
+ {2, {{0, 1, DOWN}}, {}},
+ {2, {{0, 1, UP}}, {}},
+ /* Change twice in the same time period */
+ {6, {{0, 1, DOWN}}, {}},
+ {6, {{0, 1, UP}}, {}},
+ /* Change three times in the same time period */
+ {7, {{0, 1, DOWN}}, {}},
+ {7, {{0, 1, UP}}, {}},
+ {7, {{0, 1, DOWN}}, {}},
+ /* Change twice in the same time period */
+ {8, {{0, 1, UP}}, {}},
+ {8, {{0, 1, DOWN}}, {}},
+ /* Change three times in the same time period */
+ {9, {{0, 1, UP}}, {}},
+ {9, {{0, 1, DOWN}}, {}},
+ {9, {{0, 1, UP}}, {}},
+
+ {14, {}, {{0, 1, UP}}},
+ /* Press key again after 1ms delay */
+ {15, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyLong) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ {25, {{0, 1, UP}}, {}},
+
+ {30, {}, {{0, 1, UP}}},
+
+ {50, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ {75, {{0, 1, UP}}, {}},
+
+ {80, {}, {{0, 1, UP}}},
+
+ {100, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, TwoKeysShort) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ {1, {{0, 2, DOWN}}, {{0, 2, DOWN}}},
+ /* Release key after 2ms delay */
+ {2, {{0, 1, UP}}, {}},
+ {3, {{0, 2, UP}}, {}},
+
+ {5, {}, {}}, /* See OneKeyShort1 */
+ {6, {}, {}}, /* See OneKeyShort1 */
+
+ {10, {}, {{0, 1, UP}}}, /* 5ms+5ms after DOWN at time 0 */
+ /* Press key again after 1ms delay */
+ {11, {{0, 1, DOWN}}, {{0, 1, DOWN}, {0, 2, UP}}}, /* 5ms+5ms after DOWN at time 0 */
+ {12, {{0, 2, DOWN}}, {{0, 2, DOWN}}}, /* 5ms+5ms after DOWN at time 0 */
+ });
+ runEvents();
+}
+
+
+TEST_F(DebounceTest, OneKeyDelayedScan1) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Processing is very late, immediately release key */
+ {300, {{0, 1, UP}}, {}},
+
+ {305, {}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan2) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Processing is very late, immediately release key */
+ {300, {{0, 1, UP}}, {}},
+
+ /* Processing is very late again */
+ {600, {}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan3) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Processing is very late */
+ {300, {}, {}},
+ /* Release key after 1ms */
+ {301, {{0, 1, UP}}, {}},
+
+ {306, {}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan4) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Processing is very late */
+ {300, {}, {}},
+ /* Release key after 1ms */
+ {301, {{0, 1, UP}}, {}},
+
+ /* Processing is very late again */
+ {600, {}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan5) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ {5, {{0, 1, UP}}, {}},
+
+ /* Processing is very late */
+ {300, {}, {{0, 1, UP}}},
+ /* Immediately press key again */
+ {300, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan6) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ {5, {{0, 1, UP}}, {}},
+
+ /* Processing is very late */
+ {300, {}, {{0, 1, UP}}},
+
+ /* Press key again after 1ms */
+ {301, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan7) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ {5, {{0, 1, UP}}, {}},
+
+ /* Press key again before debounce expires */
+ {300, {{0, 1, DOWN}}, {}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan8) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Processing is a bit late */
+ {50, {}, {}},
+ /* Release key after 1ms */
+ {51, {{0, 1, UP}}, {}},
+
+ /* Processing is a bit late again */
+ {100, {}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
diff --git a/quantum/debounce/tests/debounce_test_common.cpp b/quantum/debounce/tests/debounce_test_common.cpp
new file mode 100644
index 0000000000..1c5e7c9f4e
--- /dev/null
+++ b/quantum/debounce/tests/debounce_test_common.cpp
@@ -0,0 +1,229 @@
+/* Copyright 2021 Simon Arlott
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gtest/gtest.h"
+
+#include "debounce_test_common.h"
+
+#include <algorithm>
+#include <iomanip>
+#include <sstream>
+
+extern "C" {
+#include "quantum.h"
+#include "timer.h"
+#include "debounce.h"
+
+void set_time(uint32_t t);
+void advance_time(uint32_t ms);
+}
+
+void DebounceTest::addEvents(std::initializer_list<DebounceTestEvent> events) {
+ events_.insert(events_.end(), events.begin(), events.end());
+}
+
+void DebounceTest::runEvents() {
+ /* Run the test multiple times, from 1kHz to 10kHz scan rate */
+ for (extra_iterations_ = 0; extra_iterations_ < 10; extra_iterations_++) {
+ if (time_jumps_) {
+ /* Don't advance time smoothly, jump to the next event (some tests require this) */
+ auto_advance_time_ = false;
+ runEventsInternal();
+ } else {
+ /* Run the test with both smooth and irregular time; it must produce the same result */
+ auto_advance_time_ = true;
+ runEventsInternal();
+ auto_advance_time_ = false;
+ runEventsInternal();
+ }
+ }
+}
+
+void DebounceTest::runEventsInternal() {
+ fast_timer_t previous = 0;
+ bool first = true;
+
+ /* Initialise keyboard with start time (offset to avoid testing at 0) and all keys UP */
+ debounce_init(MATRIX_ROWS);
+ set_time(time_offset_);
+ std::fill(std::begin(input_matrix_), std::end(input_matrix_), 0);
+ std::fill(std::begin(output_matrix_), std::end(output_matrix_), 0);
+
+ for (auto &event : events_) {
+ if (!auto_advance_time_) {
+ /* Jump to the next event */
+ set_time(time_offset_ + event.time_);
+ } else if (!first && event.time_ == previous + 1) {
+ /* This event immediately follows the previous one, don't make extra debounce() calls */
+ advance_time(1);
+ } else {
+ /* Fast forward to the time for this event, calling debounce() with no changes */
+ ASSERT_LT((time_offset_ + event.time_) - timer_read_fast(), 60000) << "Test tries to advance more than 1 minute of time";
+
+ while (timer_read_fast() != time_offset_ + event.time_) {
+ runDebounce(false);
+ checkCookedMatrix(false, "debounce() modified cooked matrix");
+ advance_time(1);
+ }
+ }
+
+ first = false;
+ previous = event.time_;
+
+ /* Prepare input matrix */
+ for (auto &input : event.inputs_) {
+ matrixUpdate(input_matrix_, "input", input);
+ }
+
+ /* Call debounce */
+ runDebounce(!event.inputs_.empty());
+
+ /* Prepare output matrix */
+ for (auto &output : event.outputs_) {
+ matrixUpdate(output_matrix_, "output", output);
+ }
+
+ /* Check output matrix has expected change events */
+ for (auto &output : event.outputs_) {
+ EXPECT_EQ(!!(cooked_matrix_[output.row_] & (1U << output.col_)), directionValue(output.direction_))
+ << "Missing event at " << strTime()
+ << " expected key " << output.row_ << "," << output.col_ << " " << directionLabel(output.direction_)
+ << "\ninput_matrix: changed=" << !event.inputs_.empty() << "\n" << strMatrix(input_matrix_)
+ << "\nexpected_matrix:\n" << strMatrix(output_matrix_)
+ << "\nactual_matrix:\n" << strMatrix(cooked_matrix_);
+ }
+
+ /* Check output matrix has no other changes */
+ checkCookedMatrix(!event.inputs_.empty(), "debounce() cooked matrix does not match expected output matrix");
+
+ /* Perform some extra iterations of the matrix scan with no changes */
+ for (int i = 0; i < extra_iterations_; i++) {
+ runDebounce(false);
+ checkCookedMatrix(false, "debounce() modified cooked matrix");
+ }
+ }
+
+ /* Check that no further changes happen for 1 minute */
+ for (int i = 0; i < 60000; i++) {
+ runDebounce(false);
+ checkCookedMatrix(false, "debounce() modified cooked matrix");
+ advance_time(1);
+ }
+
+ debounce_free();
+}
+
+void DebounceTest::runDebounce(bool changed) {
+ std::copy(std::begin(input_matrix_), std::end(input_matrix_), std::begin(raw_matrix_));
+ std::copy(std::begin(output_matrix_), std::end(output_matrix_), std::begin(cooked_matrix_));
+
+ debounce(raw_matrix_, cooked_matrix_, MATRIX_ROWS, changed);
+
+ if (!std::equal(std::begin(input_matrix_), std::end(input_matrix_), std::begin(raw_matrix_))) {
+ FAIL() << "Fatal error: debounce() modified raw matrix at " << strTime()
+ << "\ninput_matrix: changed=" << changed << "\n" << strMatrix(input_matrix_)
+ << "\nraw_matrix:\n" << strMatrix(raw_matrix_);
+ }
+}
+
+void DebounceTest::checkCookedMatrix(bool changed, const std::string &error_message) {
+ if (!std::equal(std::begin(output_matrix_), std::end(output_matrix_), std::begin(cooked_matrix_))) {
+ FAIL() << "Unexpected event: " << error_message << " at " << strTime()
+ << "\ninput_matrix: changed=" << changed << "\n" << strMatrix(input_matrix_)
+ << "\nexpected_matrix:\n" << strMatrix(output_matrix_)
+ << "\nactual_matrix:\n" << strMatrix(cooked_matrix_);
+ }
+}
+
+std::string DebounceTest::strTime() {
+ std::stringstream text;
+
+ text << "time " << (timer_read_fast() - time_offset_)
+ << " (extra_iterations=" << extra_iterations_
+ << ", auto_advance_time=" << auto_advance_time_ << ")";
+
+ return text.str();
+}
+
+std::string DebounceTest::strMatrix(matrix_row_t matrix[]) {
+ std::stringstream text;
+
+ text << "\t" << std::setw(3) << "";
+ for (int col = 0; col < MATRIX_COLS; col++) {
+ text << " " << std::setw(2) << col;
+ }
+ text << "\n";
+
+ for (int row = 0; row < MATRIX_ROWS; row++) {
+ text << "\t" << std::setw(2) << row << ":";
+ for (int col = 0; col < MATRIX_COLS; col++) {
+ text << ((matrix[row] & (1U << col)) ? " XX" : " __");
+ }
+
+ text << "\n";
+ }
+
+ return text.str();
+}
+
+bool DebounceTest::directionValue(Direction direction) {
+ switch (direction) {
+ case DOWN:
+ return true;
+
+ case UP:
+ return false;
+ }
+}
+
+std::string DebounceTest::directionLabel(Direction direction) {
+ switch (direction) {
+ case DOWN:
+ return "DOWN";
+
+ case UP:
+ return "UP";
+ }
+}
+
+/* Modify a matrix and verify that events always specify a change */
+void DebounceTest::matrixUpdate(matrix_row_t matrix[], const std::string &name, const MatrixTestEvent &event) {
+ ASSERT_NE(!!(matrix[event.row_] & (1U << event.col_)), directionValue(event.direction_))
+ << "Test " << name << " at " << strTime()
+ << " sets key " << event.row_ << "," << event.col_ << " " << directionLabel(event.direction_)
+ << " but it is already " << directionLabel(event.direction_)
+ << "\n" << name << "_matrix:\n" << strMatrix(matrix);
+
+ switch (event.direction_) {
+ case DOWN:
+ matrix[event.row_] |= (1U << event.col_);
+ break;
+
+ case UP:
+ matrix[event.row_] &= ~(1U << event.col_);
+ break;
+ }
+}
+
+DebounceTestEvent::DebounceTestEvent(fast_timer_t time,
+ std::initializer_list<MatrixTestEvent> inputs,
+ std::initializer_list<MatrixTestEvent> outputs)
+ : time_(time), inputs_(inputs), outputs_(outputs) {
+}
+
+MatrixTestEvent::MatrixTestEvent(int row, int col, Direction direction)
+ : row_(row), col_(col), direction_(direction) {
+}
diff --git a/quantum/debounce/tests/debounce_test_common.h b/quantum/debounce/tests/debounce_test_common.h
new file mode 100644
index 0000000000..d87e310594
--- /dev/null
+++ b/quantum/debounce/tests/debounce_test_common.h
@@ -0,0 +1,83 @@
+/* Copyright 2021 Simon Arlott
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gtest/gtest.h"
+
+#include <initializer_list>
+#include <list>
+#include <string>
+
+extern "C" {
+#include "quantum.h"
+#include "timer.h"
+}
+
+enum Direction {
+ DOWN,
+ UP,
+};
+
+class MatrixTestEvent {
+public:
+ MatrixTestEvent(int row, int col, Direction direction);
+
+ const int row_;
+ const int col_;
+ const Direction direction_;
+};
+
+class DebounceTestEvent {
+public:
+ // 0, {{0, 1, DOWN}}, {{0, 1, DOWN}})
+ DebounceTestEvent(fast_timer_t time,
+ std::initializer_list<MatrixTestEvent> inputs,
+ std::initializer_list<MatrixTestEvent> outputs);
+
+ const fast_timer_t time_;
+ const std::list<MatrixTestEvent> inputs_;
+ const std::list<MatrixTestEvent> outputs_;
+};
+
+class DebounceTest : public ::testing::Test {
+protected:
+ void addEvents(std::initializer_list<DebounceTestEvent> events);
+ void runEvents();
+
+ fast_timer_t time_offset_ = 7777;
+ bool time_jumps_ = false;
+
+private:
+ static bool directionValue(Direction direction);
+ static std::string directionLabel(Direction direction);
+
+ void runEventsInternal();
+ void runDebounce(bool changed);
+ void checkCookedMatrix(bool changed, const std::string &error_message);
+ void matrixUpdate(matrix_row_t matrix[], const std::string &name, const MatrixTestEvent &event);
+
+ std::string strTime();
+ std::string strMatrix(matrix_row_t matrix[]);
+
+ std::list<DebounceTestEvent> events_;
+
+ matrix_row_t input_matrix_[MATRIX_ROWS];
+ matrix_row_t raw_matrix_[MATRIX_ROWS];
+ matrix_row_t cooked_matrix_[MATRIX_ROWS];
+ matrix_row_t output_matrix_[MATRIX_ROWS];
+
+ int extra_iterations_;
+ bool auto_advance_time_;
+};
diff --git a/quantum/debounce/tests/rules.mk b/quantum/debounce/tests/rules.mk
new file mode 100644
index 0000000000..66928d7eb6
--- /dev/null
+++ b/quantum/debounce/tests/rules.mk
@@ -0,0 +1,44 @@
+# Copyright 2021 Simon Arlott
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+DEBOUNCE_COMMON_DEFS := -DMATRIX_ROWS=4 -DMATRIX_COLS=10 -DDEBOUNCE=5
+
+DEBOUNCE_COMMON_SRC := $(QUANTUM_PATH)/debounce/tests/debounce_test_common.cpp \
+ $(TMK_PATH)/common/test/timer.c
+
+debounce_sym_defer_g_DEFS := $(DEBOUNCE_COMMON_DEFS)
+debounce_sym_defer_g_SRC := $(DEBOUNCE_COMMON_SRC) \
+ $(QUANTUM_PATH)/debounce/sym_defer_g.c \
+ $(QUANTUM_PATH)/debounce/tests/sym_defer_g_tests.cpp
+
+debounce_sym_defer_pk_DEFS := $(DEBOUNCE_COMMON_DEFS)
+debounce_sym_defer_pk_SRC := $(DEBOUNCE_COMMON_SRC) \
+ $(QUANTUM_PATH)/debounce/sym_defer_pk.c \
+ $(QUANTUM_PATH)/debounce/tests/sym_defer_pk_tests.cpp
+
+debounce_sym_eager_pk_DEFS := $(DEBOUNCE_COMMON_DEFS)
+debounce_sym_eager_pk_SRC := $(DEBOUNCE_COMMON_SRC) \
+ $(QUANTUM_PATH)/debounce/sym_eager_pk.c \
+ $(QUANTUM_PATH)/debounce/tests/sym_eager_pk_tests.cpp
+
+debounce_sym_eager_pr_DEFS := $(DEBOUNCE_COMMON_DEFS)
+debounce_sym_eager_pr_SRC := $(DEBOUNCE_COMMON_SRC) \
+ $(QUANTUM_PATH)/debounce/sym_eager_pr.c \
+ $(QUANTUM_PATH)/debounce/tests/sym_eager_pr_tests.cpp
+
+debounce_asym_eager_defer_pk_DEFS := $(DEBOUNCE_COMMON_DEFS)
+debounce_asym_eager_defer_pk_SRC := $(DEBOUNCE_COMMON_SRC) \
+ $(QUANTUM_PATH)/debounce/asym_eager_defer_pk.c \
+ $(QUANTUM_PATH)/debounce/tests/asym_eager_defer_pk_tests.cpp
diff --git a/quantum/debounce/tests/sym_defer_g_tests.cpp b/quantum/debounce/tests/sym_defer_g_tests.cpp
new file mode 100644
index 0000000000..a56aecd8f3
--- /dev/null
+++ b/quantum/debounce/tests/sym_defer_g_tests.cpp
@@ -0,0 +1,223 @@
+/* Copyright 2021 Simon Arlott
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gtest/gtest.h"
+
+#include "debounce_test_common.h"
+
+TEST_F(DebounceTest, OneKeyShort1) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+
+ {5, {}, {{0, 1, DOWN}}},
+ /* 0ms delay (fast scan rate) */
+ {5, {{0, 1, UP}}, {}},
+
+ {10, {}, {{0, 1, UP}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort2) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+
+ {5, {}, {{0, 1, DOWN}}},
+ /* 1ms delay */
+ {6, {{0, 1, UP}}, {}},
+
+ {11, {}, {{0, 1, UP}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort3) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+
+ {5, {}, {{0, 1, DOWN}}},
+ /* 2ms delay */
+ {7, {{0, 1, UP}}, {}},
+
+ {12, {}, {{0, 1, UP}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyTooQuick1) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+ /* Release key exactly on the debounce time */
+ {5, {{0, 1, UP}}, {}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyTooQuick2) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+
+ {5, {}, {{0, 1, DOWN}}},
+ {6, {{0, 1, UP}}, {}},
+
+ /* Press key exactly on the debounce time */
+ {11, {{0, 1, DOWN}}, {}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyBouncing1) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+ {1, {{0, 1, UP}}, {}},
+ {2, {{0, 1, DOWN}}, {}},
+ {3, {{0, 1, UP}}, {}},
+ {4, {{0, 1, DOWN}}, {}},
+ {5, {{0, 1, UP}}, {}},
+ {6, {{0, 1, DOWN}}, {}},
+ {11, {}, {{0, 1, DOWN}}}, /* 5ms after DOWN at time 7 */
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyBouncing2) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+ {5, {}, {{0, 1, DOWN}}},
+ {6, {{0, 1, UP}}, {}},
+ {7, {{0, 1, DOWN}}, {}},
+ {8, {{0, 1, UP}}, {}},
+ {9, {{0, 1, DOWN}}, {}},
+ {10, {{0, 1, UP}}, {}},
+ {15, {}, {{0, 1, UP}}}, /* 5ms after UP at time 10 */
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyLong) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+
+ {5, {}, {{0, 1, DOWN}}},
+
+ {25, {{0, 1, UP}}, {}},
+
+ {30, {}, {{0, 1, UP}}},
+
+ {50, {{0, 1, DOWN}}, {}},
+
+ {55, {}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, TwoKeysShort) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+ {1, {{0, 2, DOWN}}, {}},
+
+ {6, {}, {{0, 1, DOWN}, {0, 2, DOWN}}},
+
+ {7, {{0, 1, UP}}, {}},
+ {8, {{0, 2, UP}}, {}},
+
+ {13, {}, {{0, 1, UP}, {0, 2, UP}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, TwoKeysSimultaneous1) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}, {0, 2, DOWN}}, {}},
+
+ {5, {}, {{0, 1, DOWN}, {0, 2, DOWN}}},
+ {6, {{0, 1, UP}, {0, 2, UP}}, {}},
+
+ {11, {}, {{0, 1, UP}, {0, 2, UP}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, TwoKeysSimultaneous2) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+ {1, {{0, 2, DOWN}}, {}},
+
+ {5, {}, {}},
+ {6, {}, {{0, 1, DOWN}, {0, 2, DOWN}}},
+ {7, {{0, 1, UP}}, {}},
+ {8, {{0, 2, UP}}, {}},
+
+ {13, {}, {{0, 1, UP}, {0, 2, UP}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan1) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+
+ /* Processing is very late */
+ {300, {}, {{0, 1, DOWN}}},
+ /* Immediately release key */
+ {300, {{0, 1, UP}}, {}},
+
+ {305, {}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan2) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+
+ /* Processing is very late */
+ {300, {}, {{0, 1, DOWN}}},
+ /* Release key after 1ms */
+ {301, {{0, 1, UP}}, {}},
+
+ {306, {}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan3) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+
+ /* Release key before debounce expires */
+ {300, {{0, 1, UP}}, {}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan4) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+
+ /* Processing is a bit late */
+ {50, {}, {{0, 1, DOWN}}},
+ /* Release key after 1ms */
+ {51, {{0, 1, UP}}, {}},
+
+ {56, {}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
diff --git a/quantum/debounce/tests/sym_defer_pk_tests.cpp b/quantum/debounce/tests/sym_defer_pk_tests.cpp
new file mode 100644
index 0000000000..1f3061e59c
--- /dev/null
+++ b/quantum/debounce/tests/sym_defer_pk_tests.cpp
@@ -0,0 +1,225 @@
+/* Copyright 2021 Simon Arlott
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gtest/gtest.h"
+
+#include "debounce_test_common.h"
+
+TEST_F(DebounceTest, OneKeyShort1) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+
+ {5, {}, {{0, 1, DOWN}}},
+ /* 0ms delay (fast scan rate) */
+ {5, {{0, 1, UP}}, {}},
+
+ {10, {}, {{0, 1, UP}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort2) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+
+ {5, {}, {{0, 1, DOWN}}},
+ /* 1ms delay */
+ {6, {{0, 1, UP}}, {}},
+
+ {11, {}, {{0, 1, UP}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort3) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+
+ {5, {}, {{0, 1, DOWN}}},
+ /* 2ms delay */
+ {7, {{0, 1, UP}}, {}},
+
+ {12, {}, {{0, 1, UP}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyTooQuick1) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+ /* Release key exactly on the debounce time */
+ {5, {{0, 1, UP}}, {}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyTooQuick2) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+
+ {5, {}, {{0, 1, DOWN}}},
+ {6, {{0, 1, UP}}, {}},
+
+ /* Press key exactly on the debounce time */
+ {11, {{0, 1, DOWN}}, {}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyBouncing1) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+ {1, {{0, 1, UP}}, {}},
+ {2, {{0, 1, DOWN}}, {}},
+ {3, {{0, 1, UP}}, {}},
+ {4, {{0, 1, DOWN}}, {}},
+ {5, {{0, 1, UP}}, {}},
+ {6, {{0, 1, DOWN}}, {}},
+ {11, {}, {{0, 1, DOWN}}}, /* 5ms after DOWN at time 7 */
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyBouncing2) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+ {5, {}, {{0, 1, DOWN}}},
+ {6, {{0, 1, UP}}, {}},
+ {7, {{0, 1, DOWN}}, {}},
+ {8, {{0, 1, UP}}, {}},
+ {9, {{0, 1, DOWN}}, {}},
+ {10, {{0, 1, UP}}, {}},
+ {15, {}, {{0, 1, UP}}}, /* 5ms after UP at time 10 */
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyLong) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+
+ {5, {}, {{0, 1, DOWN}}},
+
+ {25, {{0, 1, UP}}, {}},
+
+ {30, {}, {{0, 1, UP}}},
+
+ {50, {{0, 1, DOWN}}, {}},
+
+ {55, {}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, TwoKeysShort) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+ {1, {{0, 2, DOWN}}, {}},
+
+ {5, {}, {{0, 1, DOWN}}},
+ {6, {}, {{0, 2, DOWN}}},
+
+ {7, {{0, 1, UP}}, {}},
+ {8, {{0, 2, UP}}, {}},
+
+ {12, {}, {{0, 1, UP}}},
+ {13, {}, {{0, 2, UP}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, TwoKeysSimultaneous1) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}, {0, 2, DOWN}}, {}},
+
+ {5, {}, {{0, 1, DOWN}, {0, 2, DOWN}}},
+ {6, {{0, 1, UP}, {0, 2, UP}}, {}},
+
+ {11, {}, {{0, 1, UP}, {0, 2, UP}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, TwoKeysSimultaneous2) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+ {1, {{0, 2, DOWN}}, {}},
+
+ {5, {}, {{0, 1, DOWN}}},
+ {6, {{0, 1, UP}}, {{0, 2, DOWN}}},
+ {7, {{0, 2, UP}}, {}},
+
+ {11, {}, {{0, 1, UP}}},
+ {12, {}, {{0, 2, UP}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan1) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+
+ /* Processing is very late */
+ {300, {}, {{0, 1, DOWN}}},
+ /* Immediately release key */
+ {300, {{0, 1, UP}}, {}},
+
+ {305, {}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan2) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+
+ /* Processing is very late */
+ {300, {}, {{0, 1, DOWN}}},
+ /* Release key after 1ms */
+ {301, {{0, 1, UP}}, {}},
+
+ {306, {}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan3) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+
+ /* Release key before debounce expires */
+ {300, {{0, 1, UP}}, {}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan4) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {}},
+
+ /* Processing is a bit late */
+ {50, {}, {{0, 1, DOWN}}},
+ /* Release key after 1ms */
+ {51, {{0, 1, UP}}, {}},
+
+ {56, {}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
diff --git a/quantum/debounce/tests/sym_eager_pk_tests.cpp b/quantum/debounce/tests/sym_eager_pk_tests.cpp
new file mode 100644
index 0000000000..e0fc205e33
--- /dev/null
+++ b/quantum/debounce/tests/sym_eager_pk_tests.cpp
@@ -0,0 +1,237 @@
+/* Copyright 2021 Simon Arlott
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gtest/gtest.h"
+
+#include "debounce_test_common.h"
+
+TEST_F(DebounceTest, OneKeyShort1) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ {1, {{0, 1, UP}}, {}},
+
+ {5, {}, {{0, 1, UP}}},
+ /* Press key again after 1ms delay (debounce has not yet finished) */
+ {6, {{0, 1, DOWN}}, {}},
+ {10, {}, {{0, 1, DOWN}}}, /* 5ms after UP at time 5 */
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort2) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ {1, {{0, 1, UP}}, {}},
+
+ {5, {}, {{0, 1, UP}}},
+ /* Press key again after 2ms delay (debounce has not yet finished) */
+ {7, {{0, 1, DOWN}}, {}},
+ {10, {}, {{0, 1, DOWN}}}, /* 5ms after UP at time 5 */
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort3) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ {1, {{0, 1, UP}}, {}},
+
+ {5, {}, {{0, 1, UP}}},
+ /* Press key again after 3ms delay (debounce has not yet finished) */
+ {8, {{0, 1, DOWN}}, {}},
+ {10, {}, {{0, 1, DOWN}}}, /* 5ms after UP at time 5 */
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort4) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ {1, {{0, 1, UP}}, {}},
+
+ {5, {}, {{0, 1, UP}}},
+ /* Press key again after 4ms delay (debounce has not yet finished) */
+ {9, {{0, 1, DOWN}}, {}},
+ {10, {}, {{0, 1, DOWN}}}, /* 5ms after UP at time 5 */
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort5) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ {1, {{0, 1, UP}}, {}},
+
+ {5, {}, {{0, 1, UP}}},
+ /* Press key again after 5ms delay (debounce has finished) */
+ {10, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort6) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ {1, {{0, 1, UP}}, {}},
+
+ {5, {}, {{0, 1, UP}}},
+ /* Press key after after 6ms delay (debounce has finished) */
+ {11, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyBouncing1) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ {1, {{0, 1, UP}}, {}},
+ {2, {{0, 1, DOWN}}, {}},
+ {3, {{0, 1, UP}}, {}},
+ {4, {{0, 1, DOWN}}, {}},
+ {5, {{0, 1, UP}}, {{0, 1, UP}}},
+ /* Press key again after 1ms delay (debounce has not yet finished) */
+ {6, {{0, 1, DOWN}}, {}},
+ {10, {}, {{0, 1, DOWN}}}, /* 5ms after UP at time 5 */
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyBouncing2) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ /* Change twice in the same time period */
+ {1, {{0, 1, UP}}, {}},
+ {1, {{0, 1, DOWN}}, {}},
+ /* Change three times in the same time period */
+ {2, {{0, 1, UP}}, {}},
+ {2, {{0, 1, DOWN}}, {}},
+ {2, {{0, 1, UP}}, {}},
+ /* Change three times in the same time period */
+ {3, {{0, 1, DOWN}}, {}},
+ {3, {{0, 1, UP}}, {}},
+ {3, {{0, 1, DOWN}}, {}},
+ /* Change twice in the same time period */
+ {4, {{0, 1, UP}}, {}},
+ {4, {{0, 1, DOWN}}, {}},
+ {5, {{0, 1, UP}}, {{0, 1, UP}}},
+ /* Press key again after 1ms delay (debounce has not yet finished) */
+ {6, {{0, 1, DOWN}}, {}},
+ {10, {}, {{0, 1, DOWN}}}, /* 5ms after UP at time 5 */
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyLong) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ {25, {{0, 1, UP}}, {{0, 1, UP}}},
+
+ {50, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, TwoKeysShort) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ {1, {{0, 1, UP}}, {}},
+ {2, {{0, 2, DOWN}}, {{0, 2, DOWN}}},
+ {3, {{0, 2, UP}}, {}},
+
+ {5, {}, {{0, 1, UP}}},
+ /* Press key again after 1ms delay (debounce has not yet finished) */
+ {6, {{0, 1, DOWN}}, {}},
+ {7, {}, {{0, 2, UP}}},
+
+ /* Press key again after 1ms delay (debounce has not yet finished) */
+ {9, {{0, 2, DOWN}}, {}},
+ {10, {}, {{0, 1, DOWN}}}, /* 5ms after UP at time 5 */
+
+ {12, {}, {{0, 2, DOWN}}}, /* 5ms after UP at time 7 */
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan1) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Processing is very late but the change will now be accepted */
+ {300, {{0, 1, UP}}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan2) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Processing is very late but the change will now be accepted even with a 1 scan delay */
+ {300, {}, {}},
+ {300, {{0, 1, UP}}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan3) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Processing is very late but the change will now be accepted even with a 1ms delay */
+ {300, {}, {}},
+ {301, {{0, 1, UP}}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan4) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Processing is a bit late but the change will now be accepted */
+ {50, {{0, 1, UP}}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan5) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Processing is very late but the change will now be accepted even with a 1 scan delay */
+ {50, {}, {}},
+ {50, {{0, 1, UP}}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan6) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Processing is very late but the change will now be accepted even with a 1ms delay */
+ {50, {}, {}},
+ {51, {{0, 1, UP}}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
diff --git a/quantum/debounce/tests/sym_eager_pr_tests.cpp b/quantum/debounce/tests/sym_eager_pr_tests.cpp
new file mode 100644
index 0000000000..2c4bca127e
--- /dev/null
+++ b/quantum/debounce/tests/sym_eager_pr_tests.cpp
@@ -0,0 +1,280 @@
+/* Copyright 2021 Simon Arlott
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gtest/gtest.h"
+
+#include "debounce_test_common.h"
+
+TEST_F(DebounceTest, OneKeyShort1) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ {1, {{0, 1, UP}}, {}},
+
+ {5, {}, {{0, 1, UP}}},
+ /* Press key again after 1ms delay (debounce has not yet finished) */
+ {6, {{0, 1, DOWN}}, {}},
+ {10, {}, {{0, 1, DOWN}}}, /* 5ms after UP at time 5 */
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort2) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ {1, {{0, 1, UP}}, {}},
+
+ {5, {}, {{0, 1, UP}}},
+ /* Press key again after 2ms delay (debounce has not yet finished) */
+ {7, {{0, 1, DOWN}}, {}},
+ {10, {}, {{0, 1, DOWN}}}, /* 5ms after UP at time 5 */
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort3) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ {1, {{0, 1, UP}}, {}},
+
+ {5, {}, {{0, 1, UP}}},
+ /* Press key again after 3ms delay (debounce has not yet finished) */
+ {8, {{0, 1, DOWN}}, {}},
+ {10, {}, {{0, 1, DOWN}}}, /* 5ms after UP at time 5 */
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort4) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ {1, {{0, 1, UP}}, {}},
+
+ {5, {}, {{0, 1, UP}}},
+ /* Press key again after 4ms delay (debounce has not yet finished) */
+ {9, {{0, 1, DOWN}}, {}},
+ {10, {}, {{0, 1, DOWN}}}, /* 5ms after UP at time 5 */
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort5) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ {1, {{0, 1, UP}}, {}},
+
+ {5, {}, {{0, 1, UP}}},
+ /* Press key again after 5ms delay (debounce has finished) */
+ {10, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort6) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ {1, {{0, 1, UP}}, {}},
+
+ {5, {}, {{0, 1, UP}}},
+ /* Press key after after 6ms delay (debounce has finished) */
+ {11, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyBouncing1) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ {1, {{0, 1, UP}}, {}},
+ {2, {{0, 1, DOWN}}, {}},
+ {3, {{0, 1, UP}}, {}},
+ {4, {{0, 1, DOWN}}, {}},
+ {5, {{0, 1, UP}}, {{0, 1, UP}}},
+ /* Press key again after 1ms delay (debounce has not yet finished) */
+ {6, {{0, 1, DOWN}}, {}},
+ {10, {}, {{0, 1, DOWN}}}, /* 5ms after UP at time 5 */
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyBouncing2) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ /* Change twice in the same time period */
+ {1, {{0, 1, UP}}, {}},
+ {1, {{0, 1, DOWN}}, {}},
+ /* Change three times in the same time period */
+ {2, {{0, 1, UP}}, {}},
+ {2, {{0, 1, DOWN}}, {}},
+ {2, {{0, 1, UP}}, {}},
+ /* Change three times in the same time period */
+ {3, {{0, 1, DOWN}}, {}},
+ {3, {{0, 1, UP}}, {}},
+ {3, {{0, 1, DOWN}}, {}},
+ /* Change twice in the same time period */
+ {4, {{0, 1, UP}}, {}},
+ {4, {{0, 1, DOWN}}, {}},
+ {5, {{0, 1, UP}}, {{0, 1, UP}}},
+ /* Press key again after 1ms delay (debounce has not yet finished) */
+ {6, {{0, 1, DOWN}}, {}},
+ {10, {}, {{0, 1, DOWN}}}, /* 5ms after UP at time 5 */
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyLong) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ {25, {{0, 1, UP}}, {{0, 1, UP}}},
+
+ {50, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, TwoRowsShort) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ {1, {{0, 1, UP}}, {}},
+ {2, {{2, 0, DOWN}}, {{2, 0, DOWN}}},
+ {3, {{2, 0, UP}}, {}},
+
+ {5, {}, {{0, 1, UP}}},
+ /* Press key again after 1ms delay (debounce has not yet finished) */
+ {6, {{0, 1, DOWN}}, {}},
+ {7, {}, {{2, 0, UP}}},
+
+ /* Press key again after 1ms delay (debounce has not yet finished) */
+ {9, {{2, 0, DOWN}}, {}},
+ {10, {}, {{0, 1, DOWN}}}, /* 5ms after UP at time 5 */
+
+ {12, {}, {{2, 0, DOWN}}}, /* 5ms after UP at time 7 */
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, TwoKeysOverlap) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ {1, {{0, 1, UP}}, {}},
+ /* Press a second key during the first debounce */
+ {2, {{0, 2, DOWN}}, {}},
+
+ /* Key registers as soon as debounce finishes, 5ms after time 0 */
+ {5, {}, {{0, 1, UP}, {0, 2, DOWN}}},
+ {6, {{0, 1, DOWN}}, {}},
+
+ /* Key registers as soon as debounce finishes, 5ms after time 5 */
+ {10, {}, {{0, 1, DOWN}}},
+ /* Release both keys */
+ {11, {{0, 1, UP}}, {}},
+ {12, {{0, 2, UP}}, {}},
+
+ /* Keys register as soon as debounce finishes, 5ms after time 10 */
+ {15, {}, {{0, 1, UP}, {0, 2, UP}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, TwoKeysSimultaneous1) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}, {0, 2, DOWN}}, {{0, 1, DOWN}, {0, 2, DOWN}}},
+ {20, {{0, 1, UP}}, {{0, 1, UP}}},
+ {21, {{0, 2, UP}}, {}},
+
+ /* Key registers as soon as debounce finishes, 5ms after time 20 */
+ {25, {}, {{0, 2, UP}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, TwoKeysSimultaneous2) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}, {0, 2, DOWN}}, {{0, 1, DOWN}, {0, 2, DOWN}}},
+ {20, {{0, 1, UP}, {0, 2, UP}}, {{0, 1, UP}, {0, 2, UP}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan1) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Processing is very late but the change will now be accepted */
+ {300, {{0, 1, UP}}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan2) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Processing is very late but the change will now be accepted even with a 1 scan delay */
+ {300, {}, {}},
+ {300, {{0, 1, UP}}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan3) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Processing is very late but the change will now be accepted even with a 1ms delay */
+ {300, {}, {}},
+ {301, {{0, 1, UP}}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan4) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Processing is a bit late but the change will now be accepted */
+ {50, {{0, 1, UP}}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan5) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Processing is very late but the change will now be accepted even with a 1 scan delay */
+ {50, {}, {}},
+ {50, {{0, 1, UP}}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyDelayedScan6) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Processing is very late but the change will now be accepted even with a 1ms delay */
+ {50, {}, {}},
+ {51, {{0, 1, UP}}, {{0, 1, UP}}},
+ });
+ time_jumps_ = true;
+ runEvents();
+}
diff --git a/quantum/debounce/tests/testlist.mk b/quantum/debounce/tests/testlist.mk
new file mode 100644
index 0000000000..c54c45aa63
--- /dev/null
+++ b/quantum/debounce/tests/testlist.mk
@@ -0,0 +1,6 @@
+TEST_LIST += \
+ debounce_sym_defer_g \
+ debounce_sym_defer_pk \
+ debounce_sym_eager_pk \
+ debounce_sym_eager_pr \
+ debounce_asym_eager_defer_pk
diff --git a/quantum/led_matrix.c b/quantum/led_matrix.c
index 7e0fdf896a..e7e933e1dd 100644
--- a/quantum/led_matrix.c
+++ b/quantum/led_matrix.c
@@ -33,6 +33,14 @@ const led_point_t k_led_matrix_center = {112, 32};
const led_point_t k_led_matrix_center = LED_MATRIX_CENTER;
#endif
+// clang-format off
+#ifndef LED_MATRIX_IMMEDIATE_EEPROM
+# define led_eeconfig_update(v) led_update_eeprom |= v
+#else
+# define led_eeconfig_update(v) if (v) eeconfig_update_led_matrix()
+#endif
+// clang-format on
+
// Generic effect runners
#include "led_matrix_runners/effect_runner_dx_dy_dist.h"
#include "led_matrix_runners/effect_runner_dx_dy.h"
@@ -67,10 +75,6 @@ const led_point_t k_led_matrix_center = LED_MATRIX_CENTER;
# define LED_DISABLE_TIMEOUT 0
#endif
-#if LED_DISABLE_WHEN_USB_SUSPENDED != 1
-# undef LED_DISABLE_WHEN_USB_SUSPENDED
-#endif
-
#if !defined(LED_MATRIX_MAXIMUM_BRIGHTNESS) || LED_MATRIX_MAXIMUM_BRIGHTNESS > UINT8_MAX
# undef LED_MATRIX_MAXIMUM_BRIGHTNESS
# define LED_MATRIX_MAXIMUM_BRIGHTNESS UINT8_MAX
@@ -108,6 +112,7 @@ last_hit_t g_last_hit_tracker;
// internals
static bool suspend_state = false;
+static bool led_update_eeprom = false;
static uint8_t led_last_enable = UINT8_MAX;
static uint8_t led_last_effect = UINT8_MAX;
static effect_params_t led_effect_params = {0, LED_FLAG_ALL, false};
@@ -280,6 +285,7 @@ static void led_task_timers(void) {
static void led_task_sync(void) {
// next task
+ if (led_update_eeprom) eeconfig_update_led_matrix();
if (sync_timer_elapsed32(g_led_timer) >= LED_MATRIX_LED_FLUSH_LIMIT) led_task_state = STARTING;
}
@@ -469,9 +475,7 @@ bool led_matrix_get_suspend_state(void) { return suspend_state; }
void led_matrix_toggle_eeprom_helper(bool write_to_eeprom) {
led_matrix_eeconfig.enable ^= 1;
led_task_state = STARTING;
- if (write_to_eeprom) {
- eeconfig_update_led_matrix();
- }
+ led_eeconfig_update(write_to_eeprom);
dprintf("led matrix toggle [%s]: led_matrix_eeconfig.enable = %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.enable);
}
void led_matrix_toggle_noeeprom(void) { led_matrix_toggle_eeprom_helper(false); }
@@ -479,7 +483,7 @@ void led_matrix_toggle(void) { led_matrix_toggle_eeprom_helper(true); }
void led_matrix_enable(void) {
led_matrix_enable_noeeprom();
- eeconfig_update_led_matrix();
+ led_eeconfig_update(true);
}
void led_matrix_enable_noeeprom(void) {
@@ -489,7 +493,7 @@ void led_matrix_enable_noeeprom(void) {
void led_matrix_disable(void) {
led_matrix_disable_noeeprom();
- eeconfig_update_led_matrix();
+ led_eeconfig_update(true);
}
void led_matrix_disable_noeeprom(void) {
@@ -511,9 +515,7 @@ void led_matrix_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom) {
led_matrix_eeconfig.mode = mode;
}
led_task_state = STARTING;
- if (write_to_eeprom) {
- eeconfig_update_led_matrix();
- }
+ led_eeconfig_update(write_to_eeprom);
dprintf("led matrix mode [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.mode);
}
void led_matrix_mode_noeeprom(uint8_t mode) { led_matrix_mode_eeprom_helper(mode, false); }
@@ -540,9 +542,7 @@ void led_matrix_set_val_eeprom_helper(uint8_t val, bool write_to_eeprom) {
return;
}
led_matrix_eeconfig.val = (val > LED_MATRIX_MAXIMUM_BRIGHTNESS) ? LED_MATRIX_MAXIMUM_BRIGHTNESS : val;
- if (write_to_eeprom) {
- eeconfig_update_led_matrix();
- }
+ led_eeconfig_update(write_to_eeprom);
dprintf("led matrix set val [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.val);
}
void led_matrix_set_val_noeeprom(uint8_t val) { led_matrix_set_val_eeprom_helper(val, false); }
@@ -560,9 +560,7 @@ void led_matrix_decrease_val(void) { led_matrix_decrease_val_helper(true); }
void led_matrix_set_speed_eeprom_helper(uint8_t speed, bool write_to_eeprom) {
led_matrix_eeconfig.speed = speed;
- if (write_to_eeprom) {
- eeconfig_update_led_matrix();
- }
+ led_eeconfig_update(write_to_eeprom);
dprintf("led matrix set speed [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.speed);
}
void led_matrix_set_speed_noeeprom(uint8_t speed) { led_matrix_set_speed_eeprom_helper(speed, false); }
diff --git a/quantum/matrix.c b/quantum/matrix.c
index 34d6af2e6d..71ef270892 100644
--- a/quantum/matrix.c
+++ b/quantum/matrix.c
@@ -16,6 +16,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <stdbool.h>
+#include <string.h>
#include "util.h"
#include "matrix.h"
#include "debounce.h"
@@ -24,14 +25,23 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef DIRECT_PINS
static pin_t direct_pins[MATRIX_ROWS][MATRIX_COLS] = DIRECT_PINS;
#elif (DIODE_DIRECTION == ROW2COL) || (DIODE_DIRECTION == COL2ROW)
+# ifdef MATRIX_ROW_PINS
static const pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
+# endif // MATRIX_ROW_PINS
+# ifdef MATRIX_COL_PINS
static const pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
+# endif // MATRIX_COL_PINS
#endif
/* matrix state(1:on, 0:off) */
extern matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values
extern matrix_row_t matrix[MATRIX_ROWS]; // debounced values
+// user-defined overridable functions
+__attribute__((weak)) void matrix_init_pins(void);
+__attribute__((weak)) void matrix_read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row);
+__attribute__((weak)) void matrix_read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col);
+
static inline void setPinOutput_writeLow(pin_t pin) {
ATOMIC_BLOCK_FORCEON {
setPinOutput(pin);
@@ -47,7 +57,7 @@ static inline void setPinInputHigh_atomic(pin_t pin) {
#ifdef DIRECT_PINS
-static void init_pins(void) {
+__attribute__((weak)) void matrix_init_pins(void) {
for (int row = 0; row < MATRIX_ROWS; row++) {
for (int col = 0; col < MATRIX_COLS; col++) {
pin_t pin = direct_pins[row][col];
@@ -58,7 +68,7 @@ static void init_pins(void) {
}
}
-static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
+__attribute__((weak)) void matrix_read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
// Start with a clear matrix row
matrix_row_t current_row_value = 0;
@@ -69,16 +79,13 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
}
}
- // If the row has changed, store the row and return the changed flag.
- if (current_matrix[current_row] != current_row_value) {
- current_matrix[current_row] = current_row_value;
- return true;
- }
- return false;
+ // Update the matrix
+ current_matrix[current_row] = current_row_value;
}
#elif defined(DIODE_DIRECTION)
-# if (DIODE_DIRECTION == COL2ROW)
+# if defined(MATRIX_ROW_PINS) && defined(MATRIX_COL_PINS)
+# if (DIODE_DIRECTION == COL2ROW)
static void select_row(uint8_t row) { setPinOutput_writeLow(row_pins[row]); }
@@ -90,14 +97,14 @@ static void unselect_rows(void) {
}
}
-static void init_pins(void) {
+__attribute__((weak)) void matrix_init_pins(void) {
unselect_rows();
for (uint8_t x = 0; x < MATRIX_COLS; x++) {
setPinInputHigh_atomic(col_pins[x]);
}
}
-static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
+__attribute__((weak)) void matrix_read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
// Start with a clear matrix row
matrix_row_t current_row_value = 0;
@@ -118,15 +125,11 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
unselect_row(current_row);
matrix_output_unselect_delay(); // wait for all Col signals to go HIGH
- // If the row has changed, store the row and return the changed flag.
- if (current_matrix[current_row] != current_row_value) {
- current_matrix[current_row] = current_row_value;
- return true;
- }
- return false;
+ // Update the matrix
+ current_matrix[current_row] = current_row_value;
}
-# elif (DIODE_DIRECTION == ROW2COL)
+# elif (DIODE_DIRECTION == ROW2COL)
static void select_col(uint8_t col) { setPinOutput_writeLow(col_pins[col]); }
@@ -138,59 +141,46 @@ static void unselect_cols(void) {
}
}
-static void init_pins(void) {
+__attribute__((weak)) void matrix_init_pins(void) {
unselect_cols();
for (uint8_t x = 0; x < MATRIX_ROWS; x++) {
setPinInputHigh_atomic(row_pins[x]);
}
}
-static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) {
- bool matrix_changed = false;
-
+__attribute__((weak)) void matrix_read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) {
// Select col
select_col(current_col);
matrix_output_select_delay();
// For each row...
for (uint8_t row_index = 0; row_index < MATRIX_ROWS; row_index++) {
- // Store last value of row prior to reading
- matrix_row_t last_row_value = current_matrix[row_index];
- matrix_row_t current_row_value = last_row_value;
-
// Check row pin state
if (readPin(row_pins[row_index]) == 0) {
// Pin LO, set col bit
- current_row_value |= (MATRIX_ROW_SHIFTER << current_col);
+ current_matrix[row_index] |= (MATRIX_ROW_SHIFTER << current_col);
} else {
// Pin HI, clear col bit
- current_row_value &= ~(MATRIX_ROW_SHIFTER << current_col);
- }
-
- // Determine if the matrix changed state
- if ((last_row_value != current_row_value)) {
- matrix_changed |= true;
- current_matrix[row_index] = current_row_value;
+ current_matrix[row_index] &= ~(MATRIX_ROW_SHIFTER << current_col);
}
}
// Unselect col
unselect_col(current_col);
matrix_output_unselect_delay(); // wait for all Row signals to go HIGH
-
- return matrix_changed;
}
-# else
-# error DIODE_DIRECTION must be one of COL2ROW or ROW2COL!
-# endif
+# else
+# error DIODE_DIRECTION must be one of COL2ROW or ROW2COL!
+# endif
+# endif // defined(MATRIX_ROW_PINS) && defined(MATRIX_COL_PINS)
#else
# error DIODE_DIRECTION is not defined!
#endif
void matrix_init(void) {
// initialize key pins
- init_pins();
+ matrix_init_pins();
// initialize matrix state: all keys off
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
@@ -204,20 +194,23 @@ void matrix_init(void) {
}
uint8_t matrix_scan(void) {
- bool changed = false;
+ matrix_row_t curr_matrix[MATRIX_ROWS] = {0};
#if defined(DIRECT_PINS) || (DIODE_DIRECTION == COL2ROW)
// Set row, read cols
for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
- changed |= read_cols_on_row(raw_matrix, current_row);
+ matrix_read_cols_on_row(curr_matrix, current_row);
}
#elif (DIODE_DIRECTION == ROW2COL)
// Set col, read rows
for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
- changed |= read_rows_on_col(raw_matrix, current_col);
+ matrix_read_rows_on_col(curr_matrix, current_col);
}
#endif
+ bool changed = memcmp(raw_matrix, curr_matrix, sizeof(curr_matrix)) != 0;
+ if (changed) memcpy(raw_matrix, curr_matrix, sizeof(curr_matrix));
+
debounce(raw_matrix, matrix, MATRIX_ROWS, changed);
matrix_scan_quantum();
diff --git a/quantum/quantum.h b/quantum/quantum.h
index e4a7c5723c..66ba96fde8 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -176,6 +176,10 @@ extern layer_state_t layer_state;
# include "oled_driver.h"
#endif
+#ifdef ST7565_ENABLE
+# include "st7565.h"
+#endif
+
#ifdef DIP_SWITCH_ENABLE
# include "dip_switch.h"
#endif
diff --git a/quantum/rgb_matrix.c b/quantum/rgb_matrix.c
index ab8dbd849b..3c5ddba939 100644
--- a/quantum/rgb_matrix.c
+++ b/quantum/rgb_matrix.c
@@ -31,6 +31,14 @@ const led_point_t k_rgb_matrix_center = {112, 32};
const led_point_t k_rgb_matrix_center = RGB_MATRIX_CENTER;
#endif
+// clang-format off
+#ifndef RGB_MATRIX_IMMEDIATE_EEPROM
+# define rgb_eeconfig_update(v) rgb_update_eeprom |= v
+#else
+# define rgb_eeconfig_update(v) if (v) eeconfig_update_rgb_matrix()
+#endif
+// clang-format on
+
__attribute__((weak)) RGB rgb_matrix_hsv_to_rgb(HSV hsv) { return hsv_to_rgb(hsv); }
// Generic effect runners
@@ -67,10 +75,6 @@ __attribute__((weak)) RGB rgb_matrix_hsv_to_rgb(HSV hsv) { return hsv_to_rgb(hsv
# define RGB_DISABLE_TIMEOUT 0
#endif
-#if RGB_DISABLE_WHEN_USB_SUSPENDED != 1
-# undef RGB_DISABLE_WHEN_USB_SUSPENDED
-#endif
-
#if !defined(RGB_MATRIX_MAXIMUM_BRIGHTNESS) || RGB_MATRIX_MAXIMUM_BRIGHTNESS > UINT8_MAX
# undef RGB_MATRIX_MAXIMUM_BRIGHTNESS
# define RGB_MATRIX_MAXIMUM_BRIGHTNESS UINT8_MAX
@@ -129,6 +133,7 @@ last_hit_t g_last_hit_tracker;
// internals
static bool suspend_state = false;
+static bool rgb_update_eeprom = false;
static uint8_t rgb_last_enable = UINT8_MAX;
static uint8_t rgb_last_effect = UINT8_MAX;
static effect_params_t rgb_effect_params = {0, LED_FLAG_ALL, false};
@@ -315,6 +320,7 @@ static void rgb_task_timers(void) {
static void rgb_task_sync(void) {
// next task
+ if (rgb_update_eeprom) eeconfig_update_rgb_matrix();
if (sync_timer_elapsed32(g_rgb_timer) >= RGB_MATRIX_LED_FLUSH_LIMIT) rgb_task_state = STARTING;
}
@@ -511,9 +517,7 @@ bool rgb_matrix_get_suspend_state(void) { return suspend_state; }
void rgb_matrix_toggle_eeprom_helper(bool write_to_eeprom) {
rgb_matrix_config.enable ^= 1;
rgb_task_state = STARTING;
- if (write_to_eeprom) {
- eeconfig_update_rgb_matrix();
- }
+ rgb_eeconfig_update(write_to_eeprom);
dprintf("rgb matrix toggle [%s]: rgb_matrix_config.enable = %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.enable);
}
void rgb_matrix_toggle_noeeprom(void) { rgb_matrix_toggle_eeprom_helper(false); }
@@ -521,7 +525,7 @@ void rgb_matrix_toggle(void) { rgb_matrix_toggle_eeprom_helper(true); }
void rgb_matrix_enable(void) {
rgb_matrix_enable_noeeprom();
- eeconfig_update_rgb_matrix();
+ rgb_eeconfig_update(true);
}
void rgb_matrix_enable_noeeprom(void) {
@@ -531,7 +535,7 @@ void rgb_matrix_enable_noeeprom(void) {
void rgb_matrix_disable(void) {
rgb_matrix_disable_noeeprom();
- eeconfig_update_rgb_matrix();
+ rgb_eeconfig_update(true);
}
void rgb_matrix_disable_noeeprom(void) {
@@ -553,9 +557,7 @@ void rgb_matrix_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom) {
rgb_matrix_config.mode = mode;
}
rgb_task_state = STARTING;
- if (write_to_eeprom) {
- eeconfig_update_rgb_matrix();
- }
+ rgb_eeconfig_update(write_to_eeprom);
dprintf("rgb matrix mode [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.mode);
}
void rgb_matrix_mode_noeeprom(uint8_t mode) { rgb_matrix_mode_eeprom_helper(mode, false); }
@@ -584,9 +586,7 @@ void rgb_matrix_sethsv_eeprom_helper(uint16_t hue, uint8_t sat, uint8_t val, boo
rgb_matrix_config.hsv.h = hue;
rgb_matrix_config.hsv.s = sat;
rgb_matrix_config.hsv.v = (val > RGB_MATRIX_MAXIMUM_BRIGHTNESS) ? RGB_MATRIX_MAXIMUM_BRIGHTNESS : val;
- if (write_to_eeprom) {
- eeconfig_update_rgb_matrix();
- }
+ rgb_eeconfig_update(write_to_eeprom);
dprintf("rgb matrix set hsv [%s]: %u,%u,%u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.hsv.h, rgb_matrix_config.hsv.s, rgb_matrix_config.hsv.v);
}
void rgb_matrix_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val) { rgb_matrix_sethsv_eeprom_helper(hue, sat, val, false); }
@@ -623,9 +623,7 @@ void rgb_matrix_decrease_val(void) { rgb_matrix_decrease_val_helper(true); }
void rgb_matrix_set_speed_eeprom_helper(uint8_t speed, bool write_to_eeprom) {
rgb_matrix_config.speed = speed;
- if (write_to_eeprom) {
- eeconfig_update_rgb_matrix();
- }
+ rgb_eeconfig_update(write_to_eeprom);
dprintf("rgb matrix set speed [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.speed);
}
void rgb_matrix_set_speed_noeeprom(uint8_t speed) { rgb_matrix_set_speed_eeprom_helper(speed, false); }
diff --git a/quantum/rgb_matrix.h b/quantum/rgb_matrix.h
index a615b8422c..741a2fe446 100644
--- a/quantum/rgb_matrix.h
+++ b/quantum/rgb_matrix.h
@@ -33,6 +33,8 @@
# include "is31fl3737.h"
#elif defined(IS31FL3741)
# include "is31fl3741.h"
+#elif defined(AW20216)
+# include "aw20216.h"
#elif defined(WS2812)
# include "ws2812.h"
#endif
diff --git a/quantum/rgb_matrix_animations/jellybean_raindrops_anim.h b/quantum/rgb_matrix_animations/jellybean_raindrops_anim.h
index 9493b38508..a17e954b1b 100644
--- a/quantum/rgb_matrix_animations/jellybean_raindrops_anim.h
+++ b/quantum/rgb_matrix_animations/jellybean_raindrops_anim.h
@@ -4,7 +4,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};
+ HSV hsv = {rand() & 0xFF, qadd8(rand() & 0x7F, 0x80), rgb_matrix_config.hsv.v};
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_drivers.c b/quantum/rgb_matrix_drivers.c
index 896fa6d0ef..6a11d4791e 100644
--- a/quantum/rgb_matrix_drivers.c
+++ b/quantum/rgb_matrix_drivers.c
@@ -171,6 +171,22 @@ const rgb_matrix_driver_t rgb_matrix_driver = {
};
# endif
+#elif defined(AW20216)
+# include "spi_master.h"
+static void init(void) {
+ spi_init();
+ AW20216_init();
+}
+
+static void flush(void) { AW20216_update_pwm_buffers(); }
+
+const rgb_matrix_driver_t rgb_matrix_driver = {
+ .init = init,
+ .flush = flush,
+ .set_color = AW20216_set_color,
+ .set_color_all = AW20216_set_color_all,
+};
+
#elif defined(WS2812)
# if defined(RGBLIGHT_ENABLE) && !defined(RGBLIGHT_CUSTOM_DRIVER)
# pragma message "Cannot use RGBLIGHT and RGB Matrix using WS2812 at the same time."
diff --git a/quantum/serial_link/system/serial_link.c b/quantum/serial_link/system/serial_link.c
index f77483ad8c..6363f8ff3b 100644
--- a/quantum/serial_link/system/serial_link.c
+++ b/quantum/serial_link/system/serial_link.c
@@ -29,10 +29,13 @@ SOFTWARE.
#include "serial_link/protocol/transport.h"
#include "serial_link/protocol/frame_router.h"
#include "matrix.h"
+#include "sync_timer.h"
#include <stdbool.h>
#include "print.h"
#include "config.h"
+#define SYNC_TIMER_OFFSET 2
+
static event_source_t new_data_event;
static bool serial_link_connected;
static bool is_master = false;
@@ -159,10 +162,16 @@ static matrix_object_t last_matrix = {};
SLAVE_TO_MASTER_OBJECT(keyboard_matrix, matrix_object_t);
MASTER_TO_ALL_SLAVES_OBJECT(serial_link_connected, bool);
+#ifndef DISABLE_SYNC_TIMER
+MASTER_TO_ALL_SLAVES_OBJECT(sync_timer, uint32_t);
+#endif
static remote_object_t* remote_objects[] = {
REMOTE_OBJECT(serial_link_connected),
REMOTE_OBJECT(keyboard_matrix),
+#ifndef DISABLE_SYNC_TIMER
+ REMOTE_OBJECT(sync_timer),
+#endif
};
void init_serial_link(void) {
@@ -200,14 +209,27 @@ void serial_link_update(void) {
m->rows[i] = matrix.rows[i];
}
end_write_keyboard_matrix();
+
*begin_write_serial_link_connected() = true;
end_write_serial_link_connected();
+
+#ifndef DISABLE_SYNC_TIMER
+ *begin_write_sync_timer() = sync_timer_read32() + SYNC_TIMER_OFFSET;
+ end_write_sync_timer();
+#endif
}
matrix_object_t* m = read_keyboard_matrix(0);
if (m) {
matrix_set_remote(m->rows, 0);
}
+
+#ifndef DISABLE_SYNC_TIMER
+ uint32_t* t = read_sync_timer();
+ if (t) {
+ sync_timer_update(*t);
+ }
+#endif
}
void signal_data_written(void) { chEvtBroadcast(&new_data_event); }
diff --git a/quantum/split_common/matrix.c b/quantum/split_common/matrix.c
index 039e7d9773..56d91b07fe 100644
--- a/quantum/split_common/matrix.c
+++ b/quantum/split_common/matrix.c
@@ -16,23 +16,30 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <stdbool.h>
+#include <string.h>
#include "util.h"
#include "matrix.h"
#include "debounce.h"
#include "quantum.h"
#include "split_util.h"
#include "config.h"
-#include "transport.h"
+#include "transactions.h"
-#define ERROR_DISCONNECT_COUNT 5
+#ifndef ERROR_DISCONNECT_COUNT
+# define ERROR_DISCONNECT_COUNT 5
+#endif // ERROR_DISCONNECT_COUNT
#define ROWS_PER_HAND (MATRIX_ROWS / 2)
#ifdef DIRECT_PINS
static pin_t direct_pins[MATRIX_ROWS][MATRIX_COLS] = DIRECT_PINS;
#elif (DIODE_DIRECTION == ROW2COL) || (DIODE_DIRECTION == COL2ROW)
+# ifdef MATRIX_ROW_PINS
static pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
+# endif // MATRIX_ROW_PINS
+# ifdef MATRIX_COL_PINS
static pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
+# endif // MATRIX_COL_PINS
#endif
/* matrix state(1:on, 0:off) */
@@ -45,6 +52,9 @@ uint8_t thisHand, thatHand;
// user-defined overridable functions
__attribute__((weak)) void matrix_slave_scan_kb(void) { matrix_slave_scan_user(); }
__attribute__((weak)) void matrix_slave_scan_user(void) {}
+__attribute__((weak)) void matrix_init_pins(void);
+__attribute__((weak)) void matrix_read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row);
+__attribute__((weak)) void matrix_read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col);
static inline void setPinOutput_writeLow(pin_t pin) {
ATOMIC_BLOCK_FORCEON {
@@ -61,7 +71,7 @@ static inline void setPinInputHigh_atomic(pin_t pin) {
#ifdef DIRECT_PINS
-static void init_pins(void) {
+__attribute__((weak)) void matrix_init_pins(void) {
for (int row = 0; row < MATRIX_ROWS; row++) {
for (int col = 0; col < MATRIX_COLS; col++) {
pin_t pin = direct_pins[row][col];
@@ -72,7 +82,7 @@ static void init_pins(void) {
}
}
-static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
+__attribute__((weak)) void matrix_read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
// Start with a clear matrix row
matrix_row_t current_row_value = 0;
@@ -83,16 +93,13 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
}
}
- // If the row has changed, store the row and return the changed flag.
- if (current_matrix[current_row] != current_row_value) {
- current_matrix[current_row] = current_row_value;
- return true;
- }
- return false;
+ // Update the matrix
+ current_matrix[current_row] = current_row_value;
}
#elif defined(DIODE_DIRECTION)
-# if (DIODE_DIRECTION == COL2ROW)
+# if defined(MATRIX_ROW_PINS) && defined(MATRIX_COL_PINS)
+# if (DIODE_DIRECTION == COL2ROW)
static void select_row(uint8_t row) { setPinOutput_writeLow(row_pins[row]); }
@@ -104,14 +111,14 @@ static void unselect_rows(void) {
}
}
-static void init_pins(void) {
+__attribute__((weak)) void matrix_init_pins(void) {
unselect_rows();
for (uint8_t x = 0; x < MATRIX_COLS; x++) {
setPinInputHigh_atomic(col_pins[x]);
}
}
-static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
+__attribute__((weak)) void matrix_read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
// Start with a clear matrix row
matrix_row_t current_row_value = 0;
@@ -132,15 +139,11 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
unselect_row(current_row);
matrix_output_unselect_delay(); // wait for all Col signals to go HIGH
- // If the row has changed, store the row and return the changed flag.
- if (current_matrix[current_row] != current_row_value) {
- current_matrix[current_row] = current_row_value;
- return true;
- }
- return false;
+ // Update the matrix
+ current_matrix[current_row] = current_row_value;
}
-# elif (DIODE_DIRECTION == ROW2COL)
+# elif (DIODE_DIRECTION == ROW2COL)
static void select_col(uint8_t col) { setPinOutput_writeLow(col_pins[col]); }
@@ -152,52 +155,39 @@ static void unselect_cols(void) {
}
}
-static void init_pins(void) {
+__attribute__((weak)) void matrix_init_pins(void) {
unselect_cols();
for (uint8_t x = 0; x < ROWS_PER_HAND; x++) {
setPinInputHigh_atomic(row_pins[x]);
}
}
-static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) {
- bool matrix_changed = false;
-
+__attribute__((weak)) void matrix_read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) {
// Select col
select_col(current_col);
matrix_output_select_delay();
// For each row...
for (uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++) {
- // Store last value of row prior to reading
- matrix_row_t last_row_value = current_matrix[row_index];
- matrix_row_t current_row_value = last_row_value;
-
// Check row pin state
if (readPin(row_pins[row_index]) == 0) {
// Pin LO, set col bit
- current_row_value |= (MATRIX_ROW_SHIFTER << current_col);
+ current_matrix[row_index] |= (MATRIX_ROW_SHIFTER << current_col);
} else {
// Pin HI, clear col bit
- current_row_value &= ~(MATRIX_ROW_SHIFTER << current_col);
- }
-
- // Determine if the matrix changed state
- if ((last_row_value != current_row_value)) {
- matrix_changed |= true;
- current_matrix[row_index] = current_row_value;
+ current_matrix[row_index] &= ~(MATRIX_ROW_SHIFTER << current_col);
}
}
// Unselect col
unselect_col(current_col);
matrix_output_unselect_delay(); // wait for all Row signals to go HIGH
-
- return matrix_changed;
}
-# else
-# error DIODE_DIRECTION must be one of COL2ROW or ROW2COL!
-# endif
+# else
+# error DIODE_DIRECTION must be one of COL2ROW or ROW2COL!
+# endif
+# endif // defined(MATRIX_ROW_PINS) && defined(MATRIX_COL_PINS)
#else
# error DIODE_DIRECTION is not defined!
#endif
@@ -233,7 +223,7 @@ void matrix_init(void) {
thatHand = ROWS_PER_HAND - thisHand;
// initialize key pins
- init_pins();
+ matrix_init_pins();
// initialize matrix state: all keys off
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
@@ -288,20 +278,23 @@ bool matrix_post_scan(void) {
}
uint8_t matrix_scan(void) {
- bool local_changed = false;
+ matrix_row_t curr_matrix[MATRIX_ROWS] = {0};
#if defined(DIRECT_PINS) || (DIODE_DIRECTION == COL2ROW)
// Set row, read cols
for (uint8_t current_row = 0; current_row < ROWS_PER_HAND; current_row++) {
- local_changed |= read_cols_on_row(raw_matrix, current_row);
+ matrix_read_cols_on_row(curr_matrix, current_row);
}
#elif (DIODE_DIRECTION == ROW2COL)
// Set col, read rows
for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
- local_changed |= read_rows_on_col(raw_matrix, current_col);
+ matrix_read_rows_on_col(curr_matrix, current_col);
}
#endif
+ bool local_changed = memcmp(raw_matrix, curr_matrix, sizeof(curr_matrix)) != 0;
+ if (local_changed) memcpy(raw_matrix, curr_matrix, sizeof(curr_matrix));
+
debounce(raw_matrix, matrix + thisHand, ROWS_PER_HAND, local_changed);
bool remote_changed = matrix_post_scan();
diff --git a/quantum/split_common/post_config.h b/quantum/split_common/post_config.h
index 4ae1d52732..a4c0a1956b 100644
--- a/quantum/split_common/post_config.h
+++ b/quantum/split_common/post_config.h
@@ -7,13 +7,4 @@
# ifndef F_SCL
# define F_SCL 100000UL // SCL frequency
# endif
-
-#else // use serial
-// When using serial, the user must define RGBLIGHT_SPLIT explicitly
-// in config.h as needed.
-// see quantum/rgblight_post_config.h
-# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
-// When using serial and RGBLIGHT_SPLIT need separate transaction
-# define SERIAL_USE_MULTI_TRANSACTION
-# endif
#endif
diff --git a/quantum/split_common/transaction_id_define.h b/quantum/split_common/transaction_id_define.h
new file mode 100644
index 0000000000..464c73478a
--- /dev/null
+++ b/quantum/split_common/transaction_id_define.h
@@ -0,0 +1,94 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+enum serial_transaction_id {
+#ifdef USE_I2C
+ I2C_EXECUTE_CALLBACK,
+#endif // USE_I2C
+
+ GET_SLAVE_MATRIX_CHECKSUM,
+ GET_SLAVE_MATRIX_DATA,
+
+#ifdef SPLIT_TRANSPORT_MIRROR
+ PUT_MASTER_MATRIX,
+#endif // SPLIT_TRANSPORT_MIRROR
+
+#ifdef ENCODER_ENABLE
+ GET_ENCODERS_CHECKSUM,
+ GET_ENCODERS_DATA,
+#endif // ENCODER_ENABLE
+
+#ifndef DISABLE_SYNC_TIMER
+ PUT_SYNC_TIMER,
+#endif // DISABLE_SYNC_TIMER
+
+#if !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
+ PUT_LAYER_STATE,
+ PUT_DEFAULT_LAYER_STATE,
+#endif // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
+
+#ifdef SPLIT_LED_STATE_ENABLE
+ PUT_LED_STATE,
+#endif // SPLIT_LED_STATE_ENABLE
+
+#ifdef SPLIT_MODS_ENABLE
+ PUT_MODS,
+#endif // SPLIT_MODS_ENABLE
+
+#ifdef BACKLIGHT_ENABLE
+ PUT_BACKLIGHT,
+#endif // BACKLIGHT_ENABLE
+
+#if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
+ PUT_RGBLIGHT,
+#endif // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
+
+#if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
+ PUT_LED_MATRIX,
+#endif // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
+
+#if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
+ PUT_RGB_MATRIX,
+#endif // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
+
+#if defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
+ PUT_WPM,
+#endif // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
+
+#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
+ PUT_RPC_INFO,
+ PUT_RPC_REQ_DATA,
+ EXECUTE_RPC,
+ GET_RPC_RESP_DATA,
+#endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
+
+// keyboard-specific
+#ifdef SPLIT_TRANSACTION_IDS_KB
+ SPLIT_TRANSACTION_IDS_KB,
+#endif // SPLIT_TRANSACTION_IDS_KB
+
+// user/keymap-specific
+#ifdef SPLIT_TRANSACTION_IDS_USER
+ SPLIT_TRANSACTION_IDS_USER,
+#endif // SPLIT_TRANSACTION_IDS_USER
+
+ NUM_TOTAL_TRANSACTIONS
+};
+
+// Ensure we only use 5 bits for transaction
+_Static_assert(NUM_TOTAL_TRANSACTIONS <= (1 << 5), "Max number of usable transactions exceeded");
diff --git a/quantum/split_common/transactions.c b/quantum/split_common/transactions.c
new file mode 100644
index 0000000000..99a8623b3c
--- /dev/null
+++ b/quantum/split_common/transactions.c
@@ -0,0 +1,670 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <stddef.h>
+
+#include "debug.h"
+#include "matrix.h"
+#include "quantum.h"
+#include "transactions.h"
+#include "transport.h"
+#include "transaction_id_define.h"
+
+#define SYNC_TIMER_OFFSET 2
+
+#ifndef FORCED_SYNC_THROTTLE_MS
+# define FORCED_SYNC_THROTTLE_MS 100
+#endif // FORCED_SYNC_THROTTLE_MS
+
+#define sizeof_member(type, member) sizeof(((type *)NULL)->member)
+
+#define trans_initiator2target_initializer_cb(member, cb) \
+ { &dummy, sizeof_member(split_shared_memory_t, member), offsetof(split_shared_memory_t, member), 0, 0, cb }
+#define trans_initiator2target_initializer(member) trans_initiator2target_initializer_cb(member, NULL)
+
+#define trans_target2initiator_initializer_cb(member, cb) \
+ { &dummy, 0, 0, sizeof_member(split_shared_memory_t, member), offsetof(split_shared_memory_t, member), cb }
+#define trans_target2initiator_initializer(member) trans_target2initiator_initializer_cb(member, NULL)
+
+#define transport_write(id, data, length) transport_execute_transaction(id, data, length, NULL, 0)
+#define transport_read(id, data, length) transport_execute_transaction(id, NULL, 0, data, length)
+
+static uint8_t crc8(const void *data, size_t len) {
+ const uint8_t *p = (const uint8_t *)data;
+ uint8_t crc = 0xff;
+ size_t i, j;
+ for (i = 0; i < len; i++) {
+ crc ^= p[i];
+ for (j = 0; j < 8; j++) {
+ if ((crc & 0x80) != 0)
+ crc = (uint8_t)((crc << 1) ^ 0x31);
+ else
+ crc <<= 1;
+ }
+ }
+ return crc;
+}
+
+#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
+// Forward-declare the RPC callback handlers
+void slave_rpc_info_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer);
+void slave_rpc_exec_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer);
+#endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
+
+////////////////////////////////////////////////////
+// Helpers
+
+bool transaction_handler_master(bool okay, matrix_row_t master_matrix[], matrix_row_t slave_matrix[], const char *prefix, bool (*handler)(matrix_row_t master_matrix[], matrix_row_t slave_matrix[])) {
+ if (okay) {
+ bool this_okay = true;
+ for (int iter = 1; iter <= 10; ++iter) {
+ if (!this_okay) {
+ for (int i = 0; i < iter * iter; ++i) {
+ wait_us(10);
+ }
+ }
+ ATOMIC_BLOCK_FORCEON { this_okay = handler(master_matrix, slave_matrix); };
+ if (this_okay) break;
+ }
+ okay &= this_okay;
+ if (!okay) {
+ dprintf("Failed to execute %s\n", prefix);
+ }
+ }
+ return okay;
+}
+
+#define TRANSACTION_HANDLER_MASTER(prefix) \
+ do { \
+ okay &= transaction_handler_master(okay, master_matrix, slave_matrix, #prefix, &prefix##_master); \
+ } while (0)
+
+#define TRANSACTION_HANDLER_SLAVE(prefix) \
+ do { \
+ ATOMIC_BLOCK_FORCEON { prefix##_slave(master_matrix, slave_matrix); }; \
+ } while (0)
+
+inline static bool read_if_checksum_mismatch(int8_t trans_id_checksum, int8_t trans_id_retrieve, uint32_t *last_update, void *destination, const void *equiv_shmem, size_t length) {
+ uint8_t curr_checksum;
+ bool okay = transport_read(trans_id_checksum, &curr_checksum, sizeof(curr_checksum));
+ if (okay && (timer_elapsed32(*last_update) >= FORCED_SYNC_THROTTLE_MS || curr_checksum != crc8(equiv_shmem, length))) {
+ okay &= transport_read(trans_id_retrieve, destination, length);
+ okay &= curr_checksum == crc8(equiv_shmem, length);
+ if (okay) {
+ *last_update = timer_read32();
+ }
+ } else {
+ memcpy(destination, equiv_shmem, length);
+ }
+ return okay;
+}
+
+inline static bool send_if_condition(int8_t trans_id, uint32_t *last_update, bool condition, void *source, size_t length) {
+ bool okay = true;
+ if (timer_elapsed32(*last_update) >= FORCED_SYNC_THROTTLE_MS || condition) {
+ okay &= transport_write(trans_id, source, length);
+ if (okay) {
+ *last_update = timer_read32();
+ }
+ }
+ return okay;
+}
+
+inline static bool send_if_data_mismatch(int8_t trans_id, uint32_t *last_update, void *source, const void *equiv_shmem, size_t length) {
+ // Just run a memcmp to compare the source and equivalent shmem location
+ return send_if_condition(trans_id, last_update, (memcmp(source, equiv_shmem, length) != 0), source, length);
+}
+
+////////////////////////////////////////////////////
+// Slave matrix
+
+static bool slave_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ static uint32_t last_update = 0;
+ static matrix_row_t last_matrix[(MATRIX_ROWS) / 2] = {0}; // last successfully-read matrix, so we can replicate if there are checksum errors
+ matrix_row_t temp_matrix[(MATRIX_ROWS) / 2]; // holding area while we test whether or not checksum is correct
+
+ bool okay = read_if_checksum_mismatch(GET_SLAVE_MATRIX_CHECKSUM, GET_SLAVE_MATRIX_DATA, &last_update, temp_matrix, split_shmem->smatrix.matrix, sizeof(split_shmem->smatrix.matrix));
+ if (okay) {
+ // Checksum matches the received data, save as the last matrix state
+ memcpy(last_matrix, temp_matrix, sizeof(temp_matrix));
+ }
+ // Copy out the last-known-good matrix state to the slave matrix
+ memcpy(slave_matrix, last_matrix, sizeof(last_matrix));
+ return okay;
+}
+
+static void slave_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ memcpy(split_shmem->smatrix.matrix, slave_matrix, sizeof(split_shmem->smatrix.matrix));
+ split_shmem->smatrix.checksum = crc8(split_shmem->smatrix.matrix, sizeof(split_shmem->smatrix.matrix));
+}
+
+// clang-format off
+#define TRANSACTIONS_SLAVE_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(slave_matrix_handlers)
+#define TRANSACTIONS_SLAVE_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(slave_matrix_handlers)
+#define TRANSACTIONS_SLAVE_MATRIX_REGISTRATIONS \
+ [GET_SLAVE_MATRIX_CHECKSUM] = trans_target2initiator_initializer(smatrix.checksum), \
+ [GET_SLAVE_MATRIX_DATA] = trans_target2initiator_initializer(smatrix.matrix),
+// clang-format on
+
+////////////////////////////////////////////////////
+// Master matrix
+
+#ifdef SPLIT_TRANSPORT_MIRROR
+
+static bool master_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ static uint32_t last_update = 0;
+ return send_if_data_mismatch(PUT_MASTER_MATRIX, &last_update, master_matrix, split_shmem->mmatrix.matrix, sizeof(split_shmem->mmatrix.matrix));
+}
+
+static void master_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ // Always copy to the master matrix
+ memcpy(master_matrix, split_shmem->mmatrix.matrix, sizeof(split_shmem->mmatrix.matrix));
+}
+
+# define TRANSACTIONS_MASTER_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(master_matrix_handlers)
+# define TRANSACTIONS_MASTER_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(master_matrix_handlers)
+# define TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS [PUT_MASTER_MATRIX] = trans_initiator2target_initializer(mmatrix.matrix),
+
+#else // SPLIT_TRANSPORT_MIRROR
+
+# define TRANSACTIONS_MASTER_MATRIX_MASTER()
+# define TRANSACTIONS_MASTER_MATRIX_SLAVE()
+# define TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS
+
+#endif // SPLIT_TRANSPORT_MIRROR
+
+////////////////////////////////////////////////////
+// Encoders
+
+#ifdef ENCODER_ENABLE
+
+static bool encoder_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ static uint32_t last_update = 0;
+ uint8_t temp_state[NUMBER_OF_ENCODERS];
+
+ bool okay = read_if_checksum_mismatch(GET_ENCODERS_CHECKSUM, GET_ENCODERS_DATA, &last_update, temp_state, split_shmem->encoders.state, sizeof(temp_state));
+ if (okay) encoder_update_raw(temp_state);
+ return okay;
+}
+
+static void encoder_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ uint8_t encoder_state[NUMBER_OF_ENCODERS];
+ encoder_state_raw(encoder_state);
+ // Always prepare the encoder state for read.
+ memcpy(split_shmem->encoders.state, encoder_state, sizeof(encoder_state));
+ // Now update the checksum given that the encoders has been written to
+ split_shmem->encoders.checksum = crc8(encoder_state, sizeof(encoder_state));
+}
+
+// clang-format off
+# define TRANSACTIONS_ENCODERS_MASTER() TRANSACTION_HANDLER_MASTER(encoder_handlers)
+# define TRANSACTIONS_ENCODERS_SLAVE() TRANSACTION_HANDLER_SLAVE(encoder_handlers)
+# define TRANSACTIONS_ENCODERS_REGISTRATIONS \
+ [GET_ENCODERS_CHECKSUM] = trans_target2initiator_initializer(encoders.checksum), \
+ [GET_ENCODERS_DATA] = trans_target2initiator_initializer(encoders.state),
+// clang-format on
+
+#else // ENCODER_ENABLE
+
+# define TRANSACTIONS_ENCODERS_MASTER()
+# define TRANSACTIONS_ENCODERS_SLAVE()
+# define TRANSACTIONS_ENCODERS_REGISTRATIONS
+
+#endif // ENCODER_ENABLE
+
+////////////////////////////////////////////////////
+// Sync timer
+
+#ifndef DISABLE_SYNC_TIMER
+
+static bool sync_timer_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ static uint32_t last_update = 0;
+
+ bool okay = true;
+ if (timer_elapsed32(last_update) >= FORCED_SYNC_THROTTLE_MS) {
+ uint32_t sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET;
+ okay &= transport_write(PUT_SYNC_TIMER, &sync_timer, sizeof(sync_timer));
+ if (okay) {
+ last_update = timer_read32();
+ }
+ }
+ return okay;
+}
+
+static void sync_timer_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ static uint32_t last_sync_timer = 0;
+ if (last_sync_timer != split_shmem->sync_timer) {
+ last_sync_timer = split_shmem->sync_timer;
+ sync_timer_update(last_sync_timer);
+ }
+}
+
+# define TRANSACTIONS_SYNC_TIMER_MASTER() TRANSACTION_HANDLER_MASTER(sync_timer_handlers)
+# define TRANSACTIONS_SYNC_TIMER_SLAVE() TRANSACTION_HANDLER_SLAVE(sync_timer_handlers)
+# define TRANSACTIONS_SYNC_TIMER_REGISTRATIONS [PUT_SYNC_TIMER] = trans_initiator2target_initializer(sync_timer),
+
+#else // DISABLE_SYNC_TIMER
+
+# define TRANSACTIONS_SYNC_TIMER_MASTER()
+# define TRANSACTIONS_SYNC_TIMER_SLAVE()
+# define TRANSACTIONS_SYNC_TIMER_REGISTRATIONS
+
+#endif // DISABLE_SYNC_TIMER
+
+////////////////////////////////////////////////////
+// Layer state
+
+#if !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
+
+static bool layer_state_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ static uint32_t last_layer_state_update = 0;
+ static uint32_t last_default_layer_state_update = 0;
+
+ bool okay = send_if_condition(PUT_LAYER_STATE, &last_layer_state_update, (layer_state != split_shmem->layers.layer_state), &layer_state, sizeof(layer_state));
+ if (okay) {
+ okay &= send_if_condition(PUT_DEFAULT_LAYER_STATE, &last_default_layer_state_update, (default_layer_state != split_shmem->layers.default_layer_state), &default_layer_state, sizeof(default_layer_state));
+ }
+ return okay;
+}
+
+static void layer_state_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ layer_state = split_shmem->layers.layer_state;
+ default_layer_state = split_shmem->layers.default_layer_state;
+}
+
+// clang-format off
+# define TRANSACTIONS_LAYER_STATE_MASTER() TRANSACTION_HANDLER_MASTER(layer_state_handlers)
+# define TRANSACTIONS_LAYER_STATE_SLAVE() TRANSACTION_HANDLER_SLAVE(layer_state_handlers)
+# define TRANSACTIONS_LAYER_STATE_REGISTRATIONS \
+ [PUT_LAYER_STATE] = trans_initiator2target_initializer(layers.layer_state), \
+ [PUT_DEFAULT_LAYER_STATE] = trans_initiator2target_initializer(layers.default_layer_state),
+// clang-format on
+
+#else // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
+
+# define TRANSACTIONS_LAYER_STATE_MASTER()
+# define TRANSACTIONS_LAYER_STATE_SLAVE()
+# define TRANSACTIONS_LAYER_STATE_REGISTRATIONS
+
+#endif // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
+
+////////////////////////////////////////////////////
+// LED state
+
+#ifdef SPLIT_LED_STATE_ENABLE
+
+static bool led_state_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ static uint32_t last_update = 0;
+ uint8_t led_state = host_keyboard_leds();
+ return send_if_data_mismatch(PUT_LED_STATE, &last_update, &led_state, &split_shmem->led_state, sizeof(led_state));
+}
+
+static void led_state_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ void set_split_host_keyboard_leds(uint8_t led_state);
+ set_split_host_keyboard_leds(split_shmem->led_state);
+}
+
+# define TRANSACTIONS_LED_STATE_MASTER() TRANSACTION_HANDLER_MASTER(led_state_handlers)
+# define TRANSACTIONS_LED_STATE_SLAVE() TRANSACTION_HANDLER_SLAVE(led_state_handlers)
+# define TRANSACTIONS_LED_STATE_REGISTRATIONS [PUT_LED_STATE] = trans_initiator2target_initializer(led_state),
+
+#else // SPLIT_LED_STATE_ENABLE
+
+# define TRANSACTIONS_LED_STATE_MASTER()
+# define TRANSACTIONS_LED_STATE_SLAVE()
+# define TRANSACTIONS_LED_STATE_REGISTRATIONS
+
+#endif // SPLIT_LED_STATE_ENABLE
+
+////////////////////////////////////////////////////
+// Mods
+
+#ifdef SPLIT_MODS_ENABLE
+
+static bool mods_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ static uint32_t last_update = 0;
+ bool mods_need_sync = timer_elapsed32(last_update) >= FORCED_SYNC_THROTTLE_MS;
+ split_mods_sync_t new_mods;
+ new_mods.real_mods = get_mods();
+ if (!mods_need_sync && new_mods.real_mods != split_shmem->mods.real_mods) {
+ mods_need_sync = true;
+ }
+
+ new_mods.weak_mods = get_weak_mods();
+ if (!mods_need_sync && new_mods.weak_mods != split_shmem->mods.weak_mods) {
+ mods_need_sync = true;
+ }
+
+# ifndef NO_ACTION_ONESHOT
+ new_mods.oneshot_mods = get_oneshot_mods();
+ if (!mods_need_sync && new_mods.oneshot_mods != split_shmem->mods.oneshot_mods) {
+ mods_need_sync = true;
+ }
+# endif // NO_ACTION_ONESHOT
+
+ bool okay = true;
+ if (mods_need_sync) {
+ okay &= transport_write(PUT_MODS, &new_mods, sizeof(new_mods));
+ if (okay) {
+ last_update = timer_read32();
+ }
+ }
+
+ return okay;
+}
+
+static void mods_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ set_mods(split_shmem->mods.real_mods);
+ set_weak_mods(split_shmem->mods.weak_mods);
+# ifndef NO_ACTION_ONESHOT
+ set_oneshot_mods(split_shmem->mods.oneshot_mods);
+# endif
+}
+
+# define TRANSACTIONS_MODS_MASTER() TRANSACTION_HANDLER_MASTER(mods_handlers)
+# define TRANSACTIONS_MODS_SLAVE() TRANSACTION_HANDLER_SLAVE(mods_handlers)
+# define TRANSACTIONS_MODS_REGISTRATIONS [PUT_MODS] = trans_initiator2target_initializer(mods),
+
+#else // SPLIT_MODS_ENABLE
+
+# define TRANSACTIONS_MODS_MASTER()
+# define TRANSACTIONS_MODS_SLAVE()
+# define TRANSACTIONS_MODS_REGISTRATIONS
+
+#endif // SPLIT_MODS_ENABLE
+
+////////////////////////////////////////////////////
+// Backlight
+
+#ifdef BACKLIGHT_ENABLE
+
+static bool backlight_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ static uint32_t last_update = 0;
+ uint8_t level = is_backlight_enabled() ? get_backlight_level() : 0;
+ return send_if_condition(PUT_BACKLIGHT, &last_update, (level != split_shmem->backlight_level), &level, sizeof(level));
+}
+
+static void backlight_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { backlight_set(split_shmem->backlight_level); }
+
+# define TRANSACTIONS_BACKLIGHT_MASTER() TRANSACTION_HANDLER_MASTER(backlight_handlers)
+# define TRANSACTIONS_BACKLIGHT_SLAVE() TRANSACTION_HANDLER_SLAVE(backlight_handlers)
+# define TRANSACTIONS_BACKLIGHT_REGISTRATIONS [PUT_BACKLIGHT] = trans_initiator2target_initializer(backlight_level),
+
+#else // BACKLIGHT_ENABLE
+
+# define TRANSACTIONS_BACKLIGHT_MASTER()
+# define TRANSACTIONS_BACKLIGHT_SLAVE()
+# define TRANSACTIONS_BACKLIGHT_REGISTRATIONS
+
+#endif // BACKLIGHT_ENABLE
+
+////////////////////////////////////////////////////
+// RGBLIGHT
+
+#if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
+
+static bool rgblight_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ static uint32_t last_update = 0;
+ rgblight_syncinfo_t rgblight_sync;
+ rgblight_get_syncinfo(&rgblight_sync);
+ if (send_if_condition(PUT_RGBLIGHT, &last_update, (rgblight_sync.status.change_flags != 0), &rgblight_sync, sizeof(rgblight_sync))) {
+ rgblight_clear_change_flags();
+ } else {
+ return false;
+ }
+ return true;
+}
+
+static void rgblight_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ // Update the RGB with the new data
+ if (split_shmem->rgblight_sync.status.change_flags != 0) {
+ rgblight_update_sync(&split_shmem->rgblight_sync, false);
+ split_shmem->rgblight_sync.status.change_flags = 0;
+ }
+}
+
+# define TRANSACTIONS_RGBLIGHT_MASTER() TRANSACTION_HANDLER_MASTER(rgblight_handlers)
+# define TRANSACTIONS_RGBLIGHT_SLAVE() TRANSACTION_HANDLER_SLAVE(rgblight_handlers)
+# define TRANSACTIONS_RGBLIGHT_REGISTRATIONS [PUT_RGBLIGHT] = trans_initiator2target_initializer(rgblight_sync),
+
+#else // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
+
+# define TRANSACTIONS_RGBLIGHT_MASTER()
+# define TRANSACTIONS_RGBLIGHT_SLAVE()
+# define TRANSACTIONS_RGBLIGHT_REGISTRATIONS
+
+#endif // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
+
+////////////////////////////////////////////////////
+// LED Matrix
+
+#if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
+
+static bool led_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ static uint32_t last_update = 0;
+ led_matrix_sync_t led_matrix_sync;
+ memcpy(&led_matrix_sync.led_matrix, &led_matrix_eeconfig, sizeof(led_eeconfig_t));
+ led_matrix_sync.led_suspend_state = led_matrix_get_suspend_state();
+ return send_if_data_mismatch(PUT_LED_MATRIX, &last_update, &led_matrix_sync, &split_shmem->led_matrix_sync, sizeof(led_matrix_sync));
+}
+
+static void led_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ memcpy(&led_matrix_eeconfig, &split_shmem->led_matrix_sync.led_matrix, sizeof(led_eeconfig_t));
+ led_matrix_set_suspend_state(split_shmem->led_matrix_sync.led_suspend_state);
+}
+
+# define TRANSACTIONS_LED_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(led_matrix_handlers)
+# define TRANSACTIONS_LED_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(led_matrix_handlers)
+# define TRANSACTIONS_LED_MATRIX_REGISTRATIONS [PUT_LED_MATRIX] = trans_initiator2target_initializer(led_matrix_sync),
+
+#else // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
+
+# define TRANSACTIONS_LED_MATRIX_MASTER()
+# define TRANSACTIONS_LED_MATRIX_SLAVE()
+# define TRANSACTIONS_LED_MATRIX_REGISTRATIONS
+
+#endif // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
+
+////////////////////////////////////////////////////
+// RGB Matrix
+
+#if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
+
+static bool rgb_matrix_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ static uint32_t last_update = 0;
+ rgb_matrix_sync_t rgb_matrix_sync;
+ memcpy(&rgb_matrix_sync.rgb_matrix, &rgb_matrix_config, sizeof(rgb_config_t));
+ rgb_matrix_sync.rgb_suspend_state = rgb_matrix_get_suspend_state();
+ return send_if_data_mismatch(PUT_RGB_MATRIX, &last_update, &rgb_matrix_sync, &split_shmem->rgb_matrix_sync, sizeof(rgb_matrix_sync));
+}
+
+static void rgb_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ memcpy(&rgb_matrix_config, &split_shmem->rgb_matrix_sync.rgb_matrix, sizeof(rgb_config_t));
+ rgb_matrix_set_suspend_state(split_shmem->rgb_matrix_sync.rgb_suspend_state);
+}
+
+# define TRANSACTIONS_RGB_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(rgb_matrix_handlers)
+# define TRANSACTIONS_RGB_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(rgb_matrix_handlers)
+# define TRANSACTIONS_RGB_MATRIX_REGISTRATIONS [PUT_RGB_MATRIX] = trans_initiator2target_initializer(rgb_matrix_sync),
+
+#else // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
+
+# define TRANSACTIONS_RGB_MATRIX_MASTER()
+# define TRANSACTIONS_RGB_MATRIX_SLAVE()
+# define TRANSACTIONS_RGB_MATRIX_REGISTRATIONS
+
+#endif // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
+
+////////////////////////////////////////////////////
+// WPM
+
+#if defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
+
+static bool wpm_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ static uint32_t last_update = 0;
+ uint8_t current_wpm = get_current_wpm();
+ return send_if_condition(PUT_WPM, &last_update, (current_wpm != split_shmem->current_wpm), &current_wpm, sizeof(current_wpm));
+}
+
+static void wpm_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { set_current_wpm(split_shmem->current_wpm); }
+
+# define TRANSACTIONS_WPM_MASTER() TRANSACTION_HANDLER_MASTER(wpm_handlers)
+# define TRANSACTIONS_WPM_SLAVE() TRANSACTION_HANDLER_SLAVE(wpm_handlers)
+# define TRANSACTIONS_WPM_REGISTRATIONS [PUT_WPM] = trans_initiator2target_initializer(current_wpm),
+
+#else // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
+
+# define TRANSACTIONS_WPM_MASTER()
+# define TRANSACTIONS_WPM_SLAVE()
+# define TRANSACTIONS_WPM_REGISTRATIONS
+
+#endif // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
+
+////////////////////////////////////////////////////
+
+uint8_t dummy;
+split_transaction_desc_t split_transaction_table[NUM_TOTAL_TRANSACTIONS] = {
+ // Set defaults
+ [0 ...(NUM_TOTAL_TRANSACTIONS - 1)] = {NULL, 0, 0, 0, 0, 0},
+
+#ifdef USE_I2C
+ [I2C_EXECUTE_CALLBACK] = trans_initiator2target_initializer(transaction_id),
+#endif // USE_I2C
+
+ // clang-format off
+ TRANSACTIONS_SLAVE_MATRIX_REGISTRATIONS
+ TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS
+ TRANSACTIONS_ENCODERS_REGISTRATIONS
+ TRANSACTIONS_SYNC_TIMER_REGISTRATIONS
+ TRANSACTIONS_LAYER_STATE_REGISTRATIONS
+ TRANSACTIONS_LED_STATE_REGISTRATIONS
+ TRANSACTIONS_MODS_REGISTRATIONS
+ TRANSACTIONS_BACKLIGHT_REGISTRATIONS
+ TRANSACTIONS_RGBLIGHT_REGISTRATIONS
+ TRANSACTIONS_LED_MATRIX_REGISTRATIONS
+ TRANSACTIONS_RGB_MATRIX_REGISTRATIONS
+ TRANSACTIONS_WPM_REGISTRATIONS
+// clang-format on
+
+#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
+ [PUT_RPC_INFO] = trans_initiator2target_initializer_cb(rpc_info, slave_rpc_info_callback),
+ [PUT_RPC_REQ_DATA] = trans_initiator2target_initializer(rpc_m2s_buffer),
+ [EXECUTE_RPC] = trans_initiator2target_initializer_cb(rpc_info.transaction_id, slave_rpc_exec_callback),
+ [GET_RPC_RESP_DATA] = trans_target2initiator_initializer(rpc_s2m_buffer),
+#endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
+};
+
+bool transactions_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ bool okay = true;
+ TRANSACTIONS_SLAVE_MATRIX_MASTER();
+ TRANSACTIONS_MASTER_MATRIX_MASTER();
+ TRANSACTIONS_ENCODERS_MASTER();
+ TRANSACTIONS_SYNC_TIMER_MASTER();
+ TRANSACTIONS_LAYER_STATE_MASTER();
+ TRANSACTIONS_LED_STATE_MASTER();
+ TRANSACTIONS_MODS_MASTER();
+ TRANSACTIONS_BACKLIGHT_MASTER();
+ TRANSACTIONS_RGBLIGHT_MASTER();
+ TRANSACTIONS_LED_MATRIX_MASTER();
+ TRANSACTIONS_RGB_MATRIX_MASTER();
+ TRANSACTIONS_WPM_MASTER();
+ return okay;
+}
+
+void transactions_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+ TRANSACTIONS_SLAVE_MATRIX_SLAVE();
+ TRANSACTIONS_MASTER_MATRIX_SLAVE();
+ TRANSACTIONS_ENCODERS_SLAVE();
+ TRANSACTIONS_SYNC_TIMER_SLAVE();
+ TRANSACTIONS_LAYER_STATE_SLAVE();
+ TRANSACTIONS_LED_STATE_SLAVE();
+ TRANSACTIONS_MODS_SLAVE();
+ TRANSACTIONS_BACKLIGHT_SLAVE();
+ TRANSACTIONS_RGBLIGHT_SLAVE();
+ TRANSACTIONS_LED_MATRIX_SLAVE();
+ TRANSACTIONS_RGB_MATRIX_SLAVE();
+ TRANSACTIONS_WPM_SLAVE();
+}
+
+#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
+
+void transaction_register_rpc(int8_t transaction_id, slave_callback_t callback) {
+ // Prevent invoking RPC on QMK core sync data
+ if (transaction_id <= GET_RPC_RESP_DATA) return;
+
+ // Set the callback
+ split_transaction_table[transaction_id].slave_callback = callback;
+ split_transaction_table[transaction_id].initiator2target_offset = offsetof(split_shared_memory_t, rpc_m2s_buffer);
+ split_transaction_table[transaction_id].target2initiator_offset = offsetof(split_shared_memory_t, rpc_s2m_buffer);
+}
+
+bool transaction_rpc_exec(int8_t transaction_id, uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) {
+ // Prevent invoking RPC on QMK core sync data
+ if (transaction_id <= GET_RPC_RESP_DATA) return false;
+ // Prevent sizing issues
+ if (initiator2target_buffer_size > RPC_M2S_BUFFER_SIZE) return false;
+ if (target2initiator_buffer_size > RPC_S2M_BUFFER_SIZE) return false;
+
+ // Prepare the metadata block
+ rpc_sync_info_t info = {.transaction_id = transaction_id, .m2s_length = initiator2target_buffer_size, .s2m_length = target2initiator_buffer_size};
+
+ // Make sure the local side knows that we're not sending the full block of data
+ split_transaction_table[PUT_RPC_REQ_DATA].initiator2target_buffer_size = initiator2target_buffer_size;
+ split_transaction_table[GET_RPC_RESP_DATA].target2initiator_buffer_size = target2initiator_buffer_size;
+
+ // Run through the sequence:
+ // * set the transaction ID and lengths
+ // * send the request data
+ // * execute RPC callback
+ // * retrieve the response data
+ if (!transport_write(PUT_RPC_INFO, &info, sizeof(info))) {
+ return false;
+ }
+ if (!transport_write(PUT_RPC_REQ_DATA, initiator2target_buffer, initiator2target_buffer_size)) {
+ return false;
+ }
+ if (!transport_write(EXECUTE_RPC, &transaction_id, sizeof(transaction_id))) {
+ return false;
+ }
+ if (!transport_read(GET_RPC_RESP_DATA, target2initiator_buffer, target2initiator_buffer_size)) {
+ return false;
+ }
+ return true;
+}
+
+void slave_rpc_info_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) {
+ // The RPC info block contains the intended transaction ID, as well as the sizes for both inbound and outbound data.
+ // Ignore the args -- the `split_shmem` already has the info, we just need to act upon it.
+ // We must keep the `split_transaction_table` non-const, so that it is able to be modified at runtime.
+
+ split_transaction_table[PUT_RPC_REQ_DATA].initiator2target_buffer_size = split_shmem->rpc_info.m2s_length;
+ split_transaction_table[GET_RPC_RESP_DATA].target2initiator_buffer_size = split_shmem->rpc_info.s2m_length;
+}
+
+void slave_rpc_exec_callback(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer) {
+ // We can assume that the buffer lengths are correctly set, now, given that sequentially the rpc_info callback was already executed.
+ // Go through the rpc_info and execute _that_ transaction's callback, with the scratch buffers as inputs.
+ int8_t transaction_id = split_shmem->rpc_info.transaction_id;
+ if (transaction_id < NUM_TOTAL_TRANSACTIONS) {
+ split_transaction_desc_t *trans = &split_transaction_table[transaction_id];
+ if (trans->slave_callback) {
+ trans->slave_callback(split_shmem->rpc_info.m2s_length, split_shmem->rpc_m2s_buffer, split_shmem->rpc_info.s2m_length, split_shmem->rpc_s2m_buffer);
+ }
+ }
+}
+
+#endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
diff --git a/quantum/split_common/transactions.h b/quantum/split_common/transactions.h
new file mode 100644
index 0000000000..4306ba1d87
--- /dev/null
+++ b/quantum/split_common/transactions.h
@@ -0,0 +1,54 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "stdint.h"
+#include "stdbool.h"
+
+#include "matrix.h"
+#include "transaction_id_define.h"
+#include "transport.h"
+
+typedef void (*slave_callback_t)(uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer);
+
+// Split transaction Descriptor
+typedef struct _split_transaction_desc_t {
+ uint8_t * status;
+ uint8_t initiator2target_buffer_size;
+ uint16_t initiator2target_offset;
+ uint8_t target2initiator_buffer_size;
+ uint16_t target2initiator_offset;
+ slave_callback_t slave_callback;
+} split_transaction_desc_t;
+
+// Forward declaration for the split transactions
+extern split_transaction_desc_t split_transaction_table[NUM_TOTAL_TRANSACTIONS];
+
+#define split_shmem_offset_ptr(offset) ((void *)(((uint8_t *)split_shmem) + (offset)))
+#define split_trans_initiator2target_buffer(trans) (split_shmem_offset_ptr((trans)->initiator2target_offset))
+#define split_trans_target2initiator_buffer(trans) (split_shmem_offset_ptr((trans)->target2initiator_offset))
+
+// returns false if valid data not received from slave
+bool transactions_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]);
+void transactions_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]);
+
+void transaction_register_rpc(int8_t transaction_id, slave_callback_t callback);
+
+bool transaction_rpc_exec(int8_t transaction_id, uint8_t initiator2target_buffer_size, const void *initiator2target_buffer, uint8_t target2initiator_buffer_size, void *target2initiator_buffer);
+
+#define transaction_rpc_send(transaction_id, initiator2target_buffer_size, initiator2target_buffer) transaction_rpc_exec(transaction_id, initiator2target_buffer_size, initiator2target_buffer, 0, NULL)
+#define transaction_rpc_recv(transaction_id, target2initiator_buffer_size, target2initiator_buffer) transaction_rpc_exec(transaction_id, 0, NULL, target2initiator_buffer_size, target2initiator_buffer)
diff --git a/quantum/split_common/transport.c b/quantum/split_common/transport.c
index 9ed0f7591b..a711ef85f0 100644
--- a/quantum/split_common/transport.c
+++ b/quantum/split_common/transport.c
@@ -1,452 +1,118 @@
-#include <string.h>
-#include <stddef.h>
-
-#include "config.h"
-#include "matrix.h"
-#include "quantum.h"
-
-#define ROWS_PER_HAND (MATRIX_ROWS / 2)
-#define SYNC_TIMER_OFFSET 2
-
-#ifdef RGBLIGHT_ENABLE
-# include "rgblight.h"
-#endif
-
-#ifdef BACKLIGHT_ENABLE
-# include "backlight.h"
-#endif
-
-#ifdef ENCODER_ENABLE
-# include "encoder.h"
-static pin_t encoders_pad[] = ENCODERS_PAD_A;
-# define NUMBER_OF_ENCODERS (sizeof(encoders_pad) / sizeof(pin_t))
-#endif
-
-#if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
-# include "led_matrix.h"
-#endif
-#if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
-# include "rgb_matrix.h"
-#endif
-
-#if defined(USE_I2C)
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
-# include "i2c_master.h"
-# include "i2c_slave.h"
-
-typedef struct _I2C_slave_buffer_t {
-# ifndef DISABLE_SYNC_TIMER
- uint32_t sync_timer;
-# endif
-# ifdef SPLIT_TRANSPORT_MIRROR
- matrix_row_t mmatrix[ROWS_PER_HAND];
-# endif
- matrix_row_t smatrix[ROWS_PER_HAND];
-# ifdef SPLIT_MODS_ENABLE
- uint8_t real_mods;
- uint8_t weak_mods;
-# ifndef NO_ACTION_ONESHOT
- uint8_t oneshot_mods;
-# endif
-# endif
-# ifdef BACKLIGHT_ENABLE
- uint8_t backlight_level;
-# endif
-# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
- rgblight_syncinfo_t rgblight_sync;
-# endif
-# ifdef ENCODER_ENABLE
- uint8_t encoder_state[NUMBER_OF_ENCODERS];
-# endif
-# ifdef WPM_ENABLE
- uint8_t current_wpm;
-# endif
-# if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
- led_eeconfig_t led_matrix;
- bool led_suspend_state;
-# endif
-# if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
- rgb_config_t rgb_matrix;
- bool rgb_suspend_state;
-# endif
-} I2C_slave_buffer_t;
+#include <string.h>
+#include <debug.h>
-static I2C_slave_buffer_t *const i2c_buffer = (I2C_slave_buffer_t *)i2c_slave_reg;
+#include "transactions.h"
+#include "transport.h"
+#include "transaction_id_define.h"
+#include "atomic_util.h"
-# define I2C_SYNC_TIME_START offsetof(I2C_slave_buffer_t, sync_timer)
-# define I2C_KEYMAP_MASTER_START offsetof(I2C_slave_buffer_t, mmatrix)
-# define I2C_KEYMAP_SLAVE_START offsetof(I2C_slave_buffer_t, smatrix)
-# define I2C_REAL_MODS_START offsetof(I2C_slave_buffer_t, real_mods)
-# define I2C_WEAK_MODS_START offsetof(I2C_slave_buffer_t, weak_mods)
-# define I2C_ONESHOT_MODS_START offsetof(I2C_slave_buffer_t, oneshot_mods)
-# define I2C_BACKLIGHT_START offsetof(I2C_slave_buffer_t, backlight_level)
-# define I2C_RGB_START offsetof(I2C_slave_buffer_t, rgblight_sync)
-# define I2C_ENCODER_START offsetof(I2C_slave_buffer_t, encoder_state)
-# define I2C_WPM_START offsetof(I2C_slave_buffer_t, current_wpm)
-# define I2C_LED_MATRIX_START offsetof(I2C_slave_buffer_t, led_matrix)
-# define I2C_LED_SUSPEND_START offsetof(I2C_slave_buffer_t, led_suspend_state)
-# define I2C_RGB_MATRIX_START offsetof(I2C_slave_buffer_t, rgb_matrix)
-# define I2C_RGB_SUSPEND_START offsetof(I2C_slave_buffer_t, rgb_suspend_state)
+#ifdef USE_I2C
-# define TIMEOUT 100
+# ifndef SLAVE_I2C_TIMEOUT
+# define SLAVE_I2C_TIMEOUT 100
+# endif // SLAVE_I2C_TIMEOUT
# ifndef SLAVE_I2C_ADDRESS
# define SLAVE_I2C_ADDRESS 0x32
# endif
-// Get rows from other half over i2c
-bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
- i2c_readReg(SLAVE_I2C_ADDRESS, I2C_KEYMAP_SLAVE_START, (void *)slave_matrix, sizeof(i2c_buffer->smatrix), TIMEOUT);
-# ifdef SPLIT_TRANSPORT_MIRROR
- i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_KEYMAP_MASTER_START, (void *)master_matrix, sizeof(i2c_buffer->mmatrix), TIMEOUT);
-# endif
+# include "i2c_master.h"
+# include "i2c_slave.h"
- // write backlight info
-# ifdef BACKLIGHT_ENABLE
- uint8_t level = is_backlight_enabled() ? get_backlight_level() : 0;
- if (level != i2c_buffer->backlight_level) {
- if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_BACKLIGHT_START, (void *)&level, sizeof(level), TIMEOUT) >= 0) {
- i2c_buffer->backlight_level = level;
- }
- }
-# endif
+// Ensure the I2C buffer has enough space
+_Static_assert(sizeof(split_shared_memory_t) <= I2C_SLAVE_REG_COUNT, "split_shared_memory_t too large for I2C_SLAVE_REG_COUNT");
-# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
- if (rgblight_get_change_flags()) {
- rgblight_syncinfo_t rgblight_sync;
- rgblight_get_syncinfo(&rgblight_sync);
- if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_RGB_START, (void *)&rgblight_sync, sizeof(rgblight_sync), TIMEOUT) >= 0) {
- rgblight_clear_change_flags();
- }
- }
-# endif
+split_shared_memory_t *const split_shmem = (split_shared_memory_t *)i2c_slave_reg;
-# ifdef ENCODER_ENABLE
- i2c_readReg(SLAVE_I2C_ADDRESS, I2C_ENCODER_START, (void *)i2c_buffer->encoder_state, sizeof(i2c_buffer->encoder_state), TIMEOUT);
- encoder_update_raw(i2c_buffer->encoder_state);
-# endif
+void transport_master_init(void) { i2c_init(); }
+void transport_slave_init(void) { i2c_slave_init(SLAVE_I2C_ADDRESS); }
-# ifdef WPM_ENABLE
- uint8_t current_wpm = get_current_wpm();
- if (current_wpm != i2c_buffer->current_wpm) {
- if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_WPM_START, (void *)&current_wpm, sizeof(current_wpm), TIMEOUT) >= 0) {
- i2c_buffer->current_wpm = current_wpm;
- }
+i2c_status_t transport_trigger_callback(int8_t id) {
+ // If there's no callback, indicate that we were successful
+ if (!split_transaction_table[id].slave_callback) {
+ return I2C_STATUS_SUCCESS;
}
-# endif
-# ifdef SPLIT_MODS_ENABLE
- uint8_t real_mods = get_mods();
- if (real_mods != i2c_buffer->real_mods) {
- if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_REAL_MODS_START, (void *)&real_mods, sizeof(real_mods), TIMEOUT) >= 0) {
- i2c_buffer->real_mods = real_mods;
+ // Kick off the "callback executor", now that data has been written to the slave
+ split_shmem->transaction_id = id;
+ split_transaction_desc_t *trans = &split_transaction_table[I2C_EXECUTE_CALLBACK];
+ return i2c_writeReg(SLAVE_I2C_ADDRESS, trans->initiator2target_offset, split_trans_initiator2target_buffer(trans), trans->initiator2target_buffer_size, SLAVE_I2C_TIMEOUT);
+}
+
+bool transport_execute_transaction(int8_t id, const void *initiator2target_buf, uint16_t initiator2target_length, void *target2initiator_buf, uint16_t target2initiator_length) {
+ i2c_status_t status;
+ split_transaction_desc_t *trans = &split_transaction_table[id];
+ if (initiator2target_length > 0) {
+ size_t len = trans->initiator2target_buffer_size < initiator2target_length ? trans->initiator2target_buffer_size : initiator2target_length;
+ memcpy(split_trans_initiator2target_buffer(trans), initiator2target_buf, len);
+ if ((status = i2c_writeReg(SLAVE_I2C_ADDRESS, trans->initiator2target_offset, split_trans_initiator2target_buffer(trans), len, SLAVE_I2C_TIMEOUT)) < 0) {
+ return false;
}
}
- uint8_t weak_mods = get_weak_mods();
- if (weak_mods != i2c_buffer->weak_mods) {
- if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_WEAK_MODS_START, (void *)&weak_mods, sizeof(weak_mods), TIMEOUT) >= 0) {
- i2c_buffer->weak_mods = weak_mods;
- }
+ // If we need to execute a callback on the slave, do so
+ if ((status = transport_trigger_callback(id)) < 0) {
+ return false;
}
-# ifndef NO_ACTION_ONESHOT
- uint8_t oneshot_mods = get_oneshot_mods();
- if (oneshot_mods != i2c_buffer->oneshot_mods) {
- if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_ONESHOT_MODS_START, (void *)&oneshot_mods, sizeof(oneshot_mods), TIMEOUT) >= 0) {
- i2c_buffer->oneshot_mods = oneshot_mods;
+ if (target2initiator_length > 0) {
+ size_t len = trans->target2initiator_buffer_size < target2initiator_length ? trans->target2initiator_buffer_size : target2initiator_length;
+ if ((status = i2c_readReg(SLAVE_I2C_ADDRESS, trans->target2initiator_offset, split_trans_target2initiator_buffer(trans), len, SLAVE_I2C_TIMEOUT)) < 0) {
+ return false;
}
+ memcpy(target2initiator_buf, split_trans_target2initiator_buffer(trans), len);
}
-# endif
-# endif
-# if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
- i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_LED_MATRIX_START, (void *)led_matrix_eeconfig, sizeof(i2c_buffer->led_matrix), TIMEOUT);
- bool suspend_state = led_matrix_get_suspend_state();
- i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_LED_SUSPEND_START, (void *)suspend_state, sizeof(i2c_buffer->led_suspend_state), TIMEOUT);
-# endif
-# if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
- i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_RGB_MATRIX_START, (void *)rgb_matrix_config, sizeof(i2c_buffer->rgb_matrix), TIMEOUT);
- bool suspend_state = rgb_matrix_get_suspend_state();
- i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_RGB_SUSPEND_START, (void *)suspend_state, sizeof(i2c_buffer->rgb_suspend_state), TIMEOUT);
-# endif
-
-# ifndef DISABLE_SYNC_TIMER
- i2c_buffer->sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET;
- i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_SYNC_TIME_START, (void *)&i2c_buffer->sync_timer, sizeof(i2c_buffer->sync_timer), TIMEOUT);
-# endif
return true;
}
-void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
-# ifndef DISABLE_SYNC_TIMER
- sync_timer_update(i2c_buffer->sync_timer);
-# endif
- // Copy matrix to I2C buffer
- memcpy((void *)i2c_buffer->smatrix, (void *)slave_matrix, sizeof(i2c_buffer->smatrix));
-# ifdef SPLIT_TRANSPORT_MIRROR
- memcpy((void *)master_matrix, (void *)i2c_buffer->mmatrix, sizeof(i2c_buffer->mmatrix));
-# endif
-
-// Read Backlight Info
-# ifdef BACKLIGHT_ENABLE
- backlight_set(i2c_buffer->backlight_level);
-# endif
-
-# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
- // Update the RGB with the new data
- if (i2c_buffer->rgblight_sync.status.change_flags != 0) {
- rgblight_update_sync(&i2c_buffer->rgblight_sync, false);
- i2c_buffer->rgblight_sync.status.change_flags = 0;
- }
-# endif
-
-# ifdef ENCODER_ENABLE
- encoder_state_raw(i2c_buffer->encoder_state);
-# endif
-
-# ifdef WPM_ENABLE
- set_current_wpm(i2c_buffer->current_wpm);
-# endif
-
-# ifdef SPLIT_MODS_ENABLE
- set_mods(i2c_buffer->real_mods);
- set_weak_mods(i2c_buffer->weak_mods);
-# ifndef NO_ACTION_ONESHOT
- set_oneshot_mods(i2c_buffer->oneshot_mods);
-# endif
-# endif
-
-# if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
- memcpy((void *)i2c_buffer->led_matrix, (void *)led_matrix_eeconfig, sizeof(i2c_buffer->led_matrix));
- led_matrix_set_suspend_state(i2c_buffer->led_suspend_state);
-# endif
-# if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
- memcpy((void *)i2c_buffer->rgb_matrix, (void *)rgb_matrix_config, sizeof(i2c_buffer->rgb_matrix));
- rgb_matrix_set_suspend_state(i2c_buffer->rgb_suspend_state);
-# endif
-}
-
-void transport_master_init(void) { i2c_init(); }
-
-void transport_slave_init(void) { i2c_slave_init(SLAVE_I2C_ADDRESS); }
-
-#else // USE_SERIAL
+#else // USE_I2C
# include "serial.h"
-typedef struct _Serial_s2m_buffer_t {
- // TODO: if MATRIX_COLS > 8 change to uint8_t packed_matrix[] for pack/unpack
- matrix_row_t smatrix[ROWS_PER_HAND];
-
-# ifdef ENCODER_ENABLE
- uint8_t encoder_state[NUMBER_OF_ENCODERS];
-# endif
-
-} Serial_s2m_buffer_t;
-
-typedef struct _Serial_m2s_buffer_t {
-# ifdef SPLIT_MODS_ENABLE
- uint8_t real_mods;
- uint8_t weak_mods;
-# ifndef NO_ACTION_ONESHOT
- uint8_t oneshot_mods;
-# endif
-# endif
-# ifndef DISABLE_SYNC_TIMER
- uint32_t sync_timer;
-# endif
-# ifdef SPLIT_TRANSPORT_MIRROR
- matrix_row_t mmatrix[ROWS_PER_HAND];
-# endif
-# ifdef BACKLIGHT_ENABLE
- uint8_t backlight_level;
-# endif
-# ifdef WPM_ENABLE
- uint8_t current_wpm;
-# endif
-# if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
- led_eeconfig_t led_matrix;
- bool led_suspend_state;
-# endif
-# if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
- rgb_config_t rgb_matrix;
- bool rgb_suspend_state;
-# endif
-} Serial_m2s_buffer_t;
-
-# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
-// When MCUs on both sides drive their respective RGB LED chains,
-// it is necessary to synchronize, so it is necessary to communicate RGB
-// information. In that case, define RGBLIGHT_SPLIT with info on the number
-// of LEDs on each half.
-//
-// Otherwise, if the master side MCU drives both sides RGB LED chains,
-// there is no need to communicate.
-
-typedef struct _Serial_rgblight_t {
- rgblight_syncinfo_t rgblight_sync;
-} Serial_rgblight_t;
+static split_shared_memory_t shared_memory;
+split_shared_memory_t *const split_shmem = &shared_memory;
-volatile Serial_rgblight_t serial_rgblight = {};
-uint8_t volatile status_rgblight = 0;
-# endif
-
-volatile Serial_s2m_buffer_t serial_s2m_buffer = {};
-volatile Serial_m2s_buffer_t serial_m2s_buffer = {};
-uint8_t volatile status0 = 0;
-
-enum serial_transaction_id {
- GET_SLAVE_MATRIX = 0,
-# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
- PUT_RGBLIGHT,
-# endif
-};
-
-SSTD_t transactions[] = {
- [GET_SLAVE_MATRIX] =
- {
- (uint8_t *)&status0,
- sizeof(serial_m2s_buffer),
- (uint8_t *)&serial_m2s_buffer,
- sizeof(serial_s2m_buffer),
- (uint8_t *)&serial_s2m_buffer,
- },
-# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
- [PUT_RGBLIGHT] =
- {
- (uint8_t *)&status_rgblight, sizeof(serial_rgblight), (uint8_t *)&serial_rgblight, 0, NULL // no slave to master transfer
- },
-# endif
-};
-
-void transport_master_init(void) { soft_serial_initiator_init(transactions, TID_LIMIT(transactions)); }
-
-void transport_slave_init(void) { soft_serial_target_init(transactions, TID_LIMIT(transactions)); }
+void transport_master_init(void) { soft_serial_initiator_init(); }
+void transport_slave_init(void) { soft_serial_target_init(); }
-# if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
-
-// rgblight synchronization information communication.
-
-void transport_rgblight_master(void) {
- if (rgblight_get_change_flags()) {
- rgblight_get_syncinfo((rgblight_syncinfo_t *)&serial_rgblight.rgblight_sync);
- if (soft_serial_transaction(PUT_RGBLIGHT) == TRANSACTION_END) {
- rgblight_clear_change_flags();
- }
- }
-}
-
-void transport_rgblight_slave(void) {
- if (status_rgblight == TRANSACTION_ACCEPTED) {
- rgblight_update_sync((rgblight_syncinfo_t *)&serial_rgblight.rgblight_sync, false);
- status_rgblight = TRANSACTION_END;
+bool transport_execute_transaction(int8_t id, const void *initiator2target_buf, uint16_t initiator2target_length, void *target2initiator_buf, uint16_t target2initiator_length) {
+ split_transaction_desc_t *trans = &split_transaction_table[id];
+ if (initiator2target_length > 0) {
+ size_t len = trans->initiator2target_buffer_size < initiator2target_length ? trans->initiator2target_buffer_size : initiator2target_length;
+ memcpy(split_trans_initiator2target_buffer(trans), initiator2target_buf, len);
}
-}
-# else
-# define transport_rgblight_master()
-# define transport_rgblight_slave()
-# endif
-
-bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
-# ifndef SERIAL_USE_MULTI_TRANSACTION
- if (soft_serial_transaction() != TRANSACTION_END) {
- return false;
- }
-# else
- transport_rgblight_master();
- if (soft_serial_transaction(GET_SLAVE_MATRIX) != TRANSACTION_END) {
+ if (soft_serial_transaction(id) != TRANSACTION_END) {
return false;
}
-# endif
- // TODO: if MATRIX_COLS > 8 change to unpack()
- for (int i = 0; i < ROWS_PER_HAND; ++i) {
- slave_matrix[i] = serial_s2m_buffer.smatrix[i];
-# ifdef SPLIT_TRANSPORT_MIRROR
- serial_m2s_buffer.mmatrix[i] = master_matrix[i];
-# endif
+ if (target2initiator_length > 0) {
+ size_t len = trans->target2initiator_buffer_size < target2initiator_length ? trans->target2initiator_buffer_size : target2initiator_length;
+ memcpy(target2initiator_buf, split_trans_target2initiator_buffer(trans), len);
}
-# ifdef BACKLIGHT_ENABLE
- // Write backlight level for slave to read
- serial_m2s_buffer.backlight_level = is_backlight_enabled() ? get_backlight_level() : 0;
-# endif
-
-# ifdef ENCODER_ENABLE
- encoder_update_raw((uint8_t *)serial_s2m_buffer.encoder_state);
-# endif
-
-# ifdef WPM_ENABLE
- // Write wpm to slave
- serial_m2s_buffer.current_wpm = get_current_wpm();
-# endif
-
-# ifdef SPLIT_MODS_ENABLE
- serial_m2s_buffer.real_mods = get_mods();
- serial_m2s_buffer.weak_mods = get_weak_mods();
-# ifndef NO_ACTION_ONESHOT
- serial_m2s_buffer.oneshot_mods = get_oneshot_mods();
-# endif
-# endif
-
-# if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
- serial_m2s_buffer.led_matrix = led_matrix_eeconfig;
- serial_m2s_buffer.led_suspend_state = led_matrix_get_suspend_state();
-# endif
-# if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
- serial_m2s_buffer.rgb_matrix = rgb_matrix_config;
- serial_m2s_buffer.rgb_suspend_state = rgb_matrix_get_suspend_state();
-# endif
-
-# ifndef DISABLE_SYNC_TIMER
- serial_m2s_buffer.sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET;
-# endif
return true;
}
-void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
- transport_rgblight_slave();
-# ifndef DISABLE_SYNC_TIMER
- sync_timer_update(serial_m2s_buffer.sync_timer);
-# endif
-
- // TODO: if MATRIX_COLS > 8 change to pack()
- for (int i = 0; i < ROWS_PER_HAND; ++i) {
- serial_s2m_buffer.smatrix[i] = slave_matrix[i];
-# ifdef SPLIT_TRANSPORT_MIRROR
- master_matrix[i] = serial_m2s_buffer.mmatrix[i];
-# endif
- }
-# ifdef BACKLIGHT_ENABLE
- backlight_set(serial_m2s_buffer.backlight_level);
-# endif
-
-# ifdef ENCODER_ENABLE
- encoder_state_raw((uint8_t *)serial_s2m_buffer.encoder_state);
-# endif
+#endif // USE_I2C
-# ifdef WPM_ENABLE
- set_current_wpm(serial_m2s_buffer.current_wpm);
-# endif
-
-# ifdef SPLIT_MODS_ENABLE
- set_mods(serial_m2s_buffer.real_mods);
- set_weak_mods(serial_m2s_buffer.weak_mods);
-# ifndef NO_ACTION_ONESHOT
- set_oneshot_mods(serial_m2s_buffer.oneshot_mods);
-# endif
-# endif
-
-# if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
- led_matrix_eeconfig = serial_m2s_buffer.led_matrix;
- led_matrix_set_suspend_state(serial_m2s_buffer.led_suspend_state);
-# endif
-# if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
- rgb_matrix_config = serial_m2s_buffer.rgb_matrix;
- rgb_matrix_set_suspend_state(serial_m2s_buffer.rgb_suspend_state);
-# endif
-}
+bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { return transactions_master(master_matrix, slave_matrix); }
-#endif
+void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { transactions_slave(master_matrix, slave_matrix); } \ No newline at end of file
diff --git a/quantum/split_common/transport.h b/quantum/split_common/transport.h
index a9f66301bf..2e07f6b25c 100644
--- a/quantum/split_common/transport.h
+++ b/quantum/split_common/transport.h
@@ -1,10 +1,175 @@
+/* Copyright 2021 QMK
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
#pragma once
+#include "stdint.h"
+#include "stdbool.h"
+
+#include "progmem.h"
+#include "action_layer.h"
#include "matrix.h"
+#ifndef RPC_M2S_BUFFER_SIZE
+# define RPC_M2S_BUFFER_SIZE 32
+#endif // RPC_M2S_BUFFER_SIZE
+
+#ifndef RPC_S2M_BUFFER_SIZE
+# define RPC_S2M_BUFFER_SIZE 32
+#endif // RPC_S2M_BUFFER_SIZE
+
void transport_master_init(void);
void transport_slave_init(void);
// returns false if valid data not received from slave
bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]);
void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]);
+
+bool transport_execute_transaction(int8_t id, const void *initiator2target_buf, uint16_t initiator2target_length, void *target2initiator_buf, uint16_t target2initiator_length);
+
+#ifdef ENCODER_ENABLE
+# include "encoder.h"
+# define NUMBER_OF_ENCODERS (sizeof((pin_t[])ENCODERS_PAD_A) / sizeof(pin_t))
+#endif // ENCODER_ENABLE
+
+#ifdef BACKLIGHT_ENABLE
+# include "backlight.h"
+#endif // BACKLIGHT_ENABLE
+
+#ifdef RGBLIGHT_ENABLE
+# include "rgblight.h"
+#endif // RGBLIGHT_ENABLE
+
+typedef struct _split_slave_matrix_sync_t {
+ uint8_t checksum;
+ matrix_row_t matrix[(MATRIX_ROWS) / 2];
+} split_slave_matrix_sync_t;
+
+#ifdef SPLIT_TRANSPORT_MIRROR
+typedef struct _split_master_matrix_sync_t {
+ matrix_row_t matrix[(MATRIX_ROWS) / 2];
+} split_master_matrix_sync_t;
+#endif // SPLIT_TRANSPORT_MIRROR
+
+#ifdef ENCODER_ENABLE
+typedef struct _split_slave_encoder_sync_t {
+ uint8_t checksum;
+ uint8_t state[NUMBER_OF_ENCODERS];
+} split_slave_encoder_sync_t;
+#endif // ENCODER_ENABLE
+
+#if !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
+typedef struct _split_layers_sync_t {
+ layer_state_t layer_state;
+ layer_state_t default_layer_state;
+} split_layers_sync_t;
+#endif // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
+
+#if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
+# include "led_matrix.h"
+
+typedef struct _led_matrix_sync_t {
+ led_eeconfig_t led_matrix;
+ bool led_suspend_state;
+} led_matrix_sync_t;
+#endif // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
+
+#if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
+# include "rgb_matrix.h"
+
+typedef struct _rgb_matrix_sync_t {
+ rgb_config_t rgb_matrix;
+ bool rgb_suspend_state;
+} rgb_matrix_sync_t;
+#endif // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
+
+#ifdef SPLIT_MODS_ENABLE
+typedef struct _split_mods_sync_t {
+ uint8_t real_mods;
+ uint8_t weak_mods;
+# ifndef NO_ACTION_ONESHOT
+ uint8_t oneshot_mods;
+# endif // NO_ACTION_ONESHOT
+} split_mods_sync_t;
+#endif // SPLIT_MODS_ENABLE
+
+#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
+typedef struct _rpc_sync_info_t {
+ int8_t transaction_id;
+ uint8_t m2s_length;
+ uint8_t s2m_length;
+} rpc_sync_info_t;
+#endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
+
+typedef struct _split_shared_memory_t {
+#ifdef USE_I2C
+ int8_t transaction_id;
+#endif // USE_I2C
+
+ split_slave_matrix_sync_t smatrix;
+
+#ifdef SPLIT_TRANSPORT_MIRROR
+ split_master_matrix_sync_t mmatrix;
+#endif // SPLIT_TRANSPORT_MIRROR
+
+#ifdef ENCODER_ENABLE
+ split_slave_encoder_sync_t encoders;
+#endif // ENCODER_ENABLE
+
+#ifndef DISABLE_SYNC_TIMER
+ uint32_t sync_timer;
+#endif // DISABLE_SYNC_TIMER
+
+#if !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
+ split_layers_sync_t layers;
+#endif // !defined(NO_ACTION_LAYER) && defined(SPLIT_LAYER_STATE_ENABLE)
+
+#ifdef SPLIT_LED_STATE_ENABLE
+ uint8_t led_state;
+#endif // SPLIT_LED_STATE_ENABLE
+
+#ifdef SPLIT_MODS_ENABLE
+ split_mods_sync_t mods;
+#endif // SPLIT_MODS_ENABLE
+
+#ifdef BACKLIGHT_ENABLE
+ uint8_t backlight_level;
+#endif // BACKLIGHT_ENABLE
+
+#if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
+ rgblight_syncinfo_t rgblight_sync;
+#endif // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
+
+#if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
+ led_matrix_sync_t led_matrix_sync;
+#endif // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
+
+#if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
+ rgb_matrix_sync_t rgb_matrix_sync;
+#endif // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
+
+#if defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
+ uint8_t current_wpm;
+#endif // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
+
+#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
+ rpc_sync_info_t rpc_info;
+ uint8_t rpc_m2s_buffer[RPC_M2S_BUFFER_SIZE];
+ uint8_t rpc_s2m_buffer[RPC_S2M_BUFFER_SIZE];
+#endif // defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
+} split_shared_memory_t;
+
+extern split_shared_memory_t *const split_shmem; \ No newline at end of file
diff --git a/testlist.mk b/testlist.mk
index 0d7609b9f0..d256f4c815 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/debounce/tests/testlist.mk
include $(ROOT_DIR)/quantum/sequencer/tests/testlist.mk
include $(ROOT_DIR)/quantum/serial_link/tests/testlist.mk
diff --git a/tmk_core/avr.mk b/tmk_core/avr.mk
index eb934ffe60..b787e77ece 100644
--- a/tmk_core/avr.mk
+++ b/tmk_core/avr.mk
@@ -301,7 +301,7 @@ ifneq ($(strip $(BOOTLOADER)), qmk-dfu)
endif
make -C lib/lufa/Bootloaders/DFU/ clean
$(QMK_BIN) generate-dfu-header --quiet --keyboard $(KEYBOARD) --output lib/lufa/Bootloaders/DFU/Keyboard.h
- $(eval MAX_SIZE=$(shell n=`$(CC) -E -mmcu=$(MCU) $(CFLAGS) $(OPT_DEFS) tmk_core/common/avr/bootloader_size.c 2> /dev/null | sed -ne 's/\r//;/^#/n;/^AVR_SIZE:/,$${s/^AVR_SIZE: //;p;}'` && echo $$(($$n)) || echo 0))
+ $(eval MAX_SIZE=$(shell n=`$(CC) -E -mmcu=$(MCU) -D__ASSEMBLER__ $(CFLAGS) $(OPT_DEFS) tmk_core/common/avr/bootloader_size.c 2> /dev/null | sed -ne 's/\r//;/^#/n;/^AVR_SIZE:/,$${s/^AVR_SIZE: //;p;}'` && echo $$(($$n)) || echo 0))
$(eval PROGRAM_SIZE_KB=$(shell n=`expr $(MAX_SIZE) / 1024` && echo $$(($$n)) || echo 0))
$(eval BOOT_SECTION_SIZE_KB=$(shell n=`expr $(BOOTLOADER_SIZE) / 1024` && echo $$(($$n)) || echo 0))
$(eval FLASH_SIZE_KB=$(shell n=`expr $(PROGRAM_SIZE_KB) + $(BOOT_SECTION_SIZE_KB)` && echo $$(($$n)) || echo 0))
diff --git a/tmk_core/chibios.mk b/tmk_core/chibios.mk
index 97299b7d32..7eda360460 100644
--- a/tmk_core/chibios.mk
+++ b/tmk_core/chibios.mk
@@ -390,8 +390,10 @@ ifndef TEENSY_LOADER_CLI
endif
endif
+TEENSY_LOADER_CLI_MCU ?= $(MCU_LDSCRIPT)
+
define EXEC_TEENSY
- $(TEENSY_LOADER_CLI) -mmcu=$(MCU_LDSCRIPT) -w -v $(BUILD_DIR)/$(TARGET).hex
+ $(TEENSY_LOADER_CLI) -mmcu=$(TEENSY_LOADER_CLI_MCU) -w -v $(BUILD_DIR)/$(TARGET).hex
endef
teensy: $(BUILD_DIR)/$(TARGET).hex cpfirmware sizeafter
@@ -408,6 +410,8 @@ else ifeq ($(strip $(BOOTLOADER)),kiibohd)
$(call EXEC_DFU_UTIL)
else ifeq ($(strip $(MCU_FAMILY)),KINETIS)
$(call EXEC_TEENSY)
+else ifeq ($(strip $(MCU_FAMILY)),MIMXRT1062)
+ $(call EXEC_TEENSY)
else ifeq ($(strip $(MCU_FAMILY)),STM32)
$(call EXEC_DFU_UTIL)
else
diff --git a/tmk_core/common/arm_atsam/_timer.h b/tmk_core/common/arm_atsam/_timer.h
new file mode 100644
index 0000000000..77402b612a
--- /dev/null
+++ b/tmk_core/common/arm_atsam/_timer.h
@@ -0,0 +1,19 @@
+/* Copyright 2021 Simon Arlott
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#pragma once
+
+// The platform is 32-bit, so prefer 32-bit timers to avoid overflow
+#define FAST_TIMER_T_SIZE 32
diff --git a/tmk_core/common/avr/_timer.h b/tmk_core/common/avr/_timer.h
new file mode 100644
index 0000000000..b81e0f68b7
--- /dev/null
+++ b/tmk_core/common/avr/_timer.h
@@ -0,0 +1,19 @@
+/* Copyright 2021 Simon Arlott
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#pragma once
+
+// The platform is 8-bit, so prefer 16-bit timers to reduce code size
+#define FAST_TIMER_T_SIZE 16
diff --git a/tmk_core/common/avr/gpio.h b/tmk_core/common/avr/gpio.h
index 231556c29c..e9be68491d 100644
--- a/tmk_core/common/avr/gpio.h
+++ b/tmk_core/common/avr/gpio.h
@@ -20,6 +20,8 @@
typedef uint8_t pin_t;
+/* Operation of GPIO by pin. */
+
#define setPinInput(pin) (DDRx_ADDRESS(pin) &= ~_BV((pin)&0xF), PORTx_ADDRESS(pin) &= ~_BV((pin)&0xF))
#define setPinInputHigh(pin) (DDRx_ADDRESS(pin) &= ~_BV((pin)&0xF), PORTx_ADDRESS(pin) |= _BV((pin)&0xF))
#define setPinInputLow(pin) _Static_assert(0, "AVR processors cannot implement an input as pull low")
@@ -32,3 +34,16 @@ typedef uint8_t pin_t;
#define readPin(pin) ((bool)(PINx_ADDRESS(pin) & _BV((pin)&0xF)))
#define togglePin(pin) (PORTx_ADDRESS(pin) ^= _BV((pin)&0xF))
+
+/* Operation of GPIO by port. */
+
+typedef uint8_t port_data_t;
+
+#define readPort(port) PINx_ADDRESS(port)
+
+#define setPortBitInput(port, bit) (DDRx_ADDRESS(port) &= ~_BV((bit)&0xF), PORTx_ADDRESS(port) &= ~_BV((bit)&0xF))
+#define setPortBitInputHigh(port, bit) (DDRx_ADDRESS(port) &= ~_BV((bit)&0xF), PORTx_ADDRESS(port) |= _BV((bit)&0xF))
+#define setPortBitOutput(port, bit) (DDRx_ADDRESS(port) |= _BV((bit)&0xF))
+
+#define writePortBitLow(port, bit) (PORTx_ADDRESS(port) &= ~_BV((bit)&0xF))
+#define writePortBitHigh(port, bit) (PORTx_ADDRESS(port) |= _BV((bit)&0xF))
diff --git a/tmk_core/common/chibios/_timer.h b/tmk_core/common/chibios/_timer.h
new file mode 100644
index 0000000000..77402b612a
--- /dev/null
+++ b/tmk_core/common/chibios/_timer.h
@@ -0,0 +1,19 @@
+/* Copyright 2021 Simon Arlott
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#pragma once
+
+// The platform is 32-bit, so prefer 32-bit timers to avoid overflow
+#define FAST_TIMER_T_SIZE 32
diff --git a/tmk_core/common/chibios/bootloader.c b/tmk_core/common/chibios/bootloader.c
index 11f7abf432..76d52ea608 100644
--- a/tmk_core/common/chibios/bootloader.c
+++ b/tmk_core/common/chibios/bootloader.c
@@ -95,7 +95,7 @@ void enter_bootloader_mode_if_requested(void) {
}
}
-#elif defined(KL2x) || defined(K20x) || defined(MK66F18) // STM32_BOOTLOADER_DUAL_BANK // STM32_BOOTLOADER_ADDRESS
+#elif defined(KL2x) || defined(K20x) || defined(MK66F18) || defined(MIMXRT1062) // STM32_BOOTLOADER_DUAL_BANK // STM32_BOOTLOADER_ADDRESS
/* Kinetis */
# if defined(BOOTLOADER_KIIBOHD)
diff --git a/tmk_core/common/chibios/gpio.h b/tmk_core/common/chibios/gpio.h
index 5d0e142abc..4d057f1cab 100644
--- a/tmk_core/common/chibios/gpio.h
+++ b/tmk_core/common/chibios/gpio.h
@@ -20,6 +20,8 @@
typedef ioline_t pin_t;
+/* Operation of GPIO by pin. */
+
#define setPinInput(pin) palSetLineMode(pin, PAL_MODE_INPUT)
#define setPinInputHigh(pin) palSetLineMode(pin, PAL_MODE_INPUT_PULLUP)
#define setPinInputLow(pin) palSetLineMode(pin, PAL_MODE_INPUT_PULLDOWN)
@@ -32,3 +34,17 @@ typedef ioline_t pin_t;
#define readPin(pin) palReadLine(pin)
#define togglePin(pin) palToggleLine(pin)
+
+/* Operation of GPIO by port. */
+
+typedef uint16_t port_data_t;
+
+#define readPort(pin) palReadPort(PAL_PORT(pin))
+
+#define setPortBitInput(pin, bit) palSetPadMode(PAL_PORT(pin), bit, PAL_MODE_INPUT)
+#define setPortBitInputHigh(pin, bit) palSetPadMode(PAL_PORT(pin), bit, PAL_MODE_INPUT_PULLUP)
+#define setPortBitInputLow(pin, bit) palSetPadMode(PAL_PORT(pin), bit, PAL_MODE_INPUT_PULLDOWN)
+#define setPortBitOutput(pin, bit) palSetPadMode(PAL_PORT(pin), bit, PAL_MODE_OUTPUT_PUSHPULL)
+
+#define writePortBitLow(pin, bit) palClearLine(PAL_LINE(PAL_PORT(pin), bit))
+#define writePortBitHigh(pin, bit) palSetLine(PAL_LINE(PAL_PORT(pin), bit))
diff --git a/tmk_core/common/host.c b/tmk_core/common/host.c
index e7d92cfac6..a8b391e893 100644
--- a/tmk_core/common/host.c
+++ b/tmk_core/common/host.c
@@ -17,6 +17,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <stdint.h>
//#include <avr/interrupt.h>
+#include "keyboard.h"
#include "keycode.h"
#include "host.h"
#include "util.h"
@@ -35,15 +36,20 @@ void host_set_driver(host_driver_t *d) { driver = d; }
host_driver_t *host_get_driver(void) { return driver; }
+#ifdef SPLIT_KEYBOARD
+uint8_t split_led_state = 0;
+void set_split_host_keyboard_leds(uint8_t led_state) { split_led_state = led_state; }
+#endif
+
uint8_t host_keyboard_leds(void) {
+#ifdef SPLIT_KEYBOARD
+ if (!is_keyboard_master()) return split_led_state;
+#endif
if (!driver) return 0;
return (*driver->keyboard_leds)();
}
-led_t host_keyboard_led_state(void) {
- if (!driver) return (led_t){0};
- return (led_t)((*driver->keyboard_leds)());
-}
+led_t host_keyboard_led_state(void) { return (led_t)host_keyboard_leds(); }
/* send report */
void host_keyboard_send(report_keyboard_t *report) {
diff --git a/tmk_core/common/keyboard.c b/tmk_core/common/keyboard.c
index 3d6092e71c..28fa97bc8f 100644
--- a/tmk_core/common/keyboard.c
+++ b/tmk_core/common/keyboard.c
@@ -85,6 +85,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef OLED_DRIVER_ENABLE
# include "oled_driver.h"
#endif
+#ifdef ST7565_ENABLE
+# include "st7565.h"
+#endif
#ifdef VELOCIKEY_ENABLE
# include "velocikey.h"
#endif
@@ -100,6 +103,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef EEPROM_DRIVER
# include "eeprom_driver.h"
#endif
+#if defined(CRC_ENABLE)
+# include "crc.h"
+#endif
static uint32_t last_input_modification_time = 0;
uint32_t last_input_activity_time(void) { return last_input_modification_time; }
@@ -297,6 +303,9 @@ void keyboard_init(void) {
timer_init();
sync_timer_init();
matrix_init();
+#if defined(CRC_ENABLE)
+ crc_init();
+#endif
#ifdef VIA_ENABLE
via_init();
#endif
@@ -306,6 +315,9 @@ void keyboard_init(void) {
#ifdef OLED_DRIVER_ENABLE
oled_init(OLED_ROTATION_0);
#endif
+#ifdef ST7565_ENABLE
+ st7565_init(DISPLAY_ROTATION_0);
+#endif
#ifdef PS2_MOUSE_ENABLE
ps2_mouse_init();
#endif
@@ -470,6 +482,18 @@ MATRIX_LOOP_END:
# endif
#endif
+#ifdef ST7565_ENABLE
+ st7565_task();
+# ifndef ST7565_DISABLE_TIMEOUT
+ // Wake up display if user is using those fabulous keys or spinning those encoders!
+# ifdef ENCODER_ENABLE
+ if (matrix_changed || encoders_changed) st7565_on();
+# else
+ if (matrix_changed) st7565_on();
+# endif
+# endif
+#endif
+
#ifdef MOUSEKEY_ENABLE
// mousekey repeat & acceleration
mousekey_task();
diff --git a/tmk_core/common/sync_timer.c b/tmk_core/common/sync_timer.c
index de24b463b6..68b92d8b43 100644
--- a/tmk_core/common/sync_timer.c
+++ b/tmk_core/common/sync_timer.c
@@ -26,7 +26,7 @@ SOFTWARE.
#include "sync_timer.h"
#include "keyboard.h"
-#if defined(SPLIT_KEYBOARD) && !defined(DISABLE_SYNC_TIMER)
+#if (defined(SPLIT_KEYBOARD) || defined(SERIAL_LINK_ENABLE)) && !defined(DISABLE_SYNC_TIMER)
volatile int32_t sync_timer_ms;
void sync_timer_init(void) { sync_timer_ms = 0; }
diff --git a/tmk_core/common/sync_timer.h b/tmk_core/common/sync_timer.h
index 9ddef45bb2..744e2b50d5 100644
--- a/tmk_core/common/sync_timer.h
+++ b/tmk_core/common/sync_timer.h
@@ -32,7 +32,7 @@ SOFTWARE.
extern "C" {
#endif
-#if defined(SPLIT_KEYBOARD) && !defined(DISABLE_SYNC_TIMER)
+#if (defined(SPLIT_KEYBOARD) || defined(SERIAL_LINK_ENABLE)) && !defined(DISABLE_SYNC_TIMER)
void sync_timer_init(void);
void sync_timer_update(uint32_t time);
uint16_t sync_timer_read(void);
diff --git a/tmk_core/common/timer.h b/tmk_core/common/timer.h
index 58f637dd93..928811a2b7 100644
--- a/tmk_core/common/timer.h
+++ b/tmk_core/common/timer.h
@@ -1,5 +1,6 @@
/*
Copyright 2011 Jun Wako <wakojun@gmail.com>
+Copyright 2021 Simon Arlott
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
@@ -17,13 +18,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
+#if __has_include_next("_timer.h")
+# include_next "_timer.h" /* Include the platform's _timer.h */
+#endif
+
#include <stdint.h>
#include <stdbool.h>
-#if defined(__AVR__)
-# include "avr/timer_avr.h"
-#endif
-
#define TIMER_DIFF(a, b, max) ((max == UINT8_MAX) ? ((uint8_t)((a) - (b))) : ((max == UINT16_MAX) ? ((uint16_t)((a) - (b))) : ((max == UINT32_MAX) ? ((uint32_t)((a) - (b))) : ((a) >= (b) ? (a) - (b) : (max) + 1 - (b) + (a)))))
#define TIMER_DIFF_8(a, b) TIMER_DIFF(a, b, UINT8_MAX)
#define TIMER_DIFF_16(a, b) TIMER_DIFF(a, b, UINT16_MAX)
@@ -47,6 +48,21 @@ uint32_t timer_elapsed32(uint32_t last);
#define timer_expired(current, future) ((uint16_t)(current - future) < UINT16_MAX / 2)
#define timer_expired32(current, future) ((uint32_t)(current - future) < UINT32_MAX / 2)
+// Use an appropriate timer integer size based on architecture (16-bit will overflow sooner)
+#if FAST_TIMER_T_SIZE < 32
+# define TIMER_DIFF_FAST(a, b) TIMER_DIFF_16(a, b)
+# define timer_expired_fast(current, future) timer_expired(current, future)
+typedef uint16_t fast_timer_t;
+fast_timer_t inline timer_read_fast(void) { return timer_read(); }
+fast_timer_t inline timer_elapsed_fast(fast_timer_t last) { return timer_elapsed(last); }
+#else
+# define TIMER_DIFF_FAST(a, b) TIMER_DIFF_32(a, b)
+# define timer_expired_fast(current, future) timer_expired32(current, future)
+typedef uint32_t fast_timer_t;
+fast_timer_t inline timer_read_fast(void) { return timer_read32(); }
+fast_timer_t inline timer_elapsed_fast(fast_timer_t last) { return timer_elapsed32(last); }
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/tmk_core/protocol/chibios/usb_main.c b/tmk_core/protocol/chibios/usb_main.c
index d04302acae..407b8ea75d 100644
--- a/tmk_core/protocol/chibios/usb_main.c
+++ b/tmk_core/protocol/chibios/usb_main.c
@@ -903,7 +903,8 @@ static void send_extra(uint8_t report_id, uint16_t data) {
return;
}
- report_extra_t report = {.report_id = report_id, .usage = data};
+ static report_extra_t report;
+ report = (report_extra_t){.report_id = report_id, .usage = data};
usbStartTransmitI(&USB_DRIVER, SHARED_IN_EPNUM, (uint8_t *)&report, sizeof(report_extra_t));
osalSysUnlock();
@@ -1051,45 +1052,44 @@ void virtser_task(void) {
#ifdef JOYSTICK_ENABLE
void send_joystick_packet(joystick_t *joystick) {
- joystick_report_t rep = {
+ static joystick_report_t rep;
+ rep = (joystick_report_t) {
# if JOYSTICK_AXES_COUNT > 0
.axes =
- {
- joystick->axes[0],
+ { joystick->axes[0],
# if JOYSTICK_AXES_COUNT >= 2
- joystick->axes[1],
+ joystick->axes[1],
# endif
# if JOYSTICK_AXES_COUNT >= 3
- joystick->axes[2],
+ joystick->axes[2],
# endif
# if JOYSTICK_AXES_COUNT >= 4
- joystick->axes[3],
+ joystick->axes[3],
# endif
# if JOYSTICK_AXES_COUNT >= 5
- joystick->axes[4],
+ joystick->axes[4],
# endif
# if JOYSTICK_AXES_COUNT >= 6
- joystick->axes[5],
+ joystick->axes[5],
# endif
- },
+ },
# endif // JOYSTICK_AXES_COUNT>0
# if JOYSTICK_BUTTON_COUNT > 0
- .buttons =
- {
- joystick->buttons[0],
+ .buttons = {
+ joystick->buttons[0],
# if JOYSTICK_BUTTON_COUNT > 8
- joystick->buttons[1],
+ joystick->buttons[1],
# endif
# if JOYSTICK_BUTTON_COUNT > 16
- joystick->buttons[2],
+ joystick->buttons[2],
# endif
# if JOYSTICK_BUTTON_COUNT > 24
- joystick->buttons[3],
+ joystick->buttons[3],
# endif
- }
+ }
# endif // JOYSTICK_BUTTON_COUNT>0
};
diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c
index 63619fdb3b..4ac079e168 100644
--- a/tmk_core/protocol/lufa/lufa.c
+++ b/tmk_core/protocol/lufa/lufa.c
@@ -314,45 +314,44 @@ static void Console_Task(void) {
void send_joystick_packet(joystick_t *joystick) {
uint8_t timeout = 255;
- joystick_report_t r = {
+ static joystick_report_t;
+ r = (joystick_report_t) {
# if JOYSTICK_AXES_COUNT > 0
.axes =
- {
- joystick->axes[0],
+ { joystick->axes[0],
# if JOYSTICK_AXES_COUNT >= 2
- joystick->axes[1],
+ joystick->axes[1],
# endif
# if JOYSTICK_AXES_COUNT >= 3
- joystick->axes[2],
+ joystick->axes[2],
# endif
# if JOYSTICK_AXES_COUNT >= 4
- joystick->axes[3],
+ joystick->axes[3],
# endif
# if JOYSTICK_AXES_COUNT >= 5
- joystick->axes[4],
+ joystick->axes[4],
# endif
# if JOYSTICK_AXES_COUNT >= 6
- joystick->axes[5],
+ joystick->axes[5],
# endif
- },
+ },
# endif // JOYSTICK_AXES_COUNT>0
# if JOYSTICK_BUTTON_COUNT > 0
- .buttons =
- {
- joystick->buttons[0],
+ .buttons = {
+ joystick->buttons[0],
# if JOYSTICK_BUTTON_COUNT > 8
- joystick->buttons[1],
+ joystick->buttons[1],
# endif
# if JOYSTICK_BUTTON_COUNT > 16
- joystick->buttons[2],
+ joystick->buttons[2],
# endif
# if JOYSTICK_BUTTON_COUNT > 24
- joystick->buttons[3],
+ joystick->buttons[3],
# endif
- }
+ }
# endif // JOYSTICK_BUTTON_COUNT>0
};
@@ -768,7 +767,8 @@ static void send_extra(uint8_t report_id, uint16_t data) {
if (USB_DeviceState != DEVICE_STATE_Configured) return;
- report_extra_t r = {.report_id = report_id, .usage = data};
+ static report_extra_t r;
+ r = (report_extra_t){.report_id = report_id, .usage = data};
Endpoint_SelectEndpoint(SHARED_IN_EPNUM);
/* Check if write ready for a polling interval around 10ms */
diff --git a/tmk_core/protocol/usb_descriptor.c b/tmk_core/protocol/usb_descriptor.c
index ba7760f283..c88aceb6ed 100644
--- a/tmk_core/protocol/usb_descriptor.c
+++ b/tmk_core/protocol/usb_descriptor.c
@@ -351,7 +351,7 @@ const USB_Descriptor_Device_t PROGMEM DeviceDescriptor = {
.Size = sizeof(USB_Descriptor_Device_t),
.Type = DTYPE_Device
},
- .USBSpecification = VERSION_BCD(1, 1, 0),
+ .USBSpecification = VERSION_BCD(2, 0, 0),
#if VIRTSER_ENABLE
.Class = USB_CSCP_IADDeviceClass,
diff --git a/tmk_core/protocol/vusb/vusb.c b/tmk_core/protocol/vusb/vusb.c
index 9362fbde78..876a313786 100644
--- a/tmk_core/protocol/vusb/vusb.c
+++ b/tmk_core/protocol/vusb/vusb.c
@@ -272,7 +272,8 @@ static void send_extra(uint8_t report_id, uint16_t data) {
last_id = report_id;
last_data = data;
- report_extra_t report = {.report_id = report_id, .usage = data};
+ static report_extra_t report;
+ report = (report_extra_t){.report_id = report_id, .usage = data};
if (usbInterruptIsReadyShared()) {
usbSetInterruptShared((void *)&report, sizeof(report_extra_t));
}
diff --git a/tmk_core/rules.mk b/tmk_core/rules.mk
index fc2dc68be2..597f7aa827 100644
--- a/tmk_core/rules.mk
+++ b/tmk_core/rules.mk
@@ -458,7 +458,7 @@ ifeq ($(findstring avr-gcc,$(CC)),avr-gcc)
SIZE_MARGIN = 1024
check-size:
- $(eval MAX_SIZE=$(shell n=`$(CC) -E -mmcu=$(MCU) $(CFLAGS) $(OPT_DEFS) tmk_core/common/avr/bootloader_size.c 2> /dev/null | sed -ne 's/\r//;/^#/n;/^AVR_SIZE:/,$${s/^AVR_SIZE: //;p;}'` && echo $$(($$n)) || echo 0))
+ $(eval MAX_SIZE=$(shell n=`$(CC) -E -mmcu=$(MCU) -D__ASSEMBLER__ $(CFLAGS) $(OPT_DEFS) tmk_core/common/avr/bootloader_size.c 2> /dev/null | sed -ne 's/\r//;/^#/n;/^AVR_SIZE:/,$${s/^AVR_SIZE: //;p;}'` && echo $$(($$n)) || echo 0))
$(eval CURRENT_SIZE=$(shell if [ -f $(BUILD_DIR)/$(TARGET).hex ]; then $(SIZE) --target=$(FORMAT) $(BUILD_DIR)/$(TARGET).hex | $(AWK) 'NR==2 {print $$4}'; else printf 0; fi))
$(eval FREE_SIZE=$(shell expr $(MAX_SIZE) - $(CURRENT_SIZE)))
$(eval OVER_SIZE=$(shell expr $(CURRENT_SIZE) - $(MAX_SIZE)))
diff --git a/users/bcat/config.h b/users/bcat/config.h
index 16188950e2..5bb93f3833 100644
--- a/users/bcat/config.h
+++ b/users/bcat/config.h
@@ -33,7 +33,7 @@
#if defined(RGB_MATRIX_ENABLE)
/* Turn off per-key RGB when the host goes to sleep. */
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true
+# define RGB_DISABLE_WHEN_USB_SUSPENDED
/* Keep per-key RGB increments consistent across keyboards. */
# undef RGB_MATRIX_HUE_STEP
diff --git a/users/bocaj/config.h b/users/bocaj/config.h
index 2a44aabfc4..ecfb09c6f9 100644
--- a/users/bocaj/config.h
+++ b/users/bocaj/config.h
@@ -28,7 +28,7 @@
// # define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (not recommened)
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
// # define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
// # define RGB_MATRIX_MAXIMUM_BRIGHTNESS 200 // limits maximum brightness of LEDs to 200 out of 255. If not defined maximum brightness is set to 255
// # define EECONFIG_RGB_MATRIX (uint32_t *)16
diff --git a/users/curry/config.h b/users/curry/config.h
index b982dab038..e3c0a103ef 100644
--- a/users/curry/config.h
+++ b/users/curry/config.h
@@ -17,7 +17,7 @@
#if defined(RGB_MATRIX_ENABLE)
# define RGB_MATRIX_KEYPRESSES
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true
+# define RGB_DISABLE_WHEN_USB_SUSPENDED
# define DISABLE_RGB_MATRIX_ALPHAS_MODS
# define DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
diff --git a/users/drashna/config.h b/users/drashna/config.h
index 5f7c32ff35..7964856892 100644
--- a/users/drashna/config.h
+++ b/users/drashna/config.h
@@ -65,7 +65,7 @@
// # define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (not recommened)
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
// # define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
-# define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+# define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
// # define RGB_MATRIX_MAXIMUM_BRIGHTNESS 200 // limits maximum brightness of LEDs to 200 out of 255. If not defined maximum brightness is set to 255
// # define EECONFIG_RGB_MATRIX (uint32_t *)16
diff --git a/users/spidey3/config.h b/users/spidey3/config.h
index 7062fde030..f5f5e07f0f 100644
--- a/users/spidey3/config.h
+++ b/users/spidey3/config.h
@@ -1,7 +1,7 @@
#pragma once
-#define LED_DISABLE_WHEN_USB_SUSPENDED true
-#define RGB_DISABLE_WHEN_USB_SUSPENDED true
+#define LED_DISABLE_WHEN_USB_SUSPENDED
+#define RGB_DISABLE_WHEN_USB_SUSPENDED
#define RGBLIGHT_LAYERS
#define RGBLIGHT_MAX_LAYERS 17
#define RGBLIGHT_LAYER_BLINK
diff --git a/users/tominabox1/config.h b/users/tominabox1/config.h
index 2a8c1e943d..004f58ab53 100644
--- a/users/tominabox1/config.h
+++ b/users/tominabox1/config.h
@@ -31,7 +31,7 @@
// RGB_Matrix settings
#ifdef RGB_MATRIX_ENABLE
#define RGB_MATRIX_KEYPRESSES // reacts to keypresses
- #define RGB_DISABLE_WHEN_USB_SUSPENDED true // turn off effects when suspended
+ #define RGB_DISABLE_WHEN_USB_SUSPENDED // turn off effects when suspended
#define RGB_MATRIX_LED_FLUSH_LIMIT 16 // limits in milliseconds how frequently an animation will update the LEDs. 16 (16ms) is equivalent to limiting to 60fps (increases keyboard responsiveness)
#define RGB_MATRIX_MAXIMUM_BRIGHTNESS 150 // limits maximum brightness of LEDs to 150 out of 255. Higher may cause the controller to crash.
#define RGB_MATRIX_HUE_STEP 8
diff --git a/util/update_chibios_mirror.sh b/util/update_chibios_mirror.sh
new file mode 100755
index 0000000000..3df689f54e
--- /dev/null
+++ b/util/update_chibios_mirror.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+################################
+# Configuration
+
+# The branches to mirror
+branches="trunk stable_20.3.x stable_21.6.x"
+
+# The tags to mirror
+tags="ver19.1.3 ver20.3.1 ver20.3.2 ver20.3.3 ver21.6.0"
+
+################################
+# Actions
+
+set -eEuo pipefail
+umask 022
+
+this_script="$(realpath "${BASH_SOURCE[0]}")"
+script_dir="$(realpath "$(dirname "$this_script")")"
+qmk_firmware_dir="$(realpath "$script_dir/../")"
+chibios_dir="$qmk_firmware_dir/lib/chibios"
+
+chibios_git_location=$(realpath "$chibios_dir/$(cat "$chibios_dir/.git" | awk '/gitdir:/ {print $2}')")
+chibios_git_config=$(realpath "$chibios_git_location/config")
+
+cd "$chibios_dir"
+
+if [[ -z "$(cat "$chibios_git_config" | grep '\[svn-remote "svn"\]')" ]] ; then
+ git svn init --stdlayout --prefix='svn/' http://svn.osdn.net/svnroot/chibios/
+fi
+
+if [[ -z "$(cat "$chibios_git_config" | grep '\[remote "qmk"\]')" ]] ; then
+ git remote add qmk git@github.com:qmk/ChibiOS.git
+ git remote set-url qmk git@github.com:qmk/ChibiOS.git --push
+fi
+
+echo "Updating remotes..."
+git fetch --all --tags --prune
+
+echo "Fetching latest from subversion..."
+git svn fetch
+
+echo "Updating branches..."
+for branch in $branches ; do
+ echo "Creating branch 'svn-mirror/$branch' from 'svn/$branch'..."
+ git branch -f svn-mirror/$branch svn/$branch \
+ && git push qmk svn-mirror/$branch
+done
+
+echo "Updating tags..."
+for tagname in $tags ; do
+ echo "Creating tag 'svn-mirror/$tagname' from 'svn/tags/$tagname'..."
+ GIT_COMMITTER_DATE="$(git log -n1 --pretty=format:'%ad' svn/tags/$tagname)" git tag -f -a -m "Tagging $tagname" svn-mirror/$tagname svn/tags/$tagname
+ git push qmk svn-mirror/$tagname
+done \ No newline at end of file