Compare commits

..

3 Commits

Author SHA1 Message Date
Pete Johanson
acfd8e5ea7 docs: Build fix on release branches (#3130)
Small build fix for the navbar label for the version dropdown, when
building in release version branches.
2025-12-07 02:05:16 -07:00
Pete Johanson
691740c233 docs: Add release version to the docs, with links and warning banner (#3122)
Add versions to the sidebar of the documentation, and when viewing the
deployment on zmk.dev, which tracks `main`, add a banner warning about
possibly prefering the docs for a particular stable release.
2025-12-07 01:43:49 -07:00
Peter Johanson
27cf8979a2 chore: Empty commit to trigger deploy of docs from this branch
In order to support documentation for multiple ZMK releases, add
an empty commit here to trigger a new Netlify build against this
branch.
2025-11-24 18:18:36 -07:00
43 changed files with 718 additions and 1389 deletions

View File

@@ -63,7 +63,7 @@ jobs:
- name: Install @actions/artifact - name: Install @actions/artifact
run: npm install @actions/artifact run: npm install @actions/artifact
- name: Build - name: Build
uses: actions/github-script@v8 uses: actions/github-script@v7
id: boards-list id: boards-list
with: with:
script: | script: |
@@ -95,7 +95,7 @@ jobs:
throw new Error('Failed to build one or more configurations'); throw new Error('Failed to build one or more configurations');
} }
- name: Upload artifacts - name: Upload artifacts
uses: actions/github-script@v8 uses: actions/github-script@v7
continue-on-error: ${{ github.event_name == 'pull_request' }} continue-on-error: ${{ github.event_name == 'pull_request' }}
id: boards-upload id: boards-upload
with: with:
@@ -146,7 +146,7 @@ jobs:
include-list: ${{ steps.compile-list.outputs.result }} include-list: ${{ steps.compile-list.outputs.result }}
steps: steps:
- name: Join build lists - name: Join build lists
uses: actions/github-script@v8 uses: actions/github-script@v7
id: compile-list id: compile-list
with: with:
script: | script: |
@@ -196,7 +196,7 @@ jobs:
node-version: "14.x" node-version: "14.x"
- name: Install js-yaml - name: Install js-yaml
run: npm install js-yaml run: npm install js-yaml
- uses: actions/github-script@v8 - uses: actions/github-script@v7
id: core-list id: core-list
with: with:
script: | script: |
@@ -225,7 +225,7 @@ jobs:
node-version: "14.x" node-version: "14.x"
- name: Install js-yaml - name: Install js-yaml
run: npm install js-yaml run: npm install js-yaml
- uses: actions/github-script@v8 - uses: actions/github-script@v7
id: boards-list id: boards-list
with: with:
script: | script: |
@@ -302,7 +302,7 @@ jobs:
nightly-include: ${{ steps.nightly-list.outputs.result }} nightly-include: ${{ steps.nightly-list.outputs.result }}
steps: steps:
- name: Create nightly list - name: Create nightly list
uses: actions/github-script@v8 uses: actions/github-script@v7
id: nightly-list id: nightly-list
with: with:
script: | script: |
@@ -355,7 +355,7 @@ jobs:
- name: Install js-yaml - name: Install js-yaml
run: npm install js-yaml run: npm install js-yaml
- name: Aggregate Metadata - name: Aggregate Metadata
uses: actions/github-script@v8 uses: actions/github-script@v7
id: aggregate-metadata id: aggregate-metadata
with: with:
script: | script: |
@@ -373,7 +373,7 @@ jobs:
result-encoding: string result-encoding: string
- name: Organize Metadata - name: Organize Metadata
uses: actions/github-script@v8 uses: actions/github-script@v7
id: organize-metadata id: organize-metadata
with: with:
script: | script: |
@@ -435,7 +435,7 @@ jobs:
with: with:
json: true json: true
escape_json: false escape_json: false
- uses: actions/github-script@v8 - uses: actions/github-script@v7
id: board-changes id: board-changes
with: with:
script: | script: |
@@ -443,7 +443,7 @@ jobs:
const boardChanges = changedFiles.filter(f => f.startsWith('app/boards')); const boardChanges = changedFiles.filter(f => f.startsWith('app/boards'));
return boardChanges.length ? 'true' : 'false'; return boardChanges.length ? 'true' : 'false';
result-encoding: string result-encoding: string
- uses: actions/github-script@v8 - uses: actions/github-script@v7
id: core-changes id: core-changes
with: with:
script: | script: |

View File

@@ -69,10 +69,10 @@ jobs:
exit 1 exit 1
fi fi
git clone "https://x-access-token:$ZMK_RELEASE_PLEASE_TOKEN@github.com/zmkfirmware/unified-zmk-config-template.git"
cd unified-zmk-config-template
git config user.name github-actions[bot] git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com git config user.email 41898282+github-actions[bot]@users.noreply.github.com
git clone "https://x-access-token:$ZMK_RELEASE_PLEASE_TOKEN@github.com/zmkfirmware/unified-zmk-config-template.git"
cd unified-zmk-config-template
sed -i 's/^\(\s*\)revision: .*/\1revision: '"$VERSION"'/' config/west.yml sed -i 's/^\(\s*\)revision: .*/\1revision: '"$VERSION"'/' config/west.yml
sed -i 's|uses: zmkfirmware/zmk/.github/workflows/build-user-config.yml@.*|uses: zmkfirmware/zmk/.github/workflows/build-user-config.yml@'"$VERSION"'|' .github/workflows/build.yml sed -i 's|uses: zmkfirmware/zmk/.github/workflows/build-user-config.yml@.*|uses: zmkfirmware/zmk/.github/workflows/build-user-config.yml@'"$VERSION"'|' .github/workflows/build.yml
git add . git add .

View File

@@ -22,7 +22,6 @@ jobs:
This PR was closed because it had no activity for over 10 months. This PR was closed because it had no activity for over 10 months.
Feel free to give a status update or re-open when it has been Feel free to give a status update or re-open when it has been
rebased and is ready for review (again). rebased and is ready for review (again).
days-before-issue-stale: 1000 # ~3 years
days-before-issue-close: -1 days-before-issue-close: -1
ascending: true # Process older PRs first ascending: true # Process older PRs first
operations-per-run: 30 # Default value, listed here again to make it explicit operations-per-run: 30 # Default value, listed here again to make it explicit

View File

@@ -1,12 +0,0 @@
# Copyright (c) 2025 The ZMK Contributors
# SPDX-License-Identifier: MIT
CONFIG_ZMK_BLE=y
CONFIG_ZMK_USB=y
CONFIG_MPU_ALLOW_FLASH_WRITE=y
CONFIG_NVS=y
CONFIG_SETTINGS_NVS=y
CONFIG_FLASH=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_FLASH_MAP=y

View File

@@ -3,10 +3,3 @@ CONFIG_SERIAL=n
CONFIG_UART_CONSOLE=n CONFIG_UART_CONSOLE=n
CONFIG_UART_INTERRUPT_DRIVEN=n CONFIG_UART_INTERRUPT_DRIVEN=n
CONFIG_ZMK_USB=y CONFIG_ZMK_USB=y
CONFIG_MPU_ALLOW_FLASH_WRITE=y
CONFIG_NVS=y
CONFIG_SETTINGS_NVS=y
CONFIG_FLASH=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_FLASH_MAP=y

View File

@@ -1,15 +0,0 @@
&uart0 { status = "disabled"; };
&code_partition {
reg = <0x100 (DT_SIZE_M(2) - 0x100 - DT_SIZE_K(512))>;
};
&flash0 {
partitions {
storage_partition: partition@180000 {
reg = <0x180000 DT_SIZE_K(512)>;
read-only;
};
};
};

View File

@@ -1,12 +0,0 @@
if SHIELD_TESTER_RPI_PICO
config ZMK_KEYBOARD_NAME
default "ZMK Tester"
config ZMK_BLE
def_bool n
config SETTINGS
def_bool n
endif

View File

@@ -1,2 +0,0 @@
config SHIELD_TESTER_RPI_PICO
def_bool $(shields_list_contains,tester_rpi_pico)

View File

