Merge branch 'zmkfirmware:main' into leeloo_micro_v1_branch
This commit is contained in:
commit
3364c96213
40 changed files with 2059 additions and 1562 deletions
25
.github/workflows/build-user-config.yml
vendored
25
.github/workflows/build-user-config.yml
vendored
|
@ -39,8 +39,8 @@ jobs:
|
|||
|
||||
- name: Fetch Build Matrix
|
||||
run: |
|
||||
echo "build_matrix=$(yaml2json ${{ inputs.build_matrix_path }} | jq -c .)" >> $GITHUB_ENV
|
||||
yaml2json ${{ inputs.build_matrix_path }} | jq
|
||||
echo "build_matrix=$(yaml2json '${{ inputs.build_matrix_path }}' | jq -c .)" >> $GITHUB_ENV
|
||||
yaml2json "${{ inputs.build_matrix_path }}" | jq
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -54,18 +54,13 @@ jobs:
|
|||
steps:
|
||||
- name: Prepare variables
|
||||
shell: sh -x {0}
|
||||
env:
|
||||
shield: ${{ matrix.shield }}
|
||||
run: |
|
||||
if [ -n "${{ matrix.shield }}" ]
|
||||
then
|
||||
echo "extra_cmake_args=-DSHIELD=\"${{ matrix.shield }}\"" >> $GITHUB_ENV
|
||||
echo "artifact_name=${{ matrix.shield }}-${{ matrix.board }}-zmk" >> $GITHUB_ENV
|
||||
echo "display_name=${{ matrix.shield }} - ${{ matrix.board }}" >> $GITHUB_ENV
|
||||
else
|
||||
echo "extra_cmake_args=" >> $GITHUB_ENV
|
||||
echo "artifact_name=${{ matrix.board }}-zmk" >> $GITHUB_ENV
|
||||
echo "display_name=${{ matrix.board }}" >> $GITHUB_ENV
|
||||
fi
|
||||
echo "zephyr_version=${ZEPHYR_VERSION}" >> $GITHUB_ENV
|
||||
echo "extra_cmake_args=${shield:+-DSHIELD=\"$shield\"}" >> $GITHUB_ENV
|
||||
echo "display_name=${shield:+$shield - }${{ matrix.board }}" >> $GITHUB_ENV
|
||||
echo "artifact_name=${shield:+$shield-}${{ matrix.board }}-zmk" >> $GITHUB_ENV
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
@ -89,7 +84,7 @@ jobs:
|
|||
${{ runner.os }}-
|
||||
|
||||
- name: West Init
|
||||
run: west init -l ${{ inputs.config_path }}
|
||||
run: west init -l "${{ inputs.config_path }}"
|
||||
|
||||
- name: West Update
|
||||
run: west update
|
||||
|
@ -99,7 +94,7 @@ jobs:
|
|||
|
||||
- name: West Build (${{ env.display_name }})
|
||||
shell: sh -x {0}
|
||||
run: west build -s zmk/app -b ${{ matrix.board }} -- -DZMK_CONFIG=${GITHUB_WORKSPACE}/${{ inputs.config_path }} ${{ env.extra_cmake_args }} ${{ matrix.cmake-args }}
|
||||
run: west build -s zmk/app -b "${{ matrix.board }}" -- -DZMK_CONFIG="${GITHUB_WORKSPACE}/${{ inputs.config_path }}" ${{ env.extra_cmake_args }} ${{ matrix.cmake-args }}
|
||||
|
||||
- name: ${{ env.display_name }} Kconfig file
|
||||
run: grep -v -e "^#" -e "^$" build/zephyr/.config | sort
|
||||
|
@ -113,7 +108,7 @@ jobs:
|
|||
cp build/zephyr/zmk.uf2 "build/artifacts/${{ env.artifact_name }}.uf2"
|
||||
elif [ -f build/zephyr/zmk.${{ inputs.fallback_binary }} ]
|
||||
then
|
||||
cp build/zephyr/zmk.${{ inputs.fallback_binary }} "build/artifacts/${{ env.artifact_name }}.${{ inputs.fallback_binary }}"
|
||||
cp "build/zephyr/zmk.${{ inputs.fallback_binary }}" "build/artifacts/${{ env.artifact_name }}.${{ inputs.fallback_binary }}"
|
||||
fi
|
||||
|
||||
- name: Archive (${{ env.display_name }})
|
||||
|
|
9
.vscode/extensions.json
vendored
Normal file
9
.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"esbenp.prettier-vscode",
|
||||
"ms-python.python",
|
||||
"ms-vscode.cpptools",
|
||||
"plorefice.devicetree",
|
||||
"twxs.cmake"
|
||||
]
|
||||
}
|
17
.vscode/settings.json
vendored
17
.vscode/settings.json
vendored
|
@ -3,5 +3,20 @@
|
|||
"*.overlay": "dts",
|
||||
"*.keymap": "dts"
|
||||
},
|
||||
"python.formatting.provider": "black"
|
||||
"python.formatting.provider": "black",
|
||||
"[c]": {
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[javascript][javascriptreact][typescript][typescriptreact]": {
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[python]": {
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "ms-python.python"
|
||||
},
|
||||
"[css][json][jsonc][html][markdown][yaml]": {
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
};
|
||||
|
||||
&i2c0 {
|
||||
compatible = "nordic,nrf-twim";
|
||||
compatible = "nordic,nrf-twi";
|
||||
pinctrl-0 = <&i2c0_default>;
|
||||
pinctrl-1 = <&i2c0_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
|
@ -71,6 +71,7 @@
|
|||
|
||||
&uart0 {
|
||||
compatible = "nordic,nrf-uarte";
|
||||
current-speed = <115200>;
|
||||
pinctrl-0 = <&uart0_default>;
|
||||
pinctrl-1 = <&uart0_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
|
|
6
app/boards/arm/kbdfans_tofu65/Kconfig.board
Normal file
6
app/boards/arm/kbdfans_tofu65/Kconfig.board
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Copyright (c) 2023 The ZMK Contributors
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config BOARD_KBDFANS_TOFU65_V2
|
||||
bool "KBDfans Tofu65 2.0"
|
||||
depends on SOC_RP2040
|
15
app/boards/arm/kbdfans_tofu65/Kconfig.defconfig
Normal file
15
app/boards/arm/kbdfans_tofu65/Kconfig.defconfig
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Copyright (c) 2023 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
if BOARD_KBDFANS_TOFU65_V2
|
||||
|
||||
config ZMK_KEYBOARD_NAME
|
||||
default "kbdfans tofu65"
|
||||
|
||||
config RP2_FLASH_W25Q080
|
||||
default y
|
||||
|
||||
config ZMK_USB
|
||||
default y
|
||||
|
||||
endif # BOARD_KBDFANS_TOFU65_V2
|
125
app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.dts
Normal file
125
app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.dts
Normal file
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Copyright (c) 2023 The ZMK Contributors
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include <rpi_pico/rp2040.dtsi>
|
||||
#include <dt-bindings/zmk/matrix_transform.h>
|
||||
|
||||
/ {
|
||||
|
||||
chosen {
|
||||
zephyr,sram = &sram0;
|
||||
zephyr,flash = &flash0;
|
||||
zephyr,console = &cdc_acm_uart;
|
||||
zephyr,shell-uart = &cdc_acm_uart;
|
||||
zephyr,code-partition = &code_partition;
|
||||
zmk,kscan = &kscan0;
|
||||
zmk,matrix_transform = &default_transform;
|
||||
};
|
||||
|
||||
xtal_clk: xtal-clk {
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <12000000>;
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
default_transform: keymap_transform_0 {
|
||||
compatible = "zmk,matrix-transform";
|
||||
columns = <15>;
|
||||
rows = <5>;
|
||||
|
||||
// ------- Switch Matrix ----------
|
||||
//
|
||||
// Column 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
|
||||
// ==========================================================================================
|
||||
// Row 0 || S0 | S1 | S2 | S3 | S4 | S5 | S6 | S7 | S8 | S9 | S10 | S11 | S12 | S13 | S14 |
|
||||
// Row 1 || S0 | S1 | S2 | S3 | S4 | S5 | S6 | S7 | S8 | S9 | S10 | S11 | S12 | S13 | S14 |
|
||||
// Row 2 || S0 | S1 | S2 | S3 | S4 | S5 | S6 | S7 | S8 | S9 | S10 | S11 | S12 | | S13 |
|
||||
// Row 3 || S0 | S1 | S2 | S3 | S4 | S5 | S6 | S7 | S8 | S9 | S10 | S11 | | S12 | S13 |
|
||||
// Row 4 || S0 | S1 | S2 | | | | S3 | | S4 | S5 | S6 | | S7 | S8 | S9 |
|
||||
// -----------------------------------------------------------------------------------
|
||||
//
|
||||
map = <
|
||||
RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14)
|
||||
RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) RC(1,14)
|
||||
RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,14)
|
||||
RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,13) RC(3,14)
|
||||
RC(4,0) RC(4,1) RC(4,2) RC(4,6) RC(4,8) RC(4,9) RC(4,10) RC(4,12) RC(4,13) RC(4,14)
|
||||
>;
|
||||
};
|
||||
|
||||
kscan0: kscan {
|
||||
compatible = "zmk,kscan-gpio-matrix";
|
||||
label = "KSCAN";
|
||||
|
||||
diode-direction = "col2row";
|
||||
row-gpios
|
||||
= <&gpio0 29 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
|
||||
, <&gpio0 28 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
|
||||
, <&gpio0 27 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
|
||||
, <&gpio0 26 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
|
||||
, <&gpio0 22 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
|
||||
;
|
||||
col-gpios
|
||||
= <&gpio0 25 GPIO_ACTIVE_HIGH>
|
||||
, <&gpio0 24 GPIO_ACTIVE_HIGH>
|
||||
, <&gpio0 23 GPIO_ACTIVE_HIGH>
|
||||
, <&gpio0 1 GPIO_ACTIVE_HIGH>
|
||||
, <&gpio0 7 GPIO_ACTIVE_HIGH>
|
||||
, <&gpio0 21 GPIO_ACTIVE_HIGH>
|
||||
, <&gpio0 20 GPIO_ACTIVE_HIGH>
|
||||
, <&gpio0 19 GPIO_ACTIVE_HIGH>
|
||||
, <&gpio0 18 GPIO_ACTIVE_HIGH>
|
||||
, <&gpio0 17 GPIO_ACTIVE_HIGH>
|
||||
, <&gpio0 16 GPIO_ACTIVE_HIGH>
|
||||
, <&gpio0 15 GPIO_ACTIVE_HIGH>
|
||||
, <&gpio0 14 GPIO_ACTIVE_HIGH>
|
||||
, <&gpio0 13 GPIO_ACTIVE_HIGH>
|
||||
, <&gpio0 12 GPIO_ACTIVE_HIGH>
|
||||
;
|
||||
};
|
||||
};
|
||||
|
||||
&flash0 {
|
||||
reg = <0x10000000 DT_SIZE_M(16)>;
|
||||
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
/* Reserved memory for the second stage bootloader */
|
||||
second_stage_bootloader: partition@0 {
|
||||
label = "second_stage_bootloader";
|
||||
reg = <0x00000000 0x100>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
/*
|
||||
* Usable flash. Starts at 0x100, after the bootloader. The partition
|
||||
* size is 16MB minus the 0x100 bytes taken by the bootloader.
|
||||
*/
|
||||
code_partition: partition@100 {
|
||||
label = "code";
|
||||
reg = <0x100 (DT_SIZE_M(16) - 0x100)>;
|
||||
read-only;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
&usbd {
|
||||
status = "okay";
|
||||
cdc_acm_uart: cdc_acm_uart {
|
||||
compatible = "zephyr,cdc-acm-uart";
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
&gpio0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
97
app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.keymap
Normal file
97
app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.keymap
Normal file
|
@ -0,0 +1,97 @@
|
|||
// Copyright (c) 2023 The ZMK Contributors
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/keys.h>
|
||||
|
||||
#define BASE 0
|
||||
#define FUNC 1
|
||||
|
||||
//
|
||||
// ---------- Tofu65 2.0 key switch positions ----------
|
||||
//
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 24 | 26 | 27 | 28 | 29 |
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 |
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
|
||||
/ {
|
||||
combos {
|
||||
compatible = "zmk,combos";
|
||||
|
||||
// BACKSPACE + LCTRL + LALT = &sys_reset
|
||||
combo_bootloader {
|
||||
timeout-ms = <100>;
|
||||
key-positions = <13 58 60>;
|
||||
bindings = <&sys_reset>;
|
||||
};
|
||||
|
||||
// RETURN + LCTRL + LALT = &bootloader
|
||||
combo_sys_reset {
|
||||
timeout-ms = <100>;
|
||||
key-positions = <42 58 60>;
|
||||
bindings = <&bootloader>;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
keymap {
|
||||
compatible = "zmk,keymap";
|
||||
|
||||
base {
|
||||
|
||||
// --------- Default QWERTY Layout ---------
|
||||
// Layer 0 BASE
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BSPC | HME |
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | PGU |
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | PGD |
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// | LSHIFT | Z | X | C | V | B | N | M | , | . | / | RSHFT | ↑ | END |
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// | LCTL | LGUI | LALT | SPACE | RALT | RGUI | RCTL | <- | ↓ | -> |
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
bindings = <
|
||||
&kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp HOME
|
||||
&kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp PG_UP
|
||||
&kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp ENTER &kp PG_DN
|
||||
&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &kp END
|
||||
&kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT < FUNC K_APP &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT
|
||||
>;
|
||||
};
|
||||
|
||||
func {
|
||||
// --------- Default QWERTY Layout ---------
|
||||
// Layer 1 FUNC
|
||||
// ---------------------------------------------------------------------------------------------------
|
||||
// | ESC | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | DEL | HME |
|
||||
// ---------------------------------------------------------------------------------------------------
|
||||
// | --- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | scroll lock | pause | --- | PGU |
|
||||
// ---------------------------------------------------------------------------------------------------
|
||||
// | CAPS | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | --- | PGD |
|
||||
// ---------------------------------------------------------------------------------------------------
|
||||
// | LSHIFT | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | ----- | VOL UP | MUTE |
|
||||
// ---------------------------------------------------------------------------------------------------
|
||||
// | ---- | ---- | ---- | ---- | -- | MO 1 | -- | PREV | VOL DN | NEXT |
|
||||
// ---------------------------------------------------------------------------------------------------
|
||||
bindings = <
|
||||
&kp GRAVE &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp DEL &trans
|
||||
&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &kp SLCK &kp PAUSE_BREAK &trans &trans
|
||||
&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans
|
||||
&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &kp C_VOL_UP &kp C_MUTE
|
||||
&trans &trans &trans &trans &trans &trans &trans &kp C_PREV &kp C_VOL_DN &kp C_NEXT
|
||||
>;
|
||||
};
|
||||
};
|
||||
};
|
15
app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.yaml
Normal file
15
app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.yaml
Normal file
|
@ -0,0 +1,15 @@
|
|||
identifier: kbdfans_tofu65_v2
|
||||
name: KBDfans Tofu65 2.0
|
||||
type: mcu
|
||||
arch: arm
|
||||
flash: 16384
|
||||
ram: 264
|
||||
toolchain:
|
||||
- zephyr
|
||||
- gnuarmemb
|
||||
- xtools
|
||||
supported:
|
||||
- gpio
|
||||
- usb_device
|
||||
- hwinfo
|
||||
- pwm
|
10
app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.zmk.yml
Normal file
10
app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2.zmk.yml
Normal file
|
@ -0,0 +1,10 @@
|
|||
file_format: "1"
|
||||
id: kbdfans_tofu65_v2
|
||||
name: KBDfans Tofu65 2.0
|
||||
type: board
|
||||
arch: arm
|
||||
features:
|
||||
- keys
|
||||
outputs:
|
||||
- usb
|
||||
url: https://kbdfans.com/collections/tofu65-2-0/products/tofu65-2-0
|
20
app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2_defconfig
Normal file
20
app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2_defconfig
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Copyright (c) 2023 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
CONFIG_SOC_SERIES_RP2XXX=y
|
||||
CONFIG_SOC_RP2040=y
|
||||
CONFIG_BOARD_KBDFANS_TOFU65_V2=y
|
||||
|
||||
CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=125000000
|
||||
|
||||
# Enable USB CDC ACM logging for debugging
|
||||
# CONFIG_ZMK_USB_LOGGING=y
|
||||
|
||||
# Enable reset by default
|
||||
CONFIG_RESET=y
|
||||
|
||||
# Code partition needed to target the correct flash range
|
||||
CONFIG_USE_DT_CODE_PARTITION=y
|
||||
|
||||
# Output UF2 by default, native bootloader supports it.
|
||||
CONFIG_BUILD_OUTPUT_UF2=y
|
|
@ -48,7 +48,7 @@
|
|||
};
|
||||
|
||||
&i2c0 {
|
||||
compatible = "nordic,nrf-twim";
|
||||
compatible = "nordic,nrf-twi";
|
||||
pinctrl-0 = <&i2c0_default>;
|
||||
pinctrl-1 = <&i2c0_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
|
@ -56,6 +56,7 @@
|
|||
|
||||
&uart0 {
|
||||
compatible = "nordic,nrf-uarte";
|
||||
current-speed = <115200>;
|
||||
pinctrl-0 = <&uart0_default>;
|
||||
pinctrl-1 = <&uart0_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
};
|
||||
|
||||
&i2c0 {
|
||||
compatible = "nordic,nrf-twim";
|
||||
compatible = "nordic,nrf-twi";
|
||||
pinctrl-0 = <&i2c0_default>;
|
||||
pinctrl-1 = <&i2c0_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
|
@ -56,6 +56,7 @@
|
|||
|
||||
&uart0 {
|
||||
compatible = "nordic,nrf-uarte";
|
||||
current-speed = <115200>;
|
||||
pinctrl-0 = <&uart0_default>;
|
||||
pinctrl-1 = <&uart0_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
};
|
||||
|
||||
&i2c0 {
|
||||
compatible = "nordic,nrf-twim";
|
||||
compatible = "nordic,nrf-twi";
|
||||
pinctrl-0 = <&i2c0_default>;
|
||||
pinctrl-1 = <&i2c0_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
|
@ -69,6 +69,7 @@
|
|||
|
||||
&uart0 {
|
||||
compatible = "nordic,nrf-uarte";
|
||||
current-speed = <115200>;
|
||||
pinctrl-0 = <&uart0_default>;
|
||||
pinctrl-1 = <&uart0_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
};
|
||||
|
||||
&i2c0 {
|
||||
compatible = "nordic,nrf-twim";
|
||||
compatible = "nordic,nrf-twi";
|
||||
pinctrl-0 = <&i2c0_default>;
|
||||
pinctrl-1 = <&i2c0_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
|
@ -69,6 +69,7 @@
|
|||
|
||||
&uart0 {
|
||||
compatible = "nordic,nrf-uarte";
|
||||
current-speed = <115200>;
|
||||
pinctrl-0 = <&uart0_default>;
|
||||
pinctrl-1 = <&uart0_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
|
|
|
@ -5,6 +5,7 @@ zephyr_library_named(zmk__drivers__kscan)
|
|||
zephyr_library_include_directories(${CMAKE_SOURCE_DIR}/include)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DRIVER debounce.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DRIVER kscan_gpio.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_MATRIX kscan_gpio_matrix.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DIRECT kscan_gpio_direct.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DEMUX kscan_gpio_demux.c)
|
||||
|
|
33
app/drivers/kscan/kscan_gpio.c
Normal file
33
app/drivers/kscan/kscan_gpio.c
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2022 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "kscan_gpio.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static int compare_ports(const void *a, const void *b) {
|
||||
const struct kscan_gpio *gpio_a = a;
|
||||
const struct kscan_gpio *gpio_b = b;
|
||||
|
||||
return gpio_a->spec.port - gpio_b->spec.port;
|
||||
}
|
||||
|
||||
void kscan_gpio_list_sort_by_port(struct kscan_gpio_list *list) {
|
||||
qsort(list->gpios, list->len, sizeof(list->gpios[0]), compare_ports);
|
||||
}
|
||||
|
||||
int kscan_gpio_pin_get(const struct kscan_gpio *gpio, struct kscan_gpio_port_state *state) {
|
||||
if (gpio->spec.port != state->port) {
|
||||
state->port = gpio->spec.port;
|
||||
|
||||
const int err = gpio_port_get(state->port, &state->value);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return (state->value & BIT(gpio->spec.pin)) != 0;
|
||||
}
|
61
app/drivers/kscan/kscan_gpio.h
Normal file
61
app/drivers/kscan/kscan_gpio.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2022 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/dt-bindings/gpio/gpio.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
struct kscan_gpio {
|
||||
struct gpio_dt_spec spec;
|
||||
/** The index of the GPIO in the devicetree *-gpios array. */
|
||||
size_t index;
|
||||
};
|
||||
|
||||
/** GPIO_DT_SPEC_GET_BY_IDX(), but for a struct kscan_gpio. */
|
||||
#define KSCAN_GPIO_GET_BY_IDX(node_id, prop, idx) \
|
||||
((struct kscan_gpio){.spec = GPIO_DT_SPEC_GET_BY_IDX(node_id, prop, idx), .index = idx})
|
||||
|
||||
struct kscan_gpio_list {
|
||||
struct kscan_gpio *gpios;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
/** Define a kscan_gpio_list from a compile-time GPIO array. */
|
||||
#define KSCAN_GPIO_LIST(gpio_array) \
|
||||
((struct kscan_gpio_list){.gpios = gpio_array, .len = ARRAY_SIZE(gpio_array)})
|
||||
|
||||
struct kscan_gpio_port_state {
|
||||
const struct device *port;
|
||||
gpio_port_value_t value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sorts a GPIO list by port so it can be used with kscan_gpio_pin_get().
|
||||
*/
|
||||
void kscan_gpio_list_sort_by_port(struct kscan_gpio_list *list);
|
||||
|
||||
/**
|
||||
* Get logical level of an input pin.
|
||||
*
|
||||
* This is equivalent to gpio_pin_get() except that, when iterating through the
|
||||
* pins in a list which is sorted by kscan_gpio_list_sort_by_port(), it only
|
||||
* performs one read per port instead of one read per pin.
|
||||
*
|
||||
* @param gpio The input pin to read.
|
||||
* @param state An object to track state between reads. Must be zero-initialized before the first
|
||||
* use.
|
||||
*
|
||||
* @retval 1 If pin logical value is 1 / active.
|
||||
* @retval 0 If pin logical value is 0 / inactive.
|
||||
* @retval -EIO I/O error when accessing an external GPIO chip.
|
||||
* @retval -EWOULDBLOCK if operation would block.
|
||||
*/
|
||||
int kscan_gpio_pin_get(const struct kscan_gpio *gpio, struct kscan_gpio_port_state *state);
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include "debounce.h"
|
||||
#include "kscan_gpio.h"
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/devicetree.h>
|
||||
|
@ -41,7 +42,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
|
||||
#define INST_INPUTS_LEN(n) DT_INST_PROP_LEN(n, input_gpios)
|
||||
#define KSCAN_DIRECT_INPUT_CFG_INIT(idx, inst_idx) \
|
||||
GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst_idx), input_gpios, idx)
|
||||
KSCAN_GPIO_GET_BY_IDX(DT_DRV_INST(inst_idx), input_gpios, idx)
|
||||
|
||||
struct kscan_direct_irq_callback {
|
||||
const struct device *dev;
|
||||
|
@ -50,6 +51,7 @@ struct kscan_direct_irq_callback {
|
|||
|
||||
struct kscan_direct_data {
|
||||
const struct device *dev;
|
||||
struct kscan_gpio_list inputs;
|
||||
kscan_callback_t callback;
|
||||
struct k_work_delayable work;
|
||||
#if USE_INTERRUPTS
|
||||
|
@ -62,17 +64,7 @@ struct kscan_direct_data {
|
|||
struct debounce_state *pin_state;
|
||||
};
|
||||
|
||||
struct kscan_gpio_list {
|
||||
const struct gpio_dt_spec *gpios;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
/** Define a kscan_gpio_list from a compile-time GPIO array. */
|
||||
#define KSCAN_GPIO_LIST(gpio_array) \
|
||||
((struct kscan_gpio_list){.gpios = gpio_array, .len = ARRAY_SIZE(gpio_array)})
|
||||
|
||||
struct kscan_direct_config {
|
||||
struct kscan_gpio_list inputs;
|
||||
struct debounce_config debounce_config;
|
||||
int32_t debounce_scan_period_ms;
|
||||
int32_t poll_period_ms;
|
||||
|
@ -81,10 +73,10 @@ struct kscan_direct_config {
|
|||
|
||||
#if USE_INTERRUPTS
|
||||
static int kscan_direct_interrupt_configure(const struct device *dev, const gpio_flags_t flags) {
|
||||
const struct kscan_direct_config *config = dev->config;
|
||||
const struct kscan_direct_data *data = dev->data;
|
||||
|
||||
for (int i = 0; i < config->inputs.len; i++) {
|
||||
const struct gpio_dt_spec *gpio = &config->inputs.gpios[i];
|
||||
for (int i = 0; i < data->inputs.len; i++) {
|
||||
const struct gpio_dt_spec *gpio = &data->inputs.gpios[i].spec;
|
||||
|
||||
int err = gpio_pin_interrupt_configure_dt(gpio, flags);
|
||||
if (err) {
|
||||
|
@ -134,16 +126,16 @@ static gpio_flags_t kscan_gpio_get_extra_flags(const struct gpio_dt_spec *gpio,
|
|||
|
||||
static int kscan_inputs_set_flags(const struct kscan_gpio_list *inputs,
|
||||
const struct gpio_dt_spec *active_gpio) {
|
||||
gpio_flags_t extra_flags;
|
||||
for (int i = 0; i < inputs->len; i++) {
|
||||
extra_flags = GPIO_INPUT | kscan_gpio_get_extra_flags(&inputs->gpios[i],
|
||||
&inputs->gpios[i] == active_gpio);
|
||||
const bool active = &inputs->gpios[i].spec == active_gpio;
|
||||
const gpio_flags_t extra_flags =
|
||||
GPIO_INPUT | kscan_gpio_get_extra_flags(&inputs->gpios[i].spec, active);
|
||||
LOG_DBG("Extra flags equal to: %d", extra_flags);
|
||||
|
||||
int err = gpio_pin_configure_dt(&inputs->gpios[i], extra_flags);
|
||||
int err = gpio_pin_configure_dt(&inputs->gpios[i].spec, extra_flags);
|
||||
if (err) {
|
||||
LOG_ERR("Unable to configure flags on pin %d on %s", inputs->gpios[i].pin,
|
||||
inputs->gpios[i].port->name);
|
||||
LOG_ERR("Unable to configure flags on pin %d on %s", inputs->gpios[i].spec.pin,
|
||||
inputs->gpios[i].spec.port->name);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
@ -179,28 +171,35 @@ static int kscan_direct_read(const struct device *dev) {
|
|||
const struct kscan_direct_config *config = dev->config;
|
||||
|
||||
// Read the inputs.
|
||||
for (int i = 0; i < config->inputs.len; i++) {
|
||||
const struct gpio_dt_spec *gpio = &config->inputs.gpios[i];
|
||||
struct kscan_gpio_port_state state = {0};
|
||||
|
||||
const bool active = gpio_pin_get_dt(gpio);
|
||||
for (int i = 0; i < data->inputs.len; i++) {
|
||||
const struct kscan_gpio *gpio = &data->inputs.gpios[i];
|
||||
|
||||
debounce_update(&data->pin_state[i], active, config->debounce_scan_period_ms,
|
||||
const int active = kscan_gpio_pin_get(gpio, &state);
|
||||
if (active < 0) {
|
||||
LOG_ERR("Failed to read port %s: %i", gpio->spec.port->name, active);
|
||||
return active;
|
||||
}
|
||||
|
||||
debounce_update(&data->pin_state[gpio->index], active, config->debounce_scan_period_ms,
|
||||
&config->debounce_config);
|
||||
}
|
||||
|
||||
// Process the new state.
|
||||
bool continue_scan = false;
|
||||
|
||||
for (int i = 0; i < config->inputs.len; i++) {
|
||||
struct debounce_state *state = &data->pin_state[i];
|
||||
for (int i = 0; i < data->inputs.len; i++) {
|
||||
const struct kscan_gpio *gpio = &data->inputs.gpios[i];
|
||||
struct debounce_state *state = &data->pin_state[gpio->index];
|
||||
|
||||
if (debounce_get_changed(state)) {
|
||||
const bool pressed = debounce_is_pressed(state);
|
||||
|
||||
LOG_DBG("Sending event at 0,%i state %s", i, pressed ? "on" : "off");
|
||||
data->callback(dev, 0, i, pressed);
|
||||
LOG_DBG("Sending event at 0,%i state %s", gpio->index, pressed ? "on" : "off");
|
||||
data->callback(dev, 0, gpio->index, pressed);
|
||||
if (config->toggle_mode && pressed) {
|
||||
kscan_inputs_set_flags(&config->inputs, &config->inputs.gpios[i]);
|
||||
kscan_inputs_set_flags(&data->inputs, &gpio->spec);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -289,10 +288,11 @@ static int kscan_direct_init_input_inst(const struct device *dev, const struct g
|
|||
}
|
||||
|
||||
static int kscan_direct_init_inputs(const struct device *dev) {
|
||||
const struct kscan_direct_data *data = dev->data;
|
||||
const struct kscan_direct_config *config = dev->config;
|
||||
|
||||
for (int i = 0; i < config->inputs.len; i++) {
|
||||
const struct gpio_dt_spec *gpio = &config->inputs.gpios[i];
|
||||
for (int i = 0; i < data->inputs.len; i++) {
|
||||
const struct gpio_dt_spec *gpio = &data->inputs.gpios[i].spec;
|
||||
int err = kscan_direct_init_input_inst(dev, gpio, i, config->toggle_mode);
|
||||
if (err) {
|
||||
return err;
|
||||
|
@ -307,6 +307,9 @@ static int kscan_direct_init(const struct device *dev) {
|
|||
|
||||
data->dev = dev;
|
||||
|
||||
// Sort inputs by port so we can read each port just once per scan.
|
||||
kscan_gpio_list_sort_by_port(&data->inputs);
|
||||
|
||||
kscan_direct_init_inputs(dev);
|
||||
|
||||
k_work_init_delayable(&data->work, kscan_direct_work_handler);
|
||||
|
@ -326,7 +329,7 @@ static const struct kscan_driver_api kscan_direct_api = {
|
|||
BUILD_ASSERT(INST_DEBOUNCE_RELEASE_MS(n) <= DEBOUNCE_COUNTER_MAX, \
|
||||
"ZMK_KSCAN_DEBOUNCE_RELEASE_MS or debounce-release-ms is too large"); \
|
||||
\
|
||||
static const struct gpio_dt_spec kscan_direct_inputs_##n[] = { \
|
||||
static struct kscan_gpio kscan_direct_inputs_##n[] = { \
|
||||
LISTIFY(INST_INPUTS_LEN(n), KSCAN_DIRECT_INPUT_CFG_INIT, (, ), n)}; \
|
||||
\
|
||||
static struct debounce_state kscan_direct_state_##n[INST_INPUTS_LEN(n)]; \
|
||||
|
@ -335,10 +338,11 @@ static const struct kscan_driver_api kscan_direct_api = {
|
|||
(static struct kscan_direct_irq_callback kscan_direct_irqs_##n[INST_INPUTS_LEN(n)];)) \
|
||||
\
|
||||
static struct kscan_direct_data kscan_direct_data_##n = { \
|
||||
.pin_state = kscan_direct_state_##n, COND_INTERRUPTS((.irqs = kscan_direct_irqs_##n, ))}; \
|
||||
.inputs = KSCAN_GPIO_LIST(kscan_direct_inputs_##n), \
|
||||
.pin_state = kscan_direct_state_##n, \
|
||||
COND_INTERRUPTS((.irqs = kscan_direct_irqs_##n, ))}; \
|
||||
\
|
||||
static struct kscan_direct_config kscan_direct_config_##n = { \
|
||||
.inputs = KSCAN_GPIO_LIST(kscan_direct_inputs_##n), \
|
||||
.debounce_config = \
|
||||
{ \
|
||||
.debounce_press_ms = INST_DEBOUNCE_PRESS_MS(n), \
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include "debounce.h"
|
||||
#include "kscan_gpio.h"
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/devicetree.h>
|
||||
|
@ -50,9 +51,9 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, pollcode, intcode)
|
||||
|
||||
#define KSCAN_GPIO_ROW_CFG_INIT(idx, inst_idx) \
|
||||
GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst_idx), row_gpios, idx)
|
||||
KSCAN_GPIO_GET_BY_IDX(DT_DRV_INST(inst_idx), row_gpios, idx)
|
||||
#define KSCAN_GPIO_COL_CFG_INIT(idx, inst_idx) \
|
||||
GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst_idx), col_gpios, idx)
|
||||
KSCAN_GPIO_GET_BY_IDX(DT_DRV_INST(inst_idx), col_gpios, idx)
|
||||
|
||||
enum kscan_diode_direction {
|
||||
KSCAN_ROW2COL,
|
||||
|
@ -66,6 +67,7 @@ struct kscan_matrix_irq_callback {
|
|||
|
||||
struct kscan_matrix_data {
|
||||
const struct device *dev;
|
||||
struct kscan_gpio_list inputs;
|
||||
kscan_callback_t callback;
|
||||
struct k_work_delayable work;
|
||||
#if USE_INTERRUPTS
|
||||
|
@ -76,26 +78,16 @@ struct kscan_matrix_data {
|
|||
int64_t scan_time;
|
||||
/**
|
||||
* Current state of the matrix as a flattened 2D array of length
|
||||
* (config->rows.len * config->cols.len)
|
||||
* (config->rows * config->cols)
|
||||
*/
|
||||
struct debounce_state *matrix_state;
|
||||
};
|
||||
|
||||
struct kscan_gpio_list {
|
||||
const struct gpio_dt_spec *gpios;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
/** Define a kscan_gpio_list from a compile-time GPIO array. */
|
||||
#define KSCAN_GPIO_LIST(gpio_array) \
|
||||
((struct kscan_gpio_list){.gpios = gpio_array, .len = ARRAY_SIZE(gpio_array)})
|
||||
|
||||
struct kscan_matrix_config {
|
||||
struct kscan_gpio_list rows;
|
||||
struct kscan_gpio_list cols;
|
||||
struct kscan_gpio_list inputs;
|
||||
struct kscan_gpio_list outputs;
|
||||
struct debounce_config debounce_config;
|
||||
size_t rows;
|
||||
size_t cols;
|
||||
int32_t debounce_scan_period_ms;
|
||||
int32_t poll_period_ms;
|
||||
enum kscan_diode_direction diode_direction;
|
||||
|
@ -105,10 +97,10 @@ struct kscan_matrix_config {
|
|||
* Get the index into a matrix state array from a row and column.
|
||||
*/
|
||||
static int state_index_rc(const struct kscan_matrix_config *config, const int row, const int col) {
|
||||
__ASSERT(row < config->rows.len, "Invalid row %i", row);
|
||||
__ASSERT(col < config->cols.len, "Invalid column %i", col);
|
||||
__ASSERT(row < config->rows, "Invalid row %i", row);
|
||||
__ASSERT(col < config->cols, "Invalid column %i", col);
|
||||
|
||||
return (col * config->rows.len) + row;
|
||||
return (col * config->rows) + row;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -125,7 +117,7 @@ static int kscan_matrix_set_all_outputs(const struct device *dev, const int valu
|
|||
const struct kscan_matrix_config *config = dev->config;
|
||||
|
||||
for (int i = 0; i < config->outputs.len; i++) {
|
||||
const struct gpio_dt_spec *gpio = &config->outputs.gpios[i];
|
||||
const struct gpio_dt_spec *gpio = &config->outputs.gpios[i].spec;
|
||||
|
||||
int err = gpio_pin_set_dt(gpio, value);
|
||||
if (err) {
|
||||
|
@ -139,10 +131,10 @@ static int kscan_matrix_set_all_outputs(const struct device *dev, const int valu
|
|||
|
||||
#if USE_INTERRUPTS
|
||||
static int kscan_matrix_interrupt_configure(const struct device *dev, const gpio_flags_t flags) {
|
||||
const struct kscan_matrix_config *config = dev->config;
|
||||
const struct kscan_matrix_data *data = dev->data;
|
||||
|
||||
for (int i = 0; i < config->inputs.len; i++) {
|
||||
const struct gpio_dt_spec *gpio = &config->inputs.gpios[i];
|
||||
for (int i = 0; i < data->inputs.len; i++) {
|
||||
const struct gpio_dt_spec *gpio = &data->inputs.gpios[i].spec;
|
||||
|
||||
int err = gpio_pin_interrupt_configure_dt(gpio, flags);
|
||||
if (err) {
|
||||
|
@ -226,32 +218,37 @@ static int kscan_matrix_read(const struct device *dev) {
|
|||
const struct kscan_matrix_config *config = dev->config;
|
||||
|
||||
// Scan the matrix.
|
||||
for (int o = 0; o < config->outputs.len; o++) {
|
||||
const struct gpio_dt_spec *out_gpio = &config->outputs.gpios[o];
|
||||
for (int i = 0; i < config->outputs.len; i++) {
|
||||
const struct kscan_gpio *out_gpio = &config->outputs.gpios[i];
|
||||
|
||||
int err = gpio_pin_set_dt(out_gpio, 1);
|
||||
int err = gpio_pin_set_dt(&out_gpio->spec, 1);
|
||||
if (err) {
|
||||
LOG_ERR("Failed to set output %i active: %i", o, err);
|
||||
LOG_ERR("Failed to set output %i active: %i", out_gpio->index, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
#if CONFIG_ZMK_KSCAN_MATRIX_WAIT_BEFORE_INPUTS > 0
|
||||
k_busy_wait(CONFIG_ZMK_KSCAN_MATRIX_WAIT_BEFORE_INPUTS);
|
||||
#endif
|
||||
struct kscan_gpio_port_state state = {0};
|
||||
|
||||
for (int i = 0; i < config->inputs.len; i++) {
|
||||
const struct gpio_dt_spec *in_gpio = &config->inputs.gpios[i];
|
||||
for (int j = 0; j < data->inputs.len; j++) {
|
||||
const struct kscan_gpio *in_gpio = &data->inputs.gpios[j];
|
||||
|
||||
const int index = state_index_io(config, i, o);
|
||||
const bool active = gpio_pin_get_dt(in_gpio);
|
||||
const int index = state_index_io(config, in_gpio->index, out_gpio->index);
|
||||
const int active = kscan_gpio_pin_get(in_gpio, &state);
|
||||
if (active < 0) {
|
||||
LOG_ERR("Failed to read port %s: %i", in_gpio->spec.port->name, active);
|
||||
return active;
|
||||
}
|
||||
|
||||
debounce_update(&data->matrix_state[index], active, config->debounce_scan_period_ms,
|
||||
&config->debounce_config);
|
||||
}
|
||||
|
||||
err = gpio_pin_set_dt(out_gpio, 0);
|
||||
err = gpio_pin_set_dt(&out_gpio->spec, 0);
|
||||
if (err) {
|
||||
LOG_ERR("Failed to set output %i inactive: %i", o, err);
|
||||
LOG_ERR("Failed to set output %i inactive: %i", out_gpio->index, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -263,8 +260,8 @@ static int kscan_matrix_read(const struct device *dev) {
|
|||
// Process the new state.
|
||||
bool continue_scan = false;
|
||||
|
||||
for (int r = 0; r < config->rows.len; r++) {
|
||||
for (int c = 0; c < config->cols.len; c++) {
|
||||
for (int r = 0; r < config->rows; r++) {
|
||||
for (int c = 0; c < config->cols; c++) {
|
||||
const int index = state_index_rc(config, r, c);
|
||||
struct debounce_state *state = &data->matrix_state[index];
|
||||
|
||||
|
@ -329,28 +326,28 @@ static int kscan_matrix_disable(const struct device *dev) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static int kscan_matrix_init_input_inst(const struct device *dev, const struct gpio_dt_spec *gpio,
|
||||
const int index) {
|
||||
if (!device_is_ready(gpio->port)) {
|
||||
LOG_ERR("GPIO is not ready: %s", gpio->port->name);
|
||||
static int kscan_matrix_init_input_inst(const struct device *dev, const struct kscan_gpio *gpio) {
|
||||
if (!device_is_ready(gpio->spec.port)) {
|
||||
LOG_ERR("GPIO is not ready: %s", gpio->spec.port->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int err = gpio_pin_configure_dt(gpio, GPIO_INPUT);
|
||||
int err = gpio_pin_configure_dt(&gpio->spec, GPIO_INPUT);
|
||||
if (err) {
|
||||
LOG_ERR("Unable to configure pin %u on %s for input", gpio->pin, gpio->port->name);
|
||||
LOG_ERR("Unable to configure pin %u on %s for input", gpio->spec.pin,
|
||||
gpio->spec.port->name);
|
||||
return err;
|
||||
}
|
||||
|
||||
LOG_DBG("Configured pin %u on %s for input", gpio->pin, gpio->port->name);
|
||||
LOG_DBG("Configured pin %u on %s for input", gpio->spec.pin, gpio->spec.port->name);
|
||||
|
||||
#if USE_INTERRUPTS
|
||||
struct kscan_matrix_data *data = dev->data;
|
||||
struct kscan_matrix_irq_callback *irq = &data->irqs[index];
|
||||
struct kscan_matrix_irq_callback *irq = &data->irqs[gpio->index];
|
||||
|
||||
irq->dev = dev;
|
||||
gpio_init_callback(&irq->callback, kscan_matrix_irq_callback_handler, BIT(gpio->pin));
|
||||
err = gpio_add_callback(gpio->port, &irq->callback);
|
||||
gpio_init_callback(&irq->callback, kscan_matrix_irq_callback_handler, BIT(gpio->spec.pin));
|
||||
err = gpio_add_callback(gpio->spec.port, &irq->callback);
|
||||
if (err) {
|
||||
LOG_ERR("Error adding the callback to the input device: %i", err);
|
||||
return err;
|
||||
|
@ -361,11 +358,11 @@ static int kscan_matrix_init_input_inst(const struct device *dev, const struct g
|
|||
}
|
||||
|
||||
static int kscan_matrix_init_inputs(const struct device *dev) {
|
||||
const struct kscan_matrix_config *config = dev->config;
|
||||
const struct kscan_matrix_data *data = dev->data;
|
||||
|
||||
for (int i = 0; i < config->inputs.len; i++) {
|
||||
const struct gpio_dt_spec *gpio = &config->inputs.gpios[i];
|
||||
int err = kscan_matrix_init_input_inst(dev, gpio, i);
|
||||
for (int i = 0; i < data->inputs.len; i++) {
|
||||
const struct kscan_gpio *gpio = &data->inputs.gpios[i];
|
||||
int err = kscan_matrix_init_input_inst(dev, gpio);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
@ -396,7 +393,7 @@ static int kscan_matrix_init_outputs(const struct device *dev) {
|
|||
const struct kscan_matrix_config *config = dev->config;
|
||||
|
||||
for (int i = 0; i < config->outputs.len; i++) {
|
||||
const struct gpio_dt_spec *gpio = &config->outputs.gpios[i];
|
||||
const struct gpio_dt_spec *gpio = &config->outputs.gpios[i].spec;
|
||||
int err = kscan_matrix_init_output_inst(dev, gpio);
|
||||
if (err) {
|
||||
return err;
|
||||
|
@ -411,6 +408,9 @@ static int kscan_matrix_init(const struct device *dev) {
|
|||
|
||||
data->dev = dev;
|
||||
|
||||
// Sort inputs by port so we can read each port just once per scan.
|
||||
kscan_gpio_list_sort_by_port(&data->inputs);
|
||||
|
||||
kscan_matrix_init_inputs(dev);
|
||||
kscan_matrix_init_outputs(dev);
|
||||
kscan_matrix_set_all_outputs(dev, 0);
|
||||
|
@ -432,10 +432,10 @@ static const struct kscan_driver_api kscan_matrix_api = {
|
|||
BUILD_ASSERT(INST_DEBOUNCE_RELEASE_MS(n) <= DEBOUNCE_COUNTER_MAX, \
|
||||
"ZMK_KSCAN_DEBOUNCE_RELEASE_MS or debounce-release-ms is too large"); \
|
||||
\
|
||||
static const struct gpio_dt_spec kscan_matrix_rows_##n[] = { \
|
||||
static struct kscan_gpio kscan_matrix_rows_##n[] = { \
|
||||
LISTIFY(INST_ROWS_LEN(n), KSCAN_GPIO_ROW_CFG_INIT, (, ), n)}; \
|
||||
\
|
||||
static const struct gpio_dt_spec kscan_matrix_cols_##n[] = { \
|
||||
static struct kscan_gpio kscan_matrix_cols_##n[] = { \
|
||||
LISTIFY(INST_COLS_LEN(n), KSCAN_GPIO_COL_CFG_INIT, (, ), n)}; \
|
||||
\
|
||||
static struct debounce_state kscan_matrix_state_##n[INST_MATRIX_LEN(n)]; \
|
||||
|
@ -444,14 +444,14 @@ static const struct kscan_driver_api kscan_matrix_api = {
|
|||
(static struct kscan_matrix_irq_callback kscan_matrix_irqs_##n[INST_INPUTS_LEN(n)];)) \
|
||||
\
|
||||
static struct kscan_matrix_data kscan_matrix_data_##n = { \
|
||||
.inputs = \
|
||||
KSCAN_GPIO_LIST(COND_DIODE_DIR(n, (kscan_matrix_cols_##n), (kscan_matrix_rows_##n))), \
|
||||
.matrix_state = kscan_matrix_state_##n, \
|
||||
COND_INTERRUPTS((.irqs = kscan_matrix_irqs_##n, ))}; \
|
||||
\
|
||||
static struct kscan_matrix_config kscan_matrix_config_##n = { \
|
||||
.rows = KSCAN_GPIO_LIST(kscan_matrix_rows_##n), \
|
||||
.cols = KSCAN_GPIO_LIST(kscan_matrix_cols_##n), \
|
||||
.inputs = \
|
||||
KSCAN_GPIO_LIST(COND_DIODE_DIR(n, (kscan_matrix_cols_##n), (kscan_matrix_rows_##n))), \
|
||||
.rows = ARRAY_SIZE(kscan_matrix_rows_##n), \
|
||||
.cols = ARRAY_SIZE(kscan_matrix_cols_##n), \
|
||||
.outputs = \
|
||||
KSCAN_GPIO_LIST(COND_DIODE_DIR(n, (kscan_matrix_rows_##n), (kscan_matrix_cols_##n))), \
|
||||
.debounce_config = \
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#if ZMK_BLE_IS_CENTRAL
|
||||
#define ZMK_BLE_PROFILE_COUNT (CONFIG_BT_MAX_PAIRED - 1)
|
||||
#define ZMK_BLE_SPLIT_PERIPHERAL_COUNT 1
|
||||
#define ZMK_SPLIT_BLE_PERIPHERAL_COUNT 1
|
||||
#else
|
||||
#define ZMK_BLE_PROFILE_COUNT CONFIG_BT_MAX_PAIRED
|
||||
#endif
|
||||
|
|
|
@ -118,6 +118,7 @@ void set_profile_address(uint8_t index, const bt_addr_le_t *addr) {
|
|||
|
||||
bool zmk_ble_active_profile_is_connected() {
|
||||
struct bt_conn *conn;
|
||||
struct bt_conn_info info;
|
||||
bt_addr_le_t *addr = zmk_ble_active_profile_addr();
|
||||
if (!bt_addr_le_cmp(addr, BT_ADDR_LE_ANY)) {
|
||||
return false;
|
||||
|
@ -125,9 +126,11 @@ bool zmk_ble_active_profile_is_connected() {
|
|||
return false;
|
||||
}
|
||||
|
||||
bt_conn_get_info(conn, &info);
|
||||
|
||||
bt_conn_unref(conn);
|
||||
|
||||
return true;
|
||||
return info.state == BT_CONN_STATE_CONNECTED;
|
||||
}
|
||||
|
||||
#define CHECKED_ADV_STOP() \
|
||||
|
|
|
@ -6,9 +6,8 @@ menuconfig ZMK_DISPLAY
|
|||
default n
|
||||
select DISPLAY
|
||||
select LVGL
|
||||
select LV_THEMES
|
||||
select LV_THEME_MONO
|
||||
select LV_CONF_MINIMAL
|
||||
imply LV_USE_THEME_MONO
|
||||
|
||||
if ZMK_DISPLAY
|
||||
|
||||
|
@ -16,6 +15,13 @@ config ZMK_DISPLAY_BLANK_ON_IDLE
|
|||
bool "Blank display on idle"
|
||||
default y if SSD1306
|
||||
|
||||
if LV_USE_THEME_MONO
|
||||
|
||||
config ZMK_DISPLAY_INVERT
|
||||
bool "Invert display colors"
|
||||
|
||||
endif
|
||||
|
||||
choice LV_TXT_ENC
|
||||
default LV_TXT_ENC_UTF8
|
||||
|
||||
|
|
|
@ -91,7 +91,8 @@ int zmk_display_is_initialized() { return initialized; }
|
|||
static void initialize_theme() {
|
||||
#if IS_ENABLED(CONFIG_LV_USE_THEME_MONO)
|
||||
lv_disp_t *disp = lv_disp_get_default();
|
||||
lv_theme_t *theme = lv_theme_mono_init(disp, false, CONFIG_LV_FONT_DEFAULT);
|
||||
lv_theme_t *theme =
|
||||
lv_theme_mono_init(disp, IS_ENABLED(CONFIG_ZMK_DISPLAY_INVERT), CONFIG_LV_FONT_DEFAULT);
|
||||
theme->font_small = CONFIG_ZMK_LV_FONT_DEFAULT_SMALL;
|
||||
|
||||
disp->theme = theme;
|
||||
|
|
|
@ -218,7 +218,7 @@ int zmk_keymap_apply_position_state(uint8_t source, int layer, uint32_t position
|
|||
#endif
|
||||
case BEHAVIOR_LOCALITY_GLOBAL:
|
||||
#if ZMK_BLE_IS_CENTRAL
|
||||
for (int i = 0; i < ZMK_BLE_SPLIT_PERIPHERAL_COUNT; i++) {
|
||||
for (int i = 0; i < ZMK_SPLIT_BLE_PERIPHERAL_COUNT; i++) {
|
||||
zmk_split_bt_invoke_behavior(i, &binding, event, pressed);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -21,11 +21,11 @@ config ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE
|
|||
int "Max number of key position state events to queue when received from peripherals"
|
||||
default 5
|
||||
|
||||
config ZMK_BLE_SPLIT_CENTRAL_SPLIT_RUN_STACK_SIZE
|
||||
config ZMK_SPLIT_BLE_CENTRAL_SPLIT_RUN_STACK_SIZE
|
||||
int "BLE split central write thread stack size"
|
||||
default 512
|
||||
|
||||
config ZMK_BLE_SPLIT_CENTRAL_SPLIT_RUN_QUEUE_SIZE
|
||||
config ZMK_SPLIT_BLE_CENTRAL_SPLIT_RUN_QUEUE_SIZE
|
||||
int "Max number of behavior run events to queue to send to the peripheral(s)"
|
||||
default 5
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ struct peripheral_slot {
|
|||
uint8_t changed_positions[POSITION_STATE_DATA_LEN];
|
||||
};
|
||||
|
||||
static struct peripheral_slot peripherals[ZMK_BLE_SPLIT_PERIPHERAL_COUNT];
|
||||
static struct peripheral_slot peripherals[ZMK_SPLIT_BLE_PERIPHERAL_COUNT];
|
||||
|
||||
static const struct bt_uuid_128 split_service_uuid = BT_UUID_INIT_128(ZMK_SPLIT_BT_SERVICE_UUID);
|
||||
|
||||
|
@ -65,7 +65,7 @@ void peripheral_event_work_callback(struct k_work *work) {
|
|||
K_WORK_DEFINE(peripheral_event_work, peripheral_event_work_callback);
|
||||
|
||||
int peripheral_slot_index_for_conn(struct bt_conn *conn) {
|
||||
for (int i = 0; i < ZMK_BLE_SPLIT_PERIPHERAL_COUNT; i++) {
|
||||
for (int i = 0; i < ZMK_SPLIT_BLE_PERIPHERAL_COUNT; i++) {
|
||||
if (peripherals[i].conn == conn) {
|
||||
return i;
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ struct peripheral_slot *peripheral_slot_for_conn(struct bt_conn *conn) {
|
|||
}
|
||||
|
||||
int release_peripheral_slot(int index) {
|
||||
if (index < 0 || index >= ZMK_BLE_SPLIT_PERIPHERAL_COUNT) {
|
||||
if (index < 0 || index >= ZMK_SPLIT_BLE_PERIPHERAL_COUNT) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -131,7 +131,7 @@ int release_peripheral_slot(int index) {
|
|||
}
|
||||
|
||||
int reserve_peripheral_slot() {
|
||||
for (int i = 0; i < ZMK_BLE_SPLIT_PERIPHERAL_COUNT; i++) {
|
||||
for (int i = 0; i < ZMK_SPLIT_BLE_PERIPHERAL_COUNT; i++) {
|
||||
if (peripherals[i].state == PERIPHERAL_SLOT_STATE_OPEN) {
|
||||
// Be sure the slot is fully reinitialized.
|
||||
release_peripheral_slot(i);
|
||||
|
@ -504,7 +504,7 @@ static struct bt_conn_cb conn_callbacks = {
|
|||
};
|
||||
|
||||
K_THREAD_STACK_DEFINE(split_central_split_run_q_stack,
|
||||
CONFIG_ZMK_BLE_SPLIT_CENTRAL_SPLIT_RUN_STACK_SIZE);
|
||||
CONFIG_ZMK_SPLIT_BLE_CENTRAL_SPLIT_RUN_STACK_SIZE);
|
||||
|
||||
struct k_work_q split_central_split_run_q;
|
||||
|
||||
|
@ -515,7 +515,7 @@ struct zmk_split_run_behavior_payload_wrapper {
|
|||
|
||||
K_MSGQ_DEFINE(zmk_split_central_split_run_msgq,
|
||||
sizeof(struct zmk_split_run_behavior_payload_wrapper),
|
||||
CONFIG_ZMK_BLE_SPLIT_CENTRAL_SPLIT_RUN_QUEUE_SIZE, 4);
|
||||
CONFIG_ZMK_SPLIT_BLE_CENTRAL_SPLIT_RUN_QUEUE_SIZE, 4);
|
||||
|
||||
void split_central_split_run_callback(struct k_work *work) {
|
||||
struct zmk_split_run_behavior_payload_wrapper payload_wrapper;
|
||||
|
|
|
@ -133,6 +133,23 @@ See the following example, which uses a hold-tap behavior definition, configured
|
|||
By default, `hold-trigger-key-positions` are evaluated upon the first _key press_ after
|
||||
the hold-tap. For homerow mods, this is not always ideal, because it prevents combining multiple modifiers unless they are included in `hold-trigger-key-positions`. To overwrite this behavior, one can set `hold-trigger-on-release`. If set to true, the evaluation of `hold-trigger-key-positions` gets delayed until _key release_. This allows combining multiple modifiers when the next key is _held_, while still deciding the hold-tap in favor of a tap when the next key is _tapped_.
|
||||
|
||||
#### Using different behavior types with hold-taps
|
||||
|
||||
You can create instances of hold-taps invoking most [behavior types](../features/keymaps.md#behaviors) for hold or tap actions, by referencing their node labels in the `bindings` value.
|
||||
The two parameters that are passed to the hold-tap in your keymap will be forwarded to the referred behaviors, first one to the hold behavior and second one to the tap.
|
||||
|
||||
If you use behaviors that accept no parameters such as [mod-morphs](mod-morph.md) or [macros](macros.md), you can pass a dummy parameter value such as `0` to the hold-tap when you use it in your keymap.
|
||||
For instance, a hold-tap with node label `caps` and `bindings = <&kp>, <&caps_word>;` can be used in the keymap as below to send the caps lock keycode on hold and invoke the [caps word behavior](caps-word.md) on tap:
|
||||
|
||||
```
|
||||
&caps CAPS 0
|
||||
```
|
||||
|
||||
:::info
|
||||
You cannot use behaviors that expect more than one parameter such as [`&bt`](bluetooth.md) and [`&rgb_ug`](underglow.md) with hold-taps, due to the limitations of the [devicetree keymap format](../config/index.md#devicetree-files).
|
||||
One workaround is to create a [macro](macros.md) that invokes those behaviors and use the macro as the hold or tap action.
|
||||
:::
|
||||
|
||||
### Example Use-Cases
|
||||
|
||||
<Tabs
|
||||
|
|
|
@ -33,7 +33,7 @@ A macro definition looks like:
|
|||
|
||||
:::note
|
||||
The text before the colon (`:`) in the declaration of the macro node is the "node label", and is the text
|
||||
used to reference the macro in your keymap
|
||||
used to reference the macro in your keymap.
|
||||
:::
|
||||
|
||||
The macro can then be bound in your keymap by referencing it by the label `&zed_em_kay`, e.g.:
|
||||
|
@ -44,6 +44,11 @@ The macro can then be bound in your keymap by referencing it by the label `&zed_
|
|||
};
|
||||
```
|
||||
|
||||
:::note
|
||||
For use cases involving sending a single keycode with modifiers, for instance ctrl+tab, the [key press behavior](key-press.md)
|
||||
with [modifier functions](../codes/modifiers.mdx#modifier-functions) can be used instead of a macro.
|
||||
:::
|
||||
|
||||
### Bindings
|
||||
|
||||
Like [hold-taps](/docs/behaviors/hold-tap), macros are created by composing other behaviors, and any of those behaviors can
|
||||
|
|
|
@ -17,12 +17,15 @@ Definition files:
|
|||
| Config | Type | Description | Default |
|
||||
| -------------------------------------------------- | ---- | -------------------------------------------------------------- | ------- |
|
||||
| `CONFIG_ZMK_DISPLAY` | bool | Enable support for displays | n |
|
||||
| `CONFIG_ZMK_DISPLAY_INVERT` | bool | Invert display colors from black-on-white to white-on-black | n |
|
||||
| `CONFIG_ZMK_WIDGET_LAYER_STATUS` | bool | Enable a widget to show the highest, active layer | y |
|
||||
| `CONFIG_ZMK_WIDGET_BATTERY_STATUS` | bool | Enable a widget to show battery charge information | y |
|
||||
| `CONFIG_ZMK_WIDGET_BATTERY_STATUS_SHOW_PERCENTAGE` | bool | If battery widget is enabled, show percentage instead of icons | n |
|
||||
| `CONFIG_ZMK_WIDGET_OUTPUT_STATUS` | bool | Enable a widget to show the current output (USB/BLE) | y |
|
||||
| `CONFIG_ZMK_WIDGET_WPM_STATUS` | bool | Enable a widget to show words per minute | n |
|
||||
|
||||
Note that `CONFIG_ZMK_DISPLAY_INVERT` setting might not work as expected with custom status screens that utilize images.
|
||||
|
||||
If `CONFIG_ZMK_DISPLAY` is enabled, exactly zero or one of the following options must be set to `y`. The first option is used if none are set.
|
||||
|
||||
| Config | Description |
|
||||
|
|
|
@ -97,8 +97,8 @@ Following split keyboard settings are defined in [zmk/app/src/split/Kconfig](htt
|
|||
| `CONFIG_ZMK_SPLIT_BLE` | bool | Use BLE to communicate between split keyboard halves | y |
|
||||
| `CONFIG_ZMK_SPLIT_ROLE_CENTRAL` | bool | `y` for central device, `n` for peripheral | |
|
||||
| `CONFIG_ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE` | int | Max number of key state events to queue when received from peripherals | 5 |
|
||||
| `CONFIG_ZMK_BLE_SPLIT_CENTRAL_SPLIT_RUN_STACK_SIZE` | int | Stack size of the BLE split central write thread | 512 |
|
||||
| `CONFIG_ZMK_BLE_SPLIT_CENTRAL_SPLIT_RUN_QUEUE_SIZE` | int | Max number of behavior run events to queue to send to the peripheral(s) | 5 |
|
||||
| `CONFIG_ZMK_SPLIT_BLE_CENTRAL_SPLIT_RUN_STACK_SIZE` | int | Stack size of the BLE split central write thread | 512 |
|
||||
| `CONFIG_ZMK_SPLIT_BLE_CENTRAL_SPLIT_RUN_QUEUE_SIZE` | int | Max number of behavior run events to queue to send to the peripheral(s) | 5 |
|
||||
| `CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_STACK_SIZE` | int | Stack size of the BLE split peripheral notify thread | 650 |
|
||||
| `CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_PRIORITY` | int | Priority of the BLE split peripheral notify thread | 5 |
|
||||
| `CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_POSITION_QUEUE_SIZE` | int | Max number of key state events to queue to send to the central | 10 |
|
||||
|
|
|
@ -38,6 +38,24 @@ Management of the bluetooth in ZMK is accomplished using the [`&bt` behavior](..
|
|||
|
||||
## Troubleshooting
|
||||
|
||||
### Connectivity Issues
|
||||
|
||||
Some users may experience a poor connection between the keyboard and the host. This might be due to poor quality BLE hardware, a metal enclosure on the keyboard or host, or the distance between them. Increasing the transmit power of the keyboard's BLE radio may reduce the severity of this problem. To do this, set the `CONFIG_BT_CTLR_TX_PWR_PLUS_8` configuration value in the `.conf` file of your user config directory as such:
|
||||
|
||||
```
|
||||
CONFIG_BT_CTLR_TX_PWR_PLUS_8=y
|
||||
```
|
||||
|
||||
For the `nRF52840`, the value `PLUS_8` can be set to any multiple of four between `MINUS_20` and `PLUS_8`. The default value for this config is `0`, but if you are having connection issues it is recommended to set it to `PLUS_8` because the power consumption difference is negligible. For more information on changing the transmit power of your BLE device, please refer to [the Zephyr docs.](https://docs.zephyrproject.org/latest/kconfig.html#CONFIG_BT_CTLR_TX_PWR)
|
||||
|
||||
:::info
|
||||
This setting can also improve the connection strength between the keyboard halves for split keyboards.
|
||||
:::
|
||||
|
||||
### Using bluetooth output with USB power
|
||||
|
||||
If you want to test bluetooth output on your keyboard and are powering it through the USB connection rather than a battery, you will be able to pair with a host device but may not see keystrokes sent. In this case you need to use the [output selection behavior](../behaviors/outputs.md) to prefer sending keystrokes over bluetooth rather than USB. This might be necessary even if you are not powering from a device capable of receiving USB inputs, such as a USB charger.
|
||||
|
||||
## Known Issues
|
||||
|
||||
There are a few known issues related to BLE and ZMK:
|
||||
|
@ -57,3 +75,18 @@ If you attempt to pair a ZMK keyboard from macOS in a way that causes a bonding
|
|||
1. Remove the keyboard from macOS using the Bluetooth control panel.
|
||||
1. Invoke `&bt BT_CLR` on the keyboard while the profile associated with the macOS device is active, by pressing the correct keys for your particular keymap.
|
||||
1. Try connecting again from macOS.
|
||||
|
||||
### Windows Connected But Not Working
|
||||
|
||||
Occasionally pairing the keyboard to a Windows device might result in a state where the keyboard is connected but does not send any key strokes.
|
||||
If this occurs:
|
||||
|
||||
1. Remove the keyboard from Windows using the Bluetooth settings.
|
||||
1. Invoke `&bt BT_CLR` on the keyboard while the profile associated with the Windows device is active, by pressing the correct keys for your particular keymap.
|
||||
1. Turn off Bluetooth from Windows settings, then turn it back on.
|
||||
1. Pair the keyboard to the Windows device.
|
||||
|
||||
If this doesn't help, try following the procedure above but replace step 3 with one of the following:
|
||||
|
||||
- Restart the Windows device
|
||||
- Open "Device Manager," turn on "Show hidden devices" from the "View" menu, then find and delete the keyboard under the "Bluetooth" item
|
||||
|
|
|
@ -99,8 +99,6 @@ one millisecond of latency but protects against short noise spikes.
|
|||
|
||||
ZMK's default debouncing is similar to QMK's `sym_defer_pk` algorithm.
|
||||
|
||||
Setting `CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS=0` for eager debouncing would be similar
|
||||
to QMK's (unimplemented as of this writing) `asym_eager_defer_pk`.
|
||||
Setting `CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS=0` for eager debouncing would be similar to QMK's `asym_eager_defer_pk`.
|
||||
|
||||
See [QMK's Debounce API documentation](https://beta.docs.qmk.fm/using-qmk/software-features/feature_debounce_type)
|
||||
for more information.
|
||||
See [QMK's Debounce API documentation](https://docs.qmk.fm/#/feature_debounce_type) for more information.
|
||||
|
|
|
@ -5,6 +5,8 @@ sidebar_title: Troubleshooting
|
|||
|
||||
The following page provides suggestions for common errors that may occur during firmware compilation or other issues with keyboard usage. If the information provided is insufficient to resolve the issue, feel free to seek out help from the [ZMK Discord](https://zmk.dev/community/discord/invite).
|
||||
|
||||
Please also see [the troubleshooting section](features/bluetooth.md#troubleshooting) under the Bluetooth feature page for issues related to bluetooth.
|
||||
|
||||
### File Transfer Error
|
||||
|
||||
Variations of the warnings shown below occur when flashing the `<firmware>.uf2` onto the microcontroller. This is because the microcontroller resets itself before the OS receives confirmation that the file transfer is complete. Errors like this are normal and can generally be ignored. Verification of a functional board can be done by attempting to pair your newly flashed keyboard to your computer via Bluetooth or plugging in a USB cable if `ZMK_USB` is enabled in your Kconfig.defconfig.
|
||||
|
@ -100,17 +102,3 @@ Perform the following steps to reset both halves of your split keyboard:
|
|||
1. Flash the actual image for each half of the split keyboard (e.g `my_board_left.uf2` to the left half, `my_board_right.uf2` to the right half).
|
||||
|
||||
After completing these steps, pair the halves of the split keyboard together by resetting them at the same time. Most commonly, this is done by grounding the reset pins for each of your keyboard's microcontrollers or pressing the reset buttons at the same time.
|
||||
|
||||
### Connectivity Issues
|
||||
|
||||
Some users may experience a poor connection between the keyboard and the host. This might be due to poor quality BLE hardware, a metal enclosure on the keyboard or host, or the distance between them. Increasing the transmit power of the keyboard's BLE radio may reduce the severity of this problem. To do this, set the `CONFIG_BT_CTLR_TX_PWR_PLUS_8` configuration value in the `.conf` file of your user config directory as such:
|
||||
|
||||
```
|
||||
CONFIG_BT_CTLR_TX_PWR_PLUS_8=y
|
||||
```
|
||||
|
||||
For the `nRF52840`, the value `PLUS_8` can be set to any multiple of four between `MINUS_20` and `PLUS_8`. The default value for this config is `0`, but if you are having connection issues it is recommended to set it to `PLUS_8` because the power consumption difference is negligible. For more information on changing the transmit power of your BLE device, please refer to [the Zephyr docs.](https://docs.zephyrproject.org/latest/kconfig.html#CONFIG_BT_CTLR_TX_PWR)
|
||||
|
||||
### Other notes and warnings
|
||||
|
||||
- If you want to test bluetooth output on your keyboard and are powering it through the USB connection rather than a battery, you will be able to pair with a host device but may not see keystrokes sent. In this case you need to use the [output selection behavior](../docs/behaviors/outputs.md) to prefer sending keystrokes over bluetooth rather than USB. This might be necessary even if you are not powering from a device capable of receiving USB inputs, such as a USB charger.
|
||||
|
|
2785
docs/package-lock.json
generated
2785
docs/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -15,11 +15,11 @@
|
|||
"typecheck": "tsc"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "^2.1.0",
|
||||
"@docusaurus/preset-classic": "^2.1.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.32",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.3",
|
||||
"@fortawesome/react-fontawesome": "^0.1.18",
|
||||
"@docusaurus/core": "^2.4.0",
|
||||
"@docusaurus/preset-classic": "^2.4.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.4.0",
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"classnames": "^2.2.6",
|
||||
"js-yaml": "^4.1.0",
|
||||
|
@ -28,7 +28,7 @@
|
|||
"react-copy-to-clipboard": "^5.0.3",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-toastify": "^7.0.4",
|
||||
"web-tree-sitter": "^0.19.4"
|
||||
"web-tree-sitter": "^0.20.8"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
@ -43,24 +43,24 @@
|
|||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "^2.1.0",
|
||||
"@docusaurus/types": "^2.1.0",
|
||||
"@tsconfig/docusaurus": "^1.0.5",
|
||||
"@docusaurus/module-type-aliases": "^2.4.0",
|
||||
"@docusaurus/types": "^2.4.0",
|
||||
"@tsconfig/docusaurus": "^1.0.7",
|
||||
"@types/js-yaml": "^4.0.5",
|
||||
"@types/react": "^17.0.3",
|
||||
"@types/react-helmet": "^6.1.5",
|
||||
"@types/react": "^17.0.58",
|
||||
"@types/react-helmet": "^6.1.6",
|
||||
"@types/react-router-dom": "^5.1.7",
|
||||
"eslint": "^8.0.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint": "^8.39.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-mdx": "^2.0.5",
|
||||
"eslint-plugin-react": "^7.30.0",
|
||||
"json-schema-to-typescript": "^10.1.5",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"json-schema-to-typescript": "^12.0.0",
|
||||
"mustache": "^4.2.0",
|
||||
"null-loader": "^4.0.0",
|
||||
"prebuild-webpack-plugin": "^1.1.1",
|
||||
"prettier": "^2.8.7",
|
||||
"string-replace-loader": "^3.1.0",
|
||||
"typescript": "^4.6.3",
|
||||
"webpack": "^5.72.1"
|
||||
"typescript": "^5.0.4",
|
||||
"webpack": "^5.80.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,36 +16,6 @@ module.exports = function () {
|
|||
test: /web-tree-sitter/,
|
||||
loader: "null-loader",
|
||||
});
|
||||
} else {
|
||||
// The way web-tree-sitter loads tree-sitter.wasm isn't something that
|
||||
// Docusaurus/Webpack identify as an asset. There is currently no way to
|
||||
// set location of the file other than patching web-tree-sitter.
|
||||
// (see https://github.com/tree-sitter/tree-sitter/issues/559)
|
||||
rules.push({
|
||||
test: /tree-sitter\.js$/,
|
||||
loader: "string-replace-loader",
|
||||
options: {
|
||||
multiple: [
|
||||
// Replace the path to tree-sitter.wasm with a "new URL()" to clue
|
||||
// Webpack in that it is an asset.
|
||||
{
|
||||
search: '"tree-sitter.wasm"',
|
||||
replace: '(new URL("tree-sitter.wasm", import.meta.url)).href',
|
||||
strict: true,
|
||||
},
|
||||
// Webpack replaces "new URL()" with the full URL to the asset, but
|
||||
// web-tree-sitter will still add a prefix to it unless there is a
|
||||
// Module.locateFile() function.
|
||||
{
|
||||
search: "var Module=void 0!==Module?Module:{};",
|
||||
replace: `var Module = {
|
||||
locateFile: (path, prefix) => path.startsWith('http') ? path : prefix + path,
|
||||
};`,
|
||||
strict: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
@ -2,10 +2,23 @@ import Parser from "web-tree-sitter";
|
|||
|
||||
import { Codes, Behaviors } from "./data/keymap-upgrade";
|
||||
|
||||
const TREE_SITTER_WASM_URL = new URL(
|
||||
"/node_modules/web-tree-sitter/tree-sitter.wasm",
|
||||
import.meta.url
|
||||
);
|
||||
|
||||
let Devicetree;
|
||||
|
||||
export async function initParser() {
|
||||
await Parser.init();
|
||||
await Parser.init({
|
||||
locateFile: (path, prefix) => {
|
||||
// When locating tree-sitter.wasm, use a path that Webpack can map to the correct URL.
|
||||
if (path == "tree-sitter.wasm") {
|
||||
return TREE_SITTER_WASM_URL.href;
|
||||
}
|
||||
return prefix + path;
|
||||
},
|
||||
});
|
||||
Devicetree = await Parser.Language.load("/tree-sitter-devicetree.wasm");
|
||||
}
|
||||
|
||||
|
|
BIN
docs/static/tree-sitter-devicetree.wasm
vendored
BIN
docs/static/tree-sitter-devicetree.wasm
vendored
Binary file not shown.
|
@ -3,7 +3,7 @@
|
|||
"include": ["src/"],
|
||||
"compilerOptions": {
|
||||
"types": ["node", "@docusaurus/theme-classic"],
|
||||
"moduleResolution": "Node",
|
||||
"moduleResolution": "Node16",
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true,
|
||||
"strict": true,
|
||||
|
|
Loading…
Add table
Reference in a new issue