Merge branch 'upstream_main' into mercury
This commit is contained in:
commit
3bacad469e
34 changed files with 1335 additions and 1600 deletions
|
@ -1,4 +1,4 @@
|
||||||
FROM zmkfirmware/zmk-dev-arm:2.5
|
FROM docker.io/zmkfirmware/zmk-dev-arm:2.5
|
||||||
|
|
||||||
COPY .bashrc tmp
|
COPY .bashrc tmp
|
||||||
RUN mv /tmp/.bashrc ~/.bashrc
|
RUN mv /tmp/.bashrc ~/.bashrc
|
||||||
|
|
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
|
@ -3,7 +3,7 @@
|
||||||
- [ ] This board/shield is tested working on real hardware
|
- [ ] This board/shield is tested working on real hardware
|
||||||
- [ ] Definitions follow the general style of other shields/boards upstream ([Reference](https://zmk.dev/docs/development/new-shield))
|
- [ ] Definitions follow the general style of other shields/boards upstream ([Reference](https://zmk.dev/docs/development/new-shield))
|
||||||
- [ ] `.zmk.yml` metadata file added
|
- [ ] `.zmk.yml` metadata file added
|
||||||
- [ ] Proper Copyright + License headers added to applicable files
|
- [ ] Proper Copyright + License headers added to applicable files (Generally, we stick to "The ZMK Contributors" for copyrights to help avoid churn when files get edited)
|
||||||
- [ ] General consistent formatting of DeviceTree files
|
- [ ] General consistent formatting of DeviceTree files
|
||||||
- [ ] Keymaps do not use deprecated key defines (Check using the [upgrader tool](https://zmk.dev/docs/codes/keymap-upgrader))
|
- [ ] Keymaps do not use deprecated key defines (Check using the [upgrader tool](https://zmk.dev/docs/codes/keymap-upgrader))
|
||||||
- [ ] `&pro_micro` used in favor of `&pro_micro_d/a` if applicable
|
- [ ] `&pro_micro` used in favor of `&pro_micro_d/a` if applicable
|
||||||
|
|
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
@ -14,7 +14,7 @@ jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: zmkfirmware/zmk-build-arm:2.5
|
image: docker.io/zmkfirmware/zmk-build-arm:2.5
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
board:
|
board:
|
||||||
|
|
|
@ -29,7 +29,7 @@ jobs:
|
||||||
validate-metadata:
|
validate-metadata:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: zmkfirmware/zmk-dev-arm:2.5
|
image: docker.io/zmkfirmware/zmk-dev-arm:2.5
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
|
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
|
@ -16,7 +16,7 @@ jobs:
|
||||||
integration_test:
|
integration_test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: zmkfirmware/zmk-build-arm:2.5
|
image: docker.io/zmkfirmware/zmk-build-arm:2.5
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
32
app/Kconfig
32
app/Kconfig
|
@ -262,36 +262,54 @@ config ZMK_RGB_UNDERGLOW_EXT_POWER
|
||||||
bool "RGB underglow toggling also controls external power"
|
bool "RGB underglow toggling also controls external power"
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
config ZMK_RGB_UNDERGLOW_BRT_MIN
|
||||||
|
int "RGB underglow minimum brightness in percent"
|
||||||
|
range 0 100
|
||||||
|
default 0
|
||||||
|
|
||||||
|
config ZMK_RGB_UNDERGLOW_BRT_MAX
|
||||||
|
int "RGB underglow maximum brightness in percent"
|
||||||
|
range ZMK_RGB_UNDERGLOW_BRT_MIN 100
|
||||||
|
default 100
|
||||||
|
|
||||||
config ZMK_RGB_UNDERGLOW_HUE_STEP
|
config ZMK_RGB_UNDERGLOW_HUE_STEP
|
||||||
int "RGB underglow hue step in degrees of 360"
|
int "RGB underglow hue step in degrees"
|
||||||
|
range 0 359
|
||||||
default 10
|
default 10
|
||||||
|
|
||||||
config ZMK_RGB_UNDERGLOW_SAT_STEP
|
config ZMK_RGB_UNDERGLOW_SAT_STEP
|
||||||
int "RGB underglow sturation step in percent"
|
int "RGB underglow saturation step in percent"
|
||||||
|
range 0 100
|
||||||
default 10
|
default 10
|
||||||
|
|
||||||
config ZMK_RGB_UNDERGLOW_BRT_STEP
|
config ZMK_RGB_UNDERGLOW_BRT_STEP
|
||||||
int "RGB underglow brightness step in percent"
|
int "RGB underglow brightness step in percent"
|
||||||
|
range 0 100
|
||||||
default 10
|
default 10
|
||||||
|
|
||||||
config ZMK_RGB_UNDERGLOW_HUE_START
|
config ZMK_RGB_UNDERGLOW_HUE_START
|
||||||
int "RGB underglow start hue value from 0-359"
|
int "RGB underglow start hue value in degrees"
|
||||||
|
range 0 359
|
||||||
default 0
|
default 0
|
||||||
|
|
||||||
config ZMK_RGB_UNDERGLOW_SAT_START
|
config ZMK_RGB_UNDERGLOW_SAT_START
|
||||||
int "RGB underglow start saturations value from 0-100"
|
int "RGB underglow start saturations value in percent"
|
||||||
|
range 0 100
|
||||||
default 100
|
default 100
|
||||||
|
|
||||||
config ZMK_RGB_UNDERGLOW_BRT_START
|
config ZMK_RGB_UNDERGLOW_BRT_START
|
||||||
int "RGB underglow start brightness value from 0-100"
|
int "RGB underglow start brightness value in percent"
|
||||||
default 100
|
range ZMK_RGB_UNDERGLOW_BRT_MIN ZMK_RGB_UNDERGLOW_BRT_MAX
|
||||||
|
default ZMK_RGB_UNDERGLOW_BRT_MAX
|
||||||
|
|
||||||
config ZMK_RGB_UNDERGLOW_SPD_START
|
config ZMK_RGB_UNDERGLOW_SPD_START
|
||||||
int "RGB underglow start animation speed value from 1-5"
|
int "RGB underglow start animation speed value"
|
||||||
|
range 1 5
|
||||||
default 3
|
default 3
|
||||||
|
|
||||||
config ZMK_RGB_UNDERGLOW_EFF_START
|
config ZMK_RGB_UNDERGLOW_EFF_START
|
||||||
int "RGB underglow start effect int value related to the effect enum list"
|
int "RGB underglow start effect int value related to the effect enum list"
|
||||||
|
range 0 3
|
||||||
default 0
|
default 0
|
||||||
|
|
||||||
config ZMK_RGB_UNDERGLOW_ON_START
|
config ZMK_RGB_UNDERGLOW_ON_START
|
||||||
|
|
19
app/boards/shields/ergodash/Kconfig.defconfig
Normal file
19
app/boards/shields/ergodash/Kconfig.defconfig
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# Copyright (c) 2020 The ZMK Contributors
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
if SHIELD_ERGODASH_LEFT
|
||||||
|
|
||||||
|
config ZMK_KEYBOARD_NAME
|
||||||
|
default "Ergodash"
|
||||||
|
|
||||||
|
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||||
|
default y
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
if SHIELD_ERGODASH_LEFT || SHIELD_ERGODASH_RIGHT
|
||||||
|
|
||||||
|
config ZMK_SPLIT
|
||||||
|
default y
|
||||||
|
|
||||||
|
endif
|
8
app/boards/shields/ergodash/Kconfig.shield
Normal file
8
app/boards/shields/ergodash/Kconfig.shield
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# Copyright (c) 2020 The ZMK Contributors
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
config SHIELD_ERGODASH_LEFT
|
||||||
|
def_bool $(shields_list_contains,ergodash_left)
|
||||||
|
|
||||||
|
config SHIELD_ERGODASH_RIGHT
|
||||||
|
def_bool $(shields_list_contains,ergodash_right)
|
0
app/boards/shields/ergodash/ergodash.conf
Normal file
0
app/boards/shields/ergodash/ergodash.conf
Normal file
61
app/boards/shields/ergodash/ergodash.dtsi
Normal file
61
app/boards/shields/ergodash/ergodash.dtsi
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <dt-bindings/zmk/matrix_transform.h>
|
||||||
|
|
||||||
|
/ {
|
||||||
|
chosen {
|
||||||
|
zmk,kscan = &kscan0;
|
||||||
|
zmk,matrix_transform = &default_transform;
|
||||||
|
};
|
||||||
|
|
||||||
|
default_transform: keymap_transform_0 {
|
||||||
|
compatible = "zmk,matrix-transform";
|
||||||
|
columns = <14>;
|
||||||
|
rows = <5>;
|
||||||
|
// Numbering based on rev 1.2 schema
|
||||||
|
// * keys that can be in different positions are denoted as MW
|
||||||
|
// * MW40 can be broken off
|
||||||
|
// | SW1 | SW5 | SW9 | SW13 | SW17 | SW21 | SW25 | | | | SW25 | SW21 | SW17 | SW13 | SW9 | SW5 | SW1 |
|
||||||
|
// | SW2 | SW6 | SW10 | SW14 | SW18 | SW22 | SW26 | | | | SW26 | SW22 | SW18 | SW14 | SW10 | SW6 | SW2 |
|
||||||
|
// | SW3 | SW7 | SW11 | SW15 | SW19 | SW23 | SW27 | | | | SW27 | SW23 | SW19 | SW15 | SW11 | SW7 | SW3 |
|
||||||
|
// | SW4 | SW8 | SW12 | SW16 | SW20 | SW24 | | MW28 | | MW28 | | SW24 | SW20 | SW16 | SW12 | SW8 | SW4 |
|
||||||
|
// | SW30 | SW31 | SW32 | MW33 | SW34 | | MW35 | MW40 | | MW40 | MW35 | | SW34 | MW33 | SW32 | SW31 | SW30 |
|
||||||
|
map = <
|
||||||
|
RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,13) RC(0,12) RC(0,11) RC(0,10) RC(0,9) RC(0,8) RC(0,7)
|
||||||
|
RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,13) RC(1,12) RC(1,11) RC(1,10) RC(1,9) RC(1,8) RC(1,7)
|
||||||
|
RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,13) RC(2,12) RC(2,11) RC(2,10) RC(2,9) RC(2,8) RC(2,7)
|
||||||
|
RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,13) RC(3,12) RC(3,11) RC(3,10) RC(3,9) RC(3,8) RC(3,7)
|
||||||
|
RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,13) RC(4,12) RC(4,11) RC(4,10) RC(4,9) RC(4,8) RC(4,7)
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
|
||||||
|
kscan0: kscan {
|
||||||
|
compatible = "zmk,kscan-gpio-matrix";
|
||||||
|
label = "KSCAN";
|
||||||
|
|
||||||
|
diode-direction = "col2row";
|
||||||
|
|
||||||
|
row-gpios
|
||||||
|
= <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
|
||||||
|
, <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
|
||||||
|
, <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
|
||||||
|
, <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
|
||||||
|
, <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
|
||||||
|
;
|
||||||
|
|
||||||
|
col-gpios
|
||||||
|
= <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
|
||||||
|
, <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
|
||||||
|
, <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
|
||||||
|
, <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
|
||||||
|
, <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
|
||||||
|
, <&pro_micro 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
|
||||||
|
, <&pro_micro 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
|
||||||
|
;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
86
app/boards/shields/ergodash/ergodash.keymap
Normal file
86
app/boards/shields/ergodash/ergodash.keymap
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <behaviors.dtsi>
|
||||||
|
#include <dt-bindings/zmk/keys.h>
|
||||||
|
#include <dt-bindings/zmk/bt.h>
|
||||||
|
|
||||||
|
#define DEFAULT 0
|
||||||
|
#define LOWER 1
|
||||||
|
#define RAISE 2
|
||||||
|
|
||||||
|
|
||||||
|
/ {
|
||||||
|
keymap {
|
||||||
|
compatible = "zmk,keymap";
|
||||||
|
|
||||||
|
default_layer {
|
||||||
|
/* QWERTY
|
||||||
|
* .----------------------------------------------------------------------------------------------------------------------.
|
||||||
|
* | ` | 1 | 2 | 3 | 4 | 5 | [ | | ] | 6 | 7 | 8 | 9 | 0 | PScr |
|
||||||
|
* |------+------+------+------+------+------+------+--------------------+------+------+------+------+------+------+------|
|
||||||
|
* | ESC | Q | W | E | R | T | - | | = | Y | U | I | O | P | \ |
|
||||||
|
* |------+------+------+------+------+------+------+--------------------+------+------+------+------+------+------+------|
|
||||||
|
* | Tab | A | S | D | F | G | Del | | Bksp | H | J | K | L | ; | ' |
|
||||||
|
* |------+------+------+------+------+------+---------------------------+------+------+------+------+------+------+------|
|
||||||
|
* | Shift| Z | X | C | V | B | End | | Home | N | M | , | . | / | Shift|
|
||||||
|
* |-------------+------+------+------+------+------+------+------+------+------+------+------+------+------+-------------|
|
||||||
|
* | Ctrl | | PGDN | Win |||||||| Alt | Space| Lower|||||||| Raise| Enter| RAlt |||||||| | PGUP | Ins | RCtrl|
|
||||||
|
* .----------------------------------------------------------------------------------------------------------------------.
|
||||||
|
*/
|
||||||
|
bindings = <
|
||||||
|
&kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp LBKT &kp RBKT &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp PSCRN
|
||||||
|
&kp ESC &kp Q &kp W &kp E &kp R &kp T &kp MINUS &kp EQUAL &kp Y &kp U &kp I &kp O &kp P &kp BSLH
|
||||||
|
&kp TAB &kp A &kp S &kp D &kp F &kp G &kp DEL &kp BSPC &kp H &kp J &kp K &kp L &kp SEMI &kp SQT
|
||||||
|
&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp END &kp HOME &kp N &kp M &kp COMMA &kp DOT &kp SLASH &kp RSHFT
|
||||||
|
&kp LCTRL &none &kp PG_DN &kp LMETA &kp LALT &kp SPACE &mo LOWER &mo RAISE &kp RET &kp RALT &none &kp PG_UP &kp INS &kp RCTRL
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
lower_layer {
|
||||||
|
/* .----------------------------------------------------------------------------------------------------------------------.
|
||||||
|
* | F11 | F1 | F2 | F3 | F4 | F5 | | | | F6 | F7 | F8 | F9 | F10 | F12 |
|
||||||
|
* |------+------+------+------+------+------+------+--------------------+------+------+------+------+------+------+------|
|
||||||
|
* | | | | | | | | | | | | | | | |
|
||||||
|
* |------+------+------+------+------+------+------+--------------------+------+------+------+------+------+------+------|
|
||||||
|
* | | | | | | | | | | | | | | | |
|
||||||
|
* |------+------+------+------+------+------+---------------------------+------+------+------+------+------+------+------|
|
||||||
|
* | Shift| Boot | Reset| | | | | | | | | | | | Shift|
|
||||||
|
* |-------------+------+------+------+------+------+------+------+------+------+------+------+------+------+-------------|
|
||||||
|
* | Ctlr | | | Win |||||||| Alt | | Lower|||||||| Raise| | RAlt |||||||| | | | RCtrl|
|
||||||
|
* .----------------------------------------------------------------------------------------------------------------------.
|
||||||
|
*/ /* FIXME boot and reset are not yet locale aware */
|
||||||
|
bindings = <
|
||||||
|
&kp F11 &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp &none &kp &none &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F12
|
||||||
|
&none &none &none &none &none &none &none &none &none &none &none &none &none &none
|
||||||
|
&none &none &none &none &none &none &none &none &none &none &none &none &none &none
|
||||||
|
&trans &bootloader &reset &none &none &none &none &none &none &none &none &none &none &trans
|
||||||
|
&trans &none &none &trans &trans &none &trans &trans &none &trans &none &none &none &trans
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
raise_layer {
|
||||||
|
/* .----------------------------------------------------------------------------------------------------------------------.
|
||||||
|
* | | BT 0 | BT 1 | BT 2 | BT 3 | | BTCL | | | | | | | | |
|
||||||
|
* |------+------+------+------+------+------+------+--------------------+------+------+------+------+------+------+------|
|
||||||
|
* | | | | | | | | | | | | | | | |
|
||||||
|
* |------+------+------+------+------+------+------+--------------------+------+------+------+------+------+------+------|
|
||||||
|
* | | | | | | | | | | | | | | | |
|
||||||
|
* |------+------+------+------+------+------+---------------------------+------+------+------+------+------+------+------|
|
||||||
|
* | Shift| | | | | | | | | | | | Boot | Reset| Shift|
|
||||||
|
* |-------------+------+------+------+------+------+------+------+------+------+------+------+------+------+-------------|
|
||||||
|
* | Ctlr | | | Win |||||||| Alt | | Lower|||||||| Raise| | RAlt |||||||| | | | RCtrl|
|
||||||
|
* .----------------------------------------------------------------------------------------------------------------------.
|
||||||
|
*/ /* FIXME boot and reset are not yet locale aware */
|
||||||
|
bindings = <
|
||||||
|
&none &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &none &bt BT_CLR &none &none &none &none &none &none &none
|
||||||
|
&none &none &none &none &none &none &none &none &none &none &none &none &none &none
|
||||||
|
&none &none &none &none &none &none &none &none &none &none &none &none &none &none
|
||||||
|
&trans &none &none &none &none &none &none &none &none &none &none &bootloader &reset &trans
|
||||||
|
&trans &none &none &trans &trans &none &trans &trans &none &trans &none &none &none &trans
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
11
app/boards/shields/ergodash/ergodash.zmk.yml
Normal file
11
app/boards/shields/ergodash/ergodash.zmk.yml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
file_format: "1"
|
||||||
|
id: ergodash
|
||||||
|
name: Ergodash
|
||||||
|
type: shield
|
||||||
|
url: https://github.com/omkbd/ErgoDash
|
||||||
|
requires: [pro_micro]
|
||||||
|
features:
|
||||||
|
- keys
|
||||||
|
siblings:
|
||||||
|
- ergodash_left
|
||||||
|
- ergodash_right
|
8
app/boards/shields/ergodash/ergodash_left.overlay
Normal file
8
app/boards/shields/ergodash/ergodash_left.overlay
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ergodash.dtsi"
|
||||||
|
|
11
app/boards/shields/ergodash/ergodash_right.overlay
Normal file
11
app/boards/shields/ergodash/ergodash_right.overlay
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ergodash.dtsi"
|
||||||
|
|
||||||
|
&default_transform {
|
||||||
|
col-offset = <7>;
|
||||||
|
};
|
|
@ -61,14 +61,17 @@ foreach(root ${BOARD_ROOT})
|
||||||
if (EXISTS "${root}/boards/${BOARD}.overlay")
|
if (EXISTS "${root}/boards/${BOARD}.overlay")
|
||||||
list(APPEND ZMK_DTC_FILES "${root}/boards/${BOARD}.overlay")
|
list(APPEND ZMK_DTC_FILES "${root}/boards/${BOARD}.overlay")
|
||||||
endif()
|
endif()
|
||||||
|
if (NOT DEFINED BOARD_DIR_NAME)
|
||||||
find_path(BOARD_DIR
|
find_path(BOARD_DIR
|
||||||
NAMES ${BOARD}_defconfig
|
NAMES ${BOARD}_defconfig
|
||||||
PATHS ${root}/boards/*/*
|
PATHS ${root}/boards/*/*
|
||||||
NO_DEFAULT_PATH
|
NO_DEFAULT_PATH
|
||||||
)
|
)
|
||||||
if(BOARD_DIR)
|
if(BOARD_DIR)
|
||||||
|
get_filename_component(BOARD_DIR_NAME ${BOARD_DIR} NAME)
|
||||||
list(APPEND KEYMAP_DIRS ${BOARD_DIR})
|
list(APPEND KEYMAP_DIRS ${BOARD_DIR})
|
||||||
endif()
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
if(DEFINED SHIELD)
|
if(DEFINED SHIELD)
|
||||||
find_path(shields_refs_list
|
find_path(shields_refs_list
|
||||||
|
@ -130,7 +133,7 @@ endif()
|
||||||
|
|
||||||
if(NOT KEYMAP_FILE)
|
if(NOT KEYMAP_FILE)
|
||||||
foreach(keymap_dir ${KEYMAP_DIRS})
|
foreach(keymap_dir ${KEYMAP_DIRS})
|
||||||
foreach(keymap_prefix ${SHIELD} ${SHIELD_DIR} ${BOARD} ${BOARD_DIR})
|
foreach(keymap_prefix ${SHIELD} ${SHIELD_DIR} ${BOARD} ${BOARD_DIR_NAME})
|
||||||
if (EXISTS ${keymap_dir}/${keymap_prefix}.keymap)
|
if (EXISTS ${keymap_dir}/${keymap_prefix}.keymap)
|
||||||
set(KEYMAP_FILE "${keymap_dir}/${keymap_prefix}.keymap" CACHE STRING "Selected keymap file")
|
set(KEYMAP_FILE "${keymap_dir}/${keymap_prefix}.keymap" CACHE STRING "Selected keymap file")
|
||||||
message(STATUS "Using keymap file: ${KEYMAP_FILE}")
|
message(STATUS "Using keymap file: ${KEYMAP_FILE}")
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
zephyr_library_named(zmk__drivers__kscan)
|
zephyr_library_named(zmk__drivers__kscan)
|
||||||
zephyr_library_include_directories(${CMAKE_SOURCE_DIR}/include)
|
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_matrix.c)
|
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DRIVER kscan_gpio_matrix.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DRIVER kscan_gpio_direct.c)
|
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DRIVER kscan_gpio_direct.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DRIVER kscan_gpio_demux.c)
|
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DRIVER kscan_gpio_demux.c)
|
||||||
|
|
|
@ -14,6 +14,24 @@ config ZMK_KSCAN_MATRIX_POLLING
|
||||||
config ZMK_KSCAN_DIRECT_POLLING
|
config ZMK_KSCAN_DIRECT_POLLING
|
||||||
bool "Poll for key event triggers instead of using interrupts on direct wired boards."
|
bool "Poll for key event triggers instead of using interrupts on direct wired boards."
|
||||||
|
|
||||||
|
config ZMK_KSCAN_DEBOUNCE_PRESS_MS
|
||||||
|
int "Debounce time for key press in milliseconds."
|
||||||
|
default -1
|
||||||
|
help
|
||||||
|
Global debounce time for key press in milliseconds.
|
||||||
|
If this is -1, the debounce time is controlled by the debounce-press-ms
|
||||||
|
Devicetree property, which defaults to 5 ms. Otherwise this overrides the
|
||||||
|
debounce time for all key scan drivers to the chosen value.
|
||||||
|
|
||||||
|
config ZMK_KSCAN_DEBOUNCE_RELEASE_MS
|
||||||
|
int "Debounce time for key release in milliseconds."
|
||||||
|
default -1
|
||||||
|
help
|
||||||
|
Global debounce time for key release in milliseconds.
|
||||||
|
If this is -1, the debounce time is controlled by the debounce-release-ms
|
||||||
|
Devicetree property, which defaults to 5 ms. Otherwise this overrides the
|
||||||
|
debounce time for all key scan drivers to the chosen value.
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
config ZMK_KSCAN_INIT_PRIORITY
|
config ZMK_KSCAN_INIT_PRIORITY
|
||||||
|
|
62
app/drivers/kscan/debounce.c
Normal file
62
app/drivers/kscan/debounce.c
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "debounce.h"
|
||||||
|
|
||||||
|
static uint32_t get_threshold(const struct debounce_state *state,
|
||||||
|
const struct debounce_config *config) {
|
||||||
|
return state->pressed ? config->debounce_release_ms : config->debounce_press_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void increment_counter(struct debounce_state *state, const int elapsed_ms) {
|
||||||
|
if (state->counter + elapsed_ms > DEBOUNCE_COUNTER_MAX) {
|
||||||
|
state->counter = DEBOUNCE_COUNTER_MAX;
|
||||||
|
} else {
|
||||||
|
state->counter += elapsed_ms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void decrement_counter(struct debounce_state *state, const int elapsed_ms) {
|
||||||
|
if (state->counter < elapsed_ms) {
|
||||||
|
state->counter = 0;
|
||||||
|
} else {
|
||||||
|
state->counter -= elapsed_ms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void debounce_update(struct debounce_state *state, const bool active, const int elapsed_ms,
|
||||||
|
const struct debounce_config *config) {
|
||||||
|
// This uses a variation of the integrator debouncing described at
|
||||||
|
// https://www.kennethkuhn.com/electronics/debounce.c
|
||||||
|
// Every update where "active" does not match the current state, we increment
|
||||||
|
// a counter, otherwise we decrement it. When the counter reaches a
|
||||||
|
// threshold, the state flips and we reset the counter.
|
||||||
|
state->changed = false;
|
||||||
|
|
||||||
|
if (active == state->pressed) {
|
||||||
|
decrement_counter(state, elapsed_ms);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t flip_threshold = get_threshold(state, config);
|
||||||
|
|
||||||
|
if (state->counter < flip_threshold) {
|
||||||
|
increment_counter(state, elapsed_ms);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->pressed = !state->pressed;
|
||||||
|
state->counter = 0;
|
||||||
|
state->changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool debounce_is_active(const struct debounce_state *state) {
|
||||||
|
return state->pressed || state->counter > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool debounce_is_pressed(const struct debounce_state *state) { return state->pressed; }
|
||||||
|
|
||||||
|
bool debounce_get_changed(const struct debounce_state *state) { return state->changed; }
|
56
app/drivers/kscan/debounce.h
Normal file
56
app/drivers/kscan/debounce.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/util.h>
|
||||||
|
|
||||||
|
#define DEBOUNCE_COUNTER_BITS 14
|
||||||
|
#define DEBOUNCE_COUNTER_MAX BIT_MASK(DEBOUNCE_COUNTER_BITS)
|
||||||
|
|
||||||
|
struct debounce_state {
|
||||||
|
bool pressed : 1;
|
||||||
|
bool changed : 1;
|
||||||
|
uint16_t counter : DEBOUNCE_COUNTER_BITS;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct debounce_config {
|
||||||
|
/** Duration a switch must be pressed to latch as pressed. */
|
||||||
|
uint32_t debounce_press_ms;
|
||||||
|
/** Duration a switch must be released to latch as released. */
|
||||||
|
uint32_t debounce_release_ms;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debounces one switch.
|
||||||
|
*
|
||||||
|
* @param state The state for the switch to debounce.
|
||||||
|
* @param active Is the switch currently pressed?
|
||||||
|
* @param elapsed_ms Time elapsed since the previous update in milliseconds.
|
||||||
|
* @param config Debounce settings.
|
||||||
|
*/
|
||||||
|
void debounce_update(struct debounce_state *state, const bool active, const int elapsed_ms,
|
||||||
|
const struct debounce_config *config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns whether the switch is either latched as pressed or it is potentially
|
||||||
|
* pressed but the debouncer has not yet made a decision. If this returns true,
|
||||||
|
* the kscan driver should continue to poll quickly.
|
||||||
|
*/
|
||||||
|
bool debounce_is_active(const struct debounce_state *state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns whether the switch is latched as pressed.
|
||||||
|
*/
|
||||||
|
bool debounce_is_pressed(const struct debounce_state *state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns whether the pressed state of the switch changed in the last call to
|
||||||
|
* debounce_update.
|
||||||
|
*/
|
||||||
|
bool debounce_get_changed(const struct debounce_state *state);
|
|
@ -4,10 +4,13 @@
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "debounce.h"
|
||||||
|
|
||||||
#include <device.h>
|
#include <device.h>
|
||||||
#include <devicetree.h>
|
#include <devicetree.h>
|
||||||
#include <drivers/gpio.h>
|
#include <drivers/gpio.h>
|
||||||
#include <drivers/kscan.h>
|
#include <drivers/kscan.h>
|
||||||
|
#include <kernel.h>
|
||||||
#include <logging/log.h>
|
#include <logging/log.h>
|
||||||
#include <sys/__assert.h>
|
#include <sys/__assert.h>
|
||||||
#include <sys/util.h>
|
#include <sys/util.h>
|
||||||
|
@ -27,6 +30,20 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
#define INST_MATRIX_LEN(n) (INST_ROWS_LEN(n) * INST_COLS_LEN(n))
|
#define INST_MATRIX_LEN(n) (INST_ROWS_LEN(n) * INST_COLS_LEN(n))
|
||||||
#define INST_INPUTS_LEN(n) COND_DIODE_DIR(n, (INST_COLS_LEN(n)), (INST_ROWS_LEN(n)))
|
#define INST_INPUTS_LEN(n) COND_DIODE_DIR(n, (INST_COLS_LEN(n)), (INST_ROWS_LEN(n)))
|
||||||
|
|
||||||
|
#if CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS >= 0
|
||||||
|
#define INST_DEBOUNCE_PRESS_MS(n) CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS
|
||||||
|
#else
|
||||||
|
#define INST_DEBOUNCE_PRESS_MS(n) \
|
||||||
|
DT_INST_PROP_OR(n, debounce_period, DT_INST_PROP(n, debounce_press_ms))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_ZMK_KSCAN_DEBOUNCE_RELEASE_MS >= 0
|
||||||
|
#define INST_DEBOUNCE_RELEASE_MS(n) CONFIG_ZMK_KSCAN_DEBOUNCE_RELEASE_MS
|
||||||
|
#else
|
||||||
|
#define INST_DEBOUNCE_RELEASE_MS(n) \
|
||||||
|
DT_INST_PROP_OR(n, debounce_period, DT_INST_PROP(n, debounce_release_ms))
|
||||||
|
#endif
|
||||||
|
|
||||||
#define USE_POLLING IS_ENABLED(CONFIG_ZMK_KSCAN_MATRIX_POLLING)
|
#define USE_POLLING IS_ENABLED(CONFIG_ZMK_KSCAN_MATRIX_POLLING)
|
||||||
#define USE_INTERRUPTS (!USE_POLLING)
|
#define USE_INTERRUPTS (!USE_POLLING)
|
||||||
|
|
||||||
|
@ -66,26 +83,23 @@ enum kscan_diode_direction {
|
||||||
struct kscan_matrix_irq_callback {
|
struct kscan_matrix_irq_callback {
|
||||||
const struct device *dev;
|
const struct device *dev;
|
||||||
struct gpio_callback callback;
|
struct gpio_callback callback;
|
||||||
struct k_delayed_work *work;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct kscan_matrix_data {
|
struct kscan_matrix_data {
|
||||||
const struct device *dev;
|
const struct device *dev;
|
||||||
kscan_callback_t callback;
|
kscan_callback_t callback;
|
||||||
struct k_delayed_work work;
|
struct k_delayed_work work;
|
||||||
#if USE_POLLING
|
#if USE_INTERRUPTS
|
||||||
struct k_timer poll_timer;
|
|
||||||
#else
|
|
||||||
/** Array of length config->inputs.len */
|
/** Array of length config->inputs.len */
|
||||||
struct kscan_matrix_irq_callback *irqs;
|
struct kscan_matrix_irq_callback *irqs;
|
||||||
#endif
|
#endif
|
||||||
|
/** Timestamp of the current or scheduled scan. */
|
||||||
|
int64_t scan_time;
|
||||||
/**
|
/**
|
||||||
* Current state of the matrix as a flattened 2D array of length
|
* Current state of the matrix as a flattened 2D array of length
|
||||||
* (config->rows.len * config->cols.len)
|
* (config->rows.len * config->cols.len)
|
||||||
*/
|
*/
|
||||||
bool *current_state;
|
struct debounce_state *matrix_state;
|
||||||
/** Buffer for reading in the next matrix state. Parallel array to current_state. */
|
|
||||||
bool *next_state;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct kscan_gpio_list {
|
struct kscan_gpio_list {
|
||||||
|
@ -102,7 +116,8 @@ struct kscan_matrix_config {
|
||||||
struct kscan_gpio_list cols;
|
struct kscan_gpio_list cols;
|
||||||
struct kscan_gpio_list inputs;
|
struct kscan_gpio_list inputs;
|
||||||
struct kscan_gpio_list outputs;
|
struct kscan_gpio_list outputs;
|
||||||
int32_t debounce_period_ms;
|
struct debounce_config debounce_config;
|
||||||
|
int32_t debounce_scan_period_ms;
|
||||||
int32_t poll_period_ms;
|
int32_t poll_period_ms;
|
||||||
enum kscan_diode_direction diode_direction;
|
enum kscan_diode_direction diode_direction;
|
||||||
};
|
};
|
||||||
|
@ -190,19 +205,49 @@ static int kscan_matrix_interrupt_disable(const struct device *dev) {
|
||||||
#if USE_INTERRUPTS
|
#if USE_INTERRUPTS
|
||||||
static void kscan_matrix_irq_callback_handler(const struct device *port, struct gpio_callback *cb,
|
static void kscan_matrix_irq_callback_handler(const struct device *port, struct gpio_callback *cb,
|
||||||
const gpio_port_pins_t pin) {
|
const gpio_port_pins_t pin) {
|
||||||
struct kscan_matrix_irq_callback *data =
|
struct kscan_matrix_irq_callback *irq_data =
|
||||||
CONTAINER_OF(cb, struct kscan_matrix_irq_callback, callback);
|
CONTAINER_OF(cb, struct kscan_matrix_irq_callback, callback);
|
||||||
const struct kscan_matrix_config *config = data->dev->config;
|
struct kscan_matrix_data *data = irq_data->dev->data;
|
||||||
|
|
||||||
// Disable our interrupts temporarily to avoid re-entry while we scan.
|
// Disable our interrupts temporarily to avoid re-entry while we scan.
|
||||||
kscan_matrix_interrupt_disable(data->dev);
|
kscan_matrix_interrupt_disable(data->dev);
|
||||||
|
|
||||||
|
data->scan_time = k_uptime_get();
|
||||||
|
|
||||||
// TODO (Zephyr 2.6): use k_work_reschedule()
|
// TODO (Zephyr 2.6): use k_work_reschedule()
|
||||||
k_delayed_work_cancel(data->work);
|
k_delayed_work_cancel(&data->work);
|
||||||
k_delayed_work_submit(data->work, K_MSEC(config->debounce_period_ms));
|
k_delayed_work_submit(&data->work, K_NO_WAIT);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void kscan_matrix_read_continue(const struct device *dev) {
|
||||||
|
const struct kscan_matrix_config *config = dev->config;
|
||||||
|
struct kscan_matrix_data *data = dev->data;
|
||||||
|
|
||||||
|
data->scan_time += config->debounce_scan_period_ms;
|
||||||
|
|
||||||
|
// TODO (Zephyr 2.6): use k_work_reschedule()
|
||||||
|
k_delayed_work_cancel(&data->work);
|
||||||
|
k_delayed_work_submit(&data->work, K_TIMEOUT_ABS_MS(data->scan_time));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kscan_matrix_read_end(const struct device *dev) {
|
||||||
|
#if USE_INTERRUPTS
|
||||||
|
// Return to waiting for an interrupt.
|
||||||
|
kscan_matrix_interrupt_enable(dev);
|
||||||
|
#else
|
||||||
|
struct kscan_matrix_data *data = dev->data;
|
||||||
|
const struct kscan_matrix_config *config = dev->config;
|
||||||
|
|
||||||
|
data->scan_time += config->poll_period_ms;
|
||||||
|
|
||||||
|
// Return to polling slowly.
|
||||||
|
// TODO (Zephyr 2.6): use k_work_reschedule()
|
||||||
|
k_delayed_work_cancel(&data->work);
|
||||||
|
k_delayed_work_submit(&data->work, K_TIMEOUT_ABS_MS(data->scan_time));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static int kscan_matrix_read(const struct device *dev) {
|
static int kscan_matrix_read(const struct device *dev) {
|
||||||
struct kscan_matrix_data *data = dev->data;
|
struct kscan_matrix_data *data = dev->data;
|
||||||
const struct kscan_matrix_config *config = dev->config;
|
const struct kscan_matrix_config *config = dev->config;
|
||||||
|
@ -221,7 +266,10 @@ static int kscan_matrix_read(const struct device *dev) {
|
||||||
const struct kscan_gpio_dt_spec *in_gpio = &config->inputs.gpios[i];
|
const struct kscan_gpio_dt_spec *in_gpio = &config->inputs.gpios[i];
|
||||||
|
|
||||||
const int index = state_index_io(config, i, o);
|
const int index = state_index_io(config, i, o);
|
||||||
data->next_state[index] = gpio_pin_get(in_gpio->port, in_gpio->pin);
|
const bool active = gpio_pin_get(in_gpio->port, in_gpio->pin);
|
||||||
|
|
||||||
|
debounce_update(&data->matrix_state[index], active, config->debounce_scan_period_ms,
|
||||||
|
&config->debounce_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = gpio_pin_set(out_gpio->port, out_gpio->pin, 0);
|
err = gpio_pin_set(out_gpio->port, out_gpio->pin, 0);
|
||||||
|
@ -232,50 +280,36 @@ static int kscan_matrix_read(const struct device *dev) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process the new state.
|
// Process the new state.
|
||||||
#if USE_INTERRUPTS
|
bool continue_scan = false;
|
||||||
bool submit_followup_read = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (int r = 0; r < config->rows.len; r++) {
|
for (int r = 0; r < config->rows.len; r++) {
|
||||||
for (int c = 0; c < config->cols.len; c++) {
|
for (int c = 0; c < config->cols.len; c++) {
|
||||||
const int index = state_index_rc(config, r, c);
|
const int index = state_index_rc(config, r, c);
|
||||||
const bool pressed = data->next_state[index];
|
struct debounce_state *state = &data->matrix_state[index];
|
||||||
|
|
||||||
|
if (debounce_get_changed(state)) {
|
||||||
|
const bool pressed = debounce_is_pressed(state);
|
||||||
|
|
||||||
// Follow up reads are needed if any key is pressed because further
|
|
||||||
// interrupts won't fire on already tripped GPIO pins.
|
|
||||||
#if USE_INTERRUPTS
|
|
||||||
submit_followup_read = submit_followup_read || pressed;
|
|
||||||
#endif
|
|
||||||
if (pressed != data->current_state[index]) {
|
|
||||||
LOG_DBG("Sending event at %i,%i state %s", r, c, pressed ? "on" : "off");
|
LOG_DBG("Sending event at %i,%i state %s", r, c, pressed ? "on" : "off");
|
||||||
data->current_state[index] = pressed;
|
|
||||||
data->callback(dev, r, c, pressed);
|
data->callback(dev, r, c, pressed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
continue_scan = continue_scan || debounce_is_active(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if USE_INTERRUPTS
|
if (continue_scan) {
|
||||||
if (submit_followup_read) {
|
// At least one key is pressed or the debouncer has not yet decided if
|
||||||
// At least one key is pressed. Poll until everything is released.
|
// it is pressed. Poll quickly until everything is released.
|
||||||
// TODO (Zephyr 2.6): use k_work_reschedule()
|
kscan_matrix_read_continue(dev);
|
||||||
k_delayed_work_cancel(&data->work);
|
|
||||||
k_delayed_work_submit(&data->work, K_MSEC(config->debounce_period_ms));
|
|
||||||
} else {
|
} else {
|
||||||
// All keys are released. Return to waiting for an interrupt.
|
// All keys are released. Return to normal.
|
||||||
kscan_matrix_interrupt_enable(dev);
|
kscan_matrix_read_end(dev);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if USE_POLLING
|
|
||||||
static void kscan_matrix_timer_handler(struct k_timer *timer) {
|
|
||||||
struct kscan_matrix_data *data = CONTAINER_OF(timer, struct kscan_matrix_data, poll_timer);
|
|
||||||
k_delayed_work_submit(&data->work, K_NO_WAIT);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void kscan_matrix_work_handler(struct k_work *work) {
|
static void kscan_matrix_work_handler(struct k_work *work) {
|
||||||
struct k_delayed_work *dwork = CONTAINER_OF(work, struct k_delayed_work, work);
|
struct k_delayed_work *dwork = CONTAINER_OF(work, struct k_delayed_work, work);
|
||||||
struct kscan_matrix_data *data = CONTAINER_OF(dwork, struct kscan_matrix_data, work);
|
struct kscan_matrix_data *data = CONTAINER_OF(dwork, struct kscan_matrix_data, work);
|
||||||
|
@ -294,27 +328,23 @@ static int kscan_matrix_configure(const struct device *dev, const kscan_callback
|
||||||
}
|
}
|
||||||
|
|
||||||
static int kscan_matrix_enable(const struct device *dev) {
|
static int kscan_matrix_enable(const struct device *dev) {
|
||||||
#if USE_POLLING
|
|
||||||
struct kscan_matrix_data *data = dev->data;
|
struct kscan_matrix_data *data = dev->data;
|
||||||
const struct kscan_matrix_config *config = dev->config;
|
|
||||||
|
|
||||||
k_timer_start(&data->poll_timer, K_MSEC(config->poll_period_ms),
|
data->scan_time = k_uptime_get();
|
||||||
K_MSEC(config->poll_period_ms));
|
|
||||||
return 0;
|
// Read will automatically start interrupts/polling once done.
|
||||||
#else
|
|
||||||
// Read will automatically enable interrupts once done.
|
|
||||||
return kscan_matrix_read(dev);
|
return kscan_matrix_read(dev);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int kscan_matrix_disable(const struct device *dev) {
|
static int kscan_matrix_disable(const struct device *dev) {
|
||||||
#if USE_POLLING
|
|
||||||
struct kscan_matrix_data *data = dev->data;
|
struct kscan_matrix_data *data = dev->data;
|
||||||
|
|
||||||
k_timer_stop(&data->poll_timer);
|
k_delayed_work_cancel(&data->work);
|
||||||
return 0;
|
|
||||||
#else
|
#if USE_INTERRUPTS
|
||||||
return kscan_matrix_interrupt_disable(dev);
|
return kscan_matrix_interrupt_disable(dev);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,7 +368,6 @@ static int kscan_matrix_init_input_inst(const struct device *dev,
|
||||||
struct kscan_matrix_irq_callback *irq = &data->irqs[index];
|
struct kscan_matrix_irq_callback *irq = &data->irqs[index];
|
||||||
|
|
||||||
irq->dev = dev;
|
irq->dev = dev;
|
||||||
irq->work = &data->work;
|
|
||||||
gpio_init_callback(&irq->callback, kscan_matrix_irq_callback_handler, BIT(gpio->pin));
|
gpio_init_callback(&irq->callback, kscan_matrix_irq_callback_handler, BIT(gpio->pin));
|
||||||
err = gpio_add_callback(gpio->port, &irq->callback);
|
err = gpio_add_callback(gpio->port, &irq->callback);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -407,10 +436,6 @@ static int kscan_matrix_init(const struct device *dev) {
|
||||||
|
|
||||||
k_delayed_work_init(&data->work, kscan_matrix_work_handler);
|
k_delayed_work_init(&data->work, kscan_matrix_work_handler);
|
||||||
|
|
||||||
#if USE_POLLING
|
|
||||||
k_timer_init(&data->poll_timer, kscan_matrix_timer_handler, NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,21 +446,24 @@ static const struct kscan_driver_api kscan_matrix_api = {
|
||||||
};
|
};
|
||||||
|
|
||||||
#define KSCAN_MATRIX_INIT(index) \
|
#define KSCAN_MATRIX_INIT(index) \
|
||||||
|
BUILD_ASSERT(INST_DEBOUNCE_PRESS_MS(index) <= DEBOUNCE_COUNTER_MAX, \
|
||||||
|
"ZMK_KSCAN_DEBOUNCE_PRESS_MS or debounce-press-ms is too large"); \
|
||||||
|
BUILD_ASSERT(INST_DEBOUNCE_RELEASE_MS(index) <= DEBOUNCE_COUNTER_MAX, \
|
||||||
|
"ZMK_KSCAN_DEBOUNCE_RELEASE_MS or debounce-release-ms is too large"); \
|
||||||
|
\
|
||||||
static const struct kscan_gpio_dt_spec kscan_matrix_rows_##index[] = { \
|
static const struct kscan_gpio_dt_spec kscan_matrix_rows_##index[] = { \
|
||||||
UTIL_LISTIFY(INST_ROWS_LEN(index), KSCAN_GPIO_ROW_CFG_INIT, index)}; \
|
UTIL_LISTIFY(INST_ROWS_LEN(index), KSCAN_GPIO_ROW_CFG_INIT, index)}; \
|
||||||
\
|
\
|
||||||
static const struct kscan_gpio_dt_spec kscan_matrix_cols_##index[] = { \
|
static const struct kscan_gpio_dt_spec kscan_matrix_cols_##index[] = { \
|
||||||
UTIL_LISTIFY(INST_COLS_LEN(index), KSCAN_GPIO_COL_CFG_INIT, index)}; \
|
UTIL_LISTIFY(INST_COLS_LEN(index), KSCAN_GPIO_COL_CFG_INIT, index)}; \
|
||||||
\
|
\
|
||||||
static bool kscan_current_state_##index[INST_MATRIX_LEN(index)]; \
|
static struct debounce_state kscan_matrix_state_##index[INST_MATRIX_LEN(index)]; \
|
||||||
static bool kscan_next_state_##index[INST_MATRIX_LEN(index)]; \
|
|
||||||
\
|
\
|
||||||
COND_INTERRUPTS((static struct kscan_matrix_irq_callback \
|
COND_INTERRUPTS((static struct kscan_matrix_irq_callback \
|
||||||
kscan_matrix_irqs_##index[INST_INPUTS_LEN(index)];)) \
|
kscan_matrix_irqs_##index[INST_INPUTS_LEN(index)];)) \
|
||||||
\
|
\
|
||||||
static struct kscan_matrix_data kscan_matrix_data_##index = { \
|
static struct kscan_matrix_data kscan_matrix_data_##index = { \
|
||||||
.current_state = kscan_current_state_##index, \
|
.matrix_state = kscan_matrix_state_##index, \
|
||||||
.next_state = kscan_next_state_##index, \
|
|
||||||
COND_INTERRUPTS((.irqs = kscan_matrix_irqs_##index, ))}; \
|
COND_INTERRUPTS((.irqs = kscan_matrix_irqs_##index, ))}; \
|
||||||
\
|
\
|
||||||
static struct kscan_matrix_config kscan_matrix_config_##index = { \
|
static struct kscan_matrix_config kscan_matrix_config_##index = { \
|
||||||
|
@ -445,7 +473,12 @@ static const struct kscan_driver_api kscan_matrix_api = {
|
||||||
COND_DIODE_DIR(index, (kscan_matrix_cols_##index), (kscan_matrix_rows_##index))), \
|
COND_DIODE_DIR(index, (kscan_matrix_cols_##index), (kscan_matrix_rows_##index))), \
|
||||||
.outputs = KSCAN_GPIO_LIST( \
|
.outputs = KSCAN_GPIO_LIST( \
|
||||||
COND_DIODE_DIR(index, (kscan_matrix_rows_##index), (kscan_matrix_cols_##index))), \
|
COND_DIODE_DIR(index, (kscan_matrix_rows_##index), (kscan_matrix_cols_##index))), \
|
||||||
.debounce_period_ms = DT_INST_PROP(index, debounce_period), \
|
.debounce_config = \
|
||||||
|
{ \
|
||||||
|
.debounce_press_ms = INST_DEBOUNCE_PRESS_MS(index), \
|
||||||
|
.debounce_release_ms = INST_DEBOUNCE_RELEASE_MS(index), \
|
||||||
|
}, \
|
||||||
|
.debounce_scan_period_ms = DT_INST_PROP(index, debounce_scan_period_ms), \
|
||||||
.poll_period_ms = DT_INST_PROP(index, poll_period_ms), \
|
.poll_period_ms = DT_INST_PROP(index, poll_period_ms), \
|
||||||
.diode_direction = INST_DIODE_DIR(index), \
|
.diode_direction = INST_DIODE_DIR(index), \
|
||||||
}; \
|
}; \
|
||||||
|
|
|
@ -15,13 +15,26 @@ properties:
|
||||||
type: phandle-array
|
type: phandle-array
|
||||||
required: true
|
required: true
|
||||||
debounce-period:
|
debounce-period:
|
||||||
|
type: int
|
||||||
|
required: false
|
||||||
|
deprecated: true
|
||||||
|
description: Deprecated. Use debounce-press-ms and debounce-release-ms instead.
|
||||||
|
debounce-press-ms:
|
||||||
type: int
|
type: int
|
||||||
default: 5
|
default: 5
|
||||||
description: Debounce time in milliseconds
|
description: Debounce time for key press in milliseconds. Use 0 for eager debouncing.
|
||||||
|
debounce-release-ms:
|
||||||
|
type: int
|
||||||
|
default: 5
|
||||||
|
description: Debounce time for key release in milliseconds.
|
||||||
|
debounce-scan-period-ms:
|
||||||
|
type: int
|
||||||
|
default: 1
|
||||||
|
description: Time between reads in milliseconds when any key is pressed.
|
||||||
poll-period-ms:
|
poll-period-ms:
|
||||||
type: int
|
type: int
|
||||||
default: 10
|
default: 10
|
||||||
description: Time between reads in milliseconds when polling is enabled
|
description: Time between reads in milliseconds when no key is pressed and ZMK_KSCAN_MATRIX_POLLING is enabled.
|
||||||
diode-direction:
|
diode-direction:
|
||||||
type: string
|
type: string
|
||||||
default: row2col
|
default: row2col
|
||||||
|
|
|
@ -469,22 +469,12 @@ static int position_state_changed_listener(const zmk_event_t *ev) {
|
||||||
ZMK_LISTENER(combo, position_state_changed_listener);
|
ZMK_LISTENER(combo, position_state_changed_listener);
|
||||||
ZMK_SUBSCRIPTION(combo, zmk_position_state_changed);
|
ZMK_SUBSCRIPTION(combo, zmk_position_state_changed);
|
||||||
|
|
||||||
// todo: remove this once #506 is merged and #include <zmk/keymap.h>
|
|
||||||
#define KEY_BINDING_TO_STRUCT(idx, drv_inst) \
|
|
||||||
{ \
|
|
||||||
.behavior_dev = DT_LABEL(DT_PHANDLE_BY_IDX(drv_inst, bindings, idx)), \
|
|
||||||
.param1 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(drv_inst, bindings, idx, param1), (0), \
|
|
||||||
(DT_PHA_BY_IDX(drv_inst, bindings, idx, param1))), \
|
|
||||||
.param2 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(drv_inst, bindings, idx, param2), (0), \
|
|
||||||
(DT_PHA_BY_IDX(drv_inst, bindings, idx, param2))), \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define COMBO_INST(n) \
|
#define COMBO_INST(n) \
|
||||||
static struct combo_cfg combo_config_##n = { \
|
static struct combo_cfg combo_config_##n = { \
|
||||||
.timeout_ms = DT_PROP(n, timeout_ms), \
|
.timeout_ms = DT_PROP(n, timeout_ms), \
|
||||||
.key_positions = DT_PROP(n, key_positions), \
|
.key_positions = DT_PROP(n, key_positions), \
|
||||||
.key_position_len = DT_PROP_LEN(n, key_positions), \
|
.key_position_len = DT_PROP_LEN(n, key_positions), \
|
||||||
.behavior = KEY_BINDING_TO_STRUCT(0, n), \
|
.behavior = ZMK_KEYMAP_EXTRACT_BINDING(0, n), \
|
||||||
.virtual_key_position = ZMK_KEYMAP_LEN + __COUNTER__, \
|
.virtual_key_position = ZMK_KEYMAP_LEN + __COUNTER__, \
|
||||||
.slow_release = DT_PROP(n, slow_release), \
|
.slow_release = DT_PROP(n, slow_release), \
|
||||||
.layers = DT_PROP(n, layers), \
|
.layers = DT_PROP(n, layers), \
|
||||||
|
|
|
@ -39,7 +39,7 @@ static struct output_status_state get_state(const zmk_event_t *_eh) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_status_symbol(lv_obj_t *label, struct output_status_state state) {
|
static void set_status_symbol(lv_obj_t *label, struct output_status_state state) {
|
||||||
char text[6] = {};
|
char text[9] = {};
|
||||||
|
|
||||||
switch (state.selected_endpoint) {
|
switch (state.selected_endpoint) {
|
||||||
case ZMK_ENDPOINT_USB:
|
case ZMK_ENDPOINT_USB:
|
||||||
|
|
|
@ -28,6 +28,9 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
#define SAT_MAX 100
|
#define SAT_MAX 100
|
||||||
#define BRT_MAX 100
|
#define BRT_MAX 100
|
||||||
|
|
||||||
|
BUILD_ASSERT(CONFIG_ZMK_RGB_UNDERGLOW_BRT_MIN <= CONFIG_ZMK_RGB_UNDERGLOW_BRT_MAX,
|
||||||
|
"ERROR: RGB underglow maximum brightness is less than minimum brightness");
|
||||||
|
|
||||||
enum rgb_underglow_effect {
|
enum rgb_underglow_effect {
|
||||||
UNDERGLOW_EFFECT_SOLID,
|
UNDERGLOW_EFFECT_SOLID,
|
||||||
UNDERGLOW_EFFECT_BREATHE,
|
UNDERGLOW_EFFECT_BREATHE,
|
||||||
|
@ -54,6 +57,17 @@ static struct rgb_underglow_state state;
|
||||||
static const struct device *ext_power;
|
static const struct device *ext_power;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static struct zmk_led_hsb hsb_scale_min_max(struct zmk_led_hsb hsb) {
|
||||||
|
hsb.b = CONFIG_ZMK_RGB_UNDERGLOW_BRT_MIN +
|
||||||
|
(CONFIG_ZMK_RGB_UNDERGLOW_BRT_MAX - CONFIG_ZMK_RGB_UNDERGLOW_BRT_MIN) * hsb.b / BRT_MAX;
|
||||||
|
return hsb;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct zmk_led_hsb hsb_scale_zero_max(struct zmk_led_hsb hsb) {
|
||||||
|
hsb.b = hsb.b * CONFIG_ZMK_RGB_UNDERGLOW_BRT_MAX / BRT_MAX;
|
||||||
|
return hsb;
|
||||||
|
}
|
||||||
|
|
||||||
static struct led_rgb hsb_to_rgb(struct zmk_led_hsb hsb) {
|
static struct led_rgb hsb_to_rgb(struct zmk_led_hsb hsb) {
|
||||||
double r, g, b;
|
double r, g, b;
|
||||||
|
|
||||||
|
@ -105,7 +119,7 @@ static struct led_rgb hsb_to_rgb(struct zmk_led_hsb hsb) {
|
||||||
|
|
||||||
static void zmk_rgb_underglow_effect_solid() {
|
static void zmk_rgb_underglow_effect_solid() {
|
||||||
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
|
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
|
||||||
pixels[i] = hsb_to_rgb(state.color);
|
pixels[i] = hsb_to_rgb(hsb_scale_min_max(state.color));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +128,7 @@ static void zmk_rgb_underglow_effect_breathe() {
|
||||||
struct zmk_led_hsb hsb = state.color;
|
struct zmk_led_hsb hsb = state.color;
|
||||||
hsb.b = abs(state.animation_step - 1200) / 12;
|
hsb.b = abs(state.animation_step - 1200) / 12;
|
||||||
|
|
||||||
pixels[i] = hsb_to_rgb(hsb);
|
pixels[i] = hsb_to_rgb(hsb_scale_zero_max(hsb));
|
||||||
}
|
}
|
||||||
|
|
||||||
state.animation_step += state.animation_speed * 10;
|
state.animation_step += state.animation_speed * 10;
|
||||||
|
@ -129,7 +143,7 @@ static void zmk_rgb_underglow_effect_spectrum() {
|
||||||
struct zmk_led_hsb hsb = state.color;
|
struct zmk_led_hsb hsb = state.color;
|
||||||
hsb.h = state.animation_step;
|
hsb.h = state.animation_step;
|
||||||
|
|
||||||
pixels[i] = hsb_to_rgb(hsb);
|
pixels[i] = hsb_to_rgb(hsb_scale_min_max(hsb));
|
||||||
}
|
}
|
||||||
|
|
||||||
state.animation_step += state.animation_speed;
|
state.animation_step += state.animation_speed;
|
||||||
|
@ -141,7 +155,7 @@ static void zmk_rgb_underglow_effect_swirl() {
|
||||||
struct zmk_led_hsb hsb = state.color;
|
struct zmk_led_hsb hsb = state.color;
|
||||||
hsb.h = (HUE_MAX / STRIP_NUM_PIXELS * i + state.animation_step) % HUE_MAX;
|
hsb.h = (HUE_MAX / STRIP_NUM_PIXELS * i + state.animation_step) % HUE_MAX;
|
||||||
|
|
||||||
pixels[i] = hsb_to_rgb(hsb);
|
pixels[i] = hsb_to_rgb(hsb_scale_min_max(hsb));
|
||||||
}
|
}
|
||||||
|
|
||||||
state.animation_step += state.animation_speed * 2;
|
state.animation_step += state.animation_speed * 2;
|
||||||
|
@ -371,12 +385,7 @@ struct zmk_led_hsb zmk_rgb_underglow_calc_brt(int direction) {
|
||||||
struct zmk_led_hsb color = state.color;
|
struct zmk_led_hsb color = state.color;
|
||||||
|
|
||||||
int b = color.b + (direction * CONFIG_ZMK_RGB_UNDERGLOW_BRT_STEP);
|
int b = color.b + (direction * CONFIG_ZMK_RGB_UNDERGLOW_BRT_STEP);
|
||||||
if (b < 0) {
|
color.b = CLAMP(b, 0, BRT_MAX);
|
||||||
b = 0;
|
|
||||||
} else if (b > BRT_MAX) {
|
|
||||||
b = BRT_MAX;
|
|
||||||
}
|
|
||||||
color.b = b;
|
|
||||||
|
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ This allows you to use those defines, e.g. `LOWER` later in your keymap.
|
||||||
## Momentary Layer
|
## Momentary Layer
|
||||||
|
|
||||||
The "momentary layer" behavior enables a layer while a certain key is pressed. Immediately upon
|
The "momentary layer" behavior enables a layer while a certain key is pressed. Immediately upon
|
||||||
activation of the key, the layer is enabled, and immediately open release of the key, the layer is disabled
|
activation of the key, the layer is enabled, and immediately upon release of the key, the layer is disabled
|
||||||
again.
|
again.
|
||||||
|
|
||||||
### Behavior Binding
|
### Behavior Binding
|
||||||
|
|
|
@ -19,7 +19,7 @@ If you are working with the documentation from within VS Code+Docker please be a
|
||||||
:::
|
:::
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
You will need `Node.js` and `npm` installed to update the documentation. If you're using the ZMK dev container (Docker) the necessary dependencies are already installed.
|
You will need `Node.js` and `npm` installed to update the documentation. If you're using the ZMK dev container (Docker) the necessary dependencies are already installed. Otherwise, you must install these dependencies yourself. Since `Node.js` packages in Linux distributions tend to be outdated, it's recommended to install the current version from a repository like [NodeSource](https://github.com/nodesource/distributions) to avoid build errors.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
## Testing Documentation Updates Locally
|
## Testing Documentation Updates Locally
|
||||||
|
|
100
docs/docs/features/debouncing.md
Normal file
100
docs/docs/features/debouncing.md
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
---
|
||||||
|
title: Debouncing
|
||||||
|
sidebar_label: Debouncing
|
||||||
|
---
|
||||||
|
|
||||||
|
To prevent contact bounce (also known as chatter) and noise spikes from causing
|
||||||
|
unwanted key presses, ZMK uses a [cycle-based debounce algorithm](https://www.kennethkuhn.com/electronics/debounce.c),
|
||||||
|
with each key debounced independently.
|
||||||
|
|
||||||
|
By default the debounce algorithm decides that a key is pressed or released after
|
||||||
|
the input is stable for 5 milliseconds. You can decrease this to improve latency
|
||||||
|
or increase it to improve reliability.
|
||||||
|
|
||||||
|
If you are having problems with a single key press registering multiple inputs,
|
||||||
|
you can try increasing the debounce press and/or release times to compensate.
|
||||||
|
You should also check for mechanical issues that might be causing the bouncing,
|
||||||
|
such as hot swap sockets that are making poor contact. You can try replacing the
|
||||||
|
socket or using some sharp tweezers to bend the contacts back together.
|
||||||
|
|
||||||
|
## Debounce Configuration
|
||||||
|
|
||||||
|
### Global Options
|
||||||
|
|
||||||
|
You can set these options in your `.conf` file to control debouncing globally.
|
||||||
|
Values must be <= 127.
|
||||||
|
|
||||||
|
- `CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS`: Debounce time for key press in milliseconds. Default = 5.
|
||||||
|
- `CONFIG_ZMK_KSCAN_DEBOUNCE_RELEASE_MS`: Debounce time for key release in milliseconds. Default = 5.
|
||||||
|
|
||||||
|
For example, this would shorten the debounce time for both press and release:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS=3
|
||||||
|
CONFIG_ZMK_KSCAN_DEBOUNCE_RELEASE_MS=3
|
||||||
|
```
|
||||||
|
|
||||||
|
### Per-driver Options
|
||||||
|
|
||||||
|
You can add these Devicetree properties to a kscan node to control debouncing for
|
||||||
|
that instance of the driver. Values must be <= 127.
|
||||||
|
|
||||||
|
- `debounce-press-ms`: Debounce time for key press in milliseconds. Default = 5.
|
||||||
|
- `debounce-release-ms`: Debounce time for key release in milliseconds. Default = 5.
|
||||||
|
- ~~`debounce-period`~~: Deprecated. Sets both press and release debounce times.
|
||||||
|
- `debounce-scan-period-ms`: Time between reads in milliseconds when any key is pressed. Default = 1.
|
||||||
|
|
||||||
|
If one of the global options described above is set, it overrides the corresponding
|
||||||
|
per-driver option.
|
||||||
|
|
||||||
|
For example, if your board/shield has a kscan driver labeled `kscan0` in its
|
||||||
|
`.overlay`, `.dts`, or `.dtsi` files,
|
||||||
|
|
||||||
|
```devicetree
|
||||||
|
kscan0: kscan {
|
||||||
|
compatible = "zmk,kscan-gpio-matrix";
|
||||||
|
...
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
then you could add this to your `.keymap`:
|
||||||
|
|
||||||
|
```devicetree
|
||||||
|
&kscan0 {
|
||||||
|
debounce-press-ms = <3>;
|
||||||
|
debounce-release-ms = <3>;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
This must be placed outside of any blocks surrounded by curly braces (`{...}`).
|
||||||
|
|
||||||
|
`debounce-scan-period-ms` determines how often the keyboard scans while debouncing. It defaults to 1 ms, but it can be increased to reduce power use. Note that the debounce press/release timers are rounded up to the next multiple of the scan period. For example, if the scan period is 2 ms and debounce timer is 5 ms, key presses will take 6 ms to register instead of 5.
|
||||||
|
|
||||||
|
## Eager Debouncing
|
||||||
|
|
||||||
|
Eager debouncing means reporting a key change immediately and then ignoring
|
||||||
|
further changes for the debounce time. This eliminates latency but it is not
|
||||||
|
noise-resistant.
|
||||||
|
|
||||||
|
ZMK does not currently support true eager debouncing, but you can get something
|
||||||
|
very close by setting the time to detect a key press to zero and the time to detect
|
||||||
|
a key release to a larger number. This will detect a key press immediately, then
|
||||||
|
debounce the key release.
|
||||||
|
|
||||||
|
```ini
|
||||||
|
CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS=0
|
||||||
|
CONFIG_ZMK_KSCAN_DEBOUNCE_RELEASE_MS=5
|
||||||
|
```
|
||||||
|
|
||||||
|
Also consider setting `CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS=1` instead, which adds
|
||||||
|
one millisecond of latency but protects against short noise spikes.
|
||||||
|
|
||||||
|
## Comparison With QMK
|
||||||
|
|
||||||
|
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`.
|
||||||
|
|
||||||
|
See [QMK's Debounce API documentation](https://beta.docs.qmk.fm/using-qmk/software-features/feature_debounce_type)
|
||||||
|
for more information.
|
1984
docs/package-lock.json
generated
1984
docs/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -19,15 +19,16 @@
|
||||||
"@docusaurus/preset-classic": "^2.0.0-beta.3",
|
"@docusaurus/preset-classic": "^2.0.0-beta.3",
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.32",
|
"@fortawesome/fontawesome-svg-core": "^1.2.32",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.15.3",
|
"@fortawesome/free-solid-svg-icons": "^5.15.3",
|
||||||
"@fortawesome/react-fontawesome": "^0.1.14",
|
"@fortawesome/react-fontawesome": "^0.1.16",
|
||||||
|
"@mdx-js/react": "^1.6.22",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
|
"js-yaml": "^4.1.0",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-async": "^10.0.1",
|
"react-async": "^10.0.1",
|
||||||
"react-copy-to-clipboard": "^5.0.3",
|
"react-copy-to-clipboard": "^5.0.3",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-toastify": "^7.0.4",
|
"react-toastify": "^7.0.4",
|
||||||
"web-tree-sitter": "^0.19.4",
|
"web-tree-sitter": "^0.19.4"
|
||||||
"@mdx-js/react": "^1.6.22"
|
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
"production": [
|
"production": [
|
||||||
|
@ -42,6 +43,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@docusaurus/module-type-aliases": "^2.0.0-beta.3",
|
||||||
|
"@tsconfig/docusaurus": "^1.0.2",
|
||||||
|
"@types/react": "^17.0.3",
|
||||||
|
"@types/react-helmet": "^6.1.0",
|
||||||
|
"@types/react-router-dom": "^5.1.7",
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^7.32.0",
|
||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-config-prettier": "^8.3.0",
|
||||||
"eslint-plugin-mdx": "^1.13.0",
|
"eslint-plugin-mdx": "^1.13.0",
|
||||||
|
@ -53,11 +59,6 @@
|
||||||
"prettier": "2.3.1",
|
"prettier": "2.3.1",
|
||||||
"string-replace-loader": "^3.0.3",
|
"string-replace-loader": "^3.0.3",
|
||||||
"typescript": "^4.2.3",
|
"typescript": "^4.2.3",
|
||||||
"webpack": "^5.46.0",
|
"webpack": "^5.46.0"
|
||||||
"@docusaurus/module-type-aliases": "^2.0.0-beta.3",
|
|
||||||
"@tsconfig/docusaurus": "^1.0.2",
|
|
||||||
"@types/react": "^17.0.3",
|
|
||||||
"@types/react-helmet": "^6.1.0",
|
|
||||||
"@types/react-router-dom": "^5.1.7"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ module.exports = {
|
||||||
Features: [
|
Features: [
|
||||||
"features/keymaps",
|
"features/keymaps",
|
||||||
"features/combos",
|
"features/combos",
|
||||||
|
"features/debouncing",
|
||||||
"features/displays",
|
"features/displays",
|
||||||
"features/encoders",
|
"features/encoders",
|
||||||
"features/underglow",
|
"features/underglow",
|
||||||
|
|
|
@ -12,7 +12,7 @@ const glob = require("glob");
|
||||||
function generateHardwareMetadataAggregate() {
|
function generateHardwareMetadataAggregate() {
|
||||||
glob("../app/boards/**/*.zmk.yml", (error, files) => {
|
glob("../app/boards/**/*.zmk.yml", (error, files) => {
|
||||||
const aggregated = files.flatMap((f) =>
|
const aggregated = files.flatMap((f) =>
|
||||||
yaml.safeLoadAll(fs.readFileSync(f, "utf8"))
|
yaml.loadAll(fs.readFileSync(f, "utf8"))
|
||||||
);
|
);
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
"src/data/hardware-metadata.json",
|
"src/data/hardware-metadata.json",
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var PrebuildPlugin = require("prebuild-webpack-plugin");
|
var PrebuildPlugin = require("prebuild-webpack-plugin");
|
||||||
|
const path = require("path");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const glob = require("glob");
|
const glob = require("glob");
|
||||||
const yaml = require("js-yaml");
|
const yaml = require("js-yaml");
|
||||||
|
@ -12,9 +13,10 @@ const Mustache = require("mustache");
|
||||||
|
|
||||||
function generateSetupScripts() {
|
function generateSetupScripts() {
|
||||||
return glob("../app/boards/**/*.zmk.yml", (error, files) => {
|
return glob("../app/boards/**/*.zmk.yml", (error, files) => {
|
||||||
const aggregated = files.flatMap((f) =>
|
const aggregated = files.map((f) => ({
|
||||||
yaml.safeLoadAll(fs.readFileSync(f, "utf8"))
|
...yaml.load(fs.readFileSync(f, "utf8")),
|
||||||
);
|
__base_dir: path.basename(path.dirname(f)),
|
||||||
|
}));
|
||||||
|
|
||||||
const data = aggregated.reduce(
|
const data = aggregated.reduce(
|
||||||
(agg, item) => {
|
(agg, item) => {
|
||||||
|
@ -25,7 +27,9 @@ function generateSetupScripts() {
|
||||||
agg.keyboards.push(item);
|
agg.keyboards.push(item);
|
||||||
break;
|
break;
|
||||||
case "board":
|
case "board":
|
||||||
if (!item.features?.includes("keys")) {
|
if (item.features?.includes("keys")) {
|
||||||
|
agg.keyboards.push(item);
|
||||||
|
} else {
|
||||||
agg.boards.push(item);
|
agg.boards.push(item);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -35,6 +39,9 @@ function generateSetupScripts() {
|
||||||
{ keyboards: [], boards: [] }
|
{ keyboards: [], boards: [] }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
data.keyboards.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
data.boards.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
|
||||||
for (let script_ext of ["sh", "ps1"]) {
|
for (let script_ext of ["sh", "ps1"]) {
|
||||||
const templateBuffer = fs.readFileSync(
|
const templateBuffer = fs.readFileSync(
|
||||||
`src/templates/setup.${script_ext}.mustache`,
|
`src/templates/setup.${script_ext}.mustache`,
|
||||||
|
|
|
@ -84,36 +84,59 @@ if (Test-CommandExists Get-Acl) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$repo_path = "https://github.com/zmkfirmware/zmk-config-split-template.git"
|
$repo_path = "https://github.com/zmkfirmware/unified-zmk-config-template.git"
|
||||||
|
|
||||||
$title = "ZMK Config Setup:"
|
$title = "ZMK Config Setup:"
|
||||||
$prompt = "Pick an MCU board"
|
|
||||||
$options = {{#boards}}"{{{name}}}", {{/boards}} "" | Where-Object { $_ -ne "" }
|
|
||||||
$boards = {{#boards}}"{{id}}", {{/boards}} "" | Where-Object { $_ -ne "" }
|
|
||||||
|
|
||||||
Write-Host "$title"
|
|
||||||
Write-Host ""
|
|
||||||
Write-Host "MCU Board Selection:"
|
|
||||||
|
|
||||||
$choice = Get-Choice-From-Options -Options $options -Prompt $prompt
|
|
||||||
$board = $($boards[$choice])
|
|
||||||
|
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "Keyboard Shield Selection:"
|
Write-Host "Keyboard Shield Selection:"
|
||||||
$prompt = "Pick a keyboard"
|
$prompt = "Pick a keyboard"
|
||||||
|
|
||||||
|
$keyboards = [ordered]@{
|
||||||
|
{{#keyboards}}
|
||||||
|
"{{id}}" = @{
|
||||||
|
name = "{{{name}}}";
|
||||||
|
type = "{{type}}";
|
||||||
|
basedir = "{{__base_dir}}";
|
||||||
|
split = "{{split}}";
|
||||||
|
arch = "{{arch}}";
|
||||||
|
siblings = {{#siblings.0}}@(
|
||||||
|
{{#siblings}}
|
||||||
|
"{{.}}"
|
||||||
|
{{/siblings}}
|
||||||
|
){{/siblings.0}}{{^siblings.0}}( "{{id}}" ){{/siblings.0}};
|
||||||
|
}
|
||||||
|
{{/keyboards}}
|
||||||
|
}
|
||||||
# TODO: Add support for "Other" and linking to docs on adding custom shields in user config repos.
|
# TODO: Add support for "Other" and linking to docs on adding custom shields in user config repos.
|
||||||
$options = {{#keyboards}}"{{name}}", {{/keyboards}} "" | Where-Object { $_ -ne "" }
|
|
||||||
$names = {{#keyboards}}"{{id}}", {{/keyboards}} "" | Where-Object { $_ -ne "" }
|
|
||||||
$splits = {{#keyboards}}"{{#split}}y{{/split}}{{^split}}n{{/split}}", {{/keyboards}} "" | Where-Object { $_ -ne "" }
|
|
||||||
|
|
||||||
$choice = Get-Choice-From-Options -Options $options -Prompt $prompt
|
$choice = Get-Choice-From-Options -Options ($keyboards.values | % { $_['name'] }) -Prompt $prompt
|
||||||
$shield_title = $($options[$choice])
|
$keyboard = $($($keyboards.keys)[$choice])
|
||||||
$shield = $($names[$choice])
|
$keyboard_title = $keyboards[$keyboard].name
|
||||||
$split = $($splits[$choice])
|
$basedir = $keyboards[$keyboard].basedir
|
||||||
|
$keyboard_split = $keyboards[$keyboard].split
|
||||||
|
$keyboard_arch = $keyboards[$keyboard].arch
|
||||||
|
$keyboard_siblings = $keyboards[$keyboard].siblings
|
||||||
|
$keyboard_type = $keyboards[$keyboard].type
|
||||||
|
|
||||||
if ($split -eq "n") {
|
if ($keyboard_type -eq "shield") {
|
||||||
$repo_path = "https://github.com/zmkfirmware/zmk-config-template.git"
|
$prompt = "Pick an MCU board"
|
||||||
|
$boards = [ordered]@{
|
||||||
|
{{#boards}}
|
||||||
|
{{id}} = "{{{name}}}";
|
||||||
|
{{/boards}}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "$title"
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "MCU Board Selection:"
|
||||||
|
|
||||||
|
$choice = Get-Choice-From-Options -Options $boards.values -Prompt $prompt
|
||||||
|
$shields = $keyboard_siblings
|
||||||
|
$board = $($($boards.keys)[$choice])
|
||||||
|
$boards = ( $board )
|
||||||
|
} else {
|
||||||
|
$boards = ( $keyboard_siblings )
|
||||||
|
$shields = @( )
|
||||||
}
|
}
|
||||||
|
|
||||||
$copy_keymap = Read-Host "Copy in the stock keymap for customisation? [Yn]"
|
$copy_keymap = Read-Host "Copy in the stock keymap for customisation? [Yn]"
|
||||||
|
@ -144,8 +167,12 @@ else {
|
||||||
|
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "Preparing a user config for:"
|
Write-Host "Preparing a user config for:"
|
||||||
Write-Host "* MCU Board: ${board}"
|
if ($keyboard_type -eq "shield") {
|
||||||
Write-Host "* Shield: ${shield}"
|
Write-Host "* MCU Board: ${boards}"
|
||||||
|
Write-Host "* Shield(s): ${shields}"
|
||||||
|
} else {
|
||||||
|
Write-Host "* Board(s): ${boards}"
|
||||||
|
}
|
||||||
|
|
||||||
if ($copy_keymap -eq "yes") {
|
if ($copy_keymap -eq "yes") {
|
||||||
Write-Host "* Copy Keymap?: Yes"
|
Write-Host "* Copy Keymap?: Yes"
|
||||||
|
@ -171,24 +198,43 @@ Set-Location "$repo_name"
|
||||||
|
|
||||||
Push-Location config
|
Push-Location config
|
||||||
|
|
||||||
Invoke-RestMethod -Uri "https://raw.githubusercontent.com/zmkfirmware/zmk/main/app/boards/shields/${shield}/${shield}.conf" -OutFile "${shield}.conf"
|
$config_file = "${keyboard}.conf"
|
||||||
|
$keymap_file = "${keyboard}.keymap"
|
||||||
|
|
||||||
|
if ($keyboard_type -eq "shield") {
|
||||||
|
$config_url = "https://raw.githubusercontent.com/zmkfirmware/zmk/main/app/boards/shields/${basedir}/${keyboard}.conf"
|
||||||
|
$keymap_url = "https://raw.githubusercontent.com/zmkfirmware/zmk/main/app/boards/shields/${basedir}/${keyboard}.keymap"
|
||||||
|
} else {
|
||||||
|
$config_url = "https://raw.githubusercontent.com/zmkfirmware/zmk/main/app/boards/${keyboard_arch}/${basedir}/${keyboard}.conf"
|
||||||
|
$keymap_url = "https://raw.githubusercontent.com/zmkfirmware/zmk/main/app/boards/${keyboard_arch}/${basedir}/${keyboard}.keymap"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Downloading config file (${config_url})"
|
||||||
|
Try {
|
||||||
|
Invoke-RestMethod -Uri "${config_url}" -OutFile "${config_file}"
|
||||||
|
} Catch {
|
||||||
|
Set-Content -Path $config_file "# Place configuration items here"
|
||||||
|
}
|
||||||
|
|
||||||
if ($copy_keymap -eq "yes") {
|
if ($copy_keymap -eq "yes") {
|
||||||
Invoke-RestMethod -Uri "https://raw.githubusercontent.com/zmkfirmware/zmk/main/app/boards/shields/${shield}/${shield}.keymap" -OutFile "${shield}.keymap"
|
Write-Host "Downloading keymap file (${keymap_url})"
|
||||||
|
Invoke-RestMethod -Uri "${keymap_url}" -OutFile "${keymap_file}"
|
||||||
}
|
}
|
||||||
|
|
||||||
Pop-Location
|
Pop-Location
|
||||||
|
|
||||||
$build_file = (Get-Content .github/workflows/build.yml).replace("BOARD_NAME", $board)
|
Add-Content -Path "build.yaml" -Value "include:"
|
||||||
$build_file = $build_file.replace("SHIELD_NAME", $shield)
|
foreach ($b in ${boards}) {
|
||||||
$build_file = $build_file.replace("KEYBOARD_TITLE", $shield_title)
|
if ($keyboard_type -eq "shield") {
|
||||||
|
foreach ($s in ${shields}) {
|
||||||
if ($board -eq "proton_c") {
|
Add-Content -Path "build.yaml" -Value " - board: $b"
|
||||||
$build_file = $build_file.replace("uf2", "hex")
|
Add-Content -Path "build.yaml" -Value " shield: $s"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Add-Content -Path "build.yaml" -Value " - board: $b"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Set-Content -Path .github/workflows/build.yml -Value $build_file
|
|
||||||
|
|
||||||
Remove-Item -Recurse -Force .git
|
Remove-Item -Recurse -Force .git
|
||||||
git init .
|
git init .
|
||||||
git add .
|
git add .
|
||||||
|
|
|
@ -51,7 +51,7 @@ if [[ $curl_exists == "true" && $wget_exists == "true" ]]; then
|
||||||
if [[ $force_wget == "true" ]]; then
|
if [[ $force_wget == "true" ]]; then
|
||||||
download_command="wget "
|
download_command="wget "
|
||||||
else
|
else
|
||||||
download_command="curl -O "
|
download_command="curl -fsOL "
|
||||||
fi
|
fi
|
||||||
elif [[ $curl_exists == "true" ]]; then
|
elif [[ $curl_exists == "true" ]]; then
|
||||||
download_command="curl -O "
|
download_command="curl -O "
|
||||||
|
@ -62,7 +62,7 @@ else
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
repo_path="https://github.com/zmkfirmware/zmk-config-split-template.git"
|
repo_path="https://github.com/zmkfirmware/unified-zmk-config-template.git"
|
||||||
title="ZMK Config Setup:"
|
title="ZMK Config Setup:"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
@ -71,8 +71,17 @@ PS3="Pick a keyboard: "
|
||||||
options=({{#keyboards}}"{{{name}}}" {{/keyboards}})
|
options=({{#keyboards}}"{{{name}}}" {{/keyboards}})
|
||||||
keyboards_id=({{#keyboards}}"{{id}}" {{/keyboards}})
|
keyboards_id=({{#keyboards}}"{{id}}" {{/keyboards}})
|
||||||
keyboards_type=({{#keyboards}}"{{type}}" {{/keyboards}})
|
keyboards_type=({{#keyboards}}"{{type}}" {{/keyboards}})
|
||||||
|
keyboards_arch=({{#keyboards}}"{{arch}}" {{/keyboards}})
|
||||||
|
keyboards_basedir=({{#keyboards}}"{{__base_dir}}" {{/keyboards}})
|
||||||
keyboards_split=({{#keyboards}}"{{#split}}y{{/split}}{{^split}}n{{/split}}" {{/keyboards}})
|
keyboards_split=({{#keyboards}}"{{#split}}y{{/split}}{{^split}}n{{/split}}" {{/keyboards}})
|
||||||
keyboards_shield=({{#keyboards}}"{{#compatible}}y{{/compatible}}{{^compatible}}n{{/compatible}}" {{/keyboards}})
|
keyboards_shield=({{#keyboards}}"{{#compatible}}y{{/compatible}}{{^compatible}}n{{/compatible}}" {{/keyboards}})
|
||||||
|
|
||||||
|
{{#keyboards}}
|
||||||
|
{{#siblings.0}}
|
||||||
|
{{id}}_siblings=({{#siblings}}"{{.}}" {{/siblings}})
|
||||||
|
{{/siblings.0}}
|
||||||
|
{{/keyboards}}
|
||||||
|
|
||||||
select opt in "${options[@]}" "Quit"; do
|
select opt in "${options[@]}" "Quit"; do
|
||||||
case "$REPLY" in
|
case "$REPLY" in
|
||||||
''|*[!0-9]*) echo "Invalid option. Try another one."; continue;;
|
''|*[!0-9]*) echo "Invalid option. Try another one."; continue;;
|
||||||
|
@ -85,9 +94,17 @@ select opt in "${options[@]}" "Quit"; do
|
||||||
fi
|
fi
|
||||||
keyboard_index=$(( $REPLY-1 ))
|
keyboard_index=$(( $REPLY-1 ))
|
||||||
keyboard=${keyboards_id[$keyboard_index]}
|
keyboard=${keyboards_id[$keyboard_index]}
|
||||||
|
keyboard_arch=${keyboards_arch[$keyboard_index]}
|
||||||
|
keyboard_basedir=${keyboards_basedir[$keyboard_index]}
|
||||||
keyboard_title=${options[$keyboard_index]}
|
keyboard_title=${options[$keyboard_index]}
|
||||||
|
keyboard_sibling_var=${keyboard}_siblings[@]
|
||||||
|
keyboard_sibling_first=${keyboard}_siblings[0]
|
||||||
|
if [ -n "${!keyboard_sibling_first}" ]; then
|
||||||
|
keyboard_siblings=${!keyboard_sibling_var}
|
||||||
|
else
|
||||||
|
keyboard_siblings=( "${keyboard}" )
|
||||||
|
fi
|
||||||
split=${keyboards_split[$keyboard_index]}
|
split=${keyboards_split[$keyboard_index]}
|
||||||
type=${keyboards_type[$keyboard_index]}
|
|
||||||
keyboard_shield=${keyboards_shield[$keyboard_index]}
|
keyboard_shield=${keyboards_shield[$keyboard_index]}
|
||||||
break
|
break
|
||||||
;;
|
;;
|
||||||
|
@ -96,6 +113,7 @@ select opt in "${options[@]}" "Quit"; do
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ "$keyboard_shield" == "y" ]; then
|
if [ "$keyboard_shield" == "y" ]; then
|
||||||
|
shields=$keyboard_siblings
|
||||||
shield=${keyboard}
|
shield=${keyboard}
|
||||||
shield_title=${keyboard_title}
|
shield_title=${keyboard_title}
|
||||||
|
|
||||||
|
@ -119,6 +137,7 @@ if [ "$keyboard_shield" == "y" ]; then
|
||||||
board_index=$(( $REPLY-1 ))
|
board_index=$(( $REPLY-1 ))
|
||||||
board=${board_ids[$board_index]}
|
board=${board_ids[$board_index]}
|
||||||
board_title=${options[$board_index]}
|
board_title=${options[$board_index]}
|
||||||
|
boards=( "${board}" )
|
||||||
break
|
break
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
@ -126,12 +145,7 @@ if [ "$keyboard_shield" == "y" ]; then
|
||||||
done
|
done
|
||||||
else
|
else
|
||||||
board=${keyboard}
|
board=${keyboard}
|
||||||
echo "Support for onboard microcontroller keyboards is still a work in progress."
|
boards=$keyboard_siblings
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$split" == "n" ]; then
|
|
||||||
repo_path="https://github.com/zmkfirmware/zmk-config-template.git"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
read -r -e -p "Copy in the stock keymap for customization? [Yn]: " copy_keymap
|
read -r -e -p "Copy in the stock keymap for customization? [Yn]: " copy_keymap
|
||||||
|
@ -152,8 +166,12 @@ fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Preparing a user config for:"
|
echo "Preparing a user config for:"
|
||||||
echo "* MCU Board: ${board}"
|
if [ "$keyboard_shield" == "y" ]; then
|
||||||
echo "* Shield: ${shield}"
|
echo "* MCU Board: ${boards}"
|
||||||
|
echo "* Shield(s): ${shields}"
|
||||||
|
else
|
||||||
|
echo "* Board(s): ${boards}"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$copy_keymap" == "yes" ]; then
|
if [ "$copy_keymap" == "yes" ]; then
|
||||||
echo "* Copy Keymap?: ✓"
|
echo "* Copy Keymap?: ✓"
|
||||||
|
@ -178,26 +196,37 @@ cd ${repo_name}
|
||||||
|
|
||||||
pushd config
|
pushd config
|
||||||
|
|
||||||
$download_command "https://raw.githubusercontent.com/zmkfirmware/zmk/main/app/boards/shields/${shield}/${shield}.conf"
|
if [ "$keyboard_shield" == "y" ]; then
|
||||||
|
config_file="https://raw.githubusercontent.com/zmkfirmware/zmk/main/app/boards/shields/${keyboard_basedir}/${shield}.conf"
|
||||||
|
|
||||||
|
keymap_file="https://raw.githubusercontent.com/zmkfirmware/zmk/main/app/boards/shields/${keyboard_basedir}/${shield}.keymap"
|
||||||
|
else
|
||||||
|
config_file="https://raw.githubusercontent.com/zmkfirmware/zmk/main/app/boards/${keyboard_arch}/${keyboard_basedir}/${board}.conf"
|
||||||
|
keymap_file="https://raw.githubusercontent.com/zmkfirmware/zmk/main/app/boards/${keyboard_arch}/${keyboard_basedir}/${board}.keymap"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Downloading config file (${config_file})"
|
||||||
|
$download_command "${config_file}" || echo "# Put configuration options here" > "${keyboard}.conf"
|
||||||
if [ "$copy_keymap" == "yes" ]; then
|
if [ "$copy_keymap" == "yes" ]; then
|
||||||
$download_command "https://raw.githubusercontent.com/zmkfirmware/zmk/main/app/boards/shields/${shield}/${shield}.keymap"
|
echo "Downloading keymap file (${keymap_file})"
|
||||||
|
$download_command "${keymap_file}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
popd
|
popd
|
||||||
|
|
||||||
sed -i'.orig' \
|
echo "include:" >> build.yaml
|
||||||
-e "s/BOARD_NAME/$board/" \
|
|
||||||
-e "s/SHIELD_NAME/$shield/" \
|
|
||||||
-e "s|KEYBOARD_TITLE|$shield_title|" \
|
|
||||||
.github/workflows/build.yml
|
|
||||||
|
|
||||||
if [ "$board" == "proton_c" ]; then
|
for b in ${boards}; do
|
||||||
# Proton-C board still fa
|
if [ -n "${shields}" ];
|
||||||
sed -i'.orig' -e "s/uf2/hex/g" .github/workflows/build.yml
|
then
|
||||||
fi
|
for s in ${shields}; do
|
||||||
|
echo " - board: ${b}" >> build.yaml
|
||||||
rm .github/workflows/*.yml.orig
|
echo " shield: ${s}" >> build.yaml
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo " - board: ${b}" >> build.yaml
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
rm -rf .git
|
rm -rf .git
|
||||||
git init .
|
git init .
|
||||||
|
|
Loading…
Add table
Reference in a new issue