@@ -1,95 +0,0 @@
/*
* Copyright (c) 2025 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <physical_layouts.dtsi>
/ {
tester_position_map {
compatible = "zmk,physical-layout-position-map";
complete;
pinout_map: pinout_positions {
physical-layout = <&physical_layout0>;
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 25>;
};
inline_map: single_row_positions {
physical-layout = <&physical_layout1>;
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 25>;
};
};
physical_layout0: physical_layout_0 {
compatible = "zmk,physical-layout";
display-name = "Rpi Pico Pinout";
kscan = <&kscan0>;
transform = <&matrix_transform0>;
keys // w h x y rot rx ry
= <&key_physical_attrs 100 100 0 0 0 0 0>
, <&key_physical_attrs 100 100 0 100 0 0 0>
, <&key_physical_attrs 100 100 0 300 0 0 0>
, <&key_physical_attrs 100 100 0 400 0 0 0>
, <&key_physical_attrs 100 100 0 500 0 0 0>
, <&key_physical_attrs 100 100 0 600 0 0 0>
, <&key_physical_attrs 100 100 0 800 0 0 0>
, <&key_physical_attrs 100 100 0 900 0 0 0>
, <&key_physical_attrs 100 100 0 1000 0 0 0>
, <&key_physical_attrs 100 100 0 1100 0 0 0>
, <&key_physical_attrs 100 100 0 1300 0 0 0>
, <&key_physical_attrs 100 100 0 1400 0 0 0>
, <&key_physical_attrs 100 100 0 1500 0 0 0>
, <&key_physical_attrs 100 100 0 1600 0 0 0>
, <&key_physical_attrs 100 100 0 1800 0 0 0>
, <&key_physical_attrs 100 100 0 1900 0 0 0>
, <&key_physical_attrs 100 100 600 1900 0 0 0>
, <&key_physical_attrs 100 100 600 1800 0 0 0>
, <&key_physical_attrs 100 100 600 1600 0 0 0>
, <&key_physical_attrs 100 100 600 1500 0 0 0>
, <&key_physical_attrs 100 100 600 1400 0 0 0>
, <&key_physical_attrs 100 100 600 1300 0 0 0>
, <&key_physical_attrs 100 100 600 1100 0 0 0>
, <&key_physical_attrs 100 100 600 900 0 0 0>
, <&key_physical_attrs 100 100 600 800 0 0 0>
, <&key_physical_attrs 100 100 600 600 0 0 0>
;
};
physical_layout1: physical_layout_1 {
compatible = "zmk,physical-layout";
display-name = "Single Row";
// Single row of eighteen "keys", in ascending "Arduino" order.
keys // w h x y rot rx ry
= <&key_physical_attrs 100 100 0 0 0 0 0>
, <&key_physical_attrs 100 100 100 0 0 0 0>
, <&key_physical_attrs 100 100 200 0 0 0 0>
, <&key_physical_attrs 100 100 300 0 0 0 0>
, <&key_physical_attrs 100 100 400 0 0 0 0>
, <&key_physical_attrs 100 100 500 0 0 0 0>
, <&key_physical_attrs 100 100 600 0 0 0 0>
, <&key_physical_attrs 100 100 700 0 0 0 0>
, <&key_physical_attrs 100 100 800 0 0 0 0>
, <&key_physical_attrs 100 100 900 0 0 0 0>
, <&key_physical_attrs 100 100 1000 0 0 0 0>
, <&key_physical_attrs 100 100 1100 0 0 0 0>
, <&key_physical_attrs 100 100 1200 0 0 0 0>
, <&key_physical_attrs 100 100 1300 0 0 0 0>
, <&key_physical_attrs 100 100 1400 0 0 0 0>
, <&key_physical_attrs 100 100 1500 0 0 0 0>
, <&key_physical_attrs 100 100 1600 0 0 0 0>
, <&key_physical_attrs 100 100 1700 0 0 0 0>
, <&key_physical_attrs 100 100 1800 0 0 0 0>
, <&key_physical_attrs 100 100 1900 0 0 0 0>
, <&key_physical_attrs 100 100 2000 0 0 0 0>
, <&key_physical_attrs 100 100 2100 0 0 0 0>
, <&key_physical_attrs 100 100 2200 0 0 0 0>
, <&key_physical_attrs 100 100 2300 0 0 0 0>
, <&key_physical_attrs 100 100 2400 0 0 0 0>
, <&key_physical_attrs 100 100 2500 0 0 0 0>
;
};
};

View File

@@ -1,77 +0,0 @@
#include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
#define PIN_MACRO(name, pin) \
/ { \
macros { \
name: name { \
compatible = "zmk,behavior-macro"; \
wait-ms = <5>; \
tap-ms = <5>; \
#binding-cells = <0>; \
bindings = <&kp P &kp I &kp N &kp SPACE>, pin, <&kp ENTER>; \
}; \
}; \
};
PIN_MACRO(pin0, <&kp N0>)
PIN_MACRO(pin1, <&kp N1>)
PIN_MACRO(pin2, <&kp N2>)
PIN_MACRO(pin3, <&kp N3>)
PIN_MACRO(pin4, <&kp N4>)
PIN_MACRO(pin5, <&kp N5>)
PIN_MACRO(pin6, <&kp N6>)
PIN_MACRO(pin7, <&kp N7>)
PIN_MACRO(pin8, <&kp N8>)
PIN_MACRO(pin9, <&kp N9>)
PIN_MACRO(pin10, <&kp N1 &kp N0>)
PIN_MACRO(pin11, <&kp N1 &kp N1>)
PIN_MACRO(pin12, <&kp N1 &kp N2>)
PIN_MACRO(pin13, <&kp N1 &kp N3>)
PIN_MACRO(pin14, <&kp N1 &kp N4>)
PIN_MACRO(pin15, <&kp N1 &kp N5>)
PIN_MACRO(pin16, <&kp N1 &kp N6>)
PIN_MACRO(pin17, <&kp N1 &kp N7>)
PIN_MACRO(pin18, <&kp N1 &kp N8>)
PIN_MACRO(pin19, <&kp N1 &kp N9>)
PIN_MACRO(pin20, <&kp N2 &kp N0>)
PIN_MACRO(pin21, <&kp N2 &kp N1>)
PIN_MACRO(pin22, <&kp N2 &kp N2>)
PIN_MACRO(pin26, <&kp N2 &kp N6>)
PIN_MACRO(pin27, <&kp N2 &kp N7>)
PIN_MACRO(pin28, <&kp N2 &kp N8>)
/ {
keymap {
compatible = "zmk,keymap";
default_layer {
bindings = <&pin0
&pin1
&pin2
&pin3
&pin4
&pin5
&pin6
&pin7
&pin8
&pin9
&pin10
&pin11
&pin12
&pin13
&pin14
&pin15
&pin16
&pin17
&pin18
&pin19
&pin20
&pin21
&pin22
&pin26
&pin27
&pin28>;
};
};
};

View File

@@ -1,63 +0,0 @@
#include <dt-bindings/zmk/matrix_transform.h>
#include "tester_rpi_pico-layouts.dtsi"
&physical_layout0 {
transform = <&transform0>;
};
&physical_layout1 {
transform = <&transform0>;
};
/ {
chosen {
zmk,kscan = &kscan0;
zmk,physical-layout = &physical_layout0;
};
kscan0: kscan {
compatible = "zmk,kscan-gpio-direct";
wakeup-source;
debounce-press-ms = <10>;
debounce-release-ms = <10>;
input-gpios
= <&pico_header 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 11 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 12 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 17 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 18 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 19 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 20 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 21 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 22 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 26 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 27 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pico_header 28 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
;
};
transform0: keymap_transform {
compatible = "zmk,matrix-transform";
columns = <26>;
rows = <1>;
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(0,15) RC(0,16) RC(0,17) RC(0,18) RC(0,19)
RC(0,20) RC(0,21) RC(0,22) RC(0,23) RC(0,24) RC(0,25)
>;
};
};

View File

@@ -1,6 +0,0 @@
file_format: "1"
id: tester_rpi_pico
name: TesterRpiPico
type: shield
url: https://zmk.dev/docs/troubleshooting/hardware-issues
requires: [rpi_pico]

View File

@@ -7,20 +7,13 @@
#pragma once #pragma once
#include <zmk/events/position_state_changed.h> #include <zmk/events/position_state_changed.h>
#include <zephyr/sys/util.h>
#include <zephyr/devicetree.h>
#define ZMK_KEYMAP_LAYERS_FOREACH(_fn) \
COND_CODE_1(IS_ENABLED(CONFIG_ZMK_STUDIO), (DT_FOREACH_CHILD(DT_INST(0, zmk_keymap), _fn)), \
(DT_FOREACH_CHILD_STATUS_OKAY(DT_INST(0, zmk_keymap), _fn)))
#define ZMK_KEYMAP_LAYERS_FOREACH_SEP(_fn, _sep) \
COND_CODE_1(IS_ENABLED(CONFIG_ZMK_STUDIO), \
(DT_FOREACH_CHILD_SEP(DT_INST(0, zmk_keymap), _fn, _sep)), \
(DT_FOREACH_CHILD_STATUS_OKAY_SEP(DT_INST(0, zmk_keymap), _fn, _sep)))
#define ZMK_LAYER_CHILD_LEN_PLUS_ONE(node) 1 + #define ZMK_LAYER_CHILD_LEN_PLUS_ONE(node) 1 +
#define ZMK_KEYMAP_LAYERS_LEN (ZMK_KEYMAP_LAYERS_FOREACH(ZMK_LAYER_CHILD_LEN_PLUS_ONE) 0) #define ZMK_KEYMAP_LAYERS_LEN \
(COND_CODE_1( \
IS_ENABLED(CONFIG_ZMK_STUDIO), \
(DT_FOREACH_CHILD(DT_INST(0, zmk_keymap), ZMK_LAYER_CHILD_LEN_PLUS_ONE)), \
(DT_FOREACH_CHILD_STATUS_OKAY(DT_INST(0, zmk_keymap), ZMK_LAYER_CHILD_LEN_PLUS_ONE))) 0)
/** /**
* @brief A layer ID is a stable identifier to refer to a layer, regardless of ordering. * @brief A layer ID is a stable identifier to refer to a layer, regardless of ordering.

View File

@@ -74,7 +74,12 @@ static uint8_t keymap_layer_orders[ZMK_KEYMAP_LAYERS_LEN];
#define KEYMAP_VAR(_name, _opts, no_init) \ #define KEYMAP_VAR(_name, _opts, no_init) \
static _opts struct zmk_behavior_binding _name[ZMK_KEYMAP_LAYERS_LEN][ZMK_KEYMAP_LEN] = { \ static _opts struct zmk_behavior_binding _name[ZMK_KEYMAP_LAYERS_LEN][ZMK_KEYMAP_LEN] = { \
COND_CODE_0(no_init, (ZMK_KEYMAP_LAYERS_FOREACH_SEP(TRANSFORMED_LAYER, (, ))), (0))}; COND_CODE_0( \
no_init, \
(COND_CODE_1(IS_ENABLED(CONFIG_ZMK_STUDIO), \
(DT_INST_FOREACH_CHILD_SEP(0, TRANSFORMED_LAYER, (, ))), \
(DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP(0, TRANSFORMED_LAYER, (, ))))), \
(0))};
KEYMAP_VAR(zmk_keymap, COND_CODE_1(IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE), (), (const)), KEYMAP_VAR(zmk_keymap, COND_CODE_1(IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE), (), (const)),
IS_ENABLED(CONFIG_ZMK_STUDIO)) IS_ENABLED(CONFIG_ZMK_STUDIO))
@@ -84,14 +89,14 @@ KEYMAP_VAR(zmk_keymap, COND_CODE_1(IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE
KEYMAP_VAR(zmk_stock_keymap, const, 0) KEYMAP_VAR(zmk_stock_keymap, const, 0)
static char zmk_keymap_layer_names[ZMK_KEYMAP_LAYERS_LEN][CONFIG_ZMK_KEYMAP_LAYER_NAME_MAX_LEN] = { static char zmk_keymap_layer_names[ZMK_KEYMAP_LAYERS_LEN][CONFIG_ZMK_KEYMAP_LAYER_NAME_MAX_LEN] = {
ZMK_KEYMAP_LAYERS_FOREACH_SEP(LAYER_NAME, (, ))}; DT_INST_FOREACH_CHILD_SEP(0, LAYER_NAME, (, ))};
static uint32_t changed_layer_names = 0; static uint32_t changed_layer_names = 0;
#else #else
static const char *zmk_keymap_layer_names[ZMK_KEYMAP_LAYERS_LEN] = { static const char *zmk_keymap_layer_names[ZMK_KEYMAP_LAYERS_LEN] = {
ZMK_KEYMAP_LAYERS_FOREACH_SEP(LAYER_NAME, (, ))}; DT_INST_FOREACH_CHILD_SEP(0, LAYER_NAME, (, ))};
#endif #endif

View File

@@ -104,7 +104,7 @@ Note that documentation is still lacking for utilizing more than one peripheral
[petejohanson] contributed a fix to release held keys on peripheral disconnect [#1340](https://github.com/zmkfirmware/zmk/pull/1340), which makes scenarios where a split disconnects unexpectedly less painful. [petejohanson] contributed a fix to release held keys on peripheral disconnect [#1340](https://github.com/zmkfirmware/zmk/pull/1340), which makes scenarios where a split disconnects unexpectedly less painful.
[petejohanson] also improved [the `settings_reset` shield](/docs/troubleshooting/connection-issues#split-keyboard-parts-unable-to-pair) by making it clear bonds more reliably, and allow it to build for all boards in [#1879](https://github.com/zmkfirmware/zmk/pull/1879). [petejohanson] also improved [the `settings_reset` shield](/docs/troubleshooting/connection-issues#split-keyboard-halves-unable-to-pair) by making it clear bonds more reliably, and allow it to build for all boards in [#1879](https://github.com/zmkfirmware/zmk/pull/1879).
[petejohanson] and [xudongzheng] contributed additional split connectivity improvements, via using directed advertising in [#1913](https://github.com/zmkfirmware/zmk/pull/1913) and improving the robustness of central scanning in [#1912](https://github.com/zmkfirmware/zmk/pull/1912). [petejohanson] and [xudongzheng] contributed additional split connectivity improvements, via using directed advertising in [#1913](https://github.com/zmkfirmware/zmk/pull/1913) and improving the robustness of central scanning in [#1912](https://github.com/zmkfirmware/zmk/pull/1912).

View File

@@ -78,9 +78,7 @@ CONFIG_EC11=y
CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y
``` ```
Files ending with `_defconfig` use the same syntax as `.conf` files. They set the default configuration for the hardware, which is then overridden by anything in a `.conf` file. The list of available settings is determined by various files in ZMK whose names start with `Kconfig`. Files ending with `_defconfig` use the same syntax, but are intended for setting configuration specific to the hardware which users typically won't need to change. Note that options are _not_ prefixed with `CONFIG_` in these files.
The list of available settings is determined by various files in ZMK whose names start with `Kconfig`. Note that options are _not_ prefixed with `CONFIG_` in these files.
See [Zephyr's Kconfig documentation](https://docs.zephyrproject.org/3.5.0/build/kconfig/index.html) for more details on Kconfig files. See [Zephyr's Kconfig documentation](https://docs.zephyrproject.org/3.5.0/build/kconfig/index.html) for more details on Kconfig files.
@@ -112,9 +110,7 @@ Example: `CONFIG_FOO="foo"`
## Devicetree Files ## Devicetree Files
Various Devicetree files are combined to build a tree that describes the hardware for a keyboard. They are also used to define keymaps. A full primer on Devicetree can be found in the [Devicetree Overview page](../development/devicetree.md) -- a shorter summary of some of the points can be found below. Various Devicetree files are combined to build a tree that describes the hardware for a keyboard. They are also used to define keymaps.
### Devicetree Overview
Devicetree files use various file extensions. These indicate the purpose of the file, but they have no effect on how the file is processed. Common file extensions for Devicetree files include: Devicetree files use various file extensions. These indicate the purpose of the file, but they have no effect on how the file is processed. Common file extensions for Devicetree files include:
@@ -188,3 +184,88 @@ If the node you want to edit doesn't have a label, you can also write a new tree
}; };
}; };
``` ```
### Devicetree Property Types
These are some of the property types you will see most often when working with ZMK. [Zephyr's Devicetree bindings documentation](https://docs.zephyrproject.org/3.5.0/build/dts/bindings.html) provides more detailed information and a full list of types.
#### bool
True or false. To set the property to true, list it with no value. To set it to false, do not list it.
Example: `property;`
If a property has already been set to true and you need to override it to false, use the following command to delete the existing property:
```dts
/delete-property/ the-property-name;
```
#### int
A single integer surrounded by angle brackets. Also supports mathematical expressions.
Example: `property = <42>;`
#### string
Text surrounded by double quotes.
Example: `property = "foo";`
#### array
A list of integers surrounded by angle brackets and separated with spaces. Mathematical expressions can be used but must be surrounded by parenthesis.
Example: `property = <1 2 3 4>;`
Values can also be split into multiple blocks, e.g. `property = <1 2>, <3 4>;`
#### phandle
A single node reference surrounded by angle brackets.
Example: `property = <&label>`
#### phandles
A list of node references surrounded by angle brackets.
Example: `property = <&label1 &label2 &label3>`
#### phandle array
A list of node references and possibly numbers to associate with the node. Mathematical expressions can be used but must be surrounded by parenthesis.
Example: `property = <&none &mo 1>;`
Values can also be split into multiple blocks, e.g. `property = <&none>, <&mo 1>;`
See the documentation for "phandle-array" in [Zephyr's Devicetree bindings documentation](https://docs.zephyrproject.org/3.5.0/build/dts/bindings.html)
for more details on how parameters are associated with nodes.
#### GPIO array
This is just a phandle array. The documentation lists this as a different type to make it clear which properties expect an array of GPIOs.
Each item in the array should be a label for a GPIO node (the names of which differ between hardware platforms) followed by an index and configuration flags. See [Zephyr's GPIO documentation](https://docs.zephyrproject.org/3.5.0/hardware/peripherals/gpio.html) for a full list of flags.
Example:
```dts
some-gpios =
<&gpio0 0 GPIO_ACTIVE_HIGH>,
<&gpio0 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
;
```
#### path
A path to a node, either as a node reference or as a string.
Examples:
```dts
property = &label;
property = "/path/to/some/node";
```

View File

@@ -316,7 +316,7 @@ One possible way to do this is a 3x4 matrix where the direct GPIO keys are shift
compatible = "zmk,kscan-gpio-direct"; compatible = "zmk,kscan-gpio-direct";
// define 2 direct GPIOs here... // define 2 direct GPIOs here...
}; };
}; }
``` ```
## Mock Driver ## Mock Driver

View File

@@ -1,55 +0,0 @@
---
title: Persistent Settings
sidebar_label: Settings
---
ZMK uses [Zephyr's settings subsystem](https://docs.zephyrproject.org/3.5.0/services/settings/index.html) to store certain runtime settings in the "storage" partition of the controller's flash memory.
These settings will be saved after certain events and loaded on boot.
For instance, bond information for [paired Bluetooth hosts](../features/bluetooth.md) are stored in this partition so that users do not need to pair to each device again after the controller loses power.
Persisted settings are **not** cleared by flashing regular ZMK firmware: this is by design, since modifications like keymap changes should not cause users to lose their Bluetooth pairings.
They can only be cleared by setting a special Kconfig symbol or flashing a special firmware build as documented below.
Below is a non-comprehensive list of ZMK features that utilize persisted settings.
- [Bluetooth](../features/bluetooth.md): Stores pairing keys and MAC addresses associated with hosts, BT profile selected through the [keymap behavior](../keymaps/behaviors/bluetooth.md)[^1]
- [Split keyboards](../features/split-keyboards.md): Stores pairing keys and MAC addresses for wireless connection between parts
- [Output selection](../keymaps/behaviors/outputs.md): Stores last selected preferred endpoint changed through the keymap behavior[^1]
- [ZMK Studio](../features/studio.md): Stores any runtime keymap modifications and selected physical layouts after they are saved to the keyboard
- [Lighting](../features/lighting.md): Stores current brightness/color/effects for [underglow](../keymaps/behaviors/underglow.md) and [backlight](../keymaps/behaviors/backlight.md) features after being changed through their keymap behaviors[^1]
- [Power management](../keymaps/behaviors/power.md): Stores the state of the external power toggle as changed through the keymap behavior[^1]
[^1]: These are not saved immediately, but after `CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE` milliseconds in order to reduce potential wear on the flash memory.
## Kconfig
See [Configuration Overview](index.md) for instructions on how to change these settings.
Definition file: [zmk/app/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/Kconfig)
| Config | Type | Description | Default |
| ------------------------------------ | ---- | ----------------------------------------------------------------------------- | ------- |
| `CONFIG_ZMK_SETTINGS_RESET_ON_START` | bool | Clears all persistent settings from the keyboard at startup | n |
| `CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE` | int | Milliseconds to wait after a setting change before writing it to flash memory | 60000 |
## Clearing Persisted Settings
While regular ZMK builds will not cause any settings to be cleared upon flashing, flashing a build with `CONFIG_ZMK_SETTINGS_RESET_ON_START` enabled as documented above will cause the firmware to run a special procedure when the controller starts that clears the settings partition.
For end users, it is recommended to use a special [shield](../development/hardware-integration/index.mdx#boards--shields) named `settings_reset` to build a new firmware file, then flash that firmware.
See example for building firmware using this shield in the [troubleshooting docs](../troubleshooting/connection-issues.mdx#building-a-reset-firmware).
In both cases, regular, non-reset firmware will need to be flashed afterwards for normal operation.
:::warning
Since pairing information between split keyboards are also cleared with this process, you will need to clear settings on all parts of a split keyboard.
Please follow the full procedure described in [troubleshooting](../troubleshooting/connection-issues.mdx#split-keyboard-parts-unable-to-pair) so that the parts can pair correctly after clearing.
:::
:::tip
[ZMK Studio](../features/studio.md)-specific settings can be easily cleared using the "Restore Stock Settings" button in the header of the Studio client.
:::

View File

@@ -14,18 +14,13 @@ Definition file: [zmk/app/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/
### General ### General
| Config | Type | Description | Default | | Config | Type | Description | Default |
| --------------------------- | ------ | -------------------------------------------- | ------- | | ------------------------------------ | ------ | ----------------------------------------------------------------------------- | ------- |
| `CONFIG_ZMK_KEYBOARD_NAME` | string | The name of the keyboard (max 16 characters) | | | `CONFIG_ZMK_KEYBOARD_NAME` | string | The name of the keyboard (max 16 characters) | |
| `CONFIG_ZMK_SETTINGS_RESET_ON_START` | bool | Clears all persistent settings from the keyboard at startup | n |
| `CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE` | int | Milliseconds to wait after a setting change before writing it to flash memory | 60000 |
| `CONFIG_ZMK_WPM` | bool | Enable calculating words per minute | n | | `CONFIG_ZMK_WPM` | bool | Enable calculating words per minute | n |
| `CONFIG_HEAP_MEM_POOL_SIZE` | int | Size of the heap memory pool | 8192 | | `CONFIG_HEAP_MEM_POOL_SIZE` | int | Size of the heap memory pool | 8192 |
:::info
Because ZMK enables [the Zephyr setting](https://docs.zephyrproject.org/3.5.0/kconfig.html#CONFIG_BT_DEVICE_NAME_DYNAMIC) that allows for runtime modification of the device BT name,
changing `CONFIG_ZMK_KEYBOARD_NAME` requires [clearing the stored settings](./settings.md#clearing-persisted-settings) on the controller in order to take effect.
:::
### HID ### HID
:::warning[Refreshing the HID descriptor] :::warning[Refreshing the HID descriptor]

View File

@@ -50,7 +50,7 @@ It is also possible to build firmware locally on your computer by following the
For normal keyboards, follow the same flashing instructions as before to flash your updated firmware. For normal keyboards, follow the same flashing instructions as before to flash your updated firmware.
For [split keyboards](features/split-keyboards.md#building-and-flashing-firmware), only the central (left) side will need to be reflashed if you are just updating your keymap. For [split keyboards](features/split-keyboards.md#building-and-flashing-firmware), only the central (left) side will need to be reflashed if you are just updating your keymap.
More troubleshooting information for split keyboards can be found [here](troubleshooting/connection-issues.mdx#split-keyboard-parts-unable-to-pair). More troubleshooting information for split keyboards can be found [here](troubleshooting/connection-issues.mdx#split-keyboard-halves-unable-to-pair).
## Building Additional Keyboards ## Building Additional Keyboards

View File

@@ -1,322 +0,0 @@
---
title: Devicetree Overview
sidebar_label: Devicetree Overview
---
ZMK makes heavy usage of a type of [tree data structure](<https://en.wikipedia.org/wiki/Tree_(abstract_data_type)>) known as _devicetree_.
Devicetree is a _declarative_ way of describing almost everything about a Zephyr device, from the definition of keymaps and configuration of behaviors all the way to the internal storage partitions and architecture of the board's MCU.
This page is an introduction to devicetree for ZMK users and designers.
For further reading, refer to the [devicetree spec](https://github.com/devicetree-org/devicetree-specification/releases) and [Zephyr's documentation](https://docs.zephyrproject.org/latest/build/dts/index.html#devicetree-guide).
## Running Example
The following segment taken from a keymap will be used as a running example:
```dts
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
/ {
behaviors {
spc_ul: space_underscore {
compatible = "zmk,behavior-mod-morph";
#binding-cells = <0>;
bindings = <&kp SPACE>, <&kp UNDERSCORE>;
mods = <(MOD_LSFT|MOD_RSFT)>;
};
};
keymap {
compatible = "zmk,keymap";
default_layer {
bindings = <&spc_ul &kp Z &kp M &kp K>;
};
};
};
```
It may be helpful to open this page twice and leave one copy open at this example.
Note also that Devicetree uses C-style comments, i.e. `// ...` for line comments and `/* ... */` for block comments.
## Structure
A devicetree node has the general structure (parts within `[]` being optional)
```dts
[label:] name {
[properties]
[child nodes]
};
```
The root node of the devicetree always has the name `/`, i.e. is written as
```dts
/ {
[child nodes]
};
```
It is also the _only_ node which has the `/` character as a name. See the devicetree spec for permitted characters for node names.
After various preprocessing steps, all contents of the devicetree will be found within/under the root node.
If one node is found within another node, we say that the first node is a _child node_ of the second one. Similarly, one can also refer to a _grandchild node_, etc.
In the running example, `behaviors` and `keymap` are child nodes of the root node. `space_underscore` and `default_layer` are child nodes of `behaviors` and `keymap` respectively, making them both grandchild nodes of the root node.
### Properties
What properties a node may have varies drastically. Of the standard properties, there are two which are of particularly relevant to users and designers: `compatible` and `status`. Additional standard properties may be found in the [devicetree spec](https://github.com/devicetree-org/devicetree-specification/releases).
#### Property types
These are some of the property types you will see most often when working with ZMK. [Zephyr's Devicetree bindings documentation](https://docs.zephyrproject.org/3.5.0/build/dts/bindings.html) provides more detailed information and a full list of types.
##### bool
True or false. To set the property to true, list it with no value. To set it to false, do not list it.
Example: `property;`
If a property has already been set to true and you need to override it to false, use the following command to delete the existing property:
```dts
/delete-property/ the-property-name;
```
##### int
A single integer surrounded by angle brackets. Also supports mathematical expressions.
Example: `property = <42>;`
##### string
Text surrounded by double quotes.
Example: `property = "foo";`
##### array
A list of integers surrounded by angle brackets and separated with spaces. Mathematical expressions can be used but must be surrounded by parenthesis.
Example: `property = <1 2 3 4>;`
Values can also be split into multiple blocks, e.g. `property = <1 2>, <3 4>;`
##### phandle
A single node reference surrounded by angle brackets. Phandles will be explained in more detail in a [later section](#labels-and-phandles).
Example: `property = <&label>`
##### phandles
A list of node references surrounded by angle brackets. Phandles will be explained in more detail in a [later section](#labels-and-phandles).
Example: `property = <&label1 &label2 &label3>`
##### phandle array
A list of node references and possibly numbers to associate with the node. Mathematical expressions can be used but must be surrounded by parenthesis. Phandles will be explained in more detail in a [later section](#labels-and-phandles).
Example: `property = <&none &mo 1>;`
Values can also be split into multiple blocks, e.g. `property = <&none>, <&mo 1>;`
See the documentation for "phandle-array" in [Zephyr's Devicetree bindings documentation](https://docs.zephyrproject.org/3.5.0/build/dts/bindings.html)
for more details on how parameters are associated with nodes.
##### GPIO array
This is just a phandle array. The documentation lists this as a different type to make it clear which properties expect an array of GPIOs.
Each item in the array should be a label for a GPIO node (the names of which differ between hardware platforms) followed by an index and configuration flags. See [Zephyr's GPIO documentation](https://docs.zephyrproject.org/3.5.0/hardware/peripherals/gpio.html) for a full list of flags. Phandles and labels will be explained in more detail in a [later section](#labels-and-phandles).
Example:
```dts
some-gpios =
<&gpio0 0 GPIO_ACTIVE_HIGH>,
<&gpio0 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
;
```
##### path
A path to a node, either as a node reference or as a string. This will be explained in more detail in a [later section](#labels-and-phandles).
Examples:
```dts
property = &label;
property = "/path/to/some/node";
```
#### Compatible
The most important property that a node has is generally the `compatible` property. This property is used to map code to nodes. There are some special cases, such as the node named `chosen`, where the node name is used rather than a `compatible` property.
In the running example, `space_underscore` has the property `compatible = "zmk,behavior-mod-morph";`. The [ZMK's mod-morph behavior code](https://github.com/zmkfirmware/zmk/blob/main/app/src/behaviors/behavior_mod_morph.c#L7) acts on all nodes with `compatible` set to this value. The [ZMK keymap code](https://github.com/zmkfirmware/zmk/blob/main/app/src/keymap.c#L29) acts similarly for `compatible = "zmk,keymap";`.
The `compatible` property is also used to identify what additional properties a node may have. Any properties which are not one of the standard properties must be listed in a "devicetree bindings" file. These files will sometimes also include some additional information on the usage of the node.
ZMK keeps all of its devicetree bindings under the [`app/dts/bindings` directory](https://github.com/zmkfirmware/zmk/tree/main/app/dts/bindings).
The bindings file for `compatible = "zmk,behavior-mod-morph";` is [`app/dts/bindings/behaviors/zmk,behavior-mod-morph.yaml`](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-mod-morph.yaml).
```dts title="zmk,behavior-mod-morph.yaml"
# Copyright (c) 2020 The ZMK Contributors
# SPDX-License-Identifier: MIT
description: Mod Morph Behavior
compatible: "zmk,behavior-mod-morph"
include: zero_param.yaml
properties:
bindings:
type: phandle-array
required: true
mods:
type: int
required: true
keep-mods:
type: int
required: false
```
The properties the node can have are listed under `properties`. Some additional properties are imported from [zero_param.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zero_param.yaml). Bindings files are **the authority** on node properties, with our [documentation of said properties](https://zmk.dev/docs/config/behaviors#devicetree-7) sometimes omitting things like the `#binding-cells` property (imported from the previously mentioned file, describing the number of parameters that the behavior accepts). A full description of the bindings file syntax can be found in [Zephyr's documentation](https://docs.zephyrproject.org/3.5.0/build/dts/bindings-syntax.html).
Note that binding files can also specify properties for children, like the [`zmk,keymap.yaml` bindings file](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/zmk%2Ckeymap.yaml) specifying properties for layers in the keymap.
#### Status
The `status` property simply describes the status of a node. For ZMK users and designers, there are only two relevant values that this could be set to:
- `status = "disabled";` The node is disabled. Code should not take effect or make use of the node, but it can still be referenced by other parts of the devicetree.
- `status = "okay";` The default setting when not explicitly stated. The node is treated as "active". This property is generally only explicitly stated when overwriting a `status = "disabled";`.
How this property is used in practice will become more clear after the [devicetree preprocessing](#devicetree-preprocessing) section later on.
### Labels and Phandles
In addition to _names_, nodes can also have _labels_. For the ZMK user/designer, labels are arguably more important than node names. Whereas node names are used within code to access individual nodes, labels are used to reference other nodes from within devicetree itself. Such a reference is called a _phandle_, and can be thought of as similar to a pointer in C.
In the running example, `spc_ul` is the label given to the node `space_underscore`. The `bindings` property of the `default_layer` node is a "phandle-array" - an array of references to other nodes[^1]. Its first element is `&spc_ul` - a phandle to the node with label `spc_ul`, i.e. `space_underscore`. `&kp` is another example of a phandle. It points to a node [defined as below](https://github.com/zmkfirmware/zmk/blob/main/app/dts/behaviors/key_press.dtsi):
```dts
/ {
behaviors {
kp: key_press {
compatible = "zmk,behavior-key-press";
#binding-cells = <1>;
display-name = "Key Press";
};
};
};
```
This node is imported from a different file -- imports will be discussed later on. The `&kp` phandles found in the running example also show the concept of _parameters_ being passed to phandles. In this case, `Z`, `M`, and `K` are passed as parameters.
When ZMK needs to trigger a behavior found at a location in the keymap's `binding` property, it uses the phandle to identify the behavior node which needs to be called. It then executes the code determined by the `compatible` property of said node, passing in parameters while doing so[^2]. Depending on the behavior, another behavior phandle may need to be triggered, in which case the same process is used to identify the node and thus the parts of code which need to be executed.
Essentially, each layer in a keymap consists of an array of phandles pointing to various behaviors (alongside parameters) that were defined elsewhere. If you do not need to define the behavior node yourself, that just means ZMK has already defined it for you.
[^1]: A phandle array by definition also includes metadata, i.e. parameters. Strictly speaking, a list of phandles without metadata has type `phandles` rather than `phandle-array`. A property with a single phandle has type `phandle`.
[^2]: The number of parameters passed to the behavior code (and skipped over to find the next behavior phandle) is determined by the `#binding-cells` property mentioned above.
## Devicetree Preprocessing
Much of the complexity in `dts` files comes from preprocessing. The resulting devicetree after all preprocessing has finished [can be inspected](../troubleshooting/building-issues.md#devicetree-related-issues) for both GitHub Actions and local builds. For reasons that will make more sense later, your keymap and most of your customisations will be found near the bottom of the file.
Preprocessing comes from two sources:
1. The [C preprocessor](https://gcc.gnu.org/onlinedocs/cpp/) can be used within Devicetree Source (`dts`) files.
2. Devicetree has its own system for merging together, overwriting, and even deleting nodes and properties.
### C Preprocessor
An introduction to the C preprocessor is beyond the scope of this page. There are plenty of resources online for the unfamiliar reader to refer to.
However, some specific methods of how the C preprocessor is used in ZMK's devicetree files can be useful, to better understand how everything fits together.
The C preprocessor is used to import some nodes and other preprocessor definitions from other files. The lines
```dts
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
```
which are found at the top of the running example import the default behavior node definitions for ZMK, along with a list of preprocessor definitions. The parameters `Z`, `M`, and `K` (passed to the `&kp` phandle in the running example) are actually C preprocessor defines. For example, during preprocessing references to `Z` get turned into the number `0x07001D`, which is the number that gets passed to the ZMK host device (e.g. your computer) for it to then re-interpret as the letter "z".
The C preprocessor often gets leveraged by ZMK power users to reduce repetition in their keymap files. An example of this is the [macro-behavior convenience macro](../keymaps/behaviors/macros.md#convenience-c-macro). ZMK designers will also come across the `RC` macro used for matrix transformations, and make use of convenience defines such as `GPIO_ACTIVE_HIGH`.
### Devicetree Processing
A devicetree is almost always constructed from multiple files. These files are generally speaking:
- `.dtsi` files, which exist exclusively to be included via the C preprocessor (their contents get "pasted" at the location of the `#include` command) and are not used by the build sytem otherwise.
- A `.dts` file, which forms the "base" of the devicetree. A single one of these is always present when a devicetree is constructed. For ZMK, the `.dts` file contains the sections of the devicetree describing the [_board_](hardware-integration/index.mdx#what-is-a-board). This includes importing a number of `.dtsi` files describing the specific SoC that the board uses.
- Any number of `.overlay` files. These files can come from various sources, such as [shields](hardware-integration/index.mdx#what-is-a-shield) or [snippets](https://docs.zephyrproject.org/3.5.0/build/snippets/index.html). An overlay is applied to a `.dts` file by appending its contents to the end of the `.dts` file, i.e. it is placed at the bottom of the file. Multiple overlays are applied by doing so repeatedly in a particular order. Without going into the details of the exact order in which overlays are applied, it is enough to know that if you specify e.g. `shield: corne_left nice_view_adapter nice_view` in your `build.yaml`, then the overlays are applied left to right.
- A single `.keymap` file. This file being included is ZMK-specific, and is treated as the "final" `.overlay` file, appended after all other overlays.
#### Merging and overwriting nodes
When a node appears multiple times in the devicetree (after the files are imported and merged together), it gets merged into a single node as a preprocessing step. For example:
```dts
/ {
mn_ex: my_example_node {
property1 = <0>;
property2 = <2>;
};
};
/ {
my_example_node {
property2 = <1>;
property3 = <4>;
};
example2 {
property;
};
};
```
The second appearance of `my_example_node` has priority, thus its `property2` value will overwrite the first appearance. The two root nodes also get merged in the process. The resulting tree after processing would be
```dts
/ {
mn_ex: my_example_node {
property1 = <0>;
property2 = <1>;
property3 = <4>;
};
example2 {
property;
};
};
```
Labels do not get overwritten; a node can have multiple labels. Phandles can also be used to overwrite or add properties:
```dts
&mn_ex {
property4 = <2>;
};
```
The phandle approach is the recommended one, as one does not need to know the exact names of all the parent nodes with this approach. Crucially, when using phandles to overwrite or add properties, **the phandle must not be located within the root node**. It is instead placed outside of the tree entirely.
#### Special devicetree directives
Devicetree has some special directives that affect the tree. Relevant ones are:
- Nodes can be deleted with the /delete-node/ directive: `/delete-node/ &node_label;` outside of the root node.
- Properties can be deleted with the /delete-property/ directive: `/delete-property/ node-property;` inside the relevant node.
- `/omit-if-no-ref/` causes a node to be omitted from the resulting devicetree if there are no references/phandles to the node: `/omit-if-no-ref/ &node_label;`

View File

@@ -1,180 +0,0 @@
---
title: ZMK Events
sidebar_label: ZMK Events
---
ZMK makes use of events to decouple individual components such as behaviors and peripherals from the core functionality. For this purpose, ZMK has implemented its own event manager. This page is a (brief) overview of the functionality and methods exposed by the event manager, documenting its API. Its purpose is to aid module developers and contributors, such as for the development of [new behaviors](./new-behavior.mdx) or [new features](./module-creation.md). There is no value in reading this page as an end-user.
To see what events exist and what data they contain, it is best to view the corresponding [event header files](https://github.com/zmkfirmware/zmk/tree/main/app/include/zmk/events) directly. Including the event_manager header via `#include <zmk/event_manager.h>` is required for any interaction with the event system.
## Generic Events
The generic event type is `struct zmk_event_t`. This struct looks like this:
```c
typedef struct {
const struct zmk_event_type *event;
uint8_t last_listener_index;
} zmk_event_t;
```
In memory, the struct for a specific raised event `struct zmk_specific_thing_happened_event` **always** consists of a `zmk_event_t` struct **followed immediately afterwards** by the struct containing the data for the actual event.
```c
struct zmk_specific_thing_happened_event {
zmk_event_t header;
struct zmk_specific_thing_happened data;
};
```
The contents of `header.event` allows us to identify which type a particular event actually is, so that we may safely access its data in `data`. This is handled by the following function, which allows us to obtain the underlying data from a generic event:
```c
struct zmk_specific_thing_happened *as_specific_thing_happened(const zmk_event_t *eh);
```
This method takes in a pointer to a `zmk_event_t` (which is actually a pointer to a specific event, such as `zmk_specific_thing_happened_event`), and will return the underlying `zmk_specific_thing_happened` data struct if the `zmk_event_t` header indicates that the generic event pointer is indeed a pointer to a `zmk_specific_thing_happened_event`. If the type of the event does not match the function, then the function will return `NULL`. By convention, `zmk_event_t` pointer arguments are named `eh`, short for "event header".
This method will exist for every type of event, so for `zmk_layer_state_changed` we have `as_zmk_layer_state_changed`, etc. It is generated by a macro as part of the event declaration.
## Subscribing To Events
### Subscription and Listener
To subscribe to any events, you will first need to inform the event manager that you wish to add a new listener.
This is done by calling the `ZMK_LISTENER` macro:
```c
ZMK_LISTENER(combo, behavior_combo_listener);
```
This macro takes two parameters:
1. (`combo` in the example) This gives a name to the listener, for the event manager to refer back to it.
2. (`behavior_combo_listener` in the example) This is a [callback](<https://en.wikipedia.org/wiki/Callback_(computer_programming)>) that will be called whenever **any** event that the listener subscribes to occurs (if it is not handled by another listener with a higher priority). By convention, the callback should have the suffix `_listener`.
Once you have a listener set up, you can subscribe to individual events by calling the `ZMK_SUBSCRIPTION` macro:
```c
ZMK_SUBSCRIPTION(combo, zmk_keycode_state_changed);
```
The first parameter is the name of the listener created with `ZMK_LISTENER`, while the second is the name of the _struct_ that defines the event's data, which was declared in the corresponding header file. By convention the header file for an event will be named `specific_thing_happened`, with the struct named `zmk_specific_thing_happened`.
Of course, you will also need to import the corresponding event header at the top of your file.
### Listener Callback
The listener will be passed a raised `zmk_event_t` pointer (as described previously) as an argument, and should have `int` as its return type.
The listener should return one of three values (which are of type `int`) back to the event manager:
- `ZMK_EV_EVENT_BUBBLE`: Keep propagating the event `struct` to the next listener.
- `ZMK_EV_EVENT_HANDLED`: Stop propagating the event `struct` to the next listener. The event manager still owns the `struct`'s memory, so it will be `free`d automatically. Do **not** free the memory in this function.
- `ZMK_EV_EVENT_CAPTURED`: Stop propagating the event `struct` to the next listener. The event `struct`'s memory is now owned by your code, so the event manager will not free the event `struct` memory. Make sure your code will release or free the event at some point in the future. (Use the `ZMK_EVENT_*` macros described [below](#raising-events).)
If an error occurs during the listener call, it should return a negative value indicating the appropriate error code.
As mentioned previously, the same callback will be called when any event that is subscribed to occurs. To obtain the underlying event from the generic event passed to the listener, the previously described `as_zmk_specific_thing_happened` function should be used:
```c
int behavior_hold_tap_listener(const zmk_event_t *eh) {
if (as_zmk_position_state_changed(eh) != NULL) {
// it is a position_state_changed event, handle it with my_position_state_handler
return my_position_state_handler(eh);
} else if (as_zmk_keycode_state_changed(eh) != NULL) {
// it is a keycode_state_changed event, handle it with my_keycode_state_handler
return my_keycode_state_handler(eh);
}
return ZMK_EV_EVENT_BUBBLE;
}
```
The priority of the listeners is determined by the order in which the linker links the files. Within ZMK, this is the order of the corresponding files in `CMakeLists.txt`. External modules targeting `app` are linked prior to any files within ZMK itself, making them the highest priority. It is thus the module maintainer's responsibility to both ensure that their module does not cause issues by being first in the listener queue. For example, [hold-tap](../keymaps/behaviors/hold-tap.mdx) is the first listener to `position_state_changed`, and may behave inconsistently if a behavior defined in a module listens to `position_state_changed` and invokes a `hold-tap` (e.g. by calling `zmk_behavior_invoke_event` with a `hold-tap` as the binding).
In addition, because modules listen to the events first, they should _never_ capture/handle an event defined in ZMK without releasing it later. Unless it is unavoidable, it is recommended to bubble events whenever possible.
When considering multiple modules, priority is determined by the order in which the modules are present in the user's `west.yml`. Hence there should be no order dependencies between modules, only within a module.
## Raising Events
There are several different ways to raise events, with slight differences between them.
- `int raise_zmk_specific_thing_happened(struct zmk_specific_thing_happened event)`: This function will take an event data structure, add a header to it, and then start handling the event with the first registered event listener.
The following macros can also be used for advanced use cases. These will each take in an event `ev` which already consists of the header & data combination, i.e. `ev` has the type `struct zmk_specific_thing_happened_event`.
- `ZMK_EVENT_RAISE(ev)`: Start handling this event (`ev`) with the first registered event listener.
- `ZMK_EVENT_RAISE_AFTER(ev, mod)`: Start handling this event (`ev`) after the event is captured by the named [event listener](#subscription-and-listener) (`mod`). The named event listener will be skipped as well.
- `ZMK_EVENT_RAISE_AT(ev, mod)`: Start handling this event (`ev`) at the named [event listener](#subscription-and-listener) (`mod`). The named event listener is the first handler to be invoked.
- `ZMK_EVENT_RELEASE(ev)`: Continue handling this event (`ev`) at the next registered event listener.
- `ZMK_EVENT_FREE(ev)`: Free the memory associated with the event (`ev`).
Optionally, some events may also declare an extra function similar to `raise_zmk_specific_thing_happened` named `raise_specific_thing_happened`. This function will take in some or all of the components of the `zmk_specific_thing_happened` struct, and then create the struct (perhaps with some additional data obtained from elsewhere) before calling `raise_zmk_specific_thing_happened`. For example:
```c
static inline int raise_layer_state_changed(uint8_t layer, bool state) {
return raise_zmk_layer_state_changed(
(struct zmk_layer_state_changed){
.layer = layer,
.state = state,
.timestamp = k_uptime_get()
}
);
}
```
## Creating New Events
### Header File
Your event's header file should have four things:
- A copyright comment
- Any required header includes (along with `#pragma once`)
- The event's data struct
- The macro `ZMK_EVENT_DECLARE`, called with the name of your event's data struct.
For example:
```c
/*
- Copyright (c) 2021 The ZMK Contributors
-
- SPDX-License-Identifier: MIT
*/
#pragma once
#include <zephyr/kernel.h>
#include <zmk/endpoints_types.h>
#include <zmk/event_manager.h>
struct zmk_endpoint_changed {
struct zmk_endpoint_instance endpoint;
};
ZMK_EVENT_DECLARE(zmk_endpoint_changed);
```
### Code File
Your event's code file merely needs three things:
- A copyright comment
- Any required header files (including that of your event)
- The macro `ZMK_EVENT_IMPL`, called with the name of your event's data struct.
```c
/*
* Copyright (c) 2021 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <zephyr/kernel.h>
#include <zmk/events/endpoint_changed.h>
ZMK_EVENT_IMPL(zmk_endpoint_changed);
```

View File

@@ -166,7 +166,7 @@ Finally, we will list the `wakeup_scan` device in an additional configuration se
Here are the properties for the node: Here are the properties for the node:
- The `compatible` property for the node must be `zmk,soft-off-wakeup-sources`. - The `compatible` property for the node must be `zmk,soft-off-wakeup-sources`.
- The `wakeup-sources` property is a [phandle array](../devicetree.md#property-types) pointing to all the devices that should be enabled during the shutdown process to be sure they can later wake the keyboard. - The `wakeup-sources` property is a [phandle array](../../config/index.md#devicetree-property-types) pointing to all the devices that should be enabled during the shutdown process to be sure they can later wake the keyboard.
:::tip :::tip
If you add your kscan to the `wakeup-sources` array, then your keyboard will wake upon pressing any key in your kscan. Essentially, this causes `&soft_off` to behave like a behavior that puts the keyboard in deep sleep. If you choose to do so, then you can omit everything aside from the `soft_off_wakers` node. If you add your kscan to the `wakeup-sources` array, then your keyboard will wake upon pressing any key in your kscan. Essentially, this causes `&soft_off` to behave like a behavior that puts the keyboard in deep sleep. If you choose to do so, then you can omit everything aside from the `soft_off_wakers` node.

View File

@@ -99,14 +99,14 @@ command. These are invoked whenever a new build system is generated. To add
permanent arguments, set the `build.cmake-args` configuration option. permanent arguments, set the `build.cmake-args` configuration option.
```sh ```sh
west config build.cmake-args -- -DSHIELD=kyria_left west config build.cmake-args -- -DSHIELD=kyra_left
``` ```
Multiple arguments are added by assigning a string to the configuration option: Multiple arguments are added by assigning a string to the configuration option:
```sh ```sh
west config build.cmake-args \ west config build.cmake-args \
-- "-DSHIELD=kyria_left -DZMK_CONFIG=/absolute/path/to/zmk-config" -- "-DSHIELD=kyra_left -DZMK_CONFIG=/absolute/path/to/zmk-config"
``` ```
### Pristine Building ### Pristine Building

View File

@@ -203,10 +203,10 @@ west zephyr-export
pip install -r zephyr/scripts/requirements-base.txt pip install -r zephyr/scripts/requirements-base.txt
``` ```
If you are going to build firmware with [ZMK Studio](../../../features/studio.md), also install `requirements-extras.txt` dependencies: If you are going to build firmware with [ZMK Studio](../../../features/studio.md), also install `requirements-extra.txt` dependencies:
```sh ```sh
pip install -r zephyr/scripts/requirements-extras.txt pip install -r zephyr/scripts/requirements-extra.txt
``` ```
</TabItem> </TabItem>
@@ -301,10 +301,10 @@ west zephyr-export
pip3 install --user -r zephyr/scripts/requirements-base.txt pip3 install --user -r zephyr/scripts/requirements-base.txt
``` ```
If you are going to build firmware with [ZMK Studio](../../../features/studio.md), also install `requirements-extras.txt` dependencies: If you are going to build firmware with [ZMK Studio](../../../features/studio.md), also install `requirements-extra.txt` dependencies:
```sh ```sh
pip3 install -r zephyr/scripts/requirements-extras.txt pip3 install -r zephyr/scripts/requirements-extra.txt
``` ```
</TabItem> </TabItem>
@@ -317,10 +317,10 @@ pip3 install -r zephyr/scripts/requirements-extras.txt
pip install -r zephyr/scripts/requirements-base.txt pip install -r zephyr/scripts/requirements-base.txt
``` ```
If you are going to build firmware with [ZMK Studio](../../../features/studio.md), also install `requirements-extras.txt` dependencies: If you are going to build firmware with [ZMK Studio](../../../features/studio.md), also install `requirements-extra.txt` dependencies:
```sh ```sh
pip install -r zephyr/scripts/requirements-extras.txt pip install -r zephyr/scripts/requirements-extra.txt
``` ```
</TabItem> </TabItem>
@@ -332,10 +332,10 @@ pip install -r zephyr/scripts/requirements-extras.txt
pip3 install -r zephyr/scripts/requirements-base.txt pip3 install -r zephyr/scripts/requirements-base.txt
``` ```
If you are going to build firmware with [ZMK Studio](../../../features/studio.md), also install `requirements-extras.txt` dependencies: If you are going to build firmware with [ZMK Studio](../../../features/studio.md), also install `requirements-extra.txt` dependencies:
```sh ```sh
pip3 install -r zephyr/scripts/requirements-extras.txt pip3 install -r zephyr/scripts/requirements-extra.txt
``` ```
</TabItem> </TabItem>

View File

@@ -215,7 +215,7 @@ Including `zmk/event_manager.h` is required for the following dependencies to fu
- `zmk/events/keycode_state_changed.h`: Keycode events' state (on/off), usage page, keycode value, modifiers, and timestamps - `zmk/events/keycode_state_changed.h`: Keycode events' state (on/off), usage page, keycode value, modifiers, and timestamps
- `zmk/events/modifiers_state_changed.h`: Modifier events' state (on/off) and modifier value - `zmk/events/modifiers_state_changed.h`: Modifier events' state (on/off) and modifier value
Events can be used similarly to hardware interrupts. See [Events](events.md) for more information on using events. Events can be used similarly to hardware interrupts, through the use of [listeners](#listeners-and-subscriptions).
###### Listeners and subscriptions ###### Listeners and subscriptions
@@ -223,13 +223,31 @@ The condensed form of lines 192-225 of the tap-dance driver, shown below, does a
```c title="app/src/behaviors/behavior_tap_dance.c (Lines 192-197, 225)" ```c title="app/src/behaviors/behavior_tap_dance.c (Lines 192-197, 225)"
static int tap_dance_position_state_changed_listener(const zmk_event_t *eh); static int tap_dance_position_state_changed_listener(const zmk_event_t *eh);
ZMK_LISTENER(behavior_tap_dance, tap_dance_position_state_changed_listener); ZMK_LISTENER(behavior_tap_dance, tap_dance_position_state_changed_listener);
ZMK_SUBSCRIPTION(behavior_tap_dance, zmk_position_state_changed); ZMK_SUBSCRIPTION(behavior_tap_dance, zmk_position_state_changed);
static int tap_dance_position_state_changed_listener(const zmk_event_t *eh){ static int tap_dance_position_state_changed_listener(const zmk_event_t *eh){
// Do stuff... // Do stuff...
} }
``` ```
Listeners, defined by the `ZMK_LISTENER(mod, cb)` function, take in a listener name (`mod`) and a callback function (`cb`) as their parameters. On the other hand subscriptions are defined by the `ZMK_SUBSCRIPTION(mod, ev_type)`, and determine what kind of event (`ev_type`) should invoke the callback function from the listener. In the tap-dance example, this listener executes code depending on a `zmk_position_state_changed` event, or simply, a change in key position. Other types of ZMK events can be found as the name of the `struct` inside each of the files located at `app/include/zmk/events/<Event Type>.h`. All control paths in a listener should `return` one of the [`ZMK_EV_EVENT_*` values](#return-values), which are shown below.
###### `return` values:
- `ZMK_EV_EVENT_BUBBLE`: Keep propagating the event `struct` to the next listener.
- `ZMK_EV_EVENT_HANDLED`: Stop propagating the event `struct` to the next listener. The event manager still owns the `struct`'s memory, so it will be `free`d automatically. Do **not** free the memory in this function.
- `ZMK_EV_EVENT_CAPTURED`: Stop propagating the event `struct` to the next listener. The event `struct`'s memory is now owned by your code, so the event manager will not free the event `struct` memory. Make sure your code will release or free the event at some point in the future. (Use the [`ZMK_EVENT_*` macros](#macros) described below.)
###### Macros:
- `ZMK_EVENT_RAISE(ev)`: Start handling this event (`ev`) with the first registered event listener.
- `ZMK_EVENT_RAISE_AFTER(ev, mod)`: Start handling this event (`ev`) after the event is captured by the named [event listener](#listeners-and-subscriptions) (`mod`). The named event listener will be skipped as well.
- `ZMK_EVENT_RAISE_AT(ev, mod)`: Start handling this event (`ev`) at the named [event listener](#listeners-and-subscriptions) (`mod`). The named event listener is the first handler to be invoked.
- `ZMK_EVENT_RELEASE(ev)`: Continue handling this event (`ev`) at the next registered event listener.
- `ZMK_EVENT_FREE(ev)`: Free the memory associated with the event (`ev`).
#### `BEHAVIOR_DT_INST_DEFINE` #### `BEHAVIOR_DT_INST_DEFINE`
`BEHAVIOR_DT_INST_DEFINE` is a special ZMK macro. It forwards all the parameters to Zephyr's `DEVICE_DT_INST_DEFINE` macro to define the driver instance, then it adds the driver to a list of ZMK behaviors so they can be found by `zmk_behavior_get_binding()`. `BEHAVIOR_DT_INST_DEFINE` is a special ZMK macro. It forwards all the parameters to Zephyr's `DEVICE_DT_INST_DEFINE` macro to define the driver instance, then it adds the driver to a list of ZMK behaviors so they can be found by `zmk_behavior_get_binding()`.

View File

@@ -68,7 +68,7 @@ sudo tio /dev/ttyACM0
</TabItem> </TabItem>
<TabItem value="win"> <TabItem value="win">
On Windows, you can use [PuTTY](https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html). Once installed, use Device Manager to figure out which COM port your controller is communicating on (listed under 'Ports (COM & LPT)') and specify that as the 'Serial line' in PuTTY. On Windows, you can use [PuTTY](https://www.putty.org/). Once installed, use Device Manager to figure out which COM port your controller is communicating on (listed under 'Ports (COM & LPT)') and specify that as the 'Serial line' in PuTTY.
![Controller COM port](../assets/usb-logging/com.jpg) ![Controller COM port](../assets/usb-logging/com.jpg)
@@ -86,13 +86,7 @@ You can connect to the device with [tio](https://tio.github.io/) (can be install
sudo tio /dev/tty.usbmodem14401 sudo tio /dev/tty.usbmodem14401
``` ```
Alternatively, `cu` should be preinstalled (see `man cu` for usage instructions): You should see tio printing `Disconnected` or `Connected` when you disconnect or reconnect the USB cable.
```sh
sudo cu -l /dev/tty.usbmodem14401
```
You should see the console printing `Disconnected` or `Connected` when you disconnect or reconnect the USB cable.
</TabItem> </TabItem>
</Tabs> </Tabs>

View File

@@ -87,7 +87,7 @@ Similar to how [bluetooth profiles](bluetooth.md) are managed between the keyboa
In practice, this means that your split keyboard parts will automatically pair and work the first time they are all on at the same time. In practice, this means that your split keyboard parts will automatically pair and work the first time they are all on at the same time.
However, if this process somehow went wrong or you used controllers in a different split keyboard configuration before, you will need to explicitly clear the stored bond information so that the parts can pair properly. However, if this process somehow went wrong or you used controllers in a different split keyboard configuration before, you will need to explicitly clear the stored bond information so that the parts can pair properly.
For this, please follow [the specified procedure](../troubleshooting/connection-issues.mdx#split-keyboard-parts-unable-to-pair) in the troubleshooting section. For this, please follow [the specified procedure](../troubleshooting/connection-issues.mdx#split-keyboard-halves-unable-to-pair) in the troubleshooting section.
:::warning :::warning
If the central keyboard part is either advertising for a pairing or waiting for disconnected peripherals, it will consume more power and drain batteries faster. If the central keyboard part is either advertising for a pairing or waiting for disconnected peripherals, it will consume more power and drain batteries faster.

View File

@@ -37,7 +37,7 @@ Here is a table describing the action for each define:
- Parameter #2: Only applies to `BL_SET`and is the brightness value - Parameter #2: Only applies to `BL_SET`and is the brightness value
:::note[Backlight settings persistence] :::note[Backlight settings persistence]
The backlight settings that are changed via the `&bl` behavior will be [saved to flash storage](../../config/settings.md) and hence persist across restarts and firmware flashes. The backlight settings that are changed via the `&bl` behavior will be saved to flash storage and hence persist across restarts and firmware flashes.
They will also override the start values set by [`CONFIG_ZMK_BACKLIGHT_*_START` settings](../../config/lighting.md#kconfig-1). They will also override the start values set by [`CONFIG_ZMK_BACKLIGHT_*_START` settings](../../config/lighting.md#kconfig-1).
However the settings will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory. However the settings will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory.
::: :::

View File

@@ -48,7 +48,7 @@ Here is a table describing the command for each define:
| `BT_DISC` | Disconnect from the 0-indexed profile by number, if it's currently connected and inactive; must include a number as an argument in the keymap to work correctly, e.g. `BT_DISC 0`. | | `BT_DISC` | Disconnect from the 0-indexed profile by number, if it's currently connected and inactive; must include a number as an argument in the keymap to work correctly, e.g. `BT_DISC 0`. |
:::note[Selected profile persistence] :::note[Selected profile persistence]
The profile that is selected by the `BT_SEL`/`BT_PRV`/`BT_NXT` actions will be [saved to flash storage](../../config/settings.md) and hence persist across restarts and firmware flashes. The profile that is selected by the `BT_SEL`/`BT_PRV`/`BT_NXT` actions will be saved to flash storage and hence persist across restarts and firmware flashes.
However it will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory. However it will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory.
::: :::

View File

@@ -66,7 +66,7 @@ By default, layer-tap is configured with the ["tap-preferred" `flavor`](#interru
Example: Example:
```dts ```dts
&lt 1 A &lt 3 SPACE
``` ```
### Configuration ### Configuration

View File

@@ -45,7 +45,7 @@ The output selection behavior changes the preferred output on press.
- Parameter #1: Command, e.g. `OUT_BLE` - Parameter #1: Command, e.g. `OUT_BLE`
:::note[Output selection persistence] :::note[Output selection persistence]
The endpoint that is selected by the `&out` behavior will be [saved to flash storage](../../config/settings.md) and hence persist across restarts and firmware flashes. The endpoint that is selected by the `&out` behavior will be saved to flash storage and hence persist across restarts and firmware flashes.
However it will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory. However it will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory.
::: :::

View File

@@ -44,7 +44,7 @@ Here is a table describing the command for each define:
- Parameter#1: Command, e.g `EP_ON` - Parameter#1: Command, e.g `EP_ON`
:::note[External power state persistence] :::note[External power state persistence]
The on/off state that is set by the `&ext_power` behavior will be [saved to flash storage](../../config/settings.md) and hence persist across restarts and firmware flashes. The on/off state that is set by the `&ext_power` behavior will be saved to flash storage and hence persist across restarts and firmware flashes.
However it will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory. However it will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory.
::: :::

View File

@@ -56,7 +56,7 @@ Value Limits:
::: :::
:::note[RGB settings persistence] :::note[RGB settings persistence]
The RGB settings that are changed via the `&rgb_ug` behavior will be [saved to flash storage](../../config/settings.md) and hence persist across restarts and firmware flashes. The RGB settings that are changed via the `&rgb_ug` behavior will be saved to flash storage and hence persist across restarts and firmware flashes.
They will also override the start values set by [`CONFIG_ZMK_RGB_*_START` settings](../../config/lighting.md#kconfig). They will also override the start values set by [`CONFIG_ZMK_RGB_*_START` settings](../../config/lighting.md#kconfig).
However the settings will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory. However the settings will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory.
::: :::

View File

@@ -8,15 +8,14 @@ description: Troubleshooting wireless connection issues of ZMK devices.
[USB logging](../development/usb-logging.mdx) can be very helpful for diagnosing issues with ZMK. However, when connected to USB your ZMK device will output to USB by default. To troubleshoot wireless connection issues using logging, you will need to [change the preferred output endpoint](../keymaps/behaviors/outputs.md). [USB logging](../development/usb-logging.mdx) can be very helpful for diagnosing issues with ZMK. However, when connected to USB your ZMK device will output to USB by default. To troubleshoot wireless connection issues using logging, you will need to [change the preferred output endpoint](../keymaps/behaviors/outputs.md).
::: :::
## Split Keyboard Parts Unable to Pair ## Split Keyboard Halves Unable to Pair
[Split keyboard](../features/split-keyboards.md) parts will automatically pair with one another, but there are some cases where this breaks and the pairing needs to be reset, for example: [Split keyboard](../features/split-keyboards.md) halves will automatically pair with one another, but there are some cases where this breaks, and the pairing needs to be reset, for example:
- Changing which part is the central. - Switching which halves are the central/peripheral.
- Replacing the controller for one of the parts. - Replacing the controller for one of the halves.
These issues can be resolved by flashing a settings reset firmware to both controllers to clear the stored pairing information. These issues can be resolved by flashing a settings reset firmware to both controllers.
See [persistent settings documentation](../config/settings.md) for more information.
:::warning :::warning
@@ -46,16 +45,16 @@ If you use a [local development environment](../development/local-toolchain/setu
### Reset Split Keyboard Procedure ### Reset Split Keyboard Procedure
Perform the following steps to reset **_all_** parts of your split keyboard: Perform the following steps to reset **_both_** halves of your split keyboard:
1. Put each part of the split keyboard into bootloader mode. 1. Put each half of the split keyboard into bootloader mode.
1. Flash one of the parts of the split with the settings reset firmware. 1. Flash one of the halves of the split with the settings reset firmware.
1. Repeat step 2 with the other parts of the split keyboard. 1. Repeat step 2 with the other half of the split keyboard.
1. Flash the actual image for each part of the split keyboard (e.g `my_board_left.uf2` to the left half, `my_board_right.uf2` to the right half). 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).
If the central and a peripheral has not paired after completing these steps, it can help to reset the central and the peripheral at around 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, or turning both off then on with a power switch. 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.
Once this is done, you should remove/forget the keyboard on any paired host device and pair it again, since the pairing information for them will also have been cleared from the keyboard. Once this is done, you can remove/forget the keyboard on each host device and pair it again.
:::info :::info

View File

@@ -232,7 +232,7 @@ Please refer to [the pairing section in the split keyboards documentation](featu
:::note :::note
If you have issues connecting the halves, make sure that both sides are getting powered properly through USB or batteries, then follow the If you have issues connecting the halves, make sure that both sides are getting powered properly through USB or batteries, then follow the
[recommended troubleshooting procedure](troubleshooting/connection-issues.mdx#split-keyboard-parts-unable-to-pair). This is typically necessary if you [recommended troubleshooting procedure](troubleshooting/connection-issues.mdx#split-keyboard-halves-unable-to-pair). This is typically necessary if you
swapped firmware sides between controllers, like flashing left side firmware to the same controller after flashing the right, or vice versa. swapped firmware sides between controllers, like flashing left side firmware to the same controller after flashing the right, or vice versa.
::: :::

View File

@@ -1,6 +1,34 @@
const { execSync } = require("child_process");
const path = require("path"); const path = require("path");
const theme = require("./src/theme/prism/themes/github"); const theme = require("./src/theme/prism/themes/github");
const darkTheme = require("./src/theme/prism/themes/github-dark-dimmed"); const darkTheme = require("./src/theme/prism/themes/github-dark-dimmed");
const { releaseVersions } = require("./zmk-release-versions.json");
const gitBranch =
process.env.BRANCH ||
execSync("git branch --show-current", { encoding: "utf-8" }).trim();
const isDevelopmentVersion =
gitBranch === "main" || !/^v\d+\.\d+-branch$/.test(gitBranch);
const versionNavbarItems = [
{
label: "Pre-Release",
description: "Current active development branch (main)",
href: "https://zmk.dev/docs/",
},
...releaseVersions.map((r) => ({
label: "v" + r,
description: "Stable release v" + r,
href: `https://v${r.replaceAll(".", "-")}-branch.zmk.dev/docs/`,
})),
];
const versionDropDownLabel = (
isDevelopmentVersion
? versionNavbarItems[0]
: versionNavbarItems.find((item) => {
return item.label === gitBranch.replace("-branch", "");
})
).label;
module.exports = { module.exports = {
title: "ZMK Firmware", title: "ZMK Firmware",
@@ -11,6 +39,10 @@ module.exports = {
trailingSlash: "false", trailingSlash: "false",
organizationName: "zmkfirmware", // Usually your GitHub org/user name. organizationName: "zmkfirmware", // Usually your GitHub org/user name.
projectName: "zmk", // Usually your repo name. projectName: "zmk", // Usually your repo name.
customFields: {
isDevelopmentVersion,
releaseVersions,
},
plugins: [ plugins: [
"@docusaurus/theme-mermaid", "@docusaurus/theme-mermaid",
path.resolve(__dirname, "src/docusaurus-tree-sitter-plugin"), path.resolve(__dirname, "src/docusaurus-tree-sitter-plugin"),
@@ -51,16 +83,29 @@ module.exports = {
label: "Docs", label: "Docs",
position: "left", position: "left",
}, },
{ to: "blog", label: "Blog", position: "left" }, isDevelopmentVersion
? { to: "blog", label: "Blog", position: "left" }
: { href: "https://zmk.dev/blog", label: "Blog", position: "left" },
{
type: "dropdown",
label: "Tools",
position: "left",
items: [
{ {
to: "power-profiler", to: "power-profiler",
label: "Power Profiler", label: "Power Profiler",
position: "left",
}, },
{ {
to: "keymap-upgrader", to: "keymap-upgrader",
label: "Keymap Upgrader", label: "Keymap Upgrader",
position: "left", },
],
},
{
type: "dropdown",
label: versionDropDownLabel,
position: "right",
items: versionNavbarItems,
}, },
{ {
href: "https://zmk.studio/", href: "https://zmk.studio/",
@@ -69,7 +114,8 @@ module.exports = {
}, },
{ {
href: "https://github.com/zmkfirmware/zmk", href: "https://github.com/zmkfirmware/zmk",
label: "GitHub", "aria-label": "ZMK GitHub Repository",
className: "header-github-link",
position: "right", position: "right",
}, },
], ],

850
docs/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -15,9 +15,9 @@
"typecheck": "tsc" "typecheck": "tsc"
}, },
"dependencies": { "dependencies": {
"@docusaurus/core": "^3.8.1", "@docusaurus/core": "^3.8.0",
"@docusaurus/preset-classic": "^3.8.1", "@docusaurus/preset-classic": "^3.8.0",
"@docusaurus/theme-mermaid": "^3.8.1", "@docusaurus/theme-mermaid": "^3.8.0",
"@fortawesome/fontawesome-svg-core": "^6.7.1", "@fortawesome/fontawesome-svg-core": "^6.7.1",
"@fortawesome/free-solid-svg-icons": "^6.7.1", "@fortawesome/free-solid-svg-icons": "^6.7.1",
"@fortawesome/react-fontawesome": "^0.2.0", "@fortawesome/react-fontawesome": "^0.2.0",

View File

@@ -130,7 +130,6 @@ module.exports = {
"config/layout", "config/layout",
"config/kscan", "config/kscan",
"config/power", "config/power",
"config/settings",
"config/split", "config/split",
"config/system", "config/system",
"config/studio", "config/studio",
@@ -209,10 +208,8 @@ module.exports = {
}, },
"development/module-creation", "development/module-creation",
"development/usb-logging", "development/usb-logging",
"development/devicetree",
"development/studio-rpc-protocol", "development/studio-rpc-protocol",
"development/new-behavior", "development/new-behavior",
"development/events",
], ],
}, },
], ],

View File

@@ -23,6 +23,21 @@
--docusaurus-highlighted-code-line-bg: rgb(255 255 255 / 8%); --docusaurus-highlighted-code-line-bg: rgb(255 255 255 / 8%);
} }
.header-github-link::before {
content: "";
width: 24px;
height: 24px;
display: flex;
background-color: var(--ifm-navbar-link-color);
mask-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E");
transition: background-color var(--ifm-transition-fast)
var(--ifm-transition-timing-default);
}
.header-github-link:hover::before {
background-color: var(--ifm-navbar-link-hover-color);
}
.docusaurus-highlight-code-line { .docusaurus-highlight-code-line {
display: block; display: block;
margin: 0 calc(-1 * var(--ifm-pre-padding)); margin: 0 calc(-1 * var(--ifm-pre-padding));

View File

@@ -0,0 +1,60 @@
import { type ReactNode } from "react";
import clsx from "clsx";
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
import Link from "@docusaurus/Link";
import { ThemeClassNames } from "@docusaurus/theme-common";
import type { Props } from "@theme/DocVersionBanner";
function ZMKReleaseLink({ version }: { version: string }): ReactNode {
return (
<Link
href={`https://v${version.replaceAll(".", "-")}-branch.zmk.dev/docs/`}
>
v{version}
</Link>
);
}
function DevWarningBanner({
className,
latestVersion,
}: Props & { latestVersion: string }): ReactNode {
return (
<div
className={clsx(
className,
ThemeClassNames.docs.docVersionBanner,
"alert alert--warning margin-bottom--md"
)}
role="alert"
>
You're viewing the documentation for the development version of ZMK. You
may want the latest release <ZMKReleaseLink version={latestVersion} />.
</div>
);
}
export default function DocVersionBanner({ className }: Props): ReactNode {
const {
siteConfig: { customFields },
} = useDocusaurusContext();
if (
!customFields?.releaseVersions ||
!Array.isArray(customFields.releaseVersions)
) {
return null;
}
const releaseVersions: [string] = customFields.releaseVersions as [string];
if (customFields.isDevelopmentVersion) {
return (
<DevWarningBanner
className={className}
latestVersion={releaseVersions[0]}
/>
);
}
return null;
}

View File

@@ -0,0 +1,3 @@
{
"releaseVersions": ["0.3"]
}