diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 42d377fe4a9..e04bcd080b1 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -56,7 +56,7 @@ jobs:
- name: Deploy
if: ${{ github.event_name == 'push' && github.repository == 'qmk/qmk_firmware' }}
- uses: JamesIves/github-pages-deploy-action@v4.6.8
+ uses: JamesIves/github-pages-deploy-action@v4.6.9
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: gh-pages
diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk
index cc13fbd3f73..86ced309029 100644
--- a/builddefs/common_features.mk
+++ b/builddefs/common_features.mk
@@ -129,13 +129,13 @@ ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes)
MOUSE_ENABLE := yes
VPATH += $(QUANTUM_DIR)/pointing_device
SRC += $(QUANTUM_DIR)/pointing_device/pointing_device.c
- SRC += $(QUANTUM_DIR)/pointing_device/pointing_device_drivers.c
SRC += $(QUANTUM_DIR)/pointing_device/pointing_device_auto_mouse.c
ifneq ($(strip $(POINTING_DEVICE_DRIVER)), custom)
SRC += drivers/sensors/$(strip $(POINTING_DEVICE_DRIVER)).c
OPT_DEFS += -DPOINTING_DEVICE_DRIVER_$(strip $(shell echo $(POINTING_DEVICE_DRIVER) | tr '[:lower:]' '[:upper:]'))
endif
OPT_DEFS += -DPOINTING_DEVICE_DRIVER_$(strip $(POINTING_DEVICE_DRIVER))
+ OPT_DEFS += -DPOINTING_DEVICE_DRIVER_NAME=$(strip $(POINTING_DEVICE_DRIVER))
ifeq ($(strip $(POINTING_DEVICE_DRIVER)), adns9800)
SPI_DRIVER_REQUIRED = yes
else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), analog_joystick)
@@ -215,7 +215,7 @@ else
COMMON_VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/flash
COMMON_VPATH += $(DRIVER_PATH)/flash
SRC += eeprom_driver.c eeprom_legacy_emulated_flash.c legacy_flash_ops.c
- else ifneq ($(filter $(MCU_SERIES),STM32F1xx STM32F3xx STM32F4xx STM32L4xx STM32G4xx WB32F3G71xx WB32FQ95xx GD32VF103),)
+ else ifneq ($(filter $(MCU_SERIES),STM32F1xx STM32F3xx STM32F4xx STM32L4xx STM32G4xx WB32F3G71xx WB32FQ95xx AT32F415 GD32VF103),)
# Wear-leveling EEPROM implementation, backed by MCU flash
OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_WEAR_LEVELING
SRC += eeprom_driver.c eeprom_wear_leveling.c
@@ -456,6 +456,10 @@ ifeq ($(strip $(RGB_MATRIX_ENABLE)), yes)
COMMON_VPATH += $(QUANTUM_DIR)/rgb_matrix/animations
COMMON_VPATH += $(QUANTUM_DIR)/rgb_matrix/animations/runners
POST_CONFIG_H += $(QUANTUM_DIR)/rgb_matrix/post_config.h
+
+ # TODO: Remove this
+ SRC += $(QUANTUM_DIR)/process_keycode/process_underglow.c
+
SRC += $(QUANTUM_DIR)/process_keycode/process_rgb_matrix.c
SRC += $(QUANTUM_DIR)/color.c
SRC += $(QUANTUM_DIR)/rgb_matrix/rgb_matrix.c
diff --git a/builddefs/docsgen/.vitepress/config.mts b/builddefs/docsgen/.vitepress/config.mts
index 54ecae2e86b..d2fe2886b21 100644
--- a/builddefs/docsgen/.vitepress/config.mts
+++ b/builddefs/docsgen/.vitepress/config.mts
@@ -39,8 +39,15 @@ export default defineConfig(({ mode }) => {
provider: "local",
},
+ editLink: {
+ pattern: 'https://github.com/qmk/qmk_firmware/edit/master/docs/:path'
+ },
+ lastUpdated: true,
+
sidebar: sidebar,
+ externalLinkIcon: true,
+
socialLinks: [
{ icon: { svg: '' }, link: "https://reddit.com/r/olkb" },
{ icon: "discord", link: "https://discord.gg/qmk" },
diff --git a/builddefs/generic_features.mk b/builddefs/generic_features.mk
index dc34a642307..f14f4408770 100644
--- a/builddefs/generic_features.mk
+++ b/builddefs/generic_features.mk
@@ -36,6 +36,7 @@ GENERIC_FEATURES = \
HAPTIC \
KEY_LOCK \
KEY_OVERRIDE \
+ LAYER_LOCK \
LEADER \
MAGIC \
MOUSEKEY \
diff --git a/data/constants/keycodes/keycodes_0.0.1_midi.hjson b/data/constants/keycodes/keycodes_0.0.1_midi.hjson
index b9826f92c96..5ab9ef24d5f 100644
--- a/data/constants/keycodes/keycodes_0.0.1_midi.hjson
+++ b/data/constants/keycodes/keycodes_0.0.1_midi.hjson
@@ -84,7 +84,7 @@
"group": "midi",
"key": "QK_MIDI_NOTE_G_SHARP_0",
"aliases": [
- "MI_Gs"
+ "MI_Gs",
"MI_Ab"
]
},
@@ -99,7 +99,7 @@
"group": "midi",
"key": "QK_MIDI_NOTE_A_SHARP_0",
"aliases": [
- "MI_As"
+ "MI_As",
"MI_Bb"
]
},
diff --git a/data/constants/keycodes/keycodes_0.0.2_kb.hjson b/data/constants/keycodes/keycodes_0.0.2_kb.hjson
index f9ffc7432d3..28c4a8e8be9 100644
--- a/data/constants/keycodes/keycodes_0.0.2_kb.hjson
+++ b/data/constants/keycodes/keycodes_0.0.2_kb.hjson
@@ -2,131 +2,131 @@
"keycodes": {
"0x7E00": {
"group": "kb",
- "key": "QK_KB_0",
+ "key": "QK_KB_0"
},
"0x7E01": {
"group": "kb",
- "key": "QK_KB_1",
+ "key": "QK_KB_1"
},
"0x7E02": {
"group": "kb",
- "key": "QK_KB_2",
+ "key": "QK_KB_2"
},
"0x7E03": {
"group": "kb",
- "key": "QK_KB_3",
+ "key": "QK_KB_3"
},
"0x7E04": {
"group": "kb",
- "key": "QK_KB_4",
+ "key": "QK_KB_4"
},
"0x7E05": {
"group": "kb",
- "key": "QK_KB_5",
+ "key": "QK_KB_5"
},
"0x7E06": {
"group": "kb",
- "key": "QK_KB_6",
+ "key": "QK_KB_6"
},
"0x7E07": {
"group": "kb",
- "key": "QK_KB_7",
+ "key": "QK_KB_7"
},
"0x7E08": {
"group": "kb",
- "key": "QK_KB_8",
+ "key": "QK_KB_8"
},
"0x7E09": {
"group": "kb",
- "key": "QK_KB_9",
+ "key": "QK_KB_9"
},
"0x7E0A": {
"group": "kb",
- "key": "QK_KB_10",
+ "key": "QK_KB_10"
},
"0x7E0B": {
"group": "kb",
- "key": "QK_KB_11",
+ "key": "QK_KB_11"
},
"0x7E0C": {
"group": "kb",
- "key": "QK_KB_12",
+ "key": "QK_KB_12"
},
"0x7E0D": {
"group": "kb",
- "key": "QK_KB_13",
+ "key": "QK_KB_13"
},
"0x7E0E": {
"group": "kb",
- "key": "QK_KB_14",
+ "key": "QK_KB_14"
},
"0x7E0F": {
"group": "kb",
- "key": "QK_KB_15",
+ "key": "QK_KB_15"
},
"0x7E10": {
"group": "kb",
- "key": "QK_KB_16",
+ "key": "QK_KB_16"
},
"0x7E11": {
"group": "kb",
- "key": "QK_KB_17",
+ "key": "QK_KB_17"
},
"0x7E12": {
"group": "kb",
- "key": "QK_KB_18",
+ "key": "QK_KB_18"
},
"0x7E13": {
"group": "kb",
- "key": "QK_KB_19",
+ "key": "QK_KB_19"
},
"0x7E14": {
"group": "kb",
- "key": "QK_KB_20",
+ "key": "QK_KB_20"
},
"0x7E15": {
"group": "kb",
- "key": "QK_KB_21",
+ "key": "QK_KB_21"
},
"0x7E16": {
"group": "kb",
- "key": "QK_KB_22",
+ "key": "QK_KB_22"
},
"0x7E17": {
"group": "kb",
- "key": "QK_KB_23",
+ "key": "QK_KB_23"
},
"0x7E18": {
"group": "kb",
- "key": "QK_KB_24",
+ "key": "QK_KB_24"
},
"0x7E19": {
"group": "kb",
- "key": "QK_KB_25",
+ "key": "QK_KB_25"
},
"0x7E1A": {
"group": "kb",
- "key": "QK_KB_26",
- },
+ "key": "QK_KB_26"
+ },
"0x7E1B": {
"group": "kb",
- "key": "QK_KB_27",
+ "key": "QK_KB_27"
},
"0x7E1C": {
"group": "kb",
- "key": "QK_KB_28",
+ "key": "QK_KB_28"
},
"0x7E1D": {
"group": "kb",
- "key": "QK_KB_29",
+ "key": "QK_KB_29"
},
"0x7E1E": {
"group": "kb",
- "key": "QK_KB_30",
+ "key": "QK_KB_30"
},
"0x7E1F": {
"group": "kb",
- "key": "QK_KB_31",
- },
+ "key": "QK_KB_31"
+ }
}
}
diff --git a/data/constants/keycodes/keycodes_0.0.2_midi.hjson b/data/constants/keycodes/keycodes_0.0.2_midi.hjson
index c15c2dd4336..ddf79be96cd 100644
--- a/data/constants/keycodes/keycodes_0.0.2_midi.hjson
+++ b/data/constants/keycodes/keycodes_0.0.2_midi.hjson
@@ -86,7 +86,7 @@
"group": "midi",
"key": "QK_MIDI_NOTE_G_SHARP_0",
"aliases": [
- "MI_Gs"
+ "MI_Gs",
"MI_Ab"
]
},
@@ -101,7 +101,7 @@
"group": "midi",
"key": "QK_MIDI_NOTE_A_SHARP_0",
"aliases": [
- "MI_As"
+ "MI_As",
"MI_Bb"
]
},
diff --git a/data/constants/keycodes/keycodes_0.0.2_user.hjson b/data/constants/keycodes/keycodes_0.0.2_user.hjson
index 42392dc6493..a30e8e8eed1 100644
--- a/data/constants/keycodes/keycodes_0.0.2_user.hjson
+++ b/data/constants/keycodes/keycodes_0.0.2_user.hjson
@@ -2,131 +2,131 @@
"keycodes": {
"0x7E40": {
"group": "user",
- "key": "QK_USER_0",
+ "key": "QK_USER_0"
},
"0x7E41": {
"group": "user",
- "key": "QK_USER_1",
+ "key": "QK_USER_1"
},
"0x7E42": {
"group": "user",
- "key": "QK_USER_2",
+ "key": "QK_USER_2"
},
"0x7E43": {
"group": "user",
- "key": "QK_USER_3",
+ "key": "QK_USER_3"
},
"0x7E44": {
"group": "user",
- "key": "QK_USER_4",
+ "key": "QK_USER_4"
},
"0x7E45": {
"group": "user",
- "key": "QK_USER_5",
+ "key": "QK_USER_5"
},
"0x7E46": {
"group": "user",
- "key": "QK_USER_6",
+ "key": "QK_USER_6"
},
"0x7E47": {
"group": "user",
- "key": "QK_USER_7",
+ "key": "QK_USER_7"
},
"0x7E48": {
"group": "user",
- "key": "QK_USER_8",
+ "key": "QK_USER_8"
},
"0x7E49": {
"group": "user",
- "key": "QK_USER_9",
+ "key": "QK_USER_9"
},
"0x7E4A": {
"group": "user",
- "key": "QK_USER_10",
+ "key": "QK_USER_10"
},
"0x7E4B": {
"group": "user",
- "key": "QK_USER_11",
+ "key": "QK_USER_11"
},
"0x7E4C": {
"group": "user",
- "key": "QK_USER_12",
+ "key": "QK_USER_12"
},
"0x7E4D": {
"group": "user",
- "key": "QK_USER_13",
+ "key": "QK_USER_13"
},
"0x7E4E": {
"group": "user",
- "key": "QK_USER_14",
+ "key": "QK_USER_14"
},
"0x7E4F": {
"group": "user",
- "key": "QK_USER_15",
+ "key": "QK_USER_15"
},
"0x7E50": {
"group": "user",
- "key": "QK_USER_16",
+ "key": "QK_USER_16"
},
"0x7E51": {
"group": "user",
- "key": "QK_USER_17",
+ "key": "QK_USER_17"
},
"0x7E52": {
"group": "user",
- "key": "QK_USER_18",
+ "key": "QK_USER_18"
},
"0x7E53": {
"group": "user",
- "key": "QK_USER_19",
+ "key": "QK_USER_19"
},
"0x7E54": {
"group": "user",
- "key": "QK_USER_20",
+ "key": "QK_USER_20"
},
"0x7E55": {
"group": "user",
- "key": "QK_USER_21",
+ "key": "QK_USER_21"
},
"0x7E56": {
"group": "user",
- "key": "QK_USER_22",
+ "key": "QK_USER_22"
},
"0x7E57": {
"group": "user",
- "key": "QK_USER_23",
+ "key": "QK_USER_23"
},
"0x7E58": {
"group": "user",
- "key": "QK_USER_24",
+ "key": "QK_USER_24"
},
"0x7E59": {
"group": "user",
- "key": "QK_USER_25",
+ "key": "QK_USER_25"
},
"0x7E5A": {
"group": "user",
- "key": "QK_USER_26",
- },
+ "key": "QK_USER_26"
+ },
"0x7E5B": {
"group": "user",
- "key": "QK_USER_27",
+ "key": "QK_USER_27"
},
"0x7E5C": {
"group": "user",
- "key": "QK_USER_28",
+ "key": "QK_USER_28"
},
"0x7E5D": {
"group": "user",
- "key": "QK_USER_29",
+ "key": "QK_USER_29"
},
"0x7E5E": {
"group": "user",
- "key": "QK_USER_30",
+ "key": "QK_USER_30"
},
"0x7E5F": {
"group": "user",
- "key": "QK_USER_31",
- },
+ "key": "QK_USER_31"
+ }
}
}
diff --git a/data/constants/keycodes/keycodes_0.0.6_connection.hjson b/data/constants/keycodes/keycodes_0.0.6_connection.hjson
index 9a1a750f1ae..9be11068254 100644
--- a/data/constants/keycodes/keycodes_0.0.6_connection.hjson
+++ b/data/constants/keycodes/keycodes_0.0.6_connection.hjson
@@ -7,41 +7,47 @@
"keycodes": {
"0x7780": {
"group": "connection",
- "key": "QK_OUTPUT_NEXT",
+ "key": "QK_OUTPUT_AUTO",
"aliases": [
- "OU_NEXT",
"OU_AUTO"
]
},
"0x7781": {
+ "group": "connection",
+ "key": "QK_OUTPUT_NEXT",
+ "aliases": [
+ "OU_NEXT"
+ ]
+ },
+ "0x7782": {
"group": "connection",
"key": "QK_OUTPUT_PREV",
"aliases": [
"OU_PREV"
]
},
- "0x7782": {
+ "0x7783": {
"group": "connection",
"key": "QK_OUTPUT_NONE",
"aliases": [
"OU_NONE"
]
},
- "0x7783": {
+ "0x7784": {
"group": "connection",
"key": "QK_OUTPUT_USB",
"aliases": [
"OU_USB"
]
},
- "0x7784": {
+ "0x7785": {
"group": "connection",
"key": "QK_OUTPUT_2P4GHZ",
"aliases": [
"OU_2P4G"
]
},
- "0x7785": {
+ "0x7786": {
"group": "connection",
"key": "QK_OUTPUT_BLUETOOTH",
"aliases": [
diff --git a/data/constants/keycodes/keycodes_0.0.6_quantum.hjson b/data/constants/keycodes/keycodes_0.0.6_quantum.hjson
index 814cd66a5b1..be3285f9e43 100644
--- a/data/constants/keycodes/keycodes_0.0.6_quantum.hjson
+++ b/data/constants/keycodes/keycodes_0.0.6_quantum.hjson
@@ -3,5 +3,12 @@
"0x7C20": "!delete!", // old QK_OUTPUT_AUTO
"0x7C21": "!delete!", // old QK_OUTPUT_USB
"0x7C22": "!delete!", // old QK_OUTPUT_BLUETOOTH
+ "0x7C7B": {
+ "group": "quantum",
+ "key": "QK_LAYER_LOCK",
+ "aliases": [
+ "QK_LLCK"
+ ]
+ }
}
}
diff --git a/data/mappings/info_config.hjson b/data/mappings/info_config.hjson
index 4c895cf5d50..8d3e3c7f0ee 100644
--- a/data/mappings/info_config.hjson
+++ b/data/mappings/info_config.hjson
@@ -64,6 +64,9 @@
"WEAR_LEVELING_BACKING_SIZE": {"info_key": "eeprom.wear_leveling.backing_size", "value_type": "int", "to_json": false},
"WEAR_LEVELING_LOGICAL_SIZE": {"info_key": "eeprom.wear_leveling.logical_size", "value_type": "int", "to_json": false},
+ // Layer locking
+ "LAYER_LOCK_IDLE_TIMEOUT": {"info_key": "layer_lock.timeout", "value_type": "int"},
+
// Indicators
"LED_CAPS_LOCK_PIN": {"info_key": "indicators.caps_lock"},
"LED_NUM_LOCK_PIN": {"info_key": "indicators.num_lock"},
diff --git a/data/schemas/keyboard.jsonschema b/data/schemas/keyboard.jsonschema
index 72a33f55ad1..ec87680fa05 100644
--- a/data/schemas/keyboard.jsonschema
+++ b/data/schemas/keyboard.jsonschema
@@ -92,6 +92,7 @@
"GD32VF103",
"WB32F3G71",
"WB32FQ95",
+ "AT32F415",
"atmega16u2",
"atmega32u2",
"atmega16u4",
@@ -216,6 +217,7 @@
"type": "string",
"enum": [
"apm32-dfu",
+ "at32-dfu",
"atmel-dfu",
"bootloadhid",
"caterina",
@@ -373,6 +375,12 @@
}
},
"keycodes": {"$ref": "qmk.definitions.v1#/keycode_decl_array"},
+ "layer_lock": {
+ "type": "object",
+ "properties": {
+ "timeout": {"$ref": "qmk.definitions.v1#/unsigned_int"}
+ }
+ },
"layout_aliases": {
"type": "object",
"additionalProperties": {"$ref": "qmk.definitions.v1#/layout_macro"}
diff --git a/docs/_aliases.json b/docs/_aliases.json
index f06e032215c..0dfcdea1e2f 100644
--- a/docs/_aliases.json
+++ b/docs/_aliases.json
@@ -16,6 +16,8 @@
"/tutorial": "/newbs",
"/unicode": "/feature_unicode",
+ "/features/bluetooth": "/features/wireless",
+
"/adc_driver": "/drivers/adc",
"/apa102_driver": "/drivers/apa102",
"/audio_driver": "/drivers/audio",
@@ -24,7 +26,7 @@
"/feature_auto_shift": "/features/auto_shift",
"/feature_autocorrect": "/features/autocorrect",
"/feature_backlight": "/features/backlight",
- "/feature_bluetooth": "/features/bluetooth",
+ "/feature_bluetooth": "/features/wireless",
"/feature_bootmagic": "/features/bootmagic",
"/feature_caps_word": "/features/caps_word",
"/feature_combo": "/features/combo",
diff --git a/docs/_sidebar.json b/docs/_sidebar.json
index d691011d641..15c3cbec317 100644
--- a/docs/_sidebar.json
+++ b/docs/_sidebar.json
@@ -123,6 +123,7 @@
{ "text": "Key Lock", "link": "/features/key_lock" },
{ "text": "Key Overrides", "link": "/features/key_overrides" },
{ "text": "Layers", "link": "/feature_layers" },
+ { "text": "Layer Lock", "link": "/features/layer_lock" },
{ "text": "One Shot Keys", "link": "/one_shot_keys" },
{ "text": "OS Detection", "link": "/features/os_detection" },
{ "text": "Raw HID", "link": "/features/rawhid" },
@@ -166,7 +167,6 @@
]
},
{ "text": "Audio", "link": "/features/audio" },
- { "text": "Bluetooth", "link": "/features/bluetooth" },
{ "text": "Bootmagic", "link": "/features/bootmagic" },
{ "text": "Converters", "link": "/feature_converters" },
{ "text": "Custom Matrix", "link": "/custom_matrix" },
@@ -179,7 +179,8 @@
{ "text": "Pointing Device", "link": "/features/pointing_device" },
{ "text": "PS/2 Mouse", "link": "/features/ps2_mouse" },
{ "text": "Split Keyboard", "link": "/features/split_keyboard" },
- { "text": "Stenography", "link": "/features/stenography" }
+ { "text": "Stenography", "link": "/features/stenography" },
+ { "text": "Wireless", "link": "/features/wireless" }
]
},
{
diff --git a/docs/api_development_overview.md b/docs/api_development_overview.md
index e55d0341006..eb164bec525 100644
--- a/docs/api_development_overview.md
+++ b/docs/api_development_overview.md
@@ -4,7 +4,7 @@ This page attempts to introduce developers to the QMK Compiler. It does not go i
# Overview
-The QMK Compile API consists of a few movings parts:
+The QMK Compile API consists of a few moving parts:

diff --git a/docs/cli_commands.md b/docs/cli_commands.md
index 7d74d8e6177..4cd5ae98c39 100644
--- a/docs/cli_commands.md
+++ b/docs/cli_commands.md
@@ -153,20 +153,26 @@ qmk cd
This command allows for searching through keyboard/keymap targets, filtering by specific criteria. `info.json` and `rules.mk` files contribute to the search data, as well as keymap configurations, and the results can be filtered using "dotty" syntax matching the overall `info.json` file format.
-For example, one could search for all keyboards using STM32F411:
+For example, one could search for all keyboards powered by the STM32F411 microcontroller:
```
-qmk find -f 'processor=STM32F411'
+qmk find -f 'processor==STM32F411'
```
-...and one can further constrain the list to keyboards using STM32F411 as well as rgb_matrix support:
+The list can be further constrained by passing additional filter expressions:
```
-qmk find -f 'processor=STM32F411' -f 'features.rgb_matrix=true'
+qmk find -f 'processor==STM32F411' -f 'features.rgb_matrix==true'
```
-The following filter expressions are also supported:
+The following filter expressions are supported:
+ - `key == value`: Match targets where `key` is equal to `value`. May include wildcards such as `*` and `?`.
+ - `key != value`: Match targets where `key` is not `value`. May include wildcards such as `*` and `?`.
+ - `key < value`: Match targets where `key` is a number less than `value`.
+ - `key > value`: Match targets where `key` is a number greater than `value`.
+ - `key <= value`: Match targets where `key` is a number less than or equal to `value`.
+ - `key >= value`: Match targets where `key` is a number greater than or equal to `value`.
- `exists(key)`: Match targets where `key` is present.
- `absent(key)`: Match targets where `key` is not present.
- `contains(key, value)`: Match targets where `key` contains `value`. Can be used for strings, arrays and object keys.
@@ -175,7 +181,7 @@ The following filter expressions are also supported:
You can also list arbitrary values for each matched target with `--print`:
```
-qmk find -f 'processor=STM32F411' -p 'keyboard_name' -p 'features.rgb_matrix'
+qmk find -f 'processor==STM32F411' -p 'keyboard_name' -p 'features.rgb_matrix'
```
**Usage**:
diff --git a/docs/compatible_microcontrollers.md b/docs/compatible_microcontrollers.md
index e2d27e06f2f..f148c39191e 100644
--- a/docs/compatible_microcontrollers.md
+++ b/docs/compatible_microcontrollers.md
@@ -57,6 +57,10 @@ You can also use any ARM chip with USB that [ChibiOS](https://www.chibios.org) s
* [WB32F3G71xx](http://www.westberrytech.com)
* [WB32FQ95xx](http://www.westberrytech.com)
+### Artery (AT32)
+
+ * [AT32F415](https://www.arterychip.com/en/product/AT32F415.jsp)
+
### NXP (Kinetis)
* [MKL26Z64](https://www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/kl-series-cortex-m0-plus/kinetis-kl2x-72-96-mhz-usb-ultra-low-power-microcontrollers-mcus-based-on-arm-cortex-m0-plus-core:KL2x)
diff --git a/docs/driver_installation_zadig.md b/docs/driver_installation_zadig.md
index 9743c0adc2f..1a5bd1cc346 100644
--- a/docs/driver_installation_zadig.md
+++ b/docs/driver_installation_zadig.md
@@ -98,6 +98,7 @@ The device name here is the name that appears in Zadig, and may not be what the
|`bootloadhid` |HIDBoot |`16C0:05DF` |HidUsb |
|`usbasploader`|USBasp |`16C0:05DC` |libusbK|
|`apm32-dfu` |APM32 DFU ISP Mode |`314B:0106` |WinUSB |
+|`at32-dfu` |AT32 Bootloader DFU |`2E3C:DF11` |WinUSB |
|`stm32-dfu` |STM32 BOOTLOADER |`0483:DF11` |WinUSB |
|`gd32v-dfu` |GD32V BOOTLOADER |`28E9:0189` |WinUSB |
|`kiibohd` |Kiibohd DFU Bootloader |`1C11:B007` |WinUSB |
diff --git a/docs/drivers/audio.md b/docs/drivers/audio.md
index c764c97369a..165e61f0655 100644
--- a/docs/drivers/audio.md
+++ b/docs/drivers/audio.md
@@ -57,27 +57,32 @@ This driver needs one Timer per enabled/used DAC channel, to trigger conversion;
Additionally, in the board config, you'll want to make changes to enable the DACs, GPT for Timers 6, 7 and 8:
-```c
-//halconf.h:
-#define HAL_USE_DAC TRUE
-#define HAL_USE_GPT TRUE
+::: code-group
+```c [halconf.h]
+#pragma once
+
+#define HAL_USE_DAC TRUE // [!code focus]
+#define HAL_USE_GPT TRUE // [!code focus]
+
#include_next
```
+```c [mcuconf.h]
+#pragma once
-```c
-// mcuconf.h:
#include_next
-#undef STM32_DAC_USE_DAC1_CH1
-#define STM32_DAC_USE_DAC1_CH1 TRUE
-#undef STM32_DAC_USE_DAC1_CH2
-#define STM32_DAC_USE_DAC1_CH2 TRUE
-#undef STM32_GPT_USE_TIM6
-#define STM32_GPT_USE_TIM6 TRUE
-#undef STM32_GPT_USE_TIM7
-#define STM32_GPT_USE_TIM7 TRUE
-#undef STM32_GPT_USE_TIM8
-#define STM32_GPT_USE_TIM8 TRUE
+
+#undef STM32_DAC_USE_DAC1_CH1 // [!code focus]
+#define STM32_DAC_USE_DAC1_CH1 TRUE // [!code focus]
+#undef STM32_DAC_USE_DAC1_CH2 // [!code focus]
+#define STM32_DAC_USE_DAC1_CH2 TRUE // [!code focus]
+#undef STM32_GPT_USE_TIM6 // [!code focus]
+#define STM32_GPT_USE_TIM6 TRUE // [!code focus]
+#undef STM32_GPT_USE_TIM7 // [!code focus]
+#define STM32_GPT_USE_TIM7 TRUE // [!code focus]
+#undef STM32_GPT_USE_TIM8 // [!code focus]
+#define STM32_GPT_USE_TIM8 TRUE // [!code focus]
```
+:::
::: tip
Note: DAC1 (A4) uses TIM6, DAC2 (A5) uses TIM7, and the audio state timer uses TIM8 (configurable).
@@ -95,23 +100,28 @@ only needs one timer (GPTD6, Tim6) to trigger the DAC unit to do a conversion; t
Additionally, in the board config, you'll want to make changes to enable the DACs, GPT for Timer 6:
-```c
-//halconf.h:
-#define HAL_USE_DAC TRUE
-#define HAL_USE_GPT TRUE
+::: code-group
+```c [halconf.h]
+#pragma once
+
+#define HAL_USE_DAC TRUE // [!code focus]
+#define HAL_USE_GPT TRUE // [!code focus]
+
#include_next
```
+```c [mcuconf.h]
+#pragma once
-```c
-// mcuconf.h:
#include_next
-#undef STM32_DAC_USE_DAC1_CH1
-#define STM32_DAC_USE_DAC1_CH1 TRUE
-#undef STM32_DAC_USE_DAC1_CH2
-#define STM32_DAC_USE_DAC1_CH2 TRUE
-#undef STM32_GPT_USE_TIM6
-#define STM32_GPT_USE_TIM6 TRUE
+
+#undef STM32_DAC_USE_DAC1_CH1 // [!code focus]
+#define STM32_DAC_USE_DAC1_CH1 TRUE // [!code focus]
+#undef STM32_DAC_USE_DAC1_CH2 // [!code focus]
+#define STM32_DAC_USE_DAC1_CH2 TRUE // [!code focus]
+#undef STM32_GPT_USE_TIM6 // [!code focus]
+#define STM32_GPT_USE_TIM6 TRUE // [!code focus]
```
+:::
### DAC Config
@@ -170,19 +180,25 @@ This driver uses the ChibiOS-PWM system to produce a square-wave on specific out
The hardware directly toggles the pin via its alternate function. See your MCU's data-sheet for which pin can be driven by what timer - looking for TIMx_CHy and the corresponding alternate function.
A configuration example for the STM32F103C8 would be:
-```c
-//halconf.h:
-#define HAL_USE_PWM TRUE
-#define HAL_USE_PAL TRUE
+
+::: code-group
+```c [halconf.h]
+#pragma once
+
+#define HAL_USE_PWM TRUE // [!code focus]
+#define HAL_USE_PAL TRUE // [!code focus]
+
#include_next
```
+```c [mcuconf.h]
+#pragma once
-```c
-// mcuconf.h:
#include_next
-#undef STM32_PWM_USE_TIM1
-#define STM32_PWM_USE_TIM1 TRUE
+
+#undef STM32_PWM_USE_TIM1 // [!code focus]
+#define STM32_PWM_USE_TIM1 TRUE // [!code focus]
```
+:::
If we now target pin A8, looking through the data-sheet of the STM32F103C8, for the timers and alternate functions
- TIM1_CH1 = PA8 <- alternate0
diff --git a/docs/drivers/i2c.md b/docs/drivers/i2c.md
index 10949ed59e0..c806a090c56 100644
--- a/docs/drivers/i2c.md
+++ b/docs/drivers/i2c.md
@@ -54,18 +54,25 @@ The ATmega16/32U2 does not possess I2C functionality, and so cannot use this dri
You'll need to determine which pins can be used for I2C -- a an example, STM32 parts generally have multiple I2C peripherals, labeled I2C1, I2C2, I2C3 etc.
-To enable I2C, modify your board's `halconf.h` to enable I2C:
+To enable I2C, modify your board's `halconf.h` to enable I2C, then modify your board's `mcuconf.h` to enable the peripheral you've chosen:
-```c
-#define HAL_USE_I2C TRUE
+::: code-group
+```c [halconf.h]
+#pragma once
+
+#define HAL_USE_I2C TRUE // [!code focus]
+
+#include_next
```
+```c [mcuconf.h]
+#pragma once
-Then, modify your board's `mcuconf.h` to enable the peripheral you've chosen, for example:
+#include_next
-```c
-#undef STM32_I2C_USE_I2C2
-#define STM32_I2C_USE_I2C2 TRUE
+#undef STM32_I2C_USE_I2C2 // [!code focus]
+#define STM32_I2C_USE_I2C2 TRUE // [!code focus]
```
+:::
|`mcuconf.h` Setting |Description |Default|
|----------------------------|----------------------------------------------------------------------------------|-------|
diff --git a/docs/drivers/serial.md b/docs/drivers/serial.md
index 75d11bc93bc..dda75f629a2 100644
--- a/docs/drivers/serial.md
+++ b/docs/drivers/serial.md
@@ -12,8 +12,6 @@ The Serial driver powers the [Split Keyboard](../features/split_keyboard) featur
Serial in this context should be read as **sending information one bit at a time**, rather than implementing UART/USART/RS485/RS232 standards.
:::
-
-
## Bitbang
This is the Default driver, absence of configuration assumes this driver. It works by [bit banging](https://en.wikipedia.org/wiki/Bit_banging) a GPIO pin using the CPU. It is therefore not as efficient as a dedicated hardware peripheral, which the Half-duplex and Full-duplex drivers use.
@@ -53,11 +51,15 @@ SERIAL_DRIVER = bitbang
#define SOFT_SERIAL_PIN D0 // or D1, D2, D3, E6
```
-3. On ARM platforms you must turn on ChibiOS `PAL_USE_CALLBACKS` feature:
+3. On ARM platforms you must turn on ChibiOS PAL callbacks:
-* In `halconf.h` add the line `#define PAL_USE_CALLBACKS TRUE`.
+```c
+#pragma once
-
+#define PAL_USE_CALLBACKS TRUE // [!code focus]
+
+#include_next
+```
## USART Half-duplex
@@ -117,8 +119,6 @@ For STM32 MCUs several GPIO configuration options can be changed as well. See th
4. Decide either for `SERIAL`, `SIO`, or `PIO` subsystem. See section ["Choosing a driver subsystem"](#choosing-a-driver-subsystem).
-
-
## USART Full-duplex
Targeting ARM boards based on ChibiOS where communication is offloaded to an USART hardware device. The advantages over bitbanging are fast, accurate timings and reduced CPU usage; therefore it is advised to choose this driver over all others where possible. Due to its internal design Full-duplex is slightly more efficient than the Half-duplex driver, but Full-duplex should be primarily chosen if Half-duplex operation is not supported by the controller's USART peripheral.
@@ -179,38 +179,46 @@ For STM32 MCUs several GPIO configuration options, including the ability for `TX
4. Decide either for `SERIAL`, `SIO`, or `PIO` subsystem. See section ["Choosing a driver subsystem"](#choosing-a-driver-subsystem).
-
-
## Choosing a driver subsystem
### The `SERIAL` driver
The `SERIAL` Subsystem is supported for the majority of ChibiOS MCUs and should be used whenever supported. Follow these steps in order to activate it:
-1. In your keyboards `halconf.h` add:
+1. Enable the SERIAL subsystem in the ChibiOS HAL.
-```c
-#define HAL_USE_SERIAL TRUE
-```
+ Add the following to your keyboard's `halconf.h`, creating it if necessary:
-2. In your keyboards `mcuconf.h`: activate the USART peripheral that is used on your MCU. The shown example is for an STM32 MCU, so this will not work on MCUs by other manufacturers. You can find the correct names in the `mcuconf.h` files of your MCU that ship with ChibiOS.
-
-Just below `#include_next ` add:
+ ```c
+ #pragma once
-```c
-#include_next
+ #define HAL_USE_SERIAL TRUE // [!code focus]
-#undef STM32_SERIAL_USE_USARTn
-#define STM32_SERIAL_USE_USARTn TRUE
-```
+ #include_next
+ ```
-Where 'n' matches the peripheral number of your selected USART on the MCU.
+2. Activate the USART peripheral that is used on your MCU. The shown example is for an STM32 MCU, so this will not work on MCUs by other manufacturers. You can find the correct names in the `mcuconf.h` files of your MCU that ship with ChibiOS.
-3. In you keyboards `config.h`: override the default USART `SERIAL` driver if you use a USART peripheral that does not belong to the default selected `SD1` driver. For instance, if you selected `STM32_SERIAL_USE_USART3` the matching driver would be `SD3`.
+ Add the following to your keyboard's `mcuconf.h`, creating it if necessary:
-```c
- #define SERIAL_USART_DRIVER SD3
- ```
+ ```c
+ #pragma once
+
+ #include_next
+
+ #undef STM32_SERIAL_USE_USARTn // [!code focus]
+ #define STM32_SERIAL_USE_USARTn TRUE // [!code focus]
+ ```
+
+ Where *n* matches the peripheral number of your selected USART on the MCU.
+
+3. Override the default USART `SERIAL` driver if you use a USART peripheral that does not belong to the default selected `SD1` driver. For instance, if you selected `STM32_SERIAL_USE_USART3` the matching driver would be `SD3`.
+
+ Add the following to your keyboard's `config.h`:
+
+ ```c
+ #define SERIAL_USART_DRIVER SD3
+ ```
### The `SIO` driver
@@ -218,31 +226,41 @@ The `SIO` Subsystem was added to ChibiOS with the 21.11 release and is only supp
Follow these steps in order to activate it:
-1. In your keyboards `halconf.h` add:
+1. Enable the SIO subsystem in the ChibiOS HAL.
-```c
-#define HAL_USE_SIO TRUE
-```
+ Add the following to your keyboard's `halconf.h`, creating it if necessary:
-2. In your keyboards `mcuconf.h:` activate the USART peripheral that is used on your MCU. The shown example is for an STM32 MCU, so this will not work on MCUs by other manufacturers. You can find the correct names in the `mcuconf.h` files of your MCU that ship with ChibiOS.
-
-Just below `#include_next ` add:
+ ```c
+ #pragma once
-```c
-#include_next
+ #define HAL_USE_SIO TRUE // [!code focus]
-#undef STM32_SIO_USE_USARTn
-#define STM32_SIO_USE_USARTn TRUE
-```
+ #include_next
+ ```
-Where 'n' matches the peripheral number of your selected USART on the MCU.
+2. Activate the USART peripheral that is used on your MCU. The shown example is for an STM32 MCU, so this will not work on MCUs by other manufacturers. You can find the correct names in the `mcuconf.h` files of your MCU that ship with ChibiOS.
-3. In the keyboard's `config.h` file: override the default USART `SIO` driver if you use a USART peripheral that does not belong to the default selected `SIOD1` driver. For instance, if you selected `STM32_SERIAL_USE_USART3` the matching driver would be `SIOD3`.
+ Add the following to your keyboard's `mcuconf.h`, creating it if necessary:
+
+ ```c
+ #pragma once
+
+ #include_next
+
+ #undef STM32_SIO_USE_USARTn // [!code focus]
+ #define STM32_SIO_USE_USARTn TRUE // [!code focus]
+ ```
+
+ Where *n* matches the peripheral number of your selected USART on the MCU.
+
+3. Override the default USART `SIO` driver if you use a USART peripheral that does not belong to the default selected `SIOD1` driver. For instance, if you selected `STM32_SERIAL_USE_USART3` the matching driver would be `SIOD3`.
+
+ Add the following to your keyboard's `config.h`:
+
+ ```c
+ #define SERIAL_USART_DRIVER SIOD3
+ ```
-```c
- #define SERIAL_USART_DRIVER SIOD3
- ```
-
### The `PIO` driver
The `PIO` subsystem is a Raspberry Pi RP2040 specific implementation, using an integrated PIO peripheral and is therefore only available on this MCU. Because of the flexible nature of PIO peripherals, **any** GPIO pin can be used as a `TX` or `RX` pin. Half-duplex and Full-duplex operation modes are fully supported with this driver. Half-duplex uses the built-in pull-ups and GPIO manipulation of the RP2040 to drive the line high by default, thus an external pull-up resistor **is not required**.
@@ -254,8 +272,6 @@ Optionally, the PIO peripheral utilized for split communication can be changed w
The Serial PIO program uses 2 state machines, 13 instructions and the complete interrupt handler of the PIO peripheral it is running on.
-
-
## Advanced Configuration
There are several advanced configuration options that can be defined in your keyboards `config.h` file:
@@ -265,9 +281,11 @@ There are several advanced configuration options that can be defined in your key
If you're having issues or need a higher baudrate with serial communication, you can change the baudrate which in turn controls the communication speed for serial. You want to lower the baudrate if you experience failed transactions.
```c
-#define SELECT_SOFT_SERIAL_SPEED {#}
+#define SELECT_SOFT_SERIAL_SPEED n
```
+Where *n* is one of:
+
| Speed | Bitbang | Half-duplex and Full-duplex |
| ----- | -------------------------- | --------------------------- |
| `0` | 189000 baud (experimental) | 460800 baud |
@@ -287,8 +305,6 @@ This is the default time window in milliseconds in which a successful communicat
#define SERIAL_USART_TIMEOUT 20 // USART driver timeout. default 20
```
-
-
## Troubleshooting
If you're having issues withe serial communication, you can enable debug messages that will give you insights which part of the communication failed. The enable these messages add to your keyboards `config.h` file:
diff --git a/docs/drivers/spi.md b/docs/drivers/spi.md
index ddc35de8511..43d2a056d5d 100644
--- a/docs/drivers/spi.md
+++ b/docs/drivers/spi.md
@@ -32,20 +32,27 @@ You may use more than one slave select pin, not just the `SS` pin. This is usefu
You'll need to determine which pins can be used for SPI -- as an example, STM32 parts generally have multiple SPI peripherals, labeled SPI1, SPI2, SPI3 etc.
-To enable SPI, modify your board's `halconf.h` to enable SPI:
+To enable SPI, modify your board's `halconf.h` to enable SPI, then modify your board's `mcuconf.h` to enable the peripheral you've chosen:
-```c
-#define HAL_USE_SPI TRUE
-#define SPI_USE_WAIT TRUE
-#define SPI_SELECT_MODE SPI_SELECT_MODE_PAD
+::: code-group
+```c [halconf.h]
+#pragma once
+
+#define HAL_USE_SPI TRUE // [!code focus]
+#define SPI_USE_WAIT TRUE // [!code focus]
+#define SPI_SELECT_MODE SPI_SELECT_MODE_PAD // [!code focus]
+
+#include_next
```
+```c [mcuconf.h]
+#pragma once
-Then, modify your board's `mcuconf.h` to enable the peripheral you've chosen, for example:
+#include_next
-```c
-#undef STM32_SPI_USE_SPI2
-#define STM32_SPI_USE_SPI2 TRUE
+#undef STM32_SPI_USE_SPI2 // [!code focus]
+#define STM32_SPI_USE_SPI2 TRUE // [!code focus]
```
+:::
Configuration-wise, you'll need to set up the peripheral as per your MCU's datasheet -- the defaults match the pins for a Proton-C, i.e. STM32F303.
diff --git a/docs/drivers/uart.md b/docs/drivers/uart.md
index 23f5b3d6e43..7cc68727eec 100644
--- a/docs/drivers/uart.md
+++ b/docs/drivers/uart.md
@@ -35,8 +35,12 @@ You'll need to determine which pins can be used for UART -- as an example, STM32
To enable UART, modify your board's `mcuconf.h` to enable the peripheral you've chosen, for example:
```c
-#undef STM32_SERIAL_USE_USART2
-#define STM32_SERIAL_USE_USART2 TRUE
+#pragma once
+
+#include_next
+
+#undef STM32_SERIAL_USE_USART2 // [!code focus]
+#define STM32_SERIAL_USE_USART2 TRUE // [!code focus]
```
Configuration-wise, you'll need to set up the peripheral as per your MCU's datasheet -- the defaults match the pins for a Proton-C, i.e. STM32F303.
diff --git a/docs/drivers/ws2812.md b/docs/drivers/ws2812.md
index 036ea40d1df..4d1e7279281 100644
--- a/docs/drivers/ws2812.md
+++ b/docs/drivers/ws2812.md
@@ -160,15 +160,23 @@ To configure the DI pin for open drain configuration, add the following to your
Depending on the ChibiOS board configuration, you may need to enable SPI at the keyboard level. For STM32, this would look like:
-`halconf.h`:
-```c
-#define HAL_USE_SPI TRUE
+::: code-group
+```c [halconf.h]
+#pragma once
+
+#define HAL_USE_SPI TRUE // [!code focus]
+
+#include_next
```
-`mcuconf.h`:
-```c
-#undef STM32_SPI_USE_SPI1
-#define STM32_SPI_USE_SPI1 TRUE
+```c [mcuconf.h]
+#pragma once
+
+#include_next
+
+#undef STM32_SPI_USE_SPI1 // [!code focus]
+#define STM32_SPI_USE_SPI1 TRUE // [!code focus]
```
+:::
The following `define`s apply only to the `spi` driver:
@@ -213,15 +221,23 @@ The following `#define`s apply only to the PIO driver:
Depending on the ChibiOS board configuration, you may need to enable PWM at the keyboard level. For STM32, this would look like:
-`halconf.h`:
-```c
-#define HAL_USE_PWM TRUE
+::: code-group
+```c [halconf.h]
+#pragma once
+
+#define HAL_USE_PWM TRUE // [!code focus]
+
+#include_next
```
-`mcuconf.h`:
-```c
-#undef STM32_PWM_USE_TIM2
-#define STM32_PWM_USE_TIM2 TRUE
+```c [mcuconf.h]
+#pragma once
+
+#include_next
+
+#undef STM32_PWM_USE_TIM2 // [!code focus]
+#define STM32_PWM_USE_TIM2 TRUE // [!code focus]
```
+:::
The following `#define`s apply only to the `pwm` driver:
diff --git a/docs/feature_advanced_keycodes.md b/docs/feature_advanced_keycodes.md
index 7f5a10d1c13..18740044f43 100644
--- a/docs/feature_advanced_keycodes.md
+++ b/docs/feature_advanced_keycodes.md
@@ -11,7 +11,7 @@ These allow you to combine a modifier with a keycode. When pressed, the keydown
|`RCTL(kc)`| |Hold Right Control and press `kc` |
|`RSFT(kc)`| |Hold Right Shift and press `kc` |
|`RALT(kc)`|`ROPT(kc)`, `ALGR(kc)` |Hold Right Alt and press `kc` |
-|`RGUI(kc)`|`RCMD(kc)`, `LWIN(kc)` |Hold Right GUI and press `kc` |
+|`RGUI(kc)`|`RCMD(kc)`, `RWIN(kc)` |Hold Right GUI and press `kc` |
|`LSG(kc)` |`SGUI(kc)`, `SCMD(kc)`, `SWIN(kc)`|Hold Left Shift and GUI and press `kc` |
|`LAG(kc)` | |Hold Left Alt and Left GUI and press `kc` |
|`RSG(kc)` | |Hold Right Shift and Right GUI and press `kc` |
diff --git a/docs/feature_layers.md b/docs/feature_layers.md
index 30ab7132226..45f02fe536d 100644
--- a/docs/feature_layers.md
+++ b/docs/feature_layers.md
@@ -17,6 +17,9 @@ These functions allow you to activate layers in various ways. Note that layers a
* `TO(layer)` - activates *layer* and de-activates all other layers (except your default layer). This function is special, because instead of just adding/removing one layer to your active layer stack, it will completely replace your current active layers, uniquely allowing you to replace higher layers with a lower one. This is activated on keydown (as soon as the key is pressed).
* `TT(layer)` - Layer Tap-Toggle. If you hold the key down, *layer* is activated, and then is de-activated when you let go (like `MO`). If you repeatedly tap it, the layer will be toggled on or off (like `TG`). It needs 5 taps by default, but you can change this by defining `TAPPING_TOGGLE` -- for example, `#define TAPPING_TOGGLE 2` to toggle on just two taps.
+See also the [Layer Lock key](features/layer_lock), which locks the highest
+active layer until pressed again.
+
### Caveats {#caveats}
Currently, the `layer` argument of `LT()` is limited to layers 0-15, and the `kc` argument to the [Basic Keycode set](keycodes_basic), meaning you can't use keycodes like `LCTL()`, `KC_TILD`, or anything greater than `0xFF`. This is because QMK uses 16-bit keycodes, of which 4 bits are used for the function identifier and 4 bits for the layer, leaving only 8 bits for the keycode.
diff --git a/docs/feature_macros.md b/docs/feature_macros.md
index 055bb3ff8f7..b4e37a1ba96 100644
--- a/docs/feature_macros.md
+++ b/docs/feature_macros.md
@@ -42,38 +42,7 @@ You can define up to 32 macros in a `keymap.json` file, as used by [Configurator
### Selecting Your Host Keyboard Layout
-If you type in a language other than English, or use a non-QWERTY layout like Colemak, Dvorak, or Workman, you may have set your computer's input language to match this layout. This presents a challenge when creating macros - you may need to type different keys to get the same letters! To address this you can add the `host_language` key to your `keymap.json`, like so:
-
-```json
-{
- "keyboard": "handwired/my_macropad",
- "keymap": "my_keymap",
- "host_language": "dvorak",
- "macros": [
- ["Hello, World!"]
- ],
- "layout": "LAYOUT_all",
- "layers": [
- ["QK_MACRO_0"]
- ]
-}
-```
-
-The current list of available languages is:
-
-| belgian | bepo | br_abnt2 | canadian_multilingual |
-|:-------:|:----:|:--------:|:---------------------:|
-| **colemak** | **croatian** | **czech** | **danish** |
-| **dvorak_fr** | **dvorak** | **dvp** | **estonian** |
-| **finnish** | **fr_ch** | **french_afnor** | **french** |
-| **french_osx** | **german_ch** | **german** | **german_osx** |
-| **hungarian** | **icelandic** | **italian** | **italian_osx_ansi** |
-| **italian_osx_iso** | **jis** | **latvian** | **lithuanian_azerty** |
-| **lithuanian_qwerty** | **norman** | **norwegian** | **portuguese** |
-| **portuguese_osx_iso** | **romanian** | **serbian_latin** | **slovak** |
-| **slovenian** | **spanish_dvorak** | **spanish_latin_america** | **spanish** |
-| **swedish** | **turkish_f** | **turkish_q** | **uk** |
-| **us_international** | **workman** | **workman_zxcvm** |
+If you type in a language other than English, or use a non-QWERTY layout like Colemak, Dvorak, or Workman, you may have set your computer's input language to match this layout. This presents a challenge when creating macros — you may need to type different keys to get the same letters! To address this you can use [language-specific keycodes](reference_keymap_extras).
### Macro Basics
diff --git a/docs/features/backlight.md b/docs/features/backlight.md
index 94726756fdb..20f84ac6b59 100644
--- a/docs/features/backlight.md
+++ b/docs/features/backlight.md
@@ -161,15 +161,23 @@ Note that the choice of timer may conflict with the [Audio](audio) feature.
Depending on the ChibiOS board configuration, you may need to enable PWM at the keyboard level. For STM32, this would look like:
-`halconf.h`:
-```c
-#define HAL_USE_PWM TRUE
+::: code-group
+```c [halconf.h]
+#pragma once
+
+#define HAL_USE_PWM TRUE // [!code focus]
+
+#include_next
```
-`mcuconf.h`:
-```c
-#undef STM32_PWM_USE_TIM4
-#define STM32_PWM_USE_TIM4 TRUE
+```c [mcuconf.h]
+#pragma once
+
+#include_next
+
+#undef STM32_PWM_USE_TIM4 // [!code focus]
+#define STM32_PWM_USE_TIM4 TRUE // [!code focus]
```
+:::
The following `#define`s apply only to the `pwm` driver:
@@ -187,15 +195,23 @@ Refer to the ST datasheet for your particular MCU to determine these values. For
Depending on the ChibiOS board configuration, you may need to enable general-purpose timers at the keyboard level. For STM32, this would look like:
-`halconf.h`:
-```c
-#define HAL_USE_GPT TRUE
+::: code-group
+```c [halconf.h]
+#pragma once
+
+#define HAL_USE_GPT TRUE // [!code focus]
+
+#include_next
```
-`mcuconf.h`:
-```c
-#undef STM32_GPT_USE_TIM15
-#define STM32_GPT_USE_TIM15 TRUE
+```c [mcuconf.h]
+#pragma once
+
+#include_next
+
+#undef STM32_GPT_USE_TIM15 // [!code focus]
+#define STM32_GPT_USE_TIM15 TRUE // [!code focus]
```
+:::
The following `#define`s apply only to the `timer` driver:
diff --git a/docs/features/joystick.md b/docs/features/joystick.md
index 69db4655d59..cbf6c6daf7e 100644
--- a/docs/features/joystick.md
+++ b/docs/features/joystick.md
@@ -1,6 +1,6 @@
# Joystick {#joystick}
-This feature provides game controller input as a joystick device supporting up to 6 axes and 32 buttons. Axes can be read either from an [ADC-capable input pin](../drivers/adc), or can be virtual, so that its value is provided by your code.
+This feature provides game controller input as a joystick device supporting up to 6 axes, 32 buttons and a hat switch. Axes can be read either from an [ADC-capable input pin](../drivers/adc), or can be virtual, so that its value is provided by your code.
An analog device such as a [potentiometer](https://en.wikipedia.org/wiki/Potentiometer) found on an analog joystick's axes is based on a voltage divider, where adjusting the movable wiper controls the output voltage which can then be read by the microcontroller's ADC.
@@ -37,6 +37,42 @@ By default, two axes and eight buttons are defined, with a reported resolution o
You must define at least one button or axis. Also note that the maximum ADC resolution of the supported AVR MCUs is 10-bit, and 12-bit for most STM32 MCUs.
:::
+### Hat Switch {#hat-switch}
+
+To enable the 8-way hat switch, add the following to your `config.h`:
+
+```c
+#define JOYSTICK_HAS_HAT
+````
+
+The position can be set by calling `joystick_set_hat(value)`. The range of values moves clockwise from the top (ie. north), with the default "center" position represented by a value of `-1`:
+
+```
+ 0
+ 7 N 1
+ NW .--'--. NE
+ / \
+6 W | -1 | E 2
+ \ /
+ SW '--.--' SE
+ 5 S 3
+ 4
+```
+
+Alternatively you can use these predefined names:
+
+|Define |Value|Angle|
+|------------------------|-----|-----|
+|`JOYSTICK_HAT_CENTER` |`-1` | |
+|`JOYSTICK_HAT_NORTH` |`0` |0° |
+|`JOYSTICK_HAT_NORTHEAST`|`1` |45° |
+|`JOYSTICK_HAT_EAST` |`2` |90° |
+|`JOYSTICK_HAT_SOUTHEAST`|`3` |135° |
+|`JOYSTICK_HAT_SOUTH` |`4` |180° |
+|`JOYSTICK_HAT_SOUTHWEST`|`5` |225° |
+|`JOYSTICK_HAT_WEST` |`6` |270° |
+|`JOYSTICK_HAT_NORTHWEST`|`7` |315° |
+
### Axes {#axes}
When defining axes for your joystick, you must provide a definition array typically in your `keymap.c`.
@@ -149,6 +185,8 @@ Contains the state of the joystick.
A bit-packed array containing the joystick button states. The size is calculated as `(JOYSTICK_BUTTON_COUNT - 1) / 8 + 1`.
- `int16_t axes[]`
An array of analog values for each defined axis.
+ - `int8_t hat`
+ The hat switch position.
- `bool dirty`
Whether the current state needs to be sent to the host.
@@ -222,3 +260,14 @@ Set the value of the given axis.
The axis to set the value of.
- `int16_t value`
The value to set.
+
+---
+
+### `void joystick_set_hat(int8_t value)` {#api-joystick-set-hat}
+
+Set the position of the hat switch.
+
+#### Arguments {#api-joystick-set-hat-arguments}
+
+ - `int8_t value`
+ The hat switch position to set.
diff --git a/docs/features/layer_lock.md b/docs/features/layer_lock.md
new file mode 100644
index 00000000000..aaf323acccd
--- /dev/null
+++ b/docs/features/layer_lock.md
@@ -0,0 +1,139 @@
+# Layer Lock
+
+Some [layer switches](../feature_layers#switching-and-toggling-layers) access
+the layer by holding the key, including momentary layer `MO(layer)` and layer
+tap `LT(layer, key)` keys. You may sometimes need to stay on the layer for a
+long period of time. Layer Lock "locks" the current layer to stay on, supposing
+it was accessed by one of:
+
+ * `MO(layer)` momentary layer switch
+ * `LT(layer, key)` layer tap
+ * `OSL(layer)` one-shot layer
+ * `TT(layer)` layer tap toggle
+ * `LM(layer, mod)` layer-mod key (the layer is locked, but not the mods)
+
+Press the Layer Lock key again to unlock the layer. Additionally, when a layer
+is locked, layer switch keys that turn off the layer such as `TO(other_layer)`
+will unlock it.
+
+
+## How do I enable Layer Lock
+
+In your rules.mk, add:
+
+```make
+LAYER_LOCK_ENABLE = yes
+```
+
+Pick a key in your keymap on a layer you intend to lock, and assign it the
+keycode `QK_LAYER_LOCK` (short alias `QK_LLCK`). Note that locking the base
+layer has no effect, so typically, this key is used on layers above the base
+layer.
+
+
+## Example use
+
+Consider a keymap with the following base layer.
+
+
+
+The highlighted key is a momentary layer switch `MO(NAV)`. Holding it accesses a
+navigation layer.
+
+
+
+
+Holding the NAV key is fine for brief use, but awkward to continue holding when
+using navigation functions continuously. The Layer Lock key comes to the rescue:
+
+1. Hold the NAV key, activating the navigation layer.
+2. Tap Layer Lock.
+3. Release NAV. The navigation layer stays on.
+4. Make use of the arrow keys, etc.
+5. Tap Layer Lock or NAV again to turn the navigation layer back off.
+
+A variation that would also work is to put the Layer Lock key on the base layer
+and make other layers transparent (`KC_TRNS`) in that position. Pressing the
+Layer Lock key locks (or unlocks) the highest active layer, regardless of which
+layer the Layer Lock key is on.
+
+
+## Idle timeout
+
+Optionally, Layer Lock may be configured to unlock if the keyboard is idle
+for some time. In config.h, define `LAYER_LOCK_IDLE_TIMEOUT` in units of
+milliseconds:
+
+```c
+#define LAYER_LOCK_IDLE_TIMEOUT 60000 // Turn off after 60 seconds.
+```
+
+
+## Functions
+
+Use the following functions to query and manipulate the layer lock state.
+
+| Function | Description |
+|----------------------------|------------------------------------|
+| `is_layer_locked(layer)` | Checks whether `layer` is locked. |
+| `layer_lock_on(layer)` | Locks and turns on `layer`. |
+| `layer_lock_off(layer)` | Unlocks and turns off `layer`. |
+| `layer_lock_invert(layer)` | Toggles whether `layer` is locked. |
+
+
+## Representing the current Layer Lock state
+
+There is an optional callback `layer_lock_set_user()` that gets called when a
+layer is locked or unlocked. This is useful to represent the current lock state
+for instance by setting an LED. In keymap.c, define
+
+```c
+bool layer_lock_set_user(layer_state_t locked_layers) {
+ // Do something like `set_led(is_layer_locked(NAV));`
+ return true;
+}
+```
+
+The argument `locked_layers` is a bitfield in which the kth bit is on if the kth
+layer is locked. Alternatively, you can use `is_layer_locked(layer)` to check if
+a given layer is locked.
+
+
+## Combine Layer Lock with a mod-tap
+
+It is possible to create a [mod-tap MT key](../mod_tap) that acts as a modifier
+on hold and Layer Lock on tap. Since Layer Lock is not a [basic
+keycode](../keycodes_basic), attempting `MT(mod, QK_LLCK)` is invalid does not
+work directly, yet this effect can be achieved through [changing the tap
+function](../mod_tap#changing-tap-function). For example, the following
+implements a `SFTLLCK` key that acts as Shift on hold and Layer Lock on tap:
+
+```c
+#define SFTLLCK LSFT_T(KC_0)
+
+// Use SFTLLCK in your keymap...
+
+bool process_record_user(uint16_t keycode, keyrecord_t *record) {
+ switch (keycode) {
+ case SFTLLCK:
+ if (record->tap.count) {
+ if (record->event.pressed) {
+ // Toggle the lock on the highest layer.
+ layer_lock_invert(get_highest_layer(layer_state));
+ }
+ return false;
+ }
+ break;
+
+ // Other macros...
+ }
+ return true;
+}
+```
+
+In the above, `KC_0` is an arbitrary placeholder for the tapping keycode. This
+keycode will never be sent, so any basic keycode will do. In
+`process_record_user()`, the tap press event is changed to toggle the lock on
+the highest layer. Layer Lock can be combined with a [layer-tap LT
+key](../feature_layers#switching-and-toggling-layers) similarly.
+
diff --git a/docs/features/ps2_mouse.md b/docs/features/ps2_mouse.md
index 90f4cca8275..52443c3ce29 100644
--- a/docs/features/ps2_mouse.md
+++ b/docs/features/ps2_mouse.md
@@ -90,18 +90,22 @@ PS2_ENABLE = yes
PS2_DRIVER = interrupt
```
-In your keyboard config.h:
+In your keyboard `config.h`:
```c
#define PS2_CLOCK_PIN A8
#define PS2_DATA_PIN A9
```
-And in the chibios specifig halconf.h:
-```c
-#define PAL_USE_CALLBACKS TRUE
-```
+And in the ChibiOS specific `halconf.h`:
+```c
+#pragma once
+
+#define PAL_USE_CALLBACKS TRUE // [!code focus]
+
+#include_next
+```
### USART Version {#usart-version}
diff --git a/docs/features/rgblight.md b/docs/features/rgblight.md
index 2afc2eb7d09..4322fe796e7 100644
--- a/docs/features/rgblight.md
+++ b/docs/features/rgblight.md
@@ -59,6 +59,10 @@ Changing the **Value** sets the overall brightness.
## Keycodes
+::: warning
+These keycodes also simultaneously control [RGB Matrix](rgb_matrix), if enabled. This behaviour is in the process of being deprecated, so during this time it is recommended to additionally include the dedicated RGB Matrix keycodes to your keymap, and add `#define RGB_MATRIX_DISABLE_SHARED_KEYCODES` to `config.h`.
+:::
+
|Key |Aliases |Description |
|------------------------------|----------|---------------------------------------------------------------------|
|`QK_UNDERGLOW_TOGGLE` |`UG_TOGG` |Toggle RGB lighting on or off |
diff --git a/docs/features/bluetooth.md b/docs/features/wireless.md
similarity index 53%
rename from docs/features/bluetooth.md
rename to docs/features/wireless.md
index d3634498be4..0d73ad3583e 100644
--- a/docs/features/bluetooth.md
+++ b/docs/features/wireless.md
@@ -1,4 +1,4 @@
-# Bluetooth
+# Wireless / Bluetooth
## Bluetooth Known Supported Hardware
@@ -39,8 +39,20 @@ BLUETOOTH_DRIVER = bluefruit_le # or rn42
This is used when multiple keyboard outputs can be selected. Currently this only allows for switching between USB and Bluetooth on keyboards that support both.
-| Key | Aliases | Description |
-|-----------------------|----------------------|------------------------------------------------|
-| `QK_OUTPUT_NEXT` | `OU_NEXT`, `OU_AUTO` | Automatically switch between USB and Bluetooth |
-| `QK_OUTPUT_USB` | `OU_USB` | USB only |
-| `QK_OUTPUT_BLUETOOTH` | `OU_BT` | Bluetooth only |
+| Key | Aliases | Description |
+|-----------------------------|-----------|-----------------------------------------------------------------------------------------------|
+| `QK_OUTPUT_AUTO` | `OU_AUTO` | Automatically switch to USB when plugged in, otherwise use wireless |
+| `QK_OUTPUT_NEXT` | `OU_NEXT` | Cycle forwards through USB, Bluetooth, and 2.4GHz (when available) **(not yet implemented)** |
+| `QK_OUTPUT_PREV` | `OU_PREV` | Cycle backwards through USB, Bluetooth, and 2.4GHz (when available) **(not yet implemented)** |
+| `QK_OUTPUT_NONE` | `OU_NONE` | Disable all output **(not yet implemented)** |
+| `QK_OUTPUT_USB` | `OU_USB` | Output to USB only |
+| `QK_OUTPUT_2P4GHZ` | `OU_2P4G` | Output to 2.4GHz only **(not yet implemented)** |
+| `QK_OUTPUT_BLUETOOTH` | `OU_BT` | Output to Bluetooth only |
+| `QK_BLUETOOTH_PROFILE_NEXT` | `BT_NEXT` | Move to the next Bluetooth profile **(not yet implemented)** |
+| `QK_BLUETOOTH_PROFILE_PREV` | `BT_PREV` | Move to the previous Bluetooth profile **(not yet implemented)** |
+| `QK_BLUETOOTH_UNPAIR` | `BT_UNPR` | Un-pair the current Bluetooth profile **(not yet implemented)** |
+| `QK_BLUETOOTH_PROFILE1` | `BT_PRF1` | Swap to Bluetooth profile #1 **(not yet implemented)** |
+| `QK_BLUETOOTH_PROFILE2` | `BT_PRF2` | Swap to Bluetooth profile #2 **(not yet implemented)** |
+| `QK_BLUETOOTH_PROFILE3` | `BT_PRF3` | Swap to Bluetooth profile #3 **(not yet implemented)** |
+| `QK_BLUETOOTH_PROFILE4` | `BT_PRF4` | Swap to Bluetooth profile #4 **(not yet implemented)** |
+| `QK_BLUETOOTH_PROFILE5` | `BT_PRF5` | Swap to Bluetooth profile #5 **(not yet implemented)** |
diff --git a/docs/flashing.md b/docs/flashing.md
index 2afb8588602..29dc780aaf0 100644
--- a/docs/flashing.md
+++ b/docs/flashing.md
@@ -345,6 +345,39 @@ Flashing sequence:
3. Flash a .bin file
4. Reset the device into application mode (may be done automatically)
+## AT32 DFU
+
+All AT32 MCUs come preloaded with a factory bootloader that cannot be modified nor deleted.
+
+To ensure compatibility with the AT32-DFU bootloader, make sure this block is present in your `rules.mk`:
+
+```make
+# Bootloader selection
+BOOTLOADER = at32-dfu
+```
+
+Compatible flashers:
+
+* [dfu-util](https://dfu-util.sourceforge.net/) / `:dfu-util` target in QMK (recommended command line)
+ ```
+ dfu-util -a 0 -d 2E3C:DF11 -s 0x8000000:leave -D
+ ```
+
+Flashing sequence:
+
+1. Enter the bootloader using any of the following methods:
+ * Tap the `QK_BOOT` keycode
+ * If a reset circuit is present, tap the `RESET` button on the PCB; some boards may also have a toggle switch that must be flipped
+ * Otherwise, you need to bridge `BOOT0` to VCC (via `BOOT0` button or jumper), short `RESET` to GND (via `RESET` button or jumper), and then let go of the `BOOT0` bridge
+2. Wait for the OS to detect the device
+3. Flash a .bin file
+4. Reset the device into application mode (may be done automatically)
+
+### `make` Targets
+
+* `:dfu-util`: Waits until an AT32 bootloader device is available, and then flashes the firmware.
+* `:dfu-util-split-left` and `:dfu-util-split-right`: Flashes the firmware as with `:dfu-util`, but also sets the handedness setting in EEPROM.
+
## tinyuf2
Keyboards may opt into supporting the tinyuf2 bootloader. This is currently only supported on F303/F401/F411.
diff --git a/docs/keycodes.md b/docs/keycodes.md
index 1210390f54b..cae6418266a 100644
--- a/docs/keycodes.md
+++ b/docs/keycodes.md
@@ -290,15 +290,27 @@ See also: [Backlighting](features/backlight)
| `QK_BACKLIGHT_DOWN` | `BL_DOWN` | Decrease the backlight level |
| `QK_BACKLIGHT_TOGGLE_BREATHING` | `BL_BRTG` | Toggle backlight breathing |
-## Bluetooth {#bluetooth}
+## Wireless/Bluetooth {#bluetooth}
-See also: [Bluetooth](features/bluetooth)
+See also: [Wireless](features/wireless)
-| Key | Aliases | Description |
-|-----------------------|----------------------|------------------------------------------------|
-| `QK_OUTPUT_NEXT` | `OU_NEXT`, `OU_AUTO` | Automatically switch between USB and Bluetooth |
-| `QK_OUTPUT_USB` | `OU_USB` | USB only |
-| `QK_OUTPUT_BLUETOOTH` | `OU_BT` | Bluetooth only |
+| Key | Aliases | Description |
+|-----------------------------|-----------|-----------------------------------------------------------------------------------------------|
+| `QK_OUTPUT_AUTO` | `OU_AUTO` | Automatically switch to USB when plugged in, otherwise use wireless |
+| `QK_OUTPUT_NEXT` | `OU_NEXT` | Cycle forwards through USB, Bluetooth, and 2.4GHz (when available) **(not yet implemented)** |
+| `QK_OUTPUT_PREV` | `OU_PREV` | Cycle backwards through USB, Bluetooth, and 2.4GHz (when available) **(not yet implemented)** |
+| `QK_OUTPUT_NONE` | `OU_NONE` | Disable all output **(not yet implemented)** |
+| `QK_OUTPUT_USB` | `OU_USB` | Output to USB only |
+| `QK_OUTPUT_2P4GHZ` | `OU_2P4G` | Output to 2.4GHz only **(not yet implemented)** |
+| `QK_OUTPUT_BLUETOOTH` | `OU_BT` | Output to Bluetooth only |
+| `QK_BLUETOOTH_PROFILE_NEXT` | `BT_NEXT` | Move to the next Bluetooth profile **(not yet implemented)** |
+| `QK_BLUETOOTH_PROFILE_PREV` | `BT_PREV` | Move to the previous Bluetooth profile **(not yet implemented)** |
+| `QK_BLUETOOTH_UNPAIR` | `BT_UNPR` | Un-pair the current Bluetooth profile **(not yet implemented)** |
+| `QK_BLUETOOTH_PROFILE1` | `BT_PRF1` | Swap to Bluetooth profile #1 **(not yet implemented)** |
+| `QK_BLUETOOTH_PROFILE2` | `BT_PRF2` | Swap to Bluetooth profile #2 **(not yet implemented)** |
+| `QK_BLUETOOTH_PROFILE3` | `BT_PRF3` | Swap to Bluetooth profile #3 **(not yet implemented)** |
+| `QK_BLUETOOTH_PROFILE4` | `BT_PRF4` | Swap to Bluetooth profile #4 **(not yet implemented)** |
+| `QK_BLUETOOTH_PROFILE5` | `BT_PRF5` | Swap to Bluetooth profile #5 **(not yet implemented)** |
## Caps Word {#caps-word}
@@ -375,6 +387,14 @@ See also: [Key Lock](features/key_lock)
|---------|--------------------------------------------------------------|
|`QK_LOCK`|Hold down the next key pressed, until the key is pressed again|
+## Layer Lock {#layer-lock}
+
+See also: [Layer Lock](features/layer_lock)
+
+|Key |Aliases |Description |
+|---------------|---------|----------------------------------|
+|`QK_LAYER_LOCK`|`QK_LLCK`|Locks or unlocks the highest layer|
+
## Layer Switching {#layer-switching}
See also: [Layer Switching](feature_layers#switching-and-toggling-layers)
diff --git a/docs/newbs.md b/docs/newbs.md
index 64593cbad12..95cde67f0cd 100644
--- a/docs/newbs.md
+++ b/docs/newbs.md
@@ -4,7 +4,7 @@ Your computer keyboard has a processor inside of it, similar to the one inside y
QMK tries to put a lot of power into your hands by making easy things easy, and hard things possible. You don't have to know how to program to create powerful keymaps — you only have to follow a few simple syntax rules.
-Not sure if your keyboard can run QMK? If it's a mechanical keyboard you built yourself chances are good it can. We support a [large number of hobbyist boards](https://qmk.fm/keyboards/). If your current keyboard can't run QMK there are a lot of choices out there for boards that do.
+Not sure if your keyboard can run QMK? If it's a mechanical keyboard you built yourself chances are good it can. We support a [large number of hobbyist boards](https://browse.qmk.fm/). If your current keyboard can't run QMK there are a lot of choices out there for boards that do.
::: tip Is This Guide For Me?
If the thought of programming intimidates you, please [take a look at our online GUI](newbs_building_firmware_configurator) instead.
diff --git a/docs/porting_your_keyboard_to_qmk.md b/docs/porting_your_keyboard_to_qmk.md
index e5a1f803f71..737ec4a2cf3 100644
--- a/docs/porting_your_keyboard_to_qmk.md
+++ b/docs/porting_your_keyboard_to_qmk.md
@@ -4,52 +4,51 @@ This page describes the support for [Compatible Microcontrollers](compatible_mic
If you have not yet you should read the [Keyboard Guidelines](hardware_keyboard_guidelines) to get a sense of how keyboards fit into QMK.
-
QMK has a number of features to simplify working with keyboards. For most, you don't have to write a single line of code. To get started, run `qmk new-keyboard`:
```
$ qmk new-keyboard
Ψ Generating a new QMK keyboard directory
-Name Your Keyboard Project
-For more infomation, see:
-https://docs.qmk.fm/hardware_keyboard_guidelines#naming-your-keyboardproject
+Ψ Name Your Keyboard Project
+Ψ For more information, see:
+https://docs.qmk.fm/hardware_keyboard_guidelines#naming-your-keyboard-project
+Keyboard Name? mycoolkeeb
+Ψ Attribution
+Ψ Used for maintainer, copyright, etc.
+Your GitHub Username? [jsmith]
+Ψ More Attribution
+Ψ Used for maintainer, copyright, etc.
+Your Real Name? [John Smith]
+Ψ Pick Base Layout
+Ψ As a starting point, one of the common layouts can be used to
+bootstrap the process
+Default Layout?
+ 1. 60_abnt2
+ ...
+ 65. none of the above
+Please enter your choice: [65]
+Ψ What Powers Your Project
+Ψ Is your board using a separate development board, such as a Pro Micro,
+or is the microcontroller integrated onto the PCB?
-keyboard Name? mycoolkeeb
-
-Attribution
-Used for maintainer, copyright, etc
-
-Your GitHub Username? [jsmith]
-
-More Attribution
-Used for maintainer, copyright, etc
-
-Your Real Name? [John Smith]
-
-Pick Base Layout
-As a starting point, one of the common layouts can be used to bootstrap the process
-
-Default Layout?
- 1. 60_ansi
-...
- 50. tkl_iso
- 51. none of the above
-Please enter your choice: [51]
-
-What Powers Your Project
-For more infomation, see:
-https://docs.qmk.fm/#/compatible_microcontrollers
-
-MCU?
- 1. atmega32u4
-...
- 22. STM32F303
-Please enter your choice: [12]
+For more information, see:
+https://docs.qmk.fm/compatible_microcontrollers
+Using a Development Board? [y/n] y
+Ψ Select Development Board
+Ψ For more information, see:
+https://docs.qmk.fm/compatible_microcontrollers
+Development Board?
+ 1. bit_c_pro
+ ...
+ 14. promicro
+ ...
+ 18. svlinky
+Please enter your choice: [14]
Ψ Created a new keyboard called mycoolkeeb.
-Ψ To start working on things, `cd` into keyboards/mycoolkeeb,
-Ψ or open the directory in your preferred text editor.
-Ψ And build with qmk compile -kb mycoolkeeb -km default.
+Ψ Build Command: qmk compile -kb mycoolkeeb -km default.
+Ψ Project Location: /Users/jsmith/qmk_firmware/keyboards/mycoolkeeb.
+Ψ Now update the config files to match the hardware!
```
This will create all the files needed to support your new keyboard, and populate the settings with default values. Now you just need to customize it for your keyboard.
@@ -58,13 +57,13 @@ This will create all the files needed to support your new keyboard, and populate
This is where you'll describe your keyboard. Please follow the [Keyboard Readme Template](documentation_templates#keyboard-readmemd-template) when writing your `readme.md`. You're encouraged to place an image at the top of your `readme.md`, please use an external service such as [Imgur](https://imgur.com) to host the images.
-## `info.json`
+## `keyboard.json`
-The `info.json` file is where you configure the hardware and feature set for your keyboard. There are a lot of options that can be placed in that file, too many to list here. For a complete overview of available options see the [Data Driven Configuration Options](reference_info_json) page.
+The `keyboard.json` file is where you configure the hardware and feature set for your keyboard. There are a lot of options that can be placed in that file, too many to list here. For a complete overview of available options see the [Data Driven Configuration Options](reference_info_json) page.
### Hardware Configuration
-At the top of the `info.json` you'll find USB related settings. These control how your keyboard appears to the Operating System. If you don't have a good reason to change you should leave the `usb.vid` as `0xFEED`. For the `usb.pid` you should pick a number that is not yet in use.
+At the top of the `keyboard.json` you'll find USB related settings. These control how your keyboard appears to the Operating System. If you don't have a good reason to change you should leave the `usb.vid` as `0xFEED`. For the `usb.pid` you should pick a number that is not yet in use.
Do change the `manufacturer` and `keyboard_name` lines to accurately reflect your keyboard.
@@ -82,10 +81,11 @@ Do change the `manufacturer` and `keyboard_name` lines to accurately reflect you
Windows and macOS will display the `manufacturer` and `keyboard_name` in the list of USB devices. `lsusb` on Linux instead prefers the values in the list maintained by the [USB ID Repository](http://www.linux-usb.org/usb-ids.html). By default, it will only use `manufacturer` and `keyboard_name` if the list does not contain that `usb.vid` / `usb.pid`. `sudo lsusb -v` will show the values reported by the device, and they are also present in kernel logs after plugging it in.
:::
-
### Matrix Configuration
-The next section of the `info` file deals with your keyboard's matrix. The first thing you should define is which pins on your MCU are connected to rows and columns. To do so simply specify the names of those pins:
+The next section of the `keyboard.json` deals with your keyboard's matrix. The first thing you should define is which pins on your MCU are connected to rows and columns. To do so simply specify the names of those pins:
+
+#### Diode Matrix
```json
"matrix_pins": {
@@ -94,7 +94,7 @@ The next section of the `info` file deals with your keyboard's matrix. The first
},
```
-The size of the `matrix_pins.cols` and `matrix_pins.rows` arrays infer the size of the matrix (previously `MATRIX_ROWS` and `MATRIX_COLS`).
+The matrix dimensions are inferred from the length of the `matrix_pins.cols` and `matrix_pins.rows` arrays (previously specified explicitly in `config.h` with `MATRIX_ROWS` and `MATRIX_COLS`).
Finally, you can specify the direction your diodes point. This can be `COL2ROW` or `ROW2COL`.
@@ -103,54 +103,56 @@ Finally, you can specify the direction your diodes point. This can be `COL2ROW`
```
#### Direct Pin Matrix
-To configure a keyboard where each switch is connected to a separate pin and ground instead of sharing row and column pins, use `matrix_pins.direct`. The mapping defines the pins of each switch in rows and columns, from left to right. The size of the `matrix_pins.direct` array infers the size of the matrix. Use `NO_PIN` to fill in blank spaces. Overrides the behaviour of `diode_direction`, `matrix_pins.cols` and `matrix_pins.rows`.
+
+To configure a keyboard where each switch is connected to a separate pin and ground instead of sharing row and column pins, use `matrix_pins.direct`. This overrides the behaviour of `diode_direction`, `matrix_pins.cols` and `matrix_pins.rows`, and they should not be specified together.
```json
"matrix_pins": {
"direct": [
- ["F1", "E6", "B0", "B2", "B3" ],
- ["F5", "F0", "B1", "B7", "D2" ],
- ["F6", "F7", "C7", "D5", "D3" ],
- ["B5", "C6", "B6", "NO_PIN", "NO_PIN"]
+ ["F1", "E6", "B0", "B2", "B3"],
+ ["F5", "F0", "B1", "B7", "D2"],
+ ["F6", "F7", "C7", "D5", "D3"],
+ ["B5", "C6", "B6", null, null]
]
},
```
-### Layout macros
+Here, the matrix dimensions are inferred directly from the dimensions of the `matrix_pins.direct` array. Since there are no row or column pins to prescribe the matrix dimensions, you can arrange it however you like. Each "row" must contain the same number of "column"s; use `null` to fill in blank spaces, but try to minimize them.
-Next is configuring Layout Macro(s). These define the physical arrangement of keys, and its position within the matrix that a switch are connected to. This allows you to have a physical arrangement of keys that differs from the wiring matrix.
+### Layout Macros
+
+Next is configuring layout macro(s). These define the physical arrangement of keys, and their position within the matrix that switches are connected to. This allows you to have a physical arrangement of keys that differs from the wiring matrix.
```json
"layouts": {
"LAYOUT_ortho_4x4": {
"layout": [
- { "matrix": [0, 0], "x": 0, "y": 0 },
- { "matrix": [0, 1], "x": 1, "y": 0 },
- { "matrix": [0, 2], "x": 2, "y": 0 },
- { "matrix": [0, 3], "x": 3, "y": 0 },
- { "matrix": [1, 0], "x": 0, "y": 1 },
- { "matrix": [1, 1], "x": 1, "y": 1 },
- { "matrix": [1, 2], "x": 2, "y": 1 },
- { "matrix": [1, 3], "x": 3, "y": 1 },
- { "matrix": [2, 0], "x": 0, "y": 2 },
- { "matrix": [2, 1], "x": 1, "y": 2 },
- { "matrix": [2, 2], "x": 2, "y": 2 },
- { "matrix": [2, 3], "x": 3, "y": 2 },
- { "matrix": [3, 0], "x": 0, "y": 3 },
- { "matrix": [3, 1], "x": 1, "y": 3 },
- { "matrix": [3, 2], "x": 2, "y": 3 },
- { "matrix": [3, 3], "x": 3, "y": 3 }
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [0, 1], "x": 1, "y": 0},
+ {"matrix": [0, 2], "x": 2, "y": 0},
+ {"matrix": [0, 3], "x": 3, "y": 0},
+ {"matrix": [1, 0], "x": 0, "y": 1},
+ {"matrix": [1, 1], "x": 1, "y": 1},
+ {"matrix": [1, 2], "x": 2, "y": 1},
+ {"matrix": [1, 3], "x": 3, "y": 1},
+ {"matrix": [2, 0], "x": 0, "y": 2},
+ {"matrix": [2, 1], "x": 1, "y": 2},
+ {"matrix": [2, 2], "x": 2, "y": 2},
+ {"matrix": [2, 3], "x": 3, "y": 2},
+ {"matrix": [3, 0], "x": 0, "y": 3},
+ {"matrix": [3, 1], "x": 1, "y": 3},
+ {"matrix": [3, 2], "x": 2, "y": 3},
+ {"matrix": [3, 3], "x": 3, "y": 3}
]
}
}
-
```
-In the above example,
+In the above example,
* `LAYOUT_ortho_4x4` defines the name of the layout macro
* It must conform to the [layout guidelines](hardware_keyboard_guidelines#keyboard-name-h)
-* `"matrix": [0, 0]` defines the electrical position
+* `"matrix": [0, 0]` defines the matrix row and column that the key is associated with
::: tip
See also: [Split Keyboard Layout Macro](features/split_keyboard#layout-macro) and [Matrix to Physical Layout](understanding_qmk#matrix-to-physical-layout-map).
@@ -158,9 +160,10 @@ See also: [Split Keyboard Layout Macro](features/split_keyboard#layout-macro) an
## Additional Configuration
-There are a lot of features that can be turned on or off, configured or tuned. Some of these have yet to be migrated over to [Data Driven Configuration](data_driven_config). The following sections cover the process for when an `info.json` option is unavailable.
+There are a lot of features that can be turned on or off, configured or tuned. Some of these have yet to be migrated over to [Data Driven Configuration](data_driven_config). The following sections cover the process for when a data-driven option is unavailable.
### Configuration Options
+
For available options for `config.h`, you should see the [Config Options](config_options#the-configh-file) page for more details.
### Build Options
diff --git a/docs/reference_configurator_support.md b/docs/reference_configurator_support.md
index dffed5c0c34..d0824c7705e 100644
--- a/docs/reference_configurator_support.md
+++ b/docs/reference_configurator_support.md
@@ -156,25 +156,25 @@ For more on the `info.json` files, see [`info.json` Format](reference_info_json)
The Configurator's API uses the layout macro and the JSON file we've given it to create a visual representation of the keyboard that has each visual object tied to a specific key, in sequence:
-key in layout macro | JSON object used
-:---: | :----
-k00 | {"label":"Num Lock", "x":0, "y":0}
-k01 | {"label":"/", "x":1, "y":0}
-k02 | {"label":"*", "x":2, "y":0}
-k03 | {"label":"-", "x":3, "y":0}
-k10 | {"label":"7", "x":0, "y":1}
-k11 | {"label":"8", "x":1, "y":1}
-k12 | {"label":"9", "x":2, "y":1}
-k13 | {"label":"+", "x":3, "y":1, "h":2}
-k20 | {"label":"4", "x":0, "y":2}
-k21 | {"label":"5", "x":1, "y":2}
-k22 | {"label":"6", "x":2, "y":2}
-k30 | {"label":"1", "x":0, "y":3}
-k31 | {"label":"2", "x":1, "y":3}
-k32 | {"label":"3", "x":2, "y":3}
-k33 | {"label":"Enter", "x":3, "y":3, "h":2}
-k40 | {"label":"0", "x":0, "y":4, "w":2}
-k42 | {"label":".", "x":2, "y":4}
+| Key in layout macro | JSON object used |
+| ------------------- | ---------------------------------------- |
+| k00 | `{"label":"Num Lock", "x":0, "y":0}` |
+| k01 | `{"label":"/", "x":1, "y":0}` |
+| k02 | `{"label":"*", "x":2, "y":0}` |
+| k03 | `{"label":"-", "x":3, "y":0}` |
+| k10 | `{"label":"7", "x":0, "y":1}` |
+| k11 | `{"label":"8", "x":1, "y":1}` |
+| k12 | `{"label":"9", "x":2, "y":1}` |
+| k13 | `{"label":"+", "x":3, "y":1, "h":2}` |
+| k20 | `{"label":"4", "x":0, "y":2}` |
+| k21 | `{"label":"5", "x":1, "y":2}` |
+| k22 | `{"label":"6", "x":2, "y":2}` |
+| k30 | `{"label":"1", "x":0, "y":3}` |
+| k31 | `{"label":"2", "x":1, "y":3}` |
+| k32 | `{"label":"3", "x":2, "y":3}` |
+| k33 | `{"label":"Enter", "x":3, "y":3, "h":2}` |
+| k40 | `{"label":"0", "x":0, "y":4, "w":2}` |
+| k42 | `{"label":".", "x":2, "y":4}` |
When a user selects the top-left key in the Configurator, and assigns Num Lock to it, the Configurator builds a keymap file with `KC_NUM` as the first key, and so on as the keymap is built. The `label` keys are not used; they are only for the user's reference in identifying specific keys when debugging the `info.json` file.
diff --git a/docs/reference_info_json.md b/docs/reference_info_json.md
index 82110537a9d..99ff7b1f7a3 100644
--- a/docs/reference_info_json.md
+++ b/docs/reference_info_json.md
@@ -16,7 +16,7 @@ You can create `info.json` files at every level under `qmk_firmware/keyboards/String Required
- * A URL to the keyboard's product page, [QMK.fm/keyboards](https://qmk.fm/keyboards) page, or other page describing information about the keyboard.
+ * A URL to the keyboard's product page, [QMK Keyboards](https://browse.qmk.fm/) page, or other page describing information about the keyboard.
* Example: `"https://clueboard.co"`
* `bootloader_instructions` String
* Instructions for putting the keyboard into a mode that allows for firmware flashing.
@@ -177,9 +177,9 @@ Configures the [Backlight](features/backlight) feature.
* `pins` Array: Pin
* A list of GPIO pins connected to the backlight LEDs (`software` and `timer` drivers only).
-## Bluetooth {#bluetooth}
+## Wireless/Bluetooth {#bluetooth}
-Configures the [Bluetooth](features/bluetooth) feature.
+Configures the [Wireless](features/wireless) feature.
* `bluetooth`
* `driver` String
diff --git a/docs/reference_keymap_extras.md b/docs/reference_keymap_extras.md
index d45183b6c6a..f6b4b8faf68 100644
--- a/docs/reference_keymap_extras.md
+++ b/docs/reference_keymap_extras.md
@@ -2,9 +2,31 @@
Keyboards are able to support a wide range of languages. However, this support is not actually achieved within the keyboard itself - instead, it sends numerical codes, which the operating system maps to the appropriate characters depending on the user's configured keyboard layout. By default (and per the HID spec), this is the US ANSI layout. For example, when a Swedish person presses the key with the `å` character printed on it, the keyboard is *actually* sending the keycode for `[`.
-Obviously, this can get confusing, so QMK provides language-specific keycode aliases for many keyboard layouts. These won't do much on their own - you still have to set the matching keyboard layout in your OS settings. Think of them more as keycap labels for your keymap.
+Obviously, this can get confusing, so QMK provides language-specific keycode aliases for many keyboard layouts. These are used in place of the `KC_` prefixed ones. They won't do much on their own - you still have to set the matching keyboard layout in your OS settings. Think of them more as keycap labels for your keymap. The language-specific keycode aliases are defined in the files listed in the [Keycodes Header](#header-files) column below.
-Simply `#include` one of the keycode headers below at the top of your `keymap.c`, and assign the keycodes defined in the header in place of the `KC_` prefixed ones.
+## Selecting Your Host Keyboard Layout
+
+To select a host keyboard layout, simply `#include` one of the [keycode headers](#header-files) below at the top of your `keymap.c`. Example:
+
+```c
+#include QMK_KEYBOARD_H
+
+#include "keymap_japanese.h" // [!code focus]
+```
+
+Alternatively, if using `keymap.json`, add the `host_language` key as shown in the following example. The available languages are those with a _Sendstring LUT Header_ entry in one of the [Header Files](#header-files) tables.
+
+```json
+{
+ "keyboard": "handwired/my_macropad",
+ "keymap": "my_keymap",
+ "host_language": "swedish", // [!code focus]
+ "layout": "LAYOUT_all",
+ "layers": [
+ ["SE_ARNG"]
+ ]
+}
+```
## Sendstring Support
diff --git a/drivers/sensors/adns5050.c b/drivers/sensors/adns5050.c
index f28a5dcc455..1768c9f3b4a 100644
--- a/drivers/sensors/adns5050.c
+++ b/drivers/sensors/adns5050.c
@@ -21,6 +21,7 @@
#include "wait.h"
#include "debug.h"
#include "gpio.h"
+#include "pointing_device_internal.h"
// Registers
// clang-format off
@@ -45,6 +46,13 @@
#define REG_MOTION_BURST 0x63
// clang-format on
+const pointing_device_driver_t adns5050_pointing_device_driver = {
+ .init = adns5050_init,
+ .get_report = adns5050_get_report,
+ .set_cpi = adns5050_set_cpi,
+ .get_cpi = adns5050_get_cpi,
+};
+
static bool powered_down = false;
void adns5050_init(void) {
@@ -226,3 +234,15 @@ void adns5050_power_down(void) {
adns5050_write_reg(REG_MOUSE_CONTROL, 0b10);
}
}
+
+report_mouse_t adns5050_get_report(report_mouse_t mouse_report) {
+ report_adns5050_t data = adns5050_read_burst();
+
+ if (data.dx != 0 || data.dy != 0) {
+ pd_dprintf("Raw ] X: %d, Y: %d\n", data.dx, data.dy);
+ mouse_report.x = (mouse_xy_report_t)data.dx;
+ mouse_report.y = (mouse_xy_report_t)data.dy;
+ }
+
+ return mouse_report;
+}
diff --git a/drivers/sensors/adns5050.h b/drivers/sensors/adns5050.h
index 586f16b590b..4dfcbc3c70d 100644
--- a/drivers/sensors/adns5050.h
+++ b/drivers/sensors/adns5050.h
@@ -21,6 +21,7 @@
#include
#include
+#include "pointing_device.h"
// CPI values
// clang-format off
@@ -69,6 +70,8 @@ typedef struct {
int8_t dy;
} report_adns5050_t;
+const pointing_device_driver_t adns5050_pointing_device_driver;
+
// A bunch of functions to implement the ADNS5050-specific serial protocol.
// Note that the "serial.h" driver is insufficient, because it does not
// manually manipulate a serial clock signal.
@@ -84,3 +87,4 @@ uint16_t adns5050_get_cpi(void);
int8_t convert_twoscomp(uint8_t data);
bool adns5050_check_signature(void);
void adns5050_power_down(void);
+report_mouse_t adns5050_get_report(report_mouse_t mouse_report);
diff --git a/drivers/sensors/adns9800.c b/drivers/sensors/adns9800.c
index f4abdb50874..0dbc528351c 100644
--- a/drivers/sensors/adns9800.c
+++ b/drivers/sensors/adns9800.c
@@ -77,6 +77,13 @@
#define MSB1 0x80
// clang-format on
+const pointing_device_driver_t adns9800_pointing_device_driver = {
+ .init = adns9800_init,
+ .get_report = adns9800_get_report_driver,
+ .set_cpi = adns9800_set_cpi,
+ .get_cpi = adns9800_get_cpi,
+};
+
uint16_t __attribute__((weak)) adns9800_srom_get_length(void) {
return 0;
}
@@ -236,3 +243,12 @@ report_adns9800_t adns9800_get_report(void) {
return report;
}
+
+report_mouse_t adns9800_get_report_driver(report_mouse_t mouse_report) {
+ report_adns9800_t sensor_report = adns9800_get_report();
+
+ mouse_report.x = CONSTRAIN_HID_XY(sensor_report.x);
+ mouse_report.y = CONSTRAIN_HID_XY(sensor_report.y);
+
+ return mouse_report;
+}
diff --git a/drivers/sensors/adns9800.h b/drivers/sensors/adns9800.h
index 3f1a005789f..023f31b1323 100644
--- a/drivers/sensors/adns9800.h
+++ b/drivers/sensors/adns9800.h
@@ -17,6 +17,7 @@
#pragma once
#include
+#include "pointing_device.h"
#ifndef ADNS9800_CPI
# define ADNS9800_CPI 1600
@@ -60,6 +61,8 @@ typedef struct {
int16_t y;
} report_adns9800_t;
+const pointing_device_driver_t adns9800_pointing_device_driver;
+
void adns9800_init(void);
config_adns9800_t adns9800_get_config(void);
void adns9800_set_config(config_adns9800_t);
@@ -67,3 +70,4 @@ uint16_t adns9800_get_cpi(void);
void adns9800_set_cpi(uint16_t cpi);
/* Reads and clears the current delta values on the ADNS sensor */
report_adns9800_t adns9800_get_report(void);
+report_mouse_t adns9800_get_report_driver(report_mouse_t mouse_report);
diff --git a/drivers/sensors/analog_joystick.c b/drivers/sensors/analog_joystick.c
index 15b35a45f25..93bbaa1b51b 100644
--- a/drivers/sensors/analog_joystick.c
+++ b/drivers/sensors/analog_joystick.c
@@ -20,6 +20,14 @@
#include "wait.h"
#include "timer.h"
#include
+#include "pointing_device_internal.h"
+
+const pointing_device_driver_t analog_joystick_pointing_device_driver = {
+ .init = analog_joystick_init,
+ .get_report = analog_joystick_get_report,
+ .set_cpi = NULL,
+ .get_cpi = NULL,
+};
// Set Parameters
#ifndef ANALOG_JOYSTICK_AUTO_AXIS
@@ -145,3 +153,16 @@ void analog_joystick_init(void) {
maxAxisValues[1] = yOrigin + 100;
#endif
}
+
+report_mouse_t analog_joystick_get_report(report_mouse_t mouse_report) {
+ report_analog_joystick_t data = analog_joystick_read();
+
+ pd_dprintf("Raw ] X: %d, Y: %d\n", data.x, data.y);
+
+ mouse_report.x = data.x;
+ mouse_report.y = data.y;
+
+ mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, data.button, POINTING_DEVICE_BUTTON1);
+
+ return mouse_report;
+}
diff --git a/drivers/sensors/analog_joystick.h b/drivers/sensors/analog_joystick.h
index 6892a08817f..c84da83db13 100644
--- a/drivers/sensors/analog_joystick.h
+++ b/drivers/sensors/analog_joystick.h
@@ -18,6 +18,7 @@
#include
#include
+#include "pointing_device.h"
#ifndef ANALOG_JOYSTICK_X_AXIS_PIN
# error No pin specified for X Axis
@@ -42,6 +43,8 @@
# define ANALOG_JOYSTICK_SPEED_MAX 2
#endif
+const pointing_device_driver_t analog_joystick_pointing_device_driver;
+
typedef struct {
int8_t x;
int8_t y;
@@ -49,3 +52,4 @@ typedef struct {
} report_analog_joystick_t;
report_analog_joystick_t analog_joystick_read(void);
void analog_joystick_init(void);
+report_mouse_t analog_joystick_get_report(report_mouse_t mouse_report);
diff --git a/drivers/sensors/azoteq_iqs5xx.c b/drivers/sensors/azoteq_iqs5xx.c
index 367873eb062..1bb64f19844 100644
--- a/drivers/sensors/azoteq_iqs5xx.c
+++ b/drivers/sensors/azoteq_iqs5xx.c
@@ -98,6 +98,13 @@
#define AZOTEQ_IQS5XX_INCH_TO_RESOLUTION_Y(inch) (DIVIDE_UNSIGNED_ROUND((inch) * (uint32_t)AZOTEQ_IQS5XX_HEIGHT_MM * 10, 254))
#define AZOTEQ_IQS5XX_RESOLUTION_Y_TO_INCH(px) (DIVIDE_UNSIGNED_ROUND((px) * (uint32_t)254, AZOTEQ_IQS5XX_HEIGHT_MM * 10))
+const pointing_device_driver_t azoteq_iqs5xx_pointing_device_driver = {
+ .init = azoteq_iqs5xx_init,
+ .get_report = azoteq_iqs5xx_get_report,
+ .set_cpi = azoteq_iqs5xx_set_cpi,
+ .get_cpi = azoteq_iqs5xx_get_cpi,
+};
+
static uint16_t azoteq_iqs5xx_product_number = AZOTEQ_IQS5XX_UNKNOWN;
static struct {
@@ -312,3 +319,105 @@ void azoteq_iqs5xx_setup_resolution(void) {
azoteq_iqs5xx_device_resolution_t.resolution_y = AZOTEQ_IQS5XX_RESOLUTION_Y;
#endif
}
+
+static i2c_status_t azoteq_iqs5xx_init_status = 1;
+
+void azoteq_iqs5xx_init(void) {
+ i2c_init();
+ azoteq_iqs5xx_wake();
+ azoteq_iqs5xx_reset_suspend(true, false, true);
+ wait_ms(100);
+ azoteq_iqs5xx_wake();
+ if (azoteq_iqs5xx_get_product() != AZOTEQ_IQS5XX_UNKNOWN) {
+ azoteq_iqs5xx_setup_resolution();
+ azoteq_iqs5xx_init_status = azoteq_iqs5xx_set_report_rate(AZOTEQ_IQS5XX_REPORT_RATE, AZOTEQ_IQS5XX_ACTIVE, false);
+ azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_event_mode(false, false);
+ azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_reati(true, false);
+#if defined(AZOTEQ_IQS5XX_ROTATION_90)
+ azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_xy_config(false, true, true, true, false);
+#elif defined(AZOTEQ_IQS5XX_ROTATION_180)
+ azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_xy_config(true, true, false, true, false);
+#elif defined(AZOTEQ_IQS5XX_ROTATION_270)
+ azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_xy_config(true, false, true, true, false);
+#else
+ azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_xy_config(false, false, false, true, false);
+#endif
+ azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_gesture_config(true);
+ wait_ms(AZOTEQ_IQS5XX_REPORT_RATE + 1);
+ }
+};
+
+report_mouse_t azoteq_iqs5xx_get_report(report_mouse_t mouse_report) {
+ report_mouse_t temp_report = {0};
+ static uint8_t previous_button_state = 0;
+ static uint8_t read_error_count = 0;
+
+ if (azoteq_iqs5xx_init_status == I2C_STATUS_SUCCESS) {
+ azoteq_iqs5xx_base_data_t base_data = {0};
+#if !defined(POINTING_DEVICE_MOTION_PIN)
+ azoteq_iqs5xx_wake();
+#endif
+ i2c_status_t status = azoteq_iqs5xx_get_base_data(&base_data);
+ bool ignore_movement = false;
+
+ if (status == I2C_STATUS_SUCCESS) {
+ // pd_dprintf("IQS5XX - previous cycle time: %d \n", base_data.previous_cycle_time);
+ read_error_count = 0;
+ if (base_data.gesture_events_0.single_tap || base_data.gesture_events_0.press_and_hold) {
+ pd_dprintf("IQS5XX - Single tap/hold.\n");
+ temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON1);
+ } else if (base_data.gesture_events_1.two_finger_tap) {
+ pd_dprintf("IQS5XX - Two finger tap.\n");
+ temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON2);
+ } else if (base_data.gesture_events_0.swipe_x_neg) {
+ pd_dprintf("IQS5XX - X-.\n");
+ temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON4);
+ ignore_movement = true;
+ } else if (base_data.gesture_events_0.swipe_x_pos) {
+ pd_dprintf("IQS5XX - X+.\n");
+ temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON5);
+ ignore_movement = true;
+ } else if (base_data.gesture_events_0.swipe_y_neg) {
+ pd_dprintf("IQS5XX - Y-.\n");
+ temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON6);
+ ignore_movement = true;
+ } else if (base_data.gesture_events_0.swipe_y_pos) {
+ pd_dprintf("IQS5XX - Y+.\n");
+ temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON3);
+ ignore_movement = true;
+ } else if (base_data.gesture_events_1.zoom) {
+ if (AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.x.h, base_data.x.l) < 0) {
+ pd_dprintf("IQS5XX - Zoom out.\n");
+ temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON7);
+ } else if (AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.x.h, base_data.x.l) > 0) {
+ pd_dprintf("IQS5XX - Zoom in.\n");
+ temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON8);
+ }
+ } else if (base_data.gesture_events_1.scroll) {
+ pd_dprintf("IQS5XX - Scroll.\n");
+ temp_report.h = CONSTRAIN_HID(AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.x.h, base_data.x.l));
+ temp_report.v = CONSTRAIN_HID(AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.y.h, base_data.y.l));
+ }
+ if (base_data.number_of_fingers == 1 && !ignore_movement) {
+ temp_report.x = CONSTRAIN_HID_XY(AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.x.h, base_data.x.l));
+ temp_report.y = CONSTRAIN_HID_XY(AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.y.h, base_data.y.l));
+ }
+
+ previous_button_state = temp_report.buttons;
+
+ } else {
+ if (read_error_count > 10) {
+ read_error_count = 0;
+ previous_button_state = 0;
+ } else {
+ read_error_count++;
+ }
+ temp_report.buttons = previous_button_state;
+ pd_dprintf("IQS5XX - get report failed: %d \n", status);
+ }
+ } else {
+ pd_dprintf("IQS5XX - Init failed: %d \n", azoteq_iqs5xx_init_status);
+ }
+
+ return temp_report;
+}
diff --git a/drivers/sensors/azoteq_iqs5xx.h b/drivers/sensors/azoteq_iqs5xx.h
index 704ec2bab3b..4190fe470c7 100644
--- a/drivers/sensors/azoteq_iqs5xx.h
+++ b/drivers/sensors/azoteq_iqs5xx.h
@@ -176,6 +176,8 @@ typedef struct {
# define POINTING_DEVICE_TASK_THROTTLE_MS AZOTEQ_IQS5XX_REPORT_RATE
#endif
+const pointing_device_driver_t azoteq_iqs5xx_pointing_device_driver;
+
void azoteq_iqs5xx_init(void);
i2c_status_t azoteq_iqs5xx_wake(void);
report_mouse_t azoteq_iqs5xx_get_report(report_mouse_t mouse_report);
diff --git a/drivers/sensors/cirque_pinnacle.c b/drivers/sensors/cirque_pinnacle.c
index 9afc9df8044..893cb98bf05 100644
--- a/drivers/sensors/cirque_pinnacle.c
+++ b/drivers/sensors/cirque_pinnacle.c
@@ -4,6 +4,7 @@
// refer to documentation: Gen2 and Gen3 (Pinnacle ASIC) at https://www.cirque.com/documentation
#include "cirque_pinnacle.h"
+#include "cirque_pinnacle_gestures.h"
#include "wait.h"
#include "timer.h"
@@ -350,3 +351,144 @@ pinnacle_data_t cirque_pinnacle_read_data(void) {
result.valid = true;
return result;
}
+
+#ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE
+static bool cursor_glide_enable = true;
+
+static cursor_glide_context_t glide = {.config = {
+ .coef = 102, /* Good default friction coef */
+ .interval = 10, /* 100sps */
+ .trigger_px = 10, /* Default threshold in case of hover, set to 0 if you'd like */
+ }};
+
+void cirque_pinnacle_enable_cursor_glide(bool enable) {
+ cursor_glide_enable = enable;
+}
+
+void cirque_pinnacle_configure_cursor_glide(float trigger_px) {
+ glide.config.trigger_px = trigger_px;
+}
+#endif
+
+#if CIRQUE_PINNACLE_POSITION_MODE
+
+# ifdef POINTING_DEVICE_AUTO_MOUSE_ENABLE
+static bool is_touch_down;
+
+bool auto_mouse_activation(report_mouse_t mouse_report) {
+ return is_touch_down || mouse_report.x != 0 || mouse_report.y != 0 || mouse_report.h != 0 || mouse_report.v != 0 || mouse_report.buttons;
+}
+# endif
+
+report_mouse_t cirque_pinnacle_get_report(report_mouse_t mouse_report) {
+ uint16_t scale = cirque_pinnacle_get_scale();
+ pinnacle_data_t touchData = cirque_pinnacle_read_data();
+ mouse_xy_report_t report_x = 0, report_y = 0;
+ static uint16_t x = 0, y = 0, last_scale = 0;
+
+# if defined(CIRQUE_PINNACLE_TAP_ENABLE)
+ mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, false, POINTING_DEVICE_BUTTON1);
+# endif
+# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE
+ cursor_glide_t glide_report = {0};
+
+ if (cursor_glide_enable) {
+ glide_report = cursor_glide_check(&glide);
+ }
+# endif
+
+ if (!touchData.valid) {
+# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE
+ if (cursor_glide_enable && glide_report.valid) {
+ report_x = glide_report.dx;
+ report_y = glide_report.dy;
+ goto mouse_report_update;
+ }
+# endif
+ return mouse_report;
+ }
+
+ if (touchData.touchDown) {
+ pd_dprintf("cirque_pinnacle touchData x=%4d y=%4d z=%2d\n", touchData.xValue, touchData.yValue, touchData.zValue);
+ }
+
+# ifdef POINTING_DEVICE_AUTO_MOUSE_ENABLE
+ is_touch_down = touchData.touchDown;
+# endif
+
+ // Scale coordinates to arbitrary X, Y resolution
+ cirque_pinnacle_scale_data(&touchData, scale, scale);
+
+ if (!cirque_pinnacle_gestures(&mouse_report, touchData)) {
+ if (last_scale && scale == last_scale && x && y && touchData.xValue && touchData.yValue) {
+ report_x = CONSTRAIN_HID_XY((int16_t)(touchData.xValue - x));
+ report_y = CONSTRAIN_HID_XY((int16_t)(touchData.yValue - y));
+ }
+ x = touchData.xValue;
+ y = touchData.yValue;
+ last_scale = scale;
+
+# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE
+ if (cursor_glide_enable) {
+ if (touchData.touchDown) {
+ cursor_glide_update(&glide, report_x, report_y, touchData.zValue);
+ } else if (!glide_report.valid) {
+ glide_report = cursor_glide_start(&glide);
+ if (glide_report.valid) {
+ report_x = glide_report.dx;
+ report_y = glide_report.dy;
+ }
+ }
+ }
+# endif
+ }
+
+# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE
+mouse_report_update:
+# endif
+ mouse_report.x = report_x;
+ mouse_report.y = report_y;
+
+ return mouse_report;
+}
+
+uint16_t cirque_pinnacle_get_cpi(void) {
+ return CIRQUE_PINNACLE_PX_TO_INCH(cirque_pinnacle_get_scale());
+}
+void cirque_pinnacle_set_cpi(uint16_t cpi) {
+ cirque_pinnacle_set_scale(CIRQUE_PINNACLE_INCH_TO_PX(cpi));
+}
+
+// clang-format off
+const pointing_device_driver_t cirque_pinnacle_pointing_device_driver = {
+ .init = cirque_pinnacle_init,
+ .get_report = cirque_pinnacle_get_report,
+ .set_cpi = cirque_pinnacle_set_cpi,
+ .get_cpi = cirque_pinnacle_get_cpi
+};
+// clang-format on
+#else
+report_mouse_t cirque_pinnacle_get_report(report_mouse_t mouse_report) {
+ pinnacle_data_t touchData = cirque_pinnacle_read_data();
+
+ // Scale coordinates to arbitrary X, Y resolution
+ cirque_pinnacle_scale_data(&touchData, cirque_pinnacle_get_scale(), cirque_pinnacle_get_scale());
+
+ if (touchData.valid) {
+ mouse_report.buttons = touchData.buttons;
+ mouse_report.x = CONSTRAIN_HID_XY(touchData.xDelta);
+ mouse_report.y = CONSTRAIN_HID_XY(touchData.yDelta);
+ mouse_report.v = touchData.wheelCount;
+ }
+ return mouse_report;
+}
+
+// clang-format off
+const pointing_device_driver_t cirque_pinnacle_pointing_device_driver = {
+ .init = cirque_pinnacle_init,
+ .get_report = cirque_pinnacle_get_report,
+ .set_cpi = cirque_pinnacle_set_scale,
+ .get_cpi = cirque_pinnacle_get_scale
+};
+// clang-format on
+#endif
diff --git a/drivers/sensors/cirque_pinnacle.h b/drivers/sensors/cirque_pinnacle.h
index 8717b329911..1a17e539a40 100644
--- a/drivers/sensors/cirque_pinnacle.h
+++ b/drivers/sensors/cirque_pinnacle.h
@@ -6,6 +6,7 @@
#include
#include
#include "pointing_device_internal.h"
+#include "pointing_device.h"
#ifndef CIRQUE_PINNACLE_TIMEOUT
# define CIRQUE_PINNACLE_TIMEOUT 20 // I2C timeout in milliseconds
@@ -109,6 +110,10 @@ typedef struct {
#endif
} pinnacle_data_t;
+#define cirque_pinnacle_i2c_pointing_device_driver cirque_pinnacle_pointing_device_driver
+#define cirque_pinnacle_spi_pointing_device_driver cirque_pinnacle_pointing_device_driver
+const pointing_device_driver_t cirque_pinnacle_pointing_device_driver;
+
void cirque_pinnacle_init(void);
void cirque_pinnacle_calibrate(void);
void cirque_pinnacle_cursor_smoothing(bool enable);
@@ -116,3 +121,6 @@ pinnacle_data_t cirque_pinnacle_read_data(void);
void cirque_pinnacle_scale_data(pinnacle_data_t* coordinates, uint16_t xResolution, uint16_t yResolution);
uint16_t cirque_pinnacle_get_scale(void);
void cirque_pinnacle_set_scale(uint16_t scale);
+uint16_t cirque_pinnacle_get_cpi(void);
+void cirque_pinnacle_set_cpi(uint16_t cpi);
+report_mouse_t cirque_pinnacle_get_report(report_mouse_t mouse_report);
diff --git a/drivers/sensors/paw3204.c b/drivers/sensors/paw3204.c
index 28c47522ed5..475821f175c 100644
--- a/drivers/sensors/paw3204.c
+++ b/drivers/sensors/paw3204.c
@@ -20,6 +20,7 @@
#include "wait.h"
#include "debug.h"
#include "gpio.h"
+#include "pointing_device_internal.h"
#define REG_PID1 0x00
#define REG_PID2 0x01
@@ -50,6 +51,13 @@ void paw3204_serial_write(uint8_t reg_addr);
uint8_t paw3204_read_reg(uint8_t reg_addr);
void paw3204_write_reg(uint8_t reg_addr, uint8_t data);
+const pointing_device_driver_t paw3204_pointing_device_driver = {
+ .init = paw3204_init,
+ .get_report = paw3204_get_report,
+ .set_cpi = paw3204_set_cpi,
+ .get_cpi = paw3204_get_cpi,
+};
+
void paw3204_init(void) {
gpio_set_pin_output(PAW3204_SCLK_PIN); // setclockpin to output
gpio_set_pin_input_high(PAW3204_SDIO_PIN); // set datapin input high
@@ -170,3 +178,15 @@ uint16_t paw3204_get_cpi(void) {
uint8_t read_pid_paw3204(void) {
return paw3204_read_reg(REG_PID1);
}
+
+report_mouse_t paw3204_get_report(report_mouse_t mouse_report) {
+ report_paw3204_t data = paw3204_read();
+ if (data.isMotion) {
+ pd_dprintf("Raw ] X: %d, Y: %d\n", data.x, data.y);
+
+ mouse_report.x = data.x;
+ mouse_report.y = data.y;
+ }
+
+ return mouse_report;
+}
diff --git a/drivers/sensors/paw3204.h b/drivers/sensors/paw3204.h
index 7f487d90dce..a4bb8e16a67 100644
--- a/drivers/sensors/paw3204.h
+++ b/drivers/sensors/paw3204.h
@@ -18,6 +18,7 @@
#include
#include
+#include "pointing_device.h"
#ifndef PAW3204_SCLK_PIN
# ifdef POINTING_DEVICE_SCLK_PIN
@@ -40,6 +41,8 @@ typedef struct {
bool isMotion;
} report_paw3204_t;
+const pointing_device_driver_t paw3204_pointing_device_driver;
+
/**
* @brief Initializes the sensor so it is in a working state and ready to
* be polled for data.
@@ -74,3 +77,5 @@ void paw3204_set_cpi(uint16_t cpi);
* @return uint16_t Current CPI value of the sensor
*/
uint16_t paw3204_get_cpi(void);
+
+report_mouse_t paw3204_get_report(report_mouse_t mouse_report);
diff --git a/drivers/sensors/pimoroni_trackball.c b/drivers/sensors/pimoroni_trackball.c
index 9c6d26d73de..afbe3d5b77f 100644
--- a/drivers/sensors/pimoroni_trackball.c
+++ b/drivers/sensors/pimoroni_trackball.c
@@ -33,6 +33,13 @@
static uint16_t precision = 128;
+const pointing_device_driver_t pimoroni_trackball_pointing_device_driver = {
+ .init = pimoroni_trackball_device_init,
+ .get_report = pimoroni_trackball_get_report,
+ .set_cpi = pimoroni_trackball_set_cpi,
+ .get_cpi = pimoroni_trackball_get_cpi,
+};
+
uint16_t pimoroni_trackball_get_cpi(void) {
return (precision * 125);
}
@@ -61,8 +68,8 @@ void pimoroni_trackball_set_rgbw(uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
pd_dprintf("Trackball RGBW i2c_status_t: %d\n", status);
}
-i2c_status_t read_pimoroni_trackball(pimoroni_data_t* data) {
- i2c_status_t status = i2c_read_register(PIMORONI_TRACKBALL_ADDRESS << 1, PIMORONI_TRACKBALL_REG_LEFT, (uint8_t*)data, sizeof(*data), PIMORONI_TRACKBALL_TIMEOUT);
+i2c_status_t read_pimoroni_trackball(pimoroni_data_t *data) {
+ i2c_status_t status = i2c_read_register(PIMORONI_TRACKBALL_ADDRESS << 1, PIMORONI_TRACKBALL_REG_LEFT, (uint8_t *)data, sizeof(*data), PIMORONI_TRACKBALL_TIMEOUT);
#ifdef POINTING_DEVICE_DEBUG
static uint16_t d_timer;
@@ -92,3 +99,50 @@ int16_t pimoroni_trackball_get_offsets(uint8_t negative_dir, uint8_t positive_di
uint16_t magnitude = (scale * offset * offset * precision) >> 7;
return isnegative ? -(int16_t)(magnitude) : (int16_t)(magnitude);
}
+
+mouse_xy_report_t pimoroni_trackball_adapt_values(xy_clamp_range_t *offset) {
+ if (*offset > XY_REPORT_MAX) {
+ *offset -= XY_REPORT_MAX;
+ return (mouse_xy_report_t)XY_REPORT_MAX;
+ } else if (*offset < XY_REPORT_MIN) {
+ *offset += XY_REPORT_MAX;
+ return (mouse_xy_report_t)XY_REPORT_MIN;
+ } else {
+ mouse_xy_report_t temp_return = *offset;
+ *offset = 0;
+ return temp_return;
+ }
+}
+
+report_mouse_t pimoroni_trackball_get_report(report_mouse_t mouse_report) {
+ static uint16_t debounce = 0;
+ static uint8_t error_count = 0;
+ pimoroni_data_t pimoroni_data = {0};
+ static xy_clamp_range_t x_offset = 0, y_offset = 0;
+
+ if (error_count < PIMORONI_TRACKBALL_ERROR_COUNT) {
+ i2c_status_t status = read_pimoroni_trackball(&pimoroni_data);
+
+ if (status == I2C_STATUS_SUCCESS) {
+ error_count = 0;
+
+ if (!(pimoroni_data.click & 128)) {
+ mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, false, POINTING_DEVICE_BUTTON1);
+ if (!debounce) {
+ x_offset += pimoroni_trackball_get_offsets(pimoroni_data.right, pimoroni_data.left, PIMORONI_TRACKBALL_SCALE);
+ y_offset += pimoroni_trackball_get_offsets(pimoroni_data.down, pimoroni_data.up, PIMORONI_TRACKBALL_SCALE);
+ mouse_report.x = pimoroni_trackball_adapt_values(&x_offset);
+ mouse_report.y = pimoroni_trackball_adapt_values(&y_offset);
+ } else {
+ debounce--;
+ }
+ } else {
+ mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, true, POINTING_DEVICE_BUTTON1);
+ debounce = PIMORONI_TRACKBALL_DEBOUNCE_CYCLES;
+ }
+ } else {
+ error_count++;
+ }
+ }
+ return mouse_report;
+}
diff --git a/drivers/sensors/pimoroni_trackball.h b/drivers/sensors/pimoroni_trackball.h
index 749f381bbd6..1904214a74a 100644
--- a/drivers/sensors/pimoroni_trackball.h
+++ b/drivers/sensors/pimoroni_trackball.h
@@ -19,6 +19,7 @@
#include
#include "report.h"
#include "i2c_master.h"
+#include "pointing_device.h"
#ifndef PIMORONI_TRACKBALL_ADDRESS
# define PIMORONI_TRACKBALL_ADDRESS 0x0A
@@ -49,9 +50,12 @@ typedef struct {
uint8_t click;
} pimoroni_data_t;
-void pimoroni_trackball_device_init(void);
-void pimoroni_trackball_set_rgbw(uint8_t red, uint8_t green, uint8_t blue, uint8_t white);
-int16_t pimoroni_trackball_get_offsets(uint8_t negative_dir, uint8_t positive_dir, uint8_t scale);
-uint16_t pimoroni_trackball_get_cpi(void);
-void pimoroni_trackball_set_cpi(uint16_t cpi);
-i2c_status_t read_pimoroni_trackball(pimoroni_data_t* data);
+const pointing_device_driver_t pimoroni_trackball_pointing_device_driver;
+
+void pimoroni_trackball_device_init(void);
+void pimoroni_trackball_set_rgbw(uint8_t red, uint8_t green, uint8_t blue, uint8_t white);
+int16_t pimoroni_trackball_get_offsets(uint8_t negative_dir, uint8_t positive_dir, uint8_t scale);
+uint16_t pimoroni_trackball_get_cpi(void);
+void pimoroni_trackball_set_cpi(uint16_t cpi);
+i2c_status_t read_pimoroni_trackball(pimoroni_data_t* data);
+report_mouse_t pimoroni_trackball_get_report(report_mouse_t mouse_report);
diff --git a/drivers/sensors/pmw3320.c b/drivers/sensors/pmw3320.c
index f19fbfd1ab4..74fefd4c53d 100644
--- a/drivers/sensors/pmw3320.c
+++ b/drivers/sensors/pmw3320.c
@@ -21,6 +21,14 @@
#include "wait.h"
#include "debug.h"
#include "gpio.h"
+#include "pointing_device_internal.h"
+
+const pointing_device_driver_t pmw3320_pointing_device_drivera = {
+ .init = pmw3320_init,
+ .get_report = pmw3320_get_report,
+ .set_cpi = pmw3320_set_cpi,
+ .get_cpi = pmw3320_get_cpi,
+};
void pmw3320_init(void) {
// Initialize sensor serial pins.
@@ -190,3 +198,15 @@ bool pmw3320_check_signature(void) {
return (pid == 0x3b && pid2 == 0xc4);
}
+
+report_mouse_t pmw3320_get_report(report_mouse_t mouse_report) {
+ report_pmw3320_t data = pmw3320_read_burst();
+
+ if (data.dx != 0 || data.dy != 0) {
+ pd_dprintf("Raw ] X: %d, Y: %d\n", data.dx, data.dy);
+ mouse_report.x = (mouse_xy_report_t)data.dx;
+ mouse_report.y = (mouse_xy_report_t)data.dy;
+ }
+
+ return mouse_report;
+}
diff --git a/drivers/sensors/pmw3320.h b/drivers/sensors/pmw3320.h
index a1fd5469196..cfff25bd8a6 100644
--- a/drivers/sensors/pmw3320.h
+++ b/drivers/sensors/pmw3320.h
@@ -21,6 +21,7 @@
#include
#include
+#include "pointing_device.h"
#define constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
@@ -54,6 +55,8 @@ typedef struct {
int8_t dy;
} report_pmw3320_t;
+const pointing_device_driver_t pmw3320_pointing_device_driver;
+
// A bunch of functions to implement the PMW3320-specific serial protocol.
// Mostly taken from ADNS5050 driver.
// Note that the "serial.h" driver is insufficient, because it does not
@@ -69,6 +72,7 @@ void pmw3320_set_cpi(uint16_t cpi);
uint16_t pmw3320_get_cpi(void);
int8_t convert_twoscomp(uint8_t data);
bool pmw3320_check_signature(void);
+report_mouse_t pmw3320_get_report(report_mouse_t mouse_report);
#if !defined(PMW3320_CPI)
# define PMW3320_CPI 1000
diff --git a/drivers/sensors/pmw33xx_common.c b/drivers/sensors/pmw33xx_common.c
index b4fa727af9b..f3285ec4972 100644
--- a/drivers/sensors/pmw33xx_common.c
+++ b/drivers/sensors/pmw33xx_common.c
@@ -26,6 +26,13 @@ static bool in_burst_right[ARRAY_SIZE(cs_pins_right)] = {0};
bool __attribute__((cold)) pmw33xx_upload_firmware(uint8_t sensor);
bool __attribute__((cold)) pmw33xx_check_signature(uint8_t sensor);
+const pointing_device_driver_t pmw33xx_pointing_device_driver = {
+ .init = pmw33xx_init_wrapper,
+ .get_report = pmw33xx_get_report,
+ .set_cpi = pmw33xx_set_cpi_wrapper,
+ .get_cpi = pmw33xx_get_cpi_wrapper,
+};
+
uint16_t __attribute__((weak)) pmw33xx_srom_get_length(void) {
return 0;
}
@@ -228,3 +235,38 @@ pmw33xx_report_t pmw33xx_read_burst(uint8_t sensor) {
return report;
}
+
+void pmw33xx_init_wrapper(void) {
+ pmw33xx_init(0);
+}
+
+void pmw33xx_set_cpi_wrapper(uint16_t cpi) {
+ pmw33xx_set_cpi(0, cpi);
+}
+
+uint16_t pmw33xx_get_cpi_wrapper(void) {
+ return pmw33xx_get_cpi(0);
+}
+
+report_mouse_t pmw33xx_get_report(report_mouse_t mouse_report) {
+ pmw33xx_report_t report = pmw33xx_read_burst(0);
+ static bool in_motion = false;
+
+ if (report.motion.b.is_lifted) {
+ return mouse_report;
+ }
+
+ if (!report.motion.b.is_motion) {
+ in_motion = false;
+ return mouse_report;
+ }
+
+ if (!in_motion) {
+ in_motion = true;
+ pd_dprintf("PWM3360 (0): starting motion\n");
+ }
+
+ mouse_report.x = CONSTRAIN_HID_XY(report.delta_x);
+ mouse_report.y = CONSTRAIN_HID_XY(report.delta_y);
+ return mouse_report;
+}
diff --git a/drivers/sensors/pmw33xx_common.h b/drivers/sensors/pmw33xx_common.h
index b30ee3d5966..22e35c33275 100644
--- a/drivers/sensors/pmw33xx_common.h
+++ b/drivers/sensors/pmw33xx_common.h
@@ -14,6 +14,7 @@
#include
#include "spi_master.h"
#include "util.h"
+#include "pointing_device.h"
#if defined(POINTING_DEVICE_DRIVER_pmw3360)
# include "pmw3360.h"
@@ -102,6 +103,10 @@ _Static_assert(sizeof((pmw33xx_report_t){0}.motion) == 1, "pmw33xx_report_t.moti
#define CONSTRAIN(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
+#define pmw3360_pointing_device_driver pmw33xx_pointing_device_driver;
+#define pmw3389_pointing_device_driver pmw33xx_pointing_device_driver;
+const pointing_device_driver_t pmw33xx_pointing_device_driver;
+
/**
* @brief Initializes the given sensor so it is in a working state and ready to
* be polled for data.
@@ -170,3 +175,8 @@ uint8_t pmw33xx_read(uint8_t sensor, uint8_t reg_addr);
* @return false Write failed, do not proceed operation
*/
bool pmw33xx_write(uint8_t sensor, uint8_t reg_addr, uint8_t data);
+
+void pmw33xx_init_wrapper(void);
+void pmw33xx_set_cpi_wrapper(uint16_t cpi);
+uint16_t pmw33xx_get_cpi_wrapper(void);
+report_mouse_t pmw33xx_get_report(report_mouse_t mouse_report);
diff --git a/keyboards/bastardkb/charybdis/3x5/blackpill/config.h b/keyboards/bastardkb/charybdis/3x5/blackpill/config.h
index 0467a1261f4..bd1e0fe31ec 100644
--- a/keyboards/bastardkb/charybdis/3x5/blackpill/config.h
+++ b/keyboards/bastardkb/charybdis/3x5/blackpill/config.h
@@ -29,7 +29,6 @@
#define WS2812_EXTERNAL_PULLUP
#define WS2812_PWM_DMA_STREAM STM32_DMA1_STREAM1
#define WS2812_PWM_DMA_CHANNEL 3
-#define WS2812_PWM_TARGET_PERIOD 800000
/* Serial configuration for split keyboard. */
#define SERIAL_USART_TX_PIN A9
diff --git a/keyboards/bastardkb/charybdis/3x6/blackpill/config.h b/keyboards/bastardkb/charybdis/3x6/blackpill/config.h
index b41a1d3f574..e1365a109d9 100644
--- a/keyboards/bastardkb/charybdis/3x6/blackpill/config.h
+++ b/keyboards/bastardkb/charybdis/3x6/blackpill/config.h
@@ -27,7 +27,6 @@
#define WS2812_EXTERNAL_PULLUP
#define WS2812_PWM_DMA_STREAM STM32_DMA1_STREAM1
#define WS2812_PWM_DMA_CHANNEL 3
-#define WS2812_PWM_TARGET_PERIOD 800000
/* Serial configuration for split keyboard. */
#define SERIAL_USART_TX_PIN A9
diff --git a/keyboards/bastardkb/charybdis/4x6/blackpill/config.h b/keyboards/bastardkb/charybdis/4x6/blackpill/config.h
index 0467a1261f4..bd1e0fe31ec 100644
--- a/keyboards/bastardkb/charybdis/4x6/blackpill/config.h
+++ b/keyboards/bastardkb/charybdis/4x6/blackpill/config.h
@@ -29,7 +29,6 @@
#define WS2812_EXTERNAL_PULLUP
#define WS2812_PWM_DMA_STREAM STM32_DMA1_STREAM1
#define WS2812_PWM_DMA_CHANNEL 3
-#define WS2812_PWM_TARGET_PERIOD 800000
/* Serial configuration for split keyboard. */
#define SERIAL_USART_TX_PIN A9
diff --git a/keyboards/bastardkb/charybdis/charybdis.c b/keyboards/bastardkb/charybdis/charybdis.c
index 0ee5c3eed97..2251b247581 100644
--- a/keyboards/bastardkb/charybdis/charybdis.c
+++ b/keyboards/bastardkb/charybdis/charybdis.c
@@ -393,7 +393,6 @@ bool shutdown_kb(bool jump_to_bootloader) {
rgblight_setrgb(RGB_RED);
#endif // RGBLIGHT_ENABLE
#ifdef RGB_MATRIX_ENABLE
- void rgb_matrix_update_pwm_buffers(void);
rgb_matrix_set_color_all(RGB_RED);
rgb_matrix_update_pwm_buffers();
#endif // RGB_MATRIX_ENABLE
diff --git a/keyboards/bastardkb/dilemma/dilemma.c b/keyboards/bastardkb/dilemma/dilemma.c
index 7c87fdcadd6..b406e265261 100644
--- a/keyboards/bastardkb/dilemma/dilemma.c
+++ b/keyboards/bastardkb/dilemma/dilemma.c
@@ -354,7 +354,6 @@ bool shutdown_kb(bool jump_to_bootloader) {
rgblight_setrgb(RGB_RED);
#endif // RGBLIGHT_ENABLE
#ifdef RGB_MATRIX_ENABLE
- void rgb_matrix_update_pwm_buffers(void);
rgb_matrix_set_color_all(RGB_RED);
rgb_matrix_update_pwm_buffers();
#endif // RGB_MATRIX_ENABLE
diff --git a/keyboards/bastardkb/scylla/blackpill/config.h b/keyboards/bastardkb/scylla/blackpill/config.h
index 1d86b474ee9..bf7879edbee 100644
--- a/keyboards/bastardkb/scylla/blackpill/config.h
+++ b/keyboards/bastardkb/scylla/blackpill/config.h
@@ -29,7 +29,6 @@
#define WS2812_EXTERNAL_PULLUP
#define WS2812_PWM_DMA_STREAM STM32_DMA1_STREAM1
#define WS2812_PWM_DMA_CHANNEL 3
-#define WS2812_PWM_TARGET_PERIOD 800000
/* Serial configuration for split keyboard. */
#define SERIAL_USART_TX_PIN A9
diff --git a/keyboards/bastardkb/skeletyl/blackpill/config.h b/keyboards/bastardkb/skeletyl/blackpill/config.h
index 1d86b474ee9..bf7879edbee 100644
--- a/keyboards/bastardkb/skeletyl/blackpill/config.h
+++ b/keyboards/bastardkb/skeletyl/blackpill/config.h
@@ -29,7 +29,6 @@
#define WS2812_EXTERNAL_PULLUP
#define WS2812_PWM_DMA_STREAM STM32_DMA1_STREAM1
#define WS2812_PWM_DMA_CHANNEL 3
-#define WS2812_PWM_TARGET_PERIOD 800000
/* Serial configuration for split keyboard. */
#define SERIAL_USART_TX_PIN A9
diff --git a/keyboards/bastardkb/tbkmini/blackpill/config.h b/keyboards/bastardkb/tbkmini/blackpill/config.h
index 1d86b474ee9..bf7879edbee 100644
--- a/keyboards/bastardkb/tbkmini/blackpill/config.h
+++ b/keyboards/bastardkb/tbkmini/blackpill/config.h
@@ -29,7 +29,6 @@
#define WS2812_EXTERNAL_PULLUP
#define WS2812_PWM_DMA_STREAM STM32_DMA1_STREAM1
#define WS2812_PWM_DMA_CHANNEL 3
-#define WS2812_PWM_TARGET_PERIOD 800000
/* Serial configuration for split keyboard. */
#define SERIAL_USART_TX_PIN A9
diff --git a/keyboards/cannonkeys/sagittarius/keyboard.json b/keyboards/cannonkeys/sagittarius/keyboard.json
index 8f83a42984b..e64268ab53a 100644
--- a/keyboards/cannonkeys/sagittarius/keyboard.json
+++ b/keyboards/cannonkeys/sagittarius/keyboard.json
@@ -60,6 +60,14 @@
"resync": true
}
},
+ "encoder": {
+ "rotary": [
+ {"pin_a": "B12", "pin_b": "B11", "resolution": 2},
+ {"pin_a": "B12", "pin_b": "B11", "resolution": 2},
+ {"pin_a": "B12", "pin_b": "B11", "resolution": 2},
+ {"pin_a": "B12", "pin_b": "B11", "resolution": 2}
+ ]
+ },
"layouts": {
"LAYOUT_default": {
"layout": [
diff --git a/keyboards/cannonkeys/sagittarius/keymaps/default/keymap.c b/keyboards/cannonkeys/sagittarius/keymaps/default/keymap.c
index 093895bb99f..a97574c7745 100644
--- a/keyboards/cannonkeys/sagittarius/keymaps/default/keymap.c
+++ b/keyboards/cannonkeys/sagittarius/keymaps/default/keymap.c
@@ -44,3 +44,10 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
)
};
+
+#if defined(ENCODER_MAP_ENABLE)
+const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = {
+ [0] = { ENCODER_CCW_CW(KC_MS_WH_UP, KC_MS_WH_DOWN), ENCODER_CCW_CW(KC_VOLD, KC_VOLU), ENCODER_CCW_CW(UG_HUED, UG_HUEU), ENCODER_CCW_CW(UG_SATD, UG_SATU) },
+ [1] = { ENCODER_CCW_CW(UG_VALD, UG_VALU), ENCODER_CCW_CW(UG_SPDD, UG_SPDU), ENCODER_CCW_CW(UG_PREV, UG_NEXT), ENCODER_CCW_CW(KC_RIGHT, KC_LEFT) },
+};
+#endif
diff --git a/keyboards/cannonkeys/sagittarius/keymaps/default/rules.mk b/keyboards/cannonkeys/sagittarius/keymaps/default/rules.mk
new file mode 100644
index 00000000000..376fe3d8dcd
--- /dev/null
+++ b/keyboards/cannonkeys/sagittarius/keymaps/default/rules.mk
@@ -0,0 +1,2 @@
+ENCODER_ENABLE = yes
+ENCODER_MAP_ENABLE = yes
diff --git a/keyboards/cannonkeys/sagittarius/sagittarius.c b/keyboards/cannonkeys/sagittarius/sagittarius.c
new file mode 100644
index 00000000000..1000f7dd43a
--- /dev/null
+++ b/keyboards/cannonkeys/sagittarius/sagittarius.c
@@ -0,0 +1,40 @@
+// Copyright 2024 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include QMK_KEYBOARD_H
+
+#if defined(ENCODER_ENABLE) || defined(ENCODER_MAP_ENABLE)
+
+# if !defined(ENCODER_SETTLE_PIN_STATE_DELAY_US)
+# define ENCODER_SETTLE_PIN_STATE_DELAY_US 2
+# endif
+
+static pin_t matrix_row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
+
+void encoder_driver_task(void) {
+ // Set all relevant rows to output, which is different to the matrix expectations
+ for (uint8_t i = 0; i < 4; i++) {
+ gpio_set_pin_output(matrix_row_pins[i]);
+ }
+
+ // Read each encoder
+ for (uint8_t i = 0; i < 4; i++) {
+ // Set the row pin low for the corresponding encoder...
+ for (uint8_t j = 0; j < 4; j++) {
+ gpio_write_pin(matrix_row_pins[j], (i == j) ? 0 : 1);
+ }
+ // ...and let them settle.
+ wait_us(ENCODER_SETTLE_PIN_STATE_DELAY_US);
+
+ // Run the normal encoder handling
+ extern void encoder_quadrature_handle_read(uint8_t index, uint8_t pin_a_state, uint8_t pin_b_state);
+ extern uint8_t encoder_quadrature_read_pin(uint8_t index, bool pad_b);
+ encoder_quadrature_handle_read(i, encoder_quadrature_read_pin(i, false), encoder_quadrature_read_pin(i, true));
+ }
+
+ // Set all rows back to input-high as per matrix expectations
+ for (uint8_t i = 0; i < 4; i++) {
+ gpio_set_pin_input_high(matrix_row_pins[i]);
+ }
+}
+
+#endif // defined(ENCODER_ENABLE) || defined(ENCODER_MAP_ENABLE)
diff --git a/keyboards/cannonkeys/satisfaction75_hs/keyboard.json b/keyboards/cannonkeys/satisfaction75_hs/keyboard.json
index 6e8172ec028..48faa60362b 100644
--- a/keyboards/cannonkeys/satisfaction75_hs/keyboard.json
+++ b/keyboards/cannonkeys/satisfaction75_hs/keyboard.json
@@ -112,9 +112,9 @@
{"matrix": [5, 1], "x": 1.25, "y": 5.25, "w": 1.25},
{"matrix": [5, 2], "x": 2.5, "y": 5.25, "w": 1.25},
{"matrix": [5, 6], "x": 3.75, "y": 5.25, "w": 6.25},
- {"matrix": [5, 10], "x": 10, "y": 5.25, "w": 1},
- {"matrix": [5, 11], "x": 11, "y": 5.25, "w": 1},
- {"matrix": [5, 9], "x": 12, "y": 5.25, "w": 1},
+ {"matrix": [5, 10], "x": 10, "y": 5.25},
+ {"matrix": [5, 11], "x": 11, "y": 5.25},
+ {"matrix": [5, 9], "x": 12, "y": 5.25},
{"matrix": [5, 12], "x": 13.25, "y": 5.5},
{"matrix": [5, 13], "x": 14.25, "y": 5.5},
{"matrix": [5, 14], "x": 15.25, "y": 5.5}
diff --git a/keyboards/cipulot/ec_menhir/rules.mk b/keyboards/cipulot/common/common_cipulot.mk
similarity index 67%
rename from keyboards/cipulot/ec_menhir/rules.mk
rename to keyboards/cipulot/common/common_cipulot.mk
index e7d73cefc98..a1bbedab188 100644
--- a/keyboards/cipulot/ec_menhir/rules.mk
+++ b/keyboards/cipulot/common/common_cipulot.mk
@@ -2,3 +2,7 @@ CUSTOM_MATRIX = lite
ANALOG_DRIVER_REQUIRED = yes
VPATH += keyboards/cipulot/common
SRC += matrix.c ec_board.c ec_switch_matrix.c
+
+ifeq ($(strip $(VIA_ENABLE)), yes)
+ SRC += via_ec.c
+endif
diff --git a/keyboards/cipulot/common/ec_board.c b/keyboards/cipulot/common/ec_board.c
index d9ba1975893..0ccb9f6d3c3 100644
--- a/keyboards/cipulot/common/ec_board.c
+++ b/keyboards/cipulot/common/ec_board.c
@@ -17,6 +17,10 @@
#include "ec_switch_matrix.h"
#include "keyboard.h"
+#ifdef SPLIT_KEYBOARD
+# include "transactions.h"
+#endif
+
void eeconfig_init_kb(void) {
// Default values
eeprom_ec_config.actuation_mode = DEFAULT_ACTUATION_MODE;
@@ -57,8 +61,14 @@ void keyboard_post_init_kb(void) {
ec_config.rescaled_mode_0_actuation_threshold[row][col] = rescale(ec_config.mode_0_actuation_threshold, 0, 1023, ec_config.noise_floor[row][col], eeprom_ec_config.bottoming_reading[row][col]);
ec_config.rescaled_mode_0_release_threshold[row][col] = rescale(ec_config.mode_0_release_threshold, 0, 1023, ec_config.noise_floor[row][col], eeprom_ec_config.bottoming_reading[row][col]);
ec_config.rescaled_mode_1_initial_deadzone_offset[row][col] = rescale(ec_config.mode_1_initial_deadzone_offset, 0, 1023, ec_config.noise_floor[row][col], eeprom_ec_config.bottoming_reading[row][col]);
+ ec_config.rescaled_mode_1_actuation_offset[row][col] = rescale(ec_config.mode_1_actuation_offset, 0, 1023, ec_config.noise_floor[row][col], eeprom_ec_config.bottoming_reading[row][col]);
+ ec_config.rescaled_mode_1_release_offset[row][col] = rescale(ec_config.mode_1_release_offset, 0, 1023, ec_config.noise_floor[row][col], eeprom_ec_config.bottoming_reading[row][col]);
}
}
+#ifdef SPLIT_KEYBOARD
+ transaction_register_rpc(RPC_ID_VIA_CMD, via_cmd_slave_handler);
+#endif
+
keyboard_post_init_user();
}
diff --git a/keyboards/cipulot/common/ec_switch_matrix.c b/keyboards/cipulot/common/ec_switch_matrix.c
index 33123bd236e..25c745703b4 100644
--- a/keyboards/cipulot/common/ec_switch_matrix.c
+++ b/keyboards/cipulot/common/ec_switch_matrix.c
@@ -37,8 +37,14 @@ const pin_t amux_en_pins[] = AMUX_EN_PINS;
const pin_t amux_n_col_sizes[] = AMUX_COL_CHANNELS_SIZES;
const pin_t amux_n_col_channels[][AMUX_MAX_COLS_COUNT] = {AMUX_COL_CHANNELS};
+#ifdef UNUSED_POSITIONS_LIST
+const uint8_t UNUSED_POSITIONS[][2] = UNUSED_POSITIONS_LIST;
+# define UNUSED_POSITIONS_COUNT ARRAY_SIZE(UNUSED_POSITIONS)
+#endif
+
#define AMUX_SEL_PINS_COUNT ARRAY_SIZE(amux_sel_pins)
#define EXPECTED_AMUX_SEL_PINS_COUNT ceil(log2(AMUX_MAX_COLS_COUNT)
+
// Checks for the correctness of the configuration
_Static_assert(ARRAY_SIZE(amux_en_pins) == AMUX_COUNT, "AMUX_EN_PINS doesn't have the minimum number of bits required to enable all the multiplexers available");
// Check that number of select pins is enough to select all the channels
@@ -70,6 +76,16 @@ void init_amux(void) {
}
}
+// Disable all the unused rows
+void disable_unused_row(uint8_t row) {
+ // disable all the other rows apart from the current selected one
+ for (uint8_t idx = 0; idx < MATRIX_ROWS; idx++) {
+ if (idx != row) {
+ gpio_write_pin_low(row_pins[idx]);
+ }
+ }
+}
+
// Select the multiplexer channel of the specified multiplexer
void select_amux_channel(uint8_t channel, uint8_t col) {
// Get the channel for the specified multiplexer
@@ -158,6 +174,10 @@ void ec_noise_floor(void) {
sum += amux_n_col_sizes[i];
uint8_t adjusted_col = col + sum;
for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
+#ifdef UNUSED_POSITIONS_LIST
+ if (is_unused_position(row, adjusted_col)) continue;
+#endif
+ disable_unused_row(row);
ec_config.noise_floor[row][adjusted_col] += ec_readkey_raw(amux, row, col);
}
}
@@ -180,11 +200,15 @@ bool ec_matrix_scan(matrix_row_t current_matrix[]) {
for (uint8_t amux = 0; amux < AMUX_COUNT; amux++) {
disable_unused_amux(amux);
for (uint8_t col = 0; col < amux_n_col_sizes[amux]; col++) {
+ uint8_t sum = 0;
+ for (uint8_t i = 0; i < (amux > 0 ? amux : 0); i++)
+ sum += amux_n_col_sizes[i];
+ uint8_t adjusted_col = col + sum;
for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
- uint8_t sum = 0;
- for (uint8_t i = 0; i < (amux > 0 ? amux : 0); i++)
- sum += amux_n_col_sizes[i];
- uint8_t adjusted_col = col + sum;
+#ifdef UNUSED_POSITIONS_LIST
+ if (is_unused_position(row, adjusted_col)) continue;
+#endif
+ disable_unused_row(row);
sw_value[row][adjusted_col] = ec_readkey_raw(amux, row, col);
if (ec_config.bottoming_calibration) {
@@ -266,7 +290,7 @@ bool ec_update_key(matrix_row_t* current_row, uint8_t row, uint8_t col, uint16_t
uprintf("Key pressed: %d, %d, %d\n", row, col, sw_value);
}
// Has key moved up enough to be released?
- else if (sw_value < ec_config.extremum[row][col] - ec_config.mode_1_release_offset) {
+ else if (sw_value < ec_config.extremum[row][col] - ec_config.rescaled_mode_1_release_offset[row][col]) {
ec_config.extremum[row][col] = sw_value;
*current_row &= ~(1 << col);
uprintf("Key released: %d, %d, %d\n", row, col, sw_value);
@@ -280,7 +304,7 @@ bool ec_update_key(matrix_row_t* current_row, uint8_t row, uint8_t col, uint16_t
ec_config.extremum[row][col] = sw_value;
}
// Has key moved down enough to be pressed?
- else if (sw_value > ec_config.extremum[row][col] + ec_config.mode_1_actuation_offset) {
+ else if (sw_value > ec_config.extremum[row][col] + ec_config.rescaled_mode_1_actuation_offset[row][col]) {
ec_config.extremum[row][col] = sw_value;
*current_row |= (1 << col);
uprintf("Key pressed: %d, %d, %d\n", row, col, sw_value);
@@ -312,6 +336,18 @@ void ec_print_matrix(void) {
print("\n");
}
+// Check if the position is unused
+#ifdef UNUSED_POSITIONS_LIST
+bool is_unused_position(uint8_t row, uint8_t col) {
+ for (uint8_t i = 0; i < UNUSED_POSITIONS_COUNT; i++) {
+ if (UNUSED_POSITIONS[i][0] == row && UNUSED_POSITIONS[i][1] == col) {
+ return true;
+ }
+ }
+ return false;
+}
+#endif
+
// Rescale the value to a different range
uint16_t rescale(uint16_t x, uint16_t in_min, uint16_t in_max, uint16_t out_min, uint16_t out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
diff --git a/keyboards/cipulot/common/ec_switch_matrix.h b/keyboards/cipulot/common/ec_switch_matrix.h
index 4b424911da8..8fbca372bf6 100644
--- a/keyboards/cipulot/common/ec_switch_matrix.h
+++ b/keyboards/cipulot/common/ec_switch_matrix.h
@@ -37,11 +37,13 @@ typedef struct {
uint16_t mode_0_actuation_threshold; // threshold for key press in mode 0
uint16_t mode_0_release_threshold; // threshold for key release in mode 0
uint16_t mode_1_initial_deadzone_offset; // threshold for key press in mode 1 (initial deadzone)
+ uint8_t mode_1_actuation_offset; // offset for key press in mode 1 (1-255)
+ uint8_t mode_1_release_offset; // offset for key release in mode 1 (1-255)
uint16_t rescaled_mode_0_actuation_threshold[MATRIX_ROWS][MATRIX_COLS]; // threshold for key press in mode 0 rescaled to actual scale
uint16_t rescaled_mode_0_release_threshold[MATRIX_ROWS][MATRIX_COLS]; // threshold for key release in mode 0 rescaled to actual scale
uint16_t rescaled_mode_1_initial_deadzone_offset[MATRIX_ROWS][MATRIX_COLS]; // threshold for key press in mode 1 (initial deadzone) rescaled to actual scale
- uint8_t mode_1_actuation_offset; // offset for key press in mode 1 (1-255)
- uint8_t mode_1_release_offset; // offset for key release in mode 1 (1-255)
+ uint8_t rescaled_mode_1_actuation_offset[MATRIX_ROWS][MATRIX_COLS]; // offset for key press in mode 1 rescaled to actual scale
+ uint8_t rescaled_mode_1_release_offset[MATRIX_ROWS][MATRIX_COLS]; // offset for key release in mode 1 rescaled to actual scale
uint16_t extremum[MATRIX_ROWS][MATRIX_COLS]; // extremum values for mode 1
uint16_t noise_floor[MATRIX_ROWS][MATRIX_COLS]; // noise floor detected during startup
bool bottoming_calibration; // calibration mode for bottoming out values (true: calibration mode, false: normal mode)
@@ -58,6 +60,7 @@ extern ec_config_t ec_config;
void init_row(void);
void init_amux(void);
+void disable_unused_row(uint8_t row);
void select_amux_channel(uint8_t channel, uint8_t col);
void disable_unused_amux(uint8_t channel);
void discharge_capacitor(void);
@@ -71,3 +74,11 @@ bool ec_update_key(matrix_row_t* current_row, uint8_t row, uint8_t col, uint
void ec_print_matrix(void);
uint16_t rescale(uint16_t x, uint16_t in_min, uint16_t in_max, uint16_t out_min, uint16_t out_max);
+
+#ifdef UNUSED_POSITIONS_LIST
+bool is_unused_position(uint8_t row, uint8_t col);
+#endif
+
+#ifdef SPLIT_KEYBOARD
+void via_cmd_slave_handler(uint8_t m2s_size, const void* m2s_buffer, uint8_t s2m_size, void* s2m_buffer);
+#endif
diff --git a/keyboards/cipulot/common/via_ec.c b/keyboards/cipulot/common/via_ec.c
index ce4e813f759..ed34a579b22 100644
--- a/keyboards/cipulot/common/via_ec.c
+++ b/keyboards/cipulot/common/via_ec.c
@@ -19,6 +19,10 @@
#include "print.h"
#include "via.h"
+#ifdef SPLIT_KEYBOARD
+# include "transactions.h"
+#endif
+
#ifdef VIA_ENABLE
void ec_rescale_values(uint8_t item);
@@ -50,6 +54,12 @@ void via_config_set_value(uint8_t *data) {
uint8_t *value_id = &(data[0]);
uint8_t *value_data = &(data[1]);
+# ifdef SPLIT_KEYBOARD
+ if (is_keyboard_master()) {
+ transaction_rpc_send(RPC_ID_VIA_CMD, 30, data);
+ }
+# endif
+
switch (*value_id) {
case id_actuation_mode: {
eeprom_ec_config.actuation_mode = value_data[0];
@@ -115,6 +125,8 @@ void via_config_set_value(uint8_t *data) {
ec_rescale_values(0);
ec_rescale_values(1);
ec_rescale_values(2);
+ ec_rescale_values(3);
+ ec_rescale_values(4);
uprintf("#############################\n");
uprintf("# Noise floor data acquired #\n");
uprintf("#############################\n");
@@ -124,13 +136,14 @@ void via_config_set_value(uint8_t *data) {
case id_show_calibration_data: {
if (value_data[0] == 0) {
ec_show_calibration_data();
- break;
}
+ break;
}
case id_clear_bottoming_calibration_data: {
if (value_data[0] == 0) {
ec_clear_bottoming_calibration_data();
}
+ break;
}
default: {
// Unhandled value.
@@ -240,6 +253,22 @@ void ec_rescale_values(uint8_t item) {
}
}
break;
+ // Rescale the Rapid Trigger mode actuation offsets
+ case 3:
+ for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
+ for (uint8_t col = 0; col < MATRIX_COLS; col++) {
+ ec_config.rescaled_mode_1_actuation_offset[row][col] = rescale(ec_config.mode_1_actuation_offset, 0, 1023, ec_config.noise_floor[row][col], eeprom_ec_config.bottoming_reading[row][col]);
+ }
+ }
+ break;
+ // Rescale the Rapid Trigger mode release offsets
+ case 4:
+ for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
+ for (uint8_t col = 0; col < MATRIX_COLS; col++) {
+ ec_config.rescaled_mode_1_release_offset[row][col] = rescale(ec_config.mode_1_release_offset, 0, 1023, ec_config.noise_floor[row][col], eeprom_ec_config.bottoming_reading[row][col]);
+ }
+ }
+ break;
default:
// Unhandled item.
@@ -258,9 +287,11 @@ void ec_save_threshold_data(uint8_t option) {
// Save Rapid Trigger mode thresholds and rescale them for runtime usage
else if (option == 1) {
eeprom_ec_config.mode_1_initial_deadzone_offset = ec_config.mode_1_initial_deadzone_offset;
- eeprom_ec_config.mode_1_actuation_offset = ec_config.mode_1_actuation_offset;
- eeprom_ec_config.mode_1_release_offset = ec_config.mode_1_release_offset;
+ eeprom_ec_config.mode_1_actuation_offset = ec_config.mode_1_actuation_offset;
+ eeprom_ec_config.mode_1_release_offset = ec_config.mode_1_release_offset;
ec_rescale_values(2);
+ ec_rescale_values(3);
+ ec_rescale_values(4);
}
eeconfig_update_kb_datablock(&eeprom_ec_config);
uprintf("####################################\n");
@@ -272,11 +303,12 @@ void ec_save_threshold_data(uint8_t option) {
void ec_save_bottoming_reading(void) {
for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
- // If the bottom reading doesn't go over the noise floor by BOTTOMING_CALIBRATION_THRESHOLD, it is likely that:
- // 1. The key is not actually in the matrix
- // 2. The key is on an alternative layout, therefore not being pressed
- // 3. The key in in the current layout but not being pressed
- if (ec_config.bottoming_reading[row][col] < (ec_config.noise_floor[row][col] + BOTTOMING_CALIBRATION_THRESHOLD)) {
+ // If the calibration starter flag is still set on the key, it indicates that the key was skipped during the scan because it is not physically present.
+ // If the flag is not set, it means a bottoming reading was taken. If this reading doesn't exceed the noise floor by the BOTTOMING_CALIBRATION_THRESHOLD, it likely indicates one of the following:
+ // 1. The key is part of an alternative layout and is not being pressed.
+ // 2. The key is in the current layout but is not being pressed.
+ // In both conditions we should set the bottoming reading to the maximum value to avoid false positives.
+ if (ec_config.bottoming_calibration_starter[row][col] || ec_config.bottoming_reading[row][col] < (ec_config.noise_floor[row][col] + BOTTOMING_CALIBRATION_THRESHOLD)) {
eeprom_ec_config.bottoming_reading[row][col] = 1023;
} else {
eeprom_ec_config.bottoming_reading[row][col] = ec_config.bottoming_reading[row][col];
@@ -287,6 +319,8 @@ void ec_save_bottoming_reading(void) {
ec_rescale_values(0);
ec_rescale_values(1);
ec_rescale_values(2);
+ ec_rescale_values(3);
+ ec_rescale_values(4);
eeconfig_update_kb_datablock(&eeprom_ec_config);
}
@@ -360,4 +394,14 @@ void ec_clear_bottoming_calibration_data(void) {
uprintf("######################################\n");
}
+# ifdef SPLIT_KEYBOARD
+void via_cmd_slave_handler(uint8_t m2s_size, const void *m2s_buffer, uint8_t s2m_size, void *s2m_buffer) {
+ if (m2s_size == (RAW_EPSIZE-2)) {
+ via_config_set_value((uint8_t *)m2s_buffer);
+ } else {
+ uprintf("Unexpected response in slave handler\n");
+ }
+}
+# endif
+
#endif // VIA_ENABLE
diff --git a/keyboards/cipulot/ec_23u/post_rules.mk b/keyboards/cipulot/ec_23u/post_rules.mk
index d726a112a8c..5dba48cc5fd 100644
--- a/keyboards/cipulot/ec_23u/post_rules.mk
+++ b/keyboards/cipulot/ec_23u/post_rules.mk
@@ -1,3 +1 @@
-ifeq ($(strip $(VIA_ENABLE)), yes)
- SRC += keyboards/cipulot/common/via_ec.c
-endif
+include keyboards/cipulot/common/common_cipulot.mk
diff --git a/keyboards/cipulot/ec_23u/rules.mk b/keyboards/cipulot/ec_23u/rules.mk
index 318e0215ce9..3aa0e2bf061 100644
--- a/keyboards/cipulot/ec_23u/rules.mk
+++ b/keyboards/cipulot/ec_23u/rules.mk
@@ -1,5 +1 @@
-CUSTOM_MATRIX = lite
-ANALOG_DRIVER_REQUIRED = yes
-VPATH += keyboards/cipulot/common
-SRC += matrix.c ec_board.c ec_switch_matrix.c
OPT = 2
diff --git a/keyboards/cipulot/ec_60/config.h b/keyboards/cipulot/ec_60/config.h
index 24525501439..a409df2dfc5 100644
--- a/keyboards/cipulot/ec_60/config.h
+++ b/keyboards/cipulot/ec_60/config.h
@@ -19,6 +19,8 @@
#define MATRIX_ROWS 5
#define MATRIX_COLS 15
+#define UNUSED_POSITIONS_LIST { {1, 14}, {2, 14}, {4, 3}, {4, 8} }
+
#define MATRIX_ROW_PINS \
{ B15, A8, B0, A7, B1 }
diff --git a/keyboards/cipulot/ec_60/post_rules.mk b/keyboards/cipulot/ec_60/post_rules.mk
index d726a112a8c..5dba48cc5fd 100644
--- a/keyboards/cipulot/ec_60/post_rules.mk
+++ b/keyboards/cipulot/ec_60/post_rules.mk
@@ -1,3 +1 @@
-ifeq ($(strip $(VIA_ENABLE)), yes)
- SRC += keyboards/cipulot/common/via_ec.c
-endif
+include keyboards/cipulot/common/common_cipulot.mk
diff --git a/keyboards/cipulot/ec_60/rules.mk b/keyboards/cipulot/ec_60/rules.mk
index ce525670a68..1716098b3e1 100644
--- a/keyboards/cipulot/ec_60/rules.mk
+++ b/keyboards/cipulot/ec_60/rules.mk
@@ -1,5 +1 @@
-CUSTOM_MATRIX = lite
-ANALOG_DRIVER_REQUIRED = yes
-VPATH += keyboards/cipulot/common
-SRC += matrix.c ec_board.c ec_switch_matrix.c
OPT = 3
diff --git a/keyboards/cipulot/ec_60x/config.h b/keyboards/cipulot/ec_60x/config.h
index 1a8d105d680..1784076d21c 100644
--- a/keyboards/cipulot/ec_60x/config.h
+++ b/keyboards/cipulot/ec_60x/config.h
@@ -19,6 +19,8 @@
#define MATRIX_ROWS 5
#define MATRIX_COLS 15
+#define UNUSED_POSITIONS_LIST { {2, 14}, {4, 3}, {4, 5}, {4, 7}, {4, 9}, {4, 14} }
+
#define MATRIX_ROW_PINS \
{ A8, A15, B12, B8, B9}
diff --git a/keyboards/cipulot/ec_60x/post_rules.mk b/keyboards/cipulot/ec_60x/post_rules.mk
index d726a112a8c..5dba48cc5fd 100644
--- a/keyboards/cipulot/ec_60x/post_rules.mk
+++ b/keyboards/cipulot/ec_60x/post_rules.mk
@@ -1,3 +1 @@
-ifeq ($(strip $(VIA_ENABLE)), yes)
- SRC += keyboards/cipulot/common/via_ec.c
-endif
+include keyboards/cipulot/common/common_cipulot.mk
diff --git a/keyboards/cipulot/ec_60x/rules.mk b/keyboards/cipulot/ec_60x/rules.mk
index 318e0215ce9..3aa0e2bf061 100644
--- a/keyboards/cipulot/ec_60x/rules.mk
+++ b/keyboards/cipulot/ec_60x/rules.mk
@@ -1,5 +1 @@
-CUSTOM_MATRIX = lite
-ANALOG_DRIVER_REQUIRED = yes
-VPATH += keyboards/cipulot/common
-SRC += matrix.c ec_board.c ec_switch_matrix.c
OPT = 2
diff --git a/keyboards/cipulot/ec_660c/config.h b/keyboards/cipulot/ec_660c/config.h
index 9e883c40da2..16b2ade719d 100644
--- a/keyboards/cipulot/ec_660c/config.h
+++ b/keyboards/cipulot/ec_660c/config.h
@@ -19,6 +19,8 @@
#define MATRIX_ROWS 5
#define MATRIX_COLS 15
+#define UNUSED_POSITIONS_LIST { {3, 14}, {4, 3}, {4, 4}, {4, 5}, {4, 7}, {4, 8} }
+
#define MATRIX_ROW_PINS \
{ B1, B10, B0, A1, A0 }
diff --git a/keyboards/cipulot/ec_660c/post_rules.mk b/keyboards/cipulot/ec_660c/post_rules.mk
index d726a112a8c..5dba48cc5fd 100644
--- a/keyboards/cipulot/ec_660c/post_rules.mk
+++ b/keyboards/cipulot/ec_660c/post_rules.mk
@@ -1,3 +1 @@
-ifeq ($(strip $(VIA_ENABLE)), yes)
- SRC += keyboards/cipulot/common/via_ec.c
-endif
+include keyboards/cipulot/common/common_cipulot.mk
diff --git a/keyboards/cipulot/ec_660c/rules.mk b/keyboards/cipulot/ec_660c/rules.mk
index ce525670a68..1716098b3e1 100644
--- a/keyboards/cipulot/ec_660c/rules.mk
+++ b/keyboards/cipulot/ec_660c/rules.mk
@@ -1,5 +1 @@
-CUSTOM_MATRIX = lite
-ANALOG_DRIVER_REQUIRED = yes
-VPATH += keyboards/cipulot/common
-SRC += matrix.c ec_board.c ec_switch_matrix.c
OPT = 3
diff --git a/keyboards/cipulot/ec_980c/config.h b/keyboards/cipulot/ec_980c/config.h
index e3723822e33..bd8afcb687d 100644
--- a/keyboards/cipulot/ec_980c/config.h
+++ b/keyboards/cipulot/ec_980c/config.h
@@ -19,6 +19,8 @@
#define MATRIX_ROWS 6
#define MATRIX_COLS 19
+#define UNUSED_POSITIONS_LIST { {0, 1}, {0, 10}, {3, 14}, {4, 13}, {5, 4}, {5, 7}, {5, 12} }
+
#define MATRIX_ROW_PINS \
{ B13, B12, B14, A9, B6, B7 }
diff --git a/keyboards/cipulot/ec_980c/ec_980c.c b/keyboards/cipulot/ec_980c/ec_980c.c
index 49b52487451..eaa636ede6a 100644
--- a/keyboards/cipulot/ec_980c/ec_980c.c
+++ b/keyboards/cipulot/ec_980c/ec_980c.c
@@ -69,6 +69,8 @@ void keyboard_post_init_kb(void) {
ec_config.rescaled_mode_0_actuation_threshold[row][col] = rescale(ec_config.mode_0_actuation_threshold, 0, 1023, ec_config.noise_floor[row][col], eeprom_ec_config.bottoming_reading[row][col]);
ec_config.rescaled_mode_0_release_threshold[row][col] = rescale(ec_config.mode_0_release_threshold, 0, 1023, ec_config.noise_floor[row][col], eeprom_ec_config.bottoming_reading[row][col]);
ec_config.rescaled_mode_1_initial_deadzone_offset[row][col] = rescale(ec_config.mode_1_initial_deadzone_offset, 0, 1023, ec_config.noise_floor[row][col], eeprom_ec_config.bottoming_reading[row][col]);
+ ec_config.rescaled_mode_1_actuation_offset[row][col] = rescale(ec_config.mode_1_actuation_offset, 0, 1023, ec_config.noise_floor[row][col], eeprom_ec_config.bottoming_reading[row][col]);
+ ec_config.rescaled_mode_1_release_offset[row][col] = rescale(ec_config.mode_1_release_offset, 0, 1023, ec_config.noise_floor[row][col], eeprom_ec_config.bottoming_reading[row][col]);
}
}
diff --git a/keyboards/cipulot/ec_980c/ec_switch_matrix.c b/keyboards/cipulot/ec_980c/ec_switch_matrix.c
index 33123bd236e..00a0b632fbc 100644
--- a/keyboards/cipulot/ec_980c/ec_switch_matrix.c
+++ b/keyboards/cipulot/ec_980c/ec_switch_matrix.c
@@ -37,6 +37,11 @@ const pin_t amux_en_pins[] = AMUX_EN_PINS;
const pin_t amux_n_col_sizes[] = AMUX_COL_CHANNELS_SIZES;
const pin_t amux_n_col_channels[][AMUX_MAX_COLS_COUNT] = {AMUX_COL_CHANNELS};
+#ifdef UNUSED_POSITIONS_LIST
+const uint8_t UNUSED_POSITIONS[][2] = UNUSED_POSITIONS_LIST;
+# define UNUSED_POSITIONS_COUNT (sizeof(UNUSED_POSITIONS) / sizeof(UNUSED_POSITIONS[0]))
+#endif
+
#define AMUX_SEL_PINS_COUNT ARRAY_SIZE(amux_sel_pins)
#define EXPECTED_AMUX_SEL_PINS_COUNT ceil(log2(AMUX_MAX_COLS_COUNT)
// Checks for the correctness of the configuration
@@ -70,6 +75,16 @@ void init_amux(void) {
}
}
+// Disable all the unused rows
+void disable_unused_row(uint8_t row) {
+ // disable all the other rows apart from the current selected one
+ for (uint8_t idx = 0; idx < MATRIX_ROWS; idx++) {
+ if (idx != row) {
+ gpio_write_pin_low(row_pins[idx]);
+ }
+ }
+}
+
// Select the multiplexer channel of the specified multiplexer
void select_amux_channel(uint8_t channel, uint8_t col) {
// Get the channel for the specified multiplexer
@@ -158,6 +173,10 @@ void ec_noise_floor(void) {
sum += amux_n_col_sizes[i];
uint8_t adjusted_col = col + sum;
for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
+#ifdef UNUSED_POSITIONS_LIST
+ if (is_unused_position(row, adjusted_col)) continue;
+#endif
+ disable_unused_row(row);
ec_config.noise_floor[row][adjusted_col] += ec_readkey_raw(amux, row, col);
}
}
@@ -180,11 +199,15 @@ bool ec_matrix_scan(matrix_row_t current_matrix[]) {
for (uint8_t amux = 0; amux < AMUX_COUNT; amux++) {
disable_unused_amux(amux);
for (uint8_t col = 0; col < amux_n_col_sizes[amux]; col++) {
+ uint8_t sum = 0;
+ for (uint8_t i = 0; i < (amux > 0 ? amux : 0); i++)
+ sum += amux_n_col_sizes[i];
+ uint8_t adjusted_col = col + sum;
for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
- uint8_t sum = 0;
- for (uint8_t i = 0; i < (amux > 0 ? amux : 0); i++)
- sum += amux_n_col_sizes[i];
- uint8_t adjusted_col = col + sum;
+#ifdef UNUSED_POSITIONS_LIST
+ if (is_unused_position(row, adjusted_col)) continue;
+#endif
+ disable_unused_row(row);
sw_value[row][adjusted_col] = ec_readkey_raw(amux, row, col);
if (ec_config.bottoming_calibration) {
@@ -229,7 +252,7 @@ uint16_t ec_readkey_raw(uint8_t channel, uint8_t row, uint8_t col) {
}
// Update press/release state of key
-bool ec_update_key(matrix_row_t* current_row, uint8_t row, uint8_t col, uint16_t sw_value) {
+bool ec_update_key(matrix_row_t *current_row, uint8_t row, uint8_t col, uint16_t sw_value) {
bool current_state = (*current_row >> col) & 1;
// Real Time Noise Floor Calibration
@@ -266,7 +289,7 @@ bool ec_update_key(matrix_row_t* current_row, uint8_t row, uint8_t col, uint16_t
uprintf("Key pressed: %d, %d, %d\n", row, col, sw_value);
}
// Has key moved up enough to be released?
- else if (sw_value < ec_config.extremum[row][col] - ec_config.mode_1_release_offset) {
+ else if (sw_value < ec_config.extremum[row][col] - ec_config.rescaled_mode_1_release_offset[row][col]) {
ec_config.extremum[row][col] = sw_value;
*current_row &= ~(1 << col);
uprintf("Key released: %d, %d, %d\n", row, col, sw_value);
@@ -280,7 +303,7 @@ bool ec_update_key(matrix_row_t* current_row, uint8_t row, uint8_t col, uint16_t
ec_config.extremum[row][col] = sw_value;
}
// Has key moved down enough to be pressed?
- else if (sw_value > ec_config.extremum[row][col] + ec_config.mode_1_actuation_offset) {
+ else if (sw_value > ec_config.extremum[row][col] + ec_config.rescaled_mode_1_actuation_offset[row][col]) {
ec_config.extremum[row][col] = sw_value;
*current_row |= (1 << col);
uprintf("Key pressed: %d, %d, %d\n", row, col, sw_value);
@@ -312,6 +335,18 @@ void ec_print_matrix(void) {
print("\n");
}
+// Check if the position is unused
+#ifdef UNUSED_POSITIONS_LIST
+bool is_unused_position(uint8_t row, uint8_t col) {
+ for (uint8_t i = 0; i < UNUSED_POSITIONS_COUNT; i++) {
+ if (UNUSED_POSITIONS[i][0] == row && UNUSED_POSITIONS[i][1] == col) {
+ return true;
+ }
+ }
+ return false;
+}
+#endif
+
// Rescale the value to a different range
uint16_t rescale(uint16_t x, uint16_t in_min, uint16_t in_max, uint16_t out_min, uint16_t out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
diff --git a/keyboards/cipulot/ec_980c/ec_switch_matrix.h b/keyboards/cipulot/ec_980c/ec_switch_matrix.h
index 8a75b5de5fb..a89f8970ab1 100644
--- a/keyboards/cipulot/ec_980c/ec_switch_matrix.h
+++ b/keyboards/cipulot/ec_980c/ec_switch_matrix.h
@@ -47,11 +47,13 @@ typedef struct {
uint16_t mode_0_actuation_threshold; // threshold for key press in mode 0
uint16_t mode_0_release_threshold; // threshold for key release in mode 0
uint16_t mode_1_initial_deadzone_offset; // threshold for key press in mode 1 (initial deadzone)
+ uint8_t mode_1_actuation_offset; // offset for key press in mode 1 (1-255)
+ uint8_t mode_1_release_offset; // offset for key release in mode 1 (1-255)
uint16_t rescaled_mode_0_actuation_threshold[MATRIX_ROWS][MATRIX_COLS]; // threshold for key press in mode 0 rescaled to actual scale
uint16_t rescaled_mode_0_release_threshold[MATRIX_ROWS][MATRIX_COLS]; // threshold for key release in mode 0 rescaled to actual scale
uint16_t rescaled_mode_1_initial_deadzone_offset[MATRIX_ROWS][MATRIX_COLS]; // threshold for key press in mode 1 (initial deadzone) rescaled to actual scale
- uint8_t mode_1_actuation_offset; // offset for key press in mode 1 (1-255)
- uint8_t mode_1_release_offset; // offset for key release in mode 1 (1-255)
+ uint8_t rescaled_mode_1_actuation_offset[MATRIX_ROWS][MATRIX_COLS]; // offset for key press in mode 1 rescaled to actual scale
+ uint8_t rescaled_mode_1_release_offset[MATRIX_ROWS][MATRIX_COLS]; // offset for key release in mode 1 rescaled to actual scale
uint16_t extremum[MATRIX_ROWS][MATRIX_COLS]; // extremum values for mode 1
uint16_t noise_floor[MATRIX_ROWS][MATRIX_COLS]; // noise floor detected during startup
bool bottoming_calibration; // calibration mode for bottoming out values (true: calibration mode, false: normal mode)
@@ -81,3 +83,7 @@ bool ec_update_key(matrix_row_t* current_row, uint8_t row, uint8_t col, uint
void ec_print_matrix(void);
uint16_t rescale(uint16_t x, uint16_t in_min, uint16_t in_max, uint16_t out_min, uint16_t out_max);
+
+#ifdef UNUSED_POSITIONS_LIST
+bool is_unused_position(uint8_t row, uint8_t col);
+#endif
diff --git a/keyboards/cipulot/ec_alveus/1_0_0/config.h b/keyboards/cipulot/ec_alveus/1_0_0/config.h
index ab51289c023..995ede408bd 100644
--- a/keyboards/cipulot/ec_alveus/1_0_0/config.h
+++ b/keyboards/cipulot/ec_alveus/1_0_0/config.h
@@ -19,6 +19,8 @@
#define MATRIX_ROWS 5
#define MATRIX_COLS 16
+#define UNUSED_POSITIONS_LIST { {2, 12}, {3, 11}, {3, 12}, {4, 3}, {4, 4}, {4, 6}, {4, 7}, {4, 8}, {4, 9}, {4, 10} }
+
#define MATRIX_ROW_PINS \
{ A14, B3, A15, B5, B4 }
diff --git a/keyboards/cipulot/ec_alveus/1_0_0/post_rules.mk b/keyboards/cipulot/ec_alveus/1_0_0/post_rules.mk
index d726a112a8c..5dba48cc5fd 100644
--- a/keyboards/cipulot/ec_alveus/1_0_0/post_rules.mk
+++ b/keyboards/cipulot/ec_alveus/1_0_0/post_rules.mk
@@ -1,3 +1 @@
-ifeq ($(strip $(VIA_ENABLE)), yes)
- SRC += keyboards/cipulot/common/via_ec.c
-endif
+include keyboards/cipulot/common/common_cipulot.mk
diff --git a/keyboards/cipulot/ec_alveus/1_0_0/rules.mk b/keyboards/cipulot/ec_alveus/1_0_0/rules.mk
index ce525670a68..1716098b3e1 100644
--- a/keyboards/cipulot/ec_alveus/1_0_0/rules.mk
+++ b/keyboards/cipulot/ec_alveus/1_0_0/rules.mk
@@ -1,5 +1 @@
-CUSTOM_MATRIX = lite
-ANALOG_DRIVER_REQUIRED = yes
-VPATH += keyboards/cipulot/common
-SRC += matrix.c ec_board.c ec_switch_matrix.c
OPT = 3
diff --git a/keyboards/cipulot/ec_alveus/1_2_0/config.h b/keyboards/cipulot/ec_alveus/1_2_0/config.h
index ab51289c023..05276c1d75d 100644
--- a/keyboards/cipulot/ec_alveus/1_2_0/config.h
+++ b/keyboards/cipulot/ec_alveus/1_2_0/config.h
@@ -19,6 +19,8 @@
#define MATRIX_ROWS 5
#define MATRIX_COLS 16
+#define UNUSED_POSITIONS_LIST { {3, 11}, {3, 12}, {4, 3}, {4, 4}, {4, 6}, {4, 7}, {4, 8}, {4, 9}, {4, 10} }
+
#define MATRIX_ROW_PINS \
{ A14, B3, A15, B5, B4 }
diff --git a/keyboards/cipulot/ec_alveus/1_2_0/post_rules.mk b/keyboards/cipulot/ec_alveus/1_2_0/post_rules.mk
index d726a112a8c..5dba48cc5fd 100644
--- a/keyboards/cipulot/ec_alveus/1_2_0/post_rules.mk
+++ b/keyboards/cipulot/ec_alveus/1_2_0/post_rules.mk
@@ -1,3 +1 @@
-ifeq ($(strip $(VIA_ENABLE)), yes)
- SRC += keyboards/cipulot/common/via_ec.c
-endif
+include keyboards/cipulot/common/common_cipulot.mk
diff --git a/keyboards/cipulot/ec_alveus/1_2_0/rules.mk b/keyboards/cipulot/ec_alveus/1_2_0/rules.mk
index ce525670a68..1716098b3e1 100644
--- a/keyboards/cipulot/ec_alveus/1_2_0/rules.mk
+++ b/keyboards/cipulot/ec_alveus/1_2_0/rules.mk
@@ -1,5 +1 @@
-CUSTOM_MATRIX = lite
-ANALOG_DRIVER_REQUIRED = yes
-VPATH += keyboards/cipulot/common
-SRC += matrix.c ec_board.c ec_switch_matrix.c
OPT = 3
diff --git a/keyboards/cipulot/ec_dolice/config.h b/keyboards/cipulot/ec_dolice/config.h
index a5c56e79491..2048fd4449e 100644
--- a/keyboards/cipulot/ec_dolice/config.h
+++ b/keyboards/cipulot/ec_dolice/config.h
@@ -19,6 +19,8 @@
#define MATRIX_ROWS 5
#define MATRIX_COLS 15
+#define UNUSED_POSITIONS_LIST { {2, 14}, {4, 0}, {4, 2}, {4, 4}, {4, 7}, {4, 9}, {4, 11}, {4, 12}, {4, 13} }
+
#define MATRIX_ROW_PINS \
{ B13, A8, B12, B14, B15 }
diff --git a/keyboards/cipulot/ec_dolice/post_rules.mk b/keyboards/cipulot/ec_dolice/post_rules.mk
index d726a112a8c..5dba48cc5fd 100644
--- a/keyboards/cipulot/ec_dolice/post_rules.mk
+++ b/keyboards/cipulot/ec_dolice/post_rules.mk
@@ -1,3 +1 @@
-ifeq ($(strip $(VIA_ENABLE)), yes)
- SRC += keyboards/cipulot/common/via_ec.c
-endif
+include keyboards/cipulot/common/common_cipulot.mk
diff --git a/keyboards/cipulot/ec_dolice/rules.mk b/keyboards/cipulot/ec_dolice/rules.mk
index ce525670a68..1716098b3e1 100644
--- a/keyboards/cipulot/ec_dolice/rules.mk
+++ b/keyboards/cipulot/ec_dolice/rules.mk
@@ -1,5 +1 @@
-CUSTOM_MATRIX = lite
-ANALOG_DRIVER_REQUIRED = yes
-VPATH += keyboards/cipulot/common
-SRC += matrix.c ec_board.c ec_switch_matrix.c
OPT = 3
diff --git a/keyboards/cipulot/ec_menhir/config.h b/keyboards/cipulot/ec_menhir/config.h
index bd0094c7f15..d70fed7a3b4 100644
--- a/keyboards/cipulot/ec_menhir/config.h
+++ b/keyboards/cipulot/ec_menhir/config.h
@@ -19,6 +19,8 @@
#define MATRIX_ROWS 4
#define MATRIX_COLS 12
+#define UNUSED_POSITIONS_LIST { {2, 11}, {3, 0}, {3, 3}, {3, 7}, {3, 10}, {3, 11} }
+
#define MATRIX_ROW_PINS \
{ A0, A3, A2, A1 }
diff --git a/keyboards/cipulot/ec_menhir/post_rules.mk b/keyboards/cipulot/ec_menhir/post_rules.mk
index d726a112a8c..5dba48cc5fd 100644
--- a/keyboards/cipulot/ec_menhir/post_rules.mk
+++ b/keyboards/cipulot/ec_menhir/post_rules.mk
@@ -1,3 +1 @@
-ifeq ($(strip $(VIA_ENABLE)), yes)
- SRC += keyboards/cipulot/common/via_ec.c
-endif
+include keyboards/cipulot/common/common_cipulot.mk
diff --git a/keyboards/cipulot/ec_pro2/config.h b/keyboards/cipulot/ec_pro2/config.h
index a05e716823a..63c81a6364b 100644
--- a/keyboards/cipulot/ec_pro2/config.h
+++ b/keyboards/cipulot/ec_pro2/config.h
@@ -19,6 +19,8 @@
#define MATRIX_ROWS 5
#define MATRIX_COLS 15
+#define UNUSED_POSITIONS_LIST { {1, 14}, {2, 14}, {3, 12}, {4, 0}, {4, 3}, {4, 4}, {4, 5}, {4, 7}, {4, 8}, {4, 11}, {4, 12}, {4, 13}, {4, 14} }
+
#define MATRIX_ROW_PINS \
{ B15, A8, B0, A7, B1 }
diff --git a/keyboards/cipulot/ec_pro2/post_rules.mk b/keyboards/cipulot/ec_pro2/post_rules.mk
index d726a112a8c..5dba48cc5fd 100644
--- a/keyboards/cipulot/ec_pro2/post_rules.mk
+++ b/keyboards/cipulot/ec_pro2/post_rules.mk
@@ -1,3 +1 @@
-ifeq ($(strip $(VIA_ENABLE)), yes)
- SRC += keyboards/cipulot/common/via_ec.c
-endif
+include keyboards/cipulot/common/common_cipulot.mk
diff --git a/keyboards/cipulot/ec_pro2/rules.mk b/keyboards/cipulot/ec_pro2/rules.mk
index 318e0215ce9..3aa0e2bf061 100644
--- a/keyboards/cipulot/ec_pro2/rules.mk
+++ b/keyboards/cipulot/ec_pro2/rules.mk
@@ -1,5 +1 @@
-CUSTOM_MATRIX = lite
-ANALOG_DRIVER_REQUIRED = yes
-VPATH += keyboards/cipulot/common
-SRC += matrix.c ec_board.c ec_switch_matrix.c
OPT = 2
diff --git a/keyboards/cipulot/ec_prox/ansi_iso/config.h b/keyboards/cipulot/ec_prox/ansi_iso/config.h
index bf25d0b7128..00794921a36 100644
--- a/keyboards/cipulot/ec_prox/ansi_iso/config.h
+++ b/keyboards/cipulot/ec_prox/ansi_iso/config.h
@@ -19,6 +19,8 @@
#define MATRIX_ROWS 5
#define MATRIX_COLS 15
+#define UNUSED_POSITIONS_LIST { {1, 14}, {2, 14}, {3, 12}, {4, 0}, {4, 3}, {4, 4}, {4, 5}, {4, 7}, {4, 8}, {4, 11}, {4, 12}, {4, 13}, {4, 14} }
+
#define MATRIX_ROW_PINS \
{ A7, B0, A4, A5, A6 }
diff --git a/keyboards/cipulot/ec_prox/ansi_iso/post_rules.mk b/keyboards/cipulot/ec_prox/ansi_iso/post_rules.mk
index d726a112a8c..5dba48cc5fd 100644
--- a/keyboards/cipulot/ec_prox/ansi_iso/post_rules.mk
+++ b/keyboards/cipulot/ec_prox/ansi_iso/post_rules.mk
@@ -1,3 +1 @@
-ifeq ($(strip $(VIA_ENABLE)), yes)
- SRC += keyboards/cipulot/common/via_ec.c
-endif
+include keyboards/cipulot/common/common_cipulot.mk
diff --git a/keyboards/cipulot/ec_prox/ansi_iso/rules.mk b/keyboards/cipulot/ec_prox/ansi_iso/rules.mk
index 318e0215ce9..3aa0e2bf061 100644
--- a/keyboards/cipulot/ec_prox/ansi_iso/rules.mk
+++ b/keyboards/cipulot/ec_prox/ansi_iso/rules.mk
@@ -1,5 +1 @@
-CUSTOM_MATRIX = lite
-ANALOG_DRIVER_REQUIRED = yes
-VPATH += keyboards/cipulot/common
-SRC += matrix.c ec_board.c ec_switch_matrix.c
OPT = 2
diff --git a/keyboards/cipulot/ec_prox/jis/config.h b/keyboards/cipulot/ec_prox/jis/config.h
index fd3c048bc38..d7461097cd5 100644
--- a/keyboards/cipulot/ec_prox/jis/config.h
+++ b/keyboards/cipulot/ec_prox/jis/config.h
@@ -19,6 +19,8 @@
#define MATRIX_ROWS 5
#define MATRIX_COLS 14
+#define UNUSED_POSITIONS_LIST { {4, 6} }
+
#define MATRIX_ROW_PINS \
{ A7, B0, A4, A5, A6 }
diff --git a/keyboards/cipulot/ec_prox/jis/post_rules.mk b/keyboards/cipulot/ec_prox/jis/post_rules.mk
index d726a112a8c..5dba48cc5fd 100644
--- a/keyboards/cipulot/ec_prox/jis/post_rules.mk
+++ b/keyboards/cipulot/ec_prox/jis/post_rules.mk
@@ -1,3 +1 @@
-ifeq ($(strip $(VIA_ENABLE)), yes)
- SRC += keyboards/cipulot/common/via_ec.c
-endif
+include keyboards/cipulot/common/common_cipulot.mk
diff --git a/keyboards/cipulot/ec_prox/jis/rules.mk b/keyboards/cipulot/ec_prox/jis/rules.mk
index 318e0215ce9..3aa0e2bf061 100644
--- a/keyboards/cipulot/ec_prox/jis/rules.mk
+++ b/keyboards/cipulot/ec_prox/jis/rules.mk
@@ -1,5 +1 @@
-CUSTOM_MATRIX = lite
-ANALOG_DRIVER_REQUIRED = yes
-VPATH += keyboards/cipulot/common
-SRC += matrix.c ec_board.c ec_switch_matrix.c
OPT = 2
diff --git a/keyboards/cipulot/ec_theca/config.h b/keyboards/cipulot/ec_theca/config.h
index d9fea559675..e62801b10fc 100644
--- a/keyboards/cipulot/ec_theca/config.h
+++ b/keyboards/cipulot/ec_theca/config.h
@@ -19,6 +19,8 @@
#define MATRIX_ROWS 6
#define MATRIX_COLS 16
+#define UNUSED_POSITIONS_LIST { {3, 12}, {4, 11}, {4, 12}, {5, 3}, {5, 4}, {5, 6}, {5, 7}, {5, 8}, {5, 9} }
+
#define MATRIX_ROW_PINS \
{ B4, A14, B3, A15, B6, B5 }
diff --git a/keyboards/cipulot/ec_theca/post_rules.mk b/keyboards/cipulot/ec_theca/post_rules.mk
index d726a112a8c..5dba48cc5fd 100644
--- a/keyboards/cipulot/ec_theca/post_rules.mk
+++ b/keyboards/cipulot/ec_theca/post_rules.mk
@@ -1,3 +1 @@
-ifeq ($(strip $(VIA_ENABLE)), yes)
- SRC += keyboards/cipulot/common/via_ec.c
-endif
+include keyboards/cipulot/common/common_cipulot.mk
diff --git a/keyboards/cipulot/ec_theca/rules.mk b/keyboards/cipulot/ec_theca/rules.mk
index ce525670a68..1716098b3e1 100644
--- a/keyboards/cipulot/ec_theca/rules.mk
+++ b/keyboards/cipulot/ec_theca/rules.mk
@@ -1,5 +1 @@
-CUSTOM_MATRIX = lite
-ANALOG_DRIVER_REQUIRED = yes
-VPATH += keyboards/cipulot/common
-SRC += matrix.c ec_board.c ec_switch_matrix.c
OPT = 3
diff --git a/keyboards/cipulot/ec_tkl/config.h b/keyboards/cipulot/ec_tkl/config.h
index 95a7f9137a1..d2178fa869d 100644
--- a/keyboards/cipulot/ec_tkl/config.h
+++ b/keyboards/cipulot/ec_tkl/config.h
@@ -19,6 +19,8 @@
#define MATRIX_ROWS 6
#define MATRIX_COLS 16
+#define UNUSED_POSITIONS_LIST { {5, 3}, {5, 5} }
+
#define MATRIX_ROW_PINS \
{ B6, B5, B12, B10, B13, B7 }
diff --git a/keyboards/cipulot/ec_tkl/post_rules.mk b/keyboards/cipulot/ec_tkl/post_rules.mk
index d726a112a8c..5dba48cc5fd 100644
--- a/keyboards/cipulot/ec_tkl/post_rules.mk
+++ b/keyboards/cipulot/ec_tkl/post_rules.mk
@@ -1,3 +1 @@
-ifeq ($(strip $(VIA_ENABLE)), yes)
- SRC += keyboards/cipulot/common/via_ec.c
-endif
+include keyboards/cipulot/common/common_cipulot.mk
diff --git a/keyboards/cipulot/ec_tkl/rules.mk b/keyboards/cipulot/ec_tkl/rules.mk
index 318e0215ce9..3aa0e2bf061 100644
--- a/keyboards/cipulot/ec_tkl/rules.mk
+++ b/keyboards/cipulot/ec_tkl/rules.mk
@@ -1,5 +1 @@
-CUSTOM_MATRIX = lite
-ANALOG_DRIVER_REQUIRED = yes
-VPATH += keyboards/cipulot/common
-SRC += matrix.c ec_board.c ec_switch_matrix.c
OPT = 2
diff --git a/keyboards/cipulot/ec_typeb/config.h b/keyboards/cipulot/ec_typeb/config.h
index bf25d0b7128..908bae13e65 100644
--- a/keyboards/cipulot/ec_typeb/config.h
+++ b/keyboards/cipulot/ec_typeb/config.h
@@ -19,6 +19,8 @@
#define MATRIX_ROWS 5
#define MATRIX_COLS 15
+#define UNUSED_POSITIONS_LIST { {1, 14}, {2, 12}, {2, 14}, {3, 1}, {3, 12}, {4, 0}, {4, 3}, {4, 4}, {4, 5}, {4, 7}, {4, 8}, {4, 11}, {4, 12}, {4, 13}, {4, 14} }
+
#define MATRIX_ROW_PINS \
{ A7, B0, A4, A5, A6 }
diff --git a/keyboards/cipulot/ec_typeb/post_rules.mk b/keyboards/cipulot/ec_typeb/post_rules.mk
index d726a112a8c..5dba48cc5fd 100644
--- a/keyboards/cipulot/ec_typeb/post_rules.mk
+++ b/keyboards/cipulot/ec_typeb/post_rules.mk
@@ -1,3 +1 @@
-ifeq ($(strip $(VIA_ENABLE)), yes)
- SRC += keyboards/cipulot/common/via_ec.c
-endif
+include keyboards/cipulot/common/common_cipulot.mk
diff --git a/keyboards/cipulot/ec_typeb/rules.mk b/keyboards/cipulot/ec_typeb/rules.mk
index ce525670a68..1716098b3e1 100644
--- a/keyboards/cipulot/ec_typeb/rules.mk
+++ b/keyboards/cipulot/ec_typeb/rules.mk
@@ -1,5 +1 @@
-CUSTOM_MATRIX = lite
-ANALOG_DRIVER_REQUIRED = yes
-VPATH += keyboards/cipulot/common
-SRC += matrix.c ec_board.c ec_switch_matrix.c
OPT = 3
diff --git a/keyboards/cipulot/ec_typek/config.h b/keyboards/cipulot/ec_typek/config.h
index a6619c600c8..9821dcbba66 100644
--- a/keyboards/cipulot/ec_typek/config.h
+++ b/keyboards/cipulot/ec_typek/config.h
@@ -17,6 +17,8 @@
#define MATRIX_ROWS 5
#define MATRIX_COLS 15
+#define UNUSED_POSITIONS_LIST { {2, 13}, {4, 2}, {4, 4}, {4, 9}, {4, 11}, {4, 12}, {4, 14} }
+
#define MATRIX_ROW_PINS \
{ B14, B13, B12, A6, A7 }
diff --git a/keyboards/cipulot/ec_typek/ec_switch_matrix.c b/keyboards/cipulot/ec_typek/ec_switch_matrix.c
index da58a75bbcf..ca555378255 100644
--- a/keyboards/cipulot/ec_typek/ec_switch_matrix.c
+++ b/keyboards/cipulot/ec_typek/ec_switch_matrix.c
@@ -37,6 +37,11 @@ const pin_t amux_en_pins[] = AMUX_EN_PINS;
const pin_t amux_n_col_sizes[] = AMUX_COL_CHANNELS_SIZES;
const pin_t amux_n_col_channels[][AMUX_MAX_COLS_COUNT] = {AMUX_COL_CHANNELS};
+#ifdef UNUSED_POSITIONS_LIST
+const uint8_t UNUSED_POSITIONS[][2] = UNUSED_POSITIONS_LIST;
+# define UNUSED_POSITIONS_COUNT (sizeof(UNUSED_POSITIONS) / sizeof(UNUSED_POSITIONS[0]))
+#endif
+
#define AMUX_SEL_PINS_COUNT ARRAY_SIZE(amux_sel_pins)
#define EXPECTED_AMUX_SEL_PINS_COUNT ceil(log2(AMUX_MAX_COLS_COUNT)
// Checks for the correctness of the configuration
@@ -70,6 +75,16 @@ void init_amux(void) {
}
}
+// Disable all the unused rows
+void disable_unused_row(uint8_t row) {
+ // disable all the other rows apart from the current selected one
+ for (uint8_t idx = 0; idx < MATRIX_ROWS; idx++) {
+ if (idx != row) {
+ gpio_write_pin_low(row_pins[idx]);
+ }
+ }
+}
+
// Select the multiplexer channel of the specified multiplexer
void select_amux_channel(uint8_t channel, uint8_t col) {
// Get the channel for the specified multiplexer
@@ -158,6 +173,10 @@ void ec_noise_floor(void) {
sum += amux_n_col_sizes[i];
uint8_t adjusted_col = col + sum;
for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
+#ifdef UNUSED_POSITIONS_LIST
+ if (is_unused_position(row, adjusted_col)) continue;
+#endif
+ disable_unused_row(row);
ec_config.noise_floor[row][adjusted_col] += ec_readkey_raw(amux, row, col);
}
}
@@ -180,11 +199,15 @@ bool ec_matrix_scan(matrix_row_t current_matrix[]) {
for (uint8_t amux = 0; amux < AMUX_COUNT; amux++) {
disable_unused_amux(amux);
for (uint8_t col = 0; col < amux_n_col_sizes[amux]; col++) {
+ uint8_t sum = 0;
+ for (uint8_t i = 0; i < (amux > 0 ? amux : 0); i++)
+ sum += amux_n_col_sizes[i];
+ uint8_t adjusted_col = col + sum;
for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
- uint8_t sum = 0;
- for (uint8_t i = 0; i < (amux > 0 ? amux : 0); i++)
- sum += amux_n_col_sizes[i];
- uint8_t adjusted_col = col + sum;
+#ifdef UNUSED_POSITIONS_LIST
+ if (is_unused_position(row, adjusted_col)) continue;
+#endif
+ disable_unused_row(row);
sw_value[row][adjusted_col] = ec_readkey_raw(amux, row, col);
if (ec_config.bottoming_calibration) {
@@ -229,7 +252,7 @@ uint16_t ec_readkey_raw(uint8_t channel, uint8_t row, uint8_t col) {
}
// Update press/release state of key
-bool ec_update_key(matrix_row_t* current_row, uint8_t row, uint8_t col, uint16_t sw_value) {
+bool ec_update_key(matrix_row_t *current_row, uint8_t row, uint8_t col, uint16_t sw_value) {
bool current_state = (*current_row >> col) & 1;
// Real Time Noise Floor Calibration
@@ -266,7 +289,7 @@ bool ec_update_key(matrix_row_t* current_row, uint8_t row, uint8_t col, uint16_t
uprintf("Key pressed: %d, %d, %d\n", row, col, sw_value);
}
// Has key moved up enough to be released?
- else if (sw_value < ec_config.extremum[row][col] - ec_config.mode_1_release_offset) {
+ else if (sw_value < ec_config.extremum[row][col] - ec_config.rescaled_mode_1_release_offset[row][col]) {
ec_config.extremum[row][col] = sw_value;
*current_row &= ~(1 << col);
uprintf("Key released: %d, %d, %d\n", row, col, sw_value);
@@ -280,7 +303,7 @@ bool ec_update_key(matrix_row_t* current_row, uint8_t row, uint8_t col, uint16_t
ec_config.extremum[row][col] = sw_value;
}
// Has key moved down enough to be pressed?
- else if (sw_value > ec_config.extremum[row][col] + ec_config.mode_1_actuation_offset) {
+ else if (sw_value > ec_config.extremum[row][col] + ec_config.rescaled_mode_1_actuation_offset[row][col]) {
ec_config.extremum[row][col] = sw_value;
*current_row |= (1 << col);
uprintf("Key pressed: %d, %d, %d\n", row, col, sw_value);
@@ -312,6 +335,18 @@ void ec_print_matrix(void) {
print("\n");
}
+// Check if the position is unused
+#ifdef UNUSED_POSITIONS_LIST
+bool is_unused_position(uint8_t row, uint8_t col) {
+ for (uint8_t i = 0; i < UNUSED_POSITIONS_COUNT; i++) {
+ if (UNUSED_POSITIONS[i][0] == row && UNUSED_POSITIONS[i][1] == col) {
+ return true;
+ }
+ }
+ return false;
+}
+#endif
+
// Rescale the value to a different range
uint16_t rescale(uint16_t x, uint16_t in_min, uint16_t in_max, uint16_t out_min, uint16_t out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
diff --git a/keyboards/cipulot/ec_typek/ec_switch_matrix.h b/keyboards/cipulot/ec_typek/ec_switch_matrix.h
index fad20360bc7..e3b6afb976d 100644
--- a/keyboards/cipulot/ec_typek/ec_switch_matrix.h
+++ b/keyboards/cipulot/ec_typek/ec_switch_matrix.h
@@ -33,13 +33,13 @@ typedef struct PACKED {
indicator_config num;
indicator_config caps;
indicator_config scroll;
- uint8_t actuation_mode; // 0: normal board-wide APC, 1: Rapid trigger from specific board-wide actuation point, 2: Rapid trigger from resting point
- uint16_t mode_0_actuation_threshold; // threshold for key press in mode 0
- uint16_t mode_0_release_threshold; // threshold for key release in mode 0
- uint16_t mode_1_initial_deadzone_offset; // threshold for key press in mode 1
- uint8_t mode_1_actuation_offset; // offset for key press in mode 1 and 2 (1-255)
- uint8_t mode_1_release_offset; // offset for key release in mode 1 and 2 (1-255)
- uint16_t bottoming_reading[MATRIX_ROWS][MATRIX_COLS]; // bottoming reading
+ uint8_t actuation_mode; // 0: normal board-wide APC, 1: Rapid trigger from specific board-wide actuation point, 2: Rapid trigger from resting point
+ uint16_t mode_0_actuation_threshold; // threshold for key press in mode 0
+ uint16_t mode_0_release_threshold; // threshold for key release in mode 0
+ uint16_t mode_1_initial_deadzone_offset; // threshold for key press in mode 1
+ uint8_t mode_1_actuation_offset; // offset for key press in mode 1 and 2 (1-255)
+ uint8_t mode_1_release_offset; // offset for key release in mode 1 and 2 (1-255)
+ uint16_t bottoming_reading[MATRIX_ROWS][MATRIX_COLS]; // bottoming reading
} eeprom_ec_config_t;
typedef struct {
@@ -47,11 +47,13 @@ typedef struct {
uint16_t mode_0_actuation_threshold; // threshold for key press in mode 0
uint16_t mode_0_release_threshold; // threshold for key release in mode 0
uint16_t mode_1_initial_deadzone_offset; // threshold for key press in mode 1 (initial deadzone)
+ uint8_t mode_1_actuation_offset; // offset for key press in mode 1 (1-255)
+ uint8_t mode_1_release_offset; // offset for key release in mode 1 (1-255)
uint16_t rescaled_mode_0_actuation_threshold[MATRIX_ROWS][MATRIX_COLS]; // threshold for key press in mode 0 rescaled to actual scale
uint16_t rescaled_mode_0_release_threshold[MATRIX_ROWS][MATRIX_COLS]; // threshold for key release in mode 0 rescaled to actual scale
uint16_t rescaled_mode_1_initial_deadzone_offset[MATRIX_ROWS][MATRIX_COLS]; // threshold for key press in mode 1 (initial deadzone) rescaled to actual scale
- uint8_t mode_1_actuation_offset; // offset for key press in mode 1 (1-255)
- uint8_t mode_1_release_offset; // offset for key release in mode 1 (1-255)
+ uint8_t rescaled_mode_1_actuation_offset[MATRIX_ROWS][MATRIX_COLS]; // offset for key press in mode 1 rescaled to actual scale
+ uint8_t rescaled_mode_1_release_offset[MATRIX_ROWS][MATRIX_COLS]; // offset for key release in mode 1 rescaled to actual scale
uint16_t extremum[MATRIX_ROWS][MATRIX_COLS]; // extremum values for mode 1
uint16_t noise_floor[MATRIX_ROWS][MATRIX_COLS]; // noise floor detected during startup
bool bottoming_calibration; // calibration mode for bottoming out values (true: calibration mode, false: normal mode)
@@ -82,3 +84,7 @@ void ec_print_matrix(void);
uint16_t rescale(uint16_t x, uint16_t in_min, uint16_t in_max, uint16_t out_min, uint16_t out_max);
bool indicators_callback(void);
+
+#ifdef UNUSED_POSITIONS_LIST
+bool is_unused_position(uint8_t row, uint8_t col);
+#endif
diff --git a/keyboards/cipulot/ec_typek/ec_typek.c b/keyboards/cipulot/ec_typek/ec_typek.c
index b899ddbb8a8..d4241f66f1e 100644
--- a/keyboards/cipulot/ec_typek/ec_typek.c
+++ b/keyboards/cipulot/ec_typek/ec_typek.c
@@ -69,6 +69,8 @@ void keyboard_post_init_kb(void) {
ec_config.rescaled_mode_0_actuation_threshold[row][col] = rescale(ec_config.mode_0_actuation_threshold, 0, 1023, ec_config.noise_floor[row][col], eeprom_ec_config.bottoming_reading[row][col]);
ec_config.rescaled_mode_0_release_threshold[row][col] = rescale(ec_config.mode_0_release_threshold, 0, 1023, ec_config.noise_floor[row][col], eeprom_ec_config.bottoming_reading[row][col]);
ec_config.rescaled_mode_1_initial_deadzone_offset[row][col] = rescale(ec_config.mode_1_initial_deadzone_offset, 0, 1023, ec_config.noise_floor[row][col], eeprom_ec_config.bottoming_reading[row][col]);
+ ec_config.rescaled_mode_1_actuation_offset[row][col] = rescale(ec_config.mode_1_actuation_offset, 0, 1023, ec_config.noise_floor[row][col], eeprom_ec_config.bottoming_reading[row][col]);
+ ec_config.rescaled_mode_1_release_offset[row][col] = rescale(ec_config.mode_1_release_offset, 0, 1023, ec_config.noise_floor[row][col], eeprom_ec_config.bottoming_reading[row][col]);
}
}
@@ -82,7 +84,7 @@ void keyboard_post_init_kb(void) {
// This function gets called when caps, num, scroll change
bool led_update_kb(led_t led_state) {
- if(led_update_user(led_state)) {
+ if (led_update_user(led_state)) {
indicators_callback();
}
return true;
diff --git a/keyboards/cipulot/ec_vero/config.h b/keyboards/cipulot/ec_vero/config.h
index 89f7474b552..d86c0b6ab04 100644
--- a/keyboards/cipulot/ec_vero/config.h
+++ b/keyboards/cipulot/ec_vero/config.h
@@ -19,6 +19,8 @@
#define MATRIX_ROWS 5
#define MATRIX_COLS 15
+#define UNUSED_POSITIONS_LIST { {2, 14}, {3, 12}, {4, 0}, {4, 3}, {4, 4}, {4, 5}, {4, 7}, {4, 8}, {4, 9}, {4, 12}, {4, 13}, {4, 14} }
+
#define MATRIX_ROW_PINS \
{ B7, B6, A9, A10, B3 }
diff --git a/keyboards/cipulot/ec_vero/post_rules.mk b/keyboards/cipulot/ec_vero/post_rules.mk
index d726a112a8c..5dba48cc5fd 100644
--- a/keyboards/cipulot/ec_vero/post_rules.mk
+++ b/keyboards/cipulot/ec_vero/post_rules.mk
@@ -1,3 +1 @@
-ifeq ($(strip $(VIA_ENABLE)), yes)
- SRC += keyboards/cipulot/common/via_ec.c
-endif
+include keyboards/cipulot/common/common_cipulot.mk
diff --git a/keyboards/cipulot/ec_vero/rules.mk b/keyboards/cipulot/ec_vero/rules.mk
index ce525670a68..1716098b3e1 100644
--- a/keyboards/cipulot/ec_vero/rules.mk
+++ b/keyboards/cipulot/ec_vero/rules.mk
@@ -1,5 +1 @@
-CUSTOM_MATRIX = lite
-ANALOG_DRIVER_REQUIRED = yes
-VPATH += keyboards/cipulot/common
-SRC += matrix.c ec_board.c ec_switch_matrix.c
OPT = 3
diff --git a/keyboards/cipulot/ec_virgo/config.h b/keyboards/cipulot/ec_virgo/config.h
index 2fce8cd7fa7..87cfbcdd76a 100644
--- a/keyboards/cipulot/ec_virgo/config.h
+++ b/keyboards/cipulot/ec_virgo/config.h
@@ -19,6 +19,8 @@
#define MATRIX_ROWS 6
#define MATRIX_COLS 18
+#define UNUSED_POSITIONS_LIST { {0, 6}, {0, 14}, {3, 14}, {3, 15}, {3, 16}, {3, 17}, {4, 12}, {4, 15}, {4, 17}, {5, 1}, {5, 4}, {5, 8}, {5, 11}, {5, 12}, {5, 14} }
+
#define MATRIX_ROW_PINS \
{ B6, B7, B5, B4, B3, A15 }
diff --git a/keyboards/cipulot/ec_virgo/post_rules.mk b/keyboards/cipulot/ec_virgo/post_rules.mk
index d726a112a8c..5dba48cc5fd 100644
--- a/keyboards/cipulot/ec_virgo/post_rules.mk
+++ b/keyboards/cipulot/ec_virgo/post_rules.mk
@@ -1,3 +1 @@
-ifeq ($(strip $(VIA_ENABLE)), yes)
- SRC += keyboards/cipulot/common/via_ec.c
-endif
+include keyboards/cipulot/common/common_cipulot.mk
diff --git a/keyboards/cipulot/ec_virgo/rules.mk b/keyboards/cipulot/ec_virgo/rules.mk
index ce525670a68..1716098b3e1 100644
--- a/keyboards/cipulot/ec_virgo/rules.mk
+++ b/keyboards/cipulot/ec_virgo/rules.mk
@@ -1,5 +1 @@
-CUSTOM_MATRIX = lite
-ANALOG_DRIVER_REQUIRED = yes
-VPATH += keyboards/cipulot/common
-SRC += matrix.c ec_board.c ec_switch_matrix.c
OPT = 3
diff --git a/keyboards/cipulot/mnk_60_ec/config.h b/keyboards/cipulot/mnk_60_ec/config.h
index 1a7df486572..1f31c91aaa1 100644
--- a/keyboards/cipulot/mnk_60_ec/config.h
+++ b/keyboards/cipulot/mnk_60_ec/config.h
@@ -19,6 +19,8 @@
#define MATRIX_ROWS 5
#define MATRIX_COLS 14
+#define UNUSED_POSITIONS_LIST { {3, 13}, {4, 3}, {4, 4}, {4, 6}, {4, 7}, {4, 8}, {4, 9}, {4, 13} }
+
#define MATRIX_ROW_PINS \
{ B13, B14, B15, A8, A15 }
diff --git a/keyboards/cipulot/mnk_60_ec/post_rules.mk b/keyboards/cipulot/mnk_60_ec/post_rules.mk
index d726a112a8c..5dba48cc5fd 100644
--- a/keyboards/cipulot/mnk_60_ec/post_rules.mk
+++ b/keyboards/cipulot/mnk_60_ec/post_rules.mk
@@ -1,3 +1 @@
-ifeq ($(strip $(VIA_ENABLE)), yes)
- SRC += keyboards/cipulot/common/via_ec.c
-endif
+include keyboards/cipulot/common/common_cipulot.mk
diff --git a/keyboards/cipulot/mnk_60_ec/rules.mk b/keyboards/cipulot/mnk_60_ec/rules.mk
index ce525670a68..1716098b3e1 100644
--- a/keyboards/cipulot/mnk_60_ec/rules.mk
+++ b/keyboards/cipulot/mnk_60_ec/rules.mk
@@ -1,5 +1 @@
-CUSTOM_MATRIX = lite
-ANALOG_DRIVER_REQUIRED = yes
-VPATH += keyboards/cipulot/common
-SRC += matrix.c ec_board.c ec_switch_matrix.c
OPT = 3
diff --git a/keyboards/cipulot/mnk_65_ec/config.h b/keyboards/cipulot/mnk_65_ec/config.h
index 01d1248c436..9d880ba3bda 100644
--- a/keyboards/cipulot/mnk_65_ec/config.h
+++ b/keyboards/cipulot/mnk_65_ec/config.h
@@ -19,6 +19,8 @@
#define MATRIX_ROWS 5
#define MATRIX_COLS 15
+#define UNUSED_POSITIONS_LIST { {2, 13}, {3, 13}, {4, 3}, {4, 4}, {4, 6}, {4, 7}, {4, 8}, {4, 10}, {4, 13} }
+
#define MATRIX_ROW_PINS \
{ B14, B15, A8, B12, A15 }
diff --git a/keyboards/cipulot/mnk_65_ec/post_rules.mk b/keyboards/cipulot/mnk_65_ec/post_rules.mk
index d726a112a8c..5dba48cc5fd 100644
--- a/keyboards/cipulot/mnk_65_ec/post_rules.mk
+++ b/keyboards/cipulot/mnk_65_ec/post_rules.mk
@@ -1,3 +1 @@
-ifeq ($(strip $(VIA_ENABLE)), yes)
- SRC += keyboards/cipulot/common/via_ec.c
-endif
+include keyboards/cipulot/common/common_cipulot.mk
diff --git a/keyboards/cipulot/mnk_65_ec/rules.mk b/keyboards/cipulot/mnk_65_ec/rules.mk
index ce525670a68..1716098b3e1 100644
--- a/keyboards/cipulot/mnk_65_ec/rules.mk
+++ b/keyboards/cipulot/mnk_65_ec/rules.mk
@@ -1,5 +1 @@
-CUSTOM_MATRIX = lite
-ANALOG_DRIVER_REQUIRED = yes
-VPATH += keyboards/cipulot/common
-SRC += matrix.c ec_board.c ec_switch_matrix.c
OPT = 3
diff --git a/keyboards/cipulot/rf_r1_8_9xu/config.h b/keyboards/cipulot/rf_r1_8_9xu/config.h
index cd98ff7f3da..91e3a459c37 100644
--- a/keyboards/cipulot/rf_r1_8_9xu/config.h
+++ b/keyboards/cipulot/rf_r1_8_9xu/config.h
@@ -19,6 +19,8 @@
#define MATRIX_ROWS 6
#define MATRIX_COLS 16
+#define UNUSED_POSITIONS_LIST { {5, 3}, {5, 5} }
+
#define MATRIX_ROW_PINS \
{ B15, A8, B13, B12, B14, B0 }
diff --git a/keyboards/cipulot/rf_r1_8_9xu/post_rules.mk b/keyboards/cipulot/rf_r1_8_9xu/post_rules.mk
index d726a112a8c..5dba48cc5fd 100644
--- a/keyboards/cipulot/rf_r1_8_9xu/post_rules.mk
+++ b/keyboards/cipulot/rf_r1_8_9xu/post_rules.mk
@@ -1,3 +1 @@
-ifeq ($(strip $(VIA_ENABLE)), yes)
- SRC += keyboards/cipulot/common/via_ec.c
-endif
+include keyboards/cipulot/common/common_cipulot.mk
diff --git a/keyboards/cipulot/rf_r1_8_9xu/rules.mk b/keyboards/cipulot/rf_r1_8_9xu/rules.mk
index 318e0215ce9..3aa0e2bf061 100644
--- a/keyboards/cipulot/rf_r1_8_9xu/rules.mk
+++ b/keyboards/cipulot/rf_r1_8_9xu/rules.mk
@@ -1,5 +1 @@
-CUSTOM_MATRIX = lite
-ANALOG_DRIVER_REQUIRED = yes
-VPATH += keyboards/cipulot/common
-SRC += matrix.c ec_board.c ec_switch_matrix.c
OPT = 2
diff --git a/keyboards/converter/thinkpad_t6x/rpi_pico/keyboard.json b/keyboards/converter/thinkpad_t6x/rpi_pico/keyboard.json
new file mode 100644
index 00000000000..4f876a4a94e
--- /dev/null
+++ b/keyboards/converter/thinkpad_t6x/rpi_pico/keyboard.json
@@ -0,0 +1,131 @@
+{
+ "manufacturer": "strobo5",
+ "keyboard_name": "converter/thinkpad_t6x/rpi_pico",
+ "maintainer": "strobo5",
+ "board": "GENERIC_RP_RP2040",
+ "bootloader": "rp2040",
+ "diode_direction": "COL2ROW",
+ "features": {
+ "bootmagic": true,
+ "extrakey": true,
+ "mousekey": true
+ },
+ "matrix_pins": {
+ "cols": ["GP7", "GP9", "GP11", "GP13", "GP17", "GP16", "GP14", "GP12", "GP15", "GP8", "GP10", "GP6", "GP4", "GP2", "GP5", "GP3"],
+ "rows": ["GP20", "GP26", "GP22", "GP21", "GP18", "GP19", "GP27", "GP28"]
+ },
+ "processor": "RP2040",
+ "ps2": {
+ "clock_pin": "GP1",
+ "data_pin": "GP0",
+ "driver": "vendor",
+ "enabled": true,
+ "mouse_enabled": true
+ },
+ "url": "https://github.com/strobo5/T61_PiPico_Scanner",
+ "usb": {
+ "device_version": "1.0.0",
+ "pid": "0x0000",
+ "vid": "0xFEED"
+ },
+ "layouts": {
+ "LAYOUT_iso": {
+ "layout": [
+ {"label": "Esc", "matrix": [5, 0], "x": 0, "y": 0, "w": 0.9, "h": 0.75},
+ {"label": "Mute", "matrix": [4, 10], "x": 0.9, "y": 0, "w": 0.75, "h": 0.5},
+ {"label": "Vol -", "matrix": [3, 10], "x": 1.65, "y": 0, "w": 0.75, "h": 0.5},
+ {"label": "Vol +", "matrix": [2, 10], "x": 2.4, "y": 0, "w": 0.75, "h": 0.5},
+ {"label": "ThinkVantage", "matrix": [5, 10], "x": 3.5, "y": 0, "w": 1.25, "h": 0.5},
+ {"label": "PrtSc", "matrix": [1, 13], "x": 8.9, "y": 0, "w": 0.9, "h": 0.65},
+ {"label": "ScrLk", "matrix": [2, 13], "x": 9.8, "y": 0, "w": 0.9, "h": 0.65},
+ {"label": "Pause", "matrix": [6, 12], "x": 10.7, "y": 0, "w": 0.9, "h": 0.65},
+ {"label": "Insert", "matrix": [0, 9], "x": 12, "y": 0, "w": 0.9, "h": 0.65},
+ {"label": "Home", "matrix": [0, 12], "x": 12.9, "y": 0, "w": 0.9, "h": 0.65},
+ {"label": "PgUp", "matrix": [0, 11], "x": 13.8, "y": 0, "w": 0.9, "h": 0.65},
+ {"label": "F1", "matrix": [0, 1], "x": 0, "y": 0.75, "w": 0.9, "h": 0.65},
+ {"label": "F2", "matrix": [0, 2], "x": 0.9, "y": 0.75, "w": 0.9, "h": 0.65},
+ {"label": "F3", "matrix": [3, 2], "x": 1.8, "y": 0.75, "w": 0.9, "h": 0.65},
+ {"label": "F4", "matrix": [5, 2], "x": 2.7, "y": 0.75, "w": 0.9, "h": 0.65},
+ {"label": "F5", "matrix": [5, 8], "x": 4, "y": 0.75, "w": 0.9, "h": 0.65},
+ {"label": "F6", "matrix": [5, 5], "x": 4.9, "y": 0.75, "w": 0.9, "h": 0.65},
+ {"label": "F7", "matrix": [3, 6], "x": 5.8, "y": 0.75, "w": 0.9, "h": 0.65},
+ {"label": "F8", "matrix": [0, 6], "x": 6.7, "y": 0.75, "w": 0.9, "h": 0.65},
+ {"label": "F9", "matrix": [0, 8], "x": 8, "y": 0.75, "w": 0.9, "h": 0.65},
+ {"label": "F10", "matrix": [1, 8], "x": 8.9, "y": 0.75, "w": 0.9, "h": 0.65},
+ {"label": "F11", "matrix": [1, 10], "x": 9.8, "y": 0.75, "w": 0.9, "h": 0.65},
+ {"label": "F12", "matrix": [1, 9], "x": 10.7, "y": 0.75, "w": 0.9, "h": 0.65},
+ {"label": "Delete", "matrix": [0, 10], "x": 12, "y": 0.75, "w": 0.9, "h": 0.65},
+ {"label": "End", "matrix": [1, 12], "x": 12.9, "y": 0.75, "w": 0.9, "h": 0.65},
+ {"label": "PgDn", "matrix": [1, 11], "x": 13.8, "y": 0.75, "w": 0.9, "h": 0.65},
+ {"label": "`\u00ac", "matrix": [0, 0], "x": 0, "y": 1.4},
+ {"label": "1!", "matrix": [1, 0], "x": 1, "y": 1.4},
+ {"label": "2\"", "matrix": [1, 1], "x": 2, "y": 1.4},
+ {"label": "3\u00a3", "matrix": [1, 2], "x": 3, "y": 1.4},
+ {"label": "4$", "matrix": [1, 3], "x": 4, "y": 1.4},
+ {"label": "5%", "matrix": [0, 3], "x": 5, "y": 1.4},
+ {"label": "6^", "matrix": [0, 4], "x": 6, "y": 1.4},
+ {"label": "7&", "matrix": [1, 4], "x": 7, "y": 1.4},
+ {"label": "8*", "matrix": [1, 5], "x": 8, "y": 1.4},
+ {"label": "9(", "matrix": [1, 6], "x": 9, "y": 1.4},
+ {"label": "0)", "matrix": [1, 7], "x": 10, "y": 1.4},
+ {"label": "-_", "matrix": [0, 7], "x": 11, "y": 1.4},
+ {"label": "=+", "matrix": [0, 5], "x": 12, "y": 1.4},
+ {"label": "Bksp", "matrix": [3, 8], "x": 13, "y": 1.4, "w": 2},
+ {"label": "Tab", "matrix": [3, 0], "x": 0, "y": 2.4, "w": 1.5},
+ {"label": "Q", "matrix": [2, 0], "x": 1.5, "y": 2.4},
+ {"label": "W", "matrix": [2, 1], "x": 2.5, "y": 2.4},
+ {"label": "E", "matrix": [2, 2], "x": 3.5, "y": 2.4},
+ {"label": "R", "matrix": [2, 3], "x": 4.5, "y": 2.4},
+ {"label": "T", "matrix": [3, 3], "x": 5.5, "y": 2.4},
+ {"label": "Y", "matrix": [3, 4], "x": 6.5, "y": 2.4},
+ {"label": "U", "matrix": [2, 4], "x": 7.5, "y": 2.4},
+ {"label": "I", "matrix": [2, 5], "x": 8.5, "y": 2.4},
+ {"label": "O", "matrix": [2, 6], "x": 9.5, "y": 2.4},
+ {"label": "P", "matrix": [2, 7], "x": 10.5, "y": 2.4},
+ {"label": "[{", "matrix": [3, 7], "x": 11.5, "y": 2.4},
+ {"label": "]}", "matrix": [3, 5], "x": 12.5, "y": 2.4},
+ {"label": "Caps Lock", "matrix": [3, 1], "x": 0, "y": 3.4, "w": 1.75},
+ {"label": "A", "matrix": [4, 0], "x": 1.75, "y": 3.4},
+ {"label": "S", "matrix": [4, 1], "x": 2.75, "y": 3.4},
+ {"label": "D", "matrix": [4, 2], "x": 3.75, "y": 3.4},
+ {"label": "F", "matrix": [4, 3], "x": 4.75, "y": 3.4},
+ {"label": "G", "matrix": [5, 3], "x": 5.75, "y": 3.4},
+ {"label": "H", "matrix": [5, 4], "x": 6.75, "y": 3.4},
+ {"label": "J", "matrix": [4, 4], "x": 7.75, "y": 3.4},
+ {"label": "K", "matrix": [4, 5], "x": 8.75, "y": 3.4},
+ {"label": "L", "matrix": [4, 6], "x": 9.75, "y": 3.4},
+ {"label": ";:", "matrix": [4, 7], "x": 10.75, "y": 3.4},
+ {"label": "'@", "matrix": [5, 7], "x": 11.75, "y": 3.4},
+ {"label": "#~", "matrix": [6, 7], "x": 12.75, "y": 3.4},
+ {"label": "Enter", "matrix": [6, 8], "x": 13.75, "y": 2.4, "w": 1.25, "h": 2},
+ {"label": "Shift", "matrix": [3, 14], "x": 0, "y": 4.4, "w": 1.25},
+ {"label": "\\|", "matrix": [5, 1], "x": 1.25, "y": 4.4},
+ {"label": "Z", "matrix": [6, 0], "x": 2.25, "y": 4.4},
+ {"label": "X", "matrix": [6, 1], "x": 3.25, "y": 4.4},
+ {"label": "C", "matrix": [6, 2], "x": 4.25, "y": 4.4},
+ {"label": "V", "matrix": [6, 3], "x": 5.25, "y": 4.4},
+ {"label": "B", "matrix": [7, 3], "x": 6.25, "y": 4.4},
+ {"label": "N", "matrix": [7, 4], "x": 7.25, "y": 4.4},
+ {"label": "M", "matrix": [6, 4], "x": 8.25, "y": 4.4},
+ {"label": ",<", "matrix": [6, 5], "x": 9.25, "y": 4.4},
+ {"label": ".>", "matrix": [6, 6], "x": 10.25, "y": 4.4},
+ {"label": "/?", "matrix": [7, 7], "x": 11.25, "y": 4.4},
+ {"label": "Shift", "matrix": [6, 14], "x": 12.25, "y": 4.4, "w": 2.75},
+ {"label": "Fn", "matrix": [4, 9], "x": 0, "y": 5.4},
+ {"label": "Ctrl", "matrix": [0, 15], "x": 1, "y": 5.4, "w": 1.25},
+ {"label": "Left OS", "matrix": [2, 11], "x": 2.25, "y": 5.4, "w": 0.9},
+ {"label": "Alt", "matrix": [5, 13], "x": 3.15, "y": 5.4},
+ {"label": "Space", "matrix": [7, 8], "x": 4.15, "y": 5.4, "w": 5},
+ {"label": "AltGr", "matrix": [7, 13], "x": 9.25, "y": 5.4},
+ {"label": "Menu", "matrix": [4, 11], "x": 10.25, "y": 5.4},
+ {"label": "Ctrl", "matrix": [6, 15], "x": 11.25, "y": 5.4},
+ {"label": "Browser Back", "matrix": [6, 11], "x": 12.25, "y": 5.4, "w": 0.9, "h": 0.75},
+ {"label": "Up", "matrix": [5, 12], "x": 13.15, "y": 5.4, "w": 0.9, "h": 0.75},
+ {"label": "Browser Forward", "matrix": [7, 11], "x": 14.05, "y": 5.4, "w": 0.9, "h": 0.75},
+ {"label": "Left", "matrix": [7, 12], "x": 12.25, "y": 6.15, "w": 0.9, "h": 0.75},
+ {"label": "Down", "matrix": [7, 10], "x": 13.15, "y": 6.15, "w": 0.9, "h": 0.75},
+ {"label": "Right", "matrix": [7, 9], "x": 14.05, "y": 6.15, "w": 0.9, "h": 0.75}
+ ]
+ }
+ }
+}
diff --git a/keyboards/converter/thinkpad_t6x/rpi_pico/keymaps/default/keymap.c b/keyboards/converter/thinkpad_t6x/rpi_pico/keymaps/default/keymap.c
new file mode 100644
index 00000000000..4dac20888fb
--- /dev/null
+++ b/keyboards/converter/thinkpad_t6x/rpi_pico/keymaps/default/keymap.c
@@ -0,0 +1,17 @@
+// Copyright 2023 QMK
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include QMK_KEYBOARD_H
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+ [0] = LAYOUT_iso(
+ KC_ESC, KC_MUTE, KC_VOLD, KC_VOLU, QK_BOOT, KC_PSCR, KC_SCRL, KC_PAUS, KC_INS, KC_HOME, KC_PGUP,
+ KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_DEL, KC_END, KC_PGDN,
+ 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_EQL, KC_BSPC,
+ KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC,
+ KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_NUHS, KC_ENT,
+ KC_LSFT, KC_NUBS, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT,
+ KC_NO, KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, KC_APP, KC_RCTL, KC_WBAK, KC_UP , KC_WFWD,
+ KC_LEFT, KC_DOWN, KC_RGHT
+ )
+};
diff --git a/keyboards/converter/thinkpad_t6x/rpi_pico/readme.md b/keyboards/converter/thinkpad_t6x/rpi_pico/readme.md
new file mode 100644
index 00000000000..0008dad2f14
--- /dev/null
+++ b/keyboards/converter/thinkpad_t6x/rpi_pico/readme.md
@@ -0,0 +1,27 @@
+# converter/thinkpad_t6x/rpi_pico
+
+
+
+This is a converter PCB for Lenovo Thinkpad keyboards from a wide range of models (T60, T61, X220, ...), based on the Raspberry Pi Pico. The QMK implementation here is specific to the converter in the link below. Similar PCB designs to convert a Thinkpad keyboard to USB exist, but they use a different microcontroller and wiring of the keyboard connector with the MCU.
+
+* Keyboard Maintainer: [Michael Büchler](https://github.com/strobo5)
+* Hardware Supported: The linked converter PCB with keyboards from various Thinkpad models
+* Hardware Availability: [Custom PCB](https://github.com/strobo5/T61_PiPico_Scanner)
+
+Make example for this keyboard (after setting up your build environment):
+
+ make converter/thinkpad_t6x/rpi_pico:default
+
+Flashing example for this keyboard:
+
+ make converter/thinkpad_t6x/rpi_pico:default:flash
+
+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).
+
+## Bootloader
+
+Enter the bootloader in 3 ways:
+
+* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (usually the top left key or Escape) and plug in the keyboard
+* **Physical reset button**: Briefly press the button on the back of the PCB - some may have pads you must short instead
+* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available
diff --git a/keyboards/druah/majestouch_redux/keyboard.json b/keyboards/druah/majestouch_redux/keyboard.json
new file mode 100644
index 00000000000..b9ea139bd58
--- /dev/null
+++ b/keyboards/druah/majestouch_redux/keyboard.json
@@ -0,0 +1,131 @@
+{
+ "manufacturer": "FILCO",
+ "keyboard_name": "Majestouch Redux",
+ "maintainer": "Druah",
+ "bootloader": "atmel-dfu",
+ "build": {
+ "lto": true
+ },
+ "diode_direction": "COL2ROW",
+ "features": {
+ "bootmagic": true,
+ "extrakey": true,
+ "mousekey": true,
+ "nkro": true
+ },
+ "indicators": {
+ "caps_lock": "C1",
+ "scroll_lock": "C0"
+ },
+ "matrix_pins": {
+ "cols": ["A0", "A1", "A2", "F6", "F7", "E6", "F0", "F1", "F2", "B3", "B2", "B1", "F3", "F4", "C5", "C6", "C3"],
+ "rows": ["C2", "B4", "B5", "F5", "C7", "C4"]
+ },
+ "processor": "at90usb646",
+ "qmk": {
+ "locking": {
+ "enabled": true,
+ "resync": true
+ }
+ },
+ "url": "https://druah.moe",
+ "usb": {
+ "device_version": "1.0.0",
+ "pid": "0x0003",
+ "vid": "0x444E"
+ },
+ "community_layouts": ["tkl_ansi"],
+ "layouts": {
+ "LAYOUT_tkl_ansi": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [0, 2], "x": 2, "y": 0},
+ {"matrix": [0, 3], "x": 3, "y": 0},
+ {"matrix": [0, 4], "x": 4, "y": 0},
+ {"matrix": [0, 5], "x": 5, "y": 0},
+ {"matrix": [0, 6], "x": 6.5, "y": 0},
+ {"matrix": [0, 7], "x": 7.5, "y": 0},
+ {"matrix": [0, 8], "x": 8.5, "y": 0},
+ {"matrix": [0, 9], "x": 9.5, "y": 0},
+ {"matrix": [0, 10], "x": 11, "y": 0},
+ {"matrix": [0, 11], "x": 12, "y": 0},
+ {"matrix": [0, 12], "x": 13, "y": 0},
+ {"matrix": [0, 13], "x": 14, "y": 0},
+ {"matrix": [0, 14], "x": 15.25, "y": 0},
+ {"matrix": [0, 15], "x": 16.25, "y": 0},
+ {"matrix": [0, 16], "x": 17.25, "y": 0},
+ {"matrix": [1, 0], "x": 0, "y": 1.5},
+ {"matrix": [1, 1], "x": 1, "y": 1.5},
+ {"matrix": [1, 2], "x": 2, "y": 1.5},
+ {"matrix": [1, 3], "x": 3, "y": 1.5},
+ {"matrix": [1, 4], "x": 4, "y": 1.5},
+ {"matrix": [1, 5], "x": 5, "y": 1.5},
+ {"matrix": [1, 6], "x": 6, "y": 1.5},
+ {"matrix": [1, 7], "x": 7, "y": 1.5},
+ {"matrix": [1, 8], "x": 8, "y": 1.5},
+ {"matrix": [1, 9], "x": 9, "y": 1.5},
+ {"matrix": [1, 10], "x": 10, "y": 1.5},
+ {"matrix": [1, 11], "x": 11, "y": 1.5},
+ {"matrix": [1, 12], "x": 12, "y": 1.5},
+ {"matrix": [1, 13], "x": 13, "y": 1.5, "w": 2},
+ {"matrix": [1, 14], "x": 15.25, "y": 1.5},
+ {"matrix": [1, 15], "x": 16.25, "y": 1.5},
+ {"matrix": [1, 16], "x": 17.25, "y": 1.5},
+ {"matrix": [2, 0], "x": 0, "y": 2.5, "w": 1.5},
+ {"matrix": [2, 1], "x": 1.5, "y": 2.5},
+ {"matrix": [2, 2], "x": 2.5, "y": 2.5},
+ {"matrix": [2, 3], "x": 3.5, "y": 2.5},
+ {"matrix": [2, 4], "x": 4.5, "y": 2.5},
+ {"matrix": [2, 5], "x": 5.5, "y": 2.5},
+ {"matrix": [2, 6], "x": 6.5, "y": 2.5},
+ {"matrix": [2, 7], "x": 7.5, "y": 2.5},
+ {"matrix": [2, 8], "x": 8.5, "y": 2.5},
+ {"matrix": [2, 9], "x": 9.5, "y": 2.5},
+ {"matrix": [2, 10], "x": 10.5, "y": 2.5},
+ {"matrix": [2, 11], "x": 11.5, "y": 2.5},
+ {"matrix": [2, 12], "x": 12.5, "y": 2.5},
+ {"matrix": [2, 13], "x": 13.5, "y": 2.5, "w": 1.5},
+ {"matrix": [2, 14], "x": 15.25, "y": 2.5},
+ {"matrix": [2, 15], "x": 16.25, "y": 2.5},
+ {"matrix": [2, 16], "x": 17.25, "y": 2.5},
+ {"matrix": [3, 0], "x": 0, "y": 3.5, "w": 1.75},
+ {"matrix": [3, 1], "x": 1.75, "y": 3.5},
+ {"matrix": [3, 2], "x": 2.75, "y": 3.5},
+ {"matrix": [3, 3], "x": 3.75, "y": 3.5},
+ {"matrix": [3, 4], "x": 4.75, "y": 3.5},
+ {"matrix": [3, 5], "x": 5.75, "y": 3.5},
+ {"matrix": [3, 6], "x": 6.75, "y": 3.5},
+ {"matrix": [3, 7], "x": 7.75, "y": 3.5},
+ {"matrix": [3, 8], "x": 8.75, "y": 3.5},
+ {"matrix": [3, 9], "x": 9.75, "y": 3.5},
+ {"matrix": [3, 10], "x": 10.75, "y": 3.5},
+ {"matrix": [3, 11], "x": 11.75, "y": 3.5},
+ {"matrix": [3, 13], "x": 12.75, "y": 3.5, "w": 2.25},
+ {"matrix": [4, 0], "x": 0, "y": 4.5, "w": 2.25},
+ {"matrix": [4, 2], "x": 2.25, "y": 4.5},
+ {"matrix": [4, 3], "x": 3.25, "y": 4.5},
+ {"matrix": [4, 4], "x": 4.25, "y": 4.5},
+ {"matrix": [4, 5], "x": 5.25, "y": 4.5},
+ {"matrix": [4, 6], "x": 6.25, "y": 4.5},
+ {"matrix": [4, 7], "x": 7.25, "y": 4.5},
+ {"matrix": [4, 8], "x": 8.25, "y": 4.5},
+ {"matrix": [4, 9], "x": 9.25, "y": 4.5},
+ {"matrix": [4, 10], "x": 10.25, "y": 4.5},
+ {"matrix": [4, 11], "x": 11.25, "y": 4.5},
+ {"matrix": [4, 13], "x": 12.25, "y": 4.5, "w": 2.75},
+ {"matrix": [4, 15], "x": 16.25, "y": 4.5},
+ {"matrix": [5, 0], "x": 0, "y": 5.5, "w": 1.25},
+ {"matrix": [5, 1], "x": 1.25, "y": 5.5, "w": 1.25},
+ {"matrix": [5, 2], "x": 2.5, "y": 5.5, "w": 1.25},
+ {"matrix": [5, 7], "x": 3.75, "y": 5.5, "w": 6.25},
+ {"matrix": [5, 10], "x": 10, "y": 5.5, "w": 1.25},
+ {"matrix": [5, 11], "x": 11.25, "y": 5.5, "w": 1.25},
+ {"matrix": [5, 12], "x": 12.5, "y": 5.5, "w": 1.25},
+ {"matrix": [5, 13], "x": 13.75, "y": 5.5, "w": 1.25},
+ {"matrix": [5, 14], "x": 15.25, "y": 5.5},
+ {"matrix": [5, 15], "x": 16.25, "y": 5.5},
+ {"matrix": [5, 16], "x": 17.25, "y": 5.5}
+ ]
+ }
+ }
+}
diff --git a/keyboards/druah/majestouch_redux/keymaps/default/keymap.c b/keyboards/druah/majestouch_redux/keymaps/default/keymap.c
new file mode 100644
index 00000000000..a3f8be1bbac
--- /dev/null
+++ b/keyboards/druah/majestouch_redux/keymaps/default/keymap.c
@@ -0,0 +1,32 @@
+// Copyright 2024 Druah (@Druah)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include QMK_KEYBOARD_H
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+ /*
+ * ┌───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐┌───┬───┬───┐
+ * │Esc│ │F1 │F2 │F3 │F4 │ │F5 │F6 │F7 │F8 │ │F9 │F10│F11│F12││PSc│Scr│Pse│
+ * └───┘ └───┴───┴───┴───┘ └───┴───┴───┴───┘ └───┴───┴───┴───┘└───┴───┴───┘
+ * ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐┌───┬───┬───┐
+ * │ ` │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ - │ = │ Backsp││Ins│Hom│PgU│
+ * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤├───┼───┼───┤
+ * │ Tab │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │ [ │ ] │ \ ││Del│End│PgD│
+ * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤└───┴───┴───┘
+ * │ Caps │ A │ S │ D │ F │ G │ H │ J │ K │ L │ ; │ ' │ Enter │
+ * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤ ┌───┐
+ * │ Shift │ Z │ X │ C │ V │ B │ N │ M │ , │ . │ / │ Shift │ │ ↑ │
+ * ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤┌───┼───┼───┐
+ * │Ctrl│GUI │Alt │ │ Alt│ GUI│Menu│Ctrl││ ← │ ↓ │ → │
+ * └────┴────┴────┴────────────────────────┴────┴────┴────┴────┘└───┴───┴───┘
+ */
+ [0] = LAYOUT_tkl_ansi(
+ KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_PSCR, KC_SCRL, KC_PAUS,
+
+ 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_EQL, KC_BSPC, KC_INS, KC_HOME, KC_PGUP,
+ KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_DEL, KC_END, KC_PGDN,
+ KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT,
+ KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP,
+ KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, KC_RGUI, KC_APP, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT
+ )
+};
diff --git a/keyboards/druah/majestouch_redux/readme.md b/keyboards/druah/majestouch_redux/readme.md
new file mode 100644
index 00000000000..19df7d46974
--- /dev/null
+++ b/keyboards/druah/majestouch_redux/readme.md
@@ -0,0 +1,27 @@
+# Majestouch Redux
+
+
+
+A replacement PCB for the FILCO Majestouch TKL line of keyboards (and other keyboards) compatible with [Phantom TKL](https://deskthority.net/wiki/Phantom) PCB spacing
+
+* Keyboard Maintainer: [Druah](https://github.com/Druah)
+* Hardware Supported: Majestouch Redux
+* Hardware Availability: Private buy
+
+Make example for this keyboard (after setting up your build environment):
+
+ make druah/majestouch_redux:default
+
+Flashing example for this keyboard:
+
+ make druah/majestouch_redux:default:flash
+
+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).
+
+## Bootloader
+
+Enter the bootloader in 3 ways:
+
+* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (the Escape/top left key) and plug in the keyboard
+* **Physical reset button**: Briefly press the button on the back of the PCB labelled with "RESET"
+* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available
diff --git a/keyboards/handwired/macroboard/config.h b/keyboards/handwired/macroboard/config.h
index ca12d2c7539..21171b93742 100644
--- a/keyboards/handwired/macroboard/config.h
+++ b/keyboards/handwired/macroboard/config.h
@@ -22,4 +22,3 @@ along with this program. If not, see .
#define WS2812_PWM_PAL_MODE 2
#define WS2812_PWM_DMA_STREAM STM32_DMA1_STREAM6 // DMA Stream for TIMx_UP, see the respective reference manual for the appropriate values for your MCU.
#define WS2812_PWM_DMA_CHANNEL 2 // DMA Channel for TIMx_UP, see the respective reference manual for the appropriate values for your MCU.
-#define WS2812_PWM_TARGET_PERIOD 800000
diff --git a/keyboards/handwired/onekey/at_start_f415/board.h b/keyboards/handwired/onekey/at_start_f415/board.h
new file mode 100644
index 00000000000..f4adc2d4183
--- /dev/null
+++ b/keyboards/handwired/onekey/at_start_f415/board.h
@@ -0,0 +1,10 @@
+// Copyright 2023-2024 HorrorTroll
+// Copyright 2023-2024 Zhaqian
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include_next
+
+#undef AT32F415KB
+#define AT32F415RC
diff --git a/keyboards/handwired/onekey/at_start_f415/config.h b/keyboards/handwired/onekey/at_start_f415/config.h
new file mode 100644
index 00000000000..266e45dd004
--- /dev/null
+++ b/keyboards/handwired/onekey/at_start_f415/config.h
@@ -0,0 +1,10 @@
+// Copyright 2023-2024 HorrorTroll
+// Copyright 2023-2024 Zhaqian
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#define ADC_PIN A0
+
+#define BACKLIGHT_PWM_DRIVER PWMD5
+#define BACKLIGHT_PWM_CHANNEL 1
diff --git a/keyboards/handwired/onekey/at_start_f415/halconf.h b/keyboards/handwired/onekey/at_start_f415/halconf.h
new file mode 100644
index 00000000000..1423633d15f
--- /dev/null
+++ b/keyboards/handwired/onekey/at_start_f415/halconf.h
@@ -0,0 +1,13 @@
+// Copyright 2023-2024 HorrorTroll
+// Copyright 2023-2024 Zhaqian
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#define HAL_USE_ADC TRUE
+
+#define HAL_USE_I2C TRUE
+
+#define HAL_USE_PWM TRUE
+
+#include_next
diff --git a/keyboards/handwired/onekey/at_start_f415/keyboard.json b/keyboards/handwired/onekey/at_start_f415/keyboard.json
new file mode 100644
index 00000000000..f598923a6a5
--- /dev/null
+++ b/keyboards/handwired/onekey/at_start_f415/keyboard.json
@@ -0,0 +1,20 @@
+{
+ "keyboard_name": "Onekey AT-START-F415",
+ "processor": "AT32F415",
+ "bootloader": "at32-dfu",
+ "usb": {
+ "shared_endpoint": {
+ "keyboard": true
+ }
+ },
+ "matrix_pins": {
+ "cols": ["B3"],
+ "rows": ["B4"]
+ },
+ "backlight": {
+ "pin": "A0"
+ },
+ "ws2812": {
+ "pin": "B0"
+ }
+}
diff --git a/keyboards/handwired/onekey/at_start_f415/mcuconf.h b/keyboards/handwired/onekey/at_start_f415/mcuconf.h
new file mode 100644
index 00000000000..9bc11d507cc
--- /dev/null
+++ b/keyboards/handwired/onekey/at_start_f415/mcuconf.h
@@ -0,0 +1,16 @@
+// Copyright 2023-2024 HorrorTroll
+// Copyright 2023-2024 Zhaqian
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include_next
+
+#undef AT32_ADC_USE_ADC1
+#define AT32_ADC_USE_ADC1 TRUE
+
+#undef AT32_I2C_USE_I2C1
+#define AT32_I2C_USE_I2C1 TRUE
+
+#undef AT32_PWM_USE_TMR5
+#define AT32_PWM_USE_TMR5 TRUE
diff --git a/keyboards/handwired/onekey/at_start_f415/readme.md b/keyboards/handwired/onekey/at_start_f415/readme.md
new file mode 100644
index 00000000000..499ef5fb169
--- /dev/null
+++ b/keyboards/handwired/onekey/at_start_f415/readme.md
@@ -0,0 +1,3 @@
+# Artery AT-START-F415 Board Onekey
+
+To trigger keypress, short together pins *B3* and *B4*.
diff --git a/keyboards/handwired/tenstad/keyboard.json b/keyboards/handwired/tenstad/keyboard.json
new file mode 100644
index 00000000000..1220d3b107f
--- /dev/null
+++ b/keyboards/handwired/tenstad/keyboard.json
@@ -0,0 +1,85 @@
+{
+ "manufacturer": "Amund Tenstad",
+ "keyboard_name": "tenstad",
+ "maintainer": "tenstad",
+ "bootloader": "rp2040",
+ "diode_direction": "ROW2COL",
+ "features": {
+ "bootmagic": true,
+ "extrakey": true,
+ "mousekey": true,
+ "nkro": true
+ },
+ "matrix_pins": {
+ "cols": ["GP29", "GP28", "GP27", "GP26", "GP15", "GP14"],
+ "rows": ["GP3", "GP4", "GP5", "GP6"]
+ },
+ "processor": "RP2040",
+ "split": {
+ "enabled": true,
+ "serial": {
+ "driver": "vendor"
+ },
+ "transport": {
+ "protocol": "serial"
+ }
+ },
+ "url": "https://github.com/tenstad/keyboard",
+ "usb": {
+ "device_version": "1.0.0",
+ "pid": "0x0000",
+ "vid": "0xFEED"
+ },
+ "layouts": {
+ "LAYOUT_split_3x6_5": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 1.35},
+ {"matrix": [0, 1], "x": 1, "y": 0.95},
+ {"matrix": [0, 2], "x": 2.35, "y": 0.35},
+ {"matrix": [0, 3], "x": 3.35, "y": 0},
+ {"matrix": [0, 4], "x": 4.65, "y": 0.4},
+ {"matrix": [0, 5], "x": 5.65, "y": 0.4},
+ {"matrix": [4, 5], "x": 12.25, "y": 0.4},
+ {"matrix": [4, 4], "x": 13.25, "y": 0.4},
+ {"matrix": [4, 3], "x": 14.55, "y": 0},
+ {"matrix": [4, 2], "x": 15.55, "y": 0.35},
+ {"matrix": [4, 1], "x": 16.9, "y": 0.95},
+ {"matrix": [4, 0], "x": 17.9, "y": 1.35},
+ {"matrix": [1, 0], "x": 0.1, "y": 2.35},
+ {"matrix": [1, 1], "x": 1.1, "y": 1.95},
+ {"matrix": [1, 2], "x": 2.4, "y": 1.35},
+ {"matrix": [1, 3], "x": 3.4, "y": 1},
+ {"matrix": [1, 4], "x": 4.65, "y": 1.4},
+ {"matrix": [1, 5], "x": 5.65, "y": 1.4},
+ {"matrix": [5, 5], "x": 12.25, "y": 1.4},
+ {"matrix": [5, 4], "x": 13.25, "y": 1.4},
+ {"matrix": [5, 3], "x": 14.5, "y": 1},
+ {"matrix": [5, 2], "x": 15.5, "y": 1.35},
+ {"matrix": [5, 1], "x": 16.8, "y": 1.95},
+ {"matrix": [5, 0], "x": 17.8, "y": 2.35},
+ {"matrix": [2, 0], "x": 0.2, "y": 3.35},
+ {"matrix": [2, 1], "x": 1.2, "y": 2.95},
+ {"matrix": [2, 2], "x": 2.45, "y": 2.35},
+ {"matrix": [2, 3], "x": 3.45, "y": 2},
+ {"matrix": [2, 4], "x": 4.65, "y": 2.4},
+ {"matrix": [2, 5], "x": 5.65, "y": 2.4},
+ {"matrix": [6, 5], "x": 12.25, "y": 2.4},
+ {"matrix": [6, 4], "x": 13.25, "y": 2.4},
+ {"matrix": [6, 3], "x": 14.45, "y": 2},
+ {"matrix": [6, 2], "x": 15.45, "y": 2.35},
+ {"matrix": [6, 1], "x": 16.7, "y": 2.95},
+ {"matrix": [6, 0], "x": 17.7, "y": 3.35},
+ {"matrix": [3, 5], "x": 6.85, "y": 3},
+ {"matrix": [3, 3], "x": 7.95, "y": 3.35},
+ {"matrix": [3, 4], "x": 5.6, "y": 3.95},
+ {"matrix": [3, 1], "x": 6.7, "y": 4.1},
+ {"matrix": [3, 2], "x": 7.8, "y": 4.45},
+ {"matrix": [7, 3], "x": 9.95, "y": 3.35},
+ {"matrix": [7, 5], "x": 11.05, "y": 3},
+ {"matrix": [7, 2], "x": 10.1, "y": 4.45},
+ {"matrix": [7, 1], "x": 11.2, "y": 4.1},
+ {"matrix": [7, 4], "x": 12.3, "y": 3.95}
+ ]
+ }
+ }
+}
diff --git a/keyboards/handwired/tenstad/keymaps/default/keymap.json b/keyboards/handwired/tenstad/keymaps/default/keymap.json
new file mode 100644
index 00000000000..4882e307321
--- /dev/null
+++ b/keyboards/handwired/tenstad/keymaps/default/keymap.json
@@ -0,0 +1,55 @@
+{
+ "keyboard": "handwired/tenstad",
+ "keymap": "default",
+ "layout": "LAYOUT_split_3x6_5",
+ "layers": [
+ [
+ "KC_ESC",
+ "KC_Q",
+ "KC_W",
+ "KC_E",
+ "KC_R",
+ "KC_T",
+ "KC_Y",
+ "KC_U",
+ "KC_I",
+ "KC_O",
+ "KC_P",
+ "KC_RBRC",
+ "KC_TAB",
+ "KC_A",
+ "KC_S",
+ "KC_D",
+ "KC_F",
+ "KC_G",
+ "KC_H",
+ "KC_J",
+ "KC_K",
+ "KC_L",
+ "KC_GRV",
+ "KC_QUOT",
+ "KC_LCTL",
+ "KC_Z",
+ "KC_X",
+ "KC_C",
+ "KC_V",
+ "KC_B",
+ "KC_N",
+ "KC_M",
+ "KC_COMM",
+ "KC_DOT",
+ "KC_MINS",
+ "KC_RSFT",
+ "KC_NO",
+ "KC_NO",
+ "KC_TAB",
+ "KC_NO",
+ "KC_NO",
+ "KC_DEL",
+ "KC_NO",
+ "KC_BSPC",
+ "KC_SPC",
+ "KC_ENT"
+ ]
+ ]
+}
diff --git a/keyboards/handwired/tenstad/readme.md b/keyboards/handwired/tenstad/readme.md
new file mode 100644
index 00000000000..8ed97513303
--- /dev/null
+++ b/keyboards/handwired/tenstad/readme.md
@@ -0,0 +1,19 @@
+# tenstad
+
+
+
+[tenstad/keyboard](https://github.com/tenstad/keyboard) - hand-soldered ergonomic split 3x6 keyboard with 5 thumb keys
+
+* Keyboard Maintainer: [Amund Tenstad](https://github.com/tenstad)
+* Hardware Supported: RP2040 Zero
+* Hardware Availability: [List of Parts](https://github.com/tenstad/keyboard/blob/main/README.md#parts) from [AliExpress](https://aliexpress.com)
+
+Make example for this keyboard (after setting up your build environment):
+
+ make handwired/tenstad:default
+
+Flashing example for this keyboard:
+
+ make handwired/tenstad:default:flash
+
+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/handwired/tractyl_manuform/5x6_right/f411/config.h b/keyboards/handwired/tractyl_manuform/5x6_right/f411/config.h
index 64169da7e50..28acc1e69b7 100644
--- a/keyboards/handwired/tractyl_manuform/5x6_right/f411/config.h
+++ b/keyboards/handwired/tractyl_manuform/5x6_right/f411/config.h
@@ -28,7 +28,6 @@ along with this program. If not, see .
//#define WS2812_PWM_COMPLEMENTARY_OUTPUT // Define for a complementary timer output (TIMx_CHyN); omit for a normal timer output (TIMx_CHy).
#define WS2812_PWM_DMA_STREAM STM32_DMA1_STREAM7 // DMA Stream for TIMx_UP, see the respective reference manual for the appropriate values for your MCU.
#define WS2812_PWM_DMA_CHANNEL 3 // DMA Channel for TIMx_UP, see the respective reference manual for the appropriate values for your MCU.
-#define WS2812_PWM_TARGET_PERIOD 800000
#define DEBUG_LED_PIN C13
diff --git a/keyboards/herevoland/buff75/keyboard.json b/keyboards/herevoland/buff75/keyboard.json
new file mode 100644
index 00000000000..15f3e27ac18
--- /dev/null
+++ b/keyboards/herevoland/buff75/keyboard.json
@@ -0,0 +1,137 @@
+{
+ "keyboard_name": "Buff75",
+ "processor": "STM32F103",
+ "bootloader": "stm32duino",
+ "manufacturer": "HereVoLand",
+ "url": "",
+ "maintainer": "Here VoLand @Vem",
+ "usb": {
+ "vid": "0xB727",
+ "pid": "0xB727",
+ "device_version": "0.0.1"
+ },
+ "features": {
+ "bootmagic": true,
+ "mousekey": true,
+ "extrakey": true,
+ "nkro": true,
+ "rgblight": true
+ },
+ "rgblight": {
+ "led_count": 1,
+ "brightness_steps": 8,
+ "saturation_steps": 8,
+ "sleep": true,
+ "animations": {
+ "breathing": true,
+ "rainbow_mood": true,
+ "rainbow_swirl": true,
+ "snake": true,
+ "knight": true,
+ "christmas": true,
+ "static_gradient": true,
+ "alternating": true,
+ "twinkle": true
+ }
+ },
+ "ws2812": {
+ "pin": "B2"
+ },
+ "diode_direction": "COL2ROW",
+ "matrix_pins": {
+ "cols": ["B9", "B8", "B7", "B6", "B5", "B4", "B3", "A15", "A8", "B15", "B14", "B13", "B12", "A3", "A4" ],
+ "rows": ["A5", "B10", "B1", "B0", "A7", "A6"]
+ },
+ "layouts": {
+ "LAYOUT": {
+ "layout": [
+ {"label":"Esc", "matrix": [0,0], "x":0, "y":0},
+ {"label":"F1", "matrix": [0,1], "x":1.5, "y":0},
+ {"label":"F2", "matrix": [0,2], "x":2.5, "y":0},
+ {"label":"F3", "matrix": [0,3], "x":3.5, "y":0},
+ {"label":"F4", "matrix": [0,4], "x":4.5, "y":0},
+ {"label":"F5", "matrix": [0,6], "x":6, "y":0},
+ {"label":"F6", "matrix": [0,7], "x":7, "y":0},
+ {"label":"F7", "matrix": [0,8], "x":8, "y":0},
+ {"label":"F8", "matrix": [0,9], "x":9, "y":0},
+ {"label":"F9", "matrix": [0,10], "x":10.5, "y":0},
+ {"label":"F10", "matrix": [0,11], "x":11.5, "y":0},
+ {"label":"F11", "matrix": [0,12], "x":12.5, "y":0},
+ {"label":"F12", "matrix": [0,13], "x":13.5, "y":0},
+ {"label":"Home", "matrix": [0,14], "x":15, "y":0},
+
+ {"label":"`~", "matrix": [1,0], "x":0, "y":1.25},
+ {"label":"1!", "matrix": [1,1], "x":1, "y":1.25},
+ {"label":"2@", "matrix": [1,2], "x":2, "y":1.25},
+ {"label":"3#", "matrix": [1,3], "x":3, "y":1.25},
+ {"label":"4$", "matrix": [1,4], "x":4, "y":1.25},
+ {"label":"5%", "matrix": [1,5], "x":5, "y":1.25},
+ {"label":"6^", "matrix": [1,6], "x":6, "y":1.25},
+ {"label":"7&", "matrix": [1,7], "x":7, "y":1.25},
+ {"label":"8*", "matrix": [1,8], "x":8, "y":1.25},
+ {"label":"9(", "matrix": [1,9], "x":9, "y":1.25},
+ {"label":"0)", "matrix": [1,10], "x":10, "y":1.25},
+ {"label":"-_", "matrix": [1,11], "x":11, "y":1.25},
+ {"label":"=+", "matrix": [1,12], "x":12, "y":1.25},
+ {"label":"Backspace", "matrix": [1,13], "x":13, "y":1.25},
+ {"label":"Page Up", "matrix": [1,14], "x":15, "y":1.25},
+
+ {"label":"Tab", "matrix": [2,0], "x":0, "y":2.25, "w":1.5},
+ {"label":"Q", "matrix": [2,1], "x":1.5, "y":2.25},
+ {"label":"W", "matrix": [2,2], "x":2.5, "y":2.25},
+ {"label":"E", "matrix": [2,3], "x":3.5, "y":2.25},
+ {"label":"R", "matrix": [2,4], "x":4.5, "y":2.25},
+ {"label":"T", "matrix": [2,5], "x":5.5, "y":2.25},
+ {"label":"Y", "matrix": [2,6], "x":6.5, "y":2.25},
+ {"label":"U", "matrix": [2,7], "x":7.5, "y":2.25},
+ {"label":"I", "matrix": [2,8], "x":8.5, "y":2.25},
+ {"label":"O", "matrix": [2,9], "x":9.5, "y":2.25},
+ {"label":"P", "matrix": [2,10], "x":10.5, "y":2.25},
+ {"label":"[", "matrix": [2,11], "x":11.5, "y":2.25},
+ {"label":"]", "matrix": [2,12], "x":12.5, "y":2.25},
+ {"label":"\\", "matrix": [2,13], "x":13.5, "y":2.25, "w":1.5},
+ {"label":"Page Down", "matrix": [2,14], "x":15, "y":2.25},
+
+ {"label":"Caps Lock", "matrix": [3,0], "x":0, "y":3.25, "w":1.75},
+ {"label":"A", "matrix": [3,1], "x":1.75, "y":3.25},
+ {"label":"S", "matrix": [3,2], "x":2.75, "y":3.25},
+ {"label":"D", "matrix": [3,3], "x":3.75, "y":3.25},
+ {"label":"F", "matrix": [3,4], "x":4.75, "y":3.25},
+ {"label":"G", "matrix": [3,5], "x":5.75, "y":3.25},
+ {"label":"H", "matrix": [3,6], "x":6.75, "y":3.25},
+ {"label":"J", "matrix": [3,7], "x":7.75, "y":3.25},
+ {"label":"K", "matrix": [3,8], "x":8.75, "y":3.25},
+ {"label":"L", "matrix": [3,9], "x":9.75, "y":3.25},
+ {"label":";", "matrix": [3,10], "x":10.75, "y":3.25},
+ {"label":"'", "matrix": [3,11], "x":11.75, "y":3.25},
+ {"label":"Enter", "matrix": [3,13], "x":12.75, "y":3.25, "w":2.25},
+ {"label":"End", "matrix": [3,14], "x":15, "y":3.25},
+
+ {"label":"Shift", "matrix": [4,0], "x":0, "y":4.25, "w":2.25},
+ {"label":"Z", "matrix": [4,2], "x":2.25, "y":4.25},
+ {"label":"X", "matrix": [4,3], "x":3.25, "y":4.25},
+ {"label":"C", "matrix": [4,4], "x":4.25, "y":4.25},
+ {"label":"V", "matrix": [4,5], "x":5.25, "y":4.25},
+ {"label":"B", "matrix": [4,6], "x":6.25, "y":4.25},
+ {"label":"N", "matrix": [4,7], "x":7.25, "y":4.25},
+ {"label":"M", "matrix": [4,8], "x":8.25, "y":4.25},
+ {"label":",", "matrix": [4,9], "x":9.25, "y":4.25},
+ {"label":".", "matrix": [4,10], "x":10.25, "y":4.25},
+ {"label":"/", "matrix": [4,11], "x":11.25, "y":4.25},
+ {"label":"Shift", "matrix": [4,12], "x":12.25, "y":4.25, "w":1.75},
+ {"label":"Up", "matrix": [4,13], "x":14, "y":4.25},
+ {"label":"End", "matrix": [4,14], "x":15, "y":4.25},
+
+ {"label":"Ctrl", "matrix": [5,0], "x":0, "y":5.25, "w":1.25},
+ {"label":"Win", "matrix": [5,1], "x":1.25, "y":5.25, "w":1.25},
+ {"label":"Alt", "matrix": [5,2], "x":2.5, "y":5.25, "w":1.25},
+ {"label":"Space", "matrix": [5,6], "x":3.75, "y":5.25, "w":6.25},
+ {"label":"Alt", "matrix": [5,10], "x":10, "y":5.25, "w":1.25},
+ {"label":"Fn", "matrix": [5,11], "x":11.25, "y":5.25, "w":1.25},
+ {"label":"Left", "matrix": [5,12], "x":13, "y":5.25},
+ {"label":"Down", "matrix": [5,13], "x":14, "y":5.25},
+ {"label":"Right", "matrix": [5,14], "x":15, "y":5.25}
+ ]
+ }
+ }
+}
diff --git a/keyboards/herevoland/buff75/keymaps/default/keymap.c b/keyboards/herevoland/buff75/keymaps/default/keymap.c
new file mode 100644
index 00000000000..28762b9a17c
--- /dev/null
+++ b/keyboards/herevoland/buff75/keymaps/default/keymap.c
@@ -0,0 +1,36 @@
+/* Copyright 2024 楽(HereVoLand @Vem)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include QMK_KEYBOARD_H
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+ [0] = LAYOUT(
+ KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_HOME,
+ 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_EQL, KC_BSPC, KC_PGUP,
+ KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGDN,
+ KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_DEL,
+ KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM,KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_END,
+ KC_LCTL, KC_LGUI,KC_LALT, KC_SPC, KC_RALT, MO(1), KC_LEFT, KC_DOWN, KC_RIGHT
+ ),
+ [1] = LAYOUT(
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PSCR,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_HOME, KC_UP, KC_END, KC_TRNS, KC_TRNS,
+ KC_CAPS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_HOME, KC_PGUP, KC_LEFT, KC_RGHT, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_END, KC_PGDN, KC_DOWN, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_LCTL, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
+ )
+};
diff --git a/keyboards/herevoland/buff75/matrix_diagram.md b/keyboards/herevoland/buff75/matrix_diagram.md
new file mode 100644
index 00000000000..35cca7ec06f
--- /dev/null
+++ b/keyboards/herevoland/buff75/matrix_diagram.md
@@ -0,0 +1,18 @@
+# Matrix Diagram for Buff75
+
+```
+ ┌───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐ ┌───┐
+ │00 │ │01 │02 │03 │04 │ │06 │07 │08 │09 │ │0A │0B │0C │0D │ │0E │
+ └───┘ └───┴───┴───┴───┘ └───┴───┴───┴───┘ └───┴───┴───┴───┘ └───┘
+ ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┬───┐
+ │10 │11 │12 │13 │14 │15 │16 │17 │18 │19 │1A │1B │1C │1D │1E │
+ ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────┬──┼───┤
+ │20 │21 │22 │23 │24 │25 │26 │27 │28 │29 │2A │2B │2C │2D│2E │
+ ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬─────┴──┼───┤
+ │30 │31 │32 │33 │34 │35 │36 │37 │38 │39 │3A │3B │3D │3E │
+ ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────┬───┼───┤
+ │40 │42 │43 │44 │45 │46 │47 │48 │49 │4A │4B │4C │4D │4E │
+ ├────┬───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴──┬┴───┴┬─┬───┼───┼───┤
+ │50 │51 │52 │56 │5A │ 5B │ │5C │5D |5E |
+ └────┴────┴────┴────────────────────────┴───┴─────┘ └───┴───┘───┘
+```
diff --git a/keyboards/herevoland/buff75/readme.md b/keyboards/herevoland/buff75/readme.md
new file mode 100644
index 00000000000..b5ce6407d71
--- /dev/null
+++ b/keyboards/herevoland/buff75/readme.md
@@ -0,0 +1,25 @@
+# Buff75
+
+
+An 75%/TenKeyLess sized keyboard with 1 RGB.
+
+* Keyboard Maintainer: [HereVoLand](https://github.com/Vem-596)
+* Hardware Supported: buff75
+* Hardware Availability: [BUFF Customer-Keyboard](https://shop107132374.taobao.com)
+
+Make example for this keyboard (after setting up your build environment):
+
+ make herevoland/buff75:default
+
+Flashing example for this keyboard:
+
+ make herevoland/buff75:default:flash
+
+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).
+
+## Bootloader
+
+Enter the bootloader in 2 ways:
+
+- **Bootmagic reset**: Hold down the key at (0,0) in the matrix (usually the top left key which is Escape in this keyboard) and plug in the keyboard
+- **Keycode in layout**: Press the key mapped to `QK_BOOT`
diff --git a/keyboards/idyllic/pizzapad/keyboard.json b/keyboards/idyllic/pizzapad/keyboard.json
new file mode 100644
index 00000000000..638db198227
--- /dev/null
+++ b/keyboards/idyllic/pizzapad/keyboard.json
@@ -0,0 +1,36 @@
+{
+ "manufacturer": "Zykrah",
+ "keyboard_name": "Pizza Pad",
+ "maintainer": "zykrah",
+ "processor": "RP2040",
+ "bootloader": "rp2040",
+ "diode_direction": "COL2ROW",
+ "dynamic_keymap": {
+ "layer_count": 6
+ },
+ "matrix_pins": {
+ "cols": ["GP1", "GP0", "GP7"],
+ "rows": ["GP6", "GP29", "GP28"]
+ },
+ "usb": {
+ "device_version": "0.0.1",
+ "pid": "0x5050",
+ "vid": "0x7A79"
+ },
+ "community_layouts": ["ortho_3x3"],
+ "layouts": {
+ "LAYOUT_ortho_3x3": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [0, 1], "x": 1, "y": 0},
+ {"matrix": [0, 2], "x": 2, "y": 0},
+ {"matrix": [1, 0], "x": 0, "y": 1},
+ {"matrix": [1, 1], "x": 1, "y": 1},
+ {"matrix": [1, 2], "x": 2, "y": 1},
+ {"matrix": [2, 0], "x": 0, "y": 2},
+ {"matrix": [2, 1], "x": 1, "y": 2},
+ {"matrix": [2, 2], "x": 2, "y": 2}
+ ]
+ }
+ }
+}
diff --git a/keyboards/idyllic/pizzapad/keymaps/default/keymap.c b/keyboards/idyllic/pizzapad/keymaps/default/keymap.c
new file mode 100644
index 00000000000..333b33bc0b4
--- /dev/null
+++ b/keyboards/idyllic/pizzapad/keymaps/default/keymap.c
@@ -0,0 +1,12 @@
+// Copyright 2024 Zykrah (@zykrah)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include QMK_KEYBOARD_H
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+ [0] = LAYOUT_ortho_3x3(
+ KC_P7, KC_P8, KC_P9,
+ KC_P4, KC_P5, KC_P6,
+ KC_P1, KC_P2, KC_P3
+ )
+};
diff --git a/keyboards/idyllic/pizzapad/readme.md b/keyboards/idyllic/pizzapad/readme.md
new file mode 100644
index 00000000000..04098cb522d
--- /dev/null
+++ b/keyboards/idyllic/pizzapad/readme.md
@@ -0,0 +1,27 @@
+# Pizza Pad PCB
+
+
+
+A 3x3 PCB designed for the Idyllic Pretty Pad.
+
+* Keyboard Maintainer: Zykrah
+* Hardware Supported: Pizza Pad PCB (using a SEEED XIAO RP2040)
+* Hardware Availability: [Mechstock](https://mechstock.com.au/)
+
+Make example for this keyboard (after setting up your build environment):
+
+ make idyllic/pizzapad:default
+
+Flashing example for this keyboard:
+
+ make idyllic/pizzapad:default:flash
+
+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).
+
+## Bootloader
+
+Enter the bootloader in 3 ways:
+
+* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (usually the top left key or Escape) and plug in the keyboard
+* **Physical reset button**: Briefly press both the `BOOT` and `RESET` buttons at the same time
+* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available
diff --git a/keyboards/inett_studio/sqx/hotswap/config.h b/keyboards/inett_studio/sqx/hotswap/config.h
index 4172a72379f..22d2e739cbb 100644
--- a/keyboards/inett_studio/sqx/hotswap/config.h
+++ b/keyboards/inett_studio/sqx/hotswap/config.h
@@ -20,3 +20,5 @@
#define IS31FL3731_I2C_ADDRESS_1 IS31FL3731_I2C_ADDRESS_GND
#define IS31FL3731_I2C_ADDRESS_2 IS31FL3731_I2C_ADDRESS_VCC
+
+#define RGB_MATRIX_DISABLE_SHARED_KEYCODES
diff --git a/keyboards/inett_studio/sqx/universal/config.h b/keyboards/inett_studio/sqx/universal/config.h
index 4172a72379f..22d2e739cbb 100644
--- a/keyboards/inett_studio/sqx/universal/config.h
+++ b/keyboards/inett_studio/sqx/universal/config.h
@@ -20,3 +20,5 @@
#define IS31FL3731_I2C_ADDRESS_1 IS31FL3731_I2C_ADDRESS_GND
#define IS31FL3731_I2C_ADDRESS_2 IS31FL3731_I2C_ADDRESS_VCC
+
+#define RGB_MATRIX_DISABLE_SHARED_KEYCODES
diff --git a/keyboards/kprepublic/bm60hsrgb_ec/rev2/config.h b/keyboards/kprepublic/bm60hsrgb_ec/rev2/config.h
index b58434efece..ddb8a2525ff 100644
--- a/keyboards/kprepublic/bm60hsrgb_ec/rev2/config.h
+++ b/keyboards/kprepublic/bm60hsrgb_ec/rev2/config.h
@@ -16,3 +16,5 @@
#pragma once
#define IS31FL3733_I2C_ADDRESS_1 IS31FL3733_I2C_ADDRESS_GND_GND
+
+#define RGB_MATRIX_DISABLE_SHARED_KEYCODES
diff --git a/keyboards/kprepublic/bm68hsrgb/rev2/config.h b/keyboards/kprepublic/bm68hsrgb/rev2/config.h
index f35697b992e..026cbdcdca0 100644
--- a/keyboards/kprepublic/bm68hsrgb/rev2/config.h
+++ b/keyboards/kprepublic/bm68hsrgb/rev2/config.h
@@ -17,3 +17,5 @@
#pragma once
#define IS31FL3741_I2C_ADDRESS_1 IS31FL3741_I2C_ADDRESS_GND
+
+#define RGB_MATRIX_DISABLE_SHARED_KEYCODES
diff --git a/keyboards/lily58/lite_rev3/config.h b/keyboards/lily58/lite_rev3/config.h
new file mode 100644
index 00000000000..9d2d289f5bb
--- /dev/null
+++ b/keyboards/lily58/lite_rev3/config.h
@@ -0,0 +1,14 @@
+// Copyright 2023 yuchi
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET
+#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT 500U
+
+#define SERIAL_USART_FULL_DUPLEX
+#define SERIAL_USART_TX_PIN GP0
+#define SERIAL_USART_RX_PIN GP1
+
+#define I2C_DRIVER I2CD1
+#define I2C1_SDA_PIN GP14
+#define I2C1_SCL_PIN GP15
diff --git a/keyboards/lily58/lite_rev3/halconf.h b/keyboards/lily58/lite_rev3/halconf.h
new file mode 100644
index 00000000000..4639740d44e
--- /dev/null
+++ b/keyboards/lily58/lite_rev3/halconf.h
@@ -0,0 +1,7 @@
+// Copyright 2024 QMK
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
+
+#define HAL_USE_I2C TRUE
+
+#include_next
\ No newline at end of file
diff --git a/keyboards/lily58/lite_rev3/keyboard.json b/keyboards/lily58/lite_rev3/keyboard.json
new file mode 100644
index 00000000000..2073c0661e5
--- /dev/null
+++ b/keyboards/lily58/lite_rev3/keyboard.json
@@ -0,0 +1,104 @@
+{
+ "keyboard_name": "Lily58 Lite Rev3",
+ "manufacturer": "Liliums",
+ "maintainer": "yuchi",
+ "url": "",
+ "processor": "RP2040",
+ "bootloader": "rp2040",
+ "diode_direction": "COL2ROW",
+ "usb": {
+ "vid": "0x1209",
+ "pid": "0x5801",
+ "device_version": "1.0.0"
+ },
+ "split": {
+ "enabled": true,
+ "serial": {
+ "driver": "vendor"
+ }
+ },
+ "matrix_pins": {
+ "cols": ["GP8", "GP7", "GP6", "GP5", "GP4", "GP3"],
+ "rows": ["GP13", "GP12", "GP11", "GP10", "GP9"]
+ },
+ "features": {
+ "oled": true,
+ "bootmagic": true,
+ "extrakey": true,
+ "mousekey": true,
+ "nkro": true
+ },
+ "layouts": {
+ "LAYOUT": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0.5},
+ {"matrix": [0, 1], "x": 1, "y": 0.375},
+ {"matrix": [0, 2], "x": 2, "y": 0.125},
+ {"matrix": [0, 3], "x": 3, "y": 0},
+ {"matrix": [0, 4], "x": 4, "y": 0.125},
+ {"matrix": [0, 5], "x": 5, "y": 0.25},
+
+ {"matrix": [5, 5], "x": 10.5, "y": 0.25},
+ {"matrix": [5, 4], "x": 11.5, "y": 0.125},
+ {"matrix": [5, 3], "x": 12.5, "y": 0},
+ {"matrix": [5, 2], "x": 13.5, "y": 0.125},
+ {"matrix": [5, 1], "x": 14.5, "y": 0.375},
+ {"matrix": [5, 0], "x": 15.5, "y": 0.5},
+
+ {"matrix": [1, 0], "x": 0, "y": 1.5},
+ {"matrix": [1, 1], "x": 1, "y": 1.375},
+ {"matrix": [1, 2], "x": 2, "y": 1.125},
+ {"matrix": [1, 3], "x": 3, "y": 1},
+ {"matrix": [1, 4], "x": 4, "y": 1.125},
+ {"matrix": [1, 5], "x": 5, "y": 1.25},
+
+ {"matrix": [6, 5], "x": 10.5, "y": 1.25},
+ {"matrix": [6, 4], "x": 11.5, "y": 1.125},
+ {"matrix": [6, 3], "x": 12.5, "y": 1},
+ {"matrix": [6, 2], "x": 13.5, "y": 1.125},
+ {"matrix": [6, 1], "x": 14.5, "y": 1.375},
+ {"matrix": [6, 0], "x": 15.5, "y": 1.5},
+
+ {"matrix": [2, 0], "x": 0, "y": 2.5},
+ {"matrix": [2, 1], "x": 1, "y": 2.375},
+ {"matrix": [2, 2], "x": 2, "y": 2.125},
+ {"matrix": [2, 3], "x": 3, "y": 2},
+ {"matrix": [2, 4], "x": 4, "y": 2.125},
+ {"matrix": [2, 5], "x": 5, "y": 2.25},
+
+ {"matrix": [7, 5], "x": 10.5, "y": 2.25},
+ {"matrix": [7, 4], "x": 11.5, "y": 2.125},
+ {"matrix": [7, 3], "x": 12.5, "y": 2},
+ {"matrix": [7, 2], "x": 13.5, "y": 2.125},
+ {"matrix": [7, 1], "x": 14.5, "y": 2.375},
+ {"matrix": [7, 0], "x": 15.5, "y": 2.5},
+
+ {"matrix": [3, 0], "x": 0, "y": 3.5},
+ {"matrix": [3, 1], "x": 1, "y": 3.375},
+ {"matrix": [3, 2], "x": 2, "y": 3.125},
+ {"matrix": [3, 3], "x": 3, "y": 3},
+ {"matrix": [3, 4], "x": 4, "y": 3.125},
+ {"matrix": [3, 5], "x": 5, "y": 3.25},
+ {"matrix": [4, 5], "x": 6, "y": 2.75},
+
+ {"matrix": [9, 5], "x": 9.5, "y": 2.75},
+ {"matrix": [8, 5], "x": 10.5, "y": 3.25},
+ {"matrix": [8, 4], "x": 11.5, "y": 3.125},
+ {"matrix": [8, 3], "x": 12.5, "y": 3},
+ {"matrix": [8, 2], "x": 13.5, "y": 3.125},
+ {"matrix": [8, 1], "x": 14.5, "y": 3.375},
+ {"matrix": [8, 0], "x": 15.5, "y": 3.5},
+
+ {"matrix": [4, 1], "x": 2.5, "y": 4.125},
+ {"matrix": [4, 2], "x": 3.5, "y": 4.15},
+ {"matrix": [4, 3], "x": 4.5, "y": 4.25},
+ {"matrix": [4, 4], "x": 6, "y": 4.25, "h": 1.5},
+
+ {"matrix": [9, 4], "x": 9.5, "y": 4.25, "h": 1.5},
+ {"matrix": [9, 3], "x": 11, "y": 4.25},
+ {"matrix": [9, 2], "x": 12, "y": 4.15},
+ {"matrix": [9, 1], "x": 13, "y": 4.15}
+ ]
+ }
+ }
+}
diff --git a/keyboards/lily58/lite_rev3/mcuconf.h b/keyboards/lily58/lite_rev3/mcuconf.h
new file mode 100644
index 00000000000..432c72853ac
--- /dev/null
+++ b/keyboards/lily58/lite_rev3/mcuconf.h
@@ -0,0 +1,11 @@
+// Copyright 2024 QMK
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
+
+#include_next
+
+#undef RP_I2C_USE_I2C0
+#define RP_I2C_USE_I2C0 FALSE
+
+#undef RP_I2C_USE_I2C1
+#define RP_I2C_USE_I2C1 TRUE
diff --git a/keyboards/lily58/lite_rev3/readme.md b/keyboards/lily58/lite_rev3/readme.md
new file mode 100644
index 00000000000..54ce6229d1b
--- /dev/null
+++ b/keyboards/lily58/lite_rev3/readme.md
@@ -0,0 +1,28 @@
+# Lily58 Lite Rev3
+
+
+
+
+
+* Keyboard Maintainer: [yuchi](https://github.com/kata0510)
+* Hardware Supported: RP2040-Zero
+* Hardware Availability: [PCB Link](https://github.com/kata0510/Lily58/tree/master/Lite_Rev3)
+* Other Information(ja) [Link](https://docs.liliums.net/lily58-lite-rev3/about/)
+
+Make example for this keyboard (after setting up your build environment):
+
+ make lily58/lite_rev3:default
+
+Flashing example for this keyboard:
+
+ make lily58/lite_rev3:default:flash
+
+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).
+
+## Bootloader
+
+Enter the bootloader in 3 ways:
+
+* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (usually the top left key or Escape) and plug in the keyboard
+* **Physical reset button**: Briefly press the button on the back of the PCB - some may have pads you must short instead
+* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available
diff --git a/keyboards/madjax_macropad/keyboard.json b/keyboards/madjax_macropad/keyboard.json
new file mode 100644
index 00000000000..ac2802faef2
--- /dev/null
+++ b/keyboards/madjax_macropad/keyboard.json
@@ -0,0 +1,55 @@
+{
+ "manufacturer": "MadJax",
+ "keyboard_name": "madjax_macropad",
+ "maintainer": "guidoism",
+ "bootloader": "rp2040",
+ "diode_direction": "COL2ROW",
+ "features": {
+ "bootmagic": true,
+ "command": false,
+ "console": false,
+ "encoder": true,
+ "extrakey": true,
+ "mousekey": true,
+ "nkro": true
+ },
+ "matrix_pins": {
+ "cols": ["GP26", "GP27", "GP28", "GP29"],
+ "rows": ["GP6", "GP7", "GP0", "GP4", "GP3"]
+ },
+ "encoder": {
+ "rotary": [
+ {"pin_a": "GP1", "pin_b": "GP2"}
+ ]
+ },
+ "processor": "RP2040",
+ "url": "https://github.com/guidoism/madjax_macropad",
+ "usb": {
+ "device_version": "1.0.0",
+ "pid": "0x0000",
+ "vid": "0xFEED"
+ },
+ "layouts": {
+ "LAYOUT": {
+ "layout": [
+ {"matrix": [0, 3], "x": 3, "y": 0},
+ {"matrix": [1, 0], "x": 0, "y": 1},
+ {"matrix": [1, 1], "x": 1, "y": 1},
+ {"matrix": [1, 2], "x": 2, "y": 1},
+ {"matrix": [1, 3], "x": 3, "y": 1},
+ {"matrix": [2, 0], "x": 0, "y": 2},
+ {"matrix": [2, 1], "x": 1, "y": 2},
+ {"matrix": [2, 2], "x": 2, "y": 2},
+ {"matrix": [2, 3], "x": 3, "y": 2},
+ {"matrix": [3, 0], "x": 0, "y": 3},
+ {"matrix": [3, 1], "x": 1, "y": 3},
+ {"matrix": [3, 2], "x": 2, "y": 3},
+ {"matrix": [3, 3], "x": 3, "y": 3},
+ {"matrix": [4, 0], "x": 0, "y": 4},
+ {"matrix": [4, 1], "x": 1, "y": 4},
+ {"matrix": [4, 2], "x": 2, "y": 4},
+ {"matrix": [4, 3], "x": 3, "y": 4}
+ ]
+ }
+ }
+}
diff --git a/keyboards/madjax_macropad/keymaps/default/keymap.c b/keyboards/madjax_macropad/keymaps/default/keymap.c
new file mode 100644
index 00000000000..693438c1f3e
--- /dev/null
+++ b/keyboards/madjax_macropad/keymaps/default/keymap.c
@@ -0,0 +1,49 @@
+// Copyright 2023 QMK
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include QMK_KEYBOARD_H
+
+enum custom_keycodes {
+ KC_P00 = SAFE_RANGE
+};
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+ /*
+ * ┌───┐
+ * │ - │
+ * ┌───┬───┬───┼───┤
+ * │ 7 │ 8 │ 9 │ + │
+ * ├───┼───┼───┼───┤
+ * │ 4 │ 5 │ 6 │ % │
+ * ├───┼───┼───┼───┤
+ * │ 1 │ 2 │ 3 │ = │
+ * ├───┼───┼───┼───┤
+ * │ 0 │00 │ . │Ent│
+ * └───┴───┴───┴───┘
+ */
+ [0] = LAYOUT(
+ KC_PMNS,
+ KC_P7, KC_P8, KC_P9, KC_PPLS,
+ KC_P4, KC_P5, KC_P6, KC_PERC,
+ KC_P1, KC_P2, KC_P3, KC_EQL,
+ KC_P0, KC_P00, KC_PDOT, KC_PENT
+ )
+};
+
+bool process_record_user(uint16_t keycode, keyrecord_t *record) {
+ if (record->event.pressed) {
+ switch(keycode) {
+ case KC_P00:
+ tap_code(KC_P0);
+ tap_code(KC_P0);
+ return false;
+ }
+ }
+ return true;
+}
+
+#if defined(ENCODER_MAP_ENABLE)
+const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = {
+ [0] = { ENCODER_CCW_CW(KC_PGUP, KC_PGDN) }
+};
+#endif
diff --git a/keyboards/madjax_macropad/keymaps/default/rules.mk b/keyboards/madjax_macropad/keymaps/default/rules.mk
new file mode 100644
index 00000000000..ee325681483
--- /dev/null
+++ b/keyboards/madjax_macropad/keymaps/default/rules.mk
@@ -0,0 +1 @@
+ENCODER_MAP_ENABLE = yes
diff --git a/keyboards/madjax_macropad/readme.md b/keyboards/madjax_macropad/readme.md
new file mode 100644
index 00000000000..1abe17ecca9
--- /dev/null
+++ b/keyboards/madjax_macropad/readme.md
@@ -0,0 +1,24 @@
+# MadJax Macropad
+
+* Keyboard Maintainer: [Guido Bartolucci](https://github.com/guidoism)
+* Hardware Supported: Seeed Studio XIAO RP2040
+* Hardware Availability: https://github.com/guidoism/madjax_macropad
+
+Make example for this keyboard (after setting up your build environment):
+
+ make madjax_macropad:default
+
+Flashing example for this keyboard:
+
+ make madjax_macropad:default:flash
+
+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).
+
+## Bootloader
+
+Enter the bootloader in 3 ways:
+
+* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (usually the top left key or Escape) and plug in the keyboard
+* **Physical reset button**: Briefly press the button on the back of the PCB - some may have pads you must short instead
+* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available
+
diff --git a/keyboards/mechlovin/adelais/rgb_led/rev2/config.h b/keyboards/mechlovin/adelais/rgb_led/rev2/config.h
index 82b582bfe12..fea263d7fbe 100644
--- a/keyboards/mechlovin/adelais/rgb_led/rev2/config.h
+++ b/keyboards/mechlovin/adelais/rgb_led/rev2/config.h
@@ -2,3 +2,5 @@
#define IS31FL3731_I2C_ADDRESS_1 IS31FL3731_I2C_ADDRESS_GND
#define IS31FL3731_I2C_ADDRESS_2 IS31FL3731_I2C_ADDRESS_SDA
+
+#define RGB_MATRIX_DISABLE_SHARED_KEYCODES
diff --git a/keyboards/mechlovin/hannah60rgb/rev2/config.h b/keyboards/mechlovin/hannah60rgb/rev2/config.h
index 82b582bfe12..fea263d7fbe 100644
--- a/keyboards/mechlovin/hannah60rgb/rev2/config.h
+++ b/keyboards/mechlovin/hannah60rgb/rev2/config.h
@@ -2,3 +2,5 @@
#define IS31FL3731_I2C_ADDRESS_1 IS31FL3731_I2C_ADDRESS_GND
#define IS31FL3731_I2C_ADDRESS_2 IS31FL3731_I2C_ADDRESS_SDA
+
+#define RGB_MATRIX_DISABLE_SHARED_KEYCODES
diff --git a/keyboards/miiiw/blackio83/rev_0100/rev_0100.c b/keyboards/miiiw/blackio83/rev_0100/rev_0100.c
index 18f4c86510e..139bc1aaaef 100644
--- a/keyboards/miiiw/blackio83/rev_0100/rev_0100.c
+++ b/keyboards/miiiw/blackio83/rev_0100/rev_0100.c
@@ -165,7 +165,6 @@ uint32_t loop_10Hz(uint32_t trigger_time, void *cb_arg) {
wait_ms(50);
eeconfig_init();
#ifdef RGB_MATRIX_ENABLE
- extern void rgb_matrix_update_pwm_buffers(void);
for(int i = 0; i < 5; i++) {
rgb_matrix_set_color_all(RGB_WHITE);
rgb_matrix_update_pwm_buffers();
diff --git a/keyboards/mode/m60h/config.h b/keyboards/mode/m60h/config.h
index cde4ffdbc61..e51bff8ca51 100644
--- a/keyboards/mode/m60h/config.h
+++ b/keyboards/mode/m60h/config.h
@@ -6,5 +6,4 @@
#define WS2812_PWM_DRIVER PWMD4
#define WS2812_PWM_CHANNEL 4
#define WS2812_PWM_DMA_STREAM STM32_DMA1_STREAM6
-#define WS2812_PWM_DMA_CHANNEL 2
-#define WS2812_PWM_TARGET_PERIOD 800000
\ No newline at end of file
+#define WS2812_PWM_DMA_CHANNEL 2
\ No newline at end of file
diff --git a/keyboards/mode/m60h_f/config.h b/keyboards/mode/m60h_f/config.h
index cde4ffdbc61..e51bff8ca51 100644
--- a/keyboards/mode/m60h_f/config.h
+++ b/keyboards/mode/m60h_f/config.h
@@ -6,5 +6,4 @@
#define WS2812_PWM_DRIVER PWMD4
#define WS2812_PWM_CHANNEL 4
#define WS2812_PWM_DMA_STREAM STM32_DMA1_STREAM6
-#define WS2812_PWM_DMA_CHANNEL 2
-#define WS2812_PWM_TARGET_PERIOD 800000
\ No newline at end of file
+#define WS2812_PWM_DMA_CHANNEL 2
\ No newline at end of file
diff --git a/keyboards/mode/m60s/config.h b/keyboards/mode/m60s/config.h
index cde4ffdbc61..e51bff8ca51 100644
--- a/keyboards/mode/m60s/config.h
+++ b/keyboards/mode/m60s/config.h
@@ -6,5 +6,4 @@
#define WS2812_PWM_DRIVER PWMD4
#define WS2812_PWM_CHANNEL 4
#define WS2812_PWM_DMA_STREAM STM32_DMA1_STREAM6
-#define WS2812_PWM_DMA_CHANNEL 2
-#define WS2812_PWM_TARGET_PERIOD 800000
\ No newline at end of file
+#define WS2812_PWM_DMA_CHANNEL 2
\ No newline at end of file
diff --git a/keyboards/mountainmechdesigns/teton_78/keyboard.json b/keyboards/mountainmechdesigns/teton_78/keyboard.json
new file mode 100644
index 00000000000..d6f5ce9cd83
--- /dev/null
+++ b/keyboards/mountainmechdesigns/teton_78/keyboard.json
@@ -0,0 +1,113 @@
+{
+ "manufacturer": "Bennett Balogh",
+ "keyboard_name": "teton_78",
+ "maintainer": "qmk",
+ "bootloader": "atmel-dfu",
+ "bootmagic": {
+ "matrix": [0, 2]
+ },
+ "diode_direction": "COL2ROW",
+ "features": {
+ "bootmagic": true,
+ "command": false,
+ "console": false,
+ "extrakey": true,
+ "mousekey": true,
+ "nkro": true
+ },
+ "matrix_pins": {
+ "cols": ["F7", "F6", "F5", "F4", "F1", "F0", "B0", "B1", "B2", "B3", "D4", "D6", "D7", "B4", "B5", "B6", "C6", "C7"],
+ "rows": ["D0", "D1", "D2", "D3", "D5"]
+ },
+ "processor": "atmega32u4",
+ "url": "",
+ "usb": {
+ "device_version": "1.0.0",
+ "pid": "0x3349",
+ "vid": "0x8A5B"
+ },
+ "layouts": {
+ "LAYOUT": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [0, 1], "x": 0, "y": 1},
+ {"matrix": [0, 2], "x": 2.25, "y": 0},
+ {"matrix": [0, 3], "x": 3.25, "y": 0},
+ {"matrix": [0, 4], "x": 4.25, "y": 0},
+ {"matrix": [0, 5], "x": 5.25, "y": 0},
+ {"matrix": [0, 6], "x": 6.25, "y": 0},
+ {"matrix": [0, 7], "x": 7.25, "y": 0},
+ {"matrix": [0, 8], "x": 8.25, "y": 0},
+ {"matrix": [0, 9], "x": 9.25, "y": 0},
+ {"matrix": [0, 10], "x": 10.25, "y": 0},
+ {"matrix": [0, 11], "x": 11.25, "y": 0},
+ {"matrix": [0, 12], "x": 12.25, "y": 0},
+ {"matrix": [0, 13], "x": 13.25, "y": 0},
+ {"matrix": [0, 14], "x": 14.25, "y": 0},
+ {"matrix": [0, 15], "x": 15.25, "y": 0, "w": 2},
+ {"matrix": [0, 16], "x": 17.5, "y": 0},
+ {"matrix": [0, 17], "x": 18.5, "y": 0},
+ {"matrix": [1, 0], "x": 1, "y": 0},
+ {"matrix": [1, 1], "x": 1, "y": 1},
+ {"matrix": [1, 2], "x": 2.25, "y": 1, "w": 1.5},
+ {"matrix": [1, 3], "x": 3.75, "y": 1},
+ {"matrix": [1, 4], "x": 4.75, "y": 1},
+ {"matrix": [1, 5], "x": 5.75, "y": 1},
+ {"matrix": [1, 6], "x": 6.75, "y": 1},
+ {"matrix": [1, 7], "x": 7.75, "y": 1},
+ {"matrix": [1, 8], "x": 8.75, "y": 1},
+ {"matrix": [1, 9], "x": 9.75, "y": 1},
+ {"matrix": [1, 10], "x": 10.75, "y": 1},
+ {"matrix": [1, 11], "x": 11.75, "y": 1},
+ {"matrix": [1, 12], "x": 12.75, "y": 1},
+ {"matrix": [1, 13], "x": 13.75, "y": 1},
+ {"matrix": [1, 14], "x": 14.75, "y": 1},
+ {"matrix": [1, 15], "x": 15.75, "y": 1, "w": 1.5},
+ {"matrix": [1, 16], "x": 17.5, "y": 1},
+ {"matrix": [1, 17], "x": 18.5, "y": 1},
+ {"matrix": [2, 0], "x": 0, "y": 2},
+ {"matrix": [2, 1], "x": 1, "y": 2},
+ {"matrix": [2, 2], "x": 2.25, "y": 2, "w": 1.75},
+ {"matrix": [2, 3], "x": 4, "y": 2},
+ {"matrix": [2, 4], "x": 5, "y": 2},
+ {"matrix": [2, 5], "x": 6, "y": 2},
+ {"matrix": [2, 6], "x": 7, "y": 2},
+ {"matrix": [2, 7], "x": 8, "y": 2},
+ {"matrix": [2, 8], "x": 9, "y": 2},
+ {"matrix": [2, 9], "x": 10, "y": 2},
+ {"matrix": [2, 10], "x": 11, "y": 2},
+ {"matrix": [2, 11], "x": 12, "y": 2},
+ {"matrix": [2, 12], "x": 13, "y": 2},
+ {"matrix": [2, 13], "x": 14, "y": 2},
+ {"matrix": [2, 14], "x": 15, "y": 2, "w": 2.25},
+ {"matrix": [3, 0], "x": 0, "y": 3},
+ {"matrix": [3, 1], "x": 1, "y": 3},
+ {"matrix": [3, 2], "x": 2.25, "y": 3, "w": 2.25},
+ {"matrix": [3, 3], "x": 4.5, "y": 3},
+ {"matrix": [3, 4], "x": 5.5, "y": 3},
+ {"matrix": [3, 5], "x": 6.5, "y": 3},
+ {"matrix": [3, 6], "x": 7.5, "y": 3},
+ {"matrix": [3, 7], "x": 8.5, "y": 3},
+ {"matrix": [3, 8], "x": 9.5, "y": 3},
+ {"matrix": [3, 9], "x": 10.5, "y": 3},
+ {"matrix": [3, 10], "x": 11.5, "y": 3},
+ {"matrix": [3, 11], "x": 12.5, "y": 3},
+ {"matrix": [3, 12], "x": 13.5, "y": 3},
+ {"matrix": [3, 13], "x": 14.5, "y": 3, "w": 2.75},
+ {"matrix": [3, 16], "x": 17.5, "y": 3},
+ {"matrix": [4, 0], "x": 0, "y": 4},
+ {"matrix": [4, 1], "x": 1, "y": 4},
+ {"matrix": [4, 2], "x": 2.25, "y": 4, "w": 1.25},
+ {"matrix": [4, 3], "x": 3.5, "y": 4, "w": 1.25},
+ {"matrix": [4, 4], "x": 4.75, "y": 4, "w": 1.25},
+ {"matrix": [4, 7], "x": 6, "y": 4, "w": 6.25},
+ {"matrix": [4, 11], "x": 12.25, "y": 4, "w": 1.25},
+ {"matrix": [4, 12], "x": 13.5, "y": 4, "w": 1.25},
+ {"matrix": [4, 13], "x": 14.75, "y": 4, "w": 1.25},
+ {"matrix": [4, 14], "x": 16.5, "y": 4, "w": 1.25},
+ {"matrix": [4, 16], "x": 17.5, "y": 4, "w": 1.25},
+ {"matrix": [4, 17], "x": 18.5, "y": 4, "w": 1.25}
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/keyboards/mountainmechdesigns/teton_78/keymaps/default/keymap.c b/keyboards/mountainmechdesigns/teton_78/keymaps/default/keymap.c
new file mode 100644
index 00000000000..c4762d577d6
--- /dev/null
+++ b/keyboards/mountainmechdesigns/teton_78/keymaps/default/keymap.c
@@ -0,0 +1,29 @@
+/* Copyright 2024 Bennett Balogh LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include QMK_KEYBOARD_H
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+
+
+ [0] = LAYOUT(
+
+ KC_F1, KC_F6, 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_EQL, KC_BSPC, KC_INS, KC_HOME,
+ KC_F2, KC_F7, KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_DEL, KC_END,
+ KC_F3, KC_F8, KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT,
+ KC_F4, KC_F9, KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP,
+ KC_F5, KC_F10, KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, KC_RGUI, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT)
+};
diff --git a/keyboards/mountainmechdesigns/teton_78/readme.md b/keyboards/mountainmechdesigns/teton_78/readme.md
new file mode 100644
index 00000000000..40ef5c436bf
--- /dev/null
+++ b/keyboards/mountainmechdesigns/teton_78/readme.md
@@ -0,0 +1,37 @@
+# Teton 78 QMK Firmware
+
+## Introduction
+
+
+
+This is the QMK firmware repository for the Teton78, a 68XT solder and hotswao keyboard designed by Mountain Mech Designs - Bennett Balogh.
+
+The Teton 78 has entered GB and sucessfully finalized in November 2024 The IC page for the keyboard can be found [here](https://geekhack.org/index.php?topic=123275.0).
+The sale page can be found [here](https://www.mountainmechdesigns.com/)
+Discord link can be found [here](https://discord.gg/h9dMwRNfVy)
+
+## About
+
+* Keyboard Maintainer: [Bennett Balogh](https://github.com/AwesomeBalogh)
+* Hardware Supported: Atmega32u4
+* Hardware Availability: N/A
+
+## How to compile
+
+After setting up your build environment, you can compile the Teton 78 default keymap by using:
+
+ make mountainmechdesigns/teton_78:default
+
+Flash using
+
+ make mountainmechdesigns/teton_78:default:flash
+
+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).
+
+## Bootloader
+
+Enter the bootloader in 3 ways:
+
+* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (usually the top left key or Escape) and plug in the keyboard
+* **Physical reset button**: Briefly press the button on the back of the PCB - some may have pads you must short instead
+* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available
\ No newline at end of file
diff --git a/keyboards/owlab/voice65/hotswap/config.h b/keyboards/owlab/voice65/hotswap/config.h
index be6b66e58a8..97bde08548e 100644
--- a/keyboards/owlab/voice65/hotswap/config.h
+++ b/keyboards/owlab/voice65/hotswap/config.h
@@ -18,3 +18,5 @@ along with this program. If not, see .
#pragma once
#define IS31FL3741_I2C_ADDRESS_1 IS31FL3741_I2C_ADDRESS_GND
+
+#define RGB_MATRIX_DISABLE_SHARED_KEYCODES
diff --git a/keyboards/owlab/voice65/soldered/config.h b/keyboards/owlab/voice65/soldered/config.h
index be6b66e58a8..97bde08548e 100644
--- a/keyboards/owlab/voice65/soldered/config.h
+++ b/keyboards/owlab/voice65/soldered/config.h
@@ -18,3 +18,5 @@ along with this program. If not, see .
#pragma once
#define IS31FL3741_I2C_ADDRESS_1 IS31FL3741_I2C_ADDRESS_GND
+
+#define RGB_MATRIX_DISABLE_SHARED_KEYCODES
diff --git a/keyboards/qwertykeys/qk100/ansi/config.h b/keyboards/qwertykeys/qk100/ansi/config.h
index b78d15782ba..ceba1c798dd 100644
--- a/keyboards/qwertykeys/qk100/ansi/config.h
+++ b/keyboards/qwertykeys/qk100/ansi/config.h
@@ -30,3 +30,5 @@ along with this program. If not, see .
#define I2C1_DUTY_CYCLE FAST_DUTY_CYCLE_2
#define IS31FL3741_I2C_ADDRESS_1 IS31FL3741_I2C_ADDRESS_GND
+
+#define RGB_MATRIX_DISABLE_SHARED_KEYCODES
diff --git a/keyboards/sdrakbs/sdrakb00/keyboard.json b/keyboards/sdrakbs/sdrakb00/keyboard.json
new file mode 100644
index 00000000000..f9e24cc63f0
--- /dev/null
+++ b/keyboards/sdrakbs/sdrakb00/keyboard.json
@@ -0,0 +1,71 @@
+{
+ "manufacturer": "Diego Andres Rabaioli",
+ "keyboard_name": "sdrakb00",
+ "maintainer": "drabaioli",
+ "bootloader": "atmel-dfu",
+ "diode_direction": "COL2ROW",
+ "encoder": {
+ "rotary": [
+ {"pin_a": "B5", "pin_b": "B6", "resolution": 2}
+ ]
+ },
+ "features": {
+ "bootmagic": true,
+ "encoder": true,
+ "extrakey": true,
+ "mousekey": true,
+ "nkro": true,
+ "rgb_matrix": true
+ },
+ "matrix_pins": {
+ "cols": ["F0", "F1", "F4", "F5"],
+ "rows": ["D4", "D6", "D7"]
+ },
+ "processor": "atmega32u4",
+ "rgb_matrix": {
+ "driver": "ws2812",
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0, "flags": 4},
+ {"matrix": [0, 1], "x": 16, "y": 0, "flags": 4},
+ {"matrix": [0, 2], "x": 32, "y": 0, "flags": 4},
+ {"matrix": [1, 0], "x": 0, "y": 16, "flags": 4},
+ {"matrix": [1, 1], "x": 16, "y": 16, "flags": 4},
+ {"matrix": [1, 2], "x": 32, "y": 16, "flags": 4},
+ {"matrix": [1, 3], "x": 48, "y": 16, "flags": 4},
+ {"matrix": [2, 0], "x": 0, "y": 32, "flags": 4},
+ {"matrix": [2, 1], "x": 16, "y": 32, "flags": 4},
+ {"matrix": [2, 2], "x": 32, "y": 32, "flags": 4},
+ {"matrix": [2, 3], "x": 48, "y": 32, "flags": 4}
+ ],
+ "max_brightness": 100,
+ "sleep": true,
+ "timeout": 300000
+ },
+ "url": "https://github.com/drabaioli/SdraKb00",
+ "usb": {
+ "device_version": "1.0.0",
+ "pid": "0x4200",
+ "vid": "0x7331"
+ },
+ "ws2812": {
+ "pin": "B0"
+ },
+ "layouts": {
+ "LAYOUT_ortho_3x4": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [0, 1], "x": 1, "y": 0},
+ {"matrix": [0, 2], "x": 2, "y": 0},
+ {"matrix": [0, 3], "x": 3, "y": 0, "encoder": 0},
+ {"matrix": [1, 0], "x": 0, "y": 1},
+ {"matrix": [1, 1], "x": 1, "y": 1},
+ {"matrix": [1, 2], "x": 2, "y": 1},
+ {"matrix": [1, 3], "x": 3, "y": 1},
+ {"matrix": [2, 0], "x": 0, "y": 2},
+ {"matrix": [2, 1], "x": 1, "y": 2},
+ {"matrix": [2, 2], "x": 2, "y": 2},
+ {"matrix": [2, 3], "x": 3, "y": 2}
+ ]
+ }
+ }
+}
diff --git a/keyboards/sdrakbs/sdrakb00/keymaps/default/keymap.c b/keyboards/sdrakbs/sdrakb00/keymaps/default/keymap.c
new file mode 100644
index 00000000000..c5481b1076e
--- /dev/null
+++ b/keyboards/sdrakbs/sdrakb00/keymaps/default/keymap.c
@@ -0,0 +1,74 @@
+// Copyright 2023 QMK
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include QMK_KEYBOARD_H
+
+/* Keymap for 3x4 Macropad
+ *
+ * Layer 0 (Base Layer) - Numpad layout with mute button and layer toggle:
+ * ,----------------------,
+ * | 7 | 8 | 9 | MUTE |
+ * |-------+-------+-------+--------|
+ * | 4 | 5 | 6 | Layer1 |
+ * |-------+-------+-------+--------|
+ * | 1 | 2 | 3 | 0 |
+ * `-----------------------^--------'
+ *
+ * Layer 1 (Function Layer) - Accessed by holding MO(1):
+ * ,----------------------,
+ * | BKSP | / | - | ---- |
+ * |-------+-------+-------+--------|
+ * | = | * | + | ---- |
+ * |-------+-------+-------+--------|
+ * | ENTER | ---- | ---- | . |
+ * `-----------------------^--------'
+ *
+ * The base layer (0) provides standard numpad functionality with:
+ * - Numbers 0-9 in traditional numpad layout
+ * - Mute button in top right
+ * - Layer 1 momentary toggle (MO1) in middle right
+ *
+ * The function layer (1) adds:
+ * - Basic mathematical operators (+, -, *, /)
+ * - Backspace, Enter, and decimal point
+ * - Equal sign for calculations
+ * - Empty slots marked as ---- (KC_NO)
+ */
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+
+ [0] = LAYOUT_ortho_3x4(
+ KC_KP_7, KC_KP_8, KC_KP_9, KC_MUTE,
+ KC_KP_4, KC_KP_5, KC_KP_6, MO(1),
+ KC_KP_1, KC_KP_2, KC_KP_3, KC_KP_0
+ ),
+
+ [1] = LAYOUT_ortho_3x4(
+ KC_BACKSPACE, KC_KP_SLASH, KC_KP_MINUS, _______,
+ KC_EQUAL, KC_KP_ASTERISK, KC_KP_PLUS, _______,
+ KC_ENTER, _______, _______, KC_KP_DOT
+ )
+};
+
+
+/*
+ * Handle layer state changes by updating RGB matrix colors
+ *
+ * Sets RGB matrix colors based on active layer:
+ * - Layer 0: Light green (#88FB7A)
+ * - Layer 1: Red
+ * - Other layers: Red (fallback)
+ */
+layer_state_t layer_state_set_user(layer_state_t state) {
+ switch (get_highest_layer(state)) {
+ case 0:
+ rgb_matrix_sethsv(85, 255, 251); // #88FB7A for layer 0
+ break;
+ case 1:
+ rgb_matrix_sethsv(0, 255, 255); // Red for layer 1
+ break;
+ default:
+ rgb_matrix_sethsv(0, 255, 255); // Red for any other layer
+ break;
+ }
+ return state;
+}
diff --git a/keyboards/sdrakbs/sdrakb00/readme.md b/keyboards/sdrakbs/sdrakb00/readme.md
new file mode 100644
index 00000000000..21e56f9595a
--- /dev/null
+++ b/keyboards/sdrakbs/sdrakb00/readme.md
@@ -0,0 +1,52 @@
+# sdrakb00
+
+
+
+11 keys hot-swap macropad with rotary encoder.
+
+Macropad features:
+- 11 hot-swap keys
+- Rotary encoder with push button
+- AtMega32U4 MCU
+- Per-key RGB led for backlighting
+- USB-C connector
+- On PCB SPI header
+- MCU reset button
+- Switch mounting plate
+- Power LED indicator
+
+* Keyboard Maintainer: [Diego Andres Rabaioli](https://github.com/drabaioli)
+* Hardware Supported: Pro Micro Atmega32u4 based macropad with 11 keys, RGB LED chain and rotary encoder
+* Hardware Availability: [Get the gerbers and have fun building it your self ;)](https://github.com/drabaioli/SdraKb00)
+
+Build SdraKb00 firmware:
+
+ make sdrakbs/sdrakb00:default
+
+Flashing SdraKb00 firmware, execute:
+
+ make sdrakbs/sdrakb00:default:flash
+
+Then press the reset button on the back side of the PCB.
+
+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).
+
+## Bootloader
+
+Enter the bootloader in 3 ways:
+
+* **Physical reset button** (preferred): Briefly press the button on the back of the PCB
+* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (usually the top left key or Escape) and plug in the keyboard
+
+## Default Keymap
+
+### Base Layer (0)
+- NumPad layout (1-9, 0)
+- Encoder: Volume Up/Down
+- Encoder Push: Mute
+- Layer Switch: Hold (1,3) key for function layer
+
+### Function Layer (1)
+- NumPad operators (+, -, *, /)
+- Enter, "=" and backspace keys
+- Decimal point
diff --git a/keyboards/shorty/keyboard.json b/keyboards/shorty/keyboard.json
new file mode 100644
index 00000000000..158648badd4
--- /dev/null
+++ b/keyboards/shorty/keyboard.json
@@ -0,0 +1,48 @@
+{
+ "manufacturer": "Hawtkeys",
+ "keyboard_name": "shorty",
+ "maintainer": "hawtkeys",
+ "bootloader": "rp2040",
+ "diode_direction": "ROW2COL",
+ "encoder": {
+ "rotary": [
+ {"pin_a": "GP28", "pin_b": "GP27"},
+ {"pin_a": "GP3", "pin_b": "GP4"}
+ ]
+ },
+ "features": {
+ "bootmagic": true,
+ "encoder": true,
+ "extrakey": true,
+ "mousekey": true,
+ "nkro": true
+ },
+ "matrix_pins": {
+ "cols": ["GP14", "GP13", "GP12"],
+ "rows": ["GP11", "GP10", "GP9", "GP29", "GP2"]
+ },
+ "processor": "RP2040",
+ "url": "",
+ "usb": {
+ "device_version": "1.0.0",
+ "pid": "0x5400",
+ "vid": "0x5453"
+ },
+ "layouts": {
+ "LAYOUT": {
+ "layout": [
+ {"matrix": [3, 0], "x": 0, "y": 0},
+ {"matrix": [4, 0], "x": 2, "y": 0},
+ {"matrix": [0, 0], "x": 0, "y": 1},
+ {"matrix": [0, 1], "x": 1, "y": 1},
+ {"matrix": [0, 2], "x": 2, "y": 1},
+ {"matrix": [1, 0], "x": 0, "y": 2},
+ {"matrix": [1, 1], "x": 1, "y": 2},
+ {"matrix": [1, 2], "x": 2, "y": 2},
+ {"matrix": [2, 0], "x": 0, "y": 3},
+ {"matrix": [2, 1], "x": 1, "y": 3},
+ {"matrix": [2, 2], "x": 2, "y": 3}
+ ]
+ }
+ }
+}
diff --git a/keyboards/shorty/keymaps/default/keymap.c b/keyboards/shorty/keymaps/default/keymap.c
new file mode 100644
index 00000000000..ef4bbba7ef0
--- /dev/null
+++ b/keyboards/shorty/keymaps/default/keymap.c
@@ -0,0 +1,18 @@
+// Copyright 2023 QMK
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include QMK_KEYBOARD_H
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+ [0] = LAYOUT(
+ KC_A, KC_D,
+ KC_P7, KC_P8, KC_P9,
+ KC_P4, KC_P5, KC_P6,
+ KC_P1, KC_P2, KC_P3
+ )
+};
+
+#if defined(ENCODER_MAP_ENABLE)
+const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = {
+ [0] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU), ENCODER_CCW_CW(MS_WHLD, MS_WHLU) }
+};
+#endif
diff --git a/keyboards/shorty/readme.md b/keyboards/shorty/readme.md
new file mode 100644
index 00000000000..23f023b92ce
--- /dev/null
+++ b/keyboards/shorty/readme.md
@@ -0,0 +1,27 @@
+# Shorty Zero
+
+
+
+The Shorty Zero is a 3x3 customizable macropad designed for productivity, gaming, and creative workflows, featuring programmable keys and rotary knobs.
+
+* Keyboard Maintainer: [Hawtkeys](https://github.com/hawtkeys)
+* Hardware Supported: Raspberry Pi Pico, Hawtkeys Shorty Zero PCB
+* Hardware Availability: [Available @ hawtkeys.com](https://hawtkeys.com)
+
+Make example for this keyboard (after setting up your build environment):
+
+ make shorty:default
+
+Flashing example for this keyboard:
+
+ make shorty:default:flash
+
+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).
+
+## Bootloader
+
+Enter the bootloader in 3 ways:
+
+* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (usually the top left key or Escape) and plug in the keyboard
+* **Physical reset button**: Briefly press the button on the back of the PCB - some may have pads you must short instead
+* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available
\ No newline at end of file
diff --git a/keyboards/takashicompany/klec_01/keyboard.json b/keyboards/takashicompany/klec_01/keyboard.json
new file mode 100644
index 00000000000..36baa8bf60f
--- /dev/null
+++ b/keyboards/takashicompany/klec_01/keyboard.json
@@ -0,0 +1,77 @@
+{
+ "manufacturer": "takashicompany",
+ "keyboard_name": "KLEC-01",
+ "maintainer": "takashicompany",
+ "development_board": "promicro",
+ "diode_direction": "COL2ROW",
+ "features": {
+ "bootmagic": true,
+ "command": false,
+ "console": false,
+ "extrakey": true,
+ "mousekey": true,
+ "nkro": true
+ },
+ "matrix_pins": {
+ "cols": ["F4", "F5", "F6", "F7", "B1", "B3", "B2", "B6"],
+ "rows": ["D4", "C6", "D7", "E6", "B4", "B5"]
+ },
+ "url": "",
+ "usb": {
+ "device_version": "1.0.0",
+ "pid": "0x1001",
+ "vid": "0x7463"
+ },
+ "layouts": {
+ "LAYOUT": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [0, 1], "x": 1, "y": 0},
+ {"matrix": [0, 2], "x": 2, "y": 0},
+ {"matrix": [0, 3], "x": 3, "y": 0},
+ {"matrix": [1, 0], "x": 4, "y": 0},
+ {"matrix": [1, 1], "x": 5, "y": 0},
+ {"matrix": [1, 2], "x": 6, "y": 0},
+ {"matrix": [1, 3], "x": 7, "y": 0},
+ {"matrix": [2, 0], "x": 8, "y": 0},
+ {"matrix": [2, 1], "x": 9, "y": 0},
+ {"matrix": [2, 2], "x": 10, "y": 0},
+ {"matrix": [2, 3], "x": 11, "y": 0, "w": 1.75},
+ {"matrix": [0, 4], "x": 0, "y": 1, "w": 1.25},
+ {"matrix": [0, 5], "x": 1.25, "y": 1},
+ {"matrix": [0, 6], "x": 2.25, "y": 1},
+ {"matrix": [0, 7], "x": 3.25, "y": 1},
+ {"matrix": [1, 4], "x": 4.25, "y": 1},
+ {"matrix": [1, 5], "x": 5.25, "y": 1},
+ {"matrix": [1, 6], "x": 6.25, "y": 1},
+ {"matrix": [1, 7], "x": 7.25, "y": 1},
+ {"matrix": [2, 4], "x": 8.25, "y": 1},
+ {"matrix": [2, 5], "x": 9.25, "y": 1},
+ {"matrix": [2, 6], "x": 10.25, "y": 1},
+ {"matrix": [2, 7], "x": 11.25, "y": 1, "w": 1.5},
+ {"matrix": [3, 0], "x": 0, "y": 2, "w": 1.75},
+ {"matrix": [3, 1], "x": 1.75, "y": 2},
+ {"matrix": [3, 2], "x": 2.75, "y": 2},
+ {"matrix": [3, 3], "x": 3.75, "y": 2},
+ {"matrix": [4, 0], "x": 4.75, "y": 2},
+ {"matrix": [4, 1], "x": 5.75, "y": 2},
+ {"matrix": [4, 2], "x": 6.75, "y": 2},
+ {"matrix": [4, 3], "x": 7.75, "y": 2},
+ {"matrix": [5, 0], "x": 8.75, "y": 2},
+ {"matrix": [5, 1], "x": 9.75, "y": 2},
+ {"matrix": [5, 2], "x": 10.75, "y": 2},
+ {"matrix": [5, 3], "x": 11.75, "y": 2},
+ {"matrix": [3, 4], "x": 0, "y": 3},
+ {"matrix": [3, 5], "x": 1, "y": 3},
+ {"matrix": [3, 6], "x": 2, "y": 3},
+ {"matrix": [3, 7], "x": 3, "y": 3, "w": 1.25},
+ {"matrix": [4, 4], "x": 4.25, "y": 3, "w": 2},
+ {"matrix": [4, 5], "x": 6.25, "y": 3, "w": 2.25},
+ {"matrix": [5, 4], "x": 8.5, "y": 3, "w": 1.25},
+ {"matrix": [5, 5], "x": 9.75, "y": 3},
+ {"matrix": [5, 6], "x": 10.75, "y": 3},
+ {"matrix": [5, 7], "x": 11.75, "y": 3}
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/keyboards/takashicompany/klec_01/keymaps/default/keymap.c b/keyboards/takashicompany/klec_01/keymaps/default/keymap.c
new file mode 100644
index 00000000000..551c211b73a
--- /dev/null
+++ b/keyboards/takashicompany/klec_01/keymaps/default/keymap.c
@@ -0,0 +1,69 @@
+// Copyright 2023 QMK
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include QMK_KEYBOARD_H
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+ [0] = LAYOUT(
+ KC_ESC, LT(7, 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, LT(6, KC_D), KC_F, KC_G, KC_H, KC_J, LT(6, KC_K), KC_L, KC_ENT, KC_ENT,
+ KC_LSFT, LSFT_T(KC_Z), LGUI_T(KC_X), KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, LCTL_T(KC_DOT), KC_UP, KC_RSFT,
+ KC_LCTL, KC_LGUI, KC_LALT, LALT_T(KC_LNG2), LSFT_T(KC_TAB), LT(2, KC_SPC), LT(1, KC_LNG1), KC_LEFT, KC_DOWN, KC_RGHT
+ ),
+
+ [1] = LAYOUT(
+ KC_TRNS, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_TRNS,
+ KC_TRNS, LCTL_T(KC_EQL), KC_LBRC, KC_SLSH, KC_MINS, KC_INT1, KC_SCLN, KC_QUOT, KC_RBRC, KC_NUHS, KC_INT3, KC_TRNS,
+ KC_TRNS, LSFT_T(KC_PLUS), KC_LCBR, KC_QUES, KC_UNDS, LSFT(KC_INT1), KC_COLN, KC_DQUO, KC_RCBR, LSFT(KC_NUHS), KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
+ ),
+
+ [2] = LAYOUT(
+ KC_TRNS, KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, LGUI(KC_INT3), KC_TRNS,
+ KC_TRNS, KC_PLUS, KC_LCBR, KC_QUES, KC_UNDS, LSFT(KC_INT1), KC_COLN, KC_DQUO, KC_RCBR, LSFT(KC_NUHS), LSFT(KC_INT3), KC_TRNS,
+ KC_TRNS, KC_LSFT, KC_LGUI, KC_LALT, KC_LNG2, KC_LSFT, KC_SPC, KC_LNG1, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
+ ),
+
+ [3] = LAYOUT(
+ KC_TRNS, LT(7, KC_Q), KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_TRNS,
+ KC_TRNS, KC_A, KC_S, LT(6, KC_D), KC_F, KC_G, KC_H, KC_J, LT(6, KC_K), KC_L, KC_ENT, KC_TRNS,
+ KC_TRNS, LSFT_T(KC_Z), LGUI_T(KC_X), KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, LCTL_T(KC_DOT), KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
+ ),
+
+ [4] = LAYOUT(
+ KC_TRNS, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_CIRC, KC_AT, KC_SLSH, KC_MINS, KC_UNDS, KC_SCLN, KC_COLN, KC_LBRC, KC_RBRC, KC_INT3, KC_TRNS,
+ KC_TRNS, LT(5, KC_TILD), KC_GRV, KC_QUES, KC_EQL, KC_UNDS, KC_PLUS, KC_ASTR, KC_LCBR, KC_RCBR, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
+ ),
+
+ [5] = LAYOUT(
+ KC_TRNS, KC_EXLM, KC_DQUO, KC_HASH, KC_DLR, KC_PERC, KC_AMPR, KC_QUOT, KC_LPRN, KC_RPRN, KC_BSLS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TILD, KC_GRV, KC_QUES, KC_EQL, KC_UNDS, KC_PLUS, KC_ASTR, KC_LCBR, KC_RCBR, KC_PIPE, KC_TRNS,
+ KC_TRNS, KC_LSFT, KC_LGUI, KC_LALT, KC_LNG2, KC_LSFT, KC_SPC, KC_LNG1, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
+ ),
+
+ [6] = LAYOUT(
+ KC_TRNS, KC_ESC, KC_TAB, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_UP, KC_NO, KC_NO, KC_TRNS,
+ KC_TRNS, KC_LCTL, KC_TRNS, KC_QUES, KC_EXLM, KC_NO, KC_NO, KC_LEFT, KC_DOWN, KC_RGHT, KC_NO, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_LSFT, KC_LGUI, KC_LALT, KC_LNG2, KC_TRNS, KC_NO, KC_LNG1, KC_NO, KC_NO, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
+ ),
+
+ [7] = LAYOUT(
+ KC_TRNS, KC_NO, KC_TAB, KC_NO, KC_NO, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_NO, KC_NO, KC_NO, KC_NO, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_TRNS,
+ KC_TRNS, KC_LSFT, KC_NO, KC_NO, KC_NO, KC_TRNS, KC_TRNS, KC_TRNS, KC_NO, MO(8), KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
+ ),
+
+ [8] = LAYOUT(
+ KC_TRNS, UG_TOGG, UG_NEXT, UG_HUEU, UG_SATU, UG_VALU, KC_NO, KC_NO, KC_NO, DF(0), DF(3), KC_TRNS, KC_TRNS,
+ KC_TRNS, RGB_M_P, RGB_M_B, RGB_M_R, RGB_M_SW, RGB_M_SN, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_TRNS,
+ KC_TRNS, RGB_M_K, RGB_M_X, RGB_M_G, KC_NO, KC_NO, QK_BOOT, KC_NO, KC_NO, KC_NO, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
+ )
+};
\ No newline at end of file
diff --git a/keyboards/takashicompany/klec_01/readme.md b/keyboards/takashicompany/klec_01/readme.md
new file mode 100644
index 00000000000..e907c7b68a3
--- /dev/null
+++ b/keyboards/takashicompany/klec_01/readme.md
@@ -0,0 +1,29 @@
+# takashicompany/klec_01
+
+
+
+46-key integrated keyboard.
+
+The layout is similar to a conventional keyboard, making it a good introduction to 40% keyboards.
+
+* Keyboard Maintainer: [takashicompany](https://github.com/takashicompany)
+* Hardware Supported: PCB, Pro Micro
+* Hardware Availability: https://github.com/takashicompany/klec_01
+
+Make example for this keyboard (after setting up your build environment):
+
+ make takashicompany/klec_01:default
+
+Flashing example for this keyboard:
+
+ make takashicompany/klec_01:default:flash
+
+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).
+
+## Bootloader
+
+Enter the bootloader in 3 ways:
+
+* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (usually the top left key or Escape) and plug in the keyboard
+* **Physical reset button**: Briefly press the button on the back of the PCB - some may have pads you must short instead
+* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available
diff --git a/keyboards/takashicompany/klec_02/keyboard.json b/keyboards/takashicompany/klec_02/keyboard.json
new file mode 100644
index 00000000000..045c4ef315c
--- /dev/null
+++ b/keyboards/takashicompany/klec_02/keyboard.json
@@ -0,0 +1,73 @@
+{
+ "manufacturer": "takashicompany",
+ "keyboard_name": "KLEC-02",
+ "maintainer": "takashicompany",
+ "development_board": "promicro",
+ "diode_direction": "COL2ROW",
+ "features": {
+ "bootmagic": true,
+ "command": false,
+ "console": false,
+ "extrakey": true,
+ "mousekey": true,
+ "nkro": true
+ },
+ "matrix_pins": {
+ "cols": ["D4", "C6", "D7", "E6", "B4"],
+ "rows": ["F4", "F5", "F6", "F7"]
+ },
+ "split": {
+ "enabled": true,
+ "serial": {
+ "pin": "D2"
+ }
+ },
+ "url": "",
+ "usb": {
+ "device_version": "1.0.0",
+ "pid": "0x1002",
+ "vid": "0x7463"
+ },
+ "layouts": {
+ "LAYOUT": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [0, 1], "x": 1, "y": 0},
+ {"matrix": [0, 2], "x": 2, "y": 0},
+ {"matrix": [0, 3], "x": 3, "y": 0},
+ {"matrix": [0, 4], "x": 4, "y": 0},
+ {"matrix": [4, 0], "x": 6.25, "y": 0},
+ {"matrix": [4, 1], "x": 7.25, "y": 0},
+ {"matrix": [4, 2], "x": 8.25, "y": 0},
+ {"matrix": [4, 3], "x": 9.25, "y": 0},
+ {"matrix": [4, 4], "x": 10.25, "y": 0},
+ {"matrix": [1, 0], "x": 0.25, "y": 1},
+ {"matrix": [1, 1], "x": 1.25, "y": 1},
+ {"matrix": [1, 2], "x": 2.25, "y": 1},
+ {"matrix": [1, 3], "x": 3.25, "y": 1},
+ {"matrix": [1, 4], "x": 4.25, "y": 1},
+ {"matrix": [5, 0], "x": 6.5, "y": 1},
+ {"matrix": [5, 1], "x": 7.5, "y": 1},
+ {"matrix": [5, 2], "x": 8.5, "y": 1},
+ {"matrix": [5, 3], "x": 9.5, "y": 1},
+ {"matrix": [5, 4], "x": 10.5, "y": 1},
+ {"matrix": [2, 0], "x": 0.5, "y": 2},
+ {"matrix": [2, 1], "x": 1.5, "y": 2},
+ {"matrix": [2, 2], "x": 2.5, "y": 2},
+ {"matrix": [2, 3], "x": 3.5, "y": 2},
+ {"matrix": [2, 4], "x": 4.5, "y": 2},
+ {"matrix": [6, 0], "x": 6.75, "y": 2},
+ {"matrix": [6, 1], "x": 7.75, "y": 2},
+ {"matrix": [6, 2], "x": 8.75, "y": 2},
+ {"matrix": [6, 3], "x": 9.75, "y": 2},
+ {"matrix": [6, 4], "x": 10.75, "y": 2},
+ {"matrix": [3, 2], "x": 2.75, "y": 3},
+ {"matrix": [3, 3], "x": 3.75, "y": 3, "w": 1.25},
+ {"matrix": [3, 4], "x": 5, "y": 3},
+ {"matrix": [7, 0], "x": 6.25, "y": 3},
+ {"matrix": [7, 1], "x": 7.25, "y": 3, "w": 1.25},
+ {"matrix": [7, 2], "x": 8.5, "y": 3}
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/keyboards/takashicompany/klec_02/keymaps/default/keymap.c b/keyboards/takashicompany/klec_02/keymaps/default/keymap.c
new file mode 100644
index 00000000000..0431b8e6b7e
--- /dev/null
+++ b/keyboards/takashicompany/klec_02/keymaps/default/keymap.c
@@ -0,0 +1,70 @@
+// Copyright 2023 QMK
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include QMK_KEYBOARD_H
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+
+ [0] = LAYOUT(
+ LT(7, KC_Q), KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P,
+ KC_A, KC_S, LT(6, KC_D), KC_F, KC_G, KC_H, KC_J, LT(6, KC_K), KC_L, KC_ENT,
+ LSFT_T(KC_Z), LGUI_T(KC_X), KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, LCTL_T(KC_DOT), KC_BSPC,
+ KC_LGUI, LALT_T(KC_LNG2), LSFT_T(KC_TAB), LT(2, KC_SPC), LT(1, KC_LNG1), KC_RGUI
+ ),
+
+ [1] = LAYOUT(
+ KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0,
+ LCTL_T(KC_EQL), KC_LBRC, KC_SLSH, KC_MINS, KC_INT1, KC_SCLN, KC_QUOT, KC_RBRC, KC_NUHS, KC_INT3,
+ LSFT_T(KC_PLUS), KC_LCBR, KC_QUES, KC_UNDS, LSFT(KC_INT1), KC_COLN, KC_DQUO, KC_RCBR, LSFT(KC_NUHS), LSFT(KC_INT3),
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
+ ),
+
+ [2] = LAYOUT(
+ KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, LGUI(KC_INT3),
+ KC_PLUS, KC_LCBR, KC_QUES, KC_UNDS, LSFT(KC_INT1), KC_COLN, KC_DQUO, KC_RCBR, LSFT(KC_NUHS), LSFT(KC_INT3),
+ KC_LSFT, KC_LGUI, KC_LALT, KC_LNG2, KC_LSFT, KC_SPC, KC_LNG1, KC_TRNS, KC_TRNS, KC_DEL,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
+ ),
+
+ [3] = LAYOUT(
+ LT(7, KC_Q), KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P,
+ KC_A, KC_S, LT(6, KC_D), KC_F, KC_G, KC_H, KC_J, LT(6, KC_K), KC_L, KC_ENT,
+ LSFT_T(KC_Z), LGUI_T(KC_X), KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, LCTL_T(KC_DOT), KC_BSPC,
+ KC_LGUI, LALT_T(KC_LNG2), LSFT_T(KC_TAB), LT(5, KC_SPC), LT(4, KC_LNG1), KC_RGUI
+ ),
+
+ [4] = LAYOUT(
+ KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0,
+ KC_CIRC, KC_AT, KC_SLSH, KC_MINS, KC_UNDS, KC_SCLN, KC_COLN, KC_LBRC, KC_RBRC, KC_INT3,
+ LT(5, KC_TILD), KC_GRV, KC_QUES, KC_EQL, KC_UNDS, KC_PLUS, KC_ASTR, KC_LCBR, KC_RCBR, KC_PIPE,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
+ ),
+
+ [5] = LAYOUT(
+ KC_EXLM, KC_DQUO, KC_HASH, KC_DLR, KC_PERC, KC_AMPR, KC_QUOT, KC_LPRN, KC_RPRN, KC_BSLS,
+ KC_TILD, KC_GRV, KC_QUES, KC_EQL, KC_UNDS, KC_PLUS, KC_ASTR, KC_LCBR, KC_RCBR, KC_PIPE,
+ KC_LSFT, KC_LGUI, KC_LALT, KC_LNG2, KC_LSFT, KC_SPC, KC_LNG1, KC_TRNS, KC_TRNS, KC_DEL,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
+ ),
+
+ [6] = LAYOUT(
+ KC_ESC, KC_TAB, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_UP, KC_NO, KC_NO,
+ KC_LCTL, KC_TRNS, KC_QUES, KC_EXLM, KC_NO, KC_NO, KC_LEFT, KC_DOWN, KC_RGHT, KC_NO,
+ KC_LSFT, KC_LGUI, KC_LALT, KC_LNG2, KC_TRNS, KC_NO, KC_LNG1, KC_NO, KC_NO, KC_DEL,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
+ ),
+
+ [7] = LAYOUT(
+ KC_NO, KC_TAB, KC_NO, KC_NO, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6,
+ KC_NO, KC_NO, KC_NO, KC_NO, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12,
+ KC_LSFT, KC_NO, KC_NO, KC_NO, KC_TRNS, KC_TRNS, KC_TRNS, KC_NO, MO(8), MO(9),
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
+ ),
+
+ [8] = LAYOUT(
+ UG_TOGG, UG_NEXT, UG_HUEU, UG_SATU, UG_VALU, KC_NO, KC_NO, KC_NO, DF(0), DF(3),
+ RGB_M_P, RGB_M_B, RGB_M_R, RGB_M_SW, RGB_M_SN, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
+ RGB_M_K, RGB_M_X, RGB_M_G, KC_NO, KC_NO, QK_BOOT, KC_NO, KC_NO, KC_NO, KC_NO,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
+ )
+};
\ No newline at end of file
diff --git a/keyboards/takashicompany/klec_02/readme.md b/keyboards/takashicompany/klec_02/readme.md
new file mode 100644
index 00000000000..0b492a5e18a
--- /dev/null
+++ b/keyboards/takashicompany/klec_02/readme.md
@@ -0,0 +1,28 @@
+# KLEC-02
+
+
+
+The KLEC-02 is a 36-key segmented keyboard.
+The PCB can be fitted with key switch sockets, allowing easy replacement of key switches.
+
+* Keyboard Maintainer: [takashicompany](https://github.com/takashicompany)
+* Hardware Supported: PCB, Pro Micro
+* Hardware Availability: https://github.com/takashicompany/klec_02
+
+Make example for this keyboard (after setting up your build environment):
+
+ make takashicompany/klec_02:default
+
+Flashing example for this keyboard:
+
+ make takashicompany/klec_02:default:flash
+
+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).
+
+## Bootloader
+
+Enter the bootloader in 3 ways:
+
+* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (usually the top left key or Escape) and plug in the keyboard
+* **Physical reset button**: Briefly press the button on the back of the PCB - some may have pads you must short instead
+* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available
diff --git a/keyboards/trnthsn/s6xty/config.h b/keyboards/trnthsn/s6xty/config.h
new file mode 100644
index 00000000000..cb72d64967e
--- /dev/null
+++ b/keyboards/trnthsn/s6xty/config.h
@@ -0,0 +1,21 @@
+/*
+Copyright 2024 ThanhSon.Mech
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+#pragma once
+
+#define WS2812_SPI_DRIVER SPID2
+#define WS2812_SPI_SCK_PIN B13
diff --git a/keyboards/trnthsn/s6xty/halconf.h b/keyboards/trnthsn/s6xty/halconf.h
new file mode 100644
index 00000000000..b8f0a217c4b
--- /dev/null
+++ b/keyboards/trnthsn/s6xty/halconf.h
@@ -0,0 +1,21 @@
+/* Copyright 2024 ThanhSon.Mech
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+#define HAL_USE_SPI TRUE
+
+#include_next
diff --git a/keyboards/trnthsn/s6xty/keyboard.json b/keyboards/trnthsn/s6xty/keyboard.json
new file mode 100644
index 00000000000..3ec2f87f3df
--- /dev/null
+++ b/keyboards/trnthsn/s6xty/keyboard.json
@@ -0,0 +1,504 @@
+{
+ "manufacturer": "ThanhSon.Mech",
+ "keyboard_name": "S6xty",
+ "maintainer": "trnthsn",
+ "bootloader": "stm32-dfu",
+ "diode_direction": "COL2ROW",
+ "features": {
+ "bootmagic": true,
+ "command": false,
+ "console": false,
+ "extrakey": true,
+ "mousekey": true,
+ "nkro": true
+ },
+ "indicators": {
+ "caps_lock": "B12"
+ },
+ "matrix_pins": {
+ "cols": ["B14", "A0", "A10", "C15", "A2", "A1", "B11", "B10", "B1", "B0", "A7", "A6", "A5", "A4"],
+ "rows": ["B3", "B7", "A3", "A9", "A8"]
+ },
+ "processor": "STM32F072",
+ "rgblight": {
+ "animations": {
+ "alternating": true,
+ "breathing": true,
+ "christmas": true,
+ "knight": true,
+ "rainbow_mood": true,
+ "rainbow_swirl": true,
+ "snake": true,
+ "static_gradient": true,
+ "twinkle": true
+ },
+ "led_count": 22,
+ "sleep": true
+ },
+ "url": "",
+ "usb": {
+ "device_version": "0.0.1",
+ "pid": "0x5336",
+ "vid": "0x5453"
+ },
+ "ws2812": {
+ "driver": "spi",
+ "pin": "B15"
+ },
+ "community_layouts": ["60_ansi_tsangan", "60_ansi_tsangan_split_bs_rshift", "60_ansi_wkl", "60_ansi_wkl_split_bs_rshift", "60_hhkb"],
+ "layouts": {
+ "LAYOUT_60_ansi_tsangan": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [0, 1], "x": 1, "y": 0},
+ {"matrix": [0, 2], "x": 2, "y": 0},
+ {"matrix": [0, 3], "x": 3, "y": 0},
+ {"matrix": [0, 4], "x": 4, "y": 0},
+ {"matrix": [0, 5], "x": 5, "y": 0},
+ {"matrix": [0, 6], "x": 6, "y": 0},
+ {"matrix": [0, 7], "x": 7, "y": 0},
+ {"matrix": [0, 8], "x": 8, "y": 0},
+ {"matrix": [0, 9], "x": 9, "y": 0},
+ {"matrix": [0, 10], "x": 10, "y": 0},
+ {"matrix": [0, 11], "x": 11, "y": 0},
+ {"matrix": [0, 12], "x": 12, "y": 0},
+ {"matrix": [0, 13], "x": 13, "y": 0, "w": 2},
+ {"matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
+ {"matrix": [1, 1], "x": 1.5, "y": 1},
+ {"matrix": [1, 2], "x": 2.5, "y": 1},
+ {"matrix": [1, 3], "x": 3.5, "y": 1},
+ {"matrix": [1, 4], "x": 4.5, "y": 1},
+ {"matrix": [1, 5], "x": 5.5, "y": 1},
+ {"matrix": [1, 6], "x": 6.5, "y": 1},
+ {"matrix": [1, 7], "x": 7.5, "y": 1},
+ {"matrix": [1, 8], "x": 8.5, "y": 1},
+ {"matrix": [1, 9], "x": 9.5, "y": 1},
+ {"matrix": [1, 10], "x": 10.5, "y": 1},
+ {"matrix": [1, 11], "x": 11.5, "y": 1},
+ {"matrix": [1, 12], "x": 12.5, "y": 1},
+ {"matrix": [1, 13], "x": 13.5, "y": 1, "w": 1.5},
+ {"matrix": [2, 0], "x": 0, "y": 2, "w": 1.75},
+ {"matrix": [2, 1], "x": 1.75, "y": 2},
+ {"matrix": [2, 2], "x": 2.75, "y": 2},
+ {"matrix": [2, 3], "x": 3.75, "y": 2},
+ {"matrix": [2, 4], "x": 4.75, "y": 2},
+ {"matrix": [2, 5], "x": 5.75, "y": 2},
+ {"matrix": [2, 6], "x": 6.75, "y": 2},
+ {"matrix": [2, 7], "x": 7.75, "y": 2},
+ {"matrix": [2, 8], "x": 8.75, "y": 2},
+ {"matrix": [2, 9], "x": 9.75, "y": 2},
+ {"matrix": [2, 10], "x": 10.75, "y": 2},
+ {"matrix": [2, 11], "x": 11.75, "y": 2},
+ {"matrix": [2, 13], "x": 12.75, "y": 2, "w": 2.25},
+ {"matrix": [3, 0], "x": 0, "y": 3, "w": 2.25},
+ {"matrix": [3, 2], "x": 2.25, "y": 3},
+ {"matrix": [3, 3], "x": 3.25, "y": 3},
+ {"matrix": [3, 4], "x": 4.25, "y": 3},
+ {"matrix": [3, 5], "x": 5.25, "y": 3},
+ {"matrix": [3, 6], "x": 6.25, "y": 3},
+ {"matrix": [3, 7], "x": 7.25, "y": 3},
+ {"matrix": [3, 8], "x": 8.25, "y": 3},
+ {"matrix": [3, 9], "x": 9.25, "y": 3},
+ {"matrix": [3, 10], "x": 10.25, "y": 3},
+ {"matrix": [3, 11], "x": 11.25, "y": 3},
+ {"matrix": [3, 12], "x": 12.25, "y": 3, "w": 2.75},
+ {"matrix": [4, 0], "x": 0, "y": 4, "w": 1.5},
+ {"matrix": [4, 1], "x": 1.5, "y": 4},
+ {"matrix": [4, 2], "x": 2.5, "y": 4, "w": 1.5},
+ {"matrix": [4, 7], "x": 4, "y": 4, "w": 7},
+ {"matrix": [4, 10], "x": 11, "y": 4, "w": 1.5},
+ {"matrix": [4, 12], "x": 12.5, "y": 4},
+ {"matrix": [4, 13], "x": 13.5, "y": 4, "w": 1.5}
+ ]
+ },
+ "LAYOUT_60_ansi_tsangan_arrow": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [0, 1], "x": 1, "y": 0},
+ {"matrix": [0, 2], "x": 2, "y": 0},
+ {"matrix": [0, 3], "x": 3, "y": 0},
+ {"matrix": [0, 4], "x": 4, "y": 0},
+ {"matrix": [0, 5], "x": 5, "y": 0},
+ {"matrix": [0, 6], "x": 6, "y": 0},
+ {"matrix": [0, 7], "x": 7, "y": 0},
+ {"matrix": [0, 8], "x": 8, "y": 0},
+ {"matrix": [0, 9], "x": 9, "y": 0},
+ {"matrix": [0, 10], "x": 10, "y": 0},
+ {"matrix": [0, 11], "x": 11, "y": 0},
+ {"matrix": [0, 12], "x": 12, "y": 0},
+ {"matrix": [0, 13], "x": 13, "y": 0, "w": 2},
+ {"matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
+ {"matrix": [1, 1], "x": 1.5, "y": 1},
+ {"matrix": [1, 2], "x": 2.5, "y": 1},
+ {"matrix": [1, 3], "x": 3.5, "y": 1},
+ {"matrix": [1, 4], "x": 4.5, "y": 1},
+ {"matrix": [1, 5], "x": 5.5, "y": 1},
+ {"matrix": [1, 6], "x": 6.5, "y": 1},
+ {"matrix": [1, 7], "x": 7.5, "y": 1},
+ {"matrix": [1, 8], "x": 8.5, "y": 1},
+ {"matrix": [1, 9], "x": 9.5, "y": 1},
+ {"matrix": [1, 10], "x": 10.5, "y": 1},
+ {"matrix": [1, 11], "x": 11.5, "y": 1},
+ {"matrix": [1, 12], "x": 12.5, "y": 1},
+ {"matrix": [1, 13], "x": 13.5, "y": 1, "w": 1.5},
+ {"matrix": [2, 0], "x": 0, "y": 2, "w": 1.75},
+ {"matrix": [2, 1], "x": 1.75, "y": 2},
+ {"matrix": [2, 2], "x": 2.75, "y": 2},
+ {"matrix": [2, 3], "x": 3.75, "y": 2},
+ {"matrix": [2, 4], "x": 4.75, "y": 2},
+ {"matrix": [2, 5], "x": 5.75, "y": 2},
+ {"matrix": [2, 6], "x": 6.75, "y": 2},
+ {"matrix": [2, 7], "x": 7.75, "y": 2},
+ {"matrix": [2, 8], "x": 8.75, "y": 2},
+ {"matrix": [2, 9], "x": 9.75, "y": 2},
+ {"matrix": [2, 10], "x": 10.75, "y": 2},
+ {"matrix": [2, 11], "x": 11.75, "y": 2},
+ {"matrix": [2, 13], "x": 12.75, "y": 2, "w": 2.25},
+ {"matrix": [3, 0], "x": 0, "y": 3, "w": 2.25},
+ {"matrix": [3, 2], "x": 2.25, "y": 3},
+ {"matrix": [3, 3], "x": 3.25, "y": 3},
+ {"matrix": [3, 4], "x": 4.25, "y": 3},
+ {"matrix": [3, 5], "x": 5.25, "y": 3},
+ {"matrix": [3, 6], "x": 6.25, "y": 3},
+ {"matrix": [3, 7], "x": 7.25, "y": 3},
+ {"matrix": [3, 8], "x": 8.25, "y": 3},
+ {"matrix": [3, 9], "x": 9.25, "y": 3},
+ {"matrix": [3, 10], "x": 10.25, "y": 3},
+ {"matrix": [3, 11], "x": 11.25, "y": 3, "w": 1.75},
+ {"matrix": [3, 12], "x": 13, "y": 3},
+ {"matrix": [3, 13], "x": 14, "y": 3},
+ {"matrix": [4, 0], "x": 0, "y": 4, "w": 1.5},
+ {"matrix": [4, 1], "x": 1.5, "y": 4},
+ {"matrix": [4, 2], "x": 2.5, "y": 4, "w": 1.5},
+ {"matrix": [4, 7], "x": 4, "y": 4, "w": 7},
+ {"matrix": [4, 10], "x": 11, "y": 4},
+ {"matrix": [4, 11], "x": 12, "y": 4},
+ {"matrix": [4, 12], "x": 13, "y": 4},
+ {"matrix": [4, 13], "x": 14, "y": 4}
+ ]
+ },
+ "LAYOUT_60_ansi_tsangan_split_bs_rshift": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [0, 1], "x": 1, "y": 0},
+ {"matrix": [0, 2], "x": 2, "y": 0},
+ {"matrix": [0, 3], "x": 3, "y": 0},
+ {"matrix": [0, 4], "x": 4, "y": 0},
+ {"matrix": [0, 5], "x": 5, "y": 0},
+ {"matrix": [0, 6], "x": 6, "y": 0},
+ {"matrix": [0, 7], "x": 7, "y": 0},
+ {"matrix": [0, 8], "x": 8, "y": 0},
+ {"matrix": [0, 9], "x": 9, "y": 0},
+ {"matrix": [0, 10], "x": 10, "y": 0},
+ {"matrix": [0, 11], "x": 11, "y": 0},
+ {"matrix": [0, 12], "x": 12, "y": 0},
+ {"matrix": [2, 12], "x": 13, "y": 0},
+ {"matrix": [0, 13], "x": 14, "y": 0},
+ {"matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
+ {"matrix": [1, 1], "x": 1.5, "y": 1},
+ {"matrix": [1, 2], "x": 2.5, "y": 1},
+ {"matrix": [1, 3], "x": 3.5, "y": 1},
+ {"matrix": [1, 4], "x": 4.5, "y": 1},
+ {"matrix": [1, 5], "x": 5.5, "y": 1},
+ {"matrix": [1, 6], "x": 6.5, "y": 1},
+ {"matrix": [1, 7], "x": 7.5, "y": 1},
+ {"matrix": [1, 8], "x": 8.5, "y": 1},
+ {"matrix": [1, 9], "x": 9.5, "y": 1},
+ {"matrix": [1, 10], "x": 10.5, "y": 1},
+ {"matrix": [1, 11], "x": 11.5, "y": 1},
+ {"matrix": [1, 12], "x": 12.5, "y": 1},
+ {"matrix": [1, 13], "x": 13.5, "y": 1, "w": 1.5},
+ {"matrix": [2, 0], "x": 0, "y": 2, "w": 1.75},
+ {"matrix": [2, 1], "x": 1.75, "y": 2},
+ {"matrix": [2, 2], "x": 2.75, "y": 2},
+ {"matrix": [2, 3], "x": 3.75, "y": 2},
+ {"matrix": [2, 4], "x": 4.75, "y": 2},
+ {"matrix": [2, 5], "x": 5.75, "y": 2},
+ {"matrix": [2, 6], "x": 6.75, "y": 2},
+ {"matrix": [2, 7], "x": 7.75, "y": 2},
+ {"matrix": [2, 8], "x": 8.75, "y": 2},
+ {"matrix": [2, 9], "x": 9.75, "y": 2},
+ {"matrix": [2, 10], "x": 10.75, "y": 2},
+ {"matrix": [2, 11], "x": 11.75, "y": 2},
+ {"matrix": [2, 13], "x": 12.75, "y": 2, "w": 2.25},
+ {"matrix": [3, 0], "x": 0, "y": 3, "w": 2.25},
+ {"matrix": [3, 2], "x": 2.25, "y": 3},
+ {"matrix": [3, 3], "x": 3.25, "y": 3},
+ {"matrix": [3, 4], "x": 4.25, "y": 3},
+ {"matrix": [3, 5], "x": 5.25, "y": 3},
+ {"matrix": [3, 6], "x": 6.25, "y": 3},
+ {"matrix": [3, 7], "x": 7.25, "y": 3},
+ {"matrix": [3, 8], "x": 8.25, "y": 3},
+ {"matrix": [3, 9], "x": 9.25, "y": 3},
+ {"matrix": [3, 10], "x": 10.25, "y": 3},
+ {"matrix": [3, 11], "x": 11.25, "y": 3},
+ {"matrix": [3, 12], "x": 12.25, "y": 3, "w": 1.75},
+ {"matrix": [3, 13], "x": 14, "y": 3},
+ {"matrix": [4, 0], "x": 0, "y": 4, "w": 1.5},
+ {"matrix": [4, 1], "x": 1.5, "y": 4},
+ {"matrix": [4, 2], "x": 2.5, "y": 4, "w": 1.5},
+ {"matrix": [4, 7], "x": 4, "y": 4, "w": 7},
+ {"matrix": [4, 10], "x": 11, "y": 4, "w": 1.5},
+ {"matrix": [4, 12], "x": 12.5, "y": 4},
+ {"matrix": [4, 13], "x": 13.5, "y": 4, "w": 1.5}
+ ]
+ },
+ "LAYOUT_60_ansi_wkl": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [0, 1], "x": 1, "y": 0},
+ {"matrix": [0, 2], "x": 2, "y": 0},
+ {"matrix": [0, 3], "x": 3, "y": 0},
+ {"matrix": [0, 4], "x": 4, "y": 0},
+ {"matrix": [0, 5], "x": 5, "y": 0},
+ {"matrix": [0, 6], "x": 6, "y": 0},
+ {"matrix": [0, 7], "x": 7, "y": 0},
+ {"matrix": [0, 8], "x": 8, "y": 0},
+ {"matrix": [0, 9], "x": 9, "y": 0},
+ {"matrix": [0, 10], "x": 10, "y": 0},
+ {"matrix": [0, 11], "x": 11, "y": 0},
+ {"matrix": [0, 12], "x": 12, "y": 0},
+ {"matrix": [0, 13], "x": 13, "y": 0, "w": 2},
+ {"matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
+ {"matrix": [1, 1], "x": 1.5, "y": 1},
+ {"matrix": [1, 2], "x": 2.5, "y": 1},
+ {"matrix": [1, 3], "x": 3.5, "y": 1},
+ {"matrix": [1, 4], "x": 4.5, "y": 1},
+ {"matrix": [1, 5], "x": 5.5, "y": 1},
+ {"matrix": [1, 6], "x": 6.5, "y": 1},
+ {"matrix": [1, 7], "x": 7.5, "y": 1},
+ {"matrix": [1, 8], "x": 8.5, "y": 1},
+ {"matrix": [1, 9], "x": 9.5, "y": 1},
+ {"matrix": [1, 10], "x": 10.5, "y": 1},
+ {"matrix": [1, 11], "x": 11.5, "y": 1},
+ {"matrix": [1, 12], "x": 12.5, "y": 1},
+ {"matrix": [1, 13], "x": 13.5, "y": 1, "w": 1.5},
+ {"matrix": [2, 0], "x": 0, "y": 2, "w": 1.75},
+ {"matrix": [2, 1], "x": 1.75, "y": 2},
+ {"matrix": [2, 2], "x": 2.75, "y": 2},
+ {"matrix": [2, 3], "x": 3.75, "y": 2},
+ {"matrix": [2, 4], "x": 4.75, "y": 2},
+ {"matrix": [2, 5], "x": 5.75, "y": 2},
+ {"matrix": [2, 6], "x": 6.75, "y": 2},
+ {"matrix": [2, 7], "x": 7.75, "y": 2},
+ {"matrix": [2, 8], "x": 8.75, "y": 2},
+ {"matrix": [2, 9], "x": 9.75, "y": 2},
+ {"matrix": [2, 10], "x": 10.75, "y": 2},
+ {"matrix": [2, 11], "x": 11.75, "y": 2},
+ {"matrix": [2, 13], "x": 12.75, "y": 2, "w": 2.25},
+ {"matrix": [3, 0], "x": 0, "y": 3, "w": 2.25},
+ {"matrix": [3, 2], "x": 2.25, "y": 3},
+ {"matrix": [3, 3], "x": 3.25, "y": 3},
+ {"matrix": [3, 4], "x": 4.25, "y": 3},
+ {"matrix": [3, 5], "x": 5.25, "y": 3},
+ {"matrix": [3, 6], "x": 6.25, "y": 3},
+ {"matrix": [3, 7], "x": 7.25, "y": 3},
+ {"matrix": [3, 8], "x": 8.25, "y": 3},
+ {"matrix": [3, 9], "x": 9.25, "y": 3},
+ {"matrix": [3, 10], "x": 10.25, "y": 3},
+ {"matrix": [3, 11], "x": 11.25, "y": 3},
+ {"matrix": [3, 12], "x": 12.25, "y": 3, "w": 2.75},
+ {"matrix": [4, 0], "x": 0, "y": 4, "w": 1.5},
+ {"matrix": [4, 2], "x": 2.5, "y": 4, "w": 1.5},
+ {"matrix": [4, 7], "x": 4, "y": 4, "w": 7},
+ {"matrix": [4, 10], "x": 11, "y": 4, "w": 1.5},
+ {"matrix": [4, 13], "x": 13.5, "y": 4, "w": 1.5}
+ ]
+ },
+ "LAYOUT_60_ansi_wkl_split_bs_rshift": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [0, 1], "x": 1, "y": 0},
+ {"matrix": [0, 2], "x": 2, "y": 0},
+ {"matrix": [0, 3], "x": 3, "y": 0},
+ {"matrix": [0, 4], "x": 4, "y": 0},
+ {"matrix": [0, 5], "x": 5, "y": 0},
+ {"matrix": [0, 6], "x": 6, "y": 0},
+ {"matrix": [0, 7], "x": 7, "y": 0},
+ {"matrix": [0, 8], "x": 8, "y": 0},
+ {"matrix": [0, 9], "x": 9, "y": 0},
+ {"matrix": [0, 10], "x": 10, "y": 0},
+ {"matrix": [0, 11], "x": 11, "y": 0},
+ {"matrix": [0, 12], "x": 12, "y": 0},
+ {"matrix": [2, 12], "x": 13, "y": 0},
+ {"matrix": [0, 13], "x": 14, "y": 0},
+ {"matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
+ {"matrix": [1, 1], "x": 1.5, "y": 1},
+ {"matrix": [1, 2], "x": 2.5, "y": 1},
+ {"matrix": [1, 3], "x": 3.5, "y": 1},
+ {"matrix": [1, 4], "x": 4.5, "y": 1},
+ {"matrix": [1, 5], "x": 5.5, "y": 1},
+ {"matrix": [1, 6], "x": 6.5, "y": 1},
+ {"matrix": [1, 7], "x": 7.5, "y": 1},
+ {"matrix": [1, 8], "x": 8.5, "y": 1},
+ {"matrix": [1, 9], "x": 9.5, "y": 1},
+ {"matrix": [1, 10], "x": 10.5, "y": 1},
+ {"matrix": [1, 11], "x": 11.5, "y": 1},
+ {"matrix": [1, 12], "x": 12.5, "y": 1},
+ {"matrix": [1, 13], "x": 13.5, "y": 1, "w": 1.5},
+ {"matrix": [2, 0], "x": 0, "y": 2, "w": 1.75},
+ {"matrix": [2, 1], "x": 1.75, "y": 2},
+ {"matrix": [2, 2], "x": 2.75, "y": 2},
+ {"matrix": [2, 3], "x": 3.75, "y": 2},
+ {"matrix": [2, 4], "x": 4.75, "y": 2},
+ {"matrix": [2, 5], "x": 5.75, "y": 2},
+ {"matrix": [2, 6], "x": 6.75, "y": 2},
+ {"matrix": [2, 7], "x": 7.75, "y": 2},
+ {"matrix": [2, 8], "x": 8.75, "y": 2},
+ {"matrix": [2, 9], "x": 9.75, "y": 2},
+ {"matrix": [2, 10], "x": 10.75, "y": 2},
+ {"matrix": [2, 11], "x": 11.75, "y": 2},
+ {"matrix": [2, 13], "x": 12.75, "y": 2, "w": 2.25},
+ {"matrix": [3, 0], "x": 0, "y": 3, "w": 2.25},
+ {"matrix": [3, 2], "x": 2.25, "y": 3},
+ {"matrix": [3, 3], "x": 3.25, "y": 3},
+ {"matrix": [3, 4], "x": 4.25, "y": 3},
+ {"matrix": [3, 5], "x": 5.25, "y": 3},
+ {"matrix": [3, 6], "x": 6.25, "y": 3},
+ {"matrix": [3, 7], "x": 7.25, "y": 3},
+ {"matrix": [3, 8], "x": 8.25, "y": 3},
+ {"matrix": [3, 9], "x": 9.25, "y": 3},
+ {"matrix": [3, 10], "x": 10.25, "y": 3},
+ {"matrix": [3, 11], "x": 11.25, "y": 3},
+ {"matrix": [3, 12], "x": 12.25, "y": 3, "w": 1.75},
+ {"matrix": [3, 13], "x": 14, "y": 3},
+ {"matrix": [4, 0], "x": 0, "y": 4, "w": 1.5},
+ {"matrix": [4, 2], "x": 2.5, "y": 4, "w": 1.5},
+ {"matrix": [4, 7], "x": 4, "y": 4, "w": 7},
+ {"matrix": [4, 10], "x": 11, "y": 4, "w": 1.5},
+ {"matrix": [4, 13], "x": 13.5, "y": 4, "w": 1.5}
+ ]
+ },
+ "LAYOUT_60_hhkb": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [0, 1], "x": 1, "y": 0},
+ {"matrix": [0, 2], "x": 2, "y": 0},
+ {"matrix": [0, 3], "x": 3, "y": 0},
+ {"matrix": [0, 4], "x": 4, "y": 0},
+ {"matrix": [0, 5], "x": 5, "y": 0},
+ {"matrix": [0, 6], "x": 6, "y": 0},
+ {"matrix": [0, 7], "x": 7, "y": 0},
+ {"matrix": [0, 8], "x": 8, "y": 0},
+ {"matrix": [0, 9], "x": 9, "y": 0},
+ {"matrix": [0, 10], "x": 10, "y": 0},
+ {"matrix": [0, 11], "x": 11, "y": 0},
+ {"matrix": [0, 12], "x": 12, "y": 0},
+ {"matrix": [2, 12], "x": 13, "y": 0},
+ {"matrix": [0, 13], "x": 14, "y": 0},
+ {"matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
+ {"matrix": [1, 1], "x": 1.5, "y": 1},
+ {"matrix": [1, 2], "x": 2.5, "y": 1},
+ {"matrix": [1, 3], "x": 3.5, "y": 1},
+ {"matrix": [1, 4], "x": 4.5, "y": 1},
+ {"matrix": [1, 5], "x": 5.5, "y": 1},
+ {"matrix": [1, 6], "x": 6.5, "y": 1},
+ {"matrix": [1, 7], "x": 7.5, "y": 1},
+ {"matrix": [1, 8], "x": 8.5, "y": 1},
+ {"matrix": [1, 9], "x": 9.5, "y": 1},
+ {"matrix": [1, 10], "x": 10.5, "y": 1},
+ {"matrix": [1, 11], "x": 11.5, "y": 1},
+ {"matrix": [1, 12], "x": 12.5, "y": 1},
+ {"matrix": [1, 13], "x": 13.5, "y": 1, "w": 1.5},
+ {"matrix": [2, 0], "x": 0, "y": 2, "w": 1.75},
+ {"matrix": [2, 1], "x": 1.75, "y": 2},
+ {"matrix": [2, 2], "x": 2.75, "y": 2},
+ {"matrix": [2, 3], "x": 3.75, "y": 2},
+ {"matrix": [2, 4], "x": 4.75, "y": 2},
+ {"matrix": [2, 5], "x": 5.75, "y": 2},
+ {"matrix": [2, 6], "x": 6.75, "y": 2},
+ {"matrix": [2, 7], "x": 7.75, "y": 2},
+ {"matrix": [2, 8], "x": 8.75, "y": 2},
+ {"matrix": [2, 9], "x": 9.75, "y": 2},
+ {"matrix": [2, 10], "x": 10.75, "y": 2},
+ {"matrix": [2, 11], "x": 11.75, "y": 2},
+ {"matrix": [2, 13], "x": 12.75, "y": 2, "w": 2.25},
+ {"matrix": [3, 0], "x": 0, "y": 3, "w": 2.25},
+ {"matrix": [3, 2], "x": 2.25, "y": 3},
+ {"matrix": [3, 3], "x": 3.25, "y": 3},
+ {"matrix": [3, 4], "x": 4.25, "y": 3},
+ {"matrix": [3, 5], "x": 5.25, "y": 3},
+ {"matrix": [3, 6], "x": 6.25, "y": 3},
+ {"matrix": [3, 7], "x": 7.25, "y": 3},
+ {"matrix": [3, 8], "x": 8.25, "y": 3},
+ {"matrix": [3, 9], "x": 9.25, "y": 3},
+ {"matrix": [3, 10], "x": 10.25, "y": 3},
+ {"matrix": [3, 11], "x": 11.25, "y": 3},
+ {"matrix": [3, 12], "x": 12.25, "y": 3, "w": 1.75},
+ {"matrix": [3, 13], "x": 14, "y": 3},
+ {"matrix": [4, 1], "x": 1.5, "y": 4},
+ {"matrix": [4, 2], "x": 2.5, "y": 4, "w": 1.5},
+ {"matrix": [4, 7], "x": 4, "y": 4, "w": 7},
+ {"matrix": [4, 10], "x": 11, "y": 4, "w": 1.5},
+ {"matrix": [4, 12], "x": 12.5, "y": 4}
+ ]
+ },
+ "LAYOUT_all": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [0, 1], "x": 1, "y": 0},
+ {"matrix": [0, 2], "x": 2, "y": 0},
+ {"matrix": [0, 3], "x": 3, "y": 0},
+ {"matrix": [0, 4], "x": 4, "y": 0},
+ {"matrix": [0, 5], "x": 5, "y": 0},
+ {"matrix": [0, 6], "x": 6, "y": 0},
+ {"matrix": [0, 7], "x": 7, "y": 0},
+ {"matrix": [0, 8], "x": 8, "y": 0},
+ {"matrix": [0, 9], "x": 9, "y": 0},
+ {"matrix": [0, 10], "x": 10, "y": 0},
+ {"matrix": [0, 11], "x": 11, "y": 0},
+ {"matrix": [0, 12], "x": 12, "y": 0},
+ {"matrix": [2, 12], "x": 13, "y": 0},
+ {"matrix": [0, 13], "x": 14, "y": 0},
+ {"matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
+ {"matrix": [1, 1], "x": 1.5, "y": 1},
+ {"matrix": [1, 2], "x": 2.5, "y": 1},
+ {"matrix": [1, 3], "x": 3.5, "y": 1},
+ {"matrix": [1, 4], "x": 4.5, "y": 1},
+ {"matrix": [1, 5], "x": 5.5, "y": 1},
+ {"matrix": [1, 6], "x": 6.5, "y": 1},
+ {"matrix": [1, 7], "x": 7.5, "y": 1},
+ {"matrix": [1, 8], "x": 8.5, "y": 1},
+ {"matrix": [1, 9], "x": 9.5, "y": 1},
+ {"matrix": [1, 10], "x": 10.5, "y": 1},
+ {"matrix": [1, 11], "x": 11.5, "y": 1},
+ {"matrix": [1, 12], "x": 12.5, "y": 1},
+ {"matrix": [1, 13], "x": 13.5, "y": 1, "w": 1.5},
+ {"matrix": [2, 0], "x": 0, "y": 2, "w": 1.75},
+ {"matrix": [2, 1], "x": 1.75, "y": 2},
+ {"matrix": [2, 2], "x": 2.75, "y": 2},
+ {"matrix": [2, 3], "x": 3.75, "y": 2},
+ {"matrix": [2, 4], "x": 4.75, "y": 2},
+ {"matrix": [2, 5], "x": 5.75, "y": 2},
+ {"matrix": [2, 6], "x": 6.75, "y": 2},
+ {"matrix": [2, 7], "x": 7.75, "y": 2},
+ {"matrix": [2, 8], "x": 8.75, "y": 2},
+ {"matrix": [2, 9], "x": 9.75, "y": 2},
+ {"matrix": [2, 10], "x": 10.75, "y": 2},
+ {"matrix": [2, 11], "x": 11.75, "y": 2},
+ {"matrix": [2, 13], "x": 12.75, "y": 2, "w": 2.25},
+ {"matrix": [3, 0], "x": 0, "y": 3, "w": 2.25},
+ {"matrix": [3, 2], "x": 2.25, "y": 3},
+ {"matrix": [3, 3], "x": 3.25, "y": 3},
+ {"matrix": [3, 4], "x": 4.25, "y": 3},
+ {"matrix": [3, 5], "x": 5.25, "y": 3},
+ {"matrix": [3, 6], "x": 6.25, "y": 3},
+ {"matrix": [3, 7], "x": 7.25, "y": 3},
+ {"matrix": [3, 8], "x": 8.25, "y": 3},
+ {"matrix": [3, 9], "x": 9.25, "y": 3},
+ {"matrix": [3, 10], "x": 10.25, "y": 3},
+ {"matrix": [3, 11], "x": 11.25, "y": 3, "w": 1.75},
+ {"matrix": [3, 12], "x": 13, "y": 3},
+ {"matrix": [3, 13], "x": 14, "y": 3},
+ {"matrix": [4, 0], "x": 0, "y": 4, "w": 1.5},
+ {"matrix": [4, 1], "x": 1.5, "y": 4},
+ {"matrix": [4, 2], "x": 2.5, "y": 4, "w": 1.5},
+ {"matrix": [4, 7], "x": 4, "y": 4, "w": 7},
+ {"matrix": [4, 10], "x": 11, "y": 4},
+ {"matrix": [4, 11], "x": 12, "y": 4},
+ {"matrix": [4, 12], "x": 13, "y": 4},
+ {"matrix": [4, 13], "x": 14, "y": 4}
+ ]
+ }
+ }
+}
diff --git a/keyboards/trnthsn/s6xty/keymaps/default/keymap.c b/keyboards/trnthsn/s6xty/keymaps/default/keymap.c
new file mode 100644
index 00000000000..97dba0d7491
--- /dev/null
+++ b/keyboards/trnthsn/s6xty/keymaps/default/keymap.c
@@ -0,0 +1,40 @@
+// Copyright 2024 QMK
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include QMK_KEYBOARD_H
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+ // ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
+ // │Esc│ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ - │ = │Bsp│Bsp│
+ // ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┤
+ // │ Tab │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │ [ │ ] │ \ │
+ // ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤
+ // │ Caps │ A │ S │ D │ F │ G │ H │ J │ K │ L │ ; │ ' │ Enter │
+ // ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───┴┬───┬───┤
+ // │ Shift │ Z │ X │ C │ V │ B │ N │ M │ , │ . │Shift │↑ │/ │
+ // ├─────┬──┴┬──┴──┬┴───┴───┴───┴───┴───┴───┴──┬┴──┬───┼───┼───┤
+ // │Ctrl │GUI│ Alt │ │Fn │← │↓ │→ │
+ // └─────┴───┴─────┴───────────────────────────┴───┴───┴───┴───┘
+
+ [0] = LAYOUT_all(
+ KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_BSPC,
+ KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS,
+ KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT,
+ KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_RSFT, KC_UP, KC_SLSH,
+ KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, MO(1), KC_LEFT, KC_DOWN, KC_RGHT
+ ),
+ [1] = LAYOUT_all(
+ KC_GRV, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_INS, KC_DEL,
+ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_PSCR, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ MO(2) , _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______
+ ),
+ [2] = LAYOUT_all(
+ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, QK_BOOT, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______
+ )
+};
diff --git a/keyboards/trnthsn/s6xty/mcuconf.h b/keyboards/trnthsn/s6xty/mcuconf.h
new file mode 100644
index 00000000000..3bf940e0bec
--- /dev/null
+++ b/keyboards/trnthsn/s6xty/mcuconf.h
@@ -0,0 +1,22 @@
+/* Copyright 2024 ThanhSon.Mech
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+#include_next
+
+#undef STM32_SPI_USE_SPI2
+#define STM32_SPI_USE_SPI2 TRUE
diff --git a/keyboards/trnthsn/s6xty/readme.md b/keyboards/trnthsn/s6xty/readme.md
new file mode 100644
index 00000000000..eb518b7cee5
--- /dev/null
+++ b/keyboards/trnthsn/s6xty/readme.md
@@ -0,0 +1,27 @@
+# S6xty
+
+
+
+A 60% keyboard PCB compatible with various keyboard cases. Supports a left USB Type-C connector or 3 JST SH positions for a daughter board
+
+* Keyboard Maintainer: [ThanhSon.Mech](https://github.com/trnthsn)
+* Hardware Supported: s6xty PCB, STM32F072
+* Hardware Availability: [ThanhSon.Mech](https://www.facebook.com/ThanhSon.mech)
+
+Make example for this keyboard (after setting up your build environment):
+
+ make trnthsn/s6xty:default
+
+Flashing example for this keyboard:
+
+ make trnthsn/s6xty:default:flash
+
+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).
+
+## Bootloader
+
+Enter the bootloader in 3 ways:
+
+* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (usually the top left key or Escape) and plug in the keyboard
+* **Physical reset button**: Briefly press the button on the back of the PCB - some may have pads you must short instead
+* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available
diff --git a/keyboards/whitefacemountain/ampersand/keyboard.json b/keyboards/whitefacemountain/ampersand/keyboard.json
index 04840d05bcd..b0929e2d3c9 100644
--- a/keyboards/whitefacemountain/ampersand/keyboard.json
+++ b/keyboards/whitefacemountain/ampersand/keyboard.json
@@ -64,13 +64,13 @@
{"label": ".", "matrix": [2, 9], "x": 9.75, "y": 2},
{"label": "/", "matrix": [2, 10], "x": 10.75, "y": 2},
{"label": "Shift", "matrix": [2, 11], "x": 11.75, "y": 2, "w": 1.75},
- {"label": "Ctrl", "matrix": [3, 0], "x": 0, "y": 3, "w": 1},
- {"label": "LAlt", "matrix": [3, 1], "x": 1.75, "y": 3, "w": 1},
- {"label": "LGui", "matrix": [3, 2], "x": 2.75, "y": 3, "w": 1},
+ {"label": "Ctrl", "matrix": [3, 0], "x": 0, "y": 3},
+ {"label": "LAlt", "matrix": [3, 1], "x": 1.75, "y": 3},
+ {"label": "LGui", "matrix": [3, 2], "x": 2.75, "y": 3},
{"label": "Space", "matrix": [3, 5], "x": 3.75, "y": 3, "w": 6},
- {"label": "RGui", "matrix": [3, 8], "x": 9.75, "y": 3, "w": 1},
- {"label": "RAlt", "matrix": [3, 9], "x": 10.75, "y": 3, "w": 1},
- {"label": "RCtrl", "matrix": [3, 11], "x": 12.5, "y": 3, "w": 1}
+ {"label": "RGui", "matrix": [3, 8], "x": 9.75, "y": 3},
+ {"label": "RAlt", "matrix": [3, 9], "x": 10.75, "y": 3},
+ {"label": "RCtrl", "matrix": [3, 11], "x": 12.5, "y": 3}
]
},
"LAYOUT_split_bars": {
@@ -113,14 +113,14 @@
{"label": ".", "matrix": [2, 9], "x": 9.75, "y": 2},
{"label": "/", "matrix": [2, 10], "x": 10.75, "y": 2},
{"label": "Shift", "matrix": [2, 11], "x": 11.75, "y": 2, "w": 1.75},
- {"label": "Ctrl", "matrix": [3, 0], "x": 0, "y": 3, "w": 1},
+ {"label": "Ctrl", "matrix": [3, 0], "x": 0, "y": 3},
{"label": "LAlt", "matrix": [3, 1], "x": 1.75, "y": 3, "w": 1.5},
- {"label": "LGui", "matrix": [3, 2], "x": 3.25, "y": 3, "w": 1},
+ {"label": "LGui", "matrix": [3, 2], "x": 3.25, "y": 3},
{"label": "Space", "matrix": [3, 3], "x": 4.25, "y": 3, "w": 2.25},
{"label": "Space", "matrix": [3, 7], "x": 6.5, "y": 3, "w": 2.75},
- {"label": "RGui", "matrix": [3, 8], "x": 9.25, "y": 3, "w": 1},
+ {"label": "RGui", "matrix": [3, 8], "x": 9.25, "y": 3},
{"label": "RAlt", "matrix": [3, 9], "x": 10.25, "y": 3, "w": 1.5},
- {"label": "RCtrl", "matrix": [3, 11], "x": 12.5, "y": 3, "w": 1}
+ {"label": "RCtrl", "matrix": [3, 11], "x": 12.5, "y": 3}
]
}
}
diff --git a/keyboards/windstudio/wind_x/r1/keyboard.json b/keyboards/windstudio/wind_x/r1/keyboard.json
new file mode 100644
index 00000000000..1b5f34fe3e8
--- /dev/null
+++ b/keyboards/windstudio/wind_x/r1/keyboard.json
@@ -0,0 +1,205 @@
+{
+ "manufacturer": "Windstudio",
+ "keyboard_name": "Wind X R1",
+ "maintainer": "chrisgve",
+ "bootloader": "atmel-dfu",
+ "diode_direction": "COL2ROW",
+ "features": {
+ "bootmagic": true,
+ "extrakey": true,
+ "mousekey": true,
+ "nkro": true
+ },
+ "matrix_pins": {
+ "cols": ["C7", "C6", "B6", "E6", "F6", "D6", "D7", "B4", "B5", "F7", "B7", "F4", "F5", "D4", "B0", "B1", "B2", "B3"],
+ "rows": ["F0", "F1", "D2", "D1", "D0"]
+ },
+ "processor": "atmega32u4",
+ "url": "",
+ "usb": {
+ "device_version": "0.0.1",
+ "pid": "0x6801",
+ "vid": "0x6F75"
+ },
+ "layout_aliases": {
+ "LAYOUT_tsangan": "LAYOUT_7u_space_bar_split_bs"
+ },
+ "layouts": {
+ "LAYOUT": {
+ "layout": [
+ {"label": "Esc", "matrix": [0, 0], "x": 0, "y": 0},
+ {"label": "1", "matrix": [0, 1], "x": 1, "y": 0},
+ {"label": "2", "matrix": [0, 2], "x": 2, "y": 0},
+ {"label": "3", "matrix": [0, 3], "x": 3, "y": 0},
+ {"label": "4", "matrix": [0, 4], "x": 4, "y": 0},
+ {"label": "5", "matrix": [0, 5], "x": 5, "y": 0},
+ {"label": "6", "matrix": [0, 6], "x": 6, "y": 0},
+ {"label": "7", "matrix": [0, 7], "x": 7, "y": 0},
+ {"label": "8", "matrix": [0, 8], "x": 8, "y": 0},
+ {"label": "9", "matrix": [0, 9], "x": 9, "y": 0},
+ {"label": "0", "matrix": [0, 10], "x": 10, "y": 0},
+ {"label": "-", "matrix": [0, 11], "x": 11, "y": 0},
+ {"label": "=", "matrix": [0, 12], "x": 12, "y": 0},
+ {"label": "Backspace", "matrix": [0, 13], "x": 13, "y": 0, "w": 2},
+ {"label": "Del", "matrix": [4, 11], "x": 16, "y": 0},
+ {"label": "NumLock", "matrix": [0, 14], "x": 18, "y": 0},
+ {"label": "KP/", "matrix": [0, 15], "x": 19, "y": 0},
+ {"label": "KP*", "matrix": [0, 16], "x": 20, "y": 0},
+ {"label": "KP-", "matrix": [0, 17], "x": 21, "y": 0},
+ {"label": "Tab", "matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
+ {"label": "Q", "matrix": [1, 1], "x": 1.5, "y": 1},
+ {"label": "W", "matrix": [1, 2], "x": 2.5, "y": 1},
+ {"label": "E", "matrix": [1, 3], "x": 3.5, "y": 1},
+ {"label": "R", "matrix": [1, 4], "x": 4.5, "y": 1},
+ {"label": "T", "matrix": [1, 5], "x": 5.5, "y": 1},
+ {"label": "Y", "matrix": [1, 6], "x": 6.5, "y": 1},
+ {"label": "U", "matrix": [1, 7], "x": 7.5, "y": 1},
+ {"label": "I", "matrix": [1, 8], "x": 8.5, "y": 1},
+ {"label": "O", "matrix": [1, 9], "x": 9.5, "y": 1},
+ {"label": "P", "matrix": [1, 10], "x": 10.5, "y": 1},
+ {"label": "[", "matrix": [1, 11], "x": 11.5, "y": 1},
+ {"label": "]", "matrix": [1, 12], "x": 12.5, "y": 1},
+ {"label": "\\", "matrix": [2, 12], "x": 13.5, "y": 1, "w": 1.5},
+ {"label": "PgUp", "matrix": [4, 12], "x": 16, "y": 1},
+ {"label": "KP7", "matrix": [1, 14], "x": 18, "y": 1},
+ {"label": "KP8", "matrix": [1, 15], "x": 19, "y": 1},
+ {"label": "KP9", "matrix": [1, 16], "x": 20, "y": 1},
+ {"label": "KP+", "matrix": [1, 17], "x": 21, "y": 1},
+ {"label": "Caps", "matrix": [2, 0], "x": 0, "y": 2, "w": 1.75},
+ {"label": "A", "matrix": [2, 1], "x": 1.75, "y": 2},
+ {"label": "S", "matrix": [2, 2], "x": 2.75, "y": 2},
+ {"label": "D", "matrix": [2, 3], "x": 3.75, "y": 2},
+ {"label": "F", "matrix": [2, 4], "x": 4.75, "y": 2},
+ {"label": "G", "matrix": [2, 5], "x": 5.75, "y": 2},
+ {"label": "H", "matrix": [2, 6], "x": 6.75, "y": 2},
+ {"label": "J", "matrix": [2, 7], "x": 7.75, "y": 2},
+ {"label": "K", "matrix": [2, 8], "x": 8.75, "y": 2},
+ {"label": "L", "matrix": [2, 9], "x": 9.75, "y": 2},
+ {"label": ";", "matrix": [2, 10], "x": 10.75, "y": 2},
+ {"label": "'", "matrix": [2, 11], "x": 11.75, "y": 2},
+ {"label": "Return", "matrix": [2, 13], "x": 12.75, "y": 2, "w": 2.25},
+ {"label": "PgDn", "matrix": [4, 13], "x": 16, "y": 2},
+ {"label": "KP4", "matrix": [2, 14], "x": 18, "y": 2},
+ {"label": "KP5", "matrix": [2, 15], "x": 19, "y": 2},
+ {"label": "KP6", "matrix": [2, 16], "x": 20, "y": 2},
+ {"label": "KP+", "matrix": [2, 17], "x": 21, "y": 2},
+ {"label": "Shift", "matrix": [3, 0], "x": 0, "y": 3, "w": 2.25},
+ {"label": "Z", "matrix": [3, 2], "x": 2.25, "y": 3},
+ {"label": "X", "matrix": [3, 3], "x": 3.25, "y": 3},
+ {"label": "C", "matrix": [3, 4], "x": 4.25, "y": 3},
+ {"label": "V", "matrix": [3, 5], "x": 5.25, "y": 3},
+ {"label": "B", "matrix": [3, 6], "x": 6.25, "y": 3},
+ {"label": "N", "matrix": [3, 7], "x": 7.25, "y": 3},
+ {"label": "M", "matrix": [3, 8], "x": 8.25, "y": 3},
+ {"label": ",", "matrix": [3, 9], "x": 9.25, "y": 3},
+ {"label": ".", "matrix": [3, 10], "x": 10.25, "y": 3},
+ {"label": "/", "matrix": [3, 11], "x": 11.25, "y": 3},
+ {"label": "Shift", "matrix": [3, 12], "x": 12.25, "y": 3, "w": 1.75},
+ {"label": "Up", "matrix": [3, 13], "x": 13, "y": 3},
+ {"label": "KP1", "matrix": [3, 14], "x": 18, "y": 3},
+ {"label": "KP2", "matrix": [3, 15], "x": 19, "y": 3},
+ {"label": "KP3", "matrix": [3, 16], "x": 20, "y": 3},
+ {"label": "Enter", "matrix": [3, 17], "x": 21, "y": 3},
+ {"label": "Ctrl", "matrix": [4, 0], "x": 0, "y": 4, "w": 1.25},
+ {"label": "GUI", "matrix": [4, 1], "x": 1.25, "y": 4, "w": 1.25},
+ {"label": "Alt", "matrix": [4, 2], "x": 2.5, "y": 4, "w": 1.25},
+ {"label": "Space", "matrix": [4, 5], "x": 3.75, "y": 4, "w": 6.25},
+ {"label": "GUI", "matrix": [4, 6], "x": 10, "y": 4, "w": 1.25},
+ {"label": "Ctrl", "matrix": [4, 7], "x": 11.25, "y": 4, "w": 1.25},
+ {"label": "Left", "matrix": [4, 8], "x": 14, "y": 4},
+ {"label": "Down", "matrix": [4, 9], "x": 15, "y": 4},
+ {"label": "Right", "matrix": [4, 10], "x": 16, "y": 4},
+ {"label": "KP0", "matrix": [4, 16], "x": 18, "y": 4},
+ {"label": "KP.", "matrix": [4, 17], "x": 19, "y": 4}
+ ]
+ },
+ "LAYOUT_7u_space_bar_split_bs": {
+ "layout": [
+ {"label": "Esc", "matrix": [0, 0], "x": 0, "y": 0},
+ {"label": "1", "matrix": [0, 1], "x": 1, "y": 0},
+ {"label": "2", "matrix": [0, 2], "x": 2, "y": 0},
+ {"label": "3", "matrix": [0, 3], "x": 3, "y": 0},
+ {"label": "4", "matrix": [0, 4], "x": 4, "y": 0},
+ {"label": "5", "matrix": [0, 5], "x": 5, "y": 0},
+ {"label": "6", "matrix": [0, 6], "x": 6, "y": 0},
+ {"label": "7", "matrix": [0, 7], "x": 7, "y": 0},
+ {"label": "8", "matrix": [0, 8], "x": 8, "y": 0},
+ {"label": "9", "matrix": [0, 9], "x": 9, "y": 0},
+ {"label": "0", "matrix": [0, 10], "x": 10, "y": 0},
+ {"label": "-", "matrix": [0, 11], "x": 11, "y": 0},
+ {"label": "=", "matrix": [0, 12], "x": 12, "y": 0},
+ {"label": "\\", "matrix": [0, 13], "x": 13, "y": 0},
+ {"label": "`", "matrix": [1, 13], "x": 14, "y": 0},
+ {"label": "PgUp", "matrix": [4, 11], "x": 16, "y": 0},
+ {"label": "NumLock", "matrix": [0, 14], "x": 18, "y": 0},
+ {"label": "KP/", "matrix": [0, 15], "x": 19, "y": 0},
+ {"label": "KP*", "matrix": [0, 16], "x": 20, "y": 0},
+ {"label": "KP-", "matrix": [0, 17], "x": 21, "y": 0},
+ {"label": "Tab", "matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
+ {"label": "Q", "matrix": [1, 1], "x": 1.5, "y": 1},
+ {"label": "W", "matrix": [1, 2], "x": 2.5, "y": 1},
+ {"label": "E", "matrix": [1, 3], "x": 3.5, "y": 1},
+ {"label": "R", "matrix": [1, 4], "x": 4.5, "y": 1},
+ {"label": "T", "matrix": [1, 5], "x": 5.5, "y": 1},
+ {"label": "Y", "matrix": [1, 6], "x": 6.5, "y": 1},
+ {"label": "U", "matrix": [1, 7], "x": 7.5, "y": 1},
+ {"label": "I", "matrix": [1, 8], "x": 8.5, "y": 1},
+ {"label": "O", "matrix": [1, 9], "x": 9.5, "y": 1},
+ {"label": "P", "matrix": [1, 10], "x": 10.5, "y": 1},
+ {"label": "[", "matrix": [1, 11], "x": 11.5, "y": 1},
+ {"label": "]", "matrix": [1, 12], "x": 12.5, "y": 1},
+ {"label": "Backspace", "matrix": [2, 12], "x": 13.5, "y": 1, "w": 1.5},
+ {"label": "PgDn", "matrix": [4, 12], "x": 16, "y": 1},
+ {"label": "KP7", "matrix": [1, 14], "x": 18, "y": 1},
+ {"label": "KP8", "matrix": [1, 15], "x": 19, "y": 1},
+ {"label": "KP9", "matrix": [1, 16], "x": 20, "y": 1},
+ {"label": "KP+", "matrix": [1, 17], "x": 21, "y": 1},
+ {"label": "Ctrl", "matrix": [2, 0], "x": 0, "y": 2, "w": 1.75},
+ {"label": "A", "matrix": [2, 1], "x": 1.75, "y": 2},
+ {"label": "S", "matrix": [2, 2], "x": 2.75, "y": 2},
+ {"label": "D", "matrix": [2, 3], "x": 3.75, "y": 2},
+ {"label": "F", "matrix": [2, 4], "x": 4.75, "y": 2},
+ {"label": "G", "matrix": [2, 5], "x": 5.75, "y": 2},
+ {"label": "H", "matrix": [2, 6], "x": 6.75, "y": 2},
+ {"label": "J", "matrix": [2, 7], "x": 7.75, "y": 2},
+ {"label": "K", "matrix": [2, 8], "x": 8.75, "y": 2},
+ {"label": "L", "matrix": [2, 9], "x": 9.75, "y": 2},
+ {"label": ";", "matrix": [2, 10], "x": 10.75, "y": 2},
+ {"label": "'", "matrix": [2, 11], "x": 11.75, "y": 2},
+ {"label": "Return", "matrix": [2, 13], "x": 12.75, "y": 2, "w": 2.25},
+ {"label": "End", "matrix": [4, 13], "x": 16, "y": 2},
+ {"label": "KP4", "matrix": [2, 14], "x": 18, "y": 2},
+ {"label": "KP5", "matrix": [2, 15], "x": 19, "y": 2},
+ {"label": "KP6", "matrix": [2, 16], "x": 20, "y": 2},
+ {"label": "KP+", "matrix": [2, 17], "x": 21, "y": 2},
+ {"label": "Shift", "matrix": [3, 0], "x": 0, "y": 3, "w": 2.25},
+ {"label": "Z", "matrix": [3, 2], "x": 2.25, "y": 3},
+ {"label": "X", "matrix": [3, 3], "x": 3.25, "y": 3},
+ {"label": "C", "matrix": [3, 4], "x": 4.25, "y": 3},
+ {"label": "V", "matrix": [3, 5], "x": 5.25, "y": 3},
+ {"label": "B", "matrix": [3, 6], "x": 6.25, "y": 3},
+ {"label": "N", "matrix": [3, 7], "x": 7.25, "y": 3},
+ {"label": "M", "matrix": [3, 8], "x": 8.25, "y": 3},
+ {"label": ",", "matrix": [3, 9], "x": 9.25, "y": 3},
+ {"label": ".", "matrix": [3, 10], "x": 10.25, "y": 3},
+ {"label": "/", "matrix": [3, 11], "x": 11.25, "y": 3},
+ {"label": "Shift", "matrix": [3, 12], "x": 12.25, "y": 3, "w": 1.75},
+ {"label": "Up", "matrix": [3, 13], "x": 13, "y": 3},
+ {"label": "KP1", "matrix": [3, 14], "x": 18, "y": 3},
+ {"label": "KP2", "matrix": [3, 15], "x": 19, "y": 3},
+ {"label": "KP3", "matrix": [3, 16], "x": 20, "y": 3},
+ {"label": "Enter", "matrix": [3, 17], "x": 21, "y": 3},
+ {"label": "Ctrl", "matrix": [4, 0], "x": 0, "y": 4, "w": 1.5},
+ {"label": "GUI", "matrix": [4, 1], "x": 1.5, "y": 4},
+ {"label": "Alt", "matrix": [4, 2], "x": 2.5, "y": 4, "w": 1.5},
+ {"label": "Space", "matrix": [4, 5], "x": 4, "y": 4, "w": 7},
+ {"label": "Ctrl", "matrix": [4, 7], "x": 11, "y": 4, "w": 1.5},
+ {"label": "Left", "matrix": [4, 8], "x": 13, "y": 4},
+ {"label": "Down", "matrix": [4, 9], "x": 14, "y": 4},
+ {"label": "Right", "matrix": [4, 10], "x": 15, "y": 4},
+ {"label": "KP0", "matrix": [4, 16], "x": 18, "y": 4},
+ {"label": "KP.", "matrix": [4, 17], "x": 19, "y": 4}
+ ]
+ }
+ }
+}
diff --git a/keyboards/windstudio/wind_x/r1/keymaps/default/keymap.c b/keyboards/windstudio/wind_x/r1/keymaps/default/keymap.c
new file mode 100644
index 00000000000..dd3134e2a0f
--- /dev/null
+++ b/keyboards/windstudio/wind_x/r1/keymaps/default/keymap.c
@@ -0,0 +1,40 @@
+/* Copyright 2024 chrisgve
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include QMK_KEYBOARD_H
+
+// clang-format off
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+
+ [0] = LAYOUT(
+ QK_GESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_DEL, KC_NUM, KC_PSLS, KC_PAST, KC_PMNS,
+ KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGUP, KC_P7, KC_P8, KC_P9, KC_PPLS,
+ KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_PGDN, KC_P4, KC_P5, KC_P6, KC_PPLS,
+ KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_P1, KC_P2, KC_P3, KC_PENT,
+ KC_LCTL, KC_LGUI, KC_LALT, LT(1, KC_SPC), KC_RGUI, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT, KC_P0, KC_PDOT
+ ),
+
+ [1] = LAYOUT(
+ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ QK_BOOT, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______
+ )
+
+};
+
+// clang-format on
diff --git a/keyboards/windstudio/wind_x/r1/keymaps/default/readme.md b/keyboards/windstudio/wind_x/r1/keymaps/default/readme.md
new file mode 100644
index 00000000000..2fa0952a830
--- /dev/null
+++ b/keyboards/windstudio/wind_x/r1/keymaps/default/readme.md
@@ -0,0 +1,6 @@
+# Default Wind X R1 Layout
+
+This is the default layout that comes flashed on every Wind X R1. For the most
+part it's a straightforward and easy to follow layout. The only unusual key is
+the key in the upper left, which sends Escape normally, but Grave when any of
+the Ctrl, Alt, or GUI modifiers are held down.
diff --git a/keyboards/windstudio/wind_x/r1/readme.md b/keyboards/windstudio/wind_x/r1/readme.md
new file mode 100644
index 00000000000..c501951e422
--- /dev/null
+++ b/keyboards/windstudio/wind_x/r1/readme.md
@@ -0,0 +1,28 @@
+# WindX R1 by Windstudio
+
+
+_Compact, yet feature full working or gaming keyboard_
+
+A large layout keyboard without the function keys. [More info on geekhack.org](https://geekhack.org/index.php?topic=114767.0)
+
+- Keyboard Maintainer: [Christian C. Berclaz](https://github.com/chrisgve)
+- Hardware Supported: Wind X R1 w/ ATmega32U4 microcontroller
+- Hardware Availability: [windstudio.store](https://windstudio.store/collections/wind-x)
+
+Make example for this keyboard (after setting up your build environment):
+
+ make windstudio/wind_x/r1:default
+
+Flashing example for this keyboard:
+
+ make windstudio/wind_x/r1:default:flash
+
+See the [build environment setup](getting_started_build_tools) and the [make instructions](getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](newbs).
+
+## Bootloader
+
+Enter the bootloader in 3 ways:
+
+- **Bootmagic reset**: Hold down the key at (0,0) in the matrix (usually the top left key or Escape) and plug in the keyboard
+- **Physical reset button**: Briefly press the button on the back of the PCB - some may have pads you must short instead
+- **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available
diff --git a/keyboards/work_louder/loop/config.h b/keyboards/work_louder/loop/config.h
index b883b0ff578..5b031c6fc10 100644
--- a/keyboards/work_louder/loop/config.h
+++ b/keyboards/work_louder/loop/config.h
@@ -18,3 +18,5 @@ along with this program. If not, see .
#pragma once
#define RGBLIGHT_DI_PIN E6
+
+#define RGB_MATRIX_DISABLE_SHARED_KEYCODES
diff --git a/keyboards/work_louder/micro/config.h b/keyboards/work_louder/micro/config.h
index b9f2d8d87dc..6748a5f5951 100644
--- a/keyboards/work_louder/micro/config.h
+++ b/keyboards/work_louder/micro/config.h
@@ -9,3 +9,5 @@
#define WORK_LOUDER_LED_PIN_1 B6
#define WORK_LOUDER_LED_PIN_2 B7
#define WORK_LOUDER_LED_PIN_3 B5
+
+#define RGB_MATRIX_DISABLE_SHARED_KEYCODES
diff --git a/keyboards/work_louder/nano/config.h b/keyboards/work_louder/nano/config.h
index 2372f371b99..492931c559c 100644
--- a/keyboards/work_louder/nano/config.h
+++ b/keyboards/work_louder/nano/config.h
@@ -18,3 +18,5 @@ along with this program. If not, see .
#pragma once
#define RGBLIGHT_DI_PIN C7
+
+#define RGB_MATRIX_DISABLE_SHARED_KEYCODES
diff --git a/keyboards/work_louder/numpad/config.h b/keyboards/work_louder/numpad/config.h
index cfc27d36124..809c498dbbb 100644
--- a/keyboards/work_louder/numpad/config.h
+++ b/keyboards/work_louder/numpad/config.h
@@ -5,3 +5,5 @@
#define RGBLIGHT_DI_PIN D2
#define RGBLIGHT_DEFAULT_MODE RGBLIGHT_MODE_STATIC_GRADIENT + 9
+
+#define RGB_MATRIX_DISABLE_SHARED_KEYCODES
diff --git a/keyboards/work_louder/work_board/config.h b/keyboards/work_louder/work_board/config.h
index 6688711bbbc..efd4c529cd8 100644
--- a/keyboards/work_louder/work_board/config.h
+++ b/keyboards/work_louder/work_board/config.h
@@ -20,3 +20,5 @@ along with this program. If not, see .
#define RGBLIGHT_DI_PIN D2
#define RGBLIGHT_DEFAULT_MODE RGBLIGHT_MODE_STATIC_GRADIENT + 9
+
+#define RGB_MATRIX_DISABLE_SHARED_KEYCODES
diff --git a/keyboards/zeix/singa/kohaku/config.h b/keyboards/zeix/singa/kohaku/config.h
new file mode 100644
index 00000000000..77970ce4d34
--- /dev/null
+++ b/keyboards/zeix/singa/kohaku/config.h
@@ -0,0 +1,20 @@
+/*
+Copyright 2023 zeix (@itsme-zeix)
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+#pragma once
+
+#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET
+#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT 500U
diff --git a/keyboards/zeix/singa/kohaku/keyboard.json b/keyboards/zeix/singa/kohaku/keyboard.json
new file mode 100644
index 00000000000..542bad9c6fc
--- /dev/null
+++ b/keyboards/zeix/singa/kohaku/keyboard.json
@@ -0,0 +1,698 @@
+{
+ "manufacturer": "SINGA",
+ "keyboard_name": "Kohaku",
+ "maintainer": "itsme-zeix",
+ "bootloader": "rp2040",
+ "diode_direction": "COL2ROW",
+ "features": {
+ "rgblight": true,
+ "bootmagic": true,
+ "extrakey": true,
+ "mousekey": true
+ },
+ "indicators": {
+ "caps_lock": "GP29"
+ },
+ "matrix_pins": {
+ "cols": ["GP7", "GP6", "GP5", "GP4", "GP3", "GP2", "GP1", "GP0"],
+ "rows": ["GP27", "GP28", "GP10", "GP11", "GP18", "GP19", "GP23", "GP24", "GP25", "GP26"]
+ },
+ "processor": "RP2040",
+ "rgblight": {
+ "animations": {
+ "alternating": true,
+ "breathing": true,
+ "christmas": true,
+ "knight": true,
+ "rainbow_mood": true,
+ "rainbow_swirl": true,
+ "snake": true,
+ "static_gradient": true,
+ "twinkle": true
+ },
+ "brightness_steps": 8,
+ "led_count": 28,
+ "saturation_steps": 8,
+ "sleep": true
+ },
+ "usb": {
+ "device_version": "0.0.1",
+ "pid": "0x8888",
+ "vid": "0x4C27"
+ },
+ "ws2812": {
+ "driver": "vendor",
+ "pin": "GP20"
+ },
+ "community_layouts": ["65_ansi_blocker", "65_ansi_blocker_split_bs", "65_ansi_blocker_tsangan", "65_ansi_blocker_tsangan_split_bs", "65_iso_blocker", "65_iso_blocker_split_bs", "65_iso_blocker_tsangan", "65_iso_blocker_tsangan_split_bs"],
+ "layouts": {
+ "LAYOUT_all": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [1, 0], "x": 1, "y": 0},
+ {"matrix": [0, 1], "x": 2, "y": 0},
+ {"matrix": [1, 1], "x": 3, "y": 0},
+ {"matrix": [0, 2], "x": 4, "y": 0},
+ {"matrix": [1, 2], "x": 5, "y": 0},
+ {"matrix": [0, 3], "x": 6, "y": 0},
+ {"matrix": [1, 3], "x": 7, "y": 0},
+ {"matrix": [0, 4], "x": 8, "y": 0},
+ {"matrix": [1, 4], "x": 9, "y": 0},
+ {"matrix": [0, 5], "x": 10, "y": 0},
+ {"matrix": [1, 5], "x": 11, "y": 0},
+ {"matrix": [0, 6], "x": 12, "y": 0},
+ {"matrix": [1, 6], "x": 13, "y": 0},
+ {"matrix": [0, 7], "x": 14, "y": 0},
+ {"matrix": [1, 7], "x": 15, "y": 0},
+ {"matrix": [2, 0], "x": 0, "y": 1, "w": 1.5},
+ {"matrix": [3, 0], "x": 1.5, "y": 1},
+ {"matrix": [2, 1], "x": 2.5, "y": 1},
+ {"matrix": [3, 1], "x": 3.5, "y": 1},
+ {"matrix": [2, 2], "x": 4.5, "y": 1},
+ {"matrix": [3, 2], "x": 5.5, "y": 1},
+ {"matrix": [2, 3], "x": 6.5, "y": 1},
+ {"matrix": [3, 3], "x": 7.5, "y": 1},
+ {"matrix": [2, 4], "x": 8.5, "y": 1},
+ {"matrix": [3, 4], "x": 9.5, "y": 1},
+ {"matrix": [2, 5], "x": 10.5, "y": 1},
+ {"matrix": [3, 5], "x": 11.5, "y": 1},
+ {"matrix": [2, 6], "x": 12.5, "y": 1},
+ {"matrix": [3, 6], "x": 13.5, "y": 1, "w": 1.5},
+ {"matrix": [3, 7], "x": 15, "y": 1},
+ {"matrix": [4, 0], "x": 0, "y": 2, "w": 1.75},
+ {"matrix": [5, 0], "x": 1.75, "y": 2},
+ {"matrix": [4, 1], "x": 2.75, "y": 2},
+ {"matrix": [5, 1], "x": 3.75, "y": 2},
+ {"matrix": [4, 2], "x": 4.75, "y": 2},
+ {"matrix": [5, 2], "x": 5.75, "y": 2},
+ {"matrix": [4, 3], "x": 6.75, "y": 2},
+ {"matrix": [5, 3], "x": 7.75, "y": 2},
+ {"matrix": [4, 4], "x": 8.75, "y": 2},
+ {"matrix": [5, 4], "x": 9.75, "y": 2},
+ {"matrix": [4, 5], "x": 10.75, "y": 2},
+ {"matrix": [5, 5], "x": 11.75, "y": 2},
+ {"matrix": [4, 6], "x": 12.75, "y": 2},
+ {"matrix": [5, 6], "x": 13.75, "y": 2, "w": 1.25},
+ {"matrix": [5, 7], "x": 15, "y": 2},
+ {"matrix": [6, 0], "x": 0, "y": 3, "w": 1.25},
+ {"matrix": [7, 0], "x": 1.25, "y": 3},
+ {"matrix": [6, 1], "x": 2.25, "y": 3},
+ {"matrix": [7, 1], "x": 3.25, "y": 3},
+ {"matrix": [6, 2], "x": 4.25, "y": 3},
+ {"matrix": [7, 2], "x": 5.25, "y": 3},
+ {"matrix": [6, 3], "x": 6.25, "y": 3},
+ {"matrix": [7, 3], "x": 7.25, "y": 3},
+ {"matrix": [6, 4], "x": 8.25, "y": 3},
+ {"matrix": [7, 4], "x": 9.25, "y": 3},
+ {"matrix": [6, 5], "x": 10.25, "y": 3},
+ {"matrix": [7, 5], "x": 11.25, "y": 3},
+ {"matrix": [6, 6], "x": 12.25, "y": 3, "w": 1.75},
+ {"matrix": [7, 6], "x": 14, "y": 3},
+ {"matrix": [7, 7], "x": 15, "y": 3},
+ {"matrix": [8, 0], "x": 0, "y": 4, "w": 1.25},
+ {"matrix": [9, 0], "x": 1.25, "y": 4, "w": 1.25},
+ {"matrix": [8, 1], "x": 2.5, "y": 4, "w": 1.25},
+ {"matrix": [9, 2], "x": 3.75, "y": 4, "w": 2.75},
+ {"matrix": [8, 3], "x": 6.5, "y": 4, "w": 1.25},
+ {"matrix": [9, 4], "x": 7.75, "y": 4, "w": 2.25},
+ {"matrix": [8, 5], "x": 10, "y": 4, "w": 1.25},
+ {"matrix": [9, 5], "x": 11.25, "y": 4, "w": 1.25},
+ {"matrix": [8, 6], "x": 13, "y": 4},
+ {"matrix": [9, 6], "x": 14, "y": 4},
+ {"matrix": [9, 7], "x": 15, "y": 4}
+ ]
+ },
+ "LAYOUT_65_ansi_blocker": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [1, 0], "x": 1, "y": 0},
+ {"matrix": [0, 1], "x": 2, "y": 0},
+ {"matrix": [1, 1], "x": 3, "y": 0},
+ {"matrix": [0, 2], "x": 4, "y": 0},
+ {"matrix": [1, 2], "x": 5, "y": 0},
+ {"matrix": [0, 3], "x": 6, "y": 0},
+ {"matrix": [1, 3], "x": 7, "y": 0},
+ {"matrix": [0, 4], "x": 8, "y": 0},
+ {"matrix": [1, 4], "x": 9, "y": 0},
+ {"matrix": [0, 5], "x": 10, "y": 0},
+ {"matrix": [1, 5], "x": 11, "y": 0},
+ {"matrix": [0, 6], "x": 12, "y": 0},
+ {"matrix": [0, 7], "x": 13, "y": 0, "w": 2},
+ {"matrix": [1, 7], "x": 15, "y": 0},
+ {"matrix": [2, 0], "x": 0, "y": 1, "w": 1.5},
+ {"matrix": [3, 0], "x": 1.5, "y": 1},
+ {"matrix": [2, 1], "x": 2.5, "y": 1},
+ {"matrix": [3, 1], "x": 3.5, "y": 1},
+ {"matrix": [2, 2], "x": 4.5, "y": 1},
+ {"matrix": [3, 2], "x": 5.5, "y": 1},
+ {"matrix": [2, 3], "x": 6.5, "y": 1},
+ {"matrix": [3, 3], "x": 7.5, "y": 1},
+ {"matrix": [2, 4], "x": 8.5, "y": 1},
+ {"matrix": [3, 4], "x": 9.5, "y": 1},
+ {"matrix": [2, 5], "x": 10.5, "y": 1},
+ {"matrix": [3, 5], "x": 11.5, "y": 1},
+ {"matrix": [2, 6], "x": 12.5, "y": 1},
+ {"matrix": [3, 6], "x": 13.5, "y": 1, "w": 1.5},
+ {"matrix": [3, 7], "x": 15, "y": 1},
+ {"matrix": [4, 0], "x": 0, "y": 2, "w": 1.75},
+ {"matrix": [5, 0], "x": 1.75, "y": 2},
+ {"matrix": [4, 1], "x": 2.75, "y": 2},
+ {"matrix": [5, 1], "x": 3.75, "y": 2},
+ {"matrix": [4, 2], "x": 4.75, "y": 2},
+ {"matrix": [5, 2], "x": 5.75, "y": 2},
+ {"matrix": [4, 3], "x": 6.75, "y": 2},
+ {"matrix": [5, 3], "x": 7.75, "y": 2},
+ {"matrix": [4, 4], "x": 8.75, "y": 2},
+ {"matrix": [5, 4], "x": 9.75, "y": 2},
+ {"matrix": [4, 5], "x": 10.75, "y": 2},
+ {"matrix": [5, 5], "x": 11.75, "y": 2},
+ {"matrix": [5, 6], "x": 12.75, "y": 2, "w": 2.25},
+ {"matrix": [5, 7], "x": 15, "y": 2},
+ {"matrix": [6, 0], "x": 0, "y": 3, "w": 2.25},
+ {"matrix": [6, 1], "x": 2.25, "y": 3},
+ {"matrix": [7, 1], "x": 3.25, "y": 3},
+ {"matrix": [6, 2], "x": 4.25, "y": 3},
+ {"matrix": [7, 2], "x": 5.25, "y": 3},
+ {"matrix": [6, 3], "x": 6.25, "y": 3},
+ {"matrix": [7, 3], "x": 7.25, "y": 3},
+ {"matrix": [6, 4], "x": 8.25, "y": 3},
+ {"matrix": [7, 4], "x": 9.25, "y": 3},
+ {"matrix": [6, 5], "x": 10.25, "y": 3},
+ {"matrix": [7, 5], "x": 11.25, "y": 3},
+ {"matrix": [6, 6], "x": 12.25, "y": 3, "w": 1.75},
+ {"matrix": [7, 6], "x": 14, "y": 3},
+ {"matrix": [7, 7], "x": 15, "y": 3},
+ {"matrix": [8, 0], "x": 0, "y": 4, "w": 1.25},
+ {"matrix": [9, 0], "x": 1.25, "y": 4, "w": 1.25},
+ {"matrix": [8, 1], "x": 2.5, "y": 4, "w": 1.25},
+ {"matrix": [8, 3], "x": 3.75, "y": 4, "w": 6.25},
+ {"matrix": [8, 5], "x": 10, "y": 4, "w": 1.25},
+ {"matrix": [9, 5], "x": 11.25, "y": 4, "w": 1.25},
+ {"matrix": [8, 6], "x": 13, "y": 4},
+ {"matrix": [9, 6], "x": 14, "y": 4},
+ {"matrix": [9, 7], "x": 15, "y": 4}
+ ]
+ },
+ "LAYOUT_65_ansi_blocker_split_bs": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [1, 0], "x": 1, "y": 0},
+ {"matrix": [0, 1], "x": 2, "y": 0},
+ {"matrix": [1, 1], "x": 3, "y": 0},
+ {"matrix": [0, 2], "x": 4, "y": 0},
+ {"matrix": [1, 2], "x": 5, "y": 0},
+ {"matrix": [0, 3], "x": 6, "y": 0},
+ {"matrix": [1, 3], "x": 7, "y": 0},
+ {"matrix": [0, 4], "x": 8, "y": 0},
+ {"matrix": [1, 4], "x": 9, "y": 0},
+ {"matrix": [0, 5], "x": 10, "y": 0},
+ {"matrix": [1, 5], "x": 11, "y": 0},
+ {"matrix": [0, 6], "x": 12, "y": 0},
+ {"matrix": [1, 6], "x": 13, "y": 0},
+ {"matrix": [0, 7], "x": 14, "y": 0},
+ {"matrix": [1, 7], "x": 15, "y": 0},
+ {"matrix": [2, 0], "x": 0, "y": 1, "w": 1.5},
+ {"matrix": [3, 0], "x": 1.5, "y": 1},
+ {"matrix": [2, 1], "x": 2.5, "y": 1},
+ {"matrix": [3, 1], "x": 3.5, "y": 1},
+ {"matrix": [2, 2], "x": 4.5, "y": 1},
+ {"matrix": [3, 2], "x": 5.5, "y": 1},
+ {"matrix": [2, 3], "x": 6.5, "y": 1},
+ {"matrix": [3, 3], "x": 7.5, "y": 1},
+ {"matrix": [2, 4], "x": 8.5, "y": 1},
+ {"matrix": [3, 4], "x": 9.5, "y": 1},
+ {"matrix": [2, 5], "x": 10.5, "y": 1},
+ {"matrix": [3, 5], "x": 11.5, "y": 1},
+ {"matrix": [2, 6], "x": 12.5, "y": 1},
+ {"matrix": [3, 6], "x": 13.5, "y": 1, "w": 1.5},
+ {"matrix": [3, 7], "x": 15, "y": 1},
+ {"matrix": [4, 0], "x": 0, "y": 2, "w": 1.75},
+ {"matrix": [5, 0], "x": 1.75, "y": 2},
+ {"matrix": [4, 1], "x": 2.75, "y": 2},
+ {"matrix": [5, 1], "x": 3.75, "y": 2},
+ {"matrix": [4, 2], "x": 4.75, "y": 2},
+ {"matrix": [5, 2], "x": 5.75, "y": 2},
+ {"matrix": [4, 3], "x": 6.75, "y": 2},
+ {"matrix": [5, 3], "x": 7.75, "y": 2},
+ {"matrix": [4, 4], "x": 8.75, "y": 2},
+ {"matrix": [5, 4], "x": 9.75, "y": 2},
+ {"matrix": [4, 5], "x": 10.75, "y": 2},
+ {"matrix": [5, 5], "x": 11.75, "y": 2},
+ {"matrix": [5, 6], "x": 12.75, "y": 2, "w": 2.25},
+ {"matrix": [5, 7], "x": 15, "y": 2},
+ {"matrix": [6, 0], "x": 0, "y": 3, "w": 2.25},
+ {"matrix": [6, 1], "x": 2.25, "y": 3},
+ {"matrix": [7, 1], "x": 3.25, "y": 3},
+ {"matrix": [6, 2], "x": 4.25, "y": 3},
+ {"matrix": [7, 2], "x": 5.25, "y": 3},
+ {"matrix": [6, 3], "x": 6.25, "y": 3},
+ {"matrix": [7, 3], "x": 7.25, "y": 3},
+ {"matrix": [6, 4], "x": 8.25, "y": 3},
+ {"matrix": [7, 4], "x": 9.25, "y": 3},
+ {"matrix": [6, 5], "x": 10.25, "y": 3},
+ {"matrix": [7, 5], "x": 11.25, "y": 3},
+ {"matrix": [6, 6], "x": 12.25, "y": 3, "w": 1.75},
+ {"matrix": [7, 6], "x": 14, "y": 3},
+ {"matrix": [7, 7], "x": 15, "y": 3},
+ {"matrix": [8, 0], "x": 0, "y": 4, "w": 1.25},
+ {"matrix": [9, 0], "x": 1.25, "y": 4, "w": 1.25},
+ {"matrix": [8, 1], "x": 2.5, "y": 4, "w": 1.25},
+ {"matrix": [8, 3], "x": 3.75, "y": 4, "w": 6.25},
+ {"matrix": [8, 5], "x": 10, "y": 4, "w": 1.25},
+ {"matrix": [9, 5], "x": 11.25, "y": 4, "w": 1.25},
+ {"matrix": [8, 6], "x": 13, "y": 4},
+ {"matrix": [9, 6], "x": 14, "y": 4},
+ {"matrix": [9, 7], "x": 15, "y": 4}
+ ]
+ },
+ "LAYOUT_65_ansi_blocker_tsangan": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [1, 0], "x": 1, "y": 0},
+ {"matrix": [0, 1], "x": 2, "y": 0},
+ {"matrix": [1, 1], "x": 3, "y": 0},
+ {"matrix": [0, 2], "x": 4, "y": 0},
+ {"matrix": [1, 2], "x": 5, "y": 0},
+ {"matrix": [0, 3], "x": 6, "y": 0},
+ {"matrix": [1, 3], "x": 7, "y": 0},
+ {"matrix": [0, 4], "x": 8, "y": 0},
+ {"matrix": [1, 4], "x": 9, "y": 0},
+ {"matrix": [0, 5], "x": 10, "y": 0},
+ {"matrix": [1, 5], "x": 11, "y": 0},
+ {"matrix": [0, 6], "x": 12, "y": 0},
+ {"matrix": [0, 7], "x": 13, "y": 0, "w": 2},
+ {"matrix": [1, 7], "x": 15, "y": 0},
+ {"matrix": [2, 0], "x": 0, "y": 1, "w": 1.5},
+ {"matrix": [3, 0], "x": 1.5, "y": 1},
+ {"matrix": [2, 1], "x": 2.5, "y": 1},
+ {"matrix": [3, 1], "x": 3.5, "y": 1},
+ {"matrix": [2, 2], "x": 4.5, "y": 1},
+ {"matrix": [3, 2], "x": 5.5, "y": 1},
+ {"matrix": [2, 3], "x": 6.5, "y": 1},
+ {"matrix": [3, 3], "x": 7.5, "y": 1},
+ {"matrix": [2, 4], "x": 8.5, "y": 1},
+ {"matrix": [3, 4], "x": 9.5, "y": 1},
+ {"matrix": [2, 5], "x": 10.5, "y": 1},
+ {"matrix": [3, 5], "x": 11.5, "y": 1},
+ {"matrix": [2, 6], "x": 12.5, "y": 1},
+ {"matrix": [3, 6], "x": 13.5, "y": 1, "w": 1.5},
+ {"matrix": [3, 7], "x": 15, "y": 1},
+ {"matrix": [4, 0], "x": 0, "y": 2, "w": 1.75},
+ {"matrix": [5, 0], "x": 1.75, "y": 2},
+ {"matrix": [4, 1], "x": 2.75, "y": 2},
+ {"matrix": [5, 1], "x": 3.75, "y": 2},
+ {"matrix": [4, 2], "x": 4.75, "y": 2},
+ {"matrix": [5, 2], "x": 5.75, "y": 2},
+ {"matrix": [4, 3], "x": 6.75, "y": 2},
+ {"matrix": [5, 3], "x": 7.75, "y": 2},
+ {"matrix": [4, 4], "x": 8.75, "y": 2},
+ {"matrix": [5, 4], "x": 9.75, "y": 2},
+ {"matrix": [4, 5], "x": 10.75, "y": 2},
+ {"matrix": [5, 5], "x": 11.75, "y": 2},
+ {"matrix": [5, 6], "x": 12.75, "y": 2, "w": 2.25},
+ {"matrix": [5, 7], "x": 15, "y": 2},
+ {"matrix": [6, 0], "x": 0, "y": 3, "w": 2.25},
+ {"matrix": [6, 1], "x": 2.25, "y": 3},
+ {"matrix": [7, 1], "x": 3.25, "y": 3},
+ {"matrix": [6, 2], "x": 4.25, "y": 3},
+ {"matrix": [7, 2], "x": 5.25, "y": 3},
+ {"matrix": [6, 3], "x": 6.25, "y": 3},
+ {"matrix": [7, 3], "x": 7.25, "y": 3},
+ {"matrix": [6, 4], "x": 8.25, "y": 3},
+ {"matrix": [7, 4], "x": 9.25, "y": 3},
+ {"matrix": [6, 5], "x": 10.25, "y": 3},
+ {"matrix": [7, 5], "x": 11.25, "y": 3},
+ {"matrix": [6, 6], "x": 12.25, "y": 3, "w": 1.75},
+ {"matrix": [7, 6], "x": 14, "y": 3},
+ {"matrix": [7, 7], "x": 15, "y": 3},
+ {"matrix": [8, 0], "x": 0, "y": 4, "w": 1.5},
+ {"matrix": [9, 0], "x": 1.5, "y": 4},
+ {"matrix": [8, 1], "x": 2.5, "y": 4, "w": 1.5},
+ {"matrix": [8, 3], "x": 4, "y": 4, "w": 7},
+ {"matrix": [8, 5], "x": 11, "y": 4, "w": 1.5},
+ {"matrix": [8, 6], "x": 13, "y": 4},
+ {"matrix": [9, 6], "x": 14, "y": 4},
+ {"matrix": [9, 7], "x": 15, "y": 4}
+ ]
+ },
+ "LAYOUT_65_ansi_blocker_tsangan_split_bs": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [1, 0], "x": 1, "y": 0},
+ {"matrix": [0, 1], "x": 2, "y": 0},
+ {"matrix": [1, 1], "x": 3, "y": 0},
+ {"matrix": [0, 2], "x": 4, "y": 0},
+ {"matrix": [1, 2], "x": 5, "y": 0},
+ {"matrix": [0, 3], "x": 6, "y": 0},
+ {"matrix": [1, 3], "x": 7, "y": 0},
+ {"matrix": [0, 4], "x": 8, "y": 0},
+ {"matrix": [1, 4], "x": 9, "y": 0},
+ {"matrix": [0, 5], "x": 10, "y": 0},
+ {"matrix": [1, 5], "x": 11, "y": 0},
+ {"matrix": [0, 6], "x": 12, "y": 0},
+ {"matrix": [1, 6], "x": 13, "y": 0},
+ {"matrix": [0, 7], "x": 14, "y": 0},
+ {"matrix": [1, 7], "x": 15, "y": 0},
+ {"matrix": [2, 0], "x": 0, "y": 1, "w": 1.5},
+ {"matrix": [3, 0], "x": 1.5, "y": 1},
+ {"matrix": [2, 1], "x": 2.5, "y": 1},
+ {"matrix": [3, 1], "x": 3.5, "y": 1},
+ {"matrix": [2, 2], "x": 4.5, "y": 1},
+ {"matrix": [3, 2], "x": 5.5, "y": 1},
+ {"matrix": [2, 3], "x": 6.5, "y": 1},
+ {"matrix": [3, 3], "x": 7.5, "y": 1},
+ {"matrix": [2, 4], "x": 8.5, "y": 1},
+ {"matrix": [3, 4], "x": 9.5, "y": 1},
+ {"matrix": [2, 5], "x": 10.5, "y": 1},
+ {"matrix": [3, 5], "x": 11.5, "y": 1},
+ {"matrix": [2, 6], "x": 12.5, "y": 1},
+ {"matrix": [3, 6], "x": 13.5, "y": 1, "w": 1.5},
+ {"matrix": [3, 7], "x": 15, "y": 1},
+ {"matrix": [4, 0], "x": 0, "y": 2, "w": 1.75},
+ {"matrix": [5, 0], "x": 1.75, "y": 2},
+ {"matrix": [4, 1], "x": 2.75, "y": 2},
+ {"matrix": [5, 1], "x": 3.75, "y": 2},
+ {"matrix": [4, 2], "x": 4.75, "y": 2},
+ {"matrix": [5, 2], "x": 5.75, "y": 2},
+ {"matrix": [4, 3], "x": 6.75, "y": 2},
+ {"matrix": [5, 3], "x": 7.75, "y": 2},
+ {"matrix": [4, 4], "x": 8.75, "y": 2},
+ {"matrix": [5, 4], "x": 9.75, "y": 2},
+ {"matrix": [4, 5], "x": 10.75, "y": 2},
+ {"matrix": [5, 5], "x": 11.75, "y": 2},
+ {"matrix": [5, 6], "x": 12.75, "y": 2, "w": 2.25},
+ {"matrix": [5, 7], "x": 15, "y": 2},
+ {"matrix": [6, 0], "x": 0, "y": 3, "w": 2.25},
+ {"matrix": [6, 1], "x": 2.25, "y": 3},
+ {"matrix": [7, 1], "x": 3.25, "y": 3},
+ {"matrix": [6, 2], "x": 4.25, "y": 3},
+ {"matrix": [7, 2], "x": 5.25, "y": 3},
+ {"matrix": [6, 3], "x": 6.25, "y": 3},
+ {"matrix": [7, 3], "x": 7.25, "y": 3},
+ {"matrix": [6, 4], "x": 8.25, "y": 3},
+ {"matrix": [7, 4], "x": 9.25, "y": 3},
+ {"matrix": [6, 5], "x": 10.25, "y": 3},
+ {"matrix": [7, 5], "x": 11.25, "y": 3},
+ {"matrix": [6, 6], "x": 12.25, "y": 3, "w": 1.75},
+ {"matrix": [7, 6], "x": 14, "y": 3},
+ {"matrix": [7, 7], "x": 15, "y": 3},
+ {"matrix": [8, 0], "x": 0, "y": 4, "w": 1.5},
+ {"matrix": [9, 0], "x": 1.5, "y": 4},
+ {"matrix": [8, 1], "x": 2.5, "y": 4, "w": 1.5},
+ {"matrix": [8, 3], "x": 4, "y": 4, "w": 7},
+ {"matrix": [8, 5], "x": 11, "y": 4, "w": 1.5},
+ {"matrix": [8, 6], "x": 13, "y": 4},
+ {"matrix": [9, 6], "x": 14, "y": 4},
+ {"matrix": [9, 7], "x": 15, "y": 4}
+ ]
+ },
+ "LAYOUT_65_iso_blocker": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [1, 0], "x": 1, "y": 0},
+ {"matrix": [0, 1], "x": 2, "y": 0},
+ {"matrix": [1, 1], "x": 3, "y": 0},
+ {"matrix": [0, 2], "x": 4, "y": 0},
+ {"matrix": [1, 2], "x": 5, "y": 0},
+ {"matrix": [0, 3], "x": 6, "y": 0},
+ {"matrix": [1, 3], "x": 7, "y": 0},
+ {"matrix": [0, 4], "x": 8, "y": 0},
+ {"matrix": [1, 4], "x": 9, "y": 0},
+ {"matrix": [0, 5], "x": 10, "y": 0},
+ {"matrix": [1, 5], "x": 11, "y": 0},
+ {"matrix": [0, 6], "x": 12, "y": 0},
+ {"matrix": [0, 7], "x": 13, "y": 0, "w": 2},
+ {"matrix": [1, 7], "x": 15, "y": 0},
+ {"matrix": [2, 0], "x": 0, "y": 1, "w": 1.5},
+ {"matrix": [3, 0], "x": 1.5, "y": 1},
+ {"matrix": [2, 1], "x": 2.5, "y": 1},
+ {"matrix": [3, 1], "x": 3.5, "y": 1},
+ {"matrix": [2, 2], "x": 4.5, "y": 1},
+ {"matrix": [3, 2], "x": 5.5, "y": 1},
+ {"matrix": [2, 3], "x": 6.5, "y": 1},
+ {"matrix": [3, 3], "x": 7.5, "y": 1},
+ {"matrix": [2, 4], "x": 8.5, "y": 1},
+ {"matrix": [3, 4], "x": 9.5, "y": 1},
+ {"matrix": [2, 5], "x": 10.5, "y": 1},
+ {"matrix": [3, 5], "x": 11.5, "y": 1},
+ {"matrix": [2, 6], "x": 12.5, "y": 1},
+ {"matrix": [3, 7], "x": 15, "y": 1},
+ {"matrix": [4, 0], "x": 0, "y": 2, "w": 1.75},
+ {"matrix": [5, 0], "x": 1.75, "y": 2},
+ {"matrix": [4, 1], "x": 2.75, "y": 2},
+ {"matrix": [5, 1], "x": 3.75, "y": 2},
+ {"matrix": [4, 2], "x": 4.75, "y": 2},
+ {"matrix": [5, 2], "x": 5.75, "y": 2},
+ {"matrix": [4, 3], "x": 6.75, "y": 2},
+ {"matrix": [5, 3], "x": 7.75, "y": 2},
+ {"matrix": [4, 4], "x": 8.75, "y": 2},
+ {"matrix": [5, 4], "x": 9.75, "y": 2},
+ {"matrix": [4, 5], "x": 10.75, "y": 2},
+ {"matrix": [5, 5], "x": 11.75, "y": 2},
+ {"matrix": [4, 6], "x": 12.75, "y": 2},
+ {"matrix": [5, 6], "x": 13.75, "y": 1, "w": 1.25, "h": 2},
+ {"matrix": [5, 7], "x": 15, "y": 2},
+ {"matrix": [6, 0], "x": 0, "y": 3, "w": 1.25},
+ {"matrix": [7, 0], "x": 1.25, "y": 3},
+ {"matrix": [6, 1], "x": 2.25, "y": 3},
+ {"matrix": [7, 1], "x": 3.25, "y": 3},
+ {"matrix": [6, 2], "x": 4.25, "y": 3},
+ {"matrix": [7, 2], "x": 5.25, "y": 3},
+ {"matrix": [6, 3], "x": 6.25, "y": 3},
+ {"matrix": [7, 3], "x": 7.25, "y": 3},
+ {"matrix": [6, 4], "x": 8.25, "y": 3},
+ {"matrix": [7, 4], "x": 9.25, "y": 3},
+ {"matrix": [6, 5], "x": 10.25, "y": 3},
+ {"matrix": [7, 5], "x": 11.25, "y": 3},
+ {"matrix": [6, 6], "x": 12.25, "y": 3, "w": 1.75},
+ {"matrix": [7, 6], "x": 14, "y": 3},
+ {"matrix": [7, 7], "x": 15, "y": 3},
+ {"matrix": [8, 0], "x": 0, "y": 4, "w": 1.25},
+ {"matrix": [9, 0], "x": 1.25, "y": 4, "w": 1.25},
+ {"matrix": [8, 1], "x": 2.5, "y": 4, "w": 1.25},
+ {"matrix": [8, 3], "x": 3.75, "y": 4, "w": 6.25},
+ {"matrix": [8, 5], "x": 10, "y": 4, "w": 1.25},
+ {"matrix": [9, 5], "x": 11.25, "y": 4, "w": 1.25},
+ {"matrix": [8, 6], "x": 13, "y": 4},
+ {"matrix": [9, 6], "x": 14, "y": 4},
+ {"matrix": [9, 7], "x": 15, "y": 4}
+ ]
+ },
+ "LAYOUT_65_iso_blocker_split_bs": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [1, 0], "x": 1, "y": 0},
+ {"matrix": [0, 1], "x": 2, "y": 0},
+ {"matrix": [1, 1], "x": 3, "y": 0},
+ {"matrix": [0, 2], "x": 4, "y": 0},
+ {"matrix": [1, 2], "x": 5, "y": 0},
+ {"matrix": [0, 3], "x": 6, "y": 0},
+ {"matrix": [1, 3], "x": 7, "y": 0},
+ {"matrix": [0, 4], "x": 8, "y": 0},
+ {"matrix": [1, 4], "x": 9, "y": 0},
+ {"matrix": [0, 5], "x": 10, "y": 0},
+ {"matrix": [1, 5], "x": 11, "y": 0},
+ {"matrix": [0, 6], "x": 12, "y": 0},
+ {"matrix": [1, 6], "x": 13, "y": 0},
+ {"matrix": [0, 7], "x": 14, "y": 0},
+ {"matrix": [1, 7], "x": 15, "y": 0},
+ {"matrix": [2, 0], "x": 0, "y": 1, "w": 1.5},
+ {"matrix": [3, 0], "x": 1.5, "y": 1},
+ {"matrix": [2, 1], "x": 2.5, "y": 1},
+ {"matrix": [3, 1], "x": 3.5, "y": 1},
+ {"matrix": [2, 2], "x": 4.5, "y": 1},
+ {"matrix": [3, 2], "x": 5.5, "y": 1},
+ {"matrix": [2, 3], "x": 6.5, "y": 1},
+ {"matrix": [3, 3], "x": 7.5, "y": 1},
+ {"matrix": [2, 4], "x": 8.5, "y": 1},
+ {"matrix": [3, 4], "x": 9.5, "y": 1},
+ {"matrix": [2, 5], "x": 10.5, "y": 1},
+ {"matrix": [3, 5], "x": 11.5, "y": 1},
+ {"matrix": [2, 6], "x": 12.5, "y": 1},
+ {"matrix": [3, 7], "x": 15, "y": 1},
+ {"matrix": [4, 0], "x": 0, "y": 2, "w": 1.75},
+ {"matrix": [5, 0], "x": 1.75, "y": 2},
+ {"matrix": [4, 1], "x": 2.75, "y": 2},
+ {"matrix": [5, 1], "x": 3.75, "y": 2},
+ {"matrix": [4, 2], "x": 4.75, "y": 2},
+ {"matrix": [5, 2], "x": 5.75, "y": 2},
+ {"matrix": [4, 3], "x": 6.75, "y": 2},
+ {"matrix": [5, 3], "x": 7.75, "y": 2},
+ {"matrix": [4, 4], "x": 8.75, "y": 2},
+ {"matrix": [5, 4], "x": 9.75, "y": 2},
+ {"matrix": [4, 5], "x": 10.75, "y": 2},
+ {"matrix": [5, 5], "x": 11.75, "y": 2},
+ {"matrix": [4, 6], "x": 12.75, "y": 2},
+ {"matrix": [5, 6], "x": 13.75, "y": 1, "w": 1.25, "h": 2},
+ {"matrix": [5, 7], "x": 15, "y": 2},
+ {"matrix": [6, 0], "x": 0, "y": 3, "w": 1.25},
+ {"matrix": [7, 0], "x": 1.25, "y": 3},
+ {"matrix": [6, 1], "x": 2.25, "y": 3},
+ {"matrix": [7, 1], "x": 3.25, "y": 3},
+ {"matrix": [6, 2], "x": 4.25, "y": 3},
+ {"matrix": [7, 2], "x": 5.25, "y": 3},
+ {"matrix": [6, 3], "x": 6.25, "y": 3},
+ {"matrix": [7, 3], "x": 7.25, "y": 3},
+ {"matrix": [6, 4], "x": 8.25, "y": 3},
+ {"matrix": [7, 4], "x": 9.25, "y": 3},
+ {"matrix": [6, 5], "x": 10.25, "y": 3},
+ {"matrix": [7, 5], "x": 11.25, "y": 3},
+ {"matrix": [6, 6], "x": 12.25, "y": 3, "w": 1.75},
+ {"matrix": [7, 6], "x": 14, "y": 3},
+ {"matrix": [7, 7], "x": 15, "y": 3},
+ {"matrix": [8, 0], "x": 0, "y": 4, "w": 1.25},
+ {"matrix": [9, 0], "x": 1.25, "y": 4, "w": 1.25},
+ {"matrix": [8, 1], "x": 2.5, "y": 4, "w": 1.25},
+ {"matrix": [8, 3], "x": 3.75, "y": 4, "w": 6.25},
+ {"matrix": [8, 5], "x": 10, "y": 4, "w": 1.25},
+ {"matrix": [9, 5], "x": 11.25, "y": 4, "w": 1.25},
+ {"matrix": [8, 6], "x": 13, "y": 4},
+ {"matrix": [9, 6], "x": 14, "y": 4},
+ {"matrix": [9, 7], "x": 15, "y": 4}
+ ]
+ },
+ "LAYOUT_65_iso_blocker_tsangan": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [1, 0], "x": 1, "y": 0},
+ {"matrix": [0, 1], "x": 2, "y": 0},
+ {"matrix": [1, 1], "x": 3, "y": 0},
+ {"matrix": [0, 2], "x": 4, "y": 0},
+ {"matrix": [1, 2], "x": 5, "y": 0},
+ {"matrix": [0, 3], "x": 6, "y": 0},
+ {"matrix": [1, 3], "x": 7, "y": 0},
+ {"matrix": [0, 4], "x": 8, "y": 0},
+ {"matrix": [1, 4], "x": 9, "y": 0},
+ {"matrix": [0, 5], "x": 10, "y": 0},
+ {"matrix": [1, 5], "x": 11, "y": 0},
+ {"matrix": [0, 6], "x": 12, "y": 0},
+ {"matrix": [0, 7], "x": 13, "y": 0, "w": 2},
+ {"matrix": [1, 7], "x": 15, "y": 0},
+ {"matrix": [2, 0], "x": 0, "y": 1, "w": 1.5},
+ {"matrix": [3, 0], "x": 1.5, "y": 1},
+ {"matrix": [2, 1], "x": 2.5, "y": 1},
+ {"matrix": [3, 1], "x": 3.5, "y": 1},
+ {"matrix": [2, 2], "x": 4.5, "y": 1},
+ {"matrix": [3, 2], "x": 5.5, "y": 1},
+ {"matrix": [2, 3], "x": 6.5, "y": 1},
+ {"matrix": [3, 3], "x": 7.5, "y": 1},
+ {"matrix": [2, 4], "x": 8.5, "y": 1},
+ {"matrix": [3, 4], "x": 9.5, "y": 1},
+ {"matrix": [2, 5], "x": 10.5, "y": 1},
+ {"matrix": [3, 5], "x": 11.5, "y": 1},
+ {"matrix": [2, 6], "x": 12.5, "y": 1},
+ {"matrix": [3, 7], "x": 15, "y": 1},
+ {"matrix": [4, 0], "x": 0, "y": 2, "w": 1.75},
+ {"matrix": [5, 0], "x": 1.75, "y": 2},
+ {"matrix": [4, 1], "x": 2.75, "y": 2},
+ {"matrix": [5, 1], "x": 3.75, "y": 2},
+ {"matrix": [4, 2], "x": 4.75, "y": 2},
+ {"matrix": [5, 2], "x": 5.75, "y": 2},
+ {"matrix": [4, 3], "x": 6.75, "y": 2},
+ {"matrix": [5, 3], "x": 7.75, "y": 2},
+ {"matrix": [4, 4], "x": 8.75, "y": 2},
+ {"matrix": [5, 4], "x": 9.75, "y": 2},
+ {"matrix": [4, 5], "x": 10.75, "y": 2},
+ {"matrix": [5, 5], "x": 11.75, "y": 2},
+ {"matrix": [4, 6], "x": 12.75, "y": 2},
+ {"matrix": [5, 6], "x": 13.75, "y": 1, "w": 1.25, "h": 2},
+ {"matrix": [5, 7], "x": 15, "y": 2},
+ {"matrix": [6, 0], "x": 0, "y": 3, "w": 1.25},
+ {"matrix": [7, 0], "x": 1.25, "y": 3},
+ {"matrix": [6, 1], "x": 2.25, "y": 3},
+ {"matrix": [7, 1], "x": 3.25, "y": 3},
+ {"matrix": [6, 2], "x": 4.25, "y": 3},
+ {"matrix": [7, 2], "x": 5.25, "y": 3},
+ {"matrix": [6, 3], "x": 6.25, "y": 3},
+ {"matrix": [7, 3], "x": 7.25, "y": 3},
+ {"matrix": [6, 4], "x": 8.25, "y": 3},
+ {"matrix": [7, 4], "x": 9.25, "y": 3},
+ {"matrix": [6, 5], "x": 10.25, "y": 3},
+ {"matrix": [7, 5], "x": 11.25, "y": 3},
+ {"matrix": [6, 6], "x": 12.25, "y": 3, "w": 1.75},
+ {"matrix": [7, 6], "x": 14, "y": 3},
+ {"matrix": [7, 7], "x": 15, "y": 3},
+ {"matrix": [8, 0], "x": 0, "y": 4, "w": 1.5},
+ {"matrix": [9, 0], "x": 1.5, "y": 4},
+ {"matrix": [8, 1], "x": 2.5, "y": 4, "w": 1.5},
+ {"matrix": [8, 3], "x": 4, "y": 4, "w": 7},
+ {"matrix": [8, 5], "x": 11, "y": 4, "w": 1.5},
+ {"matrix": [8, 6], "x": 13, "y": 4},
+ {"matrix": [9, 6], "x": 14, "y": 4},
+ {"matrix": [9, 7], "x": 15, "y": 4}
+ ]
+ },
+ "LAYOUT_65_iso_blocker_tsangan_split_bs": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [1, 0], "x": 1, "y": 0},
+ {"matrix": [0, 1], "x": 2, "y": 0},
+ {"matrix": [1, 1], "x": 3, "y": 0},
+ {"matrix": [0, 2], "x": 4, "y": 0},
+ {"matrix": [1, 2], "x": 5, "y": 0},
+ {"matrix": [0, 3], "x": 6, "y": 0},
+ {"matrix": [1, 3], "x": 7, "y": 0},
+ {"matrix": [0, 4], "x": 8, "y": 0},
+ {"matrix": [1, 4], "x": 9, "y": 0},
+ {"matrix": [0, 5], "x": 10, "y": 0},
+ {"matrix": [1, 5], "x": 11, "y": 0},
+ {"matrix": [0, 6], "x": 12, "y": 0},
+ {"matrix": [1, 6], "x": 13, "y": 0},
+ {"matrix": [0, 7], "x": 14, "y": 0},
+ {"matrix": [1, 7], "x": 15, "y": 0},
+ {"matrix": [2, 0], "x": 0, "y": 1, "w": 1.5},
+ {"matrix": [3, 0], "x": 1.5, "y": 1},
+ {"matrix": [2, 1], "x": 2.5, "y": 1},
+ {"matrix": [3, 1], "x": 3.5, "y": 1},
+ {"matrix": [2, 2], "x": 4.5, "y": 1},
+ {"matrix": [3, 2], "x": 5.5, "y": 1},
+ {"matrix": [2, 3], "x": 6.5, "y": 1},
+ {"matrix": [3, 3], "x": 7.5, "y": 1},
+ {"matrix": [2, 4], "x": 8.5, "y": 1},
+ {"matrix": [3, 4], "x": 9.5, "y": 1},
+ {"matrix": [2, 5], "x": 10.5, "y": 1},
+ {"matrix": [3, 5], "x": 11.5, "y": 1},
+ {"matrix": [2, 6], "x": 12.5, "y": 1},
+ {"matrix": [3, 7], "x": 15, "y": 1},
+ {"matrix": [4, 0], "x": 0, "y": 2, "w": 1.75},
+ {"matrix": [5, 0], "x": 1.75, "y": 2},
+ {"matrix": [4, 1], "x": 2.75, "y": 2},
+ {"matrix": [5, 1], "x": 3.75, "y": 2},
+ {"matrix": [4, 2], "x": 4.75, "y": 2},
+ {"matrix": [5, 2], "x": 5.75, "y": 2},
+ {"matrix": [4, 3], "x": 6.75, "y": 2},
+ {"matrix": [5, 3], "x": 7.75, "y": 2},
+ {"matrix": [4, 4], "x": 8.75, "y": 2},
+ {"matrix": [5, 4], "x": 9.75, "y": 2},
+ {"matrix": [4, 5], "x": 10.75, "y": 2},
+ {"matrix": [5, 5], "x": 11.75, "y": 2},
+ {"matrix": [4, 6], "x": 12.75, "y": 2},
+ {"matrix": [5, 6], "x": 13.75, "y": 1, "w": 1.25, "h": 2},
+ {"matrix": [5, 7], "x": 15, "y": 2},
+ {"matrix": [6, 0], "x": 0, "y": 3, "w": 1.25},
+ {"matrix": [7, 0], "x": 1.25, "y": 3},
+ {"matrix": [6, 1], "x": 2.25, "y": 3},
+ {"matrix": [7, 1], "x": 3.25, "y": 3},
+ {"matrix": [6, 2], "x": 4.25, "y": 3},
+ {"matrix": [7, 2], "x": 5.25, "y": 3},
+ {"matrix": [6, 3], "x": 6.25, "y": 3},
+ {"matrix": [7, 3], "x": 7.25, "y": 3},
+ {"matrix": [6, 4], "x": 8.25, "y": 3},
+ {"matrix": [7, 4], "x": 9.25, "y": 3},
+ {"matrix": [6, 5], "x": 10.25, "y": 3},
+ {"matrix": [7, 5], "x": 11.25, "y": 3},
+ {"matrix": [6, 6], "x": 12.25, "y": 3, "w": 1.75},
+ {"matrix": [7, 6], "x": 14, "y": 3},
+ {"matrix": [7, 7], "x": 15, "y": 3},
+ {"matrix": [8, 0], "x": 0, "y": 4, "w": 1.5},
+ {"matrix": [9, 0], "x": 1.5, "y": 4},
+ {"matrix": [8, 1], "x": 2.5, "y": 4, "w": 1.5},
+ {"matrix": [8, 3], "x": 4, "y": 4, "w": 7},
+ {"matrix": [8, 5], "x": 11, "y": 4, "w": 1.5},
+ {"matrix": [8, 6], "x": 13, "y": 4},
+ {"matrix": [9, 6], "x": 14, "y": 4},
+ {"matrix": [9, 7], "x": 15, "y": 4}
+ ]
+ }
+ }
+}
diff --git a/keyboards/zeix/singa/kohaku/keymaps/default/keymap.c b/keyboards/zeix/singa/kohaku/keymaps/default/keymap.c
new file mode 100644
index 00000000000..e58dd0c18ae
--- /dev/null
+++ b/keyboards/zeix/singa/kohaku/keymaps/default/keymap.c
@@ -0,0 +1,35 @@
+/*
+Copyright 2024 zeix (@itsme-zeix)
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+#include QMK_KEYBOARD_H
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+
+[0] = LAYOUT_all(
+ KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSLS, KC_BSPC, KC_INS,
+ KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGUP,
+ KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_NUHS, KC_ENT, KC_PGDN,
+ KC_LSFT, KC_NUBS, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, MO(1),
+ KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_SPC, KC_SPC, KC_RALT, KC_RCTL, KC_LEFT, KC_DOWN, KC_RIGHT
+ ),
+
+[1] = LAYOUT_all(
+ KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_TRNS, KC_DEL, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
+ ),
+};
diff --git a/keyboards/zeix/singa/kohaku/matrix_diagram.md b/keyboards/zeix/singa/kohaku/matrix_diagram.md
new file mode 100644
index 00000000000..79cd5d07845
--- /dev/null
+++ b/keyboards/zeix/singa/kohaku/matrix_diagram.md
@@ -0,0 +1,30 @@
+# Matrix Diagram for Singa Kohaku (Designed by Zeix)
+
+```
+ ┌───┬───┐
+ Split Backspace │16 │07 │
+ └───┴───┘
+┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┬───┐
+│00 │10 │01 │11 │02 │12 │03 │13 │04 │14 │05 │15 │06 │07 │17 │
+├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┼───┤ ┌─────┐
+│20 │30 │21 │31 │22 │32 │23 │33 │24 │34 │25 │35 │26 │36 │37 │ │ │
+├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┼───┤ ┌──┴┐56 │ ISO Enter
+│40 │50 │41 │51 │42 │52 │43 │53 │44 │54 │45 │55 │56 │57 │ │46 │ │
+├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────┬───┼───┤ └───┴────┘
+│60 │61 │71 │62 │72 │63 │73 │64 │74 │65 │75 │66 │76 │77 │
+├─────┬──┴┬──┴──┬┴───┴───┴───┴───┴───┴───┴──┬┴───┴┬─┬───┼───┼───┤
+│80 │90 │81 │83 │95 │ │86 │96 │97 │
+└─────┴───┴─────┴───────────────────────────┴─────┘ └───┴───┴───┘
+┌────┬───┐
+│60 │70 │ Split Left Shift
+└────┴───┘
+┌────┬────┬────┬────────────────────────┬────┬────┐
+│80 │90 │81 │83 │85 │95 │ 6.25u
+└────┴────┴────┴────────────────────────┴────┴────┘
+┌────┬────┬────┬───────────┬────┬───────┬────┬────┐
+│80 │90 │81 │92 │83 │94 │85 │95 │ Split Space (Left 2.75u)
+└────┴────┴────┴───────────┴────┴───────┴────┴────┘
+┌────┬────┬────┬───────┬────┬───────────┬────┬────┐
+│80 │90 │81 │92 │83 │94 │85 │95 │ Split Space (Left 2.25u)
+└────┴────┴────┴───────┴────┴───────────┴────┴────┘
+```
diff --git a/keyboards/zeix/singa/kohaku/readme.md b/keyboards/zeix/singa/kohaku/readme.md
new file mode 100644
index 00000000000..864f660e5c9
--- /dev/null
+++ b/keyboards/zeix/singa/kohaku/readme.md
@@ -0,0 +1,27 @@
+# SINGA Kohaku R2 (PCB designed by Zeix)
+
+
+
+65% PCB designed to support Kohaku R2.
+
+- Keyboard Maintainer: [Zeix](https://github.com/itsme-zeix)
+- Hardware Supported: Singa Kohaku R2 (PCB designed by Zeix)
+- Hardware Availability: https://singakbd.com/
+
+Make example for this keyboard (after setting up your build environment):
+
+ make zeix/singa/kohaku:default
+
+Flashing example for this keyboard:
+
+ make zeix/singa/kohaku:default:flash
+
+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).
+
+## Bootloader
+
+Enter the bootloader in 3 ways:
+
+- **Bootmagic reset**: Hold down the top left key and plug in the keyboard.
+- **Physical reset button**: Briefly press the `RESET` button twice or short the 'USB_BOOT' and `GND` pads and plug in the keyboard.
+- **Keycode in layout**: Press the key mapped to `QK_BOOT`.
diff --git a/keyboards/zykrah/fuyu_hs/config.h b/keyboards/zykrah/fuyu_hs/config.h
new file mode 100644
index 00000000000..767cc3f69ac
--- /dev/null
+++ b/keyboards/zykrah/fuyu_hs/config.h
@@ -0,0 +1,21 @@
+/*
+Copyright 2024 Zykrah
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+#pragma once
+
+#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET
+#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT 500U
diff --git a/keyboards/zykrah/fuyu_hs/keyboard.json b/keyboards/zykrah/fuyu_hs/keyboard.json
new file mode 100644
index 00000000000..de5530b8dec
--- /dev/null
+++ b/keyboards/zykrah/fuyu_hs/keyboard.json
@@ -0,0 +1,404 @@
+{
+ "keyboard_name": "Fuyu Hotswap",
+ "maintainer": "zykrah",
+ "manufacturer": "Zykrah",
+ "processor": "RP2040",
+ "bootloader": "rp2040",
+ "usb": {
+ "device_version": "0.0.1",
+ "pid": "0x4648",
+ "vid": "0x7A79"
+ },
+ "features": {
+ "bootmagic": true,
+ "extrakey": true,
+ "mousekey": true,
+ "nkro": true,
+ "rgb_matrix": true
+ },
+ "diode_direction": "COL2ROW",
+ "dynamic_keymap": {
+ "layer_count": 6
+ },
+ "matrix_pins": {
+ "rows": ["GP13", "GP12", "GP11", "GP10", "GP15", "GP14"],
+ "cols": ["GP29", "GP28", "GP27", "GP26", "GP25", "GP24", "GP23", "GP22", "GP21", "GP20", "GP19", "GP18", "GP17", "GP16", "GP2", "GP1", "GP0"]
+ },
+ "rgb_matrix": {
+ "animations": {
+ "alphas_mods": true,
+ "gradient_up_down": true,
+ "gradient_left_right": true,
+ "breathing": true,
+ "band_sat": true,
+ "band_val": true,
+ "band_pinwheel_sat": true,
+ "band_pinwheel_val": true,
+ "band_spiral_sat": true,
+ "band_spiral_val": true,
+ "cycle_all": true,
+ "cycle_left_right": true,
+ "cycle_up_down": true,
+ "rainbow_moving_chevron": true,
+ "cycle_out_in": true,
+ "cycle_out_in_dual": true,
+ "cycle_pinwheel": true,
+ "cycle_spiral": true,
+ "dual_beacon": true,
+ "rainbow_beacon": true,
+ "rainbow_pinwheels": true,
+ "raindrops": true,
+ "jellybean_raindrops": true,
+ "hue_breathing": true,
+ "hue_pendulum": true,
+ "hue_wave": true,
+ "pixel_rain": true,
+ "pixel_flow": true,
+ "pixel_fractal": true
+ },
+ "default": {
+ "val": 150
+ },
+ "driver": "ws2812",
+ "max_brightness": 200,
+ "layout": [
+ {"x": 112, "y": 32, "flags": 8},
+ {"x": 138, "y": 17, "flags": 8},
+ {"x": 112, "y": 2, "flags": 8},
+ {"x": 86, "y": 17, "flags": 8},
+ {"x": 86, "y": 47, "flags": 8},
+ {"x": 112, "y": 62, "flags": 8},
+ {"x": 138, "y": 47, "flags": 8},
+ {"x": 0, "y": 0, "flags": 2},
+ {"x": 16, "y": 0, "flags": 2},
+ {"x": 32, "y": 0, "flags": 2},
+ {"x": 48, "y": 0, "flags": 2},
+ {"x": 64, "y": 0, "flags": 2},
+ {"x": 80, "y": 0, "flags": 2},
+ {"x": 96, "y": 0, "flags": 2},
+ {"x": 112, "y": 0, "flags": 2},
+ {"x": 128, "y": 0, "flags": 2},
+ {"x": 144, "y": 0, "flags": 2},
+ {"x": 160, "y": 0, "flags": 2},
+ {"x": 176, "y": 0, "flags": 2},
+ {"x": 192, "y": 0, "flags": 2},
+ {"x": 208, "y": 0, "flags": 2},
+ {"x": 208, "y": 16, "flags": 2},
+ {"x": 208, "y": 32, "flags": 2},
+ {"x": 208, "y": 48, "flags": 2},
+ {"x": 208, "y": 64, "flags": 2},
+ {"x": 192, "y": 64, "flags": 2},
+ {"x": 176, "y": 64, "flags": 2},
+ {"x": 160, "y": 64, "flags": 2},
+ {"x": 144, "y": 64, "flags": 2},
+ {"x": 128, "y": 64, "flags": 2},
+ {"x": 112, "y": 64, "flags": 2},
+ {"x": 96, "y": 64, "flags": 2},
+ {"x": 80, "y": 64, "flags": 2},
+ {"x": 64, "y": 64, "flags": 2},
+ {"x": 48, "y": 64, "flags": 2},
+ {"x": 32, "y": 64, "flags": 2},
+ {"x": 16, "y": 64, "flags": 2},
+ {"x": 0, "y": 64, "flags": 2},
+ {"x": 0, "y": 48, "flags": 2},
+ {"x": 0, "y": 32, "flags": 2},
+ {"x": 0, "y": 16, "flags": 2}
+ ]
+ },
+ "url": "https://github.com/zykrah/fuyu",
+ "ws2812": {
+ "driver": "vendor",
+ "pin": "GP3"
+ },
+ "layouts": {
+ "LAYOUT_all": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [0, 2], "x": 2, "y": 0},
+ {"matrix": [0, 3], "x": 3, "y": 0},
+ {"matrix": [0, 4], "x": 4, "y": 0},
+ {"matrix": [0, 5], "x": 5, "y": 0},
+ {"matrix": [0, 6], "x": 6.5, "y": 0},
+ {"matrix": [0, 7], "x": 7.5, "y": 0},
+ {"matrix": [0, 8], "x": 8.5, "y": 0},
+ {"matrix": [0, 9], "x": 9.5, "y": 0},
+ {"matrix": [0, 10], "x": 11, "y": 0},
+ {"matrix": [0, 11], "x": 12, "y": 0},
+ {"matrix": [0, 12], "x": 13, "y": 0},
+ {"matrix": [0, 13], "x": 14, "y": 0},
+ {"matrix": [0, 14], "x": 15.25, "y": 0},
+ {"matrix": [0, 15], "x": 16.25, "y": 0},
+ {"matrix": [0, 16], "x": 17.25, "y": 0},
+ {"matrix": [1, 0], "x": 0, "y": 1.25},
+ {"matrix": [1, 1], "x": 1, "y": 1.25},
+ {"matrix": [1, 2], "x": 2, "y": 1.25},
+ {"matrix": [1, 3], "x": 3, "y": 1.25},
+ {"matrix": [1, 4], "x": 4, "y": 1.25},
+ {"matrix": [1, 5], "x": 5, "y": 1.25},
+ {"matrix": [1, 6], "x": 6, "y": 1.25},
+ {"matrix": [1, 7], "x": 7, "y": 1.25},
+ {"matrix": [1, 8], "x": 8, "y": 1.25},
+ {"matrix": [1, 9], "x": 9, "y": 1.25},
+ {"matrix": [1, 10], "x": 10, "y": 1.25},
+ {"matrix": [1, 11], "x": 11, "y": 1.25},
+ {"matrix": [1, 12], "x": 12, "y": 1.25},
+ {"matrix": [1, 13], "x": 13, "y": 1.25},
+ {"matrix": [3, 13], "x": 14, "y": 1.25},
+ {"matrix": [1, 14], "x": 15.25, "y": 1.25},
+ {"matrix": [1, 15], "x": 16.25, "y": 1.25},
+ {"matrix": [1, 16], "x": 17.25, "y": 1.25},
+ {"matrix": [2, 0], "x": 0, "y": 2.25, "w": 1.5},
+ {"matrix": [2, 1], "x": 1.5, "y": 2.25},
+ {"matrix": [2, 2], "x": 2.5, "y": 2.25},
+ {"matrix": [2, 3], "x": 3.5, "y": 2.25},
+ {"matrix": [2, 4], "x": 4.5, "y": 2.25},
+ {"matrix": [2, 5], "x": 5.5, "y": 2.25},
+ {"matrix": [2, 6], "x": 6.5, "y": 2.25},
+ {"matrix": [2, 7], "x": 7.5, "y": 2.25},
+ {"matrix": [2, 8], "x": 8.5, "y": 2.25},
+ {"matrix": [2, 9], "x": 9.5, "y": 2.25},
+ {"matrix": [2, 10], "x": 10.5, "y": 2.25},
+ {"matrix": [2, 11], "x": 11.5, "y": 2.25},
+ {"matrix": [2, 12], "x": 12.5, "y": 2.25},
+ {"matrix": [2, 13], "x": 13.5, "y": 2.25, "w": 1.5},
+ {"matrix": [2, 14], "x": 15.25, "y": 2.25},
+ {"matrix": [2, 15], "x": 16.25, "y": 2.25},
+ {"matrix": [2, 16], "x": 17.25, "y": 2.25},
+ {"matrix": [3, 0], "x": 0, "y": 3.25, "w": 1.75},
+ {"matrix": [3, 1], "x": 1.75, "y": 3.25},
+ {"matrix": [3, 2], "x": 2.75, "y": 3.25},
+ {"matrix": [3, 3], "x": 3.75, "y": 3.25},
+ {"matrix": [3, 4], "x": 4.75, "y": 3.25},
+ {"matrix": [3, 5], "x": 5.75, "y": 3.25},
+ {"matrix": [3, 6], "x": 6.75, "y": 3.25},
+ {"matrix": [3, 7], "x": 7.75, "y": 3.25},
+ {"matrix": [3, 8], "x": 8.75, "y": 3.25},
+ {"matrix": [3, 9], "x": 9.75, "y": 3.25},
+ {"matrix": [3, 10], "x": 10.75, "y": 3.25},
+ {"matrix": [3, 11], "x": 11.75, "y": 3.25},
+ {"matrix": [3, 12], "x": 12.75, "y": 3.25, "w": 2.25},
+ {"matrix": [3, 14], "x": 15.25, "y": 3.25},
+ {"matrix": [3, 15], "x": 16.25, "y": 3.25},
+ {"matrix": [3, 16], "x": 17.25, "y": 3.25},
+ {"matrix": [4, 0], "x": 0, "y": 4.25, "w": 2.25},
+ {"matrix": [4, 2], "x": 2.25, "y": 4.25},
+ {"matrix": [4, 3], "x": 3.25, "y": 4.25},
+ {"matrix": [4, 4], "x": 4.25, "y": 4.25},
+ {"matrix": [4, 5], "x": 5.25, "y": 4.25},
+ {"matrix": [4, 6], "x": 6.25, "y": 4.25},
+ {"matrix": [4, 7], "x": 7.25, "y": 4.25},
+ {"matrix": [4, 8], "x": 8.25, "y": 4.25},
+ {"matrix": [4, 9], "x": 9.25, "y": 4.25},
+ {"matrix": [4, 10], "x": 10.25, "y": 4.25},
+ {"matrix": [4, 11], "x": 11.25, "y": 4.25},
+ {"matrix": [4, 12], "x": 12.25, "y": 4.25, "w": 1.75},
+ {"matrix": [4, 13], "x": 14, "y": 4.25},
+ {"matrix": [4, 14], "x": 15.25, "y": 4.25},
+ {"matrix": [4, 15], "x": 16.25, "y": 4.25},
+ {"matrix": [4, 16], "x": 17.25, "y": 4.25},
+ {"matrix": [5, 0], "x": 0, "y": 5.25, "w": 1.25},
+ {"matrix": [5, 1], "x": 1.25, "y": 5.25, "w": 1.25},
+ {"matrix": [5, 2], "x": 2.5, "y": 5.25, "w": 1.25},
+ {"matrix": [5, 6], "x": 3.75, "y": 5.25, "w": 6.25},
+ {"matrix": [5, 10], "x": 10, "y": 5.25, "w": 1.25},
+ {"matrix": [5, 11], "x": 11.25, "y": 5.25, "w": 1.25},
+ {"matrix": [5, 12], "x": 12.5, "y": 5.25, "w": 1.25},
+ {"matrix": [5, 13], "x": 13.75, "y": 5.25, "w": 1.25},
+ {"matrix": [5, 14], "x": 15.25, "y": 5.25},
+ {"matrix": [5, 15], "x": 16.25, "y": 5.25},
+ {"matrix": [5, 16], "x": 17.25, "y": 5.25}
+ ]
+ },
+ "LAYOUT_tkl_ansi_numpad": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [0, 2], "x": 2, "y": 0},
+ {"matrix": [0, 3], "x": 3, "y": 0},
+ {"matrix": [0, 4], "x": 4, "y": 0},
+ {"matrix": [0, 5], "x": 5, "y": 0},
+ {"matrix": [0, 6], "x": 6.5, "y": 0},
+ {"matrix": [0, 7], "x": 7.5, "y": 0},
+ {"matrix": [0, 8], "x": 8.5, "y": 0},
+ {"matrix": [0, 9], "x": 9.5, "y": 0},
+ {"matrix": [0, 10], "x": 11, "y": 0},
+ {"matrix": [0, 11], "x": 12, "y": 0},
+ {"matrix": [0, 12], "x": 13, "y": 0},
+ {"matrix": [0, 13], "x": 14, "y": 0},
+ {"matrix": [0, 14], "x": 15.25, "y": 0},
+ {"matrix": [0, 15], "x": 16.25, "y": 0},
+ {"matrix": [0, 16], "x": 17.25, "y": 0},
+ {"matrix": [1, 0], "x": 0, "y": 1.25},
+ {"matrix": [1, 1], "x": 1, "y": 1.25},
+ {"matrix": [1, 2], "x": 2, "y": 1.25},
+ {"matrix": [1, 3], "x": 3, "y": 1.25},
+ {"matrix": [1, 4], "x": 4, "y": 1.25},
+ {"matrix": [1, 5], "x": 5, "y": 1.25},
+ {"matrix": [1, 6], "x": 6, "y": 1.25},
+ {"matrix": [1, 7], "x": 7, "y": 1.25},
+ {"matrix": [1, 8], "x": 8, "y": 1.25},
+ {"matrix": [1, 9], "x": 9, "y": 1.25},
+ {"matrix": [1, 10], "x": 10, "y": 1.25},
+ {"matrix": [1, 11], "x": 11, "y": 1.25},
+ {"matrix": [1, 12], "x": 12, "y": 1.25},
+ {"matrix": [1, 13], "x": 13, "y": 1.25, "w": 2},
+ {"matrix": [1, 14], "x": 15.25, "y": 1.25},
+ {"matrix": [1, 15], "x": 16.25, "y": 1.25},
+ {"matrix": [1, 16], "x": 17.25, "y": 1.25},
+ {"matrix": [2, 0], "x": 0, "y": 2.25, "w": 1.5},
+ {"matrix": [2, 1], "x": 1.5, "y": 2.25},
+ {"matrix": [2, 2], "x": 2.5, "y": 2.25},
+ {"matrix": [2, 3], "x": 3.5, "y": 2.25},
+ {"matrix": [2, 4], "x": 4.5, "y": 2.25},
+ {"matrix": [2, 5], "x": 5.5, "y": 2.25},
+ {"matrix": [2, 6], "x": 6.5, "y": 2.25},
+ {"matrix": [2, 7], "x": 7.5, "y": 2.25},
+ {"matrix": [2, 8], "x": 8.5, "y": 2.25},
+ {"matrix": [2, 9], "x": 9.5, "y": 2.25},
+ {"matrix": [2, 10], "x": 10.5, "y": 2.25},
+ {"matrix": [2, 11], "x": 11.5, "y": 2.25},
+ {"matrix": [2, 12], "x": 12.5, "y": 2.25},
+ {"matrix": [2, 13], "x": 13.5, "y": 2.25, "w": 1.5},
+ {"matrix": [2, 14], "x": 15.25, "y": 2.25},
+ {"matrix": [2, 15], "x": 16.25, "y": 2.25},
+ {"matrix": [2, 16], "x": 17.25, "y": 2.25},
+ {"matrix": [3, 0], "x": 0, "y": 3.25, "w": 1.75},
+ {"matrix": [3, 1], "x": 1.75, "y": 3.25},
+ {"matrix": [3, 2], "x": 2.75, "y": 3.25},
+ {"matrix": [3, 3], "x": 3.75, "y": 3.25},
+ {"matrix": [3, 4], "x": 4.75, "y": 3.25},
+ {"matrix": [3, 5], "x": 5.75, "y": 3.25},
+ {"matrix": [3, 6], "x": 6.75, "y": 3.25},
+ {"matrix": [3, 7], "x": 7.75, "y": 3.25},
+ {"matrix": [3, 8], "x": 8.75, "y": 3.25},
+ {"matrix": [3, 9], "x": 9.75, "y": 3.25},
+ {"matrix": [3, 10], "x": 10.75, "y": 3.25},
+ {"matrix": [3, 11], "x": 11.75, "y": 3.25},
+ {"matrix": [3, 12], "x": 12.75, "y": 3.25, "w": 2.25},
+ {"matrix": [3, 14], "x": 15.25, "y": 3.25},
+ {"matrix": [3, 15], "x": 16.25, "y": 3.25},
+ {"matrix": [3, 16], "x": 17.25, "y": 3.25},
+ {"matrix": [4, 0], "x": 0, "y": 4.25, "w": 2.25},
+ {"matrix": [4, 2], "x": 2.25, "y": 4.25},
+ {"matrix": [4, 3], "x": 3.25, "y": 4.25},
+ {"matrix": [4, 4], "x": 4.25, "y": 4.25},
+ {"matrix": [4, 5], "x": 5.25, "y": 4.25},
+ {"matrix": [4, 6], "x": 6.25, "y": 4.25},
+ {"matrix": [4, 7], "x": 7.25, "y": 4.25},
+ {"matrix": [4, 8], "x": 8.25, "y": 4.25},
+ {"matrix": [4, 9], "x": 9.25, "y": 4.25},
+ {"matrix": [4, 10], "x": 10.25, "y": 4.25},
+ {"matrix": [4, 11], "x": 11.25, "y": 4.25},
+ {"matrix": [4, 12], "x": 12.25, "y": 4.25, "w": 2.75},
+ {"matrix": [4, 14], "x": 15.25, "y": 4.25},
+ {"matrix": [4, 15], "x": 16.25, "y": 4.25},
+ {"matrix": [4, 16], "x": 17.25, "y": 4.25},
+ {"matrix": [5, 0], "x": 0, "y": 5.25, "w": 1.25},
+ {"matrix": [5, 1], "x": 1.25, "y": 5.25, "w": 1.25},
+ {"matrix": [5, 2], "x": 2.5, "y": 5.25, "w": 1.25},
+ {"matrix": [5, 6], "x": 3.75, "y": 5.25, "w": 6.25},
+ {"matrix": [5, 10], "x": 10, "y": 5.25, "w": 1.25},
+ {"matrix": [5, 11], "x": 11.25, "y": 5.25, "w": 1.25},
+ {"matrix": [5, 12], "x": 12.5, "y": 5.25, "w": 1.25},
+ {"matrix": [5, 13], "x": 13.75, "y": 5.25, "w": 1.25},
+ {"matrix": [5, 14], "x": 15.25, "y": 5.25},
+ {"matrix": [5, 15], "x": 16.25, "y": 5.25},
+ {"matrix": [5, 16], "x": 17.25, "y": 5.25}
+ ]
+ },
+ "LAYOUT_tkl_ansi_tsangan_numpad": {
+ "layout": [
+ {"matrix": [0, 0], "x": 0, "y": 0},
+ {"matrix": [0, 2], "x": 2, "y": 0},
+ {"matrix": [0, 3], "x": 3, "y": 0},
+ {"matrix": [0, 4], "x": 4, "y": 0},
+ {"matrix": [0, 5], "x": 5, "y": 0},
+ {"matrix": [0, 6], "x": 6.5, "y": 0},
+ {"matrix": [0, 7], "x": 7.5, "y": 0},
+ {"matrix": [0, 8], "x": 8.5, "y": 0},
+ {"matrix": [0, 9], "x": 9.5, "y": 0},
+ {"matrix": [0, 10], "x": 11, "y": 0},
+ {"matrix": [0, 11], "x": 12, "y": 0},
+ {"matrix": [0, 12], "x": 13, "y": 0},
+ {"matrix": [0, 13], "x": 14, "y": 0},
+ {"matrix": [0, 14], "x": 15.25, "y": 0},
+ {"matrix": [0, 15], "x": 16.25, "y": 0},
+ {"matrix": [0, 16], "x": 17.25, "y": 0},
+ {"matrix": [1, 0], "x": 0, "y": 1.25},
+ {"matrix": [1, 1], "x": 1, "y": 1.25},
+ {"matrix": [1, 2], "x": 2, "y": 1.25},
+ {"matrix": [1, 3], "x": 3, "y": 1.25},
+ {"matrix": [1, 4], "x": 4, "y": 1.25},
+ {"matrix": [1, 5], "x": 5, "y": 1.25},
+ {"matrix": [1, 6], "x": 6, "y": 1.25},
+ {"matrix": [1, 7], "x": 7, "y": 1.25},
+ {"matrix": [1, 8], "x": 8, "y": 1.25},
+ {"matrix": [1, 9], "x": 9, "y": 1.25},
+ {"matrix": [1, 10], "x": 10, "y": 1.25},
+ {"matrix": [1, 11], "x": 11, "y": 1.25},
+ {"matrix": [1, 12], "x": 12, "y": 1.25},
+ {"matrix": [1, 13], "x": 13, "y": 1.25, "w": 2},
+ {"matrix": [1, 14], "x": 15.25, "y": 1.25},
+ {"matrix": [1, 15], "x": 16.25, "y": 1.25},
+ {"matrix": [1, 16], "x": 17.25, "y": 1.25},
+ {"matrix": [2, 0], "x": 0, "y": 2.25, "w": 1.5},
+ {"matrix": [2, 1], "x": 1.5, "y": 2.25},
+ {"matrix": [2, 2], "x": 2.5, "y": 2.25},
+ {"matrix": [2, 3], "x": 3.5, "y": 2.25},
+ {"matrix": [2, 4], "x": 4.5, "y": 2.25},
+ {"matrix": [2, 5], "x": 5.5, "y": 2.25},
+ {"matrix": [2, 6], "x": 6.5, "y": 2.25},
+ {"matrix": [2, 7], "x": 7.5, "y": 2.25},
+ {"matrix": [2, 8], "x": 8.5, "y": 2.25},
+ {"matrix": [2, 9], "x": 9.5, "y": 2.25},
+ {"matrix": [2, 10], "x": 10.5, "y": 2.25},
+ {"matrix": [2, 11], "x": 11.5, "y": 2.25},
+ {"matrix": [2, 12], "x": 12.5, "y": 2.25},
+ {"matrix": [2, 13], "x": 13.5, "y": 2.25, "w": 1.5},
+ {"matrix": [2, 14], "x": 15.25, "y": 2.25},
+ {"matrix": [2, 15], "x": 16.25, "y": 2.25},
+ {"matrix": [2, 16], "x": 17.25, "y": 2.25},
+ {"matrix": [3, 0], "x": 0, "y": 3.25, "w": 1.75},
+ {"matrix": [3, 1], "x": 1.75, "y": 3.25},
+ {"matrix": [3, 2], "x": 2.75, "y": 3.25},
+ {"matrix": [3, 3], "x": 3.75, "y": 3.25},
+ {"matrix": [3, 4], "x": 4.75, "y": 3.25},
+ {"matrix": [3, 5], "x": 5.75, "y": 3.25},
+ {"matrix": [3, 6], "x": 6.75, "y": 3.25},
+ {"matrix": [3, 7], "x": 7.75, "y": 3.25},
+ {"matrix": [3, 8], "x": 8.75, "y": 3.25},
+ {"matrix": [3, 9], "x": 9.75, "y": 3.25},
+ {"matrix": [3, 10], "x": 10.75, "y": 3.25},
+ {"matrix": [3, 11], "x": 11.75, "y": 3.25},
+ {"matrix": [3, 12], "x": 12.75, "y": 3.25, "w": 2.25},
+ {"matrix": [3, 14], "x": 15.25, "y": 3.25},
+ {"matrix": [3, 15], "x": 16.25, "y": 3.25},
+ {"matrix": [3, 16], "x": 17.25, "y": 3.25},
+ {"matrix": [4, 0], "x": 0, "y": 4.25, "w": 2.25},
+ {"matrix": [4, 2], "x": 2.25, "y": 4.25},
+ {"matrix": [4, 3], "x": 3.25, "y": 4.25},
+ {"matrix": [4, 4], "x": 4.25, "y": 4.25},
+ {"matrix": [4, 5], "x": 5.25, "y": 4.25},
+ {"matrix": [4, 6], "x": 6.25, "y": 4.25},
+ {"matrix": [4, 7], "x": 7.25, "y": 4.25},
+ {"matrix": [4, 8], "x": 8.25, "y": 4.25},
+ {"matrix": [4, 9], "x": 9.25, "y": 4.25},
+ {"matrix": [4, 10], "x": 10.25, "y": 4.25},
+ {"matrix": [4, 11], "x": 11.25, "y": 4.25},
+ {"matrix": [4, 12], "x": 12.25, "y": 4.25, "w": 2.75},
+ {"matrix": [4, 14], "x": 15.25, "y": 4.25},
+ {"matrix": [4, 15], "x": 16.25, "y": 4.25},
+ {"matrix": [4, 16], "x": 17.25, "y": 4.25},
+ {"matrix": [5, 0], "x": 0, "y": 5.25, "w": 1.5},
+ {"matrix": [5, 1], "x": 1.5, "y": 5.25},
+ {"matrix": [5, 2], "x": 2.5, "y": 5.25, "w": 1.5},
+ {"matrix": [5, 6], "x": 4, "y": 5.25, "w": 7},
+ {"matrix": [5, 11], "x": 11, "y": 5.25, "w": 1.5},
+ {"matrix": [5, 12], "x": 12.5, "y": 5.25},
+ {"matrix": [5, 13], "x": 13.5, "y": 5.25, "w": 1.5},
+ {"matrix": [5, 14], "x": 15.25, "y": 5.25},
+ {"matrix": [5, 15], "x": 16.25, "y": 5.25},
+ {"matrix": [5, 16], "x": 17.25, "y": 5.25}
+ ]
+ }
+ }
+}
diff --git a/keyboards/zykrah/fuyu_hs/keymaps/default/keymap.c b/keyboards/zykrah/fuyu_hs/keymaps/default/keymap.c
new file mode 100644
index 00000000000..e04c98a9fbb
--- /dev/null
+++ b/keyboards/zykrah/fuyu_hs/keymaps/default/keymap.c
@@ -0,0 +1,39 @@
+/*
+Copyright 2024 Zykrah
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+#include QMK_KEYBOARD_H
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+
+ [0] = LAYOUT_all(
+ KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_PSCR, KC_SCRL, KC_PAUS,
+ 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_EQL, KC_BSPC, KC_BSPC, KC_INS, KC_HOME, KC_PGUP,
+ KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_DEL, KC_END, KC_PGDN,
+ KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_TRNS, KC_TRNS, KC_UP, KC_TRNS,
+ KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, MO(1), KC_RGUI, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT),
+
+
+ [1] = LAYOUT_all(
+ QK_BOOT, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS),
+
+};
diff --git a/keyboards/zykrah/fuyu_hs/readme.md b/keyboards/zykrah/fuyu_hs/readme.md
new file mode 100644
index 00000000000..41c5cded51d
--- /dev/null
+++ b/keyboards/zykrah/fuyu_hs/readme.md
@@ -0,0 +1,27 @@
+# FUYU HOTSWAP
+
+
+
+An F12 TKL Hotswappable H87-Compat Type-C PCB for the Geon F1-8K
+
+* Keyboard Maintainer: [Zykrah](https://github.com/zykrah)
+* Hardware Supported: Fuyu HS 7u rev1, Fuyu HS 6.25u rev1
+* Hardware Availability: [Github Repo](https://github.com/zykrah/fuyu), [GEON Store](https://geon.works/products/fuyu-pcb-for-f1-8k), [Cafege](https://cafege.com.au/products/fuyu-8k-pcb)
+
+Make example for this keyboard (after setting up your build environment):
+
+ make zykrah/fuyu_hs:default
+
+Flashing example for this keyboard:
+
+ make zykrah/fuyu_hs:default:flash
+
+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).
+
+## Bootloader
+
+Enter the bootloader in 3 ways:
+
+* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (usually the top left key or Escape) and plug in the keyboard
+* **Physical reset button**: Briefly short the `RST` and `GND` pads on the SWD header twice, or short the `BOOT` header and plug in keyboard
+* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available
diff --git a/lib/python/qmk/cli/__init__.py b/lib/python/qmk/cli/__init__.py
index 0baf19a629d..2d63dfb4477 100644
--- a/lib/python/qmk/cli/__init__.py
+++ b/lib/python/qmk/cli/__init__.py
@@ -207,8 +207,8 @@ def _eprint(errmsg):
# Ubuntu 24.04: 3.12
# void: 3.12
-if sys.version_info[0] != 3 or sys.version_info[1] < 7:
- _eprint('Error: Your Python is too old! Please upgrade to Python 3.7 or later.')
+if sys.version_info[0] != 3 or sys.version_info[1] < 9:
+ _eprint('Error: Your Python is too old! Please upgrade to Python 3.9 or later.')
exit(127)
milc_version = __VERSION__.split('.')
diff --git a/lib/python/qmk/cli/doctor/check.py b/lib/python/qmk/cli/doctor/check.py
index d563811aba9..2804a1d7df1 100644
--- a/lib/python/qmk/cli/doctor/check.py
+++ b/lib/python/qmk/cli/doctor/check.py
@@ -4,6 +4,8 @@ from enum import Enum
import re
import shutil
from subprocess import DEVNULL, TimeoutExpired
+from tempfile import TemporaryDirectory
+from pathlib import Path
from milc import cli
from qmk import submodules
@@ -44,7 +46,35 @@ def _check_arm_gcc_version():
version_number = ESSENTIAL_BINARIES['arm-none-eabi-gcc']['output'].strip()
cli.log.info('Found arm-none-eabi-gcc version %s', version_number)
- return CheckStatus.OK # Right now all known arm versions are ok
+ # Right now all known ARM versions are ok, so check that it can produce binaries
+ return _check_arm_gcc_installation()
+
+
+def _check_arm_gcc_installation():
+ """Returns OK if the arm-none-eabi-gcc is fully installed and can produce binaries.
+ """
+ with TemporaryDirectory() as temp_dir:
+ temp_file = Path(temp_dir) / 'test.elf'
+
+ args = ['arm-none-eabi-gcc', '-mcpu=cortex-m0', '-mthumb', '-mno-thumb-interwork', '--specs=nosys.specs', '--specs=nano.specs', '-x', 'c', '-o', str(temp_file), '-']
+ result = cli.run(args, stdin=None, stdout=None, stderr=None, input='#include \nint main() { return __NEWLIB__ * __NEWLIB_MINOR__ * __NEWLIB_PATCHLEVEL__; }')
+ if result.returncode == 0:
+ cli.log.info('Successfully compiled using arm-none-eabi-gcc')
+ else:
+ cli.log.error(f'Failed to compile a simple program with arm-none-eabi-gcc, return code {result.returncode}')
+ cli.log.error(f'Command: {" ".join(args)}')
+ return CheckStatus.ERROR
+
+ args = ['arm-none-eabi-size', str(temp_file)]
+ result = cli.run(args, stdin=None, stdout=None, stderr=None)
+ if result.returncode == 0:
+ cli.log.info('Successfully tested arm-none-eabi-binutils using arm-none-eabi-size')
+ else:
+ cli.log.error(f'Failed to execute arm-none-eabi-size, perhaps corrupt arm-none-eabi-binutils, return code {result.returncode}')
+ cli.log.error(f'Command: {" ".join(args)}')
+ return CheckStatus.ERROR
+
+ return CheckStatus.OK
def _check_avr_gcc_version():
@@ -53,7 +83,35 @@ def _check_avr_gcc_version():
version_number = ESSENTIAL_BINARIES['avr-gcc']['output'].strip()
cli.log.info('Found avr-gcc version %s', version_number)
- return CheckStatus.OK
+ # Right now all known AVR versions are ok, so check that it can produce binaries
+ return _check_avr_gcc_installation()
+
+
+def _check_avr_gcc_installation():
+ """Returns OK if the avr-gcc is fully installed and can produce binaries.
+ """
+ with TemporaryDirectory() as temp_dir:
+ temp_file = Path(temp_dir) / 'test.elf'
+
+ args = ['avr-gcc', '-mmcu=atmega32u4', '-x', 'c', '-o', str(temp_file), '-']
+ result = cli.run(args, stdin=None, stdout=None, stderr=None, input='int main() { return 0; }')
+ if result.returncode == 0:
+ cli.log.info('Successfully compiled using avr-gcc')
+ else:
+ cli.log.error(f'Failed to compile a simple program with avr-gcc, return code {result.returncode}')
+ cli.log.error(f'Command: {" ".join(args)}')
+ return CheckStatus.ERROR
+
+ args = ['avr-size', str(temp_file)]
+ result = cli.run(args, stdin=None, stdout=None, stderr=None)
+ if result.returncode == 0:
+ cli.log.info('Successfully tested avr-binutils using avr-size')
+ else:
+ cli.log.error(f'Failed to execute avr-size, perhaps corrupt avr-binutils, return code {result.returncode}')
+ cli.log.error(f'Command: {" ".join(args)}')
+ return CheckStatus.ERROR
+
+ return CheckStatus.OK
def _check_avrdude_version():
diff --git a/lib/python/qmk/cli/find.py b/lib/python/qmk/cli/find.py
index bfed91e22cd..7d8b1b066c9 100644
--- a/lib/python/qmk/cli/find.py
+++ b/lib/python/qmk/cli/find.py
@@ -1,5 +1,6 @@
"""Command to search through all keyboards and keymaps for a given search criteria.
"""
+import os
from milc import cli
from qmk.search import filter_help, search_keymap_targets
from qmk.util import maybe_exit_config
@@ -20,6 +21,7 @@ from qmk.util import maybe_exit_config
def find(cli):
"""Search through all keyboards and keymaps for a given search criteria.
"""
+ os.environ.setdefault('SKIP_SCHEMA_VALIDATION', '1')
maybe_exit_config(should_exit=False, should_reraise=True)
targets = search_keymap_targets([('all', cli.config.find.keymap)], cli.args.filter)
diff --git a/lib/python/qmk/cli/mass_compile.py b/lib/python/qmk/cli/mass_compile.py
index cf9be0fd1e2..4c4669d4517 100755
--- a/lib/python/qmk/cli/mass_compile.py
+++ b/lib/python/qmk/cli/mass_compile.py
@@ -20,6 +20,8 @@ def mass_compile_targets(targets: List[BuildTarget], clean: bool, dry_run: bool,
if len(targets) == 0:
return
+ os.environ.setdefault('SKIP_SCHEMA_VALIDATION', '1')
+
make_cmd = find_make()
builddir = Path(QMK_FIRMWARE) / '.build'
makefile = builddir / 'parallel_kb_builds.mk'
diff --git a/lib/python/qmk/cli/new/keyboard.py b/lib/python/qmk/cli/new/keyboard.py
index b84b130f8ec..bd02acf9c84 100644
--- a/lib/python/qmk/cli/new/keyboard.py
+++ b/lib/python/qmk/cli/new/keyboard.py
@@ -8,7 +8,7 @@ from pathlib import Path
from dotty_dict import dotty
from milc import cli
-from milc.questions import choice, question
+from milc.questions import choice, question, yesno
from qmk.git import git_get_username
from qmk.json_schema import load_jsonschema
@@ -131,60 +131,70 @@ def _question(*args, **kwargs):
return ret
-def prompt_keyboard():
- prompt = """{fg_yellow}Name Your Keyboard Project{style_reset_all}
-For more infomation, see:
-https://docs.qmk.fm/hardware_keyboard_guidelines#naming-your-keyboard-project
+def prompt_heading_subheading(heading, subheading):
+ cli.log.info(f"{{fg_yellow}}{heading}{{style_reset_all}}")
+ cli.log.info(subheading)
-Keyboard Name? """
+
+def prompt_keyboard():
+ prompt_heading_subheading("Name Your Keyboard Project", """For more information, see:
+https://docs.qmk.fm/hardware_keyboard_guidelines#naming-your-keyboard-project""")
errmsg = 'Keyboard already exists! Please choose a different name:'
- return _question(prompt, reprompt=errmsg, validate=lambda x: not keyboard(x).exists())
+ return _question("Keyboard Name?", reprompt=errmsg, validate=lambda x: not keyboard(x).exists())
def prompt_user():
- prompt = """
-{fg_yellow}Attribution{style_reset_all}
-Used for maintainer, copyright, etc
+ prompt_heading_subheading("Attribution", "Used for maintainer, copyright, etc.")
-Your GitHub Username? """
- return question(prompt, default=git_get_username())
+ return question("Your GitHub Username?", default=git_get_username())
def prompt_name(def_name):
- prompt = """
-{fg_yellow}More Attribution{style_reset_all}
-Used for maintainer, copyright, etc
+ prompt_heading_subheading("More Attribution", "Used for maintainer, copyright, etc.")
-Your Real Name? """
- return question(prompt, default=def_name)
+ return question("Your Real Name?", default=def_name)
def prompt_layout():
- prompt = """
-{fg_yellow}Pick Base Layout{style_reset_all}
-As a starting point, one of the common layouts can be used to bootstrap the process
+ prompt_heading_subheading("Pick Base Layout", """As a starting point, one of the common layouts can be used to
+bootstrap the process""")
-Default Layout? """
# avoid overwhelming user - remove some?
filtered_layouts = [x for x in available_layouts if not any(xs in x for xs in ['_split', '_blocker', '_tsangan', '_f13'])]
filtered_layouts.append("none of the above")
- return choice(prompt, filtered_layouts, default=len(filtered_layouts) - 1)
+ return choice("Default Layout?", filtered_layouts, default=len(filtered_layouts) - 1)
+
+
+def prompt_mcu_type():
+ prompt_heading_subheading(
+ "What Powers Your Project", """Is your board using a separate development board, such as a Pro Micro,
+or is the microcontroller integrated onto the PCB?
+
+For more information, see:
+https://docs.qmk.fm/compatible_microcontrollers"""
+ )
+
+ return yesno("Using a Development Board?")
+
+
+def prompt_dev_board():
+ prompt_heading_subheading("Select Development Board", """For more information, see:
+https://docs.qmk.fm/compatible_microcontrollers""")
+
+ return choice("Development Board?", dev_boards, default=dev_boards.index("promicro"))
def prompt_mcu():
- prompt = """
-{fg_yellow}What Powers Your Project{style_reset_all}
-For more infomation, see:
-https://docs.qmk.fm/#/compatible_microcontrollers
+ prompt_heading_subheading("Select Microcontroller", """For more information, see:
+https://docs.qmk.fm/compatible_microcontrollers""")
-MCU? """
# remove any options strictly used for compatibility
- filtered_mcu = [x for x in (dev_boards + mcu_types) if not any(xs in x for xs in ['cortex', 'unknown'])]
+ filtered_mcu = [x for x in mcu_types if not any(xs in x for xs in ['cortex', 'unknown'])]
- return choice(prompt, filtered_mcu, default=filtered_mcu.index("atmega32u4"))
+ return choice("Microcontroller?", filtered_mcu, default=filtered_mcu.index("atmega32u4"))
@cli.argument('-kb', '--keyboard', help='Specify the name for the new keyboard directory', arg_only=True, type=keyboard_name)
@@ -211,7 +221,11 @@ def new_keyboard(cli):
user_name = cli.config.new_keyboard.name if cli.config.new_keyboard.name else prompt_user()
real_name = cli.args.realname or cli.config.new_keyboard.name if cli.args.realname or cli.config.new_keyboard.name else prompt_name(user_name)
default_layout = cli.args.layout if cli.args.layout else prompt_layout()
- mcu = cli.args.type if cli.args.type else prompt_mcu()
+
+ if cli.args.type:
+ mcu = cli.args.type
+ else:
+ mcu = prompt_dev_board() if prompt_mcu_type() else prompt_mcu()
config = {}
if mcu in dev_boards:
diff --git a/lib/python/qmk/cli/new/keymap.py b/lib/python/qmk/cli/new/keymap.py
index d4339bc9ef0..f1df05636ce 100755
--- a/lib/python/qmk/cli/new/keymap.py
+++ b/lib/python/qmk/cli/new/keymap.py
@@ -1,5 +1,6 @@
"""This script automates the copying of the default keymap into your own keymap.
"""
+import re
import shutil
from milc import cli
@@ -13,6 +14,13 @@ from qmk.keyboard import keyboard_completer, keyboard_folder
from qmk.userspace import UserspaceDefs
+def validate_keymap_name(name):
+ """Returns True if the given keymap name contains only a-z, 0-9 and underscore characters.
+ """
+ regex = re.compile(r'^[a-zA-Z0-9][a-zA-Z0-9_]+$')
+ return bool(regex.match(name))
+
+
def prompt_keyboard():
prompt = """{fg_yellow}Select Keyboard{style_reset_all}
If you`re unsure you can view a full list of supported keyboards with {fg_yellow}qmk list-keyboards{style_reset_all}.
@@ -60,6 +68,10 @@ def new_keymap(cli):
cli.log.error(f'Default keymap {{fg_cyan}}{keymap_path_default}{{fg_reset}} does not exist!')
return False
+ if not validate_keymap_name(user_name):
+ cli.log.error('Keymap names must contain only {fg_cyan}a-z{fg_reset}, {fg_cyan}0-9{fg_reset} and {fg_cyan}_{fg_reset}! Please choose a different name.')
+ return False
+
if keymap_path_new.exists():
cli.log.error(f'Keymap {{fg_cyan}}{user_name}{{fg_reset}} already exists! Please choose a different name.')
return False
diff --git a/lib/python/qmk/cli/painter/convert_graphics.py b/lib/python/qmk/cli/painter/convert_graphics.py
index 553c26aa5d5..f74d655fd57 100644
--- a/lib/python/qmk/cli/painter/convert_graphics.py
+++ b/lib/python/qmk/cli/painter/convert_graphics.py
@@ -60,9 +60,7 @@ def painter_convert_graphics(cli):
return
# Work out the text substitutions for rendering the output data
- args_str = " ".join((f"--{arg} {getattr(cli.args, arg.replace('-', '_'))}" for arg in ["input", "output", "format", "no-rle", "no-deltas"]))
- command = f"qmk painter-convert-graphics {args_str}"
- subs = generate_subs(cli, out_bytes, image_metadata=metadata, command=command)
+ subs = generate_subs(cli, out_bytes, image_metadata=metadata, command_name="painter_convert_graphics")
# Render and write the header file
header_text = render_header(subs)
diff --git a/lib/python/qmk/cli/painter/make_font.py b/lib/python/qmk/cli/painter/make_font.py
index 19db8449316..3e18fd74a56 100644
--- a/lib/python/qmk/cli/painter/make_font.py
+++ b/lib/python/qmk/cli/painter/make_font.py
@@ -61,10 +61,8 @@ def painter_convert_font_image(cli):
return
# Work out the text substitutions for rendering the output data
- args_str = " ".join((f"--{arg} {getattr(cli.args, arg.replace('-', '_'))}" for arg in ["input", "output", "no-ascii", "unicode-glyphs", "format", "no-rle"]))
- command = f"qmk painter-convert-font-image {args_str}"
metadata = {"glyphs": _generate_font_glyphs_list(not cli.args.no_ascii, cli.args.unicode_glyphs)}
- subs = generate_subs(cli, out_bytes, font_metadata=metadata, command=command)
+ subs = generate_subs(cli, out_bytes, font_metadata=metadata, command_name="painter_convert_font_image")
# Render and write the header file
header_text = render_header(subs)
diff --git a/lib/python/qmk/cli/via2json.py b/lib/python/qmk/cli/via2json.py
index 73c9a61b3d3..537e1026406 100755
--- a/lib/python/qmk/cli/via2json.py
+++ b/lib/python/qmk/cli/via2json.py
@@ -29,6 +29,7 @@ def _convert_macros(via_macros):
if len(via_macros) == 0:
return list()
split_regex = re.compile(r'(}\,)|(\,{)')
+ macro_group_regex = re.compile(r'({.+?})')
macros = list()
for via_macro in via_macros:
# Split VIA macro to its elements
@@ -38,13 +39,28 @@ def _convert_macros(via_macros):
macro_data = list()
for m in macro:
if '{' in m or '}' in m:
- # Found keycode(s)
- keycodes = m.split(',')
- # Remove whitespaces and curly braces from around keycodes
- keycodes = list(map(lambda s: s.strip(' {}'), keycodes))
- # Remove the KC prefix
- keycodes = list(map(lambda s: s.replace('KC_', ''), keycodes))
- macro_data.append({"action": "tap", "keycodes": keycodes})
+ # Split macro groups
+ macro_groups = macro_group_regex.findall(m)
+ for macro_group in macro_groups:
+ # Remove whitespaces and curly braces from around group
+ macro_group = macro_group.strip(' {}')
+
+ macro_action = 'tap'
+ macro_keycodes = []
+
+ if macro_group[0] == '+':
+ macro_action = 'down'
+ macro_keycodes.append(macro_group[1:])
+ elif macro_group[0] == '-':
+ macro_action = 'up'
+ macro_keycodes.append(macro_group[1:])
+ else:
+ macro_keycodes.extend(macro_group.split(',') if ',' in macro_group else [macro_group])
+
+ # Remove the KC prefixes
+ macro_keycodes = list(map(lambda s: s.replace('KC_', ''), macro_keycodes))
+
+ macro_data.append({"action": macro_action, "keycodes": macro_keycodes})
else:
# Found text
macro_data.append(m)
@@ -54,13 +70,13 @@ def _convert_macros(via_macros):
def _fix_macro_keys(keymap_data):
- macro_no = re.compile(r'MACRO0?([0-9]{1,2})')
+ macro_no = re.compile(r'MACRO0?\(([0-9]{1,2})\)')
for i in range(0, len(keymap_data)):
for j in range(0, len(keymap_data[i])):
kc = keymap_data[i][j]
m = macro_no.match(kc)
if m:
- keymap_data[i][j] = f'MACRO_{m.group(1)}'
+ keymap_data[i][j] = f'MC_{m.group(1)}'
return keymap_data
diff --git a/lib/python/qmk/constants.py b/lib/python/qmk/constants.py
index b6f46180b29..e055d3fbc95 100644
--- a/lib/python/qmk/constants.py
+++ b/lib/python/qmk/constants.py
@@ -22,7 +22,7 @@ QMK_FIRMWARE_UPSTREAM = 'qmk/qmk_firmware'
MAX_KEYBOARD_SUBFOLDERS = 5
# Supported processor types
-CHIBIOS_PROCESSORS = 'cortex-m0', 'cortex-m0plus', 'cortex-m3', 'cortex-m4', 'MKL26Z64', 'MK20DX128', 'MK20DX256', 'MK64FX512', 'MK66FX1M0', 'RP2040', 'STM32F042', 'STM32F072', 'STM32F103', 'STM32F303', 'STM32F401', 'STM32F405', 'STM32F407', 'STM32F411', 'STM32F446', 'STM32G431', 'STM32G474', 'STM32H723', 'STM32H733', 'STM32L412', 'STM32L422', 'STM32L432', 'STM32L433', 'STM32L442', 'STM32L443', 'GD32VF103', 'WB32F3G71', 'WB32FQ95'
+CHIBIOS_PROCESSORS = 'cortex-m0', 'cortex-m0plus', 'cortex-m3', 'cortex-m4', 'MKL26Z64', 'MK20DX128', 'MK20DX256', 'MK64FX512', 'MK66FX1M0', 'RP2040', 'STM32F042', 'STM32F072', 'STM32F103', 'STM32F303', 'STM32F401', 'STM32F405', 'STM32F407', 'STM32F411', 'STM32F446', 'STM32G431', 'STM32G474', 'STM32H723', 'STM32H733', 'STM32L412', 'STM32L422', 'STM32L432', 'STM32L433', 'STM32L442', 'STM32L443', 'GD32VF103', 'WB32F3G71', 'WB32FQ95', 'AT32F415'
LUFA_PROCESSORS = 'at90usb162', 'atmega16u2', 'atmega32u2', 'atmega16u4', 'atmega32u4', 'at90usb646', 'at90usb647', 'at90usb1286', 'at90usb1287', None
VUSB_PROCESSORS = 'atmega32a', 'atmega328p', 'atmega328', 'attiny85'
@@ -55,6 +55,7 @@ MCU2BOOTLOADER = {
"GD32VF103": "gd32v-dfu",
"WB32F3G71": "wb32-dfu",
"WB32FQ95": "wb32-dfu",
+ "AT32F415": "at32-dfu",
"atmega16u2": "atmel-dfu",
"atmega32u2": "atmel-dfu",
"atmega16u4": "atmel-dfu",
@@ -93,6 +94,7 @@ BOOTLOADER_VIDS_PIDS = {
'apm32-dfu': {("314b", "0106")},
'gd32v-dfu': {("28e9", "0189")},
'wb32-dfu': {("342d", "dfa0")},
+ 'at32-dfu': {("2e3c", "df11")},
'bootloadhid': {("16c0", "05df")},
'usbasploader': {("16c0", "05dc")},
'usbtinyisp': {("1782", "0c9f")},
diff --git a/lib/python/qmk/decorators.py b/lib/python/qmk/decorators.py
index f6270990b97..16b44d6d591 100644
--- a/lib/python/qmk/decorators.py
+++ b/lib/python/qmk/decorators.py
@@ -9,6 +9,15 @@ from qmk.keyboard import find_keyboard_from_dir
from qmk.keymap import find_keymap_from_dir
+def _get_subcommand_name():
+ """Handle missing cli.subcommand_name on older versions of milc
+ """
+ try:
+ return cli.subcommand_name
+ except AttributeError:
+ return cli._subcommand.__name__
+
+
def automagic_keyboard(func):
"""Sets `cli.config..keyboard` based on environment.
@@ -16,13 +25,15 @@ def automagic_keyboard(func):
"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
+ cmd = _get_subcommand_name()
+
# Ensure that `--keyboard` was not passed and CWD is under `qmk_firmware/keyboards`
- if cli.config_source[cli._subcommand.__name__]['keyboard'] != 'argument':
+ if cli.config_source[cmd]['keyboard'] != 'argument':
keyboard = find_keyboard_from_dir()
if keyboard:
- cli.config[cli._subcommand.__name__]['keyboard'] = keyboard
- cli.config_source[cli._subcommand.__name__]['keyboard'] = 'keyboard_directory'
+ cli.config[cmd]['keyboard'] = keyboard
+ cli.config_source[cmd]['keyboard'] = 'keyboard_directory'
return func(*args, **kwargs)
@@ -36,13 +47,15 @@ def automagic_keymap(func):
"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
+ cmd = _get_subcommand_name()
+
# Ensure that `--keymap` was not passed and that we're under `qmk_firmware`
- if cli.config_source[cli._subcommand.__name__]['keymap'] != 'argument':
+ if cli.config_source[cmd]['keymap'] != 'argument':
keymap_name, keymap_type = find_keymap_from_dir()
if keymap_name:
- cli.config[cli._subcommand.__name__]['keymap'] = keymap_name
- cli.config_source[cli._subcommand.__name__]['keymap'] = keymap_type
+ cli.config[cmd]['keymap'] = keymap_name
+ cli.config_source[cmd]['keymap'] = keymap_type
return func(*args, **kwargs)
diff --git a/lib/python/qmk/info.py b/lib/python/qmk/info.py
index 0c6dd181d9b..5dae353538a 100644
--- a/lib/python/qmk/info.py
+++ b/lib/python/qmk/info.py
@@ -1,6 +1,7 @@
"""Functions that help us generate and use info.json files.
"""
import re
+import os
from pathlib import Path
import jsonschema
from dotty_dict import dotty
@@ -14,7 +15,7 @@ from qmk.keyboard import config_h, rules_mk
from qmk.commands import parse_configurator_json
from qmk.makefile import parse_rules_mk_file
from qmk.math import compute
-from qmk.util import maybe_exit
+from qmk.util import maybe_exit, truthy
true_values = ['1', 'on', 'yes']
false_values = ['0', 'off', 'no']
@@ -262,7 +263,9 @@ def info_json(keyboard, force_layout=None):
info_data["community_layouts"] = [force_layout]
# Validate
- _validate(keyboard, info_data)
+ # Skip processing if necessary
+ if not truthy(os.environ.get('SKIP_SCHEMA_VALIDATION'), False):
+ _validate(keyboard, info_data)
# Check that the reported matrix size is consistent with the actual matrix size
_check_matrix(info_data)
@@ -941,13 +944,14 @@ def merge_info_jsons(keyboard, info_data):
_log_error(info_data, "Invalid file %s, root object should be a dictionary." % (str(info_file),))
continue
- try:
- validate(new_info_data, 'qmk.keyboard.v1')
- except jsonschema.ValidationError as e:
- json_path = '.'.join([str(p) for p in e.absolute_path])
- cli.log.error('Not including data from file: %s', info_file)
- cli.log.error('\t%s: %s', json_path, e.message)
- continue
+ if not truthy(os.environ.get('SKIP_SCHEMA_VALIDATION'), False):
+ try:
+ validate(new_info_data, 'qmk.keyboard.v1')
+ except jsonschema.ValidationError as e:
+ json_path = '.'.join([str(p) for p in e.absolute_path])
+ cli.log.error('Not including data from file: %s', info_file)
+ cli.log.error('\t%s: %s', json_path, e.message)
+ continue
# Merge layout data in
if 'layout_aliases' in new_info_data:
diff --git a/lib/python/qmk/painter.py b/lib/python/qmk/painter.py
index 512a486ce87..ed0372c163e 100644
--- a/lib/python/qmk/painter.py
+++ b/lib/python/qmk/painter.py
@@ -3,6 +3,7 @@
import datetime
import math
import re
+from pathlib import Path
from string import Template
from PIL import Image, ImageOps
@@ -137,10 +138,31 @@ def _render_image_metadata(metadata):
return "\n".join(lines)
-def generate_subs(cli, out_bytes, *, font_metadata=None, image_metadata=None, command):
+def command_args_str(cli, command_name):
+ """Given a command name, introspect milc to get the arguments passed in."""
+
+ args = {}
+ max_length = 0
+ for arg_name, was_passed in cli.args_passed[command_name].items():
+ max_length = max(max_length, len(arg_name))
+
+ val = getattr(cli.args, arg_name.replace("-", "_"))
+
+ # do not leak full paths, keep just file name
+ if isinstance(val, Path):
+ val = val.name
+
+ args[arg_name] = val
+
+ return "\n".join(f"// {arg_name.ljust(max_length)} | {val}" for arg_name, val in args.items())
+
+
+def generate_subs(cli, out_bytes, *, font_metadata=None, image_metadata=None, command_name):
if font_metadata is not None and image_metadata is not None:
raise ValueError("Cant generate subs for font and image at the same time")
+ args = command_args_str(cli, command_name)
+
subs = {
"year": datetime.date.today().strftime("%Y"),
"input_file": cli.args.input.name,
@@ -148,7 +170,8 @@ def generate_subs(cli, out_bytes, *, font_metadata=None, image_metadata=None, co
"byte_count": len(out_bytes),
"bytes_lines": render_bytes(out_bytes),
"format": cli.args.format,
- "generator_command": command,
+ "generator_command": command_name.replace("_", "-"),
+ "command_args": args,
}
if font_metadata is not None:
@@ -167,7 +190,7 @@ def generate_subs(cli, out_bytes, *, font_metadata=None, image_metadata=None, co
subs.update({
"generated_type": "image",
"var_prefix": "gfx",
- "generator_command": command,
+ "generator_command": command_name,
"metadata": _render_image_metadata(image_metadata),
})
@@ -183,7 +206,8 @@ license_template = """\
// Copyright ${year} QMK -- generated source code only, ${generated_type} retains original copyright
// SPDX-License-Identifier: GPL-2.0-or-later
-// This file was auto-generated by `${generator_command}`
+// This file was auto-generated by `${generator_command}` with arguments:
+${command_args}
"""
diff --git a/lib/python/qmk/search.py b/lib/python/qmk/search.py
index 25e3d92066d..c7bce344ad1 100644
--- a/lib/python/qmk/search.py
+++ b/lib/python/qmk/search.py
@@ -119,8 +119,11 @@ def filter_help() -> str:
def _set_log_level(level):
cli.acquire_lock()
- old = cli.log_level
- cli.log_level = level
+ try:
+ old = cli.log_level
+ cli.log_level = level
+ except AttributeError:
+ old = cli.log.level
cli.log.setLevel(level)
logging.root.setLevel(level)
cli.release_lock()
@@ -236,11 +239,11 @@ def _filter_keymap_targets(target_list: List[KeyboardKeymapDesc], filters: List[
valid_targets = parallel_map(_load_keymap_info, target_list)
function_re = re.compile(r'^(?P[a-zA-Z]+)\((?P[a-zA-Z0-9_\.]+)(,\s*(?P[^#]+))?\)$')
- equals_re = re.compile(r'^(?P[a-zA-Z0-9_\.]+)\s*=\s*(?P[^#]+)$')
+ comparison_re = re.compile(r'^(?P[a-zA-Z0-9_\.]+)\s*(?P[\<\>\!=]=|\<|\>)\s*(?P[^#]+)$')
for filter_expr in filters:
function_match = function_re.match(filter_expr)
- equals_match = equals_re.match(filter_expr)
+ comparison_match = comparison_re.match(filter_expr)
if function_match is not None:
func_name = function_match.group('function').lower()
@@ -256,23 +259,43 @@ def _filter_keymap_targets(target_list: List[KeyboardKeymapDesc], filters: List[
value_str = f", {{fg_cyan}}{value}{{fg_reset}}" if value is not None else ""
cli.log.info(f'Filtering on condition: {{fg_green}}{func_name}{{fg_reset}}({{fg_cyan}}{key}{{fg_reset}}{value_str})...')
- elif equals_match is not None:
- key = equals_match.group('key')
- value = equals_match.group('value')
- cli.log.info(f'Filtering on condition: {{fg_cyan}}{key}{{fg_reset}} == {{fg_cyan}}{value}{{fg_reset}}...')
+ elif comparison_match is not None:
+ key = comparison_match.group('key')
+ op = comparison_match.group('op')
+ value = comparison_match.group('value')
+ cli.log.info(f'Filtering on condition: {{fg_cyan}}{key}{{fg_reset}} {op} {{fg_cyan}}{value}{{fg_reset}}...')
- def _make_filter(k, v):
+ def _make_filter(k, o, v):
expr = fnmatch.translate(v)
rule = re.compile(f'^{expr}$', re.IGNORECASE)
def f(e: KeyboardKeymapDesc):
lhs = e.dotty.get(k)
- lhs = str(False if lhs is None else lhs)
- return rule.search(lhs) is not None
+ rhs = v
+
+ if o in ['<', '>', '<=', '>=']:
+ lhs = int(False if lhs is None else lhs)
+ rhs = int(rhs)
+
+ if o == '<':
+ return lhs < rhs
+ elif o == '>':
+ return lhs > rhs
+ elif o == '<=':
+ return lhs <= rhs
+ elif o == '>=':
+ return lhs >= rhs
+ else:
+ lhs = str(False if lhs is None else lhs)
+
+ if o == '!=':
+ return rule.search(lhs) is None
+ elif o == '==':
+ return rule.search(lhs) is not None
return f
- valid_targets = filter(_make_filter(key, value), valid_targets)
+ valid_targets = filter(_make_filter(key, op, value), valid_targets)
else:
cli.log.warning(f'Unrecognized filter expression: {filter_expr}')
continue
diff --git a/lib/python/qmk/tests/test_cli_commands.py b/lib/python/qmk/tests/test_cli_commands.py
index f18bd12f820..b10fd8d19d5 100644
--- a/lib/python/qmk/tests/test_cli_commands.py
+++ b/lib/python/qmk/tests/test_cli_commands.py
@@ -390,7 +390,7 @@ def test_find_contains():
def test_find_multiple_conditions():
# this is intended to match at least 'crkbd/rev1'
result = check_subcommand(
- 'find', '-f', 'exists(rgb_matrix.split_count)', '-f', 'contains(matrix_pins.cols, B1)', '-f', 'length(matrix_pins.cols, 6)', '-f', 'absent(eeprom.driver)', '-f', 'ws2812.pin=D3', '-p', 'rgb_matrix.split_count', '-p', 'matrix_pins.cols', '-p',
+ 'find', '-f', 'exists(rgb_matrix.split_count)', '-f', 'contains(matrix_pins.cols, B1)', '-f', 'length(matrix_pins.cols, 6)', '-f', 'absent(eeprom.driver)', '-f', 'ws2812.pin == D3', '-p', 'rgb_matrix.split_count', '-p', 'matrix_pins.cols', '-p',
'eeprom.driver', '-p', 'ws2812.pin'
)
check_returncode(result)
diff --git a/lib/python/qmk/util.py b/lib/python/qmk/util.py
index b73fab89d12..8f99410e1de 100644
--- a/lib/python/qmk/util.py
+++ b/lib/python/qmk/util.py
@@ -27,6 +27,27 @@ def maybe_exit_config(should_exit: bool = True, should_reraise: bool = False):
maybe_exit_reraise = should_reraise
+def truthy(value, value_if_unknown=False):
+ """Returns True if the value is truthy, False otherwise.
+
+ Deals with:
+ True: 1, true, t, yes, y, on
+ False: 0, false, f, no, n, off
+ """
+ if value in {False, True}:
+ return bool(value)
+
+ test_value = str(value).strip().lower()
+
+ if test_value in {"1", "true", "t", "yes", "y", "on"}:
+ return True
+
+ if test_value in {"0", "false", "f", "no", "n", "off"}:
+ return False
+
+ return value_if_unknown
+
+
@contextlib.contextmanager
def parallelize():
"""Returns a function that can be used in place of a map() call.
diff --git a/platforms/avr/timer.c b/platforms/avr/timer.c
index 9fb671ae8d8..26ba0e29fa2 100644
--- a/platforms/avr/timer.c
+++ b/platforms/avr/timer.c
@@ -25,6 +25,7 @@ along with this program. If not, see .
// counter resolution 1ms
// NOTE: union { uint32_t timer32; struct { uint16_t dummy; uint16_t timer16; }}
volatile uint32_t timer_count;
+static uint32_t saved_ms;
/** \brief timer initialization
*
@@ -78,6 +79,24 @@ inline void timer_clear(void) {
}
}
+/** \brief timer save
+ *
+ * Set saved_ms to current time.
+ */
+void timer_save(void) {
+ saved_ms = timer_read32();
+}
+
+/** \brief timer restore
+ *
+ * Set timer_count to saved_ms
+ */
+void timer_restore(void) {
+ ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
+ timer_count = saved_ms;
+ }
+}
+
/** \brief timer read
*
* FIXME: needs doc
diff --git a/platforms/chibios/boards/GENERIC_AT32_F415XX/board/board.c b/platforms/chibios/boards/GENERIC_AT32_F415XX/board/board.c
new file mode 100644
index 00000000000..28cf7c18e01
--- /dev/null
+++ b/platforms/chibios/boards/GENERIC_AT32_F415XX/board/board.c
@@ -0,0 +1,101 @@
+/*
+ ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
+ ChibiOS - Copyright (C) 2023..2024 HorrorTroll
+ ChibiOS - Copyright (C) 2023..2024 Zhaqian
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#include "hal.h"
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/**
+ * @brief PAL setup.
+ * @details Digital I/O ports static configuration as defined in @p board.h.
+ * This variable is used by the HAL when initializing the PAL driver.
+ */
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+const PALConfig pal_default_config =
+{
+ {VAL_GPIOAODT, VAL_GPIOACFGLR, VAL_GPIOACFGHR},
+ {VAL_GPIOBODT, VAL_GPIOBCFGLR, VAL_GPIOBCFGHR},
+#if AT32_HAS_GPIOC
+ {VAL_GPIOCODT, VAL_GPIOCCFGLR, VAL_GPIOCCFGHR},
+#endif
+ {VAL_GPIODODT, VAL_GPIODCFGLR, VAL_GPIODCFGHR},
+#if AT32_HAS_GPIOF
+ {VAL_GPIOFODT, VAL_GPIOFCFGLR, VAL_GPIOFCFGHR},
+#endif
+};
+#endif
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Early initialization code.
+ * @details System clocks are initialized before everything else.
+ */
+void __early_init(void) {
+ at32_clock_init();
+}
+
+#if HAL_USE_SDC || defined(__DOXYGEN__)
+/**
+ * @brief SDC card detection.
+ */
+bool sdc_lld_is_card_inserted(SDCDriver *sdcp) {
+ static bool last_status = false;
+
+ if (blkIsTransferring(sdcp))
+ return last_status;
+ return last_status = (bool)palReadPad(GPIOC, GPIOC_PIN11);
+}
+
+/**
+ * @brief SDC card write protection detection.
+ */
+bool sdc_lld_is_write_protected(SDCDriver *sdcp) {
+
+ (void)sdcp;
+ return false;
+}
+#endif /* HAL_USE_SDC */
+
+/**
+ * @brief Board-specific initialization code.
+ * @note You can add your board-specific code here.
+ */
+void boardInit(void) {
+ IOMUX->REMAP |= IOMUX_REMAP_SWJTAG_MUX_JTAGDIS;
+}
diff --git a/platforms/chibios/boards/GENERIC_AT32_F415XX/board/board.h b/platforms/chibios/boards/GENERIC_AT32_F415XX/board/board.h
new file mode 100644
index 00000000000..c3ade198bae
--- /dev/null
+++ b/platforms/chibios/boards/GENERIC_AT32_F415XX/board/board.h
@@ -0,0 +1,207 @@
+/*
+ ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
+ ChibiOS - Copyright (C) 2023..2024 HorrorTroll
+ ChibiOS - Copyright (C) 2023..2024 Zhaqian
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef _BOARD_H_
+#define _BOARD_H_
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*
+ * Setup for a Generic AT32F415 board.
+ */
+
+/*
+ * Board identifier.
+ */
+#define BOARD_GENERIC_AT32_F415XX
+#define BOARD_NAME "GENERIC AT32F415 board"
+
+/*
+ * Board oscillators-related settings.
+ */
+#if !defined(AT32_LEXTCLK)
+#define AT32_LEXTCLK 32768
+#endif
+
+#if !defined(AT32_HEXTCLK)
+#define AT32_HEXTCLK 8000000
+#endif
+
+/*
+ * MCU type, supported types are defined in ./os/hal/platforms/hal_lld.h.
+ */
+#define AT32F415KB
+
+/*
+ * IO pins assignments.
+ */
+#define GPIOA_PIN0 0U
+#define GPIOA_PIN1 1U
+#define GPIOA_PIN2 2U
+#define GPIOA_PIN3 3U
+#define GPIOA_PIN4 4U
+#define GPIOA_PIN5 5U
+#define GPIOA_PIN6 6U
+#define GPIOA_PIN7 7U
+#define GPIOA_PIN8 8U
+#define GPIOA_PIN9 9U
+#define GPIOA_PIN10 10U
+#define GPIOA_PIN11 11U
+#define GPIOA_PIN12 12U
+#define GPIOA_SWDIO 13U
+#define GPIOA_SWCLK 14U
+#define GPIOA_PIN15 15U
+
+#define GPIOB_PIN0 0U
+#define GPIOB_PIN1 1U
+#define GPIOB_PIN2 2U
+#define GPIOB_PIN3 3U
+#define GPIOB_PIN4 4U
+#define GPIOB_PIN5 5U
+#define GPIOB_PIN6 6U
+#define GPIOB_PIN7 7U
+#define GPIOB_PIN8 8U
+#define GPIOB_PIN9 9U
+#define GPIOB_PIN10 10U
+#define GPIOB_PIN11 11U
+#define GPIOB_PIN12 12U
+#define GPIOB_PIN13 13U
+#define GPIOB_PIN14 14U
+#define GPIOB_PIN15 15U
+
+#define GPIOC_PIN0 0U
+#define GPIOC_PIN1 1U
+#define GPIOC_PIN2 2U
+#define GPIOC_PIN3 3U
+#define GPIOC_PIN4 4U
+#define GPIOC_PIN5 5U
+#define GPIOC_PIN6 6U
+#define GPIOC_PIN7 7U
+#define GPIOC_PIN8 8U
+#define GPIOC_PIN9 9U
+#define GPIOC_PIN10 10U
+#define GPIOC_PIN11 11U
+#define GPIOC_PIN12 12U
+#define GPIOC_PIN13 13U
+#define GPIOC_PIN14 14U
+#define GPIOC_PIN15 15U
+
+#define GPIOD_HEXT_IN 0U
+#define GPIOD_HEXT_OUT 1U
+#define GPIOD_PIN2 2U
+
+#define GPIOF_PIN4 4U
+#define GPIOF_PIN5 5U
+#define GPIOF_PIN6 6U
+#define GPIOF_PIN7 7U
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*
+ * I/O ports initial setup, this configuration is established soon after reset
+ * in the initialization code.
+ *
+ * The digits have the following meaning:
+ * 0 - Analog input.
+ * 1 - Push Pull output 10MHz.
+ * 2 - Push Pull output 2MHz.
+ * 3 - Push Pull output 50MHz.
+ * 4 - Digital input.
+ * 5 - Open Drain output 10MHz.
+ * 6 - Open Drain output 2MHz.
+ * 7 - Open Drain output 50MHz.
+ * 8 - Digital input with Pull-Up or Pull-Down resistor depending on ODT.
+ * 9 - Alternate Push Pull output 10MHz.
+ * A - Alternate Push Pull output 2MHz.
+ * B - Alternate Push Pull output 50MHz.
+ * C - Reserved.
+ * D - Alternate Open Drain output 10MHz.
+ * E - Alternate Open Drain output 2MHz.
+ * F - Alternate Open Drain output 50MHz.
+ * Please refer to the AT32 Reference Manual for details.
+ */
+
+/*
+ * Port A setup.
+ */
+#define VAL_GPIOACFGLR 0x88888B88 /* PA7...PA0 */
+#define VAL_GPIOACFGHR 0x888888B8 /* PA15...PA8 */
+#define VAL_GPIOAODT 0xFFFFFFFF
+
+/*
+ * Port B setup.
+ */
+#define VAL_GPIOBCFGLR 0x88888888 /* PB7...PB0 */
+#define VAL_GPIOBCFGHR 0x88888888 /* PB15...PB8 */
+#define VAL_GPIOBODT 0xFFFFFFFF
+
+/*
+ * Port C setup.
+ */
+#define VAL_GPIOCCFGLR 0x88888888 /* PC7...PC0 */
+#define VAL_GPIOCCFGHR 0x88888888 /* PC15...PC8 */
+#define VAL_GPIOCODT 0xFFFFFFFF
+
+/*
+ * Port D setup.
+ * Everything input with pull-up except:
+ * PD0 - Normal input (GPIOD_HEXT_IN).
+ * PD1 - Normal input (GPIOD_HEXT_OUT).
+ */
+#define VAL_GPIODCFGLR 0x88888844 /* PD7...PD0 */
+#define VAL_GPIODCFGHR 0x88888888 /* PD15...PD8 */
+#define VAL_GPIODODT 0xFFFFFFFF
+
+/*
+ * Port F setup.
+ */
+#define VAL_GPIOFCFGLR 0x88888888 /* PF7...PF0 */
+#define VAL_GPIOFCFGHR 0x88888888 /* PF15...PF8 */
+#define VAL_GPIOFODT 0xFFFFFFFF
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if !defined(_FROM_ASM_)
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void boardInit(void);
+#ifdef __cplusplus
+}
+#endif
+#endif /* _FROM_ASM_ */
+
+#endif /* _BOARD_H_ */
diff --git a/platforms/chibios/boards/GENERIC_AT32_F415XX/board/board.mk b/platforms/chibios/boards/GENERIC_AT32_F415XX/board/board.mk
new file mode 100644
index 00000000000..842e3359059
--- /dev/null
+++ b/platforms/chibios/boards/GENERIC_AT32_F415XX/board/board.mk
@@ -0,0 +1,9 @@
+# List of all the board related files.
+BOARDSRC = $(BOARD_PATH)/board/board.c
+
+# Required include directories
+BOARDINC = $(BOARD_PATH)/board
+
+# Shared variables
+ALLCSRC += $(BOARDSRC)
+ALLINC += $(BOARDINC)
diff --git a/platforms/chibios/boards/GENERIC_AT32_F415XX/configs/config.h b/platforms/chibios/boards/GENERIC_AT32_F415XX/configs/config.h
new file mode 100644
index 00000000000..da60447a0af
--- /dev/null
+++ b/platforms/chibios/boards/GENERIC_AT32_F415XX/configs/config.h
@@ -0,0 +1,13 @@
+// Copyright 2023-2024 HorrorTroll
+// Copyright 2023-2024 Zhaqian
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#define BOARD_OTG_VBUSIG
+
+#define USB_ENDPOINTS_ARE_REORDERABLE
+
+#ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP
+# define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE
+#endif
diff --git a/platforms/chibios/boards/GENERIC_AT32_F415XX/configs/mcuconf.h b/platforms/chibios/boards/GENERIC_AT32_F415XX/configs/mcuconf.h
new file mode 100644
index 00000000000..d148379fe1d
--- /dev/null
+++ b/platforms/chibios/boards/GENERIC_AT32_F415XX/configs/mcuconf.h
@@ -0,0 +1,236 @@
+/*
+ ChibiOS - Copyright (C) 2006..2020 Giovanni Di Sirio
+ ChibiOS - Copyright (C) 2023..2024 HorrorTroll
+ ChibiOS - Copyright (C) 2023..2024 Zhaqian
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef MCUCONF_H
+#define MCUCONF_H
+
+/*
+ * AT32F415 drivers configuration.
+ * The following settings override the default settings present in
+ * the various device driver implementation headers.
+ * Note that the settings for each driver only have effect if the whole
+ * driver is enabled in halconf.h.
+ *
+ * IRQ priorities:
+ * 15...0 Lowest...Highest.
+ *
+ * DMA priorities:
+ * 0...3 Lowest...Highest.
+ */
+
+#define AT32F415_MCUCONF
+
+/*
+ * General settings.
+ */
+#define AT32_NO_INIT FALSE
+
+/*
+ * HAL driver system settings.
+ */
+#define AT32_HICK_ENABLED TRUE
+#define AT32_LICK_ENABLED FALSE
+#define AT32_HEXT_ENABLED TRUE
+#define AT32_LEXT_ENABLED FALSE
+#define AT32_SCLKSEL AT32_SCLKSEL_PLL
+#define AT32_PLLRCS AT32_PLLRCS_HEXT
+#define AT32_PLLHEXTDIV AT32_PLLHEXTDIV_DIV1
+#define AT32_PLLCFGEN AT32_PLLCFGEN_SOLID
+#define AT32_PLLMULT_VALUE 18
+#define AT32_PLL_FR_VALUE 4
+#define AT32_PLL_MS_VALUE 1
+#define AT32_PLL_NS_VALUE 72
+#define AT32_AHBDIV AT32_AHBDIV_DIV1
+#define AT32_APB1DIV AT32_APB1DIV_DIV2
+#define AT32_APB2DIV AT32_APB2DIV_DIV2
+#define AT32_ADCDIV AT32_ADCDIV_DIV4
+#define AT32_USB_CLOCK_REQUIRED TRUE
+#define AT32_USBDIV AT32_USBDIV_DIV3
+#define AT32_CLKOUT_SEL AT32_CLKOUT_SEL_NOCLOCK
+#define AT32_CLKOUTDIV AT32_CLKOUTDIV_DIV1
+#define AT32_ERTCSEL AT32_ERTCSEL_HEXTDIV
+#define AT32_PVM_ENABLE FALSE
+#define AT32_PVMSEL AT32_PVMSEL_LEV1
+
+/*
+ * IRQ system settings.
+ */
+#define AT32_IRQ_EXINT0_PRIORITY 6
+#define AT32_IRQ_EXINT1_PRIORITY 6
+#define AT32_IRQ_EXINT2_PRIORITY 6
+#define AT32_IRQ_EXINT3_PRIORITY 6
+#define AT32_IRQ_EXINT4_PRIORITY 6
+#define AT32_IRQ_EXINT5_9_PRIORITY 6
+#define AT32_IRQ_EXINT10_15_PRIORITY 6
+#define AT32_IRQ_EXINT16_PRIORITY 6
+#define AT32_IRQ_EXINT17_PRIORITY 15
+#define AT32_IRQ_EXINT18_PRIORITY 6
+#define AT32_IRQ_EXINT19_PRIORITY 6
+#define AT32_IRQ_EXINT20_PRIORITY 6
+#define AT32_IRQ_EXINT21_PRIORITY 15
+#define AT32_IRQ_EXINT22_PRIORITY 15
+
+#define AT32_IRQ_TMR1_BRK_TMR9_PRIORITY 7
+#define AT32_IRQ_TMR1_OVF_TMR10_PRIORITY 7
+#define AT32_IRQ_TMR1_HALL_TMR11_PRIORITY 7
+#define AT32_IRQ_TMR1_CH_PRIORITY 7
+#define AT32_IRQ_TMR2_PRIORITY 7
+#define AT32_IRQ_TMR3_PRIORITY 7
+#define AT32_IRQ_TMR4_PRIORITY 7
+#define AT32_IRQ_TMR5_PRIORITY 7
+
+#define AT32_IRQ_USART1_PRIORITY 12
+#define AT32_IRQ_USART2_PRIORITY 12
+#define AT32_IRQ_USART3_PRIORITY 12
+#define AT32_IRQ_UART4_PRIORITY 12
+#define AT32_IRQ_UART5_PRIORITY 12
+
+/*
+ * ADC driver system settings.
+ */
+#define AT32_ADC_USE_ADC1 FALSE
+#define AT32_ADC_ADC1_DMA_PRIORITY 2
+#define AT32_ADC_ADC1_IRQ_PRIORITY 6
+
+/*
+ * CAN driver system settings.
+ */
+#define AT32_CAN_USE_CAN1 FALSE
+#define AT32_CAN_CAN1_IRQ_PRIORITY 11
+
+/*
+ * DMA driver system settings.
+ */
+#define AT32_DMA_USE_DMAMUX TRUE
+
+/*
+ * GPT driver system settings.
+ */
+#define AT32_GPT_USE_TMR1 FALSE
+#define AT32_GPT_USE_TMR2 FALSE
+#define AT32_GPT_USE_TMR3 FALSE
+#define AT32_GPT_USE_TMR4 FALSE
+#define AT32_GPT_USE_TMR5 FALSE
+#define AT32_GPT_USE_TMR9 FALSE
+#define AT32_GPT_USE_TMR10 FALSE
+#define AT32_GPT_USE_TMR11 FALSE
+
+/*
+ * I2C driver system settings.
+ */
+#define AT32_I2C_USE_I2C1 FALSE
+#define AT32_I2C_USE_I2C2 FALSE
+#define AT32_I2C_BUSY_TIMEOUT 50
+#define AT32_I2C_I2C1_IRQ_PRIORITY 5
+#define AT32_I2C_I2C2_IRQ_PRIORITY 5
+#define AT32_I2C_I2C1_DMA_PRIORITY 3
+#define AT32_I2C_I2C2_DMA_PRIORITY 3
+#define AT32_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure")
+
+/*
+ * ICU driver system settings.
+ */
+#define AT32_ICU_USE_TMR1 FALSE
+#define AT32_ICU_USE_TMR2 FALSE
+#define AT32_ICU_USE_TMR3 FALSE
+#define AT32_ICU_USE_TMR4 FALSE
+#define AT32_ICU_USE_TMR5 FALSE
+#define AT32_ICU_USE_TMR9 FALSE
+#define AT32_ICU_USE_TMR10 FALSE
+#define AT32_ICU_USE_TMR11 FALSE
+
+/*
+ * PWM driver system settings.
+ */
+#define AT32_PWM_USE_TMR1 FALSE
+#define AT32_PWM_USE_TMR2 FALSE
+#define AT32_PWM_USE_TMR3 FALSE
+#define AT32_PWM_USE_TMR4 FALSE
+#define AT32_PWM_USE_TMR5 FALSE
+#define AT32_PWM_USE_TMR9 FALSE
+#define AT32_PWM_USE_TMR10 FALSE
+#define AT32_PWM_USE_TMR11 FALSE
+
+/*
+ * RTC driver system settings.
+ */
+#define AT32_ERTC_DIVA_VALUE 32
+#define AT32_ERTC_DIVB_VALUE 1024
+#define AT32_ERTC_CTRL_INIT 0
+#define AT32_ERTC_TAMP_INIT 0
+
+/*
+ * SDC driver system settings.
+ */
+#define AT32_SDC_SDIO_DMA_PRIORITY 3
+#define AT32_SDC_SDIO_IRQ_PRIORITY 9
+#define AT32_SDC_WRITE_TIMEOUT_MS 1000
+#define AT32_SDC_READ_TIMEOUT_MS 1000
+#define AT32_SDC_CLOCK_ACTIVATION_DELAY 10
+#define AT32_SDC_SDIO_UNALIGNED_SUPPORT TRUE
+
+/*
+ * SERIAL driver system settings.
+ */
+#define AT32_SERIAL_USE_USART1 FALSE
+#define AT32_SERIAL_USE_USART2 FALSE
+#define AT32_SERIAL_USE_USART3 FALSE
+#define AT32_SERIAL_USE_UART4 FALSE
+#define AT32_SERIAL_USE_UART5 FALSE
+
+/*
+ * SPI driver system settings.
+ */
+#define AT32_SPI_USE_SPI1 FALSE
+#define AT32_SPI_USE_SPI2 FALSE
+#define AT32_SPI_SPI1_DMA_PRIORITY 1
+#define AT32_SPI_SPI2_DMA_PRIORITY 1
+#define AT32_SPI_SPI1_IRQ_PRIORITY 10
+#define AT32_SPI_SPI2_IRQ_PRIORITY 10
+#define AT32_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure")
+
+/*
+ * ST driver system settings.
+ */
+#define AT32_ST_IRQ_PRIORITY 8
+#define AT32_ST_USE_TIMER 2
+
+/*
+ * UART driver system settings.
+ */
+#define AT32_UART_USE_USART1 FALSE
+#define AT32_UART_USE_USART2 FALSE
+#define AT32_UART_USE_USART3 FALSE
+#define AT32_UART_USART1_DMA_PRIORITY 0
+#define AT32_UART_USART2_DMA_PRIORITY 0
+#define AT32_UART_USART3_DMA_PRIORITY 0
+#define AT32_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure")
+
+/*
+ * USB driver system settings.
+ */
+#define AT32_USB_USE_OTG1 TRUE
+#define AT32_USB_OTG1_IRQ_PRIORITY 14
+#define AT32_USB_OTG1_RX_FIFO_SIZE 512
+
+/*
+ * WDG driver system settings.
+ */
+#define AT32_WDG_USE_WDT FALSE
+
+#endif /* MCUCONF_H */
diff --git a/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/config.h b/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/config.h
index 90a41326a16..5333a919a0b 100644
--- a/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/config.h
+++ b/platforms/chibios/boards/GENERIC_STM32_F405XG/configs/config.h
@@ -21,3 +21,13 @@
#ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP
# define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE
#endif
+
+#ifdef WEAR_LEVELING_EMBEDDED_FLASH
+# ifndef WEAR_LEVELING_EFL_FIRST_SECTOR
+# ifdef BOOTLOADER_TINYUF2
+# define WEAR_LEVELING_EFL_FIRST_SECTOR 3
+# else
+# define WEAR_LEVELING_EFL_FIRST_SECTOR 1
+# endif
+# endif
+#endif
diff --git a/platforms/chibios/boards/GENERIC_STM32_F407XE/configs/config.h b/platforms/chibios/boards/GENERIC_STM32_F407XE/configs/config.h
index 90a41326a16..5333a919a0b 100644
--- a/platforms/chibios/boards/GENERIC_STM32_F407XE/configs/config.h
+++ b/platforms/chibios/boards/GENERIC_STM32_F407XE/configs/config.h
@@ -21,3 +21,13 @@
#ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP
# define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE
#endif
+
+#ifdef WEAR_LEVELING_EMBEDDED_FLASH
+# ifndef WEAR_LEVELING_EFL_FIRST_SECTOR
+# ifdef BOOTLOADER_TINYUF2
+# define WEAR_LEVELING_EFL_FIRST_SECTOR 3
+# else
+# define WEAR_LEVELING_EFL_FIRST_SECTOR 1
+# endif
+# endif
+#endif
diff --git a/platforms/chibios/boards/GENERIC_STM32_F446XE/configs/config.h b/platforms/chibios/boards/GENERIC_STM32_F446XE/configs/config.h
index cbb98f90980..362327efded 100644
--- a/platforms/chibios/boards/GENERIC_STM32_F446XE/configs/config.h
+++ b/platforms/chibios/boards/GENERIC_STM32_F446XE/configs/config.h
@@ -17,3 +17,13 @@
#ifndef EARLY_INIT_PERFORM_BOOTLOADER_JUMP
# define EARLY_INIT_PERFORM_BOOTLOADER_JUMP TRUE
#endif
+
+#ifdef WEAR_LEVELING_EMBEDDED_FLASH
+# ifndef WEAR_LEVELING_EFL_FIRST_SECTOR
+# ifdef BOOTLOADER_TINYUF2
+# define WEAR_LEVELING_EFL_FIRST_SECTOR 3
+# else
+# define WEAR_LEVELING_EFL_FIRST_SECTOR 1
+# endif
+# endif
+#endif
diff --git a/platforms/chibios/boards/common/ld/STM32F401xC.ld b/platforms/chibios/boards/common/ld/STM32F401xC.ld
index 8bc1cda09c9..64f019706fa 100644
--- a/platforms/chibios/boards/common/ld/STM32F401xC.ld
+++ b/platforms/chibios/boards/common/ld/STM32F401xC.ld
@@ -5,6 +5,9 @@
*/
f4xx_flash_size = 256k;
-f4xx_ram_size = 64k;
+f4xx_ram1_size = 64k;
+f4xx_ram2_size = 0;
+f4xx_ram4_size = 0;
+f4xx_ram5_size = 0;
INCLUDE stm32f4xx_common.ld
diff --git a/platforms/chibios/boards/common/ld/STM32F401xC_tinyuf2.ld b/platforms/chibios/boards/common/ld/STM32F401xC_tinyuf2.ld
index 9e0306bde85..05aa51917f6 100644
--- a/platforms/chibios/boards/common/ld/STM32F401xC_tinyuf2.ld
+++ b/platforms/chibios/boards/common/ld/STM32F401xC_tinyuf2.ld
@@ -5,6 +5,9 @@
*/
f4xx_flash_size = 256k;
-f4xx_ram_size = 64k;
+f4xx_ram1_size = 64k;
+f4xx_ram2_size = 0;
+f4xx_ram4_size = 0;
+f4xx_ram5_size = 0;
INCLUDE stm32f4xx_tinyuf2_common.ld
diff --git a/platforms/chibios/boards/common/ld/STM32F401xE.ld b/platforms/chibios/boards/common/ld/STM32F401xE.ld
index 3c2a93bd304..6c72c8f127f 100644
--- a/platforms/chibios/boards/common/ld/STM32F401xE.ld
+++ b/platforms/chibios/boards/common/ld/STM32F401xE.ld
@@ -5,6 +5,9 @@
*/
f4xx_flash_size = 512k;
-f4xx_ram_size = 96k;
+f4xx_ram1_size = 96k;
+f4xx_ram2_size = 0;
+f4xx_ram4_size = 0;
+f4xx_ram5_size = 0;
INCLUDE stm32f4xx_common.ld
diff --git a/platforms/chibios/boards/common/ld/STM32F401xE_tinyuf2.ld b/platforms/chibios/boards/common/ld/STM32F401xE_tinyuf2.ld
index a7fa419cfbd..65272ec015f 100644
--- a/platforms/chibios/boards/common/ld/STM32F401xE_tinyuf2.ld
+++ b/platforms/chibios/boards/common/ld/STM32F401xE_tinyuf2.ld
@@ -5,6 +5,9 @@
*/
f4xx_flash_size = 512k;
-f4xx_ram_size = 96k;
+f4xx_ram1_size = 96k;
+f4xx_ram2_size = 0;
+f4xx_ram4_size = 0;
+f4xx_ram5_size = 0;
INCLUDE stm32f4xx_tinyuf2_common.ld
diff --git a/platforms/chibios/boards/common/ld/STM32F405xG.ld b/platforms/chibios/boards/common/ld/STM32F405xG.ld
index b7d0baa2103..d9468e18c57 100644
--- a/platforms/chibios/boards/common/ld/STM32F405xG.ld
+++ b/platforms/chibios/boards/common/ld/STM32F405xG.ld
@@ -1,86 +1,13 @@
/*
- ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-/*
- * STM32F405xG memory setup.
- * Note: Use of ram1 and ram2 is mutually exclusive with use of ram0.
+ * Copyright 2006..2018 Giovanni Di Sirio
+ * Copyright 2022 QMK contributors
+ * SPDX-License-Identifier: GPL-2.0-or-later
*/
-MEMORY
-{
- flash0 (rx) : org = 0x08000000, len = 16k /* Sector 0 - Init code as ROM bootloader assumes application starts here */
- flash1 (rx) : org = 0x08004000, len = 16k /* Sector 1 - Emulated eeprom */
- flash2 (rx) : org = 0x08008000, len = 1M - 32k /* Sector 2..6 - Rest of firmware */
- flash3 (rx) : org = 0x00000000, len = 0
- flash4 (rx) : org = 0x00000000, len = 0
- flash5 (rx) : org = 0x00000000, len = 0
- flash6 (rx) : org = 0x00000000, len = 0
- flash7 (rx) : org = 0x00000000, len = 0
- ram0 (wx) : org = 0x20000000, len = 128k /* SRAM1 + SRAM2 */
- ram1 (wx) : org = 0x20000000, len = 112k /* SRAM1 */
- ram2 (wx) : org = 0x2001C000, len = 16k /* SRAM2 */
- ram3 (wx) : org = 0x00000000, len = 0
- ram4 (wx) : org = 0x10000000, len = 64k /* CCM SRAM */
- ram5 (wx) : org = 0x40024000, len = 4k /* BCKP SRAM */
- ram6 (wx) : org = 0x00000000, len = 0
- ram7 (wx) : org = 0x00000000, len = 0
-}
-/* For each data/text section two region are defined, a virtual region
- and a load region (_LMA suffix).*/
+f4xx_flash_size = 1M;
+f4xx_ram1_size = 112k;
+f4xx_ram2_size = 16k;
+f4xx_ram4_size = 64k;
+f4xx_ram5_size = 4k;
-/* Flash region to be used for exception vectors.*/
-REGION_ALIAS("VECTORS_FLASH", flash0);
-REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
-
-/* Flash region to be used for constructors and destructors.*/
-REGION_ALIAS("XTORS_FLASH", flash2);
-REGION_ALIAS("XTORS_FLASH_LMA", flash2);
-
-/* Flash region to be used for code text.*/
-REGION_ALIAS("TEXT_FLASH", flash2);
-REGION_ALIAS("TEXT_FLASH_LMA", flash2);
-
-/* Flash region to be used for read only data.*/
-REGION_ALIAS("RODATA_FLASH", flash2);
-REGION_ALIAS("RODATA_FLASH_LMA", flash2);
-
-/* Flash region to be used for various.*/
-REGION_ALIAS("VARIOUS_FLASH", flash2);
-REGION_ALIAS("VARIOUS_FLASH_LMA", flash2);
-
-/* Flash region to be used for RAM(n) initialization data.*/
-REGION_ALIAS("RAM_INIT_FLASH_LMA", flash2);
-
-/* RAM region to be used for Main stack. This stack accommodates the processing
- of all exceptions and interrupts.*/
-REGION_ALIAS("MAIN_STACK_RAM", ram0);
-
-/* RAM region to be used for the process stack. This is the stack used by
- the main() function.*/
-REGION_ALIAS("PROCESS_STACK_RAM", ram0);
-
-/* RAM region to be used for data segment.*/
-REGION_ALIAS("DATA_RAM", ram0);
-REGION_ALIAS("DATA_RAM_LMA", flash2);
-
-/* RAM region to be used for BSS segment.*/
-REGION_ALIAS("BSS_RAM", ram0);
-
-/* RAM region to be used for the default heap.*/
-REGION_ALIAS("HEAP_RAM", ram0);
-
-/* Generic rules inclusion.*/
-INCLUDE rules.ld
+INCLUDE stm32f4xx_common.ld
diff --git a/platforms/chibios/boards/common/ld/STM32F405xG_tinyuf2.ld b/platforms/chibios/boards/common/ld/STM32F405xG_tinyuf2.ld
index 1ee4aa1a06c..51c4b625ac8 100644
--- a/platforms/chibios/boards/common/ld/STM32F405xG_tinyuf2.ld
+++ b/platforms/chibios/boards/common/ld/STM32F405xG_tinyuf2.ld
@@ -1,89 +1,13 @@
/*
- ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-/*
- * STM32F405xG memory setup.
- * Note: Use of ram1 and ram2 is mutually exclusive with use of ram0.
+ * Copyright 2006..2018 Giovanni Di Sirio
+ * Copyright 2022 QMK contributors
+ * SPDX-License-Identifier: GPL-2.0-or-later
*/
-MEMORY
-{
- flash0 (rx) : org = 0x08000000 + 64k, len = 1M - 64k /* tinyuf2 bootloader requires app to be located at 64k offset for this MCU */
- flash1 (rx) : org = 0x00000000, len = 0
- flash2 (rx) : org = 0x00000000, len = 0
- flash3 (rx) : org = 0x00000000, len = 0
- flash4 (rx) : org = 0x00000000, len = 0
- flash5 (rx) : org = 0x00000000, len = 0
- flash6 (rx) : org = 0x00000000, len = 0
- flash7 (rx) : org = 0x00000000, len = 0
- ram0 (wx) : org = 0x20000000, len = 128k /* SRAM1 + SRAM2 */
- ram1 (wx) : org = 0x20000000, len = 112k /* SRAM1 */
- ram2 (wx) : org = 0x2001C000, len = 16k /* SRAM2 */
- ram3 (wx) : org = 0x00000000, len = 0
- ram4 (wx) : org = 0x10000000, len = 64k /* CCM SRAM */
- ram5 (wx) : org = 0x40024000, len = 4k /* BCKP SRAM */
- ram6 (wx) : org = 0x00000000, len = 0
- ram7 (wx) : org = 0x00000000, len = 0
-}
-/* For each data/text section two region are defined, a virtual region
- and a load region (_LMA suffix).*/
+f4xx_flash_size = 1M;
+f4xx_ram1_size = 112k;
+f4xx_ram2_size = 16k;
+f4xx_ram4_size = 64k;
+f4xx_ram5_size = 4k;
-/* Flash region to be used for exception vectors.*/
-REGION_ALIAS("VECTORS_FLASH", flash0);
-REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
-
-/* Flash region to be used for constructors and destructors.*/
-REGION_ALIAS("XTORS_FLASH", flash0);
-REGION_ALIAS("XTORS_FLASH_LMA", flash0);
-
-/* Flash region to be used for code text.*/
-REGION_ALIAS("TEXT_FLASH", flash0);
-REGION_ALIAS("TEXT_FLASH_LMA", flash0);
-
-/* Flash region to be used for read only data.*/
-REGION_ALIAS("RODATA_FLASH", flash0);
-REGION_ALIAS("RODATA_FLASH_LMA", flash0);
-
-/* Flash region to be used for various.*/
-REGION_ALIAS("VARIOUS_FLASH", flash0);
-REGION_ALIAS("VARIOUS_FLASH_LMA", flash0);
-
-/* Flash region to be used for RAM(n) initialization data.*/
-REGION_ALIAS("RAM_INIT_FLASH_LMA", flash0);
-
-/* RAM region to be used for Main stack. This stack accommodates the processing
- of all exceptions and interrupts.*/
-REGION_ALIAS("MAIN_STACK_RAM", ram0);
-
-/* RAM region to be used for the process stack. This is the stack used by
- the main() function.*/
-REGION_ALIAS("PROCESS_STACK_RAM", ram0);
-
-/* RAM region to be used for data segment.*/
-REGION_ALIAS("DATA_RAM", ram0);
-REGION_ALIAS("DATA_RAM_LMA", flash0);
-
-/* RAM region to be used for BSS segment.*/
-REGION_ALIAS("BSS_RAM", ram0);
-
-/* RAM region to be used for the default heap.*/
-REGION_ALIAS("HEAP_RAM", ram0);
-
-/* Generic rules inclusion.*/
-INCLUDE rules.ld
-
-/* TinyUF2 bootloader reset support */
-_board_dfu_dbl_tap = ORIGIN(ram0) + 64k - 4; /* this is based off the linker file for tinyuf2 */
+INCLUDE stm32f4xx_tinyuf2_common.ld
diff --git a/platforms/chibios/boards/common/ld/STM32F407xE.ld b/platforms/chibios/boards/common/ld/STM32F407xE.ld
new file mode 100644
index 00000000000..66dd9911634
--- /dev/null
+++ b/platforms/chibios/boards/common/ld/STM32F407xE.ld
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2006..2018 Giovanni Di Sirio
+ * Copyright 2022 QMK contributors
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+f4xx_flash_size = 512k;
+f4xx_ram1_size = 112k;
+f4xx_ram2_size = 16k;
+f4xx_ram4_size = 64k;
+f4xx_ram5_size = 4k;
+
+INCLUDE stm32f4xx_common.ld
diff --git a/platforms/chibios/boards/common/ld/STM32F407xE_tinyuf2.ld b/platforms/chibios/boards/common/ld/STM32F407xE_tinyuf2.ld
new file mode 100644
index 00000000000..0cb7b89636d
--- /dev/null
+++ b/platforms/chibios/boards/common/ld/STM32F407xE_tinyuf2.ld
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2006..2018 Giovanni Di Sirio
+ * Copyright 2022 QMK contributors
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+f4xx_flash_size = 512k;
+f4xx_ram1_size = 112k;
+f4xx_ram2_size = 16k;
+f4xx_ram4_size = 64k;
+f4xx_ram5_size = 4k;
+
+INCLUDE stm32f4xx_tinyuf2_common.ld
diff --git a/platforms/chibios/boards/common/ld/STM32F411xC.ld b/platforms/chibios/boards/common/ld/STM32F411xC.ld
index 7827c9c7d2c..5e3f7e034bc 100644
--- a/platforms/chibios/boards/common/ld/STM32F411xC.ld
+++ b/platforms/chibios/boards/common/ld/STM32F411xC.ld
@@ -5,6 +5,9 @@
*/
f4xx_flash_size = 256k;
-f4xx_ram_size = 128k;
+f4xx_ram1_size = 128k;
+f4xx_ram2_size = 0;
+f4xx_ram4_size = 0;
+f4xx_ram5_size = 0;
INCLUDE stm32f4xx_common.ld
diff --git a/platforms/chibios/boards/common/ld/STM32F411xC_tinyuf2.ld b/platforms/chibios/boards/common/ld/STM32F411xC_tinyuf2.ld
index 0367b49f8fc..63a33309fde 100644
--- a/platforms/chibios/boards/common/ld/STM32F411xC_tinyuf2.ld
+++ b/platforms/chibios/boards/common/ld/STM32F411xC_tinyuf2.ld
@@ -5,6 +5,9 @@
*/
f4xx_flash_size = 256k;
-f4xx_ram_size = 128k;
+f4xx_ram1_size = 128k;
+f4xx_ram2_size = 0;
+f4xx_ram4_size = 0;
+f4xx_ram5_size = 0;
INCLUDE stm32f4xx_tinyuf2_common.ld
diff --git a/platforms/chibios/boards/common/ld/STM32F411xE.ld b/platforms/chibios/boards/common/ld/STM32F411xE.ld
index c621ede53a4..c798a775e99 100644
--- a/platforms/chibios/boards/common/ld/STM32F411xE.ld
+++ b/platforms/chibios/boards/common/ld/STM32F411xE.ld
@@ -5,6 +5,9 @@
*/
f4xx_flash_size = 512k;
-f4xx_ram_size = 128k;
+f4xx_ram1_size = 128k;
+f4xx_ram2_size = 0;
+f4xx_ram4_size = 0;
+f4xx_ram5_size = 0;
INCLUDE stm32f4xx_common.ld
diff --git a/platforms/chibios/boards/common/ld/STM32F411xE_tinyuf2.ld b/platforms/chibios/boards/common/ld/STM32F411xE_tinyuf2.ld
index d982f7fb8f6..25253f55907 100644
--- a/platforms/chibios/boards/common/ld/STM32F411xE_tinyuf2.ld
+++ b/platforms/chibios/boards/common/ld/STM32F411xE_tinyuf2.ld
@@ -5,6 +5,9 @@
*/
f4xx_flash_size = 512k;
-f4xx_ram_size = 128k;
+f4xx_ram1_size = 128k;
+f4xx_ram2_size = 0;
+f4xx_ram4_size = 0;
+f4xx_ram5_size = 0;
INCLUDE stm32f4xx_tinyuf2_common.ld
diff --git a/platforms/chibios/boards/common/ld/STM32F446xE.ld b/platforms/chibios/boards/common/ld/STM32F446xE.ld
new file mode 100644
index 00000000000..6e6c5dd3a4e
--- /dev/null
+++ b/platforms/chibios/boards/common/ld/STM32F446xE.ld
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2006..2018 Giovanni Di Sirio
+ * Copyright 2022 QMK contributors
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+f4xx_flash_size = 512k;
+f4xx_ram1_size = 112k;
+f4xx_ram2_size = 16k;
+f4xx_ram4_size = 0;
+f4xx_ram5_size = 4k;
+
+INCLUDE stm32f4xx_common.ld
diff --git a/platforms/chibios/boards/common/ld/STM32F446xE_tinyuf2.ld b/platforms/chibios/boards/common/ld/STM32F446xE_tinyuf2.ld
new file mode 100644
index 00000000000..676ffbdf0c0
--- /dev/null
+++ b/platforms/chibios/boards/common/ld/STM32F446xE_tinyuf2.ld
@@ -0,0 +1,13 @@
+/*
+* Copyright 2006..2018 Giovanni Di Sirio
+ * Copyright 2022 QMK contributors
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+f4xx_flash_size = 512k;
+f4xx_ram1_size = 112k;
+f4xx_ram2_size = 16k;
+f4xx_ram4_size = 0;
+f4xx_ram5_size = 4k;
+
+INCLUDE stm32f4xx_tinyuf2_common.ld
diff --git a/platforms/chibios/boards/common/ld/stm32f4xx_common.ld b/platforms/chibios/boards/common/ld/stm32f4xx_common.ld
index 1ddf7e96bc9..d5c7c736264 100644
--- a/platforms/chibios/boards/common/ld/stm32f4xx_common.ld
+++ b/platforms/chibios/boards/common/ld/stm32f4xx_common.ld
@@ -24,12 +24,12 @@ MEMORY
flash5 (rx) : org = 0x00000000, len = 0
flash6 (rx) : org = 0x00000000, len = 0
flash7 (rx) : org = 0x00000000, len = 0
- ram0 (wx) : org = 0x20000000, len = f4xx_ram_size
- ram1 (wx) : org = 0x00000000, len = 0
- ram2 (wx) : org = 0x00000000, len = 0
+ ram0 (wx) : org = 0x20000000, len = f4xx_ram1_size + f4xx_ram2_size /* SRAM1 + SRAM2 */
+ ram1 (wx) : org = 0x20000000, len = f4xx_ram1_size /* SRAM1 */
+ ram2 (wx) : org = 0x20000000 + f4xx_ram1_size, len = f4xx_ram2_size /* SRAM2 */
ram3 (wx) : org = 0x00000000, len = 0
- ram4 (wx) : org = 0x00000000, len = 0
- ram5 (wx) : org = 0x00000000, len = 0
+ ram4 (wx) : org = 0x10000000, len = f4xx_ram4_size /* CCM SRAM */
+ ram5 (wx) : org = 0x40024000, len = f4xx_ram5_size /* BCKP SRAM */
ram6 (wx) : org = 0x00000000, len = 0
ram7 (wx) : org = 0x00000000, len = 0
}
@@ -80,4 +80,3 @@ REGION_ALIAS("HEAP_RAM", ram0);
/* Generic rules inclusion.*/
INCLUDE rules.ld
-
diff --git a/platforms/chibios/boards/common/ld/stm32f4xx_tinyuf2_common.ld b/platforms/chibios/boards/common/ld/stm32f4xx_tinyuf2_common.ld
index ab03a9e6833..d995bd014a3 100644
--- a/platforms/chibios/boards/common/ld/stm32f4xx_tinyuf2_common.ld
+++ b/platforms/chibios/boards/common/ld/stm32f4xx_tinyuf2_common.ld
@@ -27,12 +27,12 @@ MEMORY
flash5 (rx) : org = 0x00000000, len = 0
flash6 (rx) : org = 0x00000000, len = 0
flash7 (rx) : org = 0x00000000, len = 0
- ram0 (wx) : org = 0x20000000, len = f4xx_ram_size
- ram1 (wx) : org = 0x00000000, len = 0
- ram2 (wx) : org = 0x00000000, len = 0
+ ram0 (wx) : org = 0x20000000, len = f4xx_ram1_size + f4xx_ram2_size /* SRAM1 + SRAM2 */
+ ram1 (wx) : org = 0x20000000, len = f4xx_ram1_size /* SRAM1 */
+ ram2 (wx) : org = 0x20000000 + f4xx_ram1_size, len = f4xx_ram2_size /* SRAM2 */
ram3 (wx) : org = 0x00000000, len = 0
- ram4 (wx) : org = 0x00000000, len = 0
- ram5 (wx) : org = 0x00000000, len = 0
+ ram4 (wx) : org = 0x10000000, len = f4xx_ram4_size /* CCM SRAM */
+ ram5 (wx) : org = 0x40024000, len = f4xx_ram5_size /* BCKP SRAM */
ram6 (wx) : org = 0x00000000, len = 0
ram7 (wx) : org = 0x00000000, len = 0
}
@@ -86,5 +86,3 @@ INCLUDE rules.ld
/* TinyUF2 bootloader reset support */
_board_dfu_dbl_tap = ORIGIN(ram0) + 64k - 4; /* this is based off the linker file for tinyuf2 */
-
-
diff --git a/platforms/chibios/bootloader.mk b/platforms/chibios/bootloader.mk
index 5b6edd73ad3..e292e1e0b08 100644
--- a/platforms/chibios/bootloader.mk
+++ b/platforms/chibios/bootloader.mk
@@ -26,6 +26,7 @@
# stm32-dfu STM32 USB DFU in ROM
# apm32-dfu APM32 USB DFU in ROM
# wb32-dfu WB32 USB DFU in ROM
+# at32-dfu AT32 USB DFU in ROM
# tinyuf2 TinyUF2
# rp2040 Raspberry Pi RP2040
# Current options for RISC-V:
@@ -119,6 +120,14 @@ ifeq ($(strip $(BOOTLOADER)), wb32-dfu)
OPT_DEFS += -DBOOTLOADER_WB32_DFU
BOOTLOADER_TYPE = wb32_dfu
endif
+ifeq ($(strip $(BOOTLOADER)), at32-dfu)
+ OPT_DEFS += -DBOOTLOADER_AT32_DFU
+ BOOTLOADER_TYPE = at32_dfu
+
+ # Options to pass to dfu-util when flashing
+ DFU_ARGS ?= -d 2E3C:DF11 -a 0 -s 0x08000000:leave
+ DFU_SUFFIX_ARGS ?= -v 2E3C -p DF11
+endif
ifeq ($(strip $(BOOTLOADER_TYPE)),)
ifneq ($(strip $(BOOTLOADER)),)
diff --git a/platforms/chibios/bootloaders/at32_dfu.c b/platforms/chibios/bootloaders/at32_dfu.c
new file mode 100644
index 00000000000..f3a453d0fce
--- /dev/null
+++ b/platforms/chibios/bootloaders/at32_dfu.c
@@ -0,0 +1,83 @@
+// Copyright 2021-2023 QMK
+// Copyright 2023-2024 HorrorTroll
+// Copyright 2023-2024 Zhaqian
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "bootloader.h"
+#include "util.h"
+
+#include
+#include
+#include "wait.h"
+
+#ifndef AT32_BOOTLOADER_RAM_SYMBOL
+# define AT32_BOOTLOADER_RAM_SYMBOL __ram0_end__
+#endif
+
+extern uint32_t AT32_BOOTLOADER_RAM_SYMBOL;
+
+/* This code should be checked whether it runs correctly on platforms */
+#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
+#define BOOTLOADER_MAGIC 0xDEADBEEF
+#define MAGIC_ADDR (unsigned long *)(SYMVAL(AT32_BOOTLOADER_RAM_SYMBOL) - 4)
+
+__attribute__((weak)) void bootloader_marker_enable(void) {
+ uint32_t *marker = (uint32_t *)MAGIC_ADDR;
+ *marker = BOOTLOADER_MAGIC; // set magic flag => reset handler will jump into boot loader
+}
+
+__attribute__((weak)) bool bootloader_marker_active(void) {
+ const uint32_t *marker = (const uint32_t *)MAGIC_ADDR;
+ return (*marker == BOOTLOADER_MAGIC) ? true : false;
+}
+
+__attribute__((weak)) void bootloader_marker_disable(void) {
+ uint32_t *marker = (uint32_t *)MAGIC_ADDR;
+ *marker = 0;
+}
+
+__attribute__((weak)) void bootloader_jump(void) {
+ bootloader_marker_enable();
+ NVIC_SystemReset();
+}
+
+__attribute__((weak)) void mcu_reset(void) {
+ NVIC_SystemReset();
+}
+
+void enter_bootloader_mode_if_requested(void) {
+ if (bootloader_marker_active()) {
+ bootloader_marker_disable();
+
+ struct system_memory_vector_t {
+ uint32_t stack_top;
+ void (*entrypoint)(void);
+ };
+ const struct system_memory_vector_t *bootloader = (const struct system_memory_vector_t *)(AT32_BOOTLOADER_ADDRESS);
+
+ __disable_irq();
+
+#if defined(__MPU_PRESENT) && (__MPU_PRESENT == 1U)
+ ARM_MPU_Disable();
+#endif
+
+ SysTick->CTRL = 0;
+ SysTick->VAL = 0;
+ SysTick->LOAD = 0;
+
+ // Clear interrupt enable and interrupt pending registers
+ for (int i = 0; i < ARRAY_SIZE(NVIC->ICER); i++) {
+ NVIC->ICER[i] = 0xFFFFFFFF;
+ NVIC->ICPR[i] = 0xFFFFFFFF;
+ }
+
+ __set_CONTROL(0);
+ __set_MSP(bootloader->stack_top);
+ __enable_irq();
+
+ // Jump to bootloader
+ bootloader->entrypoint();
+ while (true) {
+ }
+ }
+}
diff --git a/platforms/chibios/chibios_config.h b/platforms/chibios/chibios_config.h
index 8f46fe07360..95136baf303 100644
--- a/platforms/chibios/chibios_config.h
+++ b/platforms/chibios/chibios_config.h
@@ -142,6 +142,19 @@
# endif
#endif
+// AT32 compatibility
+#if defined(MCU_AT32)
+# define CPU_CLOCK AT32_SYSCLK
+
+# if defined(AT32F415)
+# define USE_GPIOV1
+# define USE_I2CV1
+# define PAL_MODE_ALTERNATE_OPENDRAIN PAL_MODE_AT32_ALTERNATE_OPENDRAIN
+# define PAL_MODE_ALTERNATE_PUSHPULL PAL_MODE_AT32_ALTERNATE_PUSHPULL
+# define AUDIO_PWM_PAL_MODE PAL_MODE_ALTERNATE_PUSHPULL
+# endif
+#endif
+
#if defined(GD32VF103)
/* This chip has the same API as STM32F103, but uses different names for literally the same thing.
* As of 4.7.2021 QMK is tailored to use STM32 defines/names, for compatibility sake
diff --git a/platforms/chibios/drivers/analog.c b/platforms/chibios/drivers/analog.c
index fb146df9367..7e1f87e6c95 100644
--- a/platforms/chibios/drivers/analog.c
+++ b/platforms/chibios/drivers/analog.c
@@ -22,7 +22,7 @@
# error "You need to set HAL_USE_ADC to TRUE in your halconf.h to use the ADC."
#endif
-#if !RP_ADC_USE_ADC1 && !STM32_ADC_USE_ADC1 && !STM32_ADC_USE_ADC2 && !STM32_ADC_USE_ADC3 && !STM32_ADC_USE_ADC4 && !WB32_ADC_USE_ADC1
+#if !RP_ADC_USE_ADC1 && !STM32_ADC_USE_ADC1 && !STM32_ADC_USE_ADC2 && !STM32_ADC_USE_ADC3 && !STM32_ADC_USE_ADC4 && !WB32_ADC_USE_ADC1 && !AT32_ADC_USE_ADC1
# error "You need to set one of the 'xxx_ADC_USE_ADCx' settings to TRUE in your mcuconf.h to use the ADC."
#endif
@@ -45,7 +45,7 @@
// Otherwise assume V3
#if defined(STM32F0XX) || defined(STM32L0XX)
# define USE_ADCV1
-#elif defined(STM32F1XX) || defined(STM32F2XX) || defined(STM32F4XX) || defined(GD32VF103) || defined(WB32F3G71xx) || defined(WB32FQ95xx)
+#elif defined(STM32F1XX) || defined(STM32F2XX) || defined(STM32F4XX) || defined(GD32VF103) || defined(WB32F3G71xx) || defined(WB32FQ95xx) || defined(AT32F415)
# define USE_ADCV2
#endif
@@ -82,7 +82,7 @@
/* User configurable ADC options */
#ifndef ADC_COUNT
-# if defined(RP2040) || defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F4XX) || defined(GD32VF103) || defined(WB32F3G71xx) || defined(WB32FQ95xx)
+# if defined(RP2040) || defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F4XX) || defined(GD32VF103) || defined(WB32F3G71xx) || defined(WB32FQ95xx) || defined(AT32F415)
# define ADC_COUNT 1
# elif defined(STM32F3XX) || defined(STM32G4XX)
# define ADC_COUNT 4
@@ -142,11 +142,16 @@ static ADCConversionGroup adcConversionGroup = {
.cfgr1 = ADC_CFGR1_CONT | ADC_RESOLUTION,
.smpr = ADC_SAMPLING_RATE,
#elif defined(USE_ADCV2)
-# if !defined(STM32F1XX) && !defined(GD32VF103) && !defined(WB32F3G71xx) && !defined(WB32FQ95xx)
- .cr2 = ADC_CR2_SWSTART, // F103 seem very unhappy with, F401 seems very unhappy without...
+# if !defined(STM32F1XX) && !defined(GD32VF103) && !defined(WB32F3G71xx) && !defined(WB32FQ95xx) && !defined(AT32F415)
+ .cr2 = ADC_CR2_SWSTART, // F103 seem very unhappy with, F401 seems very unhappy without...
# endif
+# if defined(AT32F415)
+ .spt2 = ADC_SPT2_CSPT_AN0(ADC_SAMPLING_RATE) | ADC_SPT2_CSPT_AN1(ADC_SAMPLING_RATE) | ADC_SPT2_CSPT_AN2(ADC_SAMPLING_RATE) | ADC_SPT2_CSPT_AN3(ADC_SAMPLING_RATE) | ADC_SPT2_CSPT_AN4(ADC_SAMPLING_RATE) | ADC_SPT2_CSPT_AN5(ADC_SAMPLING_RATE) | ADC_SPT2_CSPT_AN6(ADC_SAMPLING_RATE) | ADC_SPT2_CSPT_AN7(ADC_SAMPLING_RATE) | ADC_SPT2_CSPT_AN8(ADC_SAMPLING_RATE) | ADC_SPT2_CSPT_AN9(ADC_SAMPLING_RATE),
+ .spt1 = ADC_SPT1_CSPT_AN10(ADC_SAMPLING_RATE) | ADC_SPT1_CSPT_AN11(ADC_SAMPLING_RATE) | ADC_SPT1_CSPT_AN12(ADC_SAMPLING_RATE) | ADC_SPT1_CSPT_AN13(ADC_SAMPLING_RATE) | ADC_SPT1_CSPT_AN14(ADC_SAMPLING_RATE) | ADC_SPT1_CSPT_AN15(ADC_SAMPLING_RATE),
+# else
.smpr2 = ADC_SMPR2_SMP_AN0(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN1(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN2(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN3(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN4(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN5(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN6(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN7(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN8(ADC_SAMPLING_RATE) | ADC_SMPR2_SMP_AN9(ADC_SAMPLING_RATE),
.smpr1 = ADC_SMPR1_SMP_AN10(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN11(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN12(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN13(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN14(ADC_SAMPLING_RATE) | ADC_SMPR1_SMP_AN15(ADC_SAMPLING_RATE),
+# endif
#elif defined(RP2040)
// RP2040 does not have any extra config here
#else
@@ -242,7 +247,7 @@ __attribute__((weak)) adc_mux pinToMux(pin_t pin) {
case F9: return TO_MUX( ADC_CHANNEL_IN7, 2 );
case F10: return TO_MUX( ADC_CHANNEL_IN8, 2 );
# endif
-#elif defined(STM32F1XX) || defined(GD32VF103) || defined(WB32F3G71xx) || defined(WB32FQ95xx)
+#elif defined(STM32F1XX) || defined(GD32VF103) || defined(WB32F3G71xx) || defined(WB32FQ95xx) || defined(AT32F415)
case A0: return TO_MUX( ADC_CHANNEL_IN0, 0 );
case A1: return TO_MUX( ADC_CHANNEL_IN1, 0 );
case A2: return TO_MUX( ADC_CHANNEL_IN2, 0 );
@@ -344,7 +349,7 @@ __attribute__((weak)) adc_mux pinToMux(pin_t pin) {
static inline ADCDriver* intToADCDriver(uint8_t adcInt) {
switch (adcInt) {
-#if RP_ADC_USE_ADC1 || STM32_ADC_USE_ADC1 || WB32_ADC_USE_ADC1
+#if RP_ADC_USE_ADC1 || STM32_ADC_USE_ADC1 || WB32_ADC_USE_ADC1 || AT32_ADC_USE_ADC1
case 0:
return &ADCD1;
#endif
@@ -391,7 +396,11 @@ int16_t adc_read(adc_mux mux) {
// TODO: fix previous assumption of only 1 input...
adcConversionGroup.chselr = 1 << mux.input; /*no macro to convert N to ADC_CHSELR_CHSEL1*/
#elif defined(USE_ADCV2)
+# if defined(AT32F415)
+ adcConversionGroup.osq3 = ADC_OSQ3_OSN1_N(mux.input);
+# else
adcConversionGroup.sqr3 = ADC_SQR3_SQ1_N(mux.input);
+# endif
#elif defined(RP2040)
adcConversionGroup.channel_mask = 1 << mux.input;
#else
diff --git a/platforms/chibios/drivers/serial_usart.c b/platforms/chibios/drivers/serial_usart.c
index 767ef8726fc..becf3afbce1 100644
--- a/platforms/chibios/drivers/serial_usart.c
+++ b/platforms/chibios/drivers/serial_usart.c
@@ -9,6 +9,17 @@
#if defined(SERIAL_USART_CONFIG)
static QMKSerialConfig serial_config = SERIAL_USART_CONFIG;
+#elif defined(MCU_AT32) /* AT32 MCUs */
+static QMKSerialConfig serial_config = {
+ .speed = (SERIAL_USART_SPEED),
+ .ctrl1 = (SERIAL_USART_CTRL1),
+ .ctrl2 = (SERIAL_USART_CTRL2),
+# if !defined(SERIAL_USART_FULL_DUPLEX)
+ .ctrl3 = ((SERIAL_USART_CTRL3) | USART_CTRL3_SLBEN) /* activate half-duplex mode */
+# else
+ .ctrl3 = (SERIAL_USART_CTRL3)
+# endif
+};
#elif defined(MCU_STM32) /* STM32 MCUs */
static QMKSerialConfig serial_config = {
# if HAL_USE_SERIAL
@@ -160,7 +171,7 @@ inline bool serial_transport_receive_blocking(uint8_t* destination, const size_t
* @brief Initiate pins for USART peripheral. Half-duplex configuration.
*/
__attribute__((weak)) void usart_init(void) {
-# if defined(MCU_STM32) /* STM32 MCUs */
+# if defined(MCU_STM32) || defined(MCU_AT32) /* STM32 and AT32 MCUs */
# if defined(USE_GPIOV1)
palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_OPENDRAIN);
# else
@@ -183,7 +194,7 @@ __attribute__((weak)) void usart_init(void) {
* @brief Initiate pins for USART peripheral. Full-duplex configuration.
*/
__attribute__((weak)) void usart_init(void) {
-# if defined(MCU_STM32) /* STM32 MCUs */
+# if defined(MCU_STM32) || defined(MCU_AT32) /* STM32 and AT32 MCUs */
# if defined(USE_GPIOV1)
palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE_PUSHPULL);
palSetLineMode(SERIAL_USART_RX_PIN, PAL_MODE_INPUT);
diff --git a/platforms/chibios/drivers/serial_usart.h b/platforms/chibios/drivers/serial_usart.h
index dec8a292e98..dbd7673273f 100644
--- a/platforms/chibios/drivers/serial_usart.h
+++ b/platforms/chibios/drivers/serial_usart.h
@@ -74,40 +74,75 @@ typedef SIOConfig QMKSerialConfig;
# endif
#endif
-#if !defined(USART_CR1_M0)
-# define USART_CR1_M0 USART_CR1_M // some platforms (f1xx) dont have this so
-#endif
+#if defined(MCU_STM32) /* STM32 MCUs */
+# if !defined(USART_CR1_M0)
+# define USART_CR1_M0 USART_CR1_M // some platforms (f1xx) dont have this so
+# endif
-#if !defined(SERIAL_USART_CR1)
-# define SERIAL_USART_CR1 (USART_CR1_PCE | USART_CR1_PS | USART_CR1_M0) // parity enable, odd parity, 9 bit length
-#endif
+# if !defined(SERIAL_USART_CR1)
+# define SERIAL_USART_CR1 (USART_CR1_PCE | USART_CR1_PS | USART_CR1_M0) // parity enable, odd parity, 9 bit length
+# endif
-#if !defined(SERIAL_USART_CR2)
-# define SERIAL_USART_CR2 (USART_CR2_STOP_1) // 2 stop bits
-#endif
+# if !defined(SERIAL_USART_CR2)
+# define SERIAL_USART_CR2 (USART_CR2_STOP_1) // 2 stop bits
+# endif
-#if !defined(SERIAL_USART_CR3)
-# define SERIAL_USART_CR3 0
-#endif
+# if !defined(SERIAL_USART_CR3)
+# define SERIAL_USART_CR3 0
+# endif
-#if defined(USART1_REMAP)
-# define USART_REMAP \
- do { \
- (AFIO->MAPR |= AFIO_MAPR_USART1_REMAP); \
- } while (0)
-#elif defined(USART2_REMAP)
-# define USART_REMAP \
- do { \
- (AFIO->MAPR |= AFIO_MAPR_USART2_REMAP); \
- } while (0)
-#elif defined(USART3_PARTIALREMAP)
-# define USART_REMAP \
- do { \
- (AFIO->MAPR |= AFIO_MAPR_USART3_REMAP_PARTIALREMAP); \
- } while (0)
-#elif defined(USART3_FULLREMAP)
-# define USART_REMAP \
- do { \
- (AFIO->MAPR |= AFIO_MAPR_USART3_REMAP_FULLREMAP); \
- } while (0)
+# if defined(USART1_REMAP)
+# define USART_REMAP \
+ do { \
+ (AFIO->MAPR |= AFIO_MAPR_USART1_REMAP); \
+ } while (0)
+# elif defined(USART2_REMAP)
+# define USART_REMAP \
+ do { \
+ (AFIO->MAPR |= AFIO_MAPR_USART2_REMAP); \
+ } while (0)
+# elif defined(USART3_PARTIALREMAP)
+# define USART_REMAP \
+ do { \
+ (AFIO->MAPR |= AFIO_MAPR_USART3_REMAP_PARTIALREMAP); \
+ } while (0)
+# elif defined(USART3_FULLREMAP)
+# define USART_REMAP \
+ do { \
+ (AFIO->MAPR |= AFIO_MAPR_USART3_REMAP_FULLREMAP); \
+ } while (0)
+# endif
+#elif defined(MCU_AT32) /* AT32 MCUs */
+# if !defined(USART_CTRL1_DBN0)
+# define USART_CTRL1_DBN0 USART_CTRL1_DBN
+# endif
+
+# if !defined(SERIAL_USART_CTRL1)
+# define SERIAL_USART_CTRL1 (USART_CTRL1_PEN | USART_CTRL1_PSEL | USART_CTRL1_DBN0) // parity enable, odd parity, 9 bit length
+# endif
+
+# if !defined(SERIAL_USART_CTRL2)
+# define SERIAL_USART_CTRL2 (USART_CTRL2_STOPBN_1) // 2 stop bits
+# endif
+
+# if !defined(SERIAL_USART_CTRL3)
+# define SERIAL_USART_CTRL3 0
+# endif
+
+# if defined(USART1_REMAP)
+# define USART_REMAP \
+ do { \
+ (IOMUX->REMAP |= IOMUX_REMAP_USART1_MUX); \
+ } while (0)
+# elif defined(USART3_PARTIALREMAP)
+# define USART_REMAP \
+ do { \
+ (IOMUX->REMAP |= IOMUX_REMAP_USART3_MUX_MUX1); \
+ } while (0)
+# elif defined(USART3_FULLREMAP)
+# define USART_REMAP \
+ do { \
+ (IOMUX->REMAP |= IOMUX_REMAP_USART3_MUX_MUX2); \
+ } while (0)
+# endif
#endif
diff --git a/platforms/chibios/drivers/spi_master.c b/platforms/chibios/drivers/spi_master.c
index cbe765e233d..6417b7077f5 100644
--- a/platforms/chibios/drivers/spi_master.c
+++ b/platforms/chibios/drivers/spi_master.c
@@ -103,9 +103,15 @@ bool spi_start_extended(spi_start_config_t *start_config) {
roundedDivisor <<= 1;
}
+# if defined(AT32F415)
+ if (roundedDivisor < 2 || roundedDivisor > 1024) {
+ return false;
+ }
+# else
if (roundedDivisor < 2 || roundedDivisor > 256) {
return false;
}
+# endif
#endif
#if defined(K20x) || defined(KL2x)
@@ -240,6 +246,59 @@ bool spi_start_extended(spi_start_config_t *start_config) {
spiConfig.SSPCR0 |= SPI_SSPCR0_SPH; // Clock phase: sample on second edge transition
break;
}
+#elif defined(AT32F415)
+ spiConfig.ctrl1 = 0;
+
+ if (lsbFirst) {
+ spiConfig.ctrl1 |= SPI_CTRL1_LTF;
+ }
+
+ switch (mode) {
+ case 0:
+ break;
+ case 1:
+ spiConfig.ctrl1 |= SPI_CTRL1_CLKPHA;
+ break;
+ case 2:
+ spiConfig.ctrl1 |= SPI_CTRL1_CLKPOL;
+ break;
+ case 3:
+ spiConfig.ctrl1 |= SPI_CTRL1_CLKPHA | SPI_CTRL1_CLKPOL;
+ break;
+ }
+
+ switch (roundedDivisor) {
+ case 2:
+ break;
+ case 4:
+ spiConfig.ctrl1 |= SPI_CTRL1_MDIV_0;
+ break;
+ case 8:
+ spiConfig.ctrl1 |= SPI_CTRL1_MDIV_1;
+ break;
+ case 16:
+ spiConfig.ctrl1 |= SPI_CTRL1_MDIV_1 | SPI_CTRL1_MDIV_0;
+ break;
+ case 32:
+ spiConfig.ctrl1 |= SPI_CTRL1_MDIV_2;
+ break;
+ case 64:
+ spiConfig.ctrl1 |= SPI_CTRL1_MDIV_2 | SPI_CTRL1_MDIV_0;
+ break;
+ case 128:
+ spiConfig.ctrl1 |= SPI_CTRL1_MDIV_2 | SPI_CTRL1_MDIV_1;
+ break;
+ case 256:
+ spiConfig.ctrl1 |= SPI_CTRL1_MDIV_2 | SPI_CTRL1_MDIV_1 | SPI_CTRL1_MDIV_0;
+ break;
+ case 512:
+ spiConfig.ctrl2 |= SPI_CTRL1_MDIV_3;
+ break;
+ case 1024:
+ spiConfig.ctrl2 |= SPI_CTRL1_MDIV_3;
+ spiConfig.ctrl1 |= SPI_CTRL1_MDIV_0;
+ break;
+ }
#else
spiConfig.cr1 = 0;
diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c b/platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c
index f49c4a45b0b..fed16d20b1a 100644
--- a/platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c
+++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_efl.c
@@ -33,7 +33,7 @@ static inline uint32_t detect_flash_size(void) {
#elif defined(FLASH_SIZE)
return FLASH_SIZE;
#elif defined(FLASHSIZE_BASE)
-# if defined(QMK_MCU_SERIES_STM32F0XX) || defined(QMK_MCU_SERIES_STM32F1XX) || defined(QMK_MCU_SERIES_STM32F3XX) || defined(QMK_MCU_SERIES_STM32F4XX) || defined(QMK_MCU_SERIES_STM32G4XX) || defined(QMK_MCU_SERIES_STM32L0XX) || defined(QMK_MCU_SERIES_STM32L4XX) || defined(QMK_MCU_SERIES_GD32VF103)
+# if defined(QMK_MCU_SERIES_STM32F0XX) || defined(QMK_MCU_SERIES_STM32F1XX) || defined(QMK_MCU_SERIES_STM32F3XX) || defined(QMK_MCU_SERIES_STM32F4XX) || defined(QMK_MCU_SERIES_STM32G4XX) || defined(QMK_MCU_SERIES_STM32L0XX) || defined(QMK_MCU_SERIES_STM32L4XX) || defined(QMK_MCU_SERIES_AT32F415) || defined(QMK_MCU_SERIES_GD32VF103)
return ((*(uint32_t *)FLASHSIZE_BASE) & 0xFFFFU) << 10U; // this register has the flash size in kB, so we convert it to bytes
# elif defined(QMK_MCU_SERIES_STM32L1XX)
# error This MCU family has an uncommon flash size register definition and has not been implemented. Perhaps try using the true EEPROM on the MCU instead?
diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_efl_config.h b/platforms/chibios/drivers/wear_leveling/wear_leveling_efl_config.h
index 0f0fa694e9c..f09f824bd8b 100644
--- a/platforms/chibios/drivers/wear_leveling/wear_leveling_efl_config.h
+++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_efl_config.h
@@ -16,6 +16,8 @@
# define BACKING_STORE_WRITE_SIZE 4 // from hal_efl_lld.c
# elif defined(QMK_MCU_FAMILY_WB32)
# define BACKING_STORE_WRITE_SIZE 8 // from hal_efl_lld.c
+# elif defined(QMK_MCU_FAMILY_AT32)
+# define BACKING_STORE_WRITE_SIZE 2 // from hal_efl_lld.c
# elif defined(QMK_MCU_FAMILY_STM32)
# if defined(STM32_FLASH_LINE_SIZE) // from some family's stm32_registry.h file
# define BACKING_STORE_WRITE_SIZE (STM32_FLASH_LINE_SIZE)
diff --git a/platforms/chibios/drivers/ws2812_bitbang.c b/platforms/chibios/drivers/ws2812_bitbang.c
index fce1963d0ae..a88c5ff619d 100644
--- a/platforms/chibios/drivers/ws2812_bitbang.c
+++ b/platforms/chibios/drivers/ws2812_bitbang.c
@@ -11,7 +11,7 @@
/* Adapted from https://github.com/bigjosh/SimpleNeoPixelDemo/ */
#ifndef WS2812_BITBANG_NOP_FUDGE
-# if defined(STM32F0XX) || defined(STM32F1XX) || defined(GD32VF103) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX) || defined(WB32F3G71xx) || defined(WB32FQ95xx)
+# if defined(STM32F0XX) || defined(STM32F1XX) || defined(GD32VF103) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX) || defined(WB32F3G71xx) || defined(WB32FQ95xx) || defined(AT32F415)
# define WS2812_BITBANG_NOP_FUDGE 0.4
# else
# if defined(RP2040)
diff --git a/platforms/chibios/drivers/ws2812_pwm.c b/platforms/chibios/drivers/ws2812_pwm.c
index dc0e3091633..50927b849a4 100644
--- a/platforms/chibios/drivers/ws2812_pwm.c
+++ b/platforms/chibios/drivers/ws2812_pwm.c
@@ -40,6 +40,9 @@
#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) && !defined(WS2812_PWM_DMAMUX_ID)
# error "please consult your MCU's datasheet and specify in your config.h: #define WS2812_PWM_DMAMUX_ID STM32_DMAMUX1_TIM?_UP"
#endif
+#if (AT32_DMA_SUPPORTS_DMAMUX == TRUE) && !defined(WS2812_PWM_DMAMUX_CHANNEL) && !defined(WS2812_PWM_DMAMUX_ID)
+# error "please consult your MCU's datasheet and specify in your config.h: #define WS2812_PWM_DMAMUX_CHANNEL 1, #define WS2812_PWM_DMAMUX_ID AT32_DMAMUX_TMR?_OVERFLOW"
+#endif
/* Summarize https://www.st.com/resource/en/application_note/an4013-stm32-crossseries-timer-overview-stmicroelectronics.pdf to
* figure out if we are using a 32bit timer. This is needed to setup the DMA controller correctly.
@@ -79,15 +82,15 @@
# endif
#endif
-#ifndef WS2812_PWM_TARGET_PERIOD
-//# define WS2812_PWM_TARGET_PERIOD 800000 // Original code is 800k...?
-# define WS2812_PWM_TARGET_PERIOD 80000 // TODO: work out why 10x less on f303/f4x1
+// Default is 800000Hz, which has a period of 1.25us
+#ifndef WS2812_PWM_FREQUENCY
+# define WS2812_PWM_FREQUENCY (1000000000 / WS2812_TIMING)
#endif
/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
-#define WS2812_PWM_FREQUENCY (CPU_CLOCK / 2) /**< Clock frequency of PWM, must be valid with respect to system clock! */
-#define WS2812_PWM_PERIOD (WS2812_PWM_FREQUENCY / WS2812_PWM_TARGET_PERIOD) /**< Clock period in ticks. 1 / 800kHz = 1.25 uS (as per datasheet) */
+#define WS2812_PWM_TICK_FREQUENCY (CPU_CLOCK / 2) /**< Clock frequency of PWM ticks, must be valid with respect to system clock! */
+#define WS2812_PWM_PERIOD (WS2812_PWM_TICK_FREQUENCY / WS2812_PWM_FREQUENCY) /**< Clock period in PWM ticks. */
/**
* @brief Number of bit-periods to hold the data line low at the end of a frame
@@ -102,37 +105,16 @@
/**
* @brief High period for a zero, in ticks
- *
- * Per the datasheet:
- * WS2812:
- * - T0H: 200 nS to 500 nS, inclusive
- * - T0L: 650 nS to 950 nS, inclusive
- * WS2812B:
- * - T0H: 200 nS to 500 nS, inclusive
- * - T0L: 750 nS to 1050 nS, inclusive
- *
- * The duty cycle is calculated for a high period of 350 nS.
*/
-#define WS2812_DUTYCYCLE_0 (WS2812_PWM_FREQUENCY / (1000000000 / 350))
+#define WS2812_DUTYCYCLE_0 (WS2812_PWM_TICK_FREQUENCY / (1000000000 / WS2812_T0H))
#if (WS2812_DUTYCYCLE_0 > 255)
# error WS2812 PWM driver: High period for a 0 is more than a byte
#endif
/**
* @brief High period for a one, in ticks
- *
- * Per the datasheet:
- * WS2812:
- * - T1H: 550 nS to 850 nS, inclusive
- * - T1L: 450 nS to 750 nS, inclusive
- * WS2812B:
- * - T1H: 750 nS to 1050 nS, inclusive
- * - T1L: 200 nS to 500 nS, inclusive
- *
- * The duty cycle is calculated for a high period of 800 nS.
- * This is in the middle of the specifications of the WS2812 and WS2812B.
*/
-#define WS2812_DUTYCYCLE_1 (WS2812_PWM_FREQUENCY / (1000000000 / 800))
+#define WS2812_DUTYCYCLE_1 (WS2812_PWM_TICK_FREQUENCY / (1000000000 / WS2812_T1H))
#if (WS2812_DUTYCYCLE_1 > 255)
# error WS2812 PWM driver: High period for a 1 is more than a byte
#endif
@@ -290,6 +272,14 @@ typedef uint32_t ws2812_buffer_t;
# define WS2812_PWM_DMA_PERIPHERAL_WIDTH STM32_DMA_CR_PSIZE_HWORD
typedef uint16_t ws2812_buffer_t;
# endif
+#elif defined(AT32F415)
+# define WS2812_PWM_DMA_MEMORY_WIDTH AT32_DMA_CCTRL_MWIDTH_BYTE
+# if defined(WS2812_PWM_TIMER_32BIT)
+# define WS2812_PWM_DMA_PERIPHERAL_WIDTH AT32_DMA_CCTRL_PWIDTH_WORD
+# else
+# define WS2812_PWM_DMA_PERIPHERAL_WIDTH AT32_DMA_CCTRL_PWIDTH_HWORD
+# endif
+typedef uint8_t ws2812_buffer_t;
#else
# define WS2812_PWM_DMA_MEMORY_WIDTH STM32_DMA_CR_MSIZE_BYTE
# if defined(WS2812_PWM_TIMER_32BIT)
@@ -322,7 +312,7 @@ void ws2812_init(void) {
// PWM Configuration
//#pragma GCC diagnostic ignored "-Woverride-init" // Turn off override-init warning for this struct. We use the overriding ability to set a "default" channel config
static const PWMConfig ws2812_pwm_config = {
- .frequency = WS2812_PWM_FREQUENCY,
+ .frequency = WS2812_PWM_TICK_FREQUENCY,
.period = WS2812_PWM_PERIOD, // Mit dieser Periode wird UDE-Event erzeugt und ein neuer Wert (Länge WS2812_BIT_N) vom DMA ins CCR geschrieben
.callback = NULL,
.channels =
@@ -330,8 +320,13 @@ void ws2812_init(void) {
[0 ... 3] = {.mode = PWM_OUTPUT_DISABLED, .callback = NULL}, // Channels default to disabled
[WS2812_PWM_CHANNEL - 1] = {.mode = WS2812_PWM_OUTPUT_MODE, .callback = NULL}, // Turn on the channel we care about
},
+#if defined(AT32F415)
+ .ctrl2 = 0,
+ .iden = AT32_TMR_IDEN_OVFDEN, // DMA on update event for next period
+#else
.cr2 = 0,
.dier = TIM_DIER_UDE, // DMA on update event for next period
+#endif
};
//#pragma GCC diagnostic pop // Restore command-line warning options
@@ -342,6 +337,11 @@ void ws2812_init(void) {
dmaStreamSetSource(WS2812_PWM_DMA_STREAM, ws2812_frame_buffer);
dmaStreamSetDestination(WS2812_PWM_DMA_STREAM, &(WS2812_PWM_DRIVER.tim->CCR[WS2812_PWM_CHANNEL - 1])); // Ziel ist der An-Zeit im Cap-Comp-Register
dmaStreamSetMode(WS2812_PWM_DMA_STREAM, WB32_DMA_CHCFG_HWHIF(WS2812_PWM_DMA_CHANNEL) | WB32_DMA_CHCFG_DIR_M2P | WB32_DMA_CHCFG_PSIZE_WORD | WB32_DMA_CHCFG_MSIZE_WORD | WB32_DMA_CHCFG_MINC | WB32_DMA_CHCFG_CIRC | WB32_DMA_CHCFG_TCIE | WB32_DMA_CHCFG_PL(3));
+#elif defined(AT32F415)
+ dmaStreamAlloc(WS2812_PWM_DMA_STREAM - AT32_DMA_STREAM(0), 10, NULL, NULL);
+ dmaStreamSetPeripheral(WS2812_PWM_DMA_STREAM, &(WS2812_PWM_DRIVER.tmr->CDT[WS2812_PWM_CHANNEL - 1])); // Ziel ist der An-Zeit im Cap-Comp-Register
+ dmaStreamSetMemory0(WS2812_PWM_DMA_STREAM, ws2812_frame_buffer);
+ dmaStreamSetMode(WS2812_PWM_DMA_STREAM, AT32_DMA_CCTRL_DTD_M2P | WS2812_PWM_DMA_PERIPHERAL_WIDTH | WS2812_PWM_DMA_MEMORY_WIDTH | AT32_DMA_CCTRL_MINCM | AT32_DMA_CCTRL_LM | AT32_DMA_CCTRL_CHPL(3));
#else
dmaStreamAlloc(WS2812_PWM_DMA_STREAM - STM32_DMA_STREAM(0), 10, NULL, NULL);
dmaStreamSetPeripheral(WS2812_PWM_DMA_STREAM, &(WS2812_PWM_DRIVER.tim->CCR[WS2812_PWM_CHANNEL - 1])); // Ziel ist der An-Zeit im Cap-Comp-Register
@@ -356,6 +356,11 @@ void ws2812_init(void) {
dmaSetRequestSource(WS2812_PWM_DMA_STREAM, WS2812_PWM_DMAMUX_ID);
#endif
+#if (AT32_DMA_SUPPORTS_DMAMUX == TRUE)
+ // If the MCU has a DMAMUX we need to assign the correct resource
+ dmaSetRequestSource(WS2812_PWM_DMA_STREAM, WS2812_PWM_DMAMUX_CHANNEL, WS2812_PWM_DMAMUX_ID);
+#endif
+
// Start DMA
dmaStreamEnable(WS2812_PWM_DMA_STREAM);
diff --git a/platforms/chibios/drivers/ws2812_spi.c b/platforms/chibios/drivers/ws2812_spi.c
index a1357edec57..d1792b871bf 100644
--- a/platforms/chibios/drivers/ws2812_spi.c
+++ b/platforms/chibios/drivers/ws2812_spi.c
@@ -40,26 +40,53 @@
// Define SPI config speed
// baudrate should target 3.2MHz
+#if defined(AT32F415)
+# if WS2812_SPI_DIVISOR == 2
+# define WS2812_SPI_DIVISOR_CTRL1_MDIV_X (0)
+# elif WS2812_SPI_DIVISOR == 4
+# define WS2812_SPI_DIVISOR_CTRL1_MDIV_X (SPI_CTRL1_MDIV_0)
+# elif WS2812_SPI_DIVISOR == 8
+# define WS2812_SPI_DIVISOR_CTRL1_MDIV_X (SPI_CTRL1_MDIV_1)
+# elif WS2812_SPI_DIVISOR == 16 // default
+# define WS2812_SPI_DIVISOR_CTRL1_MDIV_X (SPI_CTRL1_MDIV_1 | SPI_CTRL1_MDIV_0)
+# elif WS2812_SPI_DIVISOR == 32
+# define WS2812_SPI_DIVISOR_CTRL1_MDIV_X (SPI_CTRL1_MDIV_2)
+# elif WS2812_SPI_DIVISOR == 64
+# define WS2812_SPI_DIVISOR_CTRL1_MDIV_X (SPI_CTRL1_MDIV_2 | SPI_CTRL1_MDIV_0)
+# elif WS2812_SPI_DIVISOR == 128
+# define WS2812_SPI_DIVISOR_CTRL1_MDIV_X (SPI_CTRL1_MDIV_2 | SPI_CTRL1_MDIV_1)
+# elif WS2812_SPI_DIVISOR == 256
+# define WS2812_SPI_DIVISOR_CTRL1_MDIV_X (SPI_CTRL1_MDIV_2 | SPI_CTRL1_MDIV_1 | SPI_CTRL1_MDIV_0)
+# elif WS2812_SPI_DIVISOR == 512
+# define WS2812_SPI_DIVISOR_CTRL2_MDIV_X (SPI_CTRL1_MDIV_3)
+# elif WS2812_SPI_DIVISOR == 1024
+# define WS2812_SPI_DIVISOR_CTRL2_MDIV_X (SPI_CTRL1_MDIV_3)
+# define WS2812_SPI_DIVISOR_CTRL1_MDIV_X (SPI_CTRL1_MDIV_0)
+# else
+# error "Configured WS2812_SPI_DIVISOR value is not supported at this time."
+# endif
+#else
// F072 fpclk = 48MHz
// 48/16 = 3Mhz
-#if WS2812_SPI_DIVISOR == 2
-# define WS2812_SPI_DIVISOR_CR1_BR_X (0)
-#elif WS2812_SPI_DIVISOR == 4
-# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_0)
-#elif WS2812_SPI_DIVISOR == 8
-# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_1)
-#elif WS2812_SPI_DIVISOR == 16 // default
-# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_1 | SPI_CR1_BR_0)
-#elif WS2812_SPI_DIVISOR == 32
-# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2)
-#elif WS2812_SPI_DIVISOR == 64
-# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2 | SPI_CR1_BR_0)
-#elif WS2812_SPI_DIVISOR == 128
-# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2 | SPI_CR1_BR_1)
-#elif WS2812_SPI_DIVISOR == 256
-# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0)
-#else
-# error "Configured WS2812_SPI_DIVISOR value is not supported at this time."
+# if WS2812_SPI_DIVISOR == 2
+# define WS2812_SPI_DIVISOR_CR1_BR_X (0)
+# elif WS2812_SPI_DIVISOR == 4
+# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_0)
+# elif WS2812_SPI_DIVISOR == 8
+# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_1)
+# elif WS2812_SPI_DIVISOR == 16 // default
+# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_1 | SPI_CR1_BR_0)
+# elif WS2812_SPI_DIVISOR == 32
+# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2)
+# elif WS2812_SPI_DIVISOR == 64
+# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2 | SPI_CR1_BR_0)
+# elif WS2812_SPI_DIVISOR == 128
+# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2 | SPI_CR1_BR_1)
+# elif WS2812_SPI_DIVISOR == 256
+# define WS2812_SPI_DIVISOR_CR1_BR_X (SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0)
+# else
+# error "Configured WS2812_SPI_DIVISOR value is not supported at this time."
+# endif
#endif
// Use SPI circular buffer
@@ -176,8 +203,16 @@ void ws2812_init(void) {
NULL, // error_cb
PAL_PORT(WS2812_DI_PIN),
PAL_PAD(WS2812_DI_PIN),
+# if defined(AT32F415)
+ WS2812_SPI_DIVISOR_CTRL1_MDIV_X,
+# if (WS2812_SPI_DIVISOR == 512 || WS2812_SPI_DIVISOR == 1024)
+ WS2812_SPI_DIVISOR_CTRL2_MDIV_X,
+# endif
+ 0
+# else
WS2812_SPI_DIVISOR_CR1_BR_X,
0
+# endif
#endif
};
diff --git a/platforms/chibios/flash.mk b/platforms/chibios/flash.mk
index 525f177f9eb..f4db17a58bf 100644
--- a/platforms/chibios/flash.mk
+++ b/platforms/chibios/flash.mk
@@ -113,6 +113,8 @@ else ifeq ($(strip $(MCU_FAMILY)),STM32)
$(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL)
else ifeq ($(strip $(MCU_FAMILY)),WB32)
$(UNSYNC_OUTPUT_CMD) && $(call EXEC_WB32_DFU_UPDATER)
+else ifeq ($(strip $(MCU_FAMILY)),AT32)
+ $(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL)
else ifeq ($(strip $(MCU_FAMILY)),GD32V)
$(UNSYNC_OUTPUT_CMD) && $(call EXEC_DFU_UTIL)
else
diff --git a/platforms/chibios/mcu_selection.mk b/platforms/chibios/mcu_selection.mk
index a1597fa1e91..086a2b31c60 100644
--- a/platforms/chibios/mcu_selection.mk
+++ b/platforms/chibios/mcu_selection.mk
@@ -809,6 +809,40 @@ ifneq ($(findstring WB32FQ95, $(MCU)),)
WB32_BOOTLOADER_ADDRESS ?= 0x1FFFE000
endif
+ifneq ($(findstring AT32F415, $(MCU)),)
+ # Cortex version
+ MCU = cortex-m4
+
+ # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
+ ARMV = 7
+
+ ## chip/board settings
+ # - the next two should match the directories in
+ # /os/hal/ports/$(MCU_PORT_NAME)/$(MCU_SERIES)
+ # OR
+ # /os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
+ MCU_FAMILY = AT32
+ MCU_SERIES = AT32F415
+
+ # Linker script to use
+ # - it should exist either in /os/common/startup/ARMCMx/compilers/GCC/ld/
+ # or /ld/
+ MCU_LDSCRIPT ?= AT32F415xB
+
+ # Startup code to use
+ # - it should exist in /os/common/startup/ARMCMx/compilers/GCC/mk/
+ MCU_STARTUP ?= at32f415
+
+ # Board: it should exist either in /os/hal/boards/,
+ # /boards/, or drivers/boards/
+ BOARD ?= GENERIC_AT32_F415XX
+
+ USE_FPU ?= no
+
+ # Bootloader address for AT32 DFU
+ AT32_BOOTLOADER_ADDRESS ?= 0x1FFFAC00
+endif
+
ifneq ($(findstring GD32VF103, $(MCU)),)
# RISC-V
MCU = risc-v
diff --git a/platforms/chibios/platform.mk b/platforms/chibios/platform.mk
index 169707966ff..cf9fac251e4 100644
--- a/platforms/chibios/platform.mk
+++ b/platforms/chibios/platform.mk
@@ -155,6 +155,10 @@ ifdef WB32_BOOTLOADER_ADDRESS
OPT_DEFS += -DWB32_BOOTLOADER_ADDRESS=$(WB32_BOOTLOADER_ADDRESS)
endif
+ifdef AT32_BOOTLOADER_ADDRESS
+ OPT_DEFS += -DAT32_BOOTLOADER_ADDRESS=$(AT32_BOOTLOADER_ADDRESS)
+endif
+
# Work out if we need to set up the include for the bootloader definitions
ifneq ("$(wildcard $(KEYBOARD_PATH_5)/bootloader_defs.h)","")
OPT_DEFS += -include $(KEYBOARD_PATH_5)/bootloader_defs.h
diff --git a/platforms/chibios/timer.c b/platforms/chibios/timer.c
index 5e01ea63724..4a347b445d8 100644
--- a/platforms/chibios/timer.c
+++ b/platforms/chibios/timer.c
@@ -5,6 +5,7 @@
static uint32_t ticks_offset = 0;
static uint32_t last_ticks = 0;
static uint32_t ms_offset = 0;
+static uint32_t saved_ms = 0;
#if CH_CFG_ST_RESOLUTION < 32
static uint32_t last_systime = 0;
static uint32_t overflow = 0;
@@ -73,6 +74,26 @@ void timer_clear(void) {
chSysUnlock();
}
+__attribute__((weak)) void platform_timer_save_value(uint32_t value) {
+ saved_ms = value;
+}
+
+__attribute__((weak)) uint32_t platform_timer_restore_value(void) {
+ return saved_ms;
+}
+
+void timer_restore(void) {
+ chSysLock();
+ ticks_offset = get_system_time_ticks();
+ last_ticks = 0;
+ ms_offset = platform_timer_restore_value();
+ chSysUnlock();
+}
+
+void timer_save(void) {
+ platform_timer_save_value(timer_read32());
+}
+
uint16_t timer_read(void) {
return (uint16_t)timer_read32();
}
diff --git a/platforms/timer.h b/platforms/timer.h
index d55f40f0b0b..fb8ff6bc545 100644
--- a/platforms/timer.h
+++ b/platforms/timer.h
@@ -38,6 +38,8 @@ extern volatile uint32_t timer_count;
void timer_init(void);
void timer_clear(void);
+void timer_save(void);
+void timer_restore(void);
uint16_t timer_read(void);
uint32_t timer_read32(void);
uint16_t timer_elapsed(uint16_t last);
diff --git a/quantum/joystick.c b/quantum/joystick.c
index 32f19b2cd99..62893fd1997 100644
--- a/quantum/joystick.c
+++ b/quantum/joystick.c
@@ -29,6 +29,9 @@ joystick_t joystick_state = {
0
#endif
},
+#ifdef JOYSTICK_HAS_HAT
+ .hat = -1,
+#endif
.dirty = false,
};
@@ -145,6 +148,13 @@ void joystick_set_axis(uint8_t axis, int16_t value) {
}
}
+#ifdef JOYSTICK_HAS_HAT
+void joystick_set_hat(int8_t value) {
+ joystick_state.hat = value;
+ joystick_state.dirty = true;
+}
+#endif
+
void joystick_init(void) {
joystick_init_axes();
}
diff --git a/quantum/joystick.h b/quantum/joystick.h
index 5a69ceac64a..24f80c1ad6f 100644
--- a/quantum/joystick.h
+++ b/quantum/joystick.h
@@ -52,6 +52,16 @@
#define JOYSTICK_MAX_VALUE ((1L << (JOYSTICK_AXIS_RESOLUTION - 1)) - 1)
+#define JOYSTICK_HAT_CENTER -1
+#define JOYSTICK_HAT_NORTH 0
+#define JOYSTICK_HAT_NORTHEAST 1
+#define JOYSTICK_HAT_EAST 2
+#define JOYSTICK_HAT_SOUTHEAST 3
+#define JOYSTICK_HAT_SOUTH 4
+#define JOYSTICK_HAT_SOUTHWEST 5
+#define JOYSTICK_HAT_WEST 6
+#define JOYSTICK_HAT_NORTHWEST 7
+
// configure on input_pin of the joystick_axes array entry to NO_PIN
// to prevent it from being read from the ADC. This allows outputting forged axis value.
#define JOYSTICK_AXIS_VIRTUAL \
@@ -73,7 +83,10 @@ extern joystick_config_t joystick_axes[JOYSTICK_AXIS_COUNT];
typedef struct {
uint8_t buttons[(JOYSTICK_BUTTON_COUNT - 1) / 8 + 1];
int16_t axes[JOYSTICK_AXIS_COUNT];
- bool dirty;
+#ifdef JOYSTICK_HAS_HAT
+ int8_t hat;
+#endif
+ bool dirty;
} joystick_t;
extern joystick_t joystick_state;
@@ -129,4 +142,11 @@ void joystick_read_axes(void);
*/
void joystick_set_axis(uint8_t axis, int16_t value);
+/**
+ * \brief Set the position of the hat switch.
+ *
+ * \param value The hat switch position to set.
+ */
+void joystick_set_hat(int8_t value);
+
/** \} */
diff --git a/quantum/keyboard.c b/quantum/keyboard.c
index df1dc1c3ee0..d7836cf36e0 100644
--- a/quantum/keyboard.c
+++ b/quantum/keyboard.c
@@ -140,6 +140,9 @@ along with this program. If not, see .
#ifdef OS_DETECTION_ENABLE
# include "os_detection.h"
#endif
+#ifdef LAYER_LOCK_ENABLE
+# include "layer_lock.h"
+#endif
static uint32_t last_input_modification_time = 0;
uint32_t last_input_activity_time(void) {
@@ -655,6 +658,10 @@ void quantum_task(void) {
#ifdef SECURE_ENABLE
secure_task();
#endif
+
+#ifdef LAYER_LOCK_ENABLE
+ layer_lock_task();
+#endif
}
/** \brief Main task that is repeatedly called as fast as possible. */
diff --git a/quantum/keycodes.h b/quantum/keycodes.h
index 38127bb6da1..e9da5105ce4 100644
--- a/quantum/keycodes.h
+++ b/quantum/keycodes.h
@@ -622,12 +622,13 @@ enum qk_keycode_defines {
QK_MACRO_29 = 0x771D,
QK_MACRO_30 = 0x771E,
QK_MACRO_31 = 0x771F,
- QK_OUTPUT_NEXT = 0x7780,
- QK_OUTPUT_PREV = 0x7781,
- QK_OUTPUT_NONE = 0x7782,
- QK_OUTPUT_USB = 0x7783,
- QK_OUTPUT_2P4GHZ = 0x7784,
- QK_OUTPUT_BLUETOOTH = 0x7785,
+ QK_OUTPUT_AUTO = 0x7780,
+ QK_OUTPUT_NEXT = 0x7781,
+ QK_OUTPUT_PREV = 0x7782,
+ QK_OUTPUT_NONE = 0x7783,
+ QK_OUTPUT_USB = 0x7784,
+ QK_OUTPUT_2P4GHZ = 0x7785,
+ QK_OUTPUT_BLUETOOTH = 0x7786,
QK_BLUETOOTH_PROFILE_NEXT = 0x7790,
QK_BLUETOOTH_PROFILE_PREV = 0x7791,
QK_BLUETOOTH_UNPAIR = 0x7792,
@@ -758,6 +759,7 @@ enum qk_keycode_defines {
QK_TRI_LAYER_UPPER = 0x7C78,
QK_REPEAT_KEY = 0x7C79,
QK_ALT_REPEAT_KEY = 0x7C7A,
+ QK_LAYER_LOCK = 0x7C7B,
QK_KB_0 = 0x7E00,
QK_KB_1 = 0x7E01,
QK_KB_2 = 0x7E02,
@@ -1309,8 +1311,8 @@ enum qk_keycode_defines {
MC_29 = QK_MACRO_29,
MC_30 = QK_MACRO_30,
MC_31 = QK_MACRO_31,
+ OU_AUTO = QK_OUTPUT_AUTO,
OU_NEXT = QK_OUTPUT_NEXT,
- OU_AUTO = QK_OUTPUT_NEXT,
OU_PREV = QK_OUTPUT_PREV,
OU_NONE = QK_OUTPUT_NONE,
OU_USB = QK_OUTPUT_USB,
@@ -1444,6 +1446,7 @@ enum qk_keycode_defines {
TL_UPPR = QK_TRI_LAYER_UPPER,
QK_REP = QK_REPEAT_KEY,
QK_AREP = QK_ALT_REPEAT_KEY,
+ QK_LLCK = QK_LAYER_LOCK,
};
// Range Helpers
@@ -1494,13 +1497,13 @@ enum qk_keycode_defines {
#define IS_AUDIO_KEYCODE(code) ((code) >= QK_AUDIO_ON && (code) <= QK_AUDIO_VOICE_PREVIOUS)
#define IS_STENO_KEYCODE(code) ((code) >= QK_STENO_BOLT && (code) <= QK_STENO_COMB_MAX)
#define IS_MACRO_KEYCODE(code) ((code) >= QK_MACRO_0 && (code) <= QK_MACRO_31)
-#define IS_CONNECTION_KEYCODE(code) ((code) >= QK_OUTPUT_NEXT && (code) <= QK_BLUETOOTH_PROFILE5)
+#define IS_CONNECTION_KEYCODE(code) ((code) >= QK_OUTPUT_AUTO && (code) <= QK_BLUETOOTH_PROFILE5)
#define IS_BACKLIGHT_KEYCODE(code) ((code) >= QK_BACKLIGHT_ON && (code) <= QK_BACKLIGHT_TOGGLE_BREATHING)
#define IS_LED_MATRIX_KEYCODE(code) ((code) >= QK_LED_MATRIX_ON && (code) <= QK_LED_MATRIX_SPEED_DOWN)
#define IS_UNDERGLOW_KEYCODE(code) ((code) >= QK_UNDERGLOW_TOGGLE && (code) <= QK_UNDERGLOW_SPEED_DOWN)
#define IS_RGB_KEYCODE(code) ((code) >= RGB_MODE_PLAIN && (code) <= RGB_MODE_TWINKLE)
#define IS_RGB_MATRIX_KEYCODE(code) ((code) >= QK_RGB_MATRIX_ON && (code) <= QK_RGB_MATRIX_SPEED_DOWN)
-#define IS_QUANTUM_KEYCODE(code) ((code) >= QK_BOOTLOADER && (code) <= QK_ALT_REPEAT_KEY)
+#define IS_QUANTUM_KEYCODE(code) ((code) >= QK_BOOTLOADER && (code) <= QK_LAYER_LOCK)
#define IS_KB_KEYCODE(code) ((code) >= QK_KB_0 && (code) <= QK_KB_31)
#define IS_USER_KEYCODE(code) ((code) >= QK_USER_0 && (code) <= QK_USER_31)
@@ -1520,12 +1523,12 @@ enum qk_keycode_defines {
#define AUDIO_KEYCODE_RANGE QK_AUDIO_ON ... QK_AUDIO_VOICE_PREVIOUS
#define STENO_KEYCODE_RANGE QK_STENO_BOLT ... QK_STENO_COMB_MAX
#define MACRO_KEYCODE_RANGE QK_MACRO_0 ... QK_MACRO_31
-#define CONNECTION_KEYCODE_RANGE QK_OUTPUT_NEXT ... QK_BLUETOOTH_PROFILE5
+#define CONNECTION_KEYCODE_RANGE QK_OUTPUT_AUTO ... QK_BLUETOOTH_PROFILE5
#define BACKLIGHT_KEYCODE_RANGE QK_BACKLIGHT_ON ... QK_BACKLIGHT_TOGGLE_BREATHING
#define LED_MATRIX_KEYCODE_RANGE QK_LED_MATRIX_ON ... QK_LED_MATRIX_SPEED_DOWN
#define UNDERGLOW_KEYCODE_RANGE QK_UNDERGLOW_TOGGLE ... QK_UNDERGLOW_SPEED_DOWN
#define RGB_KEYCODE_RANGE RGB_MODE_PLAIN ... RGB_MODE_TWINKLE
#define RGB_MATRIX_KEYCODE_RANGE QK_RGB_MATRIX_ON ... QK_RGB_MATRIX_SPEED_DOWN
-#define QUANTUM_KEYCODE_RANGE QK_BOOTLOADER ... QK_ALT_REPEAT_KEY
+#define QUANTUM_KEYCODE_RANGE QK_BOOTLOADER ... QK_LAYER_LOCK
#define KB_KEYCODE_RANGE QK_KB_0 ... QK_KB_31
#define USER_KEYCODE_RANGE QK_USER_0 ... QK_USER_31
diff --git a/quantum/layer_lock.c b/quantum/layer_lock.c
new file mode 100644
index 00000000000..9fc84bcfca1
--- /dev/null
+++ b/quantum/layer_lock.c
@@ -0,0 +1,100 @@
+// Copyright 2022-2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "layer_lock.h"
+#include "quantum_keycodes.h"
+
+#ifndef NO_ACTION_LAYER
+// The current lock state. The kth bit is on if layer k is locked.
+layer_state_t locked_layers = 0;
+
+// Layer Lock timer to disable layer lock after X seconds inactivity
+# if defined(LAYER_LOCK_IDLE_TIMEOUT) && LAYER_LOCK_IDLE_TIMEOUT > 0
+uint32_t layer_lock_timer = 0;
+
+void layer_lock_timeout_task(void) {
+ if (locked_layers && timer_elapsed32(layer_lock_timer) > LAYER_LOCK_IDLE_TIMEOUT) {
+ layer_lock_all_off();
+ layer_lock_timer = timer_read32();
+ }
+}
+void layer_lock_activity_trigger(void) {
+ layer_lock_timer = timer_read32();
+}
+# else
+void layer_lock_timeout_task(void) {}
+void layer_lock_activity_trigger(void) {}
+# endif // LAYER_LOCK_IDLE_TIMEOUT > 0
+
+bool is_layer_locked(uint8_t layer) {
+ return locked_layers & ((layer_state_t)1 << layer);
+}
+
+void layer_lock_invert(uint8_t layer) {
+ const layer_state_t mask = (layer_state_t)1 << layer;
+ if ((locked_layers & mask) == 0) { // Layer is being locked.
+# ifndef NO_ACTION_ONESHOT
+ if (layer == get_oneshot_layer()) {
+ reset_oneshot_layer(); // Reset so that OSL doesn't turn layer off.
+ }
+# endif // NO_ACTION_ONESHOT
+ layer_on(layer);
+ layer_lock_activity_trigger();
+ } else { // Layer is being unlocked.
+ layer_off(layer);
+ }
+ layer_lock_set_kb(locked_layers ^= mask);
+}
+
+// Implement layer_lock_on/off by deferring to layer_lock_invert.
+void layer_lock_on(uint8_t layer) {
+ if (!is_layer_locked(layer)) {
+ layer_lock_invert(layer);
+ }
+}
+
+void layer_lock_off(uint8_t layer) {
+ if (is_layer_locked(layer)) {
+ layer_lock_invert(layer);
+ }
+}
+
+void layer_lock_all_off(void) {
+ layer_and(~locked_layers);
+ locked_layers = 0;
+ layer_lock_set_kb(locked_layers);
+}
+
+#else // NO_ACTION_LAYER
+bool is_layer_locked(uint8_t layer) {
+ return false;
+}
+void layer_lock_on(uint8_t layer) {}
+void layer_lock_off(uint8_t layer) {}
+void layer_lock_all_off(void) {}
+void layer_lock_invert(uint8_t layer) {}
+void layer_lock_timeout_task(void) {}
+void layer_lock_activity_trigger(void) {}
+#endif // NO_ACTION_LAYER
+
+__attribute__((weak)) bool layer_lock_set_kb(layer_state_t locked_layers) {
+ return layer_lock_set_user(locked_layers);
+}
+__attribute__((weak)) bool layer_lock_set_user(layer_state_t locked_layers) {
+ return true;
+}
+
+void layer_lock_task(void) {
+ layer_lock_timeout_task();
+}
diff --git a/quantum/layer_lock.h b/quantum/layer_lock.h
new file mode 100644
index 00000000000..97f6c60d70d
--- /dev/null
+++ b/quantum/layer_lock.h
@@ -0,0 +1,98 @@
+// Copyright 2022-2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ * @file layer_lock.h
+ * @brief Layer Lock, a key to stay in the current layer.
+ *
+ * Overview
+ * --------
+ *
+ * Layers are often accessed by holding a button, e.g. with a momentary layer
+ * switch `MO(layer)` or layer tap `LT(layer, key)` key. But you may sometimes
+ * want to "lock" or "toggle" the layer so that it stays on without having to
+ * hold down a button. One way to do that is with a tap-toggle `TT` layer key,
+ * but here is an alternative.
+ *
+ * This library implements a "Layer Lock key". When tapped, it "locks" the
+ * highest layer to stay active, assuming the layer was activated by one of the
+ * following keys:
+ *
+ * * `MO(layer)` momentary layer switch
+ * * `LT(layer, key)` layer tap
+ * * `OSL(layer)` one-shot layer
+ * * `TT(layer)` layer tap toggle
+ * * `LM(layer, mod)` layer-mod key (the layer is locked, but not the mods)
+ *
+ * Tapping the Layer Lock key again unlocks and turns off the layer.
+ *
+ * @note When a layer is "locked", other layer keys such as `TO(layer)` or
+ * manually calling `layer_off(layer)` will override and unlock the layer.
+ *
+ * Configuration
+ * -------------
+ *
+ * Optionally, a timeout may be defined so that Layer Lock disables
+ * automatically if not keys are pressed for `LAYER_LOCK_IDLE_TIMEOUT`
+ * milliseconds. Define `LAYER_LOCK_IDLE_TIMEOUT` in your config.h, for instance
+ *
+ * #define LAYER_LOCK_IDLE_TIMEOUT 60000 // Turn off after 60 seconds.
+ *
+ * For full documentation, see
+ *
+ */
+
+#pragma once
+
+#include
+#include
+#include "action_layer.h"
+#include "action_util.h"
+
+/** Returns true if `layer` is currently locked. */
+bool is_layer_locked(uint8_t layer);
+
+/** Locks and turns on `layer`. */
+void layer_lock_on(uint8_t layer);
+
+/** Unlocks and turns off `layer`. */
+void layer_lock_off(uint8_t layer);
+
+/** Unlocks and turns off all locked layers. */
+void layer_lock_all_off(void);
+
+/** Toggles whether `layer` is locked. */
+void layer_lock_invert(uint8_t layer);
+
+/**
+ * Optional callback that gets called when a layer is locked or unlocked.
+ *
+ * This is useful to represent the current lock state, e.g. by setting an LED or
+ * playing a sound. In your keymap, define
+ *
+ * void layer_lock_set_user(layer_state_t locked_layers) {
+ * // Do something like `set_led(is_layer_locked(NAV));`
+ * }
+ *
+ * @param locked_layers Bitfield in which the kth bit represents whether the
+ * kth layer is on.
+ */
+bool layer_lock_set_kb(layer_state_t locked_layers);
+bool layer_lock_set_user(layer_state_t locked_layers);
+
+/** Handle various background tasks */
+void layer_lock_task(void);
+
+/** Update any configured timeouts */
+void layer_lock_activity_trigger(void);
diff --git a/quantum/led_matrix/animations/breathing_anim.h b/quantum/led_matrix/animations/breathing_anim.h
index 0bd4cb0cc38..3d1b0d95d21 100644
--- a/quantum/led_matrix/animations/breathing_anim.h
+++ b/quantum/led_matrix/animations/breathing_anim.h
@@ -2,17 +2,12 @@
LED_MATRIX_EFFECT(BREATHING)
# ifdef LED_MATRIX_CUSTOM_EFFECT_IMPLS
-bool BREATHING(effect_params_t* params) {
- LED_MATRIX_USE_LIMITS(led_min, led_max);
+static uint8_t BREATHING_math(uint8_t val, uint8_t i, uint8_t time) {
+ return scale8(abs8(sin8(time / 2) - 128) * 2, val);
+}
- uint8_t val = led_matrix_eeconfig.val;
- uint16_t time = scale16by8(g_led_timer, led_matrix_eeconfig.speed / 8);
- val = scale8(abs8(sin8(time) - 128) * 2, val);
- for (uint8_t i = led_min; i < led_max; i++) {
- LED_MATRIX_TEST_LED_FLAGS();
- led_matrix_set_value(i, val);
- }
- return led_matrix_check_finished_leds(led_max);
+bool BREATHING(effect_params_t* params) {
+ return effect_runner_i(params, &BREATHING_math);
}
# endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS
diff --git a/quantum/pointing_device/pointing_device.c b/quantum/pointing_device/pointing_device.c
index 7d3be9e524f..cac2875fc8d 100644
--- a/quantum/pointing_device/pointing_device.c
+++ b/quantum/pointing_device/pointing_device.c
@@ -79,7 +79,28 @@ uint16_t pointing_device_get_shared_cpi(void) {
static report_mouse_t local_mouse_report = {};
static bool pointing_device_force_send = false;
-extern const pointing_device_driver_t pointing_device_driver;
+#define POINTING_DEVICE_DRIVER_CONCAT(name) name##_pointing_device_driver
+#define POINTING_DEVICE_DRIVER(name) POINTING_DEVICE_DRIVER_CONCAT(name)
+
+#ifdef POINTING_DEVICE_DRIVER_custom
+__attribute__((weak)) void pointing_device_driver_init(void) {}
+__attribute__((weak)) report_mouse_t pointing_device_driver_get_report(report_mouse_t mouse_report) {
+ return mouse_report;
+}
+__attribute__((weak)) uint16_t pointing_device_driver_get_cpi(void) {
+ return 0;
+}
+__attribute__((weak)) void pointing_device_driver_set_cpi(uint16_t cpi) {}
+
+const pointing_device_driver_t custom_pointing_device_driver = {
+ .init = pointing_device_driver_init,
+ .get_report = pointing_device_driver_get_report,
+ .get_cpi = pointing_device_driver_get_cpi,
+ .set_cpi = pointing_device_driver_set_cpi,
+};
+#endif
+
+const pointing_device_driver_t *pointing_device_driver = &POINTING_DEVICE_DRIVER(POINTING_DEVICE_DRIVER_NAME);
/**
* @brief Keyboard level code pointing device initialisation
@@ -146,7 +167,7 @@ __attribute__((weak)) void pointing_device_init(void) {
if ((POINTING_DEVICE_THIS_SIDE))
#endif
{
- pointing_device_driver.init();
+ pointing_device_driver->init();
#ifdef POINTING_DEVICE_MOTION_PIN
# ifdef POINTING_DEVICE_MOTION_PIN_ACTIVE_LOW
gpio_set_pin_input_high(POINTING_DEVICE_MOTION_PIN);
@@ -258,15 +279,15 @@ __attribute__((weak)) bool pointing_device_task(void) {
# if defined(POINTING_DEVICE_COMBINED)
static uint8_t old_buttons = 0;
local_mouse_report.buttons = old_buttons;
- local_mouse_report = pointing_device_driver.get_report(local_mouse_report);
+ local_mouse_report = pointing_device_driver->get_report(local_mouse_report);
old_buttons = local_mouse_report.buttons;
# elif defined(POINTING_DEVICE_LEFT) || defined(POINTING_DEVICE_RIGHT)
- local_mouse_report = POINTING_DEVICE_THIS_SIDE ? pointing_device_driver.get_report(local_mouse_report) : shared_mouse_report;
+ local_mouse_report = POINTING_DEVICE_THIS_SIDE ? pointing_device_driver->get_report(local_mouse_report) : shared_mouse_report;
# else
# error "You need to define the side(s) the pointing device is on. POINTING_DEVICE_COMBINED / POINTING_DEVICE_LEFT / POINTING_DEVICE_RIGHT"
# endif
#else
- local_mouse_report = pointing_device_driver.get_report(local_mouse_report);
+ local_mouse_report = pointing_device_driver->get_report(local_mouse_report);
#endif // defined(SPLIT_POINTING_ENABLE)
#ifdef POINTING_DEVICE_MOTION_PIN
@@ -331,9 +352,9 @@ void pointing_device_set_report(report_mouse_t mouse_report) {
*/
uint16_t pointing_device_get_cpi(void) {
#if defined(SPLIT_POINTING_ENABLE)
- return POINTING_DEVICE_THIS_SIDE ? pointing_device_driver.get_cpi() : shared_cpi;
+ return POINTING_DEVICE_THIS_SIDE ? pointing_device_driver->get_cpi() : shared_cpi;
#else
- return pointing_device_driver.get_cpi();
+ return pointing_device_driver->get_cpi();
#endif
}
@@ -347,12 +368,12 @@ uint16_t pointing_device_get_cpi(void) {
void pointing_device_set_cpi(uint16_t cpi) {
#if defined(SPLIT_POINTING_ENABLE)
if (POINTING_DEVICE_THIS_SIDE) {
- pointing_device_driver.set_cpi(cpi);
+ pointing_device_driver->set_cpi(cpi);
} else {
shared_cpi = cpi;
}
#else
- pointing_device_driver.set_cpi(cpi);
+ pointing_device_driver->set_cpi(cpi);
#endif
}
@@ -370,7 +391,7 @@ void pointing_device_set_cpi(uint16_t cpi) {
void pointing_device_set_cpi_on_side(bool left, uint16_t cpi) {
bool local = (is_keyboard_left() == left);
if (local) {
- pointing_device_driver.set_cpi(cpi);
+ pointing_device_driver->set_cpi(cpi);
} else {
shared_cpi = cpi;
}
diff --git a/quantum/pointing_device/pointing_device.h b/quantum/pointing_device/pointing_device.h
index b0f8533d6d0..72188c977dd 100644
--- a/quantum/pointing_device/pointing_device.h
+++ b/quantum/pointing_device/pointing_device.h
@@ -21,6 +21,13 @@ along with this program. If not, see .
#include "host.h"
#include "report.h"
+typedef struct {
+ void (*init)(void);
+ report_mouse_t (*get_report)(report_mouse_t mouse_report);
+ void (*set_cpi)(uint16_t);
+ uint16_t (*get_cpi)(void);
+} pointing_device_driver_t;
+
#ifdef POINTING_DEVICE_AUTO_MOUSE_ENABLE
# include "pointing_device_auto_mouse.h"
#endif
@@ -44,7 +51,6 @@ along with this program. If not, see .
# include "drivers/sensors/azoteq_iqs5xx.h"
#elif defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_i2c) || defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_spi)
# include "drivers/sensors/cirque_pinnacle.h"
-# include "drivers/sensors/cirque_pinnacle_gestures.h"
# include "pointing_device_gestures.h"
#elif defined(POINTING_DEVICE_DRIVER_paw3204)
# include "drivers/sensors/paw3204.h"
@@ -74,13 +80,6 @@ uint16_t pointing_device_driver_get_cpi(void);
void pointing_device_driver_set_cpi(uint16_t cpi);
#endif
-typedef struct {
- void (*init)(void);
- report_mouse_t (*get_report)(report_mouse_t mouse_report);
- void (*set_cpi)(uint16_t);
- uint16_t (*get_cpi)(void);
-} pointing_device_driver_t;
-
typedef enum {
POINTING_DEVICE_BUTTON1,
POINTING_DEVICE_BUTTON2,
@@ -112,6 +111,9 @@ typedef int32_t hv_clamp_range_t;
typedef int16_t hv_clamp_range_t;
#endif
+#define CONSTRAIN_HID(amt) ((amt) < INT8_MIN ? INT8_MIN : ((amt) > INT8_MAX ? INT8_MAX : (amt)))
+#define CONSTRAIN_HID_XY(amt) ((amt) < XY_REPORT_MIN ? XY_REPORT_MIN : ((amt) > XY_REPORT_MAX ? XY_REPORT_MAX : (amt)))
+
void pointing_device_init(void);
bool pointing_device_task(void);
bool pointing_device_send(void);
diff --git a/quantum/pointing_device/pointing_device_drivers.c b/quantum/pointing_device/pointing_device_drivers.c
deleted file mode 100644
index 6cbe427401e..00000000000
--- a/quantum/pointing_device/pointing_device_drivers.c
+++ /dev/null
@@ -1,514 +0,0 @@
-/* Copyright 2017 Joshua Broekhuijsen
- * Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna)
- * Copyright 2021 Dasky (@daskygit)
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#include "pointing_device.h"
-#include "pointing_device_internal.h"
-#include "debug.h"
-#include "wait.h"
-#include "timer.h"
-#include
-
-#define CONSTRAIN_HID(amt) ((amt) < INT8_MIN ? INT8_MIN : ((amt) > INT8_MAX ? INT8_MAX : (amt)))
-#define CONSTRAIN_HID_XY(amt) ((amt) < XY_REPORT_MIN ? XY_REPORT_MIN : ((amt) > XY_REPORT_MAX ? XY_REPORT_MAX : (amt)))
-
-// get_report functions should probably be moved to their respective drivers.
-
-#if defined(POINTING_DEVICE_DRIVER_adns5050)
-report_mouse_t adns5050_get_report(report_mouse_t mouse_report) {
- report_adns5050_t data = adns5050_read_burst();
-
- if (data.dx != 0 || data.dy != 0) {
- pd_dprintf("Raw ] X: %d, Y: %d\n", data.dx, data.dy);
- mouse_report.x = (mouse_xy_report_t)data.dx;
- mouse_report.y = (mouse_xy_report_t)data.dy;
- }
-
- return mouse_report;
-}
-
-// clang-format off
-const pointing_device_driver_t pointing_device_driver = {
- .init = adns5050_init,
- .get_report = adns5050_get_report,
- .set_cpi = adns5050_set_cpi,
- .get_cpi = adns5050_get_cpi,
-};
-// clang-format on
-
-#elif defined(POINTING_DEVICE_DRIVER_pmw3320)
-report_mouse_t pmw3320_get_report(report_mouse_t mouse_report) {
- report_pmw3320_t data = pmw3320_read_burst();
-
- if (data.dx != 0 || data.dy != 0) {
- pd_dprintf("Raw ] X: %d, Y: %d\n", data.dx, data.dy);
- mouse_report.x = (mouse_xy_report_t)data.dx;
- mouse_report.y = (mouse_xy_report_t)data.dy;
- }
-
- return mouse_report;
-}
-
-// clang-format off
-const pointing_device_driver_t pointing_device_driver = {
- .init = pmw3320_init,
- .get_report = pmw3320_get_report,
- .set_cpi = pmw3320_set_cpi,
- .get_cpi = pmw3320_get_cpi,
-};
-// clang-format on
-
-#elif defined(POINTING_DEVICE_DRIVER_adns9800)
-
-report_mouse_t adns9800_get_report_driver(report_mouse_t mouse_report) {
- report_adns9800_t sensor_report = adns9800_get_report();
-
- mouse_report.x = CONSTRAIN_HID_XY(sensor_report.x);
- mouse_report.y = CONSTRAIN_HID_XY(sensor_report.y);
-
- return mouse_report;
-}
-
-// clang-format off
-const pointing_device_driver_t pointing_device_driver = {
- .init = adns9800_init,
- .get_report = adns9800_get_report_driver,
- .set_cpi = adns9800_set_cpi,
- .get_cpi = adns9800_get_cpi
-};
-// clang-format on
-
-#elif defined(POINTING_DEVICE_DRIVER_analog_joystick)
-report_mouse_t analog_joystick_get_report(report_mouse_t mouse_report) {
- report_analog_joystick_t data = analog_joystick_read();
-
- pd_dprintf("Raw ] X: %d, Y: %d\n", data.x, data.y);
-
- mouse_report.x = data.x;
- mouse_report.y = data.y;
-
- mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, data.button, POINTING_DEVICE_BUTTON1);
-
- return mouse_report;
-}
-
-// clang-format off
-const pointing_device_driver_t pointing_device_driver = {
- .init = analog_joystick_init,
- .get_report = analog_joystick_get_report,
- .set_cpi = NULL,
- .get_cpi = NULL
-};
-// clang-format on
-
-#elif defined(POINTING_DEVICE_DRIVER_azoteq_iqs5xx)
-
-static i2c_status_t azoteq_iqs5xx_init_status = 1;
-
-void azoteq_iqs5xx_init(void) {
- i2c_init();
- azoteq_iqs5xx_wake();
- azoteq_iqs5xx_reset_suspend(true, false, true);
- wait_ms(100);
- azoteq_iqs5xx_wake();
- if (azoteq_iqs5xx_get_product() != AZOTEQ_IQS5XX_UNKNOWN) {
- azoteq_iqs5xx_setup_resolution();
- azoteq_iqs5xx_init_status = azoteq_iqs5xx_set_report_rate(AZOTEQ_IQS5XX_REPORT_RATE, AZOTEQ_IQS5XX_ACTIVE, false);
- azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_event_mode(false, false);
- azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_reati(true, false);
-# if defined(AZOTEQ_IQS5XX_ROTATION_90)
- azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_xy_config(false, true, true, true, false);
-# elif defined(AZOTEQ_IQS5XX_ROTATION_180)
- azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_xy_config(true, true, false, true, false);
-# elif defined(AZOTEQ_IQS5XX_ROTATION_270)
- azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_xy_config(true, false, true, true, false);
-# else
- azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_xy_config(false, false, false, true, false);
-# endif
- azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_gesture_config(true);
- wait_ms(AZOTEQ_IQS5XX_REPORT_RATE + 1);
- }
-};
-
-report_mouse_t azoteq_iqs5xx_get_report(report_mouse_t mouse_report) {
- report_mouse_t temp_report = {0};
- static uint8_t previous_button_state = 0;
- static uint8_t read_error_count = 0;
-
- if (azoteq_iqs5xx_init_status == I2C_STATUS_SUCCESS) {
- azoteq_iqs5xx_base_data_t base_data = {0};
-# if !defined(POINTING_DEVICE_MOTION_PIN)
- azoteq_iqs5xx_wake();
-# endif
- i2c_status_t status = azoteq_iqs5xx_get_base_data(&base_data);
- bool ignore_movement = false;
-
- if (status == I2C_STATUS_SUCCESS) {
- // pd_dprintf("IQS5XX - previous cycle time: %d \n", base_data.previous_cycle_time);
- read_error_count = 0;
- if (base_data.gesture_events_0.single_tap || base_data.gesture_events_0.press_and_hold) {
- pd_dprintf("IQS5XX - Single tap/hold.\n");
- temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON1);
- } else if (base_data.gesture_events_1.two_finger_tap) {
- pd_dprintf("IQS5XX - Two finger tap.\n");
- temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON2);
- } else if (base_data.gesture_events_0.swipe_x_neg) {
- pd_dprintf("IQS5XX - X-.\n");
- temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON4);
- ignore_movement = true;
- } else if (base_data.gesture_events_0.swipe_x_pos) {
- pd_dprintf("IQS5XX - X+.\n");
- temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON5);
- ignore_movement = true;
- } else if (base_data.gesture_events_0.swipe_y_neg) {
- pd_dprintf("IQS5XX - Y-.\n");
- temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON6);
- ignore_movement = true;
- } else if (base_data.gesture_events_0.swipe_y_pos) {
- pd_dprintf("IQS5XX - Y+.\n");
- temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON3);
- ignore_movement = true;
- } else if (base_data.gesture_events_1.zoom) {
- if (AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.x.h, base_data.x.l) < 0) {
- pd_dprintf("IQS5XX - Zoom out.\n");
- temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON7);
- } else if (AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.x.h, base_data.x.l) > 0) {
- pd_dprintf("IQS5XX - Zoom in.\n");
- temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON8);
- }
- } else if (base_data.gesture_events_1.scroll) {
- pd_dprintf("IQS5XX - Scroll.\n");
- temp_report.h = CONSTRAIN_HID(AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.x.h, base_data.x.l));
- temp_report.v = CONSTRAIN_HID(AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.y.h, base_data.y.l));
- }
- if (base_data.number_of_fingers == 1 && !ignore_movement) {
- temp_report.x = CONSTRAIN_HID_XY(AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.x.h, base_data.x.l));
- temp_report.y = CONSTRAIN_HID_XY(AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.y.h, base_data.y.l));
- }
-
- previous_button_state = temp_report.buttons;
-
- } else {
- if (read_error_count > 10) {
- read_error_count = 0;
- previous_button_state = 0;
- } else {
- read_error_count++;
- }
- temp_report.buttons = previous_button_state;
- pd_dprintf("IQS5XX - get report failed: %d \n", status);
- }
- } else {
- pd_dprintf("IQS5XX - Init failed: %d \n", azoteq_iqs5xx_init_status);
- }
-
- return temp_report;
-}
-
-// clang-format off
-const pointing_device_driver_t pointing_device_driver = {
- .init = azoteq_iqs5xx_init,
- .get_report = azoteq_iqs5xx_get_report,
- .set_cpi = azoteq_iqs5xx_set_cpi,
- .get_cpi = azoteq_iqs5xx_get_cpi
-};
-// clang-format on
-
-#elif defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_i2c) || defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_spi)
-# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE
-static bool cursor_glide_enable = true;
-
-static cursor_glide_context_t glide = {.config = {
- .coef = 102, /* Good default friction coef */
- .interval = 10, /* 100sps */
- .trigger_px = 10, /* Default threshold in case of hover, set to 0 if you'd like */
- }};
-
-void cirque_pinnacle_enable_cursor_glide(bool enable) {
- cursor_glide_enable = enable;
-}
-
-void cirque_pinnacle_configure_cursor_glide(float trigger_px) {
- glide.config.trigger_px = trigger_px;
-}
-# endif
-
-# if CIRQUE_PINNACLE_POSITION_MODE
-
-# ifdef POINTING_DEVICE_AUTO_MOUSE_ENABLE
-static bool is_touch_down;
-
-bool auto_mouse_activation(report_mouse_t mouse_report) {
- return is_touch_down || mouse_report.x != 0 || mouse_report.y != 0 || mouse_report.h != 0 || mouse_report.v != 0 || mouse_report.buttons;
-}
-# endif
-
-report_mouse_t cirque_pinnacle_get_report(report_mouse_t mouse_report) {
- uint16_t scale = cirque_pinnacle_get_scale();
- pinnacle_data_t touchData = cirque_pinnacle_read_data();
- mouse_xy_report_t report_x = 0, report_y = 0;
- static uint16_t x = 0, y = 0, last_scale = 0;
-
-# if defined(CIRQUE_PINNACLE_TAP_ENABLE)
- mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, false, POINTING_DEVICE_BUTTON1);
-# endif
-# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE
- cursor_glide_t glide_report = {0};
-
- if (cursor_glide_enable) {
- glide_report = cursor_glide_check(&glide);
- }
-# endif
-
- if (!touchData.valid) {
-# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE
- if (cursor_glide_enable && glide_report.valid) {
- report_x = glide_report.dx;
- report_y = glide_report.dy;
- goto mouse_report_update;
- }
-# endif
- return mouse_report;
- }
-
- if (touchData.touchDown) {
- pd_dprintf("cirque_pinnacle touchData x=%4d y=%4d z=%2d\n", touchData.xValue, touchData.yValue, touchData.zValue);
- }
-
-# ifdef POINTING_DEVICE_AUTO_MOUSE_ENABLE
- is_touch_down = touchData.touchDown;
-# endif
-
- // Scale coordinates to arbitrary X, Y resolution
- cirque_pinnacle_scale_data(&touchData, scale, scale);
-
- if (!cirque_pinnacle_gestures(&mouse_report, touchData)) {
- if (last_scale && scale == last_scale && x && y && touchData.xValue && touchData.yValue) {
- report_x = CONSTRAIN_HID_XY((int16_t)(touchData.xValue - x));
- report_y = CONSTRAIN_HID_XY((int16_t)(touchData.yValue - y));
- }
- x = touchData.xValue;
- y = touchData.yValue;
- last_scale = scale;
-
-# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE
- if (cursor_glide_enable) {
- if (touchData.touchDown) {
- cursor_glide_update(&glide, report_x, report_y, touchData.zValue);
- } else if (!glide_report.valid) {
- glide_report = cursor_glide_start(&glide);
- if (glide_report.valid) {
- report_x = glide_report.dx;
- report_y = glide_report.dy;
- }
- }
- }
-# endif
- }
-
-# ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE
-mouse_report_update:
-# endif
- mouse_report.x = report_x;
- mouse_report.y = report_y;
-
- return mouse_report;
-}
-
-uint16_t cirque_pinnacle_get_cpi(void) {
- return CIRQUE_PINNACLE_PX_TO_INCH(cirque_pinnacle_get_scale());
-}
-void cirque_pinnacle_set_cpi(uint16_t cpi) {
- cirque_pinnacle_set_scale(CIRQUE_PINNACLE_INCH_TO_PX(cpi));
-}
-
-// clang-format off
-const pointing_device_driver_t pointing_device_driver = {
- .init = cirque_pinnacle_init,
- .get_report = cirque_pinnacle_get_report,
- .set_cpi = cirque_pinnacle_set_cpi,
- .get_cpi = cirque_pinnacle_get_cpi
-};
-// clang-format on
-# else
-report_mouse_t cirque_pinnacle_get_report(report_mouse_t mouse_report) {
- pinnacle_data_t touchData = cirque_pinnacle_read_data();
-
- // Scale coordinates to arbitrary X, Y resolution
- cirque_pinnacle_scale_data(&touchData, cirque_pinnacle_get_scale(), cirque_pinnacle_get_scale());
-
- if (touchData.valid) {
- mouse_report.buttons = touchData.buttons;
- mouse_report.x = CONSTRAIN_HID_XY(touchData.xDelta);
- mouse_report.y = CONSTRAIN_HID_XY(touchData.yDelta);
- mouse_report.v = touchData.wheelCount;
- }
- return mouse_report;
-}
-
-// clang-format off
-const pointing_device_driver_t pointing_device_driver = {
- .init = cirque_pinnacle_init,
- .get_report = cirque_pinnacle_get_report,
- .set_cpi = cirque_pinnacle_set_scale,
- .get_cpi = cirque_pinnacle_get_scale
-};
-// clang-format on
-# endif
-
-#elif defined(POINTING_DEVICE_DRIVER_paw3204)
-
-report_mouse_t paw3204_get_report(report_mouse_t mouse_report) {
- report_paw3204_t data = paw3204_read();
- if (data.isMotion) {
- pd_dprintf("Raw ] X: %d, Y: %d\n", data.x, data.y);
-
- mouse_report.x = data.x;
- mouse_report.y = data.y;
- }
-
- return mouse_report;
-}
-const pointing_device_driver_t pointing_device_driver = {
- .init = paw3204_init,
- .get_report = paw3204_get_report,
- .set_cpi = paw3204_set_cpi,
- .get_cpi = paw3204_get_cpi,
-};
-#elif defined(POINTING_DEVICE_DRIVER_pimoroni_trackball)
-
-mouse_xy_report_t pimoroni_trackball_adapt_values(xy_clamp_range_t* offset) {
- if (*offset > XY_REPORT_MAX) {
- *offset -= XY_REPORT_MAX;
- return (mouse_xy_report_t)XY_REPORT_MAX;
- } else if (*offset < XY_REPORT_MIN) {
- *offset += XY_REPORT_MAX;
- return (mouse_xy_report_t)XY_REPORT_MIN;
- } else {
- mouse_xy_report_t temp_return = *offset;
- *offset = 0;
- return temp_return;
- }
-}
-
-report_mouse_t pimoroni_trackball_get_report(report_mouse_t mouse_report) {
- static uint16_t debounce = 0;
- static uint8_t error_count = 0;
- pimoroni_data_t pimoroni_data = {0};
- static xy_clamp_range_t x_offset = 0, y_offset = 0;
-
- if (error_count < PIMORONI_TRACKBALL_ERROR_COUNT) {
- i2c_status_t status = read_pimoroni_trackball(&pimoroni_data);
-
- if (status == I2C_STATUS_SUCCESS) {
- error_count = 0;
-
- if (!(pimoroni_data.click & 128)) {
- mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, false, POINTING_DEVICE_BUTTON1);
- if (!debounce) {
- x_offset += pimoroni_trackball_get_offsets(pimoroni_data.right, pimoroni_data.left, PIMORONI_TRACKBALL_SCALE);
- y_offset += pimoroni_trackball_get_offsets(pimoroni_data.down, pimoroni_data.up, PIMORONI_TRACKBALL_SCALE);
- mouse_report.x = pimoroni_trackball_adapt_values(&x_offset);
- mouse_report.y = pimoroni_trackball_adapt_values(&y_offset);
- } else {
- debounce--;
- }
- } else {
- mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, true, POINTING_DEVICE_BUTTON1);
- debounce = PIMORONI_TRACKBALL_DEBOUNCE_CYCLES;
- }
- } else {
- error_count++;
- }
- }
- return mouse_report;
-}
-
-// clang-format off
-const pointing_device_driver_t pointing_device_driver = {
- .init = pimoroni_trackball_device_init,
- .get_report = pimoroni_trackball_get_report,
- .set_cpi = pimoroni_trackball_set_cpi,
- .get_cpi = pimoroni_trackball_get_cpi
-};
-// clang-format on
-
-#elif defined(POINTING_DEVICE_DRIVER_pmw3360) || defined(POINTING_DEVICE_DRIVER_pmw3389)
-static void pmw33xx_init_wrapper(void) {
- pmw33xx_init(0);
-}
-
-static void pmw33xx_set_cpi_wrapper(uint16_t cpi) {
- pmw33xx_set_cpi(0, cpi);
-}
-
-static uint16_t pmw33xx_get_cpi_wrapper(void) {
- return pmw33xx_get_cpi(0);
-}
-
-report_mouse_t pmw33xx_get_report(report_mouse_t mouse_report) {
- pmw33xx_report_t report = pmw33xx_read_burst(0);
- static bool in_motion = false;
-
- if (report.motion.b.is_lifted) {
- return mouse_report;
- }
-
- if (!report.motion.b.is_motion) {
- in_motion = false;
- return mouse_report;
- }
-
- if (!in_motion) {
- in_motion = true;
- pd_dprintf("PWM3360 (0): starting motion\n");
- }
-
- mouse_report.x = CONSTRAIN_HID_XY(report.delta_x);
- mouse_report.y = CONSTRAIN_HID_XY(report.delta_y);
- return mouse_report;
-}
-
-// clang-format off
-const pointing_device_driver_t pointing_device_driver = {
- .init = pmw33xx_init_wrapper,
- .get_report = pmw33xx_get_report,
- .set_cpi = pmw33xx_set_cpi_wrapper,
- .get_cpi = pmw33xx_get_cpi_wrapper
-};
-// clang-format on
-
-#else
-__attribute__((weak)) void pointing_device_driver_init(void) {}
-__attribute__((weak)) report_mouse_t pointing_device_driver_get_report(report_mouse_t mouse_report) {
- return mouse_report;
-}
-__attribute__((weak)) uint16_t pointing_device_driver_get_cpi(void) {
- return 0;
-}
-__attribute__((weak)) void pointing_device_driver_set_cpi(uint16_t cpi) {}
-
-// clang-format off
-const pointing_device_driver_t pointing_device_driver = {
- .init = pointing_device_driver_init,
- .get_report = pointing_device_driver_get_report,
- .get_cpi = pointing_device_driver_get_cpi,
- .set_cpi = pointing_device_driver_set_cpi
-};
-// clang-format on
-
-#endif
diff --git a/quantum/process_keycode/process_layer_lock.c b/quantum/process_keycode/process_layer_lock.c
new file mode 100644
index 00000000000..6946d3c8862
--- /dev/null
+++ b/quantum/process_keycode/process_layer_lock.c
@@ -0,0 +1,82 @@
+// Copyright 2022-2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "layer_lock.h"
+#include "process_layer_lock.h"
+#include "quantum_keycodes.h"
+#include "action_util.h"
+
+// The current lock state. The kth bit is on if layer k is locked.
+extern layer_state_t locked_layers;
+
+// Handles an event on an `MO` or `TT` layer switch key.
+static inline bool handle_mo_or_tt(uint8_t layer, keyrecord_t* record) {
+ if (is_layer_locked(layer)) {
+ if (record->event.pressed) { // On press, unlock the layer.
+ layer_lock_invert(layer);
+ }
+ return false; // Skip default handling.
+ }
+ return true;
+}
+
+bool process_layer_lock(uint16_t keycode, keyrecord_t* record) {
+#ifndef NO_ACTION_LAYER
+ layer_lock_activity_trigger();
+
+ // The intention is that locked layers remain on. If something outside of
+ // this feature turned any locked layers off, unlock them.
+ if ((locked_layers & ~layer_state) != 0) {
+ layer_lock_set_kb(locked_layers &= layer_state);
+ }
+
+ if (keycode == QK_LAYER_LOCK) {
+ if (record->event.pressed) { // The layer lock key was pressed.
+ layer_lock_invert(get_highest_layer(layer_state));
+ }
+ return false;
+ }
+
+ switch (keycode) {
+ case QK_MOMENTARY ... QK_MOMENTARY_MAX: // `MO(layer)` keys.
+ return handle_mo_or_tt(QK_MOMENTARY_GET_LAYER(keycode), record);
+
+ case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX: // `TT(layer)`.
+ return handle_mo_or_tt(QK_LAYER_TAP_TOGGLE_GET_LAYER(keycode), record);
+
+ case QK_LAYER_MOD ... QK_LAYER_MOD_MAX: { // `LM(layer, mod)`.
+ uint8_t layer = QK_LAYER_MOD_GET_LAYER(keycode);
+ if (is_layer_locked(layer)) {
+ if (record->event.pressed) { // On press, unlock the layer.
+ layer_lock_invert(layer);
+ } else { // On release, clear the mods.
+ clear_mods();
+ send_keyboard_report();
+ }
+ return false; // Skip default handling.
+ }
+ } break;
+
+# ifndef NO_ACTION_TAPPING
+ case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: // `LT(layer, key)` keys.
+ if (record->tap.count == 0 && !record->event.pressed && is_layer_locked(QK_LAYER_TAP_GET_LAYER(keycode))) {
+ // Release event on a held layer-tap key where the layer is locked.
+ return false; // Skip default handling so that layer stays on.
+ }
+ break;
+# endif // NO_ACTION_TAPPING
+ }
+#endif // NO_ACTION_LAYER
+ return true;
+}
diff --git a/quantum/process_keycode/process_layer_lock.h b/quantum/process_keycode/process_layer_lock.h
new file mode 100644
index 00000000000..6795110029a
--- /dev/null
+++ b/quantum/process_keycode/process_layer_lock.h
@@ -0,0 +1,21 @@
+// Copyright 2022-2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include
+#include
+#include "action.h"
+
+bool process_layer_lock(uint16_t keycode, keyrecord_t* record);
diff --git a/quantum/process_keycode/process_underglow.c b/quantum/process_keycode/process_underglow.c
index 779672ac076..6104cd02c6c 100644
--- a/quantum/process_keycode/process_underglow.c
+++ b/quantum/process_keycode/process_underglow.c
@@ -2,87 +2,200 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "process_underglow.h"
-#include "rgblight.h"
+#if defined(RGBLIGHT_ENABLE)
+# include "rgblight.h"
+#endif
#include "action_util.h"
#include "keycodes.h"
#include "modifiers.h"
+// TODO: Remove this
+#if defined(RGB_MATRIX_ENABLE) && !defined(RGB_MATRIX_DISABLE_SHARED_KEYCODES)
+# include "rgb_matrix.h"
+#endif
+
bool process_underglow(uint16_t keycode, keyrecord_t *record) {
if (record->event.pressed) {
uint8_t shifted = get_mods() & MOD_MASK_SHIFT;
switch (keycode) {
case QK_UNDERGLOW_TOGGLE:
+#if defined(RGBLIGHT_ENABLE)
rgblight_toggle();
+#endif
+
+#if defined(RGB_MATRIX_ENABLE) && !defined(RGB_MATRIX_DISABLE_SHARED_KEYCODES)
+ rgb_matrix_toggle();
+#endif
return false;
case QK_UNDERGLOW_MODE_NEXT:
+#if defined(RGBLIGHT_ENABLE)
if (shifted) {
rgblight_step_reverse();
} else {
rgblight_step();
}
+#endif
+
+#if defined(RGB_MATRIX_ENABLE) && !defined(RGB_MATRIX_DISABLE_SHARED_KEYCODES)
+ if (shifted) {
+ rgb_matrix_step_reverse();
+ } else {
+ rgb_matrix_step();
+ }
+#endif
return false;
case QK_UNDERGLOW_MODE_PREVIOUS:
+#if defined(RGBLIGHT_ENABLE)
if (shifted) {
rgblight_step();
} else {
rgblight_step_reverse();
}
+#endif
+
+#if defined(RGB_MATRIX_ENABLE) && !defined(RGB_MATRIX_DISABLE_SHARED_KEYCODES)
+ if (shifted) {
+ rgb_matrix_step();
+ } else {
+ rgb_matrix_step_reverse();
+ }
+#endif
return false;
case QK_UNDERGLOW_HUE_UP:
+#if defined(RGBLIGHT_ENABLE)
if (shifted) {
rgblight_decrease_hue();
} else {
rgblight_increase_hue();
}
+#endif
+
+#if defined(RGB_MATRIX_ENABLE) && !defined(RGB_MATRIX_DISABLE_SHARED_KEYCODES)
+ if (shifted) {
+ rgb_matrix_decrease_hue();
+ } else {
+ rgb_matrix_increase_hue();
+ }
+#endif
return false;
case QK_UNDERGLOW_HUE_DOWN:
+#if defined(RGBLIGHT_ENABLE)
if (shifted) {
rgblight_increase_hue();
} else {
rgblight_decrease_hue();
}
+#endif
+
+#if defined(RGB_MATRIX_ENABLE) && !defined(RGB_MATRIX_DISABLE_SHARED_KEYCODES)
+ if (shifted) {
+ rgb_matrix_increase_hue();
+ } else {
+ rgb_matrix_decrease_hue();
+ }
+#endif
return false;
case QK_UNDERGLOW_SATURATION_UP:
+#if defined(RGBLIGHT_ENABLE)
if (shifted) {
rgblight_decrease_sat();
} else {
rgblight_increase_sat();
}
+#endif
+
+#if defined(RGB_MATRIX_ENABLE) && !defined(RGB_MATRIX_DISABLE_SHARED_KEYCODES)
+ if (shifted) {
+ rgb_matrix_decrease_sat();
+ } else {
+ rgb_matrix_increase_sat();
+ }
+#endif
return false;
case QK_UNDERGLOW_SATURATION_DOWN:
+#if defined(RGBLIGHT_ENABLE)
if (shifted) {
rgblight_increase_sat();
} else {
rgblight_decrease_sat();
}
+#endif
+
+#if defined(RGB_MATRIX_ENABLE) && !defined(RGB_MATRIX_DISABLE_SHARED_KEYCODES)
+ if (shifted) {
+ rgb_matrix_increase_sat();
+ } else {
+ rgb_matrix_decrease_sat();
+ }
+#endif
return false;
case QK_UNDERGLOW_VALUE_UP:
+#if defined(RGBLIGHT_ENABLE)
if (shifted) {
rgblight_decrease_val();
} else {
rgblight_increase_val();
}
+#endif
+
+#if defined(RGB_MATRIX_ENABLE) && !defined(RGB_MATRIX_DISABLE_SHARED_KEYCODES)
+ if (shifted) {
+ rgb_matrix_decrease_val();
+ } else {
+ rgb_matrix_increase_val();
+ }
+#endif
return false;
case QK_UNDERGLOW_VALUE_DOWN:
+#if defined(RGBLIGHT_ENABLE)
if (shifted) {
- rgblight_increase_hue();
+ rgblight_increase_val();
} else {
- rgblight_decrease_hue();
+ rgblight_decrease_val();
}
+#endif
+
+#if defined(RGB_MATRIX_ENABLE) && !defined(RGB_MATRIX_DISABLE_SHARED_KEYCODES)
+ if (shifted) {
+ rgb_matrix_increase_val();
+ } else {
+ rgb_matrix_decrease_val();
+ }
+#endif
return false;
case QK_UNDERGLOW_SPEED_UP:
+#if defined(RGBLIGHT_ENABLE)
if (shifted) {
rgblight_decrease_speed();
} else {
rgblight_increase_speed();
}
+#endif
+
+#if defined(RGB_MATRIX_ENABLE) && !defined(RGB_MATRIX_DISABLE_SHARED_KEYCODES)
+ if (shifted) {
+ rgb_matrix_decrease_speed();
+ } else {
+ rgb_matrix_increase_speed();
+ }
+#endif
return false;
case QK_UNDERGLOW_SPEED_DOWN:
+#if defined(RGBLIGHT_ENABLE)
if (shifted) {
rgblight_increase_speed();
} else {
rgblight_decrease_speed();
}
+#endif
+
+#if defined(RGB_MATRIX_ENABLE) && !defined(RGB_MATRIX_DISABLE_SHARED_KEYCODES)
+ if (shifted) {
+ rgb_matrix_increase_speed();
+ } else {
+ rgb_matrix_decrease_speed();
+ }
+#endif
return false;
}
}
diff --git a/quantum/quantum.c b/quantum/quantum.c
index 8bfe04e1798..4aef26a6a56 100644
--- a/quantum/quantum.c
+++ b/quantum/quantum.c
@@ -60,7 +60,7 @@
# include "process_rgb_matrix.h"
#endif
-#if defined(RGBLIGHT_ENABLE)
+#if defined(RGBLIGHT_ENABLE) || defined(RGB_MATRIX_ENABLE)
# include "process_underglow.h"
#endif
@@ -76,6 +76,10 @@
# include "process_unicode_common.h"
#endif
+#ifdef LAYER_LOCK_ENABLE
+# include "process_layer_lock.h"
+#endif
+
#ifdef AUDIO_ENABLE
# ifndef GOODBYE_SONG
# define GOODBYE_SONG SONG(GOODBYE_SOUND)
@@ -382,7 +386,7 @@ bool process_record_quantum(keyrecord_t *record) {
#ifdef GRAVE_ESC_ENABLE
process_grave_esc(keycode, record) &&
#endif
-#if defined(RGBLIGHT_ENABLE)
+#if defined(RGBLIGHT_ENABLE) || defined(RGB_MATRIX_ENABLE)
process_underglow(keycode, record) &&
#endif
#if defined(RGB_MATRIX_ENABLE)
@@ -400,6 +404,9 @@ bool process_record_quantum(keyrecord_t *record) {
#ifdef TRI_LAYER_ENABLE
process_tri_layer(keycode, record) &&
#endif
+#ifdef LAYER_LOCK_ENABLE
+ process_layer_lock(keycode, record) &&
+#endif
#ifdef BLUETOOTH_ENABLE
process_connection(keycode, record) &&
#endif
diff --git a/quantum/quantum.h b/quantum/quantum.h
index b60d8a86bf7..9db88a54d4b 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -240,6 +240,10 @@ extern layer_state_t layer_state;
# include "os_detection.h"
#endif
+#ifdef LAYER_LOCK_ENABLE
+# include "layer_lock.h"
+#endif
+
void set_single_default_layer(uint8_t default_layer);
void set_single_persistent_default_layer(uint8_t default_layer);
diff --git a/quantum/rgb_matrix/animations/breathing_anim.h b/quantum/rgb_matrix/animations/breathing_anim.h
index ed0c808f878..8fa8e3dad4d 100644
--- a/quantum/rgb_matrix/animations/breathing_anim.h
+++ b/quantum/rgb_matrix/animations/breathing_anim.h
@@ -2,18 +2,13 @@
RGB_MATRIX_EFFECT(BREATHING)
# ifdef RGB_MATRIX_CUSTOM_EFFECT_IMPLS
-bool BREATHING(effect_params_t* params) {
- RGB_MATRIX_USE_LIMITS(led_min, led_max);
+hsv_t BREATHING_math(hsv_t hsv, uint8_t i, uint8_t time) {
+ hsv.v = scale8(abs8(sin8(time / 2) - 128) * 2, hsv.v);
+ return hsv;
+}
- hsv_t hsv = rgb_matrix_config.hsv;
- uint16_t time = scale16by8(g_rgb_timer, rgb_matrix_config.speed / 8);
- hsv.v = scale8(abs8(sin8(time) - 128) * 2, hsv.v);
- rgb_t rgb = rgb_matrix_hsv_to_rgb(hsv);
- for (uint8_t i = led_min; i < led_max; i++) {
- RGB_MATRIX_TEST_LED_FLAGS();
- rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
- }
- return rgb_matrix_check_finished_leds(led_max);
+bool BREATHING(effect_params_t* params) {
+ return effect_runner_i(params, &BREATHING_math);
}
# endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
diff --git a/quantum/rgb_matrix/animations/jellybean_raindrops_anim.h b/quantum/rgb_matrix/animations/jellybean_raindrops_anim.h
index 2b20b0706b5..5790b273673 100644
--- a/quantum/rgb_matrix/animations/jellybean_raindrops_anim.h
+++ b/quantum/rgb_matrix/animations/jellybean_raindrops_anim.h
@@ -2,25 +2,33 @@
RGB_MATRIX_EFFECT(JELLYBEAN_RAINDROPS)
# ifdef RGB_MATRIX_CUSTOM_EFFECT_IMPLS
-static void jellybean_raindrops_set_color(int i, effect_params_t* params) {
+static void jellybean_raindrops_set_color(uint8_t i, effect_params_t* params) {
if (!HAS_ANY_FLAGS(g_led_config.flags[i], params->flags)) return;
+
hsv_t hsv = {random8(), random8_min_max(127, 255), rgb_matrix_config.hsv.v};
rgb_t rgb = rgb_matrix_hsv_to_rgb(hsv);
rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
}
bool JELLYBEAN_RAINDROPS(effect_params_t* params) {
+ static uint16_t index = RGB_MATRIX_LED_COUNT + 1;
+
+ // Periodic trigger for LED change
+ if ((params->iter == 0) && (scale16by8(g_rgb_timer, qadd8(rgb_matrix_config.speed, 16)) % 5 == 0)) {
+ index = random8_max(RGB_MATRIX_LED_COUNT);
+ }
+
RGB_MATRIX_USE_LIMITS(led_min, led_max);
- if (!params->init) {
- // Change one LED every tick, make sure speed is not 0
- if (scale16by8(g_rgb_timer, qadd8(rgb_matrix_config.speed, 16)) % 5 == 0) {
- jellybean_raindrops_set_color(random8_max(RGB_MATRIX_LED_COUNT), params);
- }
- } else {
- for (int i = led_min; i < led_max; i++) {
+ if (params->init) {
+ for (uint8_t i = led_min; i < led_max; i++) {
jellybean_raindrops_set_color(i, params);
}
}
+ // Change LED once and set index out of range till next trigger
+ else if (led_min <= index && index < led_max) {
+ jellybean_raindrops_set_color(index, params);
+ index = RGB_MATRIX_LED_COUNT + 1;
+ }
return rgb_matrix_check_finished_leds(led_max);
}
diff --git a/quantum/rgb_matrix/animations/pixel_rain_anim.h b/quantum/rgb_matrix/animations/pixel_rain_anim.h
index d7f0e3bebd0..c0370831d80 100644
--- a/quantum/rgb_matrix/animations/pixel_rain_anim.h
+++ b/quantum/rgb_matrix/animations/pixel_rain_anim.h
@@ -6,25 +6,20 @@ RGB_MATRIX_EFFECT(PIXEL_RAIN)
# ifdef RGB_MATRIX_CUSTOM_EFFECT_IMPLS
static bool PIXEL_RAIN(effect_params_t* params) {
- static uint32_t wait_timer = 0;
+ static fast_timer_t timer = 0;
+ static uint16_t index = RGB_MATRIX_LED_COUNT + 1;
- inline uint32_t interval(void) {
- return 500 / scale16by8(qadd8(rgb_matrix_config.speed, 16), 16);
- }
-
- inline void rain_pixel(uint8_t led_index) {
- if (!HAS_ANY_FLAGS(g_led_config.flags[led_index], params->flags)) {
- return;
- }
- hsv_t hsv = (random8() & 2) ? (hsv_t){0, 0, 0} : (hsv_t){random8(), random8_min_max(127, 255), rgb_matrix_config.hsv.v};
- rgb_t rgb = rgb_matrix_hsv_to_rgb(hsv);
- rgb_matrix_set_color(led_index, rgb.r, rgb.g, rgb.b);
- wait_timer = g_rgb_timer + interval();
+ if ((params->iter == 0) && (timer_elapsed_fast(timer) > (320 - rgb_matrix_config.speed))) {
+ index = random8_max(RGB_MATRIX_LED_COUNT);
+ timer = timer_read_fast();
}
RGB_MATRIX_USE_LIMITS(led_min, led_max);
- if (g_rgb_timer > wait_timer) {
- rain_pixel(random8_max(RGB_MATRIX_LED_COUNT));
+ if (led_min <= index && index < led_max && HAS_ANY_FLAGS(g_led_config.flags[index], params->flags)) {
+ hsv_t hsv = (random8() & 2) ? (hsv_t){0, 0, 0} : (hsv_t){random8(), random8_min_max(127, 255), rgb_matrix_config.hsv.v};
+ rgb_t rgb = rgb_matrix_hsv_to_rgb(hsv);
+ rgb_matrix_set_color(index, rgb.r, rgb.g, rgb.b);
+ index = RGB_MATRIX_LED_COUNT + 1;
}
return rgb_matrix_check_finished_leds(led_max);
}
diff --git a/quantum/rgb_matrix/animations/riverflow_anim.h b/quantum/rgb_matrix/animations/riverflow_anim.h
index 737735fe83c..e9ef25f70ce 100644
--- a/quantum/rgb_matrix/animations/riverflow_anim.h
+++ b/quantum/rgb_matrix/animations/riverflow_anim.h
@@ -4,18 +4,14 @@ RGB_MATRIX_EFFECT(RIVERFLOW)
// inspired by @PleasureTek's Massdrop Alt LED animation
-bool RIVERFLOW(effect_params_t* params) {
- RGB_MATRIX_USE_LIMITS(led_min, led_max);
- for (uint8_t i = led_min; i < led_max; i++) {
- RGB_MATRIX_TEST_LED_FLAGS();
- hsv_t hsv = rgb_matrix_config.hsv;
- uint16_t time = scale16by8(g_rgb_timer + (i * 315), rgb_matrix_config.speed / 8);
- hsv.v = scale8(abs8(sin8(time) - 128) * 2, hsv.v);
- rgb_t rgb = rgb_matrix_hsv_to_rgb(hsv);
- rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
- }
+hsv_t RIVERFLOW_math(hsv_t hsv, uint8_t i, uint8_t time) {
+ time = scale16by8(g_rgb_timer + (i * 315), rgb_matrix_config.speed / 8);
+ hsv.v = scale8(abs8(sin8(time) - 128) * 2, hsv.v);
+ return hsv;
+}
- return rgb_matrix_check_finished_leds(led_max);
+bool RIVERFLOW(effect_params_t* params) {
+ return effect_runner_i(params, &RIVERFLOW_math);
}
# endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
diff --git a/quantum/rgb_matrix/rgb_matrix.h b/quantum/rgb_matrix/rgb_matrix.h
index 842a60c8b7e..33f7e06a639 100644
--- a/quantum/rgb_matrix/rgb_matrix.h
+++ b/quantum/rgb_matrix/rgb_matrix.h
@@ -212,6 +212,7 @@ void rgb_matrix_decrease_speed_noeeprom(void);
led_flags_t rgb_matrix_get_flags(void);
void rgb_matrix_set_flags(led_flags_t flags);
void rgb_matrix_set_flags_noeeprom(led_flags_t flags);
+void rgb_matrix_update_pwm_buffers(void);
#ifndef RGBLIGHT_ENABLE
# define eeconfig_update_rgblight_current eeconfig_update_rgb_matrix
diff --git a/quantum/split_common/transactions.c b/quantum/split_common/transactions.c
index 6c1aeb284d3..f66b2ad89fb 100644
--- a/quantum/split_common/transactions.c
+++ b/quantum/split_common/transactions.c
@@ -733,7 +733,7 @@ static bool pointing_handlers_master(matrix_row_t master_matrix[], matrix_row_t
return okay;
}
-extern const pointing_device_driver_t pointing_device_driver;
+extern const pointing_device_driver_t *pointing_device_driver;
static void pointing_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
# if defined(POINTING_DEVICE_LEFT)
@@ -753,18 +753,18 @@ static void pointing_handlers_slave(matrix_row_t master_matrix[], matrix_row_t s
last_exec = timer_read32();
# endif
- uint16_t temp_cpi = !pointing_device_driver.get_cpi ? 0 : pointing_device_driver.get_cpi(); // check for NULL
+ uint16_t temp_cpi = !pointing_device_driver->get_cpi ? 0 : pointing_device_driver->get_cpi(); // check for NULL
split_shared_memory_lock();
split_slave_pointing_sync_t pointing;
memcpy(&pointing, &split_shmem->pointing, sizeof(split_slave_pointing_sync_t));
split_shared_memory_unlock();
- if (pointing.cpi && pointing.cpi != temp_cpi && pointing_device_driver.set_cpi) {
- pointing_device_driver.set_cpi(pointing.cpi);
+ if (pointing.cpi && pointing.cpi != temp_cpi && pointing_device_driver->set_cpi) {
+ pointing_device_driver->set_cpi(pointing.cpi);
}
- pointing.report = pointing_device_driver.get_report((report_mouse_t){0});
+ pointing.report = pointing_device_driver->get_report((report_mouse_t){0});
// Now update the checksum given that the pointing has been written to
pointing.checksum = crc8(&pointing.report, sizeof(report_mouse_t));
diff --git a/requirements.txt b/requirements.txt
index 6bee7463243..fbee51ee575 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,5 @@
# Python requirements
-appdirs
+# platformdirs
argcomplete
colorama
dotty-dict
diff --git a/tests/layer_lock/config.h b/tests/layer_lock/config.h
new file mode 100644
index 00000000000..25d0b20c0ea
--- /dev/null
+++ b/tests/layer_lock/config.h
@@ -0,0 +1,8 @@
+// Copyright 2021 Christopher Courtney, aka Drashna Jael're (@drashna)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "test_common.h"
+
+#define LAYER_LOCK_IDLE_TIMEOUT 1000
diff --git a/tests/layer_lock/test.mk b/tests/layer_lock/test.mk
new file mode 100644
index 00000000000..05771e4dbf8
--- /dev/null
+++ b/tests/layer_lock/test.mk
@@ -0,0 +1,8 @@
+# Copyright 2021 Christopher Courtney, aka Drashna Jael're (@drashna)
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# --------------------------------------------------------------------------------
+# Keep this file, even if it is empty, as a marker that this folder contains tests
+# --------------------------------------------------------------------------------
+
+LAYER_LOCK_ENABLE = yes
diff --git a/tests/layer_lock/test_layer_lock.cpp b/tests/layer_lock/test_layer_lock.cpp
new file mode 100644
index 00000000000..00742c3b436
--- /dev/null
+++ b/tests/layer_lock/test_layer_lock.cpp
@@ -0,0 +1,284 @@
+// Copyright 2021 Christopher Courtney, aka Drashna Jael're (@drashna)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "keycodes.h"
+#include "test_common.hpp"
+
+using testing::_;
+
+class LayerLock : public TestFixture {};
+
+TEST_F(LayerLock, LayerLockState) {
+ TestDriver driver;
+ KeymapKey key_a = KeymapKey(0, 0, 0, KC_A);
+ KeymapKey key_b = KeymapKey(1, 0, 0, KC_B);
+ KeymapKey key_c = KeymapKey(2, 0, 0, KC_C);
+ KeymapKey key_d = KeymapKey(3, 0, 0, KC_C);
+
+ set_keymap({key_a, key_b, key_c, key_d});
+
+ EXPECT_FALSE(is_layer_locked(1));
+ EXPECT_FALSE(is_layer_locked(2));
+ EXPECT_FALSE(is_layer_locked(3));
+
+ layer_lock_invert(1); // Layer 1: unlocked -> locked
+ layer_lock_on(2); // Layer 2: unlocked -> locked
+ layer_lock_off(3); // Layer 3: stays unlocked
+
+ // Layers 1 and 2 are now on.
+ EXPECT_TRUE(layer_state_is(1));
+ EXPECT_TRUE(layer_state_is(2));
+ // Layers 1 and 2 are now locked.
+ EXPECT_TRUE(is_layer_locked(1));
+ EXPECT_TRUE(is_layer_locked(2));
+ EXPECT_FALSE(is_layer_locked(3));
+
+ layer_lock_invert(1); // Layer 1: locked -> unlocked
+ layer_lock_on(2); // Layer 2: stays locked
+ layer_lock_on(3); // Layer 3: unlocked -> locked
+
+ EXPECT_FALSE(layer_state_is(1));
+ EXPECT_TRUE(layer_state_is(2));
+ EXPECT_TRUE(layer_state_is(3));
+ EXPECT_FALSE(is_layer_locked(1));
+ EXPECT_TRUE(is_layer_locked(2));
+ EXPECT_TRUE(is_layer_locked(3));
+
+ layer_lock_invert(1); // Layer 1: unlocked -> locked
+ layer_lock_off(2); // Layer 2: locked -> unlocked
+
+ EXPECT_TRUE(layer_state_is(1));
+ EXPECT_FALSE(layer_state_is(2));
+ EXPECT_TRUE(layer_state_is(3));
+ EXPECT_TRUE(is_layer_locked(1));
+ EXPECT_FALSE(is_layer_locked(2));
+ EXPECT_TRUE(is_layer_locked(3));
+
+ layer_lock_all_off(); // Layers 1 and 3: locked -> unlocked
+
+ EXPECT_FALSE(layer_state_is(1));
+ EXPECT_FALSE(layer_state_is(2));
+ EXPECT_FALSE(layer_state_is(3));
+ EXPECT_FALSE(is_layer_locked(1));
+ EXPECT_FALSE(is_layer_locked(2));
+ EXPECT_FALSE(is_layer_locked(3));
+}
+
+TEST_F(LayerLock, LayerLockMomentaryTest) {
+ TestDriver driver;
+ KeymapKey key_layer = KeymapKey(0, 0, 0, MO(1));
+ KeymapKey key_a = KeymapKey(0, 1, 0, KC_A);
+ KeymapKey key_trns = KeymapKey(1, 0, 0, KC_TRNS);
+ KeymapKey key_ll = KeymapKey(1, 1, 0, QK_LAYER_LOCK);
+
+ set_keymap({key_layer, key_a, key_trns, key_ll});
+
+ EXPECT_NO_REPORT(driver);
+ key_layer.press();
+ run_one_scan_loop();
+ EXPECT_TRUE(layer_state_is(1));
+ EXPECT_FALSE(is_layer_locked(1));
+ VERIFY_AND_CLEAR(driver);
+
+ EXPECT_NO_REPORT(driver);
+ tap_key(key_ll);
+ EXPECT_TRUE(layer_state_is(1));
+ EXPECT_TRUE(is_layer_locked(1));
+ VERIFY_AND_CLEAR(driver);
+
+ EXPECT_NO_REPORT(driver);
+ key_layer.release();
+ run_one_scan_loop();
+ EXPECT_TRUE(layer_state_is(1));
+ EXPECT_TRUE(is_layer_locked(1));
+ VERIFY_AND_CLEAR(driver);
+
+ // Pressing Layer Lock again unlocks the lock.
+ EXPECT_NO_REPORT(driver);
+ key_ll.press();
+ run_one_scan_loop();
+ EXPECT_FALSE(layer_state_is(1));
+ EXPECT_FALSE(is_layer_locked(1));
+ VERIFY_AND_CLEAR(driver);
+}
+
+TEST_F(LayerLock, LayerLockLayerTapTest) {
+ TestDriver driver;
+ KeymapKey key_layer = KeymapKey(0, 0, 0, LT(1, KC_B));
+ KeymapKey key_a = KeymapKey(0, 1, 0, KC_A);
+ KeymapKey key_trns = KeymapKey(1, 0, 0, KC_TRNS);
+ KeymapKey key_ll = KeymapKey(1, 1, 0, QK_LAYER_LOCK);
+
+ set_keymap({key_layer, key_a, key_trns, key_ll});
+
+ EXPECT_NO_REPORT(driver);
+ key_layer.press();
+ idle_for(TAPPING_TERM);
+ run_one_scan_loop();
+ EXPECT_TRUE(layer_state_is(1));
+ VERIFY_AND_CLEAR(driver);
+
+ EXPECT_NO_REPORT(driver);
+ tap_key(key_ll);
+ EXPECT_TRUE(layer_state_is(1));
+ EXPECT_TRUE(is_layer_locked(1));
+ VERIFY_AND_CLEAR(driver);
+
+ // Pressing Layer Lock again unlocks the lock.
+ EXPECT_NO_REPORT(driver);
+ key_ll.press();
+ run_one_scan_loop();
+ EXPECT_FALSE(layer_state_is(1));
+ EXPECT_FALSE(is_layer_locked(1));
+ VERIFY_AND_CLEAR(driver);
+}
+
+TEST_F(LayerLock, LayerLockOneshotTapTest) {
+ TestDriver driver;
+ KeymapKey key_layer = KeymapKey(0, 0, 0, OSL(1));
+ KeymapKey key_a = KeymapKey(0, 1, 0, KC_A);
+ KeymapKey key_trns = KeymapKey(1, 0, 0, KC_TRNS);
+ KeymapKey key_ll = KeymapKey(1, 1, 0, QK_LAYER_LOCK);
+
+ set_keymap({key_layer, key_a, key_trns, key_ll});
+
+ EXPECT_NO_REPORT(driver);
+ tap_key(key_layer);
+ run_one_scan_loop();
+ EXPECT_TRUE(layer_state_is(1));
+ VERIFY_AND_CLEAR(driver);
+
+ EXPECT_NO_REPORT(driver);
+ tap_key(key_ll);
+ run_one_scan_loop();
+ EXPECT_TRUE(layer_state_is(1));
+ EXPECT_TRUE(is_layer_locked(1));
+ VERIFY_AND_CLEAR(driver);
+
+ // Pressing Layer Lock again unlocks the lock.
+ EXPECT_NO_REPORT(driver);
+ key_ll.press();
+ run_one_scan_loop();
+ EXPECT_FALSE(layer_state_is(1));
+ EXPECT_FALSE(is_layer_locked(1));
+ VERIFY_AND_CLEAR(driver);
+}
+
+TEST_F(LayerLock, LayerLockOneshotHoldTest) {
+ TestDriver driver;
+ KeymapKey key_layer = KeymapKey(0, 0, 0, OSL(1));
+ KeymapKey key_a = KeymapKey(0, 1, 0, KC_A);
+ KeymapKey key_trns = KeymapKey(1, 0, 0, KC_TRNS);
+ KeymapKey key_ll = KeymapKey(1, 1, 0, QK_LAYER_LOCK);
+
+ set_keymap({key_layer, key_a, key_trns, key_ll});
+
+ EXPECT_NO_REPORT(driver);
+ key_layer.press();
+ idle_for(TAPPING_TERM);
+ run_one_scan_loop();
+ EXPECT_TRUE(layer_state_is(1));
+ VERIFY_AND_CLEAR(driver);
+
+ EXPECT_NO_REPORT(driver);
+ tap_key(key_ll);
+ run_one_scan_loop();
+ EXPECT_TRUE(layer_state_is(1));
+ VERIFY_AND_CLEAR(driver);
+
+ EXPECT_NO_REPORT(driver);
+ key_layer.release();
+ run_one_scan_loop();
+ EXPECT_TRUE(layer_state_is(1));
+ EXPECT_TRUE(is_layer_locked(1));
+ VERIFY_AND_CLEAR(driver);
+
+ // Pressing Layer Lock again unlocks the lock.
+ EXPECT_NO_REPORT(driver);
+ key_ll.press();
+ run_one_scan_loop();
+ EXPECT_FALSE(layer_state_is(1));
+ EXPECT_FALSE(is_layer_locked(1));
+ VERIFY_AND_CLEAR(driver);
+}
+
+TEST_F(LayerLock, LayerLockTimeoutTest) {
+ TestDriver driver;
+ KeymapKey key_layer = KeymapKey(0, 0, 0, MO(1));
+ KeymapKey key_a = KeymapKey(0, 1, 0, KC_A);
+ KeymapKey key_trns = KeymapKey(1, 0, 0, KC_TRNS);
+ KeymapKey key_ll = KeymapKey(1, 1, 0, QK_LAYER_LOCK);
+
+ set_keymap({key_layer, key_a, key_trns, key_ll});
+
+ EXPECT_NO_REPORT(driver);
+ key_layer.press();
+ run_one_scan_loop();
+ EXPECT_TRUE(layer_state_is(1));
+ VERIFY_AND_CLEAR(driver);
+
+ EXPECT_NO_REPORT(driver);
+ tap_key(key_ll);
+ EXPECT_TRUE(layer_state_is(1));
+ VERIFY_AND_CLEAR(driver);
+
+ EXPECT_NO_REPORT(driver);
+ key_layer.release();
+ run_one_scan_loop();
+ EXPECT_TRUE(layer_state_is(1));
+ EXPECT_TRUE(is_layer_locked(1));
+ VERIFY_AND_CLEAR(driver);
+
+ EXPECT_NO_REPORT(driver);
+ idle_for(LAYER_LOCK_IDLE_TIMEOUT);
+ run_one_scan_loop();
+ EXPECT_FALSE(layer_state_is(1));
+ EXPECT_FALSE(is_layer_locked(1));
+ VERIFY_AND_CLEAR(driver);
+}
+
+TEST_F(LayerLock, ToKeyOverridesLayerLock) {
+ TestDriver driver;
+ KeymapKey key_layer = KeymapKey(0, 0, 0, MO(1));
+ KeymapKey key_to0 = KeymapKey(1, 0, 0, TO(0));
+ KeymapKey key_ll = KeymapKey(1, 1, 0, QK_LAYER_LOCK);
+
+ set_keymap({key_layer, key_to0, key_ll});
+
+ EXPECT_NO_REPORT(driver);
+ layer_lock_on(1);
+ run_one_scan_loop();
+ EXPECT_TRUE(layer_state_is(1));
+ EXPECT_TRUE(is_layer_locked(1));
+ VERIFY_AND_CLEAR(driver);
+
+ EXPECT_NO_REPORT(driver);
+ tap_key(key_to0); // TO(0) overrides Layer Lock and unlocks layer 1.
+ EXPECT_FALSE(layer_state_is(1));
+ EXPECT_FALSE(is_layer_locked(1));
+ VERIFY_AND_CLEAR(driver);
+}
+
+TEST_F(LayerLock, LayerClearOverridesLayerLock) {
+ TestDriver driver;
+ KeymapKey key_layer = KeymapKey(0, 0, 0, MO(1));
+ KeymapKey key_a = KeymapKey(0, 1, 0, KC_A);
+ KeymapKey key_ll = KeymapKey(1, 1, 0, QK_LAYER_LOCK);
+
+ set_keymap({key_layer, key_a, key_ll});
+
+ EXPECT_NO_REPORT(driver);
+ layer_lock_on(1);
+ run_one_scan_loop();
+ EXPECT_TRUE(layer_state_is(1));
+ EXPECT_TRUE(is_layer_locked(1));
+ VERIFY_AND_CLEAR(driver);
+
+ EXPECT_REPORT(driver, (KC_A));
+ layer_clear(); // layer_clear() overrides Layer Lock and unlocks layer 1.
+ key_a.press();
+ run_one_scan_loop();
+ EXPECT_FALSE(layer_state_is(1));
+ EXPECT_FALSE(is_layer_locked(1));
+ VERIFY_AND_CLEAR(driver);
+}
diff --git a/tests/test_common/keycode_table.cpp b/tests/test_common/keycode_table.cpp
index e4d445de828..ae1a9edcd0f 100644
--- a/tests/test_common/keycode_table.cpp
+++ b/tests/test_common/keycode_table.cpp
@@ -562,6 +562,7 @@ std::map KEYCODE_ID_TABLE = {
{QK_MACRO_29, "QK_MACRO_29"},
{QK_MACRO_30, "QK_MACRO_30"},
{QK_MACRO_31, "QK_MACRO_31"},
+ {QK_OUTPUT_AUTO, "QK_OUTPUT_AUTO"},
{QK_OUTPUT_NEXT, "QK_OUTPUT_NEXT"},
{QK_OUTPUT_PREV, "QK_OUTPUT_PREV"},
{QK_OUTPUT_NONE, "QK_OUTPUT_NONE"},
@@ -698,6 +699,7 @@ std::map KEYCODE_ID_TABLE = {
{QK_TRI_LAYER_UPPER, "QK_TRI_LAYER_UPPER"},
{QK_REPEAT_KEY, "QK_REPEAT_KEY"},
{QK_ALT_REPEAT_KEY, "QK_ALT_REPEAT_KEY"},
+ {QK_LAYER_LOCK, "QK_LAYER_LOCK"},
{QK_KB_0, "QK_KB_0"},
{QK_KB_1, "QK_KB_1"},
{QK_KB_2, "QK_KB_2"},
diff --git a/tmk_core/protocol/host.c b/tmk_core/protocol/host.c
index 732fbdc37d4..df805c827c2 100644
--- a/tmk_core/protocol/host.c
+++ b/tmk_core/protocol/host.c
@@ -193,6 +193,10 @@ void host_joystick_send(joystick_t *joystick) {
},
# endif
+# ifdef JOYSTICK_HAS_HAT
+ .hat = joystick->hat,
+# endif
+
# if JOYSTICK_BUTTON_COUNT > 0
.buttons =
{
diff --git a/tmk_core/protocol/report.h b/tmk_core/protocol/report.h
index 37c8ea48f1b..d854f51d5c4 100644
--- a/tmk_core/protocol/report.h
+++ b/tmk_core/protocol/report.h
@@ -246,6 +246,11 @@ typedef struct {
joystick_axis_t axes[JOYSTICK_AXIS_COUNT];
#endif
+#ifdef JOYSTICK_HAS_HAT
+ int8_t hat : 4;
+ uint8_t reserved : 4;
+#endif
+
#if JOYSTICK_BUTTON_COUNT > 0
uint8_t buttons[(JOYSTICK_BUTTON_COUNT - 1) / 8 + 1];
#endif
diff --git a/tmk_core/protocol/usb_descriptor.c b/tmk_core/protocol/usb_descriptor.c
index e7d12a07d9f..c7fb660b65d 100644
--- a/tmk_core/protocol/usb_descriptor.c
+++ b/tmk_core/protocol/usb_descriptor.c
@@ -247,6 +247,23 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
# endif
+# ifdef JOYSTICK_HAS_HAT
+ // Hat Switch (4 bits)
+ HID_RI_USAGE(8, 0x39), // Hat Switch
+ HID_RI_LOGICAL_MINIMUM(8, 0x00),
+ HID_RI_LOGICAL_MAXIMUM(8, 0x07),
+ HID_RI_PHYSICAL_MINIMUM(8, 0),
+ HID_RI_PHYSICAL_MAXIMUM(16, 315),
+ HID_RI_UNIT(8, 0x14), // Degree, English Rotation
+ HID_RI_REPORT_COUNT(8, 1),
+ HID_RI_REPORT_SIZE(8, 4),
+ HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NULLSTATE),
+ // Padding (4 bits)
+ HID_RI_REPORT_COUNT(8, 0x04),
+ HID_RI_REPORT_SIZE(8, 0x01),
+ HID_RI_INPUT(8, HID_IOF_CONSTANT),
+# endif
+
# if JOYSTICK_BUTTON_COUNT > 0
HID_RI_USAGE_PAGE(8, 0x09), // Button
HID_RI_USAGE_MINIMUM(8, 0x01),
diff --git a/tmk_core/protocol/vusb/vusb.c b/tmk_core/protocol/vusb/vusb.c
index 2a29fe65d90..fdbfcc17dce 100644
--- a/tmk_core/protocol/vusb/vusb.c
+++ b/tmk_core/protocol/vusb/vusb.c
@@ -621,6 +621,23 @@ const PROGMEM uchar shared_hid_report[] = {
0x81, 0x02, // Input (Data, Variable, Absolute)
# endif
+# ifdef JOYSTICK_HAS_HAT
+ // Hat Switch (4 bits)
+ 0x09, 0x39, // Usage (Hat Switch)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x07, // Logical Maximum (7)
+ 0x35, 0x00, // Physical Minimum (0)
+ 0x46, 0x3B, 0x01, // Physical Maximum (315)
+ 0x65, 0x14, // Unit (Degree, English Rotation)
+ 0x95, 0x01, // Report Count (1)
+ 0x75, 0x04, // Report Size (4)
+ 0x81, 0x42, // Input (Data, Variable, Absolute, Null State)
+ // Padding (4 bits)
+ 0x95, 0x04, // Report Count (4)
+ 0x75, 0x01, // Report Size (1)
+ 0x81, 0x01, // Input (Constant)
+# endif
+
# if JOYSTICK_BUTTON_COUNT > 0
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (Button 1)